18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci// 38c2ecf20Sopenharmony_ci// Driver for the Texas Instruments TAS2562 CODEC 48c2ecf20Sopenharmony_ci// Copyright (C) 2019 Texas Instruments Inc. 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/module.h> 88c2ecf20Sopenharmony_ci#include <linux/errno.h> 98c2ecf20Sopenharmony_ci#include <linux/device.h> 108c2ecf20Sopenharmony_ci#include <linux/i2c.h> 118c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 128c2ecf20Sopenharmony_ci#include <linux/regmap.h> 138c2ecf20Sopenharmony_ci#include <linux/slab.h> 148c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h> 158c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h> 168c2ecf20Sopenharmony_ci#include <linux/delay.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <sound/pcm.h> 198c2ecf20Sopenharmony_ci#include <sound/pcm_params.h> 208c2ecf20Sopenharmony_ci#include <sound/soc.h> 218c2ecf20Sopenharmony_ci#include <sound/soc-dapm.h> 228c2ecf20Sopenharmony_ci#include <sound/tlv.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include "tas2562.h" 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#define TAS2562_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |\ 278c2ecf20Sopenharmony_ci SNDRV_PCM_FORMAT_S32_LE) 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci/* DVC equation involves floating point math 308c2ecf20Sopenharmony_ci * round(10^(volume in dB/20)*2^30) 318c2ecf20Sopenharmony_ci * so create a lookup table for 2dB step 328c2ecf20Sopenharmony_ci */ 338c2ecf20Sopenharmony_cistatic const unsigned int float_vol_db_lookup[] = { 348c2ecf20Sopenharmony_ci0x00000d43, 0x000010b2, 0x00001505, 0x00001a67, 0x00002151, 358c2ecf20Sopenharmony_ci0x000029f1, 0x000034cd, 0x00004279, 0x000053af, 0x0000695b, 368c2ecf20Sopenharmony_ci0x0000695b, 0x0000a6fa, 0x0000d236, 0x000108a4, 0x00014d2a, 378c2ecf20Sopenharmony_ci0x0001a36e, 0x00021008, 0x000298c0, 0x000344df, 0x00041d8f, 388c2ecf20Sopenharmony_ci0x00052e5a, 0x000685c8, 0x00083621, 0x000a566d, 0x000d03a7, 398c2ecf20Sopenharmony_ci0x0010624d, 0x0014a050, 0x0019f786, 0x0020b0bc, 0x0029279d, 408c2ecf20Sopenharmony_ci0x0033cf8d, 0x004139d3, 0x00521d50, 0x00676044, 0x0082248a, 418c2ecf20Sopenharmony_ci0x00a3d70a, 0x00ce4328, 0x0103ab3d, 0x0146e75d, 0x019b8c27, 428c2ecf20Sopenharmony_ci0x02061b89, 0x028c423f, 0x03352529, 0x0409c2b0, 0x05156d68, 438c2ecf20Sopenharmony_ci0x080e9f96, 0x0a24b062, 0x0cc509ab, 0x10137987, 0x143d1362, 448c2ecf20Sopenharmony_ci0x197a967f, 0x2013739e, 0x28619ae9, 0x32d64617, 0x40000000 458c2ecf20Sopenharmony_ci}; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistruct tas2562_data { 488c2ecf20Sopenharmony_ci struct snd_soc_component *component; 498c2ecf20Sopenharmony_ci struct gpio_desc *sdz_gpio; 508c2ecf20Sopenharmony_ci struct regmap *regmap; 518c2ecf20Sopenharmony_ci struct device *dev; 528c2ecf20Sopenharmony_ci struct i2c_client *client; 538c2ecf20Sopenharmony_ci int v_sense_slot; 548c2ecf20Sopenharmony_ci int i_sense_slot; 558c2ecf20Sopenharmony_ci int volume_lvl; 568c2ecf20Sopenharmony_ci int model_id; 578c2ecf20Sopenharmony_ci}; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cienum tas256x_model { 608c2ecf20Sopenharmony_ci TAS2562, 618c2ecf20Sopenharmony_ci TAS2563, 628c2ecf20Sopenharmony_ci TAS2564, 638c2ecf20Sopenharmony_ci TAS2110, 648c2ecf20Sopenharmony_ci}; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistatic int tas2562_set_bias_level(struct snd_soc_component *component, 678c2ecf20Sopenharmony_ci enum snd_soc_bias_level level) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci struct tas2562_data *tas2562 = 708c2ecf20Sopenharmony_ci snd_soc_component_get_drvdata(component); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci switch (level) { 738c2ecf20Sopenharmony_ci case SND_SOC_BIAS_ON: 748c2ecf20Sopenharmony_ci snd_soc_component_update_bits(component, 758c2ecf20Sopenharmony_ci TAS2562_PWR_CTRL, 768c2ecf20Sopenharmony_ci TAS2562_MODE_MASK, TAS2562_ACTIVE); 778c2ecf20Sopenharmony_ci break; 788c2ecf20Sopenharmony_ci case SND_SOC_BIAS_STANDBY: 798c2ecf20Sopenharmony_ci case SND_SOC_BIAS_PREPARE: 808c2ecf20Sopenharmony_ci snd_soc_component_update_bits(component, 818c2ecf20Sopenharmony_ci TAS2562_PWR_CTRL, 828c2ecf20Sopenharmony_ci TAS2562_MODE_MASK, TAS2562_MUTE); 838c2ecf20Sopenharmony_ci break; 848c2ecf20Sopenharmony_ci case SND_SOC_BIAS_OFF: 858c2ecf20Sopenharmony_ci snd_soc_component_update_bits(component, 868c2ecf20Sopenharmony_ci TAS2562_PWR_CTRL, 878c2ecf20Sopenharmony_ci TAS2562_MODE_MASK, TAS2562_SHUTDOWN); 888c2ecf20Sopenharmony_ci break; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci default: 918c2ecf20Sopenharmony_ci dev_err(tas2562->dev, 928c2ecf20Sopenharmony_ci "wrong power level setting %d\n", level); 938c2ecf20Sopenharmony_ci return -EINVAL; 948c2ecf20Sopenharmony_ci } 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci return 0; 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistatic int tas2562_set_samplerate(struct tas2562_data *tas2562, int samplerate) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci int samp_rate; 1028c2ecf20Sopenharmony_ci int ramp_rate; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci switch (samplerate) { 1058c2ecf20Sopenharmony_ci case 7350: 1068c2ecf20Sopenharmony_ci ramp_rate = TAS2562_TDM_CFG0_RAMPRATE_44_1; 1078c2ecf20Sopenharmony_ci samp_rate = TAS2562_TDM_CFG0_SAMPRATE_7305_8KHZ; 1088c2ecf20Sopenharmony_ci break; 1098c2ecf20Sopenharmony_ci case 8000: 1108c2ecf20Sopenharmony_ci ramp_rate = 0; 1118c2ecf20Sopenharmony_ci samp_rate = TAS2562_TDM_CFG0_SAMPRATE_7305_8KHZ; 1128c2ecf20Sopenharmony_ci break; 1138c2ecf20Sopenharmony_ci case 14700: 1148c2ecf20Sopenharmony_ci ramp_rate = TAS2562_TDM_CFG0_RAMPRATE_44_1; 1158c2ecf20Sopenharmony_ci samp_rate = TAS2562_TDM_CFG0_SAMPRATE_14_7_16KHZ; 1168c2ecf20Sopenharmony_ci break; 1178c2ecf20Sopenharmony_ci case 16000: 1188c2ecf20Sopenharmony_ci ramp_rate = 0; 1198c2ecf20Sopenharmony_ci samp_rate = TAS2562_TDM_CFG0_SAMPRATE_14_7_16KHZ; 1208c2ecf20Sopenharmony_ci break; 1218c2ecf20Sopenharmony_ci case 22050: 1228c2ecf20Sopenharmony_ci ramp_rate = TAS2562_TDM_CFG0_RAMPRATE_44_1; 1238c2ecf20Sopenharmony_ci samp_rate = TAS2562_TDM_CFG0_SAMPRATE_22_05_24KHZ; 1248c2ecf20Sopenharmony_ci break; 1258c2ecf20Sopenharmony_ci case 24000: 1268c2ecf20Sopenharmony_ci ramp_rate = 0; 1278c2ecf20Sopenharmony_ci samp_rate = TAS2562_TDM_CFG0_SAMPRATE_22_05_24KHZ; 1288c2ecf20Sopenharmony_ci break; 1298c2ecf20Sopenharmony_ci case 29400: 1308c2ecf20Sopenharmony_ci ramp_rate = TAS2562_TDM_CFG0_RAMPRATE_44_1; 1318c2ecf20Sopenharmony_ci samp_rate = TAS2562_TDM_CFG0_SAMPRATE_29_4_32KHZ; 1328c2ecf20Sopenharmony_ci break; 1338c2ecf20Sopenharmony_ci case 32000: 1348c2ecf20Sopenharmony_ci ramp_rate = 0; 1358c2ecf20Sopenharmony_ci samp_rate = TAS2562_TDM_CFG0_SAMPRATE_29_4_32KHZ; 1368c2ecf20Sopenharmony_ci break; 1378c2ecf20Sopenharmony_ci case 44100: 1388c2ecf20Sopenharmony_ci ramp_rate = TAS2562_TDM_CFG0_RAMPRATE_44_1; 1398c2ecf20Sopenharmony_ci samp_rate = TAS2562_TDM_CFG0_SAMPRATE_44_1_48KHZ; 1408c2ecf20Sopenharmony_ci break; 1418c2ecf20Sopenharmony_ci case 48000: 1428c2ecf20Sopenharmony_ci ramp_rate = 0; 1438c2ecf20Sopenharmony_ci samp_rate = TAS2562_TDM_CFG0_SAMPRATE_44_1_48KHZ; 1448c2ecf20Sopenharmony_ci break; 1458c2ecf20Sopenharmony_ci case 88200: 1468c2ecf20Sopenharmony_ci ramp_rate = TAS2562_TDM_CFG0_RAMPRATE_44_1; 1478c2ecf20Sopenharmony_ci samp_rate = TAS2562_TDM_CFG0_SAMPRATE_88_2_96KHZ; 1488c2ecf20Sopenharmony_ci break; 1498c2ecf20Sopenharmony_ci case 96000: 1508c2ecf20Sopenharmony_ci ramp_rate = 0; 1518c2ecf20Sopenharmony_ci samp_rate = TAS2562_TDM_CFG0_SAMPRATE_88_2_96KHZ; 1528c2ecf20Sopenharmony_ci break; 1538c2ecf20Sopenharmony_ci case 176400: 1548c2ecf20Sopenharmony_ci ramp_rate = TAS2562_TDM_CFG0_RAMPRATE_44_1; 1558c2ecf20Sopenharmony_ci samp_rate = TAS2562_TDM_CFG0_SAMPRATE_176_4_192KHZ; 1568c2ecf20Sopenharmony_ci break; 1578c2ecf20Sopenharmony_ci case 192000: 1588c2ecf20Sopenharmony_ci ramp_rate = 0; 1598c2ecf20Sopenharmony_ci samp_rate = TAS2562_TDM_CFG0_SAMPRATE_176_4_192KHZ; 1608c2ecf20Sopenharmony_ci break; 1618c2ecf20Sopenharmony_ci default: 1628c2ecf20Sopenharmony_ci dev_info(tas2562->dev, "%s, unsupported sample rate, %d\n", 1638c2ecf20Sopenharmony_ci __func__, samplerate); 1648c2ecf20Sopenharmony_ci return -EINVAL; 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci snd_soc_component_update_bits(tas2562->component, TAS2562_TDM_CFG0, 1688c2ecf20Sopenharmony_ci TAS2562_TDM_CFG0_RAMPRATE_MASK, ramp_rate); 1698c2ecf20Sopenharmony_ci snd_soc_component_update_bits(tas2562->component, TAS2562_TDM_CFG0, 1708c2ecf20Sopenharmony_ci TAS2562_TDM_CFG0_SAMPRATE_MASK, samp_rate); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci return 0; 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_cistatic int tas2562_set_dai_tdm_slot(struct snd_soc_dai *dai, 1768c2ecf20Sopenharmony_ci unsigned int tx_mask, unsigned int rx_mask, 1778c2ecf20Sopenharmony_ci int slots, int slot_width) 1788c2ecf20Sopenharmony_ci{ 1798c2ecf20Sopenharmony_ci struct snd_soc_component *component = dai->component; 1808c2ecf20Sopenharmony_ci struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(component); 1818c2ecf20Sopenharmony_ci int left_slot, right_slot; 1828c2ecf20Sopenharmony_ci int slots_cfg; 1838c2ecf20Sopenharmony_ci int ret; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci if (!tx_mask) { 1868c2ecf20Sopenharmony_ci dev_err(component->dev, "tx masks must not be 0\n"); 1878c2ecf20Sopenharmony_ci return -EINVAL; 1888c2ecf20Sopenharmony_ci } 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci if (slots == 1) { 1918c2ecf20Sopenharmony_ci if (tx_mask != 1) 1928c2ecf20Sopenharmony_ci return -EINVAL; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci left_slot = 0; 1958c2ecf20Sopenharmony_ci right_slot = 0; 1968c2ecf20Sopenharmony_ci } else { 1978c2ecf20Sopenharmony_ci left_slot = __ffs(tx_mask); 1988c2ecf20Sopenharmony_ci tx_mask &= ~(1 << left_slot); 1998c2ecf20Sopenharmony_ci if (tx_mask == 0) { 2008c2ecf20Sopenharmony_ci right_slot = left_slot; 2018c2ecf20Sopenharmony_ci } else { 2028c2ecf20Sopenharmony_ci right_slot = __ffs(tx_mask); 2038c2ecf20Sopenharmony_ci tx_mask &= ~(1 << right_slot); 2048c2ecf20Sopenharmony_ci } 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci slots_cfg = (right_slot << TAS2562_RIGHT_SLOT_SHIFT) | left_slot; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci ret = snd_soc_component_write(component, TAS2562_TDM_CFG3, slots_cfg); 2108c2ecf20Sopenharmony_ci if (ret < 0) 2118c2ecf20Sopenharmony_ci return ret; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci switch (slot_width) { 2148c2ecf20Sopenharmony_ci case 16: 2158c2ecf20Sopenharmony_ci ret = snd_soc_component_update_bits(component, 2168c2ecf20Sopenharmony_ci TAS2562_TDM_CFG2, 2178c2ecf20Sopenharmony_ci TAS2562_TDM_CFG2_RXLEN_MASK, 2188c2ecf20Sopenharmony_ci TAS2562_TDM_CFG2_RXLEN_16B); 2198c2ecf20Sopenharmony_ci break; 2208c2ecf20Sopenharmony_ci case 24: 2218c2ecf20Sopenharmony_ci ret = snd_soc_component_update_bits(component, 2228c2ecf20Sopenharmony_ci TAS2562_TDM_CFG2, 2238c2ecf20Sopenharmony_ci TAS2562_TDM_CFG2_RXLEN_MASK, 2248c2ecf20Sopenharmony_ci TAS2562_TDM_CFG2_RXLEN_24B); 2258c2ecf20Sopenharmony_ci break; 2268c2ecf20Sopenharmony_ci case 32: 2278c2ecf20Sopenharmony_ci ret = snd_soc_component_update_bits(component, 2288c2ecf20Sopenharmony_ci TAS2562_TDM_CFG2, 2298c2ecf20Sopenharmony_ci TAS2562_TDM_CFG2_RXLEN_MASK, 2308c2ecf20Sopenharmony_ci TAS2562_TDM_CFG2_RXLEN_32B); 2318c2ecf20Sopenharmony_ci break; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci case 0: 2348c2ecf20Sopenharmony_ci /* Do not change slot width */ 2358c2ecf20Sopenharmony_ci break; 2368c2ecf20Sopenharmony_ci default: 2378c2ecf20Sopenharmony_ci dev_err(tas2562->dev, "slot width not supported"); 2388c2ecf20Sopenharmony_ci ret = -EINVAL; 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci if (ret < 0) 2428c2ecf20Sopenharmony_ci return ret; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci ret = snd_soc_component_update_bits(component, TAS2562_TDM_CFG5, 2458c2ecf20Sopenharmony_ci TAS2562_TDM_CFG5_VSNS_SLOT_MASK, 2468c2ecf20Sopenharmony_ci tas2562->v_sense_slot); 2478c2ecf20Sopenharmony_ci if (ret < 0) 2488c2ecf20Sopenharmony_ci return ret; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci ret = snd_soc_component_update_bits(component, TAS2562_TDM_CFG6, 2518c2ecf20Sopenharmony_ci TAS2562_TDM_CFG6_ISNS_SLOT_MASK, 2528c2ecf20Sopenharmony_ci tas2562->i_sense_slot); 2538c2ecf20Sopenharmony_ci if (ret < 0) 2548c2ecf20Sopenharmony_ci return ret; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci return 0; 2578c2ecf20Sopenharmony_ci} 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_cistatic int tas2562_set_bitwidth(struct tas2562_data *tas2562, int bitwidth) 2608c2ecf20Sopenharmony_ci{ 2618c2ecf20Sopenharmony_ci int ret; 2628c2ecf20Sopenharmony_ci int val; 2638c2ecf20Sopenharmony_ci int sense_en; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci switch (bitwidth) { 2668c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S16_LE: 2678c2ecf20Sopenharmony_ci snd_soc_component_update_bits(tas2562->component, 2688c2ecf20Sopenharmony_ci TAS2562_TDM_CFG2, 2698c2ecf20Sopenharmony_ci TAS2562_TDM_CFG2_RXWLEN_MASK, 2708c2ecf20Sopenharmony_ci TAS2562_TDM_CFG2_RXWLEN_16B); 2718c2ecf20Sopenharmony_ci break; 2728c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S24_LE: 2738c2ecf20Sopenharmony_ci snd_soc_component_update_bits(tas2562->component, 2748c2ecf20Sopenharmony_ci TAS2562_TDM_CFG2, 2758c2ecf20Sopenharmony_ci TAS2562_TDM_CFG2_RXWLEN_MASK, 2768c2ecf20Sopenharmony_ci TAS2562_TDM_CFG2_RXWLEN_24B); 2778c2ecf20Sopenharmony_ci break; 2788c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S32_LE: 2798c2ecf20Sopenharmony_ci snd_soc_component_update_bits(tas2562->component, 2808c2ecf20Sopenharmony_ci TAS2562_TDM_CFG2, 2818c2ecf20Sopenharmony_ci TAS2562_TDM_CFG2_RXWLEN_MASK, 2828c2ecf20Sopenharmony_ci TAS2562_TDM_CFG2_RXWLEN_32B); 2838c2ecf20Sopenharmony_ci break; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci default: 2868c2ecf20Sopenharmony_ci dev_info(tas2562->dev, "Unsupported bitwidth format\n"); 2878c2ecf20Sopenharmony_ci return -EINVAL; 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci val = snd_soc_component_read(tas2562->component, TAS2562_PWR_CTRL); 2918c2ecf20Sopenharmony_ci if (val < 0) 2928c2ecf20Sopenharmony_ci return val; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci if (val & (1 << TAS2562_VSENSE_POWER_EN)) 2958c2ecf20Sopenharmony_ci sense_en = 0; 2968c2ecf20Sopenharmony_ci else 2978c2ecf20Sopenharmony_ci sense_en = TAS2562_TDM_CFG5_VSNS_EN; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci ret = snd_soc_component_update_bits(tas2562->component, TAS2562_TDM_CFG5, 3008c2ecf20Sopenharmony_ci TAS2562_TDM_CFG5_VSNS_EN, sense_en); 3018c2ecf20Sopenharmony_ci if (ret < 0) 3028c2ecf20Sopenharmony_ci return ret; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci if (val & (1 << TAS2562_ISENSE_POWER_EN)) 3058c2ecf20Sopenharmony_ci sense_en = 0; 3068c2ecf20Sopenharmony_ci else 3078c2ecf20Sopenharmony_ci sense_en = TAS2562_TDM_CFG6_ISNS_EN; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci ret = snd_soc_component_update_bits(tas2562->component, TAS2562_TDM_CFG6, 3108c2ecf20Sopenharmony_ci TAS2562_TDM_CFG6_ISNS_EN, sense_en); 3118c2ecf20Sopenharmony_ci if (ret < 0) 3128c2ecf20Sopenharmony_ci return ret; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci return 0; 3158c2ecf20Sopenharmony_ci} 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_cistatic int tas2562_hw_params(struct snd_pcm_substream *substream, 3188c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params, 3198c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 3208c2ecf20Sopenharmony_ci{ 3218c2ecf20Sopenharmony_ci struct snd_soc_component *component = dai->component; 3228c2ecf20Sopenharmony_ci struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(component); 3238c2ecf20Sopenharmony_ci int ret; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci ret = tas2562_set_bitwidth(tas2562, params_format(params)); 3268c2ecf20Sopenharmony_ci if (ret) { 3278c2ecf20Sopenharmony_ci dev_err(tas2562->dev, "set bitwidth failed, %d\n", ret); 3288c2ecf20Sopenharmony_ci return ret; 3298c2ecf20Sopenharmony_ci } 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci ret = tas2562_set_samplerate(tas2562, params_rate(params)); 3328c2ecf20Sopenharmony_ci if (ret) 3338c2ecf20Sopenharmony_ci dev_err(tas2562->dev, "set sample rate failed, %d\n", ret); 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci return ret; 3368c2ecf20Sopenharmony_ci} 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_cistatic int tas2562_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) 3398c2ecf20Sopenharmony_ci{ 3408c2ecf20Sopenharmony_ci struct snd_soc_component *component = dai->component; 3418c2ecf20Sopenharmony_ci struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(component); 3428c2ecf20Sopenharmony_ci u8 asi_cfg_1 = 0; 3438c2ecf20Sopenharmony_ci u8 tdm_rx_start_slot = 0; 3448c2ecf20Sopenharmony_ci int ret; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 3478c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_NB_NF: 3488c2ecf20Sopenharmony_ci asi_cfg_1 = 0; 3498c2ecf20Sopenharmony_ci break; 3508c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_IB_NF: 3518c2ecf20Sopenharmony_ci asi_cfg_1 |= TAS2562_TDM_CFG1_RX_FALLING; 3528c2ecf20Sopenharmony_ci break; 3538c2ecf20Sopenharmony_ci default: 3548c2ecf20Sopenharmony_ci dev_err(tas2562->dev, "ASI format Inverse is not found\n"); 3558c2ecf20Sopenharmony_ci return -EINVAL; 3568c2ecf20Sopenharmony_ci } 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci ret = snd_soc_component_update_bits(component, TAS2562_TDM_CFG1, 3598c2ecf20Sopenharmony_ci TAS2562_TDM_CFG1_RX_EDGE_MASK, 3608c2ecf20Sopenharmony_ci asi_cfg_1); 3618c2ecf20Sopenharmony_ci if (ret < 0) { 3628c2ecf20Sopenharmony_ci dev_err(tas2562->dev, "Failed to set RX edge\n"); 3638c2ecf20Sopenharmony_ci return ret; 3648c2ecf20Sopenharmony_ci } 3658c2ecf20Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 3668c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_LEFT_J: 3678c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_DSP_B: 3688c2ecf20Sopenharmony_ci tdm_rx_start_slot = 0; 3698c2ecf20Sopenharmony_ci break; 3708c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_I2S: 3718c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_DSP_A: 3728c2ecf20Sopenharmony_ci tdm_rx_start_slot = 1; 3738c2ecf20Sopenharmony_ci break; 3748c2ecf20Sopenharmony_ci default: 3758c2ecf20Sopenharmony_ci dev_err(tas2562->dev, 3768c2ecf20Sopenharmony_ci "DAI Format is not found, fmt=0x%x\n", fmt); 3778c2ecf20Sopenharmony_ci return -EINVAL; 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci ret = snd_soc_component_update_bits(component, TAS2562_TDM_CFG1, 3818c2ecf20Sopenharmony_ci TAS2562_RX_OFF_MASK, (tdm_rx_start_slot << 1)); 3828c2ecf20Sopenharmony_ci if (ret < 0) 3838c2ecf20Sopenharmony_ci return ret; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci return 0; 3868c2ecf20Sopenharmony_ci} 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_cistatic int tas2562_mute(struct snd_soc_dai *dai, int mute, int direction) 3898c2ecf20Sopenharmony_ci{ 3908c2ecf20Sopenharmony_ci struct snd_soc_component *component = dai->component; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci return snd_soc_component_update_bits(component, TAS2562_PWR_CTRL, 3938c2ecf20Sopenharmony_ci TAS2562_MODE_MASK, 3948c2ecf20Sopenharmony_ci mute ? TAS2562_MUTE : 0); 3958c2ecf20Sopenharmony_ci} 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_cistatic int tas2562_codec_probe(struct snd_soc_component *component) 3988c2ecf20Sopenharmony_ci{ 3998c2ecf20Sopenharmony_ci struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(component); 4008c2ecf20Sopenharmony_ci int ret; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci tas2562->component = component; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci if (tas2562->sdz_gpio) 4058c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(tas2562->sdz_gpio, 1); 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci ret = snd_soc_component_update_bits(component, TAS2562_PWR_CTRL, 4088c2ecf20Sopenharmony_ci TAS2562_MODE_MASK, TAS2562_MUTE); 4098c2ecf20Sopenharmony_ci if (ret < 0) 4108c2ecf20Sopenharmony_ci return ret; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci return 0; 4138c2ecf20Sopenharmony_ci} 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 4168c2ecf20Sopenharmony_cistatic int tas2562_suspend(struct snd_soc_component *component) 4178c2ecf20Sopenharmony_ci{ 4188c2ecf20Sopenharmony_ci struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(component); 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci regcache_cache_only(tas2562->regmap, true); 4218c2ecf20Sopenharmony_ci regcache_mark_dirty(tas2562->regmap); 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci if (tas2562->sdz_gpio) 4248c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(tas2562->sdz_gpio, 0); 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci return 0; 4278c2ecf20Sopenharmony_ci} 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_cistatic int tas2562_resume(struct snd_soc_component *component) 4308c2ecf20Sopenharmony_ci{ 4318c2ecf20Sopenharmony_ci struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(component); 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci if (tas2562->sdz_gpio) 4348c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(tas2562->sdz_gpio, 1); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci regcache_cache_only(tas2562->regmap, false); 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci return regcache_sync(tas2562->regmap); 4398c2ecf20Sopenharmony_ci} 4408c2ecf20Sopenharmony_ci#else 4418c2ecf20Sopenharmony_ci#define tas2562_suspend NULL 4428c2ecf20Sopenharmony_ci#define tas2562_resume NULL 4438c2ecf20Sopenharmony_ci#endif 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_cistatic const char * const tas2562_ASI1_src[] = { 4468c2ecf20Sopenharmony_ci "I2C offset", "Left", "Right", "LeftRightDiv2", 4478c2ecf20Sopenharmony_ci}; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(tas2562_ASI1_src_enum, TAS2562_TDM_CFG2, 4, 4508c2ecf20Sopenharmony_ci tas2562_ASI1_src); 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new tas2562_asi1_mux = 4538c2ecf20Sopenharmony_ci SOC_DAPM_ENUM("ASI1 Source", tas2562_ASI1_src_enum); 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_cistatic int tas2562_dac_event(struct snd_soc_dapm_widget *w, 4568c2ecf20Sopenharmony_ci struct snd_kcontrol *kcontrol, int event) 4578c2ecf20Sopenharmony_ci{ 4588c2ecf20Sopenharmony_ci struct snd_soc_component *component = 4598c2ecf20Sopenharmony_ci snd_soc_dapm_to_component(w->dapm); 4608c2ecf20Sopenharmony_ci struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(component); 4618c2ecf20Sopenharmony_ci int ret; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci switch (event) { 4648c2ecf20Sopenharmony_ci case SND_SOC_DAPM_POST_PMU: 4658c2ecf20Sopenharmony_ci ret = snd_soc_component_update_bits(component, 4668c2ecf20Sopenharmony_ci TAS2562_PWR_CTRL, 4678c2ecf20Sopenharmony_ci TAS2562_MODE_MASK, 4688c2ecf20Sopenharmony_ci TAS2562_MUTE); 4698c2ecf20Sopenharmony_ci if (ret) 4708c2ecf20Sopenharmony_ci goto end; 4718c2ecf20Sopenharmony_ci break; 4728c2ecf20Sopenharmony_ci case SND_SOC_DAPM_PRE_PMD: 4738c2ecf20Sopenharmony_ci ret = snd_soc_component_update_bits(component, 4748c2ecf20Sopenharmony_ci TAS2562_PWR_CTRL, 4758c2ecf20Sopenharmony_ci TAS2562_MODE_MASK, 4768c2ecf20Sopenharmony_ci TAS2562_SHUTDOWN); 4778c2ecf20Sopenharmony_ci if (ret) 4788c2ecf20Sopenharmony_ci goto end; 4798c2ecf20Sopenharmony_ci break; 4808c2ecf20Sopenharmony_ci default: 4818c2ecf20Sopenharmony_ci dev_err(tas2562->dev, "Not supported evevt\n"); 4828c2ecf20Sopenharmony_ci return -EINVAL; 4838c2ecf20Sopenharmony_ci } 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ciend: 4868c2ecf20Sopenharmony_ci if (ret < 0) 4878c2ecf20Sopenharmony_ci return ret; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci return 0; 4908c2ecf20Sopenharmony_ci} 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_cistatic int tas2562_volume_control_get(struct snd_kcontrol *kcontrol, 4938c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 4948c2ecf20Sopenharmony_ci{ 4958c2ecf20Sopenharmony_ci struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 4968c2ecf20Sopenharmony_ci struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(component); 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = tas2562->volume_lvl; 4998c2ecf20Sopenharmony_ci return 0; 5008c2ecf20Sopenharmony_ci} 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_cistatic int tas2562_volume_control_put(struct snd_kcontrol *kcontrol, 5038c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 5048c2ecf20Sopenharmony_ci{ 5058c2ecf20Sopenharmony_ci struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 5068c2ecf20Sopenharmony_ci struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(component); 5078c2ecf20Sopenharmony_ci int ret; 5088c2ecf20Sopenharmony_ci u32 reg_val; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci reg_val = float_vol_db_lookup[ucontrol->value.integer.value[0]/2]; 5118c2ecf20Sopenharmony_ci ret = snd_soc_component_write(component, TAS2562_DVC_CFG4, 5128c2ecf20Sopenharmony_ci (reg_val & 0xff)); 5138c2ecf20Sopenharmony_ci if (ret) 5148c2ecf20Sopenharmony_ci return ret; 5158c2ecf20Sopenharmony_ci ret = snd_soc_component_write(component, TAS2562_DVC_CFG3, 5168c2ecf20Sopenharmony_ci ((reg_val >> 8) & 0xff)); 5178c2ecf20Sopenharmony_ci if (ret) 5188c2ecf20Sopenharmony_ci return ret; 5198c2ecf20Sopenharmony_ci ret = snd_soc_component_write(component, TAS2562_DVC_CFG2, 5208c2ecf20Sopenharmony_ci ((reg_val >> 16) & 0xff)); 5218c2ecf20Sopenharmony_ci if (ret) 5228c2ecf20Sopenharmony_ci return ret; 5238c2ecf20Sopenharmony_ci ret = snd_soc_component_write(component, TAS2562_DVC_CFG1, 5248c2ecf20Sopenharmony_ci ((reg_val >> 24) & 0xff)); 5258c2ecf20Sopenharmony_ci if (ret) 5268c2ecf20Sopenharmony_ci return ret; 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci tas2562->volume_lvl = ucontrol->value.integer.value[0]; 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci return ret; 5318c2ecf20Sopenharmony_ci} 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci/* Digital Volume Control. From 0 dB to -110 dB in 1 dB steps */ 5348c2ecf20Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(dvc_tlv, -11000, 100, 0); 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_cistatic DECLARE_TLV_DB_SCALE(tas2562_dac_tlv, 850, 50, 0); 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new isense_switch = 5398c2ecf20Sopenharmony_ci SOC_DAPM_SINGLE("Switch", TAS2562_PWR_CTRL, TAS2562_ISENSE_POWER_EN, 5408c2ecf20Sopenharmony_ci 1, 1); 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new vsense_switch = 5438c2ecf20Sopenharmony_ci SOC_DAPM_SINGLE("Switch", TAS2562_PWR_CTRL, TAS2562_VSENSE_POWER_EN, 5448c2ecf20Sopenharmony_ci 1, 1); 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new tas2562_snd_controls[] = { 5478c2ecf20Sopenharmony_ci SOC_SINGLE_TLV("Amp Gain Volume", TAS2562_PB_CFG1, 1, 0x1c, 0, 5488c2ecf20Sopenharmony_ci tas2562_dac_tlv), 5498c2ecf20Sopenharmony_ci { 5508c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 5518c2ecf20Sopenharmony_ci .name = "Digital Volume Control", 5528c2ecf20Sopenharmony_ci .index = 0, 5538c2ecf20Sopenharmony_ci .tlv.p = dvc_tlv, 5548c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | SNDRV_CTL_ELEM_ACCESS_READWRITE, 5558c2ecf20Sopenharmony_ci .info = snd_soc_info_volsw, 5568c2ecf20Sopenharmony_ci .get = tas2562_volume_control_get, 5578c2ecf20Sopenharmony_ci .put = tas2562_volume_control_put, 5588c2ecf20Sopenharmony_ci .private_value = SOC_SINGLE_VALUE(TAS2562_DVC_CFG1, 0, 110, 0, 0), 5598c2ecf20Sopenharmony_ci }, 5608c2ecf20Sopenharmony_ci}; 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget tas2110_dapm_widgets[] = { 5638c2ecf20Sopenharmony_ci SND_SOC_DAPM_AIF_IN("ASI1", "ASI1 Playback", 0, SND_SOC_NOPM, 0, 0), 5648c2ecf20Sopenharmony_ci SND_SOC_DAPM_MUX("ASI1 Sel", SND_SOC_NOPM, 0, 0, &tas2562_asi1_mux), 5658c2ecf20Sopenharmony_ci SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0, tas2562_dac_event, 5668c2ecf20Sopenharmony_ci SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), 5678c2ecf20Sopenharmony_ci SND_SOC_DAPM_OUTPUT("OUT"), 5688c2ecf20Sopenharmony_ci}; 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route tas2110_audio_map[] = { 5718c2ecf20Sopenharmony_ci {"ASI1 Sel", "I2C offset", "ASI1"}, 5728c2ecf20Sopenharmony_ci {"ASI1 Sel", "Left", "ASI1"}, 5738c2ecf20Sopenharmony_ci {"ASI1 Sel", "Right", "ASI1"}, 5748c2ecf20Sopenharmony_ci {"ASI1 Sel", "LeftRightDiv2", "ASI1"}, 5758c2ecf20Sopenharmony_ci { "DAC", NULL, "ASI1 Sel" }, 5768c2ecf20Sopenharmony_ci { "OUT", NULL, "DAC" }, 5778c2ecf20Sopenharmony_ci}; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver soc_component_dev_tas2110 = { 5808c2ecf20Sopenharmony_ci .probe = tas2562_codec_probe, 5818c2ecf20Sopenharmony_ci .suspend = tas2562_suspend, 5828c2ecf20Sopenharmony_ci .resume = tas2562_resume, 5838c2ecf20Sopenharmony_ci .set_bias_level = tas2562_set_bias_level, 5848c2ecf20Sopenharmony_ci .controls = tas2562_snd_controls, 5858c2ecf20Sopenharmony_ci .num_controls = ARRAY_SIZE(tas2562_snd_controls), 5868c2ecf20Sopenharmony_ci .dapm_widgets = tas2110_dapm_widgets, 5878c2ecf20Sopenharmony_ci .num_dapm_widgets = ARRAY_SIZE(tas2110_dapm_widgets), 5888c2ecf20Sopenharmony_ci .dapm_routes = tas2110_audio_map, 5898c2ecf20Sopenharmony_ci .num_dapm_routes = ARRAY_SIZE(tas2110_audio_map), 5908c2ecf20Sopenharmony_ci .idle_bias_on = 1, 5918c2ecf20Sopenharmony_ci .use_pmdown_time = 1, 5928c2ecf20Sopenharmony_ci .endianness = 1, 5938c2ecf20Sopenharmony_ci .non_legacy_dai_naming = 1, 5948c2ecf20Sopenharmony_ci}; 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget tas2562_dapm_widgets[] = { 5978c2ecf20Sopenharmony_ci SND_SOC_DAPM_AIF_IN("ASI1", "ASI1 Playback", 0, SND_SOC_NOPM, 0, 0), 5988c2ecf20Sopenharmony_ci SND_SOC_DAPM_MUX("ASI1 Sel", SND_SOC_NOPM, 0, 0, &tas2562_asi1_mux), 5998c2ecf20Sopenharmony_ci SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0, tas2562_dac_event, 6008c2ecf20Sopenharmony_ci SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), 6018c2ecf20Sopenharmony_ci SND_SOC_DAPM_SWITCH("ISENSE", TAS2562_PWR_CTRL, 3, 1, &isense_switch), 6028c2ecf20Sopenharmony_ci SND_SOC_DAPM_SWITCH("VSENSE", TAS2562_PWR_CTRL, 2, 1, &vsense_switch), 6038c2ecf20Sopenharmony_ci SND_SOC_DAPM_SIGGEN("VMON"), 6048c2ecf20Sopenharmony_ci SND_SOC_DAPM_SIGGEN("IMON"), 6058c2ecf20Sopenharmony_ci SND_SOC_DAPM_OUTPUT("OUT"), 6068c2ecf20Sopenharmony_ci}; 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route tas2562_audio_map[] = { 6098c2ecf20Sopenharmony_ci {"ASI1 Sel", "I2C offset", "ASI1"}, 6108c2ecf20Sopenharmony_ci {"ASI1 Sel", "Left", "ASI1"}, 6118c2ecf20Sopenharmony_ci {"ASI1 Sel", "Right", "ASI1"}, 6128c2ecf20Sopenharmony_ci {"ASI1 Sel", "LeftRightDiv2", "ASI1"}, 6138c2ecf20Sopenharmony_ci { "DAC", NULL, "ASI1 Sel" }, 6148c2ecf20Sopenharmony_ci { "OUT", NULL, "DAC" }, 6158c2ecf20Sopenharmony_ci {"ISENSE", "Switch", "IMON"}, 6168c2ecf20Sopenharmony_ci {"VSENSE", "Switch", "VMON"}, 6178c2ecf20Sopenharmony_ci}; 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver soc_component_dev_tas2562 = { 6208c2ecf20Sopenharmony_ci .probe = tas2562_codec_probe, 6218c2ecf20Sopenharmony_ci .suspend = tas2562_suspend, 6228c2ecf20Sopenharmony_ci .resume = tas2562_resume, 6238c2ecf20Sopenharmony_ci .set_bias_level = tas2562_set_bias_level, 6248c2ecf20Sopenharmony_ci .controls = tas2562_snd_controls, 6258c2ecf20Sopenharmony_ci .num_controls = ARRAY_SIZE(tas2562_snd_controls), 6268c2ecf20Sopenharmony_ci .dapm_widgets = tas2562_dapm_widgets, 6278c2ecf20Sopenharmony_ci .num_dapm_widgets = ARRAY_SIZE(tas2562_dapm_widgets), 6288c2ecf20Sopenharmony_ci .dapm_routes = tas2562_audio_map, 6298c2ecf20Sopenharmony_ci .num_dapm_routes = ARRAY_SIZE(tas2562_audio_map), 6308c2ecf20Sopenharmony_ci .idle_bias_on = 1, 6318c2ecf20Sopenharmony_ci .use_pmdown_time = 1, 6328c2ecf20Sopenharmony_ci .endianness = 1, 6338c2ecf20Sopenharmony_ci .non_legacy_dai_naming = 1, 6348c2ecf20Sopenharmony_ci}; 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_cistatic const struct snd_soc_dai_ops tas2562_speaker_dai_ops = { 6378c2ecf20Sopenharmony_ci .hw_params = tas2562_hw_params, 6388c2ecf20Sopenharmony_ci .set_fmt = tas2562_set_dai_fmt, 6398c2ecf20Sopenharmony_ci .set_tdm_slot = tas2562_set_dai_tdm_slot, 6408c2ecf20Sopenharmony_ci .mute_stream = tas2562_mute, 6418c2ecf20Sopenharmony_ci .no_capture_mute = 1, 6428c2ecf20Sopenharmony_ci}; 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_cistatic struct snd_soc_dai_driver tas2562_dai[] = { 6458c2ecf20Sopenharmony_ci { 6468c2ecf20Sopenharmony_ci .name = "tas2562-amplifier", 6478c2ecf20Sopenharmony_ci .id = 0, 6488c2ecf20Sopenharmony_ci .playback = { 6498c2ecf20Sopenharmony_ci .stream_name = "ASI1 Playback", 6508c2ecf20Sopenharmony_ci .channels_min = 2, 6518c2ecf20Sopenharmony_ci .channels_max = 2, 6528c2ecf20Sopenharmony_ci .rates = SNDRV_PCM_RATE_8000_192000, 6538c2ecf20Sopenharmony_ci .formats = TAS2562_FORMATS, 6548c2ecf20Sopenharmony_ci }, 6558c2ecf20Sopenharmony_ci .capture = { 6568c2ecf20Sopenharmony_ci .stream_name = "ASI1 Capture", 6578c2ecf20Sopenharmony_ci .channels_min = 0, 6588c2ecf20Sopenharmony_ci .channels_max = 2, 6598c2ecf20Sopenharmony_ci .rates = SNDRV_PCM_RATE_8000_192000, 6608c2ecf20Sopenharmony_ci .formats = TAS2562_FORMATS, 6618c2ecf20Sopenharmony_ci }, 6628c2ecf20Sopenharmony_ci .ops = &tas2562_speaker_dai_ops, 6638c2ecf20Sopenharmony_ci }, 6648c2ecf20Sopenharmony_ci}; 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_cistatic const struct regmap_range_cfg tas2562_ranges[] = { 6678c2ecf20Sopenharmony_ci { 6688c2ecf20Sopenharmony_ci .range_min = 0, 6698c2ecf20Sopenharmony_ci .range_max = 5 * 128, 6708c2ecf20Sopenharmony_ci .selector_reg = TAS2562_PAGE_CTRL, 6718c2ecf20Sopenharmony_ci .selector_mask = 0xff, 6728c2ecf20Sopenharmony_ci .selector_shift = 0, 6738c2ecf20Sopenharmony_ci .window_start = 0, 6748c2ecf20Sopenharmony_ci .window_len = 128, 6758c2ecf20Sopenharmony_ci }, 6768c2ecf20Sopenharmony_ci}; 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_cistatic const struct reg_default tas2562_reg_defaults[] = { 6798c2ecf20Sopenharmony_ci { TAS2562_PAGE_CTRL, 0x00 }, 6808c2ecf20Sopenharmony_ci { TAS2562_SW_RESET, 0x00 }, 6818c2ecf20Sopenharmony_ci { TAS2562_PWR_CTRL, 0x0e }, 6828c2ecf20Sopenharmony_ci { TAS2562_PB_CFG1, 0x20 }, 6838c2ecf20Sopenharmony_ci { TAS2562_TDM_CFG0, 0x09 }, 6848c2ecf20Sopenharmony_ci { TAS2562_TDM_CFG1, 0x02 }, 6858c2ecf20Sopenharmony_ci { TAS2562_DVC_CFG1, 0x40 }, 6868c2ecf20Sopenharmony_ci { TAS2562_DVC_CFG2, 0x40 }, 6878c2ecf20Sopenharmony_ci { TAS2562_DVC_CFG3, 0x00 }, 6888c2ecf20Sopenharmony_ci { TAS2562_DVC_CFG4, 0x00 }, 6898c2ecf20Sopenharmony_ci}; 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_cistatic const struct regmap_config tas2562_regmap_config = { 6928c2ecf20Sopenharmony_ci .reg_bits = 8, 6938c2ecf20Sopenharmony_ci .val_bits = 8, 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci .max_register = 5 * 128, 6968c2ecf20Sopenharmony_ci .cache_type = REGCACHE_RBTREE, 6978c2ecf20Sopenharmony_ci .reg_defaults = tas2562_reg_defaults, 6988c2ecf20Sopenharmony_ci .num_reg_defaults = ARRAY_SIZE(tas2562_reg_defaults), 6998c2ecf20Sopenharmony_ci .ranges = tas2562_ranges, 7008c2ecf20Sopenharmony_ci .num_ranges = ARRAY_SIZE(tas2562_ranges), 7018c2ecf20Sopenharmony_ci}; 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_cistatic int tas2562_parse_dt(struct tas2562_data *tas2562) 7048c2ecf20Sopenharmony_ci{ 7058c2ecf20Sopenharmony_ci struct device *dev = tas2562->dev; 7068c2ecf20Sopenharmony_ci int ret = 0; 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci tas2562->sdz_gpio = devm_gpiod_get_optional(dev, "shutdown", GPIOD_OUT_HIGH); 7098c2ecf20Sopenharmony_ci if (IS_ERR(tas2562->sdz_gpio)) { 7108c2ecf20Sopenharmony_ci if (PTR_ERR(tas2562->sdz_gpio) == -EPROBE_DEFER) 7118c2ecf20Sopenharmony_ci return -EPROBE_DEFER; 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci tas2562->sdz_gpio = NULL; 7148c2ecf20Sopenharmony_ci } 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci /* 7178c2ecf20Sopenharmony_ci * The shut-down property is deprecated but needs to be checked for 7188c2ecf20Sopenharmony_ci * backwards compatibility. 7198c2ecf20Sopenharmony_ci */ 7208c2ecf20Sopenharmony_ci if (tas2562->sdz_gpio == NULL) { 7218c2ecf20Sopenharmony_ci tas2562->sdz_gpio = devm_gpiod_get_optional(dev, "shut-down", 7228c2ecf20Sopenharmony_ci GPIOD_OUT_HIGH); 7238c2ecf20Sopenharmony_ci if (IS_ERR(tas2562->sdz_gpio)) 7248c2ecf20Sopenharmony_ci if (PTR_ERR(tas2562->sdz_gpio) == -EPROBE_DEFER) 7258c2ecf20Sopenharmony_ci return -EPROBE_DEFER; 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci tas2562->sdz_gpio = NULL; 7288c2ecf20Sopenharmony_ci } 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci if (tas2562->model_id == TAS2110) 7318c2ecf20Sopenharmony_ci return ret; 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci ret = fwnode_property_read_u32(dev->fwnode, "ti,imon-slot-no", 7348c2ecf20Sopenharmony_ci &tas2562->i_sense_slot); 7358c2ecf20Sopenharmony_ci if (ret) { 7368c2ecf20Sopenharmony_ci dev_err(dev, "Property %s is missing setting default slot\n", 7378c2ecf20Sopenharmony_ci "ti,imon-slot-no"); 7388c2ecf20Sopenharmony_ci tas2562->i_sense_slot = 0; 7398c2ecf20Sopenharmony_ci } 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci ret = fwnode_property_read_u32(dev->fwnode, "ti,vmon-slot-no", 7438c2ecf20Sopenharmony_ci &tas2562->v_sense_slot); 7448c2ecf20Sopenharmony_ci if (ret) { 7458c2ecf20Sopenharmony_ci dev_info(dev, "Property %s is missing setting default slot\n", 7468c2ecf20Sopenharmony_ci "ti,vmon-slot-no"); 7478c2ecf20Sopenharmony_ci tas2562->v_sense_slot = 2; 7488c2ecf20Sopenharmony_ci } 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci if (tas2562->v_sense_slot < tas2562->i_sense_slot) { 7518c2ecf20Sopenharmony_ci dev_err(dev, "Vsense slot must be greater than Isense slot\n"); 7528c2ecf20Sopenharmony_ci return -EINVAL; 7538c2ecf20Sopenharmony_ci } 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci return ret; 7568c2ecf20Sopenharmony_ci} 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_cistatic int tas2562_probe(struct i2c_client *client, 7598c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 7608c2ecf20Sopenharmony_ci{ 7618c2ecf20Sopenharmony_ci struct device *dev = &client->dev; 7628c2ecf20Sopenharmony_ci struct tas2562_data *data; 7638c2ecf20Sopenharmony_ci int ret; 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 7668c2ecf20Sopenharmony_ci if (!data) 7678c2ecf20Sopenharmony_ci return -ENOMEM; 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci data->client = client; 7708c2ecf20Sopenharmony_ci data->dev = &client->dev; 7718c2ecf20Sopenharmony_ci data->model_id = id->driver_data; 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci tas2562_parse_dt(data); 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci data->regmap = devm_regmap_init_i2c(client, &tas2562_regmap_config); 7768c2ecf20Sopenharmony_ci if (IS_ERR(data->regmap)) { 7778c2ecf20Sopenharmony_ci ret = PTR_ERR(data->regmap); 7788c2ecf20Sopenharmony_ci dev_err(dev, "failed to allocate register map: %d\n", ret); 7798c2ecf20Sopenharmony_ci return ret; 7808c2ecf20Sopenharmony_ci } 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci dev_set_drvdata(&client->dev, data); 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci if (data->model_id == TAS2110) 7858c2ecf20Sopenharmony_ci return devm_snd_soc_register_component(dev, 7868c2ecf20Sopenharmony_ci &soc_component_dev_tas2110, 7878c2ecf20Sopenharmony_ci tas2562_dai, 7888c2ecf20Sopenharmony_ci ARRAY_SIZE(tas2562_dai)); 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci return devm_snd_soc_register_component(dev, &soc_component_dev_tas2562, 7918c2ecf20Sopenharmony_ci tas2562_dai, 7928c2ecf20Sopenharmony_ci ARRAY_SIZE(tas2562_dai)); 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci} 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_cistatic const struct i2c_device_id tas2562_id[] = { 7978c2ecf20Sopenharmony_ci { "tas2562", TAS2562 }, 7988c2ecf20Sopenharmony_ci { "tas2563", TAS2563 }, 7998c2ecf20Sopenharmony_ci { "tas2564", TAS2564 }, 8008c2ecf20Sopenharmony_ci { "tas2110", TAS2110 }, 8018c2ecf20Sopenharmony_ci { } 8028c2ecf20Sopenharmony_ci}; 8038c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, tas2562_id); 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_cistatic const struct of_device_id tas2562_of_match[] = { 8068c2ecf20Sopenharmony_ci { .compatible = "ti,tas2562", }, 8078c2ecf20Sopenharmony_ci { .compatible = "ti,tas2563", }, 8088c2ecf20Sopenharmony_ci { .compatible = "ti,tas2564", }, 8098c2ecf20Sopenharmony_ci { .compatible = "ti,tas2110", }, 8108c2ecf20Sopenharmony_ci { }, 8118c2ecf20Sopenharmony_ci}; 8128c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, tas2562_of_match); 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_cistatic struct i2c_driver tas2562_i2c_driver = { 8158c2ecf20Sopenharmony_ci .driver = { 8168c2ecf20Sopenharmony_ci .name = "tas2562", 8178c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(tas2562_of_match), 8188c2ecf20Sopenharmony_ci }, 8198c2ecf20Sopenharmony_ci .probe = tas2562_probe, 8208c2ecf20Sopenharmony_ci .id_table = tas2562_id, 8218c2ecf20Sopenharmony_ci}; 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_cimodule_i2c_driver(tas2562_i2c_driver); 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ciMODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>"); 8268c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("TAS2562 Audio amplifier driver"); 8278c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 828