1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 26387f866SBrian Austin /* 36387f866SBrian Austin * cs35l35.c -- CS35L35 ALSA SoC audio driver 46387f866SBrian Austin * 56387f866SBrian Austin * Copyright 2017 Cirrus Logic, Inc. 66387f866SBrian Austin * 76387f866SBrian Austin * Author: Brian Austin <brian.austin@cirrus.com> 86387f866SBrian Austin */ 96387f866SBrian Austin 106387f866SBrian Austin #include <linux/module.h> 116387f866SBrian Austin #include <linux/moduleparam.h> 126387f866SBrian Austin #include <linux/kernel.h> 136387f866SBrian Austin #include <linux/init.h> 146387f866SBrian Austin #include <linux/delay.h> 156387f866SBrian Austin #include <linux/i2c.h> 166387f866SBrian Austin #include <linux/slab.h> 176387f866SBrian Austin #include <linux/platform_device.h> 186387f866SBrian Austin #include <linux/regulator/consumer.h> 196387f866SBrian Austin #include <linux/gpio/consumer.h> 206387f866SBrian Austin #include <linux/of_device.h> 216387f866SBrian Austin #include <linux/of_gpio.h> 226387f866SBrian Austin #include <linux/regmap.h> 236387f866SBrian Austin #include <sound/core.h> 246387f866SBrian Austin #include <sound/pcm.h> 256387f866SBrian Austin #include <sound/pcm_params.h> 266387f866SBrian Austin #include <sound/soc.h> 276387f866SBrian Austin #include <sound/soc-dapm.h> 286387f866SBrian Austin #include <linux/gpio.h> 296387f866SBrian Austin #include <sound/initval.h> 306387f866SBrian Austin #include <sound/tlv.h> 316387f866SBrian Austin #include <sound/cs35l35.h> 326387f866SBrian Austin #include <linux/of_irq.h> 336387f866SBrian Austin #include <linux/completion.h> 346387f866SBrian Austin 356387f866SBrian Austin #include "cs35l35.h" 3660ba916dSCharles Keepax #include "cirrus_legacy.h" 376387f866SBrian Austin 386387f866SBrian Austin /* 396387f866SBrian Austin * Some fields take zero as a valid value so use a high bit flag that won't 406387f866SBrian Austin * get written to the device to mark those. 416387f866SBrian Austin */ 426387f866SBrian Austin #define CS35L35_VALID_PDATA 0x80000000 436387f866SBrian Austin 446387f866SBrian Austin static const struct reg_default cs35l35_reg[] = { 456387f866SBrian Austin {CS35L35_PWRCTL1, 0x01}, 466387f866SBrian Austin {CS35L35_PWRCTL2, 0x11}, 476387f866SBrian Austin {CS35L35_PWRCTL3, 0x00}, 486387f866SBrian Austin {CS35L35_CLK_CTL1, 0x04}, 49fbeea237SCharles Keepax {CS35L35_CLK_CTL2, 0x12}, 506387f866SBrian Austin {CS35L35_CLK_CTL3, 0xCF}, 516387f866SBrian Austin {CS35L35_SP_FMT_CTL1, 0x20}, 526387f866SBrian Austin {CS35L35_SP_FMT_CTL2, 0x00}, 536387f866SBrian Austin {CS35L35_SP_FMT_CTL3, 0x02}, 546387f866SBrian Austin {CS35L35_MAG_COMP_CTL, 0x00}, 556387f866SBrian Austin {CS35L35_AMP_INP_DRV_CTL, 0x01}, 566387f866SBrian Austin {CS35L35_AMP_DIG_VOL_CTL, 0x12}, 576387f866SBrian Austin {CS35L35_AMP_DIG_VOL, 0x00}, 586387f866SBrian Austin {CS35L35_ADV_DIG_VOL, 0x00}, 596387f866SBrian Austin {CS35L35_PROTECT_CTL, 0x06}, 606387f866SBrian Austin {CS35L35_AMP_GAIN_AUD_CTL, 0x13}, 616387f866SBrian Austin {CS35L35_AMP_GAIN_PDM_CTL, 0x00}, 626387f866SBrian Austin {CS35L35_AMP_GAIN_ADV_CTL, 0x00}, 636387f866SBrian Austin {CS35L35_GPI_CTL, 0x00}, 646387f866SBrian Austin {CS35L35_BST_CVTR_V_CTL, 0x00}, 656387f866SBrian Austin {CS35L35_BST_PEAK_I, 0x07}, 666387f866SBrian Austin {CS35L35_BST_RAMP_CTL, 0x85}, 676387f866SBrian Austin {CS35L35_BST_CONV_COEF_1, 0x24}, 686387f866SBrian Austin {CS35L35_BST_CONV_COEF_2, 0x24}, 69fbeea237SCharles Keepax {CS35L35_BST_CONV_SLOPE_COMP, 0x4E}, 706387f866SBrian Austin {CS35L35_BST_CONV_SW_FREQ, 0x04}, 716387f866SBrian Austin {CS35L35_CLASS_H_CTL, 0x0B}, 726387f866SBrian Austin {CS35L35_CLASS_H_HEADRM_CTL, 0x0B}, 736387f866SBrian Austin {CS35L35_CLASS_H_RELEASE_RATE, 0x08}, 746387f866SBrian Austin {CS35L35_CLASS_H_FET_DRIVE_CTL, 0x41}, 756387f866SBrian Austin {CS35L35_CLASS_H_VP_CTL, 0xC5}, 766387f866SBrian Austin {CS35L35_VPBR_CTL, 0x0A}, 77fbeea237SCharles Keepax {CS35L35_VPBR_VOL_CTL, 0x90}, 786387f866SBrian Austin {CS35L35_VPBR_TIMING_CTL, 0x6A}, 79fbeea237SCharles Keepax {CS35L35_VPBR_MODE_VOL_CTL, 0x00}, 806387f866SBrian Austin {CS35L35_SPKR_MON_CTL, 0xC0}, 816387f866SBrian Austin {CS35L35_IMON_SCALE_CTL, 0x30}, 826387f866SBrian Austin {CS35L35_AUDIN_RXLOC_CTL, 0x00}, 836387f866SBrian Austin {CS35L35_ADVIN_RXLOC_CTL, 0x80}, 846387f866SBrian Austin {CS35L35_VMON_TXLOC_CTL, 0x00}, 856387f866SBrian Austin {CS35L35_IMON_TXLOC_CTL, 0x80}, 866387f866SBrian Austin {CS35L35_VPMON_TXLOC_CTL, 0x04}, 876387f866SBrian Austin {CS35L35_VBSTMON_TXLOC_CTL, 0x84}, 886387f866SBrian Austin {CS35L35_VPBR_STATUS_TXLOC_CTL, 0x04}, 896387f866SBrian Austin {CS35L35_ZERO_FILL_LOC_CTL, 0x00}, 906387f866SBrian Austin {CS35L35_AUDIN_DEPTH_CTL, 0x0F}, 916387f866SBrian Austin {CS35L35_SPKMON_DEPTH_CTL, 0x0F}, 926387f866SBrian Austin {CS35L35_SUPMON_DEPTH_CTL, 0x0F}, 936387f866SBrian Austin {CS35L35_ZEROFILL_DEPTH_CTL, 0x00}, 946387f866SBrian Austin {CS35L35_MULT_DEV_SYNCH1, 0x02}, 956387f866SBrian Austin {CS35L35_MULT_DEV_SYNCH2, 0x80}, 966387f866SBrian Austin {CS35L35_PROT_RELEASE_CTL, 0x00}, 976387f866SBrian Austin {CS35L35_DIAG_MODE_REG_LOCK, 0x00}, 986387f866SBrian Austin {CS35L35_DIAG_MODE_CTL_1, 0x40}, 996387f866SBrian Austin {CS35L35_DIAG_MODE_CTL_2, 0x00}, 1006387f866SBrian Austin {CS35L35_INT_MASK_1, 0xFF}, 1016387f866SBrian Austin {CS35L35_INT_MASK_2, 0xFF}, 1026387f866SBrian Austin {CS35L35_INT_MASK_3, 0xFF}, 1036387f866SBrian Austin {CS35L35_INT_MASK_4, 0xFF}, 1046387f866SBrian Austin 1056387f866SBrian Austin }; 1066387f866SBrian Austin 1076387f866SBrian Austin static bool cs35l35_volatile_register(struct device *dev, unsigned int reg) 1086387f866SBrian Austin { 1096387f866SBrian Austin switch (reg) { 1106387f866SBrian Austin case CS35L35_INT_STATUS_1: 1116387f866SBrian Austin case CS35L35_INT_STATUS_2: 1126387f866SBrian Austin case CS35L35_INT_STATUS_3: 1136387f866SBrian Austin case CS35L35_INT_STATUS_4: 1146387f866SBrian Austin case CS35L35_PLL_STATUS: 1156387f866SBrian Austin case CS35L35_OTP_TRIM_STATUS: 1166387f866SBrian Austin return true; 1176387f866SBrian Austin default: 1186387f866SBrian Austin return false; 1196387f866SBrian Austin } 1206387f866SBrian Austin } 1216387f866SBrian Austin 1226387f866SBrian Austin static bool cs35l35_readable_register(struct device *dev, unsigned int reg) 1236387f866SBrian Austin { 1246387f866SBrian Austin switch (reg) { 1256387f866SBrian Austin case CS35L35_DEVID_AB ... CS35L35_PWRCTL3: 1266387f866SBrian Austin case CS35L35_CLK_CTL1 ... CS35L35_SP_FMT_CTL3: 1276387f866SBrian Austin case CS35L35_MAG_COMP_CTL ... CS35L35_AMP_GAIN_AUD_CTL: 1286387f866SBrian Austin case CS35L35_AMP_GAIN_PDM_CTL ... CS35L35_BST_PEAK_I: 1296387f866SBrian Austin case CS35L35_BST_RAMP_CTL ... CS35L35_BST_CONV_SW_FREQ: 1306387f866SBrian Austin case CS35L35_CLASS_H_CTL ... CS35L35_CLASS_H_VP_CTL: 1316387f866SBrian Austin case CS35L35_CLASS_H_STATUS: 1326387f866SBrian Austin case CS35L35_VPBR_CTL ... CS35L35_VPBR_MODE_VOL_CTL: 1336387f866SBrian Austin case CS35L35_VPBR_ATTEN_STATUS: 1346387f866SBrian Austin case CS35L35_SPKR_MON_CTL: 1356387f866SBrian Austin case CS35L35_IMON_SCALE_CTL ... CS35L35_ZEROFILL_DEPTH_CTL: 1366387f866SBrian Austin case CS35L35_MULT_DEV_SYNCH1 ... CS35L35_PROT_RELEASE_CTL: 1376387f866SBrian Austin case CS35L35_DIAG_MODE_REG_LOCK ... CS35L35_DIAG_MODE_CTL_2: 1386387f866SBrian Austin case CS35L35_INT_MASK_1 ... CS35L35_PLL_STATUS: 1396387f866SBrian Austin case CS35L35_OTP_TRIM_STATUS: 1406387f866SBrian Austin return true; 1416387f866SBrian Austin default: 1426387f866SBrian Austin return false; 1436387f866SBrian Austin } 1446387f866SBrian Austin } 1456387f866SBrian Austin 1466387f866SBrian Austin static bool cs35l35_precious_register(struct device *dev, unsigned int reg) 1476387f866SBrian Austin { 1486387f866SBrian Austin switch (reg) { 1496387f866SBrian Austin case CS35L35_INT_STATUS_1: 1506387f866SBrian Austin case CS35L35_INT_STATUS_2: 1516387f866SBrian Austin case CS35L35_INT_STATUS_3: 1526387f866SBrian Austin case CS35L35_INT_STATUS_4: 1536387f866SBrian Austin case CS35L35_PLL_STATUS: 1546387f866SBrian Austin case CS35L35_OTP_TRIM_STATUS: 1556387f866SBrian Austin return true; 1566387f866SBrian Austin default: 1576387f866SBrian Austin return false; 1586387f866SBrian Austin } 1596387f866SBrian Austin } 1606387f866SBrian Austin 161dc43f46aSCharles Keepax static void cs35l35_reset(struct cs35l35_private *cs35l35) 162dc43f46aSCharles Keepax { 163dc43f46aSCharles Keepax gpiod_set_value_cansleep(cs35l35->reset_gpio, 0); 164dc43f46aSCharles Keepax usleep_range(2000, 2100); 165dc43f46aSCharles Keepax gpiod_set_value_cansleep(cs35l35->reset_gpio, 1); 166dc43f46aSCharles Keepax usleep_range(1000, 1100); 167dc43f46aSCharles Keepax } 168dc43f46aSCharles Keepax 16977b329d1SCharles Keepax static int cs35l35_wait_for_pdn(struct cs35l35_private *cs35l35) 17077b329d1SCharles Keepax { 17177b329d1SCharles Keepax int ret; 17277b329d1SCharles Keepax 17377b329d1SCharles Keepax if (cs35l35->pdata.ext_bst) { 17477b329d1SCharles Keepax usleep_range(5000, 5500); 17577b329d1SCharles Keepax return 0; 17677b329d1SCharles Keepax } 17777b329d1SCharles Keepax 17877b329d1SCharles Keepax reinit_completion(&cs35l35->pdn_done); 17977b329d1SCharles Keepax 18077b329d1SCharles Keepax ret = wait_for_completion_timeout(&cs35l35->pdn_done, 18177b329d1SCharles Keepax msecs_to_jiffies(100)); 18277b329d1SCharles Keepax if (ret == 0) { 18377b329d1SCharles Keepax dev_err(cs35l35->dev, "PDN_DONE did not complete\n"); 18477b329d1SCharles Keepax return -ETIMEDOUT; 18577b329d1SCharles Keepax } 18677b329d1SCharles Keepax 18777b329d1SCharles Keepax return 0; 18877b329d1SCharles Keepax } 18977b329d1SCharles Keepax 1906387f866SBrian Austin static int cs35l35_sdin_event(struct snd_soc_dapm_widget *w, 1916387f866SBrian Austin struct snd_kcontrol *kcontrol, int event) 1926387f866SBrian Austin { 19386c2eddfSKuninori Morimoto struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 19486c2eddfSKuninori Morimoto struct cs35l35_private *cs35l35 = snd_soc_component_get_drvdata(component); 1956387f866SBrian Austin int ret = 0; 1966387f866SBrian Austin 1976387f866SBrian Austin switch (event) { 1986387f866SBrian Austin case SND_SOC_DAPM_PRE_PMU: 1996387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL1, 2006387f866SBrian Austin CS35L35_MCLK_DIS_MASK, 2016387f866SBrian Austin 0 << CS35L35_MCLK_DIS_SHIFT); 2026387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL1, 2036387f866SBrian Austin CS35L35_DISCHG_FILT_MASK, 2046387f866SBrian Austin 0 << CS35L35_DISCHG_FILT_SHIFT); 2056387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL1, 2066387f866SBrian Austin CS35L35_PDN_ALL_MASK, 0); 2076387f866SBrian Austin break; 2086387f866SBrian Austin case SND_SOC_DAPM_POST_PMD: 2096387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL1, 2106387f866SBrian Austin CS35L35_DISCHG_FILT_MASK, 2116387f866SBrian Austin 1 << CS35L35_DISCHG_FILT_SHIFT); 2126387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL1, 2136387f866SBrian Austin CS35L35_PDN_ALL_MASK, 1); 2146387f866SBrian Austin 2152c84afb5SCharles Keepax /* Already muted, so disable volume ramp for faster shutdown */ 2162c84afb5SCharles Keepax regmap_update_bits(cs35l35->regmap, CS35L35_AMP_DIG_VOL_CTL, 2172c84afb5SCharles Keepax CS35L35_AMP_DIGSFT_MASK, 0); 2182c84afb5SCharles Keepax 21977b329d1SCharles Keepax ret = cs35l35_wait_for_pdn(cs35l35); 2206387f866SBrian Austin 2216387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL1, 2226387f866SBrian Austin CS35L35_MCLK_DIS_MASK, 2236387f866SBrian Austin 1 << CS35L35_MCLK_DIS_SHIFT); 2242c84afb5SCharles Keepax 2252c84afb5SCharles Keepax regmap_update_bits(cs35l35->regmap, CS35L35_AMP_DIG_VOL_CTL, 2262c84afb5SCharles Keepax CS35L35_AMP_DIGSFT_MASK, 2272c84afb5SCharles Keepax 1 << CS35L35_AMP_DIGSFT_SHIFT); 2286387f866SBrian Austin break; 2296387f866SBrian Austin default: 23086c2eddfSKuninori Morimoto dev_err(component->dev, "Invalid event = 0x%x\n", event); 2316387f866SBrian Austin ret = -EINVAL; 2326387f866SBrian Austin } 2336387f866SBrian Austin return ret; 2346387f866SBrian Austin } 2356387f866SBrian Austin 2366387f866SBrian Austin static int cs35l35_main_amp_event(struct snd_soc_dapm_widget *w, 2376387f866SBrian Austin struct snd_kcontrol *kcontrol, int event) 2386387f866SBrian Austin { 23986c2eddfSKuninori Morimoto struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 24086c2eddfSKuninori Morimoto struct cs35l35_private *cs35l35 = snd_soc_component_get_drvdata(component); 2416387f866SBrian Austin unsigned int reg[4]; 2426387f866SBrian Austin int i; 2436387f866SBrian Austin 2446387f866SBrian Austin switch (event) { 2456387f866SBrian Austin case SND_SOC_DAPM_PRE_PMU: 2466387f866SBrian Austin if (cs35l35->pdata.bst_pdn_fet_on) 2476387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, 2486387f866SBrian Austin CS35L35_PDN_BST_MASK, 2496387f866SBrian Austin 0 << CS35L35_PDN_BST_FETON_SHIFT); 2506387f866SBrian Austin else 2516387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, 2526387f866SBrian Austin CS35L35_PDN_BST_MASK, 2536387f866SBrian Austin 0 << CS35L35_PDN_BST_FETOFF_SHIFT); 2546387f866SBrian Austin break; 2556387f866SBrian Austin case SND_SOC_DAPM_POST_PMU: 2566387f866SBrian Austin usleep_range(5000, 5100); 2576387f866SBrian Austin /* If in PDM mode we must use VP for Voltage control */ 2586387f866SBrian Austin if (cs35l35->pdm_mode) 2596387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 2606387f866SBrian Austin CS35L35_BST_CVTR_V_CTL, 2616387f866SBrian Austin CS35L35_BST_CTL_MASK, 2626387f866SBrian Austin 0 << CS35L35_BST_CTL_SHIFT); 2636387f866SBrian Austin 2646387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PROTECT_CTL, 2656387f866SBrian Austin CS35L35_AMP_MUTE_MASK, 0); 2666387f866SBrian Austin 2676387f866SBrian Austin for (i = 0; i < 2; i++) 2686387f866SBrian Austin regmap_bulk_read(cs35l35->regmap, CS35L35_INT_STATUS_1, 2696387f866SBrian Austin ®, ARRAY_SIZE(reg)); 2706387f866SBrian Austin 2716387f866SBrian Austin break; 2726387f866SBrian Austin case SND_SOC_DAPM_PRE_PMD: 2736387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PROTECT_CTL, 2746387f866SBrian Austin CS35L35_AMP_MUTE_MASK, 2756387f866SBrian Austin 1 << CS35L35_AMP_MUTE_SHIFT); 2766387f866SBrian Austin if (cs35l35->pdata.bst_pdn_fet_on) 2776387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, 2786387f866SBrian Austin CS35L35_PDN_BST_MASK, 2796387f866SBrian Austin 1 << CS35L35_PDN_BST_FETON_SHIFT); 2806387f866SBrian Austin else 2816387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, 2826387f866SBrian Austin CS35L35_PDN_BST_MASK, 2836387f866SBrian Austin 1 << CS35L35_PDN_BST_FETOFF_SHIFT); 2846387f866SBrian Austin break; 2856387f866SBrian Austin case SND_SOC_DAPM_POST_PMD: 2866387f866SBrian Austin usleep_range(5000, 5100); 2876387f866SBrian Austin /* 2886387f866SBrian Austin * If PDM mode we should switch back to pdata value 2896387f866SBrian Austin * for Voltage control when we go down 2906387f866SBrian Austin */ 2916387f866SBrian Austin if (cs35l35->pdm_mode) 2926387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 2936387f866SBrian Austin CS35L35_BST_CVTR_V_CTL, 2946387f866SBrian Austin CS35L35_BST_CTL_MASK, 2956387f866SBrian Austin cs35l35->pdata.bst_vctl 2966387f866SBrian Austin << CS35L35_BST_CTL_SHIFT); 2976387f866SBrian Austin 2986387f866SBrian Austin break; 2996387f866SBrian Austin default: 30086c2eddfSKuninori Morimoto dev_err(component->dev, "Invalid event = 0x%x\n", event); 3016387f866SBrian Austin } 3026387f866SBrian Austin return 0; 3036387f866SBrian Austin } 3046387f866SBrian Austin 3056387f866SBrian Austin static DECLARE_TLV_DB_SCALE(amp_gain_tlv, 0, 1, 1); 3066387f866SBrian Austin static DECLARE_TLV_DB_SCALE(dig_vol_tlv, -10200, 50, 0); 3076387f866SBrian Austin 3086387f866SBrian Austin static const struct snd_kcontrol_new cs35l35_aud_controls[] = { 3096387f866SBrian Austin SOC_SINGLE_SX_TLV("Digital Audio Volume", CS35L35_AMP_DIG_VOL, 3106387f866SBrian Austin 0, 0x34, 0xE4, dig_vol_tlv), 3116387f866SBrian Austin SOC_SINGLE_TLV("Analog Audio Volume", CS35L35_AMP_GAIN_AUD_CTL, 0, 19, 0, 3126387f866SBrian Austin amp_gain_tlv), 3136387f866SBrian Austin SOC_SINGLE_TLV("PDM Volume", CS35L35_AMP_GAIN_PDM_CTL, 0, 19, 0, 3146387f866SBrian Austin amp_gain_tlv), 3156387f866SBrian Austin }; 3166387f866SBrian Austin 3176387f866SBrian Austin static const struct snd_kcontrol_new cs35l35_adv_controls[] = { 3186387f866SBrian Austin SOC_SINGLE_SX_TLV("Digital Advisory Volume", CS35L35_ADV_DIG_VOL, 3196387f866SBrian Austin 0, 0x34, 0xE4, dig_vol_tlv), 3206387f866SBrian Austin SOC_SINGLE_TLV("Analog Advisory Volume", CS35L35_AMP_GAIN_ADV_CTL, 0, 19, 0, 3216387f866SBrian Austin amp_gain_tlv), 3226387f866SBrian Austin }; 3236387f866SBrian Austin 3246387f866SBrian Austin static const struct snd_soc_dapm_widget cs35l35_dapm_widgets[] = { 3256387f866SBrian Austin SND_SOC_DAPM_AIF_IN_E("SDIN", NULL, 0, CS35L35_PWRCTL3, 1, 1, 3266387f866SBrian Austin cs35l35_sdin_event, SND_SOC_DAPM_PRE_PMU | 3276387f866SBrian Austin SND_SOC_DAPM_POST_PMD), 3286387f866SBrian Austin SND_SOC_DAPM_AIF_OUT("SDOUT", NULL, 0, CS35L35_PWRCTL3, 2, 1), 3296387f866SBrian Austin 3306387f866SBrian Austin SND_SOC_DAPM_OUTPUT("SPK"), 3316387f866SBrian Austin 3326387f866SBrian Austin SND_SOC_DAPM_INPUT("VP"), 3336387f866SBrian Austin SND_SOC_DAPM_INPUT("VBST"), 3346387f866SBrian Austin SND_SOC_DAPM_INPUT("ISENSE"), 3356387f866SBrian Austin SND_SOC_DAPM_INPUT("VSENSE"), 3366387f866SBrian Austin 3376387f866SBrian Austin SND_SOC_DAPM_ADC("VMON ADC", NULL, CS35L35_PWRCTL2, 7, 1), 3386387f866SBrian Austin SND_SOC_DAPM_ADC("IMON ADC", NULL, CS35L35_PWRCTL2, 6, 1), 3396387f866SBrian Austin SND_SOC_DAPM_ADC("VPMON ADC", NULL, CS35L35_PWRCTL3, 3, 1), 3406387f866SBrian Austin SND_SOC_DAPM_ADC("VBSTMON ADC", NULL, CS35L35_PWRCTL3, 4, 1), 3416387f866SBrian Austin SND_SOC_DAPM_ADC("CLASS H", NULL, CS35L35_PWRCTL2, 5, 1), 3426387f866SBrian Austin 3436387f866SBrian Austin SND_SOC_DAPM_OUT_DRV_E("Main AMP", CS35L35_PWRCTL2, 0, 1, NULL, 0, 3446387f866SBrian Austin cs35l35_main_amp_event, SND_SOC_DAPM_PRE_PMU | 3456387f866SBrian Austin SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU | 3466387f866SBrian Austin SND_SOC_DAPM_PRE_PMD), 3476387f866SBrian Austin }; 3486387f866SBrian Austin 3496387f866SBrian Austin static const struct snd_soc_dapm_route cs35l35_audio_map[] = { 3506387f866SBrian Austin {"VPMON ADC", NULL, "VP"}, 3516387f866SBrian Austin {"VBSTMON ADC", NULL, "VBST"}, 3526387f866SBrian Austin {"IMON ADC", NULL, "ISENSE"}, 3536387f866SBrian Austin {"VMON ADC", NULL, "VSENSE"}, 3546387f866SBrian Austin {"SDOUT", NULL, "IMON ADC"}, 3556387f866SBrian Austin {"SDOUT", NULL, "VMON ADC"}, 3566387f866SBrian Austin {"SDOUT", NULL, "VBSTMON ADC"}, 3576387f866SBrian Austin {"SDOUT", NULL, "VPMON ADC"}, 3586387f866SBrian Austin {"AMP Capture", NULL, "SDOUT"}, 3596387f866SBrian Austin 3606387f866SBrian Austin {"SDIN", NULL, "AMP Playback"}, 3616387f866SBrian Austin {"CLASS H", NULL, "SDIN"}, 3626387f866SBrian Austin {"Main AMP", NULL, "CLASS H"}, 3636387f866SBrian Austin {"SPK", NULL, "Main AMP"}, 3646387f866SBrian Austin }; 3656387f866SBrian Austin 3666387f866SBrian Austin static int cs35l35_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) 3676387f866SBrian Austin { 36886c2eddfSKuninori Morimoto struct snd_soc_component *component = codec_dai->component; 36986c2eddfSKuninori Morimoto struct cs35l35_private *cs35l35 = snd_soc_component_get_drvdata(component); 3706387f866SBrian Austin 3714e7f0ea0SDavid Rhodes switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { 3724e7f0ea0SDavid Rhodes case SND_SOC_DAIFMT_CBP_CFP: 3736387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL1, 3746387f866SBrian Austin CS35L35_MS_MASK, 1 << CS35L35_MS_SHIFT); 3754e7f0ea0SDavid Rhodes cs35l35->clock_consumer = false; 3766387f866SBrian Austin break; 3774e7f0ea0SDavid Rhodes case SND_SOC_DAIFMT_CBC_CFC: 3786387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL1, 3796387f866SBrian Austin CS35L35_MS_MASK, 0 << CS35L35_MS_SHIFT); 3804e7f0ea0SDavid Rhodes cs35l35->clock_consumer = true; 3816387f866SBrian Austin break; 3826387f866SBrian Austin default: 3836387f866SBrian Austin return -EINVAL; 3846387f866SBrian Austin } 3856387f866SBrian Austin 3866387f866SBrian Austin switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 3876387f866SBrian Austin case SND_SOC_DAIFMT_I2S: 3886387f866SBrian Austin cs35l35->i2s_mode = true; 3896387f866SBrian Austin cs35l35->pdm_mode = false; 3906387f866SBrian Austin break; 3916387f866SBrian Austin case SND_SOC_DAIFMT_PDM: 3926387f866SBrian Austin cs35l35->pdm_mode = true; 3936387f866SBrian Austin cs35l35->i2s_mode = false; 3946387f866SBrian Austin break; 3956387f866SBrian Austin default: 3966387f866SBrian Austin return -EINVAL; 3976387f866SBrian Austin } 3986387f866SBrian Austin 3996387f866SBrian Austin return 0; 4006387f866SBrian Austin } 4016387f866SBrian Austin 4026387f866SBrian Austin struct cs35l35_sysclk_config { 4036387f866SBrian Austin int sysclk; 4046387f866SBrian Austin int srate; 4056387f866SBrian Austin u8 clk_cfg; 4066387f866SBrian Austin }; 4076387f866SBrian Austin 4086387f866SBrian Austin static struct cs35l35_sysclk_config cs35l35_clk_ctl[] = { 4096387f866SBrian Austin 4106387f866SBrian Austin /* SYSCLK, Sample Rate, Serial Port Cfg */ 4116387f866SBrian Austin {5644800, 44100, 0x00}, 4126387f866SBrian Austin {5644800, 88200, 0x40}, 4136387f866SBrian Austin {6144000, 48000, 0x10}, 4146387f866SBrian Austin {6144000, 96000, 0x50}, 4156387f866SBrian Austin {11289600, 44100, 0x01}, 4166387f866SBrian Austin {11289600, 88200, 0x41}, 4176387f866SBrian Austin {11289600, 176400, 0x81}, 4186387f866SBrian Austin {12000000, 44100, 0x03}, 4196387f866SBrian Austin {12000000, 48000, 0x13}, 4206387f866SBrian Austin {12000000, 88200, 0x43}, 4216387f866SBrian Austin {12000000, 96000, 0x53}, 4226387f866SBrian Austin {12000000, 176400, 0x83}, 4236387f866SBrian Austin {12000000, 192000, 0x93}, 4246387f866SBrian Austin {12288000, 48000, 0x11}, 4256387f866SBrian Austin {12288000, 96000, 0x51}, 4266387f866SBrian Austin {12288000, 192000, 0x91}, 4276387f866SBrian Austin {13000000, 44100, 0x07}, 4286387f866SBrian Austin {13000000, 48000, 0x17}, 4296387f866SBrian Austin {13000000, 88200, 0x47}, 4306387f866SBrian Austin {13000000, 96000, 0x57}, 4316387f866SBrian Austin {13000000, 176400, 0x87}, 4326387f866SBrian Austin {13000000, 192000, 0x97}, 4336387f866SBrian Austin {22579200, 44100, 0x02}, 4346387f866SBrian Austin {22579200, 88200, 0x42}, 4356387f866SBrian Austin {22579200, 176400, 0x82}, 4366387f866SBrian Austin {24000000, 44100, 0x0B}, 4376387f866SBrian Austin {24000000, 48000, 0x1B}, 4386387f866SBrian Austin {24000000, 88200, 0x4B}, 4396387f866SBrian Austin {24000000, 96000, 0x5B}, 4406387f866SBrian Austin {24000000, 176400, 0x8B}, 4416387f866SBrian Austin {24000000, 192000, 0x9B}, 4426387f866SBrian Austin {24576000, 48000, 0x12}, 4436387f866SBrian Austin {24576000, 96000, 0x52}, 4446387f866SBrian Austin {24576000, 192000, 0x92}, 4456387f866SBrian Austin {26000000, 44100, 0x0F}, 4466387f866SBrian Austin {26000000, 48000, 0x1F}, 4476387f866SBrian Austin {26000000, 88200, 0x4F}, 4486387f866SBrian Austin {26000000, 96000, 0x5F}, 4496387f866SBrian Austin {26000000, 176400, 0x8F}, 4506387f866SBrian Austin {26000000, 192000, 0x9F}, 4516387f866SBrian Austin }; 4526387f866SBrian Austin 4536387f866SBrian Austin static int cs35l35_get_clk_config(int sysclk, int srate) 4546387f866SBrian Austin { 4556387f866SBrian Austin int i; 4566387f866SBrian Austin 4576387f866SBrian Austin for (i = 0; i < ARRAY_SIZE(cs35l35_clk_ctl); i++) { 4586387f866SBrian Austin if (cs35l35_clk_ctl[i].sysclk == sysclk && 4596387f866SBrian Austin cs35l35_clk_ctl[i].srate == srate) 4606387f866SBrian Austin return cs35l35_clk_ctl[i].clk_cfg; 4616387f866SBrian Austin } 4626387f866SBrian Austin return -EINVAL; 4636387f866SBrian Austin } 4646387f866SBrian Austin 4656387f866SBrian Austin static int cs35l35_hw_params(struct snd_pcm_substream *substream, 4666387f866SBrian Austin struct snd_pcm_hw_params *params, 4676387f866SBrian Austin struct snd_soc_dai *dai) 4686387f866SBrian Austin { 46986c2eddfSKuninori Morimoto struct snd_soc_component *component = dai->component; 47086c2eddfSKuninori Morimoto struct cs35l35_private *cs35l35 = snd_soc_component_get_drvdata(component); 4716387f866SBrian Austin struct classh_cfg *classh = &cs35l35->pdata.classh_algo; 4726387f866SBrian Austin int srate = params_rate(params); 4736387f866SBrian Austin int ret = 0; 4746387f866SBrian Austin u8 sp_sclks; 4756387f866SBrian Austin int audin_format; 4766387f866SBrian Austin int errata_chk; 4776387f866SBrian Austin 4786387f866SBrian Austin int clk_ctl = cs35l35_get_clk_config(cs35l35->sysclk, srate); 4796387f866SBrian Austin 4806387f866SBrian Austin if (clk_ctl < 0) { 48186c2eddfSKuninori Morimoto dev_err(component->dev, "Invalid CLK:Rate %d:%d\n", 4826387f866SBrian Austin cs35l35->sysclk, srate); 4836387f866SBrian Austin return -EINVAL; 4846387f866SBrian Austin } 4856387f866SBrian Austin 4866387f866SBrian Austin ret = regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL2, 4876387f866SBrian Austin CS35L35_CLK_CTL2_MASK, clk_ctl); 4886387f866SBrian Austin if (ret != 0) { 48986c2eddfSKuninori Morimoto dev_err(component->dev, "Failed to set port config %d\n", ret); 4906387f866SBrian Austin return ret; 4916387f866SBrian Austin } 4926387f866SBrian Austin 4936387f866SBrian Austin /* 4946387f866SBrian Austin * Rev A0 Errata 4956387f866SBrian Austin * When configured for the weak-drive detection path (CH_WKFET_DIS = 0) 4966387f866SBrian Austin * the Class H algorithm does not enable weak-drive operation for 4976387f866SBrian Austin * nonzero values of CH_WKFET_DELAY if SP_RATE = 01 or 10 4986387f866SBrian Austin */ 4991a46b7b8SCharles Keepax errata_chk = (clk_ctl & CS35L35_SP_RATE_MASK) >> CS35L35_SP_RATE_SHIFT; 5006387f866SBrian Austin 5016387f866SBrian Austin if (classh->classh_wk_fet_disable == 0x00 && 5021a46b7b8SCharles Keepax (errata_chk == 0x01 || errata_chk == 0x02)) { 5036387f866SBrian Austin ret = regmap_update_bits(cs35l35->regmap, 5046387f866SBrian Austin CS35L35_CLASS_H_FET_DRIVE_CTL, 5056387f866SBrian Austin CS35L35_CH_WKFET_DEL_MASK, 5066387f866SBrian Austin 0 << CS35L35_CH_WKFET_DEL_SHIFT); 5076387f866SBrian Austin if (ret != 0) { 50886c2eddfSKuninori Morimoto dev_err(component->dev, "Failed to set fet config %d\n", 5096387f866SBrian Austin ret); 5106387f866SBrian Austin return ret; 5116387f866SBrian Austin } 5126387f866SBrian Austin } 5136387f866SBrian Austin 5146387f866SBrian Austin /* 5156387f866SBrian Austin * You can pull more Monitor data from the SDOUT pin than going to SDIN 5166387f866SBrian Austin * Just make sure your SCLK is fast enough to fill the frame 5176387f866SBrian Austin */ 5186387f866SBrian Austin if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 5196387f866SBrian Austin switch (params_width(params)) { 5206387f866SBrian Austin case 8: 5216387f866SBrian Austin audin_format = CS35L35_SDIN_DEPTH_8; 5226387f866SBrian Austin break; 5236387f866SBrian Austin case 16: 5246387f866SBrian Austin audin_format = CS35L35_SDIN_DEPTH_16; 5256387f866SBrian Austin break; 5266387f866SBrian Austin case 24: 5276387f866SBrian Austin audin_format = CS35L35_SDIN_DEPTH_24; 5286387f866SBrian Austin break; 5296387f866SBrian Austin default: 53086c2eddfSKuninori Morimoto dev_err(component->dev, "Unsupported Width %d\n", 5316387f866SBrian Austin params_width(params)); 5326387f866SBrian Austin return -EINVAL; 5336387f866SBrian Austin } 5346387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 5356387f866SBrian Austin CS35L35_AUDIN_DEPTH_CTL, 5366387f866SBrian Austin CS35L35_AUDIN_DEPTH_MASK, 5376387f866SBrian Austin audin_format << 5386387f866SBrian Austin CS35L35_AUDIN_DEPTH_SHIFT); 5396387f866SBrian Austin if (cs35l35->pdata.stereo) { 5406387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 5416387f866SBrian Austin CS35L35_AUDIN_DEPTH_CTL, 5426387f866SBrian Austin CS35L35_ADVIN_DEPTH_MASK, 5436387f866SBrian Austin audin_format << 5446387f866SBrian Austin CS35L35_ADVIN_DEPTH_SHIFT); 5456387f866SBrian Austin } 5466387f866SBrian Austin } 5476387f866SBrian Austin 5486387f866SBrian Austin if (cs35l35->i2s_mode) { 5496387f866SBrian Austin /* We have to take the SCLK to derive num sclks 5506387f866SBrian Austin * to configure the CLOCK_CTL3 register correctly 5516387f866SBrian Austin */ 5526387f866SBrian Austin if ((cs35l35->sclk / srate) % 4) { 55386c2eddfSKuninori Morimoto dev_err(component->dev, "Unsupported sclk/fs ratio %d:%d\n", 5546387f866SBrian Austin cs35l35->sclk, srate); 5556387f866SBrian Austin return -EINVAL; 5566387f866SBrian Austin } 5576387f866SBrian Austin sp_sclks = ((cs35l35->sclk / srate) / 4) - 1; 5586387f866SBrian Austin 5594e7f0ea0SDavid Rhodes /* Only certain ratios supported when device is a clock consumer */ 5604e7f0ea0SDavid Rhodes if (cs35l35->clock_consumer) { 5616387f866SBrian Austin switch (sp_sclks) { 5626387f866SBrian Austin case CS35L35_SP_SCLKS_32FS: 5636387f866SBrian Austin case CS35L35_SP_SCLKS_48FS: 5646387f866SBrian Austin case CS35L35_SP_SCLKS_64FS: 5656387f866SBrian Austin break; 5666387f866SBrian Austin default: 56786c2eddfSKuninori Morimoto dev_err(component->dev, "ratio not supported\n"); 5686387f866SBrian Austin return -EINVAL; 569f3a612a6Skbuild test robot } 5706387f866SBrian Austin } else { 5714e7f0ea0SDavid Rhodes /* Only certain ratios supported when device is a clock provider */ 5726387f866SBrian Austin switch (sp_sclks) { 5736387f866SBrian Austin case CS35L35_SP_SCLKS_32FS: 5746387f866SBrian Austin case CS35L35_SP_SCLKS_64FS: 5756387f866SBrian Austin break; 5766387f866SBrian Austin default: 57786c2eddfSKuninori Morimoto dev_err(component->dev, "ratio not supported\n"); 5786387f866SBrian Austin return -EINVAL; 579f3a612a6Skbuild test robot } 5806387f866SBrian Austin } 5816387f866SBrian Austin ret = regmap_update_bits(cs35l35->regmap, 5826387f866SBrian Austin CS35L35_CLK_CTL3, 5836387f866SBrian Austin CS35L35_SP_SCLKS_MASK, sp_sclks << 5846387f866SBrian Austin CS35L35_SP_SCLKS_SHIFT); 5856387f866SBrian Austin if (ret != 0) { 58686c2eddfSKuninori Morimoto dev_err(component->dev, "Failed to set fsclk %d\n", ret); 5876387f866SBrian Austin return ret; 5886387f866SBrian Austin } 5896387f866SBrian Austin } 5906387f866SBrian Austin 5916387f866SBrian Austin return ret; 5926387f866SBrian Austin } 5936387f866SBrian Austin 5946387f866SBrian Austin static const unsigned int cs35l35_src_rates[] = { 5956387f866SBrian Austin 44100, 48000, 88200, 96000, 176400, 192000 5966387f866SBrian Austin }; 5976387f866SBrian Austin 5986387f866SBrian Austin static const struct snd_pcm_hw_constraint_list cs35l35_constraints = { 5996387f866SBrian Austin .count = ARRAY_SIZE(cs35l35_src_rates), 6006387f866SBrian Austin .list = cs35l35_src_rates, 6016387f866SBrian Austin }; 6026387f866SBrian Austin 6036387f866SBrian Austin static int cs35l35_pcm_startup(struct snd_pcm_substream *substream, 6046387f866SBrian Austin struct snd_soc_dai *dai) 6056387f866SBrian Austin { 60686c2eddfSKuninori Morimoto struct snd_soc_component *component = dai->component; 60786c2eddfSKuninori Morimoto struct cs35l35_private *cs35l35 = snd_soc_component_get_drvdata(component); 6086387f866SBrian Austin 6096387f866SBrian Austin if (!substream->runtime) 6106387f866SBrian Austin return 0; 6116387f866SBrian Austin 6126387f866SBrian Austin snd_pcm_hw_constraint_list(substream->runtime, 0, 6136387f866SBrian Austin SNDRV_PCM_HW_PARAM_RATE, &cs35l35_constraints); 6146387f866SBrian Austin 6156387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_AMP_INP_DRV_CTL, 6166387f866SBrian Austin CS35L35_PDM_MODE_MASK, 6176387f866SBrian Austin 0 << CS35L35_PDM_MODE_SHIFT); 6186387f866SBrian Austin 6196387f866SBrian Austin return 0; 6206387f866SBrian Austin } 6216387f866SBrian Austin 6226387f866SBrian Austin static const unsigned int cs35l35_pdm_rates[] = { 6236387f866SBrian Austin 44100, 48000, 88200, 96000 6246387f866SBrian Austin }; 6256387f866SBrian Austin 6266387f866SBrian Austin static const struct snd_pcm_hw_constraint_list cs35l35_pdm_constraints = { 6276387f866SBrian Austin .count = ARRAY_SIZE(cs35l35_pdm_rates), 6286387f866SBrian Austin .list = cs35l35_pdm_rates, 6296387f866SBrian Austin }; 6306387f866SBrian Austin 6316387f866SBrian Austin static int cs35l35_pdm_startup(struct snd_pcm_substream *substream, 6326387f866SBrian Austin struct snd_soc_dai *dai) 6336387f866SBrian Austin { 63486c2eddfSKuninori Morimoto struct snd_soc_component *component = dai->component; 63586c2eddfSKuninori Morimoto struct cs35l35_private *cs35l35 = snd_soc_component_get_drvdata(component); 6366387f866SBrian Austin 6376387f866SBrian Austin if (!substream->runtime) 6386387f866SBrian Austin return 0; 6396387f866SBrian Austin 6406387f866SBrian Austin snd_pcm_hw_constraint_list(substream->runtime, 0, 6416387f866SBrian Austin SNDRV_PCM_HW_PARAM_RATE, 6426387f866SBrian Austin &cs35l35_pdm_constraints); 6436387f866SBrian Austin 6446387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_AMP_INP_DRV_CTL, 6456387f866SBrian Austin CS35L35_PDM_MODE_MASK, 6466387f866SBrian Austin 1 << CS35L35_PDM_MODE_SHIFT); 6476387f866SBrian Austin 6486387f866SBrian Austin return 0; 6496387f866SBrian Austin } 6506387f866SBrian Austin 6516387f866SBrian Austin static int cs35l35_dai_set_sysclk(struct snd_soc_dai *dai, 6526387f866SBrian Austin int clk_id, unsigned int freq, int dir) 6536387f866SBrian Austin { 65486c2eddfSKuninori Morimoto struct snd_soc_component *component = dai->component; 65586c2eddfSKuninori Morimoto struct cs35l35_private *cs35l35 = snd_soc_component_get_drvdata(component); 6566387f866SBrian Austin 6576387f866SBrian Austin /* Need the SCLK Frequency regardless of sysclk source for I2S */ 6586387f866SBrian Austin cs35l35->sclk = freq; 6596387f866SBrian Austin 6606387f866SBrian Austin return 0; 6616387f866SBrian Austin } 6626387f866SBrian Austin 6636387f866SBrian Austin static const struct snd_soc_dai_ops cs35l35_ops = { 6646387f866SBrian Austin .startup = cs35l35_pcm_startup, 6656387f866SBrian Austin .set_fmt = cs35l35_set_dai_fmt, 6666387f866SBrian Austin .hw_params = cs35l35_hw_params, 6676387f866SBrian Austin .set_sysclk = cs35l35_dai_set_sysclk, 6686387f866SBrian Austin }; 6696387f866SBrian Austin 6706387f866SBrian Austin static const struct snd_soc_dai_ops cs35l35_pdm_ops = { 6716387f866SBrian Austin .startup = cs35l35_pdm_startup, 6726387f866SBrian Austin .set_fmt = cs35l35_set_dai_fmt, 6736387f866SBrian Austin .hw_params = cs35l35_hw_params, 6746387f866SBrian Austin }; 6756387f866SBrian Austin 6766387f866SBrian Austin static struct snd_soc_dai_driver cs35l35_dai[] = { 6776387f866SBrian Austin { 6786387f866SBrian Austin .name = "cs35l35-pcm", 6796387f866SBrian Austin .id = 0, 6806387f866SBrian Austin .playback = { 6816387f866SBrian Austin .stream_name = "AMP Playback", 6826387f866SBrian Austin .channels_min = 1, 6836387f866SBrian Austin .channels_max = 8, 6846387f866SBrian Austin .rates = SNDRV_PCM_RATE_KNOT, 6856387f866SBrian Austin .formats = CS35L35_FORMATS, 6866387f866SBrian Austin }, 6876387f866SBrian Austin .capture = { 6886387f866SBrian Austin .stream_name = "AMP Capture", 6896387f866SBrian Austin .channels_min = 1, 6906387f866SBrian Austin .channels_max = 8, 6916387f866SBrian Austin .rates = SNDRV_PCM_RATE_KNOT, 6926387f866SBrian Austin .formats = CS35L35_FORMATS, 6936387f866SBrian Austin }, 6946387f866SBrian Austin .ops = &cs35l35_ops, 695260b668cSKuninori Morimoto .symmetric_rate = 1, 6966387f866SBrian Austin }, 6976387f866SBrian Austin { 6986387f866SBrian Austin .name = "cs35l35-pdm", 6996387f866SBrian Austin .id = 1, 7006387f866SBrian Austin .playback = { 7016387f866SBrian Austin .stream_name = "PDM Playback", 7026387f866SBrian Austin .channels_min = 1, 7036387f866SBrian Austin .channels_max = 2, 7046387f866SBrian Austin .rates = SNDRV_PCM_RATE_KNOT, 7056387f866SBrian Austin .formats = CS35L35_FORMATS, 7066387f866SBrian Austin }, 7076387f866SBrian Austin .ops = &cs35l35_pdm_ops, 7086387f866SBrian Austin }, 7096387f866SBrian Austin }; 7106387f866SBrian Austin 71186c2eddfSKuninori Morimoto static int cs35l35_component_set_sysclk(struct snd_soc_component *component, 7126387f866SBrian Austin int clk_id, int source, unsigned int freq, 7136387f866SBrian Austin int dir) 7146387f866SBrian Austin { 71586c2eddfSKuninori Morimoto struct cs35l35_private *cs35l35 = snd_soc_component_get_drvdata(component); 7166387f866SBrian Austin int clksrc; 7176387f866SBrian Austin int ret = 0; 7186387f866SBrian Austin 7196387f866SBrian Austin switch (clk_id) { 7206387f866SBrian Austin case 0: 7216387f866SBrian Austin clksrc = CS35L35_CLK_SOURCE_MCLK; 7226387f866SBrian Austin break; 7236387f866SBrian Austin case 1: 7246387f866SBrian Austin clksrc = CS35L35_CLK_SOURCE_SCLK; 7256387f866SBrian Austin break; 7266387f866SBrian Austin case 2: 7276387f866SBrian Austin clksrc = CS35L35_CLK_SOURCE_PDM; 7286387f866SBrian Austin break; 7296387f866SBrian Austin default: 73086c2eddfSKuninori Morimoto dev_err(component->dev, "Invalid CLK Source\n"); 7316387f866SBrian Austin return -EINVAL; 732f3a612a6Skbuild test robot } 7336387f866SBrian Austin 7346387f866SBrian Austin switch (freq) { 7356387f866SBrian Austin case 5644800: 7366387f866SBrian Austin case 6144000: 7376387f866SBrian Austin case 11289600: 7386387f866SBrian Austin case 12000000: 7396387f866SBrian Austin case 12288000: 7406387f866SBrian Austin case 13000000: 7416387f866SBrian Austin case 22579200: 7426387f866SBrian Austin case 24000000: 7436387f866SBrian Austin case 24576000: 7446387f866SBrian Austin case 26000000: 7456387f866SBrian Austin cs35l35->sysclk = freq; 7466387f866SBrian Austin break; 7476387f866SBrian Austin default: 74886c2eddfSKuninori Morimoto dev_err(component->dev, "Invalid CLK Frequency Input : %d\n", freq); 7496387f866SBrian Austin return -EINVAL; 7506387f866SBrian Austin } 7516387f866SBrian Austin 7526387f866SBrian Austin ret = regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL1, 7536387f866SBrian Austin CS35L35_CLK_SOURCE_MASK, 7546387f866SBrian Austin clksrc << CS35L35_CLK_SOURCE_SHIFT); 7556387f866SBrian Austin if (ret != 0) { 75686c2eddfSKuninori Morimoto dev_err(component->dev, "Failed to set sysclk %d\n", ret); 7576387f866SBrian Austin return ret; 7586387f866SBrian Austin } 7596387f866SBrian Austin 7606387f866SBrian Austin return ret; 7616387f866SBrian Austin } 7626387f866SBrian Austin 763b7c752d6SBrian Austin static int cs35l35_boost_inductor(struct cs35l35_private *cs35l35, 764b7c752d6SBrian Austin int inductor) 765b7c752d6SBrian Austin { 766b7c752d6SBrian Austin struct regmap *regmap = cs35l35->regmap; 767b7c752d6SBrian Austin unsigned int bst_ipk = 0; 768b7c752d6SBrian Austin 769b7c752d6SBrian Austin /* 770b7c752d6SBrian Austin * Digital Boost Converter Configuration for feedback, 771b7c752d6SBrian Austin * ramping, switching frequency, and estimation block seeding. 772b7c752d6SBrian Austin */ 773b7c752d6SBrian Austin 774b7c752d6SBrian Austin regmap_update_bits(regmap, CS35L35_BST_CONV_SW_FREQ, 775b7c752d6SBrian Austin CS35L35_BST_CONV_SWFREQ_MASK, 0x00); 776b7c752d6SBrian Austin 777b7c752d6SBrian Austin regmap_read(regmap, CS35L35_BST_PEAK_I, &bst_ipk); 778b7c752d6SBrian Austin bst_ipk &= CS35L35_BST_IPK_MASK; 779b7c752d6SBrian Austin 780b7c752d6SBrian Austin switch (inductor) { 781b7c752d6SBrian Austin case 1000: /* 1 uH */ 782b7c752d6SBrian Austin regmap_write(regmap, CS35L35_BST_CONV_COEF_1, 0x24); 783b7c752d6SBrian Austin regmap_write(regmap, CS35L35_BST_CONV_COEF_2, 0x24); 784b7c752d6SBrian Austin regmap_update_bits(regmap, CS35L35_BST_CONV_SW_FREQ, 785b7c752d6SBrian Austin CS35L35_BST_CONV_LBST_MASK, 0x00); 786b7c752d6SBrian Austin 787b7c752d6SBrian Austin if (bst_ipk < 0x04) 788b7c752d6SBrian Austin regmap_write(regmap, CS35L35_BST_CONV_SLOPE_COMP, 0x1B); 789b7c752d6SBrian Austin else 790b7c752d6SBrian Austin regmap_write(regmap, CS35L35_BST_CONV_SLOPE_COMP, 0x4E); 791b7c752d6SBrian Austin break; 792b7c752d6SBrian Austin case 1200: /* 1.2 uH */ 793b7c752d6SBrian Austin regmap_write(regmap, CS35L35_BST_CONV_COEF_1, 0x20); 794b7c752d6SBrian Austin regmap_write(regmap, CS35L35_BST_CONV_COEF_2, 0x20); 795b7c752d6SBrian Austin regmap_update_bits(regmap, CS35L35_BST_CONV_SW_FREQ, 796b7c752d6SBrian Austin CS35L35_BST_CONV_LBST_MASK, 0x01); 797b7c752d6SBrian Austin 798b7c752d6SBrian Austin if (bst_ipk < 0x04) 799b7c752d6SBrian Austin regmap_write(regmap, CS35L35_BST_CONV_SLOPE_COMP, 0x1B); 800b7c752d6SBrian Austin else 801b7c752d6SBrian Austin regmap_write(regmap, CS35L35_BST_CONV_SLOPE_COMP, 0x47); 802b7c752d6SBrian Austin break; 803b7c752d6SBrian Austin case 1500: /* 1.5uH */ 804b7c752d6SBrian Austin regmap_write(regmap, CS35L35_BST_CONV_COEF_1, 0x20); 805b7c752d6SBrian Austin regmap_write(regmap, CS35L35_BST_CONV_COEF_2, 0x20); 806b7c752d6SBrian Austin regmap_update_bits(regmap, CS35L35_BST_CONV_SW_FREQ, 807b7c752d6SBrian Austin CS35L35_BST_CONV_LBST_MASK, 0x02); 808b7c752d6SBrian Austin 809b7c752d6SBrian Austin if (bst_ipk < 0x04) 810b7c752d6SBrian Austin regmap_write(regmap, CS35L35_BST_CONV_SLOPE_COMP, 0x1B); 811b7c752d6SBrian Austin else 812b7c752d6SBrian Austin regmap_write(regmap, CS35L35_BST_CONV_SLOPE_COMP, 0x3C); 813b7c752d6SBrian Austin break; 814b7c752d6SBrian Austin case 2200: /* 2.2uH */ 815b7c752d6SBrian Austin regmap_write(regmap, CS35L35_BST_CONV_COEF_1, 0x19); 816b7c752d6SBrian Austin regmap_write(regmap, CS35L35_BST_CONV_COEF_2, 0x25); 817b7c752d6SBrian Austin regmap_update_bits(regmap, CS35L35_BST_CONV_SW_FREQ, 818b7c752d6SBrian Austin CS35L35_BST_CONV_LBST_MASK, 0x03); 819b7c752d6SBrian Austin 820b7c752d6SBrian Austin if (bst_ipk < 0x04) 821b7c752d6SBrian Austin regmap_write(regmap, CS35L35_BST_CONV_SLOPE_COMP, 0x1B); 822b7c752d6SBrian Austin else 823b7c752d6SBrian Austin regmap_write(regmap, CS35L35_BST_CONV_SLOPE_COMP, 0x23); 824b7c752d6SBrian Austin break; 825b7c752d6SBrian Austin default: 826b7c752d6SBrian Austin dev_err(cs35l35->dev, "Invalid Inductor Value %d uH\n", 827b7c752d6SBrian Austin inductor); 828b7c752d6SBrian Austin return -EINVAL; 829b7c752d6SBrian Austin } 830b7c752d6SBrian Austin return 0; 831b7c752d6SBrian Austin } 832b7c752d6SBrian Austin 83386c2eddfSKuninori Morimoto static int cs35l35_component_probe(struct snd_soc_component *component) 8346387f866SBrian Austin { 83586c2eddfSKuninori Morimoto struct cs35l35_private *cs35l35 = snd_soc_component_get_drvdata(component); 8366387f866SBrian Austin struct classh_cfg *classh = &cs35l35->pdata.classh_algo; 8376387f866SBrian Austin struct monitor_cfg *monitor_config = &cs35l35->pdata.mon_cfg; 8386387f866SBrian Austin int ret; 8396387f866SBrian Austin 8406387f866SBrian Austin /* Set Platform Data */ 8416387f866SBrian Austin if (cs35l35->pdata.bst_vctl) 8426387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_BST_CVTR_V_CTL, 8436387f866SBrian Austin CS35L35_BST_CTL_MASK, 8446387f866SBrian Austin cs35l35->pdata.bst_vctl); 8456387f866SBrian Austin 8466387f866SBrian Austin if (cs35l35->pdata.bst_ipk) 8476387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_BST_PEAK_I, 8486387f866SBrian Austin CS35L35_BST_IPK_MASK, 8496387f866SBrian Austin cs35l35->pdata.bst_ipk << 8506387f866SBrian Austin CS35L35_BST_IPK_SHIFT); 8516387f866SBrian Austin 852b7c752d6SBrian Austin ret = cs35l35_boost_inductor(cs35l35, cs35l35->pdata.boost_ind); 853b7c752d6SBrian Austin if (ret) 854b7c752d6SBrian Austin return ret; 855b7c752d6SBrian Austin 8566387f866SBrian Austin if (cs35l35->pdata.gain_zc) 8576387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PROTECT_CTL, 8586387f866SBrian Austin CS35L35_AMP_GAIN_ZC_MASK, 8596387f866SBrian Austin cs35l35->pdata.gain_zc << 8606387f866SBrian Austin CS35L35_AMP_GAIN_ZC_SHIFT); 8616387f866SBrian Austin 8626387f866SBrian Austin if (cs35l35->pdata.aud_channel) 8636387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 8646387f866SBrian Austin CS35L35_AUDIN_RXLOC_CTL, 8656387f866SBrian Austin CS35L35_AUD_IN_LR_MASK, 8666387f866SBrian Austin cs35l35->pdata.aud_channel << 8676387f866SBrian Austin CS35L35_AUD_IN_LR_SHIFT); 8686387f866SBrian Austin 8696387f866SBrian Austin if (cs35l35->pdata.stereo) { 8706387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 8716387f866SBrian Austin CS35L35_ADVIN_RXLOC_CTL, 8726387f866SBrian Austin CS35L35_ADV_IN_LR_MASK, 8736387f866SBrian Austin cs35l35->pdata.adv_channel << 8746387f866SBrian Austin CS35L35_ADV_IN_LR_SHIFT); 8756387f866SBrian Austin if (cs35l35->pdata.shared_bst) 8766387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_CLASS_H_CTL, 8776387f866SBrian Austin CS35L35_CH_STEREO_MASK, 8786387f866SBrian Austin 1 << CS35L35_CH_STEREO_SHIFT); 87986c2eddfSKuninori Morimoto ret = snd_soc_add_component_controls(component, cs35l35_adv_controls, 8806387f866SBrian Austin ARRAY_SIZE(cs35l35_adv_controls)); 8816387f866SBrian Austin if (ret) 8826387f866SBrian Austin return ret; 8836387f866SBrian Austin } 8846387f866SBrian Austin 8856387f866SBrian Austin if (cs35l35->pdata.sp_drv_str) 8866387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL1, 8876387f866SBrian Austin CS35L35_SP_DRV_MASK, 8886387f866SBrian Austin cs35l35->pdata.sp_drv_str << 8896387f866SBrian Austin CS35L35_SP_DRV_SHIFT); 8908d45f2d2SCharles Keepax if (cs35l35->pdata.sp_drv_unused) 8918d45f2d2SCharles Keepax regmap_update_bits(cs35l35->regmap, CS35L35_SP_FMT_CTL3, 8928d45f2d2SCharles Keepax CS35L35_SP_I2S_DRV_MASK, 8938d45f2d2SCharles Keepax cs35l35->pdata.sp_drv_unused << 8948d45f2d2SCharles Keepax CS35L35_SP_I2S_DRV_SHIFT); 8956387f866SBrian Austin 8966387f866SBrian Austin if (classh->classh_algo_enable) { 8976387f866SBrian Austin if (classh->classh_bst_override) 8986387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 8996387f866SBrian Austin CS35L35_CLASS_H_CTL, 9006387f866SBrian Austin CS35L35_CH_BST_OVR_MASK, 9016387f866SBrian Austin classh->classh_bst_override << 9026387f866SBrian Austin CS35L35_CH_BST_OVR_SHIFT); 9036387f866SBrian Austin if (classh->classh_bst_max_limit) 9046387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 9056387f866SBrian Austin CS35L35_CLASS_H_CTL, 9066387f866SBrian Austin CS35L35_CH_BST_LIM_MASK, 9076387f866SBrian Austin classh->classh_bst_max_limit << 9086387f866SBrian Austin CS35L35_CH_BST_LIM_SHIFT); 9096387f866SBrian Austin if (classh->classh_mem_depth) 9106387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 9116387f866SBrian Austin CS35L35_CLASS_H_CTL, 9126387f866SBrian Austin CS35L35_CH_MEM_DEPTH_MASK, 9136387f866SBrian Austin classh->classh_mem_depth << 9146387f866SBrian Austin CS35L35_CH_MEM_DEPTH_SHIFT); 9156387f866SBrian Austin if (classh->classh_headroom) 9166387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 9176387f866SBrian Austin CS35L35_CLASS_H_HEADRM_CTL, 9186387f866SBrian Austin CS35L35_CH_HDRM_CTL_MASK, 9196387f866SBrian Austin classh->classh_headroom << 9206387f866SBrian Austin CS35L35_CH_HDRM_CTL_SHIFT); 9216387f866SBrian Austin if (classh->classh_release_rate) 9226387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 9236387f866SBrian Austin CS35L35_CLASS_H_RELEASE_RATE, 9246387f866SBrian Austin CS35L35_CH_REL_RATE_MASK, 9256387f866SBrian Austin classh->classh_release_rate << 9266387f866SBrian Austin CS35L35_CH_REL_RATE_SHIFT); 9276387f866SBrian Austin if (classh->classh_wk_fet_disable) 9286387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 9296387f866SBrian Austin CS35L35_CLASS_H_FET_DRIVE_CTL, 9306387f866SBrian Austin CS35L35_CH_WKFET_DIS_MASK, 9316387f866SBrian Austin classh->classh_wk_fet_disable << 9326387f866SBrian Austin CS35L35_CH_WKFET_DIS_SHIFT); 9336387f866SBrian Austin if (classh->classh_wk_fet_delay) 9346387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 9356387f866SBrian Austin CS35L35_CLASS_H_FET_DRIVE_CTL, 9366387f866SBrian Austin CS35L35_CH_WKFET_DEL_MASK, 9376387f866SBrian Austin classh->classh_wk_fet_delay << 9386387f866SBrian Austin CS35L35_CH_WKFET_DEL_SHIFT); 9396387f866SBrian Austin if (classh->classh_wk_fet_thld) 9406387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 9416387f866SBrian Austin CS35L35_CLASS_H_FET_DRIVE_CTL, 9426387f866SBrian Austin CS35L35_CH_WKFET_THLD_MASK, 9436387f866SBrian Austin classh->classh_wk_fet_thld << 9446387f866SBrian Austin CS35L35_CH_WKFET_THLD_SHIFT); 9456387f866SBrian Austin if (classh->classh_vpch_auto) 9466387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 9476387f866SBrian Austin CS35L35_CLASS_H_VP_CTL, 9486387f866SBrian Austin CS35L35_CH_VP_AUTO_MASK, 9496387f866SBrian Austin classh->classh_vpch_auto << 9506387f866SBrian Austin CS35L35_CH_VP_AUTO_SHIFT); 9516387f866SBrian Austin if (classh->classh_vpch_rate) 9526387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 9536387f866SBrian Austin CS35L35_CLASS_H_VP_CTL, 9546387f866SBrian Austin CS35L35_CH_VP_RATE_MASK, 9556387f866SBrian Austin classh->classh_vpch_rate << 9566387f866SBrian Austin CS35L35_CH_VP_RATE_SHIFT); 9576387f866SBrian Austin if (classh->classh_vpch_man) 9586387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 9596387f866SBrian Austin CS35L35_CLASS_H_VP_CTL, 9606387f866SBrian Austin CS35L35_CH_VP_MAN_MASK, 9616387f866SBrian Austin classh->classh_vpch_man << 9626387f866SBrian Austin CS35L35_CH_VP_MAN_SHIFT); 9636387f866SBrian Austin } 9646387f866SBrian Austin 9656387f866SBrian Austin if (monitor_config->is_present) { 9666387f866SBrian Austin if (monitor_config->vmon_specs) { 9676387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 9686387f866SBrian Austin CS35L35_SPKMON_DEPTH_CTL, 9696387f866SBrian Austin CS35L35_VMON_DEPTH_MASK, 9706387f866SBrian Austin monitor_config->vmon_dpth << 9716387f866SBrian Austin CS35L35_VMON_DEPTH_SHIFT); 9726387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 9736387f866SBrian Austin CS35L35_VMON_TXLOC_CTL, 9746387f866SBrian Austin CS35L35_MON_TXLOC_MASK, 9756387f866SBrian Austin monitor_config->vmon_loc << 9766387f866SBrian Austin CS35L35_MON_TXLOC_SHIFT); 9776387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 9786387f866SBrian Austin CS35L35_VMON_TXLOC_CTL, 9796387f866SBrian Austin CS35L35_MON_FRM_MASK, 9806387f866SBrian Austin monitor_config->vmon_frm << 9816387f866SBrian Austin CS35L35_MON_FRM_SHIFT); 9826387f866SBrian Austin } 9836387f866SBrian Austin if (monitor_config->imon_specs) { 9846387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 9856387f866SBrian Austin CS35L35_SPKMON_DEPTH_CTL, 9866387f866SBrian Austin CS35L35_IMON_DEPTH_MASK, 9876387f866SBrian Austin monitor_config->imon_dpth << 9886387f866SBrian Austin CS35L35_IMON_DEPTH_SHIFT); 9896387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 9906387f866SBrian Austin CS35L35_IMON_TXLOC_CTL, 9916387f866SBrian Austin CS35L35_MON_TXLOC_MASK, 9926387f866SBrian Austin monitor_config->imon_loc << 9936387f866SBrian Austin CS35L35_MON_TXLOC_SHIFT); 9946387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 9956387f866SBrian Austin CS35L35_IMON_TXLOC_CTL, 9966387f866SBrian Austin CS35L35_MON_FRM_MASK, 9976387f866SBrian Austin monitor_config->imon_frm << 9986387f866SBrian Austin CS35L35_MON_FRM_SHIFT); 99906bdf385SCharles Keepax regmap_update_bits(cs35l35->regmap, 100006bdf385SCharles Keepax CS35L35_IMON_SCALE_CTL, 100106bdf385SCharles Keepax CS35L35_IMON_SCALE_MASK, 100206bdf385SCharles Keepax monitor_config->imon_scale << 100306bdf385SCharles Keepax CS35L35_IMON_SCALE_SHIFT); 10046387f866SBrian Austin } 10056387f866SBrian Austin if (monitor_config->vpmon_specs) { 10066387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 10076387f866SBrian Austin CS35L35_SUPMON_DEPTH_CTL, 10086387f866SBrian Austin CS35L35_VPMON_DEPTH_MASK, 10096387f866SBrian Austin monitor_config->vpmon_dpth << 10106387f866SBrian Austin CS35L35_VPMON_DEPTH_SHIFT); 10116387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 10126387f866SBrian Austin CS35L35_VPMON_TXLOC_CTL, 10136387f866SBrian Austin CS35L35_MON_TXLOC_MASK, 10146387f866SBrian Austin monitor_config->vpmon_loc << 10156387f866SBrian Austin CS35L35_MON_TXLOC_SHIFT); 10166387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 10176387f866SBrian Austin CS35L35_VPMON_TXLOC_CTL, 10186387f866SBrian Austin CS35L35_MON_FRM_MASK, 10196387f866SBrian Austin monitor_config->vpmon_frm << 10206387f866SBrian Austin CS35L35_MON_FRM_SHIFT); 10216387f866SBrian Austin } 10226387f866SBrian Austin if (monitor_config->vbstmon_specs) { 10236387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 10246387f866SBrian Austin CS35L35_SUPMON_DEPTH_CTL, 10256387f866SBrian Austin CS35L35_VBSTMON_DEPTH_MASK, 10266387f866SBrian Austin monitor_config->vpmon_dpth << 10276387f866SBrian Austin CS35L35_VBSTMON_DEPTH_SHIFT); 10286387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 10296387f866SBrian Austin CS35L35_VBSTMON_TXLOC_CTL, 10306387f866SBrian Austin CS35L35_MON_TXLOC_MASK, 10316387f866SBrian Austin monitor_config->vbstmon_loc << 10326387f866SBrian Austin CS35L35_MON_TXLOC_SHIFT); 10336387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 10346387f866SBrian Austin CS35L35_VBSTMON_TXLOC_CTL, 10356387f866SBrian Austin CS35L35_MON_FRM_MASK, 10366387f866SBrian Austin monitor_config->vbstmon_frm << 10376387f866SBrian Austin CS35L35_MON_FRM_SHIFT); 10386387f866SBrian Austin } 10396387f866SBrian Austin if (monitor_config->vpbrstat_specs) { 10406387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 10416387f866SBrian Austin CS35L35_SUPMON_DEPTH_CTL, 10426387f866SBrian Austin CS35L35_VPBRSTAT_DEPTH_MASK, 10436387f866SBrian Austin monitor_config->vpbrstat_dpth << 10446387f866SBrian Austin CS35L35_VPBRSTAT_DEPTH_SHIFT); 10456387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 10466387f866SBrian Austin CS35L35_VPBR_STATUS_TXLOC_CTL, 10476387f866SBrian Austin CS35L35_MON_TXLOC_MASK, 10486387f866SBrian Austin monitor_config->vpbrstat_loc << 10496387f866SBrian Austin CS35L35_MON_TXLOC_SHIFT); 10506387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 10516387f866SBrian Austin CS35L35_VPBR_STATUS_TXLOC_CTL, 10526387f866SBrian Austin CS35L35_MON_FRM_MASK, 10536387f866SBrian Austin monitor_config->vpbrstat_frm << 10546387f866SBrian Austin CS35L35_MON_FRM_SHIFT); 10556387f866SBrian Austin } 10566387f866SBrian Austin if (monitor_config->zerofill_specs) { 10576387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 10586387f866SBrian Austin CS35L35_SUPMON_DEPTH_CTL, 10596387f866SBrian Austin CS35L35_ZEROFILL_DEPTH_MASK, 10606387f866SBrian Austin monitor_config->zerofill_dpth << 10616387f866SBrian Austin CS35L35_ZEROFILL_DEPTH_SHIFT); 10626387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 10636387f866SBrian Austin CS35L35_ZERO_FILL_LOC_CTL, 10646387f866SBrian Austin CS35L35_MON_TXLOC_MASK, 10656387f866SBrian Austin monitor_config->zerofill_loc << 10666387f866SBrian Austin CS35L35_MON_TXLOC_SHIFT); 10676387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 10686387f866SBrian Austin CS35L35_ZERO_FILL_LOC_CTL, 10696387f866SBrian Austin CS35L35_MON_FRM_MASK, 10706387f866SBrian Austin monitor_config->zerofill_frm << 10716387f866SBrian Austin CS35L35_MON_FRM_SHIFT); 10726387f866SBrian Austin } 10736387f866SBrian Austin } 10746387f866SBrian Austin 1075bfe41c67SDan Carpenter return 0; 10766387f866SBrian Austin } 10776387f866SBrian Austin 107886c2eddfSKuninori Morimoto static const struct snd_soc_component_driver soc_component_dev_cs35l35 = { 107986c2eddfSKuninori Morimoto .probe = cs35l35_component_probe, 108086c2eddfSKuninori Morimoto .set_sysclk = cs35l35_component_set_sysclk, 10816387f866SBrian Austin .dapm_widgets = cs35l35_dapm_widgets, 10826387f866SBrian Austin .num_dapm_widgets = ARRAY_SIZE(cs35l35_dapm_widgets), 10836387f866SBrian Austin .dapm_routes = cs35l35_audio_map, 10846387f866SBrian Austin .num_dapm_routes = ARRAY_SIZE(cs35l35_audio_map), 10856387f866SBrian Austin .controls = cs35l35_aud_controls, 10866387f866SBrian Austin .num_controls = ARRAY_SIZE(cs35l35_aud_controls), 108786c2eddfSKuninori Morimoto .idle_bias_on = 1, 108886c2eddfSKuninori Morimoto .use_pmdown_time = 1, 108986c2eddfSKuninori Morimoto .endianness = 1, 10906387f866SBrian Austin }; 10916387f866SBrian Austin 10926387f866SBrian Austin static struct regmap_config cs35l35_regmap = { 10936387f866SBrian Austin .reg_bits = 8, 10946387f866SBrian Austin .val_bits = 8, 10956387f866SBrian Austin 10966387f866SBrian Austin .max_register = CS35L35_MAX_REGISTER, 10976387f866SBrian Austin .reg_defaults = cs35l35_reg, 10986387f866SBrian Austin .num_reg_defaults = ARRAY_SIZE(cs35l35_reg), 10996387f866SBrian Austin .volatile_reg = cs35l35_volatile_register, 11006387f866SBrian Austin .readable_reg = cs35l35_readable_register, 11016387f866SBrian Austin .precious_reg = cs35l35_precious_register, 1102*28f851baSMark Brown .cache_type = REGCACHE_MAPLE, 11031c96a2f6SDavid Frey .use_single_read = true, 11041c96a2f6SDavid Frey .use_single_write = true, 11056387f866SBrian Austin }; 11066387f866SBrian Austin 11076387f866SBrian Austin static irqreturn_t cs35l35_irq(int irq, void *data) 11086387f866SBrian Austin { 11096387f866SBrian Austin struct cs35l35_private *cs35l35 = data; 11106387f866SBrian Austin unsigned int sticky1, sticky2, sticky3, sticky4; 11116387f866SBrian Austin unsigned int mask1, mask2, mask3, mask4, current1; 11126387f866SBrian Austin 11136387f866SBrian Austin /* ack the irq by reading all status registers */ 11146387f866SBrian Austin regmap_read(cs35l35->regmap, CS35L35_INT_STATUS_4, &sticky4); 11156387f866SBrian Austin regmap_read(cs35l35->regmap, CS35L35_INT_STATUS_3, &sticky3); 11166387f866SBrian Austin regmap_read(cs35l35->regmap, CS35L35_INT_STATUS_2, &sticky2); 11176387f866SBrian Austin regmap_read(cs35l35->regmap, CS35L35_INT_STATUS_1, &sticky1); 11186387f866SBrian Austin 11196387f866SBrian Austin regmap_read(cs35l35->regmap, CS35L35_INT_MASK_4, &mask4); 11206387f866SBrian Austin regmap_read(cs35l35->regmap, CS35L35_INT_MASK_3, &mask3); 11216387f866SBrian Austin regmap_read(cs35l35->regmap, CS35L35_INT_MASK_2, &mask2); 11226387f866SBrian Austin regmap_read(cs35l35->regmap, CS35L35_INT_MASK_1, &mask1); 11236387f866SBrian Austin 11246387f866SBrian Austin /* Check to see if unmasked bits are active */ 11256387f866SBrian Austin if (!(sticky1 & ~mask1) && !(sticky2 & ~mask2) && !(sticky3 & ~mask3) 11266387f866SBrian Austin && !(sticky4 & ~mask4)) 11276387f866SBrian Austin return IRQ_NONE; 11286387f866SBrian Austin 11296387f866SBrian Austin if (sticky2 & CS35L35_PDN_DONE) 11306387f866SBrian Austin complete(&cs35l35->pdn_done); 11316387f866SBrian Austin 11326387f866SBrian Austin /* read the current values */ 11336387f866SBrian Austin regmap_read(cs35l35->regmap, CS35L35_INT_STATUS_1, ¤t1); 11346387f866SBrian Austin 11356387f866SBrian Austin /* handle the interrupts */ 11366387f866SBrian Austin if (sticky1 & CS35L35_CAL_ERR) { 11375d3d0ad6SCharles Keepax dev_crit(cs35l35->dev, "Calibration Error\n"); 11386387f866SBrian Austin 11396387f866SBrian Austin /* error is no longer asserted; safe to reset */ 11406387f866SBrian Austin if (!(current1 & CS35L35_CAL_ERR)) { 11416387f866SBrian Austin pr_debug("%s : Cal error release\n", __func__); 11426387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 11436387f866SBrian Austin CS35L35_PROT_RELEASE_CTL, 11446387f866SBrian Austin CS35L35_CAL_ERR_RLS, 0); 11456387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 11466387f866SBrian Austin CS35L35_PROT_RELEASE_CTL, 11476387f866SBrian Austin CS35L35_CAL_ERR_RLS, 11486387f866SBrian Austin CS35L35_CAL_ERR_RLS); 11496387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 11506387f866SBrian Austin CS35L35_PROT_RELEASE_CTL, 11516387f866SBrian Austin CS35L35_CAL_ERR_RLS, 0); 11526387f866SBrian Austin } 11536387f866SBrian Austin } 11546387f866SBrian Austin 11556387f866SBrian Austin if (sticky1 & CS35L35_AMP_SHORT) { 11565d3d0ad6SCharles Keepax dev_crit(cs35l35->dev, "AMP Short Error\n"); 11576387f866SBrian Austin /* error is no longer asserted; safe to reset */ 11586387f866SBrian Austin if (!(current1 & CS35L35_AMP_SHORT)) { 11595d3d0ad6SCharles Keepax dev_dbg(cs35l35->dev, "Amp short error release\n"); 11606387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 11616387f866SBrian Austin CS35L35_PROT_RELEASE_CTL, 11626387f866SBrian Austin CS35L35_SHORT_RLS, 0); 11636387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 11646387f866SBrian Austin CS35L35_PROT_RELEASE_CTL, 11656387f866SBrian Austin CS35L35_SHORT_RLS, 11666387f866SBrian Austin CS35L35_SHORT_RLS); 11676387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 11686387f866SBrian Austin CS35L35_PROT_RELEASE_CTL, 11696387f866SBrian Austin CS35L35_SHORT_RLS, 0); 11706387f866SBrian Austin } 11716387f866SBrian Austin } 11726387f866SBrian Austin 11736387f866SBrian Austin if (sticky1 & CS35L35_OTW) { 11745d3d0ad6SCharles Keepax dev_warn(cs35l35->dev, "Over temperature warning\n"); 11756387f866SBrian Austin 11766387f866SBrian Austin /* error is no longer asserted; safe to reset */ 11776387f866SBrian Austin if (!(current1 & CS35L35_OTW)) { 11785d3d0ad6SCharles Keepax dev_dbg(cs35l35->dev, "Over temperature warn release\n"); 11796387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 11806387f866SBrian Austin CS35L35_PROT_RELEASE_CTL, 11816387f866SBrian Austin CS35L35_OTW_RLS, 0); 11826387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 11836387f866SBrian Austin CS35L35_PROT_RELEASE_CTL, 11846387f866SBrian Austin CS35L35_OTW_RLS, 11856387f866SBrian Austin CS35L35_OTW_RLS); 11866387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 11876387f866SBrian Austin CS35L35_PROT_RELEASE_CTL, 11886387f866SBrian Austin CS35L35_OTW_RLS, 0); 11896387f866SBrian Austin } 11906387f866SBrian Austin } 11916387f866SBrian Austin 11926387f866SBrian Austin if (sticky1 & CS35L35_OTE) { 11935d3d0ad6SCharles Keepax dev_crit(cs35l35->dev, "Over temperature error\n"); 11946387f866SBrian Austin /* error is no longer asserted; safe to reset */ 11956387f866SBrian Austin if (!(current1 & CS35L35_OTE)) { 11965d3d0ad6SCharles Keepax dev_dbg(cs35l35->dev, "Over temperature error release\n"); 11976387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 11986387f866SBrian Austin CS35L35_PROT_RELEASE_CTL, 11996387f866SBrian Austin CS35L35_OTE_RLS, 0); 12006387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 12016387f866SBrian Austin CS35L35_PROT_RELEASE_CTL, 12026387f866SBrian Austin CS35L35_OTE_RLS, 12036387f866SBrian Austin CS35L35_OTE_RLS); 12046387f866SBrian Austin regmap_update_bits(cs35l35->regmap, 12056387f866SBrian Austin CS35L35_PROT_RELEASE_CTL, 12066387f866SBrian Austin CS35L35_OTE_RLS, 0); 12076387f866SBrian Austin } 12086387f866SBrian Austin } 12096387f866SBrian Austin 12106387f866SBrian Austin if (sticky3 & CS35L35_BST_HIGH) { 12115d3d0ad6SCharles Keepax dev_crit(cs35l35->dev, "VBST error: powering off!\n"); 12126387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, 12136387f866SBrian Austin CS35L35_PDN_AMP, CS35L35_PDN_AMP); 12146387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL1, 12156387f866SBrian Austin CS35L35_PDN_ALL, CS35L35_PDN_ALL); 12166387f866SBrian Austin } 12176387f866SBrian Austin 12186387f866SBrian Austin if (sticky3 & CS35L35_LBST_SHORT) { 12195d3d0ad6SCharles Keepax dev_crit(cs35l35->dev, "LBST error: powering off!\n"); 12206387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, 12216387f866SBrian Austin CS35L35_PDN_AMP, CS35L35_PDN_AMP); 12226387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL1, 12236387f866SBrian Austin CS35L35_PDN_ALL, CS35L35_PDN_ALL); 12246387f866SBrian Austin } 12256387f866SBrian Austin 12266387f866SBrian Austin if (sticky2 & CS35L35_VPBR_ERR) 12275d3d0ad6SCharles Keepax dev_dbg(cs35l35->dev, "Error: Reactive Brownout\n"); 12286387f866SBrian Austin 12296387f866SBrian Austin if (sticky4 & CS35L35_VMON_OVFL) 12305d3d0ad6SCharles Keepax dev_dbg(cs35l35->dev, "Error: VMON overflow\n"); 12316387f866SBrian Austin 12326387f866SBrian Austin if (sticky4 & CS35L35_IMON_OVFL) 12335d3d0ad6SCharles Keepax dev_dbg(cs35l35->dev, "Error: IMON overflow\n"); 12346387f866SBrian Austin 12356387f866SBrian Austin return IRQ_HANDLED; 12366387f866SBrian Austin } 12376387f866SBrian Austin 12386387f866SBrian Austin 12396387f866SBrian Austin static int cs35l35_handle_of_data(struct i2c_client *i2c_client, 12406387f866SBrian Austin struct cs35l35_platform_data *pdata) 12416387f866SBrian Austin { 12426387f866SBrian Austin struct device_node *np = i2c_client->dev.of_node; 12436387f866SBrian Austin struct device_node *classh, *signal_format; 12446387f866SBrian Austin struct classh_cfg *classh_config = &pdata->classh_algo; 12456387f866SBrian Austin struct monitor_cfg *monitor_config = &pdata->mon_cfg; 12466387f866SBrian Austin unsigned int val32 = 0; 124706bdf385SCharles Keepax u8 monitor_array[4]; 124806bdf385SCharles Keepax const int imon_array_size = ARRAY_SIZE(monitor_array); 124906bdf385SCharles Keepax const int mon_array_size = imon_array_size - 1; 12506387f866SBrian Austin int ret = 0; 12516387f866SBrian Austin 12526387f866SBrian Austin if (!np) 12536387f866SBrian Austin return 0; 12546387f866SBrian Austin 12556387f866SBrian Austin pdata->bst_pdn_fet_on = of_property_read_bool(np, 12566387f866SBrian Austin "cirrus,boost-pdn-fet-on"); 12576387f866SBrian Austin 12586387f866SBrian Austin ret = of_property_read_u32(np, "cirrus,boost-ctl-millivolt", &val32); 12596387f866SBrian Austin if (ret >= 0) { 12606387f866SBrian Austin if (val32 < 2600 || val32 > 9000) { 12616387f866SBrian Austin dev_err(&i2c_client->dev, 12626387f866SBrian Austin "Invalid Boost Voltage %d mV\n", val32); 12636387f866SBrian Austin return -EINVAL; 12646387f866SBrian Austin } 12656387f866SBrian Austin pdata->bst_vctl = ((val32 - 2600) / 100) + 1; 12666387f866SBrian Austin } 12676387f866SBrian Austin 12686387f866SBrian Austin ret = of_property_read_u32(np, "cirrus,boost-peak-milliamp", &val32); 12696387f866SBrian Austin if (ret >= 0) { 12706387f866SBrian Austin if (val32 < 1680 || val32 > 4480) { 12716387f866SBrian Austin dev_err(&i2c_client->dev, 12726387f866SBrian Austin "Invalid Boost Peak Current %u mA\n", val32); 12736387f866SBrian Austin return -EINVAL; 12746387f866SBrian Austin } 12756387f866SBrian Austin 1276486fb959SCharles Keepax pdata->bst_ipk = ((val32 - 1680) / 110) | CS35L35_VALID_PDATA; 12776387f866SBrian Austin } 12786387f866SBrian Austin 1279b7c752d6SBrian Austin ret = of_property_read_u32(np, "cirrus,boost-ind-nanohenry", &val32); 1280b7c752d6SBrian Austin if (ret >= 0) { 1281b7c752d6SBrian Austin pdata->boost_ind = val32; 1282b7c752d6SBrian Austin } else { 1283b7c752d6SBrian Austin dev_err(&i2c_client->dev, "Inductor not specified.\n"); 1284b7c752d6SBrian Austin return -EINVAL; 12856387f866SBrian Austin } 12866387f866SBrian Austin 12876387f866SBrian Austin if (of_property_read_u32(np, "cirrus,sp-drv-strength", &val32) >= 0) 12886387f866SBrian Austin pdata->sp_drv_str = val32; 12898d45f2d2SCharles Keepax if (of_property_read_u32(np, "cirrus,sp-drv-unused", &val32) >= 0) 12908d45f2d2SCharles Keepax pdata->sp_drv_unused = val32 | CS35L35_VALID_PDATA; 12916387f866SBrian Austin 12926387f866SBrian Austin pdata->stereo = of_property_read_bool(np, "cirrus,stereo-config"); 12936387f866SBrian Austin 12946387f866SBrian Austin if (pdata->stereo) { 12956387f866SBrian Austin ret = of_property_read_u32(np, "cirrus,audio-channel", &val32); 12966387f866SBrian Austin if (ret >= 0) 12976387f866SBrian Austin pdata->aud_channel = val32; 12986387f866SBrian Austin 12996387f866SBrian Austin ret = of_property_read_u32(np, "cirrus,advisory-channel", 13006387f866SBrian Austin &val32); 13016387f866SBrian Austin if (ret >= 0) 13026387f866SBrian Austin pdata->adv_channel = val32; 13036387f866SBrian Austin 13046387f866SBrian Austin pdata->shared_bst = of_property_read_bool(np, 13056387f866SBrian Austin "cirrus,shared-boost"); 13066387f866SBrian Austin } 13076387f866SBrian Austin 130877b329d1SCharles Keepax pdata->ext_bst = of_property_read_bool(np, "cirrus,external-boost"); 130977b329d1SCharles Keepax 13106387f866SBrian Austin pdata->gain_zc = of_property_read_bool(np, "cirrus,amp-gain-zc"); 13116387f866SBrian Austin 13126387f866SBrian Austin classh = of_get_child_by_name(np, "cirrus,classh-internal-algo"); 1313e733ab7eSBernard Zhao classh_config->classh_algo_enable = (classh != NULL); 13146387f866SBrian Austin 13156387f866SBrian Austin if (classh_config->classh_algo_enable) { 13166387f866SBrian Austin classh_config->classh_bst_override = 13176387f866SBrian Austin of_property_read_bool(np, "cirrus,classh-bst-overide"); 13186387f866SBrian Austin 13196387f866SBrian Austin ret = of_property_read_u32(classh, 13206387f866SBrian Austin "cirrus,classh-bst-max-limit", 13216387f866SBrian Austin &val32); 13226387f866SBrian Austin if (ret >= 0) { 13236387f866SBrian Austin val32 |= CS35L35_VALID_PDATA; 13246387f866SBrian Austin classh_config->classh_bst_max_limit = val32; 13256387f866SBrian Austin } 13266387f866SBrian Austin 13276387f866SBrian Austin ret = of_property_read_u32(classh, 13286387f866SBrian Austin "cirrus,classh-bst-max-limit", 13296387f866SBrian Austin &val32); 13306387f866SBrian Austin if (ret >= 0) { 13316387f866SBrian Austin val32 |= CS35L35_VALID_PDATA; 13326387f866SBrian Austin classh_config->classh_bst_max_limit = val32; 13336387f866SBrian Austin } 13346387f866SBrian Austin 13356387f866SBrian Austin ret = of_property_read_u32(classh, "cirrus,classh-mem-depth", 13366387f866SBrian Austin &val32); 13376387f866SBrian Austin if (ret >= 0) { 13386387f866SBrian Austin val32 |= CS35L35_VALID_PDATA; 13396387f866SBrian Austin classh_config->classh_mem_depth = val32; 13406387f866SBrian Austin } 13416387f866SBrian Austin 13426387f866SBrian Austin ret = of_property_read_u32(classh, "cirrus,classh-release-rate", 13436387f866SBrian Austin &val32); 13446387f866SBrian Austin if (ret >= 0) 13456387f866SBrian Austin classh_config->classh_release_rate = val32; 13466387f866SBrian Austin 13476387f866SBrian Austin ret = of_property_read_u32(classh, "cirrus,classh-headroom", 13486387f866SBrian Austin &val32); 13496387f866SBrian Austin if (ret >= 0) { 13506387f866SBrian Austin val32 |= CS35L35_VALID_PDATA; 13516387f866SBrian Austin classh_config->classh_headroom = val32; 13526387f866SBrian Austin } 13536387f866SBrian Austin 13546387f866SBrian Austin ret = of_property_read_u32(classh, 13556387f866SBrian Austin "cirrus,classh-wk-fet-disable", 13566387f866SBrian Austin &val32); 13576387f866SBrian Austin if (ret >= 0) 13586387f866SBrian Austin classh_config->classh_wk_fet_disable = val32; 13596387f866SBrian Austin 13606387f866SBrian Austin ret = of_property_read_u32(classh, "cirrus,classh-wk-fet-delay", 13616387f866SBrian Austin &val32); 13626387f866SBrian Austin if (ret >= 0) { 13636387f866SBrian Austin val32 |= CS35L35_VALID_PDATA; 13646387f866SBrian Austin classh_config->classh_wk_fet_delay = val32; 13656387f866SBrian Austin } 13666387f866SBrian Austin 13676387f866SBrian Austin ret = of_property_read_u32(classh, "cirrus,classh-wk-fet-thld", 13686387f866SBrian Austin &val32); 13696387f866SBrian Austin if (ret >= 0) 13706387f866SBrian Austin classh_config->classh_wk_fet_thld = val32; 13716387f866SBrian Austin 13726387f866SBrian Austin ret = of_property_read_u32(classh, "cirrus,classh-vpch-auto", 13736387f866SBrian Austin &val32); 13746387f866SBrian Austin if (ret >= 0) { 13756387f866SBrian Austin val32 |= CS35L35_VALID_PDATA; 13766387f866SBrian Austin classh_config->classh_vpch_auto = val32; 13776387f866SBrian Austin } 13786387f866SBrian Austin 13796387f866SBrian Austin ret = of_property_read_u32(classh, "cirrus,classh-vpch-rate", 13806387f866SBrian Austin &val32); 13816387f866SBrian Austin if (ret >= 0) { 13826387f866SBrian Austin val32 |= CS35L35_VALID_PDATA; 13836387f866SBrian Austin classh_config->classh_vpch_rate = val32; 13846387f866SBrian Austin } 13856387f866SBrian Austin 13866387f866SBrian Austin ret = of_property_read_u32(classh, "cirrus,classh-vpch-man", 13876387f866SBrian Austin &val32); 13886387f866SBrian Austin if (ret >= 0) 13896387f866SBrian Austin classh_config->classh_vpch_man = val32; 13906387f866SBrian Austin } 13916387f866SBrian Austin of_node_put(classh); 13926387f866SBrian Austin 13936387f866SBrian Austin /* frame depth location */ 13946387f866SBrian Austin signal_format = of_get_child_by_name(np, "cirrus,monitor-signal-format"); 13956387f866SBrian Austin monitor_config->is_present = signal_format ? true : false; 13966387f866SBrian Austin if (monitor_config->is_present) { 13976387f866SBrian Austin ret = of_property_read_u8_array(signal_format, "cirrus,imon", 139806bdf385SCharles Keepax monitor_array, imon_array_size); 13996387f866SBrian Austin if (!ret) { 14006387f866SBrian Austin monitor_config->imon_specs = true; 14016387f866SBrian Austin monitor_config->imon_dpth = monitor_array[0]; 14026387f866SBrian Austin monitor_config->imon_loc = monitor_array[1]; 14036387f866SBrian Austin monitor_config->imon_frm = monitor_array[2]; 140406bdf385SCharles Keepax monitor_config->imon_scale = monitor_array[3]; 14056387f866SBrian Austin } 14066387f866SBrian Austin ret = of_property_read_u8_array(signal_format, "cirrus,vmon", 140706bdf385SCharles Keepax monitor_array, mon_array_size); 14086387f866SBrian Austin if (!ret) { 14096387f866SBrian Austin monitor_config->vmon_specs = true; 14106387f866SBrian Austin monitor_config->vmon_dpth = monitor_array[0]; 14116387f866SBrian Austin monitor_config->vmon_loc = monitor_array[1]; 14126387f866SBrian Austin monitor_config->vmon_frm = monitor_array[2]; 14136387f866SBrian Austin } 14146387f866SBrian Austin ret = of_property_read_u8_array(signal_format, "cirrus,vpmon", 141506bdf385SCharles Keepax monitor_array, mon_array_size); 14166387f866SBrian Austin if (!ret) { 14176387f866SBrian Austin monitor_config->vpmon_specs = true; 14186387f866SBrian Austin monitor_config->vpmon_dpth = monitor_array[0]; 14196387f866SBrian Austin monitor_config->vpmon_loc = monitor_array[1]; 14206387f866SBrian Austin monitor_config->vpmon_frm = monitor_array[2]; 14216387f866SBrian Austin } 14226387f866SBrian Austin ret = of_property_read_u8_array(signal_format, "cirrus,vbstmon", 142306bdf385SCharles Keepax monitor_array, mon_array_size); 14246387f866SBrian Austin if (!ret) { 14256387f866SBrian Austin monitor_config->vbstmon_specs = true; 14266387f866SBrian Austin monitor_config->vbstmon_dpth = monitor_array[0]; 14276387f866SBrian Austin monitor_config->vbstmon_loc = monitor_array[1]; 14286387f866SBrian Austin monitor_config->vbstmon_frm = monitor_array[2]; 14296387f866SBrian Austin } 14306387f866SBrian Austin ret = of_property_read_u8_array(signal_format, "cirrus,vpbrstat", 143106bdf385SCharles Keepax monitor_array, mon_array_size); 14326387f866SBrian Austin if (!ret) { 14336387f866SBrian Austin monitor_config->vpbrstat_specs = true; 14346387f866SBrian Austin monitor_config->vpbrstat_dpth = monitor_array[0]; 14356387f866SBrian Austin monitor_config->vpbrstat_loc = monitor_array[1]; 14366387f866SBrian Austin monitor_config->vpbrstat_frm = monitor_array[2]; 14376387f866SBrian Austin } 14386387f866SBrian Austin ret = of_property_read_u8_array(signal_format, "cirrus,zerofill", 143906bdf385SCharles Keepax monitor_array, mon_array_size); 14406387f866SBrian Austin if (!ret) { 14416387f866SBrian Austin monitor_config->zerofill_specs = true; 14426387f866SBrian Austin monitor_config->zerofill_dpth = monitor_array[0]; 14436387f866SBrian Austin monitor_config->zerofill_loc = monitor_array[1]; 14446387f866SBrian Austin monitor_config->zerofill_frm = monitor_array[2]; 14456387f866SBrian Austin } 14466387f866SBrian Austin } 14476387f866SBrian Austin of_node_put(signal_format); 14486387f866SBrian Austin 14496387f866SBrian Austin return 0; 14506387f866SBrian Austin } 14516387f866SBrian Austin 14526387f866SBrian Austin /* Errata Rev A0 */ 14536387f866SBrian Austin static const struct reg_sequence cs35l35_errata_patch[] = { 14546387f866SBrian Austin 14556387f866SBrian Austin { 0x7F, 0x99 }, 14566387f866SBrian Austin { 0x00, 0x99 }, 14576387f866SBrian Austin { 0x52, 0x22 }, 14586387f866SBrian Austin { 0x04, 0x14 }, 14596387f866SBrian Austin { 0x6D, 0x44 }, 14606387f866SBrian Austin { 0x24, 0x10 }, 14616387f866SBrian Austin { 0x58, 0xC4 }, 14626387f866SBrian Austin { 0x00, 0x98 }, 14636387f866SBrian Austin { 0x18, 0x08 }, 14646387f866SBrian Austin { 0x00, 0x00 }, 14656387f866SBrian Austin { 0x7F, 0x00 }, 14666387f866SBrian Austin }; 14676387f866SBrian Austin 14684a404345SStephen Kitt static int cs35l35_i2c_probe(struct i2c_client *i2c_client) 14696387f866SBrian Austin { 14706387f866SBrian Austin struct cs35l35_private *cs35l35; 14711f758cd9SCharles Keepax struct device *dev = &i2c_client->dev; 14721f758cd9SCharles Keepax struct cs35l35_platform_data *pdata = dev_get_platdata(dev); 147360ba916dSCharles Keepax int i, devid; 14746387f866SBrian Austin int ret; 14756387f866SBrian Austin unsigned int reg; 14766387f866SBrian Austin 14771f758cd9SCharles Keepax cs35l35 = devm_kzalloc(dev, sizeof(struct cs35l35_private), GFP_KERNEL); 14786387f866SBrian Austin if (!cs35l35) 14796387f866SBrian Austin return -ENOMEM; 14806387f866SBrian Austin 14815d3d0ad6SCharles Keepax cs35l35->dev = dev; 14825d3d0ad6SCharles Keepax 14836387f866SBrian Austin i2c_set_clientdata(i2c_client, cs35l35); 14846387f866SBrian Austin cs35l35->regmap = devm_regmap_init_i2c(i2c_client, &cs35l35_regmap); 14856387f866SBrian Austin if (IS_ERR(cs35l35->regmap)) { 14866387f866SBrian Austin ret = PTR_ERR(cs35l35->regmap); 14871f758cd9SCharles Keepax dev_err(dev, "regmap_init() failed: %d\n", ret); 148838c694e9SChristophe JAILLET return ret; 14896387f866SBrian Austin } 14906387f866SBrian Austin 14916387f866SBrian Austin for (i = 0; i < ARRAY_SIZE(cs35l35_supplies); i++) 14926387f866SBrian Austin cs35l35->supplies[i].supply = cs35l35_supplies[i]; 149303ff570cSColin Ian King 14946387f866SBrian Austin cs35l35->num_supplies = ARRAY_SIZE(cs35l35_supplies); 14956387f866SBrian Austin 14961f758cd9SCharles Keepax ret = devm_regulator_bulk_get(dev, cs35l35->num_supplies, 14976387f866SBrian Austin cs35l35->supplies); 14986387f866SBrian Austin if (ret != 0) { 14991f758cd9SCharles Keepax dev_err(dev, "Failed to request core supplies: %d\n", ret); 15006387f866SBrian Austin return ret; 15016387f866SBrian Austin } 15026387f866SBrian Austin 15036387f866SBrian Austin if (pdata) { 15046387f866SBrian Austin cs35l35->pdata = *pdata; 15056387f866SBrian Austin } else { 15061f758cd9SCharles Keepax pdata = devm_kzalloc(dev, sizeof(struct cs35l35_platform_data), 15076387f866SBrian Austin GFP_KERNEL); 15086387f866SBrian Austin if (!pdata) 15096387f866SBrian Austin return -ENOMEM; 15106387f866SBrian Austin if (i2c_client->dev.of_node) { 15116387f866SBrian Austin ret = cs35l35_handle_of_data(i2c_client, pdata); 15126387f866SBrian Austin if (ret != 0) 15136387f866SBrian Austin return ret; 15146387f866SBrian Austin 15156387f866SBrian Austin } 15166387f866SBrian Austin cs35l35->pdata = *pdata; 15176387f866SBrian Austin } 15186387f866SBrian Austin 15196387f866SBrian Austin ret = regulator_bulk_enable(cs35l35->num_supplies, 15206387f866SBrian Austin cs35l35->supplies); 15216387f866SBrian Austin if (ret != 0) { 15221f758cd9SCharles Keepax dev_err(dev, "Failed to enable core supplies: %d\n", ret); 15236387f866SBrian Austin return ret; 15246387f866SBrian Austin } 15256387f866SBrian Austin 15266387f866SBrian Austin /* returning NULL can be valid if in stereo mode */ 15271f758cd9SCharles Keepax cs35l35->reset_gpio = devm_gpiod_get_optional(dev, "reset", 15281f758cd9SCharles Keepax GPIOD_OUT_LOW); 15296387f866SBrian Austin if (IS_ERR(cs35l35->reset_gpio)) { 15306387f866SBrian Austin ret = PTR_ERR(cs35l35->reset_gpio); 15318e71321dSCharles Keepax cs35l35->reset_gpio = NULL; 15326387f866SBrian Austin if (ret == -EBUSY) { 15331f758cd9SCharles Keepax dev_info(dev, 15346387f866SBrian Austin "Reset line busy, assuming shared reset\n"); 15356387f866SBrian Austin } else { 15361f758cd9SCharles Keepax dev_err(dev, "Failed to get reset GPIO: %d\n", ret); 15376387f866SBrian Austin goto err; 15386387f866SBrian Austin } 15396387f866SBrian Austin } 15406387f866SBrian Austin 1541dc43f46aSCharles Keepax cs35l35_reset(cs35l35); 15426387f866SBrian Austin 15436387f866SBrian Austin init_completion(&cs35l35->pdn_done); 15446387f866SBrian Austin 15451f758cd9SCharles Keepax ret = devm_request_threaded_irq(dev, i2c_client->irq, NULL, cs35l35_irq, 1546bf5043d6SCharles Keepax IRQF_ONESHOT | IRQF_TRIGGER_LOW | 1547bf5043d6SCharles Keepax IRQF_SHARED, "cs35l35", cs35l35); 15486387f866SBrian Austin if (ret != 0) { 15491f758cd9SCharles Keepax dev_err(dev, "Failed to request IRQ: %d\n", ret); 15506387f866SBrian Austin goto err; 15516387f866SBrian Austin } 15526387f866SBrian Austin /* initialize codec */ 155360ba916dSCharles Keepax devid = cirrus_read_device_id(cs35l35->regmap, CS35L35_DEVID_AB); 155460ba916dSCharles Keepax if (devid < 0) { 155560ba916dSCharles Keepax ret = devid; 155660ba916dSCharles Keepax dev_err(dev, "Failed to read device ID: %d\n", ret); 155760ba916dSCharles Keepax goto err; 155860ba916dSCharles Keepax } 15596387f866SBrian Austin 15606387f866SBrian Austin if (devid != CS35L35_CHIP_ID) { 15611f758cd9SCharles Keepax dev_err(dev, "CS35L35 Device ID (%X). Expected ID %X\n", 15626387f866SBrian Austin devid, CS35L35_CHIP_ID); 15636387f866SBrian Austin ret = -ENODEV; 15646387f866SBrian Austin goto err; 15656387f866SBrian Austin } 15666387f866SBrian Austin 15676387f866SBrian Austin ret = regmap_read(cs35l35->regmap, CS35L35_REV_ID, ®); 15686387f866SBrian Austin if (ret < 0) { 15691f758cd9SCharles Keepax dev_err(dev, "Get Revision ID failed: %d\n", ret); 15706387f866SBrian Austin goto err; 15716387f866SBrian Austin } 15726387f866SBrian Austin 15736387f866SBrian Austin ret = regmap_register_patch(cs35l35->regmap, cs35l35_errata_patch, 15746387f866SBrian Austin ARRAY_SIZE(cs35l35_errata_patch)); 15756387f866SBrian Austin if (ret < 0) { 15761f758cd9SCharles Keepax dev_err(dev, "Failed to apply errata patch: %d\n", ret); 15776387f866SBrian Austin goto err; 15786387f866SBrian Austin } 15796387f866SBrian Austin 15801f758cd9SCharles Keepax dev_info(dev, "Cirrus Logic CS35L35 (%x), Revision: %02X\n", 158182875163SAxel Lin devid, reg & 0xFF); 15826387f866SBrian Austin 15836387f866SBrian Austin /* Set the INT Masks for critical errors */ 15846387f866SBrian Austin regmap_write(cs35l35->regmap, CS35L35_INT_MASK_1, 15856387f866SBrian Austin CS35L35_INT1_CRIT_MASK); 15866387f866SBrian Austin regmap_write(cs35l35->regmap, CS35L35_INT_MASK_2, 15876387f866SBrian Austin CS35L35_INT2_CRIT_MASK); 15886387f866SBrian Austin regmap_write(cs35l35->regmap, CS35L35_INT_MASK_3, 15896387f866SBrian Austin CS35L35_INT3_CRIT_MASK); 15906387f866SBrian Austin regmap_write(cs35l35->regmap, CS35L35_INT_MASK_4, 15916387f866SBrian Austin CS35L35_INT4_CRIT_MASK); 15926387f866SBrian Austin 15936387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, 15946387f866SBrian Austin CS35L35_PWR2_PDN_MASK, 15956387f866SBrian Austin CS35L35_PWR2_PDN_MASK); 15966387f866SBrian Austin 15976387f866SBrian Austin if (cs35l35->pdata.bst_pdn_fet_on) 15986387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, 15996387f866SBrian Austin CS35L35_PDN_BST_MASK, 16006387f866SBrian Austin 1 << CS35L35_PDN_BST_FETON_SHIFT); 16016387f866SBrian Austin else 16026387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, 16036387f866SBrian Austin CS35L35_PDN_BST_MASK, 16046387f866SBrian Austin 1 << CS35L35_PDN_BST_FETOFF_SHIFT); 16056387f866SBrian Austin 16066387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL3, 16076387f866SBrian Austin CS35L35_PWR3_PDN_MASK, 16086387f866SBrian Austin CS35L35_PWR3_PDN_MASK); 16096387f866SBrian Austin 16106387f866SBrian Austin regmap_update_bits(cs35l35->regmap, CS35L35_PROTECT_CTL, 16116387f866SBrian Austin CS35L35_AMP_MUTE_MASK, 1 << CS35L35_AMP_MUTE_SHIFT); 16126387f866SBrian Austin 161386c2eddfSKuninori Morimoto ret = devm_snd_soc_register_component(dev, &soc_component_dev_cs35l35, 161486c2eddfSKuninori Morimoto cs35l35_dai, ARRAY_SIZE(cs35l35_dai)); 16156387f866SBrian Austin if (ret < 0) { 161686c2eddfSKuninori Morimoto dev_err(dev, "Failed to register component: %d\n", ret); 16176387f866SBrian Austin goto err; 16186387f866SBrian Austin } 16196387f866SBrian Austin 16201bb06adaSCharles Keepax return 0; 16211bb06adaSCharles Keepax 16226387f866SBrian Austin err: 16236387f866SBrian Austin regulator_bulk_disable(cs35l35->num_supplies, 16246387f866SBrian Austin cs35l35->supplies); 16256387f866SBrian Austin gpiod_set_value_cansleep(cs35l35->reset_gpio, 0); 16266387f866SBrian Austin 16276387f866SBrian Austin return ret; 16286387f866SBrian Austin } 16296387f866SBrian Austin 1630ed5c2f5fSUwe Kleine-König static void cs35l35_i2c_remove(struct i2c_client *i2c_client) 163147c4cc08SCharles Keepax { 163247c4cc08SCharles Keepax struct cs35l35_private *cs35l35 = i2c_get_clientdata(i2c_client); 163347c4cc08SCharles Keepax 163447c4cc08SCharles Keepax regulator_bulk_disable(cs35l35->num_supplies, cs35l35->supplies); 163547c4cc08SCharles Keepax gpiod_set_value_cansleep(cs35l35->reset_gpio, 0); 163647c4cc08SCharles Keepax } 163747c4cc08SCharles Keepax 16386387f866SBrian Austin static const struct of_device_id cs35l35_of_match[] = { 16396387f866SBrian Austin {.compatible = "cirrus,cs35l35"}, 16406387f866SBrian Austin {}, 16416387f866SBrian Austin }; 16426387f866SBrian Austin MODULE_DEVICE_TABLE(of, cs35l35_of_match); 16436387f866SBrian Austin 16446387f866SBrian Austin static const struct i2c_device_id cs35l35_id[] = { 16456387f866SBrian Austin {"cs35l35", 0}, 16466387f866SBrian Austin {} 16476387f866SBrian Austin }; 16486387f866SBrian Austin 16496387f866SBrian Austin MODULE_DEVICE_TABLE(i2c, cs35l35_id); 16506387f866SBrian Austin 16516387f866SBrian Austin static struct i2c_driver cs35l35_i2c_driver = { 16526387f866SBrian Austin .driver = { 16536387f866SBrian Austin .name = "cs35l35", 16546387f866SBrian Austin .of_match_table = cs35l35_of_match, 16556387f866SBrian Austin }, 16566387f866SBrian Austin .id_table = cs35l35_id, 16579abcd240SUwe Kleine-König .probe = cs35l35_i2c_probe, 165847c4cc08SCharles Keepax .remove = cs35l35_i2c_remove, 16596387f866SBrian Austin }; 16606387f866SBrian Austin 16616387f866SBrian Austin module_i2c_driver(cs35l35_i2c_driver); 16626387f866SBrian Austin 16636387f866SBrian Austin MODULE_DESCRIPTION("ASoC CS35L35 driver"); 16646387f866SBrian Austin MODULE_AUTHOR("Brian Austin, Cirrus Logic Inc, <brian.austin@cirrus.com>"); 16656387f866SBrian Austin MODULE_LICENSE("GPL"); 1666