mfd: vexpress: Convert custom func API to regmap
authorPawel Moll <pawel.moll@arm.com>
Wed, 30 Apr 2014 15:46:29 +0000 (16:46 +0100)
committerPawel Moll <pawel.moll@arm.com>
Thu, 15 May 2014 16:02:18 +0000 (17:02 +0100)
Components of the Versatile Express platform (configuration
microcontrollers on motherboard and daughterboards in particular)
talk to each other over a custom configuration bus. They
provide miscellaneous functions (from clock generator control
to energy sensors) which are represented as platform devices
(and Device Tree nodes). The transactions on the bus can
be generated by different "bridges" in the system, some
of which are universal for the whole platform (for the price
of high transfer latencies), others restricted to a subsystem
(but much faster).

Until now drivers for such functions were using custom "func"
API, which is being replaced in this patch by regmap calls.
This required:

* a rework (and move to drivers/bus directory, as suggested
  by Samuel and Arnd) of the config bus core, which is much
  simpler now and uses device model infrastructure (class)
  to keep track of the bridges; non-DT case (soon to be
  retired anyway) is simply covered by a special device
  registration function

* the new config-bus driver also takes over device population,
  so there is no need for special matching table for
  of_platform_populate nor "simple-bus" hack in the arm64
  model dtsi file (relevant bindings documentation has
  been updated); this allows all the vexpress devices
  fit into normal device model, making it possible
  to remove plenty of early inits and other hacks in
  the near future

* adaptation of the syscfg bridge implementation in the
  sysreg driver, again making it much simpler; there is
  a special case of the "energy" function spanning two
  registers, where they should be both defined in the tree
  now, but backward compatibility is maintained in the code

* modification of the relevant drivers:

  * hwmon - just a straight-forward API change
  * power/reset driver - API change
  * regulator - API change plus error handling
    simplification
  * osc clock driver - this one required larger rework
    in order to turn in into a standard platform driver

Signed-off-by: Pawel Moll <pawel.moll@arm.com>
Acked-by: Mark Brown <broonie@linaro.org>
Acked-by: Lee Jones <lee.jones@linaro.org>
Acked-by: Guenter Roeck <linux@roeck-us.net>
Acked-by: Mike Turquette <mturquette@linaro.org>
17 files changed:
Documentation/devicetree/bindings/arm/vexpress-sysreg.txt
Documentation/devicetree/bindings/arm/vexpress.txt
arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts
arch/arm/mach-vexpress/ct-ca9x4.c
arch/arm/mach-vexpress/v2m.c
arch/arm64/boot/dts/rtsm_ve-motherboard.dtsi
drivers/bus/Kconfig
drivers/bus/Makefile
drivers/bus/vexpress-config.c [new file with mode: 0644]
drivers/clk/versatile/clk-vexpress-osc.c
drivers/hwmon/vexpress.c
drivers/mfd/Makefile
drivers/mfd/vexpress-config.c [deleted file]
drivers/mfd/vexpress-sysreg.c
drivers/power/reset/vexpress-poweroff.c
drivers/regulator/vexpress.c
include/linux/vexpress.h

index 5580e9c4bd8584034a9d9812c491962f08fa253e..57b423f789957f214bbb5a96c6cd5f81d83db24b 100644 (file)
@@ -27,24 +27,45 @@ Example:
 This block also can also act a bridge to the platform's configuration
 bus via "system control" interface, addressing devices with site number,
 position in the board stack, config controller, function and device
-numbers - see motherboard's TRM for more details.
-
-The node describing a config device must refer to the sysreg node via
-"arm,vexpress,config-bridge" phandle (can be also defined in the node's
-parent) and relies on the board topology properties - see main vexpress
-node documentation for more details. It must also define the following
-property:
-- arm,vexpress-sysreg,func : must contain two cells:
-  - first cell defines function number (eg. 1 for clock generator,
-    2 for voltage regulators etc.)
-  - device number (eg. osc 0, osc 1 etc.)
+numbers - see motherboard's TRM for more details. All configuration
+controller accessible via this interface must reference the sysreg
+node via "arm,vexpress,config-bridge" phandle and define appropriate
+topology properties - see main vexpress node documentation for more
+details. Each child of such node describes one function and must
+define the following properties:
+- compatible value : must be one of (corresponding to the TRM):
+       "arm,vexpress-amp"
+       "arm,vexpress-dvimode"
+       "arm,vexpress-energy"
+       "arm,vexpress-muxfpga"
+       "arm,vexpress-osc"
+       "arm,vexpress-power"
+       "arm,vexpress-reboot"
+       "arm,vexpress-reset"
+       "arm,vexpress-scc"
+       "arm,vexpress-shutdown"
+       "arm,vexpress-temp"
+       "arm,vexpress-volt"
+- arm,vexpress-sysreg,func : must contain a set of two cells long groups:
+  - first cell of each group defines the function number
+    (eg. 1 for clock generator, 2 for voltage regulators etc.)
+  - second cell of each group defines device number (eg. osc 0,
+    osc 1 etc.)
+  - some functions (eg. energy meter, with its 64 bit long counter)
+    are using more than one function/device number pair
 
 Example:
        mcc {
+               compatible = "arm,vexpress,config-bus";
                arm,vexpress,config-bridge = <&v2m_sysreg>;
 
                osc@0 {
                        compatible = "arm,vexpress-osc";
                        arm,vexpress-sysreg,func = <1 0>;
                };
+
+               energy@0 {
+                       compatible = "arm,vexpress-energy";
+                       arm,vexpress-sysreg,func = <13 0>, <13 1>;
+               };
        };
index ae49161e478ae556a31cb9eed4bc66e50daf9c70..39844cd0bccefd41a8d18dd42e3368c9df6d5488 100644 (file)
@@ -80,12 +80,17 @@ but also control clock generators, voltage regulators, gather
 environmental data like temperature, power consumption etc. Even
 the video output switch (FPGA) is controlled that way.
 
-Nodes describing devices controlled by this infrastructure should
-point at the bridge device node:
+The controllers are not mapped into normal memory address space
+and must be accessed through bridges - other devices capable
+of generating transactions on the configuration bus.
+
+The nodes describing configuration controllers must define
+the following properties:
+- compatible value:
+       compatible = "arm,vexpress,config-bus";
 - bridge phandle:
        arm,vexpress,config-bridge = <phandle>;
-This property can be also defined in a parent node (eg. for a DCC)
-and is effective for all children.
+and children describing available functions.
 
 
 Platform topology
