Commit | Line | Data |
---|---|---|
d6871a73 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
16b27467 RF |
2 | /* |
3 | * Core MFD support for Cirrus Logic Madera codecs | |
4 | * | |
5 | * Copyright (C) 2015-2018 Cirrus Logic | |
16b27467 RF |
6 | */ |
7 | ||
8 | #include <linux/device.h> | |
9 | #include <linux/delay.h> | |
10 | #include <linux/err.h> | |
de5567ca | 11 | #include <linux/gpio/consumer.h> |
16b27467 RF |
12 | #include <linux/mfd/core.h> |
13 | #include <linux/module.h> | |
7f947213 | 14 | #include <linux/mutex.h> |
16b27467 RF |
15 | #include <linux/notifier.h> |
16 | #include <linux/of.h> | |
16b27467 RF |
17 | #include <linux/platform_device.h> |
18 | #include <linux/pm_runtime.h> | |
19 | #include <linux/regmap.h> | |
20 | #include <linux/regulator/consumer.h> | |
21 | #include <linux/regulator/machine.h> | |
22 | #include <linux/regulator/of_regulator.h> | |
23 | ||
24 | #include <linux/mfd/madera/core.h> | |
25 | #include <linux/mfd/madera/registers.h> | |
26 | ||
27 | #include "madera.h" | |
28 | ||
1ef921b6 | 29 | #define CS47L15_SILICON_ID 0x6370 |
16b27467 RF |
30 | #define CS47L35_SILICON_ID 0x6360 |
31 | #define CS47L85_SILICON_ID 0x6338 | |
32 | #define CS47L90_SILICON_ID 0x6364 | |
29793990 | 33 | #define CS47L92_SILICON_ID 0x6371 |
16b27467 RF |
34 | |
35 | #define MADERA_32KZ_MCLK2 1 | |
36 | ||
003035b3 CK |
37 | #define MADERA_RESET_MIN_US 2000 |
38 | #define MADERA_RESET_MAX_US 3000 | |
39 | ||
f594d01b CK |
40 | #define ERRATA_DCVDD_MIN_US 10000 |
41 | #define ERRATA_DCVDD_MAX_US 15000 | |
42 | ||
16b27467 RF |
43 | static const char * const madera_core_supplies[] = { |
44 | "AVDD", | |
45 | "DBVDD1", | |
46 | }; | |
47 | ||
48 | static const struct mfd_cell madera_ldo1_devs[] = { | |
77b3ddab CK |
49 | { |
50 | .name = "madera-ldo1", | |
51 | .level = MFD_DEP_LEVEL_HIGH, | |
52 | }, | |
16b27467 RF |
53 | }; |
54 | ||
1ef921b6 RF |
55 | static const char * const cs47l15_supplies[] = { |
56 | "MICVDD", | |
57 | "CPVDD1", | |
58 | "SPKVDD", | |
59 | }; | |
60 | ||
61 | static const struct mfd_cell cs47l15_devs[] = { | |
62 | { .name = "madera-pinctrl", }, | |
b92735f4 CK |
63 | { .name = "madera-irq", }, |
64 | { .name = "madera-gpio", }, | |
1ef921b6 RF |
65 | { |
66 | .name = "madera-extcon", | |
67 | .parent_supplies = cs47l15_supplies, | |
68 | .num_parent_supplies = 1, /* We only need MICVDD */ | |
69 | }, | |
70 | { | |
71 | .name = "cs47l15-codec", | |
72 | .parent_supplies = cs47l15_supplies, | |
73 | .num_parent_supplies = ARRAY_SIZE(cs47l15_supplies), | |
74 | }, | |
75 | }; | |
76 | ||
16b27467 RF |
77 | static const char * const cs47l35_supplies[] = { |
78 | "MICVDD", | |
79 | "DBVDD2", | |
80 | "CPVDD1", | |
81 | "CPVDD2", | |
82 | "SPKVDD", | |
83 | }; | |
84 | ||
85 | static const struct mfd_cell cs47l35_devs[] = { | |
86 | { .name = "madera-pinctrl", }, | |
87 | { .name = "madera-irq", }, | |
88 | { .name = "madera-micsupp", }, | |
89 | { .name = "madera-gpio", }, | |
ee1856db CK |
90 | { |
91 | .name = "madera-extcon", | |
92 | .parent_supplies = cs47l35_supplies, | |
93 | .num_parent_supplies = 1, /* We only need MICVDD */ | |
94 | }, | |
16b27467 RF |
95 | { |
96 | .name = "cs47l35-codec", | |
97 | .parent_supplies = cs47l35_supplies, | |
98 | .num_parent_supplies = ARRAY_SIZE(cs47l35_supplies), | |
99 | }, | |
100 | }; | |
101 | ||
102 | static const char * const cs47l85_supplies[] = { | |
103 | "MICVDD", | |
104 | "DBVDD2", | |
105 | "DBVDD3", | |
106 | "DBVDD4", | |
107 | "CPVDD1", | |
108 | "CPVDD2", | |
109 | "SPKVDDL", | |
110 | "SPKVDDR", | |
111 | }; | |
112 | ||
113 | static const struct mfd_cell cs47l85_devs[] = { | |
114 | { .name = "madera-pinctrl", }, | |
115 | { .name = "madera-irq", }, | |
b92735f4 | 116 | { .name = "madera-micsupp", }, |
16b27467 | 117 | { .name = "madera-gpio", }, |
ee1856db CK |
118 | { |
119 | .name = "madera-extcon", | |
120 | .parent_supplies = cs47l85_supplies, | |
121 | .num_parent_supplies = 1, /* We only need MICVDD */ | |
122 | }, | |
16b27467 RF |
123 | { |
124 | .name = "cs47l85-codec", | |
125 | .parent_supplies = cs47l85_supplies, | |
126 | .num_parent_supplies = ARRAY_SIZE(cs47l85_supplies), | |
127 | }, | |
128 | }; | |
129 | ||
130 | static const char * const cs47l90_supplies[] = { | |
131 | "MICVDD", | |
132 | "DBVDD2", | |
133 | "DBVDD3", | |
134 | "DBVDD4", | |
135 | "CPVDD1", | |
136 | "CPVDD2", | |
137 | }; | |
138 | ||
139 | static const struct mfd_cell cs47l90_devs[] = { | |
140 | { .name = "madera-pinctrl", }, | |
141 | { .name = "madera-irq", }, | |
142 | { .name = "madera-micsupp", }, | |
143 | { .name = "madera-gpio", }, | |
ee1856db CK |
144 | { |
145 | .name = "madera-extcon", | |
146 | .parent_supplies = cs47l90_supplies, | |
147 | .num_parent_supplies = 1, /* We only need MICVDD */ | |
148 | }, | |
16b27467 RF |
149 | { |
150 | .name = "cs47l90-codec", | |
151 | .parent_supplies = cs47l90_supplies, | |
152 | .num_parent_supplies = ARRAY_SIZE(cs47l90_supplies), | |
153 | }, | |
154 | }; | |
155 | ||
29793990 RF |
156 | static const char * const cs47l92_supplies[] = { |
157 | "MICVDD", | |
158 | "CPVDD1", | |
159 | "CPVDD2", | |
160 | }; | |
161 | ||
162 | static const struct mfd_cell cs47l92_devs[] = { | |
b92735f4 | 163 | { .name = "madera-pinctrl", }, |
29793990 RF |
164 | { .name = "madera-irq", }, |
165 | { .name = "madera-micsupp", }, | |
b92735f4 | 166 | { .name = "madera-gpio", }, |
29793990 RF |
167 | { |
168 | .name = "madera-extcon", | |
169 | .parent_supplies = cs47l92_supplies, | |
170 | .num_parent_supplies = 1, /* We only need MICVDD */ | |
171 | }, | |
172 | { | |
173 | .name = "cs47l92-codec", | |
174 | .parent_supplies = cs47l92_supplies, | |
175 | .num_parent_supplies = ARRAY_SIZE(cs47l92_supplies), | |
176 | }, | |
177 | }; | |
178 | ||
16b27467 RF |
179 | /* Used by madera-i2c and madera-spi drivers */ |
180 | const char *madera_name_from_type(enum madera_type type) | |
181 | { | |
182 | switch (type) { | |
1ef921b6 RF |
183 | case CS47L15: |
184 | return "CS47L15"; | |
16b27467 RF |
185 | case CS47L35: |
186 | return "CS47L35"; | |
187 | case CS47L85: | |
188 | return "CS47L85"; | |
189 | case CS47L90: | |
190 | return "CS47L90"; | |
191 | case CS47L91: | |
192 | return "CS47L91"; | |
29793990 RF |
193 | case CS42L92: |
194 | return "CS42L92"; | |
195 | case CS47L92: | |
196 | return "CS47L92"; | |
197 | case CS47L93: | |
198 | return "CS47L93"; | |
16b27467 RF |
199 | case WM1840: |
200 | return "WM1840"; | |
201 | default: | |
202 | return "Unknown"; | |
203 | } | |
204 | } | |
205 | EXPORT_SYMBOL_GPL(madera_name_from_type); | |
206 | ||
b04e68d1 RF |
207 | #define MADERA_BOOT_POLL_INTERVAL_USEC 5000 |
208 | #define MADERA_BOOT_POLL_TIMEOUT_USEC 25000 | |
16b27467 | 209 | |
7f6d8698 | 210 | static int madera_wait_for_boot_noack(struct madera *madera) |
16b27467 | 211 | { |
b04e68d1 | 212 | ktime_t timeout; |
32325016 | 213 | unsigned int val = 0; |
b04e68d1 | 214 | int ret = 0; |
16b27467 RF |
215 | |
216 | /* | |
217 | * We can't use an interrupt as we need to runtime resume to do so, | |
218 | * so we poll the status bit. This won't race with the interrupt | |
219 | * handler because it will be blocked on runtime resume. | |
b04e68d1 RF |
220 | * The chip could NAK a read request while it is booting so ignore |
221 | * errors from regmap_read. | |
16b27467 | 222 | */ |
b04e68d1 RF |
223 | timeout = ktime_add_us(ktime_get(), MADERA_BOOT_POLL_TIMEOUT_USEC); |
224 | regmap_read(madera->regmap, MADERA_IRQ1_RAW_STATUS_1, &val); | |
225 | while (!(val & MADERA_BOOT_DONE_STS1) && | |
226 | !ktime_after(ktime_get(), timeout)) { | |
227 | usleep_range(MADERA_BOOT_POLL_INTERVAL_USEC / 2, | |
228 | MADERA_BOOT_POLL_INTERVAL_USEC); | |
229 | regmap_read(madera->regmap, MADERA_IRQ1_RAW_STATUS_1, &val); | |
4bcb83e0 | 230 | } |
b04e68d1 RF |
231 | |
232 | if (!(val & MADERA_BOOT_DONE_STS1)) { | |
233 | dev_err(madera->dev, "Polling BOOT_DONE_STS timed out\n"); | |
234 | ret = -ETIMEDOUT; | |
235 | } | |
16b27467 | 236 | |
7f6d8698 CK |
237 | return ret; |
238 | } | |
239 | ||
240 | static int madera_wait_for_boot(struct madera *madera) | |
241 | { | |
242 | int ret = madera_wait_for_boot_noack(madera); | |
243 | ||
16b27467 RF |
244 | /* |
245 | * BOOT_DONE defaults to unmasked on boot so we must ack it. | |
b04e68d1 | 246 | * Do this even after a timeout to avoid interrupt storms. |
16b27467 RF |
247 | */ |
248 | regmap_write(madera->regmap, MADERA_IRQ1_STATUS_1, | |
249 | MADERA_BOOT_DONE_EINT1); | |
250 | ||
251 | pm_runtime_mark_last_busy(madera->dev); | |
252 | ||
253 | return ret; | |
254 | } | |
255 | ||
256 | static int madera_soft_reset(struct madera *madera) | |
257 | { | |
258 | int ret; | |
259 | ||
260 | ret = regmap_write(madera->regmap, MADERA_SOFTWARE_RESET, 0); | |
261 | if (ret != 0) { | |
262 | dev_err(madera->dev, "Failed to soft reset device: %d\n", ret); | |
263 | return ret; | |
264 | } | |
265 | ||
266 | /* Allow time for internal clocks to startup after reset */ | |
003035b3 | 267 | usleep_range(MADERA_RESET_MIN_US, MADERA_RESET_MAX_US); |
16b27467 RF |
268 | |
269 | return 0; | |
270 | } | |
271 | ||
272 | static void madera_enable_hard_reset(struct madera *madera) | |
273 | { | |
16b27467 RF |
274 | /* |
275 | * There are many existing out-of-tree users of these codecs that we | |
276 | * can't break so preserve the expected behaviour of setting the line | |
277 | * low to assert reset. | |
278 | */ | |
279 | gpiod_set_raw_value_cansleep(madera->pdata.reset, 0); | |
280 | } | |
281 | ||
282 | static void madera_disable_hard_reset(struct madera *madera) | |
283 | { | |
16b27467 | 284 | gpiod_set_raw_value_cansleep(madera->pdata.reset, 1); |
003035b3 CK |
285 | |
286 | usleep_range(MADERA_RESET_MIN_US, MADERA_RESET_MAX_US); | |
16b27467 RF |
287 | } |
288 | ||
289 | static int __maybe_unused madera_runtime_resume(struct device *dev) | |
290 | { | |
291 | struct madera *madera = dev_get_drvdata(dev); | |
292 | int ret; | |
293 | ||
294 | dev_dbg(dev, "Leaving sleep mode\n"); | |
295 | ||
f594d01b CK |
296 | if (!madera->reset_errata) |
297 | madera_enable_hard_reset(madera); | |
1cd7b935 | 298 | |
16b27467 RF |
299 | ret = regulator_enable(madera->dcvdd); |
300 | if (ret) { | |
301 | dev_err(dev, "Failed to enable DCVDD: %d\n", ret); | |
302 | return ret; | |
303 | } | |
304 | ||
305 | regcache_cache_only(madera->regmap, false); | |
306 | regcache_cache_only(madera->regmap_32bit, false); | |
307 | ||
f594d01b CK |
308 | if (madera->reset_errata) |
309 | usleep_range(ERRATA_DCVDD_MIN_US, ERRATA_DCVDD_MAX_US); | |
310 | else | |
311 | madera_disable_hard_reset(madera); | |
1cd7b935 | 312 | |
f594d01b | 313 | if (!madera->pdata.reset || madera->reset_errata) { |
1cd7b935 CK |
314 | ret = madera_wait_for_boot(madera); |
315 | if (ret) | |
316 | goto err; | |
317 | ||
318 | ret = madera_soft_reset(madera); | |
319 | if (ret) { | |
320 | dev_err(dev, "Failed to reset: %d\n", ret); | |
321 | goto err; | |
322 | } | |
323 | } | |
003035b3 | 324 | |
16b27467 RF |
325 | ret = madera_wait_for_boot(madera); |
326 | if (ret) | |
327 | goto err; | |
328 | ||
329 | ret = regcache_sync(madera->regmap); | |
330 | if (ret) { | |
331 | dev_err(dev, "Failed to restore 16-bit register cache\n"); | |
332 | goto err; | |
333 | } | |
334 | ||
335 | ret = regcache_sync(madera->regmap_32bit); | |
336 | if (ret) { | |
337 | dev_err(dev, "Failed to restore 32-bit register cache\n"); | |
338 | goto err; | |
339 | } | |
340 | ||
341 | return 0; | |
342 | ||
343 | err: | |
344 | regcache_cache_only(madera->regmap_32bit, true); | |
345 | regcache_cache_only(madera->regmap, true); | |
346 | regulator_disable(madera->dcvdd); | |
347 | ||
348 | return ret; | |
349 | } | |
350 | ||
351 | static int __maybe_unused madera_runtime_suspend(struct device *dev) | |
352 | { | |
353 | struct madera *madera = dev_get_drvdata(dev); | |
354 | ||
355 | dev_dbg(madera->dev, "Entering sleep mode\n"); | |
356 | ||
357 | regcache_cache_only(madera->regmap, true); | |
358 | regcache_mark_dirty(madera->regmap); | |
359 | regcache_cache_only(madera->regmap_32bit, true); | |
360 | regcache_mark_dirty(madera->regmap_32bit); | |
361 | ||
362 | regulator_disable(madera->dcvdd); | |
363 | ||
364 | return 0; | |
365 | } | |
366 | ||
367 | const struct dev_pm_ops madera_pm_ops = { | |
368 | SET_RUNTIME_PM_OPS(madera_runtime_suspend, | |
369 | madera_runtime_resume, | |
370 | NULL) | |
371 | }; | |
372 | EXPORT_SYMBOL_GPL(madera_pm_ops); | |
373 | ||
374 | const struct of_device_id madera_of_match[] = { | |
1ef921b6 | 375 | { .compatible = "cirrus,cs47l15", .data = (void *)CS47L15 }, |
16b27467 RF |
376 | { .compatible = "cirrus,cs47l35", .data = (void *)CS47L35 }, |
377 | { .compatible = "cirrus,cs47l85", .data = (void *)CS47L85 }, | |
378 | { .compatible = "cirrus,cs47l90", .data = (void *)CS47L90 }, | |
379 | { .compatible = "cirrus,cs47l91", .data = (void *)CS47L91 }, | |
29793990 RF |
380 | { .compatible = "cirrus,cs42l92", .data = (void *)CS42L92 }, |
381 | { .compatible = "cirrus,cs47l92", .data = (void *)CS47L92 }, | |
382 | { .compatible = "cirrus,cs47l93", .data = (void *)CS47L93 }, | |
16b27467 RF |
383 | { .compatible = "cirrus,wm1840", .data = (void *)WM1840 }, |
384 | {} | |
385 | }; | |
5aa3709c | 386 | MODULE_DEVICE_TABLE(of, madera_of_match); |
16b27467 RF |
387 | EXPORT_SYMBOL_GPL(madera_of_match); |
388 | ||
389 | static int madera_get_reset_gpio(struct madera *madera) | |
390 | { | |
391 | struct gpio_desc *reset; | |
16b27467 RF |
392 | |
393 | if (madera->pdata.reset) | |
394 | return 0; | |
395 | ||
396 | reset = devm_gpiod_get_optional(madera->dev, "reset", GPIOD_OUT_LOW); | |
f104563f KK |
397 | if (IS_ERR(reset)) |
398 | return dev_err_probe(madera->dev, PTR_ERR(reset), | |
399 | "Failed to request /RESET"); | |
16b27467 RF |
400 | |
401 | /* | |
402 | * A hard reset is needed for full reset of the chip. We allow running | |
403 | * without hard reset only because it can be useful for early | |
404 | * prototyping and some debugging, but we need to warn it's not ideal. | |
405 | */ | |
406 | if (!reset) | |
407 | dev_warn(madera->dev, | |
408 | "Running without reset GPIO is not recommended\n"); | |
409 | ||
410 | madera->pdata.reset = reset; | |
411 | ||
412 | return 0; | |
413 | } | |
414 | ||
415 | static void madera_set_micbias_info(struct madera *madera) | |
416 | { | |
417 | /* | |
418 | * num_childbias is an array because future codecs can have different | |
419 | * childbiases for each micbias. Unspecified values default to 0. | |
420 | */ | |
421 | switch (madera->type) { | |
1ef921b6 RF |
422 | case CS47L15: |
423 | madera->num_micbias = 1; | |
424 | madera->num_childbias[0] = 3; | |
425 | return; | |
16b27467 RF |
426 | case CS47L35: |
427 | madera->num_micbias = 2; | |
428 | madera->num_childbias[0] = 2; | |
429 | madera->num_childbias[1] = 2; | |
430 | return; | |
431 | case CS47L85: | |
432 | case WM1840: | |
433 | madera->num_micbias = 4; | |
434 | /* no child biases */ | |
435 | return; | |
436 | case CS47L90: | |
437 | case CS47L91: | |
438 | madera->num_micbias = 2; | |
439 | madera->num_childbias[0] = 4; | |
440 | madera->num_childbias[1] = 4; | |
441 | return; | |
29793990 RF |
442 | case CS42L92: |
443 | case CS47L92: | |
444 | case CS47L93: | |
445 | madera->num_micbias = 2; | |
446 | madera->num_childbias[0] = 4; | |
447 | madera->num_childbias[1] = 2; | |
448 | return; | |
16b27467 RF |
449 | default: |
450 | return; | |
451 | } | |
452 | } | |
453 | ||
454 | int madera_dev_init(struct madera *madera) | |
455 | { | |
456 | struct device *dev = madera->dev; | |
457 | unsigned int hwid; | |
458 | int (*patch_fn)(struct madera *) = NULL; | |
459 | const struct mfd_cell *mfd_devs; | |
460 | int n_devs = 0; | |
461 | int i, ret; | |
462 | ||
463 | dev_set_drvdata(madera->dev, madera); | |
464 | BLOCKING_INIT_NOTIFIER_HEAD(&madera->notifier); | |
7f947213 RF |
465 | mutex_init(&madera->dapm_ptr_lock); |
466 | ||
16b27467 RF |
467 | madera_set_micbias_info(madera); |
468 | ||
469 | /* | |
470 | * We need writable hw config info that all children can share. | |
471 | * Simplest to take one shared copy of pdata struct. | |
472 | */ | |
473 | if (dev_get_platdata(madera->dev)) { | |
474 | memcpy(&madera->pdata, dev_get_platdata(madera->dev), | |
475 | sizeof(madera->pdata)); | |
476 | } | |
477 | ||
1e624fce CK |
478 | madera->mclk[MADERA_MCLK1].id = "mclk1"; |
479 | madera->mclk[MADERA_MCLK2].id = "mclk2"; | |
480 | madera->mclk[MADERA_MCLK3].id = "mclk3"; | |
481 | ||
482 | ret = devm_clk_bulk_get_optional(madera->dev, ARRAY_SIZE(madera->mclk), | |
483 | madera->mclk); | |
484 | if (ret) { | |
485 | dev_err(madera->dev, "Failed to get clocks: %d\n", ret); | |
486 | return ret; | |
487 | } | |
488 | ||
489 | /* Not using devm_clk_get to prevent breakage of existing DTs */ | |
490 | if (!madera->mclk[MADERA_MCLK2].clk) | |
491 | dev_warn(madera->dev, "Missing MCLK2, requires 32kHz clock\n"); | |
492 | ||
16b27467 RF |
493 | ret = madera_get_reset_gpio(madera); |
494 | if (ret) | |
495 | return ret; | |
496 | ||
497 | regcache_cache_only(madera->regmap, true); | |
498 | regcache_cache_only(madera->regmap_32bit, true); | |
499 | ||
500 | for (i = 0; i < ARRAY_SIZE(madera_core_supplies); i++) | |
501 | madera->core_supplies[i].supply = madera_core_supplies[i]; | |
502 | ||
503 | madera->num_core_supplies = ARRAY_SIZE(madera_core_supplies); | |
504 | ||
505 | /* | |
506 | * On some codecs DCVDD could be supplied by the internal LDO1. | |
507 | * For those we must add the LDO1 driver before requesting DCVDD | |
508 | * No devm_ because we need to control shutdown order of children. | |
509 | */ | |
510 | switch (madera->type) { | |
1ef921b6 | 511 | case CS47L15: |
f594d01b CK |
512 | madera->reset_errata = true; |
513 | break; | |
16b27467 RF |
514 | case CS47L35: |
515 | case CS47L90: | |
516 | case CS47L91: | |
29793990 RF |
517 | case CS42L92: |
518 | case CS47L92: | |
519 | case CS47L93: | |
16b27467 RF |
520 | break; |
521 | case CS47L85: | |
522 | case WM1840: | |
523 | ret = mfd_add_devices(madera->dev, PLATFORM_DEVID_NONE, | |
524 | madera_ldo1_devs, | |
525 | ARRAY_SIZE(madera_ldo1_devs), | |
526 | NULL, 0, NULL); | |
527 | if (ret) { | |
528 | dev_err(dev, "Failed to add LDO1 child: %d\n", ret); | |
529 | return ret; | |
530 | } | |
531 | break; | |
532 | default: | |
533 | /* No point continuing if the type is unknown */ | |
534 | dev_err(madera->dev, "Unknown device type %d\n", madera->type); | |
535 | return -ENODEV; | |
536 | } | |
537 | ||
538 | ret = devm_regulator_bulk_get(dev, madera->num_core_supplies, | |
539 | madera->core_supplies); | |
540 | if (ret) { | |
541 | dev_err(dev, "Failed to request core supplies: %d\n", ret); | |
542 | goto err_devs; | |
543 | } | |
544 | ||
545 | /* | |
546 | * Don't use devres here. If the regulator is one of our children it | |
547 | * will already have been removed before devres cleanup on this mfd | |
548 | * driver tries to call put() on it. We need control of shutdown order. | |
549 | */ | |
550 | madera->dcvdd = regulator_get(madera->dev, "DCVDD"); | |
551 | if (IS_ERR(madera->dcvdd)) { | |
552 | ret = PTR_ERR(madera->dcvdd); | |
553 | dev_err(dev, "Failed to request DCVDD: %d\n", ret); | |
554 | goto err_devs; | |
555 | } | |
556 | ||
557 | ret = regulator_bulk_enable(madera->num_core_supplies, | |
558 | madera->core_supplies); | |
559 | if (ret) { | |
560 | dev_err(dev, "Failed to enable core supplies: %d\n", ret); | |
561 | goto err_dcvdd; | |
562 | } | |
563 | ||
f594d01b CK |
564 | if (madera->reset_errata) |
565 | madera_disable_hard_reset(madera); | |
566 | ||
16b27467 RF |
567 | ret = regulator_enable(madera->dcvdd); |
568 | if (ret) { | |
569 | dev_err(dev, "Failed to enable DCVDD: %d\n", ret); | |
570 | goto err_enable; | |
571 | } | |
572 | ||
f594d01b CK |
573 | if (madera->reset_errata) |
574 | usleep_range(ERRATA_DCVDD_MIN_US, ERRATA_DCVDD_MAX_US); | |
575 | else | |
576 | madera_disable_hard_reset(madera); | |
16b27467 RF |
577 | |
578 | regcache_cache_only(madera->regmap, false); | |
579 | regcache_cache_only(madera->regmap_32bit, false); | |
580 | ||
7f6d8698 CK |
581 | ret = madera_wait_for_boot_noack(madera); |
582 | if (ret) { | |
583 | dev_err(madera->dev, "Device failed initial boot: %d\n", ret); | |
584 | goto err_reset; | |
585 | } | |
586 | ||
16b27467 RF |
587 | /* |
588 | * Now we can power up and verify that this is a chip we know about | |
589 | * before we start doing any writes to its registers. | |
590 | */ | |
591 | ret = regmap_read(madera->regmap, MADERA_SOFTWARE_RESET, &hwid); | |
592 | if (ret) { | |
593 | dev_err(dev, "Failed to read ID register: %d\n", ret); | |
594 | goto err_reset; | |
595 | } | |
596 | ||
597 | switch (hwid) { | |
1ef921b6 RF |
598 | case CS47L15_SILICON_ID: |
599 | if (IS_ENABLED(CONFIG_MFD_CS47L15)) { | |
600 | switch (madera->type) { | |
601 | case CS47L15: | |
602 | patch_fn = &cs47l15_patch; | |
603 | mfd_devs = cs47l15_devs; | |
604 | n_devs = ARRAY_SIZE(cs47l15_devs); | |
605 | break; | |
606 | default: | |
607 | break; | |
608 | } | |
609 | } | |
610 | break; | |
16b27467 RF |
611 | case CS47L35_SILICON_ID: |
612 | if (IS_ENABLED(CONFIG_MFD_CS47L35)) { | |
613 | switch (madera->type) { | |
614 | case CS47L35: | |
615 | patch_fn = cs47l35_patch; | |
616 | mfd_devs = cs47l35_devs; | |
617 | n_devs = ARRAY_SIZE(cs47l35_devs); | |
618 | break; | |
619 | default: | |
620 | break; | |
621 | } | |
622 | } | |
623 | break; | |
624 | case CS47L85_SILICON_ID: | |
625 | if (IS_ENABLED(CONFIG_MFD_CS47L85)) { | |
626 | switch (madera->type) { | |
627 | case CS47L85: | |
628 | case WM1840: | |
629 | patch_fn = cs47l85_patch; | |
630 | mfd_devs = cs47l85_devs; | |
631 | n_devs = ARRAY_SIZE(cs47l85_devs); | |
632 | break; | |
633 | default: | |
634 | break; | |
635 | } | |
636 | } | |
637 | break; | |
638 | case CS47L90_SILICON_ID: | |
639 | if (IS_ENABLED(CONFIG_MFD_CS47L90)) { | |
640 | switch (madera->type) { | |
641 | case CS47L90: | |
642 | case CS47L91: | |
643 | patch_fn = cs47l90_patch; | |
644 | mfd_devs = cs47l90_devs; | |
645 | n_devs = ARRAY_SIZE(cs47l90_devs); | |
646 | break; | |
647 | default: | |
648 | break; | |
649 | } | |
650 | } | |
651 | break; | |
29793990 RF |
652 | case CS47L92_SILICON_ID: |
653 | if (IS_ENABLED(CONFIG_MFD_CS47L92)) { | |
654 | switch (madera->type) { | |
655 | case CS42L92: | |
656 | case CS47L92: | |
657 | case CS47L93: | |
658 | patch_fn = cs47l92_patch; | |
659 | mfd_devs = cs47l92_devs; | |
660 | n_devs = ARRAY_SIZE(cs47l92_devs); | |
661 | break; | |
662 | default: | |
663 | break; | |
664 | } | |
665 | } | |
666 | break; | |
16b27467 RF |
667 | default: |
668 | dev_err(madera->dev, "Unknown device ID: %x\n", hwid); | |
669 | ret = -EINVAL; | |
670 | goto err_reset; | |
671 | } | |
672 | ||
673 | if (!n_devs) { | |
674 | dev_err(madera->dev, "Device ID 0x%x not a %s\n", hwid, | |
675 | madera->type_name); | |
676 | ret = -ENODEV; | |
677 | goto err_reset; | |
678 | } | |
679 | ||
680 | /* | |
681 | * It looks like a device we support. If we don't have a hard reset | |
682 | * we can now attempt a soft reset. | |
683 | */ | |
f594d01b | 684 | if (!madera->pdata.reset || madera->reset_errata) { |
16b27467 RF |
685 | ret = madera_soft_reset(madera); |
686 | if (ret) | |
687 | goto err_reset; | |
688 | } | |
689 | ||
690 | ret = madera_wait_for_boot(madera); | |
691 | if (ret) { | |
7f6d8698 | 692 | dev_err(madera->dev, "Failed to clear boot done: %d\n", ret); |
16b27467 RF |
693 | goto err_reset; |
694 | } | |
695 | ||
696 | ret = regmap_read(madera->regmap, MADERA_HARDWARE_REVISION, | |
697 | &madera->rev); | |
698 | if (ret) { | |
699 | dev_err(dev, "Failed to read revision register: %d\n", ret); | |
700 | goto err_reset; | |
701 | } | |
702 | madera->rev &= MADERA_HW_REVISION_MASK; | |
703 | ||
704 | dev_info(dev, "%s silicon revision %d\n", madera->type_name, | |
705 | madera->rev); | |
706 | ||
707 | /* Apply hardware patch */ | |
708 | if (patch_fn) { | |
709 | ret = patch_fn(madera); | |
710 | if (ret) { | |
711 | dev_err(madera->dev, "Failed to apply patch %d\n", ret); | |
712 | goto err_reset; | |
713 | } | |
714 | } | |
715 | ||
716 | /* Init 32k clock sourced from MCLK2 */ | |
1e624fce CK |
717 | ret = clk_prepare_enable(madera->mclk[MADERA_MCLK2].clk); |
718 | if (ret) { | |
719 | dev_err(madera->dev, "Failed to enable 32k clock: %d\n", ret); | |
720 | goto err_reset; | |
721 | } | |
722 | ||
16b27467 RF |
723 | ret = regmap_update_bits(madera->regmap, |
724 | MADERA_CLOCK_32K_1, | |
725 | MADERA_CLK_32K_ENA_MASK | MADERA_CLK_32K_SRC_MASK, | |
726 | MADERA_CLK_32K_ENA | MADERA_32KZ_MCLK2); | |
727 | if (ret) { | |
728 | dev_err(madera->dev, "Failed to init 32k clock: %d\n", ret); | |
1e624fce | 729 | goto err_clock; |
16b27467 RF |
730 | } |
731 | ||
732 | pm_runtime_set_active(madera->dev); | |
733 | pm_runtime_enable(madera->dev); | |
734 | pm_runtime_set_autosuspend_delay(madera->dev, 100); | |
735 | pm_runtime_use_autosuspend(madera->dev); | |
736 | ||
737 | /* No devm_ because we need to control shutdown order of children */ | |
738 | ret = mfd_add_devices(madera->dev, PLATFORM_DEVID_NONE, | |
739 | mfd_devs, n_devs, | |
740 | NULL, 0, NULL); | |
741 | if (ret) { | |
742 | dev_err(madera->dev, "Failed to add subdevices: %d\n", ret); | |
743 | goto err_pm_runtime; | |
744 | } | |
745 | ||
746 | return 0; | |
747 | ||
748 | err_pm_runtime: | |
749 | pm_runtime_disable(madera->dev); | |
1e624fce CK |
750 | err_clock: |
751 | clk_disable_unprepare(madera->mclk[MADERA_MCLK2].clk); | |
16b27467 RF |
752 | err_reset: |
753 | madera_enable_hard_reset(madera); | |
754 | regulator_disable(madera->dcvdd); | |
755 | err_enable: | |
756 | regulator_bulk_disable(madera->num_core_supplies, | |
757 | madera->core_supplies); | |
758 | err_dcvdd: | |
759 | regulator_put(madera->dcvdd); | |
760 | err_devs: | |
761 | mfd_remove_devices(dev); | |
762 | ||
763 | return ret; | |
764 | } | |
765 | EXPORT_SYMBOL_GPL(madera_dev_init); | |
766 | ||
767 | int madera_dev_exit(struct madera *madera) | |
768 | { | |
769 | /* Prevent any IRQs being serviced while we clean up */ | |
770 | disable_irq(madera->irq); | |
771 | ||
77b3ddab | 772 | pm_runtime_get_sync(madera->dev); |
16b27467 | 773 | |
77b3ddab CK |
774 | mfd_remove_devices(madera->dev); |
775 | ||
776 | pm_runtime_disable(madera->dev); | |
1e624fce | 777 | |
16b27467 RF |
778 | regulator_disable(madera->dcvdd); |
779 | regulator_put(madera->dcvdd); | |
780 | ||
77b3ddab CK |
781 | mfd_remove_devices_late(madera->dev); |
782 | ||
783 | pm_runtime_set_suspended(madera->dev); | |
784 | pm_runtime_put_noidle(madera->dev); | |
785 | ||
786 | clk_disable_unprepare(madera->mclk[MADERA_MCLK2].clk); | |
787 | ||
16b27467 RF |
788 | madera_enable_hard_reset(madera); |
789 | ||
790 | regulator_bulk_disable(madera->num_core_supplies, | |
791 | madera->core_supplies); | |
792 | return 0; | |
793 | } | |
794 | EXPORT_SYMBOL_GPL(madera_dev_exit); | |
795 | ||
796 | MODULE_DESCRIPTION("Madera core MFD driver"); | |
797 | MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>"); | |
798 | MODULE_LICENSE("GPL v2"); |