162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci// 362306a36Sopenharmony_ci// Driver for the Texas Instruments TAS2764 CODEC 462306a36Sopenharmony_ci// Copyright (C) 2020 Texas Instruments Inc. 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/module.h> 762306a36Sopenharmony_ci#include <linux/moduleparam.h> 862306a36Sopenharmony_ci#include <linux/err.h> 962306a36Sopenharmony_ci#include <linux/init.h> 1062306a36Sopenharmony_ci#include <linux/delay.h> 1162306a36Sopenharmony_ci#include <linux/pm.h> 1262306a36Sopenharmony_ci#include <linux/i2c.h> 1362306a36Sopenharmony_ci#include <linux/gpio.h> 1462306a36Sopenharmony_ci#include <linux/gpio/consumer.h> 1562306a36Sopenharmony_ci#include <linux/regulator/consumer.h> 1662306a36Sopenharmony_ci#include <linux/regmap.h> 1762306a36Sopenharmony_ci#include <linux/of.h> 1862306a36Sopenharmony_ci#include <linux/of_gpio.h> 1962306a36Sopenharmony_ci#include <linux/slab.h> 2062306a36Sopenharmony_ci#include <sound/soc.h> 2162306a36Sopenharmony_ci#include <sound/pcm.h> 2262306a36Sopenharmony_ci#include <sound/pcm_params.h> 2362306a36Sopenharmony_ci#include <sound/initval.h> 2462306a36Sopenharmony_ci#include <sound/tlv.h> 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#include "tas2764.h" 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistruct tas2764_priv { 2962306a36Sopenharmony_ci struct snd_soc_component *component; 3062306a36Sopenharmony_ci struct gpio_desc *reset_gpio; 3162306a36Sopenharmony_ci struct gpio_desc *sdz_gpio; 3262306a36Sopenharmony_ci struct regmap *regmap; 3362306a36Sopenharmony_ci struct device *dev; 3462306a36Sopenharmony_ci int irq; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci int v_sense_slot; 3762306a36Sopenharmony_ci int i_sense_slot; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci bool dac_powered; 4062306a36Sopenharmony_ci bool unmuted; 4162306a36Sopenharmony_ci}; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cistatic const char *tas2764_int_ltch0_msgs[8] = { 4462306a36Sopenharmony_ci "fault: over temperature", /* INT_LTCH0 & BIT(0) */ 4562306a36Sopenharmony_ci "fault: over current", 4662306a36Sopenharmony_ci "fault: bad TDM clock", 4762306a36Sopenharmony_ci "limiter active", 4862306a36Sopenharmony_ci "fault: PVDD below limiter inflection point", 4962306a36Sopenharmony_ci "fault: limiter max attenuation", 5062306a36Sopenharmony_ci "fault: BOP infinite hold", 5162306a36Sopenharmony_ci "fault: BOP mute", /* INT_LTCH0 & BIT(7) */ 5262306a36Sopenharmony_ci}; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistatic const unsigned int tas2764_int_readout_regs[6] = { 5562306a36Sopenharmony_ci TAS2764_INT_LTCH0, 5662306a36Sopenharmony_ci TAS2764_INT_LTCH1, 5762306a36Sopenharmony_ci TAS2764_INT_LTCH1_0, 5862306a36Sopenharmony_ci TAS2764_INT_LTCH2, 5962306a36Sopenharmony_ci TAS2764_INT_LTCH3, 6062306a36Sopenharmony_ci TAS2764_INT_LTCH4, 6162306a36Sopenharmony_ci}; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistatic irqreturn_t tas2764_irq(int irq, void *data) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci struct tas2764_priv *tas2764 = data; 6662306a36Sopenharmony_ci u8 latched[6] = {0, 0, 0, 0, 0, 0}; 6762306a36Sopenharmony_ci int ret = IRQ_NONE; 6862306a36Sopenharmony_ci int i; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(latched); i++) 7162306a36Sopenharmony_ci latched[i] = snd_soc_component_read(tas2764->component, 7262306a36Sopenharmony_ci tas2764_int_readout_regs[i]); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci for (i = 0; i < 8; i++) { 7562306a36Sopenharmony_ci if (latched[0] & BIT(i)) { 7662306a36Sopenharmony_ci dev_crit_ratelimited(tas2764->dev, "%s\n", 7762306a36Sopenharmony_ci tas2764_int_ltch0_msgs[i]); 7862306a36Sopenharmony_ci ret = IRQ_HANDLED; 7962306a36Sopenharmony_ci } 8062306a36Sopenharmony_ci } 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci if (latched[0]) { 8362306a36Sopenharmony_ci dev_err_ratelimited(tas2764->dev, "other context to the fault: %02x,%02x,%02x,%02x,%02x", 8462306a36Sopenharmony_ci latched[1], latched[2], latched[3], latched[4], latched[5]); 8562306a36Sopenharmony_ci snd_soc_component_update_bits(tas2764->component, 8662306a36Sopenharmony_ci TAS2764_INT_CLK_CFG, 8762306a36Sopenharmony_ci TAS2764_INT_CLK_CFG_IRQZ_CLR, 8862306a36Sopenharmony_ci TAS2764_INT_CLK_CFG_IRQZ_CLR); 8962306a36Sopenharmony_ci } 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci return ret; 9262306a36Sopenharmony_ci} 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistatic void tas2764_reset(struct tas2764_priv *tas2764) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci if (tas2764->reset_gpio) { 9762306a36Sopenharmony_ci gpiod_set_value_cansleep(tas2764->reset_gpio, 0); 9862306a36Sopenharmony_ci msleep(20); 9962306a36Sopenharmony_ci gpiod_set_value_cansleep(tas2764->reset_gpio, 1); 10062306a36Sopenharmony_ci usleep_range(1000, 2000); 10162306a36Sopenharmony_ci } 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci snd_soc_component_write(tas2764->component, TAS2764_SW_RST, 10462306a36Sopenharmony_ci TAS2764_RST); 10562306a36Sopenharmony_ci usleep_range(1000, 2000); 10662306a36Sopenharmony_ci} 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cistatic int tas2764_update_pwr_ctrl(struct tas2764_priv *tas2764) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci struct snd_soc_component *component = tas2764->component; 11162306a36Sopenharmony_ci unsigned int val; 11262306a36Sopenharmony_ci int ret; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci if (tas2764->dac_powered) 11562306a36Sopenharmony_ci val = tas2764->unmuted ? 11662306a36Sopenharmony_ci TAS2764_PWR_CTRL_ACTIVE : TAS2764_PWR_CTRL_MUTE; 11762306a36Sopenharmony_ci else 11862306a36Sopenharmony_ci val = TAS2764_PWR_CTRL_SHUTDOWN; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci ret = snd_soc_component_update_bits(component, TAS2764_PWR_CTRL, 12162306a36Sopenharmony_ci TAS2764_PWR_CTRL_MASK, val); 12262306a36Sopenharmony_ci if (ret < 0) 12362306a36Sopenharmony_ci return ret; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci return 0; 12662306a36Sopenharmony_ci} 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci#ifdef CONFIG_PM 12962306a36Sopenharmony_cistatic int tas2764_codec_suspend(struct snd_soc_component *component) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component); 13262306a36Sopenharmony_ci int ret; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci ret = snd_soc_component_update_bits(component, TAS2764_PWR_CTRL, 13562306a36Sopenharmony_ci TAS2764_PWR_CTRL_MASK, 13662306a36Sopenharmony_ci TAS2764_PWR_CTRL_SHUTDOWN); 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci if (ret < 0) 13962306a36Sopenharmony_ci return ret; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci if (tas2764->sdz_gpio) 14262306a36Sopenharmony_ci gpiod_set_value_cansleep(tas2764->sdz_gpio, 0); 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci regcache_cache_only(tas2764->regmap, true); 14562306a36Sopenharmony_ci regcache_mark_dirty(tas2764->regmap); 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci return 0; 14862306a36Sopenharmony_ci} 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_cistatic int tas2764_codec_resume(struct snd_soc_component *component) 15162306a36Sopenharmony_ci{ 15262306a36Sopenharmony_ci struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component); 15362306a36Sopenharmony_ci int ret; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci if (tas2764->sdz_gpio) { 15662306a36Sopenharmony_ci gpiod_set_value_cansleep(tas2764->sdz_gpio, 1); 15762306a36Sopenharmony_ci usleep_range(1000, 2000); 15862306a36Sopenharmony_ci } 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci ret = tas2764_update_pwr_ctrl(tas2764); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci if (ret < 0) 16362306a36Sopenharmony_ci return ret; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci regcache_cache_only(tas2764->regmap, false); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci return regcache_sync(tas2764->regmap); 16862306a36Sopenharmony_ci} 16962306a36Sopenharmony_ci#else 17062306a36Sopenharmony_ci#define tas2764_codec_suspend NULL 17162306a36Sopenharmony_ci#define tas2764_codec_resume NULL 17262306a36Sopenharmony_ci#endif 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_cistatic const char * const tas2764_ASI1_src[] = { 17562306a36Sopenharmony_ci "I2C offset", "Left", "Right", "LeftRightDiv2", 17662306a36Sopenharmony_ci}; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL( 17962306a36Sopenharmony_ci tas2764_ASI1_src_enum, TAS2764_TDM_CFG2, TAS2764_TDM_CFG2_SCFG_SHIFT, 18062306a36Sopenharmony_ci tas2764_ASI1_src); 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_cistatic const struct snd_kcontrol_new tas2764_asi1_mux = 18362306a36Sopenharmony_ci SOC_DAPM_ENUM("ASI1 Source", tas2764_ASI1_src_enum); 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_cistatic int tas2764_dac_event(struct snd_soc_dapm_widget *w, 18662306a36Sopenharmony_ci struct snd_kcontrol *kcontrol, int event) 18762306a36Sopenharmony_ci{ 18862306a36Sopenharmony_ci struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 18962306a36Sopenharmony_ci struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component); 19062306a36Sopenharmony_ci int ret; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci switch (event) { 19362306a36Sopenharmony_ci case SND_SOC_DAPM_POST_PMU: 19462306a36Sopenharmony_ci tas2764->dac_powered = true; 19562306a36Sopenharmony_ci ret = tas2764_update_pwr_ctrl(tas2764); 19662306a36Sopenharmony_ci break; 19762306a36Sopenharmony_ci case SND_SOC_DAPM_PRE_PMD: 19862306a36Sopenharmony_ci tas2764->dac_powered = false; 19962306a36Sopenharmony_ci ret = tas2764_update_pwr_ctrl(tas2764); 20062306a36Sopenharmony_ci break; 20162306a36Sopenharmony_ci default: 20262306a36Sopenharmony_ci dev_err(tas2764->dev, "Unsupported event\n"); 20362306a36Sopenharmony_ci return -EINVAL; 20462306a36Sopenharmony_ci } 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci if (ret < 0) 20762306a36Sopenharmony_ci return ret; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci return 0; 21062306a36Sopenharmony_ci} 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_cistatic const struct snd_kcontrol_new isense_switch = 21362306a36Sopenharmony_ci SOC_DAPM_SINGLE("Switch", TAS2764_PWR_CTRL, TAS2764_ISENSE_POWER_EN, 1, 1); 21462306a36Sopenharmony_cistatic const struct snd_kcontrol_new vsense_switch = 21562306a36Sopenharmony_ci SOC_DAPM_SINGLE("Switch", TAS2764_PWR_CTRL, TAS2764_VSENSE_POWER_EN, 1, 1); 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_cistatic const struct snd_soc_dapm_widget tas2764_dapm_widgets[] = { 21862306a36Sopenharmony_ci SND_SOC_DAPM_AIF_IN("ASI1", "ASI1 Playback", 0, SND_SOC_NOPM, 0, 0), 21962306a36Sopenharmony_ci SND_SOC_DAPM_MUX("ASI1 Sel", SND_SOC_NOPM, 0, 0, &tas2764_asi1_mux), 22062306a36Sopenharmony_ci SND_SOC_DAPM_SWITCH("ISENSE", TAS2764_PWR_CTRL, TAS2764_ISENSE_POWER_EN, 22162306a36Sopenharmony_ci 1, &isense_switch), 22262306a36Sopenharmony_ci SND_SOC_DAPM_SWITCH("VSENSE", TAS2764_PWR_CTRL, TAS2764_VSENSE_POWER_EN, 22362306a36Sopenharmony_ci 1, &vsense_switch), 22462306a36Sopenharmony_ci SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0, tas2764_dac_event, 22562306a36Sopenharmony_ci SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), 22662306a36Sopenharmony_ci SND_SOC_DAPM_OUTPUT("OUT"), 22762306a36Sopenharmony_ci SND_SOC_DAPM_SIGGEN("VMON"), 22862306a36Sopenharmony_ci SND_SOC_DAPM_SIGGEN("IMON") 22962306a36Sopenharmony_ci}; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_cistatic const struct snd_soc_dapm_route tas2764_audio_map[] = { 23262306a36Sopenharmony_ci {"ASI1 Sel", "I2C offset", "ASI1"}, 23362306a36Sopenharmony_ci {"ASI1 Sel", "Left", "ASI1"}, 23462306a36Sopenharmony_ci {"ASI1 Sel", "Right", "ASI1"}, 23562306a36Sopenharmony_ci {"ASI1 Sel", "LeftRightDiv2", "ASI1"}, 23662306a36Sopenharmony_ci {"DAC", NULL, "ASI1 Sel"}, 23762306a36Sopenharmony_ci {"OUT", NULL, "DAC"}, 23862306a36Sopenharmony_ci {"ISENSE", "Switch", "IMON"}, 23962306a36Sopenharmony_ci {"VSENSE", "Switch", "VMON"}, 24062306a36Sopenharmony_ci}; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_cistatic int tas2764_mute(struct snd_soc_dai *dai, int mute, int direction) 24362306a36Sopenharmony_ci{ 24462306a36Sopenharmony_ci struct tas2764_priv *tas2764 = 24562306a36Sopenharmony_ci snd_soc_component_get_drvdata(dai->component); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci tas2764->unmuted = !mute; 24862306a36Sopenharmony_ci return tas2764_update_pwr_ctrl(tas2764); 24962306a36Sopenharmony_ci} 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_cistatic int tas2764_set_bitwidth(struct tas2764_priv *tas2764, int bitwidth) 25262306a36Sopenharmony_ci{ 25362306a36Sopenharmony_ci struct snd_soc_component *component = tas2764->component; 25462306a36Sopenharmony_ci int sense_en; 25562306a36Sopenharmony_ci int val; 25662306a36Sopenharmony_ci int ret; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci switch (bitwidth) { 25962306a36Sopenharmony_ci case SNDRV_PCM_FORMAT_S16_LE: 26062306a36Sopenharmony_ci ret = snd_soc_component_update_bits(component, 26162306a36Sopenharmony_ci TAS2764_TDM_CFG2, 26262306a36Sopenharmony_ci TAS2764_TDM_CFG2_RXW_MASK, 26362306a36Sopenharmony_ci TAS2764_TDM_CFG2_RXW_16BITS); 26462306a36Sopenharmony_ci break; 26562306a36Sopenharmony_ci case SNDRV_PCM_FORMAT_S24_LE: 26662306a36Sopenharmony_ci ret = snd_soc_component_update_bits(component, 26762306a36Sopenharmony_ci TAS2764_TDM_CFG2, 26862306a36Sopenharmony_ci TAS2764_TDM_CFG2_RXW_MASK, 26962306a36Sopenharmony_ci TAS2764_TDM_CFG2_RXW_24BITS); 27062306a36Sopenharmony_ci break; 27162306a36Sopenharmony_ci case SNDRV_PCM_FORMAT_S32_LE: 27262306a36Sopenharmony_ci ret = snd_soc_component_update_bits(component, 27362306a36Sopenharmony_ci TAS2764_TDM_CFG2, 27462306a36Sopenharmony_ci TAS2764_TDM_CFG2_RXW_MASK, 27562306a36Sopenharmony_ci TAS2764_TDM_CFG2_RXW_32BITS); 27662306a36Sopenharmony_ci break; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci default: 27962306a36Sopenharmony_ci return -EINVAL; 28062306a36Sopenharmony_ci } 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci if (ret < 0) 28362306a36Sopenharmony_ci return ret; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci val = snd_soc_component_read(tas2764->component, TAS2764_PWR_CTRL); 28662306a36Sopenharmony_ci if (val < 0) 28762306a36Sopenharmony_ci return val; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci if (val & (1 << TAS2764_VSENSE_POWER_EN)) 29062306a36Sopenharmony_ci sense_en = 0; 29162306a36Sopenharmony_ci else 29262306a36Sopenharmony_ci sense_en = TAS2764_TDM_CFG5_VSNS_ENABLE; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci ret = snd_soc_component_update_bits(tas2764->component, TAS2764_TDM_CFG5, 29562306a36Sopenharmony_ci TAS2764_TDM_CFG5_VSNS_ENABLE, 29662306a36Sopenharmony_ci sense_en); 29762306a36Sopenharmony_ci if (ret < 0) 29862306a36Sopenharmony_ci return ret; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci if (val & (1 << TAS2764_ISENSE_POWER_EN)) 30162306a36Sopenharmony_ci sense_en = 0; 30262306a36Sopenharmony_ci else 30362306a36Sopenharmony_ci sense_en = TAS2764_TDM_CFG6_ISNS_ENABLE; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci ret = snd_soc_component_update_bits(tas2764->component, TAS2764_TDM_CFG6, 30662306a36Sopenharmony_ci TAS2764_TDM_CFG6_ISNS_ENABLE, 30762306a36Sopenharmony_ci sense_en); 30862306a36Sopenharmony_ci if (ret < 0) 30962306a36Sopenharmony_ci return ret; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci return 0; 31262306a36Sopenharmony_ci} 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_cistatic int tas2764_set_samplerate(struct tas2764_priv *tas2764, int samplerate) 31562306a36Sopenharmony_ci{ 31662306a36Sopenharmony_ci struct snd_soc_component *component = tas2764->component; 31762306a36Sopenharmony_ci int ramp_rate_val; 31862306a36Sopenharmony_ci int ret; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci switch (samplerate) { 32162306a36Sopenharmony_ci case 48000: 32262306a36Sopenharmony_ci ramp_rate_val = TAS2764_TDM_CFG0_SMP_48KHZ | 32362306a36Sopenharmony_ci TAS2764_TDM_CFG0_44_1_48KHZ; 32462306a36Sopenharmony_ci break; 32562306a36Sopenharmony_ci case 44100: 32662306a36Sopenharmony_ci ramp_rate_val = TAS2764_TDM_CFG0_SMP_44_1KHZ | 32762306a36Sopenharmony_ci TAS2764_TDM_CFG0_44_1_48KHZ; 32862306a36Sopenharmony_ci break; 32962306a36Sopenharmony_ci case 96000: 33062306a36Sopenharmony_ci ramp_rate_val = TAS2764_TDM_CFG0_SMP_48KHZ | 33162306a36Sopenharmony_ci TAS2764_TDM_CFG0_88_2_96KHZ; 33262306a36Sopenharmony_ci break; 33362306a36Sopenharmony_ci case 88200: 33462306a36Sopenharmony_ci ramp_rate_val = TAS2764_TDM_CFG0_SMP_44_1KHZ | 33562306a36Sopenharmony_ci TAS2764_TDM_CFG0_88_2_96KHZ; 33662306a36Sopenharmony_ci break; 33762306a36Sopenharmony_ci default: 33862306a36Sopenharmony_ci return -EINVAL; 33962306a36Sopenharmony_ci } 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG0, 34262306a36Sopenharmony_ci TAS2764_TDM_CFG0_SMP_MASK | 34362306a36Sopenharmony_ci TAS2764_TDM_CFG0_MASK, 34462306a36Sopenharmony_ci ramp_rate_val); 34562306a36Sopenharmony_ci if (ret < 0) 34662306a36Sopenharmony_ci return ret; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci return 0; 34962306a36Sopenharmony_ci} 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_cistatic int tas2764_hw_params(struct snd_pcm_substream *substream, 35262306a36Sopenharmony_ci struct snd_pcm_hw_params *params, 35362306a36Sopenharmony_ci struct snd_soc_dai *dai) 35462306a36Sopenharmony_ci{ 35562306a36Sopenharmony_ci struct snd_soc_component *component = dai->component; 35662306a36Sopenharmony_ci struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component); 35762306a36Sopenharmony_ci int ret; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci ret = tas2764_set_bitwidth(tas2764, params_format(params)); 36062306a36Sopenharmony_ci if (ret < 0) 36162306a36Sopenharmony_ci return ret; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci return tas2764_set_samplerate(tas2764, params_rate(params)); 36462306a36Sopenharmony_ci} 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_cistatic int tas2764_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) 36762306a36Sopenharmony_ci{ 36862306a36Sopenharmony_ci struct snd_soc_component *component = dai->component; 36962306a36Sopenharmony_ci struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component); 37062306a36Sopenharmony_ci u8 tdm_rx_start_slot = 0, asi_cfg_0 = 0, asi_cfg_1 = 0; 37162306a36Sopenharmony_ci int ret; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 37462306a36Sopenharmony_ci case SND_SOC_DAIFMT_NB_IF: 37562306a36Sopenharmony_ci asi_cfg_0 ^= TAS2764_TDM_CFG0_FRAME_START; 37662306a36Sopenharmony_ci fallthrough; 37762306a36Sopenharmony_ci case SND_SOC_DAIFMT_NB_NF: 37862306a36Sopenharmony_ci asi_cfg_1 = TAS2764_TDM_CFG1_RX_RISING; 37962306a36Sopenharmony_ci break; 38062306a36Sopenharmony_ci case SND_SOC_DAIFMT_IB_IF: 38162306a36Sopenharmony_ci asi_cfg_0 ^= TAS2764_TDM_CFG0_FRAME_START; 38262306a36Sopenharmony_ci fallthrough; 38362306a36Sopenharmony_ci case SND_SOC_DAIFMT_IB_NF: 38462306a36Sopenharmony_ci asi_cfg_1 = TAS2764_TDM_CFG1_RX_FALLING; 38562306a36Sopenharmony_ci break; 38662306a36Sopenharmony_ci } 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG1, 38962306a36Sopenharmony_ci TAS2764_TDM_CFG1_RX_MASK, 39062306a36Sopenharmony_ci asi_cfg_1); 39162306a36Sopenharmony_ci if (ret < 0) 39262306a36Sopenharmony_ci return ret; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 39562306a36Sopenharmony_ci case SND_SOC_DAIFMT_I2S: 39662306a36Sopenharmony_ci asi_cfg_0 ^= TAS2764_TDM_CFG0_FRAME_START; 39762306a36Sopenharmony_ci fallthrough; 39862306a36Sopenharmony_ci case SND_SOC_DAIFMT_DSP_A: 39962306a36Sopenharmony_ci tdm_rx_start_slot = 1; 40062306a36Sopenharmony_ci break; 40162306a36Sopenharmony_ci case SND_SOC_DAIFMT_DSP_B: 40262306a36Sopenharmony_ci case SND_SOC_DAIFMT_LEFT_J: 40362306a36Sopenharmony_ci tdm_rx_start_slot = 0; 40462306a36Sopenharmony_ci break; 40562306a36Sopenharmony_ci default: 40662306a36Sopenharmony_ci dev_err(tas2764->dev, 40762306a36Sopenharmony_ci "DAI Format is not found, fmt=0x%x\n", fmt); 40862306a36Sopenharmony_ci return -EINVAL; 40962306a36Sopenharmony_ci } 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG0, 41262306a36Sopenharmony_ci TAS2764_TDM_CFG0_FRAME_START, 41362306a36Sopenharmony_ci asi_cfg_0); 41462306a36Sopenharmony_ci if (ret < 0) 41562306a36Sopenharmony_ci return ret; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG1, 41862306a36Sopenharmony_ci TAS2764_TDM_CFG1_MASK, 41962306a36Sopenharmony_ci (tdm_rx_start_slot << TAS2764_TDM_CFG1_51_SHIFT)); 42062306a36Sopenharmony_ci if (ret < 0) 42162306a36Sopenharmony_ci return ret; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci return 0; 42462306a36Sopenharmony_ci} 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_cistatic int tas2764_set_dai_tdm_slot(struct snd_soc_dai *dai, 42762306a36Sopenharmony_ci unsigned int tx_mask, 42862306a36Sopenharmony_ci unsigned int rx_mask, 42962306a36Sopenharmony_ci int slots, int slot_width) 43062306a36Sopenharmony_ci{ 43162306a36Sopenharmony_ci struct snd_soc_component *component = dai->component; 43262306a36Sopenharmony_ci struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component); 43362306a36Sopenharmony_ci int left_slot, right_slot; 43462306a36Sopenharmony_ci int slots_cfg; 43562306a36Sopenharmony_ci int slot_size; 43662306a36Sopenharmony_ci int ret; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci if (tx_mask == 0 || rx_mask != 0) 43962306a36Sopenharmony_ci return -EINVAL; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci left_slot = __ffs(tx_mask); 44262306a36Sopenharmony_ci tx_mask &= ~(1 << left_slot); 44362306a36Sopenharmony_ci if (tx_mask == 0) { 44462306a36Sopenharmony_ci right_slot = left_slot; 44562306a36Sopenharmony_ci } else { 44662306a36Sopenharmony_ci right_slot = __ffs(tx_mask); 44762306a36Sopenharmony_ci tx_mask &= ~(1 << right_slot); 44862306a36Sopenharmony_ci } 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci if (tx_mask != 0 || left_slot >= slots || right_slot >= slots) 45162306a36Sopenharmony_ci return -EINVAL; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci slots_cfg = (right_slot << TAS2764_TDM_CFG3_RXS_SHIFT) | left_slot; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci ret = snd_soc_component_write(component, TAS2764_TDM_CFG3, slots_cfg); 45662306a36Sopenharmony_ci if (ret) 45762306a36Sopenharmony_ci return ret; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci switch (slot_width) { 46062306a36Sopenharmony_ci case 16: 46162306a36Sopenharmony_ci slot_size = TAS2764_TDM_CFG2_RXS_16BITS; 46262306a36Sopenharmony_ci break; 46362306a36Sopenharmony_ci case 24: 46462306a36Sopenharmony_ci slot_size = TAS2764_TDM_CFG2_RXS_24BITS; 46562306a36Sopenharmony_ci break; 46662306a36Sopenharmony_ci case 32: 46762306a36Sopenharmony_ci slot_size = TAS2764_TDM_CFG2_RXS_32BITS; 46862306a36Sopenharmony_ci break; 46962306a36Sopenharmony_ci default: 47062306a36Sopenharmony_ci return -EINVAL; 47162306a36Sopenharmony_ci } 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG2, 47462306a36Sopenharmony_ci TAS2764_TDM_CFG2_RXS_MASK, 47562306a36Sopenharmony_ci slot_size); 47662306a36Sopenharmony_ci if (ret < 0) 47762306a36Sopenharmony_ci return ret; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG5, 48062306a36Sopenharmony_ci TAS2764_TDM_CFG5_50_MASK, 48162306a36Sopenharmony_ci tas2764->v_sense_slot); 48262306a36Sopenharmony_ci if (ret < 0) 48362306a36Sopenharmony_ci return ret; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG6, 48662306a36Sopenharmony_ci TAS2764_TDM_CFG6_50_MASK, 48762306a36Sopenharmony_ci tas2764->i_sense_slot); 48862306a36Sopenharmony_ci if (ret < 0) 48962306a36Sopenharmony_ci return ret; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci return 0; 49262306a36Sopenharmony_ci} 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_cistatic const struct snd_soc_dai_ops tas2764_dai_ops = { 49562306a36Sopenharmony_ci .mute_stream = tas2764_mute, 49662306a36Sopenharmony_ci .hw_params = tas2764_hw_params, 49762306a36Sopenharmony_ci .set_fmt = tas2764_set_fmt, 49862306a36Sopenharmony_ci .set_tdm_slot = tas2764_set_dai_tdm_slot, 49962306a36Sopenharmony_ci .no_capture_mute = 1, 50062306a36Sopenharmony_ci}; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci#define TAS2764_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ 50362306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci#define TAS2764_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\ 50662306a36Sopenharmony_ci SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_88200) 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_cistatic struct snd_soc_dai_driver tas2764_dai_driver[] = { 50962306a36Sopenharmony_ci { 51062306a36Sopenharmony_ci .name = "tas2764 ASI1", 51162306a36Sopenharmony_ci .id = 0, 51262306a36Sopenharmony_ci .playback = { 51362306a36Sopenharmony_ci .stream_name = "ASI1 Playback", 51462306a36Sopenharmony_ci .channels_min = 1, 51562306a36Sopenharmony_ci .channels_max = 2, 51662306a36Sopenharmony_ci .rates = TAS2764_RATES, 51762306a36Sopenharmony_ci .formats = TAS2764_FORMATS, 51862306a36Sopenharmony_ci }, 51962306a36Sopenharmony_ci .capture = { 52062306a36Sopenharmony_ci .stream_name = "ASI1 Capture", 52162306a36Sopenharmony_ci .channels_min = 0, 52262306a36Sopenharmony_ci .channels_max = 2, 52362306a36Sopenharmony_ci .rates = TAS2764_RATES, 52462306a36Sopenharmony_ci .formats = TAS2764_FORMATS, 52562306a36Sopenharmony_ci }, 52662306a36Sopenharmony_ci .ops = &tas2764_dai_ops, 52762306a36Sopenharmony_ci .symmetric_rate = 1, 52862306a36Sopenharmony_ci }, 52962306a36Sopenharmony_ci}; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_cistatic int tas2764_codec_probe(struct snd_soc_component *component) 53262306a36Sopenharmony_ci{ 53362306a36Sopenharmony_ci struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component); 53462306a36Sopenharmony_ci int ret; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci tas2764->component = component; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci if (tas2764->sdz_gpio) { 53962306a36Sopenharmony_ci gpiod_set_value_cansleep(tas2764->sdz_gpio, 1); 54062306a36Sopenharmony_ci usleep_range(1000, 2000); 54162306a36Sopenharmony_ci } 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci tas2764_reset(tas2764); 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci if (tas2764->irq) { 54662306a36Sopenharmony_ci ret = snd_soc_component_write(tas2764->component, TAS2764_INT_MASK0, 0xff); 54762306a36Sopenharmony_ci if (ret < 0) 54862306a36Sopenharmony_ci return ret; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci ret = snd_soc_component_write(tas2764->component, TAS2764_INT_MASK1, 0xff); 55162306a36Sopenharmony_ci if (ret < 0) 55262306a36Sopenharmony_ci return ret; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci ret = snd_soc_component_write(tas2764->component, TAS2764_INT_MASK2, 0xff); 55562306a36Sopenharmony_ci if (ret < 0) 55662306a36Sopenharmony_ci return ret; 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci ret = snd_soc_component_write(tas2764->component, TAS2764_INT_MASK3, 0xff); 55962306a36Sopenharmony_ci if (ret < 0) 56062306a36Sopenharmony_ci return ret; 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci ret = snd_soc_component_write(tas2764->component, TAS2764_INT_MASK4, 0xff); 56362306a36Sopenharmony_ci if (ret < 0) 56462306a36Sopenharmony_ci return ret; 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci ret = devm_request_threaded_irq(tas2764->dev, tas2764->irq, NULL, tas2764_irq, 56762306a36Sopenharmony_ci IRQF_ONESHOT | IRQF_SHARED | IRQF_TRIGGER_LOW, 56862306a36Sopenharmony_ci "tas2764", tas2764); 56962306a36Sopenharmony_ci if (ret) 57062306a36Sopenharmony_ci dev_warn(tas2764->dev, "failed to request IRQ: %d\n", ret); 57162306a36Sopenharmony_ci } 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci ret = snd_soc_component_update_bits(tas2764->component, TAS2764_TDM_CFG5, 57462306a36Sopenharmony_ci TAS2764_TDM_CFG5_VSNS_ENABLE, 0); 57562306a36Sopenharmony_ci if (ret < 0) 57662306a36Sopenharmony_ci return ret; 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci ret = snd_soc_component_update_bits(tas2764->component, TAS2764_TDM_CFG6, 57962306a36Sopenharmony_ci TAS2764_TDM_CFG6_ISNS_ENABLE, 0); 58062306a36Sopenharmony_ci if (ret < 0) 58162306a36Sopenharmony_ci return ret; 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci return 0; 58462306a36Sopenharmony_ci} 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_cistatic DECLARE_TLV_DB_SCALE(tas2764_digital_tlv, 1100, 50, 0); 58762306a36Sopenharmony_cistatic DECLARE_TLV_DB_SCALE(tas2764_playback_volume, -10050, 50, 1); 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_cistatic const char * const tas2764_hpf_texts[] = { 59062306a36Sopenharmony_ci "Disabled", "2 Hz", "50 Hz", "100 Hz", "200 Hz", 59162306a36Sopenharmony_ci "400 Hz", "800 Hz" 59262306a36Sopenharmony_ci}; 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL( 59562306a36Sopenharmony_ci tas2764_hpf_enum, TAS2764_DC_BLK0, 59662306a36Sopenharmony_ci TAS2764_DC_BLK0_HPF_FREQ_PB_SHIFT, tas2764_hpf_texts); 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_cistatic const struct snd_kcontrol_new tas2764_snd_controls[] = { 59962306a36Sopenharmony_ci SOC_SINGLE_TLV("Speaker Volume", TAS2764_DVC, 0, 60062306a36Sopenharmony_ci TAS2764_DVC_MAX, 1, tas2764_playback_volume), 60162306a36Sopenharmony_ci SOC_SINGLE_TLV("Amp Gain Volume", TAS2764_CHNL_0, 1, 0x14, 0, 60262306a36Sopenharmony_ci tas2764_digital_tlv), 60362306a36Sopenharmony_ci SOC_ENUM("HPF Corner Frequency", tas2764_hpf_enum), 60462306a36Sopenharmony_ci}; 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_cistatic const struct snd_soc_component_driver soc_component_driver_tas2764 = { 60762306a36Sopenharmony_ci .probe = tas2764_codec_probe, 60862306a36Sopenharmony_ci .suspend = tas2764_codec_suspend, 60962306a36Sopenharmony_ci .resume = tas2764_codec_resume, 61062306a36Sopenharmony_ci .controls = tas2764_snd_controls, 61162306a36Sopenharmony_ci .num_controls = ARRAY_SIZE(tas2764_snd_controls), 61262306a36Sopenharmony_ci .dapm_widgets = tas2764_dapm_widgets, 61362306a36Sopenharmony_ci .num_dapm_widgets = ARRAY_SIZE(tas2764_dapm_widgets), 61462306a36Sopenharmony_ci .dapm_routes = tas2764_audio_map, 61562306a36Sopenharmony_ci .num_dapm_routes = ARRAY_SIZE(tas2764_audio_map), 61662306a36Sopenharmony_ci .idle_bias_on = 1, 61762306a36Sopenharmony_ci .endianness = 1, 61862306a36Sopenharmony_ci}; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_cistatic const struct reg_default tas2764_reg_defaults[] = { 62162306a36Sopenharmony_ci { TAS2764_PAGE, 0x00 }, 62262306a36Sopenharmony_ci { TAS2764_SW_RST, 0x00 }, 62362306a36Sopenharmony_ci { TAS2764_PWR_CTRL, 0x1a }, 62462306a36Sopenharmony_ci { TAS2764_DVC, 0x00 }, 62562306a36Sopenharmony_ci { TAS2764_CHNL_0, 0x28 }, 62662306a36Sopenharmony_ci { TAS2764_TDM_CFG0, 0x09 }, 62762306a36Sopenharmony_ci { TAS2764_TDM_CFG1, 0x02 }, 62862306a36Sopenharmony_ci { TAS2764_TDM_CFG2, 0x0a }, 62962306a36Sopenharmony_ci { TAS2764_TDM_CFG3, 0x10 }, 63062306a36Sopenharmony_ci { TAS2764_TDM_CFG5, 0x42 }, 63162306a36Sopenharmony_ci}; 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_cistatic const struct regmap_range_cfg tas2764_regmap_ranges[] = { 63462306a36Sopenharmony_ci { 63562306a36Sopenharmony_ci .range_min = 0, 63662306a36Sopenharmony_ci .range_max = 1 * 128, 63762306a36Sopenharmony_ci .selector_reg = TAS2764_PAGE, 63862306a36Sopenharmony_ci .selector_mask = 0xff, 63962306a36Sopenharmony_ci .selector_shift = 0, 64062306a36Sopenharmony_ci .window_start = 0, 64162306a36Sopenharmony_ci .window_len = 128, 64262306a36Sopenharmony_ci }, 64362306a36Sopenharmony_ci}; 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_cistatic bool tas2764_volatile_register(struct device *dev, unsigned int reg) 64662306a36Sopenharmony_ci{ 64762306a36Sopenharmony_ci switch (reg) { 64862306a36Sopenharmony_ci case TAS2764_INT_LTCH0 ... TAS2764_INT_LTCH4: 64962306a36Sopenharmony_ci case TAS2764_INT_CLK_CFG: 65062306a36Sopenharmony_ci return true; 65162306a36Sopenharmony_ci default: 65262306a36Sopenharmony_ci return false; 65362306a36Sopenharmony_ci } 65462306a36Sopenharmony_ci} 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_cistatic const struct regmap_config tas2764_i2c_regmap = { 65762306a36Sopenharmony_ci .reg_bits = 8, 65862306a36Sopenharmony_ci .val_bits = 8, 65962306a36Sopenharmony_ci .volatile_reg = tas2764_volatile_register, 66062306a36Sopenharmony_ci .reg_defaults = tas2764_reg_defaults, 66162306a36Sopenharmony_ci .num_reg_defaults = ARRAY_SIZE(tas2764_reg_defaults), 66262306a36Sopenharmony_ci .cache_type = REGCACHE_RBTREE, 66362306a36Sopenharmony_ci .ranges = tas2764_regmap_ranges, 66462306a36Sopenharmony_ci .num_ranges = ARRAY_SIZE(tas2764_regmap_ranges), 66562306a36Sopenharmony_ci .max_register = 1 * 128, 66662306a36Sopenharmony_ci}; 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_cistatic int tas2764_parse_dt(struct device *dev, struct tas2764_priv *tas2764) 66962306a36Sopenharmony_ci{ 67062306a36Sopenharmony_ci int ret = 0; 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci tas2764->reset_gpio = devm_gpiod_get_optional(tas2764->dev, "reset", 67362306a36Sopenharmony_ci GPIOD_OUT_HIGH); 67462306a36Sopenharmony_ci if (IS_ERR(tas2764->reset_gpio)) { 67562306a36Sopenharmony_ci if (PTR_ERR(tas2764->reset_gpio) == -EPROBE_DEFER) { 67662306a36Sopenharmony_ci tas2764->reset_gpio = NULL; 67762306a36Sopenharmony_ci return -EPROBE_DEFER; 67862306a36Sopenharmony_ci } 67962306a36Sopenharmony_ci } 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci tas2764->sdz_gpio = devm_gpiod_get_optional(dev, "shutdown", GPIOD_OUT_HIGH); 68262306a36Sopenharmony_ci if (IS_ERR(tas2764->sdz_gpio)) { 68362306a36Sopenharmony_ci if (PTR_ERR(tas2764->sdz_gpio) == -EPROBE_DEFER) 68462306a36Sopenharmony_ci return -EPROBE_DEFER; 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci tas2764->sdz_gpio = NULL; 68762306a36Sopenharmony_ci } 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci ret = fwnode_property_read_u32(dev->fwnode, "ti,imon-slot-no", 69062306a36Sopenharmony_ci &tas2764->i_sense_slot); 69162306a36Sopenharmony_ci if (ret) 69262306a36Sopenharmony_ci tas2764->i_sense_slot = 0; 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci ret = fwnode_property_read_u32(dev->fwnode, "ti,vmon-slot-no", 69562306a36Sopenharmony_ci &tas2764->v_sense_slot); 69662306a36Sopenharmony_ci if (ret) 69762306a36Sopenharmony_ci tas2764->v_sense_slot = 2; 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci return 0; 70062306a36Sopenharmony_ci} 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_cistatic int tas2764_i2c_probe(struct i2c_client *client) 70362306a36Sopenharmony_ci{ 70462306a36Sopenharmony_ci struct tas2764_priv *tas2764; 70562306a36Sopenharmony_ci int result; 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci tas2764 = devm_kzalloc(&client->dev, sizeof(struct tas2764_priv), 70862306a36Sopenharmony_ci GFP_KERNEL); 70962306a36Sopenharmony_ci if (!tas2764) 71062306a36Sopenharmony_ci return -ENOMEM; 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci tas2764->dev = &client->dev; 71362306a36Sopenharmony_ci tas2764->irq = client->irq; 71462306a36Sopenharmony_ci i2c_set_clientdata(client, tas2764); 71562306a36Sopenharmony_ci dev_set_drvdata(&client->dev, tas2764); 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci tas2764->regmap = devm_regmap_init_i2c(client, &tas2764_i2c_regmap); 71862306a36Sopenharmony_ci if (IS_ERR(tas2764->regmap)) { 71962306a36Sopenharmony_ci result = PTR_ERR(tas2764->regmap); 72062306a36Sopenharmony_ci dev_err(&client->dev, "Failed to allocate register map: %d\n", 72162306a36Sopenharmony_ci result); 72262306a36Sopenharmony_ci return result; 72362306a36Sopenharmony_ci } 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci if (client->dev.of_node) { 72662306a36Sopenharmony_ci result = tas2764_parse_dt(&client->dev, tas2764); 72762306a36Sopenharmony_ci if (result) { 72862306a36Sopenharmony_ci dev_err(tas2764->dev, "%s: Failed to parse devicetree\n", 72962306a36Sopenharmony_ci __func__); 73062306a36Sopenharmony_ci return result; 73162306a36Sopenharmony_ci } 73262306a36Sopenharmony_ci } 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci return devm_snd_soc_register_component(tas2764->dev, 73562306a36Sopenharmony_ci &soc_component_driver_tas2764, 73662306a36Sopenharmony_ci tas2764_dai_driver, 73762306a36Sopenharmony_ci ARRAY_SIZE(tas2764_dai_driver)); 73862306a36Sopenharmony_ci} 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_cistatic const struct i2c_device_id tas2764_i2c_id[] = { 74162306a36Sopenharmony_ci { "tas2764", 0}, 74262306a36Sopenharmony_ci { } 74362306a36Sopenharmony_ci}; 74462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, tas2764_i2c_id); 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci#if defined(CONFIG_OF) 74762306a36Sopenharmony_cistatic const struct of_device_id tas2764_of_match[] = { 74862306a36Sopenharmony_ci { .compatible = "ti,tas2764" }, 74962306a36Sopenharmony_ci {}, 75062306a36Sopenharmony_ci}; 75162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, tas2764_of_match); 75262306a36Sopenharmony_ci#endif 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_cistatic struct i2c_driver tas2764_i2c_driver = { 75562306a36Sopenharmony_ci .driver = { 75662306a36Sopenharmony_ci .name = "tas2764", 75762306a36Sopenharmony_ci .of_match_table = of_match_ptr(tas2764_of_match), 75862306a36Sopenharmony_ci }, 75962306a36Sopenharmony_ci .probe = tas2764_i2c_probe, 76062306a36Sopenharmony_ci .id_table = tas2764_i2c_id, 76162306a36Sopenharmony_ci}; 76262306a36Sopenharmony_cimodule_i2c_driver(tas2764_i2c_driver); 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ciMODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>"); 76562306a36Sopenharmony_ciMODULE_DESCRIPTION("TAS2764 I2C Smart Amplifier driver"); 76662306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 767