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