18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci// 38c2ecf20Sopenharmony_ci// ALSA SoC Texas Instruments TAS2770 20-W Digital Input Mono Class-D 48c2ecf20Sopenharmony_ci// Audio Amplifier with Speaker I/V Sense 58c2ecf20Sopenharmony_ci// 68c2ecf20Sopenharmony_ci// Copyright (C) 2016-2017 Texas Instruments Incorporated - https://www.ti.com/ 78c2ecf20Sopenharmony_ci// Author: Tracy Yi <tracy-yi@ti.com> 88c2ecf20Sopenharmony_ci// Frank Shi <shifu0704@thundersoft.com> 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/module.h> 118c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 128c2ecf20Sopenharmony_ci#include <linux/err.h> 138c2ecf20Sopenharmony_ci#include <linux/init.h> 148c2ecf20Sopenharmony_ci#include <linux/delay.h> 158c2ecf20Sopenharmony_ci#include <linux/pm.h> 168c2ecf20Sopenharmony_ci#include <linux/i2c.h> 178c2ecf20Sopenharmony_ci#include <linux/gpio.h> 188c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h> 198c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h> 208c2ecf20Sopenharmony_ci#include <linux/firmware.h> 218c2ecf20Sopenharmony_ci#include <linux/regmap.h> 228c2ecf20Sopenharmony_ci#include <linux/of.h> 238c2ecf20Sopenharmony_ci#include <linux/of_gpio.h> 248c2ecf20Sopenharmony_ci#include <linux/slab.h> 258c2ecf20Sopenharmony_ci#include <sound/soc.h> 268c2ecf20Sopenharmony_ci#include <sound/pcm.h> 278c2ecf20Sopenharmony_ci#include <sound/pcm_params.h> 288c2ecf20Sopenharmony_ci#include <sound/initval.h> 298c2ecf20Sopenharmony_ci#include <sound/tlv.h> 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#include "tas2770.h" 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#define TAS2770_MDELAY 0xFFFFFFFE 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic void tas2770_reset(struct tas2770_priv *tas2770) 368c2ecf20Sopenharmony_ci{ 378c2ecf20Sopenharmony_ci if (tas2770->reset_gpio) { 388c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(tas2770->reset_gpio, 0); 398c2ecf20Sopenharmony_ci msleep(20); 408c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(tas2770->reset_gpio, 1); 418c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 428c2ecf20Sopenharmony_ci } 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci snd_soc_component_write(tas2770->component, TAS2770_SW_RST, 458c2ecf20Sopenharmony_ci TAS2770_RST); 468c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 478c2ecf20Sopenharmony_ci} 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistatic int tas2770_update_pwr_ctrl(struct tas2770_priv *tas2770) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci struct snd_soc_component *component = tas2770->component; 528c2ecf20Sopenharmony_ci unsigned int val; 538c2ecf20Sopenharmony_ci int ret; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci if (tas2770->dac_powered) 568c2ecf20Sopenharmony_ci val = tas2770->unmuted ? 578c2ecf20Sopenharmony_ci TAS2770_PWR_CTRL_ACTIVE : TAS2770_PWR_CTRL_MUTE; 588c2ecf20Sopenharmony_ci else 598c2ecf20Sopenharmony_ci val = TAS2770_PWR_CTRL_SHUTDOWN; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci ret = snd_soc_component_update_bits(component, TAS2770_PWR_CTRL, 628c2ecf20Sopenharmony_ci TAS2770_PWR_CTRL_MASK, val); 638c2ecf20Sopenharmony_ci if (ret < 0) 648c2ecf20Sopenharmony_ci return ret; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci return 0; 678c2ecf20Sopenharmony_ci} 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 708c2ecf20Sopenharmony_cistatic int tas2770_codec_suspend(struct snd_soc_component *component) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci struct tas2770_priv *tas2770 = snd_soc_component_get_drvdata(component); 738c2ecf20Sopenharmony_ci int ret = 0; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci regcache_cache_only(tas2770->regmap, true); 768c2ecf20Sopenharmony_ci regcache_mark_dirty(tas2770->regmap); 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci if (tas2770->sdz_gpio) { 798c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(tas2770->sdz_gpio, 0); 808c2ecf20Sopenharmony_ci } else { 818c2ecf20Sopenharmony_ci ret = snd_soc_component_update_bits(component, TAS2770_PWR_CTRL, 828c2ecf20Sopenharmony_ci TAS2770_PWR_CTRL_MASK, 838c2ecf20Sopenharmony_ci TAS2770_PWR_CTRL_SHUTDOWN); 848c2ecf20Sopenharmony_ci if (ret < 0) { 858c2ecf20Sopenharmony_ci regcache_cache_only(tas2770->regmap, false); 868c2ecf20Sopenharmony_ci regcache_sync(tas2770->regmap); 878c2ecf20Sopenharmony_ci return ret; 888c2ecf20Sopenharmony_ci } 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci ret = 0; 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci return ret; 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cistatic int tas2770_codec_resume(struct snd_soc_component *component) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci struct tas2770_priv *tas2770 = snd_soc_component_get_drvdata(component); 998c2ecf20Sopenharmony_ci int ret = 0; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci if (tas2770->sdz_gpio) { 1028c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(tas2770->sdz_gpio, 1); 1038c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 1048c2ecf20Sopenharmony_ci } else { 1058c2ecf20Sopenharmony_ci ret = tas2770_update_pwr_ctrl(tas2770); 1068c2ecf20Sopenharmony_ci if (ret < 0) 1078c2ecf20Sopenharmony_ci return ret; 1088c2ecf20Sopenharmony_ci } 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci regcache_cache_only(tas2770->regmap, false); 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci return regcache_sync(tas2770->regmap); 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci#else 1158c2ecf20Sopenharmony_ci#define tas2770_codec_suspend NULL 1168c2ecf20Sopenharmony_ci#define tas2770_codec_resume NULL 1178c2ecf20Sopenharmony_ci#endif 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_cistatic const char * const tas2770_ASI1_src[] = { 1208c2ecf20Sopenharmony_ci "I2C offset", "Left", "Right", "LeftRightDiv2", 1218c2ecf20Sopenharmony_ci}; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL( 1248c2ecf20Sopenharmony_ci tas2770_ASI1_src_enum, TAS2770_TDM_CFG_REG2, 1258c2ecf20Sopenharmony_ci 4, tas2770_ASI1_src); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new tas2770_asi1_mux = 1288c2ecf20Sopenharmony_ci SOC_DAPM_ENUM("ASI1 Source", tas2770_ASI1_src_enum); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic int tas2770_dac_event(struct snd_soc_dapm_widget *w, 1318c2ecf20Sopenharmony_ci struct snd_kcontrol *kcontrol, int event) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci struct snd_soc_component *component = 1348c2ecf20Sopenharmony_ci snd_soc_dapm_to_component(w->dapm); 1358c2ecf20Sopenharmony_ci struct tas2770_priv *tas2770 = 1368c2ecf20Sopenharmony_ci snd_soc_component_get_drvdata(component); 1378c2ecf20Sopenharmony_ci int ret; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci switch (event) { 1408c2ecf20Sopenharmony_ci case SND_SOC_DAPM_POST_PMU: 1418c2ecf20Sopenharmony_ci tas2770->dac_powered = 1; 1428c2ecf20Sopenharmony_ci ret = tas2770_update_pwr_ctrl(tas2770); 1438c2ecf20Sopenharmony_ci break; 1448c2ecf20Sopenharmony_ci case SND_SOC_DAPM_PRE_PMD: 1458c2ecf20Sopenharmony_ci tas2770->dac_powered = 0; 1468c2ecf20Sopenharmony_ci ret = tas2770_update_pwr_ctrl(tas2770); 1478c2ecf20Sopenharmony_ci break; 1488c2ecf20Sopenharmony_ci default: 1498c2ecf20Sopenharmony_ci dev_err(tas2770->dev, "Not supported evevt\n"); 1508c2ecf20Sopenharmony_ci return -EINVAL; 1518c2ecf20Sopenharmony_ci } 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci return ret; 1548c2ecf20Sopenharmony_ci} 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new isense_switch = 1578c2ecf20Sopenharmony_ci SOC_DAPM_SINGLE("Switch", TAS2770_PWR_CTRL, 3, 1, 1); 1588c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new vsense_switch = 1598c2ecf20Sopenharmony_ci SOC_DAPM_SINGLE("Switch", TAS2770_PWR_CTRL, 2, 1, 1); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget tas2770_dapm_widgets[] = { 1628c2ecf20Sopenharmony_ci SND_SOC_DAPM_AIF_IN("ASI1", "ASI1 Playback", 0, SND_SOC_NOPM, 0, 0), 1638c2ecf20Sopenharmony_ci SND_SOC_DAPM_MUX("ASI1 Sel", SND_SOC_NOPM, 0, 0, &tas2770_asi1_mux), 1648c2ecf20Sopenharmony_ci SND_SOC_DAPM_SWITCH("ISENSE", TAS2770_PWR_CTRL, 3, 1, &isense_switch), 1658c2ecf20Sopenharmony_ci SND_SOC_DAPM_SWITCH("VSENSE", TAS2770_PWR_CTRL, 2, 1, &vsense_switch), 1668c2ecf20Sopenharmony_ci SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0, tas2770_dac_event, 1678c2ecf20Sopenharmony_ci SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), 1688c2ecf20Sopenharmony_ci SND_SOC_DAPM_OUTPUT("OUT"), 1698c2ecf20Sopenharmony_ci SND_SOC_DAPM_SIGGEN("VMON"), 1708c2ecf20Sopenharmony_ci SND_SOC_DAPM_SIGGEN("IMON") 1718c2ecf20Sopenharmony_ci}; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route tas2770_audio_map[] = { 1748c2ecf20Sopenharmony_ci {"ASI1 Sel", "I2C offset", "ASI1"}, 1758c2ecf20Sopenharmony_ci {"ASI1 Sel", "Left", "ASI1"}, 1768c2ecf20Sopenharmony_ci {"ASI1 Sel", "Right", "ASI1"}, 1778c2ecf20Sopenharmony_ci {"ASI1 Sel", "LeftRightDiv2", "ASI1"}, 1788c2ecf20Sopenharmony_ci {"DAC", NULL, "ASI1 Sel"}, 1798c2ecf20Sopenharmony_ci {"OUT", NULL, "DAC"}, 1808c2ecf20Sopenharmony_ci {"ISENSE", "Switch", "IMON"}, 1818c2ecf20Sopenharmony_ci {"VSENSE", "Switch", "VMON"}, 1828c2ecf20Sopenharmony_ci}; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_cistatic int tas2770_mute(struct snd_soc_dai *dai, int mute, int direction) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci struct snd_soc_component *component = dai->component; 1878c2ecf20Sopenharmony_ci struct tas2770_priv *tas2770 = 1888c2ecf20Sopenharmony_ci snd_soc_component_get_drvdata(component); 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci tas2770->unmuted = !mute; 1918c2ecf20Sopenharmony_ci return tas2770_update_pwr_ctrl(tas2770); 1928c2ecf20Sopenharmony_ci} 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_cistatic int tas2770_set_bitwidth(struct tas2770_priv *tas2770, int bitwidth) 1958c2ecf20Sopenharmony_ci{ 1968c2ecf20Sopenharmony_ci int ret; 1978c2ecf20Sopenharmony_ci struct snd_soc_component *component = tas2770->component; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci switch (bitwidth) { 2008c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S16_LE: 2018c2ecf20Sopenharmony_ci ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG2, 2028c2ecf20Sopenharmony_ci TAS2770_TDM_CFG_REG2_RXW_MASK, 2038c2ecf20Sopenharmony_ci TAS2770_TDM_CFG_REG2_RXW_16BITS); 2048c2ecf20Sopenharmony_ci tas2770->v_sense_slot = tas2770->i_sense_slot + 2; 2058c2ecf20Sopenharmony_ci break; 2068c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S24_LE: 2078c2ecf20Sopenharmony_ci ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG2, 2088c2ecf20Sopenharmony_ci TAS2770_TDM_CFG_REG2_RXW_MASK, 2098c2ecf20Sopenharmony_ci TAS2770_TDM_CFG_REG2_RXW_24BITS); 2108c2ecf20Sopenharmony_ci tas2770->v_sense_slot = tas2770->i_sense_slot + 4; 2118c2ecf20Sopenharmony_ci break; 2128c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S32_LE: 2138c2ecf20Sopenharmony_ci ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG2, 2148c2ecf20Sopenharmony_ci TAS2770_TDM_CFG_REG2_RXW_MASK, 2158c2ecf20Sopenharmony_ci TAS2770_TDM_CFG_REG2_RXW_32BITS); 2168c2ecf20Sopenharmony_ci tas2770->v_sense_slot = tas2770->i_sense_slot + 4; 2178c2ecf20Sopenharmony_ci break; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci default: 2208c2ecf20Sopenharmony_ci return -EINVAL; 2218c2ecf20Sopenharmony_ci } 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci if (ret < 0) 2248c2ecf20Sopenharmony_ci return ret; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG5, 2278c2ecf20Sopenharmony_ci TAS2770_TDM_CFG_REG5_VSNS_MASK | 2288c2ecf20Sopenharmony_ci TAS2770_TDM_CFG_REG5_50_MASK, 2298c2ecf20Sopenharmony_ci TAS2770_TDM_CFG_REG5_VSNS_ENABLE | 2308c2ecf20Sopenharmony_ci tas2770->v_sense_slot); 2318c2ecf20Sopenharmony_ci if (ret < 0) 2328c2ecf20Sopenharmony_ci return ret; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG6, 2358c2ecf20Sopenharmony_ci TAS2770_TDM_CFG_REG6_ISNS_MASK | 2368c2ecf20Sopenharmony_ci TAS2770_TDM_CFG_REG6_50_MASK, 2378c2ecf20Sopenharmony_ci TAS2770_TDM_CFG_REG6_ISNS_ENABLE | 2388c2ecf20Sopenharmony_ci tas2770->i_sense_slot); 2398c2ecf20Sopenharmony_ci if (ret < 0) 2408c2ecf20Sopenharmony_ci return ret; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci return 0; 2438c2ecf20Sopenharmony_ci} 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_cistatic int tas2770_set_samplerate(struct tas2770_priv *tas2770, int samplerate) 2468c2ecf20Sopenharmony_ci{ 2478c2ecf20Sopenharmony_ci struct snd_soc_component *component = tas2770->component; 2488c2ecf20Sopenharmony_ci int ramp_rate_val; 2498c2ecf20Sopenharmony_ci int ret; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci switch (samplerate) { 2528c2ecf20Sopenharmony_ci case 48000: 2538c2ecf20Sopenharmony_ci ramp_rate_val = TAS2770_TDM_CFG_REG0_SMP_48KHZ | 2548c2ecf20Sopenharmony_ci TAS2770_TDM_CFG_REG0_31_44_1_48KHZ; 2558c2ecf20Sopenharmony_ci break; 2568c2ecf20Sopenharmony_ci case 44100: 2578c2ecf20Sopenharmony_ci ramp_rate_val = TAS2770_TDM_CFG_REG0_SMP_44_1KHZ | 2588c2ecf20Sopenharmony_ci TAS2770_TDM_CFG_REG0_31_44_1_48KHZ; 2598c2ecf20Sopenharmony_ci break; 2608c2ecf20Sopenharmony_ci case 96000: 2618c2ecf20Sopenharmony_ci ramp_rate_val = TAS2770_TDM_CFG_REG0_SMP_48KHZ | 2628c2ecf20Sopenharmony_ci TAS2770_TDM_CFG_REG0_31_88_2_96KHZ; 2638c2ecf20Sopenharmony_ci break; 2648c2ecf20Sopenharmony_ci case 88200: 2658c2ecf20Sopenharmony_ci ramp_rate_val = TAS2770_TDM_CFG_REG0_SMP_44_1KHZ | 2668c2ecf20Sopenharmony_ci TAS2770_TDM_CFG_REG0_31_88_2_96KHZ; 2678c2ecf20Sopenharmony_ci break; 2688c2ecf20Sopenharmony_ci case 192000: 2698c2ecf20Sopenharmony_ci ramp_rate_val = TAS2770_TDM_CFG_REG0_SMP_48KHZ | 2708c2ecf20Sopenharmony_ci TAS2770_TDM_CFG_REG0_31_176_4_192KHZ; 2718c2ecf20Sopenharmony_ci break; 2728c2ecf20Sopenharmony_ci case 176400: 2738c2ecf20Sopenharmony_ci ramp_rate_val = TAS2770_TDM_CFG_REG0_SMP_44_1KHZ | 2748c2ecf20Sopenharmony_ci TAS2770_TDM_CFG_REG0_31_176_4_192KHZ; 2758c2ecf20Sopenharmony_ci break; 2768c2ecf20Sopenharmony_ci default: 2778c2ecf20Sopenharmony_ci return -EINVAL; 2788c2ecf20Sopenharmony_ci } 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG0, 2818c2ecf20Sopenharmony_ci TAS2770_TDM_CFG_REG0_SMP_MASK | 2828c2ecf20Sopenharmony_ci TAS2770_TDM_CFG_REG0_31_MASK, 2838c2ecf20Sopenharmony_ci ramp_rate_val); 2848c2ecf20Sopenharmony_ci if (ret < 0) 2858c2ecf20Sopenharmony_ci return ret; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci return 0; 2888c2ecf20Sopenharmony_ci} 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_cistatic int tas2770_hw_params(struct snd_pcm_substream *substream, 2918c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params, 2928c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 2938c2ecf20Sopenharmony_ci{ 2948c2ecf20Sopenharmony_ci struct snd_soc_component *component = dai->component; 2958c2ecf20Sopenharmony_ci struct tas2770_priv *tas2770 = 2968c2ecf20Sopenharmony_ci snd_soc_component_get_drvdata(component); 2978c2ecf20Sopenharmony_ci int ret; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci ret = tas2770_set_bitwidth(tas2770, params_format(params)); 3008c2ecf20Sopenharmony_ci if (ret) 3018c2ecf20Sopenharmony_ci return ret; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci return tas2770_set_samplerate(tas2770, params_rate(params)); 3048c2ecf20Sopenharmony_ci} 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_cistatic int tas2770_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) 3078c2ecf20Sopenharmony_ci{ 3088c2ecf20Sopenharmony_ci struct snd_soc_component *component = dai->component; 3098c2ecf20Sopenharmony_ci struct tas2770_priv *tas2770 = 3108c2ecf20Sopenharmony_ci snd_soc_component_get_drvdata(component); 3118c2ecf20Sopenharmony_ci u8 tdm_rx_start_slot = 0, invert_fpol = 0, fpol_preinv = 0, asi_cfg_1 = 0; 3128c2ecf20Sopenharmony_ci int ret; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 3158c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_CBS_CFS: 3168c2ecf20Sopenharmony_ci break; 3178c2ecf20Sopenharmony_ci default: 3188c2ecf20Sopenharmony_ci dev_err(tas2770->dev, "ASI format master is not found\n"); 3198c2ecf20Sopenharmony_ci return -EINVAL; 3208c2ecf20Sopenharmony_ci } 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 3238c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_NB_IF: 3248c2ecf20Sopenharmony_ci invert_fpol = 1; 3258c2ecf20Sopenharmony_ci fallthrough; 3268c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_NB_NF: 3278c2ecf20Sopenharmony_ci asi_cfg_1 |= TAS2770_TDM_CFG_REG1_RX_RSING; 3288c2ecf20Sopenharmony_ci break; 3298c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_IB_IF: 3308c2ecf20Sopenharmony_ci invert_fpol = 1; 3318c2ecf20Sopenharmony_ci fallthrough; 3328c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_IB_NF: 3338c2ecf20Sopenharmony_ci asi_cfg_1 |= TAS2770_TDM_CFG_REG1_RX_FALING; 3348c2ecf20Sopenharmony_ci break; 3358c2ecf20Sopenharmony_ci default: 3368c2ecf20Sopenharmony_ci dev_err(tas2770->dev, "ASI format Inverse is not found\n"); 3378c2ecf20Sopenharmony_ci return -EINVAL; 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG1, 3418c2ecf20Sopenharmony_ci TAS2770_TDM_CFG_REG1_RX_MASK, 3428c2ecf20Sopenharmony_ci asi_cfg_1); 3438c2ecf20Sopenharmony_ci if (ret < 0) 3448c2ecf20Sopenharmony_ci return ret; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 3478c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_I2S: 3488c2ecf20Sopenharmony_ci tdm_rx_start_slot = 1; 3498c2ecf20Sopenharmony_ci fpol_preinv = 0; 3508c2ecf20Sopenharmony_ci break; 3518c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_DSP_A: 3528c2ecf20Sopenharmony_ci tdm_rx_start_slot = 0; 3538c2ecf20Sopenharmony_ci fpol_preinv = 1; 3548c2ecf20Sopenharmony_ci break; 3558c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_DSP_B: 3568c2ecf20Sopenharmony_ci tdm_rx_start_slot = 1; 3578c2ecf20Sopenharmony_ci fpol_preinv = 1; 3588c2ecf20Sopenharmony_ci break; 3598c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_LEFT_J: 3608c2ecf20Sopenharmony_ci tdm_rx_start_slot = 0; 3618c2ecf20Sopenharmony_ci fpol_preinv = 1; 3628c2ecf20Sopenharmony_ci break; 3638c2ecf20Sopenharmony_ci default: 3648c2ecf20Sopenharmony_ci dev_err(tas2770->dev, 3658c2ecf20Sopenharmony_ci "DAI Format is not found, fmt=0x%x\n", fmt); 3668c2ecf20Sopenharmony_ci return -EINVAL; 3678c2ecf20Sopenharmony_ci } 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG1, 3708c2ecf20Sopenharmony_ci TAS2770_TDM_CFG_REG1_MASK, 3718c2ecf20Sopenharmony_ci (tdm_rx_start_slot << TAS2770_TDM_CFG_REG1_51_SHIFT)); 3728c2ecf20Sopenharmony_ci if (ret < 0) 3738c2ecf20Sopenharmony_ci return ret; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG0, 3768c2ecf20Sopenharmony_ci TAS2770_TDM_CFG_REG0_FPOL_MASK, 3778c2ecf20Sopenharmony_ci (fpol_preinv ^ invert_fpol) 3788c2ecf20Sopenharmony_ci ? TAS2770_TDM_CFG_REG0_FPOL_RSING 3798c2ecf20Sopenharmony_ci : TAS2770_TDM_CFG_REG0_FPOL_FALING); 3808c2ecf20Sopenharmony_ci if (ret < 0) 3818c2ecf20Sopenharmony_ci return ret; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci return 0; 3848c2ecf20Sopenharmony_ci} 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_cistatic int tas2770_set_dai_tdm_slot(struct snd_soc_dai *dai, 3878c2ecf20Sopenharmony_ci unsigned int tx_mask, 3888c2ecf20Sopenharmony_ci unsigned int rx_mask, 3898c2ecf20Sopenharmony_ci int slots, int slot_width) 3908c2ecf20Sopenharmony_ci{ 3918c2ecf20Sopenharmony_ci struct snd_soc_component *component = dai->component; 3928c2ecf20Sopenharmony_ci int left_slot, right_slot; 3938c2ecf20Sopenharmony_ci int ret; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci if (tx_mask == 0 || rx_mask != 0) 3968c2ecf20Sopenharmony_ci return -EINVAL; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci left_slot = __ffs(tx_mask); 3998c2ecf20Sopenharmony_ci tx_mask &= ~(1 << left_slot); 4008c2ecf20Sopenharmony_ci if (tx_mask == 0) { 4018c2ecf20Sopenharmony_ci right_slot = left_slot; 4028c2ecf20Sopenharmony_ci } else { 4038c2ecf20Sopenharmony_ci right_slot = __ffs(tx_mask); 4048c2ecf20Sopenharmony_ci tx_mask &= ~(1 << right_slot); 4058c2ecf20Sopenharmony_ci } 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci if (tx_mask != 0 || left_slot >= slots || right_slot >= slots) 4088c2ecf20Sopenharmony_ci return -EINVAL; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG3, 4118c2ecf20Sopenharmony_ci TAS2770_TDM_CFG_REG3_30_MASK, 4128c2ecf20Sopenharmony_ci (left_slot << TAS2770_TDM_CFG_REG3_30_SHIFT)); 4138c2ecf20Sopenharmony_ci if (ret < 0) 4148c2ecf20Sopenharmony_ci return ret; 4158c2ecf20Sopenharmony_ci ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG3, 4168c2ecf20Sopenharmony_ci TAS2770_TDM_CFG_REG3_RXS_MASK, 4178c2ecf20Sopenharmony_ci (right_slot << TAS2770_TDM_CFG_REG3_RXS_SHIFT)); 4188c2ecf20Sopenharmony_ci if (ret < 0) 4198c2ecf20Sopenharmony_ci return ret; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci switch (slot_width) { 4228c2ecf20Sopenharmony_ci case 16: 4238c2ecf20Sopenharmony_ci ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG2, 4248c2ecf20Sopenharmony_ci TAS2770_TDM_CFG_REG2_RXS_MASK, 4258c2ecf20Sopenharmony_ci TAS2770_TDM_CFG_REG2_RXS_16BITS); 4268c2ecf20Sopenharmony_ci break; 4278c2ecf20Sopenharmony_ci case 24: 4288c2ecf20Sopenharmony_ci ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG2, 4298c2ecf20Sopenharmony_ci TAS2770_TDM_CFG_REG2_RXS_MASK, 4308c2ecf20Sopenharmony_ci TAS2770_TDM_CFG_REG2_RXS_24BITS); 4318c2ecf20Sopenharmony_ci break; 4328c2ecf20Sopenharmony_ci case 32: 4338c2ecf20Sopenharmony_ci ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG2, 4348c2ecf20Sopenharmony_ci TAS2770_TDM_CFG_REG2_RXS_MASK, 4358c2ecf20Sopenharmony_ci TAS2770_TDM_CFG_REG2_RXS_32BITS); 4368c2ecf20Sopenharmony_ci break; 4378c2ecf20Sopenharmony_ci case 0: 4388c2ecf20Sopenharmony_ci /* Do not change slot width */ 4398c2ecf20Sopenharmony_ci ret = 0; 4408c2ecf20Sopenharmony_ci break; 4418c2ecf20Sopenharmony_ci default: 4428c2ecf20Sopenharmony_ci ret = -EINVAL; 4438c2ecf20Sopenharmony_ci } 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci if (ret < 0) 4468c2ecf20Sopenharmony_ci return ret; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci return 0; 4498c2ecf20Sopenharmony_ci} 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_cistatic struct snd_soc_dai_ops tas2770_dai_ops = { 4528c2ecf20Sopenharmony_ci .mute_stream = tas2770_mute, 4538c2ecf20Sopenharmony_ci .hw_params = tas2770_hw_params, 4548c2ecf20Sopenharmony_ci .set_fmt = tas2770_set_fmt, 4558c2ecf20Sopenharmony_ci .set_tdm_slot = tas2770_set_dai_tdm_slot, 4568c2ecf20Sopenharmony_ci .no_capture_mute = 1, 4578c2ecf20Sopenharmony_ci}; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci#define TAS2770_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ 4608c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci#define TAS2770_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\ 4638c2ecf20Sopenharmony_ci SNDRV_PCM_RATE_96000 |\ 4648c2ecf20Sopenharmony_ci SNDRV_PCM_RATE_192000\ 4658c2ecf20Sopenharmony_ci ) 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_cistatic struct snd_soc_dai_driver tas2770_dai_driver[] = { 4688c2ecf20Sopenharmony_ci { 4698c2ecf20Sopenharmony_ci .name = "tas2770 ASI1", 4708c2ecf20Sopenharmony_ci .id = 0, 4718c2ecf20Sopenharmony_ci .playback = { 4728c2ecf20Sopenharmony_ci .stream_name = "ASI1 Playback", 4738c2ecf20Sopenharmony_ci .channels_min = 1, 4748c2ecf20Sopenharmony_ci .channels_max = 2, 4758c2ecf20Sopenharmony_ci .rates = TAS2770_RATES, 4768c2ecf20Sopenharmony_ci .formats = TAS2770_FORMATS, 4778c2ecf20Sopenharmony_ci }, 4788c2ecf20Sopenharmony_ci .capture = { 4798c2ecf20Sopenharmony_ci .stream_name = "ASI1 Capture", 4808c2ecf20Sopenharmony_ci .channels_min = 0, 4818c2ecf20Sopenharmony_ci .channels_max = 2, 4828c2ecf20Sopenharmony_ci .rates = TAS2770_RATES, 4838c2ecf20Sopenharmony_ci .formats = TAS2770_FORMATS, 4848c2ecf20Sopenharmony_ci }, 4858c2ecf20Sopenharmony_ci .ops = &tas2770_dai_ops, 4868c2ecf20Sopenharmony_ci .symmetric_rates = 1, 4878c2ecf20Sopenharmony_ci }, 4888c2ecf20Sopenharmony_ci}; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_cistatic const struct regmap_config tas2770_i2c_regmap; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_cistatic int tas2770_codec_probe(struct snd_soc_component *component) 4938c2ecf20Sopenharmony_ci{ 4948c2ecf20Sopenharmony_ci struct tas2770_priv *tas2770 = 4958c2ecf20Sopenharmony_ci snd_soc_component_get_drvdata(component); 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci tas2770->component = component; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci if (tas2770->sdz_gpio) { 5008c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(tas2770->sdz_gpio, 1); 5018c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 5028c2ecf20Sopenharmony_ci } 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci tas2770_reset(tas2770); 5058c2ecf20Sopenharmony_ci regmap_reinit_cache(tas2770->regmap, &tas2770_i2c_regmap); 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci return 0; 5088c2ecf20Sopenharmony_ci} 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_cistatic DECLARE_TLV_DB_SCALE(tas2770_digital_tlv, 1100, 50, 0); 5118c2ecf20Sopenharmony_cistatic DECLARE_TLV_DB_SCALE(tas2770_playback_volume, -12750, 50, 0); 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new tas2770_snd_controls[] = { 5148c2ecf20Sopenharmony_ci SOC_SINGLE_TLV("Speaker Playback Volume", TAS2770_PLAY_CFG_REG2, 5158c2ecf20Sopenharmony_ci 0, TAS2770_PLAY_CFG_REG2_VMAX, 1, tas2770_playback_volume), 5168c2ecf20Sopenharmony_ci SOC_SINGLE_TLV("Amp Gain Volume", TAS2770_PLAY_CFG_REG0, 0, 0x14, 0, 5178c2ecf20Sopenharmony_ci tas2770_digital_tlv), 5188c2ecf20Sopenharmony_ci}; 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver soc_component_driver_tas2770 = { 5218c2ecf20Sopenharmony_ci .probe = tas2770_codec_probe, 5228c2ecf20Sopenharmony_ci .suspend = tas2770_codec_suspend, 5238c2ecf20Sopenharmony_ci .resume = tas2770_codec_resume, 5248c2ecf20Sopenharmony_ci .controls = tas2770_snd_controls, 5258c2ecf20Sopenharmony_ci .num_controls = ARRAY_SIZE(tas2770_snd_controls), 5268c2ecf20Sopenharmony_ci .dapm_widgets = tas2770_dapm_widgets, 5278c2ecf20Sopenharmony_ci .num_dapm_widgets = ARRAY_SIZE(tas2770_dapm_widgets), 5288c2ecf20Sopenharmony_ci .dapm_routes = tas2770_audio_map, 5298c2ecf20Sopenharmony_ci .num_dapm_routes = ARRAY_SIZE(tas2770_audio_map), 5308c2ecf20Sopenharmony_ci .idle_bias_on = 1, 5318c2ecf20Sopenharmony_ci .endianness = 1, 5328c2ecf20Sopenharmony_ci .non_legacy_dai_naming = 1, 5338c2ecf20Sopenharmony_ci}; 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_cistatic int tas2770_register_codec(struct tas2770_priv *tas2770) 5368c2ecf20Sopenharmony_ci{ 5378c2ecf20Sopenharmony_ci return devm_snd_soc_register_component(tas2770->dev, 5388c2ecf20Sopenharmony_ci &soc_component_driver_tas2770, 5398c2ecf20Sopenharmony_ci tas2770_dai_driver, ARRAY_SIZE(tas2770_dai_driver)); 5408c2ecf20Sopenharmony_ci} 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_cistatic const struct reg_default tas2770_reg_defaults[] = { 5438c2ecf20Sopenharmony_ci { TAS2770_PAGE, 0x00 }, 5448c2ecf20Sopenharmony_ci { TAS2770_SW_RST, 0x00 }, 5458c2ecf20Sopenharmony_ci { TAS2770_PWR_CTRL, 0x0e }, 5468c2ecf20Sopenharmony_ci { TAS2770_PLAY_CFG_REG0, 0x10 }, 5478c2ecf20Sopenharmony_ci { TAS2770_PLAY_CFG_REG1, 0x01 }, 5488c2ecf20Sopenharmony_ci { TAS2770_PLAY_CFG_REG2, 0x00 }, 5498c2ecf20Sopenharmony_ci { TAS2770_MSC_CFG_REG0, 0x07 }, 5508c2ecf20Sopenharmony_ci { TAS2770_TDM_CFG_REG1, 0x02 }, 5518c2ecf20Sopenharmony_ci { TAS2770_TDM_CFG_REG2, 0x0a }, 5528c2ecf20Sopenharmony_ci { TAS2770_TDM_CFG_REG3, 0x10 }, 5538c2ecf20Sopenharmony_ci { TAS2770_INT_MASK_REG0, 0xfc }, 5548c2ecf20Sopenharmony_ci { TAS2770_INT_MASK_REG1, 0xb1 }, 5558c2ecf20Sopenharmony_ci { TAS2770_INT_CFG, 0x05 }, 5568c2ecf20Sopenharmony_ci { TAS2770_MISC_IRQ, 0x81 }, 5578c2ecf20Sopenharmony_ci { TAS2770_CLK_CGF, 0x0c }, 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci}; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_cistatic bool tas2770_volatile(struct device *dev, unsigned int reg) 5628c2ecf20Sopenharmony_ci{ 5638c2ecf20Sopenharmony_ci switch (reg) { 5648c2ecf20Sopenharmony_ci case TAS2770_PAGE: /* regmap implementation requires this */ 5658c2ecf20Sopenharmony_ci case TAS2770_SW_RST: /* always clears after write */ 5668c2ecf20Sopenharmony_ci case TAS2770_BO_PRV_REG0:/* has a self clearing bit */ 5678c2ecf20Sopenharmony_ci case TAS2770_LVE_INT_REG0: 5688c2ecf20Sopenharmony_ci case TAS2770_LVE_INT_REG1: 5698c2ecf20Sopenharmony_ci case TAS2770_LAT_INT_REG0:/* Sticky interrupt flags */ 5708c2ecf20Sopenharmony_ci case TAS2770_LAT_INT_REG1:/* Sticky interrupt flags */ 5718c2ecf20Sopenharmony_ci case TAS2770_VBAT_MSB: 5728c2ecf20Sopenharmony_ci case TAS2770_VBAT_LSB: 5738c2ecf20Sopenharmony_ci case TAS2770_TEMP_MSB: 5748c2ecf20Sopenharmony_ci case TAS2770_TEMP_LSB: 5758c2ecf20Sopenharmony_ci return true; 5768c2ecf20Sopenharmony_ci } 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci return false; 5798c2ecf20Sopenharmony_ci} 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_cistatic bool tas2770_writeable(struct device *dev, unsigned int reg) 5828c2ecf20Sopenharmony_ci{ 5838c2ecf20Sopenharmony_ci switch (reg) { 5848c2ecf20Sopenharmony_ci case TAS2770_LVE_INT_REG0: 5858c2ecf20Sopenharmony_ci case TAS2770_LVE_INT_REG1: 5868c2ecf20Sopenharmony_ci case TAS2770_LAT_INT_REG0: 5878c2ecf20Sopenharmony_ci case TAS2770_LAT_INT_REG1: 5888c2ecf20Sopenharmony_ci case TAS2770_VBAT_MSB: 5898c2ecf20Sopenharmony_ci case TAS2770_VBAT_LSB: 5908c2ecf20Sopenharmony_ci case TAS2770_TEMP_MSB: 5918c2ecf20Sopenharmony_ci case TAS2770_TEMP_LSB: 5928c2ecf20Sopenharmony_ci case TAS2770_TDM_CLK_DETC: 5938c2ecf20Sopenharmony_ci case TAS2770_REV_AND_GPID: 5948c2ecf20Sopenharmony_ci return false; 5958c2ecf20Sopenharmony_ci } 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci return true; 5988c2ecf20Sopenharmony_ci} 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_cistatic const struct regmap_range_cfg tas2770_regmap_ranges[] = { 6018c2ecf20Sopenharmony_ci { 6028c2ecf20Sopenharmony_ci .range_min = 0, 6038c2ecf20Sopenharmony_ci .range_max = 1 * 128, 6048c2ecf20Sopenharmony_ci .selector_reg = TAS2770_PAGE, 6058c2ecf20Sopenharmony_ci .selector_mask = 0xff, 6068c2ecf20Sopenharmony_ci .selector_shift = 0, 6078c2ecf20Sopenharmony_ci .window_start = 0, 6088c2ecf20Sopenharmony_ci .window_len = 128, 6098c2ecf20Sopenharmony_ci }, 6108c2ecf20Sopenharmony_ci}; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_cistatic const struct regmap_config tas2770_i2c_regmap = { 6138c2ecf20Sopenharmony_ci .reg_bits = 8, 6148c2ecf20Sopenharmony_ci .val_bits = 8, 6158c2ecf20Sopenharmony_ci .writeable_reg = tas2770_writeable, 6168c2ecf20Sopenharmony_ci .volatile_reg = tas2770_volatile, 6178c2ecf20Sopenharmony_ci .reg_defaults = tas2770_reg_defaults, 6188c2ecf20Sopenharmony_ci .num_reg_defaults = ARRAY_SIZE(tas2770_reg_defaults), 6198c2ecf20Sopenharmony_ci .cache_type = REGCACHE_RBTREE, 6208c2ecf20Sopenharmony_ci .ranges = tas2770_regmap_ranges, 6218c2ecf20Sopenharmony_ci .num_ranges = ARRAY_SIZE(tas2770_regmap_ranges), 6228c2ecf20Sopenharmony_ci .max_register = 1 * 128, 6238c2ecf20Sopenharmony_ci}; 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_cistatic int tas2770_parse_dt(struct device *dev, struct tas2770_priv *tas2770) 6268c2ecf20Sopenharmony_ci{ 6278c2ecf20Sopenharmony_ci int rc = 0; 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci rc = fwnode_property_read_u32(dev->fwnode, "ti,imon-slot-no", 6308c2ecf20Sopenharmony_ci &tas2770->i_sense_slot); 6318c2ecf20Sopenharmony_ci if (rc) { 6328c2ecf20Sopenharmony_ci dev_info(tas2770->dev, "Property %s is missing setting default slot\n", 6338c2ecf20Sopenharmony_ci "ti,imon-slot-no"); 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci tas2770->i_sense_slot = 0; 6368c2ecf20Sopenharmony_ci } 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci rc = fwnode_property_read_u32(dev->fwnode, "ti,vmon-slot-no", 6398c2ecf20Sopenharmony_ci &tas2770->v_sense_slot); 6408c2ecf20Sopenharmony_ci if (rc) { 6418c2ecf20Sopenharmony_ci dev_info(tas2770->dev, "Property %s is missing setting default slot\n", 6428c2ecf20Sopenharmony_ci "ti,vmon-slot-no"); 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci tas2770->v_sense_slot = 2; 6458c2ecf20Sopenharmony_ci } 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci tas2770->sdz_gpio = devm_gpiod_get_optional(dev, "shutdown", GPIOD_OUT_HIGH); 6488c2ecf20Sopenharmony_ci if (IS_ERR(tas2770->sdz_gpio)) { 6498c2ecf20Sopenharmony_ci if (PTR_ERR(tas2770->sdz_gpio) == -EPROBE_DEFER) 6508c2ecf20Sopenharmony_ci return -EPROBE_DEFER; 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci tas2770->sdz_gpio = NULL; 6538c2ecf20Sopenharmony_ci } 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci return 0; 6568c2ecf20Sopenharmony_ci} 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_cistatic int tas2770_i2c_probe(struct i2c_client *client, 6598c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 6608c2ecf20Sopenharmony_ci{ 6618c2ecf20Sopenharmony_ci struct tas2770_priv *tas2770; 6628c2ecf20Sopenharmony_ci int result; 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci tas2770 = devm_kzalloc(&client->dev, sizeof(struct tas2770_priv), 6658c2ecf20Sopenharmony_ci GFP_KERNEL); 6668c2ecf20Sopenharmony_ci if (!tas2770) 6678c2ecf20Sopenharmony_ci return -ENOMEM; 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci tas2770->dev = &client->dev; 6708c2ecf20Sopenharmony_ci i2c_set_clientdata(client, tas2770); 6718c2ecf20Sopenharmony_ci dev_set_drvdata(&client->dev, tas2770); 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci tas2770->regmap = devm_regmap_init_i2c(client, &tas2770_i2c_regmap); 6748c2ecf20Sopenharmony_ci if (IS_ERR(tas2770->regmap)) { 6758c2ecf20Sopenharmony_ci result = PTR_ERR(tas2770->regmap); 6768c2ecf20Sopenharmony_ci dev_err(&client->dev, "Failed to allocate register map: %d\n", 6778c2ecf20Sopenharmony_ci result); 6788c2ecf20Sopenharmony_ci return result; 6798c2ecf20Sopenharmony_ci } 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci if (client->dev.of_node) { 6828c2ecf20Sopenharmony_ci result = tas2770_parse_dt(&client->dev, tas2770); 6838c2ecf20Sopenharmony_ci if (result) { 6848c2ecf20Sopenharmony_ci dev_err(tas2770->dev, "%s: Failed to parse devicetree\n", 6858c2ecf20Sopenharmony_ci __func__); 6868c2ecf20Sopenharmony_ci return result; 6878c2ecf20Sopenharmony_ci } 6888c2ecf20Sopenharmony_ci } 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci tas2770->reset_gpio = devm_gpiod_get_optional(tas2770->dev, "reset", 6918c2ecf20Sopenharmony_ci GPIOD_OUT_HIGH); 6928c2ecf20Sopenharmony_ci if (IS_ERR(tas2770->reset_gpio)) { 6938c2ecf20Sopenharmony_ci if (PTR_ERR(tas2770->reset_gpio) == -EPROBE_DEFER) { 6948c2ecf20Sopenharmony_ci tas2770->reset_gpio = NULL; 6958c2ecf20Sopenharmony_ci return -EPROBE_DEFER; 6968c2ecf20Sopenharmony_ci } 6978c2ecf20Sopenharmony_ci } 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci result = tas2770_register_codec(tas2770); 7008c2ecf20Sopenharmony_ci if (result) 7018c2ecf20Sopenharmony_ci dev_err(tas2770->dev, "Register codec failed.\n"); 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci return result; 7048c2ecf20Sopenharmony_ci} 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_cistatic const struct i2c_device_id tas2770_i2c_id[] = { 7078c2ecf20Sopenharmony_ci { "tas2770", 0}, 7088c2ecf20Sopenharmony_ci { } 7098c2ecf20Sopenharmony_ci}; 7108c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, tas2770_i2c_id); 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci#if defined(CONFIG_OF) 7138c2ecf20Sopenharmony_cistatic const struct of_device_id tas2770_of_match[] = { 7148c2ecf20Sopenharmony_ci { .compatible = "ti,tas2770" }, 7158c2ecf20Sopenharmony_ci {}, 7168c2ecf20Sopenharmony_ci}; 7178c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, tas2770_of_match); 7188c2ecf20Sopenharmony_ci#endif 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_cistatic struct i2c_driver tas2770_i2c_driver = { 7218c2ecf20Sopenharmony_ci .driver = { 7228c2ecf20Sopenharmony_ci .name = "tas2770", 7238c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(tas2770_of_match), 7248c2ecf20Sopenharmony_ci }, 7258c2ecf20Sopenharmony_ci .probe = tas2770_i2c_probe, 7268c2ecf20Sopenharmony_ci .id_table = tas2770_i2c_id, 7278c2ecf20Sopenharmony_ci}; 7288c2ecf20Sopenharmony_cimodule_i2c_driver(tas2770_i2c_driver); 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ciMODULE_AUTHOR("Shi Fu <shifu0704@thundersoft.com>"); 7318c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("TAS2770 I2C Smart Amplifier driver"); 7328c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 733