xref: /linux/drivers/mfd/arizona-core.c (revision ca76ceb8b9ca1466be9b6de5e4c0fb19b37417ee)
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 
133cc72986SMark Brown #include <linux/delay.h>
1459db9691SMark Brown #include <linux/err.h>
153cc72986SMark Brown #include <linux/gpio.h>
163cc72986SMark Brown #include <linux/interrupt.h>
173cc72986SMark Brown #include <linux/mfd/core.h>
183cc72986SMark Brown #include <linux/module.h>
193cc72986SMark Brown #include <linux/pm_runtime.h>
203cc72986SMark Brown #include <linux/regmap.h>
213cc72986SMark Brown #include <linux/regulator/consumer.h>
223cc72986SMark Brown #include <linux/slab.h>
233cc72986SMark Brown 
243cc72986SMark Brown #include <linux/mfd/arizona/core.h>
253cc72986SMark Brown #include <linux/mfd/arizona/registers.h>
263cc72986SMark Brown 
273cc72986SMark Brown #include "arizona.h"
283cc72986SMark Brown 
293cc72986SMark Brown static const char *wm5102_core_supplies[] = {
303cc72986SMark Brown 	"AVDD",
313cc72986SMark Brown 	"DBVDD1",
323cc72986SMark Brown };
333cc72986SMark Brown 
343cc72986SMark Brown int arizona_clk32k_enable(struct arizona *arizona)
353cc72986SMark Brown {
363cc72986SMark Brown 	int ret = 0;
373cc72986SMark Brown 
383cc72986SMark Brown 	mutex_lock(&arizona->clk_lock);
393cc72986SMark Brown 
403cc72986SMark Brown 	arizona->clk32k_ref++;
413cc72986SMark Brown 
42247fa192SMark Brown 	if (arizona->clk32k_ref == 1) {
43247fa192SMark Brown 		switch (arizona->pdata.clk32k_src) {
44247fa192SMark Brown 		case ARIZONA_32KZ_MCLK1:
45247fa192SMark Brown 			ret = pm_runtime_get_sync(arizona->dev);
46247fa192SMark Brown 			if (ret != 0)
47247fa192SMark Brown 				goto out;
48247fa192SMark Brown 			break;
49247fa192SMark Brown 		}
50247fa192SMark Brown 
513cc72986SMark Brown 		ret = regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1,
523cc72986SMark Brown 					 ARIZONA_CLK_32K_ENA,
533cc72986SMark Brown 					 ARIZONA_CLK_32K_ENA);
54247fa192SMark Brown 	}
553cc72986SMark Brown 
56247fa192SMark Brown out:
573cc72986SMark Brown 	if (ret != 0)
583cc72986SMark Brown 		arizona->clk32k_ref--;
593cc72986SMark Brown 
603cc72986SMark Brown 	mutex_unlock(&arizona->clk_lock);
613cc72986SMark Brown 
623cc72986SMark Brown 	return ret;
633cc72986SMark Brown }
643cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_clk32k_enable);
653cc72986SMark Brown 
663cc72986SMark Brown int arizona_clk32k_disable(struct arizona *arizona)
673cc72986SMark Brown {
683cc72986SMark Brown 	int ret = 0;
693cc72986SMark Brown 
703cc72986SMark Brown 	mutex_lock(&arizona->clk_lock);
713cc72986SMark Brown 
723cc72986SMark Brown 	BUG_ON(arizona->clk32k_ref <= 0);
733cc72986SMark Brown 
743cc72986SMark Brown 	arizona->clk32k_ref--;
753cc72986SMark Brown 
76247fa192SMark Brown 	if (arizona->clk32k_ref == 0) {
773cc72986SMark Brown 		regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1,
783cc72986SMark Brown 				   ARIZONA_CLK_32K_ENA, 0);
793cc72986SMark Brown 
80247fa192SMark Brown 		switch (arizona->pdata.clk32k_src) {
81247fa192SMark Brown 		case ARIZONA_32KZ_MCLK1:
82247fa192SMark Brown 			pm_runtime_put_sync(arizona->dev);
83247fa192SMark Brown 			break;
84247fa192SMark Brown 		}
85247fa192SMark Brown 	}
86247fa192SMark Brown 
873cc72986SMark Brown 	mutex_unlock(&arizona->clk_lock);
883cc72986SMark Brown 
893cc72986SMark Brown 	return ret;
903cc72986SMark Brown }
913cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_clk32k_disable);
923cc72986SMark Brown 
933cc72986SMark Brown static irqreturn_t arizona_clkgen_err(int irq, void *data)
943cc72986SMark Brown {
953cc72986SMark Brown 	struct arizona *arizona = data;
963cc72986SMark Brown 
973cc72986SMark Brown 	dev_err(arizona->dev, "CLKGEN error\n");
983cc72986SMark Brown 
993cc72986SMark Brown 	return IRQ_HANDLED;
1003cc72986SMark Brown }
1013cc72986SMark Brown 
1023cc72986SMark Brown static irqreturn_t arizona_underclocked(int irq, void *data)
1033cc72986SMark Brown {
1043cc72986SMark Brown 	struct arizona *arizona = data;
1053cc72986SMark Brown 	unsigned int val;
1063cc72986SMark Brown 	int ret;
1073cc72986SMark Brown 
1083cc72986SMark Brown 	ret = regmap_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_8,
1093cc72986SMark Brown 			  &val);
1103cc72986SMark Brown 	if (ret != 0) {
1113cc72986SMark Brown 		dev_err(arizona->dev, "Failed to read underclock status: %d\n",
1123cc72986SMark Brown 			ret);
1133cc72986SMark Brown 		return IRQ_NONE;
1143cc72986SMark Brown 	}
1153cc72986SMark Brown 
1163cc72986SMark Brown 	if (val & ARIZONA_AIF3_UNDERCLOCKED_STS)
1173cc72986SMark Brown 		dev_err(arizona->dev, "AIF3 underclocked\n");
1183cc72986SMark Brown 	if (val & ARIZONA_AIF2_UNDERCLOCKED_STS)
1193ebef34dSCharles Keepax 		dev_err(arizona->dev, "AIF2 underclocked\n");
1203ebef34dSCharles Keepax 	if (val & ARIZONA_AIF1_UNDERCLOCKED_STS)
1213cc72986SMark Brown 		dev_err(arizona->dev, "AIF1 underclocked\n");
1223cc72986SMark Brown 	if (val & ARIZONA_ISRC2_UNDERCLOCKED_STS)
1233cc72986SMark Brown 		dev_err(arizona->dev, "ISRC2 underclocked\n");
1243cc72986SMark Brown 	if (val & ARIZONA_ISRC1_UNDERCLOCKED_STS)
1253cc72986SMark Brown 		dev_err(arizona->dev, "ISRC1 underclocked\n");
1263cc72986SMark Brown 	if (val & ARIZONA_FX_UNDERCLOCKED_STS)
1273cc72986SMark Brown 		dev_err(arizona->dev, "FX underclocked\n");
1283cc72986SMark Brown 	if (val & ARIZONA_ASRC_UNDERCLOCKED_STS)
1293cc72986SMark Brown 		dev_err(arizona->dev, "ASRC underclocked\n");
1303cc72986SMark Brown 	if (val & ARIZONA_DAC_UNDERCLOCKED_STS)
1313cc72986SMark Brown 		dev_err(arizona->dev, "DAC underclocked\n");
1323cc72986SMark Brown 	if (val & ARIZONA_ADC_UNDERCLOCKED_STS)
1333cc72986SMark Brown 		dev_err(arizona->dev, "ADC underclocked\n");
1343cc72986SMark Brown 	if (val & ARIZONA_MIXER_UNDERCLOCKED_STS)
135648a9880SMark Brown 		dev_err(arizona->dev, "Mixer dropped sample\n");
1363cc72986SMark Brown 
1373cc72986SMark Brown 	return IRQ_HANDLED;
1383cc72986SMark Brown }
1393cc72986SMark Brown 
1403cc72986SMark Brown static irqreturn_t arizona_overclocked(int irq, void *data)
1413cc72986SMark Brown {
1423cc72986SMark Brown 	struct arizona *arizona = data;
1433cc72986SMark Brown 	unsigned int val[2];
1443cc72986SMark Brown 	int ret;
1453cc72986SMark Brown 
1463cc72986SMark Brown 	ret = regmap_bulk_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_6,
1473cc72986SMark Brown 			       &val[0], 2);
1483cc72986SMark Brown 	if (ret != 0) {
1493cc72986SMark Brown 		dev_err(arizona->dev, "Failed to read overclock status: %d\n",
1503cc72986SMark Brown 			ret);
1513cc72986SMark Brown 		return IRQ_NONE;
1523cc72986SMark Brown 	}
1533cc72986SMark Brown 
1543cc72986SMark Brown 	if (val[0] & ARIZONA_PWM_OVERCLOCKED_STS)
1553cc72986SMark Brown 		dev_err(arizona->dev, "PWM overclocked\n");
1563cc72986SMark Brown 	if (val[0] & ARIZONA_FX_CORE_OVERCLOCKED_STS)
1573cc72986SMark Brown 		dev_err(arizona->dev, "FX core overclocked\n");
1583cc72986SMark Brown 	if (val[0] & ARIZONA_DAC_SYS_OVERCLOCKED_STS)
1593cc72986SMark Brown 		dev_err(arizona->dev, "DAC SYS overclocked\n");
1603cc72986SMark Brown 	if (val[0] & ARIZONA_DAC_WARP_OVERCLOCKED_STS)
1613cc72986SMark Brown 		dev_err(arizona->dev, "DAC WARP overclocked\n");
1623cc72986SMark Brown 	if (val[0] & ARIZONA_ADC_OVERCLOCKED_STS)
1633cc72986SMark Brown 		dev_err(arizona->dev, "ADC overclocked\n");
1643cc72986SMark Brown 	if (val[0] & ARIZONA_MIXER_OVERCLOCKED_STS)
1653cc72986SMark Brown 		dev_err(arizona->dev, "Mixer overclocked\n");
1663cc72986SMark Brown 	if (val[0] & ARIZONA_AIF3_SYNC_OVERCLOCKED_STS)
1673cc72986SMark Brown 		dev_err(arizona->dev, "AIF3 overclocked\n");
1683cc72986SMark Brown 	if (val[0] & ARIZONA_AIF2_SYNC_OVERCLOCKED_STS)
1693cc72986SMark Brown 		dev_err(arizona->dev, "AIF2 overclocked\n");
1703cc72986SMark Brown 	if (val[0] & ARIZONA_AIF1_SYNC_OVERCLOCKED_STS)
1713cc72986SMark Brown 		dev_err(arizona->dev, "AIF1 overclocked\n");
1723cc72986SMark Brown 	if (val[0] & ARIZONA_PAD_CTRL_OVERCLOCKED_STS)
1733cc72986SMark Brown 		dev_err(arizona->dev, "Pad control overclocked\n");
1743cc72986SMark Brown 
1753cc72986SMark Brown 	if (val[1] & ARIZONA_SLIMBUS_SUBSYS_OVERCLOCKED_STS)
1763cc72986SMark Brown 		dev_err(arizona->dev, "Slimbus subsystem overclocked\n");
1773cc72986SMark Brown 	if (val[1] & ARIZONA_SLIMBUS_ASYNC_OVERCLOCKED_STS)
1783cc72986SMark Brown 		dev_err(arizona->dev, "Slimbus async overclocked\n");
1793cc72986SMark Brown 	if (val[1] & ARIZONA_SLIMBUS_SYNC_OVERCLOCKED_STS)
1803cc72986SMark Brown 		dev_err(arizona->dev, "Slimbus sync overclocked\n");
1813cc72986SMark Brown 	if (val[1] & ARIZONA_ASRC_ASYNC_SYS_OVERCLOCKED_STS)
1823cc72986SMark Brown 		dev_err(arizona->dev, "ASRC async system overclocked\n");
1833cc72986SMark Brown 	if (val[1] & ARIZONA_ASRC_ASYNC_WARP_OVERCLOCKED_STS)
1843cc72986SMark Brown 		dev_err(arizona->dev, "ASRC async WARP overclocked\n");
1853cc72986SMark Brown 	if (val[1] & ARIZONA_ASRC_SYNC_SYS_OVERCLOCKED_STS)
1863cc72986SMark Brown 		dev_err(arizona->dev, "ASRC sync system overclocked\n");
1873cc72986SMark Brown 	if (val[1] & ARIZONA_ASRC_SYNC_WARP_OVERCLOCKED_STS)
1883cc72986SMark Brown 		dev_err(arizona->dev, "ASRC sync WARP overclocked\n");
1893cc72986SMark Brown 	if (val[1] & ARIZONA_ADSP2_1_OVERCLOCKED_STS)
1903cc72986SMark Brown 		dev_err(arizona->dev, "DSP1 overclocked\n");
1913cc72986SMark Brown 	if (val[1] & ARIZONA_ISRC2_OVERCLOCKED_STS)
1923cc72986SMark Brown 		dev_err(arizona->dev, "ISRC2 overclocked\n");
1933cc72986SMark Brown 	if (val[1] & ARIZONA_ISRC1_OVERCLOCKED_STS)
1943cc72986SMark Brown 		dev_err(arizona->dev, "ISRC1 overclocked\n");
1953cc72986SMark Brown 
1963cc72986SMark Brown 	return IRQ_HANDLED;
1973cc72986SMark Brown }
1983cc72986SMark Brown 
1999d53dfdcSCharles Keepax static int arizona_poll_reg(struct arizona *arizona,
2009d53dfdcSCharles Keepax 			    int timeout, unsigned int reg,
2019d53dfdcSCharles Keepax 			    unsigned int mask, unsigned int target)
2029d53dfdcSCharles Keepax {
2039d53dfdcSCharles Keepax 	unsigned int val = 0;
2049d53dfdcSCharles Keepax 	int ret, i;
2059d53dfdcSCharles Keepax 
2069d53dfdcSCharles Keepax 	for (i = 0; i < timeout; i++) {
2079d53dfdcSCharles Keepax 		ret = regmap_read(arizona->regmap, reg, &val);
2089d53dfdcSCharles Keepax 		if (ret != 0) {
2099d53dfdcSCharles Keepax 			dev_err(arizona->dev, "Failed to read reg %u: %d\n",
2109d53dfdcSCharles Keepax 				reg, ret);
2119d53dfdcSCharles Keepax 			continue;
2129d53dfdcSCharles Keepax 		}
2139d53dfdcSCharles Keepax 
2149d53dfdcSCharles Keepax 		if ((val & mask) == target)
2159d53dfdcSCharles Keepax 			return 0;
2169d53dfdcSCharles Keepax 
2179d53dfdcSCharles Keepax 		msleep(1);
2189d53dfdcSCharles Keepax 	}
2199d53dfdcSCharles Keepax 
2209d53dfdcSCharles Keepax 	dev_err(arizona->dev, "Polling reg %u timed out: %x\n", reg, val);
2219d53dfdcSCharles Keepax 	return -ETIMEDOUT;
2229d53dfdcSCharles Keepax }
2239d53dfdcSCharles Keepax 
2243cc72986SMark Brown static int arizona_wait_for_boot(struct arizona *arizona)
2253cc72986SMark Brown {
2269d53dfdcSCharles Keepax 	int ret;
2273cc72986SMark Brown 
2283cc72986SMark Brown 	/*
2293cc72986SMark Brown 	 * We can't use an interrupt as we need to runtime resume to do so,
2303cc72986SMark Brown 	 * we won't race with the interrupt handler as it'll be blocked on
2313cc72986SMark Brown 	 * runtime resume.
2323cc72986SMark Brown 	 */
2339d53dfdcSCharles Keepax 	ret = arizona_poll_reg(arizona, 5, ARIZONA_INTERRUPT_RAW_STATUS_5,
2349d53dfdcSCharles Keepax 			       ARIZONA_BOOT_DONE_STS, ARIZONA_BOOT_DONE_STS);
2353cc72986SMark Brown 
2369d53dfdcSCharles Keepax 	if (!ret)
2373cc72986SMark Brown 		regmap_write(arizona->regmap, ARIZONA_INTERRUPT_STATUS_5,
2383cc72986SMark Brown 			     ARIZONA_BOOT_DONE_STS);
2393cc72986SMark Brown 
2403cc72986SMark Brown 	pm_runtime_mark_last_busy(arizona->dev);
2413cc72986SMark Brown 
2429d53dfdcSCharles Keepax 	return ret;
2433cc72986SMark Brown }
2443cc72986SMark Brown 
245e80436bbSCharles Keepax static int arizona_apply_hardware_patch(struct arizona* arizona)
246e80436bbSCharles Keepax {
247e80436bbSCharles Keepax 	unsigned int fll, sysclk;
248e80436bbSCharles Keepax 	int ret, err;
249e80436bbSCharles Keepax 
250e80436bbSCharles Keepax 	regcache_cache_bypass(arizona->regmap, true);
251e80436bbSCharles Keepax 
252e80436bbSCharles Keepax 	/* Cache existing FLL and SYSCLK settings */
253e80436bbSCharles Keepax 	ret = regmap_read(arizona->regmap, ARIZONA_FLL1_CONTROL_1, &fll);
254e80436bbSCharles Keepax 	if (ret != 0) {
255e80436bbSCharles Keepax 		dev_err(arizona->dev, "Failed to cache FLL settings: %d\n",
256e80436bbSCharles Keepax 			ret);
257e80436bbSCharles Keepax 		return ret;
258e80436bbSCharles Keepax 	}
259e80436bbSCharles Keepax 	ret = regmap_read(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, &sysclk);
260e80436bbSCharles Keepax 	if (ret != 0) {
261e80436bbSCharles Keepax 		dev_err(arizona->dev, "Failed to cache SYSCLK settings: %d\n",
262e80436bbSCharles Keepax 			ret);
263e80436bbSCharles Keepax 		return ret;
264e80436bbSCharles Keepax 	}
265e80436bbSCharles Keepax 
266e80436bbSCharles Keepax 	/* Start up SYSCLK using the FLL in free running mode */
267e80436bbSCharles Keepax 	ret = regmap_write(arizona->regmap, ARIZONA_FLL1_CONTROL_1,
268e80436bbSCharles Keepax 			ARIZONA_FLL1_ENA | ARIZONA_FLL1_FREERUN);
269e80436bbSCharles Keepax 	if (ret != 0) {
270e80436bbSCharles Keepax 		dev_err(arizona->dev,
271e80436bbSCharles Keepax 			"Failed to start FLL in freerunning mode: %d\n",
272e80436bbSCharles Keepax 			ret);
273e80436bbSCharles Keepax 		return ret;
274e80436bbSCharles Keepax 	}
275e80436bbSCharles Keepax 	ret = arizona_poll_reg(arizona, 25, ARIZONA_INTERRUPT_RAW_STATUS_5,
276e80436bbSCharles Keepax 			       ARIZONA_FLL1_CLOCK_OK_STS,
277e80436bbSCharles Keepax 			       ARIZONA_FLL1_CLOCK_OK_STS);
278e80436bbSCharles Keepax 	if (ret != 0) {
279e80436bbSCharles Keepax 		ret = -ETIMEDOUT;
280e80436bbSCharles Keepax 		goto err_fll;
281e80436bbSCharles Keepax 	}
282e80436bbSCharles Keepax 
283e80436bbSCharles Keepax 	ret = regmap_write(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, 0x0144);
284e80436bbSCharles Keepax 	if (ret != 0) {
285e80436bbSCharles Keepax 		dev_err(arizona->dev, "Failed to start SYSCLK: %d\n", ret);
286e80436bbSCharles Keepax 		goto err_fll;
287e80436bbSCharles Keepax 	}
288e80436bbSCharles Keepax 
289e80436bbSCharles Keepax 	/* Start the write sequencer and wait for it to finish */
290e80436bbSCharles Keepax 	ret = regmap_write(arizona->regmap, ARIZONA_WRITE_SEQUENCER_CTRL_0,
291e80436bbSCharles Keepax 			ARIZONA_WSEQ_ENA | ARIZONA_WSEQ_START | 160);
292e80436bbSCharles Keepax 	if (ret != 0) {
293e80436bbSCharles Keepax 		dev_err(arizona->dev, "Failed to start write sequencer: %d\n",
294e80436bbSCharles Keepax 			ret);
295e80436bbSCharles Keepax 		goto err_sysclk;
296e80436bbSCharles Keepax 	}
297e80436bbSCharles Keepax 	ret = arizona_poll_reg(arizona, 5, ARIZONA_WRITE_SEQUENCER_CTRL_1,
298e80436bbSCharles Keepax 			       ARIZONA_WSEQ_BUSY, 0);
299e80436bbSCharles Keepax 	if (ret != 0) {
300e80436bbSCharles Keepax 		regmap_write(arizona->regmap, ARIZONA_WRITE_SEQUENCER_CTRL_0,
301e80436bbSCharles Keepax 				ARIZONA_WSEQ_ABORT);
302e80436bbSCharles Keepax 		ret = -ETIMEDOUT;
303e80436bbSCharles Keepax 	}
304e80436bbSCharles Keepax 
305e80436bbSCharles Keepax err_sysclk:
306e80436bbSCharles Keepax 	err = regmap_write(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, sysclk);
307e80436bbSCharles Keepax 	if (err != 0) {
308e80436bbSCharles Keepax 		dev_err(arizona->dev,
309e80436bbSCharles Keepax 			"Failed to re-apply old SYSCLK settings: %d\n",
310e80436bbSCharles Keepax 			err);
311e80436bbSCharles Keepax 	}
312e80436bbSCharles Keepax 
313e80436bbSCharles Keepax err_fll:
314e80436bbSCharles Keepax 	err = regmap_write(arizona->regmap, ARIZONA_FLL1_CONTROL_1, fll);
315e80436bbSCharles Keepax 	if (err != 0) {
316e80436bbSCharles Keepax 		dev_err(arizona->dev,
317e80436bbSCharles Keepax 			"Failed to re-apply old FLL settings: %d\n",
318e80436bbSCharles Keepax 			err);
319e80436bbSCharles Keepax 	}
320e80436bbSCharles Keepax 
321e80436bbSCharles Keepax 	regcache_cache_bypass(arizona->regmap, false);
322e80436bbSCharles Keepax 
323e80436bbSCharles Keepax 	if (ret != 0)
324e80436bbSCharles Keepax 		return ret;
325e80436bbSCharles Keepax 	else
326e80436bbSCharles Keepax 		return err;
327e80436bbSCharles Keepax }
328e80436bbSCharles Keepax 
3293cc72986SMark Brown #ifdef CONFIG_PM_RUNTIME
3303cc72986SMark Brown static int arizona_runtime_resume(struct device *dev)
3313cc72986SMark Brown {
3323cc72986SMark Brown 	struct arizona *arizona = dev_get_drvdata(dev);
3333cc72986SMark Brown 	int ret;
3343cc72986SMark Brown 
335508c8299SMark Brown 	dev_dbg(arizona->dev, "Leaving AoD mode\n");
336508c8299SMark Brown 
33759db9691SMark Brown 	ret = regulator_enable(arizona->dcvdd);
33859db9691SMark Brown 	if (ret != 0) {
33959db9691SMark Brown 		dev_err(arizona->dev, "Failed to enable DCVDD: %d\n", ret);
34059db9691SMark Brown 		return ret;
34159db9691SMark Brown 	}
3423cc72986SMark Brown 
3433cc72986SMark Brown 	regcache_cache_only(arizona->regmap, false);
3443cc72986SMark Brown 
3454c9bb8bcSCharles Keepax 	switch (arizona->type) {
3464c9bb8bcSCharles Keepax 	case WM5102:
3474c9bb8bcSCharles Keepax 		ret = wm5102_patch(arizona);
3484c9bb8bcSCharles Keepax 		if (ret != 0) {
3494c9bb8bcSCharles Keepax 			dev_err(arizona->dev, "Failed to apply patch: %d\n",
3504c9bb8bcSCharles Keepax 				ret);
3514c9bb8bcSCharles Keepax 			goto err;
3524c9bb8bcSCharles Keepax 		}
353e80436bbSCharles Keepax 
354e80436bbSCharles Keepax 		ret = arizona_apply_hardware_patch(arizona);
355e80436bbSCharles Keepax 		if (ret != 0) {
356e80436bbSCharles Keepax 			dev_err(arizona->dev,
357e80436bbSCharles Keepax 				"Failed to apply hardware patch: %d\n",
358e80436bbSCharles Keepax 				ret);
359e80436bbSCharles Keepax 			goto err;
360e80436bbSCharles Keepax 		}
361e80436bbSCharles Keepax 		break;
362e80436bbSCharles Keepax 	default:
36312bb68edSCharles Keepax 		ret = arizona_wait_for_boot(arizona);
36412bb68edSCharles Keepax 		if (ret != 0) {
36512bb68edSCharles Keepax 			goto err;
36612bb68edSCharles Keepax 		}
36712bb68edSCharles Keepax 
368e80436bbSCharles Keepax 		break;
3694c9bb8bcSCharles Keepax 	}
3704c9bb8bcSCharles Keepax 
3719270bdf5SMark Brown 	ret = regcache_sync(arizona->regmap);
3729270bdf5SMark Brown 	if (ret != 0) {
3739270bdf5SMark Brown 		dev_err(arizona->dev, "Failed to restore register cache\n");
3744816bd1cSMark Brown 		goto err;
3759270bdf5SMark Brown 	}
3763cc72986SMark Brown 
3773cc72986SMark Brown 	return 0;
3784816bd1cSMark Brown 
3794816bd1cSMark Brown err:
3804816bd1cSMark Brown 	regcache_cache_only(arizona->regmap, true);
3814816bd1cSMark Brown 	regulator_disable(arizona->dcvdd);
3824816bd1cSMark Brown 	return ret;
3833cc72986SMark Brown }
3843cc72986SMark Brown 
3853cc72986SMark Brown static int arizona_runtime_suspend(struct device *dev)
3863cc72986SMark Brown {
3873cc72986SMark Brown 	struct arizona *arizona = dev_get_drvdata(dev);
3883cc72986SMark Brown 
389508c8299SMark Brown 	dev_dbg(arizona->dev, "Entering AoD mode\n");
390508c8299SMark Brown 
39159db9691SMark Brown 	regulator_disable(arizona->dcvdd);
3923cc72986SMark Brown 	regcache_cache_only(arizona->regmap, true);
3933cc72986SMark Brown 	regcache_mark_dirty(arizona->regmap);
3943cc72986SMark Brown 
3953cc72986SMark Brown 	return 0;
3963cc72986SMark Brown }
3973cc72986SMark Brown #endif
3983cc72986SMark Brown 
399dc781d0eSMark Brown #ifdef CONFIG_PM_SLEEP
400dc781d0eSMark Brown static int arizona_resume_noirq(struct device *dev)
401dc781d0eSMark Brown {
402dc781d0eSMark Brown 	struct arizona *arizona = dev_get_drvdata(dev);
403dc781d0eSMark Brown 
404dc781d0eSMark Brown 	dev_dbg(arizona->dev, "Early resume, disabling IRQ\n");
405dc781d0eSMark Brown 	disable_irq(arizona->irq);
406dc781d0eSMark Brown 
407dc781d0eSMark Brown 	return 0;
408dc781d0eSMark Brown }
409dc781d0eSMark Brown 
410dc781d0eSMark Brown static int arizona_resume(struct device *dev)
411dc781d0eSMark Brown {
412dc781d0eSMark Brown 	struct arizona *arizona = dev_get_drvdata(dev);
413dc781d0eSMark Brown 
414dc781d0eSMark Brown 	dev_dbg(arizona->dev, "Late resume, reenabling IRQ\n");
415dc781d0eSMark Brown 	enable_irq(arizona->irq);
416dc781d0eSMark Brown 
417dc781d0eSMark Brown 	return 0;
418dc781d0eSMark Brown }
419dc781d0eSMark Brown #endif
420dc781d0eSMark Brown 
4213cc72986SMark Brown const struct dev_pm_ops arizona_pm_ops = {
4223cc72986SMark Brown 	SET_RUNTIME_PM_OPS(arizona_runtime_suspend,
4233cc72986SMark Brown 			   arizona_runtime_resume,
4243cc72986SMark Brown 			   NULL)
425dc781d0eSMark Brown 	SET_SYSTEM_SLEEP_PM_OPS(NULL, arizona_resume)
426dc781d0eSMark Brown #ifdef CONFIG_PM_SLEEP
427dc781d0eSMark Brown 	.resume_noirq = arizona_resume_noirq,
428dc781d0eSMark Brown #endif
4293cc72986SMark Brown };
4303cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_pm_ops);
4313cc72986SMark Brown 
4323cc72986SMark Brown static struct mfd_cell early_devs[] = {
4333cc72986SMark Brown 	{ .name = "arizona-ldo1" },
4343cc72986SMark Brown };
4353cc72986SMark Brown 
4363cc72986SMark Brown static struct mfd_cell wm5102_devs[] = {
437d7768111SMark Brown 	{ .name = "arizona-micsupp" },
4383cc72986SMark Brown 	{ .name = "arizona-extcon" },
4393cc72986SMark Brown 	{ .name = "arizona-gpio" },
440503b1cacSMark Brown 	{ .name = "arizona-haptics" },
4413cc72986SMark Brown 	{ .name = "arizona-pwm" },
4423cc72986SMark Brown 	{ .name = "wm5102-codec" },
4433cc72986SMark Brown };
4443cc72986SMark Brown 
445e102befeSMark Brown static struct mfd_cell wm5110_devs[] = {
446d7768111SMark Brown 	{ .name = "arizona-micsupp" },
447e102befeSMark Brown 	{ .name = "arizona-extcon" },
448e102befeSMark Brown 	{ .name = "arizona-gpio" },
449503b1cacSMark Brown 	{ .name = "arizona-haptics" },
450e102befeSMark Brown 	{ .name = "arizona-pwm" },
451e102befeSMark Brown 	{ .name = "wm5110-codec" },
452e102befeSMark Brown };
453e102befeSMark Brown 
454f791be49SBill Pemberton int arizona_dev_init(struct arizona *arizona)
4553cc72986SMark Brown {
4563cc72986SMark Brown 	struct device *dev = arizona->dev;
4573cc72986SMark Brown 	const char *type_name;
4583cc72986SMark Brown 	unsigned int reg, val;
45962d62b59SMark Brown 	int (*apply_patch)(struct arizona *) = NULL;
4603cc72986SMark Brown 	int ret, i;
4613cc72986SMark Brown 
4623cc72986SMark Brown 	dev_set_drvdata(arizona->dev, arizona);
4633cc72986SMark Brown 	mutex_init(&arizona->clk_lock);
4643cc72986SMark Brown 
4653cc72986SMark Brown 	if (dev_get_platdata(arizona->dev))
4663cc72986SMark Brown 		memcpy(&arizona->pdata, dev_get_platdata(arizona->dev),
4673cc72986SMark Brown 		       sizeof(arizona->pdata));
4683cc72986SMark Brown 
4693cc72986SMark Brown 	regcache_cache_only(arizona->regmap, true);
4703cc72986SMark Brown 
4713cc72986SMark Brown 	switch (arizona->type) {
4723cc72986SMark Brown 	case WM5102:
473e102befeSMark Brown 	case WM5110:
4743cc72986SMark Brown 		for (i = 0; i < ARRAY_SIZE(wm5102_core_supplies); i++)
4753cc72986SMark Brown 			arizona->core_supplies[i].supply
4763cc72986SMark Brown 				= wm5102_core_supplies[i];
4773cc72986SMark Brown 		arizona->num_core_supplies = ARRAY_SIZE(wm5102_core_supplies);
4783cc72986SMark Brown 		break;
4793cc72986SMark Brown 	default:
4803cc72986SMark Brown 		dev_err(arizona->dev, "Unknown device type %d\n",
4813cc72986SMark Brown 			arizona->type);
4823cc72986SMark Brown 		return -EINVAL;
4833cc72986SMark Brown 	}
4843cc72986SMark Brown 
4853cc72986SMark Brown 	ret = mfd_add_devices(arizona->dev, -1, early_devs,
4860848c94fSMark Brown 			      ARRAY_SIZE(early_devs), NULL, 0, NULL);
4873cc72986SMark Brown 	if (ret != 0) {
4883cc72986SMark Brown 		dev_err(dev, "Failed to add early children: %d\n", ret);
4893cc72986SMark Brown 		return ret;
4903cc72986SMark Brown 	}
4913cc72986SMark Brown 
4923cc72986SMark Brown 	ret = devm_regulator_bulk_get(dev, arizona->num_core_supplies,
4933cc72986SMark Brown 				      arizona->core_supplies);
4943cc72986SMark Brown 	if (ret != 0) {
4953cc72986SMark Brown 		dev_err(dev, "Failed to request core supplies: %d\n",
4963cc72986SMark Brown 			ret);
4973cc72986SMark Brown 		goto err_early;
4983cc72986SMark Brown 	}
4993cc72986SMark Brown 
50059db9691SMark Brown 	arizona->dcvdd = devm_regulator_get(arizona->dev, "DCVDD");
50159db9691SMark Brown 	if (IS_ERR(arizona->dcvdd)) {
50259db9691SMark Brown 		ret = PTR_ERR(arizona->dcvdd);
50359db9691SMark Brown 		dev_err(dev, "Failed to request DCVDD: %d\n", ret);
50459db9691SMark Brown 		goto err_early;
50559db9691SMark Brown 	}
50659db9691SMark Brown 
50787d3af4aSMark Brown 	if (arizona->pdata.reset) {
50887d3af4aSMark Brown 		/* Start out with /RESET low to put the chip into reset */
50987d3af4aSMark Brown 		ret = gpio_request_one(arizona->pdata.reset,
51087d3af4aSMark Brown 				       GPIOF_DIR_OUT | GPIOF_INIT_LOW,
51187d3af4aSMark Brown 				       "arizona /RESET");
51287d3af4aSMark Brown 		if (ret != 0) {
51387d3af4aSMark Brown 			dev_err(dev, "Failed to request /RESET: %d\n", ret);
51487d3af4aSMark Brown 			goto err_early;
51587d3af4aSMark Brown 		}
51687d3af4aSMark Brown 	}
51787d3af4aSMark Brown 
5183cc72986SMark Brown 	ret = regulator_bulk_enable(arizona->num_core_supplies,
5193cc72986SMark Brown 				    arizona->core_supplies);
5203cc72986SMark Brown 	if (ret != 0) {
5213cc72986SMark Brown 		dev_err(dev, "Failed to enable core supplies: %d\n",
5223cc72986SMark Brown 			ret);
5233cc72986SMark Brown 		goto err_early;
5243cc72986SMark Brown 	}
5253cc72986SMark Brown 
52659db9691SMark Brown 	ret = regulator_enable(arizona->dcvdd);
52759db9691SMark Brown 	if (ret != 0) {
52859db9691SMark Brown 		dev_err(dev, "Failed to enable DCVDD: %d\n", ret);
52959db9691SMark Brown 		goto err_enable;
53059db9691SMark Brown 	}
53159db9691SMark Brown 
532c25feaa5SCharles Keepax 	if (arizona->pdata.reset) {
5333cc72986SMark Brown 		gpio_set_value_cansleep(arizona->pdata.reset, 1);
534c25feaa5SCharles Keepax 		msleep(1);
535c25feaa5SCharles Keepax 	}
5363cc72986SMark Brown 
5373cc72986SMark Brown 	regcache_cache_only(arizona->regmap, false);
5383cc72986SMark Brown 
539*ca76ceb8SMark Brown 	/* Verify that this is a chip we know about */
540*ca76ceb8SMark Brown 	ret = regmap_read(arizona->regmap, ARIZONA_SOFTWARE_RESET, &reg);
541*ca76ceb8SMark Brown 	if (ret != 0) {
542*ca76ceb8SMark Brown 		dev_err(dev, "Failed to read ID register: %d\n", ret);
543*ca76ceb8SMark Brown 		goto err_reset;
544*ca76ceb8SMark Brown 	}
545*ca76ceb8SMark Brown 
546*ca76ceb8SMark Brown 	switch (reg) {
547*ca76ceb8SMark Brown 	case 0x5102:
548*ca76ceb8SMark Brown 	case 0x5110:
549*ca76ceb8SMark Brown 		break;
550*ca76ceb8SMark Brown 	default:
551*ca76ceb8SMark Brown 		dev_err(arizona->dev, "Unknown device ID: %x\n", reg);
552*ca76ceb8SMark Brown 		goto err_reset;
553*ca76ceb8SMark Brown 	}
554*ca76ceb8SMark Brown 
555*ca76ceb8SMark Brown 	/* If we have a /RESET GPIO we'll already be reset */
556*ca76ceb8SMark Brown 	if (!arizona->pdata.reset) {
557*ca76ceb8SMark Brown 		regcache_mark_dirty(arizona->regmap);
558*ca76ceb8SMark Brown 
559*ca76ceb8SMark Brown 		ret = regmap_write(arizona->regmap, ARIZONA_SOFTWARE_RESET, 0);
560*ca76ceb8SMark Brown 		if (ret != 0) {
561*ca76ceb8SMark Brown 			dev_err(dev, "Failed to reset device: %d\n", ret);
562*ca76ceb8SMark Brown 			goto err_reset;
563*ca76ceb8SMark Brown 		}
564*ca76ceb8SMark Brown 
565*ca76ceb8SMark Brown 		msleep(1);
566*ca76ceb8SMark Brown 
567*ca76ceb8SMark Brown 		ret = regcache_sync(arizona->regmap);
568*ca76ceb8SMark Brown 		if (ret != 0) {
569*ca76ceb8SMark Brown 			dev_err(dev, "Failed to sync device: %d\n", ret);
570*ca76ceb8SMark Brown 			goto err_reset;
571*ca76ceb8SMark Brown 		}
572*ca76ceb8SMark Brown 	}
573*ca76ceb8SMark Brown 
574*ca76ceb8SMark Brown 	/* Ensure device startup is complete */
575*ca76ceb8SMark Brown 	switch (arizona->type) {
576*ca76ceb8SMark Brown 	case WM5102:
577*ca76ceb8SMark Brown 		ret = regmap_read(arizona->regmap, 0x19, &val);
578*ca76ceb8SMark Brown 		if (ret != 0)
579*ca76ceb8SMark Brown 			dev_err(dev,
580*ca76ceb8SMark Brown 				"Failed to check write sequencer state: %d\n",
581*ca76ceb8SMark Brown 				ret);
582*ca76ceb8SMark Brown 		else if (val & 0x01)
583*ca76ceb8SMark Brown 			break;
584*ca76ceb8SMark Brown 		/* Fall through */
585*ca76ceb8SMark Brown 	default:
586*ca76ceb8SMark Brown 		ret = arizona_wait_for_boot(arizona);
587*ca76ceb8SMark Brown 		if (ret != 0) {
588*ca76ceb8SMark Brown 			dev_err(arizona->dev,
589*ca76ceb8SMark Brown 				"Device failed initial boot: %d\n", ret);
590*ca76ceb8SMark Brown 			goto err_reset;
591*ca76ceb8SMark Brown 		}
592*ca76ceb8SMark Brown 		break;
593*ca76ceb8SMark Brown 	}
594*ca76ceb8SMark Brown 
595*ca76ceb8SMark Brown 	/* Read the device ID information & do device specific stuff */
5963cc72986SMark Brown 	ret = regmap_read(arizona->regmap, ARIZONA_SOFTWARE_RESET, &reg);
5973cc72986SMark Brown 	if (ret != 0) {
5983cc72986SMark Brown 		dev_err(dev, "Failed to read ID register: %d\n", ret);
59959db9691SMark Brown 		goto err_reset;
6003cc72986SMark Brown 	}
6013cc72986SMark Brown 
6023cc72986SMark Brown 	ret = regmap_read(arizona->regmap, ARIZONA_DEVICE_REVISION,
6033cc72986SMark Brown 			  &arizona->rev);
6043cc72986SMark Brown 	if (ret != 0) {
6053cc72986SMark Brown 		dev_err(dev, "Failed to read revision register: %d\n", ret);
60659db9691SMark Brown 		goto err_reset;
6073cc72986SMark Brown 	}
6083cc72986SMark Brown 	arizona->rev &= ARIZONA_DEVICE_REVISION_MASK;
6093cc72986SMark Brown 
6103cc72986SMark Brown 	switch (reg) {
611863df8d5SMark Brown #ifdef CONFIG_MFD_WM5102
6123cc72986SMark Brown 	case 0x5102:
6133cc72986SMark Brown 		type_name = "WM5102";
6143cc72986SMark Brown 		if (arizona->type != WM5102) {
6153cc72986SMark Brown 			dev_err(arizona->dev, "WM5102 registered as %d\n",
6163cc72986SMark Brown 				arizona->type);
6173cc72986SMark Brown 			arizona->type = WM5102;
6183cc72986SMark Brown 		}
61962d62b59SMark Brown 		apply_patch = wm5102_patch;
620c6d6bfb1SMark Brown 		arizona->rev &= 0x7;
6213cc72986SMark Brown 		break;
622863df8d5SMark Brown #endif
623e102befeSMark Brown #ifdef CONFIG_MFD_WM5110
624e102befeSMark Brown 	case 0x5110:
625e102befeSMark Brown 		type_name = "WM5110";
626e102befeSMark Brown 		if (arizona->type != WM5110) {
627e102befeSMark Brown 			dev_err(arizona->dev, "WM5110 registered as %d\n",
628e102befeSMark Brown 				arizona->type);
629e102befeSMark Brown 			arizona->type = WM5110;
630e102befeSMark Brown 		}
63162d62b59SMark Brown 		apply_patch = wm5110_patch;
632e102befeSMark Brown 		break;
633e102befeSMark Brown #endif
6343cc72986SMark Brown 	default:
6353cc72986SMark Brown 		dev_err(arizona->dev, "Unknown device ID %x\n", reg);
63659db9691SMark Brown 		goto err_reset;
6373cc72986SMark Brown 	}
6383cc72986SMark Brown 
6393cc72986SMark Brown 	dev_info(dev, "%s revision %c\n", type_name, arizona->rev + 'A');
6403cc72986SMark Brown 
64162d62b59SMark Brown 	if (apply_patch) {
64262d62b59SMark Brown 		ret = apply_patch(arizona);
64362d62b59SMark Brown 		if (ret != 0) {
64462d62b59SMark Brown 			dev_err(arizona->dev, "Failed to apply patch: %d\n",
64562d62b59SMark Brown 				ret);
64662d62b59SMark Brown 			goto err_reset;
64762d62b59SMark Brown 		}
648e80436bbSCharles Keepax 
649e80436bbSCharles Keepax 		switch (arizona->type) {
650e80436bbSCharles Keepax 		case WM5102:
651e80436bbSCharles Keepax 			ret = arizona_apply_hardware_patch(arizona);
652e80436bbSCharles Keepax 			if (ret != 0) {
653e80436bbSCharles Keepax 				dev_err(arizona->dev,
654e80436bbSCharles Keepax 					"Failed to apply hardware patch: %d\n",
655e80436bbSCharles Keepax 					ret);
656e80436bbSCharles Keepax 				goto err_reset;
657e80436bbSCharles Keepax 			}
658e80436bbSCharles Keepax 			break;
659e80436bbSCharles Keepax 		default:
660e80436bbSCharles Keepax 			break;
661e80436bbSCharles Keepax 		}
66262d62b59SMark Brown 	}
66362d62b59SMark Brown 
6643cc72986SMark Brown 	for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) {
6653cc72986SMark Brown 		if (!arizona->pdata.gpio_defaults[i])
6663cc72986SMark Brown 			continue;
6673cc72986SMark Brown 
6683cc72986SMark Brown 		regmap_write(arizona->regmap, ARIZONA_GPIO1_CTRL + i,
6693cc72986SMark Brown 			     arizona->pdata.gpio_defaults[i]);
6703cc72986SMark Brown 	}
6713cc72986SMark Brown 
6723cc72986SMark Brown 	pm_runtime_set_autosuspend_delay(arizona->dev, 100);
6733cc72986SMark Brown 	pm_runtime_use_autosuspend(arizona->dev);
6743cc72986SMark Brown 	pm_runtime_enable(arizona->dev);
6753cc72986SMark Brown 
6763cc72986SMark Brown 	/* Chip default */
6773cc72986SMark Brown 	if (!arizona->pdata.clk32k_src)
6783cc72986SMark Brown 		arizona->pdata.clk32k_src = ARIZONA_32KZ_MCLK2;
6793cc72986SMark Brown 
6803cc72986SMark Brown 	switch (arizona->pdata.clk32k_src) {
6813cc72986SMark Brown 	case ARIZONA_32KZ_MCLK1:
6823cc72986SMark Brown 	case ARIZONA_32KZ_MCLK2:
6833cc72986SMark Brown 		regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1,
6843cc72986SMark Brown 				   ARIZONA_CLK_32K_SRC_MASK,
6853cc72986SMark Brown 				   arizona->pdata.clk32k_src - 1);
686767c6dc0SMark Brown 		arizona_clk32k_enable(arizona);
6873cc72986SMark Brown 		break;
6883cc72986SMark Brown 	case ARIZONA_32KZ_NONE:
6893cc72986SMark Brown 		regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1,
6903cc72986SMark Brown 				   ARIZONA_CLK_32K_SRC_MASK, 2);
6913cc72986SMark Brown 		break;
6923cc72986SMark Brown 	default:
6933cc72986SMark Brown 		dev_err(arizona->dev, "Invalid 32kHz clock source: %d\n",
6943cc72986SMark Brown 			arizona->pdata.clk32k_src);
6953cc72986SMark Brown 		ret = -EINVAL;
69659db9691SMark Brown 		goto err_reset;
6973cc72986SMark Brown 	}
6983cc72986SMark Brown 
6993d91f828SMark Brown 	for (i = 0; i < ARIZONA_MAX_MICBIAS; i++) {
700544c7aadSMark Brown 		if (!arizona->pdata.micbias[i].mV &&
701544c7aadSMark Brown 		    !arizona->pdata.micbias[i].bypass)
7023d91f828SMark Brown 			continue;
7033d91f828SMark Brown 
704544c7aadSMark Brown 		/* Apply default for bypass mode */
705544c7aadSMark Brown 		if (!arizona->pdata.micbias[i].mV)
706544c7aadSMark Brown 			arizona->pdata.micbias[i].mV = 2800;
707544c7aadSMark Brown 
7083d91f828SMark Brown 		val = (arizona->pdata.micbias[i].mV - 1500) / 100;
709544c7aadSMark Brown 
7103d91f828SMark Brown 		val <<= ARIZONA_MICB1_LVL_SHIFT;
7113d91f828SMark Brown 
7123d91f828SMark Brown 		if (arizona->pdata.micbias[i].ext_cap)
7133d91f828SMark Brown 			val |= ARIZONA_MICB1_EXT_CAP;
7143d91f828SMark Brown 
7153d91f828SMark Brown 		if (arizona->pdata.micbias[i].discharge)
7163d91f828SMark Brown 			val |= ARIZONA_MICB1_DISCH;
7173d91f828SMark Brown 
7183d91f828SMark Brown 		if (arizona->pdata.micbias[i].fast_start)
7193d91f828SMark Brown 			val |= ARIZONA_MICB1_RATE;
7203d91f828SMark Brown 
721544c7aadSMark Brown 		if (arizona->pdata.micbias[i].bypass)
722544c7aadSMark Brown 			val |= ARIZONA_MICB1_BYPASS;
723544c7aadSMark Brown 
7243d91f828SMark Brown 		regmap_update_bits(arizona->regmap,
7253d91f828SMark Brown 				   ARIZONA_MIC_BIAS_CTRL_1 + i,
7263d91f828SMark Brown 				   ARIZONA_MICB1_LVL_MASK |
7273d91f828SMark Brown 				   ARIZONA_MICB1_DISCH |
728544c7aadSMark Brown 				   ARIZONA_MICB1_BYPASS |
7293d91f828SMark Brown 				   ARIZONA_MICB1_RATE, val);
7303d91f828SMark Brown 	}
7313d91f828SMark Brown 
7323cc72986SMark Brown 	for (i = 0; i < ARIZONA_MAX_INPUT; i++) {
7333cc72986SMark Brown 		/* Default for both is 0 so noop with defaults */
7343cc72986SMark Brown 		val = arizona->pdata.dmic_ref[i]
7353cc72986SMark Brown 			<< ARIZONA_IN1_DMIC_SUP_SHIFT;
7363cc72986SMark Brown 		val |= arizona->pdata.inmode[i] << ARIZONA_IN1_MODE_SHIFT;
7373cc72986SMark Brown 
7383cc72986SMark Brown 		regmap_update_bits(arizona->regmap,
7393cc72986SMark Brown 				   ARIZONA_IN1L_CONTROL + (i * 8),
7403cc72986SMark Brown 				   ARIZONA_IN1_DMIC_SUP_MASK |
7413cc72986SMark Brown 				   ARIZONA_IN1_MODE_MASK, val);
7423cc72986SMark Brown 	}
7433cc72986SMark Brown 
7443cc72986SMark Brown 	for (i = 0; i < ARIZONA_MAX_OUTPUT; i++) {
7453cc72986SMark Brown 		/* Default is 0 so noop with defaults */
7463cc72986SMark Brown 		if (arizona->pdata.out_mono[i])
7473cc72986SMark Brown 			val = ARIZONA_OUT1_MONO;
7483cc72986SMark Brown 		else
7493cc72986SMark Brown 			val = 0;
7503cc72986SMark Brown 
7513cc72986SMark Brown 		regmap_update_bits(arizona->regmap,
7523cc72986SMark Brown 				   ARIZONA_OUTPUT_PATH_CONFIG_1L + (i * 8),
7533cc72986SMark Brown 				   ARIZONA_OUT1_MONO, val);
7543cc72986SMark Brown 	}
7553cc72986SMark Brown 
7563cc72986SMark Brown 	for (i = 0; i < ARIZONA_MAX_PDM_SPK; i++) {
7573cc72986SMark Brown 		if (arizona->pdata.spk_mute[i])
7583cc72986SMark Brown 			regmap_update_bits(arizona->regmap,
7592a51da04SMark Brown 					   ARIZONA_PDM_SPK1_CTRL_1 + (i * 2),
7603cc72986SMark Brown 					   ARIZONA_SPK1_MUTE_ENDIAN_MASK |
7613cc72986SMark Brown 					   ARIZONA_SPK1_MUTE_SEQ1_MASK,
7623cc72986SMark Brown 					   arizona->pdata.spk_mute[i]);
7633cc72986SMark Brown 
7643cc72986SMark Brown 		if (arizona->pdata.spk_fmt[i])
7653cc72986SMark Brown 			regmap_update_bits(arizona->regmap,
7662a51da04SMark Brown 					   ARIZONA_PDM_SPK1_CTRL_2 + (i * 2),
7673cc72986SMark Brown 					   ARIZONA_SPK1_FMT_MASK,
7683cc72986SMark Brown 					   arizona->pdata.spk_fmt[i]);
7693cc72986SMark Brown 	}
7703cc72986SMark Brown 
7713cc72986SMark Brown 	/* Set up for interrupts */
7723cc72986SMark Brown 	ret = arizona_irq_init(arizona);
7733cc72986SMark Brown 	if (ret != 0)
77459db9691SMark Brown 		goto err_reset;
7753cc72986SMark Brown 
7763cc72986SMark Brown 	arizona_request_irq(arizona, ARIZONA_IRQ_CLKGEN_ERR, "CLKGEN error",
7773cc72986SMark Brown 			    arizona_clkgen_err, arizona);
7783cc72986SMark Brown 	arizona_request_irq(arizona, ARIZONA_IRQ_OVERCLOCKED, "Overclocked",
7793cc72986SMark Brown 			    arizona_overclocked, arizona);
7803cc72986SMark Brown 	arizona_request_irq(arizona, ARIZONA_IRQ_UNDERCLOCKED, "Underclocked",
7813cc72986SMark Brown 			    arizona_underclocked, arizona);
7823cc72986SMark Brown 
7833cc72986SMark Brown 	switch (arizona->type) {
7843cc72986SMark Brown 	case WM5102:
7853cc72986SMark Brown 		ret = mfd_add_devices(arizona->dev, -1, wm5102_devs,
7860848c94fSMark Brown 				      ARRAY_SIZE(wm5102_devs), NULL, 0, NULL);
7873cc72986SMark Brown 		break;
788e102befeSMark Brown 	case WM5110:
789e102befeSMark Brown 		ret = mfd_add_devices(arizona->dev, -1, wm5110_devs,
79078566afdSCharles Keepax 				      ARRAY_SIZE(wm5110_devs), NULL, 0, NULL);
791e102befeSMark Brown 		break;
7923cc72986SMark Brown 	}
7933cc72986SMark Brown 
7943cc72986SMark Brown 	if (ret != 0) {
7953cc72986SMark Brown 		dev_err(arizona->dev, "Failed to add subdevices: %d\n", ret);
7963cc72986SMark Brown 		goto err_irq;
7973cc72986SMark Brown 	}
7983cc72986SMark Brown 
79959db9691SMark Brown #ifdef CONFIG_PM_RUNTIME
80059db9691SMark Brown 	regulator_disable(arizona->dcvdd);
80159db9691SMark Brown #endif
80259db9691SMark Brown 
8033cc72986SMark Brown 	return 0;
8043cc72986SMark Brown 
8053cc72986SMark Brown err_irq:
8063cc72986SMark Brown 	arizona_irq_exit(arizona);
8073cc72986SMark Brown err_reset:
8083cc72986SMark Brown 	if (arizona->pdata.reset) {
80987d3af4aSMark Brown 		gpio_set_value_cansleep(arizona->pdata.reset, 0);
8103cc72986SMark Brown 		gpio_free(arizona->pdata.reset);
8113cc72986SMark Brown 	}
81259db9691SMark Brown 	regulator_disable(arizona->dcvdd);
8133cc72986SMark Brown err_enable:
8143a36a0dbSMark Brown 	regulator_bulk_disable(arizona->num_core_supplies,
8153cc72986SMark Brown 			       arizona->core_supplies);
8163cc72986SMark Brown err_early:
8173cc72986SMark Brown 	mfd_remove_devices(dev);
8183cc72986SMark Brown 	return ret;
8193cc72986SMark Brown }
8203cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_dev_init);
8213cc72986SMark Brown 
8224740f73fSBill Pemberton int arizona_dev_exit(struct arizona *arizona)
8233cc72986SMark Brown {
8243cc72986SMark Brown 	mfd_remove_devices(arizona->dev);
8253cc72986SMark Brown 	arizona_free_irq(arizona, ARIZONA_IRQ_UNDERCLOCKED, arizona);
8263cc72986SMark Brown 	arizona_free_irq(arizona, ARIZONA_IRQ_OVERCLOCKED, arizona);
8273cc72986SMark Brown 	arizona_free_irq(arizona, ARIZONA_IRQ_CLKGEN_ERR, arizona);
8283cc72986SMark Brown 	pm_runtime_disable(arizona->dev);
8293cc72986SMark Brown 	arizona_irq_exit(arizona);
8303cc72986SMark Brown 	return 0;
8313cc72986SMark Brown }
8323cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_dev_exit);
833