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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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