Alsa-devel
Threads by month
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
December 2019
- 123 participants
- 376 discussions
12 Dec '19
Hi,
this is a patch set to adapt the latest ALSA PCM API to staging
drivers. Basically these are merely cleanups, as shown in diffstat,
and there should be no functional changes.
As the corresponding ALSA PCM API change is found in 5.5-rc1, please
apply these on 5.5-rc1 or later. Or if you prefer, I can merge them
through sound tree, too. Let me know.
thanks,
Takashi
===
Takashi Iwai (4):
staging: most: Use managed buffer allocation
staging: bcm2835-audio: Use managed buffer allocation
staging: most: Drop superfluous ioctl PCM ops
staging: bcm2835-audio: Drop superfluous ioctl PCM ops
drivers/staging/most/sound/sound.c | 45 +---------------------
.../vc04_services/bcm2835-audio/bcm2835-pcm.c | 19 +--------
2 files changed, 2 insertions(+), 62 deletions(-)
--
2.16.4
3
7
12 Dec '19
---
sound/soc/codecs/Kconfig | 14 +
sound/soc/codecs/Makefile | 2 +
sound/soc/codecs/mt6660.c | 1063 +++++++++++++++++++++++++++++++++++++++++++++
sound/soc/codecs/mt6660.h | 95 ++++
4 files changed, 1174 insertions(+)
create mode 100644 sound/soc/codecs/mt6660.c
create mode 100644 sound/soc/codecs/mt6660.h
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 229cc89..806cd03 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -122,6 +122,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_ML26124 if I2C
select SND_SOC_MT6351 if MTK_PMIC_WRAP
select SND_SOC_MT6358 if MTK_PMIC_WRAP
+ select SND_SOC_MT6660 if I2C
select SND_SOC_NAU8540 if I2C
select SND_SOC_NAU8810 if I2C
select SND_SOC_NAU8822 if I2C
@@ -1465,6 +1466,19 @@ config SND_SOC_MT6358
Enable support for the platform which uses MT6358 as
external codec device.
+config SND_SOC_MT6660
+ tristate "Mediatek MT6660 Speaker Amplifier"
+ depends on I2C
+ select CRC32
+ select CRYPTO_SHA256
+ select CRYTO_RSA
+ help
+ MediaTek MT6660 is a smart power amplifier which contain
+ speaker protection, multi-band DRC, equalizer functions.
+ Select N if you don't have MT6660 on board.
+ Select M to build this as module.
+
+
config SND_SOC_NAU8540
tristate "Nuvoton Technology Corporation NAU85L40 CODEC"
depends on I2C
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index c498373..2b6814c 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -119,6 +119,7 @@ snd-soc-msm8916-analog-objs := msm8916-wcd-analog.o
snd-soc-msm8916-digital-objs := msm8916-wcd-digital.o
snd-soc-mt6351-objs := mt6351.o
snd-soc-mt6358-objs := mt6358.o
+snd-soc-mt6660-objs := mt6660.o
snd-soc-nau8540-objs := nau8540.o
snd-soc-nau8810-objs := nau8810.o
snd-soc-nau8822-objs := nau8822.o
@@ -403,6 +404,7 @@ obj-$(CONFIG_SND_SOC_MSM8916_WCD_ANALOG) +=snd-soc-msm8916-analog.o
obj-$(CONFIG_SND_SOC_MSM8916_WCD_DIGITAL) +=snd-soc-msm8916-digital.o
obj-$(CONFIG_SND_SOC_MT6351) += snd-soc-mt6351.o
obj-$(CONFIG_SND_SOC_MT6358) += snd-soc-mt6358.o
+obj-$(CONFIG_SND_SOC_MT6660) += snd-soc-mt6660.o
obj-$(CONFIG_SND_SOC_NAU8540) += snd-soc-nau8540.o
obj-$(CONFIG_SND_SOC_NAU8810) += snd-soc-nau8810.o
obj-$(CONFIG_SND_SOC_NAU8822) += snd-soc-nau8822.o
diff --git a/sound/soc/codecs/mt6660.c b/sound/soc/codecs/mt6660.c
new file mode 100644
index 0000000..92a2329
--- /dev/null
+++ b/sound/soc/codecs/mt6660.c
@@ -0,0 +1,1063 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 MediaTek Inc.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/pm_runtime.h>
+#include <linux/delay.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <sound/pcm_params.h>
+#include <linux/debugfs.h>
+
+#include "mt6660.h"
+
+struct codec_reg_val {
+ u32 addr;
+ u32 mask;
+ u32 data;
+};
+
+struct reg_size_table {
+ u32 addr;
+ u8 size;
+};
+
+static const struct reg_size_table mt6660_reg_size_table[] = {
+ { MT6660_REG_HPF1_COEF, 4 },
+ { MT6660_REG_HPF2_COEF, 4 },
+ { MT6660_REG_TDM_CFG3, 2 },
+ { MT6660_REG_RESV17, 2 },
+ { MT6660_REG_RESV23, 2 },
+ { MT6660_REG_SIGMAX, 2 },
+ { MT6660_REG_DEVID, 2},
+ { MT6660_REG_TDM_CFG3, 2},
+ { MT6660_REG_HCLIP_CTRL, 2},
+ { MT6660_REG_DA_GAIN, 2},
+};
+
+static int mt6660_get_reg_size(uint32_t addr)
+{
+ int i = 0;
+
+ for (i = 0; i < ARRAY_SIZE(mt6660_reg_size_table); i++) {
+ if (mt6660_reg_size_table[i].addr == addr)
+ return mt6660_reg_size_table[i].size;
+ }
+ return 1;
+}
+
+#if GENERIC_DEBUGFS
+static int mt6660_dbg_io_read(void *drvdata, u16 reg, void *val, u16 size)
+{
+ struct mt6660_chip *chip = (struct mt6660_chip *)drvdata;
+ int ret = 0, i = 0;
+ unsigned int data;
+ u8 *_val = val;
+
+ if (size != 1 && size != 2 && size != 4) {
+ dev_err(chip->dev, "%s size not match\n", __func__);
+ return -EINVAL;
+ }
+ ret = regmap_read(chip->regmap, reg, &data);
+ if (reg < 0)
+ return ret;
+
+ for (i = 0; i < size; i++)
+ _val[size-i-1] = (data >> (8*i))&0xff;
+
+ return 0;
+}
+
+static int mt6660_dbg_io_write(void *drvdata, u16 reg,
+ const void *val, u16 size)
+{
+ struct mt6660_chip *chip = (struct mt6660_chip *)drvdata;
+ int reg_size = mt6660_get_reg_size(reg);
+ int i = 0;
+ unsigned int regval = 0;
+ u8 *_val = (u8 *)val;
+
+ if (size != reg_size) {
+ dev_err(chip->dev,
+ "%s size not match reg_size(%d), size(%d)\n",
+ __func__, reg_size, size);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < size; i++) {
+ regval <<= 8;
+ regval |= _val[i];
+ }
+
+ return regmap_write(chip->regmap, reg, regval);
+}
+#endif /* GENERIC_DEBUGFS */
+
+static int mt6660_reg_write(void *context, unsigned int reg, unsigned int val)
+{
+ struct mt6660_chip *chip = context;
+ int size = mt6660_get_reg_size(reg);
+ u8 reg_data[4] = {0};
+ int i = 0;
+
+ for (i = 0; i < size; i++)
+ reg_data[size - i - 1] = (val >> (8 * i)) & 0xff;
+
+ return i2c_smbus_write_i2c_block_data(chip->i2c, reg, size, reg_data);
+}
+
+static int mt6660_reg_read(void *context, unsigned int reg, unsigned int *val)
+{
+ struct mt6660_chip *chip = context;
+ int size = mt6660_get_reg_size(reg);
+ int i = 0, ret = 0;
+ u8 data[4] = {0};
+ u32 reg_data = 0;
+
+ ret = i2c_smbus_read_i2c_block_data(chip->i2c, reg, size, data);
+ if (ret < 0)
+ return ret;
+ for (i = 0; i < size; i++) {
+ reg_data <<= 8;
+ reg_data |= data[i];
+ }
+ *val = reg_data;
+
+ return ret;
+}
+
+static bool mt6660_volatile_reg(struct device *dev, unsigned int reg)
+{
+ return true;
+}
+
+static struct regmap_config mt6660_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 32,
+ .reg_write = mt6660_reg_write,
+ .reg_read = mt6660_reg_read,
+ .volatile_reg = mt6660_volatile_reg,
+};
+
+static unsigned int mt6660_component_io_read(
+ struct snd_soc_component *component, unsigned int reg)
+{
+ struct mt6660_chip *chip = snd_soc_component_get_drvdata(component);
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(chip->regmap, reg, &val);
+ if (ret < 0) /* ret success -> >= 0, fail -> < - */
+ return ret;
+ pr_err("%s val = 0x%x\n", __func__, val);
+ return val;
+}
+
+static int mt6660_component_io_write(struct snd_soc_component *component,
+ unsigned int reg, unsigned int data)
+{
+ struct mt6660_chip *chip = snd_soc_component_get_drvdata(component);
+
+ pr_err("%s data = 0x%x\n", __func__, data);
+ return regmap_write(chip->regmap, reg, data);
+}
+
+static const int mt6660_dump_table[] = {
+ MT6660_REG_DEVID,
+ MT6660_REG_SYSTEM_CTRL,
+ MT6660_REG_IRQ_STATUS1,
+ MT6660_REG_ADDA_CLOCK,
+ MT6660_REG_SERIAL_CFG1,
+ MT6660_REG_DATAO_SEL,
+ MT6660_REG_TDM_CFG3,
+ MT6660_REG_HPF_CTRL,
+ MT6660_REG_HPF1_COEF,
+ MT6660_REG_HPF2_COEF,
+ MT6660_REG_PATH_BYPASS,
+ MT6660_REG_WDT_CTRL,
+ MT6660_REG_HCLIP_CTRL,
+ MT6660_REG_VOL_CTRL,
+ MT6660_REG_SPS_CTRL,
+ MT6660_REG_SIGMAX,
+ MT6660_REG_CALI_T0,
+ MT6660_REG_BST_CTRL,
+ MT6660_REG_PROTECTION_CFG,
+ MT6660_REG_DA_GAIN,
+ MT6660_REG_AUDIO_IN2_SEL,
+ MT6660_REG_SIG_GAIN,
+ MT6660_REG_PLL_CFG1,
+ MT6660_REG_DRE_CTRL,
+ MT6660_REG_DRE_THDMODE,
+ MT6660_REG_DRE_CORASE,
+ MT6660_REG_PWM_CTRL,
+ MT6660_REG_DC_PROTECT_CTRL,
+ MT6660_REG_ADC_USB_MODE,
+ MT6660_REG_INTERNAL_CFG,
+ MT6660_REG_RESV0,
+ MT6660_REG_RESV1,
+ MT6660_REG_RESV2,
+ MT6660_REG_RESV3,
+ MT6660_REG_RESV7,
+ MT6660_REG_RESV10,
+ MT6660_REG_RESV11,
+ MT6660_REG_RESV16,
+ MT6660_REG_RESV17,
+ MT6660_REG_RESV19,
+ MT6660_REG_RESV21,
+ MT6660_REG_RESV23,
+ MT6660_REG_RESV31,
+ MT6660_REG_RESV40,
+};
+
+#if GENERIC_DEBUGFS
+#ifdef CONFIG_DEBUG_FS
+/* reg/size/data/bustype */
+#define PREALLOC_RBUFFER_SIZE (32)
+#define PREALLOC_WBUFFER_SIZE (1000)
+
+static int data_debug_show(struct seq_file *s, void *data)
+{
+ struct dbg_info *di = s->private;
+ struct dbg_internal *d = &di->internal;
+ void *buffer;
+ u8 *pdata;
+ int i, ret;
+
+ if (d->data_buffer_size < d->size) {
+ buffer = kzalloc(d->size, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+ kfree(d->data_buffer);
+ d->data_buffer = buffer;
+ d->data_buffer_size = d->size;
+ }
+ /* read transfer */
+ if (!di->io_read)
+ return -EPERM;
+ ret = di->io_read(di->io_drvdata, d->reg, d->data_buffer, d->size);
+ if (ret < 0)
+ return ret;
+ pdata = d->data_buffer;
+ seq_printf(s, "0x");
+ for (i = 0; i < d->size; i++)
+ seq_printf(s, "%02x,", *(pdata + i));
+ seq_printf(s, "\n");
+ return 0;
+}
+
+static int data_debug_open(struct inode *inode, struct file *file)
+{
+ if (file->f_mode & FMODE_READ)
+ return single_open(file, data_debug_show, inode->i_private);
+ return simple_open(inode, file);
+}
+
+static ssize_t data_debug_write(struct file *file,
+ const char __user *user_buf,
+ size_t cnt, loff_t *loff)
+{
+ struct dbg_info *di = file->private_data;
+ struct dbg_internal *d = &di->internal;
+ void *buffer;
+ u8 *pdata;
+ char buf[PREALLOC_WBUFFER_SIZE + 1], *token, *cur;
+ int val_cnt = 0, ret;
+
+ if (cnt > PREALLOC_WBUFFER_SIZE)
+ return -ENOMEM;
+ if (copy_from_user(buf, user_buf, cnt))
+ return -EFAULT;
+ buf[cnt] = 0;
+ /* buffer size check */
+ if (d->data_buffer_size < d->size) {
+ buffer = kzalloc(d->size, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+ kfree(d->data_buffer);
+ d->data_buffer = buffer;
+ d->data_buffer_size = d->size;
+ }
+ /* data parsing */
+ cur = buf;
+ pdata = d->data_buffer;
+ while ((token = strsep(&cur, ",\n")) != NULL) {
+ if (!*token)
+ break;
+ if (val_cnt++ >= d->size)
+ break;
+ if (kstrtou8(token, 16, pdata++))
+ return -EINVAL;
+ }
+ if (val_cnt != d->size)
+ return -EINVAL;
+ /* write transfer */
+ if (!di->io_write)
+ return -EPERM;
+ ret = di->io_write(di->io_drvdata, d->reg, d->data_buffer, d->size);
+ return (ret < 0) ? ret : cnt;
+}
+
+static int data_debug_release(struct inode *inode, struct file *file)
+{
+ if (file->f_mode & FMODE_READ)
+ return single_release(inode, file);
+ return 0;
+}
+
+static const struct file_operations data_debug_fops = {
+ .open = data_debug_open,
+ .read = seq_read,
+ .write = data_debug_write,
+ .llseek = seq_lseek,
+ .release = data_debug_release,
+};
+
+static int type_debug_show(struct seq_file *s, void *data)
+{
+ struct dbg_info *di = s->private;
+
+ seq_printf(s, "%s,%s\n", di->typestr, di->devname);
+ return 0;
+}
+
+static int type_debug_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, type_debug_show, inode->i_private);
+}
+
+static const struct file_operations type_debug_fops = {
+ .open = type_debug_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int dump_debug_show(struct seq_file *s, void *data)
+{
+ struct dbg_info *di = s->private;
+ struct mt6660_chip *chip =
+ container_of(di, struct mt6660_chip, dbg_info);
+ int i = 0, j = 0, ret = 0;
+ unsigned int val;
+ int size = 0;
+
+ if (!chip) {
+ pr_err("%s chip is null\n", __func__);
+ return -ENODEV;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(mt6660_dump_table); i++) {
+ ret = regmap_read(chip->regmap, mt6660_dump_table[i], &val);
+ size = mt6660_get_reg_size(mt6660_dump_table[i]);
+ seq_printf(s, "reg0x%02x:0x", mt6660_dump_table[i]);
+ for (j = size - 1; j >= 0; j--)
+ seq_printf(s, "%x,", (val >> 8*j)&0xff);
+ seq_printf(s, "\n");
+ }
+ return 0;
+}
+
+static int dump_debug_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, dump_debug_show, inode->i_private);
+}
+
+static const struct file_operations dump_debug_fops = {
+ .open = dump_debug_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static ssize_t lock_debug_read(struct file *file,
+ char __user *user_buf, size_t cnt, loff_t *loff)
+{
+ struct dbg_info *di = file->private_data;
+ struct dbg_internal *d = &di->internal;
+ char buf[10];
+
+ snprintf(buf, sizeof(buf), "%d\n", mutex_is_locked(&d->io_lock));
+ return simple_read_from_buffer(user_buf, cnt, loff, buf, strlen(buf));
+}
+
+static ssize_t lock_debug_write(struct file *file,
+ const char __user *user_buf,
+ size_t cnt, loff_t *loff)
+{
+ struct dbg_info *di = file->private_data;
+ struct dbg_internal *d = &di->internal;
+ u32 lock;
+ int ret;
+
+ ret = kstrtou32_from_user(user_buf, cnt, 0, &lock);
+ if (ret < 0)
+ return ret;
+ lock ? mutex_lock(&d->io_lock) : mutex_unlock(&d->io_lock);
+ return cnt;
+}
+
+static const struct file_operations lock_debug_fops = {
+ .open = simple_open,
+ .read = lock_debug_read,
+ .write = lock_debug_write,
+};
+
+static int generic_debugfs_init(struct dbg_info *di)
+{
+ struct dbg_internal *d = &di->internal;
+
+ /* valid check */
+ if (!di->dirname || !di->devname || !di->typestr)
+ return -EINVAL;
+ d->data_buffer_size = PREALLOC_RBUFFER_SIZE;
+ d->data_buffer = kzalloc(PREALLOC_RBUFFER_SIZE, GFP_KERNEL);
+ if (!d->data_buffer)
+ return -ENOMEM;
+ /* create debugfs */
+ d->rt_root = debugfs_lookup("ext_dev_io", NULL);
+ if (!d->rt_root) {
+ d->rt_root = debugfs_create_dir("ext_dev_io", NULL);
+ if (!d->rt_root)
+ return -ENODEV;
+ d->rt_dir_create = true;
+ }
+ d->ic_root = debugfs_create_dir(di->dirname, d->rt_root);
+ if (!d->ic_root)
+ goto err_cleanup_rt;
+ if (!debugfs_create_u16("reg", 0644, d->ic_root, &d->reg))
+ goto err_cleanup_ic;
+ if (!debugfs_create_u16("size", 0644, d->ic_root, &d->size))
+ goto err_cleanup_ic;
+ if (!debugfs_create_file("data", 0644,
+ d->ic_root, di, &data_debug_fops))
+ goto err_cleanup_ic;
+ if (!debugfs_create_file("type", 0444,
+ d->ic_root, di, &type_debug_fops))
+ goto err_cleanup_ic;
+ if (!debugfs_create_file("lock", 0644,
+ d->ic_root, di, &lock_debug_fops))
+ goto err_cleanup_ic;
+ if (!debugfs_create_file("dumps", 0444,
+ d->ic_root, di, &dump_debug_fops))
+ goto err_cleanup_ic;
+ mutex_init(&d->io_lock);
+ return 0;
+err_cleanup_ic:
+ debugfs_remove_recursive(d->ic_root);
+err_cleanup_rt:
+ if (d->rt_dir_create)
+ debugfs_remove_recursive(d->rt_root);
+ kfree(d->data_buffer);
+ return -ENODEV;
+}
+
+static void generic_debugfs_exit(struct dbg_info *di)
+{
+ struct dbg_internal *d = &di->internal;
+
+ mutex_destroy(&d->io_lock);
+ debugfs_remove_recursive(d->ic_root);
+ if (d->rt_dir_create)
+ debugfs_remove_recursive(d->rt_root);
+ kfree(d->data_buffer);
+}
+#else
+static inline int generic_debugfs_init(struct dbg_info *di)
+{
+ return 0;
+}
+
+static inline void generic_debugfs_exit(struct dbg_info *di) {}
+#endif /* CONFIG_DEBUG_FS */
+#endif /* GENERIC_DEBUGFS */
+
+/*
+ * MT6660 Generic Setting make this chip work normally.
+ * it is tuned by Richtek RDs.
+ */
+static const struct codec_reg_val generic_reg_inits[] = {
+ { MT6660_REG_WDT_CTRL, 0x80, 0x00 },
+ { MT6660_REG_SPS_CTRL, 0x01, 0x00 },
+ { MT6660_REG_AUDIO_IN2_SEL, 0x1c, 0x04 },
+ { MT6660_REG_RESV11, 0x0c, 0x00 },
+ { MT6660_REG_RESV31, 0x03, 0x03 },
+ { MT6660_REG_RESV40, 0x01, 0x00 },
+ { MT6660_REG_RESV0, 0x44, 0x04 },
+ { MT6660_REG_RESV19, 0xff, 0x82 },
+ { MT6660_REG_RESV17, 0x7777, 0x7273 },
+ { MT6660_REG_RESV16, 0x07, 0x03 },
+ { MT6660_REG_DRE_CORASE, 0xe0, 0x20 },
+ { MT6660_REG_ADDA_CLOCK, 0xff, 0x70 },
+ { MT6660_REG_RESV21, 0xff, 0x20 },
+ { MT6660_REG_DRE_THDMODE, 0xff, 0x40 },
+ { MT6660_REG_RESV23, 0xffff, 0x17f8 },
+ { MT6660_REG_PWM_CTRL, 0xff, 0x15 },
+ { MT6660_REG_ADC_USB_MODE, 0xff, 0x00 },
+ { MT6660_REG_PROTECTION_CFG, 0xff, 0x1d },
+ { MT6660_REG_HPF1_COEF, 0xffffffff, 0x7fdb7ffe },
+ { MT6660_REG_HPF2_COEF, 0xffffffff, 0x7fdb7ffe },
+ { MT6660_REG_SIG_GAIN, 0xff, 0x58 },
+ { MT6660_REG_RESV6, 0xff, 0xce },
+ { MT6660_REG_SIGMAX, 0xffff, 0x7fff },
+ { MT6660_REG_DA_GAIN, 0xffff, 0x0116 },
+ { MT6660_REG_TDM_CFG3, 0x1800, 0x0800 },
+ { MT6660_REG_DRE_CTRL, 0x1f, 0x07 },
+};
+
+static int mt6660_component_init_setting(struct snd_soc_component *component)
+{
+ int i, len, ret;
+ const struct codec_reg_val *init_table;
+
+ pr_info("%s start\n", __func__);
+ init_table = generic_reg_inits;
+ len = ARRAY_SIZE(generic_reg_inits);
+
+ for (i = 0; i < len; i++) {
+ ret = snd_soc_component_update_bits(component,
+ init_table[i].addr,
+ init_table[i].mask, init_table[i].data);
+ if (ret < 0)
+ return ret;
+ }
+ pr_info("%s end\n", __func__);
+ return 0;
+}
+
+static int mt6660_component_set_bias_level(struct snd_soc_component *component,
+ enum snd_soc_bias_level level)
+{
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_component_get_dapm(component);
+ struct mt6660_chip *chip = snd_soc_component_get_drvdata(component);
+ unsigned int val;
+ int ret = 0;
+
+ switch (level) {
+ case SND_SOC_BIAS_OFF:
+ ret = regmap_read(chip->regmap, MT6660_REG_IRQ_STATUS1, &val);
+ dev_info(component->dev,
+ "%s reg0x05 = 0x%x\n", __func__, val);
+ break;
+ case SND_SOC_BIAS_ON:
+ case SND_SOC_BIAS_PREPARE:
+ /* Fall Through */
+ case SND_SOC_BIAS_STANDBY:
+ default:
+ break;
+ }
+ dapm->bias_level = level;
+ dev_dbg(component->dev, "c bias_level = %d\n", level);
+ return 0;
+}
+
+static int mt6660_codec_dac_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ usleep_range(1000, 1100);
+ break;
+ }
+ return 0;
+}
+
+static int mt6660_codec_classd_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ int ret = 0;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ dev_dbg(component->dev,
+ "%s: before classd turn on\n", __func__);
+ /* config to adaptive mode */
+ ret = snd_soc_component_update_bits(component,
+ MT6660_REG_BST_CTRL, 0x03, 0x03);
+ if (ret < 0) {
+ dev_err(component->dev, "config mode adaptive fail\n");
+ return ret;
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ /* voltage sensing enable */
+ ret = snd_soc_component_update_bits(component,
+ MT6660_REG_RESV7, 0x04, 0x04);
+ if (ret < 0) {
+ dev_err(component->dev,
+ "enable voltage sensing fail\n");
+ return ret;
+ }
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ /* voltage sensing disable */
+ ret = snd_soc_component_update_bits(component,
+ MT6660_REG_RESV7, 0x04, 0x00);
+ if (ret < 0) {
+ dev_err(component->dev,
+ "disable voltage sensing fail\n");
+ return ret;
+ }
+ /* pop-noise improvement 1 */
+ ret = snd_soc_component_update_bits(component,
+ MT6660_REG_RESV10, 0x10, 0x10);
+ if (ret < 0) {
+ dev_err(component->dev,
+ "pop-noise improvement 1 fail\n");
+ return ret;
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ dev_dbg(component->dev,
+ "%s: after classd turn off\n", __func__);
+ /* pop-noise improvement 2 */
+ ret = snd_soc_component_update_bits(component,
+ MT6660_REG_RESV10, 0x10, 0x00);
+ if (ret < 0) {
+ dev_err(component->dev,
+ "pop-noise improvement 2 fail\n");
+ return ret;
+ }
+ /* config to off mode */
+ ret = snd_soc_component_update_bits(component,
+ MT6660_REG_BST_CTRL, 0x03, 0x00);
+ if (ret < 0) {
+ dev_err(component->dev, "config mode off fail\n");
+ return ret;
+ }
+ break;
+ }
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget mt6660_component_dapm_widgets[] = {
+ SND_SOC_DAPM_DAC_E("DAC", NULL, MT6660_REG_PLL_CFG1,
+ 0, 1, mt6660_codec_dac_event, SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_ADC("VI ADC", NULL, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_PGA("PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_OUT_DRV_E("ClassD", MT6660_REG_SYSTEM_CTRL, 2, 0,
+ NULL, 0, mt6660_codec_classd_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_OUTPUT("OUTP"),
+ SND_SOC_DAPM_OUTPUT("OUTN"),
+};
+
+static const struct snd_soc_dapm_route mt6660_component_dapm_routes[] = {
+ { "DAC", NULL, "aif_playback"},
+ { "PGA", NULL, "DAC"},
+ { "ClassD", NULL, "PGA"},
+ { "OUTP", NULL, "ClassD"},
+ { "OUTN", NULL, "ClassD"},
+ { "VI ADC", NULL, "ClassD"},
+ { "aif_capture", NULL, "VI ADC"},
+};
+
+static int mt6660_component_put_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ int put_ret = 0;
+
+ pm_runtime_get_sync(component->dev);
+ put_ret = snd_soc_put_volsw(kcontrol, ucontrol);
+ if (put_ret < 0)
+ return put_ret;
+ pm_runtime_put(component->dev);
+ return put_ret;
+}
+
+static int mt6660_component_get_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct mt6660_chip *chip = (struct mt6660_chip *)
+ snd_soc_component_get_drvdata(component);
+ int ret = -EINVAL;
+
+ if (!strcmp(kcontrol->id.name, "Chip_Rev")) {
+ ucontrol->value.integer.value[0] = chip->chip_rev & 0x0f;
+ ret = 0;
+ }
+ return ret;
+}
+
+static const DECLARE_TLV_DB_SCALE(vol_ctl_tlv, -1155, 5, 0);
+
+static const struct snd_kcontrol_new mt6660_component_snd_controls[] = {
+ SOC_SINGLE_EXT_TLV("Digital Volume", MT6660_REG_VOL_CTRL, 0, 255,
+ 1, snd_soc_get_volsw, mt6660_component_put_volsw,
+ vol_ctl_tlv),
+ SOC_SINGLE_EXT("WDT Switch", MT6660_REG_WDT_CTRL, 7, 1, 0,
+ snd_soc_get_volsw, mt6660_component_put_volsw),
+ SOC_SINGLE_EXT("Hard_Clip Switch", MT6660_REG_HCLIP_CTRL, 8, 1, 0,
+ snd_soc_get_volsw, mt6660_component_put_volsw),
+ SOC_SINGLE_EXT("Clip Switch", MT6660_REG_SPS_CTRL, 0, 1, 0,
+ snd_soc_get_volsw, mt6660_component_put_volsw),
+ SOC_SINGLE_EXT("BoostMode", MT6660_REG_BST_CTRL, 0, 3, 0,
+ snd_soc_get_volsw, mt6660_component_put_volsw),
+ SOC_SINGLE_EXT("DRE Switch", MT6660_REG_DRE_CTRL, 0, 1, 0,
+ snd_soc_get_volsw, mt6660_component_put_volsw),
+ SOC_SINGLE_EXT("DC_Protect Switch",
+ MT6660_REG_DC_PROTECT_CTRL, 3, 1, 0,
+ snd_soc_get_volsw, mt6660_component_put_volsw),
+ SOC_SINGLE_EXT("audio input selection", MT6660_REG_DATAO_SEL, 6, 3, 0,
+ snd_soc_get_volsw, mt6660_component_put_volsw),
+ SOC_SINGLE_EXT("Data Output Left Channel Selection",
+ MT6660_REG_DATAO_SEL, 3, 7, 0,
+ snd_soc_get_volsw, mt6660_component_put_volsw),
+ SOC_SINGLE_EXT("Data Output Right Channel Selection",
+ MT6660_REG_DATAO_SEL, 0, 7, 0,
+ snd_soc_get_volsw, mt6660_component_put_volsw),
+ /* for debug purpose */
+ SOC_SINGLE_EXT("HPF_AUD_IN Switch", MT6660_REG_HPF_CTRL, 0, 1, 0,
+ snd_soc_get_volsw, mt6660_component_put_volsw),
+ SOC_SINGLE_EXT("AUD_LOOP_BACK Switch", MT6660_REG_PATH_BYPASS, 4, 1, 0,
+ snd_soc_get_volsw, mt6660_component_put_volsw),
+ SOC_SINGLE_EXT("Mute Switch", MT6660_REG_SYSTEM_CTRL, 1, 1, 0,
+ snd_soc_get_volsw, mt6660_component_put_volsw),
+ SOC_SINGLE_EXT("Bypass CS Comp Switch", MT6660_REG_PATH_BYPASS, 2, 1, 0,
+ snd_soc_get_volsw, mt6660_component_put_volsw),
+ SOC_SINGLE_EXT("T0_SEL", MT6660_REG_CALI_T0, 0, 7, 0,
+ snd_soc_get_volsw, NULL),
+ SOC_SINGLE_EXT("Chip_Rev", SND_SOC_NOPM, 0, 16, 0,
+ mt6660_component_get_volsw, NULL),
+};
+
+static int mt6660_component_probe(struct snd_soc_component *component)
+{
+ struct mt6660_chip *chip = snd_soc_component_get_drvdata(component);
+ int ret = 0;
+
+ pr_info("%s\n", __func__);
+ //snd_soc_component_init_regmap(component, chip->regmap);
+
+ /* init chip setting */
+ ret = mt6660_component_init_setting(component);
+ if (ret < 0)
+ dev_err(chip->dev, "chip i2c init setting fail\n");
+
+ return ret;
+}
+
+static void mt6660_component_remove(struct snd_soc_component *component)
+{
+ pr_info("%s\n", __func__);
+ snd_soc_component_exit_regmap(component);
+}
+
+static const struct snd_soc_component_driver mt6660_component_driver = {
+ .probe = mt6660_component_probe,
+ .remove = mt6660_component_remove,
+ .read = mt6660_component_io_read,
+ .write = mt6660_component_io_write,
+
+ .controls = mt6660_component_snd_controls,
+ .num_controls = ARRAY_SIZE(mt6660_component_snd_controls),
+ .dapm_widgets = mt6660_component_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(mt6660_component_dapm_widgets),
+ .dapm_routes = mt6660_component_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(mt6660_component_dapm_routes),
+
+ .set_bias_level = mt6660_component_set_bias_level,
+ .idle_bias_on = false, /* idle_bias_off = true */
+};
+
+static int mt6660_component_aif_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *dai)
+{
+ int word_len = params_physical_width(hw_params);
+ int aud_bit = params_width(hw_params);
+ u16 reg_data = 0;
+ int ret = 0;
+
+ dev_dbg(dai->dev, "%s: ++\n", __func__);
+ dev_dbg(dai->dev, "format: 0x%08x\n", params_format(hw_params));
+ dev_dbg(dai->dev, "rate: 0x%08x\n", params_rate(hw_params));
+ dev_dbg(dai->dev, "word_len: %d, aud_bit: %d\n", word_len, aud_bit);
+ if (word_len > 32 || word_len < 16) {
+ dev_err(dai->dev, "not supported word length\n");
+ return -ENOTSUPP;
+ }
+ switch (aud_bit) {
+ case 16:
+ reg_data = 3;
+ break;
+ case 18:
+ reg_data = 2;
+ break;
+ case 20:
+ reg_data = 1;
+ break;
+ case 24:
+ case 32:
+ reg_data = 0;
+ break;
+ default:
+ return -ENOTSUPP;
+ }
+ ret = snd_soc_component_update_bits(dai->component,
+ MT6660_REG_SERIAL_CFG1, 0xc0, (reg_data << 6));
+ if (ret < 0) {
+ dev_err(dai->dev, "config aud bit fail\n");
+ return ret;
+ }
+ ret = snd_soc_component_update_bits(dai->component,
+ MT6660_REG_TDM_CFG3, 0x3f0, word_len << 4);
+ if (ret < 0) {
+ dev_err(dai->dev, "config word len fail\n");
+ return ret;
+ }
+ dev_dbg(dai->dev, "%s: --\n", __func__);
+ return 0;
+}
+
+static const struct snd_soc_dai_ops mt6660_component_aif_ops = {
+ .hw_params = mt6660_component_aif_hw_params,
+};
+
+#define STUB_RATES SNDRV_PCM_RATE_8000_192000
+#define STUB_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_U16_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_U24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE | \
+ SNDRV_PCM_FMTBIT_U32_LE)
+
+static struct snd_soc_dai_driver mt6660_codec_dai = {
+ .name = "mt6660-aif",
+ .playback = {
+ .stream_name = "aif_playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = STUB_RATES,
+ .formats = STUB_FORMATS,
+ },
+ .capture = {
+ .stream_name = "aif_capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = STUB_RATES,
+ .formats = STUB_FORMATS,
+ },
+ /* dai properties */
+ .symmetric_rates = 1,
+ .symmetric_channels = 1,
+ .symmetric_samplebits = 1,
+ /* dai operations */
+ .ops = &mt6660_component_aif_ops,
+};
+
+static inline int _mt6660_chip_id_check(struct mt6660_chip *chip)
+{
+ u8 id[2] = {0};
+ int ret = 0;
+
+ ret = i2c_smbus_read_i2c_block_data(chip->i2c, MT6660_REG_DEVID, 2, id);
+ if (ret < 0)
+ return ret;
+ ret = (id[0] << 8) + id[1];
+ ret &= 0x0ff0;
+ if (ret != 0x00e0 && ret != 0x01e0)
+ return -ENODEV;
+ return ret;
+}
+
+static inline int _mt6660_chip_sw_reset(struct mt6660_chip *chip)
+{
+ int ret;
+
+ /* turn on main pll first, then trigger reset */
+ ret = regmap_write(chip->regmap, 0x03, 0x00);
+ if (ret < 0)
+ return ret;
+ ret = regmap_write(chip->regmap, MT6660_REG_SYSTEM_CTRL, 0x80);
+ msleep(30);
+ return 0;
+}
+
+static inline int _mt6660_chip_power_on(struct mt6660_chip *chip, int on_off)
+{
+ u8 reg_data = 0;
+ int ret = 0;
+
+ ret = i2c_smbus_read_byte_data(chip->i2c, MT6660_REG_SYSTEM_CTRL);
+ if (ret < 0)
+ return ret;
+ reg_data = (u8)ret;
+ if (on_off)
+ reg_data &= (~0x01);
+ else
+ reg_data |= 0x01;
+ return regmap_write(chip->regmap, MT6660_REG_SYSTEM_CTRL, reg_data);
+}
+
+static inline int _mt6660_read_chip_revision(struct mt6660_chip *chip)
+{
+ u8 reg_data[2] = {0};
+ int ret = 0;
+
+ ret = i2c_smbus_read_i2c_block_data(
+ chip->i2c, MT6660_REG_DEVID, 2, reg_data);
+ if (ret < 0) {
+ dev_err(chip->dev, "get chip revision fail\n");
+ return ret;
+ }
+ chip->chip_rev = reg_data[1];
+ return 0;
+}
+
+static int mt6660_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct mt6660_chip *chip = NULL;
+ int ret = 0;
+
+ pr_info("%s start\n", __func__);
+ chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+ chip->i2c = client;
+ chip->dev = &client->dev;
+ mutex_init(&chip->io_lock);
+ i2c_set_clientdata(client, chip);
+
+ chip->regmap = devm_regmap_init(&client->dev,
+ NULL, chip, &mt6660_regmap_config);
+ if (IS_ERR(chip->regmap)) {
+ ret = PTR_ERR(chip->regmap);
+ dev_err(&client->dev, "failed to initialise regmap: %d\n", ret);
+ return ret;
+ }
+
+#if GENERIC_DEBUGFS
+ /* debugfs interface */
+ chip->dbg_info.dirname = devm_kasprintf(&client->dev,
+ GFP_KERNEL, "MT6660.%s",
+ dev_name(&client->dev));
+ chip->dbg_info.devname = dev_name(&client->dev);
+ chip->dbg_info.typestr = devm_kasprintf(&client->dev,
+ GFP_KERNEL, "I2C,MT6660");
+ chip->dbg_info.io_drvdata = chip;
+ chip->dbg_info.io_read = mt6660_dbg_io_read;
+ chip->dbg_info.io_write = mt6660_dbg_io_write;
+
+ ret = generic_debugfs_init(&chip->dbg_info);
+ if (ret < 0) {
+ dev_err(&client->dev, "generic dbg init fail\n");
+ return -EINVAL;
+ }
+#endif /* GENERIC_DEBUGFS */
+
+ /* chip reset first */
+ ret = _mt6660_chip_sw_reset(chip);
+ if (ret < 0) {
+ dev_err(chip->dev, "chip reset fail\n");
+ goto probe_fail;
+ }
+ /* chip power on */
+ ret = _mt6660_chip_power_on(chip, 1);
+ if (ret < 0) {
+ dev_err(chip->dev, "chip power on 2 fail\n");
+ goto probe_fail;
+ }
+ /* chip devid check */
+ ret = _mt6660_chip_id_check(chip);
+ if (ret < 0) {
+ dev_err(chip->dev, "chip id check fail\n");
+ goto probe_fail;
+ }
+ /* chip revision get */
+ ret = _mt6660_read_chip_revision(chip);
+ if (ret < 0) {
+ dev_err(chip->dev, "read chip revision fail\n");
+ goto probe_fail;
+ }
+ pm_runtime_set_active(chip->dev);
+ pm_runtime_enable(chip->dev);
+
+ ret = devm_snd_soc_register_component(chip->dev,
+ &mt6660_component_driver,
+ &mt6660_codec_dai, 1);
+ pr_info("%s end, ret = %d\n", __func__, ret);
+ return ret;
+probe_fail:
+ _mt6660_chip_power_on(chip, 0);
+ mutex_destroy(&chip->io_lock);
+ return ret;
+}
+
+static int mt6660_i2c_remove(struct i2c_client *client)
+{
+ struct mt6660_chip *chip = i2c_get_clientdata(client);
+
+ pm_runtime_disable(chip->dev);
+ pm_runtime_set_suspended(chip->dev);
+#if GENERIC_DEBUGFS
+ generic_debugfs_exit(&chip->dbg_info);
+#endif /* GENERIC_DEBUGFS */
+ mutex_destroy(&chip->io_lock);
+ return 0;
+}
+
+static int __maybe_unused mt6660_i2c_runtime_suspend(struct device *dev)
+{
+ struct mt6660_chip *chip = dev_get_drvdata(dev);
+
+ dev_dbg(dev, "enter low power mode\n");
+ return regmap_update_bits(chip->regmap,
+ MT6660_REG_SYSTEM_CTRL, 0x01, 0x01);
+}
+
+static int __maybe_unused mt6660_i2c_runtime_resume(struct device *dev)
+{
+ struct mt6660_chip *chip = dev_get_drvdata(dev);
+
+ dev_dbg(dev, "exit low power mode\n");
+ return regmap_update_bits(chip->regmap,
+ MT6660_REG_SYSTEM_CTRL, 0x01, 0x00);
+}
+
+static const struct dev_pm_ops mt6660_dev_pm_ops = {
+ SET_RUNTIME_PM_OPS(mt6660_i2c_runtime_suspend,
+ mt6660_i2c_runtime_resume, NULL)
+};
+
+static const struct of_device_id __maybe_unused mt6660_of_id[] = {
+ { .compatible = "mediatek,mt6660",},
+ {},
+};
+MODULE_DEVICE_TABLE(of, mt6660_of_id);
+
+static const struct i2c_device_id mt6660_i2c_id[] = {
+ {"mt6660", 0 },
+ {},
+};
+MODULE_DEVICE_TABLE(i2c, mt6660_i2c_id);
+
+static struct i2c_driver mt6660_i2c_driver = {
+ .driver = {
+ .name = "mt6660",
+ .of_match_table = of_match_ptr(mt6660_of_id),
+ .pm = &mt6660_dev_pm_ops,
+ },
+ .probe = mt6660_i2c_probe,
+ .remove = mt6660_i2c_remove,
+ .id_table = mt6660_i2c_id,
+};
+module_i2c_driver(mt6660_i2c_driver);
+
+MODULE_AUTHOR("Jeff Chang <jeff_chang(a)richtek.com>");
+MODULE_DESCRIPTION("MT6660 SPKAMP Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.0.7_G");
diff --git a/sound/soc/codecs/mt6660.h b/sound/soc/codecs/mt6660.h
new file mode 100644
index 0000000..9e62dcc
--- /dev/null
+++ b/sound/soc/codecs/mt6660.h
@@ -0,0 +1,95 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2019 MediaTek Inc.
+ */
+
+#ifndef __SND_SOC_MT6660_H
+#define __SND_SOC_MT6660_H
+
+#include <linux/mutex.h>
+#include <linux/regmap.h>
+
+#define GENERIC_DEBUGFS 0
+
+#if GENERIC_DEBUGFS
+struct dbg_internal {
+ struct dentry *rt_root;
+ struct dentry *ic_root;
+ bool rt_dir_create;
+ struct mutex io_lock;
+ u16 reg;
+ u16 size;
+ u16 data_buffer_size;
+ void *data_buffer;
+};
+
+struct dbg_info {
+ const char *dirname;
+ const char *devname;
+ const char *typestr;
+ void *io_drvdata;
+ int (*io_read)(void *drvdata, u16 reg, void *val, u16 size);
+ int (*io_write)(void *drvdata, u16 reg, const void *val, u16 size);
+ struct dbg_internal internal;
+};
+#endif /* GENERIC_DEBUGFS */
+
+struct mt6660_chip {
+ struct i2c_client *i2c;
+ struct device *dev;
+ struct platform_device *param_dev;
+ struct mutex io_lock;
+#if GENERIC_DEBUGFS
+ struct dbg_info dbg_info;
+#endif /* GENERIC_DEBUGFS */
+ struct regmap *regmap;
+ u16 chip_rev;
+};
+
+#define MT6660_REG_DEVID (0x00)
+#define MT6660_REG_SYSTEM_CTRL (0x03)
+#define MT6660_REG_IRQ_STATUS1 (0x05)
+#define MT6660_REG_ADDA_CLOCK (0x07)
+#define MT6660_REG_SERIAL_CFG1 (0x10)
+#define MT6660_REG_DATAO_SEL (0x12)
+#define MT6660_REG_TDM_CFG3 (0x15)
+#define MT6660_REG_HPF_CTRL (0x18)
+#define MT6660_REG_HPF1_COEF (0x1A)
+#define MT6660_REG_HPF2_COEF (0x1B)
+#define MT6660_REG_PATH_BYPASS (0x1E)
+#define MT6660_REG_WDT_CTRL (0x20)
+#define MT6660_REG_HCLIP_CTRL (0x24)
+#define MT6660_REG_VOL_CTRL (0x29)
+#define MT6660_REG_SPS_CTRL (0x30)
+#define MT6660_REG_SIGMAX (0x33)
+#define MT6660_REG_CALI_T0 (0x3F)
+#define MT6660_REG_BST_CTRL (0x40)
+#define MT6660_REG_PROTECTION_CFG (0x46)
+#define MT6660_REG_DA_GAIN (0x4c)
+#define MT6660_REG_AUDIO_IN2_SEL (0x50)
+#define MT6660_REG_SIG_GAIN (0x51)
+#define MT6660_REG_PLL_CFG1 (0x60)
+#define MT6660_REG_DRE_CTRL (0x68)
+#define MT6660_REG_DRE_THDMODE (0x69)
+#define MT6660_REG_DRE_CORASE (0x6B)
+#define MT6660_REG_PWM_CTRL (0x70)
+#define MT6660_REG_DC_PROTECT_CTRL (0x74)
+#define MT6660_REG_ADC_USB_MODE (0x7c)
+#define MT6660_REG_INTERNAL_CFG (0x88)
+#define MT6660_REG_RESV0 (0x98)
+#define MT6660_REG_RESV1 (0x99)
+#define MT6660_REG_RESV2 (0x9A)
+#define MT6660_REG_RESV3 (0x9B)
+#define MT6660_REG_RESV6 (0xA2)
+#define MT6660_REG_RESV7 (0xA3)
+#define MT6660_REG_RESV10 (0xB0)
+#define MT6660_REG_RESV11 (0xB1)
+#define MT6660_REG_RESV16 (0xB6)
+#define MT6660_REG_RESV17 (0xB7)
+#define MT6660_REG_RESV19 (0xB9)
+#define MT6660_REG_RESV21 (0xBB)
+#define MT6660_REG_RESV23 (0xBD)
+#define MT6660_REG_RESV31 (0xD3)
+#define MT6660_REG_RESV40 (0xE0)
+
+#endif /* __SND_SOC_MT6660_H */
--
2.7.4
2
1
[alsa-devel] [PATCH] ALSA: hda: tegra: Fix unused variable compile warning
by Takashi Iwai 12 Dec '19
by Takashi Iwai 12 Dec '19
12 Dec '19
Forgot to remove the variable declaration as well in the last commit.
sound/pci/hda/hda_tegra.c: In function 'hda_tegra_runtime_suspend':
sound/pci/hda/hda_tegra.c:169:19: warning: unused variable 'bus' [-Wunused-variable]
Fixes: f36da9406e66 ("ALSA: hda: Support PCM sync_stop")
Reported-by: Stephen Rothwell <sfr(a)canb.auug.org.au>
Signed-off-by: Takashi Iwai <tiwai(a)suse.de>
---
sound/pci/hda/hda_tegra.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c
index fc2e0a294bc1..269f242fcbfd 100644
--- a/sound/pci/hda/hda_tegra.c
+++ b/sound/pci/hda/hda_tegra.c
@@ -166,7 +166,6 @@ static int __maybe_unused hda_tegra_runtime_suspend(struct device *dev)
struct snd_card *card = dev_get_drvdata(dev);
struct azx *chip = card->private_data;
struct hda_tegra *hda = container_of(chip, struct hda_tegra, chip);
- struct hdac_bus *bus = azx_bus(chip);
if (chip && chip->running) {
azx_stop_chip(chip);
--
2.16.4
1
0
12 Dec '19
---
sound/soc/codecs/Kconfig | 14 +
sound/soc/codecs/Makefile | 2 +
sound/soc/codecs/mt6660.c | 1065 +++++++++++++++++++++++++++++++++++++++++++++
sound/soc/codecs/mt6660.h | 95 ++++
4 files changed, 1176 insertions(+)
create mode 100644 sound/soc/codecs/mt6660.c
create mode 100644 sound/soc/codecs/mt6660.h
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 229cc89..806cd03 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -122,6 +122,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_ML26124 if I2C
select SND_SOC_MT6351 if MTK_PMIC_WRAP
select SND_SOC_MT6358 if MTK_PMIC_WRAP
+ select SND_SOC_MT6660 if I2C
select SND_SOC_NAU8540 if I2C
select SND_SOC_NAU8810 if I2C
select SND_SOC_NAU8822 if I2C
@@ -1465,6 +1466,19 @@ config SND_SOC_MT6358
Enable support for the platform which uses MT6358 as
external codec device.
+config SND_SOC_MT6660
+ tristate "Mediatek MT6660 Speaker Amplifier"
+ depends on I2C
+ select CRC32
+ select CRYPTO_SHA256
+ select CRYTO_RSA
+ help
+ MediaTek MT6660 is a smart power amplifier which contain
+ speaker protection, multi-band DRC, equalizer functions.
+ Select N if you don't have MT6660 on board.
+ Select M to build this as module.
+
+
config SND_SOC_NAU8540
tristate "Nuvoton Technology Corporation NAU85L40 CODEC"
depends on I2C
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index c498373..2b6814c 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -119,6 +119,7 @@ snd-soc-msm8916-analog-objs := msm8916-wcd-analog.o
snd-soc-msm8916-digital-objs := msm8916-wcd-digital.o
snd-soc-mt6351-objs := mt6351.o
snd-soc-mt6358-objs := mt6358.o
+snd-soc-mt6660-objs := mt6660.o
snd-soc-nau8540-objs := nau8540.o
snd-soc-nau8810-objs := nau8810.o
snd-soc-nau8822-objs := nau8822.o
@@ -403,6 +404,7 @@ obj-$(CONFIG_SND_SOC_MSM8916_WCD_ANALOG) +=snd-soc-msm8916-analog.o
obj-$(CONFIG_SND_SOC_MSM8916_WCD_DIGITAL) +=snd-soc-msm8916-digital.o
obj-$(CONFIG_SND_SOC_MT6351) += snd-soc-mt6351.o
obj-$(CONFIG_SND_SOC_MT6358) += snd-soc-mt6358.o
+obj-$(CONFIG_SND_SOC_MT6660) += snd-soc-mt6660.o
obj-$(CONFIG_SND_SOC_NAU8540) += snd-soc-nau8540.o
obj-$(CONFIG_SND_SOC_NAU8810) += snd-soc-nau8810.o
obj-$(CONFIG_SND_SOC_NAU8822) += snd-soc-nau8822.o
diff --git a/sound/soc/codecs/mt6660.c b/sound/soc/codecs/mt6660.c
new file mode 100644
index 0000000..9e9d496
--- /dev/null
+++ b/sound/soc/codecs/mt6660.c
@@ -0,0 +1,1065 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 MediaTek Inc.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/pm_runtime.h>
+#include <linux/delay.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <sound/pcm_params.h>
+#include <linux/debugfs.h>
+
+#include "mt6660.h"
+
+struct codec_reg_val {
+ u32 addr;
+ u32 mask;
+ u32 data;
+};
+
+struct reg_size_table {
+ u32 addr;
+ u8 size;
+};
+
+static const struct reg_size_table mt6660_reg_size_table[] = {
+ { MT6660_REG_HPF1_COEF, 4 },
+ { MT6660_REG_HPF2_COEF, 4 },
+ { MT6660_REG_TDM_CFG3, 2 },
+ { MT6660_REG_RESV17, 2 },
+ { MT6660_REG_RESV23, 2 },
+ { MT6660_REG_SIGMAX, 2 },
+ { MT6660_REG_DEVID, 2},
+ { MT6660_REG_TDM_CFG3, 2},
+ { MT6660_REG_HCLIP_CTRL, 2},
+ { MT6660_REG_DA_GAIN, 2},
+};
+
+static int mt6660_get_reg_size(uint32_t addr)
+{
+ int i = 0;
+
+ for (i = 0; i < ARRAY_SIZE(mt6660_reg_size_table); i++) {
+ if (mt6660_reg_size_table[i].addr == addr)
+ return mt6660_reg_size_table[i].size;
+ }
+ return 1;
+}
+
+#if GENERIC_DEBUGFS
+static int mt6660_dbg_io_read(void *drvdata, u16 reg, void *val, u16 size)
+{
+ struct mt6660_chip *chip = (struct mt6660_chip *)drvdata;
+ int ret = 0, i = 0;
+ unsigned int data;
+ u8 *_val = val;
+
+ if (size != 1 && size != 2 && size != 4) {
+ dev_err(chip->dev, "%s size not match\n", __func__);
+ return -EINVAL;
+ }
+ ret = regmap_read(chip->regmap, reg, &data);
+ if (reg < 0)
+ return ret;
+
+ for (i = 0; i < size; i++)
+ _val[size-i-1] = (data >> (8*i))&0xff;
+
+ return 0;
+}
+
+static int mt6660_dbg_io_write(void *drvdata, u16 reg,
+ const void *val, u16 size)
+{
+ struct mt6660_chip *chip = (struct mt6660_chip *)drvdata;
+ int reg_size = mt6660_get_reg_size(reg);
+ int i = 0;
+ unsigned int regval = 0;
+ u8 *_val = (u8 *)val;
+
+ if (size != reg_size) {
+ dev_err(chip->dev,
+ "%s size not match reg_size(%d), size(%d)\n",
+ __func__, reg_size, size);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < size; i++) {
+ regval <<= 8;
+ regval |= _val[i];
+ }
+
+ return regmap_write(chip->regmap, reg, regval);
+}
+#endif /* GENERIC_DEBUGFS */
+
+static int mt6660_reg_write(void *context, unsigned int reg, unsigned int val)
+{
+ struct mt6660_chip *chip = context;
+ int size = mt6660_get_reg_size(reg);
+ u8 reg_data[4] = {0};
+ int i = 0;
+
+ for (i = 0; i < size; i++)
+ reg_data[size - i - 1] = (val >> (8 * i)) & 0xff;
+
+ return i2c_smbus_write_i2c_block_data(chip->i2c, reg, size, reg_data);
+}
+
+static int mt6660_reg_read(void *context, unsigned int reg, unsigned int *val)
+{
+ struct mt6660_chip *chip = context;
+ int size = mt6660_get_reg_size(reg);
+ int i = 0, ret = 0;
+ u8 data[4] = {0};
+ u32 reg_data = 0;
+
+ ret = i2c_smbus_read_i2c_block_data(chip->i2c, reg, size, data);
+ if (ret < 0)
+ return ret;
+ for (i = 0; i < size; i++) {
+ reg_data <<= 8;
+ reg_data |= data[i];
+ }
+ *val = reg_data;
+
+ return ret;
+}
+
+static bool mt6660_volatile_reg(struct device *dev, unsigned int reg)
+{
+ return true;
+}
+
+static struct regmap_config mt6660_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 32,
+ .reg_write = mt6660_reg_write,
+ .reg_read = mt6660_reg_read,
+ .volatile_reg = mt6660_volatile_reg,
+};
+
+static unsigned int mt6660_component_io_read(
+ struct snd_soc_component *component, unsigned int reg)
+{
+ struct mt6660_chip *chip = snd_soc_component_get_drvdata(component);
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(chip->regmap, reg, &val);
+ if (ret < 0) /* ret success -> >= 0, fail -> < - */
+ return ret;
+ pr_err("%s val = 0x%x\n", __func__, val);
+ return val;
+}
+
+static int mt6660_component_io_write(struct snd_soc_component *component,
+ unsigned int reg, unsigned int data)
+{
+ struct mt6660_chip *chip = snd_soc_component_get_drvdata(component);
+
+ pr_err("%s data = 0x%x\n", __func__, data);
+ return regmap_write(chip->regmap, reg, data);
+}
+
+static const int mt6660_dump_table[] = {
+ MT6660_REG_DEVID,
+ MT6660_REG_SYSTEM_CTRL,
+ MT6660_REG_IRQ_STATUS1,
+ MT6660_REG_ADDA_CLOCK,
+ MT6660_REG_SERIAL_CFG1,
+ MT6660_REG_DATAO_SEL,
+ MT6660_REG_TDM_CFG3,
+ MT6660_REG_HPF_CTRL,
+ MT6660_REG_HPF1_COEF,
+ MT6660_REG_HPF2_COEF,
+ MT6660_REG_PATH_BYPASS,
+ MT6660_REG_WDT_CTRL,
+ MT6660_REG_HCLIP_CTRL,
+ MT6660_REG_VOL_CTRL,
+ MT6660_REG_SPS_CTRL,
+ MT6660_REG_SIGMAX,
+ MT6660_REG_CALI_T0,
+ MT6660_REG_BST_CTRL,
+ MT6660_REG_PROTECTION_CFG,
+ MT6660_REG_DA_GAIN,
+ MT6660_REG_AUDIO_IN2_SEL,
+ MT6660_REG_SIG_GAIN,
+ MT6660_REG_PLL_CFG1,
+ MT6660_REG_DRE_CTRL,
+ MT6660_REG_DRE_THDMODE,
+ MT6660_REG_DRE_CORASE,
+ MT6660_REG_PWM_CTRL,
+ MT6660_REG_DC_PROTECT_CTRL,
+ MT6660_REG_ADC_USB_MODE,
+ MT6660_REG_INTERNAL_CFG,
+ MT6660_REG_RESV0,
+ MT6660_REG_RESV1,
+ MT6660_REG_RESV2,
+ MT6660_REG_RESV3,
+ MT6660_REG_RESV7,
+ MT6660_REG_RESV10,
+ MT6660_REG_RESV11,
+ MT6660_REG_RESV16,
+ MT6660_REG_RESV17,
+ MT6660_REG_RESV19,
+ MT6660_REG_RESV21,
+ MT6660_REG_RESV23,
+ MT6660_REG_RESV31,
+ MT6660_REG_RESV40,
+};
+
+#if GENERIC_DEBUGFS
+#ifdef CONFIG_DEBUG_FS
+/* reg/size/data/bustype */
+#define PREALLOC_RBUFFER_SIZE (32)
+#define PREALLOC_WBUFFER_SIZE (1000)
+
+static int data_debug_show(struct seq_file *s, void *data)
+{
+ struct dbg_info *di = s->private;
+ struct dbg_internal *d = &di->internal;
+ void *buffer;
+ u8 *pdata;
+ int i, ret;
+
+ if (d->data_buffer_size < d->size) {
+ buffer = kzalloc(d->size, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+ kfree(d->data_buffer);
+ d->data_buffer = buffer;
+ d->data_buffer_size = d->size;
+ }
+ /* read transfer */
+ if (!di->io_read)
+ return -EPERM;
+ ret = di->io_read(di->io_drvdata, d->reg, d->data_buffer, d->size);
+ if (ret < 0)
+ return ret;
+ pdata = d->data_buffer;
+ seq_printf(s, "0x");
+ for (i = 0; i < d->size; i++)
+ seq_printf(s, "%02x,", *(pdata + i));
+ seq_printf(s, "\n");
+ return 0;
+}
+
+static int data_debug_open(struct inode *inode, struct file *file)
+{
+ if (file->f_mode & FMODE_READ)
+ return single_open(file, data_debug_show, inode->i_private);
+ return simple_open(inode, file);
+}
+
+static ssize_t data_debug_write(struct file *file,
+ const char __user *user_buf,
+ size_t cnt, loff_t *loff)
+{
+ struct dbg_info *di = file->private_data;
+ struct dbg_internal *d = &di->internal;
+ void *buffer;
+ u8 *pdata;
+ char buf[PREALLOC_WBUFFER_SIZE + 1], *token, *cur;
+ int val_cnt = 0, ret;
+
+ if (cnt > PREALLOC_WBUFFER_SIZE)
+ return -ENOMEM;
+ if (copy_from_user(buf, user_buf, cnt))
+ return -EFAULT;
+ buf[cnt] = 0;
+ /* buffer size check */
+ if (d->data_buffer_size < d->size) {
+ buffer = kzalloc(d->size, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+ kfree(d->data_buffer);
+ d->data_buffer = buffer;
+ d->data_buffer_size = d->size;
+ }
+ /* data parsing */
+ cur = buf;
+ pdata = d->data_buffer;
+ while ((token = strsep(&cur, ",\n")) != NULL) {
+ if (!*token)
+ break;
+ if (val_cnt++ >= d->size)
+ break;
+ if (kstrtou8(token, 16, pdata++))
+ return -EINVAL;
+ }
+ if (val_cnt != d->size)
+ return -EINVAL;
+ /* write transfer */
+ if (!di->io_write)
+ return -EPERM;
+ ret = di->io_write(di->io_drvdata, d->reg, d->data_buffer, d->size);
+ return (ret < 0) ? ret : cnt;
+}
+
+static int data_debug_release(struct inode *inode, struct file *file)
+{
+ if (file->f_mode & FMODE_READ)
+ return single_release(inode, file);
+ return 0;
+}
+
+static const struct file_operations data_debug_fops = {
+ .open = data_debug_open,
+ .read = seq_read,
+ .write = data_debug_write,
+ .llseek = seq_lseek,
+ .release = data_debug_release,
+};
+
+static int type_debug_show(struct seq_file *s, void *data)
+{
+ struct dbg_info *di = s->private;
+
+ seq_printf(s, "%s,%s\n", di->typestr, di->devname);
+ return 0;
+}
+
+static int type_debug_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, type_debug_show, inode->i_private);
+}
+
+static const struct file_operations type_debug_fops = {
+ .open = type_debug_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int dump_debug_show(struct seq_file *s, void *data)
+{
+ struct dbg_info *di = s->private;
+ struct mt6660_chip *chip =
+ container_of(di, struct mt6660_chip, dbg_info);
+ int i = 0, j = 0, ret = 0;
+ unsigned int val;
+ int size = 0;
+
+ if (!chip) {
+ pr_err("%s chip is null\n", __func__);
+ return -ENODEV;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(mt6660_dump_table); i++) {
+ ret = regmap_read(chip->regmap, mt6660_dump_table[i], &val);
+ size = mt6660_get_reg_size(mt6660_dump_table[i]);
+ seq_printf(s, "reg0x%02x:0x", mt6660_dump_table[i]);
+ for (j = size - 1; j >= 0; j--)
+ seq_printf(s, "%x,", (val >> 8*j)&0xff);
+ seq_printf(s, "\n");
+ }
+ return 0;
+}
+
+static int dump_debug_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, dump_debug_show, inode->i_private);
+}
+
+static const struct file_operations dump_debug_fops = {
+ .open = dump_debug_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static ssize_t lock_debug_read(struct file *file,
+ char __user *user_buf, size_t cnt, loff_t *loff)
+{
+ struct dbg_info *di = file->private_data;
+ struct dbg_internal *d = &di->internal;
+ char buf[10];
+
+ snprintf(buf, sizeof(buf), "%d\n", mutex_is_locked(&d->io_lock));
+ return simple_read_from_buffer(user_buf, cnt, loff, buf, strlen(buf));
+}
+
+static ssize_t lock_debug_write(struct file *file,
+ const char __user *user_buf,
+ size_t cnt, loff_t *loff)
+{
+ struct dbg_info *di = file->private_data;
+ struct dbg_internal *d = &di->internal;
+ u32 lock;
+ int ret;
+
+ ret = kstrtou32_from_user(user_buf, cnt, 0, &lock);
+ if (ret < 0)
+ return ret;
+ lock ? mutex_lock(&d->io_lock) : mutex_unlock(&d->io_lock);
+ return cnt;
+}
+
+static const struct file_operations lock_debug_fops = {
+ .open = simple_open,
+ .read = lock_debug_read,
+ .write = lock_debug_write,
+};
+
+static int generic_debugfs_init(struct dbg_info *di)
+{
+ struct dbg_internal *d = &di->internal;
+
+ /* valid check */
+ if (!di->dirname || !di->devname || !di->typestr)
+ return -EINVAL;
+ d->data_buffer_size = PREALLOC_RBUFFER_SIZE;
+ d->data_buffer = kzalloc(PREALLOC_RBUFFER_SIZE, GFP_KERNEL);
+ if (!d->data_buffer)
+ return -ENOMEM;
+ /* create debugfs */
+ d->rt_root = debugfs_lookup("ext_dev_io", NULL);
+ if (!d->rt_root) {
+ d->rt_root = debugfs_create_dir("ext_dev_io", NULL);
+ if (!d->rt_root)
+ return -ENODEV;
+ d->rt_dir_create = true;
+ }
+ d->ic_root = debugfs_create_dir(di->dirname, d->rt_root);
+ if (!d->ic_root)
+ goto err_cleanup_rt;
+ if (!debugfs_create_u16("reg", 0644, d->ic_root, &d->reg))
+ goto err_cleanup_ic;
+ if (!debugfs_create_u16("size", 0644, d->ic_root, &d->size))
+ goto err_cleanup_ic;
+ if (!debugfs_create_file("data", 0644,
+ d->ic_root, di, &data_debug_fops))
+ goto err_cleanup_ic;
+ if (!debugfs_create_file("type", 0444,
+ d->ic_root, di, &type_debug_fops))
+ goto err_cleanup_ic;
+ if (!debugfs_create_file("lock", 0644,
+ d->ic_root, di, &lock_debug_fops))
+ goto err_cleanup_ic;
+ if (!debugfs_create_file("dumps", 0444,
+ d->ic_root, di, &dump_debug_fops))
+ goto err_cleanup_ic;
+ mutex_init(&d->io_lock);
+ return 0;
+err_cleanup_ic:
+ debugfs_remove_recursive(d->ic_root);
+err_cleanup_rt:
+ if (d->rt_dir_create)
+ debugfs_remove_recursive(d->rt_root);
+ kfree(d->data_buffer);
+ return -ENODEV;
+}
+
+static void generic_debugfs_exit(struct dbg_info *di)
+{
+ struct dbg_internal *d = &di->internal;
+
+ mutex_destroy(&d->io_lock);
+ debugfs_remove_recursive(d->ic_root);
+ if (d->rt_dir_create)
+ debugfs_remove_recursive(d->rt_root);
+ kfree(d->data_buffer);
+}
+#else
+static inline int generic_debugfs_init(struct dbg_info *di)
+{
+ return 0;
+}
+
+static inline void generic_debugfs_exit(struct dbg_info *di) {}
+#endif /* CONFIG_DEBUG_FS */
+#endif /* GENERIC_DEBUGFS */
+
+/*
+ * MT6660 Generic Setting make this chip work normally.
+ * it is tuned by Richtek RDs.
+ */
+static const struct codec_reg_val generic_reg_inits[] = {
+ { MT6660_REG_WDT_CTRL, 0x80, 0x00 },
+ { MT6660_REG_SPS_CTRL, 0x01, 0x00 },
+ { MT6660_REG_AUDIO_IN2_SEL, 0x1c, 0x04 },
+ { MT6660_REG_RESV11, 0x0c, 0x00 },
+ { MT6660_REG_RESV31, 0x03, 0x03 },
+ { MT6660_REG_RESV40, 0x01, 0x00 },
+ { MT6660_REG_RESV0, 0x44, 0x04 },
+ { MT6660_REG_RESV19, 0xff, 0x82 },
+ { MT6660_REG_RESV17, 0x7777, 0x7273 },
+ { MT6660_REG_RESV16, 0x07, 0x03 },
+ { MT6660_REG_DRE_CORASE, 0xe0, 0x20 },
+ { MT6660_REG_ADDA_CLOCK, 0xff, 0x70 },
+ { MT6660_REG_RESV21, 0xff, 0x20 },
+ { MT6660_REG_DRE_THDMODE, 0xff, 0x40 },
+ { MT6660_REG_RESV23, 0xffff, 0x17f8 },
+ { MT6660_REG_PWM_CTRL, 0xff, 0x15 },
+ { MT6660_REG_ADC_USB_MODE, 0xff, 0x00 },
+ { MT6660_REG_PROTECTION_CFG, 0xff, 0x1d },
+ { MT6660_REG_HPF1_COEF, 0xffffffff, 0x7fdb7ffe },
+ { MT6660_REG_HPF2_COEF, 0xffffffff, 0x7fdb7ffe },
+ { MT6660_REG_SIG_GAIN, 0xff, 0x58 },
+ { MT6660_REG_RESV6, 0xff, 0xce },
+ { MT6660_REG_SIGMAX, 0xffff, 0x7fff },
+ { MT6660_REG_DA_GAIN, 0xffff, 0x0116 },
+ { MT6660_REG_TDM_CFG3, 0x1800, 0x0800 },
+ { MT6660_REG_DRE_CTRL, 0x1f, 0x07 },
+};
+
+static int mt6660_component_init_setting(struct snd_soc_component *component)
+{
+ int i, len, ret;
+ const struct codec_reg_val *init_table;
+
+ pr_info("%s start\n", __func__);
+ init_table = generic_reg_inits;
+ len = ARRAY_SIZE(generic_reg_inits);
+
+ for (i = 0; i < len; i++) {
+ pr_err("fuck 1\n");
+ ret = snd_soc_component_update_bits(component,
+ init_table[i].addr,
+ init_table[i].mask, init_table[i].data);
+ pr_err("fuck 2\n");
+ if (ret < 0)
+ return ret;
+ }
+ pr_info("%s end\n", __func__);
+ return 0;
+}
+
+static int mt6660_component_set_bias_level(struct snd_soc_component *component,
+ enum snd_soc_bias_level level)
+{
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_component_get_dapm(component);
+ struct mt6660_chip *chip = snd_soc_component_get_drvdata(component);
+ unsigned int val;
+ int ret = 0;
+
+ switch (level) {
+ case SND_SOC_BIAS_OFF:
+ ret = regmap_read(chip->regmap, MT6660_REG_IRQ_STATUS1, &val);
+ dev_info(component->dev,
+ "%s reg0x05 = 0x%x\n", __func__, val);
+ break;
+ case SND_SOC_BIAS_ON:
+ case SND_SOC_BIAS_PREPARE:
+ /* Fall Through */
+ case SND_SOC_BIAS_STANDBY:
+ default:
+ break;
+ }
+ dapm->bias_level = level;
+ dev_dbg(component->dev, "c bias_level = %d\n", level);
+ return 0;
+}
+
+static int mt6660_codec_dac_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ usleep_range(1000, 1100);
+ break;
+ }
+ return 0;
+}
+
+static int mt6660_codec_classd_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ int ret = 0;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ dev_dbg(component->dev,
+ "%s: before classd turn on\n", __func__);
+ /* config to adaptive mode */
+ ret = snd_soc_component_update_bits(component,
+ MT6660_REG_BST_CTRL, 0x03, 0x03);
+ if (ret < 0) {
+ dev_err(component->dev, "config mode adaptive fail\n");
+ return ret;
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ /* voltage sensing enable */
+ ret = snd_soc_component_update_bits(component,
+ MT6660_REG_RESV7, 0x04, 0x04);
+ if (ret < 0) {
+ dev_err(component->dev,
+ "enable voltage sensing fail\n");
+ return ret;
+ }
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ /* voltage sensing disable */
+ ret = snd_soc_component_update_bits(component,
+ MT6660_REG_RESV7, 0x04, 0x00);
+ if (ret < 0) {
+ dev_err(component->dev,
+ "disable voltage sensing fail\n");
+ return ret;
+ }
+ /* pop-noise improvement 1 */
+ ret = snd_soc_component_update_bits(component,
+ MT6660_REG_RESV10, 0x10, 0x10);
+ if (ret < 0) {
+ dev_err(component->dev,
+ "pop-noise improvement 1 fail\n");
+ return ret;
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ dev_dbg(component->dev,
+ "%s: after classd turn off\n", __func__);
+ /* pop-noise improvement 2 */
+ ret = snd_soc_component_update_bits(component,
+ MT6660_REG_RESV10, 0x10, 0x00);
+ if (ret < 0) {
+ dev_err(component->dev,
+ "pop-noise improvement 2 fail\n");
+ return ret;
+ }
+ /* config to off mode */
+ ret = snd_soc_component_update_bits(component,
+ MT6660_REG_BST_CTRL, 0x03, 0x00);
+ if (ret < 0) {
+ dev_err(component->dev, "config mode off fail\n");
+ return ret;
+ }
+ break;
+ }
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget mt6660_component_dapm_widgets[] = {
+ SND_SOC_DAPM_DAC_E("DAC", NULL, MT6660_REG_PLL_CFG1,
+ 0, 1, mt6660_codec_dac_event, SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_ADC("VI ADC", NULL, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_PGA("PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_OUT_DRV_E("ClassD", MT6660_REG_SYSTEM_CTRL, 2, 0,
+ NULL, 0, mt6660_codec_classd_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_OUTPUT("OUTP"),
+ SND_SOC_DAPM_OUTPUT("OUTN"),
+};
+
+static const struct snd_soc_dapm_route mt6660_component_dapm_routes[] = {
+ { "DAC", NULL, "aif_playback"},
+ { "PGA", NULL, "DAC"},
+ { "ClassD", NULL, "PGA"},
+ { "OUTP", NULL, "ClassD"},
+ { "OUTN", NULL, "ClassD"},
+ { "VI ADC", NULL, "ClassD"},
+ { "aif_capture", NULL, "VI ADC"},
+};
+
+static int mt6660_component_put_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ int put_ret = 0;
+
+ pm_runtime_get_sync(component->dev);
+ put_ret = snd_soc_put_volsw(kcontrol, ucontrol);
+ if (put_ret < 0)
+ return put_ret;
+ pm_runtime_put(component->dev);
+ return put_ret;
+}
+
+static int mt6660_component_get_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct mt6660_chip *chip = (struct mt6660_chip *)
+ snd_soc_component_get_drvdata(component);
+ int ret = -EINVAL;
+
+ if (!strcmp(kcontrol->id.name, "Chip_Rev")) {
+ ucontrol->value.integer.value[0] = chip->chip_rev & 0x0f;
+ ret = 0;
+ }
+ return ret;
+}
+
+static const DECLARE_TLV_DB_SCALE(vol_ctl_tlv, -1155, 5, 0);
+
+static const struct snd_kcontrol_new mt6660_component_snd_controls[] = {
+ SOC_SINGLE_EXT_TLV("Digital Volume", MT6660_REG_VOL_CTRL, 0, 255,
+ 1, snd_soc_get_volsw, mt6660_component_put_volsw,
+ vol_ctl_tlv),
+ SOC_SINGLE_EXT("WDT Switch", MT6660_REG_WDT_CTRL, 7, 1, 0,
+ snd_soc_get_volsw, mt6660_component_put_volsw),
+ SOC_SINGLE_EXT("Hard_Clip Switch", MT6660_REG_HCLIP_CTRL, 8, 1, 0,
+ snd_soc_get_volsw, mt6660_component_put_volsw),
+ SOC_SINGLE_EXT("Clip Switch", MT6660_REG_SPS_CTRL, 0, 1, 0,
+ snd_soc_get_volsw, mt6660_component_put_volsw),
+ SOC_SINGLE_EXT("BoostMode", MT6660_REG_BST_CTRL, 0, 3, 0,
+ snd_soc_get_volsw, mt6660_component_put_volsw),
+ SOC_SINGLE_EXT("DRE Switch", MT6660_REG_DRE_CTRL, 0, 1, 0,
+ snd_soc_get_volsw, mt6660_component_put_volsw),
+ SOC_SINGLE_EXT("DC_Protect Switch",
+ MT6660_REG_DC_PROTECT_CTRL, 3, 1, 0,
+ snd_soc_get_volsw, mt6660_component_put_volsw),
+ SOC_SINGLE_EXT("audio input selection", MT6660_REG_DATAO_SEL, 6, 3, 0,
+ snd_soc_get_volsw, mt6660_component_put_volsw),
+ SOC_SINGLE_EXT("Data Output Left Channel Selection",
+ MT6660_REG_DATAO_SEL, 3, 7, 0,
+ snd_soc_get_volsw, mt6660_component_put_volsw),
+ SOC_SINGLE_EXT("Data Output Right Channel Selection",
+ MT6660_REG_DATAO_SEL, 0, 7, 0,
+ snd_soc_get_volsw, mt6660_component_put_volsw),
+ /* for debug purpose */
+ SOC_SINGLE_EXT("HPF_AUD_IN Switch", MT6660_REG_HPF_CTRL, 0, 1, 0,
+ snd_soc_get_volsw, mt6660_component_put_volsw),
+ SOC_SINGLE_EXT("AUD_LOOP_BACK Switch", MT6660_REG_PATH_BYPASS, 4, 1, 0,
+ snd_soc_get_volsw, mt6660_component_put_volsw),
+ SOC_SINGLE_EXT("Mute Switch", MT6660_REG_SYSTEM_CTRL, 1, 1, 0,
+ snd_soc_get_volsw, mt6660_component_put_volsw),
+ SOC_SINGLE_EXT("Bypass CS Comp Switch", MT6660_REG_PATH_BYPASS, 2, 1, 0,
+ snd_soc_get_volsw, mt6660_component_put_volsw),
+ SOC_SINGLE_EXT("T0_SEL", MT6660_REG_CALI_T0, 0, 7, 0,
+ snd_soc_get_volsw, NULL),
+ SOC_SINGLE_EXT("Chip_Rev", SND_SOC_NOPM, 0, 16, 0,
+ mt6660_component_get_volsw, NULL),
+};
+
+static int mt6660_component_probe(struct snd_soc_component *component)
+{
+ struct mt6660_chip *chip = snd_soc_component_get_drvdata(component);
+ int ret = 0;
+
+ pr_info("%s\n", __func__);
+ //snd_soc_component_init_regmap(component, chip->regmap);
+
+ /* init chip setting */
+ ret = mt6660_component_init_setting(component);
+ if (ret < 0)
+ dev_err(chip->dev, "chip i2c init setting fail\n");
+
+ return ret;
+}
+
+static void mt6660_component_remove(struct snd_soc_component *component)
+{
+ pr_info("%s\n", __func__);
+ snd_soc_component_exit_regmap(component);
+}
+
+static const struct snd_soc_component_driver mt6660_component_driver = {
+ .probe = mt6660_component_probe,
+ .remove = mt6660_component_remove,
+ .read = mt6660_component_io_read,
+ .write = mt6660_component_io_write,
+
+ .controls = mt6660_component_snd_controls,
+ .num_controls = ARRAY_SIZE(mt6660_component_snd_controls),
+ .dapm_widgets = mt6660_component_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(mt6660_component_dapm_widgets),
+ .dapm_routes = mt6660_component_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(mt6660_component_dapm_routes),
+
+ .set_bias_level = mt6660_component_set_bias_level,
+ .idle_bias_on = false, /* idle_bias_off = true */
+};
+
+static int mt6660_component_aif_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *dai)
+{
+ int word_len = params_physical_width(hw_params);
+ int aud_bit = params_width(hw_params);
+ u16 reg_data = 0;
+ int ret = 0;
+
+ dev_dbg(dai->dev, "%s: ++\n", __func__);
+ dev_dbg(dai->dev, "format: 0x%08x\n", params_format(hw_params));
+ dev_dbg(dai->dev, "rate: 0x%08x\n", params_rate(hw_params));
+ dev_dbg(dai->dev, "word_len: %d, aud_bit: %d\n", word_len, aud_bit);
+ if (word_len > 32 || word_len < 16) {
+ dev_err(dai->dev, "not supported word length\n");
+ return -ENOTSUPP;
+ }
+ switch (aud_bit) {
+ case 16:
+ reg_data = 3;
+ break;
+ case 18:
+ reg_data = 2;
+ break;
+ case 20:
+ reg_data = 1;
+ break;
+ case 24:
+ case 32:
+ reg_data = 0;
+ break;
+ default:
+ return -ENOTSUPP;
+ }
+ ret = snd_soc_component_update_bits(dai->component,
+ MT6660_REG_SERIAL_CFG1, 0xc0, (reg_data << 6));
+ if (ret < 0) {
+ dev_err(dai->dev, "config aud bit fail\n");
+ return ret;
+ }
+ ret = snd_soc_component_update_bits(dai->component,
+ MT6660_REG_TDM_CFG3, 0x3f0, word_len << 4);
+ if (ret < 0) {
+ dev_err(dai->dev, "config word len fail\n");
+ return ret;
+ }
+ dev_dbg(dai->dev, "%s: --\n", __func__);
+ return 0;
+}
+
+static const struct snd_soc_dai_ops mt6660_component_aif_ops = {
+ .hw_params = mt6660_component_aif_hw_params,
+};
+
+#define STUB_RATES SNDRV_PCM_RATE_8000_192000
+#define STUB_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_U16_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_U24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE | \
+ SNDRV_PCM_FMTBIT_U32_LE)
+
+static struct snd_soc_dai_driver mt6660_codec_dai = {
+ .name = "mt6660-aif",
+ .playback = {
+ .stream_name = "aif_playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = STUB_RATES,
+ .formats = STUB_FORMATS,
+ },
+ .capture = {
+ .stream_name = "aif_capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = STUB_RATES,
+ .formats = STUB_FORMATS,
+ },
+ /* dai properties */
+ .symmetric_rates = 1,
+ .symmetric_channels = 1,
+ .symmetric_samplebits = 1,
+ /* dai operations */
+ .ops = &mt6660_component_aif_ops,
+};
+
+static inline int _mt6660_chip_id_check(struct mt6660_chip *chip)
+{
+ u8 id[2] = {0};
+ int ret = 0;
+
+ ret = i2c_smbus_read_i2c_block_data(chip->i2c, MT6660_REG_DEVID, 2, id);
+ if (ret < 0)
+ return ret;
+ ret = (id[0] << 8) + id[1];
+ ret &= 0x0ff0;
+ if (ret != 0x00e0 && ret != 0x01e0)
+ return -ENODEV;
+ return ret;
+}
+
+static inline int _mt6660_chip_sw_reset(struct mt6660_chip *chip)
+{
+ int ret;
+
+ /* turn on main pll first, then trigger reset */
+ ret = regmap_write(chip->regmap, 0x03, 0x00);
+ if (ret < 0)
+ return ret;
+ ret = regmap_write(chip->regmap, MT6660_REG_SYSTEM_CTRL, 0x80);
+ msleep(30);
+ return 0;
+}
+
+static inline int _mt6660_chip_power_on(struct mt6660_chip *chip, int on_off)
+{
+ u8 reg_data = 0;
+ int ret = 0;
+
+ ret = i2c_smbus_read_byte_data(chip->i2c, MT6660_REG_SYSTEM_CTRL);
+ if (ret < 0)
+ return ret;
+ reg_data = (u8)ret;
+ if (on_off)
+ reg_data &= (~0x01);
+ else
+ reg_data |= 0x01;
+ return regmap_write(chip->regmap, MT6660_REG_SYSTEM_CTRL, reg_data);
+}
+
+static inline int _mt6660_read_chip_revision(struct mt6660_chip *chip)
+{
+ u8 reg_data[2] = {0};
+ int ret = 0;
+
+ ret = i2c_smbus_read_i2c_block_data(
+ chip->i2c, MT6660_REG_DEVID, 2, reg_data);
+ if (ret < 0) {
+ dev_err(chip->dev, "get chip revision fail\n");
+ return ret;
+ }
+ chip->chip_rev = reg_data[1];
+ return 0;
+}
+
+static int mt6660_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct mt6660_chip *chip = NULL;
+ int ret = 0;
+
+ pr_info("%s start\n", __func__);
+ chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+ chip->i2c = client;
+ chip->dev = &client->dev;
+ mutex_init(&chip->io_lock);
+ i2c_set_clientdata(client, chip);
+
+ chip->regmap = devm_regmap_init(&client->dev,
+ NULL, chip, &mt6660_regmap_config);
+ if (IS_ERR(chip->regmap)) {
+ ret = PTR_ERR(chip->regmap);
+ dev_err(&client->dev, "failed to initialise regmap: %d\n", ret);
+ return ret;
+ }
+
+#if GENERIC_DEBUGFS
+ /* debugfs interface */
+ chip->dbg_info.dirname = devm_kasprintf(&client->dev,
+ GFP_KERNEL, "MT6660.%s",
+ dev_name(&client->dev));
+ chip->dbg_info.devname = dev_name(&client->dev);
+ chip->dbg_info.typestr = devm_kasprintf(&client->dev,
+ GFP_KERNEL, "I2C,MT6660");
+ chip->dbg_info.io_drvdata = chip;
+ chip->dbg_info.io_read = mt6660_dbg_io_read;
+ chip->dbg_info.io_write = mt6660_dbg_io_write;
+
+ ret = generic_debugfs_init(&chip->dbg_info);
+ if (ret < 0) {
+ dev_err(&client->dev, "generic dbg init fail\n");
+ return -EINVAL;
+ }
+#endif /* GENERIC_DEBUGFS */
+
+ /* chip reset first */
+ ret = _mt6660_chip_sw_reset(chip);
+ if (ret < 0) {
+ dev_err(chip->dev, "chip reset fail\n");
+ goto probe_fail;
+ }
+ /* chip power on */
+ ret = _mt6660_chip_power_on(chip, 1);
+ if (ret < 0) {
+ dev_err(chip->dev, "chip power on 2 fail\n");
+ goto probe_fail;
+ }
+ /* chip devid check */
+ ret = _mt6660_chip_id_check(chip);
+ if (ret < 0) {
+ dev_err(chip->dev, "chip id check fail\n");
+ goto probe_fail;
+ }
+ /* chip revision get */
+ ret = _mt6660_read_chip_revision(chip);
+ if (ret < 0) {
+ dev_err(chip->dev, "read chip revision fail\n");
+ goto probe_fail;
+ }
+ pm_runtime_set_active(chip->dev);
+ pm_runtime_enable(chip->dev);
+
+ ret = devm_snd_soc_register_component(chip->dev,
+ &mt6660_component_driver,
+ &mt6660_codec_dai, 1);
+ pr_info("%s end, ret = %d\n", __func__, ret);
+ return ret;
+probe_fail:
+ _mt6660_chip_power_on(chip, 0);
+ mutex_destroy(&chip->io_lock);
+ return ret;
+}
+
+static int mt6660_i2c_remove(struct i2c_client *client)
+{
+ struct mt6660_chip *chip = i2c_get_clientdata(client);
+
+ pm_runtime_disable(chip->dev);
+ pm_runtime_set_suspended(chip->dev);
+#if GENERIC_DEBUGFS
+ generic_debugfs_exit(&chip->dbg_info);
+#endif /* GENERIC_DEBUGFS */
+ mutex_destroy(&chip->io_lock);
+ return 0;
+}
+
+static int __maybe_unused mt6660_i2c_runtime_suspend(struct device *dev)
+{
+ struct mt6660_chip *chip = dev_get_drvdata(dev);
+
+ dev_dbg(dev, "enter low power mode\n");
+ return regmap_update_bits(chip->regmap,
+ MT6660_REG_SYSTEM_CTRL, 0x01, 0x01);
+}
+
+static int __maybe_unused mt6660_i2c_runtime_resume(struct device *dev)
+{
+ struct mt6660_chip *chip = dev_get_drvdata(dev);
+
+ dev_dbg(dev, "exit low power mode\n");
+ return regmap_update_bits(chip->regmap,
+ MT6660_REG_SYSTEM_CTRL, 0x01, 0x00);
+}
+
+static const struct dev_pm_ops mt6660_dev_pm_ops = {
+ SET_RUNTIME_PM_OPS(mt6660_i2c_runtime_suspend,
+ mt6660_i2c_runtime_resume, NULL)
+};
+
+static const struct of_device_id __maybe_unused mt6660_of_id[] = {
+ { .compatible = "mediatek,mt6660",},
+ {},
+};
+MODULE_DEVICE_TABLE(of, mt6660_of_id);
+
+static const struct i2c_device_id mt6660_i2c_id[] = {
+ {"mt6660", 0 },
+ {},
+};
+MODULE_DEVICE_TABLE(i2c, mt6660_i2c_id);
+
+static struct i2c_driver mt6660_i2c_driver = {
+ .driver = {
+ .name = "mt6660",
+ .of_match_table = of_match_ptr(mt6660_of_id),
+ .pm = &mt6660_dev_pm_ops,
+ },
+ .probe = mt6660_i2c_probe,
+ .remove = mt6660_i2c_remove,
+ .id_table = mt6660_i2c_id,
+};
+module_i2c_driver(mt6660_i2c_driver);
+
+MODULE_AUTHOR("Jeff Chang <jeff_chang(a)richtek.com>");
+MODULE_DESCRIPTION("MT6660 SPKAMP Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.0.7_G");
diff --git a/sound/soc/codecs/mt6660.h b/sound/soc/codecs/mt6660.h
new file mode 100644
index 0000000..9e62dcc
--- /dev/null
+++ b/sound/soc/codecs/mt6660.h
@@ -0,0 +1,95 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2019 MediaTek Inc.
+ */
+
+#ifndef __SND_SOC_MT6660_H
+#define __SND_SOC_MT6660_H
+
+#include <linux/mutex.h>
+#include <linux/regmap.h>
+
+#define GENERIC_DEBUGFS 0
+
+#if GENERIC_DEBUGFS
+struct dbg_internal {
+ struct dentry *rt_root;
+ struct dentry *ic_root;
+ bool rt_dir_create;
+ struct mutex io_lock;
+ u16 reg;
+ u16 size;
+ u16 data_buffer_size;
+ void *data_buffer;
+};
+
+struct dbg_info {
+ const char *dirname;
+ const char *devname;
+ const char *typestr;
+ void *io_drvdata;
+ int (*io_read)(void *drvdata, u16 reg, void *val, u16 size);
+ int (*io_write)(void *drvdata, u16 reg, const void *val, u16 size);
+ struct dbg_internal internal;
+};
+#endif /* GENERIC_DEBUGFS */
+
+struct mt6660_chip {
+ struct i2c_client *i2c;
+ struct device *dev;
+ struct platform_device *param_dev;
+ struct mutex io_lock;
+#if GENERIC_DEBUGFS
+ struct dbg_info dbg_info;
+#endif /* GENERIC_DEBUGFS */
+ struct regmap *regmap;
+ u16 chip_rev;
+};
+
+#define MT6660_REG_DEVID (0x00)
+#define MT6660_REG_SYSTEM_CTRL (0x03)
+#define MT6660_REG_IRQ_STATUS1 (0x05)
+#define MT6660_REG_ADDA_CLOCK (0x07)
+#define MT6660_REG_SERIAL_CFG1 (0x10)
+#define MT6660_REG_DATAO_SEL (0x12)
+#define MT6660_REG_TDM_CFG3 (0x15)
+#define MT6660_REG_HPF_CTRL (0x18)
+#define MT6660_REG_HPF1_COEF (0x1A)
+#define MT6660_REG_HPF2_COEF (0x1B)
+#define MT6660_REG_PATH_BYPASS (0x1E)
+#define MT6660_REG_WDT_CTRL (0x20)
+#define MT6660_REG_HCLIP_CTRL (0x24)
+#define MT6660_REG_VOL_CTRL (0x29)
+#define MT6660_REG_SPS_CTRL (0x30)
+#define MT6660_REG_SIGMAX (0x33)
+#define MT6660_REG_CALI_T0 (0x3F)
+#define MT6660_REG_BST_CTRL (0x40)
+#define MT6660_REG_PROTECTION_CFG (0x46)
+#define MT6660_REG_DA_GAIN (0x4c)
+#define MT6660_REG_AUDIO_IN2_SEL (0x50)
+#define MT6660_REG_SIG_GAIN (0x51)
+#define MT6660_REG_PLL_CFG1 (0x60)
+#define MT6660_REG_DRE_CTRL (0x68)
+#define MT6660_REG_DRE_THDMODE (0x69)
+#define MT6660_REG_DRE_CORASE (0x6B)
+#define MT6660_REG_PWM_CTRL (0x70)
+#define MT6660_REG_DC_PROTECT_CTRL (0x74)
+#define MT6660_REG_ADC_USB_MODE (0x7c)
+#define MT6660_REG_INTERNAL_CFG (0x88)
+#define MT6660_REG_RESV0 (0x98)
+#define MT6660_REG_RESV1 (0x99)
+#define MT6660_REG_RESV2 (0x9A)
+#define MT6660_REG_RESV3 (0x9B)
+#define MT6660_REG_RESV6 (0xA2)
+#define MT6660_REG_RESV7 (0xA3)
+#define MT6660_REG_RESV10 (0xB0)
+#define MT6660_REG_RESV11 (0xB1)
+#define MT6660_REG_RESV16 (0xB6)
+#define MT6660_REG_RESV17 (0xB7)
+#define MT6660_REG_RESV19 (0xB9)
+#define MT6660_REG_RESV21 (0xBB)
+#define MT6660_REG_RESV23 (0xBD)
+#define MT6660_REG_RESV31 (0xD3)
+#define MT6660_REG_RESV40 (0xE0)
+
+#endif /* __SND_SOC_MT6660_H */
--
2.7.4
1
0
Hi Mark
ASoC has codec_conf, and we are using original
dev_name, of_node for it to finding codec.
But, we already have snd_soc_dai_link_component method.
We can reuse it for codec_conf, too.
This patches are for it.
Kuninori Morimoto (15):
ASoC: soc-core: support snd_soc_dai_link_component for codec_conf
ASoC: fsl: imx-audmix: use snd_soc_dai_link_component for codec_conf
ASoC: intel: kbl_da7219_max98927: use snd_soc_dai_link_component for codec_conf
ASoC: intel: kbl_rt5663_max98927: use snd_soc_dai_link_component for codec_conf
ASoC: intel: kbl_rt5663_rt5514_max98927: use snd_soc_dai_link_component for codec_conf
ASoC: intel: skl_nau88l25_ssm4567: use snd_soc_dai_link_component for codec_conf
ASoC: mediatek: mt8173-rt5650-rt5514: use snd_soc_dai_link_component for codec_conf
ASoC: mediatek: mt8173-rt5650-rt5676: use snd_soc_dai_link_component for codec_conf
ASoC: mediatek: mt8183-da7219-max98357: use snd_soc_dai_link_component for codec_conf
ASoC: samsung: bells: use snd_soc_dai_link_component for codec_conf
ASoC: samsung: lowland: use snd_soc_dai_link_component for codec_conf
ASoC: samsung: neo1973_wm8753: use snd_soc_dai_link_component for codec_conf
ASoC: samsung: speyside: use snd_soc_dai_link_component for codec_conf
ASoC: ti: rx51: use snd_soc_dai_link_component for codec_conf
ASoC: soc-core: remove legacy style of codec_conf
include/sound/soc.h | 4 ++--
sound/soc/fsl/imx-audmix.c | 2 +-
sound/soc/intel/boards/kbl_da7219_max98927.c | 8 ++++----
sound/soc/intel/boards/kbl_rt5663_max98927.c | 4 ++--
sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c | 4 ++--
sound/soc/intel/boards/skl_nau88l25_ssm4567.c | 4 ++--
sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c | 2 +-
sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c | 2 +-
sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c | 2 +-
sound/soc/samsung/bells.c | 2 +-
sound/soc/samsung/lowland.c | 2 +-
sound/soc/samsung/neo1973_wm8753.c | 2 +-
sound/soc/samsung/speyside.c | 2 +-
sound/soc/soc-core.c | 12 +++++-------
sound/soc/ti/rx51.c | 12 ++++++------
15 files changed, 31 insertions(+), 33 deletions(-)
--
2.7.4
2
17
[alsa-devel] [PATCH v3 00/15] Move PMC clocks into Tegra PMC driver
by Sowjanya Komatineni 12 Dec '19
by Sowjanya Komatineni 12 Dec '19
12 Dec '19
Tegra PMC has clk_out_1, clk_out_2, clk_out_3 and blink controls which
are currently registered by Tegra clock driver using clk_regiser_mux and
clk_register_gate which performs direct Tegra PMC register access.
When Tegra PMC is in secure mode, any access from non-secure world will
not go through.
This patch series adds these Tegra PMC clocks and blink controls to Tegra
PMC driver with PMC as clock provider and removed them from Tegra clock
driver. This also adds PMC specific clock id's to use in device tree and
removed clock ids of PMC clock from Tegra clock driver.
clk_out_1 is dedicated for audio mclk and current ASoC driver does not
setting extern1 as parent for clk_out_1 and enabling clk_out_1 and
currently this is taken care by Tegra clock driver during clock inits
and there is no need to enable this during clock init.
So, this series also includes patch that updates ASoC driver to take
care of configuring parent of mclk and enabling mclk using both extern1
and clk_out_1 and updates all device trees to use clk_out_1 from pmc as
mclk incase if device tree don't specify assigned-clock-parents.
This series also includes a patch for mclk fallback to use extern1
when retrieving mclk fails with new device tree which uses pmc provider
to have this backward compatible of new DT with old kernels.
This series also includes a patch to remove clock ids for these clocks
from clock dt-binding as these clocks are not used in any of the existing
device tree except in tegra210-smaug.dts and this series includes a patch
to update clock provider from tegra_car to pmc in tegra210-smaug.dts for
clk_out_2.
[v3]: Changes between v2 and v3 are
- Removes set parent of clk_out_1_mux to extern1 and enabling
extern1 from the clock driver.
- Doesn't enable clk_out_1 and blink by default in pmc driver
- Updates ASoC driver to take care of audio mclk parent
configuration incase if device tree don't specify assigned
clock parent properties and enables mclk using both clk_out_1
and extern1.
- updates all device trees using extern1 as mclk in sound node
to use clk_out_1 from pmc.
- patch for YAML format pmc dt-binding
- Includes v2 feedback
[v2]: Changes between v1 and v2 are
- v2 includes patches for adding clk_out_1, clk_out_2, clk_out_3,
blink controls to Tegra PMC driver and removing clk-tegra-pmc.
- feedback related to pmc clocks in Tegra PMC driver from v1
- Removed patches for WB0 PLLM overrides and PLLE IDDQ PMC programming
by the clock driver using helper functions from Tegra PMC.
Note:
To use helper functions from PMC driver, PMC early init need to
happen prior to using helper functions and these helper functions are
for PLLM Override and PLLE IDDQ programming in PMC during PLLM/PLLE
clock registration which happen in clock_init prior to Tegra PMC
probe.
Moving PLLM/PLLE clocks registration to happen after Tegra PMC
impacts other clocks EMC, MC and corresponding tegra_emc_init and
tegra_mc_init.
This implementation of configuring PMC registers thru helper
functions in clock driver needs proper changes across PMC, Clock,
EMC and MC inits to have it work across all Tegra platforms.
Currently PLLM Override is not enabled in the bootloader so proper
patches for this fix will be taken care separately.
[v1]: v1 includes patches for below fixes.
- adding clk_out_1, clk_out_2, clk_out_3, blink controls to Tegra PMC
driver and removing clk-tegra-pmc.
- updated clock provider from tegra_car to pmc in the device tree
tegra210-smaug.dts that uses clk_out_2.
- Added helper functions in PMC driver for WB0 PLLM overrides and PLLE
IDDQ programming to use by clock driver and updated clock driver to
use these helper functions and removed direct PMC access from clock
driver and all pmc base address references in clock driver.
Sowjanya Komatineni (15):
dt-bindings: soc: tegra-pmc: Add Tegra PMC clock bindings
dt-bindings: tegra: Convert Tegra PMC bindings to YAML
soc: tegra: Add Tegra PMC clock registrations into PMC driver
dt-bindings: soc: tegra-pmc: Add id for Tegra PMC blink control
soc: pmc: Add blink output clock registration to Tegra PMC
clk: tegra: Remove tegra_pmc_clk_init along with clk ids
dt-bindings: clock: tegra: Remove pmc clock ids from clock dt-bindings
ASoC: tegra: Add audio mclk control through clk_out_1 and extern1
ASoC: tegra: Add fallback for audio mclk
clk: tegra: Remove extern1 and cdev1 from clocks inittable
ARM: dts: tegra: Add clock-cells property to pmc
arm64: tegra: Add clock-cells property to Tegra PMC node
ARM: tegra: Update sound node clocks in device tree
arm64: tegra: smaug: Change clk_out_2 provider to pmc
ASoC: nau8825: change Tegra clk_out_2 provider from tegra_car to pmc
.../bindings/arm/tegra/nvidia,tegra20-pmc.txt | 45 ++-
.../bindings/arm/tegra/nvidia,tegra20-pmc.yaml | 291 ++++++++++++++++++
.../devicetree/bindings/sound/nau8825.txt | 2 +-
arch/arm/boot/dts/tegra114-dalmore.dts | 7 +-
arch/arm/boot/dts/tegra114.dtsi | 4 +-
arch/arm/boot/dts/tegra124-apalis-v1.2.dtsi | 7 +-
arch/arm/boot/dts/tegra124-apalis.dtsi | 7 +-
arch/arm/boot/dts/tegra124-jetson-tk1.dts | 7 +-
arch/arm/boot/dts/tegra124-nyan.dtsi | 7 +-
arch/arm/boot/dts/tegra124-venice2.dts | 7 +-
arch/arm/boot/dts/tegra124.dtsi | 4 +-
arch/arm/boot/dts/tegra20.dtsi | 4 +-
arch/arm/boot/dts/tegra30-apalis-v1.1.dtsi | 7 +-
arch/arm/boot/dts/tegra30-apalis.dtsi | 7 +-
arch/arm/boot/dts/tegra30-beaver.dts | 7 +-
arch/arm/boot/dts/tegra30-cardhu.dtsi | 7 +-
arch/arm/boot/dts/tegra30-colibri.dtsi | 7 +-
arch/arm/boot/dts/tegra30.dtsi | 4 +-
arch/arm64/boot/dts/nvidia/tegra132.dtsi | 4 +-
arch/arm64/boot/dts/nvidia/tegra210-smaug.dts | 2 +-
arch/arm64/boot/dts/nvidia/tegra210.dtsi | 2 +
drivers/clk/tegra/Makefile | 1 -
drivers/clk/tegra/clk-id.h | 7 -
drivers/clk/tegra/clk-tegra-pmc.c | 122 --------
drivers/clk/tegra/clk-tegra114.c | 12 -
drivers/clk/tegra/clk-tegra124.c | 28 +-
drivers/clk/tegra/clk-tegra20.c | 5 -
drivers/clk/tegra/clk-tegra210.c | 12 -
drivers/clk/tegra/clk-tegra30.c | 13 -
drivers/clk/tegra/clk.h | 1 -
drivers/soc/tegra/pmc.c | 340 +++++++++++++++++++++
include/dt-bindings/clock/tegra114-car.h | 14 +-
include/dt-bindings/clock/tegra124-car-common.h | 14 +-
include/dt-bindings/clock/tegra20-car.h | 2 +-
include/dt-bindings/clock/tegra210-car.h | 14 +-
include/dt-bindings/clock/tegra30-car.h | 14 +-
include/dt-bindings/soc/tegra-pmc.h | 19 ++
sound/soc/tegra/tegra_asoc_utils.c | 76 ++++-
sound/soc/tegra/tegra_asoc_utils.h | 1 +
39 files changed, 890 insertions(+), 244 deletions(-)
create mode 100644 Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.yaml
delete mode 100644 drivers/clk/tegra/clk-tegra-pmc.c
create mode 100644 include/dt-bindings/soc/tegra-pmc.h
--
2.7.4
5
29
Re: [alsa-devel] [PATCH v3 03/15] soc: tegra: Add Tegra PMC clock registrations into PMC driver
by Dmitry Osipenko 12 Dec '19
by Dmitry Osipenko 12 Dec '19
12 Dec '19
11.12.2019 21:50, Sowjanya Komatineni пишет:
>
> On 12/10/19 5:06 PM, Sowjanya Komatineni wrote:
>>
>> On 12/10/19 9:41 AM, Dmitry Osipenko wrote:
>>> 10.12.2019 19:53, Sowjanya Komatineni пишет:
>>>> On 12/9/19 3:03 PM, Sowjanya Komatineni wrote:
>>>>> On 12/9/19 12:46 PM, Sowjanya Komatineni wrote:
>>>>>> On 12/9/19 12:12 PM, Dmitry Osipenko wrote:
>>>>>>> 08.12.2019 00:36, Sowjanya Komatineni пишет:
>>>>>>>> On 12/7/19 11:59 AM, Sowjanya Komatineni wrote:
>>>>>>>>> On 12/7/19 8:00 AM, Dmitry Osipenko wrote:
>>>>>>>>>> 07.12.2019 18:53, Dmitry Osipenko пишет:
>>>>>>>>>>> 07.12.2019 18:47, Dmitry Osipenko пишет:
>>>>>>>>>>>> 07.12.2019 17:28, Dmitry Osipenko пишет:
>>>>>>>>>>>>> 06.12.2019 05:48, Sowjanya Komatineni пишет:
>>>>>>>>>>>>>> Tegra210 and prior Tegra PMC has clk_out_1, clk_out_2,
>>>>>>>>>>>>>> clk_out_3
>>>>>>>>>>>>>> with
>>>>>>>>>>>>>> mux and gate for each of these clocks.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Currently these PMC clocks are registered by Tegra clock
>>>>>>>>>>>>>> driver
>>>>>>>>>>>>>> using
>>>>>>>>>>>>>> clk_register_mux and clk_register_gate by passing PMC base
>>>>>>>>>>>>>> address
>>>>>>>>>>>>>> and register offsets and PMC programming for these clocks
>>>>>>>>>>>>>> happens
>>>>>>>>>>>>>> through direct PMC access by the clock driver.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> With this, when PMC is in secure mode any direct PMC access
>>>>>>>>>>>>>> from the
>>>>>>>>>>>>>> non-secure world does not go through and these clocks will
>>>>>>>>>>>>>> not be
>>>>>>>>>>>>>> functional.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> This patch adds these clocks registration with PMC as a clock
>>>>>>>>>>>>>> provider
>>>>>>>>>>>>>> for these clocks. clk_ops callback implementations for these
>>>>>>>>>>>>>> clocks
>>>>>>>>>>>>>> uses tegra_pmc_readl and tegra_pmc_writel which supports PMC
>>>>>>>>>>>>>> programming
>>>>>>>>>>>>>> in secure mode and non-secure mode.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Signed-off-by: Sowjanya Komatineni <skomatineni(a)nvidia.com>
>>>>>>>>>>>>>> ---
>>>>>>>>>>>> [snip]
>>>>>>>>>>>>
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>> +static const struct clk_ops pmc_clk_gate_ops = {
>>>>>>>>>>>>>> + .is_enabled = pmc_clk_is_enabled,
>>>>>>>>>>>>>> + .enable = pmc_clk_enable,
>>>>>>>>>>>>>> + .disable = pmc_clk_disable,
>>>>>>>>>>>>>> +};
>>>>>>>>>>>>> What's the benefit of separating GATE from the MUX?
>>>>>>>>>>>>>
>>>>>>>>>>>>> I think it could be a single clock.
>>>>>>>>>>>> According to TRM:
>>>>>>>>>>>>
>>>>>>>>>>>> 1. GATE and MUX are separate entities.
>>>>>>>>>>>>
>>>>>>>>>>>> 2. GATE is the parent of MUX (see PMC's CLK_OUT paths diagram
>>>>>>>>>>>> in TRM).
>>>>>>>>>>>>
>>>>>>>>>>>> 3. PMC doesn't gate EXTPERIPH clock but could "force-enable"
>>>>>>>>>>>> it,
>>>>>>>>>>>> correct?
>>>>>>>> Was following existing clk-tegra-pmc as I am not sure of reason for
>>>>>>>> having these clocks registered as separate mux and gate clocks.
>>>>>>>>
>>>>>>>> Yes, PMC clocks can be registered as single clock and can use
>>>>>>>> clk_ops
>>>>>>>> for set/get parent and enable/disable.
>>>>>>>>
>>>>>>>> enable/disable of PMC clocks is for force-enable to force the
>>>>>>>> clock to
>>>>>>>> run regardless of ACCEPT_REQ or INVERT_REQ.
>>>>>>>>
>>>>>>>>>>> 4. clk_m_div2/4 are internal PMC OSC dividers and thus these
>>>>>>>>>>> clocks
>>>>>>>>>>> should belong to PMC.
>>>>>>>>>> Also, it should be "osc" and not "clk_m".
>>>>>>>>> I followed the same parents as it were in existing clk-tegra-pmc
>>>>>>>>> driver.
>>>>>>>>>
>>>>>>>>> Yeah they are wrong and they should be from osc and not clk_m.
>>>>>>>>>
>>>>>>>>> Will fix in next version.
>>>>>>>>>
>>>>> Reg clk_m_div2/3, they are dividers at OSC pad and not really internal
>>>>> to PMC block.
>>>>>
>>>>> current clock driver creates clk_m_div clocks which should actually be
>>>>> osc_div2/osc_div4 clocks with osc as parent.
>>>>>
>>>>> There are no clk_m_div2 and clk_m_div4 from clk_m
>>>>>
>>>>> Will fix this in next version.
>>>>>
>>>>>>> Could you please describe the full EXTPERIPH clock topology and
>>>>>>> how the
>>>>>>> pinmux configuration is related to it all?
>>>>>>>
>>>>>>> What is internal to the Tegra chip and what are the external
>>>>>>> outputs?
>>>>>>>
>>>>>>> Is it possible to bypass PMC on T30+ for the EXTPERIPH clocks?
>>>>>> PMC CLK1/2/3 possible sources are OSC_DIV1, OSC_DIV2, OSC_DIV4,
>>>>>> EXTPERIPH from CAR.
>>>>>>
>>>>>> OSC_DIV1/2/4 are with internal dividers at the OSC Pads
>>>>>>
>>>>>> EXTPERIPH is from CAR and it has reset and enable controls along with
>>>>>> clock source selections to choose one of the PLLA_OUT0, CLK_S,
>>>>>> PLLP_OUT0, CLK_M, PLLE_OUT0
>>>>>>
>>>>>> So, PMC CLK1/2/4 possible parents are OSC_DIV1, OSC_DIV2, OSC_DIV4,
>>>>>> EXTERN.
>>>>>>
>>>>>>
>>>>>> CLK1/2/3 also has Pinmux to route EXTPERIPH output on to these pins.
>>>>>>
>>>>>>
>>>>>> When EXTERN output clock is selected for these PMC clocks thru
>>>>>> CLKx_SRC_SEL, output clock is from driver by EXTPERIPH from CAR via
>>>>>> Pinmux logic or driven as per CLKx_SRC_SEL bypassing pinmux based on
>>>>>> CLKx_ACCEPT_REQ bit.
>>>>>>
>>>>>>
>>>>>> PMC Clock control register has bit CLKx_ACCEPT_REQ
>>>>>> When CLKx_ACCEPT_REQ = 0, output clock driver is from by EXTPERIPH
>>>>>> through the pinmux
>>>>>> When CLKx_ACCEPT_REQ = 1, output clock is based on CLKx_SRC_SEL bits
>>>>>> (OSC_DIV1/2/4 and EXTPERIPH clock bypassing the pinmux)
>>>>>>
>>>>>> FORCE_EN bit in PMC CLock control register forces the clock to run
>>>>>> regardless of this.
>>>> PMC clock gate is based on the state of CLKx_ACCEPT_REQ and FORCE_EN
>>>> like explained above.
>>>>
>>>> CLKx_ACCEPT_REQ is 0 default and FORCE_EN acts as gate to
>>>> enable/disable
>>>> EXTPERIPH clock output to PMC CLK_OUT_1/2/3.
>>> [and to enable OSC as well]
>>>
>>>> So I believe we need to register as MUX and Gate rather than as a
>>>> single
>>>> clock. Please confirm.
>>> 1. The force-enabling is applied to both OSC and EXTERN sources of
>>> PMC_CLK_OUT_x by PMC at once.
>>>
>>> 2. Both of PMC's force-enabling and OSC/EXTERN selection is internal
>>> to PMC.
>>>
>>> Should be better to define it as a single "pmc_clk_out_x". I don't see
>>> any good reasons for differentiating PMC's Gate from the MUX, it's a
>>> single hardware unit from a point of view of the rest of the system.
>>>
>>> Peter, do you have any objections?
>>
>> We added fallback option for audio mclk and also added check for
>> assigned-clock-parents dt property in audio driver and if its not then
>> we do parent init configuration in audio driver.
>>
>> Current clock driver creates 2 separate clocks clk_out_1_mux and
>> clk_out_1 for each pmc clock in clock driver and uses extern1 as
>> parent to clk_out_1_mux and clk_out_1_mux is parent to clk_out_1.
>>
>> With change of registering each pmc clock as a single clock, when we
>> do parent init assignment in audio driver when
>> assigned-clock-properties are not used in DT (as we removed parent
>> inits for extern and clk_outs from clock driver), we should still try
>> to get clock based on clk_out_1_mux as parent assignment of extern1 is
>> for clk_out_1_mux as per existing clock tree.
>>
>> clk_out_1_mux clock retrieve will fail with this change of single
>> clock when any new platform device tree doesn't specify
>> assigned-clock-parents properties and tegra_asoc_utils_init fails.
You made the PMC/CaR changes before the audio changes, the clk_out_1_mux
won't exist for the audio driver patches.
If you care about bisect-ability of the patches, then the clock and
audio changes need to be done in a single patch. But I don't think that
it's worthwhile.
>> With single clock, extern1 is the parent for clk_out_1 and with
>> separate clocks for mux and gate, extern1 is the parent for
>> clk_out_1_mux.
>
> If we move to single clock now, it need one more additional fallback
> implementation in audio driver during parent configuration as
> clk_out_1_mux will not be there with single clock change and old/current
> kernel has it as it uses separate clocks for pmc mux and gate.
Why additional fallback? Additional to what?
> Also, with single clock for both PMC mux and gate now, new DT should use
> extern1 as parent to CLK_OUT_1 as CLK_OUT_1_MUX will not be there old
> PMC dt-bindings has separate clocks for MUX (CLK_OUT_1_MUX) and gate
> (CLK_OUT_1)
>
> DT bindings will not be compatible b/w old and new changes if we move to
> Single PMC clock now.
Sorry, I don't understand what you're meaning by the "new changes".
> Should we go with same separate clocks to have it compatible to avoid
> all this?
>
1
0
11 Dec '19
Hi,
this is the second part of PCM API updates for ASoC.
This one just removes the superfluous PCM ioctl ops (and relevant
cleanups). Applicable on top of the previous patch set.
thanks,
Takashi
===
Takashi Iwai (23):
ASoC: amd: Drop superfluous ioctl PCM ops
ASoC: atmel: Drop superfluous ioctl PCM ops
ASoC: au1x: Drop superfluous ioctl PCM ops
ASoC: bcm: Drop superfluous ioctl PCM ops
ASoC: dwc: Drop superfluous ioctl PCM ops
ASoC: fsl: Drop superfluous ioctl PCM ops
ASoC: intel: Drop superfluous ioctl PCM ops
ASoC: kirkwood: Drop superfluous ioctl PCM ops
ASoC: mediatek: Drop superfluous ioctl PCM ops
ASoC: meson: Drop superfluous ioctl PCM ops
ASoC: pxa: Drop superfluous ioctl PCM ops
ASoC: qcom: Drop superfluous ioctl PCM ops
ASoC: samsung: Drop superfluous ioctl PCM ops
ASoC: sh: Drop superfluous ioctl PCM ops
ASoC: generic-dmaengine: Drop superfluous ioctl PCM ops
ASoC: SOF: Drop superfluous ioctl PCM ops
ASoC: sprd: Drop superfluous ioctl PCM ops
ASoC: txx9: Drop superfluous ioctl PCM ops
ASoC: uniphier: Drop superfluous ioctl PCM ops
ASoC: xilinx: Drop superfluous ioctl PCM ops
ASoC: xtensa: Drop superfluous ioctl PCM ops
ASoC: utils: Drop superfluous ioctl PCM ops
ASoC: Drop snd_soc_pcm_lib_ioctl()
include/sound/soc.h | 5 -----
sound/soc/amd/acp-pcm-dma.c | 1 -
sound/soc/amd/raven/acp3x-pcm-dma.c | 1 -
sound/soc/atmel/atmel-pcm-pdc.c | 1 -
sound/soc/au1x/dbdma2.c | 1 -
sound/soc/au1x/dma.c | 1 -
sound/soc/bcm/cygnus-pcm.c | 1 -
sound/soc/dwc/dwc-pcm.c | 1 -
sound/soc/fsl/fsl_asrc_dma.c | 1 -
sound/soc/fsl/fsl_dma.c | 1 -
sound/soc/fsl/imx-pcm-fiq.c | 1 -
sound/soc/fsl/mpc5200_dma.c | 1 -
sound/soc/intel/atom/sst-mfld-platform-pcm.c | 1 -
sound/soc/intel/baytrail/sst-baytrail-pcm.c | 1 -
sound/soc/intel/haswell/sst-haswell-pcm.c | 1 -
sound/soc/intel/skylake/skl-pcm.c | 1 -
sound/soc/kirkwood/kirkwood-dma.c | 1 -
sound/soc/mediatek/common/mtk-afe-platform-driver.c | 1 -
sound/soc/mediatek/common/mtk-btcvsd.c | 1 -
sound/soc/mediatek/mt6797/mt6797-afe-pcm.c | 1 -
sound/soc/mediatek/mt8183/mt8183-afe-pcm.c | 1 -
sound/soc/meson/axg-frddr.c | 3 ---
sound/soc/meson/axg-toddr.c | 3 ---
sound/soc/pxa/mmp-pcm.c | 1 -
sound/soc/pxa/pxa-ssp.c | 1 -
sound/soc/pxa/pxa2xx-ac97.c | 1 -
sound/soc/pxa/pxa2xx-i2s.c | 1 -
sound/soc/pxa/pxa2xx-pcm.c | 1 -
sound/soc/qcom/lpass-platform.c | 1 -
sound/soc/qcom/qdsp6/q6asm-dai.c | 1 -
sound/soc/samsung/idma.c | 1 -
sound/soc/sh/dma-sh7760.c | 1 -
sound/soc/sh/fsi.c | 1 -
sound/soc/sh/rcar/core.c | 1 -
sound/soc/sh/siu_pcm.c | 1 -
sound/soc/soc-core.c | 12 ------------
sound/soc/soc-generic-dmaengine-pcm.c | 2 --
sound/soc/soc-utils.c | 1 -
sound/soc/sof/pcm.c | 1 -
sound/soc/sprd/sprd-pcm-dma.c | 1 -
sound/soc/txx9/txx9aclc.c | 1 -
sound/soc/uniphier/aio-dma.c | 1 -
sound/soc/xilinx/xlnx_formatter_pcm.c | 1 -
sound/soc/xtensa/xtfpga-i2s.c | 1 -
44 files changed, 64 deletions(-)
--
2.16.4
7
58
11 Dec '19
Hi,
this is a patch set to adapt the recent PCM API updates to ASoC
drivers. This is the first half of the whole changes, just for
updating the buffer allocation code with the new API. There should be
no functional changes.
The ASoC core changes are already found in 5.5-rc1, so please merge
these onto 5.5-rc1 or later branch. Or I can merge through my tree,
too, just let me know.
thanks,
Takashi
===
Takashi Iwai (23):
ASoC: amd: Use managed buffer allocation
ASoC: au1x: Use managed buffer allocation
ASoC: dwc: Use managed buffer allocation
ASoC: mediatek: Use managed buffer allocation
ASoC: meson: Use managed buffer allocation
ASoC: dma-sh7760: Use managed buffer allocation
ASoC: fsi: Use managed buffer allocation
ASoC: rcar: Use managed buffer allocation
ASoC: siu_pcm: Use managed buffer allocation
ASoC: generic-dmaengine-pcm: Use managed buffer allocation
ASoC: SOF: Use managed buffer allocation
ASoC: stm32: Use managed buffer allocation
ASoC: txx9: Use managed buffer allocation
ASoC: uniphier: Use managed buffer allocation
ASoC: xilinx: Use managed buffer allocation
ASoC: xtensa: Use managed buffer allocation
ASoC: cros_ec_codec: Use managed buffer allocation
ASoC: rt5514-spi: Use managed buffer allocation
ASoC: rt5677-spi: Use managed buffer allocation
ASoC: intel: atom: Use managed buffer allocation
ASoC: intel: baytrail: Use managed buffer allocation
ASoC: intel: haswell: Use managed buffer allocation
ASoC: intel: skylake: Use managed buffer allocation
sound/soc/amd/acp-pcm-dma.c | 58 ++++++++--------------
sound/soc/amd/raven/acp3x-pcm-dma.c | 30 +++--------
sound/soc/au1x/dbdma2.c | 14 +-----
sound/soc/au1x/dma.c | 21 +++-----
sound/soc/codecs/cros_ec_codec.c | 8 +--
sound/soc/codecs/rt5514-spi.c | 10 ++--
sound/soc/codecs/rt5677-spi.c | 10 ++--
sound/soc/dwc/dwc-pcm.c | 24 +--------
sound/soc/intel/atom/sst-mfld-platform-pcm.c | 25 +---------
sound/soc/intel/baytrail/sst-baytrail-pcm.c | 19 +------
sound/soc/intel/haswell/sst-haswell-pcm.c | 17 +------
sound/soc/intel/skylake/skl-pcm.c | 26 +++-------
sound/soc/mediatek/common/mtk-afe-fe-dai.c | 14 +-----
sound/soc/mediatek/common/mtk-afe-fe-dai.h | 2 -
.../soc/mediatek/common/mtk-afe-platform-driver.c | 12 +----
.../soc/mediatek/common/mtk-afe-platform-driver.h | 2 -
sound/soc/mediatek/mt2701/mt2701-afe-pcm.c | 2 -
sound/soc/mediatek/mt6797/mt6797-afe-pcm.c | 1 -
sound/soc/mediatek/mt8183/mt8183-afe-pcm.c | 1 -
sound/soc/meson/axg-fifo.c | 13 ++---
sound/soc/sh/dma-sh7760.c | 14 +-----
sound/soc/sh/fsi.c | 18 +------
sound/soc/sh/rcar/core.c | 23 +++------
sound/soc/sh/siu_pcm.c | 39 +--------------
sound/soc/soc-generic-dmaengine-pcm.c | 12 +----
sound/soc/sof/pcm.c | 34 ++++---------
sound/soc/stm/stm32_adfsdm.c | 29 +----------
sound/soc/txx9/txx9aclc.c | 14 +-----
sound/soc/uniphier/aio-dma.c | 30 +----------
sound/soc/xilinx/xlnx_formatter_pcm.c | 13 +----
sound/soc/xtensa/xtfpga-i2s.c | 9 ++--
31 files changed, 93 insertions(+), 451 deletions(-)
--
2.16.4
3
47
[alsa-devel] [PATCH] ASoC: soc-core: merge soc_set_name_prefix() and soc_set_of_name_prefix()
by Kuninori Morimoto 11 Dec '19
by Kuninori Morimoto 11 Dec '19
11 Dec '19
From: Kuninori Morimoto <kuninori.morimoto.gx(a)renesas.com>
soc_set_name_prefix() is calling soc_set_of_name_prefix().
We don't need to separate these operation.
This patch merges these.
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx(a)renesas.com>
---
sound/soc/soc-core.c | 20 +++++++-------------
1 file changed, 7 insertions(+), 13 deletions(-)
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 750469a..f8090bd 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -1206,22 +1206,12 @@ static int soc_init_pcm_runtime(struct snd_soc_card *card,
return ret;
}
-static void soc_set_of_name_prefix(struct snd_soc_component *component)
-{
- struct device_node *of_node = soc_component_to_node(component);
- const char *str;
- int ret;
-
- ret = of_property_read_string(of_node, "sound-name-prefix", &str);
- if (!ret)
- component->name_prefix = str;
-}
-
static void soc_set_name_prefix(struct snd_soc_card *card,
struct snd_soc_component *component)
{
struct device_node *of_node = soc_component_to_node(component);
- int i;
+ const char *str;
+ int ret, i;
for (i = 0; i < card->num_configs; i++) {
struct snd_soc_codec_conf *map = &card->codec_conf[i];
@@ -1238,7 +1228,11 @@ static void soc_set_name_prefix(struct snd_soc_card *card,
* If there is no configuration table or no match in the table,
* check if a prefix is provided in the node
*/
- soc_set_of_name_prefix(component);
+ ret = of_property_read_string(of_node, "sound-name-prefix", &str);
+ if (ret < 0)
+ return;
+
+ component->name_prefix = str;
}
static void soc_remove_component(struct snd_soc_component *component,
--
2.7.4
2
1