On Thu, 04 Sep 2014 10:15:27 +0530 Pankaj Dubey <pankaj.dubey@xxxxxxxxxxx> wrote: > Hi Boris, > > On Wednesday, September 03, 2014 Boris BREZILLON wrote, > > To: Arnd Bergmann > > Cc: Pankaj Dubey; kgene.kim@xxxxxxxxxxx; linux@xxxxxxxxxxxxxxxx; Alexander > > Shiyan; naushad@xxxxxxxxxxx; Tomasz Figa; linux-kernel@xxxxxxxxxxxxxxx; > > joshi@xxxxxxxxxxx; linux-samsung-soc@xxxxxxxxxxxxxxx; > thomas.ab@xxxxxxxxxxx; > > tomasz.figa@xxxxxxxxx; vikas.sajjan@xxxxxxxxxxx; chow.kim@xxxxxxxxxxx; > > lee.jones@xxxxxxxxxx; Michal Simek; linux-arm-kernel@xxxxxxxxxxxxxxxxxxx; > Mark > > Brown > > Subject: Re: [PATCH v2] mfd: syscon: Decouple syscon interface from > platform > > devices > > > > On Wed, 03 Sep 2014 15:49:04 +0200 > > Arnd Bergmann <arnd@xxxxxxxx> wrote: > > > > > On Wednesday 03 September 2014 15:16:11 Boris BREZILLON wrote: > > > > I checked that part, and it appears most of the code is already > > > > there (see usage of regmap_attach_dev function here [1]). > > > > > > > > The only problem I see is that errors are still printed with > > > > dev_err, which, AFAIK, will trigger a kernel panic if dev is NULL. > > > > > > Actually not: > > > > > > static int __dev_printk(const char *level, const struct device *dev, > > > struct va_format *vaf) { > > > if (!dev) > > > return printk("%s(NULL device *): %pV", level, vaf); > > > > > > return dev_printk_emit(level[1] - '0', dev, > > > "%s %s: %pV", > > > dev_driver_string(dev), dev_name(dev), > > > vaf); } > > > > > > > My bad then (I don't know where I looked at to think NULL dev was not > gracefully > > handled :-)). Thanks for pointing this out. > > Given that, I think it should work fine even with a NULL dev. > > I'll give it a try on at91 ;-). > > > > We have tested this patch, on Exynos board and found working well. > In our use case DT based drivers such as USB Phy, SATA Phy, Watchdog are > calling > syscon_regmap_lookup_by APIs to get regmap handle to Exynos PMU and it > worked > well for these drivers. > > It would be great if after testing you share result here or give a > Tested-By. > I eventually tested it (just required minor modifications to my PMC code: see below). Still, this patch is not achieving my final goal which is to remove the global at91_pmc_base variable and make use of the syscon regmap to implement at91 cpu idle and platform suspend. Moreover, I'd like to remove the lock in at91_pmc struct as regmap is already taking care of locking the resources when accessing a register, but this requires a lot more changes. Anyway, here is my Tested-by: Boris Brezillon <boris.brezillon@xxxxxxxxxxxxxxxxxx> diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig index dd28e1f..7df2c9b 100644 --- a/arch/arm/mach-at91/Kconfig +++ b/arch/arm/mach-at91/Kconfig @@ -23,6 +23,7 @@ config COMMON_CLK_AT91 bool default AT91_PMC_UNIT && USE_OF && !AT91_USE_OLD_CLK select COMMON_CLK + select MFD_SYSCON config OLD_CLK_AT91 bool diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c index 524196b..fb2c0af 100644 --- a/drivers/clk/at91/pmc.c +++ b/drivers/clk/at91/pmc.c @@ -19,6 +19,7 @@ #include <linux/irqchip/chained_irq.h> #include <linux/irqdomain.h> #include <linux/of_irq.h> +#include <linux/mfd/syscon.h> #include <asm/proc-fns.h> @@ -190,6 +191,7 @@ static const struct at91_pmc_caps sama5d3_caps = { }; static struct at91_pmc *__init at91_pmc_init(struct device_node *np, + struct regmap *regmap, void __iomem *regbase, int virq, const struct at91_pmc_caps *caps) { @@ -205,7 +207,7 @@ static struct at91_pmc *__init at91_pmc_init(struct device_node *np, return NULL; spin_lock_init(&pmc->lock); - pmc->regbase = regbase; + pmc->regmap = regmap; pmc->virq = virq; pmc->caps = caps; @@ -348,16 +350,46 @@ static void __init of_at91_pmc_setup(struct device_node *np, void (*clk_setup)(struct device_node *, struct at91_pmc *); const struct of_device_id *clk_id; void __iomem *regbase = of_iomap(np, 0); + struct regmap *regmap; int virq; - if (!regbase) - return; + /* + * If the pmc compatible property does not contain the "syscon" + * string, patch the property so that syscon_node_to_regmap can + * consider it as a syscon device. + */ + if (!of_device_is_compatible(np, "syscon")) { + struct property *newprop, *oldprop; + + oldprop = of_find_property(np, "compatible", NULL); + if (!oldprop) + panic("Could not find compatible property"); + + newprop = kzalloc(sizeof(*newprop), GFP_KERNEL); + if (!newprop) + panic("Could not allocate compatible property"); + + newprop->name = "compatible"; + newprop->length = oldprop->length + sizeof("syscon"); + newprop->value = kmalloc(newprop->length, GFP_KERNEL); + if (!newprop->value) { + kfree(newprop->value); + panic("Could not allocate compatible string"); + } + memcpy(newprop->value, oldprop->value, oldprop->length); + memcpy(newprop->value + oldprop->length, "syscon", sizeof("syscon")); + of_update_property(np, newprop); + } + + regmap = syscon_node_to_regmap(np); + if (IS_ERR(regmap)) + panic("Could not retrieve syscon regmap"); virq = irq_of_parse_and_map(np, 0); if (!virq) return; - pmc = at91_pmc_init(np, regbase, virq, caps); + pmc = at91_pmc_init(np, regmap, regbase, virq, caps); if (!pmc) return; for_each_child_of_node(np, childnp) { diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h index 6c76259..49589ea 100644 --- a/drivers/clk/at91/pmc.h +++ b/drivers/clk/at91/pmc.h @@ -14,6 +14,7 @@ #include <linux/io.h> #include <linux/irqdomain.h> +#include <linux/regmap.h> #include <linux/spinlock.h> struct clk_range { @@ -28,7 +29,7 @@ struct at91_pmc_caps { }; struct at91_pmc { - void __iomem *regbase; + struct regmap *regmap; int virq; spinlock_t lock; const struct at91_pmc_caps *caps; @@ -47,12 +48,16 @@ static inline void pmc_unlock(struct at91_pmc *pmc) static inline u32 pmc_read(struct at91_pmc *pmc, int offset) { - return readl(pmc->regbase + offset); + unsigned int ret = 0; + + regmap_read(pmc->regmap, offset, &ret); + + return ret; } static inline void pmc_write(struct at91_pmc *pmc, int offset, u32 value) { - writel(value, pmc->regbase + offset); + regmap_write(pmc->regmap, offset, value); } int of_at91_get_clk_range(struct device_node *np, const char *propname, -- To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html