13cc72986SMark Brown /* 23cc72986SMark Brown * Arizona core driver 33cc72986SMark Brown * 43cc72986SMark Brown * Copyright 2012 Wolfson Microelectronics plc 53cc72986SMark Brown * 63cc72986SMark Brown * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> 73cc72986SMark Brown * 83cc72986SMark Brown * This program is free software; you can redistribute it and/or modify 93cc72986SMark Brown * it under the terms of the GNU General Public License version 2 as 103cc72986SMark Brown * published by the Free Software Foundation. 113cc72986SMark Brown */ 123cc72986SMark Brown 13cdd8da8cSSylwester Nawrocki #include <linux/clk.h> 143cc72986SMark Brown #include <linux/delay.h> 1559db9691SMark Brown #include <linux/err.h> 163cc72986SMark Brown #include <linux/gpio.h> 173cc72986SMark Brown #include <linux/interrupt.h> 183cc72986SMark Brown #include <linux/mfd/core.h> 193cc72986SMark Brown #include <linux/module.h> 20d781009cSMark Brown #include <linux/of.h> 21d781009cSMark Brown #include <linux/of_device.h> 22d781009cSMark Brown #include <linux/of_gpio.h> 233cc72986SMark Brown #include <linux/pm_runtime.h> 243cc72986SMark Brown #include <linux/regmap.h> 253cc72986SMark Brown #include <linux/regulator/consumer.h> 265927467dSMark Brown #include <linux/regulator/machine.h> 273cc72986SMark Brown #include <linux/slab.h> 28ae05ea36SRichard Fitzgerald #include <linux/platform_device.h> 293cc72986SMark Brown 303cc72986SMark Brown #include <linux/mfd/arizona/core.h> 313cc72986SMark Brown #include <linux/mfd/arizona/registers.h> 323cc72986SMark Brown 333cc72986SMark Brown #include "arizona.h" 343cc72986SMark Brown 353762aedeSCharles Keepax static const char * const wm5102_core_supplies[] = { 363cc72986SMark Brown "AVDD", 373cc72986SMark Brown "DBVDD1", 383cc72986SMark Brown }; 393cc72986SMark Brown 403cc72986SMark Brown int arizona_clk32k_enable(struct arizona *arizona) 413cc72986SMark Brown { 423cc72986SMark Brown int ret = 0; 433cc72986SMark Brown 443cc72986SMark Brown mutex_lock(&arizona->clk_lock); 453cc72986SMark Brown 463cc72986SMark Brown arizona->clk32k_ref++; 473cc72986SMark Brown 48247fa192SMark Brown if (arizona->clk32k_ref == 1) { 49247fa192SMark Brown switch (arizona->pdata.clk32k_src) { 50247fa192SMark Brown case ARIZONA_32KZ_MCLK1: 51247fa192SMark Brown ret = pm_runtime_get_sync(arizona->dev); 52247fa192SMark Brown if (ret != 0) 53cdd8da8cSSylwester Nawrocki goto err_ref; 54cdd8da8cSSylwester Nawrocki ret = clk_prepare_enable(arizona->mclk[ARIZONA_MCLK1]); 55cdd8da8cSSylwester Nawrocki if (ret != 0) 56cdd8da8cSSylwester Nawrocki goto err_pm; 57cdd8da8cSSylwester Nawrocki break; 58cdd8da8cSSylwester Nawrocki case ARIZONA_32KZ_MCLK2: 59cdd8da8cSSylwester Nawrocki ret = clk_prepare_enable(arizona->mclk[ARIZONA_MCLK2]); 60cdd8da8cSSylwester Nawrocki if (ret != 0) 61cdd8da8cSSylwester Nawrocki goto err_ref; 62247fa192SMark Brown break; 63247fa192SMark Brown } 64247fa192SMark Brown 653cc72986SMark Brown ret = regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, 663cc72986SMark Brown ARIZONA_CLK_32K_ENA, 673cc72986SMark Brown ARIZONA_CLK_32K_ENA); 68247fa192SMark Brown } 693cc72986SMark Brown 70cdd8da8cSSylwester Nawrocki err_pm: 71cdd8da8cSSylwester Nawrocki pm_runtime_put_sync(arizona->dev); 72cdd8da8cSSylwester Nawrocki err_ref: 733cc72986SMark Brown if (ret != 0) 743cc72986SMark Brown arizona->clk32k_ref--; 753cc72986SMark Brown 763cc72986SMark Brown mutex_unlock(&arizona->clk_lock); 773cc72986SMark Brown 783cc72986SMark Brown return ret; 793cc72986SMark Brown } 803cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_clk32k_enable); 813cc72986SMark Brown 823cc72986SMark Brown int arizona_clk32k_disable(struct arizona *arizona) 833cc72986SMark Brown { 843cc72986SMark Brown mutex_lock(&arizona->clk_lock); 853cc72986SMark Brown 863cc72986SMark Brown BUG_ON(arizona->clk32k_ref <= 0); 873cc72986SMark Brown 883cc72986SMark Brown arizona->clk32k_ref--; 893cc72986SMark Brown 90247fa192SMark Brown if (arizona->clk32k_ref == 0) { 913cc72986SMark Brown regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, 923cc72986SMark Brown ARIZONA_CLK_32K_ENA, 0); 933cc72986SMark Brown 94247fa192SMark Brown switch (arizona->pdata.clk32k_src) { 95247fa192SMark Brown case ARIZONA_32KZ_MCLK1: 96247fa192SMark Brown pm_runtime_put_sync(arizona->dev); 97cdd8da8cSSylwester Nawrocki clk_disable_unprepare(arizona->mclk[ARIZONA_MCLK1]); 98cdd8da8cSSylwester Nawrocki break; 99cdd8da8cSSylwester Nawrocki case ARIZONA_32KZ_MCLK2: 100cdd8da8cSSylwester Nawrocki clk_disable_unprepare(arizona->mclk[ARIZONA_MCLK2]); 101247fa192SMark Brown break; 102247fa192SMark Brown } 103247fa192SMark Brown } 104247fa192SMark Brown 1053cc72986SMark Brown mutex_unlock(&arizona->clk_lock); 1063cc72986SMark Brown 107a260fba1SJavier Martinez Canillas return 0; 1083cc72986SMark Brown } 1093cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_clk32k_disable); 1103cc72986SMark Brown 1113cc72986SMark Brown static irqreturn_t arizona_clkgen_err(int irq, void *data) 1123cc72986SMark Brown { 1133cc72986SMark Brown struct arizona *arizona = data; 1143cc72986SMark Brown 1153cc72986SMark Brown dev_err(arizona->dev, "CLKGEN error\n"); 1163cc72986SMark Brown 1173cc72986SMark Brown return IRQ_HANDLED; 1183cc72986SMark Brown } 1193cc72986SMark Brown 1203cc72986SMark Brown static irqreturn_t arizona_underclocked(int irq, void *data) 1213cc72986SMark Brown { 1223cc72986SMark Brown struct arizona *arizona = data; 1233cc72986SMark Brown unsigned int val; 1243cc72986SMark Brown int ret; 1253cc72986SMark Brown 1263cc72986SMark Brown ret = regmap_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_8, 1273cc72986SMark Brown &val); 1283cc72986SMark Brown if (ret != 0) { 1293cc72986SMark Brown dev_err(arizona->dev, "Failed to read underclock status: %d\n", 1303cc72986SMark Brown ret); 1313cc72986SMark Brown return IRQ_NONE; 1323cc72986SMark Brown } 1333cc72986SMark Brown 1343cc72986SMark Brown if (val & ARIZONA_AIF3_UNDERCLOCKED_STS) 1353cc72986SMark Brown dev_err(arizona->dev, "AIF3 underclocked\n"); 1363cc72986SMark Brown if (val & ARIZONA_AIF2_UNDERCLOCKED_STS) 1373ebef34dSCharles Keepax dev_err(arizona->dev, "AIF2 underclocked\n"); 1383ebef34dSCharles Keepax if (val & ARIZONA_AIF1_UNDERCLOCKED_STS) 1393cc72986SMark Brown dev_err(arizona->dev, "AIF1 underclocked\n"); 1406e440d27SCharles Keepax if (val & ARIZONA_ISRC3_UNDERCLOCKED_STS) 1416e440d27SCharles Keepax dev_err(arizona->dev, "ISRC3 underclocked\n"); 1423cc72986SMark Brown if (val & ARIZONA_ISRC2_UNDERCLOCKED_STS) 1433cc72986SMark Brown dev_err(arizona->dev, "ISRC2 underclocked\n"); 1443cc72986SMark Brown if (val & ARIZONA_ISRC1_UNDERCLOCKED_STS) 1453cc72986SMark Brown dev_err(arizona->dev, "ISRC1 underclocked\n"); 1463cc72986SMark Brown if (val & ARIZONA_FX_UNDERCLOCKED_STS) 1473cc72986SMark Brown dev_err(arizona->dev, "FX underclocked\n"); 1483cc72986SMark Brown if (val & ARIZONA_ASRC_UNDERCLOCKED_STS) 1493cc72986SMark Brown dev_err(arizona->dev, "ASRC underclocked\n"); 1503cc72986SMark Brown if (val & ARIZONA_DAC_UNDERCLOCKED_STS) 1513cc72986SMark Brown dev_err(arizona->dev, "DAC underclocked\n"); 1523cc72986SMark Brown if (val & ARIZONA_ADC_UNDERCLOCKED_STS) 1533cc72986SMark Brown dev_err(arizona->dev, "ADC underclocked\n"); 1543cc72986SMark Brown if (val & ARIZONA_MIXER_UNDERCLOCKED_STS) 155648a9880SMark Brown dev_err(arizona->dev, "Mixer dropped sample\n"); 1563cc72986SMark Brown 1573cc72986SMark Brown return IRQ_HANDLED; 1583cc72986SMark Brown } 1593cc72986SMark Brown 1603cc72986SMark Brown static irqreturn_t arizona_overclocked(int irq, void *data) 1613cc72986SMark Brown { 1623cc72986SMark Brown struct arizona *arizona = data; 1636887b042SRichard Fitzgerald unsigned int val[3]; 1643cc72986SMark Brown int ret; 1653cc72986SMark Brown 1663cc72986SMark Brown ret = regmap_bulk_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_6, 1676887b042SRichard Fitzgerald &val[0], 3); 1683cc72986SMark Brown if (ret != 0) { 1693cc72986SMark Brown dev_err(arizona->dev, "Failed to read overclock status: %d\n", 1703cc72986SMark Brown ret); 1713cc72986SMark Brown return IRQ_NONE; 1723cc72986SMark Brown } 1733cc72986SMark Brown 1746887b042SRichard Fitzgerald switch (arizona->type) { 1756887b042SRichard Fitzgerald case WM8998: 1766887b042SRichard Fitzgerald case WM1814: 1776887b042SRichard Fitzgerald /* Some bits are shifted on WM8998, 1786887b042SRichard Fitzgerald * rearrange to match the standard bit layout 1796887b042SRichard Fitzgerald */ 1806887b042SRichard Fitzgerald val[0] = ((val[0] & 0x60e0) >> 1) | 1816887b042SRichard Fitzgerald ((val[0] & 0x1e00) >> 2) | 1826887b042SRichard Fitzgerald (val[0] & 0x000f); 1836887b042SRichard Fitzgerald break; 1846887b042SRichard Fitzgerald default: 1856887b042SRichard Fitzgerald break; 1866887b042SRichard Fitzgerald } 1876887b042SRichard Fitzgerald 1883cc72986SMark Brown if (val[0] & ARIZONA_PWM_OVERCLOCKED_STS) 1893cc72986SMark Brown dev_err(arizona->dev, "PWM overclocked\n"); 1903cc72986SMark Brown if (val[0] & ARIZONA_FX_CORE_OVERCLOCKED_STS) 1913cc72986SMark Brown dev_err(arizona->dev, "FX core overclocked\n"); 1923cc72986SMark Brown if (val[0] & ARIZONA_DAC_SYS_OVERCLOCKED_STS) 1933cc72986SMark Brown dev_err(arizona->dev, "DAC SYS overclocked\n"); 1943cc72986SMark Brown if (val[0] & ARIZONA_DAC_WARP_OVERCLOCKED_STS) 1953cc72986SMark Brown dev_err(arizona->dev, "DAC WARP overclocked\n"); 1963cc72986SMark Brown if (val[0] & ARIZONA_ADC_OVERCLOCKED_STS) 1973cc72986SMark Brown dev_err(arizona->dev, "ADC overclocked\n"); 1983cc72986SMark Brown if (val[0] & ARIZONA_MIXER_OVERCLOCKED_STS) 1993cc72986SMark Brown dev_err(arizona->dev, "Mixer overclocked\n"); 2003cc72986SMark Brown if (val[0] & ARIZONA_AIF3_SYNC_OVERCLOCKED_STS) 2013cc72986SMark Brown dev_err(arizona->dev, "AIF3 overclocked\n"); 2023cc72986SMark Brown if (val[0] & ARIZONA_AIF2_SYNC_OVERCLOCKED_STS) 2033cc72986SMark Brown dev_err(arizona->dev, "AIF2 overclocked\n"); 2043cc72986SMark Brown if (val[0] & ARIZONA_AIF1_SYNC_OVERCLOCKED_STS) 2053cc72986SMark Brown dev_err(arizona->dev, "AIF1 overclocked\n"); 2063cc72986SMark Brown if (val[0] & ARIZONA_PAD_CTRL_OVERCLOCKED_STS) 2073cc72986SMark Brown dev_err(arizona->dev, "Pad control overclocked\n"); 2083cc72986SMark Brown 2093cc72986SMark Brown if (val[1] & ARIZONA_SLIMBUS_SUBSYS_OVERCLOCKED_STS) 2103cc72986SMark Brown dev_err(arizona->dev, "Slimbus subsystem overclocked\n"); 2113cc72986SMark Brown if (val[1] & ARIZONA_SLIMBUS_ASYNC_OVERCLOCKED_STS) 2123cc72986SMark Brown dev_err(arizona->dev, "Slimbus async overclocked\n"); 2133cc72986SMark Brown if (val[1] & ARIZONA_SLIMBUS_SYNC_OVERCLOCKED_STS) 2143cc72986SMark Brown dev_err(arizona->dev, "Slimbus sync overclocked\n"); 2153cc72986SMark Brown if (val[1] & ARIZONA_ASRC_ASYNC_SYS_OVERCLOCKED_STS) 2163cc72986SMark Brown dev_err(arizona->dev, "ASRC async system overclocked\n"); 2173cc72986SMark Brown if (val[1] & ARIZONA_ASRC_ASYNC_WARP_OVERCLOCKED_STS) 2183cc72986SMark Brown dev_err(arizona->dev, "ASRC async WARP overclocked\n"); 2193cc72986SMark Brown if (val[1] & ARIZONA_ASRC_SYNC_SYS_OVERCLOCKED_STS) 2203cc72986SMark Brown dev_err(arizona->dev, "ASRC sync system overclocked\n"); 2213cc72986SMark Brown if (val[1] & ARIZONA_ASRC_SYNC_WARP_OVERCLOCKED_STS) 2223cc72986SMark Brown dev_err(arizona->dev, "ASRC sync WARP overclocked\n"); 2233cc72986SMark Brown if (val[1] & ARIZONA_ADSP2_1_OVERCLOCKED_STS) 2243cc72986SMark Brown dev_err(arizona->dev, "DSP1 overclocked\n"); 2256e440d27SCharles Keepax if (val[1] & ARIZONA_ISRC3_OVERCLOCKED_STS) 2266e440d27SCharles Keepax dev_err(arizona->dev, "ISRC3 overclocked\n"); 2273cc72986SMark Brown if (val[1] & ARIZONA_ISRC2_OVERCLOCKED_STS) 2283cc72986SMark Brown dev_err(arizona->dev, "ISRC2 overclocked\n"); 2293cc72986SMark Brown if (val[1] & ARIZONA_ISRC1_OVERCLOCKED_STS) 2303cc72986SMark Brown dev_err(arizona->dev, "ISRC1 overclocked\n"); 2313cc72986SMark Brown 2326887b042SRichard Fitzgerald if (val[2] & ARIZONA_SPDIF_OVERCLOCKED_STS) 2336887b042SRichard Fitzgerald dev_err(arizona->dev, "SPDIF overclocked\n"); 2346887b042SRichard Fitzgerald 2353cc72986SMark Brown return IRQ_HANDLED; 2363cc72986SMark Brown } 2373cc72986SMark Brown 2389d53dfdcSCharles Keepax static int arizona_poll_reg(struct arizona *arizona, 2399d53dfdcSCharles Keepax int timeout, unsigned int reg, 2409d53dfdcSCharles Keepax unsigned int mask, unsigned int target) 2419d53dfdcSCharles Keepax { 2429d53dfdcSCharles Keepax unsigned int val = 0; 2439d53dfdcSCharles Keepax int ret, i; 2449d53dfdcSCharles Keepax 2459d53dfdcSCharles Keepax for (i = 0; i < timeout; i++) { 2469d53dfdcSCharles Keepax ret = regmap_read(arizona->regmap, reg, &val); 2479d53dfdcSCharles Keepax if (ret != 0) { 2489d53dfdcSCharles Keepax dev_err(arizona->dev, "Failed to read reg %u: %d\n", 2499d53dfdcSCharles Keepax reg, ret); 2509d53dfdcSCharles Keepax continue; 2519d53dfdcSCharles Keepax } 2529d53dfdcSCharles Keepax 2539d53dfdcSCharles Keepax if ((val & mask) == target) 2549d53dfdcSCharles Keepax return 0; 2559d53dfdcSCharles Keepax 256b79a980fSLee Jones usleep_range(1000, 5000); 2579d53dfdcSCharles Keepax } 2589d53dfdcSCharles Keepax 2599d53dfdcSCharles Keepax dev_err(arizona->dev, "Polling reg %u timed out: %x\n", reg, val); 2609d53dfdcSCharles Keepax return -ETIMEDOUT; 2619d53dfdcSCharles Keepax } 2629d53dfdcSCharles Keepax 2633cc72986SMark Brown static int arizona_wait_for_boot(struct arizona *arizona) 2643cc72986SMark Brown { 2659d53dfdcSCharles Keepax int ret; 2663cc72986SMark Brown 2673cc72986SMark Brown /* 2683cc72986SMark Brown * We can't use an interrupt as we need to runtime resume to do so, 2693cc72986SMark Brown * we won't race with the interrupt handler as it'll be blocked on 2703cc72986SMark Brown * runtime resume. 2713cc72986SMark Brown */ 2729d53dfdcSCharles Keepax ret = arizona_poll_reg(arizona, 5, ARIZONA_INTERRUPT_RAW_STATUS_5, 2739d53dfdcSCharles Keepax ARIZONA_BOOT_DONE_STS, ARIZONA_BOOT_DONE_STS); 2743cc72986SMark Brown 2759d53dfdcSCharles Keepax if (!ret) 2763cc72986SMark Brown regmap_write(arizona->regmap, ARIZONA_INTERRUPT_STATUS_5, 2773cc72986SMark Brown ARIZONA_BOOT_DONE_STS); 2783cc72986SMark Brown 2793cc72986SMark Brown pm_runtime_mark_last_busy(arizona->dev); 2803cc72986SMark Brown 2819d53dfdcSCharles Keepax return ret; 2823cc72986SMark Brown } 2833cc72986SMark Brown 2842229875dSCharles Keepax static inline void arizona_enable_reset(struct arizona *arizona) 2852229875dSCharles Keepax { 2862229875dSCharles Keepax if (arizona->pdata.reset) 2872229875dSCharles Keepax gpio_set_value_cansleep(arizona->pdata.reset, 0); 2882229875dSCharles Keepax } 2892229875dSCharles Keepax 2902229875dSCharles Keepax static void arizona_disable_reset(struct arizona *arizona) 2912229875dSCharles Keepax { 2922229875dSCharles Keepax if (arizona->pdata.reset) { 293121c075cSCharles Keepax switch (arizona->type) { 294121c075cSCharles Keepax case WM5110: 295121c075cSCharles Keepax case WM8280: 296121c075cSCharles Keepax /* Meet requirements for minimum reset duration */ 297b79a980fSLee Jones usleep_range(5000, 10000); 298121c075cSCharles Keepax break; 299121c075cSCharles Keepax default: 300121c075cSCharles Keepax break; 301121c075cSCharles Keepax } 302121c075cSCharles Keepax 3032229875dSCharles Keepax gpio_set_value_cansleep(arizona->pdata.reset, 1); 304b79a980fSLee Jones usleep_range(1000, 5000); 3052229875dSCharles Keepax } 3062229875dSCharles Keepax } 3072229875dSCharles Keepax 3083850e3eeSCharles Keepax struct arizona_sysclk_state { 3093850e3eeSCharles Keepax unsigned int fll; 3103850e3eeSCharles Keepax unsigned int sysclk; 3113850e3eeSCharles Keepax }; 3123850e3eeSCharles Keepax 3133850e3eeSCharles Keepax static int arizona_enable_freerun_sysclk(struct arizona *arizona, 3143850e3eeSCharles Keepax struct arizona_sysclk_state *state) 315e80436bbSCharles Keepax { 316e80436bbSCharles Keepax int ret, err; 317e80436bbSCharles Keepax 318e80436bbSCharles Keepax /* Cache existing FLL and SYSCLK settings */ 3193850e3eeSCharles Keepax ret = regmap_read(arizona->regmap, ARIZONA_FLL1_CONTROL_1, &state->fll); 3200be068a0SCharles Keepax if (ret) { 321e80436bbSCharles Keepax dev_err(arizona->dev, "Failed to cache FLL settings: %d\n", 322e80436bbSCharles Keepax ret); 323e80436bbSCharles Keepax return ret; 324e80436bbSCharles Keepax } 3253850e3eeSCharles Keepax ret = regmap_read(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, 3263850e3eeSCharles Keepax &state->sysclk); 3270be068a0SCharles Keepax if (ret) { 328e80436bbSCharles Keepax dev_err(arizona->dev, "Failed to cache SYSCLK settings: %d\n", 329e80436bbSCharles Keepax ret); 330e80436bbSCharles Keepax return ret; 331e80436bbSCharles Keepax } 332e80436bbSCharles Keepax 333e80436bbSCharles Keepax /* Start up SYSCLK using the FLL in free running mode */ 334e80436bbSCharles Keepax ret = regmap_write(arizona->regmap, ARIZONA_FLL1_CONTROL_1, 335e80436bbSCharles Keepax ARIZONA_FLL1_ENA | ARIZONA_FLL1_FREERUN); 3360be068a0SCharles Keepax if (ret) { 337e80436bbSCharles Keepax dev_err(arizona->dev, 338e80436bbSCharles Keepax "Failed to start FLL in freerunning mode: %d\n", 339e80436bbSCharles Keepax ret); 340e80436bbSCharles Keepax return ret; 341e80436bbSCharles Keepax } 342e80436bbSCharles Keepax ret = arizona_poll_reg(arizona, 25, ARIZONA_INTERRUPT_RAW_STATUS_5, 343e80436bbSCharles Keepax ARIZONA_FLL1_CLOCK_OK_STS, 344e80436bbSCharles Keepax ARIZONA_FLL1_CLOCK_OK_STS); 3450be068a0SCharles Keepax if (ret) { 346e80436bbSCharles Keepax ret = -ETIMEDOUT; 347e80436bbSCharles Keepax goto err_fll; 348e80436bbSCharles Keepax } 349e80436bbSCharles Keepax 350e80436bbSCharles Keepax ret = regmap_write(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, 0x0144); 3510be068a0SCharles Keepax if (ret) { 352e80436bbSCharles Keepax dev_err(arizona->dev, "Failed to start SYSCLK: %d\n", ret); 353e80436bbSCharles Keepax goto err_fll; 354e80436bbSCharles Keepax } 355e80436bbSCharles Keepax 3563850e3eeSCharles Keepax return 0; 3573850e3eeSCharles Keepax 3583850e3eeSCharles Keepax err_fll: 3593850e3eeSCharles Keepax err = regmap_write(arizona->regmap, ARIZONA_FLL1_CONTROL_1, state->fll); 3603850e3eeSCharles Keepax if (err) 3613850e3eeSCharles Keepax dev_err(arizona->dev, 3623850e3eeSCharles Keepax "Failed to re-apply old FLL settings: %d\n", err); 3633850e3eeSCharles Keepax 3643850e3eeSCharles Keepax return ret; 3653850e3eeSCharles Keepax } 3663850e3eeSCharles Keepax 3673850e3eeSCharles Keepax static int arizona_disable_freerun_sysclk(struct arizona *arizona, 3683850e3eeSCharles Keepax struct arizona_sysclk_state *state) 3693850e3eeSCharles Keepax { 3703850e3eeSCharles Keepax int ret; 3713850e3eeSCharles Keepax 3723850e3eeSCharles Keepax ret = regmap_write(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, 3733850e3eeSCharles Keepax state->sysclk); 3743850e3eeSCharles Keepax if (ret) { 3753850e3eeSCharles Keepax dev_err(arizona->dev, 3763850e3eeSCharles Keepax "Failed to re-apply old SYSCLK settings: %d\n", ret); 3773850e3eeSCharles Keepax return ret; 3783850e3eeSCharles Keepax } 3793850e3eeSCharles Keepax 3803850e3eeSCharles Keepax ret = regmap_write(arizona->regmap, ARIZONA_FLL1_CONTROL_1, state->fll); 3813850e3eeSCharles Keepax if (ret) { 3823850e3eeSCharles Keepax dev_err(arizona->dev, 3833850e3eeSCharles Keepax "Failed to re-apply old FLL settings: %d\n", ret); 3843850e3eeSCharles Keepax return ret; 3853850e3eeSCharles Keepax } 3863850e3eeSCharles Keepax 3873850e3eeSCharles Keepax return 0; 3883850e3eeSCharles Keepax } 3893850e3eeSCharles Keepax 3903850e3eeSCharles Keepax static int wm5102_apply_hardware_patch(struct arizona *arizona) 3913850e3eeSCharles Keepax { 3923850e3eeSCharles Keepax struct arizona_sysclk_state state; 3933850e3eeSCharles Keepax int err, ret; 3943850e3eeSCharles Keepax 3953850e3eeSCharles Keepax ret = arizona_enable_freerun_sysclk(arizona, &state); 3963850e3eeSCharles Keepax if (ret) 3973850e3eeSCharles Keepax return ret; 3983850e3eeSCharles Keepax 399e80436bbSCharles Keepax /* Start the write sequencer and wait for it to finish */ 400e80436bbSCharles Keepax ret = regmap_write(arizona->regmap, ARIZONA_WRITE_SEQUENCER_CTRL_0, 401e80436bbSCharles Keepax ARIZONA_WSEQ_ENA | ARIZONA_WSEQ_START | 160); 4020be068a0SCharles Keepax if (ret) { 403e80436bbSCharles Keepax dev_err(arizona->dev, "Failed to start write sequencer: %d\n", 404e80436bbSCharles Keepax ret); 4053850e3eeSCharles Keepax goto err; 406e80436bbSCharles Keepax } 4073850e3eeSCharles Keepax 408e80436bbSCharles Keepax ret = arizona_poll_reg(arizona, 5, ARIZONA_WRITE_SEQUENCER_CTRL_1, 409e80436bbSCharles Keepax ARIZONA_WSEQ_BUSY, 0); 4100be068a0SCharles Keepax if (ret) { 411e80436bbSCharles Keepax regmap_write(arizona->regmap, ARIZONA_WRITE_SEQUENCER_CTRL_0, 412e80436bbSCharles Keepax ARIZONA_WSEQ_ABORT); 413e80436bbSCharles Keepax ret = -ETIMEDOUT; 414e80436bbSCharles Keepax } 415e80436bbSCharles Keepax 4163850e3eeSCharles Keepax err: 4173850e3eeSCharles Keepax err = arizona_disable_freerun_sysclk(arizona, &state); 418e80436bbSCharles Keepax 4190be068a0SCharles Keepax return ret ?: err; 420e80436bbSCharles Keepax } 421e80436bbSCharles Keepax 422882bc468SCharles Keepax /* 423882bc468SCharles Keepax * Register patch to some of the CODECs internal write sequences 424882bc468SCharles Keepax * to ensure a clean exit from the low power sleep state. 425882bc468SCharles Keepax */ 4268019ff6cSNariman Poushin static const struct reg_sequence wm5110_sleep_patch[] = { 427882bc468SCharles Keepax { 0x337A, 0xC100 }, 428882bc468SCharles Keepax { 0x337B, 0x0041 }, 429882bc468SCharles Keepax { 0x3300, 0xA210 }, 430882bc468SCharles Keepax { 0x3301, 0x050C }, 431882bc468SCharles Keepax }; 432882bc468SCharles Keepax 433882bc468SCharles Keepax static int wm5110_apply_sleep_patch(struct arizona *arizona) 434882bc468SCharles Keepax { 435882bc468SCharles Keepax struct arizona_sysclk_state state; 436882bc468SCharles Keepax int err, ret; 437882bc468SCharles Keepax 438882bc468SCharles Keepax ret = arizona_enable_freerun_sysclk(arizona, &state); 439882bc468SCharles Keepax if (ret) 440882bc468SCharles Keepax return ret; 441882bc468SCharles Keepax 442882bc468SCharles Keepax ret = regmap_multi_reg_write_bypassed(arizona->regmap, 443882bc468SCharles Keepax wm5110_sleep_patch, 444882bc468SCharles Keepax ARRAY_SIZE(wm5110_sleep_patch)); 445882bc468SCharles Keepax 446882bc468SCharles Keepax err = arizona_disable_freerun_sysclk(arizona, &state); 447882bc468SCharles Keepax 448882bc468SCharles Keepax return ret ?: err; 449882bc468SCharles Keepax } 450882bc468SCharles Keepax 4511c1c6bbaSCharles Keepax static int wm5102_clear_write_sequencer(struct arizona *arizona) 4521c1c6bbaSCharles Keepax { 4531c1c6bbaSCharles Keepax int ret; 4541c1c6bbaSCharles Keepax 4551c1c6bbaSCharles Keepax ret = regmap_write(arizona->regmap, ARIZONA_WRITE_SEQUENCER_CTRL_3, 4561c1c6bbaSCharles Keepax 0x0); 4571c1c6bbaSCharles Keepax if (ret) { 4581c1c6bbaSCharles Keepax dev_err(arizona->dev, 4591c1c6bbaSCharles Keepax "Failed to clear write sequencer state: %d\n", ret); 4601c1c6bbaSCharles Keepax return ret; 4611c1c6bbaSCharles Keepax } 4621c1c6bbaSCharles Keepax 4631c1c6bbaSCharles Keepax arizona_enable_reset(arizona); 4641c1c6bbaSCharles Keepax regulator_disable(arizona->dcvdd); 4651c1c6bbaSCharles Keepax 4661c1c6bbaSCharles Keepax msleep(20); 4671c1c6bbaSCharles Keepax 4681c1c6bbaSCharles Keepax ret = regulator_enable(arizona->dcvdd); 4691c1c6bbaSCharles Keepax if (ret) { 4701c1c6bbaSCharles Keepax dev_err(arizona->dev, "Failed to re-enable DCVDD: %d\n", ret); 4711c1c6bbaSCharles Keepax return ret; 4721c1c6bbaSCharles Keepax } 4731c1c6bbaSCharles Keepax arizona_disable_reset(arizona); 4741c1c6bbaSCharles Keepax 4751c1c6bbaSCharles Keepax return 0; 4761c1c6bbaSCharles Keepax } 4771c1c6bbaSCharles Keepax 47848bb9fe4SRafael J. Wysocki #ifdef CONFIG_PM 479e7811147SRichard Fitzgerald static int arizona_isolate_dcvdd(struct arizona *arizona) 480e7811147SRichard Fitzgerald { 481e7811147SRichard Fitzgerald int ret; 482e7811147SRichard Fitzgerald 483e7811147SRichard Fitzgerald ret = regmap_update_bits(arizona->regmap, 484e7811147SRichard Fitzgerald ARIZONA_ISOLATION_CONTROL, 485e7811147SRichard Fitzgerald ARIZONA_ISOLATE_DCVDD1, 486e7811147SRichard Fitzgerald ARIZONA_ISOLATE_DCVDD1); 487e7811147SRichard Fitzgerald if (ret != 0) 488e7811147SRichard Fitzgerald dev_err(arizona->dev, "Failed to isolate DCVDD: %d\n", ret); 489e7811147SRichard Fitzgerald 490e7811147SRichard Fitzgerald return ret; 491e7811147SRichard Fitzgerald } 492e7811147SRichard Fitzgerald 493e7811147SRichard Fitzgerald static int arizona_connect_dcvdd(struct arizona *arizona) 494e7811147SRichard Fitzgerald { 495e7811147SRichard Fitzgerald int ret; 496e7811147SRichard Fitzgerald 497e7811147SRichard Fitzgerald ret = regmap_update_bits(arizona->regmap, 498e7811147SRichard Fitzgerald ARIZONA_ISOLATION_CONTROL, 499e7811147SRichard Fitzgerald ARIZONA_ISOLATE_DCVDD1, 0); 500e7811147SRichard Fitzgerald if (ret != 0) 501e7811147SRichard Fitzgerald dev_err(arizona->dev, "Failed to connect DCVDD: %d\n", ret); 502e7811147SRichard Fitzgerald 503e7811147SRichard Fitzgerald return ret; 504e7811147SRichard Fitzgerald } 505e7811147SRichard Fitzgerald 506e3424273SRichard Fitzgerald static int arizona_is_jack_det_active(struct arizona *arizona) 507e3424273SRichard Fitzgerald { 508e3424273SRichard Fitzgerald unsigned int val; 509e3424273SRichard Fitzgerald int ret; 510e3424273SRichard Fitzgerald 511e3424273SRichard Fitzgerald ret = regmap_read(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE, &val); 512e3424273SRichard Fitzgerald if (ret) { 513e3424273SRichard Fitzgerald dev_err(arizona->dev, 514e3424273SRichard Fitzgerald "Failed to check jack det status: %d\n", ret); 515e3424273SRichard Fitzgerald return ret; 516e3424273SRichard Fitzgerald } else if (val & ARIZONA_JD1_ENA) { 517e3424273SRichard Fitzgerald return 1; 518e3424273SRichard Fitzgerald } else { 519e3424273SRichard Fitzgerald return 0; 520e3424273SRichard Fitzgerald } 521e3424273SRichard Fitzgerald } 522e3424273SRichard Fitzgerald 5233cc72986SMark Brown static int arizona_runtime_resume(struct device *dev) 5243cc72986SMark Brown { 5253cc72986SMark Brown struct arizona *arizona = dev_get_drvdata(dev); 5263cc72986SMark Brown int ret; 5273cc72986SMark Brown 528508c8299SMark Brown dev_dbg(arizona->dev, "Leaving AoD mode\n"); 529508c8299SMark Brown 530e6cb7341SCharles Keepax if (arizona->has_fully_powered_off) { 531e6cb7341SCharles Keepax dev_dbg(arizona->dev, "Re-enabling core supplies\n"); 532e6cb7341SCharles Keepax 533e6cb7341SCharles Keepax ret = regulator_bulk_enable(arizona->num_core_supplies, 534e6cb7341SCharles Keepax arizona->core_supplies); 535e6cb7341SCharles Keepax if (ret) { 536e6cb7341SCharles Keepax dev_err(dev, "Failed to enable core supplies: %d\n", 537e6cb7341SCharles Keepax ret); 538e6cb7341SCharles Keepax return ret; 539e6cb7341SCharles Keepax } 540e6cb7341SCharles Keepax } 541e6cb7341SCharles Keepax 54259db9691SMark Brown ret = regulator_enable(arizona->dcvdd); 54359db9691SMark Brown if (ret != 0) { 54459db9691SMark Brown dev_err(arizona->dev, "Failed to enable DCVDD: %d\n", ret); 545e6cb7341SCharles Keepax if (arizona->has_fully_powered_off) 546e6cb7341SCharles Keepax regulator_bulk_disable(arizona->num_core_supplies, 547e6cb7341SCharles Keepax arizona->core_supplies); 54859db9691SMark Brown return ret; 54959db9691SMark Brown } 5503cc72986SMark Brown 551e6cb7341SCharles Keepax if (arizona->has_fully_powered_off) { 552e6cb7341SCharles Keepax arizona_disable_reset(arizona); 553e6cb7341SCharles Keepax enable_irq(arizona->irq); 554e6cb7341SCharles Keepax arizona->has_fully_powered_off = false; 555e6cb7341SCharles Keepax } 556e6cb7341SCharles Keepax 5573cc72986SMark Brown regcache_cache_only(arizona->regmap, false); 5583cc72986SMark Brown 5594c9bb8bcSCharles Keepax switch (arizona->type) { 5604c9bb8bcSCharles Keepax case WM5102: 5615927467dSMark Brown if (arizona->external_dcvdd) { 562e7811147SRichard Fitzgerald ret = arizona_connect_dcvdd(arizona); 563e7811147SRichard Fitzgerald if (ret != 0) 5645927467dSMark Brown goto err; 5655927467dSMark Brown } 5665927467dSMark Brown 5674c9bb8bcSCharles Keepax ret = wm5102_patch(arizona); 5684c9bb8bcSCharles Keepax if (ret != 0) { 5694c9bb8bcSCharles Keepax dev_err(arizona->dev, "Failed to apply patch: %d\n", 5704c9bb8bcSCharles Keepax ret); 5714c9bb8bcSCharles Keepax goto err; 5724c9bb8bcSCharles Keepax } 573e80436bbSCharles Keepax 5740be068a0SCharles Keepax ret = wm5102_apply_hardware_patch(arizona); 5750be068a0SCharles Keepax if (ret) { 576e80436bbSCharles Keepax dev_err(arizona->dev, 577e80436bbSCharles Keepax "Failed to apply hardware patch: %d\n", 578e80436bbSCharles Keepax ret); 579e80436bbSCharles Keepax goto err; 580e80436bbSCharles Keepax } 581e80436bbSCharles Keepax break; 58296129a0eSCharles Keepax case WM5110: 58396129a0eSCharles Keepax case WM8280: 58496129a0eSCharles Keepax ret = arizona_wait_for_boot(arizona); 58596129a0eSCharles Keepax if (ret) 58696129a0eSCharles Keepax goto err; 58796129a0eSCharles Keepax 58896129a0eSCharles Keepax if (arizona->external_dcvdd) { 589e7811147SRichard Fitzgerald ret = arizona_connect_dcvdd(arizona); 590e7811147SRichard Fitzgerald if (ret != 0) 59196129a0eSCharles Keepax goto err; 59296129a0eSCharles Keepax } else { 59396129a0eSCharles Keepax /* 59496129a0eSCharles Keepax * As this is only called for the internal regulator 59596129a0eSCharles Keepax * (where we know voltage ranges available) it is ok 59696129a0eSCharles Keepax * to request an exact range. 59796129a0eSCharles Keepax */ 59896129a0eSCharles Keepax ret = regulator_set_voltage(arizona->dcvdd, 59996129a0eSCharles Keepax 1200000, 1200000); 60096129a0eSCharles Keepax if (ret < 0) { 60196129a0eSCharles Keepax dev_err(arizona->dev, 60296129a0eSCharles Keepax "Failed to set resume voltage: %d\n", 60396129a0eSCharles Keepax ret); 60496129a0eSCharles Keepax goto err; 60596129a0eSCharles Keepax } 60696129a0eSCharles Keepax } 607e6cb7341SCharles Keepax 608e6cb7341SCharles Keepax ret = wm5110_apply_sleep_patch(arizona); 609e6cb7341SCharles Keepax if (ret) { 610e6cb7341SCharles Keepax dev_err(arizona->dev, 611e6cb7341SCharles Keepax "Failed to re-apply sleep patch: %d\n", 612e6cb7341SCharles Keepax ret); 613e6cb7341SCharles Keepax goto err; 614e6cb7341SCharles Keepax } 61596129a0eSCharles Keepax break; 616ea1f3339SRichard Fitzgerald case WM1831: 617ea1f3339SRichard Fitzgerald case CS47L24: 618ea1f3339SRichard Fitzgerald ret = arizona_wait_for_boot(arizona); 619ea1f3339SRichard Fitzgerald if (ret != 0) 620ea1f3339SRichard Fitzgerald goto err; 621ea1f3339SRichard Fitzgerald break; 622e80436bbSCharles Keepax default: 62312bb68edSCharles Keepax ret = arizona_wait_for_boot(arizona); 6243762aedeSCharles Keepax if (ret != 0) 62512bb68edSCharles Keepax goto err; 62612bb68edSCharles Keepax 6275927467dSMark Brown if (arizona->external_dcvdd) { 628e7811147SRichard Fitzgerald ret = arizona_connect_dcvdd(arizona); 629e7811147SRichard Fitzgerald if (ret != 0) 6305927467dSMark Brown goto err; 6315927467dSMark Brown } 632e80436bbSCharles Keepax break; 6334c9bb8bcSCharles Keepax } 6344c9bb8bcSCharles Keepax 6359270bdf5SMark Brown ret = regcache_sync(arizona->regmap); 6369270bdf5SMark Brown if (ret != 0) { 6379270bdf5SMark Brown dev_err(arizona->dev, "Failed to restore register cache\n"); 6384816bd1cSMark Brown goto err; 6399270bdf5SMark Brown } 6403cc72986SMark Brown 6413cc72986SMark Brown return 0; 6424816bd1cSMark Brown 6434816bd1cSMark Brown err: 6444816bd1cSMark Brown regcache_cache_only(arizona->regmap, true); 6454816bd1cSMark Brown regulator_disable(arizona->dcvdd); 6464816bd1cSMark Brown return ret; 6473cc72986SMark Brown } 6483cc72986SMark Brown 6493cc72986SMark Brown static int arizona_runtime_suspend(struct device *dev) 6503cc72986SMark Brown { 6513cc72986SMark Brown struct arizona *arizona = dev_get_drvdata(dev); 652a05950a4SDan Carpenter int jd_active = 0; 6535927467dSMark Brown int ret; 6543cc72986SMark Brown 655508c8299SMark Brown dev_dbg(arizona->dev, "Entering AoD mode\n"); 656508c8299SMark Brown 65796129a0eSCharles Keepax switch (arizona->type) { 65896129a0eSCharles Keepax case WM5110: 65996129a0eSCharles Keepax case WM8280: 660e3424273SRichard Fitzgerald jd_active = arizona_is_jack_det_active(arizona); 661e3424273SRichard Fitzgerald if (jd_active < 0) 662e3424273SRichard Fitzgerald return jd_active; 663e3424273SRichard Fitzgerald 664e7811147SRichard Fitzgerald if (arizona->external_dcvdd) { 665e7811147SRichard Fitzgerald ret = arizona_isolate_dcvdd(arizona); 666e7811147SRichard Fitzgerald if (ret != 0) 667e7811147SRichard Fitzgerald return ret; 668e7811147SRichard Fitzgerald } else { 66996129a0eSCharles Keepax /* 67096129a0eSCharles Keepax * As this is only called for the internal regulator 67196129a0eSCharles Keepax * (where we know voltage ranges available) it is ok 67296129a0eSCharles Keepax * to request an exact range. 67396129a0eSCharles Keepax */ 674e7811147SRichard Fitzgerald ret = regulator_set_voltage(arizona->dcvdd, 675e7811147SRichard Fitzgerald 1175000, 1175000); 67696129a0eSCharles Keepax if (ret < 0) { 67796129a0eSCharles Keepax dev_err(arizona->dev, 678e7811147SRichard Fitzgerald "Failed to set suspend voltage: %d\n", 679e7811147SRichard Fitzgerald ret); 680e6cb7341SCharles Keepax return ret; 681e6cb7341SCharles Keepax } 682e7811147SRichard Fitzgerald } 683e6cb7341SCharles Keepax break; 684e6cb7341SCharles Keepax case WM5102: 685e3424273SRichard Fitzgerald jd_active = arizona_is_jack_det_active(arizona); 686e3424273SRichard Fitzgerald if (jd_active < 0) 687e3424273SRichard Fitzgerald return jd_active; 688e3424273SRichard Fitzgerald 689e7811147SRichard Fitzgerald if (arizona->external_dcvdd) { 690e7811147SRichard Fitzgerald ret = arizona_isolate_dcvdd(arizona); 691e7811147SRichard Fitzgerald if (ret != 0) 692e7811147SRichard Fitzgerald return ret; 693e7811147SRichard Fitzgerald } 694e7811147SRichard Fitzgerald 695e3424273SRichard Fitzgerald if (!jd_active) { 696e6cb7341SCharles Keepax ret = regmap_write(arizona->regmap, 697e6cb7341SCharles Keepax ARIZONA_WRITE_SEQUENCER_CTRL_3, 0x0); 698e6cb7341SCharles Keepax if (ret) { 699e6cb7341SCharles Keepax dev_err(arizona->dev, 700e6cb7341SCharles Keepax "Failed to clear write sequencer: %d\n", 70196129a0eSCharles Keepax ret); 70296129a0eSCharles Keepax return ret; 70396129a0eSCharles Keepax } 704e6cb7341SCharles Keepax } 70596129a0eSCharles Keepax break; 706ea1f3339SRichard Fitzgerald case WM1831: 707ea1f3339SRichard Fitzgerald case CS47L24: 708ea1f3339SRichard Fitzgerald break; 70996129a0eSCharles Keepax default: 710e3424273SRichard Fitzgerald jd_active = arizona_is_jack_det_active(arizona); 711e3424273SRichard Fitzgerald if (jd_active < 0) 712e3424273SRichard Fitzgerald return jd_active; 713e3424273SRichard Fitzgerald 714e7811147SRichard Fitzgerald if (arizona->external_dcvdd) { 715e7811147SRichard Fitzgerald ret = arizona_isolate_dcvdd(arizona); 716e7811147SRichard Fitzgerald if (ret != 0) 717e7811147SRichard Fitzgerald return ret; 718e7811147SRichard Fitzgerald } 71996129a0eSCharles Keepax break; 72096129a0eSCharles Keepax } 7215927467dSMark Brown 7223cc72986SMark Brown regcache_cache_only(arizona->regmap, true); 7233cc72986SMark Brown regcache_mark_dirty(arizona->regmap); 724e293e847SCharles Keepax regulator_disable(arizona->dcvdd); 7253cc72986SMark Brown 726e6cb7341SCharles Keepax /* Allow us to completely power down if no jack detection */ 727e3424273SRichard Fitzgerald if (!jd_active) { 728e6cb7341SCharles Keepax dev_dbg(arizona->dev, "Fully powering off\n"); 729e6cb7341SCharles Keepax 730e6cb7341SCharles Keepax arizona->has_fully_powered_off = true; 731e6cb7341SCharles Keepax 73211150929SCharles Keepax disable_irq_nosync(arizona->irq); 733e6cb7341SCharles Keepax arizona_enable_reset(arizona); 734e6cb7341SCharles Keepax regulator_bulk_disable(arizona->num_core_supplies, 735e6cb7341SCharles Keepax arizona->core_supplies); 736e6cb7341SCharles Keepax } 737e6cb7341SCharles Keepax 7383cc72986SMark Brown return 0; 7393cc72986SMark Brown } 7403cc72986SMark Brown #endif 7413cc72986SMark Brown 742dc781d0eSMark Brown #ifdef CONFIG_PM_SLEEP 74367c99296SMark Brown static int arizona_suspend(struct device *dev) 74467c99296SMark Brown { 74567c99296SMark Brown struct arizona *arizona = dev_get_drvdata(dev); 74667c99296SMark Brown 74767c99296SMark Brown dev_dbg(arizona->dev, "Suspend, disabling IRQ\n"); 74867c99296SMark Brown disable_irq(arizona->irq); 74967c99296SMark Brown 75067c99296SMark Brown return 0; 75167c99296SMark Brown } 75267c99296SMark Brown 7533612b27cSCharles Keepax static int arizona_suspend_noirq(struct device *dev) 75467c99296SMark Brown { 75567c99296SMark Brown struct arizona *arizona = dev_get_drvdata(dev); 75667c99296SMark Brown 75767c99296SMark Brown dev_dbg(arizona->dev, "Late suspend, reenabling IRQ\n"); 75867c99296SMark Brown enable_irq(arizona->irq); 75967c99296SMark Brown 76067c99296SMark Brown return 0; 76167c99296SMark Brown } 76267c99296SMark Brown 763dc781d0eSMark Brown static int arizona_resume_noirq(struct device *dev) 764dc781d0eSMark Brown { 765dc781d0eSMark Brown struct arizona *arizona = dev_get_drvdata(dev); 766dc781d0eSMark Brown 767dc781d0eSMark Brown dev_dbg(arizona->dev, "Early resume, disabling IRQ\n"); 768dc781d0eSMark Brown disable_irq(arizona->irq); 769dc781d0eSMark Brown 770dc781d0eSMark Brown return 0; 771dc781d0eSMark Brown } 772dc781d0eSMark Brown 773dc781d0eSMark Brown static int arizona_resume(struct device *dev) 774dc781d0eSMark Brown { 775dc781d0eSMark Brown struct arizona *arizona = dev_get_drvdata(dev); 776dc781d0eSMark Brown 7773612b27cSCharles Keepax dev_dbg(arizona->dev, "Resume, reenabling IRQ\n"); 778dc781d0eSMark Brown enable_irq(arizona->irq); 779dc781d0eSMark Brown 780dc781d0eSMark Brown return 0; 781dc781d0eSMark Brown } 782dc781d0eSMark Brown #endif 783dc781d0eSMark Brown 7843cc72986SMark Brown const struct dev_pm_ops arizona_pm_ops = { 7853cc72986SMark Brown SET_RUNTIME_PM_OPS(arizona_runtime_suspend, 7863cc72986SMark Brown arizona_runtime_resume, 7873cc72986SMark Brown NULL) 78867c99296SMark Brown SET_SYSTEM_SLEEP_PM_OPS(arizona_suspend, arizona_resume) 7893612b27cSCharles Keepax SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(arizona_suspend_noirq, 7903612b27cSCharles Keepax arizona_resume_noirq) 7913cc72986SMark Brown }; 7923cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_pm_ops); 7933cc72986SMark Brown 794d781009cSMark Brown #ifdef CONFIG_OF 795942786e6SLee Jones unsigned long arizona_of_get_type(struct device *dev) 796d781009cSMark Brown { 797d781009cSMark Brown const struct of_device_id *id = of_match_device(arizona_of_match, dev); 798d781009cSMark Brown 799d781009cSMark Brown if (id) 800942786e6SLee Jones return (unsigned long)id->data; 801d781009cSMark Brown else 802d781009cSMark Brown return 0; 803d781009cSMark Brown } 804d781009cSMark Brown EXPORT_SYMBOL_GPL(arizona_of_get_type); 805d781009cSMark Brown 806e4fcb1d6SCharles Keepax int arizona_of_get_named_gpio(struct arizona *arizona, const char *prop, 807e4fcb1d6SCharles Keepax bool mandatory) 808e4fcb1d6SCharles Keepax { 809e4fcb1d6SCharles Keepax int gpio; 810e4fcb1d6SCharles Keepax 811e4fcb1d6SCharles Keepax gpio = of_get_named_gpio(arizona->dev->of_node, prop, 0); 812e4fcb1d6SCharles Keepax if (gpio < 0) { 813e4fcb1d6SCharles Keepax if (mandatory) 814e4fcb1d6SCharles Keepax dev_err(arizona->dev, 815e4fcb1d6SCharles Keepax "Mandatory DT gpio %s missing/malformed: %d\n", 816e4fcb1d6SCharles Keepax prop, gpio); 817e4fcb1d6SCharles Keepax 818e4fcb1d6SCharles Keepax gpio = 0; 819e4fcb1d6SCharles Keepax } 820e4fcb1d6SCharles Keepax 821e4fcb1d6SCharles Keepax return gpio; 822e4fcb1d6SCharles Keepax } 823e4fcb1d6SCharles Keepax EXPORT_SYMBOL_GPL(arizona_of_get_named_gpio); 824e4fcb1d6SCharles Keepax 825d781009cSMark Brown static int arizona_of_get_core_pdata(struct arizona *arizona) 826d781009cSMark Brown { 827e4fcb1d6SCharles Keepax struct arizona_pdata *pdata = &arizona->pdata; 828cc47aed9SInha Song struct property *prop; 829cc47aed9SInha Song const __be32 *cur; 830cc47aed9SInha Song u32 val; 831*f4c05262SRichard Fitzgerald u32 pdm_val[ARIZONA_MAX_PDM_SPK]; 832d781009cSMark Brown int ret, i; 833cc47aed9SInha Song int count = 0; 834d781009cSMark Brown 835e4fcb1d6SCharles Keepax pdata->reset = arizona_of_get_named_gpio(arizona, "wlf,reset", true); 836d781009cSMark Brown 837d781009cSMark Brown ret = of_property_read_u32_array(arizona->dev->of_node, 838d781009cSMark Brown "wlf,gpio-defaults", 8393762aedeSCharles Keepax pdata->gpio_defaults, 8403762aedeSCharles Keepax ARRAY_SIZE(pdata->gpio_defaults)); 841d781009cSMark Brown if (ret >= 0) { 842d781009cSMark Brown /* 843d781009cSMark Brown * All values are literal except out of range values 844d781009cSMark Brown * which are chip default, translate into platform 845d781009cSMark Brown * data which uses 0 as chip default and out of range 846d781009cSMark Brown * as zero. 847d781009cSMark Brown */ 8483762aedeSCharles Keepax for (i = 0; i < ARRAY_SIZE(pdata->gpio_defaults); i++) { 8493762aedeSCharles Keepax if (pdata->gpio_defaults[i] > 0xffff) 8503762aedeSCharles Keepax pdata->gpio_defaults[i] = 0; 8513762aedeSCharles Keepax else if (pdata->gpio_defaults[i] == 0) 8523762aedeSCharles Keepax pdata->gpio_defaults[i] = 0x10000; 853d781009cSMark Brown } 854d781009cSMark Brown } else { 855d781009cSMark Brown dev_err(arizona->dev, "Failed to parse GPIO defaults: %d\n", 856d781009cSMark Brown ret); 857d781009cSMark Brown } 858d781009cSMark Brown 859cc47aed9SInha Song of_property_for_each_u32(arizona->dev->of_node, "wlf,inmode", prop, 860cc47aed9SInha Song cur, val) { 8613762aedeSCharles Keepax if (count == ARRAY_SIZE(pdata->inmode)) 862cc47aed9SInha Song break; 863cc47aed9SInha Song 8643762aedeSCharles Keepax pdata->inmode[count] = val; 865cc47aed9SInha Song count++; 866cc47aed9SInha Song } 867cc47aed9SInha Song 868e7ad27caSCharles Keepax count = 0; 869e7ad27caSCharles Keepax of_property_for_each_u32(arizona->dev->of_node, "wlf,dmic-ref", prop, 870e7ad27caSCharles Keepax cur, val) { 8713762aedeSCharles Keepax if (count == ARRAY_SIZE(pdata->dmic_ref)) 872e7ad27caSCharles Keepax break; 873e7ad27caSCharles Keepax 8743762aedeSCharles Keepax pdata->dmic_ref[count] = val; 875e7ad27caSCharles Keepax count++; 876e7ad27caSCharles Keepax } 877e7ad27caSCharles Keepax 878f199d393SCharles Keepax count = 0; 879f199d393SCharles Keepax of_property_for_each_u32(arizona->dev->of_node, "wlf,out-mono", prop, 880f199d393SCharles Keepax cur, val) { 881f199d393SCharles Keepax if (count == ARRAY_SIZE(pdata->out_mono)) 882f199d393SCharles Keepax break; 883f199d393SCharles Keepax 884f199d393SCharles Keepax pdata->out_mono[count] = !!val; 885f199d393SCharles Keepax count++; 886f199d393SCharles Keepax } 887f199d393SCharles Keepax 888*f4c05262SRichard Fitzgerald count = 0; 889*f4c05262SRichard Fitzgerald of_property_for_each_u32(arizona->dev->of_node, 890*f4c05262SRichard Fitzgerald "wlf,max-channels-clocked", 891*f4c05262SRichard Fitzgerald prop, cur, val) { 892*f4c05262SRichard Fitzgerald if (count == ARRAY_SIZE(pdata->max_channels_clocked)) 893*f4c05262SRichard Fitzgerald break; 894*f4c05262SRichard Fitzgerald 895*f4c05262SRichard Fitzgerald pdata->max_channels_clocked[count] = val; 896*f4c05262SRichard Fitzgerald count++; 897*f4c05262SRichard Fitzgerald } 898*f4c05262SRichard Fitzgerald 899*f4c05262SRichard Fitzgerald ret = of_property_read_u32_array(arizona->dev->of_node, 900*f4c05262SRichard Fitzgerald "wlf,spk-fmt", 901*f4c05262SRichard Fitzgerald pdm_val, 902*f4c05262SRichard Fitzgerald ARRAY_SIZE(pdm_val)); 903*f4c05262SRichard Fitzgerald 904*f4c05262SRichard Fitzgerald if (ret >= 0) 905*f4c05262SRichard Fitzgerald for (count = 0; count < ARRAY_SIZE(pdata->spk_fmt); ++count) 906*f4c05262SRichard Fitzgerald pdata->spk_fmt[count] = pdm_val[count]; 907*f4c05262SRichard Fitzgerald 908*f4c05262SRichard Fitzgerald ret = of_property_read_u32_array(arizona->dev->of_node, 909*f4c05262SRichard Fitzgerald "wlf,spk-mute", 910*f4c05262SRichard Fitzgerald pdm_val, 911*f4c05262SRichard Fitzgerald ARRAY_SIZE(pdm_val)); 912*f4c05262SRichard Fitzgerald 913*f4c05262SRichard Fitzgerald if (ret >= 0) 914*f4c05262SRichard Fitzgerald for (count = 0; count < ARRAY_SIZE(pdata->spk_mute); ++count) 915*f4c05262SRichard Fitzgerald pdata->spk_mute[count] = pdm_val[count]; 916*f4c05262SRichard Fitzgerald 917d781009cSMark Brown return 0; 918d781009cSMark Brown } 919d781009cSMark Brown 920d781009cSMark Brown const struct of_device_id arizona_of_match[] = { 921d781009cSMark Brown { .compatible = "wlf,wm5102", .data = (void *)WM5102 }, 922d781009cSMark Brown { .compatible = "wlf,wm5110", .data = (void *)WM5110 }, 923e5d4ef0dSRichard Fitzgerald { .compatible = "wlf,wm8280", .data = (void *)WM8280 }, 924dc7d4863SCharles Keepax { .compatible = "wlf,wm8997", .data = (void *)WM8997 }, 9256887b042SRichard Fitzgerald { .compatible = "wlf,wm8998", .data = (void *)WM8998 }, 9266887b042SRichard Fitzgerald { .compatible = "wlf,wm1814", .data = (void *)WM1814 }, 927ea1f3339SRichard Fitzgerald { .compatible = "wlf,wm1831", .data = (void *)WM1831 }, 928ea1f3339SRichard Fitzgerald { .compatible = "cirrus,cs47l24", .data = (void *)CS47L24 }, 929d781009cSMark Brown {}, 930d781009cSMark Brown }; 931d781009cSMark Brown EXPORT_SYMBOL_GPL(arizona_of_match); 932d781009cSMark Brown #else 933d781009cSMark Brown static inline int arizona_of_get_core_pdata(struct arizona *arizona) 934d781009cSMark Brown { 935d781009cSMark Brown return 0; 936d781009cSMark Brown } 937d781009cSMark Brown #endif 938d781009cSMark Brown 9395ac98553SGeert Uytterhoeven static const struct mfd_cell early_devs[] = { 9403cc72986SMark Brown { .name = "arizona-ldo1" }, 9413cc72986SMark Brown }; 9423cc72986SMark Brown 9433762aedeSCharles Keepax static const char * const wm5102_supplies[] = { 9445fc6c396SCharles Keepax "MICVDD", 94532dadef2SCharles Keepax "DBVDD2", 94632dadef2SCharles Keepax "DBVDD3", 94732dadef2SCharles Keepax "CPVDD", 94832dadef2SCharles Keepax "SPKVDDL", 94932dadef2SCharles Keepax "SPKVDDR", 95032dadef2SCharles Keepax }; 95132dadef2SCharles Keepax 9525ac98553SGeert Uytterhoeven static const struct mfd_cell wm5102_devs[] = { 953d7768111SMark Brown { .name = "arizona-micsupp" }, 954f83c218cSCharles Keepax { .name = "arizona-gpio" }, 9555fc6c396SCharles Keepax { 9565fc6c396SCharles Keepax .name = "arizona-extcon", 9575fc6c396SCharles Keepax .parent_supplies = wm5102_supplies, 9585fc6c396SCharles Keepax .num_parent_supplies = 1, /* We only need MICVDD */ 9595fc6c396SCharles Keepax }, 960503b1cacSMark Brown { .name = "arizona-haptics" }, 9613cc72986SMark Brown { .name = "arizona-pwm" }, 96232dadef2SCharles Keepax { 96332dadef2SCharles Keepax .name = "wm5102-codec", 96432dadef2SCharles Keepax .parent_supplies = wm5102_supplies, 96532dadef2SCharles Keepax .num_parent_supplies = ARRAY_SIZE(wm5102_supplies), 96632dadef2SCharles Keepax }, 9673cc72986SMark Brown }; 9683cc72986SMark Brown 9695ac98553SGeert Uytterhoeven static const struct mfd_cell wm5110_devs[] = { 970d7768111SMark Brown { .name = "arizona-micsupp" }, 971f83c218cSCharles Keepax { .name = "arizona-gpio" }, 9725fc6c396SCharles Keepax { 9735fc6c396SCharles Keepax .name = "arizona-extcon", 9745fc6c396SCharles Keepax .parent_supplies = wm5102_supplies, 9755fc6c396SCharles Keepax .num_parent_supplies = 1, /* We only need MICVDD */ 9765fc6c396SCharles Keepax }, 977503b1cacSMark Brown { .name = "arizona-haptics" }, 978e102befeSMark Brown { .name = "arizona-pwm" }, 97932dadef2SCharles Keepax { 98032dadef2SCharles Keepax .name = "wm5110-codec", 98132dadef2SCharles Keepax .parent_supplies = wm5102_supplies, 98232dadef2SCharles Keepax .num_parent_supplies = ARRAY_SIZE(wm5102_supplies), 98332dadef2SCharles Keepax }, 98432dadef2SCharles Keepax }; 98532dadef2SCharles Keepax 986ea1f3339SRichard Fitzgerald static const char * const cs47l24_supplies[] = { 987ea1f3339SRichard Fitzgerald "MICVDD", 988ea1f3339SRichard Fitzgerald "CPVDD", 989ea1f3339SRichard Fitzgerald "SPKVDD", 990ea1f3339SRichard Fitzgerald }; 991ea1f3339SRichard Fitzgerald 992ea1f3339SRichard Fitzgerald static const struct mfd_cell cs47l24_devs[] = { 993ea1f3339SRichard Fitzgerald { .name = "arizona-gpio" }, 994ea1f3339SRichard Fitzgerald { .name = "arizona-haptics" }, 995ea1f3339SRichard Fitzgerald { .name = "arizona-pwm" }, 996ea1f3339SRichard Fitzgerald { 997ea1f3339SRichard Fitzgerald .name = "cs47l24-codec", 998ea1f3339SRichard Fitzgerald .parent_supplies = cs47l24_supplies, 999ea1f3339SRichard Fitzgerald .num_parent_supplies = ARRAY_SIZE(cs47l24_supplies), 1000ea1f3339SRichard Fitzgerald }, 1001ea1f3339SRichard Fitzgerald }; 1002ea1f3339SRichard Fitzgerald 10033762aedeSCharles Keepax static const char * const wm8997_supplies[] = { 1004996c2d4fSCharles Keepax "MICVDD", 100532dadef2SCharles Keepax "DBVDD2", 100632dadef2SCharles Keepax "CPVDD", 100732dadef2SCharles Keepax "SPKVDD", 1008e102befeSMark Brown }; 1009e102befeSMark Brown 10105ac98553SGeert Uytterhoeven static const struct mfd_cell wm8997_devs[] = { 1011dc7d4863SCharles Keepax { .name = "arizona-micsupp" }, 1012f83c218cSCharles Keepax { .name = "arizona-gpio" }, 10135fc6c396SCharles Keepax { 10145fc6c396SCharles Keepax .name = "arizona-extcon", 10155fc6c396SCharles Keepax .parent_supplies = wm8997_supplies, 10165fc6c396SCharles Keepax .num_parent_supplies = 1, /* We only need MICVDD */ 10175fc6c396SCharles Keepax }, 1018dc7d4863SCharles Keepax { .name = "arizona-haptics" }, 1019dc7d4863SCharles Keepax { .name = "arizona-pwm" }, 102032dadef2SCharles Keepax { 102132dadef2SCharles Keepax .name = "wm8997-codec", 102232dadef2SCharles Keepax .parent_supplies = wm8997_supplies, 102332dadef2SCharles Keepax .num_parent_supplies = ARRAY_SIZE(wm8997_supplies), 102432dadef2SCharles Keepax }, 1025dc7d4863SCharles Keepax }; 1026dc7d4863SCharles Keepax 10276887b042SRichard Fitzgerald static const struct mfd_cell wm8998_devs[] = { 1028f83c218cSCharles Keepax { .name = "arizona-micsupp" }, 1029f83c218cSCharles Keepax { .name = "arizona-gpio" }, 10306887b042SRichard Fitzgerald { 10316887b042SRichard Fitzgerald .name = "arizona-extcon", 10326887b042SRichard Fitzgerald .parent_supplies = wm5102_supplies, 10336887b042SRichard Fitzgerald .num_parent_supplies = 1, /* We only need MICVDD */ 10346887b042SRichard Fitzgerald }, 10356887b042SRichard Fitzgerald { .name = "arizona-haptics" }, 10366887b042SRichard Fitzgerald { .name = "arizona-pwm" }, 10376887b042SRichard Fitzgerald { 10386887b042SRichard Fitzgerald .name = "wm8998-codec", 10396887b042SRichard Fitzgerald .parent_supplies = wm5102_supplies, 10406887b042SRichard Fitzgerald .num_parent_supplies = ARRAY_SIZE(wm5102_supplies), 10416887b042SRichard Fitzgerald }, 10426887b042SRichard Fitzgerald }; 10436887b042SRichard Fitzgerald 1044f791be49SBill Pemberton int arizona_dev_init(struct arizona *arizona) 10453cc72986SMark Brown { 1046cdd8da8cSSylwester Nawrocki const char * const mclk_name[] = { "mclk1", "mclk2" }; 10473cc72986SMark Brown struct device *dev = arizona->dev; 1048ea1f3339SRichard Fitzgerald const char *type_name = NULL; 10496887b042SRichard Fitzgerald unsigned int reg, val, mask; 105062d62b59SMark Brown int (*apply_patch)(struct arizona *) = NULL; 1051ae05ea36SRichard Fitzgerald const struct mfd_cell *subdevs = NULL; 1052ae05ea36SRichard Fitzgerald int n_subdevs, ret, i; 10533cc72986SMark Brown 10543cc72986SMark Brown dev_set_drvdata(arizona->dev, arizona); 10553cc72986SMark Brown mutex_init(&arizona->clk_lock); 10563cc72986SMark Brown 10573cc72986SMark Brown if (dev_get_platdata(arizona->dev)) 10583cc72986SMark Brown memcpy(&arizona->pdata, dev_get_platdata(arizona->dev), 10593cc72986SMark Brown sizeof(arizona->pdata)); 106022d7dc8aSLee Jones else 106122d7dc8aSLee Jones arizona_of_get_core_pdata(arizona); 10623cc72986SMark Brown 1063cdd8da8cSSylwester Nawrocki BUILD_BUG_ON(ARRAY_SIZE(arizona->mclk) != ARRAY_SIZE(mclk_name)); 1064cdd8da8cSSylwester Nawrocki for (i = 0; i < ARRAY_SIZE(arizona->mclk); i++) { 1065cdd8da8cSSylwester Nawrocki arizona->mclk[i] = devm_clk_get(arizona->dev, mclk_name[i]); 1066cdd8da8cSSylwester Nawrocki if (IS_ERR(arizona->mclk[i])) { 1067cdd8da8cSSylwester Nawrocki dev_info(arizona->dev, "Failed to get %s: %ld\n", 1068cdd8da8cSSylwester Nawrocki mclk_name[i], PTR_ERR(arizona->mclk[i])); 1069cdd8da8cSSylwester Nawrocki arizona->mclk[i] = NULL; 1070cdd8da8cSSylwester Nawrocki } 1071cdd8da8cSSylwester Nawrocki } 1072cdd8da8cSSylwester Nawrocki 10733cc72986SMark Brown regcache_cache_only(arizona->regmap, true); 10743cc72986SMark Brown 10753cc72986SMark Brown switch (arizona->type) { 10763cc72986SMark Brown case WM5102: 1077e102befeSMark Brown case WM5110: 1078e5d4ef0dSRichard Fitzgerald case WM8280: 1079dc7d4863SCharles Keepax case WM8997: 10806887b042SRichard Fitzgerald case WM8998: 10816887b042SRichard Fitzgerald case WM1814: 1082ea1f3339SRichard Fitzgerald case WM1831: 1083ea1f3339SRichard Fitzgerald case CS47L24: 10843cc72986SMark Brown for (i = 0; i < ARRAY_SIZE(wm5102_core_supplies); i++) 10853cc72986SMark Brown arizona->core_supplies[i].supply 10863cc72986SMark Brown = wm5102_core_supplies[i]; 10873cc72986SMark Brown arizona->num_core_supplies = ARRAY_SIZE(wm5102_core_supplies); 10883cc72986SMark Brown break; 10893cc72986SMark Brown default: 10903cc72986SMark Brown dev_err(arizona->dev, "Unknown device type %d\n", 10913cc72986SMark Brown arizona->type); 109275d8a2b0SCharles Keepax return -ENODEV; 10933cc72986SMark Brown } 10943cc72986SMark Brown 10954a8c475fSCharles Keepax /* Mark DCVDD as external, LDO1 driver will clear if internal */ 10964a8c475fSCharles Keepax arizona->external_dcvdd = true; 10974a8c475fSCharles Keepax 1098ea1f3339SRichard Fitzgerald switch (arizona->type) { 1099ea1f3339SRichard Fitzgerald case WM1831: 1100ea1f3339SRichard Fitzgerald case CS47L24: 1101ea1f3339SRichard Fitzgerald break; /* No LDO1 regulator */ 1102ea1f3339SRichard Fitzgerald default: 11033cc72986SMark Brown ret = mfd_add_devices(arizona->dev, -1, early_devs, 11040848c94fSMark Brown ARRAY_SIZE(early_devs), NULL, 0, NULL); 11053cc72986SMark Brown if (ret != 0) { 11063cc72986SMark Brown dev_err(dev, "Failed to add early children: %d\n", ret); 11073cc72986SMark Brown return ret; 11083cc72986SMark Brown } 1109ea1f3339SRichard Fitzgerald break; 1110ea1f3339SRichard Fitzgerald } 11113cc72986SMark Brown 11123cc72986SMark Brown ret = devm_regulator_bulk_get(dev, arizona->num_core_supplies, 11133cc72986SMark Brown arizona->core_supplies); 11143cc72986SMark Brown if (ret != 0) { 11153cc72986SMark Brown dev_err(dev, "Failed to request core supplies: %d\n", 11163cc72986SMark Brown ret); 11173cc72986SMark Brown goto err_early; 11183cc72986SMark Brown } 11193cc72986SMark Brown 11200c2d0ffbSCharles Keepax /** 11210c2d0ffbSCharles Keepax * Don't use devres here because the only device we have to get 11220c2d0ffbSCharles Keepax * against is the MFD device and DCVDD will likely be supplied by 11230c2d0ffbSCharles Keepax * one of its children. Meaning that the regulator will be 11240c2d0ffbSCharles Keepax * destroyed by the time devres calls regulator put. 11250c2d0ffbSCharles Keepax */ 1126e6021511SCharles Keepax arizona->dcvdd = regulator_get(arizona->dev, "DCVDD"); 112759db9691SMark Brown if (IS_ERR(arizona->dcvdd)) { 112859db9691SMark Brown ret = PTR_ERR(arizona->dcvdd); 112959db9691SMark Brown dev_err(dev, "Failed to request DCVDD: %d\n", ret); 113059db9691SMark Brown goto err_early; 113159db9691SMark Brown } 113259db9691SMark Brown 113387d3af4aSMark Brown if (arizona->pdata.reset) { 113487d3af4aSMark Brown /* Start out with /RESET low to put the chip into reset */ 11355f056bf0SCharles Keepax ret = devm_gpio_request_one(arizona->dev, arizona->pdata.reset, 113687d3af4aSMark Brown GPIOF_DIR_OUT | GPIOF_INIT_LOW, 113787d3af4aSMark Brown "arizona /RESET"); 113887d3af4aSMark Brown if (ret != 0) { 113987d3af4aSMark Brown dev_err(dev, "Failed to request /RESET: %d\n", ret); 1140e6021511SCharles Keepax goto err_dcvdd; 114187d3af4aSMark Brown } 114287d3af4aSMark Brown } 114387d3af4aSMark Brown 11443cc72986SMark Brown ret = regulator_bulk_enable(arizona->num_core_supplies, 11453cc72986SMark Brown arizona->core_supplies); 11463cc72986SMark Brown if (ret != 0) { 11473cc72986SMark Brown dev_err(dev, "Failed to enable core supplies: %d\n", 11483cc72986SMark Brown ret); 1149e6021511SCharles Keepax goto err_dcvdd; 11503cc72986SMark Brown } 11513cc72986SMark Brown 115259db9691SMark Brown ret = regulator_enable(arizona->dcvdd); 115359db9691SMark Brown if (ret != 0) { 115459db9691SMark Brown dev_err(dev, "Failed to enable DCVDD: %d\n", ret); 115559db9691SMark Brown goto err_enable; 115659db9691SMark Brown } 115759db9691SMark Brown 11582229875dSCharles Keepax arizona_disable_reset(arizona); 11593cc72986SMark Brown 11603cc72986SMark Brown regcache_cache_only(arizona->regmap, false); 11613cc72986SMark Brown 1162ca76ceb8SMark Brown /* Verify that this is a chip we know about */ 1163ca76ceb8SMark Brown ret = regmap_read(arizona->regmap, ARIZONA_SOFTWARE_RESET, ®); 1164ca76ceb8SMark Brown if (ret != 0) { 1165ca76ceb8SMark Brown dev_err(dev, "Failed to read ID register: %d\n", ret); 1166ca76ceb8SMark Brown goto err_reset; 1167ca76ceb8SMark Brown } 1168ca76ceb8SMark Brown 1169ca76ceb8SMark Brown switch (reg) { 1170ca76ceb8SMark Brown case 0x5102: 1171ca76ceb8SMark Brown case 0x5110: 11726887b042SRichard Fitzgerald case 0x6349: 1173ea1f3339SRichard Fitzgerald case 0x6363: 1174dc7d4863SCharles Keepax case 0x8997: 1175ca76ceb8SMark Brown break; 1176ca76ceb8SMark Brown default: 1177ca76ceb8SMark Brown dev_err(arizona->dev, "Unknown device ID: %x\n", reg); 117875d8a2b0SCharles Keepax ret = -ENODEV; 1179ca76ceb8SMark Brown goto err_reset; 1180ca76ceb8SMark Brown } 1181ca76ceb8SMark Brown 1182ca76ceb8SMark Brown /* If we have a /RESET GPIO we'll already be reset */ 1183ca76ceb8SMark Brown if (!arizona->pdata.reset) { 1184ca76ceb8SMark Brown ret = regmap_write(arizona->regmap, ARIZONA_SOFTWARE_RESET, 0); 1185ca76ceb8SMark Brown if (ret != 0) { 1186ca76ceb8SMark Brown dev_err(dev, "Failed to reset device: %d\n", ret); 1187ca76ceb8SMark Brown goto err_reset; 1188ca76ceb8SMark Brown } 1189ca76ceb8SMark Brown 1190b79a980fSLee Jones usleep_range(1000, 5000); 1191ca76ceb8SMark Brown } 1192ca76ceb8SMark Brown 1193ca76ceb8SMark Brown /* Ensure device startup is complete */ 1194ca76ceb8SMark Brown switch (arizona->type) { 1195ca76ceb8SMark Brown case WM5102: 119648018943SMark Brown ret = regmap_read(arizona->regmap, 119748018943SMark Brown ARIZONA_WRITE_SEQUENCER_CTRL_3, &val); 11981c1c6bbaSCharles Keepax if (ret) { 1199ca76ceb8SMark Brown dev_err(dev, 1200ca76ceb8SMark Brown "Failed to check write sequencer state: %d\n", 1201ca76ceb8SMark Brown ret); 12021c1c6bbaSCharles Keepax } else if (val & 0x01) { 12031c1c6bbaSCharles Keepax ret = wm5102_clear_write_sequencer(arizona); 12041c1c6bbaSCharles Keepax if (ret) 12051c1c6bbaSCharles Keepax return ret; 1206ca76ceb8SMark Brown } 1207ca76ceb8SMark Brown break; 12081c1c6bbaSCharles Keepax default: 12091c1c6bbaSCharles Keepax break; 12101c1c6bbaSCharles Keepax } 12111c1c6bbaSCharles Keepax 12121c1c6bbaSCharles Keepax ret = arizona_wait_for_boot(arizona); 12131c1c6bbaSCharles Keepax if (ret) { 12141c1c6bbaSCharles Keepax dev_err(arizona->dev, "Device failed initial boot: %d\n", ret); 12151c1c6bbaSCharles Keepax goto err_reset; 1216ca76ceb8SMark Brown } 1217ca76ceb8SMark Brown 1218ca76ceb8SMark Brown /* Read the device ID information & do device specific stuff */ 12193cc72986SMark Brown ret = regmap_read(arizona->regmap, ARIZONA_SOFTWARE_RESET, ®); 12203cc72986SMark Brown if (ret != 0) { 12213cc72986SMark Brown dev_err(dev, "Failed to read ID register: %d\n", ret); 122259db9691SMark Brown goto err_reset; 12233cc72986SMark Brown } 12243cc72986SMark Brown 12253cc72986SMark Brown ret = regmap_read(arizona->regmap, ARIZONA_DEVICE_REVISION, 12263cc72986SMark Brown &arizona->rev); 12273cc72986SMark Brown if (ret != 0) { 12283cc72986SMark Brown dev_err(dev, "Failed to read revision register: %d\n", ret); 122959db9691SMark Brown goto err_reset; 12303cc72986SMark Brown } 12313cc72986SMark Brown arizona->rev &= ARIZONA_DEVICE_REVISION_MASK; 12323cc72986SMark Brown 12333cc72986SMark Brown switch (reg) { 12343cc72986SMark Brown case 0x5102: 1235b61c1ec0SRichard Fitzgerald if (IS_ENABLED(CONFIG_MFD_WM5102)) { 12363cc72986SMark Brown type_name = "WM5102"; 12373cc72986SMark Brown if (arizona->type != WM5102) { 1238b61c1ec0SRichard Fitzgerald dev_warn(arizona->dev, 1239b61c1ec0SRichard Fitzgerald "WM5102 registered as %d\n", 12403cc72986SMark Brown arizona->type); 12413cc72986SMark Brown arizona->type = WM5102; 12423cc72986SMark Brown } 1243b61c1ec0SRichard Fitzgerald 124462d62b59SMark Brown apply_patch = wm5102_patch; 1245c6d6bfb1SMark Brown arizona->rev &= 0x7; 1246ae05ea36SRichard Fitzgerald subdevs = wm5102_devs; 1247ae05ea36SRichard Fitzgerald n_subdevs = ARRAY_SIZE(wm5102_devs); 1248b61c1ec0SRichard Fitzgerald } 12493cc72986SMark Brown break; 1250e102befeSMark Brown case 0x5110: 1251b61c1ec0SRichard Fitzgerald if (IS_ENABLED(CONFIG_MFD_WM5110)) { 1252e5d4ef0dSRichard Fitzgerald switch (arizona->type) { 1253e5d4ef0dSRichard Fitzgerald case WM5110: 1254e102befeSMark Brown type_name = "WM5110"; 1255e5d4ef0dSRichard Fitzgerald break; 1256e5d4ef0dSRichard Fitzgerald case WM8280: 1257e5d4ef0dSRichard Fitzgerald type_name = "WM8280"; 1258e5d4ef0dSRichard Fitzgerald break; 1259e5d4ef0dSRichard Fitzgerald default: 1260e5d4ef0dSRichard Fitzgerald type_name = "WM5110"; 1261b61c1ec0SRichard Fitzgerald dev_warn(arizona->dev, 1262b61c1ec0SRichard Fitzgerald "WM5110 registered as %d\n", 1263e102befeSMark Brown arizona->type); 1264e102befeSMark Brown arizona->type = WM5110; 1265e5d4ef0dSRichard Fitzgerald break; 1266e102befeSMark Brown } 1267b61c1ec0SRichard Fitzgerald 126862d62b59SMark Brown apply_patch = wm5110_patch; 1269ae05ea36SRichard Fitzgerald subdevs = wm5110_devs; 1270ae05ea36SRichard Fitzgerald n_subdevs = ARRAY_SIZE(wm5110_devs); 1271b61c1ec0SRichard Fitzgerald } 1272e102befeSMark Brown break; 1273ea1f3339SRichard Fitzgerald case 0x6363: 1274ea1f3339SRichard Fitzgerald if (IS_ENABLED(CONFIG_MFD_CS47L24)) { 1275ea1f3339SRichard Fitzgerald switch (arizona->type) { 1276ea1f3339SRichard Fitzgerald case CS47L24: 1277ea1f3339SRichard Fitzgerald type_name = "CS47L24"; 1278ea1f3339SRichard Fitzgerald break; 1279ea1f3339SRichard Fitzgerald 1280ea1f3339SRichard Fitzgerald case WM1831: 1281ea1f3339SRichard Fitzgerald type_name = "WM1831"; 1282ea1f3339SRichard Fitzgerald break; 1283ea1f3339SRichard Fitzgerald 1284ea1f3339SRichard Fitzgerald default: 1285ea1f3339SRichard Fitzgerald dev_warn(arizona->dev, 1286ea1f3339SRichard Fitzgerald "CS47L24 registered as %d\n", 1287ea1f3339SRichard Fitzgerald arizona->type); 1288ea1f3339SRichard Fitzgerald arizona->type = CS47L24; 1289ea1f3339SRichard Fitzgerald break; 1290ea1f3339SRichard Fitzgerald } 1291ea1f3339SRichard Fitzgerald 1292ea1f3339SRichard Fitzgerald apply_patch = cs47l24_patch; 1293ea1f3339SRichard Fitzgerald subdevs = cs47l24_devs; 1294ea1f3339SRichard Fitzgerald n_subdevs = ARRAY_SIZE(cs47l24_devs); 1295ea1f3339SRichard Fitzgerald } 1296ea1f3339SRichard Fitzgerald break; 1297dc7d4863SCharles Keepax case 0x8997: 1298b61c1ec0SRichard Fitzgerald if (IS_ENABLED(CONFIG_MFD_WM8997)) { 1299dc7d4863SCharles Keepax type_name = "WM8997"; 1300dc7d4863SCharles Keepax if (arizona->type != WM8997) { 1301b61c1ec0SRichard Fitzgerald dev_warn(arizona->dev, 1302b61c1ec0SRichard Fitzgerald "WM8997 registered as %d\n", 1303dc7d4863SCharles Keepax arizona->type); 1304dc7d4863SCharles Keepax arizona->type = WM8997; 1305dc7d4863SCharles Keepax } 1306b61c1ec0SRichard Fitzgerald 1307dc7d4863SCharles Keepax apply_patch = wm8997_patch; 1308ae05ea36SRichard Fitzgerald subdevs = wm8997_devs; 1309ae05ea36SRichard Fitzgerald n_subdevs = ARRAY_SIZE(wm8997_devs); 1310b61c1ec0SRichard Fitzgerald } 1311dc7d4863SCharles Keepax break; 13126887b042SRichard Fitzgerald case 0x6349: 1313b61c1ec0SRichard Fitzgerald if (IS_ENABLED(CONFIG_MFD_WM8998)) { 13146887b042SRichard Fitzgerald switch (arizona->type) { 13156887b042SRichard Fitzgerald case WM8998: 13166887b042SRichard Fitzgerald type_name = "WM8998"; 13176887b042SRichard Fitzgerald break; 13186887b042SRichard Fitzgerald 13196887b042SRichard Fitzgerald case WM1814: 13206887b042SRichard Fitzgerald type_name = "WM1814"; 13216887b042SRichard Fitzgerald break; 13226887b042SRichard Fitzgerald 13236887b042SRichard Fitzgerald default: 13246887b042SRichard Fitzgerald type_name = "WM8998"; 1325b61c1ec0SRichard Fitzgerald dev_warn(arizona->dev, 1326b61c1ec0SRichard Fitzgerald "WM8998 registered as %d\n", 13276887b042SRichard Fitzgerald arizona->type); 13286887b042SRichard Fitzgerald arizona->type = WM8998; 13296887b042SRichard Fitzgerald } 13306887b042SRichard Fitzgerald 13316887b042SRichard Fitzgerald apply_patch = wm8998_patch; 1332ae05ea36SRichard Fitzgerald subdevs = wm8998_devs; 1333ae05ea36SRichard Fitzgerald n_subdevs = ARRAY_SIZE(wm8998_devs); 1334b61c1ec0SRichard Fitzgerald } 13356887b042SRichard Fitzgerald break; 13363cc72986SMark Brown default: 13373cc72986SMark Brown dev_err(arizona->dev, "Unknown device ID %x\n", reg); 133875d8a2b0SCharles Keepax ret = -ENODEV; 133959db9691SMark Brown goto err_reset; 13403cc72986SMark Brown } 13413cc72986SMark Brown 1342b61c1ec0SRichard Fitzgerald if (!subdevs) { 1343b61c1ec0SRichard Fitzgerald dev_err(arizona->dev, 1344b61c1ec0SRichard Fitzgerald "No kernel support for device ID %x\n", reg); 134575d8a2b0SCharles Keepax ret = -ENODEV; 1346b61c1ec0SRichard Fitzgerald goto err_reset; 1347b61c1ec0SRichard Fitzgerald } 1348b61c1ec0SRichard Fitzgerald 13493cc72986SMark Brown dev_info(dev, "%s revision %c\n", type_name, arizona->rev + 'A'); 13503cc72986SMark Brown 135162d62b59SMark Brown if (apply_patch) { 135262d62b59SMark Brown ret = apply_patch(arizona); 135362d62b59SMark Brown if (ret != 0) { 135462d62b59SMark Brown dev_err(arizona->dev, "Failed to apply patch: %d\n", 135562d62b59SMark Brown ret); 135662d62b59SMark Brown goto err_reset; 135762d62b59SMark Brown } 1358e80436bbSCharles Keepax 1359e80436bbSCharles Keepax switch (arizona->type) { 1360e80436bbSCharles Keepax case WM5102: 13610be068a0SCharles Keepax ret = wm5102_apply_hardware_patch(arizona); 13620be068a0SCharles Keepax if (ret) { 1363e80436bbSCharles Keepax dev_err(arizona->dev, 1364e80436bbSCharles Keepax "Failed to apply hardware patch: %d\n", 1365e80436bbSCharles Keepax ret); 1366e80436bbSCharles Keepax goto err_reset; 1367e80436bbSCharles Keepax } 1368e80436bbSCharles Keepax break; 1369882bc468SCharles Keepax case WM5110: 1370882bc468SCharles Keepax case WM8280: 1371882bc468SCharles Keepax ret = wm5110_apply_sleep_patch(arizona); 1372882bc468SCharles Keepax if (ret) { 1373882bc468SCharles Keepax dev_err(arizona->dev, 1374882bc468SCharles Keepax "Failed to apply sleep patch: %d\n", 1375882bc468SCharles Keepax ret); 1376882bc468SCharles Keepax goto err_reset; 1377882bc468SCharles Keepax } 1378882bc468SCharles Keepax break; 1379e80436bbSCharles Keepax default: 1380e80436bbSCharles Keepax break; 1381e80436bbSCharles Keepax } 138262d62b59SMark Brown } 138362d62b59SMark Brown 13843cc72986SMark Brown for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) { 13853cc72986SMark Brown if (!arizona->pdata.gpio_defaults[i]) 13863cc72986SMark Brown continue; 13873cc72986SMark Brown 13883cc72986SMark Brown regmap_write(arizona->regmap, ARIZONA_GPIO1_CTRL + i, 13893cc72986SMark Brown arizona->pdata.gpio_defaults[i]); 13903cc72986SMark Brown } 13913cc72986SMark Brown 13923cc72986SMark Brown /* Chip default */ 13933cc72986SMark Brown if (!arizona->pdata.clk32k_src) 13943cc72986SMark Brown arizona->pdata.clk32k_src = ARIZONA_32KZ_MCLK2; 13953cc72986SMark Brown 13963cc72986SMark Brown switch (arizona->pdata.clk32k_src) { 13973cc72986SMark Brown case ARIZONA_32KZ_MCLK1: 13983cc72986SMark Brown case ARIZONA_32KZ_MCLK2: 13993cc72986SMark Brown regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, 14003cc72986SMark Brown ARIZONA_CLK_32K_SRC_MASK, 14013cc72986SMark Brown arizona->pdata.clk32k_src - 1); 1402767c6dc0SMark Brown arizona_clk32k_enable(arizona); 14033cc72986SMark Brown break; 14043cc72986SMark Brown case ARIZONA_32KZ_NONE: 14053cc72986SMark Brown regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, 14063cc72986SMark Brown ARIZONA_CLK_32K_SRC_MASK, 2); 14073cc72986SMark Brown break; 14083cc72986SMark Brown default: 14093cc72986SMark Brown dev_err(arizona->dev, "Invalid 32kHz clock source: %d\n", 14103cc72986SMark Brown arizona->pdata.clk32k_src); 14113cc72986SMark Brown ret = -EINVAL; 141259db9691SMark Brown goto err_reset; 14133cc72986SMark Brown } 14143cc72986SMark Brown 14153d91f828SMark Brown for (i = 0; i < ARIZONA_MAX_MICBIAS; i++) { 1416544c7aadSMark Brown if (!arizona->pdata.micbias[i].mV && 1417544c7aadSMark Brown !arizona->pdata.micbias[i].bypass) 14183d91f828SMark Brown continue; 14193d91f828SMark Brown 1420544c7aadSMark Brown /* Apply default for bypass mode */ 1421544c7aadSMark Brown if (!arizona->pdata.micbias[i].mV) 1422544c7aadSMark Brown arizona->pdata.micbias[i].mV = 2800; 1423544c7aadSMark Brown 14243d91f828SMark Brown val = (arizona->pdata.micbias[i].mV - 1500) / 100; 1425544c7aadSMark Brown 14263d91f828SMark Brown val <<= ARIZONA_MICB1_LVL_SHIFT; 14273d91f828SMark Brown 14283d91f828SMark Brown if (arizona->pdata.micbias[i].ext_cap) 14293d91f828SMark Brown val |= ARIZONA_MICB1_EXT_CAP; 14303d91f828SMark Brown 14313d91f828SMark Brown if (arizona->pdata.micbias[i].discharge) 14323d91f828SMark Brown val |= ARIZONA_MICB1_DISCH; 14333d91f828SMark Brown 1434f773fc6dSCharles Keepax if (arizona->pdata.micbias[i].soft_start) 14353d91f828SMark Brown val |= ARIZONA_MICB1_RATE; 14363d91f828SMark Brown 1437544c7aadSMark Brown if (arizona->pdata.micbias[i].bypass) 1438544c7aadSMark Brown val |= ARIZONA_MICB1_BYPASS; 1439544c7aadSMark Brown 14403d91f828SMark Brown regmap_update_bits(arizona->regmap, 14413d91f828SMark Brown ARIZONA_MIC_BIAS_CTRL_1 + i, 14423d91f828SMark Brown ARIZONA_MICB1_LVL_MASK | 144371d134b9SCharles Keepax ARIZONA_MICB1_EXT_CAP | 14443d91f828SMark Brown ARIZONA_MICB1_DISCH | 1445544c7aadSMark Brown ARIZONA_MICB1_BYPASS | 14463d91f828SMark Brown ARIZONA_MICB1_RATE, val); 14473d91f828SMark Brown } 14483d91f828SMark Brown 14493cc72986SMark Brown for (i = 0; i < ARIZONA_MAX_INPUT; i++) { 14503cc72986SMark Brown /* Default for both is 0 so noop with defaults */ 14513cc72986SMark Brown val = arizona->pdata.dmic_ref[i] 14523cc72986SMark Brown << ARIZONA_IN1_DMIC_SUP_SHIFT; 1453fc027d13SRichard Fitzgerald if (arizona->pdata.inmode[i] & ARIZONA_INMODE_DMIC) 1454fc027d13SRichard Fitzgerald val |= 1 << ARIZONA_IN1_MODE_SHIFT; 14556887b042SRichard Fitzgerald 14566887b042SRichard Fitzgerald switch (arizona->type) { 14576887b042SRichard Fitzgerald case WM8998: 14586887b042SRichard Fitzgerald case WM1814: 14596887b042SRichard Fitzgerald regmap_update_bits(arizona->regmap, 14606887b042SRichard Fitzgerald ARIZONA_ADC_DIGITAL_VOLUME_1L + (i * 8), 14616887b042SRichard Fitzgerald ARIZONA_IN1L_SRC_SE_MASK, 14626887b042SRichard Fitzgerald (arizona->pdata.inmode[i] & ARIZONA_INMODE_SE) 14636887b042SRichard Fitzgerald << ARIZONA_IN1L_SRC_SE_SHIFT); 14646887b042SRichard Fitzgerald 14656887b042SRichard Fitzgerald regmap_update_bits(arizona->regmap, 14666887b042SRichard Fitzgerald ARIZONA_ADC_DIGITAL_VOLUME_1R + (i * 8), 14676887b042SRichard Fitzgerald ARIZONA_IN1R_SRC_SE_MASK, 14686887b042SRichard Fitzgerald (arizona->pdata.inmode[i] & ARIZONA_INMODE_SE) 14696887b042SRichard Fitzgerald << ARIZONA_IN1R_SRC_SE_SHIFT); 14706887b042SRichard Fitzgerald 14716887b042SRichard Fitzgerald mask = ARIZONA_IN1_DMIC_SUP_MASK | 14726887b042SRichard Fitzgerald ARIZONA_IN1_MODE_MASK; 14736887b042SRichard Fitzgerald break; 14746887b042SRichard Fitzgerald default: 1475fc027d13SRichard Fitzgerald if (arizona->pdata.inmode[i] & ARIZONA_INMODE_SE) 1476fc027d13SRichard Fitzgerald val |= 1 << ARIZONA_IN1_SINGLE_ENDED_SHIFT; 14773cc72986SMark Brown 14786887b042SRichard Fitzgerald mask = ARIZONA_IN1_DMIC_SUP_MASK | 14796887b042SRichard Fitzgerald ARIZONA_IN1_MODE_MASK | 14806887b042SRichard Fitzgerald ARIZONA_IN1_SINGLE_ENDED_MASK; 14816887b042SRichard Fitzgerald break; 14826887b042SRichard Fitzgerald } 14836887b042SRichard Fitzgerald 14843cc72986SMark Brown regmap_update_bits(arizona->regmap, 14853cc72986SMark Brown ARIZONA_IN1L_CONTROL + (i * 8), 14866887b042SRichard Fitzgerald mask, val); 14873cc72986SMark Brown } 14883cc72986SMark Brown 14893cc72986SMark Brown for (i = 0; i < ARIZONA_MAX_OUTPUT; i++) { 14903cc72986SMark Brown /* Default is 0 so noop with defaults */ 14913cc72986SMark Brown if (arizona->pdata.out_mono[i]) 14923cc72986SMark Brown val = ARIZONA_OUT1_MONO; 14933cc72986SMark Brown else 14943cc72986SMark Brown val = 0; 14953cc72986SMark Brown 14963cc72986SMark Brown regmap_update_bits(arizona->regmap, 14973cc72986SMark Brown ARIZONA_OUTPUT_PATH_CONFIG_1L + (i * 8), 14983cc72986SMark Brown ARIZONA_OUT1_MONO, val); 14993cc72986SMark Brown } 15003cc72986SMark Brown 15013cc72986SMark Brown for (i = 0; i < ARIZONA_MAX_PDM_SPK; i++) { 15023cc72986SMark Brown if (arizona->pdata.spk_mute[i]) 15033cc72986SMark Brown regmap_update_bits(arizona->regmap, 15042a51da04SMark Brown ARIZONA_PDM_SPK1_CTRL_1 + (i * 2), 15053cc72986SMark Brown ARIZONA_SPK1_MUTE_ENDIAN_MASK | 15063cc72986SMark Brown ARIZONA_SPK1_MUTE_SEQ1_MASK, 15073cc72986SMark Brown arizona->pdata.spk_mute[i]); 15083cc72986SMark Brown 15093cc72986SMark Brown if (arizona->pdata.spk_fmt[i]) 15103cc72986SMark Brown regmap_update_bits(arizona->regmap, 15112a51da04SMark Brown ARIZONA_PDM_SPK1_CTRL_2 + (i * 2), 15123cc72986SMark Brown ARIZONA_SPK1_FMT_MASK, 15133cc72986SMark Brown arizona->pdata.spk_fmt[i]); 15143cc72986SMark Brown } 15153cc72986SMark Brown 151672e43164SCharles Keepax pm_runtime_set_active(arizona->dev); 151772e43164SCharles Keepax pm_runtime_enable(arizona->dev); 151872e43164SCharles Keepax 15193cc72986SMark Brown /* Set up for interrupts */ 15203cc72986SMark Brown ret = arizona_irq_init(arizona); 15213cc72986SMark Brown if (ret != 0) 1522d347792cSCharles Keepax goto err_pm; 15233cc72986SMark Brown 152472e43164SCharles Keepax pm_runtime_set_autosuspend_delay(arizona->dev, 100); 152572e43164SCharles Keepax pm_runtime_use_autosuspend(arizona->dev); 152672e43164SCharles Keepax 15273cc72986SMark Brown arizona_request_irq(arizona, ARIZONA_IRQ_CLKGEN_ERR, "CLKGEN error", 15283cc72986SMark Brown arizona_clkgen_err, arizona); 15293cc72986SMark Brown arizona_request_irq(arizona, ARIZONA_IRQ_OVERCLOCKED, "Overclocked", 15303cc72986SMark Brown arizona_overclocked, arizona); 15313cc72986SMark Brown arizona_request_irq(arizona, ARIZONA_IRQ_UNDERCLOCKED, "Underclocked", 15323cc72986SMark Brown arizona_underclocked, arizona); 15333cc72986SMark Brown 1534ae05ea36SRichard Fitzgerald ret = mfd_add_devices(arizona->dev, PLATFORM_DEVID_NONE, 1535ae05ea36SRichard Fitzgerald subdevs, n_subdevs, NULL, 0, NULL); 15363cc72986SMark Brown 1537ae05ea36SRichard Fitzgerald if (ret) { 15383cc72986SMark Brown dev_err(arizona->dev, "Failed to add subdevices: %d\n", ret); 15393cc72986SMark Brown goto err_irq; 15403cc72986SMark Brown } 15413cc72986SMark Brown 15423cc72986SMark Brown return 0; 15433cc72986SMark Brown 15443cc72986SMark Brown err_irq: 15453cc72986SMark Brown arizona_irq_exit(arizona); 1546d347792cSCharles Keepax err_pm: 1547d347792cSCharles Keepax pm_runtime_disable(arizona->dev); 15483cc72986SMark Brown err_reset: 15492229875dSCharles Keepax arizona_enable_reset(arizona); 155059db9691SMark Brown regulator_disable(arizona->dcvdd); 15513cc72986SMark Brown err_enable: 15523a36a0dbSMark Brown regulator_bulk_disable(arizona->num_core_supplies, 15533cc72986SMark Brown arizona->core_supplies); 1554e6021511SCharles Keepax err_dcvdd: 1555e6021511SCharles Keepax regulator_put(arizona->dcvdd); 15563cc72986SMark Brown err_early: 15573cc72986SMark Brown mfd_remove_devices(dev); 15583cc72986SMark Brown return ret; 15593cc72986SMark Brown } 15603cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_dev_init); 15613cc72986SMark Brown 15624740f73fSBill Pemberton int arizona_dev_exit(struct arizona *arizona) 15633cc72986SMark Brown { 1564b804020aSCharles Keepax pm_runtime_disable(arizona->dev); 1565b804020aSCharles Keepax 1566df6b3352SCharles Keepax regulator_disable(arizona->dcvdd); 1567e6021511SCharles Keepax regulator_put(arizona->dcvdd); 1568df6b3352SCharles Keepax 15693cc72986SMark Brown mfd_remove_devices(arizona->dev); 15703cc72986SMark Brown arizona_free_irq(arizona, ARIZONA_IRQ_UNDERCLOCKED, arizona); 15713cc72986SMark Brown arizona_free_irq(arizona, ARIZONA_IRQ_OVERCLOCKED, arizona); 15723cc72986SMark Brown arizona_free_irq(arizona, ARIZONA_IRQ_CLKGEN_ERR, arizona); 15733cc72986SMark Brown arizona_irq_exit(arizona); 15742229875dSCharles Keepax arizona_enable_reset(arizona); 1575df6b3352SCharles Keepax 15764420286eSCharles Keepax regulator_bulk_disable(arizona->num_core_supplies, 15771d017b6bSMark Brown arizona->core_supplies); 15783cc72986SMark Brown return 0; 15793cc72986SMark Brown } 15803cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_dev_exit); 1581