xref: /linux/drivers/mfd/arizona-core.c (revision de4ea10ad7bd86445875bab25596016544f827ca)
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 
13cdd8da8cSSylwester 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)
53cdd8da8cSSylwester Nawrocki 				goto err_ref;
54cdd8da8cSSylwester Nawrocki 			ret = clk_prepare_enable(arizona->mclk[ARIZONA_MCLK1]);
55cdd8da8cSSylwester Nawrocki 			if (ret != 0)
56cdd8da8cSSylwester Nawrocki 				goto err_pm;
57cdd8da8cSSylwester Nawrocki 			break;
58cdd8da8cSSylwester Nawrocki 		case ARIZONA_32KZ_MCLK2:
59cdd8da8cSSylwester Nawrocki 			ret = clk_prepare_enable(arizona->mclk[ARIZONA_MCLK2]);
60cdd8da8cSSylwester Nawrocki 			if (ret != 0)
61cdd8da8cSSylwester 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 
70cdd8da8cSSylwester Nawrocki err_pm:
71cdd8da8cSSylwester Nawrocki 	pm_runtime_put_sync(arizona->dev);
72cdd8da8cSSylwester 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);
97cdd8da8cSSylwester Nawrocki 			clk_disable_unprepare(arizona->mclk[ARIZONA_MCLK1]);
98cdd8da8cSSylwester Nawrocki 			break;
99cdd8da8cSSylwester Nawrocki 		case ARIZONA_32KZ_MCLK2:
100cdd8da8cSSylwester 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);
345*de4ea10aSCharles Keepax 	if (ret)
346e80436bbSCharles Keepax 		goto err_fll;
347e80436bbSCharles Keepax 
348e80436bbSCharles Keepax 	ret = regmap_write(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, 0x0144);
3490be068a0SCharles Keepax 	if (ret) {
350e80436bbSCharles Keepax 		dev_err(arizona->dev, "Failed to start SYSCLK: %d\n", ret);
351e80436bbSCharles Keepax 		goto err_fll;
352e80436bbSCharles Keepax 	}
353e80436bbSCharles Keepax 
3543850e3eeSCharles Keepax 	return 0;
3553850e3eeSCharles Keepax 
3563850e3eeSCharles Keepax err_fll:
3573850e3eeSCharles Keepax 	err = regmap_write(arizona->regmap, ARIZONA_FLL1_CONTROL_1, state->fll);
3583850e3eeSCharles Keepax 	if (err)
3593850e3eeSCharles Keepax 		dev_err(arizona->dev,
3603850e3eeSCharles Keepax 			"Failed to re-apply old FLL settings: %d\n", err);
3613850e3eeSCharles Keepax 
3623850e3eeSCharles Keepax 	return ret;
3633850e3eeSCharles Keepax }
3643850e3eeSCharles Keepax 
3653850e3eeSCharles Keepax static int arizona_disable_freerun_sysclk(struct arizona *arizona,
3663850e3eeSCharles Keepax 					  struct arizona_sysclk_state *state)
3673850e3eeSCharles Keepax {
3683850e3eeSCharles Keepax 	int ret;
3693850e3eeSCharles Keepax 
3703850e3eeSCharles Keepax 	ret = regmap_write(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1,
3713850e3eeSCharles Keepax 			   state->sysclk);
3723850e3eeSCharles Keepax 	if (ret) {
3733850e3eeSCharles Keepax 		dev_err(arizona->dev,
3743850e3eeSCharles Keepax 			"Failed to re-apply old SYSCLK settings: %d\n", ret);
3753850e3eeSCharles Keepax 		return ret;
3763850e3eeSCharles Keepax 	}
3773850e3eeSCharles Keepax 
3783850e3eeSCharles Keepax 	ret = regmap_write(arizona->regmap, ARIZONA_FLL1_CONTROL_1, state->fll);
3793850e3eeSCharles Keepax 	if (ret) {
3803850e3eeSCharles Keepax 		dev_err(arizona->dev,
3813850e3eeSCharles Keepax 			"Failed to re-apply old FLL settings: %d\n", ret);
3823850e3eeSCharles Keepax 		return ret;
3833850e3eeSCharles Keepax 	}
3843850e3eeSCharles Keepax 
3853850e3eeSCharles Keepax 	return 0;
3863850e3eeSCharles Keepax }
3873850e3eeSCharles Keepax 
3883850e3eeSCharles Keepax static int wm5102_apply_hardware_patch(struct arizona *arizona)
3893850e3eeSCharles Keepax {
3903850e3eeSCharles Keepax 	struct arizona_sysclk_state state;
3913850e3eeSCharles Keepax 	int err, ret;
3923850e3eeSCharles Keepax 
3933850e3eeSCharles Keepax 	ret = arizona_enable_freerun_sysclk(arizona, &state);
3943850e3eeSCharles Keepax 	if (ret)
3953850e3eeSCharles Keepax 		return ret;
3963850e3eeSCharles Keepax 
397e80436bbSCharles Keepax 	/* Start the write sequencer and wait for it to finish */
398e80436bbSCharles Keepax 	ret = regmap_write(arizona->regmap, ARIZONA_WRITE_SEQUENCER_CTRL_0,
399e80436bbSCharles Keepax 			   ARIZONA_WSEQ_ENA | ARIZONA_WSEQ_START | 160);
4000be068a0SCharles Keepax 	if (ret) {
401e80436bbSCharles Keepax 		dev_err(arizona->dev, "Failed to start write sequencer: %d\n",
402e80436bbSCharles Keepax 			ret);
4033850e3eeSCharles Keepax 		goto err;
404e80436bbSCharles Keepax 	}
4053850e3eeSCharles Keepax 
406e80436bbSCharles Keepax 	ret = arizona_poll_reg(arizona, 5, ARIZONA_WRITE_SEQUENCER_CTRL_1,
407e80436bbSCharles Keepax 			       ARIZONA_WSEQ_BUSY, 0);
408*de4ea10aSCharles Keepax 	if (ret)
409e80436bbSCharles Keepax 		regmap_write(arizona->regmap, ARIZONA_WRITE_SEQUENCER_CTRL_0,
410e80436bbSCharles Keepax 			     ARIZONA_WSEQ_ABORT);
411e80436bbSCharles Keepax 
4123850e3eeSCharles Keepax err:
4133850e3eeSCharles Keepax 	err = arizona_disable_freerun_sysclk(arizona, &state);
414e80436bbSCharles Keepax 
4150be068a0SCharles Keepax 	return ret ?: err;
416e80436bbSCharles Keepax }
417e80436bbSCharles Keepax 
418882bc468SCharles Keepax /*
419882bc468SCharles Keepax  * Register patch to some of the CODECs internal write sequences
420882bc468SCharles Keepax  * to ensure a clean exit from the low power sleep state.
421882bc468SCharles Keepax  */
4228019ff6cSNariman Poushin static const struct reg_sequence wm5110_sleep_patch[] = {
423882bc468SCharles Keepax 	{ 0x337A, 0xC100 },
424882bc468SCharles Keepax 	{ 0x337B, 0x0041 },
425882bc468SCharles Keepax 	{ 0x3300, 0xA210 },
426882bc468SCharles Keepax 	{ 0x3301, 0x050C },
427882bc468SCharles Keepax };
428882bc468SCharles Keepax 
429882bc468SCharles Keepax static int wm5110_apply_sleep_patch(struct arizona *arizona)
430882bc468SCharles Keepax {
431882bc468SCharles Keepax 	struct arizona_sysclk_state state;
432882bc468SCharles Keepax 	int err, ret;
433882bc468SCharles Keepax 
434882bc468SCharles Keepax 	ret = arizona_enable_freerun_sysclk(arizona, &state);
435882bc468SCharles Keepax 	if (ret)
436882bc468SCharles Keepax 		return ret;
437882bc468SCharles Keepax 
438882bc468SCharles Keepax 	ret = regmap_multi_reg_write_bypassed(arizona->regmap,
439882bc468SCharles Keepax 					      wm5110_sleep_patch,
440882bc468SCharles Keepax 					      ARRAY_SIZE(wm5110_sleep_patch));
441882bc468SCharles Keepax 
442882bc468SCharles Keepax 	err = arizona_disable_freerun_sysclk(arizona, &state);
443882bc468SCharles Keepax 
444882bc468SCharles Keepax 	return ret ?: err;
445882bc468SCharles Keepax }
446882bc468SCharles Keepax 
4471c1c6bbaSCharles Keepax static int wm5102_clear_write_sequencer(struct arizona *arizona)
4481c1c6bbaSCharles Keepax {
4491c1c6bbaSCharles Keepax 	int ret;
4501c1c6bbaSCharles Keepax 
4511c1c6bbaSCharles Keepax 	ret = regmap_write(arizona->regmap, ARIZONA_WRITE_SEQUENCER_CTRL_3,
4521c1c6bbaSCharles Keepax 			   0x0);
4531c1c6bbaSCharles Keepax 	if (ret) {
4541c1c6bbaSCharles Keepax 		dev_err(arizona->dev,
4551c1c6bbaSCharles Keepax 			"Failed to clear write sequencer state: %d\n", ret);
4561c1c6bbaSCharles Keepax 		return ret;
4571c1c6bbaSCharles Keepax 	}
4581c1c6bbaSCharles Keepax 
4591c1c6bbaSCharles Keepax 	arizona_enable_reset(arizona);
4601c1c6bbaSCharles Keepax 	regulator_disable(arizona->dcvdd);
4611c1c6bbaSCharles Keepax 
4621c1c6bbaSCharles Keepax 	msleep(20);
4631c1c6bbaSCharles Keepax 
4641c1c6bbaSCharles Keepax 	ret = regulator_enable(arizona->dcvdd);
4651c1c6bbaSCharles Keepax 	if (ret) {
4661c1c6bbaSCharles Keepax 		dev_err(arizona->dev, "Failed to re-enable DCVDD: %d\n", ret);
4671c1c6bbaSCharles Keepax 		return ret;
4681c1c6bbaSCharles Keepax 	}
4691c1c6bbaSCharles Keepax 	arizona_disable_reset(arizona);
4701c1c6bbaSCharles Keepax 
4711c1c6bbaSCharles Keepax 	return 0;
4721c1c6bbaSCharles Keepax }
4731c1c6bbaSCharles Keepax 
47448bb9fe4SRafael J. Wysocki #ifdef CONFIG_PM
475e7811147SRichard Fitzgerald static int arizona_isolate_dcvdd(struct arizona *arizona)
476e7811147SRichard Fitzgerald {
477e7811147SRichard Fitzgerald 	int ret;
478e7811147SRichard Fitzgerald 
479e7811147SRichard Fitzgerald 	ret = regmap_update_bits(arizona->regmap,
480e7811147SRichard Fitzgerald 				 ARIZONA_ISOLATION_CONTROL,
481e7811147SRichard Fitzgerald 				 ARIZONA_ISOLATE_DCVDD1,
482e7811147SRichard Fitzgerald 				 ARIZONA_ISOLATE_DCVDD1);
483e7811147SRichard Fitzgerald 	if (ret != 0)
484e7811147SRichard Fitzgerald 		dev_err(arizona->dev, "Failed to isolate DCVDD: %d\n", ret);
485e7811147SRichard Fitzgerald 
486e7811147SRichard Fitzgerald 	return ret;
487e7811147SRichard Fitzgerald }
488e7811147SRichard Fitzgerald 
489e7811147SRichard Fitzgerald static int arizona_connect_dcvdd(struct arizona *arizona)
490e7811147SRichard Fitzgerald {
491e7811147SRichard Fitzgerald 	int ret;
492e7811147SRichard Fitzgerald 
493e7811147SRichard Fitzgerald 	ret = regmap_update_bits(arizona->regmap,
494e7811147SRichard Fitzgerald 				 ARIZONA_ISOLATION_CONTROL,
495e7811147SRichard Fitzgerald 				 ARIZONA_ISOLATE_DCVDD1, 0);
496e7811147SRichard Fitzgerald 	if (ret != 0)
497e7811147SRichard Fitzgerald 		dev_err(arizona->dev, "Failed to connect DCVDD: %d\n", ret);
498e7811147SRichard Fitzgerald 
499e7811147SRichard Fitzgerald 	return ret;
500e7811147SRichard Fitzgerald }
501e7811147SRichard Fitzgerald 
502e3424273SRichard Fitzgerald static int arizona_is_jack_det_active(struct arizona *arizona)
503e3424273SRichard Fitzgerald {
504e3424273SRichard Fitzgerald 	unsigned int val;
505e3424273SRichard Fitzgerald 	int ret;
506e3424273SRichard Fitzgerald 
507e3424273SRichard Fitzgerald 	ret = regmap_read(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE, &val);
508e3424273SRichard Fitzgerald 	if (ret) {
509e3424273SRichard Fitzgerald 		dev_err(arizona->dev,
510e3424273SRichard Fitzgerald 			"Failed to check jack det status: %d\n", ret);
511e3424273SRichard Fitzgerald 		return ret;
512e3424273SRichard Fitzgerald 	} else if (val & ARIZONA_JD1_ENA) {
513e3424273SRichard Fitzgerald 		return 1;
514e3424273SRichard Fitzgerald 	} else {
515e3424273SRichard Fitzgerald 		return 0;
516e3424273SRichard Fitzgerald 	}
517e3424273SRichard Fitzgerald }
518e3424273SRichard Fitzgerald 
5193cc72986SMark Brown static int arizona_runtime_resume(struct device *dev)
5203cc72986SMark Brown {
5213cc72986SMark Brown 	struct arizona *arizona = dev_get_drvdata(dev);
5223cc72986SMark Brown 	int ret;
5233cc72986SMark Brown 
524508c8299SMark Brown 	dev_dbg(arizona->dev, "Leaving AoD mode\n");
525508c8299SMark Brown 
526e6cb7341SCharles Keepax 	if (arizona->has_fully_powered_off) {
527e6cb7341SCharles Keepax 		dev_dbg(arizona->dev, "Re-enabling core supplies\n");
528e6cb7341SCharles Keepax 
529e6cb7341SCharles Keepax 		ret = regulator_bulk_enable(arizona->num_core_supplies,
530e6cb7341SCharles Keepax 					    arizona->core_supplies);
531e6cb7341SCharles Keepax 		if (ret) {
532e6cb7341SCharles Keepax 			dev_err(dev, "Failed to enable core supplies: %d\n",
533e6cb7341SCharles Keepax 				ret);
534e6cb7341SCharles Keepax 			return ret;
535e6cb7341SCharles Keepax 		}
536e6cb7341SCharles Keepax 	}
537e6cb7341SCharles Keepax 
53859db9691SMark Brown 	ret = regulator_enable(arizona->dcvdd);
53959db9691SMark Brown 	if (ret != 0) {
54059db9691SMark Brown 		dev_err(arizona->dev, "Failed to enable DCVDD: %d\n", ret);
541e6cb7341SCharles Keepax 		if (arizona->has_fully_powered_off)
542e6cb7341SCharles Keepax 			regulator_bulk_disable(arizona->num_core_supplies,
543e6cb7341SCharles Keepax 					       arizona->core_supplies);
54459db9691SMark Brown 		return ret;
54559db9691SMark Brown 	}
5463cc72986SMark Brown 
547e6cb7341SCharles Keepax 	if (arizona->has_fully_powered_off) {
548e6cb7341SCharles Keepax 		arizona_disable_reset(arizona);
549e6cb7341SCharles Keepax 		enable_irq(arizona->irq);
550e6cb7341SCharles Keepax 		arizona->has_fully_powered_off = false;
551e6cb7341SCharles Keepax 	}
552e6cb7341SCharles Keepax 
5533cc72986SMark Brown 	regcache_cache_only(arizona->regmap, false);
5543cc72986SMark Brown 
5554c9bb8bcSCharles Keepax 	switch (arizona->type) {
5564c9bb8bcSCharles Keepax 	case WM5102:
5575927467dSMark Brown 		if (arizona->external_dcvdd) {
558e7811147SRichard Fitzgerald 			ret = arizona_connect_dcvdd(arizona);
559e7811147SRichard Fitzgerald 			if (ret != 0)
5605927467dSMark Brown 				goto err;
5615927467dSMark Brown 		}
5625927467dSMark Brown 
5634c9bb8bcSCharles Keepax 		ret = wm5102_patch(arizona);
5644c9bb8bcSCharles Keepax 		if (ret != 0) {
5654c9bb8bcSCharles Keepax 			dev_err(arizona->dev, "Failed to apply patch: %d\n",
5664c9bb8bcSCharles Keepax 				ret);
5674c9bb8bcSCharles Keepax 			goto err;
5684c9bb8bcSCharles Keepax 		}
569e80436bbSCharles Keepax 
5700be068a0SCharles Keepax 		ret = wm5102_apply_hardware_patch(arizona);
5710be068a0SCharles Keepax 		if (ret) {
572e80436bbSCharles Keepax 			dev_err(arizona->dev,
573e80436bbSCharles Keepax 				"Failed to apply hardware patch: %d\n",
574e80436bbSCharles Keepax 				ret);
575e80436bbSCharles Keepax 			goto err;
576e80436bbSCharles Keepax 		}
577e80436bbSCharles Keepax 		break;
57896129a0eSCharles Keepax 	case WM5110:
57996129a0eSCharles Keepax 	case WM8280:
58096129a0eSCharles Keepax 		ret = arizona_wait_for_boot(arizona);
58196129a0eSCharles Keepax 		if (ret)
58296129a0eSCharles Keepax 			goto err;
58396129a0eSCharles Keepax 
58496129a0eSCharles Keepax 		if (arizona->external_dcvdd) {
585e7811147SRichard Fitzgerald 			ret = arizona_connect_dcvdd(arizona);
586e7811147SRichard Fitzgerald 			if (ret != 0)
58796129a0eSCharles Keepax 				goto err;
58896129a0eSCharles Keepax 		} else {
58996129a0eSCharles Keepax 			/*
59096129a0eSCharles Keepax 			 * As this is only called for the internal regulator
59196129a0eSCharles Keepax 			 * (where we know voltage ranges available) it is ok
59296129a0eSCharles Keepax 			 * to request an exact range.
59396129a0eSCharles Keepax 			 */
59496129a0eSCharles Keepax 			ret = regulator_set_voltage(arizona->dcvdd,
59596129a0eSCharles Keepax 						    1200000, 1200000);
59696129a0eSCharles Keepax 			if (ret < 0) {
59796129a0eSCharles Keepax 				dev_err(arizona->dev,
59896129a0eSCharles Keepax 					"Failed to set resume voltage: %d\n",
59996129a0eSCharles Keepax 					ret);
60096129a0eSCharles Keepax 				goto err;
60196129a0eSCharles Keepax 			}
60296129a0eSCharles Keepax 		}
603e6cb7341SCharles Keepax 
604e6cb7341SCharles Keepax 		ret = wm5110_apply_sleep_patch(arizona);
605e6cb7341SCharles Keepax 		if (ret) {
606e6cb7341SCharles Keepax 			dev_err(arizona->dev,
607e6cb7341SCharles Keepax 				"Failed to re-apply sleep patch: %d\n",
608e6cb7341SCharles Keepax 				ret);
609e6cb7341SCharles Keepax 			goto err;
610e6cb7341SCharles Keepax 		}
61196129a0eSCharles Keepax 		break;
612ea1f3339SRichard Fitzgerald 	case WM1831:
613ea1f3339SRichard Fitzgerald 	case CS47L24:
614ea1f3339SRichard Fitzgerald 		ret = arizona_wait_for_boot(arizona);
615ea1f3339SRichard Fitzgerald 		if (ret != 0)
616ea1f3339SRichard Fitzgerald 			goto err;
617ea1f3339SRichard Fitzgerald 		break;
618e80436bbSCharles Keepax 	default:
61912bb68edSCharles Keepax 		ret = arizona_wait_for_boot(arizona);
6203762aedeSCharles Keepax 		if (ret != 0)
62112bb68edSCharles Keepax 			goto err;
62212bb68edSCharles Keepax 
6235927467dSMark Brown 		if (arizona->external_dcvdd) {
624e7811147SRichard Fitzgerald 			ret = arizona_connect_dcvdd(arizona);
625e7811147SRichard Fitzgerald 			if (ret != 0)
6265927467dSMark Brown 				goto err;
6275927467dSMark Brown 		}
628e80436bbSCharles Keepax 		break;
6294c9bb8bcSCharles Keepax 	}
6304c9bb8bcSCharles Keepax 
6319270bdf5SMark Brown 	ret = regcache_sync(arizona->regmap);
6329270bdf5SMark Brown 	if (ret != 0) {
6339270bdf5SMark Brown 		dev_err(arizona->dev, "Failed to restore register cache\n");
6344816bd1cSMark Brown 		goto err;
6359270bdf5SMark Brown 	}
6363cc72986SMark Brown 
6373cc72986SMark Brown 	return 0;
6384816bd1cSMark Brown 
6394816bd1cSMark Brown err:
6404816bd1cSMark Brown 	regcache_cache_only(arizona->regmap, true);
6414816bd1cSMark Brown 	regulator_disable(arizona->dcvdd);
6424816bd1cSMark Brown 	return ret;
6433cc72986SMark Brown }
6443cc72986SMark Brown 
6453cc72986SMark Brown static int arizona_runtime_suspend(struct device *dev)
6463cc72986SMark Brown {
6473cc72986SMark Brown 	struct arizona *arizona = dev_get_drvdata(dev);
648a05950a4SDan Carpenter 	int jd_active = 0;
6495927467dSMark Brown 	int ret;
6503cc72986SMark Brown 
651508c8299SMark Brown 	dev_dbg(arizona->dev, "Entering AoD mode\n");
652508c8299SMark Brown 
65396129a0eSCharles Keepax 	switch (arizona->type) {
65496129a0eSCharles Keepax 	case WM5110:
65596129a0eSCharles Keepax 	case WM8280:
656e3424273SRichard Fitzgerald 		jd_active = arizona_is_jack_det_active(arizona);
657e3424273SRichard Fitzgerald 		if (jd_active < 0)
658e3424273SRichard Fitzgerald 			return jd_active;
659e3424273SRichard Fitzgerald 
660e7811147SRichard Fitzgerald 		if (arizona->external_dcvdd) {
661e7811147SRichard Fitzgerald 			ret = arizona_isolate_dcvdd(arizona);
662e7811147SRichard Fitzgerald 			if (ret != 0)
663e7811147SRichard Fitzgerald 				return ret;
664e7811147SRichard Fitzgerald 		} else {
66596129a0eSCharles Keepax 			/*
66696129a0eSCharles Keepax 			 * As this is only called for the internal regulator
66796129a0eSCharles Keepax 			 * (where we know voltage ranges available) it is ok
66896129a0eSCharles Keepax 			 * to request an exact range.
66996129a0eSCharles Keepax 			 */
670e7811147SRichard Fitzgerald 			ret = regulator_set_voltage(arizona->dcvdd,
671e7811147SRichard Fitzgerald 						    1175000, 1175000);
67296129a0eSCharles Keepax 			if (ret < 0) {
67396129a0eSCharles Keepax 				dev_err(arizona->dev,
674e7811147SRichard Fitzgerald 					"Failed to set suspend voltage: %d\n",
675e7811147SRichard Fitzgerald 					ret);
676e6cb7341SCharles Keepax 				return ret;
677e6cb7341SCharles Keepax 			}
678e7811147SRichard Fitzgerald 		}
679e6cb7341SCharles Keepax 		break;
680e6cb7341SCharles Keepax 	case WM5102:
681e3424273SRichard Fitzgerald 		jd_active = arizona_is_jack_det_active(arizona);
682e3424273SRichard Fitzgerald 		if (jd_active < 0)
683e3424273SRichard Fitzgerald 			return jd_active;
684e3424273SRichard Fitzgerald 
685e7811147SRichard Fitzgerald 		if (arizona->external_dcvdd) {
686e7811147SRichard Fitzgerald 			ret = arizona_isolate_dcvdd(arizona);
687e7811147SRichard Fitzgerald 			if (ret != 0)
688e7811147SRichard Fitzgerald 				return ret;
689e7811147SRichard Fitzgerald 		}
690e7811147SRichard Fitzgerald 
691e3424273SRichard Fitzgerald 		if (!jd_active) {
692e6cb7341SCharles Keepax 			ret = regmap_write(arizona->regmap,
693e6cb7341SCharles Keepax 					   ARIZONA_WRITE_SEQUENCER_CTRL_3, 0x0);
694e6cb7341SCharles Keepax 			if (ret) {
695e6cb7341SCharles Keepax 				dev_err(arizona->dev,
696e6cb7341SCharles Keepax 					"Failed to clear write sequencer: %d\n",
69796129a0eSCharles Keepax 					ret);
69896129a0eSCharles Keepax 				return ret;
69996129a0eSCharles Keepax 			}
700e6cb7341SCharles Keepax 		}
70196129a0eSCharles Keepax 		break;
702ea1f3339SRichard Fitzgerald 	case WM1831:
703ea1f3339SRichard Fitzgerald 	case CS47L24:
704ea1f3339SRichard Fitzgerald 		break;
70596129a0eSCharles Keepax 	default:
706e3424273SRichard Fitzgerald 		jd_active = arizona_is_jack_det_active(arizona);
707e3424273SRichard Fitzgerald 		if (jd_active < 0)
708e3424273SRichard Fitzgerald 			return jd_active;
709e3424273SRichard Fitzgerald 
710e7811147SRichard Fitzgerald 		if (arizona->external_dcvdd) {
711e7811147SRichard Fitzgerald 			ret = arizona_isolate_dcvdd(arizona);
712e7811147SRichard Fitzgerald 			if (ret != 0)
713e7811147SRichard Fitzgerald 				return ret;
714e7811147SRichard Fitzgerald 		}
71596129a0eSCharles Keepax 		break;
71696129a0eSCharles Keepax 	}
7175927467dSMark Brown 
7183cc72986SMark Brown 	regcache_cache_only(arizona->regmap, true);
7193cc72986SMark Brown 	regcache_mark_dirty(arizona->regmap);
720e293e847SCharles Keepax 	regulator_disable(arizona->dcvdd);
7213cc72986SMark Brown 
722e6cb7341SCharles Keepax 	/* Allow us to completely power down if no jack detection */
723e3424273SRichard Fitzgerald 	if (!jd_active) {
724e6cb7341SCharles Keepax 		dev_dbg(arizona->dev, "Fully powering off\n");
725e6cb7341SCharles Keepax 
726e6cb7341SCharles Keepax 		arizona->has_fully_powered_off = true;
727e6cb7341SCharles Keepax 
72811150929SCharles Keepax 		disable_irq_nosync(arizona->irq);
729e6cb7341SCharles Keepax 		arizona_enable_reset(arizona);
730e6cb7341SCharles Keepax 		regulator_bulk_disable(arizona->num_core_supplies,
731e6cb7341SCharles Keepax 				       arizona->core_supplies);
732e6cb7341SCharles Keepax 	}
733e6cb7341SCharles Keepax 
7343cc72986SMark Brown 	return 0;
7353cc72986SMark Brown }
7363cc72986SMark Brown #endif
7373cc72986SMark Brown 
738dc781d0eSMark Brown #ifdef CONFIG_PM_SLEEP
73967c99296SMark Brown static int arizona_suspend(struct device *dev)
74067c99296SMark Brown {
74167c99296SMark Brown 	struct arizona *arizona = dev_get_drvdata(dev);
74267c99296SMark Brown 
74367c99296SMark Brown 	dev_dbg(arizona->dev, "Suspend, disabling IRQ\n");
74467c99296SMark Brown 	disable_irq(arizona->irq);
74567c99296SMark Brown 
74667c99296SMark Brown 	return 0;
74767c99296SMark Brown }
74867c99296SMark Brown 
7493612b27cSCharles Keepax static int arizona_suspend_noirq(struct device *dev)
75067c99296SMark Brown {
75167c99296SMark Brown 	struct arizona *arizona = dev_get_drvdata(dev);
75267c99296SMark Brown 
75367c99296SMark Brown 	dev_dbg(arizona->dev, "Late suspend, reenabling IRQ\n");
75467c99296SMark Brown 	enable_irq(arizona->irq);
75567c99296SMark Brown 
75667c99296SMark Brown 	return 0;
75767c99296SMark Brown }
75867c99296SMark Brown 
759dc781d0eSMark Brown static int arizona_resume_noirq(struct device *dev)
760dc781d0eSMark Brown {
761dc781d0eSMark Brown 	struct arizona *arizona = dev_get_drvdata(dev);
762dc781d0eSMark Brown 
763dc781d0eSMark Brown 	dev_dbg(arizona->dev, "Early resume, disabling IRQ\n");
764dc781d0eSMark Brown 	disable_irq(arizona->irq);
765dc781d0eSMark Brown 
766dc781d0eSMark Brown 	return 0;
767dc781d0eSMark Brown }
768dc781d0eSMark Brown 
769dc781d0eSMark Brown static int arizona_resume(struct device *dev)
770dc781d0eSMark Brown {
771dc781d0eSMark Brown 	struct arizona *arizona = dev_get_drvdata(dev);
772dc781d0eSMark Brown 
7733612b27cSCharles Keepax 	dev_dbg(arizona->dev, "Resume, reenabling IRQ\n");
774dc781d0eSMark Brown 	enable_irq(arizona->irq);
775dc781d0eSMark Brown 
776dc781d0eSMark Brown 	return 0;
777dc781d0eSMark Brown }
778dc781d0eSMark Brown #endif
779dc781d0eSMark Brown 
7803cc72986SMark Brown const struct dev_pm_ops arizona_pm_ops = {
7813cc72986SMark Brown 	SET_RUNTIME_PM_OPS(arizona_runtime_suspend,
7823cc72986SMark Brown 			   arizona_runtime_resume,
7833cc72986SMark Brown 			   NULL)
78467c99296SMark Brown 	SET_SYSTEM_SLEEP_PM_OPS(arizona_suspend, arizona_resume)
7853612b27cSCharles Keepax 	SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(arizona_suspend_noirq,
7863612b27cSCharles Keepax 				      arizona_resume_noirq)
7873cc72986SMark Brown };
7883cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_pm_ops);
7893cc72986SMark Brown 
790d781009cSMark Brown #ifdef CONFIG_OF
791942786e6SLee Jones unsigned long arizona_of_get_type(struct device *dev)
792d781009cSMark Brown {
793d781009cSMark Brown 	const struct of_device_id *id = of_match_device(arizona_of_match, dev);
794d781009cSMark Brown 
795d781009cSMark Brown 	if (id)
796942786e6SLee Jones 		return (unsigned long)id->data;
797d781009cSMark Brown 	else
798d781009cSMark Brown 		return 0;
799d781009cSMark Brown }
800d781009cSMark Brown EXPORT_SYMBOL_GPL(arizona_of_get_type);
801d781009cSMark Brown 
802d781009cSMark Brown static int arizona_of_get_core_pdata(struct arizona *arizona)
803d781009cSMark Brown {
804e4fcb1d6SCharles Keepax 	struct arizona_pdata *pdata = &arizona->pdata;
805cc47aed9SInha Song 	struct property *prop;
806cc47aed9SInha Song 	const __be32 *cur;
807cc47aed9SInha Song 	u32 val;
808f4c05262SRichard Fitzgerald 	u32 pdm_val[ARIZONA_MAX_PDM_SPK];
809d781009cSMark Brown 	int ret, i;
810cc47aed9SInha Song 	int count = 0;
811d781009cSMark Brown 
8121961531dSCharles Keepax 	pdata->reset = of_get_named_gpio(arizona->dev->of_node, "wlf,reset", 0);
813b8d336edSCharles Keepax 	if (pdata->reset == -EPROBE_DEFER) {
814b8d336edSCharles Keepax 		return pdata->reset;
815b8d336edSCharles Keepax 	} else if (pdata->reset < 0) {
8161961531dSCharles Keepax 		dev_err(arizona->dev, "Reset GPIO missing/malformed: %d\n",
8171961531dSCharles Keepax 			pdata->reset);
8181961531dSCharles Keepax 
8191961531dSCharles Keepax 		pdata->reset = 0;
8201961531dSCharles Keepax 	}
821d781009cSMark Brown 
822d781009cSMark Brown 	ret = of_property_read_u32_array(arizona->dev->of_node,
823d781009cSMark Brown 					 "wlf,gpio-defaults",
8243762aedeSCharles Keepax 					 pdata->gpio_defaults,
8253762aedeSCharles Keepax 					 ARRAY_SIZE(pdata->gpio_defaults));
826d781009cSMark Brown 	if (ret >= 0) {
827d781009cSMark Brown 		/*
828d781009cSMark Brown 		 * All values are literal except out of range values
829d781009cSMark Brown 		 * which are chip default, translate into platform
830d781009cSMark Brown 		 * data which uses 0 as chip default and out of range
831d781009cSMark Brown 		 * as zero.
832d781009cSMark Brown 		 */
8333762aedeSCharles Keepax 		for (i = 0; i < ARRAY_SIZE(pdata->gpio_defaults); i++) {
8343762aedeSCharles Keepax 			if (pdata->gpio_defaults[i] > 0xffff)
8353762aedeSCharles Keepax 				pdata->gpio_defaults[i] = 0;
8363762aedeSCharles Keepax 			else if (pdata->gpio_defaults[i] == 0)
8373762aedeSCharles Keepax 				pdata->gpio_defaults[i] = 0x10000;
838d781009cSMark Brown 		}
839d781009cSMark Brown 	} else {
840d781009cSMark Brown 		dev_err(arizona->dev, "Failed to parse GPIO defaults: %d\n",
841d781009cSMark Brown 			ret);
842d781009cSMark Brown 	}
843d781009cSMark Brown 
844cc47aed9SInha Song 	of_property_for_each_u32(arizona->dev->of_node, "wlf,inmode", prop,
845cc47aed9SInha Song 				 cur, val) {
8463762aedeSCharles Keepax 		if (count == ARRAY_SIZE(pdata->inmode))
847cc47aed9SInha Song 			break;
848cc47aed9SInha Song 
8493762aedeSCharles Keepax 		pdata->inmode[count] = val;
850cc47aed9SInha Song 		count++;
851cc47aed9SInha Song 	}
852cc47aed9SInha Song 
853e7ad27caSCharles Keepax 	count = 0;
854e7ad27caSCharles Keepax 	of_property_for_each_u32(arizona->dev->of_node, "wlf,dmic-ref", prop,
855e7ad27caSCharles Keepax 				 cur, val) {
8563762aedeSCharles Keepax 		if (count == ARRAY_SIZE(pdata->dmic_ref))
857e7ad27caSCharles Keepax 			break;
858e7ad27caSCharles Keepax 
8593762aedeSCharles Keepax 		pdata->dmic_ref[count] = val;
860e7ad27caSCharles Keepax 		count++;
861e7ad27caSCharles Keepax 	}
862e7ad27caSCharles Keepax 
863f199d393SCharles Keepax 	count = 0;
864f199d393SCharles Keepax 	of_property_for_each_u32(arizona->dev->of_node, "wlf,out-mono", prop,
865f199d393SCharles Keepax 				 cur, val) {
866f199d393SCharles Keepax 		if (count == ARRAY_SIZE(pdata->out_mono))
867f199d393SCharles Keepax 			break;
868f199d393SCharles Keepax 
869f199d393SCharles Keepax 		pdata->out_mono[count] = !!val;
870f199d393SCharles Keepax 		count++;
871f199d393SCharles Keepax 	}
872f199d393SCharles Keepax 
873f4c05262SRichard Fitzgerald 	count = 0;
874f4c05262SRichard Fitzgerald 	of_property_for_each_u32(arizona->dev->of_node,
875f4c05262SRichard Fitzgerald 				 "wlf,max-channels-clocked",
876f4c05262SRichard Fitzgerald 				 prop, cur, val) {
877f4c05262SRichard Fitzgerald 		if (count == ARRAY_SIZE(pdata->max_channels_clocked))
878f4c05262SRichard Fitzgerald 			break;
879f4c05262SRichard Fitzgerald 
880f4c05262SRichard Fitzgerald 		pdata->max_channels_clocked[count] = val;
881f4c05262SRichard Fitzgerald 		count++;
882f4c05262SRichard Fitzgerald 	}
883f4c05262SRichard Fitzgerald 
884f4c05262SRichard Fitzgerald 	ret = of_property_read_u32_array(arizona->dev->of_node,
885f4c05262SRichard Fitzgerald 					 "wlf,spk-fmt",
886f4c05262SRichard Fitzgerald 					 pdm_val,
887f4c05262SRichard Fitzgerald 					 ARRAY_SIZE(pdm_val));
888f4c05262SRichard Fitzgerald 
889f4c05262SRichard Fitzgerald 	if (ret >= 0)
890f4c05262SRichard Fitzgerald 		for (count = 0; count < ARRAY_SIZE(pdata->spk_fmt); ++count)
891f4c05262SRichard Fitzgerald 			pdata->spk_fmt[count] = pdm_val[count];
892f4c05262SRichard Fitzgerald 
893f4c05262SRichard Fitzgerald 	ret = of_property_read_u32_array(arizona->dev->of_node,
894f4c05262SRichard Fitzgerald 					 "wlf,spk-mute",
895f4c05262SRichard Fitzgerald 					 pdm_val,
896f4c05262SRichard Fitzgerald 					 ARRAY_SIZE(pdm_val));
897f4c05262SRichard Fitzgerald 
898f4c05262SRichard Fitzgerald 	if (ret >= 0)
899f4c05262SRichard Fitzgerald 		for (count = 0; count < ARRAY_SIZE(pdata->spk_mute); ++count)
900f4c05262SRichard Fitzgerald 			pdata->spk_mute[count] = pdm_val[count];
901f4c05262SRichard Fitzgerald 
902d781009cSMark Brown 	return 0;
903d781009cSMark Brown }
904d781009cSMark Brown 
905d781009cSMark Brown const struct of_device_id arizona_of_match[] = {
906d781009cSMark Brown 	{ .compatible = "wlf,wm5102", .data = (void *)WM5102 },
907d781009cSMark Brown 	{ .compatible = "wlf,wm5110", .data = (void *)WM5110 },
908e5d4ef0dSRichard Fitzgerald 	{ .compatible = "wlf,wm8280", .data = (void *)WM8280 },
909dc7d4863SCharles Keepax 	{ .compatible = "wlf,wm8997", .data = (void *)WM8997 },
9106887b042SRichard Fitzgerald 	{ .compatible = "wlf,wm8998", .data = (void *)WM8998 },
9116887b042SRichard Fitzgerald 	{ .compatible = "wlf,wm1814", .data = (void *)WM1814 },
912ea1f3339SRichard Fitzgerald 	{ .compatible = "wlf,wm1831", .data = (void *)WM1831 },
913ea1f3339SRichard Fitzgerald 	{ .compatible = "cirrus,cs47l24", .data = (void *)CS47L24 },
914d781009cSMark Brown 	{},
915d781009cSMark Brown };
916d781009cSMark Brown EXPORT_SYMBOL_GPL(arizona_of_match);
917d781009cSMark Brown #else
918d781009cSMark Brown static inline int arizona_of_get_core_pdata(struct arizona *arizona)
919d781009cSMark Brown {
920d781009cSMark Brown 	return 0;
921d781009cSMark Brown }
922d781009cSMark Brown #endif
923d781009cSMark Brown 
9245ac98553SGeert Uytterhoeven static const struct mfd_cell early_devs[] = {
9253cc72986SMark Brown 	{ .name = "arizona-ldo1" },
9263cc72986SMark Brown };
9273cc72986SMark Brown 
9283762aedeSCharles Keepax static const char * const wm5102_supplies[] = {
9295fc6c396SCharles Keepax 	"MICVDD",
93032dadef2SCharles Keepax 	"DBVDD2",
93132dadef2SCharles Keepax 	"DBVDD3",
93232dadef2SCharles Keepax 	"CPVDD",
93332dadef2SCharles Keepax 	"SPKVDDL",
93432dadef2SCharles Keepax 	"SPKVDDR",
93532dadef2SCharles Keepax };
93632dadef2SCharles Keepax 
9375ac98553SGeert Uytterhoeven static const struct mfd_cell wm5102_devs[] = {
938d7768111SMark Brown 	{ .name = "arizona-micsupp" },
939f83c218cSCharles Keepax 	{ .name = "arizona-gpio" },
9405fc6c396SCharles Keepax 	{
9415fc6c396SCharles Keepax 		.name = "arizona-extcon",
9425fc6c396SCharles Keepax 		.parent_supplies = wm5102_supplies,
9435fc6c396SCharles Keepax 		.num_parent_supplies = 1, /* We only need MICVDD */
9445fc6c396SCharles Keepax 	},
945503b1cacSMark Brown 	{ .name = "arizona-haptics" },
9463cc72986SMark Brown 	{ .name = "arizona-pwm" },
94732dadef2SCharles Keepax 	{
94832dadef2SCharles Keepax 		.name = "wm5102-codec",
94932dadef2SCharles Keepax 		.parent_supplies = wm5102_supplies,
95032dadef2SCharles Keepax 		.num_parent_supplies = ARRAY_SIZE(wm5102_supplies),
95132dadef2SCharles Keepax 	},
9523cc72986SMark Brown };
9533cc72986SMark Brown 
9545ac98553SGeert Uytterhoeven static const struct mfd_cell wm5110_devs[] = {
955d7768111SMark Brown 	{ .name = "arizona-micsupp" },
956f83c218cSCharles Keepax 	{ .name = "arizona-gpio" },
9575fc6c396SCharles Keepax 	{
9585fc6c396SCharles Keepax 		.name = "arizona-extcon",
9595fc6c396SCharles Keepax 		.parent_supplies = wm5102_supplies,
9605fc6c396SCharles Keepax 		.num_parent_supplies = 1, /* We only need MICVDD */
9615fc6c396SCharles Keepax 	},
962503b1cacSMark Brown 	{ .name = "arizona-haptics" },
963e102befeSMark Brown 	{ .name = "arizona-pwm" },
96432dadef2SCharles Keepax 	{
96532dadef2SCharles Keepax 		.name = "wm5110-codec",
96632dadef2SCharles Keepax 		.parent_supplies = wm5102_supplies,
96732dadef2SCharles Keepax 		.num_parent_supplies = ARRAY_SIZE(wm5102_supplies),
96832dadef2SCharles Keepax 	},
96932dadef2SCharles Keepax };
97032dadef2SCharles Keepax 
971ea1f3339SRichard Fitzgerald static const char * const cs47l24_supplies[] = {
972ea1f3339SRichard Fitzgerald 	"MICVDD",
973ea1f3339SRichard Fitzgerald 	"CPVDD",
974ea1f3339SRichard Fitzgerald 	"SPKVDD",
975ea1f3339SRichard Fitzgerald };
976ea1f3339SRichard Fitzgerald 
977ea1f3339SRichard Fitzgerald static const struct mfd_cell cs47l24_devs[] = {
978ea1f3339SRichard Fitzgerald 	{ .name = "arizona-gpio" },
979ea1f3339SRichard Fitzgerald 	{ .name = "arizona-haptics" },
980ea1f3339SRichard Fitzgerald 	{ .name = "arizona-pwm" },
981ea1f3339SRichard Fitzgerald 	{
982ea1f3339SRichard Fitzgerald 		.name = "cs47l24-codec",
983ea1f3339SRichard Fitzgerald 		.parent_supplies = cs47l24_supplies,
984ea1f3339SRichard Fitzgerald 		.num_parent_supplies = ARRAY_SIZE(cs47l24_supplies),
985ea1f3339SRichard Fitzgerald 	},
986ea1f3339SRichard Fitzgerald };
987ea1f3339SRichard Fitzgerald 
9883762aedeSCharles Keepax static const char * const wm8997_supplies[] = {
989996c2d4fSCharles Keepax 	"MICVDD",
99032dadef2SCharles Keepax 	"DBVDD2",
99132dadef2SCharles Keepax 	"CPVDD",
99232dadef2SCharles Keepax 	"SPKVDD",
993e102befeSMark Brown };
994e102befeSMark Brown 
9955ac98553SGeert Uytterhoeven static const struct mfd_cell wm8997_devs[] = {
996dc7d4863SCharles Keepax 	{ .name = "arizona-micsupp" },
997f83c218cSCharles Keepax 	{ .name = "arizona-gpio" },
9985fc6c396SCharles Keepax 	{
9995fc6c396SCharles Keepax 		.name = "arizona-extcon",
10005fc6c396SCharles Keepax 		.parent_supplies = wm8997_supplies,
10015fc6c396SCharles Keepax 		.num_parent_supplies = 1, /* We only need MICVDD */
10025fc6c396SCharles Keepax 	},
1003dc7d4863SCharles Keepax 	{ .name = "arizona-haptics" },
1004dc7d4863SCharles Keepax 	{ .name = "arizona-pwm" },
100532dadef2SCharles Keepax 	{
100632dadef2SCharles Keepax 		.name = "wm8997-codec",
100732dadef2SCharles Keepax 		.parent_supplies = wm8997_supplies,
100832dadef2SCharles Keepax 		.num_parent_supplies = ARRAY_SIZE(wm8997_supplies),
100932dadef2SCharles Keepax 	},
1010dc7d4863SCharles Keepax };
1011dc7d4863SCharles Keepax 
10126887b042SRichard Fitzgerald static const struct mfd_cell wm8998_devs[] = {
1013f83c218cSCharles Keepax 	{ .name = "arizona-micsupp" },
1014f83c218cSCharles Keepax 	{ .name = "arizona-gpio" },
10156887b042SRichard Fitzgerald 	{
10166887b042SRichard Fitzgerald 		.name = "arizona-extcon",
10176887b042SRichard Fitzgerald 		.parent_supplies = wm5102_supplies,
10186887b042SRichard Fitzgerald 		.num_parent_supplies = 1, /* We only need MICVDD */
10196887b042SRichard Fitzgerald 	},
10206887b042SRichard Fitzgerald 	{ .name = "arizona-haptics" },
10216887b042SRichard Fitzgerald 	{ .name = "arizona-pwm" },
10226887b042SRichard Fitzgerald 	{
10236887b042SRichard Fitzgerald 		.name = "wm8998-codec",
10246887b042SRichard Fitzgerald 		.parent_supplies = wm5102_supplies,
10256887b042SRichard Fitzgerald 		.num_parent_supplies = ARRAY_SIZE(wm5102_supplies),
10266887b042SRichard Fitzgerald 	},
10276887b042SRichard Fitzgerald };
10286887b042SRichard Fitzgerald 
1029f791be49SBill Pemberton int arizona_dev_init(struct arizona *arizona)
10303cc72986SMark Brown {
1031cdd8da8cSSylwester Nawrocki 	const char * const mclk_name[] = { "mclk1", "mclk2" };
10323cc72986SMark Brown 	struct device *dev = arizona->dev;
1033ea1f3339SRichard Fitzgerald 	const char *type_name = NULL;
10346887b042SRichard Fitzgerald 	unsigned int reg, val, mask;
103562d62b59SMark Brown 	int (*apply_patch)(struct arizona *) = NULL;
1036ae05ea36SRichard Fitzgerald 	const struct mfd_cell *subdevs = NULL;
1037ae05ea36SRichard Fitzgerald 	int n_subdevs, ret, i;
10383cc72986SMark Brown 
10393cc72986SMark Brown 	dev_set_drvdata(arizona->dev, arizona);
10403cc72986SMark Brown 	mutex_init(&arizona->clk_lock);
10413cc72986SMark Brown 
1042b8d336edSCharles Keepax 	if (dev_get_platdata(arizona->dev)) {
10433cc72986SMark Brown 		memcpy(&arizona->pdata, dev_get_platdata(arizona->dev),
10443cc72986SMark Brown 		       sizeof(arizona->pdata));
1045b8d336edSCharles Keepax 	} else {
1046b8d336edSCharles Keepax 		ret = arizona_of_get_core_pdata(arizona);
1047b8d336edSCharles Keepax 		if (ret < 0)
1048b8d336edSCharles Keepax 			return ret;
1049b8d336edSCharles Keepax 	}
10503cc72986SMark Brown 
1051cdd8da8cSSylwester Nawrocki 	BUILD_BUG_ON(ARRAY_SIZE(arizona->mclk) != ARRAY_SIZE(mclk_name));
1052cdd8da8cSSylwester Nawrocki 	for (i = 0; i < ARRAY_SIZE(arizona->mclk); i++) {
1053cdd8da8cSSylwester Nawrocki 		arizona->mclk[i] = devm_clk_get(arizona->dev, mclk_name[i]);
1054cdd8da8cSSylwester Nawrocki 		if (IS_ERR(arizona->mclk[i])) {
1055cdd8da8cSSylwester Nawrocki 			dev_info(arizona->dev, "Failed to get %s: %ld\n",
1056cdd8da8cSSylwester Nawrocki 				 mclk_name[i], PTR_ERR(arizona->mclk[i]));
1057cdd8da8cSSylwester Nawrocki 			arizona->mclk[i] = NULL;
1058cdd8da8cSSylwester Nawrocki 		}
1059cdd8da8cSSylwester Nawrocki 	}
1060cdd8da8cSSylwester Nawrocki 
10613cc72986SMark Brown 	regcache_cache_only(arizona->regmap, true);
10623cc72986SMark Brown 
10633cc72986SMark Brown 	switch (arizona->type) {
10643cc72986SMark Brown 	case WM5102:
1065e102befeSMark Brown 	case WM5110:
1066e5d4ef0dSRichard Fitzgerald 	case WM8280:
1067dc7d4863SCharles Keepax 	case WM8997:
10686887b042SRichard Fitzgerald 	case WM8998:
10696887b042SRichard Fitzgerald 	case WM1814:
1070ea1f3339SRichard Fitzgerald 	case WM1831:
1071ea1f3339SRichard Fitzgerald 	case CS47L24:
10723cc72986SMark Brown 		for (i = 0; i < ARRAY_SIZE(wm5102_core_supplies); i++)
10733cc72986SMark Brown 			arizona->core_supplies[i].supply
10743cc72986SMark Brown 				= wm5102_core_supplies[i];
10753cc72986SMark Brown 		arizona->num_core_supplies = ARRAY_SIZE(wm5102_core_supplies);
10763cc72986SMark Brown 		break;
10773cc72986SMark Brown 	default:
10783cc72986SMark Brown 		dev_err(arizona->dev, "Unknown device type %d\n",
10793cc72986SMark Brown 			arizona->type);
108075d8a2b0SCharles Keepax 		return -ENODEV;
10813cc72986SMark Brown 	}
10823cc72986SMark Brown 
10834a8c475fSCharles Keepax 	/* Mark DCVDD as external, LDO1 driver will clear if internal */
10844a8c475fSCharles Keepax 	arizona->external_dcvdd = true;
10854a8c475fSCharles Keepax 
1086ea1f3339SRichard Fitzgerald 	switch (arizona->type) {
1087ea1f3339SRichard Fitzgerald 	case WM1831:
1088ea1f3339SRichard Fitzgerald 	case CS47L24:
1089ea1f3339SRichard Fitzgerald 		break; /* No LDO1 regulator */
1090ea1f3339SRichard Fitzgerald 	default:
10913cc72986SMark Brown 		ret = mfd_add_devices(arizona->dev, -1, early_devs,
10920848c94fSMark Brown 				      ARRAY_SIZE(early_devs), NULL, 0, NULL);
10933cc72986SMark Brown 		if (ret != 0) {
10943cc72986SMark Brown 			dev_err(dev, "Failed to add early children: %d\n", ret);
10953cc72986SMark Brown 			return ret;
10963cc72986SMark Brown 		}
1097ea1f3339SRichard Fitzgerald 		break;
1098ea1f3339SRichard Fitzgerald 	}
10993cc72986SMark Brown 
11003cc72986SMark Brown 	ret = devm_regulator_bulk_get(dev, arizona->num_core_supplies,
11013cc72986SMark Brown 				      arizona->core_supplies);
11023cc72986SMark Brown 	if (ret != 0) {
11033cc72986SMark Brown 		dev_err(dev, "Failed to request core supplies: %d\n",
11043cc72986SMark Brown 			ret);
11053cc72986SMark Brown 		goto err_early;
11063cc72986SMark Brown 	}
11073cc72986SMark Brown 
11080c2d0ffbSCharles Keepax 	/**
11090c2d0ffbSCharles Keepax 	 * Don't use devres here because the only device we have to get
11100c2d0ffbSCharles Keepax 	 * against is the MFD device and DCVDD will likely be supplied by
11110c2d0ffbSCharles Keepax 	 * one of its children. Meaning that the regulator will be
11120c2d0ffbSCharles Keepax 	 * destroyed by the time devres calls regulator put.
11130c2d0ffbSCharles Keepax 	 */
1114e6021511SCharles Keepax 	arizona->dcvdd = regulator_get(arizona->dev, "DCVDD");
111559db9691SMark Brown 	if (IS_ERR(arizona->dcvdd)) {
111659db9691SMark Brown 		ret = PTR_ERR(arizona->dcvdd);
111759db9691SMark Brown 		dev_err(dev, "Failed to request DCVDD: %d\n", ret);
111859db9691SMark Brown 		goto err_early;
111959db9691SMark Brown 	}
112059db9691SMark Brown 
112187d3af4aSMark Brown 	if (arizona->pdata.reset) {
112287d3af4aSMark Brown 		/* Start out with /RESET low to put the chip into reset */
11235f056bf0SCharles Keepax 		ret = devm_gpio_request_one(arizona->dev, arizona->pdata.reset,
112487d3af4aSMark Brown 					    GPIOF_DIR_OUT | GPIOF_INIT_LOW,
112587d3af4aSMark Brown 					    "arizona /RESET");
112687d3af4aSMark Brown 		if (ret != 0) {
112787d3af4aSMark Brown 			dev_err(dev, "Failed to request /RESET: %d\n", ret);
1128e6021511SCharles Keepax 			goto err_dcvdd;
112987d3af4aSMark Brown 		}
113087d3af4aSMark Brown 	}
113187d3af4aSMark Brown 
11323cc72986SMark Brown 	ret = regulator_bulk_enable(arizona->num_core_supplies,
11333cc72986SMark Brown 				    arizona->core_supplies);
11343cc72986SMark Brown 	if (ret != 0) {
11353cc72986SMark Brown 		dev_err(dev, "Failed to enable core supplies: %d\n",
11363cc72986SMark Brown 			ret);
1137e6021511SCharles Keepax 		goto err_dcvdd;
11383cc72986SMark Brown 	}
11393cc72986SMark Brown 
114059db9691SMark Brown 	ret = regulator_enable(arizona->dcvdd);
114159db9691SMark Brown 	if (ret != 0) {
114259db9691SMark Brown 		dev_err(dev, "Failed to enable DCVDD: %d\n", ret);
114359db9691SMark Brown 		goto err_enable;
114459db9691SMark Brown 	}
114559db9691SMark Brown 
11462229875dSCharles Keepax 	arizona_disable_reset(arizona);
11473cc72986SMark Brown 
11483cc72986SMark Brown 	regcache_cache_only(arizona->regmap, false);
11493cc72986SMark Brown 
1150ca76ceb8SMark Brown 	/* Verify that this is a chip we know about */
1151ca76ceb8SMark Brown 	ret = regmap_read(arizona->regmap, ARIZONA_SOFTWARE_RESET, &reg);
1152ca76ceb8SMark Brown 	if (ret != 0) {
1153ca76ceb8SMark Brown 		dev_err(dev, "Failed to read ID register: %d\n", ret);
1154ca76ceb8SMark Brown 		goto err_reset;
1155ca76ceb8SMark Brown 	}
1156ca76ceb8SMark Brown 
1157ca76ceb8SMark Brown 	switch (reg) {
1158ca76ceb8SMark Brown 	case 0x5102:
1159ca76ceb8SMark Brown 	case 0x5110:
11606887b042SRichard Fitzgerald 	case 0x6349:
1161ea1f3339SRichard Fitzgerald 	case 0x6363:
1162dc7d4863SCharles Keepax 	case 0x8997:
1163ca76ceb8SMark Brown 		break;
1164ca76ceb8SMark Brown 	default:
1165ca76ceb8SMark Brown 		dev_err(arizona->dev, "Unknown device ID: %x\n", reg);
116675d8a2b0SCharles Keepax 		ret = -ENODEV;
1167ca76ceb8SMark Brown 		goto err_reset;
1168ca76ceb8SMark Brown 	}
1169ca76ceb8SMark Brown 
1170ca76ceb8SMark Brown 	/* If we have a /RESET GPIO we'll already be reset */
1171ca76ceb8SMark Brown 	if (!arizona->pdata.reset) {
1172ca76ceb8SMark Brown 		ret = regmap_write(arizona->regmap, ARIZONA_SOFTWARE_RESET, 0);
1173ca76ceb8SMark Brown 		if (ret != 0) {
1174ca76ceb8SMark Brown 			dev_err(dev, "Failed to reset device: %d\n", ret);
1175ca76ceb8SMark Brown 			goto err_reset;
1176ca76ceb8SMark Brown 		}
1177ca76ceb8SMark Brown 
1178b79a980fSLee Jones 		usleep_range(1000, 5000);
1179ca76ceb8SMark Brown 	}
1180ca76ceb8SMark Brown 
1181ca76ceb8SMark Brown 	/* Ensure device startup is complete */
1182ca76ceb8SMark Brown 	switch (arizona->type) {
1183ca76ceb8SMark Brown 	case WM5102:
118448018943SMark Brown 		ret = regmap_read(arizona->regmap,
118548018943SMark Brown 				  ARIZONA_WRITE_SEQUENCER_CTRL_3, &val);
11861c1c6bbaSCharles Keepax 		if (ret) {
1187ca76ceb8SMark Brown 			dev_err(dev,
1188ca76ceb8SMark Brown 				"Failed to check write sequencer state: %d\n",
1189ca76ceb8SMark Brown 				ret);
11901c1c6bbaSCharles Keepax 		} else if (val & 0x01) {
11911c1c6bbaSCharles Keepax 			ret = wm5102_clear_write_sequencer(arizona);
11921c1c6bbaSCharles Keepax 			if (ret)
11931c1c6bbaSCharles Keepax 				return ret;
1194ca76ceb8SMark Brown 		}
1195ca76ceb8SMark Brown 		break;
11961c1c6bbaSCharles Keepax 	default:
11971c1c6bbaSCharles Keepax 		break;
11981c1c6bbaSCharles Keepax 	}
11991c1c6bbaSCharles Keepax 
12001c1c6bbaSCharles Keepax 	ret = arizona_wait_for_boot(arizona);
12011c1c6bbaSCharles Keepax 	if (ret) {
12021c1c6bbaSCharles Keepax 		dev_err(arizona->dev, "Device failed initial boot: %d\n", ret);
12031c1c6bbaSCharles Keepax 		goto err_reset;
1204ca76ceb8SMark Brown 	}
1205ca76ceb8SMark Brown 
1206ca76ceb8SMark Brown 	/* Read the device ID information & do device specific stuff */
12073cc72986SMark Brown 	ret = regmap_read(arizona->regmap, ARIZONA_SOFTWARE_RESET, &reg);
12083cc72986SMark Brown 	if (ret != 0) {
12093cc72986SMark Brown 		dev_err(dev, "Failed to read ID register: %d\n", ret);
121059db9691SMark Brown 		goto err_reset;
12113cc72986SMark Brown 	}
12123cc72986SMark Brown 
12133cc72986SMark Brown 	ret = regmap_read(arizona->regmap, ARIZONA_DEVICE_REVISION,
12143cc72986SMark Brown 			  &arizona->rev);
12153cc72986SMark Brown 	if (ret != 0) {
12163cc72986SMark Brown 		dev_err(dev, "Failed to read revision register: %d\n", ret);
121759db9691SMark Brown 		goto err_reset;
12183cc72986SMark Brown 	}
12193cc72986SMark Brown 	arizona->rev &= ARIZONA_DEVICE_REVISION_MASK;
12203cc72986SMark Brown 
12213cc72986SMark Brown 	switch (reg) {
12223cc72986SMark Brown 	case 0x5102:
1223b61c1ec0SRichard Fitzgerald 		if (IS_ENABLED(CONFIG_MFD_WM5102)) {
12243cc72986SMark Brown 			type_name = "WM5102";
12253cc72986SMark Brown 			if (arizona->type != WM5102) {
1226b61c1ec0SRichard Fitzgerald 				dev_warn(arizona->dev,
1227b61c1ec0SRichard Fitzgerald 					 "WM5102 registered as %d\n",
12283cc72986SMark Brown 					 arizona->type);
12293cc72986SMark Brown 				arizona->type = WM5102;
12303cc72986SMark Brown 			}
1231b61c1ec0SRichard Fitzgerald 
123262d62b59SMark Brown 			apply_patch = wm5102_patch;
1233c6d6bfb1SMark Brown 			arizona->rev &= 0x7;
1234ae05ea36SRichard Fitzgerald 			subdevs = wm5102_devs;
1235ae05ea36SRichard Fitzgerald 			n_subdevs = ARRAY_SIZE(wm5102_devs);
1236b61c1ec0SRichard Fitzgerald 		}
12373cc72986SMark Brown 		break;
1238e102befeSMark Brown 	case 0x5110:
1239b61c1ec0SRichard Fitzgerald 		if (IS_ENABLED(CONFIG_MFD_WM5110)) {
1240e5d4ef0dSRichard Fitzgerald 			switch (arizona->type) {
1241e5d4ef0dSRichard Fitzgerald 			case WM5110:
1242e102befeSMark Brown 				type_name = "WM5110";
1243e5d4ef0dSRichard Fitzgerald 				break;
1244e5d4ef0dSRichard Fitzgerald 			case WM8280:
1245e5d4ef0dSRichard Fitzgerald 				type_name = "WM8280";
1246e5d4ef0dSRichard Fitzgerald 				break;
1247e5d4ef0dSRichard Fitzgerald 			default:
1248e5d4ef0dSRichard Fitzgerald 				type_name = "WM5110";
1249b61c1ec0SRichard Fitzgerald 				dev_warn(arizona->dev,
1250b61c1ec0SRichard Fitzgerald 					 "WM5110 registered as %d\n",
1251e102befeSMark Brown 					 arizona->type);
1252e102befeSMark Brown 				arizona->type = WM5110;
1253e5d4ef0dSRichard Fitzgerald 				break;
1254e102befeSMark Brown 			}
1255b61c1ec0SRichard Fitzgerald 
125662d62b59SMark Brown 			apply_patch = wm5110_patch;
1257ae05ea36SRichard Fitzgerald 			subdevs = wm5110_devs;
1258ae05ea36SRichard Fitzgerald 			n_subdevs = ARRAY_SIZE(wm5110_devs);
1259b61c1ec0SRichard Fitzgerald 		}
1260e102befeSMark Brown 		break;
1261ea1f3339SRichard Fitzgerald 	case 0x6363:
1262ea1f3339SRichard Fitzgerald 		if (IS_ENABLED(CONFIG_MFD_CS47L24)) {
1263ea1f3339SRichard Fitzgerald 			switch (arizona->type) {
1264ea1f3339SRichard Fitzgerald 			case CS47L24:
1265ea1f3339SRichard Fitzgerald 				type_name = "CS47L24";
1266ea1f3339SRichard Fitzgerald 				break;
1267ea1f3339SRichard Fitzgerald 
1268ea1f3339SRichard Fitzgerald 			case WM1831:
1269ea1f3339SRichard Fitzgerald 				type_name = "WM1831";
1270ea1f3339SRichard Fitzgerald 				break;
1271ea1f3339SRichard Fitzgerald 
1272ea1f3339SRichard Fitzgerald 			default:
1273ea1f3339SRichard Fitzgerald 				dev_warn(arizona->dev,
1274ea1f3339SRichard Fitzgerald 					 "CS47L24 registered as %d\n",
1275ea1f3339SRichard Fitzgerald 					 arizona->type);
1276ea1f3339SRichard Fitzgerald 				arizona->type = CS47L24;
1277ea1f3339SRichard Fitzgerald 				break;
1278ea1f3339SRichard Fitzgerald 			}
1279ea1f3339SRichard Fitzgerald 
1280ea1f3339SRichard Fitzgerald 			apply_patch = cs47l24_patch;
1281ea1f3339SRichard Fitzgerald 			subdevs = cs47l24_devs;
1282ea1f3339SRichard Fitzgerald 			n_subdevs = ARRAY_SIZE(cs47l24_devs);
1283ea1f3339SRichard Fitzgerald 		}
1284ea1f3339SRichard Fitzgerald 		break;
1285dc7d4863SCharles Keepax 	case 0x8997:
1286b61c1ec0SRichard Fitzgerald 		if (IS_ENABLED(CONFIG_MFD_WM8997)) {
1287dc7d4863SCharles Keepax 			type_name = "WM8997";
1288dc7d4863SCharles Keepax 			if (arizona->type != WM8997) {
1289b61c1ec0SRichard Fitzgerald 				dev_warn(arizona->dev,
1290b61c1ec0SRichard Fitzgerald 					 "WM8997 registered as %d\n",
1291dc7d4863SCharles Keepax 					 arizona->type);
1292dc7d4863SCharles Keepax 				arizona->type = WM8997;
1293dc7d4863SCharles Keepax 			}
1294b61c1ec0SRichard Fitzgerald 
1295dc7d4863SCharles Keepax 			apply_patch = wm8997_patch;
1296ae05ea36SRichard Fitzgerald 			subdevs = wm8997_devs;
1297ae05ea36SRichard Fitzgerald 			n_subdevs = ARRAY_SIZE(wm8997_devs);
1298b61c1ec0SRichard Fitzgerald 		}
1299dc7d4863SCharles Keepax 		break;
13006887b042SRichard Fitzgerald 	case 0x6349:
1301b61c1ec0SRichard Fitzgerald 		if (IS_ENABLED(CONFIG_MFD_WM8998)) {
13026887b042SRichard Fitzgerald 			switch (arizona->type) {
13036887b042SRichard Fitzgerald 			case WM8998:
13046887b042SRichard Fitzgerald 				type_name = "WM8998";
13056887b042SRichard Fitzgerald 				break;
13066887b042SRichard Fitzgerald 
13076887b042SRichard Fitzgerald 			case WM1814:
13086887b042SRichard Fitzgerald 				type_name = "WM1814";
13096887b042SRichard Fitzgerald 				break;
13106887b042SRichard Fitzgerald 
13116887b042SRichard Fitzgerald 			default:
13126887b042SRichard Fitzgerald 				type_name = "WM8998";
1313b61c1ec0SRichard Fitzgerald 				dev_warn(arizona->dev,
1314b61c1ec0SRichard Fitzgerald 					 "WM8998 registered as %d\n",
13156887b042SRichard Fitzgerald 					 arizona->type);
13166887b042SRichard Fitzgerald 				arizona->type = WM8998;
13176887b042SRichard Fitzgerald 			}
13186887b042SRichard Fitzgerald 
13196887b042SRichard Fitzgerald 			apply_patch = wm8998_patch;
1320ae05ea36SRichard Fitzgerald 			subdevs = wm8998_devs;
1321ae05ea36SRichard Fitzgerald 			n_subdevs = ARRAY_SIZE(wm8998_devs);
1322b61c1ec0SRichard Fitzgerald 		}
13236887b042SRichard Fitzgerald 		break;
13243cc72986SMark Brown 	default:
13253cc72986SMark Brown 		dev_err(arizona->dev, "Unknown device ID %x\n", reg);
132675d8a2b0SCharles Keepax 		ret = -ENODEV;
132759db9691SMark Brown 		goto err_reset;
13283cc72986SMark Brown 	}
13293cc72986SMark Brown 
1330b61c1ec0SRichard Fitzgerald 	if (!subdevs) {
1331b61c1ec0SRichard Fitzgerald 		dev_err(arizona->dev,
1332b61c1ec0SRichard Fitzgerald 			"No kernel support for device ID %x\n", reg);
133375d8a2b0SCharles Keepax 		ret = -ENODEV;
1334b61c1ec0SRichard Fitzgerald 		goto err_reset;
1335b61c1ec0SRichard Fitzgerald 	}
1336b61c1ec0SRichard Fitzgerald 
13373cc72986SMark Brown 	dev_info(dev, "%s revision %c\n", type_name, arizona->rev + 'A');
13383cc72986SMark Brown 
133962d62b59SMark Brown 	if (apply_patch) {
134062d62b59SMark Brown 		ret = apply_patch(arizona);
134162d62b59SMark Brown 		if (ret != 0) {
134262d62b59SMark Brown 			dev_err(arizona->dev, "Failed to apply patch: %d\n",
134362d62b59SMark Brown 				ret);
134462d62b59SMark Brown 			goto err_reset;
134562d62b59SMark Brown 		}
1346e80436bbSCharles Keepax 
1347e80436bbSCharles Keepax 		switch (arizona->type) {
1348e80436bbSCharles Keepax 		case WM5102:
13490be068a0SCharles Keepax 			ret = wm5102_apply_hardware_patch(arizona);
13500be068a0SCharles Keepax 			if (ret) {
1351e80436bbSCharles Keepax 				dev_err(arizona->dev,
1352e80436bbSCharles Keepax 					"Failed to apply hardware patch: %d\n",
1353e80436bbSCharles Keepax 					ret);
1354e80436bbSCharles Keepax 				goto err_reset;
1355e80436bbSCharles Keepax 			}
1356e80436bbSCharles Keepax 			break;
1357882bc468SCharles Keepax 		case WM5110:
1358882bc468SCharles Keepax 		case WM8280:
1359882bc468SCharles Keepax 			ret = wm5110_apply_sleep_patch(arizona);
1360882bc468SCharles Keepax 			if (ret) {
1361882bc468SCharles Keepax 				dev_err(arizona->dev,
1362882bc468SCharles Keepax 					"Failed to apply sleep patch: %d\n",
1363882bc468SCharles Keepax 					ret);
1364882bc468SCharles Keepax 				goto err_reset;
1365882bc468SCharles Keepax 			}
1366882bc468SCharles Keepax 			break;
1367e80436bbSCharles Keepax 		default:
1368e80436bbSCharles Keepax 			break;
1369e80436bbSCharles Keepax 		}
137062d62b59SMark Brown 	}
137162d62b59SMark Brown 
13723cc72986SMark Brown 	for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) {
13733cc72986SMark Brown 		if (!arizona->pdata.gpio_defaults[i])
13743cc72986SMark Brown 			continue;
13753cc72986SMark Brown 
13763cc72986SMark Brown 		regmap_write(arizona->regmap, ARIZONA_GPIO1_CTRL + i,
13773cc72986SMark Brown 			     arizona->pdata.gpio_defaults[i]);
13783cc72986SMark Brown 	}
13793cc72986SMark Brown 
13803cc72986SMark Brown 	/* Chip default */
13813cc72986SMark Brown 	if (!arizona->pdata.clk32k_src)
13823cc72986SMark Brown 		arizona->pdata.clk32k_src = ARIZONA_32KZ_MCLK2;
13833cc72986SMark Brown 
13843cc72986SMark Brown 	switch (arizona->pdata.clk32k_src) {
13853cc72986SMark Brown 	case ARIZONA_32KZ_MCLK1:
13863cc72986SMark Brown 	case ARIZONA_32KZ_MCLK2:
13873cc72986SMark Brown 		regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1,
13883cc72986SMark Brown 				   ARIZONA_CLK_32K_SRC_MASK,
13893cc72986SMark Brown 				   arizona->pdata.clk32k_src - 1);
1390767c6dc0SMark Brown 		arizona_clk32k_enable(arizona);
13913cc72986SMark Brown 		break;
13923cc72986SMark Brown 	case ARIZONA_32KZ_NONE:
13933cc72986SMark Brown 		regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1,
13943cc72986SMark Brown 				   ARIZONA_CLK_32K_SRC_MASK, 2);
13953cc72986SMark Brown 		break;
13963cc72986SMark Brown 	default:
13973cc72986SMark Brown 		dev_err(arizona->dev, "Invalid 32kHz clock source: %d\n",
13983cc72986SMark Brown 			arizona->pdata.clk32k_src);
13993cc72986SMark Brown 		ret = -EINVAL;
140059db9691SMark Brown 		goto err_reset;
14013cc72986SMark Brown 	}
14023cc72986SMark Brown 
14033d91f828SMark Brown 	for (i = 0; i < ARIZONA_MAX_MICBIAS; i++) {
1404544c7aadSMark Brown 		if (!arizona->pdata.micbias[i].mV &&
1405544c7aadSMark Brown 		    !arizona->pdata.micbias[i].bypass)
14063d91f828SMark Brown 			continue;
14073d91f828SMark Brown 
1408544c7aadSMark Brown 		/* Apply default for bypass mode */
1409544c7aadSMark Brown 		if (!arizona->pdata.micbias[i].mV)
1410544c7aadSMark Brown 			arizona->pdata.micbias[i].mV = 2800;
1411544c7aadSMark Brown 
14123d91f828SMark Brown 		val = (arizona->pdata.micbias[i].mV - 1500) / 100;
1413544c7aadSMark Brown 
14143d91f828SMark Brown 		val <<= ARIZONA_MICB1_LVL_SHIFT;
14153d91f828SMark Brown 
14163d91f828SMark Brown 		if (arizona->pdata.micbias[i].ext_cap)
14173d91f828SMark Brown 			val |= ARIZONA_MICB1_EXT_CAP;
14183d91f828SMark Brown 
14193d91f828SMark Brown 		if (arizona->pdata.micbias[i].discharge)
14203d91f828SMark Brown 			val |= ARIZONA_MICB1_DISCH;
14213d91f828SMark Brown 
1422f773fc6dSCharles Keepax 		if (arizona->pdata.micbias[i].soft_start)
14233d91f828SMark Brown 			val |= ARIZONA_MICB1_RATE;
14243d91f828SMark Brown 
1425544c7aadSMark Brown 		if (arizona->pdata.micbias[i].bypass)
1426544c7aadSMark Brown 			val |= ARIZONA_MICB1_BYPASS;
1427544c7aadSMark Brown 
14283d91f828SMark Brown 		regmap_update_bits(arizona->regmap,
14293d91f828SMark Brown 				   ARIZONA_MIC_BIAS_CTRL_1 + i,
14303d91f828SMark Brown 				   ARIZONA_MICB1_LVL_MASK |
143171d134b9SCharles Keepax 				   ARIZONA_MICB1_EXT_CAP |
14323d91f828SMark Brown 				   ARIZONA_MICB1_DISCH |
1433544c7aadSMark Brown 				   ARIZONA_MICB1_BYPASS |
14343d91f828SMark Brown 				   ARIZONA_MICB1_RATE, val);
14353d91f828SMark Brown 	}
14363d91f828SMark Brown 
14373cc72986SMark Brown 	for (i = 0; i < ARIZONA_MAX_INPUT; i++) {
14383cc72986SMark Brown 		/* Default for both is 0 so noop with defaults */
14393cc72986SMark Brown 		val = arizona->pdata.dmic_ref[i]
14403cc72986SMark Brown 			<< ARIZONA_IN1_DMIC_SUP_SHIFT;
1441fc027d13SRichard Fitzgerald 		if (arizona->pdata.inmode[i] & ARIZONA_INMODE_DMIC)
1442fc027d13SRichard Fitzgerald 			val |= 1 << ARIZONA_IN1_MODE_SHIFT;
14436887b042SRichard Fitzgerald 
14446887b042SRichard Fitzgerald 		switch (arizona->type) {
14456887b042SRichard Fitzgerald 		case WM8998:
14466887b042SRichard Fitzgerald 		case WM1814:
14476887b042SRichard Fitzgerald 			regmap_update_bits(arizona->regmap,
14486887b042SRichard Fitzgerald 				ARIZONA_ADC_DIGITAL_VOLUME_1L + (i * 8),
14496887b042SRichard Fitzgerald 				ARIZONA_IN1L_SRC_SE_MASK,
14506887b042SRichard Fitzgerald 				(arizona->pdata.inmode[i] & ARIZONA_INMODE_SE)
14516887b042SRichard Fitzgerald 					<< ARIZONA_IN1L_SRC_SE_SHIFT);
14526887b042SRichard Fitzgerald 
14536887b042SRichard Fitzgerald 			regmap_update_bits(arizona->regmap,
14546887b042SRichard Fitzgerald 				ARIZONA_ADC_DIGITAL_VOLUME_1R + (i * 8),
14556887b042SRichard Fitzgerald 				ARIZONA_IN1R_SRC_SE_MASK,
14566887b042SRichard Fitzgerald 				(arizona->pdata.inmode[i] & ARIZONA_INMODE_SE)
14576887b042SRichard Fitzgerald 					<< ARIZONA_IN1R_SRC_SE_SHIFT);
14586887b042SRichard Fitzgerald 
14596887b042SRichard Fitzgerald 			mask = ARIZONA_IN1_DMIC_SUP_MASK |
14606887b042SRichard Fitzgerald 				ARIZONA_IN1_MODE_MASK;
14616887b042SRichard Fitzgerald 			break;
14626887b042SRichard Fitzgerald 		default:
1463fc027d13SRichard Fitzgerald 			if (arizona->pdata.inmode[i] & ARIZONA_INMODE_SE)
1464fc027d13SRichard Fitzgerald 				val |= 1 << ARIZONA_IN1_SINGLE_ENDED_SHIFT;
14653cc72986SMark Brown 
14666887b042SRichard Fitzgerald 			mask = ARIZONA_IN1_DMIC_SUP_MASK |
14676887b042SRichard Fitzgerald 				ARIZONA_IN1_MODE_MASK |
14686887b042SRichard Fitzgerald 				ARIZONA_IN1_SINGLE_ENDED_MASK;
14696887b042SRichard Fitzgerald 			break;
14706887b042SRichard Fitzgerald 		}
14716887b042SRichard Fitzgerald 
14723cc72986SMark Brown 		regmap_update_bits(arizona->regmap,
14733cc72986SMark Brown 				   ARIZONA_IN1L_CONTROL + (i * 8),
14746887b042SRichard Fitzgerald 				   mask, val);
14753cc72986SMark Brown 	}
14763cc72986SMark Brown 
14773cc72986SMark Brown 	for (i = 0; i < ARIZONA_MAX_OUTPUT; i++) {
14783cc72986SMark Brown 		/* Default is 0 so noop with defaults */
14793cc72986SMark Brown 		if (arizona->pdata.out_mono[i])
14803cc72986SMark Brown 			val = ARIZONA_OUT1_MONO;
14813cc72986SMark Brown 		else
14823cc72986SMark Brown 			val = 0;
14833cc72986SMark Brown 
14843cc72986SMark Brown 		regmap_update_bits(arizona->regmap,
14853cc72986SMark Brown 				   ARIZONA_OUTPUT_PATH_CONFIG_1L + (i * 8),
14863cc72986SMark Brown 				   ARIZONA_OUT1_MONO, val);
14873cc72986SMark Brown 	}
14883cc72986SMark Brown 
14893cc72986SMark Brown 	for (i = 0; i < ARIZONA_MAX_PDM_SPK; i++) {
14903cc72986SMark Brown 		if (arizona->pdata.spk_mute[i])
14913cc72986SMark Brown 			regmap_update_bits(arizona->regmap,
14922a51da04SMark Brown 					   ARIZONA_PDM_SPK1_CTRL_1 + (i * 2),
14933cc72986SMark Brown 					   ARIZONA_SPK1_MUTE_ENDIAN_MASK |
14943cc72986SMark Brown 					   ARIZONA_SPK1_MUTE_SEQ1_MASK,
14953cc72986SMark Brown 					   arizona->pdata.spk_mute[i]);
14963cc72986SMark Brown 
14973cc72986SMark Brown 		if (arizona->pdata.spk_fmt[i])
14983cc72986SMark Brown 			regmap_update_bits(arizona->regmap,
14992a51da04SMark Brown 					   ARIZONA_PDM_SPK1_CTRL_2 + (i * 2),
15003cc72986SMark Brown 					   ARIZONA_SPK1_FMT_MASK,
15013cc72986SMark Brown 					   arizona->pdata.spk_fmt[i]);
15023cc72986SMark Brown 	}
15033cc72986SMark Brown 
150472e43164SCharles Keepax 	pm_runtime_set_active(arizona->dev);
150572e43164SCharles Keepax 	pm_runtime_enable(arizona->dev);
150672e43164SCharles Keepax 
15073cc72986SMark Brown 	/* Set up for interrupts */
15083cc72986SMark Brown 	ret = arizona_irq_init(arizona);
15093cc72986SMark Brown 	if (ret != 0)
1510d347792cSCharles Keepax 		goto err_pm;
15113cc72986SMark Brown 
151272e43164SCharles Keepax 	pm_runtime_set_autosuspend_delay(arizona->dev, 100);
151372e43164SCharles Keepax 	pm_runtime_use_autosuspend(arizona->dev);
151472e43164SCharles Keepax 
15153cc72986SMark Brown 	arizona_request_irq(arizona, ARIZONA_IRQ_CLKGEN_ERR, "CLKGEN error",
15163cc72986SMark Brown 			    arizona_clkgen_err, arizona);
15173cc72986SMark Brown 	arizona_request_irq(arizona, ARIZONA_IRQ_OVERCLOCKED, "Overclocked",
15183cc72986SMark Brown 			    arizona_overclocked, arizona);
15193cc72986SMark Brown 	arizona_request_irq(arizona, ARIZONA_IRQ_UNDERCLOCKED, "Underclocked",
15203cc72986SMark Brown 			    arizona_underclocked, arizona);
15213cc72986SMark Brown 
1522ae05ea36SRichard Fitzgerald 	ret = mfd_add_devices(arizona->dev, PLATFORM_DEVID_NONE,
1523ae05ea36SRichard Fitzgerald 			      subdevs, n_subdevs, NULL, 0, NULL);
15243cc72986SMark Brown 
1525ae05ea36SRichard Fitzgerald 	if (ret) {
15263cc72986SMark Brown 		dev_err(arizona->dev, "Failed to add subdevices: %d\n", ret);
15273cc72986SMark Brown 		goto err_irq;
15283cc72986SMark Brown 	}
15293cc72986SMark Brown 
15303cc72986SMark Brown 	return 0;
15313cc72986SMark Brown 
15323cc72986SMark Brown err_irq:
15333cc72986SMark Brown 	arizona_irq_exit(arizona);
1534d347792cSCharles Keepax err_pm:
1535d347792cSCharles Keepax 	pm_runtime_disable(arizona->dev);
15363cc72986SMark Brown err_reset:
15372229875dSCharles Keepax 	arizona_enable_reset(arizona);
153859db9691SMark Brown 	regulator_disable(arizona->dcvdd);
15393cc72986SMark Brown err_enable:
15403a36a0dbSMark Brown 	regulator_bulk_disable(arizona->num_core_supplies,
15413cc72986SMark Brown 			       arizona->core_supplies);
1542e6021511SCharles Keepax err_dcvdd:
1543e6021511SCharles Keepax 	regulator_put(arizona->dcvdd);
15443cc72986SMark Brown err_early:
15453cc72986SMark Brown 	mfd_remove_devices(dev);
15463cc72986SMark Brown 	return ret;
15473cc72986SMark Brown }
15483cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_dev_init);
15493cc72986SMark Brown 
15504740f73fSBill Pemberton int arizona_dev_exit(struct arizona *arizona)
15513cc72986SMark Brown {
1552fb36f77eSCharles Keepax 	disable_irq(arizona->irq);
1553b804020aSCharles Keepax 	pm_runtime_disable(arizona->dev);
1554b804020aSCharles Keepax 
1555df6b3352SCharles Keepax 	regulator_disable(arizona->dcvdd);
1556e6021511SCharles Keepax 	regulator_put(arizona->dcvdd);
1557df6b3352SCharles Keepax 
15583cc72986SMark Brown 	mfd_remove_devices(arizona->dev);
15593cc72986SMark Brown 	arizona_free_irq(arizona, ARIZONA_IRQ_UNDERCLOCKED, arizona);
15603cc72986SMark Brown 	arizona_free_irq(arizona, ARIZONA_IRQ_OVERCLOCKED, arizona);
15613cc72986SMark Brown 	arizona_free_irq(arizona, ARIZONA_IRQ_CLKGEN_ERR, arizona);
15623cc72986SMark Brown 	arizona_irq_exit(arizona);
15632229875dSCharles Keepax 	arizona_enable_reset(arizona);
1564df6b3352SCharles Keepax 
15654420286eSCharles Keepax 	regulator_bulk_disable(arizona->num_core_supplies,
15661d017b6bSMark Brown 			       arizona->core_supplies);
15673cc72986SMark Brown 	return 0;
15683cc72986SMark Brown }
15693cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_dev_exit);
1570