blob: a2abc0094def75cc807e1aa99284b9141b011b1d [file] [log] [blame]
Charles Keepaxd6871a72019-06-26 14:33:36 +01001// SPDX-License-Identifier: GPL-2.0-only
Richard Fitzgerald16b27462018-05-21 10:59:56 +01002/*
3 * Core MFD support for Cirrus Logic Madera codecs
4 *
5 * Copyright (C) 2015-2018 Cirrus Logic
Richard Fitzgerald16b27462018-05-21 10:59:56 +01006 */
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>
Richard Fitzgerald7f947212018-11-12 15:28:37 +000014#include <linux/mutex.h>
Richard Fitzgerald16b27462018-05-21 10:59:56 +010015#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
Richard Fitzgerald1ef921b2019-05-30 15:39:52 +010030#define CS47L15_SILICON_ID 0x6370
Richard Fitzgerald16b27462018-05-21 10:59:56 +010031#define CS47L35_SILICON_ID 0x6360
32#define CS47L85_SILICON_ID 0x6338
33#define CS47L90_SILICON_ID 0x6364
Richard Fitzgerald29793992019-05-30 15:39:53 +010034#define CS47L92_SILICON_ID 0x6371
Richard Fitzgerald16b27462018-05-21 10:59:56 +010035
36#define MADERA_32KZ_MCLK2 1
37
Charles Keepax003035b2020-01-14 15:10:48 +000038#define MADERA_RESET_MIN_US 2000
39#define MADERA_RESET_MAX_US 3000
40
Charles Keepaxf594d012020-10-27 09:41:32 +000041#define ERRATA_DCVDD_MIN_US 10000
42#define ERRATA_DCVDD_MAX_US 15000
43
Richard Fitzgerald16b27462018-05-21 10:59:56 +010044static const char * const madera_core_supplies[] = {
45 "AVDD",
46 "DBVDD1",
47};
48
49static const struct mfd_cell madera_ldo1_devs[] = {
Charles Keepax77b3dda2020-07-23 11:54:59 +010050 {
51 .name = "madera-ldo1",
52 .level = MFD_DEP_LEVEL_HIGH,
53 },
Richard Fitzgerald16b27462018-05-21 10:59:56 +010054};
55
Richard Fitzgerald1ef921b2019-05-30 15:39:52 +010056static const char * const cs47l15_supplies[] = {
57 "MICVDD",
58 "CPVDD1",
59 "SPKVDD",
60};
61
62static const struct mfd_cell cs47l15_devs[] = {
63 { .name = "madera-pinctrl", },
Charles Keepaxb92735f2020-06-15 14:53:23 +010064 { .name = "madera-irq", },
65 { .name = "madera-gpio", },
Richard Fitzgerald1ef921b2019-05-30 15:39:52 +010066 {
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
Richard Fitzgerald16b27462018-05-21 10:59:56 +010078static const char * const cs47l35_supplies[] = {
79 "MICVDD",
80 "DBVDD2",
81 "CPVDD1",
82 "CPVDD2",
83 "SPKVDD",
84};
85
86static const struct mfd_cell cs47l35_devs[] = {
87 { .name = "madera-pinctrl", },
88 { .name = "madera-irq", },
89 { .name = "madera-micsupp", },
90 { .name = "madera-gpio", },
Charles Keepaxee1856d2019-05-20 10:06:28 +010091 {
92 .name = "madera-extcon",
93 .parent_supplies = cs47l35_supplies,
94 .num_parent_supplies = 1, /* We only need MICVDD */
95 },
Richard Fitzgerald16b27462018-05-21 10:59:56 +010096 {
97 .name = "cs47l35-codec",
98 .parent_supplies = cs47l35_supplies,
99 .num_parent_supplies = ARRAY_SIZE(cs47l35_supplies),
100 },
101};
102
103static const char * const cs47l85_supplies[] = {
104 "MICVDD",
105 "DBVDD2",
106 "DBVDD3",
107 "DBVDD4",
108 "CPVDD1",
109 "CPVDD2",
110 "SPKVDDL",
111 "SPKVDDR",
112};
113
114static const struct mfd_cell cs47l85_devs[] = {
115 { .name = "madera-pinctrl", },
116 { .name = "madera-irq", },
Charles Keepaxb92735f2020-06-15 14:53:23 +0100117 { .name = "madera-micsupp", },
Richard Fitzgerald16b27462018-05-21 10:59:56 +0100118 { .name = "madera-gpio", },
Charles Keepaxee1856d2019-05-20 10:06:28 +0100119 {
120 .name = "madera-extcon",
121 .parent_supplies = cs47l85_supplies,
122 .num_parent_supplies = 1, /* We only need MICVDD */
123 },
Richard Fitzgerald16b27462018-05-21 10:59:56 +0100124 {
125 .name = "cs47l85-codec",
126 .parent_supplies = cs47l85_supplies,
127 .num_parent_supplies = ARRAY_SIZE(cs47l85_supplies),
128 },
129};
130
131static const char * const cs47l90_supplies[] = {
132 "MICVDD",
133 "DBVDD2",
134 "DBVDD3",
135 "DBVDD4",
136 "CPVDD1",
137 "CPVDD2",
138};
139
140static const struct mfd_cell cs47l90_devs[] = {
141 { .name = "madera-pinctrl", },
142 { .name = "madera-irq", },
143 { .name = "madera-micsupp", },
144 { .name = "madera-gpio", },
Charles Keepaxee1856d2019-05-20 10:06:28 +0100145 {
146 .name = "madera-extcon",
147 .parent_supplies = cs47l90_supplies,
148 .num_parent_supplies = 1, /* We only need MICVDD */
149 },
Richard Fitzgerald16b27462018-05-21 10:59:56 +0100150 {
151 .name = "cs47l90-codec",
152 .parent_supplies = cs47l90_supplies,
153 .num_parent_supplies = ARRAY_SIZE(cs47l90_supplies),
154 },
155};
156
Richard Fitzgerald29793992019-05-30 15:39:53 +0100157static const char * const cs47l92_supplies[] = {
158 "MICVDD",
159 "CPVDD1",
160 "CPVDD2",
161};
162
163static const struct mfd_cell cs47l92_devs[] = {
Charles Keepaxb92735f2020-06-15 14:53:23 +0100164 { .name = "madera-pinctrl", },
Richard Fitzgerald29793992019-05-30 15:39:53 +0100165 { .name = "madera-irq", },
166 { .name = "madera-micsupp", },
Charles Keepaxb92735f2020-06-15 14:53:23 +0100167 { .name = "madera-gpio", },
Richard Fitzgerald29793992019-05-30 15:39:53 +0100168 {
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
Richard Fitzgerald16b27462018-05-21 10:59:56 +0100180/* Used by madera-i2c and madera-spi drivers */
181const char *madera_name_from_type(enum madera_type type)
182{
183 switch (type) {
Richard Fitzgerald1ef921b2019-05-30 15:39:52 +0100184 case CS47L15:
185 return "CS47L15";
Richard Fitzgerald16b27462018-05-21 10:59:56 +0100186 case CS47L35:
187 return "CS47L35";
188 case CS47L85:
189 return "CS47L85";
190 case CS47L90:
191 return "CS47L90";
192 case CS47L91:
193 return "CS47L91";
Richard Fitzgerald29793992019-05-30 15:39:53 +0100194 case CS42L92:
195 return "CS42L92";
196 case CS47L92:
197 return "CS47L92";
198 case CS47L93:
199 return "CS47L93";
Richard Fitzgerald16b27462018-05-21 10:59:56 +0100200 case WM1840:
201 return "WM1840";
202 default:
203 return "Unknown";
204 }
205}
206EXPORT_SYMBOL_GPL(madera_name_from_type);
207
Richard Fitzgeraldb04e68d2018-08-27 14:51:15 +0100208#define MADERA_BOOT_POLL_INTERVAL_USEC 5000
209#define MADERA_BOOT_POLL_TIMEOUT_USEC 25000
Richard Fitzgerald16b27462018-05-21 10:59:56 +0100210
Charles Keepax7f6d8692020-01-06 10:28:34 +0000211static int madera_wait_for_boot_noack(struct madera *madera)
Richard Fitzgerald16b27462018-05-21 10:59:56 +0100212{
Richard Fitzgeraldb04e68d2018-08-27 14:51:15 +0100213 ktime_t timeout;
Stuart Henderson32325012019-05-20 10:06:27 +0100214 unsigned int val = 0;
Richard Fitzgeraldb04e68d2018-08-27 14:51:15 +0100215 int ret = 0;
Richard Fitzgerald16b27462018-05-21 10:59:56 +0100216
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.
Richard Fitzgeraldb04e68d2018-08-27 14:51:15 +0100221 * The chip could NAK a read request while it is booting so ignore
222 * errors from regmap_read.
Richard Fitzgerald16b27462018-05-21 10:59:56 +0100223 */
Richard Fitzgeraldb04e68d2018-08-27 14:51:15 +0100224 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);
Richard Fitzgerald4bcb83e2018-12-14 14:39:14 +0000231 }
Richard Fitzgerald16b27462018-05-21 10:59:56 +0100232
Richard Fitzgeraldb04e68d2018-08-27 14:51:15 +0100233 if (!(val & MADERA_BOOT_DONE_STS1)) {
234 dev_err(madera->dev, "Polling BOOT_DONE_STS timed out\n");
235 ret = -ETIMEDOUT;
236 }
Richard Fitzgerald16b27462018-05-21 10:59:56 +0100237
Charles Keepax7f6d8692020-01-06 10:28:34 +0000238 return ret;
239}
240
241static int madera_wait_for_boot(struct madera *madera)
242{
243 int ret = madera_wait_for_boot_noack(madera);
244
Richard Fitzgerald16b27462018-05-21 10:59:56 +0100245 /*
246 * BOOT_DONE defaults to unmasked on boot so we must ack it.
Richard Fitzgeraldb04e68d2018-08-27 14:51:15 +0100247 * Do this even after a timeout to avoid interrupt storms.
Richard Fitzgerald16b27462018-05-21 10:59:56 +0100248 */
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
257static 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 */
Charles Keepax003035b2020-01-14 15:10:48 +0000268 usleep_range(MADERA_RESET_MIN_US, MADERA_RESET_MAX_US);
Richard Fitzgerald16b27462018-05-21 10:59:56 +0100269
270 return 0;
271}
272
273static void madera_enable_hard_reset(struct madera *madera)
274{
Richard Fitzgerald16b27462018-05-21 10:59:56 +0100275 /*
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
283static void madera_disable_hard_reset(struct madera *madera)
284{
Richard Fitzgerald16b27462018-05-21 10:59:56 +0100285 gpiod_set_raw_value_cansleep(madera->pdata.reset, 1);
Charles Keepax003035b2020-01-14 15:10:48 +0000286
287 usleep_range(MADERA_RESET_MIN_US, MADERA_RESET_MAX_US);
Richard Fitzgerald16b27462018-05-21 10:59:56 +0100288}
289
290static 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
Charles Keepaxf594d012020-10-27 09:41:32 +0000297 if (!madera->reset_errata)
298 madera_enable_hard_reset(madera);
Charles Keepax1cd7b932020-10-27 09:41:31 +0000299
Richard Fitzgerald16b27462018-05-21 10:59:56 +0100300 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
Charles Keepaxf594d012020-10-27 09:41:32 +0000309 if (madera->reset_errata)
310 usleep_range(ERRATA_DCVDD_MIN_US, ERRATA_DCVDD_MAX_US);
311 else
312 madera_disable_hard_reset(madera);
Charles Keepax1cd7b932020-10-27 09:41:31 +0000313
Charles Keepaxf594d012020-10-27 09:41:32 +0000314 if (!madera->pdata.reset || madera->reset_errata) {
Charles Keepax1cd7b932020-10-27 09:41:31 +0000315 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 }
Charles Keepax003035b2020-01-14 15:10:48 +0000325
Richard Fitzgerald16b27462018-05-21 10:59:56 +0100326 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
344err:
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
352static 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
368const struct dev_pm_ops madera_pm_ops = {
369 SET_RUNTIME_PM_OPS(madera_runtime_suspend,
370 madera_runtime_resume,
371 NULL)
372};
373EXPORT_SYMBOL_GPL(madera_pm_ops);
374
375const struct of_device_id madera_of_match[] = {
Richard Fitzgerald1ef921b2019-05-30 15:39:52 +0100376 { .compatible = "cirrus,cs47l15", .data = (void *)CS47L15 },
Richard Fitzgerald16b27462018-05-21 10:59:56 +0100377 { .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 },
Richard Fitzgerald29793992019-05-30 15:39:53 +0100381 { .compatible = "cirrus,cs42l92", .data = (void *)CS42L92 },
382 { .compatible = "cirrus,cs47l92", .data = (void *)CS47L92 },
383 { .compatible = "cirrus,cs47l93", .data = (void *)CS47L93 },
Richard Fitzgerald16b27462018-05-21 10:59:56 +0100384 { .compatible = "cirrus,wm1840", .data = (void *)WM1840 },
385 {}
386};
Daniel Gomez5aa37092019-05-11 12:03:58 +0200387MODULE_DEVICE_TABLE(of, madera_of_match);
Richard Fitzgerald16b27462018-05-21 10:59:56 +0100388EXPORT_SYMBOL_GPL(madera_of_match);
389
390static int madera_get_reset_gpio(struct madera *madera)
391{
392 struct gpio_desc *reset;
Richard Fitzgerald16b27462018-05-21 10:59:56 +0100393
394 if (madera->pdata.reset)
395 return 0;
396
397 reset = devm_gpiod_get_optional(madera->dev, "reset", GPIOD_OUT_LOW);
Krzysztof Kozlowskif1045632020-08-26 16:49:33 +0200398 if (IS_ERR(reset))
399 return dev_err_probe(madera->dev, PTR_ERR(reset),
400 "Failed to request /RESET");
Richard Fitzgerald16b27462018-05-21 10:59:56 +0100401
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
416static 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) {
Richard Fitzgerald1ef921b2019-05-30 15:39:52 +0100423 case CS47L15:
424 madera->num_micbias = 1;
425 madera->num_childbias[0] = 3;
426 return;
Richard Fitzgerald16b27462018-05-21 10:59:56 +0100427 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;
Richard Fitzgerald29793992019-05-30 15:39:53 +0100443 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;
Richard Fitzgerald16b27462018-05-21 10:59:56 +0100450 default:
451 return;
452 }
453}
454
455int 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);
Richard Fitzgerald7f947212018-11-12 15:28:37 +0000466 mutex_init(&madera->dapm_ptr_lock);
467
Richard Fitzgerald16b27462018-05-21 10:59:56 +0100468 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
Charles Keepax1e624fc2019-10-21 14:58:13 +0100479 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
Richard Fitzgerald16b27462018-05-21 10:59:56 +0100494 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) {
Richard Fitzgerald1ef921b2019-05-30 15:39:52 +0100512 case CS47L15:
Charles Keepaxf594d012020-10-27 09:41:32 +0000513 madera->reset_errata = true;
514 break;
Richard Fitzgerald16b27462018-05-21 10:59:56 +0100515 case CS47L35:
516 case CS47L90:
517 case CS47L91:
Richard Fitzgerald29793992019-05-30 15:39:53 +0100518 case CS42L92:
519 case CS47L92:
520 case CS47L93:
Richard Fitzgerald16b27462018-05-21 10:59:56 +0100521 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
Charles Keepaxf594d012020-10-27 09:41:32 +0000565 if (madera->reset_errata)
566 madera_disable_hard_reset(madera);
567
Richard Fitzgerald16b27462018-05-21 10:59:56 +0100568 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
Charles Keepaxf594d012020-10-27 09:41:32 +0000574 if (madera->reset_errata)
575 usleep_range(ERRATA_DCVDD_MIN_US, ERRATA_DCVDD_MAX_US);
576 else
577 madera_disable_hard_reset(madera);
Richard Fitzgerald16b27462018-05-21 10:59:56 +0100578
579 regcache_cache_only(madera->regmap, false);
580 regcache_cache_only(madera->regmap_32bit, false);
581
Charles Keepax7f6d8692020-01-06 10:28:34 +0000582 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
Richard Fitzgerald16b27462018-05-21 10:59:56 +0100588 /*
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) {
Richard Fitzgerald1ef921b2019-05-30 15:39:52 +0100599 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;
Richard Fitzgerald16b27462018-05-21 10:59:56 +0100612 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;
Richard Fitzgerald29793992019-05-30 15:39:53 +0100653 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;
Richard Fitzgerald16b27462018-05-21 10:59:56 +0100668 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 */
Charles Keepaxf594d012020-10-27 09:41:32 +0000685 if (!madera->pdata.reset || madera->reset_errata) {
Richard Fitzgerald16b27462018-05-21 10:59:56 +0100686 ret = madera_soft_reset(madera);
687 if (ret)
688 goto err_reset;
689 }
690
691 ret = madera_wait_for_boot(madera);
692 if (ret) {
Charles Keepax7f6d8692020-01-06 10:28:34 +0000693 dev_err(madera->dev, "Failed to clear boot done: %d\n", ret);
Richard Fitzgerald16b27462018-05-21 10:59:56 +0100694 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 */
Charles Keepax1e624fc2019-10-21 14:58:13 +0100718 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
Richard Fitzgerald16b27462018-05-21 10:59:56 +0100724 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);
Charles Keepax1e624fc2019-10-21 14:58:13 +0100730 goto err_clock;
Richard Fitzgerald16b27462018-05-21 10:59:56 +0100731 }
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
749err_pm_runtime:
750 pm_runtime_disable(madera->dev);
Charles Keepax1e624fc2019-10-21 14:58:13 +0100751err_clock:
752 clk_disable_unprepare(madera->mclk[MADERA_MCLK2].clk);
Richard Fitzgerald16b27462018-05-21 10:59:56 +0100753err_reset:
754 madera_enable_hard_reset(madera);
755 regulator_disable(madera->dcvdd);
756err_enable:
757 regulator_bulk_disable(madera->num_core_supplies,
758 madera->core_supplies);
759err_dcvdd:
760 regulator_put(madera->dcvdd);
761err_devs:
762 mfd_remove_devices(dev);
763
764 return ret;
765}
766EXPORT_SYMBOL_GPL(madera_dev_init);
767
768int madera_dev_exit(struct madera *madera)
769{
770 /* Prevent any IRQs being serviced while we clean up */
771 disable_irq(madera->irq);
772
Charles Keepax77b3dda2020-07-23 11:54:59 +0100773 pm_runtime_get_sync(madera->dev);
Richard Fitzgerald16b27462018-05-21 10:59:56 +0100774
Charles Keepax77b3dda2020-07-23 11:54:59 +0100775 mfd_remove_devices(madera->dev);
776
777 pm_runtime_disable(madera->dev);
Charles Keepax1e624fc2019-10-21 14:58:13 +0100778
Richard Fitzgerald16b27462018-05-21 10:59:56 +0100779 regulator_disable(madera->dcvdd);
780 regulator_put(madera->dcvdd);
781
Charles Keepax77b3dda2020-07-23 11:54:59 +0100782 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
Richard Fitzgerald16b27462018-05-21 10:59:56 +0100789 madera_enable_hard_reset(madera);
790
791 regulator_bulk_disable(madera->num_core_supplies,
792 madera->core_supplies);
793 return 0;
794}
795EXPORT_SYMBOL_GPL(madera_dev_exit);
796
797MODULE_DESCRIPTION("Madera core MFD driver");
798MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
799MODULE_LICENSE("GPL v2");