1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Core MFD support for Cirrus Logic Madera codecs
4 *
5 * Copyright (C) 2015-2018 Cirrus Logic
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; version 2.
10 */
11
12 #include <linux/device.h>
13 #include <linux/delay.h>
14 #include <linux/err.h>
15 #include <linux/gpio.h>
16 #include <linux/mfd/core.h>
17 #include <linux/module.h>
18 #include <linux/notifier.h>
19 #include <linux/of.h>
20 #include <linux/of_gpio.h>
21 #include <linux/platform_device.h>
22 #include <linux/pm_runtime.h>
23 #include <linux/regmap.h>
24 #include <linux/regulator/consumer.h>
25 #include <linux/regulator/machine.h>
26 #include <linux/regulator/of_regulator.h>
27
28 #include <linux/mfd/madera/core.h>
29 #include <linux/mfd/madera/registers.h>
30
31 #include "madera.h"
32
33 #define CS47L35_SILICON_ID 0x6360
34 #define CS47L85_SILICON_ID 0x6338
35 #define CS47L90_SILICON_ID 0x6364
36
37 #define MADERA_32KZ_MCLK2 1
38
39 static const char * const madera_core_supplies[] = {
40 "AVDD",
41 "DBVDD1",
42 };
43
44 static const struct mfd_cell madera_ldo1_devs[] = {
45 { .name = "madera-ldo1" },
46 };
47
48 static const char * const cs47l35_supplies[] = {
49 "MICVDD",
50 "DBVDD2",
51 "CPVDD1",
52 "CPVDD2",
53 "SPKVDD",
54 };
55
56 static const struct mfd_cell cs47l35_devs[] = {
57 { .name = "madera-pinctrl", },
58 { .name = "madera-irq", },
59 { .name = "madera-micsupp", },
60 { .name = "madera-gpio", },
61 { .name = "madera-extcon", },
62 {
63 .name = "cs47l35-codec",
64 .parent_supplies = cs47l35_supplies,
65 .num_parent_supplies = ARRAY_SIZE(cs47l35_supplies),
66 },
67 };
68
69 static const char * const cs47l85_supplies[] = {
70 "MICVDD",
71 "DBVDD2",
72 "DBVDD3",
73 "DBVDD4",
74 "CPVDD1",
75 "CPVDD2",
76 "SPKVDDL",
77 "SPKVDDR",
78 };
79
80 static const struct mfd_cell cs47l85_devs[] = {
81 { .name = "madera-pinctrl", },
82 { .name = "madera-irq", },
83 { .name = "madera-micsupp" },
84 { .name = "madera-gpio", },
85 { .name = "madera-extcon", },
86 {
87 .name = "cs47l85-codec",
88 .parent_supplies = cs47l85_supplies,
89 .num_parent_supplies = ARRAY_SIZE(cs47l85_supplies),
90 },
91 };
92
93 static const char * const cs47l90_supplies[] = {
94 "MICVDD",
95 "DBVDD2",
96 "DBVDD3",
97 "DBVDD4",
98 "CPVDD1",
99 "CPVDD2",
100 };
101
102 static const struct mfd_cell cs47l90_devs[] = {
103 { .name = "madera-pinctrl", },
104 { .name = "madera-irq", },
105 { .name = "madera-micsupp", },
106 { .name = "madera-gpio", },
107 { .name = "madera-extcon", },
108 {
109 .name = "cs47l90-codec",
110 .parent_supplies = cs47l90_supplies,
111 .num_parent_supplies = ARRAY_SIZE(cs47l90_supplies),
112 },
113 };
114
115 /* Used by madera-i2c and madera-spi drivers */
madera_name_from_type(enum madera_type type)116 const char *madera_name_from_type(enum madera_type type)
117 {
118 switch (type) {
119 case CS47L35:
120 return "CS47L35";
121 case CS47L85:
122 return "CS47L85";
123 case CS47L90:
124 return "CS47L90";
125 case CS47L91:
126 return "CS47L91";
127 case WM1840:
128 return "WM1840";
129 default:
130 return "Unknown";
131 }
132 }
133 EXPORT_SYMBOL_GPL(madera_name_from_type);
134
135 #define MADERA_BOOT_POLL_MAX_INTERVAL_US 5000
136 #define MADERA_BOOT_POLL_TIMEOUT_US 25000
137
madera_wait_for_boot(struct madera * madera)138 static int madera_wait_for_boot(struct madera *madera)
139 {
140 unsigned int val;
141 int ret;
142
143 /*
144 * We can't use an interrupt as we need to runtime resume to do so,
145 * so we poll the status bit. This won't race with the interrupt
146 * handler because it will be blocked on runtime resume.
147 */
148 ret = regmap_read_poll_timeout(madera->regmap,
149 MADERA_IRQ1_RAW_STATUS_1,
150 val,
151 (val & MADERA_BOOT_DONE_STS1),
152 MADERA_BOOT_POLL_MAX_INTERVAL_US,
153 MADERA_BOOT_POLL_TIMEOUT_US);
154
155 if (ret)
156 dev_err(madera->dev, "Polling BOOT_DONE_STS failed: %d\n", ret);
157
158 /*
159 * BOOT_DONE defaults to unmasked on boot so we must ack it.
160 * Do this unconditionally to avoid interrupt storms.
161 */
162 regmap_write(madera->regmap, MADERA_IRQ1_STATUS_1,
163 MADERA_BOOT_DONE_EINT1);
164
165 pm_runtime_mark_last_busy(madera->dev);
166
167 return ret;
168 }
169
madera_soft_reset(struct madera * madera)170 static int madera_soft_reset(struct madera *madera)
171 {
172 int ret;
173
174 ret = regmap_write(madera->regmap, MADERA_SOFTWARE_RESET, 0);
175 if (ret != 0) {
176 dev_err(madera->dev, "Failed to soft reset device: %d\n", ret);
177 return ret;
178 }
179
180 /* Allow time for internal clocks to startup after reset */
181 usleep_range(1000, 2000);
182
183 return 0;
184 }
185
madera_enable_hard_reset(struct madera * madera)186 static void madera_enable_hard_reset(struct madera *madera)
187 {
188 if (!madera->pdata.reset)
189 return;
190
191 /*
192 * There are many existing out-of-tree users of these codecs that we
193 * can't break so preserve the expected behaviour of setting the line
194 * low to assert reset.
195 */
196 gpiod_set_raw_value_cansleep(madera->pdata.reset, 0);
197 }
198
madera_disable_hard_reset(struct madera * madera)199 static void madera_disable_hard_reset(struct madera *madera)
200 {
201 if (!madera->pdata.reset)
202 return;
203
204 gpiod_set_raw_value_cansleep(madera->pdata.reset, 1);
205 usleep_range(1000, 2000);
206 }
207
madera_runtime_resume(struct device * dev)208 static int __maybe_unused madera_runtime_resume(struct device *dev)
209 {
210 struct madera *madera = dev_get_drvdata(dev);
211 int ret;
212
213 dev_dbg(dev, "Leaving sleep mode\n");
214
215 ret = regulator_enable(madera->dcvdd);
216 if (ret) {
217 dev_err(dev, "Failed to enable DCVDD: %d\n", ret);
218 return ret;
219 }
220
221 regcache_cache_only(madera->regmap, false);
222 regcache_cache_only(madera->regmap_32bit, false);
223
224 ret = madera_wait_for_boot(madera);
225 if (ret)
226 goto err;
227
228 ret = regcache_sync(madera->regmap);
229 if (ret) {
230 dev_err(dev, "Failed to restore 16-bit register cache\n");
231 goto err;
232 }
233
234 ret = regcache_sync(madera->regmap_32bit);
235 if (ret) {
236 dev_err(dev, "Failed to restore 32-bit register cache\n");
237 goto err;
238 }
239
240 return 0;
241
242 err:
243 regcache_cache_only(madera->regmap_32bit, true);
244 regcache_cache_only(madera->regmap, true);
245 regulator_disable(madera->dcvdd);
246
247 return ret;
248 }
249
madera_runtime_suspend(struct device * dev)250 static int __maybe_unused madera_runtime_suspend(struct device *dev)
251 {
252 struct madera *madera = dev_get_drvdata(dev);
253
254 dev_dbg(madera->dev, "Entering sleep mode\n");
255
256 regcache_cache_only(madera->regmap, true);
257 regcache_mark_dirty(madera->regmap);
258 regcache_cache_only(madera->regmap_32bit, true);
259 regcache_mark_dirty(madera->regmap_32bit);
260
261 regulator_disable(madera->dcvdd);
262
263 return 0;
264 }
265
266 const struct dev_pm_ops madera_pm_ops = {
267 SET_RUNTIME_PM_OPS(madera_runtime_suspend,
268 madera_runtime_resume,
269 NULL)
270 };
271 EXPORT_SYMBOL_GPL(madera_pm_ops);
272
273 const struct of_device_id madera_of_match[] = {
274 { .compatible = "cirrus,cs47l35", .data = (void *)CS47L35 },
275 { .compatible = "cirrus,cs47l85", .data = (void *)CS47L85 },
276 { .compatible = "cirrus,cs47l90", .data = (void *)CS47L90 },
277 { .compatible = "cirrus,cs47l91", .data = (void *)CS47L91 },
278 { .compatible = "cirrus,wm1840", .data = (void *)WM1840 },
279 {}
280 };
281 EXPORT_SYMBOL_GPL(madera_of_match);
282
madera_get_reset_gpio(struct madera * madera)283 static int madera_get_reset_gpio(struct madera *madera)
284 {
285 struct gpio_desc *reset;
286 int ret;
287
288 if (madera->pdata.reset)
289 return 0;
290
291 reset = devm_gpiod_get_optional(madera->dev, "reset", GPIOD_OUT_LOW);
292 if (IS_ERR(reset)) {
293 ret = PTR_ERR(reset);
294 if (ret != -EPROBE_DEFER)
295 dev_err(madera->dev, "Failed to request /RESET: %d\n",
296 ret);
297 return ret;
298 }
299
300 /*
301 * A hard reset is needed for full reset of the chip. We allow running
302 * without hard reset only because it can be useful for early
303 * prototyping and some debugging, but we need to warn it's not ideal.
304 */
305 if (!reset)
306 dev_warn(madera->dev,
307 "Running without reset GPIO is not recommended\n");
308
309 madera->pdata.reset = reset;
310
311 return 0;
312 }
313
madera_set_micbias_info(struct madera * madera)314 static void madera_set_micbias_info(struct madera *madera)
315 {
316 /*
317 * num_childbias is an array because future codecs can have different
318 * childbiases for each micbias. Unspecified values default to 0.
319 */
320 switch (madera->type) {
321 case CS47L35:
322 madera->num_micbias = 2;
323 madera->num_childbias[0] = 2;
324 madera->num_childbias[1] = 2;
325 return;
326 case CS47L85:
327 case WM1840:
328 madera->num_micbias = 4;
329 /* no child biases */
330 return;
331 case CS47L90:
332 case CS47L91:
333 madera->num_micbias = 2;
334 madera->num_childbias[0] = 4;
335 madera->num_childbias[1] = 4;
336 return;
337 default:
338 return;
339 }
340 }
341
madera_dev_init(struct madera * madera)342 int madera_dev_init(struct madera *madera)
343 {
344 struct device *dev = madera->dev;
345 unsigned int hwid;
346 int (*patch_fn)(struct madera *) = NULL;
347 const struct mfd_cell *mfd_devs;
348 int n_devs = 0;
349 int i, ret;
350
351 dev_set_drvdata(madera->dev, madera);
352 BLOCKING_INIT_NOTIFIER_HEAD(&madera->notifier);
353 madera_set_micbias_info(madera);
354
355 /*
356 * We need writable hw config info that all children can share.
357 * Simplest to take one shared copy of pdata struct.
358 */
359 if (dev_get_platdata(madera->dev)) {
360 memcpy(&madera->pdata, dev_get_platdata(madera->dev),
361 sizeof(madera->pdata));
362 }
363
364 ret = madera_get_reset_gpio(madera);
365 if (ret)
366 return ret;
367
368 regcache_cache_only(madera->regmap, true);
369 regcache_cache_only(madera->regmap_32bit, true);
370
371 for (i = 0; i < ARRAY_SIZE(madera_core_supplies); i++)
372 madera->core_supplies[i].supply = madera_core_supplies[i];
373
374 madera->num_core_supplies = ARRAY_SIZE(madera_core_supplies);
375
376 /*
377 * On some codecs DCVDD could be supplied by the internal LDO1.
378 * For those we must add the LDO1 driver before requesting DCVDD
379 * No devm_ because we need to control shutdown order of children.
380 */
381 switch (madera->type) {
382 case CS47L35:
383 case CS47L90:
384 case CS47L91:
385 break;
386 case CS47L85:
387 case WM1840:
388 ret = mfd_add_devices(madera->dev, PLATFORM_DEVID_NONE,
389 madera_ldo1_devs,
390 ARRAY_SIZE(madera_ldo1_devs),
391 NULL, 0, NULL);
392 if (ret) {
393 dev_err(dev, "Failed to add LDO1 child: %d\n", ret);
394 return ret;
395 }
396 break;
397 default:
398 /* No point continuing if the type is unknown */
399 dev_err(madera->dev, "Unknown device type %d\n", madera->type);
400 return -ENODEV;
401 }
402
403 ret = devm_regulator_bulk_get(dev, madera->num_core_supplies,
404 madera->core_supplies);
405 if (ret) {
406 dev_err(dev, "Failed to request core supplies: %d\n", ret);
407 goto err_devs;
408 }
409
410 /*
411 * Don't use devres here. If the regulator is one of our children it
412 * will already have been removed before devres cleanup on this mfd
413 * driver tries to call put() on it. We need control of shutdown order.
414 */
415 madera->dcvdd = regulator_get(madera->dev, "DCVDD");
416 if (IS_ERR(madera->dcvdd)) {
417 ret = PTR_ERR(madera->dcvdd);
418 dev_err(dev, "Failed to request DCVDD: %d\n", ret);
419 goto err_devs;
420 }
421
422 ret = regulator_bulk_enable(madera->num_core_supplies,
423 madera->core_supplies);
424 if (ret) {
425 dev_err(dev, "Failed to enable core supplies: %d\n", ret);
426 goto err_dcvdd;
427 }
428
429 ret = regulator_enable(madera->dcvdd);
430 if (ret) {
431 dev_err(dev, "Failed to enable DCVDD: %d\n", ret);
432 goto err_enable;
433 }
434
435 madera_disable_hard_reset(madera);
436
437 regcache_cache_only(madera->regmap, false);
438 regcache_cache_only(madera->regmap_32bit, false);
439
440 /*
441 * Now we can power up and verify that this is a chip we know about
442 * before we start doing any writes to its registers.
443 */
444 ret = regmap_read(madera->regmap, MADERA_SOFTWARE_RESET, &hwid);
445 if (ret) {
446 dev_err(dev, "Failed to read ID register: %d\n", ret);
447 goto err_reset;
448 }
449
450 switch (hwid) {
451 case CS47L35_SILICON_ID:
452 if (IS_ENABLED(CONFIG_MFD_CS47L35)) {
453 switch (madera->type) {
454 case CS47L35:
455 patch_fn = cs47l35_patch;
456 mfd_devs = cs47l35_devs;
457 n_devs = ARRAY_SIZE(cs47l35_devs);
458 break;
459 default:
460 break;
461 }
462 }
463 break;
464 case CS47L85_SILICON_ID:
465 if (IS_ENABLED(CONFIG_MFD_CS47L85)) {
466 switch (madera->type) {
467 case CS47L85:
468 case WM1840:
469 patch_fn = cs47l85_patch;
470 mfd_devs = cs47l85_devs;
471 n_devs = ARRAY_SIZE(cs47l85_devs);
472 break;
473 default:
474 break;
475 }
476 }
477 break;
478 case CS47L90_SILICON_ID:
479 if (IS_ENABLED(CONFIG_MFD_CS47L90)) {
480 switch (madera->type) {
481 case CS47L90:
482 case CS47L91:
483 patch_fn = cs47l90_patch;
484 mfd_devs = cs47l90_devs;
485 n_devs = ARRAY_SIZE(cs47l90_devs);
486 break;
487 default:
488 break;
489 }
490 }
491 break;
492 default:
493 dev_err(madera->dev, "Unknown device ID: %x\n", hwid);
494 ret = -EINVAL;
495 goto err_reset;
496 }
497
498 if (!n_devs) {
499 dev_err(madera->dev, "Device ID 0x%x not a %s\n", hwid,
500 madera->type_name);
501 ret = -ENODEV;
502 goto err_reset;
503 }
504
505 /*
506 * It looks like a device we support. If we don't have a hard reset
507 * we can now attempt a soft reset.
508 */
509 if (!madera->pdata.reset) {
510 ret = madera_soft_reset(madera);
511 if (ret)
512 goto err_reset;
513 }
514
515 ret = madera_wait_for_boot(madera);
516 if (ret) {
517 dev_err(madera->dev, "Device failed initial boot: %d\n", ret);
518 goto err_reset;
519 }
520
521 ret = regmap_read(madera->regmap, MADERA_HARDWARE_REVISION,
522 &madera->rev);
523 if (ret) {
524 dev_err(dev, "Failed to read revision register: %d\n", ret);
525 goto err_reset;
526 }
527 madera->rev &= MADERA_HW_REVISION_MASK;
528
529 dev_info(dev, "%s silicon revision %d\n", madera->type_name,
530 madera->rev);
531
532 /* Apply hardware patch */
533 if (patch_fn) {
534 ret = patch_fn(madera);
535 if (ret) {
536 dev_err(madera->dev, "Failed to apply patch %d\n", ret);
537 goto err_reset;
538 }
539 }
540
541 /* Init 32k clock sourced from MCLK2 */
542 ret = regmap_update_bits(madera->regmap,
543 MADERA_CLOCK_32K_1,
544 MADERA_CLK_32K_ENA_MASK | MADERA_CLK_32K_SRC_MASK,
545 MADERA_CLK_32K_ENA | MADERA_32KZ_MCLK2);
546 if (ret) {
547 dev_err(madera->dev, "Failed to init 32k clock: %d\n", ret);
548 goto err_reset;
549 }
550
551 pm_runtime_set_active(madera->dev);
552 pm_runtime_enable(madera->dev);
553 pm_runtime_set_autosuspend_delay(madera->dev, 100);
554 pm_runtime_use_autosuspend(madera->dev);
555
556 /* No devm_ because we need to control shutdown order of children */
557 ret = mfd_add_devices(madera->dev, PLATFORM_DEVID_NONE,
558 mfd_devs, n_devs,
559 NULL, 0, NULL);
560 if (ret) {
561 dev_err(madera->dev, "Failed to add subdevices: %d\n", ret);
562 goto err_pm_runtime;
563 }
564
565 return 0;
566
567 err_pm_runtime:
568 pm_runtime_disable(madera->dev);
569 err_reset:
570 madera_enable_hard_reset(madera);
571 regulator_disable(madera->dcvdd);
572 err_enable:
573 regulator_bulk_disable(madera->num_core_supplies,
574 madera->core_supplies);
575 err_dcvdd:
576 regulator_put(madera->dcvdd);
577 err_devs:
578 mfd_remove_devices(dev);
579
580 return ret;
581 }
582 EXPORT_SYMBOL_GPL(madera_dev_init);
583
madera_dev_exit(struct madera * madera)584 int madera_dev_exit(struct madera *madera)
585 {
586 /* Prevent any IRQs being serviced while we clean up */
587 disable_irq(madera->irq);
588
589 /*
590 * DCVDD could be supplied by a child node, we must disable it before
591 * removing the children, and prevent PM runtime from turning it back on
592 */
593 pm_runtime_disable(madera->dev);
594
595 regulator_disable(madera->dcvdd);
596 regulator_put(madera->dcvdd);
597
598 mfd_remove_devices(madera->dev);
599 madera_enable_hard_reset(madera);
600
601 regulator_bulk_disable(madera->num_core_supplies,
602 madera->core_supplies);
603 return 0;
604 }
605 EXPORT_SYMBOL_GPL(madera_dev_exit);
606
607 MODULE_DESCRIPTION("Madera core MFD driver");
608 MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
609 MODULE_LICENSE("GPL v2");
610