[PATCH 3/4] soc/imx: add new GPC driver
Lucas Stach
l.stach at pengutronix.de
Tue Jan 24 08:54:38 PST 2017
Hi Shawn,
thanks for the review.
Am Dienstag, den 24.01.2017, 20:49 +0800 schrieb Shawn Guo:
> On Fri, Jan 20, 2017 at 04:52:24PM +0100, Lucas Stach wrote:
> > This is an almost complete re-write of the previous GPC power gating control
> > code found in the IMX architecture code. It supports both the old and the new
> > DT binding, allowing more domains to be added later and generally makes the
> > driver easier to extend, while keeping compatibility with existing DTBs.
>
> Shouldn't we generally wrap the commit log around column 72?
>
I don't see why we should wrap commit messages earlier than the actual
code, but I think thats mostly an issue of personal preference.
> >
> > Signed-off-by: Lucas Stach <l.stach at pengutronix.de>
> > ---
> > drivers/soc/Makefile | 1 +
> > drivers/soc/imx/Makefile | 1 +
> > drivers/soc/imx/gpc.c | 480 +++++++++++++++++++++++++++++++++++++++++++++++
> > 3 files changed, 482 insertions(+)
> > create mode 100644 drivers/soc/imx/Makefile
> > create mode 100644 drivers/soc/imx/gpc.c
[...]
> > +static struct platform_driver imx_pgc_power_domain_driver = {
> > + .driver = {
> > + .name = "imx-pgc-pd",
> > + },
> > + .probe = imx_pgc_power_domain_probe,
> > + .remove = imx_pgc_power_domain_remove,
>
> Not sure how .remove hook is going to be useful for a
> builtin_platform_driver.
>
There is nothing preventing a manual unbind/bind on a builtin driver.
But yes, this is mostly future proofing right now.
[...]
> > +static int imx_gpc_old_dt_init(struct device *dev, struct regmap *regmap)
> > +{
> > + struct imx_pm_domain *domain;
> > + int i, ret;
> > +
> > + for (i = 0; i < 2; i++) {
> > + domain = &imx_gpc_domains[i];
> > + domain->regmap = regmap;
> > + domain->ipg_rate_mhz = 33;
>
> I see it's being 66MHz in the existing driver code. What's the reason
> behind this change?
>
Thanks for the catch. This should stay at 66MHz.
> > +
> > + if (i == 1) {
> > + domain->supply = devm_regulator_get(dev, "pu");
> > + if (IS_ERR(domain->supply))
> > + return PTR_ERR(domain->supply);;
> > +
> > + ret = imx_pgc_get_clocks(dev, domain);
> > + if (ret)
> > + goto clk_err;
> > +
> > + domain->base.power_on(&domain->base);
> > + }
> > + }
> > +
> > + for (i = 0; i < 2; i++)
> > + pm_genpd_init(&imx_gpc_domains[i].base, NULL, false);
> > +
> > + if (IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS)) {
> > + ret = of_genpd_add_provider_onecell(dev->of_node,
> > + &imx_gpc_onecell_data);
> > + if (ret)
> > + goto genpd_err;
> > + }
> > +
> > + return 0;
> > +
> > +genpd_err:
> > + pm_genpd_remove(&imx_gpc_domains[1].base);
> > + imx_pgc_put_clocks(&imx_gpc_domains[1]);
> > +clk_err:
> > + pm_genpd_remove(&imx_gpc_domains[0].base);
>
> I do not think that imx_gpc_domains[0].base is already registered on
> clk_err path.
>
Um right, this seems to be a leftover from an earlier version.
> > +
> > + return ret;
> > +}
> > +
> > +static int imx_gpc_probe(struct platform_device *pdev)
> > +{
> > + const struct of_device_id *of_id =
> > + of_match_device(imx_gpc_dt_ids, &pdev->dev);
> > + const struct imx_gpc_dt_data *of_id_data = of_id->data;
> > + struct device_node *pgc_node;
> > + struct regmap *regmap;
> > + struct resource *res;
> > + void __iomem *base;
> > + int ret;
> > +
> > + pgc_node = of_get_child_by_name(pdev->dev.of_node, "pgc");
> > +
> > + /* bail out if DT too old and doesn't provide the necessary info */
> > + if (!of_property_read_bool(pdev->dev.of_node, "#power-domain-cells") &&
> > + !pgc_node)
> > + return 0;
> > +
> > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > + base = devm_ioremap_resource(&pdev->dev, res);
> > + if (IS_ERR(base))
> > + return PTR_ERR(base);
> > +
> > + regmap = devm_regmap_init_mmio_clk(&pdev->dev, NULL, base,
> > + &imx_gpc_regmap_config);
> > + if (IS_ERR(regmap)) {
> > + ret = PTR_ERR(regmap);
> > + dev_err(&pdev->dev, "failed to init regmap: %d\n",
> > + ret);
> > + return ret;
> > + }
> > +
> > + if (!pgc_node) {
> > + /* old DT layout is only supported for mx6q aka 2 domains */
> > + if (of_id_data->num_domains != 2) {
> > + dev_err(&pdev->dev, "could not find pgc DT node\n");
> > + return -ENODEV;
> > + }
> > +
> > + ret = imx_gpc_old_dt_init(&pdev->dev, regmap);
> > + if (ret)
> > + return ret;
> > + } else {
> > + struct imx_pm_domain *domain;
> > + struct platform_device *pd_pdev;
> > + struct device_node *np;
> > + struct clk *ipg_clk;
> > + unsigned int ipg_rate_mhz;
> > + int domain_index;
> > +
> > + ipg_clk = devm_clk_get(&pdev->dev, "ipg");
> > + if (IS_ERR(ipg_clk))
> > + return PTR_ERR(ipg_clk);
> > + ipg_rate_mhz = clk_get_rate(ipg_clk) / 1000000;
> > +
> > + for_each_child_of_node(pgc_node, np) {
> > + ret = of_property_read_u32(np, "reg", &domain_index);
> > + if (ret) {
> > + of_node_put(np);
> > + return ret;
> > + }
>
> Should we have a check here to ensure that domain_index doesn't exceed
> imx_gpc_domains[] array size?
Yes.
Regards,
Lucas
More information about the linux-arm-kernel
mailing list