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