18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci 38c2ecf20Sopenharmony_ci// Copyright (c) 2019 MediaTek Inc. 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci#include <linux/module.h> 68c2ecf20Sopenharmony_ci#include <linux/kernel.h> 78c2ecf20Sopenharmony_ci#include <linux/err.h> 88c2ecf20Sopenharmony_ci#include <linux/i2c.h> 98c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 108c2ecf20Sopenharmony_ci#include <linux/delay.h> 118c2ecf20Sopenharmony_ci#include <sound/soc.h> 128c2ecf20Sopenharmony_ci#include <sound/tlv.h> 138c2ecf20Sopenharmony_ci#include <sound/pcm_params.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include "mt6660.h" 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_cistruct reg_size_table { 188c2ecf20Sopenharmony_ci u32 addr; 198c2ecf20Sopenharmony_ci u8 size; 208c2ecf20Sopenharmony_ci}; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cistatic const struct reg_size_table mt6660_reg_size_table[] = { 238c2ecf20Sopenharmony_ci { MT6660_REG_HPF1_COEF, 4 }, 248c2ecf20Sopenharmony_ci { MT6660_REG_HPF2_COEF, 4 }, 258c2ecf20Sopenharmony_ci { MT6660_REG_TDM_CFG3, 2 }, 268c2ecf20Sopenharmony_ci { MT6660_REG_RESV17, 2 }, 278c2ecf20Sopenharmony_ci { MT6660_REG_RESV23, 2 }, 288c2ecf20Sopenharmony_ci { MT6660_REG_SIGMAX, 2 }, 298c2ecf20Sopenharmony_ci { MT6660_REG_DEVID, 2 }, 308c2ecf20Sopenharmony_ci { MT6660_REG_HCLIP_CTRL, 2 }, 318c2ecf20Sopenharmony_ci { MT6660_REG_DA_GAIN, 2 }, 328c2ecf20Sopenharmony_ci}; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic int mt6660_get_reg_size(uint32_t addr) 358c2ecf20Sopenharmony_ci{ 368c2ecf20Sopenharmony_ci int i; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(mt6660_reg_size_table); i++) { 398c2ecf20Sopenharmony_ci if (mt6660_reg_size_table[i].addr == addr) 408c2ecf20Sopenharmony_ci return mt6660_reg_size_table[i].size; 418c2ecf20Sopenharmony_ci } 428c2ecf20Sopenharmony_ci return 1; 438c2ecf20Sopenharmony_ci} 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic int mt6660_reg_write(void *context, unsigned int reg, unsigned int val) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci struct mt6660_chip *chip = context; 488c2ecf20Sopenharmony_ci int size = mt6660_get_reg_size(reg); 498c2ecf20Sopenharmony_ci u8 reg_data[4]; 508c2ecf20Sopenharmony_ci int i, ret; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci for (i = 0; i < size; i++) 538c2ecf20Sopenharmony_ci reg_data[size - i - 1] = (val >> (8 * i)) & 0xff; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci ret = i2c_smbus_write_i2c_block_data(chip->i2c, reg, size, reg_data); 568c2ecf20Sopenharmony_ci return ret; 578c2ecf20Sopenharmony_ci} 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic int mt6660_reg_read(void *context, unsigned int reg, unsigned int *val) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci struct mt6660_chip *chip = context; 628c2ecf20Sopenharmony_ci int size = mt6660_get_reg_size(reg); 638c2ecf20Sopenharmony_ci int i, ret; 648c2ecf20Sopenharmony_ci u8 data[4]; 658c2ecf20Sopenharmony_ci u32 reg_data = 0; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci ret = i2c_smbus_read_i2c_block_data(chip->i2c, reg, size, data); 688c2ecf20Sopenharmony_ci if (ret < 0) 698c2ecf20Sopenharmony_ci return ret; 708c2ecf20Sopenharmony_ci for (i = 0; i < size; i++) { 718c2ecf20Sopenharmony_ci reg_data <<= 8; 728c2ecf20Sopenharmony_ci reg_data |= data[i]; 738c2ecf20Sopenharmony_ci } 748c2ecf20Sopenharmony_ci *val = reg_data; 758c2ecf20Sopenharmony_ci return 0; 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_cistatic const struct regmap_config mt6660_regmap_config = { 798c2ecf20Sopenharmony_ci .reg_bits = 8, 808c2ecf20Sopenharmony_ci .val_bits = 32, 818c2ecf20Sopenharmony_ci .reg_write = mt6660_reg_write, 828c2ecf20Sopenharmony_ci .reg_read = mt6660_reg_read, 838c2ecf20Sopenharmony_ci}; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic int mt6660_codec_dac_event(struct snd_soc_dapm_widget *w, 868c2ecf20Sopenharmony_ci struct snd_kcontrol *kcontrol, int event) 878c2ecf20Sopenharmony_ci{ 888c2ecf20Sopenharmony_ci if (event == SND_SOC_DAPM_POST_PMU) 898c2ecf20Sopenharmony_ci usleep_range(1000, 1100); 908c2ecf20Sopenharmony_ci return 0; 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistatic int mt6660_codec_classd_event(struct snd_soc_dapm_widget *w, 948c2ecf20Sopenharmony_ci struct snd_kcontrol *kcontrol, int event) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci struct snd_soc_component *component = 978c2ecf20Sopenharmony_ci snd_soc_dapm_to_component(w->dapm); 988c2ecf20Sopenharmony_ci int ret; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci switch (event) { 1018c2ecf20Sopenharmony_ci case SND_SOC_DAPM_PRE_PMU: 1028c2ecf20Sopenharmony_ci dev_dbg(component->dev, 1038c2ecf20Sopenharmony_ci "%s: before classd turn on\n", __func__); 1048c2ecf20Sopenharmony_ci /* config to adaptive mode */ 1058c2ecf20Sopenharmony_ci ret = snd_soc_component_update_bits(component, 1068c2ecf20Sopenharmony_ci MT6660_REG_BST_CTRL, 0x03, 0x03); 1078c2ecf20Sopenharmony_ci if (ret < 0) { 1088c2ecf20Sopenharmony_ci dev_err(component->dev, "config mode adaptive fail\n"); 1098c2ecf20Sopenharmony_ci return ret; 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci break; 1128c2ecf20Sopenharmony_ci case SND_SOC_DAPM_POST_PMU: 1138c2ecf20Sopenharmony_ci /* voltage sensing enable */ 1148c2ecf20Sopenharmony_ci ret = snd_soc_component_update_bits(component, 1158c2ecf20Sopenharmony_ci MT6660_REG_RESV7, 0x04, 0x04); 1168c2ecf20Sopenharmony_ci if (ret < 0) { 1178c2ecf20Sopenharmony_ci dev_err(component->dev, 1188c2ecf20Sopenharmony_ci "enable voltage sensing fail\n"); 1198c2ecf20Sopenharmony_ci return ret; 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci dev_dbg(component->dev, "Amp on\n"); 1228c2ecf20Sopenharmony_ci break; 1238c2ecf20Sopenharmony_ci case SND_SOC_DAPM_PRE_PMD: 1248c2ecf20Sopenharmony_ci dev_dbg(component->dev, "Amp off\n"); 1258c2ecf20Sopenharmony_ci /* voltage sensing disable */ 1268c2ecf20Sopenharmony_ci ret = snd_soc_component_update_bits(component, 1278c2ecf20Sopenharmony_ci MT6660_REG_RESV7, 0x04, 0x00); 1288c2ecf20Sopenharmony_ci if (ret < 0) { 1298c2ecf20Sopenharmony_ci dev_err(component->dev, 1308c2ecf20Sopenharmony_ci "disable voltage sensing fail\n"); 1318c2ecf20Sopenharmony_ci return ret; 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci /* pop-noise improvement 1 */ 1348c2ecf20Sopenharmony_ci ret = snd_soc_component_update_bits(component, 1358c2ecf20Sopenharmony_ci MT6660_REG_RESV10, 0x10, 0x10); 1368c2ecf20Sopenharmony_ci if (ret < 0) { 1378c2ecf20Sopenharmony_ci dev_err(component->dev, 1388c2ecf20Sopenharmony_ci "pop-noise improvement 1 fail\n"); 1398c2ecf20Sopenharmony_ci return ret; 1408c2ecf20Sopenharmony_ci } 1418c2ecf20Sopenharmony_ci break; 1428c2ecf20Sopenharmony_ci case SND_SOC_DAPM_POST_PMD: 1438c2ecf20Sopenharmony_ci dev_dbg(component->dev, 1448c2ecf20Sopenharmony_ci "%s: after classd turn off\n", __func__); 1458c2ecf20Sopenharmony_ci /* pop-noise improvement 2 */ 1468c2ecf20Sopenharmony_ci ret = snd_soc_component_update_bits(component, 1478c2ecf20Sopenharmony_ci MT6660_REG_RESV10, 0x10, 0x00); 1488c2ecf20Sopenharmony_ci if (ret < 0) { 1498c2ecf20Sopenharmony_ci dev_err(component->dev, 1508c2ecf20Sopenharmony_ci "pop-noise improvement 2 fail\n"); 1518c2ecf20Sopenharmony_ci return ret; 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci /* config to off mode */ 1548c2ecf20Sopenharmony_ci ret = snd_soc_component_update_bits(component, 1558c2ecf20Sopenharmony_ci MT6660_REG_BST_CTRL, 0x03, 0x00); 1568c2ecf20Sopenharmony_ci if (ret < 0) { 1578c2ecf20Sopenharmony_ci dev_err(component->dev, "config mode off fail\n"); 1588c2ecf20Sopenharmony_ci return ret; 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci break; 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci return 0; 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget mt6660_component_dapm_widgets[] = { 1668c2ecf20Sopenharmony_ci SND_SOC_DAPM_DAC_E("DAC", NULL, MT6660_REG_PLL_CFG1, 1678c2ecf20Sopenharmony_ci 0, 1, mt6660_codec_dac_event, SND_SOC_DAPM_POST_PMU), 1688c2ecf20Sopenharmony_ci SND_SOC_DAPM_ADC("VI ADC", NULL, SND_SOC_NOPM, 0, 0), 1698c2ecf20Sopenharmony_ci SND_SOC_DAPM_PGA("PGA", SND_SOC_NOPM, 0, 0, NULL, 0), 1708c2ecf20Sopenharmony_ci SND_SOC_DAPM_OUT_DRV_E("ClassD", MT6660_REG_SYSTEM_CTRL, 2, 0, 1718c2ecf20Sopenharmony_ci NULL, 0, mt6660_codec_classd_event, 1728c2ecf20Sopenharmony_ci SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | 1738c2ecf20Sopenharmony_ci SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), 1748c2ecf20Sopenharmony_ci SND_SOC_DAPM_OUTPUT("OUTP"), 1758c2ecf20Sopenharmony_ci SND_SOC_DAPM_OUTPUT("OUTN"), 1768c2ecf20Sopenharmony_ci}; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route mt6660_component_dapm_routes[] = { 1798c2ecf20Sopenharmony_ci { "DAC", NULL, "aif_playback" }, 1808c2ecf20Sopenharmony_ci { "PGA", NULL, "DAC" }, 1818c2ecf20Sopenharmony_ci { "ClassD", NULL, "PGA" }, 1828c2ecf20Sopenharmony_ci { "OUTP", NULL, "ClassD" }, 1838c2ecf20Sopenharmony_ci { "OUTN", NULL, "ClassD" }, 1848c2ecf20Sopenharmony_ci { "VI ADC", NULL, "ClassD" }, 1858c2ecf20Sopenharmony_ci { "aif_capture", NULL, "VI ADC" }, 1868c2ecf20Sopenharmony_ci}; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cistatic int mt6660_component_get_volsw(struct snd_kcontrol *kcontrol, 1898c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 1908c2ecf20Sopenharmony_ci{ 1918c2ecf20Sopenharmony_ci struct snd_soc_component *component = 1928c2ecf20Sopenharmony_ci snd_soc_kcontrol_component(kcontrol); 1938c2ecf20Sopenharmony_ci struct mt6660_chip *chip = (struct mt6660_chip *) 1948c2ecf20Sopenharmony_ci snd_soc_component_get_drvdata(component); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = chip->chip_rev & 0x0f; 1978c2ecf20Sopenharmony_ci return 0; 1988c2ecf20Sopenharmony_ci} 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(vol_ctl_tlv, -1155, 5, 0); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new mt6660_component_snd_controls[] = { 2038c2ecf20Sopenharmony_ci SOC_SINGLE_TLV("Digital Volume", MT6660_REG_VOL_CTRL, 0, 255, 2048c2ecf20Sopenharmony_ci 1, vol_ctl_tlv), 2058c2ecf20Sopenharmony_ci SOC_SINGLE("Hard Clip Switch", MT6660_REG_HCLIP_CTRL, 8, 1, 0), 2068c2ecf20Sopenharmony_ci SOC_SINGLE("Clip Switch", MT6660_REG_SPS_CTRL, 0, 1, 0), 2078c2ecf20Sopenharmony_ci SOC_SINGLE("Boost Mode", MT6660_REG_BST_CTRL, 0, 3, 0), 2088c2ecf20Sopenharmony_ci SOC_SINGLE("DRE Switch", MT6660_REG_DRE_CTRL, 0, 1, 0), 2098c2ecf20Sopenharmony_ci SOC_SINGLE("DC Protect Switch", MT6660_REG_DC_PROTECT_CTRL, 3, 1, 0), 2108c2ecf20Sopenharmony_ci SOC_SINGLE("Data Output Left Channel Selection", 2118c2ecf20Sopenharmony_ci MT6660_REG_DATAO_SEL, 3, 7, 0), 2128c2ecf20Sopenharmony_ci SOC_SINGLE("Data Output Right Channel Selection", 2138c2ecf20Sopenharmony_ci MT6660_REG_DATAO_SEL, 0, 7, 0), 2148c2ecf20Sopenharmony_ci SOC_SINGLE_EXT("T0 SEL", MT6660_REG_CALI_T0, 0, 7, 0, 2158c2ecf20Sopenharmony_ci snd_soc_get_volsw, NULL), 2168c2ecf20Sopenharmony_ci SOC_SINGLE_EXT("Chip Rev", MT6660_REG_DEVID, 8, 15, 0, 2178c2ecf20Sopenharmony_ci mt6660_component_get_volsw, NULL), 2188c2ecf20Sopenharmony_ci}; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_cistatic int _mt6660_chip_power_on(struct mt6660_chip *chip, int on_off) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci return regmap_write_bits(chip->regmap, MT6660_REG_SYSTEM_CTRL, 2238c2ecf20Sopenharmony_ci 0x01, on_off ? 0x00 : 0x01); 2248c2ecf20Sopenharmony_ci} 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_cistruct reg_table { 2278c2ecf20Sopenharmony_ci uint32_t addr; 2288c2ecf20Sopenharmony_ci uint32_t mask; 2298c2ecf20Sopenharmony_ci uint32_t val; 2308c2ecf20Sopenharmony_ci}; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_cistatic const struct reg_table mt6660_setting_table[] = { 2338c2ecf20Sopenharmony_ci { 0x20, 0x80, 0x00 }, 2348c2ecf20Sopenharmony_ci { 0x30, 0x01, 0x00 }, 2358c2ecf20Sopenharmony_ci { 0x50, 0x1c, 0x04 }, 2368c2ecf20Sopenharmony_ci { 0xB1, 0x0c, 0x00 }, 2378c2ecf20Sopenharmony_ci { 0xD3, 0x03, 0x03 }, 2388c2ecf20Sopenharmony_ci { 0xE0, 0x01, 0x00 }, 2398c2ecf20Sopenharmony_ci { 0x98, 0x44, 0x04 }, 2408c2ecf20Sopenharmony_ci { 0xB9, 0xff, 0x82 }, 2418c2ecf20Sopenharmony_ci { 0xB7, 0x7777, 0x7273 }, 2428c2ecf20Sopenharmony_ci { 0xB6, 0x07, 0x03 }, 2438c2ecf20Sopenharmony_ci { 0x6B, 0xe0, 0x20 }, 2448c2ecf20Sopenharmony_ci { 0x07, 0xff, 0x70 }, 2458c2ecf20Sopenharmony_ci { 0xBB, 0xff, 0x20 }, 2468c2ecf20Sopenharmony_ci { 0x69, 0xff, 0x40 }, 2478c2ecf20Sopenharmony_ci { 0xBD, 0xffff, 0x17f8 }, 2488c2ecf20Sopenharmony_ci { 0x70, 0xff, 0x15 }, 2498c2ecf20Sopenharmony_ci { 0x7C, 0xff, 0x00 }, 2508c2ecf20Sopenharmony_ci { 0x46, 0xff, 0x1d }, 2518c2ecf20Sopenharmony_ci { 0x1A, 0xffffffff, 0x7fdb7ffe }, 2528c2ecf20Sopenharmony_ci { 0x1B, 0xffffffff, 0x7fdb7ffe }, 2538c2ecf20Sopenharmony_ci { 0x51, 0xff, 0x58 }, 2548c2ecf20Sopenharmony_ci { 0xA2, 0xff, 0xce }, 2558c2ecf20Sopenharmony_ci { 0x33, 0xffff, 0x7fff }, 2568c2ecf20Sopenharmony_ci { 0x4C, 0xffff, 0x0116 }, 2578c2ecf20Sopenharmony_ci { 0x16, 0x1800, 0x0800 }, 2588c2ecf20Sopenharmony_ci { 0x68, 0x1f, 0x07 }, 2598c2ecf20Sopenharmony_ci}; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_cistatic int mt6660_component_setting(struct snd_soc_component *component) 2628c2ecf20Sopenharmony_ci{ 2638c2ecf20Sopenharmony_ci struct mt6660_chip *chip = snd_soc_component_get_drvdata(component); 2648c2ecf20Sopenharmony_ci int ret = 0; 2658c2ecf20Sopenharmony_ci size_t i = 0; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci ret = _mt6660_chip_power_on(chip, 1); 2688c2ecf20Sopenharmony_ci if (ret < 0) { 2698c2ecf20Sopenharmony_ci dev_err(component->dev, "%s chip power on failed\n", __func__); 2708c2ecf20Sopenharmony_ci return ret; 2718c2ecf20Sopenharmony_ci } 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(mt6660_setting_table); i++) { 2748c2ecf20Sopenharmony_ci ret = snd_soc_component_update_bits(component, 2758c2ecf20Sopenharmony_ci mt6660_setting_table[i].addr, 2768c2ecf20Sopenharmony_ci mt6660_setting_table[i].mask, 2778c2ecf20Sopenharmony_ci mt6660_setting_table[i].val); 2788c2ecf20Sopenharmony_ci if (ret < 0) { 2798c2ecf20Sopenharmony_ci dev_err(component->dev, "%s update 0x%02x failed\n", 2808c2ecf20Sopenharmony_ci __func__, mt6660_setting_table[i].addr); 2818c2ecf20Sopenharmony_ci return ret; 2828c2ecf20Sopenharmony_ci } 2838c2ecf20Sopenharmony_ci } 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci ret = _mt6660_chip_power_on(chip, 0); 2868c2ecf20Sopenharmony_ci if (ret < 0) { 2878c2ecf20Sopenharmony_ci dev_err(component->dev, "%s chip power off failed\n", __func__); 2888c2ecf20Sopenharmony_ci return ret; 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci return 0; 2928c2ecf20Sopenharmony_ci} 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_cistatic int mt6660_component_probe(struct snd_soc_component *component) 2958c2ecf20Sopenharmony_ci{ 2968c2ecf20Sopenharmony_ci struct mt6660_chip *chip = snd_soc_component_get_drvdata(component); 2978c2ecf20Sopenharmony_ci int ret; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci dev_dbg(component->dev, "%s\n", __func__); 3008c2ecf20Sopenharmony_ci snd_soc_component_init_regmap(component, chip->regmap); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci ret = mt6660_component_setting(component); 3038c2ecf20Sopenharmony_ci if (ret < 0) 3048c2ecf20Sopenharmony_ci dev_err(chip->dev, "mt6660 component setting failed\n"); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci return ret; 3078c2ecf20Sopenharmony_ci} 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_cistatic void mt6660_component_remove(struct snd_soc_component *component) 3108c2ecf20Sopenharmony_ci{ 3118c2ecf20Sopenharmony_ci dev_dbg(component->dev, "%s\n", __func__); 3128c2ecf20Sopenharmony_ci snd_soc_component_exit_regmap(component); 3138c2ecf20Sopenharmony_ci} 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver mt6660_component_driver = { 3168c2ecf20Sopenharmony_ci .probe = mt6660_component_probe, 3178c2ecf20Sopenharmony_ci .remove = mt6660_component_remove, 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci .controls = mt6660_component_snd_controls, 3208c2ecf20Sopenharmony_ci .num_controls = ARRAY_SIZE(mt6660_component_snd_controls), 3218c2ecf20Sopenharmony_ci .dapm_widgets = mt6660_component_dapm_widgets, 3228c2ecf20Sopenharmony_ci .num_dapm_widgets = ARRAY_SIZE(mt6660_component_dapm_widgets), 3238c2ecf20Sopenharmony_ci .dapm_routes = mt6660_component_dapm_routes, 3248c2ecf20Sopenharmony_ci .num_dapm_routes = ARRAY_SIZE(mt6660_component_dapm_routes), 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci .idle_bias_on = false, /* idle_bias_off = true */ 3278c2ecf20Sopenharmony_ci}; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_cistatic int mt6660_component_aif_hw_params(struct snd_pcm_substream *substream, 3308c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *dai) 3318c2ecf20Sopenharmony_ci{ 3328c2ecf20Sopenharmony_ci int word_len = params_physical_width(hw_params); 3338c2ecf20Sopenharmony_ci int aud_bit = params_width(hw_params); 3348c2ecf20Sopenharmony_ci u16 reg_data = 0; 3358c2ecf20Sopenharmony_ci int ret; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci dev_dbg(dai->dev, "%s: ++\n", __func__); 3388c2ecf20Sopenharmony_ci dev_dbg(dai->dev, "format: 0x%08x\n", params_format(hw_params)); 3398c2ecf20Sopenharmony_ci dev_dbg(dai->dev, "rate: 0x%08x\n", params_rate(hw_params)); 3408c2ecf20Sopenharmony_ci dev_dbg(dai->dev, "word_len: %d, aud_bit: %d\n", word_len, aud_bit); 3418c2ecf20Sopenharmony_ci if (word_len > 32 || word_len < 16) { 3428c2ecf20Sopenharmony_ci dev_err(dai->dev, "not supported word length\n"); 3438c2ecf20Sopenharmony_ci return -ENOTSUPP; 3448c2ecf20Sopenharmony_ci } 3458c2ecf20Sopenharmony_ci switch (aud_bit) { 3468c2ecf20Sopenharmony_ci case 16: 3478c2ecf20Sopenharmony_ci reg_data = 3; 3488c2ecf20Sopenharmony_ci break; 3498c2ecf20Sopenharmony_ci case 18: 3508c2ecf20Sopenharmony_ci reg_data = 2; 3518c2ecf20Sopenharmony_ci break; 3528c2ecf20Sopenharmony_ci case 20: 3538c2ecf20Sopenharmony_ci reg_data = 1; 3548c2ecf20Sopenharmony_ci break; 3558c2ecf20Sopenharmony_ci case 24: 3568c2ecf20Sopenharmony_ci case 32: 3578c2ecf20Sopenharmony_ci reg_data = 0; 3588c2ecf20Sopenharmony_ci break; 3598c2ecf20Sopenharmony_ci default: 3608c2ecf20Sopenharmony_ci return -ENOTSUPP; 3618c2ecf20Sopenharmony_ci } 3628c2ecf20Sopenharmony_ci ret = snd_soc_component_update_bits(dai->component, 3638c2ecf20Sopenharmony_ci MT6660_REG_SERIAL_CFG1, 0xc0, (reg_data << 6)); 3648c2ecf20Sopenharmony_ci if (ret < 0) { 3658c2ecf20Sopenharmony_ci dev_err(dai->dev, "config aud bit fail\n"); 3668c2ecf20Sopenharmony_ci return ret; 3678c2ecf20Sopenharmony_ci } 3688c2ecf20Sopenharmony_ci ret = snd_soc_component_update_bits(dai->component, 3698c2ecf20Sopenharmony_ci MT6660_REG_TDM_CFG3, 0x3f0, word_len << 4); 3708c2ecf20Sopenharmony_ci if (ret < 0) { 3718c2ecf20Sopenharmony_ci dev_err(dai->dev, "config word len fail\n"); 3728c2ecf20Sopenharmony_ci return ret; 3738c2ecf20Sopenharmony_ci } 3748c2ecf20Sopenharmony_ci dev_dbg(dai->dev, "%s: --\n", __func__); 3758c2ecf20Sopenharmony_ci return 0; 3768c2ecf20Sopenharmony_ci} 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_cistatic const struct snd_soc_dai_ops mt6660_component_aif_ops = { 3798c2ecf20Sopenharmony_ci .hw_params = mt6660_component_aif_hw_params, 3808c2ecf20Sopenharmony_ci}; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci#define STUB_RATES SNDRV_PCM_RATE_8000_192000 3838c2ecf20Sopenharmony_ci#define STUB_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ 3848c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_U16_LE | \ 3858c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_LE | \ 3868c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_U24_LE | \ 3878c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S32_LE | \ 3888c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_U32_LE) 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_cistatic struct snd_soc_dai_driver mt6660_codec_dai = { 3918c2ecf20Sopenharmony_ci .name = "mt6660-aif", 3928c2ecf20Sopenharmony_ci .playback = { 3938c2ecf20Sopenharmony_ci .stream_name = "aif_playback", 3948c2ecf20Sopenharmony_ci .channels_min = 1, 3958c2ecf20Sopenharmony_ci .channels_max = 2, 3968c2ecf20Sopenharmony_ci .rates = STUB_RATES, 3978c2ecf20Sopenharmony_ci .formats = STUB_FORMATS, 3988c2ecf20Sopenharmony_ci }, 3998c2ecf20Sopenharmony_ci .capture = { 4008c2ecf20Sopenharmony_ci .stream_name = "aif_capture", 4018c2ecf20Sopenharmony_ci .channels_min = 1, 4028c2ecf20Sopenharmony_ci .channels_max = 2, 4038c2ecf20Sopenharmony_ci .rates = STUB_RATES, 4048c2ecf20Sopenharmony_ci .formats = STUB_FORMATS, 4058c2ecf20Sopenharmony_ci }, 4068c2ecf20Sopenharmony_ci /* dai properties */ 4078c2ecf20Sopenharmony_ci .symmetric_rates = 1, 4088c2ecf20Sopenharmony_ci .symmetric_channels = 1, 4098c2ecf20Sopenharmony_ci .symmetric_samplebits = 1, 4108c2ecf20Sopenharmony_ci /* dai operations */ 4118c2ecf20Sopenharmony_ci .ops = &mt6660_component_aif_ops, 4128c2ecf20Sopenharmony_ci}; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_cistatic int _mt6660_chip_id_check(struct mt6660_chip *chip) 4158c2ecf20Sopenharmony_ci{ 4168c2ecf20Sopenharmony_ci int ret; 4178c2ecf20Sopenharmony_ci unsigned int val; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci ret = regmap_read(chip->regmap, MT6660_REG_DEVID, &val); 4208c2ecf20Sopenharmony_ci if (ret < 0) 4218c2ecf20Sopenharmony_ci return ret; 4228c2ecf20Sopenharmony_ci val &= 0x0ff0; 4238c2ecf20Sopenharmony_ci if (val != 0x00e0 && val != 0x01e0) { 4248c2ecf20Sopenharmony_ci dev_err(chip->dev, "%s id(%x) not match\n", __func__, val); 4258c2ecf20Sopenharmony_ci return -ENODEV; 4268c2ecf20Sopenharmony_ci } 4278c2ecf20Sopenharmony_ci return 0; 4288c2ecf20Sopenharmony_ci} 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_cistatic int _mt6660_chip_sw_reset(struct mt6660_chip *chip) 4318c2ecf20Sopenharmony_ci{ 4328c2ecf20Sopenharmony_ci int ret; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci /* turn on main pll first, then trigger reset */ 4358c2ecf20Sopenharmony_ci ret = regmap_write(chip->regmap, MT6660_REG_SYSTEM_CTRL, 0x00); 4368c2ecf20Sopenharmony_ci if (ret < 0) 4378c2ecf20Sopenharmony_ci return ret; 4388c2ecf20Sopenharmony_ci ret = regmap_write(chip->regmap, MT6660_REG_SYSTEM_CTRL, 0x80); 4398c2ecf20Sopenharmony_ci if (ret < 0) 4408c2ecf20Sopenharmony_ci return ret; 4418c2ecf20Sopenharmony_ci msleep(30); 4428c2ecf20Sopenharmony_ci return 0; 4438c2ecf20Sopenharmony_ci} 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_cistatic int _mt6660_read_chip_revision(struct mt6660_chip *chip) 4468c2ecf20Sopenharmony_ci{ 4478c2ecf20Sopenharmony_ci int ret; 4488c2ecf20Sopenharmony_ci unsigned int val; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci ret = regmap_read(chip->regmap, MT6660_REG_DEVID, &val); 4518c2ecf20Sopenharmony_ci if (ret < 0) { 4528c2ecf20Sopenharmony_ci dev_err(chip->dev, "get chip revision fail\n"); 4538c2ecf20Sopenharmony_ci return ret; 4548c2ecf20Sopenharmony_ci } 4558c2ecf20Sopenharmony_ci chip->chip_rev = val&0xff; 4568c2ecf20Sopenharmony_ci dev_info(chip->dev, "%s chip_rev = %x\n", __func__, chip->chip_rev); 4578c2ecf20Sopenharmony_ci return 0; 4588c2ecf20Sopenharmony_ci} 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_cistatic int mt6660_i2c_probe(struct i2c_client *client, 4618c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 4628c2ecf20Sopenharmony_ci{ 4638c2ecf20Sopenharmony_ci struct mt6660_chip *chip = NULL; 4648c2ecf20Sopenharmony_ci int ret; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "%s\n", __func__); 4678c2ecf20Sopenharmony_ci chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); 4688c2ecf20Sopenharmony_ci if (!chip) 4698c2ecf20Sopenharmony_ci return -ENOMEM; 4708c2ecf20Sopenharmony_ci chip->i2c = client; 4718c2ecf20Sopenharmony_ci chip->dev = &client->dev; 4728c2ecf20Sopenharmony_ci mutex_init(&chip->io_lock); 4738c2ecf20Sopenharmony_ci i2c_set_clientdata(client, chip); 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci chip->regmap = devm_regmap_init(&client->dev, 4768c2ecf20Sopenharmony_ci NULL, chip, &mt6660_regmap_config); 4778c2ecf20Sopenharmony_ci if (IS_ERR(chip->regmap)) { 4788c2ecf20Sopenharmony_ci ret = PTR_ERR(chip->regmap); 4798c2ecf20Sopenharmony_ci dev_err(&client->dev, "failed to initialise regmap: %d\n", ret); 4808c2ecf20Sopenharmony_ci return ret; 4818c2ecf20Sopenharmony_ci } 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci /* chip reset first */ 4848c2ecf20Sopenharmony_ci ret = _mt6660_chip_sw_reset(chip); 4858c2ecf20Sopenharmony_ci if (ret < 0) { 4868c2ecf20Sopenharmony_ci dev_err(chip->dev, "chip reset fail\n"); 4878c2ecf20Sopenharmony_ci goto probe_fail; 4888c2ecf20Sopenharmony_ci } 4898c2ecf20Sopenharmony_ci /* chip power on */ 4908c2ecf20Sopenharmony_ci ret = _mt6660_chip_power_on(chip, 1); 4918c2ecf20Sopenharmony_ci if (ret < 0) { 4928c2ecf20Sopenharmony_ci dev_err(chip->dev, "chip power on 2 fail\n"); 4938c2ecf20Sopenharmony_ci goto probe_fail; 4948c2ecf20Sopenharmony_ci } 4958c2ecf20Sopenharmony_ci /* chip devid check */ 4968c2ecf20Sopenharmony_ci ret = _mt6660_chip_id_check(chip); 4978c2ecf20Sopenharmony_ci if (ret < 0) { 4988c2ecf20Sopenharmony_ci dev_err(chip->dev, "chip id check fail\n"); 4998c2ecf20Sopenharmony_ci goto probe_fail; 5008c2ecf20Sopenharmony_ci } 5018c2ecf20Sopenharmony_ci /* chip revision get */ 5028c2ecf20Sopenharmony_ci ret = _mt6660_read_chip_revision(chip); 5038c2ecf20Sopenharmony_ci if (ret < 0) { 5048c2ecf20Sopenharmony_ci dev_err(chip->dev, "read chip revision fail\n"); 5058c2ecf20Sopenharmony_ci goto probe_fail; 5068c2ecf20Sopenharmony_ci } 5078c2ecf20Sopenharmony_ci pm_runtime_set_active(chip->dev); 5088c2ecf20Sopenharmony_ci pm_runtime_enable(chip->dev); 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci ret = devm_snd_soc_register_component(chip->dev, 5118c2ecf20Sopenharmony_ci &mt6660_component_driver, 5128c2ecf20Sopenharmony_ci &mt6660_codec_dai, 1); 5138c2ecf20Sopenharmony_ci if (ret) 5148c2ecf20Sopenharmony_ci pm_runtime_disable(chip->dev); 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci return ret; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ciprobe_fail: 5198c2ecf20Sopenharmony_ci _mt6660_chip_power_on(chip, 0); 5208c2ecf20Sopenharmony_ci mutex_destroy(&chip->io_lock); 5218c2ecf20Sopenharmony_ci return ret; 5228c2ecf20Sopenharmony_ci} 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_cistatic int mt6660_i2c_remove(struct i2c_client *client) 5258c2ecf20Sopenharmony_ci{ 5268c2ecf20Sopenharmony_ci struct mt6660_chip *chip = i2c_get_clientdata(client); 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci pm_runtime_disable(chip->dev); 5298c2ecf20Sopenharmony_ci pm_runtime_set_suspended(chip->dev); 5308c2ecf20Sopenharmony_ci mutex_destroy(&chip->io_lock); 5318c2ecf20Sopenharmony_ci return 0; 5328c2ecf20Sopenharmony_ci} 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_cistatic int __maybe_unused mt6660_i2c_runtime_suspend(struct device *dev) 5358c2ecf20Sopenharmony_ci{ 5368c2ecf20Sopenharmony_ci struct mt6660_chip *chip = dev_get_drvdata(dev); 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci dev_dbg(dev, "enter low power mode\n"); 5398c2ecf20Sopenharmony_ci return regmap_update_bits(chip->regmap, 5408c2ecf20Sopenharmony_ci MT6660_REG_SYSTEM_CTRL, 0x01, 0x01); 5418c2ecf20Sopenharmony_ci} 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_cistatic int __maybe_unused mt6660_i2c_runtime_resume(struct device *dev) 5448c2ecf20Sopenharmony_ci{ 5458c2ecf20Sopenharmony_ci struct mt6660_chip *chip = dev_get_drvdata(dev); 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci dev_dbg(dev, "exit low power mode\n"); 5488c2ecf20Sopenharmony_ci return regmap_update_bits(chip->regmap, 5498c2ecf20Sopenharmony_ci MT6660_REG_SYSTEM_CTRL, 0x01, 0x00); 5508c2ecf20Sopenharmony_ci} 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_cistatic const struct dev_pm_ops mt6660_dev_pm_ops = { 5538c2ecf20Sopenharmony_ci SET_RUNTIME_PM_OPS(mt6660_i2c_runtime_suspend, 5548c2ecf20Sopenharmony_ci mt6660_i2c_runtime_resume, NULL) 5558c2ecf20Sopenharmony_ci}; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_cistatic const struct of_device_id __maybe_unused mt6660_of_id[] = { 5588c2ecf20Sopenharmony_ci { .compatible = "mediatek,mt6660",}, 5598c2ecf20Sopenharmony_ci {}, 5608c2ecf20Sopenharmony_ci}; 5618c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, mt6660_of_id); 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_cistatic const struct i2c_device_id mt6660_i2c_id[] = { 5648c2ecf20Sopenharmony_ci {"mt6660", 0 }, 5658c2ecf20Sopenharmony_ci {}, 5668c2ecf20Sopenharmony_ci}; 5678c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, mt6660_i2c_id); 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_cistatic struct i2c_driver mt6660_i2c_driver = { 5708c2ecf20Sopenharmony_ci .driver = { 5718c2ecf20Sopenharmony_ci .name = "mt6660", 5728c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(mt6660_of_id), 5738c2ecf20Sopenharmony_ci .pm = &mt6660_dev_pm_ops, 5748c2ecf20Sopenharmony_ci }, 5758c2ecf20Sopenharmony_ci .probe = mt6660_i2c_probe, 5768c2ecf20Sopenharmony_ci .remove = mt6660_i2c_remove, 5778c2ecf20Sopenharmony_ci .id_table = mt6660_i2c_id, 5788c2ecf20Sopenharmony_ci}; 5798c2ecf20Sopenharmony_cimodule_i2c_driver(mt6660_i2c_driver); 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jeff Chang <jeff_chang@richtek.com>"); 5828c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("MT6660 SPKAMP Driver"); 5838c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 5848c2ecf20Sopenharmony_ciMODULE_VERSION("1.0.8_G"); 585