diff options
author | Dong Aisheng <dong.aisheng@linaro.org> | 2012-09-04 22:57:13 -0400 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2012-09-17 09:24:14 -0400 |
commit | 87d687301f380729ec320619f100f3ba39f3693d (patch) | |
tree | 3f6f274a01552da3b5f7af4dc1eaaad04a11c1b4 /drivers | |
parent | a435ae1d51e2f18414f2a87219fdbe068231e692 (diff) |
mfd: Add syscon driver based on regmap
Add regmap based syscon driver.
This is usually used for access misc bits in registers which does not belong
to a specific module, for example, IMX IOMUXC GPR and ANATOP.
With this driver, client can use generic regmap API to access registers
which are registered into syscon.
Reviewed-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Acked-by: Stephen Warren <swarren@wwwdotorg.org>
Signed-off-by: Dong Aisheng <dong.aisheng@linaro.org>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/mfd/Kconfig | 8 | ||||
-rw-r--r-- | drivers/mfd/Makefile | 1 | ||||
-rw-r--r-- | drivers/mfd/syscon.c | 176 |
3 files changed, 185 insertions, 0 deletions
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 | ||
1007 | config 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 | |||
1007 | config MFD_PALMAS | 1015 | config 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 | |||
132 | obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o | 132 | obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o |
133 | obj-$(CONFIG_MFD_SEC_CORE) += sec-core.o sec-irq.o | 133 | obj-$(CONFIG_MFD_SEC_CORE) += sec-core.o sec-irq.o |
134 | obj-$(CONFIG_MFD_ANATOP) += anatop-mfd.o | 134 | obj-$(CONFIG_MFD_ANATOP) += anatop-mfd.o |
135 | obj-$(CONFIG_MFD_SYSCON) += syscon.o | ||
135 | obj-$(CONFIG_MFD_LM3533) += lm3533-core.o lm3533-ctrlbank.o | 136 | obj-$(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 | |||
24 | static struct platform_driver syscon_driver; | ||
25 | |||
26 | struct syscon { | ||
27 | struct device *dev; | ||
28 | void __iomem *base; | ||
29 | struct regmap *regmap; | ||
30 | }; | ||
31 | |||
32 | static 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 | |||
40 | struct 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 | } | ||
54 | EXPORT_SYMBOL_GPL(syscon_node_to_regmap); | ||
55 | |||
56 | struct 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 | } | ||
70 | EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_compatible); | ||
71 | |||
72 | struct 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 | } | ||
87 | EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_phandle); | ||
88 | |||
89 | static const struct of_device_id of_syscon_match[] = { | ||
90 | { .compatible = "syscon", }, | ||
91 | { }, | ||
92 | }; | ||
93 | |||
94 | static struct regmap_config syscon_regmap_config = { | ||
95 | .reg_bits = 32, | ||
96 | .val_bits = 32, | ||
97 | .reg_stride = 4, | ||
98 | }; | ||
99 | |||
100 | static 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 | |||
141 | static 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 | |||
152 | static 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 | |||
162 | static int __init syscon_init(void) | ||
163 | { | ||
164 | return platform_driver_register(&syscon_driver); | ||
165 | } | ||
166 | postcore_initcall(syscon_init); | ||
167 | |||
168 | static void __exit syscon_exit(void) | ||
169 | { | ||
170 | platform_driver_unregister(&syscon_driver); | ||
171 | } | ||
172 | module_exit(syscon_exit); | ||
173 | |||
174 | MODULE_AUTHOR("Dong Aisheng <dong.aisheng@linaro.org>"); | ||
175 | MODULE_DESCRIPTION("System Control driver"); | ||
176 | MODULE_LICENSE("GPL v2"); | ||