16387f866SBrian Austin /* 26387f866SBrian Austin * cs35l35.c -- CS35L35 ALSA SoC audio driver 36387f866SBrian Austin * 46387f866SBrian Austin * Copyright 2017 Cirrus Logic, Inc. 56387f866SBrian Austin * 66387f866SBrian Austin * Author: Brian Austin <brian.austin@cirrus.com> 76387f866SBrian Austin * 86387f866SBrian Austin * This program is free software; you can redistribute it and/or modify 96387f866SBrian Austin * it under the terms of the GNU General Public License version 2 as 106387f866SBrian Austin * published by the Free Software Foundation. 116387f866SBrian Austin * 126387f866SBrian Austin */ 136387f866SBrian Austin 146387f866SBrian Austin #include <linux/module.h> 156387f866SBrian Austin #include <linux/moduleparam.h> 166387f866SBrian Austin #include <linux/version.h> 176387f866SBrian Austin #include <linux/kernel.h> 186387f866SBrian Austin #include <linux/init.h> 196387f866SBrian Austin #include <linux/delay.h> 206387f866SBrian Austin #include <linux/i2c.h> 216387f866SBrian Austin #include <linux/slab.h> 226387f866SBrian Austin #include <linux/platform_device.h> 236387f866SBrian Austin #include <linux/regulator/consumer.h> 246387f866SBrian Austin #include <linux/gpio/consumer.h> 256387f866SBrian Austin #include <linux/of_device.h> 266387f866SBrian Austin #include <linux/of_gpio.h> 276387f866SBrian Austin #include <linux/regmap.h> 286387f866SBrian Austin #include <sound/core.h> 296387f866SBrian Austin #include <sound/pcm.h> 306387f866SBrian Austin #include <sound/pcm_params.h> 316387f866SBrian Austin #include <sound/soc.h> 326387f866SBrian Austin #include <sound/soc-dapm.h> 336387f866SBrian Austin #include <linux/gpio.h> 346387f866SBrian Austin #include <sound/initval.h> 356387f866SBrian Austin #include <sound/tlv.h> 366387f866SBrian Austin #include <sound/cs35l35.h> 376387f866SBrian Austin #include <linux/of_irq.h> 386387f866SBrian Austin #include <linux/completion.h> 396387f866SBrian Austin 406387f866SBrian Austin #include "cs35l35.h" 416387f866SBrian Austin 426387f866SBrian Austin /* 436387f866SBrian Austin * Some fields take zero as a valid value so use a high bit flag that won't 446387f866SBrian Austin * get written to the device to mark those. 456387f866SBrian Austin */ 466387f866SBrian Austin #define CS35L35_VALID_PDATA 0x80000000 476387f866SBrian Austin 486387f866SBrian Austin static const struct reg_default cs35l35_reg[] = { 496387f866SBrian Austin {CS35L35_PWRCTL1, 0x01}, 506387f866SBrian Austin {CS35L35_PWRCTL2, 0x11}, 516387f866SBrian Austin {CS35L35_PWRCTL3, 0x00}, 526387f866SBrian Austin {CS35L35_CLK_CTL1, 0x04}, 53fbeea237SCharles Keepax {CS35L35_CLK_CTL2, 0x12}, 546387f866SBrian Austin {CS35L35_CLK_CTL3, 0xCF}, 556387f866SBrian Austin {CS35L35_SP_FMT_CTL1, 0x20}, 566387f866SBrian Austin {CS35L35_SP_FMT_CTL2, 0x00}, 576387f866SBrian Austin {CS35L35_SP_FMT_CTL3, 0x02}, 586387f866SBrian Austin {CS35L35_MAG_COMP_CTL, 0x00}, 596387f866SBrian Austin {CS35L35_AMP_INP_DRV_CTL, 0x01}, 606387f866SBrian Austin {CS35L35_AMP_DIG_VOL_CTL, 0x12}, 616387f866SBrian Austin {CS35L35_AMP_DIG_VOL, 0x00}, 626387f866SBrian Austin {CS35L35_ADV_DIG_VOL, 0x00}, 636387f866SBrian Austin {CS35L35_PROTECT_CTL, 0x06}, 646387f866SBrian Austin {CS35L35_AMP_GAIN_AUD_CTL, 0x13}, 656387f866SBrian Austin {CS35L35_AMP_GAIN_PDM_CTL, 0x00}, 666387f866SBrian Austin {CS35L35_AMP_GAIN_ADV_CTL, 0x00}, 676387f866SBrian Austin {CS35L35_GPI_CTL, 0x00}, 686387f866SBrian Austin {CS35L35_BST_CVTR_V_CTL, 0x00}, 696387f866SBrian Austin {CS35L35_BST_PEAK_I, 0x07}, 706387f866SBrian Austin {CS35L35_BST_RAMP_CTL, 0x85}, 716387f866SBrian Austin {CS35L35_BST_CONV_COEF_1, 0x24}, 726387f866SBrian Austin {CS35L35_BST_CONV_COEF_2, 0x24}, 73fbeea237SCharles Keepax {CS35L35_BST_CONV_SLOPE_COMP, 0x4E}, 746387f866SBrian Austin {CS35L35_BST_CONV_SW_FREQ, 0x04}, 756387f866SBrian Austin {CS35L35_CLASS_H_CTL, 0x0B}, 766387f866SBrian Austin {CS35L35_CLASS_H_HEADRM_CTL, 0x0B}, 776387f866SBrian Austin {CS35L35_CLASS_H_RELEASE_RATE, 0x08}, 786387f866SBrian Austin {CS35L35_CLASS_H_FET_DRIVE_CTL, 0x41}, 796387f866SBrian Austin {CS35L35_CLASS_H_VP_CTL, 0xC5}, 806387f866SBrian Austin {CS35L35_VPBR_CTL, 0x0A}, 81fbeea237SCharles Keepax {CS35L35_VPBR_VOL_CTL, 0x90}, 826387f866SBrian Austin {CS35L35_VPBR_TIMING_CTL, 0x6A}, 83fbeea237SCharles Keepax {CS35L35_VPBR_MODE_VOL_CTL, 0x00}, 846387f866SBrian Austin {CS35L35_SPKR_MON_CTL, 0xC0}, 856387f866SBrian Austin {CS35L35_IMON_SCALE_CTL, 0x30}, 866387f866SBrian Austin {CS35L35_AUDIN_RXLOC_CTL, 0x00}, 876387f866SBrian Austin {CS35L35_ADVIN_RXLOC_CTL, 0x80}, 886387f866SBrian Austin {CS35L35_VMON_TXLOC_CTL, 0x00}, 896387f866SBrian Austin {CS35L35_IMON_TXLOC_CTL, 0x80}, 906387f866SBrian Austin {CS35L35_VPMON_TXLOC_CTL, 0x04}, 916387f866SBrian Austin {CS35L35_VBSTMON_TXLOC_CTL, 0x84}, 926387f866SBrian Austin {CS35L35_VPBR_STATUS_TXLOC_CTL, 0x04}, 936387f866SBrian Austin {CS35L35_ZERO_FILL_LOC_CTL, 0x00}, 946387f866SBrian Austin {CS35L35_AUDIN_DEPTH_CTL, 0x0F}, 956387f866SBrian Austin {CS35L35_SPKMON_DEPTH_CTL, 0x0F}, 966387f866SBrian Austin {CS35L35_SUPMON_DEPTH_CTL, 0x0F}, 976387f866SBrian Austin {CS35L35_ZEROFILL_DEPTH_CTL, 0x00}, 986387f866SBrian Austin {CS35L35_MULT_DEV_SYNCH1, 0x02}, 996387f866SBrian Austin {CS35L35_MULT_DEV_SYNCH2, 0x80}, 1006387f866SBrian Austin {CS35L35_PROT_RELEASE_CTL, 0x00}, 1016387f866SBrian Austin {CS35L35_DIAG_MODE_REG_LOCK, 0x00}, 1026387f866SBrian Austin {CS35L35_DIAG_MODE_CTL_1, 0x40}, 1036387f866SBrian Austin {CS35L35_DIAG_MODE_CTL_2, 0x00}, 1046387f866SBrian Austin {CS35L35_INT_MASK_1, 0xFF}, 1056387f866SBrian Austin {CS35L35_INT_MASK_2, 0xFF}, 1066387f866SBrian Austin {CS35L35_INT_MASK_3, 0xFF}, 1076387f866SBrian Austin {CS35L35_INT_MASK_4, 0xFF}, 1086387f866SBrian Austin 1096387f866SBrian Austin }; 1106387f866SBrian Austin 1116387f866SBrian Austin static bool cs35l35_volatile_register(struct device *dev, unsigned int reg) 1126387f866SBrian Austin { 1136387f866SBrian Austin switch (reg) { 1146387f866SBrian Austin case CS35L35_INT_STATUS_1: 1156387f866SBrian Austin case CS35L35_INT_STATUS_2: 1166387f866SBrian Austin case CS35L35_INT_STATUS_3: 1176387f866SBrian Austin case CS35L35_INT_STATUS_4: 1186387f866SBrian Austin case CS35L35_PLL_STATUS: 1196387f866SBrian Austin case CS35L35_OTP_TRIM_STATUS: 1206387f866SBrian Austin return true; 1216387f866SBrian Austin default: 1226387f866SBrian Austin return false; 1236387f866SBrian Austin } 1246387f866SBrian Austin } 1256387f866SBrian Austin 1266387f866SBrian Austin static bool cs35l35_readable_register(struct device *dev, unsigned int reg) 1276387f866SBrian Austin { 1286387f866SBrian Austin switch (reg) { 1296387f866SBrian Austin case CS35L35_DEVID_AB ... CS35L35_PWRCTL3: 1306387f866SBrian Austin case CS35L35_CLK_CTL1 ... CS35L35_SP_FMT_CTL3: 1316387f866SBrian Austin case CS35L35_MAG_COMP_CTL ... CS35L35_AMP_GAIN_AUD_CTL: 1326387f866SBrian Austin case CS35L35_AMP_GAIN_PDM_CTL ... CS35L35_BST_PEAK_I: 1336387f866SBrian Austin case CS35L35_BST_RAMP_CTL ... CS35L35_BST_CONV_SW_FREQ: 1346387f866SBrian Austin case CS35L35_CLASS_H_CTL ... CS35L35_CLASS_H_VP_CTL: 1356387f866SBrian Austin case CS35L35_CLASS_H_STATUS: 1366387f866SBrian Austin case CS35L35_VPBR_CTL ... CS35L35_VPBR_MODE_VOL_CTL: 1376387f866SBrian Austin case CS35L35_VPBR_ATTEN_STATUS: 1386387f866SBrian Austin case CS35L35_SPKR_MON_CTL: 1396387f866SBrian Austin case CS35L35_IMON_SCALE_CTL ... CS35L35_ZEROFILL_DEPTH_CTL: 1406387f866SBrian Austin case CS35L35_MULT_DEV_SYNCH1 ... CS35L35_PROT_RELEASE_CTL: 1416387f866SBrian Austin case CS35L35_DIAG_MODE_REG_LOCK ... CS35L35_DIAG_MODE_CTL_2: 1426387f866SBrian Austin case CS35L35_INT_MASK_1 ... CS35L35_PLL_STATUS: 1436387f866SBrian Austin case CS35L35_OTP_TRIM_STATUS: 1446387f866SBrian Austin return true; 1456387f866SBrian Austin default: 1466387f866SBrian Austin return false; 1476387f866SBrian Austin } 1486387f866SBrian Austin } 1496387f866SBrian Austin 1506387f866SBrian Austin static bool cs35l35_precious_register(struct device *dev, unsigned int reg) 1516387f866SBrian Austin { 1526387f866SBrian Austin switch (reg) { 1536387f866SBrian Austin case CS35L35_INT_STATUS_1: 1546387f866SBrian Austin case CS35L35_INT_STATUS_2: 1556387f866SBrian Austin case CS35L35_INT_STATUS_3: 1566387f866SBrian Austin case CS35L35_INT_STATUS_4: 1576387f866SBrian Austin case CS35L35_PLL_STATUS: 1586387f866SBrian Austin case CS35L35_OTP_TRIM_STATUS: 1596387f866SBrian Austin return true; 1606387f866SBrian Austin default: 1616387f866SBrian Austin return false; 1626387f866SBrian Austin } 1636387f866SBrian Austin } 1646387f866SBrian Austin 16577b329d1SCharles Keepax static int cs35l35_wait_for_pdn(struct cs35l35_private *cs35l35) 16677b329d1SCharles Keepax { 16777b329d1SCharles Keepax int ret; 16877b329d1SCharles Keepax 16977b329d1SCharles Keepax if (cs35l35->pdata.ext_bst) { 17077b329d1SCharles Keepax usleep_range(5000, 5500); 17177b329d1SCharles Keepax return 0; 17277b329d1SCharles Keepax } 17377b329d1SCharles Keepax 17477b329d1SCharles Keepax reinit_completion(&cs35l35->pdn_done); 17577b329d1SCharles Keepax 17677b329d1SCharles Keepax ret = wait_for_completion_timeout(&cs35l35->pdn_done, 17777b329d1SCharles Keepax msecs_to_jiffies(100)); 17877b329d1SCharles Keepax if (ret == 0) { 17977b329d1SCharles Keepax dev_err(cs35l35->dev, "PDN_DONE did not complete\n"); 18077b329d1SCharles Keepax return -ETIMEDOUT; 18177b329d1SCharles Keepax } 18277b329d1SCharles Keepax 18377b329d1SCharles Keepax return 0; 18477b329d1SCharles Keepax } 18577b329d1SCharles Keepax 1866387f866SBrian Austin static int cs35l35_sdin_event(struct snd_soc_dapm_widget *w, 1876387f866SBrian Austin struct snd_kcontrol *kcontrol, int event) 1886387f866SBrian Austin { 1896387f866SBrian Austin struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); 1906387f866SBrian Austin struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec); 1916387f866SBrian Austin int ret = 0; 1926387f866SBrian Austin 1936387f866SBrian Austin switch (event) { 1946387f866SBrian Austin case SND_SOC_DAPM_PRE_PMU: 1956387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL1, 1966387f866SBrian Austin CS35L35_MCLK_DIS_MASK, 1976387f866SBrian Austin 0 << CS35L35_MCLK_DIS_SHIFT); 1986387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL1, 1996387f866SBrian Austin CS35L35_DISCHG_FILT_MASK, 2006387f866SBrian Austin 0 << CS35L35_DISCHG_FILT_SHIFT); 2016387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL1, 2026387f866SBrian Austin CS35L35_PDN_ALL_MASK, 0); 2036387f866SBrian Austin break; 2046387f866SBrian Austin case SND_SOC_DAPM_POST_PMD: 2056387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL1, 2066387f866SBrian Austin CS35L35_DISCHG_FILT_MASK, 2076387f866SBrian Austin 1 << CS35L35_DISCHG_FILT_SHIFT); 2086387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL1, 2096387f866SBrian Austin CS35L35_PDN_ALL_MASK, 1); 2106387f866SBrian Austin 2112c84afb5SCharles Keepax /* Already muted, so disable volume ramp for faster shutdown */ 2122c84afb5SCharles Keepax regmap_update_bits(cs35l35->regmap, CS35L35_AMP_DIG_VOL_CTL, 2132c84afb5SCharles Keepax CS35L35_AMP_DIGSFT_MASK, 0); 2142c84afb5SCharles Keepax 21577b329d1SCharles Keepax ret = cs35l35_wait_for_pdn(cs35l35); 2166387f866SBrian Austin 2176387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL1, 2186387f866SBrian Austin CS35L35_MCLK_DIS_MASK, 2196387f866SBrian Austin 1 << CS35L35_MCLK_DIS_SHIFT); 2202c84afb5SCharles Keepax 2212c84afb5SCharles Keepax regmap_update_bits(cs35l35->regmap, CS35L35_AMP_DIG_VOL_CTL, 2222c84afb5SCharles Keepax CS35L35_AMP_DIGSFT_MASK, 2232c84afb5SCharles Keepax 1 << CS35L35_AMP_DIGSFT_SHIFT); 2246387f866SBrian Austin break; 2256387f866SBrian Austin default: 2266387f866SBrian Austin dev_err(codec->dev, "Invalid event = 0x%x\n", event); 2276387f866SBrian Austin ret = -EINVAL; 2286387f866SBrian Austin } 2296387f866SBrian Austin return ret; 2306387f866SBrian Austin } 2316387f866SBrian Austin 2326387f866SBrian Austin static int cs35l35_main_amp_event(struct snd_soc_dapm_widget *w, 2336387f866SBrian Austin struct snd_kcontrol *kcontrol, int event) 2346387f866SBrian Austin { 2356387f866SBrian Austin struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); 2366387f866SBrian Austin struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec); 2376387f866SBrian Austin unsigned int reg[4]; 2386387f866SBrian Austin int i; 2396387f866SBrian Austin 2406387f866SBrian Austin switch (event) { 2416387f866SBrian Austin case SND_SOC_DAPM_PRE_PMU: 2426387f866SBrian Austin if (cs35l35->pdata.bst_pdn_fet_on) 2436387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, 2446387f866SBrian Austin CS35L35_PDN_BST_MASK, 2456387f866SBrian Austin 0 << CS35L35_PDN_BST_FETON_SHIFT); 2466387f866SBrian Austin else 2476387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, 2486387f866SBrian Austin CS35L35_PDN_BST_MASK, 2496387f866SBrian Austin 0 << CS35L35_PDN_BST_FETOFF_SHIFT); 2506387f866SBrian Austin break; 2516387f866SBrian Austin case SND_SOC_DAPM_POST_PMU: 2526387f866SBrian Austin usleep_range(5000, 5100); 2536387f866SBrian Austin /* If in PDM mode we must use VP for Voltage control */ 2546387f866SBrian Austin if (cs35l35->pdm_mode) 2556387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 2566387f866SBrian Austin CS35L35_BST_CVTR_V_CTL, 2576387f866SBrian Austin CS35L35_BST_CTL_MASK, 2586387f866SBrian Austin 0 << CS35L35_BST_CTL_SHIFT); 2596387f866SBrian Austin 2606387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PROTECT_CTL, 2616387f866SBrian Austin CS35L35_AMP_MUTE_MASK, 0); 2626387f866SBrian Austin 2636387f866SBrian Austin for (i = 0; i < 2; i++) 2646387f866SBrian Austin regmap_bulk_read(cs35l35->regmap, CS35L35_INT_STATUS_1, 2656387f866SBrian Austin ®, ARRAY_SIZE(reg)); 2666387f866SBrian Austin 2676387f866SBrian Austin break; 2686387f866SBrian Austin case SND_SOC_DAPM_PRE_PMD: 2696387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PROTECT_CTL, 2706387f866SBrian Austin CS35L35_AMP_MUTE_MASK, 2716387f866SBrian Austin 1 << CS35L35_AMP_MUTE_SHIFT); 2726387f866SBrian Austin if (cs35l35->pdata.bst_pdn_fet_on) 2736387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, 2746387f866SBrian Austin CS35L35_PDN_BST_MASK, 2756387f866SBrian Austin 1 << CS35L35_PDN_BST_FETON_SHIFT); 2766387f866SBrian Austin else 2776387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, 2786387f866SBrian Austin CS35L35_PDN_BST_MASK, 2796387f866SBrian Austin 1 << CS35L35_PDN_BST_FETOFF_SHIFT); 2806387f866SBrian Austin break; 2816387f866SBrian Austin case SND_SOC_DAPM_POST_PMD: 2826387f866SBrian Austin usleep_range(5000, 5100); 2836387f866SBrian Austin /* 2846387f866SBrian Austin * If PDM mode we should switch back to pdata value 2856387f866SBrian Austin * for Voltage control when we go down 2866387f866SBrian Austin */ 2876387f866SBrian Austin if (cs35l35->pdm_mode) 2886387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 2896387f866SBrian Austin CS35L35_BST_CVTR_V_CTL, 2906387f866SBrian Austin CS35L35_BST_CTL_MASK, 2916387f866SBrian Austin cs35l35->pdata.bst_vctl 2926387f866SBrian Austin << CS35L35_BST_CTL_SHIFT); 2936387f866SBrian Austin 2946387f866SBrian Austin break; 2956387f866SBrian Austin default: 2966387f866SBrian Austin dev_err(codec->dev, "Invalid event = 0x%x\n", event); 2976387f866SBrian Austin } 2986387f866SBrian Austin return 0; 2996387f866SBrian Austin } 3006387f866SBrian Austin 3016387f866SBrian Austin static DECLARE_TLV_DB_SCALE(amp_gain_tlv, 0, 1, 1); 3026387f866SBrian Austin static DECLARE_TLV_DB_SCALE(dig_vol_tlv, -10200, 50, 0); 3036387f866SBrian Austin 3046387f866SBrian Austin static const struct snd_kcontrol_new cs35l35_aud_controls[] = { 3056387f866SBrian Austin SOC_SINGLE_SX_TLV("Digital Audio Volume", CS35L35_AMP_DIG_VOL, 3066387f866SBrian Austin 0, 0x34, 0xE4, dig_vol_tlv), 3076387f866SBrian Austin SOC_SINGLE_TLV("Analog Audio Volume", CS35L35_AMP_GAIN_AUD_CTL, 0, 19, 0, 3086387f866SBrian Austin amp_gain_tlv), 3096387f866SBrian Austin SOC_SINGLE_TLV("PDM Volume", CS35L35_AMP_GAIN_PDM_CTL, 0, 19, 0, 3106387f866SBrian Austin amp_gain_tlv), 3116387f866SBrian Austin }; 3126387f866SBrian Austin 3136387f866SBrian Austin static const struct snd_kcontrol_new cs35l35_adv_controls[] = { 3146387f866SBrian Austin SOC_SINGLE_SX_TLV("Digital Advisory Volume", CS35L35_ADV_DIG_VOL, 3156387f866SBrian Austin 0, 0x34, 0xE4, dig_vol_tlv), 3166387f866SBrian Austin SOC_SINGLE_TLV("Analog Advisory Volume", CS35L35_AMP_GAIN_ADV_CTL, 0, 19, 0, 3176387f866SBrian Austin amp_gain_tlv), 3186387f866SBrian Austin }; 3196387f866SBrian Austin 3206387f866SBrian Austin static const struct snd_soc_dapm_widget cs35l35_dapm_widgets[] = { 3216387f866SBrian Austin SND_SOC_DAPM_AIF_IN_E("SDIN", NULL, 0, CS35L35_PWRCTL3, 1, 1, 3226387f866SBrian Austin cs35l35_sdin_event, SND_SOC_DAPM_PRE_PMU | 3236387f866SBrian Austin SND_SOC_DAPM_POST_PMD), 3246387f866SBrian Austin SND_SOC_DAPM_AIF_OUT("SDOUT", NULL, 0, CS35L35_PWRCTL3, 2, 1), 3256387f866SBrian Austin 3266387f866SBrian Austin SND_SOC_DAPM_OUTPUT("SPK"), 3276387f866SBrian Austin 3286387f866SBrian Austin SND_SOC_DAPM_INPUT("VP"), 3296387f866SBrian Austin SND_SOC_DAPM_INPUT("VBST"), 3306387f866SBrian Austin SND_SOC_DAPM_INPUT("ISENSE"), 3316387f866SBrian Austin SND_SOC_DAPM_INPUT("VSENSE"), 3326387f866SBrian Austin 3336387f866SBrian Austin SND_SOC_DAPM_ADC("VMON ADC", NULL, CS35L35_PWRCTL2, 7, 1), 3346387f866SBrian Austin SND_SOC_DAPM_ADC("IMON ADC", NULL, CS35L35_PWRCTL2, 6, 1), 3356387f866SBrian Austin SND_SOC_DAPM_ADC("VPMON ADC", NULL, CS35L35_PWRCTL3, 3, 1), 3366387f866SBrian Austin SND_SOC_DAPM_ADC("VBSTMON ADC", NULL, CS35L35_PWRCTL3, 4, 1), 3376387f866SBrian Austin SND_SOC_DAPM_ADC("CLASS H", NULL, CS35L35_PWRCTL2, 5, 1), 3386387f866SBrian Austin 3396387f866SBrian Austin SND_SOC_DAPM_OUT_DRV_E("Main AMP", CS35L35_PWRCTL2, 0, 1, NULL, 0, 3406387f866SBrian Austin cs35l35_main_amp_event, SND_SOC_DAPM_PRE_PMU | 3416387f866SBrian Austin SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU | 3426387f866SBrian Austin SND_SOC_DAPM_PRE_PMD), 3436387f866SBrian Austin }; 3446387f866SBrian Austin 3456387f866SBrian Austin static const struct snd_soc_dapm_route cs35l35_audio_map[] = { 3466387f866SBrian Austin {"VPMON ADC", NULL, "VP"}, 3476387f866SBrian Austin {"VBSTMON ADC", NULL, "VBST"}, 3486387f866SBrian Austin {"IMON ADC", NULL, "ISENSE"}, 3496387f866SBrian Austin {"VMON ADC", NULL, "VSENSE"}, 3506387f866SBrian Austin {"SDOUT", NULL, "IMON ADC"}, 3516387f866SBrian Austin {"SDOUT", NULL, "VMON ADC"}, 3526387f866SBrian Austin {"SDOUT", NULL, "VBSTMON ADC"}, 3536387f866SBrian Austin {"SDOUT", NULL, "VPMON ADC"}, 3546387f866SBrian Austin {"AMP Capture", NULL, "SDOUT"}, 3556387f866SBrian Austin 3566387f866SBrian Austin {"SDIN", NULL, "AMP Playback"}, 3576387f866SBrian Austin {"CLASS H", NULL, "SDIN"}, 3586387f866SBrian Austin {"Main AMP", NULL, "CLASS H"}, 3596387f866SBrian Austin {"SPK", NULL, "Main AMP"}, 3606387f866SBrian Austin }; 3616387f866SBrian Austin 3626387f866SBrian Austin static int cs35l35_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) 3636387f866SBrian Austin { 3646387f866SBrian Austin struct snd_soc_codec *codec = codec_dai->codec; 3656387f866SBrian Austin struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec); 3666387f866SBrian Austin 3676387f866SBrian Austin switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 3686387f866SBrian Austin case SND_SOC_DAIFMT_CBM_CFM: 3696387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL1, 3706387f866SBrian Austin CS35L35_MS_MASK, 1 << CS35L35_MS_SHIFT); 3716387f866SBrian Austin cs35l35->slave_mode = false; 3726387f866SBrian Austin break; 3736387f866SBrian Austin case SND_SOC_DAIFMT_CBS_CFS: 3746387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL1, 3756387f866SBrian Austin CS35L35_MS_MASK, 0 << CS35L35_MS_SHIFT); 3766387f866SBrian Austin cs35l35->slave_mode = true; 3776387f866SBrian Austin break; 3786387f866SBrian Austin default: 3796387f866SBrian Austin return -EINVAL; 3806387f866SBrian Austin } 3816387f866SBrian Austin 3826387f866SBrian Austin switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 3836387f866SBrian Austin case SND_SOC_DAIFMT_I2S: 3846387f866SBrian Austin cs35l35->i2s_mode = true; 3856387f866SBrian Austin cs35l35->pdm_mode = false; 3866387f866SBrian Austin break; 3876387f866SBrian Austin case SND_SOC_DAIFMT_PDM: 3886387f866SBrian Austin cs35l35->pdm_mode = true; 3896387f866SBrian Austin cs35l35->i2s_mode = false; 3906387f866SBrian Austin break; 3916387f866SBrian Austin default: 3926387f866SBrian Austin return -EINVAL; 3936387f866SBrian Austin } 3946387f866SBrian Austin 3956387f866SBrian Austin return 0; 3966387f866SBrian Austin } 3976387f866SBrian Austin 3986387f866SBrian Austin struct cs35l35_sysclk_config { 3996387f866SBrian Austin int sysclk; 4006387f866SBrian Austin int srate; 4016387f866SBrian Austin u8 clk_cfg; 4026387f866SBrian Austin }; 4036387f866SBrian Austin 4046387f866SBrian Austin static struct cs35l35_sysclk_config cs35l35_clk_ctl[] = { 4056387f866SBrian Austin 4066387f866SBrian Austin /* SYSCLK, Sample Rate, Serial Port Cfg */ 4076387f866SBrian Austin {5644800, 44100, 0x00}, 4086387f866SBrian Austin {5644800, 88200, 0x40}, 4096387f866SBrian Austin {6144000, 48000, 0x10}, 4106387f866SBrian Austin {6144000, 96000, 0x50}, 4116387f866SBrian Austin {11289600, 44100, 0x01}, 4126387f866SBrian Austin {11289600, 88200, 0x41}, 4136387f866SBrian Austin {11289600, 176400, 0x81}, 4146387f866SBrian Austin {12000000, 44100, 0x03}, 4156387f866SBrian Austin {12000000, 48000, 0x13}, 4166387f866SBrian Austin {12000000, 88200, 0x43}, 4176387f866SBrian Austin {12000000, 96000, 0x53}, 4186387f866SBrian Austin {12000000, 176400, 0x83}, 4196387f866SBrian Austin {12000000, 192000, 0x93}, 4206387f866SBrian Austin {12288000, 48000, 0x11}, 4216387f866SBrian Austin {12288000, 96000, 0x51}, 4226387f866SBrian Austin {12288000, 192000, 0x91}, 4236387f866SBrian Austin {13000000, 44100, 0x07}, 4246387f866SBrian Austin {13000000, 48000, 0x17}, 4256387f866SBrian Austin {13000000, 88200, 0x47}, 4266387f866SBrian Austin {13000000, 96000, 0x57}, 4276387f866SBrian Austin {13000000, 176400, 0x87}, 4286387f866SBrian Austin {13000000, 192000, 0x97}, 4296387f866SBrian Austin {22579200, 44100, 0x02}, 4306387f866SBrian Austin {22579200, 88200, 0x42}, 4316387f866SBrian Austin {22579200, 176400, 0x82}, 4326387f866SBrian Austin {24000000, 44100, 0x0B}, 4336387f866SBrian Austin {24000000, 48000, 0x1B}, 4346387f866SBrian Austin {24000000, 88200, 0x4B}, 4356387f866SBrian Austin {24000000, 96000, 0x5B}, 4366387f866SBrian Austin {24000000, 176400, 0x8B}, 4376387f866SBrian Austin {24000000, 192000, 0x9B}, 4386387f866SBrian Austin {24576000, 48000, 0x12}, 4396387f866SBrian Austin {24576000, 96000, 0x52}, 4406387f866SBrian Austin {24576000, 192000, 0x92}, 4416387f866SBrian Austin {26000000, 44100, 0x0F}, 4426387f866SBrian Austin {26000000, 48000, 0x1F}, 4436387f866SBrian Austin {26000000, 88200, 0x4F}, 4446387f866SBrian Austin {26000000, 96000, 0x5F}, 4456387f866SBrian Austin {26000000, 176400, 0x8F}, 4466387f866SBrian Austin {26000000, 192000, 0x9F}, 4476387f866SBrian Austin }; 4486387f866SBrian Austin 4496387f866SBrian Austin static int cs35l35_get_clk_config(int sysclk, int srate) 4506387f866SBrian Austin { 4516387f866SBrian Austin int i; 4526387f866SBrian Austin 4536387f866SBrian Austin for (i = 0; i < ARRAY_SIZE(cs35l35_clk_ctl); i++) { 4546387f866SBrian Austin if (cs35l35_clk_ctl[i].sysclk == sysclk && 4556387f866SBrian Austin cs35l35_clk_ctl[i].srate == srate) 4566387f866SBrian Austin return cs35l35_clk_ctl[i].clk_cfg; 4576387f866SBrian Austin } 4586387f866SBrian Austin return -EINVAL; 4596387f866SBrian Austin } 4606387f866SBrian Austin 4616387f866SBrian Austin static int cs35l35_hw_params(struct snd_pcm_substream *substream, 4626387f866SBrian Austin struct snd_pcm_hw_params *params, 4636387f866SBrian Austin struct snd_soc_dai *dai) 4646387f866SBrian Austin { 4656387f866SBrian Austin struct snd_soc_codec *codec = dai->codec; 4666387f866SBrian Austin struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec); 4676387f866SBrian Austin struct classh_cfg *classh = &cs35l35->pdata.classh_algo; 4686387f866SBrian Austin int srate = params_rate(params); 4696387f866SBrian Austin int ret = 0; 4706387f866SBrian Austin u8 sp_sclks; 4716387f866SBrian Austin int audin_format; 4726387f866SBrian Austin int errata_chk; 4736387f866SBrian Austin 4746387f866SBrian Austin int clk_ctl = cs35l35_get_clk_config(cs35l35->sysclk, srate); 4756387f866SBrian Austin 4766387f866SBrian Austin if (clk_ctl < 0) { 4776387f866SBrian Austin dev_err(codec->dev, "Invalid CLK:Rate %d:%d\n", 4786387f866SBrian Austin cs35l35->sysclk, srate); 4796387f866SBrian Austin return -EINVAL; 4806387f866SBrian Austin } 4816387f866SBrian Austin 4826387f866SBrian Austin ret = regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL2, 4836387f866SBrian Austin CS35L35_CLK_CTL2_MASK, clk_ctl); 4846387f866SBrian Austin if (ret != 0) { 4856387f866SBrian Austin dev_err(codec->dev, "Failed to set port config %d\n", ret); 4866387f866SBrian Austin return ret; 4876387f866SBrian Austin } 4886387f866SBrian Austin 4896387f866SBrian Austin /* 4906387f866SBrian Austin * Rev A0 Errata 4916387f866SBrian Austin * When configured for the weak-drive detection path (CH_WKFET_DIS = 0) 4926387f866SBrian Austin * the Class H algorithm does not enable weak-drive operation for 4936387f866SBrian Austin * nonzero values of CH_WKFET_DELAY if SP_RATE = 01 or 10 4946387f866SBrian Austin */ 4956387f866SBrian Austin errata_chk = clk_ctl & CS35L35_SP_RATE_MASK; 4966387f866SBrian Austin 4976387f866SBrian Austin if (classh->classh_wk_fet_disable == 0x00 && 4986387f866SBrian Austin (errata_chk == 0x01 || errata_chk == 0x03)) { 4996387f866SBrian Austin ret = regmap_update_bits(cs35l35->regmap, 5006387f866SBrian Austin CS35L35_CLASS_H_FET_DRIVE_CTL, 5016387f866SBrian Austin CS35L35_CH_WKFET_DEL_MASK, 5026387f866SBrian Austin 0 << CS35L35_CH_WKFET_DEL_SHIFT); 5036387f866SBrian Austin if (ret != 0) { 5046387f866SBrian Austin dev_err(codec->dev, "Failed to set fet config %d\n", 5056387f866SBrian Austin ret); 5066387f866SBrian Austin return ret; 5076387f866SBrian Austin } 5086387f866SBrian Austin } 5096387f866SBrian Austin 5106387f866SBrian Austin /* 5116387f866SBrian Austin * You can pull more Monitor data from the SDOUT pin than going to SDIN 5126387f866SBrian Austin * Just make sure your SCLK is fast enough to fill the frame 5136387f866SBrian Austin */ 5146387f866SBrian Austin if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 5156387f866SBrian Austin switch (params_width(params)) { 5166387f866SBrian Austin case 8: 5176387f866SBrian Austin audin_format = CS35L35_SDIN_DEPTH_8; 5186387f866SBrian Austin break; 5196387f866SBrian Austin case 16: 5206387f866SBrian Austin audin_format = CS35L35_SDIN_DEPTH_16; 5216387f866SBrian Austin break; 5226387f866SBrian Austin case 24: 5236387f866SBrian Austin audin_format = CS35L35_SDIN_DEPTH_24; 5246387f866SBrian Austin break; 5256387f866SBrian Austin default: 5266387f866SBrian Austin dev_err(codec->dev, "Unsupported Width %d\n", 5276387f866SBrian Austin params_width(params)); 5286387f866SBrian Austin return -EINVAL; 5296387f866SBrian Austin } 5306387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 5316387f866SBrian Austin CS35L35_AUDIN_DEPTH_CTL, 5326387f866SBrian Austin CS35L35_AUDIN_DEPTH_MASK, 5336387f866SBrian Austin audin_format << 5346387f866SBrian Austin CS35L35_AUDIN_DEPTH_SHIFT); 5356387f866SBrian Austin if (cs35l35->pdata.stereo) { 5366387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 5376387f866SBrian Austin CS35L35_AUDIN_DEPTH_CTL, 5386387f866SBrian Austin CS35L35_ADVIN_DEPTH_MASK, 5396387f866SBrian Austin audin_format << 5406387f866SBrian Austin CS35L35_ADVIN_DEPTH_SHIFT); 5416387f866SBrian Austin } 5426387f866SBrian Austin } 5436387f866SBrian Austin 5446387f866SBrian Austin if (cs35l35->i2s_mode) { 5456387f866SBrian Austin /* We have to take the SCLK to derive num sclks 5466387f866SBrian Austin * to configure the CLOCK_CTL3 register correctly 5476387f866SBrian Austin */ 5486387f866SBrian Austin if ((cs35l35->sclk / srate) % 4) { 5496387f866SBrian Austin dev_err(codec->dev, "Unsupported sclk/fs ratio %d:%d\n", 5506387f866SBrian Austin cs35l35->sclk, srate); 5516387f866SBrian Austin return -EINVAL; 5526387f866SBrian Austin } 5536387f866SBrian Austin sp_sclks = ((cs35l35->sclk / srate) / 4) - 1; 5546387f866SBrian Austin 5556387f866SBrian Austin /* Only certain ratios are supported in I2S Slave Mode */ 5566387f866SBrian Austin if (cs35l35->slave_mode) { 5576387f866SBrian Austin switch (sp_sclks) { 5586387f866SBrian Austin case CS35L35_SP_SCLKS_32FS: 5596387f866SBrian Austin case CS35L35_SP_SCLKS_48FS: 5606387f866SBrian Austin case CS35L35_SP_SCLKS_64FS: 5616387f866SBrian Austin break; 5626387f866SBrian Austin default: 5636387f866SBrian Austin dev_err(codec->dev, "ratio not supported\n"); 5646387f866SBrian Austin return -EINVAL; 565f3a612a6Skbuild test robot } 5666387f866SBrian Austin } else { 5676387f866SBrian Austin /* Only certain ratios supported in I2S MASTER Mode */ 5686387f866SBrian Austin switch (sp_sclks) { 5696387f866SBrian Austin case CS35L35_SP_SCLKS_32FS: 5706387f866SBrian Austin case CS35L35_SP_SCLKS_64FS: 5716387f866SBrian Austin break; 5726387f866SBrian Austin default: 5736387f866SBrian Austin dev_err(codec->dev, "ratio not supported\n"); 5746387f866SBrian Austin return -EINVAL; 575f3a612a6Skbuild test robot } 5766387f866SBrian Austin } 5776387f866SBrian Austin ret = regmap_update_bits(cs35l35->regmap, 5786387f866SBrian Austin CS35L35_CLK_CTL3, 5796387f866SBrian Austin CS35L35_SP_SCLKS_MASK, sp_sclks << 5806387f866SBrian Austin CS35L35_SP_SCLKS_SHIFT); 5816387f866SBrian Austin if (ret != 0) { 5826387f866SBrian Austin dev_err(codec->dev, "Failed to set fsclk %d\n", ret); 5836387f866SBrian Austin return ret; 5846387f866SBrian Austin } 5856387f866SBrian Austin } 5866387f866SBrian Austin 5876387f866SBrian Austin return ret; 5886387f866SBrian Austin } 5896387f866SBrian Austin 5906387f866SBrian Austin static const unsigned int cs35l35_src_rates[] = { 5916387f866SBrian Austin 44100, 48000, 88200, 96000, 176400, 192000 5926387f866SBrian Austin }; 5936387f866SBrian Austin 5946387f866SBrian Austin static const struct snd_pcm_hw_constraint_list cs35l35_constraints = { 5956387f866SBrian Austin .count = ARRAY_SIZE(cs35l35_src_rates), 5966387f866SBrian Austin .list = cs35l35_src_rates, 5976387f866SBrian Austin }; 5986387f866SBrian Austin 5996387f866SBrian Austin static int cs35l35_pcm_startup(struct snd_pcm_substream *substream, 6006387f866SBrian Austin struct snd_soc_dai *dai) 6016387f866SBrian Austin { 6026387f866SBrian Austin struct snd_soc_codec *codec = dai->codec; 6036387f866SBrian Austin struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec); 6046387f866SBrian Austin 6056387f866SBrian Austin if (!substream->runtime) 6066387f866SBrian Austin return 0; 6076387f866SBrian Austin 6086387f866SBrian Austin snd_pcm_hw_constraint_list(substream->runtime, 0, 6096387f866SBrian Austin SNDRV_PCM_HW_PARAM_RATE, &cs35l35_constraints); 6106387f866SBrian Austin 6116387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_AMP_INP_DRV_CTL, 6126387f866SBrian Austin CS35L35_PDM_MODE_MASK, 6136387f866SBrian Austin 0 << CS35L35_PDM_MODE_SHIFT); 6146387f866SBrian Austin 6156387f866SBrian Austin return 0; 6166387f866SBrian Austin } 6176387f866SBrian Austin 6186387f866SBrian Austin static const unsigned int cs35l35_pdm_rates[] = { 6196387f866SBrian Austin 44100, 48000, 88200, 96000 6206387f866SBrian Austin }; 6216387f866SBrian Austin 6226387f866SBrian Austin static const struct snd_pcm_hw_constraint_list cs35l35_pdm_constraints = { 6236387f866SBrian Austin .count = ARRAY_SIZE(cs35l35_pdm_rates), 6246387f866SBrian Austin .list = cs35l35_pdm_rates, 6256387f866SBrian Austin }; 6266387f866SBrian Austin 6276387f866SBrian Austin static int cs35l35_pdm_startup(struct snd_pcm_substream *substream, 6286387f866SBrian Austin struct snd_soc_dai *dai) 6296387f866SBrian Austin { 6306387f866SBrian Austin struct snd_soc_codec *codec = dai->codec; 6316387f866SBrian Austin struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec); 6326387f866SBrian Austin 6336387f866SBrian Austin if (!substream->runtime) 6346387f866SBrian Austin return 0; 6356387f866SBrian Austin 6366387f866SBrian Austin snd_pcm_hw_constraint_list(substream->runtime, 0, 6376387f866SBrian Austin SNDRV_PCM_HW_PARAM_RATE, 6386387f866SBrian Austin &cs35l35_pdm_constraints); 6396387f866SBrian Austin 6406387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_AMP_INP_DRV_CTL, 6416387f866SBrian Austin CS35L35_PDM_MODE_MASK, 6426387f866SBrian Austin 1 << CS35L35_PDM_MODE_SHIFT); 6436387f866SBrian Austin 6446387f866SBrian Austin return 0; 6456387f866SBrian Austin } 6466387f866SBrian Austin 6476387f866SBrian Austin static int cs35l35_dai_set_sysclk(struct snd_soc_dai *dai, 6486387f866SBrian Austin int clk_id, unsigned int freq, int dir) 6496387f866SBrian Austin { 6506387f866SBrian Austin struct snd_soc_codec *codec = dai->codec; 6516387f866SBrian Austin struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec); 6526387f866SBrian Austin 6536387f866SBrian Austin /* Need the SCLK Frequency regardless of sysclk source for I2S */ 6546387f866SBrian Austin cs35l35->sclk = freq; 6556387f866SBrian Austin 6566387f866SBrian Austin return 0; 6576387f866SBrian Austin } 6586387f866SBrian Austin 6596387f866SBrian Austin static const struct snd_soc_dai_ops cs35l35_ops = { 6606387f866SBrian Austin .startup = cs35l35_pcm_startup, 6616387f866SBrian Austin .set_fmt = cs35l35_set_dai_fmt, 6626387f866SBrian Austin .hw_params = cs35l35_hw_params, 6636387f866SBrian Austin .set_sysclk = cs35l35_dai_set_sysclk, 6646387f866SBrian Austin }; 6656387f866SBrian Austin 6666387f866SBrian Austin static const struct snd_soc_dai_ops cs35l35_pdm_ops = { 6676387f866SBrian Austin .startup = cs35l35_pdm_startup, 6686387f866SBrian Austin .set_fmt = cs35l35_set_dai_fmt, 6696387f866SBrian Austin .hw_params = cs35l35_hw_params, 6706387f866SBrian Austin }; 6716387f866SBrian Austin 6726387f866SBrian Austin static struct snd_soc_dai_driver cs35l35_dai[] = { 6736387f866SBrian Austin { 6746387f866SBrian Austin .name = "cs35l35-pcm", 6756387f866SBrian Austin .id = 0, 6766387f866SBrian Austin .playback = { 6776387f866SBrian Austin .stream_name = "AMP Playback", 6786387f866SBrian Austin .channels_min = 1, 6796387f866SBrian Austin .channels_max = 8, 6806387f866SBrian Austin .rates = SNDRV_PCM_RATE_KNOT, 6816387f866SBrian Austin .formats = CS35L35_FORMATS, 6826387f866SBrian Austin }, 6836387f866SBrian Austin .capture = { 6846387f866SBrian Austin .stream_name = "AMP Capture", 6856387f866SBrian Austin .channels_min = 1, 6866387f866SBrian Austin .channels_max = 8, 6876387f866SBrian Austin .rates = SNDRV_PCM_RATE_KNOT, 6886387f866SBrian Austin .formats = CS35L35_FORMATS, 6896387f866SBrian Austin }, 6906387f866SBrian Austin .ops = &cs35l35_ops, 6916387f866SBrian Austin .symmetric_rates = 1, 6926387f866SBrian Austin }, 6936387f866SBrian Austin { 6946387f866SBrian Austin .name = "cs35l35-pdm", 6956387f866SBrian Austin .id = 1, 6966387f866SBrian Austin .playback = { 6976387f866SBrian Austin .stream_name = "PDM Playback", 6986387f866SBrian Austin .channels_min = 1, 6996387f866SBrian Austin .channels_max = 2, 7006387f866SBrian Austin .rates = SNDRV_PCM_RATE_KNOT, 7016387f866SBrian Austin .formats = CS35L35_FORMATS, 7026387f866SBrian Austin }, 7036387f866SBrian Austin .ops = &cs35l35_pdm_ops, 7046387f866SBrian Austin }, 7056387f866SBrian Austin }; 7066387f866SBrian Austin 7076387f866SBrian Austin static int cs35l35_codec_set_sysclk(struct snd_soc_codec *codec, 7086387f866SBrian Austin int clk_id, int source, unsigned int freq, 7096387f866SBrian Austin int dir) 7106387f866SBrian Austin { 7116387f866SBrian Austin struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec); 7126387f866SBrian Austin int clksrc; 7136387f866SBrian Austin int ret = 0; 7146387f866SBrian Austin 7156387f866SBrian Austin switch (clk_id) { 7166387f866SBrian Austin case 0: 7176387f866SBrian Austin clksrc = CS35L35_CLK_SOURCE_MCLK; 7186387f866SBrian Austin break; 7196387f866SBrian Austin case 1: 7206387f866SBrian Austin clksrc = CS35L35_CLK_SOURCE_SCLK; 7216387f866SBrian Austin break; 7226387f866SBrian Austin case 2: 7236387f866SBrian Austin clksrc = CS35L35_CLK_SOURCE_PDM; 7246387f866SBrian Austin break; 7256387f866SBrian Austin default: 7266387f866SBrian Austin dev_err(codec->dev, "Invalid CLK Source\n"); 7276387f866SBrian Austin return -EINVAL; 728f3a612a6Skbuild test robot } 7296387f866SBrian Austin 7306387f866SBrian Austin switch (freq) { 7316387f866SBrian Austin case 5644800: 7326387f866SBrian Austin case 6144000: 7336387f866SBrian Austin case 11289600: 7346387f866SBrian Austin case 12000000: 7356387f866SBrian Austin case 12288000: 7366387f866SBrian Austin case 13000000: 7376387f866SBrian Austin case 22579200: 7386387f866SBrian Austin case 24000000: 7396387f866SBrian Austin case 24576000: 7406387f866SBrian Austin case 26000000: 7416387f866SBrian Austin cs35l35->sysclk = freq; 7426387f866SBrian Austin break; 7436387f866SBrian Austin default: 7446387f866SBrian Austin dev_err(codec->dev, "Invalid CLK Frequency Input : %d\n", freq); 7456387f866SBrian Austin return -EINVAL; 7466387f866SBrian Austin } 7476387f866SBrian Austin 7486387f866SBrian Austin ret = regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL1, 7496387f866SBrian Austin CS35L35_CLK_SOURCE_MASK, 7506387f866SBrian Austin clksrc << CS35L35_CLK_SOURCE_SHIFT); 7516387f866SBrian Austin if (ret != 0) { 7526387f866SBrian Austin dev_err(codec->dev, "Failed to set sysclk %d\n", ret); 7536387f866SBrian Austin return ret; 7546387f866SBrian Austin } 7556387f866SBrian Austin 7566387f866SBrian Austin return ret; 7576387f866SBrian Austin } 7586387f866SBrian Austin 759*b7c752d6SBrian Austin static int cs35l35_boost_inductor(struct cs35l35_private *cs35l35, 760*b7c752d6SBrian Austin int inductor) 761*b7c752d6SBrian Austin { 762*b7c752d6SBrian Austin struct regmap *regmap = cs35l35->regmap; 763*b7c752d6SBrian Austin unsigned int bst_ipk = 0; 764*b7c752d6SBrian Austin 765*b7c752d6SBrian Austin /* 766*b7c752d6SBrian Austin * Digital Boost Converter Configuration for feedback, 767*b7c752d6SBrian Austin * ramping, switching frequency, and estimation block seeding. 768*b7c752d6SBrian Austin */ 769*b7c752d6SBrian Austin 770*b7c752d6SBrian Austin regmap_update_bits(regmap, CS35L35_BST_CONV_SW_FREQ, 771*b7c752d6SBrian Austin CS35L35_BST_CONV_SWFREQ_MASK, 0x00); 772*b7c752d6SBrian Austin 773*b7c752d6SBrian Austin regmap_read(regmap, CS35L35_BST_PEAK_I, &bst_ipk); 774*b7c752d6SBrian Austin bst_ipk &= CS35L35_BST_IPK_MASK; 775*b7c752d6SBrian Austin 776*b7c752d6SBrian Austin switch (inductor) { 777*b7c752d6SBrian Austin case 1000: /* 1 uH */ 778*b7c752d6SBrian Austin regmap_write(regmap, CS35L35_BST_CONV_COEF_1, 0x24); 779*b7c752d6SBrian Austin regmap_write(regmap, CS35L35_BST_CONV_COEF_2, 0x24); 780*b7c752d6SBrian Austin regmap_update_bits(regmap, CS35L35_BST_CONV_SW_FREQ, 781*b7c752d6SBrian Austin CS35L35_BST_CONV_LBST_MASK, 0x00); 782*b7c752d6SBrian Austin 783*b7c752d6SBrian Austin if (bst_ipk < 0x04) 784*b7c752d6SBrian Austin regmap_write(regmap, CS35L35_BST_CONV_SLOPE_COMP, 0x1B); 785*b7c752d6SBrian Austin else 786*b7c752d6SBrian Austin regmap_write(regmap, CS35L35_BST_CONV_SLOPE_COMP, 0x4E); 787*b7c752d6SBrian Austin break; 788*b7c752d6SBrian Austin case 1200: /* 1.2 uH */ 789*b7c752d6SBrian Austin regmap_write(regmap, CS35L35_BST_CONV_COEF_1, 0x20); 790*b7c752d6SBrian Austin regmap_write(regmap, CS35L35_BST_CONV_COEF_2, 0x20); 791*b7c752d6SBrian Austin regmap_update_bits(regmap, CS35L35_BST_CONV_SW_FREQ, 792*b7c752d6SBrian Austin CS35L35_BST_CONV_LBST_MASK, 0x01); 793*b7c752d6SBrian Austin 794*b7c752d6SBrian Austin if (bst_ipk < 0x04) 795*b7c752d6SBrian Austin regmap_write(regmap, CS35L35_BST_CONV_SLOPE_COMP, 0x1B); 796*b7c752d6SBrian Austin else 797*b7c752d6SBrian Austin regmap_write(regmap, CS35L35_BST_CONV_SLOPE_COMP, 0x47); 798*b7c752d6SBrian Austin break; 799*b7c752d6SBrian Austin case 1500: /* 1.5uH */ 800*b7c752d6SBrian Austin regmap_write(regmap, CS35L35_BST_CONV_COEF_1, 0x20); 801*b7c752d6SBrian Austin regmap_write(regmap, CS35L35_BST_CONV_COEF_2, 0x20); 802*b7c752d6SBrian Austin regmap_update_bits(regmap, CS35L35_BST_CONV_SW_FREQ, 803*b7c752d6SBrian Austin CS35L35_BST_CONV_LBST_MASK, 0x02); 804*b7c752d6SBrian Austin 805*b7c752d6SBrian Austin if (bst_ipk < 0x04) 806*b7c752d6SBrian Austin regmap_write(regmap, CS35L35_BST_CONV_SLOPE_COMP, 0x1B); 807*b7c752d6SBrian Austin else 808*b7c752d6SBrian Austin regmap_write(regmap, CS35L35_BST_CONV_SLOPE_COMP, 0x3C); 809*b7c752d6SBrian Austin break; 810*b7c752d6SBrian Austin case 2200: /* 2.2uH */ 811*b7c752d6SBrian Austin regmap_write(regmap, CS35L35_BST_CONV_COEF_1, 0x19); 812*b7c752d6SBrian Austin regmap_write(regmap, CS35L35_BST_CONV_COEF_2, 0x25); 813*b7c752d6SBrian Austin regmap_update_bits(regmap, CS35L35_BST_CONV_SW_FREQ, 814*b7c752d6SBrian Austin CS35L35_BST_CONV_LBST_MASK, 0x03); 815*b7c752d6SBrian Austin 816*b7c752d6SBrian Austin if (bst_ipk < 0x04) 817*b7c752d6SBrian Austin regmap_write(regmap, CS35L35_BST_CONV_SLOPE_COMP, 0x1B); 818*b7c752d6SBrian Austin else 819*b7c752d6SBrian Austin regmap_write(regmap, CS35L35_BST_CONV_SLOPE_COMP, 0x23); 820*b7c752d6SBrian Austin break; 821*b7c752d6SBrian Austin default: 822*b7c752d6SBrian Austin dev_err(cs35l35->dev, "Invalid Inductor Value %d uH\n", 823*b7c752d6SBrian Austin inductor); 824*b7c752d6SBrian Austin return -EINVAL; 825*b7c752d6SBrian Austin } 826*b7c752d6SBrian Austin return 0; 827*b7c752d6SBrian Austin } 828*b7c752d6SBrian Austin 8296387f866SBrian Austin static int cs35l35_codec_probe(struct snd_soc_codec *codec) 8306387f866SBrian Austin { 8316387f866SBrian Austin struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec); 8326387f866SBrian Austin struct classh_cfg *classh = &cs35l35->pdata.classh_algo; 8336387f866SBrian Austin struct monitor_cfg *monitor_config = &cs35l35->pdata.mon_cfg; 8346387f866SBrian Austin int ret; 8356387f866SBrian Austin 8366387f866SBrian Austin /* Set Platform Data */ 8376387f866SBrian Austin if (cs35l35->pdata.bst_vctl) 8386387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_BST_CVTR_V_CTL, 8396387f866SBrian Austin CS35L35_BST_CTL_MASK, 8406387f866SBrian Austin cs35l35->pdata.bst_vctl); 8416387f866SBrian Austin 8426387f866SBrian Austin if (cs35l35->pdata.bst_ipk) 8436387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_BST_PEAK_I, 8446387f866SBrian Austin CS35L35_BST_IPK_MASK, 8456387f866SBrian Austin cs35l35->pdata.bst_ipk << 8466387f866SBrian Austin CS35L35_BST_IPK_SHIFT); 8476387f866SBrian Austin 848*b7c752d6SBrian Austin ret = cs35l35_boost_inductor(cs35l35, cs35l35->pdata.boost_ind); 849*b7c752d6SBrian Austin if (ret) 850*b7c752d6SBrian Austin return ret; 851*b7c752d6SBrian Austin 8526387f866SBrian Austin if (cs35l35->pdata.gain_zc) 8536387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PROTECT_CTL, 8546387f866SBrian Austin CS35L35_AMP_GAIN_ZC_MASK, 8556387f866SBrian Austin cs35l35->pdata.gain_zc << 8566387f866SBrian Austin CS35L35_AMP_GAIN_ZC_SHIFT); 8576387f866SBrian Austin 8586387f866SBrian Austin if (cs35l35->pdata.aud_channel) 8596387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 8606387f866SBrian Austin CS35L35_AUDIN_RXLOC_CTL, 8616387f866SBrian Austin CS35L35_AUD_IN_LR_MASK, 8626387f866SBrian Austin cs35l35->pdata.aud_channel << 8636387f866SBrian Austin CS35L35_AUD_IN_LR_SHIFT); 8646387f866SBrian Austin 8656387f866SBrian Austin if (cs35l35->pdata.stereo) { 8666387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 8676387f866SBrian Austin CS35L35_ADVIN_RXLOC_CTL, 8686387f866SBrian Austin CS35L35_ADV_IN_LR_MASK, 8696387f866SBrian Austin cs35l35->pdata.adv_channel << 8706387f866SBrian Austin CS35L35_ADV_IN_LR_SHIFT); 8716387f866SBrian Austin if (cs35l35->pdata.shared_bst) 8726387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_CLASS_H_CTL, 8736387f866SBrian Austin CS35L35_CH_STEREO_MASK, 8746387f866SBrian Austin 1 << CS35L35_CH_STEREO_SHIFT); 8756387f866SBrian Austin ret = snd_soc_add_codec_controls(codec, cs35l35_adv_controls, 8766387f866SBrian Austin ARRAY_SIZE(cs35l35_adv_controls)); 8776387f866SBrian Austin if (ret) 8786387f866SBrian Austin return ret; 8796387f866SBrian Austin } 8806387f866SBrian Austin 8816387f866SBrian Austin if (cs35l35->pdata.sp_drv_str) 8826387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL1, 8836387f866SBrian Austin CS35L35_SP_DRV_MASK, 8846387f866SBrian Austin cs35l35->pdata.sp_drv_str << 8856387f866SBrian Austin CS35L35_SP_DRV_SHIFT); 8868d45f2d2SCharles Keepax if (cs35l35->pdata.sp_drv_unused) 8878d45f2d2SCharles Keepax regmap_update_bits(cs35l35->regmap, CS35L35_SP_FMT_CTL3, 8888d45f2d2SCharles Keepax CS35L35_SP_I2S_DRV_MASK, 8898d45f2d2SCharles Keepax cs35l35->pdata.sp_drv_unused << 8908d45f2d2SCharles Keepax CS35L35_SP_I2S_DRV_SHIFT); 8916387f866SBrian Austin 8926387f866SBrian Austin if (classh->classh_algo_enable) { 8936387f866SBrian Austin if (classh->classh_bst_override) 8946387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 8956387f866SBrian Austin CS35L35_CLASS_H_CTL, 8966387f866SBrian Austin CS35L35_CH_BST_OVR_MASK, 8976387f866SBrian Austin classh->classh_bst_override << 8986387f866SBrian Austin CS35L35_CH_BST_OVR_SHIFT); 8996387f866SBrian Austin if (classh->classh_bst_max_limit) 9006387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 9016387f866SBrian Austin CS35L35_CLASS_H_CTL, 9026387f866SBrian Austin CS35L35_CH_BST_LIM_MASK, 9036387f866SBrian Austin classh->classh_bst_max_limit << 9046387f866SBrian Austin CS35L35_CH_BST_LIM_SHIFT); 9056387f866SBrian Austin if (classh->classh_mem_depth) 9066387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 9076387f866SBrian Austin CS35L35_CLASS_H_CTL, 9086387f866SBrian Austin CS35L35_CH_MEM_DEPTH_MASK, 9096387f866SBrian Austin classh->classh_mem_depth << 9106387f866SBrian Austin CS35L35_CH_MEM_DEPTH_SHIFT); 9116387f866SBrian Austin if (classh->classh_headroom) 9126387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 9136387f866SBrian Austin CS35L35_CLASS_H_HEADRM_CTL, 9146387f866SBrian Austin CS35L35_CH_HDRM_CTL_MASK, 9156387f866SBrian Austin classh->classh_headroom << 9166387f866SBrian Austin CS35L35_CH_HDRM_CTL_SHIFT); 9176387f866SBrian Austin if (classh->classh_release_rate) 9186387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 9196387f866SBrian Austin CS35L35_CLASS_H_RELEASE_RATE, 9206387f866SBrian Austin CS35L35_CH_REL_RATE_MASK, 9216387f866SBrian Austin classh->classh_release_rate << 9226387f866SBrian Austin CS35L35_CH_REL_RATE_SHIFT); 9236387f866SBrian Austin if (classh->classh_wk_fet_disable) 9246387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 9256387f866SBrian Austin CS35L35_CLASS_H_FET_DRIVE_CTL, 9266387f866SBrian Austin CS35L35_CH_WKFET_DIS_MASK, 9276387f866SBrian Austin classh->classh_wk_fet_disable << 9286387f866SBrian Austin CS35L35_CH_WKFET_DIS_SHIFT); 9296387f866SBrian Austin if (classh->classh_wk_fet_delay) 9306387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 9316387f866SBrian Austin CS35L35_CLASS_H_FET_DRIVE_CTL, 9326387f866SBrian Austin CS35L35_CH_WKFET_DEL_MASK, 9336387f866SBrian Austin classh->classh_wk_fet_delay << 9346387f866SBrian Austin CS35L35_CH_WKFET_DEL_SHIFT); 9356387f866SBrian Austin if (classh->classh_wk_fet_thld) 9366387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 9376387f866SBrian Austin CS35L35_CLASS_H_FET_DRIVE_CTL, 9386387f866SBrian Austin CS35L35_CH_WKFET_THLD_MASK, 9396387f866SBrian Austin classh->classh_wk_fet_thld << 9406387f866SBrian Austin CS35L35_CH_WKFET_THLD_SHIFT); 9416387f866SBrian Austin if (classh->classh_vpch_auto) 9426387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 9436387f866SBrian Austin CS35L35_CLASS_H_VP_CTL, 9446387f866SBrian Austin CS35L35_CH_VP_AUTO_MASK, 9456387f866SBrian Austin classh->classh_vpch_auto << 9466387f866SBrian Austin CS35L35_CH_VP_AUTO_SHIFT); 9476387f866SBrian Austin if (classh->classh_vpch_rate) 9486387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 9496387f866SBrian Austin CS35L35_CLASS_H_VP_CTL, 9506387f866SBrian Austin CS35L35_CH_VP_RATE_MASK, 9516387f866SBrian Austin classh->classh_vpch_rate << 9526387f866SBrian Austin CS35L35_CH_VP_RATE_SHIFT); 9536387f866SBrian Austin if (classh->classh_vpch_man) 9546387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 9556387f866SBrian Austin CS35L35_CLASS_H_VP_CTL, 9566387f866SBrian Austin CS35L35_CH_VP_MAN_MASK, 9576387f866SBrian Austin classh->classh_vpch_man << 9586387f866SBrian Austin CS35L35_CH_VP_MAN_SHIFT); 9596387f866SBrian Austin } 9606387f866SBrian Austin 9616387f866SBrian Austin if (monitor_config->is_present) { 9626387f866SBrian Austin if (monitor_config->vmon_specs) { 9636387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 9646387f866SBrian Austin CS35L35_SPKMON_DEPTH_CTL, 9656387f866SBrian Austin CS35L35_VMON_DEPTH_MASK, 9666387f866SBrian Austin monitor_config->vmon_dpth << 9676387f866SBrian Austin CS35L35_VMON_DEPTH_SHIFT); 9686387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 9696387f866SBrian Austin CS35L35_VMON_TXLOC_CTL, 9706387f866SBrian Austin CS35L35_MON_TXLOC_MASK, 9716387f866SBrian Austin monitor_config->vmon_loc << 9726387f866SBrian Austin CS35L35_MON_TXLOC_SHIFT); 9736387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 9746387f866SBrian Austin CS35L35_VMON_TXLOC_CTL, 9756387f866SBrian Austin CS35L35_MON_FRM_MASK, 9766387f866SBrian Austin monitor_config->vmon_frm << 9776387f866SBrian Austin CS35L35_MON_FRM_SHIFT); 9786387f866SBrian Austin } 9796387f866SBrian Austin if (monitor_config->imon_specs) { 9806387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 9816387f866SBrian Austin CS35L35_SPKMON_DEPTH_CTL, 9826387f866SBrian Austin CS35L35_IMON_DEPTH_MASK, 9836387f866SBrian Austin monitor_config->imon_dpth << 9846387f866SBrian Austin CS35L35_IMON_DEPTH_SHIFT); 9856387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 9866387f866SBrian Austin CS35L35_IMON_TXLOC_CTL, 9876387f866SBrian Austin CS35L35_MON_TXLOC_MASK, 9886387f866SBrian Austin monitor_config->imon_loc << 9896387f866SBrian Austin CS35L35_MON_TXLOC_SHIFT); 9906387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 9916387f866SBrian Austin CS35L35_IMON_TXLOC_CTL, 9926387f866SBrian Austin CS35L35_MON_FRM_MASK, 9936387f866SBrian Austin monitor_config->imon_frm << 9946387f866SBrian Austin CS35L35_MON_FRM_SHIFT); 99506bdf385SCharles Keepax regmap_update_bits(cs35l35->regmap, 99606bdf385SCharles Keepax CS35L35_IMON_SCALE_CTL, 99706bdf385SCharles Keepax CS35L35_IMON_SCALE_MASK, 99806bdf385SCharles Keepax monitor_config->imon_scale << 99906bdf385SCharles Keepax CS35L35_IMON_SCALE_SHIFT); 10006387f866SBrian Austin } 10016387f866SBrian Austin if (monitor_config->vpmon_specs) { 10026387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 10036387f866SBrian Austin CS35L35_SUPMON_DEPTH_CTL, 10046387f866SBrian Austin CS35L35_VPMON_DEPTH_MASK, 10056387f866SBrian Austin monitor_config->vpmon_dpth << 10066387f866SBrian Austin CS35L35_VPMON_DEPTH_SHIFT); 10076387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 10086387f866SBrian Austin CS35L35_VPMON_TXLOC_CTL, 10096387f866SBrian Austin CS35L35_MON_TXLOC_MASK, 10106387f866SBrian Austin monitor_config->vpmon_loc << 10116387f866SBrian Austin CS35L35_MON_TXLOC_SHIFT); 10126387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 10136387f866SBrian Austin CS35L35_VPMON_TXLOC_CTL, 10146387f866SBrian Austin CS35L35_MON_FRM_MASK, 10156387f866SBrian Austin monitor_config->vpmon_frm << 10166387f866SBrian Austin CS35L35_MON_FRM_SHIFT); 10176387f866SBrian Austin } 10186387f866SBrian Austin if (monitor_config->vbstmon_specs) { 10196387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 10206387f866SBrian Austin CS35L35_SUPMON_DEPTH_CTL, 10216387f866SBrian Austin CS35L35_VBSTMON_DEPTH_MASK, 10226387f866SBrian Austin monitor_config->vpmon_dpth << 10236387f866SBrian Austin CS35L35_VBSTMON_DEPTH_SHIFT); 10246387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 10256387f866SBrian Austin CS35L35_VBSTMON_TXLOC_CTL, 10266387f866SBrian Austin CS35L35_MON_TXLOC_MASK, 10276387f866SBrian Austin monitor_config->vbstmon_loc << 10286387f866SBrian Austin CS35L35_MON_TXLOC_SHIFT); 10296387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 10306387f866SBrian Austin CS35L35_VBSTMON_TXLOC_CTL, 10316387f866SBrian Austin CS35L35_MON_FRM_MASK, 10326387f866SBrian Austin monitor_config->vbstmon_frm << 10336387f866SBrian Austin CS35L35_MON_FRM_SHIFT); 10346387f866SBrian Austin } 10356387f866SBrian Austin if (monitor_config->vpbrstat_specs) { 10366387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 10376387f866SBrian Austin CS35L35_SUPMON_DEPTH_CTL, 10386387f866SBrian Austin CS35L35_VPBRSTAT_DEPTH_MASK, 10396387f866SBrian Austin monitor_config->vpbrstat_dpth << 10406387f866SBrian Austin CS35L35_VPBRSTAT_DEPTH_SHIFT); 10416387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 10426387f866SBrian Austin CS35L35_VPBR_STATUS_TXLOC_CTL, 10436387f866SBrian Austin CS35L35_MON_TXLOC_MASK, 10446387f866SBrian Austin monitor_config->vpbrstat_loc << 10456387f866SBrian Austin CS35L35_MON_TXLOC_SHIFT); 10466387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 10476387f866SBrian Austin CS35L35_VPBR_STATUS_TXLOC_CTL, 10486387f866SBrian Austin CS35L35_MON_FRM_MASK, 10496387f866SBrian Austin monitor_config->vpbrstat_frm << 10506387f866SBrian Austin CS35L35_MON_FRM_SHIFT); 10516387f866SBrian Austin } 10526387f866SBrian Austin if (monitor_config->zerofill_specs) { 10536387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 10546387f866SBrian Austin CS35L35_SUPMON_DEPTH_CTL, 10556387f866SBrian Austin CS35L35_ZEROFILL_DEPTH_MASK, 10566387f866SBrian Austin monitor_config->zerofill_dpth << 10576387f866SBrian Austin CS35L35_ZEROFILL_DEPTH_SHIFT); 10586387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 10596387f866SBrian Austin CS35L35_ZERO_FILL_LOC_CTL, 10606387f866SBrian Austin CS35L35_MON_TXLOC_MASK, 10616387f866SBrian Austin monitor_config->zerofill_loc << 10626387f866SBrian Austin CS35L35_MON_TXLOC_SHIFT); 10636387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 10646387f866SBrian Austin CS35L35_ZERO_FILL_LOC_CTL, 10656387f866SBrian Austin CS35L35_MON_FRM_MASK, 10666387f866SBrian Austin monitor_config->zerofill_frm << 10676387f866SBrian Austin CS35L35_MON_FRM_SHIFT); 10686387f866SBrian Austin } 10696387f866SBrian Austin } 10706387f866SBrian Austin 1071bfe41c67SDan Carpenter return 0; 10726387f866SBrian Austin } 10736387f866SBrian Austin 10746387f866SBrian Austin static struct snd_soc_codec_driver soc_codec_dev_cs35l35 = { 10756387f866SBrian Austin .probe = cs35l35_codec_probe, 10766387f866SBrian Austin .set_sysclk = cs35l35_codec_set_sysclk, 10776387f866SBrian Austin .component_driver = { 10786387f866SBrian Austin .dapm_widgets = cs35l35_dapm_widgets, 10796387f866SBrian Austin .num_dapm_widgets = ARRAY_SIZE(cs35l35_dapm_widgets), 10806387f866SBrian Austin 10816387f866SBrian Austin .dapm_routes = cs35l35_audio_map, 10826387f866SBrian Austin .num_dapm_routes = ARRAY_SIZE(cs35l35_audio_map), 10836387f866SBrian Austin 10846387f866SBrian Austin .controls = cs35l35_aud_controls, 10856387f866SBrian Austin .num_controls = ARRAY_SIZE(cs35l35_aud_controls), 10866387f866SBrian Austin }, 10876387f866SBrian Austin 10886387f866SBrian Austin }; 10896387f866SBrian Austin 10906387f866SBrian Austin static struct regmap_config cs35l35_regmap = { 10916387f866SBrian Austin .reg_bits = 8, 10926387f866SBrian Austin .val_bits = 8, 10936387f866SBrian Austin 10946387f866SBrian Austin .max_register = CS35L35_MAX_REGISTER, 10956387f866SBrian Austin .reg_defaults = cs35l35_reg, 10966387f866SBrian Austin .num_reg_defaults = ARRAY_SIZE(cs35l35_reg), 10976387f866SBrian Austin .volatile_reg = cs35l35_volatile_register, 10986387f866SBrian Austin .readable_reg = cs35l35_readable_register, 10996387f866SBrian Austin .precious_reg = cs35l35_precious_register, 11006387f866SBrian Austin .cache_type = REGCACHE_RBTREE, 11016387f866SBrian Austin }; 11026387f866SBrian Austin 11036387f866SBrian Austin static irqreturn_t cs35l35_irq(int irq, void *data) 11046387f866SBrian Austin { 11056387f866SBrian Austin struct cs35l35_private *cs35l35 = data; 11066387f866SBrian Austin unsigned int sticky1, sticky2, sticky3, sticky4; 11076387f866SBrian Austin unsigned int mask1, mask2, mask3, mask4, current1; 11086387f866SBrian Austin 11096387f866SBrian Austin /* ack the irq by reading all status registers */ 11106387f866SBrian Austin regmap_read(cs35l35->regmap, CS35L35_INT_STATUS_4, &sticky4); 11116387f866SBrian Austin regmap_read(cs35l35->regmap, CS35L35_INT_STATUS_3, &sticky3); 11126387f866SBrian Austin regmap_read(cs35l35->regmap, CS35L35_INT_STATUS_2, &sticky2); 11136387f866SBrian Austin regmap_read(cs35l35->regmap, CS35L35_INT_STATUS_1, &sticky1); 11146387f866SBrian Austin 11156387f866SBrian Austin regmap_read(cs35l35->regmap, CS35L35_INT_MASK_4, &mask4); 11166387f866SBrian Austin regmap_read(cs35l35->regmap, CS35L35_INT_MASK_3, &mask3); 11176387f866SBrian Austin regmap_read(cs35l35->regmap, CS35L35_INT_MASK_2, &mask2); 11186387f866SBrian Austin regmap_read(cs35l35->regmap, CS35L35_INT_MASK_1, &mask1); 11196387f866SBrian Austin 11206387f866SBrian Austin /* Check to see if unmasked bits are active */ 11216387f866SBrian Austin if (!(sticky1 & ~mask1) && !(sticky2 & ~mask2) && !(sticky3 & ~mask3) 11226387f866SBrian Austin && !(sticky4 & ~mask4)) 11236387f866SBrian Austin return IRQ_NONE; 11246387f866SBrian Austin 11256387f866SBrian Austin if (sticky2 & CS35L35_PDN_DONE) 11266387f866SBrian Austin complete(&cs35l35->pdn_done); 11276387f866SBrian Austin 11286387f866SBrian Austin /* read the current values */ 11296387f866SBrian Austin regmap_read(cs35l35->regmap, CS35L35_INT_STATUS_1, ¤t1); 11306387f866SBrian Austin 11316387f866SBrian Austin /* handle the interrupts */ 11326387f866SBrian Austin if (sticky1 & CS35L35_CAL_ERR) { 11335d3d0ad6SCharles Keepax dev_crit(cs35l35->dev, "Calibration Error\n"); 11346387f866SBrian Austin 11356387f866SBrian Austin /* error is no longer asserted; safe to reset */ 11366387f866SBrian Austin if (!(current1 & CS35L35_CAL_ERR)) { 11376387f866SBrian Austin pr_debug("%s : Cal error release\n", __func__); 11386387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 11396387f866SBrian Austin CS35L35_PROT_RELEASE_CTL, 11406387f866SBrian Austin CS35L35_CAL_ERR_RLS, 0); 11416387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 11426387f866SBrian Austin CS35L35_PROT_RELEASE_CTL, 11436387f866SBrian Austin CS35L35_CAL_ERR_RLS, 11446387f866SBrian Austin CS35L35_CAL_ERR_RLS); 11456387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 11466387f866SBrian Austin CS35L35_PROT_RELEASE_CTL, 11476387f866SBrian Austin CS35L35_CAL_ERR_RLS, 0); 11486387f866SBrian Austin } 11496387f866SBrian Austin } 11506387f866SBrian Austin 11516387f866SBrian Austin if (sticky1 & CS35L35_AMP_SHORT) { 11525d3d0ad6SCharles Keepax dev_crit(cs35l35->dev, "AMP Short Error\n"); 11536387f866SBrian Austin /* error is no longer asserted; safe to reset */ 11546387f866SBrian Austin if (!(current1 & CS35L35_AMP_SHORT)) { 11555d3d0ad6SCharles Keepax dev_dbg(cs35l35->dev, "Amp short error release\n"); 11566387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 11576387f866SBrian Austin CS35L35_PROT_RELEASE_CTL, 11586387f866SBrian Austin CS35L35_SHORT_RLS, 0); 11596387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 11606387f866SBrian Austin CS35L35_PROT_RELEASE_CTL, 11616387f866SBrian Austin CS35L35_SHORT_RLS, 11626387f866SBrian Austin CS35L35_SHORT_RLS); 11636387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 11646387f866SBrian Austin CS35L35_PROT_RELEASE_CTL, 11656387f866SBrian Austin CS35L35_SHORT_RLS, 0); 11666387f866SBrian Austin } 11676387f866SBrian Austin } 11686387f866SBrian Austin 11696387f866SBrian Austin if (sticky1 & CS35L35_OTW) { 11705d3d0ad6SCharles Keepax dev_warn(cs35l35->dev, "Over temperature warning\n"); 11716387f866SBrian Austin 11726387f866SBrian Austin /* error is no longer asserted; safe to reset */ 11736387f866SBrian Austin if (!(current1 & CS35L35_OTW)) { 11745d3d0ad6SCharles Keepax dev_dbg(cs35l35->dev, "Over temperature warn release\n"); 11756387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 11766387f866SBrian Austin CS35L35_PROT_RELEASE_CTL, 11776387f866SBrian Austin CS35L35_OTW_RLS, 0); 11786387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 11796387f866SBrian Austin CS35L35_PROT_RELEASE_CTL, 11806387f866SBrian Austin CS35L35_OTW_RLS, 11816387f866SBrian Austin CS35L35_OTW_RLS); 11826387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 11836387f866SBrian Austin CS35L35_PROT_RELEASE_CTL, 11846387f866SBrian Austin CS35L35_OTW_RLS, 0); 11856387f866SBrian Austin } 11866387f866SBrian Austin } 11876387f866SBrian Austin 11886387f866SBrian Austin if (sticky1 & CS35L35_OTE) { 11895d3d0ad6SCharles Keepax dev_crit(cs35l35->dev, "Over temperature error\n"); 11906387f866SBrian Austin /* error is no longer asserted; safe to reset */ 11916387f866SBrian Austin if (!(current1 & CS35L35_OTE)) { 11925d3d0ad6SCharles Keepax dev_dbg(cs35l35->dev, "Over temperature error release\n"); 11936387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 11946387f866SBrian Austin CS35L35_PROT_RELEASE_CTL, 11956387f866SBrian Austin CS35L35_OTE_RLS, 0); 11966387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 11976387f866SBrian Austin CS35L35_PROT_RELEASE_CTL, 11986387f866SBrian Austin CS35L35_OTE_RLS, 11996387f866SBrian Austin CS35L35_OTE_RLS); 12006387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 12016387f866SBrian Austin CS35L35_PROT_RELEASE_CTL, 12026387f866SBrian Austin CS35L35_OTE_RLS, 0); 12036387f866SBrian Austin } 12046387f866SBrian Austin } 12056387f866SBrian Austin 12066387f866SBrian Austin if (sticky3 & CS35L35_BST_HIGH) { 12075d3d0ad6SCharles Keepax dev_crit(cs35l35->dev, "VBST error: powering off!\n"); 12086387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, 12096387f866SBrian Austin CS35L35_PDN_AMP, CS35L35_PDN_AMP); 12106387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL1, 12116387f866SBrian Austin CS35L35_PDN_ALL, CS35L35_PDN_ALL); 12126387f866SBrian Austin } 12136387f866SBrian Austin 12146387f866SBrian Austin if (sticky3 & CS35L35_LBST_SHORT) { 12155d3d0ad6SCharles Keepax dev_crit(cs35l35->dev, "LBST error: powering off!\n"); 12166387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, 12176387f866SBrian Austin CS35L35_PDN_AMP, CS35L35_PDN_AMP); 12186387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL1, 12196387f866SBrian Austin CS35L35_PDN_ALL, CS35L35_PDN_ALL); 12206387f866SBrian Austin } 12216387f866SBrian Austin 12226387f866SBrian Austin if (sticky2 & CS35L35_VPBR_ERR) 12235d3d0ad6SCharles Keepax dev_dbg(cs35l35->dev, "Error: Reactive Brownout\n"); 12246387f866SBrian Austin 12256387f866SBrian Austin if (sticky4 & CS35L35_VMON_OVFL) 12265d3d0ad6SCharles Keepax dev_dbg(cs35l35->dev, "Error: VMON overflow\n"); 12276387f866SBrian Austin 12286387f866SBrian Austin if (sticky4 & CS35L35_IMON_OVFL) 12295d3d0ad6SCharles Keepax dev_dbg(cs35l35->dev, "Error: IMON overflow\n"); 12306387f866SBrian Austin 12316387f866SBrian Austin return IRQ_HANDLED; 12326387f866SBrian Austin } 12336387f866SBrian Austin 12346387f866SBrian Austin 12356387f866SBrian Austin static int cs35l35_handle_of_data(struct i2c_client *i2c_client, 12366387f866SBrian Austin struct cs35l35_platform_data *pdata) 12376387f866SBrian Austin { 12386387f866SBrian Austin struct device_node *np = i2c_client->dev.of_node; 12396387f866SBrian Austin struct device_node *classh, *signal_format; 12406387f866SBrian Austin struct classh_cfg *classh_config = &pdata->classh_algo; 12416387f866SBrian Austin struct monitor_cfg *monitor_config = &pdata->mon_cfg; 12426387f866SBrian Austin unsigned int val32 = 0; 124306bdf385SCharles Keepax u8 monitor_array[4]; 124406bdf385SCharles Keepax const int imon_array_size = ARRAY_SIZE(monitor_array); 124506bdf385SCharles Keepax const int mon_array_size = imon_array_size - 1; 12466387f866SBrian Austin int ret = 0; 12476387f866SBrian Austin 12486387f866SBrian Austin if (!np) 12496387f866SBrian Austin return 0; 12506387f866SBrian Austin 12516387f866SBrian Austin pdata->bst_pdn_fet_on = of_property_read_bool(np, 12526387f866SBrian Austin "cirrus,boost-pdn-fet-on"); 12536387f866SBrian Austin 12546387f866SBrian Austin ret = of_property_read_u32(np, "cirrus,boost-ctl-millivolt", &val32); 12556387f866SBrian Austin if (ret >= 0) { 12566387f866SBrian Austin if (val32 < 2600 || val32 > 9000) { 12576387f866SBrian Austin dev_err(&i2c_client->dev, 12586387f866SBrian Austin "Invalid Boost Voltage %d mV\n", val32); 12596387f866SBrian Austin return -EINVAL; 12606387f866SBrian Austin } 12616387f866SBrian Austin pdata->bst_vctl = ((val32 - 2600) / 100) + 1; 12626387f866SBrian Austin } 12636387f866SBrian Austin 12646387f866SBrian Austin ret = of_property_read_u32(np, "cirrus,boost-peak-milliamp", &val32); 12656387f866SBrian Austin if (ret >= 0) { 12666387f866SBrian Austin if (val32 < 1680 || val32 > 4480) { 12676387f866SBrian Austin dev_err(&i2c_client->dev, 12686387f866SBrian Austin "Invalid Boost Peak Current %u mA\n", val32); 12696387f866SBrian Austin return -EINVAL; 12706387f866SBrian Austin } 12716387f866SBrian Austin 12726387f866SBrian Austin pdata->bst_ipk = (val32 - 1680) / 110; 12736387f866SBrian Austin } 12746387f866SBrian Austin 1275*b7c752d6SBrian Austin ret = of_property_read_u32(np, "cirrus,boost-ind-nanohenry", &val32); 1276*b7c752d6SBrian Austin if (ret >= 0) { 1277*b7c752d6SBrian Austin pdata->boost_ind = val32; 1278*b7c752d6SBrian Austin } else { 1279*b7c752d6SBrian Austin dev_err(&i2c_client->dev, "Inductor not specified.\n"); 1280*b7c752d6SBrian Austin return -EINVAL; 1281*b7c752d6SBrian Austin } 1282*b7c752d6SBrian Austin 12836387f866SBrian Austin if (of_property_read_u32(np, "cirrus,sp-drv-strength", &val32) >= 0) 12846387f866SBrian Austin pdata->sp_drv_str = val32; 12858d45f2d2SCharles Keepax if (of_property_read_u32(np, "cirrus,sp-drv-unused", &val32) >= 0) 12868d45f2d2SCharles Keepax pdata->sp_drv_unused = val32 | CS35L35_VALID_PDATA; 12876387f866SBrian Austin 12886387f866SBrian Austin pdata->stereo = of_property_read_bool(np, "cirrus,stereo-config"); 12896387f866SBrian Austin 12906387f866SBrian Austin if (pdata->stereo) { 12916387f866SBrian Austin ret = of_property_read_u32(np, "cirrus,audio-channel", &val32); 12926387f866SBrian Austin if (ret >= 0) 12936387f866SBrian Austin pdata->aud_channel = val32; 12946387f866SBrian Austin 12956387f866SBrian Austin ret = of_property_read_u32(np, "cirrus,advisory-channel", 12966387f866SBrian Austin &val32); 12976387f866SBrian Austin if (ret >= 0) 12986387f866SBrian Austin pdata->adv_channel = val32; 12996387f866SBrian Austin 13006387f866SBrian Austin pdata->shared_bst = of_property_read_bool(np, 13016387f866SBrian Austin "cirrus,shared-boost"); 13026387f866SBrian Austin } 13036387f866SBrian Austin 130477b329d1SCharles Keepax pdata->ext_bst = of_property_read_bool(np, "cirrus,external-boost"); 130577b329d1SCharles Keepax 13066387f866SBrian Austin pdata->gain_zc = of_property_read_bool(np, "cirrus,amp-gain-zc"); 13076387f866SBrian Austin 13086387f866SBrian Austin classh = of_get_child_by_name(np, "cirrus,classh-internal-algo"); 13096387f866SBrian Austin classh_config->classh_algo_enable = classh ? true : false; 13106387f866SBrian Austin 13116387f866SBrian Austin if (classh_config->classh_algo_enable) { 13126387f866SBrian Austin classh_config->classh_bst_override = 13136387f866SBrian Austin of_property_read_bool(np, "cirrus,classh-bst-overide"); 13146387f866SBrian Austin 13156387f866SBrian Austin ret = of_property_read_u32(classh, 13166387f866SBrian Austin "cirrus,classh-bst-max-limit", 13176387f866SBrian Austin &val32); 13186387f866SBrian Austin if (ret >= 0) { 13196387f866SBrian Austin val32 |= CS35L35_VALID_PDATA; 13206387f866SBrian Austin classh_config->classh_bst_max_limit = val32; 13216387f866SBrian Austin } 13226387f866SBrian Austin 13236387f866SBrian Austin ret = of_property_read_u32(classh, 13246387f866SBrian Austin "cirrus,classh-bst-max-limit", 13256387f866SBrian Austin &val32); 13266387f866SBrian Austin if (ret >= 0) { 13276387f866SBrian Austin val32 |= CS35L35_VALID_PDATA; 13286387f866SBrian Austin classh_config->classh_bst_max_limit = val32; 13296387f866SBrian Austin } 13306387f866SBrian Austin 13316387f866SBrian Austin ret = of_property_read_u32(classh, "cirrus,classh-mem-depth", 13326387f866SBrian Austin &val32); 13336387f866SBrian Austin if (ret >= 0) { 13346387f866SBrian Austin val32 |= CS35L35_VALID_PDATA; 13356387f866SBrian Austin classh_config->classh_mem_depth = val32; 13366387f866SBrian Austin } 13376387f866SBrian Austin 13386387f866SBrian Austin ret = of_property_read_u32(classh, "cirrus,classh-release-rate", 13396387f866SBrian Austin &val32); 13406387f866SBrian Austin if (ret >= 0) 13416387f866SBrian Austin classh_config->classh_release_rate = val32; 13426387f866SBrian Austin 13436387f866SBrian Austin ret = of_property_read_u32(classh, "cirrus,classh-headroom", 13446387f866SBrian Austin &val32); 13456387f866SBrian Austin if (ret >= 0) { 13466387f866SBrian Austin val32 |= CS35L35_VALID_PDATA; 13476387f866SBrian Austin classh_config->classh_headroom = val32; 13486387f866SBrian Austin } 13496387f866SBrian Austin 13506387f866SBrian Austin ret = of_property_read_u32(classh, 13516387f866SBrian Austin "cirrus,classh-wk-fet-disable", 13526387f866SBrian Austin &val32); 13536387f866SBrian Austin if (ret >= 0) 13546387f866SBrian Austin classh_config->classh_wk_fet_disable = val32; 13556387f866SBrian Austin 13566387f866SBrian Austin ret = of_property_read_u32(classh, "cirrus,classh-wk-fet-delay", 13576387f866SBrian Austin &val32); 13586387f866SBrian Austin if (ret >= 0) { 13596387f866SBrian Austin val32 |= CS35L35_VALID_PDATA; 13606387f866SBrian Austin classh_config->classh_wk_fet_delay = val32; 13616387f866SBrian Austin } 13626387f866SBrian Austin 13636387f866SBrian Austin ret = of_property_read_u32(classh, "cirrus,classh-wk-fet-thld", 13646387f866SBrian Austin &val32); 13656387f866SBrian Austin if (ret >= 0) 13666387f866SBrian Austin classh_config->classh_wk_fet_thld = val32; 13676387f866SBrian Austin 13686387f866SBrian Austin ret = of_property_read_u32(classh, "cirrus,classh-vpch-auto", 13696387f866SBrian Austin &val32); 13706387f866SBrian Austin if (ret >= 0) { 13716387f866SBrian Austin val32 |= CS35L35_VALID_PDATA; 13726387f866SBrian Austin classh_config->classh_vpch_auto = val32; 13736387f866SBrian Austin } 13746387f866SBrian Austin 13756387f866SBrian Austin ret = of_property_read_u32(classh, "cirrus,classh-vpch-rate", 13766387f866SBrian Austin &val32); 13776387f866SBrian Austin if (ret >= 0) { 13786387f866SBrian Austin val32 |= CS35L35_VALID_PDATA; 13796387f866SBrian Austin classh_config->classh_vpch_rate = val32; 13806387f866SBrian Austin } 13816387f866SBrian Austin 13826387f866SBrian Austin ret = of_property_read_u32(classh, "cirrus,classh-vpch-man", 13836387f866SBrian Austin &val32); 13846387f866SBrian Austin if (ret >= 0) 13856387f866SBrian Austin classh_config->classh_vpch_man = val32; 13866387f866SBrian Austin } 13876387f866SBrian Austin of_node_put(classh); 13886387f866SBrian Austin 13896387f866SBrian Austin /* frame depth location */ 13906387f866SBrian Austin signal_format = of_get_child_by_name(np, "cirrus,monitor-signal-format"); 13916387f866SBrian Austin monitor_config->is_present = signal_format ? true : false; 13926387f866SBrian Austin if (monitor_config->is_present) { 13936387f866SBrian Austin ret = of_property_read_u8_array(signal_format, "cirrus,imon", 139406bdf385SCharles Keepax monitor_array, imon_array_size); 13956387f866SBrian Austin if (!ret) { 13966387f866SBrian Austin monitor_config->imon_specs = true; 13976387f866SBrian Austin monitor_config->imon_dpth = monitor_array[0]; 13986387f866SBrian Austin monitor_config->imon_loc = monitor_array[1]; 13996387f866SBrian Austin monitor_config->imon_frm = monitor_array[2]; 140006bdf385SCharles Keepax monitor_config->imon_scale = monitor_array[3]; 14016387f866SBrian Austin } 14026387f866SBrian Austin ret = of_property_read_u8_array(signal_format, "cirrus,vmon", 140306bdf385SCharles Keepax monitor_array, mon_array_size); 14046387f866SBrian Austin if (!ret) { 14056387f866SBrian Austin monitor_config->vmon_specs = true; 14066387f866SBrian Austin monitor_config->vmon_dpth = monitor_array[0]; 14076387f866SBrian Austin monitor_config->vmon_loc = monitor_array[1]; 14086387f866SBrian Austin monitor_config->vmon_frm = monitor_array[2]; 14096387f866SBrian Austin } 14106387f866SBrian Austin ret = of_property_read_u8_array(signal_format, "cirrus,vpmon", 141106bdf385SCharles Keepax monitor_array, mon_array_size); 14126387f866SBrian Austin if (!ret) { 14136387f866SBrian Austin monitor_config->vpmon_specs = true; 14146387f866SBrian Austin monitor_config->vpmon_dpth = monitor_array[0]; 14156387f866SBrian Austin monitor_config->vpmon_loc = monitor_array[1]; 14166387f866SBrian Austin monitor_config->vpmon_frm = monitor_array[2]; 14176387f866SBrian Austin } 14186387f866SBrian Austin ret = of_property_read_u8_array(signal_format, "cirrus,vbstmon", 141906bdf385SCharles Keepax monitor_array, mon_array_size); 14206387f866SBrian Austin if (!ret) { 14216387f866SBrian Austin monitor_config->vbstmon_specs = true; 14226387f866SBrian Austin monitor_config->vbstmon_dpth = monitor_array[0]; 14236387f866SBrian Austin monitor_config->vbstmon_loc = monitor_array[1]; 14246387f866SBrian Austin monitor_config->vbstmon_frm = monitor_array[2]; 14256387f866SBrian Austin } 14266387f866SBrian Austin ret = of_property_read_u8_array(signal_format, "cirrus,vpbrstat", 142706bdf385SCharles Keepax monitor_array, mon_array_size); 14286387f866SBrian Austin if (!ret) { 14296387f866SBrian Austin monitor_config->vpbrstat_specs = true; 14306387f866SBrian Austin monitor_config->vpbrstat_dpth = monitor_array[0]; 14316387f866SBrian Austin monitor_config->vpbrstat_loc = monitor_array[1]; 14326387f866SBrian Austin monitor_config->vpbrstat_frm = monitor_array[2]; 14336387f866SBrian Austin } 14346387f866SBrian Austin ret = of_property_read_u8_array(signal_format, "cirrus,zerofill", 143506bdf385SCharles Keepax monitor_array, mon_array_size); 14366387f866SBrian Austin if (!ret) { 14376387f866SBrian Austin monitor_config->zerofill_specs = true; 14386387f866SBrian Austin monitor_config->zerofill_dpth = monitor_array[0]; 14396387f866SBrian Austin monitor_config->zerofill_loc = monitor_array[1]; 14406387f866SBrian Austin monitor_config->zerofill_frm = monitor_array[2]; 14416387f866SBrian Austin } 14426387f866SBrian Austin } 14436387f866SBrian Austin of_node_put(signal_format); 14446387f866SBrian Austin 14456387f866SBrian Austin return 0; 14466387f866SBrian Austin } 14476387f866SBrian Austin 14486387f866SBrian Austin /* Errata Rev A0 */ 14496387f866SBrian Austin static const struct reg_sequence cs35l35_errata_patch[] = { 14506387f866SBrian Austin 14516387f866SBrian Austin { 0x7F, 0x99 }, 14526387f866SBrian Austin { 0x00, 0x99 }, 14536387f866SBrian Austin { 0x52, 0x22 }, 14546387f866SBrian Austin { 0x04, 0x14 }, 14556387f866SBrian Austin { 0x6D, 0x44 }, 14566387f866SBrian Austin { 0x24, 0x10 }, 14576387f866SBrian Austin { 0x58, 0xC4 }, 14586387f866SBrian Austin { 0x00, 0x98 }, 14596387f866SBrian Austin { 0x18, 0x08 }, 14606387f866SBrian Austin { 0x00, 0x00 }, 14616387f866SBrian Austin { 0x7F, 0x00 }, 14626387f866SBrian Austin }; 14636387f866SBrian Austin 14646387f866SBrian Austin static int cs35l35_i2c_probe(struct i2c_client *i2c_client, 14656387f866SBrian Austin const struct i2c_device_id *id) 14666387f866SBrian Austin { 14676387f866SBrian Austin struct cs35l35_private *cs35l35; 14681f758cd9SCharles Keepax struct device *dev = &i2c_client->dev; 14691f758cd9SCharles Keepax struct cs35l35_platform_data *pdata = dev_get_platdata(dev); 14706387f866SBrian Austin int i; 14716387f866SBrian Austin int ret; 14726387f866SBrian Austin unsigned int devid = 0; 14736387f866SBrian Austin unsigned int reg; 14746387f866SBrian Austin 14751f758cd9SCharles Keepax cs35l35 = devm_kzalloc(dev, sizeof(struct cs35l35_private), GFP_KERNEL); 14766387f866SBrian Austin if (!cs35l35) 14776387f866SBrian Austin return -ENOMEM; 14786387f866SBrian Austin 14795d3d0ad6SCharles Keepax cs35l35->dev = dev; 14805d3d0ad6SCharles Keepax 14816387f866SBrian Austin i2c_set_clientdata(i2c_client, cs35l35); 14826387f866SBrian Austin cs35l35->regmap = devm_regmap_init_i2c(i2c_client, &cs35l35_regmap); 14836387f866SBrian Austin if (IS_ERR(cs35l35->regmap)) { 14846387f866SBrian Austin ret = PTR_ERR(cs35l35->regmap); 14851f758cd9SCharles Keepax dev_err(dev, "regmap_init() failed: %d\n", ret); 14866387f866SBrian Austin goto err; 14876387f866SBrian Austin } 14886387f866SBrian Austin 14896387f866SBrian Austin for (i = 0; i < ARRAY_SIZE(cs35l35_supplies); i++) 14906387f866SBrian Austin cs35l35->supplies[i].supply = cs35l35_supplies[i]; 149103ff570cSColin Ian King 14926387f866SBrian Austin cs35l35->num_supplies = ARRAY_SIZE(cs35l35_supplies); 14936387f866SBrian Austin 14941f758cd9SCharles Keepax ret = devm_regulator_bulk_get(dev, cs35l35->num_supplies, 14956387f866SBrian Austin cs35l35->supplies); 14966387f866SBrian Austin if (ret != 0) { 14971f758cd9SCharles Keepax dev_err(dev, "Failed to request core supplies: %d\n", ret); 14986387f866SBrian Austin return ret; 14996387f866SBrian Austin } 15006387f866SBrian Austin 15016387f866SBrian Austin if (pdata) { 15026387f866SBrian Austin cs35l35->pdata = *pdata; 15036387f866SBrian Austin } else { 15041f758cd9SCharles Keepax pdata = devm_kzalloc(dev, sizeof(struct cs35l35_platform_data), 15056387f866SBrian Austin GFP_KERNEL); 15066387f866SBrian Austin if (!pdata) 15076387f866SBrian Austin return -ENOMEM; 15086387f866SBrian Austin if (i2c_client->dev.of_node) { 15096387f866SBrian Austin ret = cs35l35_handle_of_data(i2c_client, pdata); 15106387f866SBrian Austin if (ret != 0) 15116387f866SBrian Austin return ret; 15126387f866SBrian Austin 15136387f866SBrian Austin } 15146387f866SBrian Austin cs35l35->pdata = *pdata; 15156387f866SBrian Austin } 15166387f866SBrian Austin 15176387f866SBrian Austin ret = regulator_bulk_enable(cs35l35->num_supplies, 15186387f866SBrian Austin cs35l35->supplies); 15196387f866SBrian Austin if (ret != 0) { 15201f758cd9SCharles Keepax dev_err(dev, "Failed to enable core supplies: %d\n", ret); 15216387f866SBrian Austin return ret; 15226387f866SBrian Austin } 15236387f866SBrian Austin 15246387f866SBrian Austin /* returning NULL can be valid if in stereo mode */ 15251f758cd9SCharles Keepax cs35l35->reset_gpio = devm_gpiod_get_optional(dev, "reset", 15261f758cd9SCharles Keepax GPIOD_OUT_LOW); 15276387f866SBrian Austin if (IS_ERR(cs35l35->reset_gpio)) { 15286387f866SBrian Austin ret = PTR_ERR(cs35l35->reset_gpio); 15298e71321dSCharles Keepax cs35l35->reset_gpio = NULL; 15306387f866SBrian Austin if (ret == -EBUSY) { 15311f758cd9SCharles Keepax dev_info(dev, 15326387f866SBrian Austin "Reset line busy, assuming shared reset\n"); 15336387f866SBrian Austin } else { 15341f758cd9SCharles Keepax dev_err(dev, "Failed to get reset GPIO: %d\n", ret); 15356387f866SBrian Austin goto err; 15366387f866SBrian Austin } 15376387f866SBrian Austin } 15386387f866SBrian Austin 15396387f866SBrian Austin gpiod_set_value_cansleep(cs35l35->reset_gpio, 1); 15406387f866SBrian Austin 15416387f866SBrian Austin init_completion(&cs35l35->pdn_done); 15426387f866SBrian Austin 15431f758cd9SCharles Keepax ret = devm_request_threaded_irq(dev, i2c_client->irq, NULL, cs35l35_irq, 1544bf5043d6SCharles Keepax IRQF_ONESHOT | IRQF_TRIGGER_LOW | 1545bf5043d6SCharles Keepax IRQF_SHARED, "cs35l35", cs35l35); 15466387f866SBrian Austin if (ret != 0) { 15471f758cd9SCharles Keepax dev_err(dev, "Failed to request IRQ: %d\n", ret); 15486387f866SBrian Austin goto err; 15496387f866SBrian Austin } 15506387f866SBrian Austin /* initialize codec */ 15516387f866SBrian Austin ret = regmap_read(cs35l35->regmap, CS35L35_DEVID_AB, ®); 15526387f866SBrian Austin 15536387f866SBrian Austin devid = (reg & 0xFF) << 12; 15546387f866SBrian Austin ret = regmap_read(cs35l35->regmap, CS35L35_DEVID_CD, ®); 15556387f866SBrian Austin devid |= (reg & 0xFF) << 4; 15566387f866SBrian Austin ret = regmap_read(cs35l35->regmap, CS35L35_DEVID_E, ®); 15576387f866SBrian Austin devid |= (reg & 0xF0) >> 4; 15586387f866SBrian Austin 15596387f866SBrian Austin if (devid != CS35L35_CHIP_ID) { 15601f758cd9SCharles Keepax dev_err(dev, "CS35L35 Device ID (%X). Expected ID %X\n", 15616387f866SBrian Austin devid, CS35L35_CHIP_ID); 15626387f866SBrian Austin ret = -ENODEV; 15636387f866SBrian Austin goto err; 15646387f866SBrian Austin } 15656387f866SBrian Austin 15666387f866SBrian Austin ret = regmap_read(cs35l35->regmap, CS35L35_REV_ID, ®); 15676387f866SBrian Austin if (ret < 0) { 15681f758cd9SCharles Keepax dev_err(dev, "Get Revision ID failed: %d\n", ret); 15696387f866SBrian Austin goto err; 15706387f866SBrian Austin } 15716387f866SBrian Austin 15726387f866SBrian Austin ret = regmap_register_patch(cs35l35->regmap, cs35l35_errata_patch, 15736387f866SBrian Austin ARRAY_SIZE(cs35l35_errata_patch)); 15746387f866SBrian Austin if (ret < 0) { 15751f758cd9SCharles Keepax dev_err(dev, "Failed to apply errata patch: %d\n", ret); 15766387f866SBrian Austin goto err; 15776387f866SBrian Austin } 15786387f866SBrian Austin 15791f758cd9SCharles Keepax dev_info(dev, "Cirrus Logic CS35L35 (%x), Revision: %02X\n", 158082875163SAxel Lin devid, reg & 0xFF); 15816387f866SBrian Austin 15826387f866SBrian Austin /* Set the INT Masks for critical errors */ 15836387f866SBrian Austin regmap_write(cs35l35->regmap, CS35L35_INT_MASK_1, 15846387f866SBrian Austin CS35L35_INT1_CRIT_MASK); 15856387f866SBrian Austin regmap_write(cs35l35->regmap, CS35L35_INT_MASK_2, 15866387f866SBrian Austin CS35L35_INT2_CRIT_MASK); 15876387f866SBrian Austin regmap_write(cs35l35->regmap, CS35L35_INT_MASK_3, 15886387f866SBrian Austin CS35L35_INT3_CRIT_MASK); 15896387f866SBrian Austin regmap_write(cs35l35->regmap, CS35L35_INT_MASK_4, 15906387f866SBrian Austin CS35L35_INT4_CRIT_MASK); 15916387f866SBrian Austin 15926387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, 15936387f866SBrian Austin CS35L35_PWR2_PDN_MASK, 15946387f866SBrian Austin CS35L35_PWR2_PDN_MASK); 15956387f866SBrian Austin 15966387f866SBrian Austin if (cs35l35->pdata.bst_pdn_fet_on) 15976387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, 15986387f866SBrian Austin CS35L35_PDN_BST_MASK, 15996387f866SBrian Austin 1 << CS35L35_PDN_BST_FETON_SHIFT); 16006387f866SBrian Austin else 16016387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, 16026387f866SBrian Austin CS35L35_PDN_BST_MASK, 16036387f866SBrian Austin 1 << CS35L35_PDN_BST_FETOFF_SHIFT); 16046387f866SBrian Austin 16056387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL3, 16066387f866SBrian Austin CS35L35_PWR3_PDN_MASK, 16076387f866SBrian Austin CS35L35_PWR3_PDN_MASK); 16086387f866SBrian Austin 16096387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PROTECT_CTL, 16106387f866SBrian Austin CS35L35_AMP_MUTE_MASK, 1 << CS35L35_AMP_MUTE_SHIFT); 16116387f866SBrian Austin 16121f758cd9SCharles Keepax ret = snd_soc_register_codec(dev, &soc_codec_dev_cs35l35, cs35l35_dai, 16136387f866SBrian Austin ARRAY_SIZE(cs35l35_dai)); 16146387f866SBrian Austin if (ret < 0) { 16151f758cd9SCharles Keepax dev_err(dev, "Failed to register codec: %d\n", ret); 16166387f866SBrian Austin goto err; 16176387f866SBrian Austin } 16186387f866SBrian Austin 16191bb06adaSCharles Keepax return 0; 16201bb06adaSCharles Keepax 16216387f866SBrian Austin err: 16226387f866SBrian Austin regulator_bulk_disable(cs35l35->num_supplies, 16236387f866SBrian Austin cs35l35->supplies); 16246387f866SBrian Austin gpiod_set_value_cansleep(cs35l35->reset_gpio, 0); 16256387f866SBrian Austin 16266387f866SBrian Austin return ret; 16276387f866SBrian Austin } 16286387f866SBrian Austin 16296387f866SBrian Austin static int cs35l35_i2c_remove(struct i2c_client *client) 16306387f866SBrian Austin { 16316387f866SBrian Austin snd_soc_unregister_codec(&client->dev); 16326387f866SBrian Austin return 0; 16336387f866SBrian Austin } 16346387f866SBrian Austin 16356387f866SBrian Austin static const struct of_device_id cs35l35_of_match[] = { 16366387f866SBrian Austin {.compatible = "cirrus,cs35l35"}, 16376387f866SBrian Austin {}, 16386387f866SBrian Austin }; 16396387f866SBrian Austin MODULE_DEVICE_TABLE(of, cs35l35_of_match); 16406387f866SBrian Austin 16416387f866SBrian Austin static const struct i2c_device_id cs35l35_id[] = { 16426387f866SBrian Austin {"cs35l35", 0}, 16436387f866SBrian Austin {} 16446387f866SBrian Austin }; 16456387f866SBrian Austin 16466387f866SBrian Austin MODULE_DEVICE_TABLE(i2c, cs35l35_id); 16476387f866SBrian Austin 16486387f866SBrian Austin static struct i2c_driver cs35l35_i2c_driver = { 16496387f866SBrian Austin .driver = { 16506387f866SBrian Austin .name = "cs35l35", 16516387f866SBrian Austin .of_match_table = cs35l35_of_match, 16526387f866SBrian Austin }, 16536387f866SBrian Austin .id_table = cs35l35_id, 16546387f866SBrian Austin .probe = cs35l35_i2c_probe, 16556387f866SBrian Austin .remove = cs35l35_i2c_remove, 16566387f866SBrian Austin }; 16576387f866SBrian Austin 16586387f866SBrian Austin module_i2c_driver(cs35l35_i2c_driver); 16596387f866SBrian Austin 16606387f866SBrian Austin MODULE_DESCRIPTION("ASoC CS35L35 driver"); 16616387f866SBrian Austin MODULE_AUTHOR("Brian Austin, Cirrus Logic Inc, <brian.austin@cirrus.com>"); 16626387f866SBrian Austin MODULE_LICENSE("GPL"); 1663