@@ -197,7 +202,7 @@ Example of a VE tile description (simplified)
        };
 
        dcc {
-               compatible = "simple-bus";
+               compatible = "arm,vexpress,config-bus";
                arm,vexpress,config-bridge = <&v2m_sysreg>;
 
                osc@0 {
index 15f98cbcb75a3be41737c208b772db8a161ed8d1..a25c262326dcdcc2e681f6f2e900de8ea59891a2 100644 (file)
                        arm,vexpress-sysreg,func = <12 0>;
                        label = "A15 Pcore";
                };
+
                power@1 {
                        /* Total power for the three A7 cores */
                        compatible = "arm,vexpress-power";
                energy@0 {
                        /* Total energy for the two A15 cores */
                        compatible = "arm,vexpress-energy";
-                       arm,vexpress-sysreg,func = <13 0>;
+                       arm,vexpress-sysreg,func = <13 0>, <13 1>;
                        label = "A15 Jcore";
                };
 
                energy@2 {
                        /* Total energy for the three A7 cores */
                        compatible = "arm,vexpress-energy";
-                       arm,vexpress-sysreg,func = <13 2>;
+                       arm,vexpress-sysreg,func = <13 2>, <13 3>;
                        label = "A7 Jcore";
                };
        };
index 6f34497a42451ea23ea5cea4633e4d47ffcd44ae..35e394aa00e5b6cd65d4ba9d3b1c1d91529447a0 100644 (file)
@@ -128,6 +128,10 @@ static struct platform_device pmu_device = {
        .resource       = pmu_resources,
 };
 
+static struct clk_lookup osc1_lookup = {
+       .dev_id         = "ct:clcd",
+};
+
 static struct platform_device osc1_device = {
        .name           = "vexpress-osc",
        .id             = 1,
@@ -135,6 +139,7 @@ static struct platform_device osc1_device = {
        .resource       = (struct resource []) {
                VEXPRESS_RES_FUNC(0xf, 1),
        },
+       .dev.platform_data = &osc1_lookup,
 };
 
 static void __init ct_ca9x4_init(void)
@@ -155,10 +160,7 @@ static void __init ct_ca9x4_init(void)
                amba_device_register(ct_ca9x4_amba_devs[i], &iomem_resource);
 
        platform_device_register(&pmu_device);
-       platform_device_register(&osc1_device);
-
-       WARN_ON(clk_register_clkdev(vexpress_osc_setup(&osc1_device.dev),
-                       NULL, "ct:clcd"));
+       vexpress_sysreg_config_device_register(&osc1_device);
 }
 
 #ifdef CONFIG_SMP
index 4f8b8cb17ff50560c751058b2f44980294482428..ac95220a5019ae5dc076621cc67a4b314b16069f 100644 (file)
@@ -340,11 +340,6 @@ static void __init v2m_init(void)
        regulator_register_fixed(0, v2m_eth_supplies,
                        ARRAY_SIZE(v2m_eth_supplies));
 
-       platform_device_register(&v2m_muxfpga_device);
-       platform_device_register(&v2m_shutdown_device);
-       platform_device_register(&v2m_reboot_device);
-       platform_device_register(&v2m_dvimode_device);
-
        platform_device_register(&v2m_sysreg_device);
        platform_device_register(&v2m_pcie_i2c_device);
        platform_device_register(&v2m_ddc_i2c_device);
@@ -356,6 +351,11 @@ static void __init v2m_init(void)
        for (i = 0; i < ARRAY_SIZE(v2m_amba_devs); i++)
                amba_device_register(v2m_amba_devs[i], &iomem_resource);
 
+       vexpress_sysreg_config_device_register(&v2m_muxfpga_device);
+       vexpress_sysreg_config_device_register(&v2m_shutdown_device);
+       vexpress_sysreg_config_device_register(&v2m_reboot_device);
+       vexpress_sysreg_config_device_register(&v2m_dvimode_device);
+
        ct_desc->init_tile();
 }
 
@@ -423,17 +423,11 @@ void __init v2m_dt_init_early(void)
        versatile_sched_clock_init(vexpress_get_24mhz_clock_base(), 24000000);
 }
 
