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"); 1263cc72986SMark Brown if (val & ARIZONA_ISRC2_UNDERCLOCKED_STS) 1273cc72986SMark Brown dev_err(arizona->dev, "ISRC2 underclocked\n"); 1283cc72986SMark Brown if (val & ARIZONA_ISRC1_UNDERCLOCKED_STS) 1293cc72986SMark Brown dev_err(arizona->dev, "ISRC1 underclocked\n"); 1303cc72986SMark Brown if (val & ARIZONA_FX_UNDERCLOCKED_STS) 1313cc72986SMark Brown dev_err(arizona->dev, "FX underclocked\n"); 1323cc72986SMark Brown if (val & ARIZONA_ASRC_UNDERCLOCKED_STS) 1333cc72986SMark Brown dev_err(arizona->dev, "ASRC underclocked\n"); 1343cc72986SMark Brown if (val & ARIZONA_DAC_UNDERCLOCKED_STS) 1353cc72986SMark Brown dev_err(arizona->dev, "DAC underclocked\n"); 1363cc72986SMark Brown if (val & ARIZONA_ADC_UNDERCLOCKED_STS) 1373cc72986SMark Brown dev_err(arizona->dev, "ADC underclocked\n"); 1383cc72986SMark Brown if (val & ARIZONA_MIXER_UNDERCLOCKED_STS) 139648a9880SMark Brown dev_err(arizona->dev, "Mixer dropped sample\n"); 1403cc72986SMark Brown 1413cc72986SMark Brown return IRQ_HANDLED; 1423cc72986SMark Brown } 1433cc72986SMark Brown 1443cc72986SMark Brown static irqreturn_t arizona_overclocked(int irq, void *data) 1453cc72986SMark Brown { 1463cc72986SMark Brown struct arizona *arizona = data; 1473cc72986SMark Brown unsigned int val[2]; 1483cc72986SMark Brown int ret; 1493cc72986SMark Brown 1503cc72986SMark Brown ret = regmap_bulk_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_6, 1513cc72986SMark Brown &val[0], 2); 1523cc72986SMark Brown if (ret != 0) { 1533cc72986SMark Brown dev_err(arizona->dev, "Failed to read overclock status: %d\n", 1543cc72986SMark Brown ret); 1553cc72986SMark Brown return IRQ_NONE; 1563cc72986SMark Brown } 1573cc72986SMark Brown 1583cc72986SMark Brown if (val[0] & ARIZONA_PWM_OVERCLOCKED_STS) 1593cc72986SMark Brown dev_err(arizona->dev, "PWM overclocked\n"); 1603cc72986SMark Brown if (val[0] & ARIZONA_FX_CORE_OVERCLOCKED_STS) 1613cc72986SMark Brown dev_err(arizona->dev, "FX core overclocked\n"); 1623cc72986SMark Brown if (val[0] & ARIZONA_DAC_SYS_OVERCLOCKED_STS) 1633cc72986SMark Brown dev_err(arizona->dev, "DAC SYS overclocked\n"); 1643cc72986SMark Brown if (val[0] & ARIZONA_DAC_WARP_OVERCLOCKED_STS) 1653cc72986SMark Brown dev_err(arizona->dev, "DAC WARP overclocked\n"); 1663cc72986SMark Brown if (val[0] & ARIZONA_ADC_OVERCLOCKED_STS) 1673cc72986SMark Brown dev_err(arizona->dev, "ADC overclocked\n"); 1683cc72986SMark Brown if (val[0] & ARIZONA_MIXER_OVERCLOCKED_STS) 1693cc72986SMark Brown dev_err(arizona->dev, "Mixer overclocked\n"); 1703cc72986SMark Brown if (val[0] & ARIZONA_AIF3_SYNC_OVERCLOCKED_STS) 1713cc72986SMark Brown dev_err(arizona->dev, "AIF3 overclocked\n"); 1723cc72986SMark Brown if (val[0] & ARIZONA_AIF2_SYNC_OVERCLOCKED_STS) 1733cc72986SMark Brown dev_err(arizona->dev, "AIF2 overclocked\n"); 1743cc72986SMark Brown if (val[0] & ARIZONA_AIF1_SYNC_OVERCLOCKED_STS) 1753cc72986SMark Brown dev_err(arizona->dev, "AIF1 overclocked\n"); 1763cc72986SMark Brown if (val[0] & ARIZONA_PAD_CTRL_OVERCLOCKED_STS) 1773cc72986SMark Brown dev_err(arizona->dev, "Pad control overclocked\n"); 1783cc72986SMark Brown 1793cc72986SMark Brown if (val[1] & ARIZONA_SLIMBUS_SUBSYS_OVERCLOCKED_STS) 1803cc72986SMark Brown dev_err(arizona->dev, "Slimbus subsystem overclocked\n"); 1813cc72986SMark Brown if (val[1] & ARIZONA_SLIMBUS_ASYNC_OVERCLOCKED_STS) 1823cc72986SMark Brown dev_err(arizona->dev, "Slimbus async overclocked\n"); 1833cc72986SMark Brown if (val[1] & ARIZONA_SLIMBUS_SYNC_OVERCLOCKED_STS) 1843cc72986SMark Brown dev_err(arizona->dev, "Slimbus sync overclocked\n"); 1853cc72986SMark Brown if (val[1] & ARIZONA_ASRC_ASYNC_SYS_OVERCLOCKED_STS) 1863cc72986SMark Brown dev_err(arizona->dev, "ASRC async system overclocked\n"); 1873cc72986SMark Brown if (val[1] & ARIZONA_ASRC_ASYNC_WARP_OVERCLOCKED_STS) 1883cc72986SMark Brown dev_err(arizona->dev, "ASRC async WARP overclocked\n"); 1893cc72986SMark Brown if (val[1] & ARIZONA_ASRC_SYNC_SYS_OVERCLOCKED_STS) 1903cc72986SMark Brown dev_err(arizona->dev, "ASRC sync system overclocked\n"); 1913cc72986SMark Brown if (val[1] & ARIZONA_ASRC_SYNC_WARP_OVERCLOCKED_STS) 1923cc72986SMark Brown dev_err(arizona->dev, "ASRC sync WARP overclocked\n"); 1933cc72986SMark Brown if (val[1] & ARIZONA_ADSP2_1_OVERCLOCKED_STS) 1943cc72986SMark Brown dev_err(arizona->dev, "DSP1 overclocked\n"); 1953cc72986SMark Brown if (val[1] & ARIZONA_ISRC2_OVERCLOCKED_STS) 1963cc72986SMark Brown dev_err(arizona->dev, "ISRC2 overclocked\n"); 1973cc72986SMark Brown if (val[1] & ARIZONA_ISRC1_OVERCLOCKED_STS) 1983cc72986SMark Brown dev_err(arizona->dev, "ISRC1 overclocked\n"); 1993cc72986SMark Brown 2003cc72986SMark Brown return IRQ_HANDLED; 2013cc72986SMark Brown } 2023cc72986SMark Brown 2039d53dfdcSCharles Keepax static int arizona_poll_reg(struct arizona *arizona, 2049d53dfdcSCharles Keepax int timeout, unsigned int reg, 2059d53dfdcSCharles Keepax unsigned int mask, unsigned int target) 2069d53dfdcSCharles Keepax { 2079d53dfdcSCharles Keepax unsigned int val = 0; 2089d53dfdcSCharles Keepax int ret, i; 2099d53dfdcSCharles Keepax 2109d53dfdcSCharles Keepax for (i = 0; i < timeout; i++) { 2119d53dfdcSCharles Keepax ret = regmap_read(arizona->regmap, reg, &val); 2129d53dfdcSCharles Keepax if (ret != 0) { 2139d53dfdcSCharles Keepax dev_err(arizona->dev, "Failed to read reg %u: %d\n", 2149d53dfdcSCharles Keepax reg, ret); 2159d53dfdcSCharles Keepax continue; 2169d53dfdcSCharles Keepax } 2179d53dfdcSCharles Keepax 2189d53dfdcSCharles Keepax if ((val & mask) == target) 2199d53dfdcSCharles Keepax return 0; 2209d53dfdcSCharles Keepax 2219d53dfdcSCharles Keepax msleep(1); 2229d53dfdcSCharles Keepax } 2239d53dfdcSCharles Keepax 2249d53dfdcSCharles Keepax dev_err(arizona->dev, "Polling reg %u timed out: %x\n", reg, val); 2259d53dfdcSCharles Keepax return -ETIMEDOUT; 2269d53dfdcSCharles Keepax } 2279d53dfdcSCharles Keepax 2283cc72986SMark Brown static int arizona_wait_for_boot(struct arizona *arizona) 2293cc72986SMark Brown { 2309d53dfdcSCharles Keepax int ret; 2313cc72986SMark Brown 2323cc72986SMark Brown /* 2333cc72986SMark Brown * We can't use an interrupt as we need to runtime resume to do so, 2343cc72986SMark Brown * we won't race with the interrupt handler as it'll be blocked on 2353cc72986SMark Brown * runtime resume. 2363cc72986SMark Brown */ 2379d53dfdcSCharles Keepax ret = arizona_poll_reg(arizona, 5, ARIZONA_INTERRUPT_RAW_STATUS_5, 2389d53dfdcSCharles Keepax ARIZONA_BOOT_DONE_STS, ARIZONA_BOOT_DONE_STS); 2393cc72986SMark Brown 2409d53dfdcSCharles Keepax if (!ret) 2413cc72986SMark Brown regmap_write(arizona->regmap, ARIZONA_INTERRUPT_STATUS_5, 2423cc72986SMark Brown ARIZONA_BOOT_DONE_STS); 2433cc72986SMark Brown 2443cc72986SMark Brown pm_runtime_mark_last_busy(arizona->dev); 2453cc72986SMark Brown 2469d53dfdcSCharles Keepax return ret; 2473cc72986SMark Brown } 2483cc72986SMark Brown 249e80436bbSCharles Keepax static int arizona_apply_hardware_patch(struct arizona* arizona) 250e80436bbSCharles Keepax { 251e80436bbSCharles Keepax unsigned int fll, sysclk; 252e80436bbSCharles Keepax int ret, err; 253e80436bbSCharles Keepax 254e80436bbSCharles Keepax regcache_cache_bypass(arizona->regmap, true); 255e80436bbSCharles Keepax 256e80436bbSCharles Keepax /* Cache existing FLL and SYSCLK settings */ 257e80436bbSCharles Keepax ret = regmap_read(arizona->regmap, ARIZONA_FLL1_CONTROL_1, &fll); 258e80436bbSCharles Keepax if (ret != 0) { 259e80436bbSCharles Keepax dev_err(arizona->dev, "Failed to cache FLL settings: %d\n", 260e80436bbSCharles Keepax ret); 261e80436bbSCharles Keepax return ret; 262e80436bbSCharles Keepax } 263e80436bbSCharles Keepax ret = regmap_read(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, &sysclk); 264e80436bbSCharles Keepax if (ret != 0) { 265e80436bbSCharles Keepax dev_err(arizona->dev, "Failed to cache SYSCLK settings: %d\n", 266e80436bbSCharles Keepax ret); 267e80436bbSCharles Keepax return ret; 268e80436bbSCharles Keepax } 269e80436bbSCharles Keepax 270e80436bbSCharles Keepax /* Start up SYSCLK using the FLL in free running mode */ 271e80436bbSCharles Keepax ret = regmap_write(arizona->regmap, ARIZONA_FLL1_CONTROL_1, 272e80436bbSCharles Keepax ARIZONA_FLL1_ENA | ARIZONA_FLL1_FREERUN); 273e80436bbSCharles Keepax if (ret != 0) { 274e80436bbSCharles Keepax dev_err(arizona->dev, 275e80436bbSCharles Keepax "Failed to start FLL in freerunning mode: %d\n", 276e80436bbSCharles Keepax ret); 277e80436bbSCharles Keepax return ret; 278e80436bbSCharles Keepax } 279e80436bbSCharles Keepax ret = arizona_poll_reg(arizona, 25, ARIZONA_INTERRUPT_RAW_STATUS_5, 280e80436bbSCharles Keepax ARIZONA_FLL1_CLOCK_OK_STS, 281e80436bbSCharles Keepax ARIZONA_FLL1_CLOCK_OK_STS); 282e80436bbSCharles Keepax if (ret != 0) { 283e80436bbSCharles Keepax ret = -ETIMEDOUT; 284e80436bbSCharles Keepax goto err_fll; 285e80436bbSCharles Keepax } 286e80436bbSCharles Keepax 287e80436bbSCharles Keepax ret = regmap_write(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, 0x0144); 288e80436bbSCharles Keepax if (ret != 0) { 289e80436bbSCharles Keepax dev_err(arizona->dev, "Failed to start SYSCLK: %d\n", ret); 290e80436bbSCharles Keepax goto err_fll; 291e80436bbSCharles Keepax } 292e80436bbSCharles Keepax 293e80436bbSCharles Keepax /* Start the write sequencer and wait for it to finish */ 294e80436bbSCharles Keepax ret = regmap_write(arizona->regmap, ARIZONA_WRITE_SEQUENCER_CTRL_0, 295e80436bbSCharles Keepax ARIZONA_WSEQ_ENA | ARIZONA_WSEQ_START | 160); 296e80436bbSCharles Keepax if (ret != 0) { 297e80436bbSCharles Keepax dev_err(arizona->dev, "Failed to start write sequencer: %d\n", 298e80436bbSCharles Keepax ret); 299e80436bbSCharles Keepax goto err_sysclk; 300e80436bbSCharles Keepax } 301e80436bbSCharles Keepax ret = arizona_poll_reg(arizona, 5, ARIZONA_WRITE_SEQUENCER_CTRL_1, 302e80436bbSCharles Keepax ARIZONA_WSEQ_BUSY, 0); 303e80436bbSCharles Keepax if (ret != 0) { 304e80436bbSCharles Keepax regmap_write(arizona->regmap, ARIZONA_WRITE_SEQUENCER_CTRL_0, 305e80436bbSCharles Keepax ARIZONA_WSEQ_ABORT); 306e80436bbSCharles Keepax ret = -ETIMEDOUT; 307e80436bbSCharles Keepax } 308e80436bbSCharles Keepax 309e80436bbSCharles Keepax err_sysclk: 310e80436bbSCharles Keepax err = regmap_write(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, sysclk); 311e80436bbSCharles Keepax if (err != 0) { 312e80436bbSCharles Keepax dev_err(arizona->dev, 313e80436bbSCharles Keepax "Failed to re-apply old SYSCLK settings: %d\n", 314e80436bbSCharles Keepax err); 315e80436bbSCharles Keepax } 316e80436bbSCharles Keepax 317e80436bbSCharles Keepax err_fll: 318e80436bbSCharles Keepax err = regmap_write(arizona->regmap, ARIZONA_FLL1_CONTROL_1, fll); 319e80436bbSCharles Keepax if (err != 0) { 320e80436bbSCharles Keepax dev_err(arizona->dev, 321e80436bbSCharles Keepax "Failed to re-apply old FLL settings: %d\n", 322e80436bbSCharles Keepax err); 323e80436bbSCharles Keepax } 324e80436bbSCharles Keepax 325e80436bbSCharles Keepax regcache_cache_bypass(arizona->regmap, false); 326e80436bbSCharles Keepax 327e80436bbSCharles Keepax if (ret != 0) 328e80436bbSCharles Keepax return ret; 329e80436bbSCharles Keepax else 330e80436bbSCharles Keepax return err; 331e80436bbSCharles Keepax } 332e80436bbSCharles Keepax 3333cc72986SMark Brown #ifdef CONFIG_PM_RUNTIME 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 396d9d03496SCharles Keepax switch (arizona->type) { 397d9d03496SCharles Keepax case WM5102: 398d9d03496SCharles Keepax ret = wm5102_patch(arizona); 399d9d03496SCharles Keepax if (ret != 0) { 400d9d03496SCharles Keepax dev_err(arizona->dev, "Failed to apply patch: %d\n", 401d9d03496SCharles Keepax ret); 402d9d03496SCharles Keepax goto err; 403d9d03496SCharles Keepax } 404d9d03496SCharles Keepax default: 405d9d03496SCharles Keepax break; 406d9d03496SCharles Keepax } 407d9d03496SCharles Keepax 4089270bdf5SMark Brown ret = regcache_sync(arizona->regmap); 4099270bdf5SMark Brown if (ret != 0) { 4109270bdf5SMark Brown dev_err(arizona->dev, "Failed to restore register cache\n"); 4114816bd1cSMark Brown goto err; 4129270bdf5SMark Brown } 4133cc72986SMark Brown 4143cc72986SMark Brown return 0; 4154816bd1cSMark Brown 4164816bd1cSMark Brown err: 4174816bd1cSMark Brown regcache_cache_only(arizona->regmap, true); 4184816bd1cSMark Brown regulator_disable(arizona->dcvdd); 4194816bd1cSMark Brown return ret; 4203cc72986SMark Brown } 4213cc72986SMark Brown 4223cc72986SMark Brown static int arizona_runtime_suspend(struct device *dev) 4233cc72986SMark Brown { 4243cc72986SMark Brown struct arizona *arizona = dev_get_drvdata(dev); 4255927467dSMark Brown int ret; 4263cc72986SMark Brown 427508c8299SMark Brown dev_dbg(arizona->dev, "Entering AoD mode\n"); 428508c8299SMark Brown 4295927467dSMark Brown if (arizona->external_dcvdd) { 4305927467dSMark Brown ret = regmap_update_bits(arizona->regmap, 4315927467dSMark Brown ARIZONA_ISOLATION_CONTROL, 4325927467dSMark Brown ARIZONA_ISOLATE_DCVDD1, 4335927467dSMark Brown ARIZONA_ISOLATE_DCVDD1); 4345927467dSMark Brown if (ret != 0) { 4355927467dSMark Brown dev_err(arizona->dev, "Failed to isolate DCVDD: %d\n", 4365927467dSMark Brown ret); 4375927467dSMark Brown return ret; 4385927467dSMark Brown } 4395927467dSMark Brown } 4405927467dSMark Brown 44159db9691SMark Brown regulator_disable(arizona->dcvdd); 4423cc72986SMark Brown regcache_cache_only(arizona->regmap, true); 4433cc72986SMark Brown regcache_mark_dirty(arizona->regmap); 4443cc72986SMark Brown 4453cc72986SMark Brown return 0; 4463cc72986SMark Brown } 4473cc72986SMark Brown #endif 4483cc72986SMark Brown 449dc781d0eSMark Brown #ifdef CONFIG_PM_SLEEP 45067c99296SMark Brown static int arizona_suspend(struct device *dev) 45167c99296SMark Brown { 45267c99296SMark Brown struct arizona *arizona = dev_get_drvdata(dev); 45367c99296SMark Brown 45467c99296SMark Brown dev_dbg(arizona->dev, "Suspend, disabling IRQ\n"); 45567c99296SMark Brown disable_irq(arizona->irq); 45667c99296SMark Brown 45767c99296SMark Brown return 0; 45867c99296SMark Brown } 45967c99296SMark Brown 46067c99296SMark Brown static int arizona_suspend_late(struct device *dev) 46167c99296SMark Brown { 46267c99296SMark Brown struct arizona *arizona = dev_get_drvdata(dev); 46367c99296SMark Brown 46467c99296SMark Brown dev_dbg(arizona->dev, "Late suspend, reenabling IRQ\n"); 46567c99296SMark Brown enable_irq(arizona->irq); 46667c99296SMark Brown 46767c99296SMark Brown return 0; 46867c99296SMark Brown } 46967c99296SMark Brown 470dc781d0eSMark Brown static int arizona_resume_noirq(struct device *dev) 471dc781d0eSMark Brown { 472dc781d0eSMark Brown struct arizona *arizona = dev_get_drvdata(dev); 473dc781d0eSMark Brown 474dc781d0eSMark Brown dev_dbg(arizona->dev, "Early resume, disabling IRQ\n"); 475dc781d0eSMark Brown disable_irq(arizona->irq); 476dc781d0eSMark Brown 477dc781d0eSMark Brown return 0; 478dc781d0eSMark Brown } 479dc781d0eSMark Brown 480dc781d0eSMark Brown static int arizona_resume(struct device *dev) 481dc781d0eSMark Brown { 482dc781d0eSMark Brown struct arizona *arizona = dev_get_drvdata(dev); 483dc781d0eSMark Brown 484dc781d0eSMark Brown dev_dbg(arizona->dev, "Late resume, reenabling IRQ\n"); 485dc781d0eSMark Brown enable_irq(arizona->irq); 486dc781d0eSMark Brown 487dc781d0eSMark Brown return 0; 488dc781d0eSMark Brown } 489dc781d0eSMark Brown #endif 490dc781d0eSMark Brown 4913cc72986SMark Brown const struct dev_pm_ops arizona_pm_ops = { 4923cc72986SMark Brown SET_RUNTIME_PM_OPS(arizona_runtime_suspend, 4933cc72986SMark Brown arizona_runtime_resume, 4943cc72986SMark Brown NULL) 49567c99296SMark Brown SET_SYSTEM_SLEEP_PM_OPS(arizona_suspend, arizona_resume) 496dc781d0eSMark Brown #ifdef CONFIG_PM_SLEEP 49767c99296SMark Brown .suspend_late = arizona_suspend_late, 498dc781d0eSMark Brown .resume_noirq = arizona_resume_noirq, 499dc781d0eSMark Brown #endif 5003cc72986SMark Brown }; 5013cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_pm_ops); 5023cc72986SMark Brown 503d781009cSMark Brown #ifdef CONFIG_OF 504d781009cSMark Brown int arizona_of_get_type(struct device *dev) 505d781009cSMark Brown { 506d781009cSMark Brown const struct of_device_id *id = of_match_device(arizona_of_match, dev); 507d781009cSMark Brown 508d781009cSMark Brown if (id) 509d781009cSMark Brown return (int)id->data; 510d781009cSMark Brown else 511d781009cSMark Brown return 0; 512d781009cSMark Brown } 513d781009cSMark Brown EXPORT_SYMBOL_GPL(arizona_of_get_type); 514d781009cSMark Brown 515d781009cSMark Brown static int arizona_of_get_core_pdata(struct arizona *arizona) 516d781009cSMark Brown { 517d781009cSMark Brown int ret, i; 518d781009cSMark Brown 519d781009cSMark Brown arizona->pdata.reset = of_get_named_gpio(arizona->dev->of_node, 520d781009cSMark Brown "wlf,reset", 0); 521d781009cSMark Brown if (arizona->pdata.reset < 0) 522d781009cSMark Brown arizona->pdata.reset = 0; 523d781009cSMark Brown 524d781009cSMark Brown arizona->pdata.ldoena = of_get_named_gpio(arizona->dev->of_node, 525d781009cSMark Brown "wlf,ldoena", 0); 526d781009cSMark Brown if (arizona->pdata.ldoena < 0) 527d781009cSMark Brown arizona->pdata.ldoena = 0; 528d781009cSMark Brown 529d781009cSMark Brown ret = of_property_read_u32_array(arizona->dev->of_node, 530d781009cSMark Brown "wlf,gpio-defaults", 531d781009cSMark Brown arizona->pdata.gpio_defaults, 532d781009cSMark Brown ARRAY_SIZE(arizona->pdata.gpio_defaults)); 533d781009cSMark Brown if (ret >= 0) { 534d781009cSMark Brown /* 535d781009cSMark Brown * All values are literal except out of range values 536d781009cSMark Brown * which are chip default, translate into platform 537d781009cSMark Brown * data which uses 0 as chip default and out of range 538d781009cSMark Brown * as zero. 539d781009cSMark Brown */ 540d781009cSMark Brown for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) { 541d781009cSMark Brown if (arizona->pdata.gpio_defaults[i] > 0xffff) 542d781009cSMark Brown arizona->pdata.gpio_defaults[i] = 0; 543d781009cSMark Brown if (arizona->pdata.gpio_defaults[i] == 0) 544d781009cSMark Brown arizona->pdata.gpio_defaults[i] = 0x10000; 545d781009cSMark Brown } 546d781009cSMark Brown } else { 547d781009cSMark Brown dev_err(arizona->dev, "Failed to parse GPIO defaults: %d\n", 548d781009cSMark Brown ret); 549d781009cSMark Brown } 550d781009cSMark Brown 551d781009cSMark Brown return 0; 552d781009cSMark Brown } 553d781009cSMark Brown 554d781009cSMark Brown const struct of_device_id arizona_of_match[] = { 555d781009cSMark Brown { .compatible = "wlf,wm5102", .data = (void *)WM5102 }, 556d781009cSMark Brown { .compatible = "wlf,wm5110", .data = (void *)WM5110 }, 557*dc7d4863SCharles Keepax { .compatible = "wlf,wm8997", .data = (void *)WM8997 }, 558d781009cSMark Brown {}, 559d781009cSMark Brown }; 560d781009cSMark Brown EXPORT_SYMBOL_GPL(arizona_of_match); 561d781009cSMark Brown #else 562d781009cSMark Brown static inline int arizona_of_get_core_pdata(struct arizona *arizona) 563d781009cSMark Brown { 564d781009cSMark Brown return 0; 565d781009cSMark Brown } 566d781009cSMark Brown #endif 567d781009cSMark Brown 5683cc72986SMark Brown static struct mfd_cell early_devs[] = { 5693cc72986SMark Brown { .name = "arizona-ldo1" }, 5703cc72986SMark Brown }; 5713cc72986SMark Brown 5723cc72986SMark Brown static struct mfd_cell wm5102_devs[] = { 573d7768111SMark Brown { .name = "arizona-micsupp" }, 5743cc72986SMark Brown { .name = "arizona-extcon" }, 5753cc72986SMark Brown { .name = "arizona-gpio" }, 576503b1cacSMark Brown { .name = "arizona-haptics" }, 5773cc72986SMark Brown { .name = "arizona-pwm" }, 5783cc72986SMark Brown { .name = "wm5102-codec" }, 5793cc72986SMark Brown }; 5803cc72986SMark Brown 581e102befeSMark Brown static struct mfd_cell wm5110_devs[] = { 582d7768111SMark Brown { .name = "arizona-micsupp" }, 583e102befeSMark Brown { .name = "arizona-extcon" }, 584e102befeSMark Brown { .name = "arizona-gpio" }, 585503b1cacSMark Brown { .name = "arizona-haptics" }, 586e102befeSMark Brown { .name = "arizona-pwm" }, 587e102befeSMark Brown { .name = "wm5110-codec" }, 588e102befeSMark Brown }; 589e102befeSMark Brown 590*dc7d4863SCharles Keepax static struct mfd_cell wm8997_devs[] = { 591*dc7d4863SCharles Keepax { .name = "arizona-micsupp" }, 592*dc7d4863SCharles Keepax { .name = "arizona-extcon" }, 593*dc7d4863SCharles Keepax { .name = "arizona-gpio" }, 594*dc7d4863SCharles Keepax { .name = "arizona-haptics" }, 595*dc7d4863SCharles Keepax { .name = "arizona-pwm" }, 596*dc7d4863SCharles Keepax { .name = "wm8997-codec" }, 597*dc7d4863SCharles Keepax }; 598*dc7d4863SCharles Keepax 599f791be49SBill Pemberton int arizona_dev_init(struct arizona *arizona) 6003cc72986SMark Brown { 6013cc72986SMark Brown struct device *dev = arizona->dev; 6023cc72986SMark Brown const char *type_name; 6033cc72986SMark Brown unsigned int reg, val; 60462d62b59SMark Brown int (*apply_patch)(struct arizona *) = NULL; 6053cc72986SMark Brown int ret, i; 6063cc72986SMark Brown 6073cc72986SMark Brown dev_set_drvdata(arizona->dev, arizona); 6083cc72986SMark Brown mutex_init(&arizona->clk_lock); 6093cc72986SMark Brown 610d781009cSMark Brown arizona_of_get_core_pdata(arizona); 611d781009cSMark Brown 6123cc72986SMark Brown if (dev_get_platdata(arizona->dev)) 6133cc72986SMark Brown memcpy(&arizona->pdata, dev_get_platdata(arizona->dev), 6143cc72986SMark Brown sizeof(arizona->pdata)); 6153cc72986SMark Brown 6163cc72986SMark Brown regcache_cache_only(arizona->regmap, true); 6173cc72986SMark Brown 6183cc72986SMark Brown switch (arizona->type) { 6193cc72986SMark Brown case WM5102: 620e102befeSMark Brown case WM5110: 621*dc7d4863SCharles Keepax case WM8997: 6223cc72986SMark Brown for (i = 0; i < ARRAY_SIZE(wm5102_core_supplies); i++) 6233cc72986SMark Brown arizona->core_supplies[i].supply 6243cc72986SMark Brown = wm5102_core_supplies[i]; 6253cc72986SMark Brown arizona->num_core_supplies = ARRAY_SIZE(wm5102_core_supplies); 6263cc72986SMark Brown break; 6273cc72986SMark Brown default: 6283cc72986SMark Brown dev_err(arizona->dev, "Unknown device type %d\n", 6293cc72986SMark Brown arizona->type); 6303cc72986SMark Brown return -EINVAL; 6313cc72986SMark Brown } 6323cc72986SMark Brown 6333cc72986SMark Brown ret = mfd_add_devices(arizona->dev, -1, early_devs, 6340848c94fSMark Brown ARRAY_SIZE(early_devs), NULL, 0, NULL); 6353cc72986SMark Brown if (ret != 0) { 6363cc72986SMark Brown dev_err(dev, "Failed to add early children: %d\n", ret); 6373cc72986SMark Brown return ret; 6383cc72986SMark Brown } 6393cc72986SMark Brown 6403cc72986SMark Brown ret = devm_regulator_bulk_get(dev, arizona->num_core_supplies, 6413cc72986SMark Brown arizona->core_supplies); 6423cc72986SMark Brown if (ret != 0) { 6433cc72986SMark Brown dev_err(dev, "Failed to request core supplies: %d\n", 6443cc72986SMark Brown ret); 6453cc72986SMark Brown goto err_early; 6463cc72986SMark Brown } 6473cc72986SMark Brown 64859db9691SMark Brown arizona->dcvdd = devm_regulator_get(arizona->dev, "DCVDD"); 64959db9691SMark Brown if (IS_ERR(arizona->dcvdd)) { 65059db9691SMark Brown ret = PTR_ERR(arizona->dcvdd); 65159db9691SMark Brown dev_err(dev, "Failed to request DCVDD: %d\n", ret); 65259db9691SMark Brown goto err_early; 65359db9691SMark Brown } 65459db9691SMark Brown 65587d3af4aSMark Brown if (arizona->pdata.reset) { 65687d3af4aSMark Brown /* Start out with /RESET low to put the chip into reset */ 65787d3af4aSMark Brown ret = gpio_request_one(arizona->pdata.reset, 65887d3af4aSMark Brown GPIOF_DIR_OUT | GPIOF_INIT_LOW, 65987d3af4aSMark Brown "arizona /RESET"); 66087d3af4aSMark Brown if (ret != 0) { 66187d3af4aSMark Brown dev_err(dev, "Failed to request /RESET: %d\n", ret); 66287d3af4aSMark Brown goto err_early; 66387d3af4aSMark Brown } 66487d3af4aSMark Brown } 66587d3af4aSMark Brown 6663cc72986SMark Brown ret = regulator_bulk_enable(arizona->num_core_supplies, 6673cc72986SMark Brown arizona->core_supplies); 6683cc72986SMark Brown if (ret != 0) { 6693cc72986SMark Brown dev_err(dev, "Failed to enable core supplies: %d\n", 6703cc72986SMark Brown ret); 6713cc72986SMark Brown goto err_early; 6723cc72986SMark Brown } 6733cc72986SMark Brown 67459db9691SMark Brown ret = regulator_enable(arizona->dcvdd); 67559db9691SMark Brown if (ret != 0) { 67659db9691SMark Brown dev_err(dev, "Failed to enable DCVDD: %d\n", ret); 67759db9691SMark Brown goto err_enable; 67859db9691SMark Brown } 67959db9691SMark Brown 680c25feaa5SCharles Keepax if (arizona->pdata.reset) { 6813cc72986SMark Brown gpio_set_value_cansleep(arizona->pdata.reset, 1); 682c25feaa5SCharles Keepax msleep(1); 683c25feaa5SCharles Keepax } 6843cc72986SMark Brown 6853cc72986SMark Brown regcache_cache_only(arizona->regmap, false); 6863cc72986SMark Brown 687ca76ceb8SMark Brown /* Verify that this is a chip we know about */ 688ca76ceb8SMark Brown ret = regmap_read(arizona->regmap, ARIZONA_SOFTWARE_RESET, ®); 689ca76ceb8SMark Brown if (ret != 0) { 690ca76ceb8SMark Brown dev_err(dev, "Failed to read ID register: %d\n", ret); 691ca76ceb8SMark Brown goto err_reset; 692ca76ceb8SMark Brown } 693ca76ceb8SMark Brown 694ca76ceb8SMark Brown switch (reg) { 695ca76ceb8SMark Brown case 0x5102: 696ca76ceb8SMark Brown case 0x5110: 697*dc7d4863SCharles Keepax case 0x8997: 698ca76ceb8SMark Brown break; 699ca76ceb8SMark Brown default: 700ca76ceb8SMark Brown dev_err(arizona->dev, "Unknown device ID: %x\n", reg); 701ca76ceb8SMark Brown goto err_reset; 702ca76ceb8SMark Brown } 703ca76ceb8SMark Brown 704ca76ceb8SMark Brown /* If we have a /RESET GPIO we'll already be reset */ 705ca76ceb8SMark Brown if (!arizona->pdata.reset) { 706ca76ceb8SMark Brown regcache_mark_dirty(arizona->regmap); 707ca76ceb8SMark Brown 708ca76ceb8SMark Brown ret = regmap_write(arizona->regmap, ARIZONA_SOFTWARE_RESET, 0); 709ca76ceb8SMark Brown if (ret != 0) { 710ca76ceb8SMark Brown dev_err(dev, "Failed to reset device: %d\n", ret); 711ca76ceb8SMark Brown goto err_reset; 712ca76ceb8SMark Brown } 713ca76ceb8SMark Brown 714ca76ceb8SMark Brown msleep(1); 715ca76ceb8SMark Brown 716ca76ceb8SMark Brown ret = regcache_sync(arizona->regmap); 717ca76ceb8SMark Brown if (ret != 0) { 718ca76ceb8SMark Brown dev_err(dev, "Failed to sync device: %d\n", ret); 719ca76ceb8SMark Brown goto err_reset; 720ca76ceb8SMark Brown } 721ca76ceb8SMark Brown } 722ca76ceb8SMark Brown 723ca76ceb8SMark Brown /* Ensure device startup is complete */ 724ca76ceb8SMark Brown switch (arizona->type) { 725ca76ceb8SMark Brown case WM5102: 726ca76ceb8SMark Brown ret = regmap_read(arizona->regmap, 0x19, &val); 727ca76ceb8SMark Brown if (ret != 0) 728ca76ceb8SMark Brown dev_err(dev, 729ca76ceb8SMark Brown "Failed to check write sequencer state: %d\n", 730ca76ceb8SMark Brown ret); 731ca76ceb8SMark Brown else if (val & 0x01) 732ca76ceb8SMark Brown break; 733ca76ceb8SMark Brown /* Fall through */ 734ca76ceb8SMark Brown default: 735ca76ceb8SMark Brown ret = arizona_wait_for_boot(arizona); 736ca76ceb8SMark Brown if (ret != 0) { 737ca76ceb8SMark Brown dev_err(arizona->dev, 738ca76ceb8SMark Brown "Device failed initial boot: %d\n", ret); 739ca76ceb8SMark Brown goto err_reset; 740ca76ceb8SMark Brown } 741ca76ceb8SMark Brown break; 742ca76ceb8SMark Brown } 743ca76ceb8SMark Brown 744ca76ceb8SMark Brown /* Read the device ID information & do device specific stuff */ 7453cc72986SMark Brown ret = regmap_read(arizona->regmap, ARIZONA_SOFTWARE_RESET, ®); 7463cc72986SMark Brown if (ret != 0) { 7473cc72986SMark Brown dev_err(dev, "Failed to read ID register: %d\n", ret); 74859db9691SMark Brown goto err_reset; 7493cc72986SMark Brown } 7503cc72986SMark Brown 7513cc72986SMark Brown ret = regmap_read(arizona->regmap, ARIZONA_DEVICE_REVISION, 7523cc72986SMark Brown &arizona->rev); 7533cc72986SMark Brown if (ret != 0) { 7543cc72986SMark Brown dev_err(dev, "Failed to read revision register: %d\n", ret); 75559db9691SMark Brown goto err_reset; 7563cc72986SMark Brown } 7573cc72986SMark Brown arizona->rev &= ARIZONA_DEVICE_REVISION_MASK; 7583cc72986SMark Brown 7593cc72986SMark Brown switch (reg) { 760863df8d5SMark Brown #ifdef CONFIG_MFD_WM5102 7613cc72986SMark Brown case 0x5102: 7623cc72986SMark Brown type_name = "WM5102"; 7633cc72986SMark Brown if (arizona->type != WM5102) { 7643cc72986SMark Brown dev_err(arizona->dev, "WM5102 registered as %d\n", 7653cc72986SMark Brown arizona->type); 7663cc72986SMark Brown arizona->type = WM5102; 7673cc72986SMark Brown } 76862d62b59SMark Brown apply_patch = wm5102_patch; 769c6d6bfb1SMark Brown arizona->rev &= 0x7; 7703cc72986SMark Brown break; 771863df8d5SMark Brown #endif 772e102befeSMark Brown #ifdef CONFIG_MFD_WM5110 773e102befeSMark Brown case 0x5110: 774e102befeSMark Brown type_name = "WM5110"; 775e102befeSMark Brown if (arizona->type != WM5110) { 776e102befeSMark Brown dev_err(arizona->dev, "WM5110 registered as %d\n", 777e102befeSMark Brown arizona->type); 778e102befeSMark Brown arizona->type = WM5110; 779e102befeSMark Brown } 78062d62b59SMark Brown apply_patch = wm5110_patch; 781e102befeSMark Brown break; 782e102befeSMark Brown #endif 783*dc7d4863SCharles Keepax #ifdef CONFIG_MFD_WM8997 784*dc7d4863SCharles Keepax case 0x8997: 785*dc7d4863SCharles Keepax type_name = "WM8997"; 786*dc7d4863SCharles Keepax if (arizona->type != WM8997) { 787*dc7d4863SCharles Keepax dev_err(arizona->dev, "WM8997 registered as %d\n", 788*dc7d4863SCharles Keepax arizona->type); 789*dc7d4863SCharles Keepax arizona->type = WM8997; 790*dc7d4863SCharles Keepax } 791*dc7d4863SCharles Keepax apply_patch = wm8997_patch; 792*dc7d4863SCharles Keepax break; 793*dc7d4863SCharles Keepax #endif 7943cc72986SMark Brown default: 7953cc72986SMark Brown dev_err(arizona->dev, "Unknown device ID %x\n", reg); 79659db9691SMark Brown goto err_reset; 7973cc72986SMark Brown } 7983cc72986SMark Brown 7993cc72986SMark Brown dev_info(dev, "%s revision %c\n", type_name, arizona->rev + 'A'); 8003cc72986SMark Brown 80162d62b59SMark Brown if (apply_patch) { 80262d62b59SMark Brown ret = apply_patch(arizona); 80362d62b59SMark Brown if (ret != 0) { 80462d62b59SMark Brown dev_err(arizona->dev, "Failed to apply patch: %d\n", 80562d62b59SMark Brown ret); 80662d62b59SMark Brown goto err_reset; 80762d62b59SMark Brown } 808e80436bbSCharles Keepax 809e80436bbSCharles Keepax switch (arizona->type) { 810e80436bbSCharles Keepax case WM5102: 811e80436bbSCharles Keepax ret = arizona_apply_hardware_patch(arizona); 812e80436bbSCharles Keepax if (ret != 0) { 813e80436bbSCharles Keepax dev_err(arizona->dev, 814e80436bbSCharles Keepax "Failed to apply hardware patch: %d\n", 815e80436bbSCharles Keepax ret); 816e80436bbSCharles Keepax goto err_reset; 817e80436bbSCharles Keepax } 818e80436bbSCharles Keepax break; 819e80436bbSCharles Keepax default: 820e80436bbSCharles Keepax break; 821e80436bbSCharles Keepax } 82262d62b59SMark Brown } 82362d62b59SMark Brown 8243cc72986SMark Brown for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) { 8253cc72986SMark Brown if (!arizona->pdata.gpio_defaults[i]) 8263cc72986SMark Brown continue; 8273cc72986SMark Brown 8283cc72986SMark Brown regmap_write(arizona->regmap, ARIZONA_GPIO1_CTRL + i, 8293cc72986SMark Brown arizona->pdata.gpio_defaults[i]); 8303cc72986SMark Brown } 8313cc72986SMark Brown 8325927467dSMark Brown /* 8335927467dSMark Brown * LDO1 can only be used to supply DCVDD so if it has no 8345927467dSMark Brown * consumers then DCVDD is supplied externally. 8355927467dSMark Brown */ 8365927467dSMark Brown if (arizona->pdata.ldo1 && 8375927467dSMark Brown arizona->pdata.ldo1->num_consumer_supplies == 0) 8385927467dSMark Brown arizona->external_dcvdd = true; 8395927467dSMark Brown 8403cc72986SMark Brown pm_runtime_set_autosuspend_delay(arizona->dev, 100); 8413cc72986SMark Brown pm_runtime_use_autosuspend(arizona->dev); 8423cc72986SMark Brown pm_runtime_enable(arizona->dev); 8433cc72986SMark Brown 8443cc72986SMark Brown /* Chip default */ 8453cc72986SMark Brown if (!arizona->pdata.clk32k_src) 8463cc72986SMark Brown arizona->pdata.clk32k_src = ARIZONA_32KZ_MCLK2; 8473cc72986SMark Brown 8483cc72986SMark Brown switch (arizona->pdata.clk32k_src) { 8493cc72986SMark Brown case ARIZONA_32KZ_MCLK1: 8503cc72986SMark Brown case ARIZONA_32KZ_MCLK2: 8513cc72986SMark Brown regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, 8523cc72986SMark Brown ARIZONA_CLK_32K_SRC_MASK, 8533cc72986SMark Brown arizona->pdata.clk32k_src - 1); 854767c6dc0SMark Brown arizona_clk32k_enable(arizona); 8553cc72986SMark Brown break; 8563cc72986SMark Brown case ARIZONA_32KZ_NONE: 8573cc72986SMark Brown regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, 8583cc72986SMark Brown ARIZONA_CLK_32K_SRC_MASK, 2); 8593cc72986SMark Brown break; 8603cc72986SMark Brown default: 8613cc72986SMark Brown dev_err(arizona->dev, "Invalid 32kHz clock source: %d\n", 8623cc72986SMark Brown arizona->pdata.clk32k_src); 8633cc72986SMark Brown ret = -EINVAL; 86459db9691SMark Brown goto err_reset; 8653cc72986SMark Brown } 8663cc72986SMark Brown 8673d91f828SMark Brown for (i = 0; i < ARIZONA_MAX_MICBIAS; i++) { 868544c7aadSMark Brown if (!arizona->pdata.micbias[i].mV && 869544c7aadSMark Brown !arizona->pdata.micbias[i].bypass) 8703d91f828SMark Brown continue; 8713d91f828SMark Brown 872544c7aadSMark Brown /* Apply default for bypass mode */ 873544c7aadSMark Brown if (!arizona->pdata.micbias[i].mV) 874544c7aadSMark Brown arizona->pdata.micbias[i].mV = 2800; 875544c7aadSMark Brown 8763d91f828SMark Brown val = (arizona->pdata.micbias[i].mV - 1500) / 100; 877544c7aadSMark Brown 8783d91f828SMark Brown val <<= ARIZONA_MICB1_LVL_SHIFT; 8793d91f828SMark Brown 8803d91f828SMark Brown if (arizona->pdata.micbias[i].ext_cap) 8813d91f828SMark Brown val |= ARIZONA_MICB1_EXT_CAP; 8823d91f828SMark Brown 8833d91f828SMark Brown if (arizona->pdata.micbias[i].discharge) 8843d91f828SMark Brown val |= ARIZONA_MICB1_DISCH; 8853d91f828SMark Brown 886f773fc6dSCharles Keepax if (arizona->pdata.micbias[i].soft_start) 8873d91f828SMark Brown val |= ARIZONA_MICB1_RATE; 8883d91f828SMark Brown 889544c7aadSMark Brown if (arizona->pdata.micbias[i].bypass) 890544c7aadSMark Brown val |= ARIZONA_MICB1_BYPASS; 891544c7aadSMark Brown 8923d91f828SMark Brown regmap_update_bits(arizona->regmap, 8933d91f828SMark Brown ARIZONA_MIC_BIAS_CTRL_1 + i, 8943d91f828SMark Brown ARIZONA_MICB1_LVL_MASK | 8953d91f828SMark Brown ARIZONA_MICB1_DISCH | 896544c7aadSMark Brown ARIZONA_MICB1_BYPASS | 8973d91f828SMark Brown ARIZONA_MICB1_RATE, val); 8983d91f828SMark Brown } 8993d91f828SMark Brown 9003cc72986SMark Brown for (i = 0; i < ARIZONA_MAX_INPUT; i++) { 9013cc72986SMark Brown /* Default for both is 0 so noop with defaults */ 9023cc72986SMark Brown val = arizona->pdata.dmic_ref[i] 9033cc72986SMark Brown << ARIZONA_IN1_DMIC_SUP_SHIFT; 9043cc72986SMark Brown val |= arizona->pdata.inmode[i] << ARIZONA_IN1_MODE_SHIFT; 9053cc72986SMark Brown 9063cc72986SMark Brown regmap_update_bits(arizona->regmap, 9073cc72986SMark Brown ARIZONA_IN1L_CONTROL + (i * 8), 9083cc72986SMark Brown ARIZONA_IN1_DMIC_SUP_MASK | 9093cc72986SMark Brown ARIZONA_IN1_MODE_MASK, val); 9103cc72986SMark Brown } 9113cc72986SMark Brown 9123cc72986SMark Brown for (i = 0; i < ARIZONA_MAX_OUTPUT; i++) { 9133cc72986SMark Brown /* Default is 0 so noop with defaults */ 9143cc72986SMark Brown if (arizona->pdata.out_mono[i]) 9153cc72986SMark Brown val = ARIZONA_OUT1_MONO; 9163cc72986SMark Brown else 9173cc72986SMark Brown val = 0; 9183cc72986SMark Brown 9193cc72986SMark Brown regmap_update_bits(arizona->regmap, 9203cc72986SMark Brown ARIZONA_OUTPUT_PATH_CONFIG_1L + (i * 8), 9213cc72986SMark Brown ARIZONA_OUT1_MONO, val); 9223cc72986SMark Brown } 9233cc72986SMark Brown 9243cc72986SMark Brown for (i = 0; i < ARIZONA_MAX_PDM_SPK; i++) { 9253cc72986SMark Brown if (arizona->pdata.spk_mute[i]) 9263cc72986SMark Brown regmap_update_bits(arizona->regmap, 9272a51da04SMark Brown ARIZONA_PDM_SPK1_CTRL_1 + (i * 2), 9283cc72986SMark Brown ARIZONA_SPK1_MUTE_ENDIAN_MASK | 9293cc72986SMark Brown ARIZONA_SPK1_MUTE_SEQ1_MASK, 9303cc72986SMark Brown arizona->pdata.spk_mute[i]); 9313cc72986SMark Brown 9323cc72986SMark Brown if (arizona->pdata.spk_fmt[i]) 9333cc72986SMark Brown regmap_update_bits(arizona->regmap, 9342a51da04SMark Brown ARIZONA_PDM_SPK1_CTRL_2 + (i * 2), 9353cc72986SMark Brown ARIZONA_SPK1_FMT_MASK, 9363cc72986SMark Brown arizona->pdata.spk_fmt[i]); 9373cc72986SMark Brown } 9383cc72986SMark Brown 9393cc72986SMark Brown /* Set up for interrupts */ 9403cc72986SMark Brown ret = arizona_irq_init(arizona); 9413cc72986SMark Brown if (ret != 0) 94259db9691SMark Brown goto err_reset; 9433cc72986SMark Brown 9443cc72986SMark Brown arizona_request_irq(arizona, ARIZONA_IRQ_CLKGEN_ERR, "CLKGEN error", 9453cc72986SMark Brown arizona_clkgen_err, arizona); 9463cc72986SMark Brown arizona_request_irq(arizona, ARIZONA_IRQ_OVERCLOCKED, "Overclocked", 9473cc72986SMark Brown arizona_overclocked, arizona); 9483cc72986SMark Brown arizona_request_irq(arizona, ARIZONA_IRQ_UNDERCLOCKED, "Underclocked", 9493cc72986SMark Brown arizona_underclocked, arizona); 9503cc72986SMark Brown 9513cc72986SMark Brown switch (arizona->type) { 9523cc72986SMark Brown case WM5102: 9533cc72986SMark Brown ret = mfd_add_devices(arizona->dev, -1, wm5102_devs, 9540848c94fSMark Brown ARRAY_SIZE(wm5102_devs), NULL, 0, NULL); 9553cc72986SMark Brown break; 956e102befeSMark Brown case WM5110: 957e102befeSMark Brown ret = mfd_add_devices(arizona->dev, -1, wm5110_devs, 95878566afdSCharles Keepax ARRAY_SIZE(wm5110_devs), NULL, 0, NULL); 959e102befeSMark Brown break; 960*dc7d4863SCharles Keepax case WM8997: 961*dc7d4863SCharles Keepax ret = mfd_add_devices(arizona->dev, -1, wm8997_devs, 962*dc7d4863SCharles Keepax ARRAY_SIZE(wm8997_devs), NULL, 0, NULL); 963*dc7d4863SCharles Keepax break; 9643cc72986SMark Brown } 9653cc72986SMark Brown 9663cc72986SMark Brown if (ret != 0) { 9673cc72986SMark Brown dev_err(arizona->dev, "Failed to add subdevices: %d\n", ret); 9683cc72986SMark Brown goto err_irq; 9693cc72986SMark Brown } 9703cc72986SMark Brown 97159db9691SMark Brown #ifdef CONFIG_PM_RUNTIME 97259db9691SMark Brown regulator_disable(arizona->dcvdd); 97359db9691SMark Brown #endif 97459db9691SMark Brown 9753cc72986SMark Brown return 0; 9763cc72986SMark Brown 9773cc72986SMark Brown err_irq: 9783cc72986SMark Brown arizona_irq_exit(arizona); 9793cc72986SMark Brown err_reset: 9803cc72986SMark Brown if (arizona->pdata.reset) { 98187d3af4aSMark Brown gpio_set_value_cansleep(arizona->pdata.reset, 0); 9823cc72986SMark Brown gpio_free(arizona->pdata.reset); 9833cc72986SMark Brown } 98459db9691SMark Brown regulator_disable(arizona->dcvdd); 9853cc72986SMark Brown err_enable: 9863a36a0dbSMark Brown regulator_bulk_disable(arizona->num_core_supplies, 9873cc72986SMark Brown arizona->core_supplies); 9883cc72986SMark Brown err_early: 9893cc72986SMark Brown mfd_remove_devices(dev); 9903cc72986SMark Brown return ret; 9913cc72986SMark Brown } 9923cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_dev_init); 9933cc72986SMark Brown 9944740f73fSBill Pemberton int arizona_dev_exit(struct arizona *arizona) 9953cc72986SMark Brown { 9963cc72986SMark Brown mfd_remove_devices(arizona->dev); 9973cc72986SMark Brown arizona_free_irq(arizona, ARIZONA_IRQ_UNDERCLOCKED, arizona); 9983cc72986SMark Brown arizona_free_irq(arizona, ARIZONA_IRQ_OVERCLOCKED, arizona); 9993cc72986SMark Brown arizona_free_irq(arizona, ARIZONA_IRQ_CLKGEN_ERR, arizona); 10003cc72986SMark Brown pm_runtime_disable(arizona->dev); 10013cc72986SMark Brown arizona_irq_exit(arizona); 10021d017b6bSMark Brown if (arizona->pdata.reset) 10031d017b6bSMark Brown gpio_set_value_cansleep(arizona->pdata.reset, 0); 10041d017b6bSMark Brown regulator_disable(arizona->dcvdd); 10051d017b6bSMark Brown regulator_bulk_disable(ARRAY_SIZE(arizona->core_supplies), 10061d017b6bSMark Brown arizona->core_supplies); 10073cc72986SMark Brown return 0; 10083cc72986SMark Brown } 10093cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_dev_exit); 1010