Commit | Line | Data |
---|---|---|
2874c5fd | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
9e501086 MB |
2 | /* |
3 | * wm8994-core.c -- Device access for Wolfson WM8994 | |
4 | * | |
5 | * Copyright 2009 Wolfson Microelectronics PLC. | |
6 | * | |
7 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | |
9e501086 MB |
8 | */ |
9 | ||
10 | #include <linux/kernel.h> | |
11 | #include <linux/module.h> | |
5a0e3ad6 | 12 | #include <linux/slab.h> |
9e501086 | 13 | #include <linux/i2c.h> |
d6c645fc | 14 | #include <linux/err.h> |
9e501086 MB |
15 | #include <linux/delay.h> |
16 | #include <linux/mfd/core.h> | |
20fb2772 | 17 | #include <linux/of.h> |
d450f19e | 18 | #include <linux/pm_runtime.h> |
d6c645fc | 19 | #include <linux/regmap.h> |
9e501086 MB |
20 | #include <linux/regulator/consumer.h> |
21 | #include <linux/regulator/machine.h> | |
22 | ||
23 | #include <linux/mfd/wm8994/core.h> | |
24 | #include <linux/mfd/wm8994/pdata.h> | |
25 | #include <linux/mfd/wm8994/registers.h> | |
26 | ||
c3f13861 | 27 | #include "wm8994.h" |
9e501086 | 28 | |
ad59de48 | 29 | static const struct mfd_cell wm8994_regulator_devs[] = { |
d450f19e MB |
30 | { |
31 | .name = "wm8994-ldo", | |
fef22cb4 | 32 | .id = 0, |
d450f19e MB |
33 | .pm_runtime_no_callbacks = true, |
34 | }, | |
35 | { | |
36 | .name = "wm8994-ldo", | |
fef22cb4 | 37 | .id = 1, |
d450f19e MB |
38 | .pm_runtime_no_callbacks = true, |
39 | }, | |
9e501086 MB |
40 | }; |
41 | ||
f977284a | 42 | static const struct resource wm8994_codec_resources[] = { |
c9fbf7e0 MB |
43 | { |
44 | .start = WM8994_IRQ_TEMP_SHUT, | |
45 | .end = WM8994_IRQ_TEMP_WARN, | |
46 | .flags = IORESOURCE_IRQ, | |
47 | }, | |
48 | }; | |
49 | ||
f977284a | 50 | static const struct resource wm8994_gpio_resources[] = { |
c9fbf7e0 MB |
51 | { |
52 | .start = WM8994_IRQ_GPIO(1), | |
53 | .end = WM8994_IRQ_GPIO(11), | |
54 | .flags = IORESOURCE_IRQ, | |
55 | }, | |
56 | }; | |
57 | ||
ad59de48 | 58 | static const struct mfd_cell wm8994_devs[] = { |
c9fbf7e0 MB |
59 | { |
60 | .name = "wm8994-codec", | |
61 | .num_resources = ARRAY_SIZE(wm8994_codec_resources), | |
62 | .resources = wm8994_codec_resources, | |
63 | }, | |
64 | ||
65 | { | |
66 | .name = "wm8994-gpio", | |
67 | .num_resources = ARRAY_SIZE(wm8994_gpio_resources), | |
68 | .resources = wm8994_gpio_resources, | |
d450f19e | 69 | .pm_runtime_no_callbacks = true, |
c9fbf7e0 | 70 | }, |
9e501086 MB |
71 | }; |
72 | ||
73 | /* | |
74 | * Supplies for the main bulk of CODEC; the LDO supplies are ignored | |
75 | * and should be handled via the standard regulator API supply | |
76 | * management. | |
77 | */ | |
b1f43bf3 MB |
78 | static const char *wm1811_main_supplies[] = { |
79 | "DBVDD1", | |
80 | "DBVDD2", | |
81 | "DBVDD3", | |
82 | "DCVDD", | |
83 | "AVDD1", | |
84 | "AVDD2", | |
85 | "CPVDD", | |
86 | "SPKVDD1", | |
87 | "SPKVDD2", | |
88 | }; | |
89 | ||
9e501086 MB |
90 | static const char *wm8994_main_supplies[] = { |
91 | "DBVDD", | |
92 | "DCVDD", | |
93 | "AVDD1", | |
94 | "AVDD2", | |
95 | "CPVDD", | |
96 | "SPKVDD1", | |
97 | "SPKVDD2", | |
98 | }; | |
99 | ||
559e0df6 MB |
100 | static const char *wm8958_main_supplies[] = { |
101 | "DBVDD1", | |
102 | "DBVDD2", | |
103 | "DBVDD3", | |
104 | "DCVDD", | |
105 | "AVDD1", | |
106 | "AVDD2", | |
107 | "CPVDD", | |
108 | "SPKVDD1", | |
109 | "SPKVDD2", | |
110 | }; | |
111 | ||
d450f19e | 112 | static int wm8994_suspend(struct device *dev) |
9e501086 MB |
113 | { |
114 | struct wm8994 *wm8994 = dev_get_drvdata(dev); | |
115 | int ret; | |
116 | ||
77bd70e9 | 117 | /* Don't actually go through with the suspend if the CODEC is |
ebe38f80 | 118 | * still active for accessory detect. */ |
5f40c6b6 MB |
119 | switch (wm8994->type) { |
120 | case WM8958: | |
b5488b6e | 121 | case WM1811: |
5f40c6b6 MB |
122 | ret = wm8994_reg_read(wm8994, WM8958_MIC_DETECT_1); |
123 | if (ret < 0) { | |
124 | dev_err(dev, "Failed to read power status: %d\n", ret); | |
125 | } else if (ret & WM8958_MICD_ENA) { | |
126 | dev_dbg(dev, "CODEC still active, ignoring suspend\n"); | |
127 | return 0; | |
128 | } | |
129 | break; | |
130 | default: | |
131 | break; | |
132 | } | |
133 | ||
881de670 MB |
134 | /* Disable LDO pulldowns while the device is suspended if we |
135 | * don't know that something will be driving them. */ | |
136 | if (!wm8994->ldo_ena_always_driven) | |
137 | wm8994_set_bits(wm8994, WM8994_PULL_CONTROL_2, | |
138 | WM8994_LDO1ENA_PD | WM8994_LDO2ENA_PD, | |
139 | WM8994_LDO1ENA_PD | WM8994_LDO2ENA_PD); | |
140 | ||
f40dff9e MB |
141 | /* Explicitly put the device into reset in case regulators |
142 | * don't get disabled in order to ensure consistent restart. | |
143 | */ | |
be79cf2f MB |
144 | wm8994_reg_write(wm8994, WM8994_SOFTWARE_RESET, |
145 | wm8994_reg_read(wm8994, WM8994_SOFTWARE_RESET)); | |
f40dff9e | 146 | |
ed393dcd MB |
147 | regcache_mark_dirty(wm8994->regmap); |
148 | ||
78a27cd3 CR |
149 | /* Restore GPIO registers to prevent problems with mismatched |
150 | * pin configurations. | |
151 | */ | |
ed393dcd MB |
152 | ret = regcache_sync_region(wm8994->regmap, WM8994_GPIO_1, |
153 | WM8994_GPIO_11); | |
78a27cd3 CR |
154 | if (ret != 0) |
155 | dev_err(dev, "Failed to restore GPIO registers: %d\n", ret); | |
156 | ||
1a2017b7 MB |
157 | /* In case one of the GPIOs is used as a wake input. */ |
158 | ret = regcache_sync_region(wm8994->regmap, | |
159 | WM8994_INTERRUPT_STATUS_1_MASK, | |
160 | WM8994_INTERRUPT_STATUS_1_MASK); | |
161 | if (ret != 0) | |
162 | dev_err(dev, "Failed to restore interrupt mask: %d\n", ret); | |
163 | ||
3befc925 | 164 | regcache_cache_only(wm8994->regmap, true); |
77bd70e9 MB |
165 | wm8994->suspended = true; |
166 | ||
559e0df6 | 167 | ret = regulator_bulk_disable(wm8994->num_supplies, |
9e501086 MB |
168 | wm8994->supplies); |
169 | if (ret != 0) { | |
170 | dev_err(dev, "Failed to disable supplies: %d\n", ret); | |
171 | return ret; | |
172 | } | |
173 | ||
174 | return 0; | |
175 | } | |
176 | ||
d450f19e | 177 | static int wm8994_resume(struct device *dev) |
9e501086 MB |
178 | { |
179 | struct wm8994 *wm8994 = dev_get_drvdata(dev); | |
c3f13861 | 180 | int ret; |
9e501086 | 181 | |
77bd70e9 MB |
182 | /* We may have lied to the PM core about suspending */ |
183 | if (!wm8994->suspended) | |
184 | return 0; | |
185 | ||
559e0df6 | 186 | ret = regulator_bulk_enable(wm8994->num_supplies, |
9e501086 MB |
187 | wm8994->supplies); |
188 | if (ret != 0) { | |
189 | dev_err(dev, "Failed to enable supplies: %d\n", ret); | |
190 | return ret; | |
191 | } | |
192 | ||
3befc925 | 193 | regcache_cache_only(wm8994->regmap, false); |
c3f13861 MB |
194 | ret = regcache_sync(wm8994->regmap); |
195 | if (ret != 0) { | |
196 | dev_err(dev, "Failed to restore register map: %d\n", ret); | |
197 | goto err_enable; | |
98ae1cca | 198 | } |
c9fbf7e0 | 199 | |
881de670 MB |
200 | /* Disable LDO pulldowns while the device is active */ |
201 | wm8994_set_bits(wm8994, WM8994_PULL_CONTROL_2, | |
202 | WM8994_LDO1ENA_PD | WM8994_LDO2ENA_PD, | |
203 | 0); | |
204 | ||
77bd70e9 MB |
205 | wm8994->suspended = false; |
206 | ||
9e501086 | 207 | return 0; |
c3f13861 MB |
208 | |
209 | err_enable: | |
210 | regulator_bulk_disable(wm8994->num_supplies, wm8994->supplies); | |
211 | ||
212 | return ret; | |
9e501086 | 213 | } |
9e501086 MB |
214 | |
215 | #ifdef CONFIG_REGULATOR | |
216 | static int wm8994_ldo_in_use(struct wm8994_pdata *pdata, int ldo) | |
217 | { | |
218 | struct wm8994_ldo_pdata *ldo_pdata; | |
219 | ||
220 | if (!pdata) | |
221 | return 0; | |
222 | ||
223 | ldo_pdata = &pdata->ldo[ldo]; | |
224 | ||
225 | if (!ldo_pdata->init_data) | |
226 | return 0; | |
227 | ||
228 | return ldo_pdata->init_data->num_consumer_supplies != 0; | |
229 | } | |
230 | #else | |
231 | static int wm8994_ldo_in_use(struct wm8994_pdata *pdata, int ldo) | |
232 | { | |
233 | return 0; | |
234 | } | |
235 | #endif | |
236 | ||
8019ff6c | 237 | static const struct reg_sequence wm8994_revc_patch[] = { |
462835e4 MB |
238 | { 0x102, 0x3 }, |
239 | { 0x56, 0x3 }, | |
240 | { 0x817, 0x0 }, | |
241 | { 0x102, 0x0 }, | |
242 | }; | |
243 | ||
8019ff6c | 244 | static const struct reg_sequence wm8958_reva_patch[] = { |
462835e4 MB |
245 | { 0x102, 0x3 }, |
246 | { 0xcb, 0x81 }, | |
247 | { 0x817, 0x0 }, | |
248 | { 0x102, 0x0 }, | |
249 | }; | |
250 | ||
8019ff6c | 251 | static const struct reg_sequence wm1811_reva_patch[] = { |
462835e4 | 252 | { 0x102, 0x3 }, |
9282a7b9 | 253 | { 0x56, 0xc07 }, |
462835e4 MB |
254 | { 0x5d, 0x7e }, |
255 | { 0x5e, 0x0 }, | |
256 | { 0x102, 0x0 }, | |
257 | }; | |
258 | ||
20fb2772 MB |
259 | #ifdef CONFIG_OF |
260 | static int wm8994_set_pdata_from_of(struct wm8994 *wm8994) | |
261 | { | |
262 | struct device_node *np = wm8994->dev->of_node; | |
263 | struct wm8994_pdata *pdata = &wm8994->pdata; | |
264 | int i; | |
265 | ||
266 | if (!np) | |
267 | return 0; | |
268 | ||
269 | if (of_property_read_u32_array(np, "wlf,gpio-cfg", pdata->gpio_defaults, | |
270 | ARRAY_SIZE(pdata->gpio_defaults)) >= 0) { | |
271 | for (i = 0; i < ARRAY_SIZE(pdata->gpio_defaults); i++) { | |
272 | if (wm8994->pdata.gpio_defaults[i] == 0) | |
273 | pdata->gpio_defaults[i] | |
274 | = WM8994_CONFIGURE_GPIO; | |
275 | } | |
276 | } | |
277 | ||
278 | of_property_read_u32_array(np, "wlf,micbias-cfg", pdata->micbias, | |
279 | ARRAY_SIZE(pdata->micbias)); | |
280 | ||
01330edc RH |
281 | pdata->lineout1_diff = !of_property_read_bool(np, "wlf,lineout1-se"); |
282 | pdata->lineout2_diff = !of_property_read_bool(np, "wlf,lineout2-se"); | |
283 | pdata->lineout1fb = of_property_read_bool(np, "wlf,lineout1-feedback"); | |
284 | pdata->lineout2fb = of_property_read_bool(np, "wlf,lineout2-feedback") || | |
285 | of_property_read_bool(np, "wlf,ldoena-always-driven"); | |
20fb2772 | 286 | |
102370fb AP |
287 | pdata->spkmode_pu = of_property_read_bool(np, "wlf,spkmode-pu"); |
288 | ||
4d3e55bc AP |
289 | pdata->csnaddr_pd = of_property_read_bool(np, "wlf,csnaddr-pd"); |
290 | ||
20fb2772 MB |
291 | return 0; |
292 | } | |
293 | #else | |
294 | static int wm8994_set_pdata_from_of(struct wm8994 *wm8994) | |
295 | { | |
296 | return 0; | |
297 | } | |
298 | #endif | |
299 | ||
9e501086 MB |
300 | /* |
301 | * Instantiate the generic non-control parts of the device. | |
302 | */ | |
f791be49 | 303 | static int wm8994_device_init(struct wm8994 *wm8994, int irq) |
9e501086 | 304 | { |
a8a8fc28 | 305 | struct wm8994_pdata *pdata; |
34697898 | 306 | struct regmap_config *regmap_config; |
8019ff6c | 307 | const struct reg_sequence *regmap_patch = NULL; |
559e0df6 | 308 | const char *devname; |
222bc784 | 309 | int ret, i, patch_regs = 0; |
26c34c25 | 310 | int pulls = 0; |
9e501086 | 311 | |
a8a8fc28 MB |
312 | if (dev_get_platdata(wm8994->dev)) { |
313 | pdata = dev_get_platdata(wm8994->dev); | |
314 | wm8994->pdata = *pdata; | |
315 | } | |
316 | pdata = &wm8994->pdata; | |
317 | ||
20fb2772 MB |
318 | ret = wm8994_set_pdata_from_of(wm8994); |
319 | if (ret != 0) | |
320 | return ret; | |
321 | ||
9e501086 | 322 | /* Add the on-chip regulators first for bootstrapping */ |
fef22cb4 | 323 | ret = mfd_add_devices(wm8994->dev, 0, |
9e501086 MB |
324 | wm8994_regulator_devs, |
325 | ARRAY_SIZE(wm8994_regulator_devs), | |
55692af5 | 326 | NULL, 0, NULL); |
9e501086 MB |
327 | if (ret != 0) { |
328 | dev_err(wm8994->dev, "Failed to add children: %d\n", ret); | |
9db4249f | 329 | goto err; |
9e501086 MB |
330 | } |
331 | ||
559e0df6 | 332 | switch (wm8994->type) { |
b1f43bf3 MB |
333 | case WM1811: |
334 | wm8994->num_supplies = ARRAY_SIZE(wm1811_main_supplies); | |
335 | break; | |
559e0df6 MB |
336 | case WM8994: |
337 | wm8994->num_supplies = ARRAY_SIZE(wm8994_main_supplies); | |
338 | break; | |
339 | case WM8958: | |
340 | wm8994->num_supplies = ARRAY_SIZE(wm8958_main_supplies); | |
341 | break; | |
342 | default: | |
343 | BUG(); | |
9db4249f | 344 | goto err; |
559e0df6 MB |
345 | } |
346 | ||
a86854d0 KC |
347 | wm8994->supplies = devm_kcalloc(wm8994->dev, |
348 | wm8994->num_supplies, | |
349 | sizeof(struct regulator_bulk_data), | |
350 | GFP_KERNEL); | |
fccbd21f AL |
351 | if (!wm8994->supplies) { |
352 | ret = -ENOMEM; | |
9db4249f | 353 | goto err; |
fccbd21f | 354 | } |
9e501086 | 355 | |
559e0df6 | 356 | switch (wm8994->type) { |
b1f43bf3 MB |
357 | case WM1811: |
358 | for (i = 0; i < ARRAY_SIZE(wm1811_main_supplies); i++) | |
359 | wm8994->supplies[i].supply = wm1811_main_supplies[i]; | |
360 | break; | |
559e0df6 MB |
361 | case WM8994: |
362 | for (i = 0; i < ARRAY_SIZE(wm8994_main_supplies); i++) | |
363 | wm8994->supplies[i].supply = wm8994_main_supplies[i]; | |
364 | break; | |
365 | case WM8958: | |
366 | for (i = 0; i < ARRAY_SIZE(wm8958_main_supplies); i++) | |
367 | wm8994->supplies[i].supply = wm8958_main_supplies[i]; | |
368 | break; | |
369 | default: | |
370 | BUG(); | |
9db4249f | 371 | goto err; |
559e0df6 | 372 | } |
202b5689 VK |
373 | |
374 | /* | |
375 | * Can't use devres helper here as some of the supplies are provided by | |
376 | * wm8994->dev's children (regulators) and those regulators are | |
377 | * unregistered by the devres core before the supplies are freed. | |
378 | */ | |
379 | ret = regulator_bulk_get(wm8994->dev, wm8994->num_supplies, | |
9e501086 MB |
380 | wm8994->supplies); |
381 | if (ret != 0) { | |
7ff864e1 MS |
382 | if (ret != -EPROBE_DEFER) |
383 | dev_err(wm8994->dev, "Failed to get supplies: %d\n", | |
384 | ret); | |
9db4249f | 385 | goto err; |
9e501086 MB |
386 | } |
387 | ||
3e56c468 | 388 | ret = regulator_bulk_enable(wm8994->num_supplies, wm8994->supplies); |
9e501086 MB |
389 | if (ret != 0) { |
390 | dev_err(wm8994->dev, "Failed to enable supplies: %d\n", ret); | |
202b5689 | 391 | goto err_regulator_free; |
9e501086 MB |
392 | } |
393 | ||
394 | ret = wm8994_reg_read(wm8994, WM8994_SOFTWARE_RESET); | |
395 | if (ret < 0) { | |
396 | dev_err(wm8994->dev, "Failed to read ID register\n"); | |
397 | goto err_enable; | |
398 | } | |
559e0df6 | 399 | switch (ret) { |
b1f43bf3 MB |
400 | case 0x1811: |
401 | devname = "WM1811"; | |
402 | if (wm8994->type != WM1811) | |
403 | dev_warn(wm8994->dev, "Device registered as type %d\n", | |
404 | wm8994->type); | |
405 | wm8994->type = WM1811; | |
406 | break; | |
559e0df6 MB |
407 | case 0x8994: |
408 | devname = "WM8994"; | |
409 | if (wm8994->type != WM8994) | |
410 | dev_warn(wm8994->dev, "Device registered as type %d\n", | |
411 | wm8994->type); | |
412 | wm8994->type = WM8994; | |
413 | break; | |
414 | case 0x8958: | |
415 | devname = "WM8958"; | |
416 | if (wm8994->type != WM8958) | |
417 | dev_warn(wm8994->dev, "Device registered as type %d\n", | |
418 | wm8994->type); | |
419 | wm8994->type = WM8958; | |
420 | break; | |
421 | default: | |
9e501086 MB |
422 | dev_err(wm8994->dev, "Device is not a WM8994, ID is %x\n", |
423 | ret); | |
424 | ret = -EINVAL; | |
425 | goto err_enable; | |
426 | } | |
427 | ||
428 | ret = wm8994_reg_read(wm8994, WM8994_CHIP_REVISION); | |
429 | if (ret < 0) { | |
430 | dev_err(wm8994->dev, "Failed to read revision register: %d\n", | |
431 | ret); | |
432 | goto err_enable; | |
433 | } | |
cc7a7279 MB |
434 | wm8994->revision = ret & WM8994_CHIP_REV_MASK; |
435 | wm8994->cust_id = (ret & WM8994_CUST_ID_MASK) >> WM8994_CUST_ID_SHIFT; | |
9e501086 | 436 | |
a2495bc7 MB |
437 | switch (wm8994->type) { |
438 | case WM8994: | |
7ed5849c | 439 | switch (wm8994->revision) { |
a2495bc7 MB |
440 | case 0: |
441 | case 1: | |
559e0df6 MB |
442 | dev_warn(wm8994->dev, |
443 | "revision %c not fully supported\n", | |
7ed5849c | 444 | 'A' + wm8994->revision); |
a2495bc7 | 445 | break; |
462835e4 MB |
446 | case 2: |
447 | case 3: | |
d54e17f9 | 448 | default: |
462835e4 MB |
449 | regmap_patch = wm8994_revc_patch; |
450 | patch_regs = ARRAY_SIZE(wm8994_revc_patch); | |
451 | break; | |
462835e4 MB |
452 | } |
453 | break; | |
454 | ||
455 | case WM8958: | |
456 | switch (wm8994->revision) { | |
457 | case 0: | |
458 | regmap_patch = wm8958_reva_patch; | |
459 | patch_regs = ARRAY_SIZE(wm8958_reva_patch); | |
460 | break; | |
a2495bc7 MB |
461 | default: |
462 | break; | |
463 | } | |
9e501086 | 464 | break; |
462835e4 | 465 | |
443e67ed MB |
466 | case WM1811: |
467 | /* Revision C did not change the relevant layer */ | |
7ed5849c MB |
468 | if (wm8994->revision > 1) |
469 | wm8994->revision++; | |
d54e17f9 MB |
470 | |
471 | regmap_patch = wm1811_reva_patch; | |
472 | patch_regs = ARRAY_SIZE(wm1811_reva_patch); | |
443e67ed | 473 | break; |
462835e4 | 474 | |
9e501086 | 475 | default: |
9e501086 MB |
476 | break; |
477 | } | |
478 | ||
cc7a7279 MB |
479 | dev_info(wm8994->dev, "%s revision %c CUST_ID %02x\n", devname, |
480 | 'A' + wm8994->revision, wm8994->cust_id); | |
9e501086 | 481 | |
34697898 MB |
482 | switch (wm8994->type) { |
483 | case WM1811: | |
484 | regmap_config = &wm1811_regmap_config; | |
485 | break; | |
486 | case WM8994: | |
487 | regmap_config = &wm8994_regmap_config; | |
488 | break; | |
489 | case WM8958: | |
490 | regmap_config = &wm8958_regmap_config; | |
491 | break; | |
492 | default: | |
493 | dev_err(wm8994->dev, "Unknown device type %d\n", wm8994->type); | |
df47df55 AB |
494 | ret = -EINVAL; |
495 | goto err_enable; | |
34697898 MB |
496 | } |
497 | ||
498 | ret = regmap_reinit_cache(wm8994->regmap, regmap_config); | |
499 | if (ret != 0) { | |
500 | dev_err(wm8994->dev, "Failed to reinit register cache: %d\n", | |
501 | ret); | |
df47df55 | 502 | goto err_enable; |
34697898 | 503 | } |
9e501086 | 504 | |
f3799e93 MB |
505 | /* Explicitly put the device into reset in case regulators |
506 | * don't get disabled in order to ensure we know the device | |
507 | * state. | |
508 | */ | |
509 | ret = wm8994_reg_write(wm8994, WM8994_SOFTWARE_RESET, | |
510 | wm8994_reg_read(wm8994, WM8994_SOFTWARE_RESET)); | |
511 | if (ret != 0) { | |
512 | dev_err(wm8994->dev, "Failed to reset device: %d\n", ret); | |
df47df55 | 513 | goto err_enable; |
f3799e93 MB |
514 | } |
515 | ||
462835e4 MB |
516 | if (regmap_patch) { |
517 | ret = regmap_register_patch(wm8994->regmap, regmap_patch, | |
518 | patch_regs); | |
519 | if (ret != 0) { | |
520 | dev_err(wm8994->dev, "Failed to register patch: %d\n", | |
521 | ret); | |
df47df55 | 522 | goto err_enable; |
462835e4 MB |
523 | } |
524 | } | |
525 | ||
a8a8fc28 MB |
526 | wm8994->irq_base = pdata->irq_base; |
527 | wm8994->gpio_base = pdata->gpio_base; | |
528 | ||
529 | /* GPIO configuration is only applied if it's non-zero */ | |
530 | for (i = 0; i < ARRAY_SIZE(pdata->gpio_defaults); i++) { | |
531 | if (pdata->gpio_defaults[i]) { | |
532 | wm8994_set_bits(wm8994, WM8994_GPIO_1 + i, | |
533 | 0xffff, pdata->gpio_defaults[i]); | |
9e501086 | 534 | } |
a8a8fc28 | 535 | } |
881de670 | 536 | |
a8a8fc28 | 537 | wm8994->ldo_ena_always_driven = pdata->ldo_ena_always_driven; |
26c34c25 | 538 | |
a8a8fc28 MB |
539 | if (pdata->spkmode_pu) |
540 | pulls |= WM8994_SPKMODE_PU; | |
4d3e55bc AP |
541 | if (pdata->csnaddr_pd) |
542 | pulls |= WM8994_CSNADDR_PD; | |
9e501086 | 543 | |
26c34c25 | 544 | /* Disable unneeded pulls */ |
881de670 | 545 | wm8994_set_bits(wm8994, WM8994_PULL_CONTROL_2, |
26c34c25 MB |
546 | WM8994_LDO1ENA_PD | WM8994_LDO2ENA_PD | |
547 | WM8994_SPKMODE_PU | WM8994_CSNADDR_PD, | |
548 | pulls); | |
881de670 | 549 | |
9e501086 MB |
550 | /* In some system designs where the regulators are not in use, |
551 | * we can achieve a small reduction in leakage currents by | |
552 | * floating LDO outputs. This bit makes no difference if the | |
553 | * LDOs are enabled, it only affects cases where the LDOs were | |
554 | * in operation and are then disabled. | |
555 | */ | |
556 | for (i = 0; i < WM8994_NUM_LDO_REGS; i++) { | |
557 | if (wm8994_ldo_in_use(pdata, i)) | |
558 | wm8994_set_bits(wm8994, WM8994_LDO_1 + i, | |
559 | WM8994_LDO1_DISCH, WM8994_LDO1_DISCH); | |
560 | else | |
561 | wm8994_set_bits(wm8994, WM8994_LDO_1 + i, | |
562 | WM8994_LDO1_DISCH, 0); | |
563 | } | |
564 | ||
c9fbf7e0 MB |
565 | wm8994_irq_init(wm8994); |
566 | ||
9e501086 MB |
567 | ret = mfd_add_devices(wm8994->dev, -1, |
568 | wm8994_devs, ARRAY_SIZE(wm8994_devs), | |
55692af5 | 569 | NULL, 0, NULL); |
9e501086 MB |
570 | if (ret != 0) { |
571 | dev_err(wm8994->dev, "Failed to add children: %d\n", ret); | |
c9fbf7e0 | 572 | goto err_irq; |
9e501086 MB |
573 | } |
574 | ||
f4a19540 | 575 | pm_runtime_set_active(wm8994->dev); |
d450f19e | 576 | pm_runtime_enable(wm8994->dev); |
ee67b0cd | 577 | pm_runtime_idle(wm8994->dev); |
d450f19e | 578 | |
9e501086 MB |
579 | return 0; |
580 | ||
c9fbf7e0 MB |
581 | err_irq: |
582 | wm8994_irq_exit(wm8994); | |
9e501086 | 583 | err_enable: |
559e0df6 | 584 | regulator_bulk_disable(wm8994->num_supplies, |
9e501086 | 585 | wm8994->supplies); |
202b5689 VK |
586 | err_regulator_free: |
587 | regulator_bulk_free(wm8994->num_supplies, wm8994->supplies); | |
9db4249f | 588 | err: |
9e501086 | 589 | mfd_remove_devices(wm8994->dev); |
9e501086 MB |
590 | return ret; |
591 | } | |
592 | ||
4740f73f | 593 | static void wm8994_device_exit(struct wm8994 *wm8994) |
9e501086 | 594 | { |
f4a19540 | 595 | pm_runtime_get_sync(wm8994->dev); |
d450f19e | 596 | pm_runtime_disable(wm8994->dev); |
f4a19540 | 597 | pm_runtime_put_noidle(wm8994->dev); |
c9fbf7e0 | 598 | wm8994_irq_exit(wm8994); |
3e56c468 | 599 | regulator_bulk_disable(wm8994->num_supplies, wm8994->supplies); |
202b5689 | 600 | regulator_bulk_free(wm8994->num_supplies, wm8994->supplies); |
bb63f7d3 | 601 | mfd_remove_devices(wm8994->dev); |
9e501086 MB |
602 | } |
603 | ||
cf763c2e | 604 | static const struct of_device_id wm8994_of_match[] = { |
39aa3b5a MB |
605 | { .compatible = "wlf,wm1811", .data = (void *)WM1811 }, |
606 | { .compatible = "wlf,wm8994", .data = (void *)WM8994 }, | |
607 | { .compatible = "wlf,wm8958", .data = (void *)WM8958 }, | |
cf763c2e MB |
608 | { } |
609 | }; | |
610 | MODULE_DEVICE_TABLE(of, wm8994_of_match); | |
611 | ||
54f872ba | 612 | static int wm8994_i2c_probe(struct i2c_client *i2c) |
9e501086 MB |
613 | { |
614 | struct wm8994 *wm8994; | |
d6c645fc | 615 | int ret; |
9e501086 | 616 | |
2fa33494 | 617 | wm8994 = devm_kzalloc(&i2c->dev, sizeof(struct wm8994), GFP_KERNEL); |
d0a11693 | 618 | if (wm8994 == NULL) |
9e501086 | 619 | return -ENOMEM; |
9e501086 MB |
620 | |
621 | i2c_set_clientdata(i2c, wm8994); | |
622 | wm8994->dev = &i2c->dev; | |
c9fbf7e0 | 623 | wm8994->irq = i2c->irq; |
20fb2772 | 624 | |
0db434f5 | 625 | wm8994->type = (enum wm8994_type)i2c_get_match_data(i2c); |
9e501086 | 626 | |
9db4249f | 627 | wm8994->regmap = devm_regmap_init_i2c(i2c, &wm8994_base_regmap_config); |
d6c645fc MB |
628 | if (IS_ERR(wm8994->regmap)) { |
629 | ret = PTR_ERR(wm8994->regmap); | |
630 | dev_err(wm8994->dev, "Failed to allocate register map: %d\n", | |
631 | ret); | |
d6c645fc MB |
632 | return ret; |
633 | } | |
634 | ||
559e0df6 | 635 | return wm8994_device_init(wm8994, i2c->irq); |
9e501086 MB |
636 | } |
637 | ||
ed5c2f5f | 638 | static void wm8994_i2c_remove(struct i2c_client *i2c) |
9e501086 MB |
639 | { |
640 | struct wm8994 *wm8994 = i2c_get_clientdata(i2c); | |
641 | ||
642 | wm8994_device_exit(wm8994); | |
9e501086 MB |
643 | } |
644 | ||
9e501086 | 645 | static const struct i2c_device_id wm8994_i2c_id[] = { |
b1f43bf3 | 646 | { "wm1811", WM1811 }, |
71d17184 | 647 | { "wm1811a", WM1811 }, |
559e0df6 MB |
648 | { "wm8994", WM8994 }, |
649 | { "wm8958", WM8958 }, | |
9e501086 MB |
650 | { } |
651 | }; | |
652 | MODULE_DEVICE_TABLE(i2c, wm8994_i2c_id); | |
653 | ||
6394678e | 654 | static const struct dev_pm_ops wm8994_pm_ops = { |
9dd3baec | 655 | RUNTIME_PM_OPS(wm8994_suspend, wm8994_resume, NULL) |
6394678e | 656 | }; |
d450f19e | 657 | |
9e501086 MB |
658 | static struct i2c_driver wm8994_i2c_driver = { |
659 | .driver = { | |
d450f19e | 660 | .name = "wm8994", |
9dd3baec | 661 | .pm = pm_ptr(&wm8994_pm_ops), |
7b64f245 | 662 | .of_match_table = wm8994_of_match, |
9e501086 | 663 | }, |
9816d859 | 664 | .probe = wm8994_i2c_probe, |
84449216 | 665 | .remove = wm8994_i2c_remove, |
9e501086 MB |
666 | .id_table = wm8994_i2c_id, |
667 | }; | |
668 | ||
ceb57d27 | 669 | module_i2c_driver(wm8994_i2c_driver); |
9e501086 MB |
670 | |
671 | MODULE_DESCRIPTION("Core support for the WM8994 audio CODEC"); | |
672 | MODULE_LICENSE("GPL"); | |
673 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); | |
d4f9b542 | 674 | MODULE_SOFTDEP("pre: wm8994_regulator"); |