-static const struct of_device_id v2m_dt_bus_match[] __initconst = {
-       { .compatible = "simple-bus", },
-       { .compatible = "arm,amba-bus", },
-       { .compatible = "arm,vexpress,config-bus", },
-       {}
-};
 
 static void __init v2m_dt_init(void)
 {
        l2x0_of_init(0x00400000, 0xfe0fffff);
-       of_platform_populate(NULL, v2m_dt_bus_match, NULL, NULL);
+       of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
 }
 
 static const char * const v2m_dt_match[] __initconst = {
index 2f2ecd217363d4b554bbf24ab987521cc5835ba9..ac2cb2418025af014f7c6d135d23ff148dcef183 100644 (file)
                };
 
                mcc {
-                       compatible = "arm,vexpress,config-bus", "simple-bus";
+                       compatible = "arm,vexpress,config-bus";
                        arm,vexpress,config-bridge = <&v2m_sysreg>;
 
                        v2m_oscclk1: osc@1 {
index 552373c4e362ed659cc40ec83ddd6bb564e630f9..f24e79dd51bf3b4e611219a894e9617c012b5676 100644 (file)
@@ -41,4 +41,13 @@ config ARM_CCI
        help
          Driver supporting the CCI cache coherent interconnect for ARM
          platforms.
+
+config VEXPRESS_CONFIG
+       bool "Versatile Express configuration bus"
+       default y if ARCH_VEXPRESS
+       depends on ARM || ARM64
+       select REGMAP
+       help
+         Platform configuration infrastructure for the ARM Ltd.
+         Versatile Express.
 endmenu
index 8947bdd0de8bb2c0fdfc918e8dc9d166b6af81fa..f095aa771de9ac2d0c21f84c0d8e34d4de70b12f 100644 (file)
@@ -10,3 +10,5 @@ obj-$(CONFIG_OMAP_OCP2SCP)    += omap-ocp2scp.o
 obj-$(CONFIG_OMAP_INTERCONNECT)        += omap_l3_smx.o omap_l3_noc.o
 # CCI cache coherent interconnect for ARM platforms
 obj-$(CONFIG_ARM_CCI)          += arm-cci.o
+
+obj-$(CONFIG_VEXPRESS_CONFIG)  += vexpress-config.o
diff --git a/drivers/bus/vexpress-config.c b/drivers/bus/vexpress-config.c
new file mode 100644 (file)
index 0000000..27a07df
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Copyright (C) 2014 ARM Limited
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/vexpress.h>
+
+
+struct vexpress_config_bridge {
+       struct vexpress_config_bridge_ops *ops;
+       void *context;
+};
+
+
+static DEFINE_MUTEX(vexpress_config_mutex);
+static struct class *vexpress_config_class;
+static u32 vexpress_config_site_master = VEXPRESS_SITE_MASTER;
+
+
+void vexpress_config_set_master(u32 site)
+{
+       vexpress_config_site_master = site;
+}
+
+u32 vexpress_config_get_master(void)
+{
+       return vexpress_config_site_master;
+}
+
+void vexpress_config_lock(void *arg)
+{
+       mutex_lock(&vexpress_config_mutex);
+}
+
+void vexpress_config_unlock(void *arg)
+{
+       mutex_unlock(&vexpress_config_mutex);
+}
+
+
+static void vexpress_config_find_prop(struct device_node *node,
+               const char *name, u32 *val)
+{
+       /* Default value */
+       *val = 0;
+
+       of_node_get(node);
+       while (node) {
+               if (of_property_read_u32(node, name, val) == 0) {
+                       of_node_put(node);
+                       return;
+               }
+               node = of_get_next_parent(node);
+       }
+}
+
+int vexpress_config_get_topo(struct device_node *node, u32 *site,
+               u32 *position, u32 *dcc)
+{
+       vexpress_config_find_prop(node, "arm,vexpress,site", site);
+       if (*site == VEXPRESS_SITE_MASTER)
+               *site = vexpress_config_site_master;
+       if (WARN_ON(vexpress_config_site_master == VEXPRESS_SITE_MASTER))
+               return -EINVAL;
+       vexpress_config_find_prop(node, "arm,vexpress,position", position);
+       vexpress_config_find_prop(node, "arm,vexpress,dcc", dcc);
+
+       return 0;
+}
+
+
+static void vexpress_config_devres_release(struct device *dev, void *res)
+{
+       struct vexpress_config_bridge *bridge = dev_get_drvdata(dev->parent);
+       struct regmap *regmap = res;
+
+       bridge->ops->regmap_exit(regmap, bridge->context);
+}
+
+struct regmap *devm_regmap_init_vexpress_config(struct device *dev)
+{
+       struct vexpress_config_bridge *bridge;
+       struct regmap *regmap;
+       struct regmap **res;
+
+       if (WARN_ON(dev->parent->class != vexpress_config_class))
+               return ERR_PTR(-ENODEV);
+
+       bridge = dev_get_drvdata(dev->parent);
+       if (WARN_ON(!bridge))
+               return ERR_PTR(-EINVAL);
+
+       res = devres_alloc(vexpress_config_devres_release, sizeof(*res),
+                       GFP_KERNEL);
+       if (!res)
+               return ERR_PTR(-ENOMEM);
+
+       regmap = bridge->ops->regmap_init(dev, bridge->context);
+       if (IS_ERR(regmap)) {
+               devres_free(res);
+               return regmap;
+       }
+
+       *res = regmap;
+       devres_add(dev, res);
+
+       return regmap;
+}
+
+
+struct device *vexpress_config_bridge_register(struct device *parent,
+               struct vexpress_config_bridge_ops *ops, void *context)
+{
+       struct device *dev;
+       struct vexpress_config_bridge *bridge;
+
+       if (!vexpress_config_class) {
+               vexpress_config_class = class_create(THIS_MODULE,
+                               "vexpress-config");
+               if (IS_ERR(vexpress_config_class))
+                       return (void *)vexpress_config_class;
+       }
+
+       dev = device_create(vexpress_config_class, parent, 0,
+                       NULL, "%s.bridge", dev_name(parent));
+
+       if (IS_ERR(dev))
+               return dev;
+
+       bridge = devm_kmalloc(dev, sizeof(*bridge), GFP_KERNEL);
+       if (!bridge) {
+               put_device(dev);
+               device_unregister(dev);
+               return ERR_PTR(-ENOMEM);
+       }
+       bridge->ops = ops;
+       bridge->context = context;
+
+       dev_set_drvdata(dev, bridge);
+
+       dev_dbg(parent, "Registered bridge '%s', parent node %p\n",
+                       dev_name(dev), parent->of_node);
+
+       return dev;
+}
+
+
+static int vexpress_config_node_match(struct device *dev, const void *data)
+{
+       const struct device_node *node = data;
+
+       dev_dbg(dev, "Parent node %p, looking for %p\n",
+                       dev->parent->of_node, node);
+
+       return dev->parent->of_node == node;
+}
+
+static int vexpress_config_populate(struct device_node *node)
+{
+       struct device_node *bridge;
+       struct device *parent;
+
+       bridge = of_parse_phandle(node, "arm,vexpress,config-bridge", 0);
+       if (!bridge)
+               return -EINVAL;
+
+       parent = class_find_device(vexpress_config_class, NULL, bridge,
+                       vexpress_config_node_match);
+       if (WARN_ON(!parent))
+               return -ENODEV;
+
+       return of_platform_populate(node, NULL, NULL, parent);
+}
+
+static int __init vexpress_config_init(void)
+{
+       int err = 0;
+       struct device_node *node;
+
+       /* Need the config devices early, before the "normal" devices... */
+       for_each_compatible_node(node, NULL, "arm,vexpress,config-bus") {
+               err = vexpress_config_populate(node);
+               if (err)
+                       break;
+       }
+
+       return err;
+}
+postcore_initcall(vexpress_config_init);
+
index 422391242b39ceac4a322ee532288ee46b6eba32..529a59c0fbfa4ced8f163abe77663d038dd78b24 100644 (file)
@@ -11,8 +11,6 @@
  * Copyright (C) 2012 ARM Limited
  */
 
-#define pr_fmt(fmt) "vexpress-osc: " fmt
-
 #include <linux/clkdev.h>
 #include <linux/clk-provider.h>
 #include <linux/err.h>
@@ -22,7 +20,7 @@
 #include <linux/vexpress.h>
 
 struct vexpress_osc {
-       struct vexpress_config_func *func;
+       struct regmap *reg;
        struct clk_hw hw;
        unsigned long rate_min;
        unsigned long rate_max;
@@ -36,7 +34,7 @@ static unsigned long vexpress_osc_recalc_rate(struct clk_hw *hw,
        struct vexpress_osc *osc = to_vexpress_osc(hw);
        u32 rate;
 
-       vexpress_config_read(osc->func, 0, &rate);
+       regmap_read(osc->reg, 0, &rate);
 
        return rate;
 }
@@ -60,7 +58,7 @@ static int vexpress_osc_set_rate(struct clk_hw *hw, unsigned long rate,
 {
        struct vexpress_osc *osc = to_vexpress_osc(hw);
 
-       return vexpress_config_write(osc->func, 0, rate);
+       return regmap_write(osc->reg, 0, rate);
 }
 
 static struct clk_ops vexpress_osc_ops = {
@@ -70,58 +68,31 @@ static struct clk_ops vexpress_osc_ops = {
 };
 
 
-struct clk * __init vexpress_osc_setup(struct device *dev)
-{
-       struct clk_init_data init;
-       struct vexpress_osc *osc = kzalloc(sizeof(*osc), GFP_KERNEL);
-
-       if (!osc)
-               return NULL;
-
-       osc->func = vexpress_config_func_get_by_dev(dev);
-       if (!osc->func) {
-               kfree(osc);
-               return NULL;
-       }
-
-       init.name = dev_name(dev);
-       init.ops = &vexpress_osc_ops;
-       init.flags = CLK_IS_ROOT;
-       init.num_parents = 0;
-       osc->hw.init = &init;
-
-       return clk_register(NULL, &osc->hw);
-}
-
-void __init vexpress_osc_of_setup(struct device_node *node)
+static int vexpress_osc_probe(struct platform_device *pdev)
 {
+       struct clk_lookup *cl = pdev->dev.platform_data; /* Non-DT lookup */
        struct clk_init_data init;
        struct vexpress_osc *osc;
        struct clk *clk;
        u32 range[2];
 
-       vexpress_sysreg_of_early_init();
-
-       osc = kzalloc(sizeof(*osc), GFP_KERNEL);
+       osc = devm_kzalloc(&pdev->dev, sizeof(*osc), GFP_KERNEL);
        if (!osc)
-               return;
+               return -ENOMEM;
 
-       osc->func = vexpress_config_func_get_by_node(node);
-       if (!osc->func) {
-               pr_err("Failed to obtain config func for node '%s'!\n",
-                               node->full_name);
-               goto error;
-       }
+       osc->reg = devm_regmap_init_vexpress_config(&pdev->dev);
+       if (IS_ERR(osc->reg))
+               return PTR_ERR(osc->reg);
 
-       if (of_property_read_u32_array(node, "freq-range", range,
+       if (of_property_read_u32_array(pdev->dev.of_node, "freq-range", range,
                        ARRAY_SIZE(range)) == 0) {
                osc->rate_min = range[0];
                osc->rate_max = range[1];
        }
 
-       of_property_read_string(node, "clock-output-names", &init.name);
-       if (!init.name)
-               init.name = node->full_name;
+       if (of_property_read_string(pdev->dev.of_node, "clock-output-names",
+                       &init.name) != 0)
+               init.name = dev_name(&pdev->dev);
 
        init.ops = &vexpress_osc_ops;
        init.flags = CLK_IS_ROOT;
@@ -130,20 +101,37 @@ void __init vexpress_osc_of_setup(struct device_node *node)
        osc->hw.init = &init;
 
        clk = clk_register(NULL, &osc->hw);
-       if (IS_ERR(clk)) {
-               pr_err("Failed to register clock '%s'!\n", init.name);
-               goto error;
+       if (IS_ERR(clk))
+               return PTR_ERR(clk);
+
+       of_clk_add_provider(pdev->dev.of_node, of_clk_src_simple_get, clk);
+
+       /* Only happens for non-DT cases */
+       if (cl) {
+               cl->clk = clk;
+               clkdev_add(cl);
        }
 
-       of_clk_add_provider(node, of_clk_src_simple_get, clk);
+       dev_dbg(&pdev->dev, "Registered clock '%s'\n", init.name);
+
+       return 0;
+}
 
-       pr_debug("Registered clock '%s'\n", init.name);
+static struct of_device_id vexpress_osc_of_match[] = {
+       { .compatible = "arm,vexpress-osc", },
+       {}
+};
 
-       return;
+static struct platform_driver vexpress_osc_driver = {
+       .driver = {
+               .name = "vexpress-osc",
+               .of_match_table = vexpress_osc_of_match,
+       },
+       .probe = vexpress_osc_probe,
+};
 
-error:
-       if (osc->func)
-               vexpress_config_func_put(osc->func);
-       kfree(osc);
+static int __init vexpress_osc_init(void)
+{
+       return platform_driver_register(&vexpress_osc_driver);
 }
-CLK_OF_DECLARE(vexpress_soc, "arm,vexpress-osc", vexpress_osc_of_setup);
+core_initcall(vexpress_osc_init);
index 8242b75d96c87e9b69a079f00e871e70f1867c7f..611f34c7333de3180f3bbc2d30f48f927c6b3c2c 100644 (file)
@@ -26,7 +26,7 @@
 
 struct vexpress_hwmon_data {
        struct device *hwmon_dev;
-       struct vexpress_config_func *func;
+       struct regmap *reg;
        const char *name;
 };
 
@@ -53,7 +53,7 @@ static ssize_t vexpress_hwmon_u32_show(struct device *dev,
        int err;
        u32 value;
 
-       err = vexpress_config_read(data->func, 0, &value);
+       err = regmap_read(data->reg, 0, &value);
        if (err)
                return err;
 
@@ -68,11 +68,11 @@ static ssize_t vexpress_hwmon_u64_show(struct device *dev,
        int err;
        u32 value_hi, value_lo;
 
-       err = vexpress_config_read(data->func, 0, &value_lo);
+       err = regmap_read(data->reg, 0, &value_lo);
        if (err)
                return err;
 
-       err = vexpress_config_read(data->func, 1, &value_hi);
+       err = regmap_read(data->reg, 1, &value_hi);
        if (err)
                return err;
 
@@ -234,9 +234,9 @@ static int vexpress_hwmon_probe(struct platform_device *pdev)
        type = match->data;
        data->name = type->name;
 
-       data->func = vexpress_config_func_get_by_dev(&pdev->dev);
-       if (!data->func)
-               return -ENODEV;
+       data->reg = devm_regmap_init_vexpress_config(&pdev->dev);
+       if (IS_ERR(data->reg))
+               return PTR_ERR(data->reg);
 
        err = sysfs_create_groups(&pdev->dev.kobj, type->attr_groups);
        if (err)
@@ -252,7 +252,6 @@ static int vexpress_hwmon_probe(struct platform_device *pdev)
 
 error:
        sysfs_remove_group(&pdev->dev.kobj, match->data);
-       vexpress_config_func_put(data->func);
        return err;
 }
 
@@ -266,8 +265,6 @@ static int vexpress_hwmon_remove(struct platform_device *pdev)
        match = of_match_device(vexpress_hwmon_of_match, &pdev->dev);
        sysfs_remove_group(&pdev->dev.kobj, match->data);
 
-       vexpress_config_func_put(data->func);
-
        return 0;
 }
 
index 2851275e2656f8d1f012fee8a7f740b857c21262..9ba838eb5131ebf4bb9e4d48dfacce5caf858349 100644 (file)
@@ -161,7 +161,7 @@ obj-$(CONFIG_MFD_RC5T583)   += rc5t583.o rc5t583-irq.o
 obj-$(CONFIG_MFD_SEC_CORE)     += sec-core.o sec-irq.o
 obj-$(CONFIG_MFD_SYSCON)       += syscon.o
 obj-$(CONFIG_MFD_LM3533)       += lm3533-core.o lm3533-ctrlbank.o
-obj-$(CONFIG_VEXPRESS_CONFIG)  += vexpress-config.o vexpress-sysreg.o
+obj-$(CONFIG_VEXPRESS_CONFIG)  += vexpress-sysreg.o
 obj-$(CONFIG_MFD_RETU)         += retu-mfd.o
 obj-$(CONFIG_MFD_AS3711)       += as3711.o
 obj-$(CONFIG_MFD_AS3722)       += as3722.o
diff --git a/drivers/mfd/vexpress-config.c b/drivers/mfd/vexpress-config.c
deleted file mode 100644 (file)
index d0db89d..0000000
+++ /dev/null
@@ -1,287 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * Copyright (C) 2012 ARM Limited
- */
-
-#define pr_fmt(fmt) "vexpress-config: " fmt
-
-#include <linux/bitops.h>
-#include <linux/completion.h>
-#include <linux/export.h>
-#include <linux/list.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/vexpress.h>
-
-
-#define VEXPRESS_CONFIG_MAX_BRIDGES 2
-
-static struct vexpress_config_bridge {
-       struct device_node *node;
-       struct vexpress_config_bridge_info *info;
-       struct list_head transactions;
-       spinlock_t transactions_lock;
-} vexpress_config_bridges[VEXPRESS_CONFIG_MAX_BRIDGES];
-
-static DECLARE_BITMAP(vexpress_config_bridges_map,
-               ARRAY_SIZE(vexpress_config_bridges));
-static DEFINE_MUTEX(vexpress_config_bridges_mutex);
-
-struct vexpress_config_bridge *vexpress_config_bridge_register(
-               struct device_node *node,
-               struct vexpress_config_bridge_info *info)
-{
-       struct vexpress_config_bridge *bridge;
-       int i;
-
-       pr_debug("Registering bridge '%s'\n", info->name);
-
-       mutex_lock(&vexpress_config_bridges_mutex);
-       i = find_first_zero_bit(vexpress_config_bridges_map,
-                       ARRAY_SIZE(vexpress_config_bridges));
-       if (i >= ARRAY_SIZE(vexpress_config_bridges)) {
-               pr_err("Can't register more bridges!\n");
-               mutex_unlock(&vexpress_config_bridges_mutex);
-               return NULL;
-       }
-       __set_bit(i, vexpress_config_bridges_map);
-       bridge = &vexpress_config_bridges[i];
-
-       bridge->node = node;
-       bridge->info = info;
-       INIT_LIST_HEAD(&bridge->transactions);
-       spin_lock_init(&bridge->transactions_lock);
-
-       mutex_unlock(&vexpress_config_bridges_mutex);
-
-       return bridge;
-}
-EXPORT_SYMBOL(vexpress_config_bridge_register);
-
-void vexpress_config_bridge_unregister(struct vexpress_config_bridge *bridge)
-{
-       struct vexpress_config_bridge __bridge = *bridge;
-       int i;
-
-       mutex_lock(&vexpress_config_bridges_mutex);
-       for (i = 0; i < ARRAY_SIZE(vexpress_config_bridges); i++)
-               if (&vexpress_config_bridges[i] == bridge)
-                       __clear_bit(i, vexpress_config_bridges_map);
-       mutex_unlock(&vexpress_config_bridges_mutex);
-
-       WARN_ON(!list_empty(&__bridge.transactions));
-       while (!list_empty(&__bridge.transactions))
-               cpu_relax();
-}
-EXPORT_SYMBOL(vexpress_config_bridge_unregister);
-
-
-struct vexpress_config_func {
-       struct vexpress_config_bridge *bridge;
-       void *func;
-};
-
-struct vexpress_config_func *__vexpress_config_func_get(struct device *dev,
-               struct device_node *node)
-{
-       struct device_node *bridge_node;
-       struct vexpress_config_func *func;
-       int i;
-
-       if (WARN_ON(dev && node && dev->of_node != node))
-               return NULL;
-       if (dev && !node)
-               node = dev->of_node;
-
-       func = kzalloc(sizeof(*func), GFP_KERNEL);
-       if (!func)
-               return NULL;
-
-       bridge_node = of_node_get(node);
-       while (bridge_node) {
-               const __be32 *prop = of_get_property(bridge_node,
-                               "arm,vexpress,config-bridge", NULL);
-
-               if (prop) {
-                       bridge_node = of_find_node_by_phandle(
-                                       be32_to_cpup(prop));
-                       break;
-               }
-
-               bridge_node = of_get_next_parent(bridge_node);
-       }
-
-       mutex_lock(&vexpress_config_bridges_mutex);
-       for (i = 0; i < ARRAY_SIZE(vexpress_config_bridges); i++) {
-               struct vexpress_config_bridge *bridge =
-                               &vexpress_config_bridges[i];
-
-               if (test_bit(i, vexpress_config_bridges_map) &&
-                               bridge->node == bridge_node) {
-                       func->bridge = bridge;
-                       func->func = bridge->info->func_get(dev, node);
-                       break;
-               }
-       }
-       mutex_unlock(&vexpress_config_bridges_mutex);
-
-       if (!func->func) {
-               of_node_put(node);
-               kfree(func);
-               return NULL;
-       }
-
-       return func;
-}
-EXPORT_SYMBOL(__vexpress_config_func_get);
-
-void vexpress_config_func_put(struct vexpress_config_func *func)
-{
-       func->bridge->info->func_put(func->func);
-       of_node_put(func->bridge->node);
-       kfree(func);
-}
-EXPORT_SYMBOL(vexpress_config_func_put);
-
-struct vexpress_config_trans {
-       struct vexpress_config_func *func;
-       int offset;
-       bool write;
-       u32 *data;
-       int status;
-       struct completion completion;
-       struct list_head list;
-};
-
-static void vexpress_config_dump_trans(const char *what,
-               struct vexpress_config_trans *trans)
-{
-       pr_debug("%s %s trans %p func 0x%p offset %d data 0x%x status %d\n",
-                       what, trans->write ? "write" : "read", trans,
-                       trans->func->func, trans->offset,
-                       trans->data ? *trans->data : 0, trans->status);
-}
-
-static int vexpress_config_schedule(struct vexpress_config_trans *trans)
-{
-       int status;
-       struct vexpress_config_bridge *bridge = trans->func->bridge;
-       unsigned long flags;
-
-       init_completion(&trans->completion);
-       trans->status = -EFAULT;
-
-       spin_lock_irqsave(&bridge->transactions_lock, flags);
-
-       if (list_empty(&bridge->transactions)) {
-               vexpress_config_dump_trans("Executing", trans);
-               status = bridge->info->func_exec(trans->func->func,
-                               trans->offset, trans->write, trans->data);
-       } else {
-               vexpress_config_dump_trans("Queuing", trans);
-               status = VEXPRESS_CONFIG_STATUS_WAIT;
-       }
-
-       switch (status) {
-       case VEXPRESS_CONFIG_STATUS_DONE:
-               vexpress_config_dump_trans("Finished", trans);
-               trans->status = status;
-               break;
-       case VEXPRESS_CONFIG_STATUS_WAIT:
-               list_add_tail(&trans->list, &bridge->transactions);
-               break;
-       }
-
-       spin_unlock_irqrestore(&bridge->transactions_lock, flags);
-
-       return status;
-}
-
-void vexpress_config_complete(struct vexpress_config_bridge *bridge,
-               int status)
-{
-       struct vexpress_config_trans *trans;
-       unsigned long flags;
-       const char *message = "Completed";
-
-       spin_lock_irqsave(&bridge->transactions_lock, flags);
-
-       trans = list_first_entry(&bridge->transactions,
-                       struct vexpress_config_trans, list);
-       trans->status = status;
-
-       do {
-               vexpress_config_dump_trans(message, trans);
-               list_del(&trans->list);
-               complete(&trans->completion);
-
-               if (list_empty(&bridge->transactions))
-                       break;
-
-               trans = list_first_entry(&bridge->transactions,
-                               struct vexpress_config_trans, list);
-               vexpress_config_dump_trans("Executing pending", trans);
-               trans->status = bridge->info->func_exec(trans->func->func,
-                               trans->offset, trans->write, trans->data);
-               message = "Finished pending";
-       } while (trans->status == VEXPRESS_CONFIG_STATUS_DONE);
-
-       spin_unlock_irqrestore(&bridge->transactions_lock, flags);
-}
-EXPORT_SYMBOL(vexpress_config_complete);
-
-int vexpress_config_wait(struct vexpress_config_trans *trans)
-{
-       wait_for_completion(&trans->completion);
-
-       return trans->status;
-}
-EXPORT_SYMBOL(vexpress_config_wait);
-
-int vexpress_config_read(struct vexpress_config_func *func, int offset,
-               u32 *data)
-{
-       struct vexpress_config_trans trans = {
-               .func = func,
-               .offset = offset,
-               .write = false,
-               .data = data,
-               .status = 0,
-       };
-       int status = vexpress_config_schedule(&trans);
-
-       if (status == VEXPRESS_CONFIG_STATUS_WAIT)
-               status = vexpress_config_wait(&trans);
-
-       return status;
-}
-EXPORT_SYMBOL(vexpress_config_read);
-
-int vexpress_config_write(struct vexpress_config_func *func, int offset,
-               u32 data)
-{
-       struct vexpress_config_trans trans = {
-               .func = func,
-               .offset = offset,
-               .write = true,
-               .data = &data,
-               .status = 0,
-       };
-       int status = vexpress_config_schedule(&trans);
-
-       if (status == VEXPRESS_CONFIG_STATUS_WAIT)
-               status = vexpress_config_wait(&trans);
-
-       return status;
-}
-EXPORT_SYMBOL(vexpress_config_write);
index 35281e804e7ef3879d7c6f18d28d127d7b62338a..b4138a7168db7fac5f72eb57bd1e74ef791bb6d1 100644 (file)
 #include <linux/io.h>
 #include <linux/leds.h>
 #include <linux/of_address.h>
+#include <linux/of_platform.h>
 #include <linux/platform_device.h>
 #include <linux/regulator/driver.h>
+#include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/stat.h>
 #include <linux/timer.h>
 
 static void __iomem *vexpress_sysreg_base;
 static struct device *vexpress_sysreg_dev;
-static int vexpress_master_site;
+static LIST_HEAD(vexpress_sysreg_config_funcs);
+static struct device *vexpress_sysreg_config_bridge;
 
 
+static int vexpress_sysreg_get_master(void)
+{
+       if (readl(vexpress_sysreg_base + SYS_MISC) & SYS_MISC_MASTERSITE)
+               return VEXPRESS_SITE_DB2;
+
+       return VEXPRESS_SITE_DB1;
+}
+
 void vexpress_flags_set(u32 data)
 {
        writel(~0, vexpress_sysreg_base + SYS_FLAGSCLR);
@@ -84,7 +95,7 @@ void vexpress_flags_set(u32 data)
 u32 vexpress_get_procid(int site)
 {
        if (site == VEXPRESS_SITE_MASTER)
-               site = vexpress_master_site;
+               site = vexpress_sysreg_get_master();
 
        return readl(vexpress_sysreg_base + (site == VEXPRESS_SITE_DB1 ?
                        SYS_PROCID0 : SYS_PROCID1));
@@ -114,130 +125,33 @@ void __iomem *vexpress_get_24mhz_clock_base(void)
 }
 
 
-static void vexpress_sysreg_find_prop(struct device_node *node,
-               const char *name, u32 *val)
-{
-       of_node_get(node);
-       while (node) {
-               if (of_property_read_u32(node, name, val) == 0) {
-                       of_node_put(node);
-                       return;
-               }
-               node = of_get_next_parent(node);
-       }
-}
-
-unsigned __vexpress_get_site(struct device *dev, struct device_node *node)
-{
-       u32 site = 0;
-
-       WARN_ON(dev && node && dev->of_node != node);
-       if (dev && !node)
-               node = dev->of_node;
-
-       if (node) {
-               vexpress_sysreg_find_prop(node, "arm,vexpress,site", &site);
-       } else if (dev && dev->bus == &platform_bus_type) {
-               struct platform_device *pdev = to_platform_device(dev);
-
-               if (pdev->num_resources == 1 &&
-                               pdev->resource[0].flags == IORESOURCE_BUS)
-                       site = pdev->resource[0].start;
-       } else if (dev && strncmp(dev_name(dev), "ct:", 3) == 0) {
-               site = VEXPRESS_SITE_MASTER;
-       }
-
-       if (site == VEXPRESS_SITE_MASTER)
-               site = vexpress_master_site;
-
-       return site;
-}
-
-
 struct vexpress_sysreg_config_func {
-       u32 template;
-       u32 device;
+       struct list_head list;
+       struct regmap *regmap;
+       int num_templates;
+       u32 template[0]; /* Keep this last */
 };
 
-static struct vexpress_config_bridge *vexpress_sysreg_config_bridge;
-static struct timer_list vexpress_sysreg_config_timer;
-static u32 *vexpress_sysreg_config_data;
-static int vexpress_sysreg_config_tries;
-
-static void *vexpress_sysreg_config_func_get(struct device *dev,
-               struct device_node *node)
+static int vexpress_sysreg_config_exec(struct vexpress_sysreg_config_func *func,
+               int index, bool write, u32 *data)
 {
-       struct vexpress_sysreg_config_func *config_func;
-       u32 site = 0;
-       u32 position = 0;
-       u32 dcc = 0;
-       u32 func_device[2];
-       int err = -EFAULT;
-
-       if (node) {
-               of_node_get(node);
-               vexpress_sysreg_find_prop(node, "arm,vexpress,site", &site);
-               vexpress_sysreg_find_prop(node, "arm,vexpress,position",
-                               &position);
-               vexpress_sysreg_find_prop(node, "arm,vexpress,dcc", &dcc);
-               err = of_property_read_u32_array(node,
-                               "arm,vexpress-sysreg,func", func_device,
-                               ARRAY_SIZE(func_device));
-               of_node_put(node);
-       } else if (dev && dev->bus == &platform_bus_type) {
-               struct platform_device *pdev = to_platform_device(dev);
-
-               if (pdev->num_resources == 1 &&
-                               pdev->resource[0].flags == IORESOURCE_BUS) {
-                       site = pdev->resource[0].start;
-                       func_device[0] = pdev->resource[0].end;
-                       func_device[1] = pdev->id;
-                       err = 0;
-               }
-       }
-       if (err)
-               return NULL;
-
-       config_func = kzalloc(sizeof(*config_func), GFP_KERNEL);
-       if (!config_func)
-               return NULL;
-
-       config_func->template = SYS_CFGCTRL_DCC(dcc);
-       config_func->template |= SYS_CFGCTRL_FUNC(func_device[0]);
-       config_func->template |= SYS_CFGCTRL_SITE(site == VEXPRESS_SITE_MASTER ?
-                       vexpress_master_site : site);
-       config_func->template |= SYS_CFGCTRL_POSITION(position);
-       config_func->device |= func_device[1];
-
-       dev_dbg(vexpress_sysreg_dev, "func 0x%p = 0x%x, %d\n", config_func,
-                       config_func->template, config_func->device);
-
-       return config_func;
-}
-
-static void vexpress_sysreg_config_func_put(void *func)
-{
-       kfree(func);
-}
-
-static int vexpress_sysreg_config_func_exec(void *func, int offset,
-               bool write, u32 *data)
-{
-       int status;
-       struct vexpress_sysreg_config_func *config_func = func;
-       u32 command;
+       u32 command, status;
+       int tries;
+       long timeout;
 
        if (WARN_ON(!vexpress_sysreg_base))
                return -ENOENT;
 
+       if (WARN_ON(index > func->num_templates))
+               return -EINVAL;
+
        command = readl(vexpress_sysreg_base + SYS_CFGCTRL);
        if (WARN_ON(command & SYS_CFGCTRL_START))
                return -EBUSY;
 
-       command = SYS_CFGCTRL_START;
+       command = func->template[index];
+       command |= SYS_CFGCTRL_START;
        command |= write ? SYS_CFGCTRL_WRITE : 0;
-       command |= config_func->template;
-       command |= SYS_CFGCTRL_DEVICE(config_func->device + offset);
 
        /* Use a canary for reads */
        if (!write)
@@ -250,90 +164,190 @@ static int vexpress_sysreg_config_func_exec(void *func, int offset,
        writel(command, vexpress_sysreg_base + SYS_CFGCTRL);
        mb();
 
-       if (vexpress_sysreg_dev) {
-               /* Schedule completion check */
-               if (!write)
-                       vexpress_sysreg_config_data = data;
-               vexpress_sysreg_config_tries = 100;
-               mod_timer(&vexpress_sysreg_config_timer,
-                               jiffies + usecs_to_jiffies(100));
-               status = VEXPRESS_CONFIG_STATUS_WAIT;
-       } else {
-               /* Early execution, no timer available, have to spin */
-               u32 cfgstat;
+       /* The operation can take ages... Go to sleep, 100us initially */
+       tries = 100;
+       timeout = 100;
+       do {
+               set_current_state(TASK_INTERRUPTIBLE);
+               schedule_timeout(usecs_to_jiffies(timeout));
+               if (signal_pending(current))
+                       return -EINTR;
+
+               status = readl(vexpress_sysreg_base + SYS_CFGSTAT);
+               if (status & SYS_CFGSTAT_ERR)
+                       return -EFAULT;
+
+               if (timeout > 20)
+                       timeout -= 20;
+       } while (--tries && !(status & SYS_CFGSTAT_COMPLETE));
+       if (WARN_ON_ONCE(!tries))
+               return -ETIMEDOUT;
+
+       if (!write) {
+               *data = readl(vexpress_sysreg_base + SYS_CFGDATA);
+               dev_dbg(vexpress_sysreg_dev, "func %p, read data %x\n",
+                               func, *data);
+       }
 
-               do {
-                       cpu_relax();
-                       cfgstat = readl(vexpress_sysreg_base + SYS_CFGSTAT);
-               } while (!cfgstat);
+       return 0;
+}
 
-               if (!write && (cfgstat & SYS_CFGSTAT_COMPLETE))
-                       *data = readl(vexpress_sysreg_base + SYS_CFGDATA);
-               status = VEXPRESS_CONFIG_STATUS_DONE;
+static int vexpress_sysreg_config_read(void *context, unsigned int index,
+               unsigned int *val)
+{
+       struct vexpress_sysreg_config_func *func = context;
 
-               if (cfgstat & SYS_CFGSTAT_ERR)
-                       status = -EINVAL;
-       }
+       return vexpress_sysreg_config_exec(func, index, false, val);
+}
 
-       return status;
+static int vexpress_sysreg_config_write(void *context, unsigned int index,
+               unsigned int val)
+{
+       struct vexpress_sysreg_config_func *func = context;
+
+       return vexpress_sysreg_config_exec(func, index, true, &val);
 }
 
-struct vexpress_config_bridge_info vexpress_sysreg_config_bridge_info = {
-       .name = "vexpress-sysreg",
-       .func_get = vexpress_sysreg_config_func_get,
-       .func_put = vexpress_sysreg_config_func_put,
-       .func_exec = vexpress_sysreg_config_func_exec,
+struct regmap_config vexpress_sysreg_regmap_config = {
+       .lock = vexpress_config_lock,
+       .unlock = vexpress_config_unlock,
+       .reg_bits = 32,
+       .val_bits = 32,
+       .reg_read = vexpress_sysreg_config_read,
+       .reg_write = vexpress_sysreg_config_write,
+       .reg_format_endian = REGMAP_ENDIAN_LITTLE,
+       .val_format_endian = REGMAP_ENDIAN_LITTLE,
 };
 
-static void vexpress_sysreg_config_complete(unsigned long data)
+static struct regmap *vexpress_sysreg_config_regmap_init(struct device *dev,
+               void *context)
 {
-       int status = VEXPRESS_CONFIG_STATUS_DONE;
-       u32 cfgstat = readl(vexpress_sysreg_base + SYS_CFGSTAT);
-
-       if (cfgstat & SYS_CFGSTAT_ERR)
-               status = -EINVAL;
-       if (!vexpress_sysreg_config_tries--)
-               status = -ETIMEDOUT;
-
-       if (status < 0) {
-               dev_err(vexpress_sysreg_dev, "error %d\n", status);
-       } else if (!(cfgstat & SYS_CFGSTAT_COMPLETE)) {
-               mod_timer(&vexpress_sysreg_config_timer,
-                               jiffies + usecs_to_jiffies(50));
-               return;
+       struct platform_device *pdev = to_platform_device(dev);
+       struct vexpress_sysreg_config_func *func;
+       struct property *prop;
+       const __be32 *val = NULL;
+       __be32 energy_quirk[4];
+       int num;
+       u32 site, position, dcc;
+       int err;
+       int i;
+
+       if (dev->of_node) {
+               err = vexpress_config_get_topo(dev->of_node, &site, &position,
+                               &dcc);
+               if (err)
+                       return ERR_PTR(err);
+
+               prop = of_find_property(dev->of_node,
+                               "arm,vexpress-sysreg,func", NULL);
+               if (!prop)
+                       return ERR_PTR(-EINVAL);
+
+               num = prop->length / sizeof(u32) / 2;
+               val = prop->value;
+       } else {
+               if (pdev->num_resources != 1 ||
+                               pdev->resource[0].flags != IORESOURCE_BUS)
+                       return ERR_PTR(-EFAULT);
+
+               site = pdev->resource[0].start;
+               if (site == VEXPRESS_SITE_MASTER)
+                       site = vexpress_sysreg_get_master();
+               position = 0;
+               dcc = 0;
+               num = 1;
        }
 
-       if (vexpress_sysreg_config_data) {
-               *vexpress_sysreg_config_data = readl(vexpress_sysreg_base +
-                               SYS_CFGDATA);
-               dev_dbg(vexpress_sysreg_dev, "read data %x\n",
-                               *vexpress_sysreg_config_data);
-               vexpress_sysreg_config_data = NULL;
+       /*
+        * "arm,vexpress-energy" function used to be described
+        * by its first device only, now it requires both
+        */
+       if (num == 1 && of_device_is_compatible(dev->of_node,
+                       "arm,vexpress-energy")) {
+               num = 2;
+               energy_quirk[0] = *val;
+               energy_quirk[2] = *val++;
+               energy_quirk[1] = *val;
+               energy_quirk[3] = cpu_to_be32(be32_to_cpup(val) + 1);
+               val = energy_quirk;
        }
 
-       vexpress_config_complete(vexpress_sysreg_config_bridge, status);
-}
+       func = kzalloc(sizeof(*func) + sizeof(*func->template) * num,
+                       GFP_KERNEL);
+       if (!func)
+               return NULL;
 
+       func->num_templates = num;
 
-void vexpress_sysreg_setup(struct device_node *node)
-{
-       if (WARN_ON(!vexpress_sysreg_base))
-               return;
+       for (i = 0; i < num; i++) {
+               u32 function, device;
 
-       if (readl(vexpress_sysreg_base + SYS_MISC) & SYS_MISC_MASTERSITE)
-               vexpress_master_site = VEXPRESS_SITE_DB2;
+               if (dev->of_node) {
+                       function = be32_to_cpup(val++);
+                       device = be32_to_cpup(val++);
+               } else {
+                       function = pdev->resource[0].end;
+                       device = pdev->id;
+               }
+
+               dev_dbg(dev, "func %p: %u/%u/%u/%u/%u\n",
+                               func, site, position, dcc,
+                               function, device);
+
+               func->template[i] = SYS_CFGCTRL_DCC(dcc);
+               func->template[i] |= SYS_CFGCTRL_SITE(site);
+               func->template[i] |= SYS_CFGCTRL_POSITION(position);
+               func->template[i] |= SYS_CFGCTRL_FUNC(function);
+               func->template[i] |= SYS_CFGCTRL_DEVICE(device);
+       }
+
+       vexpress_sysreg_regmap_config.max_register = num - 1;
+
+       func->regmap = regmap_init(dev, NULL, func,
+                       &vexpress_sysreg_regmap_config);
+
+       if (IS_ERR(func->regmap))
+               kfree(func);
        else
-               vexpress_master_site = VEXPRESS_SITE_DB1;
+               list_add(&func->list, &vexpress_sysreg_config_funcs);
 
-       vexpress_sysreg_config_bridge = vexpress_config_bridge_register(
-                       node, &vexpress_sysreg_config_bridge_info);
-       WARN_ON(!vexpress_sysreg_config_bridge);
+       return func->regmap;
+}
+
+static void vexpress_sysreg_config_regmap_exit(struct regmap *regmap,
+               void *context)
+{
+       struct vexpress_sysreg_config_func *func, *tmp;
+
+       regmap_exit(regmap);
+
+       list_for_each_entry_safe(func, tmp, &vexpress_sysreg_config_funcs,
+                       list) {
+               if (func->regmap == regmap) {
+                       list_del(&vexpress_sysreg_config_funcs);
+                       kfree(func);
+                       break;
+               }
+       }
+}
+
+static struct vexpress_config_bridge_ops vexpress_sysreg_config_bridge_ops = {
+       .regmap_init = vexpress_sysreg_config_regmap_init,
+       .regmap_exit = vexpress_sysreg_config_regmap_exit,
+};
+
+int vexpress_sysreg_config_device_register(struct platform_device *pdev)
+{
+       pdev->dev.parent = vexpress_sysreg_config_bridge;
+
+       return platform_device_register(pdev);
 }
 
+
 void __init vexpress_sysreg_early_init(void __iomem *base)
 {
        vexpress_sysreg_base = base;
-       vexpress_sysreg_setup(NULL);
+       vexpress_config_set_master(vexpress_sysreg_get_master());
 }
 
 void __init vexpress_sysreg_of_early_init(void)
@@ -344,10 +358,14 @@ void __init vexpress_sysreg_of_early_init(void)
                return;
 
        node = of_find_compatible_node(NULL, NULL, "arm,vexpress-sysreg");
-       if (node) {
-               vexpress_sysreg_base = of_iomap(node, 0);
-               vexpress_sysreg_setup(node);
-       }
+       if (WARN_ON(!node))
+               return;
+
+       vexpress_sysreg_base = of_iomap(node, 0);
+       if (WARN_ON(!vexpress_sysreg_base))
+               return;
+
+       vexpress_config_set_master(vexpress_sysreg_get_master());
 }
 
 
@@ -470,28 +488,22 @@ static int vexpress_sysreg_probe(struct platform_device *pdev)
                return -EBUSY;
        }
 
-       if (!vexpress_sysreg_base) {
+       if (!vexpress_sysreg_base)
                vexpress_sysreg_base = devm_ioremap(&pdev->dev, res->start,
                                resource_size(res));
-               vexpress_sysreg_setup(pdev->dev.of_node);
-       }
 
        if (!vexpress_sysreg_base) {
                dev_err(&pdev->dev, "Failed to obtain base address!\n");
                return -EFAULT;
        }
 
-       setup_timer(&vexpress_sysreg_config_timer,
-                       vexpress_sysreg_config_complete, 0);
-
+       vexpress_config_set_master(vexpress_sysreg_get_master());
        vexpress_sysreg_dev = &pdev->dev;
 
 #ifdef CONFIG_GPIOLIB
        vexpress_sysreg_gpio_chip.dev = &pdev->dev;
        err = gpiochip_add(&vexpress_sysreg_gpio_chip);
        if (err) {
-               vexpress_config_bridge_unregister(
-                               vexpress_sysreg_config_bridge);
                dev_err(&pdev->dev, "Failed to register GPIO chip! (%d)\n",
                                err);
                return err;
@@ -502,6 +514,10 @@ static int vexpress_sysreg_probe(struct platform_device *pdev)
                        sizeof(vexpress_sysreg_leds_pdata));
 #endif
 
+       vexpress_sysreg_config_bridge = vexpress_config_bridge_register(
+                       &pdev->dev, &vexpress_sysreg_config_bridge_ops, NULL);
+       WARN_ON(!vexpress_sysreg_config_bridge);
+
        device_create_file(vexpress_sysreg_dev, &dev_attr_sys_id);
 
        return 0;
@@ -522,7 +538,12 @@ static struct platform_driver vexpress_sysreg_driver = {
 
 static int __init vexpress_sysreg_init(void)
 {
-       vexpress_sysreg_of_early_init();
+       struct device_node *node;
+
+       /* Need the sysreg early, before any other device... */
+       for_each_matching_node(node, vexpress_sysreg_match)
+               of_platform_device_create(node, NULL, NULL);
+
        return platform_driver_register(&vexpress_sysreg_driver);
 }
 core_initcall(vexpress_sysreg_init);
index b95cf71ed69554e8b7c53d77271ba92e39b1e039..4dc102e2b230e9476119d4b3e1d439b17151e084 100644 (file)
 static void vexpress_reset_do(struct device *dev, const char *what)
 {
        int err = -ENOENT;
-       struct vexpress_config_func *func = dev_get_drvdata(dev);
+       struct regmap *reg = dev_get_drvdata(dev);
 
-       if (func) {
-               err = vexpress_config_write(func, 0, 0);
+       if (reg) {
+               err = regmap_write(reg, 0, 0);
                if (!err)
                        mdelay(1000);
        }
@@ -91,17 +91,17 @@ static int vexpress_reset_probe(struct platform_device *pdev)
        enum vexpress_reset_func func;
        const struct of_device_id *match =
                        of_match_device(vexpress_reset_of_match, &pdev->dev);
-       struct vexpress_config_func *config_func;
+       struct regmap *regmap;
 
        if (match)
                func = (enum vexpress_reset_func)match->data;
        else
                func = pdev->id_entry->driver_data;
 
-       config_func = vexpress_config_func_get_by_dev(&pdev->dev);
-       if (!config_func)
-               return -EINVAL;
-       dev_set_drvdata(&pdev->dev, config_func);
+       regmap = devm_regmap_init_vexpress_config(&pdev->dev);
+       if (IS_ERR(regmap))
+               return PTR_ERR(regmap);
+       dev_set_drvdata(&pdev->dev, regmap);
 
        switch (func) {
        case FUNC_SHUTDOWN:
index f3ae28a7e66371143b6be01c9640712533faf541..2863428813e488c80ed4656fc2e683be9a2dd9f3 100644 (file)
 struct vexpress_regulator {
        struct regulator_desc desc;
        struct regulator_dev *regdev;
-       struct vexpress_config_func *func;
+       struct regmap *regmap;
 };
 
 static int vexpress_regulator_get_voltage(struct regulator_dev *regdev)
 {
        struct vexpress_regulator *reg = rdev_get_drvdata(regdev);
        u32 uV;
-       int err = vexpress_config_read(reg->func, 0, &uV);
+       int err = regmap_read(reg->regmap, 0, &uV);
 
        return err ? err : uV;
 }
@@ -43,7 +43,7 @@ static int vexpress_regulator_set_voltage(struct regulator_dev *regdev,
 {
        struct vexpress_regulator *reg = rdev_get_drvdata(regdev);
 
-       return vexpress_config_write(reg->func, 0, min_uV);
+       return regmap_write(reg->regmap, 0, min_uV);
 }
 
 static struct regulator_ops vexpress_regulator_ops_ro = {
@@ -57,22 +57,17 @@ static struct regulator_ops vexpress_regulator_ops = {
 
 static int vexpress_regulator_probe(struct platform_device *pdev)
 {
-       int err;
        struct vexpress_regulator *reg;
        struct regulator_init_data *init_data;
        struct regulator_config config = { };
 
        reg = devm_kzalloc(&pdev->dev, sizeof(*reg), GFP_KERNEL);
-       if (!reg) {
-               err = -ENOMEM;
-               goto error_kzalloc;
-       }
+       if (!reg)
+               return -ENOMEM;
 
-       reg->func = vexpress_config_func_get_by_dev(&pdev->dev);
-       if (!reg->func) {
-               err = -ENXIO;
-               goto error_get_func;
-       }
+       reg->regmap = devm_regmap_init_vexpress_config(&pdev->dev);
+       if (IS_ERR(reg->regmap))
+               return PTR_ERR(reg->regmap);
 
        reg->desc.name = dev_name(&pdev->dev);
        reg->desc.type = REGULATOR_VOLTAGE;
@@ -80,10 +75,8 @@ static int vexpress_regulator_probe(struct platform_device *pdev)
        reg->desc.continuous_voltage_range = true;
 
        init_data = of_get_regulator_init_data(&pdev->dev, pdev->dev.of_node);
-       if (!init_data) {
-               err = -EINVAL;
-               goto error_get_regulator_init_data;
-       }
+       if (!init_data)
+               return -EINVAL;
 
        init_data->constraints.apply_uV = 0;
        if (init_data->constraints.min_uV && init_data->constraints.max_uV)
@@ -97,29 +90,11 @@ static int vexpress_regulator_probe(struct platform_device *pdev)
        config.of_node = pdev->dev.of_node;
 
        reg->regdev = devm_regulator_register(&pdev->dev, &reg->desc, &config);
-       if (IS_ERR(reg->regdev)) {
-               err = PTR_ERR(reg->regdev);
-               goto error_regulator_register;
-       }
+       if (IS_ERR(reg->regdev))
+               return PTR_ERR(reg->regdev);
 
        platform_set_drvdata(pdev, reg);
 
-       return 0;
-
-error_regulator_register:
-error_get_regulator_init_data:
-       vexpress_config_func_put(reg->func);
-error_get_func:
-error_kzalloc:
-       return err;
-}
-
-static int vexpress_regulator_remove(struct platform_device *pdev)
-{
-       struct vexpress_regulator *reg = platform_get_drvdata(pdev);
-
-       vexpress_config_func_put(reg->func);
-
        return 0;
 }
 
@@ -130,7 +105,6 @@ static struct of_device_id vexpress_regulator_of_match[] = {
 
 static struct platform_driver vexpress_regulator_driver = {
        .probe = vexpress_regulator_probe,
-       .remove = vexpress_regulator_remove,
        .driver = {
                .name = DRVNAME,
                .owner = THIS_MODULE,
index 617c01b8f74a353d3c3993d262dba84c8bf57a19..6b206ba6aa0e992042293c20205305146bf58ceb 100644 (file)
 #define _LINUX_VEXPRESS_H
 
 #include <linux/device.h>
+#include <linux/platform_device.h>
 #include <linux/reboot.h>
+#include <linux/regmap.h>
 
 #define VEXPRESS_SITE_MB               0
 #define VEXPRESS_SITE_DB1              1
 #define VEXPRESS_SITE_DB2              2
 #define VEXPRESS_SITE_MASTER           0xf
 
-#define VEXPRESS_CONFIG_STATUS_DONE    0
-#define VEXPRESS_CONFIG_STATUS_WAIT    1
-
 #define VEXPRESS_GPIO_MMC_CARDIN       0
 #define VEXPRESS_GPIO_MMC_WPROT                1
 #define VEXPRESS_GPIO_FLASH_WPn                2
        .flags = IORESOURCE_BUS,        \
 }
 
-/* Config bridge API */
+/* Config infrastructure */
 
-/**
- * struct vexpress_config_bridge_info - description of the platform
- * configuration infrastructure bridge.
- *
- * @name:      Bridge name
- *
- * @func_get:  Obtains pointer to a configuration function for a given
- *             device or a Device Tree node, to be used with @func_put
- *             and @func_exec. The node pointer should take precedence
- *             over device pointer when both are passed.
- *
- * @func_put:  Tells the bridge that the function will not be used any
- *             more, so all allocated resources can be released.
- *
- * @func_exec: Executes a configuration function read or write operation.
- *             The offset selects a 32 bit word of the value accessed.
- *             Must return VEXPRESS_CONFIG_STATUS_DONE when operation
- *             is finished immediately, VEXPRESS_CONFIG_STATUS_WAIT when
- *             will be completed in some time or negative value in case
- *             of error.
- */
-struct vexpress_config_bridge_info {
-       const char *name;
-       void *(*func_get)(struct device *dev, struct device_node *node);
-       void (*func_put)(void *func);
-       int (*func_exec)(void *func, int offset, bool write, u32 *data);
-};
+void vexpress_config_set_master(u32 site);
+u32 vexpress_config_get_master(void);
 
-struct vexpress_config_bridge;
+void vexpress_config_lock(void *arg);
+void vexpress_config_unlock(void *arg);
 
-struct vexpress_config_bridge *vexpress_config_bridge_register(
-               struct device_node *node,
-               struct vexpress_config_bridge_info *info);
-void vexpress_config_bridge_unregister(struct vexpress_config_bridge *bridge);
+int vexpress_config_get_topo(struct device_node *node, u32 *site,
+               u32 *position, u32 *dcc);
 
-void vexpress_config_complete(struct vexpress_config_bridge *bridge,
-               int status);
+/* Config bridge API */
 
-/* Config function API */
+struct vexpress_config_bridge_ops {
+       struct regmap * (*regmap_init)(struct device *dev, void *context);
+       void (*regmap_exit)(struct regmap *regmap, void *context);
+};
 
-struct vexpress_config_func;
+struct device *vexpress_config_bridge_register(struct device *parent,
+               struct vexpress_config_bridge_ops *ops, void *context);
 
-struct vexpress_config_func *__vexpress_config_func_get(struct device *dev,
-               struct device_node *node);
-#define vexpress_config_func_get_by_dev(dev) \
-               __vexpress_config_func_get(dev, NULL)
-#define vexpress_config_func_get_by_node(node) \
-               __vexpress_config_func_get(NULL, node)
-void vexpress_config_func_put(struct vexpress_config_func *func);
+/* Config regmap API */
 
-/* Both may sleep! */
-int vexpress_config_read(struct vexpress_config_func *func, int offset,
-               u32 *data);
-int vexpress_config_write(struct vexpress_config_func *func, int offset,
-               u32 data);
+struct regmap *devm_regmap_init_vexpress_config(struct device *dev);
 
 /* Platform control */
 
@@ -109,19 +75,12 @@ u32 vexpress_get_hbi(int site);
 void *vexpress_get_24mhz_clock_base(void);
 void vexpress_flags_set(u32 data);
 
-#define vexpress_get_site_by_node(node) __vexpress_get_site(NULL, node)
-#define vexpress_get_site_by_dev(dev) __vexpress_get_site(dev, NULL)
-unsigned __vexpress_get_site(struct device *dev, struct device_node *node);
-
 void vexpress_sysreg_early_init(void __iomem *base);
 void vexpress_sysreg_of_early_init(void);
+int vexpress_sysreg_config_device_register(struct platform_device *pdev);
 
 /* Clocks */
 
-struct clk *vexpress_osc_setup(struct device *dev);
-void vexpress_osc_of_setup(struct device_node *node);
-
 void vexpress_clk_init(void __iomem *sp810_base);
-void vexpress_clk_of_init(void);
 
 #endif