diff options
Diffstat (limited to 'sound/soc/codecs')
34 files changed, 1151 insertions, 424 deletions
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 9cc4f1848c9b..62bdb7e333b8 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -35,6 +35,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_ADAU7002 select SND_SOC_ADS117X select SND_SOC_AK4104 if SPI_MASTER + select SND_SOC_AK4118 if I2C select SND_SOC_AK4458 if I2C select SND_SOC_AK4535 if I2C select SND_SOC_AK4554 @@ -392,6 +393,11 @@ config SND_SOC_AK4104 tristate "AKM AK4104 CODEC" depends on SPI_MASTER +config SND_SOC_AK4118 + tristate "AKM AK4118 CODEC" + depends on I2C + select REGMAP_I2C + config SND_SOC_AK4458 tristate "AKM AK4458 CODEC" depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 8ffab8c8dbfa..66f55d185620 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -27,6 +27,7 @@ snd-soc-adav801-objs := adav801.o snd-soc-adav803-objs := adav803.o snd-soc-ads117x-objs := ads117x.o snd-soc-ak4104-objs := ak4104.o +snd-soc-ak4118-objs := ak4118.o snd-soc-ak4458-objs := ak4458.o snd-soc-ak4535-objs := ak4535.o snd-soc-ak4554-objs := ak4554.o @@ -290,6 +291,7 @@ obj-$(CONFIG_SND_SOC_ADAV801) += snd-soc-adav801.o obj-$(CONFIG_SND_SOC_ADAV803) += snd-soc-adav803.o obj-$(CONFIG_SND_SOC_ADS117X) += snd-soc-ads117x.o obj-$(CONFIG_SND_SOC_AK4104) += snd-soc-ak4104.o +obj-$(CONFIG_SND_SOC_AK4118) += snd-soc-ak4118.o obj-$(CONFIG_SND_SOC_AK4458) += snd-soc-ak4458.o obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o obj-$(CONFIG_SND_SOC_AK4554) += snd-soc-ak4554.o diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c index 32bc545c19cf..6dec8a65eafc 100644 --- a/sound/soc/codecs/ak4104.c +++ b/sound/soc/codecs/ak4104.c @@ -13,7 +13,7 @@ #include <linux/slab.h> #include <linux/spi/spi.h> #include <linux/of_device.h> -#include <linux/of_gpio.h> +#include <linux/gpio/consumer.h> #include <linux/regulator/consumer.h> #include <sound/asoundef.h> #include <sound/core.h> @@ -268,8 +268,8 @@ static const struct regmap_config ak4104_regmap = { static int ak4104_spi_probe(struct spi_device *spi) { - struct device_node *np = spi->dev.of_node; struct ak4104_private *ak4104; + struct gpio_desc *reset_gpiod; unsigned int val; int ret; @@ -297,19 +297,11 @@ static int ak4104_spi_probe(struct spi_device *spi) return ret; } - if (np) { - enum of_gpio_flags flags; - int gpio = of_get_named_gpio_flags(np, "reset-gpio", 0, &flags); - - if (gpio_is_valid(gpio)) { - ret = devm_gpio_request_one(&spi->dev, gpio, - flags & OF_GPIO_ACTIVE_LOW ? - GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH, - "ak4104 reset"); - if (ret < 0) - return ret; - } - } + reset_gpiod = devm_gpiod_get_optional(&spi->dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(reset_gpiod) && + PTR_ERR(reset_gpiod) == -EPROBE_DEFER) + return -EPROBE_DEFER; /* read the 'reserved' register - according to the datasheet, it * should contain 0x5b. Not a good way to verify the presence of diff --git a/sound/soc/codecs/ak4118.c b/sound/soc/codecs/ak4118.c new file mode 100644 index 000000000000..238ab29f2bf4 --- /dev/null +++ b/sound/soc/codecs/ak4118.c @@ -0,0 +1,438 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ak4118.c -- Asahi Kasei ALSA Soc Audio driver + * + * Copyright 2018 DEVIALET + */ + +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/of_gpio.h> +#include <linux/regmap.h> +#include <linux/slab.h> + +#include <sound/asoundef.h> +#include <sound/core.h> +#include <sound/initval.h> +#include <sound/soc.h> + +#define AK4118_REG_CLK_PWR_CTL 0x00 +#define AK4118_REG_FORMAT_CTL 0x01 +#define AK4118_REG_IO_CTL0 0x02 +#define AK4118_REG_IO_CTL1 0x03 +#define AK4118_REG_INT0_MASK 0x04 +#define AK4118_REG_INT1_MASK 0x05 +#define AK4118_REG_RCV_STATUS0 0x06 +#define AK4118_REG_RCV_STATUS1 0x07 +#define AK4118_REG_RXCHAN_STATUS0 0x08 +#define AK4118_REG_RXCHAN_STATUS1 0x09 +#define AK4118_REG_RXCHAN_STATUS2 0x0a +#define AK4118_REG_RXCHAN_STATUS3 0x0b +#define AK4118_REG_RXCHAN_STATUS4 0x0c +#define AK4118_REG_TXCHAN_STATUS0 0x0d +#define AK4118_REG_TXCHAN_STATUS1 0x0e +#define AK4118_REG_TXCHAN_STATUS2 0x0f +#define AK4118_REG_TXCHAN_STATUS3 0x10 +#define AK4118_REG_TXCHAN_STATUS4 0x11 +#define AK4118_REG_BURST_PREAMB_PC0 0x12 +#define AK4118_REG_BURST_PREAMB_PC1 0x13 +#define AK4118_REG_BURST_PREAMB_PD0 0x14 +#define AK4118_REG_BURST_PREAMB_PD1 0x15 +#define AK4118_REG_QSUB_CTL 0x16 +#define AK4118_REG_QSUB_TRACK 0x17 +#define AK4118_REG_QSUB_INDEX 0x18 +#define AK4118_REG_QSUB_MIN 0x19 +#define AK4118_REG_QSUB_SEC 0x1a +#define AK4118_REG_QSUB_FRAME 0x1b +#define AK4118_REG_QSUB_ZERO 0x1c +#define AK4118_REG_QSUB_ABS_MIN 0x1d +#define AK4118_REG_QSUB_ABS_SEC 0x1e +#define AK4118_REG_QSUB_ABS_FRAME 0x1f +#define AK4118_REG_GPE 0x20 +#define AK4118_REG_GPDR 0x21 +#define AK4118_REG_GPSCR 0x22 +#define AK4118_REG_GPLR 0x23 +#define AK4118_REG_DAT_MASK_DTS 0x24 +#define AK4118_REG_RX_DETECT 0x25 +#define AK4118_REG_STC_DAT_DETECT 0x26 +#define AK4118_REG_RXCHAN_STATUS5 0x27 +#define AK4118_REG_TXCHAN_STATUS5 0x28 +#define AK4118_REG_MAX 0x29 + +#define AK4118_REG_FORMAT_CTL_DIF0 (1 << 4) +#define AK4118_REG_FORMAT_CTL_DIF1 (1 << 5) +#define AK4118_REG_FORMAT_CTL_DIF2 (1 << 6) + +struct ak4118_priv { + struct regmap *regmap; + struct gpio_desc *reset; + struct gpio_desc *irq; + struct snd_soc_component *component; +}; + +static const struct reg_default ak4118_reg_defaults[] = { + {AK4118_REG_CLK_PWR_CTL, 0x43}, + {AK4118_REG_FORMAT_CTL, 0x6a}, + {AK4118_REG_IO_CTL0, 0x88}, + {AK4118_REG_IO_CTL1, 0x48}, + {AK4118_REG_INT0_MASK, 0xee}, + {AK4118_REG_INT1_MASK, 0xb5}, + {AK4118_REG_RCV_STATUS0, 0x00}, + {AK4118_REG_RCV_STATUS1, 0x10}, + {AK4118_REG_TXCHAN_STATUS0, 0x00}, + {AK4118_REG_TXCHAN_STATUS1, 0x00}, + {AK4118_REG_TXCHAN_STATUS2, 0x00}, + {AK4118_REG_TXCHAN_STATUS3, 0x00}, + {AK4118_REG_TXCHAN_STATUS4, 0x00}, + {AK4118_REG_GPE, 0x77}, + {AK4118_REG_GPDR, 0x00}, + {AK4118_REG_GPSCR, 0x00}, + {AK4118_REG_GPLR, 0x00}, + {AK4118_REG_DAT_MASK_DTS, 0x3f}, + {AK4118_REG_RX_DETECT, 0x00}, + {AK4118_REG_STC_DAT_DETECT, 0x00}, + {AK4118_REG_TXCHAN_STATUS5, 0x00}, +}; + +static const char * const ak4118_input_select_txt[] = { + "RX0", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7", +}; +static SOC_ENUM_SINGLE_DECL(ak4118_insel_enum, AK4118_REG_IO_CTL1, 0x0, + ak4118_input_select_txt); + +static const struct snd_kcontrol_new ak4118_input_mux_controls = + SOC_DAPM_ENUM("Input Select", ak4118_insel_enum); + +static const char * const ak4118_iec958_fs_txt[] = { + "44100", "48000", "32000", "22050", "11025", "24000", "16000", "88200", + "8000", "96000", "64000", "176400", "192000", +}; + +static const int ak4118_iec958_fs_val[] = { + 0x0, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xE, +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(ak4118_iec958_fs_enum, AK4118_REG_RCV_STATUS1, + 0x4, 0x4, ak4118_iec958_fs_txt, + ak4118_iec958_fs_val); + +static struct snd_kcontrol_new ak4118_iec958_controls[] = { + SOC_SINGLE("IEC958 Parity Errors", AK4118_REG_RCV_STATUS0, 0, 1, 0), + SOC_SINGLE("IEC958 No Audio", AK4118_REG_RCV_STATUS0, 1, 1, 0), + SOC_SINGLE("IEC958 PLL Lock", AK4118_REG_RCV_STATUS0, 4, 1, 1), + SOC_SINGLE("IEC958 Non PCM", AK4118_REG_RCV_STATUS0, 6, 1, 0), + SOC_ENUM("IEC958 Sampling Freq", ak4118_iec958_fs_enum), +}; + +static const struct snd_soc_dapm_widget ak4118_dapm_widgets[] = { + SND_SOC_DAPM_INPUT("INRX0"), + SND_SOC_DAPM_INPUT("INRX1"), + SND_SOC_DAPM_INPUT("INRX2"), + SND_SOC_DAPM_INPUT("INRX3"), + SND_SOC_DAPM_INPUT("INRX4"), + SND_SOC_DAPM_INPUT("INRX5"), + SND_SOC_DAPM_INPUT("INRX6"), + SND_SOC_DAPM_INPUT("INRX7"), + SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, + &ak4118_input_mux_controls), +}; + +static const struct snd_soc_dapm_route ak4118_dapm_routes[] = { + {"Input Mux", "RX0", "INRX0"}, + {"Input Mux", "RX1", "INRX1"}, + {"Input Mux", "RX2", "INRX2"}, + {"Input Mux", "RX3", "INRX3"}, + {"Input Mux", "RX4", "INRX4"}, + {"Input Mux", "RX5", "INRX5"}, + {"Input Mux", "RX6", "INRX6"}, + {"Input Mux", "RX7", "INRX7"}, +}; + + +static int ak4118_set_dai_fmt_master(struct ak4118_priv *ak4118, + unsigned int format) +{ + int dif; + + switch (format & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + dif = AK4118_REG_FORMAT_CTL_DIF0 | AK4118_REG_FORMAT_CTL_DIF2; + break; + case SND_SOC_DAIFMT_RIGHT_J: + dif = AK4118_REG_FORMAT_CTL_DIF0 | AK4118_REG_FORMAT_CTL_DIF1; + break; + case SND_SOC_DAIFMT_LEFT_J: + dif = AK4118_REG_FORMAT_CTL_DIF2; + break; + default: + return -ENOTSUPP; + } + + return dif; +} + +static int ak4118_set_dai_fmt_slave(struct ak4118_priv *ak4118, + unsigned int format) +{ + int dif; + + switch (format & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + dif = AK4118_REG_FORMAT_CTL_DIF0 | AK4118_REG_FORMAT_CTL_DIF1 | + AK4118_REG_FORMAT_CTL_DIF2; + break; + case SND_SOC_DAIFMT_LEFT_J: + dif = AK4118_REG_FORMAT_CTL_DIF1 | AK4118_REG_FORMAT_CTL_DIF2; + break; + default: + return -ENOTSUPP; + } + + return dif; +} + +static int ak4118_set_dai_fmt(struct snd_soc_dai *dai, + unsigned int format) +{ + struct snd_soc_component *component = dai->component; + struct ak4118_priv *ak4118 = snd_soc_component_get_drvdata(component); + int dif; + int ret = 0; + + switch (format & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + /* component is master */ + dif = ak4118_set_dai_fmt_master(ak4118, format); + break; + case SND_SOC_DAIFMT_CBS_CFS: + /*component is slave */ + dif = ak4118_set_dai_fmt_slave(ak4118, format); + break; + default: + ret = -ENOTSUPP; + goto exit; + } + + /* format not supported */ + if (dif < 0) { + ret = dif; + goto exit; + } + + ret = regmap_update_bits(ak4118->regmap, AK4118_REG_FORMAT_CTL, + AK4118_REG_FORMAT_CTL_DIF0 | + AK4118_REG_FORMAT_CTL_DIF1 | + AK4118_REG_FORMAT_CTL_DIF2, dif); + if (ret < 0) + goto exit; + +exit: + return ret; +} + +static int ak4118_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + return 0; +} + +static const struct snd_soc_dai_ops ak4118_dai_ops = { + .hw_params = ak4118_hw_params, + .set_fmt = ak4118_set_dai_fmt, +}; + +static struct snd_soc_dai_driver ak4118_dai = { + .name = "ak4118-hifi", + .capture = { + .stream_name = "Capture", + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | + SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_3LE | + SNDRV_PCM_FMTBIT_S24_LE + }, + .ops = &ak4118_dai_ops, +}; + +static irqreturn_t ak4118_irq_handler(int irq, void *data) +{ + struct ak4118_priv *ak4118 = data; + struct snd_soc_component *component = ak4118->component; + struct snd_kcontrol_new *kctl_new; + struct snd_kcontrol *kctl; + struct snd_ctl_elem_id *id; + unsigned int i; + + if (!component) + return IRQ_NONE; + + for (i = 0; i < ARRAY_SIZE(ak4118_iec958_controls); i++) { + kctl_new = &ak4118_iec958_controls[i]; + kctl = snd_soc_card_get_kcontrol(component->card, + kctl_new->name); + if (!kctl) + continue; + id = &kctl->id; + snd_ctl_notify(component->card->snd_card, + SNDRV_CTL_EVENT_MASK_VALUE, id); + } + + return IRQ_HANDLED; +} + +static int ak4118_probe(struct snd_soc_component *component) +{ + struct ak4118_priv *ak4118 = snd_soc_component_get_drvdata(component); + int ret = 0; + + ak4118->component = component; + + /* release reset */ + gpiod_set_value(ak4118->reset, 0); + + /* unmask all int1 sources */ + ret = regmap_write(ak4118->regmap, AK4118_REG_INT1_MASK, 0x00); + if (ret < 0) { + dev_err(component->dev, + "failed to write regmap 0x%x 0x%x: %d\n", + AK4118_REG_INT1_MASK, 0x00, ret); + return ret; + } + + /* rx detect enable on all channels */ + ret = regmap_write(ak4118->regmap, AK4118_REG_RX_DETECT, 0xff); + if (ret < 0) { + dev_err(component->dev, + "failed to write regmap 0x%x 0x%x: %d\n", + AK4118_REG_RX_DETECT, 0xff, ret); + return ret; + } + + ret = snd_soc_add_component_controls(component, ak4118_iec958_controls, + ARRAY_SIZE(ak4118_iec958_controls)); + if (ret) { + dev_err(component->dev, + "failed to add component kcontrols: %d\n", ret); + return ret; + } + + return 0; +} + +static void ak4118_remove(struct snd_soc_component *component) +{ + struct ak4118_priv *ak4118 = snd_soc_component_get_drvdata(component); + + /* hold reset */ + gpiod_set_value(ak4118->reset, 1); +} + +static const struct snd_soc_component_driver soc_component_drv_ak4118 = { + .probe = ak4118_probe, + .remove = ak4118_remove, + .dapm_widgets = ak4118_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(ak4118_dapm_widgets), + .dapm_routes = ak4118_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(ak4118_dapm_routes), + .idle_bias_on = 1, + .use_pmdown_time = 1, + .endianness = 1, + .non_legacy_dai_naming = 1, +}; + +static const struct regmap_config ak4118_regmap = { + .reg_bits = 8, + .val_bits = 8, + + .reg_defaults = ak4118_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(ak4118_reg_defaults), + + .cache_type = REGCACHE_NONE, + .max_register = AK4118_REG_MAX - 1, +}; + +static int ak4118_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct ak4118_priv *ak4118; + int ret; + + ak4118 = devm_kzalloc(&i2c->dev, sizeof(struct ak4118_priv), + GFP_KERNEL); + if (ak4118 == NULL) + return -ENOMEM; + + ak4118->regmap = devm_regmap_init_i2c(i2c, &ak4118_regmap); + if (IS_ERR(ak4118->regmap)) + return PTR_ERR(ak4118->regmap); + + i2c_set_clientdata(i2c, ak4118); + + ak4118->reset = devm_gpiod_get(&i2c->dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(ak4118->reset)) { + ret = PTR_ERR(ak4118->reset); + if (ret != -EPROBE_DEFER) + dev_err(&i2c->dev, "Failed to get reset: %d\n", ret); + return ret; + } + + ak4118->irq = devm_gpiod_get(&i2c->dev, "irq", GPIOD_IN); + if (IS_ERR(ak4118->irq)) { + ret = PTR_ERR(ak4118->irq); + if (ret != -EPROBE_DEFER) + dev_err(&i2c->dev, "Failed to get IRQ: %d\n", ret); + return ret; + } + + ret = devm_request_threaded_irq(&i2c->dev, gpiod_to_irq(ak4118->irq), + NULL, ak4118_irq_handler, + IRQF_TRIGGER_RISING | IRQF_ONESHOT, + "ak4118-irq", ak4118); + if (ret < 0) { + dev_err(&i2c->dev, "Fail to request_irq: %d\n", ret); + return ret; + } + + return snd_soc_register_component(&i2c->dev, &soc_component_drv_ak4118, + &ak4118_dai, 1); +} + +static int ak4118_i2c_remove(struct i2c_client *i2c) +{ + snd_soc_unregister_component(&i2c->dev); + return 0; +} + +static const struct of_device_id ak4118_of_match[] = { + { .compatible = "asahi-kasei,ak4118", }, + {} +}; +MODULE_DEVICE_TABLE(of, ak4118_of_match); + +static const struct i2c_device_id ak4118_id_table[] = { + { "ak4118", 0 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, ak4118_id_table); + +static struct i2c_driver ak4118_i2c_driver = { + .driver = { + .name = "ak4118", + .of_match_table = of_match_ptr(ak4118_of_match), + }, + .id_table = ak4118_id_table, + .probe = ak4118_i2c_probe, + .remove = ak4118_i2c_remove, +}; + +module_i2c_driver(ak4118_i2c_driver); + +MODULE_DESCRIPTION("Asahi Kasei AK4118 ALSA SoC driver"); +MODULE_AUTHOR("Adrien Charruel <adrien.charruel@devialet.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/ak4458.c b/sound/soc/codecs/ak4458.c index 299ada4dfaa0..70d4c89bd6fc 100644 --- a/sound/soc/codecs/ak4458.c +++ b/sound/soc/codecs/ak4458.c @@ -456,7 +456,7 @@ static int ak4458_startup(struct snd_pcm_substream *substream, return ret; } -static struct snd_soc_dai_ops ak4458_dai_ops = { +static const struct snd_soc_dai_ops ak4458_dai_ops = { .startup = ak4458_startup, .hw_params = ak4458_hw_params, .set_fmt = ak4458_set_dai_fmt, diff --git a/sound/soc/codecs/ak5558.c b/sound/soc/codecs/ak5558.c index 448bb90c9c8e..8179512129d3 100644 --- a/sound/soc/codecs/ak5558.c +++ b/sound/soc/codecs/ak5558.c @@ -130,16 +130,12 @@ static int ak5558_hw_params(struct snd_pcm_substream *substream, u8 bits; int pcm_width = max(params_physical_width(params), ak5558->slot_width); - /* set master/slave audio interface */ - bits = snd_soc_component_read32(component, AK5558_02_CONTROL1); - bits &= ~AK5558_BITS; - switch (pcm_width) { case 16: - bits |= AK5558_DIF_24BIT_MODE; + bits = AK5558_DIF_24BIT_MODE; break; case 32: - bits |= AK5558_DIF_32BIT_MODE; + bits = AK5558_DIF_32BIT_MODE; break; default: return -EINVAL; @@ -168,18 +164,15 @@ static int ak5558_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) } /* set master/slave audio interface */ - format = snd_soc_component_read32(component, AK5558_02_CONTROL1); - format &= ~AK5558_DIF; - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: - format |= AK5558_DIF_I2S_MODE; + format = AK5558_DIF_I2S_MODE; break; case SND_SOC_DAIFMT_LEFT_J: - format |= AK5558_DIF_MSB_MODE; + format = AK5558_DIF_MSB_MODE; break; case SND_SOC_DAIFMT_DSP_B: - format |= AK5558_DIF_MSB_MODE; + format = AK5558_DIF_MSB_MODE; break; default: return -EINVAL; @@ -246,7 +239,7 @@ static int ak5558_startup(struct snd_pcm_substream *substream, &ak5558_rate_constraints); } -static struct snd_soc_dai_ops ak5558_dai_ops = { +static const struct snd_soc_dai_ops ak5558_dai_ops = { .startup = ak5558_startup, .hw_params = ak5558_hw_params, diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index 3c266eeb89bf..33d74f163bd7 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c @@ -29,8 +29,8 @@ #include <linux/i2c.h> #include <linux/delay.h> #include <linux/regulator/consumer.h> +#include <linux/gpio/consumer.h> #include <linux/of_device.h> -#include <linux/of_gpio.h> /* * The codec isn't really big-endian or little-endian, since the I2S @@ -658,8 +658,8 @@ static const struct regmap_config cs4270_regmap = { static int cs4270_i2c_probe(struct i2c_client *i2c_client, const struct i2c_device_id *id) { - struct device_node *np = i2c_client->dev.of_node; struct cs4270_private *cs4270; + struct gpio_desc *reset_gpiod; unsigned int val; int ret, i; @@ -678,20 +678,11 @@ static int cs4270_i2c_probe(struct i2c_client *i2c_client, if (ret < 0) return ret; - /* See if we have a way to bring the codec out of reset */ - if (np) { - enum of_gpio_flags flags; - int gpio = of_get_named_gpio_flags(np, "reset-gpio", 0, &flags); - - if (gpio_is_valid(gpio)) { - ret = devm_gpio_request_one(&i2c_client->dev, gpio, - flags & OF_GPIO_ACTIVE_LOW ? - GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH, - "cs4270 reset"); - if (ret < 0) - return ret; - } - } + reset_gpiod = devm_gpiod_get_optional(&i2c_client->dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(reset_gpiod) && + PTR_ERR(reset_gpiod) == -EPROBE_DEFER) + return -EPROBE_DEFER; cs4270->regmap = devm_regmap_init_i2c(i2c_client, &cs4270_regmap); if (IS_ERR(cs4270->regmap)) diff --git a/sound/soc/codecs/dmic.c b/sound/soc/codecs/dmic.c index 71322e0410ee..da921da50ef0 100644 --- a/sound/soc/codecs/dmic.c +++ b/sound/soc/codecs/dmic.c @@ -30,9 +30,39 @@ #include <sound/soc.h> #include <sound/soc-dapm.h> +#define MAX_MODESWITCH_DELAY 70 +static int modeswitch_delay; +module_param(modeswitch_delay, uint, 0644); + +static int wakeup_delay; +module_param(wakeup_delay, uint, 0644); + struct dmic { struct gpio_desc *gpio_en; int wakeup_delay; + /* Delay after DMIC mode switch */ + int modeswitch_delay; +}; + +int dmic_daiops_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct dmic *dmic = snd_soc_component_get_drvdata(component); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_STOP: + if (dmic->modeswitch_delay) + mdelay(dmic->modeswitch_delay); + + break; + } + + return 0; +} + +static const struct snd_soc_dai_ops dmic_dai_ops = { + .trigger = dmic_daiops_trigger, }; static int dmic_aif_event(struct snd_soc_dapm_widget *w, @@ -68,6 +98,7 @@ static struct snd_soc_dai_driver dmic_dai = { | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE, }, + .ops = &dmic_dai_ops, }; static int dmic_component_probe(struct snd_soc_component *component) @@ -85,6 +116,15 @@ static int dmic_component_probe(struct snd_soc_component *component) device_property_read_u32(component->dev, "wakeup-delay-ms", &dmic->wakeup_delay); + device_property_read_u32(component->dev, "modeswitch-delay-ms", + &dmic->modeswitch_delay); + if (wakeup_delay) + dmic->wakeup_delay = wakeup_delay; + if (modeswitch_delay) + dmic->modeswitch_delay = modeswitch_delay; + + if (dmic->modeswitch_delay > MAX_MODESWITCH_DELAY) + dmic->modeswitch_delay = MAX_MODESWITCH_DELAY; snd_soc_component_set_drvdata(component, dmic); diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c index 2aaa83028e55..ffecdaaa8cf2 100644 --- a/sound/soc/codecs/hdac_hda.c +++ b/sound/soc/codecs/hdac_hda.c @@ -46,7 +46,7 @@ static int hdac_hda_dai_set_tdm_slot(struct snd_soc_dai *dai, static struct hda_pcm *snd_soc_find_pcm_from_dai(struct hdac_hda_priv *hda_pvt, struct snd_soc_dai *dai); -static struct snd_soc_dai_ops hdac_hda_dai_ops = { +static const struct snd_soc_dai_ops hdac_hda_dai_ops = { .startup = hdac_hda_dai_open, .shutdown = hdac_hda_dai_close, .prepare = hdac_hda_dai_prepare, diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 6216e502cf7b..3ab2949c1dfa 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -121,8 +121,16 @@ struct hdac_hdmi_dai_port_map { struct hdac_hdmi_cvt *cvt; }; +/* + * pin to port mapping table where the value indicate the pin number and + * the index indicate the port number with 1 base. + */ +static const int icl_pin2port_map[] = {0x4, 0x6, 0x8, 0xa, 0xb}; + struct hdac_hdmi_drv_data { unsigned int vendor_nid; + const int *port_map; /* pin to port mapping table */ + int port_num; }; struct hdac_hdmi_priv { @@ -1329,11 +1337,12 @@ static int hdac_hdmi_add_pin(struct hdac_device *hdev, hda_nid_t nid) return 0; } -#define INTEL_VENDOR_NID 0x08 -#define INTEL_GLK_VENDOR_NID 0x0b +#define INTEL_VENDOR_NID_0x2 0x02 +#define INTEL_VENDOR_NID_0x8 0x08 +#define INTEL_VENDOR_NID_0xb 0x0b #define INTEL_GET_VENDOR_VERB 0xf81 #define INTEL_SET_VENDOR_VERB 0x781 -#define INTEL_EN_DP12 0x02 /* enable DP 1.2 features */ +#define INTEL_EN_DP12 0x02 /* enable DP 1.2 features */ #define INTEL_EN_ALL_PIN_CVTS 0x01 /* enable 2nd & 3rd pins and convertors */ static void hdac_hdmi_skl_enable_all_pins(struct hdac_device *hdev) @@ -1538,7 +1547,26 @@ free_widgets: static int hdac_hdmi_pin2port(void *aptr, int pin) { - return pin - 4; /* map NID 0x05 -> port #1 */ + struct hdac_device *hdev = aptr; + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev); + const int *map = hdmi->drv_data->port_map; + int i; + + if (!hdmi->drv_data->port_num) + return pin - 4; /* map NID 0x05 -> port #1 */ + + /* + * looking for the pin number in the mapping table and return + * the index which indicate the port number + */ + for (i = 0; i < hdmi->drv_data->port_num; i++) { + if (pin == map[i]) + return i + 1; + } + + /* return -1 if pin number exceeds our expectation */ + dev_err(&hdev->dev, "Can't find the port for pin %d\n", pin); + return -1; } static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe) @@ -1549,9 +1577,18 @@ static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe) struct hdac_hdmi_port *hport = NULL; struct snd_soc_component *component = hdmi->component; int i; - - /* Don't know how this mapping is derived */ - hda_nid_t pin_nid = port + 0x04; + hda_nid_t pin_nid; + + if (!hdmi->drv_data->port_num) { + /* for legacy platforms */ + pin_nid = port + 0x04; + } else if (port < hdmi->drv_data->port_num) { + /* get pin number from the pin2port mapping table */ + pin_nid = hdmi->drv_data->port_map[port - 1]; + } else { + dev_err(&hdev->dev, "Can't find the pin for port %d\n", port); + return; + } dev_dbg(&hdev->dev, "%s: for pin:%d port=%d\n", __func__, pin_nid, pipe); @@ -1973,12 +2010,18 @@ static int hdac_hdmi_get_spk_alloc(struct hdac_device *hdev, int pcm_idx) return port->eld.info.spk_alloc; } +static struct hdac_hdmi_drv_data intel_icl_drv_data = { + .vendor_nid = INTEL_VENDOR_NID_0x2, + .port_map = icl_pin2port_map, + .port_num = ARRAY_SIZE(icl_pin2port_map), +}; + static struct hdac_hdmi_drv_data intel_glk_drv_data = { - .vendor_nid = INTEL_GLK_VENDOR_NID, + .vendor_nid = INTEL_VENDOR_NID_0xb, }; static struct hdac_hdmi_drv_data intel_drv_data = { - .vendor_nid = INTEL_VENDOR_NID, + .vendor_nid = INTEL_VENDOR_NID_0x8, }; static int hdac_hdmi_dev_probe(struct hdac_device *hdev) @@ -2246,6 +2289,8 @@ static const struct hda_device_id hdmi_list[] = { &intel_glk_drv_data), HDA_CODEC_EXT_ENTRY(0x8086280d, 0x100000, "Geminilake HDMI", &intel_glk_drv_data), + HDA_CODEC_EXT_ENTRY(0x8086280f, 0x100000, "Icelake HDMI", + &intel_icl_drv_data), {} }; diff --git a/sound/soc/codecs/max98373.c b/sound/soc/codecs/max98373.c index a09d01318f79..9c8616a7b61c 100644 --- a/sound/soc/codecs/max98373.c +++ b/sound/soc/codecs/max98373.c @@ -724,14 +724,39 @@ static struct snd_soc_dai_driver max98373_dai[] = { } }; +static void max98373_reset(struct max98373_priv *max98373, struct device *dev) +{ + int ret, reg, count; + + /* Software Reset */ + ret = regmap_update_bits(max98373->regmap, + MAX98373_R2000_SW_RESET, + MAX98373_SOFT_RESET, + MAX98373_SOFT_RESET); + if (ret) + dev_err(dev, "Reset command failed. (ret:%d)\n", ret); + + count = 0; + while (count < 3) { + usleep_range(10000, 11000); + /* Software Reset Verification */ + ret = regmap_read(max98373->regmap, + MAX98373_R21FF_REV_ID, ®); + if (!ret) { + dev_info(dev, "Reset completed (retry:%d)\n", count); + return; + } + count++; + } + dev_err(dev, "Reset failed. (ret:%d)\n", ret); +} + static int max98373_probe(struct snd_soc_component *component) { struct max98373_priv *max98373 = snd_soc_component_get_drvdata(component); /* Software Reset */ - regmap_write(max98373->regmap, - MAX98373_R2000_SW_RESET, MAX98373_SOFT_RESET); - usleep_range(10000, 11000); + max98373_reset(max98373, component->dev); /* IV default slot configuration */ regmap_write(max98373->regmap, @@ -818,9 +843,7 @@ static int max98373_resume(struct device *dev) { struct max98373_priv *max98373 = dev_get_drvdata(dev); - regmap_write(max98373->regmap, - MAX98373_R2000_SW_RESET, MAX98373_SOFT_RESET); - usleep_range(10000, 11000); + max98373_reset(max98373, dev); regcache_cache_only(max98373->regmap, false); regcache_sync(max98373->regmap); return 0; diff --git a/sound/soc/codecs/max9867.c b/sound/soc/codecs/max9867.c index 4ea3287162ad..8600c5439e1e 100644 --- a/sound/soc/codecs/max9867.c +++ b/sound/soc/codecs/max9867.c @@ -1,12 +1,10 @@ -/* - * max9867.c -- max9867 ALSA SoC Audio driver - * - * Copyright 2013-15 Maxim Integrated Products - * - * 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. - */ +// SPDX-License-Identifier: GPL-2.0 +// +// MAX9867 ALSA SoC codec driver +// +// Copyright 2013-2015 Maxim Integrated Products +// Copyright 2018 Ladislav Michl <ladis@linux-mips.org> +// #include <linux/delay.h> #include <linux/i2c.h> @@ -23,254 +21,237 @@ static const char *const max9867_spmode[] = { "Stereo Single", "Mono Single", "Stereo Single Fast", "Mono Single Fast" }; -static const char *const max9867_sidetone_text[] = { - "None", "Left", "Right", "LeftRight", "LeftRightDiv2", -}; static const char *const max9867_filter_text[] = {"IIR", "FIR"}; static SOC_ENUM_SINGLE_DECL(max9867_filter, MAX9867_CODECFLTR, 7, max9867_filter_text); static SOC_ENUM_SINGLE_DECL(max9867_spkmode, MAX9867_MODECONFIG, 0, max9867_spmode); -static SOC_ENUM_SINGLE_DECL(max9867_sidetone, MAX9867_DACGAIN, 6, - max9867_sidetone_text); -static DECLARE_TLV_DB_SCALE(max9860_capture_tlv, -600, 200, 0); -static DECLARE_TLV_DB_SCALE(max9860_mic_tlv, 2000, 100, 1); -static DECLARE_TLV_DB_SCALE(max9860_adc_left_tlv, -1200, 100, 1); -static DECLARE_TLV_DB_SCALE(max9860_adc_right_tlv, -1200, 100, 1); -static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(max98088_micboost_tlv, - 0, 1, TLV_DB_SCALE_ITEM(0, 2000, 0), - 2, 2, TLV_DB_SCALE_ITEM(3000, 0, 0), +static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(max9867_master_tlv, + 0, 2, TLV_DB_SCALE_ITEM(-8600, 200, 1), + 3, 17, TLV_DB_SCALE_ITEM(-7800, 400, 0), + 18, 25, TLV_DB_SCALE_ITEM(-2000, 200, 0), + 26, 34, TLV_DB_SCALE_ITEM( -500, 100, 0), + 35, 40, TLV_DB_SCALE_ITEM( 350, 50, 0), +); +static DECLARE_TLV_DB_SCALE(max9867_mic_tlv, 0, 100, 0); +static DECLARE_TLV_DB_SCALE(max9867_line_tlv, -600, 200, 0); +static DECLARE_TLV_DB_SCALE(max9867_adc_tlv, -1200, 100, 0); +static DECLARE_TLV_DB_SCALE(max9867_dac_tlv, -1500, 100, 0); +static DECLARE_TLV_DB_SCALE(max9867_dacboost_tlv, 0, 600, 0); +static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(max9867_micboost_tlv, + 0, 2, TLV_DB_SCALE_ITEM(-2000, 2000, 1), + 3, 3, TLV_DB_SCALE_ITEM(3000, 0, 0), ); static const struct snd_kcontrol_new max9867_snd_controls[] = { - SOC_DOUBLE_R("Master Playback Volume", MAX9867_LEFTVOL, - MAX9867_RIGHTVOL, 0, 63, 1), - SOC_DOUBLE_R_TLV("Capture Volume", MAX9867_LEFTMICGAIN, - MAX9867_RIGHTMICGAIN, - 0, 15, 1, max9860_capture_tlv), - SOC_DOUBLE_R_TLV("Mic Volume", MAX9867_LEFTMICGAIN, - MAX9867_RIGHTMICGAIN, 0, 31, 1, max9860_mic_tlv), - SOC_DOUBLE_R_TLV("Mic Boost Volume", MAX9867_LEFTMICGAIN, - MAX9867_RIGHTMICGAIN, 5, 3, 0, max98088_micboost_tlv), - SOC_ENUM("Digital Sidetone Src", max9867_sidetone), - SOC_SINGLE("Sidetone Volume", MAX9867_DACGAIN, 0, 31, 1), - SOC_SINGLE("DAC Volume", MAX9867_DACLEVEL, 4, 3, 0), - SOC_SINGLE("DAC Attenuation", MAX9867_DACLEVEL, 0, 15, 1), - SOC_SINGLE_TLV("ADC Left Volume", MAX9867_ADCLEVEL, - 4, 15, 1, max9860_adc_left_tlv), - SOC_SINGLE_TLV("ADC Right Volume", MAX9867_ADCLEVEL, - 0, 15, 1, max9860_adc_right_tlv), + SOC_DOUBLE_R_TLV("Master Playback Volume", MAX9867_LEFTVOL, + MAX9867_RIGHTVOL, 0, 41, 1, max9867_master_tlv), + SOC_DOUBLE_R_TLV("Line Capture Volume", MAX9867_LEFTLINELVL, + MAX9867_RIGHTLINELVL, 0, 15, 1, max9867_line_tlv), + SOC_DOUBLE_R_TLV("Mic Capture Volume", MAX9867_LEFTMICGAIN, + MAX9867_RIGHTMICGAIN, 0, 20, 1, max9867_mic_tlv), + SOC_DOUBLE_R_TLV("Mic Boost Capture Volume", MAX9867_LEFTMICGAIN, + MAX9867_RIGHTMICGAIN, 5, 4, 0, max9867_micboost_tlv), + SOC_SINGLE("Digital Sidetone Volume", MAX9867_SIDETONE, 0, 31, 1), + SOC_SINGLE_TLV("Digital Playback Volume", MAX9867_DACLEVEL, 0, 15, 1, + max9867_dac_tlv), + SOC_SINGLE_TLV("Digital Boost Playback Volume", MAX9867_DACLEVEL, 4, 3, 0, + max9867_dacboost_tlv), + SOC_DOUBLE_TLV("Digital Capture Volume", MAX9867_ADCLEVEL, 0, 4, 15, 1, + max9867_adc_tlv), SOC_ENUM("Speaker Mode", max9867_spkmode), SOC_SINGLE("Volume Smoothing Switch", MAX9867_MODECONFIG, 6, 1, 0), - SOC_SINGLE("ZCD Switch", MAX9867_MODECONFIG, 5, 1, 0), + SOC_SINGLE("Line ZC Switch", MAX9867_MODECONFIG, 5, 1, 0), SOC_ENUM("DSP Filter", max9867_filter), }; -static const char *const max9867_mux[] = {"None", "Mic", "Line", "Mic_Line"}; +/* Input mixer */ +static const struct snd_kcontrol_new max9867_input_mixer_controls[] = { + SOC_DAPM_DOUBLE("Line Capture Switch", MAX9867_INPUTCONFIG, 7, 5, 1, 0), + SOC_DAPM_DOUBLE("Mic Capture Switch", MAX9867_INPUTCONFIG, 6, 4, 1, 0), +}; + +/* Output mixer */ +static const struct snd_kcontrol_new max9867_output_mixer_controls[] = { + SOC_DAPM_DOUBLE_R("Line Bypass Switch", + MAX9867_LEFTLINELVL, MAX9867_RIGHTLINELVL, 6, 1, 1), +}; -static SOC_ENUM_SINGLE_DECL(max9867_mux_enum, - MAX9867_INPUTCONFIG, MAX9867_INPUT_SHIFT, - max9867_mux); +/* Sidetone mixer */ +static const struct snd_kcontrol_new max9867_sidetone_mixer_controls[] = { + SOC_DAPM_DOUBLE("Sidetone Switch", MAX9867_SIDETONE, 6, 7, 1, 0), +}; -static const struct snd_kcontrol_new max9867_dapm_mux_controls = - SOC_DAPM_ENUM("Route", max9867_mux_enum); +/* Line out switch */ +static const struct snd_kcontrol_new max9867_line_out_control = + SOC_DAPM_DOUBLE_R("Switch", + MAX9867_LEFTVOL, MAX9867_RIGHTVOL, 6, 1, 1); -static const struct snd_kcontrol_new max9867_left_dapm_control = - SOC_DAPM_SINGLE("Switch", MAX9867_PWRMAN, 6, 1, 0); -static const struct snd_kcontrol_new max9867_right_dapm_control = - SOC_DAPM_SINGLE("Switch", MAX9867_PWRMAN, 5, 1, 0); -static const struct snd_kcontrol_new max9867_line_dapm_control = - SOC_DAPM_SINGLE("Switch", MAX9867_LEFTLINELVL, 6, 1, 1); static const struct snd_soc_dapm_widget max9867_dapm_widgets[] = { - SND_SOC_DAPM_AIF_IN("DAI_OUT", "HiFi Playback", 0, SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_DAC("Left DAC", NULL, MAX9867_PWRMAN, 3, 0), - SND_SOC_DAPM_DAC("Right DAC", NULL, MAX9867_PWRMAN, 2, 0), - SND_SOC_DAPM_MIXER("Output Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_OUTPUT("HPOUT"), - - SND_SOC_DAPM_AIF_IN("DAI_IN", "HiFi Capture", 0, SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_ADC("Left ADC", "HiFi Capture", MAX9867_PWRMAN, 1, 0), - SND_SOC_DAPM_ADC("Right ADC", "HiFi Capture", MAX9867_PWRMAN, 0, 0), - SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, - &max9867_dapm_mux_controls), - - SND_SOC_DAPM_MIXER("Input Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_SWITCH("Left Line", MAX9867_LEFTLINELVL, 6, 1, - &max9867_left_dapm_control), - SND_SOC_DAPM_SWITCH("Right Line", MAX9867_RIGTHLINELVL, 6, 1, - &max9867_right_dapm_control), - SND_SOC_DAPM_SWITCH("Line Mixer", SND_SOC_NOPM, 0, 0, - &max9867_line_dapm_control), - SND_SOC_DAPM_INPUT("LINE_IN"), + SND_SOC_DAPM_INPUT("MICL"), + SND_SOC_DAPM_INPUT("MICR"), + SND_SOC_DAPM_INPUT("LINL"), + SND_SOC_DAPM_INPUT("LINR"), + + SND_SOC_DAPM_PGA("Left Line Input", MAX9867_PWRMAN, 6, 0, NULL, 0), + SND_SOC_DAPM_PGA("Right Line Input", MAX9867_PWRMAN, 5, 0, NULL, 0), + SND_SOC_DAPM_MIXER_NAMED_CTL("Input Mixer", SND_SOC_NOPM, 0, 0, + max9867_input_mixer_controls, + ARRAY_SIZE(max9867_input_mixer_controls)), + SND_SOC_DAPM_ADC("ADCL", "HiFi Capture", MAX9867_PWRMAN, 1, 0), + SND_SOC_DAPM_ADC("ADCR", "HiFi Capture", MAX9867_PWRMAN, 0, 0), + + SND_SOC_DAPM_MIXER("Digital", SND_SOC_NOPM, 0, 0, + max9867_sidetone_mixer_controls, + ARRAY_SIZE(max9867_sidetone_mixer_controls)), + SND_SOC_DAPM_MIXER_NAMED_CTL("Output Mixer", SND_SOC_NOPM, 0, 0, + max9867_output_mixer_controls, + ARRAY_SIZE(max9867_output_mixer_controls)), + SND_SOC_DAPM_DAC("DACL", "HiFi Playback", MAX9867_PWRMAN, 3, 0), + SND_SOC_DAPM_DAC("DACR", "HiFi Playback", MAX9867_PWRMAN, 2, 0), + SND_SOC_DAPM_SWITCH("Master Playback", SND_SOC_NOPM, 0, 0, + &max9867_line_out_control), + SND_SOC_DAPM_OUTPUT("LOUT"), + SND_SOC_DAPM_OUTPUT("ROUT"), }; static const struct snd_soc_dapm_route max9867_audio_map[] = { - {"Left DAC", NULL, "DAI_OUT"}, - {"Right DAC", NULL, "DAI_OUT"}, - {"Output Mixer", NULL, "Left DAC"}, - {"Output Mixer", NULL, "Right DAC"}, - {"HPOUT", NULL, "Output Mixer"}, - - {"Left ADC", NULL, "DAI_IN"}, - {"Right ADC", NULL, "DAI_IN"}, - {"Input Mixer", NULL, "Left ADC"}, - {"Input Mixer", NULL, "Right ADC"}, - {"Input Mux", "Line", "Input Mixer"}, - {"Input Mux", "Mic", "Input Mixer"}, - {"Input Mux", "Mic_Line", "Input Mixer"}, - {"Right Line", "Switch", "Input Mux"}, - {"Left Line", "Switch", "Input Mux"}, - {"LINE_IN", NULL, "Left Line"}, - {"LINE_IN", NULL, "Right Line"}, + {"Left Line Input", NULL, "LINL"}, + {"Right Line Input", NULL, "LINR"}, + {"Input Mixer", "Mic Capture Switch", "MICL"}, + {"Input Mixer", "Mic Capture Switch", "MICR"}, + {"Input Mixer", "Line Capture Switch", "Left Line Input"}, + {"Input Mixer", "Line Capture Switch", "Right Line Input"}, + {"ADCL", NULL, "Input Mixer"}, + {"ADCR", NULL, "Input Mixer"}, + + {"Digital", "Sidetone Switch", "ADCL"}, + {"Digital", "Sidetone Switch", "ADCR"}, + {"DACL", NULL, "Digital"}, + {"DACR", NULL, "Digital"}, + + {"Output Mixer", "Line Bypass Switch", "Left Line Input"}, + {"Output Mixer", "Line Bypass Switch", "Right Line Input"}, + {"Output Mixer", NULL, "DACL"}, + {"Output Mixer", NULL, "DACR"}, + {"Master Playback", "Switch", "Output Mixer"}, + {"LOUT", NULL, "Master Playback"}, + {"ROUT", NULL, "Master Playback"}, +}; + +static const unsigned int max9867_rates_44k1[] = { + 11025, 22050, 44100, +}; + +static const struct snd_pcm_hw_constraint_list max9867_constraints_44k1 = { + .list = max9867_rates_44k1, + .count = ARRAY_SIZE(max9867_rates_44k1), }; -enum rates { - pcm_rate_8, pcm_rate_16, pcm_rate_24, - pcm_rate_32, pcm_rate_44, - pcm_rate_48, max_pcm_rate, +static const unsigned int max9867_rates_48k[] = { + 8000, 16000, 32000, 48000, }; -static const struct ni_div_rates { - u32 mclk; - u16 ni[max_pcm_rate]; -} ni_div[] = { - {11289600, {0x116A, 0x22D4, 0x343F, 0x45A9, 0x6000, 0x687D} }, - {12000000, {0x1062, 0x20C5, 0x3127, 0x4189, 0x5A51, 0x624E} }, - {12288000, {0x1000, 0x2000, 0x3000, 0x4000, 0x5833, 0x6000} }, - {13000000, {0x0F20, 0x1E3F, 0x2D5F, 0x3C7F, 0x535F, 0x5ABE} }, - {19200000, {0x0A3D, 0x147B, 0x1EB8, 0x28F6, 0x3873, 0x3D71} }, - {24000000, {0x1062, 0x20C5, 0x1893, 0x4189, 0x5A51, 0x624E} }, - {26000000, {0x0F20, 0x1E3F, 0x16AF, 0x3C7F, 0x535F, 0x5ABE} }, - {27000000, {0x0E90, 0x1D21, 0x15D8, 0x3A41, 0x5048, 0x5762} }, +static const struct snd_pcm_hw_constraint_list max9867_constraints_48k = { + .list = max9867_rates_48k, + .count = ARRAY_SIZE(max9867_rates_48k), }; -static inline int get_ni_value(int mclk, int rate) +struct max9867_priv { + struct regmap *regmap; + const struct snd_pcm_hw_constraint_list *constraints; + unsigned int sysclk, pclk; + bool master, dsp_a; +}; + +static int max9867_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { - int i, ret = 0; + struct max9867_priv *max9867 = + snd_soc_component_get_drvdata(dai->component); - /* find the closest rate index*/ - for (i = 0; i < ARRAY_SIZE(ni_div); i++) { - if (ni_div[i].mclk >= mclk) - break; - } - if (i == ARRAY_SIZE(ni_div)) - return -EINVAL; + if (max9867->constraints) + snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, max9867->constraints); - switch (rate) { - case 8000: - return ni_div[i].ni[pcm_rate_8]; - case 16000: - return ni_div[i].ni[pcm_rate_16]; - case 32000: - return ni_div[i].ni[pcm_rate_32]; - case 44100: - return ni_div[i].ni[pcm_rate_44]; - case 48000: - return ni_div[i].ni[pcm_rate_48]; - default: - pr_err("%s wrong rate %d\n", __func__, rate); - ret = -EINVAL; - } - return ret; + return 0; } static int max9867_dai_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { + int value; + unsigned long int rate, ratio; struct snd_soc_component *component = dai->component; struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component); - unsigned int ni_h, ni_l; - int value; + unsigned int ni = DIV_ROUND_CLOSEST_ULL(96ULL * 0x10000 * params_rate(params), + max9867->pclk); - value = get_ni_value(max9867->sysclk, params_rate(params)); - if (value < 0) - return value; - - ni_h = (0xFF00 & value) >> 8; - ni_l = 0x00FF & value; /* set up the ni value */ regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKHIGH, - MAX9867_NI_HIGH_MASK, ni_h); + MAX9867_NI_HIGH_MASK, (0xFF00 & ni) >> 8); regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKLOW, - MAX9867_NI_LOW_MASK, ni_l); - if (!max9867->master) { - /* - * digital pll locks on to any externally supplied LRCLK signal - * and also enable rapid lock mode. - */ - regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKLOW, - MAX9867_RAPID_LOCK, MAX9867_RAPID_LOCK); - regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKHIGH, - MAX9867_PLL, MAX9867_PLL); - } else { - unsigned long int bclk_rate, pclk_bclk_ratio; - int bclk_value; - - bclk_rate = params_rate(params) * 2 * params_width(params); - pclk_bclk_ratio = max9867->pclk/bclk_rate; - switch (params_width(params)) { - case 8: - case 16: - switch (pclk_bclk_ratio) { - case 2: - bclk_value = MAX9867_IFC1B_PCLK_2; - break; - case 4: - bclk_value = MAX9867_IFC1B_PCLK_4; - break; + MAX9867_NI_LOW_MASK, 0x00FF & ni); + if (max9867->master) { + if (max9867->dsp_a) { + value = MAX9867_IFC1B_48X; + } else { + rate = params_rate(params) * 2 * params_width(params); + ratio = max9867->pclk / rate; + switch (params_width(params)) { case 8: - bclk_value = MAX9867_IFC1B_PCLK_8; - break; case 16: - bclk_value = MAX9867_IFC1B_PCLK_16; + switch (ratio) { + case 2: + value = MAX9867_IFC1B_PCLK_2; + break; + case 4: + value = MAX9867_IFC1B_PCLK_4; + break; + case 8: + value = MAX9867_IFC1B_PCLK_8; + break; + case 16: + value = MAX9867_IFC1B_PCLK_16; + break; + default: + return -EINVAL; + } + break; + case 24: + value = MAX9867_IFC1B_48X; + break; + case 32: + value = MAX9867_IFC1B_64X; break; default: - dev_err(component->dev, - "unsupported sampling rate\n"); return -EINVAL; } - break; - case 24: - bclk_value = MAX9867_IFC1B_24BIT; - break; - case 32: - bclk_value = MAX9867_IFC1B_32BIT; - break; - default: - dev_err(component->dev, "unsupported sampling rate\n"); - return -EINVAL; } regmap_update_bits(max9867->regmap, MAX9867_IFC1B, - MAX9867_IFC1B_BCLK_MASK, bclk_value); + MAX9867_IFC1B_BCLK_MASK, value); + } else { + /* + * digital pll locks on to any externally supplied LRCLK signal + * and also enable rapid lock mode. + */ + regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKLOW, + MAX9867_RAPID_LOCK, MAX9867_RAPID_LOCK); + regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKHIGH, + MAX9867_PLL, MAX9867_PLL); } return 0; } -static int max9867_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct snd_soc_component *component = dai->component; - struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component); - - regmap_update_bits(max9867->regmap, MAX9867_PWRMAN, - MAX9867_SHTDOWN_MASK, MAX9867_SHTDOWN_MASK); - return 0; -} - static int max9867_mute(struct snd_soc_dai *dai, int mute) { struct snd_soc_component *component = dai->component; struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component); - if (mute) - regmap_update_bits(max9867->regmap, MAX9867_DACLEVEL, - MAX9867_DAC_MUTE_MASK, MAX9867_DAC_MUTE_MASK); - else - regmap_update_bits(max9867->regmap, MAX9867_DACLEVEL, - MAX9867_DAC_MUTE_MASK, 0); - return 0; + return regmap_update_bits(max9867->regmap, MAX9867_DACLEVEL, + 1 << 6, !!mute << 6); } static int max9867_set_dai_sysclk(struct snd_soc_dai *codec_dai, @@ -283,21 +264,29 @@ static int max9867_set_dai_sysclk(struct snd_soc_dai *codec_dai, /* Set the prescaler based on the master clock frequency*/ if (freq >= 10000000 && freq <= 20000000) { value |= MAX9867_PSCLK_10_20; - max9867->pclk = freq; + max9867->pclk = freq; } else if (freq >= 20000000 && freq <= 40000000) { value |= MAX9867_PSCLK_20_40; - max9867->pclk = freq/2; + max9867->pclk = freq / 2; } else if (freq >= 40000000 && freq <= 60000000) { value |= MAX9867_PSCLK_40_60; - max9867->pclk = freq/4; + max9867->pclk = freq / 4; } else { dev_err(component->dev, "Invalid clock frequency %uHz (required 10-60MHz)\n", freq); return -EINVAL; } - value = value << MAX9867_PSCLK_SHIFT; + if (freq % 48000 == 0) + max9867->constraints = &max9867_constraints_48k; + else if (freq % 44100 == 0) + max9867->constraints = &max9867_constraints_44k1; + else + dev_warn(component->dev, + "Unable to set exact rate with %uHz clock frequency\n", + freq); max9867->sysclk = freq; + value = value << MAX9867_PSCLK_SHIFT; /* exact integer mode is not supported */ value &= ~MAX9867_FREQ_MASK; regmap_update_bits(max9867->regmap, MAX9867_SYSCLK, @@ -310,16 +299,17 @@ static int max9867_dai_set_fmt(struct snd_soc_dai *codec_dai, { struct snd_soc_component *component = codec_dai->component; struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component); - u8 iface1A = 0, iface1B = 0; + u8 iface1A, iface1B; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBM_CFM: - max9867->master = 1; - iface1A |= MAX9867_MASTER; + max9867->master = true; + iface1A = MAX9867_MASTER; + iface1B = MAX9867_IFC1B_48X; break; case SND_SOC_DAIFMT_CBS_CFS: - max9867->master = 0; - iface1A &= ~MAX9867_MASTER; + max9867->master = false; + iface1A = iface1B = 0; break; default: return -EINVAL; @@ -327,9 +317,11 @@ static int max9867_dai_set_fmt(struct snd_soc_dai *codec_dai, switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: + max9867->dsp_a = false; iface1A |= MAX9867_I2S_DLY; break; case SND_SOC_DAIFMT_DSP_A: + max9867->dsp_a = true; iface1A |= MAX9867_TDM_MODE | MAX9867_SDOUT_HIZ; break; default: @@ -355,21 +347,18 @@ static int max9867_dai_set_fmt(struct snd_soc_dai *codec_dai, regmap_write(max9867->regmap, MAX9867_IFC1A, iface1A); regmap_write(max9867->regmap, MAX9867_IFC1B, iface1B); + return 0; } static const struct snd_soc_dai_ops max9867_dai_ops = { - .set_fmt = max9867_dai_set_fmt, .set_sysclk = max9867_set_dai_sysclk, - .prepare = max9867_prepare, + .set_fmt = max9867_dai_set_fmt, .digital_mute = max9867_mute, - .hw_params = max9867_dai_hw_params, + .startup = max9867_startup, + .hw_params = max9867_dai_hw_params, }; -#define MAX9867_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ - SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) -#define MAX9867_FORMATS (SNDRV_PCM_FMTBIT_S16_LE) - static struct snd_soc_dai_driver max9867_dai[] = { { .name = "max9867-aif1", @@ -377,42 +366,74 @@ static struct snd_soc_dai_driver max9867_dai[] = { .stream_name = "HiFi Playback", .channels_min = 2, .channels_max = 2, - .rates = MAX9867_RATES, - .formats = MAX9867_FORMATS, + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, }, .capture = { .stream_name = "HiFi Capture", .channels_min = 2, .channels_max = 2, - .rates = MAX9867_RATES, - .formats = MAX9867_FORMATS, + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, }, .ops = &max9867_dai_ops, .symmetric_rates = 1, } }; -#ifdef CONFIG_PM_SLEEP -static int max9867_suspend(struct device *dev) +#ifdef CONFIG_PM +static int max9867_suspend(struct snd_soc_component *component) { - struct max9867_priv *max9867 = dev_get_drvdata(dev); + snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF); - /* Drop down to power saving mode when system is suspended */ - regmap_update_bits(max9867->regmap, MAX9867_PWRMAN, - MAX9867_SHTDOWN_MASK, ~MAX9867_SHTDOWN_MASK); return 0; } -static int max9867_resume(struct device *dev) +static int max9867_resume(struct snd_soc_component *component) { - struct max9867_priv *max9867 = dev_get_drvdata(dev); + snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY); - regmap_update_bits(max9867->regmap, MAX9867_PWRMAN, - MAX9867_SHTDOWN_MASK, MAX9867_SHTDOWN_MASK); return 0; } +#else +#define max9867_suspend NULL +#define max9867_resume NULL #endif +static int max9867_set_bias_level(struct snd_soc_component *component, + enum snd_soc_bias_level level) +{ + int err; + struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component); + + switch (level) { + case SND_SOC_BIAS_STANDBY: + if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) { + err = regcache_sync(max9867->regmap); + if (err) + return err; + + err = regmap_update_bits(max9867->regmap, MAX9867_PWRMAN, + MAX9867_SHTDOWN, MAX9867_SHTDOWN); + if (err) + return err; + } + break; + case SND_SOC_BIAS_OFF: + err = regmap_update_bits(max9867->regmap, MAX9867_PWRMAN, + MAX9867_SHTDOWN, 0); + if (err) + return err; + + regcache_mark_dirty(max9867->regmap); + break; + default: + break; + } + + return 0; +} + static const struct snd_soc_component_driver max9867_component = { .controls = max9867_snd_controls, .num_controls = ARRAY_SIZE(max9867_snd_controls), @@ -420,6 +441,9 @@ static const struct snd_soc_component_driver max9867_component = { .num_dapm_routes = ARRAY_SIZE(max9867_audio_map), .dapm_widgets = max9867_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(max9867_dapm_widgets), + .suspend = max9867_suspend, + .resume = max9867_resume, + .set_bias_level = max9867_set_bias_level, .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, @@ -450,8 +474,8 @@ static const struct reg_default max9867_reg[] = { { 0x0B, 0x00 }, { 0x0C, 0x00 }, { 0x0D, 0x00 }, - { 0x0E, 0x00 }, - { 0x0F, 0x00 }, + { 0x0E, 0x40 }, + { 0x0F, 0x40 }, { 0x10, 0x00 }, { 0x11, 0x00 }, { 0x12, 0x00 }, @@ -476,10 +500,9 @@ static int max9867_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct max9867_priv *max9867; - int ret = 0, reg; + int ret, reg; - max9867 = devm_kzalloc(&i2c->dev, - sizeof(*max9867), GFP_KERNEL); + max9867 = devm_kzalloc(&i2c->dev, sizeof(*max9867), GFP_KERNEL); if (!max9867) return -ENOMEM; @@ -490,8 +513,7 @@ static int max9867_i2c_probe(struct i2c_client *i2c, dev_err(&i2c->dev, "Failed to allocate regmap: %d\n", ret); return ret; } - ret = regmap_read(max9867->regmap, - MAX9867_REVISION, ®); + ret = regmap_read(max9867->regmap, MAX9867_REVISION, ®); if (ret < 0) { dev_err(&i2c->dev, "Failed to read: %d\n", ret); return ret; @@ -499,10 +521,8 @@ static int max9867_i2c_probe(struct i2c_client *i2c, dev_info(&i2c->dev, "device revision: %x\n", reg); ret = devm_snd_soc_register_component(&i2c->dev, &max9867_component, max9867_dai, ARRAY_SIZE(max9867_dai)); - if (ret < 0) { + if (ret < 0) dev_err(&i2c->dev, "Failed to register component: %d\n", ret); - return ret; - } return ret; } @@ -518,15 +538,10 @@ static const struct of_device_id max9867_of_match[] = { }; MODULE_DEVICE_TABLE(of, max9867_of_match); -static const struct dev_pm_ops max9867_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(max9867_suspend, max9867_resume) -}; - static struct i2c_driver max9867_i2c_driver = { .driver = { .name = "max9867", .of_match_table = of_match_ptr(max9867_of_match), - .pm = &max9867_pm_ops, }, .probe = max9867_i2c_probe, .id_table = max9867_i2c_id, @@ -534,6 +549,6 @@ static struct i2c_driver max9867_i2c_driver = { module_i2c_driver(max9867_i2c_driver); -MODULE_AUTHOR("anish kumar <yesanishhere@gmail.com>"); -MODULE_DESCRIPTION("ALSA SoC MAX9867 driver"); +MODULE_AUTHOR("Ladislav Michl <ladis@linux-mips.org>"); +MODULE_DESCRIPTION("ASoC MAX9867 driver"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/max9867.h b/sound/soc/codecs/max9867.h index 55cd9976ff47..2277798291a1 100644 --- a/sound/soc/codecs/max9867.h +++ b/sound/soc/codecs/max9867.h @@ -26,13 +26,11 @@ #define MAX9867_PSCLK_10_20 0x1 #define MAX9867_PSCLK_20_40 0x2 #define MAX9867_PSCLK_40_60 0x3 -#define MAX9867_AUDIOCLKHIGH 0x06 -#define MAX9867_NI_HIGH_WIDTH 0x7 -#define MAX9867_NI_HIGH_MASK 0x7F -#define MAX9867_NI_LOW_MASK 0x7F -#define MAX9867_NI_LOW_SHIFT 0x1 -#define MAX9867_PLL (1<<7) -#define MAX9867_AUDIOCLKLOW 0x07 +#define MAX9867_AUDIOCLKHIGH 0x06 +#define MAX9867_NI_HIGH_MASK 0x7F +#define MAX9867_NI_LOW_MASK 0xFE +#define MAX9867_PLL (1<<7) +#define MAX9867_AUDIOCLKLOW 0x07 #define MAX9867_RAPID_LOCK 0x01 #define MAX9867_IFC1A 0x08 #define MAX9867_MASTER (1<<7) @@ -43,40 +41,29 @@ #define MAX9867_BCI_MODE (1<<5) #define MAX9867_IFC1B 0x09 #define MAX9867_IFC1B_BCLK_MASK 7 -#define MAX9867_IFC1B_32BIT 0x01 -#define MAX9867_IFC1B_24BIT 0x02 -#define MAX9867_IFC1B_PCLK_2 4 -#define MAX9867_IFC1B_PCLK_4 5 -#define MAX9867_IFC1B_PCLK_8 6 -#define MAX9867_IFC1B_PCLK_16 7 +#define MAX9867_IFC1B_64X 0x01 +#define MAX9867_IFC1B_48X 0x02 +#define MAX9867_IFC1B_PCLK_2 0x04 +#define MAX9867_IFC1B_PCLK_4 0x05 +#define MAX9867_IFC1B_PCLK_8 0x06 +#define MAX9867_IFC1B_PCLK_16 0x07 #define MAX9867_CODECFLTR 0x0a -#define MAX9867_DACGAIN 0x0b +#define MAX9867_SIDETONE 0x0b #define MAX9867_DACLEVEL 0x0c -#define MAX9867_DAC_MUTE_SHIFT 0x6 -#define MAX9867_DAC_MUTE_WIDTH 0x1 -#define MAX9867_DAC_MUTE_MASK (0x1<<MAX9867_DAC_MUTE_SHIFT) #define MAX9867_ADCLEVEL 0x0d #define MAX9867_LEFTLINELVL 0x0e -#define MAX9867_RIGTHLINELVL 0x0f +#define MAX9867_RIGHTLINELVL 0x0f #define MAX9867_LEFTVOL 0x10 #define MAX9867_RIGHTVOL 0x11 #define MAX9867_LEFTMICGAIN 0x12 #define MAX9867_RIGHTMICGAIN 0x13 #define MAX9867_INPUTCONFIG 0x14 -#define MAX9867_INPUT_SHIFT 0x6 #define MAX9867_MICCONFIG 0x15 #define MAX9867_MODECONFIG 0x16 #define MAX9867_PWRMAN 0x17 -#define MAX9867_SHTDOWN_MASK (1<<7) +#define MAX9867_SHTDOWN 0x80 #define MAX9867_REVISION 0xff #define MAX9867_CACHEREGNUM 10 -/* codec private data */ -struct max9867_priv { - struct regmap *regmap; - unsigned int sysclk; - unsigned int pclk; - unsigned int master; -}; #endif diff --git a/sound/soc/codecs/nau8540.c b/sound/soc/codecs/nau8540.c index e3c8cd17daf2..4dd1a609756b 100644 --- a/sound/soc/codecs/nau8540.c +++ b/sound/soc/codecs/nau8540.c @@ -585,7 +585,7 @@ static int nau8540_calc_fll_param(unsigned int fll_in, fvco_max = 0; fvco_sel = ARRAY_SIZE(mclk_src_scaling); for (i = 0; i < ARRAY_SIZE(mclk_src_scaling); i++) { - fvco = 256 * fs * 2 * mclk_src_scaling[i].param; + fvco = 256ULL * fs * 2 * mclk_src_scaling[i].param; if (fvco > NAU_FVCO_MIN && fvco < NAU_FVCO_MAX && fvco_max < fvco) { fvco_max = fvco; diff --git a/sound/soc/codecs/nau8822.c b/sound/soc/codecs/nau8822.c index 622ce947f134..c6152a044416 100644 --- a/sound/soc/codecs/nau8822.c +++ b/sound/soc/codecs/nau8822.c @@ -1,18 +1,14 @@ -/* - * nau8822.c -- NAU8822 ALSA Soc Audio Codec driver - * - * Copyright 2017 Nuvoton Technology Corp. - * - * Author: David Lin <ctlin0@nuvoton.com> - * Co-author: John Hsu <kchsu0@nuvoton.com> - * Co-author: Seven Li <wtli@nuvoton.com> - * - * Based on WM8974.c - * - * 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. - */ +// SPDX-License-Identifier: GPL-2.0 +// +// nau8822.c -- NAU8822 ALSA Soc Audio driver +// +// Copyright 2017 Nuvoton Technology Crop. +// +// Author: David Lin <ctlin0@nuvoton.com> +// Co-author: John Hsu <kchsu0@nuvoton.com> +// Co-author: Seven Li <wtli@nuvoton.com> +// +// Based on WM8974.c #include <linux/module.h> #include <linux/moduleparam.h> diff --git a/sound/soc/codecs/nau8822.h b/sound/soc/codecs/nau8822.h index aa79c969cd44..9c552983a293 100644 --- a/sound/soc/codecs/nau8822.h +++ b/sound/soc/codecs/nau8822.h @@ -1,13 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* - * nau8822.h -- NAU8822 Soc Audio Codec driver + * nau8822.h -- NAU8822 ALSA SoC Audio driver + * + * Copyright 2017 Nuvoton Technology Crop. * * Author: David Lin <ctlin0@nuvoton.com> * Co-author: John Hsu <kchsu0@nuvoton.com> * Co-author: Seven Li <wtli@nuvoton.com> - * - * 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 __NAU8822_H__ diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c index b9fed99d8b5e..7bbcbf5f05c8 100644 --- a/sound/soc/codecs/nau8825.c +++ b/sound/soc/codecs/nau8825.c @@ -424,10 +424,8 @@ static u32 nau8825_xtalk_sidetone(u32 sig_org, u32 sig_cros) { u32 gain, sidetone; - if (unlikely(sig_org == 0) || unlikely(sig_cros == 0)) { - WARN_ON(1); + if (WARN_ON(sig_org == 0 || sig_cros == 0)) return 0; - } sig_org = nau8825_intlog10_dec3(sig_org); sig_cros = nau8825_intlog10_dec3(sig_cros); diff --git a/sound/soc/codecs/pcm3060.c b/sound/soc/codecs/pcm3060.c index 771b46e1974b..6714aa8d9026 100644 --- a/sound/soc/codecs/pcm3060.c +++ b/sound/soc/codecs/pcm3060.c @@ -198,19 +198,25 @@ static const struct snd_kcontrol_new pcm3060_dapm_controls[] = { }; static const struct snd_soc_dapm_widget pcm3060_dapm_widgets[] = { + SND_SOC_DAPM_DAC("DAC", "Playback", PCM3060_REG64, + PCM3060_REG_SHIFT_DAPSV, 1), + SND_SOC_DAPM_OUTPUT("OUTL"), SND_SOC_DAPM_OUTPUT("OUTR"), SND_SOC_DAPM_INPUT("INL"), SND_SOC_DAPM_INPUT("INR"), + + SND_SOC_DAPM_ADC("ADC", "Capture", PCM3060_REG64, + PCM3060_REG_SHIFT_ADPSV, 1), }; static const struct snd_soc_dapm_route pcm3060_dapm_map[] = { - { "OUTL", NULL, "Playback" }, - { "OUTR", NULL, "Playback" }, + { "OUTL", NULL, "DAC" }, + { "OUTR", NULL, "DAC" }, - { "Capture", NULL, "INL" }, - { "Capture", NULL, "INR" }, + { "ADC", NULL, "INL" }, + { "ADC", NULL, "INR" }, }; /* soc component */ @@ -270,9 +276,23 @@ EXPORT_SYMBOL(pcm3060_regmap); /* device */ +static void pcm3060_parse_dt(const struct device_node *np, + struct pcm3060_priv *priv) +{ + priv->out_se = of_property_read_bool(np, "ti,out-single-ended"); +} + int pcm3060_probe(struct device *dev) { int rc; + struct pcm3060_priv *priv = dev_get_drvdata(dev); + + if (dev->of_node) + pcm3060_parse_dt(dev->of_node, priv); + + if (priv->out_se) + regmap_update_bits(priv->regmap, PCM3060_REG64, + PCM3060_REG_SE, PCM3060_REG_SE); rc = devm_snd_soc_register_component(dev, &pcm3060_soc_comp_driver, pcm3060_dai, diff --git a/sound/soc/codecs/pcm3060.h b/sound/soc/codecs/pcm3060.h index fd89a68aa8a7..6a027b4a845d 100644 --- a/sound/soc/codecs/pcm3060.h +++ b/sound/soc/codecs/pcm3060.h @@ -25,6 +25,7 @@ struct pcm3060_priv_dai { struct pcm3060_priv { struct regmap *regmap; struct pcm3060_priv_dai dai[PCM3060_DAI_IDS_NUM]; + u8 out_se: 1; }; int pcm3060_probe(struct device *dev); @@ -36,7 +37,9 @@ int pcm3060_remove(struct device *dev); #define PCM3060_REG_MRST 0x80 #define PCM3060_REG_SRST 0x40 #define PCM3060_REG_ADPSV 0x20 +#define PCM3060_REG_SHIFT_ADPSV 0x05 #define PCM3060_REG_DAPSV 0x10 +#define PCM3060_REG_SHIFT_DAPSV 0x04 #define PCM3060_REG_SE 0x01 #define PCM3060_REG65 0x41 diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c index 52cc950c9fd1..08d3fe192e65 100644 --- a/sound/soc/codecs/pcm3168a.c +++ b/sound/soc/codecs/pcm3168a.c @@ -133,10 +133,6 @@ static const struct snd_kcontrol_new pcm3168a_snd_controls[] = { SOC_DOUBLE("DAC2 Invert Switch", PCM3168A_DAC_INV, 2, 3, 1, 0), SOC_DOUBLE("DAC3 Invert Switch", PCM3168A_DAC_INV, 4, 5, 1, 0), SOC_DOUBLE("DAC4 Invert Switch", PCM3168A_DAC_INV, 6, 7, 1, 0), - SOC_DOUBLE_STS("DAC1 Zero Flag", PCM3168A_DAC_ZERO, 0, 1, 1, 0), - SOC_DOUBLE_STS("DAC2 Zero Flag", PCM3168A_DAC_ZERO, 2, 3, 1, 0), - SOC_DOUBLE_STS("DAC3 Zero Flag", PCM3168A_DAC_ZERO, 4, 5, 1, 0), - SOC_DOUBLE_STS("DAC4 Zero Flag", PCM3168A_DAC_ZERO, 6, 7, 1, 0), SOC_ENUM("DAC Volume Control Type", pcm3168a_dac_volume_type), SOC_ENUM("DAC Volume Rate Multiplier", pcm3168a_dac_att_mult), SOC_ENUM("DAC De-Emphasis", pcm3168a_dac_demp), @@ -176,9 +172,6 @@ static const struct snd_kcontrol_new pcm3168a_snd_controls[] = { SOC_DOUBLE("ADC1 Mute Switch", PCM3168A_ADC_MUTE, 0, 1, 1, 0), SOC_DOUBLE("ADC2 Mute Switch", PCM3168A_ADC_MUTE, 2, 3, 1, 0), SOC_DOUBLE("ADC3 Mute Switch", PCM3168A_ADC_MUTE, 4, 5, 1, 0), - SOC_DOUBLE_STS("ADC1 Overflow Flag", PCM3168A_ADC_OV, 0, 1, 1, 0), - SOC_DOUBLE_STS("ADC2 Overflow Flag", PCM3168A_ADC_OV, 2, 3, 1, 0), - SOC_DOUBLE_STS("ADC3 Overflow Flag", PCM3168A_ADC_OV, 4, 5, 1, 0), SOC_ENUM("ADC Volume Control Type", pcm3168a_adc_volume_type), SOC_ENUM("ADC Volume Rate Multiplier", pcm3168a_adc_att_mult), SOC_ENUM("ADC Overflow Flag Polarity", pcm3168a_adc_ov_pol), @@ -504,6 +497,10 @@ static int pcm3168a_startup(struct snd_pcm_substream *substream, unsigned int fmt; unsigned int sample_min; unsigned int channel_max; + unsigned int channel_maxs[] = { + 6, /* rx */ + 8 /* tx */ + }; if (tx) fmt = pcm3168a->dac_fmt; @@ -528,18 +525,9 @@ static int pcm3168a_startup(struct snd_pcm_substream *substream, channel_max = 2; break; case PCM3168A_FMT_LEFT_J: - sample_min = 24; - if (tx) - channel_max = 8; - else - channel_max = 6; - break; case PCM3168A_FMT_I2S: sample_min = 24; - if (tx) - channel_max = 8; - else - channel_max = 6; + channel_max = channel_maxs[tx]; break; default: sample_min = 24; @@ -770,15 +758,22 @@ err_clk: } EXPORT_SYMBOL_GPL(pcm3168a_probe); -void pcm3168a_remove(struct device *dev) +static void pcm3168a_disable(struct device *dev) { struct pcm3168a_priv *pcm3168a = dev_get_drvdata(dev); - pm_runtime_disable(dev); regulator_bulk_disable(ARRAY_SIZE(pcm3168a->supplies), - pcm3168a->supplies); + pcm3168a->supplies); clk_disable_unprepare(pcm3168a->scki); } + +void pcm3168a_remove(struct device *dev) +{ + pm_runtime_disable(dev); +#ifndef CONFIG_PM + pcm3168a_disable(dev); +#endif +} EXPORT_SYMBOL_GPL(pcm3168a_remove); #ifdef CONFIG_PM @@ -833,10 +828,7 @@ static int pcm3168a_rt_suspend(struct device *dev) regcache_cache_only(pcm3168a->regmap, true); - regulator_bulk_disable(ARRAY_SIZE(pcm3168a->supplies), - pcm3168a->supplies); - - clk_disable_unprepare(pcm3168a->scki); + pcm3168a_disable(dev); return 0; } diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c index f0f2d4fd3769..6cb1653be804 100644 --- a/sound/soc/codecs/pcm512x.c +++ b/sound/soc/codecs/pcm512x.c @@ -53,6 +53,8 @@ struct pcm512x_priv { unsigned long overclock_pll; unsigned long overclock_dac; unsigned long overclock_dsp; + int mute; + struct mutex mutex; }; /* @@ -384,6 +386,61 @@ static const struct soc_enum pcm512x_veds = SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_2, PCM512x_VEDS_SHIFT, 4, pcm512x_ramp_step_text); +static int pcm512x_update_mute(struct pcm512x_priv *pcm512x) +{ + return regmap_update_bits( + pcm512x->regmap, PCM512x_MUTE, PCM512x_RQML | PCM512x_RQMR, + (!!(pcm512x->mute & 0x5) << PCM512x_RQML_SHIFT) + | (!!(pcm512x->mute & 0x3) << PCM512x_RQMR_SHIFT)); +} + +static int pcm512x_digital_playback_switch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); + + mutex_lock(&pcm512x->mutex); + ucontrol->value.integer.value[0] = !(pcm512x->mute & 0x4); + ucontrol->value.integer.value[1] = !(pcm512x->mute & 0x2); + mutex_unlock(&pcm512x->mutex); + + return 0; +} + +static int pcm512x_digital_playback_switch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); + int ret, changed = 0; + + mutex_lock(&pcm512x->mutex); + + if ((pcm512x->mute & 0x4) == (ucontrol->value.integer.value[0] << 2)) { + pcm512x->mute ^= 0x4; + changed = 1; + } + if ((pcm512x->mute & 0x2) == (ucontrol->value.integer.value[1] << 1)) { + pcm512x->mute ^= 0x2; + changed = 1; + } + + if (changed) { + ret = pcm512x_update_mute(pcm512x); + if (ret != 0) { + dev_err(component->dev, + "Failed to update digital mute: %d\n", ret); + mutex_unlock(&pcm512x->mutex); + return ret; + } + } + + mutex_unlock(&pcm512x->mutex); + + return changed; +} + static const struct snd_kcontrol_new pcm512x_controls[] = { SOC_DOUBLE_R_TLV("Digital Playback Volume", PCM512x_DIGITAL_VOLUME_2, PCM512x_DIGITAL_VOLUME_3, 0, 255, 1, digital_tlv), @@ -391,8 +448,15 @@ SOC_DOUBLE_TLV("Analogue Playback Volume", PCM512x_ANALOG_GAIN_CTRL, PCM512x_LAGN_SHIFT, PCM512x_RAGN_SHIFT, 1, 1, analog_tlv), SOC_DOUBLE_TLV("Analogue Playback Boost Volume", PCM512x_ANALOG_GAIN_BOOST, PCM512x_AGBL_SHIFT, PCM512x_AGBR_SHIFT, 1, 0, boost_tlv), -SOC_DOUBLE("Digital Playback Switch", PCM512x_MUTE, PCM512x_RQML_SHIFT, - PCM512x_RQMR_SHIFT, 1, 1), +{ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Digital Playback Switch", + .index = 0, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = snd_ctl_boolean_stereo_info, + .get = pcm512x_digital_playback_switch_get, + .put = pcm512x_digital_playback_switch_put +}, SOC_SINGLE("Deemphasis Switch", PCM512x_DSP, PCM512x_DEMP_SHIFT, 1, 1), SOC_ENUM("DSP Program", pcm512x_dsp_program), @@ -1319,10 +1383,61 @@ static int pcm512x_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return 0; } +static int pcm512x_digital_mute(struct snd_soc_dai *dai, int mute) +{ + struct snd_soc_component *component = dai->component; + struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); + int ret; + unsigned int mute_det; + + mutex_lock(&pcm512x->mutex); + + if (mute) { + pcm512x->mute |= 0x1; + ret = regmap_update_bits(pcm512x->regmap, PCM512x_MUTE, + PCM512x_RQML | PCM512x_RQMR, + PCM512x_RQML | PCM512x_RQMR); + if (ret != 0) { + dev_err(component->dev, + "Failed to set digital mute: %d\n", ret); + mutex_unlock(&pcm512x->mutex); + return ret; + } + + regmap_read_poll_timeout(pcm512x->regmap, + PCM512x_ANALOG_MUTE_DET, + mute_det, (mute_det & 0x3) == 0, + 200, 10000); + + mutex_unlock(&pcm512x->mutex); + } else { + pcm512x->mute &= ~0x1; + ret = pcm512x_update_mute(pcm512x); + if (ret != 0) { + dev_err(component->dev, + "Failed to update digital mute: %d\n", ret); + mutex_unlock(&pcm512x->mutex); + return ret; + } + + regmap_read_poll_timeout(pcm512x->regmap, + PCM512x_ANALOG_MUTE_DET, + mute_det, + (mute_det & 0x3) + == ((~pcm512x->mute >> 1) & 0x3), + 200, 10000); + } + + mutex_unlock(&pcm512x->mutex); + + return 0; +} + static const struct snd_soc_dai_ops pcm512x_dai_ops = { .startup = pcm512x_dai_startup, .hw_params = pcm512x_hw_params, .set_fmt = pcm512x_set_fmt, + .digital_mute = pcm512x_digital_mute, }; static struct snd_soc_dai_driver pcm512x_dai = { @@ -1388,6 +1503,8 @@ int pcm512x_probe(struct device *dev, struct regmap *regmap) if (!pcm512x) return -ENOMEM; + mutex_init(&pcm512x->mutex); + dev_set_drvdata(dev, pcm512x); pcm512x->regmap = regmap; diff --git a/sound/soc/codecs/pcm512x.h b/sound/soc/codecs/pcm512x.h index d70d9c0c2088..9dda8693498e 100644 --- a/sound/soc/codecs/pcm512x.h +++ b/sound/soc/codecs/pcm512x.h @@ -112,7 +112,9 @@ #define PCM512x_RQST_SHIFT 4 /* Page 0, Register 3 - mute */ +#define PCM512x_RQMR (1 << 0) #define PCM512x_RQMR_SHIFT 0 +#define PCM512x_RQML (1 << 4) #define PCM512x_RQML_SHIFT 4 /* Page 0, Register 4 - PLL */ diff --git a/sound/soc/codecs/rt5660.c b/sound/soc/codecs/rt5660.c index 27f7445b2432..e74b2e8cd423 100644 --- a/sound/soc/codecs/rt5660.c +++ b/sound/soc/codecs/rt5660.c @@ -1246,6 +1246,7 @@ MODULE_DEVICE_TABLE(of, rt5660_of_match); static const struct acpi_device_id rt5660_acpi_match[] = { { "10EC5660", 0 }, + { "10EC3277", 0 }, { }, }; MODULE_DEVICE_TABLE(acpi, rt5660_acpi_match); diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c index 7eb2cbd39d6e..da6647015708 100644 --- a/sound/soc/codecs/rt5663.c +++ b/sound/soc/codecs/rt5663.c @@ -17,6 +17,7 @@ #include <linux/platform_device.h> #include <linux/spi/spi.h> #include <linux/acpi.h> +#include <linux/regulator/consumer.h> #include <linux/workqueue.h> #include <sound/core.h> #include <sound/pcm.h> @@ -33,6 +34,9 @@ #define RT5663_DEVICE_ID_2 0x6451 #define RT5663_DEVICE_ID_1 0x6406 +#define RT5663_POWER_ON_DELAY_MS 300 +#define RT5663_SUPPLY_CURRENT_UA 500000 + enum { CODEC_VER_1, CODEC_VER_0, @@ -48,6 +52,11 @@ struct impedance_mapping_table { unsigned int dc_offset_r_manual_mic; }; +static const char *const rt5663_supply_names[] = { + "avdd", + "cpvdd", +}; + struct rt5663_priv { struct snd_soc_component *component; struct rt5663_platform_data pdata; @@ -56,6 +65,7 @@ struct rt5663_priv { struct snd_soc_jack *hs_jack; struct timer_list btn_check_timer; struct impedance_mapping_table *imp_table; + struct regulator_bulk_data supplies[ARRAY_SIZE(rt5663_supply_names)]; int codec_ver; int sysclk; @@ -3483,7 +3493,7 @@ static int rt5663_i2c_probe(struct i2c_client *i2c, { struct rt5663_platform_data *pdata = dev_get_platdata(&i2c->dev); struct rt5663_priv *rt5663; - int ret; + int ret, i; unsigned int val; struct regmap *regmap; @@ -3500,12 +3510,44 @@ static int rt5663_i2c_probe(struct i2c_client *i2c, else rt5663_parse_dp(rt5663, &i2c->dev); + for (i = 0; i < ARRAY_SIZE(rt5663->supplies); i++) + rt5663->supplies[i].supply = rt5663_supply_names[i]; + + ret = devm_regulator_bulk_get(&i2c->dev, + ARRAY_SIZE(rt5663->supplies), + rt5663->supplies); + if (ret) { + dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret); + return ret; + } + + /* Set load for regulator. */ + for (i = 0; i < ARRAY_SIZE(rt5663->supplies); i++) { + ret = regulator_set_load(rt5663->supplies[i].consumer, + RT5663_SUPPLY_CURRENT_UA); + if (ret < 0) { + dev_err(&i2c->dev, + "Failed to set regulator load on %s, ret: %d\n", + rt5663->supplies[i].supply, ret); + return ret; + } + } + + ret = regulator_bulk_enable(ARRAY_SIZE(rt5663->supplies), + rt5663->supplies); + + if (ret) { + dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret); + return ret; + } + msleep(RT5663_POWER_ON_DELAY_MS); + regmap = devm_regmap_init_i2c(i2c, &temp_regmap); if (IS_ERR(regmap)) { ret = PTR_ERR(regmap); dev_err(&i2c->dev, "Failed to allocate temp register map: %d\n", ret); - return ret; + goto err_enable; } ret = regmap_read(regmap, RT5663_VENDOR_ID_2, &val); @@ -3530,14 +3572,15 @@ static int rt5663_i2c_probe(struct i2c_client *i2c, dev_err(&i2c->dev, "Device with ID register %#x is not rt5663\n", val); - return -ENODEV; + ret = -ENODEV; + goto err_enable; } if (IS_ERR(rt5663->regmap)) { ret = PTR_ERR(rt5663->regmap); dev_err(&i2c->dev, "Failed to allocate register map: %d\n", ret); - return ret; + goto err_enable; } /* reset and calibrate */ @@ -3635,20 +3678,32 @@ static int rt5663_i2c_probe(struct i2c_client *i2c, ret = request_irq(i2c->irq, rt5663_irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "rt5663", rt5663); - if (ret) + if (ret) { dev_err(&i2c->dev, "%s Failed to reguest IRQ: %d\n", __func__, ret); + goto err_enable; + } } ret = devm_snd_soc_register_component(&i2c->dev, &soc_component_dev_rt5663, rt5663_dai, ARRAY_SIZE(rt5663_dai)); - if (ret) { - if (i2c->irq) - free_irq(i2c->irq, rt5663); - } + if (ret) + goto err_enable; + return 0; + + + /* + * Error after enabling regulators should goto err_enable + * to disable regulators. + */ +err_enable: + if (i2c->irq) + free_irq(i2c->irq, rt5663); + + regulator_bulk_disable(ARRAY_SIZE(rt5663->supplies), rt5663->supplies); return ret; } @@ -3659,6 +3714,8 @@ static int rt5663_i2c_remove(struct i2c_client *i2c) if (i2c->irq) free_irq(i2c->irq, rt5663); + regulator_bulk_disable(ARRAY_SIZE(rt5663->supplies), rt5663->supplies); + return 0; } diff --git a/sound/soc/codecs/simple-amplifier.c b/sound/soc/codecs/simple-amplifier.c index 85524acf3e9c..c07e8a80b4b7 100644 --- a/sound/soc/codecs/simple-amplifier.c +++ b/sound/soc/codecs/simple-amplifier.c @@ -19,6 +19,7 @@ #include <linux/gpio/consumer.h> #include <linux/module.h> +#include <linux/regulator/consumer.h> #include <sound/soc.h> #define DRV_NAME "simple-amplifier" @@ -58,11 +59,14 @@ static const struct snd_soc_dapm_widget simple_amp_dapm_widgets[] = { (SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD)), SND_SOC_DAPM_OUTPUT("OUTL"), SND_SOC_DAPM_OUTPUT("OUTR"), + SND_SOC_DAPM_REGULATOR_SUPPLY("VCC", 20, 0), }; static const struct snd_soc_dapm_route simple_amp_dapm_routes[] = { { "DRV", NULL, "INL" }, { "DRV", NULL, "INR" }, + { "OUTL", NULL, "VCC" }, + { "OUTR", NULL, "VCC" }, { "OUTL", NULL, "DRV" }, { "OUTR", NULL, "DRV" }, }; diff --git a/sound/soc/codecs/tas6424.c b/sound/soc/codecs/tas6424.c index 36aebdb8f55c..aaba39295079 100644 --- a/sound/soc/codecs/tas6424.c +++ b/sound/soc/codecs/tas6424.c @@ -378,7 +378,7 @@ static struct snd_soc_component_driver soc_codec_dev_tas6424 = { .non_legacy_dai_naming = 1, }; -static struct snd_soc_dai_ops tas6424_speaker_dai_ops = { +static const struct snd_soc_dai_ops tas6424_speaker_dai_ops = { .hw_params = tas6424_hw_params, .set_fmt = tas6424_set_dai_fmt, .set_tdm_slot = tas6424_set_dai_tdm_slot, diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index 608ad49ad978..c6048d95c6d3 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -1095,7 +1095,7 @@ static int aic31xx_set_dai_sysclk(struct snd_soc_dai *codec_dai, if (freq/i > 20000000) { dev_err(aic31xx->dev, "%s: Too high mclk frequency %u\n", __func__, freq); - return -EINVAL; + return -EINVAL; } aic31xx->p_div = i; diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 6a271e6e6b8f..6aa0edf8c5ef 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -1260,6 +1260,16 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai, aic3x->master = 0; iface_areg &= ~(BIT_CLK_MASTER | WORD_CLK_MASTER); break; + case SND_SOC_DAIFMT_CBM_CFS: + aic3x->master = 1; + iface_areg |= BIT_CLK_MASTER; + iface_areg &= ~WORD_CLK_MASTER; + break; + case SND_SOC_DAIFMT_CBS_CFM: + aic3x->master = 1; + iface_areg |= WORD_CLK_MASTER; + iface_areg &= ~BIT_CLK_MASTER; + break; default: return -EINVAL; } diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index a957eaeb7bc1..32907b1e20cf 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c @@ -394,7 +394,7 @@ static int dac33_hard_power(struct snd_soc_component *component, int power) if (ret != 0) { dev_err(component->dev, "Failed to enable supplies: %d\n", ret); - goto exit; + goto exit; } if (dac33->power_gpio >= 0) diff --git a/sound/soc/codecs/wm8998.c b/sound/soc/codecs/wm8998.c index 61294c787f27..409bed30a4e4 100644 --- a/sound/soc/codecs/wm8998.c +++ b/sound/soc/codecs/wm8998.c @@ -60,7 +60,7 @@ static int wm8998_asrc_ev(struct snd_soc_dapm_widget *w, dev_warn(component->dev, "Unsupported ASRC rate1 (%s)\n", arizona_sample_rate_val_to_name(val)); - return -EINVAL; + return -EINVAL; } break; default: diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c index ccdf088461b7..54c306707c02 100644 --- a/sound/soc/codecs/wm9705.c +++ b/sound/soc/codecs/wm9705.c @@ -325,8 +325,7 @@ static int wm9705_soc_probe(struct snd_soc_component *component) if (wm9705->mfd_pdata) { wm9705->ac97 = wm9705->mfd_pdata->ac97; regmap = wm9705->mfd_pdata->regmap; - } else { -#ifdef CONFIG_SND_SOC_AC97_BUS + } else if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS)) { wm9705->ac97 = snd_soc_new_ac97_component(component, WM9705_VENDOR_ID, WM9705_VENDOR_ID_MASK); if (IS_ERR(wm9705->ac97)) { @@ -339,7 +338,8 @@ static int wm9705_soc_probe(struct snd_soc_component *component) snd_soc_free_ac97_component(wm9705->ac97); return PTR_ERR(regmap); } -#endif + } else { + return -ENXIO; } snd_soc_component_set_drvdata(component, wm9705->ac97); @@ -350,14 +350,12 @@ static int wm9705_soc_probe(struct snd_soc_component *component) static void wm9705_soc_remove(struct snd_soc_component *component) { -#ifdef CONFIG_SND_SOC_AC97_BUS struct wm9705_priv *wm9705 = snd_soc_component_get_drvdata(component); - if (!wm9705->mfd_pdata) { + if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS) && !wm9705->mfd_pdata) { snd_soc_component_exit_regmap(component); snd_soc_free_ac97_component(wm9705->ac97); } -#endif } static const struct snd_soc_component_driver soc_component_dev_wm9705 = { diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index e873baa9e778..01949eaba4fd 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -642,8 +642,7 @@ static int wm9712_soc_probe(struct snd_soc_component *component) if (wm9712->mfd_pdata) { wm9712->ac97 = wm9712->mfd_pdata->ac97; regmap = wm9712->mfd_pdata->regmap; - } else { -#ifdef CONFIG_SND_SOC_AC97_BUS + } else if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS)) { int ret; wm9712->ac97 = snd_soc_new_ac97_component(component, WM9712_VENDOR_ID, @@ -660,7 +659,8 @@ static int wm9712_soc_probe(struct snd_soc_component *component) snd_soc_free_ac97_component(wm9712->ac97); return PTR_ERR(regmap); } -#endif + } else { + return -ENXIO; } snd_soc_component_init_regmap(component, regmap); @@ -673,14 +673,12 @@ static int wm9712_soc_probe(struct snd_soc_component *component) static void wm9712_soc_remove(struct snd_soc_component *component) { -#ifdef CONFIG_SND_SOC_AC97_BUS struct wm9712_priv *wm9712 = snd_soc_component_get_drvdata(component); - if (!wm9712->mfd_pdata) { + if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS) && !wm9712->mfd_pdata) { snd_soc_component_exit_regmap(component); snd_soc_free_ac97_component(wm9712->ac97); } -#endif } static const struct snd_soc_component_driver soc_component_dev_wm9712 = { diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index 643863bb32e0..5a2fdf4f69bf 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -1214,8 +1214,7 @@ static int wm9713_soc_probe(struct snd_soc_component *component) if (wm9713->mfd_pdata) { wm9713->ac97 = wm9713->mfd_pdata->ac97; regmap = wm9713->mfd_pdata->regmap; - } else { -#ifdef CONFIG_SND_SOC_AC97_BUS + } else if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS)) { wm9713->ac97 = snd_soc_new_ac97_component(component, WM9713_VENDOR_ID, WM9713_VENDOR_ID_MASK); if (IS_ERR(wm9713->ac97)) @@ -1225,7 +1224,8 @@ static int wm9713_soc_probe(struct snd_soc_component *component) snd_soc_free_ac97_component(wm9713->ac97); return PTR_ERR(regmap); } -#endif + } else { + return -ENXIO; } snd_soc_component_init_regmap(component, regmap); @@ -1238,14 +1238,12 @@ static int wm9713_soc_probe(struct snd_soc_component *component) static void wm9713_soc_remove(struct snd_soc_component *component) { -#ifdef CONFIG_SND_SOC_AC97_BUS struct wm9713_priv *wm9713 = snd_soc_component_get_drvdata(component); - if (!wm9713->mfd_pdata) { + if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS) && !wm9713->mfd_pdata) { snd_soc_component_exit_regmap(component); snd_soc_free_ac97_component(wm9713->ac97); } -#endif } static const struct snd_soc_component_driver soc_component_dev_wm9713 = { diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 66501b8dc46f..1dd291cebe67 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -2419,7 +2419,7 @@ static int wm_adsp_create_name(struct wm_adsp *dsp) return 0; } -int wm_adsp1_init(struct wm_adsp *dsp) +static int wm_adsp_common_init(struct wm_adsp *dsp) { int ret; @@ -2428,11 +2428,17 @@ int wm_adsp1_init(struct wm_adsp *dsp) return ret; INIT_LIST_HEAD(&dsp->alg_regions); + INIT_LIST_HEAD(&dsp->ctl_list); mutex_init(&dsp->pwr_lock); return 0; } + +int wm_adsp1_init(struct wm_adsp *dsp) +{ + return wm_adsp_common_init(dsp); +} EXPORT_SYMBOL_GPL(wm_adsp1_init); int wm_adsp1_event(struct snd_soc_dapm_widget *w, @@ -2917,7 +2923,7 @@ int wm_adsp2_init(struct wm_adsp *dsp) { int ret; - ret = wm_adsp_create_name(dsp); + ret = wm_adsp_common_init(dsp); if (ret) return ret; @@ -2939,12 +2945,8 @@ int wm_adsp2_init(struct wm_adsp *dsp) break; } - INIT_LIST_HEAD(&dsp->alg_regions); - INIT_LIST_HEAD(&dsp->ctl_list); INIT_WORK(&dsp->boot_work, wm_adsp2_boot_work); - mutex_init(&dsp->pwr_lock); - return 0; } EXPORT_SYMBOL_GPL(wm_adsp2_init); |