aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/mfd/syscon.txt20
-rw-r--r--drivers/mfd/Kconfig8
-rw-r--r--drivers/mfd/Makefile1
-rw-r--r--drivers/mfd/syscon.c176
-rw-r--r--include/linux/mfd/syscon.h23
5 files changed, 228 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/mfd/syscon.txt b/Documentation/devicetree/bindings/mfd/syscon.txt
new file mode 100644
index 000000000000..fe8150bb3248
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/syscon.txt
@@ -0,0 +1,20 @@
1* System Controller Registers R/W driver
2
3System controller node represents a register region containing a set
4of miscellaneous registers. The registers are not cohesive enough to
5represent as any specific type of device. The typical use-case is for
6some other node's driver, or platform-specific code, to acquire a
7reference to the syscon node (e.g. by phandle, node path, or search
8using a specific compatible value), interrogate the node (or associated
9OS driver) to determine the location of the registers, and access the
10registers directly.
11
12Required properties:
13- compatible: Should contain "syscon".
14- reg: the register region can be accessed from syscon
15
16Examples:
17gpr: iomuxc-gpr@020e0000 {
18 compatible = "fsl,imx6q-iomuxc-gpr", "syscon";
19 reg = <0x020e0000 0x38>;
20};
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 856ec00ab787..909d84b1f5c1 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -1004,6 +1004,14 @@ config MFD_ANATOP
1004 MFD controller. This controller embeds regulator and 1004 MFD controller. This controller embeds regulator and
1005 thermal devices for Freescale i.MX platforms. 1005 thermal devices for Freescale i.MX platforms.
1006 1006
1007config MFD_SYSCON
1008 bool "System Controller Register R/W Based on Regmap"
1009 depends on OF
1010 select REGMAP_MMIO
1011 help
1012 Select this option to enable accessing system control registers
1013 via regmap.
1014
1007config MFD_PALMAS 1015config MFD_PALMAS
1008 bool "Support for the TI Palmas series chips" 1016 bool "Support for the TI Palmas series chips"
1009 select MFD_CORE 1017 select MFD_CORE
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 2a4108d98442..07b66aff30b4 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -132,4 +132,5 @@ obj-$(CONFIG_MFD_PALMAS) += palmas.o
132obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o 132obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o
133obj-$(CONFIG_MFD_SEC_CORE) += sec-core.o sec-irq.o 133obj-$(CONFIG_MFD_SEC_CORE) += sec-core.o sec-irq.o
134obj-$(CONFIG_MFD_ANATOP) += anatop-mfd.o 134obj-$(CONFIG_MFD_ANATOP) += anatop-mfd.o
135obj-$(CONFIG_MFD_SYSCON) += syscon.o
135obj-$(CONFIG_MFD_LM3533) += lm3533-core.o lm3533-ctrlbank.o 136obj-$(CONFIG_MFD_LM3533) += lm3533-core.o lm3533-ctrlbank.o
diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c
new file mode 100644
index 000000000000..65fe609026cc
--- /dev/null
+++ b/drivers/mfd/syscon.c
@@ -0,0 +1,176 @@
1/*
2 * System Control Driver
3 *
4 * Copyright (C) 2012 Freescale Semiconductor, Inc.
5 * Copyright (C) 2012 Linaro Ltd.
6 *
7 * Author: Dong Aisheng <dong.aisheng@linaro.org>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 */
14
15#include <linux/err.h>
16#include <linux/io.h>
17#include <linux/module.h>
18#include <linux/of.h>
19#include <linux/of_address.h>
20#include <linux/of_platform.h>
21#include <linux/platform_device.h>
22#include <linux/regmap.h>
23
24static struct platform_driver syscon_driver;
25
26struct syscon {
27 struct device *dev;
28 void __iomem *base;
29 struct regmap *regmap;
30};
31
32static int syscon_match(struct device *dev, void *data)
33{
34 struct syscon *syscon = dev_get_drvdata(dev);
35 struct device_node *dn = data;
36
37 return (syscon->dev->of_node == dn) ? 1 : 0;
38}
39
40struct regmap *syscon_node_to_regmap(struct device_node *np)
41{
42 struct syscon *syscon;
43 struct device *dev;
44
45 dev = driver_find_device(&syscon_driver.driver, NULL, np,
46 syscon_match);
47 if (!dev)
48 return ERR_PTR(-EPROBE_DEFER);
49
50 syscon = dev_get_drvdata(dev);
51
52 return syscon->regmap;
53}
54EXPORT_SYMBOL_GPL(syscon_node_to_regmap);
55
56struct regmap *syscon_regmap_lookup_by_compatible(const char *s)
57{
58 struct device_node *syscon_np;
59 struct regmap *regmap;
60
61 syscon_np = of_find_compatible_node(NULL, NULL, s);
62 if (!syscon_np)
63 return ERR_PTR(-ENODEV);
64
65 regmap = syscon_node_to_regmap(syscon_np);
66 of_node_put(syscon_np);
67
68 return regmap;
69}
70EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_compatible);
71
72struct regmap *syscon_regmap_lookup_by_phandle(struct device_node *np,
73 const char *property)
74{
75 struct device_node *syscon_np;
76 struct regmap *regmap;
77
78 syscon_np = of_parse_phandle(np, property, 0);
79 if (!syscon_np)
80 return ERR_PTR(-ENODEV);
81
82 regmap = syscon_node_to_regmap(syscon_np);
83 of_node_put(syscon_np);
84
85 return regmap;
86}
87EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_phandle);
88
89static const struct of_device_id of_syscon_match[] = {
90 { .compatible = "syscon", },
91 { },
92};
93
94static struct regmap_config syscon_regmap_config = {
95 .reg_bits = 32,
96 .val_bits = 32,
97 .reg_stride = 4,
98};
99
100static int __devinit syscon_probe(struct platform_device *pdev)
101{
102 struct device *dev = &pdev->dev;
103 struct device_node *np = dev->of_node;
104 struct syscon *syscon;
105 struct resource res;
106 int ret;
107
108 if (!np)
109 return -ENOENT;
110
111 syscon = devm_kzalloc(dev, sizeof(struct syscon),
112 GFP_KERNEL);
113 if (!syscon)
114 return -ENOMEM;
115
116 syscon->base = of_iomap(np, 0);
117 if (!syscon->base)
118 return -EADDRNOTAVAIL;
119
120 ret = of_address_to_resource(np, 0, &res);
121 if (ret)
122 return ret;
123
124 syscon_regmap_config.max_register = res.end - res.start - 3;
125 syscon->regmap = devm_regmap_init_mmio(dev, syscon->base,
126 &syscon_regmap_config);
127 if (IS_ERR(syscon->regmap)) {
128 dev_err(dev, "regmap init failed\n");
129 return PTR_ERR(syscon->regmap);
130 }
131
132 syscon->dev = dev;
133 platform_set_drvdata(pdev, syscon);
134
135 dev_info(dev, "syscon regmap start 0x%x end 0x%x registered\n",
136 res.start, res.end);
137
138 return 0;
139}
140
141static int __devexit syscon_remove(struct platform_device *pdev)
142{
143 struct syscon *syscon;
144
145 syscon = platform_get_drvdata(pdev);
146 iounmap(syscon->base);
147 platform_set_drvdata(pdev, NULL);
148
149 return 0;
150}
151
152static struct platform_driver syscon_driver = {
153 .driver = {
154 .name = "syscon",
155 .owner = THIS_MODULE,
156 .of_match_table = of_syscon_match,
157 },
158 .probe = syscon_probe,
159 .remove = __devexit_p(syscon_remove),
160};
161
162static int __init syscon_init(void)
163{
164 return platform_driver_register(&syscon_driver);
165}
166postcore_initcall(syscon_init);
167
168static void __exit syscon_exit(void)
169{
170 platform_driver_unregister(&syscon_driver);
171}
172module_exit(syscon_exit);
173
174MODULE_AUTHOR("Dong Aisheng <dong.aisheng@linaro.org>");
175MODULE_DESCRIPTION("System Control driver");
176MODULE_LICENSE("GPL v2");
diff --git a/include/linux/mfd/syscon.h b/include/linux/mfd/syscon.h
new file mode 100644
index 000000000000..6aeb6b8da64d
--- /dev/null
+++ b/include/linux/mfd/syscon.h
@@ -0,0 +1,23 @@
1/*
2 * System Control Driver
3 *
4 * Copyright (C) 2012 Freescale Semiconductor, Inc.
5 * Copyright (C) 2012 Linaro Ltd.
6 *
7 * Author: Dong Aisheng <dong.aisheng@linaro.org>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 */
14
15#ifndef __LINUX_MFD_SYSCON_H__
16#define __LINUX_MFD_SYSCON_H__
17
18extern struct regmap *syscon_node_to_regmap(struct device_node *np);
19extern struct regmap *syscon_regmap_lookup_by_compatible(const char *s);
20extern struct regmap *syscon_regmap_lookup_by_phandle(
21 struct device_node *np,
22 const char *property);
23#endif /* __LINUX_MFD_SYSCON_H__ */