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