aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mfd/Kconfig14
-rw-r--r--drivers/mfd/Makefile1
-rw-r--r--drivers/mfd/wm97xx-core.c366
3 files changed, 381 insertions, 0 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index fc5e4fef89d2..ac5ad6d0837c 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -1746,6 +1746,20 @@ config MFD_WM8994
1746 core support for the WM8994, in order to use the actual 1746 core support for the WM8994, in order to use the actual
1747 functionaltiy of the device other drivers must be enabled. 1747 functionaltiy of the device other drivers must be enabled.
1748 1748
1749config MFD_WM97xx
1750 tristate "Wolfson Microelectronics WM97xx"
1751 select MFD_CORE
1752 select REGMAP_AC97
1753 select AC97_BUS_COMPAT
1754 depends on AC97_BUS_NEW
1755 help
1756 The WM9705, WM9712 and WM9713 is a highly integrated hi-fi CODEC
1757 designed for smartphone applications. As well as audio functionality
1758 it has on board GPIO and a touchscreen functionality which is
1759 supported via the relevant subsystems. This driver provides core
1760 support for the WM97xx, in order to use the actual functionaltiy of
1761 the device other drivers must be enabled.
1762
1749config MFD_STW481X 1763config MFD_STW481X
1750 tristate "Support for ST Microelectronics STw481x" 1764 tristate "Support for ST Microelectronics STw481x"
1751 depends on I2C && (ARCH_NOMADIK || COMPILE_TEST) 1765 depends on I2C && (ARCH_NOMADIK || COMPILE_TEST)
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index c3d0a1b39bb6..3266977f54b8 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -73,6 +73,7 @@ obj-$(CONFIG_MFD_WM8350) += wm8350.o
73obj-$(CONFIG_MFD_WM8350_I2C) += wm8350-i2c.o 73obj-$(CONFIG_MFD_WM8350_I2C) += wm8350-i2c.o
74wm8994-objs := wm8994-core.o wm8994-irq.o wm8994-regmap.o 74wm8994-objs := wm8994-core.o wm8994-irq.o wm8994-regmap.o
75obj-$(CONFIG_MFD_WM8994) += wm8994.o 75obj-$(CONFIG_MFD_WM8994) += wm8994.o
76obj-$(CONFIG_MFD_WM97xx) += wm97xx-core.o
76 77
77obj-$(CONFIG_TPS6105X) += tps6105x.o 78obj-$(CONFIG_TPS6105X) += tps6105x.o
78obj-$(CONFIG_TPS65010) += tps65010.o 79obj-$(CONFIG_TPS65010) += tps65010.o
diff --git a/drivers/mfd/wm97xx-core.c b/drivers/mfd/wm97xx-core.c
new file mode 100644
index 000000000000..4141ee52a70b
--- /dev/null
+++ b/drivers/mfd/wm97xx-core.c
@@ -0,0 +1,366 @@
1/*
2 * Wolfson WM97xx -- Core device
3 *
4 * Copyright (C) 2017 Robert Jarzmik
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * Features:
12 * - an AC97 audio codec
13 * - a touchscreen driver
14 * - a GPIO block
15 */
16
17#include <linux/device.h>
18#include <linux/mfd/core.h>
19#include <linux/mfd/wm97xx.h>
20#include <linux/module.h>
21#include <linux/regmap.h>
22#include <linux/slab.h>
23#include <linux/wm97xx.h>
24#include <sound/ac97/codec.h>
25#include <sound/ac97/compat.h>
26
27#define WM9705_VENDOR_ID 0x574d4c05
28#define WM9712_VENDOR_ID 0x574d4c12
29#define WM9713_VENDOR_ID 0x574d4c13
30#define WM97xx_VENDOR_ID_MASK 0xffffffff
31
32struct wm97xx_priv {
33 struct regmap *regmap;
34 struct snd_ac97 *ac97;
35 struct device *dev;
36 struct wm97xx_platform_data codec_pdata;
37};
38
39static bool wm97xx_readable_reg(struct device *dev, unsigned int reg)
40{
41 switch (reg) {
42 case AC97_RESET ... AC97_PCM_SURR_DAC_RATE:
43 case AC97_PCM_LR_ADC_RATE:
44 case AC97_CENTER_LFE_MASTER:
45 case AC97_SPDIF ... AC97_LINE1_LEVEL:
46 case AC97_GPIO_CFG ... 0x5c:
47 case AC97_CODEC_CLASS_REV ... AC97_PCI_SID:
48 case 0x74 ... AC97_VENDOR_ID2:
49 return true;
50 default:
51 return false;
52 }
53}
54
55static bool wm97xx_writeable_reg(struct device *dev, unsigned int reg)
56{
57 switch (reg) {
58 case AC97_VENDOR_ID1:
59 case AC97_VENDOR_ID2:
60 return false;
61 default:
62 return wm97xx_readable_reg(dev, reg);
63 }
64}
65
66static const struct reg_default wm9705_reg_defaults[] = {
67 { 0x02, 0x8000 },
68 { 0x04, 0x8000 },
69 { 0x06, 0x8000 },
70 { 0x0a, 0x8000 },
71 { 0x0c, 0x8008 },
72 { 0x0e, 0x8008 },
73 { 0x10, 0x8808 },
74 { 0x12, 0x8808 },
75 { 0x14, 0x8808 },
76 { 0x16, 0x8808 },
77 { 0x18, 0x8808 },
78 { 0x1a, 0x0000 },
79 { 0x1c, 0x8000 },
80 { 0x20, 0x0000 },
81 { 0x22, 0x0000 },
82 { 0x26, 0x000f },
83 { 0x28, 0x0605 },
84 { 0x2a, 0x0000 },
85 { 0x2c, 0xbb80 },
86 { 0x32, 0xbb80 },
87 { 0x34, 0x2000 },
88 { 0x5a, 0x0000 },
89 { 0x5c, 0x0000 },
90 { 0x72, 0x0808 },
91 { 0x74, 0x0000 },
92 { 0x76, 0x0006 },
93 { 0x78, 0x0000 },
94 { 0x7a, 0x0000 },
95};
96
97static const struct regmap_config wm9705_regmap_config = {
98 .reg_bits = 16,
99 .reg_stride = 2,
100 .val_bits = 16,
101 .max_register = 0x7e,
102 .cache_type = REGCACHE_RBTREE,
103
104 .reg_defaults = wm9705_reg_defaults,
105 .num_reg_defaults = ARRAY_SIZE(wm9705_reg_defaults),
106 .volatile_reg = regmap_ac97_default_volatile,
107 .readable_reg = wm97xx_readable_reg,
108 .writeable_reg = wm97xx_writeable_reg,
109};
110
111static struct mfd_cell wm9705_cells[] = {
112 { .name = "wm9705-codec", },
113 { .name = "wm97xx-ts", },
114};
115
116static bool wm9712_volatile_reg(struct device *dev, unsigned int reg)
117{
118 switch (reg) {
119 case AC97_REC_GAIN:
120 return true;
121 default:
122 return regmap_ac97_default_volatile(dev, reg);
123 }
124}
125
126static const struct reg_default wm9712_reg_defaults[] = {
127 { 0x02, 0x8000 },
128 { 0x04, 0x8000 },
129 { 0x06, 0x8000 },
130 { 0x08, 0x0f0f },
131 { 0x0a, 0xaaa0 },
132 { 0x0c, 0xc008 },
133 { 0x0e, 0x6808 },
134 { 0x10, 0xe808 },
135 { 0x12, 0xaaa0 },
136 { 0x14, 0xad00 },
137 { 0x16, 0x8000 },
138 { 0x18, 0xe808 },
139 { 0x1a, 0x3000 },
140 { 0x1c, 0x8000 },
141 { 0x20, 0x0000 },
142 { 0x22, 0x0000 },
143 { 0x26, 0x000f },
144 { 0x28, 0x0605 },
145 { 0x2a, 0x0410 },
146 { 0x2c, 0xbb80 },
147 { 0x2e, 0xbb80 },
148 { 0x32, 0xbb80 },
149 { 0x34, 0x2000 },
150 { 0x4c, 0xf83e },
151 { 0x4e, 0xffff },
152 { 0x50, 0x0000 },
153 { 0x52, 0x0000 },
154 { 0x56, 0xf83e },
155 { 0x58, 0x0008 },
156 { 0x5c, 0x0000 },
157 { 0x60, 0xb032 },
158 { 0x62, 0x3e00 },
159 { 0x64, 0x0000 },
160 { 0x76, 0x0006 },
161 { 0x78, 0x0001 },
162 { 0x7a, 0x0000 },
163};
164
165static const struct regmap_config wm9712_regmap_config = {
166 .reg_bits = 16,
167 .reg_stride = 2,
168 .val_bits = 16,
169 .max_register = 0x7e,
170 .cache_type = REGCACHE_RBTREE,
171
172 .reg_defaults = wm9712_reg_defaults,
173 .num_reg_defaults = ARRAY_SIZE(wm9712_reg_defaults),
174 .volatile_reg = wm9712_volatile_reg,
175 .readable_reg = wm97xx_readable_reg,
176 .writeable_reg = wm97xx_writeable_reg,
177};
178
179static struct mfd_cell wm9712_cells[] = {
180 { .name = "wm9712-codec", },
181 { .name = "wm97xx-ts", },
182};
183
184static const struct reg_default wm9713_reg_defaults[] = {
185 { 0x02, 0x8080 }, /* Speaker Output Volume */
186 { 0x04, 0x8080 }, /* Headphone Output Volume */
187 { 0x06, 0x8080 }, /* Out3/OUT4 Volume */
188 { 0x08, 0xc880 }, /* Mono Volume */
189 { 0x0a, 0xe808 }, /* LINEIN Volume */
190 { 0x0c, 0xe808 }, /* DAC PGA Volume */
191 { 0x0e, 0x0808 }, /* MIC PGA Volume */
192 { 0x10, 0x00da }, /* MIC Routing Control */
193 { 0x12, 0x8000 }, /* Record PGA Volume */
194 { 0x14, 0xd600 }, /* Record Routing */
195 { 0x16, 0xaaa0 }, /* PCBEEP Volume */
196 { 0x18, 0xaaa0 }, /* VxDAC Volume */
197 { 0x1a, 0xaaa0 }, /* AUXDAC Volume */
198 { 0x1c, 0x0000 }, /* Output PGA Mux */
199 { 0x1e, 0x0000 }, /* DAC 3D control */
200 { 0x20, 0x0f0f }, /* DAC Tone Control*/
201 { 0x22, 0x0040 }, /* MIC Input Select & Bias */
202 { 0x24, 0x0000 }, /* Output Volume Mapping & Jack */
203 { 0x26, 0x7f00 }, /* Powerdown Ctrl/Stat*/
204 { 0x28, 0x0405 }, /* Extended Audio ID */
205 { 0x2a, 0x0410 }, /* Extended Audio Start/Ctrl */
206 { 0x2c, 0xbb80 }, /* Audio DACs Sample Rate */
207 { 0x2e, 0xbb80 }, /* AUXDAC Sample Rate */
208 { 0x32, 0xbb80 }, /* Audio ADCs Sample Rate */
209 { 0x36, 0x4523 }, /* PCM codec control */
210 { 0x3a, 0x2000 }, /* SPDIF control */
211 { 0x3c, 0xfdff }, /* Powerdown 1 */
212 { 0x3e, 0xffff }, /* Powerdown 2 */
213 { 0x40, 0x0000 }, /* General Purpose */
214 { 0x42, 0x0000 }, /* Fast Power-Up Control */
215 { 0x44, 0x0080 }, /* MCLK/PLL Control */
216 { 0x46, 0x0000 }, /* MCLK/PLL Control */
217
218 { 0x4c, 0xfffe }, /* GPIO Pin Configuration */
219 { 0x4e, 0xffff }, /* GPIO Pin Polarity / Type */
220 { 0x50, 0x0000 }, /* GPIO Pin Sticky */
221 { 0x52, 0x0000 }, /* GPIO Pin Wake-Up */
222 /* GPIO Pin Status */
223 { 0x56, 0xfffe }, /* GPIO Pin Sharing */
224 { 0x58, 0x4000 }, /* GPIO PullUp/PullDown */
225 { 0x5a, 0x0000 }, /* Additional Functions 1 */
226 { 0x5c, 0x0000 }, /* Additional Functions 2 */
227 { 0x60, 0xb032 }, /* ALC Control */
228 { 0x62, 0x3e00 }, /* ALC / Noise Gate Control */
229 { 0x64, 0x0000 }, /* AUXDAC input control */
230 { 0x74, 0x0000 }, /* Digitiser Reg 1 */
231 { 0x76, 0x0006 }, /* Digitiser Reg 2 */
232 { 0x78, 0x0001 }, /* Digitiser Reg 3 */
233 { 0x7a, 0x0000 }, /* Digitiser Read Back */
234};
235
236static const struct regmap_config wm9713_regmap_config = {
237 .reg_bits = 16,
238 .reg_stride = 2,
239 .val_bits = 16,
240 .max_register = 0x7e,
241 .cache_type = REGCACHE_RBTREE,
242
243 .reg_defaults = wm9713_reg_defaults,
244 .num_reg_defaults = ARRAY_SIZE(wm9713_reg_defaults),
245 .volatile_reg = regmap_ac97_default_volatile,
246 .readable_reg = wm97xx_readable_reg,
247 .writeable_reg = wm97xx_writeable_reg,
248};
249
250static struct mfd_cell wm9713_cells[] = {
251 { .name = "wm9713-codec", },
252 { .name = "wm97xx-ts", },
253};
254
255static int wm97xx_ac97_probe(struct ac97_codec_device *adev)
256{
257 struct wm97xx_priv *wm97xx;
258 const struct regmap_config *config;
259 struct wm97xx_platform_data *codec_pdata;
260 struct mfd_cell *cells;
261 int ret = -ENODEV, nb_cells, i;
262 struct wm97xx_pdata *pdata = snd_ac97_codec_get_platdata(adev);
263
264 wm97xx = devm_kzalloc(ac97_codec_dev2dev(adev),
265 sizeof(*wm97xx), GFP_KERNEL);
266 if (!wm97xx)
267 return -ENOMEM;
268
269 wm97xx->dev = ac97_codec_dev2dev(adev);
270 wm97xx->ac97 = snd_ac97_compat_alloc(adev);
271 if (IS_ERR(wm97xx->ac97))
272 return PTR_ERR(wm97xx->ac97);
273
274
275 ac97_set_drvdata(adev, wm97xx);
276 dev_info(wm97xx->dev, "wm97xx core found, id=0x%x\n",
277 adev->vendor_id);
278
279 codec_pdata = &wm97xx->codec_pdata;
280 codec_pdata->ac97 = wm97xx->ac97;
281 codec_pdata->batt_pdata = pdata->batt_pdata;
282
283 switch (adev->vendor_id) {
284 case WM9705_VENDOR_ID:
285 config = &wm9705_regmap_config;
286 cells = wm9705_cells;
287 nb_cells = ARRAY_SIZE(wm9705_cells);
288 break;
289 case WM9712_VENDOR_ID:
290 config = &wm9712_regmap_config;
291 cells = wm9712_cells;
292 nb_cells = ARRAY_SIZE(wm9712_cells);
293 break;
294 case WM9713_VENDOR_ID:
295 config = &wm9713_regmap_config;
296 cells = wm9713_cells;
297 nb_cells = ARRAY_SIZE(wm9713_cells);
298 break;
299 default:
300 goto err_free_compat;
301 }
302
303 for (i = 0; i < nb_cells; i++) {
304 cells[i].platform_data = codec_pdata;
305 cells[i].pdata_size = sizeof(*codec_pdata);
306 }
307
308 codec_pdata->regmap = devm_regmap_init_ac97(wm97xx->ac97, config);
309 if (IS_ERR(codec_pdata->regmap)) {
310 ret = PTR_ERR(codec_pdata->regmap);
311 goto err_free_compat;
312 }
313
314 ret = devm_mfd_add_devices(wm97xx->dev, PLATFORM_DEVID_NONE,
315 cells, nb_cells, NULL, 0, NULL);
316 if (ret)
317 goto err_free_compat;
318
319 return ret;
320
321err_free_compat:
322 snd_ac97_compat_release(wm97xx->ac97);
323 return ret;
324}
325
326static int wm97xx_ac97_remove(struct ac97_codec_device *adev)
327{
328 struct wm97xx_priv *wm97xx = ac97_get_drvdata(adev);
329
330 snd_ac97_compat_release(wm97xx->ac97);
331
332 return 0;
333}
334
335static const struct ac97_id wm97xx_ac97_ids[] = {
336 { .id = WM9705_VENDOR_ID, .mask = WM97xx_VENDOR_ID_MASK },
337 { .id = WM9712_VENDOR_ID, .mask = WM97xx_VENDOR_ID_MASK },
338 { .id = WM9713_VENDOR_ID, .mask = WM97xx_VENDOR_ID_MASK },
339 { }
340};
341
342static struct ac97_codec_driver wm97xx_ac97_driver = {
343 .driver = {
344 .name = "wm97xx-core",
345 },
346 .probe = wm97xx_ac97_probe,
347 .remove = wm97xx_ac97_remove,
348 .id_table = wm97xx_ac97_ids,
349};
350
351static int __init wm97xx_module_init(void)
352{
353 return snd_ac97_codec_driver_register(&wm97xx_ac97_driver);
354}
355module_init(wm97xx_module_init);
356
357static void __exit wm97xx_module_exit(void)
358{
359 snd_ac97_codec_driver_unregister(&wm97xx_ac97_driver);
360}
361module_exit(wm97xx_module_exit);
362
363MODULE_DESCRIPTION("WM9712, WM9713 core driver");
364MODULE_AUTHOR("Robert Jarzmik <robert.jarzmik@free.fr>");
365MODULE_LICENSE("GPL");
366