xref: /openbmc/linux/drivers/mfd/arizona-core.c (revision dc0c386e)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
23cc72986SMark Brown /*
33cc72986SMark Brown  * Arizona core driver
43cc72986SMark Brown  *
53cc72986SMark Brown  * Copyright 2012 Wolfson Microelectronics plc
63cc72986SMark Brown  *
73cc72986SMark Brown  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
83cc72986SMark Brown  */
93cc72986SMark Brown 
10cdd8da8cSSylwester Nawrocki #include <linux/clk.h>
113cc72986SMark Brown #include <linux/delay.h>
1259db9691SMark Brown #include <linux/err.h>
13c1860466SCharles Keepax #include <linux/gpio/consumer.h>
143cc72986SMark Brown #include <linux/interrupt.h>
153cc72986SMark Brown #include <linux/mfd/core.h>
163cc72986SMark Brown #include <linux/module.h>
17d781009cSMark Brown #include <linux/of.h>
183cc72986SMark Brown #include <linux/pm_runtime.h>
193cc72986SMark Brown #include <linux/regmap.h>
203cc72986SMark Brown #include <linux/regulator/consumer.h>
215927467dSMark Brown #include <linux/regulator/machine.h>
223cc72986SMark Brown #include <linux/slab.h>
23f99fea94SCharles Keepax #include <linux/ktime.h>
24ae05ea36SRichard Fitzgerald #include <linux/platform_device.h>
253cc72986SMark Brown 
263cc72986SMark Brown #include <linux/mfd/arizona/core.h>
273cc72986SMark Brown #include <linux/mfd/arizona/registers.h>
283cc72986SMark Brown 
293cc72986SMark Brown #include "arizona.h"
303cc72986SMark Brown 
313762aedeSCharles Keepax static const char * const wm5102_core_supplies[] = {
323cc72986SMark Brown 	"AVDD",
333cc72986SMark Brown 	"DBVDD1",
343cc72986SMark Brown };
353cc72986SMark Brown 
arizona_clk32k_enable(struct arizona * arizona)363cc72986SMark Brown int arizona_clk32k_enable(struct arizona *arizona)
373cc72986SMark Brown {
383cc72986SMark Brown 	int ret = 0;
393cc72986SMark Brown 
403cc72986SMark Brown 	mutex_lock(&arizona->clk_lock);
413cc72986SMark Brown 
423cc72986SMark Brown 	arizona->clk32k_ref++;
433cc72986SMark Brown 
44247fa192SMark Brown 	if (arizona->clk32k_ref == 1) {
45247fa192SMark Brown 		switch (arizona->pdata.clk32k_src) {
46247fa192SMark Brown 		case ARIZONA_32KZ_MCLK1:
47*4414a7abSLiang He 			ret = pm_runtime_resume_and_get(arizona->dev);
48247fa192SMark Brown 			if (ret != 0)
49cdd8da8cSSylwester Nawrocki 				goto err_ref;
50cdd8da8cSSylwester Nawrocki 			ret = clk_prepare_enable(arizona->mclk[ARIZONA_MCLK1]);
516b269a41SSapthagiri Baratam 			if (ret != 0) {
526b269a41SSapthagiri Baratam 				pm_runtime_put_sync(arizona->dev);
536b269a41SSapthagiri Baratam 				goto err_ref;
546b269a41SSapthagiri Baratam 			}
55cdd8da8cSSylwester Nawrocki 			break;
56cdd8da8cSSylwester Nawrocki 		case ARIZONA_32KZ_MCLK2:
57cdd8da8cSSylwester Nawrocki 			ret = clk_prepare_enable(arizona->mclk[ARIZONA_MCLK2]);
58cdd8da8cSSylwester Nawrocki 			if (ret != 0)
59cdd8da8cSSylwester Nawrocki 				goto err_ref;
60247fa192SMark Brown 			break;
61247fa192SMark Brown 		}
62247fa192SMark Brown 
633cc72986SMark Brown 		ret = regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1,
643cc72986SMark Brown 					 ARIZONA_CLK_32K_ENA,
653cc72986SMark Brown 					 ARIZONA_CLK_32K_ENA);
66247fa192SMark Brown 	}
673cc72986SMark Brown 
68cdd8da8cSSylwester Nawrocki err_ref:
693cc72986SMark Brown 	if (ret != 0)
703cc72986SMark Brown 		arizona->clk32k_ref--;
713cc72986SMark Brown 
723cc72986SMark Brown 	mutex_unlock(&arizona->clk_lock);
733cc72986SMark Brown 
743cc72986SMark Brown 	return ret;
753cc72986SMark Brown }
763cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_clk32k_enable);
773cc72986SMark Brown 
arizona_clk32k_disable(struct arizona * arizona)783cc72986SMark Brown int arizona_clk32k_disable(struct arizona *arizona)
793cc72986SMark Brown {
803cc72986SMark Brown 	mutex_lock(&arizona->clk_lock);
813cc72986SMark Brown 
8214024cc9SCharles Keepax 	WARN_ON(arizona->clk32k_ref <= 0);
833cc72986SMark Brown 
843cc72986SMark Brown 	arizona->clk32k_ref--;
853cc72986SMark Brown 
86247fa192SMark Brown 	if (arizona->clk32k_ref == 0) {
873cc72986SMark Brown 		regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1,
883cc72986SMark Brown 				   ARIZONA_CLK_32K_ENA, 0);
893cc72986SMark Brown 
90247fa192SMark Brown 		switch (arizona->pdata.clk32k_src) {
91247fa192SMark Brown 		case ARIZONA_32KZ_MCLK1:
92247fa192SMark Brown 			pm_runtime_put_sync(arizona->dev);
93cdd8da8cSSylwester Nawrocki 			clk_disable_unprepare(arizona->mclk[ARIZONA_MCLK1]);
94cdd8da8cSSylwester Nawrocki 			break;
95cdd8da8cSSylwester Nawrocki 		case ARIZONA_32KZ_MCLK2:
96cdd8da8cSSylwester Nawrocki 			clk_disable_unprepare(arizona->mclk[ARIZONA_MCLK2]);
97247fa192SMark Brown 			break;
98247fa192SMark Brown 		}
99247fa192SMark Brown 	}
100247fa192SMark Brown 
1013cc72986SMark Brown 	mutex_unlock(&arizona->clk_lock);
1023cc72986SMark Brown 
103a260fba1SJavier Martinez Canillas 	return 0;
1043cc72986SMark Brown }
1053cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_clk32k_disable);
1063cc72986SMark Brown 
arizona_clkgen_err(int irq,void * data)1073cc72986SMark Brown static irqreturn_t arizona_clkgen_err(int irq, void *data)
1083cc72986SMark Brown {
1093cc72986SMark Brown 	struct arizona *arizona = data;
1103cc72986SMark Brown 
1113cc72986SMark Brown 	dev_err(arizona->dev, "CLKGEN error\n");
1123cc72986SMark Brown 
1133cc72986SMark Brown 	return IRQ_HANDLED;
1143cc72986SMark Brown }
1153cc72986SMark Brown 
arizona_underclocked(int irq,void * data)1163cc72986SMark Brown static irqreturn_t arizona_underclocked(int irq, void *data)
1173cc72986SMark Brown {
1183cc72986SMark Brown 	struct arizona *arizona = data;
1193cc72986SMark Brown 	unsigned int val;
1203cc72986SMark Brown 	int ret;
1213cc72986SMark Brown 
1223cc72986SMark Brown 	ret = regmap_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_8,
1233cc72986SMark Brown 			  &val);
1243cc72986SMark Brown 	if (ret != 0) {
1253cc72986SMark Brown 		dev_err(arizona->dev, "Failed to read underclock status: %d\n",
1263cc72986SMark Brown 			ret);
1273cc72986SMark Brown 		return IRQ_NONE;
1283cc72986SMark Brown 	}
1293cc72986SMark Brown 
1303cc72986SMark Brown 	if (val & ARIZONA_AIF3_UNDERCLOCKED_STS)
1313cc72986SMark Brown 		dev_err(arizona->dev, "AIF3 underclocked\n");
1323cc72986SMark Brown 	if (val & ARIZONA_AIF2_UNDERCLOCKED_STS)
1333ebef34dSCharles Keepax 		dev_err(arizona->dev, "AIF2 underclocked\n");
1343ebef34dSCharles Keepax 	if (val & ARIZONA_AIF1_UNDERCLOCKED_STS)
1353cc72986SMark Brown 		dev_err(arizona->dev, "AIF1 underclocked\n");
1366e440d27SCharles Keepax 	if (val & ARIZONA_ISRC3_UNDERCLOCKED_STS)
1376e440d27SCharles Keepax 		dev_err(arizona->dev, "ISRC3 underclocked\n");
1383cc72986SMark Brown 	if (val & ARIZONA_ISRC2_UNDERCLOCKED_STS)
1393cc72986SMark Brown 		dev_err(arizona->dev, "ISRC2 underclocked\n");
1403cc72986SMark Brown 	if (val & ARIZONA_ISRC1_UNDERCLOCKED_STS)
1413cc72986SMark Brown 		dev_err(arizona->dev, "ISRC1 underclocked\n");
1423cc72986SMark Brown 	if (val & ARIZONA_FX_UNDERCLOCKED_STS)
1433cc72986SMark Brown 		dev_err(arizona->dev, "FX underclocked\n");
1443cc72986SMark Brown 	if (val & ARIZONA_ASRC_UNDERCLOCKED_STS)
1453cc72986SMark Brown 		dev_err(arizona->dev, "ASRC underclocked\n");
1463cc72986SMark Brown 	if (val & ARIZONA_DAC_UNDERCLOCKED_STS)
1473cc72986SMark Brown 		dev_err(arizona->dev, "DAC underclocked\n");
1483cc72986SMark Brown 	if (val & ARIZONA_ADC_UNDERCLOCKED_STS)
1493cc72986SMark Brown 		dev_err(arizona->dev, "ADC underclocked\n");
1503cc72986SMark Brown 	if (val & ARIZONA_MIXER_UNDERCLOCKED_STS)
151648a9880SMark Brown 		dev_err(arizona->dev, "Mixer dropped sample\n");
1523cc72986SMark Brown 
1533cc72986SMark Brown 	return IRQ_HANDLED;
1543cc72986SMark Brown }
1553cc72986SMark Brown 
arizona_overclocked(int irq,void * data)1563cc72986SMark Brown static irqreturn_t arizona_overclocked(int irq, void *data)
1573cc72986SMark Brown {
1583cc72986SMark Brown 	struct arizona *arizona = data;
1596887b042SRichard Fitzgerald 	unsigned int val[3];
1603cc72986SMark Brown 	int ret;
1613cc72986SMark Brown 
1623cc72986SMark Brown 	ret = regmap_bulk_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_6,
1636887b042SRichard Fitzgerald 			       &val[0], 3);
1643cc72986SMark Brown 	if (ret != 0) {
1653cc72986SMark Brown 		dev_err(arizona->dev, "Failed to read overclock status: %d\n",
1663cc72986SMark Brown 			ret);
1673cc72986SMark Brown 		return IRQ_NONE;
1683cc72986SMark Brown 	}
1693cc72986SMark Brown 
1706887b042SRichard Fitzgerald 	switch (arizona->type) {
1716887b042SRichard Fitzgerald 	case WM8998:
1726887b042SRichard Fitzgerald 	case WM1814:
1736887b042SRichard Fitzgerald 		/* Some bits are shifted on WM8998,
1746887b042SRichard Fitzgerald 		 * rearrange to match the standard bit layout
1756887b042SRichard Fitzgerald 		 */
1766887b042SRichard Fitzgerald 		val[0] = ((val[0] & 0x60e0) >> 1) |
1776887b042SRichard Fitzgerald 			 ((val[0] & 0x1e00) >> 2) |
1786887b042SRichard Fitzgerald 			 (val[0] & 0x000f);
1796887b042SRichard Fitzgerald 		break;
1806887b042SRichard Fitzgerald 	default:
1816887b042SRichard Fitzgerald 		break;
1826887b042SRichard Fitzgerald 	}
1836887b042SRichard Fitzgerald 
1843cc72986SMark Brown 	if (val[0] & ARIZONA_PWM_OVERCLOCKED_STS)
1853cc72986SMark Brown 		dev_err(arizona->dev, "PWM overclocked\n");
1863cc72986SMark Brown 	if (val[0] & ARIZONA_FX_CORE_OVERCLOCKED_STS)
1873cc72986SMark Brown 		dev_err(arizona->dev, "FX core overclocked\n");
1883cc72986SMark Brown 	if (val[0] & ARIZONA_DAC_SYS_OVERCLOCKED_STS)
1893cc72986SMark Brown 		dev_err(arizona->dev, "DAC SYS overclocked\n");
1903cc72986SMark Brown 	if (val[0] & ARIZONA_DAC_WARP_OVERCLOCKED_STS)
1913cc72986SMark Brown 		dev_err(arizona->dev, "DAC WARP overclocked\n");
1923cc72986SMark Brown 	if (val[0] & ARIZONA_ADC_OVERCLOCKED_STS)
1933cc72986SMark Brown 		dev_err(arizona->dev, "ADC overclocked\n");
1943cc72986SMark Brown 	if (val[0] & ARIZONA_MIXER_OVERCLOCKED_STS)
1953cc72986SMark Brown 		dev_err(arizona->dev, "Mixer overclocked\n");
1963cc72986SMark Brown 	if (val[0] & ARIZONA_AIF3_SYNC_OVERCLOCKED_STS)
1973cc72986SMark Brown 		dev_err(arizona->dev, "AIF3 overclocked\n");
1983cc72986SMark Brown 	if (val[0] & ARIZONA_AIF2_SYNC_OVERCLOCKED_STS)
1993cc72986SMark Brown 		dev_err(arizona->dev, "AIF2 overclocked\n");
2003cc72986SMark Brown 	if (val[0] & ARIZONA_AIF1_SYNC_OVERCLOCKED_STS)
2013cc72986SMark Brown 		dev_err(arizona->dev, "AIF1 overclocked\n");
2023cc72986SMark Brown 	if (val[0] & ARIZONA_PAD_CTRL_OVERCLOCKED_STS)
2033cc72986SMark Brown 		dev_err(arizona->dev, "Pad control overclocked\n");
2043cc72986SMark Brown 
2053cc72986SMark Brown 	if (val[1] & ARIZONA_SLIMBUS_SUBSYS_OVERCLOCKED_STS)
2063cc72986SMark Brown 		dev_err(arizona->dev, "Slimbus subsystem overclocked\n");
2073cc72986SMark Brown 	if (val[1] & ARIZONA_SLIMBUS_ASYNC_OVERCLOCKED_STS)
2083cc72986SMark Brown 		dev_err(arizona->dev, "Slimbus async overclocked\n");
2093cc72986SMark Brown 	if (val[1] & ARIZONA_SLIMBUS_SYNC_OVERCLOCKED_STS)
2103cc72986SMark Brown 		dev_err(arizona->dev, "Slimbus sync overclocked\n");
2113cc72986SMark Brown 	if (val[1] & ARIZONA_ASRC_ASYNC_SYS_OVERCLOCKED_STS)
2123cc72986SMark Brown 		dev_err(arizona->dev, "ASRC async system overclocked\n");
2133cc72986SMark Brown 	if (val[1] & ARIZONA_ASRC_ASYNC_WARP_OVERCLOCKED_STS)
2143cc72986SMark Brown 		dev_err(arizona->dev, "ASRC async WARP overclocked\n");
2153cc72986SMark Brown 	if (val[1] & ARIZONA_ASRC_SYNC_SYS_OVERCLOCKED_STS)
2163cc72986SMark Brown 		dev_err(arizona->dev, "ASRC sync system overclocked\n");
2173cc72986SMark Brown 	if (val[1] & ARIZONA_ASRC_SYNC_WARP_OVERCLOCKED_STS)
2183cc72986SMark Brown 		dev_err(arizona->dev, "ASRC sync WARP overclocked\n");
2193cc72986SMark Brown 	if (val[1] & ARIZONA_ADSP2_1_OVERCLOCKED_STS)
2203cc72986SMark Brown 		dev_err(arizona->dev, "DSP1 overclocked\n");
2216e440d27SCharles Keepax 	if (val[1] & ARIZONA_ISRC3_OVERCLOCKED_STS)
2226e440d27SCharles Keepax 		dev_err(arizona->dev, "ISRC3 overclocked\n");
2233cc72986SMark Brown 	if (val[1] & ARIZONA_ISRC2_OVERCLOCKED_STS)
2243cc72986SMark Brown 		dev_err(arizona->dev, "ISRC2 overclocked\n");
2253cc72986SMark Brown 	if (val[1] & ARIZONA_ISRC1_OVERCLOCKED_STS)
2263cc72986SMark Brown 		dev_err(arizona->dev, "ISRC1 overclocked\n");
2273cc72986SMark Brown 
2286887b042SRichard Fitzgerald 	if (val[2] & ARIZONA_SPDIF_OVERCLOCKED_STS)
2296887b042SRichard Fitzgerald 		dev_err(arizona->dev, "SPDIF overclocked\n");
2306887b042SRichard Fitzgerald 
2313cc72986SMark Brown 	return IRQ_HANDLED;
2323cc72986SMark Brown }
2333cc72986SMark Brown 
234ef84f885SCharles Keepax #define ARIZONA_REG_POLL_DELAY_US 7500
235ef84f885SCharles Keepax 
arizona_poll_reg_delay(ktime_t timeout)236f99fea94SCharles Keepax static inline bool arizona_poll_reg_delay(ktime_t timeout)
237f99fea94SCharles Keepax {
238f99fea94SCharles Keepax 	if (ktime_compare(ktime_get(), timeout) > 0)
239f99fea94SCharles Keepax 		return false;
240f99fea94SCharles Keepax 
241f99fea94SCharles Keepax 	usleep_range(ARIZONA_REG_POLL_DELAY_US / 2, ARIZONA_REG_POLL_DELAY_US);
242f99fea94SCharles Keepax 
243f99fea94SCharles Keepax 	return true;
244f99fea94SCharles Keepax }
245f99fea94SCharles Keepax 
arizona_poll_reg(struct arizona * arizona,int timeout_ms,unsigned int reg,unsigned int mask,unsigned int target)2469d53dfdcSCharles Keepax static int arizona_poll_reg(struct arizona *arizona,
247ef84f885SCharles Keepax 			    int timeout_ms, unsigned int reg,
2489d53dfdcSCharles Keepax 			    unsigned int mask, unsigned int target)
2499d53dfdcSCharles Keepax {
250f99fea94SCharles Keepax 	ktime_t timeout = ktime_add_us(ktime_get(), timeout_ms * USEC_PER_MSEC);
2519d53dfdcSCharles Keepax 	unsigned int val = 0;
252ef84f885SCharles Keepax 	int ret;
2539d53dfdcSCharles Keepax 
254f99fea94SCharles Keepax 	do {
255f99fea94SCharles Keepax 		ret = regmap_read(arizona->regmap, reg, &val);
2569d53dfdcSCharles Keepax 
257f99fea94SCharles Keepax 		if ((val & mask) == target)
258f99fea94SCharles Keepax 			return 0;
259f99fea94SCharles Keepax 	} while (arizona_poll_reg_delay(timeout));
260f99fea94SCharles Keepax 
261f99fea94SCharles Keepax 	if (ret) {
262f99fea94SCharles Keepax 		dev_err(arizona->dev, "Failed polling reg 0x%x: %d\n",
263f99fea94SCharles Keepax 			reg, ret);
264ef84f885SCharles Keepax 		return ret;
2659d53dfdcSCharles Keepax 	}
2669d53dfdcSCharles Keepax 
267f99fea94SCharles Keepax 	dev_err(arizona->dev, "Polling reg 0x%x timed out: %x\n", reg, val);
268f99fea94SCharles Keepax 	return -ETIMEDOUT;
269f99fea94SCharles Keepax }
270f99fea94SCharles Keepax 
arizona_wait_for_boot(struct arizona * arizona)2713cc72986SMark Brown static int arizona_wait_for_boot(struct arizona *arizona)
2723cc72986SMark Brown {
2739d53dfdcSCharles Keepax 	int ret;
2743cc72986SMark Brown 
2753cc72986SMark Brown 	/*
2763cc72986SMark Brown 	 * We can't use an interrupt as we need to runtime resume to do so,
2773cc72986SMark Brown 	 * we won't race with the interrupt handler as it'll be blocked on
2783cc72986SMark Brown 	 * runtime resume.
2793cc72986SMark Brown 	 */
280ef84f885SCharles Keepax 	ret = arizona_poll_reg(arizona, 30, ARIZONA_INTERRUPT_RAW_STATUS_5,
2819d53dfdcSCharles Keepax 			       ARIZONA_BOOT_DONE_STS, ARIZONA_BOOT_DONE_STS);
2823cc72986SMark Brown 
2839d53dfdcSCharles Keepax 	if (!ret)
2843cc72986SMark Brown 		regmap_write(arizona->regmap, ARIZONA_INTERRUPT_STATUS_5,
2853cc72986SMark Brown 			     ARIZONA_BOOT_DONE_STS);
2863cc72986SMark Brown 
2873cc72986SMark Brown 	pm_runtime_mark_last_busy(arizona->dev);
2883cc72986SMark Brown 
2899d53dfdcSCharles Keepax 	return ret;
2903cc72986SMark Brown }
2913cc72986SMark Brown 
arizona_enable_reset(struct arizona * arizona)2922229875dSCharles Keepax static inline void arizona_enable_reset(struct arizona *arizona)
2932229875dSCharles Keepax {
2942229875dSCharles Keepax 	if (arizona->pdata.reset)
295c1860466SCharles Keepax 		gpiod_set_raw_value_cansleep(arizona->pdata.reset, 0);
2962229875dSCharles Keepax }
2972229875dSCharles Keepax 
arizona_disable_reset(struct arizona * arizona)2982229875dSCharles Keepax static void arizona_disable_reset(struct arizona *arizona)
2992229875dSCharles Keepax {
3002229875dSCharles Keepax 	if (arizona->pdata.reset) {
301121c075cSCharles Keepax 		switch (arizona->type) {
302121c075cSCharles Keepax 		case WM5110:
303121c075cSCharles Keepax 		case WM8280:
304121c075cSCharles Keepax 			/* Meet requirements for minimum reset duration */
305b79a980fSLee Jones 			usleep_range(5000, 10000);
306121c075cSCharles Keepax 			break;
307121c075cSCharles Keepax 		default:
308121c075cSCharles Keepax 			break;
309121c075cSCharles Keepax 		}
310121c075cSCharles Keepax 
311c1860466SCharles Keepax 		gpiod_set_raw_value_cansleep(arizona->pdata.reset, 1);
312b79a980fSLee Jones 		usleep_range(1000, 5000);
3132229875dSCharles Keepax 	}
3142229875dSCharles Keepax }
3152229875dSCharles Keepax 
3163850e3eeSCharles Keepax struct arizona_sysclk_state {
3173850e3eeSCharles Keepax 	unsigned int fll;
3183850e3eeSCharles Keepax 	unsigned int sysclk;
3193850e3eeSCharles Keepax };
3203850e3eeSCharles Keepax 
arizona_enable_freerun_sysclk(struct arizona * arizona,struct arizona_sysclk_state * state)3213850e3eeSCharles Keepax static int arizona_enable_freerun_sysclk(struct arizona *arizona,
3223850e3eeSCharles Keepax 					 struct arizona_sysclk_state *state)
323e80436bbSCharles Keepax {
324e80436bbSCharles Keepax 	int ret, err;
325e80436bbSCharles Keepax 
326e80436bbSCharles Keepax 	/* Cache existing FLL and SYSCLK settings */
3273850e3eeSCharles Keepax 	ret = regmap_read(arizona->regmap, ARIZONA_FLL1_CONTROL_1, &state->fll);
3280be068a0SCharles Keepax 	if (ret) {
329e80436bbSCharles Keepax 		dev_err(arizona->dev, "Failed to cache FLL settings: %d\n",
330e80436bbSCharles Keepax 			ret);
331e80436bbSCharles Keepax 		return ret;
332e80436bbSCharles Keepax 	}
3333850e3eeSCharles Keepax 	ret = regmap_read(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1,
3343850e3eeSCharles Keepax 			  &state->sysclk);
3350be068a0SCharles Keepax 	if (ret) {
336e80436bbSCharles Keepax 		dev_err(arizona->dev, "Failed to cache SYSCLK settings: %d\n",
337e80436bbSCharles Keepax 			ret);
338e80436bbSCharles Keepax 		return ret;
339e80436bbSCharles Keepax 	}
340e80436bbSCharles Keepax 
341e80436bbSCharles Keepax 	/* Start up SYSCLK using the FLL in free running mode */
342e80436bbSCharles Keepax 	ret = regmap_write(arizona->regmap, ARIZONA_FLL1_CONTROL_1,
343e80436bbSCharles Keepax 			ARIZONA_FLL1_ENA | ARIZONA_FLL1_FREERUN);
3440be068a0SCharles Keepax 	if (ret) {
345e80436bbSCharles Keepax 		dev_err(arizona->dev,
346e80436bbSCharles Keepax 			"Failed to start FLL in freerunning mode: %d\n",
347e80436bbSCharles Keepax 			ret);
348e80436bbSCharles Keepax 		return ret;
349e80436bbSCharles Keepax 	}
350ef84f885SCharles Keepax 	ret = arizona_poll_reg(arizona, 180, ARIZONA_INTERRUPT_RAW_STATUS_5,
351e80436bbSCharles Keepax 			       ARIZONA_FLL1_CLOCK_OK_STS,
352e80436bbSCharles Keepax 			       ARIZONA_FLL1_CLOCK_OK_STS);
353de4ea10aSCharles Keepax 	if (ret)
354e80436bbSCharles Keepax 		goto err_fll;
355e80436bbSCharles Keepax 
356e80436bbSCharles Keepax 	ret = regmap_write(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, 0x0144);
3570be068a0SCharles Keepax 	if (ret) {
358e80436bbSCharles Keepax 		dev_err(arizona->dev, "Failed to start SYSCLK: %d\n", ret);
359e80436bbSCharles Keepax 		goto err_fll;
360e80436bbSCharles Keepax 	}
361e80436bbSCharles Keepax 
3623850e3eeSCharles Keepax 	return 0;
3633850e3eeSCharles Keepax 
3643850e3eeSCharles Keepax err_fll:
3653850e3eeSCharles Keepax 	err = regmap_write(arizona->regmap, ARIZONA_FLL1_CONTROL_1, state->fll);
3663850e3eeSCharles Keepax 	if (err)
3673850e3eeSCharles Keepax 		dev_err(arizona->dev,
3683850e3eeSCharles Keepax 			"Failed to re-apply old FLL settings: %d\n", err);
3693850e3eeSCharles Keepax 
3703850e3eeSCharles Keepax 	return ret;
3713850e3eeSCharles Keepax }
3723850e3eeSCharles Keepax 
arizona_disable_freerun_sysclk(struct arizona * arizona,struct arizona_sysclk_state * state)3733850e3eeSCharles Keepax static int arizona_disable_freerun_sysclk(struct arizona *arizona,
3743850e3eeSCharles Keepax 					  struct arizona_sysclk_state *state)
3753850e3eeSCharles Keepax {
3763850e3eeSCharles Keepax 	int ret;
3773850e3eeSCharles Keepax 
3783850e3eeSCharles Keepax 	ret = regmap_write(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1,
3793850e3eeSCharles Keepax 			   state->sysclk);
3803850e3eeSCharles Keepax 	if (ret) {
3813850e3eeSCharles Keepax 		dev_err(arizona->dev,
3823850e3eeSCharles Keepax 			"Failed to re-apply old SYSCLK settings: %d\n", ret);
3833850e3eeSCharles Keepax 		return ret;
3843850e3eeSCharles Keepax 	}
3853850e3eeSCharles Keepax 
3863850e3eeSCharles Keepax 	ret = regmap_write(arizona->regmap, ARIZONA_FLL1_CONTROL_1, state->fll);
3873850e3eeSCharles Keepax 	if (ret) {
3883850e3eeSCharles Keepax 		dev_err(arizona->dev,
3893850e3eeSCharles Keepax 			"Failed to re-apply old FLL settings: %d\n", ret);
3903850e3eeSCharles Keepax 		return ret;
3913850e3eeSCharles Keepax 	}
3923850e3eeSCharles Keepax 
3933850e3eeSCharles Keepax 	return 0;
3943850e3eeSCharles Keepax }
3953850e3eeSCharles Keepax 
wm5102_apply_hardware_patch(struct arizona * arizona)3963850e3eeSCharles Keepax static int wm5102_apply_hardware_patch(struct arizona *arizona)
3973850e3eeSCharles Keepax {
3983850e3eeSCharles Keepax 	struct arizona_sysclk_state state;
3993850e3eeSCharles Keepax 	int err, ret;
4003850e3eeSCharles Keepax 
4013850e3eeSCharles Keepax 	ret = arizona_enable_freerun_sysclk(arizona, &state);
4023850e3eeSCharles Keepax 	if (ret)
4033850e3eeSCharles Keepax 		return ret;
4043850e3eeSCharles Keepax 
405e80436bbSCharles Keepax 	/* Start the write sequencer and wait for it to finish */
406e80436bbSCharles Keepax 	ret = regmap_write(arizona->regmap, ARIZONA_WRITE_SEQUENCER_CTRL_0,
407e80436bbSCharles Keepax 			   ARIZONA_WSEQ_ENA | ARIZONA_WSEQ_START | 160);
4080be068a0SCharles Keepax 	if (ret) {
409e80436bbSCharles Keepax 		dev_err(arizona->dev, "Failed to start write sequencer: %d\n",
410e80436bbSCharles Keepax 			ret);
4113850e3eeSCharles Keepax 		goto err;
412e80436bbSCharles Keepax 	}
4133850e3eeSCharles Keepax 
414ef84f885SCharles Keepax 	ret = arizona_poll_reg(arizona, 30, ARIZONA_WRITE_SEQUENCER_CTRL_1,
415e80436bbSCharles Keepax 			       ARIZONA_WSEQ_BUSY, 0);
416de4ea10aSCharles Keepax 	if (ret)
417e80436bbSCharles Keepax 		regmap_write(arizona->regmap, ARIZONA_WRITE_SEQUENCER_CTRL_0,
418e80436bbSCharles Keepax 			     ARIZONA_WSEQ_ABORT);
419e80436bbSCharles Keepax 
4203850e3eeSCharles Keepax err:
4213850e3eeSCharles Keepax 	err = arizona_disable_freerun_sysclk(arizona, &state);
422e80436bbSCharles Keepax 
4230be068a0SCharles Keepax 	return ret ?: err;
424e80436bbSCharles Keepax }
425e80436bbSCharles Keepax 
426882bc468SCharles Keepax /*
427882bc468SCharles Keepax  * Register patch to some of the CODECs internal write sequences
428882bc468SCharles Keepax  * to ensure a clean exit from the low power sleep state.
429882bc468SCharles Keepax  */
4308019ff6cSNariman Poushin static const struct reg_sequence wm5110_sleep_patch[] = {
431882bc468SCharles Keepax 	{ 0x337A, 0xC100 },
432882bc468SCharles Keepax 	{ 0x337B, 0x0041 },
433882bc468SCharles Keepax 	{ 0x3300, 0xA210 },
434882bc468SCharles Keepax 	{ 0x3301, 0x050C },
435882bc468SCharles Keepax };
436882bc468SCharles Keepax 
wm5110_apply_sleep_patch(struct arizona * arizona)437882bc468SCharles Keepax static int wm5110_apply_sleep_patch(struct arizona *arizona)
438882bc468SCharles Keepax {
439882bc468SCharles Keepax 	struct arizona_sysclk_state state;
440882bc468SCharles Keepax 	int err, ret;
441882bc468SCharles Keepax 
442882bc468SCharles Keepax 	ret = arizona_enable_freerun_sysclk(arizona, &state);
443882bc468SCharles Keepax 	if (ret)
444882bc468SCharles Keepax 		return ret;
445882bc468SCharles Keepax 
446882bc468SCharles Keepax 	ret = regmap_multi_reg_write_bypassed(arizona->regmap,
447882bc468SCharles Keepax 					      wm5110_sleep_patch,
448882bc468SCharles Keepax 					      ARRAY_SIZE(wm5110_sleep_patch));
449882bc468SCharles Keepax 
450882bc468SCharles Keepax 	err = arizona_disable_freerun_sysclk(arizona, &state);
451882bc468SCharles Keepax 
452882bc468SCharles Keepax 	return ret ?: err;
453882bc468SCharles Keepax }
454882bc468SCharles Keepax 
wm5102_clear_write_sequencer(struct arizona * arizona)4551c1c6bbaSCharles Keepax static int wm5102_clear_write_sequencer(struct arizona *arizona)
4561c1c6bbaSCharles Keepax {
4571c1c6bbaSCharles Keepax 	int ret;
4581c1c6bbaSCharles Keepax 
4591c1c6bbaSCharles Keepax 	ret = regmap_write(arizona->regmap, ARIZONA_WRITE_SEQUENCER_CTRL_3,
4601c1c6bbaSCharles Keepax 			   0x0);
4611c1c6bbaSCharles Keepax 	if (ret) {
4621c1c6bbaSCharles Keepax 		dev_err(arizona->dev,
4631c1c6bbaSCharles Keepax 			"Failed to clear write sequencer state: %d\n", ret);
4641c1c6bbaSCharles Keepax 		return ret;
4651c1c6bbaSCharles Keepax 	}
4661c1c6bbaSCharles Keepax 
4671c1c6bbaSCharles Keepax 	arizona_enable_reset(arizona);
4681c1c6bbaSCharles Keepax 	regulator_disable(arizona->dcvdd);
4691c1c6bbaSCharles Keepax 
4701c1c6bbaSCharles Keepax 	msleep(20);
4711c1c6bbaSCharles Keepax 
4721c1c6bbaSCharles Keepax 	ret = regulator_enable(arizona->dcvdd);
4731c1c6bbaSCharles Keepax 	if (ret) {
4741c1c6bbaSCharles Keepax 		dev_err(arizona->dev, "Failed to re-enable DCVDD: %d\n", ret);
4751c1c6bbaSCharles Keepax 		return ret;
4761c1c6bbaSCharles Keepax 	}
4771c1c6bbaSCharles Keepax 	arizona_disable_reset(arizona);
4781c1c6bbaSCharles Keepax 
4791c1c6bbaSCharles Keepax 	return 0;
4801c1c6bbaSCharles Keepax }
4811c1c6bbaSCharles Keepax 
arizona_isolate_dcvdd(struct arizona * arizona)482e7811147SRichard Fitzgerald static int arizona_isolate_dcvdd(struct arizona *arizona)
483e7811147SRichard Fitzgerald {
484e7811147SRichard Fitzgerald 	int ret;
485e7811147SRichard Fitzgerald 
486e7811147SRichard Fitzgerald 	ret = regmap_update_bits(arizona->regmap,
487e7811147SRichard Fitzgerald 				 ARIZONA_ISOLATION_CONTROL,
488e7811147SRichard Fitzgerald 				 ARIZONA_ISOLATE_DCVDD1,
489e7811147SRichard Fitzgerald 				 ARIZONA_ISOLATE_DCVDD1);
490e7811147SRichard Fitzgerald 	if (ret != 0)
491e7811147SRichard Fitzgerald 		dev_err(arizona->dev, "Failed to isolate DCVDD: %d\n", ret);
492e7811147SRichard Fitzgerald 
493e7811147SRichard Fitzgerald 	return ret;
494e7811147SRichard Fitzgerald }
495e7811147SRichard Fitzgerald 
arizona_connect_dcvdd(struct arizona * arizona)496e7811147SRichard Fitzgerald static int arizona_connect_dcvdd(struct arizona *arizona)
497e7811147SRichard Fitzgerald {
498e7811147SRichard Fitzgerald 	int ret;
499e7811147SRichard Fitzgerald 
500e7811147SRichard Fitzgerald 	ret = regmap_update_bits(arizona->regmap,
501e7811147SRichard Fitzgerald 				 ARIZONA_ISOLATION_CONTROL,
502e7811147SRichard Fitzgerald 				 ARIZONA_ISOLATE_DCVDD1, 0);
503e7811147SRichard Fitzgerald 	if (ret != 0)
504e7811147SRichard Fitzgerald 		dev_err(arizona->dev, "Failed to connect DCVDD: %d\n", ret);
505e7811147SRichard Fitzgerald 
506e7811147SRichard Fitzgerald 	return ret;
507e7811147SRichard Fitzgerald }
508e7811147SRichard Fitzgerald 
arizona_is_jack_det_active(struct arizona * arizona)509e3424273SRichard Fitzgerald static int arizona_is_jack_det_active(struct arizona *arizona)
510e3424273SRichard Fitzgerald {
511e3424273SRichard Fitzgerald 	unsigned int val;
512e3424273SRichard Fitzgerald 	int ret;
513e3424273SRichard Fitzgerald 
514e3424273SRichard Fitzgerald 	ret = regmap_read(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE, &val);
515e3424273SRichard Fitzgerald 	if (ret) {
516e3424273SRichard Fitzgerald 		dev_err(arizona->dev,
517e3424273SRichard Fitzgerald 			"Failed to check jack det status: %d\n", ret);
518e3424273SRichard Fitzgerald 		return ret;
519e3424273SRichard Fitzgerald 	} else if (val & ARIZONA_JD1_ENA) {
520e3424273SRichard Fitzgerald 		return 1;
521e3424273SRichard Fitzgerald 	} else {
522e3424273SRichard Fitzgerald 		return 0;
523e3424273SRichard Fitzgerald 	}
524e3424273SRichard Fitzgerald }
525e3424273SRichard Fitzgerald 
arizona_runtime_resume(struct device * dev)5263cc72986SMark Brown static int arizona_runtime_resume(struct device *dev)
5273cc72986SMark Brown {
5283cc72986SMark Brown 	struct arizona *arizona = dev_get_drvdata(dev);
5293cc72986SMark Brown 	int ret;
5303cc72986SMark Brown 
531508c8299SMark Brown 	dev_dbg(arizona->dev, "Leaving AoD mode\n");
532508c8299SMark Brown 
533e6cb7341SCharles Keepax 	if (arizona->has_fully_powered_off) {
534e6cb7341SCharles Keepax 		dev_dbg(arizona->dev, "Re-enabling core supplies\n");
535e6cb7341SCharles Keepax 
536e6cb7341SCharles Keepax 		ret = regulator_bulk_enable(arizona->num_core_supplies,
537e6cb7341SCharles Keepax 					    arizona->core_supplies);
538e6cb7341SCharles Keepax 		if (ret) {
539e6cb7341SCharles Keepax 			dev_err(dev, "Failed to enable core supplies: %d\n",
540e6cb7341SCharles Keepax 				ret);
541e6cb7341SCharles Keepax 			return ret;
542e6cb7341SCharles Keepax 		}
543e6cb7341SCharles Keepax 	}
544e6cb7341SCharles Keepax 
54559db9691SMark Brown 	ret = regulator_enable(arizona->dcvdd);
54659db9691SMark Brown 	if (ret != 0) {
54759db9691SMark Brown 		dev_err(arizona->dev, "Failed to enable DCVDD: %d\n", ret);
548e6cb7341SCharles Keepax 		if (arizona->has_fully_powered_off)
549e6cb7341SCharles Keepax 			regulator_bulk_disable(arizona->num_core_supplies,
550e6cb7341SCharles Keepax 					       arizona->core_supplies);
55159db9691SMark Brown 		return ret;
55259db9691SMark Brown 	}
5533cc72986SMark Brown 
554e6cb7341SCharles Keepax 	if (arizona->has_fully_powered_off) {
555e6cb7341SCharles Keepax 		arizona_disable_reset(arizona);
556e6cb7341SCharles Keepax 		enable_irq(arizona->irq);
557e6cb7341SCharles Keepax 		arizona->has_fully_powered_off = false;
558e6cb7341SCharles Keepax 	}
559e6cb7341SCharles Keepax 
5603cc72986SMark Brown 	regcache_cache_only(arizona->regmap, false);
5613cc72986SMark Brown 
5624c9bb8bcSCharles Keepax 	switch (arizona->type) {
5634c9bb8bcSCharles Keepax 	case WM5102:
5645927467dSMark Brown 		if (arizona->external_dcvdd) {
565e7811147SRichard Fitzgerald 			ret = arizona_connect_dcvdd(arizona);
566e7811147SRichard Fitzgerald 			if (ret != 0)
5675927467dSMark Brown 				goto err;
5685927467dSMark Brown 		}
5695927467dSMark Brown 
5704c9bb8bcSCharles Keepax 		ret = wm5102_patch(arizona);
5714c9bb8bcSCharles Keepax 		if (ret != 0) {
5724c9bb8bcSCharles Keepax 			dev_err(arizona->dev, "Failed to apply patch: %d\n",
5734c9bb8bcSCharles Keepax 				ret);
5744c9bb8bcSCharles Keepax 			goto err;
5754c9bb8bcSCharles Keepax 		}
576e80436bbSCharles Keepax 
5770be068a0SCharles Keepax 		ret = wm5102_apply_hardware_patch(arizona);
5780be068a0SCharles Keepax 		if (ret) {
579e80436bbSCharles Keepax 			dev_err(arizona->dev,
580e80436bbSCharles Keepax 				"Failed to apply hardware patch: %d\n",
581e80436bbSCharles Keepax 				ret);
582e80436bbSCharles Keepax 			goto err;
583e80436bbSCharles Keepax 		}
584e80436bbSCharles Keepax 		break;
58596129a0eSCharles Keepax 	case WM5110:
58696129a0eSCharles Keepax 	case WM8280:
58796129a0eSCharles Keepax 		ret = arizona_wait_for_boot(arizona);
58896129a0eSCharles Keepax 		if (ret)
58996129a0eSCharles Keepax 			goto err;
59096129a0eSCharles Keepax 
59196129a0eSCharles Keepax 		if (arizona->external_dcvdd) {
592e7811147SRichard Fitzgerald 			ret = arizona_connect_dcvdd(arizona);
593e7811147SRichard Fitzgerald 			if (ret != 0)
59496129a0eSCharles Keepax 				goto err;
59596129a0eSCharles Keepax 		} else {
59696129a0eSCharles Keepax 			/*
59796129a0eSCharles Keepax 			 * As this is only called for the internal regulator
59896129a0eSCharles Keepax 			 * (where we know voltage ranges available) it is ok
59996129a0eSCharles Keepax 			 * to request an exact range.
60096129a0eSCharles Keepax 			 */
60196129a0eSCharles Keepax 			ret = regulator_set_voltage(arizona->dcvdd,
60296129a0eSCharles Keepax 						    1200000, 1200000);
60396129a0eSCharles Keepax 			if (ret < 0) {
60496129a0eSCharles Keepax 				dev_err(arizona->dev,
60596129a0eSCharles Keepax 					"Failed to set resume voltage: %d\n",
60696129a0eSCharles Keepax 					ret);
60796129a0eSCharles Keepax 				goto err;
60896129a0eSCharles Keepax 			}
60996129a0eSCharles Keepax 		}
610e6cb7341SCharles Keepax 
611e6cb7341SCharles Keepax 		ret = wm5110_apply_sleep_patch(arizona);
612e6cb7341SCharles Keepax 		if (ret) {
613e6cb7341SCharles Keepax 			dev_err(arizona->dev,
614e6cb7341SCharles Keepax 				"Failed to re-apply sleep patch: %d\n",
615e6cb7341SCharles Keepax 				ret);
616e6cb7341SCharles Keepax 			goto err;
617e6cb7341SCharles Keepax 		}
61896129a0eSCharles Keepax 		break;
619ea1f3339SRichard Fitzgerald 	case WM1831:
620ea1f3339SRichard Fitzgerald 	case CS47L24:
621ea1f3339SRichard Fitzgerald 		ret = arizona_wait_for_boot(arizona);
622ea1f3339SRichard Fitzgerald 		if (ret != 0)
623ea1f3339SRichard Fitzgerald 			goto err;
624ea1f3339SRichard Fitzgerald 		break;
625e80436bbSCharles Keepax 	default:
62612bb68edSCharles Keepax 		ret = arizona_wait_for_boot(arizona);
6273762aedeSCharles Keepax 		if (ret != 0)
62812bb68edSCharles Keepax 			goto err;
62912bb68edSCharles Keepax 
6305927467dSMark Brown 		if (arizona->external_dcvdd) {
631e7811147SRichard Fitzgerald 			ret = arizona_connect_dcvdd(arizona);
632e7811147SRichard Fitzgerald 			if (ret != 0)
6335927467dSMark Brown 				goto err;
6345927467dSMark Brown 		}
635e80436bbSCharles Keepax 		break;
6364c9bb8bcSCharles Keepax 	}
6374c9bb8bcSCharles Keepax 
6389270bdf5SMark Brown 	ret = regcache_sync(arizona->regmap);
6399270bdf5SMark Brown 	if (ret != 0) {
6409270bdf5SMark Brown 		dev_err(arizona->dev, "Failed to restore register cache\n");
6414816bd1cSMark Brown 		goto err;
6429270bdf5SMark Brown 	}
6433cc72986SMark Brown 
6443cc72986SMark Brown 	return 0;
6454816bd1cSMark Brown 
6464816bd1cSMark Brown err:
6474816bd1cSMark Brown 	regcache_cache_only(arizona->regmap, true);
6484816bd1cSMark Brown 	regulator_disable(arizona->dcvdd);
6494816bd1cSMark Brown 	return ret;
6503cc72986SMark Brown }
6513cc72986SMark Brown 
arizona_runtime_suspend(struct device * dev)6523cc72986SMark Brown static int arizona_runtime_suspend(struct device *dev)
6533cc72986SMark Brown {
6543cc72986SMark Brown 	struct arizona *arizona = dev_get_drvdata(dev);
655a05950a4SDan Carpenter 	int jd_active = 0;
6565927467dSMark Brown 	int ret;
6573cc72986SMark Brown 
658508c8299SMark Brown 	dev_dbg(arizona->dev, "Entering AoD mode\n");
659508c8299SMark Brown 
66096129a0eSCharles Keepax 	switch (arizona->type) {
66196129a0eSCharles Keepax 	case WM5110:
66296129a0eSCharles Keepax 	case WM8280:
663e3424273SRichard Fitzgerald 		jd_active = arizona_is_jack_det_active(arizona);
664e3424273SRichard Fitzgerald 		if (jd_active < 0)
665e3424273SRichard Fitzgerald 			return jd_active;
666e3424273SRichard Fitzgerald 
667e7811147SRichard Fitzgerald 		if (arizona->external_dcvdd) {
668e7811147SRichard Fitzgerald 			ret = arizona_isolate_dcvdd(arizona);
669e7811147SRichard Fitzgerald 			if (ret != 0)
670e7811147SRichard Fitzgerald 				return ret;
671e7811147SRichard Fitzgerald 		} else {
67296129a0eSCharles Keepax 			/*
67396129a0eSCharles Keepax 			 * As this is only called for the internal regulator
67496129a0eSCharles Keepax 			 * (where we know voltage ranges available) it is ok
67596129a0eSCharles Keepax 			 * to request an exact range.
67696129a0eSCharles Keepax 			 */
677e7811147SRichard Fitzgerald 			ret = regulator_set_voltage(arizona->dcvdd,
678e7811147SRichard Fitzgerald 						    1175000, 1175000);
67996129a0eSCharles Keepax 			if (ret < 0) {
68096129a0eSCharles Keepax 				dev_err(arizona->dev,
681e7811147SRichard Fitzgerald 					"Failed to set suspend voltage: %d\n",
682e7811147SRichard Fitzgerald 					ret);
683e6cb7341SCharles Keepax 				return ret;
684e6cb7341SCharles Keepax 			}
685e7811147SRichard Fitzgerald 		}
686e6cb7341SCharles Keepax 		break;
687e6cb7341SCharles Keepax 	case WM5102:
688e3424273SRichard Fitzgerald 		jd_active = arizona_is_jack_det_active(arizona);
689e3424273SRichard Fitzgerald 		if (jd_active < 0)
690e3424273SRichard Fitzgerald 			return jd_active;
691e3424273SRichard Fitzgerald 
692e7811147SRichard Fitzgerald 		if (arizona->external_dcvdd) {
693e7811147SRichard Fitzgerald 			ret = arizona_isolate_dcvdd(arizona);
694e7811147SRichard Fitzgerald 			if (ret != 0)
695e7811147SRichard Fitzgerald 				return ret;
696e7811147SRichard Fitzgerald 		}
697e7811147SRichard Fitzgerald 
698e3424273SRichard Fitzgerald 		if (!jd_active) {
699e6cb7341SCharles Keepax 			ret = regmap_write(arizona->regmap,
700e6cb7341SCharles Keepax 					   ARIZONA_WRITE_SEQUENCER_CTRL_3, 0x0);
701e6cb7341SCharles Keepax 			if (ret) {
702e6cb7341SCharles Keepax 				dev_err(arizona->dev,
703e6cb7341SCharles Keepax 					"Failed to clear write sequencer: %d\n",
70496129a0eSCharles Keepax 					ret);
70596129a0eSCharles Keepax 				return ret;
70696129a0eSCharles Keepax 			}
707e6cb7341SCharles Keepax 		}
70896129a0eSCharles Keepax 		break;
709ea1f3339SRichard Fitzgerald 	case WM1831:
710ea1f3339SRichard Fitzgerald 	case CS47L24:
711ea1f3339SRichard Fitzgerald 		break;
71296129a0eSCharles Keepax 	default:
713e3424273SRichard Fitzgerald 		jd_active = arizona_is_jack_det_active(arizona);
714e3424273SRichard Fitzgerald 		if (jd_active < 0)
715e3424273SRichard Fitzgerald 			return jd_active;
716e3424273SRichard Fitzgerald 
717e7811147SRichard Fitzgerald 		if (arizona->external_dcvdd) {
718e7811147SRichard Fitzgerald 			ret = arizona_isolate_dcvdd(arizona);
719e7811147SRichard Fitzgerald 			if (ret != 0)
720e7811147SRichard Fitzgerald 				return ret;
721e7811147SRichard Fitzgerald 		}
72296129a0eSCharles Keepax 		break;
72396129a0eSCharles Keepax 	}
7245927467dSMark Brown 
7253cc72986SMark Brown 	regcache_cache_only(arizona->regmap, true);
7263cc72986SMark Brown 	regcache_mark_dirty(arizona->regmap);
727e293e847SCharles Keepax 	regulator_disable(arizona->dcvdd);
7283cc72986SMark Brown 
729e6cb7341SCharles Keepax 	/* Allow us to completely power down if no jack detection */
730e3424273SRichard Fitzgerald 	if (!jd_active) {
731e6cb7341SCharles Keepax 		dev_dbg(arizona->dev, "Fully powering off\n");
732e6cb7341SCharles Keepax 
733e6cb7341SCharles Keepax 		arizona->has_fully_powered_off = true;
734e6cb7341SCharles Keepax 
73511150929SCharles Keepax 		disable_irq_nosync(arizona->irq);
736e6cb7341SCharles Keepax 		arizona_enable_reset(arizona);
737e6cb7341SCharles Keepax 		regulator_bulk_disable(arizona->num_core_supplies,
738e6cb7341SCharles Keepax 				       arizona->core_supplies);
739e6cb7341SCharles Keepax 	}
740e6cb7341SCharles Keepax 
7413cc72986SMark Brown 	return 0;
7423cc72986SMark Brown }
7433cc72986SMark Brown 
arizona_suspend(struct device * dev)74467c99296SMark Brown static int arizona_suspend(struct device *dev)
74567c99296SMark Brown {
74667c99296SMark Brown 	struct arizona *arizona = dev_get_drvdata(dev);
74767c99296SMark Brown 
74867c99296SMark Brown 	dev_dbg(arizona->dev, "Suspend, disabling IRQ\n");
74967c99296SMark Brown 	disable_irq(arizona->irq);
75067c99296SMark Brown 
75167c99296SMark Brown 	return 0;
75267c99296SMark Brown }
75367c99296SMark Brown 
arizona_suspend_noirq(struct device * dev)7543612b27cSCharles Keepax static int arizona_suspend_noirq(struct device *dev)
75567c99296SMark Brown {
75667c99296SMark Brown 	struct arizona *arizona = dev_get_drvdata(dev);
75767c99296SMark Brown 
75867c99296SMark Brown 	dev_dbg(arizona->dev, "Late suspend, reenabling IRQ\n");
75967c99296SMark Brown 	enable_irq(arizona->irq);
76067c99296SMark Brown 
76167c99296SMark Brown 	return 0;
76267c99296SMark Brown }
76367c99296SMark Brown 
arizona_resume_noirq(struct device * dev)764dc781d0eSMark Brown static int arizona_resume_noirq(struct device *dev)
765dc781d0eSMark Brown {
766dc781d0eSMark Brown 	struct arizona *arizona = dev_get_drvdata(dev);
767dc781d0eSMark Brown 
768dc781d0eSMark Brown 	dev_dbg(arizona->dev, "Early resume, disabling IRQ\n");
769dc781d0eSMark Brown 	disable_irq(arizona->irq);
770dc781d0eSMark Brown 
771dc781d0eSMark Brown 	return 0;
772dc781d0eSMark Brown }
773dc781d0eSMark Brown 
arizona_resume(struct device * dev)774dc781d0eSMark Brown static int arizona_resume(struct device *dev)
775dc781d0eSMark Brown {
776dc781d0eSMark Brown 	struct arizona *arizona = dev_get_drvdata(dev);
777dc781d0eSMark Brown 
7783612b27cSCharles Keepax 	dev_dbg(arizona->dev, "Resume, reenabling IRQ\n");
779dc781d0eSMark Brown 	enable_irq(arizona->irq);
780dc781d0eSMark Brown 
781dc781d0eSMark Brown 	return 0;
782dc781d0eSMark Brown }
783dc781d0eSMark Brown 
78450d3ac7dSPaul Cercueil EXPORT_GPL_DEV_PM_OPS(arizona_pm_ops) = {
78550d3ac7dSPaul Cercueil 	RUNTIME_PM_OPS(arizona_runtime_suspend,
7863cc72986SMark Brown 		       arizona_runtime_resume,
7873cc72986SMark Brown 		       NULL)
78850d3ac7dSPaul Cercueil 	SYSTEM_SLEEP_PM_OPS(arizona_suspend, arizona_resume)
78950d3ac7dSPaul Cercueil 	NOIRQ_SYSTEM_SLEEP_PM_OPS(arizona_suspend_noirq,
7903612b27cSCharles Keepax 				  arizona_resume_noirq)
7913cc72986SMark Brown };
7923cc72986SMark Brown 
793d781009cSMark Brown #ifdef CONFIG_OF
arizona_of_get_core_pdata(struct arizona * arizona)794d781009cSMark Brown static int arizona_of_get_core_pdata(struct arizona *arizona)
795d781009cSMark Brown {
796e4fcb1d6SCharles Keepax 	struct arizona_pdata *pdata = &arizona->pdata;
797d781009cSMark Brown 	int ret, i;
798d781009cSMark Brown 
799c1860466SCharles Keepax 	/* Handle old non-standard DT binding */
8005da3f767SDmitry Torokhov 	pdata->reset = devm_gpiod_get(arizona->dev, "wlf,reset", GPIOD_OUT_LOW);
801c1860466SCharles Keepax 	if (IS_ERR(pdata->reset)) {
802c1860466SCharles Keepax 		ret = PTR_ERR(pdata->reset);
8031961531dSCharles Keepax 
804c1860466SCharles Keepax 		/*
805c1860466SCharles Keepax 		 * Reset missing will be caught when other binding is read
806c1860466SCharles Keepax 		 * but all other errors imply this binding is in use but has
807c1860466SCharles Keepax 		 * encountered a problem so should be handled.
808c1860466SCharles Keepax 		 */
809c1860466SCharles Keepax 		if (ret == -EPROBE_DEFER)
810c1860466SCharles Keepax 			return ret;
811c1860466SCharles Keepax 		else if (ret != -ENOENT && ret != -ENOSYS)
812c1860466SCharles Keepax 			dev_err(arizona->dev, "Reset GPIO malformed: %d\n",
813c1860466SCharles Keepax 				ret);
814c1860466SCharles Keepax 
815c1860466SCharles Keepax 		pdata->reset = NULL;
8161961531dSCharles Keepax 	}
817d781009cSMark Brown 
818d781009cSMark Brown 	ret = of_property_read_u32_array(arizona->dev->of_node,
819d781009cSMark Brown 					 "wlf,gpio-defaults",
8203762aedeSCharles Keepax 					 pdata->gpio_defaults,
8213762aedeSCharles Keepax 					 ARRAY_SIZE(pdata->gpio_defaults));
822d781009cSMark Brown 	if (ret >= 0) {
823d781009cSMark Brown 		/*
824d781009cSMark Brown 		 * All values are literal except out of range values
825d781009cSMark Brown 		 * which are chip default, translate into platform
826d781009cSMark Brown 		 * data which uses 0 as chip default and out of range
827d781009cSMark Brown 		 * as zero.
828d781009cSMark Brown 		 */
8293762aedeSCharles Keepax 		for (i = 0; i < ARRAY_SIZE(pdata->gpio_defaults); i++) {
8303762aedeSCharles Keepax 			if (pdata->gpio_defaults[i] > 0xffff)
8313762aedeSCharles Keepax 				pdata->gpio_defaults[i] = 0;
8323762aedeSCharles Keepax 			else if (pdata->gpio_defaults[i] == 0)
8333762aedeSCharles Keepax 				pdata->gpio_defaults[i] = 0x10000;
834d781009cSMark Brown 		}
835d781009cSMark Brown 	} else {
836d781009cSMark Brown 		dev_err(arizona->dev, "Failed to parse GPIO defaults: %d\n",
837d781009cSMark Brown 			ret);
838d781009cSMark Brown 	}
839d781009cSMark Brown 
840d781009cSMark Brown 	return 0;
841d781009cSMark Brown }
842d781009cSMark Brown #else
arizona_of_get_core_pdata(struct arizona * arizona)843d781009cSMark Brown static inline int arizona_of_get_core_pdata(struct arizona *arizona)
844d781009cSMark Brown {
845d781009cSMark Brown 	return 0;
846d781009cSMark Brown }
847d781009cSMark Brown #endif
848d781009cSMark Brown 
8495ac98553SGeert Uytterhoeven static const struct mfd_cell early_devs[] = {
8503cc72986SMark Brown 	{ .name = "arizona-ldo1" },
8513cc72986SMark Brown };
8523cc72986SMark Brown 
8533762aedeSCharles Keepax static const char * const wm5102_supplies[] = {
8545fc6c396SCharles Keepax 	"MICVDD",
85532dadef2SCharles Keepax 	"DBVDD2",
85632dadef2SCharles Keepax 	"DBVDD3",
85732dadef2SCharles Keepax 	"CPVDD",
85832dadef2SCharles Keepax 	"SPKVDDL",
85932dadef2SCharles Keepax 	"SPKVDDR",
86032dadef2SCharles Keepax };
86132dadef2SCharles Keepax 
8625ac98553SGeert Uytterhoeven static const struct mfd_cell wm5102_devs[] = {
863d7768111SMark Brown 	{ .name = "arizona-micsupp" },
864f83c218cSCharles Keepax 	{ .name = "arizona-gpio" },
865503b1cacSMark Brown 	{ .name = "arizona-haptics" },
8663cc72986SMark Brown 	{ .name = "arizona-pwm" },
86732dadef2SCharles Keepax 	{
86832dadef2SCharles Keepax 		.name = "wm5102-codec",
86932dadef2SCharles Keepax 		.parent_supplies = wm5102_supplies,
87032dadef2SCharles Keepax 		.num_parent_supplies = ARRAY_SIZE(wm5102_supplies),
87132dadef2SCharles Keepax 	},
8723cc72986SMark Brown };
8733cc72986SMark Brown 
8745ac98553SGeert Uytterhoeven static const struct mfd_cell wm5110_devs[] = {
875d7768111SMark Brown 	{ .name = "arizona-micsupp" },
876f83c218cSCharles Keepax 	{ .name = "arizona-gpio" },
877503b1cacSMark Brown 	{ .name = "arizona-haptics" },
878e102befeSMark Brown 	{ .name = "arizona-pwm" },
87932dadef2SCharles Keepax 	{
88032dadef2SCharles Keepax 		.name = "wm5110-codec",
88132dadef2SCharles Keepax 		.parent_supplies = wm5102_supplies,
88232dadef2SCharles Keepax 		.num_parent_supplies = ARRAY_SIZE(wm5102_supplies),
88332dadef2SCharles Keepax 	},
88432dadef2SCharles Keepax };
88532dadef2SCharles Keepax 
886ea1f3339SRichard Fitzgerald static const char * const cs47l24_supplies[] = {
887ea1f3339SRichard Fitzgerald 	"MICVDD",
888ea1f3339SRichard Fitzgerald 	"CPVDD",
889ea1f3339SRichard Fitzgerald 	"SPKVDD",
890ea1f3339SRichard Fitzgerald };
891ea1f3339SRichard Fitzgerald 
892ea1f3339SRichard Fitzgerald static const struct mfd_cell cs47l24_devs[] = {
893ea1f3339SRichard Fitzgerald 	{ .name = "arizona-gpio" },
894ea1f3339SRichard Fitzgerald 	{ .name = "arizona-haptics" },
895ea1f3339SRichard Fitzgerald 	{ .name = "arizona-pwm" },
896ea1f3339SRichard Fitzgerald 	{
897ea1f3339SRichard Fitzgerald 		.name = "cs47l24-codec",
898ea1f3339SRichard Fitzgerald 		.parent_supplies = cs47l24_supplies,
899ea1f3339SRichard Fitzgerald 		.num_parent_supplies = ARRAY_SIZE(cs47l24_supplies),
900ea1f3339SRichard Fitzgerald 	},
901ea1f3339SRichard Fitzgerald };
902ea1f3339SRichard Fitzgerald 
9033762aedeSCharles Keepax static const char * const wm8997_supplies[] = {
904996c2d4fSCharles Keepax 	"MICVDD",
90532dadef2SCharles Keepax 	"DBVDD2",
90632dadef2SCharles Keepax 	"CPVDD",
90732dadef2SCharles Keepax 	"SPKVDD",
908e102befeSMark Brown };
909e102befeSMark Brown 
9105ac98553SGeert Uytterhoeven static const struct mfd_cell wm8997_devs[] = {
911dc7d4863SCharles Keepax 	{ .name = "arizona-micsupp" },
912f83c218cSCharles Keepax 	{ .name = "arizona-gpio" },
913dc7d4863SCharles Keepax 	{ .name = "arizona-haptics" },
914dc7d4863SCharles Keepax 	{ .name = "arizona-pwm" },
91532dadef2SCharles Keepax 	{
91632dadef2SCharles Keepax 		.name = "wm8997-codec",
91732dadef2SCharles Keepax 		.parent_supplies = wm8997_supplies,
91832dadef2SCharles Keepax 		.num_parent_supplies = ARRAY_SIZE(wm8997_supplies),
91932dadef2SCharles Keepax 	},
920dc7d4863SCharles Keepax };
921dc7d4863SCharles Keepax 
9226887b042SRichard Fitzgerald static const struct mfd_cell wm8998_devs[] = {
923f83c218cSCharles Keepax 	{ .name = "arizona-micsupp" },
924f83c218cSCharles Keepax 	{ .name = "arizona-gpio" },
9256887b042SRichard Fitzgerald 	{ .name = "arizona-haptics" },
9266887b042SRichard Fitzgerald 	{ .name = "arizona-pwm" },
9276887b042SRichard Fitzgerald 	{
9286887b042SRichard Fitzgerald 		.name = "wm8998-codec",
9296887b042SRichard Fitzgerald 		.parent_supplies = wm5102_supplies,
9306887b042SRichard Fitzgerald 		.num_parent_supplies = ARRAY_SIZE(wm5102_supplies),
9316887b042SRichard Fitzgerald 	},
9326887b042SRichard Fitzgerald };
9336887b042SRichard Fitzgerald 
arizona_dev_init(struct arizona * arizona)934f791be49SBill Pemberton int arizona_dev_init(struct arizona *arizona)
9353cc72986SMark Brown {
9368e27a563SColin Ian King 	static const char * const mclk_name[] = { "mclk1", "mclk2" };
9373cc72986SMark Brown 	struct device *dev = arizona->dev;
938ea1f3339SRichard Fitzgerald 	const char *type_name = NULL;
9396000c99eSCharles Keepax 	unsigned int reg, val;
94062d62b59SMark Brown 	int (*apply_patch)(struct arizona *) = NULL;
941ae05ea36SRichard Fitzgerald 	const struct mfd_cell *subdevs = NULL;
9425da6cbcdSArnd Bergmann 	int n_subdevs = 0, ret, i;
9433cc72986SMark Brown 
9443cc72986SMark Brown 	dev_set_drvdata(arizona->dev, arizona);
9453cc72986SMark Brown 	mutex_init(&arizona->clk_lock);
9463cc72986SMark Brown 
947b8d336edSCharles Keepax 	if (dev_get_platdata(arizona->dev)) {
9483cc72986SMark Brown 		memcpy(&arizona->pdata, dev_get_platdata(arizona->dev),
9493cc72986SMark Brown 		       sizeof(arizona->pdata));
950b8d336edSCharles Keepax 	} else {
951b8d336edSCharles Keepax 		ret = arizona_of_get_core_pdata(arizona);
952b8d336edSCharles Keepax 		if (ret < 0)
953b8d336edSCharles Keepax 			return ret;
954b8d336edSCharles Keepax 	}
9553cc72986SMark Brown 
956cdd8da8cSSylwester Nawrocki 	BUILD_BUG_ON(ARRAY_SIZE(arizona->mclk) != ARRAY_SIZE(mclk_name));
957cdd8da8cSSylwester Nawrocki 	for (i = 0; i < ARRAY_SIZE(arizona->mclk); i++) {
958cdd8da8cSSylwester Nawrocki 		arizona->mclk[i] = devm_clk_get(arizona->dev, mclk_name[i]);
959cdd8da8cSSylwester Nawrocki 		if (IS_ERR(arizona->mclk[i])) {
960cdd8da8cSSylwester Nawrocki 			dev_info(arizona->dev, "Failed to get %s: %ld\n",
961cdd8da8cSSylwester Nawrocki 				 mclk_name[i], PTR_ERR(arizona->mclk[i]));
962cdd8da8cSSylwester Nawrocki 			arizona->mclk[i] = NULL;
963cdd8da8cSSylwester Nawrocki 		}
964cdd8da8cSSylwester Nawrocki 	}
965cdd8da8cSSylwester Nawrocki 
9663cc72986SMark Brown 	regcache_cache_only(arizona->regmap, true);
9673cc72986SMark Brown 
9683cc72986SMark Brown 	switch (arizona->type) {
9693cc72986SMark Brown 	case WM5102:
970e102befeSMark Brown 	case WM5110:
971e5d4ef0dSRichard Fitzgerald 	case WM8280:
972dc7d4863SCharles Keepax 	case WM8997:
9736887b042SRichard Fitzgerald 	case WM8998:
9746887b042SRichard Fitzgerald 	case WM1814:
975ea1f3339SRichard Fitzgerald 	case WM1831:
976ea1f3339SRichard Fitzgerald 	case CS47L24:
9773cc72986SMark Brown 		for (i = 0; i < ARRAY_SIZE(wm5102_core_supplies); i++)
9783cc72986SMark Brown 			arizona->core_supplies[i].supply
9793cc72986SMark Brown 				= wm5102_core_supplies[i];
9803cc72986SMark Brown 		arizona->num_core_supplies = ARRAY_SIZE(wm5102_core_supplies);
9813cc72986SMark Brown 		break;
9823cc72986SMark Brown 	default:
9833cc72986SMark Brown 		dev_err(arizona->dev, "Unknown device type %d\n",
9843cc72986SMark Brown 			arizona->type);
98575d8a2b0SCharles Keepax 		return -ENODEV;
9863cc72986SMark Brown 	}
9873cc72986SMark Brown 
9884a8c475fSCharles Keepax 	/* Mark DCVDD as external, LDO1 driver will clear if internal */
9894a8c475fSCharles Keepax 	arizona->external_dcvdd = true;
9904a8c475fSCharles Keepax 
991ea1f3339SRichard Fitzgerald 	switch (arizona->type) {
992ea1f3339SRichard Fitzgerald 	case WM1831:
993ea1f3339SRichard Fitzgerald 	case CS47L24:
994ea1f3339SRichard Fitzgerald 		break; /* No LDO1 regulator */
995ea1f3339SRichard Fitzgerald 	default:
9963cc72986SMark Brown 		ret = mfd_add_devices(arizona->dev, -1, early_devs,
9970848c94fSMark Brown 				      ARRAY_SIZE(early_devs), NULL, 0, NULL);
9983cc72986SMark Brown 		if (ret != 0) {
9993cc72986SMark Brown 			dev_err(dev, "Failed to add early children: %d\n", ret);
10003cc72986SMark Brown 			return ret;
10013cc72986SMark Brown 		}
1002ea1f3339SRichard Fitzgerald 		break;
1003ea1f3339SRichard Fitzgerald 	}
10043cc72986SMark Brown 
10053cc72986SMark Brown 	ret = devm_regulator_bulk_get(dev, arizona->num_core_supplies,
10063cc72986SMark Brown 				      arizona->core_supplies);
10073cc72986SMark Brown 	if (ret != 0) {
10083cc72986SMark Brown 		dev_err(dev, "Failed to request core supplies: %d\n",
10093cc72986SMark Brown 			ret);
10103cc72986SMark Brown 		goto err_early;
10113cc72986SMark Brown 	}
10123cc72986SMark Brown 
10130c2d0ffbSCharles Keepax 	/**
10140c2d0ffbSCharles Keepax 	 * Don't use devres here because the only device we have to get
10150c2d0ffbSCharles Keepax 	 * against is the MFD device and DCVDD will likely be supplied by
10160c2d0ffbSCharles Keepax 	 * one of its children. Meaning that the regulator will be
10170c2d0ffbSCharles Keepax 	 * destroyed by the time devres calls regulator put.
10180c2d0ffbSCharles Keepax 	 */
1019e6021511SCharles Keepax 	arizona->dcvdd = regulator_get(arizona->dev, "DCVDD");
102059db9691SMark Brown 	if (IS_ERR(arizona->dcvdd)) {
102159db9691SMark Brown 		ret = PTR_ERR(arizona->dcvdd);
102259db9691SMark Brown 		dev_err(dev, "Failed to request DCVDD: %d\n", ret);
102359db9691SMark Brown 		goto err_early;
102459db9691SMark Brown 	}
102559db9691SMark Brown 
1026c1860466SCharles Keepax 	if (!arizona->pdata.reset) {
102787d3af4aSMark Brown 		/* Start out with /RESET low to put the chip into reset */
1028c1860466SCharles Keepax 		arizona->pdata.reset = devm_gpiod_get(arizona->dev, "reset",
1029c1860466SCharles Keepax 						      GPIOD_OUT_LOW);
1030c1860466SCharles Keepax 		if (IS_ERR(arizona->pdata.reset)) {
1031c1860466SCharles Keepax 			ret = PTR_ERR(arizona->pdata.reset);
1032c1860466SCharles Keepax 			if (ret == -EPROBE_DEFER)
1033e6021511SCharles Keepax 				goto err_dcvdd;
1034c1860466SCharles Keepax 
1035c1860466SCharles Keepax 			dev_err(arizona->dev,
1036c1860466SCharles Keepax 				"Reset GPIO missing/malformed: %d\n", ret);
1037c1860466SCharles Keepax 
1038c1860466SCharles Keepax 			arizona->pdata.reset = NULL;
103987d3af4aSMark Brown 		}
104087d3af4aSMark Brown 	}
104187d3af4aSMark Brown 
10423cc72986SMark Brown 	ret = regulator_bulk_enable(arizona->num_core_supplies,
10433cc72986SMark Brown 				    arizona->core_supplies);
10443cc72986SMark Brown 	if (ret != 0) {
10453cc72986SMark Brown 		dev_err(dev, "Failed to enable core supplies: %d\n",
10463cc72986SMark Brown 			ret);
1047e6021511SCharles Keepax 		goto err_dcvdd;
10483cc72986SMark Brown 	}
10493cc72986SMark Brown 
105059db9691SMark Brown 	ret = regulator_enable(arizona->dcvdd);
105159db9691SMark Brown 	if (ret != 0) {
105259db9691SMark Brown 		dev_err(dev, "Failed to enable DCVDD: %d\n", ret);
105359db9691SMark Brown 		goto err_enable;
105459db9691SMark Brown 	}
105559db9691SMark Brown 
10562229875dSCharles Keepax 	arizona_disable_reset(arizona);
10573cc72986SMark Brown 
10583cc72986SMark Brown 	regcache_cache_only(arizona->regmap, false);
10593cc72986SMark Brown 
1060ca76ceb8SMark Brown 	/* Verify that this is a chip we know about */
1061ca76ceb8SMark Brown 	ret = regmap_read(arizona->regmap, ARIZONA_SOFTWARE_RESET, &reg);
1062ca76ceb8SMark Brown 	if (ret != 0) {
1063ca76ceb8SMark Brown 		dev_err(dev, "Failed to read ID register: %d\n", ret);
1064ca76ceb8SMark Brown 		goto err_reset;
1065ca76ceb8SMark Brown 	}
1066ca76ceb8SMark Brown 
1067ca76ceb8SMark Brown 	switch (reg) {
1068ca76ceb8SMark Brown 	case 0x5102:
1069ca76ceb8SMark Brown 	case 0x5110:
10706887b042SRichard Fitzgerald 	case 0x6349:
1071ea1f3339SRichard Fitzgerald 	case 0x6363:
1072dc7d4863SCharles Keepax 	case 0x8997:
1073ca76ceb8SMark Brown 		break;
1074ca76ceb8SMark Brown 	default:
1075ca76ceb8SMark Brown 		dev_err(arizona->dev, "Unknown device ID: %x\n", reg);
107675d8a2b0SCharles Keepax 		ret = -ENODEV;
1077ca76ceb8SMark Brown 		goto err_reset;
1078ca76ceb8SMark Brown 	}
1079ca76ceb8SMark Brown 
1080ca76ceb8SMark Brown 	/* If we have a /RESET GPIO we'll already be reset */
1081ca76ceb8SMark Brown 	if (!arizona->pdata.reset) {
1082ca76ceb8SMark Brown 		ret = regmap_write(arizona->regmap, ARIZONA_SOFTWARE_RESET, 0);
1083ca76ceb8SMark Brown 		if (ret != 0) {
1084ca76ceb8SMark Brown 			dev_err(dev, "Failed to reset device: %d\n", ret);
1085ca76ceb8SMark Brown 			goto err_reset;
1086ca76ceb8SMark Brown 		}
1087ca76ceb8SMark Brown 
1088b79a980fSLee Jones 		usleep_range(1000, 5000);
1089ca76ceb8SMark Brown 	}
1090ca76ceb8SMark Brown 
1091ca76ceb8SMark Brown 	/* Ensure device startup is complete */
1092ca76ceb8SMark Brown 	switch (arizona->type) {
1093ca76ceb8SMark Brown 	case WM5102:
109448018943SMark Brown 		ret = regmap_read(arizona->regmap,
109548018943SMark Brown 				  ARIZONA_WRITE_SEQUENCER_CTRL_3, &val);
10961c1c6bbaSCharles Keepax 		if (ret) {
1097ca76ceb8SMark Brown 			dev_err(dev,
1098ca76ceb8SMark Brown 				"Failed to check write sequencer state: %d\n",
1099ca76ceb8SMark Brown 				ret);
11001c1c6bbaSCharles Keepax 		} else if (val & 0x01) {
11011c1c6bbaSCharles Keepax 			ret = wm5102_clear_write_sequencer(arizona);
11021c1c6bbaSCharles Keepax 			if (ret)
11031c1c6bbaSCharles Keepax 				return ret;
1104ca76ceb8SMark Brown 		}
1105ca76ceb8SMark Brown 		break;
11061c1c6bbaSCharles Keepax 	default:
11071c1c6bbaSCharles Keepax 		break;
11081c1c6bbaSCharles Keepax 	}
11091c1c6bbaSCharles Keepax 
11101c1c6bbaSCharles Keepax 	ret = arizona_wait_for_boot(arizona);
11111c1c6bbaSCharles Keepax 	if (ret) {
11121c1c6bbaSCharles Keepax 		dev_err(arizona->dev, "Device failed initial boot: %d\n", ret);
11131c1c6bbaSCharles Keepax 		goto err_reset;
1114ca76ceb8SMark Brown 	}
1115ca76ceb8SMark Brown 
1116ca76ceb8SMark Brown 	/* Read the device ID information & do device specific stuff */
11173cc72986SMark Brown 	ret = regmap_read(arizona->regmap, ARIZONA_SOFTWARE_RESET, &reg);
11183cc72986SMark Brown 	if (ret != 0) {
11193cc72986SMark Brown 		dev_err(dev, "Failed to read ID register: %d\n", ret);
112059db9691SMark Brown 		goto err_reset;
11213cc72986SMark Brown 	}
11223cc72986SMark Brown 
11233cc72986SMark Brown 	ret = regmap_read(arizona->regmap, ARIZONA_DEVICE_REVISION,
11243cc72986SMark Brown 			  &arizona->rev);
11253cc72986SMark Brown 	if (ret != 0) {
11263cc72986SMark Brown 		dev_err(dev, "Failed to read revision register: %d\n", ret);
112759db9691SMark Brown 		goto err_reset;
11283cc72986SMark Brown 	}
11293cc72986SMark Brown 	arizona->rev &= ARIZONA_DEVICE_REVISION_MASK;
11303cc72986SMark Brown 
11313cc72986SMark Brown 	switch (reg) {
11323cc72986SMark Brown 	case 0x5102:
1133b61c1ec0SRichard Fitzgerald 		if (IS_ENABLED(CONFIG_MFD_WM5102)) {
11343cc72986SMark Brown 			type_name = "WM5102";
11353cc72986SMark Brown 			if (arizona->type != WM5102) {
1136b61c1ec0SRichard Fitzgerald 				dev_warn(arizona->dev,
1137b61c1ec0SRichard Fitzgerald 					 "WM5102 registered as %d\n",
11383cc72986SMark Brown 					 arizona->type);
11393cc72986SMark Brown 				arizona->type = WM5102;
11403cc72986SMark Brown 			}
1141b61c1ec0SRichard Fitzgerald 
114262d62b59SMark Brown 			apply_patch = wm5102_patch;
1143c6d6bfb1SMark Brown 			arizona->rev &= 0x7;
1144ae05ea36SRichard Fitzgerald 			subdevs = wm5102_devs;
1145ae05ea36SRichard Fitzgerald 			n_subdevs = ARRAY_SIZE(wm5102_devs);
1146b61c1ec0SRichard Fitzgerald 		}
11473cc72986SMark Brown 		break;
1148e102befeSMark Brown 	case 0x5110:
1149b61c1ec0SRichard Fitzgerald 		if (IS_ENABLED(CONFIG_MFD_WM5110)) {
1150e5d4ef0dSRichard Fitzgerald 			switch (arizona->type) {
1151e5d4ef0dSRichard Fitzgerald 			case WM5110:
1152e102befeSMark Brown 				type_name = "WM5110";
1153e5d4ef0dSRichard Fitzgerald 				break;
1154e5d4ef0dSRichard Fitzgerald 			case WM8280:
1155e5d4ef0dSRichard Fitzgerald 				type_name = "WM8280";
1156e5d4ef0dSRichard Fitzgerald 				break;
1157e5d4ef0dSRichard Fitzgerald 			default:
1158e5d4ef0dSRichard Fitzgerald 				type_name = "WM5110";
1159b61c1ec0SRichard Fitzgerald 				dev_warn(arizona->dev,
1160b61c1ec0SRichard Fitzgerald 					 "WM5110 registered as %d\n",
1161e102befeSMark Brown 					 arizona->type);
1162e102befeSMark Brown 				arizona->type = WM5110;
1163e5d4ef0dSRichard Fitzgerald 				break;
1164e102befeSMark Brown 			}
1165b61c1ec0SRichard Fitzgerald 
116662d62b59SMark Brown 			apply_patch = wm5110_patch;
1167ae05ea36SRichard Fitzgerald 			subdevs = wm5110_devs;
1168ae05ea36SRichard Fitzgerald 			n_subdevs = ARRAY_SIZE(wm5110_devs);
1169b61c1ec0SRichard Fitzgerald 		}
1170e102befeSMark Brown 		break;
1171ea1f3339SRichard Fitzgerald 	case 0x6363:
1172ea1f3339SRichard Fitzgerald 		if (IS_ENABLED(CONFIG_MFD_CS47L24)) {
1173ea1f3339SRichard Fitzgerald 			switch (arizona->type) {
1174ea1f3339SRichard Fitzgerald 			case CS47L24:
1175ea1f3339SRichard Fitzgerald 				type_name = "CS47L24";
1176ea1f3339SRichard Fitzgerald 				break;
1177ea1f3339SRichard Fitzgerald 
1178ea1f3339SRichard Fitzgerald 			case WM1831:
1179ea1f3339SRichard Fitzgerald 				type_name = "WM1831";
1180ea1f3339SRichard Fitzgerald 				break;
1181ea1f3339SRichard Fitzgerald 
1182ea1f3339SRichard Fitzgerald 			default:
1183ea1f3339SRichard Fitzgerald 				dev_warn(arizona->dev,
1184ea1f3339SRichard Fitzgerald 					 "CS47L24 registered as %d\n",
1185ea1f3339SRichard Fitzgerald 					 arizona->type);
1186ea1f3339SRichard Fitzgerald 				arizona->type = CS47L24;
1187ea1f3339SRichard Fitzgerald 				break;
1188ea1f3339SRichard Fitzgerald 			}
1189ea1f3339SRichard Fitzgerald 
1190ea1f3339SRichard Fitzgerald 			apply_patch = cs47l24_patch;
1191ea1f3339SRichard Fitzgerald 			subdevs = cs47l24_devs;
1192ea1f3339SRichard Fitzgerald 			n_subdevs = ARRAY_SIZE(cs47l24_devs);
1193ea1f3339SRichard Fitzgerald 		}
1194ea1f3339SRichard Fitzgerald 		break;
1195dc7d4863SCharles Keepax 	case 0x8997:
1196b61c1ec0SRichard Fitzgerald 		if (IS_ENABLED(CONFIG_MFD_WM8997)) {
1197dc7d4863SCharles Keepax 			type_name = "WM8997";
1198dc7d4863SCharles Keepax 			if (arizona->type != WM8997) {
1199b61c1ec0SRichard Fitzgerald 				dev_warn(arizona->dev,
1200b61c1ec0SRichard Fitzgerald 					 "WM8997 registered as %d\n",
1201dc7d4863SCharles Keepax 					 arizona->type);
1202dc7d4863SCharles Keepax 				arizona->type = WM8997;
1203dc7d4863SCharles Keepax 			}
1204b61c1ec0SRichard Fitzgerald 
1205dc7d4863SCharles Keepax 			apply_patch = wm8997_patch;
1206ae05ea36SRichard Fitzgerald 			subdevs = wm8997_devs;
1207ae05ea36SRichard Fitzgerald 			n_subdevs = ARRAY_SIZE(wm8997_devs);
1208b61c1ec0SRichard Fitzgerald 		}
1209dc7d4863SCharles Keepax 		break;
12106887b042SRichard Fitzgerald 	case 0x6349:
1211b61c1ec0SRichard Fitzgerald 		if (IS_ENABLED(CONFIG_MFD_WM8998)) {
12126887b042SRichard Fitzgerald 			switch (arizona->type) {
12136887b042SRichard Fitzgerald 			case WM8998:
12146887b042SRichard Fitzgerald 				type_name = "WM8998";
12156887b042SRichard Fitzgerald 				break;
12166887b042SRichard Fitzgerald 
12176887b042SRichard Fitzgerald 			case WM1814:
12186887b042SRichard Fitzgerald 				type_name = "WM1814";
12196887b042SRichard Fitzgerald 				break;
12206887b042SRichard Fitzgerald 
12216887b042SRichard Fitzgerald 			default:
12226887b042SRichard Fitzgerald 				type_name = "WM8998";
1223b61c1ec0SRichard Fitzgerald 				dev_warn(arizona->dev,
1224b61c1ec0SRichard Fitzgerald 					 "WM8998 registered as %d\n",
12256887b042SRichard Fitzgerald 					 arizona->type);
12266887b042SRichard Fitzgerald 				arizona->type = WM8998;
12276887b042SRichard Fitzgerald 			}
12286887b042SRichard Fitzgerald 
12296887b042SRichard Fitzgerald 			apply_patch = wm8998_patch;
1230ae05ea36SRichard Fitzgerald 			subdevs = wm8998_devs;
1231ae05ea36SRichard Fitzgerald 			n_subdevs = ARRAY_SIZE(wm8998_devs);
1232b61c1ec0SRichard Fitzgerald 		}
12336887b042SRichard Fitzgerald 		break;
12343cc72986SMark Brown 	default:
12353cc72986SMark Brown 		dev_err(arizona->dev, "Unknown device ID %x\n", reg);
123675d8a2b0SCharles Keepax 		ret = -ENODEV;
123759db9691SMark Brown 		goto err_reset;
12383cc72986SMark Brown 	}
12393cc72986SMark Brown 
1240b61c1ec0SRichard Fitzgerald 	if (!subdevs) {
1241b61c1ec0SRichard Fitzgerald 		dev_err(arizona->dev,
1242b61c1ec0SRichard Fitzgerald 			"No kernel support for device ID %x\n", reg);
124375d8a2b0SCharles Keepax 		ret = -ENODEV;
1244b61c1ec0SRichard Fitzgerald 		goto err_reset;
1245b61c1ec0SRichard Fitzgerald 	}
1246b61c1ec0SRichard Fitzgerald 
12473cc72986SMark Brown 	dev_info(dev, "%s revision %c\n", type_name, arizona->rev + 'A');
12483cc72986SMark Brown 
124962d62b59SMark Brown 	if (apply_patch) {
125062d62b59SMark Brown 		ret = apply_patch(arizona);
125162d62b59SMark Brown 		if (ret != 0) {
125262d62b59SMark Brown 			dev_err(arizona->dev, "Failed to apply patch: %d\n",
125362d62b59SMark Brown 				ret);
125462d62b59SMark Brown 			goto err_reset;
125562d62b59SMark Brown 		}
1256e80436bbSCharles Keepax 
1257e80436bbSCharles Keepax 		switch (arizona->type) {
1258e80436bbSCharles Keepax 		case WM5102:
12590be068a0SCharles Keepax 			ret = wm5102_apply_hardware_patch(arizona);
12600be068a0SCharles Keepax 			if (ret) {
1261e80436bbSCharles Keepax 				dev_err(arizona->dev,
1262e80436bbSCharles Keepax 					"Failed to apply hardware patch: %d\n",
1263e80436bbSCharles Keepax 					ret);
1264e80436bbSCharles Keepax 				goto err_reset;
1265e80436bbSCharles Keepax 			}
1266e80436bbSCharles Keepax 			break;
1267882bc468SCharles Keepax 		case WM5110:
1268882bc468SCharles Keepax 		case WM8280:
1269882bc468SCharles Keepax 			ret = wm5110_apply_sleep_patch(arizona);
1270882bc468SCharles Keepax 			if (ret) {
1271882bc468SCharles Keepax 				dev_err(arizona->dev,
1272882bc468SCharles Keepax 					"Failed to apply sleep patch: %d\n",
1273882bc468SCharles Keepax 					ret);
1274882bc468SCharles Keepax 				goto err_reset;
1275882bc468SCharles Keepax 			}
1276882bc468SCharles Keepax 			break;
1277e80436bbSCharles Keepax 		default:
1278e80436bbSCharles Keepax 			break;
1279e80436bbSCharles Keepax 		}
128062d62b59SMark Brown 	}
128162d62b59SMark Brown 
12823cc72986SMark Brown 	for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) {
12833cc72986SMark Brown 		if (!arizona->pdata.gpio_defaults[i])
12843cc72986SMark Brown 			continue;
12853cc72986SMark Brown 
12863cc72986SMark Brown 		regmap_write(arizona->regmap, ARIZONA_GPIO1_CTRL + i,
12873cc72986SMark Brown 			     arizona->pdata.gpio_defaults[i]);
12883cc72986SMark Brown 	}
12893cc72986SMark Brown 
12903cc72986SMark Brown 	/* Chip default */
12913cc72986SMark Brown 	if (!arizona->pdata.clk32k_src)
12923cc72986SMark Brown 		arizona->pdata.clk32k_src = ARIZONA_32KZ_MCLK2;
12933cc72986SMark Brown 
12943cc72986SMark Brown 	switch (arizona->pdata.clk32k_src) {
12953cc72986SMark Brown 	case ARIZONA_32KZ_MCLK1:
12963cc72986SMark Brown 	case ARIZONA_32KZ_MCLK2:
12973cc72986SMark Brown 		regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1,
12983cc72986SMark Brown 				   ARIZONA_CLK_32K_SRC_MASK,
12993cc72986SMark Brown 				   arizona->pdata.clk32k_src - 1);
1300767c6dc0SMark Brown 		arizona_clk32k_enable(arizona);
13013cc72986SMark Brown 		break;
13023cc72986SMark Brown 	case ARIZONA_32KZ_NONE:
13033cc72986SMark Brown 		regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1,
13043cc72986SMark Brown 				   ARIZONA_CLK_32K_SRC_MASK, 2);
13053cc72986SMark Brown 		break;
13063cc72986SMark Brown 	default:
13073cc72986SMark Brown 		dev_err(arizona->dev, "Invalid 32kHz clock source: %d\n",
13083cc72986SMark Brown 			arizona->pdata.clk32k_src);
13093cc72986SMark Brown 		ret = -EINVAL;
131059db9691SMark Brown 		goto err_reset;
13113cc72986SMark Brown 	}
13123cc72986SMark Brown 
13133d91f828SMark Brown 	for (i = 0; i < ARIZONA_MAX_MICBIAS; i++) {
1314544c7aadSMark Brown 		if (!arizona->pdata.micbias[i].mV &&
1315544c7aadSMark Brown 		    !arizona->pdata.micbias[i].bypass)
13163d91f828SMark Brown 			continue;
13173d91f828SMark Brown 
1318544c7aadSMark Brown 		/* Apply default for bypass mode */
1319544c7aadSMark Brown 		if (!arizona->pdata.micbias[i].mV)
1320544c7aadSMark Brown 			arizona->pdata.micbias[i].mV = 2800;
1321544c7aadSMark Brown 
13223d91f828SMark Brown 		val = (arizona->pdata.micbias[i].mV - 1500) / 100;
1323544c7aadSMark Brown 
13243d91f828SMark Brown 		val <<= ARIZONA_MICB1_LVL_SHIFT;
13253d91f828SMark Brown 
13263d91f828SMark Brown 		if (arizona->pdata.micbias[i].ext_cap)
13273d91f828SMark Brown 			val |= ARIZONA_MICB1_EXT_CAP;
13283d91f828SMark Brown 
13293d91f828SMark Brown 		if (arizona->pdata.micbias[i].discharge)
13303d91f828SMark Brown 			val |= ARIZONA_MICB1_DISCH;
13313d91f828SMark Brown 
1332f773fc6dSCharles Keepax 		if (arizona->pdata.micbias[i].soft_start)
13333d91f828SMark Brown 			val |= ARIZONA_MICB1_RATE;
13343d91f828SMark Brown 
1335544c7aadSMark Brown 		if (arizona->pdata.micbias[i].bypass)
1336544c7aadSMark Brown 			val |= ARIZONA_MICB1_BYPASS;
1337544c7aadSMark Brown 
13383d91f828SMark Brown 		regmap_update_bits(arizona->regmap,
13393d91f828SMark Brown 				   ARIZONA_MIC_BIAS_CTRL_1 + i,
13403d91f828SMark Brown 				   ARIZONA_MICB1_LVL_MASK |
134171d134b9SCharles Keepax 				   ARIZONA_MICB1_EXT_CAP |
13423d91f828SMark Brown 				   ARIZONA_MICB1_DISCH |
1343544c7aadSMark Brown 				   ARIZONA_MICB1_BYPASS |
13443d91f828SMark Brown 				   ARIZONA_MICB1_RATE, val);
13453d91f828SMark Brown 	}
13463d91f828SMark Brown 
134772e43164SCharles Keepax 	pm_runtime_set_active(arizona->dev);
134872e43164SCharles Keepax 	pm_runtime_enable(arizona->dev);
134972e43164SCharles Keepax 
13503cc72986SMark Brown 	/* Set up for interrupts */
13513cc72986SMark Brown 	ret = arizona_irq_init(arizona);
13523cc72986SMark Brown 	if (ret != 0)
1353d347792cSCharles Keepax 		goto err_pm;
13543cc72986SMark Brown 
135572e43164SCharles Keepax 	pm_runtime_set_autosuspend_delay(arizona->dev, 100);
135672e43164SCharles Keepax 	pm_runtime_use_autosuspend(arizona->dev);
135772e43164SCharles Keepax 
13583cc72986SMark Brown 	arizona_request_irq(arizona, ARIZONA_IRQ_CLKGEN_ERR, "CLKGEN error",
13593cc72986SMark Brown 			    arizona_clkgen_err, arizona);
13603cc72986SMark Brown 	arizona_request_irq(arizona, ARIZONA_IRQ_OVERCLOCKED, "Overclocked",
13613cc72986SMark Brown 			    arizona_overclocked, arizona);
13623cc72986SMark Brown 	arizona_request_irq(arizona, ARIZONA_IRQ_UNDERCLOCKED, "Underclocked",
13633cc72986SMark Brown 			    arizona_underclocked, arizona);
13643cc72986SMark Brown 
1365ae05ea36SRichard Fitzgerald 	ret = mfd_add_devices(arizona->dev, PLATFORM_DEVID_NONE,
1366ae05ea36SRichard Fitzgerald 			      subdevs, n_subdevs, NULL, 0, NULL);
13673cc72986SMark Brown 
1368ae05ea36SRichard Fitzgerald 	if (ret) {
13693cc72986SMark Brown 		dev_err(arizona->dev, "Failed to add subdevices: %d\n", ret);
13703cc72986SMark Brown 		goto err_irq;
13713cc72986SMark Brown 	}
13723cc72986SMark Brown 
13733cc72986SMark Brown 	return 0;
13743cc72986SMark Brown 
13753cc72986SMark Brown err_irq:
13763cc72986SMark Brown 	arizona_irq_exit(arizona);
1377d347792cSCharles Keepax err_pm:
1378d347792cSCharles Keepax 	pm_runtime_disable(arizona->dev);
1379ddff6c45SCharles Keepax 
1380ddff6c45SCharles Keepax 	switch (arizona->pdata.clk32k_src) {
1381ddff6c45SCharles Keepax 	case ARIZONA_32KZ_MCLK1:
1382ddff6c45SCharles Keepax 	case ARIZONA_32KZ_MCLK2:
1383ddff6c45SCharles Keepax 		arizona_clk32k_disable(arizona);
1384ddff6c45SCharles Keepax 		break;
1385ddff6c45SCharles Keepax 	default:
1386ddff6c45SCharles Keepax 		break;
1387ddff6c45SCharles Keepax 	}
13883cc72986SMark Brown err_reset:
13892229875dSCharles Keepax 	arizona_enable_reset(arizona);
139059db9691SMark Brown 	regulator_disable(arizona->dcvdd);
13913cc72986SMark Brown err_enable:
13923a36a0dbSMark Brown 	regulator_bulk_disable(arizona->num_core_supplies,
13933cc72986SMark Brown 			       arizona->core_supplies);
1394e6021511SCharles Keepax err_dcvdd:
1395e6021511SCharles Keepax 	regulator_put(arizona->dcvdd);
13963cc72986SMark Brown err_early:
13973cc72986SMark Brown 	mfd_remove_devices(dev);
13983cc72986SMark Brown 	return ret;
13993cc72986SMark Brown }
14003cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_dev_init);
14013cc72986SMark Brown 
arizona_dev_exit(struct arizona * arizona)14024740f73fSBill Pemberton int arizona_dev_exit(struct arizona *arizona)
14033cc72986SMark Brown {
1404fb36f77eSCharles Keepax 	disable_irq(arizona->irq);
1405b804020aSCharles Keepax 	pm_runtime_disable(arizona->dev);
1406b804020aSCharles Keepax 
1407df6b3352SCharles Keepax 	regulator_disable(arizona->dcvdd);
1408e6021511SCharles Keepax 	regulator_put(arizona->dcvdd);
1409df6b3352SCharles Keepax 
1410ddff6c45SCharles Keepax 	switch (arizona->pdata.clk32k_src) {
1411ddff6c45SCharles Keepax 	case ARIZONA_32KZ_MCLK1:
1412ddff6c45SCharles Keepax 	case ARIZONA_32KZ_MCLK2:
1413ddff6c45SCharles Keepax 		arizona_clk32k_disable(arizona);
1414ddff6c45SCharles Keepax 		break;
1415ddff6c45SCharles Keepax 	default:
1416ddff6c45SCharles Keepax 		break;
1417ddff6c45SCharles Keepax 	}
1418ddff6c45SCharles Keepax 
14193cc72986SMark Brown 	mfd_remove_devices(arizona->dev);
14203cc72986SMark Brown 	arizona_free_irq(arizona, ARIZONA_IRQ_UNDERCLOCKED, arizona);
14213cc72986SMark Brown 	arizona_free_irq(arizona, ARIZONA_IRQ_OVERCLOCKED, arizona);
14223cc72986SMark Brown 	arizona_free_irq(arizona, ARIZONA_IRQ_CLKGEN_ERR, arizona);
14233cc72986SMark Brown 	arizona_irq_exit(arizona);
14242229875dSCharles Keepax 	arizona_enable_reset(arizona);
1425df6b3352SCharles Keepax 
14264420286eSCharles Keepax 	regulator_bulk_disable(arizona->num_core_supplies,
14271d017b6bSMark Brown 			       arizona->core_supplies);
14283cc72986SMark Brown 	return 0;
14293cc72986SMark Brown }
14303cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_dev_exit);
143133d55070SHans de Goede 
143233d55070SHans de Goede MODULE_LICENSE("GPL v2");
1433