blob: eed8e4f7a5a14c6c724097567f1b817419dba3a9 [file] [log] [blame]
Mark Brown2aa13b92010-10-20 00:00:11 +02001/*
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>
Mark Brown87d19062011-02-01 11:46:12 +000017#include <linux/pm.h>
Mark Brown2aa13b92010-10-20 00:00:11 +020018#include <linux/spi/spi.h>
19
20#include <linux/mfd/wm831x/core.h>
21
22static int wm831x_spi_read_device(struct wm831x *wm831x, unsigned short reg,
23 int bytes, void *dest)
24{
25 u16 tx_val;
26 u16 *d = dest;
27 int r, ret;
28
29 /* Go register at a time */
30 for (r = reg; r < reg + (bytes / 2); r++) {
31 tx_val = r | 0x8000;
32
33 ret = spi_write_then_read(wm831x->control_data,
34 (u8 *)&tx_val, 2, (u8 *)d, 2);
35 if (ret != 0)
36 return ret;
37
38 *d = be16_to_cpu(*d);
39
40 d++;
41 }
42
43 return 0;
44}
45
46static int wm831x_spi_write_device(struct wm831x *wm831x, unsigned short reg,
47 int bytes, void *src)
48{
49 struct spi_device *spi = wm831x->control_data;
50 u16 *s = src;
51 u16 data[2];
52 int ret, r;
53
54 /* Go register at a time */
55 for (r = reg; r < reg + (bytes / 2); r++) {
56 data[0] = r;
57 data[1] = *s++;
58
59 ret = spi_write(spi, (char *)&data, sizeof(data));
60 if (ret != 0)
61 return ret;
62 }
63
64 return 0;
65}
66
67static int __devinit wm831x_spi_probe(struct spi_device *spi)
68{
69 struct wm831x *wm831x;
70 enum wm831x_parent type;
71
72 /* Currently SPI support for ID tables is unmerged, we're faking it */
73 if (strcmp(spi->modalias, "wm8310") == 0)
74 type = WM8310;
75 else if (strcmp(spi->modalias, "wm8311") == 0)
76 type = WM8311;
77 else if (strcmp(spi->modalias, "wm8312") == 0)
78 type = WM8312;
79 else if (strcmp(spi->modalias, "wm8320") == 0)
80 type = WM8320;
81 else if (strcmp(spi->modalias, "wm8321") == 0)
82 type = WM8321;
83 else if (strcmp(spi->modalias, "wm8325") == 0)
84 type = WM8325;
Mark Brown412dc112010-11-24 18:01:41 +000085 else if (strcmp(spi->modalias, "wm8326") == 0)
86 type = WM8326;
Mark Brown2aa13b92010-10-20 00:00:11 +020087 else {
88 dev_err(&spi->dev, "Unknown device type\n");
89 return -EINVAL;
90 }
91
92 wm831x = kzalloc(sizeof(struct wm831x), GFP_KERNEL);
93 if (wm831x == NULL)
94 return -ENOMEM;
95
96 spi->bits_per_word = 16;
97 spi->mode = SPI_MODE_0;
98
99 dev_set_drvdata(&spi->dev, wm831x);
100 wm831x->dev = &spi->dev;
101 wm831x->control_data = spi;
102 wm831x->read_dev = wm831x_spi_read_device;
103 wm831x->write_dev = wm831x_spi_write_device;
104
105 return wm831x_device_init(wm831x, type, spi->irq);
106}
107
108static int __devexit wm831x_spi_remove(struct spi_device *spi)
109{
110 struct wm831x *wm831x = dev_get_drvdata(&spi->dev);
111
112 wm831x_device_exit(wm831x);
113
114 return 0;
115}
116
Mark Brown87d19062011-02-01 11:46:12 +0000117static int wm831x_spi_suspend(struct device *dev)
Mark Brown2aa13b92010-10-20 00:00:11 +0200118{
Mark Brown87d19062011-02-01 11:46:12 +0000119 struct wm831x *wm831x = dev_get_drvdata(dev);
Mark Brown2aa13b92010-10-20 00:00:11 +0200120
121 return wm831x_device_suspend(wm831x);
122}
123
Mark Brown87d19062011-02-01 11:46:12 +0000124static const struct dev_pm_ops wm831x_spi_pm = {
125 .freeze = wm831x_spi_suspend,
126 .suspend = wm831x_spi_suspend,
127};
128
Mark Brown2aa13b92010-10-20 00:00:11 +0200129static struct spi_driver wm8310_spi_driver = {
130 .driver = {
131 .name = "wm8310",
132 .bus = &spi_bus_type,
133 .owner = THIS_MODULE,
Mark Brown87d19062011-02-01 11:46:12 +0000134 .pm = &wm831x_spi_pm,
Mark Brown2aa13b92010-10-20 00:00:11 +0200135 },
136 .probe = wm831x_spi_probe,
137 .remove = __devexit_p(wm831x_spi_remove),
Mark Brown2aa13b92010-10-20 00:00:11 +0200138};
139
140static struct spi_driver wm8311_spi_driver = {
141 .driver = {
142 .name = "wm8311",
143 .bus = &spi_bus_type,
144 .owner = THIS_MODULE,
Mark Brown87d19062011-02-01 11:46:12 +0000145 .pm = &wm831x_spi_pm,
Mark Brown2aa13b92010-10-20 00:00:11 +0200146 },
147 .probe = wm831x_spi_probe,
148 .remove = __devexit_p(wm831x_spi_remove),
Mark Brown2aa13b92010-10-20 00:00:11 +0200149};
150
151static struct spi_driver wm8312_spi_driver = {
152 .driver = {
153 .name = "wm8312",
154 .bus = &spi_bus_type,
155 .owner = THIS_MODULE,
Mark Brown87d19062011-02-01 11:46:12 +0000156 .pm = &wm831x_spi_pm,
Mark Brown2aa13b92010-10-20 00:00:11 +0200157 },
158 .probe = wm831x_spi_probe,
159 .remove = __devexit_p(wm831x_spi_remove),
Mark Brown2aa13b92010-10-20 00:00:11 +0200160};
161
162static struct spi_driver wm8320_spi_driver = {
163 .driver = {
164 .name = "wm8320",
165 .bus = &spi_bus_type,
166 .owner = THIS_MODULE,
Mark Brown87d19062011-02-01 11:46:12 +0000167 .pm = &wm831x_spi_pm,
Mark Brown2aa13b92010-10-20 00:00:11 +0200168 },
169 .probe = wm831x_spi_probe,
170 .remove = __devexit_p(wm831x_spi_remove),
Mark Brown2aa13b92010-10-20 00:00:11 +0200171};
172
173static struct spi_driver wm8321_spi_driver = {
174 .driver = {
175 .name = "wm8321",
176 .bus = &spi_bus_type,
177 .owner = THIS_MODULE,
Mark Brown87d19062011-02-01 11:46:12 +0000178 .pm = &wm831x_spi_pm,
Mark Brown2aa13b92010-10-20 00:00:11 +0200179 },
180 .probe = wm831x_spi_probe,
181 .remove = __devexit_p(wm831x_spi_remove),
Mark Brown2aa13b92010-10-20 00:00:11 +0200182};
183
184static struct spi_driver wm8325_spi_driver = {
185 .driver = {
186 .name = "wm8325",
187 .bus = &spi_bus_type,
188 .owner = THIS_MODULE,
Mark Brown87d19062011-02-01 11:46:12 +0000189 .pm = &wm831x_spi_pm,
Mark Brown2aa13b92010-10-20 00:00:11 +0200190 },
191 .probe = wm831x_spi_probe,
192 .remove = __devexit_p(wm831x_spi_remove),
Mark Brown2aa13b92010-10-20 00:00:11 +0200193};
194
Mark Brown412dc112010-11-24 18:01:41 +0000195static struct spi_driver wm8326_spi_driver = {
196 .driver = {
197 .name = "wm8326",
198 .bus = &spi_bus_type,
199 .owner = THIS_MODULE,
Mark Brown87d19062011-02-01 11:46:12 +0000200 .pm = &wm831x_spi_pm,
Mark Brown412dc112010-11-24 18:01:41 +0000201 },
202 .probe = wm831x_spi_probe,
203 .remove = __devexit_p(wm831x_spi_remove),
Mark Brown412dc112010-11-24 18:01:41 +0000204};
205
Mark Brown2aa13b92010-10-20 00:00:11 +0200206static int __init wm831x_spi_init(void)
207{
208 int ret;
209
210 ret = spi_register_driver(&wm8310_spi_driver);
211 if (ret != 0)
212 pr_err("Failed to register WM8310 SPI driver: %d\n", ret);
213
214 ret = spi_register_driver(&wm8311_spi_driver);
215 if (ret != 0)
216 pr_err("Failed to register WM8311 SPI driver: %d\n", ret);
217
218 ret = spi_register_driver(&wm8312_spi_driver);
219 if (ret != 0)
220 pr_err("Failed to register WM8312 SPI driver: %d\n", ret);
221
222 ret = spi_register_driver(&wm8320_spi_driver);
223 if (ret != 0)
224 pr_err("Failed to register WM8320 SPI driver: %d\n", ret);
225
226 ret = spi_register_driver(&wm8321_spi_driver);
227 if (ret != 0)
228 pr_err("Failed to register WM8321 SPI driver: %d\n", ret);
229
230 ret = spi_register_driver(&wm8325_spi_driver);
231 if (ret != 0)
232 pr_err("Failed to register WM8325 SPI driver: %d\n", ret);
233
Mark Brown412dc112010-11-24 18:01:41 +0000234 ret = spi_register_driver(&wm8326_spi_driver);
235 if (ret != 0)
236 pr_err("Failed to register WM8326 SPI driver: %d\n", ret);
237
Mark Brown2aa13b92010-10-20 00:00:11 +0200238 return 0;
239}
240subsys_initcall(wm831x_spi_init);
241
242static void __exit wm831x_spi_exit(void)
243{
Mark Brown412dc112010-11-24 18:01:41 +0000244 spi_unregister_driver(&wm8326_spi_driver);
Mark Brown2aa13b92010-10-20 00:00:11 +0200245 spi_unregister_driver(&wm8325_spi_driver);
246 spi_unregister_driver(&wm8321_spi_driver);
247 spi_unregister_driver(&wm8320_spi_driver);
248 spi_unregister_driver(&wm8312_spi_driver);
249 spi_unregister_driver(&wm8311_spi_driver);
250 spi_unregister_driver(&wm8310_spi_driver);
251}
252module_exit(wm831x_spi_exit);
253
254MODULE_DESCRIPTION("SPI support for WM831x/2x AudioPlus PMICs");
255MODULE_LICENSE("GPL");
256MODULE_AUTHOR("Mark Brown");