Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Copyright 2015 Toradex AG
0004  *
0005  * Stefan Agner <stefan@agner.ch>
0006  *
0007  * Freescale TCON device driver
0008  */
0009 
0010 #include <linux/clk.h>
0011 #include <linux/io.h>
0012 #include <linux/mm.h>
0013 #include <linux/of_address.h>
0014 #include <linux/platform_device.h>
0015 #include <linux/regmap.h>
0016 
0017 #include "fsl_tcon.h"
0018 
0019 void fsl_tcon_bypass_disable(struct fsl_tcon *tcon)
0020 {
0021     regmap_update_bits(tcon->regs, FSL_TCON_CTRL1,
0022                FSL_TCON_CTRL1_TCON_BYPASS, 0);
0023 }
0024 
0025 void fsl_tcon_bypass_enable(struct fsl_tcon *tcon)
0026 {
0027     regmap_update_bits(tcon->regs, FSL_TCON_CTRL1,
0028                FSL_TCON_CTRL1_TCON_BYPASS,
0029                FSL_TCON_CTRL1_TCON_BYPASS);
0030 }
0031 
0032 static struct regmap_config fsl_tcon_regmap_config = {
0033     .reg_bits = 32,
0034     .reg_stride = 4,
0035     .val_bits = 32,
0036 
0037     .name = "tcon",
0038 };
0039 
0040 static int fsl_tcon_init_regmap(struct device *dev,
0041                 struct fsl_tcon *tcon,
0042                 struct device_node *np)
0043 {
0044     struct resource res;
0045     void __iomem *regs;
0046 
0047     if (of_address_to_resource(np, 0, &res))
0048         return -EINVAL;
0049 
0050     regs = devm_ioremap_resource(dev, &res);
0051     if (IS_ERR(regs))
0052         return PTR_ERR(regs);
0053 
0054     tcon->regs = devm_regmap_init_mmio(dev, regs,
0055                        &fsl_tcon_regmap_config);
0056     return PTR_ERR_OR_ZERO(tcon->regs);
0057 }
0058 
0059 struct fsl_tcon *fsl_tcon_init(struct device *dev)
0060 {
0061     struct fsl_tcon *tcon;
0062     struct device_node *np;
0063     int ret;
0064 
0065     /* TCON node is not mandatory, some devices do not provide TCON */
0066     np = of_parse_phandle(dev->of_node, "fsl,tcon", 0);
0067     if (!np)
0068         return NULL;
0069 
0070     tcon = devm_kzalloc(dev, sizeof(*tcon), GFP_KERNEL);
0071     if (!tcon)
0072         goto err_node_put;
0073 
0074     ret = fsl_tcon_init_regmap(dev, tcon, np);
0075     if (ret) {
0076         dev_err(dev, "Couldn't create the TCON regmap\n");
0077         goto err_node_put;
0078     }
0079 
0080     tcon->ipg_clk = of_clk_get_by_name(np, "ipg");
0081     if (IS_ERR(tcon->ipg_clk)) {
0082         dev_err(dev, "Couldn't get the TCON bus clock\n");
0083         goto err_node_put;
0084     }
0085 
0086     ret = clk_prepare_enable(tcon->ipg_clk);
0087     if (ret) {
0088         dev_err(dev, "Couldn't enable the TCON clock\n");
0089         goto err_node_put;
0090     }
0091 
0092     of_node_put(np);
0093     dev_info(dev, "Using TCON in bypass mode\n");
0094 
0095     return tcon;
0096 
0097 err_node_put:
0098     of_node_put(np);
0099     return NULL;
0100 }
0101 
0102 void fsl_tcon_free(struct fsl_tcon *tcon)
0103 {
0104     clk_disable_unprepare(tcon->ipg_clk);
0105     clk_put(tcon->ipg_clk);
0106 }
0107