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