[alsa-devel] [PATCH] ASoC: MT6660 update to 1.0.8_G
From: Jeff Chang jeff_chang@richtek.com
1. add parsing register initial table via device tree. 2. add applying initial register value function at component driver.
Signed-off-by: Jeff Chang jeff_chang@richtek.com --- Documentation/devicetree/bindings/sound/mt6660.txt | 53 ++++++++++ sound/soc/codecs/mt6660.c | 114 ++++++++++++++++++++- 2 files changed, 164 insertions(+), 3 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/mt6660.txt
Following Mr. Mark's Suggestion, I create another patch for applying our chip INIT SETTING.
diff --git a/Documentation/devicetree/bindings/sound/mt6660.txt b/Documentation/devicetree/bindings/sound/mt6660.txt new file mode 100644 index 0000000..2a1736b --- /dev/null +++ b/Documentation/devicetree/bindings/sound/mt6660.txt @@ -0,0 +1,53 @@ +MT6660 MediaTek Speaker Amplifier + +This device supports I2C mode only. + +Required properties: + + - compatible : "mediatek,mt6660" + + - reg : The I2C slave address + +Optional properties: + + - rt,init_setting_num : The initial register setting element number. + + - rt,init_setting_addr : the addreses array for INIT Setting table. + + - rt,init_setting_mask : the mask array for INIT Setting table. + + - rt,init_setting_val : the value array for INIT Setting table. + +Example: + + mt6660@34 { + status = "ok"; + compatible = "mediatek,mt6660"; + reg = <0x34>; + rt,init_setting_num = <26>; + rt,init_setting_addr = + <0x20 0x30 0x50 0xB1 + 0xD3 0xE0 0x98 0xB9 + 0xB7 0xB6 0x6B 0x07 + 0xBB 0x69 0xBD 0x70 + 0x7C 0x46 0x1A 0x1B + 0x51 0xA2 0x33 0x4C + 0x15 0x68>; + rt,init_setting_mask = + <0x80 0x01 0x1c 0x0c + 0x03 0x01 0x44 0xff + 0x7777 0x07 0xe0 0xff + 0xff 0xff 0xffff 0xff + 0xff 0xff 0xffffffff 0xffffffff + 0xff 0xff 0xffff 0xffff + 0x1800 0x1f>; + rt,init_setting_val = + <0x00 0x00 0x04 0x00 + 0x03 0x00 0x04 0x82 + 0x7273 0x03 0x20 0x70 + 0x20 0x40 0x17f8 0x15 + 0x00 0x1d 0x7fdb7ffe 0x7fdb7ffe + 0x58 0xce 0x7fff 0x0116 + 0x0800 0x07>; + }; + diff --git a/sound/soc/codecs/mt6660.c b/sound/soc/codecs/mt6660.c index a36c416..5df2780 100644 --- a/sound/soc/codecs/mt6660.c +++ b/sound/soc/codecs/mt6660.c @@ -9,7 +9,6 @@ #include <linux/i2c.h> #include <linux/pm_runtime.h> #include <linux/delay.h> -#include <linux/debugfs.h> #include <sound/soc.h> #include <sound/tlv.h> #include <sound/pcm_params.h> @@ -225,14 +224,48 @@ static int _mt6660_chip_power_on(struct mt6660_chip *chip, int on_off) 0x01, on_off ? 0x00 : 0x01); }
+static int mt6660_apply_plat_data(struct mt6660_chip *chip, + struct snd_soc_component *component) +{ + size_t i; + int num = chip->plat_data.init_setting_num; + int ret; + + ret = _mt6660_chip_power_on(chip, 1); + if (ret < 0) { + dev_err(chip->dev, "%s power on failed\n", __func__); + return ret; + } + + for (i = 0; i < num; i++) { + ret = snd_soc_component_update_bits(component, + chip->plat_data.init_setting_addr[i], + chip->plat_data.init_setting_mask[i], + chip->plat_data.init_setting_val[i]); + if (ret < 0) + return ret; + } + ret = _mt6660_chip_power_on(chip, 0); + if (ret < 0) { + dev_err(chip->dev, "%s power on failed\n", __func__); + return ret; + } + return 0; +} + static int mt6660_component_probe(struct snd_soc_component *component) { struct mt6660_chip *chip = snd_soc_component_get_drvdata(component); + int ret;
dev_dbg(component->dev, "%s\n", __func__); snd_soc_component_init_regmap(component, chip->regmap);
- return 0; + ret = mt6660_apply_plat_data(chip, component); + if (ret < 0) + dev_err(chip->dev, "mt6660 apply plat data failed\n"); + + return ret; }
static void mt6660_component_remove(struct snd_soc_component *component) @@ -386,6 +419,75 @@ static int _mt6660_read_chip_revision(struct mt6660_chip *chip) return 0; }
+static int mt6660_parse_dt(struct mt6660_chip *chip, struct device *dev) +{ + struct device_node *np = dev->of_node; + u32 val; + size_t i; + + if (!np) { + dev_err(dev, "no device node\n"); + return -EINVAL; + } + + if (of_property_read_u32(np, "rt,init_setting_num", &val)) { + dev_err(dev, "no init setting\n"); + chip->plat_data.init_setting_num = 0; + } else { + chip->plat_data.init_setting_num = val; + } + + if (chip->plat_data.init_setting_num) { + chip->plat_data.init_setting_addr = + devm_kzalloc(dev, sizeof(u32) * + chip->plat_data.init_setting_num, GFP_KERNEL); + if (!chip->plat_data.init_setting_addr) { + dev_err(dev, "%s addr memory alloc failed\n", __func__); + return -ENOMEM; + } + chip->plat_data.init_setting_mask = + devm_kzalloc(dev, sizeof(u32) * + chip->plat_data.init_setting_num, GFP_KERNEL); + if (!chip->plat_data.init_setting_mask) { + dev_err(dev, "%s mask memory alloc failed\n", __func__); + return -ENOMEM; + } + chip->plat_data.init_setting_val = + devm_kzalloc(dev, sizeof(u32) * + chip->plat_data.init_setting_num, GFP_KERNEL); + if (!chip->plat_data.init_setting_val) { + dev_err(dev, "%s val memory alloc failed\n", __func__); + return -ENOMEM; + } + + if (of_property_read_u32_array(np, "rt,init_setting_addr", + chip->plat_data.init_setting_addr, + chip->plat_data.init_setting_num)) { + dev_err(dev, "no init setting addr\n"); + } + if (of_property_read_u32_array(np, "rt,init_setting_mask", + chip->plat_data.init_setting_mask, + chip->plat_data.init_setting_num)) { + dev_err(dev, "no init setting mask\n"); + } + if (of_property_read_u32_array(np, "rt,init_setting_val", + chip->plat_data.init_setting_val, + chip->plat_data.init_setting_num)) { + dev_err(dev, "no init setting val\n"); + } + } + + dev_dbg(dev, "%s, init stting table, num = %d\n", __func__, + chip->plat_data.init_setting_num); + for (i = 0; i < chip->plat_data.init_setting_num; i++) { + dev_dbg(dev, "0x%02x, 0x%08x, 0x%08x\n", + chip->plat_data.init_setting_addr[i], + chip->plat_data.init_setting_mask[i], + chip->plat_data.init_setting_val[i]); + } + return 0; +} + static int mt6660_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -401,6 +503,12 @@ static int mt6660_i2c_probe(struct i2c_client *client, mutex_init(&chip->io_lock); i2c_set_clientdata(client, chip);
+ ret = mt6660_parse_dt(chip, &client->dev); + if (ret < 0) { + dev_err(&client->dev, "parsing dts failed\n"); + return ret; + } + chip->regmap = devm_regmap_init(&client->dev, NULL, chip, &mt6660_regmap_config); if (IS_ERR(chip->regmap)) { @@ -506,4 +614,4 @@ module_i2c_driver(mt6660_i2c_driver); MODULE_AUTHOR("Jeff Chang jeff_chang@richtek.com"); MODULE_DESCRIPTION("MT6660 SPKAMP Driver"); MODULE_LICENSE("GPL"); -MODULE_VERSION("1.0.7_G"); +MODULE_VERSION("1.0.8_G");
On Tue, Feb 04, 2020 at 11:41:37AM +0800, Jeff Chang wrote:
From: Jeff Chang jeff_chang@richtek.com
- add parsing register initial table via device tree.
- add applying initial register value function at component driver.
OK, so there's still a problem with the whole concept of putting "initial register settings" in the device tree - this is clearly not idiomatic for an ASoC driver. If there are machine specific settings that need to be done unconditionally (eg, values controlled by external passive components) there should be specific properties for them. If there are runtime options these should be normal ALSA controls with the default values being whatever the hardware defaults are. If there are things that should just always be set no matter what then they should just be hard coded into the driver.
participants (2)
-
Jeff Chang
-
Mark Brown