162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci// Driver for the Texas Instruments TAS2780 Mono 362306a36Sopenharmony_ci// Audio amplifier 462306a36Sopenharmony_ci// Copyright (C) 2022 Texas Instruments Inc. 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/module.h> 762306a36Sopenharmony_ci#include <linux/err.h> 862306a36Sopenharmony_ci#include <linux/pm.h> 962306a36Sopenharmony_ci#include <linux/i2c.h> 1062306a36Sopenharmony_ci#include <linux/gpio.h> 1162306a36Sopenharmony_ci#include <linux/gpio/consumer.h> 1262306a36Sopenharmony_ci#include <linux/regmap.h> 1362306a36Sopenharmony_ci#include <linux/of.h> 1462306a36Sopenharmony_ci#include <linux/of_gpio.h> 1562306a36Sopenharmony_ci#include <sound/soc.h> 1662306a36Sopenharmony_ci#include <sound/pcm.h> 1762306a36Sopenharmony_ci#include <sound/pcm_params.h> 1862306a36Sopenharmony_ci#include <sound/tlv.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include "tas2780.h" 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cistruct tas2780_priv { 2362306a36Sopenharmony_ci struct snd_soc_component *component; 2462306a36Sopenharmony_ci struct gpio_desc *reset_gpio; 2562306a36Sopenharmony_ci struct regmap *regmap; 2662306a36Sopenharmony_ci struct device *dev; 2762306a36Sopenharmony_ci int v_sense_slot; 2862306a36Sopenharmony_ci int i_sense_slot; 2962306a36Sopenharmony_ci}; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic void tas2780_reset(struct tas2780_priv *tas2780) 3262306a36Sopenharmony_ci{ 3362306a36Sopenharmony_ci int ret = 0; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci if (tas2780->reset_gpio) { 3662306a36Sopenharmony_ci gpiod_set_value_cansleep(tas2780->reset_gpio, 0); 3762306a36Sopenharmony_ci usleep_range(2000, 2050); 3862306a36Sopenharmony_ci gpiod_set_value_cansleep(tas2780->reset_gpio, 1); 3962306a36Sopenharmony_ci usleep_range(2000, 2050); 4062306a36Sopenharmony_ci } 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci ret = snd_soc_component_write(tas2780->component, TAS2780_SW_RST, 4362306a36Sopenharmony_ci TAS2780_RST); 4462306a36Sopenharmony_ci if (ret) 4562306a36Sopenharmony_ci dev_err(tas2780->dev, "%s:errCode:0x%x Reset error!\n", 4662306a36Sopenharmony_ci __func__, ret); 4762306a36Sopenharmony_ci} 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci#ifdef CONFIG_PM 5062306a36Sopenharmony_cistatic int tas2780_codec_suspend(struct snd_soc_component *component) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci struct tas2780_priv *tas2780 = 5362306a36Sopenharmony_ci snd_soc_component_get_drvdata(component); 5462306a36Sopenharmony_ci int ret = 0; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci ret = snd_soc_component_update_bits(component, TAS2780_PWR_CTRL, 5762306a36Sopenharmony_ci TAS2780_PWR_CTRL_MASK, TAS2780_PWR_CTRL_SHUTDOWN); 5862306a36Sopenharmony_ci if (ret < 0) { 5962306a36Sopenharmony_ci dev_err(tas2780->dev, "%s:errCode:0x%0x:power down error\n", 6062306a36Sopenharmony_ci __func__, ret); 6162306a36Sopenharmony_ci goto err; 6262306a36Sopenharmony_ci } 6362306a36Sopenharmony_ci ret = 0; 6462306a36Sopenharmony_ci regcache_cache_only(tas2780->regmap, true); 6562306a36Sopenharmony_ci regcache_mark_dirty(tas2780->regmap); 6662306a36Sopenharmony_cierr: 6762306a36Sopenharmony_ci return ret; 6862306a36Sopenharmony_ci} 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistatic int tas2780_codec_resume(struct snd_soc_component *component) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci struct tas2780_priv *tas2780 = 7362306a36Sopenharmony_ci snd_soc_component_get_drvdata(component); 7462306a36Sopenharmony_ci int ret = 0; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci ret = snd_soc_component_update_bits(component, TAS2780_PWR_CTRL, 7762306a36Sopenharmony_ci TAS2780_PWR_CTRL_MASK, TAS2780_PWR_CTRL_ACTIVE); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci if (ret < 0) { 8062306a36Sopenharmony_ci dev_err(tas2780->dev, "%s:errCode:0x%0x:power down error\n", 8162306a36Sopenharmony_ci __func__, ret); 8262306a36Sopenharmony_ci goto err; 8362306a36Sopenharmony_ci } 8462306a36Sopenharmony_ci ret = 0; 8562306a36Sopenharmony_ci regcache_cache_only(tas2780->regmap, false); 8662306a36Sopenharmony_ci ret = regcache_sync(tas2780->regmap); 8762306a36Sopenharmony_cierr: 8862306a36Sopenharmony_ci return ret; 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci#endif 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistatic const char * const tas2780_ASI1_src[] = { 9362306a36Sopenharmony_ci "I2C offset", "Left", "Right", "LeftRightDiv2", 9462306a36Sopenharmony_ci}; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL( 9762306a36Sopenharmony_ci tas2780_ASI1_src_enum, TAS2780_TDM_CFG2, 4, tas2780_ASI1_src); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cistatic const struct snd_kcontrol_new tas2780_asi1_mux = 10062306a36Sopenharmony_ci SOC_DAPM_ENUM("ASI1 Source", tas2780_ASI1_src_enum); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cistatic const struct snd_kcontrol_new isense_switch = 10362306a36Sopenharmony_ci SOC_DAPM_SINGLE("Switch", TAS2780_PWR_CTRL, 10462306a36Sopenharmony_ci TAS2780_ISENSE_POWER_EN, 1, 1); 10562306a36Sopenharmony_cistatic const struct snd_kcontrol_new vsense_switch = 10662306a36Sopenharmony_ci SOC_DAPM_SINGLE("Switch", TAS2780_PWR_CTRL, 10762306a36Sopenharmony_ci TAS2780_VSENSE_POWER_EN, 1, 1); 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic const struct snd_soc_dapm_widget tas2780_dapm_widgets[] = { 11062306a36Sopenharmony_ci SND_SOC_DAPM_AIF_IN("ASI1", "ASI1 Playback", 0, SND_SOC_NOPM, 0, 0), 11162306a36Sopenharmony_ci SND_SOC_DAPM_MUX("ASI1 Sel", SND_SOC_NOPM, 0, 0, &tas2780_asi1_mux), 11262306a36Sopenharmony_ci SND_SOC_DAPM_SWITCH("ISENSE", TAS2780_PWR_CTRL, 11362306a36Sopenharmony_ci TAS2780_ISENSE_POWER_EN, 1, &isense_switch), 11462306a36Sopenharmony_ci SND_SOC_DAPM_SWITCH("VSENSE", TAS2780_PWR_CTRL, 11562306a36Sopenharmony_ci TAS2780_VSENSE_POWER_EN, 1, &vsense_switch), 11662306a36Sopenharmony_ci SND_SOC_DAPM_OUTPUT("OUT"), 11762306a36Sopenharmony_ci SND_SOC_DAPM_SIGGEN("VMON"), 11862306a36Sopenharmony_ci SND_SOC_DAPM_SIGGEN("IMON") 11962306a36Sopenharmony_ci}; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_cistatic const struct snd_soc_dapm_route tas2780_audio_map[] = { 12262306a36Sopenharmony_ci {"ASI1 Sel", "I2C offset", "ASI1"}, 12362306a36Sopenharmony_ci {"ASI1 Sel", "Left", "ASI1"}, 12462306a36Sopenharmony_ci {"ASI1 Sel", "Right", "ASI1"}, 12562306a36Sopenharmony_ci {"ASI1 Sel", "LeftRightDiv2", "ASI1"}, 12662306a36Sopenharmony_ci {"OUT", NULL, "ASI1 Sel"}, 12762306a36Sopenharmony_ci {"ISENSE", "Switch", "IMON"}, 12862306a36Sopenharmony_ci {"VSENSE", "Switch", "VMON"}, 12962306a36Sopenharmony_ci}; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_cistatic int tas2780_mute(struct snd_soc_dai *dai, int mute, int direction) 13262306a36Sopenharmony_ci{ 13362306a36Sopenharmony_ci struct snd_soc_component *component = dai->component; 13462306a36Sopenharmony_ci struct tas2780_priv *tas2780 = 13562306a36Sopenharmony_ci snd_soc_component_get_drvdata(component); 13662306a36Sopenharmony_ci int ret = 0; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci ret = snd_soc_component_update_bits(component, TAS2780_PWR_CTRL, 13962306a36Sopenharmony_ci TAS2780_PWR_CTRL_MASK, 14062306a36Sopenharmony_ci mute ? TAS2780_PWR_CTRL_MUTE : 0); 14162306a36Sopenharmony_ci if (ret < 0) { 14262306a36Sopenharmony_ci dev_err(tas2780->dev, "%s: Failed to set powercontrol\n", 14362306a36Sopenharmony_ci __func__); 14462306a36Sopenharmony_ci goto err; 14562306a36Sopenharmony_ci } 14662306a36Sopenharmony_ci ret = 0; 14762306a36Sopenharmony_cierr: 14862306a36Sopenharmony_ci return ret; 14962306a36Sopenharmony_ci} 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_cistatic int tas2780_set_bitwidth(struct tas2780_priv *tas2780, int bitwidth) 15262306a36Sopenharmony_ci{ 15362306a36Sopenharmony_ci struct snd_soc_component *component = tas2780->component; 15462306a36Sopenharmony_ci int sense_en; 15562306a36Sopenharmony_ci int val; 15662306a36Sopenharmony_ci int ret; 15762306a36Sopenharmony_ci int slot_size; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci switch (bitwidth) { 16062306a36Sopenharmony_ci case SNDRV_PCM_FORMAT_S16_LE: 16162306a36Sopenharmony_ci ret = snd_soc_component_update_bits(component, 16262306a36Sopenharmony_ci TAS2780_TDM_CFG2, 16362306a36Sopenharmony_ci TAS2780_TDM_CFG2_RXW_MASK, 16462306a36Sopenharmony_ci TAS2780_TDM_CFG2_RXW_16BITS); 16562306a36Sopenharmony_ci slot_size = TAS2780_TDM_CFG2_RXS_16BITS; 16662306a36Sopenharmony_ci break; 16762306a36Sopenharmony_ci case SNDRV_PCM_FORMAT_S24_LE: 16862306a36Sopenharmony_ci ret = snd_soc_component_update_bits(component, 16962306a36Sopenharmony_ci TAS2780_TDM_CFG2, 17062306a36Sopenharmony_ci TAS2780_TDM_CFG2_RXW_MASK, 17162306a36Sopenharmony_ci TAS2780_TDM_CFG2_RXW_24BITS); 17262306a36Sopenharmony_ci slot_size = TAS2780_TDM_CFG2_RXS_24BITS; 17362306a36Sopenharmony_ci break; 17462306a36Sopenharmony_ci case SNDRV_PCM_FORMAT_S32_LE: 17562306a36Sopenharmony_ci ret = snd_soc_component_update_bits(component, 17662306a36Sopenharmony_ci TAS2780_TDM_CFG2, 17762306a36Sopenharmony_ci TAS2780_TDM_CFG2_RXW_MASK, 17862306a36Sopenharmony_ci TAS2780_TDM_CFG2_RXW_32BITS); 17962306a36Sopenharmony_ci slot_size = TAS2780_TDM_CFG2_RXS_32BITS; 18062306a36Sopenharmony_ci break; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci default: 18362306a36Sopenharmony_ci ret = -EINVAL; 18462306a36Sopenharmony_ci } 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci if (ret < 0) { 18762306a36Sopenharmony_ci dev_err(tas2780->dev, "%s:errCode:0x%x set bitwidth error\n", 18862306a36Sopenharmony_ci __func__, ret); 18962306a36Sopenharmony_ci goto err; 19062306a36Sopenharmony_ci } 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci ret = snd_soc_component_update_bits(component, TAS2780_TDM_CFG2, 19362306a36Sopenharmony_ci TAS2780_TDM_CFG2_RXS_MASK, slot_size); 19462306a36Sopenharmony_ci if (ret < 0) { 19562306a36Sopenharmony_ci dev_err(tas2780->dev, 19662306a36Sopenharmony_ci "%s:errCode:0x%x set RX slot size error\n", 19762306a36Sopenharmony_ci __func__, ret); 19862306a36Sopenharmony_ci goto err; 19962306a36Sopenharmony_ci } 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci val = snd_soc_component_read(tas2780->component, TAS2780_PWR_CTRL); 20262306a36Sopenharmony_ci if (val < 0) { 20362306a36Sopenharmony_ci dev_err(tas2780->dev, "%s:errCode:0x%x read PWR_CTRL error\n", 20462306a36Sopenharmony_ci __func__, val); 20562306a36Sopenharmony_ci ret = val; 20662306a36Sopenharmony_ci goto err; 20762306a36Sopenharmony_ci } 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci if (val & (1 << TAS2780_VSENSE_POWER_EN)) 21062306a36Sopenharmony_ci sense_en = 0; 21162306a36Sopenharmony_ci else 21262306a36Sopenharmony_ci sense_en = TAS2780_TDM_CFG5_VSNS_ENABLE; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci ret = snd_soc_component_update_bits(tas2780->component, 21562306a36Sopenharmony_ci TAS2780_TDM_CFG5, TAS2780_TDM_CFG5_VSNS_ENABLE, sense_en); 21662306a36Sopenharmony_ci if (ret < 0) { 21762306a36Sopenharmony_ci dev_err(tas2780->dev, "%s:errCode:0x%x enable vSNS error\n", 21862306a36Sopenharmony_ci __func__, ret); 21962306a36Sopenharmony_ci goto err; 22062306a36Sopenharmony_ci } 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci if (val & (1 << TAS2780_ISENSE_POWER_EN)) 22362306a36Sopenharmony_ci sense_en = 0; 22462306a36Sopenharmony_ci else 22562306a36Sopenharmony_ci sense_en = TAS2780_TDM_CFG6_ISNS_ENABLE; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci ret = snd_soc_component_update_bits(tas2780->component, 22862306a36Sopenharmony_ci TAS2780_TDM_CFG6, TAS2780_TDM_CFG6_ISNS_ENABLE, sense_en); 22962306a36Sopenharmony_ci if (ret < 0) { 23062306a36Sopenharmony_ci dev_err(tas2780->dev, "%s:errCode:0x%x enable iSNS error\n", 23162306a36Sopenharmony_ci __func__, ret); 23262306a36Sopenharmony_ci goto err; 23362306a36Sopenharmony_ci } 23462306a36Sopenharmony_ci ret = 0; 23562306a36Sopenharmony_cierr: 23662306a36Sopenharmony_ci return ret; 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_cistatic int tas2780_set_samplerate( 24062306a36Sopenharmony_ci struct tas2780_priv *tas2780, int samplerate) 24162306a36Sopenharmony_ci{ 24262306a36Sopenharmony_ci struct snd_soc_component *component = tas2780->component; 24362306a36Sopenharmony_ci int ramp_rate_val; 24462306a36Sopenharmony_ci int ret; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci switch (samplerate) { 24762306a36Sopenharmony_ci case 48000: 24862306a36Sopenharmony_ci ramp_rate_val = TAS2780_TDM_CFG0_SMP_48KHZ | 24962306a36Sopenharmony_ci TAS2780_TDM_CFG0_44_1_48KHZ; 25062306a36Sopenharmony_ci break; 25162306a36Sopenharmony_ci case 44100: 25262306a36Sopenharmony_ci ramp_rate_val = TAS2780_TDM_CFG0_SMP_44_1KHZ | 25362306a36Sopenharmony_ci TAS2780_TDM_CFG0_44_1_48KHZ; 25462306a36Sopenharmony_ci break; 25562306a36Sopenharmony_ci case 96000: 25662306a36Sopenharmony_ci ramp_rate_val = TAS2780_TDM_CFG0_SMP_48KHZ | 25762306a36Sopenharmony_ci TAS2780_TDM_CFG0_88_2_96KHZ; 25862306a36Sopenharmony_ci break; 25962306a36Sopenharmony_ci case 88200: 26062306a36Sopenharmony_ci ramp_rate_val = TAS2780_TDM_CFG0_SMP_44_1KHZ | 26162306a36Sopenharmony_ci TAS2780_TDM_CFG0_88_2_96KHZ; 26262306a36Sopenharmony_ci break; 26362306a36Sopenharmony_ci default: 26462306a36Sopenharmony_ci return -EINVAL; 26562306a36Sopenharmony_ci } 26662306a36Sopenharmony_ci ret = snd_soc_component_update_bits(component, TAS2780_TDM_CFG0, 26762306a36Sopenharmony_ci TAS2780_TDM_CFG0_SMP_MASK | TAS2780_TDM_CFG0_MASK, 26862306a36Sopenharmony_ci ramp_rate_val); 26962306a36Sopenharmony_ci if (ret < 0) { 27062306a36Sopenharmony_ci dev_err(tas2780->dev, 27162306a36Sopenharmony_ci "%s:errCode:0x%x Failed to set ramp_rate_val\n", 27262306a36Sopenharmony_ci __func__, ret); 27362306a36Sopenharmony_ci goto err; 27462306a36Sopenharmony_ci } 27562306a36Sopenharmony_ci ret = 0; 27662306a36Sopenharmony_cierr: 27762306a36Sopenharmony_ci return ret; 27862306a36Sopenharmony_ci} 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_cistatic int tas2780_hw_params(struct snd_pcm_substream *substream, 28162306a36Sopenharmony_ci struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) 28262306a36Sopenharmony_ci{ 28362306a36Sopenharmony_ci struct snd_soc_component *component = dai->component; 28462306a36Sopenharmony_ci struct tas2780_priv *tas2780 = 28562306a36Sopenharmony_ci snd_soc_component_get_drvdata(component); 28662306a36Sopenharmony_ci int ret; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci ret = tas2780_set_bitwidth(tas2780, params_format(params)); 28962306a36Sopenharmony_ci if (ret < 0) 29062306a36Sopenharmony_ci return ret; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci return tas2780_set_samplerate(tas2780, params_rate(params)); 29362306a36Sopenharmony_ci} 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_cistatic int tas2780_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) 29662306a36Sopenharmony_ci{ 29762306a36Sopenharmony_ci struct snd_soc_component *component = dai->component; 29862306a36Sopenharmony_ci struct tas2780_priv *tas2780 = 29962306a36Sopenharmony_ci snd_soc_component_get_drvdata(component); 30062306a36Sopenharmony_ci u8 tdm_rx_start_slot = 0, asi_cfg_1 = 0; 30162306a36Sopenharmony_ci int iface; 30262306a36Sopenharmony_ci int ret = 0; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 30562306a36Sopenharmony_ci case SND_SOC_DAIFMT_NB_NF: 30662306a36Sopenharmony_ci asi_cfg_1 = TAS2780_TDM_CFG1_RX_RISING; 30762306a36Sopenharmony_ci break; 30862306a36Sopenharmony_ci case SND_SOC_DAIFMT_IB_NF: 30962306a36Sopenharmony_ci asi_cfg_1 = TAS2780_TDM_CFG1_RX_FALLING; 31062306a36Sopenharmony_ci break; 31162306a36Sopenharmony_ci default: 31262306a36Sopenharmony_ci dev_err(tas2780->dev, "ASI format Inverse is not found\n"); 31362306a36Sopenharmony_ci return -EINVAL; 31462306a36Sopenharmony_ci } 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci ret = snd_soc_component_update_bits(component, TAS2780_TDM_CFG1, 31762306a36Sopenharmony_ci TAS2780_TDM_CFG1_RX_MASK, asi_cfg_1); 31862306a36Sopenharmony_ci if (ret < 0) { 31962306a36Sopenharmony_ci dev_err(tas2780->dev, 32062306a36Sopenharmony_ci "%s:errCode:0x%x Failed to set asi_cfg_1\n", 32162306a36Sopenharmony_ci __func__, ret); 32262306a36Sopenharmony_ci goto err; 32362306a36Sopenharmony_ci } 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci if (((fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S) 32662306a36Sopenharmony_ci || ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) 32762306a36Sopenharmony_ci == SND_SOC_DAIFMT_DSP_A)){ 32862306a36Sopenharmony_ci iface = TAS2780_TDM_CFG2_SCFG_I2S; 32962306a36Sopenharmony_ci tdm_rx_start_slot = 1; 33062306a36Sopenharmony_ci } else { 33162306a36Sopenharmony_ci if (((fmt & SND_SOC_DAIFMT_FORMAT_MASK) 33262306a36Sopenharmony_ci == SND_SOC_DAIFMT_DSP_B) 33362306a36Sopenharmony_ci || ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) 33462306a36Sopenharmony_ci == SND_SOC_DAIFMT_LEFT_J)) { 33562306a36Sopenharmony_ci iface = TAS2780_TDM_CFG2_SCFG_LEFT_J; 33662306a36Sopenharmony_ci tdm_rx_start_slot = 0; 33762306a36Sopenharmony_ci } else { 33862306a36Sopenharmony_ci dev_err(tas2780->dev, 33962306a36Sopenharmony_ci "%s:DAI Format is not found, fmt=0x%x\n", 34062306a36Sopenharmony_ci __func__, fmt); 34162306a36Sopenharmony_ci ret = -EINVAL; 34262306a36Sopenharmony_ci goto err; 34362306a36Sopenharmony_ci } 34462306a36Sopenharmony_ci } 34562306a36Sopenharmony_ci ret = snd_soc_component_update_bits(component, TAS2780_TDM_CFG1, 34662306a36Sopenharmony_ci TAS2780_TDM_CFG1_MASK, 34762306a36Sopenharmony_ci (tdm_rx_start_slot << TAS2780_TDM_CFG1_51_SHIFT)); 34862306a36Sopenharmony_ci if (ret < 0) { 34962306a36Sopenharmony_ci dev_err(tas2780->dev, 35062306a36Sopenharmony_ci "%s:errCode:0x%x Failed to set tdm_rx_start_slot\n", 35162306a36Sopenharmony_ci __func__, ret); 35262306a36Sopenharmony_ci goto err; 35362306a36Sopenharmony_ci } 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci ret = snd_soc_component_update_bits(component, TAS2780_TDM_CFG2, 35662306a36Sopenharmony_ci TAS2780_TDM_CFG2_SCFG_MASK, iface); 35762306a36Sopenharmony_ci if (ret < 0) { 35862306a36Sopenharmony_ci dev_err(tas2780->dev, "%s:errCode:0x%x Failed to set iface\n", 35962306a36Sopenharmony_ci __func__, ret); 36062306a36Sopenharmony_ci goto err; 36162306a36Sopenharmony_ci } 36262306a36Sopenharmony_ci ret = 0; 36362306a36Sopenharmony_cierr: 36462306a36Sopenharmony_ci return ret; 36562306a36Sopenharmony_ci} 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_cistatic int tas2780_set_dai_tdm_slot(struct snd_soc_dai *dai, 36862306a36Sopenharmony_ci unsigned int tx_mask, 36962306a36Sopenharmony_ci unsigned int rx_mask, 37062306a36Sopenharmony_ci int slots, int slot_width) 37162306a36Sopenharmony_ci{ 37262306a36Sopenharmony_ci struct snd_soc_component *component = dai->component; 37362306a36Sopenharmony_ci struct tas2780_priv *tas2780 = 37462306a36Sopenharmony_ci snd_soc_component_get_drvdata(component); 37562306a36Sopenharmony_ci int left_slot, right_slot; 37662306a36Sopenharmony_ci int slots_cfg; 37762306a36Sopenharmony_ci int slot_size; 37862306a36Sopenharmony_ci int ret = 0; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci if (tx_mask == 0 || rx_mask != 0) 38162306a36Sopenharmony_ci return -EINVAL; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci left_slot = __ffs(tx_mask); 38462306a36Sopenharmony_ci tx_mask &= ~(1 << left_slot); 38562306a36Sopenharmony_ci if (tx_mask == 0) { 38662306a36Sopenharmony_ci right_slot = left_slot; 38762306a36Sopenharmony_ci } else { 38862306a36Sopenharmony_ci right_slot = __ffs(tx_mask); 38962306a36Sopenharmony_ci tx_mask &= ~(1 << right_slot); 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci if (tx_mask != 0 || left_slot >= slots || right_slot >= slots) 39362306a36Sopenharmony_ci return -EINVAL; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci slots_cfg = (right_slot << TAS2780_TDM_CFG3_RXS_SHIFT) | left_slot; 39662306a36Sopenharmony_ci ret = snd_soc_component_write(component, TAS2780_TDM_CFG3, slots_cfg); 39762306a36Sopenharmony_ci if (ret) { 39862306a36Sopenharmony_ci dev_err(tas2780->dev, 39962306a36Sopenharmony_ci "%s:errCode:0x%x Failed to set slots_cfg\n", 40062306a36Sopenharmony_ci __func__, ret); 40162306a36Sopenharmony_ci goto err; 40262306a36Sopenharmony_ci } 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci switch (slot_width) { 40562306a36Sopenharmony_ci case 16: 40662306a36Sopenharmony_ci slot_size = TAS2780_TDM_CFG2_RXS_16BITS; 40762306a36Sopenharmony_ci break; 40862306a36Sopenharmony_ci case 24: 40962306a36Sopenharmony_ci slot_size = TAS2780_TDM_CFG2_RXS_24BITS; 41062306a36Sopenharmony_ci break; 41162306a36Sopenharmony_ci case 32: 41262306a36Sopenharmony_ci slot_size = TAS2780_TDM_CFG2_RXS_32BITS; 41362306a36Sopenharmony_ci break; 41462306a36Sopenharmony_ci default: 41562306a36Sopenharmony_ci ret = -EINVAL; 41662306a36Sopenharmony_ci goto err; 41762306a36Sopenharmony_ci } 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci ret = snd_soc_component_update_bits(component, TAS2780_TDM_CFG2, 42062306a36Sopenharmony_ci TAS2780_TDM_CFG2_RXS_MASK, slot_size); 42162306a36Sopenharmony_ci if (ret < 0) { 42262306a36Sopenharmony_ci dev_err(tas2780->dev, 42362306a36Sopenharmony_ci "%s:errCode:0x%x Failed to set slot_size\n", 42462306a36Sopenharmony_ci __func__, ret); 42562306a36Sopenharmony_ci goto err; 42662306a36Sopenharmony_ci } 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci ret = snd_soc_component_update_bits(component, TAS2780_TDM_CFG5, 42962306a36Sopenharmony_ci TAS2780_TDM_CFG5_50_MASK, tas2780->v_sense_slot); 43062306a36Sopenharmony_ci if (ret < 0) { 43162306a36Sopenharmony_ci dev_err(tas2780->dev, 43262306a36Sopenharmony_ci "%s:errCode:0x%x Failed to set v_sense_slot\n", 43362306a36Sopenharmony_ci __func__, ret); 43462306a36Sopenharmony_ci goto err; 43562306a36Sopenharmony_ci } 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci ret = snd_soc_component_update_bits(component, TAS2780_TDM_CFG6, 43862306a36Sopenharmony_ci TAS2780_TDM_CFG6_50_MASK, tas2780->i_sense_slot); 43962306a36Sopenharmony_ci if (ret < 0) { 44062306a36Sopenharmony_ci dev_err(tas2780->dev, 44162306a36Sopenharmony_ci "%s:errCode:0x%x Failed to set i_sense_slot\n", 44262306a36Sopenharmony_ci __func__, ret); 44362306a36Sopenharmony_ci goto err; 44462306a36Sopenharmony_ci } 44562306a36Sopenharmony_ci ret = 0; 44662306a36Sopenharmony_cierr: 44762306a36Sopenharmony_ci return ret; 44862306a36Sopenharmony_ci} 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_cistatic const struct snd_soc_dai_ops tas2780_dai_ops = { 45162306a36Sopenharmony_ci .mute_stream = tas2780_mute, 45262306a36Sopenharmony_ci .hw_params = tas2780_hw_params, 45362306a36Sopenharmony_ci .set_fmt = tas2780_set_fmt, 45462306a36Sopenharmony_ci .set_tdm_slot = tas2780_set_dai_tdm_slot, 45562306a36Sopenharmony_ci .no_capture_mute = 1, 45662306a36Sopenharmony_ci}; 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci#define TAS2780_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ 45962306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci#define TAS2780_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\ 46262306a36Sopenharmony_ci SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_88200) 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_cistatic struct snd_soc_dai_driver tas2780_dai_driver[] = { 46562306a36Sopenharmony_ci { 46662306a36Sopenharmony_ci .name = "tas2780 ASI1", 46762306a36Sopenharmony_ci .id = 0, 46862306a36Sopenharmony_ci .playback = { 46962306a36Sopenharmony_ci .stream_name = "ASI1 Playback", 47062306a36Sopenharmony_ci .channels_min = 2, 47162306a36Sopenharmony_ci .channels_max = 2, 47262306a36Sopenharmony_ci .rates = TAS2780_RATES, 47362306a36Sopenharmony_ci .formats = TAS2780_FORMATS, 47462306a36Sopenharmony_ci }, 47562306a36Sopenharmony_ci .capture = { 47662306a36Sopenharmony_ci .stream_name = "ASI1 Capture", 47762306a36Sopenharmony_ci .channels_min = 1, 47862306a36Sopenharmony_ci .channels_max = 2, 47962306a36Sopenharmony_ci .rates = TAS2780_RATES, 48062306a36Sopenharmony_ci .formats = TAS2780_FORMATS, 48162306a36Sopenharmony_ci }, 48262306a36Sopenharmony_ci .ops = &tas2780_dai_ops, 48362306a36Sopenharmony_ci .symmetric_rate = 1, 48462306a36Sopenharmony_ci }, 48562306a36Sopenharmony_ci}; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_cistatic int tas2780_codec_probe(struct snd_soc_component *component) 48862306a36Sopenharmony_ci{ 48962306a36Sopenharmony_ci struct tas2780_priv *tas2780 = 49062306a36Sopenharmony_ci snd_soc_component_get_drvdata(component); 49162306a36Sopenharmony_ci int ret = 0; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci tas2780->component = component; 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci tas2780_reset(tas2780); 49662306a36Sopenharmony_ci ret = snd_soc_component_update_bits(component, 49762306a36Sopenharmony_ci TAS2780_IC_CFG, TAS2780_IC_CFG_MASK, 49862306a36Sopenharmony_ci TAS2780_IC_CFG_ENABLE); 49962306a36Sopenharmony_ci if (ret < 0) 50062306a36Sopenharmony_ci dev_err(tas2780->dev, "%s:errCode:0x%0x\n", 50162306a36Sopenharmony_ci __func__, ret); 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci return ret; 50462306a36Sopenharmony_ci} 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_cistatic DECLARE_TLV_DB_SCALE(tas2780_digital_tlv, 1100, 50, 0); 50762306a36Sopenharmony_cistatic DECLARE_TLV_DB_SCALE(tas2780_playback_volume, -10000, 50, 0); 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_cistatic const struct snd_kcontrol_new tas2780_snd_controls[] = { 51062306a36Sopenharmony_ci SOC_SINGLE_TLV("Speaker Volume", TAS2780_DVC, 0, 51162306a36Sopenharmony_ci TAS2780_DVC_MAX, 1, tas2780_playback_volume), 51262306a36Sopenharmony_ci SOC_SINGLE_TLV("Amp Gain Volume", TAS2780_CHNL_0, 0, 0x14, 0, 51362306a36Sopenharmony_ci tas2780_digital_tlv), 51462306a36Sopenharmony_ci}; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_cistatic const struct snd_soc_component_driver soc_component_driver_tas2780 = { 51762306a36Sopenharmony_ci .probe = tas2780_codec_probe, 51862306a36Sopenharmony_ci#ifdef CONFIG_PM 51962306a36Sopenharmony_ci .suspend = tas2780_codec_suspend, 52062306a36Sopenharmony_ci .resume = tas2780_codec_resume, 52162306a36Sopenharmony_ci#endif 52262306a36Sopenharmony_ci .controls = tas2780_snd_controls, 52362306a36Sopenharmony_ci .num_controls = ARRAY_SIZE(tas2780_snd_controls), 52462306a36Sopenharmony_ci .dapm_widgets = tas2780_dapm_widgets, 52562306a36Sopenharmony_ci .num_dapm_widgets = ARRAY_SIZE(tas2780_dapm_widgets), 52662306a36Sopenharmony_ci .dapm_routes = tas2780_audio_map, 52762306a36Sopenharmony_ci .num_dapm_routes = ARRAY_SIZE(tas2780_audio_map), 52862306a36Sopenharmony_ci .idle_bias_on = 1, 52962306a36Sopenharmony_ci .endianness = 1, 53062306a36Sopenharmony_ci}; 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_cistatic const struct reg_default tas2780_reg_defaults[] = { 53362306a36Sopenharmony_ci { TAS2780_PAGE, 0x00 }, 53462306a36Sopenharmony_ci { TAS2780_SW_RST, 0x00 }, 53562306a36Sopenharmony_ci { TAS2780_PWR_CTRL, 0x1a }, 53662306a36Sopenharmony_ci { TAS2780_DVC, 0x00 }, 53762306a36Sopenharmony_ci { TAS2780_CHNL_0, 0x00 }, 53862306a36Sopenharmony_ci { TAS2780_TDM_CFG0, 0x09 }, 53962306a36Sopenharmony_ci { TAS2780_TDM_CFG1, 0x02 }, 54062306a36Sopenharmony_ci { TAS2780_TDM_CFG2, 0x0a }, 54162306a36Sopenharmony_ci { TAS2780_TDM_CFG3, 0x10 }, 54262306a36Sopenharmony_ci { TAS2780_TDM_CFG5, 0x42 }, 54362306a36Sopenharmony_ci}; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_cistatic const struct regmap_range_cfg tas2780_regmap_ranges[] = { 54662306a36Sopenharmony_ci { 54762306a36Sopenharmony_ci .range_min = 0, 54862306a36Sopenharmony_ci .range_max = 1 * 128, 54962306a36Sopenharmony_ci .selector_reg = TAS2780_PAGE, 55062306a36Sopenharmony_ci .selector_mask = 0xff, 55162306a36Sopenharmony_ci .selector_shift = 0, 55262306a36Sopenharmony_ci .window_start = 0, 55362306a36Sopenharmony_ci .window_len = 128, 55462306a36Sopenharmony_ci }, 55562306a36Sopenharmony_ci}; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_cistatic const struct regmap_config tas2780_i2c_regmap = { 55862306a36Sopenharmony_ci .reg_bits = 8, 55962306a36Sopenharmony_ci .val_bits = 8, 56062306a36Sopenharmony_ci .reg_defaults = tas2780_reg_defaults, 56162306a36Sopenharmony_ci .num_reg_defaults = ARRAY_SIZE(tas2780_reg_defaults), 56262306a36Sopenharmony_ci .cache_type = REGCACHE_RBTREE, 56362306a36Sopenharmony_ci .ranges = tas2780_regmap_ranges, 56462306a36Sopenharmony_ci .num_ranges = ARRAY_SIZE(tas2780_regmap_ranges), 56562306a36Sopenharmony_ci .max_register = 1 * 128, 56662306a36Sopenharmony_ci}; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_cistatic int tas2780_parse_dt(struct device *dev, struct tas2780_priv *tas2780) 56962306a36Sopenharmony_ci{ 57062306a36Sopenharmony_ci int ret = 0; 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci tas2780->reset_gpio = devm_gpiod_get_optional(tas2780->dev, "reset", 57362306a36Sopenharmony_ci GPIOD_OUT_HIGH); 57462306a36Sopenharmony_ci if (IS_ERR(tas2780->reset_gpio)) { 57562306a36Sopenharmony_ci if (PTR_ERR(tas2780->reset_gpio) == -EPROBE_DEFER) { 57662306a36Sopenharmony_ci tas2780->reset_gpio = NULL; 57762306a36Sopenharmony_ci return -EPROBE_DEFER; 57862306a36Sopenharmony_ci } 57962306a36Sopenharmony_ci } 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci ret = fwnode_property_read_u32(dev->fwnode, "ti,imon-slot-no", 58262306a36Sopenharmony_ci &tas2780->i_sense_slot); 58362306a36Sopenharmony_ci if (ret) 58462306a36Sopenharmony_ci tas2780->i_sense_slot = 0; 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci ret = fwnode_property_read_u32(dev->fwnode, "ti,vmon-slot-no", 58762306a36Sopenharmony_ci &tas2780->v_sense_slot); 58862306a36Sopenharmony_ci if (ret) 58962306a36Sopenharmony_ci tas2780->v_sense_slot = 2; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci return 0; 59262306a36Sopenharmony_ci} 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_cistatic int tas2780_i2c_probe(struct i2c_client *client) 59562306a36Sopenharmony_ci{ 59662306a36Sopenharmony_ci struct tas2780_priv *tas2780; 59762306a36Sopenharmony_ci int result; 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci tas2780 = devm_kzalloc(&client->dev, sizeof(struct tas2780_priv), 60062306a36Sopenharmony_ci GFP_KERNEL); 60162306a36Sopenharmony_ci if (!tas2780) 60262306a36Sopenharmony_ci return -ENOMEM; 60362306a36Sopenharmony_ci tas2780->dev = &client->dev; 60462306a36Sopenharmony_ci i2c_set_clientdata(client, tas2780); 60562306a36Sopenharmony_ci dev_set_drvdata(&client->dev, tas2780); 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci tas2780->regmap = devm_regmap_init_i2c(client, &tas2780_i2c_regmap); 60862306a36Sopenharmony_ci if (IS_ERR(tas2780->regmap)) { 60962306a36Sopenharmony_ci result = PTR_ERR(tas2780->regmap); 61062306a36Sopenharmony_ci dev_err(&client->dev, "Failed to allocate register map: %d\n", 61162306a36Sopenharmony_ci result); 61262306a36Sopenharmony_ci return result; 61362306a36Sopenharmony_ci } 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci if (client->dev.of_node) { 61662306a36Sopenharmony_ci result = tas2780_parse_dt(&client->dev, tas2780); 61762306a36Sopenharmony_ci if (result) { 61862306a36Sopenharmony_ci dev_err(tas2780->dev, 61962306a36Sopenharmony_ci "%s: Failed to parse devicetree\n", __func__); 62062306a36Sopenharmony_ci return result; 62162306a36Sopenharmony_ci } 62262306a36Sopenharmony_ci } 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci return devm_snd_soc_register_component(tas2780->dev, 62562306a36Sopenharmony_ci &soc_component_driver_tas2780, tas2780_dai_driver, 62662306a36Sopenharmony_ci ARRAY_SIZE(tas2780_dai_driver)); 62762306a36Sopenharmony_ci} 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_cistatic const struct i2c_device_id tas2780_i2c_id[] = { 63062306a36Sopenharmony_ci { "tas2780", 0}, 63162306a36Sopenharmony_ci { } 63262306a36Sopenharmony_ci}; 63362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, tas2780_i2c_id); 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci#if defined(CONFIG_OF) 63662306a36Sopenharmony_cistatic const struct of_device_id tas2780_of_match[] = { 63762306a36Sopenharmony_ci { .compatible = "ti,tas2780" }, 63862306a36Sopenharmony_ci {}, 63962306a36Sopenharmony_ci}; 64062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, tas2780_of_match); 64162306a36Sopenharmony_ci#endif 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_cistatic struct i2c_driver tas2780_i2c_driver = { 64462306a36Sopenharmony_ci .driver = { 64562306a36Sopenharmony_ci .name = "tas2780", 64662306a36Sopenharmony_ci .of_match_table = of_match_ptr(tas2780_of_match), 64762306a36Sopenharmony_ci }, 64862306a36Sopenharmony_ci .probe = tas2780_i2c_probe, 64962306a36Sopenharmony_ci .id_table = tas2780_i2c_id, 65062306a36Sopenharmony_ci}; 65162306a36Sopenharmony_cimodule_i2c_driver(tas2780_i2c_driver); 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ciMODULE_AUTHOR("Raphael Xu <raphael-xu@ti.com>"); 65462306a36Sopenharmony_ciMODULE_DESCRIPTION("TAS2780 I2C Smart Amplifier driver"); 65562306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 656