aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2010-10-19 18:00:11 -0400
committerSamuel Ortiz <sameo@linux.intel.com>2010-10-28 18:30:25 -0400
commit2aa13b9e8096ab7f12c67f3a5b9a38b194a30ce9 (patch)
tree648b95fc9019f284e172de9b9241df11fb865738
parente5b486841d572c5ac83c798f82f4f67cbbac5320 (diff)
mfd: Add WM831x SPI support
Implement support for controlling WM831x and WM832x devices using SPI. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
-rw-r--r--drivers/mfd/Kconfig11
-rw-r--r--drivers/mfd/Makefile1
-rw-r--r--drivers/mfd/wm831x-spi.c232
3 files changed, 244 insertions, 0 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 2fb1e892331..3a1493b8b5e 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -329,6 +329,17 @@ config MFD_WM831X_I2C
329 for accessing the device, additional drivers must be enabled in 329 for accessing the device, additional drivers must be enabled in
330 order to use the functionality of the device. 330 order to use the functionality of the device.
331 331
332config MFD_WM831X_SPI
333 bool "Support Wolfson Microelectronics WM831x/2x PMICs with SPI"
334 select MFD_CORE
335 select MFD_WM831X
336 depends on SPI_MASTER && GENERIC_HARDIRQS
337 help
338 Support for the Wolfson Microelecronics WM831x and WM832x PMICs
339 when controlled using SPI. This driver provides common support
340 for accessing the device, additional drivers must be enabled in
341 order to use the functionality of the device.
342
332config MFD_WM8350 343config MFD_WM8350
333 bool 344 bool
334 depends on GENERIC_HARDIRQS 345 depends on GENERIC_HARDIRQS
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index c9ef41b13bf..f54b3659abb 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -25,6 +25,7 @@ obj-$(CONFIG_MFD_WM8400) += wm8400-core.o
25wm831x-objs := wm831x-core.o wm831x-irq.o wm831x-otp.o 25wm831x-objs := wm831x-core.o wm831x-irq.o wm831x-otp.o
26obj-$(CONFIG_MFD_WM831X) += wm831x.o 26obj-$(CONFIG_MFD_WM831X) += wm831x.o
27obj-$(CONFIG_MFD_WM831X_I2C) += wm831x-i2c.o 27obj-$(CONFIG_MFD_WM831X_I2C) += wm831x-i2c.o
28obj-$(CONFIG_MFD_WM831X_SPI) += wm831x-spi.o
28wm8350-objs := wm8350-core.o wm8350-regmap.o wm8350-gpio.o 29wm8350-objs := wm8350-core.o wm8350-regmap.o wm8350-gpio.o
29wm8350-objs += wm8350-irq.o 30wm8350-objs += wm8350-irq.o
30obj-$(CONFIG_MFD_WM8350) += wm8350.o 31obj-$(CONFIG_MFD_WM8350) += wm8350.o
diff --git a/drivers/mfd/wm831x-spi.c b/drivers/mfd/wm831x-spi.c
new file mode 100644
index 00000000000..2789b151b0f
--- /dev/null
+++ b/drivers/mfd/wm831x-spi.c
@@ -0,0 +1,232 @@
1/*
2 * wm831x-spi.c -- SPI access for Wolfson WM831x PMICs
3 *
4 * Copyright 2009,2010 Wolfson Microelectronics PLC.
5 *
6 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 *
13 */
14
15#include <linux/kernel.h>
16#include <linux/module.h>
17#include <linux/spi/spi.h>
18
19#include <linux/mfd/wm831x/core.h>
20
21static int wm831x_spi_read_device(struct wm831x *wm831x, unsigned short reg,
22 int bytes, void *dest)
23{
24 u16 tx_val;
25 u16 *d = dest;
26 int r, ret;
27
28 /* Go register at a time */
29 for (r = reg; r < reg + (bytes / 2); r++) {
30 tx_val = r | 0x8000;
31
32 ret = spi_write_then_read(wm831x->control_data,
33 (u8 *)&tx_val, 2, (u8 *)d, 2);
34 if (ret != 0)
35 return ret;
36
37 *d = be16_to_cpu(*d);
38
39 d++;
40 }
41
42 return 0;
43}
44
45static int wm831x_spi_write_device(struct wm831x *wm831x, unsigned short reg,
46 int bytes, void *src)
47{
48 struct spi_device *spi = wm831x->control_data;
49 u16 *s = src;
50 u16 data[2];
51 int ret, r;
52
53 /* Go register at a time */
54 for (r = reg; r < reg + (bytes / 2); r++) {
55 data[0] = r;
56 data[1] = *s++;
57
58 ret = spi_write(spi, (char *)&data, sizeof(data));
59 if (ret != 0)
60 return ret;
61 }
62
63 return 0;
64}
65
66static int __devinit wm831x_spi_probe(struct spi_device *spi)
67{
68 struct wm831x *wm831x;
69 enum wm831x_parent type;
70
71 /* Currently SPI support for ID tables is unmerged, we're faking it */
72 if (strcmp(spi->modalias, "wm8310") == 0)
73 type = WM8310;
74 else if (strcmp(spi->modalias, "wm8311") == 0)
75 type = WM8311;
76 else if (strcmp(spi->modalias, "wm8312") == 0)
77 type = WM8312;
78 else if (strcmp(spi->modalias, "wm8320") == 0)
79 type = WM8320;
80 else if (strcmp(spi->modalias, "wm8321") == 0)
81 type = WM8321;
82 else if (strcmp(spi->modalias, "wm8325") == 0)
83 type = WM8325;
84 else {
85 dev_err(&spi->dev, "Unknown device type\n");
86 return -EINVAL;
87 }
88
89 wm831x = kzalloc(sizeof(struct wm831x), GFP_KERNEL);
90 if (wm831x == NULL)
91 return -ENOMEM;
92
93 spi->bits_per_word = 16;
94 spi->mode = SPI_MODE_0;
95
96 dev_set_drvdata(&spi->dev, wm831x);
97 wm831x->dev = &spi->dev;
98 wm831x->control_data = spi;
99 wm831x->read_dev = wm831x_spi_read_device;
100 wm831x->write_dev = wm831x_spi_write_device;
101
102 return wm831x_device_init(wm831x, type, spi->irq);
103}
104
105static int __devexit wm831x_spi_remove(struct spi_device *spi)
106{
107 struct wm831x *wm831x = dev_get_drvdata(&spi->dev);
108
109 wm831x_device_exit(wm831x);
110
111 return 0;
112}
113
114static int wm831x_spi_suspend(struct spi_device *spi, pm_message_t m)
115{
116 struct wm831x *wm831x = dev_get_drvdata(&spi->dev);
117
118 return wm831x_device_suspend(wm831x);
119}
120
121static struct spi_driver wm8310_spi_driver = {
122 .driver = {
123 .name = "wm8310",
124 .bus = &spi_bus_type,
125 .owner = THIS_MODULE,
126 },
127 .probe = wm831x_spi_probe,
128 .remove = __devexit_p(wm831x_spi_remove),
129 .suspend = wm831x_spi_suspend,
130};
131
132static struct spi_driver wm8311_spi_driver = {
133 .driver = {
134 .name = "wm8311",
135 .bus = &spi_bus_type,
136 .owner = THIS_MODULE,
137 },
138 .probe = wm831x_spi_probe,
139 .remove = __devexit_p(wm831x_spi_remove),
140 .suspend = wm831x_spi_suspend,
141};
142
143static struct spi_driver wm8312_spi_driver = {
144 .driver = {
145 .name = "wm8312",
146 .bus = &spi_bus_type,
147 .owner = THIS_MODULE,
148 },
149 .probe = wm831x_spi_probe,
150 .remove = __devexit_p(wm831x_spi_remove),
151 .suspend = wm831x_spi_suspend,
152};
153
154static struct spi_driver wm8320_spi_driver = {
155 .driver = {
156 .name = "wm8320",
157 .bus = &spi_bus_type,
158 .owner = THIS_MODULE,
159 },
160 .probe = wm831x_spi_probe,
161 .remove = __devexit_p(wm831x_spi_remove),
162 .suspend = wm831x_spi_suspend,
163};
164
165static struct spi_driver wm8321_spi_driver = {
166 .driver = {
167 .name = "wm8321",
168 .bus = &spi_bus_type,
169 .owner = THIS_MODULE,
170 },
171 .probe = wm831x_spi_probe,
172 .remove = __devexit_p(wm831x_spi_remove),
173 .suspend = wm831x_spi_suspend,
174};
175
176static struct spi_driver wm8325_spi_driver = {
177 .driver = {
178 .name = "wm8325",
179 .bus = &spi_bus_type,
180 .owner = THIS_MODULE,
181 },
182 .probe = wm831x_spi_probe,
183 .remove = __devexit_p(wm831x_spi_remove),
184 .suspend = wm831x_spi_suspend,
185};
186
187static int __init wm831x_spi_init(void)
188{
189 int ret;
190
191 ret = spi_register_driver(&wm8310_spi_driver);
192 if (ret != 0)
193 pr_err("Failed to register WM8310 SPI driver: %d\n", ret);
194
195 ret = spi_register_driver(&wm8311_spi_driver);
196 if (ret != 0)
197 pr_err("Failed to register WM8311 SPI driver: %d\n", ret);
198
199 ret = spi_register_driver(&wm8312_spi_driver);
200 if (ret != 0)
201 pr_err("Failed to register WM8312 SPI driver: %d\n", ret);
202
203 ret = spi_register_driver(&wm8320_spi_driver);
204 if (ret != 0)
205 pr_err("Failed to register WM8320 SPI driver: %d\n", ret);
206
207 ret = spi_register_driver(&wm8321_spi_driver);
208 if (ret != 0)
209 pr_err("Failed to register WM8321 SPI driver: %d\n", ret);
210
211 ret = spi_register_driver(&wm8325_spi_driver);
212 if (ret != 0)
213 pr_err("Failed to register WM8325 SPI driver: %d\n", ret);
214
215 return 0;
216}
217subsys_initcall(wm831x_spi_init);
218
219static void __exit wm831x_spi_exit(void)
220{
221 spi_unregister_driver(&wm8325_spi_driver);
222 spi_unregister_driver(&wm8321_spi_driver);
223 spi_unregister_driver(&wm8320_spi_driver);
224 spi_unregister_driver(&wm8312_spi_driver);
225 spi_unregister_driver(&wm8311_spi_driver);
226 spi_unregister_driver(&wm8310_spi_driver);
227}
228module_exit(wm831x_spi_exit);
229
230MODULE_DESCRIPTION("SPI support for WM831x/2x AudioPlus PMICs");
231MODULE_LICENSE("GPL");
232MODULE_AUTHOR("Mark Brown");