13cc72986SMark Brown /* 23cc72986SMark Brown * Arizona core driver 33cc72986SMark Brown * 43cc72986SMark Brown * Copyright 2012 Wolfson Microelectronics plc 53cc72986SMark Brown * 63cc72986SMark Brown * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> 73cc72986SMark Brown * 83cc72986SMark Brown * This program is free software; you can redistribute it and/or modify 93cc72986SMark Brown * it under the terms of the GNU General Public License version 2 as 103cc72986SMark Brown * published by the Free Software Foundation. 113cc72986SMark Brown */ 123cc72986SMark Brown 133cc72986SMark Brown #include <linux/delay.h> 1459db9691SMark Brown #include <linux/err.h> 153cc72986SMark Brown #include <linux/gpio.h> 163cc72986SMark Brown #include <linux/interrupt.h> 173cc72986SMark Brown #include <linux/mfd/core.h> 183cc72986SMark Brown #include <linux/module.h> 19d781009cSMark Brown #include <linux/of.h> 20d781009cSMark Brown #include <linux/of_device.h> 21d781009cSMark Brown #include <linux/of_gpio.h> 223cc72986SMark Brown #include <linux/pm_runtime.h> 233cc72986SMark Brown #include <linux/regmap.h> 243cc72986SMark Brown #include <linux/regulator/consumer.h> 255927467dSMark Brown #include <linux/regulator/machine.h> 263cc72986SMark Brown #include <linux/slab.h> 273cc72986SMark Brown 283cc72986SMark Brown #include <linux/mfd/arizona/core.h> 293cc72986SMark Brown #include <linux/mfd/arizona/registers.h> 303cc72986SMark Brown 313cc72986SMark Brown #include "arizona.h" 323cc72986SMark Brown 333cc72986SMark Brown static const char *wm5102_core_supplies[] = { 343cc72986SMark Brown "AVDD", 353cc72986SMark Brown "DBVDD1", 363cc72986SMark Brown }; 373cc72986SMark Brown 383cc72986SMark Brown int arizona_clk32k_enable(struct arizona *arizona) 393cc72986SMark Brown { 403cc72986SMark Brown int ret = 0; 413cc72986SMark Brown 423cc72986SMark Brown mutex_lock(&arizona->clk_lock); 433cc72986SMark Brown 443cc72986SMark Brown arizona->clk32k_ref++; 453cc72986SMark Brown 46247fa192SMark Brown if (arizona->clk32k_ref == 1) { 47247fa192SMark Brown switch (arizona->pdata.clk32k_src) { 48247fa192SMark Brown case ARIZONA_32KZ_MCLK1: 49247fa192SMark Brown ret = pm_runtime_get_sync(arizona->dev); 50247fa192SMark Brown if (ret != 0) 51247fa192SMark Brown goto out; 52247fa192SMark Brown break; 53247fa192SMark Brown } 54247fa192SMark Brown 553cc72986SMark Brown ret = regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, 563cc72986SMark Brown ARIZONA_CLK_32K_ENA, 573cc72986SMark Brown ARIZONA_CLK_32K_ENA); 58247fa192SMark Brown } 593cc72986SMark Brown 60247fa192SMark Brown out: 613cc72986SMark Brown if (ret != 0) 623cc72986SMark Brown arizona->clk32k_ref--; 633cc72986SMark Brown 643cc72986SMark Brown mutex_unlock(&arizona->clk_lock); 653cc72986SMark Brown 663cc72986SMark Brown return ret; 673cc72986SMark Brown } 683cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_clk32k_enable); 693cc72986SMark Brown 703cc72986SMark Brown int arizona_clk32k_disable(struct arizona *arizona) 713cc72986SMark Brown { 723cc72986SMark Brown int ret = 0; 733cc72986SMark Brown 743cc72986SMark Brown mutex_lock(&arizona->clk_lock); 753cc72986SMark Brown 763cc72986SMark Brown BUG_ON(arizona->clk32k_ref <= 0); 773cc72986SMark Brown 783cc72986SMark Brown arizona->clk32k_ref--; 793cc72986SMark Brown 80247fa192SMark Brown if (arizona->clk32k_ref == 0) { 813cc72986SMark Brown regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, 823cc72986SMark Brown ARIZONA_CLK_32K_ENA, 0); 833cc72986SMark Brown 84247fa192SMark Brown switch (arizona->pdata.clk32k_src) { 85247fa192SMark Brown case ARIZONA_32KZ_MCLK1: 86247fa192SMark Brown pm_runtime_put_sync(arizona->dev); 87247fa192SMark Brown break; 88247fa192SMark Brown } 89247fa192SMark Brown } 90247fa192SMark Brown 913cc72986SMark Brown mutex_unlock(&arizona->clk_lock); 923cc72986SMark Brown 933cc72986SMark Brown return ret; 943cc72986SMark Brown } 953cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_clk32k_disable); 963cc72986SMark Brown 973cc72986SMark Brown static irqreturn_t arizona_clkgen_err(int irq, void *data) 983cc72986SMark Brown { 993cc72986SMark Brown struct arizona *arizona = data; 1003cc72986SMark Brown 1013cc72986SMark Brown dev_err(arizona->dev, "CLKGEN error\n"); 1023cc72986SMark Brown 1033cc72986SMark Brown return IRQ_HANDLED; 1043cc72986SMark Brown } 1053cc72986SMark Brown 1063cc72986SMark Brown static irqreturn_t arizona_underclocked(int irq, void *data) 1073cc72986SMark Brown { 1083cc72986SMark Brown struct arizona *arizona = data; 1093cc72986SMark Brown unsigned int val; 1103cc72986SMark Brown int ret; 1113cc72986SMark Brown 1123cc72986SMark Brown ret = regmap_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_8, 1133cc72986SMark Brown &val); 1143cc72986SMark Brown if (ret != 0) { 1153cc72986SMark Brown dev_err(arizona->dev, "Failed to read underclock status: %d\n", 1163cc72986SMark Brown ret); 1173cc72986SMark Brown return IRQ_NONE; 1183cc72986SMark Brown } 1193cc72986SMark Brown 1203cc72986SMark Brown if (val & ARIZONA_AIF3_UNDERCLOCKED_STS) 1213cc72986SMark Brown dev_err(arizona->dev, "AIF3 underclocked\n"); 1223cc72986SMark Brown if (val & ARIZONA_AIF2_UNDERCLOCKED_STS) 1233ebef34dSCharles Keepax dev_err(arizona->dev, "AIF2 underclocked\n"); 1243ebef34dSCharles Keepax if (val & ARIZONA_AIF1_UNDERCLOCKED_STS) 1253cc72986SMark Brown dev_err(arizona->dev, "AIF1 underclocked\n"); 1266e440d27SCharles Keepax if (val & ARIZONA_ISRC3_UNDERCLOCKED_STS) 1276e440d27SCharles Keepax dev_err(arizona->dev, "ISRC3 underclocked\n"); 1283cc72986SMark Brown if (val & ARIZONA_ISRC2_UNDERCLOCKED_STS) 1293cc72986SMark Brown dev_err(arizona->dev, "ISRC2 underclocked\n"); 1303cc72986SMark Brown if (val & ARIZONA_ISRC1_UNDERCLOCKED_STS) 1313cc72986SMark Brown dev_err(arizona->dev, "ISRC1 underclocked\n"); 1323cc72986SMark Brown if (val & ARIZONA_FX_UNDERCLOCKED_STS) 1333cc72986SMark Brown dev_err(arizona->dev, "FX underclocked\n"); 1343cc72986SMark Brown if (val & ARIZONA_ASRC_UNDERCLOCKED_STS) 1353cc72986SMark Brown dev_err(arizona->dev, "ASRC underclocked\n"); 1363cc72986SMark Brown if (val & ARIZONA_DAC_UNDERCLOCKED_STS) 1373cc72986SMark Brown dev_err(arizona->dev, "DAC underclocked\n"); 1383cc72986SMark Brown if (val & ARIZONA_ADC_UNDERCLOCKED_STS) 1393cc72986SMark Brown dev_err(arizona->dev, "ADC underclocked\n"); 1403cc72986SMark Brown if (val & ARIZONA_MIXER_UNDERCLOCKED_STS) 141648a9880SMark Brown dev_err(arizona->dev, "Mixer dropped sample\n"); 1423cc72986SMark Brown 1433cc72986SMark Brown return IRQ_HANDLED; 1443cc72986SMark Brown } 1453cc72986SMark Brown 1463cc72986SMark Brown static irqreturn_t arizona_overclocked(int irq, void *data) 1473cc72986SMark Brown { 1483cc72986SMark Brown struct arizona *arizona = data; 1493cc72986SMark Brown unsigned int val[2]; 1503cc72986SMark Brown int ret; 1513cc72986SMark Brown 1523cc72986SMark Brown ret = regmap_bulk_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_6, 1533cc72986SMark Brown &val[0], 2); 1543cc72986SMark Brown if (ret != 0) { 1553cc72986SMark Brown dev_err(arizona->dev, "Failed to read overclock status: %d\n", 1563cc72986SMark Brown ret); 1573cc72986SMark Brown return IRQ_NONE; 1583cc72986SMark Brown } 1593cc72986SMark Brown 1603cc72986SMark Brown if (val[0] & ARIZONA_PWM_OVERCLOCKED_STS) 1613cc72986SMark Brown dev_err(arizona->dev, "PWM overclocked\n"); 1623cc72986SMark Brown if (val[0] & ARIZONA_FX_CORE_OVERCLOCKED_STS) 1633cc72986SMark Brown dev_err(arizona->dev, "FX core overclocked\n"); 1643cc72986SMark Brown if (val[0] & ARIZONA_DAC_SYS_OVERCLOCKED_STS) 1653cc72986SMark Brown dev_err(arizona->dev, "DAC SYS overclocked\n"); 1663cc72986SMark Brown if (val[0] & ARIZONA_DAC_WARP_OVERCLOCKED_STS) 1673cc72986SMark Brown dev_err(arizona->dev, "DAC WARP overclocked\n"); 1683cc72986SMark Brown if (val[0] & ARIZONA_ADC_OVERCLOCKED_STS) 1693cc72986SMark Brown dev_err(arizona->dev, "ADC overclocked\n"); 1703cc72986SMark Brown if (val[0] & ARIZONA_MIXER_OVERCLOCKED_STS) 1713cc72986SMark Brown dev_err(arizona->dev, "Mixer overclocked\n"); 1723cc72986SMark Brown if (val[0] & ARIZONA_AIF3_SYNC_OVERCLOCKED_STS) 1733cc72986SMark Brown dev_err(arizona->dev, "AIF3 overclocked\n"); 1743cc72986SMark Brown if (val[0] & ARIZONA_AIF2_SYNC_OVERCLOCKED_STS) 1753cc72986SMark Brown dev_err(arizona->dev, "AIF2 overclocked\n"); 1763cc72986SMark Brown if (val[0] & ARIZONA_AIF1_SYNC_OVERCLOCKED_STS) 1773cc72986SMark Brown dev_err(arizona->dev, "AIF1 overclocked\n"); 1783cc72986SMark Brown if (val[0] & ARIZONA_PAD_CTRL_OVERCLOCKED_STS) 1793cc72986SMark Brown dev_err(arizona->dev, "Pad control overclocked\n"); 1803cc72986SMark Brown 1813cc72986SMark Brown if (val[1] & ARIZONA_SLIMBUS_SUBSYS_OVERCLOCKED_STS) 1823cc72986SMark Brown dev_err(arizona->dev, "Slimbus subsystem overclocked\n"); 1833cc72986SMark Brown if (val[1] & ARIZONA_SLIMBUS_ASYNC_OVERCLOCKED_STS) 1843cc72986SMark Brown dev_err(arizona->dev, "Slimbus async overclocked\n"); 1853cc72986SMark Brown if (val[1] & ARIZONA_SLIMBUS_SYNC_OVERCLOCKED_STS) 1863cc72986SMark Brown dev_err(arizona->dev, "Slimbus sync overclocked\n"); 1873cc72986SMark Brown if (val[1] & ARIZONA_ASRC_ASYNC_SYS_OVERCLOCKED_STS) 1883cc72986SMark Brown dev_err(arizona->dev, "ASRC async system overclocked\n"); 1893cc72986SMark Brown if (val[1] & ARIZONA_ASRC_ASYNC_WARP_OVERCLOCKED_STS) 1903cc72986SMark Brown dev_err(arizona->dev, "ASRC async WARP overclocked\n"); 1913cc72986SMark Brown if (val[1] & ARIZONA_ASRC_SYNC_SYS_OVERCLOCKED_STS) 1923cc72986SMark Brown dev_err(arizona->dev, "ASRC sync system overclocked\n"); 1933cc72986SMark Brown if (val[1] & ARIZONA_ASRC_SYNC_WARP_OVERCLOCKED_STS) 1943cc72986SMark Brown dev_err(arizona->dev, "ASRC sync WARP overclocked\n"); 1953cc72986SMark Brown if (val[1] & ARIZONA_ADSP2_1_OVERCLOCKED_STS) 1963cc72986SMark Brown dev_err(arizona->dev, "DSP1 overclocked\n"); 1976e440d27SCharles Keepax if (val[1] & ARIZONA_ISRC3_OVERCLOCKED_STS) 1986e440d27SCharles Keepax dev_err(arizona->dev, "ISRC3 overclocked\n"); 1993cc72986SMark Brown if (val[1] & ARIZONA_ISRC2_OVERCLOCKED_STS) 2003cc72986SMark Brown dev_err(arizona->dev, "ISRC2 overclocked\n"); 2013cc72986SMark Brown if (val[1] & ARIZONA_ISRC1_OVERCLOCKED_STS) 2023cc72986SMark Brown dev_err(arizona->dev, "ISRC1 overclocked\n"); 2033cc72986SMark Brown 2043cc72986SMark Brown return IRQ_HANDLED; 2053cc72986SMark Brown } 2063cc72986SMark Brown 2079d53dfdcSCharles Keepax static int arizona_poll_reg(struct arizona *arizona, 2089d53dfdcSCharles Keepax int timeout, unsigned int reg, 2099d53dfdcSCharles Keepax unsigned int mask, unsigned int target) 2109d53dfdcSCharles Keepax { 2119d53dfdcSCharles Keepax unsigned int val = 0; 2129d53dfdcSCharles Keepax int ret, i; 2139d53dfdcSCharles Keepax 2149d53dfdcSCharles Keepax for (i = 0; i < timeout; i++) { 2159d53dfdcSCharles Keepax ret = regmap_read(arizona->regmap, reg, &val); 2169d53dfdcSCharles Keepax if (ret != 0) { 2179d53dfdcSCharles Keepax dev_err(arizona->dev, "Failed to read reg %u: %d\n", 2189d53dfdcSCharles Keepax reg, ret); 2199d53dfdcSCharles Keepax continue; 2209d53dfdcSCharles Keepax } 2219d53dfdcSCharles Keepax 2229d53dfdcSCharles Keepax if ((val & mask) == target) 2239d53dfdcSCharles Keepax return 0; 2249d53dfdcSCharles Keepax 2259d53dfdcSCharles Keepax msleep(1); 2269d53dfdcSCharles Keepax } 2279d53dfdcSCharles Keepax 2289d53dfdcSCharles Keepax dev_err(arizona->dev, "Polling reg %u timed out: %x\n", reg, val); 2299d53dfdcSCharles Keepax return -ETIMEDOUT; 2309d53dfdcSCharles Keepax } 2319d53dfdcSCharles Keepax 2323cc72986SMark Brown static int arizona_wait_for_boot(struct arizona *arizona) 2333cc72986SMark Brown { 2349d53dfdcSCharles Keepax int ret; 2353cc72986SMark Brown 2363cc72986SMark Brown /* 2373cc72986SMark Brown * We can't use an interrupt as we need to runtime resume to do so, 2383cc72986SMark Brown * we won't race with the interrupt handler as it'll be blocked on 2393cc72986SMark Brown * runtime resume. 2403cc72986SMark Brown */ 2419d53dfdcSCharles Keepax ret = arizona_poll_reg(arizona, 5, ARIZONA_INTERRUPT_RAW_STATUS_5, 2429d53dfdcSCharles Keepax ARIZONA_BOOT_DONE_STS, ARIZONA_BOOT_DONE_STS); 2433cc72986SMark Brown 2449d53dfdcSCharles Keepax if (!ret) 2453cc72986SMark Brown regmap_write(arizona->regmap, ARIZONA_INTERRUPT_STATUS_5, 2463cc72986SMark Brown ARIZONA_BOOT_DONE_STS); 2473cc72986SMark Brown 2483cc72986SMark Brown pm_runtime_mark_last_busy(arizona->dev); 2493cc72986SMark Brown 2509d53dfdcSCharles Keepax return ret; 2513cc72986SMark Brown } 2523cc72986SMark Brown 253e80436bbSCharles Keepax static int arizona_apply_hardware_patch(struct arizona* arizona) 254e80436bbSCharles Keepax { 255e80436bbSCharles Keepax unsigned int fll, sysclk; 256e80436bbSCharles Keepax int ret, err; 257e80436bbSCharles Keepax 258e80436bbSCharles Keepax /* Cache existing FLL and SYSCLK settings */ 259e80436bbSCharles Keepax ret = regmap_read(arizona->regmap, ARIZONA_FLL1_CONTROL_1, &fll); 260e80436bbSCharles Keepax if (ret != 0) { 261e80436bbSCharles Keepax dev_err(arizona->dev, "Failed to cache FLL settings: %d\n", 262e80436bbSCharles Keepax ret); 263e80436bbSCharles Keepax return ret; 264e80436bbSCharles Keepax } 265e80436bbSCharles Keepax ret = regmap_read(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, &sysclk); 266e80436bbSCharles Keepax if (ret != 0) { 267e80436bbSCharles Keepax dev_err(arizona->dev, "Failed to cache SYSCLK settings: %d\n", 268e80436bbSCharles Keepax ret); 269e80436bbSCharles Keepax return ret; 270e80436bbSCharles Keepax } 271e80436bbSCharles Keepax 272e80436bbSCharles Keepax /* Start up SYSCLK using the FLL in free running mode */ 273e80436bbSCharles Keepax ret = regmap_write(arizona->regmap, ARIZONA_FLL1_CONTROL_1, 274e80436bbSCharles Keepax ARIZONA_FLL1_ENA | ARIZONA_FLL1_FREERUN); 275e80436bbSCharles Keepax if (ret != 0) { 276e80436bbSCharles Keepax dev_err(arizona->dev, 277e80436bbSCharles Keepax "Failed to start FLL in freerunning mode: %d\n", 278e80436bbSCharles Keepax ret); 279e80436bbSCharles Keepax return ret; 280e80436bbSCharles Keepax } 281e80436bbSCharles Keepax ret = arizona_poll_reg(arizona, 25, ARIZONA_INTERRUPT_RAW_STATUS_5, 282e80436bbSCharles Keepax ARIZONA_FLL1_CLOCK_OK_STS, 283e80436bbSCharles Keepax ARIZONA_FLL1_CLOCK_OK_STS); 284e80436bbSCharles Keepax if (ret != 0) { 285e80436bbSCharles Keepax ret = -ETIMEDOUT; 286e80436bbSCharles Keepax goto err_fll; 287e80436bbSCharles Keepax } 288e80436bbSCharles Keepax 289e80436bbSCharles Keepax ret = regmap_write(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, 0x0144); 290e80436bbSCharles Keepax if (ret != 0) { 291e80436bbSCharles Keepax dev_err(arizona->dev, "Failed to start SYSCLK: %d\n", ret); 292e80436bbSCharles Keepax goto err_fll; 293e80436bbSCharles Keepax } 294e80436bbSCharles Keepax 295e80436bbSCharles Keepax /* Start the write sequencer and wait for it to finish */ 296e80436bbSCharles Keepax ret = regmap_write(arizona->regmap, ARIZONA_WRITE_SEQUENCER_CTRL_0, 297e80436bbSCharles Keepax ARIZONA_WSEQ_ENA | ARIZONA_WSEQ_START | 160); 298e80436bbSCharles Keepax if (ret != 0) { 299e80436bbSCharles Keepax dev_err(arizona->dev, "Failed to start write sequencer: %d\n", 300e80436bbSCharles Keepax ret); 301e80436bbSCharles Keepax goto err_sysclk; 302e80436bbSCharles Keepax } 303e80436bbSCharles Keepax ret = arizona_poll_reg(arizona, 5, ARIZONA_WRITE_SEQUENCER_CTRL_1, 304e80436bbSCharles Keepax ARIZONA_WSEQ_BUSY, 0); 305e80436bbSCharles Keepax if (ret != 0) { 306e80436bbSCharles Keepax regmap_write(arizona->regmap, ARIZONA_WRITE_SEQUENCER_CTRL_0, 307e80436bbSCharles Keepax ARIZONA_WSEQ_ABORT); 308e80436bbSCharles Keepax ret = -ETIMEDOUT; 309e80436bbSCharles Keepax } 310e80436bbSCharles Keepax 311e80436bbSCharles Keepax err_sysclk: 312e80436bbSCharles Keepax err = regmap_write(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, sysclk); 313e80436bbSCharles Keepax if (err != 0) { 314e80436bbSCharles Keepax dev_err(arizona->dev, 315e80436bbSCharles Keepax "Failed to re-apply old SYSCLK settings: %d\n", 316e80436bbSCharles Keepax err); 317e80436bbSCharles Keepax } 318e80436bbSCharles Keepax 319e80436bbSCharles Keepax err_fll: 320e80436bbSCharles Keepax err = regmap_write(arizona->regmap, ARIZONA_FLL1_CONTROL_1, fll); 321e80436bbSCharles Keepax if (err != 0) { 322e80436bbSCharles Keepax dev_err(arizona->dev, 323e80436bbSCharles Keepax "Failed to re-apply old FLL settings: %d\n", 324e80436bbSCharles Keepax err); 325e80436bbSCharles Keepax } 326e80436bbSCharles Keepax 327e80436bbSCharles Keepax if (ret != 0) 328e80436bbSCharles Keepax return ret; 329e80436bbSCharles Keepax else 330e80436bbSCharles Keepax return err; 331e80436bbSCharles Keepax } 332e80436bbSCharles Keepax 333*48bb9fe4SRafael J. Wysocki #ifdef CONFIG_PM 3343cc72986SMark Brown static int arizona_runtime_resume(struct device *dev) 3353cc72986SMark Brown { 3363cc72986SMark Brown struct arizona *arizona = dev_get_drvdata(dev); 3373cc72986SMark Brown int ret; 3383cc72986SMark Brown 339508c8299SMark Brown dev_dbg(arizona->dev, "Leaving AoD mode\n"); 340508c8299SMark Brown 34159db9691SMark Brown ret = regulator_enable(arizona->dcvdd); 34259db9691SMark Brown if (ret != 0) { 34359db9691SMark Brown dev_err(arizona->dev, "Failed to enable DCVDD: %d\n", ret); 34459db9691SMark Brown return ret; 34559db9691SMark Brown } 3463cc72986SMark Brown 3473cc72986SMark Brown regcache_cache_only(arizona->regmap, false); 3483cc72986SMark Brown 3494c9bb8bcSCharles Keepax switch (arizona->type) { 3504c9bb8bcSCharles Keepax case WM5102: 3515927467dSMark Brown if (arizona->external_dcvdd) { 3525927467dSMark Brown ret = regmap_update_bits(arizona->regmap, 3535927467dSMark Brown ARIZONA_ISOLATION_CONTROL, 3545927467dSMark Brown ARIZONA_ISOLATE_DCVDD1, 0); 3555927467dSMark Brown if (ret != 0) { 3565927467dSMark Brown dev_err(arizona->dev, 3575927467dSMark Brown "Failed to connect DCVDD: %d\n", ret); 3585927467dSMark Brown goto err; 3595927467dSMark Brown } 3605927467dSMark Brown } 3615927467dSMark Brown 3624c9bb8bcSCharles Keepax ret = wm5102_patch(arizona); 3634c9bb8bcSCharles Keepax if (ret != 0) { 3644c9bb8bcSCharles Keepax dev_err(arizona->dev, "Failed to apply patch: %d\n", 3654c9bb8bcSCharles Keepax ret); 3664c9bb8bcSCharles Keepax goto err; 3674c9bb8bcSCharles Keepax } 368e80436bbSCharles Keepax 369e80436bbSCharles Keepax ret = arizona_apply_hardware_patch(arizona); 370e80436bbSCharles Keepax if (ret != 0) { 371e80436bbSCharles Keepax dev_err(arizona->dev, 372e80436bbSCharles Keepax "Failed to apply hardware patch: %d\n", 373e80436bbSCharles Keepax ret); 374e80436bbSCharles Keepax goto err; 375e80436bbSCharles Keepax } 376e80436bbSCharles Keepax break; 377e80436bbSCharles Keepax default: 37812bb68edSCharles Keepax ret = arizona_wait_for_boot(arizona); 37912bb68edSCharles Keepax if (ret != 0) { 38012bb68edSCharles Keepax goto err; 38112bb68edSCharles Keepax } 38212bb68edSCharles Keepax 3835927467dSMark Brown if (arizona->external_dcvdd) { 3845927467dSMark Brown ret = regmap_update_bits(arizona->regmap, 3855927467dSMark Brown ARIZONA_ISOLATION_CONTROL, 3865927467dSMark Brown ARIZONA_ISOLATE_DCVDD1, 0); 3875927467dSMark Brown if (ret != 0) { 3885927467dSMark Brown dev_err(arizona->dev, 3895927467dSMark Brown "Failed to connect DCVDD: %d\n", ret); 3905927467dSMark Brown goto err; 3915927467dSMark Brown } 3925927467dSMark Brown } 393e80436bbSCharles Keepax break; 3944c9bb8bcSCharles Keepax } 3954c9bb8bcSCharles Keepax 3969270bdf5SMark Brown ret = regcache_sync(arizona->regmap); 3979270bdf5SMark Brown if (ret != 0) { 3989270bdf5SMark Brown dev_err(arizona->dev, "Failed to restore register cache\n"); 3994816bd1cSMark Brown goto err; 4009270bdf5SMark Brown } 4013cc72986SMark Brown 4023cc72986SMark Brown return 0; 4034816bd1cSMark Brown 4044816bd1cSMark Brown err: 4054816bd1cSMark Brown regcache_cache_only(arizona->regmap, true); 4064816bd1cSMark Brown regulator_disable(arizona->dcvdd); 4074816bd1cSMark Brown return ret; 4083cc72986SMark Brown } 4093cc72986SMark Brown 4103cc72986SMark Brown static int arizona_runtime_suspend(struct device *dev) 4113cc72986SMark Brown { 4123cc72986SMark Brown struct arizona *arizona = dev_get_drvdata(dev); 4135927467dSMark Brown int ret; 4143cc72986SMark Brown 415508c8299SMark Brown dev_dbg(arizona->dev, "Entering AoD mode\n"); 416508c8299SMark Brown 4175927467dSMark Brown if (arizona->external_dcvdd) { 4185927467dSMark Brown ret = regmap_update_bits(arizona->regmap, 4195927467dSMark Brown ARIZONA_ISOLATION_CONTROL, 4205927467dSMark Brown ARIZONA_ISOLATE_DCVDD1, 4215927467dSMark Brown ARIZONA_ISOLATE_DCVDD1); 4225927467dSMark Brown if (ret != 0) { 4235927467dSMark Brown dev_err(arizona->dev, "Failed to isolate DCVDD: %d\n", 4245927467dSMark Brown ret); 4255927467dSMark Brown return ret; 4265927467dSMark Brown } 4275927467dSMark Brown } 4285927467dSMark Brown 4293cc72986SMark Brown regcache_cache_only(arizona->regmap, true); 4303cc72986SMark Brown regcache_mark_dirty(arizona->regmap); 431e293e847SCharles Keepax regulator_disable(arizona->dcvdd); 4323cc72986SMark Brown 4333cc72986SMark Brown return 0; 4343cc72986SMark Brown } 4353cc72986SMark Brown #endif 4363cc72986SMark Brown 437dc781d0eSMark Brown #ifdef CONFIG_PM_SLEEP 43867c99296SMark Brown static int arizona_suspend(struct device *dev) 43967c99296SMark Brown { 44067c99296SMark Brown struct arizona *arizona = dev_get_drvdata(dev); 44167c99296SMark Brown 44267c99296SMark Brown dev_dbg(arizona->dev, "Suspend, disabling IRQ\n"); 44367c99296SMark Brown disable_irq(arizona->irq); 44467c99296SMark Brown 44567c99296SMark Brown return 0; 44667c99296SMark Brown } 44767c99296SMark Brown 44867c99296SMark Brown static int arizona_suspend_late(struct device *dev) 44967c99296SMark Brown { 45067c99296SMark Brown struct arizona *arizona = dev_get_drvdata(dev); 45167c99296SMark Brown 45267c99296SMark Brown dev_dbg(arizona->dev, "Late suspend, reenabling IRQ\n"); 45367c99296SMark Brown enable_irq(arizona->irq); 45467c99296SMark Brown 45567c99296SMark Brown return 0; 45667c99296SMark Brown } 45767c99296SMark Brown 458dc781d0eSMark Brown static int arizona_resume_noirq(struct device *dev) 459dc781d0eSMark Brown { 460dc781d0eSMark Brown struct arizona *arizona = dev_get_drvdata(dev); 461dc781d0eSMark Brown 462dc781d0eSMark Brown dev_dbg(arizona->dev, "Early resume, disabling IRQ\n"); 463dc781d0eSMark Brown disable_irq(arizona->irq); 464dc781d0eSMark Brown 465dc781d0eSMark Brown return 0; 466dc781d0eSMark Brown } 467dc781d0eSMark Brown 468dc781d0eSMark Brown static int arizona_resume(struct device *dev) 469dc781d0eSMark Brown { 470dc781d0eSMark Brown struct arizona *arizona = dev_get_drvdata(dev); 471dc781d0eSMark Brown 472dc781d0eSMark Brown dev_dbg(arizona->dev, "Late resume, reenabling IRQ\n"); 473dc781d0eSMark Brown enable_irq(arizona->irq); 474dc781d0eSMark Brown 475dc781d0eSMark Brown return 0; 476dc781d0eSMark Brown } 477dc781d0eSMark Brown #endif 478dc781d0eSMark Brown 4793cc72986SMark Brown const struct dev_pm_ops arizona_pm_ops = { 4803cc72986SMark Brown SET_RUNTIME_PM_OPS(arizona_runtime_suspend, 4813cc72986SMark Brown arizona_runtime_resume, 4823cc72986SMark Brown NULL) 48367c99296SMark Brown SET_SYSTEM_SLEEP_PM_OPS(arizona_suspend, arizona_resume) 484dc781d0eSMark Brown #ifdef CONFIG_PM_SLEEP 48567c99296SMark Brown .suspend_late = arizona_suspend_late, 486dc781d0eSMark Brown .resume_noirq = arizona_resume_noirq, 487dc781d0eSMark Brown #endif 4883cc72986SMark Brown }; 4893cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_pm_ops); 4903cc72986SMark Brown 491d781009cSMark Brown #ifdef CONFIG_OF 492942786e6SLee Jones unsigned long arizona_of_get_type(struct device *dev) 493d781009cSMark Brown { 494d781009cSMark Brown const struct of_device_id *id = of_match_device(arizona_of_match, dev); 495d781009cSMark Brown 496d781009cSMark Brown if (id) 497942786e6SLee Jones return (unsigned long)id->data; 498d781009cSMark Brown else 499d781009cSMark Brown return 0; 500d781009cSMark Brown } 501d781009cSMark Brown EXPORT_SYMBOL_GPL(arizona_of_get_type); 502d781009cSMark Brown 503e4fcb1d6SCharles Keepax int arizona_of_get_named_gpio(struct arizona *arizona, const char *prop, 504e4fcb1d6SCharles Keepax bool mandatory) 505e4fcb1d6SCharles Keepax { 506e4fcb1d6SCharles Keepax int gpio; 507e4fcb1d6SCharles Keepax 508e4fcb1d6SCharles Keepax gpio = of_get_named_gpio(arizona->dev->of_node, prop, 0); 509e4fcb1d6SCharles Keepax if (gpio < 0) { 510e4fcb1d6SCharles Keepax if (mandatory) 511e4fcb1d6SCharles Keepax dev_err(arizona->dev, 512e4fcb1d6SCharles Keepax "Mandatory DT gpio %s missing/malformed: %d\n", 513e4fcb1d6SCharles Keepax prop, gpio); 514e4fcb1d6SCharles Keepax 515e4fcb1d6SCharles Keepax gpio = 0; 516e4fcb1d6SCharles Keepax } 517e4fcb1d6SCharles Keepax 518e4fcb1d6SCharles Keepax return gpio; 519e4fcb1d6SCharles Keepax } 520e4fcb1d6SCharles Keepax EXPORT_SYMBOL_GPL(arizona_of_get_named_gpio); 521e4fcb1d6SCharles Keepax 522d781009cSMark Brown static int arizona_of_get_core_pdata(struct arizona *arizona) 523d781009cSMark Brown { 524e4fcb1d6SCharles Keepax struct arizona_pdata *pdata = &arizona->pdata; 525cc47aed9SInha Song struct property *prop; 526cc47aed9SInha Song const __be32 *cur; 527cc47aed9SInha Song u32 val; 528d781009cSMark Brown int ret, i; 529cc47aed9SInha Song int count = 0; 530d781009cSMark Brown 531e4fcb1d6SCharles Keepax pdata->reset = arizona_of_get_named_gpio(arizona, "wlf,reset", true); 532d781009cSMark Brown 533d781009cSMark Brown ret = of_property_read_u32_array(arizona->dev->of_node, 534d781009cSMark Brown "wlf,gpio-defaults", 535d781009cSMark Brown arizona->pdata.gpio_defaults, 536d781009cSMark Brown ARRAY_SIZE(arizona->pdata.gpio_defaults)); 537d781009cSMark Brown if (ret >= 0) { 538d781009cSMark Brown /* 539d781009cSMark Brown * All values are literal except out of range values 540d781009cSMark Brown * which are chip default, translate into platform 541d781009cSMark Brown * data which uses 0 as chip default and out of range 542d781009cSMark Brown * as zero. 543d781009cSMark Brown */ 544d781009cSMark Brown for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) { 545d781009cSMark Brown if (arizona->pdata.gpio_defaults[i] > 0xffff) 546d781009cSMark Brown arizona->pdata.gpio_defaults[i] = 0; 54791c73935SCharles Keepax else if (arizona->pdata.gpio_defaults[i] == 0) 548d781009cSMark Brown arizona->pdata.gpio_defaults[i] = 0x10000; 549d781009cSMark Brown } 550d781009cSMark Brown } else { 551d781009cSMark Brown dev_err(arizona->dev, "Failed to parse GPIO defaults: %d\n", 552d781009cSMark Brown ret); 553d781009cSMark Brown } 554d781009cSMark Brown 555cc47aed9SInha Song of_property_for_each_u32(arizona->dev->of_node, "wlf,inmode", prop, 556cc47aed9SInha Song cur, val) { 557cc47aed9SInha Song if (count == ARRAY_SIZE(arizona->pdata.inmode)) 558cc47aed9SInha Song break; 559cc47aed9SInha Song 560cc47aed9SInha Song arizona->pdata.inmode[count] = val; 561cc47aed9SInha Song count++; 562cc47aed9SInha Song } 563cc47aed9SInha Song 564d781009cSMark Brown return 0; 565d781009cSMark Brown } 566d781009cSMark Brown 567d781009cSMark Brown const struct of_device_id arizona_of_match[] = { 568d781009cSMark Brown { .compatible = "wlf,wm5102", .data = (void *)WM5102 }, 569d781009cSMark Brown { .compatible = "wlf,wm5110", .data = (void *)WM5110 }, 570dc7d4863SCharles Keepax { .compatible = "wlf,wm8997", .data = (void *)WM8997 }, 571d781009cSMark Brown {}, 572d781009cSMark Brown }; 573d781009cSMark Brown EXPORT_SYMBOL_GPL(arizona_of_match); 574d781009cSMark Brown #else 575d781009cSMark Brown static inline int arizona_of_get_core_pdata(struct arizona *arizona) 576d781009cSMark Brown { 577d781009cSMark Brown return 0; 578d781009cSMark Brown } 579d781009cSMark Brown #endif 580d781009cSMark Brown 5815ac98553SGeert Uytterhoeven static const struct mfd_cell early_devs[] = { 5823cc72986SMark Brown { .name = "arizona-ldo1" }, 5833cc72986SMark Brown }; 5843cc72986SMark Brown 58532dadef2SCharles Keepax static const char *wm5102_supplies[] = { 5865fc6c396SCharles Keepax "MICVDD", 58732dadef2SCharles Keepax "DBVDD2", 58832dadef2SCharles Keepax "DBVDD3", 58932dadef2SCharles Keepax "CPVDD", 59032dadef2SCharles Keepax "SPKVDDL", 59132dadef2SCharles Keepax "SPKVDDR", 59232dadef2SCharles Keepax }; 59332dadef2SCharles Keepax 5945ac98553SGeert Uytterhoeven static const struct mfd_cell wm5102_devs[] = { 595d7768111SMark Brown { .name = "arizona-micsupp" }, 5965fc6c396SCharles Keepax { 5975fc6c396SCharles Keepax .name = "arizona-extcon", 5985fc6c396SCharles Keepax .parent_supplies = wm5102_supplies, 5995fc6c396SCharles Keepax .num_parent_supplies = 1, /* We only need MICVDD */ 6005fc6c396SCharles Keepax }, 6013cc72986SMark Brown { .name = "arizona-gpio" }, 602503b1cacSMark Brown { .name = "arizona-haptics" }, 6033cc72986SMark Brown { .name = "arizona-pwm" }, 60432dadef2SCharles Keepax { 60532dadef2SCharles Keepax .name = "wm5102-codec", 60632dadef2SCharles Keepax .parent_supplies = wm5102_supplies, 60732dadef2SCharles Keepax .num_parent_supplies = ARRAY_SIZE(wm5102_supplies), 60832dadef2SCharles Keepax }, 6093cc72986SMark Brown }; 6103cc72986SMark Brown 6115ac98553SGeert Uytterhoeven static const struct mfd_cell wm5110_devs[] = { 612d7768111SMark Brown { .name = "arizona-micsupp" }, 6135fc6c396SCharles Keepax { 6145fc6c396SCharles Keepax .name = "arizona-extcon", 6155fc6c396SCharles Keepax .parent_supplies = wm5102_supplies, 6165fc6c396SCharles Keepax .num_parent_supplies = 1, /* We only need MICVDD */ 6175fc6c396SCharles Keepax }, 618e102befeSMark Brown { .name = "arizona-gpio" }, 619503b1cacSMark Brown { .name = "arizona-haptics" }, 620e102befeSMark Brown { .name = "arizona-pwm" }, 62132dadef2SCharles Keepax { 62232dadef2SCharles Keepax .name = "wm5110-codec", 62332dadef2SCharles Keepax .parent_supplies = wm5102_supplies, 62432dadef2SCharles Keepax .num_parent_supplies = ARRAY_SIZE(wm5102_supplies), 62532dadef2SCharles Keepax }, 62632dadef2SCharles Keepax }; 62732dadef2SCharles Keepax 62832dadef2SCharles Keepax static const char *wm8997_supplies[] = { 629996c2d4fSCharles Keepax "MICVDD", 63032dadef2SCharles Keepax "DBVDD2", 63132dadef2SCharles Keepax "CPVDD", 63232dadef2SCharles Keepax "SPKVDD", 633e102befeSMark Brown }; 634e102befeSMark Brown 6355ac98553SGeert Uytterhoeven static const struct mfd_cell wm8997_devs[] = { 636dc7d4863SCharles Keepax { .name = "arizona-micsupp" }, 6375fc6c396SCharles Keepax { 6385fc6c396SCharles Keepax .name = "arizona-extcon", 6395fc6c396SCharles Keepax .parent_supplies = wm8997_supplies, 6405fc6c396SCharles Keepax .num_parent_supplies = 1, /* We only need MICVDD */ 6415fc6c396SCharles Keepax }, 642dc7d4863SCharles Keepax { .name = "arizona-gpio" }, 643dc7d4863SCharles Keepax { .name = "arizona-haptics" }, 644dc7d4863SCharles Keepax { .name = "arizona-pwm" }, 64532dadef2SCharles Keepax { 64632dadef2SCharles Keepax .name = "wm8997-codec", 64732dadef2SCharles Keepax .parent_supplies = wm8997_supplies, 64832dadef2SCharles Keepax .num_parent_supplies = ARRAY_SIZE(wm8997_supplies), 64932dadef2SCharles Keepax }, 650dc7d4863SCharles Keepax }; 651dc7d4863SCharles Keepax 652f791be49SBill Pemberton int arizona_dev_init(struct arizona *arizona) 6533cc72986SMark Brown { 6543cc72986SMark Brown struct device *dev = arizona->dev; 6553cc72986SMark Brown const char *type_name; 6563cc72986SMark Brown unsigned int reg, val; 65762d62b59SMark Brown int (*apply_patch)(struct arizona *) = NULL; 6583cc72986SMark Brown int ret, i; 6593cc72986SMark Brown 6603cc72986SMark Brown dev_set_drvdata(arizona->dev, arizona); 6613cc72986SMark Brown mutex_init(&arizona->clk_lock); 6623cc72986SMark Brown 6633cc72986SMark Brown if (dev_get_platdata(arizona->dev)) 6643cc72986SMark Brown memcpy(&arizona->pdata, dev_get_platdata(arizona->dev), 6653cc72986SMark Brown sizeof(arizona->pdata)); 66622d7dc8aSLee Jones else 66722d7dc8aSLee Jones arizona_of_get_core_pdata(arizona); 6683cc72986SMark Brown 6693cc72986SMark Brown regcache_cache_only(arizona->regmap, true); 6703cc72986SMark Brown 6713cc72986SMark Brown switch (arizona->type) { 6723cc72986SMark Brown case WM5102: 673e102befeSMark Brown case WM5110: 674dc7d4863SCharles Keepax case WM8997: 6753cc72986SMark Brown for (i = 0; i < ARRAY_SIZE(wm5102_core_supplies); i++) 6763cc72986SMark Brown arizona->core_supplies[i].supply 6773cc72986SMark Brown = wm5102_core_supplies[i]; 6783cc72986SMark Brown arizona->num_core_supplies = ARRAY_SIZE(wm5102_core_supplies); 6793cc72986SMark Brown break; 6803cc72986SMark Brown default: 6813cc72986SMark Brown dev_err(arizona->dev, "Unknown device type %d\n", 6823cc72986SMark Brown arizona->type); 6833cc72986SMark Brown return -EINVAL; 6843cc72986SMark Brown } 6853cc72986SMark Brown 6864a8c475fSCharles Keepax /* Mark DCVDD as external, LDO1 driver will clear if internal */ 6874a8c475fSCharles Keepax arizona->external_dcvdd = true; 6884a8c475fSCharles Keepax 6893cc72986SMark Brown ret = mfd_add_devices(arizona->dev, -1, early_devs, 6900848c94fSMark Brown ARRAY_SIZE(early_devs), NULL, 0, NULL); 6913cc72986SMark Brown if (ret != 0) { 6923cc72986SMark Brown dev_err(dev, "Failed to add early children: %d\n", ret); 6933cc72986SMark Brown return ret; 6943cc72986SMark Brown } 6953cc72986SMark Brown 6963cc72986SMark Brown ret = devm_regulator_bulk_get(dev, arizona->num_core_supplies, 6973cc72986SMark Brown arizona->core_supplies); 6983cc72986SMark Brown if (ret != 0) { 6993cc72986SMark Brown dev_err(dev, "Failed to request core supplies: %d\n", 7003cc72986SMark Brown ret); 7013cc72986SMark Brown goto err_early; 7023cc72986SMark Brown } 7033cc72986SMark Brown 7040c2d0ffbSCharles Keepax /** 7050c2d0ffbSCharles Keepax * Don't use devres here because the only device we have to get 7060c2d0ffbSCharles Keepax * against is the MFD device and DCVDD will likely be supplied by 7070c2d0ffbSCharles Keepax * one of its children. Meaning that the regulator will be 7080c2d0ffbSCharles Keepax * destroyed by the time devres calls regulator put. 7090c2d0ffbSCharles Keepax */ 710e6021511SCharles Keepax arizona->dcvdd = regulator_get(arizona->dev, "DCVDD"); 71159db9691SMark Brown if (IS_ERR(arizona->dcvdd)) { 71259db9691SMark Brown ret = PTR_ERR(arizona->dcvdd); 71359db9691SMark Brown dev_err(dev, "Failed to request DCVDD: %d\n", ret); 71459db9691SMark Brown goto err_early; 71559db9691SMark Brown } 71659db9691SMark Brown 71787d3af4aSMark Brown if (arizona->pdata.reset) { 71887d3af4aSMark Brown /* Start out with /RESET low to put the chip into reset */ 71987d3af4aSMark Brown ret = gpio_request_one(arizona->pdata.reset, 72087d3af4aSMark Brown GPIOF_DIR_OUT | GPIOF_INIT_LOW, 72187d3af4aSMark Brown "arizona /RESET"); 72287d3af4aSMark Brown if (ret != 0) { 72387d3af4aSMark Brown dev_err(dev, "Failed to request /RESET: %d\n", ret); 724e6021511SCharles Keepax goto err_dcvdd; 72587d3af4aSMark Brown } 72687d3af4aSMark Brown } 72787d3af4aSMark Brown 7283cc72986SMark Brown ret = regulator_bulk_enable(arizona->num_core_supplies, 7293cc72986SMark Brown arizona->core_supplies); 7303cc72986SMark Brown if (ret != 0) { 7313cc72986SMark Brown dev_err(dev, "Failed to enable core supplies: %d\n", 7323cc72986SMark Brown ret); 733e6021511SCharles Keepax goto err_dcvdd; 7343cc72986SMark Brown } 7353cc72986SMark Brown 73659db9691SMark Brown ret = regulator_enable(arizona->dcvdd); 73759db9691SMark Brown if (ret != 0) { 73859db9691SMark Brown dev_err(dev, "Failed to enable DCVDD: %d\n", ret); 73959db9691SMark Brown goto err_enable; 74059db9691SMark Brown } 74159db9691SMark Brown 742c25feaa5SCharles Keepax if (arizona->pdata.reset) { 7433cc72986SMark Brown gpio_set_value_cansleep(arizona->pdata.reset, 1); 744c25feaa5SCharles Keepax msleep(1); 745c25feaa5SCharles Keepax } 7463cc72986SMark Brown 7473cc72986SMark Brown regcache_cache_only(arizona->regmap, false); 7483cc72986SMark Brown 749ca76ceb8SMark Brown /* Verify that this is a chip we know about */ 750ca76ceb8SMark Brown ret = regmap_read(arizona->regmap, ARIZONA_SOFTWARE_RESET, ®); 751ca76ceb8SMark Brown if (ret != 0) { 752ca76ceb8SMark Brown dev_err(dev, "Failed to read ID register: %d\n", ret); 753ca76ceb8SMark Brown goto err_reset; 754ca76ceb8SMark Brown } 755ca76ceb8SMark Brown 756ca76ceb8SMark Brown switch (reg) { 757ca76ceb8SMark Brown case 0x5102: 758ca76ceb8SMark Brown case 0x5110: 759dc7d4863SCharles Keepax case 0x8997: 760ca76ceb8SMark Brown break; 761ca76ceb8SMark Brown default: 762ca76ceb8SMark Brown dev_err(arizona->dev, "Unknown device ID: %x\n", reg); 763ca76ceb8SMark Brown goto err_reset; 764ca76ceb8SMark Brown } 765ca76ceb8SMark Brown 766ca76ceb8SMark Brown /* If we have a /RESET GPIO we'll already be reset */ 767ca76ceb8SMark Brown if (!arizona->pdata.reset) { 768ca76ceb8SMark Brown regcache_mark_dirty(arizona->regmap); 769ca76ceb8SMark Brown 770ca76ceb8SMark Brown ret = regmap_write(arizona->regmap, ARIZONA_SOFTWARE_RESET, 0); 771ca76ceb8SMark Brown if (ret != 0) { 772ca76ceb8SMark Brown dev_err(dev, "Failed to reset device: %d\n", ret); 773ca76ceb8SMark Brown goto err_reset; 774ca76ceb8SMark Brown } 775ca76ceb8SMark Brown 776ca76ceb8SMark Brown msleep(1); 777ca76ceb8SMark Brown 778ca76ceb8SMark Brown ret = regcache_sync(arizona->regmap); 779ca76ceb8SMark Brown if (ret != 0) { 780ca76ceb8SMark Brown dev_err(dev, "Failed to sync device: %d\n", ret); 781ca76ceb8SMark Brown goto err_reset; 782ca76ceb8SMark Brown } 783ca76ceb8SMark Brown } 784ca76ceb8SMark Brown 785ca76ceb8SMark Brown /* Ensure device startup is complete */ 786ca76ceb8SMark Brown switch (arizona->type) { 787ca76ceb8SMark Brown case WM5102: 78848018943SMark Brown ret = regmap_read(arizona->regmap, 78948018943SMark Brown ARIZONA_WRITE_SEQUENCER_CTRL_3, &val); 790ca76ceb8SMark Brown if (ret != 0) 791ca76ceb8SMark Brown dev_err(dev, 792ca76ceb8SMark Brown "Failed to check write sequencer state: %d\n", 793ca76ceb8SMark Brown ret); 794ca76ceb8SMark Brown else if (val & 0x01) 795ca76ceb8SMark Brown break; 796ca76ceb8SMark Brown /* Fall through */ 797ca76ceb8SMark Brown default: 798ca76ceb8SMark Brown ret = arizona_wait_for_boot(arizona); 799ca76ceb8SMark Brown if (ret != 0) { 800ca76ceb8SMark Brown dev_err(arizona->dev, 801ca76ceb8SMark Brown "Device failed initial boot: %d\n", ret); 802ca76ceb8SMark Brown goto err_reset; 803ca76ceb8SMark Brown } 804ca76ceb8SMark Brown break; 805ca76ceb8SMark Brown } 806ca76ceb8SMark Brown 807ca76ceb8SMark Brown /* Read the device ID information & do device specific stuff */ 8083cc72986SMark Brown ret = regmap_read(arizona->regmap, ARIZONA_SOFTWARE_RESET, ®); 8093cc72986SMark Brown if (ret != 0) { 8103cc72986SMark Brown dev_err(dev, "Failed to read ID register: %d\n", ret); 81159db9691SMark Brown goto err_reset; 8123cc72986SMark Brown } 8133cc72986SMark Brown 8143cc72986SMark Brown ret = regmap_read(arizona->regmap, ARIZONA_DEVICE_REVISION, 8153cc72986SMark Brown &arizona->rev); 8163cc72986SMark Brown if (ret != 0) { 8173cc72986SMark Brown dev_err(dev, "Failed to read revision register: %d\n", ret); 81859db9691SMark Brown goto err_reset; 8193cc72986SMark Brown } 8203cc72986SMark Brown arizona->rev &= ARIZONA_DEVICE_REVISION_MASK; 8213cc72986SMark Brown 8223cc72986SMark Brown switch (reg) { 823863df8d5SMark Brown #ifdef CONFIG_MFD_WM5102 8243cc72986SMark Brown case 0x5102: 8253cc72986SMark Brown type_name = "WM5102"; 8263cc72986SMark Brown if (arizona->type != WM5102) { 8273cc72986SMark Brown dev_err(arizona->dev, "WM5102 registered as %d\n", 8283cc72986SMark Brown arizona->type); 8293cc72986SMark Brown arizona->type = WM5102; 8303cc72986SMark Brown } 83162d62b59SMark Brown apply_patch = wm5102_patch; 832c6d6bfb1SMark Brown arizona->rev &= 0x7; 8333cc72986SMark Brown break; 834863df8d5SMark Brown #endif 835e102befeSMark Brown #ifdef CONFIG_MFD_WM5110 836e102befeSMark Brown case 0x5110: 837e102befeSMark Brown type_name = "WM5110"; 838e102befeSMark Brown if (arizona->type != WM5110) { 839e102befeSMark Brown dev_err(arizona->dev, "WM5110 registered as %d\n", 840e102befeSMark Brown arizona->type); 841e102befeSMark Brown arizona->type = WM5110; 842e102befeSMark Brown } 84362d62b59SMark Brown apply_patch = wm5110_patch; 844e102befeSMark Brown break; 845e102befeSMark Brown #endif 846dc7d4863SCharles Keepax #ifdef CONFIG_MFD_WM8997 847dc7d4863SCharles Keepax case 0x8997: 848dc7d4863SCharles Keepax type_name = "WM8997"; 849dc7d4863SCharles Keepax if (arizona->type != WM8997) { 850dc7d4863SCharles Keepax dev_err(arizona->dev, "WM8997 registered as %d\n", 851dc7d4863SCharles Keepax arizona->type); 852dc7d4863SCharles Keepax arizona->type = WM8997; 853dc7d4863SCharles Keepax } 854dc7d4863SCharles Keepax apply_patch = wm8997_patch; 855dc7d4863SCharles Keepax break; 856dc7d4863SCharles Keepax #endif 8573cc72986SMark Brown default: 8583cc72986SMark Brown dev_err(arizona->dev, "Unknown device ID %x\n", reg); 85959db9691SMark Brown goto err_reset; 8603cc72986SMark Brown } 8613cc72986SMark Brown 8623cc72986SMark Brown dev_info(dev, "%s revision %c\n", type_name, arizona->rev + 'A'); 8633cc72986SMark Brown 86462d62b59SMark Brown if (apply_patch) { 86562d62b59SMark Brown ret = apply_patch(arizona); 86662d62b59SMark Brown if (ret != 0) { 86762d62b59SMark Brown dev_err(arizona->dev, "Failed to apply patch: %d\n", 86862d62b59SMark Brown ret); 86962d62b59SMark Brown goto err_reset; 87062d62b59SMark Brown } 871e80436bbSCharles Keepax 872e80436bbSCharles Keepax switch (arizona->type) { 873e80436bbSCharles Keepax case WM5102: 874e80436bbSCharles Keepax ret = arizona_apply_hardware_patch(arizona); 875e80436bbSCharles Keepax if (ret != 0) { 876e80436bbSCharles Keepax dev_err(arizona->dev, 877e80436bbSCharles Keepax "Failed to apply hardware patch: %d\n", 878e80436bbSCharles Keepax ret); 879e80436bbSCharles Keepax goto err_reset; 880e80436bbSCharles Keepax } 881e80436bbSCharles Keepax break; 882e80436bbSCharles Keepax default: 883e80436bbSCharles Keepax break; 884e80436bbSCharles Keepax } 88562d62b59SMark Brown } 88662d62b59SMark Brown 8873cc72986SMark Brown for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) { 8883cc72986SMark Brown if (!arizona->pdata.gpio_defaults[i]) 8893cc72986SMark Brown continue; 8903cc72986SMark Brown 8913cc72986SMark Brown regmap_write(arizona->regmap, ARIZONA_GPIO1_CTRL + i, 8923cc72986SMark Brown arizona->pdata.gpio_defaults[i]); 8933cc72986SMark Brown } 8943cc72986SMark Brown 8953cc72986SMark Brown pm_runtime_set_autosuspend_delay(arizona->dev, 100); 8963cc72986SMark Brown pm_runtime_use_autosuspend(arizona->dev); 8973cc72986SMark Brown pm_runtime_enable(arizona->dev); 8983cc72986SMark Brown 8993cc72986SMark Brown /* Chip default */ 9003cc72986SMark Brown if (!arizona->pdata.clk32k_src) 9013cc72986SMark Brown arizona->pdata.clk32k_src = ARIZONA_32KZ_MCLK2; 9023cc72986SMark Brown 9033cc72986SMark Brown switch (arizona->pdata.clk32k_src) { 9043cc72986SMark Brown case ARIZONA_32KZ_MCLK1: 9053cc72986SMark Brown case ARIZONA_32KZ_MCLK2: 9063cc72986SMark Brown regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, 9073cc72986SMark Brown ARIZONA_CLK_32K_SRC_MASK, 9083cc72986SMark Brown arizona->pdata.clk32k_src - 1); 909767c6dc0SMark Brown arizona_clk32k_enable(arizona); 9103cc72986SMark Brown break; 9113cc72986SMark Brown case ARIZONA_32KZ_NONE: 9123cc72986SMark Brown regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, 9133cc72986SMark Brown ARIZONA_CLK_32K_SRC_MASK, 2); 9143cc72986SMark Brown break; 9153cc72986SMark Brown default: 9163cc72986SMark Brown dev_err(arizona->dev, "Invalid 32kHz clock source: %d\n", 9173cc72986SMark Brown arizona->pdata.clk32k_src); 9183cc72986SMark Brown ret = -EINVAL; 91959db9691SMark Brown goto err_reset; 9203cc72986SMark Brown } 9213cc72986SMark Brown 9223d91f828SMark Brown for (i = 0; i < ARIZONA_MAX_MICBIAS; i++) { 923544c7aadSMark Brown if (!arizona->pdata.micbias[i].mV && 924544c7aadSMark Brown !arizona->pdata.micbias[i].bypass) 9253d91f828SMark Brown continue; 9263d91f828SMark Brown 927544c7aadSMark Brown /* Apply default for bypass mode */ 928544c7aadSMark Brown if (!arizona->pdata.micbias[i].mV) 929544c7aadSMark Brown arizona->pdata.micbias[i].mV = 2800; 930544c7aadSMark Brown 9313d91f828SMark Brown val = (arizona->pdata.micbias[i].mV - 1500) / 100; 932544c7aadSMark Brown 9333d91f828SMark Brown val <<= ARIZONA_MICB1_LVL_SHIFT; 9343d91f828SMark Brown 9353d91f828SMark Brown if (arizona->pdata.micbias[i].ext_cap) 9363d91f828SMark Brown val |= ARIZONA_MICB1_EXT_CAP; 9373d91f828SMark Brown 9383d91f828SMark Brown if (arizona->pdata.micbias[i].discharge) 9393d91f828SMark Brown val |= ARIZONA_MICB1_DISCH; 9403d91f828SMark Brown 941f773fc6dSCharles Keepax if (arizona->pdata.micbias[i].soft_start) 9423d91f828SMark Brown val |= ARIZONA_MICB1_RATE; 9433d91f828SMark Brown 944544c7aadSMark Brown if (arizona->pdata.micbias[i].bypass) 945544c7aadSMark Brown val |= ARIZONA_MICB1_BYPASS; 946544c7aadSMark Brown 9473d91f828SMark Brown regmap_update_bits(arizona->regmap, 9483d91f828SMark Brown ARIZONA_MIC_BIAS_CTRL_1 + i, 9493d91f828SMark Brown ARIZONA_MICB1_LVL_MASK | 95071d134b9SCharles Keepax ARIZONA_MICB1_EXT_CAP | 9513d91f828SMark Brown ARIZONA_MICB1_DISCH | 952544c7aadSMark Brown ARIZONA_MICB1_BYPASS | 9533d91f828SMark Brown ARIZONA_MICB1_RATE, val); 9543d91f828SMark Brown } 9553d91f828SMark Brown 9563cc72986SMark Brown for (i = 0; i < ARIZONA_MAX_INPUT; i++) { 9573cc72986SMark Brown /* Default for both is 0 so noop with defaults */ 9583cc72986SMark Brown val = arizona->pdata.dmic_ref[i] 9593cc72986SMark Brown << ARIZONA_IN1_DMIC_SUP_SHIFT; 9603cc72986SMark Brown val |= arizona->pdata.inmode[i] << ARIZONA_IN1_MODE_SHIFT; 9613cc72986SMark Brown 9623cc72986SMark Brown regmap_update_bits(arizona->regmap, 9633cc72986SMark Brown ARIZONA_IN1L_CONTROL + (i * 8), 9643cc72986SMark Brown ARIZONA_IN1_DMIC_SUP_MASK | 9653cc72986SMark Brown ARIZONA_IN1_MODE_MASK, val); 9663cc72986SMark Brown } 9673cc72986SMark Brown 9683cc72986SMark Brown for (i = 0; i < ARIZONA_MAX_OUTPUT; i++) { 9693cc72986SMark Brown /* Default is 0 so noop with defaults */ 9703cc72986SMark Brown if (arizona->pdata.out_mono[i]) 9713cc72986SMark Brown val = ARIZONA_OUT1_MONO; 9723cc72986SMark Brown else 9733cc72986SMark Brown val = 0; 9743cc72986SMark Brown 9753cc72986SMark Brown regmap_update_bits(arizona->regmap, 9763cc72986SMark Brown ARIZONA_OUTPUT_PATH_CONFIG_1L + (i * 8), 9773cc72986SMark Brown ARIZONA_OUT1_MONO, val); 9783cc72986SMark Brown } 9793cc72986SMark Brown 9803cc72986SMark Brown for (i = 0; i < ARIZONA_MAX_PDM_SPK; i++) { 9813cc72986SMark Brown if (arizona->pdata.spk_mute[i]) 9823cc72986SMark Brown regmap_update_bits(arizona->regmap, 9832a51da04SMark Brown ARIZONA_PDM_SPK1_CTRL_1 + (i * 2), 9843cc72986SMark Brown ARIZONA_SPK1_MUTE_ENDIAN_MASK | 9853cc72986SMark Brown ARIZONA_SPK1_MUTE_SEQ1_MASK, 9863cc72986SMark Brown arizona->pdata.spk_mute[i]); 9873cc72986SMark Brown 9883cc72986SMark Brown if (arizona->pdata.spk_fmt[i]) 9893cc72986SMark Brown regmap_update_bits(arizona->regmap, 9902a51da04SMark Brown ARIZONA_PDM_SPK1_CTRL_2 + (i * 2), 9913cc72986SMark Brown ARIZONA_SPK1_FMT_MASK, 9923cc72986SMark Brown arizona->pdata.spk_fmt[i]); 9933cc72986SMark Brown } 9943cc72986SMark Brown 9953cc72986SMark Brown /* Set up for interrupts */ 9963cc72986SMark Brown ret = arizona_irq_init(arizona); 9973cc72986SMark Brown if (ret != 0) 99859db9691SMark Brown goto err_reset; 9993cc72986SMark Brown 10003cc72986SMark Brown arizona_request_irq(arizona, ARIZONA_IRQ_CLKGEN_ERR, "CLKGEN error", 10013cc72986SMark Brown arizona_clkgen_err, arizona); 10023cc72986SMark Brown arizona_request_irq(arizona, ARIZONA_IRQ_OVERCLOCKED, "Overclocked", 10033cc72986SMark Brown arizona_overclocked, arizona); 10043cc72986SMark Brown arizona_request_irq(arizona, ARIZONA_IRQ_UNDERCLOCKED, "Underclocked", 10053cc72986SMark Brown arizona_underclocked, arizona); 10063cc72986SMark Brown 10073cc72986SMark Brown switch (arizona->type) { 10083cc72986SMark Brown case WM5102: 10093cc72986SMark Brown ret = mfd_add_devices(arizona->dev, -1, wm5102_devs, 10100848c94fSMark Brown ARRAY_SIZE(wm5102_devs), NULL, 0, NULL); 10113cc72986SMark Brown break; 1012e102befeSMark Brown case WM5110: 1013e102befeSMark Brown ret = mfd_add_devices(arizona->dev, -1, wm5110_devs, 101478566afdSCharles Keepax ARRAY_SIZE(wm5110_devs), NULL, 0, NULL); 1015e102befeSMark Brown break; 1016dc7d4863SCharles Keepax case WM8997: 1017dc7d4863SCharles Keepax ret = mfd_add_devices(arizona->dev, -1, wm8997_devs, 1018dc7d4863SCharles Keepax ARRAY_SIZE(wm8997_devs), NULL, 0, NULL); 1019dc7d4863SCharles Keepax break; 10203cc72986SMark Brown } 10213cc72986SMark Brown 10223cc72986SMark Brown if (ret != 0) { 10233cc72986SMark Brown dev_err(arizona->dev, "Failed to add subdevices: %d\n", ret); 10243cc72986SMark Brown goto err_irq; 10253cc72986SMark Brown } 10263cc72986SMark Brown 1027*48bb9fe4SRafael J. Wysocki #ifdef CONFIG_PM 102859db9691SMark Brown regulator_disable(arizona->dcvdd); 102959db9691SMark Brown #endif 103059db9691SMark Brown 10313cc72986SMark Brown return 0; 10323cc72986SMark Brown 10333cc72986SMark Brown err_irq: 10343cc72986SMark Brown arizona_irq_exit(arizona); 10353cc72986SMark Brown err_reset: 10363cc72986SMark Brown if (arizona->pdata.reset) { 103787d3af4aSMark Brown gpio_set_value_cansleep(arizona->pdata.reset, 0); 10383cc72986SMark Brown gpio_free(arizona->pdata.reset); 10393cc72986SMark Brown } 104059db9691SMark Brown regulator_disable(arizona->dcvdd); 10413cc72986SMark Brown err_enable: 10423a36a0dbSMark Brown regulator_bulk_disable(arizona->num_core_supplies, 10433cc72986SMark Brown arizona->core_supplies); 1044e6021511SCharles Keepax err_dcvdd: 1045e6021511SCharles Keepax regulator_put(arizona->dcvdd); 10463cc72986SMark Brown err_early: 10473cc72986SMark Brown mfd_remove_devices(dev); 10483cc72986SMark Brown return ret; 10493cc72986SMark Brown } 10503cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_dev_init); 10513cc72986SMark Brown 10524740f73fSBill Pemberton int arizona_dev_exit(struct arizona *arizona) 10533cc72986SMark Brown { 1054b804020aSCharles Keepax pm_runtime_disable(arizona->dev); 1055b804020aSCharles Keepax 1056df6b3352SCharles Keepax regulator_disable(arizona->dcvdd); 1057e6021511SCharles Keepax regulator_put(arizona->dcvdd); 1058df6b3352SCharles Keepax 10593cc72986SMark Brown mfd_remove_devices(arizona->dev); 10603cc72986SMark Brown arizona_free_irq(arizona, ARIZONA_IRQ_UNDERCLOCKED, arizona); 10613cc72986SMark Brown arizona_free_irq(arizona, ARIZONA_IRQ_OVERCLOCKED, arizona); 10623cc72986SMark Brown arizona_free_irq(arizona, ARIZONA_IRQ_CLKGEN_ERR, arizona); 10633cc72986SMark Brown arizona_irq_exit(arizona); 10641d017b6bSMark Brown if (arizona->pdata.reset) 10651d017b6bSMark Brown gpio_set_value_cansleep(arizona->pdata.reset, 0); 1066df6b3352SCharles Keepax 10674420286eSCharles Keepax regulator_bulk_disable(arizona->num_core_supplies, 10681d017b6bSMark Brown arizona->core_supplies); 10693cc72986SMark Brown return 0; 10703cc72986SMark Brown } 10713cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_dev_exit); 1072