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