1bc765162SLukas Bulwahn // SPDX-License-Identifier: GPL-2.0 2f289e55cSJeff Chang 3f289e55cSJeff Chang // Copyright (c) 2019 MediaTek Inc. 4f289e55cSJeff Chang 5f289e55cSJeff Chang #include <linux/module.h> 6f289e55cSJeff Chang #include <linux/kernel.h> 7f289e55cSJeff Chang #include <linux/err.h> 8f289e55cSJeff Chang #include <linux/i2c.h> 9f289e55cSJeff Chang #include <linux/pm_runtime.h> 10f289e55cSJeff Chang #include <linux/delay.h> 11f289e55cSJeff Chang #include <sound/soc.h> 12f289e55cSJeff Chang #include <sound/tlv.h> 13f289e55cSJeff Chang #include <sound/pcm_params.h> 14f289e55cSJeff Chang 15f289e55cSJeff Chang #include "mt6660.h" 16f289e55cSJeff Chang 17f289e55cSJeff Chang struct reg_size_table { 18f289e55cSJeff Chang u32 addr; 19f289e55cSJeff Chang u8 size; 20f289e55cSJeff Chang }; 21f289e55cSJeff Chang 22f289e55cSJeff Chang static const struct reg_size_table mt6660_reg_size_table[] = { 23f289e55cSJeff Chang { MT6660_REG_HPF1_COEF, 4 }, 24f289e55cSJeff Chang { MT6660_REG_HPF2_COEF, 4 }, 25f289e55cSJeff Chang { MT6660_REG_TDM_CFG3, 2 }, 26f289e55cSJeff Chang { MT6660_REG_RESV17, 2 }, 27f289e55cSJeff Chang { MT6660_REG_RESV23, 2 }, 28f289e55cSJeff Chang { MT6660_REG_SIGMAX, 2 }, 29f289e55cSJeff Chang { MT6660_REG_DEVID, 2 }, 30f289e55cSJeff Chang { MT6660_REG_HCLIP_CTRL, 2 }, 31f289e55cSJeff Chang { MT6660_REG_DA_GAIN, 2 }, 32f289e55cSJeff Chang }; 33f289e55cSJeff Chang 34f289e55cSJeff Chang static int mt6660_get_reg_size(uint32_t addr) 35f289e55cSJeff Chang { 36f289e55cSJeff Chang int i; 37f289e55cSJeff Chang 38f289e55cSJeff Chang for (i = 0; i < ARRAY_SIZE(mt6660_reg_size_table); i++) { 39f289e55cSJeff Chang if (mt6660_reg_size_table[i].addr == addr) 40f289e55cSJeff Chang return mt6660_reg_size_table[i].size; 41f289e55cSJeff Chang } 42f289e55cSJeff Chang return 1; 43f289e55cSJeff Chang } 44f289e55cSJeff Chang 45f289e55cSJeff Chang static int mt6660_reg_write(void *context, unsigned int reg, unsigned int val) 46f289e55cSJeff Chang { 47f289e55cSJeff Chang struct mt6660_chip *chip = context; 48f289e55cSJeff Chang int size = mt6660_get_reg_size(reg); 49f289e55cSJeff Chang u8 reg_data[4]; 50b2fde4deSchiminghao int i; 51f289e55cSJeff Chang 52f289e55cSJeff Chang for (i = 0; i < size; i++) 53f289e55cSJeff Chang reg_data[size - i - 1] = (val >> (8 * i)) & 0xff; 54f289e55cSJeff Chang 55b2fde4deSchiminghao return i2c_smbus_write_i2c_block_data(chip->i2c, reg, size, reg_data); 56f289e55cSJeff Chang } 57f289e55cSJeff Chang 58f289e55cSJeff Chang static int mt6660_reg_read(void *context, unsigned int reg, unsigned int *val) 59f289e55cSJeff Chang { 60f289e55cSJeff Chang struct mt6660_chip *chip = context; 61f289e55cSJeff Chang int size = mt6660_get_reg_size(reg); 62f289e55cSJeff Chang int i, ret; 63f289e55cSJeff Chang u8 data[4]; 64f289e55cSJeff Chang u32 reg_data = 0; 65f289e55cSJeff Chang 66f289e55cSJeff Chang ret = i2c_smbus_read_i2c_block_data(chip->i2c, reg, size, data); 67f289e55cSJeff Chang if (ret < 0) 68f289e55cSJeff Chang return ret; 69f289e55cSJeff Chang for (i = 0; i < size; i++) { 70f289e55cSJeff Chang reg_data <<= 8; 71f289e55cSJeff Chang reg_data |= data[i]; 72f289e55cSJeff Chang } 73f289e55cSJeff Chang *val = reg_data; 74f289e55cSJeff Chang return 0; 75f289e55cSJeff Chang } 76f289e55cSJeff Chang 77f289e55cSJeff Chang static const struct regmap_config mt6660_regmap_config = { 78f289e55cSJeff Chang .reg_bits = 8, 79f289e55cSJeff Chang .val_bits = 32, 80f289e55cSJeff Chang .reg_write = mt6660_reg_write, 81f289e55cSJeff Chang .reg_read = mt6660_reg_read, 82f289e55cSJeff Chang }; 83f289e55cSJeff Chang 84f289e55cSJeff Chang static int mt6660_codec_dac_event(struct snd_soc_dapm_widget *w, 85f289e55cSJeff Chang struct snd_kcontrol *kcontrol, int event) 86f289e55cSJeff Chang { 87f289e55cSJeff Chang if (event == SND_SOC_DAPM_POST_PMU) 88f289e55cSJeff Chang usleep_range(1000, 1100); 89f289e55cSJeff Chang return 0; 90f289e55cSJeff Chang } 91f289e55cSJeff Chang 92f289e55cSJeff Chang static int mt6660_codec_classd_event(struct snd_soc_dapm_widget *w, 93f289e55cSJeff Chang struct snd_kcontrol *kcontrol, int event) 94f289e55cSJeff Chang { 95f289e55cSJeff Chang struct snd_soc_component *component = 96f289e55cSJeff Chang snd_soc_dapm_to_component(w->dapm); 97f289e55cSJeff Chang int ret; 98f289e55cSJeff Chang 99f289e55cSJeff Chang switch (event) { 100f289e55cSJeff Chang case SND_SOC_DAPM_PRE_PMU: 101f289e55cSJeff Chang dev_dbg(component->dev, 102f289e55cSJeff Chang "%s: before classd turn on\n", __func__); 103f289e55cSJeff Chang /* config to adaptive mode */ 104f289e55cSJeff Chang ret = snd_soc_component_update_bits(component, 105f289e55cSJeff Chang MT6660_REG_BST_CTRL, 0x03, 0x03); 106f289e55cSJeff Chang if (ret < 0) { 107f289e55cSJeff Chang dev_err(component->dev, "config mode adaptive fail\n"); 108f289e55cSJeff Chang return ret; 109f289e55cSJeff Chang } 110f289e55cSJeff Chang break; 111f289e55cSJeff Chang case SND_SOC_DAPM_POST_PMU: 112f289e55cSJeff Chang /* voltage sensing enable */ 113f289e55cSJeff Chang ret = snd_soc_component_update_bits(component, 114f289e55cSJeff Chang MT6660_REG_RESV7, 0x04, 0x04); 115f289e55cSJeff Chang if (ret < 0) { 116f289e55cSJeff Chang dev_err(component->dev, 117f289e55cSJeff Chang "enable voltage sensing fail\n"); 118f289e55cSJeff Chang return ret; 119f289e55cSJeff Chang } 120f289e55cSJeff Chang dev_dbg(component->dev, "Amp on\n"); 121f289e55cSJeff Chang break; 122f289e55cSJeff Chang case SND_SOC_DAPM_PRE_PMD: 123f289e55cSJeff Chang dev_dbg(component->dev, "Amp off\n"); 124f289e55cSJeff Chang /* voltage sensing disable */ 125f289e55cSJeff Chang ret = snd_soc_component_update_bits(component, 126f289e55cSJeff Chang MT6660_REG_RESV7, 0x04, 0x00); 127f289e55cSJeff Chang if (ret < 0) { 128f289e55cSJeff Chang dev_err(component->dev, 129f289e55cSJeff Chang "disable voltage sensing fail\n"); 130f289e55cSJeff Chang return ret; 131f289e55cSJeff Chang } 132f289e55cSJeff Chang /* pop-noise improvement 1 */ 133f289e55cSJeff Chang ret = snd_soc_component_update_bits(component, 134f289e55cSJeff Chang MT6660_REG_RESV10, 0x10, 0x10); 135f289e55cSJeff Chang if (ret < 0) { 136f289e55cSJeff Chang dev_err(component->dev, 137f289e55cSJeff Chang "pop-noise improvement 1 fail\n"); 138f289e55cSJeff Chang return ret; 139f289e55cSJeff Chang } 140f289e55cSJeff Chang break; 141f289e55cSJeff Chang case SND_SOC_DAPM_POST_PMD: 142f289e55cSJeff Chang dev_dbg(component->dev, 143f289e55cSJeff Chang "%s: after classd turn off\n", __func__); 144f289e55cSJeff Chang /* pop-noise improvement 2 */ 145f289e55cSJeff Chang ret = snd_soc_component_update_bits(component, 146f289e55cSJeff Chang MT6660_REG_RESV10, 0x10, 0x00); 147f289e55cSJeff Chang if (ret < 0) { 148f289e55cSJeff Chang dev_err(component->dev, 149f289e55cSJeff Chang "pop-noise improvement 2 fail\n"); 150f289e55cSJeff Chang return ret; 151f289e55cSJeff Chang } 152f289e55cSJeff Chang /* config to off mode */ 153f289e55cSJeff Chang ret = snd_soc_component_update_bits(component, 154f289e55cSJeff Chang MT6660_REG_BST_CTRL, 0x03, 0x00); 155f289e55cSJeff Chang if (ret < 0) { 156f289e55cSJeff Chang dev_err(component->dev, "config mode off fail\n"); 157f289e55cSJeff Chang return ret; 158f289e55cSJeff Chang } 159f289e55cSJeff Chang break; 160f289e55cSJeff Chang } 161f289e55cSJeff Chang return 0; 162f289e55cSJeff Chang } 163f289e55cSJeff Chang 164f289e55cSJeff Chang static const struct snd_soc_dapm_widget mt6660_component_dapm_widgets[] = { 165f289e55cSJeff Chang SND_SOC_DAPM_DAC_E("DAC", NULL, MT6660_REG_PLL_CFG1, 166f289e55cSJeff Chang 0, 1, mt6660_codec_dac_event, SND_SOC_DAPM_POST_PMU), 167f289e55cSJeff Chang SND_SOC_DAPM_ADC("VI ADC", NULL, SND_SOC_NOPM, 0, 0), 168f289e55cSJeff Chang SND_SOC_DAPM_PGA("PGA", SND_SOC_NOPM, 0, 0, NULL, 0), 169f289e55cSJeff Chang SND_SOC_DAPM_OUT_DRV_E("ClassD", MT6660_REG_SYSTEM_CTRL, 2, 0, 170f289e55cSJeff Chang NULL, 0, mt6660_codec_classd_event, 171f289e55cSJeff Chang SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | 172f289e55cSJeff Chang SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), 173f289e55cSJeff Chang SND_SOC_DAPM_OUTPUT("OUTP"), 174f289e55cSJeff Chang SND_SOC_DAPM_OUTPUT("OUTN"), 175f289e55cSJeff Chang }; 176f289e55cSJeff Chang 177f289e55cSJeff Chang static const struct snd_soc_dapm_route mt6660_component_dapm_routes[] = { 178f289e55cSJeff Chang { "DAC", NULL, "aif_playback" }, 179f289e55cSJeff Chang { "PGA", NULL, "DAC" }, 180f289e55cSJeff Chang { "ClassD", NULL, "PGA" }, 181f289e55cSJeff Chang { "OUTP", NULL, "ClassD" }, 182f289e55cSJeff Chang { "OUTN", NULL, "ClassD" }, 183f289e55cSJeff Chang { "VI ADC", NULL, "ClassD" }, 184f289e55cSJeff Chang { "aif_capture", NULL, "VI ADC" }, 185f289e55cSJeff Chang }; 186f289e55cSJeff Chang 187f289e55cSJeff Chang static int mt6660_component_get_volsw(struct snd_kcontrol *kcontrol, 188f289e55cSJeff Chang struct snd_ctl_elem_value *ucontrol) 189f289e55cSJeff Chang { 190f289e55cSJeff Chang struct snd_soc_component *component = 191f289e55cSJeff Chang snd_soc_kcontrol_component(kcontrol); 192f289e55cSJeff Chang struct mt6660_chip *chip = (struct mt6660_chip *) 193f289e55cSJeff Chang snd_soc_component_get_drvdata(component); 194f289e55cSJeff Chang 195f289e55cSJeff Chang ucontrol->value.integer.value[0] = chip->chip_rev & 0x0f; 196f289e55cSJeff Chang return 0; 197f289e55cSJeff Chang } 198f289e55cSJeff Chang 199f289e55cSJeff Chang static const DECLARE_TLV_DB_SCALE(vol_ctl_tlv, -1155, 5, 0); 200f289e55cSJeff Chang 201f289e55cSJeff Chang static const struct snd_kcontrol_new mt6660_component_snd_controls[] = { 202f289e55cSJeff Chang SOC_SINGLE_TLV("Digital Volume", MT6660_REG_VOL_CTRL, 0, 255, 203f289e55cSJeff Chang 1, vol_ctl_tlv), 204f289e55cSJeff Chang SOC_SINGLE("Hard Clip Switch", MT6660_REG_HCLIP_CTRL, 8, 1, 0), 205f289e55cSJeff Chang SOC_SINGLE("Clip Switch", MT6660_REG_SPS_CTRL, 0, 1, 0), 206f289e55cSJeff Chang SOC_SINGLE("Boost Mode", MT6660_REG_BST_CTRL, 0, 3, 0), 207f289e55cSJeff Chang SOC_SINGLE("DRE Switch", MT6660_REG_DRE_CTRL, 0, 1, 0), 208f289e55cSJeff Chang SOC_SINGLE("DC Protect Switch", MT6660_REG_DC_PROTECT_CTRL, 3, 1, 0), 209f289e55cSJeff Chang SOC_SINGLE("Data Output Left Channel Selection", 210f289e55cSJeff Chang MT6660_REG_DATAO_SEL, 3, 7, 0), 211f289e55cSJeff Chang SOC_SINGLE("Data Output Right Channel Selection", 212f289e55cSJeff Chang MT6660_REG_DATAO_SEL, 0, 7, 0), 213f289e55cSJeff Chang SOC_SINGLE_EXT("T0 SEL", MT6660_REG_CALI_T0, 0, 7, 0, 214f289e55cSJeff Chang snd_soc_get_volsw, NULL), 215f289e55cSJeff Chang SOC_SINGLE_EXT("Chip Rev", MT6660_REG_DEVID, 8, 15, 0, 216f289e55cSJeff Chang mt6660_component_get_volsw, NULL), 217f289e55cSJeff Chang }; 218f289e55cSJeff Chang 219f289e55cSJeff Chang static int _mt6660_chip_power_on(struct mt6660_chip *chip, int on_off) 220f289e55cSJeff Chang { 221f289e55cSJeff Chang return regmap_write_bits(chip->regmap, MT6660_REG_SYSTEM_CTRL, 222f289e55cSJeff Chang 0x01, on_off ? 0x00 : 0x01); 223f289e55cSJeff Chang } 224f289e55cSJeff Chang 225eaa2330bSJeff Chang struct reg_table { 226eaa2330bSJeff Chang uint32_t addr; 227eaa2330bSJeff Chang uint32_t mask; 228eaa2330bSJeff Chang uint32_t val; 229eaa2330bSJeff Chang }; 230eaa2330bSJeff Chang 231eaa2330bSJeff Chang static const struct reg_table mt6660_setting_table[] = { 232eaa2330bSJeff Chang { 0x20, 0x80, 0x00 }, 233eaa2330bSJeff Chang { 0x30, 0x01, 0x00 }, 234eaa2330bSJeff Chang { 0x50, 0x1c, 0x04 }, 235eaa2330bSJeff Chang { 0xB1, 0x0c, 0x00 }, 236eaa2330bSJeff Chang { 0xD3, 0x03, 0x03 }, 237eaa2330bSJeff Chang { 0xE0, 0x01, 0x00 }, 238eaa2330bSJeff Chang { 0x98, 0x44, 0x04 }, 239eaa2330bSJeff Chang { 0xB9, 0xff, 0x82 }, 240eaa2330bSJeff Chang { 0xB7, 0x7777, 0x7273 }, 241eaa2330bSJeff Chang { 0xB6, 0x07, 0x03 }, 242eaa2330bSJeff Chang { 0x6B, 0xe0, 0x20 }, 243eaa2330bSJeff Chang { 0x07, 0xff, 0x70 }, 244eaa2330bSJeff Chang { 0xBB, 0xff, 0x20 }, 245eaa2330bSJeff Chang { 0x69, 0xff, 0x40 }, 246eaa2330bSJeff Chang { 0xBD, 0xffff, 0x17f8 }, 247eaa2330bSJeff Chang { 0x70, 0xff, 0x15 }, 248eaa2330bSJeff Chang { 0x7C, 0xff, 0x00 }, 249eaa2330bSJeff Chang { 0x46, 0xff, 0x1d }, 250eaa2330bSJeff Chang { 0x1A, 0xffffffff, 0x7fdb7ffe }, 251eaa2330bSJeff Chang { 0x1B, 0xffffffff, 0x7fdb7ffe }, 252eaa2330bSJeff Chang { 0x51, 0xff, 0x58 }, 253eaa2330bSJeff Chang { 0xA2, 0xff, 0xce }, 254eaa2330bSJeff Chang { 0x33, 0xffff, 0x7fff }, 255eaa2330bSJeff Chang { 0x4C, 0xffff, 0x0116 }, 256eaa2330bSJeff Chang { 0x16, 0x1800, 0x0800 }, 257eaa2330bSJeff Chang { 0x68, 0x1f, 0x07 }, 258eaa2330bSJeff Chang }; 259eaa2330bSJeff Chang 260eaa2330bSJeff Chang static int mt6660_component_setting(struct snd_soc_component *component) 261eaa2330bSJeff Chang { 262eaa2330bSJeff Chang struct mt6660_chip *chip = snd_soc_component_get_drvdata(component); 263eaa2330bSJeff Chang int ret = 0; 264eaa2330bSJeff Chang size_t i = 0; 265eaa2330bSJeff Chang 266eaa2330bSJeff Chang ret = _mt6660_chip_power_on(chip, 1); 267eaa2330bSJeff Chang if (ret < 0) { 268eaa2330bSJeff Chang dev_err(component->dev, "%s chip power on failed\n", __func__); 269eaa2330bSJeff Chang return ret; 270eaa2330bSJeff Chang } 271eaa2330bSJeff Chang 272eaa2330bSJeff Chang for (i = 0; i < ARRAY_SIZE(mt6660_setting_table); i++) { 273eaa2330bSJeff Chang ret = snd_soc_component_update_bits(component, 274eaa2330bSJeff Chang mt6660_setting_table[i].addr, 275eaa2330bSJeff Chang mt6660_setting_table[i].mask, 276eaa2330bSJeff Chang mt6660_setting_table[i].val); 277eaa2330bSJeff Chang if (ret < 0) { 278eaa2330bSJeff Chang dev_err(component->dev, "%s update 0x%02x failed\n", 279eaa2330bSJeff Chang __func__, mt6660_setting_table[i].addr); 280eaa2330bSJeff Chang return ret; 281eaa2330bSJeff Chang } 282eaa2330bSJeff Chang } 283eaa2330bSJeff Chang 284eaa2330bSJeff Chang ret = _mt6660_chip_power_on(chip, 0); 285eaa2330bSJeff Chang if (ret < 0) { 286eaa2330bSJeff Chang dev_err(component->dev, "%s chip power off failed\n", __func__); 287eaa2330bSJeff Chang return ret; 288eaa2330bSJeff Chang } 289eaa2330bSJeff Chang 290eaa2330bSJeff Chang return 0; 291eaa2330bSJeff Chang } 292eaa2330bSJeff Chang 293f289e55cSJeff Chang static int mt6660_component_probe(struct snd_soc_component *component) 294f289e55cSJeff Chang { 295f289e55cSJeff Chang struct mt6660_chip *chip = snd_soc_component_get_drvdata(component); 296eaa2330bSJeff Chang int ret; 297f289e55cSJeff Chang 298f289e55cSJeff Chang dev_dbg(component->dev, "%s\n", __func__); 299f289e55cSJeff Chang snd_soc_component_init_regmap(component, chip->regmap); 300f289e55cSJeff Chang 301eaa2330bSJeff Chang ret = mt6660_component_setting(component); 302eaa2330bSJeff Chang if (ret < 0) 303eaa2330bSJeff Chang dev_err(chip->dev, "mt6660 component setting failed\n"); 304eaa2330bSJeff Chang 305eaa2330bSJeff Chang return ret; 306f289e55cSJeff Chang } 307f289e55cSJeff Chang 308f289e55cSJeff Chang static void mt6660_component_remove(struct snd_soc_component *component) 309f289e55cSJeff Chang { 310f289e55cSJeff Chang dev_dbg(component->dev, "%s\n", __func__); 311f289e55cSJeff Chang snd_soc_component_exit_regmap(component); 312f289e55cSJeff Chang } 313f289e55cSJeff Chang 314f289e55cSJeff Chang static const struct snd_soc_component_driver mt6660_component_driver = { 315f289e55cSJeff Chang .probe = mt6660_component_probe, 316f289e55cSJeff Chang .remove = mt6660_component_remove, 317f289e55cSJeff Chang 318f289e55cSJeff Chang .controls = mt6660_component_snd_controls, 319f289e55cSJeff Chang .num_controls = ARRAY_SIZE(mt6660_component_snd_controls), 320f289e55cSJeff Chang .dapm_widgets = mt6660_component_dapm_widgets, 321f289e55cSJeff Chang .num_dapm_widgets = ARRAY_SIZE(mt6660_component_dapm_widgets), 322f289e55cSJeff Chang .dapm_routes = mt6660_component_dapm_routes, 323f289e55cSJeff Chang .num_dapm_routes = ARRAY_SIZE(mt6660_component_dapm_routes), 324f289e55cSJeff Chang 325f289e55cSJeff Chang .idle_bias_on = false, /* idle_bias_off = true */ 3268044910bSCharles Keepax .endianness = 1, 327f289e55cSJeff Chang }; 328f289e55cSJeff Chang 329f289e55cSJeff Chang static int mt6660_component_aif_hw_params(struct snd_pcm_substream *substream, 330f289e55cSJeff Chang struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *dai) 331f289e55cSJeff Chang { 332f289e55cSJeff Chang int word_len = params_physical_width(hw_params); 333f289e55cSJeff Chang int aud_bit = params_width(hw_params); 334f289e55cSJeff Chang u16 reg_data = 0; 335f289e55cSJeff Chang int ret; 336f289e55cSJeff Chang 337f289e55cSJeff Chang dev_dbg(dai->dev, "%s: ++\n", __func__); 338f289e55cSJeff Chang dev_dbg(dai->dev, "format: 0x%08x\n", params_format(hw_params)); 339f289e55cSJeff Chang dev_dbg(dai->dev, "rate: 0x%08x\n", params_rate(hw_params)); 340f289e55cSJeff Chang dev_dbg(dai->dev, "word_len: %d, aud_bit: %d\n", word_len, aud_bit); 341f289e55cSJeff Chang if (word_len > 32 || word_len < 16) { 342f289e55cSJeff Chang dev_err(dai->dev, "not supported word length\n"); 343f289e55cSJeff Chang return -ENOTSUPP; 344f289e55cSJeff Chang } 345f289e55cSJeff Chang switch (aud_bit) { 346f289e55cSJeff Chang case 16: 347f289e55cSJeff Chang reg_data = 3; 348f289e55cSJeff Chang break; 349f289e55cSJeff Chang case 18: 350f289e55cSJeff Chang reg_data = 2; 351f289e55cSJeff Chang break; 352f289e55cSJeff Chang case 20: 353f289e55cSJeff Chang reg_data = 1; 354f289e55cSJeff Chang break; 355f289e55cSJeff Chang case 24: 356f289e55cSJeff Chang case 32: 357f289e55cSJeff Chang reg_data = 0; 358f289e55cSJeff Chang break; 359f289e55cSJeff Chang default: 360f289e55cSJeff Chang return -ENOTSUPP; 361f289e55cSJeff Chang } 362f289e55cSJeff Chang ret = snd_soc_component_update_bits(dai->component, 363f289e55cSJeff Chang MT6660_REG_SERIAL_CFG1, 0xc0, (reg_data << 6)); 364f289e55cSJeff Chang if (ret < 0) { 365f289e55cSJeff Chang dev_err(dai->dev, "config aud bit fail\n"); 366f289e55cSJeff Chang return ret; 367f289e55cSJeff Chang } 368f289e55cSJeff Chang ret = snd_soc_component_update_bits(dai->component, 369f289e55cSJeff Chang MT6660_REG_TDM_CFG3, 0x3f0, word_len << 4); 370f289e55cSJeff Chang if (ret < 0) { 371f289e55cSJeff Chang dev_err(dai->dev, "config word len fail\n"); 372f289e55cSJeff Chang return ret; 373f289e55cSJeff Chang } 374f289e55cSJeff Chang dev_dbg(dai->dev, "%s: --\n", __func__); 375f289e55cSJeff Chang return 0; 376f289e55cSJeff Chang } 377f289e55cSJeff Chang 378f289e55cSJeff Chang static const struct snd_soc_dai_ops mt6660_component_aif_ops = { 379f289e55cSJeff Chang .hw_params = mt6660_component_aif_hw_params, 380f289e55cSJeff Chang }; 381f289e55cSJeff Chang 382f289e55cSJeff Chang #define STUB_RATES SNDRV_PCM_RATE_8000_192000 383f289e55cSJeff Chang #define STUB_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ 384f289e55cSJeff Chang SNDRV_PCM_FMTBIT_U16_LE | \ 385f289e55cSJeff Chang SNDRV_PCM_FMTBIT_S24_LE | \ 386f289e55cSJeff Chang SNDRV_PCM_FMTBIT_U24_LE | \ 387f289e55cSJeff Chang SNDRV_PCM_FMTBIT_S32_LE | \ 388f289e55cSJeff Chang SNDRV_PCM_FMTBIT_U32_LE) 389f289e55cSJeff Chang 390f289e55cSJeff Chang static struct snd_soc_dai_driver mt6660_codec_dai = { 391f289e55cSJeff Chang .name = "mt6660-aif", 392f289e55cSJeff Chang .playback = { 393f289e55cSJeff Chang .stream_name = "aif_playback", 394f289e55cSJeff Chang .channels_min = 1, 395f289e55cSJeff Chang .channels_max = 2, 396f289e55cSJeff Chang .rates = STUB_RATES, 397f289e55cSJeff Chang .formats = STUB_FORMATS, 398f289e55cSJeff Chang }, 399f289e55cSJeff Chang .capture = { 400f289e55cSJeff Chang .stream_name = "aif_capture", 401f289e55cSJeff Chang .channels_min = 1, 402f289e55cSJeff Chang .channels_max = 2, 403f289e55cSJeff Chang .rates = STUB_RATES, 404f289e55cSJeff Chang .formats = STUB_FORMATS, 405f289e55cSJeff Chang }, 406f289e55cSJeff Chang /* dai properties */ 407852d4daaSKuninori Morimoto .symmetric_rate = 1, 408f289e55cSJeff Chang .symmetric_channels = 1, 409852d4daaSKuninori Morimoto .symmetric_sample_bits = 1, 410f289e55cSJeff Chang /* dai operations */ 411f289e55cSJeff Chang .ops = &mt6660_component_aif_ops, 412f289e55cSJeff Chang }; 413f289e55cSJeff Chang 414f289e55cSJeff Chang static int _mt6660_chip_id_check(struct mt6660_chip *chip) 415f289e55cSJeff Chang { 416f289e55cSJeff Chang int ret; 417f289e55cSJeff Chang unsigned int val; 418f289e55cSJeff Chang 419f289e55cSJeff Chang ret = regmap_read(chip->regmap, MT6660_REG_DEVID, &val); 420f289e55cSJeff Chang if (ret < 0) 421f289e55cSJeff Chang return ret; 422f289e55cSJeff Chang val &= 0x0ff0; 423f289e55cSJeff Chang if (val != 0x00e0 && val != 0x01e0) { 424f289e55cSJeff Chang dev_err(chip->dev, "%s id(%x) not match\n", __func__, val); 425f289e55cSJeff Chang return -ENODEV; 426f289e55cSJeff Chang } 427f289e55cSJeff Chang return 0; 428f289e55cSJeff Chang } 429f289e55cSJeff Chang 430f289e55cSJeff Chang static int _mt6660_chip_sw_reset(struct mt6660_chip *chip) 431f289e55cSJeff Chang { 432f289e55cSJeff Chang int ret; 433f289e55cSJeff Chang 434f289e55cSJeff Chang /* turn on main pll first, then trigger reset */ 435f289e55cSJeff Chang ret = regmap_write(chip->regmap, MT6660_REG_SYSTEM_CTRL, 0x00); 436f289e55cSJeff Chang if (ret < 0) 437f289e55cSJeff Chang return ret; 438f289e55cSJeff Chang ret = regmap_write(chip->regmap, MT6660_REG_SYSTEM_CTRL, 0x80); 439f289e55cSJeff Chang if (ret < 0) 440f289e55cSJeff Chang return ret; 441f289e55cSJeff Chang msleep(30); 442f289e55cSJeff Chang return 0; 443f289e55cSJeff Chang } 444f289e55cSJeff Chang 445f289e55cSJeff Chang static int _mt6660_read_chip_revision(struct mt6660_chip *chip) 446f289e55cSJeff Chang { 447f289e55cSJeff Chang int ret; 448f289e55cSJeff Chang unsigned int val; 449f289e55cSJeff Chang 450f289e55cSJeff Chang ret = regmap_read(chip->regmap, MT6660_REG_DEVID, &val); 451f289e55cSJeff Chang if (ret < 0) { 452f289e55cSJeff Chang dev_err(chip->dev, "get chip revision fail\n"); 453f289e55cSJeff Chang return ret; 454f289e55cSJeff Chang } 455f289e55cSJeff Chang chip->chip_rev = val&0xff; 456f289e55cSJeff Chang dev_info(chip->dev, "%s chip_rev = %x\n", __func__, chip->chip_rev); 457f289e55cSJeff Chang return 0; 458f289e55cSJeff Chang } 459f289e55cSJeff Chang 460b6d7a80dSStephen Kitt static int mt6660_i2c_probe(struct i2c_client *client) 461f289e55cSJeff Chang { 462f289e55cSJeff Chang struct mt6660_chip *chip = NULL; 463f289e55cSJeff Chang int ret; 464f289e55cSJeff Chang 465f289e55cSJeff Chang dev_dbg(&client->dev, "%s\n", __func__); 466f289e55cSJeff Chang chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); 467f289e55cSJeff Chang if (!chip) 468f289e55cSJeff Chang return -ENOMEM; 469f289e55cSJeff Chang chip->i2c = client; 470f289e55cSJeff Chang chip->dev = &client->dev; 471f289e55cSJeff Chang mutex_init(&chip->io_lock); 472f289e55cSJeff Chang i2c_set_clientdata(client, chip); 473f289e55cSJeff Chang 474f289e55cSJeff Chang chip->regmap = devm_regmap_init(&client->dev, 475f289e55cSJeff Chang NULL, chip, &mt6660_regmap_config); 476f289e55cSJeff Chang if (IS_ERR(chip->regmap)) { 477f289e55cSJeff Chang ret = PTR_ERR(chip->regmap); 478f289e55cSJeff Chang dev_err(&client->dev, "failed to initialise regmap: %d\n", ret); 479f289e55cSJeff Chang return ret; 480f289e55cSJeff Chang } 481f289e55cSJeff Chang 482f289e55cSJeff Chang /* chip reset first */ 483f289e55cSJeff Chang ret = _mt6660_chip_sw_reset(chip); 484f289e55cSJeff Chang if (ret < 0) { 485f289e55cSJeff Chang dev_err(chip->dev, "chip reset fail\n"); 486f289e55cSJeff Chang goto probe_fail; 487f289e55cSJeff Chang } 488f289e55cSJeff Chang /* chip power on */ 489f289e55cSJeff Chang ret = _mt6660_chip_power_on(chip, 1); 490f289e55cSJeff Chang if (ret < 0) { 491f289e55cSJeff Chang dev_err(chip->dev, "chip power on 2 fail\n"); 492f289e55cSJeff Chang goto probe_fail; 493f289e55cSJeff Chang } 494f289e55cSJeff Chang /* chip devid check */ 495f289e55cSJeff Chang ret = _mt6660_chip_id_check(chip); 496f289e55cSJeff Chang if (ret < 0) { 497f289e55cSJeff Chang dev_err(chip->dev, "chip id check fail\n"); 498f289e55cSJeff Chang goto probe_fail; 499f289e55cSJeff Chang } 500f289e55cSJeff Chang /* chip revision get */ 501f289e55cSJeff Chang ret = _mt6660_read_chip_revision(chip); 502f289e55cSJeff Chang if (ret < 0) { 503f289e55cSJeff Chang dev_err(chip->dev, "read chip revision fail\n"); 504f289e55cSJeff Chang goto probe_fail; 505f289e55cSJeff Chang } 506c4ab29b0SZhang Qilong pm_runtime_set_active(chip->dev); 507c4ab29b0SZhang Qilong pm_runtime_enable(chip->dev); 508f289e55cSJeff Chang 509f289e55cSJeff Chang ret = devm_snd_soc_register_component(chip->dev, 510f289e55cSJeff Chang &mt6660_component_driver, 511f289e55cSJeff Chang &mt6660_codec_dai, 1); 512c4ab29b0SZhang Qilong if (ret) 513c4ab29b0SZhang Qilong pm_runtime_disable(chip->dev); 514b73f11e8SZhang Qilong 515f289e55cSJeff Chang return ret; 516b73f11e8SZhang Qilong 517f289e55cSJeff Chang probe_fail: 518f289e55cSJeff Chang _mt6660_chip_power_on(chip, 0); 519f289e55cSJeff Chang mutex_destroy(&chip->io_lock); 520f289e55cSJeff Chang return ret; 521f289e55cSJeff Chang } 522f289e55cSJeff Chang 523ed5c2f5fSUwe Kleine-König static void mt6660_i2c_remove(struct i2c_client *client) 524f289e55cSJeff Chang { 525f289e55cSJeff Chang struct mt6660_chip *chip = i2c_get_clientdata(client); 526f289e55cSJeff Chang 527f289e55cSJeff Chang pm_runtime_disable(chip->dev); 528f289e55cSJeff Chang pm_runtime_set_suspended(chip->dev); 529f289e55cSJeff Chang mutex_destroy(&chip->io_lock); 530f289e55cSJeff Chang } 531f289e55cSJeff Chang 532f289e55cSJeff Chang static int __maybe_unused mt6660_i2c_runtime_suspend(struct device *dev) 533f289e55cSJeff Chang { 534f289e55cSJeff Chang struct mt6660_chip *chip = dev_get_drvdata(dev); 535f289e55cSJeff Chang 536f289e55cSJeff Chang dev_dbg(dev, "enter low power mode\n"); 537f289e55cSJeff Chang return regmap_update_bits(chip->regmap, 538f289e55cSJeff Chang MT6660_REG_SYSTEM_CTRL, 0x01, 0x01); 539f289e55cSJeff Chang } 540f289e55cSJeff Chang 541f289e55cSJeff Chang static int __maybe_unused mt6660_i2c_runtime_resume(struct device *dev) 542f289e55cSJeff Chang { 543f289e55cSJeff Chang struct mt6660_chip *chip = dev_get_drvdata(dev); 544f289e55cSJeff Chang 545f289e55cSJeff Chang dev_dbg(dev, "exit low power mode\n"); 546f289e55cSJeff Chang return regmap_update_bits(chip->regmap, 547f289e55cSJeff Chang MT6660_REG_SYSTEM_CTRL, 0x01, 0x00); 548f289e55cSJeff Chang } 549f289e55cSJeff Chang 550f289e55cSJeff Chang static const struct dev_pm_ops mt6660_dev_pm_ops = { 551f289e55cSJeff Chang SET_RUNTIME_PM_OPS(mt6660_i2c_runtime_suspend, 552f289e55cSJeff Chang mt6660_i2c_runtime_resume, NULL) 553f289e55cSJeff Chang }; 554f289e55cSJeff Chang 555f289e55cSJeff Chang static const struct of_device_id __maybe_unused mt6660_of_id[] = { 556f289e55cSJeff Chang { .compatible = "mediatek,mt6660",}, 557f289e55cSJeff Chang {}, 558f289e55cSJeff Chang }; 559f289e55cSJeff Chang MODULE_DEVICE_TABLE(of, mt6660_of_id); 560f289e55cSJeff Chang 561f289e55cSJeff Chang static const struct i2c_device_id mt6660_i2c_id[] = { 562*ba2a2c37SUwe Kleine-König {"mt6660" }, 563f289e55cSJeff Chang {}, 564f289e55cSJeff Chang }; 565f289e55cSJeff Chang MODULE_DEVICE_TABLE(i2c, mt6660_i2c_id); 566f289e55cSJeff Chang 567f289e55cSJeff Chang static struct i2c_driver mt6660_i2c_driver = { 568f289e55cSJeff Chang .driver = { 569f289e55cSJeff Chang .name = "mt6660", 570f289e55cSJeff Chang .of_match_table = of_match_ptr(mt6660_of_id), 571f289e55cSJeff Chang .pm = &mt6660_dev_pm_ops, 572f289e55cSJeff Chang }, 5739abcd240SUwe Kleine-König .probe = mt6660_i2c_probe, 574f289e55cSJeff Chang .remove = mt6660_i2c_remove, 575f289e55cSJeff Chang .id_table = mt6660_i2c_id, 576f289e55cSJeff Chang }; 577f289e55cSJeff Chang module_i2c_driver(mt6660_i2c_driver); 578f289e55cSJeff Chang 579f289e55cSJeff Chang MODULE_AUTHOR("Jeff Chang <jeff_chang@richtek.com>"); 580f289e55cSJeff Chang MODULE_DESCRIPTION("MT6660 SPKAMP Driver"); 581f289e55cSJeff Chang MODULE_LICENSE("GPL"); 582eaa2330bSJeff Chang MODULE_VERSION("1.0.8_G"); 583