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> 193cc72986SMark Brown #include <linux/pm_runtime.h> 203cc72986SMark Brown #include <linux/regmap.h> 213cc72986SMark Brown #include <linux/regulator/consumer.h> 223cc72986SMark Brown #include <linux/slab.h> 233cc72986SMark Brown 243cc72986SMark Brown #include <linux/mfd/arizona/core.h> 253cc72986SMark Brown #include <linux/mfd/arizona/registers.h> 263cc72986SMark Brown 273cc72986SMark Brown #include "arizona.h" 283cc72986SMark Brown 293cc72986SMark Brown static const char *wm5102_core_supplies[] = { 303cc72986SMark Brown "AVDD", 313cc72986SMark Brown "DBVDD1", 323cc72986SMark Brown }; 333cc72986SMark Brown 343cc72986SMark Brown int arizona_clk32k_enable(struct arizona *arizona) 353cc72986SMark Brown { 363cc72986SMark Brown int ret = 0; 373cc72986SMark Brown 383cc72986SMark Brown mutex_lock(&arizona->clk_lock); 393cc72986SMark Brown 403cc72986SMark Brown arizona->clk32k_ref++; 413cc72986SMark Brown 423cc72986SMark Brown if (arizona->clk32k_ref == 1) 433cc72986SMark Brown ret = regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, 443cc72986SMark Brown ARIZONA_CLK_32K_ENA, 453cc72986SMark Brown ARIZONA_CLK_32K_ENA); 463cc72986SMark Brown 473cc72986SMark Brown if (ret != 0) 483cc72986SMark Brown arizona->clk32k_ref--; 493cc72986SMark Brown 503cc72986SMark Brown mutex_unlock(&arizona->clk_lock); 513cc72986SMark Brown 523cc72986SMark Brown return ret; 533cc72986SMark Brown } 543cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_clk32k_enable); 553cc72986SMark Brown 563cc72986SMark Brown int arizona_clk32k_disable(struct arizona *arizona) 573cc72986SMark Brown { 583cc72986SMark Brown int ret = 0; 593cc72986SMark Brown 603cc72986SMark Brown mutex_lock(&arizona->clk_lock); 613cc72986SMark Brown 623cc72986SMark Brown BUG_ON(arizona->clk32k_ref <= 0); 633cc72986SMark Brown 643cc72986SMark Brown arizona->clk32k_ref--; 653cc72986SMark Brown 663cc72986SMark Brown if (arizona->clk32k_ref == 0) 673cc72986SMark Brown regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, 683cc72986SMark Brown ARIZONA_CLK_32K_ENA, 0); 693cc72986SMark Brown 703cc72986SMark Brown mutex_unlock(&arizona->clk_lock); 713cc72986SMark Brown 723cc72986SMark Brown return ret; 733cc72986SMark Brown } 743cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_clk32k_disable); 753cc72986SMark Brown 763cc72986SMark Brown static irqreturn_t arizona_clkgen_err(int irq, void *data) 773cc72986SMark Brown { 783cc72986SMark Brown struct arizona *arizona = data; 793cc72986SMark Brown 803cc72986SMark Brown dev_err(arizona->dev, "CLKGEN error\n"); 813cc72986SMark Brown 823cc72986SMark Brown return IRQ_HANDLED; 833cc72986SMark Brown } 843cc72986SMark Brown 853cc72986SMark Brown static irqreturn_t arizona_underclocked(int irq, void *data) 863cc72986SMark Brown { 873cc72986SMark Brown struct arizona *arizona = data; 883cc72986SMark Brown unsigned int val; 893cc72986SMark Brown int ret; 903cc72986SMark Brown 913cc72986SMark Brown ret = regmap_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_8, 923cc72986SMark Brown &val); 933cc72986SMark Brown if (ret != 0) { 943cc72986SMark Brown dev_err(arizona->dev, "Failed to read underclock status: %d\n", 953cc72986SMark Brown ret); 963cc72986SMark Brown return IRQ_NONE; 973cc72986SMark Brown } 983cc72986SMark Brown 993cc72986SMark Brown if (val & ARIZONA_AIF3_UNDERCLOCKED_STS) 1003cc72986SMark Brown dev_err(arizona->dev, "AIF3 underclocked\n"); 1013cc72986SMark Brown if (val & ARIZONA_AIF3_UNDERCLOCKED_STS) 1023cc72986SMark Brown dev_err(arizona->dev, "AIF3 underclocked\n"); 1033cc72986SMark Brown if (val & ARIZONA_AIF2_UNDERCLOCKED_STS) 1043cc72986SMark Brown dev_err(arizona->dev, "AIF1 underclocked\n"); 1053cc72986SMark Brown if (val & ARIZONA_ISRC2_UNDERCLOCKED_STS) 1063cc72986SMark Brown dev_err(arizona->dev, "ISRC2 underclocked\n"); 1073cc72986SMark Brown if (val & ARIZONA_ISRC1_UNDERCLOCKED_STS) 1083cc72986SMark Brown dev_err(arizona->dev, "ISRC1 underclocked\n"); 1093cc72986SMark Brown if (val & ARIZONA_FX_UNDERCLOCKED_STS) 1103cc72986SMark Brown dev_err(arizona->dev, "FX underclocked\n"); 1113cc72986SMark Brown if (val & ARIZONA_ASRC_UNDERCLOCKED_STS) 1123cc72986SMark Brown dev_err(arizona->dev, "ASRC underclocked\n"); 1133cc72986SMark Brown if (val & ARIZONA_DAC_UNDERCLOCKED_STS) 1143cc72986SMark Brown dev_err(arizona->dev, "DAC underclocked\n"); 1153cc72986SMark Brown if (val & ARIZONA_ADC_UNDERCLOCKED_STS) 1163cc72986SMark Brown dev_err(arizona->dev, "ADC underclocked\n"); 1173cc72986SMark Brown if (val & ARIZONA_MIXER_UNDERCLOCKED_STS) 1183cc72986SMark Brown dev_err(arizona->dev, "Mixer underclocked\n"); 1193cc72986SMark Brown 1203cc72986SMark Brown return IRQ_HANDLED; 1213cc72986SMark Brown } 1223cc72986SMark Brown 1233cc72986SMark Brown static irqreturn_t arizona_overclocked(int irq, void *data) 1243cc72986SMark Brown { 1253cc72986SMark Brown struct arizona *arizona = data; 1263cc72986SMark Brown unsigned int val[2]; 1273cc72986SMark Brown int ret; 1283cc72986SMark Brown 1293cc72986SMark Brown ret = regmap_bulk_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_6, 1303cc72986SMark Brown &val[0], 2); 1313cc72986SMark Brown if (ret != 0) { 1323cc72986SMark Brown dev_err(arizona->dev, "Failed to read overclock status: %d\n", 1333cc72986SMark Brown ret); 1343cc72986SMark Brown return IRQ_NONE; 1353cc72986SMark Brown } 1363cc72986SMark Brown 1373cc72986SMark Brown if (val[0] & ARIZONA_PWM_OVERCLOCKED_STS) 1383cc72986SMark Brown dev_err(arizona->dev, "PWM overclocked\n"); 1393cc72986SMark Brown if (val[0] & ARIZONA_FX_CORE_OVERCLOCKED_STS) 1403cc72986SMark Brown dev_err(arizona->dev, "FX core overclocked\n"); 1413cc72986SMark Brown if (val[0] & ARIZONA_DAC_SYS_OVERCLOCKED_STS) 1423cc72986SMark Brown dev_err(arizona->dev, "DAC SYS overclocked\n"); 1433cc72986SMark Brown if (val[0] & ARIZONA_DAC_WARP_OVERCLOCKED_STS) 1443cc72986SMark Brown dev_err(arizona->dev, "DAC WARP overclocked\n"); 1453cc72986SMark Brown if (val[0] & ARIZONA_ADC_OVERCLOCKED_STS) 1463cc72986SMark Brown dev_err(arizona->dev, "ADC overclocked\n"); 1473cc72986SMark Brown if (val[0] & ARIZONA_MIXER_OVERCLOCKED_STS) 1483cc72986SMark Brown dev_err(arizona->dev, "Mixer overclocked\n"); 1493cc72986SMark Brown if (val[0] & ARIZONA_AIF3_SYNC_OVERCLOCKED_STS) 1503cc72986SMark Brown dev_err(arizona->dev, "AIF3 overclocked\n"); 1513cc72986SMark Brown if (val[0] & ARIZONA_AIF2_SYNC_OVERCLOCKED_STS) 1523cc72986SMark Brown dev_err(arizona->dev, "AIF2 overclocked\n"); 1533cc72986SMark Brown if (val[0] & ARIZONA_AIF1_SYNC_OVERCLOCKED_STS) 1543cc72986SMark Brown dev_err(arizona->dev, "AIF1 overclocked\n"); 1553cc72986SMark Brown if (val[0] & ARIZONA_PAD_CTRL_OVERCLOCKED_STS) 1563cc72986SMark Brown dev_err(arizona->dev, "Pad control overclocked\n"); 1573cc72986SMark Brown 1583cc72986SMark Brown if (val[1] & ARIZONA_SLIMBUS_SUBSYS_OVERCLOCKED_STS) 1593cc72986SMark Brown dev_err(arizona->dev, "Slimbus subsystem overclocked\n"); 1603cc72986SMark Brown if (val[1] & ARIZONA_SLIMBUS_ASYNC_OVERCLOCKED_STS) 1613cc72986SMark Brown dev_err(arizona->dev, "Slimbus async overclocked\n"); 1623cc72986SMark Brown if (val[1] & ARIZONA_SLIMBUS_SYNC_OVERCLOCKED_STS) 1633cc72986SMark Brown dev_err(arizona->dev, "Slimbus sync overclocked\n"); 1643cc72986SMark Brown if (val[1] & ARIZONA_ASRC_ASYNC_SYS_OVERCLOCKED_STS) 1653cc72986SMark Brown dev_err(arizona->dev, "ASRC async system overclocked\n"); 1663cc72986SMark Brown if (val[1] & ARIZONA_ASRC_ASYNC_WARP_OVERCLOCKED_STS) 1673cc72986SMark Brown dev_err(arizona->dev, "ASRC async WARP overclocked\n"); 1683cc72986SMark Brown if (val[1] & ARIZONA_ASRC_SYNC_SYS_OVERCLOCKED_STS) 1693cc72986SMark Brown dev_err(arizona->dev, "ASRC sync system overclocked\n"); 1703cc72986SMark Brown if (val[1] & ARIZONA_ASRC_SYNC_WARP_OVERCLOCKED_STS) 1713cc72986SMark Brown dev_err(arizona->dev, "ASRC sync WARP overclocked\n"); 1723cc72986SMark Brown if (val[1] & ARIZONA_ADSP2_1_OVERCLOCKED_STS) 1733cc72986SMark Brown dev_err(arizona->dev, "DSP1 overclocked\n"); 1743cc72986SMark Brown if (val[1] & ARIZONA_ISRC2_OVERCLOCKED_STS) 1753cc72986SMark Brown dev_err(arizona->dev, "ISRC2 overclocked\n"); 1763cc72986SMark Brown if (val[1] & ARIZONA_ISRC1_OVERCLOCKED_STS) 1773cc72986SMark Brown dev_err(arizona->dev, "ISRC1 overclocked\n"); 1783cc72986SMark Brown 1793cc72986SMark Brown return IRQ_HANDLED; 1803cc72986SMark Brown } 1813cc72986SMark Brown 1823cc72986SMark Brown static int arizona_wait_for_boot(struct arizona *arizona) 1833cc72986SMark Brown { 1843cc72986SMark Brown unsigned int reg; 1853cc72986SMark Brown int ret, i; 1863cc72986SMark Brown 1873cc72986SMark Brown /* 1883cc72986SMark Brown * We can't use an interrupt as we need to runtime resume to do so, 1893cc72986SMark Brown * we won't race with the interrupt handler as it'll be blocked on 1903cc72986SMark Brown * runtime resume. 1913cc72986SMark Brown */ 1923cc72986SMark Brown for (i = 0; i < 5; i++) { 1933cc72986SMark Brown msleep(1); 1943cc72986SMark Brown 1953cc72986SMark Brown ret = regmap_read(arizona->regmap, 1963cc72986SMark Brown ARIZONA_INTERRUPT_RAW_STATUS_5, ®); 1973cc72986SMark Brown if (ret != 0) { 1983cc72986SMark Brown dev_err(arizona->dev, "Failed to read boot state: %d\n", 1993cc72986SMark Brown ret); 200cfe775ceSMark Brown continue; 2013cc72986SMark Brown } 2023cc72986SMark Brown 2033cc72986SMark Brown if (reg & ARIZONA_BOOT_DONE_STS) 2043cc72986SMark Brown break; 2053cc72986SMark Brown } 2063cc72986SMark Brown 2073cc72986SMark Brown if (reg & ARIZONA_BOOT_DONE_STS) { 2083cc72986SMark Brown regmap_write(arizona->regmap, ARIZONA_INTERRUPT_STATUS_5, 2093cc72986SMark Brown ARIZONA_BOOT_DONE_STS); 2103cc72986SMark Brown } else { 2113cc72986SMark Brown dev_err(arizona->dev, "Device boot timed out: %x\n", reg); 2123cc72986SMark Brown return -ETIMEDOUT; 2133cc72986SMark Brown } 2143cc72986SMark Brown 2153cc72986SMark Brown pm_runtime_mark_last_busy(arizona->dev); 2163cc72986SMark Brown 2173cc72986SMark Brown return 0; 2183cc72986SMark Brown } 2193cc72986SMark Brown 2203cc72986SMark Brown #ifdef CONFIG_PM_RUNTIME 2213cc72986SMark Brown static int arizona_runtime_resume(struct device *dev) 2223cc72986SMark Brown { 2233cc72986SMark Brown struct arizona *arizona = dev_get_drvdata(dev); 2243cc72986SMark Brown int ret; 2253cc72986SMark Brown 226508c8299SMark Brown dev_dbg(arizona->dev, "Leaving AoD mode\n"); 227508c8299SMark Brown 22859db9691SMark Brown ret = regulator_enable(arizona->dcvdd); 22959db9691SMark Brown if (ret != 0) { 23059db9691SMark Brown dev_err(arizona->dev, "Failed to enable DCVDD: %d\n", ret); 23159db9691SMark Brown return ret; 23259db9691SMark Brown } 2333cc72986SMark Brown 2343cc72986SMark Brown regcache_cache_only(arizona->regmap, false); 2353cc72986SMark Brown 2363cc72986SMark Brown ret = arizona_wait_for_boot(arizona); 2375879f571SMark Brown if (ret != 0) { 2385879f571SMark Brown regulator_disable(arizona->dcvdd); 2393cc72986SMark Brown return ret; 2405879f571SMark Brown } 2413cc72986SMark Brown 2423cc72986SMark Brown regcache_sync(arizona->regmap); 2433cc72986SMark Brown 2443cc72986SMark Brown return 0; 2453cc72986SMark Brown } 2463cc72986SMark Brown 2473cc72986SMark Brown static int arizona_runtime_suspend(struct device *dev) 2483cc72986SMark Brown { 2493cc72986SMark Brown struct arizona *arizona = dev_get_drvdata(dev); 2503cc72986SMark Brown 251508c8299SMark Brown dev_dbg(arizona->dev, "Entering AoD mode\n"); 252508c8299SMark Brown 25359db9691SMark Brown regulator_disable(arizona->dcvdd); 2543cc72986SMark Brown regcache_cache_only(arizona->regmap, true); 2553cc72986SMark Brown regcache_mark_dirty(arizona->regmap); 2563cc72986SMark Brown 2573cc72986SMark Brown return 0; 2583cc72986SMark Brown } 2593cc72986SMark Brown #endif 2603cc72986SMark Brown 2613cc72986SMark Brown const struct dev_pm_ops arizona_pm_ops = { 2623cc72986SMark Brown SET_RUNTIME_PM_OPS(arizona_runtime_suspend, 2633cc72986SMark Brown arizona_runtime_resume, 2643cc72986SMark Brown NULL) 2653cc72986SMark Brown }; 2663cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_pm_ops); 2673cc72986SMark Brown 2683cc72986SMark Brown static struct mfd_cell early_devs[] = { 2693cc72986SMark Brown { .name = "arizona-ldo1" }, 2703cc72986SMark Brown }; 2713cc72986SMark Brown 2723cc72986SMark Brown static struct mfd_cell wm5102_devs[] = { 2733cc72986SMark Brown { .name = "arizona-extcon" }, 2743cc72986SMark Brown { .name = "arizona-gpio" }, 2753cc72986SMark Brown { .name = "arizona-micsupp" }, 2763cc72986SMark Brown { .name = "arizona-pwm" }, 2773cc72986SMark Brown { .name = "wm5102-codec" }, 2783cc72986SMark Brown }; 2793cc72986SMark Brown 280e102befeSMark Brown static struct mfd_cell wm5110_devs[] = { 281e102befeSMark Brown { .name = "arizona-extcon" }, 282e102befeSMark Brown { .name = "arizona-gpio" }, 283e102befeSMark Brown { .name = "arizona-micsupp" }, 284e102befeSMark Brown { .name = "arizona-pwm" }, 285e102befeSMark Brown { .name = "wm5110-codec" }, 286e102befeSMark Brown }; 287e102befeSMark Brown 288f791be49SBill Pemberton int arizona_dev_init(struct arizona *arizona) 2893cc72986SMark Brown { 2903cc72986SMark Brown struct device *dev = arizona->dev; 2913cc72986SMark Brown const char *type_name; 2923cc72986SMark Brown unsigned int reg, val; 2933cc72986SMark Brown int ret, i; 2943cc72986SMark Brown 2953cc72986SMark Brown dev_set_drvdata(arizona->dev, arizona); 2963cc72986SMark Brown mutex_init(&arizona->clk_lock); 2973cc72986SMark Brown 2983cc72986SMark Brown if (dev_get_platdata(arizona->dev)) 2993cc72986SMark Brown memcpy(&arizona->pdata, dev_get_platdata(arizona->dev), 3003cc72986SMark Brown sizeof(arizona->pdata)); 3013cc72986SMark Brown 3023cc72986SMark Brown regcache_cache_only(arizona->regmap, true); 3033cc72986SMark Brown 3043cc72986SMark Brown switch (arizona->type) { 3053cc72986SMark Brown case WM5102: 306e102befeSMark Brown case WM5110: 3073cc72986SMark Brown for (i = 0; i < ARRAY_SIZE(wm5102_core_supplies); i++) 3083cc72986SMark Brown arizona->core_supplies[i].supply 3093cc72986SMark Brown = wm5102_core_supplies[i]; 3103cc72986SMark Brown arizona->num_core_supplies = ARRAY_SIZE(wm5102_core_supplies); 3113cc72986SMark Brown break; 3123cc72986SMark Brown default: 3133cc72986SMark Brown dev_err(arizona->dev, "Unknown device type %d\n", 3143cc72986SMark Brown arizona->type); 3153cc72986SMark Brown return -EINVAL; 3163cc72986SMark Brown } 3173cc72986SMark Brown 3183cc72986SMark Brown ret = mfd_add_devices(arizona->dev, -1, early_devs, 3190848c94fSMark Brown ARRAY_SIZE(early_devs), NULL, 0, NULL); 3203cc72986SMark Brown if (ret != 0) { 3213cc72986SMark Brown dev_err(dev, "Failed to add early children: %d\n", ret); 3223cc72986SMark Brown return ret; 3233cc72986SMark Brown } 3243cc72986SMark Brown 3253cc72986SMark Brown ret = devm_regulator_bulk_get(dev, arizona->num_core_supplies, 3263cc72986SMark Brown arizona->core_supplies); 3273cc72986SMark Brown if (ret != 0) { 3283cc72986SMark Brown dev_err(dev, "Failed to request core supplies: %d\n", 3293cc72986SMark Brown ret); 3303cc72986SMark Brown goto err_early; 3313cc72986SMark Brown } 3323cc72986SMark Brown 33359db9691SMark Brown arizona->dcvdd = devm_regulator_get(arizona->dev, "DCVDD"); 33459db9691SMark Brown if (IS_ERR(arizona->dcvdd)) { 33559db9691SMark Brown ret = PTR_ERR(arizona->dcvdd); 33659db9691SMark Brown dev_err(dev, "Failed to request DCVDD: %d\n", ret); 33759db9691SMark Brown goto err_early; 33859db9691SMark Brown } 33959db9691SMark Brown 3403cc72986SMark Brown ret = regulator_bulk_enable(arizona->num_core_supplies, 3413cc72986SMark Brown arizona->core_supplies); 3423cc72986SMark Brown if (ret != 0) { 3433cc72986SMark Brown dev_err(dev, "Failed to enable core supplies: %d\n", 3443cc72986SMark Brown ret); 3453cc72986SMark Brown goto err_early; 3463cc72986SMark Brown } 3473cc72986SMark Brown 34859db9691SMark Brown ret = regulator_enable(arizona->dcvdd); 34959db9691SMark Brown if (ret != 0) { 35059db9691SMark Brown dev_err(dev, "Failed to enable DCVDD: %d\n", ret); 35159db9691SMark Brown goto err_enable; 35259db9691SMark Brown } 35359db9691SMark Brown 3543cc72986SMark Brown if (arizona->pdata.reset) { 3553cc72986SMark Brown /* Start out with /RESET low to put the chip into reset */ 3563cc72986SMark Brown ret = gpio_request_one(arizona->pdata.reset, 3573cc72986SMark Brown GPIOF_DIR_OUT | GPIOF_INIT_LOW, 3583cc72986SMark Brown "arizona /RESET"); 3593cc72986SMark Brown if (ret != 0) { 3603cc72986SMark Brown dev_err(dev, "Failed to request /RESET: %d\n", ret); 36159db9691SMark Brown goto err_dcvdd; 3623cc72986SMark Brown } 3633cc72986SMark Brown 3643cc72986SMark Brown gpio_set_value_cansleep(arizona->pdata.reset, 1); 3653cc72986SMark Brown } 3663cc72986SMark Brown 3673cc72986SMark Brown regcache_cache_only(arizona->regmap, false); 3683cc72986SMark Brown 3693cc72986SMark Brown ret = regmap_read(arizona->regmap, ARIZONA_SOFTWARE_RESET, ®); 3703cc72986SMark Brown if (ret != 0) { 3713cc72986SMark Brown dev_err(dev, "Failed to read ID register: %d\n", ret); 37259db9691SMark Brown goto err_reset; 3733cc72986SMark Brown } 3743cc72986SMark Brown 3753cc72986SMark Brown ret = regmap_read(arizona->regmap, ARIZONA_DEVICE_REVISION, 3763cc72986SMark Brown &arizona->rev); 3773cc72986SMark Brown if (ret != 0) { 3783cc72986SMark Brown dev_err(dev, "Failed to read revision register: %d\n", ret); 37959db9691SMark Brown goto err_reset; 3803cc72986SMark Brown } 3813cc72986SMark Brown arizona->rev &= ARIZONA_DEVICE_REVISION_MASK; 3823cc72986SMark Brown 3833cc72986SMark Brown switch (reg) { 384863df8d5SMark Brown #ifdef CONFIG_MFD_WM5102 3853cc72986SMark Brown case 0x5102: 3863cc72986SMark Brown type_name = "WM5102"; 3873cc72986SMark Brown if (arizona->type != WM5102) { 3883cc72986SMark Brown dev_err(arizona->dev, "WM5102 registered as %d\n", 3893cc72986SMark Brown arizona->type); 3903cc72986SMark Brown arizona->type = WM5102; 3913cc72986SMark Brown } 3923cc72986SMark Brown ret = wm5102_patch(arizona); 3933cc72986SMark Brown break; 394863df8d5SMark Brown #endif 395e102befeSMark Brown #ifdef CONFIG_MFD_WM5110 396e102befeSMark Brown case 0x5110: 397e102befeSMark Brown type_name = "WM5110"; 398e102befeSMark Brown if (arizona->type != WM5110) { 399e102befeSMark Brown dev_err(arizona->dev, "WM5110 registered as %d\n", 400e102befeSMark Brown arizona->type); 401e102befeSMark Brown arizona->type = WM5110; 402e102befeSMark Brown } 403e102befeSMark Brown ret = wm5110_patch(arizona); 404e102befeSMark Brown break; 405e102befeSMark Brown #endif 4063cc72986SMark Brown default: 4073cc72986SMark Brown dev_err(arizona->dev, "Unknown device ID %x\n", reg); 40859db9691SMark Brown goto err_reset; 4093cc72986SMark Brown } 4103cc72986SMark Brown 4113cc72986SMark Brown dev_info(dev, "%s revision %c\n", type_name, arizona->rev + 'A'); 4123cc72986SMark Brown 4133cc72986SMark Brown if (ret != 0) 4143cc72986SMark Brown dev_err(arizona->dev, "Failed to apply patch: %d\n", ret); 4153cc72986SMark Brown 4163cc72986SMark Brown /* If we have a /RESET GPIO we'll already be reset */ 4173cc72986SMark Brown if (!arizona->pdata.reset) { 4183cc72986SMark Brown ret = regmap_write(arizona->regmap, ARIZONA_SOFTWARE_RESET, 0); 4193cc72986SMark Brown if (ret != 0) { 4203cc72986SMark Brown dev_err(dev, "Failed to reset device: %d\n", ret); 42159db9691SMark Brown goto err_reset; 4223cc72986SMark Brown } 4233cc72986SMark Brown } 4243cc72986SMark Brown 425af65a361SMark Brown ret = arizona_wait_for_boot(arizona); 426af65a361SMark Brown if (ret != 0) { 427af65a361SMark Brown dev_err(arizona->dev, "Device failed initial boot: %d\n", ret); 428af65a361SMark Brown goto err_reset; 429af65a361SMark Brown } 4303cc72986SMark Brown 4313cc72986SMark Brown for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) { 4323cc72986SMark Brown if (!arizona->pdata.gpio_defaults[i]) 4333cc72986SMark Brown continue; 4343cc72986SMark Brown 4353cc72986SMark Brown regmap_write(arizona->regmap, ARIZONA_GPIO1_CTRL + i, 4363cc72986SMark Brown arizona->pdata.gpio_defaults[i]); 4373cc72986SMark Brown } 4383cc72986SMark Brown 4393cc72986SMark Brown pm_runtime_set_autosuspend_delay(arizona->dev, 100); 4403cc72986SMark Brown pm_runtime_use_autosuspend(arizona->dev); 4413cc72986SMark Brown pm_runtime_enable(arizona->dev); 4423cc72986SMark Brown 4433cc72986SMark Brown /* Chip default */ 4443cc72986SMark Brown if (!arizona->pdata.clk32k_src) 4453cc72986SMark Brown arizona->pdata.clk32k_src = ARIZONA_32KZ_MCLK2; 4463cc72986SMark Brown 4473cc72986SMark Brown switch (arizona->pdata.clk32k_src) { 4483cc72986SMark Brown case ARIZONA_32KZ_MCLK1: 4493cc72986SMark Brown case ARIZONA_32KZ_MCLK2: 4503cc72986SMark Brown regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, 4513cc72986SMark Brown ARIZONA_CLK_32K_SRC_MASK, 4523cc72986SMark Brown arizona->pdata.clk32k_src - 1); 4533cc72986SMark Brown break; 4543cc72986SMark Brown case ARIZONA_32KZ_NONE: 4553cc72986SMark Brown regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, 4563cc72986SMark Brown ARIZONA_CLK_32K_SRC_MASK, 2); 4573cc72986SMark Brown break; 4583cc72986SMark Brown default: 4593cc72986SMark Brown dev_err(arizona->dev, "Invalid 32kHz clock source: %d\n", 4603cc72986SMark Brown arizona->pdata.clk32k_src); 4613cc72986SMark Brown ret = -EINVAL; 46259db9691SMark Brown goto err_reset; 4633cc72986SMark Brown } 4643cc72986SMark Brown 4653cc72986SMark Brown for (i = 0; i < ARIZONA_MAX_INPUT; i++) { 4663cc72986SMark Brown /* Default for both is 0 so noop with defaults */ 4673cc72986SMark Brown val = arizona->pdata.dmic_ref[i] 4683cc72986SMark Brown << ARIZONA_IN1_DMIC_SUP_SHIFT; 4693cc72986SMark Brown val |= arizona->pdata.inmode[i] << ARIZONA_IN1_MODE_SHIFT; 4703cc72986SMark Brown 4713cc72986SMark Brown regmap_update_bits(arizona->regmap, 4723cc72986SMark Brown ARIZONA_IN1L_CONTROL + (i * 8), 4733cc72986SMark Brown ARIZONA_IN1_DMIC_SUP_MASK | 4743cc72986SMark Brown ARIZONA_IN1_MODE_MASK, val); 4753cc72986SMark Brown } 4763cc72986SMark Brown 4773cc72986SMark Brown for (i = 0; i < ARIZONA_MAX_OUTPUT; i++) { 4783cc72986SMark Brown /* Default is 0 so noop with defaults */ 4793cc72986SMark Brown if (arizona->pdata.out_mono[i]) 4803cc72986SMark Brown val = ARIZONA_OUT1_MONO; 4813cc72986SMark Brown else 4823cc72986SMark Brown val = 0; 4833cc72986SMark Brown 4843cc72986SMark Brown regmap_update_bits(arizona->regmap, 4853cc72986SMark Brown ARIZONA_OUTPUT_PATH_CONFIG_1L + (i * 8), 4863cc72986SMark Brown ARIZONA_OUT1_MONO, val); 4873cc72986SMark Brown } 4883cc72986SMark Brown 4893cc72986SMark Brown for (i = 0; i < ARIZONA_MAX_PDM_SPK; i++) { 4903cc72986SMark Brown if (arizona->pdata.spk_mute[i]) 4913cc72986SMark Brown regmap_update_bits(arizona->regmap, 4922a51da04SMark Brown ARIZONA_PDM_SPK1_CTRL_1 + (i * 2), 4933cc72986SMark Brown ARIZONA_SPK1_MUTE_ENDIAN_MASK | 4943cc72986SMark Brown ARIZONA_SPK1_MUTE_SEQ1_MASK, 4953cc72986SMark Brown arizona->pdata.spk_mute[i]); 4963cc72986SMark Brown 4973cc72986SMark Brown if (arizona->pdata.spk_fmt[i]) 4983cc72986SMark Brown regmap_update_bits(arizona->regmap, 4992a51da04SMark Brown ARIZONA_PDM_SPK1_CTRL_2 + (i * 2), 5003cc72986SMark Brown ARIZONA_SPK1_FMT_MASK, 5013cc72986SMark Brown arizona->pdata.spk_fmt[i]); 5023cc72986SMark Brown } 5033cc72986SMark Brown 5043cc72986SMark Brown /* Set up for interrupts */ 5053cc72986SMark Brown ret = arizona_irq_init(arizona); 5063cc72986SMark Brown if (ret != 0) 50759db9691SMark Brown goto err_reset; 5083cc72986SMark Brown 5093cc72986SMark Brown arizona_request_irq(arizona, ARIZONA_IRQ_CLKGEN_ERR, "CLKGEN error", 5103cc72986SMark Brown arizona_clkgen_err, arizona); 5113cc72986SMark Brown arizona_request_irq(arizona, ARIZONA_IRQ_OVERCLOCKED, "Overclocked", 5123cc72986SMark Brown arizona_overclocked, arizona); 5133cc72986SMark Brown arizona_request_irq(arizona, ARIZONA_IRQ_UNDERCLOCKED, "Underclocked", 5143cc72986SMark Brown arizona_underclocked, arizona); 5153cc72986SMark Brown 5163cc72986SMark Brown switch (arizona->type) { 5173cc72986SMark Brown case WM5102: 5183cc72986SMark Brown ret = mfd_add_devices(arizona->dev, -1, wm5102_devs, 5190848c94fSMark Brown ARRAY_SIZE(wm5102_devs), NULL, 0, NULL); 5203cc72986SMark Brown break; 521e102befeSMark Brown case WM5110: 522e102befeSMark Brown ret = mfd_add_devices(arizona->dev, -1, wm5110_devs, 5230848c94fSMark Brown ARRAY_SIZE(wm5102_devs), NULL, 0, NULL); 524e102befeSMark Brown break; 5253cc72986SMark Brown } 5263cc72986SMark Brown 5273cc72986SMark Brown if (ret != 0) { 5283cc72986SMark Brown dev_err(arizona->dev, "Failed to add subdevices: %d\n", ret); 5293cc72986SMark Brown goto err_irq; 5303cc72986SMark Brown } 5313cc72986SMark Brown 53259db9691SMark Brown #ifdef CONFIG_PM_RUNTIME 53359db9691SMark Brown regulator_disable(arizona->dcvdd); 53459db9691SMark Brown #endif 53559db9691SMark Brown 5363cc72986SMark Brown return 0; 5373cc72986SMark Brown 5383cc72986SMark Brown err_irq: 5393cc72986SMark Brown arizona_irq_exit(arizona); 5403cc72986SMark Brown err_reset: 5413cc72986SMark Brown if (arizona->pdata.reset) { 5423cc72986SMark Brown gpio_set_value_cansleep(arizona->pdata.reset, 1); 5433cc72986SMark Brown gpio_free(arizona->pdata.reset); 5443cc72986SMark Brown } 54559db9691SMark Brown err_dcvdd: 54659db9691SMark Brown regulator_disable(arizona->dcvdd); 5473cc72986SMark Brown err_enable: 5483a36a0dbSMark Brown regulator_bulk_disable(arizona->num_core_supplies, 5493cc72986SMark Brown arizona->core_supplies); 5503cc72986SMark Brown err_early: 5513cc72986SMark Brown mfd_remove_devices(dev); 5523cc72986SMark Brown return ret; 5533cc72986SMark Brown } 5543cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_dev_init); 5553cc72986SMark Brown 556*4740f73fSBill Pemberton int arizona_dev_exit(struct arizona *arizona) 5573cc72986SMark Brown { 5583cc72986SMark Brown mfd_remove_devices(arizona->dev); 5593cc72986SMark Brown arizona_free_irq(arizona, ARIZONA_IRQ_UNDERCLOCKED, arizona); 5603cc72986SMark Brown arizona_free_irq(arizona, ARIZONA_IRQ_OVERCLOCKED, arizona); 5613cc72986SMark Brown arizona_free_irq(arizona, ARIZONA_IRQ_CLKGEN_ERR, arizona); 5623cc72986SMark Brown pm_runtime_disable(arizona->dev); 5633cc72986SMark Brown arizona_irq_exit(arizona); 5643cc72986SMark Brown return 0; 5653cc72986SMark Brown } 5663cc72986SMark Brown EXPORT_SYMBOL_GPL(arizona_dev_exit); 567