xref: /linux/drivers/mfd/arizona-core.c (revision cdd8da8cc66b3d205120560649e530978ccbc567)
13cc72986SMark Brown /*
23cc72986SMark Brown  * Arizona core driver
33cc72986SMark Brown  *
43cc72986SMark Brown  * Copyright 2012 Wolfson Microelectronics plc
53cc72986SMark Brown  *
63cc72986SMark Brown  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
73cc72986SMark Brown  *
83cc72986SMark Brown  * This program is free software; you can redistribute it and/or modify
93cc72986SMark Brown  * it under the terms of the GNU General Public License version 2 as
103cc72986SMark Brown  * published by the Free Software Foundation.
113cc72986SMark Brown  */
123cc72986SMark Brown 
13*cdd8da8cSSylwester Nawrocki #include <linux/clk.h>
143cc72986SMark Brown #include <linux/delay.h>
1559db9691SMark Brown #include <linux/err.h>
163cc72986SMark Brown #include <linux/gpio.h>
173cc72986SMark Brown #include <linux/interrupt.h>
183cc72986SMark Brown #include <linux/mfd/core.h>
193cc72986SMark Brown #include <linux/module.h>
20d781009cSMark Brown #include <linux/of.h>
21d781009cSMark Brown #include <linux/of_device.h>
22d781009cSMark Brown #include <linux/of_gpio.h>
233cc72986SMark Brown #include <linux/pm_runtime.h>
243cc72986SMark Brown #include <linux/regmap.h>
253cc72986SMark Brown #include <linux/regulator/consumer.h>
265927467dSMark Brown #include <linux/regulator/machine.h>
273cc72986SMark Brown #include <linux/slab.h>
28ae05ea36SRichard Fitzgerald #include <linux/platform_device.h>
293cc72986SMark Brown 
303cc72986SMark Brown #include <linux/mfd/arizona/core.h>
313cc72986SMark Brown #include <linux/mfd/arizona/registers.h>
323cc72986SMark Brown 
333cc72986SMark Brown #include "arizona.h"
343cc72986SMark Brown 
353762aedeSCharles Keepax static const char * const wm5102_core_supplies[] = {
363cc72986SMark Brown 	"AVDD",
373cc72986SMark Brown 	"DBVDD1",
383cc72986SMark Brown };
393cc72986SMark Brown 
403cc72986SMark Brown int arizona_clk32k_enable(struct arizona *arizona)
413cc72986SMark Brown {
423cc72986SMark Brown 	int ret = 0;
433cc72986SMark Brown 
443cc72986SMark Brown 	mutex_lock(&arizona->clk_lock);
453cc72986SMark Brown 
463cc72986SMark Brown 	arizona->clk32k_ref++;
473cc72986SMark Brown 
48247fa192SMark Brown 	if (arizona->clk32k_ref == 1) {
49247fa192SMark Brown 		switch (arizona->pdata.clk32k_src) {
50247fa192SMark Brown 		case ARIZONA_32KZ_MCLK1:
51247fa192SMark Brown 			ret = pm_runtime_get_sync(arizona->dev);
52247fa192SMark Brown 			if (ret != 0)
53*cdd8da8cSSylwester Nawrocki 				goto err_ref;
54*cdd8da8cSSylwester Nawrocki 			ret = clk_prepare_enable(arizona->mclk[ARIZONA_MCLK1]);
55*cdd8da8cSSylwester Nawrocki 			if (ret != 0)
56*cdd8da8cSSylwester Nawrocki 				goto err_pm;
57*cdd8da8cSSylwester Nawrocki 			break;
58*cdd8da8cSSylwester Nawrocki 		case ARIZONA_32KZ_MCLK2:
59*cdd8da8cSSylwester Nawrocki 			ret = clk_prepare_enable(arizona->mclk[ARIZONA_MCLK2]);
60*cdd8da8cSSylwester Nawrocki 			if (ret != 0)
61*cdd8da8cSSylwester Nawrocki 				goto err_ref;
62247fa192SMark Brown 			break;
63247fa192SMark Brown 		}
64247fa192SMark Brown 
653cc72986SMark Brown 		ret = regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1,
663cc72986SMark Brown 					 ARIZONA_CLK_32K_ENA,
673cc72986SMark Brown 					 ARIZONA_CLK_32K_ENA);
68247fa192SMark Brown 	}
693cc72986SMark Brown 
70*cdd8da8cSSylwester Nawrocki err_pm:
71*cdd8da8cSSylwester Nawrocki 	pm_runtime_put_sync(arizona->dev);
72*cdd8da8cSSylwester Nawrocki err_ref:
733cc72986SMark Brown 	if (ret != 0)
743cc72986SMark Brown 		arizona->clk32k_ref--;
753cc72986SMark Brown 
763cc72986SMark Brown 	mutex_unlock(&arizona->clk_lock);
773cc72986SMark Brown 
783cc72986SMark Brown 	return ret;
793cc72986SMark Brown }
803cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_clk32k_enable);
813cc72986SMark Brown 
823cc72986SMark Brown int arizona_clk32k_disable(struct arizona *arizona)
833cc72986SMark Brown {
843cc72986SMark Brown 	mutex_lock(&arizona->clk_lock);
853cc72986SMark Brown 
863cc72986SMark Brown 	BUG_ON(arizona->clk32k_ref <= 0);
873cc72986SMark Brown 
883cc72986SMark Brown 	arizona->clk32k_ref--;
893cc72986SMark Brown 
90247fa192SMark Brown 	if (arizona->clk32k_ref == 0) {
913cc72986SMark Brown 		regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1,
923cc72986SMark Brown 				   ARIZONA_CLK_32K_ENA, 0);
933cc72986SMark Brown 
94247fa192SMark Brown 		switch (arizona->pdata.clk32k_src) {
95247fa192SMark Brown 		case ARIZONA_32KZ_MCLK1:
96247fa192SMark Brown 			pm_runtime_put_sync(arizona->dev);
97*cdd8da8cSSylwester Nawrocki 			clk_disable_unprepare(arizona->mclk[ARIZONA_MCLK1]);
98*cdd8da8cSSylwester Nawrocki 			break;
99*cdd8da8cSSylwester Nawrocki 		case ARIZONA_32KZ_MCLK2:
100*cdd8da8cSSylwester Nawrocki 			clk_disable_unprepare(arizona->mclk[ARIZONA_MCLK2]);
101247fa192SMark Brown 			break;
102247fa192SMark Brown 		}
103247fa192SMark Brown 	}
104247fa192SMark Brown 
1053cc72986SMark Brown 	mutex_unlock(&arizona->clk_lock);
1063cc72986SMark Brown 
107a260fba1SJavier Martinez Canillas 	return 0;
1083cc72986SMark Brown }
1093cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_clk32k_disable);
1103cc72986SMark Brown 
1113cc72986SMark Brown static irqreturn_t arizona_clkgen_err(int irq, void *data)
1123cc72986SMark Brown {
1133cc72986SMark Brown 	struct arizona *arizona = data;
1143cc72986SMark Brown 
1153cc72986SMark Brown 	dev_err(arizona->dev, "CLKGEN error\n");
1163cc72986SMark Brown 
1173cc72986SMark Brown 	return IRQ_HANDLED;
1183cc72986SMark Brown }
1193cc72986SMark Brown 
1203cc72986SMark Brown static irqreturn_t arizona_underclocked(int irq, void *data)
1213cc72986SMark Brown {
1223cc72986SMark Brown 	struct arizona *arizona = data;
1233cc72986SMark Brown 	unsigned int val;
1243cc72986SMark Brown 	int ret;
1253cc72986SMark Brown 
1263cc72986SMark Brown 	ret = regmap_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_8,
1273cc72986SMark Brown 			  &val);
1283cc72986SMark Brown 	if (ret != 0) {
1293cc72986SMark Brown 		dev_err(arizona->dev, "Failed to read underclock status: %d\n",
1303cc72986SMark Brown 			ret);
1313cc72986SMark Brown 		return IRQ_NONE;
1323cc72986SMark Brown 	}
1333cc72986SMark Brown 
1343cc72986SMark Brown 	if (val & ARIZONA_AIF3_UNDERCLOCKED_STS)
1353cc72986SMark Brown 		dev_err(arizona->dev, "AIF3 underclocked\n");
1363cc72986SMark Brown 	if (val & ARIZONA_AIF2_UNDERCLOCKED_STS)
1373ebef34dSCharles Keepax 		dev_err(arizona->dev, "AIF2 underclocked\n");
1383ebef34dSCharles Keepax 	if (val & ARIZONA_AIF1_UNDERCLOCKED_STS)
1393cc72986SMark Brown 		dev_err(arizona->dev, "AIF1 underclocked\n");
1406e440d27SCharles Keepax 	if (val & ARIZONA_ISRC3_UNDERCLOCKED_STS)
1416e440d27SCharles Keepax 		dev_err(arizona->dev, "ISRC3 underclocked\n");
1423cc72986SMark Brown 	if (val & ARIZONA_ISRC2_UNDERCLOCKED_STS)
1433cc72986SMark Brown 		dev_err(arizona->dev, "ISRC2 underclocked\n");
1443cc72986SMark Brown 	if (val & ARIZONA_ISRC1_UNDERCLOCKED_STS)
1453cc72986SMark Brown 		dev_err(arizona->dev, "ISRC1 underclocked\n");
1463cc72986SMark Brown 	if (val & ARIZONA_FX_UNDERCLOCKED_STS)
1473cc72986SMark Brown 		dev_err(arizona->dev, "FX underclocked\n");
1483cc72986SMark Brown 	if (val & ARIZONA_ASRC_UNDERCLOCKED_STS)
1493cc72986SMark Brown 		dev_err(arizona->dev, "ASRC underclocked\n");
1503cc72986SMark Brown 	if (val & ARIZONA_DAC_UNDERCLOCKED_STS)
1513cc72986SMark Brown 		dev_err(arizona->dev, "DAC underclocked\n");
1523cc72986SMark Brown 	if (val & ARIZONA_ADC_UNDERCLOCKED_STS)
1533cc72986SMark Brown 		dev_err(arizona->dev, "ADC underclocked\n");
1543cc72986SMark Brown 	if (val & ARIZONA_MIXER_UNDERCLOCKED_STS)
155648a9880SMark Brown 		dev_err(arizona->dev, "Mixer dropped sample\n");
1563cc72986SMark Brown 
1573cc72986SMark Brown 	return IRQ_HANDLED;
1583cc72986SMark Brown }
1593cc72986SMark Brown 
1603cc72986SMark Brown static irqreturn_t arizona_overclocked(int irq, void *data)
1613cc72986SMark Brown {
1623cc72986SMark Brown 	struct arizona *arizona = data;
1636887b042SRichard Fitzgerald 	unsigned int val[3];
1643cc72986SMark Brown 	int ret;
1653cc72986SMark Brown 
1663cc72986SMark Brown 	ret = regmap_bulk_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_6,
1676887b042SRichard Fitzgerald 			       &val[0], 3);
1683cc72986SMark Brown 	if (ret != 0) {
1693cc72986SMark Brown 		dev_err(arizona->dev, "Failed to read overclock status: %d\n",
1703cc72986SMark Brown 			ret);
1713cc72986SMark Brown 		return IRQ_NONE;
1723cc72986SMark Brown 	}
1733cc72986SMark Brown 
1746887b042SRichard Fitzgerald 	switch (arizona->type) {
1756887b042SRichard Fitzgerald 	case WM8998:
1766887b042SRichard Fitzgerald 	case WM1814:
1776887b042SRichard Fitzgerald 		/* Some bits are shifted on WM8998,
1786887b042SRichard Fitzgerald 		 * rearrange to match the standard bit layout
1796887b042SRichard Fitzgerald 		 */
1806887b042SRichard Fitzgerald 		val[0] = ((val[0] & 0x60e0) >> 1) |
1816887b042SRichard Fitzgerald 			 ((val[0] & 0x1e00) >> 2) |
1826887b042SRichard Fitzgerald 			 (val[0] & 0x000f);
1836887b042SRichard Fitzgerald 		break;
1846887b042SRichard Fitzgerald 	default:
1856887b042SRichard Fitzgerald 		break;
1866887b042SRichard Fitzgerald 	}
1876887b042SRichard Fitzgerald 
1883cc72986SMark Brown 	if (val[0] & ARIZONA_PWM_OVERCLOCKED_STS)
1893cc72986SMark Brown 		dev_err(arizona->dev, "PWM overclocked\n");
1903cc72986SMark Brown 	if (val[0] & ARIZONA_FX_CORE_OVERCLOCKED_STS)
1913cc72986SMark Brown 		dev_err(arizona->dev, "FX core overclocked\n");
1923cc72986SMark Brown 	if (val[0] & ARIZONA_DAC_SYS_OVERCLOCKED_STS)
1933cc72986SMark Brown 		dev_err(arizona->dev, "DAC SYS overclocked\n");
1943cc72986SMark Brown 	if (val[0] & ARIZONA_DAC_WARP_OVERCLOCKED_STS)
1953cc72986SMark Brown 		dev_err(arizona->dev, "DAC WARP overclocked\n");
1963cc72986SMark Brown 	if (val[0] & ARIZONA_ADC_OVERCLOCKED_STS)
1973cc72986SMark Brown 		dev_err(arizona->dev, "ADC overclocked\n");
1983cc72986SMark Brown 	if (val[0] & ARIZONA_MIXER_OVERCLOCKED_STS)
1993cc72986SMark Brown 		dev_err(arizona->dev, "Mixer overclocked\n");
2003cc72986SMark Brown 	if (val[0] & ARIZONA_AIF3_SYNC_OVERCLOCKED_STS)
2013cc72986SMark Brown 		dev_err(arizona->dev, "AIF3 overclocked\n");
2023cc72986SMark Brown 	if (val[0] & ARIZONA_AIF2_SYNC_OVERCLOCKED_STS)
2033cc72986SMark Brown 		dev_err(arizona->dev, "AIF2 overclocked\n");
2043cc72986SMark Brown 	if (val[0] & ARIZONA_AIF1_SYNC_OVERCLOCKED_STS)
2053cc72986SMark Brown 		dev_err(arizona->dev, "AIF1 overclocked\n");
2063cc72986SMark Brown 	if (val[0] & ARIZONA_PAD_CTRL_OVERCLOCKED_STS)
2073cc72986SMark Brown 		dev_err(arizona->dev, "Pad control overclocked\n");
2083cc72986SMark Brown 
2093cc72986SMark Brown 	if (val[1] & ARIZONA_SLIMBUS_SUBSYS_OVERCLOCKED_STS)
2103cc72986SMark Brown 		dev_err(arizona->dev, "Slimbus subsystem overclocked\n");
2113cc72986SMark Brown 	if (val[1] & ARIZONA_SLIMBUS_ASYNC_OVERCLOCKED_STS)
2123cc72986SMark Brown 		dev_err(arizona->dev, "Slimbus async overclocked\n");
2133cc72986SMark Brown 	if (val[1] & ARIZONA_SLIMBUS_SYNC_OVERCLOCKED_STS)
2143cc72986SMark Brown 		dev_err(arizona->dev, "Slimbus sync overclocked\n");
2153cc72986SMark Brown 	if (val[1] & ARIZONA_ASRC_ASYNC_SYS_OVERCLOCKED_STS)
2163cc72986SMark Brown 		dev_err(arizona->dev, "ASRC async system overclocked\n");
2173cc72986SMark Brown 	if (val[1] & ARIZONA_ASRC_ASYNC_WARP_OVERCLOCKED_STS)
2183cc72986SMark Brown 		dev_err(arizona->dev, "ASRC async WARP overclocked\n");
2193cc72986SMark Brown 	if (val[1] & ARIZONA_ASRC_SYNC_SYS_OVERCLOCKED_STS)
2203cc72986SMark Brown 		dev_err(arizona->dev, "ASRC sync system overclocked\n");
2213cc72986SMark Brown 	if (val[1] & ARIZONA_ASRC_SYNC_WARP_OVERCLOCKED_STS)
2223cc72986SMark Brown 		dev_err(arizona->dev, "ASRC sync WARP overclocked\n");
2233cc72986SMark Brown 	if (val[1] & ARIZONA_ADSP2_1_OVERCLOCKED_STS)
2243cc72986SMark Brown 		dev_err(arizona->dev, "DSP1 overclocked\n");
2256e440d27SCharles Keepax 	if (val[1] & ARIZONA_ISRC3_OVERCLOCKED_STS)
2266e440d27SCharles Keepax 		dev_err(arizona->dev, "ISRC3 overclocked\n");
2273cc72986SMark Brown 	if (val[1] & ARIZONA_ISRC2_OVERCLOCKED_STS)
2283cc72986SMark Brown 		dev_err(arizona->dev, "ISRC2 overclocked\n");
2293cc72986SMark Brown 	if (val[1] & ARIZONA_ISRC1_OVERCLOCKED_STS)
2303cc72986SMark Brown 		dev_err(arizona->dev, "ISRC1 overclocked\n");
2313cc72986SMark Brown 
2326887b042SRichard Fitzgerald 	if (val[2] & ARIZONA_SPDIF_OVERCLOCKED_STS)
2336887b042SRichard Fitzgerald 		dev_err(arizona->dev, "SPDIF overclocked\n");
2346887b042SRichard Fitzgerald 
2353cc72986SMark Brown 	return IRQ_HANDLED;
2363cc72986SMark Brown }
2373cc72986SMark Brown 
2389d53dfdcSCharles Keepax static int arizona_poll_reg(struct arizona *arizona,
2399d53dfdcSCharles Keepax 			    int timeout, unsigned int reg,
2409d53dfdcSCharles Keepax 			    unsigned int mask, unsigned int target)
2419d53dfdcSCharles Keepax {
2429d53dfdcSCharles Keepax 	unsigned int val = 0;
2439d53dfdcSCharles Keepax 	int ret, i;
2449d53dfdcSCharles Keepax 
2459d53dfdcSCharles Keepax 	for (i = 0; i < timeout; i++) {
2469d53dfdcSCharles Keepax 		ret = regmap_read(arizona->regmap, reg, &val);
2479d53dfdcSCharles Keepax 		if (ret != 0) {
2489d53dfdcSCharles Keepax 			dev_err(arizona->dev, "Failed to read reg %u: %d\n",
2499d53dfdcSCharles Keepax 				reg, ret);
2509d53dfdcSCharles Keepax 			continue;
2519d53dfdcSCharles Keepax 		}
2529d53dfdcSCharles Keepax 
2539d53dfdcSCharles Keepax 		if ((val & mask) == target)
2549d53dfdcSCharles Keepax 			return 0;
2559d53dfdcSCharles Keepax 
256b79a980fSLee Jones 		usleep_range(1000, 5000);
2579d53dfdcSCharles Keepax 	}
2589d53dfdcSCharles Keepax 
2599d53dfdcSCharles Keepax 	dev_err(arizona->dev, "Polling reg %u timed out: %x\n", reg, val);
2609d53dfdcSCharles Keepax 	return -ETIMEDOUT;
2619d53dfdcSCharles Keepax }
2629d53dfdcSCharles Keepax 
2633cc72986SMark Brown static int arizona_wait_for_boot(struct arizona *arizona)
2643cc72986SMark Brown {
2659d53dfdcSCharles Keepax 	int ret;
2663cc72986SMark Brown 
2673cc72986SMark Brown 	/*
2683cc72986SMark Brown 	 * We can't use an interrupt as we need to runtime resume to do so,
2693cc72986SMark Brown 	 * we won't race with the interrupt handler as it'll be blocked on
2703cc72986SMark Brown 	 * runtime resume.
2713cc72986SMark Brown 	 */
2729d53dfdcSCharles Keepax 	ret = arizona_poll_reg(arizona, 5, ARIZONA_INTERRUPT_RAW_STATUS_5,
2739d53dfdcSCharles Keepax 			       ARIZONA_BOOT_DONE_STS, ARIZONA_BOOT_DONE_STS);
2743cc72986SMark Brown 
2759d53dfdcSCharles Keepax 	if (!ret)
2763cc72986SMark Brown 		regmap_write(arizona->regmap, ARIZONA_INTERRUPT_STATUS_5,
2773cc72986SMark Brown 			     ARIZONA_BOOT_DONE_STS);
2783cc72986SMark Brown 
2793cc72986SMark Brown 	pm_runtime_mark_last_busy(arizona->dev);
2803cc72986SMark Brown 
2819d53dfdcSCharles Keepax 	return ret;
2823cc72986SMark Brown }
2833cc72986SMark Brown 
2842229875dSCharles Keepax static inline void arizona_enable_reset(struct arizona *arizona)
2852229875dSCharles Keepax {
2862229875dSCharles Keepax 	if (arizona->pdata.reset)
2872229875dSCharles Keepax 		gpio_set_value_cansleep(arizona->pdata.reset, 0);
2882229875dSCharles Keepax }
2892229875dSCharles Keepax 
2902229875dSCharles Keepax static void arizona_disable_reset(struct arizona *arizona)
2912229875dSCharles Keepax {
2922229875dSCharles Keepax 	if (arizona->pdata.reset) {
293121c075cSCharles Keepax 		switch (arizona->type) {
294121c075cSCharles Keepax 		case WM5110:
295121c075cSCharles Keepax 		case WM8280:
296121c075cSCharles Keepax 			/* Meet requirements for minimum reset duration */
297b79a980fSLee Jones 			usleep_range(5000, 10000);
298121c075cSCharles Keepax 			break;
299121c075cSCharles Keepax 		default:
300121c075cSCharles Keepax 			break;
301121c075cSCharles Keepax 		}
302121c075cSCharles Keepax 
3032229875dSCharles Keepax 		gpio_set_value_cansleep(arizona->pdata.reset, 1);
304b79a980fSLee Jones 		usleep_range(1000, 5000);
3052229875dSCharles Keepax 	}
3062229875dSCharles Keepax }
3072229875dSCharles Keepax 
3083850e3eeSCharles Keepax struct arizona_sysclk_state {
3093850e3eeSCharles Keepax 	unsigned int fll;
3103850e3eeSCharles Keepax 	unsigned int sysclk;
3113850e3eeSCharles Keepax };
3123850e3eeSCharles Keepax 
3133850e3eeSCharles Keepax static int arizona_enable_freerun_sysclk(struct arizona *arizona,
3143850e3eeSCharles Keepax 					 struct arizona_sysclk_state *state)
315e80436bbSCharles Keepax {
316e80436bbSCharles Keepax 	int ret, err;
317e80436bbSCharles Keepax 
318e80436bbSCharles Keepax 	/* Cache existing FLL and SYSCLK settings */
3193850e3eeSCharles Keepax 	ret = regmap_read(arizona->regmap, ARIZONA_FLL1_CONTROL_1, &state->fll);
3200be068a0SCharles Keepax 	if (ret) {
321e80436bbSCharles Keepax 		dev_err(arizona->dev, "Failed to cache FLL settings: %d\n",
322e80436bbSCharles Keepax 			ret);
323e80436bbSCharles Keepax 		return ret;
324e80436bbSCharles Keepax 	}
3253850e3eeSCharles Keepax 	ret = regmap_read(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1,
3263850e3eeSCharles Keepax 			  &state->sysclk);
3270be068a0SCharles Keepax 	if (ret) {
328e80436bbSCharles Keepax 		dev_err(arizona->dev, "Failed to cache SYSCLK settings: %d\n",
329e80436bbSCharles Keepax 			ret);
330e80436bbSCharles Keepax 		return ret;
331e80436bbSCharles Keepax 	}
332e80436bbSCharles Keepax 
333e80436bbSCharles Keepax 	/* Start up SYSCLK using the FLL in free running mode */
334e80436bbSCharles Keepax 	ret = regmap_write(arizona->regmap, ARIZONA_FLL1_CONTROL_1,
335e80436bbSCharles Keepax 			ARIZONA_FLL1_ENA | ARIZONA_FLL1_FREERUN);
3360be068a0SCharles Keepax 	if (ret) {
337e80436bbSCharles Keepax 		dev_err(arizona->dev,
338e80436bbSCharles Keepax 			"Failed to start FLL in freerunning mode: %d\n",
339e80436bbSCharles Keepax 			ret);
340e80436bbSCharles Keepax 		return ret;
341e80436bbSCharles Keepax 	}
342e80436bbSCharles Keepax 	ret = arizona_poll_reg(arizona, 25, ARIZONA_INTERRUPT_RAW_STATUS_5,
343e80436bbSCharles Keepax 			       ARIZONA_FLL1_CLOCK_OK_STS,
344e80436bbSCharles Keepax 			       ARIZONA_FLL1_CLOCK_OK_STS);
3450be068a0SCharles Keepax 	if (ret) {
346e80436bbSCharles Keepax 		ret = -ETIMEDOUT;
347e80436bbSCharles Keepax 		goto err_fll;
348e80436bbSCharles Keepax 	}
349e80436bbSCharles Keepax 
350e80436bbSCharles Keepax 	ret = regmap_write(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, 0x0144);
3510be068a0SCharles Keepax 	if (ret) {
352e80436bbSCharles Keepax 		dev_err(arizona->dev, "Failed to start SYSCLK: %d\n", ret);
353e80436bbSCharles Keepax 		goto err_fll;
354e80436bbSCharles Keepax 	}
355e80436bbSCharles Keepax 
3563850e3eeSCharles Keepax 	return 0;
3573850e3eeSCharles Keepax 
3583850e3eeSCharles Keepax err_fll:
3593850e3eeSCharles Keepax 	err = regmap_write(arizona->regmap, ARIZONA_FLL1_CONTROL_1, state->fll);
3603850e3eeSCharles Keepax 	if (err)
3613850e3eeSCharles Keepax 		dev_err(arizona->dev,
3623850e3eeSCharles Keepax 			"Failed to re-apply old FLL settings: %d\n", err);
3633850e3eeSCharles Keepax 
3643850e3eeSCharles Keepax 	return ret;
3653850e3eeSCharles Keepax }
3663850e3eeSCharles Keepax 
3673850e3eeSCharles Keepax static int arizona_disable_freerun_sysclk(struct arizona *arizona,
3683850e3eeSCharles Keepax 					  struct arizona_sysclk_state *state)
3693850e3eeSCharles Keepax {
3703850e3eeSCharles Keepax 	int ret;
3713850e3eeSCharles Keepax 
3723850e3eeSCharles Keepax 	ret = regmap_write(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1,
3733850e3eeSCharles Keepax 			   state->sysclk);
3743850e3eeSCharles Keepax 	if (ret) {
3753850e3eeSCharles Keepax 		dev_err(arizona->dev,
3763850e3eeSCharles Keepax 			"Failed to re-apply old SYSCLK settings: %d\n", ret);
3773850e3eeSCharles Keepax 		return ret;
3783850e3eeSCharles Keepax 	}
3793850e3eeSCharles Keepax 
3803850e3eeSCharles Keepax 	ret = regmap_write(arizona->regmap, ARIZONA_FLL1_CONTROL_1, state->fll);
3813850e3eeSCharles Keepax 	if (ret) {
3823850e3eeSCharles Keepax 		dev_err(arizona->dev,
3833850e3eeSCharles Keepax 			"Failed to re-apply old FLL settings: %d\n", ret);
3843850e3eeSCharles Keepax 		return ret;
3853850e3eeSCharles Keepax 	}
3863850e3eeSCharles Keepax 
3873850e3eeSCharles Keepax 	return 0;
3883850e3eeSCharles Keepax }
3893850e3eeSCharles Keepax 
3903850e3eeSCharles Keepax static int wm5102_apply_hardware_patch(struct arizona *arizona)
3913850e3eeSCharles Keepax {
3923850e3eeSCharles Keepax 	struct arizona_sysclk_state state;
3933850e3eeSCharles Keepax 	int err, ret;
3943850e3eeSCharles Keepax 
3953850e3eeSCharles Keepax 	ret = arizona_enable_freerun_sysclk(arizona, &state);
3963850e3eeSCharles Keepax 	if (ret)
3973850e3eeSCharles Keepax 		return ret;
3983850e3eeSCharles Keepax 
399e80436bbSCharles Keepax 	/* Start the write sequencer and wait for it to finish */
400e80436bbSCharles Keepax 	ret = regmap_write(arizona->regmap, ARIZONA_WRITE_SEQUENCER_CTRL_0,
401e80436bbSCharles Keepax 			   ARIZONA_WSEQ_ENA | ARIZONA_WSEQ_START | 160);
4020be068a0SCharles Keepax 	if (ret) {
403e80436bbSCharles Keepax 		dev_err(arizona->dev, "Failed to start write sequencer: %d\n",
404e80436bbSCharles Keepax 			ret);
4053850e3eeSCharles Keepax 		goto err;
406e80436bbSCharles Keepax 	}
4073850e3eeSCharles Keepax 
408e80436bbSCharles Keepax 	ret = arizona_poll_reg(arizona, 5, ARIZONA_WRITE_SEQUENCER_CTRL_1,
409e80436bbSCharles Keepax 			       ARIZONA_WSEQ_BUSY, 0);
4100be068a0SCharles Keepax 	if (ret) {
411e80436bbSCharles Keepax 		regmap_write(arizona->regmap, ARIZONA_WRITE_SEQUENCER_CTRL_0,
412e80436bbSCharles Keepax 			     ARIZONA_WSEQ_ABORT);
413e80436bbSCharles Keepax 		ret = -ETIMEDOUT;
414e80436bbSCharles Keepax 	}
415e80436bbSCharles Keepax 
4163850e3eeSCharles Keepax err:
4173850e3eeSCharles Keepax 	err = arizona_disable_freerun_sysclk(arizona, &state);
418e80436bbSCharles Keepax 
4190be068a0SCharles Keepax 	return ret ?: err;
420e80436bbSCharles Keepax }
421e80436bbSCharles Keepax 
422882bc468SCharles Keepax /*
423882bc468SCharles Keepax  * Register patch to some of the CODECs internal write sequences
424882bc468SCharles Keepax  * to ensure a clean exit from the low power sleep state.
425882bc468SCharles Keepax  */
4268019ff6cSNariman Poushin static const struct reg_sequence wm5110_sleep_patch[] = {
427882bc468SCharles Keepax 	{ 0x337A, 0xC100 },
428882bc468SCharles Keepax 	{ 0x337B, 0x0041 },
429882bc468SCharles Keepax 	{ 0x3300, 0xA210 },
430882bc468SCharles Keepax 	{ 0x3301, 0x050C },
431882bc468SCharles Keepax };
432882bc468SCharles Keepax 
433882bc468SCharles Keepax static int wm5110_apply_sleep_patch(struct arizona *arizona)
434882bc468SCharles Keepax {
435882bc468SCharles Keepax 	struct arizona_sysclk_state state;
436882bc468SCharles Keepax 	int err, ret;
437882bc468SCharles Keepax 
438882bc468SCharles Keepax 	ret = arizona_enable_freerun_sysclk(arizona, &state);
439882bc468SCharles Keepax 	if (ret)
440882bc468SCharles Keepax 		return ret;
441882bc468SCharles Keepax 
442882bc468SCharles Keepax 	ret = regmap_multi_reg_write_bypassed(arizona->regmap,
443882bc468SCharles Keepax 					      wm5110_sleep_patch,
444882bc468SCharles Keepax 					      ARRAY_SIZE(wm5110_sleep_patch));
445882bc468SCharles Keepax 
446882bc468SCharles Keepax 	err = arizona_disable_freerun_sysclk(arizona, &state);
447882bc468SCharles Keepax 
448882bc468SCharles Keepax 	return ret ?: err;
449882bc468SCharles Keepax }
450882bc468SCharles Keepax 
4511c1c6bbaSCharles Keepax static int wm5102_clear_write_sequencer(struct arizona *arizona)
4521c1c6bbaSCharles Keepax {
4531c1c6bbaSCharles Keepax 	int ret;
4541c1c6bbaSCharles Keepax 
4551c1c6bbaSCharles Keepax 	ret = regmap_write(arizona->regmap, ARIZONA_WRITE_SEQUENCER_CTRL_3,
4561c1c6bbaSCharles Keepax 			   0x0);
4571c1c6bbaSCharles Keepax 	if (ret) {
4581c1c6bbaSCharles Keepax 		dev_err(arizona->dev,
4591c1c6bbaSCharles Keepax 			"Failed to clear write sequencer state: %d\n", ret);
4601c1c6bbaSCharles Keepax 		return ret;
4611c1c6bbaSCharles Keepax 	}
4621c1c6bbaSCharles Keepax 
4631c1c6bbaSCharles Keepax 	arizona_enable_reset(arizona);
4641c1c6bbaSCharles Keepax 	regulator_disable(arizona->dcvdd);
4651c1c6bbaSCharles Keepax 
4661c1c6bbaSCharles Keepax 	msleep(20);
4671c1c6bbaSCharles Keepax 
4681c1c6bbaSCharles Keepax 	ret = regulator_enable(arizona->dcvdd);
4691c1c6bbaSCharles Keepax 	if (ret) {
4701c1c6bbaSCharles Keepax 		dev_err(arizona->dev, "Failed to re-enable DCVDD: %d\n", ret);
4711c1c6bbaSCharles Keepax 		return ret;
4721c1c6bbaSCharles Keepax 	}
4731c1c6bbaSCharles Keepax 	arizona_disable_reset(arizona);
4741c1c6bbaSCharles Keepax 
4751c1c6bbaSCharles Keepax 	return 0;
4761c1c6bbaSCharles Keepax }
4771c1c6bbaSCharles Keepax 
47848bb9fe4SRafael J. Wysocki #ifdef CONFIG_PM
479e7811147SRichard Fitzgerald static int arizona_isolate_dcvdd(struct arizona *arizona)
480e7811147SRichard Fitzgerald {
481e7811147SRichard Fitzgerald 	int ret;
482e7811147SRichard Fitzgerald 
483e7811147SRichard Fitzgerald 	ret = regmap_update_bits(arizona->regmap,
484e7811147SRichard Fitzgerald 				 ARIZONA_ISOLATION_CONTROL,
485e7811147SRichard Fitzgerald 				 ARIZONA_ISOLATE_DCVDD1,
486e7811147SRichard Fitzgerald 				 ARIZONA_ISOLATE_DCVDD1);
487e7811147SRichard Fitzgerald 	if (ret != 0)
488e7811147SRichard Fitzgerald 		dev_err(arizona->dev, "Failed to isolate DCVDD: %d\n", ret);
489e7811147SRichard Fitzgerald 
490e7811147SRichard Fitzgerald 	return ret;
491e7811147SRichard Fitzgerald }
492e7811147SRichard Fitzgerald 
493e7811147SRichard Fitzgerald static int arizona_connect_dcvdd(struct arizona *arizona)
494e7811147SRichard Fitzgerald {
495e7811147SRichard Fitzgerald 	int ret;
496e7811147SRichard Fitzgerald 
497e7811147SRichard Fitzgerald 	ret = regmap_update_bits(arizona->regmap,
498e7811147SRichard Fitzgerald 				 ARIZONA_ISOLATION_CONTROL,
499e7811147SRichard Fitzgerald 				 ARIZONA_ISOLATE_DCVDD1, 0);
500e7811147SRichard Fitzgerald 	if (ret != 0)
501e7811147SRichard Fitzgerald 		dev_err(arizona->dev, "Failed to connect DCVDD: %d\n", ret);
502e7811147SRichard Fitzgerald 
503e7811147SRichard Fitzgerald 	return ret;
504e7811147SRichard Fitzgerald }
505e7811147SRichard Fitzgerald 
506e3424273SRichard Fitzgerald static int arizona_is_jack_det_active(struct arizona *arizona)
507e3424273SRichard Fitzgerald {
508e3424273SRichard Fitzgerald 	unsigned int val;
509e3424273SRichard Fitzgerald 	int ret;
510e3424273SRichard Fitzgerald 
511e3424273SRichard Fitzgerald 	ret = regmap_read(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE, &val);
512e3424273SRichard Fitzgerald 	if (ret) {
513e3424273SRichard Fitzgerald 		dev_err(arizona->dev,
514e3424273SRichard Fitzgerald 			"Failed to check jack det status: %d\n", ret);
515e3424273SRichard Fitzgerald 		return ret;
516e3424273SRichard Fitzgerald 	} else if (val & ARIZONA_JD1_ENA) {
517e3424273SRichard Fitzgerald 		return 1;
518e3424273SRichard Fitzgerald 	} else {
519e3424273SRichard Fitzgerald 		return 0;
520e3424273SRichard Fitzgerald 	}
521e3424273SRichard Fitzgerald }
522e3424273SRichard Fitzgerald 
5233cc72986SMark Brown static int arizona_runtime_resume(struct device *dev)
5243cc72986SMark Brown {
5253cc72986SMark Brown 	struct arizona *arizona = dev_get_drvdata(dev);
5263cc72986SMark Brown 	int ret;
5273cc72986SMark Brown 
528508c8299SMark Brown 	dev_dbg(arizona->dev, "Leaving AoD mode\n");
529508c8299SMark Brown 
530e6cb7341SCharles Keepax 	if (arizona->has_fully_powered_off) {
531e6cb7341SCharles Keepax 		dev_dbg(arizona->dev, "Re-enabling core supplies\n");
532e6cb7341SCharles Keepax 
533e6cb7341SCharles Keepax 		ret = regulator_bulk_enable(arizona->num_core_supplies,
534e6cb7341SCharles Keepax 					    arizona->core_supplies);
535e6cb7341SCharles Keepax 		if (ret) {
536e6cb7341SCharles Keepax 			dev_err(dev, "Failed to enable core supplies: %d\n",
537e6cb7341SCharles Keepax 				ret);
538e6cb7341SCharles Keepax 			return ret;
539e6cb7341SCharles Keepax 		}
540e6cb7341SCharles Keepax 	}
541e6cb7341SCharles Keepax 
54259db9691SMark Brown 	ret = regulator_enable(arizona->dcvdd);
54359db9691SMark Brown 	if (ret != 0) {
54459db9691SMark Brown 		dev_err(arizona->dev, "Failed to enable DCVDD: %d\n", ret);
545e6cb7341SCharles Keepax 		if (arizona->has_fully_powered_off)
546e6cb7341SCharles Keepax 			regulator_bulk_disable(arizona->num_core_supplies,
547e6cb7341SCharles Keepax 					       arizona->core_supplies);
54859db9691SMark Brown 		return ret;
54959db9691SMark Brown 	}
5503cc72986SMark Brown 
551e6cb7341SCharles Keepax 	if (arizona->has_fully_powered_off) {
552e6cb7341SCharles Keepax 		arizona_disable_reset(arizona);
553e6cb7341SCharles Keepax 		enable_irq(arizona->irq);
554e6cb7341SCharles Keepax 		arizona->has_fully_powered_off = false;
555e6cb7341SCharles Keepax 	}
556e6cb7341SCharles Keepax 
5573cc72986SMark Brown 	regcache_cache_only(arizona->regmap, false);
5583cc72986SMark Brown 
5594c9bb8bcSCharles Keepax 	switch (arizona->type) {
5604c9bb8bcSCharles Keepax 	case WM5102:
5615927467dSMark Brown 		if (arizona->external_dcvdd) {
562e7811147SRichard Fitzgerald 			ret = arizona_connect_dcvdd(arizona);
563e7811147SRichard Fitzgerald 			if (ret != 0)
5645927467dSMark Brown 				goto err;
5655927467dSMark Brown 		}
5665927467dSMark Brown 
5674c9bb8bcSCharles Keepax 		ret = wm5102_patch(arizona);
5684c9bb8bcSCharles Keepax 		if (ret != 0) {
5694c9bb8bcSCharles Keepax 			dev_err(arizona->dev, "Failed to apply patch: %d\n",
5704c9bb8bcSCharles Keepax 				ret);
5714c9bb8bcSCharles Keepax 			goto err;
5724c9bb8bcSCharles Keepax 		}
573e80436bbSCharles Keepax 
5740be068a0SCharles Keepax 		ret = wm5102_apply_hardware_patch(arizona);
5750be068a0SCharles Keepax 		if (ret) {
576e80436bbSCharles Keepax 			dev_err(arizona->dev,
577e80436bbSCharles Keepax 				"Failed to apply hardware patch: %d\n",
578e80436bbSCharles Keepax 				ret);
579e80436bbSCharles Keepax 			goto err;
580e80436bbSCharles Keepax 		}
581e80436bbSCharles Keepax 		break;
58296129a0eSCharles Keepax 	case WM5110:
58396129a0eSCharles Keepax 	case WM8280:
58496129a0eSCharles Keepax 		ret = arizona_wait_for_boot(arizona);
58596129a0eSCharles Keepax 		if (ret)
58696129a0eSCharles Keepax 			goto err;
58796129a0eSCharles Keepax 
58896129a0eSCharles Keepax 		if (arizona->external_dcvdd) {
589e7811147SRichard Fitzgerald 			ret = arizona_connect_dcvdd(arizona);
590e7811147SRichard Fitzgerald 			if (ret != 0)
59196129a0eSCharles Keepax 				goto err;
59296129a0eSCharles Keepax 		} else {
59396129a0eSCharles Keepax 			/*
59496129a0eSCharles Keepax 			 * As this is only called for the internal regulator
59596129a0eSCharles Keepax 			 * (where we know voltage ranges available) it is ok
59696129a0eSCharles Keepax 			 * to request an exact range.
59796129a0eSCharles Keepax 			 */
59896129a0eSCharles Keepax 			ret = regulator_set_voltage(arizona->dcvdd,
59996129a0eSCharles Keepax 						    1200000, 1200000);
60096129a0eSCharles Keepax 			if (ret < 0) {
60196129a0eSCharles Keepax 				dev_err(arizona->dev,
60296129a0eSCharles Keepax 					"Failed to set resume voltage: %d\n",
60396129a0eSCharles Keepax 					ret);
60496129a0eSCharles Keepax 				goto err;
60596129a0eSCharles Keepax 			}
60696129a0eSCharles Keepax 		}
607e6cb7341SCharles Keepax 
608e6cb7341SCharles Keepax 		ret = wm5110_apply_sleep_patch(arizona);
609e6cb7341SCharles Keepax 		if (ret) {
610e6cb7341SCharles Keepax 			dev_err(arizona->dev,
611e6cb7341SCharles Keepax 				"Failed to re-apply sleep patch: %d\n",
612e6cb7341SCharles Keepax 				ret);
613e6cb7341SCharles Keepax 			goto err;
614e6cb7341SCharles Keepax 		}
61596129a0eSCharles Keepax 		break;
616ea1f3339SRichard Fitzgerald 	case WM1831:
617ea1f3339SRichard Fitzgerald 	case CS47L24:
618ea1f3339SRichard Fitzgerald 		ret = arizona_wait_for_boot(arizona);
619ea1f3339SRichard Fitzgerald 		if (ret != 0)
620ea1f3339SRichard Fitzgerald 			goto err;
621ea1f3339SRichard Fitzgerald 		break;
622e80436bbSCharles Keepax 	default:
62312bb68edSCharles Keepax 		ret = arizona_wait_for_boot(arizona);
6243762aedeSCharles Keepax 		if (ret != 0)
62512bb68edSCharles Keepax 			goto err;
62612bb68edSCharles Keepax 
6275927467dSMark Brown 		if (arizona->external_dcvdd) {
628e7811147SRichard Fitzgerald 			ret = arizona_connect_dcvdd(arizona);
629e7811147SRichard Fitzgerald 			if (ret != 0)
6305927467dSMark Brown 				goto err;
6315927467dSMark Brown 		}
632e80436bbSCharles Keepax 		break;
6334c9bb8bcSCharles Keepax 	}
6344c9bb8bcSCharles Keepax 
6359270bdf5SMark Brown 	ret = regcache_sync(arizona->regmap);
6369270bdf5SMark Brown 	if (ret != 0) {
6379270bdf5SMark Brown 		dev_err(arizona->dev, "Failed to restore register cache\n");
6384816bd1cSMark Brown 		goto err;
6399270bdf5SMark Brown 	}
6403cc72986SMark Brown 
6413cc72986SMark Brown 	return 0;
6424816bd1cSMark Brown 
6434816bd1cSMark Brown err:
6444816bd1cSMark Brown 	regcache_cache_only(arizona->regmap, true);
6454816bd1cSMark Brown 	regulator_disable(arizona->dcvdd);
6464816bd1cSMark Brown 	return ret;
6473cc72986SMark Brown }
6483cc72986SMark Brown 
6493cc72986SMark Brown static int arizona_runtime_suspend(struct device *dev)
6503cc72986SMark Brown {
6513cc72986SMark Brown 	struct arizona *arizona = dev_get_drvdata(dev);
652a05950a4SDan Carpenter 	int jd_active = 0;
6535927467dSMark Brown 	int ret;
6543cc72986SMark Brown 
655508c8299SMark Brown 	dev_dbg(arizona->dev, "Entering AoD mode\n");
656508c8299SMark Brown 
65796129a0eSCharles Keepax 	switch (arizona->type) {
65896129a0eSCharles Keepax 	case WM5110:
65996129a0eSCharles Keepax 	case WM8280:
660e3424273SRichard Fitzgerald 		jd_active = arizona_is_jack_det_active(arizona);
661e3424273SRichard Fitzgerald 		if (jd_active < 0)
662e3424273SRichard Fitzgerald 			return jd_active;
663e3424273SRichard Fitzgerald 
664e7811147SRichard Fitzgerald 		if (arizona->external_dcvdd) {
665e7811147SRichard Fitzgerald 			ret = arizona_isolate_dcvdd(arizona);
666e7811147SRichard Fitzgerald 			if (ret != 0)
667e7811147SRichard Fitzgerald 				return ret;
668e7811147SRichard Fitzgerald 		} else {
66996129a0eSCharles Keepax 			/*
67096129a0eSCharles Keepax 			 * As this is only called for the internal regulator
67196129a0eSCharles Keepax 			 * (where we know voltage ranges available) it is ok
67296129a0eSCharles Keepax 			 * to request an exact range.
67396129a0eSCharles Keepax 			 */
674e7811147SRichard Fitzgerald 			ret = regulator_set_voltage(arizona->dcvdd,
675e7811147SRichard Fitzgerald 						    1175000, 1175000);
67696129a0eSCharles Keepax 			if (ret < 0) {
67796129a0eSCharles Keepax 				dev_err(arizona->dev,
678e7811147SRichard Fitzgerald 					"Failed to set suspend voltage: %d\n",
679e7811147SRichard Fitzgerald 					ret);
680e6cb7341SCharles Keepax 				return ret;
681e6cb7341SCharles Keepax 			}
682e7811147SRichard Fitzgerald 		}
683e6cb7341SCharles Keepax 		break;
684e6cb7341SCharles Keepax 	case WM5102:
685e3424273SRichard Fitzgerald 		jd_active = arizona_is_jack_det_active(arizona);
686e3424273SRichard Fitzgerald 		if (jd_active < 0)
687e3424273SRichard Fitzgerald 			return jd_active;
688e3424273SRichard Fitzgerald 
689e7811147SRichard Fitzgerald 		if (arizona->external_dcvdd) {
690e7811147SRichard Fitzgerald 			ret = arizona_isolate_dcvdd(arizona);
691e7811147SRichard Fitzgerald 			if (ret != 0)
692e7811147SRichard Fitzgerald 				return ret;
693e7811147SRichard Fitzgerald 		}
694e7811147SRichard Fitzgerald 
695e3424273SRichard Fitzgerald 		if (!jd_active) {
696e6cb7341SCharles Keepax 			ret = regmap_write(arizona->regmap,
697e6cb7341SCharles Keepax 					   ARIZONA_WRITE_SEQUENCER_CTRL_3, 0x0);
698e6cb7341SCharles Keepax 			if (ret) {
699e6cb7341SCharles Keepax 				dev_err(arizona->dev,
700e6cb7341SCharles Keepax 					"Failed to clear write sequencer: %d\n",
70196129a0eSCharles Keepax 					ret);
70296129a0eSCharles Keepax 				return ret;
70396129a0eSCharles Keepax 			}
704e6cb7341SCharles Keepax 		}
70596129a0eSCharles Keepax 		break;
706ea1f3339SRichard Fitzgerald 	case WM1831:
707ea1f3339SRichard Fitzgerald 	case CS47L24:
708ea1f3339SRichard Fitzgerald 		break;
70996129a0eSCharles Keepax 	default:
710e3424273SRichard Fitzgerald 		jd_active = arizona_is_jack_det_active(arizona);
711e3424273SRichard Fitzgerald 		if (jd_active < 0)
712e3424273SRichard Fitzgerald 			return jd_active;
713e3424273SRichard Fitzgerald 
714e7811147SRichard Fitzgerald 		if (arizona->external_dcvdd) {
715e7811147SRichard Fitzgerald 			ret = arizona_isolate_dcvdd(arizona);
716e7811147SRichard Fitzgerald 			if (ret != 0)
717e7811147SRichard Fitzgerald 				return ret;
718e7811147SRichard Fitzgerald 		}
71996129a0eSCharles Keepax 		break;
72096129a0eSCharles Keepax 	}
7215927467dSMark Brown 
7223cc72986SMark Brown 	regcache_cache_only(arizona->regmap, true);
7233cc72986SMark Brown 	regcache_mark_dirty(arizona->regmap);
724e293e847SCharles Keepax 	regulator_disable(arizona->dcvdd);
7253cc72986SMark Brown 
726e6cb7341SCharles Keepax 	/* Allow us to completely power down if no jack detection */
727e3424273SRichard Fitzgerald 	if (!jd_active) {
728e6cb7341SCharles Keepax 		dev_dbg(arizona->dev, "Fully powering off\n");
729e6cb7341SCharles Keepax 
730e6cb7341SCharles Keepax 		arizona->has_fully_powered_off = true;
731e6cb7341SCharles Keepax 
73211150929SCharles Keepax 		disable_irq_nosync(arizona->irq);
733e6cb7341SCharles Keepax 		arizona_enable_reset(arizona);
734e6cb7341SCharles Keepax 		regulator_bulk_disable(arizona->num_core_supplies,
735e6cb7341SCharles Keepax 				       arizona->core_supplies);
736e6cb7341SCharles Keepax 	}
737e6cb7341SCharles Keepax 
7383cc72986SMark Brown 	return 0;
7393cc72986SMark Brown }
7403cc72986SMark Brown #endif
7413cc72986SMark Brown 
742dc781d0eSMark Brown #ifdef CONFIG_PM_SLEEP
74367c99296SMark Brown static int arizona_suspend(struct device *dev)
74467c99296SMark Brown {
74567c99296SMark Brown 	struct arizona *arizona = dev_get_drvdata(dev);
74667c99296SMark Brown 
74767c99296SMark Brown 	dev_dbg(arizona->dev, "Suspend, disabling IRQ\n");
74867c99296SMark Brown 	disable_irq(arizona->irq);
74967c99296SMark Brown 
75067c99296SMark Brown 	return 0;
75167c99296SMark Brown }
75267c99296SMark Brown 
75367c99296SMark Brown static int arizona_suspend_late(struct device *dev)
75467c99296SMark Brown {
75567c99296SMark Brown 	struct arizona *arizona = dev_get_drvdata(dev);
75667c99296SMark Brown 
75767c99296SMark Brown 	dev_dbg(arizona->dev, "Late suspend, reenabling IRQ\n");
75867c99296SMark Brown 	enable_irq(arizona->irq);
75967c99296SMark Brown 
76067c99296SMark Brown 	return 0;
76167c99296SMark Brown }
76267c99296SMark Brown 
763dc781d0eSMark Brown static int arizona_resume_noirq(struct device *dev)
764dc781d0eSMark Brown {
765dc781d0eSMark Brown 	struct arizona *arizona = dev_get_drvdata(dev);
766dc781d0eSMark Brown 
767dc781d0eSMark Brown 	dev_dbg(arizona->dev, "Early resume, disabling IRQ\n");
768dc781d0eSMark Brown 	disable_irq(arizona->irq);
769dc781d0eSMark Brown 
770dc781d0eSMark Brown 	return 0;
771dc781d0eSMark Brown }
772dc781d0eSMark Brown 
773dc781d0eSMark Brown static int arizona_resume(struct device *dev)
774dc781d0eSMark Brown {
775dc781d0eSMark Brown 	struct arizona *arizona = dev_get_drvdata(dev);
776dc781d0eSMark Brown 
777dc781d0eSMark Brown 	dev_dbg(arizona->dev, "Late resume, reenabling IRQ\n");
778dc781d0eSMark Brown 	enable_irq(arizona->irq);
779dc781d0eSMark Brown 
780dc781d0eSMark Brown 	return 0;
781dc781d0eSMark Brown }
782dc781d0eSMark Brown #endif
783dc781d0eSMark Brown 
7843cc72986SMark Brown const struct dev_pm_ops arizona_pm_ops = {
7853cc72986SMark Brown 	SET_RUNTIME_PM_OPS(arizona_runtime_suspend,
7863cc72986SMark Brown 			   arizona_runtime_resume,
7873cc72986SMark Brown 			   NULL)
78867c99296SMark Brown 	SET_SYSTEM_SLEEP_PM_OPS(arizona_suspend, arizona_resume)
789dc781d0eSMark Brown #ifdef CONFIG_PM_SLEEP
79067c99296SMark Brown 	.suspend_late = arizona_suspend_late,
791dc781d0eSMark Brown 	.resume_noirq = arizona_resume_noirq,
792dc781d0eSMark Brown #endif
7933cc72986SMark Brown };
7943cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_pm_ops);
7953cc72986SMark Brown 
796d781009cSMark Brown #ifdef CONFIG_OF
797942786e6SLee Jones unsigned long arizona_of_get_type(struct device *dev)
798d781009cSMark Brown {
799d781009cSMark Brown 	const struct of_device_id *id = of_match_device(arizona_of_match, dev);
800d781009cSMark Brown 
801d781009cSMark Brown 	if (id)
802942786e6SLee Jones 		return (unsigned long)id->data;
803d781009cSMark Brown 	else
804d781009cSMark Brown 		return 0;
805d781009cSMark Brown }
806d781009cSMark Brown EXPORT_SYMBOL_GPL(arizona_of_get_type);
807d781009cSMark Brown 
808e4fcb1d6SCharles Keepax int arizona_of_get_named_gpio(struct arizona *arizona, const char *prop,
809e4fcb1d6SCharles Keepax 			      bool mandatory)
810e4fcb1d6SCharles Keepax {
811e4fcb1d6SCharles Keepax 	int gpio;
812e4fcb1d6SCharles Keepax 
813e4fcb1d6SCharles Keepax 	gpio = of_get_named_gpio(arizona->dev->of_node, prop, 0);
814e4fcb1d6SCharles Keepax 	if (gpio < 0) {
815e4fcb1d6SCharles Keepax 		if (mandatory)
816e4fcb1d6SCharles Keepax 			dev_err(arizona->dev,
817e4fcb1d6SCharles Keepax 				"Mandatory DT gpio %s missing/malformed: %d\n",
818e4fcb1d6SCharles Keepax 				prop, gpio);
819e4fcb1d6SCharles Keepax 
820e4fcb1d6SCharles Keepax 		gpio = 0;
821e4fcb1d6SCharles Keepax 	}
822e4fcb1d6SCharles Keepax 
823e4fcb1d6SCharles Keepax 	return gpio;
824e4fcb1d6SCharles Keepax }
825e4fcb1d6SCharles Keepax EXPORT_SYMBOL_GPL(arizona_of_get_named_gpio);
826e4fcb1d6SCharles Keepax 
827d781009cSMark Brown static int arizona_of_get_core_pdata(struct arizona *arizona)
828d781009cSMark Brown {
829e4fcb1d6SCharles Keepax 	struct arizona_pdata *pdata = &arizona->pdata;
830cc47aed9SInha Song 	struct property *prop;
831cc47aed9SInha Song 	const __be32 *cur;
832cc47aed9SInha Song 	u32 val;
833d781009cSMark Brown 	int ret, i;
834cc47aed9SInha Song 	int count = 0;
835d781009cSMark Brown 
836e4fcb1d6SCharles Keepax 	pdata->reset = arizona_of_get_named_gpio(arizona, "wlf,reset", true);
837d781009cSMark Brown 
838d781009cSMark Brown 	ret = of_property_read_u32_array(arizona->dev->of_node,
839d781009cSMark Brown 					 "wlf,gpio-defaults",
8403762aedeSCharles Keepax 					 pdata->gpio_defaults,
8413762aedeSCharles Keepax 					 ARRAY_SIZE(pdata->gpio_defaults));
842d781009cSMark Brown 	if (ret >= 0) {
843d781009cSMark Brown 		/*
844d781009cSMark Brown 		 * All values are literal except out of range values
845d781009cSMark Brown 		 * which are chip default, translate into platform
846d781009cSMark Brown 		 * data which uses 0 as chip default and out of range
847d781009cSMark Brown 		 * as zero.
848d781009cSMark Brown 		 */
8493762aedeSCharles Keepax 		for (i = 0; i < ARRAY_SIZE(pdata->gpio_defaults); i++) {
8503762aedeSCharles Keepax 			if (pdata->gpio_defaults[i] > 0xffff)
8513762aedeSCharles Keepax 				pdata->gpio_defaults[i] = 0;
8523762aedeSCharles Keepax 			else if (pdata->gpio_defaults[i] == 0)
8533762aedeSCharles Keepax 				pdata->gpio_defaults[i] = 0x10000;
854d781009cSMark Brown 		}
855d781009cSMark Brown 	} else {
856d781009cSMark Brown 		dev_err(arizona->dev, "Failed to parse GPIO defaults: %d\n",
857d781009cSMark Brown 			ret);
858d781009cSMark Brown 	}
859d781009cSMark Brown 
860cc47aed9SInha Song 	of_property_for_each_u32(arizona->dev->of_node, "wlf,inmode", prop,
861cc47aed9SInha Song 				 cur, val) {
8623762aedeSCharles Keepax 		if (count == ARRAY_SIZE(pdata->inmode))
863cc47aed9SInha Song 			break;
864cc47aed9SInha Song 
8653762aedeSCharles Keepax 		pdata->inmode[count] = val;
866cc47aed9SInha Song 		count++;
867cc47aed9SInha Song 	}
868cc47aed9SInha Song 
869e7ad27caSCharles Keepax 	count = 0;
870e7ad27caSCharles Keepax 	of_property_for_each_u32(arizona->dev->of_node, "wlf,dmic-ref", prop,
871e7ad27caSCharles Keepax 				 cur, val) {
8723762aedeSCharles Keepax 		if (count == ARRAY_SIZE(pdata->dmic_ref))
873e7ad27caSCharles Keepax 			break;
874e7ad27caSCharles Keepax 
8753762aedeSCharles Keepax 		pdata->dmic_ref[count] = val;
876e7ad27caSCharles Keepax 		count++;
877e7ad27caSCharles Keepax 	}
878e7ad27caSCharles Keepax 
879f199d393SCharles Keepax 	count = 0;
880f199d393SCharles Keepax 	of_property_for_each_u32(arizona->dev->of_node, "wlf,out-mono", prop,
881f199d393SCharles Keepax 				 cur, val) {
882f199d393SCharles Keepax 		if (count == ARRAY_SIZE(pdata->out_mono))
883f199d393SCharles Keepax 			break;
884f199d393SCharles Keepax 
885f199d393SCharles Keepax 		pdata->out_mono[count] = !!val;
886f199d393SCharles Keepax 		count++;
887f199d393SCharles Keepax 	}
888f199d393SCharles Keepax 
889d781009cSMark Brown 	return 0;
890d781009cSMark Brown }
891d781009cSMark Brown 
892d781009cSMark Brown const struct of_device_id arizona_of_match[] = {
893d781009cSMark Brown 	{ .compatible = "wlf,wm5102", .data = (void *)WM5102 },
894d781009cSMark Brown 	{ .compatible = "wlf,wm5110", .data = (void *)WM5110 },
895e5d4ef0dSRichard Fitzgerald 	{ .compatible = "wlf,wm8280", .data = (void *)WM8280 },
896dc7d4863SCharles Keepax 	{ .compatible = "wlf,wm8997", .data = (void *)WM8997 },
8976887b042SRichard Fitzgerald 	{ .compatible = "wlf,wm8998", .data = (void *)WM8998 },
8986887b042SRichard Fitzgerald 	{ .compatible = "wlf,wm1814", .data = (void *)WM1814 },
899ea1f3339SRichard Fitzgerald 	{ .compatible = "wlf,wm1831", .data = (void *)WM1831 },
900ea1f3339SRichard Fitzgerald 	{ .compatible = "cirrus,cs47l24", .data = (void *)CS47L24 },
901d781009cSMark Brown 	{},
902d781009cSMark Brown };
903d781009cSMark Brown EXPORT_SYMBOL_GPL(arizona_of_match);
904d781009cSMark Brown #else
905d781009cSMark Brown static inline int arizona_of_get_core_pdata(struct arizona *arizona)
906d781009cSMark Brown {
907d781009cSMark Brown 	return 0;
908d781009cSMark Brown }
909d781009cSMark Brown #endif
910d781009cSMark Brown 
9115ac98553SGeert Uytterhoeven static const struct mfd_cell early_devs[] = {
9123cc72986SMark Brown 	{ .name = "arizona-ldo1" },
9133cc72986SMark Brown };
9143cc72986SMark Brown 
9153762aedeSCharles Keepax static const char * const wm5102_supplies[] = {
9165fc6c396SCharles Keepax 	"MICVDD",
91732dadef2SCharles Keepax 	"DBVDD2",
91832dadef2SCharles Keepax 	"DBVDD3",
91932dadef2SCharles Keepax 	"CPVDD",
92032dadef2SCharles Keepax 	"SPKVDDL",
92132dadef2SCharles Keepax 	"SPKVDDR",
92232dadef2SCharles Keepax };
92332dadef2SCharles Keepax 
9245ac98553SGeert Uytterhoeven static const struct mfd_cell wm5102_devs[] = {
925d7768111SMark Brown 	{ .name = "arizona-micsupp" },
926f83c218cSCharles Keepax 	{ .name = "arizona-gpio" },
9275fc6c396SCharles Keepax 	{
9285fc6c396SCharles Keepax 		.name = "arizona-extcon",
9295fc6c396SCharles Keepax 		.parent_supplies = wm5102_supplies,
9305fc6c396SCharles Keepax 		.num_parent_supplies = 1, /* We only need MICVDD */
9315fc6c396SCharles Keepax 	},
932503b1cacSMark Brown 	{ .name = "arizona-haptics" },
9333cc72986SMark Brown 	{ .name = "arizona-pwm" },
93432dadef2SCharles Keepax 	{
93532dadef2SCharles Keepax 		.name = "wm5102-codec",
93632dadef2SCharles Keepax 		.parent_supplies = wm5102_supplies,
93732dadef2SCharles Keepax 		.num_parent_supplies = ARRAY_SIZE(wm5102_supplies),
93832dadef2SCharles Keepax 	},
9393cc72986SMark Brown };
9403cc72986SMark Brown 
9415ac98553SGeert Uytterhoeven static const struct mfd_cell wm5110_devs[] = {
942d7768111SMark Brown 	{ .name = "arizona-micsupp" },
943f83c218cSCharles Keepax 	{ .name = "arizona-gpio" },
9445fc6c396SCharles Keepax 	{
9455fc6c396SCharles Keepax 		.name = "arizona-extcon",
9465fc6c396SCharles Keepax 		.parent_supplies = wm5102_supplies,
9475fc6c396SCharles Keepax 		.num_parent_supplies = 1, /* We only need MICVDD */
9485fc6c396SCharles Keepax 	},
949503b1cacSMark Brown 	{ .name = "arizona-haptics" },
950e102befeSMark Brown 	{ .name = "arizona-pwm" },
95132dadef2SCharles Keepax 	{
95232dadef2SCharles Keepax 		.name = "wm5110-codec",
95332dadef2SCharles Keepax 		.parent_supplies = wm5102_supplies,
95432dadef2SCharles Keepax 		.num_parent_supplies = ARRAY_SIZE(wm5102_supplies),
95532dadef2SCharles Keepax 	},
95632dadef2SCharles Keepax };
95732dadef2SCharles Keepax 
958ea1f3339SRichard Fitzgerald static const char * const cs47l24_supplies[] = {
959ea1f3339SRichard Fitzgerald 	"MICVDD",
960ea1f3339SRichard Fitzgerald 	"CPVDD",
961ea1f3339SRichard Fitzgerald 	"SPKVDD",
962ea1f3339SRichard Fitzgerald };
963ea1f3339SRichard Fitzgerald 
964ea1f3339SRichard Fitzgerald static const struct mfd_cell cs47l24_devs[] = {
965ea1f3339SRichard Fitzgerald 	{ .name = "arizona-gpio" },
966ea1f3339SRichard Fitzgerald 	{ .name = "arizona-haptics" },
967ea1f3339SRichard Fitzgerald 	{ .name = "arizona-pwm" },
968ea1f3339SRichard Fitzgerald 	{
969ea1f3339SRichard Fitzgerald 		.name = "cs47l24-codec",
970ea1f3339SRichard Fitzgerald 		.parent_supplies = cs47l24_supplies,
971ea1f3339SRichard Fitzgerald 		.num_parent_supplies = ARRAY_SIZE(cs47l24_supplies),
972ea1f3339SRichard Fitzgerald 	},
973ea1f3339SRichard Fitzgerald };
974ea1f3339SRichard Fitzgerald 
9753762aedeSCharles Keepax static const char * const wm8997_supplies[] = {
976996c2d4fSCharles Keepax 	"MICVDD",
97732dadef2SCharles Keepax 	"DBVDD2",
97832dadef2SCharles Keepax 	"CPVDD",
97932dadef2SCharles Keepax 	"SPKVDD",
980e102befeSMark Brown };
981e102befeSMark Brown 
9825ac98553SGeert Uytterhoeven static const struct mfd_cell wm8997_devs[] = {
983dc7d4863SCharles Keepax 	{ .name = "arizona-micsupp" },
984f83c218cSCharles Keepax 	{ .name = "arizona-gpio" },
9855fc6c396SCharles Keepax 	{
9865fc6c396SCharles Keepax 		.name = "arizona-extcon",
9875fc6c396SCharles Keepax 		.parent_supplies = wm8997_supplies,
9885fc6c396SCharles Keepax 		.num_parent_supplies = 1, /* We only need MICVDD */
9895fc6c396SCharles Keepax 	},
990dc7d4863SCharles Keepax 	{ .name = "arizona-haptics" },
991dc7d4863SCharles Keepax 	{ .name = "arizona-pwm" },
99232dadef2SCharles Keepax 	{
99332dadef2SCharles Keepax 		.name = "wm8997-codec",
99432dadef2SCharles Keepax 		.parent_supplies = wm8997_supplies,
99532dadef2SCharles Keepax 		.num_parent_supplies = ARRAY_SIZE(wm8997_supplies),
99632dadef2SCharles Keepax 	},
997dc7d4863SCharles Keepax };
998dc7d4863SCharles Keepax 
9996887b042SRichard Fitzgerald static const struct mfd_cell wm8998_devs[] = {
1000f83c218cSCharles Keepax 	{ .name = "arizona-micsupp" },
1001f83c218cSCharles Keepax 	{ .name = "arizona-gpio" },
10026887b042SRichard Fitzgerald 	{
10036887b042SRichard Fitzgerald 		.name = "arizona-extcon",
10046887b042SRichard Fitzgerald 		.parent_supplies = wm5102_supplies,
10056887b042SRichard Fitzgerald 		.num_parent_supplies = 1, /* We only need MICVDD */
10066887b042SRichard Fitzgerald 	},
10076887b042SRichard Fitzgerald 	{ .name = "arizona-haptics" },
10086887b042SRichard Fitzgerald 	{ .name = "arizona-pwm" },
10096887b042SRichard Fitzgerald 	{
10106887b042SRichard Fitzgerald 		.name = "wm8998-codec",
10116887b042SRichard Fitzgerald 		.parent_supplies = wm5102_supplies,
10126887b042SRichard Fitzgerald 		.num_parent_supplies = ARRAY_SIZE(wm5102_supplies),
10136887b042SRichard Fitzgerald 	},
10146887b042SRichard Fitzgerald };
10156887b042SRichard Fitzgerald 
1016f791be49SBill Pemberton int arizona_dev_init(struct arizona *arizona)
10173cc72986SMark Brown {
1018*cdd8da8cSSylwester Nawrocki 	const char * const mclk_name[] = { "mclk1", "mclk2" };
10193cc72986SMark Brown 	struct device *dev = arizona->dev;
1020ea1f3339SRichard Fitzgerald 	const char *type_name = NULL;
10216887b042SRichard Fitzgerald 	unsigned int reg, val, mask;
102262d62b59SMark Brown 	int (*apply_patch)(struct arizona *) = NULL;
1023ae05ea36SRichard Fitzgerald 	const struct mfd_cell *subdevs = NULL;
1024ae05ea36SRichard Fitzgerald 	int n_subdevs, ret, i;
10253cc72986SMark Brown 
10263cc72986SMark Brown 	dev_set_drvdata(arizona->dev, arizona);
10273cc72986SMark Brown 	mutex_init(&arizona->clk_lock);
10283cc72986SMark Brown 
10293cc72986SMark Brown 	if (dev_get_platdata(arizona->dev))
10303cc72986SMark Brown 		memcpy(&arizona->pdata, dev_get_platdata(arizona->dev),
10313cc72986SMark Brown 		       sizeof(arizona->pdata));
103222d7dc8aSLee Jones 	else
103322d7dc8aSLee Jones 		arizona_of_get_core_pdata(arizona);
10343cc72986SMark Brown 
1035*cdd8da8cSSylwester Nawrocki 	BUILD_BUG_ON(ARRAY_SIZE(arizona->mclk) != ARRAY_SIZE(mclk_name));
1036*cdd8da8cSSylwester Nawrocki 	for (i = 0; i < ARRAY_SIZE(arizona->mclk); i++) {
1037*cdd8da8cSSylwester Nawrocki 		arizona->mclk[i] = devm_clk_get(arizona->dev, mclk_name[i]);
1038*cdd8da8cSSylwester Nawrocki 		if (IS_ERR(arizona->mclk[i])) {
1039*cdd8da8cSSylwester Nawrocki 			dev_info(arizona->dev, "Failed to get %s: %ld\n",
1040*cdd8da8cSSylwester Nawrocki 				 mclk_name[i], PTR_ERR(arizona->mclk[i]));
1041*cdd8da8cSSylwester Nawrocki 			arizona->mclk[i] = NULL;
1042*cdd8da8cSSylwester Nawrocki 		}
1043*cdd8da8cSSylwester Nawrocki 	}
1044*cdd8da8cSSylwester Nawrocki 
10453cc72986SMark Brown 	regcache_cache_only(arizona->regmap, true);
10463cc72986SMark Brown 
10473cc72986SMark Brown 	switch (arizona->type) {
10483cc72986SMark Brown 	case WM5102:
1049e102befeSMark Brown 	case WM5110:
1050e5d4ef0dSRichard Fitzgerald 	case WM8280:
1051dc7d4863SCharles Keepax 	case WM8997:
10526887b042SRichard Fitzgerald 	case WM8998:
10536887b042SRichard Fitzgerald 	case WM1814:
1054ea1f3339SRichard Fitzgerald 	case WM1831:
1055ea1f3339SRichard Fitzgerald 	case CS47L24:
10563cc72986SMark Brown 		for (i = 0; i < ARRAY_SIZE(wm5102_core_supplies); i++)
10573cc72986SMark Brown 			arizona->core_supplies[i].supply
10583cc72986SMark Brown 				= wm5102_core_supplies[i];
10593cc72986SMark Brown 		arizona->num_core_supplies = ARRAY_SIZE(wm5102_core_supplies);
10603cc72986SMark Brown 		break;
10613cc72986SMark Brown 	default:
10623cc72986SMark Brown 		dev_err(arizona->dev, "Unknown device type %d\n",
10633cc72986SMark Brown 			arizona->type);
10643cc72986SMark Brown 		return -EINVAL;
10653cc72986SMark Brown 	}
10663cc72986SMark Brown 
10674a8c475fSCharles Keepax 	/* Mark DCVDD as external, LDO1 driver will clear if internal */
10684a8c475fSCharles Keepax 	arizona->external_dcvdd = true;
10694a8c475fSCharles Keepax 
1070ea1f3339SRichard Fitzgerald 	switch (arizona->type) {
1071ea1f3339SRichard Fitzgerald 	case WM1831:
1072ea1f3339SRichard Fitzgerald 	case CS47L24:
1073ea1f3339SRichard Fitzgerald 		break; /* No LDO1 regulator */
1074ea1f3339SRichard Fitzgerald 	default:
10753cc72986SMark Brown 		ret = mfd_add_devices(arizona->dev, -1, early_devs,
10760848c94fSMark Brown 				      ARRAY_SIZE(early_devs), NULL, 0, NULL);
10773cc72986SMark Brown 		if (ret != 0) {
10783cc72986SMark Brown 			dev_err(dev, "Failed to add early children: %d\n", ret);
10793cc72986SMark Brown 			return ret;
10803cc72986SMark Brown 		}
1081ea1f3339SRichard Fitzgerald 		break;
1082ea1f3339SRichard Fitzgerald 	}
10833cc72986SMark Brown 
10843cc72986SMark Brown 	ret = devm_regulator_bulk_get(dev, arizona->num_core_supplies,
10853cc72986SMark Brown 				      arizona->core_supplies);
10863cc72986SMark Brown 	if (ret != 0) {
10873cc72986SMark Brown 		dev_err(dev, "Failed to request core supplies: %d\n",
10883cc72986SMark Brown 			ret);
10893cc72986SMark Brown 		goto err_early;
10903cc72986SMark Brown 	}
10913cc72986SMark Brown 
10920c2d0ffbSCharles Keepax 	/**
10930c2d0ffbSCharles Keepax 	 * Don't use devres here because the only device we have to get
10940c2d0ffbSCharles Keepax 	 * against is the MFD device and DCVDD will likely be supplied by
10950c2d0ffbSCharles Keepax 	 * one of its children. Meaning that the regulator will be
10960c2d0ffbSCharles Keepax 	 * destroyed by the time devres calls regulator put.
10970c2d0ffbSCharles Keepax 	 */
1098e6021511SCharles Keepax 	arizona->dcvdd = regulator_get(arizona->dev, "DCVDD");
109959db9691SMark Brown 	if (IS_ERR(arizona->dcvdd)) {
110059db9691SMark Brown 		ret = PTR_ERR(arizona->dcvdd);
110159db9691SMark Brown 		dev_err(dev, "Failed to request DCVDD: %d\n", ret);
110259db9691SMark Brown 		goto err_early;
110359db9691SMark Brown 	}
110459db9691SMark Brown 
110587d3af4aSMark Brown 	if (arizona->pdata.reset) {
110687d3af4aSMark Brown 		/* Start out with /RESET low to put the chip into reset */
11075f056bf0SCharles Keepax 		ret = devm_gpio_request_one(arizona->dev, arizona->pdata.reset,
110887d3af4aSMark Brown 					    GPIOF_DIR_OUT | GPIOF_INIT_LOW,
110987d3af4aSMark Brown 					    "arizona /RESET");
111087d3af4aSMark Brown 		if (ret != 0) {
111187d3af4aSMark Brown 			dev_err(dev, "Failed to request /RESET: %d\n", ret);
1112e6021511SCharles Keepax 			goto err_dcvdd;
111387d3af4aSMark Brown 		}
111487d3af4aSMark Brown 	}
111587d3af4aSMark Brown 
11163cc72986SMark Brown 	ret = regulator_bulk_enable(arizona->num_core_supplies,
11173cc72986SMark Brown 				    arizona->core_supplies);
11183cc72986SMark Brown 	if (ret != 0) {
11193cc72986SMark Brown 		dev_err(dev, "Failed to enable core supplies: %d\n",
11203cc72986SMark Brown 			ret);
1121e6021511SCharles Keepax 		goto err_dcvdd;
11223cc72986SMark Brown 	}
11233cc72986SMark Brown 
112459db9691SMark Brown 	ret = regulator_enable(arizona->dcvdd);
112559db9691SMark Brown 	if (ret != 0) {
112659db9691SMark Brown 		dev_err(dev, "Failed to enable DCVDD: %d\n", ret);
112759db9691SMark Brown 		goto err_enable;
112859db9691SMark Brown 	}
112959db9691SMark Brown 
11302229875dSCharles Keepax 	arizona_disable_reset(arizona);
11313cc72986SMark Brown 
11323cc72986SMark Brown 	regcache_cache_only(arizona->regmap, false);
11333cc72986SMark Brown 
1134ca76ceb8SMark Brown 	/* Verify that this is a chip we know about */
1135ca76ceb8SMark Brown 	ret = regmap_read(arizona->regmap, ARIZONA_SOFTWARE_RESET, &reg);
1136ca76ceb8SMark Brown 	if (ret != 0) {
1137ca76ceb8SMark Brown 		dev_err(dev, "Failed to read ID register: %d\n", ret);
1138ca76ceb8SMark Brown 		goto err_reset;
1139ca76ceb8SMark Brown 	}
1140ca76ceb8SMark Brown 
1141ca76ceb8SMark Brown 	switch (reg) {
1142ca76ceb8SMark Brown 	case 0x5102:
1143ca76ceb8SMark Brown 	case 0x5110:
11446887b042SRichard Fitzgerald 	case 0x6349:
1145ea1f3339SRichard Fitzgerald 	case 0x6363:
1146dc7d4863SCharles Keepax 	case 0x8997:
1147ca76ceb8SMark Brown 		break;
1148ca76ceb8SMark Brown 	default:
1149ca76ceb8SMark Brown 		dev_err(arizona->dev, "Unknown device ID: %x\n", reg);
1150ca76ceb8SMark Brown 		goto err_reset;
1151ca76ceb8SMark Brown 	}
1152ca76ceb8SMark Brown 
1153ca76ceb8SMark Brown 	/* If we have a /RESET GPIO we'll already be reset */
1154ca76ceb8SMark Brown 	if (!arizona->pdata.reset) {
1155ca76ceb8SMark Brown 		ret = regmap_write(arizona->regmap, ARIZONA_SOFTWARE_RESET, 0);
1156ca76ceb8SMark Brown 		if (ret != 0) {
1157ca76ceb8SMark Brown 			dev_err(dev, "Failed to reset device: %d\n", ret);
1158ca76ceb8SMark Brown 			goto err_reset;
1159ca76ceb8SMark Brown 		}
1160ca76ceb8SMark Brown 
1161b79a980fSLee Jones 		usleep_range(1000, 5000);
1162ca76ceb8SMark Brown 	}
1163ca76ceb8SMark Brown 
1164ca76ceb8SMark Brown 	/* Ensure device startup is complete */
1165ca76ceb8SMark Brown 	switch (arizona->type) {
1166ca76ceb8SMark Brown 	case WM5102:
116748018943SMark Brown 		ret = regmap_read(arizona->regmap,
116848018943SMark Brown 				  ARIZONA_WRITE_SEQUENCER_CTRL_3, &val);
11691c1c6bbaSCharles Keepax 		if (ret) {
1170ca76ceb8SMark Brown 			dev_err(dev,
1171ca76ceb8SMark Brown 				"Failed to check write sequencer state: %d\n",
1172ca76ceb8SMark Brown 				ret);
11731c1c6bbaSCharles Keepax 		} else if (val & 0x01) {
11741c1c6bbaSCharles Keepax 			ret = wm5102_clear_write_sequencer(arizona);
11751c1c6bbaSCharles Keepax 			if (ret)
11761c1c6bbaSCharles Keepax 				return ret;
1177ca76ceb8SMark Brown 		}
1178ca76ceb8SMark Brown 		break;
11791c1c6bbaSCharles Keepax 	default:
11801c1c6bbaSCharles Keepax 		break;
11811c1c6bbaSCharles Keepax 	}
11821c1c6bbaSCharles Keepax 
11831c1c6bbaSCharles Keepax 	ret = arizona_wait_for_boot(arizona);
11841c1c6bbaSCharles Keepax 	if (ret) {
11851c1c6bbaSCharles Keepax 		dev_err(arizona->dev, "Device failed initial boot: %d\n", ret);
11861c1c6bbaSCharles Keepax 		goto err_reset;
1187ca76ceb8SMark Brown 	}
1188ca76ceb8SMark Brown 
1189ca76ceb8SMark Brown 	/* Read the device ID information & do device specific stuff */
11903cc72986SMark Brown 	ret = regmap_read(arizona->regmap, ARIZONA_SOFTWARE_RESET, &reg);
11913cc72986SMark Brown 	if (ret != 0) {
11923cc72986SMark Brown 		dev_err(dev, "Failed to read ID register: %d\n", ret);
119359db9691SMark Brown 		goto err_reset;
11943cc72986SMark Brown 	}
11953cc72986SMark Brown 
11963cc72986SMark Brown 	ret = regmap_read(arizona->regmap, ARIZONA_DEVICE_REVISION,
11973cc72986SMark Brown 			  &arizona->rev);
11983cc72986SMark Brown 	if (ret != 0) {
11993cc72986SMark Brown 		dev_err(dev, "Failed to read revision register: %d\n", ret);
120059db9691SMark Brown 		goto err_reset;
12013cc72986SMark Brown 	}
12023cc72986SMark Brown 	arizona->rev &= ARIZONA_DEVICE_REVISION_MASK;
12033cc72986SMark Brown 
12043cc72986SMark Brown 	switch (reg) {
12053cc72986SMark Brown 	case 0x5102:
1206b61c1ec0SRichard Fitzgerald 		if (IS_ENABLED(CONFIG_MFD_WM5102)) {
12073cc72986SMark Brown 			type_name = "WM5102";
12083cc72986SMark Brown 			if (arizona->type != WM5102) {
1209b61c1ec0SRichard Fitzgerald 				dev_warn(arizona->dev,
1210b61c1ec0SRichard Fitzgerald 					 "WM5102 registered as %d\n",
12113cc72986SMark Brown 					 arizona->type);
12123cc72986SMark Brown 				arizona->type = WM5102;
12133cc72986SMark Brown 			}
1214b61c1ec0SRichard Fitzgerald 
121562d62b59SMark Brown 			apply_patch = wm5102_patch;
1216c6d6bfb1SMark Brown 			arizona->rev &= 0x7;
1217ae05ea36SRichard Fitzgerald 			subdevs = wm5102_devs;
1218ae05ea36SRichard Fitzgerald 			n_subdevs = ARRAY_SIZE(wm5102_devs);
1219b61c1ec0SRichard Fitzgerald 		}
12203cc72986SMark Brown 		break;
1221e102befeSMark Brown 	case 0x5110:
1222b61c1ec0SRichard Fitzgerald 		if (IS_ENABLED(CONFIG_MFD_WM5110)) {
1223e5d4ef0dSRichard Fitzgerald 			switch (arizona->type) {
1224e5d4ef0dSRichard Fitzgerald 			case WM5110:
1225e102befeSMark Brown 				type_name = "WM5110";
1226e5d4ef0dSRichard Fitzgerald 				break;
1227e5d4ef0dSRichard Fitzgerald 			case WM8280:
1228e5d4ef0dSRichard Fitzgerald 				type_name = "WM8280";
1229e5d4ef0dSRichard Fitzgerald 				break;
1230e5d4ef0dSRichard Fitzgerald 			default:
1231e5d4ef0dSRichard Fitzgerald 				type_name = "WM5110";
1232b61c1ec0SRichard Fitzgerald 				dev_warn(arizona->dev,
1233b61c1ec0SRichard Fitzgerald 					 "WM5110 registered as %d\n",
1234e102befeSMark Brown 					 arizona->type);
1235e102befeSMark Brown 				arizona->type = WM5110;
1236e5d4ef0dSRichard Fitzgerald 				break;
1237e102befeSMark Brown 			}
1238b61c1ec0SRichard Fitzgerald 
123962d62b59SMark Brown 			apply_patch = wm5110_patch;
1240ae05ea36SRichard Fitzgerald 			subdevs = wm5110_devs;
1241ae05ea36SRichard Fitzgerald 			n_subdevs = ARRAY_SIZE(wm5110_devs);
1242b61c1ec0SRichard Fitzgerald 		}
1243e102befeSMark Brown 		break;
1244ea1f3339SRichard Fitzgerald 	case 0x6363:
1245ea1f3339SRichard Fitzgerald 		if (IS_ENABLED(CONFIG_MFD_CS47L24)) {
1246ea1f3339SRichard Fitzgerald 			switch (arizona->type) {
1247ea1f3339SRichard Fitzgerald 			case CS47L24:
1248ea1f3339SRichard Fitzgerald 				type_name = "CS47L24";
1249ea1f3339SRichard Fitzgerald 				break;
1250ea1f3339SRichard Fitzgerald 
1251ea1f3339SRichard Fitzgerald 			case WM1831:
1252ea1f3339SRichard Fitzgerald 				type_name = "WM1831";
1253ea1f3339SRichard Fitzgerald 				break;
1254ea1f3339SRichard Fitzgerald 
1255ea1f3339SRichard Fitzgerald 			default:
1256ea1f3339SRichard Fitzgerald 				dev_warn(arizona->dev,
1257ea1f3339SRichard Fitzgerald 					 "CS47L24 registered as %d\n",
1258ea1f3339SRichard Fitzgerald 					 arizona->type);
1259ea1f3339SRichard Fitzgerald 				arizona->type = CS47L24;
1260ea1f3339SRichard Fitzgerald 				break;
1261ea1f3339SRichard Fitzgerald 			}
1262ea1f3339SRichard Fitzgerald 
1263ea1f3339SRichard Fitzgerald 			apply_patch = cs47l24_patch;
1264ea1f3339SRichard Fitzgerald 			subdevs = cs47l24_devs;
1265ea1f3339SRichard Fitzgerald 			n_subdevs = ARRAY_SIZE(cs47l24_devs);
1266ea1f3339SRichard Fitzgerald 		}
1267ea1f3339SRichard Fitzgerald 		break;
1268dc7d4863SCharles Keepax 	case 0x8997:
1269b61c1ec0SRichard Fitzgerald 		if (IS_ENABLED(CONFIG_MFD_WM8997)) {
1270dc7d4863SCharles Keepax 			type_name = "WM8997";
1271dc7d4863SCharles Keepax 			if (arizona->type != WM8997) {
1272b61c1ec0SRichard Fitzgerald 				dev_warn(arizona->dev,
1273b61c1ec0SRichard Fitzgerald 					 "WM8997 registered as %d\n",
1274dc7d4863SCharles Keepax 					 arizona->type);
1275dc7d4863SCharles Keepax 				arizona->type = WM8997;
1276dc7d4863SCharles Keepax 			}
1277b61c1ec0SRichard Fitzgerald 
1278dc7d4863SCharles Keepax 			apply_patch = wm8997_patch;
1279ae05ea36SRichard Fitzgerald 			subdevs = wm8997_devs;
1280ae05ea36SRichard Fitzgerald 			n_subdevs = ARRAY_SIZE(wm8997_devs);
1281b61c1ec0SRichard Fitzgerald 		}
1282dc7d4863SCharles Keepax 		break;
12836887b042SRichard Fitzgerald 	case 0x6349:
1284b61c1ec0SRichard Fitzgerald 		if (IS_ENABLED(CONFIG_MFD_WM8998)) {
12856887b042SRichard Fitzgerald 			switch (arizona->type) {
12866887b042SRichard Fitzgerald 			case WM8998:
12876887b042SRichard Fitzgerald 				type_name = "WM8998";
12886887b042SRichard Fitzgerald 				break;
12896887b042SRichard Fitzgerald 
12906887b042SRichard Fitzgerald 			case WM1814:
12916887b042SRichard Fitzgerald 				type_name = "WM1814";
12926887b042SRichard Fitzgerald 				break;
12936887b042SRichard Fitzgerald 
12946887b042SRichard Fitzgerald 			default:
12956887b042SRichard Fitzgerald 				type_name = "WM8998";
1296b61c1ec0SRichard Fitzgerald 				dev_warn(arizona->dev,
1297b61c1ec0SRichard Fitzgerald 					 "WM8998 registered as %d\n",
12986887b042SRichard Fitzgerald 					 arizona->type);
12996887b042SRichard Fitzgerald 				arizona->type = WM8998;
13006887b042SRichard Fitzgerald 			}
13016887b042SRichard Fitzgerald 
13026887b042SRichard Fitzgerald 			apply_patch = wm8998_patch;
1303ae05ea36SRichard Fitzgerald 			subdevs = wm8998_devs;
1304ae05ea36SRichard Fitzgerald 			n_subdevs = ARRAY_SIZE(wm8998_devs);
1305b61c1ec0SRichard Fitzgerald 		}
13066887b042SRichard Fitzgerald 		break;
13073cc72986SMark Brown 	default:
13083cc72986SMark Brown 		dev_err(arizona->dev, "Unknown device ID %x\n", reg);
130959db9691SMark Brown 		goto err_reset;
13103cc72986SMark Brown 	}
13113cc72986SMark Brown 
1312b61c1ec0SRichard Fitzgerald 	if (!subdevs) {
1313b61c1ec0SRichard Fitzgerald 		dev_err(arizona->dev,
1314b61c1ec0SRichard Fitzgerald 			"No kernel support for device ID %x\n", reg);
1315b61c1ec0SRichard Fitzgerald 		goto err_reset;
1316b61c1ec0SRichard Fitzgerald 	}
1317b61c1ec0SRichard Fitzgerald 
13183cc72986SMark Brown 	dev_info(dev, "%s revision %c\n", type_name, arizona->rev + 'A');
13193cc72986SMark Brown 
132062d62b59SMark Brown 	if (apply_patch) {
132162d62b59SMark Brown 		ret = apply_patch(arizona);
132262d62b59SMark Brown 		if (ret != 0) {
132362d62b59SMark Brown 			dev_err(arizona->dev, "Failed to apply patch: %d\n",
132462d62b59SMark Brown 				ret);
132562d62b59SMark Brown 			goto err_reset;
132662d62b59SMark Brown 		}
1327e80436bbSCharles Keepax 
1328e80436bbSCharles Keepax 		switch (arizona->type) {
1329e80436bbSCharles Keepax 		case WM5102:
13300be068a0SCharles Keepax 			ret = wm5102_apply_hardware_patch(arizona);
13310be068a0SCharles Keepax 			if (ret) {
1332e80436bbSCharles Keepax 				dev_err(arizona->dev,
1333e80436bbSCharles Keepax 					"Failed to apply hardware patch: %d\n",
1334e80436bbSCharles Keepax 					ret);
1335e80436bbSCharles Keepax 				goto err_reset;
1336e80436bbSCharles Keepax 			}
1337e80436bbSCharles Keepax 			break;
1338882bc468SCharles Keepax 		case WM5110:
1339882bc468SCharles Keepax 		case WM8280:
1340882bc468SCharles Keepax 			ret = wm5110_apply_sleep_patch(arizona);
1341882bc468SCharles Keepax 			if (ret) {
1342882bc468SCharles Keepax 				dev_err(arizona->dev,
1343882bc468SCharles Keepax 					"Failed to apply sleep patch: %d\n",
1344882bc468SCharles Keepax 					ret);
1345882bc468SCharles Keepax 				goto err_reset;
1346882bc468SCharles Keepax 			}
1347882bc468SCharles Keepax 			break;
1348e80436bbSCharles Keepax 		default:
1349e80436bbSCharles Keepax 			break;
1350e80436bbSCharles Keepax 		}
135162d62b59SMark Brown 	}
135262d62b59SMark Brown 
13533cc72986SMark Brown 	for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) {
13543cc72986SMark Brown 		if (!arizona->pdata.gpio_defaults[i])
13553cc72986SMark Brown 			continue;
13563cc72986SMark Brown 
13573cc72986SMark Brown 		regmap_write(arizona->regmap, ARIZONA_GPIO1_CTRL + i,
13583cc72986SMark Brown 			     arizona->pdata.gpio_defaults[i]);
13593cc72986SMark Brown 	}
13603cc72986SMark Brown 
13613cc72986SMark Brown 	/* Chip default */
13623cc72986SMark Brown 	if (!arizona->pdata.clk32k_src)
13633cc72986SMark Brown 		arizona->pdata.clk32k_src = ARIZONA_32KZ_MCLK2;
13643cc72986SMark Brown 
13653cc72986SMark Brown 	switch (arizona->pdata.clk32k_src) {
13663cc72986SMark Brown 	case ARIZONA_32KZ_MCLK1:
13673cc72986SMark Brown 	case ARIZONA_32KZ_MCLK2:
13683cc72986SMark Brown 		regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1,
13693cc72986SMark Brown 				   ARIZONA_CLK_32K_SRC_MASK,
13703cc72986SMark Brown 				   arizona->pdata.clk32k_src - 1);
1371767c6dc0SMark Brown 		arizona_clk32k_enable(arizona);
13723cc72986SMark Brown 		break;
13733cc72986SMark Brown 	case ARIZONA_32KZ_NONE:
13743cc72986SMark Brown 		regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1,
13753cc72986SMark Brown 				   ARIZONA_CLK_32K_SRC_MASK, 2);
13763cc72986SMark Brown 		break;
13773cc72986SMark Brown 	default:
13783cc72986SMark Brown 		dev_err(arizona->dev, "Invalid 32kHz clock source: %d\n",
13793cc72986SMark Brown 			arizona->pdata.clk32k_src);
13803cc72986SMark Brown 		ret = -EINVAL;
138159db9691SMark Brown 		goto err_reset;
13823cc72986SMark Brown 	}
13833cc72986SMark Brown 
13843d91f828SMark Brown 	for (i = 0; i < ARIZONA_MAX_MICBIAS; i++) {
1385544c7aadSMark Brown 		if (!arizona->pdata.micbias[i].mV &&
1386544c7aadSMark Brown 		    !arizona->pdata.micbias[i].bypass)
13873d91f828SMark Brown 			continue;
13883d91f828SMark Brown 
1389544c7aadSMark Brown 		/* Apply default for bypass mode */
1390544c7aadSMark Brown 		if (!arizona->pdata.micbias[i].mV)
1391544c7aadSMark Brown 			arizona->pdata.micbias[i].mV = 2800;
1392544c7aadSMark Brown 
13933d91f828SMark Brown 		val = (arizona->pdata.micbias[i].mV - 1500) / 100;
1394544c7aadSMark Brown 
13953d91f828SMark Brown 		val <<= ARIZONA_MICB1_LVL_SHIFT;
13963d91f828SMark Brown 
13973d91f828SMark Brown 		if (arizona->pdata.micbias[i].ext_cap)
13983d91f828SMark Brown 			val |= ARIZONA_MICB1_EXT_CAP;
13993d91f828SMark Brown 
14003d91f828SMark Brown 		if (arizona->pdata.micbias[i].discharge)
14013d91f828SMark Brown 			val |= ARIZONA_MICB1_DISCH;
14023d91f828SMark Brown 
1403f773fc6dSCharles Keepax 		if (arizona->pdata.micbias[i].soft_start)
14043d91f828SMark Brown 			val |= ARIZONA_MICB1_RATE;
14053d91f828SMark Brown 
1406544c7aadSMark Brown 		if (arizona->pdata.micbias[i].bypass)
1407544c7aadSMark Brown 			val |= ARIZONA_MICB1_BYPASS;
1408544c7aadSMark Brown 
14093d91f828SMark Brown 		regmap_update_bits(arizona->regmap,
14103d91f828SMark Brown 				   ARIZONA_MIC_BIAS_CTRL_1 + i,
14113d91f828SMark Brown 				   ARIZONA_MICB1_LVL_MASK |
141271d134b9SCharles Keepax 				   ARIZONA_MICB1_EXT_CAP |
14133d91f828SMark Brown 				   ARIZONA_MICB1_DISCH |
1414544c7aadSMark Brown 				   ARIZONA_MICB1_BYPASS |
14153d91f828SMark Brown 				   ARIZONA_MICB1_RATE, val);
14163d91f828SMark Brown 	}
14173d91f828SMark Brown 
14183cc72986SMark Brown 	for (i = 0; i < ARIZONA_MAX_INPUT; i++) {
14193cc72986SMark Brown 		/* Default for both is 0 so noop with defaults */
14203cc72986SMark Brown 		val = arizona->pdata.dmic_ref[i]
14213cc72986SMark Brown 			<< ARIZONA_IN1_DMIC_SUP_SHIFT;
1422fc027d13SRichard Fitzgerald 		if (arizona->pdata.inmode[i] & ARIZONA_INMODE_DMIC)
1423fc027d13SRichard Fitzgerald 			val |= 1 << ARIZONA_IN1_MODE_SHIFT;
14246887b042SRichard Fitzgerald 
14256887b042SRichard Fitzgerald 		switch (arizona->type) {
14266887b042SRichard Fitzgerald 		case WM8998:
14276887b042SRichard Fitzgerald 		case WM1814:
14286887b042SRichard Fitzgerald 			regmap_update_bits(arizona->regmap,
14296887b042SRichard Fitzgerald 				ARIZONA_ADC_DIGITAL_VOLUME_1L + (i * 8),
14306887b042SRichard Fitzgerald 				ARIZONA_IN1L_SRC_SE_MASK,
14316887b042SRichard Fitzgerald 				(arizona->pdata.inmode[i] & ARIZONA_INMODE_SE)
14326887b042SRichard Fitzgerald 					<< ARIZONA_IN1L_SRC_SE_SHIFT);
14336887b042SRichard Fitzgerald 
14346887b042SRichard Fitzgerald 			regmap_update_bits(arizona->regmap,
14356887b042SRichard Fitzgerald 				ARIZONA_ADC_DIGITAL_VOLUME_1R + (i * 8),
14366887b042SRichard Fitzgerald 				ARIZONA_IN1R_SRC_SE_MASK,
14376887b042SRichard Fitzgerald 				(arizona->pdata.inmode[i] & ARIZONA_INMODE_SE)
14386887b042SRichard Fitzgerald 					<< ARIZONA_IN1R_SRC_SE_SHIFT);
14396887b042SRichard Fitzgerald 
14406887b042SRichard Fitzgerald 			mask = ARIZONA_IN1_DMIC_SUP_MASK |
14416887b042SRichard Fitzgerald 				ARIZONA_IN1_MODE_MASK;
14426887b042SRichard Fitzgerald 			break;
14436887b042SRichard Fitzgerald 		default:
1444fc027d13SRichard Fitzgerald 			if (arizona->pdata.inmode[i] & ARIZONA_INMODE_SE)
1445fc027d13SRichard Fitzgerald 				val |= 1 << ARIZONA_IN1_SINGLE_ENDED_SHIFT;
14463cc72986SMark Brown 
14476887b042SRichard Fitzgerald 			mask = ARIZONA_IN1_DMIC_SUP_MASK |
14486887b042SRichard Fitzgerald 				ARIZONA_IN1_MODE_MASK |
14496887b042SRichard Fitzgerald 				ARIZONA_IN1_SINGLE_ENDED_MASK;
14506887b042SRichard Fitzgerald 			break;
14516887b042SRichard Fitzgerald 		}
14526887b042SRichard Fitzgerald 
14533cc72986SMark Brown 		regmap_update_bits(arizona->regmap,
14543cc72986SMark Brown 				   ARIZONA_IN1L_CONTROL + (i * 8),
14556887b042SRichard Fitzgerald 				   mask, val);
14563cc72986SMark Brown 	}
14573cc72986SMark Brown 
14583cc72986SMark Brown 	for (i = 0; i < ARIZONA_MAX_OUTPUT; i++) {
14593cc72986SMark Brown 		/* Default is 0 so noop with defaults */
14603cc72986SMark Brown 		if (arizona->pdata.out_mono[i])
14613cc72986SMark Brown 			val = ARIZONA_OUT1_MONO;
14623cc72986SMark Brown 		else
14633cc72986SMark Brown 			val = 0;
14643cc72986SMark Brown 
14653cc72986SMark Brown 		regmap_update_bits(arizona->regmap,
14663cc72986SMark Brown 				   ARIZONA_OUTPUT_PATH_CONFIG_1L + (i * 8),
14673cc72986SMark Brown 				   ARIZONA_OUT1_MONO, val);
14683cc72986SMark Brown 	}
14693cc72986SMark Brown 
14703cc72986SMark Brown 	for (i = 0; i < ARIZONA_MAX_PDM_SPK; i++) {
14713cc72986SMark Brown 		if (arizona->pdata.spk_mute[i])
14723cc72986SMark Brown 			regmap_update_bits(arizona->regmap,
14732a51da04SMark Brown 					   ARIZONA_PDM_SPK1_CTRL_1 + (i * 2),
14743cc72986SMark Brown 					   ARIZONA_SPK1_MUTE_ENDIAN_MASK |
14753cc72986SMark Brown 					   ARIZONA_SPK1_MUTE_SEQ1_MASK,
14763cc72986SMark Brown 					   arizona->pdata.spk_mute[i]);
14773cc72986SMark Brown 
14783cc72986SMark Brown 		if (arizona->pdata.spk_fmt[i])
14793cc72986SMark Brown 			regmap_update_bits(arizona->regmap,
14802a51da04SMark Brown 					   ARIZONA_PDM_SPK1_CTRL_2 + (i * 2),
14813cc72986SMark Brown 					   ARIZONA_SPK1_FMT_MASK,
14823cc72986SMark Brown 					   arizona->pdata.spk_fmt[i]);
14833cc72986SMark Brown 	}
14843cc72986SMark Brown 
148572e43164SCharles Keepax 	pm_runtime_set_active(arizona->dev);
148672e43164SCharles Keepax 	pm_runtime_enable(arizona->dev);
148772e43164SCharles Keepax 
14883cc72986SMark Brown 	/* Set up for interrupts */
14893cc72986SMark Brown 	ret = arizona_irq_init(arizona);
14903cc72986SMark Brown 	if (ret != 0)
1491d347792cSCharles Keepax 		goto err_pm;
14923cc72986SMark Brown 
149372e43164SCharles Keepax 	pm_runtime_set_autosuspend_delay(arizona->dev, 100);
149472e43164SCharles Keepax 	pm_runtime_use_autosuspend(arizona->dev);
149572e43164SCharles Keepax 
14963cc72986SMark Brown 	arizona_request_irq(arizona, ARIZONA_IRQ_CLKGEN_ERR, "CLKGEN error",
14973cc72986SMark Brown 			    arizona_clkgen_err, arizona);
14983cc72986SMark Brown 	arizona_request_irq(arizona, ARIZONA_IRQ_OVERCLOCKED, "Overclocked",
14993cc72986SMark Brown 			    arizona_overclocked, arizona);
15003cc72986SMark Brown 	arizona_request_irq(arizona, ARIZONA_IRQ_UNDERCLOCKED, "Underclocked",
15013cc72986SMark Brown 			    arizona_underclocked, arizona);
15023cc72986SMark Brown 
1503ae05ea36SRichard Fitzgerald 	ret = mfd_add_devices(arizona->dev, PLATFORM_DEVID_NONE,
1504ae05ea36SRichard Fitzgerald 			      subdevs, n_subdevs, NULL, 0, NULL);
15053cc72986SMark Brown 
1506ae05ea36SRichard Fitzgerald 	if (ret) {
15073cc72986SMark Brown 		dev_err(arizona->dev, "Failed to add subdevices: %d\n", ret);
15083cc72986SMark Brown 		goto err_irq;
15093cc72986SMark Brown 	}
15103cc72986SMark Brown 
15113cc72986SMark Brown 	return 0;
15123cc72986SMark Brown 
15133cc72986SMark Brown err_irq:
15143cc72986SMark Brown 	arizona_irq_exit(arizona);
1515d347792cSCharles Keepax err_pm:
1516d347792cSCharles Keepax 	pm_runtime_disable(arizona->dev);
15173cc72986SMark Brown err_reset:
15182229875dSCharles Keepax 	arizona_enable_reset(arizona);
151959db9691SMark Brown 	regulator_disable(arizona->dcvdd);
15203cc72986SMark Brown err_enable:
15213a36a0dbSMark Brown 	regulator_bulk_disable(arizona->num_core_supplies,
15223cc72986SMark Brown 			       arizona->core_supplies);
1523e6021511SCharles Keepax err_dcvdd:
1524e6021511SCharles Keepax 	regulator_put(arizona->dcvdd);
15253cc72986SMark Brown err_early:
15263cc72986SMark Brown 	mfd_remove_devices(dev);
15273cc72986SMark Brown 	return ret;
15283cc72986SMark Brown }
15293cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_dev_init);
15303cc72986SMark Brown 
15314740f73fSBill Pemberton int arizona_dev_exit(struct arizona *arizona)
15323cc72986SMark Brown {
1533b804020aSCharles Keepax 	pm_runtime_disable(arizona->dev);
1534b804020aSCharles Keepax 
1535df6b3352SCharles Keepax 	regulator_disable(arizona->dcvdd);
1536e6021511SCharles Keepax 	regulator_put(arizona->dcvdd);
1537df6b3352SCharles Keepax 
15383cc72986SMark Brown 	mfd_remove_devices(arizona->dev);
15393cc72986SMark Brown 	arizona_free_irq(arizona, ARIZONA_IRQ_UNDERCLOCKED, arizona);
15403cc72986SMark Brown 	arizona_free_irq(arizona, ARIZONA_IRQ_OVERCLOCKED, arizona);
15413cc72986SMark Brown 	arizona_free_irq(arizona, ARIZONA_IRQ_CLKGEN_ERR, arizona);
15423cc72986SMark Brown 	arizona_irq_exit(arizona);
15432229875dSCharles Keepax 	arizona_enable_reset(arizona);
1544df6b3352SCharles Keepax 
15454420286eSCharles Keepax 	regulator_bulk_disable(arizona->num_core_supplies,
15461d017b6bSMark Brown 			       arizona->core_supplies);
15473cc72986SMark Brown 	return 0;
15483cc72986SMark Brown }
15493cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_dev_exit);
1550