162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * cs35l35.c -- CS35L35 ALSA SoC audio driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2017 Cirrus Logic, Inc. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Author: Brian Austin <brian.austin@cirrus.com> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/module.h> 1162306a36Sopenharmony_ci#include <linux/moduleparam.h> 1262306a36Sopenharmony_ci#include <linux/kernel.h> 1362306a36Sopenharmony_ci#include <linux/init.h> 1462306a36Sopenharmony_ci#include <linux/delay.h> 1562306a36Sopenharmony_ci#include <linux/i2c.h> 1662306a36Sopenharmony_ci#include <linux/slab.h> 1762306a36Sopenharmony_ci#include <linux/platform_device.h> 1862306a36Sopenharmony_ci#include <linux/regulator/consumer.h> 1962306a36Sopenharmony_ci#include <linux/gpio/consumer.h> 2062306a36Sopenharmony_ci#include <linux/of_device.h> 2162306a36Sopenharmony_ci#include <linux/of_gpio.h> 2262306a36Sopenharmony_ci#include <linux/regmap.h> 2362306a36Sopenharmony_ci#include <sound/core.h> 2462306a36Sopenharmony_ci#include <sound/pcm.h> 2562306a36Sopenharmony_ci#include <sound/pcm_params.h> 2662306a36Sopenharmony_ci#include <sound/soc.h> 2762306a36Sopenharmony_ci#include <sound/soc-dapm.h> 2862306a36Sopenharmony_ci#include <linux/gpio.h> 2962306a36Sopenharmony_ci#include <sound/initval.h> 3062306a36Sopenharmony_ci#include <sound/tlv.h> 3162306a36Sopenharmony_ci#include <sound/cs35l35.h> 3262306a36Sopenharmony_ci#include <linux/of_irq.h> 3362306a36Sopenharmony_ci#include <linux/completion.h> 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#include "cs35l35.h" 3662306a36Sopenharmony_ci#include "cirrus_legacy.h" 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci/* 3962306a36Sopenharmony_ci * Some fields take zero as a valid value so use a high bit flag that won't 4062306a36Sopenharmony_ci * get written to the device to mark those. 4162306a36Sopenharmony_ci */ 4262306a36Sopenharmony_ci#define CS35L35_VALID_PDATA 0x80000000 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cistatic const struct reg_default cs35l35_reg[] = { 4562306a36Sopenharmony_ci {CS35L35_PWRCTL1, 0x01}, 4662306a36Sopenharmony_ci {CS35L35_PWRCTL2, 0x11}, 4762306a36Sopenharmony_ci {CS35L35_PWRCTL3, 0x00}, 4862306a36Sopenharmony_ci {CS35L35_CLK_CTL1, 0x04}, 4962306a36Sopenharmony_ci {CS35L35_CLK_CTL2, 0x12}, 5062306a36Sopenharmony_ci {CS35L35_CLK_CTL3, 0xCF}, 5162306a36Sopenharmony_ci {CS35L35_SP_FMT_CTL1, 0x20}, 5262306a36Sopenharmony_ci {CS35L35_SP_FMT_CTL2, 0x00}, 5362306a36Sopenharmony_ci {CS35L35_SP_FMT_CTL3, 0x02}, 5462306a36Sopenharmony_ci {CS35L35_MAG_COMP_CTL, 0x00}, 5562306a36Sopenharmony_ci {CS35L35_AMP_INP_DRV_CTL, 0x01}, 5662306a36Sopenharmony_ci {CS35L35_AMP_DIG_VOL_CTL, 0x12}, 5762306a36Sopenharmony_ci {CS35L35_AMP_DIG_VOL, 0x00}, 5862306a36Sopenharmony_ci {CS35L35_ADV_DIG_VOL, 0x00}, 5962306a36Sopenharmony_ci {CS35L35_PROTECT_CTL, 0x06}, 6062306a36Sopenharmony_ci {CS35L35_AMP_GAIN_AUD_CTL, 0x13}, 6162306a36Sopenharmony_ci {CS35L35_AMP_GAIN_PDM_CTL, 0x00}, 6262306a36Sopenharmony_ci {CS35L35_AMP_GAIN_ADV_CTL, 0x00}, 6362306a36Sopenharmony_ci {CS35L35_GPI_CTL, 0x00}, 6462306a36Sopenharmony_ci {CS35L35_BST_CVTR_V_CTL, 0x00}, 6562306a36Sopenharmony_ci {CS35L35_BST_PEAK_I, 0x07}, 6662306a36Sopenharmony_ci {CS35L35_BST_RAMP_CTL, 0x85}, 6762306a36Sopenharmony_ci {CS35L35_BST_CONV_COEF_1, 0x24}, 6862306a36Sopenharmony_ci {CS35L35_BST_CONV_COEF_2, 0x24}, 6962306a36Sopenharmony_ci {CS35L35_BST_CONV_SLOPE_COMP, 0x4E}, 7062306a36Sopenharmony_ci {CS35L35_BST_CONV_SW_FREQ, 0x04}, 7162306a36Sopenharmony_ci {CS35L35_CLASS_H_CTL, 0x0B}, 7262306a36Sopenharmony_ci {CS35L35_CLASS_H_HEADRM_CTL, 0x0B}, 7362306a36Sopenharmony_ci {CS35L35_CLASS_H_RELEASE_RATE, 0x08}, 7462306a36Sopenharmony_ci {CS35L35_CLASS_H_FET_DRIVE_CTL, 0x41}, 7562306a36Sopenharmony_ci {CS35L35_CLASS_H_VP_CTL, 0xC5}, 7662306a36Sopenharmony_ci {CS35L35_VPBR_CTL, 0x0A}, 7762306a36Sopenharmony_ci {CS35L35_VPBR_VOL_CTL, 0x90}, 7862306a36Sopenharmony_ci {CS35L35_VPBR_TIMING_CTL, 0x6A}, 7962306a36Sopenharmony_ci {CS35L35_VPBR_MODE_VOL_CTL, 0x00}, 8062306a36Sopenharmony_ci {CS35L35_SPKR_MON_CTL, 0xC0}, 8162306a36Sopenharmony_ci {CS35L35_IMON_SCALE_CTL, 0x30}, 8262306a36Sopenharmony_ci {CS35L35_AUDIN_RXLOC_CTL, 0x00}, 8362306a36Sopenharmony_ci {CS35L35_ADVIN_RXLOC_CTL, 0x80}, 8462306a36Sopenharmony_ci {CS35L35_VMON_TXLOC_CTL, 0x00}, 8562306a36Sopenharmony_ci {CS35L35_IMON_TXLOC_CTL, 0x80}, 8662306a36Sopenharmony_ci {CS35L35_VPMON_TXLOC_CTL, 0x04}, 8762306a36Sopenharmony_ci {CS35L35_VBSTMON_TXLOC_CTL, 0x84}, 8862306a36Sopenharmony_ci {CS35L35_VPBR_STATUS_TXLOC_CTL, 0x04}, 8962306a36Sopenharmony_ci {CS35L35_ZERO_FILL_LOC_CTL, 0x00}, 9062306a36Sopenharmony_ci {CS35L35_AUDIN_DEPTH_CTL, 0x0F}, 9162306a36Sopenharmony_ci {CS35L35_SPKMON_DEPTH_CTL, 0x0F}, 9262306a36Sopenharmony_ci {CS35L35_SUPMON_DEPTH_CTL, 0x0F}, 9362306a36Sopenharmony_ci {CS35L35_ZEROFILL_DEPTH_CTL, 0x00}, 9462306a36Sopenharmony_ci {CS35L35_MULT_DEV_SYNCH1, 0x02}, 9562306a36Sopenharmony_ci {CS35L35_MULT_DEV_SYNCH2, 0x80}, 9662306a36Sopenharmony_ci {CS35L35_PROT_RELEASE_CTL, 0x00}, 9762306a36Sopenharmony_ci {CS35L35_DIAG_MODE_REG_LOCK, 0x00}, 9862306a36Sopenharmony_ci {CS35L35_DIAG_MODE_CTL_1, 0x40}, 9962306a36Sopenharmony_ci {CS35L35_DIAG_MODE_CTL_2, 0x00}, 10062306a36Sopenharmony_ci {CS35L35_INT_MASK_1, 0xFF}, 10162306a36Sopenharmony_ci {CS35L35_INT_MASK_2, 0xFF}, 10262306a36Sopenharmony_ci {CS35L35_INT_MASK_3, 0xFF}, 10362306a36Sopenharmony_ci {CS35L35_INT_MASK_4, 0xFF}, 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci}; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_cistatic bool cs35l35_volatile_register(struct device *dev, unsigned int reg) 10862306a36Sopenharmony_ci{ 10962306a36Sopenharmony_ci switch (reg) { 11062306a36Sopenharmony_ci case CS35L35_INT_STATUS_1: 11162306a36Sopenharmony_ci case CS35L35_INT_STATUS_2: 11262306a36Sopenharmony_ci case CS35L35_INT_STATUS_3: 11362306a36Sopenharmony_ci case CS35L35_INT_STATUS_4: 11462306a36Sopenharmony_ci case CS35L35_PLL_STATUS: 11562306a36Sopenharmony_ci case CS35L35_OTP_TRIM_STATUS: 11662306a36Sopenharmony_ci return true; 11762306a36Sopenharmony_ci default: 11862306a36Sopenharmony_ci return false; 11962306a36Sopenharmony_ci } 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_cistatic bool cs35l35_readable_register(struct device *dev, unsigned int reg) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci switch (reg) { 12562306a36Sopenharmony_ci case CS35L35_DEVID_AB ... CS35L35_PWRCTL3: 12662306a36Sopenharmony_ci case CS35L35_CLK_CTL1 ... CS35L35_SP_FMT_CTL3: 12762306a36Sopenharmony_ci case CS35L35_MAG_COMP_CTL ... CS35L35_AMP_GAIN_AUD_CTL: 12862306a36Sopenharmony_ci case CS35L35_AMP_GAIN_PDM_CTL ... CS35L35_BST_PEAK_I: 12962306a36Sopenharmony_ci case CS35L35_BST_RAMP_CTL ... CS35L35_BST_CONV_SW_FREQ: 13062306a36Sopenharmony_ci case CS35L35_CLASS_H_CTL ... CS35L35_CLASS_H_VP_CTL: 13162306a36Sopenharmony_ci case CS35L35_CLASS_H_STATUS: 13262306a36Sopenharmony_ci case CS35L35_VPBR_CTL ... CS35L35_VPBR_MODE_VOL_CTL: 13362306a36Sopenharmony_ci case CS35L35_VPBR_ATTEN_STATUS: 13462306a36Sopenharmony_ci case CS35L35_SPKR_MON_CTL: 13562306a36Sopenharmony_ci case CS35L35_IMON_SCALE_CTL ... CS35L35_ZEROFILL_DEPTH_CTL: 13662306a36Sopenharmony_ci case CS35L35_MULT_DEV_SYNCH1 ... CS35L35_PROT_RELEASE_CTL: 13762306a36Sopenharmony_ci case CS35L35_DIAG_MODE_REG_LOCK ... CS35L35_DIAG_MODE_CTL_2: 13862306a36Sopenharmony_ci case CS35L35_INT_MASK_1 ... CS35L35_PLL_STATUS: 13962306a36Sopenharmony_ci case CS35L35_OTP_TRIM_STATUS: 14062306a36Sopenharmony_ci return true; 14162306a36Sopenharmony_ci default: 14262306a36Sopenharmony_ci return false; 14362306a36Sopenharmony_ci } 14462306a36Sopenharmony_ci} 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_cistatic bool cs35l35_precious_register(struct device *dev, unsigned int reg) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci switch (reg) { 14962306a36Sopenharmony_ci case CS35L35_INT_STATUS_1: 15062306a36Sopenharmony_ci case CS35L35_INT_STATUS_2: 15162306a36Sopenharmony_ci case CS35L35_INT_STATUS_3: 15262306a36Sopenharmony_ci case CS35L35_INT_STATUS_4: 15362306a36Sopenharmony_ci case CS35L35_PLL_STATUS: 15462306a36Sopenharmony_ci case CS35L35_OTP_TRIM_STATUS: 15562306a36Sopenharmony_ci return true; 15662306a36Sopenharmony_ci default: 15762306a36Sopenharmony_ci return false; 15862306a36Sopenharmony_ci } 15962306a36Sopenharmony_ci} 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistatic void cs35l35_reset(struct cs35l35_private *cs35l35) 16262306a36Sopenharmony_ci{ 16362306a36Sopenharmony_ci gpiod_set_value_cansleep(cs35l35->reset_gpio, 0); 16462306a36Sopenharmony_ci usleep_range(2000, 2100); 16562306a36Sopenharmony_ci gpiod_set_value_cansleep(cs35l35->reset_gpio, 1); 16662306a36Sopenharmony_ci usleep_range(1000, 1100); 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cistatic int cs35l35_wait_for_pdn(struct cs35l35_private *cs35l35) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci int ret; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci if (cs35l35->pdata.ext_bst) { 17462306a36Sopenharmony_ci usleep_range(5000, 5500); 17562306a36Sopenharmony_ci return 0; 17662306a36Sopenharmony_ci } 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci reinit_completion(&cs35l35->pdn_done); 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci ret = wait_for_completion_timeout(&cs35l35->pdn_done, 18162306a36Sopenharmony_ci msecs_to_jiffies(100)); 18262306a36Sopenharmony_ci if (ret == 0) { 18362306a36Sopenharmony_ci dev_err(cs35l35->dev, "PDN_DONE did not complete\n"); 18462306a36Sopenharmony_ci return -ETIMEDOUT; 18562306a36Sopenharmony_ci } 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci return 0; 18862306a36Sopenharmony_ci} 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_cistatic int cs35l35_sdin_event(struct snd_soc_dapm_widget *w, 19162306a36Sopenharmony_ci struct snd_kcontrol *kcontrol, int event) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 19462306a36Sopenharmony_ci struct cs35l35_private *cs35l35 = snd_soc_component_get_drvdata(component); 19562306a36Sopenharmony_ci int ret = 0; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci switch (event) { 19862306a36Sopenharmony_ci case SND_SOC_DAPM_PRE_PMU: 19962306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL1, 20062306a36Sopenharmony_ci CS35L35_MCLK_DIS_MASK, 20162306a36Sopenharmony_ci 0 << CS35L35_MCLK_DIS_SHIFT); 20262306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL1, 20362306a36Sopenharmony_ci CS35L35_DISCHG_FILT_MASK, 20462306a36Sopenharmony_ci 0 << CS35L35_DISCHG_FILT_SHIFT); 20562306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL1, 20662306a36Sopenharmony_ci CS35L35_PDN_ALL_MASK, 0); 20762306a36Sopenharmony_ci break; 20862306a36Sopenharmony_ci case SND_SOC_DAPM_POST_PMD: 20962306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL1, 21062306a36Sopenharmony_ci CS35L35_DISCHG_FILT_MASK, 21162306a36Sopenharmony_ci 1 << CS35L35_DISCHG_FILT_SHIFT); 21262306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL1, 21362306a36Sopenharmony_ci CS35L35_PDN_ALL_MASK, 1); 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci /* Already muted, so disable volume ramp for faster shutdown */ 21662306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, CS35L35_AMP_DIG_VOL_CTL, 21762306a36Sopenharmony_ci CS35L35_AMP_DIGSFT_MASK, 0); 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci ret = cs35l35_wait_for_pdn(cs35l35); 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL1, 22262306a36Sopenharmony_ci CS35L35_MCLK_DIS_MASK, 22362306a36Sopenharmony_ci 1 << CS35L35_MCLK_DIS_SHIFT); 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, CS35L35_AMP_DIG_VOL_CTL, 22662306a36Sopenharmony_ci CS35L35_AMP_DIGSFT_MASK, 22762306a36Sopenharmony_ci 1 << CS35L35_AMP_DIGSFT_SHIFT); 22862306a36Sopenharmony_ci break; 22962306a36Sopenharmony_ci default: 23062306a36Sopenharmony_ci dev_err(component->dev, "Invalid event = 0x%x\n", event); 23162306a36Sopenharmony_ci ret = -EINVAL; 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci return ret; 23462306a36Sopenharmony_ci} 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_cistatic int cs35l35_main_amp_event(struct snd_soc_dapm_widget *w, 23762306a36Sopenharmony_ci struct snd_kcontrol *kcontrol, int event) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 24062306a36Sopenharmony_ci struct cs35l35_private *cs35l35 = snd_soc_component_get_drvdata(component); 24162306a36Sopenharmony_ci unsigned int reg[4]; 24262306a36Sopenharmony_ci int i; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci switch (event) { 24562306a36Sopenharmony_ci case SND_SOC_DAPM_PRE_PMU: 24662306a36Sopenharmony_ci if (cs35l35->pdata.bst_pdn_fet_on) 24762306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, 24862306a36Sopenharmony_ci CS35L35_PDN_BST_MASK, 24962306a36Sopenharmony_ci 0 << CS35L35_PDN_BST_FETON_SHIFT); 25062306a36Sopenharmony_ci else 25162306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, 25262306a36Sopenharmony_ci CS35L35_PDN_BST_MASK, 25362306a36Sopenharmony_ci 0 << CS35L35_PDN_BST_FETOFF_SHIFT); 25462306a36Sopenharmony_ci break; 25562306a36Sopenharmony_ci case SND_SOC_DAPM_POST_PMU: 25662306a36Sopenharmony_ci usleep_range(5000, 5100); 25762306a36Sopenharmony_ci /* If in PDM mode we must use VP for Voltage control */ 25862306a36Sopenharmony_ci if (cs35l35->pdm_mode) 25962306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, 26062306a36Sopenharmony_ci CS35L35_BST_CVTR_V_CTL, 26162306a36Sopenharmony_ci CS35L35_BST_CTL_MASK, 26262306a36Sopenharmony_ci 0 << CS35L35_BST_CTL_SHIFT); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, CS35L35_PROTECT_CTL, 26562306a36Sopenharmony_ci CS35L35_AMP_MUTE_MASK, 0); 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci for (i = 0; i < 2; i++) 26862306a36Sopenharmony_ci regmap_bulk_read(cs35l35->regmap, CS35L35_INT_STATUS_1, 26962306a36Sopenharmony_ci ®, ARRAY_SIZE(reg)); 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci break; 27262306a36Sopenharmony_ci case SND_SOC_DAPM_PRE_PMD: 27362306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, CS35L35_PROTECT_CTL, 27462306a36Sopenharmony_ci CS35L35_AMP_MUTE_MASK, 27562306a36Sopenharmony_ci 1 << CS35L35_AMP_MUTE_SHIFT); 27662306a36Sopenharmony_ci if (cs35l35->pdata.bst_pdn_fet_on) 27762306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, 27862306a36Sopenharmony_ci CS35L35_PDN_BST_MASK, 27962306a36Sopenharmony_ci 1 << CS35L35_PDN_BST_FETON_SHIFT); 28062306a36Sopenharmony_ci else 28162306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, 28262306a36Sopenharmony_ci CS35L35_PDN_BST_MASK, 28362306a36Sopenharmony_ci 1 << CS35L35_PDN_BST_FETOFF_SHIFT); 28462306a36Sopenharmony_ci break; 28562306a36Sopenharmony_ci case SND_SOC_DAPM_POST_PMD: 28662306a36Sopenharmony_ci usleep_range(5000, 5100); 28762306a36Sopenharmony_ci /* 28862306a36Sopenharmony_ci * If PDM mode we should switch back to pdata value 28962306a36Sopenharmony_ci * for Voltage control when we go down 29062306a36Sopenharmony_ci */ 29162306a36Sopenharmony_ci if (cs35l35->pdm_mode) 29262306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, 29362306a36Sopenharmony_ci CS35L35_BST_CVTR_V_CTL, 29462306a36Sopenharmony_ci CS35L35_BST_CTL_MASK, 29562306a36Sopenharmony_ci cs35l35->pdata.bst_vctl 29662306a36Sopenharmony_ci << CS35L35_BST_CTL_SHIFT); 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci break; 29962306a36Sopenharmony_ci default: 30062306a36Sopenharmony_ci dev_err(component->dev, "Invalid event = 0x%x\n", event); 30162306a36Sopenharmony_ci } 30262306a36Sopenharmony_ci return 0; 30362306a36Sopenharmony_ci} 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_cistatic DECLARE_TLV_DB_SCALE(amp_gain_tlv, 0, 1, 1); 30662306a36Sopenharmony_cistatic DECLARE_TLV_DB_SCALE(dig_vol_tlv, -10200, 50, 0); 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_cistatic const struct snd_kcontrol_new cs35l35_aud_controls[] = { 30962306a36Sopenharmony_ci SOC_SINGLE_SX_TLV("Digital Audio Volume", CS35L35_AMP_DIG_VOL, 31062306a36Sopenharmony_ci 0, 0x34, 0xE4, dig_vol_tlv), 31162306a36Sopenharmony_ci SOC_SINGLE_TLV("Analog Audio Volume", CS35L35_AMP_GAIN_AUD_CTL, 0, 19, 0, 31262306a36Sopenharmony_ci amp_gain_tlv), 31362306a36Sopenharmony_ci SOC_SINGLE_TLV("PDM Volume", CS35L35_AMP_GAIN_PDM_CTL, 0, 19, 0, 31462306a36Sopenharmony_ci amp_gain_tlv), 31562306a36Sopenharmony_ci}; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_cistatic const struct snd_kcontrol_new cs35l35_adv_controls[] = { 31862306a36Sopenharmony_ci SOC_SINGLE_SX_TLV("Digital Advisory Volume", CS35L35_ADV_DIG_VOL, 31962306a36Sopenharmony_ci 0, 0x34, 0xE4, dig_vol_tlv), 32062306a36Sopenharmony_ci SOC_SINGLE_TLV("Analog Advisory Volume", CS35L35_AMP_GAIN_ADV_CTL, 0, 19, 0, 32162306a36Sopenharmony_ci amp_gain_tlv), 32262306a36Sopenharmony_ci}; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_cistatic const struct snd_soc_dapm_widget cs35l35_dapm_widgets[] = { 32562306a36Sopenharmony_ci SND_SOC_DAPM_AIF_IN_E("SDIN", NULL, 0, CS35L35_PWRCTL3, 1, 1, 32662306a36Sopenharmony_ci cs35l35_sdin_event, SND_SOC_DAPM_PRE_PMU | 32762306a36Sopenharmony_ci SND_SOC_DAPM_POST_PMD), 32862306a36Sopenharmony_ci SND_SOC_DAPM_AIF_OUT("SDOUT", NULL, 0, CS35L35_PWRCTL3, 2, 1), 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci SND_SOC_DAPM_OUTPUT("SPK"), 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci SND_SOC_DAPM_INPUT("VP"), 33362306a36Sopenharmony_ci SND_SOC_DAPM_INPUT("VBST"), 33462306a36Sopenharmony_ci SND_SOC_DAPM_INPUT("ISENSE"), 33562306a36Sopenharmony_ci SND_SOC_DAPM_INPUT("VSENSE"), 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci SND_SOC_DAPM_ADC("VMON ADC", NULL, CS35L35_PWRCTL2, 7, 1), 33862306a36Sopenharmony_ci SND_SOC_DAPM_ADC("IMON ADC", NULL, CS35L35_PWRCTL2, 6, 1), 33962306a36Sopenharmony_ci SND_SOC_DAPM_ADC("VPMON ADC", NULL, CS35L35_PWRCTL3, 3, 1), 34062306a36Sopenharmony_ci SND_SOC_DAPM_ADC("VBSTMON ADC", NULL, CS35L35_PWRCTL3, 4, 1), 34162306a36Sopenharmony_ci SND_SOC_DAPM_ADC("CLASS H", NULL, CS35L35_PWRCTL2, 5, 1), 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci SND_SOC_DAPM_OUT_DRV_E("Main AMP", CS35L35_PWRCTL2, 0, 1, NULL, 0, 34462306a36Sopenharmony_ci cs35l35_main_amp_event, SND_SOC_DAPM_PRE_PMU | 34562306a36Sopenharmony_ci SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU | 34662306a36Sopenharmony_ci SND_SOC_DAPM_PRE_PMD), 34762306a36Sopenharmony_ci}; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_cistatic const struct snd_soc_dapm_route cs35l35_audio_map[] = { 35062306a36Sopenharmony_ci {"VPMON ADC", NULL, "VP"}, 35162306a36Sopenharmony_ci {"VBSTMON ADC", NULL, "VBST"}, 35262306a36Sopenharmony_ci {"IMON ADC", NULL, "ISENSE"}, 35362306a36Sopenharmony_ci {"VMON ADC", NULL, "VSENSE"}, 35462306a36Sopenharmony_ci {"SDOUT", NULL, "IMON ADC"}, 35562306a36Sopenharmony_ci {"SDOUT", NULL, "VMON ADC"}, 35662306a36Sopenharmony_ci {"SDOUT", NULL, "VBSTMON ADC"}, 35762306a36Sopenharmony_ci {"SDOUT", NULL, "VPMON ADC"}, 35862306a36Sopenharmony_ci {"AMP Capture", NULL, "SDOUT"}, 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci {"SDIN", NULL, "AMP Playback"}, 36162306a36Sopenharmony_ci {"CLASS H", NULL, "SDIN"}, 36262306a36Sopenharmony_ci {"Main AMP", NULL, "CLASS H"}, 36362306a36Sopenharmony_ci {"SPK", NULL, "Main AMP"}, 36462306a36Sopenharmony_ci}; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_cistatic int cs35l35_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) 36762306a36Sopenharmony_ci{ 36862306a36Sopenharmony_ci struct snd_soc_component *component = codec_dai->component; 36962306a36Sopenharmony_ci struct cs35l35_private *cs35l35 = snd_soc_component_get_drvdata(component); 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { 37262306a36Sopenharmony_ci case SND_SOC_DAIFMT_CBP_CFP: 37362306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL1, 37462306a36Sopenharmony_ci CS35L35_MS_MASK, 1 << CS35L35_MS_SHIFT); 37562306a36Sopenharmony_ci cs35l35->clock_consumer = false; 37662306a36Sopenharmony_ci break; 37762306a36Sopenharmony_ci case SND_SOC_DAIFMT_CBC_CFC: 37862306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL1, 37962306a36Sopenharmony_ci CS35L35_MS_MASK, 0 << CS35L35_MS_SHIFT); 38062306a36Sopenharmony_ci cs35l35->clock_consumer = true; 38162306a36Sopenharmony_ci break; 38262306a36Sopenharmony_ci default: 38362306a36Sopenharmony_ci return -EINVAL; 38462306a36Sopenharmony_ci } 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 38762306a36Sopenharmony_ci case SND_SOC_DAIFMT_I2S: 38862306a36Sopenharmony_ci cs35l35->i2s_mode = true; 38962306a36Sopenharmony_ci cs35l35->pdm_mode = false; 39062306a36Sopenharmony_ci break; 39162306a36Sopenharmony_ci case SND_SOC_DAIFMT_PDM: 39262306a36Sopenharmony_ci cs35l35->pdm_mode = true; 39362306a36Sopenharmony_ci cs35l35->i2s_mode = false; 39462306a36Sopenharmony_ci break; 39562306a36Sopenharmony_ci default: 39662306a36Sopenharmony_ci return -EINVAL; 39762306a36Sopenharmony_ci } 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci return 0; 40062306a36Sopenharmony_ci} 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_cistruct cs35l35_sysclk_config { 40362306a36Sopenharmony_ci int sysclk; 40462306a36Sopenharmony_ci int srate; 40562306a36Sopenharmony_ci u8 clk_cfg; 40662306a36Sopenharmony_ci}; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_cistatic struct cs35l35_sysclk_config cs35l35_clk_ctl[] = { 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci /* SYSCLK, Sample Rate, Serial Port Cfg */ 41162306a36Sopenharmony_ci {5644800, 44100, 0x00}, 41262306a36Sopenharmony_ci {5644800, 88200, 0x40}, 41362306a36Sopenharmony_ci {6144000, 48000, 0x10}, 41462306a36Sopenharmony_ci {6144000, 96000, 0x50}, 41562306a36Sopenharmony_ci {11289600, 44100, 0x01}, 41662306a36Sopenharmony_ci {11289600, 88200, 0x41}, 41762306a36Sopenharmony_ci {11289600, 176400, 0x81}, 41862306a36Sopenharmony_ci {12000000, 44100, 0x03}, 41962306a36Sopenharmony_ci {12000000, 48000, 0x13}, 42062306a36Sopenharmony_ci {12000000, 88200, 0x43}, 42162306a36Sopenharmony_ci {12000000, 96000, 0x53}, 42262306a36Sopenharmony_ci {12000000, 176400, 0x83}, 42362306a36Sopenharmony_ci {12000000, 192000, 0x93}, 42462306a36Sopenharmony_ci {12288000, 48000, 0x11}, 42562306a36Sopenharmony_ci {12288000, 96000, 0x51}, 42662306a36Sopenharmony_ci {12288000, 192000, 0x91}, 42762306a36Sopenharmony_ci {13000000, 44100, 0x07}, 42862306a36Sopenharmony_ci {13000000, 48000, 0x17}, 42962306a36Sopenharmony_ci {13000000, 88200, 0x47}, 43062306a36Sopenharmony_ci {13000000, 96000, 0x57}, 43162306a36Sopenharmony_ci {13000000, 176400, 0x87}, 43262306a36Sopenharmony_ci {13000000, 192000, 0x97}, 43362306a36Sopenharmony_ci {22579200, 44100, 0x02}, 43462306a36Sopenharmony_ci {22579200, 88200, 0x42}, 43562306a36Sopenharmony_ci {22579200, 176400, 0x82}, 43662306a36Sopenharmony_ci {24000000, 44100, 0x0B}, 43762306a36Sopenharmony_ci {24000000, 48000, 0x1B}, 43862306a36Sopenharmony_ci {24000000, 88200, 0x4B}, 43962306a36Sopenharmony_ci {24000000, 96000, 0x5B}, 44062306a36Sopenharmony_ci {24000000, 176400, 0x8B}, 44162306a36Sopenharmony_ci {24000000, 192000, 0x9B}, 44262306a36Sopenharmony_ci {24576000, 48000, 0x12}, 44362306a36Sopenharmony_ci {24576000, 96000, 0x52}, 44462306a36Sopenharmony_ci {24576000, 192000, 0x92}, 44562306a36Sopenharmony_ci {26000000, 44100, 0x0F}, 44662306a36Sopenharmony_ci {26000000, 48000, 0x1F}, 44762306a36Sopenharmony_ci {26000000, 88200, 0x4F}, 44862306a36Sopenharmony_ci {26000000, 96000, 0x5F}, 44962306a36Sopenharmony_ci {26000000, 176400, 0x8F}, 45062306a36Sopenharmony_ci {26000000, 192000, 0x9F}, 45162306a36Sopenharmony_ci}; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_cistatic int cs35l35_get_clk_config(int sysclk, int srate) 45462306a36Sopenharmony_ci{ 45562306a36Sopenharmony_ci int i; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(cs35l35_clk_ctl); i++) { 45862306a36Sopenharmony_ci if (cs35l35_clk_ctl[i].sysclk == sysclk && 45962306a36Sopenharmony_ci cs35l35_clk_ctl[i].srate == srate) 46062306a36Sopenharmony_ci return cs35l35_clk_ctl[i].clk_cfg; 46162306a36Sopenharmony_ci } 46262306a36Sopenharmony_ci return -EINVAL; 46362306a36Sopenharmony_ci} 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_cistatic int cs35l35_hw_params(struct snd_pcm_substream *substream, 46662306a36Sopenharmony_ci struct snd_pcm_hw_params *params, 46762306a36Sopenharmony_ci struct snd_soc_dai *dai) 46862306a36Sopenharmony_ci{ 46962306a36Sopenharmony_ci struct snd_soc_component *component = dai->component; 47062306a36Sopenharmony_ci struct cs35l35_private *cs35l35 = snd_soc_component_get_drvdata(component); 47162306a36Sopenharmony_ci struct classh_cfg *classh = &cs35l35->pdata.classh_algo; 47262306a36Sopenharmony_ci int srate = params_rate(params); 47362306a36Sopenharmony_ci int ret = 0; 47462306a36Sopenharmony_ci u8 sp_sclks; 47562306a36Sopenharmony_ci int audin_format; 47662306a36Sopenharmony_ci int errata_chk; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci int clk_ctl = cs35l35_get_clk_config(cs35l35->sysclk, srate); 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci if (clk_ctl < 0) { 48162306a36Sopenharmony_ci dev_err(component->dev, "Invalid CLK:Rate %d:%d\n", 48262306a36Sopenharmony_ci cs35l35->sysclk, srate); 48362306a36Sopenharmony_ci return -EINVAL; 48462306a36Sopenharmony_ci } 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci ret = regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL2, 48762306a36Sopenharmony_ci CS35L35_CLK_CTL2_MASK, clk_ctl); 48862306a36Sopenharmony_ci if (ret != 0) { 48962306a36Sopenharmony_ci dev_err(component->dev, "Failed to set port config %d\n", ret); 49062306a36Sopenharmony_ci return ret; 49162306a36Sopenharmony_ci } 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci /* 49462306a36Sopenharmony_ci * Rev A0 Errata 49562306a36Sopenharmony_ci * When configured for the weak-drive detection path (CH_WKFET_DIS = 0) 49662306a36Sopenharmony_ci * the Class H algorithm does not enable weak-drive operation for 49762306a36Sopenharmony_ci * nonzero values of CH_WKFET_DELAY if SP_RATE = 01 or 10 49862306a36Sopenharmony_ci */ 49962306a36Sopenharmony_ci errata_chk = (clk_ctl & CS35L35_SP_RATE_MASK) >> CS35L35_SP_RATE_SHIFT; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci if (classh->classh_wk_fet_disable == 0x00 && 50262306a36Sopenharmony_ci (errata_chk == 0x01 || errata_chk == 0x02)) { 50362306a36Sopenharmony_ci ret = regmap_update_bits(cs35l35->regmap, 50462306a36Sopenharmony_ci CS35L35_CLASS_H_FET_DRIVE_CTL, 50562306a36Sopenharmony_ci CS35L35_CH_WKFET_DEL_MASK, 50662306a36Sopenharmony_ci 0 << CS35L35_CH_WKFET_DEL_SHIFT); 50762306a36Sopenharmony_ci if (ret != 0) { 50862306a36Sopenharmony_ci dev_err(component->dev, "Failed to set fet config %d\n", 50962306a36Sopenharmony_ci ret); 51062306a36Sopenharmony_ci return ret; 51162306a36Sopenharmony_ci } 51262306a36Sopenharmony_ci } 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci /* 51562306a36Sopenharmony_ci * You can pull more Monitor data from the SDOUT pin than going to SDIN 51662306a36Sopenharmony_ci * Just make sure your SCLK is fast enough to fill the frame 51762306a36Sopenharmony_ci */ 51862306a36Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 51962306a36Sopenharmony_ci switch (params_width(params)) { 52062306a36Sopenharmony_ci case 8: 52162306a36Sopenharmony_ci audin_format = CS35L35_SDIN_DEPTH_8; 52262306a36Sopenharmony_ci break; 52362306a36Sopenharmony_ci case 16: 52462306a36Sopenharmony_ci audin_format = CS35L35_SDIN_DEPTH_16; 52562306a36Sopenharmony_ci break; 52662306a36Sopenharmony_ci case 24: 52762306a36Sopenharmony_ci audin_format = CS35L35_SDIN_DEPTH_24; 52862306a36Sopenharmony_ci break; 52962306a36Sopenharmony_ci default: 53062306a36Sopenharmony_ci dev_err(component->dev, "Unsupported Width %d\n", 53162306a36Sopenharmony_ci params_width(params)); 53262306a36Sopenharmony_ci return -EINVAL; 53362306a36Sopenharmony_ci } 53462306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, 53562306a36Sopenharmony_ci CS35L35_AUDIN_DEPTH_CTL, 53662306a36Sopenharmony_ci CS35L35_AUDIN_DEPTH_MASK, 53762306a36Sopenharmony_ci audin_format << 53862306a36Sopenharmony_ci CS35L35_AUDIN_DEPTH_SHIFT); 53962306a36Sopenharmony_ci if (cs35l35->pdata.stereo) { 54062306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, 54162306a36Sopenharmony_ci CS35L35_AUDIN_DEPTH_CTL, 54262306a36Sopenharmony_ci CS35L35_ADVIN_DEPTH_MASK, 54362306a36Sopenharmony_ci audin_format << 54462306a36Sopenharmony_ci CS35L35_ADVIN_DEPTH_SHIFT); 54562306a36Sopenharmony_ci } 54662306a36Sopenharmony_ci } 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci if (cs35l35->i2s_mode) { 54962306a36Sopenharmony_ci /* We have to take the SCLK to derive num sclks 55062306a36Sopenharmony_ci * to configure the CLOCK_CTL3 register correctly 55162306a36Sopenharmony_ci */ 55262306a36Sopenharmony_ci if ((cs35l35->sclk / srate) % 4) { 55362306a36Sopenharmony_ci dev_err(component->dev, "Unsupported sclk/fs ratio %d:%d\n", 55462306a36Sopenharmony_ci cs35l35->sclk, srate); 55562306a36Sopenharmony_ci return -EINVAL; 55662306a36Sopenharmony_ci } 55762306a36Sopenharmony_ci sp_sclks = ((cs35l35->sclk / srate) / 4) - 1; 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci /* Only certain ratios supported when device is a clock consumer */ 56062306a36Sopenharmony_ci if (cs35l35->clock_consumer) { 56162306a36Sopenharmony_ci switch (sp_sclks) { 56262306a36Sopenharmony_ci case CS35L35_SP_SCLKS_32FS: 56362306a36Sopenharmony_ci case CS35L35_SP_SCLKS_48FS: 56462306a36Sopenharmony_ci case CS35L35_SP_SCLKS_64FS: 56562306a36Sopenharmony_ci break; 56662306a36Sopenharmony_ci default: 56762306a36Sopenharmony_ci dev_err(component->dev, "ratio not supported\n"); 56862306a36Sopenharmony_ci return -EINVAL; 56962306a36Sopenharmony_ci } 57062306a36Sopenharmony_ci } else { 57162306a36Sopenharmony_ci /* Only certain ratios supported when device is a clock provider */ 57262306a36Sopenharmony_ci switch (sp_sclks) { 57362306a36Sopenharmony_ci case CS35L35_SP_SCLKS_32FS: 57462306a36Sopenharmony_ci case CS35L35_SP_SCLKS_64FS: 57562306a36Sopenharmony_ci break; 57662306a36Sopenharmony_ci default: 57762306a36Sopenharmony_ci dev_err(component->dev, "ratio not supported\n"); 57862306a36Sopenharmony_ci return -EINVAL; 57962306a36Sopenharmony_ci } 58062306a36Sopenharmony_ci } 58162306a36Sopenharmony_ci ret = regmap_update_bits(cs35l35->regmap, 58262306a36Sopenharmony_ci CS35L35_CLK_CTL3, 58362306a36Sopenharmony_ci CS35L35_SP_SCLKS_MASK, sp_sclks << 58462306a36Sopenharmony_ci CS35L35_SP_SCLKS_SHIFT); 58562306a36Sopenharmony_ci if (ret != 0) { 58662306a36Sopenharmony_ci dev_err(component->dev, "Failed to set fsclk %d\n", ret); 58762306a36Sopenharmony_ci return ret; 58862306a36Sopenharmony_ci } 58962306a36Sopenharmony_ci } 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci return ret; 59262306a36Sopenharmony_ci} 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_cistatic const unsigned int cs35l35_src_rates[] = { 59562306a36Sopenharmony_ci 44100, 48000, 88200, 96000, 176400, 192000 59662306a36Sopenharmony_ci}; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_cistatic const struct snd_pcm_hw_constraint_list cs35l35_constraints = { 59962306a36Sopenharmony_ci .count = ARRAY_SIZE(cs35l35_src_rates), 60062306a36Sopenharmony_ci .list = cs35l35_src_rates, 60162306a36Sopenharmony_ci}; 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_cistatic int cs35l35_pcm_startup(struct snd_pcm_substream *substream, 60462306a36Sopenharmony_ci struct snd_soc_dai *dai) 60562306a36Sopenharmony_ci{ 60662306a36Sopenharmony_ci struct snd_soc_component *component = dai->component; 60762306a36Sopenharmony_ci struct cs35l35_private *cs35l35 = snd_soc_component_get_drvdata(component); 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci if (!substream->runtime) 61062306a36Sopenharmony_ci return 0; 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci snd_pcm_hw_constraint_list(substream->runtime, 0, 61362306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_RATE, &cs35l35_constraints); 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, CS35L35_AMP_INP_DRV_CTL, 61662306a36Sopenharmony_ci CS35L35_PDM_MODE_MASK, 61762306a36Sopenharmony_ci 0 << CS35L35_PDM_MODE_SHIFT); 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci return 0; 62062306a36Sopenharmony_ci} 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_cistatic const unsigned int cs35l35_pdm_rates[] = { 62362306a36Sopenharmony_ci 44100, 48000, 88200, 96000 62462306a36Sopenharmony_ci}; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_cistatic const struct snd_pcm_hw_constraint_list cs35l35_pdm_constraints = { 62762306a36Sopenharmony_ci .count = ARRAY_SIZE(cs35l35_pdm_rates), 62862306a36Sopenharmony_ci .list = cs35l35_pdm_rates, 62962306a36Sopenharmony_ci}; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_cistatic int cs35l35_pdm_startup(struct snd_pcm_substream *substream, 63262306a36Sopenharmony_ci struct snd_soc_dai *dai) 63362306a36Sopenharmony_ci{ 63462306a36Sopenharmony_ci struct snd_soc_component *component = dai->component; 63562306a36Sopenharmony_ci struct cs35l35_private *cs35l35 = snd_soc_component_get_drvdata(component); 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci if (!substream->runtime) 63862306a36Sopenharmony_ci return 0; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci snd_pcm_hw_constraint_list(substream->runtime, 0, 64162306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_RATE, 64262306a36Sopenharmony_ci &cs35l35_pdm_constraints); 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, CS35L35_AMP_INP_DRV_CTL, 64562306a36Sopenharmony_ci CS35L35_PDM_MODE_MASK, 64662306a36Sopenharmony_ci 1 << CS35L35_PDM_MODE_SHIFT); 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci return 0; 64962306a36Sopenharmony_ci} 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_cistatic int cs35l35_dai_set_sysclk(struct snd_soc_dai *dai, 65262306a36Sopenharmony_ci int clk_id, unsigned int freq, int dir) 65362306a36Sopenharmony_ci{ 65462306a36Sopenharmony_ci struct snd_soc_component *component = dai->component; 65562306a36Sopenharmony_ci struct cs35l35_private *cs35l35 = snd_soc_component_get_drvdata(component); 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci /* Need the SCLK Frequency regardless of sysclk source for I2S */ 65862306a36Sopenharmony_ci cs35l35->sclk = freq; 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci return 0; 66162306a36Sopenharmony_ci} 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_cistatic const struct snd_soc_dai_ops cs35l35_ops = { 66462306a36Sopenharmony_ci .startup = cs35l35_pcm_startup, 66562306a36Sopenharmony_ci .set_fmt = cs35l35_set_dai_fmt, 66662306a36Sopenharmony_ci .hw_params = cs35l35_hw_params, 66762306a36Sopenharmony_ci .set_sysclk = cs35l35_dai_set_sysclk, 66862306a36Sopenharmony_ci}; 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_cistatic const struct snd_soc_dai_ops cs35l35_pdm_ops = { 67162306a36Sopenharmony_ci .startup = cs35l35_pdm_startup, 67262306a36Sopenharmony_ci .set_fmt = cs35l35_set_dai_fmt, 67362306a36Sopenharmony_ci .hw_params = cs35l35_hw_params, 67462306a36Sopenharmony_ci}; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_cistatic struct snd_soc_dai_driver cs35l35_dai[] = { 67762306a36Sopenharmony_ci { 67862306a36Sopenharmony_ci .name = "cs35l35-pcm", 67962306a36Sopenharmony_ci .id = 0, 68062306a36Sopenharmony_ci .playback = { 68162306a36Sopenharmony_ci .stream_name = "AMP Playback", 68262306a36Sopenharmony_ci .channels_min = 1, 68362306a36Sopenharmony_ci .channels_max = 8, 68462306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_KNOT, 68562306a36Sopenharmony_ci .formats = CS35L35_FORMATS, 68662306a36Sopenharmony_ci }, 68762306a36Sopenharmony_ci .capture = { 68862306a36Sopenharmony_ci .stream_name = "AMP Capture", 68962306a36Sopenharmony_ci .channels_min = 1, 69062306a36Sopenharmony_ci .channels_max = 8, 69162306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_KNOT, 69262306a36Sopenharmony_ci .formats = CS35L35_FORMATS, 69362306a36Sopenharmony_ci }, 69462306a36Sopenharmony_ci .ops = &cs35l35_ops, 69562306a36Sopenharmony_ci .symmetric_rate = 1, 69662306a36Sopenharmony_ci }, 69762306a36Sopenharmony_ci { 69862306a36Sopenharmony_ci .name = "cs35l35-pdm", 69962306a36Sopenharmony_ci .id = 1, 70062306a36Sopenharmony_ci .playback = { 70162306a36Sopenharmony_ci .stream_name = "PDM Playback", 70262306a36Sopenharmony_ci .channels_min = 1, 70362306a36Sopenharmony_ci .channels_max = 2, 70462306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_KNOT, 70562306a36Sopenharmony_ci .formats = CS35L35_FORMATS, 70662306a36Sopenharmony_ci }, 70762306a36Sopenharmony_ci .ops = &cs35l35_pdm_ops, 70862306a36Sopenharmony_ci }, 70962306a36Sopenharmony_ci}; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_cistatic int cs35l35_component_set_sysclk(struct snd_soc_component *component, 71262306a36Sopenharmony_ci int clk_id, int source, unsigned int freq, 71362306a36Sopenharmony_ci int dir) 71462306a36Sopenharmony_ci{ 71562306a36Sopenharmony_ci struct cs35l35_private *cs35l35 = snd_soc_component_get_drvdata(component); 71662306a36Sopenharmony_ci int clksrc; 71762306a36Sopenharmony_ci int ret = 0; 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci switch (clk_id) { 72062306a36Sopenharmony_ci case 0: 72162306a36Sopenharmony_ci clksrc = CS35L35_CLK_SOURCE_MCLK; 72262306a36Sopenharmony_ci break; 72362306a36Sopenharmony_ci case 1: 72462306a36Sopenharmony_ci clksrc = CS35L35_CLK_SOURCE_SCLK; 72562306a36Sopenharmony_ci break; 72662306a36Sopenharmony_ci case 2: 72762306a36Sopenharmony_ci clksrc = CS35L35_CLK_SOURCE_PDM; 72862306a36Sopenharmony_ci break; 72962306a36Sopenharmony_ci default: 73062306a36Sopenharmony_ci dev_err(component->dev, "Invalid CLK Source\n"); 73162306a36Sopenharmony_ci return -EINVAL; 73262306a36Sopenharmony_ci } 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci switch (freq) { 73562306a36Sopenharmony_ci case 5644800: 73662306a36Sopenharmony_ci case 6144000: 73762306a36Sopenharmony_ci case 11289600: 73862306a36Sopenharmony_ci case 12000000: 73962306a36Sopenharmony_ci case 12288000: 74062306a36Sopenharmony_ci case 13000000: 74162306a36Sopenharmony_ci case 22579200: 74262306a36Sopenharmony_ci case 24000000: 74362306a36Sopenharmony_ci case 24576000: 74462306a36Sopenharmony_ci case 26000000: 74562306a36Sopenharmony_ci cs35l35->sysclk = freq; 74662306a36Sopenharmony_ci break; 74762306a36Sopenharmony_ci default: 74862306a36Sopenharmony_ci dev_err(component->dev, "Invalid CLK Frequency Input : %d\n", freq); 74962306a36Sopenharmony_ci return -EINVAL; 75062306a36Sopenharmony_ci } 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci ret = regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL1, 75362306a36Sopenharmony_ci CS35L35_CLK_SOURCE_MASK, 75462306a36Sopenharmony_ci clksrc << CS35L35_CLK_SOURCE_SHIFT); 75562306a36Sopenharmony_ci if (ret != 0) { 75662306a36Sopenharmony_ci dev_err(component->dev, "Failed to set sysclk %d\n", ret); 75762306a36Sopenharmony_ci return ret; 75862306a36Sopenharmony_ci } 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci return ret; 76162306a36Sopenharmony_ci} 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_cistatic int cs35l35_boost_inductor(struct cs35l35_private *cs35l35, 76462306a36Sopenharmony_ci int inductor) 76562306a36Sopenharmony_ci{ 76662306a36Sopenharmony_ci struct regmap *regmap = cs35l35->regmap; 76762306a36Sopenharmony_ci unsigned int bst_ipk = 0; 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci /* 77062306a36Sopenharmony_ci * Digital Boost Converter Configuration for feedback, 77162306a36Sopenharmony_ci * ramping, switching frequency, and estimation block seeding. 77262306a36Sopenharmony_ci */ 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci regmap_update_bits(regmap, CS35L35_BST_CONV_SW_FREQ, 77562306a36Sopenharmony_ci CS35L35_BST_CONV_SWFREQ_MASK, 0x00); 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci regmap_read(regmap, CS35L35_BST_PEAK_I, &bst_ipk); 77862306a36Sopenharmony_ci bst_ipk &= CS35L35_BST_IPK_MASK; 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci switch (inductor) { 78162306a36Sopenharmony_ci case 1000: /* 1 uH */ 78262306a36Sopenharmony_ci regmap_write(regmap, CS35L35_BST_CONV_COEF_1, 0x24); 78362306a36Sopenharmony_ci regmap_write(regmap, CS35L35_BST_CONV_COEF_2, 0x24); 78462306a36Sopenharmony_ci regmap_update_bits(regmap, CS35L35_BST_CONV_SW_FREQ, 78562306a36Sopenharmony_ci CS35L35_BST_CONV_LBST_MASK, 0x00); 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci if (bst_ipk < 0x04) 78862306a36Sopenharmony_ci regmap_write(regmap, CS35L35_BST_CONV_SLOPE_COMP, 0x1B); 78962306a36Sopenharmony_ci else 79062306a36Sopenharmony_ci regmap_write(regmap, CS35L35_BST_CONV_SLOPE_COMP, 0x4E); 79162306a36Sopenharmony_ci break; 79262306a36Sopenharmony_ci case 1200: /* 1.2 uH */ 79362306a36Sopenharmony_ci regmap_write(regmap, CS35L35_BST_CONV_COEF_1, 0x20); 79462306a36Sopenharmony_ci regmap_write(regmap, CS35L35_BST_CONV_COEF_2, 0x20); 79562306a36Sopenharmony_ci regmap_update_bits(regmap, CS35L35_BST_CONV_SW_FREQ, 79662306a36Sopenharmony_ci CS35L35_BST_CONV_LBST_MASK, 0x01); 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci if (bst_ipk < 0x04) 79962306a36Sopenharmony_ci regmap_write(regmap, CS35L35_BST_CONV_SLOPE_COMP, 0x1B); 80062306a36Sopenharmony_ci else 80162306a36Sopenharmony_ci regmap_write(regmap, CS35L35_BST_CONV_SLOPE_COMP, 0x47); 80262306a36Sopenharmony_ci break; 80362306a36Sopenharmony_ci case 1500: /* 1.5uH */ 80462306a36Sopenharmony_ci regmap_write(regmap, CS35L35_BST_CONV_COEF_1, 0x20); 80562306a36Sopenharmony_ci regmap_write(regmap, CS35L35_BST_CONV_COEF_2, 0x20); 80662306a36Sopenharmony_ci regmap_update_bits(regmap, CS35L35_BST_CONV_SW_FREQ, 80762306a36Sopenharmony_ci CS35L35_BST_CONV_LBST_MASK, 0x02); 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci if (bst_ipk < 0x04) 81062306a36Sopenharmony_ci regmap_write(regmap, CS35L35_BST_CONV_SLOPE_COMP, 0x1B); 81162306a36Sopenharmony_ci else 81262306a36Sopenharmony_ci regmap_write(regmap, CS35L35_BST_CONV_SLOPE_COMP, 0x3C); 81362306a36Sopenharmony_ci break; 81462306a36Sopenharmony_ci case 2200: /* 2.2uH */ 81562306a36Sopenharmony_ci regmap_write(regmap, CS35L35_BST_CONV_COEF_1, 0x19); 81662306a36Sopenharmony_ci regmap_write(regmap, CS35L35_BST_CONV_COEF_2, 0x25); 81762306a36Sopenharmony_ci regmap_update_bits(regmap, CS35L35_BST_CONV_SW_FREQ, 81862306a36Sopenharmony_ci CS35L35_BST_CONV_LBST_MASK, 0x03); 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci if (bst_ipk < 0x04) 82162306a36Sopenharmony_ci regmap_write(regmap, CS35L35_BST_CONV_SLOPE_COMP, 0x1B); 82262306a36Sopenharmony_ci else 82362306a36Sopenharmony_ci regmap_write(regmap, CS35L35_BST_CONV_SLOPE_COMP, 0x23); 82462306a36Sopenharmony_ci break; 82562306a36Sopenharmony_ci default: 82662306a36Sopenharmony_ci dev_err(cs35l35->dev, "Invalid Inductor Value %d uH\n", 82762306a36Sopenharmony_ci inductor); 82862306a36Sopenharmony_ci return -EINVAL; 82962306a36Sopenharmony_ci } 83062306a36Sopenharmony_ci return 0; 83162306a36Sopenharmony_ci} 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_cistatic int cs35l35_component_probe(struct snd_soc_component *component) 83462306a36Sopenharmony_ci{ 83562306a36Sopenharmony_ci struct cs35l35_private *cs35l35 = snd_soc_component_get_drvdata(component); 83662306a36Sopenharmony_ci struct classh_cfg *classh = &cs35l35->pdata.classh_algo; 83762306a36Sopenharmony_ci struct monitor_cfg *monitor_config = &cs35l35->pdata.mon_cfg; 83862306a36Sopenharmony_ci int ret; 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci /* Set Platform Data */ 84162306a36Sopenharmony_ci if (cs35l35->pdata.bst_vctl) 84262306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, CS35L35_BST_CVTR_V_CTL, 84362306a36Sopenharmony_ci CS35L35_BST_CTL_MASK, 84462306a36Sopenharmony_ci cs35l35->pdata.bst_vctl); 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci if (cs35l35->pdata.bst_ipk) 84762306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, CS35L35_BST_PEAK_I, 84862306a36Sopenharmony_ci CS35L35_BST_IPK_MASK, 84962306a36Sopenharmony_ci cs35l35->pdata.bst_ipk << 85062306a36Sopenharmony_ci CS35L35_BST_IPK_SHIFT); 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci ret = cs35l35_boost_inductor(cs35l35, cs35l35->pdata.boost_ind); 85362306a36Sopenharmony_ci if (ret) 85462306a36Sopenharmony_ci return ret; 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci if (cs35l35->pdata.gain_zc) 85762306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, CS35L35_PROTECT_CTL, 85862306a36Sopenharmony_ci CS35L35_AMP_GAIN_ZC_MASK, 85962306a36Sopenharmony_ci cs35l35->pdata.gain_zc << 86062306a36Sopenharmony_ci CS35L35_AMP_GAIN_ZC_SHIFT); 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci if (cs35l35->pdata.aud_channel) 86362306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, 86462306a36Sopenharmony_ci CS35L35_AUDIN_RXLOC_CTL, 86562306a36Sopenharmony_ci CS35L35_AUD_IN_LR_MASK, 86662306a36Sopenharmony_ci cs35l35->pdata.aud_channel << 86762306a36Sopenharmony_ci CS35L35_AUD_IN_LR_SHIFT); 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci if (cs35l35->pdata.stereo) { 87062306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, 87162306a36Sopenharmony_ci CS35L35_ADVIN_RXLOC_CTL, 87262306a36Sopenharmony_ci CS35L35_ADV_IN_LR_MASK, 87362306a36Sopenharmony_ci cs35l35->pdata.adv_channel << 87462306a36Sopenharmony_ci CS35L35_ADV_IN_LR_SHIFT); 87562306a36Sopenharmony_ci if (cs35l35->pdata.shared_bst) 87662306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, CS35L35_CLASS_H_CTL, 87762306a36Sopenharmony_ci CS35L35_CH_STEREO_MASK, 87862306a36Sopenharmony_ci 1 << CS35L35_CH_STEREO_SHIFT); 87962306a36Sopenharmony_ci ret = snd_soc_add_component_controls(component, cs35l35_adv_controls, 88062306a36Sopenharmony_ci ARRAY_SIZE(cs35l35_adv_controls)); 88162306a36Sopenharmony_ci if (ret) 88262306a36Sopenharmony_ci return ret; 88362306a36Sopenharmony_ci } 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci if (cs35l35->pdata.sp_drv_str) 88662306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL1, 88762306a36Sopenharmony_ci CS35L35_SP_DRV_MASK, 88862306a36Sopenharmony_ci cs35l35->pdata.sp_drv_str << 88962306a36Sopenharmony_ci CS35L35_SP_DRV_SHIFT); 89062306a36Sopenharmony_ci if (cs35l35->pdata.sp_drv_unused) 89162306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, CS35L35_SP_FMT_CTL3, 89262306a36Sopenharmony_ci CS35L35_SP_I2S_DRV_MASK, 89362306a36Sopenharmony_ci cs35l35->pdata.sp_drv_unused << 89462306a36Sopenharmony_ci CS35L35_SP_I2S_DRV_SHIFT); 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci if (classh->classh_algo_enable) { 89762306a36Sopenharmony_ci if (classh->classh_bst_override) 89862306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, 89962306a36Sopenharmony_ci CS35L35_CLASS_H_CTL, 90062306a36Sopenharmony_ci CS35L35_CH_BST_OVR_MASK, 90162306a36Sopenharmony_ci classh->classh_bst_override << 90262306a36Sopenharmony_ci CS35L35_CH_BST_OVR_SHIFT); 90362306a36Sopenharmony_ci if (classh->classh_bst_max_limit) 90462306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, 90562306a36Sopenharmony_ci CS35L35_CLASS_H_CTL, 90662306a36Sopenharmony_ci CS35L35_CH_BST_LIM_MASK, 90762306a36Sopenharmony_ci classh->classh_bst_max_limit << 90862306a36Sopenharmony_ci CS35L35_CH_BST_LIM_SHIFT); 90962306a36Sopenharmony_ci if (classh->classh_mem_depth) 91062306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, 91162306a36Sopenharmony_ci CS35L35_CLASS_H_CTL, 91262306a36Sopenharmony_ci CS35L35_CH_MEM_DEPTH_MASK, 91362306a36Sopenharmony_ci classh->classh_mem_depth << 91462306a36Sopenharmony_ci CS35L35_CH_MEM_DEPTH_SHIFT); 91562306a36Sopenharmony_ci if (classh->classh_headroom) 91662306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, 91762306a36Sopenharmony_ci CS35L35_CLASS_H_HEADRM_CTL, 91862306a36Sopenharmony_ci CS35L35_CH_HDRM_CTL_MASK, 91962306a36Sopenharmony_ci classh->classh_headroom << 92062306a36Sopenharmony_ci CS35L35_CH_HDRM_CTL_SHIFT); 92162306a36Sopenharmony_ci if (classh->classh_release_rate) 92262306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, 92362306a36Sopenharmony_ci CS35L35_CLASS_H_RELEASE_RATE, 92462306a36Sopenharmony_ci CS35L35_CH_REL_RATE_MASK, 92562306a36Sopenharmony_ci classh->classh_release_rate << 92662306a36Sopenharmony_ci CS35L35_CH_REL_RATE_SHIFT); 92762306a36Sopenharmony_ci if (classh->classh_wk_fet_disable) 92862306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, 92962306a36Sopenharmony_ci CS35L35_CLASS_H_FET_DRIVE_CTL, 93062306a36Sopenharmony_ci CS35L35_CH_WKFET_DIS_MASK, 93162306a36Sopenharmony_ci classh->classh_wk_fet_disable << 93262306a36Sopenharmony_ci CS35L35_CH_WKFET_DIS_SHIFT); 93362306a36Sopenharmony_ci if (classh->classh_wk_fet_delay) 93462306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, 93562306a36Sopenharmony_ci CS35L35_CLASS_H_FET_DRIVE_CTL, 93662306a36Sopenharmony_ci CS35L35_CH_WKFET_DEL_MASK, 93762306a36Sopenharmony_ci classh->classh_wk_fet_delay << 93862306a36Sopenharmony_ci CS35L35_CH_WKFET_DEL_SHIFT); 93962306a36Sopenharmony_ci if (classh->classh_wk_fet_thld) 94062306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, 94162306a36Sopenharmony_ci CS35L35_CLASS_H_FET_DRIVE_CTL, 94262306a36Sopenharmony_ci CS35L35_CH_WKFET_THLD_MASK, 94362306a36Sopenharmony_ci classh->classh_wk_fet_thld << 94462306a36Sopenharmony_ci CS35L35_CH_WKFET_THLD_SHIFT); 94562306a36Sopenharmony_ci if (classh->classh_vpch_auto) 94662306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, 94762306a36Sopenharmony_ci CS35L35_CLASS_H_VP_CTL, 94862306a36Sopenharmony_ci CS35L35_CH_VP_AUTO_MASK, 94962306a36Sopenharmony_ci classh->classh_vpch_auto << 95062306a36Sopenharmony_ci CS35L35_CH_VP_AUTO_SHIFT); 95162306a36Sopenharmony_ci if (classh->classh_vpch_rate) 95262306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, 95362306a36Sopenharmony_ci CS35L35_CLASS_H_VP_CTL, 95462306a36Sopenharmony_ci CS35L35_CH_VP_RATE_MASK, 95562306a36Sopenharmony_ci classh->classh_vpch_rate << 95662306a36Sopenharmony_ci CS35L35_CH_VP_RATE_SHIFT); 95762306a36Sopenharmony_ci if (classh->classh_vpch_man) 95862306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, 95962306a36Sopenharmony_ci CS35L35_CLASS_H_VP_CTL, 96062306a36Sopenharmony_ci CS35L35_CH_VP_MAN_MASK, 96162306a36Sopenharmony_ci classh->classh_vpch_man << 96262306a36Sopenharmony_ci CS35L35_CH_VP_MAN_SHIFT); 96362306a36Sopenharmony_ci } 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci if (monitor_config->is_present) { 96662306a36Sopenharmony_ci if (monitor_config->vmon_specs) { 96762306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, 96862306a36Sopenharmony_ci CS35L35_SPKMON_DEPTH_CTL, 96962306a36Sopenharmony_ci CS35L35_VMON_DEPTH_MASK, 97062306a36Sopenharmony_ci monitor_config->vmon_dpth << 97162306a36Sopenharmony_ci CS35L35_VMON_DEPTH_SHIFT); 97262306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, 97362306a36Sopenharmony_ci CS35L35_VMON_TXLOC_CTL, 97462306a36Sopenharmony_ci CS35L35_MON_TXLOC_MASK, 97562306a36Sopenharmony_ci monitor_config->vmon_loc << 97662306a36Sopenharmony_ci CS35L35_MON_TXLOC_SHIFT); 97762306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, 97862306a36Sopenharmony_ci CS35L35_VMON_TXLOC_CTL, 97962306a36Sopenharmony_ci CS35L35_MON_FRM_MASK, 98062306a36Sopenharmony_ci monitor_config->vmon_frm << 98162306a36Sopenharmony_ci CS35L35_MON_FRM_SHIFT); 98262306a36Sopenharmony_ci } 98362306a36Sopenharmony_ci if (monitor_config->imon_specs) { 98462306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, 98562306a36Sopenharmony_ci CS35L35_SPKMON_DEPTH_CTL, 98662306a36Sopenharmony_ci CS35L35_IMON_DEPTH_MASK, 98762306a36Sopenharmony_ci monitor_config->imon_dpth << 98862306a36Sopenharmony_ci CS35L35_IMON_DEPTH_SHIFT); 98962306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, 99062306a36Sopenharmony_ci CS35L35_IMON_TXLOC_CTL, 99162306a36Sopenharmony_ci CS35L35_MON_TXLOC_MASK, 99262306a36Sopenharmony_ci monitor_config->imon_loc << 99362306a36Sopenharmony_ci CS35L35_MON_TXLOC_SHIFT); 99462306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, 99562306a36Sopenharmony_ci CS35L35_IMON_TXLOC_CTL, 99662306a36Sopenharmony_ci CS35L35_MON_FRM_MASK, 99762306a36Sopenharmony_ci monitor_config->imon_frm << 99862306a36Sopenharmony_ci CS35L35_MON_FRM_SHIFT); 99962306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, 100062306a36Sopenharmony_ci CS35L35_IMON_SCALE_CTL, 100162306a36Sopenharmony_ci CS35L35_IMON_SCALE_MASK, 100262306a36Sopenharmony_ci monitor_config->imon_scale << 100362306a36Sopenharmony_ci CS35L35_IMON_SCALE_SHIFT); 100462306a36Sopenharmony_ci } 100562306a36Sopenharmony_ci if (monitor_config->vpmon_specs) { 100662306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, 100762306a36Sopenharmony_ci CS35L35_SUPMON_DEPTH_CTL, 100862306a36Sopenharmony_ci CS35L35_VPMON_DEPTH_MASK, 100962306a36Sopenharmony_ci monitor_config->vpmon_dpth << 101062306a36Sopenharmony_ci CS35L35_VPMON_DEPTH_SHIFT); 101162306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, 101262306a36Sopenharmony_ci CS35L35_VPMON_TXLOC_CTL, 101362306a36Sopenharmony_ci CS35L35_MON_TXLOC_MASK, 101462306a36Sopenharmony_ci monitor_config->vpmon_loc << 101562306a36Sopenharmony_ci CS35L35_MON_TXLOC_SHIFT); 101662306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, 101762306a36Sopenharmony_ci CS35L35_VPMON_TXLOC_CTL, 101862306a36Sopenharmony_ci CS35L35_MON_FRM_MASK, 101962306a36Sopenharmony_ci monitor_config->vpmon_frm << 102062306a36Sopenharmony_ci CS35L35_MON_FRM_SHIFT); 102162306a36Sopenharmony_ci } 102262306a36Sopenharmony_ci if (monitor_config->vbstmon_specs) { 102362306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, 102462306a36Sopenharmony_ci CS35L35_SUPMON_DEPTH_CTL, 102562306a36Sopenharmony_ci CS35L35_VBSTMON_DEPTH_MASK, 102662306a36Sopenharmony_ci monitor_config->vpmon_dpth << 102762306a36Sopenharmony_ci CS35L35_VBSTMON_DEPTH_SHIFT); 102862306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, 102962306a36Sopenharmony_ci CS35L35_VBSTMON_TXLOC_CTL, 103062306a36Sopenharmony_ci CS35L35_MON_TXLOC_MASK, 103162306a36Sopenharmony_ci monitor_config->vbstmon_loc << 103262306a36Sopenharmony_ci CS35L35_MON_TXLOC_SHIFT); 103362306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, 103462306a36Sopenharmony_ci CS35L35_VBSTMON_TXLOC_CTL, 103562306a36Sopenharmony_ci CS35L35_MON_FRM_MASK, 103662306a36Sopenharmony_ci monitor_config->vbstmon_frm << 103762306a36Sopenharmony_ci CS35L35_MON_FRM_SHIFT); 103862306a36Sopenharmony_ci } 103962306a36Sopenharmony_ci if (monitor_config->vpbrstat_specs) { 104062306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, 104162306a36Sopenharmony_ci CS35L35_SUPMON_DEPTH_CTL, 104262306a36Sopenharmony_ci CS35L35_VPBRSTAT_DEPTH_MASK, 104362306a36Sopenharmony_ci monitor_config->vpbrstat_dpth << 104462306a36Sopenharmony_ci CS35L35_VPBRSTAT_DEPTH_SHIFT); 104562306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, 104662306a36Sopenharmony_ci CS35L35_VPBR_STATUS_TXLOC_CTL, 104762306a36Sopenharmony_ci CS35L35_MON_TXLOC_MASK, 104862306a36Sopenharmony_ci monitor_config->vpbrstat_loc << 104962306a36Sopenharmony_ci CS35L35_MON_TXLOC_SHIFT); 105062306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, 105162306a36Sopenharmony_ci CS35L35_VPBR_STATUS_TXLOC_CTL, 105262306a36Sopenharmony_ci CS35L35_MON_FRM_MASK, 105362306a36Sopenharmony_ci monitor_config->vpbrstat_frm << 105462306a36Sopenharmony_ci CS35L35_MON_FRM_SHIFT); 105562306a36Sopenharmony_ci } 105662306a36Sopenharmony_ci if (monitor_config->zerofill_specs) { 105762306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, 105862306a36Sopenharmony_ci CS35L35_SUPMON_DEPTH_CTL, 105962306a36Sopenharmony_ci CS35L35_ZEROFILL_DEPTH_MASK, 106062306a36Sopenharmony_ci monitor_config->zerofill_dpth << 106162306a36Sopenharmony_ci CS35L35_ZEROFILL_DEPTH_SHIFT); 106262306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, 106362306a36Sopenharmony_ci CS35L35_ZERO_FILL_LOC_CTL, 106462306a36Sopenharmony_ci CS35L35_MON_TXLOC_MASK, 106562306a36Sopenharmony_ci monitor_config->zerofill_loc << 106662306a36Sopenharmony_ci CS35L35_MON_TXLOC_SHIFT); 106762306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, 106862306a36Sopenharmony_ci CS35L35_ZERO_FILL_LOC_CTL, 106962306a36Sopenharmony_ci CS35L35_MON_FRM_MASK, 107062306a36Sopenharmony_ci monitor_config->zerofill_frm << 107162306a36Sopenharmony_ci CS35L35_MON_FRM_SHIFT); 107262306a36Sopenharmony_ci } 107362306a36Sopenharmony_ci } 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci return 0; 107662306a36Sopenharmony_ci} 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_cistatic const struct snd_soc_component_driver soc_component_dev_cs35l35 = { 107962306a36Sopenharmony_ci .probe = cs35l35_component_probe, 108062306a36Sopenharmony_ci .set_sysclk = cs35l35_component_set_sysclk, 108162306a36Sopenharmony_ci .dapm_widgets = cs35l35_dapm_widgets, 108262306a36Sopenharmony_ci .num_dapm_widgets = ARRAY_SIZE(cs35l35_dapm_widgets), 108362306a36Sopenharmony_ci .dapm_routes = cs35l35_audio_map, 108462306a36Sopenharmony_ci .num_dapm_routes = ARRAY_SIZE(cs35l35_audio_map), 108562306a36Sopenharmony_ci .controls = cs35l35_aud_controls, 108662306a36Sopenharmony_ci .num_controls = ARRAY_SIZE(cs35l35_aud_controls), 108762306a36Sopenharmony_ci .idle_bias_on = 1, 108862306a36Sopenharmony_ci .use_pmdown_time = 1, 108962306a36Sopenharmony_ci .endianness = 1, 109062306a36Sopenharmony_ci}; 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_cistatic struct regmap_config cs35l35_regmap = { 109362306a36Sopenharmony_ci .reg_bits = 8, 109462306a36Sopenharmony_ci .val_bits = 8, 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci .max_register = CS35L35_MAX_REGISTER, 109762306a36Sopenharmony_ci .reg_defaults = cs35l35_reg, 109862306a36Sopenharmony_ci .num_reg_defaults = ARRAY_SIZE(cs35l35_reg), 109962306a36Sopenharmony_ci .volatile_reg = cs35l35_volatile_register, 110062306a36Sopenharmony_ci .readable_reg = cs35l35_readable_register, 110162306a36Sopenharmony_ci .precious_reg = cs35l35_precious_register, 110262306a36Sopenharmony_ci .cache_type = REGCACHE_MAPLE, 110362306a36Sopenharmony_ci .use_single_read = true, 110462306a36Sopenharmony_ci .use_single_write = true, 110562306a36Sopenharmony_ci}; 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_cistatic irqreturn_t cs35l35_irq(int irq, void *data) 110862306a36Sopenharmony_ci{ 110962306a36Sopenharmony_ci struct cs35l35_private *cs35l35 = data; 111062306a36Sopenharmony_ci unsigned int sticky1, sticky2, sticky3, sticky4; 111162306a36Sopenharmony_ci unsigned int mask1, mask2, mask3, mask4, current1; 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci /* ack the irq by reading all status registers */ 111462306a36Sopenharmony_ci regmap_read(cs35l35->regmap, CS35L35_INT_STATUS_4, &sticky4); 111562306a36Sopenharmony_ci regmap_read(cs35l35->regmap, CS35L35_INT_STATUS_3, &sticky3); 111662306a36Sopenharmony_ci regmap_read(cs35l35->regmap, CS35L35_INT_STATUS_2, &sticky2); 111762306a36Sopenharmony_ci regmap_read(cs35l35->regmap, CS35L35_INT_STATUS_1, &sticky1); 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_ci regmap_read(cs35l35->regmap, CS35L35_INT_MASK_4, &mask4); 112062306a36Sopenharmony_ci regmap_read(cs35l35->regmap, CS35L35_INT_MASK_3, &mask3); 112162306a36Sopenharmony_ci regmap_read(cs35l35->regmap, CS35L35_INT_MASK_2, &mask2); 112262306a36Sopenharmony_ci regmap_read(cs35l35->regmap, CS35L35_INT_MASK_1, &mask1); 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_ci /* Check to see if unmasked bits are active */ 112562306a36Sopenharmony_ci if (!(sticky1 & ~mask1) && !(sticky2 & ~mask2) && !(sticky3 & ~mask3) 112662306a36Sopenharmony_ci && !(sticky4 & ~mask4)) 112762306a36Sopenharmony_ci return IRQ_NONE; 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_ci if (sticky2 & CS35L35_PDN_DONE) 113062306a36Sopenharmony_ci complete(&cs35l35->pdn_done); 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci /* read the current values */ 113362306a36Sopenharmony_ci regmap_read(cs35l35->regmap, CS35L35_INT_STATUS_1, ¤t1); 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci /* handle the interrupts */ 113662306a36Sopenharmony_ci if (sticky1 & CS35L35_CAL_ERR) { 113762306a36Sopenharmony_ci dev_crit(cs35l35->dev, "Calibration Error\n"); 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ci /* error is no longer asserted; safe to reset */ 114062306a36Sopenharmony_ci if (!(current1 & CS35L35_CAL_ERR)) { 114162306a36Sopenharmony_ci pr_debug("%s : Cal error release\n", __func__); 114262306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, 114362306a36Sopenharmony_ci CS35L35_PROT_RELEASE_CTL, 114462306a36Sopenharmony_ci CS35L35_CAL_ERR_RLS, 0); 114562306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, 114662306a36Sopenharmony_ci CS35L35_PROT_RELEASE_CTL, 114762306a36Sopenharmony_ci CS35L35_CAL_ERR_RLS, 114862306a36Sopenharmony_ci CS35L35_CAL_ERR_RLS); 114962306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, 115062306a36Sopenharmony_ci CS35L35_PROT_RELEASE_CTL, 115162306a36Sopenharmony_ci CS35L35_CAL_ERR_RLS, 0); 115262306a36Sopenharmony_ci } 115362306a36Sopenharmony_ci } 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci if (sticky1 & CS35L35_AMP_SHORT) { 115662306a36Sopenharmony_ci dev_crit(cs35l35->dev, "AMP Short Error\n"); 115762306a36Sopenharmony_ci /* error is no longer asserted; safe to reset */ 115862306a36Sopenharmony_ci if (!(current1 & CS35L35_AMP_SHORT)) { 115962306a36Sopenharmony_ci dev_dbg(cs35l35->dev, "Amp short error release\n"); 116062306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, 116162306a36Sopenharmony_ci CS35L35_PROT_RELEASE_CTL, 116262306a36Sopenharmony_ci CS35L35_SHORT_RLS, 0); 116362306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, 116462306a36Sopenharmony_ci CS35L35_PROT_RELEASE_CTL, 116562306a36Sopenharmony_ci CS35L35_SHORT_RLS, 116662306a36Sopenharmony_ci CS35L35_SHORT_RLS); 116762306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, 116862306a36Sopenharmony_ci CS35L35_PROT_RELEASE_CTL, 116962306a36Sopenharmony_ci CS35L35_SHORT_RLS, 0); 117062306a36Sopenharmony_ci } 117162306a36Sopenharmony_ci } 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci if (sticky1 & CS35L35_OTW) { 117462306a36Sopenharmony_ci dev_warn(cs35l35->dev, "Over temperature warning\n"); 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_ci /* error is no longer asserted; safe to reset */ 117762306a36Sopenharmony_ci if (!(current1 & CS35L35_OTW)) { 117862306a36Sopenharmony_ci dev_dbg(cs35l35->dev, "Over temperature warn release\n"); 117962306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, 118062306a36Sopenharmony_ci CS35L35_PROT_RELEASE_CTL, 118162306a36Sopenharmony_ci CS35L35_OTW_RLS, 0); 118262306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, 118362306a36Sopenharmony_ci CS35L35_PROT_RELEASE_CTL, 118462306a36Sopenharmony_ci CS35L35_OTW_RLS, 118562306a36Sopenharmony_ci CS35L35_OTW_RLS); 118662306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, 118762306a36Sopenharmony_ci CS35L35_PROT_RELEASE_CTL, 118862306a36Sopenharmony_ci CS35L35_OTW_RLS, 0); 118962306a36Sopenharmony_ci } 119062306a36Sopenharmony_ci } 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci if (sticky1 & CS35L35_OTE) { 119362306a36Sopenharmony_ci dev_crit(cs35l35->dev, "Over temperature error\n"); 119462306a36Sopenharmony_ci /* error is no longer asserted; safe to reset */ 119562306a36Sopenharmony_ci if (!(current1 & CS35L35_OTE)) { 119662306a36Sopenharmony_ci dev_dbg(cs35l35->dev, "Over temperature error release\n"); 119762306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, 119862306a36Sopenharmony_ci CS35L35_PROT_RELEASE_CTL, 119962306a36Sopenharmony_ci CS35L35_OTE_RLS, 0); 120062306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, 120162306a36Sopenharmony_ci CS35L35_PROT_RELEASE_CTL, 120262306a36Sopenharmony_ci CS35L35_OTE_RLS, 120362306a36Sopenharmony_ci CS35L35_OTE_RLS); 120462306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, 120562306a36Sopenharmony_ci CS35L35_PROT_RELEASE_CTL, 120662306a36Sopenharmony_ci CS35L35_OTE_RLS, 0); 120762306a36Sopenharmony_ci } 120862306a36Sopenharmony_ci } 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci if (sticky3 & CS35L35_BST_HIGH) { 121162306a36Sopenharmony_ci dev_crit(cs35l35->dev, "VBST error: powering off!\n"); 121262306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, 121362306a36Sopenharmony_ci CS35L35_PDN_AMP, CS35L35_PDN_AMP); 121462306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL1, 121562306a36Sopenharmony_ci CS35L35_PDN_ALL, CS35L35_PDN_ALL); 121662306a36Sopenharmony_ci } 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_ci if (sticky3 & CS35L35_LBST_SHORT) { 121962306a36Sopenharmony_ci dev_crit(cs35l35->dev, "LBST error: powering off!\n"); 122062306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, 122162306a36Sopenharmony_ci CS35L35_PDN_AMP, CS35L35_PDN_AMP); 122262306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL1, 122362306a36Sopenharmony_ci CS35L35_PDN_ALL, CS35L35_PDN_ALL); 122462306a36Sopenharmony_ci } 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_ci if (sticky2 & CS35L35_VPBR_ERR) 122762306a36Sopenharmony_ci dev_dbg(cs35l35->dev, "Error: Reactive Brownout\n"); 122862306a36Sopenharmony_ci 122962306a36Sopenharmony_ci if (sticky4 & CS35L35_VMON_OVFL) 123062306a36Sopenharmony_ci dev_dbg(cs35l35->dev, "Error: VMON overflow\n"); 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci if (sticky4 & CS35L35_IMON_OVFL) 123362306a36Sopenharmony_ci dev_dbg(cs35l35->dev, "Error: IMON overflow\n"); 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ci return IRQ_HANDLED; 123662306a36Sopenharmony_ci} 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_cistatic int cs35l35_handle_of_data(struct i2c_client *i2c_client, 124062306a36Sopenharmony_ci struct cs35l35_platform_data *pdata) 124162306a36Sopenharmony_ci{ 124262306a36Sopenharmony_ci struct device_node *np = i2c_client->dev.of_node; 124362306a36Sopenharmony_ci struct device_node *classh, *signal_format; 124462306a36Sopenharmony_ci struct classh_cfg *classh_config = &pdata->classh_algo; 124562306a36Sopenharmony_ci struct monitor_cfg *monitor_config = &pdata->mon_cfg; 124662306a36Sopenharmony_ci unsigned int val32 = 0; 124762306a36Sopenharmony_ci u8 monitor_array[4]; 124862306a36Sopenharmony_ci const int imon_array_size = ARRAY_SIZE(monitor_array); 124962306a36Sopenharmony_ci const int mon_array_size = imon_array_size - 1; 125062306a36Sopenharmony_ci int ret = 0; 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci if (!np) 125362306a36Sopenharmony_ci return 0; 125462306a36Sopenharmony_ci 125562306a36Sopenharmony_ci pdata->bst_pdn_fet_on = of_property_read_bool(np, 125662306a36Sopenharmony_ci "cirrus,boost-pdn-fet-on"); 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_ci ret = of_property_read_u32(np, "cirrus,boost-ctl-millivolt", &val32); 125962306a36Sopenharmony_ci if (ret >= 0) { 126062306a36Sopenharmony_ci if (val32 < 2600 || val32 > 9000) { 126162306a36Sopenharmony_ci dev_err(&i2c_client->dev, 126262306a36Sopenharmony_ci "Invalid Boost Voltage %d mV\n", val32); 126362306a36Sopenharmony_ci return -EINVAL; 126462306a36Sopenharmony_ci } 126562306a36Sopenharmony_ci pdata->bst_vctl = ((val32 - 2600) / 100) + 1; 126662306a36Sopenharmony_ci } 126762306a36Sopenharmony_ci 126862306a36Sopenharmony_ci ret = of_property_read_u32(np, "cirrus,boost-peak-milliamp", &val32); 126962306a36Sopenharmony_ci if (ret >= 0) { 127062306a36Sopenharmony_ci if (val32 < 1680 || val32 > 4480) { 127162306a36Sopenharmony_ci dev_err(&i2c_client->dev, 127262306a36Sopenharmony_ci "Invalid Boost Peak Current %u mA\n", val32); 127362306a36Sopenharmony_ci return -EINVAL; 127462306a36Sopenharmony_ci } 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci pdata->bst_ipk = ((val32 - 1680) / 110) | CS35L35_VALID_PDATA; 127762306a36Sopenharmony_ci } 127862306a36Sopenharmony_ci 127962306a36Sopenharmony_ci ret = of_property_read_u32(np, "cirrus,boost-ind-nanohenry", &val32); 128062306a36Sopenharmony_ci if (ret >= 0) { 128162306a36Sopenharmony_ci pdata->boost_ind = val32; 128262306a36Sopenharmony_ci } else { 128362306a36Sopenharmony_ci dev_err(&i2c_client->dev, "Inductor not specified.\n"); 128462306a36Sopenharmony_ci return -EINVAL; 128562306a36Sopenharmony_ci } 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci if (of_property_read_u32(np, "cirrus,sp-drv-strength", &val32) >= 0) 128862306a36Sopenharmony_ci pdata->sp_drv_str = val32; 128962306a36Sopenharmony_ci if (of_property_read_u32(np, "cirrus,sp-drv-unused", &val32) >= 0) 129062306a36Sopenharmony_ci pdata->sp_drv_unused = val32 | CS35L35_VALID_PDATA; 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ci pdata->stereo = of_property_read_bool(np, "cirrus,stereo-config"); 129362306a36Sopenharmony_ci 129462306a36Sopenharmony_ci if (pdata->stereo) { 129562306a36Sopenharmony_ci ret = of_property_read_u32(np, "cirrus,audio-channel", &val32); 129662306a36Sopenharmony_ci if (ret >= 0) 129762306a36Sopenharmony_ci pdata->aud_channel = val32; 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_ci ret = of_property_read_u32(np, "cirrus,advisory-channel", 130062306a36Sopenharmony_ci &val32); 130162306a36Sopenharmony_ci if (ret >= 0) 130262306a36Sopenharmony_ci pdata->adv_channel = val32; 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_ci pdata->shared_bst = of_property_read_bool(np, 130562306a36Sopenharmony_ci "cirrus,shared-boost"); 130662306a36Sopenharmony_ci } 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_ci pdata->ext_bst = of_property_read_bool(np, "cirrus,external-boost"); 130962306a36Sopenharmony_ci 131062306a36Sopenharmony_ci pdata->gain_zc = of_property_read_bool(np, "cirrus,amp-gain-zc"); 131162306a36Sopenharmony_ci 131262306a36Sopenharmony_ci classh = of_get_child_by_name(np, "cirrus,classh-internal-algo"); 131362306a36Sopenharmony_ci classh_config->classh_algo_enable = (classh != NULL); 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_ci if (classh_config->classh_algo_enable) { 131662306a36Sopenharmony_ci classh_config->classh_bst_override = 131762306a36Sopenharmony_ci of_property_read_bool(np, "cirrus,classh-bst-overide"); 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_ci ret = of_property_read_u32(classh, 132062306a36Sopenharmony_ci "cirrus,classh-bst-max-limit", 132162306a36Sopenharmony_ci &val32); 132262306a36Sopenharmony_ci if (ret >= 0) { 132362306a36Sopenharmony_ci val32 |= CS35L35_VALID_PDATA; 132462306a36Sopenharmony_ci classh_config->classh_bst_max_limit = val32; 132562306a36Sopenharmony_ci } 132662306a36Sopenharmony_ci 132762306a36Sopenharmony_ci ret = of_property_read_u32(classh, 132862306a36Sopenharmony_ci "cirrus,classh-bst-max-limit", 132962306a36Sopenharmony_ci &val32); 133062306a36Sopenharmony_ci if (ret >= 0) { 133162306a36Sopenharmony_ci val32 |= CS35L35_VALID_PDATA; 133262306a36Sopenharmony_ci classh_config->classh_bst_max_limit = val32; 133362306a36Sopenharmony_ci } 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ci ret = of_property_read_u32(classh, "cirrus,classh-mem-depth", 133662306a36Sopenharmony_ci &val32); 133762306a36Sopenharmony_ci if (ret >= 0) { 133862306a36Sopenharmony_ci val32 |= CS35L35_VALID_PDATA; 133962306a36Sopenharmony_ci classh_config->classh_mem_depth = val32; 134062306a36Sopenharmony_ci } 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci ret = of_property_read_u32(classh, "cirrus,classh-release-rate", 134362306a36Sopenharmony_ci &val32); 134462306a36Sopenharmony_ci if (ret >= 0) 134562306a36Sopenharmony_ci classh_config->classh_release_rate = val32; 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_ci ret = of_property_read_u32(classh, "cirrus,classh-headroom", 134862306a36Sopenharmony_ci &val32); 134962306a36Sopenharmony_ci if (ret >= 0) { 135062306a36Sopenharmony_ci val32 |= CS35L35_VALID_PDATA; 135162306a36Sopenharmony_ci classh_config->classh_headroom = val32; 135262306a36Sopenharmony_ci } 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_ci ret = of_property_read_u32(classh, 135562306a36Sopenharmony_ci "cirrus,classh-wk-fet-disable", 135662306a36Sopenharmony_ci &val32); 135762306a36Sopenharmony_ci if (ret >= 0) 135862306a36Sopenharmony_ci classh_config->classh_wk_fet_disable = val32; 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci ret = of_property_read_u32(classh, "cirrus,classh-wk-fet-delay", 136162306a36Sopenharmony_ci &val32); 136262306a36Sopenharmony_ci if (ret >= 0) { 136362306a36Sopenharmony_ci val32 |= CS35L35_VALID_PDATA; 136462306a36Sopenharmony_ci classh_config->classh_wk_fet_delay = val32; 136562306a36Sopenharmony_ci } 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_ci ret = of_property_read_u32(classh, "cirrus,classh-wk-fet-thld", 136862306a36Sopenharmony_ci &val32); 136962306a36Sopenharmony_ci if (ret >= 0) 137062306a36Sopenharmony_ci classh_config->classh_wk_fet_thld = val32; 137162306a36Sopenharmony_ci 137262306a36Sopenharmony_ci ret = of_property_read_u32(classh, "cirrus,classh-vpch-auto", 137362306a36Sopenharmony_ci &val32); 137462306a36Sopenharmony_ci if (ret >= 0) { 137562306a36Sopenharmony_ci val32 |= CS35L35_VALID_PDATA; 137662306a36Sopenharmony_ci classh_config->classh_vpch_auto = val32; 137762306a36Sopenharmony_ci } 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_ci ret = of_property_read_u32(classh, "cirrus,classh-vpch-rate", 138062306a36Sopenharmony_ci &val32); 138162306a36Sopenharmony_ci if (ret >= 0) { 138262306a36Sopenharmony_ci val32 |= CS35L35_VALID_PDATA; 138362306a36Sopenharmony_ci classh_config->classh_vpch_rate = val32; 138462306a36Sopenharmony_ci } 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ci ret = of_property_read_u32(classh, "cirrus,classh-vpch-man", 138762306a36Sopenharmony_ci &val32); 138862306a36Sopenharmony_ci if (ret >= 0) 138962306a36Sopenharmony_ci classh_config->classh_vpch_man = val32; 139062306a36Sopenharmony_ci } 139162306a36Sopenharmony_ci of_node_put(classh); 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_ci /* frame depth location */ 139462306a36Sopenharmony_ci signal_format = of_get_child_by_name(np, "cirrus,monitor-signal-format"); 139562306a36Sopenharmony_ci monitor_config->is_present = signal_format ? true : false; 139662306a36Sopenharmony_ci if (monitor_config->is_present) { 139762306a36Sopenharmony_ci ret = of_property_read_u8_array(signal_format, "cirrus,imon", 139862306a36Sopenharmony_ci monitor_array, imon_array_size); 139962306a36Sopenharmony_ci if (!ret) { 140062306a36Sopenharmony_ci monitor_config->imon_specs = true; 140162306a36Sopenharmony_ci monitor_config->imon_dpth = monitor_array[0]; 140262306a36Sopenharmony_ci monitor_config->imon_loc = monitor_array[1]; 140362306a36Sopenharmony_ci monitor_config->imon_frm = monitor_array[2]; 140462306a36Sopenharmony_ci monitor_config->imon_scale = monitor_array[3]; 140562306a36Sopenharmony_ci } 140662306a36Sopenharmony_ci ret = of_property_read_u8_array(signal_format, "cirrus,vmon", 140762306a36Sopenharmony_ci monitor_array, mon_array_size); 140862306a36Sopenharmony_ci if (!ret) { 140962306a36Sopenharmony_ci monitor_config->vmon_specs = true; 141062306a36Sopenharmony_ci monitor_config->vmon_dpth = monitor_array[0]; 141162306a36Sopenharmony_ci monitor_config->vmon_loc = monitor_array[1]; 141262306a36Sopenharmony_ci monitor_config->vmon_frm = monitor_array[2]; 141362306a36Sopenharmony_ci } 141462306a36Sopenharmony_ci ret = of_property_read_u8_array(signal_format, "cirrus,vpmon", 141562306a36Sopenharmony_ci monitor_array, mon_array_size); 141662306a36Sopenharmony_ci if (!ret) { 141762306a36Sopenharmony_ci monitor_config->vpmon_specs = true; 141862306a36Sopenharmony_ci monitor_config->vpmon_dpth = monitor_array[0]; 141962306a36Sopenharmony_ci monitor_config->vpmon_loc = monitor_array[1]; 142062306a36Sopenharmony_ci monitor_config->vpmon_frm = monitor_array[2]; 142162306a36Sopenharmony_ci } 142262306a36Sopenharmony_ci ret = of_property_read_u8_array(signal_format, "cirrus,vbstmon", 142362306a36Sopenharmony_ci monitor_array, mon_array_size); 142462306a36Sopenharmony_ci if (!ret) { 142562306a36Sopenharmony_ci monitor_config->vbstmon_specs = true; 142662306a36Sopenharmony_ci monitor_config->vbstmon_dpth = monitor_array[0]; 142762306a36Sopenharmony_ci monitor_config->vbstmon_loc = monitor_array[1]; 142862306a36Sopenharmony_ci monitor_config->vbstmon_frm = monitor_array[2]; 142962306a36Sopenharmony_ci } 143062306a36Sopenharmony_ci ret = of_property_read_u8_array(signal_format, "cirrus,vpbrstat", 143162306a36Sopenharmony_ci monitor_array, mon_array_size); 143262306a36Sopenharmony_ci if (!ret) { 143362306a36Sopenharmony_ci monitor_config->vpbrstat_specs = true; 143462306a36Sopenharmony_ci monitor_config->vpbrstat_dpth = monitor_array[0]; 143562306a36Sopenharmony_ci monitor_config->vpbrstat_loc = monitor_array[1]; 143662306a36Sopenharmony_ci monitor_config->vpbrstat_frm = monitor_array[2]; 143762306a36Sopenharmony_ci } 143862306a36Sopenharmony_ci ret = of_property_read_u8_array(signal_format, "cirrus,zerofill", 143962306a36Sopenharmony_ci monitor_array, mon_array_size); 144062306a36Sopenharmony_ci if (!ret) { 144162306a36Sopenharmony_ci monitor_config->zerofill_specs = true; 144262306a36Sopenharmony_ci monitor_config->zerofill_dpth = monitor_array[0]; 144362306a36Sopenharmony_ci monitor_config->zerofill_loc = monitor_array[1]; 144462306a36Sopenharmony_ci monitor_config->zerofill_frm = monitor_array[2]; 144562306a36Sopenharmony_ci } 144662306a36Sopenharmony_ci } 144762306a36Sopenharmony_ci of_node_put(signal_format); 144862306a36Sopenharmony_ci 144962306a36Sopenharmony_ci return 0; 145062306a36Sopenharmony_ci} 145162306a36Sopenharmony_ci 145262306a36Sopenharmony_ci/* Errata Rev A0 */ 145362306a36Sopenharmony_cistatic const struct reg_sequence cs35l35_errata_patch[] = { 145462306a36Sopenharmony_ci 145562306a36Sopenharmony_ci { 0x7F, 0x99 }, 145662306a36Sopenharmony_ci { 0x00, 0x99 }, 145762306a36Sopenharmony_ci { 0x52, 0x22 }, 145862306a36Sopenharmony_ci { 0x04, 0x14 }, 145962306a36Sopenharmony_ci { 0x6D, 0x44 }, 146062306a36Sopenharmony_ci { 0x24, 0x10 }, 146162306a36Sopenharmony_ci { 0x58, 0xC4 }, 146262306a36Sopenharmony_ci { 0x00, 0x98 }, 146362306a36Sopenharmony_ci { 0x18, 0x08 }, 146462306a36Sopenharmony_ci { 0x00, 0x00 }, 146562306a36Sopenharmony_ci { 0x7F, 0x00 }, 146662306a36Sopenharmony_ci}; 146762306a36Sopenharmony_ci 146862306a36Sopenharmony_cistatic int cs35l35_i2c_probe(struct i2c_client *i2c_client) 146962306a36Sopenharmony_ci{ 147062306a36Sopenharmony_ci struct cs35l35_private *cs35l35; 147162306a36Sopenharmony_ci struct device *dev = &i2c_client->dev; 147262306a36Sopenharmony_ci struct cs35l35_platform_data *pdata = dev_get_platdata(dev); 147362306a36Sopenharmony_ci int i, devid; 147462306a36Sopenharmony_ci int ret; 147562306a36Sopenharmony_ci unsigned int reg; 147662306a36Sopenharmony_ci 147762306a36Sopenharmony_ci cs35l35 = devm_kzalloc(dev, sizeof(struct cs35l35_private), GFP_KERNEL); 147862306a36Sopenharmony_ci if (!cs35l35) 147962306a36Sopenharmony_ci return -ENOMEM; 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_ci cs35l35->dev = dev; 148262306a36Sopenharmony_ci 148362306a36Sopenharmony_ci i2c_set_clientdata(i2c_client, cs35l35); 148462306a36Sopenharmony_ci cs35l35->regmap = devm_regmap_init_i2c(i2c_client, &cs35l35_regmap); 148562306a36Sopenharmony_ci if (IS_ERR(cs35l35->regmap)) { 148662306a36Sopenharmony_ci ret = PTR_ERR(cs35l35->regmap); 148762306a36Sopenharmony_ci dev_err(dev, "regmap_init() failed: %d\n", ret); 148862306a36Sopenharmony_ci return ret; 148962306a36Sopenharmony_ci } 149062306a36Sopenharmony_ci 149162306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(cs35l35_supplies); i++) 149262306a36Sopenharmony_ci cs35l35->supplies[i].supply = cs35l35_supplies[i]; 149362306a36Sopenharmony_ci 149462306a36Sopenharmony_ci cs35l35->num_supplies = ARRAY_SIZE(cs35l35_supplies); 149562306a36Sopenharmony_ci 149662306a36Sopenharmony_ci ret = devm_regulator_bulk_get(dev, cs35l35->num_supplies, 149762306a36Sopenharmony_ci cs35l35->supplies); 149862306a36Sopenharmony_ci if (ret != 0) { 149962306a36Sopenharmony_ci dev_err(dev, "Failed to request core supplies: %d\n", ret); 150062306a36Sopenharmony_ci return ret; 150162306a36Sopenharmony_ci } 150262306a36Sopenharmony_ci 150362306a36Sopenharmony_ci if (pdata) { 150462306a36Sopenharmony_ci cs35l35->pdata = *pdata; 150562306a36Sopenharmony_ci } else { 150662306a36Sopenharmony_ci pdata = devm_kzalloc(dev, sizeof(struct cs35l35_platform_data), 150762306a36Sopenharmony_ci GFP_KERNEL); 150862306a36Sopenharmony_ci if (!pdata) 150962306a36Sopenharmony_ci return -ENOMEM; 151062306a36Sopenharmony_ci if (i2c_client->dev.of_node) { 151162306a36Sopenharmony_ci ret = cs35l35_handle_of_data(i2c_client, pdata); 151262306a36Sopenharmony_ci if (ret != 0) 151362306a36Sopenharmony_ci return ret; 151462306a36Sopenharmony_ci 151562306a36Sopenharmony_ci } 151662306a36Sopenharmony_ci cs35l35->pdata = *pdata; 151762306a36Sopenharmony_ci } 151862306a36Sopenharmony_ci 151962306a36Sopenharmony_ci ret = regulator_bulk_enable(cs35l35->num_supplies, 152062306a36Sopenharmony_ci cs35l35->supplies); 152162306a36Sopenharmony_ci if (ret != 0) { 152262306a36Sopenharmony_ci dev_err(dev, "Failed to enable core supplies: %d\n", ret); 152362306a36Sopenharmony_ci return ret; 152462306a36Sopenharmony_ci } 152562306a36Sopenharmony_ci 152662306a36Sopenharmony_ci /* returning NULL can be valid if in stereo mode */ 152762306a36Sopenharmony_ci cs35l35->reset_gpio = devm_gpiod_get_optional(dev, "reset", 152862306a36Sopenharmony_ci GPIOD_OUT_LOW); 152962306a36Sopenharmony_ci if (IS_ERR(cs35l35->reset_gpio)) { 153062306a36Sopenharmony_ci ret = PTR_ERR(cs35l35->reset_gpio); 153162306a36Sopenharmony_ci cs35l35->reset_gpio = NULL; 153262306a36Sopenharmony_ci if (ret == -EBUSY) { 153362306a36Sopenharmony_ci dev_info(dev, 153462306a36Sopenharmony_ci "Reset line busy, assuming shared reset\n"); 153562306a36Sopenharmony_ci } else { 153662306a36Sopenharmony_ci dev_err(dev, "Failed to get reset GPIO: %d\n", ret); 153762306a36Sopenharmony_ci goto err; 153862306a36Sopenharmony_ci } 153962306a36Sopenharmony_ci } 154062306a36Sopenharmony_ci 154162306a36Sopenharmony_ci cs35l35_reset(cs35l35); 154262306a36Sopenharmony_ci 154362306a36Sopenharmony_ci init_completion(&cs35l35->pdn_done); 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_ci ret = devm_request_threaded_irq(dev, i2c_client->irq, NULL, cs35l35_irq, 154662306a36Sopenharmony_ci IRQF_ONESHOT | IRQF_TRIGGER_LOW | 154762306a36Sopenharmony_ci IRQF_SHARED, "cs35l35", cs35l35); 154862306a36Sopenharmony_ci if (ret != 0) { 154962306a36Sopenharmony_ci dev_err(dev, "Failed to request IRQ: %d\n", ret); 155062306a36Sopenharmony_ci goto err; 155162306a36Sopenharmony_ci } 155262306a36Sopenharmony_ci /* initialize codec */ 155362306a36Sopenharmony_ci devid = cirrus_read_device_id(cs35l35->regmap, CS35L35_DEVID_AB); 155462306a36Sopenharmony_ci if (devid < 0) { 155562306a36Sopenharmony_ci ret = devid; 155662306a36Sopenharmony_ci dev_err(dev, "Failed to read device ID: %d\n", ret); 155762306a36Sopenharmony_ci goto err; 155862306a36Sopenharmony_ci } 155962306a36Sopenharmony_ci 156062306a36Sopenharmony_ci if (devid != CS35L35_CHIP_ID) { 156162306a36Sopenharmony_ci dev_err(dev, "CS35L35 Device ID (%X). Expected ID %X\n", 156262306a36Sopenharmony_ci devid, CS35L35_CHIP_ID); 156362306a36Sopenharmony_ci ret = -ENODEV; 156462306a36Sopenharmony_ci goto err; 156562306a36Sopenharmony_ci } 156662306a36Sopenharmony_ci 156762306a36Sopenharmony_ci ret = regmap_read(cs35l35->regmap, CS35L35_REV_ID, ®); 156862306a36Sopenharmony_ci if (ret < 0) { 156962306a36Sopenharmony_ci dev_err(dev, "Get Revision ID failed: %d\n", ret); 157062306a36Sopenharmony_ci goto err; 157162306a36Sopenharmony_ci } 157262306a36Sopenharmony_ci 157362306a36Sopenharmony_ci ret = regmap_register_patch(cs35l35->regmap, cs35l35_errata_patch, 157462306a36Sopenharmony_ci ARRAY_SIZE(cs35l35_errata_patch)); 157562306a36Sopenharmony_ci if (ret < 0) { 157662306a36Sopenharmony_ci dev_err(dev, "Failed to apply errata patch: %d\n", ret); 157762306a36Sopenharmony_ci goto err; 157862306a36Sopenharmony_ci } 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_ci dev_info(dev, "Cirrus Logic CS35L35 (%x), Revision: %02X\n", 158162306a36Sopenharmony_ci devid, reg & 0xFF); 158262306a36Sopenharmony_ci 158362306a36Sopenharmony_ci /* Set the INT Masks for critical errors */ 158462306a36Sopenharmony_ci regmap_write(cs35l35->regmap, CS35L35_INT_MASK_1, 158562306a36Sopenharmony_ci CS35L35_INT1_CRIT_MASK); 158662306a36Sopenharmony_ci regmap_write(cs35l35->regmap, CS35L35_INT_MASK_2, 158762306a36Sopenharmony_ci CS35L35_INT2_CRIT_MASK); 158862306a36Sopenharmony_ci regmap_write(cs35l35->regmap, CS35L35_INT_MASK_3, 158962306a36Sopenharmony_ci CS35L35_INT3_CRIT_MASK); 159062306a36Sopenharmony_ci regmap_write(cs35l35->regmap, CS35L35_INT_MASK_4, 159162306a36Sopenharmony_ci CS35L35_INT4_CRIT_MASK); 159262306a36Sopenharmony_ci 159362306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, 159462306a36Sopenharmony_ci CS35L35_PWR2_PDN_MASK, 159562306a36Sopenharmony_ci CS35L35_PWR2_PDN_MASK); 159662306a36Sopenharmony_ci 159762306a36Sopenharmony_ci if (cs35l35->pdata.bst_pdn_fet_on) 159862306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, 159962306a36Sopenharmony_ci CS35L35_PDN_BST_MASK, 160062306a36Sopenharmony_ci 1 << CS35L35_PDN_BST_FETON_SHIFT); 160162306a36Sopenharmony_ci else 160262306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, 160362306a36Sopenharmony_ci CS35L35_PDN_BST_MASK, 160462306a36Sopenharmony_ci 1 << CS35L35_PDN_BST_FETOFF_SHIFT); 160562306a36Sopenharmony_ci 160662306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL3, 160762306a36Sopenharmony_ci CS35L35_PWR3_PDN_MASK, 160862306a36Sopenharmony_ci CS35L35_PWR3_PDN_MASK); 160962306a36Sopenharmony_ci 161062306a36Sopenharmony_ci regmap_update_bits(cs35l35->regmap, CS35L35_PROTECT_CTL, 161162306a36Sopenharmony_ci CS35L35_AMP_MUTE_MASK, 1 << CS35L35_AMP_MUTE_SHIFT); 161262306a36Sopenharmony_ci 161362306a36Sopenharmony_ci ret = devm_snd_soc_register_component(dev, &soc_component_dev_cs35l35, 161462306a36Sopenharmony_ci cs35l35_dai, ARRAY_SIZE(cs35l35_dai)); 161562306a36Sopenharmony_ci if (ret < 0) { 161662306a36Sopenharmony_ci dev_err(dev, "Failed to register component: %d\n", ret); 161762306a36Sopenharmony_ci goto err; 161862306a36Sopenharmony_ci } 161962306a36Sopenharmony_ci 162062306a36Sopenharmony_ci return 0; 162162306a36Sopenharmony_ci 162262306a36Sopenharmony_cierr: 162362306a36Sopenharmony_ci regulator_bulk_disable(cs35l35->num_supplies, 162462306a36Sopenharmony_ci cs35l35->supplies); 162562306a36Sopenharmony_ci gpiod_set_value_cansleep(cs35l35->reset_gpio, 0); 162662306a36Sopenharmony_ci 162762306a36Sopenharmony_ci return ret; 162862306a36Sopenharmony_ci} 162962306a36Sopenharmony_ci 163062306a36Sopenharmony_cistatic void cs35l35_i2c_remove(struct i2c_client *i2c_client) 163162306a36Sopenharmony_ci{ 163262306a36Sopenharmony_ci struct cs35l35_private *cs35l35 = i2c_get_clientdata(i2c_client); 163362306a36Sopenharmony_ci 163462306a36Sopenharmony_ci regulator_bulk_disable(cs35l35->num_supplies, cs35l35->supplies); 163562306a36Sopenharmony_ci gpiod_set_value_cansleep(cs35l35->reset_gpio, 0); 163662306a36Sopenharmony_ci} 163762306a36Sopenharmony_ci 163862306a36Sopenharmony_cistatic const struct of_device_id cs35l35_of_match[] = { 163962306a36Sopenharmony_ci {.compatible = "cirrus,cs35l35"}, 164062306a36Sopenharmony_ci {}, 164162306a36Sopenharmony_ci}; 164262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, cs35l35_of_match); 164362306a36Sopenharmony_ci 164462306a36Sopenharmony_cistatic const struct i2c_device_id cs35l35_id[] = { 164562306a36Sopenharmony_ci {"cs35l35", 0}, 164662306a36Sopenharmony_ci {} 164762306a36Sopenharmony_ci}; 164862306a36Sopenharmony_ci 164962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, cs35l35_id); 165062306a36Sopenharmony_ci 165162306a36Sopenharmony_cistatic struct i2c_driver cs35l35_i2c_driver = { 165262306a36Sopenharmony_ci .driver = { 165362306a36Sopenharmony_ci .name = "cs35l35", 165462306a36Sopenharmony_ci .of_match_table = cs35l35_of_match, 165562306a36Sopenharmony_ci }, 165662306a36Sopenharmony_ci .id_table = cs35l35_id, 165762306a36Sopenharmony_ci .probe = cs35l35_i2c_probe, 165862306a36Sopenharmony_ci .remove = cs35l35_i2c_remove, 165962306a36Sopenharmony_ci}; 166062306a36Sopenharmony_ci 166162306a36Sopenharmony_cimodule_i2c_driver(cs35l35_i2c_driver); 166262306a36Sopenharmony_ci 166362306a36Sopenharmony_ciMODULE_DESCRIPTION("ASoC CS35L35 driver"); 166462306a36Sopenharmony_ciMODULE_AUTHOR("Brian Austin, Cirrus Logic Inc, <brian.austin@cirrus.com>"); 166562306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 1666