From fd587e320041d42eb21d12bb62da9e8ac08fd6c2 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 6 Oct 2014 23:14:23 +0800 Subject: ASoC: cs4265: Remove unused *dev field from struct cs4265_private Signed-off-by: Axel Lin Acked-by: Paul Handrigan Signed-off-by: Mark Brown --- sound/soc/codecs/cs4265.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/cs4265.c b/sound/soc/codecs/cs4265.c index 4fdd47d700e3..ce6086835ebd 100644 --- a/sound/soc/codecs/cs4265.c +++ b/sound/soc/codecs/cs4265.c @@ -32,7 +32,6 @@ #include "cs4265.h" struct cs4265_private { - struct device *dev; struct regmap *regmap; struct gpio_desc *reset_gpio; u8 format; @@ -598,7 +597,6 @@ static int cs4265_i2c_probe(struct i2c_client *i2c_client, GFP_KERNEL); if (cs4265 == NULL) return -ENOMEM; - cs4265->dev = &i2c_client->dev; cs4265->regmap = devm_regmap_init_i2c(i2c_client, &cs4265_regmap); if (IS_ERR(cs4265->regmap)) { -- cgit v1.2.3 From c973b8a7dc50ace86393f209b19aa7fd0bfaf66b Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 6 Oct 2014 23:09:47 +0800 Subject: ASoC: cs4271: Split SPI and I2C code into different modules Currently the cs4271 driver depends on SND_SOC_I2C_AND_SPI. So the driver cannot be built as built-in if CONFIG_I2C=m. Split SPI and I2C code into different modules to avoid this issue. Signed-off-by: Axel Lin Acked-by: Brian Austin Signed-off-by: Mark Brown --- sound/soc/cirrus/Kconfig | 3 +- sound/soc/codecs/Kconfig | 18 ++++- sound/soc/codecs/Makefile | 4 ++ sound/soc/codecs/cs4271-i2c.c | 62 +++++++++++++++++ sound/soc/codecs/cs4271-spi.c | 55 +++++++++++++++ sound/soc/codecs/cs4271.c | 155 +++++------------------------------------- sound/soc/codecs/cs4271.h | 11 +++ 7 files changed, 167 insertions(+), 141 deletions(-) create mode 100644 sound/soc/codecs/cs4271-i2c.c create mode 100644 sound/soc/codecs/cs4271-spi.c create mode 100644 sound/soc/codecs/cs4271.h (limited to 'sound/soc/codecs') diff --git a/sound/soc/cirrus/Kconfig b/sound/soc/cirrus/Kconfig index 5477c5475923..7b7fbcd49e5e 100644 --- a/sound/soc/cirrus/Kconfig +++ b/sound/soc/cirrus/Kconfig @@ -36,7 +36,8 @@ config SND_EP93XX_SOC_EDB93XX tristate "SoC Audio support for Cirrus Logic EDB93xx boards" depends on SND_EP93XX_SOC && (MACH_EDB9301 || MACH_EDB9302 || MACH_EDB9302A || MACH_EDB9307A || MACH_EDB9315A) select SND_EP93XX_SOC_I2S - select SND_SOC_CS4271 + select SND_SOC_CS4271_I2C if I2C + select SND_SOC_CS4271_SPI if SPI_MASTER help Say Y or M here if you want to add support for I2S audio on the Cirrus Logic EDB93xx boards. diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index a68d1731a8fd..765062551027 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -50,7 +50,8 @@ config SND_SOC_ALL_CODECS select SND_SOC_CS42L73 if I2C select SND_SOC_CS4265 if I2C select SND_SOC_CS4270 if I2C - select SND_SOC_CS4271 if SND_SOC_I2C_AND_SPI + select SND_SOC_CS4271_I2C if I2C + select SND_SOC_CS4271_SPI if SPI_MASTER select SND_SOC_CS42XX8_I2C if I2C select SND_SOC_CX20442 if TTY select SND_SOC_DA7210 if I2C @@ -370,8 +371,19 @@ config SND_SOC_CS4270_VD33_ERRATA depends on SND_SOC_CS4270 config SND_SOC_CS4271 - tristate "Cirrus Logic CS4271 CODEC" - depends on SND_SOC_I2C_AND_SPI + tristate + +config SND_SOC_CS4271_I2C + tristate "Cirrus Logic CS4271 CODEC (I2C)" + depends on I2C + select SND_SOC_CS4271 + select REGMAP_I2C + +config SND_SOC_CS4271_SPI + tristate "Cirrus Logic CS4271 CODEC (SPI)" + depends on SPI_MASTER + select SND_SOC_CS4271 + select REGMAP_SPI config SND_SOC_CS42XX8 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 5dce451661e4..ac7ec31f8cbe 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -41,6 +41,8 @@ snd-soc-cs42l73-objs := cs42l73.o snd-soc-cs4265-objs := cs4265.o snd-soc-cs4270-objs := cs4270.o snd-soc-cs4271-objs := cs4271.o +snd-soc-cs4271-i2c-objs := cs4271-i2c.o +snd-soc-cs4271-spi-objs := cs4271-spi.o snd-soc-cs42xx8-objs := cs42xx8.o snd-soc-cs42xx8-i2c-objs := cs42xx8-i2c.o snd-soc-cx20442-objs := cx20442.o @@ -217,6 +219,8 @@ obj-$(CONFIG_SND_SOC_CS42L73) += snd-soc-cs42l73.o obj-$(CONFIG_SND_SOC_CS4265) += snd-soc-cs4265.o obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o obj-$(CONFIG_SND_SOC_CS4271) += snd-soc-cs4271.o +obj-$(CONFIG_SND_SOC_CS4271_I2C) += snd-soc-cs4271-i2c.o +obj-$(CONFIG_SND_SOC_CS4271_SPI) += snd-soc-cs4271-spi.o obj-$(CONFIG_SND_SOC_CS42XX8) += snd-soc-cs42xx8.o obj-$(CONFIG_SND_SOC_CS42XX8_I2C) += snd-soc-cs42xx8-i2c.o obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o diff --git a/sound/soc/codecs/cs4271-i2c.c b/sound/soc/codecs/cs4271-i2c.c new file mode 100644 index 000000000000..b264da030340 --- /dev/null +++ b/sound/soc/codecs/cs4271-i2c.c @@ -0,0 +1,62 @@ +/* + * CS4271 I2C audio driver + * + * Copyright (c) 2010 Alexander Sverdlin + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include "cs4271.h" + +static int cs4271_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct regmap_config config; + + config = cs4271_regmap_config; + config.reg_bits = 8; + config.val_bits = 8; + + return cs4271_probe(&client->dev, + devm_regmap_init_i2c(client, &config)); +} + +static int cs4271_i2c_remove(struct i2c_client *client) +{ + snd_soc_unregister_codec(&client->dev); + return 0; +} + +static const struct i2c_device_id cs4271_i2c_id[] = { + { "cs4271", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, cs4271_i2c_id); + +static struct i2c_driver cs4271_i2c_driver = { + .driver = { + .name = "cs4271", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(cs4271_dt_ids), + }, + .probe = cs4271_i2c_probe, + .remove = cs4271_i2c_remove, + .id_table = cs4271_i2c_id, +}; +module_i2c_driver(cs4271_i2c_driver); + +MODULE_DESCRIPTION("ASoC CS4271 I2C Driver"); +MODULE_AUTHOR("Alexander Sverdlin "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs4271-spi.c b/sound/soc/codecs/cs4271-spi.c new file mode 100644 index 000000000000..acd49d86e706 --- /dev/null +++ b/sound/soc/codecs/cs4271-spi.c @@ -0,0 +1,55 @@ +/* + * CS4271 SPI audio driver + * + * Copyright (c) 2010 Alexander Sverdlin + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include "cs4271.h" + +static int cs4271_spi_probe(struct spi_device *spi) +{ + struct regmap_config config; + + config = cs4271_regmap_config; + config.reg_bits = 16; + config.val_bits = 8; + config.read_flag_mask = 0x21; + config.write_flag_mask = 0x20; + + return cs4271_probe(&spi->dev, devm_regmap_init_spi(spi, &config)); +} + +static int cs4271_spi_remove(struct spi_device *spi) +{ + snd_soc_unregister_codec(&spi->dev); + return 0; +} + +static struct spi_driver cs4271_spi_driver = { + .driver = { + .name = "cs4271", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(cs4271_dt_ids), + }, + .probe = cs4271_spi_probe, + .remove = cs4271_spi_remove, +}; +module_spi_driver(cs4271_spi_driver); + +MODULE_DESCRIPTION("ASoC CS4271 SPI Driver"); +MODULE_AUTHOR("Alexander Sverdlin "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c index 93cec52f4733..79a4efcb894c 100644 --- a/sound/soc/codecs/cs4271.c +++ b/sound/soc/codecs/cs4271.c @@ -23,8 +23,6 @@ #include #include #include -#include -#include #include #include #include @@ -32,6 +30,7 @@ #include #include #include +#include "cs4271.h" #define CS4271_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ SNDRV_PCM_FMTBIT_S24_LE | \ @@ -527,14 +526,15 @@ static int cs4271_soc_resume(struct snd_soc_codec *codec) #endif /* CONFIG_PM */ #ifdef CONFIG_OF -static const struct of_device_id cs4271_dt_ids[] = { +const struct of_device_id cs4271_dt_ids[] = { { .compatible = "cirrus,cs4271", }, { } }; MODULE_DEVICE_TABLE(of, cs4271_dt_ids); +EXPORT_SYMBOL_GPL(cs4271_dt_ids); #endif -static int cs4271_probe(struct snd_soc_codec *codec) +static int cs4271_codec_probe(struct snd_soc_codec *codec) { struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec); struct cs4271_platform_data *cs4271plat = codec->dev->platform_data; @@ -587,7 +587,7 @@ static int cs4271_probe(struct snd_soc_codec *codec) return 0; } -static int cs4271_remove(struct snd_soc_codec *codec) +static int cs4271_codec_remove(struct snd_soc_codec *codec) { struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec); @@ -599,8 +599,8 @@ static int cs4271_remove(struct snd_soc_codec *codec) }; static struct snd_soc_codec_driver soc_codec_dev_cs4271 = { - .probe = cs4271_probe, - .remove = cs4271_remove, + .probe = cs4271_codec_probe, + .remove = cs4271_codec_remove, .suspend = cs4271_soc_suspend, .resume = cs4271_soc_resume, @@ -642,14 +642,8 @@ static int cs4271_common_probe(struct device *dev, return 0; } -#if defined(CONFIG_SPI_MASTER) - -static const struct regmap_config cs4271_spi_regmap = { - .reg_bits = 16, - .val_bits = 8, +const struct regmap_config cs4271_regmap_config = { .max_register = CS4271_LASTREG, - .read_flag_mask = 0x21, - .write_flag_mask = 0x20, .reg_defaults = cs4271_reg_defaults, .num_reg_defaults = ARRAY_SIZE(cs4271_reg_defaults), @@ -657,140 +651,27 @@ static const struct regmap_config cs4271_spi_regmap = { .volatile_reg = cs4271_volatile_reg, }; +EXPORT_SYMBOL_GPL(cs4271_regmap_config); -static int cs4271_spi_probe(struct spi_device *spi) +int cs4271_probe(struct device *dev, struct regmap *regmap) { struct cs4271_private *cs4271; int ret; - ret = cs4271_common_probe(&spi->dev, &cs4271); - if (ret < 0) - return ret; - - spi_set_drvdata(spi, cs4271); - cs4271->regmap = devm_regmap_init_spi(spi, &cs4271_spi_regmap); - if (IS_ERR(cs4271->regmap)) - return PTR_ERR(cs4271->regmap); - - return snd_soc_register_codec(&spi->dev, &soc_codec_dev_cs4271, - &cs4271_dai, 1); -} - -static int cs4271_spi_remove(struct spi_device *spi) -{ - snd_soc_unregister_codec(&spi->dev); - return 0; -} - -static struct spi_driver cs4271_spi_driver = { - .driver = { - .name = "cs4271", - .owner = THIS_MODULE, - .of_match_table = of_match_ptr(cs4271_dt_ids), - }, - .probe = cs4271_spi_probe, - .remove = cs4271_spi_remove, -}; -#endif /* defined(CONFIG_SPI_MASTER) */ - -#if IS_ENABLED(CONFIG_I2C) -static const struct i2c_device_id cs4271_i2c_id[] = { - {"cs4271", 0}, - {} -}; -MODULE_DEVICE_TABLE(i2c, cs4271_i2c_id); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); -static const struct regmap_config cs4271_i2c_regmap = { - .reg_bits = 8, - .val_bits = 8, - .max_register = CS4271_LASTREG, - - .reg_defaults = cs4271_reg_defaults, - .num_reg_defaults = ARRAY_SIZE(cs4271_reg_defaults), - .cache_type = REGCACHE_RBTREE, - - .volatile_reg = cs4271_volatile_reg, -}; - -static int cs4271_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct cs4271_private *cs4271; - int ret; - - ret = cs4271_common_probe(&client->dev, &cs4271); + ret = cs4271_common_probe(dev, &cs4271); if (ret < 0) return ret; - i2c_set_clientdata(client, cs4271); - cs4271->regmap = devm_regmap_init_i2c(client, &cs4271_i2c_regmap); - if (IS_ERR(cs4271->regmap)) - return PTR_ERR(cs4271->regmap); + dev_set_drvdata(dev, cs4271); + cs4271->regmap = regmap; - return snd_soc_register_codec(&client->dev, &soc_codec_dev_cs4271, - &cs4271_dai, 1); -} - -static int cs4271_i2c_remove(struct i2c_client *client) -{ - snd_soc_unregister_codec(&client->dev); - return 0; -} - -static struct i2c_driver cs4271_i2c_driver = { - .driver = { - .name = "cs4271", - .owner = THIS_MODULE, - .of_match_table = of_match_ptr(cs4271_dt_ids), - }, - .id_table = cs4271_i2c_id, - .probe = cs4271_i2c_probe, - .remove = cs4271_i2c_remove, -}; -#endif /* IS_ENABLED(CONFIG_I2C) */ - -/* - * We only register our serial bus driver here without - * assignment to particular chip. So if any of the below - * fails, there is some problem with I2C or SPI subsystem. - * In most cases this module will be compiled with support - * of only one serial bus. - */ -static int __init cs4271_modinit(void) -{ - int ret; - -#if IS_ENABLED(CONFIG_I2C) - ret = i2c_add_driver(&cs4271_i2c_driver); - if (ret) { - pr_err("Failed to register CS4271 I2C driver: %d\n", ret); - return ret; - } -#endif - -#if defined(CONFIG_SPI_MASTER) - ret = spi_register_driver(&cs4271_spi_driver); - if (ret) { - pr_err("Failed to register CS4271 SPI driver: %d\n", ret); - return ret; - } -#endif - - return 0; -} -module_init(cs4271_modinit); - -static void __exit cs4271_modexit(void) -{ -#if defined(CONFIG_SPI_MASTER) - spi_unregister_driver(&cs4271_spi_driver); -#endif - -#if IS_ENABLED(CONFIG_I2C) - i2c_del_driver(&cs4271_i2c_driver); -#endif + return snd_soc_register_codec(dev, &soc_codec_dev_cs4271, &cs4271_dai, + 1); } -module_exit(cs4271_modexit); +EXPORT_SYMBOL_GPL(cs4271_probe); MODULE_AUTHOR("Alexander Sverdlin "); MODULE_DESCRIPTION("Cirrus Logic CS4271 ALSA SoC Codec Driver"); diff --git a/sound/soc/codecs/cs4271.h b/sound/soc/codecs/cs4271.h new file mode 100644 index 000000000000..9adad8eefdc9 --- /dev/null +++ b/sound/soc/codecs/cs4271.h @@ -0,0 +1,11 @@ +#ifndef _CS4271_PRIV_H +#define _CS4271_PRIV_H + +#include + +extern const struct of_device_id cs4271_dt_ids[]; +extern const struct regmap_config cs4271_regmap_config; + +int cs4271_probe(struct device *dev, struct regmap *regmap); + +#endif -- cgit v1.2.3 From 74d813cf37c210e94d155b0c19598fe269b8f78c Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Tue, 14 Oct 2014 20:29:26 +0300 Subject: ASoC: hdmi: Mark the maximum significant bits to HDMI codec HDMI audio can not have more than 24 bits even if on i2s bus there would be 32 bit samples. Mark this by adding .sig_bits = 24 to playback stream definition. Signed-off-by: Jyri Sarha Signed-off-by: Mark Brown --- sound/soc/codecs/hdmi.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/hdmi.c b/sound/soc/codecs/hdmi.c index 1087fd5f9917..2a52b9050371 100644 --- a/sound/soc/codecs/hdmi.c +++ b/sound/soc/codecs/hdmi.c @@ -47,6 +47,7 @@ static struct snd_soc_dai_driver hdmi_codec_dai = { SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, + .sig_bits = 24, }, .capture = { .stream_name = "Capture", -- cgit v1.2.3 From 69434097916bc52a4d6d495a0d719eb02e0cff9e Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Tue, 14 Oct 2014 20:29:27 +0300 Subject: ASoC: hdmi: HDMI codec doesn't benefit from pmdown delay Adds .ignore_pmdown_time = true to codec driver struct. HDMI codec is currently a dummy codec and doesn't benefit from pmdown delay. Even if in the future the codec would controll HDMI encoder, it would still be a digital to digital interface that should have no need for pmdown delay. Signed-off-by: Jyri Sarha Signed-off-by: Mark Brown --- sound/soc/codecs/hdmi.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/hdmi.c b/sound/soc/codecs/hdmi.c index 2a52b9050371..1391ad50f95d 100644 --- a/sound/soc/codecs/hdmi.c +++ b/sound/soc/codecs/hdmi.c @@ -76,6 +76,7 @@ static struct snd_soc_codec_driver hdmi_codec = { .num_dapm_widgets = ARRAY_SIZE(hdmi_widgets), .dapm_routes = hdmi_routes, .num_dapm_routes = ARRAY_SIZE(hdmi_routes), + .ignore_pmdown_time = true, }; static int hdmi_codec_probe(struct platform_device *pdev) -- cgit v1.2.3 From cd6e82b814ca73c474b1a2fa48a54b251da44655 Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Tue, 7 Oct 2014 10:25:37 +0800 Subject: ASoC: rt5645: Add the workqueue of the jack detect function for the debouncing Add the workqueue of the jack detect function for the debouncing. Signed-off-by: Oder Chiou Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 15 ++++++++++++++- sound/soc/codecs/rt5645.h | 1 + 2 files changed, 15 insertions(+), 1 deletion(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 3fb83bf09768..57ba74292259 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -2166,11 +2166,20 @@ int rt5645_set_jack_detect(struct snd_soc_codec *codec, } EXPORT_SYMBOL_GPL(rt5645_set_jack_detect); +static void rt5645_jack_detect_work(struct work_struct *work) +{ + struct rt5645_priv *rt5645 = + container_of(work, struct rt5645_priv, jack_detect_work.work); + + rt5645_jack_detect(rt5645->codec, rt5645->jack); +} + static irqreturn_t rt5645_irq(int irq, void *data) { struct rt5645_priv *rt5645 = data; - rt5645_jack_detect(rt5645->codec, rt5645->jack); + queue_delayed_work(system_power_efficient_wq, + &rt5645->jack_detect_work, msecs_to_jiffies(250)); return IRQ_HANDLED; } @@ -2436,6 +2445,8 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, dev_err(&i2c->dev, "Fail gpio_direction hp_det_gpio\n"); } + INIT_DELAYED_WORK(&rt5645->jack_detect_work, rt5645_jack_detect_work); + return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5645, rt5645_dai, ARRAY_SIZE(rt5645_dai)); } @@ -2447,6 +2458,8 @@ static int rt5645_i2c_remove(struct i2c_client *i2c) if (i2c->irq) free_irq(i2c->irq, rt5645); + cancel_delayed_work_sync(&rt5645->jack_detect_work); + if (gpio_is_valid(rt5645->pdata.hp_det_gpio)) gpio_free(rt5645->pdata.hp_det_gpio); diff --git a/sound/soc/codecs/rt5645.h b/sound/soc/codecs/rt5645.h index 50c62c5668ea..5ec2520614d2 100644 --- a/sound/soc/codecs/rt5645.h +++ b/sound/soc/codecs/rt5645.h @@ -2168,6 +2168,7 @@ struct rt5645_priv { struct regmap *regmap; struct i2c_client *i2c; struct snd_soc_jack *jack; + struct delayed_work jack_detect_work; int sysclk; int sysclk_src; -- cgit v1.2.3 From 80fff6bf65dcae62255bdb592603dfc247c8cacf Mon Sep 17 00:00:00 2001 From: Ben Zhang Date: Fri, 3 Oct 2014 14:37:24 -0700 Subject: ASoC: rt5677: Include gpio driver header The header file is needed because struct gpio_chip is placed in struct rt5677_priv. Signed-off-by: Ben Zhang Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677.h | 1 + 1 file changed, 1 insertion(+) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5677.h b/sound/soc/codecs/rt5677.h index d4eb6d5e6746..99fd023e3290 100644 --- a/sound/soc/codecs/rt5677.h +++ b/sound/soc/codecs/rt5677.h @@ -13,6 +13,7 @@ #define __RT5677_H__ #include +#include /* Info */ #define RT5677_RESET 0x00 -- cgit v1.2.3 From 40eb90a18e93fbd4fd0e6892b31241356c3c8e43 Mon Sep 17 00:00:00 2001 From: Anatol Pomozov Date: Fri, 10 Oct 2014 20:46:36 -0700 Subject: ASoC: rt5677: Add option to configure gpio as floating/pullup/pulldown gpio_config is array of 6 elements that allows to set GPIO as floating, pullup, pulldown. Sponsored: Google ChromeOS Signed-off-by: Anatol Pomozov Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/rt5677.txt | 7 ++++ include/sound/rt5677.h | 3 ++ sound/soc/codecs/rt5677.c | 39 ++++++++++++++++++++++ 3 files changed, 49 insertions(+) (limited to 'sound/soc/codecs') diff --git a/Documentation/devicetree/bindings/sound/rt5677.txt b/Documentation/devicetree/bindings/sound/rt5677.txt index 0701b834fc73..f82f0e906cd9 100644 --- a/Documentation/devicetree/bindings/sound/rt5677.txt +++ b/Documentation/devicetree/bindings/sound/rt5677.txt @@ -27,6 +27,12 @@ Optional properties: Boolean. Indicate MIC1/2 input and LOUT1/2/3 outputs are differential, rather than single-ended. +- realtek,gpio-config + Array of six 8bit elements that configures GPIO. + 0 - floating (reset value) + 1 - pull down + 2 - pull up + Pins on the device (for linking into audio routes): * IN1P @@ -56,4 +62,5 @@ rt5677 { realtek,pow-ldo2-gpio = <&gpio TEGRA_GPIO(V, 3) GPIO_ACTIVE_HIGH>; realtek,in1-differential = "true"; + realtek,gpio-config = /bits/ 8 <0 0 0 0 0 2>; /* pull up GPIO6 */ }; diff --git a/include/sound/rt5677.h b/include/sound/rt5677.h index 082670e3a353..a56b429a1dbc 100644 --- a/include/sound/rt5677.h +++ b/include/sound/rt5677.h @@ -27,6 +27,9 @@ struct rt5677_platform_data { bool lout3_diff; /* DMIC2 clock source selection */ enum rt5677_dmic2_clk dmic2_clk_pin; + + /* configures GPIO, 0 - floating, 1 - pulldown, 2 - pullup */ + u8 gpio_config[6]; }; #endif diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 16aa4d99a713..a454df39b7a5 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -3309,6 +3309,38 @@ static int rt5677_gpio_direction_in(struct gpio_chip *chip, unsigned offset) return 0; } +/** Configures the gpio as + * 0 - floating + * 1 - pull down + * 2 - pull up + */ +static void rt5677_gpio_config(struct rt5677_priv *rt5677, unsigned offset, + int value) +{ + int shift; + + switch (offset) { + case RT5677_GPIO1 ... RT5677_GPIO2: + shift = 2 * (1 - offset); + regmap_update_bits(rt5677->regmap, + RT5677_PR_BASE + RT5677_DIG_IN_PIN_ST_CTRL2, + 0x3 << shift, + (value & 0x3) << shift); + break; + + case RT5677_GPIO3 ... RT5677_GPIO6: + shift = 2 * (9 - offset); + regmap_update_bits(rt5677->regmap, + RT5677_PR_BASE + RT5677_DIG_IN_PIN_ST_CTRL3, + 0x3 << shift, + (value & 0x3) << shift); + break; + + default: + break; + } +} + static struct gpio_chip rt5677_template_chip = { .label = "rt5677", .owner = THIS_MODULE, @@ -3353,6 +3385,7 @@ static void rt5677_free_gpio(struct i2c_client *i2c) static int rt5677_probe(struct snd_soc_codec *codec) { struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); + int i; rt5677->codec = codec; @@ -3371,6 +3404,9 @@ static int rt5677_probe(struct snd_soc_codec *codec) regmap_write(rt5677->regmap, RT5677_DIG_MISC, 0x0020); regmap_write(rt5677->regmap, RT5677_PWR_DSP2, 0x0c00); + for (i = 0; i < RT5677_GPIO_NUM; i++) + rt5677_gpio_config(rt5677, i, rt5677->pdata.gpio_config[i]); + return 0; } @@ -3590,6 +3626,9 @@ static int rt5677_parse_dt(struct rt5677_priv *rt5677, struct device_node *np) (rt5677->pow_ldo2 != -ENOENT)) return rt5677->pow_ldo2; + of_property_read_u8_array(np, "realtek,gpio-config", + rt5677->pdata.gpio_config, RT5677_GPIO_NUM); + return 0; } -- cgit v1.2.3 From af48f1d08a5474184da9aaf8b77f4a2848b1875e Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Mon, 6 Oct 2014 16:30:51 +0800 Subject: ASoC: rt5677: Support DSP function for VAD application The ALC5677 has a programmable DSP, and there is a SPI that is dadicated for DSP firmware loading. Therefore, the patch includes a SPI driver for writing the DSP firmware. The VAD(Voice Activaty Detection) has be implemented and use the DSP to recognize the key phase. Signed-off-by: Oder Chiou Signed-off-by: Mark Brown --- sound/soc/codecs/Makefile | 2 +- sound/soc/codecs/rt5677-spi.c | 128 +++++++++++++++++++ sound/soc/codecs/rt5677-spi.h | 21 +++ sound/soc/codecs/rt5677.c | 288 +++++++++++++++++++++++++++++++++++++++++- sound/soc/codecs/rt5677.h | 6 + 5 files changed, 440 insertions(+), 5 deletions(-) create mode 100644 sound/soc/codecs/rt5677-spi.c create mode 100644 sound/soc/codecs/rt5677-spi.h (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 5dce451661e4..4435f9f18ce8 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -79,7 +79,7 @@ snd-soc-rt5640-objs := rt5640.o snd-soc-rt5645-objs := rt5645.o snd-soc-rt5651-objs := rt5651.o snd-soc-rt5670-objs := rt5670.o -snd-soc-rt5677-objs := rt5677.o +snd-soc-rt5677-objs := rt5677.o rt5677-spi.o snd-soc-sgtl5000-objs := sgtl5000.o snd-soc-alc5623-objs := alc5623.o snd-soc-alc5632-objs := alc5632.o diff --git a/sound/soc/codecs/rt5677-spi.c b/sound/soc/codecs/rt5677-spi.c new file mode 100644 index 000000000000..11c38f3a9b72 --- /dev/null +++ b/sound/soc/codecs/rt5677-spi.c @@ -0,0 +1,128 @@ +/* + * rt5677-spi.c -- RT5677 ALSA SoC audio codec driver + * + * Copyright 2013 Realtek Semiconductor Corp. + * Author: Oder Chiou + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rt5677-spi.h" + +static struct spi_device *g_spi; + +/** + * rt5677_spi_write - Write data to SPI. + * @txbuf: Data Buffer for writing. + * @len: Data length. + * + * + * Returns true for success. + */ +int rt5677_spi_write(u8 *txbuf, size_t len) +{ + int status; + + status = spi_write(g_spi, txbuf, len); + + if (status) + dev_err(&g_spi->dev, "rt5677_spi_write error %d\n", status); + + return status; +} + +/** + * rt5677_spi_burst_write - Write data to SPI by rt5677 dsp memory address. + * @addr: Start address. + * @txbuf: Data Buffer for writng. + * @len: Data length, it must be a multiple of 8. + * + * + * Returns true for success. + */ +int rt5677_spi_burst_write(u32 addr, const struct firmware *fw) +{ + u8 spi_cmd = RT5677_SPI_CMD_BURST_WRITE; + u8 *write_buf; + unsigned int i, end, offset = 0; + + write_buf = kmalloc(RT5677_SPI_BUF_LEN + 6, GFP_KERNEL); + + if (write_buf == NULL) + return -ENOMEM; + + while (offset < fw->size) { + if (offset + RT5677_SPI_BUF_LEN <= fw->size) + end = RT5677_SPI_BUF_LEN; + else + end = fw->size % RT5677_SPI_BUF_LEN; + + write_buf[0] = spi_cmd; + write_buf[1] = ((addr + offset) & 0xff000000) >> 24; + write_buf[2] = ((addr + offset) & 0x00ff0000) >> 16; + write_buf[3] = ((addr + offset) & 0x0000ff00) >> 8; + write_buf[4] = ((addr + offset) & 0x000000ff) >> 0; + + for (i = 0; i < end; i += 8) { + write_buf[i + 12] = fw->data[offset + i + 0]; + write_buf[i + 11] = fw->data[offset + i + 1]; + write_buf[i + 10] = fw->data[offset + i + 2]; + write_buf[i + 9] = fw->data[offset + i + 3]; + write_buf[i + 8] = fw->data[offset + i + 4]; + write_buf[i + 7] = fw->data[offset + i + 5]; + write_buf[i + 6] = fw->data[offset + i + 6]; + write_buf[i + 5] = fw->data[offset + i + 7]; + } + + write_buf[end + 5] = spi_cmd; + + rt5677_spi_write(write_buf, end + 6); + + offset += RT5677_SPI_BUF_LEN; + } + + kfree(write_buf); + + return 0; +} + +static int rt5677_spi_probe(struct spi_device *spi) +{ + g_spi = spi; + return 0; +} + +static struct spi_driver rt5677_spi_driver = { + .driver = { + .name = "rt5677", + .owner = THIS_MODULE, + }, + .probe = rt5677_spi_probe, +}; +module_spi_driver(rt5677_spi_driver); + +MODULE_DESCRIPTION("ASoC RT5677 SPI driver"); +MODULE_AUTHOR("Oder Chiou "); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/rt5677-spi.h b/sound/soc/codecs/rt5677-spi.h new file mode 100644 index 000000000000..7528bfd0b596 --- /dev/null +++ b/sound/soc/codecs/rt5677-spi.h @@ -0,0 +1,21 @@ +/* + * rt5677-spi.h -- RT5677 ALSA SoC audio codec driver + * + * Copyright 2013 Realtek Semiconductor Corp. + * Author: Oder Chiou + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __RT5671_SPI_H__ +#define __RT5671_SPI_H__ + +#define RT5677_SPI_BUF_LEN 240 +#define RT5677_SPI_CMD_BURST_WRITE 0x05 + +int rt5677_spi_write(u8 *txbuf, size_t len); +int rt5677_spi_burst_write(u32 addr, const struct firmware *fw); + +#endif /* __RT5677_SPI_H__ */ diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index a454df39b7a5..e6e54fa648aa 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -31,6 +32,7 @@ #include "rl6231.h" #include "rt5677.h" +#include "rt5677-spi.h" #define RT5677_DEVICE_ID 0x6327 @@ -537,6 +539,243 @@ static bool rt5677_readable_register(struct device *dev, unsigned int reg) } } +/** + * rt5677_dsp_mode_i2c_write_addr - Write value to address on DSP mode. + * @codec: SoC audio codec device. + * @addr: Address index. + * @value: Address data. + * + * + * Returns 0 for success or negative error code. + */ +static int rt5677_dsp_mode_i2c_write_addr(struct snd_soc_codec *codec, + unsigned int addr, unsigned int value, unsigned int opcode) +{ + struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); + int ret; + + mutex_lock(&rt5677->dsp_cmd_lock); + + ret = regmap_write(rt5677->regmap, RT5677_DSP_I2C_ADDR_MSB, addr >> 16); + if (ret < 0) { + dev_err(codec->dev, "Failed to set addr msb value: %d\n", ret); + goto err; + } + + ret = regmap_write(rt5677->regmap, RT5677_DSP_I2C_ADDR_LSB, + addr & 0xffff); + if (ret < 0) { + dev_err(codec->dev, "Failed to set addr lsb value: %d\n", ret); + goto err; + } + + ret = regmap_write(rt5677->regmap, RT5677_DSP_I2C_DATA_MSB, + value >> 16); + if (ret < 0) { + dev_err(codec->dev, "Failed to set data msb value: %d\n", ret); + goto err; + } + + ret = regmap_write(rt5677->regmap, RT5677_DSP_I2C_DATA_LSB, + value & 0xffff); + if (ret < 0) { + dev_err(codec->dev, "Failed to set data lsb value: %d\n", ret); + goto err; + } + + ret = regmap_write(rt5677->regmap, RT5677_DSP_I2C_OP_CODE, opcode); + if (ret < 0) { + dev_err(codec->dev, "Failed to set op code value: %d\n", ret); + goto err; + } + +err: + mutex_unlock(&rt5677->dsp_cmd_lock); + + return ret; +} + +/** + * rt5677_dsp_mode_i2c_read_addr - Read value from address on DSP mode. + * @codec: SoC audio codec device. + * @addr: Address index. + * @value: Address data. + * + * Returns 0 for success or negative error code. + */ +static int rt5677_dsp_mode_i2c_read_addr( + struct snd_soc_codec *codec, unsigned int addr, unsigned int *value) +{ + struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); + int ret; + unsigned int msb, lsb; + + mutex_lock(&rt5677->dsp_cmd_lock); + + ret = regmap_write(rt5677->regmap, RT5677_DSP_I2C_ADDR_MSB, addr >> 16); + if (ret < 0) { + dev_err(codec->dev, "Failed to set addr msb value: %d\n", ret); + goto err; + } + + ret = regmap_write(rt5677->regmap, RT5677_DSP_I2C_ADDR_LSB, + addr & 0xffff); + if (ret < 0) { + dev_err(codec->dev, "Failed to set addr lsb value: %d\n", ret); + goto err; + } + + ret = regmap_write(rt5677->regmap, RT5677_DSP_I2C_OP_CODE , 0x0002); + if (ret < 0) { + dev_err(codec->dev, "Failed to set op code value: %d\n", ret); + goto err; + } + + regmap_read(rt5677->regmap, RT5677_DSP_I2C_DATA_MSB, &msb); + regmap_read(rt5677->regmap, RT5677_DSP_I2C_DATA_LSB, &lsb); + *value = (msb << 16) | lsb; + +err: + mutex_unlock(&rt5677->dsp_cmd_lock); + + return ret; +} + +/** + * rt5677_dsp_mode_i2c_write - Write register on DSP mode. + * @codec: SoC audio codec device. + * @reg: Register index. + * @value: Register data. + * + * + * Returns 0 for success or negative error code. + */ +static int rt5677_dsp_mode_i2c_write(struct snd_soc_codec *codec, + unsigned int reg, unsigned int value) +{ + return rt5677_dsp_mode_i2c_write_addr(codec, 0x18020000 + reg * 2, + value, 0x0001); +} + +/** + * rt5677_dsp_mode_i2c_read - Read register on DSP mode. + * @codec: SoC audio codec device. + * @reg: Register index. + * + * + * Returns Register value. + */ +static unsigned int rt5677_dsp_mode_i2c_read( + struct snd_soc_codec *codec, unsigned int reg) +{ + unsigned int value = 0; + + rt5677_dsp_mode_i2c_read_addr(codec, 0x18020000 + reg * 2, &value); + + return value; +} + +/** + * rt5677_dsp_mode_i2c_update_bits - update register on DSP mode. + * @codec: audio codec + * @reg: register index. + * @mask: register mask + * @value: new value + * + * + * Returns 1 for change, 0 for no change, or negative error code. + */ +static int rt5677_dsp_mode_i2c_update_bits(struct snd_soc_codec *codec, + unsigned int reg, unsigned int mask, unsigned int value) +{ + unsigned int old, new; + int change, ret; + + ret = rt5677_dsp_mode_i2c_read(codec, reg); + if (ret < 0) { + dev_err(codec->dev, "Failed to read reg: %d\n", ret); + goto err; + } + + old = ret; + new = (old & ~mask) | (value & mask); + change = old != new; + if (change) { + ret = rt5677_dsp_mode_i2c_write(codec, reg, new); + if (ret < 0) { + dev_err(codec->dev, + "Failed to write reg: %d\n", ret); + goto err; + } + } + return change; + +err: + return ret; +} + +static int rt5677_set_dsp_vad(struct snd_soc_codec *codec, bool on) +{ + struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); + static bool activity; + int ret; + + if (on && !activity) { + activity = true; + + regcache_cache_only(rt5677->regmap, false); + regcache_cache_bypass(rt5677->regmap, true); + + regmap_update_bits(rt5677->regmap, RT5677_DIG_MISC, 0x1, 0x1); + regmap_update_bits(rt5677->regmap, + RT5677_PR_BASE + RT5677_BIAS_CUR4, 0x0f00, 0x0f00); + regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1, + RT5677_LDO1_SEL_MASK, 0x0); + regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG2, + RT5677_PWR_LDO1, RT5677_PWR_LDO1); + regmap_write(rt5677->regmap, RT5677_GLB_CLK2, 0x0080); + regmap_write(rt5677->regmap, RT5677_PWR_DSP2, 0x07ff); + regmap_write(rt5677->regmap, RT5677_PWR_DSP1, 0x07ff); + + ret = request_firmware(&rt5677->fw1, RT5677_FIRMWARE1, + codec->dev); + if (ret == 0) { + rt5677_spi_burst_write(0x50000000, rt5677->fw1); + release_firmware(rt5677->fw1); + } + + ret = request_firmware(&rt5677->fw2, RT5677_FIRMWARE2, + codec->dev); + if (ret == 0) { + rt5677_spi_burst_write(0x60000000, rt5677->fw2); + release_firmware(rt5677->fw2); + } + + rt5677_dsp_mode_i2c_update_bits(codec, RT5677_PWR_DSP1, 0x1, + 0x0); + + regcache_cache_bypass(rt5677->regmap, false); + regcache_cache_only(rt5677->regmap, true); + } else if (!on && activity) { + activity = false; + + regcache_cache_only(rt5677->regmap, false); + regcache_cache_bypass(rt5677->regmap, true); + + rt5677_dsp_mode_i2c_update_bits(codec, RT5677_PWR_DSP1, 0x1, + 0x1); + rt5677_dsp_mode_i2c_write(codec, RT5677_PWR_DSP1, 0x0001); + + regmap_write(rt5677->regmap, RT5677_RESET, 0x10ec); + + regcache_cache_bypass(rt5677->regmap, false); + regcache_mark_dirty(rt5677->regmap); + regcache_sync(rt5677->regmap); + } + + return 0; +} + static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0); static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0); static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0); @@ -556,6 +795,31 @@ static unsigned int bst_tlv[] = { 8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0), }; +static int rt5677_dsp_vad_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.integer.value[0] = rt5677->dsp_vad_en; + + return 0; +} + +static int rt5677_dsp_vad_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); + + rt5677->dsp_vad_en = !!ucontrol->value.integer.value[0]; + + if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) + rt5677_set_dsp_vad(codec, rt5677->dsp_vad_en); + + return 0; +} + static const struct snd_kcontrol_new rt5677_snd_controls[] = { /* OUTPUT Control */ SOC_SINGLE("OUT1 Playback Switch", RT5677_LOUT1, @@ -627,6 +891,9 @@ static const struct snd_kcontrol_new rt5677_snd_controls[] = { SOC_DOUBLE_TLV("Mono ADC Boost Volume", RT5677_ADC_BST_CTRL2, RT5677_MONO_ADC_L_BST_SFT, RT5677_MONO_ADC_R_BST_SFT, 3, 0, adc_bst_tlv), + + SOC_SINGLE_EXT("DSP VAD Switch", SND_SOC_NOPM, 0, 1, 0, + rt5677_dsp_vad_get, rt5677_dsp_vad_put), }; /** @@ -3181,6 +3448,8 @@ static int rt5677_set_bias_level(struct snd_soc_codec *codec, case SND_SOC_BIAS_PREPARE: if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) { + rt5677_set_dsp_vad(codec, false); + regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1, RT5677_LDO1_SEL_MASK | RT5677_LDO2_SEL_MASK, 0x0055); @@ -3214,6 +3483,9 @@ static int rt5677_set_bias_level(struct snd_soc_codec *codec, regmap_write(rt5677->regmap, RT5677_PWR_ANLG2, 0x0000); regmap_update_bits(rt5677->regmap, RT5677_PR_BASE + RT5677_BIAS_CUR4, 0x0f00, 0x0000); + + if (rt5677->dsp_vad_en) + rt5677_set_dsp_vad(codec, true); break; default: @@ -3407,6 +3679,8 @@ static int rt5677_probe(struct snd_soc_codec *codec) for (i = 0; i < RT5677_GPIO_NUM; i++) rt5677_gpio_config(rt5677, i, rt5677->pdata.gpio_config[i]); + mutex_init(&rt5677->dsp_cmd_lock); + return 0; } @@ -3426,8 +3700,11 @@ static int rt5677_suspend(struct snd_soc_codec *codec) { struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); - regcache_cache_only(rt5677->regmap, true); - regcache_mark_dirty(rt5677->regmap); + if (!rt5677->dsp_vad_en) { + regcache_cache_only(rt5677->regmap, true); + regcache_mark_dirty(rt5677->regmap); + } + if (gpio_is_valid(rt5677->pow_ldo2)) gpio_set_value_cansleep(rt5677->pow_ldo2, 0); @@ -3442,8 +3719,11 @@ static int rt5677_resume(struct snd_soc_codec *codec) gpio_set_value_cansleep(rt5677->pow_ldo2, 1); msleep(10); } - regcache_cache_only(rt5677->regmap, false); - regcache_sync(rt5677->regmap); + + if (!rt5677->dsp_vad_en) { + regcache_cache_only(rt5677->regmap, false); + regcache_sync(rt5677->regmap); + } return 0; } diff --git a/sound/soc/codecs/rt5677.h b/sound/soc/codecs/rt5677.h index 99fd023e3290..20efa4a4c82c 100644 --- a/sound/soc/codecs/rt5677.h +++ b/sound/soc/codecs/rt5677.h @@ -1507,6 +1507,9 @@ #define RT5677_GPIO5_FUNC_GPIO (0x0 << 9) #define RT5677_GPIO5_FUNC_DMIC (0x1 << 9) +#define RT5677_FIRMWARE1 "rt5677_dsp_fw1.bin" +#define RT5677_FIRMWARE2 "rt5677_dsp_fw2.bin" + /* System Clock Source */ enum { RT5677_SCLK_S_MCLK, @@ -1546,6 +1549,8 @@ struct rt5677_priv { struct snd_soc_codec *codec; struct rt5677_platform_data pdata; struct regmap *regmap; + const struct firmware *fw1, *fw2; + struct mutex dsp_cmd_lock; int sysclk; int sysclk_src; @@ -1559,6 +1564,7 @@ struct rt5677_priv { #ifdef CONFIG_GPIOLIB struct gpio_chip gpio_chip; #endif + bool dsp_vad_en; }; #endif /* __RT5677_H__ */ -- cgit v1.2.3 From 8a4bd60af4cbdfbdaab6dec6ab86471733197a4f Mon Sep 17 00:00:00 2001 From: Anatol Pomozov Date: Wed, 15 Oct 2014 13:55:32 -0700 Subject: ASoC: rt5677: Print more information if setting DAI clock failed Signed-off-by: Anatol Pomozov Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index e6e54fa648aa..caada9192f0f 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -3104,7 +3104,8 @@ static int rt5677_hw_params(struct snd_pcm_substream *substream, rt5677->lrck[dai->id] = params_rate(params); pre_div = rl6231_get_clk_info(rt5677->sysclk, rt5677->lrck[dai->id]); if (pre_div < 0) { - dev_err(codec->dev, "Unsupported clock setting\n"); + dev_err(codec->dev, "Unsupported clock setting: sysclk=%dHz lrck=%dHz\n", + rt5677->sysclk, rt5677->lrck[dai->id]); return -EINVAL; } frame_size = snd_soc_params_to_frame_size(params); -- cgit v1.2.3 From 45b6e1d300b034678c42369aad3b27d37854d1fb Mon Sep 17 00:00:00 2001 From: Anatol Pomozov Date: Thu, 16 Oct 2014 09:40:58 -0700 Subject: ASoC: rt5677: fix build when kernel compiled without GPIOLIB support Signed-off-by: Anatol Pomozov Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index caada9192f0f..d17d079fdcf3 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -3646,6 +3646,11 @@ static void rt5677_free_gpio(struct i2c_client *i2c) gpiochip_remove(&rt5677->gpio_chip); } #else +static void rt5677_gpio_config(struct rt5677_priv *rt5677, unsigned offset, + int value) +{ +} + static void rt5677_init_gpio(struct i2c_client *i2c) { } -- cgit v1.2.3 From ac884fc47b7750b1e7eaf04f0236610c84ceee54 Mon Sep 17 00:00:00 2001 From: Anatol Pomozov Date: Fri, 17 Oct 2014 11:56:42 -0700 Subject: ASoC: rt5677: add build dependency to spi Since 9cb715a9d4c the codec has a hardcoded dependency to spi. Add this dependency to Kconfig. It fixes buildbot compilation failure: sound/built-in.o: In function `spi_write': >> rt5677-spi.c:(.text+0x8265f): undefined reference to `spi_sync' sound/built-in.o: In function `rt5677_spi_driver_init': >> rt5677-spi.c:(.init.text+0x17db): undefined reference to `spi_register_driver' Signed-off-by: Anatol Pomozov Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index a68d1731a8fd..2c7482ec25e8 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -85,7 +85,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_RT5645 if I2C select SND_SOC_RT5651 if I2C select SND_SOC_RT5670 if I2C - select SND_SOC_RT5677 if I2C + select SND_SOC_RT5677 if I2C && SPI_MASTER select SND_SOC_SGTL5000 if I2C select SND_SOC_SI476X if MFD_SI476X_CORE select SND_SOC_SIRF_AUDIO_CODEC -- cgit v1.2.3 From 7f6d75d77683c8f9c18836a2fea2a1e76efc3a9a Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 7 Oct 2014 10:50:56 -0300 Subject: ASoC: sgtl5000: Cleanup the comments Fix grammar and typos. Besides that, also fix the comment about the range of SYS_MCLK, which is from 8 to 27 MHz. Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown --- sound/soc/codecs/sgtl5000.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index 6bb77d76561b..10160e7a9277 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -530,16 +530,16 @@ static int sgtl5000_set_dai_sysclk(struct snd_soc_dai *codec_dai, /* * set clock according to i2s frame clock, - * sgtl5000 provide 2 clock sources. - * 1. sys_mclk. sample freq can only configure to + * sgtl5000 provides 2 clock sources: + * 1. sys_mclk: sample freq can only be configured to * 1/256, 1/384, 1/512 of sys_mclk. - * 2. pll. can derive any audio clocks. + * 2. pll: can derive any audio clocks. * * clock setting rules: - * 1. in slave mode, only sys_mclk can use. - * 2. as constraint by sys_mclk, sample freq should - * set to 32k, 44.1k and above. - * 3. using sys_mclk prefer to pll to save power. + * 1. in slave mode, only sys_mclk can be used + * 2. as constraint by sys_mclk, sample freq should be set to 32 kHz, 44.1 kHz + * and above. + * 3. usage of sys_mclk is preferred over pll to save power. */ static int sgtl5000_set_clock(struct snd_soc_codec *codec, int frame_rate) { @@ -549,8 +549,8 @@ static int sgtl5000_set_clock(struct snd_soc_codec *codec, int frame_rate) /* * sample freq should be divided by frame clock, - * if frame clock lower than 44.1khz, sample feq should set to - * 32khz or 44.1khz. + * if frame clock is lower than 44.1 kHz, sample freq should be set to + * 32 kHz or 44.1 kHz. */ switch (frame_rate) { case 8000: @@ -603,7 +603,8 @@ static int sgtl5000_set_clock(struct snd_soc_codec *codec, int frame_rate) /* * calculate the divider of mclk/sample_freq, - * factor of freq =96k can only be 256, since mclk in range (12m,27m) + * factor of freq = 96 kHz can only be 256, since mclk is in the range + * of 8 MHz - 27 MHz */ switch (sgtl5000->sysclk / sys_fs) { case 256: @@ -619,7 +620,7 @@ static int sgtl5000_set_clock(struct snd_soc_codec *codec, int frame_rate) SGTL5000_MCLK_FREQ_SHIFT; break; default: - /* if mclk not satisify the divider, use pll */ + /* if mclk does not satisfy the divider, use pll */ if (sgtl5000->master) { clk_ctl |= SGTL5000_MCLK_FREQ_PLL << SGTL5000_MCLK_FREQ_SHIFT; @@ -795,7 +796,7 @@ static int ldo_regulator_enable(struct regulator_dev *dev) SGTL5000_LINEREG_D_POWERUP, SGTL5000_LINEREG_D_POWERUP); - /* when internal ldo enabled, simple digital power can be disabled */ + /* when internal ldo is enabled, simple digital power can be disabled */ snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER, SGTL5000_LINREG_SIMPLE_POWERUP, 0); @@ -1079,7 +1080,7 @@ static bool sgtl5000_readable(struct device *dev, unsigned int reg) /* * sgtl5000 has 3 internal power supplies: * 1. VAG, normally set to vdda/2 - * 2. chargepump, set to different value + * 2. charge pump, set to different value * according to voltage of vdda and vddio * 3. line out VAG, normally set to vddio/2 * -- cgit v1.2.3 From bd0593f5f6add279257334b4a76aecd3ee8d31dc Mon Sep 17 00:00:00 2001 From: Jean-Michel Hautbois Date: Tue, 14 Oct 2014 08:43:11 +0200 Subject: ASoC: sgtl5000: Add MicBias resistor support in DT Some systems may require a different resistor than the default one (4K). This adds a property in sgtl5000 codec. It keeps the default of 4K when nothing is specified so it does not break existing code. Signed-off-by: Jean-Michel Hautbois Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/sgtl5000.txt | 8 ++++ sound/soc/codecs/sgtl5000.c | 55 ++++++++++++++++++++-- 2 files changed, 59 insertions(+), 4 deletions(-) (limited to 'sound/soc/codecs') diff --git a/Documentation/devicetree/bindings/sound/sgtl5000.txt b/Documentation/devicetree/bindings/sound/sgtl5000.txt index 955df60a118c..d6ec92707d81 100644 --- a/Documentation/devicetree/bindings/sound/sgtl5000.txt +++ b/Documentation/devicetree/bindings/sound/sgtl5000.txt @@ -7,10 +7,18 @@ Required properties: - clocks : the clock provider of SYS_MCLK +- micbias-resistor-k-ohms : the bias resistor to be used in kOmhs + The resistor can take values of 2k, 4k or 8k. + If set to 0 it will be off. + If this node is not mentioned or if the value is unknown, then + micbias resistor is set to 4K. + + Example: codec: sgtl5000@0a { compatible = "fsl,sgtl5000"; reg = <0x0a>; clocks = <&clks 150>; + sgtl5000-micbias-resistor = <1>; }; diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index 10160e7a9277..c417b4ad0492 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -121,6 +122,13 @@ struct ldo_regulator { bool enabled; }; +enum sgtl5000_micbias_resistor { + SGTL5000_MICBIAS_OFF = 0, + SGTL5000_MICBIAS_2K = 2, + SGTL5000_MICBIAS_4K = 4, + SGTL5000_MICBIAS_8K = 8, +}; + /* sgtl5000 private structure in codec */ struct sgtl5000_priv { int sysclk; /* sysclk rate */ @@ -131,6 +139,7 @@ struct sgtl5000_priv { struct regmap *regmap; struct clk *mclk; int revision; + u8 micbias_resistor; }; /* @@ -145,12 +154,14 @@ struct sgtl5000_priv { static int mic_bias_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { + struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(w->codec); + switch (event) { case SND_SOC_DAPM_POST_PMU: - /* change mic bias resistor to 4Kohm */ + /* change mic bias resistor */ snd_soc_update_bits(w->codec, SGTL5000_CHIP_MIC_CTRL, - SGTL5000_BIAS_R_MASK, - SGTL5000_BIAS_R_4k << SGTL5000_BIAS_R_SHIFT); + SGTL5000_BIAS_R_MASK, + sgtl5000->micbias_resistor << SGTL5000_BIAS_R_SHIFT); break; case SND_SOC_DAPM_PRE_PMD: @@ -1327,7 +1338,9 @@ static int sgtl5000_probe(struct snd_soc_codec *codec) SGTL5000_HP_ZCD_EN | SGTL5000_ADC_ZCD_EN); - snd_soc_write(codec, SGTL5000_CHIP_MIC_CTRL, 2); + snd_soc_update_bits(codec, SGTL5000_CHIP_MIC_CTRL, + SGTL5000_BIAS_R_MASK, + sgtl5000->micbias_resistor << SGTL5000_BIAS_R_SHIFT); /* * disable DAP @@ -1419,6 +1432,8 @@ static int sgtl5000_i2c_probe(struct i2c_client *client, struct sgtl5000_priv *sgtl5000; int ret, reg, rev; unsigned int mclk; + struct device_node *np = client->dev.of_node; + u32 value; sgtl5000 = devm_kzalloc(&client->dev, sizeof(struct sgtl5000_priv), GFP_KERNEL); @@ -1471,6 +1486,38 @@ static int sgtl5000_i2c_probe(struct i2c_client *client, dev_info(&client->dev, "sgtl5000 revision 0x%x\n", rev); sgtl5000->revision = rev; + if (np) { + if (!of_property_read_u32(np, + "micbias-resistor-k-ohms", &value)) { + switch (value) { + case SGTL5000_MICBIAS_OFF: + sgtl5000->micbias_resistor = 0; + break; + case SGTL5000_MICBIAS_2K: + sgtl5000->micbias_resistor = 1; + break; + case SGTL5000_MICBIAS_4K: + sgtl5000->micbias_resistor = 2; + break; + case SGTL5000_MICBIAS_8K: + sgtl5000->micbias_resistor = 3; + break; + default: + sgtl5000->micbias_resistor = 2; + dev_err(&client->dev, + "Unsuitable MicBias resistor\n"); + } + } else { + /* default is 4Kohms */ + sgtl5000->micbias_resistor = 2; + } + dev_err(&client->dev, + "Unsuitable MicBias resistor\n"); + } + } else { + } + } + i2c_set_clientdata(client, sgtl5000); /* Ensure sgtl5000 will start with sane register values */ -- cgit v1.2.3 From 8735779774b8bbe14456c9e6ba4525eefc67a228 Mon Sep 17 00:00:00 2001 From: Jean-Michel Hautbois Date: Tue, 14 Oct 2014 08:43:12 +0200 Subject: ASoC: sgtl5000: Add MicBias voltage support Some systems may require to specify a bias different than default (1.25V). This adds a property in sgtl5000 codec. The property is specified in milli-volts so that it is coherent with datasheet. Signed-off-by: Jean-Michel Hautbois Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/sgtl5000.txt | 7 ++++++- sound/soc/codecs/sgtl5000.c | 13 +++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) (limited to 'sound/soc/codecs') diff --git a/Documentation/devicetree/bindings/sound/sgtl5000.txt b/Documentation/devicetree/bindings/sound/sgtl5000.txt index d6ec92707d81..1aab40339617 100644 --- a/Documentation/devicetree/bindings/sound/sgtl5000.txt +++ b/Documentation/devicetree/bindings/sound/sgtl5000.txt @@ -13,6 +13,10 @@ Required properties: If this node is not mentioned or if the value is unknown, then micbias resistor is set to 4K. +- micbias-voltage-m-volts : the bias voltage to be used in mVolts + The voltage can take values from 1.25V to 3V by 250mV steps + If this node is not mentionned or the value is unknown, then + the value is set to 1.25V. Example: @@ -20,5 +24,6 @@ codec: sgtl5000@0a { compatible = "fsl,sgtl5000"; reg = <0x0a>; clocks = <&clks 150>; - sgtl5000-micbias-resistor = <1>; + micbias-resistor-k-ohms = <2>; + micbias-voltage-m-volts = <2250>; }; diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index c417b4ad0492..59336f6aba80 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -140,6 +140,7 @@ struct sgtl5000_priv { struct clk *mclk; int revision; u8 micbias_resistor; + u8 micbias_voltage; }; /* @@ -1342,6 +1343,9 @@ static int sgtl5000_probe(struct snd_soc_codec *codec) SGTL5000_BIAS_R_MASK, sgtl5000->micbias_resistor << SGTL5000_BIAS_R_SHIFT); + snd_soc_update_bits(codec, SGTL5000_CHIP_MIC_CTRL, + SGTL5000_BIAS_R_MASK, + sgtl5000->micbias_voltage << SGTL5000_BIAS_R_SHIFT); /* * disable DAP * TODO: @@ -1511,10 +1515,19 @@ static int sgtl5000_i2c_probe(struct i2c_client *client, /* default is 4Kohms */ sgtl5000->micbias_resistor = 2; } + if (!of_property_read_u32(np, + "micbias-voltage-m-volts", &value)) { + /* 1250mV => 0 */ + /* steps of 250mV */ + if ((value >= 1250) && (value <= 3000)) + sgtl5000->micbias_voltage = (value / 250) - 5; + else { + sgtl5000->micbias_voltage = 0; dev_err(&client->dev, "Unsuitable MicBias resistor\n"); } } else { + sgtl5000->micbias_voltage = 0; } } -- cgit v1.2.3 From 9313484238ca49fe5c7513dfcb36aaddcea8c298 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 20 Oct 2014 10:56:28 +0200 Subject: ASoC: ak4535: Cleanup manual bias level transitions Set the CODEC driver's suspend_bias_off flag rather than manually going to SND_SOC_BIAS_OFF in suspend and SND_SOC_BIAS_STANDBY in resume. This makes the code a bit shorter and cleaner. Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. The manual transition to SND_SOC_BIAS_STANDBY at the end of CODEC probe() can also be removed as the core will automatically do this after the CODEC has been probed. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/ak4535.c | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c index 30e297890fec..eced46d7d6cb 100644 --- a/sound/soc/codecs/ak4535.c +++ b/sound/soc/codecs/ak4535.c @@ -373,36 +373,19 @@ static struct snd_soc_dai_driver ak4535_dai = { .ops = &ak4535_dai_ops, }; -static int ak4535_suspend(struct snd_soc_codec *codec) -{ - ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - static int ak4535_resume(struct snd_soc_codec *codec) { snd_soc_cache_sync(codec); - ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY); return 0; } static int ak4535_probe(struct snd_soc_codec *codec) { - /* power on device */ - ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - snd_soc_add_codec_controls(codec, ak4535_snd_controls, ARRAY_SIZE(ak4535_snd_controls)); return 0; } -/* power down chip */ -static int ak4535_remove(struct snd_soc_codec *codec) -{ - ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - static const struct regmap_config ak4535_regmap = { .reg_bits = 8, .val_bits = 8, @@ -417,10 +400,10 @@ static const struct regmap_config ak4535_regmap = { static struct snd_soc_codec_driver soc_codec_dev_ak4535 = { .probe = ak4535_probe, - .remove = ak4535_remove, - .suspend = ak4535_suspend, .resume = ak4535_resume, .set_bias_level = ak4535_set_bias_level, + .suspend_bias_off = true, + .dapm_widgets = ak4535_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(ak4535_dapm_widgets), .dapm_routes = ak4535_audio_map, -- cgit v1.2.3 From 4caab4194a99e58c08c70e7df846b9bda948f353 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 20 Oct 2014 10:56:29 +0200 Subject: ASoC: ak4535: Use table based setup for controls Makes the code slightly shorter and cleaner. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/ak4535.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c index eced46d7d6cb..9130d916f2f4 100644 --- a/sound/soc/codecs/ak4535.c +++ b/sound/soc/codecs/ak4535.c @@ -379,13 +379,6 @@ static int ak4535_resume(struct snd_soc_codec *codec) return 0; } -static int ak4535_probe(struct snd_soc_codec *codec) -{ - snd_soc_add_codec_controls(codec, ak4535_snd_controls, - ARRAY_SIZE(ak4535_snd_controls)); - return 0; -} - static const struct regmap_config ak4535_regmap = { .reg_bits = 8, .val_bits = 8, @@ -399,11 +392,12 @@ static const struct regmap_config ak4535_regmap = { }; static struct snd_soc_codec_driver soc_codec_dev_ak4535 = { - .probe = ak4535_probe, .resume = ak4535_resume, .set_bias_level = ak4535_set_bias_level, .suspend_bias_off = true, + .controls = ak4535_snd_controls, + .num_controls = ARRAY_SIZE(ak4535_snd_controls), .dapm_widgets = ak4535_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(ak4535_dapm_widgets), .dapm_routes = ak4535_audio_map, -- cgit v1.2.3 From 0b0171e3ad22b5a3be01bbafddede4ebea1769bd Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 20 Oct 2014 10:56:30 +0200 Subject: ASoC: ak4641: Cleanup manual bias level transitions Set the CODEC driver's suspend_bias_off flag rather than manually going to SND_SOC_BIAS_OFF in suspend and SND_SOC_BIAS_STANDBY in resume. This makes the code a bit shorter and cleaner. Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. The manual transition to SND_SOC_BIAS_STANDBY at the end of CODEC probe() can also be removed as the core will automatically do this after the CODEC has been probed. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/ak4641.c | 33 +-------------------------------- 1 file changed, 1 insertion(+), 32 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/ak4641.c b/sound/soc/codecs/ak4641.c index 7afe8f482088..70861c7b1631 100644 --- a/sound/soc/codecs/ak4641.c +++ b/sound/soc/codecs/ak4641.c @@ -505,39 +505,7 @@ static struct snd_soc_dai_driver ak4641_dai[] = { }, }; -static int ak4641_suspend(struct snd_soc_codec *codec) -{ - ak4641_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - -static int ak4641_resume(struct snd_soc_codec *codec) -{ - ak4641_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - return 0; -} - -static int ak4641_probe(struct snd_soc_codec *codec) -{ - /* power on device */ - ak4641_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - return 0; -} - -static int ak4641_remove(struct snd_soc_codec *codec) -{ - ak4641_set_bias_level(codec, SND_SOC_BIAS_OFF); - - return 0; -} - - static struct snd_soc_codec_driver soc_codec_dev_ak4641 = { - .probe = ak4641_probe, - .remove = ak4641_remove, - .suspend = ak4641_suspend, - .resume = ak4641_resume, .controls = ak4641_snd_controls, .num_controls = ARRAY_SIZE(ak4641_snd_controls), .dapm_widgets = ak4641_dapm_widgets, @@ -545,6 +513,7 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4641 = { .dapm_routes = ak4641_audio_map, .num_dapm_routes = ARRAY_SIZE(ak4641_audio_map), .set_bias_level = ak4641_set_bias_level, + .suspend_bias_off = true, }; static const struct regmap_config ak4641_regmap = { -- cgit v1.2.3 From 61ce9ee3aad2fc7a505a420957e8205c4050db69 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 20 Oct 2014 10:56:31 +0200 Subject: ASoC: ak4642: Cleanup manual bias level transitions Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. The manual transition to SND_SOC_BIAS_STANDBY at the end of CODEC probe() can also be removed as the core will automatically do this after the CODEC has been probed. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/ak4642.c | 16 ---------------- 1 file changed, 16 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index 041712592e29..dde8b49c19ad 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c @@ -491,23 +491,7 @@ static int ak4642_resume(struct snd_soc_codec *codec) return 0; } - -static int ak4642_probe(struct snd_soc_codec *codec) -{ - ak4642_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - return 0; -} - -static int ak4642_remove(struct snd_soc_codec *codec) -{ - ak4642_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - static struct snd_soc_codec_driver soc_codec_dev_ak4642 = { - .probe = ak4642_probe, - .remove = ak4642_remove, .resume = ak4642_resume, .set_bias_level = ak4642_set_bias_level, .controls = ak4642_snd_controls, -- cgit v1.2.3 From e48d73c697b77b798a82e86c937fc41e597a1471 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 20 Oct 2014 10:56:32 +0200 Subject: ASoC: ak4671: Cleanup manual bias level transitions Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. The manual transition to SND_SOC_BIAS_STANDBY at the end of CODEC probe() can also be removed as the core will automatically do this after the CODEC has been probed. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/ak4671.c | 13 ------------- 1 file changed, 13 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/ak4671.c b/sound/soc/codecs/ak4671.c index 998fa0c5a0b9..686cacb0e835 100644 --- a/sound/soc/codecs/ak4671.c +++ b/sound/soc/codecs/ak4671.c @@ -611,20 +611,7 @@ static struct snd_soc_dai_driver ak4671_dai = { .ops = &ak4671_dai_ops, }; -static int ak4671_probe(struct snd_soc_codec *codec) -{ - return ak4671_set_bias_level(codec, SND_SOC_BIAS_STANDBY); -} - -static int ak4671_remove(struct snd_soc_codec *codec) -{ - ak4671_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - static struct snd_soc_codec_driver soc_codec_dev_ak4671 = { - .probe = ak4671_probe, - .remove = ak4671_remove, .set_bias_level = ak4671_set_bias_level, .controls = ak4671_snd_controls, .num_controls = ARRAY_SIZE(ak4671_snd_controls), -- cgit v1.2.3 From a613cc4063a315efe36f233006f424e958ef4e67 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 20 Oct 2014 10:56:33 +0200 Subject: ASoC: max98088: Cleanup manual bias level transitions Set the CODEC driver's suspend_bias_off flag rather than manually going to SND_SOC_BIAS_OFF in suspend and SND_SOC_BIAS_STANDBY in resume. This makes the code a bit shorter and cleaner. Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. The manual transition to SND_SOC_BIAS_STANDBY at the end of CODEC probe() can also be removed as the core will automatically do this after the CODEC has been probed. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/max98088.c | 27 ++------------------------- 1 file changed, 2 insertions(+), 25 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c index 2cd3e5427441..bb892b3178dc 100644 --- a/sound/soc/codecs/max98088.c +++ b/sound/soc/codecs/max98088.c @@ -1887,25 +1887,6 @@ static void max98088_handle_pdata(struct snd_soc_codec *codec) max98088_handle_eq_pdata(codec); } -#ifdef CONFIG_PM -static int max98088_suspend(struct snd_soc_codec *codec) -{ - max98088_set_bias_level(codec, SND_SOC_BIAS_OFF); - - return 0; -} - -static int max98088_resume(struct snd_soc_codec *codec) -{ - max98088_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - return 0; -} -#else -#define max98088_suspend NULL -#define max98088_resume NULL -#endif - static int max98088_probe(struct snd_soc_codec *codec) { struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec); @@ -1946,9 +1927,6 @@ static int max98088_probe(struct snd_soc_codec *codec) snd_soc_write(codec, M98088_REG_51_PWR_SYS, M98088_PWRSV); - /* initialize registers cache to hardware default */ - max98088_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - snd_soc_write(codec, M98088_REG_0F_IRQ_ENABLE, 0x00); snd_soc_write(codec, M98088_REG_22_MIX_DAC, @@ -1974,7 +1952,6 @@ static int max98088_remove(struct snd_soc_codec *codec) { struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec); - max98088_set_bias_level(codec, SND_SOC_BIAS_OFF); kfree(max98088->eq_texts); return 0; @@ -1983,9 +1960,9 @@ static int max98088_remove(struct snd_soc_codec *codec) static struct snd_soc_codec_driver soc_codec_dev_max98088 = { .probe = max98088_probe, .remove = max98088_remove, - .suspend = max98088_suspend, - .resume = max98088_resume, .set_bias_level = max98088_set_bias_level, + .suspend_bias_off = true, + .controls = max98088_snd_controls, .num_controls = ARRAY_SIZE(max98088_snd_controls), .dapm_widgets = max98088_dapm_widgets, -- cgit v1.2.3 From a8669f60321c8cb08af76438727b6460d1b591b6 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 20 Oct 2014 10:56:34 +0200 Subject: ASoC: max98095: Cleanup manual bias level transitions Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. The manual transition to SND_SOC_BIAS_STANDBY at the end of CODEC probe() can also be removed as the core will automatically do this after the CODEC has been probed. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/max98095.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c index 0ee6797d5083..42103cafeb24 100644 --- a/sound/soc/codecs/max98095.c +++ b/sound/soc/codecs/max98095.c @@ -2317,9 +2317,6 @@ static int max98095_probe(struct snd_soc_codec *codec) snd_soc_write(codec, M98095_097_PWR_SYS, M98095_PWRSV); - /* initialize registers cache to hardware default */ - max98095_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - snd_soc_write(codec, M98095_048_MIX_DAC_LR, M98095_DAI1L_TO_DACL|M98095_DAI1R_TO_DACR); @@ -2359,8 +2356,6 @@ static int max98095_remove(struct snd_soc_codec *codec) struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); struct i2c_client *client = to_i2c_client(codec->dev); - max98095_set_bias_level(codec, SND_SOC_BIAS_OFF); - if (max98095->headphone_jack || max98095->mic_jack) max98095_jack_detect_disable(codec); -- cgit v1.2.3 From 46804120c59b1374f8beb2b8636ffe6b0a7c16c8 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 20 Oct 2014 10:56:35 +0200 Subject: ASoC: max9850: Cleanup manual bias level transitions Set the CODEC driver's suspend_bias_off flag rather than manually going to SND_SOC_BIAS_OFF in suspend and SND_SOC_BIAS_STANDBY in resume. This makes the code a bit shorter and cleaner. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/max9850.c | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/max9850.c b/sound/soc/codecs/max9850.c index 4fdf5aaa236f..10f8e47ce2c2 100644 --- a/sound/soc/codecs/max9850.c +++ b/sound/soc/codecs/max9850.c @@ -291,25 +291,6 @@ static struct snd_soc_dai_driver max9850_dai = { .ops = &max9850_dai_ops, }; -#ifdef CONFIG_PM -static int max9850_suspend(struct snd_soc_codec *codec) -{ - max9850_set_bias_level(codec, SND_SOC_BIAS_OFF); - - return 0; -} - -static int max9850_resume(struct snd_soc_codec *codec) -{ - max9850_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - return 0; -} -#else -#define max9850_suspend NULL -#define max9850_resume NULL -#endif - static int max9850_probe(struct snd_soc_codec *codec) { /* enable zero-detect */ @@ -324,9 +305,8 @@ static int max9850_probe(struct snd_soc_codec *codec) static struct snd_soc_codec_driver soc_codec_dev_max9850 = { .probe = max9850_probe, - .suspend = max9850_suspend, - .resume = max9850_resume, .set_bias_level = max9850_set_bias_level, + .suspend_bias_off = true, .controls = max9850_controls, .num_controls = ARRAY_SIZE(max9850_controls), -- cgit v1.2.3 From 815b776cf5983ab69d548146fb979adac5dec4de Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 20 Oct 2014 10:56:36 +0200 Subject: ASoC: sta32x: Cleanup manual bias level transitions Set the CODEC driver's suspend_bias_off flag rather than manually going to SND_SOC_BIAS_OFF in suspend and SND_SOC_BIAS_STANDBY in resume. This makes the code a bit shorter and cleaner. Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/sta32x.c | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c index 48740855566d..7e18200dd6a9 100644 --- a/sound/soc/codecs/sta32x.c +++ b/sound/soc/codecs/sta32x.c @@ -833,23 +833,6 @@ static struct snd_soc_dai_driver sta32x_dai = { .ops = &sta32x_dai_ops, }; -#ifdef CONFIG_PM -static int sta32x_suspend(struct snd_soc_codec *codec) -{ - sta32x_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - -static int sta32x_resume(struct snd_soc_codec *codec) -{ - sta32x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - return 0; -} -#else -#define sta32x_suspend NULL -#define sta32x_resume NULL -#endif - static int sta32x_probe(struct snd_soc_codec *codec) { struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); @@ -936,7 +919,6 @@ static int sta32x_remove(struct snd_soc_codec *codec) struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); sta32x_watchdog_stop(sta32x); - sta32x_set_bias_level(codec, SND_SOC_BIAS_OFF); regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies); return 0; @@ -955,9 +937,8 @@ static bool sta32x_reg_is_volatile(struct device *dev, unsigned int reg) static const struct snd_soc_codec_driver sta32x_codec = { .probe = sta32x_probe, .remove = sta32x_remove, - .suspend = sta32x_suspend, - .resume = sta32x_resume, .set_bias_level = sta32x_set_bias_level, + .suspend_bias_off = true, .controls = sta32x_snd_controls, .num_controls = ARRAY_SIZE(sta32x_snd_controls), .dapm_widgets = sta32x_dapm_widgets, -- cgit v1.2.3 From 2062c1ff3596e1ae8aafe8082460d03d9a420282 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 20 Oct 2014 10:56:37 +0200 Subject: ASoC: sta350: Cleanup manual bias level transitions Set the CODEC driver's suspend_bias_off flag rather than manually going to SND_SOC_BIAS_OFF in suspend and SND_SOC_BIAS_STANDBY in resume. This makes the code a bit shorter and cleaner. Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/sta350.c | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/sta350.c b/sound/soc/codecs/sta350.c index cc97dd52aa9c..bda2ee18769e 100644 --- a/sound/soc/codecs/sta350.c +++ b/sound/soc/codecs/sta350.c @@ -912,23 +912,6 @@ static struct snd_soc_dai_driver sta350_dai = { .ops = &sta350_dai_ops, }; -#ifdef CONFIG_PM -static int sta350_suspend(struct snd_soc_codec *codec) -{ - sta350_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - -static int sta350_resume(struct snd_soc_codec *codec) -{ - sta350_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - return 0; -} -#else -#define sta350_suspend NULL -#define sta350_resume NULL -#endif - static int sta350_probe(struct snd_soc_codec *codec) { struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec); @@ -1065,7 +1048,6 @@ static int sta350_remove(struct snd_soc_codec *codec) { struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec); - sta350_set_bias_level(codec, SND_SOC_BIAS_OFF); regulator_bulk_disable(ARRAY_SIZE(sta350->supplies), sta350->supplies); return 0; @@ -1074,9 +1056,8 @@ static int sta350_remove(struct snd_soc_codec *codec) static const struct snd_soc_codec_driver sta350_codec = { .probe = sta350_probe, .remove = sta350_remove, - .suspend = sta350_suspend, - .resume = sta350_resume, .set_bias_level = sta350_set_bias_level, + .suspend_bias_off = true, .controls = sta350_snd_controls, .num_controls = ARRAY_SIZE(sta350_snd_controls), .dapm_widgets = sta350_dapm_widgets, -- cgit v1.2.3 From cfbb77ce368b8d4181e06f8982a440702567eb98 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 20 Oct 2014 10:56:38 +0200 Subject: ASoC: sta529: Cleanup manual bias level transitions Set the CODEC driver's suspend_bias_off flag rather than manually going to SND_SOC_BIAS_OFF in suspend and SND_SOC_BIAS_STANDBY in resume. This makes the code a bit shorter and cleaner. Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. The manual transition to SND_SOC_BIAS_STANDBY at the end of CODEC probe() can also be removed as the core will automatically do this after the CODEC has been probed. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/sta529.c | 35 ++--------------------------------- 1 file changed, 2 insertions(+), 33 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/sta529.c b/sound/soc/codecs/sta529.c index 89c748dd3d6e..b0f436d10125 100644 --- a/sound/soc/codecs/sta529.c +++ b/sound/soc/codecs/sta529.c @@ -319,41 +319,10 @@ static struct snd_soc_dai_driver sta529_dai = { .ops = &sta529_dai_ops, }; -static int sta529_probe(struct snd_soc_codec *codec) -{ - sta529_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - return 0; -} - -/* power down chip */ -static int sta529_remove(struct snd_soc_codec *codec) -{ - sta529_set_bias_level(codec, SND_SOC_BIAS_OFF); - - return 0; -} - -static int sta529_suspend(struct snd_soc_codec *codec) -{ - sta529_set_bias_level(codec, SND_SOC_BIAS_OFF); - - return 0; -} - -static int sta529_resume(struct snd_soc_codec *codec) -{ - sta529_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - return 0; -} - static const struct snd_soc_codec_driver sta529_codec_driver = { - .probe = sta529_probe, - .remove = sta529_remove, .set_bias_level = sta529_set_bias_level, - .suspend = sta529_suspend, - .resume = sta529_resume, + .suspend_bias_off = true, + .controls = sta529_snd_controls, .num_controls = ARRAY_SIZE(sta529_snd_controls), }; -- cgit v1.2.3 From 4c07a43d9691ab1f264337d683dc8655b1edca46 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 20 Oct 2014 10:56:39 +0200 Subject: ASoC: stac9766: Cleanup manual bias level transitions Set the CODEC driver's suspend_bias_off flag rather than manually going to SND_SOC_BIAS_OFF in suspend and SND_SOC_BIAS_STANDBY in resume. This makes the code a bit shorter and cleaner. The manual transition to SND_SOC_BIAS_STANDBY at the end of CODEC probe() can also be removed as the core will automatically do this after the CODEC has been probed. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/stac9766.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c index 53b810d23fea..9878534ccd16 100644 --- a/sound/soc/codecs/stac9766.c +++ b/sound/soc/codecs/stac9766.c @@ -254,12 +254,6 @@ static int stac9766_reset(struct snd_soc_codec *codec, int try_warm) return 0; } -static int stac9766_codec_suspend(struct snd_soc_codec *codec) -{ - stac9766_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - static int stac9766_codec_resume(struct snd_soc_codec *codec) { u16 id, reset; @@ -278,7 +272,6 @@ reset: reset++; goto reset; } - stac9766_set_bias_level(codec, SND_SOC_BIAS_STANDBY); return 0; } @@ -349,8 +342,6 @@ static int stac9766_codec_probe(struct snd_soc_codec *codec) goto codec_err; } - stac9766_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - snd_soc_add_codec_controls(codec, stac9766_snd_ac97_controls, ARRAY_SIZE(stac9766_snd_ac97_controls)); @@ -371,9 +362,9 @@ static struct snd_soc_codec_driver soc_codec_dev_stac9766 = { .write = stac9766_ac97_write, .read = stac9766_ac97_read, .set_bias_level = stac9766_set_bias_level, + .suspend_bias_off = true, .probe = stac9766_codec_probe, .remove = stac9766_codec_remove, - .suspend = stac9766_codec_suspend, .resume = stac9766_codec_resume, .reg_cache_size = ARRAY_SIZE(stac9766_reg), .reg_word_size = sizeof(u16), -- cgit v1.2.3 From 5e3363ad1b7b2e1f197a3f56b01e21cb155ad454 Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Thu, 16 Oct 2014 11:24:26 -0700 Subject: ASoC: rt5677: add GPIO IRQ support This allows to enable Mic Jack detection feature Signed-off-by: Oder Chiou Modified-by: Anatol Pomozov Signed-off-by: Anatol Pomozov Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/rt5677.txt | 10 ++ include/sound/rt5677.h | 7 ++ sound/soc/codecs/rt5677.c | 134 +++++++++++++++++++++ sound/soc/codecs/rt5677.h | 49 ++++++++ 4 files changed, 200 insertions(+) (limited to 'sound/soc/codecs') diff --git a/Documentation/devicetree/bindings/sound/rt5677.txt b/Documentation/devicetree/bindings/sound/rt5677.txt index f82f0e906cd9..740ff771aa8b 100644 --- a/Documentation/devicetree/bindings/sound/rt5677.txt +++ b/Documentation/devicetree/bindings/sound/rt5677.txt @@ -33,6 +33,15 @@ Optional properties: 1 - pull down 2 - pull up +- realtek,jd1-gpio + Configures GPIO Mic Jack detection 1. + Select 0 ~ 3 as OFF, GPIO1, GPIO2 and GPIO3 respectively. + +- realtek,jd2-gpio +- realtek,jd3-gpio + Configures GPIO Mic Jack detection 2 and 3. + Select 0 ~ 3 as OFF, GPIO4, GPIO5 and GPIO6 respectively. + Pins on the device (for linking into audio routes): * IN1P @@ -63,4 +72,5 @@ rt5677 { <&gpio TEGRA_GPIO(V, 3) GPIO_ACTIVE_HIGH>; realtek,in1-differential = "true"; realtek,gpio-config = /bits/ 8 <0 0 0 0 0 2>; /* pull up GPIO6 */ + realtek,jd2-gpio = <3>; /* Enables Jack detection for GPIO6 */ }; diff --git a/include/sound/rt5677.h b/include/sound/rt5677.h index a56b429a1dbc..d9eb7d861cd0 100644 --- a/include/sound/rt5677.h +++ b/include/sound/rt5677.h @@ -30,6 +30,13 @@ struct rt5677_platform_data { /* configures GPIO, 0 - floating, 1 - pulldown, 2 - pullup */ u8 gpio_config[6]; + + /* jd1 can select 0 ~ 3 as OFF, GPIO1, GPIO2 and GPIO3 respectively */ + unsigned int jd1_gpio; + /* jd2 and jd3 can select 0 ~ 3 as + OFF, GPIO4, GPIO5 and GPIO6 respectively */ + unsigned int jd2_gpio; + unsigned int jd3_gpio; }; #endif diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index d17d079fdcf3..6c73dfd22a0c 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -3614,6 +3614,46 @@ static void rt5677_gpio_config(struct rt5677_priv *rt5677, unsigned offset, } } +static int rt5677_to_irq(struct gpio_chip *chip, unsigned offset) +{ + struct rt5677_priv *rt5677 = gpio_to_rt5677(chip); + struct regmap_irq_chip_data *data = rt5677->irq_data; + int irq; + + if (offset >= RT5677_GPIO1 && offset <= RT5677_GPIO3) { + if ((rt5677->pdata.jd1_gpio == 1 && offset == RT5677_GPIO1) || + (rt5677->pdata.jd1_gpio == 2 && + offset == RT5677_GPIO2) || + (rt5677->pdata.jd1_gpio == 3 && + offset == RT5677_GPIO3)) { + irq = RT5677_IRQ_JD1; + } else { + return -ENXIO; + } + } + + if (offset >= RT5677_GPIO4 && offset <= RT5677_GPIO6) { + if ((rt5677->pdata.jd2_gpio == 1 && offset == RT5677_GPIO4) || + (rt5677->pdata.jd2_gpio == 2 && + offset == RT5677_GPIO5) || + (rt5677->pdata.jd2_gpio == 3 && + offset == RT5677_GPIO6)) { + irq = RT5677_IRQ_JD2; + } else if ((rt5677->pdata.jd3_gpio == 1 && + offset == RT5677_GPIO4) || + (rt5677->pdata.jd3_gpio == 2 && + offset == RT5677_GPIO5) || + (rt5677->pdata.jd3_gpio == 3 && + offset == RT5677_GPIO6)) { + irq = RT5677_IRQ_JD3; + } else { + return -ENXIO; + } + } + + return regmap_irq_get_virq(data, irq); +} + static struct gpio_chip rt5677_template_chip = { .label = "rt5677", .owner = THIS_MODULE, @@ -3621,6 +3661,7 @@ static struct gpio_chip rt5677_template_chip = { .set = rt5677_gpio_set, .direction_input = rt5677_gpio_direction_in, .get = rt5677_gpio_get, + .to_irq = rt5677_to_irq, .can_sleep = 1, }; @@ -3685,6 +3726,31 @@ static int rt5677_probe(struct snd_soc_codec *codec) for (i = 0; i < RT5677_GPIO_NUM; i++) rt5677_gpio_config(rt5677, i, rt5677->pdata.gpio_config[i]); + if (rt5677->irq_data) { + regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL1, 0x8000, + 0x8000); + regmap_update_bits(rt5677->regmap, RT5677_DIG_MISC, 0x0018, + 0x0008); + + if (rt5677->pdata.jd1_gpio) + regmap_update_bits(rt5677->regmap, RT5677_JD_CTRL1, + RT5677_SEL_GPIO_JD1_MASK, + rt5677->pdata.jd1_gpio << + RT5677_SEL_GPIO_JD1_SFT); + + if (rt5677->pdata.jd2_gpio) + regmap_update_bits(rt5677->regmap, RT5677_JD_CTRL1, + RT5677_SEL_GPIO_JD2_MASK, + rt5677->pdata.jd2_gpio << + RT5677_SEL_GPIO_JD2_SFT); + + if (rt5677->pdata.jd3_gpio) + regmap_update_bits(rt5677->regmap, RT5677_JD_CTRL1, + RT5677_SEL_GPIO_JD3_MASK, + rt5677->pdata.jd3_gpio << + RT5677_SEL_GPIO_JD3_SFT); + } + mutex_init(&rt5677->dsp_cmd_lock); return 0; @@ -3915,9 +3981,74 @@ static int rt5677_parse_dt(struct rt5677_priv *rt5677, struct device_node *np) of_property_read_u8_array(np, "realtek,gpio-config", rt5677->pdata.gpio_config, RT5677_GPIO_NUM); + of_property_read_u32(np, "realtek,jd1-gpio", &rt5677->pdata.jd1_gpio); + of_property_read_u32(np, "realtek,jd2-gpio", &rt5677->pdata.jd2_gpio); + of_property_read_u32(np, "realtek,jd3-gpio", &rt5677->pdata.jd3_gpio); + return 0; } +static struct regmap_irq rt5677_irqs[] = { + [RT5677_IRQ_JD1] = { + .reg_offset = 0, + .mask = RT5677_EN_IRQ_GPIO_JD1, + }, + [RT5677_IRQ_JD2] = { + .reg_offset = 0, + .mask = RT5677_EN_IRQ_GPIO_JD2, + }, + [RT5677_IRQ_JD3] = { + .reg_offset = 0, + .mask = RT5677_EN_IRQ_GPIO_JD3, + }, +}; + +static struct regmap_irq_chip rt5677_irq_chip = { + .name = "rt5677", + .irqs = rt5677_irqs, + .num_irqs = ARRAY_SIZE(rt5677_irqs), + + .num_regs = 1, + .status_base = RT5677_IRQ_CTRL1, + .mask_base = RT5677_IRQ_CTRL1, + .mask_invert = 1, +}; + +int rt5677_irq_init(struct i2c_client *i2c) +{ + int ret; + struct rt5677_priv *rt5677 = i2c_get_clientdata(i2c); + + if (!rt5677->pdata.jd1_gpio && + !rt5677->pdata.jd2_gpio && + !rt5677->pdata.jd3_gpio) + return 0; + + if (!i2c->irq) { + dev_err(&i2c->dev, "No interrupt specified\n"); + return -EINVAL; + } + + ret = regmap_add_irq_chip(rt5677->regmap, i2c->irq, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, 0, + &rt5677_irq_chip, &rt5677->irq_data); + + if (ret != 0) { + dev_err(&i2c->dev, "Failed to register IRQ chip: %d\n", ret); + return ret; + } + + return 0; +} + +void rt5677_irq_exit(struct i2c_client *i2c) +{ + struct rt5677_priv *rt5677 = i2c_get_clientdata(i2c); + + if (rt5677->irq_data) + regmap_del_irq_chip(i2c->irq, rt5677->irq_data); +} + static int rt5677_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -4015,6 +4146,7 @@ static int rt5677_i2c_probe(struct i2c_client *i2c, } rt5677_init_gpio(i2c); + rt5677_irq_init(i2c); return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5677, rt5677_dai, ARRAY_SIZE(rt5677_dai)); @@ -4022,6 +4154,8 @@ static int rt5677_i2c_probe(struct i2c_client *i2c, static int rt5677_i2c_remove(struct i2c_client *i2c) { + rt5677_irq_exit(i2c); + snd_soc_unregister_codec(&i2c->dev); rt5677_free_gpio(i2c); diff --git a/sound/soc/codecs/rt5677.h b/sound/soc/codecs/rt5677.h index 20efa4a4c82c..d2c743c255a1 100644 --- a/sound/soc/codecs/rt5677.h +++ b/sound/soc/codecs/rt5677.h @@ -1368,6 +1368,48 @@ #define RT5677_SEL_SRC_IB01 (0x1 << 0) #define RT5677_SEL_SRC_IB01_SFT 0 +/* Jack Detect Control 1 (0xb5) */ +#define RT5677_SEL_GPIO_JD1_MASK (0x3 << 14) +#define RT5677_SEL_GPIO_JD1_SFT 14 +#define RT5677_SEL_GPIO_JD2_MASK (0x3 << 12) +#define RT5677_SEL_GPIO_JD2_SFT 12 +#define RT5677_SEL_GPIO_JD3_MASK (0x3 << 10) +#define RT5677_SEL_GPIO_JD3_SFT 10 + +/* IRQ Control 1 (0xbd) */ +#define RT5677_STA_GPIO_JD1 (0x1 << 15) +#define RT5677_STA_GPIO_JD1_SFT 15 +#define RT5677_EN_IRQ_GPIO_JD1 (0x1 << 14) +#define RT5677_EN_IRQ_GPIO_JD1_SFT 14 +#define RT5677_EN_GPIO_JD1_STICKY (0x1 << 13) +#define RT5677_EN_GPIO_JD1_STICKY_SFT 13 +#define RT5677_INV_GPIO_JD1 (0x1 << 12) +#define RT5677_INV_GPIO_JD1_SFT 12 +#define RT5677_STA_GPIO_JD2 (0x1 << 11) +#define RT5677_STA_GPIO_JD2_SFT 11 +#define RT5677_EN_IRQ_GPIO_JD2 (0x1 << 10) +#define RT5677_EN_IRQ_GPIO_JD2_SFT 10 +#define RT5677_EN_GPIO_JD2_STICKY (0x1 << 9) +#define RT5677_EN_GPIO_JD2_STICKY_SFT 9 +#define RT5677_INV_GPIO_JD2 (0x1 << 8) +#define RT5677_INV_GPIO_JD2_SFT 8 +#define RT5677_STA_MICBIAS1_OVCD (0x1 << 7) +#define RT5677_STA_MICBIAS1_OVCD_SFT 7 +#define RT5677_EN_IRQ_MICBIAS1_OVCD (0x1 << 6) +#define RT5677_EN_IRQ_MICBIAS1_OVCD_SFT 6 +#define RT5677_EN_MICBIAS1_OVCD_STICKY (0x1 << 5) +#define RT5677_EN_MICBIAS1_OVCD_STICKY_SFT 5 +#define RT5677_INV_MICBIAS1_OVCD (0x1 << 4) +#define RT5677_INV_MICBIAS1_OVCD_SFT 4 +#define RT5677_STA_GPIO_JD3 (0x1 << 3) +#define RT5677_STA_GPIO_JD3_SFT 3 +#define RT5677_EN_IRQ_GPIO_JD3 (0x1 << 2) +#define RT5677_EN_IRQ_GPIO_JD3_SFT 2 +#define RT5677_EN_GPIO_JD3_STICKY (0x1 << 1) +#define RT5677_EN_GPIO_JD3_STICKY_SFT 1 +#define RT5677_INV_GPIO_JD3 (0x1 << 0) +#define RT5677_INV_GPIO_JD3_SFT 0 + /* GPIO status (0xbf) */ #define RT5677_GPIO6_STATUS_MASK (0x1 << 5) #define RT5677_GPIO6_STATUS_SFT 5 @@ -1545,6 +1587,12 @@ enum { RT5677_GPIO_NUM, }; +enum { + RT5677_IRQ_JD1, + RT5677_IRQ_JD2, + RT5677_IRQ_JD3, +}; + struct rt5677_priv { struct snd_soc_codec *codec; struct rt5677_platform_data pdata; @@ -1565,6 +1613,7 @@ struct rt5677_priv { struct gpio_chip gpio_chip; #endif bool dsp_vad_en; + struct regmap_irq_chip_data *irq_data; }; #endif /* __RT5677_H__ */ -- cgit v1.2.3 From 2d27deb40db74c751c991e96ca91d675f966a0c5 Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Wed, 22 Oct 2014 20:04:08 +0800 Subject: ASoC: rt5677: rt5677_irq_init() can be static sound/soc/codecs/rt5677.c:4017:5: sparse: symbol 'rt5677_irq_init' was not declared. Should it be static? sound/soc/codecs/rt5677.c:4044:6: sparse: symbol 'rt5677_irq_exit' was not declared. Should it be static? Signed-off-by: Fengguang Wu Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 6c73dfd22a0c..413bccbff19e 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -4014,7 +4014,7 @@ static struct regmap_irq_chip rt5677_irq_chip = { .mask_invert = 1, }; -int rt5677_irq_init(struct i2c_client *i2c) +static int rt5677_irq_init(struct i2c_client *i2c) { int ret; struct rt5677_priv *rt5677 = i2c_get_clientdata(i2c); @@ -4041,7 +4041,7 @@ int rt5677_irq_init(struct i2c_client *i2c) return 0; } -void rt5677_irq_exit(struct i2c_client *i2c) +static void rt5677_irq_exit(struct i2c_client *i2c) { struct rt5677_priv *rt5677 = i2c_get_clientdata(i2c); -- cgit v1.2.3 From e29bee098ea1cc9b8537628f3c1cdf60ead83514 Mon Sep 17 00:00:00 2001 From: Ben Zhang Date: Mon, 20 Oct 2014 20:30:13 -0700 Subject: ASoC: rt5677: fix rt5677 spi driver build Create a separate module for rt5677 spi driver. Without this patch, the build fails due to multiple defs of 'init_module' and 'cleanup_module'. module_spi_driver() defines its own module, so it can't be part of the rt5677 module. Signed-off-by: Ben Zhang Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 4 ++++ sound/soc/codecs/Makefile | 4 +++- sound/soc/codecs/rt5677-spi.c | 2 ++ 3 files changed, 9 insertions(+), 1 deletion(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 2c7482ec25e8..6f21a766723c 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -504,6 +504,10 @@ config SND_SOC_RT5670 config SND_SOC_RT5677 tristate +config SND_SOC_RT5677_SPI + tristate + default SND_SOC_RT5677 + #Freescale sgtl5000 codec config SND_SOC_SGTL5000 tristate "Freescale SGTL5000 CODEC" diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 4435f9f18ce8..3e57edc1f510 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -79,7 +79,8 @@ snd-soc-rt5640-objs := rt5640.o snd-soc-rt5645-objs := rt5645.o snd-soc-rt5651-objs := rt5651.o snd-soc-rt5670-objs := rt5670.o -snd-soc-rt5677-objs := rt5677.o rt5677-spi.o +snd-soc-rt5677-objs := rt5677.o +snd-soc-rt5677-spi-objs := rt5677-spi.o snd-soc-sgtl5000-objs := sgtl5000.o snd-soc-alc5623-objs := alc5623.o snd-soc-alc5632-objs := alc5632.o @@ -256,6 +257,7 @@ obj-$(CONFIG_SND_SOC_RT5645) += snd-soc-rt5645.o obj-$(CONFIG_SND_SOC_RT5651) += snd-soc-rt5651.o obj-$(CONFIG_SND_SOC_RT5670) += snd-soc-rt5670.o obj-$(CONFIG_SND_SOC_RT5677) += snd-soc-rt5677.o +obj-$(CONFIG_SND_SOC_RT5677_SPI) += snd-soc-rt5677-spi.o obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o obj-$(CONFIG_SND_SOC_SIGMADSP) += snd-soc-sigmadsp.o obj-$(CONFIG_SND_SOC_SIGMADSP_I2C) += snd-soc-sigmadsp-i2c.o diff --git a/sound/soc/codecs/rt5677-spi.c b/sound/soc/codecs/rt5677-spi.c index 11c38f3a9b72..ef6348cb9157 100644 --- a/sound/soc/codecs/rt5677-spi.c +++ b/sound/soc/codecs/rt5677-spi.c @@ -52,6 +52,7 @@ int rt5677_spi_write(u8 *txbuf, size_t len) return status; } +EXPORT_SYMBOL_GPL(rt5677_spi_write); /** * rt5677_spi_burst_write - Write data to SPI by rt5677 dsp memory address. @@ -107,6 +108,7 @@ int rt5677_spi_burst_write(u32 addr, const struct firmware *fw) return 0; } +EXPORT_SYMBOL_GPL(rt5677_spi_burst_write); static int rt5677_spi_probe(struct spi_device *spi) { -- cgit v1.2.3 From 3f7256fe5fc64132a2dd19695255c990aa2188cf Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Fri, 24 Oct 2014 13:01:25 -0200 Subject: ASoC: sgtl5000: Use the preferred form for passing a size of a struct According to Documentation/CodingStyle - Chapter 14: "The preferred form for passing a size of a struct is the following: p = kmalloc(sizeof(*p), ...); The alternative form where struct name is spelled out hurts readability and introduces an opportunity for a bug when the pointer variable type is changed but the corresponding sizeof that is passed to a memory allocator is not." So do it as recommeded. Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown --- sound/soc/codecs/sgtl5000.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index 59336f6aba80..490404c6b4d8 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -1439,8 +1439,7 @@ static int sgtl5000_i2c_probe(struct i2c_client *client, struct device_node *np = client->dev.of_node; u32 value; - sgtl5000 = devm_kzalloc(&client->dev, sizeof(struct sgtl5000_priv), - GFP_KERNEL); + sgtl5000 = devm_kzalloc(&client->dev, sizeof(*sgtl5000), GFP_KERNEL); if (!sgtl5000) return -ENOMEM; -- cgit v1.2.3 From 54ec2d5f3f751ddcbf07b0fc1e5f01e43015e8e0 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Fri, 24 Oct 2014 13:01:26 -0200 Subject: ASoC: wm8962: Use the preferred form for passing a size of a struct According to Documentation/CodingStyle - Chapter 14: "The preferred form for passing a size of a struct is the following: p = kmalloc(sizeof(*p), ...); The alternative form where struct name is spelled out hurts readability and introduces an opportunity for a bug when the pointer variable type is changed but the corresponding sizeof that is passed to a memory allocator is not." So do it as recommeded. Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown --- sound/soc/codecs/wm8962.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index 9077411e62ce..cfd38917acb8 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -3552,8 +3552,7 @@ static int wm8962_i2c_probe(struct i2c_client *i2c, unsigned int reg; int ret, i, irq_pol, trigger; - wm8962 = devm_kzalloc(&i2c->dev, sizeof(struct wm8962_priv), - GFP_KERNEL); + wm8962 = devm_kzalloc(&i2c->dev, sizeof(*wm8962), GFP_KERNEL); if (wm8962 == NULL) return -ENOMEM; -- cgit v1.2.3 From cea82d8af3986508a05949cfbb6ad8e99ffc15eb Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Fri, 24 Oct 2014 13:01:27 -0200 Subject: ASoC: wm8731: Use the preferred form for passing a size of a struct According to Documentation/CodingStyle - Chapter 14: "The preferred form for passing a size of a struct is the following: p = kmalloc(sizeof(*p), ...); The alternative form where struct name is spelled out hurts readability and introduces an opportunity for a bug when the pointer variable type is changed but the corresponding sizeof that is passed to a memory allocator is not." So do it as recommeded. Cc: Charles Keepax Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown --- sound/soc/codecs/wm8731.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index eebb3280bfad..2c9f2a7005c3 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -680,8 +680,7 @@ static int wm8731_spi_probe(struct spi_device *spi) struct wm8731_priv *wm8731; int ret; - wm8731 = devm_kzalloc(&spi->dev, sizeof(struct wm8731_priv), - GFP_KERNEL); + wm8731 = devm_kzalloc(&spi->dev, sizeof(*wm8731), GFP_KERNEL); if (wm8731 == NULL) return -ENOMEM; -- cgit v1.2.3 From 4e44923847b0b2597eaef07d5e700f5dbed2162e Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Tue, 28 Oct 2014 17:08:40 +0100 Subject: ASoC: cs42l51: make driver user-selectable Since we are removing the Armada 370 DB audio machine driver to use the 'simple-card' Device Tree binding, we can no longer select the CS42L51 codec driver using a Kconfig 'select', and we instead need it to be user-selectable. Therefore, this commit adds a prompt to make the CS42L51 I2C codec driver user-selectable. Signed-off-by: Thomas Petazzoni Acked-by: Brian Austin Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index a68d1731a8fd..f4fb12fab166 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -336,7 +336,7 @@ config SND_SOC_CS42L51 tristate config SND_SOC_CS42L51_I2C - tristate + tristate "Cirrus Logic CS42L51 CODEC (I2C)" select SND_SOC_CS42L51 config SND_SOC_CS42L52 -- cgit v1.2.3 From e6f6ebc1f8f60d6d44f6be22c6386c238d6a9d97 Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Wed, 22 Oct 2014 16:11:39 +0800 Subject: ASoC: rt5677: Add TDM channel mapping function It is for channel to slot mapping, and it is not only for 8 channels mapping, but also in 2, 4 and 6 channels mapping. If we want to use the 2 channels in the stereo2 adc path, we need to set the item "2/1/3/4" or "2/3/1/4". It also adds for stereo channel swap. It can map the sterero channels "L/R" to "R/L", "L/L" or R/R. Signed-off-by: Oder Chiou Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677.c | 239 +++++++++++++++++++++++++++++++++++++++++++--- sound/soc/codecs/rt5677.h | 38 +++++++- 2 files changed, 262 insertions(+), 15 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 413bccbff19e..ca264f885195 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -1834,6 +1834,93 @@ static SOC_ENUM_SINGLE_DECL( static const struct snd_kcontrol_new rt5677_if4_adc_mux = SOC_DAPM_ENUM("IF4 ADC Source", rt5677_if4_adc_enum); +/* TDM IF1/2 ADC Data Selection */ /* MX-3B MX-40 [7:6][5:4][3:2][1:0] */ +static const char * const rt5677_if12_adc_swap_src[] = { + "L/R", "R/L", "L/L", "R/R" +}; + +static SOC_ENUM_SINGLE_DECL( + rt5677_if1_adc1_swap_enum, RT5677_TDM1_CTRL1, + RT5677_IF1_ADC1_SWAP_SFT, rt5677_if12_adc_swap_src); + +static const struct snd_kcontrol_new rt5677_if1_adc1_swap_mux = + SOC_DAPM_ENUM("IF1 ADC1 Swap Source", rt5677_if1_adc1_swap_enum); + +static SOC_ENUM_SINGLE_DECL( + rt5677_if1_adc2_swap_enum, RT5677_TDM1_CTRL1, + RT5677_IF1_ADC2_SWAP_SFT, rt5677_if12_adc_swap_src); + +static const struct snd_kcontrol_new rt5677_if1_adc2_swap_mux = + SOC_DAPM_ENUM("IF1 ADC2 Swap Source", rt5677_if1_adc2_swap_enum); + +static SOC_ENUM_SINGLE_DECL( + rt5677_if1_adc3_swap_enum, RT5677_TDM1_CTRL1, + RT5677_IF1_ADC3_SWAP_SFT, rt5677_if12_adc_swap_src); + +static const struct snd_kcontrol_new rt5677_if1_adc3_swap_mux = + SOC_DAPM_ENUM("IF1 ADC3 Swap Source", rt5677_if1_adc3_swap_enum); + +static SOC_ENUM_SINGLE_DECL( + rt5677_if1_adc4_swap_enum, RT5677_TDM1_CTRL1, + RT5677_IF1_ADC4_SWAP_SFT, rt5677_if12_adc_swap_src); + +static const struct snd_kcontrol_new rt5677_if1_adc4_swap_mux = + SOC_DAPM_ENUM("IF1 ADC4 Swap Source", rt5677_if1_adc4_swap_enum); + +static SOC_ENUM_SINGLE_DECL( + rt5677_if2_adc1_swap_enum, RT5677_TDM2_CTRL1, + RT5677_IF1_ADC2_SWAP_SFT, rt5677_if12_adc_swap_src); + +static const struct snd_kcontrol_new rt5677_if2_adc1_swap_mux = + SOC_DAPM_ENUM("IF1 ADC2 Swap Source", rt5677_if2_adc1_swap_enum); + +static SOC_ENUM_SINGLE_DECL( + rt5677_if2_adc2_swap_enum, RT5677_TDM2_CTRL1, + RT5677_IF2_ADC2_SWAP_SFT, rt5677_if12_adc_swap_src); + +static const struct snd_kcontrol_new rt5677_if2_adc2_swap_mux = + SOC_DAPM_ENUM("IF2 ADC2 Swap Source", rt5677_if2_adc2_swap_enum); + +static SOC_ENUM_SINGLE_DECL( + rt5677_if2_adc3_swap_enum, RT5677_TDM2_CTRL1, + RT5677_IF2_ADC3_SWAP_SFT, rt5677_if12_adc_swap_src); + +static const struct snd_kcontrol_new rt5677_if2_adc3_swap_mux = + SOC_DAPM_ENUM("IF2 ADC3 Swap Source", rt5677_if2_adc3_swap_enum); + +static SOC_ENUM_SINGLE_DECL( + rt5677_if2_adc4_swap_enum, RT5677_TDM2_CTRL1, + RT5677_IF2_ADC4_SWAP_SFT, rt5677_if12_adc_swap_src); + +static const struct snd_kcontrol_new rt5677_if2_adc4_swap_mux = + SOC_DAPM_ENUM("IF2 ADC4 Swap Source", rt5677_if2_adc4_swap_enum); + +/* TDM IF1 ADC Data Selection */ /* MX-3C [2:0] */ +static const char * const rt5677_if1_adc_tdm_swap_src[] = { + "1/2/3/4", "2/1/3/4", "2/3/1/4", "4/1/2/3", "1/3/2/4", "1/4/2/3", + "3/1/2/4", "3/4/1/2" +}; + +static SOC_ENUM_SINGLE_DECL( + rt5677_if1_adc_tdm_swap_enum, RT5677_TDM1_CTRL2, + RT5677_IF1_ADC_CTRL_SFT, rt5677_if1_adc_tdm_swap_src); + +static const struct snd_kcontrol_new rt5677_if1_adc_tdm_swap_mux = + SOC_DAPM_ENUM("IF1 ADC TDM Swap Source", rt5677_if1_adc_tdm_swap_enum); + +/* TDM IF2 ADC Data Selection */ /* MX-41[2:0] */ +static const char * const rt5677_if2_adc_tdm_swap_src[] = { + "1/2/3/4", "2/1/3/4", "3/1/2/4", "4/1/2/3", "1/3/2/4", "1/4/2/3", + "2/3/1/4", "3/4/1/2" +}; + +static SOC_ENUM_SINGLE_DECL( + rt5677_if2_adc_tdm_swap_enum, RT5677_TDM2_CTRL2, + RT5677_IF2_ADC_CTRL_SFT, rt5677_if2_adc_tdm_swap_src); + +static const struct snd_kcontrol_new rt5677_if2_adc_tdm_swap_mux = + SOC_DAPM_ENUM("IF2 ADC TDM Swap Source", rt5677_if2_adc_tdm_swap_enum); + static int rt5677_bst1_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { @@ -1945,6 +2032,52 @@ static int rt5677_set_micbias1_event(struct snd_soc_dapm_widget *w, return 0; } +static int rt5677_if1_adc_tdm_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); + unsigned int value; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + regmap_read(rt5677->regmap, RT5677_TDM1_CTRL2, &value); + if (value & RT5677_IF1_ADC_CTRL_MASK) + regmap_update_bits(rt5677->regmap, RT5677_TDM1_CTRL1, + RT5677_IF1_ADC_MODE_MASK, + RT5677_IF1_ADC_MODE_TDM); + break; + + default: + return 0; + } + + return 0; +} + +static int rt5677_if2_adc_tdm_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); + unsigned int value; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + regmap_read(rt5677->regmap, RT5677_TDM2_CTRL2, &value); + if (value & RT5677_IF2_ADC_CTRL_MASK) + regmap_update_bits(rt5677->regmap, RT5677_TDM2_CTRL1, + RT5677_IF2_ADC_MODE_MASK, + RT5677_IF2_ADC_MODE_TDM); + break; + + default: + return 0; + } + + return 0; +} + static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("PLL1", RT5677_PWR_ANLG2, RT5677_PWR_PLL1_BIT, 0, rt5677_set_pll1_event, SND_SOC_DAPM_POST_PMU), @@ -2104,10 +2237,8 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = { SND_SOC_DAPM_PGA("Stereo4 ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_PGA("Sto2 ADC LR MIX", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_PGA("Mono ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_PGA("IF1_ADC1", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_PGA("IF1_ADC2", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_PGA("IF1_ADC3", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_PGA("IF1_ADC4", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 ADC", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF2 ADC", SND_SOC_NOPM, 0, 0, NULL, 0), /* DSP */ SND_SOC_DAPM_MUX("IB9 Mux", SND_SOC_NOPM, 0, 0, @@ -2230,6 +2361,17 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = { &rt5677_if1_adc3_mux), SND_SOC_DAPM_MUX("IF1 ADC4 Mux", SND_SOC_NOPM, 0, 0, &rt5677_if1_adc4_mux), + SND_SOC_DAPM_MUX("IF1 ADC1 Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5677_if1_adc1_swap_mux), + SND_SOC_DAPM_MUX("IF1 ADC2 Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5677_if1_adc2_swap_mux), + SND_SOC_DAPM_MUX("IF1 ADC3 Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5677_if1_adc3_swap_mux), + SND_SOC_DAPM_MUX("IF1 ADC4 Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5677_if1_adc4_swap_mux), + SND_SOC_DAPM_MUX_E("IF1 ADC TDM Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5677_if1_adc_tdm_swap_mux, rt5677_if1_adc_tdm_event, + SND_SOC_DAPM_PRE_PMU), SND_SOC_DAPM_MUX("IF2 ADC1 Mux", SND_SOC_NOPM, 0, 0, &rt5677_if2_adc1_mux), SND_SOC_DAPM_MUX("IF2 ADC2 Mux", SND_SOC_NOPM, 0, 0, @@ -2238,6 +2380,17 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = { &rt5677_if2_adc3_mux), SND_SOC_DAPM_MUX("IF2 ADC4 Mux", SND_SOC_NOPM, 0, 0, &rt5677_if2_adc4_mux), + SND_SOC_DAPM_MUX("IF2 ADC1 Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5677_if2_adc1_swap_mux), + SND_SOC_DAPM_MUX("IF2 ADC2 Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5677_if2_adc2_swap_mux), + SND_SOC_DAPM_MUX("IF2 ADC3 Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5677_if2_adc3_swap_mux), + SND_SOC_DAPM_MUX("IF2 ADC4 Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5677_if2_adc4_swap_mux), + SND_SOC_DAPM_MUX_E("IF2 ADC TDM Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5677_if2_adc_tdm_swap_mux, rt5677_if2_adc_tdm_event, + SND_SOC_DAPM_PRE_PMU), SND_SOC_DAPM_MUX("IF3 ADC Mux", SND_SOC_NOPM, 0, 0, &rt5677_if3_adc_mux), SND_SOC_DAPM_MUX("IF4 ADC Mux", SND_SOC_NOPM, 0, 0, @@ -2621,11 +2774,42 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { { "IF1 ADC4 Mux", "OB67", "OB67" }, { "IF1 ADC4 Mux", "OB01", "OB01 Bypass Mux" }, + { "IF1 ADC1 Swap Mux", "L/R", "IF1 ADC1 Mux" }, + { "IF1 ADC1 Swap Mux", "R/L", "IF1 ADC1 Mux" }, + { "IF1 ADC1 Swap Mux", "L/L", "IF1 ADC1 Mux" }, + { "IF1 ADC1 Swap Mux", "R/R", "IF1 ADC1 Mux" }, + + { "IF1 ADC2 Swap Mux", "L/R", "IF1 ADC2 Mux" }, + { "IF1 ADC2 Swap Mux", "R/L", "IF1 ADC2 Mux" }, + { "IF1 ADC2 Swap Mux", "L/L", "IF1 ADC2 Mux" }, + { "IF1 ADC2 Swap Mux", "R/R", "IF1 ADC2 Mux" }, + + { "IF1 ADC3 Swap Mux", "L/R", "IF1 ADC3 Mux" }, + { "IF1 ADC3 Swap Mux", "R/L", "IF1 ADC3 Mux" }, + { "IF1 ADC3 Swap Mux", "L/L", "IF1 ADC3 Mux" }, + { "IF1 ADC3 Swap Mux", "R/R", "IF1 ADC3 Mux" }, + + { "IF1 ADC4 Swap Mux", "L/R", "IF1 ADC4 Mux" }, + { "IF1 ADC4 Swap Mux", "R/L", "IF1 ADC4 Mux" }, + { "IF1 ADC4 Swap Mux", "L/L", "IF1 ADC4 Mux" }, + { "IF1 ADC4 Swap Mux", "R/R", "IF1 ADC4 Mux" }, + + { "IF1 ADC", NULL, "IF1 ADC1 Swap Mux" }, + { "IF1 ADC", NULL, "IF1 ADC2 Swap Mux" }, + { "IF1 ADC", NULL, "IF1 ADC3 Swap Mux" }, + { "IF1 ADC", NULL, "IF1 ADC4 Swap Mux" }, + + { "IF1 ADC TDM Swap Mux", "1/2/3/4", "IF1 ADC" }, + { "IF1 ADC TDM Swap Mux", "2/1/3/4", "IF1 ADC" }, + { "IF1 ADC TDM Swap Mux", "2/3/1/4", "IF1 ADC" }, + { "IF1 ADC TDM Swap Mux", "4/1/2/3", "IF1 ADC" }, + { "IF1 ADC TDM Swap Mux", "1/3/2/4", "IF1 ADC" }, + { "IF1 ADC TDM Swap Mux", "1/4/2/3", "IF1 ADC" }, + { "IF1 ADC TDM Swap Mux", "3/1/2/4", "IF1 ADC" }, + { "IF1 ADC TDM Swap Mux", "3/4/1/2", "IF1 ADC" }, + { "AIF1TX", NULL, "I2S1" }, - { "AIF1TX", NULL, "IF1 ADC1 Mux" }, - { "AIF1TX", NULL, "IF1 ADC2 Mux" }, - { "AIF1TX", NULL, "IF1 ADC3 Mux" }, - { "AIF1TX", NULL, "IF1 ADC4 Mux" }, + { "AIF1TX", NULL, "IF1 ADC TDM Swap Mux" }, { "IF2 ADC1 Mux", "STO1 ADC MIX", "Stereo1 ADC MIX" }, { "IF2 ADC1 Mux", "OB01", "OB01 Bypass Mux" }, @@ -2642,11 +2826,42 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { { "IF2 ADC4 Mux", "OB67", "OB67" }, { "IF2 ADC4 Mux", "OB01", "OB01 Bypass Mux" }, + { "IF2 ADC1 Swap Mux", "L/R", "IF2 ADC1 Mux" }, + { "IF2 ADC1 Swap Mux", "R/L", "IF2 ADC1 Mux" }, + { "IF2 ADC1 Swap Mux", "L/L", "IF2 ADC1 Mux" }, + { "IF2 ADC1 Swap Mux", "R/R", "IF2 ADC1 Mux" }, + + { "IF2 ADC2 Swap Mux", "L/R", "IF2 ADC2 Mux" }, + { "IF2 ADC2 Swap Mux", "R/L", "IF2 ADC2 Mux" }, + { "IF2 ADC2 Swap Mux", "L/L", "IF2 ADC2 Mux" }, + { "IF2 ADC2 Swap Mux", "R/R", "IF2 ADC2 Mux" }, + + { "IF2 ADC3 Swap Mux", "L/R", "IF2 ADC3 Mux" }, + { "IF2 ADC3 Swap Mux", "R/L", "IF2 ADC3 Mux" }, + { "IF2 ADC3 Swap Mux", "L/L", "IF2 ADC3 Mux" }, + { "IF2 ADC3 Swap Mux", "R/R", "IF2 ADC3 Mux" }, + + { "IF2 ADC4 Swap Mux", "L/R", "IF2 ADC4 Mux" }, + { "IF2 ADC4 Swap Mux", "R/L", "IF2 ADC4 Mux" }, + { "IF2 ADC4 Swap Mux", "L/L", "IF2 ADC4 Mux" }, + { "IF2 ADC4 Swap Mux", "R/R", "IF2 ADC4 Mux" }, + + { "IF2 ADC", NULL, "IF2 ADC1 Swap Mux" }, + { "IF2 ADC", NULL, "IF2 ADC2 Swap Mux" }, + { "IF2 ADC", NULL, "IF2 ADC3 Swap Mux" }, + { "IF2 ADC", NULL, "IF2 ADC4 Swap Mux" }, + + { "IF2 ADC TDM Swap Mux", "1/2/3/4", "IF2 ADC" }, + { "IF2 ADC TDM Swap Mux", "2/1/3/4", "IF2 ADC" }, + { "IF2 ADC TDM Swap Mux", "3/1/2/4", "IF2 ADC" }, + { "IF2 ADC TDM Swap Mux", "4/1/2/3", "IF2 ADC" }, + { "IF2 ADC TDM Swap Mux", "1/3/2/4", "IF2 ADC" }, + { "IF2 ADC TDM Swap Mux", "1/4/2/3", "IF2 ADC" }, + { "IF2 ADC TDM Swap Mux", "2/3/1/4", "IF2 ADC" }, + { "IF2 ADC TDM Swap Mux", "3/4/1/2", "IF2 ADC" }, + { "AIF2TX", NULL, "I2S2" }, - { "AIF2TX", NULL, "IF2 ADC1 Mux" }, - { "AIF2TX", NULL, "IF2 ADC2 Mux" }, - { "AIF2TX", NULL, "IF2 ADC3 Mux" }, - { "AIF2TX", NULL, "IF2 ADC4 Mux" }, + { "AIF2TX", NULL, "IF2 ADC TDM Swap Mux" }, { "IF3 ADC Mux", "STO1 ADC MIX", "Stereo1 ADC MIX" }, { "IF3 ADC Mux", "STO2 ADC MIX", "Stereo2 ADC MIX" }, diff --git a/sound/soc/codecs/rt5677.h b/sound/soc/codecs/rt5677.h index d2c743c255a1..2f5b8c6c279e 100644 --- a/sound/soc/codecs/rt5677.h +++ b/sound/soc/codecs/rt5677.h @@ -799,7 +799,21 @@ #define RT5677_PDM2_I2C_EXE (0x1 << 1) #define RT5677_PDM2_I2C_BUSY (0x1 << 0) -/* MX3C TDM1 control 1 (0x3c) */ +/* MX3B TDM1 control 1 (0x3b) */ +#define RT5677_IF1_ADC_MODE_MASK (0x1 << 12) +#define RT5677_IF1_ADC_MODE_SFT 12 +#define RT5677_IF1_ADC_MODE_I2S (0x0 << 12) +#define RT5677_IF1_ADC_MODE_TDM (0x1 << 12) +#define RT5677_IF1_ADC1_SWAP_MASK (0x3 << 6) +#define RT5677_IF1_ADC1_SWAP_SFT 6 +#define RT5677_IF1_ADC2_SWAP_MASK (0x3 << 4) +#define RT5677_IF1_ADC2_SWAP_SFT 4 +#define RT5677_IF1_ADC3_SWAP_MASK (0x3 << 2) +#define RT5677_IF1_ADC3_SWAP_SFT 2 +#define RT5677_IF1_ADC4_SWAP_MASK (0x3 << 0) +#define RT5677_IF1_ADC4_SWAP_SFT 0 + +/* MX3C TDM1 control 2 (0x3c) */ #define RT5677_IF1_ADC4_MASK (0x3 << 10) #define RT5677_IF1_ADC4_SFT 10 #define RT5677_IF1_ADC3_MASK (0x3 << 8) @@ -808,8 +822,24 @@ #define RT5677_IF1_ADC2_SFT 6 #define RT5677_IF1_ADC1_MASK (0x3 << 4) #define RT5677_IF1_ADC1_SFT 4 - -/* MX41 TDM2 control 1 (0x41) */ +#define RT5677_IF1_ADC_CTRL_MASK (0x7 << 0) +#define RT5677_IF1_ADC_CTRL_SFT 0 + +/* MX40 TDM2 control 1 (0x40) */ +#define RT5677_IF2_ADC_MODE_MASK (0x1 << 12) +#define RT5677_IF2_ADC_MODE_SFT 12 +#define RT5677_IF2_ADC_MODE_I2S (0x0 << 12) +#define RT5677_IF2_ADC_MODE_TDM (0x1 << 12) +#define RT5677_IF2_ADC1_SWAP_MASK (0x3 << 6) +#define RT5677_IF2_ADC1_SWAP_SFT 6 +#define RT5677_IF2_ADC2_SWAP_MASK (0x3 << 4) +#define RT5677_IF2_ADC2_SWAP_SFT 4 +#define RT5677_IF2_ADC3_SWAP_MASK (0x3 << 2) +#define RT5677_IF2_ADC3_SWAP_SFT 2 +#define RT5677_IF2_ADC4_SWAP_MASK (0x3 << 0) +#define RT5677_IF2_ADC4_SWAP_SFT 0 + +/* MX41 TDM2 control 2 (0x41) */ #define RT5677_IF2_ADC4_MASK (0x3 << 10) #define RT5677_IF2_ADC4_SFT 10 #define RT5677_IF2_ADC3_MASK (0x3 << 8) @@ -818,6 +848,8 @@ #define RT5677_IF2_ADC2_SFT 6 #define RT5677_IF2_ADC1_MASK (0x3 << 4) #define RT5677_IF2_ADC1_SFT 4 +#define RT5677_IF2_ADC_CTRL_MASK (0x7 << 0) +#define RT5677_IF2_ADC_CTRL_SFT 0 /* Digital Microphone Control 1 (0x50) */ #define RT5677_DMIC_1_EN_MASK (0x1 << 15) -- cgit v1.2.3 From 6879db7648b6b995122afa98df31778c7af0855d Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Fri, 31 Oct 2014 14:52:16 +0800 Subject: ASoC: rt286: reduce power consumption This patch will optimize the power consumption of rt286. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt286.c | 211 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 155 insertions(+), 56 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c index 4aa555cbcca8..97daa80e9104 100644 --- a/sound/soc/codecs/rt286.c +++ b/sound/soc/codecs/rt286.c @@ -36,11 +36,13 @@ struct rt286_priv { struct regmap *regmap; + struct snd_soc_codec *codec; struct rt286_platform_data pdata; struct i2c_client *i2c; struct snd_soc_jack *jack; struct delayed_work jack_detect_work; int sys_clk; + int clk_id; struct reg_default *index_cache; }; @@ -298,7 +300,6 @@ static int rt286_support_power_controls[] = { static int rt286_jack_detect(struct rt286_priv *rt286, bool *hp, bool *mic) { unsigned int val, buf; - int i; *hp = false; *mic = false; @@ -309,67 +310,44 @@ static int rt286_jack_detect(struct rt286_priv *rt286, bool *hp, bool *mic) if (*hp) { /* power on HV,VERF */ regmap_update_bits(rt286->regmap, - RT286_POWER_CTRL1, 0x1001, 0x0); + RT286_DC_GAIN, 0x200, 0x200); + + snd_soc_dapm_force_enable_pin(&rt286->codec->dapm, + "HV"); + snd_soc_dapm_force_enable_pin(&rt286->codec->dapm, + "VREF"); /* power LDO1 */ - regmap_update_bits(rt286->regmap, - RT286_POWER_CTRL2, 0x4, 0x4); - regmap_write(rt286->regmap, RT286_SET_MIC1, 0x24); - regmap_read(rt286->regmap, RT286_CBJ_CTRL2, &val); + snd_soc_dapm_force_enable_pin(&rt286->codec->dapm, + "LDO1"); + snd_soc_dapm_sync(&rt286->codec->dapm); - msleep(200); - i = 40; - while (((val & 0x0800) == 0) && (i > 0)) { - regmap_read(rt286->regmap, - RT286_CBJ_CTRL2, &val); - i--; - msleep(20); - } + regmap_write(rt286->regmap, RT286_SET_MIC1, 0x24); + msleep(50); - if (0x0400 == (val & 0x0700)) { - *mic = false; + regmap_update_bits(rt286->regmap, + RT286_CBJ_CTRL1, 0xfcc0, 0xd400); + msleep(300); + regmap_read(rt286->regmap, RT286_CBJ_CTRL2, &val); - regmap_write(rt286->regmap, - RT286_SET_MIC1, 0x20); - /* power off HV,VERF */ - regmap_update_bits(rt286->regmap, - RT286_POWER_CTRL1, 0x1001, 0x1001); - regmap_update_bits(rt286->regmap, - RT286_A_BIAS_CTRL3, 0xc000, 0x0000); - regmap_update_bits(rt286->regmap, - RT286_CBJ_CTRL1, 0x0030, 0x0000); - regmap_update_bits(rt286->regmap, - RT286_A_BIAS_CTRL2, 0xc000, 0x0000); - } else if ((0x0200 == (val & 0x0700)) || - (0x0100 == (val & 0x0700))) { + if (0x0070 == (val & 0x0070)) { *mic = true; - regmap_update_bits(rt286->regmap, - RT286_A_BIAS_CTRL3, 0xc000, 0x8000); - regmap_update_bits(rt286->regmap, - RT286_CBJ_CTRL1, 0x0030, 0x0020); - regmap_update_bits(rt286->regmap, - RT286_A_BIAS_CTRL2, 0xc000, 0x8000); } else { - *mic = false; + regmap_update_bits(rt286->regmap, + RT286_CBJ_CTRL1, 0xfcc0, 0xe400); + msleep(300); + regmap_read(rt286->regmap, + RT286_CBJ_CTRL2, &val); + if (0x0070 == (val & 0x0070)) + *mic = true; + else + *mic = false; } - - regmap_update_bits(rt286->regmap, - RT286_MISC_CTRL1, - 0x0060, 0x0000); - } else { - regmap_update_bits(rt286->regmap, - RT286_MISC_CTRL1, - 0x0060, 0x0020); - regmap_update_bits(rt286->regmap, - RT286_A_BIAS_CTRL3, - 0xc000, 0x8000); regmap_update_bits(rt286->regmap, - RT286_CBJ_CTRL1, - 0x0030, 0x0020); - regmap_update_bits(rt286->regmap, - RT286_A_BIAS_CTRL2, - 0xc000, 0x8000); + RT286_DC_GAIN, 0x200, 0x0); + } else { *mic = false; + regmap_write(rt286->regmap, RT286_SET_MIC1, 0x20); } } else { regmap_read(rt286->regmap, RT286_GET_HP_SENSE, &buf); @@ -378,6 +356,12 @@ static int rt286_jack_detect(struct rt286_priv *rt286, bool *hp, bool *mic) *mic = buf & 0x80000000; } + snd_soc_dapm_disable_pin(&rt286->codec->dapm, "HV"); + snd_soc_dapm_disable_pin(&rt286->codec->dapm, "VREF"); + if (!*hp) + snd_soc_dapm_disable_pin(&rt286->codec->dapm, "LDO1"); + snd_soc_dapm_sync(&rt286->codec->dapm); + return 0; } @@ -415,6 +399,17 @@ int rt286_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack) } EXPORT_SYMBOL_GPL(rt286_mic_detect); +static int is_mclk_mode(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(source->codec); + + if (rt286->clk_id == RT286_SCLK_S_MCLK) + return 1; + else + return 0; +} + static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -6350, 50, 0); static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 1000, 0); @@ -568,7 +563,84 @@ static int rt286_adc_event(struct snd_soc_dapm_widget *w, return 0; } +static int rt286_vref_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_update_bits(codec, + RT286_CBJ_CTRL1, 0x0400, 0x0000); + mdelay(50); + break; + default: + return 0; + } + + return 0; +} + +static int rt286_ldo2_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + snd_soc_update_bits(codec, RT286_POWER_CTRL2, 0x38, 0x08); + break; + case SND_SOC_DAPM_PRE_PMD: + snd_soc_update_bits(codec, RT286_POWER_CTRL2, 0x38, 0x30); + break; + default: + return 0; + } + + return 0; +} + +static int rt286_mic1_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_update_bits(codec, + RT286_A_BIAS_CTRL3, 0xc000, 0x8000); + snd_soc_update_bits(codec, + RT286_A_BIAS_CTRL2, 0xc000, 0x8000); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_update_bits(codec, + RT286_A_BIAS_CTRL3, 0xc000, 0x0000); + snd_soc_update_bits(codec, + RT286_A_BIAS_CTRL2, 0xc000, 0x0000); + break; + default: + return 0; + } + + return 0; +} + static const struct snd_soc_dapm_widget rt286_dapm_widgets[] = { + SND_SOC_DAPM_SUPPLY_S("HV", 1, RT286_POWER_CTRL1, + 12, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("VREF", RT286_POWER_CTRL1, + 0, 1, rt286_vref_event, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_SUPPLY_S("LDO1", 1, RT286_POWER_CTRL2, + 2, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("LDO2", 2, RT286_POWER_CTRL1, + 13, 1, rt286_ldo2_event, SND_SOC_DAPM_PRE_PMD | + SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_SUPPLY("MCLK MODE", RT286_PLL_CTRL1, + 5, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("MIC1 Input Buffer", SND_SOC_NOPM, + 0, 0, rt286_mic1_event, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + /* Input Lines */ SND_SOC_DAPM_INPUT("DMIC1 Pin"), SND_SOC_DAPM_INPUT("DMIC2 Pin"), @@ -642,6 +714,25 @@ static const struct snd_soc_dapm_widget rt286_dapm_widgets[] = { }; static const struct snd_soc_dapm_route rt286_dapm_routes[] = { + {"ADC 0", NULL, "MCLK MODE", is_mclk_mode}, + {"ADC 1", NULL, "MCLK MODE", is_mclk_mode}, + {"Front", NULL, "MCLK MODE", is_mclk_mode}, + {"Surround", NULL, "MCLK MODE", is_mclk_mode}, + + {"HP Power", NULL, "LDO1"}, + {"HP Power", NULL, "LDO2"}, + + {"MIC1", NULL, "LDO1"}, + {"MIC1", NULL, "LDO2"}, + {"MIC1", NULL, "HV"}, + {"MIC1", NULL, "VREF"}, + {"MIC1", NULL, "MIC1 Input Buffer"}, + + {"SPO", NULL, "LDO1"}, + {"SPO", NULL, "LDO2"}, + {"SPO", NULL, "HV"}, + {"SPO", NULL, "VREF"}, + {"DMIC1", NULL, "DMIC1 Pin"}, {"DMIC2", NULL, "DMIC2 Pin"}, {"DMIC1", NULL, "DMIC Receiver"}, @@ -880,6 +971,7 @@ static int rt286_set_dai_sysclk(struct snd_soc_dai *dai, } rt286->sys_clk = freq; + rt286->clk_id = clk_id; return 0; } @@ -915,13 +1007,18 @@ static int rt286_set_bias_level(struct snd_soc_codec *codec, case SND_SOC_BIAS_ON: mdelay(10); + snd_soc_update_bits(codec, + RT286_CBJ_CTRL1, 0x0400, 0x0400); + snd_soc_update_bits(codec, + RT286_DC_GAIN, 0x200, 0x0); + break; case SND_SOC_BIAS_STANDBY: snd_soc_write(codec, RT286_SET_AUDIO_POWER, AC_PWRST_D3); snd_soc_update_bits(codec, - RT286_DC_GAIN, 0x200, 0x0); + RT286_CBJ_CTRL1, 0x0400, 0x0000); break; default: @@ -962,6 +1059,7 @@ static int rt286_probe(struct snd_soc_codec *codec) { struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec); + rt286->codec = codec; codec->dapm.bias_level = SND_SOC_BIAS_OFF; if (rt286->i2c->irq) { @@ -1152,7 +1250,6 @@ static int rt286_i2c_probe(struct i2c_client *i2c, if (!rt286->pdata.cbj_en) { regmap_write(rt286->regmap, RT286_CBJ_CTRL2, 0x0000); regmap_write(rt286->regmap, RT286_MIC1_DET_CTRL, 0x0816); - regmap_write(rt286->regmap, RT286_MISC_CTRL1, 0x0000); regmap_update_bits(rt286->regmap, RT286_CBJ_CTRL1, 0xf000, 0xb000); } else { @@ -1169,8 +1266,10 @@ static int rt286_i2c_probe(struct i2c_client *i2c, mdelay(10); - /*Power down LDO2*/ - regmap_update_bits(rt286->regmap, RT286_POWER_CTRL2, 0x8, 0x0); + regmap_write(rt286->regmap, RT286_MISC_CTRL1, 0x0000); + /*Power down LDO, VREF*/ + regmap_update_bits(rt286->regmap, RT286_POWER_CTRL2, 0xc, 0x0); + regmap_update_bits(rt286->regmap, RT286_POWER_CTRL1, 0x1001, 0x1001); /*Set depop parameter*/ regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL2, 0x403a, 0x401a); -- cgit v1.2.3 From d004ebbef7292848f5f7ecae50824c04780baaac Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Wed, 29 Oct 2014 16:25:38 +0300 Subject: ASoC: tlv320aic23: make codecs selectable in Kconfig Now that manual selection of drivers for audio subsystem components is preferred AIC23 codec must be selectable in Kconfig to make it possible. Signed-off-by: Max Filippov Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index a68d1731a8fd..7881b3c35b4d 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -581,11 +581,11 @@ config SND_SOC_TLV320AIC23 tristate config SND_SOC_TLV320AIC23_I2C - tristate + tristate "Texas Instruments TLV320AIC23 audio CODEC - I2C" select SND_SOC_TLV320AIC23 config SND_SOC_TLV320AIC23_SPI - tristate + tristate "Texas Instruments TLV320AIC23 audio CODEC - SPI" select SND_SOC_TLV320AIC23 config SND_SOC_TLV320AIC26 -- cgit v1.2.3 From 16af0ee16ca9391ef82e1c74c362d80551e769fe Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 30 Oct 2014 21:00:58 +0100 Subject: ASoC: ad1980: Remove unused header The constants defined in the ad1980 header are not used. So remove the file. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/blackfin/bf5xx-ad1980.c | 2 -- sound/soc/codecs/ad1980.c | 2 -- sound/soc/codecs/ad1980.h | 26 -------------------------- 3 files changed, 30 deletions(-) delete mode 100644 sound/soc/codecs/ad1980.h (limited to 'sound/soc/codecs') diff --git a/sound/soc/blackfin/bf5xx-ad1980.c b/sound/soc/blackfin/bf5xx-ad1980.c index 3450e8f9080d..0fa81a523b8a 100644 --- a/sound/soc/blackfin/bf5xx-ad1980.c +++ b/sound/soc/blackfin/bf5xx-ad1980.c @@ -46,8 +46,6 @@ #include #include -#include "../codecs/ad1980.h" - #include "bf5xx-ac97.h" static struct snd_soc_card bf5xx_board; diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c index 304d3003339a..cc28dbae8315 100644 --- a/sound/soc/codecs/ad1980.c +++ b/sound/soc/codecs/ad1980.c @@ -30,8 +30,6 @@ #include #include -#include "ad1980.h" - /* * AD1980 register cache */ diff --git a/sound/soc/codecs/ad1980.h b/sound/soc/codecs/ad1980.h deleted file mode 100644 index eb0af44ad3df..000000000000 --- a/sound/soc/codecs/ad1980.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * ad1980.h -- ad1980 Soc Audio driver - * - * WARNING: - * - * Because Analog Devices Inc. discontinued the ad1980 sound chip since - * Sep. 2009, this ad1980 driver is not maintained, tested and supported - * by ADI now. - */ - -#ifndef _AD1980_H -#define _AD1980_H -/* Bit definition of Power-Down Control/Status Register */ -#define ADC 0x0001 -#define DAC 0x0002 -#define ANL 0x0004 -#define REF 0x0008 -#define PR0 0x0100 -#define PR1 0x0200 -#define PR2 0x0400 -#define PR3 0x0800 -#define PR4 0x1000 -#define PR5 0x2000 -#define PR6 0x4000 - -#endif -- cgit v1.2.3 From e5adb6cddb17f8e76be404f23a2e0db102ee1bd1 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 30 Oct 2014 21:00:59 +0100 Subject: ASoC: ad1980: Cleanup printk usage Use dev_err()/dev_warn() instead of printk(KERN_ERR/KERN_WARNING. This is common practice and makes it easy to find out which device generated the message. While we are at it also align the error messages with the other AC'97 drivers. Also remove the info message that is printed when the driver is probed, this is just noise in bootlog. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/ad1980.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c index cc28dbae8315..5f076c24d062 100644 --- a/sound/soc/codecs/ad1980.c +++ b/sound/soc/codecs/ad1980.c @@ -209,7 +209,8 @@ static int ad1980_reset(struct snd_soc_codec *codec, int try_warm) return 0; } while (retry_cnt++ < 10); - printk(KERN_ERR "AD1980 AC97 reset failed\n"); + dev_err(codec->dev, "Failed to reset: AC97 link error\n"); + return -EIO; } @@ -219,19 +220,15 @@ static int ad1980_soc_probe(struct snd_soc_codec *codec) u16 vendor_id2; u16 ext_status; - printk(KERN_INFO "AD1980 SoC Audio Codec\n"); - ret = snd_soc_new_ac97_codec(codec, soc_ac97_ops, 0); if (ret < 0) { - printk(KERN_ERR "ad1980: failed to register AC97 codec\n"); + dev_err(codec->dev, "Failed to register AC97 codec\n"); return ret; } ret = ad1980_reset(codec, 0); - if (ret < 0) { - printk(KERN_ERR "Failed to reset AD1980: AC97 link error\n"); + if (ret < 0) goto reset_err; - } /* Read out vendor ID to make sure it is ad1980 */ if (ac97_read(codec, AC97_VENDOR_ID1) != 0x4144) { @@ -246,9 +243,8 @@ static int ad1980_soc_probe(struct snd_soc_codec *codec) ret = -ENODEV; goto reset_err; } else { - printk(KERN_WARNING "ad1980: " - "Found AD1981 - only 2/2 IN/OUT Channels " - "supported\n"); + dev_warn(codec->dev, + "Found AD1981 - only 2/2 IN/OUT Channels supported\n"); } } -- cgit v1.2.3 From 6ce13d61dc6cfc3cf6be6bd12faf75bfbc12ea91 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 30 Oct 2014 21:01:00 +0100 Subject: ASoC: ad1980: Use table based control setup Makes the code a bit cleaner. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/ad1980.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c index 5f076c24d062..9ed4e12c26d1 100644 --- a/sound/soc/codecs/ad1980.c +++ b/sound/soc/codecs/ad1980.c @@ -259,9 +259,6 @@ static int ad1980_soc_probe(struct snd_soc_codec *codec) ext_status = ac97_read(codec, AC97_EXTENDED_STATUS); ac97_write(codec, AC97_EXTENDED_STATUS, ext_status&~0x3800); - snd_soc_add_codec_controls(codec, ad1980_snd_ac97_controls, - ARRAY_SIZE(ad1980_snd_ac97_controls)); - return 0; reset_err: @@ -285,6 +282,8 @@ static struct snd_soc_codec_driver soc_codec_dev_ad1980 = { .write = ac97_write, .read = ac97_read, + .controls = ad1980_snd_ac97_controls, + .num_controls = ARRAY_SIZE(ad1980_snd_ac97_controls), .dapm_widgets = ad1980_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(ad1980_dapm_widgets), .dapm_routes = ad1980_dapm_routes, -- cgit v1.2.3 From 93932abaa3c84c2d76ce713bbbad08bad9162483 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 30 Oct 2014 21:01:01 +0100 Subject: ASoC: stac9766: Cleanup printk usage Use dev_err() instead of printk(KERN_ERR. This is common practice and makes it easy to find out which device generated the message. While we are at it also align the error messages with the other AC'97 drivers. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/stac9766.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c index 9878534ccd16..e88d9ac9cbab 100644 --- a/sound/soc/codecs/stac9766.c +++ b/sound/soc/codecs/stac9766.c @@ -262,7 +262,7 @@ static int stac9766_codec_resume(struct snd_soc_codec *codec) /* give the codec an AC97 warm reset to start the link */ reset: if (reset > 5) { - printk(KERN_ERR "stac9766 failed to resume"); + dev_err(codec->dev, "Failed to resume\n"); return -EIO; } codec->ac97->bus->ops->warm_reset(codec->ac97); @@ -338,7 +338,7 @@ static int stac9766_codec_probe(struct snd_soc_codec *codec) stac9766_reset(codec, 0); ret = stac9766_reset(codec, 1); if (ret < 0) { - printk(KERN_ERR "Failed to reset STAC9766: AC97 link error\n"); + dev_err(codec->dev, "Failed to reset: AC97 link error\n"); goto codec_err; } -- cgit v1.2.3 From 8865051d9941de905432f59f7a88662e824d5df9 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 30 Oct 2014 21:01:02 +0100 Subject: ASoC: stac9766: Use table based control setup Makes the code a bit cleaner. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/stac9766.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c index e88d9ac9cbab..6c62d291cde7 100644 --- a/sound/soc/codecs/stac9766.c +++ b/sound/soc/codecs/stac9766.c @@ -342,9 +342,6 @@ static int stac9766_codec_probe(struct snd_soc_codec *codec) goto codec_err; } - snd_soc_add_codec_controls(codec, stac9766_snd_ac97_controls, - ARRAY_SIZE(stac9766_snd_ac97_controls)); - return 0; codec_err: @@ -359,6 +356,8 @@ static int stac9766_codec_remove(struct snd_soc_codec *codec) } static struct snd_soc_codec_driver soc_codec_dev_stac9766 = { + .controls = stac9766_snd_ac97_controls, + .num_controls = ARRAY_SIZE(stac9766_snd_ac97_controls), .write = stac9766_ac97_write, .read = stac9766_ac97_read, .set_bias_level = stac9766_set_bias_level, -- cgit v1.2.3 From 9cf766f666cc4518e22f185159f285f4e3183230 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 30 Oct 2014 21:01:03 +0100 Subject: ASoC: wm9705: Cleanup printk usage Use dev_err() instead of printk(KERN_ERR. This is common practice and makes it easy to find out which device generated the message. While we are at it also align the error messages with the other AC'97 drivers. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm9705.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c index c0b7f45dfa37..355b28dd6ac9 100644 --- a/sound/soc/codecs/wm9705.c +++ b/sound/soc/codecs/wm9705.c @@ -300,6 +300,8 @@ static int wm9705_reset(struct snd_soc_codec *codec) return 0; /* Success */ } + dev_err(codec->dev, "Failed to reset: AC97 link error\n"); + return -EIO; } @@ -317,10 +319,8 @@ static int wm9705_soc_resume(struct snd_soc_codec *codec) u16 *cache = codec->reg_cache; ret = wm9705_reset(codec); - if (ret < 0) { - printk(KERN_ERR "could not reset AC97 codec\n"); + if (ret < 0) return ret; - } for (i = 2; i < ARRAY_SIZE(wm9705_reg) << 1; i += 2) { soc_ac97_ops->write(codec->ac97, i, cache[i>>1]); @@ -339,7 +339,7 @@ static int wm9705_soc_probe(struct snd_soc_codec *codec) ret = snd_soc_new_ac97_codec(codec, soc_ac97_ops, 0); if (ret < 0) { - printk(KERN_ERR "wm9705: failed to register AC97 codec\n"); + dev_err(codec->dev, "Failed to register AC97 codec\n"); return ret; } -- cgit v1.2.3 From d7cabb08ba23c87757fb3be01e82f755aad426d1 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 30 Oct 2014 21:01:04 +0100 Subject: ASoC: wm9705: Use table based control setup Makes the code a bit cleaner. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm9705.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c index 355b28dd6ac9..1650195f6c84 100644 --- a/sound/soc/codecs/wm9705.c +++ b/sound/soc/codecs/wm9705.c @@ -347,9 +347,6 @@ static int wm9705_soc_probe(struct snd_soc_codec *codec) if (ret) goto reset_err; - snd_soc_add_codec_controls(codec, wm9705_snd_ac97_controls, - ARRAY_SIZE(wm9705_snd_ac97_controls)); - return 0; reset_err: @@ -374,6 +371,9 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9705 = { .reg_word_size = sizeof(u16), .reg_cache_step = 2, .reg_cache_default = wm9705_reg, + + .controls = wm9705_snd_ac97_controls, + .num_controls = ARRAY_SIZE(wm9705_snd_ac97_controls), .dapm_widgets = wm9705_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(wm9705_dapm_widgets), .dapm_routes = wm9705_audio_map, -- cgit v1.2.3 From 12ced338ab8858d11ef5b11b65c3dc612d9551c9 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 30 Oct 2014 21:01:05 +0100 Subject: ASoC: wm9712: Cleanup printk usage Use dev_err() instead of printk(KERN_ERR. This is common practice and makes it easy to find out which device generated the message. While we are at it also align the error messages with the other AC'97 drivers. Also avoid printing two error messages when the reset fails. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm9712.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index c5eb746087b4..c389e5607ab6 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -595,7 +595,7 @@ static int wm9712_reset(struct snd_soc_codec *codec, int try_warm) return 0; err: - printk(KERN_ERR "WM9712 AC97 reset failed\n"); + dev_err(codec->dev, "Failed to reset: AC97 link error\n"); return -EIO; } @@ -611,10 +611,8 @@ static int wm9712_soc_resume(struct snd_soc_codec *codec) u16 *cache = codec->reg_cache; ret = wm9712_reset(codec, 1); - if (ret < 0) { - printk(KERN_ERR "could not reset AC97 codec\n"); + if (ret < 0) return ret; - } wm9712_set_bias_level(codec, SND_SOC_BIAS_STANDBY); @@ -637,15 +635,13 @@ static int wm9712_soc_probe(struct snd_soc_codec *codec) ret = snd_soc_new_ac97_codec(codec, soc_ac97_ops, 0); if (ret < 0) { - printk(KERN_ERR "wm9712: failed to register AC97 codec\n"); + dev_err(codec->dev, "Failed to register AC97 codec\n"); return ret; } ret = wm9712_reset(codec, 0); - if (ret < 0) { - printk(KERN_ERR "Failed to reset WM9712: AC97 link error\n"); + if (ret < 0) goto reset_err; - } /* set alc mux to none */ ac97_write(codec, AC97_VIDEO, ac97_read(codec, AC97_VIDEO) | 0x3000); -- cgit v1.2.3 From 9a812c6b7a2092e20b4b78ed0ec6614a89e96dfd Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 30 Oct 2014 21:01:06 +0100 Subject: ASoC: wm9712: Use table based control setup Makes the code a bit cleaner. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm9712.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index c389e5607ab6..f3aab6e1d92a 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -647,8 +647,6 @@ static int wm9712_soc_probe(struct snd_soc_codec *codec) ac97_write(codec, AC97_VIDEO, ac97_read(codec, AC97_VIDEO) | 0x3000); wm9712_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - snd_soc_add_codec_controls(codec, wm9712_snd_ac97_controls, - ARRAY_SIZE(wm9712_snd_ac97_controls)); return 0; @@ -675,6 +673,9 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9712 = { .reg_word_size = sizeof(u16), .reg_cache_step = 2, .reg_cache_default = wm9712_reg, + + .controls = wm9712_snd_ac97_controls, + .num_controls = ARRAY_SIZE(wm9712_snd_ac97_controls), .dapm_widgets = wm9712_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(wm9712_dapm_widgets), .dapm_routes = wm9712_audio_map, -- cgit v1.2.3 From a6c2b07f11beaf5719f03c70a9c9597534b297a5 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 30 Oct 2014 21:01:07 +0100 Subject: ASoC: wm9713: Cleanup printk usage Use dev_err()/dev_warn() instead of printk(KERN_ERR/KERN_WARNING. This is common practice and makes it easy to find out which device generated the message. While we are at it also align the error messages with the other AC'97 drivers. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm9713.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index bddee30a4bc7..38e17d45cfef 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -689,7 +689,8 @@ struct _pll_div { * to allow rounding later */ #define FIXED_PLL_SIZE ((1 << 22) * 10) -static void pll_factors(struct _pll_div *pll_div, unsigned int source) +static void pll_factors(struct snd_soc_codec *codec, + struct _pll_div *pll_div, unsigned int source) { u64 Kpart; unsigned int K, Ndiv, Nmod, target; @@ -724,7 +725,7 @@ static void pll_factors(struct _pll_div *pll_div, unsigned int source) Ndiv = target / source; if ((Ndiv < 5) || (Ndiv > 12)) - printk(KERN_WARNING + dev_warn(codec->dev, "WM9713 PLL N value %u out of recommended range!\n", Ndiv); @@ -768,7 +769,7 @@ static int wm9713_set_pll(struct snd_soc_codec *codec, return 0; } - pll_factors(&pll_div, freq_in); + pll_factors(codec, &pll_div, freq_in); if (pll_div.k == 0) { reg = (pll_div.n << 12) | (pll_div.lf << 11) | @@ -1104,8 +1105,11 @@ int wm9713_reset(struct snd_soc_codec *codec, int try_warm) soc_ac97_ops->reset(codec->ac97); if (soc_ac97_ops->warm_reset) soc_ac97_ops->warm_reset(codec->ac97); - if (ac97_read(codec, 0) != wm9713_reg[0]) + if (ac97_read(codec, 0) != wm9713_reg[0]) { + dev_err(codec->dev, "Failed to reset: AC97 link error\n"); return -EIO; + } + return 0; } EXPORT_SYMBOL_GPL(wm9713_reset); @@ -1163,10 +1167,8 @@ static int wm9713_soc_resume(struct snd_soc_codec *codec) u16 *cache = codec->reg_cache; ret = wm9713_reset(codec, 1); - if (ret < 0) { - printk(KERN_ERR "could not reset AC97 codec\n"); + if (ret < 0) return ret; - } wm9713_set_bias_level(codec, SND_SOC_BIAS_STANDBY); @@ -1205,10 +1207,8 @@ static int wm9713_soc_probe(struct snd_soc_codec *codec) * a warm reset followed by an optional cold reset for codec */ wm9713_reset(codec, 0); ret = wm9713_reset(codec, 1); - if (ret < 0) { - printk(KERN_ERR "Failed to reset WM9713: AC97 link error\n"); + if (ret < 0) goto reset_err; - } wm9713_set_bias_level(codec, SND_SOC_BIAS_STANDBY); -- cgit v1.2.3 From c1359ca303ee5125827c0d2a65f0c86d491dc993 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 30 Oct 2014 21:01:08 +0100 Subject: ASoC: wm9713: Use table based control setup Makes the code a bit cleaner. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm9713.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index 38e17d45cfef..ba8c276b9dcf 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -1216,9 +1216,6 @@ static int wm9713_soc_probe(struct snd_soc_codec *codec) reg = ac97_read(codec, AC97_CD) & 0x7fff; ac97_write(codec, AC97_CD, reg); - snd_soc_add_codec_controls(codec, wm9713_snd_ac97_controls, - ARRAY_SIZE(wm9713_snd_ac97_controls)); - return 0; reset_err: @@ -1248,6 +1245,9 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9713 = { .reg_word_size = sizeof(u16), .reg_cache_step = 2, .reg_cache_default = wm9713_reg, + + .controls = wm9713_snd_ac97_controls, + .num_controls = ARRAY_SIZE(wm9713_snd_ac97_controls), .dapm_widgets = wm9713_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(wm9713_dapm_widgets), .dapm_routes = wm9713_audio_map, -- cgit v1.2.3 From 5efe89d9525f24f607079307d2d9510e30ba8590 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 30 Oct 2014 21:01:09 +0100 Subject: ASoC: wm9713: Move driver state struct allocation to driver probe Resources for the device should be allocated in the device driver probe callback, rather than in the ASoC CODEC probe callback. E.g. one advantage is that we can use device managed allocations. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm9713.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index ba8c276b9dcf..27047839172d 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -1191,17 +1191,11 @@ static int wm9713_soc_resume(struct snd_soc_codec *codec) static int wm9713_soc_probe(struct snd_soc_codec *codec) { - struct wm9713_priv *wm9713; int ret = 0, reg; - wm9713 = kzalloc(sizeof(struct wm9713_priv), GFP_KERNEL); - if (wm9713 == NULL) - return -ENOMEM; - snd_soc_codec_set_drvdata(codec, wm9713); - ret = snd_soc_new_ac97_codec(codec, soc_ac97_ops, 0); if (ret < 0) - goto codec_err; + return ret; /* do a cold reset for the controller and then try * a warm reset followed by an optional cold reset for codec */ @@ -1220,16 +1214,12 @@ static int wm9713_soc_probe(struct snd_soc_codec *codec) reset_err: snd_soc_free_ac97_codec(codec); -codec_err: - kfree(wm9713); return ret; } static int wm9713_soc_remove(struct snd_soc_codec *codec) { - struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec); snd_soc_free_ac97_codec(codec); - kfree(wm9713); return 0; } @@ -1256,6 +1246,14 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9713 = { static int wm9713_probe(struct platform_device *pdev) { + struct wm9713_priv *wm9713; + + wm9713 = devm_kzalloc(&pdev->dev, sizeof(*wm9713), GFP_KERNEL); + if (wm9713 == NULL) + return -ENOMEM; + + platform_set_drvdata(pdev, wm9713); + return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm9713, wm9713_dai, ARRAY_SIZE(wm9713_dai)); } -- cgit v1.2.3 From 5bc39b50fd3f9e3585e0cb1cf7d7da979a063848 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 30 Oct 2014 21:01:10 +0100 Subject: ASoC: wm9713: Use virtual control instead of virtual register The wm9713 currently implements the virtual control for the Mic B Source MUX using a virtual register. Replace this by using SOC_ENUM_SINGLE_VIRT(). Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm9713.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index 27047839172d..ac13fc8f5c70 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -59,13 +59,12 @@ static const u16 wm9713_reg[] = { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0006, 0x0001, 0x0000, 0x574d, 0x4c13, - 0x0000, 0x0000, 0x0000 + 0x0000, 0x0000 }; /* virtual HP mixers regs */ #define HPL_MIXER 0x80 #define HPR_MIXER 0x82 -#define MICB_MUX 0x82 static const char *wm9713_mic_mixer[] = {"Stereo", "Mic 1", "Mic 2", "Mute"}; static const char *wm9713_rec_mux[] = {"Stereo", "Left", "Right", "Mute"}; @@ -110,7 +109,7 @@ SOC_ENUM_SINGLE(AC97_REC_GAIN_MIC, 10, 8, wm9713_dac_inv), /* dac invert 2 15 */ SOC_ENUM_SINGLE(AC97_GENERAL_PURPOSE, 15, 2, wm9713_bass), /* bass control 16 */ SOC_ENUM_SINGLE(AC97_PCI_SVID, 5, 2, wm9713_ng_type), /* noise gate type 17 */ SOC_ENUM_SINGLE(AC97_3D_CONTROL, 12, 3, wm9713_mic_select), /* mic selection 18 */ -SOC_ENUM_SINGLE(MICB_MUX, 0, 2, wm9713_micb_select), /* mic selection 19 */ +SOC_ENUM_SINGLE_VIRT(2, wm9713_micb_select), /* mic selection 19 */ }; static const DECLARE_TLV_DB_SCALE(out_tlv, -4650, 150, 0); -- cgit v1.2.3 From e894beb8183dd9e3834983440900ceb632823676 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 31 Oct 2014 10:54:23 -0700 Subject: ASoC: cs42l51: depends on I2C Fix build errors when CONFIG_I2C is not enabled by making the driver depend on I2C. ../sound/soc/codecs/cs42l51-i2c.c:55:1: warning: data definition has no type or storage class [enabled by default] module_i2c_driver(cs42l51_i2c_driver); ^ ../sound/soc/codecs/cs42l51-i2c.c:55:1: error: type defaults to 'int' in declaration of 'module_i2c_driver' [-Werror=implicit-int] ../sound/soc/codecs/cs42l51-i2c.c:55:1: warning: parameter names (without types) in function declaration [enabled by default] ../sound/soc/codecs/cs42l51-i2c.c:45:26: warning: 'cs42l51_i2c_driver' defined but not used [-Wunused-variable] static struct i2c_driver cs42l51_i2c_driver = { ^ Signed-off-by: Randy Dunlap Acked-by: Brian Austin Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index f4fb12fab166..02a36b0b7f54 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -337,6 +337,7 @@ config SND_SOC_CS42L51 config SND_SOC_CS42L51_I2C tristate "Cirrus Logic CS42L51 CODEC (I2C)" + depends on I2C select SND_SOC_CS42L51 config SND_SOC_CS42L52 -- cgit v1.2.3 From bf9706fe958469e7dfc6a9e16d9240892f055e62 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Mon, 3 Nov 2014 13:10:53 +0300 Subject: ASoC: tlv320aic23: add dependencies on I2C/SPI_MASTER This fixes build errors in configurations with I2C/SPI master disabled. Reported-by: Fengguang Wu Signed-off-by: Max Filippov Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 7881b3c35b4d..1e7a4173a3f9 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -582,10 +582,12 @@ config SND_SOC_TLV320AIC23 config SND_SOC_TLV320AIC23_I2C tristate "Texas Instruments TLV320AIC23 audio CODEC - I2C" + depends on I2C select SND_SOC_TLV320AIC23 config SND_SOC_TLV320AIC23_SPI tristate "Texas Instruments TLV320AIC23 audio CODEC - SPI" + depends on SPI_MASTER select SND_SOC_TLV320AIC23 config SND_SOC_TLV320AIC26 -- cgit v1.2.3 From 0b2e4959ceacb26eb586698d9ceecc0a6bd30f72 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Tue, 4 Nov 2014 13:15:10 +0800 Subject: ASoC: rt5645: make bias level more reasonale This patah separate bias level off to standby and off. The standby level will provide the necessary power for JD and push button functions. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 57ba74292259..1423cb283f15 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -2069,8 +2069,8 @@ static int rt5645_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { switch (level) { - case SND_SOC_BIAS_STANDBY: - if (SND_SOC_BIAS_OFF == codec->dapm.bias_level) { + case SND_SOC_BIAS_PREPARE: + if (SND_SOC_BIAS_STANDBY == codec->dapm.bias_level) { snd_soc_update_bits(codec, RT5645_PWR_ANLG1, RT5645_PWR_VREF1 | RT5645_PWR_MB | RT5645_PWR_BG | RT5645_PWR_VREF2, @@ -2085,15 +2085,24 @@ static int rt5645_set_bias_level(struct snd_soc_codec *codec, } break; + case SND_SOC_BIAS_STANDBY: + snd_soc_update_bits(codec, RT5645_PWR_ANLG1, + RT5645_PWR_VREF1 | RT5645_PWR_MB | + RT5645_PWR_BG | RT5645_PWR_VREF2, + RT5645_PWR_VREF1 | RT5645_PWR_MB | + RT5645_PWR_BG | RT5645_PWR_VREF2); + snd_soc_update_bits(codec, RT5645_PWR_ANLG1, + RT5645_PWR_FV1 | RT5645_PWR_FV2, + RT5645_PWR_FV1 | RT5645_PWR_FV2); + break; + case SND_SOC_BIAS_OFF: snd_soc_write(codec, RT5645_DEPOP_M2, 0x1100); snd_soc_write(codec, RT5645_GEN_CTRL1, 0x0128); - snd_soc_write(codec, RT5645_PWR_DIG1, 0x0000); - snd_soc_write(codec, RT5645_PWR_DIG2, 0x0000); - snd_soc_write(codec, RT5645_PWR_VOL, 0x0000); - snd_soc_write(codec, RT5645_PWR_MIXER, 0x0000); - snd_soc_write(codec, RT5645_PWR_ANLG1, 0x0000); - snd_soc_write(codec, RT5645_PWR_ANLG2, 0x0000); + snd_soc_update_bits(codec, RT5645_PWR_ANLG1, + RT5645_PWR_VREF1 | RT5645_PWR_MB | + RT5645_PWR_BG | RT5645_PWR_VREF2 | + RT5645_PWR_FV1 | RT5645_PWR_FV2, 0x0); break; default: -- cgit v1.2.3 From defcd98b16461e123cb4a6cb6ef24a1d0085c1b2 Mon Sep 17 00:00:00 2001 From: Dylan Reid Date: Mon, 3 Nov 2014 10:28:57 -0800 Subject: ASoC: max98090: Different comp tables for different pclks In addtion expand the table to handle other values of sysclk. Instead of making the table 3D, expand it to a more descriptive struct. The divisors are specified in Table 19 of the 98090 data sheet version 0p94. The dmic frequency was previously assumed. Instead make it explicit and configurable through device tree. This now handles independently set pclk and dmic frequency. Based on downstream work by Ralph Birt. Signed-off-by: Dylan Reid Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/max98090.txt | 2 + sound/soc/codecs/max98090.c | 189 +++++++++++++++++---- sound/soc/codecs/max98090.h | 8 + 3 files changed, 163 insertions(+), 36 deletions(-) (limited to 'sound/soc/codecs') diff --git a/Documentation/devicetree/bindings/sound/max98090.txt b/Documentation/devicetree/bindings/sound/max98090.txt index c454e67f54bb..aa802a274520 100644 --- a/Documentation/devicetree/bindings/sound/max98090.txt +++ b/Documentation/devicetree/bindings/sound/max98090.txt @@ -16,6 +16,8 @@ Optional properties: - clock-names: Should be "mclk" +- maxim,dmic-freq: Frequency at which to clock DMIC + Pins on the device (for linking into audio routes): * MIC1 diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index 1229554f1464..a65861cf0a44 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c @@ -1826,27 +1826,155 @@ static int max98090_set_bias_level(struct snd_soc_codec *codec, return 0; } -static const int comp_pclk_rates[] = { - 11289600, 12288000, 12000000, 13000000, 19200000 -}; - -static const int dmic_micclk[] = { - 2, 2, 2, 2, 4, 2 -}; +static const int dmic_divisors[] = { 2, 3, 4, 5, 6, 8 }; static const int comp_lrclk_rates[] = { 8000, 16000, 32000, 44100, 48000, 96000 }; -static const int dmic_comp[6][6] = { - {7, 8, 3, 3, 3, 3}, - {7, 8, 3, 3, 3, 3}, - {7, 8, 3, 3, 3, 3}, - {7, 8, 3, 1, 1, 1}, - {7, 8, 3, 1, 2, 2}, - {7, 8, 3, 3, 3, 3} +struct dmic_table { + int pclk; + struct { + int freq; + int comp[6]; /* One each for 8, 16, 32, 44.1, 48, and 96 kHz */ + } settings[6]; /* One for each dmic divisor. */ }; +static const struct dmic_table dmic_table[] = { /* One for each pclk freq. */ + { + .pclk = 11289600, + .settings = { + { .freq = 2, .comp = { 7, 8, 3, 3, 3, 3 } }, + { .freq = 1, .comp = { 7, 8, 2, 2, 2, 2 } }, + { .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } }, + { .freq = 0, .comp = { 7, 8, 6, 6, 6, 6 } }, + { .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } }, + { .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } }, + }, + }, + { + .pclk = 12000000, + .settings = { + { .freq = 2, .comp = { 7, 8, 3, 3, 3, 3 } }, + { .freq = 1, .comp = { 7, 8, 2, 2, 2, 2 } }, + { .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } }, + { .freq = 0, .comp = { 7, 8, 5, 5, 6, 6 } }, + { .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } }, + { .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } }, + } + }, + { + .pclk = 12288000, + .settings = { + { .freq = 2, .comp = { 7, 8, 3, 3, 3, 3 } }, + { .freq = 1, .comp = { 7, 8, 2, 2, 2, 2 } }, + { .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } }, + { .freq = 0, .comp = { 7, 8, 6, 6, 6, 6 } }, + { .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } }, + { .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } }, + } + }, + { + .pclk = 13000000, + .settings = { + { .freq = 2, .comp = { 7, 8, 1, 1, 1, 1 } }, + { .freq = 1, .comp = { 7, 8, 0, 0, 0, 0 } }, + { .freq = 0, .comp = { 7, 8, 1, 1, 1, 1 } }, + { .freq = 0, .comp = { 7, 8, 4, 4, 5, 5 } }, + { .freq = 0, .comp = { 7, 8, 1, 1, 1, 1 } }, + { .freq = 0, .comp = { 7, 8, 1, 1, 1, 1 } }, + } + }, + { + .pclk = 19200000, + .settings = { + { .freq = 2, .comp = { 0, 0, 0, 0, 0, 0 } }, + { .freq = 1, .comp = { 7, 8, 1, 1, 1, 1 } }, + { .freq = 0, .comp = { 7, 8, 5, 5, 6, 6 } }, + { .freq = 0, .comp = { 7, 8, 2, 2, 3, 3 } }, + { .freq = 0, .comp = { 7, 8, 1, 1, 2, 2 } }, + { .freq = 0, .comp = { 7, 8, 5, 5, 6, 6 } }, + } + }, +}; + +static int max98090_find_divisor(int target_freq, int pclk) +{ + int current_diff = INT_MAX; + int test_diff = INT_MAX; + int divisor_index = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(dmic_divisors); i++) { + test_diff = abs(target_freq - (pclk / dmic_divisors[i])); + if (test_diff < current_diff) { + current_diff = test_diff; + divisor_index = i; + } + } + + return divisor_index; +} + +static int max98090_find_closest_pclk(int pclk) +{ + int m1; + int m2; + int i; + + for (i = 0; i < ARRAY_SIZE(dmic_table); i++) { + if (pclk == dmic_table[i].pclk) + return i; + if (pclk < dmic_table[i].pclk) { + if (i == 0) + return i; + m1 = pclk - dmic_table[i-1].pclk; + m2 = dmic_table[i].pclk - pclk; + if (m1 < m2) + return i - 1; + else + return i; + } + } + + return -EINVAL; +} + +static int max98090_configure_dmic(struct max98090_priv *max98090, + int target_dmic_clk, int pclk, int fs) +{ + int micclk_index; + int pclk_index; + int dmic_freq; + int dmic_comp; + int i; + + pclk_index = max98090_find_closest_pclk(pclk); + if (pclk_index < 0) + return pclk_index; + + micclk_index = max98090_find_divisor(target_dmic_clk, pclk); + + for (i = 0; i < ARRAY_SIZE(comp_lrclk_rates) - 1; i++) { + if (fs <= (comp_lrclk_rates[i] + comp_lrclk_rates[i+1]) / 2) + break; + } + + dmic_freq = dmic_table[pclk_index].settings[micclk_index].freq; + dmic_comp = dmic_table[pclk_index].settings[micclk_index].comp[i]; + + regmap_update_bits(max98090->regmap, M98090_REG_DIGITAL_MIC_ENABLE, + M98090_MICCLK_MASK, + micclk_index << M98090_MICCLK_SHIFT); + + regmap_update_bits(max98090->regmap, M98090_REG_DIGITAL_MIC_CONFIG, + M98090_DMIC_COMP_MASK | M98090_DMIC_FREQ_MASK, + dmic_comp << M98090_DMIC_COMP_SHIFT | + dmic_freq << M98090_DMIC_FREQ_SHIFT); + + return 0; +} + static int max98090_dai_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -1854,7 +1982,6 @@ static int max98090_dai_hw_params(struct snd_pcm_substream *substream, struct snd_soc_codec *codec = dai->codec; struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec); struct max98090_cdata *cdata; - int i, j; cdata = &max98090->dai[0]; max98090->bclk = snd_soc_params_to_bclk(params); @@ -1893,27 +2020,8 @@ static int max98090_dai_hw_params(struct snd_pcm_substream *substream, snd_soc_update_bits(codec, M98090_REG_FILTER_CONFIG, M98090_DHF_MASK, M98090_DHF_MASK); - /* Check for supported PCLK to LRCLK ratios */ - for (j = 0; j < ARRAY_SIZE(comp_pclk_rates); j++) { - if (comp_pclk_rates[j] == max98090->sysclk) { - break; - } - } - - for (i = 0; i < ARRAY_SIZE(comp_lrclk_rates) - 1; i++) { - if (max98090->lrclk <= (comp_lrclk_rates[i] + - comp_lrclk_rates[i + 1]) / 2) { - break; - } - } - - snd_soc_update_bits(codec, M98090_REG_DIGITAL_MIC_ENABLE, - M98090_MICCLK_MASK, - dmic_micclk[j] << M98090_MICCLK_SHIFT); - - snd_soc_update_bits(codec, M98090_REG_DIGITAL_MIC_CONFIG, - M98090_DMIC_COMP_MASK, - dmic_comp[j][i] << M98090_DMIC_COMP_SHIFT); + max98090_configure_dmic(max98090, max98090->dmic_freq, max98090->pclk, + max98090->lrclk); return 0; } @@ -1944,12 +2052,15 @@ static int max98090_dai_set_sysclk(struct snd_soc_dai *dai, if ((freq >= 10000000) && (freq <= 20000000)) { snd_soc_write(codec, M98090_REG_SYSTEM_CLOCK, M98090_PSCLK_DIV1); + max98090->pclk = freq; } else if ((freq > 20000000) && (freq <= 40000000)) { snd_soc_write(codec, M98090_REG_SYSTEM_CLOCK, M98090_PSCLK_DIV2); + max98090->pclk = freq >> 1; } else if ((freq > 40000000) && (freq <= 60000000)) { snd_soc_write(codec, M98090_REG_SYSTEM_CLOCK, M98090_PSCLK_DIV4); + max98090->pclk = freq >> 2; } else { dev_err(codec->dev, "Invalid master clock frequency\n"); return -EINVAL; @@ -2324,6 +2435,7 @@ static int max98090_probe(struct snd_soc_codec *codec) /* Initialize private data */ max98090->sysclk = (unsigned)-1; + max98090->pclk = (unsigned)-1; max98090->master = false; cdata = &max98090->dai[0]; @@ -2463,6 +2575,11 @@ static int max98090_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, max98090); max98090->pdata = i2c->dev.platform_data; + ret = of_property_read_u32(i2c->dev.of_node, "maxim,dmic-freq", + &max98090->dmic_freq); + if (ret < 0) + max98090->dmic_freq = MAX98090_DEFAULT_DMIC_FREQ; + max98090->regmap = devm_regmap_init_i2c(i2c, &max98090_regmap); if (IS_ERR(max98090->regmap)) { ret = PTR_ERR(max98090->regmap); diff --git a/sound/soc/codecs/max98090.h b/sound/soc/codecs/max98090.h index a5f6bada06da..21ff743f5af2 100644 --- a/sound/soc/codecs/max98090.h +++ b/sound/soc/codecs/max98090.h @@ -11,6 +11,12 @@ #ifndef _MAX98090_H #define _MAX98090_H +/* + * The default operating frequency for a DMIC attached to the codec. + * This can be overridden by a device tree property. + */ +#define MAX98090_DEFAULT_DMIC_FREQ 2500000 + /* * MAX98090 Register Definitions */ @@ -1518,8 +1524,10 @@ struct max98090_priv { struct max98090_pdata *pdata; struct clk *mclk; unsigned int sysclk; + unsigned int pclk; unsigned int bclk; unsigned int lrclk; + u32 dmic_freq; struct max98090_cdata dai[1]; int jack_state; struct delayed_work jack_work; -- cgit v1.2.3 From 0c239fa6ebd20dd55d8978502d78b7c17441351a Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 5 Nov 2014 10:46:31 +0100 Subject: ASoC: sn95031: Use table based control setup Makes the code a bit cleaner. Signed-off-by: Lars-Peter Clausen Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/codecs/sn95031.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/sn95031.c b/sound/soc/codecs/sn95031.c index cf8fa40662f0..6167c5996d8e 100644 --- a/sound/soc/codecs/sn95031.c +++ b/sound/soc/codecs/sn95031.c @@ -867,9 +867,6 @@ static int sn95031_codec_probe(struct snd_soc_codec *codec) snd_soc_write(codec, SN95031_SSR2, 0x10); snd_soc_write(codec, SN95031_SSR3, 0x40); - snd_soc_add_codec_controls(codec, sn95031_snd_controls, - ARRAY_SIZE(sn95031_snd_controls)); - return 0; } @@ -886,6 +883,9 @@ static struct snd_soc_codec_driver sn95031_codec = { .remove = sn95031_codec_remove, .set_bias_level = sn95031_set_vaud_bias, .idle_bias_off = true, + + .controls = sn95031_snd_controls, + .num_controls = ARRAY_SIZE(sn95031_snd_controls), .dapm_widgets = sn95031_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(sn95031_dapm_widgets), .dapm_routes = sn95031_audio_map, -- cgit v1.2.3 From e3f1ff318e78990977dae91f7f17f02e9af38e7d Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 5 Nov 2014 10:46:32 +0100 Subject: ASoC: tas2552: Use table based DAPM setup Makes the code a bit cleaner and shorter. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/tas2552.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c index f039dc825971..b505212019e2 100644 --- a/sound/soc/codecs/tas2552.c +++ b/sound/soc/codecs/tas2552.c @@ -345,7 +345,6 @@ static const struct reg_default tas2552_init_regs[] = { static int tas2552_codec_probe(struct snd_soc_codec *codec) { struct tas2552_data *tas2552 = snd_soc_codec_get_drvdata(codec); - struct snd_soc_dapm_context *dapm = &codec->dapm; int ret; tas2552->codec = codec; @@ -390,11 +389,6 @@ static int tas2552_codec_probe(struct snd_soc_codec *codec) snd_soc_write(codec, TAS2552_CFG_2, TAS2552_BOOST_EN | TAS2552_APT_EN | TAS2552_LIM_EN); - snd_soc_dapm_new_controls(dapm, tas2552_dapm_widgets, - ARRAY_SIZE(tas2552_dapm_widgets)); - snd_soc_dapm_add_routes(dapm, tas2552_audio_map, - ARRAY_SIZE(tas2552_audio_map)); - return 0; patch_fail: @@ -462,6 +456,10 @@ static struct snd_soc_codec_driver soc_codec_dev_tas2552 = { .resume = tas2552_resume, .controls = tas2552_snd_controls, .num_controls = ARRAY_SIZE(tas2552_snd_controls), + .dapm_widgets = tas2552_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(tas2552_dapm_widgets), + .dapm_routes = tas2552_audio_map, + .num_dapm_routes = ARRAY_SIZE(tas2552_audio_map), }; static const struct regmap_config tas2552_regmap_config = { -- cgit v1.2.3 From c8b5d089d6fd614dfc8a04e3cf087c97486898fb Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 5 Nov 2014 10:46:33 +0100 Subject: ASoC: wl1273: Use table based control setup Makes the code a bit shorter and cleaner. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/wl1273.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wl1273.c b/sound/soc/codecs/wl1273.c index f3d4e88d0b7b..00aea4100bb3 100644 --- a/sound/soc/codecs/wl1273.c +++ b/sound/soc/codecs/wl1273.c @@ -452,7 +452,6 @@ static int wl1273_probe(struct snd_soc_codec *codec) { struct wl1273_core **core = codec->dev->platform_data; struct wl1273_priv *wl1273; - int r; dev_dbg(codec->dev, "%s.\n", __func__); @@ -470,12 +469,7 @@ static int wl1273_probe(struct snd_soc_codec *codec) snd_soc_codec_set_drvdata(codec, wl1273); - r = snd_soc_add_codec_controls(codec, wl1273_controls, - ARRAY_SIZE(wl1273_controls)); - if (r) - kfree(wl1273); - - return r; + return 0; } static int wl1273_remove(struct snd_soc_codec *codec) @@ -492,6 +486,8 @@ static struct snd_soc_codec_driver soc_codec_dev_wl1273 = { .probe = wl1273_probe, .remove = wl1273_remove, + .controls = wl1273_controls, + .num_controls = ARRAY_SIZE(wl1273_controls), .dapm_widgets = wl1273_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(wl1273_dapm_widgets), .dapm_routes = wl1273_dapm_routes, -- cgit v1.2.3 From a6bf30698825718f22a689a54ea023cdf51a4c76 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 5 Nov 2014 10:46:34 +0100 Subject: ASoC: wm8737: Use table based DAPM and control setup Makes the code a bit cleaner and shorter. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8737.c | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm8737.c b/sound/soc/codecs/wm8737.c index 744a422ecb05..fe41dd2b9b45 100644 --- a/sound/soc/codecs/wm8737.c +++ b/sound/soc/codecs/wm8737.c @@ -277,17 +277,6 @@ static const struct snd_soc_dapm_route intercon[] = { { "AIF", NULL, "ADCR" }, }; -static int wm8737_add_widgets(struct snd_soc_codec *codec) -{ - struct snd_soc_dapm_context *dapm = &codec->dapm; - - snd_soc_dapm_new_controls(dapm, wm8737_dapm_widgets, - ARRAY_SIZE(wm8737_dapm_widgets)); - snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon)); - - return 0; -} - /* codec mclk clock divider coefficients */ static const struct { u32 mclk; @@ -593,10 +582,6 @@ static int wm8737_probe(struct snd_soc_codec *codec) /* Bias level configuration will have done an extra enable */ regulator_bulk_disable(ARRAY_SIZE(wm8737->supplies), wm8737->supplies); - snd_soc_add_codec_controls(codec, wm8737_snd_controls, - ARRAY_SIZE(wm8737_snd_controls)); - wm8737_add_widgets(codec); - return 0; err_enable: @@ -617,6 +602,13 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8737 = { .suspend = wm8737_suspend, .resume = wm8737_resume, .set_bias_level = wm8737_set_bias_level, + + .controls = wm8737_snd_controls, + .num_controls = ARRAY_SIZE(wm8737_snd_controls), + .dapm_widgets = wm8737_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm8737_dapm_widgets), + .dapm_routes = intercon, + .num_dapm_routes = ARRAY_SIZE(intercon), }; static const struct of_device_id wm8737_of_match[] = { -- cgit v1.2.3 From c4f50dbc56580bc5fc84667860e973ca24291697 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 5 Nov 2014 10:46:35 +0100 Subject: ASoC: wm8961: Use table based DAPM and control setup Makes the code a bit cleaner. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8961.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c index 41d23e920ad5..e077bb2f0740 100644 --- a/sound/soc/codecs/wm8961.c +++ b/sound/soc/codecs/wm8961.c @@ -835,7 +835,6 @@ static struct snd_soc_dai_driver wm8961_dai = { static int wm8961_probe(struct snd_soc_codec *codec) { - struct snd_soc_dapm_context *dapm = &codec->dapm; u16 reg; /* Enable class W */ @@ -873,12 +872,6 @@ static int wm8961_probe(struct snd_soc_codec *codec) wm8961_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - snd_soc_add_codec_controls(codec, wm8961_snd_controls, - ARRAY_SIZE(wm8961_snd_controls)); - snd_soc_dapm_new_controls(dapm, wm8961_dapm_widgets, - ARRAY_SIZE(wm8961_dapm_widgets)); - snd_soc_dapm_add_routes(dapm, audio_paths, ARRAY_SIZE(audio_paths)); - return 0; } @@ -915,6 +908,13 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8961 = { .suspend = wm8961_suspend, .resume = wm8961_resume, .set_bias_level = wm8961_set_bias_level, + + .controls = wm8961_snd_controls, + .num_controls = ARRAY_SIZE(wm8961_snd_controls), + .dapm_widgets = wm8961_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm8961_dapm_widgets), + .dapm_routes = audio_paths, + .num_dapm_routes = ARRAY_SIZE(audio_paths), }; static const struct regmap_config wm8961_regmap = { -- cgit v1.2.3 From b131c02e99b9da672a2b0cf96bad48d74c39572e Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 5 Nov 2014 10:46:36 +0100 Subject: ASoC: wm8995: Use table based DAPM and control setup Makes the code a bit cleaner. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8995.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c index 1288edeb8c7d..e40c8a662183 100644 --- a/sound/soc/codecs/wm8995.c +++ b/sound/soc/codecs/wm8995.c @@ -2102,13 +2102,6 @@ static int wm8995_probe(struct snd_soc_codec *codec) wm8995_update_class_w(codec); - snd_soc_add_codec_controls(codec, wm8995_snd_controls, - ARRAY_SIZE(wm8995_snd_controls)); - snd_soc_dapm_new_controls(&codec->dapm, wm8995_dapm_widgets, - ARRAY_SIZE(wm8995_dapm_widgets)); - snd_soc_dapm_add_routes(&codec->dapm, wm8995_intercon, - ARRAY_SIZE(wm8995_intercon)); - return 0; err_reg_enable: @@ -2205,6 +2198,13 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8995 = { .remove = wm8995_remove, .set_bias_level = wm8995_set_bias_level, .idle_bias_off = true, + + .controls = wm8995_snd_controls, + .num_controls = ARRAY_SIZE(wm8995_snd_controls), + .dapm_widgets = wm8995_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm8995_dapm_widgets), + .dapm_routes = wm8995_intercon, + .num_dapm_routes = ARRAY_SIZE(wm8995_intercon), }; static struct regmap_config wm8995_regmap = { -- cgit v1.2.3 From d65fd3a42e00d322448f2518db6a3f0eb12ce1bd Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Wed, 5 Nov 2014 13:42:52 +0800 Subject: ASoC: rt5677: Minor coding style and typo fix Minor coding style and typo fix Signed-off-by: Oder Chiou Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677-spi.h | 4 ++-- sound/soc/codecs/rt5677.c | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5677-spi.h b/sound/soc/codecs/rt5677-spi.h index 7528bfd0b596..ec41b2b3b2ca 100644 --- a/sound/soc/codecs/rt5677-spi.h +++ b/sound/soc/codecs/rt5677-spi.h @@ -9,8 +9,8 @@ * published by the Free Software Foundation. */ -#ifndef __RT5671_SPI_H__ -#define __RT5671_SPI_H__ +#ifndef __RT5677_SPI_H__ +#define __RT5677_SPI_H__ #define RT5677_SPI_BUF_LEN 240 #define RT5677_SPI_CMD_BURST_WRITE 0x05 diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index ca264f885195..0d24dc45dfe4 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -1353,7 +1353,7 @@ static SOC_ENUM_SINGLE_DECL( static const struct snd_kcontrol_new rt5677_ib45_bypass_src_mux = SOC_DAPM_ENUM("IB45 Bypass Source", rt5677_ib45_bypass_src_enum); -/* Stereo ADC Source 2 */ /* MX-27 MX26 MX25 [11:10] */ +/* Stereo ADC Source 2 */ /* MX-27 MX26 MX25 [11:10] */ static const char * const rt5677_stereo_adc2_src[] = { "DD MIX1", "DMIC", "Stereo DAC MIX" }; @@ -1438,7 +1438,7 @@ static SOC_ENUM_SINGLE_DECL( static const struct snd_kcontrol_new rt5677_sto2_adc_lr_mux = SOC_DAPM_ENUM("Stereo2 ADC LR Source", rt5677_stereo2_adc_lr_enum); -/* Stereo1 ADC Source 1 */ /* MX-27 MX26 MX25 [13:12] */ +/* Stereo1 ADC Source 1 */ /* MX-27 MX26 MX25 [13:12] */ static const char * const rt5677_stereo_adc1_src[] = { "DD MIX1", "ADC1/2", "Stereo DAC MIX" }; @@ -1710,7 +1710,7 @@ static SOC_ENUM_SINGLE_DECL( static const struct snd_kcontrol_new rt5677_pdm2_r_mux = SOC_DAPM_ENUM("PDM2 Source", rt5677_pdm2_r_enum); -/* TDM IF1/2 SLB ADC1 Data Selection */ /* MX-3C MX-41 [5:4] MX-08 [1:0]*/ +/* TDM IF1/2 SLB ADC1 Data Selection */ /* MX-3C MX-41 [5:4] MX-08 [1:0] */ static const char * const rt5677_if12_adc1_src[] = { "STO1 ADC MIX", "OB01", "VAD ADC" }; @@ -1788,7 +1788,7 @@ static SOC_ENUM_SINGLE_DECL( static const struct snd_kcontrol_new rt5677_slb_adc3_mux = SOC_DAPM_ENUM("SLB ADC3 Source", rt5677_slb_adc3_enum); -/* TDM IF1/2 SLB ADC4 Data Selection */ /* MX-3C MX-41 [11:10] MX-08 [7:6] */ +/* TDM IF1/2 SLB ADC4 Data Selection */ /* MX-3C MX-41 [11:10] MX-08 [7:6] */ static const char * const rt5677_if12_adc4_src[] = { "STO4 ADC MIX", "OB67", "OB01" }; @@ -1814,7 +1814,7 @@ static SOC_ENUM_SINGLE_DECL( static const struct snd_kcontrol_new rt5677_slb_adc4_mux = SOC_DAPM_ENUM("SLB ADC4 Source", rt5677_slb_adc4_enum); -/* Interface3/4 ADC Data Input */ /* MX-2F [3:0] MX-30 [7:4]*/ +/* Interface3/4 ADC Data Input */ /* MX-2F [3:0] MX-30 [7:4] */ static const char * const rt5677_if34_adc_src[] = { "STO1 ADC MIX", "STO2 ADC MIX", "STO3 ADC MIX", "STO4 ADC MIX", "MONO ADC MIX", "OB01", "OB23", "VAD ADC" @@ -1895,7 +1895,7 @@ static SOC_ENUM_SINGLE_DECL( static const struct snd_kcontrol_new rt5677_if2_adc4_swap_mux = SOC_DAPM_ENUM("IF2 ADC4 Swap Source", rt5677_if2_adc4_swap_enum); -/* TDM IF1 ADC Data Selection */ /* MX-3C [2:0] */ +/* TDM IF1 ADC Data Selection */ /* MX-3C [2:0] */ static const char * const rt5677_if1_adc_tdm_swap_src[] = { "1/2/3/4", "2/1/3/4", "2/3/1/4", "4/1/2/3", "1/3/2/4", "1/4/2/3", "3/1/2/4", "3/4/1/2" @@ -2442,7 +2442,7 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = { rt5677_ob_7_mix, ARRAY_SIZE(rt5677_ob_7_mix)), /* Output Side */ - /* DAC mixer before sound effect */ + /* DAC mixer before sound effect */ SND_SOC_DAPM_MIXER("DAC1 MIXL", SND_SOC_NOPM, 0, 0, rt5677_dac_l_mix, ARRAY_SIZE(rt5677_dac_l_mix)), SND_SOC_DAPM_MIXER("DAC1 MIXR", SND_SOC_NOPM, 0, 0, -- cgit v1.2.3 From 1b86a3fa4eb3c7a6d738fa21475b92493f8952b1 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 5 Nov 2014 17:19:53 +0100 Subject: ASoC: ad193x: Keep DAC output stage active in idle Setting the DAC power-down bit for the ad193x will also disable the DAC output amplifier. This will cause audible clicks and pops when starting or stopping playback. To prevent this a new widget is introduced that controls the DAC power-down bit. This widget is connected to both the DAC and a newly introduced VMID widget. This makes sure that the DAC power-down bit is not set as long as a audio sink is connected to the DAC output. At the same time the PLL and SYSCLK will still be disabled when no playback or capture stream is active. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/ad193x.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c index 6844d0b2af68..387530b0b0fd 100644 --- a/sound/soc/codecs/ad193x.c +++ b/sound/soc/codecs/ad193x.c @@ -72,11 +72,13 @@ static const struct snd_kcontrol_new ad193x_snd_controls[] = { }; static const struct snd_soc_dapm_widget ad193x_dapm_widgets[] = { - SND_SOC_DAPM_DAC("DAC", "Playback", AD193X_DAC_CTRL0, 0, 1), + SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_PGA("DAC Output", AD193X_DAC_CTRL0, 0, 1, NULL, 0), SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_SUPPLY("PLL_PWR", AD193X_PLL_CLK_CTRL0, 0, 1, NULL, 0), SND_SOC_DAPM_SUPPLY("ADC_PWR", AD193X_ADC_CTRL0, 0, 1, NULL, 0), SND_SOC_DAPM_SUPPLY("SYSCLK", AD193X_PLL_CLK_CTRL0, 7, 0, NULL, 0), + SND_SOC_DAPM_VMID("VMID"), SND_SOC_DAPM_OUTPUT("DAC1OUT"), SND_SOC_DAPM_OUTPUT("DAC2OUT"), SND_SOC_DAPM_OUTPUT("DAC3OUT"), @@ -87,13 +89,15 @@ static const struct snd_soc_dapm_widget ad193x_dapm_widgets[] = { static const struct snd_soc_dapm_route audio_paths[] = { { "DAC", NULL, "SYSCLK" }, + { "DAC Output", NULL, "DAC" }, + { "DAC Output", NULL, "VMID" }, { "ADC", NULL, "SYSCLK" }, { "DAC", NULL, "ADC_PWR" }, { "ADC", NULL, "ADC_PWR" }, - { "DAC1OUT", NULL, "DAC" }, - { "DAC2OUT", NULL, "DAC" }, - { "DAC3OUT", NULL, "DAC" }, - { "DAC4OUT", NULL, "DAC" }, + { "DAC1OUT", NULL, "DAC Output" }, + { "DAC2OUT", NULL, "DAC Output" }, + { "DAC3OUT", NULL, "DAC Output" }, + { "DAC4OUT", NULL, "DAC Output" }, { "ADC", NULL, "ADC1IN" }, { "ADC", NULL, "ADC2IN" }, { "SYSCLK", NULL, "PLL_PWR" }, -- cgit v1.2.3 From 6c67cde2aa88bb06cd039aa0f61b26df887075d7 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Thu, 6 Nov 2014 09:59:59 +0800 Subject: ASoC: rt286: set combo jack by dmi This patch enables combo jack configuration according to dmi. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt286.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c index 97daa80e9104..d4acb64f477e 100644 --- a/sound/soc/codecs/rt286.c +++ b/sound/soc/codecs/rt286.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -1205,6 +1206,16 @@ static const struct acpi_device_id rt286_acpi_match[] = { }; MODULE_DEVICE_TABLE(acpi, rt286_acpi_match); +static struct dmi_system_id force_combo_jack_table[] __initdata = { + { + .ident = "Intel Wilson Beach", + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "Wilson Beach SDS") + } + }, + { } +}; + static int rt286_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -1240,6 +1251,9 @@ static int rt286_i2c_probe(struct i2c_client *i2c, if (pdata) rt286->pdata = *pdata; + if (dmi_check_system(force_combo_jack_table)) + rt286->pdata.cbj_en = true; + regmap_write(rt286->regmap, RT286_SET_AUDIO_POWER, AC_PWRST_D3); for (i = 0; i < RT286_POWER_REG_LEN; i++) -- cgit v1.2.3 From f8c101bc357d509291f6accb6f62b8439158a203 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Thu, 6 Nov 2014 10:00:00 +0800 Subject: ASoC: rt286: fix comment style Adds spaces around the /* */. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt286.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c index d4acb64f477e..2e818aaca550 100644 --- a/sound/soc/codecs/rt286.c +++ b/sound/soc/codecs/rt286.c @@ -191,7 +191,7 @@ static int rt286_hw_write(void *context, unsigned int reg, unsigned int value) u8 data[4]; int ret, i; - /*handle index registers*/ + /* handle index registers */ if (reg <= 0xff) { rt286_hw_write(client, RT286_COEF_INDEX, reg); for (i = 0; i < INDEX_CACHE_SIZE; i++) { @@ -234,7 +234,7 @@ static int rt286_hw_read(void *context, unsigned int reg, unsigned int *value) __be32 be_reg; unsigned int index, vid, buf = 0x0; - /*handle index registers*/ + /* handle index registers */ if (reg <= 0xff) { rt286_hw_write(client, RT286_COEF_INDEX, reg); reg = RT286_PROC_COEF; @@ -1281,11 +1281,11 @@ static int rt286_i2c_probe(struct i2c_client *i2c, mdelay(10); regmap_write(rt286->regmap, RT286_MISC_CTRL1, 0x0000); - /*Power down LDO, VREF*/ + /* Power down LDO, VREF */ regmap_update_bits(rt286->regmap, RT286_POWER_CTRL2, 0xc, 0x0); regmap_update_bits(rt286->regmap, RT286_POWER_CTRL1, 0x1001, 0x1001); - /*Set depop parameter*/ + /* Set depop parameter */ regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL2, 0x403a, 0x401a); regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL3, 0xf777, 0x4737); regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL4, 0x00ff, 0x003f); -- cgit v1.2.3 From bb656add19764c7a3cf28b2b330ec0a189fe4f48 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 5 Nov 2014 15:02:08 +0800 Subject: ASoC: rt5645: Add JD function support rt5645 codec support jack detection function. The patch will set related registers if JD function is used. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- include/sound/rt5645.h | 3 +++ sound/soc/codecs/rt5645.c | 20 ++++++++++++++++++++ sound/soc/codecs/rt5645.h | 5 +++++ 3 files changed, 28 insertions(+) (limited to 'sound/soc/codecs') diff --git a/include/sound/rt5645.h b/include/sound/rt5645.h index a5352712194b..937f421bc66b 100644 --- a/include/sound/rt5645.h +++ b/include/sound/rt5645.h @@ -23,6 +23,9 @@ struct rt5645_platform_data { unsigned int hp_det_gpio; bool gpio_hp_det_active_high; + + /* true if codec's jd function is used */ + bool en_jd_func; }; #endif diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 1423cb283f15..286438d6916b 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -2203,6 +2203,13 @@ static int rt5645_probe(struct snd_soc_codec *codec) snd_soc_update_bits(codec, RT5645_CHARGE_PUMP, 0x0300, 0x0200); + /* for JD function */ + if (rt5645->pdata.en_jd_func) { + snd_soc_dapm_force_enable_pin(&codec->dapm, "JD Power"); + snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO2"); + snd_soc_dapm_sync(&codec->dapm); + } + return 0; } @@ -2436,6 +2443,19 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, } + if (rt5645->pdata.en_jd_func) { + regmap_update_bits(rt5645->regmap, RT5645_GEN_CTRL3, + RT5645_IRQ_CLK_GATE_CTRL | RT5645_MICINDET_MANU, + RT5645_IRQ_CLK_GATE_CTRL | RT5645_MICINDET_MANU); + regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL1, + RT5645_CBJ_BST1_EN, RT5645_CBJ_BST1_EN); + regmap_update_bits(rt5645->regmap, RT5645_JD_CTRL3, + RT5645_JD_CBJ_EN | RT5645_JD_CBJ_POL, + RT5645_JD_CBJ_EN | RT5645_JD_CBJ_POL); + regmap_update_bits(rt5645->regmap, RT5645_MICBIAS, + RT5645_IRQ_CLK_INT, RT5645_IRQ_CLK_INT); + } + if (rt5645->i2c->irq) { ret = request_threaded_irq(rt5645->i2c->irq, NULL, rt5645_irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING diff --git a/sound/soc/codecs/rt5645.h b/sound/soc/codecs/rt5645.h index 5ec2520614d2..82f681b02949 100644 --- a/sound/soc/codecs/rt5645.h +++ b/sound/soc/codecs/rt5645.h @@ -1348,6 +1348,8 @@ #define RT5645_PWR_CLK25M_SFT 4 #define RT5645_PWR_CLK25M_PD (0x0 << 4) #define RT5645_PWR_CLK25M_PU (0x1 << 4) +#define RT5645_IRQ_CLK_MCLK (0x0 << 3) +#define RT5645_IRQ_CLK_INT (0x1 << 3) /* VAD Control 4 (0x9d) */ #define RT5645_VAD_SEL_MASK (0x3 << 8) @@ -2116,6 +2118,9 @@ enum { #define RT5645_RXDP2_SEL_ADC (0x1 << 3) #define RT5645_RXDP2_SEL_SFT (3) +/* General Control3 (0xfc) */ +#define RT5645_IRQ_CLK_GATE_CTRL (0x1 << 11) +#define RT5645_MICINDET_MANU (0x1 << 7) /* Vendor ID (0xfd) */ #define RT5645_VER_C 0x2 -- cgit v1.2.3 From feec843d6c4528263724ff3f4c463ea82bf63b4a Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 6 Nov 2014 15:59:22 +0100 Subject: ASoC: ssm4567: Add DAC high-pass-filter control Add a switch which can be used to enable/disable the DAC high-pass-filter. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/ssm4567.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/ssm4567.c b/sound/soc/codecs/ssm4567.c index 4b5c17f8507e..e1e33d8cb55a 100644 --- a/sound/soc/codecs/ssm4567.c +++ b/sound/soc/codecs/ssm4567.c @@ -145,6 +145,8 @@ static const struct snd_kcontrol_new ssm4567_snd_controls[] = { SOC_SINGLE_TLV("Master Playback Volume", SSM4567_REG_DAC_VOLUME, 0, 0xff, 1, ssm4567_vol_tlv), SOC_SINGLE("DAC Low Power Mode Switch", SSM4567_REG_DAC_CTRL, 4, 1, 0), + SOC_SINGLE("DAC High Pass Filter Switch", SSM4567_REG_DAC_CTRL, + 5, 1, 0), }; static const struct snd_soc_dapm_widget ssm4567_dapm_widgets[] = { -- cgit v1.2.3 From ead99f89b7cd2b5cfe99601380a6f6f0a1ce7e53 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 6 Nov 2014 15:59:23 +0100 Subject: ASoC: ssm4567: Add support for setting the DAI format and TDM configuration The SSM4567 has support for a couple of different DAI formats. In TDM mode it is also possible to select the TDM slot. This patch adds support for this by implementing the set_fmt and set_tdm_slot callbacks. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/ssm4567.c | 119 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/ssm4567.c b/sound/soc/codecs/ssm4567.c index e1e33d8cb55a..217667926a77 100644 --- a/sound/soc/codecs/ssm4567.c +++ b/sound/soc/codecs/ssm4567.c @@ -69,6 +69,22 @@ #define SSM4567_DAC_FS_64000_96000 0x3 #define SSM4567_DAC_FS_128000_192000 0x4 +/* SAI_CTRL_1 */ +#define SSM4567_SAI_CTRL_1_BCLK BIT(6) +#define SSM4567_SAI_CTRL_1_TDM_BLCKS_MASK (0x3 << 4) +#define SSM4567_SAI_CTRL_1_TDM_BLCKS_32 (0x0 << 4) +#define SSM4567_SAI_CTRL_1_TDM_BLCKS_48 (0x1 << 4) +#define SSM4567_SAI_CTRL_1_TDM_BLCKS_64 (0x2 << 4) +#define SSM4567_SAI_CTRL_1_FSYNC BIT(3) +#define SSM4567_SAI_CTRL_1_LJ BIT(2) +#define SSM4567_SAI_CTRL_1_TDM BIT(1) +#define SSM4567_SAI_CTRL_1_PDM BIT(0) + +/* SAI_CTRL_2 */ +#define SSM4567_SAI_CTRL_2_AUTO_SLOT BIT(3) +#define SSM4567_SAI_CTRL_2_TDM_SLOT_MASK 0x7 +#define SSM4567_SAI_CTRL_2_TDM_SLOT(x) (x) + struct ssm4567 { struct regmap *regmap; }; @@ -194,6 +210,107 @@ static int ssm4567_mute(struct snd_soc_dai *dai, int mute) SSM4567_DAC_MUTE, val); } +static int ssm4567_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, + unsigned int rx_mask, int slots, int width) +{ + struct ssm4567 *ssm4567 = snd_soc_dai_get_drvdata(dai); + unsigned int blcks; + int slot; + int ret; + + if (tx_mask == 0) + return -EINVAL; + + if (rx_mask && rx_mask != tx_mask) + return -EINVAL; + + slot = __ffs(tx_mask); + if (tx_mask != BIT(slot)) + return -EINVAL; + + switch (width) { + case 32: + blcks = SSM4567_SAI_CTRL_1_TDM_BLCKS_32; + break; + case 48: + blcks = SSM4567_SAI_CTRL_1_TDM_BLCKS_48; + break; + case 64: + blcks = SSM4567_SAI_CTRL_1_TDM_BLCKS_64; + break; + default: + return -EINVAL; + } + + ret = regmap_update_bits(ssm4567->regmap, SSM4567_REG_SAI_CTRL_2, + SSM4567_SAI_CTRL_2_AUTO_SLOT | SSM4567_SAI_CTRL_2_TDM_SLOT_MASK, + SSM4567_SAI_CTRL_2_TDM_SLOT(slot)); + if (ret) + return ret; + + return regmap_update_bits(ssm4567->regmap, SSM4567_REG_SAI_CTRL_1, + SSM4567_SAI_CTRL_1_TDM_BLCKS_MASK, blcks); +} + +static int ssm4567_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct ssm4567 *ssm4567 = snd_soc_dai_get_drvdata(dai); + unsigned int ctrl1 = 0; + bool invert_fclk; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + invert_fclk = false; + break; + case SND_SOC_DAIFMT_IB_NF: + ctrl1 |= SSM4567_SAI_CTRL_1_BCLK; + invert_fclk = false; + break; + case SND_SOC_DAIFMT_NB_IF: + ctrl1 |= SSM4567_SAI_CTRL_1_FSYNC; + invert_fclk = true; + break; + case SND_SOC_DAIFMT_IB_IF: + ctrl1 |= SSM4567_SAI_CTRL_1_BCLK; + invert_fclk = true; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + break; + case SND_SOC_DAIFMT_LEFT_J: + ctrl1 |= SSM4567_SAI_CTRL_1_LJ; + invert_fclk = !invert_fclk; + break; + case SND_SOC_DAIFMT_DSP_A: + ctrl1 |= SSM4567_SAI_CTRL_1_TDM; + break; + case SND_SOC_DAIFMT_DSP_B: + ctrl1 |= SSM4567_SAI_CTRL_1_TDM | SSM4567_SAI_CTRL_1_LJ; + break; + case SND_SOC_DAIFMT_PDM: + ctrl1 |= SSM4567_SAI_CTRL_1_PDM; + break; + default: + return -EINVAL; + } + + if (invert_fclk) + ctrl1 |= SSM4567_SAI_CTRL_1_FSYNC; + + return regmap_write(ssm4567->regmap, SSM4567_REG_SAI_CTRL_1, ctrl1); +} + static int ssm4567_set_power(struct ssm4567 *ssm4567, bool enable) { int ret = 0; @@ -248,6 +365,8 @@ static int ssm4567_set_bias_level(struct snd_soc_codec *codec, static const struct snd_soc_dai_ops ssm4567_dai_ops = { .hw_params = ssm4567_hw_params, .digital_mute = ssm4567_mute, + .set_fmt = ssm4567_set_dai_fmt, + .set_tdm_slot = ssm4567_set_tdm_slot, }; static struct snd_soc_dai_driver ssm4567_dai = { -- cgit v1.2.3 From 5ad72152b695ba5027f9c6ec9a48a8e1a70f25dc Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 6 Nov 2014 15:59:24 +0100 Subject: ASoC: ssm4567: Add support for disabling the boost stage This patch adds a switch to enable/disable boost stage of the output amplifier. Applications that know that they do not need the output amplifier boost stage can disable it to conserve a bit of power. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/ssm4567.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/ssm4567.c b/sound/soc/codecs/ssm4567.c index 217667926a77..a984485108cd 100644 --- a/sound/soc/codecs/ssm4567.c +++ b/sound/soc/codecs/ssm4567.c @@ -165,13 +165,20 @@ static const struct snd_kcontrol_new ssm4567_snd_controls[] = { 5, 1, 0), }; +static const struct snd_kcontrol_new ssm4567_amplifier_boost_control = + SOC_DAPM_SINGLE("Switch", SSM4567_REG_POWER_CTRL, 1, 1, 1); + static const struct snd_soc_dapm_widget ssm4567_dapm_widgets[] = { SND_SOC_DAPM_DAC("DAC", "HiFi Playback", SSM4567_REG_POWER_CTRL, 2, 1), + SND_SOC_DAPM_SWITCH("Amplifier Boost", SSM4567_REG_POWER_CTRL, 3, 1, + &ssm4567_amplifier_boost_control), SND_SOC_DAPM_OUTPUT("OUT"), }; static const struct snd_soc_dapm_route ssm4567_routes[] = { + { "OUT", NULL, "Amplifier Boost" }, + { "Amplifier Boost", "Switch", "DAC" }, { "OUT", NULL, "DAC" }, }; -- cgit v1.2.3 From 19ba484d7b15c8650b30377aad6e65b34d3cf3d5 Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Wed, 5 Nov 2014 13:42:53 +0800 Subject: ASoC: rt5677: Use specific r/w function for DSP mode In DSP mode, the register r/w should use the specific function to access that is invoked by address mapping of the DSP. The MX-65[1] is for switching DSP or codec mode. Signed-off-by: Oder Chiou Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677.c | 167 +++++++++++++++++++++++++++------------------- sound/soc/codecs/rt5677.h | 3 +- 2 files changed, 102 insertions(+), 68 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 0d24dc45dfe4..4b6f7d57c1bb 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -541,49 +541,51 @@ static bool rt5677_readable_register(struct device *dev, unsigned int reg) /** * rt5677_dsp_mode_i2c_write_addr - Write value to address on DSP mode. - * @codec: SoC audio codec device. + * @rt5677: Private Data. * @addr: Address index. * @value: Address data. * * * Returns 0 for success or negative error code. */ -static int rt5677_dsp_mode_i2c_write_addr(struct snd_soc_codec *codec, +static int rt5677_dsp_mode_i2c_write_addr(struct rt5677_priv *rt5677, unsigned int addr, unsigned int value, unsigned int opcode) { - struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_codec *codec = rt5677->codec; int ret; mutex_lock(&rt5677->dsp_cmd_lock); - ret = regmap_write(rt5677->regmap, RT5677_DSP_I2C_ADDR_MSB, addr >> 16); + ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_ADDR_MSB, + addr >> 16); if (ret < 0) { dev_err(codec->dev, "Failed to set addr msb value: %d\n", ret); goto err; } - ret = regmap_write(rt5677->regmap, RT5677_DSP_I2C_ADDR_LSB, + ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_ADDR_LSB, addr & 0xffff); if (ret < 0) { dev_err(codec->dev, "Failed to set addr lsb value: %d\n", ret); goto err; } - ret = regmap_write(rt5677->regmap, RT5677_DSP_I2C_DATA_MSB, + ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_DATA_MSB, value >> 16); if (ret < 0) { dev_err(codec->dev, "Failed to set data msb value: %d\n", ret); goto err; } - ret = regmap_write(rt5677->regmap, RT5677_DSP_I2C_DATA_LSB, + ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_DATA_LSB, value & 0xffff); if (ret < 0) { dev_err(codec->dev, "Failed to set data lsb value: %d\n", ret); goto err; } - ret = regmap_write(rt5677->regmap, RT5677_DSP_I2C_OP_CODE, opcode); + ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_OP_CODE, + opcode); if (ret < 0) { dev_err(codec->dev, "Failed to set op code value: %d\n", ret); goto err; @@ -597,42 +599,45 @@ err: /** * rt5677_dsp_mode_i2c_read_addr - Read value from address on DSP mode. - * @codec: SoC audio codec device. + * rt5677: Private Data. * @addr: Address index. * @value: Address data. * + * * Returns 0 for success or negative error code. */ static int rt5677_dsp_mode_i2c_read_addr( - struct snd_soc_codec *codec, unsigned int addr, unsigned int *value) + struct rt5677_priv *rt5677, unsigned int addr, unsigned int *value) { - struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_codec *codec = rt5677->codec; int ret; unsigned int msb, lsb; mutex_lock(&rt5677->dsp_cmd_lock); - ret = regmap_write(rt5677->regmap, RT5677_DSP_I2C_ADDR_MSB, addr >> 16); + ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_ADDR_MSB, + addr >> 16); if (ret < 0) { dev_err(codec->dev, "Failed to set addr msb value: %d\n", ret); goto err; } - ret = regmap_write(rt5677->regmap, RT5677_DSP_I2C_ADDR_LSB, + ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_ADDR_LSB, addr & 0xffff); if (ret < 0) { dev_err(codec->dev, "Failed to set addr lsb value: %d\n", ret); goto err; } - ret = regmap_write(rt5677->regmap, RT5677_DSP_I2C_OP_CODE , 0x0002); + ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_OP_CODE, + 0x0002); if (ret < 0) { dev_err(codec->dev, "Failed to set op code value: %d\n", ret); goto err; } - regmap_read(rt5677->regmap, RT5677_DSP_I2C_DATA_MSB, &msb); - regmap_read(rt5677->regmap, RT5677_DSP_I2C_DATA_LSB, &lsb); + regmap_read(rt5677->regmap_physical, RT5677_DSP_I2C_DATA_MSB, &msb); + regmap_read(rt5677->regmap_physical, RT5677_DSP_I2C_DATA_LSB, &lsb); *value = (msb << 16) | lsb; err: @@ -643,17 +648,17 @@ err: /** * rt5677_dsp_mode_i2c_write - Write register on DSP mode. - * @codec: SoC audio codec device. + * rt5677: Private Data. * @reg: Register index. * @value: Register data. * * * Returns 0 for success or negative error code. */ -static int rt5677_dsp_mode_i2c_write(struct snd_soc_codec *codec, +static int rt5677_dsp_mode_i2c_write(struct rt5677_priv *rt5677, unsigned int reg, unsigned int value) { - return rt5677_dsp_mode_i2c_write_addr(codec, 0x18020000 + reg * 2, + return rt5677_dsp_mode_i2c_write_addr(rt5677, 0x18020000 + reg * 2, value, 0x0001); } @@ -661,57 +666,33 @@ static int rt5677_dsp_mode_i2c_write(struct snd_soc_codec *codec, * rt5677_dsp_mode_i2c_read - Read register on DSP mode. * @codec: SoC audio codec device. * @reg: Register index. + * @value: Register data. * * - * Returns Register value. + * Returns 0 for success or negative error code. */ -static unsigned int rt5677_dsp_mode_i2c_read( - struct snd_soc_codec *codec, unsigned int reg) +static int rt5677_dsp_mode_i2c_read( + struct rt5677_priv *rt5677, unsigned int reg, unsigned int *value) { - unsigned int value = 0; + int ret = rt5677_dsp_mode_i2c_read_addr(rt5677, 0x18020000 + reg * 2, + value); - rt5677_dsp_mode_i2c_read_addr(codec, 0x18020000 + reg * 2, &value); + *value &= 0xffff; - return value; + return ret; } -/** - * rt5677_dsp_mode_i2c_update_bits - update register on DSP mode. - * @codec: audio codec - * @reg: register index. - * @mask: register mask - * @value: new value - * - * - * Returns 1 for change, 0 for no change, or negative error code. - */ -static int rt5677_dsp_mode_i2c_update_bits(struct snd_soc_codec *codec, - unsigned int reg, unsigned int mask, unsigned int value) +static void rt5677_set_dsp_mode(struct snd_soc_codec *codec, bool on) { - unsigned int old, new; - int change, ret; - - ret = rt5677_dsp_mode_i2c_read(codec, reg); - if (ret < 0) { - dev_err(codec->dev, "Failed to read reg: %d\n", ret); - goto err; - } + struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); - old = ret; - new = (old & ~mask) | (value & mask); - change = old != new; - if (change) { - ret = rt5677_dsp_mode_i2c_write(codec, reg, new); - if (ret < 0) { - dev_err(codec->dev, - "Failed to write reg: %d\n", ret); - goto err; - } + if (on) { + regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1, 0x2, 0x2); + rt5677->is_dsp_mode = true; + } else { + regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1, 0x2, 0x0); + rt5677->is_dsp_mode = false; } - return change; - -err: - return ret; } static int rt5677_set_dsp_vad(struct snd_soc_codec *codec, bool on) @@ -733,9 +714,14 @@ static int rt5677_set_dsp_vad(struct snd_soc_codec *codec, bool on) RT5677_LDO1_SEL_MASK, 0x0); regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG2, RT5677_PWR_LDO1, RT5677_PWR_LDO1); - regmap_write(rt5677->regmap, RT5677_GLB_CLK2, 0x0080); + regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK1, + RT5677_MCLK_SRC_MASK, RT5677_MCLK2_SRC); + regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK2, + RT5677_PLL2_PR_SRC_MASK | RT5677_DSP_CLK_SRC_MASK, + RT5677_PLL2_PR_SRC_MCLK2 | RT5677_DSP_CLK_SRC_BYPASS); regmap_write(rt5677->regmap, RT5677_PWR_DSP2, 0x07ff); - regmap_write(rt5677->regmap, RT5677_PWR_DSP1, 0x07ff); + regmap_write(rt5677->regmap, RT5677_PWR_DSP1, 0x07fd); + rt5677_set_dsp_mode(codec, true); ret = request_firmware(&rt5677->fw1, RT5677_FIRMWARE1, codec->dev); @@ -751,8 +737,7 @@ static int rt5677_set_dsp_vad(struct snd_soc_codec *codec, bool on) release_firmware(rt5677->fw2); } - rt5677_dsp_mode_i2c_update_bits(codec, RT5677_PWR_DSP1, 0x1, - 0x0); + regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1, 0x1, 0x0); regcache_cache_bypass(rt5677->regmap, false); regcache_cache_only(rt5677->regmap, true); @@ -762,9 +747,9 @@ static int rt5677_set_dsp_vad(struct snd_soc_codec *codec, bool on) regcache_cache_only(rt5677->regmap, false); regcache_cache_bypass(rt5677->regmap, true); - rt5677_dsp_mode_i2c_update_bits(codec, RT5677_PWR_DSP1, 0x1, - 0x1); - rt5677_dsp_mode_i2c_write(codec, RT5677_PWR_DSP1, 0x0001); + regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1, 0x1, 0x1); + rt5677_set_dsp_mode(codec, false); + regmap_write(rt5677->regmap, RT5677_PWR_DSP1, 0x0001); regmap_write(rt5677->regmap, RT5677_RESET, 0x10ec); @@ -4019,6 +4004,32 @@ static int rt5677_resume(struct snd_soc_codec *codec) #define rt5677_resume NULL #endif +static int rt5677_read(void *context, unsigned int reg, unsigned int *val) +{ + struct i2c_client *client = context; + struct rt5677_priv *rt5677 = i2c_get_clientdata(client); + + if (rt5677->is_dsp_mode) + rt5677_dsp_mode_i2c_read(rt5677, reg, val); + else + regmap_read(rt5677->regmap_physical, reg, val); + + return 0; +} + +static int rt5677_write(void *context, unsigned int reg, unsigned int val) +{ + struct i2c_client *client = context; + struct rt5677_priv *rt5677 = i2c_get_clientdata(client); + + if (rt5677->is_dsp_mode) + rt5677_dsp_mode_i2c_write(rt5677, reg, val); + else + regmap_write(rt5677->regmap_physical, reg, val); + + return 0; +} + #define RT5677_STEREO_RATES SNDRV_PCM_RATE_8000_96000 #define RT5677_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) @@ -4144,6 +4155,17 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5677 = { .num_dapm_routes = ARRAY_SIZE(rt5677_dapm_routes), }; +static const struct regmap_config rt5677_regmap_physical = { + .name = "physical", + .reg_bits = 8, + .val_bits = 16, + + .max_register = RT5677_VENDOR_ID2 + 1, + .readable_reg = rt5677_readable_register, + + .cache_type = REGCACHE_NONE, +}; + static const struct regmap_config rt5677_regmap = { .reg_bits = 8, .val_bits = 16, @@ -4153,6 +4175,8 @@ static const struct regmap_config rt5677_regmap = { .volatile_reg = rt5677_volatile_register, .readable_reg = rt5677_readable_register, + .reg_read = rt5677_read, + .reg_write = rt5677_write, .cache_type = REGCACHE_RBTREE, .reg_defaults = rt5677_reg, @@ -4309,7 +4333,16 @@ static int rt5677_i2c_probe(struct i2c_client *i2c, msleep(10); } - rt5677->regmap = devm_regmap_init_i2c(i2c, &rt5677_regmap); + rt5677->regmap_physical = devm_regmap_init_i2c(i2c, + &rt5677_regmap_physical); + if (IS_ERR(rt5677->regmap_physical)) { + ret = PTR_ERR(rt5677->regmap_physical); + dev_err(&i2c->dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + + rt5677->regmap = devm_regmap_init(&i2c->dev, NULL, i2c, &rt5677_regmap); if (IS_ERR(rt5677->regmap)) { ret = PTR_ERR(rt5677->regmap); dev_err(&i2c->dev, "Failed to allocate register map: %d\n", diff --git a/sound/soc/codecs/rt5677.h b/sound/soc/codecs/rt5677.h index 2f5b8c6c279e..9d473b2798d5 100644 --- a/sound/soc/codecs/rt5677.h +++ b/sound/soc/codecs/rt5677.h @@ -1628,7 +1628,7 @@ enum { struct rt5677_priv { struct snd_soc_codec *codec; struct rt5677_platform_data pdata; - struct regmap *regmap; + struct regmap *regmap, *regmap_physical; const struct firmware *fw1, *fw2; struct mutex dsp_cmd_lock; @@ -1646,6 +1646,7 @@ struct rt5677_priv { #endif bool dsp_vad_en; struct regmap_irq_chip_data *irq_data; + bool is_dsp_mode; }; #endif /* __RT5677_H__ */ -- cgit v1.2.3 From 9e2683530d6f78b30bcf4cabb97d1b7d6b925b85 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Fri, 31 Oct 2014 15:37:55 +0800 Subject: ASoC: rt5645: Add ASRC support This patch add ASRC support for rt5645 codec. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 144 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 286438d6916b..1dbbebc83d41 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -441,6 +441,65 @@ static SOC_ENUM_SINGLE_DECL(rt5645_tdm_adc_sel_enum, RT5645_TDM_CTRL_1, 8, rt5645_tdm_adc_data_select); +static int rt5645_clk_sel_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + unsigned int u_bit = 0, p_bit = 0; + struct soc_enum *em = + (struct soc_enum *)kcontrol->private_value; + + switch (em->reg) { + case RT5645_ASRC_2: + switch (em->shift_l) { + case 0: + u_bit = 0x8; + p_bit = RT5645_PWR_ADC_S1F; + break; + case 4: + u_bit = 0x100; + p_bit = RT5645_PWR_DAC_MF_R; + break; + case 8: + u_bit = 0x200; + p_bit = RT5645_PWR_DAC_MF_L; + break; + case 12: + u_bit = 0x400; + p_bit = RT5645_PWR_DAC_S1F; + break; + } + break; + case RT5645_ASRC_3: + switch (em->shift_l) { + case 0: + u_bit = 0x1; + p_bit = RT5645_PWR_ADC_MF_R; + break; + case 4: + u_bit = 0x2; + p_bit = RT5645_PWR_ADC_MF_L; + break; + } + break; + } + + if (u_bit || p_bit) { + switch (ucontrol->value.integer.value[0]) { + case 1 ... 4: /*enable*/ + if (snd_soc_read(codec, RT5645_PWR_DIG2) & p_bit) + snd_soc_update_bits(codec, + RT5645_ASRC_1, u_bit, u_bit); + break; + default: /*disable*/ + snd_soc_update_bits(codec, RT5645_ASRC_1, u_bit, 0); + break; + } + } + + return snd_soc_put_enum_double(kcontrol, ucontrol); +} + static const struct snd_kcontrol_new rt5645_snd_controls[] = { /* Speaker Output Volume */ SOC_DOUBLE("Speaker Channel Switch", RT5645_SPK_VOL, @@ -552,6 +611,53 @@ static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source, return 0; } +static int is_using_asrc(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + unsigned int reg, shift, val; + + switch (source->shift) { + case 0: + reg = RT5645_ASRC_3; + shift = 0; + break; + case 1: + reg = RT5645_ASRC_3; + shift = 4; + break; + case 3: + reg = RT5645_ASRC_2; + shift = 0; + break; + case 8: + reg = RT5645_ASRC_2; + shift = 4; + break; + case 9: + reg = RT5645_ASRC_2; + shift = 8; + break; + case 10: + reg = RT5645_ASRC_2; + shift = 12; + break; + default: + return 0; + } + + val = (snd_soc_read(source->codec, reg) >> shift) & 0xf; + switch (val) { + case 1: + case 2: + case 3: + case 4: + return 1; + default: + return 0; + } + +} + /* Digital Mixer */ static const struct snd_kcontrol_new rt5645_sto1_adc_l_mix[] = { SOC_DAPM_SINGLE("ADC1 Switch", RT5645_STO1_ADC_MIXER, @@ -1244,6 +1350,30 @@ static const struct snd_soc_dapm_widget rt5645_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("Mic Det Power", RT5645_PWR_VOL, RT5645_PWR_MIC_DET_BIT, 0, NULL, 0), + /* ASRC */ + SND_SOC_DAPM_SUPPLY_S("I2S1 ASRC", 1, RT5645_ASRC_1, + 11, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("I2S2 ASRC", 1, RT5645_ASRC_1, + 12, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DAC STO ASRC", 1, RT5645_ASRC_1, + 10, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DAC MONO L ASRC", 1, RT5645_ASRC_1, + 9, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DAC MONO R ASRC", 1, RT5645_ASRC_1, + 8, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DMIC STO1 ASRC", 1, RT5645_ASRC_1, + 7, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DMIC MONO L ASRC", 1, RT5645_ASRC_1, + 5, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DMIC MONO R ASRC", 1, RT5645_ASRC_1, + 4, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ADC STO1 ASRC", 1, RT5645_ASRC_1, + 3, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ADC MONO L ASRC", 1, RT5645_ASRC_1, + 1, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ADC MONO R ASRC", 1, RT5645_ASRC_1, + 0, 0, NULL, 0), + /* Input Side */ /* micbias */ SND_SOC_DAPM_MICBIAS("micbias1", RT5645_PWR_ANLG2, @@ -1502,6 +1632,17 @@ static const struct snd_soc_dapm_widget rt5645_dapm_widgets[] = { }; static const struct snd_soc_dapm_route rt5645_dapm_routes[] = { + { "adc stereo1 filter", NULL, "ADC STO1 ASRC", is_using_asrc }, + { "adc stereo2 filter", NULL, "ADC STO2 ASRC", is_using_asrc }, + { "adc mono left filter", NULL, "ADC MONO L ASRC", is_using_asrc }, + { "adc mono right filter", NULL, "ADC MONO R ASRC", is_using_asrc }, + { "dac mono left filter", NULL, "DAC MONO L ASRC", is_using_asrc }, + { "dac mono right filter", NULL, "DAC MONO R ASRC", is_using_asrc }, + { "dac stereo1 filter", NULL, "DAC STO ASRC", is_using_asrc }, + + { "I2S1", NULL, "I2S1 ASRC" }, + { "I2S2", NULL, "I2S2 ASRC" }, + { "IN1P", NULL, "LDO2" }, { "IN2P", NULL, "LDO2" }, @@ -1548,12 +1689,15 @@ static const struct snd_soc_dapm_route rt5645_dapm_routes[] = { { "Stereo1 DMIC Mux", "DMIC1", "DMIC1" }, { "Stereo1 DMIC Mux", "DMIC2", "DMIC2" }, + { "Stereo1 DMIC Mux", NULL, "DMIC STO1 ASRC" }, { "Mono DMIC L Mux", "DMIC1", "DMIC L1" }, { "Mono DMIC L Mux", "DMIC2", "DMIC L2" }, + { "Mono DMIC L Mux", NULL, "DMIC MONO L ASRC" }, { "Mono DMIC R Mux", "DMIC1", "DMIC R1" }, { "Mono DMIC R Mux", "DMIC2", "DMIC R2" }, + { "Mono DMIC R Mux", NULL, "DMIC MONO R ASRC" }, { "Stereo1 ADC L2 Mux", "DMIC", "Stereo1 DMIC Mux" }, { "Stereo1 ADC L2 Mux", "DAC MIX", "DAC MIXL" }, -- cgit v1.2.3 From cf1f2ebe8d6176de80ef9d9c979f998ec38fb265 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 3 Nov 2014 19:33:03 +0100 Subject: ASoC: wm9712/wm9713: Replace virtual registers with custom put/get callbacks The wm9712/wm9713 has separate mixers for the left and the right channel, but the inputs to the mixers are enabled/disabled by the same control. Currently this is implemented by the driver by registering two virtual controls for each physical control, one for the left mixer and one for the right mixer. Using virtual registers will no longer work when the driver has been converted to regmap. This patch converts the driver to use controls with custom put/get callbacks instead which implement the logic making sure that the physical control is unmuted when either the left or the right control is unmuted. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/wm9712.c | 163 +++++++++++++++++++++++++++++----------------- sound/soc/codecs/wm9713.c | 153 +++++++++++++++++++++++++------------------ 2 files changed, 194 insertions(+), 122 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index f3aab6e1d92a..3fad37e0d33d 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -23,6 +23,11 @@ #include #include "wm9712.h" +struct wm9712_priv { + unsigned int hp_mixer[2]; + struct mutex lock; +}; + static unsigned int ac97_read(struct snd_soc_codec *codec, unsigned int reg); static int ac97_write(struct snd_soc_codec *codec, @@ -48,12 +53,10 @@ static const u16 wm9712_reg[] = { 0x0000, 0x0000, 0x0000, 0x0000, /* 6e */ 0x0000, 0x0000, 0x0000, 0x0006, /* 76 */ 0x0001, 0x0000, 0x574d, 0x4c12, /* 7e */ - 0x0000, 0x0000 /* virtual hp mixers */ }; -/* virtual HP mixers regs */ -#define HPL_MIXER 0x80 -#define HPR_MIXER 0x82 +#define HPL_MIXER 0x0 +#define HPR_MIXER 0x1 static const char *wm9712_alc_select[] = {"None", "Left", "Right", "Stereo"}; static const char *wm9712_alc_mux[] = {"Stereo", "Left", "Right", "None"}; @@ -157,75 +160,108 @@ SOC_SINGLE_TLV("Mic 2 Volume", AC97_MIC, 0, 31, 1, main_tlv), SOC_SINGLE_TLV("Mic Boost Volume", AC97_MIC, 7, 1, 0, boost_tlv), }; +static const unsigned int wm9712_mixer_mute_regs[] = { + AC97_VIDEO, + AC97_PCM, + AC97_LINE, + AC97_PHONE, + AC97_CD, + AC97_PC_BEEP, +}; + /* We have to create a fake left and right HP mixers because * the codec only has a single control that is shared by both channels. * This makes it impossible to determine the audio path. */ -static int mixer_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event) +static int wm9712_hp_mixer_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - u16 l, r, beep, line, phone, mic, pcm, aux; - - l = ac97_read(w->codec, HPL_MIXER); - r = ac97_read(w->codec, HPR_MIXER); - beep = ac97_read(w->codec, AC97_PC_BEEP); - mic = ac97_read(w->codec, AC97_VIDEO); - phone = ac97_read(w->codec, AC97_PHONE); - line = ac97_read(w->codec, AC97_LINE); - pcm = ac97_read(w->codec, AC97_PCM); - aux = ac97_read(w->codec, AC97_CD); - - if (l & 0x1 || r & 0x1) - ac97_write(w->codec, AC97_VIDEO, mic & 0x7fff); + struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm); + struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec); + unsigned int val = ucontrol->value.enumerated.item[0]; + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + unsigned int mixer, mask, shift, old; + struct snd_soc_dapm_update update; + bool change; + + mixer = mc->shift >> 8; + shift = mc->shift & 0xff; + mask = 1 << shift; + + mutex_lock(&wm9712->lock); + old = wm9712->hp_mixer[mixer]; + if (ucontrol->value.enumerated.item[0]) + wm9712->hp_mixer[mixer] |= mask; else - ac97_write(w->codec, AC97_VIDEO, mic | 0x8000); + wm9712->hp_mixer[mixer] &= ~mask; + + change = old != wm9712->hp_mixer[mixer]; + if (change) { + update.kcontrol = kcontrol; + update.reg = wm9712_mixer_mute_regs[shift]; + update.mask = 0x8000; + if ((wm9712->hp_mixer[0] & mask) || + (wm9712->hp_mixer[1] & mask)) + update.val = 0x0; + else + update.val = 0x8000; + + snd_soc_dapm_mixer_update_power(dapm, kcontrol, val, + &update); + } - if (l & 0x2 || r & 0x2) - ac97_write(w->codec, AC97_PCM, pcm & 0x7fff); - else - ac97_write(w->codec, AC97_PCM, pcm | 0x8000); + mutex_unlock(&wm9712->lock); - if (l & 0x4 || r & 0x4) - ac97_write(w->codec, AC97_LINE, line & 0x7fff); - else - ac97_write(w->codec, AC97_LINE, line | 0x8000); + return change; +} - if (l & 0x8 || r & 0x8) - ac97_write(w->codec, AC97_PHONE, phone & 0x7fff); - else - ac97_write(w->codec, AC97_PHONE, phone | 0x8000); +static int wm9712_hp_mixer_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm); + struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + unsigned int shift, mixer; - if (l & 0x10 || r & 0x10) - ac97_write(w->codec, AC97_CD, aux & 0x7fff); - else - ac97_write(w->codec, AC97_CD, aux | 0x8000); + mixer = mc->shift >> 8; + shift = mc->shift & 0xff; - if (l & 0x20 || r & 0x20) - ac97_write(w->codec, AC97_PC_BEEP, beep & 0x7fff); - else - ac97_write(w->codec, AC97_PC_BEEP, beep | 0x8000); + ucontrol->value.enumerated.item[0] = + (wm9712->hp_mixer[mixer] >> shift) & 1; return 0; } +#define WM9712_HP_MIXER_CTRL(xname, xmixer, xshift) { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .info = snd_soc_info_volsw, \ + .get = wm9712_hp_mixer_get, .put = wm9712_hp_mixer_put, \ + .private_value = SOC_SINGLE_VALUE(SND_SOC_NOPM, \ + (xmixer << 8) | xshift, 1, 0, 0) \ +} + /* Left Headphone Mixers */ static const struct snd_kcontrol_new wm9712_hpl_mixer_controls[] = { - SOC_DAPM_SINGLE("PCBeep Bypass Switch", HPL_MIXER, 5, 1, 0), - SOC_DAPM_SINGLE("Aux Playback Switch", HPL_MIXER, 4, 1, 0), - SOC_DAPM_SINGLE("Phone Bypass Switch", HPL_MIXER, 3, 1, 0), - SOC_DAPM_SINGLE("Line Bypass Switch", HPL_MIXER, 2, 1, 0), - SOC_DAPM_SINGLE("PCM Playback Switch", HPL_MIXER, 1, 1, 0), - SOC_DAPM_SINGLE("Mic Sidetone Switch", HPL_MIXER, 0, 1, 0), + WM9712_HP_MIXER_CTRL("PCBeep Bypass Switch", HPL_MIXER, 5), + WM9712_HP_MIXER_CTRL("Aux Playback Switch", HPL_MIXER, 4), + WM9712_HP_MIXER_CTRL("Phone Bypass Switch", HPL_MIXER, 3), + WM9712_HP_MIXER_CTRL("Line Bypass Switch", HPL_MIXER, 2), + WM9712_HP_MIXER_CTRL("PCM Playback Switch", HPL_MIXER, 1), + WM9712_HP_MIXER_CTRL("Mic Sidetone Switch", HPL_MIXER, 0), }; /* Right Headphone Mixers */ static const struct snd_kcontrol_new wm9712_hpr_mixer_controls[] = { - SOC_DAPM_SINGLE("PCBeep Bypass Switch", HPR_MIXER, 5, 1, 0), - SOC_DAPM_SINGLE("Aux Playback Switch", HPR_MIXER, 4, 1, 0), - SOC_DAPM_SINGLE("Phone Bypass Switch", HPR_MIXER, 3, 1, 0), - SOC_DAPM_SINGLE("Line Bypass Switch", HPR_MIXER, 2, 1, 0), - SOC_DAPM_SINGLE("PCM Playback Switch", HPR_MIXER, 1, 1, 0), - SOC_DAPM_SINGLE("Mic Sidetone Switch", HPR_MIXER, 0, 1, 0), + WM9712_HP_MIXER_CTRL("PCBeep Bypass Switch", HPR_MIXER, 5), + WM9712_HP_MIXER_CTRL("Aux Playback Switch", HPR_MIXER, 4), + WM9712_HP_MIXER_CTRL("Phone Bypass Switch", HPR_MIXER, 3), + WM9712_HP_MIXER_CTRL("Line Bypass Switch", HPR_MIXER, 2), + WM9712_HP_MIXER_CTRL("PCM Playback Switch", HPR_MIXER, 1), + WM9712_HP_MIXER_CTRL("Mic Sidetone Switch", HPR_MIXER, 0), }; /* Speaker Mixer */ @@ -299,12 +335,10 @@ SND_SOC_DAPM_MUX("Right Mic Select Source", SND_SOC_NOPM, 0, 0, SND_SOC_DAPM_MUX("Differential Source", SND_SOC_NOPM, 0, 0, &wm9712_diff_sel_controls), SND_SOC_DAPM_MIXER("AC97 Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), -SND_SOC_DAPM_MIXER_E("Left HP Mixer", AC97_INT_PAGING, 9, 1, - &wm9712_hpl_mixer_controls[0], ARRAY_SIZE(wm9712_hpl_mixer_controls), - mixer_event, SND_SOC_DAPM_POST_REG), -SND_SOC_DAPM_MIXER_E("Right HP Mixer", AC97_INT_PAGING, 8, 1, - &wm9712_hpr_mixer_controls[0], ARRAY_SIZE(wm9712_hpr_mixer_controls), - mixer_event, SND_SOC_DAPM_POST_REG), +SND_SOC_DAPM_MIXER("Left HP Mixer", AC97_INT_PAGING, 9, 1, + &wm9712_hpl_mixer_controls[0], ARRAY_SIZE(wm9712_hpl_mixer_controls)), +SND_SOC_DAPM_MIXER("Right HP Mixer", AC97_INT_PAGING, 8, 1, + &wm9712_hpr_mixer_controls[0], ARRAY_SIZE(wm9712_hpr_mixer_controls)), SND_SOC_DAPM_MIXER("Phone Mixer", AC97_INT_PAGING, 6, 1, &wm9712_phone_mixer_controls[0], ARRAY_SIZE(wm9712_phone_mixer_controls)), SND_SOC_DAPM_MIXER("Speaker Mixer", AC97_INT_PAGING, 7, 1, @@ -471,8 +505,7 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, { u16 *cache = codec->reg_cache; - if (reg < 0x7c) - soc_ac97_ops->write(codec->ac97, reg, val); + soc_ac97_ops->write(codec->ac97, reg, val); reg = reg >> 1; if (reg < (ARRAY_SIZE(wm9712_reg))) cache[reg] = val; @@ -684,6 +717,16 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9712 = { static int wm9712_probe(struct platform_device *pdev) { + struct wm9712_priv *wm9712; + + wm9712 = devm_kzalloc(&pdev->dev, sizeof(*wm9712), GFP_KERNEL); + if (wm9712 == NULL) + return -ENOMEM; + + mutex_init(&wm9712->lock); + + platform_set_drvdata(pdev, wm9712); + return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm9712, wm9712_dai, ARRAY_SIZE(wm9712_dai)); } diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index ac13fc8f5c70..998e4c7b6b12 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -31,6 +31,8 @@ struct wm9713_priv { u32 pll_in; /* PLL input frequency */ + unsigned int hp_mixer[2]; + struct mutex lock; }; static unsigned int ac97_read(struct snd_soc_codec *codec, @@ -59,12 +61,10 @@ static const u16 wm9713_reg[] = { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0006, 0x0001, 0x0000, 0x574d, 0x4c13, - 0x0000, 0x0000 }; -/* virtual HP mixers regs */ -#define HPL_MIXER 0x80 -#define HPR_MIXER 0x82 +#define HPL_MIXER 0 +#define HPR_MIXER 1 static const char *wm9713_mic_mixer[] = {"Stereo", "Mic 1", "Mic 2", "Mute"}; static const char *wm9713_rec_mux[] = {"Stereo", "Left", "Right", "Mute"}; @@ -233,6 +233,14 @@ static int wm9713_voice_shutdown(struct snd_soc_dapm_widget *w, return 0; } +static const unsigned int wm9713_mixer_mute_regs[] = { + AC97_PC_BEEP, + AC97_MASTER_TONE, + AC97_PHONE, + AC97_REC_SEL, + AC97_PCM, + AC97_AUX, +}; /* We have to create a fake left and right HP mixers because * the codec only has a single control that is shared by both channels. @@ -240,73 +248,95 @@ static int wm9713_voice_shutdown(struct snd_soc_dapm_widget *w, * register map, thus we add a new (virtual) register to help determine the * audio route within the device. */ -static int mixer_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) +static int wm9713_hp_mixer_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - u16 l, r, beep, tone, phone, rec, pcm, aux; - - l = ac97_read(w->codec, HPL_MIXER); - r = ac97_read(w->codec, HPR_MIXER); - beep = ac97_read(w->codec, AC97_PC_BEEP); - tone = ac97_read(w->codec, AC97_MASTER_TONE); - phone = ac97_read(w->codec, AC97_PHONE); - rec = ac97_read(w->codec, AC97_REC_SEL); - pcm = ac97_read(w->codec, AC97_PCM); - aux = ac97_read(w->codec, AC97_AUX); - - if (event & SND_SOC_DAPM_PRE_REG) - return 0; - if ((l & 0x1) || (r & 0x1)) - ac97_write(w->codec, AC97_PC_BEEP, beep & 0x7fff); + struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm); + struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec); + unsigned int val = ucontrol->value.enumerated.item[0]; + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + unsigned int mixer, mask, shift, old; + struct snd_soc_dapm_update update; + bool change; + + mixer = mc->shift >> 8; + shift = mc->shift & 0xff; + mask = (1 << shift); + + mutex_lock(&wm9713->lock); + old = wm9713->hp_mixer[mixer]; + if (ucontrol->value.enumerated.item[0]) + wm9713->hp_mixer[mixer] |= mask; else - ac97_write(w->codec, AC97_PC_BEEP, beep | 0x8000); + wm9713->hp_mixer[mixer] &= ~mask; + + change = old != wm9713->hp_mixer[mixer]; + if (change) { + update.kcontrol = kcontrol; + update.reg = wm9713_mixer_mute_regs[shift]; + update.mask = 0x8000; + if ((wm9713->hp_mixer[0] & mask) || + (wm9713->hp_mixer[1] & mask)) + update.val = 0x0; + else + update.val = 0x8000; + + snd_soc_dapm_mixer_update_power(dapm, kcontrol, val, + &update); + } - if ((l & 0x2) || (r & 0x2)) - ac97_write(w->codec, AC97_MASTER_TONE, tone & 0x7fff); - else - ac97_write(w->codec, AC97_MASTER_TONE, tone | 0x8000); + mutex_unlock(&wm9713->lock); - if ((l & 0x4) || (r & 0x4)) - ac97_write(w->codec, AC97_PHONE, phone & 0x7fff); - else - ac97_write(w->codec, AC97_PHONE, phone | 0x8000); + return change; +} - if ((l & 0x8) || (r & 0x8)) - ac97_write(w->codec, AC97_REC_SEL, rec & 0x7fff); - else - ac97_write(w->codec, AC97_REC_SEL, rec | 0x8000); +static int wm9713_hp_mixer_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm); + struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + unsigned int mixer, shift; - if ((l & 0x10) || (r & 0x10)) - ac97_write(w->codec, AC97_PCM, pcm & 0x7fff); - else - ac97_write(w->codec, AC97_PCM, pcm | 0x8000); + mixer = mc->shift >> 8; + shift = mc->shift & 0xff; - if ((l & 0x20) || (r & 0x20)) - ac97_write(w->codec, AC97_AUX, aux & 0x7fff); - else - ac97_write(w->codec, AC97_AUX, aux | 0x8000); + ucontrol->value.enumerated.item[0] = + (wm9713->hp_mixer[mixer] >> shift) & 1; return 0; } +#define WM9713_HP_MIXER_CTRL(xname, xmixer, xshift) { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .info = snd_soc_info_volsw, \ + .get = wm9713_hp_mixer_get, .put = wm9713_hp_mixer_put, \ + .private_value = SOC_DOUBLE_VALUE(SND_SOC_NOPM, \ + xshift, xmixer, 1, 0, 0) \ +} + /* Left Headphone Mixers */ static const struct snd_kcontrol_new wm9713_hpl_mixer_controls[] = { -SOC_DAPM_SINGLE("Beep Playback Switch", HPL_MIXER, 5, 1, 0), -SOC_DAPM_SINGLE("Voice Playback Switch", HPL_MIXER, 4, 1, 0), -SOC_DAPM_SINGLE("Aux Playback Switch", HPL_MIXER, 3, 1, 0), -SOC_DAPM_SINGLE("PCM Playback Switch", HPL_MIXER, 2, 1, 0), -SOC_DAPM_SINGLE("MonoIn Playback Switch", HPL_MIXER, 1, 1, 0), -SOC_DAPM_SINGLE("Bypass Playback Switch", HPL_MIXER, 0, 1, 0), +WM9713_HP_MIXER_CTRL("Beep Playback Switch", HPL_MIXER, 5), +WM9713_HP_MIXER_CTRL("Voice Playback Switch", HPL_MIXER, 4), +WM9713_HP_MIXER_CTRL("Aux Playback Switch", HPL_MIXER, 3), +WM9713_HP_MIXER_CTRL("PCM Playback Switch", HPL_MIXER, 2), +WM9713_HP_MIXER_CTRL("MonoIn Playback Switch", HPL_MIXER, 1), +WM9713_HP_MIXER_CTRL("Bypass Playback Switch", HPL_MIXER, 0), }; /* Right Headphone Mixers */ static const struct snd_kcontrol_new wm9713_hpr_mixer_controls[] = { -SOC_DAPM_SINGLE("Beep Playback Switch", HPR_MIXER, 5, 1, 0), -SOC_DAPM_SINGLE("Voice Playback Switch", HPR_MIXER, 4, 1, 0), -SOC_DAPM_SINGLE("Aux Playback Switch", HPR_MIXER, 3, 1, 0), -SOC_DAPM_SINGLE("PCM Playback Switch", HPR_MIXER, 2, 1, 0), -SOC_DAPM_SINGLE("MonoIn Playback Switch", HPR_MIXER, 1, 1, 0), -SOC_DAPM_SINGLE("Bypass Playback Switch", HPR_MIXER, 0, 1, 0), +WM9713_HP_MIXER_CTRL("Beep Playback Switch", HPR_MIXER, 5), +WM9713_HP_MIXER_CTRL("Voice Playback Switch", HPR_MIXER, 4), +WM9713_HP_MIXER_CTRL("Aux Playback Switch", HPR_MIXER, 3), +WM9713_HP_MIXER_CTRL("PCM Playback Switch", HPR_MIXER, 2), +WM9713_HP_MIXER_CTRL("MonoIn Playback Switch", HPR_MIXER, 1), +WM9713_HP_MIXER_CTRL("Bypass Playback Switch", HPR_MIXER, 0), }; /* headphone capture mux */ @@ -428,12 +458,10 @@ SND_SOC_DAPM_MUX("Mic A Source", SND_SOC_NOPM, 0, 0, &wm9713_mic_sel_mux_controls), SND_SOC_DAPM_MUX("Mic B Source", SND_SOC_NOPM, 0, 0, &wm9713_micb_sel_mux_controls), -SND_SOC_DAPM_MIXER_E("Left HP Mixer", AC97_EXTENDED_MID, 3, 1, - &wm9713_hpl_mixer_controls[0], ARRAY_SIZE(wm9713_hpl_mixer_controls), - mixer_event, SND_SOC_DAPM_POST_REG), -SND_SOC_DAPM_MIXER_E("Right HP Mixer", AC97_EXTENDED_MID, 2, 1, - &wm9713_hpr_mixer_controls[0], ARRAY_SIZE(wm9713_hpr_mixer_controls), - mixer_event, SND_SOC_DAPM_POST_REG), +SND_SOC_DAPM_MIXER("Left HP Mixer", AC97_EXTENDED_MID, 3, 1, + &wm9713_hpl_mixer_controls[0], ARRAY_SIZE(wm9713_hpl_mixer_controls)), +SND_SOC_DAPM_MIXER("Right HP Mixer", AC97_EXTENDED_MID, 2, 1, + &wm9713_hpr_mixer_controls[0], ARRAY_SIZE(wm9713_hpr_mixer_controls)), SND_SOC_DAPM_MIXER("Mono Mixer", AC97_EXTENDED_MID, 0, 1, &wm9713_mono_mixer_controls[0], ARRAY_SIZE(wm9713_mono_mixer_controls)), SND_SOC_DAPM_MIXER("Speaker Mixer", AC97_EXTENDED_MID, 1, 1, @@ -666,8 +694,7 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int val) { u16 *cache = codec->reg_cache; - if (reg < 0x7c) - soc_ac97_ops->write(codec->ac97, reg, val); + soc_ac97_ops->write(codec->ac97, reg, val); reg = reg >> 1; if (reg < (ARRAY_SIZE(wm9713_reg))) cache[reg] = val; @@ -1251,6 +1278,8 @@ static int wm9713_probe(struct platform_device *pdev) if (wm9713 == NULL) return -ENOMEM; + mutex_init(&wm9713->lock); + platform_set_drvdata(pdev, wm9713); return snd_soc_register_codec(&pdev->dev, -- cgit v1.2.3 From fbace43e8817113475ebda00e28593baa436a131 Mon Sep 17 00:00:00 2001 From: Peter Rosin Date: Sat, 8 Nov 2014 14:40:17 +0100 Subject: ASoC: tfa9879: New driver for NXP Semiconductors TFA9879 amplifier. Signed-off-by: Peter Rosin Signed-off-by: Mark Brown --- MAINTAINERS | 6 + sound/soc/codecs/Kconfig | 5 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/tfa9879.c | 328 +++++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/tfa9879.h | 202 ++++++++++++++++++++++++++++ 5 files changed, 543 insertions(+) create mode 100644 sound/soc/codecs/tfa9879.c create mode 100644 sound/soc/codecs/tfa9879.h (limited to 'sound/soc/codecs') diff --git a/MAINTAINERS b/MAINTAINERS index a20df9bf8ab0..28a33296a468 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6565,6 +6565,12 @@ S: Supported F: drivers/gpu/drm/i2c/tda998x_drv.c F: include/drm/i2c/tda998x.h +NXP TFA9879 DRIVER +M: Peter Rosin +L: alsa-devel@alsa-project.org (moderated for non-subscribers) +S: Maintained +F: sound/soc/codecs/tfa9879* + OMAP SUPPORT M: Tony Lindgren L: linux-omap@vger.kernel.org diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index a68d1731a8fd..99b34a97499f 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -101,6 +101,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_STAC9766 if SND_SOC_AC97_BUS select SND_SOC_TAS2552 if I2C select SND_SOC_TAS5086 if I2C + select SND_SOC_TFA9879 if I2C select SND_SOC_TLV320AIC23_I2C if I2C select SND_SOC_TLV320AIC23_SPI if SPI_MASTER select SND_SOC_TLV320AIC26 if SPI_MASTER @@ -577,6 +578,10 @@ config SND_SOC_TAS5086 tristate "Texas Instruments TAS5086 speaker amplifier" depends on I2C +config SND_SOC_TFA9879 + tristate "NXP Semiconductors TFA9879 amplifier" + depends on I2C + config SND_SOC_TLV320AIC23 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 5dce451661e4..ccfa2ab158be 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -101,6 +101,7 @@ snd-soc-sta350-objs := sta350.o snd-soc-sta529-objs := sta529.o snd-soc-stac9766-objs := stac9766.o snd-soc-tas5086-objs := tas5086.o +snd-soc-tfa9879-objs := tfa9879.o snd-soc-tlv320aic23-objs := tlv320aic23.o snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o snd-soc-tlv320aic23-spi-objs := tlv320aic23-spi.o @@ -274,6 +275,7 @@ obj-$(CONFIG_SND_SOC_STA529) += snd-soc-sta529.o obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o obj-$(CONFIG_SND_SOC_TAS2552) += snd-soc-tas2552.o obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o +obj-$(CONFIG_SND_SOC_TFA9879) += snd-soc-tfa9879.o obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C) += snd-soc-tlv320aic23-i2c.o obj-$(CONFIG_SND_SOC_TLV320AIC23_SPI) += snd-soc-tlv320aic23-spi.o diff --git a/sound/soc/codecs/tfa9879.c b/sound/soc/codecs/tfa9879.c new file mode 100644 index 000000000000..16f1b71edb55 --- /dev/null +++ b/sound/soc/codecs/tfa9879.c @@ -0,0 +1,328 @@ +/* + * tfa9879.c -- driver for NXP Semiconductors TFA9879 + * + * Copyright (C) 2014 Axentia Technologies AB + * Author: Peter Rosin + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "tfa9879.h" + +struct tfa9879_priv { + struct regmap *regmap; + int lsb_justified; +}; + +static int tfa9879_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct tfa9879_priv *tfa9879 = snd_soc_codec_get_drvdata(codec); + int fs; + int i2s_set = 0; + + switch (params_rate(params)) { + case 8000: + fs = TFA9879_I2S_FS_8000; + break; + case 11025: + fs = TFA9879_I2S_FS_11025; + break; + case 12000: + fs = TFA9879_I2S_FS_12000; + break; + case 16000: + fs = TFA9879_I2S_FS_16000; + break; + case 22050: + fs = TFA9879_I2S_FS_22050; + break; + case 24000: + fs = TFA9879_I2S_FS_24000; + break; + case 32000: + fs = TFA9879_I2S_FS_32000; + break; + case 44100: + fs = TFA9879_I2S_FS_44100; + break; + case 48000: + fs = TFA9879_I2S_FS_48000; + break; + case 64000: + fs = TFA9879_I2S_FS_64000; + break; + case 88200: + fs = TFA9879_I2S_FS_88200; + break; + case 96000: + fs = TFA9879_I2S_FS_96000; + break; + default: + return -EINVAL; + } + + switch (params_width(params)) { + case 16: + i2s_set = TFA9879_I2S_SET_LSB_J_16; + break; + case 24: + i2s_set = TFA9879_I2S_SET_LSB_J_24; + break; + default: + return -EINVAL; + } + + if (tfa9879->lsb_justified) + snd_soc_update_bits(codec, TFA9879_SERIAL_INTERFACE_1, + TFA9879_I2S_SET_MASK, + i2s_set << TFA9879_I2S_SET_SHIFT); + + snd_soc_update_bits(codec, TFA9879_SERIAL_INTERFACE_1, + TFA9879_I2S_FS_MASK, + fs << TFA9879_I2S_FS_SHIFT); + return 0; +} + +static int tfa9879_digital_mute(struct snd_soc_dai *dai, int mute) +{ + struct snd_soc_codec *codec = dai->codec; + + snd_soc_update_bits(codec, TFA9879_MISC_CONTROL, + TFA9879_S_MUTE_MASK, + !!mute << TFA9879_S_MUTE_SHIFT); + + return 0; +} + +static int tfa9879_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = dai->codec; + struct tfa9879_priv *tfa9879 = snd_soc_codec_get_drvdata(codec); + int i2s_set; + int sck_pol; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + sck_pol = TFA9879_SCK_POL_NORMAL; + break; + case SND_SOC_DAIFMT_IB_NF: + sck_pol = TFA9879_SCK_POL_INVERSE; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + tfa9879->lsb_justified = 0; + i2s_set = TFA9879_I2S_SET_I2S_24; + break; + case SND_SOC_DAIFMT_LEFT_J: + tfa9879->lsb_justified = 0; + i2s_set = TFA9879_I2S_SET_MSB_J_24; + break; + case SND_SOC_DAIFMT_RIGHT_J: + tfa9879->lsb_justified = 1; + i2s_set = TFA9879_I2S_SET_LSB_J_24; + break; + default: + return -EINVAL; + } + + snd_soc_update_bits(codec, TFA9879_SERIAL_INTERFACE_1, + TFA9879_SCK_POL_MASK, + sck_pol << TFA9879_SCK_POL_SHIFT); + snd_soc_update_bits(codec, TFA9879_SERIAL_INTERFACE_1, + TFA9879_I2S_SET_MASK, + i2s_set << TFA9879_I2S_SET_SHIFT); + return 0; +} + +static struct reg_default tfa9879_regs[] = { + { TFA9879_DEVICE_CONTROL, 0x0000 }, /* 0x00 */ + { TFA9879_SERIAL_INTERFACE_1, 0x0a18 }, /* 0x01 */ + { TFA9879_PCM_IOM2_FORMAT_1, 0x0007 }, /* 0x02 */ + { TFA9879_SERIAL_INTERFACE_2, 0x0a18 }, /* 0x03 */ + { TFA9879_PCM_IOM2_FORMAT_2, 0x0007 }, /* 0x04 */ + { TFA9879_EQUALIZER_A1, 0x59dd }, /* 0x05 */ + { TFA9879_EQUALIZER_A2, 0xc63e }, /* 0x06 */ + { TFA9879_EQUALIZER_B1, 0x651a }, /* 0x07 */ + { TFA9879_EQUALIZER_B2, 0xe53e }, /* 0x08 */ + { TFA9879_EQUALIZER_C1, 0x4616 }, /* 0x09 */ + { TFA9879_EQUALIZER_C2, 0xd33e }, /* 0x0a */ + { TFA9879_EQUALIZER_D1, 0x4df3 }, /* 0x0b */ + { TFA9879_EQUALIZER_D2, 0xea3e }, /* 0x0c */ + { TFA9879_EQUALIZER_E1, 0x5ee0 }, /* 0x0d */ + { TFA9879_EQUALIZER_E2, 0xf93e }, /* 0x0e */ + { TFA9879_BYPASS_CONTROL, 0x0093 }, /* 0x0f */ + { TFA9879_DYNAMIC_RANGE_COMPR, 0x92ba }, /* 0x10 */ + { TFA9879_BASS_TREBLE, 0x12a5 }, /* 0x11 */ + { TFA9879_HIGH_PASS_FILTER, 0x0004 }, /* 0x12 */ + { TFA9879_VOLUME_CONTROL, 0x10bd }, /* 0x13 */ + { TFA9879_MISC_CONTROL, 0x0000 }, /* 0x14 */ +}; + +static bool tfa9879_volatile_reg(struct device *dev, unsigned int reg) +{ + return reg == TFA9879_MISC_STATUS; +} + +static const DECLARE_TLV_DB_SCALE(volume_tlv, -7050, 50, 1); +static const DECLARE_TLV_DB_SCALE(tb_gain_tlv, -1800, 200, 0); +static const char * const tb_freq_text[] = { + "Low", "Mid", "High" +}; +static const struct soc_enum treble_freq_enum = + SOC_ENUM_SINGLE(TFA9879_BASS_TREBLE, TFA9879_F_TRBLE_SHIFT, + ARRAY_SIZE(tb_freq_text), tb_freq_text); +static const struct soc_enum bass_freq_enum = + SOC_ENUM_SINGLE(TFA9879_BASS_TREBLE, TFA9879_F_BASS_SHIFT, + ARRAY_SIZE(tb_freq_text), tb_freq_text); + +static const struct snd_kcontrol_new tfa9879_controls[] = { + SOC_SINGLE_TLV("PCM Playback Volume", TFA9879_VOLUME_CONTROL, + TFA9879_VOL_SHIFT, 0xbd, 1, volume_tlv), + SOC_SINGLE_TLV("Treble Volume", TFA9879_BASS_TREBLE, + TFA9879_G_TRBLE_SHIFT, 18, 0, tb_gain_tlv), + SOC_SINGLE_TLV("Bass Volume", TFA9879_BASS_TREBLE, + TFA9879_G_BASS_SHIFT, 18, 0, tb_gain_tlv), + SOC_ENUM("Treble Corner Freq", treble_freq_enum), + SOC_ENUM("Bass Corner Freq", bass_freq_enum), +}; + +static const struct snd_soc_dapm_widget tfa9879_dapm_widgets[] = { +SND_SOC_DAPM_AIF_IN("AIFINL", "Playback", 0, SND_SOC_NOPM, 0, 0), +SND_SOC_DAPM_AIF_IN("AIFINR", "Playback", 1, SND_SOC_NOPM, 0, 0), +SND_SOC_DAPM_DAC("DAC", NULL, TFA9879_DEVICE_CONTROL, TFA9879_OPMODE_SHIFT, 0), +SND_SOC_DAPM_OUTPUT("LINEOUT"), +SND_SOC_DAPM_SUPPLY("POWER", TFA9879_DEVICE_CONTROL, TFA9879_POWERUP_SHIFT, 0, + NULL, 0), +}; + +static const struct snd_soc_dapm_route tfa9879_dapm_routes[] = { + { "DAC", NULL, "AIFINL" }, + { "DAC", NULL, "AIFINR" }, + + { "LINEOUT", NULL, "DAC" }, + + { "DAC", NULL, "POWER" }, +}; + +static const struct snd_soc_codec_driver tfa9879_codec = { + .controls = tfa9879_controls, + .num_controls = ARRAY_SIZE(tfa9879_controls), + + .dapm_widgets = tfa9879_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(tfa9879_dapm_widgets), + .dapm_routes = tfa9879_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(tfa9879_dapm_routes), +}; + +static const struct regmap_config tfa9879_regmap = { + .reg_bits = 8, + .val_bits = 16, + + .volatile_reg = tfa9879_volatile_reg, + .max_register = TFA9879_MISC_STATUS, + .reg_defaults = tfa9879_regs, + .num_reg_defaults = ARRAY_SIZE(tfa9879_regs), + .cache_type = REGCACHE_RBTREE, +}; + +static const struct snd_soc_dai_ops tfa9879_dai_ops = { + .hw_params = tfa9879_hw_params, + .digital_mute = tfa9879_digital_mute, + .set_fmt = tfa9879_set_fmt, +}; + +#define TFA9879_RATES SNDRV_PCM_RATE_8000_96000 + +#define TFA9879_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE) + +static struct snd_soc_dai_driver tfa9879_dai = { + .name = "tfa9879-hifi", + .playback = { + .stream_name = "Playback", + .channels_min = 2, + .channels_max = 2, + .rates = TFA9879_RATES, + .formats = TFA9879_FORMATS, }, + .ops = &tfa9879_dai_ops, +}; + +static int tfa9879_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct tfa9879_priv *tfa9879; + int i; + + tfa9879 = devm_kzalloc(&i2c->dev, sizeof(*tfa9879), GFP_KERNEL); + if (IS_ERR(tfa9879)) + return PTR_ERR(tfa9879); + + i2c_set_clientdata(i2c, tfa9879); + + tfa9879->regmap = devm_regmap_init_i2c(i2c, &tfa9879_regmap); + if (IS_ERR(tfa9879->regmap)) + return PTR_ERR(tfa9879->regmap); + + /* Ensure the device is in reset state */ + for (i = 0; i < ARRAY_SIZE(tfa9879_regs); i++) + regmap_write(tfa9879->regmap, + tfa9879_regs[i].reg, tfa9879_regs[i].def); + + return snd_soc_register_codec(&i2c->dev, &tfa9879_codec, + &tfa9879_dai, 1); +} + +static int tfa9879_i2c_remove(struct i2c_client *client) +{ + snd_soc_unregister_codec(&client->dev); + + return 0; +} + +static const struct i2c_device_id tfa9879_i2c_id[] = { + { "tfa9879", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, tfa9879_i2c_id); + +static struct i2c_driver tfa9879_i2c_driver = { + .driver = { + .name = "tfa9879", + .owner = THIS_MODULE, + }, + .probe = tfa9879_i2c_probe, + .remove = tfa9879_i2c_remove, + .id_table = tfa9879_i2c_id, +}; + +module_i2c_driver(tfa9879_i2c_driver); + +MODULE_DESCRIPTION("ASoC NXP Semiconductors TFA9879 driver"); +MODULE_AUTHOR("Peter Rosin "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/tfa9879.h b/sound/soc/codecs/tfa9879.h new file mode 100644 index 000000000000..3408c90c4628 --- /dev/null +++ b/sound/soc/codecs/tfa9879.h @@ -0,0 +1,202 @@ +/* + * tfa9879.h -- driver for NXP Semiconductors TFA9879 + * + * Copyright (C) 2014 Axentia Technologies AB + * Author: Peter Rosin + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#ifndef _TFA9879_H +#define _TFA9879_H + +#define TFA9879_DEVICE_CONTROL 0x00 +#define TFA9879_SERIAL_INTERFACE_1 0x01 +#define TFA9879_PCM_IOM2_FORMAT_1 0x02 +#define TFA9879_SERIAL_INTERFACE_2 0x03 +#define TFA9879_PCM_IOM2_FORMAT_2 0x04 +#define TFA9879_EQUALIZER_A1 0x05 +#define TFA9879_EQUALIZER_A2 0x06 +#define TFA9879_EQUALIZER_B1 0x07 +#define TFA9879_EQUALIZER_B2 0x08 +#define TFA9879_EQUALIZER_C1 0x09 +#define TFA9879_EQUALIZER_C2 0x0a +#define TFA9879_EQUALIZER_D1 0x0b +#define TFA9879_EQUALIZER_D2 0x0c +#define TFA9879_EQUALIZER_E1 0x0d +#define TFA9879_EQUALIZER_E2 0x0e +#define TFA9879_BYPASS_CONTROL 0x0f +#define TFA9879_DYNAMIC_RANGE_COMPR 0x10 +#define TFA9879_BASS_TREBLE 0x11 +#define TFA9879_HIGH_PASS_FILTER 0x12 +#define TFA9879_VOLUME_CONTROL 0x13 +#define TFA9879_MISC_CONTROL 0x14 +#define TFA9879_MISC_STATUS 0x15 + +/* TFA9879_DEVICE_CONTROL */ +#define TFA9879_INPUT_SEL_MASK 0x0010 +#define TFA9879_INPUT_SEL_SHIFT 4 +#define TFA9879_OPMODE_MASK 0x0008 +#define TFA9879_OPMODE_SHIFT 3 +#define TFA9879_RESET_MASK 0x0002 +#define TFA9879_RESET_SHIFT 1 +#define TFA9879_POWERUP_MASK 0x0001 +#define TFA9879_POWERUP_SHIFT 0 + +/* TFA9879_SERIAL_INTERFACE */ +#define TFA9879_MONO_SEL_MASK 0x0c00 +#define TFA9879_MONO_SEL_SHIFT 10 +#define TFA9879_MONO_SEL_LEFT 0 +#define TFA9879_MONO_SEL_RIGHT 1 +#define TFA9879_MONO_SEL_BOTH 2 +#define TFA9879_I2S_FS_MASK 0x03c0 +#define TFA9879_I2S_FS_SHIFT 6 +#define TFA9879_I2S_FS_8000 0 +#define TFA9879_I2S_FS_11025 1 +#define TFA9879_I2S_FS_12000 2 +#define TFA9879_I2S_FS_16000 3 +#define TFA9879_I2S_FS_22050 4 +#define TFA9879_I2S_FS_24000 5 +#define TFA9879_I2S_FS_32000 6 +#define TFA9879_I2S_FS_44100 7 +#define TFA9879_I2S_FS_48000 8 +#define TFA9879_I2S_FS_64000 9 +#define TFA9879_I2S_FS_88200 10 +#define TFA9879_I2S_FS_96000 11 +#define TFA9879_I2S_SET_MASK 0x0038 +#define TFA9879_I2S_SET_SHIFT 3 +#define TFA9879_I2S_SET_MSB_J_24 2 +#define TFA9879_I2S_SET_I2S_24 3 +#define TFA9879_I2S_SET_LSB_J_16 4 +#define TFA9879_I2S_SET_LSB_J_18 5 +#define TFA9879_I2S_SET_LSB_J_20 6 +#define TFA9879_I2S_SET_LSB_J_24 7 +#define TFA9879_SCK_POL_MASK 0x0004 +#define TFA9879_SCK_POL_SHIFT 2 +#define TFA9879_SCK_POL_NORMAL 0 +#define TFA9879_SCK_POL_INVERSE 1 +#define TFA9879_I_MODE_MASK 0x0003 +#define TFA9879_I_MODE_SHIFT 0 +#define TFA9879_I_MODE_I2S 0 +#define TFA9879_I_MODE_PCM_IOM2_SHORT 1 +#define TFA9879_I_MODE_PCM_IOM2_LONG 2 + +/* TFA9879_PCM_IOM2_FORMAT */ +#define TFA9879_PCM_FS_MASK 0x0800 +#define TFA9879_PCM_FS_SHIFT 11 +#define TFA9879_A_LAW_MASK 0x0400 +#define TFA9879_A_LAW_SHIFT 10 +#define TFA9879_PCM_COMP_MASK 0x0200 +#define TFA9879_PCM_COMP_SHIFT 9 +#define TFA9879_PCM_DL_MASK 0x0100 +#define TFA9879_PCM_DL_SHIFT 8 +#define TFA9879_D1_SLOT_MASK 0x00f0 +#define TFA9879_D1_SLOT_SHIFT 4 +#define TFA9879_D2_SLOT_MASK 0x000f +#define TFA9879_D2_SLOT_SHIFT 0 + +/* TFA9879_EQUALIZER_X1 */ +#define TFA9879_T1_MASK 0x8000 +#define TFA9879_T1_SHIFT 15 +#define TFA9879_K1M_MASK 0x7ff0 +#define TFA9879_K1M_SHIFT 4 +#define TFA9879_K1E_MASK 0x000f +#define TFA9879_K1E_SHIFT 0 + +/* TFA9879_EQUALIZER_X2 */ +#define TFA9879_T2_MASK 0x8000 +#define TFA9879_T2_SHIFT 15 +#define TFA9879_K2M_MASK 0x7800 +#define TFA9879_K2M_SHIFT 11 +#define TFA9879_K2E_MASK 0x0700 +#define TFA9879_K2E_SHIFT 8 +#define TFA9879_K0_MASK 0x00fe +#define TFA9879_K0_SHIFT 1 +#define TFA9879_S_MASK 0x0001 +#define TFA9879_S_SHIFT 0 + +/* TFA9879_BYPASS_CONTROL */ +#define TFA9879_L_OCP_MASK 0x00c0 +#define TFA9879_L_OCP_SHIFT 6 +#define TFA9879_L_OTP_MASK 0x0030 +#define TFA9879_L_OTP_SHIFT 4 +#define TFA9879_CLIPCTRL_MASK 0x0008 +#define TFA9879_CLIPCTRL_SHIFT 3 +#define TFA9879_HPF_BP_MASK 0x0004 +#define TFA9879_HPF_BP_SHIFT 2 +#define TFA9879_DRC_BP_MASK 0x0002 +#define TFA9879_DRC_BP_SHIFT 1 +#define TFA9879_EQ_BP_MASK 0x0001 +#define TFA9879_EQ_BP_SHIFT 0 + +/* TFA9879_DYNAMIC_RANGE_COMPR */ +#define TFA9879_AT_LVL_MASK 0xf000 +#define TFA9879_AT_LVL_SHIFT 12 +#define TFA9879_AT_RATE_MASK 0x0f00 +#define TFA9879_AT_RATE_SHIFT 8 +#define TFA9879_RL_LVL_MASK 0x00f0 +#define TFA9879_RL_LVL_SHIFT 4 +#define TFA9879_RL_RATE_MASK 0x000f +#define TFA9879_RL_RATE_SHIFT 0 + +/* TFA9879_BASS_TREBLE */ +#define TFA9879_G_TRBLE_MASK 0x3e00 +#define TFA9879_G_TRBLE_SHIFT 9 +#define TFA9879_F_TRBLE_MASK 0x0180 +#define TFA9879_F_TRBLE_SHIFT 7 +#define TFA9879_G_BASS_MASK 0x007c +#define TFA9879_G_BASS_SHIFT 2 +#define TFA9879_F_BASS_MASK 0x0003 +#define TFA9879_F_BASS_SHIFT 0 + +/* TFA9879_HIGH_PASS_FILTER */ +#define TFA9879_HP_CTRL_MASK 0x00ff +#define TFA9879_HP_CTRL_SHIFT 0 + +/* TFA9879_VOLUME_CONTROL */ +#define TFA9879_ZR_CRSS_MASK 0x1000 +#define TFA9879_ZR_CRSS_SHIFT 12 +#define TFA9879_VOL_MASK 0x00ff +#define TFA9879_VOL_SHIFT 0 + +/* TFA9879_MISC_CONTROL */ +#define TFA9879_DE_PHAS_MASK 0x0c00 +#define TFA9879_DE_PHAS_SHIFT 10 +#define TFA9879_H_MUTE_MASK 0x0200 +#define TFA9879_H_MUTE_SHIFT 9 +#define TFA9879_S_MUTE_MASK 0x0100 +#define TFA9879_S_MUTE_SHIFT 8 +#define TFA9879_P_LIM_MASK 0x00ff +#define TFA9879_P_LIM_SHIFT 0 + +/* TFA9879_MISC_STATUS */ +#define TFA9879_PS_MASK 0x4000 +#define TFA9879_PS_SHIFT 14 +#define TFA9879_PORA_MASK 0x2000 +#define TFA9879_PORA_SHIFT 13 +#define TFA9879_AMP_MASK 0x0600 +#define TFA9879_AMP_SHIFT 9 +#define TFA9879_IBP_2_MASK 0x0100 +#define TFA9879_IBP_2_SHIFT 8 +#define TFA9879_OFP_2_MASK 0x0080 +#define TFA9879_OFP_2_SHIFT 7 +#define TFA9879_UFP_2_MASK 0x0040 +#define TFA9879_UFP_2_SHIFT 6 +#define TFA9879_IBP_1_MASK 0x0020 +#define TFA9879_IBP_1_SHIFT 5 +#define TFA9879_OFP_1_MASK 0x0010 +#define TFA9879_OFP_1_SHIFT 4 +#define TFA9879_UFP_1_MASK 0x0008 +#define TFA9879_UFP_1_SHIFT 3 +#define TFA9879_OCPOKA_MASK 0x0004 +#define TFA9879_OCPOKA_SHIFT 2 +#define TFA9879_OCPOKB_MASK 0x0002 +#define TFA9879_OCPOKB_SHIFT 1 +#define TFA9879_OTPOK_MASK 0x0001 +#define TFA9879_OTPOK_SHIFT 0 + +#endif -- cgit v1.2.3 From 368494093354ac613a80c2e1d77602aa12473cf0 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 10 Nov 2014 12:27:33 +0200 Subject: ASoC: tlv320aic3x: Add TDM support TDM support is achieved using DSP transfer mode and setting a programmable offset which specifies where data begins with respect to the frame sync. It requires 256-clock mode if CODEC is master (not currently supported in the driver). No additional dependency if CODEC is slave. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic3x.c | 62 ++++++++++++++++++++++++++++++++++++++++-- sound/soc/codecs/tlv320aic3x.h | 1 + 2 files changed, 60 insertions(+), 3 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index f7c2a575a892..8770e28e53a4 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -78,6 +78,8 @@ struct aic3x_priv { struct aic3x_disable_nb disable_nb[AIC3X_NUM_SUPPLIES]; struct aic3x_setup_data *setup; unsigned int sysclk; + unsigned int dai_fmt; + unsigned int tdm_delay; struct list_head list; int master; int gpio_reset; @@ -1009,6 +1011,25 @@ found: return 0; } +static int aic3x_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); + int delay = 0; + + /* TDM slot selection only valid in DSP_A/_B mode */ + if (aic3x->dai_fmt == SND_SOC_DAIFMT_DSP_A) + delay += (aic3x->tdm_delay + 1); + else if (aic3x->dai_fmt == SND_SOC_DAIFMT_DSP_B) + delay += aic3x->tdm_delay; + + /* Configure data delay */ + snd_soc_write(codec, AIC3X_ASD_INTF_CTRLC, aic3x->tdm_delay); + + return 0; +} + static int aic3x_mute(struct snd_soc_dai *dai, int mute) { struct snd_soc_codec *codec = dai->codec; @@ -1048,7 +1069,6 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai, struct snd_soc_codec *codec = codec_dai->codec; struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); u8 iface_areg, iface_breg; - int delay = 0; iface_areg = snd_soc_read(codec, AIC3X_ASD_INTF_CTRLA) & 0x3f; iface_breg = snd_soc_read(codec, AIC3X_ASD_INTF_CTRLB) & 0x3f; @@ -1076,7 +1096,6 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai, case (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF): break; case (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF): - delay = 1; case (SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF): iface_breg |= (0x01 << 6); break; @@ -1090,10 +1109,45 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai, return -EINVAL; } + aic3x->dai_fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK; + /* set iface */ snd_soc_write(codec, AIC3X_ASD_INTF_CTRLA, iface_areg); snd_soc_write(codec, AIC3X_ASD_INTF_CTRLB, iface_breg); - snd_soc_write(codec, AIC3X_ASD_INTF_CTRLC, delay); + + return 0; +} + +static int aic3x_set_dai_tdm_slot(struct snd_soc_dai *codec_dai, + unsigned int tx_mask, unsigned int rx_mask, + int slots, int slot_width) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); + unsigned int lsb; + + if (tx_mask != rx_mask) { + dev_err(codec->dev, "tx and rx masks must be symmetric\n"); + return -EINVAL; + } + + if (unlikely(!tx_mask)) { + dev_err(codec->dev, "tx and rx masks need to be non 0\n"); + return -EINVAL; + } + + /* TDM based on DSP mode requires slots to be adjacent */ + lsb = __ffs(tx_mask); + if ((lsb + 1) != __fls(tx_mask)) { + dev_err(codec->dev, "Invalid mask, slots must be adjacent\n"); + return -EINVAL; + } + + aic3x->tdm_delay = lsb * slot_width; + + /* DOUT in high-impedance on inactive bit clocks */ + snd_soc_update_bits(codec, AIC3X_ASD_INTF_CTRLA, + DOUT_TRISTATE, DOUT_TRISTATE); return 0; } @@ -1212,9 +1266,11 @@ static int aic3x_set_bias_level(struct snd_soc_codec *codec, static const struct snd_soc_dai_ops aic3x_dai_ops = { .hw_params = aic3x_hw_params, + .prepare = aic3x_prepare, .digital_mute = aic3x_mute, .set_sysclk = aic3x_set_dai_sysclk, .set_fmt = aic3x_set_dai_fmt, + .set_tdm_slot = aic3x_set_dai_tdm_slot, }; static struct snd_soc_dai_driver aic3x_dai = { diff --git a/sound/soc/codecs/tlv320aic3x.h b/sound/soc/codecs/tlv320aic3x.h index e521ac3ddde8..89fa692df206 100644 --- a/sound/soc/codecs/tlv320aic3x.h +++ b/sound/soc/codecs/tlv320aic3x.h @@ -169,6 +169,7 @@ /* Audio serial data interface control register A bits */ #define BIT_CLK_MASTER 0x80 #define WORD_CLK_MASTER 0x40 +#define DOUT_TRISTATE 0x20 /* Codec Datapath setup register 7 */ #define FSREF_44100 (1 << 7) -- cgit v1.2.3 From 52ef6284a840bdef50b6ed505bdda014dd769cab Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 9 Nov 2014 17:00:57 +0100 Subject: ASoC: ab8500-codec: Move control lock to the driver level The ab8500 driver uses a driver specific lock to protect concurrent access to some of the control put/get handlers and uses the snd_soc_codec mutex for some others. This patch updates the driver to consistently use the driver specific lock for all controls. This will allow us to eventually remove the snd_soc_codec mutex. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/ab8500-codec.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c index fd43827bb856..7dfbc9921e91 100644 --- a/sound/soc/codecs/ab8500-codec.c +++ b/sound/soc/codecs/ab8500-codec.c @@ -126,13 +126,13 @@ struct ab8500_codec_drvdata_dbg { /* Private data for AB8500 device-driver */ struct ab8500_codec_drvdata { struct regmap *regmap; + struct mutex ctrl_lock; /* Sidetone */ long *sid_fir_values; enum sid_state sid_status; /* ANC */ - struct mutex anc_lock; long *anc_fir_values; long *anc_iir_values; enum anc_state anc_status; @@ -1129,9 +1129,9 @@ static int sid_status_control_get(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev); - mutex_lock(&codec->mutex); + mutex_lock(&drvdata->ctrl_lock); ucontrol->value.integer.value[0] = drvdata->sid_status; - mutex_unlock(&codec->mutex); + mutex_unlock(&drvdata->ctrl_lock); return 0; } @@ -1154,7 +1154,7 @@ static int sid_status_control_put(struct snd_kcontrol *kcontrol, return -EIO; } - mutex_lock(&codec->mutex); + mutex_lock(&drvdata->ctrl_lock); sidconf = snd_soc_read(codec, AB8500_SIDFIRCONF); if (((sidconf & BIT(AB8500_SIDFIRCONF_FIRSIDBUSY)) != 0)) { @@ -1185,7 +1185,7 @@ static int sid_status_control_put(struct snd_kcontrol *kcontrol, drvdata->sid_status = SID_FIR_CONFIGURED; out: - mutex_unlock(&codec->mutex); + mutex_unlock(&drvdata->ctrl_lock); dev_dbg(codec->dev, "%s: Exit\n", __func__); @@ -1198,9 +1198,9 @@ static int anc_status_control_get(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev); - mutex_lock(&codec->mutex); + mutex_lock(&drvdata->ctrl_lock); ucontrol->value.integer.value[0] = drvdata->anc_status; - mutex_unlock(&codec->mutex); + mutex_unlock(&drvdata->ctrl_lock); return 0; } @@ -1217,7 +1217,7 @@ static int anc_status_control_put(struct snd_kcontrol *kcontrol, dev_dbg(dev, "%s: Enter.\n", __func__); - mutex_lock(&drvdata->anc_lock); + mutex_lock(&drvdata->ctrl_lock); req = ucontrol->value.integer.value[0]; if (req >= ARRAY_SIZE(enum_anc_state)) { @@ -1244,9 +1244,7 @@ static int anc_status_control_put(struct snd_kcontrol *kcontrol, } snd_soc_dapm_sync(&codec->dapm); - mutex_lock(&codec->mutex); anc_configure(codec, apply_fir, apply_iir); - mutex_unlock(&codec->mutex); if (apply_fir) { if (drvdata->anc_status == ANC_IIR_CONFIGURED) @@ -1265,7 +1263,7 @@ static int anc_status_control_put(struct snd_kcontrol *kcontrol, snd_soc_dapm_sync(&codec->dapm); cleanup: - mutex_unlock(&drvdata->anc_lock); + mutex_unlock(&drvdata->ctrl_lock); if (status < 0) dev_err(dev, "%s: Unable to configure ANC! (status = %d)\n", @@ -1294,14 +1292,15 @@ static int filter_control_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct ab8500_codec_drvdata *drvdata = snd_soc_codec_get_drvdata(codec); struct filter_control *fc = (struct filter_control *)kcontrol->private_value; unsigned int i; - mutex_lock(&codec->mutex); + mutex_lock(&drvdata->ctrl_lock); for (i = 0; i < fc->count; i++) ucontrol->value.integer.value[i] = fc->value[i]; - mutex_unlock(&codec->mutex); + mutex_unlock(&drvdata->ctrl_lock); return 0; } @@ -1310,14 +1309,15 @@ static int filter_control_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct ab8500_codec_drvdata *drvdata = snd_soc_codec_get_drvdata(codec); struct filter_control *fc = (struct filter_control *)kcontrol->private_value; unsigned int i; - mutex_lock(&codec->mutex); + mutex_lock(&drvdata->ctrl_lock); for (i = 0; i < fc->count; i++) fc->value[i] = ucontrol->value.integer.value[i]; - mutex_unlock(&codec->mutex); + mutex_unlock(&drvdata->ctrl_lock); return 0; } @@ -2545,7 +2545,7 @@ static int ab8500_codec_probe(struct snd_soc_codec *codec) (void)snd_soc_dapm_disable_pin(&codec->dapm, "ANC Configure Input"); - mutex_init(&drvdata->anc_lock); + mutex_init(&drvdata->ctrl_lock); return status; } -- cgit v1.2.3 From 210a5fae55c05174b8a5b571b6698626b3ae35d3 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 9 Nov 2014 17:00:58 +0100 Subject: ASoC: max98095: Move mutex to the driver level The max98095 uses the snd_soc_codec mutex to protect against concurrent access in some of its control put handlers. Move this mutex to the driver level so we can eventually remove the snd_soc_codec mutex. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/max98095.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c index 0ee6797d5083..01f3cc9c780f 100644 --- a/sound/soc/codecs/max98095.c +++ b/sound/soc/codecs/max98095.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -57,6 +58,7 @@ struct max98095_priv { unsigned int mic2pre; struct snd_soc_jack *headphone_jack; struct snd_soc_jack *mic_jack; + struct mutex lock; }; static const struct reg_default max98095_reg_def[] = { @@ -1803,7 +1805,7 @@ static int max98095_put_eq_enum(struct snd_kcontrol *kcontrol, regsave = snd_soc_read(codec, M98095_088_CFG_LEVEL); snd_soc_update_bits(codec, M98095_088_CFG_LEVEL, regmask, 0); - mutex_lock(&codec->mutex); + mutex_lock(&max98095->lock); snd_soc_update_bits(codec, M98095_00F_HOST_CFG, M98095_SEG, M98095_SEG); m98095_eq_band(codec, channel, 0, coef_set->band1); m98095_eq_band(codec, channel, 1, coef_set->band2); @@ -1811,7 +1813,7 @@ static int max98095_put_eq_enum(struct snd_kcontrol *kcontrol, m98095_eq_band(codec, channel, 3, coef_set->band4); m98095_eq_band(codec, channel, 4, coef_set->band5); snd_soc_update_bits(codec, M98095_00F_HOST_CFG, M98095_SEG, 0); - mutex_unlock(&codec->mutex); + mutex_unlock(&max98095->lock); /* Restore the original on/off state */ snd_soc_update_bits(codec, M98095_088_CFG_LEVEL, regmask, regsave); @@ -1957,12 +1959,12 @@ static int max98095_put_bq_enum(struct snd_kcontrol *kcontrol, regsave = snd_soc_read(codec, M98095_088_CFG_LEVEL); snd_soc_update_bits(codec, M98095_088_CFG_LEVEL, regmask, 0); - mutex_lock(&codec->mutex); + mutex_lock(&max98095->lock); snd_soc_update_bits(codec, M98095_00F_HOST_CFG, M98095_SEG, M98095_SEG); m98095_biquad_band(codec, channel, 0, coef_set->band1); m98095_biquad_band(codec, channel, 1, coef_set->band2); snd_soc_update_bits(codec, M98095_00F_HOST_CFG, M98095_SEG, 0); - mutex_unlock(&codec->mutex); + mutex_unlock(&max98095->lock); /* Restore the original on/off state */ snd_soc_update_bits(codec, M98095_088_CFG_LEVEL, regmask, regsave); @@ -2395,6 +2397,8 @@ static int max98095_i2c_probe(struct i2c_client *i2c, if (max98095 == NULL) return -ENOMEM; + mutex_init(&max98095->lock); + max98095->regmap = devm_regmap_init_i2c(i2c, &max98095_regmap); if (IS_ERR(max98095->regmap)) { ret = PTR_ERR(max98095->regmap); -- cgit v1.2.3 From d74bcaaeb66826192c9e361cbfe8fd1ffaccf74e Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 9 Nov 2014 17:00:59 +0100 Subject: ASoC: wm5102: Move ultrasonic response settings lock to the driver level The wm5102 driver currently uses the snd_soc_codec mutex to protect its ultrasonic response settings from concurrent access. This patch moves this lock to the driver level. This will allow us to eventually remove the snd_soc_codec mutex. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown --- include/linux/mfd/arizona/core.h | 1 + sound/soc/codecs/arizona.c | 4 ++-- sound/soc/codecs/wm5102.c | 16 ++++++++-------- 3 files changed, 11 insertions(+), 10 deletions(-) (limited to 'sound/soc/codecs') diff --git a/include/linux/mfd/arizona/core.h b/include/linux/mfd/arizona/core.h index f34723f7663c..910e3aa1e965 100644 --- a/include/linux/mfd/arizona/core.h +++ b/include/linux/mfd/arizona/core.h @@ -141,6 +141,7 @@ struct arizona { uint16_t dac_comp_coeff; uint8_t dac_comp_enabled; + struct mutex dac_comp_lock; }; int arizona_clk32k_enable(struct arizona *arizona); diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 0c05e7a7945f..730636c14f2e 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -1164,13 +1164,13 @@ static void arizona_wm5102_set_dac_comp(struct snd_soc_codec *codec, { 0x80, 0x0 }, }; - mutex_lock(&codec->mutex); + mutex_lock(&arizona->dac_comp_lock); dac_comp[1].def = arizona->dac_comp_coeff; if (rate >= 176400) dac_comp[2].def = arizona->dac_comp_enabled; - mutex_unlock(&codec->mutex); + mutex_unlock(&arizona->dac_comp_lock); regmap_multi_reg_write(arizona->regmap, dac_comp, diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index f60234962527..1f7553492667 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -619,10 +619,10 @@ static int wm5102_out_comp_coeff_get(struct snd_kcontrol *kcontrol, struct arizona *arizona = dev_get_drvdata(codec->dev->parent); uint16_t data; - mutex_lock(&codec->mutex); + mutex_lock(&arizona->dac_comp_lock); data = cpu_to_be16(arizona->dac_comp_coeff); memcpy(ucontrol->value.bytes.data, &data, sizeof(data)); - mutex_unlock(&codec->mutex); + mutex_unlock(&arizona->dac_comp_lock); return 0; } @@ -633,11 +633,11 @@ static int wm5102_out_comp_coeff_put(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct arizona *arizona = dev_get_drvdata(codec->dev->parent); - mutex_lock(&codec->mutex); + mutex_lock(&arizona->dac_comp_lock); memcpy(&arizona->dac_comp_coeff, ucontrol->value.bytes.data, sizeof(arizona->dac_comp_coeff)); arizona->dac_comp_coeff = be16_to_cpu(arizona->dac_comp_coeff); - mutex_unlock(&codec->mutex); + mutex_unlock(&arizona->dac_comp_lock); return 0; } @@ -648,9 +648,9 @@ static int wm5102_out_comp_switch_get(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct arizona *arizona = dev_get_drvdata(codec->dev->parent); - mutex_lock(&codec->mutex); + mutex_lock(&arizona->dac_comp_lock); ucontrol->value.integer.value[0] = arizona->dac_comp_enabled; - mutex_unlock(&codec->mutex); + mutex_unlock(&arizona->dac_comp_lock); return 0; } @@ -661,9 +661,9 @@ static int wm5102_out_comp_switch_put(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct arizona *arizona = dev_get_drvdata(codec->dev->parent); - mutex_lock(&codec->mutex); + mutex_lock(&arizona->dac_comp_lock); arizona->dac_comp_enabled = ucontrol->value.integer.value[0]; - mutex_unlock(&codec->mutex); + mutex_unlock(&arizona->dac_comp_lock); return 0; } -- cgit v1.2.3 From a51ff30f45473a80f78b2572666473887e010d91 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 9 Nov 2014 17:01:00 +0100 Subject: ASoC: wm8731: Move the deemph lock to the driver level The wm8731 uses the snd_soc_codec mutex to protect its deemph settings from concurrent access. This patch moves this lock to the driver level. This will allow us to eventually remove the snd_soc_codec mutex. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8731.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index eebb3280bfad..5dae9a6f8076 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -50,6 +51,8 @@ struct wm8731_priv { int sysclk_type; int playback_fs; bool deemph; + + struct mutex lock; }; @@ -138,7 +141,7 @@ static int wm8731_put_deemph(struct snd_kcontrol *kcontrol, if (deemph > 1) return -EINVAL; - mutex_lock(&codec->mutex); + mutex_lock(&wm8731->lock); if (wm8731->deemph != deemph) { wm8731->deemph = deemph; @@ -146,7 +149,7 @@ static int wm8731_put_deemph(struct snd_kcontrol *kcontrol, ret = 1; } - mutex_unlock(&codec->mutex); + mutex_unlock(&wm8731->lock); return ret; } @@ -685,6 +688,8 @@ static int wm8731_spi_probe(struct spi_device *spi) if (wm8731 == NULL) return -ENOMEM; + mutex_init(&wm8731->lock); + wm8731->regmap = devm_regmap_init_spi(spi, &wm8731_regmap); if (IS_ERR(wm8731->regmap)) { ret = PTR_ERR(wm8731->regmap); -- cgit v1.2.3 From 78660af7ba30e9d2cc9614465c8b65b3c85f49a9 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 9 Nov 2014 17:01:01 +0100 Subject: ASoC: wm8903: Move the deemph lock to the driver level The wm8903 uses the snd_soc_codec mutex to protect its deemph settings from concurrent access. This patch moves this lock to the driver level. This will allow us to eventually remove the snd_soc_codec mutex. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8903.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index c038b3e04398..ffbe6df3453a 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -123,6 +124,7 @@ struct wm8903_priv { int sysclk; int irq; + struct mutex lock; int fs; int deemph; @@ -457,7 +459,7 @@ static int wm8903_put_deemph(struct snd_kcontrol *kcontrol, if (deemph > 1) return -EINVAL; - mutex_lock(&codec->mutex); + mutex_lock(&wm8903->lock); if (wm8903->deemph != deemph) { wm8903->deemph = deemph; @@ -465,7 +467,7 @@ static int wm8903_put_deemph(struct snd_kcontrol *kcontrol, ret = 1; } - mutex_unlock(&codec->mutex); + mutex_unlock(&wm8903->lock); return ret; } @@ -2023,6 +2025,8 @@ static int wm8903_i2c_probe(struct i2c_client *i2c, GFP_KERNEL); if (wm8903 == NULL) return -ENOMEM; + + mutex_init(&wm8903->lock); wm8903->dev = &i2c->dev; wm8903->regmap = devm_regmap_init_i2c(i2c, &wm8903_regmap); -- cgit v1.2.3 From fabfad2f8b23529722c6ef5b3537c457e63d2c82 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 9 Nov 2014 17:01:02 +0100 Subject: ASoC: wm8958: Move DSP firmware lock to driver level The wm8958 driver uses the snd_soc_codec mutex to protect the various firmware pointers from concurrent assignment. This patch moves this lock to the driver level. This will allow us to eventually remove the snd_soc_codec mutex. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8958-dsp2.c | 12 ++++++------ sound/soc/codecs/wm8994.c | 2 ++ sound/soc/codecs/wm8994.h | 2 ++ 3 files changed, 10 insertions(+), 6 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm8958-dsp2.c b/sound/soc/codecs/wm8958-dsp2.c index 0dada7f0105e..3cbc82b33292 100644 --- a/sound/soc/codecs/wm8958-dsp2.c +++ b/sound/soc/codecs/wm8958-dsp2.c @@ -867,9 +867,9 @@ static void wm8958_enh_eq_loaded(const struct firmware *fw, void *context) struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); if (fw && (wm8958_dsp2_fw(codec, "ENH_EQ", fw, true) == 0)) { - mutex_lock(&codec->mutex); + mutex_lock(&wm8994->fw_lock); wm8994->enh_eq = fw; - mutex_unlock(&codec->mutex); + mutex_unlock(&wm8994->fw_lock); } } @@ -879,9 +879,9 @@ static void wm8958_mbc_vss_loaded(const struct firmware *fw, void *context) struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); if (fw && (wm8958_dsp2_fw(codec, "MBC+VSS", fw, true) == 0)) { - mutex_lock(&codec->mutex); + mutex_lock(&wm8994->fw_lock); wm8994->mbc_vss = fw; - mutex_unlock(&codec->mutex); + mutex_unlock(&wm8994->fw_lock); } } @@ -891,9 +891,9 @@ static void wm8958_mbc_loaded(const struct firmware *fw, void *context) struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); if (fw && (wm8958_dsp2_fw(codec, "MBC", fw, true) == 0)) { - mutex_lock(&codec->mutex); + mutex_lock(&wm8994->fw_lock); wm8994->mbc = fw; - mutex_unlock(&codec->mutex); + mutex_unlock(&wm8994->fw_lock); } } diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index 1fcb9f3f3097..dbca6e0cc93a 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -4457,6 +4457,8 @@ static int wm8994_probe(struct platform_device *pdev) return -ENOMEM; platform_set_drvdata(pdev, wm8994); + mutex_init(&wm8994->fw_lock); + wm8994->wm8994 = dev_get_drvdata(pdev->dev.parent); pm_runtime_enable(&pdev->dev); diff --git a/sound/soc/codecs/wm8994.h b/sound/soc/codecs/wm8994.h index 6536f8d45ac6..dd73387b1cc4 100644 --- a/sound/soc/codecs/wm8994.h +++ b/sound/soc/codecs/wm8994.h @@ -13,6 +13,7 @@ #include #include #include +#include #include "wm_hubs.h" @@ -156,6 +157,7 @@ struct wm8994_priv { unsigned int aif1clk_disable:1; unsigned int aif2clk_disable:1; + struct mutex fw_lock; int dsp_active; const struct firmware *cur_fw; const struct firmware *mbc; -- cgit v1.2.3 From 3e4199ef0105fb718b24cbcc837ad527fd60c880 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 9 Nov 2014 17:01:03 +0100 Subject: ASoC: wm8962: Move DSP enable lock to the driver level The wm8962 uses the snd_soc_codec mutex to protect the wm8962_dsp2_ena_put() function from concurrent execution. This patch moves that lock to the driver level. This will allow us to eventually remove the snd_soc_codec mutex. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8962.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index 9077411e62ce..61ca4a7cb6ea 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -67,6 +68,7 @@ struct wm8962_priv { int fll_fref; int fll_fout; + struct mutex dsp2_ena_lock; u16 dsp2_ena; struct delayed_work mic_work; @@ -1570,7 +1572,7 @@ static int wm8962_dsp2_ena_put(struct snd_kcontrol *kcontrol, int dsp2_running = snd_soc_read(codec, WM8962_DSP2_POWER_MANAGEMENT) & WM8962_DSP2_ENA; - mutex_lock(&codec->mutex); + mutex_lock(&wm8962->dsp2_ena_lock); if (ucontrol->value.integer.value[0]) wm8962->dsp2_ena |= 1 << shift; @@ -1590,7 +1592,7 @@ static int wm8962_dsp2_ena_put(struct snd_kcontrol *kcontrol, } out: - mutex_unlock(&codec->mutex); + mutex_unlock(&wm8962->dsp2_ena_lock); return ret; } @@ -3557,6 +3559,8 @@ static int wm8962_i2c_probe(struct i2c_client *i2c, if (wm8962 == NULL) return -ENOMEM; + mutex_init(&wm8962->dsp2_ena_lock); + i2c_set_clientdata(i2c, wm8962); INIT_DELAYED_WORK(&wm8962->mic_work, wm8962_mic_work); -- cgit v1.2.3 From 0cf1863219b474e82af9cb1f6715a0bbfa3fdf1a Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Tue, 11 Nov 2014 17:59:50 +0800 Subject: ASoC: rt5670: add rt5672 codec support rt5672 is very similar to rt5670. Therefore we use one codec driver to support both codecs. The difference between rt5670 and rt5672 is there is some difference in their dapm routing table. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5670.c | 71 +++++++++++++++++++++++++++++++++++++++-------- sound/soc/codecs/rt5670.h | 6 ++++ 2 files changed, 65 insertions(+), 12 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index ba9d9b4d4857..066b58317c24 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -1595,29 +1595,40 @@ static const struct snd_soc_dapm_widget rt5670_dapm_widgets[] = { /* PDM */ SND_SOC_DAPM_SUPPLY("PDM1 Power", RT5670_PWR_DIG2, RT5670_PWR_PDM1_BIT, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("PDM2 Power", RT5670_PWR_DIG2, - RT5670_PWR_PDM2_BIT, 0, NULL, 0), SND_SOC_DAPM_MUX("PDM1 L Mux", RT5670_PDM_OUT_CTRL, RT5670_M_PDM1_L_SFT, 1, &rt5670_pdm1_l_mux), SND_SOC_DAPM_MUX("PDM1 R Mux", RT5670_PDM_OUT_CTRL, RT5670_M_PDM1_R_SFT, 1, &rt5670_pdm1_r_mux), - SND_SOC_DAPM_MUX("PDM2 L Mux", RT5670_PDM_OUT_CTRL, - RT5670_M_PDM2_L_SFT, 1, &rt5670_pdm2_l_mux), - SND_SOC_DAPM_MUX("PDM2 R Mux", RT5670_PDM_OUT_CTRL, - RT5670_M_PDM2_R_SFT, 1, &rt5670_pdm2_r_mux), /* Output Lines */ SND_SOC_DAPM_OUTPUT("HPOL"), SND_SOC_DAPM_OUTPUT("HPOR"), SND_SOC_DAPM_OUTPUT("LOUTL"), SND_SOC_DAPM_OUTPUT("LOUTR"), +}; + +static const struct snd_soc_dapm_widget rt5670_specific_dapm_widgets[] = { + SND_SOC_DAPM_SUPPLY("PDM2 Power", RT5670_PWR_DIG2, + RT5670_PWR_PDM2_BIT, 0, NULL, 0), + SND_SOC_DAPM_MUX("PDM2 L Mux", RT5670_PDM_OUT_CTRL, + RT5670_M_PDM2_L_SFT, 1, &rt5670_pdm2_l_mux), + SND_SOC_DAPM_MUX("PDM2 R Mux", RT5670_PDM_OUT_CTRL, + RT5670_M_PDM2_R_SFT, 1, &rt5670_pdm2_r_mux), SND_SOC_DAPM_OUTPUT("PDM1L"), SND_SOC_DAPM_OUTPUT("PDM1R"), SND_SOC_DAPM_OUTPUT("PDM2L"), SND_SOC_DAPM_OUTPUT("PDM2R"), }; +static const struct snd_soc_dapm_widget rt5672_specific_dapm_widgets[] = { + SND_SOC_DAPM_PGA("SPO Amp", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_OUTPUT("SPOLP"), + SND_SOC_DAPM_OUTPUT("SPOLN"), + SND_SOC_DAPM_OUTPUT("SPORP"), + SND_SOC_DAPM_OUTPUT("SPORN"), +}; + static const struct snd_soc_dapm_route rt5670_dapm_routes[] = { { "ADC Stereo1 Filter", NULL, "ADC STO1 ASRC", is_using_asrc }, { "ADC Stereo2 Filter", NULL, "ADC STO2 ASRC", is_using_asrc }, @@ -1970,12 +1981,6 @@ static const struct snd_soc_dapm_route rt5670_dapm_routes[] = { { "PDM1 R Mux", "Stereo DAC", "Stereo DAC MIXR" }, { "PDM1 R Mux", "Mono DAC", "Mono DAC MIXR" }, { "PDM1 R Mux", NULL, "PDM1 Power" }, - { "PDM2 L Mux", "Stereo DAC", "Stereo DAC MIXL" }, - { "PDM2 L Mux", "Mono DAC", "Mono DAC MIXL" }, - { "PDM2 L Mux", NULL, "PDM2 Power" }, - { "PDM2 R Mux", "Stereo DAC", "Stereo DAC MIXR" }, - { "PDM2 R Mux", "Mono DAC", "Mono DAC MIXR" }, - { "PDM2 R Mux", NULL, "PDM2 Power" }, { "HP Amp", NULL, "HPO MIX" }, { "HP Amp", NULL, "Mic Det Power" }, @@ -1993,13 +1998,30 @@ static const struct snd_soc_dapm_route rt5670_dapm_routes[] = { { "LOUTR", NULL, "LOUT R Playback" }, { "LOUTL", NULL, "Improve HP Amp Drv" }, { "LOUTR", NULL, "Improve HP Amp Drv" }, +}; +static const struct snd_soc_dapm_route rt5670_specific_dapm_routes[] = { + { "PDM2 L Mux", "Stereo DAC", "Stereo DAC MIXL" }, + { "PDM2 L Mux", "Mono DAC", "Mono DAC MIXL" }, + { "PDM2 L Mux", NULL, "PDM2 Power" }, + { "PDM2 R Mux", "Stereo DAC", "Stereo DAC MIXR" }, + { "PDM2 R Mux", "Mono DAC", "Mono DAC MIXR" }, + { "PDM2 R Mux", NULL, "PDM2 Power" }, { "PDM1L", NULL, "PDM1 L Mux" }, { "PDM1R", NULL, "PDM1 R Mux" }, { "PDM2L", NULL, "PDM2 L Mux" }, { "PDM2R", NULL, "PDM2 R Mux" }, }; +static const struct snd_soc_dapm_route rt5672_specific_dapm_routes[] = { + { "SPO Amp", NULL, "PDM1 L Mux" }, + { "SPO Amp", NULL, "PDM1 R Mux" }, + { "SPOLP", NULL, "SPO Amp" }, + { "SPOLN", NULL, "SPO Amp" }, + { "SPORP", NULL, "SPO Amp" }, + { "SPORN", NULL, "SPO Amp" }, +}; + static int rt5670_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { @@ -2331,6 +2353,29 @@ static int rt5670_probe(struct snd_soc_codec *codec) { struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); + switch (snd_soc_read(codec, RT5670_RESET) & RT5670_ID_MASK) { + case RT5670_ID_5670: + case RT5670_ID_5671: + snd_soc_dapm_new_controls(&codec->dapm, + rt5670_specific_dapm_widgets, + ARRAY_SIZE(rt5670_specific_dapm_widgets)); + snd_soc_dapm_add_routes(&codec->dapm, + rt5670_specific_dapm_routes, + ARRAY_SIZE(rt5670_specific_dapm_routes)); + break; + case RT5670_ID_5672: + snd_soc_dapm_new_controls(&codec->dapm, + rt5672_specific_dapm_widgets, + ARRAY_SIZE(rt5672_specific_dapm_widgets)); + snd_soc_dapm_add_routes(&codec->dapm, + rt5672_specific_dapm_routes, + ARRAY_SIZE(rt5672_specific_dapm_routes)); + break; + default: + dev_err(codec->dev, + "The driver is for RT5670 RT5671 or RT5672 only\n"); + return -ENODEV; + } rt5670->codec = codec; return 0; @@ -2452,6 +2497,8 @@ static const struct regmap_config rt5670_regmap = { static const struct i2c_device_id rt5670_i2c_id[] = { { "rt5670", 0 }, + { "rt5671", 0 }, + { "rt5672", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, rt5670_i2c_id); diff --git a/sound/soc/codecs/rt5670.h b/sound/soc/codecs/rt5670.h index a0b5c855b492..d11b9c207e26 100644 --- a/sound/soc/codecs/rt5670.h +++ b/sound/soc/codecs/rt5670.h @@ -228,6 +228,12 @@ #define RT5670_R_VOL_MASK (0x3f) #define RT5670_R_VOL_SFT 0 +/* SW Reset & Device ID (0x00) */ +#define RT5670_ID_MASK (0x3 << 1) +#define RT5670_ID_5670 (0x0 << 1) +#define RT5670_ID_5672 (0x1 << 1) +#define RT5670_ID_5671 (0x2 << 1) + /* Combo Jack Control 1 (0x0a) */ #define RT5670_CBJ_BST1_MASK (0xf << 12) #define RT5670_CBJ_BST1_SFT (12) -- cgit v1.2.3 From 5563502cb68d9520e13fe2350922ca88c4531c63 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Tue, 11 Nov 2014 11:31:28 +0800 Subject: ASoC: rt5645: remove unused rt5645_clk_sel_put Remove rt5645_clk_sel_put function since it is never used. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 59 ----------------------------------------------- 1 file changed, 59 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 1dbbebc83d41..665f8b64efe9 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -441,65 +441,6 @@ static SOC_ENUM_SINGLE_DECL(rt5645_tdm_adc_sel_enum, RT5645_TDM_CTRL_1, 8, rt5645_tdm_adc_data_select); -static int rt5645_clk_sel_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - unsigned int u_bit = 0, p_bit = 0; - struct soc_enum *em = - (struct soc_enum *)kcontrol->private_value; - - switch (em->reg) { - case RT5645_ASRC_2: - switch (em->shift_l) { - case 0: - u_bit = 0x8; - p_bit = RT5645_PWR_ADC_S1F; - break; - case 4: - u_bit = 0x100; - p_bit = RT5645_PWR_DAC_MF_R; - break; - case 8: - u_bit = 0x200; - p_bit = RT5645_PWR_DAC_MF_L; - break; - case 12: - u_bit = 0x400; - p_bit = RT5645_PWR_DAC_S1F; - break; - } - break; - case RT5645_ASRC_3: - switch (em->shift_l) { - case 0: - u_bit = 0x1; - p_bit = RT5645_PWR_ADC_MF_R; - break; - case 4: - u_bit = 0x2; - p_bit = RT5645_PWR_ADC_MF_L; - break; - } - break; - } - - if (u_bit || p_bit) { - switch (ucontrol->value.integer.value[0]) { - case 1 ... 4: /*enable*/ - if (snd_soc_read(codec, RT5645_PWR_DIG2) & p_bit) - snd_soc_update_bits(codec, - RT5645_ASRC_1, u_bit, u_bit); - break; - default: /*disable*/ - snd_soc_update_bits(codec, RT5645_ASRC_1, u_bit, 0); - break; - } - } - - return snd_soc_put_enum_double(kcontrol, ucontrol); -} - static const struct snd_kcontrol_new rt5645_snd_controls[] = { /* Speaker Output Volume */ SOC_DOUBLE("Speaker Channel Switch", RT5645_SPK_VOL, -- cgit v1.2.3 From a60e654be733a69879148cb4c56d0f58b749e3c4 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 11 Nov 2014 10:59:00 +0200 Subject: ASoC: tlv320aic3x: Convert SOC_ENUM_SINGLE/DOUBLE arrays to individual It is easier to find the relevant enums in the code. Use the SOC_ENUM_*_DECL macro for the individual items. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic3x.c | 151 +++++++++++++++++++++-------------------- 1 file changed, 79 insertions(+), 72 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 8770e28e53a4..990140058aa6 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -216,61 +216,68 @@ static int mic_bias_event(struct snd_soc_dapm_widget *w, return 0; } -static const char *aic3x_left_dac_mux[] = { "DAC_L1", "DAC_L3", "DAC_L2" }; -static const char *aic3x_right_dac_mux[] = { "DAC_R1", "DAC_R3", "DAC_R2" }; -static const char *aic3x_left_hpcom_mux[] = - { "differential of HPLOUT", "constant VCM", "single-ended" }; -static const char *aic3x_right_hpcom_mux[] = - { "differential of HPROUT", "constant VCM", "single-ended", - "differential of HPLCOM", "external feedback" }; -static const char *aic3x_linein_mode_mux[] = { "single-ended", "differential" }; -static const char *aic3x_adc_hpf[] = - { "Disabled", "0.0045xFs", "0.0125xFs", "0.025xFs" }; - -#define LDAC_ENUM 0 -#define RDAC_ENUM 1 -#define LHPCOM_ENUM 2 -#define RHPCOM_ENUM 3 -#define LINE1L_2_L_ENUM 4 -#define LINE1L_2_R_ENUM 5 -#define LINE1R_2_L_ENUM 6 -#define LINE1R_2_R_ENUM 7 -#define LINE2L_ENUM 8 -#define LINE2R_ENUM 9 -#define ADC_HPF_ENUM 10 - -static const struct soc_enum aic3x_enum[] = { - SOC_ENUM_SINGLE(DAC_LINE_MUX, 6, 3, aic3x_left_dac_mux), - SOC_ENUM_SINGLE(DAC_LINE_MUX, 4, 3, aic3x_right_dac_mux), - SOC_ENUM_SINGLE(HPLCOM_CFG, 4, 3, aic3x_left_hpcom_mux), - SOC_ENUM_SINGLE(HPRCOM_CFG, 3, 5, aic3x_right_hpcom_mux), - SOC_ENUM_SINGLE(LINE1L_2_LADC_CTRL, 7, 2, aic3x_linein_mode_mux), - SOC_ENUM_SINGLE(LINE1L_2_RADC_CTRL, 7, 2, aic3x_linein_mode_mux), - SOC_ENUM_SINGLE(LINE1R_2_LADC_CTRL, 7, 2, aic3x_linein_mode_mux), - SOC_ENUM_SINGLE(LINE1R_2_RADC_CTRL, 7, 2, aic3x_linein_mode_mux), - SOC_ENUM_SINGLE(LINE2L_2_LADC_CTRL, 7, 2, aic3x_linein_mode_mux), - SOC_ENUM_SINGLE(LINE2R_2_RADC_CTRL, 7, 2, aic3x_linein_mode_mux), - SOC_ENUM_DOUBLE(AIC3X_CODEC_DFILT_CTRL, 6, 4, 4, aic3x_adc_hpf), -}; - -static const char *aic3x_agc_level[] = - { "-5.5dB", "-8dB", "-10dB", "-12dB", "-14dB", "-17dB", "-20dB", "-24dB" }; -static const struct soc_enum aic3x_agc_level_enum[] = { - SOC_ENUM_SINGLE(LAGC_CTRL_A, 4, 8, aic3x_agc_level), - SOC_ENUM_SINGLE(RAGC_CTRL_A, 4, 8, aic3x_agc_level), -}; - -static const char *aic3x_agc_attack[] = { "8ms", "11ms", "16ms", "20ms" }; -static const struct soc_enum aic3x_agc_attack_enum[] = { - SOC_ENUM_SINGLE(LAGC_CTRL_A, 2, 4, aic3x_agc_attack), - SOC_ENUM_SINGLE(RAGC_CTRL_A, 2, 4, aic3x_agc_attack), -}; - -static const char *aic3x_agc_decay[] = { "100ms", "200ms", "400ms", "500ms" }; -static const struct soc_enum aic3x_agc_decay_enum[] = { - SOC_ENUM_SINGLE(LAGC_CTRL_A, 0, 4, aic3x_agc_decay), - SOC_ENUM_SINGLE(RAGC_CTRL_A, 0, 4, aic3x_agc_decay), -}; +static const char * const aic3x_left_dac_mux[] = { + "DAC_L1", "DAC_L3", "DAC_L2" }; +static SOC_ENUM_SINGLE_DECL(aic3x_left_dac_enum, DAC_LINE_MUX, 6, + aic3x_left_dac_mux); + +static const char * const aic3x_right_dac_mux[] = { + "DAC_R1", "DAC_R3", "DAC_R2" }; +static SOC_ENUM_SINGLE_DECL(aic3x_right_dac_enum, DAC_LINE_MUX, 4, + aic3x_right_dac_mux); + +static const char * const aic3x_left_hpcom_mux[] = { + "differential of HPLOUT", "constant VCM", "single-ended" }; +static SOC_ENUM_SINGLE_DECL(aic3x_left_hpcom_enum, HPLCOM_CFG, 4, + aic3x_left_hpcom_mux); + +static const char * const aic3x_right_hpcom_mux[] = { + "differential of HPROUT", "constant VCM", "single-ended", + "differential of HPLCOM", "external feedback" }; +static SOC_ENUM_SINGLE_DECL(aic3x_right_hpcom_enum, HPRCOM_CFG, 3, + aic3x_right_hpcom_mux); + +static const char * const aic3x_linein_mode_mux[] = { + "single-ended", "differential" }; +static SOC_ENUM_SINGLE_DECL(aic3x_line1l_2_l_enum, LINE1L_2_LADC_CTRL, 7, + aic3x_linein_mode_mux); +static SOC_ENUM_SINGLE_DECL(aic3x_line1l_2_r_enum, LINE1L_2_RADC_CTRL, 7, + aic3x_linein_mode_mux); +static SOC_ENUM_SINGLE_DECL(aic3x_line1r_2_l_enum, LINE1R_2_LADC_CTRL, 7, + aic3x_linein_mode_mux); +static SOC_ENUM_SINGLE_DECL(aic3x_line1r_2_r_enum, LINE1R_2_RADC_CTRL, 7, + aic3x_linein_mode_mux); +static SOC_ENUM_SINGLE_DECL(aic3x_line2l_2_ldac_enum, LINE2L_2_LADC_CTRL, 7, + aic3x_linein_mode_mux); +static SOC_ENUM_SINGLE_DECL(aic3x_line2r_2_rdac_enum, LINE2R_2_RADC_CTRL, 7, + aic3x_linein_mode_mux); + +static const char * const aic3x_adc_hpf[] = { + "Disabled", "0.0045xFs", "0.0125xFs", "0.025xFs" }; +static SOC_ENUM_DOUBLE_DECL(aic3x_adc_hpf_enum, AIC3X_CODEC_DFILT_CTRL, 6, 4, + aic3x_adc_hpf); + +static const char * const aic3x_agc_level[] = { + "-5.5dB", "-8dB", "-10dB", "-12dB", + "-14dB", "-17dB", "-20dB", "-24dB" }; +static SOC_ENUM_SINGLE_DECL(aic3x_lagc_level_enum, LAGC_CTRL_A, 4, + aic3x_agc_level); +static SOC_ENUM_SINGLE_DECL(aic3x_ragc_level_enum, RAGC_CTRL_A, 4, + aic3x_agc_level); + +static const char * const aic3x_agc_attack[] = { + "8ms", "11ms", "16ms", "20ms" }; +static SOC_ENUM_SINGLE_DECL(aic3x_lagc_attack_enum, LAGC_CTRL_A, 2, + aic3x_agc_attack); +static SOC_ENUM_SINGLE_DECL(aic3x_ragc_attack_enum, RAGC_CTRL_A, 2, + aic3x_agc_attack); + +static const char * const aic3x_agc_decay[] = { + "100ms", "200ms", "400ms", "500ms" }; +static SOC_ENUM_SINGLE_DECL(aic3x_lagc_decay_enum, LAGC_CTRL_A, 0, + aic3x_agc_decay); +static SOC_ENUM_SINGLE_DECL(aic3x_ragc_decay_enum, RAGC_CTRL_A, 0, + aic3x_agc_decay); /* * DAC digital volumes. From -63.5 to 0 dB in 0.5 dB steps @@ -385,12 +392,12 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = { * adjust PGA to max value when ADC is on and will never go back. */ SOC_DOUBLE_R("AGC Switch", LAGC_CTRL_A, RAGC_CTRL_A, 7, 0x01, 0), - SOC_ENUM("Left AGC Target level", aic3x_agc_level_enum[0]), - SOC_ENUM("Right AGC Target level", aic3x_agc_level_enum[1]), - SOC_ENUM("Left AGC Attack time", aic3x_agc_attack_enum[0]), - SOC_ENUM("Right AGC Attack time", aic3x_agc_attack_enum[1]), - SOC_ENUM("Left AGC Decay time", aic3x_agc_decay_enum[0]), - SOC_ENUM("Right AGC Decay time", aic3x_agc_decay_enum[1]), + SOC_ENUM("Left AGC Target level", aic3x_lagc_level_enum), + SOC_ENUM("Right AGC Target level", aic3x_ragc_level_enum), + SOC_ENUM("Left AGC Attack time", aic3x_lagc_attack_enum), + SOC_ENUM("Right AGC Attack time", aic3x_ragc_attack_enum), + SOC_ENUM("Left AGC Decay time", aic3x_lagc_decay_enum), + SOC_ENUM("Right AGC Decay time", aic3x_ragc_decay_enum), /* De-emphasis */ SOC_DOUBLE("De-emphasis Switch", AIC3X_CODEC_DFILT_CTRL, 2, 0, 0x01, 0), @@ -400,7 +407,7 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = { 0, 119, 0, adc_tlv), SOC_DOUBLE_R("PGA Capture Switch", LADC_VOL, RADC_VOL, 7, 0x01, 1), - SOC_ENUM("ADC HPF Cut-off", aic3x_enum[ADC_HPF_ENUM]), + SOC_ENUM("ADC HPF Cut-off", aic3x_adc_hpf_enum), }; static const struct snd_kcontrol_new aic3x_mono_controls[] = { @@ -427,19 +434,19 @@ static const struct snd_kcontrol_new aic3x_classd_amp_gain_ctrl = /* Left DAC Mux */ static const struct snd_kcontrol_new aic3x_left_dac_mux_controls = -SOC_DAPM_ENUM("Route", aic3x_enum[LDAC_ENUM]); +SOC_DAPM_ENUM("Route", aic3x_left_dac_enum); /* Right DAC Mux */ static const struct snd_kcontrol_new aic3x_right_dac_mux_controls = -SOC_DAPM_ENUM("Route", aic3x_enum[RDAC_ENUM]); +SOC_DAPM_ENUM("Route", aic3x_right_dac_enum); /* Left HPCOM Mux */ static const struct snd_kcontrol_new aic3x_left_hpcom_mux_controls = -SOC_DAPM_ENUM("Route", aic3x_enum[LHPCOM_ENUM]); +SOC_DAPM_ENUM("Route", aic3x_left_hpcom_enum); /* Right HPCOM Mux */ static const struct snd_kcontrol_new aic3x_right_hpcom_mux_controls = -SOC_DAPM_ENUM("Route", aic3x_enum[RHPCOM_ENUM]); +SOC_DAPM_ENUM("Route", aic3x_right_hpcom_enum); /* Left Line Mixer */ static const struct snd_kcontrol_new aic3x_left_line_mixer_controls[] = { @@ -531,23 +538,23 @@ static const struct snd_kcontrol_new aic3x_right_pga_mixer_controls[] = { /* Left Line1 Mux */ static const struct snd_kcontrol_new aic3x_left_line1l_mux_controls = -SOC_DAPM_ENUM("Route", aic3x_enum[LINE1L_2_L_ENUM]); +SOC_DAPM_ENUM("Route", aic3x_line1l_2_l_enum); static const struct snd_kcontrol_new aic3x_right_line1l_mux_controls = -SOC_DAPM_ENUM("Route", aic3x_enum[LINE1L_2_R_ENUM]); +SOC_DAPM_ENUM("Route", aic3x_line1l_2_r_enum); /* Right Line1 Mux */ static const struct snd_kcontrol_new aic3x_right_line1r_mux_controls = -SOC_DAPM_ENUM("Route", aic3x_enum[LINE1R_2_R_ENUM]); +SOC_DAPM_ENUM("Route", aic3x_line1r_2_r_enum); static const struct snd_kcontrol_new aic3x_left_line1r_mux_controls = -SOC_DAPM_ENUM("Route", aic3x_enum[LINE1R_2_L_ENUM]); +SOC_DAPM_ENUM("Route", aic3x_line1r_2_l_enum); /* Left Line2 Mux */ static const struct snd_kcontrol_new aic3x_left_line2_mux_controls = -SOC_DAPM_ENUM("Route", aic3x_enum[LINE2L_ENUM]); +SOC_DAPM_ENUM("Route", aic3x_line2l_2_ldac_enum); /* Right Line2 Mux */ static const struct snd_kcontrol_new aic3x_right_line2_mux_controls = -SOC_DAPM_ENUM("Route", aic3x_enum[LINE2R_ENUM]); +SOC_DAPM_ENUM("Route", aic3x_line2r_2_rdac_enum); static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { /* Left DAC to Left Outputs */ -- cgit v1.2.3 From 68d6626925c3529790a2055d41578415fa98495e Mon Sep 17 00:00:00 2001 From: Misael Lopez Cruz Date: Tue, 11 Nov 2014 10:59:01 +0200 Subject: ASoC: tlv320aic3x: Add output driver pop reduction controls Output driver has two parameters that can be configured to reduce pop noise: power-on delay and ramp-up step time. Two new kcontrols have been added to set these parameters. Signed-off-by: Misael Lopez Cruz Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic3x.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 990140058aa6..f0a828119aba 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -279,6 +279,16 @@ static SOC_ENUM_SINGLE_DECL(aic3x_lagc_decay_enum, LAGC_CTRL_A, 0, static SOC_ENUM_SINGLE_DECL(aic3x_ragc_decay_enum, RAGC_CTRL_A, 0, aic3x_agc_decay); +static const char * const aic3x_poweron_time[] = { + "0us", "10us", "100us", "1ms", "10ms", "50ms", + "100ms", "200ms", "400ms", "800ms", "2s", "4s" }; +static SOC_ENUM_SINGLE_DECL(aic3x_poweron_time_enum, HPOUT_POP_REDUCTION, 4, + aic3x_poweron_time); + +static const char * const aic3x_rampup_step[] = { "0ms", "1ms", "2ms", "4ms" }; +static SOC_ENUM_SINGLE_DECL(aic3x_rampup_step_enum, HPOUT_POP_REDUCTION, 2, + aic3x_rampup_step); + /* * DAC digital volumes. From -63.5 to 0 dB in 0.5 dB steps */ @@ -408,6 +418,10 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = { SOC_DOUBLE_R("PGA Capture Switch", LADC_VOL, RADC_VOL, 7, 0x01, 1), SOC_ENUM("ADC HPF Cut-off", aic3x_adc_hpf_enum), + + /* Pop reduction */ + SOC_ENUM("Output Driver Power-On time", aic3x_poweron_time_enum), + SOC_ENUM("Output Driver Ramp-up step", aic3x_rampup_step_enum), }; static const struct snd_kcontrol_new aic3x_mono_controls[] = { -- cgit v1.2.3 From 91159ecaf4401f7b4b0d48f59c877a0779209af5 Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Tue, 11 Nov 2014 15:31:19 +0800 Subject: ASoC: rt5677: Add TDM channel mux in DAC side of IF1 and IF2 It is the slot selection in DAC side of IF1 and IF2. Signed-off-by: Oder Chiou Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677.c | 330 +++++++++++++++++++++++++++++++++++++++++++--- sound/soc/codecs/rt5677.h | 48 ++++++- 2 files changed, 358 insertions(+), 20 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 4b6f7d57c1bb..5d317c68ca4e 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -1906,6 +1906,126 @@ static SOC_ENUM_SINGLE_DECL( static const struct snd_kcontrol_new rt5677_if2_adc_tdm_swap_mux = SOC_DAPM_ENUM("IF2 ADC TDM Swap Source", rt5677_if2_adc_tdm_swap_enum); +/* TDM IF1/2 DAC Data Selection */ /* MX-3E[14:12][10:8][6:4][2:0] + MX-3F[14:12][10:8][6:4][2:0] + MX-43[14:12][10:8][6:4][2:0] + MX-44[14:12][10:8][6:4][2:0] */ +static const char * const rt5677_if12_dac_tdm_sel_src[] = { + "Slot0", "Slot1", "Slot2", "Slot3", "Slot4", "Slot5", "Slot6", "Slot7" +}; + +static SOC_ENUM_SINGLE_DECL( + rt5677_if1_dac0_tdm_sel_enum, RT5677_TDM1_CTRL4, + RT5677_IF1_DAC0_SFT, rt5677_if12_dac_tdm_sel_src); + +static const struct snd_kcontrol_new rt5677_if1_dac0_tdm_sel_mux = + SOC_DAPM_ENUM("IF1 DAC0 TDM Source", rt5677_if1_dac0_tdm_sel_enum); + +static SOC_ENUM_SINGLE_DECL( + rt5677_if1_dac1_tdm_sel_enum, RT5677_TDM1_CTRL4, + RT5677_IF1_DAC1_SFT, rt5677_if12_dac_tdm_sel_src); + +static const struct snd_kcontrol_new rt5677_if1_dac1_tdm_sel_mux = + SOC_DAPM_ENUM("IF1 DAC1 TDM Source", rt5677_if1_dac1_tdm_sel_enum); + +static SOC_ENUM_SINGLE_DECL( + rt5677_if1_dac2_tdm_sel_enum, RT5677_TDM1_CTRL4, + RT5677_IF1_DAC2_SFT, rt5677_if12_dac_tdm_sel_src); + +static const struct snd_kcontrol_new rt5677_if1_dac2_tdm_sel_mux = + SOC_DAPM_ENUM("IF1 DAC2 TDM Source", rt5677_if1_dac2_tdm_sel_enum); + +static SOC_ENUM_SINGLE_DECL( + rt5677_if1_dac3_tdm_sel_enum, RT5677_TDM1_CTRL4, + RT5677_IF1_DAC3_SFT, rt5677_if12_dac_tdm_sel_src); + +static const struct snd_kcontrol_new rt5677_if1_dac3_tdm_sel_mux = + SOC_DAPM_ENUM("IF1 DAC3 TDM Source", rt5677_if1_dac3_tdm_sel_enum); + +static SOC_ENUM_SINGLE_DECL( + rt5677_if1_dac4_tdm_sel_enum, RT5677_TDM1_CTRL5, + RT5677_IF1_DAC4_SFT, rt5677_if12_dac_tdm_sel_src); + +static const struct snd_kcontrol_new rt5677_if1_dac4_tdm_sel_mux = + SOC_DAPM_ENUM("IF1 DAC4 TDM Source", rt5677_if1_dac4_tdm_sel_enum); + +static SOC_ENUM_SINGLE_DECL( + rt5677_if1_dac5_tdm_sel_enum, RT5677_TDM1_CTRL5, + RT5677_IF1_DAC5_SFT, rt5677_if12_dac_tdm_sel_src); + +static const struct snd_kcontrol_new rt5677_if1_dac5_tdm_sel_mux = + SOC_DAPM_ENUM("IF1 DAC5 TDM Source", rt5677_if1_dac5_tdm_sel_enum); + +static SOC_ENUM_SINGLE_DECL( + rt5677_if1_dac6_tdm_sel_enum, RT5677_TDM1_CTRL5, + RT5677_IF1_DAC6_SFT, rt5677_if12_dac_tdm_sel_src); + +static const struct snd_kcontrol_new rt5677_if1_dac6_tdm_sel_mux = + SOC_DAPM_ENUM("IF1 DAC6 TDM Source", rt5677_if1_dac6_tdm_sel_enum); + +static SOC_ENUM_SINGLE_DECL( + rt5677_if1_dac7_tdm_sel_enum, RT5677_TDM1_CTRL5, + RT5677_IF1_DAC7_SFT, rt5677_if12_dac_tdm_sel_src); + +static const struct snd_kcontrol_new rt5677_if1_dac7_tdm_sel_mux = + SOC_DAPM_ENUM("IF1 DAC7 TDM Source", rt5677_if1_dac7_tdm_sel_enum); + +static SOC_ENUM_SINGLE_DECL( + rt5677_if2_dac0_tdm_sel_enum, RT5677_TDM2_CTRL4, + RT5677_IF2_DAC0_SFT, rt5677_if12_dac_tdm_sel_src); + +static const struct snd_kcontrol_new rt5677_if2_dac0_tdm_sel_mux = + SOC_DAPM_ENUM("IF2 DAC0 TDM Source", rt5677_if2_dac0_tdm_sel_enum); + +static SOC_ENUM_SINGLE_DECL( + rt5677_if2_dac1_tdm_sel_enum, RT5677_TDM2_CTRL4, + RT5677_IF2_DAC1_SFT, rt5677_if12_dac_tdm_sel_src); + +static const struct snd_kcontrol_new rt5677_if2_dac1_tdm_sel_mux = + SOC_DAPM_ENUM("IF2 DAC1 TDM Source", rt5677_if2_dac1_tdm_sel_enum); + +static SOC_ENUM_SINGLE_DECL( + rt5677_if2_dac2_tdm_sel_enum, RT5677_TDM2_CTRL4, + RT5677_IF2_DAC2_SFT, rt5677_if12_dac_tdm_sel_src); + +static const struct snd_kcontrol_new rt5677_if2_dac2_tdm_sel_mux = + SOC_DAPM_ENUM("IF2 DAC2 TDM Source", rt5677_if2_dac2_tdm_sel_enum); + +static SOC_ENUM_SINGLE_DECL( + rt5677_if2_dac3_tdm_sel_enum, RT5677_TDM2_CTRL4, + RT5677_IF2_DAC3_SFT, rt5677_if12_dac_tdm_sel_src); + +static const struct snd_kcontrol_new rt5677_if2_dac3_tdm_sel_mux = + SOC_DAPM_ENUM("IF2 DAC3 TDM Source", rt5677_if2_dac3_tdm_sel_enum); + +static SOC_ENUM_SINGLE_DECL( + rt5677_if2_dac4_tdm_sel_enum, RT5677_TDM2_CTRL5, + RT5677_IF2_DAC4_SFT, rt5677_if12_dac_tdm_sel_src); + +static const struct snd_kcontrol_new rt5677_if2_dac4_tdm_sel_mux = + SOC_DAPM_ENUM("IF2 DAC4 TDM Source", rt5677_if2_dac4_tdm_sel_enum); + +static SOC_ENUM_SINGLE_DECL( + rt5677_if2_dac5_tdm_sel_enum, RT5677_TDM2_CTRL5, + RT5677_IF2_DAC5_SFT, rt5677_if12_dac_tdm_sel_src); + +static const struct snd_kcontrol_new rt5677_if2_dac5_tdm_sel_mux = + SOC_DAPM_ENUM("IF2 DAC5 TDM Source", rt5677_if2_dac5_tdm_sel_enum); + +static SOC_ENUM_SINGLE_DECL( + rt5677_if2_dac6_tdm_sel_enum, RT5677_TDM2_CTRL5, + RT5677_IF2_DAC6_SFT, rt5677_if12_dac_tdm_sel_src); + +static const struct snd_kcontrol_new rt5677_if2_dac6_tdm_sel_mux = + SOC_DAPM_ENUM("IF2 DAC6 TDM Source", rt5677_if2_dac6_tdm_sel_enum); + +static SOC_ENUM_SINGLE_DECL( + rt5677_if2_dac7_tdm_sel_enum, RT5677_TDM2_CTRL5, + RT5677_IF2_DAC7_SFT, rt5677_if12_dac_tdm_sel_src); + +static const struct snd_kcontrol_new rt5677_if2_dac7_tdm_sel_mux = + SOC_DAPM_ENUM("IF2 DAC7 TDM Source", rt5677_if2_dac7_tdm_sel_enum); + static int rt5677_bst1_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { @@ -2389,6 +2509,40 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = { SND_SOC_DAPM_MUX("SLB ADC4 Mux", SND_SOC_NOPM, 0, 0, &rt5677_slb_adc4_mux), + SND_SOC_DAPM_MUX("IF1 DAC0 Mux", SND_SOC_NOPM, 0, 0, + &rt5677_if1_dac0_tdm_sel_mux), + SND_SOC_DAPM_MUX("IF1 DAC1 Mux", SND_SOC_NOPM, 0, 0, + &rt5677_if1_dac1_tdm_sel_mux), + SND_SOC_DAPM_MUX("IF1 DAC2 Mux", SND_SOC_NOPM, 0, 0, + &rt5677_if1_dac2_tdm_sel_mux), + SND_SOC_DAPM_MUX("IF1 DAC3 Mux", SND_SOC_NOPM, 0, 0, + &rt5677_if1_dac3_tdm_sel_mux), + SND_SOC_DAPM_MUX("IF1 DAC4 Mux", SND_SOC_NOPM, 0, 0, + &rt5677_if1_dac4_tdm_sel_mux), + SND_SOC_DAPM_MUX("IF1 DAC5 Mux", SND_SOC_NOPM, 0, 0, + &rt5677_if1_dac5_tdm_sel_mux), + SND_SOC_DAPM_MUX("IF1 DAC6 Mux", SND_SOC_NOPM, 0, 0, + &rt5677_if1_dac6_tdm_sel_mux), + SND_SOC_DAPM_MUX("IF1 DAC7 Mux", SND_SOC_NOPM, 0, 0, + &rt5677_if1_dac7_tdm_sel_mux), + + SND_SOC_DAPM_MUX("IF2 DAC0 Mux", SND_SOC_NOPM, 0, 0, + &rt5677_if2_dac0_tdm_sel_mux), + SND_SOC_DAPM_MUX("IF2 DAC1 Mux", SND_SOC_NOPM, 0, 0, + &rt5677_if2_dac1_tdm_sel_mux), + SND_SOC_DAPM_MUX("IF2 DAC2 Mux", SND_SOC_NOPM, 0, 0, + &rt5677_if2_dac2_tdm_sel_mux), + SND_SOC_DAPM_MUX("IF2 DAC3 Mux", SND_SOC_NOPM, 0, 0, + &rt5677_if2_dac3_tdm_sel_mux), + SND_SOC_DAPM_MUX("IF2 DAC4 Mux", SND_SOC_NOPM, 0, 0, + &rt5677_if2_dac4_tdm_sel_mux), + SND_SOC_DAPM_MUX("IF2 DAC5 Mux", SND_SOC_NOPM, 0, 0, + &rt5677_if2_dac5_tdm_sel_mux), + SND_SOC_DAPM_MUX("IF2 DAC6 Mux", SND_SOC_NOPM, 0, 0, + &rt5677_if2_dac6_tdm_sel_mux), + SND_SOC_DAPM_MUX("IF2 DAC7 Mux", SND_SOC_NOPM, 0, 0, + &rt5677_if2_dac7_tdm_sel_mux), + /* Audio Interface */ SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0), @@ -3036,14 +3190,86 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { { "IF1 DAC6", NULL, "I2S1" }, { "IF1 DAC7", NULL, "I2S1" }, - { "IF1 DAC01", NULL, "IF1 DAC0" }, - { "IF1 DAC01", NULL, "IF1 DAC1" }, - { "IF1 DAC23", NULL, "IF1 DAC2" }, - { "IF1 DAC23", NULL, "IF1 DAC3" }, - { "IF1 DAC45", NULL, "IF1 DAC4" }, - { "IF1 DAC45", NULL, "IF1 DAC5" }, - { "IF1 DAC67", NULL, "IF1 DAC6" }, - { "IF1 DAC67", NULL, "IF1 DAC7" }, + { "IF1 DAC0 Mux", "Slot0", "IF1 DAC0" }, + { "IF1 DAC0 Mux", "Slot1", "IF1 DAC1" }, + { "IF1 DAC0 Mux", "Slot2", "IF1 DAC2" }, + { "IF1 DAC0 Mux", "Slot3", "IF1 DAC3" }, + { "IF1 DAC0 Mux", "Slot4", "IF1 DAC4" }, + { "IF1 DAC0 Mux", "Slot5", "IF1 DAC5" }, + { "IF1 DAC0 Mux", "Slot6", "IF1 DAC6" }, + { "IF1 DAC0 Mux", "Slot7", "IF1 DAC7" }, + + { "IF1 DAC1 Mux", "Slot0", "IF1 DAC0" }, + { "IF1 DAC1 Mux", "Slot1", "IF1 DAC1" }, + { "IF1 DAC1 Mux", "Slot2", "IF1 DAC2" }, + { "IF1 DAC1 Mux", "Slot3", "IF1 DAC3" }, + { "IF1 DAC1 Mux", "Slot4", "IF1 DAC4" }, + { "IF1 DAC1 Mux", "Slot5", "IF1 DAC5" }, + { "IF1 DAC1 Mux", "Slot6", "IF1 DAC6" }, + { "IF1 DAC1 Mux", "Slot7", "IF1 DAC7" }, + + { "IF1 DAC2 Mux", "Slot0", "IF1 DAC0" }, + { "IF1 DAC2 Mux", "Slot1", "IF1 DAC1" }, + { "IF1 DAC2 Mux", "Slot2", "IF1 DAC2" }, + { "IF1 DAC2 Mux", "Slot3", "IF1 DAC3" }, + { "IF1 DAC2 Mux", "Slot4", "IF1 DAC4" }, + { "IF1 DAC2 Mux", "Slot5", "IF1 DAC5" }, + { "IF1 DAC2 Mux", "Slot6", "IF1 DAC6" }, + { "IF1 DAC2 Mux", "Slot7", "IF1 DAC7" }, + + { "IF1 DAC3 Mux", "Slot0", "IF1 DAC0" }, + { "IF1 DAC3 Mux", "Slot1", "IF1 DAC1" }, + { "IF1 DAC3 Mux", "Slot2", "IF1 DAC2" }, + { "IF1 DAC3 Mux", "Slot3", "IF1 DAC3" }, + { "IF1 DAC3 Mux", "Slot4", "IF1 DAC4" }, + { "IF1 DAC3 Mux", "Slot5", "IF1 DAC5" }, + { "IF1 DAC3 Mux", "Slot6", "IF1 DAC6" }, + { "IF1 DAC3 Mux", "Slot7", "IF1 DAC7" }, + + { "IF1 DAC4 Mux", "Slot0", "IF1 DAC0" }, + { "IF1 DAC4 Mux", "Slot1", "IF1 DAC1" }, + { "IF1 DAC4 Mux", "Slot2", "IF1 DAC2" }, + { "IF1 DAC4 Mux", "Slot3", "IF1 DAC3" }, + { "IF1 DAC4 Mux", "Slot4", "IF1 DAC4" }, + { "IF1 DAC4 Mux", "Slot5", "IF1 DAC5" }, + { "IF1 DAC4 Mux", "Slot6", "IF1 DAC6" }, + { "IF1 DAC4 Mux", "Slot7", "IF1 DAC7" }, + + { "IF1 DAC5 Mux", "Slot0", "IF1 DAC0" }, + { "IF1 DAC5 Mux", "Slot1", "IF1 DAC1" }, + { "IF1 DAC5 Mux", "Slot2", "IF1 DAC2" }, + { "IF1 DAC5 Mux", "Slot3", "IF1 DAC3" }, + { "IF1 DAC5 Mux", "Slot4", "IF1 DAC4" }, + { "IF1 DAC5 Mux", "Slot5", "IF1 DAC5" }, + { "IF1 DAC5 Mux", "Slot6", "IF1 DAC6" }, + { "IF1 DAC5 Mux", "Slot7", "IF1 DAC7" }, + + { "IF1 DAC6 Mux", "Slot0", "IF1 DAC0" }, + { "IF1 DAC6 Mux", "Slot1", "IF1 DAC1" }, + { "IF1 DAC6 Mux", "Slot2", "IF1 DAC2" }, + { "IF1 DAC6 Mux", "Slot3", "IF1 DAC3" }, + { "IF1 DAC6 Mux", "Slot4", "IF1 DAC4" }, + { "IF1 DAC6 Mux", "Slot5", "IF1 DAC5" }, + { "IF1 DAC6 Mux", "Slot6", "IF1 DAC6" }, + { "IF1 DAC6 Mux", "Slot7", "IF1 DAC7" }, + + { "IF1 DAC7 Mux", "Slot0", "IF1 DAC0" }, + { "IF1 DAC7 Mux", "Slot1", "IF1 DAC1" }, + { "IF1 DAC7 Mux", "Slot2", "IF1 DAC2" }, + { "IF1 DAC7 Mux", "Slot3", "IF1 DAC3" }, + { "IF1 DAC7 Mux", "Slot4", "IF1 DAC4" }, + { "IF1 DAC7 Mux", "Slot5", "IF1 DAC5" }, + { "IF1 DAC7 Mux", "Slot6", "IF1 DAC6" }, + { "IF1 DAC7 Mux", "Slot7", "IF1 DAC7" }, + + { "IF1 DAC01", NULL, "IF1 DAC0 Mux" }, + { "IF1 DAC01", NULL, "IF1 DAC1 Mux" }, + { "IF1 DAC23", NULL, "IF1 DAC2 Mux" }, + { "IF1 DAC23", NULL, "IF1 DAC3 Mux" }, + { "IF1 DAC45", NULL, "IF1 DAC4 Mux" }, + { "IF1 DAC45", NULL, "IF1 DAC5 Mux" }, + { "IF1 DAC67", NULL, "IF1 DAC6 Mux" }, + { "IF1 DAC67", NULL, "IF1 DAC7 Mux" }, { "IF2 DAC0", NULL, "AIF2RX" }, { "IF2 DAC1", NULL, "AIF2RX" }, @@ -3062,14 +3288,86 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { { "IF2 DAC6", NULL, "I2S2" }, { "IF2 DAC7", NULL, "I2S2" }, - { "IF2 DAC01", NULL, "IF2 DAC0" }, - { "IF2 DAC01", NULL, "IF2 DAC1" }, - { "IF2 DAC23", NULL, "IF2 DAC2" }, - { "IF2 DAC23", NULL, "IF2 DAC3" }, - { "IF2 DAC45", NULL, "IF2 DAC4" }, - { "IF2 DAC45", NULL, "IF2 DAC5" }, - { "IF2 DAC67", NULL, "IF2 DAC6" }, - { "IF2 DAC67", NULL, "IF2 DAC7" }, + { "IF2 DAC0 Mux", "Slot0", "IF2 DAC0" }, + { "IF2 DAC0 Mux", "Slot1", "IF2 DAC1" }, + { "IF2 DAC0 Mux", "Slot2", "IF2 DAC2" }, + { "IF2 DAC0 Mux", "Slot3", "IF2 DAC3" }, + { "IF2 DAC0 Mux", "Slot4", "IF2 DAC4" }, + { "IF2 DAC0 Mux", "Slot5", "IF2 DAC5" }, + { "IF2 DAC0 Mux", "Slot6", "IF2 DAC6" }, + { "IF2 DAC0 Mux", "Slot7", "IF2 DAC7" }, + + { "IF2 DAC1 Mux", "Slot0", "IF2 DAC0" }, + { "IF2 DAC1 Mux", "Slot1", "IF2 DAC1" }, + { "IF2 DAC1 Mux", "Slot2", "IF2 DAC2" }, + { "IF2 DAC1 Mux", "Slot3", "IF2 DAC3" }, + { "IF2 DAC1 Mux", "Slot4", "IF2 DAC4" }, + { "IF2 DAC1 Mux", "Slot5", "IF2 DAC5" }, + { "IF2 DAC1 Mux", "Slot6", "IF2 DAC6" }, + { "IF2 DAC1 Mux", "Slot7", "IF2 DAC7" }, + + { "IF2 DAC2 Mux", "Slot0", "IF2 DAC0" }, + { "IF2 DAC2 Mux", "Slot1", "IF2 DAC1" }, + { "IF2 DAC2 Mux", "Slot2", "IF2 DAC2" }, + { "IF2 DAC2 Mux", "Slot3", "IF2 DAC3" }, + { "IF2 DAC2 Mux", "Slot4", "IF2 DAC4" }, + { "IF2 DAC2 Mux", "Slot5", "IF2 DAC5" }, + { "IF2 DAC2 Mux", "Slot6", "IF2 DAC6" }, + { "IF2 DAC2 Mux", "Slot7", "IF2 DAC7" }, + + { "IF2 DAC3 Mux", "Slot0", "IF2 DAC0" }, + { "IF2 DAC3 Mux", "Slot1", "IF2 DAC1" }, + { "IF2 DAC3 Mux", "Slot2", "IF2 DAC2" }, + { "IF2 DAC3 Mux", "Slot3", "IF2 DAC3" }, + { "IF2 DAC3 Mux", "Slot4", "IF2 DAC4" }, + { "IF2 DAC3 Mux", "Slot5", "IF2 DAC5" }, + { "IF2 DAC3 Mux", "Slot6", "IF2 DAC6" }, + { "IF2 DAC3 Mux", "Slot7", "IF2 DAC7" }, + + { "IF2 DAC4 Mux", "Slot0", "IF2 DAC0" }, + { "IF2 DAC4 Mux", "Slot1", "IF2 DAC1" }, + { "IF2 DAC4 Mux", "Slot2", "IF2 DAC2" }, + { "IF2 DAC4 Mux", "Slot3", "IF2 DAC3" }, + { "IF2 DAC4 Mux", "Slot4", "IF2 DAC4" }, + { "IF2 DAC4 Mux", "Slot5", "IF2 DAC5" }, + { "IF2 DAC4 Mux", "Slot6", "IF2 DAC6" }, + { "IF2 DAC4 Mux", "Slot7", "IF2 DAC7" }, + + { "IF2 DAC5 Mux", "Slot0", "IF2 DAC0" }, + { "IF2 DAC5 Mux", "Slot1", "IF2 DAC1" }, + { "IF2 DAC5 Mux", "Slot2", "IF2 DAC2" }, + { "IF2 DAC5 Mux", "Slot3", "IF2 DAC3" }, + { "IF2 DAC5 Mux", "Slot4", "IF2 DAC4" }, + { "IF2 DAC5 Mux", "Slot5", "IF2 DAC5" }, + { "IF2 DAC5 Mux", "Slot6", "IF2 DAC6" }, + { "IF2 DAC5 Mux", "Slot7", "IF2 DAC7" }, + + { "IF2 DAC6 Mux", "Slot0", "IF2 DAC0" }, + { "IF2 DAC6 Mux", "Slot1", "IF2 DAC1" }, + { "IF2 DAC6 Mux", "Slot2", "IF2 DAC2" }, + { "IF2 DAC6 Mux", "Slot3", "IF2 DAC3" }, + { "IF2 DAC6 Mux", "Slot4", "IF2 DAC4" }, + { "IF2 DAC6 Mux", "Slot5", "IF2 DAC5" }, + { "IF2 DAC6 Mux", "Slot6", "IF2 DAC6" }, + { "IF2 DAC6 Mux", "Slot7", "IF2 DAC7" }, + + { "IF2 DAC7 Mux", "Slot0", "IF2 DAC0" }, + { "IF2 DAC7 Mux", "Slot1", "IF2 DAC1" }, + { "IF2 DAC7 Mux", "Slot2", "IF2 DAC2" }, + { "IF2 DAC7 Mux", "Slot3", "IF2 DAC3" }, + { "IF2 DAC7 Mux", "Slot4", "IF2 DAC4" }, + { "IF2 DAC7 Mux", "Slot5", "IF2 DAC5" }, + { "IF2 DAC7 Mux", "Slot6", "IF2 DAC6" }, + { "IF2 DAC7 Mux", "Slot7", "IF2 DAC7" }, + + { "IF2 DAC01", NULL, "IF2 DAC0 Mux" }, + { "IF2 DAC01", NULL, "IF2 DAC1 Mux" }, + { "IF2 DAC23", NULL, "IF2 DAC2 Mux" }, + { "IF2 DAC23", NULL, "IF2 DAC3 Mux" }, + { "IF2 DAC45", NULL, "IF2 DAC4 Mux" }, + { "IF2 DAC45", NULL, "IF2 DAC5 Mux" }, + { "IF2 DAC67", NULL, "IF2 DAC6 Mux" }, + { "IF2 DAC67", NULL, "IF2 DAC7 Mux" }, { "IF3 DAC", NULL, "AIF3RX" }, { "IF3 DAC", NULL, "I2S3" }, diff --git a/sound/soc/codecs/rt5677.h b/sound/soc/codecs/rt5677.h index 9d473b2798d5..2979d5a05789 100644 --- a/sound/soc/codecs/rt5677.h +++ b/sound/soc/codecs/rt5677.h @@ -799,7 +799,7 @@ #define RT5677_PDM2_I2C_EXE (0x1 << 1) #define RT5677_PDM2_I2C_BUSY (0x1 << 0) -/* MX3B TDM1 control 1 (0x3b) */ +/* TDM1 control 1 (0x3b) */ #define RT5677_IF1_ADC_MODE_MASK (0x1 << 12) #define RT5677_IF1_ADC_MODE_SFT 12 #define RT5677_IF1_ADC_MODE_I2S (0x0 << 12) @@ -813,7 +813,7 @@ #define RT5677_IF1_ADC4_SWAP_MASK (0x3 << 0) #define RT5677_IF1_ADC4_SWAP_SFT 0 -/* MX3C TDM1 control 2 (0x3c) */ +/* TDM1 control 2 (0x3c) */ #define RT5677_IF1_ADC4_MASK (0x3 << 10) #define RT5677_IF1_ADC4_SFT 10 #define RT5677_IF1_ADC3_MASK (0x3 << 8) @@ -825,7 +825,27 @@ #define RT5677_IF1_ADC_CTRL_MASK (0x7 << 0) #define RT5677_IF1_ADC_CTRL_SFT 0 -/* MX40 TDM2 control 1 (0x40) */ +/* TDM1 control 4 (0x3e) */ +#define RT5677_IF1_DAC0_MASK (0x7 << 12) +#define RT5677_IF1_DAC0_SFT 12 +#define RT5677_IF1_DAC1_MASK (0x7 << 8) +#define RT5677_IF1_DAC1_SFT 8 +#define RT5677_IF1_DAC2_MASK (0x7 << 4) +#define RT5677_IF1_DAC2_SFT 4 +#define RT5677_IF1_DAC3_MASK (0x7 << 0) +#define RT5677_IF1_DAC3_SFT 0 + +/* TDM1 control 5 (0x3f) */ +#define RT5677_IF1_DAC4_MASK (0x7 << 12) +#define RT5677_IF1_DAC4_SFT 12 +#define RT5677_IF1_DAC5_MASK (0x7 << 8) +#define RT5677_IF1_DAC5_SFT 8 +#define RT5677_IF1_DAC6_MASK (0x7 << 4) +#define RT5677_IF1_DAC6_SFT 4 +#define RT5677_IF1_DAC7_MASK (0x7 << 0) +#define RT5677_IF1_DAC7_SFT 0 + +/* TDM2 control 1 (0x40) */ #define RT5677_IF2_ADC_MODE_MASK (0x1 << 12) #define RT5677_IF2_ADC_MODE_SFT 12 #define RT5677_IF2_ADC_MODE_I2S (0x0 << 12) @@ -839,7 +859,7 @@ #define RT5677_IF2_ADC4_SWAP_MASK (0x3 << 0) #define RT5677_IF2_ADC4_SWAP_SFT 0 -/* MX41 TDM2 control 2 (0x41) */ +/* TDM2 control 2 (0x41) */ #define RT5677_IF2_ADC4_MASK (0x3 << 10) #define RT5677_IF2_ADC4_SFT 10 #define RT5677_IF2_ADC3_MASK (0x3 << 8) @@ -851,6 +871,26 @@ #define RT5677_IF2_ADC_CTRL_MASK (0x7 << 0) #define RT5677_IF2_ADC_CTRL_SFT 0 +/* TDM2 control 4 (0x43) */ +#define RT5677_IF2_DAC0_MASK (0x7 << 12) +#define RT5677_IF2_DAC0_SFT 12 +#define RT5677_IF2_DAC1_MASK (0x7 << 8) +#define RT5677_IF2_DAC1_SFT 8 +#define RT5677_IF2_DAC2_MASK (0x7 << 4) +#define RT5677_IF2_DAC2_SFT 4 +#define RT5677_IF2_DAC3_MASK (0x7 << 0) +#define RT5677_IF2_DAC3_SFT 0 + +/* TDM2 control 5 (0x44) */ +#define RT5677_IF2_DAC4_MASK (0x7 << 12) +#define RT5677_IF2_DAC4_SFT 12 +#define RT5677_IF2_DAC5_MASK (0x7 << 8) +#define RT5677_IF2_DAC5_SFT 8 +#define RT5677_IF2_DAC6_MASK (0x7 << 4) +#define RT5677_IF2_DAC6_SFT 4 +#define RT5677_IF2_DAC7_MASK (0x7 << 0) +#define RT5677_IF2_DAC7_SFT 0 + /* Digital Microphone Control 1 (0x50) */ #define RT5677_DMIC_1_EN_MASK (0x1 << 15) #define RT5677_DMIC_1_EN_SFT 15 -- cgit v1.2.3 From ef326f4bb2675e9309ba318b19442d9823e58ee2 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 12 Nov 2014 14:55:26 +0000 Subject: ASoC: arizona: Add support for 768kHz DMIC operation The new IPs supports a new lower frequency 768kHz DMIC operation add support for this into the OSR control. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 0c05e7a7945f..786464f5a23c 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -648,7 +648,7 @@ SOC_ENUM_SINGLE_DECL(arizona_in_hpf_cut_enum, EXPORT_SYMBOL_GPL(arizona_in_hpf_cut_enum); static const char * const arizona_in_dmic_osr_text[] = { - "1.536MHz", "3.072MHz", "6.144MHz", + "1.536MHz", "3.072MHz", "6.144MHz", "768kHz", }; const struct soc_enum arizona_in_dmic_osr[] = { -- cgit v1.2.3 From e9c7f34a7eba13e1a53212246c607d13574f9eff Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Wed, 12 Nov 2014 16:12:46 +0000 Subject: ASoC: arizona: Add DSP_B and LEFT_J mode support Signed-off-by: Richard Fitzgerald Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 786464f5a23c..19887bfffbf9 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -61,6 +61,11 @@ #define ARIZONA_FLL_MIN_OUTDIV 2 #define ARIZONA_FLL_MAX_OUTDIV 7 +#define ARIZONA_FMT_DSP_MODE_A 0 +#define ARIZONA_FMT_DSP_MODE_B 1 +#define ARIZONA_FMT_I2S_MODE 2 +#define ARIZONA_FMT_LEFT_JUSTIFIED_MODE 3 + #define arizona_fll_err(_fll, fmt, ...) \ dev_err(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__) #define arizona_fll_warn(_fll, fmt, ...) \ @@ -946,10 +951,26 @@ static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_DSP_A: - mode = 0; + mode = ARIZONA_FMT_DSP_MODE_A; + break; + case SND_SOC_DAIFMT_DSP_B: + if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) + != SND_SOC_DAIFMT_CBM_CFM) { + arizona_aif_err(dai, "DSP_B not valid in slave mode\n"); + return -EINVAL; + } + mode = ARIZONA_FMT_DSP_MODE_B; break; case SND_SOC_DAIFMT_I2S: - mode = 2; + mode = ARIZONA_FMT_I2S_MODE; + break; + case SND_SOC_DAIFMT_LEFT_J: + if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) + != SND_SOC_DAIFMT_CBM_CFM) { + arizona_aif_err(dai, "LEFT_J not valid in slave mode\n"); + return -EINVAL; + } + mode = ARIZONA_FMT_LEFT_JUSTIFIED_MODE; break; default: arizona_aif_err(dai, "Unsupported DAI format %d\n", @@ -1298,7 +1319,8 @@ static int arizona_hw_params(struct snd_pcm_substream *substream, /* Force multiple of 2 channels for I2S mode */ val = snd_soc_read(codec, base + ARIZONA_AIF_FORMAT); - if ((channels & 1) && (val & ARIZONA_AIF1_FMT_MASK)) { + val &= ARIZONA_AIF1_FMT_MASK; + if ((channels & 1) && (val == ARIZONA_FMT_I2S_MODE)) { arizona_aif_dbg(dai, "Forcing stereo mode\n"); bclk_target /= channels; bclk_target *= channels + 1; -- cgit v1.2.3 From 850577db99dbc4fdebe62d30d380de1878f77d2a Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Thu, 13 Nov 2014 09:55:22 +0800 Subject: ASoC: rt5645: add register setting for TDM We need to set extra register to avoid a recording issue in TDM mode. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 5 ++++- sound/soc/codecs/rt5645.h | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 665f8b64efe9..57afa12b2f54 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -2112,8 +2112,11 @@ static int rt5645_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, struct snd_soc_codec *codec = dai->codec; unsigned int val = 0; - if (rx_mask || tx_mask) + if (rx_mask || tx_mask) { val |= (1 << 14); + snd_soc_update_bits(codec, RT5645_BASS_BACK, + RT5645_G_BB_BST_MASK, RT5645_G_BB_BST_25DB); + } switch (slots) { case 4: diff --git a/sound/soc/codecs/rt5645.h b/sound/soc/codecs/rt5645.h index 82f681b02949..196daf03fe28 100644 --- a/sound/soc/codecs/rt5645.h +++ b/sound/soc/codecs/rt5645.h @@ -1855,6 +1855,7 @@ #define RT5645_M_BB_HPF_R_SFT 6 #define RT5645_G_BB_BST_MASK (0x3f) #define RT5645_G_BB_BST_SFT 0 +#define RT5645_G_BB_BST_25DB 0x14 /* MP3 Plus Control 1 (0xd0) */ #define RT5645_M_MP3_L_MASK (0x1 << 15) -- cgit v1.2.3 From 86707f7fece1d3a34aeb1e9c7f2178fd5ff4e788 Mon Sep 17 00:00:00 2001 From: Krishna Mohan Dani Date: Thu, 13 Nov 2014 17:44:23 +0530 Subject: ASoC: rt5631: Adding the description of the codec Signed-off-by: Krishna Mohan Dani Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index a68d1731a8fd..7e43e97ef359 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -487,7 +487,8 @@ config SND_SOC_RT286 depends on I2C config SND_SOC_RT5631 - tristate + tristate "Realtek ALC5631/RT5631 CODEC" + depends on I2C config SND_SOC_RT5640 tristate -- cgit v1.2.3 From 189c88ced169d5197c806828e275c6f063b1d499 Mon Sep 17 00:00:00 2001 From: Krishna Mohan Dani Date: Thu, 13 Nov 2014 17:44:24 +0530 Subject: ASoC: rt5631: Adding Device Tree compatibility to Realtek's ALC5631/RT5631 codec driver Signed-off-by: Krishna Mohan Dani Signed-off-by: Mark Brown --- sound/soc/codecs/rt5631.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5631.c b/sound/soc/codecs/rt5631.c index 1ba27db660a6..3b7d5e4a3ef6 100644 --- a/sound/soc/codecs/rt5631.c +++ b/sound/soc/codecs/rt5631.c @@ -1686,10 +1686,18 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5631 = { static const struct i2c_device_id rt5631_i2c_id[] = { { "rt5631", 0 }, + { "alc5631", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, rt5631_i2c_id); +static struct of_device_id rt5631_i2c_dt_ids[] = { + { .compatible = "realtek,rt5631"}, + { .compatible = "realtek,alc5631"}, + { } +}; +MODULE_DEVICE_TABLE(of, rt5631_i2c_dt_ids); + static const struct regmap_config rt5631_regmap_config = { .reg_bits = 8, .val_bits = 16, @@ -1734,6 +1742,7 @@ static struct i2c_driver rt5631_i2c_driver = { .driver = { .name = "rt5631", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(rt5631_i2c_dt_ids), }, .probe = rt5631_i2c_probe, .remove = rt5631_i2c_remove, -- cgit v1.2.3 From 0605815e7ec21e048febcebb691d7f0cc3bdc36c Mon Sep 17 00:00:00 2001 From: Mengdong Lin Date: Fri, 14 Nov 2014 15:51:34 +0800 Subject: ASoC: rt5670 : Add ACPI match ID for Intel CHT/BSW platforms This patch adds the ACPI match ID for rt5670/5672 codec. So on Intel CherryTrail/Braswell platforms, the codec can be enumerated from ACPI and depends on ACPI to get platform-specific info and power saving. Signed-off-by: Mengdong Lin Reviewed-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5670.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 066b58317c24..b0aabd497ae9 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -2503,6 +2504,14 @@ static const struct i2c_device_id rt5670_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, rt5670_i2c_id); +#ifdef CONFIG_ACPI +static struct acpi_device_id rt5670_acpi_match[] = { + { "10EC5670", 0}, + { }, +}; +MODULE_DEVICE_TABLE(acpi, rt5670_acpi_match); +#endif + static int rt5670_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -2691,6 +2700,7 @@ static struct i2c_driver rt5670_i2c_driver = { .driver = { .name = "rt5670", .owner = THIS_MODULE, + .acpi_match_table = ACPI_PTR(rt5670_acpi_match), }, .probe = rt5670_i2c_probe, .remove = rt5670_i2c_remove, -- cgit v1.2.3 From 471f208af987a3741757c169c4e2ad984359000b Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Fri, 14 Nov 2014 14:25:37 +0800 Subject: ASoC: rt5645: two jacks for hp and mic Some OS need headphone and microphone to be separated. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 17 ++++++++--------- sound/soc/codecs/rt5645.h | 5 +++-- 2 files changed, 11 insertions(+), 11 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 57afa12b2f54..ef88b506a017 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -2201,8 +2201,7 @@ static int rt5645_set_bias_level(struct snd_soc_codec *codec, return 0; } -static int rt5645_jack_detect(struct snd_soc_codec *codec, - struct snd_soc_jack *jack) +static int rt5645_jack_detect(struct snd_soc_codec *codec) { struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); int gpio_state, jack_type = 0; @@ -2245,19 +2244,19 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec, snd_soc_dapm_sync(&codec->dapm); } - snd_soc_jack_report(rt5645->jack, jack_type, SND_JACK_HEADSET); - + snd_soc_jack_report(rt5645->hp_jack, jack_type, SND_JACK_HEADPHONE); + snd_soc_jack_report(rt5645->mic_jack, jack_type, SND_JACK_MICROPHONE); return 0; } int rt5645_set_jack_detect(struct snd_soc_codec *codec, - struct snd_soc_jack *jack) + struct snd_soc_jack *hp_jack, struct snd_soc_jack *mic_jack) { struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); - rt5645->jack = jack; - - rt5645_jack_detect(codec, rt5645->jack); + rt5645->hp_jack = hp_jack; + rt5645->mic_jack = mic_jack; + rt5645_jack_detect(codec); return 0; } @@ -2268,7 +2267,7 @@ static void rt5645_jack_detect_work(struct work_struct *work) struct rt5645_priv *rt5645 = container_of(work, struct rt5645_priv, jack_detect_work.work); - rt5645_jack_detect(rt5645->codec, rt5645->jack); + rt5645_jack_detect(rt5645->codec); } static irqreturn_t rt5645_irq(int irq, void *data) diff --git a/sound/soc/codecs/rt5645.h b/sound/soc/codecs/rt5645.h index 196daf03fe28..c72220abdbc0 100644 --- a/sound/soc/codecs/rt5645.h +++ b/sound/soc/codecs/rt5645.h @@ -2173,7 +2173,8 @@ struct rt5645_priv { struct rt5645_platform_data pdata; struct regmap *regmap; struct i2c_client *i2c; - struct snd_soc_jack *jack; + struct snd_soc_jack *hp_jack; + struct snd_soc_jack *mic_jack; struct delayed_work jack_detect_work; int sysclk; @@ -2188,6 +2189,6 @@ struct rt5645_priv { }; int rt5645_set_jack_detect(struct snd_soc_codec *codec, - struct snd_soc_jack *jack); + struct snd_soc_jack *hp_jack, struct snd_soc_jack *mic_jack); #endif /* __RT5645_H__ */ -- cgit v1.2.3 From 2880fc877971d6c14b0c76ac09744e3ff5b126d5 Mon Sep 17 00:00:00 2001 From: Dylan Reid Date: Thu, 13 Nov 2014 11:18:29 -0800 Subject: ASoC: add TI ts3a227e headset chip driver The TS3A227E is an autonomous audio accessory detection and configuration switch that detects 3-pole or 4-pole audio accessories and configures internal switches to route the signals accordingly. This chip also has built-in support for the new button standard described in the Android "Wired audio headset specification" v1.0. These buttons will be reported on the jack as buttons 0-3 mapped to KEY_MEDIA, KEY_VOLUMEUP, KEY_VOLUMEDOWN, and KEY_VOICE_COMMAND. This will be added as an aux_dev and have the jack passed in from the machine driver. Signed-off-by: Dylan Reid Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/ts3a227e.txt | 26 ++ sound/soc/codecs/Kconfig | 5 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/ts3a227e.c | 314 +++++++++++++++++++++ sound/soc/codecs/ts3a227e.h | 17 ++ 5 files changed, 364 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/ts3a227e.txt create mode 100644 sound/soc/codecs/ts3a227e.c create mode 100644 sound/soc/codecs/ts3a227e.h (limited to 'sound/soc/codecs') diff --git a/Documentation/devicetree/bindings/sound/ts3a227e.txt b/Documentation/devicetree/bindings/sound/ts3a227e.txt new file mode 100644 index 000000000000..e8bf23eb1803 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/ts3a227e.txt @@ -0,0 +1,26 @@ +Texas Instruments TS3A227E +Autonomous Audio Accessory Detection and Configuration Switch + +The TS3A227E detect headsets of 3-ring and 4-ring standards and +switches automatically to route the microphone correctly. It also +handles key press detection in accordance with the Android audio +headset specification v1.0. + +Required properties: + + - compatible: Should contain "ti,ts3a227e". + - reg: The i2c address. Should contain <0x3b>. + - interrupt-parent: The parent interrupt controller + - interrupts: Interrupt number for /INT pin from the 227e + + +Examples: + + i2c { + ts3a227e@3b { + compatible = "ti,ts3a227e"; + reg = <0x3b>; + interrupt-parent = <&gpio>; + interrupts = <3 IRQ_TYPE_LEVEL_LOW>; + }; + }; diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index a68d1731a8fd..243ec862c426 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -109,6 +109,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_TLV320AIC3X if I2C select SND_SOC_TPA6130A2 if I2C select SND_SOC_TLV320DAC33 if I2C + select SND_SOC_TS3A227E if I2C select SND_SOC_TWL4030 if TWL4030_CORE select SND_SOC_TWL6040 if TWL6040_CORE select SND_SOC_UDA134X @@ -607,6 +608,10 @@ config SND_SOC_TLV320AIC3X config SND_SOC_TLV320DAC33 tristate +config SND_SOC_TS3A227E + tristate "TI Headset/Mic detect and keypress chip" + depends on I2C + config SND_SOC_TWL4030 select MFD_TWL4030_AUDIO tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 5dce451661e4..a1eb7ef3b90e 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -109,6 +109,7 @@ snd-soc-tlv320aic31xx-objs := tlv320aic31xx.o snd-soc-tlv320aic32x4-objs := tlv320aic32x4.o snd-soc-tlv320aic3x-objs := tlv320aic3x.o snd-soc-tlv320dac33-objs := tlv320dac33.o +snd-soc-ts3a227e-objs := ts3a227e.o snd-soc-twl4030-objs := twl4030.o snd-soc-twl6040-objs := twl6040.o snd-soc-uda134x-objs := uda134x.o @@ -282,6 +283,7 @@ obj-$(CONFIG_SND_SOC_TLV320AIC31XX) += snd-soc-tlv320aic31xx.o obj-$(CONFIG_SND_SOC_TLV320AIC32X4) += snd-soc-tlv320aic32x4.o obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o obj-$(CONFIG_SND_SOC_TLV320DAC33) += snd-soc-tlv320dac33.o +obj-$(CONFIG_SND_SOC_TS3A227E) += snd-soc-ts3a227e.o obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o obj-$(CONFIG_SND_SOC_TWL6040) += snd-soc-twl6040.o obj-$(CONFIG_SND_SOC_UDA134X) += snd-soc-uda134x.o diff --git a/sound/soc/codecs/ts3a227e.c b/sound/soc/codecs/ts3a227e.c new file mode 100644 index 000000000000..1d1205702d23 --- /dev/null +++ b/sound/soc/codecs/ts3a227e.c @@ -0,0 +1,314 @@ +/* + * TS3A227E Autonomous Audio Accessory Detection and Configuration Switch + * + * Copyright (C) 2014 Google, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +struct ts3a227e { + struct regmap *regmap; + struct snd_soc_jack *jack; + bool plugged; + bool mic_present; + unsigned int buttons_held; +}; + +/* Button values to be reported on the jack */ +static const int ts3a227e_buttons[] = { + SND_JACK_BTN_0, + SND_JACK_BTN_1, + SND_JACK_BTN_2, + SND_JACK_BTN_3, +}; + +#define TS3A227E_NUM_BUTTONS 4 +#define TS3A227E_JACK_MASK (SND_JACK_HEADPHONE | \ + SND_JACK_MICROPHONE | \ + SND_JACK_BTN_0 | \ + SND_JACK_BTN_1 | \ + SND_JACK_BTN_2 | \ + SND_JACK_BTN_3) + +/* TS3A227E registers */ +#define TS3A227E_REG_DEVICE_ID 0x00 +#define TS3A227E_REG_INTERRUPT 0x01 +#define TS3A227E_REG_KP_INTERRUPT 0x02 +#define TS3A227E_REG_INTERRUPT_DISABLE 0x03 +#define TS3A227E_REG_SETTING_1 0x04 +#define TS3A227E_REG_SETTING_2 0x05 +#define TS3A227E_REG_SETTING_3 0x06 +#define TS3A227E_REG_SWITCH_CONTROL_1 0x07 +#define TS3A227E_REG_SWITCH_CONTROL_2 0x08 +#define TS3A227E_REG_SWITCH_STATUS_1 0x09 +#define TS3A227E_REG_SWITCH_STATUS_2 0x0a +#define TS3A227E_REG_ACCESSORY_STATUS 0x0b +#define TS3A227E_REG_ADC_OUTPUT 0x0c +#define TS3A227E_REG_KP_THRESHOLD_1 0x0d +#define TS3A227E_REG_KP_THRESHOLD_2 0x0e +#define TS3A227E_REG_KP_THRESHOLD_3 0x0f + +/* TS3A227E_REG_INTERRUPT 0x01 */ +#define INS_REM_EVENT 0x01 +#define DETECTION_COMPLETE_EVENT 0x02 + +/* TS3A227E_REG_KP_INTERRUPT 0x02 */ +#define PRESS_MASK(idx) (0x01 << (2 * (idx))) +#define RELEASE_MASK(idx) (0x02 << (2 * (idx))) + +/* TS3A227E_REG_INTERRUPT_DISABLE 0x03 */ +#define INS_REM_INT_DISABLE 0x01 +#define DETECTION_COMPLETE_INT_DISABLE 0x02 +#define ADC_COMPLETE_INT_DISABLE 0x04 +#define INTB_DISABLE 0x08 + +/* TS3A227E_REG_SETTING_2 0x05 */ +#define KP_ENABLE 0x04 + +/* TS3A227E_REG_ACCESSORY_STATUS 0x0b */ +#define TYPE_3_POLE 0x01 +#define TYPE_4_POLE_OMTP 0x02 +#define TYPE_4_POLE_STANDARD 0x04 +#define JACK_INSERTED 0x08 +#define EITHER_MIC_MASK (TYPE_4_POLE_OMTP | TYPE_4_POLE_STANDARD) + +static const struct reg_default ts3a227e_reg_defaults[] = { + { TS3A227E_REG_DEVICE_ID, 0x10 }, + { TS3A227E_REG_INTERRUPT, 0x00 }, + { TS3A227E_REG_KP_INTERRUPT, 0x00 }, + { TS3A227E_REG_INTERRUPT_DISABLE, 0x08 }, + { TS3A227E_REG_SETTING_1, 0x23 }, + { TS3A227E_REG_SETTING_2, 0x00 }, + { TS3A227E_REG_SETTING_3, 0x0e }, + { TS3A227E_REG_SWITCH_CONTROL_1, 0x00 }, + { TS3A227E_REG_SWITCH_CONTROL_2, 0x00 }, + { TS3A227E_REG_SWITCH_STATUS_1, 0x0c }, + { TS3A227E_REG_SWITCH_STATUS_2, 0x00 }, + { TS3A227E_REG_ACCESSORY_STATUS, 0x00 }, + { TS3A227E_REG_ADC_OUTPUT, 0x00 }, + { TS3A227E_REG_KP_THRESHOLD_1, 0x20 }, + { TS3A227E_REG_KP_THRESHOLD_2, 0x40 }, + { TS3A227E_REG_KP_THRESHOLD_3, 0x68 }, +}; + +static bool ts3a227e_readable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TS3A227E_REG_DEVICE_ID ... TS3A227E_REG_KP_THRESHOLD_3: + return true; + default: + return false; + } +} + +static bool ts3a227e_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TS3A227E_REG_INTERRUPT_DISABLE ... TS3A227E_REG_SWITCH_CONTROL_2: + case TS3A227E_REG_KP_THRESHOLD_1 ... TS3A227E_REG_KP_THRESHOLD_3: + return true; + default: + return false; + } +} + +static bool ts3a227e_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TS3A227E_REG_INTERRUPT ... TS3A227E_REG_INTERRUPT_DISABLE: + case TS3A227E_REG_SETTING_2: + case TS3A227E_REG_SWITCH_STATUS_1 ... TS3A227E_REG_ADC_OUTPUT: + return true; + default: + return false; + } +} + +static void ts3a227e_jack_report(struct ts3a227e *ts3a227e) +{ + unsigned int i; + int report = 0; + + if (!ts3a227e->jack) + return; + + if (ts3a227e->plugged) + report = SND_JACK_HEADPHONE; + if (ts3a227e->mic_present) + report |= SND_JACK_MICROPHONE; + for (i = 0; i < TS3A227E_NUM_BUTTONS; i++) { + if (ts3a227e->buttons_held & (1 << i)) + report |= ts3a227e_buttons[i]; + } + snd_soc_jack_report(ts3a227e->jack, report, TS3A227E_JACK_MASK); +} + +static void ts3a227e_new_jack_state(struct ts3a227e *ts3a227e, unsigned acc_reg) +{ + bool plugged, mic_present; + + plugged = !!(acc_reg & JACK_INSERTED); + mic_present = plugged && !!(acc_reg & EITHER_MIC_MASK); + + ts3a227e->plugged = plugged; + + if (mic_present != ts3a227e->mic_present) { + ts3a227e->mic_present = mic_present; + ts3a227e->buttons_held = 0; + if (mic_present) { + /* Enable key press detection. */ + regmap_update_bits(ts3a227e->regmap, + TS3A227E_REG_SETTING_2, + KP_ENABLE, KP_ENABLE); + } + } +} + +static irqreturn_t ts3a227e_interrupt(int irq, void *data) +{ + struct ts3a227e *ts3a227e = (struct ts3a227e *)data; + struct regmap *regmap = ts3a227e->regmap; + unsigned int int_reg, kp_int_reg, acc_reg, i; + + /* Check for plug/unplug. */ + regmap_read(regmap, TS3A227E_REG_INTERRUPT, &int_reg); + if (int_reg & (DETECTION_COMPLETE_EVENT | INS_REM_EVENT)) { + regmap_read(regmap, TS3A227E_REG_ACCESSORY_STATUS, &acc_reg); + ts3a227e_new_jack_state(ts3a227e, acc_reg); + } + + /* Report any key events. */ + regmap_read(regmap, TS3A227E_REG_KP_INTERRUPT, &kp_int_reg); + for (i = 0; i < TS3A227E_NUM_BUTTONS; i++) { + if (kp_int_reg & PRESS_MASK(i)) + ts3a227e->buttons_held |= (1 << i); + if (kp_int_reg & RELEASE_MASK(i)) + ts3a227e->buttons_held &= ~(1 << i); + } + + ts3a227e_jack_report(ts3a227e); + + return IRQ_HANDLED; +} + +/** + * ts3a227e_enable_jack_detect - Specify a jack for event reporting + * + * @component: component to register the jack with + * @jack: jack to use to report headset and button events on + * + * After this function has been called the headset insert/remove and button + * events 0-3 will be routed to the given jack. Jack can be null to stop + * reporting. + */ +int ts3a227e_enable_jack_detect(struct snd_soc_component *component, + struct snd_soc_jack *jack) +{ + struct ts3a227e *ts3a227e = snd_soc_component_get_drvdata(component); + + snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_MEDIA); + snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP); + snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN); + snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND); + + ts3a227e->jack = jack; + ts3a227e_jack_report(ts3a227e); + + return 0; +} +EXPORT_SYMBOL_GPL(ts3a227e_enable_jack_detect); + +static struct snd_soc_component_driver ts3a227e_soc_driver; + +static const struct regmap_config ts3a227e_regmap_config = { + .val_bits = 8, + .reg_bits = 8, + + .max_register = TS3A227E_REG_KP_THRESHOLD_3, + .readable_reg = ts3a227e_readable_reg, + .writeable_reg = ts3a227e_writeable_reg, + .volatile_reg = ts3a227e_volatile_reg, + + .cache_type = REGCACHE_RBTREE, + .reg_defaults = ts3a227e_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(ts3a227e_reg_defaults), +}; + +static int ts3a227e_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct ts3a227e *ts3a227e; + struct device *dev = &i2c->dev; + int ret; + + ts3a227e = devm_kzalloc(&i2c->dev, sizeof(*ts3a227e), GFP_KERNEL); + if (ts3a227e == NULL) + return -ENOMEM; + + i2c_set_clientdata(i2c, ts3a227e); + + ts3a227e->regmap = devm_regmap_init_i2c(i2c, &ts3a227e_regmap_config); + if (IS_ERR(ts3a227e->regmap)) + return PTR_ERR(ts3a227e->regmap); + + ret = devm_request_threaded_irq(dev, i2c->irq, NULL, ts3a227e_interrupt, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, + "TS3A227E", ts3a227e); + if (ret) { + dev_err(dev, "Cannot request irq %d (%d)\n", i2c->irq, ret); + return ret; + } + + ret = devm_snd_soc_register_component(&i2c->dev, &ts3a227e_soc_driver, + NULL, 0); + if (ret) + return ret; + + /* Enable interrupts except for ADC complete. */ + regmap_update_bits(ts3a227e->regmap, TS3A227E_REG_INTERRUPT_DISABLE, + INTB_DISABLE | ADC_COMPLETE_INT_DISABLE, + ADC_COMPLETE_INT_DISABLE); + + return 0; +} + +static const struct i2c_device_id ts3a227e_i2c_ids[] = { + { "ts3a227e", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ts3a227e_i2c_ids); + +static const struct of_device_id ts3a227e_of_match[] = { + { .compatible = "ti,ts3a227e", }, + { } +}; +MODULE_DEVICE_TABLE(of, ts3a227e_of_match); + +static struct i2c_driver ts3a227e_driver = { + .driver = { + .name = "ts3a227e", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(ts3a227e_of_match), + }, + .probe = ts3a227e_i2c_probe, + .id_table = ts3a227e_i2c_ids, +}; +module_i2c_driver(ts3a227e_driver); + +MODULE_DESCRIPTION("ASoC ts3a227e driver"); +MODULE_AUTHOR("Dylan Reid "); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/ts3a227e.h b/sound/soc/codecs/ts3a227e.h new file mode 100644 index 000000000000..e2acf9c5bebe --- /dev/null +++ b/sound/soc/codecs/ts3a227e.h @@ -0,0 +1,17 @@ +/* + * TS3A227E Autonous Audio Accessory Detection and Configureation Switch + * + * Copyright (C) 2014 Google, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _TS3A227E_H +#define _TS3A227E_H + +int ts3a227e_enable_jack_detect(struct snd_soc_component *component, + struct snd_soc_jack *jack); + +#endif -- cgit v1.2.3 From 044b724ada4448174f3f7510b791df0bdcb834ee Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 12 Nov 2014 19:54:30 +0800 Subject: ASoC: rt5670: make bias level more reasonable This patah separate bias level off to standby and off. The standby level will provide the necessary power for JD and push button functions. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5670.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index b0aabd497ae9..5e54ac957e47 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -2310,6 +2310,8 @@ static int rt5670_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, static int rt5670_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { + struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); + switch (level) { case SND_SOC_BIAS_PREPARE: if (SND_SOC_BIAS_STANDBY == codec->dapm.bias_level) { @@ -2331,16 +2333,27 @@ static int rt5670_set_bias_level(struct snd_soc_codec *codec, } break; case SND_SOC_BIAS_STANDBY: - snd_soc_write(codec, RT5670_PWR_DIG1, 0x0000); - snd_soc_write(codec, RT5670_PWR_DIG2, 0x0001); - snd_soc_write(codec, RT5670_PWR_VOL, 0x0000); - snd_soc_write(codec, RT5670_PWR_MIXER, 0x0001); - snd_soc_write(codec, RT5670_PWR_ANLG1, 0x2800); - snd_soc_write(codec, RT5670_PWR_ANLG2, 0x0004); - snd_soc_update_bits(codec, RT5670_DIG_MISC, 0x1, 0x0); + snd_soc_update_bits(codec, RT5670_PWR_ANLG1, + RT5670_PWR_VREF1 | RT5670_PWR_VREF2 | + RT5670_PWR_FV1 | RT5670_PWR_FV2, 0); snd_soc_update_bits(codec, RT5670_PWR_ANLG1, RT5670_LDO_SEL_MASK, 0x1); break; + case SND_SOC_BIAS_OFF: + if (rt5670->pdata.jd_mode) + snd_soc_update_bits(codec, RT5670_PWR_ANLG1, + RT5670_PWR_VREF1 | RT5670_PWR_MB | + RT5670_PWR_BG | RT5670_PWR_VREF2 | + RT5670_PWR_FV1 | RT5670_PWR_FV2, + RT5670_PWR_MB | RT5670_PWR_BG); + else + snd_soc_update_bits(codec, RT5670_PWR_ANLG1, + RT5670_PWR_VREF1 | RT5670_PWR_MB | + RT5670_PWR_BG | RT5670_PWR_VREF2 | + RT5670_PWR_FV1 | RT5670_PWR_FV2, 0); + + snd_soc_update_bits(codec, RT5670_DIG_MISC, 0x1, 0x0); + break; default: break; -- cgit v1.2.3 From cdcd7f7287532131d2075dd45f15aaf39dcfe983 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Fri, 14 Nov 2014 15:40:45 +0000 Subject: ASoC: wm_adsp: Use vmalloc to allocate firmware download buffer Use vmalloc to allocate the buffer for firmware/coefficient download and rely on the SPI core to split this up into DMA-able chunks. This should give better performance and means we no longer need to manually split the download into page size chunks to avoid allocating overly large continuous memory regions. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 56 ++++++++++++++++++---------------------------- 1 file changed, 22 insertions(+), 34 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index f412a9911a75..0a08ef5e27c8 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -169,11 +170,12 @@ static struct wm_adsp_buf *wm_adsp_buf_alloc(const void *src, size_t len, if (buf == NULL) return NULL; - buf->buf = kmemdup(src, len, GFP_KERNEL | GFP_DMA); + buf->buf = vmalloc(len); if (!buf->buf) { - kfree(buf); + vfree(buf); return NULL; } + memcpy(buf->buf, src, len); if (list) list_add_tail(&buf->list, list); @@ -188,7 +190,7 @@ static void wm_adsp_buf_free(struct list_head *list) struct wm_adsp_buf, list); list_del(&buf->list); - kfree(buf->buf); + vfree(buf->buf); kfree(buf); } } @@ -684,38 +686,24 @@ static int wm_adsp_load(struct wm_adsp *dsp) } if (reg) { - size_t to_write = PAGE_SIZE; - size_t remain = le32_to_cpu(region->len); - const u8 *data = region->data; - - while (remain > 0) { - if (remain < PAGE_SIZE) - to_write = remain; - - buf = wm_adsp_buf_alloc(data, - to_write, - &buf_list); - if (!buf) { - adsp_err(dsp, "Out of memory\n"); - ret = -ENOMEM; - goto out_fw; - } - - ret = regmap_raw_write_async(regmap, reg, - buf->buf, - to_write); - if (ret != 0) { - adsp_err(dsp, - "%s.%d: Failed to write %zd bytes at %d in %s: %d\n", - file, regions, - to_write, offset, - region_name, ret); - goto out_fw; - } + buf = wm_adsp_buf_alloc(region->data, + le32_to_cpu(region->len), + &buf_list); + if (!buf) { + adsp_err(dsp, "Out of memory\n"); + ret = -ENOMEM; + goto out_fw; + } - data += to_write; - reg += to_write / 2; - remain -= to_write; + ret = regmap_raw_write_async(regmap, reg, buf->buf, + le32_to_cpu(region->len)); + if (ret != 0) { + adsp_err(dsp, + "%s.%d: Failed to write %d bytes at %d in %s: %d\n", + file, regions, + le32_to_cpu(region->len), offset, + region_name, ret); + goto out_fw; } } -- cgit v1.2.3 From 6fdaac1c1ab4fee1619145487c5aaf1bd44acc7b Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 17 Nov 2014 09:37:34 +0100 Subject: ASoC: adav80x: Replace w->codec with snd_soc_dapm_to_codec(w->dapm) The codec field of the snd_soc_widget struct is eventually going to be removed, use snd_soc_dapm_to_codec(w->dapm) instead. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/adav80x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c index ce3cdca9fc62..b67480f1b1aa 100644 --- a/sound/soc/codecs/adav80x.c +++ b/sound/soc/codecs/adav80x.c @@ -212,7 +212,7 @@ static const struct snd_soc_dapm_widget adav80x_dapm_widgets[] = { static int adav80x_dapm_sysclk_check(struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink) { - struct snd_soc_codec *codec = source->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm); struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); const char *clk; @@ -236,7 +236,7 @@ static int adav80x_dapm_sysclk_check(struct snd_soc_dapm_widget *source, static int adav80x_dapm_pll_check(struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink) { - struct snd_soc_codec *codec = source->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm); struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); return adav80x->pll_src == ADAV80X_PLL_SRC_XTAL; -- cgit v1.2.3 From de172051af78883a4a2e7897e7af58ba49353b99 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 17 Nov 2014 09:37:35 +0100 Subject: ASoC: adau1373: Replace w->codec with snd_soc_dapm_to_codec(w->dapm) The codec field of the snd_soc_widget struct is eventually going to be removed, use snd_soc_dapm_to_codec(w->dapm) instead. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/adau1373.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c index 7c784ad3e8b2..783dcb57043a 100644 --- a/sound/soc/codecs/adau1373.c +++ b/sound/soc/codecs/adau1373.c @@ -551,7 +551,7 @@ static const struct snd_kcontrol_new adau1373_drc_controls[] = { static int adau1373_pll_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec); unsigned int pll_id = w->name[3] - '1'; unsigned int val; @@ -823,7 +823,7 @@ static const struct snd_soc_dapm_widget adau1373_dapm_widgets[] = { static int adau1373_check_aif_clk(struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink) { - struct snd_soc_codec *codec = source->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm); struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec); unsigned int dai; const char *clk; @@ -844,7 +844,7 @@ static int adau1373_check_aif_clk(struct snd_soc_dapm_widget *source, static int adau1373_check_src(struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink) { - struct snd_soc_codec *codec = source->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm); struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec); unsigned int dai; -- cgit v1.2.3 From d69db7f7cd57fdfc6ac64c4c8679eb7b80c84fc7 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 17 Nov 2014 09:37:36 +0100 Subject: ASoC: adau17x1: Replace w->codec with snd_soc_dapm_to_codec(w->dapm) The codec field of the snd_soc_widget struct is eventually going to be removed, use snd_soc_dapm_to_codec(w->dapm) instead. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/adau1761.c | 3 ++- sound/soc/codecs/adau1781.c | 2 +- sound/soc/codecs/adau17x1.c | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/adau1761.c b/sound/soc/codecs/adau1761.c index 5518ebd6947c..3dddb286d08d 100644 --- a/sound/soc/codecs/adau1761.c +++ b/sound/soc/codecs/adau1761.c @@ -255,7 +255,8 @@ static const struct snd_kcontrol_new adau1761_input_mux_control = static int adau1761_dejitter_fixup(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct adau *adau = snd_soc_codec_get_drvdata(w->codec); + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct adau *adau = snd_soc_codec_get_drvdata(codec); /* After any power changes have been made the dejitter circuit * has to be reinitialized. */ diff --git a/sound/soc/codecs/adau1781.c b/sound/soc/codecs/adau1781.c index e9fc00fb13dd..aa6a37cc44b7 100644 --- a/sound/soc/codecs/adau1781.c +++ b/sound/soc/codecs/adau1781.c @@ -174,7 +174,7 @@ static const struct snd_kcontrol_new adau1781_mono_mixer_controls[] = { static int adau1781_dejitter_fixup(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct adau *adau = snd_soc_codec_get_drvdata(codec); /* After any power changes have been made the dejitter circuit diff --git a/sound/soc/codecs/adau17x1.c b/sound/soc/codecs/adau17x1.c index 3e16c1c64115..427ad77bfe56 100644 --- a/sound/soc/codecs/adau17x1.c +++ b/sound/soc/codecs/adau17x1.c @@ -61,7 +61,8 @@ static const struct snd_kcontrol_new adau17x1_controls[] = { static int adau17x1_pll_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct adau *adau = snd_soc_codec_get_drvdata(w->codec); + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct adau *adau = snd_soc_codec_get_drvdata(codec); int ret; if (SND_SOC_DAPM_EVENT_ON(event)) { -- cgit v1.2.3 From 187024b36c635bd454c1b1587b58c9439d3a46ad Mon Sep 17 00:00:00 2001 From: Krishna Mohan Dani Date: Mon, 17 Nov 2014 19:26:29 +0530 Subject: ASoC: rt5631: Fixing compilation warning when DT is disabled Fixes the following compilation warning: Warning: 'rt5631_i2c_dt_ids' defined but not used - when DT is not used. Signed-off-by: Claude Youn Signed-off-by: Krishna Mohan Dani Signed-off-by: Mark Brown --- sound/soc/codecs/rt5631.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5631.c b/sound/soc/codecs/rt5631.c index 3b7d5e4a3ef6..9425545e8403 100644 --- a/sound/soc/codecs/rt5631.c +++ b/sound/soc/codecs/rt5631.c @@ -1691,12 +1691,14 @@ static const struct i2c_device_id rt5631_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, rt5631_i2c_id); +#ifdef CONFIG_OF static struct of_device_id rt5631_i2c_dt_ids[] = { { .compatible = "realtek,rt5631"}, { .compatible = "realtek,alc5631"}, { } }; MODULE_DEVICE_TABLE(of, rt5631_i2c_dt_ids); +#endif static const struct regmap_config rt5631_regmap_config = { .reg_bits = 8, -- cgit v1.2.3 From 86ae04b174152147052adec7b95dba0c9cd7dff0 Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Mon, 17 Nov 2014 10:18:11 +0800 Subject: ASoC: rt5677: Modify the default value of the MX-8E[4] for ASRC function Modify the default value of the MX-8E[4] to 1 for ASRC function. It could prevent the pop noise with ASRC function. Signed-off-by: Oder Chiou Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 5d317c68ca4e..9ae2e8468006 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -55,7 +55,8 @@ static const struct regmap_range_cfg rt5677_ranges[] = { }; static const struct reg_default init_list[] = { - {RT5677_PR_BASE + 0x3d, 0x364d}, + {RT5677_ASRC_12, 0x0018}, + {RT5677_PR_BASE + 0x3d, 0x364d}, {RT5677_PR_BASE + 0x17, 0x4fc0}, {RT5677_PR_BASE + 0x13, 0x0312}, {RT5677_PR_BASE + 0x1e, 0x0000}, @@ -173,7 +174,7 @@ static const struct reg_default rt5677_reg[] = { {RT5677_ASRC_9 , 0x0000}, {RT5677_ASRC_10 , 0x0000}, {RT5677_ASRC_11 , 0x0000}, - {RT5677_ASRC_12 , 0x0008}, + {RT5677_ASRC_12 , 0x0018}, {RT5677_ASRC_13 , 0x0000}, {RT5677_ASRC_14 , 0x0000}, {RT5677_ASRC_15 , 0x0000}, -- cgit v1.2.3 From eda1a701fd9589b6ed15b109558bd4f6202e3829 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 10 Nov 2014 22:41:47 +0100 Subject: ASoC: ac97: Use static ac97_bus We always pass soc_ac97_ops to snd_soc_new_ac97_codec(). So instead of allocating a snd_ac97_bus in snd_soc_new_ac97_codec() just use a static one that gets initialized when snd_soc_set_ac97_ops() is called. Also drop the device number parameter from snd_soc_new_ac97_codec(). We currently only support one device per bus and all drivers pass 0 for the device number. And if we should ever support multiple devices per bus it wouldn't be up to individual AC'97 device drivers to pick their number, but rather either the AC'97 adapter driver or the core code will assign them. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown --- include/sound/soc.h | 3 +-- sound/soc/codecs/ad1980.c | 2 +- sound/soc/codecs/stac9766.c | 2 +- sound/soc/codecs/wm9705.c | 2 +- sound/soc/codecs/wm9712.c | 2 +- sound/soc/codecs/wm9713.c | 2 +- sound/soc/soc-ac97.c | 22 ++++++++-------------- 7 files changed, 14 insertions(+), 21 deletions(-) (limited to 'sound/soc/codecs') diff --git a/include/sound/soc.h b/include/sound/soc.h index adef34fa5209..44b3ce531fd6 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -499,8 +499,7 @@ int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned int reg, unsigned int mask, unsigned int value); #ifdef CONFIG_SND_SOC_AC97_BUS -int snd_soc_new_ac97_codec(struct snd_soc_codec *codec, - struct snd_ac97_bus_ops *ops, int num); +int snd_soc_new_ac97_codec(struct snd_soc_codec *codec); void snd_soc_free_ac97_codec(struct snd_soc_codec *codec); int snd_soc_set_ac97_ops(struct snd_ac97_bus_ops *ops); diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c index 9ed4e12c26d1..f71cc21e67d4 100644 --- a/sound/soc/codecs/ad1980.c +++ b/sound/soc/codecs/ad1980.c @@ -220,7 +220,7 @@ static int ad1980_soc_probe(struct snd_soc_codec *codec) u16 vendor_id2; u16 ext_status; - ret = snd_soc_new_ac97_codec(codec, soc_ac97_ops, 0); + ret = snd_soc_new_ac97_codec(codec); if (ret < 0) { dev_err(codec->dev, "Failed to register AC97 codec\n"); return ret; diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c index 53b810d23fea..45ac4a71ecff 100644 --- a/sound/soc/codecs/stac9766.c +++ b/sound/soc/codecs/stac9766.c @@ -336,7 +336,7 @@ static int stac9766_codec_probe(struct snd_soc_codec *codec) { int ret = 0; - ret = snd_soc_new_ac97_codec(codec, soc_ac97_ops, 0); + ret = snd_soc_new_ac97_codec(codec); if (ret < 0) goto codec_err; diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c index 1650195f6c84..2cb8a31819fa 100644 --- a/sound/soc/codecs/wm9705.c +++ b/sound/soc/codecs/wm9705.c @@ -337,7 +337,7 @@ static int wm9705_soc_probe(struct snd_soc_codec *codec) { int ret = 0; - ret = snd_soc_new_ac97_codec(codec, soc_ac97_ops, 0); + ret = snd_soc_new_ac97_codec(codec); if (ret < 0) { dev_err(codec->dev, "Failed to register AC97 codec\n"); return ret; diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index 3fad37e0d33d..6b36223fd247 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -666,7 +666,7 @@ static int wm9712_soc_probe(struct snd_soc_codec *codec) { int ret = 0; - ret = snd_soc_new_ac97_codec(codec, soc_ac97_ops, 0); + ret = snd_soc_new_ac97_codec(codec); if (ret < 0) { dev_err(codec->dev, "Failed to register AC97 codec\n"); return ret; diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index 998e4c7b6b12..2071df707e88 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -1219,7 +1219,7 @@ static int wm9713_soc_probe(struct snd_soc_codec *codec) { int ret = 0, reg; - ret = snd_soc_new_ac97_codec(codec, soc_ac97_ops, 0); + ret = snd_soc_new_ac97_codec(codec); if (ret < 0) return ret; diff --git a/sound/soc/soc-ac97.c b/sound/soc/soc-ac97.c index da7b031a6eea..dbfca7e7dddb 100644 --- a/sound/soc/soc-ac97.c +++ b/sound/soc/soc-ac97.c @@ -38,6 +38,10 @@ struct snd_ac97_reset_cfg { int gpio_reset; }; +static struct snd_ac97_bus soc_ac97_bus = { + .ops = NULL, /* Gets initialized in snd_soc_set_ac97_ops() */ +}; + /* unregister ac97 codec */ static int soc_ac97_dev_unregister(struct snd_soc_codec *codec) { @@ -140,27 +144,17 @@ static void soc_ac97_device_release(struct device *dev) /** * snd_soc_new_ac97_codec - initailise AC97 device * @codec: audio codec - * @ops: AC97 bus operations - * @num: AC97 codec number * * Initialises AC97 codec resources for use by ad-hoc devices only. */ -int snd_soc_new_ac97_codec(struct snd_soc_codec *codec, - struct snd_ac97_bus_ops *ops, int num) +int snd_soc_new_ac97_codec(struct snd_soc_codec *codec) { codec->ac97 = kzalloc(sizeof(struct snd_ac97), GFP_KERNEL); if (codec->ac97 == NULL) return -ENOMEM; - codec->ac97->bus = kzalloc(sizeof(struct snd_ac97_bus), GFP_KERNEL); - if (codec->ac97->bus == NULL) { - kfree(codec->ac97); - codec->ac97 = NULL; - return -ENOMEM; - } - - codec->ac97->bus->ops = ops; - codec->ac97->num = num; + codec->ac97->bus = &soc_ac97_bus; + codec->ac97->num = 0; codec->ac97->dev.release = soc_ac97_device_release; /* @@ -183,7 +177,6 @@ EXPORT_SYMBOL_GPL(snd_soc_new_ac97_codec); void snd_soc_free_ac97_codec(struct snd_soc_codec *codec) { soc_unregister_ac97_codec(codec); - kfree(codec->ac97->bus); codec->ac97->bus = NULL; put_device(&codec->ac97->dev); codec->ac97 = NULL; @@ -314,6 +307,7 @@ int snd_soc_set_ac97_ops(struct snd_ac97_bus_ops *ops) return -EBUSY; soc_ac97_ops = ops; + soc_ac97_bus.ops = ops; return 0; } -- cgit v1.2.3 From 4bafcf074aca3bd191e4d93c6a140ca52654f192 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 10 Nov 2014 22:41:51 +0100 Subject: ASoC: Drop ac97_control initialization from CODEC driver DAIs This is no longer necessary as there is no code anymore that uses this for CODEC DAIs. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/ac97.c | 1 - sound/soc/codecs/ad1980.c | 1 - sound/soc/codecs/stac9766.c | 2 -- sound/soc/codecs/wm9705.c | 1 - sound/soc/codecs/wm9712.c | 1 - sound/soc/codecs/wm9713.c | 1 - 6 files changed, 7 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c index bd9b1839c8b0..5d90924e8b96 100644 --- a/sound/soc/codecs/ac97.c +++ b/sound/soc/codecs/ac97.c @@ -53,7 +53,6 @@ static const struct snd_soc_dai_ops ac97_dai_ops = { static struct snd_soc_dai_driver ac97_dai = { .name = "ac97-hifi", - .ac97_control = 1, .playback = { .stream_name = "AC97 Playback", .channels_min = 1, diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c index f71cc21e67d4..c6cb101a5b8f 100644 --- a/sound/soc/codecs/ad1980.c +++ b/sound/soc/codecs/ad1980.c @@ -170,7 +170,6 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, static struct snd_soc_dai_driver ad1980_dai = { .name = "ad1980-hifi", - .ac97_control = 1, .playback = { .stream_name = "Playback", .channels_min = 2, diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c index 45ac4a71ecff..c0808061b08a 100644 --- a/sound/soc/codecs/stac9766.c +++ b/sound/soc/codecs/stac9766.c @@ -294,7 +294,6 @@ static const struct snd_soc_dai_ops stac9766_dai_ops_digital = { static struct snd_soc_dai_driver stac9766_dai[] = { { .name = "stac9766-hifi-analog", - .ac97_control = 1, /* stream cababilities */ .playback = { @@ -316,7 +315,6 @@ static struct snd_soc_dai_driver stac9766_dai[] = { }, { .name = "stac9766-hifi-IEC958", - .ac97_control = 1, /* stream cababilities */ .playback = { diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c index 2cb8a31819fa..5b5118ba1526 100644 --- a/sound/soc/codecs/wm9705.c +++ b/sound/soc/codecs/wm9705.c @@ -263,7 +263,6 @@ static const struct snd_soc_dai_ops wm9705_dai_ops = { static struct snd_soc_dai_driver wm9705_dai[] = { { .name = "wm9705-hifi", - .ac97_control = 1, .playback = { .stream_name = "HiFi Playback", .channels_min = 1, diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index 6b36223fd247..9fa794baa5f8 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -565,7 +565,6 @@ static const struct snd_soc_dai_ops wm9712_dai_ops_aux = { static struct snd_soc_dai_driver wm9712_dai[] = { { .name = "wm9712-hifi", - .ac97_control = 1, .playback = { .stream_name = "HiFi Playback", .channels_min = 1, diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index 2071df707e88..cd1b266d3af3 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -1076,7 +1076,6 @@ static const struct snd_soc_dai_ops wm9713_dai_ops_voice = { static struct snd_soc_dai_driver wm9713_dai[] = { { .name = "wm9713-hifi", - .ac97_control = 1, .playback = { .stream_name = "HiFi Playback", .channels_min = 1, -- cgit v1.2.3 From 358a8bb5628420529e4f0b77068155ca8fa8973b Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 10 Nov 2014 22:41:53 +0100 Subject: ASoC: ac97: Push snd_ac97 pointer to the driver level Now that the ASoC core no longer needs a handle to the AC'97 device that is associated with a CODEC we can remove it from the snd_soc_codec struct and push it into the individual driver state structs like we do for other communication buses. Doing so creates a clean separation between the AC'97 bus support and the ASoC core. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown --- include/sound/soc.h | 5 ++--- sound/soc/codecs/ac97.c | 17 +++++++++++++---- sound/soc/codecs/ad1980.c | 27 ++++++++++++++++++--------- sound/soc/codecs/stac9766.c | 38 ++++++++++++++++++++++++-------------- sound/soc/codecs/wm9705.c | 31 ++++++++++++++++++++++--------- sound/soc/codecs/wm9712.c | 32 +++++++++++++++++++++----------- sound/soc/codecs/wm9713.c | 31 ++++++++++++++++++++----------- sound/soc/soc-ac97.c | 40 +++++++++++++++++++++------------------- 8 files changed, 141 insertions(+), 80 deletions(-) (limited to 'sound/soc/codecs') diff --git a/include/sound/soc.h b/include/sound/soc.h index 206cc8d6eefa..9e513ae11749 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -499,8 +499,8 @@ int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned int reg, unsigned int mask, unsigned int value); #ifdef CONFIG_SND_SOC_AC97_BUS -int snd_soc_new_ac97_codec(struct snd_soc_codec *codec); -void snd_soc_free_ac97_codec(struct snd_soc_codec *codec); +struct snd_ac97 *snd_soc_new_ac97_codec(struct snd_soc_codec *codec); +void snd_soc_free_ac97_codec(struct snd_ac97 *ac97); int snd_soc_set_ac97_ops(struct snd_ac97_bus_ops *ops); int snd_soc_set_ac97_ops_of_reset(struct snd_ac97_bus_ops *ops, @@ -797,7 +797,6 @@ struct snd_soc_codec { struct list_head card_list; /* runtime */ - struct snd_ac97 *ac97; /* for ad-hoc ac97 devices */ unsigned int cache_bypass:1; /* Suppress access to the cache */ unsigned int suspended:1; /* Codec is in suspend PM state */ unsigned int cache_init:1; /* codec cache has been initialized */ diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c index 5d90924e8b96..c6e5a313ebf4 100644 --- a/sound/soc/codecs/ac97.c +++ b/sound/soc/codecs/ac97.c @@ -37,10 +37,11 @@ static int ac97_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_codec *codec = dai->codec; + struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); int reg = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? AC97_PCM_FRONT_DAC_RATE : AC97_PCM_LR_ADC_RATE; - return snd_ac97_set_rate(codec->ac97, reg, substream->runtime->rate); + return snd_ac97_set_rate(ac97, reg, substream->runtime->rate); } #define STD_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ @@ -70,6 +71,7 @@ static struct snd_soc_dai_driver ac97_dai = { static int ac97_soc_probe(struct snd_soc_codec *codec) { + struct snd_ac97 *ac97; struct snd_ac97_bus *ac97_bus; struct snd_ac97_template ac97_template; int ret; @@ -81,24 +83,31 @@ static int ac97_soc_probe(struct snd_soc_codec *codec) return ret; memset(&ac97_template, 0, sizeof(struct snd_ac97_template)); - ret = snd_ac97_mixer(ac97_bus, &ac97_template, &codec->ac97); + ret = snd_ac97_mixer(ac97_bus, &ac97_template, &ac97); if (ret < 0) return ret; + snd_soc_codec_set_drvdata(codec, ac97); + return 0; } #ifdef CONFIG_PM static int ac97_soc_suspend(struct snd_soc_codec *codec) { - snd_ac97_suspend(codec->ac97); + struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); + + snd_ac97_suspend(ac97); return 0; } static int ac97_soc_resume(struct snd_soc_codec *codec) { - snd_ac97_resume(codec->ac97); + + struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); + + snd_ac97_resume(ac97); return 0; } diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c index c6cb101a5b8f..93bd47db6d0c 100644 --- a/sound/soc/codecs/ad1980.c +++ b/sound/soc/codecs/ad1980.c @@ -135,6 +135,7 @@ static const struct snd_soc_dapm_route ad1980_dapm_routes[] = { static unsigned int ac97_read(struct snd_soc_codec *codec, unsigned int reg) { + struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); u16 *cache = codec->reg_cache; switch (reg) { @@ -144,7 +145,7 @@ static unsigned int ac97_read(struct snd_soc_codec *codec, case AC97_EXTENDED_STATUS: case AC97_VENDOR_ID1: case AC97_VENDOR_ID2: - return soc_ac97_ops->read(codec->ac97, reg); + return soc_ac97_ops->read(ac97, reg); default: reg = reg >> 1; @@ -158,9 +159,10 @@ static unsigned int ac97_read(struct snd_soc_codec *codec, static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int val) { + struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); u16 *cache = codec->reg_cache; - soc_ac97_ops->write(codec->ac97, reg, val); + soc_ac97_ops->write(ac97, reg, val); reg = reg >> 1; if (reg < ARRAY_SIZE(ad1980_reg)) cache[reg] = val; @@ -186,16 +188,17 @@ static struct snd_soc_dai_driver ad1980_dai = { static int ad1980_reset(struct snd_soc_codec *codec, int try_warm) { + struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); unsigned int retry_cnt = 0; do { if (try_warm && soc_ac97_ops->warm_reset) { - soc_ac97_ops->warm_reset(codec->ac97); + soc_ac97_ops->warm_reset(ac97); if (ac97_read(codec, AC97_RESET) == 0x0090) return 1; } - soc_ac97_ops->reset(codec->ac97); + soc_ac97_ops->reset(ac97); /* * Set bit 16slot in register 74h, then every slot will has only * 16 bits. This command is sent out in 20bit mode, in which @@ -215,16 +218,20 @@ static int ad1980_reset(struct snd_soc_codec *codec, int try_warm) static int ad1980_soc_probe(struct snd_soc_codec *codec) { + struct snd_ac97 *ac97; int ret; u16 vendor_id2; u16 ext_status; - ret = snd_soc_new_ac97_codec(codec); - if (ret < 0) { - dev_err(codec->dev, "Failed to register AC97 codec\n"); + ac97 = snd_soc_new_ac97_codec(codec); + if (IS_ERR(ac97)) { + ret = PTR_ERR(ac97); + dev_err(codec->dev, "Failed to register AC97 codec: %d\n", ret); return ret; } + snd_soc_codec_set_drvdata(codec, ac97); + ret = ad1980_reset(codec, 0); if (ret < 0) goto reset_err; @@ -261,13 +268,15 @@ static int ad1980_soc_probe(struct snd_soc_codec *codec) return 0; reset_err: - snd_soc_free_ac97_codec(codec); + snd_soc_free_ac97_codec(ac97); return ret; } static int ad1980_soc_remove(struct snd_soc_codec *codec) { - snd_soc_free_ac97_codec(codec); + struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); + + snd_soc_free_ac97_codec(ac97); return 0; } diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c index c0808061b08a..f37a79ec45e6 100644 --- a/sound/soc/codecs/stac9766.c +++ b/sound/soc/codecs/stac9766.c @@ -139,18 +139,19 @@ static const struct snd_kcontrol_new stac9766_snd_ac97_controls[] = { static int stac9766_ac97_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int val) { + struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); u16 *cache = codec->reg_cache; if (reg > AC97_STAC_PAGE0) { stac9766_ac97_write(codec, AC97_INT_PAGING, 0); - soc_ac97_ops->write(codec->ac97, reg, val); + soc_ac97_ops->write(ac97, reg, val); stac9766_ac97_write(codec, AC97_INT_PAGING, 1); return 0; } if (reg / 2 >= ARRAY_SIZE(stac9766_reg)) return -EIO; - soc_ac97_ops->write(codec->ac97, reg, val); + soc_ac97_ops->write(ac97, reg, val); cache[reg / 2] = val; return 0; } @@ -158,11 +159,12 @@ static int stac9766_ac97_write(struct snd_soc_codec *codec, unsigned int reg, static unsigned int stac9766_ac97_read(struct snd_soc_codec *codec, unsigned int reg) { + struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); u16 val = 0, *cache = codec->reg_cache; if (reg > AC97_STAC_PAGE0) { stac9766_ac97_write(codec, AC97_INT_PAGING, 0); - val = soc_ac97_ops->read(codec->ac97, reg - AC97_STAC_PAGE0); + val = soc_ac97_ops->read(ac97, reg - AC97_STAC_PAGE0); stac9766_ac97_write(codec, AC97_INT_PAGING, 1); return val; } @@ -173,7 +175,7 @@ static unsigned int stac9766_ac97_read(struct snd_soc_codec *codec, reg == AC97_INT_PAGING || reg == AC97_VENDOR_ID1 || reg == AC97_VENDOR_ID2) { - val = soc_ac97_ops->read(codec->ac97, reg); + val = soc_ac97_ops->read(ac97, reg); return val; } return cache[reg / 2]; @@ -240,15 +242,17 @@ static int stac9766_set_bias_level(struct snd_soc_codec *codec, static int stac9766_reset(struct snd_soc_codec *codec, int try_warm) { + struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); + if (try_warm && soc_ac97_ops->warm_reset) { - soc_ac97_ops->warm_reset(codec->ac97); + soc_ac97_ops->warm_reset(ac97); if (stac9766_ac97_read(codec, 0) == stac9766_reg[0]) return 1; } - soc_ac97_ops->reset(codec->ac97); + soc_ac97_ops->reset(ac97); if (soc_ac97_ops->warm_reset) - soc_ac97_ops->warm_reset(codec->ac97); + soc_ac97_ops->warm_reset(ac97); if (stac9766_ac97_read(codec, 0) != stac9766_reg[0]) return -EIO; return 0; @@ -262,6 +266,7 @@ static int stac9766_codec_suspend(struct snd_soc_codec *codec) static int stac9766_codec_resume(struct snd_soc_codec *codec) { + struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); u16 id, reset; reset = 0; @@ -271,8 +276,8 @@ reset: printk(KERN_ERR "stac9766 failed to resume"); return -EIO; } - codec->ac97->bus->ops->warm_reset(codec->ac97); - id = soc_ac97_ops->read(codec->ac97, AC97_VENDOR_ID2); + ac97->bus->ops->warm_reset(ac97); + id = soc_ac97_ops->read(ac97, AC97_VENDOR_ID2); if (id != 0x4c13) { stac9766_reset(codec, 0); reset++; @@ -332,11 +337,14 @@ static struct snd_soc_dai_driver stac9766_dai[] = { static int stac9766_codec_probe(struct snd_soc_codec *codec) { + struct snd_ac97 *ac97; int ret = 0; - ret = snd_soc_new_ac97_codec(codec); - if (ret < 0) - goto codec_err; + ac97 = snd_soc_new_ac97_codec(codec); + if (IS_ERR(ac97)) + return PTR_ERR(ac97); + + snd_soc_codec_set_drvdata(codec, ac97); /* do a cold reset for the controller and then try * a warm reset followed by an optional cold reset for codec */ @@ -355,13 +363,15 @@ static int stac9766_codec_probe(struct snd_soc_codec *codec) return 0; codec_err: - snd_soc_free_ac97_codec(codec); + snd_soc_free_ac97_codec(ac97); return ret; } static int stac9766_codec_remove(struct snd_soc_codec *codec) { - snd_soc_free_ac97_codec(codec); + struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); + + snd_soc_free_ac97_codec(ac97); return 0; } diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c index 5b5118ba1526..d3a800fa6f06 100644 --- a/sound/soc/codecs/wm9705.c +++ b/sound/soc/codecs/wm9705.c @@ -203,13 +203,14 @@ static const struct snd_soc_dapm_route wm9705_audio_map[] = { /* We use a register cache to enhance read performance. */ static unsigned int ac97_read(struct snd_soc_codec *codec, unsigned int reg) { + struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); u16 *cache = codec->reg_cache; switch (reg) { case AC97_RESET: case AC97_VENDOR_ID1: case AC97_VENDOR_ID2: - return soc_ac97_ops->read(codec->ac97, reg); + return soc_ac97_ops->read(ac97, reg); default: reg = reg >> 1; @@ -223,9 +224,10 @@ static unsigned int ac97_read(struct snd_soc_codec *codec, unsigned int reg) static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int val) { + struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); u16 *cache = codec->reg_cache; - soc_ac97_ops->write(codec->ac97, reg, val); + soc_ac97_ops->write(ac97, reg, val); reg = reg >> 1; if (reg < (ARRAY_SIZE(wm9705_reg))) cache[reg] = val; @@ -293,8 +295,10 @@ static struct snd_soc_dai_driver wm9705_dai[] = { static int wm9705_reset(struct snd_soc_codec *codec) { + struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); + if (soc_ac97_ops->reset) { - soc_ac97_ops->reset(codec->ac97); + soc_ac97_ops->reset(ac97); if (ac97_read(codec, 0) == wm9705_reg[0]) return 0; /* Success */ } @@ -307,13 +311,16 @@ static int wm9705_reset(struct snd_soc_codec *codec) #ifdef CONFIG_PM static int wm9705_soc_suspend(struct snd_soc_codec *codec) { - soc_ac97_ops->write(codec->ac97, AC97_POWERDOWN, 0xffff); + struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); + + soc_ac97_ops->write(ac97, AC97_POWERDOWN, 0xffff); return 0; } static int wm9705_soc_resume(struct snd_soc_codec *codec) { + struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); int i, ret; u16 *cache = codec->reg_cache; @@ -322,7 +329,7 @@ static int wm9705_soc_resume(struct snd_soc_codec *codec) return ret; for (i = 2; i < ARRAY_SIZE(wm9705_reg) << 1; i += 2) { - soc_ac97_ops->write(codec->ac97, i, cache[i>>1]); + soc_ac97_ops->write(ac97, i, cache[i>>1]); } return 0; @@ -334,14 +341,18 @@ static int wm9705_soc_resume(struct snd_soc_codec *codec) static int wm9705_soc_probe(struct snd_soc_codec *codec) { + struct snd_ac97 *ac97; int ret = 0; - ret = snd_soc_new_ac97_codec(codec); - if (ret < 0) { + ac97 = snd_soc_new_ac97_codec(codec); + if (IS_ERR(ac97)) { + ret = PTR_ERR(ac97); dev_err(codec->dev, "Failed to register AC97 codec\n"); return ret; } + snd_soc_codec_set_drvdata(codec, ac97); + ret = wm9705_reset(codec); if (ret) goto reset_err; @@ -349,13 +360,15 @@ static int wm9705_soc_probe(struct snd_soc_codec *codec) return 0; reset_err: - snd_soc_free_ac97_codec(codec); + snd_soc_free_ac97_codec(ac97); return ret; } static int wm9705_soc_remove(struct snd_soc_codec *codec) { - snd_soc_free_ac97_codec(codec); + struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); + + snd_soc_free_ac97_codec(ac97); return 0; } diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index 9fa794baa5f8..52a211be5b47 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -24,6 +24,7 @@ #include "wm9712.h" struct wm9712_priv { + struct snd_ac97 *ac97; unsigned int hp_mixer[2]; struct mutex lock; }; @@ -484,12 +485,13 @@ static const struct snd_soc_dapm_route wm9712_audio_map[] = { static unsigned int ac97_read(struct snd_soc_codec *codec, unsigned int reg) { + struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec); u16 *cache = codec->reg_cache; if (reg == AC97_RESET || reg == AC97_GPIO_STATUS || reg == AC97_VENDOR_ID1 || reg == AC97_VENDOR_ID2 || reg == AC97_REC_GAIN) - return soc_ac97_ops->read(codec->ac97, reg); + return soc_ac97_ops->read(wm9712->ac97, reg); else { reg = reg >> 1; @@ -503,9 +505,10 @@ static unsigned int ac97_read(struct snd_soc_codec *codec, static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int val) { + struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec); u16 *cache = codec->reg_cache; - soc_ac97_ops->write(codec->ac97, reg, val); + soc_ac97_ops->write(wm9712->ac97, reg, val); reg = reg >> 1; if (reg < (ARRAY_SIZE(wm9712_reg))) cache[reg] = val; @@ -613,15 +616,17 @@ static int wm9712_set_bias_level(struct snd_soc_codec *codec, static int wm9712_reset(struct snd_soc_codec *codec, int try_warm) { + struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec); + if (try_warm && soc_ac97_ops->warm_reset) { - soc_ac97_ops->warm_reset(codec->ac97); + soc_ac97_ops->warm_reset(wm9712->ac97); if (ac97_read(codec, 0) == wm9712_reg[0]) return 1; } - soc_ac97_ops->reset(codec->ac97); + soc_ac97_ops->reset(wm9712->ac97); if (soc_ac97_ops->warm_reset) - soc_ac97_ops->warm_reset(codec->ac97); + soc_ac97_ops->warm_reset(wm9712->ac97); if (ac97_read(codec, 0) != wm9712_reg[0]) goto err; return 0; @@ -639,6 +644,7 @@ static int wm9712_soc_suspend(struct snd_soc_codec *codec) static int wm9712_soc_resume(struct snd_soc_codec *codec) { + struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec); int i, ret; u16 *cache = codec->reg_cache; @@ -654,7 +660,7 @@ static int wm9712_soc_resume(struct snd_soc_codec *codec) if (i == AC97_INT_PAGING || i == AC97_POWERDOWN || (i > 0x58 && i != 0x5c)) continue; - soc_ac97_ops->write(codec->ac97, i, cache[i>>1]); + soc_ac97_ops->write(wm9712->ac97, i, cache[i>>1]); } } @@ -663,11 +669,13 @@ static int wm9712_soc_resume(struct snd_soc_codec *codec) static int wm9712_soc_probe(struct snd_soc_codec *codec) { + struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec); int ret = 0; - ret = snd_soc_new_ac97_codec(codec); - if (ret < 0) { - dev_err(codec->dev, "Failed to register AC97 codec\n"); + wm9712->ac97 = snd_soc_new_ac97_codec(codec); + if (IS_ERR(wm9712->ac97)) { + ret = PTR_ERR(wm9712->ac97); + dev_err(codec->dev, "Failed to register AC97 codec: %d\n", ret); return ret; } @@ -683,13 +691,15 @@ static int wm9712_soc_probe(struct snd_soc_codec *codec) return 0; reset_err: - snd_soc_free_ac97_codec(codec); + snd_soc_free_ac97_codec(wm9712->ac97); return ret; } static int wm9712_soc_remove(struct snd_soc_codec *codec) { - snd_soc_free_ac97_codec(codec); + struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec); + + snd_soc_free_ac97_codec(wm9712->ac97); return 0; } diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index cd1b266d3af3..6c95d98b0eb1 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -30,6 +30,7 @@ #include "wm9713.h" struct wm9713_priv { + struct snd_ac97 *ac97; u32 pll_in; /* PLL input frequency */ unsigned int hp_mixer[2]; struct mutex lock; @@ -674,12 +675,13 @@ static const struct snd_soc_dapm_route wm9713_audio_map[] = { static unsigned int ac97_read(struct snd_soc_codec *codec, unsigned int reg) { + struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec); u16 *cache = codec->reg_cache; if (reg == AC97_RESET || reg == AC97_GPIO_STATUS || reg == AC97_VENDOR_ID1 || reg == AC97_VENDOR_ID2 || reg == AC97_CD) - return soc_ac97_ops->read(codec->ac97, reg); + return soc_ac97_ops->read(wm9713->ac97, reg); else { reg = reg >> 1; @@ -693,8 +695,10 @@ static unsigned int ac97_read(struct snd_soc_codec *codec, static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int val) { + struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec); + u16 *cache = codec->reg_cache; - soc_ac97_ops->write(codec->ac97, reg, val); + soc_ac97_ops->write(wm9713->ac97, reg, val); reg = reg >> 1; if (reg < (ARRAY_SIZE(wm9713_reg))) cache[reg] = val; @@ -1121,15 +1125,17 @@ static struct snd_soc_dai_driver wm9713_dai[] = { int wm9713_reset(struct snd_soc_codec *codec, int try_warm) { + struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec); + if (try_warm && soc_ac97_ops->warm_reset) { - soc_ac97_ops->warm_reset(codec->ac97); + soc_ac97_ops->warm_reset(wm9713->ac97); if (ac97_read(codec, 0) == wm9713_reg[0]) return 1; } - soc_ac97_ops->reset(codec->ac97); + soc_ac97_ops->reset(wm9713->ac97); if (soc_ac97_ops->warm_reset) - soc_ac97_ops->warm_reset(codec->ac97); + soc_ac97_ops->warm_reset(wm9713->ac97); if (ac97_read(codec, 0) != wm9713_reg[0]) { dev_err(codec->dev, "Failed to reset: AC97 link error\n"); return -EIO; @@ -1207,7 +1213,7 @@ static int wm9713_soc_resume(struct snd_soc_codec *codec) if (i == AC97_POWERDOWN || i == AC97_EXTENDED_MID || i == AC97_EXTENDED_MSTATUS || i > 0x66) continue; - soc_ac97_ops->write(codec->ac97, i, cache[i>>1]); + soc_ac97_ops->write(wm9713->ac97, i, cache[i>>1]); } } @@ -1216,11 +1222,12 @@ static int wm9713_soc_resume(struct snd_soc_codec *codec) static int wm9713_soc_probe(struct snd_soc_codec *codec) { + struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec); int ret = 0, reg; - ret = snd_soc_new_ac97_codec(codec); - if (ret < 0) - return ret; + wm9713->ac97 = snd_soc_new_ac97_codec(codec); + if (IS_ERR(wm9713->ac97)) + return PTR_ERR(wm9713->ac97); /* do a cold reset for the controller and then try * a warm reset followed by an optional cold reset for codec */ @@ -1238,13 +1245,15 @@ static int wm9713_soc_probe(struct snd_soc_codec *codec) return 0; reset_err: - snd_soc_free_ac97_codec(codec); + snd_soc_free_ac97_codec(wm9713->ac97); return ret; } static int wm9713_soc_remove(struct snd_soc_codec *codec) { - snd_soc_free_ac97_codec(codec); + struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec); + + snd_soc_free_ac97_codec(wm9713->ac97); return 0; } diff --git a/sound/soc/soc-ac97.c b/sound/soc/soc-ac97.c index 920d76c43827..2e10e9a38376 100644 --- a/sound/soc/soc-ac97.c +++ b/sound/soc/soc-ac97.c @@ -53,30 +53,33 @@ static void soc_ac97_device_release(struct device *dev) * * Initialises AC97 codec resources for use by ad-hoc devices only. */ -int snd_soc_new_ac97_codec(struct snd_soc_codec *codec) +struct snd_ac97 *snd_soc_new_ac97_codec(struct snd_soc_codec *codec) { + struct snd_ac97 *ac97; int ret; - codec->ac97 = kzalloc(sizeof(struct snd_ac97), GFP_KERNEL); - if (codec->ac97 == NULL) - return -ENOMEM; + ac97 = kzalloc(sizeof(struct snd_ac97), GFP_KERNEL); + if (ac97 == NULL) + return ERR_PTR(-ENOMEM); - codec->ac97->bus = &soc_ac97_bus; - codec->ac97->num = 0; + ac97->bus = &soc_ac97_bus; + ac97->num = 0; - codec->ac97->dev.bus = &ac97_bus_type; - codec->ac97->dev.parent = codec->component.card->dev; - codec->ac97->dev.release = soc_ac97_device_release; + ac97->dev.bus = &ac97_bus_type; + ac97->dev.parent = codec->component.card->dev; + ac97->dev.release = soc_ac97_device_release; - dev_set_name(&codec->ac97->dev, "%d-%d:%s", + dev_set_name(&ac97->dev, "%d-%d:%s", codec->component.card->snd_card->number, 0, codec->component.name); - ret = device_register(&codec->ac97->dev); - if (ret) - put_device(&codec->ac97->dev); + ret = device_register(&ac97->dev); + if (ret) { + put_device(&ac97->dev); + return ERR_PTR(ret); + } - return ret; + return ac97; } EXPORT_SYMBOL_GPL(snd_soc_new_ac97_codec); @@ -86,12 +89,11 @@ EXPORT_SYMBOL_GPL(snd_soc_new_ac97_codec); * * Frees AC97 codec device resources. */ -void snd_soc_free_ac97_codec(struct snd_soc_codec *codec) +void snd_soc_free_ac97_codec(struct snd_ac97 *ac97) { - device_del(&codec->ac97->dev); - codec->ac97->bus = NULL; - put_device(&codec->ac97->dev); - codec->ac97 = NULL; + device_del(&ac97->dev); + ac97->bus = NULL; + put_device(&ac97->dev); } EXPORT_SYMBOL_GPL(snd_soc_free_ac97_codec); -- cgit v1.2.3 From a5a267cf9ca9937b0ef946b502657ae7638282f6 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Tue, 18 Nov 2014 17:42:54 +0530 Subject: ASoC: rt286: build warning of section mismatch while building we were getting the following build warning: Section mismatch in reference from the function rt286_i2c_probe() to the variable .init.data:force_combo_jack_table The function rt286_i2c_probe() references the variable __initdata force_combo_jack_table. This is often because rt286_i2c_probe lacks a __initdata annotation or the annotation of force_combo_jack_table is wrong. we were getting the warning as force_combo_jack_table was marked with __initdata Signed-off-by: Sudip Mukherjee Signed-off-by: Mark Brown --- sound/soc/codecs/rt286.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c index 2e818aaca550..2cd4fe463102 100644 --- a/sound/soc/codecs/rt286.c +++ b/sound/soc/codecs/rt286.c @@ -1206,7 +1206,7 @@ static const struct acpi_device_id rt286_acpi_match[] = { }; MODULE_DEVICE_TABLE(acpi, rt286_acpi_match); -static struct dmi_system_id force_combo_jack_table[] __initdata = { +static struct dmi_system_id force_combo_jack_table[] = { { .ident = "Intel Wilson Beach", .matches = { -- cgit v1.2.3 From d6d521799fac14e14dead4e9428158340ff6b95f Mon Sep 17 00:00:00 2001 From: JS Park Date: Tue, 18 Nov 2014 16:07:22 +0000 Subject: ASoC: wm_adsp: Fix memory leak in wm_adsp_setup_algs Signed-off-by: JS Park Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 0a08ef5e27c8..6a2a03570977 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -1053,8 +1053,10 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp) be32_to_cpu(adsp1_alg[i].zm)); region = kzalloc(sizeof(*region), GFP_KERNEL); - if (!region) - return -ENOMEM; + if (!region) { + ret = -ENOMEM; + goto out; + } region->type = WMFW_ADSP1_DM; region->alg = be32_to_cpu(adsp1_alg[i].alg.id); region->base = be32_to_cpu(adsp1_alg[i].dm); @@ -1071,8 +1073,10 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp) } region = kzalloc(sizeof(*region), GFP_KERNEL); - if (!region) - return -ENOMEM; + if (!region) { + ret = -ENOMEM; + goto out; + } region->type = WMFW_ADSP1_ZM; region->alg = be32_to_cpu(adsp1_alg[i].alg.id); region->base = be32_to_cpu(adsp1_alg[i].zm); @@ -1101,8 +1105,10 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp) be32_to_cpu(adsp2_alg[i].zm)); region = kzalloc(sizeof(*region), GFP_KERNEL); - if (!region) - return -ENOMEM; + if (!region) { + ret = -ENOMEM; + goto out; + } region->type = WMFW_ADSP2_XM; region->alg = be32_to_cpu(adsp2_alg[i].alg.id); region->base = be32_to_cpu(adsp2_alg[i].xm); @@ -1119,8 +1125,10 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp) } region = kzalloc(sizeof(*region), GFP_KERNEL); - if (!region) - return -ENOMEM; + if (!region) { + ret = -ENOMEM; + goto out; + } region->type = WMFW_ADSP2_YM; region->alg = be32_to_cpu(adsp2_alg[i].alg.id); region->base = be32_to_cpu(adsp2_alg[i].ym); @@ -1137,8 +1145,10 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp) } region = kzalloc(sizeof(*region), GFP_KERNEL); - if (!region) - return -ENOMEM; + if (!region) { + ret = -ENOMEM; + goto out; + } region->type = WMFW_ADSP2_ZM; region->alg = be32_to_cpu(adsp2_alg[i].alg.id); region->base = be32_to_cpu(adsp2_alg[i].zm); -- cgit v1.2.3 From 00e4c3b6e285da90e736fbefff3d9e74a200ee54 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 18 Nov 2014 16:25:27 +0000 Subject: ASoC: wm_adsp: Move core_ena to be co-located with start bit Many firmwares do not wait for the start bit before they begin processing audio, whilst this is a bug on the firmware side there are too many such firmwares in the wild to ignore the situation. This patch moves the core enable to happen at same time as the start, the firmware looses the ability to overlap its own startup with the audio path bring up but we ensure that all firmwares behave. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 67124783558a..cce9020933c6 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -1595,13 +1595,6 @@ static void wm_adsp2_boot_work(struct work_struct *work) if (ret != 0) goto err; - ret = regmap_update_bits_async(dsp->regmap, - dsp->base + ADSP2_CONTROL, - ADSP2_CORE_ENA, - ADSP2_CORE_ENA); - if (ret != 0) - goto err; - dsp->running = true; return; @@ -1651,8 +1644,8 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, - ADSP2_START, - ADSP2_START); + ADSP2_CORE_ENA | ADSP2_START, + ADSP2_CORE_ENA | ADSP2_START); if (ret != 0) goto err; break; -- cgit v1.2.3 From 2dfe2b08d280c15cc7266de40412c2a911643148 Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Wed, 19 Nov 2014 13:52:18 +0800 Subject: ASoC: rt5677: Align the reg_default table with tab character Align the reg_default table with tab character Signed-off-by: Oder Chiou Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 9ae2e8468006..b2d88bb14cfe 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -55,13 +55,13 @@ static const struct regmap_range_cfg rt5677_ranges[] = { }; static const struct reg_default init_list[] = { - {RT5677_ASRC_12, 0x0018}, - {RT5677_PR_BASE + 0x3d, 0x364d}, - {RT5677_PR_BASE + 0x17, 0x4fc0}, - {RT5677_PR_BASE + 0x13, 0x0312}, - {RT5677_PR_BASE + 0x1e, 0x0000}, - {RT5677_PR_BASE + 0x12, 0x0eaa}, - {RT5677_PR_BASE + 0x14, 0x018a}, + {RT5677_ASRC_12, 0x0018}, + {RT5677_PR_BASE + 0x3d, 0x364d}, + {RT5677_PR_BASE + 0x17, 0x4fc0}, + {RT5677_PR_BASE + 0x13, 0x0312}, + {RT5677_PR_BASE + 0x1e, 0x0000}, + {RT5677_PR_BASE + 0x12, 0x0eaa}, + {RT5677_PR_BASE + 0x14, 0x018a}, }; #define RT5677_INIT_REG_LEN ARRAY_SIZE(init_list) -- cgit v1.2.3 From 35d40d10e95f52569570dc4e26da19f072aa256d Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Wed, 19 Nov 2014 13:52:19 +0800 Subject: ASoC: rt5677: Follow the gpio naming rule to rename the irq function Follow the gpio naming rule to rename the irq function. Signed-off-by: Oder Chiou Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index b2d88bb14cfe..dd080cdbff10 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -4552,7 +4552,7 @@ static struct regmap_irq_chip rt5677_irq_chip = { .mask_invert = 1, }; -static int rt5677_irq_init(struct i2c_client *i2c) +static int rt5677_init_irq(struct i2c_client *i2c) { int ret; struct rt5677_priv *rt5677 = i2c_get_clientdata(i2c); @@ -4579,7 +4579,7 @@ static int rt5677_irq_init(struct i2c_client *i2c) return 0; } -static void rt5677_irq_exit(struct i2c_client *i2c) +static void rt5677_free_irq(struct i2c_client *i2c) { struct rt5677_priv *rt5677 = i2c_get_clientdata(i2c); @@ -4693,7 +4693,7 @@ static int rt5677_i2c_probe(struct i2c_client *i2c, } rt5677_init_gpio(i2c); - rt5677_irq_init(i2c); + rt5677_init_irq(i2c); return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5677, rt5677_dai, ARRAY_SIZE(rt5677_dai)); @@ -4701,9 +4701,8 @@ static int rt5677_i2c_probe(struct i2c_client *i2c, static int rt5677_i2c_remove(struct i2c_client *i2c) { - rt5677_irq_exit(i2c); - snd_soc_unregister_codec(&i2c->dev); + rt5677_free_irq(i2c); rt5677_free_gpio(i2c); return 0; -- cgit v1.2.3 From 683996cb2255373c2055e7b69584ac153eb49f42 Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Wed, 19 Nov 2014 13:52:20 +0800 Subject: ASoC: rt5677: Set the slow charge of the vref in the end of the power sequences Set the slow charge of the vref in the end of the power sequences Signed-off-by: Oder Chiou Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677.c | 56 ++++++++++++++++++++++++++++++++++++++--------- sound/soc/codecs/rt5677.h | 1 + 2 files changed, 47 insertions(+), 10 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index dd080cdbff10..f2211f14ba41 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -2184,6 +2184,31 @@ static int rt5677_if2_adc_tdm_event(struct snd_soc_dapm_widget *w, return 0; } +static int rt5677_vref_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + if (codec->dapm.bias_level != SND_SOC_BIAS_ON && + !rt5677->is_vref_slow) { + mdelay(20); + regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1, + RT5677_PWR_FV1 | RT5677_PWR_FV2, + RT5677_PWR_FV1 | RT5677_PWR_FV2); + rt5677->is_vref_slow = true; + } + break; + + default: + return 0; + } + + return 0; +} + static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("PLL1", RT5677_PWR_ANLG2, RT5677_PWR_PLL1_BIT, 0, rt5677_set_pll1_event, SND_SOC_DAPM_POST_PMU), @@ -2669,13 +2694,20 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = { SND_SOC_DAPM_MUX("PDM2 R Mux", RT5677_PDM_OUT_CTRL, RT5677_M_PDM2_R_SFT, 1, &rt5677_pdm2_r_mux), - SND_SOC_DAPM_PGA_S("LOUT1 amp", 1, RT5677_PWR_ANLG1, RT5677_PWR_LO1_BIT, + SND_SOC_DAPM_PGA_S("LOUT1 amp", 0, RT5677_PWR_ANLG1, RT5677_PWR_LO1_BIT, 0, NULL, 0), - SND_SOC_DAPM_PGA_S("LOUT2 amp", 1, RT5677_PWR_ANLG1, RT5677_PWR_LO2_BIT, + SND_SOC_DAPM_PGA_S("LOUT2 amp", 0, RT5677_PWR_ANLG1, RT5677_PWR_LO2_BIT, 0, NULL, 0), - SND_SOC_DAPM_PGA_S("LOUT3 amp", 1, RT5677_PWR_ANLG1, RT5677_PWR_LO3_BIT, + SND_SOC_DAPM_PGA_S("LOUT3 amp", 0, RT5677_PWR_ANLG1, RT5677_PWR_LO3_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA_S("LOUT1 vref", 1, SND_SOC_NOPM, 0, 0, + rt5677_vref_event, SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PGA_S("LOUT2 vref", 1, SND_SOC_NOPM, 0, 0, + rt5677_vref_event, SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PGA_S("LOUT3 vref", 1, SND_SOC_NOPM, 0, 0, + rt5677_vref_event, SND_SOC_DAPM_POST_PMU), + /* Output Lines */ SND_SOC_DAPM_OUTPUT("LOUT1"), SND_SOC_DAPM_OUTPUT("LOUT2"), @@ -2684,6 +2716,8 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = { SND_SOC_DAPM_OUTPUT("PDM1R"), SND_SOC_DAPM_OUTPUT("PDM2L"), SND_SOC_DAPM_OUTPUT("PDM2R"), + + SND_SOC_DAPM_POST("vref", rt5677_vref_event), }; static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { @@ -3572,9 +3606,13 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { { "LOUT2 amp", NULL, "DAC 2" }, { "LOUT3 amp", NULL, "DAC 3" }, - { "LOUT1", NULL, "LOUT1 amp" }, - { "LOUT2", NULL, "LOUT2 amp" }, - { "LOUT3", NULL, "LOUT3 amp" }, + { "LOUT1 vref", NULL, "LOUT1 amp" }, + { "LOUT2 vref", NULL, "LOUT2 amp" }, + { "LOUT3 vref", NULL, "LOUT3 amp" }, + + { "LOUT1", NULL, "LOUT1 vref" }, + { "LOUT2", NULL, "LOUT2 vref" }, + { "LOUT3", NULL, "LOUT3 vref" }, { "PDM1L", NULL, "PDM1 L Mux" }, { "PDM1R", NULL, "PDM1 R Mux" }, @@ -3957,14 +3995,12 @@ static int rt5677_set_bias_level(struct snd_soc_codec *codec, RT5677_PR_BASE + RT5677_BIAS_CUR4, 0x0f00, 0x0f00); regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1, + RT5677_PWR_FV1 | RT5677_PWR_FV2 | RT5677_PWR_VREF1 | RT5677_PWR_MB | RT5677_PWR_BG | RT5677_PWR_VREF2, RT5677_PWR_VREF1 | RT5677_PWR_MB | RT5677_PWR_BG | RT5677_PWR_VREF2); - mdelay(20); - regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1, - RT5677_PWR_FV1 | RT5677_PWR_FV2, - RT5677_PWR_FV1 | RT5677_PWR_FV2); + rt5677->is_vref_slow = false; regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG2, RT5677_PWR_CORE, RT5677_PWR_CORE); regmap_update_bits(rt5677->regmap, RT5677_DIG_MISC, diff --git a/sound/soc/codecs/rt5677.h b/sound/soc/codecs/rt5677.h index 2979d5a05789..a02f64c23596 100644 --- a/sound/soc/codecs/rt5677.h +++ b/sound/soc/codecs/rt5677.h @@ -1687,6 +1687,7 @@ struct rt5677_priv { bool dsp_vad_en; struct regmap_irq_chip_data *irq_data; bool is_dsp_mode; + bool is_vref_slow; }; #endif /* __RT5677_H__ */ -- cgit v1.2.3 From 82d14636418299b4f54511a02373796b38747b48 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 18 Nov 2014 19:45:53 +0100 Subject: ASoC: ad1980: Convert to regmap This patch converts the ad1980 driver to use regmap for its IO. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 1 + sound/soc/codecs/ad1980.c | 141 ++++++++++++++++++++++++++++------------------ 2 files changed, 88 insertions(+), 54 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index a68d1731a8fd..6a66216a9c0f 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -223,6 +223,7 @@ config SND_SOC_AD193X_I2C select SND_SOC_AD193X config SND_SOC_AD1980 + select REGMAP_AC97 tristate config SND_SOC_AD73311 diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c index 93bd47db6d0c..5fd4a29a2fe0 100644 --- a/sound/soc/codecs/ad1980.c +++ b/sound/soc/codecs/ad1980.c @@ -24,32 +24,86 @@ #include #include #include +#include #include #include #include #include #include -/* - * AD1980 register cache - */ -static const u16 ad1980_reg[] = { - 0x0090, 0x8000, 0x8000, 0x8000, /* 0 - 6 */ - 0x0000, 0x0000, 0x8008, 0x8008, /* 8 - e */ - 0x8808, 0x8808, 0x0000, 0x8808, /* 10 - 16 */ - 0x8808, 0x0000, 0x8000, 0x0000, /* 18 - 1e */ - 0x0000, 0x0000, 0x0000, 0x0000, /* 20 - 26 */ - 0x03c7, 0x0000, 0xbb80, 0xbb80, /* 28 - 2e */ - 0xbb80, 0xbb80, 0x0000, 0x8080, /* 30 - 36 */ - 0x8080, 0x2000, 0x0000, 0x0000, /* 38 - 3e */ - 0x0000, 0x0000, 0x0000, 0x0000, /* reserved */ - 0x0000, 0x0000, 0x0000, 0x0000, /* reserved */ - 0x0000, 0x0000, 0x0000, 0x0000, /* reserved */ - 0x0000, 0x0000, 0x0000, 0x0000, /* reserved */ - 0x8080, 0x0000, 0x0000, 0x0000, /* 60 - 66 */ - 0x0000, 0x0000, 0x0000, 0x0000, /* reserved */ - 0x0000, 0x0000, 0x1001, 0x0000, /* 70 - 76 */ - 0x0000, 0x0000, 0x4144, 0x5370 /* 78 - 7e */ +static const struct reg_default ad1980_reg_defaults[] = { + { 0x02, 0x8000 }, + { 0x04, 0x8000 }, + { 0x06, 0x8000 }, + { 0x0c, 0x8008 }, + { 0x0e, 0x8008 }, + { 0x10, 0x8808 }, + { 0x12, 0x8808 }, + { 0x16, 0x8808 }, + { 0x18, 0x8808 }, + { 0x1a, 0x0000 }, + { 0x1c, 0x8000 }, + { 0x20, 0x0000 }, + { 0x28, 0x03c7 }, + { 0x2c, 0xbb80 }, + { 0x2e, 0xbb80 }, + { 0x30, 0xbb80 }, + { 0x32, 0xbb80 }, + { 0x36, 0x8080 }, + { 0x38, 0x8080 }, + { 0x3a, 0x2000 }, + { 0x60, 0x0000 }, + { 0x62, 0x0000 }, + { 0x72, 0x0000 }, + { 0x74, 0x1001 }, + { 0x76, 0x0000 }, +}; + +static bool ad1980_readable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case AC97_RESET ... AC97_MASTER_MONO: + case AC97_PHONE ... AC97_CD: + case AC97_AUX ... AC97_GENERAL_PURPOSE: + case AC97_POWERDOWN ... AC97_PCM_LR_ADC_RATE: + case AC97_SPDIF: + case AC97_CODEC_CLASS_REV: + case AC97_PCI_SVID: + case AC97_AD_CODEC_CFG: + case AC97_AD_JACK_SPDIF: + case AC97_AD_SERIAL_CFG: + case AC97_VENDOR_ID1: + case AC97_VENDOR_ID2: + return true; + default: + return false; + } +} + +static bool ad1980_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case AC97_VENDOR_ID1: + case AC97_VENDOR_ID2: + return false; + default: + return ad1980_readable_reg(dev, reg); + } +} + +static const struct regmap_config ad1980_regmap_config = { + .reg_bits = 16, + .reg_stride = 2, + .val_bits = 16, + .max_register = 0x7e, + .cache_type = REGCACHE_RBTREE, + + .volatile_reg = regmap_ac97_default_volatile, + .readable_reg = ad1980_readable_reg, + .writeable_reg = ad1980_writeable_reg, + + .reg_defaults = ad1980_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(ad1980_reg_defaults), }; static const char *ad1980_rec_sel[] = {"Mic", "CD", "NC", "AUX", "Line", @@ -135,39 +189,13 @@ static const struct snd_soc_dapm_route ad1980_dapm_routes[] = { static unsigned int ac97_read(struct snd_soc_codec *codec, unsigned int reg) { - struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); - u16 *cache = codec->reg_cache; - - switch (reg) { - case AC97_RESET: - case AC97_INT_PAGING: - case AC97_POWERDOWN: - case AC97_EXTENDED_STATUS: - case AC97_VENDOR_ID1: - case AC97_VENDOR_ID2: - return soc_ac97_ops->read(ac97, reg); - default: - reg = reg >> 1; - - if (reg >= ARRAY_SIZE(ad1980_reg)) - return -EINVAL; - - return cache[reg]; - } + return snd_soc_read(codec, reg); } static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int val) { - struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); - u16 *cache = codec->reg_cache; - - soc_ac97_ops->write(ac97, reg, val); - reg = reg >> 1; - if (reg < ARRAY_SIZE(ad1980_reg)) - cache[reg] = val; - - return 0; + return snd_soc_write(codec, reg, val); } static struct snd_soc_dai_driver ad1980_dai = { @@ -219,6 +247,7 @@ static int ad1980_reset(struct snd_soc_codec *codec, int try_warm) static int ad1980_soc_probe(struct snd_soc_codec *codec) { struct snd_ac97 *ac97; + struct regmap *regmap; int ret; u16 vendor_id2; u16 ext_status; @@ -230,6 +259,13 @@ static int ad1980_soc_probe(struct snd_soc_codec *codec) return ret; } + regmap = regmap_init_ac97(ac97, &ad1980_regmap_config); + if (IS_ERR(regmap)) { + ret = PTR_ERR(regmap); + goto err_free_ac97; + } + + snd_soc_codec_init_regmap(codec, regmap); snd_soc_codec_set_drvdata(codec, ac97); ret = ad1980_reset(codec, 0); @@ -268,6 +304,8 @@ static int ad1980_soc_probe(struct snd_soc_codec *codec) return 0; reset_err: + snd_soc_codec_exit_regmap(codec); +err_free_ac97: snd_soc_free_ac97_codec(ac97); return ret; } @@ -276,6 +314,7 @@ static int ad1980_soc_remove(struct snd_soc_codec *codec) { struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); + snd_soc_codec_exit_regmap(codec); snd_soc_free_ac97_codec(ac97); return 0; } @@ -283,12 +322,6 @@ static int ad1980_soc_remove(struct snd_soc_codec *codec) static struct snd_soc_codec_driver soc_codec_dev_ad1980 = { .probe = ad1980_soc_probe, .remove = ad1980_soc_remove, - .reg_cache_size = ARRAY_SIZE(ad1980_reg), - .reg_word_size = sizeof(u16), - .reg_cache_default = ad1980_reg, - .reg_cache_step = 2, - .write = ac97_write, - .read = ac97_read, .controls = ad1980_snd_ac97_controls, .num_controls = ARRAY_SIZE(ad1980_snd_ac97_controls), -- cgit v1.2.3 From 17bb577328a00e7251c8e552471b6583173ca77d Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 18 Nov 2014 19:45:54 +0100 Subject: ASoC: ad1980: Remove ac97_read/ac97_write wrappers Since the regmap conversion ac97_read/ac97_write are just simple wrappers around snd_soc_read/snd_soc_write. Use those instead directly and remove the wrappers. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/ad1980.c | 36 ++++++++++++------------------------ 1 file changed, 12 insertions(+), 24 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c index 5fd4a29a2fe0..2860eef8610c 100644 --- a/sound/soc/codecs/ad1980.c +++ b/sound/soc/codecs/ad1980.c @@ -186,18 +186,6 @@ static const struct snd_soc_dapm_route ad1980_dapm_routes[] = { { "HP_OUT_R", NULL, "Playback" }, }; -static unsigned int ac97_read(struct snd_soc_codec *codec, - unsigned int reg) -{ - return snd_soc_read(codec, reg); -} - -static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int val) -{ - return snd_soc_write(codec, reg, val); -} - static struct snd_soc_dai_driver ad1980_dai = { .name = "ad1980-hifi", .playback = { @@ -222,7 +210,7 @@ static int ad1980_reset(struct snd_soc_codec *codec, int try_warm) do { if (try_warm && soc_ac97_ops->warm_reset) { soc_ac97_ops->warm_reset(ac97); - if (ac97_read(codec, AC97_RESET) == 0x0090) + if (snd_soc_read(codec, AC97_RESET) == 0x0090) return 1; } @@ -233,9 +221,9 @@ static int ad1980_reset(struct snd_soc_codec *codec, int try_warm) * case the first nibble of data is eaten by the addr. (Tag is * always 16 bit) */ - ac97_write(codec, AC97_AD_SERIAL_CFG, 0x9900); + snd_soc_write(codec, AC97_AD_SERIAL_CFG, 0x9900); - if (ac97_read(codec, AC97_RESET) == 0x0090) + if (snd_soc_read(codec, AC97_RESET) == 0x0090) return 0; } while (retry_cnt++ < 10); @@ -273,12 +261,12 @@ static int ad1980_soc_probe(struct snd_soc_codec *codec) goto reset_err; /* Read out vendor ID to make sure it is ad1980 */ - if (ac97_read(codec, AC97_VENDOR_ID1) != 0x4144) { + if (snd_soc_read(codec, AC97_VENDOR_ID1) != 0x4144) { ret = -ENODEV; goto reset_err; } - vendor_id2 = ac97_read(codec, AC97_VENDOR_ID2); + vendor_id2 = snd_soc_read(codec, AC97_VENDOR_ID2); if (vendor_id2 != 0x5370) { if (vendor_id2 != 0x5374) { @@ -291,15 +279,15 @@ static int ad1980_soc_probe(struct snd_soc_codec *codec) } /* unmute captures and playbacks volume */ - ac97_write(codec, AC97_MASTER, 0x0000); - ac97_write(codec, AC97_PCM, 0x0000); - ac97_write(codec, AC97_REC_GAIN, 0x0000); - ac97_write(codec, AC97_CENTER_LFE_MASTER, 0x0000); - ac97_write(codec, AC97_SURROUND_MASTER, 0x0000); + snd_soc_write(codec, AC97_MASTER, 0x0000); + snd_soc_write(codec, AC97_PCM, 0x0000); + snd_soc_write(codec, AC97_REC_GAIN, 0x0000); + snd_soc_write(codec, AC97_CENTER_LFE_MASTER, 0x0000); + snd_soc_write(codec, AC97_SURROUND_MASTER, 0x0000); /*power on LFE/CENTER/Surround DACs*/ - ext_status = ac97_read(codec, AC97_EXTENDED_STATUS); - ac97_write(codec, AC97_EXTENDED_STATUS, ext_status&~0x3800); + ext_status = snd_soc_read(codec, AC97_EXTENDED_STATUS); + snd_soc_write(codec, AC97_EXTENDED_STATUS, ext_status&~0x3800); return 0; -- cgit v1.2.3 From 50c0f21b42dd4cd02b51f82274f66912d9a7fa32 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 19 Nov 2014 18:29:02 +0100 Subject: ASoC: sigmadsp: Refuse to load firmware files with a non-supported version Make sure to check the version field of the firmware header to make sure to not accidentally try to parse a firmware file with a different layout. Trying to do so can result in loading invalid firmware code to the device. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- sound/soc/codecs/sigmadsp.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/sigmadsp.c b/sound/soc/codecs/sigmadsp.c index f2de7e049bc6..81a38dd9af1f 100644 --- a/sound/soc/codecs/sigmadsp.c +++ b/sound/soc/codecs/sigmadsp.c @@ -159,6 +159,13 @@ int _process_sigma_firmware(struct device *dev, goto done; } + if (ssfw_head->version != 1) { + dev_err(dev, + "Failed to load firmware: Invalid version %d. Supported firmware versions: 1\n", + ssfw_head->version); + goto done; + } + crc = crc32(0, fw->data + sizeof(*ssfw_head), fw->size - sizeof(*ssfw_head)); pr_debug("%s: crc=%x\n", __func__, crc); -- cgit v1.2.3 From 6b25730f68073ee95079d241ea6aa7be00805254 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 19 Nov 2014 18:29:04 +0100 Subject: ASoC: sigmadsp: Drop support support SIGMA_ACTION_DELAY The official firmware generation tool never emitted any SIGMA_ACTION_DELAY instructions. Keeping support for it with the new restructured loader that also supports v2 will be difficult, so drop support for it. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/sigmadsp.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/sigmadsp.c b/sound/soc/codecs/sigmadsp.c index 81a38dd9af1f..4fd31434276b 100644 --- a/sound/soc/codecs/sigmadsp.c +++ b/sound/soc/codecs/sigmadsp.c @@ -7,7 +7,6 @@ */ #include -#include #include #include #include @@ -28,9 +27,6 @@ enum { SIGMA_ACTION_WRITEXBYTES = 0, SIGMA_ACTION_WRITESINGLE, SIGMA_ACTION_WRITESAFELOAD, - SIGMA_ACTION_DELAY, - SIGMA_ACTION_PLLWAIT, - SIGMA_ACTION_NOOP, SIGMA_ACTION_END, }; @@ -79,10 +75,6 @@ process_sigma_action(struct sigma_firmware *ssfw, struct sigma_action *sa) if (ret < 0) return -EINVAL; break; - case SIGMA_ACTION_DELAY: - udelay(len); - len = 0; - break; case SIGMA_ACTION_END: return 0; default: -- cgit v1.2.3 From d48b088e3ec45eeccf0fce0b75378e41428f47e9 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 19 Nov 2014 18:29:05 +0100 Subject: ASoC: sigmadsp: Restructure in preparation for fw v2 support The v2 file format of the SigmaDSP takes a more declarative style compared to the imperative style of the v1 format. In addition some features that are supported with v2 require the driver to keep state around for the firmware. This requires a bit of restructuring of both the firmware loader itself and the drivers making use of the firmware loader. Instead of loading and executing the firmware in place when the DSP is configured the firmware is now loaded at driver probe time. This is required since the new firmware format will in addition to the firmware data itself contain meta information describing the firmware and its requirements and capabilities. Those will for example be used to restrict the supported samplerates advertised by the driver to userspace to the list of samplerates supported for the firmware. This only does the restructuring required by the v2 format, but does not yet add support for the new format itself. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/adau1701.c | 33 ++++- sound/soc/codecs/adau1761.c | 21 ++- sound/soc/codecs/adau1781.c | 30 ++--- sound/soc/codecs/adau17x1.c | 54 +++++++- sound/soc/codecs/adau17x1.h | 9 +- sound/soc/codecs/sigmadsp-i2c.c | 52 ++++++-- sound/soc/codecs/sigmadsp-regmap.c | 38 ++++-- sound/soc/codecs/sigmadsp.c | 255 +++++++++++++++++++++++++++++++------ sound/soc/codecs/sigmadsp.h | 53 +++++--- 9 files changed, 424 insertions(+), 121 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c index 370b742117ef..05d5eb5984b6 100644 --- a/sound/soc/codecs/adau1701.c +++ b/sound/soc/codecs/adau1701.c @@ -103,6 +103,8 @@ struct adau1701 { unsigned int sysclk; struct regmap *regmap; u8 pin_config[12]; + + struct sigmadsp *sigmadsp; }; static const struct snd_kcontrol_new adau1701_controls[] = { @@ -238,12 +240,14 @@ static int adau1701_reg_read(void *context, unsigned int reg, return 0; } -static int adau1701_reset(struct snd_soc_codec *codec, unsigned int clkdiv) +static int adau1701_reset(struct snd_soc_codec *codec, unsigned int clkdiv, + unsigned int rate) { struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec); - struct i2c_client *client = to_i2c_client(codec->dev); int ret; + sigmadsp_reset(adau1701->sigmadsp); + if (clkdiv != ADAU1707_CLKDIV_UNSET && gpio_is_valid(adau1701->gpio_pll_mode[0]) && gpio_is_valid(adau1701->gpio_pll_mode[1])) { @@ -284,7 +288,7 @@ static int adau1701_reset(struct snd_soc_codec *codec, unsigned int clkdiv) * know the correct PLL setup */ if (clkdiv != ADAU1707_CLKDIV_UNSET) { - ret = process_sigma_firmware(client, ADAU1701_FIRMWARE); + ret = sigmadsp_setup(adau1701->sigmadsp, rate); if (ret) { dev_warn(codec->dev, "Failed to load firmware\n"); return ret; @@ -385,7 +389,7 @@ static int adau1701_hw_params(struct snd_pcm_substream *substream, * firmware upload. */ if (clkdiv != adau1701->pll_clkdiv) { - ret = adau1701_reset(codec, clkdiv); + ret = adau1701_reset(codec, clkdiv, params_rate(params)); if (ret < 0) return ret; } @@ -554,6 +558,14 @@ static int adau1701_set_sysclk(struct snd_soc_codec *codec, int clk_id, return 0; } +static int adau1701_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(dai->codec); + + return sigmadsp_restrict_params(adau1701->sigmadsp, substream); +} + #define ADAU1701_RATES (SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | \ SNDRV_PCM_RATE_192000) @@ -564,6 +576,7 @@ static const struct snd_soc_dai_ops adau1701_dai_ops = { .set_fmt = adau1701_set_dai_fmt, .hw_params = adau1701_hw_params, .digital_mute = adau1701_digital_mute, + .startup = adau1701_startup, }; static struct snd_soc_dai_driver adau1701_dai = { @@ -600,6 +613,10 @@ static int adau1701_probe(struct snd_soc_codec *codec) unsigned int val; struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec); + ret = sigmadsp_attach(adau1701->sigmadsp, &codec->component); + if (ret) + return ret; + /* * Let the pll_clkdiv variable default to something that won't happen * at runtime. That way, we can postpone the firmware download from @@ -609,7 +626,7 @@ static int adau1701_probe(struct snd_soc_codec *codec) adau1701->pll_clkdiv = ADAU1707_CLKDIV_UNSET; /* initalize with pre-configured pll mode settings */ - ret = adau1701_reset(codec, adau1701->pll_clkdiv); + ret = adau1701_reset(codec, adau1701->pll_clkdiv, 0); if (ret < 0) return ret; @@ -722,6 +739,12 @@ static int adau1701_i2c_probe(struct i2c_client *client, adau1701->gpio_pll_mode[1] = gpio_pll_mode[1]; i2c_set_clientdata(client, adau1701); + + adau1701->sigmadsp = devm_sigmadsp_init_i2c(client, NULL, + ADAU1701_FIRMWARE); + if (IS_ERR(adau1701->sigmadsp)) + return PTR_ERR(adau1701->sigmadsp); + ret = snd_soc_register_codec(&client->dev, &adau1701_codec_drv, &adau1701_dai, 1); return ret; diff --git a/sound/soc/codecs/adau1761.c b/sound/soc/codecs/adau1761.c index 5518ebd6947c..0ae1501f3c11 100644 --- a/sound/soc/codecs/adau1761.c +++ b/sound/soc/codecs/adau1761.c @@ -698,11 +698,6 @@ static int adau1761_codec_probe(struct snd_soc_codec *codec) ARRAY_SIZE(adau1761_dapm_routes)); if (ret) return ret; - - ret = adau17x1_load_firmware(adau, codec->dev, - ADAU1761_FIRMWARE); - if (ret) - dev_warn(codec->dev, "Failed to firmware\n"); } ret = adau17x1_add_routes(codec); @@ -771,16 +766,20 @@ int adau1761_probe(struct device *dev, struct regmap *regmap, enum adau17x1_type type, void (*switch_mode)(struct device *dev)) { struct snd_soc_dai_driver *dai_drv; + const char *firmware_name; int ret; - ret = adau17x1_probe(dev, regmap, type, switch_mode); - if (ret) - return ret; - - if (type == ADAU1361) + if (type == ADAU1361) { dai_drv = &adau1361_dai_driver; - else + firmware_name = NULL; + } else { dai_drv = &adau1761_dai_driver; + firmware_name = ADAU1761_FIRMWARE; + } + + ret = adau17x1_probe(dev, regmap, type, switch_mode, firmware_name); + if (ret) + return ret; return snd_soc_register_codec(dev, &adau1761_codec_driver, dai_drv, 1); } diff --git a/sound/soc/codecs/adau1781.c b/sound/soc/codecs/adau1781.c index e9fc00fb13dd..4c8ddc3c69e1 100644 --- a/sound/soc/codecs/adau1781.c +++ b/sound/soc/codecs/adau1781.c @@ -385,7 +385,6 @@ static int adau1781_codec_probe(struct snd_soc_codec *codec) { struct adau1781_platform_data *pdata = dev_get_platdata(codec->dev); struct adau *adau = snd_soc_codec_get_drvdata(codec); - const char *firmware; int ret; ret = adau17x1_add_widgets(codec); @@ -422,25 +421,10 @@ static int adau1781_codec_probe(struct snd_soc_codec *codec) return ret; } - switch (adau->type) { - case ADAU1381: - firmware = ADAU1381_FIRMWARE; - break; - case ADAU1781: - firmware = ADAU1781_FIRMWARE; - break; - default: - return -EINVAL; - } - ret = adau17x1_add_routes(codec); if (ret < 0) return ret; - ret = adau17x1_load_firmware(adau, codec->dev, firmware); - if (ret) - dev_warn(codec->dev, "Failed to load firmware\n"); - return 0; } @@ -495,9 +479,21 @@ EXPORT_SYMBOL_GPL(adau1781_regmap_config); int adau1781_probe(struct device *dev, struct regmap *regmap, enum adau17x1_type type, void (*switch_mode)(struct device *dev)) { + const char *firmware_name; int ret; - ret = adau17x1_probe(dev, regmap, type, switch_mode); + switch (type) { + case ADAU1381: + firmware_name = ADAU1381_FIRMWARE; + break; + case ADAU1781: + firmware_name = ADAU1781_FIRMWARE; + break; + default: + return -EINVAL; + } + + ret = adau17x1_probe(dev, regmap, type, switch_mode, firmware_name); if (ret) return ret; diff --git a/sound/soc/codecs/adau17x1.c b/sound/soc/codecs/adau17x1.c index 3e16c1c64115..1cab34c57413 100644 --- a/sound/soc/codecs/adau17x1.c +++ b/sound/soc/codecs/adau17x1.c @@ -307,6 +307,7 @@ static int adau17x1_hw_params(struct snd_pcm_substream *substream, struct adau *adau = snd_soc_codec_get_drvdata(codec); unsigned int val, div, dsp_div; unsigned int freq; + int ret; if (adau->clk_src == ADAU17X1_CLK_SRC_PLL) freq = adau->pll_freq; @@ -356,6 +357,12 @@ static int adau17x1_hw_params(struct snd_pcm_substream *substream, regmap_write(adau->regmap, ADAU17X1_DSP_SAMPLING_RATE, dsp_div); } + if (adau->sigmadsp) { + ret = adau17x1_setup_firmware(adau, params_rate(params)); + if (ret < 0) + return ret; + } + if (adau->dai_fmt != SND_SOC_DAIFMT_RIGHT_J) return 0; @@ -661,12 +668,24 @@ static int adau17x1_set_dai_tdm_slot(struct snd_soc_dai *dai, return 0; } +static int adau17x1_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct adau *adau = snd_soc_codec_get_drvdata(dai->codec); + + if (adau->sigmadsp) + return sigmadsp_restrict_params(adau->sigmadsp, substream); + + return 0; +} + const struct snd_soc_dai_ops adau17x1_dai_ops = { .hw_params = adau17x1_hw_params, .set_sysclk = adau17x1_set_dai_sysclk, .set_fmt = adau17x1_set_dai_fmt, .set_pll = adau17x1_set_dai_pll, .set_tdm_slot = adau17x1_set_dai_tdm_slot, + .startup = adau17x1_startup, }; EXPORT_SYMBOL_GPL(adau17x1_dai_ops); @@ -745,8 +764,7 @@ bool adau17x1_volatile_register(struct device *dev, unsigned int reg) } EXPORT_SYMBOL_GPL(adau17x1_volatile_register); -int adau17x1_load_firmware(struct adau *adau, struct device *dev, - const char *firmware) +int adau17x1_setup_firmware(struct adau *adau, unsigned int rate) { int ret; int dspsr; @@ -758,7 +776,7 @@ int adau17x1_load_firmware(struct adau *adau, struct device *dev, regmap_write(adau->regmap, ADAU17X1_DSP_ENABLE, 1); regmap_write(adau->regmap, ADAU17X1_DSP_SAMPLING_RATE, 0xf); - ret = process_sigma_firmware_regmap(dev, adau->regmap, firmware); + ret = sigmadsp_setup(adau->sigmadsp, rate); if (ret) { regmap_write(adau->regmap, ADAU17X1_DSP_ENABLE, 0); return ret; @@ -767,7 +785,7 @@ int adau17x1_load_firmware(struct adau *adau, struct device *dev, return 0; } -EXPORT_SYMBOL_GPL(adau17x1_load_firmware); +EXPORT_SYMBOL_GPL(adau17x1_setup_firmware); int adau17x1_add_widgets(struct snd_soc_codec *codec) { @@ -787,8 +805,21 @@ int adau17x1_add_widgets(struct snd_soc_codec *codec) ret = snd_soc_dapm_new_controls(&codec->dapm, adau17x1_dsp_dapm_widgets, ARRAY_SIZE(adau17x1_dsp_dapm_widgets)); + if (ret) + return ret; + + if (!adau->sigmadsp) + return 0; + + ret = sigmadsp_attach(adau->sigmadsp, &codec->component); + if (ret) { + dev_err(codec->dev, "Failed to attach firmware: %d\n", + ret); + return ret; + } } - return ret; + + return 0; } EXPORT_SYMBOL_GPL(adau17x1_add_widgets); @@ -829,7 +860,8 @@ int adau17x1_resume(struct snd_soc_codec *codec) EXPORT_SYMBOL_GPL(adau17x1_resume); int adau17x1_probe(struct device *dev, struct regmap *regmap, - enum adau17x1_type type, void (*switch_mode)(struct device *dev)) + enum adau17x1_type type, void (*switch_mode)(struct device *dev), + const char *firmware_name) { struct adau *adau; @@ -846,6 +878,16 @@ int adau17x1_probe(struct device *dev, struct regmap *regmap, dev_set_drvdata(dev, adau); + if (firmware_name) { + adau->sigmadsp = devm_sigmadsp_init_regmap(dev, regmap, NULL, + firmware_name); + if (IS_ERR(adau->sigmadsp)) { + dev_warn(dev, "Could not find firmware file: %ld\n", + PTR_ERR(adau->sigmadsp)); + adau->sigmadsp = NULL; + } + } + if (switch_mode) switch_mode(dev); diff --git a/sound/soc/codecs/adau17x1.h b/sound/soc/codecs/adau17x1.h index e4a557fd7155..6861aa3aec02 100644 --- a/sound/soc/codecs/adau17x1.h +++ b/sound/soc/codecs/adau17x1.h @@ -4,6 +4,8 @@ #include #include +#include "sigmadsp.h" + enum adau17x1_type { ADAU1361, ADAU1761, @@ -42,12 +44,14 @@ struct adau { bool dsp_bypass[2]; struct regmap *regmap; + struct sigmadsp *sigmadsp; }; int adau17x1_add_widgets(struct snd_soc_codec *codec); int adau17x1_add_routes(struct snd_soc_codec *codec); int adau17x1_probe(struct device *dev, struct regmap *regmap, - enum adau17x1_type type, void (*switch_mode)(struct device *dev)); + enum adau17x1_type type, void (*switch_mode)(struct device *dev), + const char *firmware_name); int adau17x1_set_micbias_voltage(struct snd_soc_codec *codec, enum adau17x1_micbias_voltage micbias); bool adau17x1_readable_register(struct device *dev, unsigned int reg); @@ -56,8 +60,7 @@ int adau17x1_resume(struct snd_soc_codec *codec); extern const struct snd_soc_dai_ops adau17x1_dai_ops; -int adau17x1_load_firmware(struct adau *adau, struct device *dev, - const char *firmware); +int adau17x1_setup_firmware(struct adau *adau, unsigned int rate); bool adau17x1_has_dsp(struct adau *adau); #define ADAU17X1_CLOCK_CONTROL 0x4000 diff --git a/sound/soc/codecs/sigmadsp-i2c.c b/sound/soc/codecs/sigmadsp-i2c.c index 246081aae8ca..bf6a2be72692 100644 --- a/sound/soc/codecs/sigmadsp-i2c.c +++ b/sound/soc/codecs/sigmadsp-i2c.c @@ -6,29 +6,59 @@ * Licensed under the GPL-2 or later. */ -#include #include +#include #include +#include +#include #include "sigmadsp.h" -static int sigma_action_write_i2c(void *control_data, - const struct sigma_action *sa, size_t len) +static int sigmadsp_write_i2c(void *control_data, + unsigned int addr, const uint8_t data[], size_t len) { - return i2c_master_send(control_data, (const unsigned char *)&sa->addr, - len); + uint8_t *buf; + int ret; + + buf = kzalloc(2 + len, GFP_KERNEL | GFP_DMA); + if (!buf) + return -ENOMEM; + + put_unaligned_be16(addr, buf); + memcpy(buf + 2, data, len); + + ret = i2c_master_send(control_data, buf, len + 2); + + kfree(buf); + + return ret; } -int process_sigma_firmware(struct i2c_client *client, const char *name) +/** + * devm_sigmadsp_init_i2c() - Initialize SigmaDSP instance + * @client: The parent I2C device + * @ops: The sigmadsp_ops to use for this instance + * @firmware_name: Name of the firmware file to load + * + * Allocates a SigmaDSP instance and loads the specified firmware file. + * + * Returns a pointer to a struct sigmadsp on success, or a PTR_ERR() on error. + */ +struct sigmadsp *devm_sigmadsp_init_i2c(struct i2c_client *client, + const struct sigmadsp_ops *ops, const char *firmware_name) { - struct sigma_firmware ssfw; + struct sigmadsp *sigmadsp; + + sigmadsp = devm_sigmadsp_init(&client->dev, ops, firmware_name); + if (IS_ERR(sigmadsp)) + return sigmadsp; - ssfw.control_data = client; - ssfw.write = sigma_action_write_i2c; + sigmadsp->control_data = client; + sigmadsp->write = sigmadsp_write_i2c; - return _process_sigma_firmware(&client->dev, &ssfw, name); + return sigmadsp; } -EXPORT_SYMBOL(process_sigma_firmware); +EXPORT_SYMBOL_GPL(devm_sigmadsp_init_i2c); MODULE_AUTHOR("Lars-Peter Clausen "); MODULE_DESCRIPTION("SigmaDSP I2C firmware loader"); diff --git a/sound/soc/codecs/sigmadsp-regmap.c b/sound/soc/codecs/sigmadsp-regmap.c index f78ed8d2cfb2..cdc5dda47b88 100644 --- a/sound/soc/codecs/sigmadsp-regmap.c +++ b/sound/soc/codecs/sigmadsp-regmap.c @@ -12,24 +12,40 @@ #include "sigmadsp.h" -static int sigma_action_write_regmap(void *control_data, - const struct sigma_action *sa, size_t len) +static int sigmadsp_write_regmap(void *control_data, + unsigned int addr, const uint8_t data[], size_t len) { - return regmap_raw_write(control_data, be16_to_cpu(sa->addr), - sa->payload, len - 2); + return regmap_raw_write(control_data, addr, + data, len); } -int process_sigma_firmware_regmap(struct device *dev, struct regmap *regmap, - const char *name) +/** + * devm_sigmadsp_init_i2c() - Initialize SigmaDSP instance + * @dev: The parent device + * @regmap: Regmap instance to use + * @ops: The sigmadsp_ops to use for this instance + * @firmware_name: Name of the firmware file to load + * + * Allocates a SigmaDSP instance and loads the specified firmware file. + * + * Returns a pointer to a struct sigmadsp on success, or a PTR_ERR() on error. + */ +struct sigmadsp *devm_sigmadsp_init_regmap(struct device *dev, + struct regmap *regmap, const struct sigmadsp_ops *ops, + const char *firmware_name) { - struct sigma_firmware ssfw; + struct sigmadsp *sigmadsp; + + sigmadsp = devm_sigmadsp_init(dev, ops, firmware_name); + if (IS_ERR(sigmadsp)) + return sigmadsp; - ssfw.control_data = regmap; - ssfw.write = sigma_action_write_regmap; + sigmadsp->control_data = regmap; + sigmadsp->write = sigmadsp_write_regmap; - return _process_sigma_firmware(dev, &ssfw, name); + return sigmadsp; } -EXPORT_SYMBOL(process_sigma_firmware_regmap); +EXPORT_SYMBOL_GPL(devm_sigmadsp_init_regmap); MODULE_AUTHOR("Lars-Peter Clausen "); MODULE_DESCRIPTION("SigmaDSP regmap firmware loader"); diff --git a/sound/soc/codecs/sigmadsp.c b/sound/soc/codecs/sigmadsp.c index 4fd31434276b..34e63b554c31 100644 --- a/sound/soc/codecs/sigmadsp.c +++ b/sound/soc/codecs/sigmadsp.c @@ -1,7 +1,7 @@ /* * Load Analog Devices SigmaStudio firmware files * - * Copyright 2009-2011 Analog Devices Inc. + * Copyright 2009-2014 Analog Devices Inc. * * Licensed under the GPL-2 or later. */ @@ -12,11 +12,21 @@ #include #include #include +#include + +#include #include "sigmadsp.h" #define SIGMA_MAGIC "ADISIGM" +struct sigmadsp_data { + struct list_head head; + unsigned int addr; + unsigned int length; + uint8_t data[]; +}; + struct sigma_firmware_header { unsigned char magic[7]; u8 version; @@ -30,6 +40,20 @@ enum { SIGMA_ACTION_END, }; +struct sigma_action { + u8 instr; + u8 len_hi; + __le16 len; + __be16 addr; + unsigned char payload[]; +} __packed; + +static int sigmadsp_write(struct sigmadsp *sigmadsp, unsigned int addr, + const uint8_t data[], size_t len) +{ + return sigmadsp->write(sigmadsp->control_data, addr, data, len); +} + static inline u32 sigma_action_len(struct sigma_action *sa) { return (sa->len_hi << 16) | le16_to_cpu(sa->len); @@ -58,11 +82,11 @@ static size_t sigma_action_size(struct sigma_action *sa) * Returns a negative error value in case of an error, 0 if processing of * the firmware should be stopped after this action, 1 otherwise. */ -static int -process_sigma_action(struct sigma_firmware *ssfw, struct sigma_action *sa) +static int process_sigma_action(struct sigmadsp *sigmadsp, + struct sigma_action *sa) { size_t len = sigma_action_len(sa); - int ret; + struct sigmadsp_data *data; pr_debug("%s: instr:%i addr:%#x len:%zu\n", __func__, sa->instr, sa->addr, len); @@ -71,9 +95,17 @@ process_sigma_action(struct sigma_firmware *ssfw, struct sigma_action *sa) case SIGMA_ACTION_WRITEXBYTES: case SIGMA_ACTION_WRITESINGLE: case SIGMA_ACTION_WRITESAFELOAD: - ret = ssfw->write(ssfw->control_data, sa, len); - if (ret < 0) + if (len < 3) return -EINVAL; + + data = kzalloc(sizeof(*data) + len - 2, GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->addr = be16_to_cpu(sa->addr); + data->length = len - 2; + memcpy(data->data, sa->payload, data->length); + list_add_tail(&data->head, &sigmadsp->data_list); break; case SIGMA_ACTION_END: return 0; @@ -84,22 +116,24 @@ process_sigma_action(struct sigma_firmware *ssfw, struct sigma_action *sa) return 1; } -static int -process_sigma_actions(struct sigma_firmware *ssfw) +static int sigmadsp_fw_load_v1(struct sigmadsp *sigmadsp, + const struct firmware *fw) { struct sigma_action *sa; - size_t size; + size_t size, pos; int ret; - while (ssfw->pos + sizeof(*sa) <= ssfw->fw->size) { - sa = (struct sigma_action *)(ssfw->fw->data + ssfw->pos); + pos = sizeof(struct sigma_firmware_header); + + while (pos + sizeof(*sa) <= fw->size) { + sa = (struct sigma_action *)(fw->data + pos); size = sigma_action_size(sa); - ssfw->pos += size; - if (ssfw->pos > ssfw->fw->size || size == 0) + pos += size; + if (pos > fw->size || size == 0) break; - ret = process_sigma_action(ssfw, sa); + ret = process_sigma_action(sigmadsp, sa); pr_debug("%s: action returned %i\n", __func__, ret); @@ -107,29 +141,40 @@ process_sigma_actions(struct sigma_firmware *ssfw) return ret; } - if (ssfw->pos != ssfw->fw->size) + if (pos != fw->size) return -EINVAL; return 0; } -int _process_sigma_firmware(struct device *dev, - struct sigma_firmware *ssfw, const char *name) +static void sigmadsp_firmware_release(struct sigmadsp *sigmadsp) { - int ret; - struct sigma_firmware_header *ssfw_head; + struct sigmadsp_data *data, *_data; + + list_for_each_entry_safe(data, _data, &sigmadsp->data_list, head) + kfree(data); + + INIT_LIST_HEAD(&sigmadsp->data_list); +} + +static void devm_sigmadsp_release(struct device *dev, void *res) +{ + sigmadsp_firmware_release((struct sigmadsp *)res); +} + +static int sigmadsp_firmware_load(struct sigmadsp *sigmadsp, const char *name) +{ + const struct sigma_firmware_header *ssfw_head; const struct firmware *fw; + int ret; u32 crc; - pr_debug("%s: loading firmware %s\n", __func__, name); - /* first load the blob */ - ret = request_firmware(&fw, name, dev); + ret = request_firmware(&fw, name, sigmadsp->dev); if (ret) { pr_debug("%s: request_firmware() failed with %i\n", __func__, ret); - return ret; + goto done; } - ssfw->fw = fw; /* then verify the header */ ret = -EINVAL; @@ -141,20 +186,13 @@ int _process_sigma_firmware(struct device *dev, * overflows later in the loading process. */ if (fw->size < sizeof(*ssfw_head) || fw->size >= 0x4000000) { - dev_err(dev, "Failed to load firmware: Invalid size\n"); + dev_err(sigmadsp->dev, "Failed to load firmware: Invalid size\n"); goto done; } ssfw_head = (void *)fw->data; if (memcmp(ssfw_head->magic, SIGMA_MAGIC, ARRAY_SIZE(ssfw_head->magic))) { - dev_err(dev, "Failed to load firmware: Invalid magic\n"); - goto done; - } - - if (ssfw_head->version != 1) { - dev_err(dev, - "Failed to load firmware: Invalid version %d. Supported firmware versions: 1\n", - ssfw_head->version); + dev_err(sigmadsp->dev, "Failed to load firmware: Invalid magic\n"); goto done; } @@ -162,23 +200,160 @@ int _process_sigma_firmware(struct device *dev, fw->size - sizeof(*ssfw_head)); pr_debug("%s: crc=%x\n", __func__, crc); if (crc != le32_to_cpu(ssfw_head->crc)) { - dev_err(dev, "Failed to load firmware: Wrong crc checksum: expected %x got %x\n", + dev_err(sigmadsp->dev, "Failed to load firmware: Wrong crc checksum: expected %x got %x\n", le32_to_cpu(ssfw_head->crc), crc); goto done; } - ssfw->pos = sizeof(*ssfw_head); + switch (ssfw_head->version) { + case 1: + ret = sigmadsp_fw_load_v1(sigmadsp, fw); + break; + default: + dev_err(sigmadsp->dev, + "Failed to load firmware: Invalid version %d. Supported firmware versions: 1\n", + ssfw_head->version); + ret = -EINVAL; + break; + } - /* finally process all of the actions */ - ret = process_sigma_actions(ssfw); + if (ret) + sigmadsp_firmware_release(sigmadsp); - done: +done: release_firmware(fw); - pr_debug("%s: loaded %s\n", __func__, name); + return ret; +} + +static int sigmadsp_init(struct sigmadsp *sigmadsp, struct device *dev, + const struct sigmadsp_ops *ops, const char *firmware_name) +{ + sigmadsp->ops = ops; + sigmadsp->dev = dev; + + INIT_LIST_HEAD(&sigmadsp->data_list); + + return sigmadsp_firmware_load(sigmadsp, firmware_name); +} + +/** + * devm_sigmadsp_init() - Initialize SigmaDSP instance + * @dev: The parent device + * @ops: The sigmadsp_ops to use for this instance + * @firmware_name: Name of the firmware file to load + * + * Allocates a SigmaDSP instance and loads the specified firmware file. + * + * Returns a pointer to a struct sigmadsp on success, or a PTR_ERR() on error. + */ +struct sigmadsp *devm_sigmadsp_init(struct device *dev, + const struct sigmadsp_ops *ops, const char *firmware_name) +{ + struct sigmadsp *sigmadsp; + int ret; + + sigmadsp = devres_alloc(devm_sigmadsp_release, sizeof(*sigmadsp), + GFP_KERNEL); + if (!sigmadsp) + return ERR_PTR(-ENOMEM); + + ret = sigmadsp_init(sigmadsp, dev, ops, firmware_name); + if (ret) { + devres_free(sigmadsp); + return ERR_PTR(ret); + } + + devres_add(dev, sigmadsp); + + return sigmadsp; +} +EXPORT_SYMBOL_GPL(devm_sigmadsp_init); + +/** + * sigmadsp_attach() - Attach a sigmadsp instance to a ASoC component + * @sigmadsp: The sigmadsp instance to attach + * @component: The component to attach to + * + * Typically called in the components probe callback. + * + * Note, once this function has been called the firmware must not be released + * until after the ALSA snd_card that the component belongs to has been + * disconnected, even if sigmadsp_attach() returns an error. + */ +int sigmadsp_attach(struct sigmadsp *sigmadsp, + struct snd_soc_component *component) +{ + sigmadsp->component = component; + + return 0; +} +EXPORT_SYMBOL_GPL(sigmadsp_attach); + +/** + * sigmadsp_setup() - Setup the DSP for the specified samplerate + * @sigmadsp: The sigmadsp instance to configure + * @samplerate: The samplerate the DSP should be configured for + * + * Loads the appropriate firmware program and parameter memory (if not already + * loaded) and enables the controls for the specified samplerate. Any control + * parameter changes that have been made previously will be restored. + * + * Returns 0 on success, a negative error code otherwise. + */ +int sigmadsp_setup(struct sigmadsp *sigmadsp, unsigned int samplerate) +{ + struct sigmadsp_data *data; + int ret; + + if (sigmadsp->current_samplerate == samplerate) + return 0; + + list_for_each_entry(data, &sigmadsp->data_list, head) { + ret = sigmadsp_write(sigmadsp, data->addr, data->data, + data->length); + if (ret) + goto err; + } + + sigmadsp->current_samplerate = samplerate; + + return 0; +err: + sigmadsp_reset(sigmadsp); return ret; } -EXPORT_SYMBOL_GPL(_process_sigma_firmware); +EXPORT_SYMBOL_GPL(sigmadsp_setup); + +/** + * sigmadsp_reset() - Notify the sigmadsp instance that the DSP has been reset + * @sigmadsp: The sigmadsp instance to reset + * + * Should be called whenever the DSP has been reset and parameter and program + * memory need to be re-loaded. + */ +void sigmadsp_reset(struct sigmadsp *sigmadsp) +{ + sigmadsp->current_samplerate = 0; +} +EXPORT_SYMBOL_GPL(sigmadsp_reset); + +/** + * sigmadsp_restrict_params() - Applies DSP firmware specific constraints + * @sigmadsp: The sigmadsp instance + * @substream: The substream to restrict + * + * Applies samplerate constraints that may be required by the firmware Should + * typically be called from the CODEC/component drivers startup callback. + * + * Returns 0 on success, a negative error code otherwise. + */ +int sigmadsp_restrict_params(struct sigmadsp *sigmadsp, + struct snd_pcm_substream *substream) +{ + return 0; +} +EXPORT_SYMBOL_GPL(sigmadsp_restrict_params); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/sigmadsp.h b/sound/soc/codecs/sigmadsp.h index c47cd23e9827..a6be91a4c2dc 100644 --- a/sound/soc/codecs/sigmadsp.h +++ b/sound/soc/codecs/sigmadsp.h @@ -11,31 +11,50 @@ #include #include +#include -struct sigma_action { - u8 instr; - u8 len_hi; - __le16 len; - __be16 addr; - unsigned char payload[]; -} __packed; +#include -struct sigma_firmware { - const struct firmware *fw; - size_t pos; +struct sigmadsp; +struct snd_soc_component; +struct snd_pcm_substream; + +struct sigmadsp_ops { + int (*safeload)(struct sigmadsp *sigmadsp, unsigned int addr, + const uint8_t *data, size_t len); +}; + +struct sigmadsp { + const struct sigmadsp_ops *ops; + + struct list_head data_list; + + unsigned int current_samplerate; + struct snd_soc_component *component; + struct device *dev; void *control_data; - int (*write)(void *control_data, const struct sigma_action *sa, - size_t len); + int (*write)(void *, unsigned int, const uint8_t *, size_t); }; -int _process_sigma_firmware(struct device *dev, - struct sigma_firmware *ssfw, const char *name); +struct sigmadsp *devm_sigmadsp_init(struct device *dev, + const struct sigmadsp_ops *ops, const char *firmware_name); +void sigmadsp_reset(struct sigmadsp *sigmadsp); + +int sigmadsp_restrict_params(struct sigmadsp *sigmadsp, + struct snd_pcm_substream *substream); struct i2c_client; -extern int process_sigma_firmware(struct i2c_client *client, const char *name); -extern int process_sigma_firmware_regmap(struct device *dev, - struct regmap *regmap, const char *name); +struct sigmadsp *devm_sigmadsp_init_regmap(struct device *dev, + struct regmap *regmap, const struct sigmadsp_ops *ops, + const char *firmware_name); +struct sigmadsp *devm_sigmadsp_init_i2c(struct i2c_client *client, + const struct sigmadsp_ops *ops, const char *firmware_name); + +int sigmadsp_attach(struct sigmadsp *sigmadsp, + struct snd_soc_component *component); +int sigmadsp_setup(struct sigmadsp *sigmadsp, unsigned int rate); +void sigmadsp_reset(struct sigmadsp *sigmadsp); #endif -- cgit v1.2.3 From a35daac77a0397d4f23b642d3dc0684682e56cc5 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 19 Nov 2014 18:29:06 +0100 Subject: ASoC: sigmadsp: Add support for fw v2 This patch adds support for the v2 version of the SigmaDSP firmware file format. The new format has support for having different program and parameter settings for different samplerates. In addition it stores metadata describing the firmware. This metadata includes the set of supported samplerates which will be used to restrict the samplerates that can be selected by userspace. Also included is information about the modifiable parameters. Those will be exposed as ALSA controls so they can be changed at runtime. The new format is based on a binary type-length-value structure that makes it both forward and backwards compatible. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/sigmadsp-i2c.c | 29 +++ sound/soc/codecs/sigmadsp-regmap.c | 8 + sound/soc/codecs/sigmadsp.c | 463 ++++++++++++++++++++++++++++++++++++- sound/soc/codecs/sigmadsp.h | 6 + 4 files changed, 504 insertions(+), 2 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/sigmadsp-i2c.c b/sound/soc/codecs/sigmadsp-i2c.c index bf6a2be72692..21ca3a5e9f66 100644 --- a/sound/soc/codecs/sigmadsp-i2c.c +++ b/sound/soc/codecs/sigmadsp-i2c.c @@ -34,6 +34,34 @@ static int sigmadsp_write_i2c(void *control_data, return ret; } +static int sigmadsp_read_i2c(void *control_data, + unsigned int addr, uint8_t data[], size_t len) +{ + struct i2c_client *client = control_data; + struct i2c_msg msgs[2]; + uint8_t buf[2]; + int ret; + + put_unaligned_be16(addr, buf); + + msgs[0].addr = client->addr; + msgs[0].len = sizeof(buf); + msgs[0].buf = buf; + msgs[0].flags = 0; + + msgs[1].addr = client->addr; + msgs[1].len = len; + msgs[1].buf = data; + msgs[1].flags = I2C_M_RD; + + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret < 0) + return ret; + else if (ret != ARRAY_SIZE(msgs)) + return -EIO; + return 0; +} + /** * devm_sigmadsp_init_i2c() - Initialize SigmaDSP instance * @client: The parent I2C device @@ -55,6 +83,7 @@ struct sigmadsp *devm_sigmadsp_init_i2c(struct i2c_client *client, sigmadsp->control_data = client; sigmadsp->write = sigmadsp_write_i2c; + sigmadsp->read = sigmadsp_read_i2c; return sigmadsp; } diff --git a/sound/soc/codecs/sigmadsp-regmap.c b/sound/soc/codecs/sigmadsp-regmap.c index cdc5dda47b88..912861be5b87 100644 --- a/sound/soc/codecs/sigmadsp-regmap.c +++ b/sound/soc/codecs/sigmadsp-regmap.c @@ -19,6 +19,13 @@ static int sigmadsp_write_regmap(void *control_data, data, len); } +static int sigmadsp_read_regmap(void *control_data, + unsigned int addr, uint8_t data[], size_t len) +{ + return regmap_raw_read(control_data, addr, + data, len); +} + /** * devm_sigmadsp_init_i2c() - Initialize SigmaDSP instance * @dev: The parent device @@ -42,6 +49,7 @@ struct sigmadsp *devm_sigmadsp_init_regmap(struct device *dev, sigmadsp->control_data = regmap; sigmadsp->write = sigmadsp_write_regmap; + sigmadsp->read = sigmadsp_read_regmap; return sigmadsp; } diff --git a/sound/soc/codecs/sigmadsp.c b/sound/soc/codecs/sigmadsp.c index 34e63b554c31..55af596935d4 100644 --- a/sound/soc/codecs/sigmadsp.c +++ b/sound/soc/codecs/sigmadsp.c @@ -14,19 +14,61 @@ #include #include +#include #include #include "sigmadsp.h" #define SIGMA_MAGIC "ADISIGM" +#define SIGMA_FW_CHUNK_TYPE_DATA 0 +#define SIGMA_FW_CHUNK_TYPE_CONTROL 1 +#define SIGMA_FW_CHUNK_TYPE_SAMPLERATES 2 + +struct sigmadsp_control { + struct list_head head; + uint32_t samplerates; + unsigned int addr; + unsigned int num_bytes; + const char *name; + struct snd_kcontrol *kcontrol; + bool cached; + uint8_t cache[]; +}; + struct sigmadsp_data { struct list_head head; + uint32_t samplerates; unsigned int addr; unsigned int length; uint8_t data[]; }; +struct sigma_fw_chunk { + __le32 length; + __le32 tag; + __le32 samplerates; +} __packed; + +struct sigma_fw_chunk_data { + struct sigma_fw_chunk chunk; + __le16 addr; + uint8_t data[]; +} __packed; + +struct sigma_fw_chunk_control { + struct sigma_fw_chunk chunk; + __le16 type; + __le16 addr; + __le16 num_bytes; + const char name[]; +} __packed; + +struct sigma_fw_chunk_samplerate { + struct sigma_fw_chunk chunk; + __le32 samplerates[]; +} __packed; + struct sigma_firmware_header { unsigned char magic[7]; u8 version; @@ -54,6 +96,269 @@ static int sigmadsp_write(struct sigmadsp *sigmadsp, unsigned int addr, return sigmadsp->write(sigmadsp->control_data, addr, data, len); } +static int sigmadsp_read(struct sigmadsp *sigmadsp, unsigned int addr, + uint8_t data[], size_t len) +{ + return sigmadsp->read(sigmadsp->control_data, addr, data, len); +} + +static int sigmadsp_ctrl_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *info) +{ + struct sigmadsp_control *ctrl = (void *)kcontrol->private_value; + + info->type = SNDRV_CTL_ELEM_TYPE_BYTES; + info->count = ctrl->num_bytes; + + return 0; +} + +static int sigmadsp_ctrl_write(struct sigmadsp *sigmadsp, + struct sigmadsp_control *ctrl, void *data) +{ + /* safeload loads up to 20 bytes in a atomic operation */ + if (ctrl->num_bytes > 4 && ctrl->num_bytes <= 20 && sigmadsp->ops && + sigmadsp->ops->safeload) + return sigmadsp->ops->safeload(sigmadsp, ctrl->addr, data, + ctrl->num_bytes); + else + return sigmadsp_write(sigmadsp, ctrl->addr, data, + ctrl->num_bytes); +} + +static int sigmadsp_ctrl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct sigmadsp_control *ctrl = (void *)kcontrol->private_value; + struct sigmadsp *sigmadsp = snd_kcontrol_chip(kcontrol); + uint8_t *data; + int ret = 0; + + mutex_lock(&sigmadsp->lock); + + data = ucontrol->value.bytes.data; + + if (!(kcontrol->vd[0].access & SNDRV_CTL_ELEM_ACCESS_INACTIVE)) + ret = sigmadsp_ctrl_write(sigmadsp, ctrl, data); + + if (ret == 0) { + memcpy(ctrl->cache, data, ctrl->num_bytes); + ctrl->cached = true; + } + + mutex_unlock(&sigmadsp->lock); + + return ret; +} + +static int sigmadsp_ctrl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct sigmadsp_control *ctrl = (void *)kcontrol->private_value; + struct sigmadsp *sigmadsp = snd_kcontrol_chip(kcontrol); + int ret = 0; + + mutex_lock(&sigmadsp->lock); + + if (!ctrl->cached) { + ret = sigmadsp_read(sigmadsp, ctrl->addr, ctrl->cache, + ctrl->num_bytes); + } + + if (ret == 0) { + ctrl->cached = true; + memcpy(ucontrol->value.bytes.data, ctrl->cache, + ctrl->num_bytes); + } + + mutex_unlock(&sigmadsp->lock); + + return ret; +} + +static void sigmadsp_control_free(struct snd_kcontrol *kcontrol) +{ + struct sigmadsp_control *ctrl = (void *)kcontrol->private_value; + + ctrl->kcontrol = NULL; +} + +static bool sigma_fw_validate_control_name(const char *name, unsigned int len) +{ + unsigned int i; + + for (i = 0; i < len; i++) { + /* Normal ASCII characters are valid */ + if (name[i] < ' ' || name[i] > '~') + return false; + } + + return true; +} + +static int sigma_fw_load_control(struct sigmadsp *sigmadsp, + const struct sigma_fw_chunk *chunk, unsigned int length) +{ + const struct sigma_fw_chunk_control *ctrl_chunk; + struct sigmadsp_control *ctrl; + unsigned int num_bytes; + size_t name_len; + char *name; + int ret; + + if (length <= sizeof(*ctrl_chunk)) + return -EINVAL; + + ctrl_chunk = (const struct sigma_fw_chunk_control *)chunk; + + name_len = length - sizeof(*ctrl_chunk); + if (name_len >= SNDRV_CTL_ELEM_ID_NAME_MAXLEN) + name_len = SNDRV_CTL_ELEM_ID_NAME_MAXLEN - 1; + + /* Make sure there are no non-displayable characaters in the string */ + if (!sigma_fw_validate_control_name(ctrl_chunk->name, name_len)) + return -EINVAL; + + num_bytes = le16_to_cpu(ctrl_chunk->num_bytes); + ctrl = kzalloc(sizeof(*ctrl) + num_bytes, GFP_KERNEL); + if (!ctrl) + return -ENOMEM; + + name = kzalloc(name_len + 1, GFP_KERNEL); + if (!name) { + ret = -ENOMEM; + goto err_free_ctrl; + } + memcpy(name, ctrl_chunk->name, name_len); + name[name_len] = '\0'; + ctrl->name = name; + + ctrl->addr = le16_to_cpu(ctrl_chunk->addr); + ctrl->num_bytes = num_bytes; + ctrl->samplerates = chunk->samplerates; + + list_add_tail(&ctrl->head, &sigmadsp->ctrl_list); + + return 0; + +err_free_ctrl: + kfree(ctrl); + + return ret; +} + +static int sigma_fw_load_data(struct sigmadsp *sigmadsp, + const struct sigma_fw_chunk *chunk, unsigned int length) +{ + const struct sigma_fw_chunk_data *data_chunk; + struct sigmadsp_data *data; + + if (length <= sizeof(*data_chunk)) + return -EINVAL; + + data_chunk = (struct sigma_fw_chunk_data *)chunk; + + length -= sizeof(*data_chunk); + + data = kzalloc(sizeof(*data) + length, GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->addr = le16_to_cpu(data_chunk->addr); + data->length = length; + data->samplerates = chunk->samplerates; + memcpy(data->data, data_chunk->data, length); + list_add_tail(&data->head, &sigmadsp->data_list); + + return 0; +} + +static int sigma_fw_load_samplerates(struct sigmadsp *sigmadsp, + const struct sigma_fw_chunk *chunk, unsigned int length) +{ + const struct sigma_fw_chunk_samplerate *rate_chunk; + unsigned int num_rates; + unsigned int *rates; + unsigned int i; + + rate_chunk = (const struct sigma_fw_chunk_samplerate *)chunk; + + num_rates = (length - sizeof(*rate_chunk)) / sizeof(__le32); + + if (num_rates > 32 || num_rates == 0) + return -EINVAL; + + /* We only allow one samplerates block per file */ + if (sigmadsp->rate_constraints.count) + return -EINVAL; + + rates = kcalloc(num_rates, sizeof(*rates), GFP_KERNEL); + if (!rates) + return -ENOMEM; + + for (i = 0; i < num_rates; i++) + rates[i] = le32_to_cpu(rate_chunk->samplerates[i]); + + sigmadsp->rate_constraints.count = num_rates; + sigmadsp->rate_constraints.list = rates; + + return 0; +} + +static int sigmadsp_fw_load_v2(struct sigmadsp *sigmadsp, + const struct firmware *fw) +{ + struct sigma_fw_chunk *chunk; + unsigned int length, pos; + int ret; + + /* + * Make sure that there is at least one chunk to avoid integer + * underflows later on. Empty firmware is still valid though. + */ + if (fw->size < sizeof(*chunk) + sizeof(struct sigma_firmware_header)) + return 0; + + pos = sizeof(struct sigma_firmware_header); + + while (pos < fw->size - sizeof(*chunk)) { + chunk = (struct sigma_fw_chunk *)(fw->data + pos); + + length = le32_to_cpu(chunk->length); + + if (length > fw->size - pos || length < sizeof(*chunk)) + return -EINVAL; + + switch (chunk->tag) { + case SIGMA_FW_CHUNK_TYPE_DATA: + ret = sigma_fw_load_data(sigmadsp, chunk, length); + break; + case SIGMA_FW_CHUNK_TYPE_CONTROL: + ret = sigma_fw_load_control(sigmadsp, chunk, length); + break; + case SIGMA_FW_CHUNK_TYPE_SAMPLERATES: + ret = sigma_fw_load_samplerates(sigmadsp, chunk, length); + break; + default: + dev_warn(sigmadsp->dev, "Unknown chunk type: %d\n", + chunk->tag); + ret = 0; + break; + } + + if (ret) + return ret; + + /* + * This can not overflow since if length is larger than the + * maximum firmware size (0x4000000) we'll error out earilier. + */ + pos += ALIGN(length, sizeof(__le32)); + } + + return 0; +} + static inline u32 sigma_action_len(struct sigma_action *sa) { return (sa->len_hi << 16) | le16_to_cpu(sa->len); @@ -149,11 +454,18 @@ static int sigmadsp_fw_load_v1(struct sigmadsp *sigmadsp, static void sigmadsp_firmware_release(struct sigmadsp *sigmadsp) { + struct sigmadsp_control *ctrl, *_ctrl; struct sigmadsp_data *data, *_data; + list_for_each_entry_safe(ctrl, _ctrl, &sigmadsp->ctrl_list, head) { + kfree(ctrl->name); + kfree(ctrl); + } + list_for_each_entry_safe(data, _data, &sigmadsp->data_list, head) kfree(data); + INIT_LIST_HEAD(&sigmadsp->ctrl_list); INIT_LIST_HEAD(&sigmadsp->data_list); } @@ -209,9 +521,12 @@ static int sigmadsp_firmware_load(struct sigmadsp *sigmadsp, const char *name) case 1: ret = sigmadsp_fw_load_v1(sigmadsp, fw); break; + case 2: + ret = sigmadsp_fw_load_v2(sigmadsp, fw); + break; default: dev_err(sigmadsp->dev, - "Failed to load firmware: Invalid version %d. Supported firmware versions: 1\n", + "Failed to load firmware: Invalid version %d. Supported firmware versions: 1, 2\n", ssfw_head->version); ret = -EINVAL; break; @@ -232,7 +547,9 @@ static int sigmadsp_init(struct sigmadsp *sigmadsp, struct device *dev, sigmadsp->ops = ops; sigmadsp->dev = dev; + INIT_LIST_HEAD(&sigmadsp->ctrl_list); INIT_LIST_HEAD(&sigmadsp->data_list); + mutex_init(&sigmadsp->lock); return sigmadsp_firmware_load(sigmadsp, firmware_name); } @@ -270,6 +587,114 @@ struct sigmadsp *devm_sigmadsp_init(struct device *dev, } EXPORT_SYMBOL_GPL(devm_sigmadsp_init); +static int sigmadsp_rate_to_index(struct sigmadsp *sigmadsp, unsigned int rate) +{ + unsigned int i; + + for (i = 0; i < sigmadsp->rate_constraints.count; i++) { + if (sigmadsp->rate_constraints.list[i] == rate) + return i; + } + + return -EINVAL; +} + +static unsigned int sigmadsp_get_samplerate_mask(struct sigmadsp *sigmadsp, + unsigned int samplerate) +{ + int samplerate_index; + + if (samplerate == 0) + return 0; + + if (sigmadsp->rate_constraints.count) { + samplerate_index = sigmadsp_rate_to_index(sigmadsp, samplerate); + if (samplerate_index < 0) + return 0; + + return BIT(samplerate_index); + } else { + return ~0; + } +} + +static bool sigmadsp_samplerate_valid(unsigned int supported, + unsigned int requested) +{ + /* All samplerates are supported */ + if (!supported) + return true; + + return supported & requested; +} + +static int sigmadsp_alloc_control(struct sigmadsp *sigmadsp, + struct sigmadsp_control *ctrl, unsigned int samplerate_mask) +{ + struct snd_kcontrol_new template; + struct snd_kcontrol *kcontrol; + int ret; + + memset(&template, 0, sizeof(template)); + template.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + template.name = ctrl->name; + template.info = sigmadsp_ctrl_info; + template.get = sigmadsp_ctrl_get; + template.put = sigmadsp_ctrl_put; + template.private_value = (unsigned long)ctrl; + template.access = SNDRV_CTL_ELEM_ACCESS_READWRITE; + if (!sigmadsp_samplerate_valid(ctrl->samplerates, samplerate_mask)) + template.access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; + + kcontrol = snd_ctl_new1(&template, sigmadsp); + if (!kcontrol) + return -ENOMEM; + + kcontrol->private_free = sigmadsp_control_free; + ctrl->kcontrol = kcontrol; + + ret = snd_ctl_add(sigmadsp->component->card->snd_card, kcontrol); + if (ret) + return ret; + + return 0; +} + +static void sigmadsp_activate_ctrl(struct sigmadsp *sigmadsp, + struct sigmadsp_control *ctrl, unsigned int samplerate_mask) +{ + struct snd_card *card = sigmadsp->component->card->snd_card; + struct snd_kcontrol_volatile *vd; + struct snd_ctl_elem_id id; + bool active, changed; + + active = sigmadsp_samplerate_valid(ctrl->samplerates, samplerate_mask); + + down_write(&card->controls_rwsem); + if (!ctrl->kcontrol) { + up_write(&card->controls_rwsem); + return; + } + + id = ctrl->kcontrol->id; + vd = &ctrl->kcontrol->vd[0]; + if (active == (bool)(vd->access & SNDRV_CTL_ELEM_ACCESS_INACTIVE)) { + vd->access ^= SNDRV_CTL_ELEM_ACCESS_INACTIVE; + changed = true; + } + up_write(&card->controls_rwsem); + + if (active && changed) { + mutex_lock(&sigmadsp->lock); + if (ctrl->cached) + sigmadsp_ctrl_write(sigmadsp, ctrl, ctrl->cache); + mutex_unlock(&sigmadsp->lock); + } + + if (changed) + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, &id); +} + /** * sigmadsp_attach() - Attach a sigmadsp instance to a ASoC component * @sigmadsp: The sigmadsp instance to attach @@ -284,8 +709,21 @@ EXPORT_SYMBOL_GPL(devm_sigmadsp_init); int sigmadsp_attach(struct sigmadsp *sigmadsp, struct snd_soc_component *component) { + struct sigmadsp_control *ctrl; + unsigned int samplerate_mask; + int ret; + sigmadsp->component = component; + samplerate_mask = sigmadsp_get_samplerate_mask(sigmadsp, + sigmadsp->current_samplerate); + + list_for_each_entry(ctrl, &sigmadsp->ctrl_list, head) { + ret = sigmadsp_alloc_control(sigmadsp, ctrl, samplerate_mask); + if (ret) + return ret; + } + return 0; } EXPORT_SYMBOL_GPL(sigmadsp_attach); @@ -303,19 +741,31 @@ EXPORT_SYMBOL_GPL(sigmadsp_attach); */ int sigmadsp_setup(struct sigmadsp *sigmadsp, unsigned int samplerate) { + struct sigmadsp_control *ctrl; + unsigned int samplerate_mask; struct sigmadsp_data *data; int ret; if (sigmadsp->current_samplerate == samplerate) return 0; + samplerate_mask = sigmadsp_get_samplerate_mask(sigmadsp, samplerate); + if (samplerate_mask == 0) + return -EINVAL; + list_for_each_entry(data, &sigmadsp->data_list, head) { + if (!sigmadsp_samplerate_valid(data->samplerates, + samplerate_mask)) + continue; ret = sigmadsp_write(sigmadsp, data->addr, data->data, data->length); if (ret) goto err; } + list_for_each_entry(ctrl, &sigmadsp->ctrl_list, head) + sigmadsp_activate_ctrl(sigmadsp, ctrl, samplerate_mask); + sigmadsp->current_samplerate = samplerate; return 0; @@ -335,6 +785,11 @@ EXPORT_SYMBOL_GPL(sigmadsp_setup); */ void sigmadsp_reset(struct sigmadsp *sigmadsp) { + struct sigmadsp_control *ctrl; + + list_for_each_entry(ctrl, &sigmadsp->ctrl_list, head) + sigmadsp_activate_ctrl(sigmadsp, ctrl, false); + sigmadsp->current_samplerate = 0; } EXPORT_SYMBOL_GPL(sigmadsp_reset); @@ -352,7 +807,11 @@ EXPORT_SYMBOL_GPL(sigmadsp_reset); int sigmadsp_restrict_params(struct sigmadsp *sigmadsp, struct snd_pcm_substream *substream) { - return 0; + if (sigmadsp->rate_constraints.count == 0) + return 0; + + return snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, &sigmadsp->rate_constraints); } EXPORT_SYMBOL_GPL(sigmadsp_restrict_params); diff --git a/sound/soc/codecs/sigmadsp.h b/sound/soc/codecs/sigmadsp.h index a6be91a4c2dc..614475cbb823 100644 --- a/sound/soc/codecs/sigmadsp.h +++ b/sound/soc/codecs/sigmadsp.h @@ -27,14 +27,20 @@ struct sigmadsp_ops { struct sigmadsp { const struct sigmadsp_ops *ops; + struct list_head ctrl_list; struct list_head data_list; + struct snd_pcm_hw_constraint_list rate_constraints; + unsigned int current_samplerate; struct snd_soc_component *component; struct device *dev; + struct mutex lock; + void *control_data; int (*write)(void *, unsigned int, const uint8_t *, size_t); + int (*read)(void *, unsigned int, uint8_t *, size_t); }; struct sigmadsp *devm_sigmadsp_init(struct device *dev, -- cgit v1.2.3 From a3a1ec66d6c9320e676fc99dbaf18db4f8dcda93 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 19 Nov 2014 18:29:07 +0100 Subject: ASoC: adau1701: Implement sigmadsp safeload The safeload feature allows to load up to 5 parameter memory registers atomically. This is helpful for switching between e.g. filter settings without causing any glitches. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/adau1701.c | 57 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 55 insertions(+), 2 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c index 05d5eb5984b6..d4e219b6b98f 100644 --- a/sound/soc/codecs/adau1701.c +++ b/sound/soc/codecs/adau1701.c @@ -22,9 +22,14 @@ #include #include +#include + #include "sigmadsp.h" #include "adau1701.h" +#define ADAU1701_SAFELOAD_DATA(i) (0x0810 + (i)) +#define ADAU1701_SAFELOAD_ADDR(i) (0x0815 + (i)) + #define ADAU1701_DSPCTRL 0x081c #define ADAU1701_SEROCTL 0x081e #define ADAU1701_SERICTL 0x081f @@ -42,6 +47,7 @@ #define ADAU1701_DSPCTRL_CR (1 << 2) #define ADAU1701_DSPCTRL_DAM (1 << 3) #define ADAU1701_DSPCTRL_ADM (1 << 4) +#define ADAU1701_DSPCTRL_IST (1 << 5) #define ADAU1701_DSPCTRL_SR_48 0x00 #define ADAU1701_DSPCTRL_SR_96 0x01 #define ADAU1701_DSPCTRL_SR_192 0x02 @@ -102,6 +108,7 @@ struct adau1701 { unsigned int pll_clkdiv; unsigned int sysclk; struct regmap *regmap; + struct i2c_client *client; u8 pin_config[12]; struct sigmadsp *sigmadsp; @@ -161,6 +168,7 @@ static bool adau1701_volatile_reg(struct device *dev, unsigned int reg) { switch (reg) { case ADAU1701_DACSET: + case ADAU1701_DSPCTRL: return true; default: return false; @@ -240,6 +248,50 @@ static int adau1701_reg_read(void *context, unsigned int reg, return 0; } +static int adau1701_safeload(struct sigmadsp *sigmadsp, unsigned int addr, + const uint8_t bytes[], size_t len) +{ + struct i2c_client *client = to_i2c_client(sigmadsp->dev); + struct adau1701 *adau1701 = i2c_get_clientdata(client); + unsigned int val; + unsigned int i; + uint8_t buf[10]; + int ret; + + ret = regmap_read(adau1701->regmap, ADAU1701_DSPCTRL, &val); + if (ret) + return ret; + + if (val & ADAU1701_DSPCTRL_IST) + msleep(50); + + for (i = 0; i < len / 4; i++) { + put_unaligned_le16(ADAU1701_SAFELOAD_DATA(i), buf); + buf[2] = 0x00; + memcpy(buf + 3, bytes + i * 4, 4); + ret = i2c_master_send(client, buf, 7); + if (ret < 0) + return ret; + else if (ret != 7) + return -EIO; + + put_unaligned_le16(ADAU1701_SAFELOAD_ADDR(i), buf); + put_unaligned_le16(addr + i, buf + 2); + ret = i2c_master_send(client, buf, 4); + if (ret < 0) + return ret; + else if (ret != 4) + return -EIO; + } + + return regmap_update_bits(adau1701->regmap, ADAU1701_DSPCTRL, + ADAU1701_DSPCTRL_IST, ADAU1701_DSPCTRL_IST); +} + +static const struct sigmadsp_ops adau1701_sigmadsp_ops = { + .safeload = adau1701_safeload, +}; + static int adau1701_reset(struct snd_soc_codec *codec, unsigned int clkdiv, unsigned int rate) { @@ -684,6 +736,7 @@ static int adau1701_i2c_probe(struct i2c_client *client, if (!adau1701) return -ENOMEM; + adau1701->client = client; adau1701->regmap = devm_regmap_init(dev, NULL, client, &adau1701_regmap); if (IS_ERR(adau1701->regmap)) @@ -740,8 +793,8 @@ static int adau1701_i2c_probe(struct i2c_client *client, i2c_set_clientdata(client, adau1701); - adau1701->sigmadsp = devm_sigmadsp_init_i2c(client, NULL, - ADAU1701_FIRMWARE); + adau1701->sigmadsp = devm_sigmadsp_init_i2c(client, + &adau1701_sigmadsp_ops, ADAU1701_FIRMWARE); if (IS_ERR(adau1701->sigmadsp)) return PTR_ERR(adau1701->sigmadsp); -- cgit v1.2.3 From 335ca471eebf130d88cb94c1192568b6c75aa9b0 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 20 Nov 2014 21:28:15 +0100 Subject: ASoC: sirf-audio-codec: Replace w->codec snd_soc_dapm_to_codec(w->dapm) The codec field of the snd_soc_widget struct is eventually going to be removed, use snd_soc_dapm_to_codec(w->dapm) instead. While we are at it also replace dev_get_drvdata() with snd_soc_codec_get_drvdata(). Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/sirf-audio-codec.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/sirf-audio-codec.c b/sound/soc/codecs/sirf-audio-codec.c index 06ba4923fd5a..07eea20e6645 100644 --- a/sound/soc/codecs/sirf-audio-codec.c +++ b/sound/soc/codecs/sirf-audio-codec.c @@ -120,7 +120,8 @@ static int atlas6_codec_enable_and_reset_event(struct snd_soc_dapm_widget *w, { #define ATLAS6_CODEC_ENABLE_BITS (1 << 29) #define ATLAS6_CODEC_RESET_BITS (1 << 28) - struct sirf_audio_codec *sirf_audio_codec = dev_get_drvdata(w->codec->dev); + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct sirf_audio_codec *sirf_audio_codec = snd_soc_codec_get_drvdata(codec); switch (event) { case SND_SOC_DAPM_PRE_PMU: enable_and_reset_codec(sirf_audio_codec->regmap, @@ -142,7 +143,8 @@ static int prima2_codec_enable_and_reset_event(struct snd_soc_dapm_widget *w, { #define PRIMA2_CODEC_ENABLE_BITS (1 << 27) #define PRIMA2_CODEC_RESET_BITS (1 << 26) - struct sirf_audio_codec *sirf_audio_codec = dev_get_drvdata(w->codec->dev); + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct sirf_audio_codec *sirf_audio_codec = snd_soc_codec_get_drvdata(codec); switch (event) { case SND_SOC_DAPM_POST_PMU: enable_and_reset_codec(sirf_audio_codec->regmap, -- cgit v1.2.3 From 0b5155bbca8b5a8a1456ae462a47eeaedf8ce091 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 20 Nov 2014 21:21:53 +0100 Subject: ASoC: max98088: Replace w->codec snd_soc_dapm_to_codec(w->dapm) The codec field of the snd_soc_widget struct is eventually going to be removed, use snd_soc_dapm_to_codec(w->dapm) instead. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/max98088.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c index 2cd3e5427441..abf3832e6f8b 100644 --- a/sound/soc/codecs/max98088.c +++ b/sound/soc/codecs/max98088.c @@ -875,7 +875,7 @@ static const struct snd_kcontrol_new max98088_right_ADC_mixer_controls[] = { static int max98088_mic_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec); switch (event) { @@ -905,7 +905,7 @@ static int max98088_mic_event(struct snd_soc_dapm_widget *w, static int max98088_line_pga(struct snd_soc_dapm_widget *w, int event, int line, u8 channel) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec); u8 *state; -- cgit v1.2.3 From 24445f8c5eae926e402335bbe0292f09b1deb7a7 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 20 Nov 2014 21:21:54 +0100 Subject: ASoC: max98090: Replace w->codec snd_soc_dapm_to_codec(w->dapm) The codec field of the snd_soc_widget struct is eventually going to be removed, use snd_soc_dapm_to_codec(w->dapm) instead. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/max98090.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index a65861cf0a44..2ad381c4ec57 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c @@ -806,7 +806,7 @@ static const struct snd_kcontrol_new max98091_snd_controls[] = { static int max98090_micinput_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec); unsigned int val = snd_soc_read(codec, w->reg); -- cgit v1.2.3 From 0db5dc943e7649bbfbc2d2de8f5cb778b05ea5bd Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 20 Nov 2014 21:21:55 +0100 Subject: ASoC: max98095: Replace w->codec snd_soc_dapm_to_codec(w->dapm) The codec field of the snd_soc_widget struct is eventually going to be removed, use snd_soc_dapm_to_codec(w->dapm) instead. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/max98095.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c index 42103cafeb24..d911d4cb9add 100644 --- a/sound/soc/codecs/max98095.c +++ b/sound/soc/codecs/max98095.c @@ -864,7 +864,7 @@ static const struct snd_kcontrol_new max98095_right_ADC_mixer_controls[] = { static int max98095_mic_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); switch (event) { @@ -894,7 +894,7 @@ static int max98095_mic_event(struct snd_soc_dapm_widget *w, static int max98095_line_pga(struct snd_soc_dapm_widget *w, int event, u8 channel) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); u8 *state; @@ -942,7 +942,7 @@ static int max98095_pga_in2_event(struct snd_soc_dapm_widget *w, static int max98095_lineout_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); switch (event) { case SND_SOC_DAPM_POST_PMU: -- cgit v1.2.3 From dee9cec42fc9cc4635ea2f45939e443210a638f8 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 21 Nov 2014 18:53:51 +0100 Subject: ASoC: adau17x1: Mark DSP parameter memory as readable and precious To be able to read back data from the DSP parameter memory the register range needs to be marked as readable. At the same time we do not want them to e.g. appear in debugfs output so mark them as precious as well. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/adau1761.c | 1 + sound/soc/codecs/adau1781.c | 1 + sound/soc/codecs/adau17x1.c | 14 ++++++++++++++ sound/soc/codecs/adau17x1.h | 1 + 4 files changed, 17 insertions(+) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/adau1761.c b/sound/soc/codecs/adau1761.c index 0ae1501f3c11..4c018c575b01 100644 --- a/sound/soc/codecs/adau1761.c +++ b/sound/soc/codecs/adau1761.c @@ -793,6 +793,7 @@ const struct regmap_config adau1761_regmap_config = { .num_reg_defaults = ARRAY_SIZE(adau1761_reg_defaults), .readable_reg = adau1761_readable_register, .volatile_reg = adau17x1_volatile_register, + .precious_reg = adau17x1_precious_register, .cache_type = REGCACHE_RBTREE, }; EXPORT_SYMBOL_GPL(adau1761_regmap_config); diff --git a/sound/soc/codecs/adau1781.c b/sound/soc/codecs/adau1781.c index 4c8ddc3c69e1..926fc99c1dda 100644 --- a/sound/soc/codecs/adau1781.c +++ b/sound/soc/codecs/adau1781.c @@ -472,6 +472,7 @@ const struct regmap_config adau1781_regmap_config = { .num_reg_defaults = ARRAY_SIZE(adau1781_reg_defaults), .readable_reg = adau1781_readable_register, .volatile_reg = adau17x1_volatile_register, + .precious_reg = adau17x1_precious_register, .cache_type = REGCACHE_RBTREE, }; EXPORT_SYMBOL_GPL(adau1781_regmap_config); diff --git a/sound/soc/codecs/adau17x1.c b/sound/soc/codecs/adau17x1.c index 1cab34c57413..50000477dc2a 100644 --- a/sound/soc/codecs/adau17x1.c +++ b/sound/soc/codecs/adau17x1.c @@ -706,8 +706,22 @@ int adau17x1_set_micbias_voltage(struct snd_soc_codec *codec, } EXPORT_SYMBOL_GPL(adau17x1_set_micbias_voltage); +bool adau17x1_precious_register(struct device *dev, unsigned int reg) +{ + /* SigmaDSP parameter memory */ + if (reg < 0x400) + return true; + + return false; +} +EXPORT_SYMBOL_GPL(adau17x1_precious_register); + bool adau17x1_readable_register(struct device *dev, unsigned int reg) { + /* SigmaDSP parameter memory */ + if (reg < 0x400) + return true; + switch (reg) { case ADAU17X1_CLOCK_CONTROL: case ADAU17X1_PLL_CONTROL: diff --git a/sound/soc/codecs/adau17x1.h b/sound/soc/codecs/adau17x1.h index 6861aa3aec02..e13583e6ff56 100644 --- a/sound/soc/codecs/adau17x1.h +++ b/sound/soc/codecs/adau17x1.h @@ -56,6 +56,7 @@ int adau17x1_set_micbias_voltage(struct snd_soc_codec *codec, enum adau17x1_micbias_voltage micbias); bool adau17x1_readable_register(struct device *dev, unsigned int reg); bool adau17x1_volatile_register(struct device *dev, unsigned int reg); +bool adau17x1_precious_register(struct device *dev, unsigned int reg); int adau17x1_resume(struct snd_soc_codec *codec); extern const struct snd_soc_dai_ops adau17x1_dai_ops; -- cgit v1.2.3 From 1fc10044d76e86b71f724988c7cbd8205bb903a8 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 21 Nov 2014 18:53:52 +0100 Subject: ASoC: sigmadsp: Fix endianness conversion Make sure to always convert the firmware data to local endianness before using it. Reported-by: kbuild test robot Fixes: a35daac77a03 ("ASoC: sigmadsp: Add support for fw v2") Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/sigmadsp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/sigmadsp.c b/sound/soc/codecs/sigmadsp.c index 55af596935d4..6abefd27b86c 100644 --- a/sound/soc/codecs/sigmadsp.c +++ b/sound/soc/codecs/sigmadsp.c @@ -235,7 +235,7 @@ static int sigma_fw_load_control(struct sigmadsp *sigmadsp, ctrl->addr = le16_to_cpu(ctrl_chunk->addr); ctrl->num_bytes = num_bytes; - ctrl->samplerates = chunk->samplerates; + ctrl->samplerates = le32_to_cpu(chunk->samplerates); list_add_tail(&ctrl->head, &sigmadsp->ctrl_list); @@ -266,7 +266,7 @@ static int sigma_fw_load_data(struct sigmadsp *sigmadsp, data->addr = le16_to_cpu(data_chunk->addr); data->length = length; - data->samplerates = chunk->samplerates; + data->samplerates = le32_to_cpu(chunk->samplerates); memcpy(data->data, data_chunk->data, length); list_add_tail(&data->head, &sigmadsp->data_list); @@ -329,7 +329,7 @@ static int sigmadsp_fw_load_v2(struct sigmadsp *sigmadsp, if (length > fw->size - pos || length < sizeof(*chunk)) return -EINVAL; - switch (chunk->tag) { + switch (le32_to_cpu(chunk->tag)) { case SIGMA_FW_CHUNK_TYPE_DATA: ret = sigma_fw_load_data(sigmadsp, chunk, length); break; -- cgit v1.2.3 From e2280c9040d8bc5039617af35ccf7b8ac4abb428 Mon Sep 17 00:00:00 2001 From: Zidan Wang Date: Thu, 20 Nov 2014 19:07:48 +0800 Subject: ASoC: wm8960: Add device tree support Document the device tree binding for the WM8960 codec, and modify the driver to extract the platform data from device tree, if present. Signed-off-by: Zidan Wang Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/wm8960.txt | 31 ++++++++++++++++ sound/soc/codecs/wm8960.c | 41 ++++++++++++++++------ 2 files changed, 62 insertions(+), 10 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/wm8960.txt (limited to 'sound/soc/codecs') diff --git a/Documentation/devicetree/bindings/sound/wm8960.txt b/Documentation/devicetree/bindings/sound/wm8960.txt new file mode 100644 index 000000000000..2deb8a3da9c5 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/wm8960.txt @@ -0,0 +1,31 @@ +WM8960 audio CODEC + +This device supports I2C only. + +Required properties: + + - compatible : "wlf,wm8960" + + - reg : the I2C address of the device. + +Optional properties: + - wlf,shared-lrclk: This is a boolean property. If present, the LRCM bit of + R24 (Additional control 2) gets set, indicating that ADCLRC and DACLRC pins + will be disabled only when ADC (Left and Right) and DAC (Left and Right) + are disabled. + When wm8960 works on synchronize mode and DACLRC pin is used to supply + frame clock, it will no frame clock for captrue unless enable DAC to enable + DACLRC pin. If shared-lrclk is present, no need to enable DAC for captrue. + + - wlf,capless: This is a boolean property. If present, OUT3 pin will be + enabled and disabled together with HP_L and HP_R pins in response to jack + detect events. + +Example: + +codec: wm8960@1a { + compatible = "wlf,wm8960"; + reg = <0x1a>; + + wlf,shared-lrclk; +}; diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index 4dc4e85116cd..99d6457c87ba 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -125,6 +125,7 @@ struct wm8960_priv { struct snd_soc_dapm_widget *out3; bool deemph; int playback_fs; + struct wm8960_data pdata; }; #define wm8960_reset(c) snd_soc_write(c, WM8960_RESET, 0) @@ -440,8 +441,8 @@ static const struct snd_soc_dapm_route audio_paths_capless[] = { static int wm8960_add_widgets(struct snd_soc_codec *codec) { - struct wm8960_data *pdata = codec->dev->platform_data; struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); + struct wm8960_data *pdata = &wm8960->pdata; struct snd_soc_dapm_context *dapm = &codec->dapm; struct snd_soc_dapm_widget *w; @@ -961,17 +962,13 @@ static int wm8960_resume(struct snd_soc_codec *codec) static int wm8960_probe(struct snd_soc_codec *codec) { struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); - struct wm8960_data *pdata = dev_get_platdata(codec->dev); + struct wm8960_data *pdata = &wm8960->pdata; int ret; - wm8960->set_bias_level = wm8960_set_bias_level_out3; - - if (!pdata) { - dev_warn(codec->dev, "No platform data supplied\n"); - } else { - if (pdata->capless) - wm8960->set_bias_level = wm8960_set_bias_level_capless; - } + if (pdata->capless) + wm8960->set_bias_level = wm8960_set_bias_level_capless; + else + wm8960->set_bias_level = wm8960_set_bias_level_out3; ret = wm8960_reset(codec); if (ret < 0) { @@ -1029,6 +1026,18 @@ static const struct regmap_config wm8960_regmap = { .volatile_reg = wm8960_volatile, }; +static void wm8960_set_pdata_from_of(struct i2c_client *i2c, + struct wm8960_data *pdata) +{ + const struct device_node *np = i2c->dev.of_node; + + if (of_property_read_bool(np, "wlf,capless")) + pdata->capless = true; + + if (of_property_read_bool(np, "wlf,shared-lrclk")) + pdata->shared_lrclk = true; +} + static int wm8960_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -1045,6 +1054,11 @@ static int wm8960_i2c_probe(struct i2c_client *i2c, if (IS_ERR(wm8960->regmap)) return PTR_ERR(wm8960->regmap); + if (pdata) + memcpy(&wm8960->pdata, pdata, sizeof(struct wm8960_data)); + else if (i2c->dev.of_node) + wm8960_set_pdata_from_of(i2c, &wm8960->pdata); + if (pdata && pdata->shared_lrclk) { ret = regmap_update_bits(wm8960->regmap, WM8960_ADDCTL2, 0x4, 0x4); @@ -1075,10 +1089,17 @@ static const struct i2c_device_id wm8960_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, wm8960_i2c_id); +static const struct of_device_id wm8960_of_match[] = { + { .compatible = "wlf,wm8960", }, + { } +}; +MODULE_DEVICE_TABLE(of, wm8960_of_match); + static struct i2c_driver wm8960_i2c_driver = { .driver = { .name = "wm8960", .owner = THIS_MODULE, + .of_match_table = wm8960_of_match, }, .probe = wm8960_i2c_probe, .remove = wm8960_i2c_remove, -- cgit v1.2.3 From ceb3c0683cfc5dcc2b627985143105f6dfb0b324 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 20 Nov 2014 21:05:38 +0100 Subject: ASoC: cs42l51: Replace w->codec snd_soc_dapm_to_codec(w->dapm) The codec field of the snd_soc_widget struct is eventually going to be removed, use snd_soc_dapm_to_codec(w->dapm) instead. Signed-off-by: Lars-Peter Clausen Acked-by: Brian Austin Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l51.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c index 09488d97de60..3142bafc9262 100644 --- a/sound/soc/codecs/cs42l51.c +++ b/sound/soc/codecs/cs42l51.c @@ -153,15 +153,17 @@ static const struct snd_kcontrol_new cs42l51_snd_controls[] = { static int cs42l51_pdn_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + switch (event) { case SND_SOC_DAPM_PRE_PMD: - snd_soc_update_bits(w->codec, CS42L51_POWER_CTL1, + snd_soc_update_bits(codec, CS42L51_POWER_CTL1, CS42L51_POWER_CTL1_PDN, CS42L51_POWER_CTL1_PDN); break; default: case SND_SOC_DAPM_POST_PMD: - snd_soc_update_bits(w->codec, CS42L51_POWER_CTL1, + snd_soc_update_bits(codec, CS42L51_POWER_CTL1, CS42L51_POWER_CTL1_PDN, 0); break; } -- cgit v1.2.3 From 6e2793b98e23372cc80d9b5d981ab2467e90acea Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 20 Nov 2014 21:05:39 +0100 Subject: ASoC: cs42l73: Replace w->codec snd_soc_dapm_to_codec(w->dapm) The codec field of the snd_soc_widget struct is eventually going to be removed, use snd_soc_dapm_to_codec(w->dapm) instead. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l73.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c index 2f8b94683e83..7c55537c69cf 100644 --- a/sound/soc/codecs/cs42l73.c +++ b/sound/soc/codecs/cs42l73.c @@ -584,7 +584,7 @@ static const struct snd_kcontrol_new cs42l73_snd_controls[] = { static int cs42l73_spklo_spk_amp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct cs42l73_private *priv = snd_soc_codec_get_drvdata(codec); switch (event) { case SND_SOC_DAPM_POST_PMD: @@ -600,7 +600,7 @@ static int cs42l73_spklo_spk_amp_event(struct snd_soc_dapm_widget *w, static int cs42l73_ear_amp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct cs42l73_private *priv = snd_soc_codec_get_drvdata(codec); switch (event) { case SND_SOC_DAPM_POST_PMD: @@ -618,7 +618,7 @@ static int cs42l73_ear_amp_event(struct snd_soc_dapm_widget *w, static int cs42l73_hp_amp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct cs42l73_private *priv = snd_soc_codec_get_drvdata(codec); switch (event) { case SND_SOC_DAPM_POST_PMD: -- cgit v1.2.3 From 4cf703a7bca4c29d06028821db60f253390a84a7 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Mon, 24 Nov 2014 15:32:35 +0200 Subject: ASoC: max98090: Fix digital microphone Commit e409dfbfccf9 ("ASoC: dapm: Add a few supply widget sanity checks") broke digital microphone support in max98090.c: max98090 i2c-193C9890:00: Conditional paths are not supported for supply widgets (DMICL_ENA -> [DMIC] -> DMIC Mux) max98090 i2c-193C9890:00: ASoC: no dapm match for DMICL_ENA --> DMIC --> DMIC Mux max98090 i2c-193C9890:00: ASoC: Failed to add route DMICL_ENA -> DMIC -> DMIC Mux max98090 i2c-193C9890:00: Conditional paths are not supported for supply widgets (DMICR_ENA -> [DMIC] -> DMIC Mux) max98090 i2c-193C9890:00: ASoC: no dapm match for DMICR_ENA --> DMIC --> DMIC Mux max98090 i2c-193C9890:00: ASoC: Failed to add route DMICR_ENA -> DMIC -> DMIC Mux Problem is partially caused by commit f69e3caa9e18 ("ASoC: max98090: Enable both DMIC channels also when using mono configuration") which connects "DMICL_ENA" and "DMICR_ENA" supply widgets to "DMIC Mux". Fix the breakage by reverting f69e3caa9e18 and then by adding additional "DMICR_ENA" to "DMICL" and "DMICL_ENA" to "DMICR" cross-connections. This disconnects these supply widgets from the mux and makes sure that both DMIC data channels are still enabled together. Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/codecs/max98090.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index 1229554f1464..994d02c1fb69 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c @@ -1311,6 +1311,10 @@ static const struct snd_soc_dapm_route max98090_dapm_routes[] = { {"MIC1 Input", NULL, "MIC1"}, {"MIC2 Input", NULL, "MIC2"}, + {"DMICL", NULL, "DMICL_ENA"}, + {"DMICL", NULL, "DMICR_ENA"}, + {"DMICR", NULL, "DMICL_ENA"}, + {"DMICR", NULL, "DMICR_ENA"}, {"DMICL", NULL, "AHPF"}, {"DMICR", NULL, "AHPF"}, @@ -1368,8 +1372,6 @@ static const struct snd_soc_dapm_route max98090_dapm_routes[] = { {"DMIC Mux", "ADC", "ADCR"}, {"DMIC Mux", "DMIC", "DMICL"}, {"DMIC Mux", "DMIC", "DMICR"}, - {"DMIC Mux", "DMIC", "DMICL_ENA"}, - {"DMIC Mux", "DMIC", "DMICR_ENA"}, {"LBENL Mux", "Normal", "DMIC Mux"}, {"LBENL Mux", "Loopback", "LTENL Mux"}, -- cgit v1.2.3 From 48826ee590da03e9882922edf96d8d27bdfe9552 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Mon, 24 Nov 2014 15:32:36 +0200 Subject: ASoC: max98090: Fix ill-defined sidetone route Commit 5fe5b767dc6f ("ASoC: dapm: Do not pretend to support controls for non mixer/mux widgets") revealed ill-defined control in a route between "STENL Mux" and DACs in max98090.c: max98090 i2c-193C9890:00: Control not supported for path STENL Mux -> [NULL] -> DACL max98090 i2c-193C9890:00: ASoC: no dapm match for STENL Mux --> NULL --> DACL max98090 i2c-193C9890:00: ASoC: Failed to add route STENL Mux -> NULL -> DACL max98090 i2c-193C9890:00: Control not supported for path STENL Mux -> [NULL] -> DACR max98090 i2c-193C9890:00: ASoC: no dapm match for STENL Mux --> NULL --> DACR max98090 i2c-193C9890:00: ASoC: Failed to add route STENL Mux -> NULL -> DACR Since there is no control between "STENL Mux" and DACs the control name must be NULL not "NULL". Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- sound/soc/codecs/max98090.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index 994d02c1fb69..20b50e46a9e8 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c @@ -1397,8 +1397,8 @@ static const struct snd_soc_dapm_route max98090_dapm_routes[] = { {"STENL Mux", "Sidetone Left", "DMICL"}, {"STENR Mux", "Sidetone Right", "ADCR"}, {"STENR Mux", "Sidetone Right", "DMICR"}, - {"DACL", "NULL", "STENL Mux"}, - {"DACR", "NULL", "STENL Mux"}, + {"DACL", NULL, "STENL Mux"}, + {"DACR", NULL, "STENL Mux"}, {"AIFINL", NULL, "SHDN"}, {"AIFINR", NULL, "SHDN"}, -- cgit v1.2.3 From 418382f29d99f1faffdd6636f378da41b44815db Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Mon, 24 Nov 2014 15:32:37 +0200 Subject: ASoC: max98090: Fix right sidetone connection It is right not left sidetone which goes to "DACR". Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/codecs/max98090.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index 20b50e46a9e8..34ed9a91f392 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c @@ -1398,7 +1398,7 @@ static const struct snd_soc_dapm_route max98090_dapm_routes[] = { {"STENR Mux", "Sidetone Right", "ADCR"}, {"STENR Mux", "Sidetone Right", "DMICR"}, {"DACL", NULL, "STENL Mux"}, - {"DACR", NULL, "STENL Mux"}, + {"DACR", NULL, "STENR Mux"}, {"AIFINL", NULL, "SHDN"}, {"AIFINR", NULL, "SHDN"}, -- cgit v1.2.3 From a6e4599f8d232b5911c46bb16f5a79b86f3dfb75 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 23 Nov 2014 15:04:12 +0100 Subject: ASoC: uda134x: Remove is_powered_on_standby from platform data According to its documentation the is_powered_on_standby field of the uda134x platform data is supposed to prevent the the driver from shutting down the ADC and DAC in standby mode. This behavior was broken in commit commit f0fba2ad1b6b ("ASoC: multi-component - ASoC Multi-Component Support") almost 5 years ago and all the flag does now is cause the driver to go to SND_SOC_BIAS_ON in probe, just for the ASoC core to put it back into SND_SOC_BIAS_STANDBY right after probe. Apparently the intended behavior has not been missed, so just remove is_powered_on_standby from the platform data struct. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- include/sound/uda134x.h | 12 ------------ sound/soc/codecs/uda134x.c | 5 +---- 2 files changed, 1 insertion(+), 16 deletions(-) (limited to 'sound/soc/codecs') diff --git a/include/sound/uda134x.h b/include/sound/uda134x.h index e475659bd3be..509efb050176 100644 --- a/include/sound/uda134x.h +++ b/include/sound/uda134x.h @@ -18,18 +18,6 @@ struct uda134x_platform_data { struct l3_pins l3; void (*power) (int); int model; - /* - ALSA SOC usually puts the device in standby mode when it's not used - for sometime. If you unset is_powered_on_standby the driver will - turn off the ADC/DAC when this callback is invoked and turn it back - on when needed. Unfortunately this will result in a very light bump - (it can be audible only with good earphones). If this bothers you - set is_powered_on_standby, you will have slightly higher power - consumption. Please note that sending the L3 command for ADC is - enough to make the bump, so it doesn't make difference if you - completely take off power from the codec. - */ - int is_powered_on_standby; #define UDA134X_UDA1340 1 #define UDA134X_UDA1341 2 #define UDA134X_UDA1344 3 diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c index 32b2f78aa62c..54240f14211f 100644 --- a/sound/soc/codecs/uda134x.c +++ b/sound/soc/codecs/uda134x.c @@ -518,10 +518,7 @@ static int uda134x_soc_probe(struct snd_soc_codec *codec) uda134x_reset(codec); - if (pd->is_powered_on_standby) - uda134x_set_bias_level(codec, SND_SOC_BIAS_ON); - else - uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); if (pd->model == UDA134X_UDA1341) { widgets = uda1341_dapm_widgets; -- cgit v1.2.3 From e03b975506545d21b1daa5c8310b59d66e74919c Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 23 Nov 2014 15:04:13 +0100 Subject: ASoC: uda134x: Cleanup manual bias level transitions Set the CODEC driver's suspend_bias_off flag rather than manually going to SND_SOC_BIAS_OFF in suspend and SND_SOC_BIAS_STANDBY in resume. This makes the code a bit shorter and cleaner. Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. The manual transition to SND_SOC_BIAS_STANDBY at the end of CODEC probe() can also be removed as the core will automatically do this after the CODEC has been probed. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/uda134x.c | 29 ++--------------------------- 1 file changed, 2 insertions(+), 27 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c index 54240f14211f..4056260a502e 100644 --- a/sound/soc/codecs/uda134x.c +++ b/sound/soc/codecs/uda134x.c @@ -518,8 +518,6 @@ static int uda134x_soc_probe(struct snd_soc_codec *codec) uda134x_reset(codec); - uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - if (pd->model == UDA134X_UDA1341) { widgets = uda1341_dapm_widgets; num_widgets = ARRAY_SIZE(uda1341_dapm_widgets); @@ -571,44 +569,21 @@ static int uda134x_soc_remove(struct snd_soc_codec *codec) { struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec); - uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - uda134x_set_bias_level(codec, SND_SOC_BIAS_OFF); - kfree(uda134x); return 0; } -#if defined(CONFIG_PM) -static int uda134x_soc_suspend(struct snd_soc_codec *codec) -{ - uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - uda134x_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - -static int uda134x_soc_resume(struct snd_soc_codec *codec) -{ - uda134x_set_bias_level(codec, SND_SOC_BIAS_PREPARE); - uda134x_set_bias_level(codec, SND_SOC_BIAS_ON); - return 0; -} -#else -#define uda134x_soc_suspend NULL -#define uda134x_soc_resume NULL -#endif /* CONFIG_PM */ - static struct snd_soc_codec_driver soc_codec_dev_uda134x = { .probe = uda134x_soc_probe, .remove = uda134x_soc_remove, - .suspend = uda134x_soc_suspend, - .resume = uda134x_soc_resume, .reg_cache_size = sizeof(uda134x_reg), .reg_word_size = sizeof(u8), .reg_cache_default = uda134x_reg, .reg_cache_step = 1, .read = uda134x_read_reg_cache, - .write = uda134x_write, .set_bias_level = uda134x_set_bias_level, + .suspend_bias_off = true, + .dapm_widgets = uda134x_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(uda134x_dapm_widgets), .dapm_routes = uda134x_dapm_routes, -- cgit v1.2.3 From e8125f04421f7757df0017a59cd9b756148ee769 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 23 Nov 2014 15:04:14 +0100 Subject: ASoC: uda1380: Cleanup manual bias level transitions Set the CODEC driver's suspend_bias_off flag rather than manually going to SND_SOC_BIAS_OFF in suspend and SND_SOC_BIAS_STANDBY in resume. This makes the code a bit shorter and cleaner. Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. The manual transition to SND_SOC_BIAS_STANDBY at the end of CODEC probe() can also be removed as the core will automatically do this after the CODEC has been probed. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/uda1380.c | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c index e62e70781ec2..dc7778b6dd7f 100644 --- a/sound/soc/codecs/uda1380.c +++ b/sound/soc/codecs/uda1380.c @@ -693,18 +693,6 @@ static struct snd_soc_dai_driver uda1380_dai[] = { }, }; -static int uda1380_suspend(struct snd_soc_codec *codec) -{ - uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - -static int uda1380_resume(struct snd_soc_codec *codec) -{ - uda1380_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - return 0; -} - static int uda1380_probe(struct snd_soc_codec *codec) { struct uda1380_platform_data *pdata =codec->dev->platform_data; @@ -739,8 +727,6 @@ static int uda1380_probe(struct snd_soc_codec *codec) INIT_WORK(&uda1380->work, uda1380_flush_work); - /* power on device */ - uda1380_set_bias_level(codec, SND_SOC_BIAS_STANDBY); /* set clock input */ switch (pdata->dac_clk) { case UDA1380_DAC_CLK_SYSCLK: @@ -766,8 +752,6 @@ static int uda1380_remove(struct snd_soc_codec *codec) { struct uda1380_platform_data *pdata =codec->dev->platform_data; - uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF); - gpio_free(pdata->gpio_reset); gpio_free(pdata->gpio_power); @@ -777,11 +761,11 @@ static int uda1380_remove(struct snd_soc_codec *codec) static struct snd_soc_codec_driver soc_codec_dev_uda1380 = { .probe = uda1380_probe, .remove = uda1380_remove, - .suspend = uda1380_suspend, - .resume = uda1380_resume, .read = uda1380_read_reg_cache, .write = uda1380_write, .set_bias_level = uda1380_set_bias_level, + .suspend_bias_off = true, + .reg_cache_size = ARRAY_SIZE(uda1380_reg), .reg_word_size = sizeof(u16), .reg_cache_default = uda1380_reg, -- cgit v1.2.3 From 2849bde56aac38645c5ed2af3971358b89a929f6 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 23 Nov 2014 13:47:50 +0100 Subject: ASoC: alc5623: Cleanup bias level transitions Set the CODEC driver's suspend_bias_off flag rather than manually going to SND_SOC_BIAS_OFF in suspend and SND_SOC_BIAS_STANDBY in resume. This makes the code a bit shorter and cleaner. Also remove the manual sequencing back to SND_SOC_BIAS_ON in resume as this is already handled by the ASoC core. Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. The manual transition to SND_SOC_BIAS_STANDBY at the end of CODEC probe() can also be removed as the core will automatically do this after the CODEC has been probed. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/alc5623.c | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/alc5623.c b/sound/soc/codecs/alc5623.c index 9d0755aa1d16..bdf8c5ac8ca4 100644 --- a/sound/soc/codecs/alc5623.c +++ b/sound/soc/codecs/alc5623.c @@ -866,7 +866,6 @@ static int alc5623_suspend(struct snd_soc_codec *codec) { struct alc5623_priv *alc5623 = snd_soc_codec_get_drvdata(codec); - alc5623_set_bias_level(codec, SND_SOC_BIAS_OFF); regcache_cache_only(alc5623->regmap, true); return 0; @@ -887,15 +886,6 @@ static int alc5623_resume(struct snd_soc_codec *codec) return ret; } - alc5623_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - /* charge alc5623 caps */ - if (codec->dapm.suspend_bias_level == SND_SOC_BIAS_ON) { - alc5623_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - codec->dapm.bias_level = SND_SOC_BIAS_ON; - alc5623_set_bias_level(codec, codec->dapm.bias_level); - } - return 0; } @@ -906,9 +896,6 @@ static int alc5623_probe(struct snd_soc_codec *codec) alc5623_reset(codec); - /* power on device */ - alc5623_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - if (alc5623->add_ctrl) { snd_soc_write(codec, ALC5623_ADD_CTRL_REG, alc5623->add_ctrl); @@ -964,19 +951,12 @@ static int alc5623_probe(struct snd_soc_codec *codec) return 0; } -/* power down chip */ -static int alc5623_remove(struct snd_soc_codec *codec) -{ - alc5623_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - static struct snd_soc_codec_driver soc_codec_device_alc5623 = { .probe = alc5623_probe, - .remove = alc5623_remove, .suspend = alc5623_suspend, .resume = alc5623_resume, .set_bias_level = alc5623_set_bias_level, + .suspend_bias_off = true, }; static const struct regmap_config alc5623_regmap = { -- cgit v1.2.3 From 5c9dc0898f343473efa3056fff9d5a9fbd577272 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 23 Nov 2014 13:47:51 +0100 Subject: ASoC: alc5632: Cleanup bias level transitions Set the CODEC driver's suspend_bias_off flag rather than manually going to SND_SOC_BIAS_OFF in suspend and SND_SOC_BIAS_STANDBY in resume. This makes the code a bit shorter and cleaner. Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. The manual transition to SND_SOC_BIAS_STANDBY at the end of CODEC probe() can also be removed as the core will automatically do this after the CODEC has been probed. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/alc5632.c | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/alc5632.c b/sound/soc/codecs/alc5632.c index 85942ca36cbf..d1fdbc266631 100644 --- a/sound/soc/codecs/alc5632.c +++ b/sound/soc/codecs/alc5632.c @@ -1038,23 +1038,15 @@ static struct snd_soc_dai_driver alc5632_dai = { }; #ifdef CONFIG_PM -static int alc5632_suspend(struct snd_soc_codec *codec) -{ - alc5632_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - static int alc5632_resume(struct snd_soc_codec *codec) { struct alc5632_priv *alc5632 = snd_soc_codec_get_drvdata(codec); regcache_sync(alc5632->regmap); - alc5632_set_bias_level(codec, SND_SOC_BIAS_STANDBY); return 0; } #else -#define alc5632_suspend NULL #define alc5632_resume NULL #endif @@ -1062,9 +1054,6 @@ static int alc5632_probe(struct snd_soc_codec *codec) { struct alc5632_priv *alc5632 = snd_soc_codec_get_drvdata(codec); - /* power on device */ - alc5632_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - switch (alc5632->id) { case 0x5c: snd_soc_add_codec_controls(codec, alc5632_vol_snd_controls, @@ -1077,19 +1066,12 @@ static int alc5632_probe(struct snd_soc_codec *codec) return 0; } -/* power down chip */ -static int alc5632_remove(struct snd_soc_codec *codec) -{ - alc5632_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - static struct snd_soc_codec_driver soc_codec_device_alc5632 = { .probe = alc5632_probe, - .remove = alc5632_remove, - .suspend = alc5632_suspend, .resume = alc5632_resume, .set_bias_level = alc5632_set_bias_level, + .suspend_bias_off = true, + .controls = alc5632_snd_controls, .num_controls = ARRAY_SIZE(alc5632_snd_controls), .dapm_widgets = alc5632_dapm_widgets, -- cgit v1.2.3 From e2dce944cc2bf22d0295330cbdcbd2ad7bd47cb4 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 23 Nov 2014 13:47:52 +0100 Subject: ASoC: rt5631: Cleanup bias level transitions Set the CODEC driver's suspend_bias_off flag rather than manually going to SND_SOC_BIAS_OFF in suspend and SND_SOC_BIAS_STANDBY in resume. This makes the code a bit shorter and cleaner. Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/rt5631.c | 27 +-------------------------- 1 file changed, 1 insertion(+), 26 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5631.c b/sound/soc/codecs/rt5631.c index 9425545e8403..6d7b7ca7d530 100644 --- a/sound/soc/codecs/rt5631.c +++ b/sound/soc/codecs/rt5631.c @@ -1612,29 +1612,6 @@ static int rt5631_probe(struct snd_soc_codec *codec) return 0; } -static int rt5631_remove(struct snd_soc_codec *codec) -{ - rt5631_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - -#ifdef CONFIG_PM -static int rt5631_suspend(struct snd_soc_codec *codec) -{ - rt5631_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - -static int rt5631_resume(struct snd_soc_codec *codec) -{ - rt5631_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - return 0; -} -#else -#define rt5631_suspend NULL -#define rt5631_resume NULL -#endif - #define RT5631_STEREO_RATES SNDRV_PCM_RATE_8000_96000 #define RT5631_FORMAT (SNDRV_PCM_FMTBIT_S16_LE | \ SNDRV_PCM_FMTBIT_S20_3LE | \ @@ -1672,10 +1649,8 @@ static struct snd_soc_dai_driver rt5631_dai[] = { static struct snd_soc_codec_driver soc_codec_dev_rt5631 = { .probe = rt5631_probe, - .remove = rt5631_remove, - .suspend = rt5631_suspend, - .resume = rt5631_resume, .set_bias_level = rt5631_set_bias_level, + .suspend_bias_off = true, .controls = rt5631_snd_controls, .num_controls = ARRAY_SIZE(rt5631_snd_controls), .dapm_widgets = rt5631_dapm_widgets, -- cgit v1.2.3 From 21a942fdd85efde65512f1458bcb952fda88886e Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 23 Nov 2014 13:37:17 +0100 Subject: ASoC: wm8350: Cleanup manual bias level transitions Set the CODEC driver's suspend_bias_off flag rather than manually going to SND_SOC_BIAS_OFF in suspend and SND_SOC_BIAS_STANDBY in resume. This makes the code a bit shorter and cleaner. Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. The manual transition to SND_SOC_BIAS_STANDBY at the end of CODEC probe() can also be removed as the core will automatically do this after the CODEC has been probed. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8350.c | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index 628ec774cf22..87f664b9cc7d 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c @@ -1242,19 +1242,6 @@ static int wm8350_set_bias_level(struct snd_soc_codec *codec, return 0; } -static int wm8350_suspend(struct snd_soc_codec *codec) -{ - wm8350_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - -static int wm8350_resume(struct snd_soc_codec *codec) -{ - wm8350_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - return 0; -} - static void wm8350_hp_work(struct wm8350_data *priv, struct wm8350_jack_data *jack, u16 mask) @@ -1565,9 +1552,6 @@ static int wm8350_codec_probe(struct snd_soc_codec *codec) wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_MICD, wm8350_mic_handler, 0, "Microphone detect", priv); - - wm8350_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - return 0; } @@ -1596,8 +1580,6 @@ static int wm8350_codec_remove(struct snd_soc_codec *codec) * wait for its completion */ flush_delayed_work(&codec->dapm.delayed_work); - wm8350_set_bias_level(codec, SND_SOC_BIAS_OFF); - wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA); return 0; @@ -1613,10 +1595,9 @@ static struct regmap *wm8350_get_regmap(struct device *dev) static struct snd_soc_codec_driver soc_codec_dev_wm8350 = { .probe = wm8350_codec_probe, .remove = wm8350_codec_remove, - .suspend = wm8350_suspend, - .resume = wm8350_resume, .get_regmap = wm8350_get_regmap, .set_bias_level = wm8350_set_bias_level, + .suspend_bias_off = true, .controls = wm8350_snd_controls, .num_controls = ARRAY_SIZE(wm8350_snd_controls), -- cgit v1.2.3 From 098f6f17c3f1beeccdce78f9722ccaa7925b8041 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 23 Nov 2014 13:37:18 +0100 Subject: ASoC: wm8400: Cleanup manual bias level transitions Set the CODEC driver's suspend_bias_off flag rather than manually going to SND_SOC_BIAS_OFF in suspend and SND_SOC_BIAS_STANDBY in resume. This makes the code a bit shorter and cleaner. Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. The manual asynchronous transition to SND_SOC_BIAS_STANDBY at the end of CODEC probe() can also be removed as the core will automatically do this after the CODEC has been probed. Also running this asynchronously has the problem of potential race conditions with the core. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/wm8400.c | 34 +--------------------------------- 1 file changed, 1 insertion(+), 33 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c index 72471bef2e9a..385894f6e264 100644 --- a/sound/soc/codecs/wm8400.c +++ b/sound/soc/codecs/wm8400.c @@ -58,12 +58,10 @@ static struct regulator_bulk_data power[] = { /* codec private data */ struct wm8400_priv { - struct snd_soc_codec *codec; struct wm8400 *wm8400; u16 fake_register; unsigned int sysclk; unsigned int pcmclk; - struct work_struct work; int fll_in, fll_out; }; @@ -1278,30 +1276,6 @@ static struct snd_soc_dai_driver wm8400_dai = { .ops = &wm8400_dai_ops, }; -static int wm8400_suspend(struct snd_soc_codec *codec) -{ - wm8400_set_bias_level(codec, SND_SOC_BIAS_OFF); - - return 0; -} - -static int wm8400_resume(struct snd_soc_codec *codec) -{ - wm8400_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - return 0; -} - -static void wm8400_probe_deferred(struct work_struct *work) -{ - struct wm8400_priv *priv = container_of(work, struct wm8400_priv, - work); - struct snd_soc_codec *codec = priv->codec; - - /* charge output caps */ - wm8400_set_bias_level(codec, SND_SOC_BIAS_STANDBY); -} - static int wm8400_codec_probe(struct snd_soc_codec *codec) { struct wm8400 *wm8400 = dev_get_platdata(codec->dev); @@ -1316,7 +1290,6 @@ static int wm8400_codec_probe(struct snd_soc_codec *codec) snd_soc_codec_set_drvdata(codec, priv); priv->wm8400 = wm8400; - priv->codec = codec; ret = devm_regulator_bulk_get(wm8400->dev, ARRAY_SIZE(power), &power[0]); @@ -1325,8 +1298,6 @@ static int wm8400_codec_probe(struct snd_soc_codec *codec) return ret; } - INIT_WORK(&priv->work, wm8400_probe_deferred); - wm8400_codec_reset(codec); reg = snd_soc_read(codec, WM8400_POWER_MANAGEMENT_1); @@ -1343,8 +1314,6 @@ static int wm8400_codec_probe(struct snd_soc_codec *codec) snd_soc_write(codec, WM8400_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8)); snd_soc_write(codec, WM8400_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8)); - if (!schedule_work(&priv->work)) - return -EINVAL; return 0; } @@ -1369,10 +1338,9 @@ static struct regmap *wm8400_get_regmap(struct device *dev) static struct snd_soc_codec_driver soc_codec_dev_wm8400 = { .probe = wm8400_codec_probe, .remove = wm8400_codec_remove, - .suspend = wm8400_suspend, - .resume = wm8400_resume, .get_regmap = wm8400_get_regmap, .set_bias_level = wm8400_set_bias_level, + .suspend_bias_off = true, .controls = wm8400_snd_controls, .num_controls = ARRAY_SIZE(wm8400_snd_controls), -- cgit v1.2.3 From 99b108c73f3876d71ac6631e85e0f093e53b7e66 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 23 Nov 2014 13:37:19 +0100 Subject: ASoC: wm8510: Cleanup manual bias level transitions Set the CODEC driver's suspend_bias_off flag rather than manually going to SND_SOC_BIAS_OFF in suspend and SND_SOC_BIAS_STANDBY in resume. This makes the code a bit shorter and cleaner. Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. The manual transition to SND_SOC_BIAS_STANDBY at the end of CODEC probe() can also be removed as the core will automatically do this after the CODEC has been probed. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8510.c | 26 +------------------------- 1 file changed, 1 insertion(+), 25 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c index e11127f9069e..8736ad094b24 100644 --- a/sound/soc/codecs/wm8510.c +++ b/sound/soc/codecs/wm8510.c @@ -575,41 +575,17 @@ static struct snd_soc_dai_driver wm8510_dai = { .symmetric_rates = 1, }; -static int wm8510_suspend(struct snd_soc_codec *codec) -{ - wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - -static int wm8510_resume(struct snd_soc_codec *codec) -{ - wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - return 0; -} - static int wm8510_probe(struct snd_soc_codec *codec) { wm8510_reset(codec); - /* power on device */ - wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - return 0; -} - -/* power down chip */ -static int wm8510_remove(struct snd_soc_codec *codec) -{ - wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF); return 0; } static struct snd_soc_codec_driver soc_codec_dev_wm8510 = { .probe = wm8510_probe, - .remove = wm8510_remove, - .suspend = wm8510_suspend, - .resume = wm8510_resume, .set_bias_level = wm8510_set_bias_level, + .suspend_bias_off = true, .controls = wm8510_snd_controls, .num_controls = ARRAY_SIZE(wm8510_snd_controls), -- cgit v1.2.3 From ca5e7c6afff94b4e103d79db835bc2990d3d340e Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 23 Nov 2014 13:37:20 +0100 Subject: ASoC: wm8523: Cleanup manual bias level transitions Set the CODEC driver's suspend_bias_off flag rather than manually going to SND_SOC_BIAS_OFF in suspend and SND_SOC_BIAS_STANDBY in resume. This makes the code a bit shorter and cleaner. Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. The manual transition to SND_SOC_BIAS_STANDBY at the end of CODEC probe() can also be removed as the core will automatically do this after the CODEC has been probed. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8523.c | 29 +---------------------------- 1 file changed, 1 insertion(+), 28 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c index ec1f5740dbd0..b1cc94f5fc4b 100644 --- a/sound/soc/codecs/wm8523.c +++ b/sound/soc/codecs/wm8523.c @@ -372,23 +372,6 @@ static struct snd_soc_dai_driver wm8523_dai = { .ops = &wm8523_dai_ops, }; -#ifdef CONFIG_PM -static int wm8523_suspend(struct snd_soc_codec *codec) -{ - wm8523_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - -static int wm8523_resume(struct snd_soc_codec *codec) -{ - wm8523_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - return 0; -} -#else -#define wm8523_suspend NULL -#define wm8523_resume NULL -#endif - static int wm8523_probe(struct snd_soc_codec *codec) { struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec); @@ -402,23 +385,13 @@ static int wm8523_probe(struct snd_soc_codec *codec) WM8523_DACR_VU, WM8523_DACR_VU); snd_soc_update_bits(codec, WM8523_DAC_CTRL3, WM8523_ZC, WM8523_ZC); - wm8523_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - return 0; -} - -static int wm8523_remove(struct snd_soc_codec *codec) -{ - wm8523_set_bias_level(codec, SND_SOC_BIAS_OFF); return 0; } static struct snd_soc_codec_driver soc_codec_dev_wm8523 = { .probe = wm8523_probe, - .remove = wm8523_remove, - .suspend = wm8523_suspend, - .resume = wm8523_resume, .set_bias_level = wm8523_set_bias_level, + .suspend_bias_off = true, .controls = wm8523_controls, .num_controls = ARRAY_SIZE(wm8523_controls), -- cgit v1.2.3 From 4d0a4c3c6dd2359c3d5facac7a306d513d79bff2 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 23 Nov 2014 13:37:21 +0100 Subject: ASoC: wm8580: Cleanup manual bias level transitions Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. The manual transition to SND_SOC_BIAS_STANDBY at the end of CODEC probe() can also be removed as the core will automatically do this after the CODEC has been probed. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8580.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index 911605ee25b0..0a887c5ec83a 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c @@ -882,8 +882,6 @@ static int wm8580_probe(struct snd_soc_codec *codec) goto err_regulator_enable; } - wm8580_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - return 0; err_regulator_enable: @@ -897,8 +895,6 @@ static int wm8580_remove(struct snd_soc_codec *codec) { struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec); - wm8580_set_bias_level(codec, SND_SOC_BIAS_OFF); - regulator_bulk_disable(ARRAY_SIZE(wm8580->supplies), wm8580->supplies); return 0; -- cgit v1.2.3 From 0bd324b1ad5c0922ac3f157763123d1550bdffd7 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 23 Nov 2014 13:37:22 +0100 Subject: ASoC: wm8711: Cleanup manual bias level transitions Set the CODEC driver's suspend_bias_off flag rather than manually going to SND_SOC_BIAS_OFF in suspend and SND_SOC_BIAS_STANDBY in resume. This makes the code a bit shorter and cleaner. Also remove the extra write that sets the WM8711_ACTIVE register to 0x00 in the suspend handler since this write is already done when transitioning to SND_SOC_BIAS_OFF. Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. The manual transition to SND_SOC_BIAS_STANDBY at the end of CODEC probe() can also be removed as the core will automatically do this after the CODEC has been probed. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8711.c | 27 ++------------------------- 1 file changed, 2 insertions(+), 25 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c index 32187e739b4f..121e46d53779 100644 --- a/sound/soc/codecs/wm8711.c +++ b/sound/soc/codecs/wm8711.c @@ -350,19 +350,6 @@ static struct snd_soc_dai_driver wm8711_dai = { .ops = &wm8711_ops, }; -static int wm8711_suspend(struct snd_soc_codec *codec) -{ - snd_soc_write(codec, WM8711_ACTIVE, 0x0); - wm8711_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - -static int wm8711_resume(struct snd_soc_codec *codec) -{ - wm8711_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - return 0; -} - static int wm8711_probe(struct snd_soc_codec *codec) { int ret; @@ -373,8 +360,6 @@ static int wm8711_probe(struct snd_soc_codec *codec) return ret; } - wm8711_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - /* Latch the update bits */ snd_soc_update_bits(codec, WM8711_LOUT1V, 0x0100, 0x0100); snd_soc_update_bits(codec, WM8711_ROUT1V, 0x0100, 0x0100); @@ -383,19 +368,11 @@ static int wm8711_probe(struct snd_soc_codec *codec) } -/* power down chip */ -static int wm8711_remove(struct snd_soc_codec *codec) -{ - wm8711_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - static struct snd_soc_codec_driver soc_codec_dev_wm8711 = { .probe = wm8711_probe, - .remove = wm8711_remove, - .suspend = wm8711_suspend, - .resume = wm8711_resume, .set_bias_level = wm8711_set_bias_level, + .suspend_bias_off = true, + .controls = wm8711_snd_controls, .num_controls = ARRAY_SIZE(wm8711_snd_controls), .dapm_widgets = wm8711_dapm_widgets, -- cgit v1.2.3 From d4d41436ff3b1fddf2f8feafa6772647eac6b61d Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 23 Nov 2014 13:37:23 +0100 Subject: ASoC: wm8728: Cleanup manual bias level transitions Set the CODEC driver's suspend_bias_off flag rather than manually going to SND_SOC_BIAS_OFF in suspend and SND_SOC_BIAS_STANDBY in resume. This makes the code a bit shorter and cleaner. Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. The manual transition to SND_SOC_BIAS_STANDBY at the end of CODEC probe() can also be removed as the core will automatically do this after the CODEC has been probed. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8728.c | 34 ++-------------------------------- 1 file changed, 2 insertions(+), 32 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c index 38ff826f589a..55c7fb4fc786 100644 --- a/sound/soc/codecs/wm8728.c +++ b/sound/soc/codecs/wm8728.c @@ -212,40 +212,10 @@ static struct snd_soc_dai_driver wm8728_dai = { .ops = &wm8728_dai_ops, }; -static int wm8728_suspend(struct snd_soc_codec *codec) -{ - wm8728_set_bias_level(codec, SND_SOC_BIAS_OFF); - - return 0; -} - -static int wm8728_resume(struct snd_soc_codec *codec) -{ - wm8728_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - return 0; -} - -static int wm8728_probe(struct snd_soc_codec *codec) -{ - /* power on device */ - wm8728_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - return 0; -} - -static int wm8728_remove(struct snd_soc_codec *codec) -{ - wm8728_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - static struct snd_soc_codec_driver soc_codec_dev_wm8728 = { - .probe = wm8728_probe, - .remove = wm8728_remove, - .suspend = wm8728_suspend, - .resume = wm8728_resume, .set_bias_level = wm8728_set_bias_level, + .suspend_bias_off = true, + .controls = wm8728_snd_controls, .num_controls = ARRAY_SIZE(wm8728_snd_controls), .dapm_widgets = wm8728_dapm_widgets, -- cgit v1.2.3 From 2081b2cf05d022ac6245334e8baa25f589e5635a Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 23 Nov 2014 13:37:24 +0100 Subject: ASoC: wm8731: Cleanup manual bias level transitions Set the CODEC driver's suspend_bias_off flag rather than manually going to SND_SOC_BIAS_OFF in suspend and SND_SOC_BIAS_STANDBY in resume. This makes the code a bit shorter and cleaner. Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8731.c | 25 ++----------------------- 1 file changed, 2 insertions(+), 23 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 2c9f2a7005c3..3b3786e5c271 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -559,25 +559,6 @@ static struct snd_soc_dai_driver wm8731_dai = { .symmetric_rates = 1, }; -#ifdef CONFIG_PM -static int wm8731_suspend(struct snd_soc_codec *codec) -{ - wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF); - - return 0; -} - -static int wm8731_resume(struct snd_soc_codec *codec) -{ - wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - return 0; -} -#else -#define wm8731_suspend NULL -#define wm8731_resume NULL -#endif - static int wm8731_probe(struct snd_soc_codec *codec) { struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec); @@ -633,8 +614,6 @@ static int wm8731_remove(struct snd_soc_codec *codec) { struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec); - wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF); - regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies); return 0; @@ -643,9 +622,9 @@ static int wm8731_remove(struct snd_soc_codec *codec) static struct snd_soc_codec_driver soc_codec_dev_wm8731 = { .probe = wm8731_probe, .remove = wm8731_remove, - .suspend = wm8731_suspend, - .resume = wm8731_resume, .set_bias_level = wm8731_set_bias_level, + .suspend_bias_off = true, + .dapm_widgets = wm8731_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(wm8731_dapm_widgets), .dapm_routes = wm8731_intercon, -- cgit v1.2.3 From 67cac3a351b9d411f8736a180767f0e898b50423 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 23 Nov 2014 13:37:25 +0100 Subject: ASoC: wm8737: Cleanup manual bias level transitions Set the CODEC driver's suspend_bias_off flag rather than manually going to SND_SOC_BIAS_OFF in suspend and SND_SOC_BIAS_STANDBY in resume. This makes the code a bit shorter and cleaner. Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8737.c | 27 +-------------------------- 1 file changed, 1 insertion(+), 26 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm8737.c b/sound/soc/codecs/wm8737.c index fe41dd2b9b45..ada9ac1ba2c6 100644 --- a/sound/soc/codecs/wm8737.c +++ b/sound/soc/codecs/wm8737.c @@ -537,23 +537,6 @@ static struct snd_soc_dai_driver wm8737_dai = { .ops = &wm8737_dai_ops, }; -#ifdef CONFIG_PM -static int wm8737_suspend(struct snd_soc_codec *codec) -{ - wm8737_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - -static int wm8737_resume(struct snd_soc_codec *codec) -{ - wm8737_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - return 0; -} -#else -#define wm8737_suspend NULL -#define wm8737_resume NULL -#endif - static int wm8737_probe(struct snd_soc_codec *codec) { struct wm8737_priv *wm8737 = snd_soc_codec_get_drvdata(codec); @@ -590,18 +573,10 @@ err_get: return ret; } -static int wm8737_remove(struct snd_soc_codec *codec) -{ - wm8737_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - static struct snd_soc_codec_driver soc_codec_dev_wm8737 = { .probe = wm8737_probe, - .remove = wm8737_remove, - .suspend = wm8737_suspend, - .resume = wm8737_resume, .set_bias_level = wm8737_set_bias_level, + .suspend_bias_off = true, .controls = wm8737_snd_controls, .num_controls = ARRAY_SIZE(wm8737_snd_controls), -- cgit v1.2.3 From d12cbf956f428229bb29fb58dee8729e16873ca7 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 23 Nov 2014 13:37:26 +0100 Subject: ASoC: wm8750: Cleanup manual bias level transitions Set the CODEC driver's suspend_bias_off flag rather than manually going to SND_SOC_BIAS_OFF in suspend and SND_SOC_BIAS_STANDBY in resume. This makes the code a bit shorter and cleaner. Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. The manual transition to SND_SOC_BIAS_STANDBY at the end of CODEC probe() can also be removed as the core will automatically do this after the CODEC has been probed. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8750.c | 25 +------------------------ 1 file changed, 1 insertion(+), 24 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index 67653a2db223..f6847fdd6ddd 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c @@ -686,18 +686,6 @@ static struct snd_soc_dai_driver wm8750_dai = { .ops = &wm8750_dai_ops, }; -static int wm8750_suspend(struct snd_soc_codec *codec) -{ - wm8750_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - -static int wm8750_resume(struct snd_soc_codec *codec) -{ - wm8750_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - return 0; -} - static int wm8750_probe(struct snd_soc_codec *codec) { int ret; @@ -708,9 +696,6 @@ static int wm8750_probe(struct snd_soc_codec *codec) return ret; } - /* charge output caps */ - wm8750_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - /* set the update bits */ snd_soc_update_bits(codec, WM8750_LDAC, 0x0100, 0x0100); snd_soc_update_bits(codec, WM8750_RDAC, 0x0100, 0x0100); @@ -724,18 +709,10 @@ static int wm8750_probe(struct snd_soc_codec *codec) return ret; } -static int wm8750_remove(struct snd_soc_codec *codec) -{ - wm8750_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - static struct snd_soc_codec_driver soc_codec_dev_wm8750 = { .probe = wm8750_probe, - .remove = wm8750_remove, - .suspend = wm8750_suspend, - .resume = wm8750_resume, .set_bias_level = wm8750_set_bias_level, + .suspend_bias_off = true, .controls = wm8750_snd_controls, .num_controls = ARRAY_SIZE(wm8750_snd_controls), -- cgit v1.2.3 From 6c286afb01cc641e2a78e485467e4a90aedfbd75 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 23 Nov 2014 13:37:27 +0100 Subject: ASoC: wm8776: Cleanup manual bias level transitions Set the CODEC driver's suspend_bias_off flag rather than manually going to SND_SOC_BIAS_OFF in suspend and SND_SOC_BIAS_STANDBY in resume. This makes the code a bit shorter and cleaner. Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. The manual transition to SND_SOC_BIAS_STANDBY at the end of CODEC probe() can also be removed as the core will automatically do this after the CODEC has been probed. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8776.c | 31 +------------------------------ 1 file changed, 1 insertion(+), 30 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm8776.c b/sound/soc/codecs/wm8776.c index 70952ceb278b..c13050b77931 100644 --- a/sound/soc/codecs/wm8776.c +++ b/sound/soc/codecs/wm8776.c @@ -408,24 +408,6 @@ static struct snd_soc_dai_driver wm8776_dai[] = { }, }; -#ifdef CONFIG_PM -static int wm8776_suspend(struct snd_soc_codec *codec) -{ - wm8776_set_bias_level(codec, SND_SOC_BIAS_OFF); - - return 0; -} - -static int wm8776_resume(struct snd_soc_codec *codec) -{ - wm8776_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - return 0; -} -#else -#define wm8776_suspend NULL -#define wm8776_resume NULL -#endif - static int wm8776_probe(struct snd_soc_codec *codec) { int ret = 0; @@ -436,8 +418,6 @@ static int wm8776_probe(struct snd_soc_codec *codec) return ret; } - wm8776_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - /* Latch the update bits; right channel only since we always * update both. */ snd_soc_update_bits(codec, WM8776_HPRVOL, 0x100, 0x100); @@ -446,19 +426,10 @@ static int wm8776_probe(struct snd_soc_codec *codec) return ret; } -/* power down chip */ -static int wm8776_remove(struct snd_soc_codec *codec) -{ - wm8776_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - static struct snd_soc_codec_driver soc_codec_dev_wm8776 = { .probe = wm8776_probe, - .remove = wm8776_remove, - .suspend = wm8776_suspend, - .resume = wm8776_resume, .set_bias_level = wm8776_set_bias_level, + .suspend_bias_off = true, .controls = wm8776_snd_controls, .num_controls = ARRAY_SIZE(wm8776_snd_controls), -- cgit v1.2.3 From a4235a14bef979752fb2ddb4dafdb696f622beb0 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 23 Nov 2014 13:37:28 +0100 Subject: ASoC: wm8804: Cleanup manual bias level transitions Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. The manual transition to SND_SOC_BIAS_STANDBY at the end of CODEC probe() can also be removed as the core will automatically do this after the CODEC has been probed. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8804.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c index 3addc5fe5cb2..1315f7642503 100644 --- a/sound/soc/codecs/wm8804.c +++ b/sound/soc/codecs/wm8804.c @@ -524,7 +524,6 @@ static int wm8804_remove(struct snd_soc_codec *codec) int i; wm8804 = snd_soc_codec_get_drvdata(codec); - wm8804_set_bias_level(codec, SND_SOC_BIAS_OFF); for (i = 0; i < ARRAY_SIZE(wm8804->supplies); ++i) regulator_unregister_notifier(wm8804->supplies[i].consumer, @@ -606,8 +605,6 @@ static int wm8804_probe(struct snd_soc_codec *codec) goto err_reg_enable; } - wm8804_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - return 0; err_reg_enable: -- cgit v1.2.3 From d2a9bc68512696a896abf7a94852c5fb5e6733a1 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 23 Nov 2014 13:37:29 +0100 Subject: ASoC: wm8900: Cleanup manual bias level transitions Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8900.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index 44a5f1511f0f..3a0d4b7d692f 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c @@ -1209,16 +1209,8 @@ static int wm8900_probe(struct snd_soc_codec *codec) return 0; } -/* power down chip */ -static int wm8900_remove(struct snd_soc_codec *codec) -{ - wm8900_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - static struct snd_soc_codec_driver soc_codec_dev_wm8900 = { .probe = wm8900_probe, - .remove = wm8900_remove, .suspend = wm8900_suspend, .resume = wm8900_resume, .set_bias_level = wm8900_set_bias_level, -- cgit v1.2.3 From b0d55b1a63ea3c3d694c58694d93f74bea61215f Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 23 Nov 2014 13:37:30 +0100 Subject: ASoC: wm8903: Cleanup manual bias level transitions Set the CODEC driver's suspend_bias_off flag rather than manually going to SND_SOC_BIAS_OFF in suspend and SND_SOC_BIAS_STANDBY in resume. This makes the code a bit shorter and cleaner. Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. The manual transition to SND_SOC_BIAS_STANDBY at the end of CODEC probe() can also be removed as the core will automatically do this after the CODEC has been probed. Also remove the unused codec field from the wm8903_priv struct so we can remove the whole probe callback. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8903.c | 35 ++--------------------------------- 1 file changed, 2 insertions(+), 33 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index c038b3e04398..9758d2ed542e 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -117,7 +117,6 @@ static const struct reg_default wm8903_reg_defaults[] = { struct wm8903_priv { struct wm8903_platform_data *pdata; struct device *dev; - struct snd_soc_codec *codec; struct regmap *regmap; int sysclk; @@ -1757,21 +1756,12 @@ static struct snd_soc_dai_driver wm8903_dai = { .symmetric_rates = 1, }; -static int wm8903_suspend(struct snd_soc_codec *codec) -{ - wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF); - - return 0; -} - static int wm8903_resume(struct snd_soc_codec *codec) { struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec); regcache_sync(wm8903->regmap); - wm8903_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - return 0; } @@ -1889,33 +1879,12 @@ static void wm8903_free_gpio(struct wm8903_priv *wm8903) } #endif -static int wm8903_probe(struct snd_soc_codec *codec) -{ - struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec); - - wm8903->codec = codec; - - /* power on device */ - wm8903_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - return 0; -} - -/* power down chip */ -static int wm8903_remove(struct snd_soc_codec *codec) -{ - wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF); - - return 0; -} - static struct snd_soc_codec_driver soc_codec_dev_wm8903 = { - .probe = wm8903_probe, - .remove = wm8903_remove, - .suspend = wm8903_suspend, .resume = wm8903_resume, .set_bias_level = wm8903_set_bias_level, .seq_notifier = wm8903_seq_notifier, + .suspend_bias_off = true, + .controls = wm8903_snd_controls, .num_controls = ARRAY_SIZE(wm8903_snd_controls), .dapm_widgets = wm8903_dapm_widgets, -- cgit v1.2.3 From 5fdf082b43995ae31d746d3d9e3b616afa24c542 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 23 Nov 2014 13:37:31 +0100 Subject: ASoC: wm8940: Cleanup manual bias level transitions Set the CODEC driver's suspend_bias_off flag rather than manually going to SND_SOC_BIAS_OFF in suspend and SND_SOC_BIAS_STANDBY in resume. This makes the code a bit shorter and cleaner. Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8940.c | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c index 52011043e54c..e4142b4309eb 100644 --- a/sound/soc/codecs/wm8940.c +++ b/sound/soc/codecs/wm8940.c @@ -695,17 +695,6 @@ static struct snd_soc_dai_driver wm8940_dai = { .symmetric_rates = 1, }; -static int wm8940_suspend(struct snd_soc_codec *codec) -{ - return wm8940_set_bias_level(codec, SND_SOC_BIAS_OFF); -} - -static int wm8940_resume(struct snd_soc_codec *codec) -{ - wm8940_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - return 0; -} - static int wm8940_probe(struct snd_soc_codec *codec) { struct wm8940_setup_data *pdata = codec->dev->platform_data; @@ -736,18 +725,11 @@ static int wm8940_probe(struct snd_soc_codec *codec) return ret; } -static int wm8940_remove(struct snd_soc_codec *codec) -{ - wm8940_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - static struct snd_soc_codec_driver soc_codec_dev_wm8940 = { .probe = wm8940_probe, - .remove = wm8940_remove, - .suspend = wm8940_suspend, - .resume = wm8940_resume, .set_bias_level = wm8940_set_bias_level, + .suspend_bias_off = true, + .controls = wm8940_snd_controls, .num_controls = ARRAY_SIZE(wm8940_snd_controls), .dapm_widgets = wm8940_dapm_widgets, -- cgit v1.2.3 From bf68a0470876b5bf43758c50a7585eb5f6e177ea Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 23 Nov 2014 13:37:32 +0100 Subject: ASoC: wm8955: Cleanup manual bias level transitions Set the CODEC driver's suspend_bias_off flag rather than manually going to SND_SOC_BIAS_OFF in suspend and SND_SOC_BIAS_STANDBY in resume. This makes the code a bit shorter and cleaner. Also remove the regcache_mark_dirty() from the suspend handler since this is already done by the ASoC core. Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8955.c | 33 +-------------------------------- 1 file changed, 1 insertion(+), 32 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c index 09d91d9dc4ee..1173f7fef5a7 100644 --- a/sound/soc/codecs/wm8955.c +++ b/sound/soc/codecs/wm8955.c @@ -866,29 +866,6 @@ static struct snd_soc_dai_driver wm8955_dai = { .ops = &wm8955_dai_ops, }; -#ifdef CONFIG_PM -static int wm8955_suspend(struct snd_soc_codec *codec) -{ - struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec); - - wm8955_set_bias_level(codec, SND_SOC_BIAS_OFF); - - regcache_mark_dirty(wm8955->regmap); - - return 0; -} - -static int wm8955_resume(struct snd_soc_codec *codec) -{ - wm8955_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - return 0; -} -#else -#define wm8955_suspend NULL -#define wm8955_resume NULL -#endif - static int wm8955_probe(struct snd_soc_codec *codec) { struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec); @@ -964,18 +941,10 @@ err_enable: return ret; } -static int wm8955_remove(struct snd_soc_codec *codec) -{ - wm8955_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - static struct snd_soc_codec_driver soc_codec_dev_wm8955 = { .probe = wm8955_probe, - .remove = wm8955_remove, - .suspend = wm8955_suspend, - .resume = wm8955_resume, .set_bias_level = wm8955_set_bias_level, + .suspend_bias_off = true, .controls = wm8955_snd_controls, .num_controls = ARRAY_SIZE(wm8955_snd_controls), -- cgit v1.2.3 From 0a87a6e1c09c3b93d91bf65809e79cf6cf358785 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 23 Nov 2014 13:37:33 +0100 Subject: ASoC: wm8960: Cleanup manual bias level transitions Set the CODEC driver's suspend_bias_off flag rather than manually going to SND_SOC_BIAS_OFF in suspend and SND_SOC_BIAS_STANDBY in resume. This makes the code a bit shorter and cleaner. Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. The manual transition to SND_SOC_BIAS_STANDBY at the end of CODEC probe() can also be removed as the core will automatically do this after the CODEC has been probed. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8960.c | 31 +------------------------------ 1 file changed, 1 insertion(+), 30 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index 99d6457c87ba..bc8793cd1d72 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -943,22 +943,6 @@ static struct snd_soc_dai_driver wm8960_dai = { .symmetric_rates = 1, }; -static int wm8960_suspend(struct snd_soc_codec *codec) -{ - struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); - - wm8960->set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - -static int wm8960_resume(struct snd_soc_codec *codec) -{ - struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); - - wm8960->set_bias_level(codec, SND_SOC_BIAS_STANDBY); - return 0; -} - static int wm8960_probe(struct snd_soc_codec *codec) { struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); @@ -976,8 +960,6 @@ static int wm8960_probe(struct snd_soc_codec *codec) return ret; } - wm8960->set_bias_level(codec, SND_SOC_BIAS_STANDBY); - /* Latch the update bits */ snd_soc_update_bits(codec, WM8960_LINVOL, 0x100, 0x100); snd_soc_update_bits(codec, WM8960_RINVOL, 0x100, 0x100); @@ -997,21 +979,10 @@ static int wm8960_probe(struct snd_soc_codec *codec) return 0; } -/* power down chip */ -static int wm8960_remove(struct snd_soc_codec *codec) -{ - struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); - - wm8960->set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - static struct snd_soc_codec_driver soc_codec_dev_wm8960 = { .probe = wm8960_probe, - .remove = wm8960_remove, - .suspend = wm8960_suspend, - .resume = wm8960_resume, .set_bias_level = wm8960_set_bias_level, + .suspend_bias_off = true, }; static const struct regmap_config wm8960_regmap = { -- cgit v1.2.3 From 7bea32c5b2493044d31a2116328c71c7048de0e3 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 23 Nov 2014 13:37:34 +0100 Subject: ASoC: wm8961: Cleanup manual bias level transitions Set the CODEC driver's suspend_bias_off flag rather than manually going to SND_SOC_BIAS_OFF in suspend and SND_SOC_BIAS_STANDBY in resume. This makes the code a bit shorter and cleaner. Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. The manual transition to SND_SOC_BIAS_STANDBY at the end of CODEC probe() can also be removed as the core will automatically do this after the CODEC has been probed. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8961.c | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c index e077bb2f0740..eeffd05384b4 100644 --- a/sound/soc/codecs/wm8961.c +++ b/sound/soc/codecs/wm8961.c @@ -870,44 +870,26 @@ static int wm8961_probe(struct snd_soc_codec *codec) reg &= ~WM8961_MANUAL_MODE; snd_soc_write(codec, WM8961_CLOCKING_3, reg); - wm8961_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - return 0; -} - -static int wm8961_remove(struct snd_soc_codec *codec) -{ - wm8961_set_bias_level(codec, SND_SOC_BIAS_OFF); return 0; } #ifdef CONFIG_PM -static int wm8961_suspend(struct snd_soc_codec *codec) -{ - wm8961_set_bias_level(codec, SND_SOC_BIAS_OFF); - - return 0; -} static int wm8961_resume(struct snd_soc_codec *codec) { snd_soc_cache_sync(codec); - wm8961_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - return 0; } #else -#define wm8961_suspend NULL #define wm8961_resume NULL #endif static struct snd_soc_codec_driver soc_codec_dev_wm8961 = { .probe = wm8961_probe, - .remove = wm8961_remove, - .suspend = wm8961_suspend, .resume = wm8961_resume, .set_bias_level = wm8961_set_bias_level, + .suspend_bias_off = true, .controls = wm8961_snd_controls, .num_controls = ARRAY_SIZE(wm8961_snd_controls), -- cgit v1.2.3 From 387fe80fb13ed9f5f3741a661f96e409a2c959b5 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 23 Nov 2014 13:37:37 +0100 Subject: ASoC: wm8983: Cleanup manual bias level transitions Set the CODEC driver's suspend_bias_off flag rather than manually going to SND_SOC_BIAS_OFF in suspend and SND_SOC_BIAS_STANDBY in resume. This makes the code a bit shorter and cleaner. Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/wm8983.c | 27 +-------------------------- 1 file changed, 1 insertion(+), 26 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm8983.c b/sound/soc/codecs/wm8983.c index ac5defda8824..5d1cf08a72b8 100644 --- a/sound/soc/codecs/wm8983.c +++ b/sound/soc/codecs/wm8983.c @@ -967,29 +967,6 @@ static int wm8983_set_bias_level(struct snd_soc_codec *codec, return 0; } -#ifdef CONFIG_PM -static int wm8983_suspend(struct snd_soc_codec *codec) -{ - wm8983_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - -static int wm8983_resume(struct snd_soc_codec *codec) -{ - wm8983_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - return 0; -} -#else -#define wm8983_suspend NULL -#define wm8983_resume NULL -#endif - -static int wm8983_remove(struct snd_soc_codec *codec) -{ - wm8983_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - static int wm8983_probe(struct snd_soc_codec *codec) { int ret; @@ -1055,10 +1032,8 @@ static struct snd_soc_dai_driver wm8983_dai = { static struct snd_soc_codec_driver soc_codec_dev_wm8983 = { .probe = wm8983_probe, - .remove = wm8983_remove, - .suspend = wm8983_suspend, - .resume = wm8983_resume, .set_bias_level = wm8983_set_bias_level, + .suspend_bias_off = true, .controls = wm8983_snd_controls, .num_controls = ARRAY_SIZE(wm8983_snd_controls), .dapm_widgets = wm8983_dapm_widgets, -- cgit v1.2.3 From d02486fd42a3295edbec4db8f7f81c1432fa60a4 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 23 Nov 2014 13:37:36 +0100 Subject: ASoC: wm8978: Cleanup manual bias level transitions Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. The manual transition to SND_SOC_BIAS_STANDBY at the end of CODEC probe() can also be removed as the core will automatically do this after the CODEC has been probed. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8978.c | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c index ee2ba574952b..cf7032911721 100644 --- a/sound/soc/codecs/wm8978.c +++ b/sound/soc/codecs/wm8978.c @@ -991,21 +991,11 @@ static int wm8978_probe(struct snd_soc_codec *codec) for (i = 0; i < ARRAY_SIZE(update_reg); i++) snd_soc_update_bits(codec, update_reg[i], 0x100, 0x100); - wm8978_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - return 0; -} - -/* power down chip */ -static int wm8978_remove(struct snd_soc_codec *codec) -{ - wm8978_set_bias_level(codec, SND_SOC_BIAS_OFF); return 0; } static struct snd_soc_codec_driver soc_codec_dev_wm8978 = { .probe = wm8978_probe, - .remove = wm8978_remove, .suspend = wm8978_suspend, .resume = wm8978_resume, .set_bias_level = wm8978_set_bias_level, -- cgit v1.2.3 From ed1358f508e1ebcb01e1e545c5330599098b7687 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 23 Nov 2014 13:37:35 +0100 Subject: ASoC: wm8974: Cleanup manual bias level transitions Set the CODEC driver's suspend_bias_off flag rather than manually going to SND_SOC_BIAS_OFF in suspend and SND_SOC_BIAS_STANDBY in resume. This makes the code a bit shorter and cleaner. Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. The manual transition to SND_SOC_BIAS_STANDBY at the end of CODEC probe() can also be removed as the core will automatically do this after the CODEC has been probed. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8974.c | 25 +------------------------ 1 file changed, 1 insertion(+), 24 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c index 682e9eda1019..ff0e4646b934 100644 --- a/sound/soc/codecs/wm8974.c +++ b/sound/soc/codecs/wm8974.c @@ -568,18 +568,6 @@ static struct snd_soc_dai_driver wm8974_dai = { .symmetric_rates = 1, }; -static int wm8974_suspend(struct snd_soc_codec *codec) -{ - wm8974_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - -static int wm8974_resume(struct snd_soc_codec *codec) -{ - wm8974_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - return 0; -} - static const struct regmap_config wm8974_regmap = { .reg_bits = 7, .val_bits = 9, @@ -599,24 +587,13 @@ static int wm8974_probe(struct snd_soc_codec *codec) return ret; } - wm8974_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - return ret; -} - -/* power down chip */ -static int wm8974_remove(struct snd_soc_codec *codec) -{ - wm8974_set_bias_level(codec, SND_SOC_BIAS_OFF); return 0; } static struct snd_soc_codec_driver soc_codec_dev_wm8974 = { .probe = wm8974_probe, - .remove = wm8974_remove, - .suspend = wm8974_suspend, - .resume = wm8974_resume, .set_bias_level = wm8974_set_bias_level, + .suspend_bias_off = true, .controls = wm8974_snd_controls, .num_controls = ARRAY_SIZE(wm8974_snd_controls), -- cgit v1.2.3 From a5dde8c42ef6b3cb47c69905ee51520e18ac6515 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 23 Nov 2014 13:37:38 +0100 Subject: ASoC: wm8985: Cleanup manual bias level transitions Set the CODEC driver's suspend_bias_off flag rather than manually going to SND_SOC_BIAS_OFF in suspend and SND_SOC_BIAS_STANDBY in resume. This makes the code a bit shorter and cleaner. Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. The manual transition to SND_SOC_BIAS_STANDBY at the end of CODEC probe() can also be removed as the core will automatically do this after the CODEC has been probed. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8985.c | 28 +--------------------------- 1 file changed, 1 insertion(+), 27 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm8985.c b/sound/soc/codecs/wm8985.c index ee380190399f..0b3b54c9971d 100644 --- a/sound/soc/codecs/wm8985.c +++ b/sound/soc/codecs/wm8985.c @@ -961,29 +961,6 @@ static int wm8985_set_bias_level(struct snd_soc_codec *codec, return 0; } -#ifdef CONFIG_PM -static int wm8985_suspend(struct snd_soc_codec *codec) -{ - wm8985_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - -static int wm8985_resume(struct snd_soc_codec *codec) -{ - wm8985_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - return 0; -} -#else -#define wm8985_suspend NULL -#define wm8985_resume NULL -#endif - -static int wm8985_remove(struct snd_soc_codec *codec) -{ - wm8985_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - static int wm8985_probe(struct snd_soc_codec *codec) { size_t i; @@ -1023,7 +1000,6 @@ static int wm8985_probe(struct snd_soc_codec *codec) snd_soc_update_bits(codec, WM8985_BIAS_CTRL, WM8985_BIASCUT, WM8985_BIASCUT); - wm8985_set_bias_level(codec, SND_SOC_BIAS_STANDBY); return 0; err_reg_enable: @@ -1064,10 +1040,8 @@ static struct snd_soc_dai_driver wm8985_dai = { static struct snd_soc_codec_driver soc_codec_dev_wm8985 = { .probe = wm8985_probe, - .remove = wm8985_remove, - .suspend = wm8985_suspend, - .resume = wm8985_resume, .set_bias_level = wm8985_set_bias_level, + .suspend_bias_off = true, .controls = wm8985_snd_controls, .num_controls = ARRAY_SIZE(wm8985_snd_controls), -- cgit v1.2.3 From 1f07b8de451f5f4f6a268a95a34183e528cda711 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 23 Nov 2014 13:37:39 +0100 Subject: ASoC: wm8988: Cleanup manual bias level transitions Set the CODEC driver's suspend_bias_off flag rather than manually going to SND_SOC_BIAS_OFF in suspend and SND_SOC_BIAS_STANDBY in resume. This makes the code a bit shorter and cleaner. Also remove the regcache_mark_dirty() from the suspend handler since it is already called by the ASoC core. Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. The manual transition to SND_SOC_BIAS_STANDBY at the end of CODEC probe() can also be removed as the core will automatically do this after the CODEC has been probed. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/wm8988.c | 27 +-------------------------- 1 file changed, 1 insertion(+), 26 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c index a5130d965146..e418199155a8 100644 --- a/sound/soc/codecs/wm8988.c +++ b/sound/soc/codecs/wm8988.c @@ -793,21 +793,6 @@ static struct snd_soc_dai_driver wm8988_dai = { .symmetric_rates = 1, }; -static int wm8988_suspend(struct snd_soc_codec *codec) -{ - struct wm8988_priv *wm8988 = snd_soc_codec_get_drvdata(codec); - - wm8988_set_bias_level(codec, SND_SOC_BIAS_OFF); - regcache_mark_dirty(wm8988->regmap); - return 0; -} - -static int wm8988_resume(struct snd_soc_codec *codec) -{ - wm8988_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - return 0; -} - static int wm8988_probe(struct snd_soc_codec *codec) { int ret = 0; @@ -825,23 +810,13 @@ static int wm8988_probe(struct snd_soc_codec *codec) snd_soc_update_bits(codec, WM8988_ROUT2V, 0x0100, 0x0100); snd_soc_update_bits(codec, WM8988_RINVOL, 0x0100, 0x0100); - wm8988_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - return 0; -} - -static int wm8988_remove(struct snd_soc_codec *codec) -{ - wm8988_set_bias_level(codec, SND_SOC_BIAS_OFF); return 0; } static struct snd_soc_codec_driver soc_codec_dev_wm8988 = { .probe = wm8988_probe, - .remove = wm8988_remove, - .suspend = wm8988_suspend, - .resume = wm8988_resume, .set_bias_level = wm8988_set_bias_level, + .suspend_bias_off = true, .controls = wm8988_snd_controls, .num_controls = ARRAY_SIZE(wm8988_snd_controls), -- cgit v1.2.3 From 955efc8f50eb11d1c85daca6db7943c63dc5c2e7 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 23 Nov 2014 13:37:40 +0100 Subject: ASoC: wm8990: Cleanup manual bias level transitions Set the CODEC driver's suspend_bias_off flag rather than manually going to SND_SOC_BIAS_OFF in suspend and SND_SOC_BIAS_STANDBY in resume. This makes the code a bit shorter and cleaner. Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8990.c | 24 ++---------------------- 1 file changed, 2 insertions(+), 22 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index 03e43e3f395e..8a584229310a 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c @@ -1271,18 +1271,6 @@ static struct snd_soc_dai_driver wm8990_dai = { .ops = &wm8990_dai_ops, }; -static int wm8990_suspend(struct snd_soc_codec *codec) -{ - wm8990_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - -static int wm8990_resume(struct snd_soc_codec *codec) -{ - wm8990_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - return 0; -} - /* * initialise the WM8990 driver * register the mixer and dsp interfaces with the kernel @@ -1309,19 +1297,11 @@ static int wm8990_probe(struct snd_soc_codec *codec) return 0; } -/* power down chip */ -static int wm8990_remove(struct snd_soc_codec *codec) -{ - wm8990_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - static struct snd_soc_codec_driver soc_codec_dev_wm8990 = { .probe = wm8990_probe, - .remove = wm8990_remove, - .suspend = wm8990_suspend, - .resume = wm8990_resume, .set_bias_level = wm8990_set_bias_level, + .suspend_bias_off = true, + .controls = wm8990_snd_controls, .num_controls = ARRAY_SIZE(wm8990_snd_controls), .dapm_widgets = wm8990_dapm_widgets, -- cgit v1.2.3 From 497b900f83c56d513794ccf56b7a87c50a34a454 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 23 Nov 2014 13:37:41 +0100 Subject: ASoC: wm8991: Cleanup manual bias level transitions Set the CODEC driver's suspend_bias_off flag rather than manually going to SND_SOC_BIAS_OFF in suspend and SND_SOC_BIAS_STANDBY in resume. This makes the code a bit shorter and cleaner. Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. The manual transition to SND_SOC_BIAS_STANDBY at the end of CODEC probe() can also be removed as the core will automatically do this after the CODEC has been probed. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8991.c | 32 ++------------------------------ 1 file changed, 2 insertions(+), 30 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm8991.c b/sound/soc/codecs/wm8991.c index d0be89731cdb..b0ac2c3e31b9 100644 --- a/sound/soc/codecs/wm8991.c +++ b/sound/soc/codecs/wm8991.c @@ -1227,32 +1227,6 @@ static int wm8991_set_bias_level(struct snd_soc_codec *codec, return 0; } -static int wm8991_suspend(struct snd_soc_codec *codec) -{ - wm8991_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - -static int wm8991_resume(struct snd_soc_codec *codec) -{ - wm8991_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - return 0; -} - -/* power down chip */ -static int wm8991_remove(struct snd_soc_codec *codec) -{ - wm8991_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - -static int wm8991_probe(struct snd_soc_codec *codec) -{ - wm8991_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - return 0; -} - #define WM8991_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ SNDRV_PCM_FMTBIT_S24_LE) @@ -1293,11 +1267,9 @@ static struct snd_soc_dai_driver wm8991_dai = { }; static struct snd_soc_codec_driver soc_codec_dev_wm8991 = { - .probe = wm8991_probe, - .remove = wm8991_remove, - .suspend = wm8991_suspend, - .resume = wm8991_resume, .set_bias_level = wm8991_set_bias_level, + .suspend_bias_off = true, + .controls = wm8991_snd_controls, .num_controls = ARRAY_SIZE(wm8991_snd_controls), .dapm_widgets = wm8991_dapm_widgets, -- cgit v1.2.3 From 77d05e7f81da95eb2b6c7ae24ae0fb3272c49282 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 23 Nov 2014 13:37:42 +0100 Subject: ASoC: wm8993: Cleanup manual bias level transitions Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. The manual transition to SND_SOC_BIAS_STANDBY at the end of CODEC probe() can also be removed as the core will automatically do this after the CODEC has been probed. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8993.c | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c index 93b14eda355a..53c6fe359496 100644 --- a/sound/soc/codecs/wm8993.c +++ b/sound/soc/codecs/wm8993.c @@ -1486,7 +1486,6 @@ static int wm8993_probe(struct snd_soc_codec *codec) { struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec); struct snd_soc_dapm_context *dapm = &codec->dapm; - int ret; wm8993->hubs_data.hp_startup_mode = 1; wm8993->hubs_data.dcs_codes_l = -2; @@ -1518,10 +1517,6 @@ static int wm8993_probe(struct snd_soc_codec *codec) wm8993->pdata.micbias1_lvl, wm8993->pdata.micbias2_lvl); - ret = wm8993_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - if (ret != 0) - return ret; - snd_soc_add_codec_controls(codec, wm8993_snd_controls, ARRAY_SIZE(wm8993_snd_controls)); if (wm8993->pdata.num_retune_configs != 0) { @@ -1550,12 +1545,6 @@ static int wm8993_probe(struct snd_soc_codec *codec) } -static int wm8993_remove(struct snd_soc_codec *codec) -{ - wm8993_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - #ifdef CONFIG_PM static int wm8993_suspend(struct snd_soc_codec *codec) { @@ -1629,7 +1618,6 @@ static const struct regmap_config wm8993_regmap = { static struct snd_soc_codec_driver soc_codec_dev_wm8993 = { .probe = wm8993_probe, - .remove = wm8993_remove, .suspend = wm8993_suspend, .resume = wm8993_resume, .set_bias_level = wm8993_set_bias_level, -- cgit v1.2.3 From 49d9ac383cddc3e8d4cae8bc7a8f4da9dc071121 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 23 Nov 2014 13:37:43 +0100 Subject: ASoC: wm8994: Cleanup manual bias level transitions Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8994.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index 1fcb9f3f3097..c3a2e751513f 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -4391,8 +4391,6 @@ static int wm8994_codec_remove(struct snd_soc_codec *codec) struct wm8994 *control = wm8994->wm8994; int i; - wm8994_set_bias_level(codec, SND_SOC_BIAS_OFF); - for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++) wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_FLL1_LOCK + i, &wm8994->fll_locked[i]); -- cgit v1.2.3 From aee9ffabec81d96d68d8537ccc6fedfbb0e6c468 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 23 Nov 2014 13:37:44 +0100 Subject: ASoC: wm8995: Cleanup manual bias level transitions Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. The manual transition to SND_SOC_BIAS_STANDBY at the end of CODEC probe() can also be removed as the core will automatically do this after the CODEC has been probed. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8995.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c index e40c8a662183..c280f0a3a424 100644 --- a/sound/soc/codecs/wm8995.c +++ b/sound/soc/codecs/wm8995.c @@ -2004,7 +2004,6 @@ static int wm8995_remove(struct snd_soc_codec *codec) int i; wm8995 = snd_soc_codec_get_drvdata(codec); - wm8995_set_bias_level(codec, SND_SOC_BIAS_OFF); for (i = 0; i < ARRAY_SIZE(wm8995->supplies); ++i) regulator_unregister_notifier(wm8995->supplies[i].consumer, @@ -2078,8 +2077,6 @@ static int wm8995_probe(struct snd_soc_codec *codec) goto err_reg_enable; } - wm8995_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - /* Latch volume updates (right only; we always do left then right). */ snd_soc_update_bits(codec, WM8995_AIF1_DAC1_RIGHT_VOLUME, WM8995_AIF1DAC1_VU_MASK, WM8995_AIF1DAC1_VU); -- cgit v1.2.3 From 68201d6998a0d7701f7c3009130c5d8cd6ad7562 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 23 Nov 2014 13:37:45 +0100 Subject: ASoC: wm9081: Cleanup manual bias level transitions Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm9081.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c index 0cdc9e2184ab..b1d946facd57 100644 --- a/sound/soc/codecs/wm9081.c +++ b/sound/soc/codecs/wm9081.c @@ -1277,15 +1277,8 @@ static int wm9081_probe(struct snd_soc_codec *codec) return 0; } -static int wm9081_remove(struct snd_soc_codec *codec) -{ - wm9081_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - static struct snd_soc_codec_driver soc_codec_dev_wm9081 = { .probe = wm9081_probe, - .remove = wm9081_remove, .set_sysclk = wm9081_set_sysclk, .set_bias_level = wm9081_set_bias_level, -- cgit v1.2.3 From a70cf928ca396447416422c2ec1697a530534ac9 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 23 Nov 2014 13:37:46 +0100 Subject: ASoC: wm9090: Cleanup manual bias level transitions Set the CODEC driver's suspend_bias_off flag rather than manually going to SND_SOC_BIAS_OFF in suspend and SND_SOC_BIAS_STANDBY in resume. This makes the code a bit shorter and cleaner. Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. The manual transition to SND_SOC_BIAS_STANDBY at the end of CODEC probe() can also be removed as the core will automatically do this after the CODEC has been probed. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm9090.c | 32 +------------------------------- 1 file changed, 1 insertion(+), 31 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm9090.c b/sound/soc/codecs/wm9090.c index a13f0725611a..6ffe8dc4f3fa 100644 --- a/sound/soc/codecs/wm9090.c +++ b/sound/soc/codecs/wm9090.c @@ -550,45 +550,15 @@ static int wm9090_probe(struct snd_soc_codec *codec) snd_soc_update_bits(codec, WM9090_CLOCKING_1, WM9090_TOCLK_ENA, WM9090_TOCLK_ENA); - wm9090_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - wm9090_add_controls(codec); return 0; } -#ifdef CONFIG_PM -static int wm9090_suspend(struct snd_soc_codec *codec) -{ - wm9090_set_bias_level(codec, SND_SOC_BIAS_OFF); - - return 0; -} - -static int wm9090_resume(struct snd_soc_codec *codec) -{ - wm9090_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - return 0; -} -#else -#define wm9090_suspend NULL -#define wm9090_resume NULL -#endif - -static int wm9090_remove(struct snd_soc_codec *codec) -{ - wm9090_set_bias_level(codec, SND_SOC_BIAS_OFF); - - return 0; -} - static struct snd_soc_codec_driver soc_codec_dev_wm9090 = { .probe = wm9090_probe, - .remove = wm9090_remove, - .suspend = wm9090_suspend, - .resume = wm9090_resume, .set_bias_level = wm9090_set_bias_level, + .suspend_bias_off = true, }; static const struct regmap_config wm9090_regmap = { -- cgit v1.2.3 From ab492b86b89be6c98bdca71cfc97b411ca42e140 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 23 Nov 2014 13:37:47 +0100 Subject: ASoC: wm9712: Cleanup manual bias level transitions Set the CODEC driver's suspend_bias_off flag rather than manually going to SND_SOC_BIAS_OFF in suspend. This makes the code a bit shorter and cleaner. The manual transition to SND_SOC_BIAS_STANDBY at the end of CODEC probe() can also be removed as the core will automatically do this after the CODEC has been probed. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm9712.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index f3aab6e1d92a..30f4b1773070 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -599,12 +599,6 @@ err: return -EIO; } -static int wm9712_soc_suspend(struct snd_soc_codec *codec) -{ - wm9712_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - static int wm9712_soc_resume(struct snd_soc_codec *codec) { int i, ret; @@ -646,8 +640,6 @@ static int wm9712_soc_probe(struct snd_soc_codec *codec) /* set alc mux to none */ ac97_write(codec, AC97_VIDEO, ac97_read(codec, AC97_VIDEO) | 0x3000); - wm9712_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - return 0; reset_err: @@ -664,11 +656,11 @@ static int wm9712_soc_remove(struct snd_soc_codec *codec) static struct snd_soc_codec_driver soc_codec_dev_wm9712 = { .probe = wm9712_soc_probe, .remove = wm9712_soc_remove, - .suspend = wm9712_soc_suspend, .resume = wm9712_soc_resume, .read = ac97_read, .write = ac97_write, .set_bias_level = wm9712_set_bias_level, + .suspend_bias_off = true, .reg_cache_size = ARRAY_SIZE(wm9712_reg), .reg_word_size = sizeof(u16), .reg_cache_step = 2, -- cgit v1.2.3 From 0cb6b1419ec864996835991a62788c588693f27d Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 23 Nov 2014 13:37:48 +0100 Subject: ASoC: wm9713: Cleanup manual bias level transitions The manual transition to SND_SOC_BIAS_STANDBY at the end of CODEC probe() can also be removed as the core will automatically do this after the CODEC has been probed. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm9713.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index ac13fc8f5c70..e977b13bacfa 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -1203,8 +1203,6 @@ static int wm9713_soc_probe(struct snd_soc_codec *codec) if (ret < 0) goto reset_err; - wm9713_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - /* unmute the adc - move to kcontrol */ reg = ac97_read(codec, AC97_CD) & 0x7fff; ac97_write(codec, AC97_CD, reg); -- cgit v1.2.3 From bbc686b34650b0f54affe9d9a637ccbe02b03760 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Mon, 24 Nov 2014 20:37:12 +0200 Subject: ASoC: tlv320aic31xx: Fix off by one error in the loop stucture. Fix off by one read beyond the end of a table. Reported-by: David Binderman Signed-off-by: Jyri Sarha Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- sound/soc/codecs/tlv320aic31xx.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index 145fe5b253d4..93de5dd0a7b9 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -911,12 +911,13 @@ static int aic31xx_set_dai_sysclk(struct snd_soc_dai *codec_dai, } aic31xx->p_div = i; - for (i = 0; aic31xx_divs[i].mclk_p != freq/aic31xx->p_div; i++) { - if (i == ARRAY_SIZE(aic31xx_divs)) { - dev_err(aic31xx->dev, "%s: Unsupported frequency %d\n", - __func__, freq); - return -EINVAL; - } + for (i = 0; i < ARRAY_SIZE(aic31xx_divs) && + aic31xx_divs[i].mclk_p != freq/aic31xx->p_div; i++) + ; + if (i == ARRAY_SIZE(aic31xx_divs)) { + dev_err(aic31xx->dev, "%s: Unsupported frequency %d\n", + __func__, freq); + return -EINVAL; } /* set clock on MCLK, BCLK, or GPIO1 as PLL input */ -- cgit v1.2.3 From 141f87d4d6ab36bfcd4c5683cf90abf83b306d90 Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Tue, 25 Nov 2014 04:49:44 +0800 Subject: ASoC: sigmadsp: fix simple_return.cocci warnings sound/soc/codecs/sigmadsp.c:656:1-4: WARNING: end returns can be simpified and declaration on line 636 can be dropped Simplify a trivial if-return sequence. Possibly combine with a preceding function call. Generated by: scripts/coccinelle/misc/simple_return.cocci Signed-off-by: Fengguang Wu Signed-off-by: Mark Brown --- sound/soc/codecs/sigmadsp.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/sigmadsp.c b/sound/soc/codecs/sigmadsp.c index 6abefd27b86c..34fdc402c1cc 100644 --- a/sound/soc/codecs/sigmadsp.c +++ b/sound/soc/codecs/sigmadsp.c @@ -633,7 +633,6 @@ static int sigmadsp_alloc_control(struct sigmadsp *sigmadsp, { struct snd_kcontrol_new template; struct snd_kcontrol *kcontrol; - int ret; memset(&template, 0, sizeof(template)); template.iface = SNDRV_CTL_ELEM_IFACE_MIXER; @@ -653,11 +652,7 @@ static int sigmadsp_alloc_control(struct sigmadsp *sigmadsp, kcontrol->private_free = sigmadsp_control_free; ctrl->kcontrol = kcontrol; - ret = snd_ctl_add(sigmadsp->component->card->snd_card, kcontrol); - if (ret) - return ret; - - return 0; + return snd_ctl_add(sigmadsp->component->card->snd_card, kcontrol); } static void sigmadsp_activate_ctrl(struct sigmadsp *sigmadsp, -- cgit v1.2.3 From 2d4e2d020516632288e8c8d1f8be2f3042d6b8de Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Tue, 18 Nov 2014 16:50:18 +0800 Subject: ASoC: rt5645: multiple JD mode support There are 3 JD modes in RT5645. This patch configure register values according to platform data. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- include/sound/rt5645.h | 1 + sound/soc/codecs/rt5645.c | 35 ++++++++++++++++++++++++++++++++++- sound/soc/codecs/rt5645.h | 7 +++++++ 3 files changed, 42 insertions(+), 1 deletion(-) (limited to 'sound/soc/codecs') diff --git a/include/sound/rt5645.h b/include/sound/rt5645.h index 937f421bc66b..120d9610054e 100644 --- a/include/sound/rt5645.h +++ b/include/sound/rt5645.h @@ -26,6 +26,7 @@ struct rt5645_platform_data { /* true if codec's jd function is used */ bool en_jd_func; + unsigned int jd_mode; }; #endif diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index ef88b506a017..6e9cd8e743a7 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -2239,7 +2239,8 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec) snd_soc_dapm_disable_pin(&codec->dapm, "micbias1"); snd_soc_dapm_disable_pin(&codec->dapm, "micbias2"); - snd_soc_dapm_disable_pin(&codec->dapm, "LDO2"); + if (rt5645->pdata.jd_mode == 0) + snd_soc_dapm_disable_pin(&codec->dapm, "LDO2"); snd_soc_dapm_disable_pin(&codec->dapm, "Mic Det Power"); snd_soc_dapm_sync(&codec->dapm); } @@ -2543,6 +2544,38 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, RT5645_IRQ_CLK_INT, RT5645_IRQ_CLK_INT); } + if (rt5645->pdata.jd_mode) { + regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2, + RT5645_IRQ_JD_1_1_EN, RT5645_IRQ_JD_1_1_EN); + regmap_update_bits(rt5645->regmap, RT5645_GEN_CTRL3, + RT5645_JD_PSV_MODE, RT5645_JD_PSV_MODE); + regmap_update_bits(rt5645->regmap, RT5645_HPO_MIXER, + RT5645_IRQ_PSV_MODE, RT5645_IRQ_PSV_MODE); + regmap_update_bits(rt5645->regmap, RT5645_MICBIAS, + RT5645_MIC2_OVCD_EN, RT5645_MIC2_OVCD_EN); + regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1, + RT5645_GP1_PIN_IRQ, RT5645_GP1_PIN_IRQ); + switch (rt5645->pdata.jd_mode) { + case 1: + regmap_update_bits(rt5645->regmap, RT5645_A_JD_CTRL1, + RT5645_JD1_MODE_MASK, + RT5645_JD1_MODE_0); + break; + case 2: + regmap_update_bits(rt5645->regmap, RT5645_A_JD_CTRL1, + RT5645_JD1_MODE_MASK, + RT5645_JD1_MODE_1); + break; + case 3: + regmap_update_bits(rt5645->regmap, RT5645_A_JD_CTRL1, + RT5645_JD1_MODE_MASK, + RT5645_JD1_MODE_2); + break; + default: + break; + } + } + if (rt5645->i2c->irq) { ret = request_threaded_irq(rt5645->i2c->irq, NULL, rt5645_irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING diff --git a/sound/soc/codecs/rt5645.h b/sound/soc/codecs/rt5645.h index c72220abdbc0..a815e36a2bdb 100644 --- a/sound/soc/codecs/rt5645.h +++ b/sound/soc/codecs/rt5645.h @@ -594,6 +594,7 @@ #define RT5645_M_DAC1_HM_SFT 14 #define RT5645_M_HPVOL_HM (0x1 << 13) #define RT5645_M_HPVOL_HM_SFT 13 +#define RT5645_IRQ_PSV_MODE (0x1 << 12) /* SPK Left Mixer Control (0x46) */ #define RT5645_G_RM_L_SM_L_MASK (0x3 << 14) @@ -1350,6 +1351,10 @@ #define RT5645_PWR_CLK25M_PU (0x1 << 4) #define RT5645_IRQ_CLK_MCLK (0x0 << 3) #define RT5645_IRQ_CLK_INT (0x1 << 3) +#define RT5645_JD1_MODE_MASK (0x3 << 0) +#define RT5645_JD1_MODE_0 (0x0 << 0) +#define RT5645_JD1_MODE_1 (0x1 << 0) +#define RT5645_JD1_MODE_2 (0x2 << 0) /* VAD Control 4 (0x9d) */ #define RT5645_VAD_SEL_MASK (0x3 << 8) @@ -1638,6 +1643,7 @@ #define RT5645_OT_P_SFT 10 #define RT5645_OT_P_NOR (0x0 << 10) #define RT5645_OT_P_INV (0x1 << 10) +#define RT5645_IRQ_JD_1_1_EN (0x1 << 9) /* IRQ Control 2 (0xbe) */ #define RT5645_IRQ_MB1_OC_MASK (0x1 << 15) @@ -2120,6 +2126,7 @@ enum { #define RT5645_RXDP2_SEL_SFT (3) /* General Control3 (0xfc) */ +#define RT5645_JD_PSV_MODE (0x1 << 12) #define RT5645_IRQ_CLK_GATE_CTRL (0x1 << 11) #define RT5645_MICINDET_MANU (0x1 << 7) -- cgit v1.2.3 From e50334d4e1c3bacfeb3bb1530f73a419d4ec6832 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 17 Nov 2014 15:27:21 +0800 Subject: ASoC: rt5670: check if asrc is useable To use ASRC, the sysclk should be faster than 384 times sample rate of I2S1. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5670.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 5e54ac957e47..3ddb34ef77d7 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -576,6 +576,18 @@ static int is_using_asrc(struct snd_soc_dapm_widget *source, } +static int can_use_asrc(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm); + struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); + + if (rt5670->sysclk > rt5670->lrck[RT5670_AIF1] * 384) + return 1; + + return 0; +} + /* Digital Mixer */ static const struct snd_kcontrol_new rt5670_sto1_adc_l_mix[] = { SOC_DAPM_SINGLE("ADC1 Switch", RT5670_STO1_ADC_MIXER, @@ -1639,8 +1651,8 @@ static const struct snd_soc_dapm_route rt5670_dapm_routes[] = { { "DAC Mono Right Filter", NULL, "DAC MONO R ASRC", is_using_asrc }, { "DAC Stereo1 Filter", NULL, "DAC STO ASRC", is_using_asrc }, - { "I2S1", NULL, "I2S1 ASRC" }, - { "I2S2", NULL, "I2S2 ASRC" }, + { "I2S1", NULL, "I2S1 ASRC", can_use_asrc}, + { "I2S2", NULL, "I2S2 ASRC", can_use_asrc}, { "DMIC1", NULL, "DMIC L1" }, { "DMIC1", NULL, "DMIC R1" }, -- cgit v1.2.3 From ff4541c3f48781f84e1cc162d73013aa32a09a41 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 17 Nov 2014 15:27:22 +0800 Subject: ASoC: rt5670: add DMIC ASRC support This patch will enable ASRC for DMIC if ASRC is useable. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5670.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 3ddb34ef77d7..8bf3a5686dd7 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -1294,6 +1294,14 @@ static const struct snd_soc_dapm_widget rt5670_dapm_widgets[] = { 9, 0, NULL, 0), SND_SOC_DAPM_SUPPLY_S("DAC MONO R ASRC", 1, RT5670_ASRC_1, 8, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DMIC STO1 ASRC", 1, RT5670_ASRC_1, + 7, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DMIC STO2 ASRC", 1, RT5670_ASRC_1, + 6, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DMIC MONO L ASRC", 1, RT5670_ASRC_1, + 5, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DMIC MONO R ASRC", 1, RT5670_ASRC_1, + 4, 0, NULL, 0), SND_SOC_DAPM_SUPPLY_S("ADC STO1 ASRC", 1, RT5670_ASRC_1, 3, 0, NULL, 0), SND_SOC_DAPM_SUPPLY_S("ADC STO2 ASRC", 1, RT5670_ASRC_1, @@ -1650,6 +1658,10 @@ static const struct snd_soc_dapm_route rt5670_dapm_routes[] = { { "DAC Mono Left Filter", NULL, "DAC MONO L ASRC", is_using_asrc }, { "DAC Mono Right Filter", NULL, "DAC MONO R ASRC", is_using_asrc }, { "DAC Stereo1 Filter", NULL, "DAC STO ASRC", is_using_asrc }, + { "Stereo1 DMIC Mux", NULL, "DMIC STO1 ASRC", can_use_asrc }, + { "Stereo2 DMIC Mux", NULL, "DMIC STO2 ASRC", can_use_asrc }, + { "Mono DMIC L Mux", NULL, "DMIC MONO L ASRC", can_use_asrc }, + { "Mono DMIC R Mux", NULL, "DMIC MONO R ASRC", can_use_asrc }, { "I2S1", NULL, "I2S1 ASRC", can_use_asrc}, { "I2S2", NULL, "I2S2 ASRC", can_use_asrc}, -- cgit v1.2.3 From 6fe17da00ba7046db2d3a952a930e127dcd7f06e Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Tue, 25 Nov 2014 09:51:41 +0800 Subject: ASoC: rt5677: Fix the issue that the regmap_range "rt5677_ranges" cannot be accessed After the patch "ASoC: rt5677: Use specific r/w function for DSP mode", the regmap_range "rt5677_ranges" was not registered in rt5677_regmap_physical, and it caused that the regmap_range "rt5677_ranges" cannot be accessed by the specific r/w function. The patch fixes this issue. Signed-off-by: Oder Chiou Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677.c | 37 ++++++++++++++++++++++++++++++------- sound/soc/codecs/rt5677.h | 2 +- 2 files changed, 31 insertions(+), 8 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index f2211f14ba41..133010dd9f34 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -4287,6 +4287,7 @@ static int rt5677_probe(struct snd_soc_codec *codec) } mutex_init(&rt5677->dsp_cmd_lock); + mutex_init(&rt5677->dsp_pri_lock); return 0; } @@ -4344,10 +4345,19 @@ static int rt5677_read(void *context, unsigned int reg, unsigned int *val) struct i2c_client *client = context; struct rt5677_priv *rt5677 = i2c_get_clientdata(client); - if (rt5677->is_dsp_mode) - rt5677_dsp_mode_i2c_read(rt5677, reg, val); - else + if (rt5677->is_dsp_mode) { + if (reg > 0xff) { + mutex_lock(&rt5677->dsp_pri_lock); + rt5677_dsp_mode_i2c_write(rt5677, RT5677_PRIV_INDEX, + reg & 0xff); + rt5677_dsp_mode_i2c_read(rt5677, RT5677_PRIV_DATA, val); + mutex_unlock(&rt5677->dsp_pri_lock); + } else { + rt5677_dsp_mode_i2c_read(rt5677, reg, val); + } + } else { regmap_read(rt5677->regmap_physical, reg, val); + } return 0; } @@ -4357,10 +4367,20 @@ static int rt5677_write(void *context, unsigned int reg, unsigned int val) struct i2c_client *client = context; struct rt5677_priv *rt5677 = i2c_get_clientdata(client); - if (rt5677->is_dsp_mode) - rt5677_dsp_mode_i2c_write(rt5677, reg, val); - else + if (rt5677->is_dsp_mode) { + if (reg > 0xff) { + mutex_lock(&rt5677->dsp_pri_lock); + rt5677_dsp_mode_i2c_write(rt5677, RT5677_PRIV_INDEX, + reg & 0xff); + rt5677_dsp_mode_i2c_write(rt5677, RT5677_PRIV_DATA, + val); + mutex_unlock(&rt5677->dsp_pri_lock); + } else { + rt5677_dsp_mode_i2c_write(rt5677, reg, val); + } + } else { regmap_write(rt5677->regmap_physical, reg, val); + } return 0; } @@ -4495,10 +4515,13 @@ static const struct regmap_config rt5677_regmap_physical = { .reg_bits = 8, .val_bits = 16, - .max_register = RT5677_VENDOR_ID2 + 1, + .max_register = RT5677_VENDOR_ID2 + 1 + (ARRAY_SIZE(rt5677_ranges) * + RT5677_PR_SPACING), .readable_reg = rt5677_readable_register, .cache_type = REGCACHE_NONE, + .ranges = rt5677_ranges, + .num_ranges = ARRAY_SIZE(rt5677_ranges), }; static const struct regmap_config rt5677_regmap = { diff --git a/sound/soc/codecs/rt5677.h b/sound/soc/codecs/rt5677.h index a02f64c23596..dbd9ffde50dc 100644 --- a/sound/soc/codecs/rt5677.h +++ b/sound/soc/codecs/rt5677.h @@ -1670,7 +1670,7 @@ struct rt5677_priv { struct rt5677_platform_data pdata; struct regmap *regmap, *regmap_physical; const struct firmware *fw1, *fw2; - struct mutex dsp_cmd_lock; + struct mutex dsp_cmd_lock, dsp_pri_lock; int sysclk; int sysclk_src; -- cgit v1.2.3 From 3ad5e861a715cbe932cd145d4612c11e5912a72f Mon Sep 17 00:00:00 2001 From: Zidan Wang Date: Thu, 27 Nov 2014 16:53:08 +0800 Subject: ASoC: wm8960: Move register initialisation to I2C driver probe() We must ensure that the clocking configuration is valid as rapidly as possible. And do software reset before the others registers updates, or the registers will be reset to the default state. Signed-off-by: Zidan Wang Signed-off-by: Mark Brown --- sound/soc/codecs/wm8960.c | 41 ++++++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 21 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index bc8793cd1d72..031a1ae71d94 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -128,7 +128,7 @@ struct wm8960_priv { struct wm8960_data pdata; }; -#define wm8960_reset(c) snd_soc_write(c, WM8960_RESET, 0) +#define wm8960_reset(c) regmap_write(c, WM8960_RESET, 0) /* enumerated controls */ static const char *wm8960_polarity[] = {"No Inversion", "Left Inverted", @@ -947,31 +947,12 @@ static int wm8960_probe(struct snd_soc_codec *codec) { struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); struct wm8960_data *pdata = &wm8960->pdata; - int ret; if (pdata->capless) wm8960->set_bias_level = wm8960_set_bias_level_capless; else wm8960->set_bias_level = wm8960_set_bias_level_out3; - ret = wm8960_reset(codec); - if (ret < 0) { - dev_err(codec->dev, "Failed to issue reset\n"); - return ret; - } - - /* Latch the update bits */ - snd_soc_update_bits(codec, WM8960_LINVOL, 0x100, 0x100); - snd_soc_update_bits(codec, WM8960_RINVOL, 0x100, 0x100); - snd_soc_update_bits(codec, WM8960_LADC, 0x100, 0x100); - snd_soc_update_bits(codec, WM8960_RADC, 0x100, 0x100); - snd_soc_update_bits(codec, WM8960_LDAC, 0x100, 0x100); - snd_soc_update_bits(codec, WM8960_RDAC, 0x100, 0x100); - snd_soc_update_bits(codec, WM8960_LOUT1, 0x100, 0x100); - snd_soc_update_bits(codec, WM8960_ROUT1, 0x100, 0x100); - snd_soc_update_bits(codec, WM8960_LOUT2, 0x100, 0x100); - snd_soc_update_bits(codec, WM8960_ROUT2, 0x100, 0x100); - snd_soc_add_codec_controls(codec, wm8960_snd_controls, ARRAY_SIZE(wm8960_snd_controls)); wm8960_add_widgets(codec); @@ -1030,7 +1011,13 @@ static int wm8960_i2c_probe(struct i2c_client *i2c, else if (i2c->dev.of_node) wm8960_set_pdata_from_of(i2c, &wm8960->pdata); - if (pdata && pdata->shared_lrclk) { + ret = wm8960_reset(wm8960->regmap); + if (ret != 0) { + dev_err(&i2c->dev, "Failed to issue reset\n"); + return ret; + } + + if (wm8960->pdata.shared_lrclk) { ret = regmap_update_bits(wm8960->regmap, WM8960_ADDCTL2, 0x4, 0x4); if (ret != 0) { @@ -1040,6 +1027,18 @@ static int wm8960_i2c_probe(struct i2c_client *i2c, } } + /* Latch the update bits */ + regmap_update_bits(wm8960->regmap, WM8960_LINVOL, 0x100, 0x100); + regmap_update_bits(wm8960->regmap, WM8960_RINVOL, 0x100, 0x100); + regmap_update_bits(wm8960->regmap, WM8960_LADC, 0x100, 0x100); + regmap_update_bits(wm8960->regmap, WM8960_RADC, 0x100, 0x100); + regmap_update_bits(wm8960->regmap, WM8960_LDAC, 0x100, 0x100); + regmap_update_bits(wm8960->regmap, WM8960_RDAC, 0x100, 0x100); + regmap_update_bits(wm8960->regmap, WM8960_LOUT1, 0x100, 0x100); + regmap_update_bits(wm8960->regmap, WM8960_ROUT1, 0x100, 0x100); + regmap_update_bits(wm8960->regmap, WM8960_LOUT2, 0x100, 0x100); + regmap_update_bits(wm8960->regmap, WM8960_ROUT2, 0x100, 0x100); + i2c_set_clientdata(i2c, wm8960); ret = snd_soc_register_codec(&i2c->dev, -- cgit v1.2.3 From d98123a76be53d570d72e04aac3e195a560ef149 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 27 Nov 2014 01:35:16 +0300 Subject: ASoC: sigmadsp: uninitialized variable in sigmadsp_activate_ctrl() The "changed" variable should be set to false at the start. Fixes: a35daac77a03 ('ASoC: sigmadsp: Add support for fw v2') Signed-off-by: Dan Carpenter Signed-off-by: Mark Brown Acked-by: Lars-Peter Clausen --- sound/soc/codecs/sigmadsp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/sigmadsp.c b/sound/soc/codecs/sigmadsp.c index 34fdc402c1cc..d53680ac78e4 100644 --- a/sound/soc/codecs/sigmadsp.c +++ b/sound/soc/codecs/sigmadsp.c @@ -661,7 +661,8 @@ static void sigmadsp_activate_ctrl(struct sigmadsp *sigmadsp, struct snd_card *card = sigmadsp->component->card->snd_card; struct snd_kcontrol_volatile *vd; struct snd_ctl_elem_id id; - bool active, changed; + bool active; + bool changed = false; active = sigmadsp_samplerate_valid(ctrl->samplerates, samplerate_mask); -- cgit v1.2.3 From 002fe7c831404d179266cfe0dad00a67333256f1 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 26 Nov 2014 20:57:50 +0100 Subject: ASoC: cq93vc: Remove unused state struct While two of the fields in the cq93vc driver state struct are initialized none of them are ever acutally read again. So remove the whole struct. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- include/linux/mfd/davinci_voicecodec.h | 7 ------- sound/soc/codecs/cq93vc.c | 8 -------- 2 files changed, 15 deletions(-) (limited to 'sound/soc/codecs') diff --git a/include/linux/mfd/davinci_voicecodec.h b/include/linux/mfd/davinci_voicecodec.h index cb01496bfa49..8e1cdbef3dad 100644 --- a/include/linux/mfd/davinci_voicecodec.h +++ b/include/linux/mfd/davinci_voicecodec.h @@ -99,12 +99,6 @@ struct davinci_vcif { dma_addr_t dma_rx_addr; }; -struct cq93vc { - struct platform_device *pdev; - struct snd_soc_codec *codec; - u32 sysclk; -}; - struct davinci_vc; struct davinci_vc { @@ -122,7 +116,6 @@ struct davinci_vc { /* Client devices */ struct davinci_vcif davinci_vcif; - struct cq93vc cq93vc; }; #endif diff --git a/sound/soc/codecs/cq93vc.c b/sound/soc/codecs/cq93vc.c index 537327c7f7f1..036a877746b9 100644 --- a/sound/soc/codecs/cq93vc.c +++ b/sound/soc/codecs/cq93vc.c @@ -62,14 +62,10 @@ static int cq93vc_mute(struct snd_soc_dai *dai, int mute) static int cq93vc_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id, unsigned int freq, int dir) { - struct snd_soc_codec *codec = codec_dai->codec; - struct davinci_vc *davinci_vc = codec->dev->platform_data; - switch (freq) { case 22579200: case 27000000: case 33868800: - davinci_vc->cq93vc.sysclk = freq; return 0; } @@ -135,10 +131,6 @@ static int cq93vc_resume(struct snd_soc_codec *codec) static int cq93vc_probe(struct snd_soc_codec *codec) { - struct davinci_vc *davinci_vc = codec->dev->platform_data; - - davinci_vc->cq93vc.codec = codec; - /* Off, with power on */ cq93vc_set_bias_level(codec, SND_SOC_BIAS_STANDBY); -- cgit v1.2.3 From 6200b75a8bbc16e434bf3d8ca54538ea678ccbd7 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 26 Nov 2014 20:57:51 +0100 Subject: ASoC: cq93vc: Cleanup manual bias level transitions Remove the manual transition back to SND_SOC_BIAS_STANDBY in resume. This is already be automatically handled by the ASoC core. Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. The manual transition to SND_SOC_BIAS_STANDBY at the end of CODEC probe() can also be removed as the core will automatically do this after the CODEC has been probed. While we are at it also remove the unused codec field from the cq93vc struct so the whole probe function can be removed. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/cq93vc.c | 25 ------------------------- 1 file changed, 25 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/cq93vc.c b/sound/soc/codecs/cq93vc.c index 036a877746b9..8d638e8aa8eb 100644 --- a/sound/soc/codecs/cq93vc.c +++ b/sound/soc/codecs/cq93vc.c @@ -122,28 +122,6 @@ static struct snd_soc_dai_driver cq93vc_dai = { .ops = &cq93vc_dai_ops, }; -static int cq93vc_resume(struct snd_soc_codec *codec) -{ - cq93vc_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - return 0; -} - -static int cq93vc_probe(struct snd_soc_codec *codec) -{ - /* Off, with power on */ - cq93vc_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - return 0; -} - -static int cq93vc_remove(struct snd_soc_codec *codec) -{ - cq93vc_set_bias_level(codec, SND_SOC_BIAS_OFF); - - return 0; -} - static struct regmap *cq93vc_get_regmap(struct device *dev) { struct davinci_vc *davinci_vc = dev->platform_data; @@ -153,9 +131,6 @@ static struct regmap *cq93vc_get_regmap(struct device *dev) static struct snd_soc_codec_driver soc_codec_dev_cq93vc = { .set_bias_level = cq93vc_set_bias_level, - .probe = cq93vc_probe, - .remove = cq93vc_remove, - .resume = cq93vc_resume, .get_regmap = cq93vc_get_regmap, .controls = cq93vc_snd_controls, .num_controls = ARRAY_SIZE(cq93vc_snd_controls), -- cgit v1.2.3 From 68d27bc63c4f331c912dfb92168f5fe4753c61c9 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 26 Nov 2014 20:57:52 +0100 Subject: ASoC: lm49453: Cleanup manual bias level transitions Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/lm49453.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/lm49453.c b/sound/soc/codecs/lm49453.c index c1ae5764983f..c4dfde9bdf1c 100644 --- a/sound/soc/codecs/lm49453.c +++ b/sound/soc/codecs/lm49453.c @@ -1395,15 +1395,7 @@ static struct snd_soc_dai_driver lm49453_dai[] = { }, }; -/* power down chip */ -static int lm49453_remove(struct snd_soc_codec *codec) -{ - lm49453_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - static struct snd_soc_codec_driver soc_codec_dev_lm49453 = { - .remove = lm49453_remove, .set_bias_level = lm49453_set_bias_level, .controls = lm49453_snd_controls, .num_controls = ARRAY_SIZE(lm49453_snd_controls), -- cgit v1.2.3 From 0eef4ed5970a736bf2449b389fb44f6fe3635765 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 26 Nov 2014 20:57:53 +0100 Subject: ASoC: sn95031: Cleanup bias level transitions Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/sn95031.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/sn95031.c b/sound/soc/codecs/sn95031.c index 6167c5996d8e..31d97cd5e59b 100644 --- a/sound/soc/codecs/sn95031.c +++ b/sound/soc/codecs/sn95031.c @@ -870,17 +870,8 @@ static int sn95031_codec_probe(struct snd_soc_codec *codec) return 0; } -static int sn95031_codec_remove(struct snd_soc_codec *codec) -{ - pr_debug("codec_remove called\n"); - sn95031_set_vaud_bias(codec, SND_SOC_BIAS_OFF); - - return 0; -} - static struct snd_soc_codec_driver sn95031_codec = { .probe = sn95031_codec_probe, - .remove = sn95031_codec_remove, .set_bias_level = sn95031_set_vaud_bias, .idle_bias_off = true, -- cgit v1.2.3 From aabb87f00304764dffe097e3b65f6a1862c2c2b5 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 26 Nov 2014 20:57:54 +0100 Subject: ASoC: tlv320aic23: Cleanup manual bias level transitions Set the CODEC driver's suspend_bias_off flag rather than manually going to SND_SOC_BIAS_OFF in suspend and SND_SOC_BIAS_STANDBY in resume. This makes the code a bit shorter and cleaner. Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. The manual transition to SND_SOC_BIAS_STANDBY at the end of CODEC probe() can also be removed as the core will automatically do this after the CODEC has been probed. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic23.c | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c index d67167920c2f..cc17e7e5126e 100644 --- a/sound/soc/codecs/tlv320aic23.c +++ b/sound/soc/codecs/tlv320aic23.c @@ -540,19 +540,11 @@ static struct snd_soc_dai_driver tlv320aic23_dai = { .ops = &tlv320aic23_dai_ops, }; -static int tlv320aic23_suspend(struct snd_soc_codec *codec) -{ - tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF); - - return 0; -} - static int tlv320aic23_resume(struct snd_soc_codec *codec) { struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec); regcache_mark_dirty(aic23->regmap); regcache_sync(aic23->regmap); - tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY); return 0; } @@ -562,9 +554,6 @@ static int tlv320aic23_codec_probe(struct snd_soc_codec *codec) /* Reset codec */ snd_soc_write(codec, TLV320AIC23_RESET, 0); - /* power on device */ - tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - snd_soc_write(codec, TLV320AIC23_DIGT, TLV320AIC23_DEEMP_44K); /* Unmute input */ @@ -589,18 +578,12 @@ static int tlv320aic23_codec_probe(struct snd_soc_codec *codec) return 0; } -static int tlv320aic23_remove(struct snd_soc_codec *codec) -{ - tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - static struct snd_soc_codec_driver soc_codec_dev_tlv320aic23 = { .probe = tlv320aic23_codec_probe, - .remove = tlv320aic23_remove, - .suspend = tlv320aic23_suspend, .resume = tlv320aic23_resume, .set_bias_level = tlv320aic23_set_bias_level, + .suspend_bias_off = true, + .controls = tlv320aic23_snd_controls, .num_controls = ARRAY_SIZE(tlv320aic23_snd_controls), .dapm_widgets = tlv320aic23_dapm_widgets, -- cgit v1.2.3 From a43a262901363ea412c288e5ebc3a3c0a8ff6591 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 26 Nov 2014 20:57:55 +0100 Subject: ASoC: tlv320aix31xx: Cleanup manual bias level transitions Set the CODEC driver's suspend_bias_off flag rather than manually going to SND_SOC_BIAS_OFF in suspend and SND_SOC_BIAS_STANDBY in resume. This makes the code a bit shorter and cleaner. Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. Signed-off-by: Lars-Peter Clausen Acked-by: Jyri Sarha Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic31xx.c | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index 145fe5b253d4..6cd5f50a9eb7 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -1056,18 +1056,6 @@ static int aic31xx_set_bias_level(struct snd_soc_codec *codec, return 0; } -static int aic31xx_suspend(struct snd_soc_codec *codec) -{ - aic31xx_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - -static int aic31xx_resume(struct snd_soc_codec *codec) -{ - aic31xx_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - return 0; -} - static int aic31xx_codec_probe(struct snd_soc_codec *codec) { int ret = 0; @@ -1110,8 +1098,6 @@ static int aic31xx_codec_remove(struct snd_soc_codec *codec) { struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec); int i; - /* power down chip */ - aic31xx_set_bias_level(codec, SND_SOC_BIAS_OFF); for (i = 0; i < ARRAY_SIZE(aic31xx->supplies); i++) regulator_unregister_notifier(aic31xx->supplies[i].consumer, @@ -1123,9 +1109,9 @@ static int aic31xx_codec_remove(struct snd_soc_codec *codec) static struct snd_soc_codec_driver soc_codec_driver_aic31xx = { .probe = aic31xx_codec_probe, .remove = aic31xx_codec_remove, - .suspend = aic31xx_suspend, - .resume = aic31xx_resume, .set_bias_level = aic31xx_set_bias_level, + .suspend_bias_off = true, + .controls = aic31xx_snd_controls, .num_controls = ARRAY_SIZE(aic31xx_snd_controls), .dapm_widgets = aic31xx_dapm_widgets, -- cgit v1.2.3 From f10c0a71e6efc7c8cbc3bfcfd0ecf822607f0b3d Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 26 Nov 2014 20:57:56 +0100 Subject: ASoC: tlv320aic32x4: Cleanup manual bias level transitions Set the CODEC driver's suspend_bias_off flag rather than manually going to SND_SOC_BIAS_OFF in suspend and SND_SOC_BIAS_STANDBY in resume. This makes the code a bit shorter and cleaner. Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. The manual transition to SND_SOC_BIAS_STANDBY at the end of CODEC probe() can also be removed as the core will automatically do this after the CODEC has been probed. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic32x4.c | 24 +----------------------- 1 file changed, 1 insertion(+), 23 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index 6ea662db2410..015467ed606b 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -597,18 +597,6 @@ static struct snd_soc_dai_driver aic32x4_dai = { .symmetric_rates = 1, }; -static int aic32x4_suspend(struct snd_soc_codec *codec) -{ - aic32x4_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - -static int aic32x4_resume(struct snd_soc_codec *codec) -{ - aic32x4_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - return 0; -} - static int aic32x4_probe(struct snd_soc_codec *codec) { struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec); @@ -654,8 +642,6 @@ static int aic32x4_probe(struct snd_soc_codec *codec) snd_soc_write(codec, AIC32X4_RMICPGANIN, AIC32X4_RMICPGANIN_CM1R_10K); - aic32x4_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - /* * Workaround: for an unknown reason, the ADC needs to be powered up * and down for the first capture to work properly. It seems related to @@ -669,18 +655,10 @@ static int aic32x4_probe(struct snd_soc_codec *codec) return 0; } -static int aic32x4_remove(struct snd_soc_codec *codec) -{ - aic32x4_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - static struct snd_soc_codec_driver soc_codec_dev_aic32x4 = { .probe = aic32x4_probe, - .remove = aic32x4_remove, - .suspend = aic32x4_suspend, - .resume = aic32x4_resume, .set_bias_level = aic32x4_set_bias_level, + .suspend_bias_off = true, .controls = aic32x4_snd_controls, .num_controls = ARRAY_SIZE(aic32x4_snd_controls), -- cgit v1.2.3 From 68f438378cde79e29f71c7e043b10d76001d8892 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 26 Nov 2014 20:57:57 +0100 Subject: ASoC: tlv320aic3x: Cleanup manual bias level transitions Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic3x.c | 1 - 1 file changed, 1 deletion(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index f0a828119aba..b7ebce054b4e 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -1491,7 +1491,6 @@ static int aic3x_remove(struct snd_soc_codec *codec) struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); int i; - aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF); list_del(&aic3x->list); for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) regulator_unregister_notifier(aic3x->supplies[i].consumer, -- cgit v1.2.3 From 90db15e17e46e2841843bf20f258fed963228bed Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 26 Nov 2014 20:57:58 +0100 Subject: ASoC: tlv320dac33: Cleanup manual bias level transitions Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320dac33.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index e21ed934bdbf..0fe2ced5b09f 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c @@ -1436,8 +1436,6 @@ static int dac33_soc_remove(struct snd_soc_codec *codec) { struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec); - dac33_set_bias_level(codec, SND_SOC_BIAS_OFF); - if (dac33->irq >= 0) { free_irq(dac33->irq, dac33->codec); destroy_workqueue(dac33->dac33_wq); -- cgit v1.2.3 From 3ec8d2036464d961a6314281ae68d80a5c071d07 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 26 Nov 2014 20:57:59 +0100 Subject: ASoC: twl4030: Cleanup manual bias level transitions Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index b6b0cb399599..27f3b21effb2 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -2177,8 +2177,6 @@ static int twl4030_soc_remove(struct snd_soc_codec *codec) struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); struct twl4030_codec_data *pdata = twl4030->pdata; - twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF); - if (pdata && pdata->hs_extmute && gpio_is_valid(pdata->hs_extmute_gpio)) gpio_free(pdata->hs_extmute_gpio); -- cgit v1.2.3 From c4ee42a050e82855aa06d7217937b1549c95bef3 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 26 Nov 2014 20:58:00 +0100 Subject: ASoC: twl6040: Cleanup manual bias level transitions Set the CODEC driver's suspend_bias_off flag rather than manually going to SND_SOC_BIAS_OFF in suspend and SND_SOC_BIAS_STANDBY in resume. This makes the code a bit shorter and cleaner. Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/twl6040.c | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c index 0f6067f04e29..5ff2b1e4638e 100644 --- a/sound/soc/codecs/twl6040.c +++ b/sound/soc/codecs/twl6040.c @@ -1095,25 +1095,6 @@ static struct snd_soc_dai_driver twl6040_dai[] = { }, }; -#ifdef CONFIG_PM -static int twl6040_suspend(struct snd_soc_codec *codec) -{ - twl6040_set_bias_level(codec, SND_SOC_BIAS_OFF); - - return 0; -} - -static int twl6040_resume(struct snd_soc_codec *codec) -{ - twl6040_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - return 0; -} -#else -#define twl6040_suspend NULL -#define twl6040_resume NULL -#endif - static int twl6040_probe(struct snd_soc_codec *codec) { struct twl6040_data *priv; @@ -1160,7 +1141,6 @@ static int twl6040_remove(struct snd_soc_codec *codec) struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); free_irq(priv->plug_irq, codec); - twl6040_set_bias_level(codec, SND_SOC_BIAS_OFF); return 0; } @@ -1168,11 +1148,10 @@ static int twl6040_remove(struct snd_soc_codec *codec) static struct snd_soc_codec_driver soc_codec_dev_twl6040 = { .probe = twl6040_probe, .remove = twl6040_remove, - .suspend = twl6040_suspend, - .resume = twl6040_resume, .read = twl6040_read, .write = twl6040_write, .set_bias_level = twl6040_set_bias_level, + .suspend_bias_off = true, .ignore_pmdown_time = true, .controls = twl6040_snd_controls, -- cgit v1.2.3 From d819ce965d451aac08e46c9f8e2119fe3a845786 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Thu, 27 Nov 2014 13:02:00 -0200 Subject: ASoC: sgtl5000: Remove MCLK restriction According to the sgtl5000 datasheet the MCLK frequency range restriction of 8 to 27 MHz only applies when the PLL is used - synchronous SYS_MCLK input mode. When running the codec as slave, the master should generate MCLK in the range of 256*fs, 384*fs or 512*fs, which is called asynchronous SYS_MCLK input mode. In asynchronous SYS_MCLK we cannot have the 8 to 27 MHz check because if we want to play a 8KHz sample rate track, with a MCLK of 8k * 512 = 4.096MHz the current check would return -EINVAL, which is not correct. Remove the 8 to 27MHz frequency check, since this only applies to the synchronous SYS_MCLK input case. Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown --- sound/soc/codecs/sgtl5000.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index 490404c6b4d8..473579106539 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -1435,7 +1435,6 @@ static int sgtl5000_i2c_probe(struct i2c_client *client, { struct sgtl5000_priv *sgtl5000; int ret, reg, rev; - unsigned int mclk; struct device_node *np = client->dev.of_node; u32 value; @@ -1460,14 +1459,6 @@ static int sgtl5000_i2c_probe(struct i2c_client *client, return ret; } - /* SGTL5000 SYS_MCLK should be between 8 and 27 MHz */ - mclk = clk_get_rate(sgtl5000->mclk); - if (mclk < 8000000 || mclk > 27000000) { - dev_err(&client->dev, "Invalid SYS_CLK frequency: %u.%03uMHz\n", - mclk / 1000000, mclk / 1000 % 1000); - return -EINVAL; - } - ret = clk_prepare_enable(sgtl5000->mclk); if (ret) return ret; -- cgit v1.2.3 From 2a4cfd10229dc93507aa5ddbc1ba0162140f4951 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Thu, 27 Nov 2014 13:02:01 -0200 Subject: ASoC: sgtl5000: Allow 8kHz playback in codec slave mode When trying to play a 8kHz file with codec in slave mode we get the following error on a mx28evk: $ aplay -Dhw:0,0 stereo_8k.wav Playing WAVE 'stereo_8k.wav' : Signed 16 bit Little Endian, Rate 8000 Hz, Stereo [ 21.218647] sgtl5000 0-000a: PLL not supported in slave mode [ 21.224559] sgtl5000 0-000a: 128 ratio is not supported. SYS_MCLK needs to be 256, 384 or 512 * fs [ 21.233687] sgtl5000 0-000a: ASoC: can't set sgtl5000 hw params: -22 aplay: set_params:1123: Unable to install hw params: This error happens because we are using 'sys_fs' instead of 'frame_rate' in the valid ratio check. Use the real'frame_rate' so that the ratio is correctly calculated and the playback can run. sgtl5000 codec manual states that in 'Synchronous SYS_MCLK input' mode that the following SYS_CLK frequencies are allowed: 256*fs, 384*fs, 512*fs. , where fs is the sampling frequency, which can be in the range of: 8, 11.025, 16, 22.5, 32, 44.1, 48, 96 kHz. Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown --- sound/soc/codecs/sgtl5000.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index 473579106539..47d6ca068897 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -618,7 +618,7 @@ static int sgtl5000_set_clock(struct snd_soc_codec *codec, int frame_rate) * factor of freq = 96 kHz can only be 256, since mclk is in the range * of 8 MHz - 27 MHz */ - switch (sgtl5000->sysclk / sys_fs) { + switch (sgtl5000->sysclk / frame_rate) { case 256: clk_ctl |= SGTL5000_MCLK_FREQ_256FS << SGTL5000_MCLK_FREQ_SHIFT; @@ -641,7 +641,7 @@ static int sgtl5000_set_clock(struct snd_soc_codec *codec, int frame_rate) "PLL not supported in slave mode\n"); dev_err(codec->dev, "%d ratio is not supported. " "SYS_MCLK needs to be 256, 384 or 512 * fs\n", - sgtl5000->sysclk / sys_fs); + sgtl5000->sysclk / frame_rate); return -EINVAL; } } -- cgit v1.2.3 From 40e3262e425a04743f2a579a379f2f189f084580 Mon Sep 17 00:00:00 2001 From: Dylan Reid Date: Thu, 4 Dec 2014 17:00:13 -0800 Subject: ASoC: rt5677: make volume TLV closer to reality The volume blocks have an step of 0.375dB, but TLV uses 0.01dB for units. Only use the resolution supported, ignoring the LSB of the volume register. This results in half the steps and 0.75dB per step, but reports accurate levels through TLV. Update the masks to reflect that these are registers have the LSB ignored. Signed-off-by: Dylan Reid Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677.c | 22 +++++++++++----------- sound/soc/codecs/rt5677.h | 24 ++++++++++++------------ 2 files changed, 23 insertions(+), 23 deletions(-) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 133010dd9f34..81fe1464d268 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -763,9 +763,9 @@ static int rt5677_set_dsp_vad(struct snd_soc_codec *codec, bool on) } static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0); -static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0); +static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -6525, 75, 0); static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0); -static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0); +static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -1725, 75, 0); static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0); static const DECLARE_TLV_DB_SCALE(st_vol_tlv, -4650, 150, 0); @@ -817,13 +817,13 @@ static const struct snd_kcontrol_new rt5677_snd_controls[] = { /* DAC Digital Volume */ SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5677_DAC1_DIG_VOL, - RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 175, 0, dac_vol_tlv), + RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 87, 0, dac_vol_tlv), SOC_DOUBLE_TLV("DAC2 Playback Volume", RT5677_DAC2_DIG_VOL, - RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 175, 0, dac_vol_tlv), + RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 87, 0, dac_vol_tlv), SOC_DOUBLE_TLV("DAC3 Playback Volume", RT5677_DAC3_DIG_VOL, - RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 175, 0, dac_vol_tlv), + RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 87, 0, dac_vol_tlv), SOC_DOUBLE_TLV("DAC4 Playback Volume", RT5677_DAC4_DIG_VOL, - RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 175, 0, dac_vol_tlv), + RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 87, 0, dac_vol_tlv), /* IN1/IN2 Control */ SOC_SINGLE_TLV("IN1 Boost", RT5677_IN1, RT5677_BST_SFT1, 8, 0, bst_tlv), @@ -842,19 +842,19 @@ static const struct snd_kcontrol_new rt5677_snd_controls[] = { RT5677_L_MUTE_SFT, RT5677_R_MUTE_SFT, 1, 1), SOC_DOUBLE_TLV("ADC1 Capture Volume", RT5677_STO1_ADC_DIG_VOL, - RT5677_STO1_ADC_L_VOL_SFT, RT5677_STO1_ADC_R_VOL_SFT, 127, 0, + RT5677_STO1_ADC_L_VOL_SFT, RT5677_STO1_ADC_R_VOL_SFT, 63, 0, adc_vol_tlv), SOC_DOUBLE_TLV("ADC2 Capture Volume", RT5677_STO2_ADC_DIG_VOL, - RT5677_STO1_ADC_L_VOL_SFT, RT5677_STO1_ADC_R_VOL_SFT, 127, 0, + RT5677_STO1_ADC_L_VOL_SFT, RT5677_STO1_ADC_R_VOL_SFT, 63, 0, adc_vol_tlv), SOC_DOUBLE_TLV("ADC3 Capture Volume", RT5677_STO3_ADC_DIG_VOL, - RT5677_STO1_ADC_L_VOL_SFT, RT5677_STO1_ADC_R_VOL_SFT, 127, 0, + RT5677_STO1_ADC_L_VOL_SFT, RT5677_STO1_ADC_R_VOL_SFT, 63, 0, adc_vol_tlv), SOC_DOUBLE_TLV("ADC4 Capture Volume", RT5677_STO4_ADC_DIG_VOL, - RT5677_STO1_ADC_L_VOL_SFT, RT5677_STO1_ADC_R_VOL_SFT, 127, 0, + RT5677_STO1_ADC_L_VOL_SFT, RT5677_STO1_ADC_R_VOL_SFT, 63, 0, adc_vol_tlv), SOC_DOUBLE_TLV("Mono ADC Capture Volume", RT5677_MONO_ADC_DIG_VOL, - RT5677_MONO_ADC_L_VOL_SFT, RT5677_MONO_ADC_R_VOL_SFT, 127, 0, + RT5677_MONO_ADC_L_VOL_SFT, RT5677_MONO_ADC_R_VOL_SFT, 63, 0, adc_vol_tlv), /* Sidetone Control */ diff --git a/sound/soc/codecs/rt5677.h b/sound/soc/codecs/rt5677.h index dbd9ffde50dc..c0a625f290cc 100644 --- a/sound/soc/codecs/rt5677.h +++ b/sound/soc/codecs/rt5677.h @@ -306,10 +306,10 @@ #define RT5677_R_MUTE_SFT 7 #define RT5677_VOL_R_MUTE (0x1 << 6) #define RT5677_VOL_R_SFT 6 -#define RT5677_L_VOL_MASK (0x3f << 8) -#define RT5677_L_VOL_SFT 8 -#define RT5677_R_VOL_MASK (0x3f) -#define RT5677_R_VOL_SFT 0 +#define RT5677_L_VOL_MASK (0x7f << 9) +#define RT5677_L_VOL_SFT 9 +#define RT5677_R_VOL_MASK (0x7f << 1) +#define RT5677_R_VOL_SFT 1 /* LOUT1 Control (0x01) */ #define RT5677_LOUT1_L_MUTE (0x1 << 15) @@ -447,16 +447,16 @@ #define RT5677_SEL_DAC2_R_SRC_SFT 0 /* Stereo1 ADC Digital Volume Control (0x1c) */ -#define RT5677_STO1_ADC_L_VOL_MASK (0x7f << 8) -#define RT5677_STO1_ADC_L_VOL_SFT 8 -#define RT5677_STO1_ADC_R_VOL_MASK (0x7f) -#define RT5677_STO1_ADC_R_VOL_SFT 0 +#define RT5677_STO1_ADC_L_VOL_MASK (0x3f << 9) +#define RT5677_STO1_ADC_L_VOL_SFT 9 +#define RT5677_STO1_ADC_R_VOL_MASK (0x3f << 1) +#define RT5677_STO1_ADC_R_VOL_SFT 1 /* Mono ADC Digital Volume Control (0x1d) */ -#define RT5677_MONO_ADC_L_VOL_MASK (0x7f << 8) -#define RT5677_MONO_ADC_L_VOL_SFT 8 -#define RT5677_MONO_ADC_R_VOL_MASK (0x7f) -#define RT5677_MONO_ADC_R_VOL_SFT 0 +#define RT5677_MONO_ADC_L_VOL_MASK (0x3f << 9) +#define RT5677_MONO_ADC_L_VOL_SFT 9 +#define RT5677_MONO_ADC_R_VOL_MASK (0x3f << 1) +#define RT5677_MONO_ADC_R_VOL_SFT 1 /* Stereo 1/2 ADC Boost Gain Control (0x1e) */ #define RT5677_STO1_ADC_L_BST_MASK (0x3 << 14) -- cgit v1.2.3 From 47370022d2ca552ab524bb14211fefa3a2518ba8 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 5 Dec 2014 20:06:31 +0000 Subject: ASoC: wm5102: Initialize dac_comp_lock mutex Commit d74bcaaeb6682 (ASoC: wm5102: Move ultrasonic response settings lock to the driver level) created a driver local mutex for protecting the ultrasonic response settings but neglected to initialize that mutex, causing loud complaints from lockep and potential runtime failures. Fix this by initializing the mutex. Signed-off-by: Mark Brown Acked-by: Charles Keepax --- sound/soc/codecs/wm5102.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index 1f7553492667..d78fb8dffc8c 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -1900,6 +1900,8 @@ static int wm5102_probe(struct platform_device *pdev) return -ENOMEM; platform_set_drvdata(pdev, wm5102); + mutex_init(&arizona->dac_comp_lock); + wm5102->core.arizona = arizona; wm5102->core.num_inputs = 6; -- cgit v1.2.3 From 75945896a2f4a7ebfc3402443f99ac32f629ee96 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Tue, 9 Dec 2014 10:14:45 +0800 Subject: ASoC: rt5645: Fix potential crash in jd function If no one defined the rt5645->pdata.hp_det_gpio in coreboot/bios. It will cause kernel to reboot because rt5645->pdata.hp_det_gpio is 0. So it is worth to add a check in rt5645_jack_detect. Signed-off-by: Bard Liao Signed-off-by: Fang, Yang A Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index d16331e0b64d..c901ef6ba69b 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -2113,6 +2113,10 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec, int gpio_state, jack_type = 0; unsigned int val; + if (!gpio_is_valid(rt5645->pdata.hp_det_gpio)) { + dev_err(codec->dev, "invalid gpio\n"); + return -EINVAL; + } gpio_state = gpio_get_value(rt5645->pdata.hp_det_gpio); dev_dbg(codec->dev, "gpio = %d(%d)\n", rt5645->pdata.hp_det_gpio, -- cgit v1.2.3 From 359ff7ffafa78dd401a1ca0019ba2fe35ff377cc Mon Sep 17 00:00:00 2001 From: Ben Zhang Date: Wed, 10 Dec 2014 20:15:25 -0800 Subject: ASoC: rt5677: add REGMAP_I2C and REGMAP_IRQ dependency The codec driver uses regmap to do i2c read/write. The codec driver started to use REGMAP_IRQ since: 5e3363ad1b7b2e1f197a3f56b01e21cb155ad454 ASoC: rt5677: add GPIO IRQ support Signed-off-by: Ben Zhang Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound/soc/codecs') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 883c5778b309..8349f982a586 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -520,6 +520,8 @@ config SND_SOC_RT5670 config SND_SOC_RT5677 tristate + select REGMAP_I2C + select REGMAP_IRQ config SND_SOC_RT5677_SPI tristate -- cgit v1.2.3