On Thu, 04 Sep 2014 10:15:27 +0530
Pankaj Dubey <pankaj.du...@samsung.com> wrote:

> Hi Boris,
> 
> On Wednesday, September 03, 2014 Boris BREZILLON wrote,
> > To: Arnd Bergmann
> > Cc: Pankaj Dubey; kgene....@samsung.com; li...@arm.linux.org.uk; Alexander
> > Shiyan; naus...@samsung.com; Tomasz Figa; linux-kernel@vger.kernel.org;
> > jo...@samsung.com; linux-samsung-...@vger.kernel.org;
> thomas...@samsung.com;
> > tomasz.f...@gmail.com; vikas.saj...@samsung.com; chow....@samsung.com;
> > lee.jo...@linaro.org; Michal Simek; linux-arm-ker...@lists.infradead.org;
> 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 <a...@arndb.de> 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.brezil...@free-electrons.com>



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-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to