From 34157f7bec8276b4296cf2ec172fc13385ac8af7 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 20 Feb 2017 21:58:34 +0100 Subject: ASoC: rsnd: drop useles self-assignments Coverity reported (CID 1397992) this self-assignment. I think the code stays readable even with the assignments removed. Signed-off-by: Wolfram Sang Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 948c5ec87980..72966bdd3daa 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -674,12 +674,10 @@ static int rsnd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) /* set clock inversion */ switch (fmt & SND_SOC_DAIFMT_INV_MASK) { case SND_SOC_DAIFMT_NB_IF: - rdai->bit_clk_inv = rdai->bit_clk_inv; rdai->frm_clk_inv = !rdai->frm_clk_inv; break; case SND_SOC_DAIFMT_IB_NF: rdai->bit_clk_inv = !rdai->bit_clk_inv; - rdai->frm_clk_inv = rdai->frm_clk_inv; break; case SND_SOC_DAIFMT_IB_IF: rdai->bit_clk_inv = !rdai->bit_clk_inv; -- cgit v1.2.1 From 56d2c61d611a50e58dba521be1325dc90f9cc933 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 20 Feb 2017 22:05:07 +0100 Subject: ASoC: rsnd: check return value of init function Currently, this function cannot fail for the ADG case. Still, let's apply defensive programming techniques to make sure we fail gracefully whenever rsnd_mod_init() gets extended with another failure case. Reported by Coverity (CID 1397893). Signed-off-by: Wolfram Sang Signed-off-by: Mark Brown --- sound/soc/sh/rcar/adg.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index 85a33ac0a5c4..54146f66538c 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -564,6 +564,7 @@ int rsnd_adg_probe(struct rsnd_priv *priv) struct rsnd_adg *adg; struct device *dev = rsnd_priv_to_dev(priv); struct device_node *np = dev->of_node; + int ret; adg = devm_kzalloc(dev, sizeof(*adg), GFP_KERNEL); if (!adg) { @@ -571,8 +572,10 @@ int rsnd_adg_probe(struct rsnd_priv *priv) return -ENOMEM; } - rsnd_mod_init(priv, &adg->mod, &adg_ops, + ret = rsnd_mod_init(priv, &adg->mod, &adg_ops, NULL, NULL, 0, 0); + if (ret) + return ret; rsnd_adg_get_clkin(priv, adg); rsnd_adg_get_clkout(priv, adg); -- cgit v1.2.1 From 870e0ddc4345e71239bfe4af03ad47976b5fa502 Mon Sep 17 00:00:00 2001 From: Baoyou Xie Date: Thu, 16 Feb 2017 19:05:06 +0800 Subject: ASoC: zx-tdm: add zte's tdm controller driver This patch adds tdm controller driver for zte's SoC family. Signed-off-by: Baoyou Xie Reviewed-by: Shawn Guo Signed-off-by: Mark Brown --- sound/soc/zte/Kconfig | 8 + sound/soc/zte/Makefile | 1 + sound/soc/zte/zx-tdm.c | 461 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 470 insertions(+) create mode 100644 sound/soc/zte/zx-tdm.c (limited to 'sound/soc') diff --git a/sound/soc/zte/Kconfig b/sound/soc/zte/Kconfig index 6d8a90d36315..75f67a5d23ea 100644 --- a/sound/soc/zte/Kconfig +++ b/sound/soc/zte/Kconfig @@ -15,3 +15,11 @@ config ZX_I2S help Say Y or M if you want to add support for codecs attached to the ZTE ZX I2S interface + +config ZX_TDM + tristate "ZTE ZX TDM Driver Support" + depends on COMMON_CLK + select SND_SOC_GENERIC_DMAENGINE_PCM + help + Say Y or M if you want to add support for codecs attached to the + ZTE ZX TDM interface diff --git a/sound/soc/zte/Makefile b/sound/soc/zte/Makefile index 77768f5fd10c..1fc841acdfdd 100644 --- a/sound/soc/zte/Makefile +++ b/sound/soc/zte/Makefile @@ -1,2 +1,3 @@ obj-$(CONFIG_ZX_SPDIF) += zx-spdif.o obj-$(CONFIG_ZX_I2S) += zx-i2s.o +obj-$(CONFIG_ZX_TDM) += zx-tdm.o diff --git a/sound/soc/zte/zx-tdm.c b/sound/soc/zte/zx-tdm.c new file mode 100644 index 000000000000..bd632cc503b3 --- /dev/null +++ b/sound/soc/zte/zx-tdm.c @@ -0,0 +1,461 @@ +/* + * ZTE's TDM driver + * + * Copyright (C) 2017 ZTE Ltd + * + * Author: Baoyou Xie + * + * License terms: GNU General Public License (GPL) version 2 + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define REG_TIMING_CTRL 0x04 +#define REG_TX_FIFO_CTRL 0x0C +#define REG_RX_FIFO_CTRL 0x10 +#define REG_INT_EN 0x1C +#define REG_INT_STATUS 0x20 +#define REG_DATABUF 0x24 +#define REG_TS_MASK0 0x44 +#define REG_PROCESS_CTRL 0x54 + +#define FIFO_CTRL_TX_RST BIT(0) +#define FIFO_CTRL_RX_RST BIT(0) +#define DEAGULT_FIFO_THRES GENMASK(4, 2) + +#define FIFO_CTRL_TX_DMA_EN BIT(1) +#define FIFO_CTRL_RX_DMA_EN BIT(1) + +#define TX_FIFO_RST_MASK BIT(0) +#define RX_FIFO_RST_MASK BIT(0) + +#define FIFOCTRL_TX_FIFO_RST BIT(0) +#define FIFOCTRL_RX_FIFO_RST BIT(0) + +#define TXTH_MASK GENMASK(5, 2) +#define RXTH_MASK GENMASK(5, 2) + +#define FIFOCTRL_THRESHOLD(x) ((x) << 2) + +#define TIMING_MS_MASK BIT(1) +/* + * 00: 8 clk cycles every timeslot + * 01: 16 clk cycles every timeslot + * 10: 32 clk cycles every timeslot + */ +#define TIMING_SYNC_WIDTH_MASK GENMASK(6, 5) +#define TIMING_WIDTH_SHIFT 5 +#define TIMING_DEFAULT_WIDTH 0 +#define TIMING_TS_WIDTH(x) ((x) << TIMING_WIDTH_SHIFT) +#define TIMING_WIDTH_FACTOR 8 + +#define TIMING_MASTER_MODE BIT(21) +#define TIMING_LSB_FIRST BIT(20) +#define TIMING_TS_NUM(x) (((x) - 1) << 7) +#define TIMING_CLK_SEL_MASK GENMASK(2, 0) +#define TIMING_CLK_SEL_DEF BIT(2) + +#define PROCESS_TX_EN BIT(0) +#define PROCESS_RX_EN BIT(1) +#define PROCESS_TDM_EN BIT(2) +#define PROCESS_DISABLE_ALL 0 + +#define INT_DISABLE_ALL 0 +#define INT_STATUS_MASK GENMASK(6, 0) + +struct zx_tdm_info { + struct snd_dmaengine_dai_dma_data dma_playback; + struct snd_dmaengine_dai_dma_data dma_capture; + resource_size_t phy_addr; + void __iomem *regbase; + struct clk *dai_wclk; + struct clk *dai_pclk; + int master; + struct device *dev; +}; + +static inline u32 zx_tdm_readl(struct zx_tdm_info *tdm, u16 reg) +{ + return readl_relaxed(tdm->regbase + reg); +} + +static inline void zx_tdm_writel(struct zx_tdm_info *tdm, u16 reg, u32 val) +{ + writel_relaxed(val, tdm->regbase + reg); +} + +static void zx_tdm_tx_en(struct zx_tdm_info *tdm, bool on) +{ + unsigned long val; + + val = zx_tdm_readl(tdm, REG_PROCESS_CTRL); + if (on) + val |= PROCESS_TX_EN | PROCESS_TDM_EN; + else + val &= ~(PROCESS_TX_EN | PROCESS_TDM_EN); + zx_tdm_writel(tdm, REG_PROCESS_CTRL, val); +} + +static void zx_tdm_rx_en(struct zx_tdm_info *tdm, bool on) +{ + unsigned long val; + + val = zx_tdm_readl(tdm, REG_PROCESS_CTRL); + if (on) + val |= PROCESS_RX_EN | PROCESS_TDM_EN; + else + val &= ~(PROCESS_RX_EN | PROCESS_TDM_EN); + zx_tdm_writel(tdm, REG_PROCESS_CTRL, val); +} + +static void zx_tdm_tx_dma_en(struct zx_tdm_info *tdm, bool on) +{ + unsigned long val; + + val = zx_tdm_readl(tdm, REG_TX_FIFO_CTRL); + val |= FIFO_CTRL_TX_RST | DEAGULT_FIFO_THRES; + if (on) + val |= FIFO_CTRL_TX_DMA_EN; + else + val &= ~FIFO_CTRL_TX_DMA_EN; + zx_tdm_writel(tdm, REG_TX_FIFO_CTRL, val); +} + +static void zx_tdm_rx_dma_en(struct zx_tdm_info *tdm, bool on) +{ + unsigned long val; + + val = zx_tdm_readl(tdm, REG_RX_FIFO_CTRL); + val |= FIFO_CTRL_RX_RST | DEAGULT_FIFO_THRES; + if (on) + val |= FIFO_CTRL_RX_DMA_EN; + else + val &= ~FIFO_CTRL_RX_DMA_EN; + zx_tdm_writel(tdm, REG_RX_FIFO_CTRL, val); +} + +#define ZX_TDM_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000) + +#define ZX_TDM_FMTBIT \ + (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_MU_LAW | \ + SNDRV_PCM_FORMAT_A_LAW) + +static int zx_tdm_dai_probe(struct snd_soc_dai *dai) +{ + struct zx_tdm_info *zx_tdm = dev_get_drvdata(dai->dev); + + snd_soc_dai_set_drvdata(dai, zx_tdm); + zx_tdm->dma_playback.addr = zx_tdm->phy_addr + REG_DATABUF; + zx_tdm->dma_playback.maxburst = 16; + zx_tdm->dma_capture.addr = zx_tdm->phy_addr + REG_DATABUF; + zx_tdm->dma_capture.maxburst = 16; + snd_soc_dai_init_dma_data(dai, &zx_tdm->dma_playback, + &zx_tdm->dma_capture); + return 0; +} + +static int zx_tdm_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) +{ + struct zx_tdm_info *tdm = snd_soc_dai_get_drvdata(cpu_dai); + unsigned long val; + + val = zx_tdm_readl(tdm, REG_TIMING_CTRL); + val &= ~(TIMING_SYNC_WIDTH_MASK | TIMING_MS_MASK); + val |= TIMING_DEFAULT_WIDTH << TIMING_WIDTH_SHIFT; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + tdm->master = 1; + val |= TIMING_MASTER_MODE; + break; + case SND_SOC_DAIFMT_CBS_CFS: + tdm->master = 0; + val &= ~TIMING_MASTER_MODE; + break; + default: + dev_err(cpu_dai->dev, "Unknown master/slave format\n"); + return -EINVAL; + } + + + zx_tdm_writel(tdm, REG_TIMING_CTRL, val); + + return 0; +} + +static int zx_tdm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *socdai) +{ + struct zx_tdm_info *tdm = snd_soc_dai_get_drvdata(socdai); + struct snd_dmaengine_dai_dma_data *dma_data; + unsigned int ts_width = TIMING_DEFAULT_WIDTH; + unsigned int ch_num = 32; + unsigned int mask = 0; + unsigned int ret = 0; + unsigned long val; + + dma_data = snd_soc_dai_get_dma_data(socdai, substream); + dma_data->addr_width = ch_num >> 3; + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_MU_LAW: + case SNDRV_PCM_FORMAT_A_LAW: + case SNDRV_PCM_FORMAT_S16_LE: + ts_width = 1; + break; + default: + ts_width = 0; + dev_err(socdai->dev, "Unknown data format\n"); + return -EINVAL; + } + + val = zx_tdm_readl(tdm, REG_TIMING_CTRL); + val |= TIMING_TS_WIDTH(ts_width) | TIMING_TS_NUM(1); + zx_tdm_writel(tdm, REG_TIMING_CTRL, val); + zx_tdm_writel(tdm, REG_TS_MASK0, mask); + + if (tdm->master) + ret = clk_set_rate(tdm->dai_wclk, + params_rate(params) * TIMING_WIDTH_FACTOR * ch_num); + + return ret; +} + +static int zx_tdm_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); + struct zx_tdm_info *zx_tdm = dev_get_drvdata(dai->dev); + unsigned int val; + int ret = 0; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + if (capture) { + val = zx_tdm_readl(zx_tdm, REG_RX_FIFO_CTRL); + val |= FIFOCTRL_RX_FIFO_RST; + zx_tdm_writel(zx_tdm, REG_RX_FIFO_CTRL, val); + + zx_tdm_rx_dma_en(zx_tdm, true); + } else { + val = zx_tdm_readl(zx_tdm, REG_TX_FIFO_CTRL); + val |= FIFOCTRL_TX_FIFO_RST; + zx_tdm_writel(zx_tdm, REG_TX_FIFO_CTRL, val); + + zx_tdm_tx_dma_en(zx_tdm, true); + } + break; + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + if (capture) + zx_tdm_rx_en(zx_tdm, true); + else + zx_tdm_tx_en(zx_tdm, true); + break; + case SNDRV_PCM_TRIGGER_STOP: + if (capture) + zx_tdm_rx_dma_en(zx_tdm, false); + else + zx_tdm_tx_dma_en(zx_tdm, false); + break; + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + if (capture) + zx_tdm_rx_en(zx_tdm, false); + else + zx_tdm_tx_en(zx_tdm, false); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static int zx_tdm_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct zx_tdm_info *zx_tdm = dev_get_drvdata(dai->dev); + int ret; + + ret = clk_prepare_enable(zx_tdm->dai_wclk); + if (ret) + return ret; + + ret = clk_prepare_enable(zx_tdm->dai_pclk); + if (ret) { + clk_disable_unprepare(zx_tdm->dai_wclk); + return ret; + } + + return 0; +} + +static void zx_tdm_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct zx_tdm_info *zx_tdm = dev_get_drvdata(dai->dev); + + clk_disable_unprepare(zx_tdm->dai_pclk); + clk_disable_unprepare(zx_tdm->dai_wclk); +} + +static struct snd_soc_dai_ops zx_tdm_dai_ops = { + .trigger = zx_tdm_trigger, + .hw_params = zx_tdm_hw_params, + .set_fmt = zx_tdm_set_fmt, + .startup = zx_tdm_startup, + .shutdown = zx_tdm_shutdown, +}; + +static const struct snd_soc_component_driver zx_tdm_component = { + .name = "zx-tdm", +}; + +static void zx_tdm_init_state(struct zx_tdm_info *tdm) +{ + unsigned int val; + + zx_tdm_writel(tdm, REG_PROCESS_CTRL, PROCESS_DISABLE_ALL); + + val = zx_tdm_readl(tdm, REG_TIMING_CTRL); + val |= TIMING_LSB_FIRST; + val &= ~TIMING_CLK_SEL_MASK; + val |= TIMING_CLK_SEL_DEF; + zx_tdm_writel(tdm, REG_TIMING_CTRL, val); + + zx_tdm_writel(tdm, REG_INT_EN, INT_DISABLE_ALL); + /* + * write INT_STATUS register to clear it. + */ + zx_tdm_writel(tdm, REG_INT_STATUS, INT_STATUS_MASK); + zx_tdm_writel(tdm, REG_RX_FIFO_CTRL, FIFOCTRL_RX_FIFO_RST); + zx_tdm_writel(tdm, REG_TX_FIFO_CTRL, FIFOCTRL_TX_FIFO_RST); + + val = zx_tdm_readl(tdm, REG_RX_FIFO_CTRL); + val &= ~(RXTH_MASK | RX_FIFO_RST_MASK); + val |= FIFOCTRL_THRESHOLD(8); + zx_tdm_writel(tdm, REG_RX_FIFO_CTRL, val); + + val = zx_tdm_readl(tdm, REG_TX_FIFO_CTRL); + val &= ~(TXTH_MASK | TX_FIFO_RST_MASK); + val |= FIFOCTRL_THRESHOLD(8); + zx_tdm_writel(tdm, REG_TX_FIFO_CTRL, val); +} + +static struct snd_soc_dai_driver zx_tdm_dai = { + .name = "zx-tdm-dai", + .id = 0, + .probe = zx_tdm_dai_probe, + .playback = { + .channels_min = 1, + .channels_max = 4, + .rates = ZX_TDM_RATES, + .formats = ZX_TDM_FMTBIT, + }, + .capture = { + .channels_min = 1, + .channels_max = 4, + .rates = ZX_TDM_RATES, + .formats = ZX_TDM_FMTBIT, + }, + .ops = &zx_tdm_dai_ops, +}; + +static int zx_tdm_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct of_phandle_args out_args; + unsigned int dma_reg_offset; + struct zx_tdm_info *zx_tdm; + unsigned int dma_mask; + struct resource *res; + struct regmap *regmap_sysctrl; + int ret; + + zx_tdm = devm_kzalloc(&pdev->dev, sizeof(*zx_tdm), GFP_KERNEL); + if (!zx_tdm) + return -ENOMEM; + + zx_tdm->dev = dev; + + zx_tdm->dai_wclk = devm_clk_get(&pdev->dev, "wclk"); + if (IS_ERR(zx_tdm->dai_wclk)) { + dev_err(&pdev->dev, "Fail to get wclk\n"); + return PTR_ERR(zx_tdm->dai_wclk); + } + + zx_tdm->dai_pclk = devm_clk_get(&pdev->dev, "pclk"); + if (IS_ERR(zx_tdm->dai_pclk)) { + dev_err(&pdev->dev, "Fail to get pclk\n"); + return PTR_ERR(zx_tdm->dai_pclk); + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + zx_tdm->phy_addr = res->start; + zx_tdm->regbase = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(zx_tdm->regbase)) + return PTR_ERR(zx_tdm->regbase); + + ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node, + "zte,tdm-dma-sysctrl", 2, 0, &out_args); + if (ret) { + dev_err(&pdev->dev, "Fail to get zte,tdm-dma-sysctrl\n"); + return ret; + } + + dma_reg_offset = out_args.args[0]; + dma_mask = out_args.args[1]; + regmap_sysctrl = syscon_node_to_regmap(out_args.np); + if (IS_ERR(regmap_sysctrl)) { + of_node_put(out_args.np); + return PTR_ERR(regmap_sysctrl); + } + + regmap_update_bits(regmap_sysctrl, dma_reg_offset, dma_mask, dma_mask); + of_node_put(out_args.np); + + zx_tdm_init_state(zx_tdm); + platform_set_drvdata(pdev, zx_tdm); + + ret = devm_snd_soc_register_component(&pdev->dev, &zx_tdm_component, + &zx_tdm_dai, 1); + if (ret) { + dev_err(&pdev->dev, "Register DAI failed: %d\n", ret); + return ret; + } + + ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); + if (ret) + dev_err(&pdev->dev, "Register platform PCM failed: %d\n", ret); + + return ret; +} + +static const struct of_device_id zx_tdm_dt_ids[] = { + { .compatible = "zte,zx296718-tdm", }, + {} +}; +MODULE_DEVICE_TABLE(of, zx_tdm_dt_ids); + +static struct platform_driver tdm_driver = { + .probe = zx_tdm_probe, + .driver = { + .name = "zx-tdm", + .of_match_table = zx_tdm_dt_ids, + }, +}; +module_platform_driver(tdm_driver); + +MODULE_AUTHOR("Baoyou Xie "); +MODULE_DESCRIPTION("ZTE TDM DAI driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.1 From ae884ae78a238c36e4abfdb53d4659d5fca67433 Mon Sep 17 00:00:00 2001 From: Romain Perier Date: Wed, 1 Mar 2017 10:11:05 +0100 Subject: ASoC: es8328: Let device auto detect ratios in slave mode In master mode, SCLK and LRCLK signals are generated by the CODEC when any of the ADC/DAC are enabled. SCLK is derived from MCLK via a programmable division set by BLK_DIV, LRCLK is derived from MCLK via another programmable division set by ADCFsRatio/DACFsRatio. In slave mode, SCLK and LRCLK signals are received as inputs and supplied externally. LRCLK and SCLK must be synchronously derived from MCLK with specific rates. The device can auto detect MCLK/LRCLK ratio according to a predefined table. LRCLK/SCLK ratio is usually 64 (SCLK = 64 * LRCLK) This commits adds support to let to device auto detect and decide which ratio to use. The mclkdiv2 and BCLK_DIV ratio and put to zero. Signed-off-by: Romain Perier Signed-off-by: Mark Brown --- sound/soc/codecs/es8328.c | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/es8328.c b/sound/soc/codecs/es8328.c index 3f84fbd071e2..51dca8662942 100644 --- a/sound/soc/codecs/es8328.c +++ b/sound/soc/codecs/es8328.c @@ -91,6 +91,7 @@ struct es8328_priv { int mclkdiv2; const struct snd_pcm_hw_constraint_list *sysclk_constraints; const int *mclk_ratios; + bool master; struct regulator_bulk_data supplies[ES8328_SUPPLY_NUM]; }; @@ -469,7 +470,7 @@ static int es8328_startup(struct snd_pcm_substream *substream, struct snd_soc_codec *codec = dai->codec; struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec); - if (es8328->sysclk_constraints) + if (es8328->master && es8328->sysclk_constraints) snd_pcm_hw_constraint_list(substream->runtime, 0, SNDRV_PCM_HW_PARAM_RATE, es8328->sysclk_constraints); @@ -488,27 +489,34 @@ static int es8328_hw_params(struct snd_pcm_substream *substream, int wl; int ratio; - if (!es8328->sysclk_constraints) { - dev_err(codec->dev, "No MCLK configured\n"); - return -EINVAL; - } - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) reg = ES8328_DACCONTROL2; else reg = ES8328_ADCCONTROL5; - for (i = 0; i < es8328->sysclk_constraints->count; i++) - if (es8328->sysclk_constraints->list[i] == params_rate(params)) - break; + if (es8328->master) { + if (!es8328->sysclk_constraints) { + dev_err(codec->dev, "No MCLK configured\n"); + return -EINVAL; + } - if (i == es8328->sysclk_constraints->count) { - dev_err(codec->dev, "LRCLK %d unsupported with current clock\n", - params_rate(params)); - return -EINVAL; + for (i = 0; i < es8328->sysclk_constraints->count; i++) + if (es8328->sysclk_constraints->list[i] == + params_rate(params)) + break; + + if (i == es8328->sysclk_constraints->count) { + dev_err(codec->dev, + "LRCLK %d unsupported with current clock\n", + params_rate(params)); + return -EINVAL; + } + ratio = es8328->mclk_ratios[i]; + } else { + ratio = 0; + es8328->mclkdiv2 = 0; } - ratio = es8328->mclk_ratios[i]; snd_soc_update_bits(codec, ES8328_MASTERMODE, ES8328_MASTERMODE_MCLKDIV2, es8328->mclkdiv2 ? ES8328_MASTERMODE_MCLKDIV2 : 0); @@ -586,6 +594,7 @@ static int es8328_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) { struct snd_soc_codec *codec = codec_dai->codec; + struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec); u8 dac_mode = 0; u8 adc_mode = 0; @@ -595,11 +604,13 @@ static int es8328_set_dai_fmt(struct snd_soc_dai *codec_dai, snd_soc_update_bits(codec, ES8328_MASTERMODE, ES8328_MASTERMODE_MSC, ES8328_MASTERMODE_MSC); + es8328->master = true; break; case SND_SOC_DAIFMT_CBS_CFS: /* Slave serial port mode */ snd_soc_update_bits(codec, ES8328_MASTERMODE, ES8328_MASTERMODE_MSC, 0); + es8328->master = false; break; default: return -EINVAL; -- cgit v1.2.1 From c7ad841eaef66114d404c8fc02a67f5ef507b1bb Mon Sep 17 00:00:00 2001 From: Romain Perier Date: Wed, 1 Mar 2017 10:11:04 +0100 Subject: ASoC: es8328: Simplify rates definition Currently most of the standard rates are supported by this driver. Instead of defining each supported rate one by one, we use the SND macro SNDRV_PCM_RATE_8000_48000. Also adds support for 88.2khz as the codec supports it and the sys clocks are already supported. Signed-off-by: Romain Perier Signed-off-by: Mark Brown --- sound/soc/codecs/es8328.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/es8328.c b/sound/soc/codecs/es8328.c index 51dca8662942..1363a68155a9 100644 --- a/sound/soc/codecs/es8328.c +++ b/sound/soc/codecs/es8328.c @@ -70,13 +70,8 @@ static const char * const supply_names[ES8328_SUPPLY_NUM] = { }; #define ES8328_RATES (SNDRV_PCM_RATE_96000 | \ - SNDRV_PCM_RATE_48000 | \ - SNDRV_PCM_RATE_44100 | \ - SNDRV_PCM_RATE_32000 | \ - SNDRV_PCM_RATE_22050 | \ - SNDRV_PCM_RATE_16000 | \ - SNDRV_PCM_RATE_11025 | \ - SNDRV_PCM_RATE_8000) + SNDRV_PCM_RATE_88200 | \ + SNDRV_PCM_RATE_8000_48000) #define ES8328_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ SNDRV_PCM_FMTBIT_S18_3LE | \ SNDRV_PCM_FMTBIT_S20_3LE | \ -- cgit v1.2.1 From 404785f9eff34086a3f67a9b5cefe6495d7b0a4a Mon Sep 17 00:00:00 2001 From: Romain Perier Date: Wed, 1 Mar 2017 10:11:06 +0100 Subject: ASoC: es8328: Enabling support for 192k The master and slave modes don't share the same table for MCLK/LRCLK ratios. The slaves mode has bigger ratios that allow to use BCLK that matche sampling frequency of 192khz. This commit enables this rate only for slave mode, i.e it does not declare this frequency in sysclk_contraints, resulting to an error in master mode (not supported CLK). Signed-off-by: Romain Perier Signed-off-by: Mark Brown --- sound/soc/codecs/es8328.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/es8328.c b/sound/soc/codecs/es8328.c index 1363a68155a9..ed7cc42d1ee2 100644 --- a/sound/soc/codecs/es8328.c +++ b/sound/soc/codecs/es8328.c @@ -69,7 +69,8 @@ static const char * const supply_names[ES8328_SUPPLY_NUM] = { "HPVDD", }; -#define ES8328_RATES (SNDRV_PCM_RATE_96000 | \ +#define ES8328_RATES (SNDRV_PCM_RATE_192000 | \ + SNDRV_PCM_RATE_96000 | \ SNDRV_PCM_RATE_88200 | \ SNDRV_PCM_RATE_8000_48000) #define ES8328_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ -- cgit v1.2.1 From 2e589fdc35c281fe1b1abe8a70004022ca504cf7 Mon Sep 17 00:00:00 2001 From: Romain Perier Date: Wed, 1 Mar 2017 10:11:07 +0100 Subject: ASoC: rockchip: Enable 192khz in hw_params operation As the sampling frequency is supported by es8328 in slave mode, add support for it in the corresponding operation. Signed-off-by: Romain Perier Signed-off-by: Mark Brown --- sound/soc/rockchip/rk3288_hdmi_analog.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/rockchip/rk3288_hdmi_analog.c b/sound/soc/rockchip/rk3288_hdmi_analog.c index b60abf322ce1..dbc53e48c52c 100644 --- a/sound/soc/rockchip/rk3288_hdmi_analog.c +++ b/sound/soc/rockchip/rk3288_hdmi_analog.c @@ -93,6 +93,9 @@ static int rk_hw_params(struct snd_pcm_substream *substream, case 96000: mclk = 12288000; break; + case 192000: + mclk = 24576000; + break; case 11025: case 22050: case 44100: -- cgit v1.2.1 From 89433a284d2cc07ca07d4fa414485aa241fc98e2 Mon Sep 17 00:00:00 2001 From: Romain Perier Date: Wed, 1 Mar 2017 10:11:07 +0100 Subject: ASoC: rockchip: Enable 192khz in hw_params operation As the sampling frequency is supported by es8328 in slave mode, add support for it in the corresponding operation. Signed-off-by: Romain Perier Signed-off-by: Mark Brown --- sound/soc/rockchip/rk3288_hdmi_analog.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/rockchip/rk3288_hdmi_analog.c b/sound/soc/rockchip/rk3288_hdmi_analog.c index b60abf322ce1..dbc53e48c52c 100644 --- a/sound/soc/rockchip/rk3288_hdmi_analog.c +++ b/sound/soc/rockchip/rk3288_hdmi_analog.c @@ -93,6 +93,9 @@ static int rk_hw_params(struct snd_pcm_substream *substream, case 96000: mclk = 12288000; break; + case 192000: + mclk = 24576000; + break; case 11025: case 22050: case 44100: -- cgit v1.2.1 From a03faba972cb0f9b3a46d8054e674d5492e06c38 Mon Sep 17 00:00:00 2001 From: Liviu Dudau Date: Wed, 1 Mar 2017 12:26:28 +0000 Subject: ASoC: TLV320AIC23: Unquote NULL from control name Without this I am getting the following messages at boot on my Trimslice: tlv320aic23-codec 2-001a: Control not supported for path LLINEIN -> [NULL] -> Line Input tlv320aic23-codec 2-001a: ASoC: no dapm match for LLINEIN --> NULL --> Line Input tlv320aic23-codec 2-001a: ASoC: Failed to add route LLINEIN -> NULL -> Line Input tlv320aic23-codec 2-001a: Control not supported for path RLINEIN -> [NULL] -> Line Input tlv320aic23-codec 2-001a: ASoC: no dapm match for RLINEIN --> NULL --> Line Input tlv320aic23-codec 2-001a: ASoC: Failed to add route RLINEIN -> NULL -> Line Input tlv320aic23-codec 2-001a: Control not supported for path MICIN -> [NULL] -> Mic Input tlv320aic23-codec 2-001a: ASoC: no dapm match for MICIN --> NULL --> Mic Input tlv320aic23-codec 2-001a: ASoC: Failed to add route MICIN -> NULL -> Mic Input tegra-snd-trimslice sound: tlv320aic23-hifi <-> 70002800.i2s mapping ok Signed-off-by: Liviu Dudau Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic23.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c index 410cae0f2060..628a8eeaab68 100644 --- a/sound/soc/codecs/tlv320aic23.c +++ b/sound/soc/codecs/tlv320aic23.c @@ -174,10 +174,9 @@ static const struct snd_soc_dapm_route tlv320aic23_intercon[] = { {"ROUT", NULL, "Output Mixer"}, /* Inputs */ - {"Line Input", "NULL", "LLINEIN"}, - {"Line Input", "NULL", "RLINEIN"}, - - {"Mic Input", "NULL", "MICIN"}, + {"Line Input", NULL, "LLINEIN"}, + {"Line Input", NULL, "RLINEIN"}, + {"Mic Input", NULL, "MICIN"}, /* input mux */ {"Capture Source", "Line", "Line Input"}, -- cgit v1.2.1 From f1013cdeeeb978e3d8ef254bee1f007da4c862f3 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 28 Feb 2017 15:43:43 +0100 Subject: ASoC: ux500: drop platform DAI assignments This platform is completely probed by device tree nowadays, so we need to do a bigger cleanup removing all the non-DT codepaths. This cleanup must however go in as a fix since it fixes a regression. Currently when Ux500 audio is enabled, dmesg complains like this: entry->name == "prealloc" entry->name == "prealloc_max" entry->name == "prealloc" ------------[ cut here ]------------ WARNING: CPU: 0 PID: 95 at ../fs/proc/generic.c:346 proc_register+0xf0/0x110 proc_dir_entry 'sub0/prealloc' already registered (...) entry->name == "prealloc_max" ------------[ cut here ]------------ WARNING: CPU: 0 PID: 95 at ../fs/proc/generic.c:346 proc_register+0xf0/0x110 proc_dir_entry 'sub0/prealloc_max' already registered (...) snd-soc-mop500 soc:sound: ab8500-codec-dai.0 <-> 80124000.msp mapping ok entry->name == "prealloc" entry->name == "prealloc_max" entry->name == "prealloc" ------------[ cut here ]------------ WARNING: CPU: 0 PID: 95 at ../fs/proc/generic.c:346 proc_register+0xf0/0x110 proc_dir_entry 'sub0/prealloc' already registered (...) entry->name == "prealloc_max" ------------[ cut here ]------------ WARNING: CPU: 0 PID: 95 at ../fs/proc/generic.c:346 proc_register+0xf0/0x110 proc_dir_entry 'sub0/prealloc_max' already registered snd-soc-mop500 soc:sound: ab8500-codec-dai.1 <-> 80125000.msp mapping ok This is because PCMs are created twice for the same hardware, and this happens because both "platform" and "CPU" DAI links are specified. But platform/CPU is an either/or pair, not a both/and pair. This has maybe worked in the past, but it is causing trouble now, so let us begin the cleanups by removing the platform assignment and silencing the boot noise, and make a proper DT cleanup for the next kernel cycle. Cc: Ulf Hansson Cc: Lee Jones Signed-off-by: Linus Walleij Signed-off-by: Mark Brown --- sound/soc/ux500/mop500.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/ux500/mop500.c b/sound/soc/ux500/mop500.c index ba9fc099cf67..b50f68a439ce 100644 --- a/sound/soc/ux500/mop500.c +++ b/sound/soc/ux500/mop500.c @@ -33,7 +33,6 @@ static struct snd_soc_dai_link mop500_dai_links[] = { .stream_name = "ab8500_0", .cpu_dai_name = "ux500-msp-i2s.1", .codec_dai_name = "ab8500-codec-dai.0", - .platform_name = "ux500-msp-i2s.1", .codec_name = "ab8500-codec.0", .init = mop500_ab8500_machine_init, .ops = mop500_ab8500_ops, @@ -43,7 +42,6 @@ static struct snd_soc_dai_link mop500_dai_links[] = { .stream_name = "ab8500_1", .cpu_dai_name = "ux500-msp-i2s.3", .codec_dai_name = "ab8500-codec-dai.1", - .platform_name = "ux500-msp-i2s.3", .codec_name = "ab8500-codec.0", .init = NULL, .ops = mop500_ab8500_ops, @@ -87,8 +85,6 @@ static int mop500_of_probe(struct platform_device *pdev, for (i = 0; i < 2; i++) { mop500_dai_links[i].cpu_of_node = msp_np[i]; mop500_dai_links[i].cpu_dai_name = NULL; - mop500_dai_links[i].platform_of_node = msp_np[i]; - mop500_dai_links[i].platform_name = NULL; mop500_dai_links[i].codec_of_node = codec_np; mop500_dai_links[i].codec_name = NULL; } -- cgit v1.2.1 From 9000b59d7a12503ece61414fff3ce58773ebf033 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 27 Feb 2017 16:47:23 +0100 Subject: ASoC: es7134: add es7134 DAC driver The es7134 is 24bit, 192Khz i2s DA converter for PCM audio. Datasheet is available here : http://www.everest-semi.com/pdf/ES7134LV%20DS.pdf This driver is also compatible with the es7144, which is the same as the es7134, with 2 additional pins for filtering capacitors. Signed-off-by: Jerome Brunet Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 4 ++ sound/soc/codecs/Makefile | 2 + sound/soc/codecs/es7134.c | 116 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 122 insertions(+) create mode 100644 sound/soc/codecs/es7134.c (limited to 'sound/soc') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index e49e9da7f1f6..7c7c2e96b836 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -72,6 +72,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_DMIC select SND_SOC_ES8328_SPI if SPI_MASTER select SND_SOC_ES8328_I2C if I2C + select SND_SOC_ES7134 select SND_SOC_GTM601 select SND_SOC_HDAC_HDMI select SND_SOC_ICS43432 @@ -525,6 +526,9 @@ config SND_SOC_HDMI_CODEC select SND_PCM_IEC958 select HDMI +config SND_SOC_ES7134 + tristate "Everest Semi ES7134 CODEC" + config SND_SOC_ES8328 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 1796cb987e71..b65868c963c9 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -63,6 +63,7 @@ snd-soc-da7219-objs := da7219.o da7219-aad.o snd-soc-da732x-objs := da732x.o snd-soc-da9055-objs := da9055.o snd-soc-dmic-objs := dmic.o +snd-soc-es7134-objs := es7134.o snd-soc-es8328-objs := es8328.o snd-soc-es8328-i2c-objs := es8328-i2c.o snd-soc-es8328-spi-objs := es8328-spi.o @@ -293,6 +294,7 @@ obj-$(CONFIG_SND_SOC_DA7219) += snd-soc-da7219.o obj-$(CONFIG_SND_SOC_DA732X) += snd-soc-da732x.o obj-$(CONFIG_SND_SOC_DA9055) += snd-soc-da9055.o obj-$(CONFIG_SND_SOC_DMIC) += snd-soc-dmic.o +obj-$(CONFIG_SND_SOC_ES7134) += snd-soc-es7134.o obj-$(CONFIG_SND_SOC_ES8328) += snd-soc-es8328.o obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.o obj-$(CONFIG_SND_SOC_ES8328_SPI)+= snd-soc-es8328-spi.o diff --git a/sound/soc/codecs/es7134.c b/sound/soc/codecs/es7134.c new file mode 100644 index 000000000000..25ede825d349 --- /dev/null +++ b/sound/soc/codecs/es7134.c @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2017 BayLibre, SAS. + * Author: Jerome Brunet + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + */ + +#include +#include + +/* + * The everest 7134 is a very simple DA converter with no register + */ + +static int es7134_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) +{ + fmt &= (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_INV_MASK | + SND_SOC_DAIFMT_MASTER_MASK); + + if (fmt != (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS)) { + dev_err(codec_dai->dev, "Invalid DAI format\n"); + return -EINVAL; + } + + return 0; +} + +static const struct snd_soc_dai_ops es7134_dai_ops = { + .set_fmt = es7134_set_fmt, +}; + +static struct snd_soc_dai_driver es7134_dai = { + .name = "es7134-hifi", + .playback = { + .stream_name = "Playback", + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = (SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S18_3LE | + SNDRV_PCM_FMTBIT_S20_3LE | + SNDRV_PCM_FMTBIT_S24_3LE | + SNDRV_PCM_FMTBIT_S24_LE), + }, + .ops = &es7134_dai_ops, +}; + +static const struct snd_soc_dapm_widget es7134_dapm_widgets[] = { + SND_SOC_DAPM_OUTPUT("AOUTL"), + SND_SOC_DAPM_OUTPUT("AOUTR"), + SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0), +}; + +static const struct snd_soc_dapm_route es7134_dapm_routes[] = { + { "AOUTL", NULL, "DAC" }, + { "AOUTR", NULL, "DAC" }, +}; + +static struct snd_soc_codec_driver es7134_codec_driver = { + .component_driver = { + .dapm_widgets = es7134_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(es7134_dapm_widgets), + .dapm_routes = es7134_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(es7134_dapm_routes), + }, +}; + +static int es7134_probe(struct platform_device *pdev) +{ + return snd_soc_register_codec(&pdev->dev, + &es7134_codec_driver, + &es7134_dai, 1); +} + +static int es7134_remove(struct platform_device *pdev) +{ + snd_soc_unregister_codec(&pdev->dev); + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id es7134_ids[] = { + { .compatible = "everest,es7134", }, + { .compatible = "everest,es7144", }, + { } +}; +MODULE_DEVICE_TABLE(of, es7134_ids); +#endif + +static struct platform_driver es7134_driver = { + .driver = { + .name = "es7134", + .of_match_table = of_match_ptr(es7134_ids), + }, + .probe = es7134_probe, + .remove = es7134_remove, +}; + +module_platform_driver(es7134_driver); + +MODULE_DESCRIPTION("ASoC ES7134 audio codec driver"); +MODULE_AUTHOR("Jerome Brunet "); +MODULE_LICENSE("GPL"); -- cgit v1.2.1 From 6387f866a2ccbf393ed5ffe7e2754eb5d0781441 Mon Sep 17 00:00:00 2001 From: Brian Austin Date: Mon, 6 Mar 2017 08:07:59 -0600 Subject: ASoC: Add support for Cirrus Logic CS35L35 Amplifier This patch adds support for the Cirrus Logic CS35L35 9V Boosted Amplifier Signed-off-by: Brian Austin Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 5 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/cs35l35.c | 1553 ++++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/cs35l35.h | 284 ++++++++ 4 files changed, 1844 insertions(+) create mode 100644 sound/soc/codecs/cs35l35.c create mode 100644 sound/soc/codecs/cs35l35.h (limited to 'sound/soc') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index e49e9da7f1f6..00885c2cb685 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -49,6 +49,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_CS35L32 if I2C select SND_SOC_CS35L33 if I2C select SND_SOC_CS35L34 if I2C + select SND_SOC_CS35L35 if I2C select SND_SOC_CS42L42 if I2C select SND_SOC_CS42L51_I2C if I2C select SND_SOC_CS42L52 if I2C && INPUT @@ -408,6 +409,10 @@ config SND_SOC_CS35L34 tristate "Cirrus Logic CS35L34 CODEC" depends on I2C +config SND_SOC_CS35L35 + tristate "Cirrus Logic CS35L35 CODEC" + depends on I2C + config SND_SOC_CS42L42 tristate "Cirrus Logic CS42L42 CODEC" depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 1796cb987e71..97b36e4ce665 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -39,6 +39,7 @@ snd-soc-cq93vc-objs := cq93vc.o snd-soc-cs35l32-objs := cs35l32.o snd-soc-cs35l33-objs := cs35l33.o snd-soc-cs35l34-objs := cs35l34.o +snd-soc-cs35l35-objs := cs35l35.o snd-soc-cs42l42-objs := cs42l42.o snd-soc-cs42l51-objs := cs42l51.o snd-soc-cs42l51-i2c-objs := cs42l51-i2c.o @@ -269,6 +270,7 @@ obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o obj-$(CONFIG_SND_SOC_CS35L32) += snd-soc-cs35l32.o obj-$(CONFIG_SND_SOC_CS35L33) += snd-soc-cs35l33.o obj-$(CONFIG_SND_SOC_CS35L34) += snd-soc-cs35l34.o +obj-$(CONFIG_SND_SOC_CS35L35) += snd-soc-cs35l35.o obj-$(CONFIG_SND_SOC_CS42L42) += snd-soc-cs42l42.o obj-$(CONFIG_SND_SOC_CS42L51) += snd-soc-cs42l51.o obj-$(CONFIG_SND_SOC_CS42L51_I2C) += snd-soc-cs42l51-i2c.o diff --git a/sound/soc/codecs/cs35l35.c b/sound/soc/codecs/cs35l35.c new file mode 100644 index 000000000000..260ed42c71e9 --- /dev/null +++ b/sound/soc/codecs/cs35l35.c @@ -0,0 +1,1553 @@ +/* + * cs35l35.c -- CS35L35 ALSA SoC audio driver + * + * Copyright 2017 Cirrus Logic, Inc. + * + * Author: Brian Austin + * + * 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 +#include +#include +#include +#include +#include + +#include "cs35l35.h" + +/* + * Some fields take zero as a valid value so use a high bit flag that won't + * get written to the device to mark those. + */ +#define CS35L35_VALID_PDATA 0x80000000 + +static const struct reg_default cs35l35_reg[] = { + {CS35L35_PWRCTL1, 0x01}, + {CS35L35_PWRCTL2, 0x11}, + {CS35L35_PWRCTL3, 0x00}, + {CS35L35_CLK_CTL1, 0x04}, + {CS35L35_CLK_CTL2, 0x10}, + {CS35L35_CLK_CTL3, 0xCF}, + {CS35L35_SP_FMT_CTL1, 0x20}, + {CS35L35_SP_FMT_CTL2, 0x00}, + {CS35L35_SP_FMT_CTL3, 0x02}, + {CS35L35_MAG_COMP_CTL, 0x00}, + {CS35L35_AMP_INP_DRV_CTL, 0x01}, + {CS35L35_AMP_DIG_VOL_CTL, 0x12}, + {CS35L35_AMP_DIG_VOL, 0x00}, + {CS35L35_ADV_DIG_VOL, 0x00}, + {CS35L35_PROTECT_CTL, 0x06}, + {CS35L35_AMP_GAIN_AUD_CTL, 0x13}, + {CS35L35_AMP_GAIN_PDM_CTL, 0x00}, + {CS35L35_AMP_GAIN_ADV_CTL, 0x00}, + {CS35L35_GPI_CTL, 0x00}, + {CS35L35_BST_CVTR_V_CTL, 0x00}, + {CS35L35_BST_PEAK_I, 0x07}, + {CS35L35_BST_RAMP_CTL, 0x85}, + {CS35L35_BST_CONV_COEF_1, 0x24}, + {CS35L35_BST_CONV_COEF_2, 0x24}, + {CS35L35_BST_CONV_SLOPE_COMP, 0x47}, + {CS35L35_BST_CONV_SW_FREQ, 0x04}, + {CS35L35_CLASS_H_CTL, 0x0B}, + {CS35L35_CLASS_H_HEADRM_CTL, 0x0B}, + {CS35L35_CLASS_H_RELEASE_RATE, 0x08}, + {CS35L35_CLASS_H_FET_DRIVE_CTL, 0x41}, + {CS35L35_CLASS_H_VP_CTL, 0xC5}, + {CS35L35_VPBR_CTL, 0x0A}, + {CS35L35_VPBR_VOL_CTL, 0x09}, + {CS35L35_VPBR_TIMING_CTL, 0x6A}, + {CS35L35_VPBR_MODE_VOL_CTL, 0x40}, + {CS35L35_SPKR_MON_CTL, 0xC0}, + {CS35L35_IMON_SCALE_CTL, 0x30}, + {CS35L35_AUDIN_RXLOC_CTL, 0x00}, + {CS35L35_ADVIN_RXLOC_CTL, 0x80}, + {CS35L35_VMON_TXLOC_CTL, 0x00}, + {CS35L35_IMON_TXLOC_CTL, 0x80}, + {CS35L35_VPMON_TXLOC_CTL, 0x04}, + {CS35L35_VBSTMON_TXLOC_CTL, 0x84}, + {CS35L35_VPBR_STATUS_TXLOC_CTL, 0x04}, + {CS35L35_ZERO_FILL_LOC_CTL, 0x00}, + {CS35L35_AUDIN_DEPTH_CTL, 0x0F}, + {CS35L35_SPKMON_DEPTH_CTL, 0x0F}, + {CS35L35_SUPMON_DEPTH_CTL, 0x0F}, + {CS35L35_ZEROFILL_DEPTH_CTL, 0x00}, + {CS35L35_MULT_DEV_SYNCH1, 0x02}, + {CS35L35_MULT_DEV_SYNCH2, 0x80}, + {CS35L35_PROT_RELEASE_CTL, 0x00}, + {CS35L35_DIAG_MODE_REG_LOCK, 0x00}, + {CS35L35_DIAG_MODE_CTL_1, 0x40}, + {CS35L35_DIAG_MODE_CTL_2, 0x00}, + {CS35L35_INT_MASK_1, 0xFF}, + {CS35L35_INT_MASK_2, 0xFF}, + {CS35L35_INT_MASK_3, 0xFF}, + {CS35L35_INT_MASK_4, 0xFF}, + +}; + +static bool cs35l35_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS35L35_INT_STATUS_1: + case CS35L35_INT_STATUS_2: + case CS35L35_INT_STATUS_3: + case CS35L35_INT_STATUS_4: + case CS35L35_PLL_STATUS: + case CS35L35_OTP_TRIM_STATUS: + return true; + default: + return false; + } +} + +static bool cs35l35_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS35L35_DEVID_AB ... CS35L35_PWRCTL3: + case CS35L35_CLK_CTL1 ... CS35L35_SP_FMT_CTL3: + case CS35L35_MAG_COMP_CTL ... CS35L35_AMP_GAIN_AUD_CTL: + case CS35L35_AMP_GAIN_PDM_CTL ... CS35L35_BST_PEAK_I: + case CS35L35_BST_RAMP_CTL ... CS35L35_BST_CONV_SW_FREQ: + case CS35L35_CLASS_H_CTL ... CS35L35_CLASS_H_VP_CTL: + case CS35L35_CLASS_H_STATUS: + case CS35L35_VPBR_CTL ... CS35L35_VPBR_MODE_VOL_CTL: + case CS35L35_VPBR_ATTEN_STATUS: + case CS35L35_SPKR_MON_CTL: + case CS35L35_IMON_SCALE_CTL ... CS35L35_ZEROFILL_DEPTH_CTL: + case CS35L35_MULT_DEV_SYNCH1 ... CS35L35_PROT_RELEASE_CTL: + case CS35L35_DIAG_MODE_REG_LOCK ... CS35L35_DIAG_MODE_CTL_2: + case CS35L35_INT_MASK_1 ... CS35L35_PLL_STATUS: + case CS35L35_OTP_TRIM_STATUS: + return true; + default: + return false; + } +} + +static bool cs35l35_precious_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS35L35_INT_STATUS_1: + case CS35L35_INT_STATUS_2: + case CS35L35_INT_STATUS_3: + case CS35L35_INT_STATUS_4: + case CS35L35_PLL_STATUS: + case CS35L35_OTP_TRIM_STATUS: + return true; + default: + return false; + } +} + +static int cs35l35_sdin_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); + struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec); + int ret = 0; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL1, + CS35L35_MCLK_DIS_MASK, + 0 << CS35L35_MCLK_DIS_SHIFT); + regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL1, + CS35L35_DISCHG_FILT_MASK, + 0 << CS35L35_DISCHG_FILT_SHIFT); + regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL1, + CS35L35_PDN_ALL_MASK, 0); + break; + case SND_SOC_DAPM_POST_PMD: + regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL1, + CS35L35_DISCHG_FILT_MASK, + 1 << CS35L35_DISCHG_FILT_SHIFT); + regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL1, + CS35L35_PDN_ALL_MASK, 1); + + reinit_completion(&cs35l35->pdn_done); + + ret = wait_for_completion_timeout(&cs35l35->pdn_done, + msecs_to_jiffies(100)); + if (ret == 0) { + dev_err(codec->dev, "TIMEOUT PDN_DONE did not complete in 100ms\n"); + ret = -ETIMEDOUT; + } + + regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL1, + CS35L35_MCLK_DIS_MASK, + 1 << CS35L35_MCLK_DIS_SHIFT); + break; + default: + dev_err(codec->dev, "Invalid event = 0x%x\n", event); + ret = -EINVAL; + } + return ret; +} + +static int cs35l35_main_amp_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); + struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec); + unsigned int reg[4]; + int i; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (cs35l35->pdata.bst_pdn_fet_on) + regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, + CS35L35_PDN_BST_MASK, + 0 << CS35L35_PDN_BST_FETON_SHIFT); + else + regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, + CS35L35_PDN_BST_MASK, + 0 << CS35L35_PDN_BST_FETOFF_SHIFT); + break; + case SND_SOC_DAPM_POST_PMU: + usleep_range(5000, 5100); + /* If in PDM mode we must use VP for Voltage control */ + if (cs35l35->pdm_mode) + regmap_update_bits(cs35l35->regmap, + CS35L35_BST_CVTR_V_CTL, + CS35L35_BST_CTL_MASK, + 0 << CS35L35_BST_CTL_SHIFT); + + regmap_update_bits(cs35l35->regmap, CS35L35_PROTECT_CTL, + CS35L35_AMP_MUTE_MASK, 0); + + for (i = 0; i < 2; i++) + regmap_bulk_read(cs35l35->regmap, CS35L35_INT_STATUS_1, + ®, ARRAY_SIZE(reg)); + + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_update_bits(cs35l35->regmap, CS35L35_PROTECT_CTL, + CS35L35_AMP_MUTE_MASK, + 1 << CS35L35_AMP_MUTE_SHIFT); + if (cs35l35->pdata.bst_pdn_fet_on) + regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, + CS35L35_PDN_BST_MASK, + 1 << CS35L35_PDN_BST_FETON_SHIFT); + else + regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, + CS35L35_PDN_BST_MASK, + 1 << CS35L35_PDN_BST_FETOFF_SHIFT); + break; + case SND_SOC_DAPM_POST_PMD: + usleep_range(5000, 5100); + /* + * If PDM mode we should switch back to pdata value + * for Voltage control when we go down + */ + if (cs35l35->pdm_mode) + regmap_update_bits(cs35l35->regmap, + CS35L35_BST_CVTR_V_CTL, + CS35L35_BST_CTL_MASK, + cs35l35->pdata.bst_vctl + << CS35L35_BST_CTL_SHIFT); + + break; + default: + dev_err(codec->dev, "Invalid event = 0x%x\n", event); + } + return 0; +} + +static DECLARE_TLV_DB_SCALE(amp_gain_tlv, 0, 1, 1); +static DECLARE_TLV_DB_SCALE(dig_vol_tlv, -10200, 50, 0); + +static const struct snd_kcontrol_new cs35l35_aud_controls[] = { + SOC_SINGLE_SX_TLV("Digital Audio Volume", CS35L35_AMP_DIG_VOL, + 0, 0x34, 0xE4, dig_vol_tlv), + SOC_SINGLE_TLV("Analog Audio Volume", CS35L35_AMP_GAIN_AUD_CTL, 0, 19, 0, + amp_gain_tlv), + SOC_SINGLE_TLV("PDM Volume", CS35L35_AMP_GAIN_PDM_CTL, 0, 19, 0, + amp_gain_tlv), +}; + +static const struct snd_kcontrol_new cs35l35_adv_controls[] = { + SOC_SINGLE_SX_TLV("Digital Advisory Volume", CS35L35_ADV_DIG_VOL, + 0, 0x34, 0xE4, dig_vol_tlv), + SOC_SINGLE_TLV("Analog Advisory Volume", CS35L35_AMP_GAIN_ADV_CTL, 0, 19, 0, + amp_gain_tlv), +}; + +static const struct snd_soc_dapm_widget cs35l35_dapm_widgets[] = { + SND_SOC_DAPM_AIF_IN_E("SDIN", NULL, 0, CS35L35_PWRCTL3, 1, 1, + cs35l35_sdin_event, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_AIF_OUT("SDOUT", NULL, 0, CS35L35_PWRCTL3, 2, 1), + + SND_SOC_DAPM_OUTPUT("SPK"), + + SND_SOC_DAPM_INPUT("VP"), + SND_SOC_DAPM_INPUT("VBST"), + SND_SOC_DAPM_INPUT("ISENSE"), + SND_SOC_DAPM_INPUT("VSENSE"), + + SND_SOC_DAPM_ADC("VMON ADC", NULL, CS35L35_PWRCTL2, 7, 1), + SND_SOC_DAPM_ADC("IMON ADC", NULL, CS35L35_PWRCTL2, 6, 1), + SND_SOC_DAPM_ADC("VPMON ADC", NULL, CS35L35_PWRCTL3, 3, 1), + SND_SOC_DAPM_ADC("VBSTMON ADC", NULL, CS35L35_PWRCTL3, 4, 1), + SND_SOC_DAPM_ADC("CLASS H", NULL, CS35L35_PWRCTL2, 5, 1), + + SND_SOC_DAPM_OUT_DRV_E("Main AMP", CS35L35_PWRCTL2, 0, 1, NULL, 0, + cs35l35_main_amp_event, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD), +}; + +static const struct snd_soc_dapm_route cs35l35_audio_map[] = { + {"VPMON ADC", NULL, "VP"}, + {"VBSTMON ADC", NULL, "VBST"}, + {"IMON ADC", NULL, "ISENSE"}, + {"VMON ADC", NULL, "VSENSE"}, + {"SDOUT", NULL, "IMON ADC"}, + {"SDOUT", NULL, "VMON ADC"}, + {"SDOUT", NULL, "VBSTMON ADC"}, + {"SDOUT", NULL, "VPMON ADC"}, + {"AMP Capture", NULL, "SDOUT"}, + + {"SDIN", NULL, "AMP Playback"}, + {"CLASS H", NULL, "SDIN"}, + {"Main AMP", NULL, "CLASS H"}, + {"SPK", NULL, "Main AMP"}, +}; + +static int cs35l35_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec); + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL1, + CS35L35_MS_MASK, 1 << CS35L35_MS_SHIFT); + cs35l35->slave_mode = false; + break; + case SND_SOC_DAIFMT_CBS_CFS: + regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL1, + CS35L35_MS_MASK, 0 << CS35L35_MS_SHIFT); + cs35l35->slave_mode = true; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + cs35l35->i2s_mode = true; + cs35l35->pdm_mode = false; + break; + case SND_SOC_DAIFMT_PDM: + cs35l35->pdm_mode = true; + cs35l35->i2s_mode = false; + break; + default: + return -EINVAL; + } + + return 0; +} + +struct cs35l35_sysclk_config { + int sysclk; + int srate; + u8 clk_cfg; +}; + +static struct cs35l35_sysclk_config cs35l35_clk_ctl[] = { + + /* SYSCLK, Sample Rate, Serial Port Cfg */ + {5644800, 44100, 0x00}, + {5644800, 88200, 0x40}, + {6144000, 48000, 0x10}, + {6144000, 96000, 0x50}, + {11289600, 44100, 0x01}, + {11289600, 88200, 0x41}, + {11289600, 176400, 0x81}, + {12000000, 44100, 0x03}, + {12000000, 48000, 0x13}, + {12000000, 88200, 0x43}, + {12000000, 96000, 0x53}, + {12000000, 176400, 0x83}, + {12000000, 192000, 0x93}, + {12288000, 48000, 0x11}, + {12288000, 96000, 0x51}, + {12288000, 192000, 0x91}, + {13000000, 44100, 0x07}, + {13000000, 48000, 0x17}, + {13000000, 88200, 0x47}, + {13000000, 96000, 0x57}, + {13000000, 176400, 0x87}, + {13000000, 192000, 0x97}, + {22579200, 44100, 0x02}, + {22579200, 88200, 0x42}, + {22579200, 176400, 0x82}, + {24000000, 44100, 0x0B}, + {24000000, 48000, 0x1B}, + {24000000, 88200, 0x4B}, + {24000000, 96000, 0x5B}, + {24000000, 176400, 0x8B}, + {24000000, 192000, 0x9B}, + {24576000, 48000, 0x12}, + {24576000, 96000, 0x52}, + {24576000, 192000, 0x92}, + {26000000, 44100, 0x0F}, + {26000000, 48000, 0x1F}, + {26000000, 88200, 0x4F}, + {26000000, 96000, 0x5F}, + {26000000, 176400, 0x8F}, + {26000000, 192000, 0x9F}, +}; + +static int cs35l35_get_clk_config(int sysclk, int srate) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(cs35l35_clk_ctl); i++) { + if (cs35l35_clk_ctl[i].sysclk == sysclk && + cs35l35_clk_ctl[i].srate == srate) + return cs35l35_clk_ctl[i].clk_cfg; + } + return -EINVAL; +} + +static int cs35l35_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 cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec); + struct classh_cfg *classh = &cs35l35->pdata.classh_algo; + int srate = params_rate(params); + int ret = 0; + u8 sp_sclks; + int audin_format; + int errata_chk; + + int clk_ctl = cs35l35_get_clk_config(cs35l35->sysclk, srate); + + if (clk_ctl < 0) { + dev_err(codec->dev, "Invalid CLK:Rate %d:%d\n", + cs35l35->sysclk, srate); + return -EINVAL; + } + + ret = regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL2, + CS35L35_CLK_CTL2_MASK, clk_ctl); + if (ret != 0) { + dev_err(codec->dev, "Failed to set port config %d\n", ret); + return ret; + } + + /* + * Rev A0 Errata + * When configured for the weak-drive detection path (CH_WKFET_DIS = 0) + * the Class H algorithm does not enable weak-drive operation for + * nonzero values of CH_WKFET_DELAY if SP_RATE = 01 or 10 + */ + errata_chk = clk_ctl & CS35L35_SP_RATE_MASK; + + if (classh->classh_wk_fet_disable == 0x00 && + (errata_chk == 0x01 || errata_chk == 0x03)) { + ret = regmap_update_bits(cs35l35->regmap, + CS35L35_CLASS_H_FET_DRIVE_CTL, + CS35L35_CH_WKFET_DEL_MASK, + 0 << CS35L35_CH_WKFET_DEL_SHIFT); + if (ret != 0) { + dev_err(codec->dev, "Failed to set fet config %d\n", + ret); + return ret; + } + } + + /* + * You can pull more Monitor data from the SDOUT pin than going to SDIN + * Just make sure your SCLK is fast enough to fill the frame + */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + switch (params_width(params)) { + case 8: + audin_format = CS35L35_SDIN_DEPTH_8; + break; + case 16: + audin_format = CS35L35_SDIN_DEPTH_16; + break; + case 24: + audin_format = CS35L35_SDIN_DEPTH_24; + break; + default: + dev_err(codec->dev, "Unsupported Width %d\n", + params_width(params)); + return -EINVAL; + } + regmap_update_bits(cs35l35->regmap, + CS35L35_AUDIN_DEPTH_CTL, + CS35L35_AUDIN_DEPTH_MASK, + audin_format << + CS35L35_AUDIN_DEPTH_SHIFT); + if (cs35l35->pdata.stereo) { + regmap_update_bits(cs35l35->regmap, + CS35L35_AUDIN_DEPTH_CTL, + CS35L35_ADVIN_DEPTH_MASK, + audin_format << + CS35L35_ADVIN_DEPTH_SHIFT); + } + } + + if (cs35l35->i2s_mode) { + /* We have to take the SCLK to derive num sclks + * to configure the CLOCK_CTL3 register correctly + */ + if ((cs35l35->sclk / srate) % 4) { + dev_err(codec->dev, "Unsupported sclk/fs ratio %d:%d\n", + cs35l35->sclk, srate); + return -EINVAL; + } + sp_sclks = ((cs35l35->sclk / srate) / 4) - 1; + + /* Only certain ratios are supported in I2S Slave Mode */ + if (cs35l35->slave_mode) { + switch (sp_sclks) { + case CS35L35_SP_SCLKS_32FS: + case CS35L35_SP_SCLKS_48FS: + case CS35L35_SP_SCLKS_64FS: + break; + default: + dev_err(codec->dev, "ratio not supported\n"); + return -EINVAL; + }; + } else { + /* Only certain ratios supported in I2S MASTER Mode */ + switch (sp_sclks) { + case CS35L35_SP_SCLKS_32FS: + case CS35L35_SP_SCLKS_64FS: + break; + default: + dev_err(codec->dev, "ratio not supported\n"); + return -EINVAL; + }; + } + ret = regmap_update_bits(cs35l35->regmap, + CS35L35_CLK_CTL3, + CS35L35_SP_SCLKS_MASK, sp_sclks << + CS35L35_SP_SCLKS_SHIFT); + if (ret != 0) { + dev_err(codec->dev, "Failed to set fsclk %d\n", ret); + return ret; + } + } + + return ret; +} + +static const unsigned int cs35l35_src_rates[] = { + 44100, 48000, 88200, 96000, 176400, 192000 +}; + +static const struct snd_pcm_hw_constraint_list cs35l35_constraints = { + .count = ARRAY_SIZE(cs35l35_src_rates), + .list = cs35l35_src_rates, +}; + +static int cs35l35_pcm_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec); + + if (!substream->runtime) + return 0; + + snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, &cs35l35_constraints); + + regmap_update_bits(cs35l35->regmap, CS35L35_AMP_INP_DRV_CTL, + CS35L35_PDM_MODE_MASK, + 0 << CS35L35_PDM_MODE_SHIFT); + + return 0; +} + +static const unsigned int cs35l35_pdm_rates[] = { + 44100, 48000, 88200, 96000 +}; + +static const struct snd_pcm_hw_constraint_list cs35l35_pdm_constraints = { + .count = ARRAY_SIZE(cs35l35_pdm_rates), + .list = cs35l35_pdm_rates, +}; + +static int cs35l35_pdm_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec); + + if (!substream->runtime) + return 0; + + snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + &cs35l35_pdm_constraints); + + regmap_update_bits(cs35l35->regmap, CS35L35_AMP_INP_DRV_CTL, + CS35L35_PDM_MODE_MASK, + 1 << CS35L35_PDM_MODE_SHIFT); + + return 0; +} + +static int cs35l35_dai_set_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = dai->codec; + struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec); + + /* Need the SCLK Frequency regardless of sysclk source for I2S */ + cs35l35->sclk = freq; + + return 0; +} + +static const struct snd_soc_dai_ops cs35l35_ops = { + .startup = cs35l35_pcm_startup, + .set_fmt = cs35l35_set_dai_fmt, + .hw_params = cs35l35_hw_params, + .set_sysclk = cs35l35_dai_set_sysclk, +}; + +static const struct snd_soc_dai_ops cs35l35_pdm_ops = { + .startup = cs35l35_pdm_startup, + .set_fmt = cs35l35_set_dai_fmt, + .hw_params = cs35l35_hw_params, +}; + +static struct snd_soc_dai_driver cs35l35_dai[] = { + { + .name = "cs35l35-pcm", + .id = 0, + .playback = { + .stream_name = "AMP Playback", + .channels_min = 1, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = CS35L35_FORMATS, + }, + .capture = { + .stream_name = "AMP Capture", + .channels_min = 1, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = CS35L35_FORMATS, + }, + .ops = &cs35l35_ops, + .symmetric_rates = 1, + }, + { + .name = "cs35l35-pdm", + .id = 1, + .playback = { + .stream_name = "PDM Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = CS35L35_FORMATS, + }, + .ops = &cs35l35_pdm_ops, + }, +}; + +static int cs35l35_codec_set_sysclk(struct snd_soc_codec *codec, + int clk_id, int source, unsigned int freq, + int dir) +{ + struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec); + int clksrc; + int ret = 0; + + switch (clk_id) { + case 0: + clksrc = CS35L35_CLK_SOURCE_MCLK; + break; + case 1: + clksrc = CS35L35_CLK_SOURCE_SCLK; + break; + case 2: + clksrc = CS35L35_CLK_SOURCE_PDM; + break; + default: + dev_err(codec->dev, "Invalid CLK Source\n"); + return -EINVAL; + }; + + switch (freq) { + case 5644800: + case 6144000: + case 11289600: + case 12000000: + case 12288000: + case 13000000: + case 22579200: + case 24000000: + case 24576000: + case 26000000: + cs35l35->sysclk = freq; + break; + default: + dev_err(codec->dev, "Invalid CLK Frequency Input : %d\n", freq); + return -EINVAL; + } + + ret = regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL1, + CS35L35_CLK_SOURCE_MASK, + clksrc << CS35L35_CLK_SOURCE_SHIFT); + if (ret != 0) { + dev_err(codec->dev, "Failed to set sysclk %d\n", ret); + return ret; + } + + return ret; +} + +static int cs35l35_codec_probe(struct snd_soc_codec *codec) +{ + struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec); + struct classh_cfg *classh = &cs35l35->pdata.classh_algo; + struct monitor_cfg *monitor_config = &cs35l35->pdata.mon_cfg; + int ret; + + cs35l35->codec = codec; + + /* Set Platform Data */ + if (cs35l35->pdata.bst_vctl) + regmap_update_bits(cs35l35->regmap, CS35L35_BST_CVTR_V_CTL, + CS35L35_BST_CTL_MASK, + cs35l35->pdata.bst_vctl); + + if (cs35l35->pdata.bst_ipk) + regmap_update_bits(cs35l35->regmap, CS35L35_BST_PEAK_I, + CS35L35_BST_IPK_MASK, + cs35l35->pdata.bst_ipk << + CS35L35_BST_IPK_SHIFT); + + if (cs35l35->pdata.gain_zc) + regmap_update_bits(cs35l35->regmap, CS35L35_PROTECT_CTL, + CS35L35_AMP_GAIN_ZC_MASK, + cs35l35->pdata.gain_zc << + CS35L35_AMP_GAIN_ZC_SHIFT); + + if (cs35l35->pdata.aud_channel) + regmap_update_bits(cs35l35->regmap, + CS35L35_AUDIN_RXLOC_CTL, + CS35L35_AUD_IN_LR_MASK, + cs35l35->pdata.aud_channel << + CS35L35_AUD_IN_LR_SHIFT); + + if (cs35l35->pdata.stereo) { + regmap_update_bits(cs35l35->regmap, + CS35L35_ADVIN_RXLOC_CTL, + CS35L35_ADV_IN_LR_MASK, + cs35l35->pdata.adv_channel << + CS35L35_ADV_IN_LR_SHIFT); + if (cs35l35->pdata.shared_bst) + regmap_update_bits(cs35l35->regmap, CS35L35_CLASS_H_CTL, + CS35L35_CH_STEREO_MASK, + 1 << CS35L35_CH_STEREO_SHIFT); + ret = snd_soc_add_codec_controls(codec, cs35l35_adv_controls, + ARRAY_SIZE(cs35l35_adv_controls)); + if (ret) + return ret; + } + + if (cs35l35->pdata.sp_drv_str) + regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL1, + CS35L35_SP_DRV_MASK, + cs35l35->pdata.sp_drv_str << + CS35L35_SP_DRV_SHIFT); + + if (classh->classh_algo_enable) { + if (classh->classh_bst_override) + regmap_update_bits(cs35l35->regmap, + CS35L35_CLASS_H_CTL, + CS35L35_CH_BST_OVR_MASK, + classh->classh_bst_override << + CS35L35_CH_BST_OVR_SHIFT); + if (classh->classh_bst_max_limit) + regmap_update_bits(cs35l35->regmap, + CS35L35_CLASS_H_CTL, + CS35L35_CH_BST_LIM_MASK, + classh->classh_bst_max_limit << + CS35L35_CH_BST_LIM_SHIFT); + if (classh->classh_mem_depth) + regmap_update_bits(cs35l35->regmap, + CS35L35_CLASS_H_CTL, + CS35L35_CH_MEM_DEPTH_MASK, + classh->classh_mem_depth << + CS35L35_CH_MEM_DEPTH_SHIFT); + if (classh->classh_headroom) + regmap_update_bits(cs35l35->regmap, + CS35L35_CLASS_H_HEADRM_CTL, + CS35L35_CH_HDRM_CTL_MASK, + classh->classh_headroom << + CS35L35_CH_HDRM_CTL_SHIFT); + if (classh->classh_release_rate) + regmap_update_bits(cs35l35->regmap, + CS35L35_CLASS_H_RELEASE_RATE, + CS35L35_CH_REL_RATE_MASK, + classh->classh_release_rate << + CS35L35_CH_REL_RATE_SHIFT); + if (classh->classh_wk_fet_disable) + regmap_update_bits(cs35l35->regmap, + CS35L35_CLASS_H_FET_DRIVE_CTL, + CS35L35_CH_WKFET_DIS_MASK, + classh->classh_wk_fet_disable << + CS35L35_CH_WKFET_DIS_SHIFT); + if (classh->classh_wk_fet_delay) + regmap_update_bits(cs35l35->regmap, + CS35L35_CLASS_H_FET_DRIVE_CTL, + CS35L35_CH_WKFET_DEL_MASK, + classh->classh_wk_fet_delay << + CS35L35_CH_WKFET_DEL_SHIFT); + if (classh->classh_wk_fet_thld) + regmap_update_bits(cs35l35->regmap, + CS35L35_CLASS_H_FET_DRIVE_CTL, + CS35L35_CH_WKFET_THLD_MASK, + classh->classh_wk_fet_thld << + CS35L35_CH_WKFET_THLD_SHIFT); + if (classh->classh_vpch_auto) + regmap_update_bits(cs35l35->regmap, + CS35L35_CLASS_H_VP_CTL, + CS35L35_CH_VP_AUTO_MASK, + classh->classh_vpch_auto << + CS35L35_CH_VP_AUTO_SHIFT); + if (classh->classh_vpch_rate) + regmap_update_bits(cs35l35->regmap, + CS35L35_CLASS_H_VP_CTL, + CS35L35_CH_VP_RATE_MASK, + classh->classh_vpch_rate << + CS35L35_CH_VP_RATE_SHIFT); + if (classh->classh_vpch_man) + regmap_update_bits(cs35l35->regmap, + CS35L35_CLASS_H_VP_CTL, + CS35L35_CH_VP_MAN_MASK, + classh->classh_vpch_man << + CS35L35_CH_VP_MAN_SHIFT); + } + + if (monitor_config->is_present) { + if (monitor_config->vmon_specs) { + regmap_update_bits(cs35l35->regmap, + CS35L35_SPKMON_DEPTH_CTL, + CS35L35_VMON_DEPTH_MASK, + monitor_config->vmon_dpth << + CS35L35_VMON_DEPTH_SHIFT); + regmap_update_bits(cs35l35->regmap, + CS35L35_VMON_TXLOC_CTL, + CS35L35_MON_TXLOC_MASK, + monitor_config->vmon_loc << + CS35L35_MON_TXLOC_SHIFT); + regmap_update_bits(cs35l35->regmap, + CS35L35_VMON_TXLOC_CTL, + CS35L35_MON_FRM_MASK, + monitor_config->vmon_frm << + CS35L35_MON_FRM_SHIFT); + } + if (monitor_config->imon_specs) { + regmap_update_bits(cs35l35->regmap, + CS35L35_SPKMON_DEPTH_CTL, + CS35L35_IMON_DEPTH_MASK, + monitor_config->imon_dpth << + CS35L35_IMON_DEPTH_SHIFT); + regmap_update_bits(cs35l35->regmap, + CS35L35_IMON_TXLOC_CTL, + CS35L35_MON_TXLOC_MASK, + monitor_config->imon_loc << + CS35L35_MON_TXLOC_SHIFT); + regmap_update_bits(cs35l35->regmap, + CS35L35_IMON_TXLOC_CTL, + CS35L35_MON_FRM_MASK, + monitor_config->imon_frm << + CS35L35_MON_FRM_SHIFT); + } + if (monitor_config->vpmon_specs) { + regmap_update_bits(cs35l35->regmap, + CS35L35_SUPMON_DEPTH_CTL, + CS35L35_VPMON_DEPTH_MASK, + monitor_config->vpmon_dpth << + CS35L35_VPMON_DEPTH_SHIFT); + regmap_update_bits(cs35l35->regmap, + CS35L35_VPMON_TXLOC_CTL, + CS35L35_MON_TXLOC_MASK, + monitor_config->vpmon_loc << + CS35L35_MON_TXLOC_SHIFT); + regmap_update_bits(cs35l35->regmap, + CS35L35_VPMON_TXLOC_CTL, + CS35L35_MON_FRM_MASK, + monitor_config->vpmon_frm << + CS35L35_MON_FRM_SHIFT); + } + if (monitor_config->vbstmon_specs) { + regmap_update_bits(cs35l35->regmap, + CS35L35_SUPMON_DEPTH_CTL, + CS35L35_VBSTMON_DEPTH_MASK, + monitor_config->vpmon_dpth << + CS35L35_VBSTMON_DEPTH_SHIFT); + regmap_update_bits(cs35l35->regmap, + CS35L35_VBSTMON_TXLOC_CTL, + CS35L35_MON_TXLOC_MASK, + monitor_config->vbstmon_loc << + CS35L35_MON_TXLOC_SHIFT); + regmap_update_bits(cs35l35->regmap, + CS35L35_VBSTMON_TXLOC_CTL, + CS35L35_MON_FRM_MASK, + monitor_config->vbstmon_frm << + CS35L35_MON_FRM_SHIFT); + } + if (monitor_config->vpbrstat_specs) { + regmap_update_bits(cs35l35->regmap, + CS35L35_SUPMON_DEPTH_CTL, + CS35L35_VPBRSTAT_DEPTH_MASK, + monitor_config->vpbrstat_dpth << + CS35L35_VPBRSTAT_DEPTH_SHIFT); + regmap_update_bits(cs35l35->regmap, + CS35L35_VPBR_STATUS_TXLOC_CTL, + CS35L35_MON_TXLOC_MASK, + monitor_config->vpbrstat_loc << + CS35L35_MON_TXLOC_SHIFT); + regmap_update_bits(cs35l35->regmap, + CS35L35_VPBR_STATUS_TXLOC_CTL, + CS35L35_MON_FRM_MASK, + monitor_config->vpbrstat_frm << + CS35L35_MON_FRM_SHIFT); + } + if (monitor_config->zerofill_specs) { + regmap_update_bits(cs35l35->regmap, + CS35L35_SUPMON_DEPTH_CTL, + CS35L35_ZEROFILL_DEPTH_MASK, + monitor_config->zerofill_dpth << + CS35L35_ZEROFILL_DEPTH_SHIFT); + regmap_update_bits(cs35l35->regmap, + CS35L35_ZERO_FILL_LOC_CTL, + CS35L35_MON_TXLOC_MASK, + monitor_config->zerofill_loc << + CS35L35_MON_TXLOC_SHIFT); + regmap_update_bits(cs35l35->regmap, + CS35L35_ZERO_FILL_LOC_CTL, + CS35L35_MON_FRM_MASK, + monitor_config->zerofill_frm << + CS35L35_MON_FRM_SHIFT); + } + } + + return ret; +} + +static struct snd_soc_codec_driver soc_codec_dev_cs35l35 = { + .probe = cs35l35_codec_probe, + .set_sysclk = cs35l35_codec_set_sysclk, + .component_driver = { + .dapm_widgets = cs35l35_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(cs35l35_dapm_widgets), + + .dapm_routes = cs35l35_audio_map, + .num_dapm_routes = ARRAY_SIZE(cs35l35_audio_map), + + .controls = cs35l35_aud_controls, + .num_controls = ARRAY_SIZE(cs35l35_aud_controls), + }, + +}; + +static struct regmap_config cs35l35_regmap = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = CS35L35_MAX_REGISTER, + .reg_defaults = cs35l35_reg, + .num_reg_defaults = ARRAY_SIZE(cs35l35_reg), + .volatile_reg = cs35l35_volatile_register, + .readable_reg = cs35l35_readable_register, + .precious_reg = cs35l35_precious_register, + .cache_type = REGCACHE_RBTREE, +}; + +static irqreturn_t cs35l35_irq(int irq, void *data) +{ + struct cs35l35_private *cs35l35 = data; + struct snd_soc_codec *codec = cs35l35->codec; + unsigned int sticky1, sticky2, sticky3, sticky4; + unsigned int mask1, mask2, mask3, mask4, current1; + + /* ack the irq by reading all status registers */ + regmap_read(cs35l35->regmap, CS35L35_INT_STATUS_4, &sticky4); + regmap_read(cs35l35->regmap, CS35L35_INT_STATUS_3, &sticky3); + regmap_read(cs35l35->regmap, CS35L35_INT_STATUS_2, &sticky2); + regmap_read(cs35l35->regmap, CS35L35_INT_STATUS_1, &sticky1); + + regmap_read(cs35l35->regmap, CS35L35_INT_MASK_4, &mask4); + regmap_read(cs35l35->regmap, CS35L35_INT_MASK_3, &mask3); + regmap_read(cs35l35->regmap, CS35L35_INT_MASK_2, &mask2); + regmap_read(cs35l35->regmap, CS35L35_INT_MASK_1, &mask1); + + /* Check to see if unmasked bits are active */ + if (!(sticky1 & ~mask1) && !(sticky2 & ~mask2) && !(sticky3 & ~mask3) + && !(sticky4 & ~mask4)) + return IRQ_NONE; + + if (sticky2 & CS35L35_PDN_DONE) + complete(&cs35l35->pdn_done); + + /* read the current values */ + regmap_read(cs35l35->regmap, CS35L35_INT_STATUS_1, ¤t1); + + /* handle the interrupts */ + if (sticky1 & CS35L35_CAL_ERR) { + dev_crit(codec->dev, "Calibration Error\n"); + + /* error is no longer asserted; safe to reset */ + if (!(current1 & CS35L35_CAL_ERR)) { + pr_debug("%s : Cal error release\n", __func__); + regmap_update_bits(cs35l35->regmap, + CS35L35_PROT_RELEASE_CTL, + CS35L35_CAL_ERR_RLS, 0); + regmap_update_bits(cs35l35->regmap, + CS35L35_PROT_RELEASE_CTL, + CS35L35_CAL_ERR_RLS, + CS35L35_CAL_ERR_RLS); + regmap_update_bits(cs35l35->regmap, + CS35L35_PROT_RELEASE_CTL, + CS35L35_CAL_ERR_RLS, 0); + } + } + + if (sticky1 & CS35L35_AMP_SHORT) { + dev_crit(codec->dev, "AMP Short Error\n"); + /* error is no longer asserted; safe to reset */ + if (!(current1 & CS35L35_AMP_SHORT)) { + dev_dbg(codec->dev, "Amp short error release\n"); + regmap_update_bits(cs35l35->regmap, + CS35L35_PROT_RELEASE_CTL, + CS35L35_SHORT_RLS, 0); + regmap_update_bits(cs35l35->regmap, + CS35L35_PROT_RELEASE_CTL, + CS35L35_SHORT_RLS, + CS35L35_SHORT_RLS); + regmap_update_bits(cs35l35->regmap, + CS35L35_PROT_RELEASE_CTL, + CS35L35_SHORT_RLS, 0); + } + } + + if (sticky1 & CS35L35_OTW) { + dev_warn(codec->dev, "Over temperature warning\n"); + + /* error is no longer asserted; safe to reset */ + if (!(current1 & CS35L35_OTW)) { + dev_dbg(codec->dev, "Over temperature warn release\n"); + regmap_update_bits(cs35l35->regmap, + CS35L35_PROT_RELEASE_CTL, + CS35L35_OTW_RLS, 0); + regmap_update_bits(cs35l35->regmap, + CS35L35_PROT_RELEASE_CTL, + CS35L35_OTW_RLS, + CS35L35_OTW_RLS); + regmap_update_bits(cs35l35->regmap, + CS35L35_PROT_RELEASE_CTL, + CS35L35_OTW_RLS, 0); + } + } + + if (sticky1 & CS35L35_OTE) { + dev_crit(codec->dev, "Over temperature error\n"); + /* error is no longer asserted; safe to reset */ + if (!(current1 & CS35L35_OTE)) { + dev_dbg(codec->dev, "Over temperature error release\n"); + regmap_update_bits(cs35l35->regmap, + CS35L35_PROT_RELEASE_CTL, + CS35L35_OTE_RLS, 0); + regmap_update_bits(cs35l35->regmap, + CS35L35_PROT_RELEASE_CTL, + CS35L35_OTE_RLS, + CS35L35_OTE_RLS); + regmap_update_bits(cs35l35->regmap, + CS35L35_PROT_RELEASE_CTL, + CS35L35_OTE_RLS, 0); + } + } + + if (sticky3 & CS35L35_BST_HIGH) { + dev_crit(codec->dev, "VBST error: powering off!\n"); + regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, + CS35L35_PDN_AMP, CS35L35_PDN_AMP); + regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL1, + CS35L35_PDN_ALL, CS35L35_PDN_ALL); + } + + if (sticky3 & CS35L35_LBST_SHORT) { + dev_crit(codec->dev, "LBST error: powering off!\n"); + regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, + CS35L35_PDN_AMP, CS35L35_PDN_AMP); + regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL1, + CS35L35_PDN_ALL, CS35L35_PDN_ALL); + } + + if (sticky2 & CS35L35_VPBR_ERR) + dev_dbg(codec->dev, "Error: Reactive Brownout\n"); + + if (sticky4 & CS35L35_VMON_OVFL) + dev_dbg(codec->dev, "Error: VMON overflow\n"); + + if (sticky4 & CS35L35_IMON_OVFL) + dev_dbg(codec->dev, "Error: IMON overflow\n"); + + return IRQ_HANDLED; +} + + +static int cs35l35_handle_of_data(struct i2c_client *i2c_client, + struct cs35l35_platform_data *pdata) +{ + struct device_node *np = i2c_client->dev.of_node; + struct device_node *classh, *signal_format; + struct classh_cfg *classh_config = &pdata->classh_algo; + struct monitor_cfg *monitor_config = &pdata->mon_cfg; + unsigned int val32 = 0; + u8 monitor_array[3]; + int ret = 0; + + if (!np) + return 0; + + pdata->bst_pdn_fet_on = of_property_read_bool(np, + "cirrus,boost-pdn-fet-on"); + + ret = of_property_read_u32(np, "cirrus,boost-ctl-millivolt", &val32); + if (ret >= 0) { + if (val32 < 2600 || val32 > 9000) { + dev_err(&i2c_client->dev, + "Invalid Boost Voltage %d mV\n", val32); + return -EINVAL; + } + pdata->bst_vctl = ((val32 - 2600) / 100) + 1; + } + + ret = of_property_read_u32(np, "cirrus,boost-peak-milliamp", &val32); + if (ret >= 0) { + if (val32 < 1680 || val32 > 4480) { + dev_err(&i2c_client->dev, + "Invalid Boost Peak Current %u mA\n", val32); + return -EINVAL; + } + + pdata->bst_ipk = (val32 - 1680) / 110; + } + + if (of_property_read_u32(np, "cirrus,sp-drv-strength", &val32) >= 0) + pdata->sp_drv_str = val32; + + pdata->stereo = of_property_read_bool(np, "cirrus,stereo-config"); + + if (pdata->stereo) { + ret = of_property_read_u32(np, "cirrus,audio-channel", &val32); + if (ret >= 0) + pdata->aud_channel = val32; + + ret = of_property_read_u32(np, "cirrus,advisory-channel", + &val32); + if (ret >= 0) + pdata->adv_channel = val32; + + pdata->shared_bst = of_property_read_bool(np, + "cirrus,shared-boost"); + } + + pdata->gain_zc = of_property_read_bool(np, "cirrus,amp-gain-zc"); + + classh = of_get_child_by_name(np, "cirrus,classh-internal-algo"); + classh_config->classh_algo_enable = classh ? true : false; + + if (classh_config->classh_algo_enable) { + classh_config->classh_bst_override = + of_property_read_bool(np, "cirrus,classh-bst-overide"); + + ret = of_property_read_u32(classh, + "cirrus,classh-bst-max-limit", + &val32); + if (ret >= 0) { + val32 |= CS35L35_VALID_PDATA; + classh_config->classh_bst_max_limit = val32; + } + + ret = of_property_read_u32(classh, + "cirrus,classh-bst-max-limit", + &val32); + if (ret >= 0) { + val32 |= CS35L35_VALID_PDATA; + classh_config->classh_bst_max_limit = val32; + } + + ret = of_property_read_u32(classh, "cirrus,classh-mem-depth", + &val32); + if (ret >= 0) { + val32 |= CS35L35_VALID_PDATA; + classh_config->classh_mem_depth = val32; + } + + ret = of_property_read_u32(classh, "cirrus,classh-release-rate", + &val32); + if (ret >= 0) + classh_config->classh_release_rate = val32; + + ret = of_property_read_u32(classh, "cirrus,classh-headroom", + &val32); + if (ret >= 0) { + val32 |= CS35L35_VALID_PDATA; + classh_config->classh_headroom = val32; + } + + ret = of_property_read_u32(classh, + "cirrus,classh-wk-fet-disable", + &val32); + if (ret >= 0) + classh_config->classh_wk_fet_disable = val32; + + ret = of_property_read_u32(classh, "cirrus,classh-wk-fet-delay", + &val32); + if (ret >= 0) { + val32 |= CS35L35_VALID_PDATA; + classh_config->classh_wk_fet_delay = val32; + } + + ret = of_property_read_u32(classh, "cirrus,classh-wk-fet-thld", + &val32); + if (ret >= 0) + classh_config->classh_wk_fet_thld = val32; + + ret = of_property_read_u32(classh, "cirrus,classh-vpch-auto", + &val32); + if (ret >= 0) { + val32 |= CS35L35_VALID_PDATA; + classh_config->classh_vpch_auto = val32; + } + + ret = of_property_read_u32(classh, "cirrus,classh-vpch-rate", + &val32); + if (ret >= 0) { + val32 |= CS35L35_VALID_PDATA; + classh_config->classh_vpch_rate = val32; + } + + ret = of_property_read_u32(classh, "cirrus,classh-vpch-man", + &val32); + if (ret >= 0) + classh_config->classh_vpch_man = val32; + } + of_node_put(classh); + + /* frame depth location */ + signal_format = of_get_child_by_name(np, "cirrus,monitor-signal-format"); + monitor_config->is_present = signal_format ? true : false; + if (monitor_config->is_present) { + ret = of_property_read_u8_array(signal_format, "cirrus,imon", + monitor_array, ARRAY_SIZE(monitor_array)); + if (!ret) { + monitor_config->imon_specs = true; + monitor_config->imon_dpth = monitor_array[0]; + monitor_config->imon_loc = monitor_array[1]; + monitor_config->imon_frm = monitor_array[2]; + } + ret = of_property_read_u8_array(signal_format, "cirrus,vmon", + monitor_array, ARRAY_SIZE(monitor_array)); + if (!ret) { + monitor_config->vmon_specs = true; + monitor_config->vmon_dpth = monitor_array[0]; + monitor_config->vmon_loc = monitor_array[1]; + monitor_config->vmon_frm = monitor_array[2]; + } + ret = of_property_read_u8_array(signal_format, "cirrus,vpmon", + monitor_array, ARRAY_SIZE(monitor_array)); + if (!ret) { + monitor_config->vpmon_specs = true; + monitor_config->vpmon_dpth = monitor_array[0]; + monitor_config->vpmon_loc = monitor_array[1]; + monitor_config->vpmon_frm = monitor_array[2]; + } + ret = of_property_read_u8_array(signal_format, "cirrus,vbstmon", + monitor_array, ARRAY_SIZE(monitor_array)); + if (!ret) { + monitor_config->vbstmon_specs = true; + monitor_config->vbstmon_dpth = monitor_array[0]; + monitor_config->vbstmon_loc = monitor_array[1]; + monitor_config->vbstmon_frm = monitor_array[2]; + } + ret = of_property_read_u8_array(signal_format, "cirrus,vpbrstat", + monitor_array, ARRAY_SIZE(monitor_array)); + if (!ret) { + monitor_config->vpbrstat_specs = true; + monitor_config->vpbrstat_dpth = monitor_array[0]; + monitor_config->vpbrstat_loc = monitor_array[1]; + monitor_config->vpbrstat_frm = monitor_array[2]; + } + ret = of_property_read_u8_array(signal_format, "cirrus,zerofill", + monitor_array, ARRAY_SIZE(monitor_array)); + if (!ret) { + monitor_config->zerofill_specs = true; + monitor_config->zerofill_dpth = monitor_array[0]; + monitor_config->zerofill_loc = monitor_array[1]; + monitor_config->zerofill_frm = monitor_array[2]; + } + } + of_node_put(signal_format); + + return 0; +} + +/* Errata Rev A0 */ +static const struct reg_sequence cs35l35_errata_patch[] = { + + { 0x7F, 0x99 }, + { 0x00, 0x99 }, + { 0x52, 0x22 }, + { 0x04, 0x14 }, + { 0x6D, 0x44 }, + { 0x24, 0x10 }, + { 0x58, 0xC4 }, + { 0x00, 0x98 }, + { 0x18, 0x08 }, + { 0x00, 0x00 }, + { 0x7F, 0x00 }, +}; + +static int cs35l35_i2c_probe(struct i2c_client *i2c_client, + const struct i2c_device_id *id) +{ + struct cs35l35_private *cs35l35; + struct cs35l35_platform_data *pdata = + dev_get_platdata(&i2c_client->dev); + int i; + int ret; + unsigned int devid = 0; + unsigned int reg; + + cs35l35 = devm_kzalloc(&i2c_client->dev, + sizeof(struct cs35l35_private), + GFP_KERNEL); + if (!cs35l35) + return -ENOMEM; + + i2c_set_clientdata(i2c_client, cs35l35); + cs35l35->regmap = devm_regmap_init_i2c(i2c_client, &cs35l35_regmap); + if (IS_ERR(cs35l35->regmap)) { + ret = PTR_ERR(cs35l35->regmap); + dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret); + goto err; + } + + for (i = 0; i < ARRAY_SIZE(cs35l35_supplies); i++) + cs35l35->supplies[i].supply = cs35l35_supplies[i]; + cs35l35->num_supplies = ARRAY_SIZE(cs35l35_supplies); + + ret = devm_regulator_bulk_get(&i2c_client->dev, + cs35l35->num_supplies, + cs35l35->supplies); + if (ret != 0) { + dev_err(&i2c_client->dev, + "Failed to request core supplies: %d\n", + ret); + return ret; + } + + if (pdata) { + cs35l35->pdata = *pdata; + } else { + pdata = devm_kzalloc(&i2c_client->dev, + sizeof(struct cs35l35_platform_data), + GFP_KERNEL); + if (!pdata) + return -ENOMEM; + if (i2c_client->dev.of_node) { + ret = cs35l35_handle_of_data(i2c_client, pdata); + if (ret != 0) + return ret; + + } + cs35l35->pdata = *pdata; + } + + ret = regulator_bulk_enable(cs35l35->num_supplies, + cs35l35->supplies); + if (ret != 0) { + dev_err(&i2c_client->dev, + "Failed to enable core supplies: %d\n", + ret); + return ret; + } + + /* returning NULL can be valid if in stereo mode */ + cs35l35->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev, + "reset", GPIOD_OUT_LOW); + if (IS_ERR(cs35l35->reset_gpio)) { + ret = PTR_ERR(cs35l35->reset_gpio); + if (ret == -EBUSY) { + dev_info(&i2c_client->dev, + "Reset line busy, assuming shared reset\n"); + cs35l35->reset_gpio = NULL; + } else { + dev_err(&i2c_client->dev, + "Failed to get reset GPIO: %d\n", ret); + goto err; + } + } + + gpiod_set_value_cansleep(cs35l35->reset_gpio, 1); + + init_completion(&cs35l35->pdn_done); + + ret = devm_request_threaded_irq(&i2c_client->dev, i2c_client->irq, NULL, + cs35l35_irq, IRQF_ONESHOT | IRQF_TRIGGER_LOW, + "cs35l35", cs35l35); + if (ret != 0) { + dev_err(&i2c_client->dev, "Failed to request IRQ: %d\n", ret); + goto err; + } + /* initialize codec */ + ret = regmap_read(cs35l35->regmap, CS35L35_DEVID_AB, ®); + + devid = (reg & 0xFF) << 12; + ret = regmap_read(cs35l35->regmap, CS35L35_DEVID_CD, ®); + devid |= (reg & 0xFF) << 4; + ret = regmap_read(cs35l35->regmap, CS35L35_DEVID_E, ®); + devid |= (reg & 0xF0) >> 4; + + if (devid != CS35L35_CHIP_ID) { + dev_err(&i2c_client->dev, + "CS35L35 Device ID (%X). Expected ID %X\n", + devid, CS35L35_CHIP_ID); + ret = -ENODEV; + goto err; + } + + ret = regmap_read(cs35l35->regmap, CS35L35_REV_ID, ®); + if (ret < 0) { + dev_err(&i2c_client->dev, "Get Revision ID failed: %d\n", ret); + goto err; + } + + ret = regmap_register_patch(cs35l35->regmap, cs35l35_errata_patch, + ARRAY_SIZE(cs35l35_errata_patch)); + if (ret < 0) { + dev_err(&i2c_client->dev, "Failed to apply errata patch: %d\n", + ret); + goto err; + } + + dev_info(&i2c_client->dev, + "Cirrus Logic CS35L35 (%x), Revision: %02X\n", devid, + ret & 0xFF); + + /* Set the INT Masks for critical errors */ + regmap_write(cs35l35->regmap, CS35L35_INT_MASK_1, + CS35L35_INT1_CRIT_MASK); + regmap_write(cs35l35->regmap, CS35L35_INT_MASK_2, + CS35L35_INT2_CRIT_MASK); + regmap_write(cs35l35->regmap, CS35L35_INT_MASK_3, + CS35L35_INT3_CRIT_MASK); + regmap_write(cs35l35->regmap, CS35L35_INT_MASK_4, + CS35L35_INT4_CRIT_MASK); + + regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, + CS35L35_PWR2_PDN_MASK, + CS35L35_PWR2_PDN_MASK); + + if (cs35l35->pdata.bst_pdn_fet_on) + regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, + CS35L35_PDN_BST_MASK, + 1 << CS35L35_PDN_BST_FETON_SHIFT); + else + regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, + CS35L35_PDN_BST_MASK, + 1 << CS35L35_PDN_BST_FETOFF_SHIFT); + + regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL3, + CS35L35_PWR3_PDN_MASK, + CS35L35_PWR3_PDN_MASK); + + regmap_update_bits(cs35l35->regmap, CS35L35_PROTECT_CTL, + CS35L35_AMP_MUTE_MASK, 1 << CS35L35_AMP_MUTE_SHIFT); + + ret = snd_soc_register_codec(&i2c_client->dev, + &soc_codec_dev_cs35l35, cs35l35_dai, + ARRAY_SIZE(cs35l35_dai)); + if (ret < 0) { + dev_err(&i2c_client->dev, + "Failed to register codec: %d\n", ret); + goto err; + } + +err: + regulator_bulk_disable(cs35l35->num_supplies, + cs35l35->supplies); + gpiod_set_value_cansleep(cs35l35->reset_gpio, 0); + + return ret; +} + +static int cs35l35_i2c_remove(struct i2c_client *client) +{ + snd_soc_unregister_codec(&client->dev); + return 0; +} + +static const struct of_device_id cs35l35_of_match[] = { + {.compatible = "cirrus,cs35l35"}, + {}, +}; +MODULE_DEVICE_TABLE(of, cs35l35_of_match); + +static const struct i2c_device_id cs35l35_id[] = { + {"cs35l35", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, cs35l35_id); + +static struct i2c_driver cs35l35_i2c_driver = { + .driver = { + .name = "cs35l35", + .of_match_table = cs35l35_of_match, + }, + .id_table = cs35l35_id, + .probe = cs35l35_i2c_probe, + .remove = cs35l35_i2c_remove, +}; + +module_i2c_driver(cs35l35_i2c_driver); + +MODULE_DESCRIPTION("ASoC CS35L35 driver"); +MODULE_AUTHOR("Brian Austin, Cirrus Logic Inc, "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs35l35.h b/sound/soc/codecs/cs35l35.h new file mode 100644 index 000000000000..e27a7fef5fb1 --- /dev/null +++ b/sound/soc/codecs/cs35l35.h @@ -0,0 +1,284 @@ +/* + * cs35l35.h -- CS35L35 ALSA SoC audio driver + * + * Copyright 2016 Cirrus Logic, Inc. + * + * Author: Brian Austin + * + * 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 __CS35L35_H__ +#define __CS35L35_H__ + +#define CS35L35_FIRSTREG 0x01 +#define CS35L35_LASTREG 0x7E +#define CS35L35_CHIP_ID 0x00035A35 +#define CS35L35_DEVID_AB 0x01 /* Device ID A & B [RO] */ +#define CS35L35_DEVID_CD 0x02 /* Device ID C & D [RO] */ +#define CS35L35_DEVID_E 0x03 /* Device ID E [RO] */ +#define CS35L35_FAB_ID 0x04 /* Fab ID [RO] */ +#define CS35L35_REV_ID 0x05 /* Revision ID [RO] */ +#define CS35L35_PWRCTL1 0x06 /* Power Ctl 1 */ +#define CS35L35_PWRCTL2 0x07 /* Power Ctl 2 */ +#define CS35L35_PWRCTL3 0x08 /* Power Ctl 3 */ +#define CS35L35_CLK_CTL1 0x0A /* Clocking Ctl 1 */ +#define CS35L35_CLK_CTL2 0x0B /* Clocking Ctl 2 */ +#define CS35L35_CLK_CTL3 0x0C /* Clocking Ctl 3 */ +#define CS35L35_SP_FMT_CTL1 0x0D /* Serial Port Format CTL1 */ +#define CS35L35_SP_FMT_CTL2 0x0E /* Serial Port Format CTL2 */ +#define CS35L35_SP_FMT_CTL3 0x0F /* Serial Port Format CTL3 */ +#define CS35L35_MAG_COMP_CTL 0x13 /* Magnitude Comp CTL */ +#define CS35L35_AMP_INP_DRV_CTL 0x14 /* Amp Input Drive Ctl */ +#define CS35L35_AMP_DIG_VOL_CTL 0x15 /* Amplifier Dig Volume Ctl */ +#define CS35L35_AMP_DIG_VOL 0x16 /* Amplifier Dig Volume */ +#define CS35L35_ADV_DIG_VOL 0x17 /* Advisory Digital Volume */ +#define CS35L35_PROTECT_CTL 0x18 /* Amp Gain - Prot Ctl Param */ +#define CS35L35_AMP_GAIN_AUD_CTL 0x19 /* Amp Serial Port Gain Ctl */ +#define CS35L35_AMP_GAIN_PDM_CTL 0x1A /* Amplifier Gain PDM Ctl */ +#define CS35L35_AMP_GAIN_ADV_CTL 0x1B /* Amplifier Gain Ctl */ +#define CS35L35_GPI_CTL 0x1C /* GPI Ctl */ +#define CS35L35_BST_CVTR_V_CTL 0x1D /* Boost Conv Voltage Ctl */ +#define CS35L35_BST_PEAK_I 0x1E /* Boost Conv Peak Current */ +#define CS35L35_BST_RAMP_CTL 0x20 /* Boost Conv Soft Ramp Ctl */ +#define CS35L35_BST_CONV_COEF_1 0x21 /* Boost Conv Coefficients 1 */ +#define CS35L35_BST_CONV_COEF_2 0x22 /* Boost Conv Coefficients 2 */ +#define CS35L35_BST_CONV_SLOPE_COMP 0x23 /* Boost Conv Slope Comp */ +#define CS35L35_BST_CONV_SW_FREQ 0x24 /* Boost Conv L BST SW Freq */ +#define CS35L35_CLASS_H_CTL 0x30 /* CLS H Control */ +#define CS35L35_CLASS_H_HEADRM_CTL 0x31 /* CLS H Headroom Ctl */ +#define CS35L35_CLASS_H_RELEASE_RATE 0x32 /* CLS H Release Rate */ +#define CS35L35_CLASS_H_FET_DRIVE_CTL 0x33 /* CLS H Weak FET Drive Ctl */ +#define CS35L35_CLASS_H_VP_CTL 0x34 /* CLS H VP Ctl */ +#define CS35L35_CLASS_H_STATUS 0x38 /* CLS H Status */ +#define CS35L35_VPBR_CTL 0x3A /* VPBR Ctl */ +#define CS35L35_VPBR_VOL_CTL 0x3B /* VPBR Volume Ctl */ +#define CS35L35_VPBR_TIMING_CTL 0x3C /* VPBR Timing Ctl */ +#define CS35L35_VPBR_MODE_VOL_CTL 0x3D /* VPBR Mode/Attack Vol Ctl */ +#define CS35L35_VPBR_ATTEN_STATUS 0x4B /* VPBR Attenuation Status */ +#define CS35L35_SPKR_MON_CTL 0x4E /* Speaker Monitoring Ctl */ +#define CS35L35_IMON_SCALE_CTL 0x51 /* IMON Scale Ctl */ +#define CS35L35_AUDIN_RXLOC_CTL 0x52 /* Audio Input RX Loc Ctl */ +#define CS35L35_ADVIN_RXLOC_CTL 0x53 /* Advisory Input RX Loc Ctl */ +#define CS35L35_VMON_TXLOC_CTL 0x54 /* VMON TX Loc Ctl */ +#define CS35L35_IMON_TXLOC_CTL 0x55 /* IMON TX Loc Ctl */ +#define CS35L35_VPMON_TXLOC_CTL 0x56 /* VPMON TX Loc Ctl */ +#define CS35L35_VBSTMON_TXLOC_CTL 0x57 /* VBSTMON TX Loc Ctl */ +#define CS35L35_VPBR_STATUS_TXLOC_CTL 0x58 /* VPBR Status TX Loc Ctl */ +#define CS35L35_ZERO_FILL_LOC_CTL 0x59 /* Zero Fill Loc Ctl */ +#define CS35L35_AUDIN_DEPTH_CTL 0x5A /* Audio Input Depth Ctl */ +#define CS35L35_SPKMON_DEPTH_CTL 0x5B /* SPK Mon Output Depth Ctl */ +#define CS35L35_SUPMON_DEPTH_CTL 0x5C /* Supply Mon Out Depth Ctl */ +#define CS35L35_ZEROFILL_DEPTH_CTL 0x5D /* Zero Fill Mon Output Ctl */ +#define CS35L35_MULT_DEV_SYNCH1 0x62 /* Multidevice Synch */ +#define CS35L35_MULT_DEV_SYNCH2 0x63 /* Multidevice Synch 2 */ +#define CS35L35_PROT_RELEASE_CTL 0x64 /* Protection Release Ctl */ +#define CS35L35_DIAG_MODE_REG_LOCK 0x68 /* Diagnostic Mode Reg Lock */ +#define CS35L35_DIAG_MODE_CTL_1 0x69 /* Diagnostic Mode Ctl 1 */ +#define CS35L35_DIAG_MODE_CTL_2 0x6A /* Diagnostic Mode Ctl 2 */ +#define CS35L35_INT_MASK_1 0x70 /* Interrupt Mask 1 */ +#define CS35L35_INT_MASK_2 0x71 /* Interrupt Mask 2 */ +#define CS35L35_INT_MASK_3 0x72 /* Interrupt Mask 3 */ +#define CS35L35_INT_MASK_4 0x73 /* Interrupt Mask 4 */ +#define CS35L35_INT_STATUS_1 0x74 /* Interrupt Status 1 */ +#define CS35L35_INT_STATUS_2 0x75 /* Interrupt Status 2 */ +#define CS35L35_INT_STATUS_3 0x76 /* Interrupt Status 3 */ +#define CS35L35_INT_STATUS_4 0x77 /* Interrupt Status 4 */ +#define CS35L35_PLL_STATUS 0x78 /* PLL Status */ +#define CS35L35_OTP_TRIM_STATUS 0x7E /* OTP Trim Status */ + +#define CS35L35_MAX_REGISTER 0x7F + +/* CS35L35_PWRCTL1 */ +#define CS35L35_SFT_RST 0x80 +#define CS35L35_DISCHG_FLT 0x02 +#define CS35L35_PDN_ALL 0x01 + +/* CS35L35_PWRCTL2 */ +#define CS35L35_PDN_VMON 0x80 +#define CS35L35_PDN_IMON 0x40 +#define CS35L35_PDN_CLASSH 0x20 +#define CS35L35_PDN_VPBR 0x10 +#define CS35L35_PDN_BST 0x04 +#define CS35L35_PDN_AMP 0x01 + +/* CS35L35_PWRCTL3 */ +#define CS35L35_PDN_VBSTMON_OUT 0x10 +#define CS35L35_PDN_VMON_OUT 0x08 + +#define CS35L35_AUDIN_DEPTH_MASK 0x03 +#define CS35L35_AUDIN_DEPTH_SHIFT 0 +#define CS35L35_ADVIN_DEPTH_MASK 0x0C +#define CS35L35_ADVIN_DEPTH_SHIFT 2 +#define CS35L35_SDIN_DEPTH_8 0x01 +#define CS35L35_SDIN_DEPTH_16 0x02 +#define CS35L35_SDIN_DEPTH_24 0x03 + +#define CS35L35_SDOUT_DEPTH_8 0x01 +#define CS35L35_SDOUT_DEPTH_12 0x02 +#define CS35L35_SDOUT_DEPTH_16 0x03 + +#define CS35L35_AUD_IN_LR_MASK 0x80 +#define CS35L35_AUD_IN_LR_SHIFT 7 +#define CS35L35_ADV_IN_LR_MASK 0x80 +#define CS35L35_ADV_IN_LR_SHIFT 7 +#define CS35L35_AUD_IN_LOC_MASK 0x0F +#define CS35L35_AUD_IN_LOC_SHIFT 0 +#define CS35L35_ADV_IN_LOC_MASK 0x0F +#define CS35L35_ADV_IN_LOC_SHIFT 0 + +#define CS35L35_IMON_DEPTH_MASK 0x03 +#define CS35L35_IMON_DEPTH_SHIFT 0 +#define CS35L35_VMON_DEPTH_MASK 0x0C +#define CS35L35_VMON_DEPTH_SHIFT 2 +#define CS35L35_VBSTMON_DEPTH_MASK 0x03 +#define CS35L35_VBSTMON_DEPTH_SHIFT 0 +#define CS35L35_VPMON_DEPTH_MASK 0x0C +#define CS35L35_VPMON_DEPTH_SHIFT 2 +#define CS35L35_VPBRSTAT_DEPTH_MASK 0x30 +#define CS35L35_VPBRSTAT_DEPTH_SHIFT 4 +#define CS35L35_ZEROFILL_DEPTH_MASK 0x03 +#define CS35L35_ZEROFILL_DEPTH_SHIFT 0x00 + +#define CS35L35_MON_TXLOC_MASK 0x3F +#define CS35L35_MON_TXLOC_SHIFT 0 +#define CS35L35_MON_FRM_MASK 0x80 +#define CS35L35_MON_FRM_SHIFT 7 + +#define CS35L35_MS_MASK 0x80 +#define CS35L35_MS_SHIFT 7 +#define CS35L35_SPMODE_MASK 0x40 +#define CS35L35_SP_DRV_MASK 0x10 +#define CS35L35_SP_DRV_SHIFT 4 +#define CS35L35_CLK_CTL2_MASK 0xFF +#define CS35L35_PDM_MODE_MASK 0x40 +#define CS35L35_PDM_MODE_SHIFT 6 +#define CS35L35_CLK_SOURCE_MASK 0x03 +#define CS35L35_CLK_SOURCE_SHIFT 0 +#define CS35L35_CLK_SOURCE_MCLK 0 +#define CS35L35_CLK_SOURCE_SCLK 1 +#define CS35L35_CLK_SOURCE_PDM 2 + +#define CS35L35_SP_SCLKS_MASK 0x0F +#define CS35L35_SP_SCLKS_SHIFT 0x00 +#define CS35L35_SP_SCLKS_16FS 0x03 +#define CS35L35_SP_SCLKS_32FS 0x07 +#define CS35L35_SP_SCLKS_48FS 0x0B +#define CS35L35_SP_SCLKS_64FS 0x0F +#define CS35L35_SP_RATE_MASK 0xC0 + +#define CS35L35_PDN_BST_MASK 0x06 +#define CS35L35_PDN_BST_FETON_SHIFT 1 +#define CS35L35_PDN_BST_FETOFF_SHIFT 2 +#define CS35L35_PWR2_PDN_MASK 0xE0 +#define CS35L35_PWR3_PDN_MASK 0x1E +#define CS35L35_PDN_ALL_MASK 0x01 +#define CS35L35_DISCHG_FILT_MASK 0x02 +#define CS35L35_DISCHG_FILT_SHIFT 1 +#define CS35L35_MCLK_DIS_MASK 0x04 +#define CS35L35_MCLK_DIS_SHIFT 2 + +#define CS35L35_BST_CTL_MASK 0x7F +#define CS35L35_BST_CTL_SHIFT 0 +#define CS35L35_BST_IPK_MASK 0x1F +#define CS35L35_BST_IPK_SHIFT 0 +#define CS35L35_AMP_MUTE_MASK 0x20 +#define CS35L35_AMP_MUTE_SHIFT 5 +#define CS35L35_AMP_GAIN_ZC_MASK 0x10 +#define CS35L35_AMP_GAIN_ZC_SHIFT 4 + +/* Class H Algorithm Control */ +#define CS35L35_CH_STEREO_MASK 0x40 +#define CS35L35_CH_STEREO_SHIFT 6 +#define CS35L35_CH_BST_OVR_MASK 0x04 +#define CS35L35_CH_BST_OVR_SHIFT 2 +#define CS35L35_CH_BST_LIM_MASK 0x08 +#define CS35L35_CH_BST_LIM_SHIFT 3 +#define CS35L35_CH_MEM_DEPTH_MASK 0x01 +#define CS35L35_CH_MEM_DEPTH_SHIFT 0 +#define CS35L35_CH_HDRM_CTL_MASK 0x3F +#define CS35L35_CH_HDRM_CTL_SHIFT 0 +#define CS35L35_CH_REL_RATE_MASK 0xFF +#define CS35L35_CH_REL_RATE_SHIFT 0 +#define CS35L35_CH_WKFET_DIS_MASK 0x80 +#define CS35L35_CH_WKFET_DIS_SHIFT 7 +#define CS35L35_CH_WKFET_DEL_MASK 0x70 +#define CS35L35_CH_WKFET_DEL_SHIFT 4 +#define CS35L35_CH_WKFET_THLD_MASK 0x0F +#define CS35L35_CH_WKFET_THLD_SHIFT 0 +#define CS35L35_CH_VP_AUTO_MASK 0x80 +#define CS35L35_CH_VP_AUTO_SHIFT 7 +#define CS35L35_CH_VP_RATE_MASK 0x60 +#define CS35L35_CH_VP_RATE_SHIFT 5 +#define CS35L35_CH_VP_MAN_MASK 0x1F +#define CS35L35_CH_VP_MAN_SHIFT 0 + +/* CS35L35_PROT_RELEASE_CTL */ +#define CS35L35_CAL_ERR_RLS 0x80 +#define CS35L35_SHORT_RLS 0x04 +#define CS35L35_OTW_RLS 0x02 +#define CS35L35_OTE_RLS 0x01 + +/* INT Mask Registers */ +#define CS35L35_INT1_CRIT_MASK 0x38 +#define CS35L35_INT2_CRIT_MASK 0xEF +#define CS35L35_INT3_CRIT_MASK 0xEE +#define CS35L35_INT4_CRIT_MASK 0xFF + +/* PDN DONE Masks */ +#define CS35L35_M_PDN_DONE_SHIFT 4 +#define CS35L35_M_PDN_DONE_MASK 0x10 + +/* CS35L35_INT_1 */ +#define CS35L35_CAL_ERR 0x80 +#define CS35L35_OTP_ERR 0x40 +#define CS35L35_LRCLK_ERR 0x20 +#define CS35L35_SPCLK_ERR 0x10 +#define CS35L35_MCLK_ERR 0x08 +#define CS35L35_AMP_SHORT 0x04 +#define CS35L35_OTW 0x02 +#define CS35L35_OTE 0x01 + +/* CS35L35_INT_2 */ +#define CS35L35_PDN_DONE 0x10 +#define CS35L35_VPBR_ERR 0x02 +#define CS35L35_VPBR_CLR 0x01 + +/* CS35L35_INT_3 */ +#define CS35L35_BST_HIGH 0x10 +#define CS35L35_BST_HIGH_FLAG 0x08 +#define CS35L35_BST_IPK_FLAG 0x04 +#define CS35L35_LBST_SHORT 0x01 + +/* CS35L35_INT_4 */ +#define CS35L35_VMON_OVFL 0x08 +#define CS35L35_IMON_OVFL 0x04 + +#define CS35L35_FORMATS (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) + +struct cs35l35_private { + struct snd_soc_codec *codec; + struct cs35l35_platform_data pdata; + struct regmap *regmap; + struct regulator_bulk_data supplies[2]; + int num_supplies; + int sysclk; + int sclk; + bool pdm_mode; + bool i2s_mode; + bool slave_mode; + /* GPIO for /RST */ + struct gpio_desc *reset_gpio; + struct completion pdn_done; +}; + +static const char * const cs35l35_supplies[] = { + "VA", + "VP", +}; + +#endif -- cgit v1.2.1 From 85825d5e886912655f6c1896d76035ce1316254b Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 6 Mar 2017 18:44:50 +0100 Subject: ASoC: dio2125: add dio2125 amp driver The dio2125 is a stereo output driver with adjustable gain. Signed-off-by: Jerome Brunet Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 5 ++ sound/soc/codecs/Makefile | 2 + sound/soc/codecs/dio2125.c | 120 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 127 insertions(+) create mode 100644 sound/soc/codecs/dio2125.c (limited to 'sound/soc') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index e49e9da7f1f6..5e5fcb660ca3 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -69,6 +69,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_DA7219 if I2C select SND_SOC_DA732X if I2C select SND_SOC_DA9055 if I2C + select SND_SOC_DIO2125 select SND_SOC_DMIC select SND_SOC_ES8328_SPI if SPI_MASTER select SND_SOC_ES8328_I2C if I2C @@ -516,6 +517,10 @@ config SND_SOC_DA732X config SND_SOC_DA9055 tristate +config SND_SOC_DIO2125 + tristate "Dioo DIO2125 Amplifier" + select GPIOLIB + config SND_SOC_DMIC tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 1796cb987e71..04894fa8891b 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -221,6 +221,7 @@ snd-soc-wm9712-objs := wm9712.o snd-soc-wm9713-objs := wm9713.o snd-soc-wm-hubs-objs := wm_hubs.o # Amp +snd-soc-dio2125-objs := dio2125.o snd-soc-max9877-objs := max9877.o snd-soc-max98504-objs := max98504.o snd-soc-tpa6130a2-objs := tpa6130a2.o @@ -448,6 +449,7 @@ obj-$(CONFIG_SND_SOC_WM_ADSP) += snd-soc-wm-adsp.o obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o # Amp +obj-$(CONFIG_SND_SOC_DIO2125) += snd-soc-dio2125.o obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o obj-$(CONFIG_SND_SOC_MAX98504) += snd-soc-max98504.o obj-$(CONFIG_SND_SOC_TPA6130A2) += snd-soc-tpa6130a2.o diff --git a/sound/soc/codecs/dio2125.c b/sound/soc/codecs/dio2125.c new file mode 100644 index 000000000000..015e310556d3 --- /dev/null +++ b/sound/soc/codecs/dio2125.c @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2017 BayLibre, SAS. + * Author: Jerome Brunet + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + */ + +#include +#include +#include + +#define DRV_NAME "dio2125" + +struct dio2125 { + struct gpio_desc *gpiod_enable; +}; + +static int drv_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *control, int event) +{ + struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm); + struct dio2125 *priv = snd_soc_component_get_drvdata(c); + int val; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + val = 1; + break; + case SND_SOC_DAPM_PRE_PMD: + val = 0; + break; + default: + WARN(1, "Unexpected event"); + return -EINVAL; + } + + gpiod_set_value(priv->gpiod_enable, val); + + return 0; +} + +static const struct snd_soc_dapm_widget dio2125_dapm_widgets[] = { + SND_SOC_DAPM_INPUT("INL"), + SND_SOC_DAPM_INPUT("INR"), + SND_SOC_DAPM_OUT_DRV_E("DRV", SND_SOC_NOPM, 0, 0, NULL, 0, drv_event, + (SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD)), + SND_SOC_DAPM_OUTPUT("OUTL"), + SND_SOC_DAPM_OUTPUT("OUTR"), +}; + +static const struct snd_soc_dapm_route dio2125_dapm_routes[] = { + { "DRV", NULL, "INL" }, + { "DRV", NULL, "INR" }, + { "OUTL", NULL, "DRV" }, + { "OUTR", NULL, "DRV" }, +}; + +static const struct snd_soc_component_driver dio2125_component_driver = { + .dapm_widgets = dio2125_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(dio2125_dapm_widgets), + .dapm_routes = dio2125_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(dio2125_dapm_routes), +}; + +static int dio2125_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct dio2125 *priv; + int err; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (priv == NULL) + return -ENOMEM; + platform_set_drvdata(pdev, priv); + + priv->gpiod_enable = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW); + if (IS_ERR(priv->gpiod_enable)) { + err = PTR_ERR(priv->gpiod_enable); + if (err != -EPROBE_DEFER) + dev_err(dev, "Failed to get 'enable' gpio: %d", err); + return err; + } + + return devm_snd_soc_register_component(dev, &dio2125_component_driver, + NULL, 0); +} + +#ifdef CONFIG_OF +static const struct of_device_id dio2125_ids[] = { + { .compatible = "dioo,dio2125", }, + { } +}; +MODULE_DEVICE_TABLE(of, dio2125_ids); +#endif + +static struct platform_driver dio2125_driver = { + .driver = { + .name = DRV_NAME, + .of_match_table = of_match_ptr(dio2125_ids), + }, + .probe = dio2125_probe, +}; + +module_platform_driver(dio2125_driver); + +MODULE_DESCRIPTION("ASoC DIO2125 output driver"); +MODULE_AUTHOR("Jerome Brunet "); +MODULE_LICENSE("GPL"); -- cgit v1.2.1 From 08458871b60c4bfe49973ce1c27a2b4bc4c159b0 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 21 Feb 2017 18:50:05 +0000 Subject: ASoC: Intel: Skylake: fix spelling mistake: "allocationf" -> "allocation" Trivial fix to spelling mistake in dev_err message. Signed-off-by: Colin Ian King Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-pcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index e12520e142ff..635cbb1e7d91 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -1165,7 +1165,7 @@ static int skl_pcm_new(struct snd_soc_pcm_runtime *rtd) snd_dma_pci_data(skl->pci), size, MAX_PREALLOC_SIZE); if (retval) { - dev_err(dai->dev, "dma buffer allocationf fail\n"); + dev_err(dai->dev, "dma buffer allocation fail\n"); return retval; } } -- cgit v1.2.1 From b3ec72ace939b0abd75d5d875e77cf0b777debb7 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 20 Feb 2017 19:46:10 +0200 Subject: ASoC: Intel: bdw-rt5677: Use devm_gpiod_get() Since index is always 0 replace devm_gpiod_get_index() by devm_gpiod_get() and apply proper flags. Signed-off-by: Andy Shevchenko Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/intel/boards/bdw-rt5677.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/intel/boards/bdw-rt5677.c b/sound/soc/intel/boards/bdw-rt5677.c index 53c6b4cbb1e1..14d9693c1641 100644 --- a/sound/soc/intel/boards/bdw-rt5677.c +++ b/sound/soc/intel/boards/bdw-rt5677.c @@ -193,13 +193,12 @@ static int bdw_rt5677_init(struct snd_soc_pcm_runtime *rtd) RT5677_CLK_SEL_I2S1_ASRC); /* Request rt5677 GPIO for headphone amp control */ - bdw_rt5677->gpio_hp_en = devm_gpiod_get_index(codec->dev, - "headphone-enable", 0, 0); + bdw_rt5677->gpio_hp_en = devm_gpiod_get(codec->dev, "headphone-enable", + GPIOD_OUT_LOW); if (IS_ERR(bdw_rt5677->gpio_hp_en)) { dev_err(codec->dev, "Can't find HP_AMP_SHDN_L gpio\n"); return PTR_ERR(bdw_rt5677->gpio_hp_en); } - gpiod_direction_output(bdw_rt5677->gpio_hp_en, 0); /* Create and initialize headphone jack */ if (!snd_soc_card_jack_new(rtd->card, "Headphone Jack", -- cgit v1.2.1 From 31d648f051fe82c9d6c2176b1b5ee402b1a18f21 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Fri, 17 Feb 2017 22:48:56 +0530 Subject: ASoC: Intel: bxtn: Store the FW/Library context at boot Store the DSP firmware/library at boot, so that for S3 to S0 transition use the stored ctx for downloading the firmware to DSP memory. Signed-off-by: Jeeja KP Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/bxt-sst.c | 55 +++++++++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 19 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/intel/skylake/bxt-sst.c b/sound/soc/intel/skylake/bxt-sst.c index 15a063a403cc..7762d5a18fce 100644 --- a/sound/soc/intel/skylake/bxt-sst.c +++ b/sound/soc/intel/skylake/bxt-sst.c @@ -50,33 +50,47 @@ static unsigned int bxt_get_errorcode(struct sst_dsp *ctx) return sst_dsp_shim_read(ctx, BXT_ADSP_ERROR_CODE); } +static void sst_bxt_release_library(struct skl_lib_info *linfo, int lib_count) +{ + int i; + + for (i = 1; i < lib_count; i++) { + if (linfo[i].fw) { + release_firmware(linfo[i].fw); + linfo[i].fw = NULL; + } + } +} + static int bxt_load_library(struct sst_dsp *ctx, struct skl_lib_info *linfo, int lib_count) { struct snd_dma_buffer dmab; struct skl_sst *skl = ctx->thread_context; - const struct firmware *fw = NULL; struct firmware stripped_fw; int ret = 0, i, dma_id, stream_tag; /* library indices start from 1 to N. 0 represents base FW */ for (i = 1; i < lib_count; i++) { - ret = request_firmware(&fw, linfo[i].name, ctx->dev); - if (ret < 0) { - dev_err(ctx->dev, "Request lib %s failed:%d\n", + if (linfo[i].fw == NULL) { + ret = request_firmware(&linfo[i].fw, linfo[i].name, + ctx->dev); + if (ret < 0) { + dev_err(ctx->dev, "Request lib %s failed:%d\n", linfo[i].name, ret); - return ret; + goto load_library_failed; + } } if (skl->is_first_boot) { - ret = snd_skl_parse_uuids(ctx, fw, + ret = snd_skl_parse_uuids(ctx, linfo[i].fw, BXT_ADSP_FW_BIN_HDR_OFFSET, i); if (ret < 0) goto load_library_failed; } - stripped_fw.data = fw->data; - stripped_fw.size = fw->size; + stripped_fw.data = linfo[i].fw->data; + stripped_fw.size = linfo[i].fw->size; skl_dsp_strip_extended_manifest(&stripped_fw); stream_tag = ctx->dsp_ops.prepare(ctx->dev, 0x40, @@ -99,14 +113,12 @@ bxt_load_library(struct sst_dsp *ctx, struct skl_lib_info *linfo, int lib_count) ctx->dsp_ops.trigger(ctx->dev, false, stream_tag); ctx->dsp_ops.cleanup(ctx->dev, &dmab, stream_tag); - release_firmware(fw); - fw = NULL; } return ret; load_library_failed: - release_firmware(fw); + sst_bxt_release_library(linfo, lib_count); return ret; } @@ -208,16 +220,14 @@ static int bxt_load_base_firmware(struct sst_dsp *ctx) struct skl_sst *skl = ctx->thread_context; int ret; - ret = request_firmware(&ctx->fw, ctx->fw_name, ctx->dev); - if (ret < 0) { - dev_err(ctx->dev, "Request firmware failed %d\n", ret); - goto sst_load_base_firmware_failed; + if (ctx->fw == NULL) { + ret = request_firmware(&ctx->fw, ctx->fw_name, ctx->dev); + if (ret < 0) { + dev_err(ctx->dev, "Request firmware failed %d\n", ret); + return ret; + } } - /* check for extended manifest */ - if (ctx->fw == NULL) - goto sst_load_base_firmware_failed; - /* prase uuids on first boot */ if (skl->is_first_boot) { ret = snd_skl_parse_uuids(ctx, ctx->fw, BXT_ADSP_FW_BIN_HDR_OFFSET, 0); @@ -265,8 +275,11 @@ static int bxt_load_base_firmware(struct sst_dsp *ctx) } } + return ret; + sst_load_base_firmware_failed: release_firmware(ctx->fw); + ctx->fw = NULL; return ret; } @@ -635,6 +648,10 @@ EXPORT_SYMBOL_GPL(bxt_sst_init_fw); void bxt_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx) { + + sst_bxt_release_library(ctx->lib_info, ctx->lib_count); + if (ctx->dsp->fw) + release_firmware(ctx->dsp->fw); skl_freeup_uuid_list(ctx); skl_ipc_free(&ctx->ipc); ctx->dsp->cl_dev.ops.cl_cleanup_controller(ctx->dsp); -- cgit v1.2.1 From 7d3f91dc1e4db18b644695c9442c62679a5dff6e Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Fri, 17 Feb 2017 22:48:57 +0530 Subject: ASoC: Intel: bxtn: optimize ROM init retries During S3->S0 transition, sometime ROM init fails because of authentication engine loads later than the OS. In this case driver waits for a longer period and then retries the FW download causing huge delay in resume time of audio device. To avoid this, ROM INIT wait time is set to a optimal value and increased the retries for firmware download. Signed-off-by: Jeeja KP Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/bxt-sst.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/intel/skylake/bxt-sst.c b/sound/soc/intel/skylake/bxt-sst.c index 7762d5a18fce..d3be1be5a372 100644 --- a/sound/soc/intel/skylake/bxt-sst.c +++ b/sound/soc/intel/skylake/bxt-sst.c @@ -25,7 +25,8 @@ #include "skl-sst-ipc.h" #define BXT_BASEFW_TIMEOUT 3000 -#define BXT_INIT_TIMEOUT 500 +#define BXT_INIT_TIMEOUT 300 +#define BXT_ROM_INIT_TIMEOUT 70 #define BXT_IPC_PURGE_FW 0x01004000 #define BXT_ROM_INIT 0x5 @@ -45,6 +46,8 @@ /* Delay before scheduling D0i3 entry */ #define BXT_D0I3_DELAY 5000 +#define BXT_FW_ROM_INIT_RETRY 3 + static unsigned int bxt_get_errorcode(struct sst_dsp *ctx) { return sst_dsp_shim_read(ctx, BXT_ADSP_ERROR_CODE); @@ -185,7 +188,7 @@ static int sst_bxt_prepare_fw(struct sst_dsp *ctx, /* Step 7: Wait for ROM init */ ret = sst_dsp_register_poll(ctx, BXT_ADSP_FW_STATUS, SKL_FW_STS_MASK, - SKL_FW_INIT, BXT_INIT_TIMEOUT, "ROM Load"); + SKL_FW_INIT, BXT_ROM_INIT_TIMEOUT, "ROM Load"); if (ret < 0) { dev_err(ctx->dev, "Timeout for ROM init, ret:%d\n", ret); goto base_fw_load_failed; @@ -218,7 +221,7 @@ static int bxt_load_base_firmware(struct sst_dsp *ctx) { struct firmware stripped_fw; struct skl_sst *skl = ctx->thread_context; - int ret; + int ret, i; if (ctx->fw == NULL) { ret = request_firmware(&ctx->fw, ctx->fw_name, ctx->dev); @@ -239,18 +242,20 @@ static int bxt_load_base_firmware(struct sst_dsp *ctx) stripped_fw.size = ctx->fw->size; skl_dsp_strip_extended_manifest(&stripped_fw); - ret = sst_bxt_prepare_fw(ctx, stripped_fw.data, stripped_fw.size); - /* Retry Enabling core and ROM load. Retry seemed to help */ - if (ret < 0) { + + for (i = 0; i < BXT_FW_ROM_INIT_RETRY; i++) { ret = sst_bxt_prepare_fw(ctx, stripped_fw.data, stripped_fw.size); - if (ret < 0) { - dev_err(ctx->dev, "Error code=0x%x: FW status=0x%x\n", + if (ret == 0) + break; + } + + if (ret < 0) { + dev_err(ctx->dev, "Error code=0x%x: FW status=0x%x\n", sst_dsp_shim_read(ctx, BXT_ADSP_ERROR_CODE), sst_dsp_shim_read(ctx, BXT_ADSP_FW_STATUS)); - dev_err(ctx->dev, "Core En/ROM load fail:%d\n", ret); - goto sst_load_base_firmware_failed; - } + dev_err(ctx->dev, "Core En/ROM load fail:%d\n", ret); + goto sst_load_base_firmware_failed; } ret = sst_transfer_fw_host_dma(ctx); -- cgit v1.2.1 From e2c187a689b4a717024ba90c67a6ecd8ff36a23e Mon Sep 17 00:00:00 2001 From: Codrut Grosu Date: Sat, 25 Feb 2017 13:18:08 +0200 Subject: ASoC: tegra: Remove unnecessary 'out of memory' message This was reported by checkpatch.pl Signed-off-by: Codrut GROSU Acked-by: Thierry Reding Signed-off-by: Mark Brown --- sound/soc/tegra/tegra20_ac97.c | 1 - sound/soc/tegra/tegra20_das.c | 1 - sound/soc/tegra/tegra20_i2s.c | 1 - sound/soc/tegra/tegra20_spdif.c | 5 ++--- sound/soc/tegra/tegra30_ahub.c | 4 +--- sound/soc/tegra/tegra30_i2s.c | 1 - sound/soc/tegra/tegra_alc5632.c | 4 +--- sound/soc/tegra/tegra_max98090.c | 4 +--- sound/soc/tegra/tegra_rt5640.c | 4 +--- sound/soc/tegra/tegra_sgtl5000.c | 4 +--- sound/soc/tegra/tegra_wm8753.c | 4 +--- sound/soc/tegra/tegra_wm8903.c | 4 +--- sound/soc/tegra/tegra_wm9712.c | 4 +--- sound/soc/tegra/trimslice.c | 4 +--- 14 files changed, 11 insertions(+), 34 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/tegra/tegra20_ac97.c b/sound/soc/tegra/tegra20_ac97.c index a68368edab9c..affad46bf188 100644 --- a/sound/soc/tegra/tegra20_ac97.c +++ b/sound/soc/tegra/tegra20_ac97.c @@ -318,7 +318,6 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev) ac97 = devm_kzalloc(&pdev->dev, sizeof(struct tegra20_ac97), GFP_KERNEL); if (!ac97) { - dev_err(&pdev->dev, "Can't allocate tegra20_ac97\n"); ret = -ENOMEM; goto err; } diff --git a/sound/soc/tegra/tegra20_das.c b/sound/soc/tegra/tegra20_das.c index 89add13c31cf..6d4a2774135e 100644 --- a/sound/soc/tegra/tegra20_das.c +++ b/sound/soc/tegra/tegra20_das.c @@ -142,7 +142,6 @@ static int tegra20_das_probe(struct platform_device *pdev) das = devm_kzalloc(&pdev->dev, sizeof(struct tegra20_das), GFP_KERNEL); if (!das) { - dev_err(&pdev->dev, "Can't allocate tegra20_das\n"); ret = -ENOMEM; goto err; } diff --git a/sound/soc/tegra/tegra20_i2s.c b/sound/soc/tegra/tegra20_i2s.c index 14106fa82bca..26253c2849e7 100644 --- a/sound/soc/tegra/tegra20_i2s.c +++ b/sound/soc/tegra/tegra20_i2s.c @@ -345,7 +345,6 @@ static int tegra20_i2s_platform_probe(struct platform_device *pdev) i2s = devm_kzalloc(&pdev->dev, sizeof(struct tegra20_i2s), GFP_KERNEL); if (!i2s) { - dev_err(&pdev->dev, "Can't allocate tegra20_i2s\n"); ret = -ENOMEM; goto err; } diff --git a/sound/soc/tegra/tegra20_spdif.c b/sound/soc/tegra/tegra20_spdif.c index a0c3640572b9..767c0491e11a 100644 --- a/sound/soc/tegra/tegra20_spdif.c +++ b/sound/soc/tegra/tegra20_spdif.c @@ -271,10 +271,9 @@ static int tegra20_spdif_platform_probe(struct platform_device *pdev) spdif = devm_kzalloc(&pdev->dev, sizeof(struct tegra20_spdif), GFP_KERNEL); - if (!spdif) { - dev_err(&pdev->dev, "Can't allocate tegra20_spdif\n"); + if (!spdif) return -ENOMEM; - } + dev_set_drvdata(&pdev->dev, spdif); spdif->clk_spdif_out = devm_clk_get(&pdev->dev, "spdif_out"); diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c index fef3b9a21a66..d7494c0e9053 100644 --- a/sound/soc/tegra/tegra30_ahub.c +++ b/sound/soc/tegra/tegra30_ahub.c @@ -560,10 +560,8 @@ static int tegra30_ahub_probe(struct platform_device *pdev) ahub = devm_kzalloc(&pdev->dev, sizeof(struct tegra30_ahub), GFP_KERNEL); - if (!ahub) { - dev_err(&pdev->dev, "Can't allocate tegra30_ahub\n"); + if (!ahub) return -ENOMEM; - } dev_set_drvdata(&pdev->dev, ahub); ahub->soc_data = soc_data; diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c index 8e55583aa104..b2b279c96029 100644 --- a/sound/soc/tegra/tegra30_i2s.c +++ b/sound/soc/tegra/tegra30_i2s.c @@ -385,7 +385,6 @@ static int tegra30_i2s_platform_probe(struct platform_device *pdev) i2s = devm_kzalloc(&pdev->dev, sizeof(struct tegra30_i2s), GFP_KERNEL); if (!i2s) { - dev_err(&pdev->dev, "Can't allocate tegra30_i2s\n"); ret = -ENOMEM; goto err; } diff --git a/sound/soc/tegra/tegra_alc5632.c b/sound/soc/tegra/tegra_alc5632.c index eead6e7f205b..0509902512cc 100644 --- a/sound/soc/tegra/tegra_alc5632.c +++ b/sound/soc/tegra/tegra_alc5632.c @@ -169,10 +169,8 @@ static int tegra_alc5632_probe(struct platform_device *pdev) alc5632 = devm_kzalloc(&pdev->dev, sizeof(struct tegra_alc5632), GFP_KERNEL); - if (!alc5632) { - dev_err(&pdev->dev, "Can't allocate tegra_alc5632\n"); + if (!alc5632) return -ENOMEM; - } card->dev = &pdev->dev; platform_set_drvdata(pdev, card); diff --git a/sound/soc/tegra/tegra_max98090.c b/sound/soc/tegra/tegra_max98090.c index a403db6d563e..c34a54d6e812 100644 --- a/sound/soc/tegra/tegra_max98090.c +++ b/sound/soc/tegra/tegra_max98090.c @@ -225,10 +225,8 @@ static int tegra_max98090_probe(struct platform_device *pdev) machine = devm_kzalloc(&pdev->dev, sizeof(struct tegra_max98090), GFP_KERNEL); - if (!machine) { - dev_err(&pdev->dev, "Can't allocate tegra_max98090\n"); + if (!machine) return -ENOMEM; - } card->dev = &pdev->dev; platform_set_drvdata(pdev, card); diff --git a/sound/soc/tegra/tegra_rt5640.c b/sound/soc/tegra/tegra_rt5640.c index 25b9fc03ba62..93a356802345 100644 --- a/sound/soc/tegra/tegra_rt5640.c +++ b/sound/soc/tegra/tegra_rt5640.c @@ -170,10 +170,8 @@ static int tegra_rt5640_probe(struct platform_device *pdev) machine = devm_kzalloc(&pdev->dev, sizeof(struct tegra_rt5640), GFP_KERNEL); - if (!machine) { - dev_err(&pdev->dev, "Can't allocate tegra_rt5640\n"); + if (!machine) return -ENOMEM; - } card->dev = &pdev->dev; platform_set_drvdata(pdev, card); diff --git a/sound/soc/tegra/tegra_sgtl5000.c b/sound/soc/tegra/tegra_sgtl5000.c index 4bbab098f50b..6dda01f69983 100644 --- a/sound/soc/tegra/tegra_sgtl5000.c +++ b/sound/soc/tegra/tegra_sgtl5000.c @@ -120,10 +120,8 @@ static int tegra_sgtl5000_driver_probe(struct platform_device *pdev) machine = devm_kzalloc(&pdev->dev, sizeof(struct tegra_sgtl5000), GFP_KERNEL); - if (!machine) { - dev_err(&pdev->dev, "Can't allocate tegra_sgtl5000 struct\n"); + if (!machine) return -ENOMEM; - } card->dev = &pdev->dev; platform_set_drvdata(pdev, card); diff --git a/sound/soc/tegra/tegra_wm8753.c b/sound/soc/tegra/tegra_wm8753.c index bdedd1028569..d0ab0026a4cd 100644 --- a/sound/soc/tegra/tegra_wm8753.c +++ b/sound/soc/tegra/tegra_wm8753.c @@ -128,10 +128,8 @@ static int tegra_wm8753_driver_probe(struct platform_device *pdev) machine = devm_kzalloc(&pdev->dev, sizeof(struct tegra_wm8753), GFP_KERNEL); - if (!machine) { - dev_err(&pdev->dev, "Can't allocate tegra_wm8753 struct\n"); + if (!machine) return -ENOMEM; - } card->dev = &pdev->dev; platform_set_drvdata(pdev, card); diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c index 2013e9c4bba0..dbfb49298ae8 100644 --- a/sound/soc/tegra/tegra_wm8903.c +++ b/sound/soc/tegra/tegra_wm8903.c @@ -248,10 +248,8 @@ static int tegra_wm8903_driver_probe(struct platform_device *pdev) machine = devm_kzalloc(&pdev->dev, sizeof(struct tegra_wm8903), GFP_KERNEL); - if (!machine) { - dev_err(&pdev->dev, "Can't allocate tegra_wm8903 struct\n"); + if (!machine) return -ENOMEM; - } card->dev = &pdev->dev; platform_set_drvdata(pdev, card); diff --git a/sound/soc/tegra/tegra_wm9712.c b/sound/soc/tegra/tegra_wm9712.c index 6492f8143ff1..c9cd22432627 100644 --- a/sound/soc/tegra/tegra_wm9712.c +++ b/sound/soc/tegra/tegra_wm9712.c @@ -77,10 +77,8 @@ static int tegra_wm9712_driver_probe(struct platform_device *pdev) machine = devm_kzalloc(&pdev->dev, sizeof(struct tegra_wm9712), GFP_KERNEL); - if (!machine) { - dev_err(&pdev->dev, "Can't allocate tegra_wm9712 struct\n"); + if (!machine) return -ENOMEM; - } card->dev = &pdev->dev; platform_set_drvdata(pdev, card); diff --git a/sound/soc/tegra/trimslice.c b/sound/soc/tegra/trimslice.c index 870f84ab5005..c9dcad9bb931 100644 --- a/sound/soc/tegra/trimslice.c +++ b/sound/soc/tegra/trimslice.c @@ -123,10 +123,8 @@ static int tegra_snd_trimslice_probe(struct platform_device *pdev) trimslice = devm_kzalloc(&pdev->dev, sizeof(struct tegra_trimslice), GFP_KERNEL); - if (!trimslice) { - dev_err(&pdev->dev, "Can't allocate tegra_trimslice\n"); + if (!trimslice) return -ENOMEM; - } card->dev = &pdev->dev; platform_set_drvdata(pdev, card); -- cgit v1.2.1 From ec5a82d6c0b860bf4cba5c7ef8646ae5dad9f5a6 Mon Sep 17 00:00:00 2001 From: Adrian Dinu Date: Sat, 25 Feb 2017 13:23:00 +0200 Subject: ASoC: Add space around '=' This was reported by checkpatch.pl Signed-off-by: Adrian Dinu Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 6dca408faae3..d29fbc7195a0 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3139,7 +3139,7 @@ static int snd_soc_component_initialize(struct snd_soc_component *component, component->suspend = component->driver->suspend; component->resume = component->driver->resume; component->pcm_new = component->driver->pcm_new; - component->pcm_free= component->driver->pcm_free; + component->pcm_free = component->driver->pcm_free; dapm = &component->dapm; dapm->dev = dev; -- cgit v1.2.1 From 1dbe692380de6eebdd3702b820a4bee6b931a2e5 Mon Sep 17 00:00:00 2001 From: Codrut Grosu Date: Sat, 25 Feb 2017 23:33:50 +0200 Subject: ASoC: pxa-ssp: Added blank line after declarations This was reported by checkpatch.pl Signed-off-by: Codrut Grosu Signed-off-by: Mark Brown --- sound/soc/pxa/pxa-ssp.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound/soc') diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index 3cad990dad2c..e9f6df38b152 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c @@ -354,6 +354,7 @@ static int pxa_ssp_set_dai_pll(struct snd_soc_dai *cpu_dai, int pll_id, if (ssp->type == PXA3xx_SSP) { u32 val; u64 tmp = 19968; + tmp *= 1000000; do_div(tmp, freq_out); val = tmp; -- cgit v1.2.1 From 3e22e9d702ee719c8106fd44578b12ce27999ae6 Mon Sep 17 00:00:00 2001 From: Codrut Grosu Date: Sat, 25 Feb 2017 22:33:00 +0200 Subject: ASoC: pxa: Remove space before semicolon This was reported by checkpatch.pl Signed-off-by: Codrut Grosu Signed-off-by: Mark Brown --- sound/soc/pxa/spitz.c | 4 ++-- sound/soc/pxa/z2.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c index 07d77cddac60..d38a2b519c52 100644 --- a/sound/soc/pxa/spitz.c +++ b/sound/soc/pxa/spitz.c @@ -230,8 +230,8 @@ static const struct snd_soc_dapm_route spitz_audio_map[] = { {"Headset Jack", NULL, "ROUT1"}, /* ext speaker connected to LOUT2, ROUT2 */ - {"Ext Spk", NULL , "ROUT2"}, - {"Ext Spk", NULL , "LOUT2"}, + {"Ext Spk", NULL, "ROUT2"}, + {"Ext Spk", NULL, "LOUT2"}, /* mic is connected to input 1 - with bias */ {"LINPUT1", NULL, "Mic Bias"}, diff --git a/sound/soc/pxa/z2.c b/sound/soc/pxa/z2.c index 990b1aa6d7f6..6d88d9acc666 100644 --- a/sound/soc/pxa/z2.c +++ b/sound/soc/pxa/z2.c @@ -119,8 +119,8 @@ static const struct snd_soc_dapm_route z2_audio_map[] = { {"Headphone Jack", NULL, "ROUT1"}, /* ext speaker connected to LOUT2, ROUT2 */ - {"Ext Spk", NULL , "ROUT2"}, - {"Ext Spk", NULL , "LOUT2"}, + {"Ext Spk", NULL, "ROUT2"}, + {"Ext Spk", NULL, "LOUT2"}, /* mic is connected to R input 2 - with bias */ {"RINPUT2", NULL, "Mic Bias"}, -- cgit v1.2.1 From 291aaff0c6f2c56645061b9c8afadc0bb1251676 Mon Sep 17 00:00:00 2001 From: Codrut Grosu Date: Sat, 25 Feb 2017 23:26:56 +0200 Subject: ASoC: pxa: Remove unneeded else after return statement This was reported by checkpatch.pl Signed-off-by: Codrut Grosu Signed-off-by: Mark Brown --- sound/soc/pxa/pxa2xx-ac97.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c index 2e2fb1838ec2..f49bf02e5ec2 100644 --- a/sound/soc/pxa/pxa2xx-ac97.c +++ b/sound/soc/pxa/pxa2xx-ac97.c @@ -140,9 +140,8 @@ static int pxa2xx_ac97_mic_startup(struct snd_pcm_substream *substream, { if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) return -ENODEV; - else - snd_soc_dai_set_dma_data(cpu_dai, substream, - &pxa2xx_ac97_pcm_mic_mono_in); + snd_soc_dai_set_dma_data(cpu_dai, substream, + &pxa2xx_ac97_pcm_mic_mono_in); return 0; } -- cgit v1.2.1 From 05af0917aaf8a0755de8fbbf72153ad6ca1f5443 Mon Sep 17 00:00:00 2001 From: Codrut Grosu Date: Sat, 25 Feb 2017 23:54:16 +0200 Subject: ASoC: pxa: The open brace is placed with the previous line This was reported by checkpatch.pl Signed-off-by: Codrut Grosu Signed-off-by: Mark Brown --- sound/soc/pxa/raumfeld.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/pxa/raumfeld.c b/sound/soc/pxa/raumfeld.c index 552b763005ed..47c91730e93c 100644 --- a/sound/soc/pxa/raumfeld.c +++ b/sound/soc/pxa/raumfeld.c @@ -228,14 +228,12 @@ static struct snd_soc_ops raumfeld_ak4104_ops = { .codec_name = "spi0.0", \ } -static struct snd_soc_dai_link snd_soc_raumfeld_connector_dai[] = -{ +static struct snd_soc_dai_link snd_soc_raumfeld_connector_dai[] = { DAI_LINK_CS4270, DAI_LINK_AK4104, }; -static struct snd_soc_dai_link snd_soc_raumfeld_speaker_dai[] = -{ +static struct snd_soc_dai_link snd_soc_raumfeld_speaker_dai[] = { DAI_LINK_CS4270, }; -- cgit v1.2.1 From ca87cfad69e6b657a4f5fa665b67aee275792af4 Mon Sep 17 00:00:00 2001 From: Codrut Grosu Date: Sat, 25 Feb 2017 22:42:33 +0200 Subject: ASoC: pxa: Add space around ':' and '(' This was reported by checkpatch.pl Signed-off-by: Codrut Grosu Signed-off-by: Mark Brown --- sound/soc/pxa/pxa2xx-i2s.c | 2 +- sound/soc/pxa/tosa.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c index 0389cf7b4b1e..27aa0e4341bc 100644 --- a/sound/soc/pxa/pxa2xx-i2s.c +++ b/sound/soc/pxa/pxa2xx-i2s.c @@ -119,7 +119,7 @@ static int pxa_i2s_wait(void) int i; /* flush the Rx FIFO */ - for(i = 0; i < 16; i++) + for (i = 0; i < 16; i++) SADR; return 0; } diff --git a/sound/soc/pxa/tosa.c b/sound/soc/pxa/tosa.c index e022b2a777f6..1812748b75bf 100644 --- a/sound/soc/pxa/tosa.c +++ b/sound/soc/pxa/tosa.c @@ -133,7 +133,7 @@ static int tosa_set_spk(struct snd_kcontrol *kcontrol, static int tosa_hp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) { - gpio_set_value(TOSA_GPIO_L_MUTE, SND_SOC_DAPM_EVENT_ON(event) ? 1 :0); + gpio_set_value(TOSA_GPIO_L_MUTE, SND_SOC_DAPM_EVENT_ON(event) ? 1 : 0); return 0; } -- cgit v1.2.1 From 672e3cbe783e2f3f40bdc19e5cb09accdd3e4b6b Mon Sep 17 00:00:00 2001 From: Codrut Grosu Date: Sat, 25 Feb 2017 22:50:29 +0200 Subject: ASoC: pxa: Remove spaces before tabs This was reported by checkpatch.pl Signed-off-by: Codrut Grosu Signed-off-by: Mark Brown --- sound/soc/pxa/pxa2xx-i2s.c | 6 +++--- sound/soc/pxa/pxa2xx-pcm.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c index 27aa0e4341bc..3fb60baf6eab 100644 --- a/sound/soc/pxa/pxa2xx-i2s.c +++ b/sound/soc/pxa/pxa2xx-i2s.c @@ -46,10 +46,10 @@ #define SACR0_STRF (1 << 5) /* FIFO Select for EFWR Special Function */ #define SACR0_EFWR (1 << 4) /* Enable EFWR Function */ #define SACR0_RST (1 << 3) /* FIFO, i2s Register Reset */ -#define SACR0_BCKD (1 << 2) /* Bit Clock Direction */ +#define SACR0_BCKD (1 << 2) /* Bit Clock Direction */ #define SACR0_ENB (1 << 0) /* Enable I2S Link */ #define SACR1_ENLBF (1 << 5) /* Enable Loopback */ -#define SACR1_DRPL (1 << 4) /* Disable Replaying Function */ +#define SACR1_DRPL (1 << 4) /* Disable Replaying Function */ #define SACR1_DREC (1 << 3) /* Disable Recording Function */ #define SACR1_AMSL (1 << 0) /* Specify Alternate Mode */ @@ -60,7 +60,7 @@ #define SASR0_TFS (1 << 3) /* Tx FIFO Service Request */ #define SASR0_BSY (1 << 2) /* I2S Busy */ #define SASR0_RNE (1 << 1) /* Rx FIFO Not Empty */ -#define SASR0_TNF (1 << 0) /* Tx FIFO Not Empty */ +#define SASR0_TNF (1 << 0) /* Tx FIFO Not Empty */ #define SAICR_ROR (1 << 6) /* Clear Rx FIFO Overrun Interrupt */ #define SAICR_TUR (1 << 5) /* Clear Tx FIFO Underrun Interrupt */ diff --git a/sound/soc/pxa/pxa2xx-pcm.c b/sound/soc/pxa/pxa2xx-pcm.c index 410d48b93031..b51d7a0755d5 100644 --- a/sound/soc/pxa/pxa2xx-pcm.c +++ b/sound/soc/pxa/pxa2xx-pcm.c @@ -85,7 +85,7 @@ static int pxa2xx_soc_pcm_new(struct snd_soc_pcm_runtime *rtd) } static struct snd_soc_platform_driver pxa2xx_soc_platform = { - .ops = &pxa2xx_pcm_ops, + .ops = &pxa2xx_pcm_ops, .pcm_new = pxa2xx_soc_pcm_new, .pcm_free = pxa2xx_pcm_free_dma_buffers, }; -- cgit v1.2.1 From 17339f6099154678485244cc17d700f19ece0dc0 Mon Sep 17 00:00:00 2001 From: Codrut Grosu Date: Sat, 25 Feb 2017 23:06:36 +0200 Subject: ASoC: pxa: Remove unneeded return statement in void function This was reported by checkpatch.pl Signed-off-by: Codrut Grosu Signed-off-by: Mark Brown --- sound/soc/pxa/mmp-pcm.c | 1 - sound/soc/pxa/mmp-sspa.c | 1 - 2 files changed, 2 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/pxa/mmp-pcm.c b/sound/soc/pxa/mmp-pcm.c index 96df9b2d8fc4..5b5f1a442891 100644 --- a/sound/soc/pxa/mmp-pcm.c +++ b/sound/soc/pxa/mmp-pcm.c @@ -166,7 +166,6 @@ static void mmp_pcm_free_dma_buffers(struct snd_pcm *pcm) buf->area = NULL; } - return; } static int mmp_pcm_preallocate_dma_buffer(struct snd_pcm_substream *substream, diff --git a/sound/soc/pxa/mmp-sspa.c b/sound/soc/pxa/mmp-sspa.c index ca8b23f8c525..9cc35012e6e5 100644 --- a/sound/soc/pxa/mmp-sspa.c +++ b/sound/soc/pxa/mmp-sspa.c @@ -119,7 +119,6 @@ static void mmp_sspa_shutdown(struct snd_pcm_substream *substream, clk_disable(priv->sspa->clk); clk_disable(priv->sysclk); - return; } /* -- cgit v1.2.1 From 34e82433c26ea6908fa19783fee2c4bba5bad9c8 Mon Sep 17 00:00:00 2001 From: Codrut Grosu Date: Sat, 25 Feb 2017 23:40:31 +0200 Subject: ASoC: pxa-ssp: Line up *s in block comments This was reported by checkpatch.pl Signed-off-by: Codrut Grosu Signed-off-by: Mark Brown --- sound/soc/pxa/pxa-ssp.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index e9f6df38b152..0291c7cb64eb 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c @@ -591,13 +591,13 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream, if ((pxa_ssp_get_scr(ssp) == 4) && (width == 16)) { /* This is a special case where the bitclk is 64fs - * and we're not dealing with 2*32 bits of audio - * samples. - * - * The SSP values used for that are all found out by - * trying and failing a lot; some of the registers - * needed for that mode are only available on PXA3xx. - */ + * and we're not dealing with 2*32 bits of audio + * samples. + * + * The SSP values used for that are all found out by + * trying and failing a lot; some of the registers + * needed for that mode are only available on PXA3xx. + */ if (ssp->type != PXA3xx_SSP) return -EINVAL; -- cgit v1.2.1 From 8804e073a8b7b85e98e46a239da4d2d92adfe124 Mon Sep 17 00:00:00 2001 From: Adriana Constantinescu Date: Sun, 26 Feb 2017 21:12:06 +0200 Subject: ASoC: omap: Remove unnecessary 'out of memory' message Out of memory message detected using checkpatch.pl Signed-off-by: Adriana Constantinescu Acked-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/omap/rx51.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/omap/rx51.c b/sound/soc/omap/rx51.c index a76845748a10..086b59b7b6d7 100644 --- a/sound/soc/omap/rx51.c +++ b/sound/soc/omap/rx51.c @@ -433,10 +433,9 @@ static int rx51_soc_probe(struct platform_device *pdev) } pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); - if (pdata == NULL) { - dev_err(card->dev, "failed to create private data\n"); + if (pdata == NULL) return -ENOMEM; - } + snd_soc_card_set_drvdata(card, pdata); pdata->tvout_selection_gpio = devm_gpiod_get(card->dev, -- cgit v1.2.1 From bf3c6ef7f5b1e43739ad0356a5afee5127c86465 Mon Sep 17 00:00:00 2001 From: Codrut Grosu Date: Sat, 25 Feb 2017 20:59:17 +0200 Subject: ASoC: tegra: Add blank line after declarations This was reported by checkpatch.pl Signed-off-by: Codrut GROSU Acked-by: Thierry Reding Signed-off-by: Mark Brown --- sound/soc/tegra/tegra20_das.c | 1 + sound/soc/tegra/tegra30_ahub.c | 1 + 2 files changed, 2 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/tegra/tegra20_das.c b/sound/soc/tegra/tegra20_das.c index 6d4a2774135e..4024e3abbeed 100644 --- a/sound/soc/tegra/tegra20_das.c +++ b/sound/soc/tegra/tegra20_das.c @@ -41,6 +41,7 @@ static inline void tegra20_das_write(u32 reg, u32 val) static inline u32 tegra20_das_read(u32 reg) { u32 val; + regmap_read(das->regmap, reg, &val); return val; } diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c index d7494c0e9053..8c10ae7982ba 100644 --- a/sound/soc/tegra/tegra30_ahub.c +++ b/sound/soc/tegra/tegra30_ahub.c @@ -41,6 +41,7 @@ static inline void tegra30_apbif_write(u32 reg, u32 val) static inline u32 tegra30_apbif_read(u32 reg) { u32 val; + regmap_read(ahub->regmap_apbif, reg, &val); return val; } -- cgit v1.2.1 From c2dcce361ab7161e494e93f19a2945574c5a2cd7 Mon Sep 17 00:00:00 2001 From: Codrut Grosu Date: Sat, 25 Feb 2017 21:17:53 +0200 Subject: ASoC: txx9: Added blank line after declarations This was reported by checkpatch.pl Signed-off-by: Codrut GROSU Signed-off-by: Mark Brown --- sound/soc/txx9/txx9aclc.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound/soc') diff --git a/sound/soc/txx9/txx9aclc.c b/sound/soc/txx9/txx9aclc.c index a8f705bb60dc..2cb2e0672c44 100644 --- a/sound/soc/txx9/txx9aclc.c +++ b/sound/soc/txx9/txx9aclc.c @@ -392,6 +392,7 @@ static int txx9aclc_pcm_remove(struct snd_soc_platform *platform) for (i = 0; i < 2; i++) { struct txx9aclc_dmadata *dmadata = &dev->dmadata[i]; struct dma_chan *chan = dmadata->dma_chan; + if (chan) { dmadata->frag_count = -1; dmaengine_terminate_all(chan); -- cgit v1.2.1 From 8fcf1e5eb460d8f032c699280f5a33fbf3716c29 Mon Sep 17 00:00:00 2001 From: Codrut Grosu Date: Sat, 25 Feb 2017 21:33:22 +0200 Subject: ASoC: ux500: Added */ to the next line This was reported by checkpatch.pl Signed-off-by: Codrut GROSU Signed-off-by: Mark Brown --- sound/soc/ux500/ux500_msp_dai.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/ux500/ux500_msp_dai.c b/sound/soc/ux500/ux500_msp_dai.c index b343efd9be5b..36e9bb2bd634 100644 --- a/sound/soc/ux500/ux500_msp_dai.c +++ b/sound/soc/ux500/ux500_msp_dai.c @@ -482,7 +482,8 @@ static int ux500_msp_dai_prepare(struct snd_pcm_substream *substream, if ((drvdata->fmt & SND_SOC_DAIFMT_MASTER_MASK) && (drvdata->msp->f_bitclk > 19200000)) { /* If the bit-clock is higher than 19.2MHz, Vape should be - * run in 100% OPP. Only when bit-clock is used (MSP master) */ + * run in 100% OPP. Only when bit-clock is used (MSP master) + */ prcmu_qos_update_requirement(PRCMU_QOS_APE_OPP, "ux500-msp-i2s", 100); drvdata->vape_opp_constraint = 1; -- cgit v1.2.1 From b1c5d923720a066b95249f3702a94d27b5714ee9 Mon Sep 17 00:00:00 2001 From: Codrut Grosu Date: Sat, 25 Feb 2017 21:41:25 +0200 Subject: ASoC: ux500: Remove unuseful break after return This was reported by checkpatch.pl Signed-off-by: Codrut GROSU Signed-off-by: Mark Brown --- sound/soc/ux500/ux500_msp_i2s.c | 1 - 1 file changed, 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/ux500/ux500_msp_i2s.c b/sound/soc/ux500/ux500_msp_i2s.c index 959d7b4edf56..bd5266aca0f1 100644 --- a/sound/soc/ux500/ux500_msp_i2s.c +++ b/sound/soc/ux500/ux500_msp_i2s.c @@ -604,7 +604,6 @@ int ux500_msp_i2s_trigger(struct ux500_msp *msp, int cmd, int direction) break; default: return -EINVAL; - break; } return 0; -- cgit v1.2.1 From fe3a980cd39125efb7e9ddd67dd0f1a9ef237171 Mon Sep 17 00:00:00 2001 From: Codrut Grosu Date: Sat, 25 Feb 2017 21:50:21 +0200 Subject: ASoC: ux500: Added blank line after declarations This was reported by checkpatch.pl Signed-off-by: Codrut GROSU Signed-off-by: Mark Brown --- sound/soc/ux500/ux500_msp_dai.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound/soc') diff --git a/sound/soc/ux500/ux500_msp_dai.c b/sound/soc/ux500/ux500_msp_dai.c index 36e9bb2bd634..ec5152aa3f6e 100644 --- a/sound/soc/ux500/ux500_msp_dai.c +++ b/sound/soc/ux500/ux500_msp_dai.c @@ -133,6 +133,7 @@ static int setup_pcm_framing(struct snd_soc_dai *dai, unsigned int rate, struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev); u32 frame_length = MSP_FRAME_LEN_1; + prot_desc->frame_width = 0; switch (drvdata->slots) { -- cgit v1.2.1 From adbdba3fa1b618376363db317324c69d8ce5659c Mon Sep 17 00:00:00 2001 From: Codrut Grosu Date: Sat, 25 Feb 2017 21:59:33 +0200 Subject: ASoC: sirf: Added blank line after declarations This was reported by checkpatch.pl Signed-off-by: Codrut GROSU Signed-off-by: Mark Brown --- sound/soc/sirf/sirf-audio-port.c | 1 + sound/soc/sirf/sirf-audio.c | 1 + sound/soc/sirf/sirf-usp.c | 3 +++ 3 files changed, 5 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/sirf/sirf-audio-port.c b/sound/soc/sirf/sirf-audio-port.c index 3f2cce03275c..be066de74aaa 100644 --- a/sound/soc/sirf/sirf-audio-port.c +++ b/sound/soc/sirf/sirf-audio-port.c @@ -19,6 +19,7 @@ struct sirf_audio_port { static int sirf_audio_port_dai_probe(struct snd_soc_dai *dai) { struct sirf_audio_port *port = snd_soc_dai_get_drvdata(dai); + snd_soc_dai_init_dma_data(dai, &port->playback_dma_data, &port->capture_dma_data); return 0; diff --git a/sound/soc/sirf/sirf-audio.c b/sound/soc/sirf/sirf-audio.c index 94ea152e0362..f2bc50790f76 100644 --- a/sound/soc/sirf/sirf-audio.c +++ b/sound/soc/sirf/sirf-audio.c @@ -27,6 +27,7 @@ static int sirf_audio_hp_event(struct snd_soc_dapm_widget *w, struct snd_soc_card *card = dapm->card; struct sirf_audio_card *sirf_audio_card = snd_soc_card_get_drvdata(card); int on = !SND_SOC_DAPM_EVENT_OFF(event); + if (gpio_is_valid(sirf_audio_card->gpio_hp_pa)) gpio_set_value(sirf_audio_card->gpio_hp_pa, on); return 0; diff --git a/sound/soc/sirf/sirf-usp.c b/sound/soc/sirf/sirf-usp.c index 45fc06c0e0e5..77e7dcf969d0 100644 --- a/sound/soc/sirf/sirf-usp.c +++ b/sound/soc/sirf/sirf-usp.c @@ -71,6 +71,7 @@ static void sirf_usp_rx_disable(struct sirf_usp *usp) static int sirf_usp_pcm_dai_probe(struct snd_soc_dai *dai) { struct sirf_usp *usp = snd_soc_dai_get_drvdata(dai); + snd_soc_dai_init_dma_data(dai, &usp->playback_dma_data, &usp->capture_dma_data); return 0; @@ -294,6 +295,7 @@ static struct snd_soc_dai_driver sirf_usp_pcm_dai = { static int sirf_usp_pcm_runtime_suspend(struct device *dev) { struct sirf_usp *usp = dev_get_drvdata(dev); + clk_disable_unprepare(usp->clk); return 0; } @@ -302,6 +304,7 @@ static int sirf_usp_pcm_runtime_resume(struct device *dev) { struct sirf_usp *usp = dev_get_drvdata(dev); int ret; + ret = clk_prepare_enable(usp->clk); if (ret) { dev_err(dev, "clk_enable failed: %d\n", ret); -- cgit v1.2.1 From 7be5c5fe9287c7f5cc0f2f3c742d602c82daa2d6 Mon Sep 17 00:00:00 2001 From: Codrut Grosu Date: Sat, 25 Feb 2017 22:25:23 +0200 Subject: ASoC: pxa: Add space around '=' This was reported by checkpatch.pl Signed-off-by: Codrut Grosu Acked-by: Robert Jarzmik Signed-off-by: Mark Brown --- sound/soc/pxa/e750_wm9705.c | 2 +- sound/soc/pxa/e800_wm9712.c | 2 +- sound/soc/pxa/em-x270.c | 2 +- sound/soc/pxa/mioa701_wm9713.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/pxa/e750_wm9705.c b/sound/soc/pxa/e750_wm9705.c index fdcd94adee7c..82bcbbb1841b 100644 --- a/sound/soc/pxa/e750_wm9705.c +++ b/sound/soc/pxa/e750_wm9705.c @@ -81,7 +81,7 @@ static struct snd_soc_dai_link e750_dai[] = { .name = "AC97 Aux", .stream_name = "AC97 Aux", .cpu_dai_name = "pxa2xx-ac97-aux", - .codec_dai_name ="wm9705-aux", + .codec_dai_name = "wm9705-aux", .platform_name = "pxa-pcm-audio", .codec_name = "wm9705-codec", }, diff --git a/sound/soc/pxa/e800_wm9712.c b/sound/soc/pxa/e800_wm9712.c index 2df714f70ec0..1ed8aa2348f1 100644 --- a/sound/soc/pxa/e800_wm9712.c +++ b/sound/soc/pxa/e800_wm9712.c @@ -81,7 +81,7 @@ static struct snd_soc_dai_link e800_dai[] = { .name = "AC97 Aux", .stream_name = "AC97 Aux", .cpu_dai_name = "pxa2xx-ac97-aux", - .codec_dai_name ="wm9712-aux", + .codec_dai_name = "wm9712-aux", .platform_name = "pxa-pcm-audio", .codec_name = "wm9712-codec", }, diff --git a/sound/soc/pxa/em-x270.c b/sound/soc/pxa/em-x270.c index 6f2020f6c8d3..e046770ce70e 100644 --- a/sound/soc/pxa/em-x270.c +++ b/sound/soc/pxa/em-x270.c @@ -43,7 +43,7 @@ static struct snd_soc_dai_link em_x270_dai[] = { .name = "AC97 Aux", .stream_name = "AC97 Aux", .cpu_dai_name = "pxa2xx-ac97-aux", - .codec_dai_name ="wm9712-aux", + .codec_dai_name = "wm9712-aux", .platform_name = "pxa-pcm-audio", .codec_name = "wm9712-codec", }, diff --git a/sound/soc/pxa/mioa701_wm9713.c b/sound/soc/pxa/mioa701_wm9713.c index 8760a6687885..c4c6fbedc723 100644 --- a/sound/soc/pxa/mioa701_wm9713.c +++ b/sound/soc/pxa/mioa701_wm9713.c @@ -157,7 +157,7 @@ static struct snd_soc_dai_link mioa701_dai[] = { .name = "AC97 Aux", .stream_name = "AC97 Aux", .cpu_dai_name = "pxa2xx-ac97-aux", - .codec_dai_name ="wm9713-aux", + .codec_dai_name = "wm9713-aux", .codec_name = "wm9713-codec", .platform_name = "pxa-pcm-audio", .ops = &mioa701_ops, -- cgit v1.2.1 From ea2a2ad17ca1e9dbb01ac935f1b1b53f99f73b13 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Tue, 7 Mar 2017 14:12:22 +0100 Subject: ASoC: dio2125: use gpiod_set_value_cansleep Use the "cansleep" variant of gpiod_set_value so the driver can be used with slow gpio controllers as well. Fixes: 85825d5e8869 ("ASoC: dio2125: add dio2125 amp driver") Reported-by: Mark Brown Signed-off-by: Jerome Brunet Signed-off-by: Mark Brown --- sound/soc/codecs/dio2125.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/dio2125.c b/sound/soc/codecs/dio2125.c index 015e310556d3..09451cd44f9b 100644 --- a/sound/soc/codecs/dio2125.c +++ b/sound/soc/codecs/dio2125.c @@ -46,7 +46,7 @@ static int drv_event(struct snd_soc_dapm_widget *w, return -EINVAL; } - gpiod_set_value(priv->gpiod_enable, val); + gpiod_set_value_cansleep(priv->gpiod_enable, val); return 0; } -- cgit v1.2.1 From 114ab993e1845a4152bc01d1075b1fb38e741df9 Mon Sep 17 00:00:00 2001 From: Calin Cruceru Date: Sat, 25 Feb 2017 12:11:11 +0200 Subject: ASoC: samsung: Remove extra blank lines This was reported by checkpatch.pl Signed-off-by: Calin Cruceru Signed-off-by: Mark Brown --- sound/soc/samsung/bells.c | 1 - sound/soc/samsung/i2s-regs.h | 2 -- sound/soc/samsung/i2s.c | 1 - sound/soc/samsung/s3c-i2s-v2.c | 1 - 4 files changed, 5 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/samsung/bells.c b/sound/soc/samsung/bells.c index 3dd246fa0059..34deba461ae1 100644 --- a/sound/soc/samsung/bells.c +++ b/sound/soc/samsung/bells.c @@ -446,7 +446,6 @@ static struct snd_soc_card bells_cards[] = { }, }; - static int bells_probe(struct platform_device *pdev) { int ret; diff --git a/sound/soc/samsung/i2s-regs.h b/sound/soc/samsung/i2s-regs.h index 9170c311d66e..fe6914005494 100644 --- a/sound/soc/samsung/i2s-regs.h +++ b/sound/soc/samsung/i2s-regs.h @@ -160,5 +160,3 @@ #define I2SSIZE_SHIFT (16) #endif /* __SND_SOC_SAMSUNG_I2S_REGS_H */ - - diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 52a47ed292a4..af3ba4d4ccc5 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -1242,7 +1242,6 @@ static int samsung_i2s_probe(struct platform_device *pdev) i2s_dai_data = (struct samsung_i2s_dai_data *) platform_get_device_id(pdev)->driver_data; - pri_dai = i2s_alloc_dai(pdev, false); if (!pri_dai) { dev_err(&pdev->dev, "Unable to alloc I2S_pri\n"); diff --git a/sound/soc/samsung/s3c-i2s-v2.c b/sound/soc/samsung/s3c-i2s-v2.c index 644f186fd35c..8f42deaa184b 100644 --- a/sound/soc/samsung/s3c-i2s-v2.c +++ b/sound/soc/samsung/s3c-i2s-v2.c @@ -72,7 +72,6 @@ static inline void dbg_showcon(const char *fn, u32 con) } #endif - /* Turn on or off the transmission path. */ static void s3c2412_snd_txctrl(struct s3c_i2sv2_info *i2s, int on) { -- cgit v1.2.1 From 84052652feb89e76fde6fd37d26c9649da715557 Mon Sep 17 00:00:00 2001 From: Codrut Grosu Date: Sat, 25 Feb 2017 12:12:21 +0200 Subject: ASoC: txx9: Added requiered spaces. This was reported by checpatch.pl Signed-off-by: Codrut GROSU Signed-off-by: Mark Brown --- sound/soc/txx9/txx9aclc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/txx9/txx9aclc.c b/sound/soc/txx9/txx9aclc.c index 2cb2e0672c44..7912bf09dc4d 100644 --- a/sound/soc/txx9/txx9aclc.c +++ b/sound/soc/txx9/txx9aclc.c @@ -206,7 +206,7 @@ static void txx9aclc_dma_tasklet(unsigned long data) static int txx9aclc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { struct txx9aclc_dmadata *dmadata = substream->runtime->private_data; - struct txx9aclc_plat_drvdata *drvdata =txx9aclc_drvdata; + struct txx9aclc_plat_drvdata *drvdata = txx9aclc_drvdata; void __iomem *base = drvdata->base; unsigned long flags; int ret = 0; @@ -340,7 +340,7 @@ static bool filter(struct dma_chan *chan, void *param) static int txx9aclc_dma_init(struct txx9aclc_soc_device *dev, struct txx9aclc_dmadata *dmadata) { - struct txx9aclc_plat_drvdata *drvdata =txx9aclc_drvdata; + struct txx9aclc_plat_drvdata *drvdata = txx9aclc_drvdata; struct txx9dmac_slave *ds = &dmadata->dma_slave; dma_cap_mask_t mask; -- cgit v1.2.1 From 70d435ba1cd6a955e715b8a4729bbc9044e9d7ff Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Wed, 8 Mar 2017 10:17:02 +0100 Subject: ASoC: imx-pcm-dma: simplify pcm_config The generic snd_dmaengine_pcm is able to retrieve all the needed information from the attached dmaengine and is in fact able to provide much more accurate flags to userspace, like the SDMA engine being only able to operate in batch mode. To avoid any future inconsistencies between the dmaengine and the pcm_config, rip out the fixed config and rely on the core to fill in the right flags derived from the dmaengine information. Signed-off-by: Lucas Stach Signed-off-by: Mark Brown --- sound/soc/fsl/imx-pcm-dma.c | 28 ---------------------------- 1 file changed, 28 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/fsl/imx-pcm-dma.c b/sound/soc/fsl/imx-pcm-dma.c index f3d3d1ffa84e..314814ddd2b0 100644 --- a/sound/soc/fsl/imx-pcm-dma.c +++ b/sound/soc/fsl/imx-pcm-dma.c @@ -33,48 +33,20 @@ static bool filter(struct dma_chan *chan, void *param) return true; } -static const struct snd_pcm_hardware imx_pcm_hardware = { - .info = SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_RESUME, - .buffer_bytes_max = IMX_DEFAULT_DMABUF_SIZE, - .period_bytes_min = 128, - .period_bytes_max = 65535, /* Limited by SDMA engine */ - .periods_min = 2, - .periods_max = 255, - .fifo_size = 0, -}; - static const struct snd_dmaengine_pcm_config imx_dmaengine_pcm_config = { - .pcm_hardware = &imx_pcm_hardware, .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config, .compat_filter_fn = filter, - .prealloc_buffer_size = IMX_DEFAULT_DMABUF_SIZE, }; int imx_pcm_dma_init(struct platform_device *pdev, size_t size) { struct snd_dmaengine_pcm_config *config; - struct snd_pcm_hardware *pcm_hardware; config = devm_kzalloc(&pdev->dev, sizeof(struct snd_dmaengine_pcm_config), GFP_KERNEL); if (!config) return -ENOMEM; *config = imx_dmaengine_pcm_config; - if (size) - config->prealloc_buffer_size = size; - - pcm_hardware = devm_kzalloc(&pdev->dev, - sizeof(struct snd_pcm_hardware), GFP_KERNEL); - *pcm_hardware = imx_pcm_hardware; - if (size) - pcm_hardware->buffer_bytes_max = size; - - config->pcm_hardware = pcm_hardware; return devm_snd_dmaengine_pcm_register(&pdev->dev, config, -- cgit v1.2.1 From 8e15e762cddf68a401df5c6aa45da3c27712e856 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Mon, 6 Mar 2017 16:12:22 +0900 Subject: ASoC: Intel: Skylake: use a helper macro to rounding-up calculation In 'include/linux/kernel.h', there's a helper macro to round numerical value. Let's use it. Signed-off-by: Takashi Sakamoto Acked-by: Vinod Koul Tested-by: Subhransu S. Prusty Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-topology.c | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index ed58b5b3555a..17a9a55026a4 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -299,8 +299,6 @@ static void skl_tplg_update_buffer_size(struct skl_sst *ctx, { int multiplier = 1; struct skl_module_fmt *in_fmt, *out_fmt; - int in_rate, out_rate; - /* Since fixups is applied to pin 0 only, ibs, obs needs * change for pin 0 only @@ -311,21 +309,13 @@ static void skl_tplg_update_buffer_size(struct skl_sst *ctx, if (mcfg->m_type == SKL_MODULE_TYPE_SRCINT) multiplier = 5; - if (in_fmt->s_freq % 1000) - in_rate = (in_fmt->s_freq / 1000) + 1; - else - in_rate = (in_fmt->s_freq / 1000); - - mcfg->ibs = in_rate * (mcfg->in_fmt->channels) * + mcfg->ibs = DIV_ROUND_UP(in_fmt->s_freq, 1000) * + (mcfg->in_fmt->channels) * (mcfg->in_fmt->bit_depth >> 3) * multiplier; - if (mcfg->out_fmt->s_freq % 1000) - out_rate = (mcfg->out_fmt->s_freq / 1000) + 1; - else - out_rate = (mcfg->out_fmt->s_freq / 1000); - - mcfg->obs = out_rate * (mcfg->out_fmt->channels) * + mcfg->obs = DIV_ROUND_UP(mcfg->out_fmt->s_freq, 1000) * + (mcfg->out_fmt->channels) * (mcfg->out_fmt->bit_depth >> 3) * multiplier; } -- cgit v1.2.1 From cb7d53b499f95febd4b5bc80a473706c717d5d2c Mon Sep 17 00:00:00 2001 From: Alin Grigorean Date: Sat, 25 Feb 2017 12:47:26 +0200 Subject: ASoC: fsl: Remove unneeded init of static variable This was reported by checkpatch.pl Signed-off-by: Alin Grigorean Acked-by: Nicolin Chen Signed-off-by: Mark Brown --- sound/soc/fsl/imx-pcm-fiq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/fsl/imx-pcm-fiq.c b/sound/soc/fsl/imx-pcm-fiq.c index dac6688540dc..92410f7ca1fa 100644 --- a/sound/soc/fsl/imx-pcm-fiq.c +++ b/sound/soc/fsl/imx-pcm-fiq.c @@ -282,7 +282,7 @@ static int imx_pcm_new(struct snd_soc_pcm_runtime *rtd) return 0; } -static int ssi_irq = 0; +static int ssi_irq; static int imx_pcm_fiq_new(struct snd_soc_pcm_runtime *rtd) { -- cgit v1.2.1 From 246126b0a4f24f8e88f148c9d0d6d72e6fafe6cc Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 8 Mar 2017 19:05:33 +0800 Subject: ASoC: rt5665: increase button detection accuracy Use sar adc for button detection to increase accuracy. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5665.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c index 61137160c116..de2c104bbaf3 100644 --- a/sound/soc/codecs/rt5665.c +++ b/sound/soc/codecs/rt5665.c @@ -1139,7 +1139,8 @@ static void rt5665_enable_push_button_irq(struct snd_soc_codec *codec, bool enable) { if (enable) { - snd_soc_write(codec, RT5665_4BTN_IL_CMD_1, 0x000b); + snd_soc_write(codec, RT5665_4BTN_IL_CMD_1, 0x0003); + snd_soc_update_bits(codec, RT5665_SAR_IL_CMD_9, 0x1, 0x1); snd_soc_write(codec, RT5665_IL_CMD_1, 0x0048); snd_soc_update_bits(codec, RT5665_4BTN_IL_CMD_2, RT5665_4BTN_IL_MASK | RT5665_4BTN_IL_RST_MASK, -- cgit v1.2.1 From 948059ddf93f4dfbb1f2f00885d2172b835a03b1 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 8 Mar 2017 19:05:36 +0800 Subject: ASoC: rt5665: enable TDM if more than 2 channels TDM is necessary for more than 2 channels. And there is no control bit to specify which slots are using. Machine driver will not need to call snd_soc_dai_set_tdm_slot if we do it in rt5665_hw_params. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5665.c | 114 ++++++++++++++++++++++++---------------------- 1 file changed, 59 insertions(+), 55 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c index de2c104bbaf3..b8c50ed72396 100644 --- a/sound/soc/codecs/rt5665.c +++ b/sound/soc/codecs/rt5665.c @@ -3964,6 +3964,62 @@ static const struct snd_soc_dapm_route rt5665_dapm_routes[] = { {"PDMR", NULL, "PDM R Playback"}, }; +static int rt5665_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, + unsigned int rx_mask, int slots, int slot_width) +{ + struct snd_soc_codec *codec = dai->codec; + unsigned int val = 0; + + if (rx_mask || tx_mask) + val |= RT5665_I2S1_MODE_TDM; + + switch (slots) { + case 4: + val |= RT5665_TDM_IN_CH_4; + val |= RT5665_TDM_OUT_CH_4; + break; + case 6: + val |= RT5665_TDM_IN_CH_6; + val |= RT5665_TDM_OUT_CH_6; + break; + case 8: + val |= RT5665_TDM_IN_CH_8; + val |= RT5665_TDM_OUT_CH_8; + break; + case 2: + break; + default: + return -EINVAL; + } + + switch (slot_width) { + case 20: + val |= RT5665_TDM_IN_LEN_20; + val |= RT5665_TDM_OUT_LEN_20; + break; + case 24: + val |= RT5665_TDM_IN_LEN_24; + val |= RT5665_TDM_OUT_LEN_24; + break; + case 32: + val |= RT5665_TDM_IN_LEN_32; + val |= RT5665_TDM_OUT_LEN_32; + break; + case 16: + break; + default: + return -EINVAL; + } + + snd_soc_update_bits(codec, RT5665_TDM_CTRL_1, + RT5665_I2S1_MODE_MASK | RT5665_TDM_IN_CH_MASK | + RT5665_TDM_OUT_CH_MASK | RT5665_TDM_IN_LEN_MASK | + RT5665_TDM_OUT_LEN_MASK, val); + + return 0; +} + + static int rt5665_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { @@ -4010,6 +4066,9 @@ static int rt5665_hw_params(struct snd_pcm_substream *substream, switch (dai->id) { case RT5665_AIF1_1: case RT5665_AIF1_2: + if (params_channels(params) > 2) + rt5665_set_tdm_slot(dai, 0xf, 0xf, + params_channels(params), params_width(params)); mask_clk = RT5665_I2S_PD1_MASK; val_clk = pre_div << RT5665_I2S_PD1_SFT; snd_soc_update_bits(codec, RT5665_I2S1_SDP, @@ -4227,61 +4286,6 @@ static int rt5665_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int Source, return 0; } -static int rt5665_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, - unsigned int rx_mask, int slots, int slot_width) -{ - struct snd_soc_codec *codec = dai->codec; - unsigned int val = 0; - - if (rx_mask || tx_mask) - val |= RT5665_I2S1_MODE_TDM; - - switch (slots) { - case 4: - val |= RT5665_TDM_IN_CH_4; - val |= RT5665_TDM_OUT_CH_4; - break; - case 6: - val |= RT5665_TDM_IN_CH_6; - val |= RT5665_TDM_OUT_CH_6; - break; - case 8: - val |= RT5665_TDM_IN_CH_8; - val |= RT5665_TDM_OUT_CH_8; - break; - case 2: - break; - default: - return -EINVAL; - } - - switch (slot_width) { - case 20: - val |= RT5665_TDM_IN_LEN_20; - val |= RT5665_TDM_OUT_LEN_20; - break; - case 24: - val |= RT5665_TDM_IN_LEN_24; - val |= RT5665_TDM_OUT_LEN_24; - break; - case 32: - val |= RT5665_TDM_IN_LEN_32; - val |= RT5665_TDM_OUT_LEN_32; - break; - case 16: - break; - default: - return -EINVAL; - } - - snd_soc_update_bits(codec, RT5665_TDM_CTRL_1, - RT5665_I2S1_MODE_MASK | RT5665_TDM_IN_CH_MASK | - RT5665_TDM_OUT_CH_MASK | RT5665_TDM_IN_LEN_MASK | - RT5665_TDM_OUT_LEN_MASK, val); - - return 0; -} - static int rt5665_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio) { struct snd_soc_codec *codec = dai->codec; -- cgit v1.2.1 From 39841944c651f2e019d6e77aceb349a2695d8e2d Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 8 Mar 2017 19:05:30 +0800 Subject: ASoC: rt5665: enhance jack type detection function Use manual mode for jack detection function to increase accuracy. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5665.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c index b8c50ed72396..1baa9ce2648a 100644 --- a/sound/soc/codecs/rt5665.c +++ b/sound/soc/codecs/rt5665.c @@ -1193,10 +1193,13 @@ static int rt5665_headset_detect(struct snd_soc_codec *codec, int jack_insert) } regmap_update_bits(rt5665->regmap, RT5665_EJD_CTRL_1, - 0x180, 0x180); + 0x1a0, 0x120); regmap_write(rt5665->regmap, RT5665_EJD_CTRL_3, 0x3424); + regmap_write(rt5665->regmap, RT5665_IL_CMD_1, 0x0048); regmap_write(rt5665->regmap, RT5665_SAR_IL_CMD_1, 0xa291); + usleep_range(10000, 15000); + rt5665->sar_adc_value = snd_soc_read(rt5665->codec, RT5665_SAR_IL_CMD_4) & 0x7ff; @@ -4788,7 +4791,7 @@ static int rt5665_i2c_probe(struct i2c_client *i2c, regmap_write(rt5665->regmap, RT5665_HP_LOGIC_CTRL_2, 0x0002); regmap_update_bits(rt5665->regmap, RT5665_EJD_CTRL_1, - 0xf000 | RT5665_VREF_POW_MASK, 0xd000 | RT5665_VREF_POW_REG); + 0xf000 | RT5665_VREF_POW_MASK, 0xe000 | RT5665_VREF_POW_REG); /* Work around for pow_pump */ regmap_update_bits(rt5665->regmap, RT5665_STO1_DAC_SIL_DET, RT5665_DEB_STO_DAC_MASK, RT5665_DEB_80_MS); -- cgit v1.2.1 From 4aa8146c89f336230de7f449805bd0edfc878fd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Myl=C3=A8ne=20Josserand?= Date: Fri, 10 Feb 2017 10:41:30 +0100 Subject: ASoC: sun8i-codec: Remove analog "HP" widget MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "HP" widget is already present and take part to the analog part (sun8i-codec-analog). Remove it from the digital part as it is unnecessary. Signed-off-by: Mylène Josserand Acked-by: Chen-Yu Tsai Signed-off-by: Mark Brown --- sound/soc/sunxi/sun8i-codec.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c index b92bdc8361af..d60f6fbd36a2 100644 --- a/sound/soc/sunxi/sun8i-codec.c +++ b/sound/soc/sunxi/sun8i-codec.c @@ -321,8 +321,6 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = { SUN8I_MOD_RST_CTL_AIF1, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("RST DAC", SUN8I_MOD_RST_CTL, SUN8I_MOD_RST_CTL_DAC, 0, NULL, 0), - - SND_SOC_DAPM_OUTPUT("HP"), }; static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = { @@ -344,10 +342,6 @@ static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = { /* DAC Mixer Routes */ { "Left DAC Mixer", "LSlot 0", "Digital Left DAC"}, { "Right DAC Mixer", "RSlot 0", "Digital Right DAC"}, - - /* End of route : HP out */ - { "HP", NULL, "Left DAC Mixer" }, - { "HP", NULL, "Right DAC Mixer" }, }; static struct snd_soc_dai_ops sun8i_codec_dai_ops = { -- cgit v1.2.1 From ca14da6e611674cad275f29ac2aaf1e2eb427c6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Myl=C3=A8ne=20Josserand?= Date: Fri, 10 Feb 2017 10:41:31 +0100 Subject: ASoC: sun8i-codec: Update mixer to use SOC_DAPM_DOUBLE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update the driver to use the new SOC_DAPM_DOUBLE definition on the digital DAC mixer. Update the names accordingly as, when they are shared, the controls are not prefixed with the widget's name anymore. Signed-off-by: Mylène Josserand Acked-by: Chen-Yu Tsai Signed-off-by: Mark Brown --- sound/soc/sunxi/sun8i-codec.c | 45 ++++++++++++++++++++----------------------- 1 file changed, 21 insertions(+), 24 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c index d60f6fbd36a2..107fa8213600 100644 --- a/sound/soc/sunxi/sun8i-codec.c +++ b/sound/soc/sunxi/sun8i-codec.c @@ -259,25 +259,20 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream, return 0; } -static const struct snd_kcontrol_new sun8i_output_left_mixer_controls[] = { - SOC_DAPM_SINGLE("LSlot 0", SUN8I_DAC_MXR_SRC, - SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA0L, 1, 0), - SOC_DAPM_SINGLE("LSlot 1", SUN8I_DAC_MXR_SRC, - SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA1L, 1, 0), - SOC_DAPM_SINGLE("DACL", SUN8I_DAC_MXR_SRC, - SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF2DACL, 1, 0), - SOC_DAPM_SINGLE("ADCL", SUN8I_DAC_MXR_SRC, - SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_ADCL, 1, 0), -}; - -static const struct snd_kcontrol_new sun8i_output_right_mixer_controls[] = { - SOC_DAPM_SINGLE("RSlot 0", SUN8I_DAC_MXR_SRC, +static const struct snd_kcontrol_new sun8i_dac_mixer_controls[] = { + SOC_DAPM_DOUBLE("AIF1 Slot 0 Digital DAC Playback Switch", + SUN8I_DAC_MXR_SRC, + SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA0L, SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA0R, 1, 0), - SOC_DAPM_SINGLE("RSlot 1", SUN8I_DAC_MXR_SRC, + SOC_DAPM_DOUBLE("AIF1 Slot 1 Digital DAC Playback Switch", + SUN8I_DAC_MXR_SRC, + SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA1L, SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA1R, 1, 0), - SOC_DAPM_SINGLE("DACR", SUN8I_DAC_MXR_SRC, + SOC_DAPM_DOUBLE("AIF2 Digital DAC Playback Switch", SUN8I_DAC_MXR_SRC, + SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF2DACL, SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF2DACR, 1, 0), - SOC_DAPM_SINGLE("ADCR", SUN8I_DAC_MXR_SRC, + SOC_DAPM_DOUBLE("ADC Digital DAC Playback Switch", SUN8I_DAC_MXR_SRC, + SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_ADCL, SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_ADCR, 1, 0), }; @@ -293,12 +288,12 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = { SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_ENA, 0), /* DAC Mixers */ - SND_SOC_DAPM_MIXER("Left DAC Mixer", SND_SOC_NOPM, 0, 0, - sun8i_output_left_mixer_controls, - ARRAY_SIZE(sun8i_output_left_mixer_controls)), - SND_SOC_DAPM_MIXER("Right DAC Mixer", SND_SOC_NOPM, 0, 0, - sun8i_output_right_mixer_controls, - ARRAY_SIZE(sun8i_output_right_mixer_controls)), + SND_SOC_DAPM_MIXER("Left Digital DAC Mixer", SND_SOC_NOPM, 0, 0, + sun8i_dac_mixer_controls, + ARRAY_SIZE(sun8i_dac_mixer_controls)), + SND_SOC_DAPM_MIXER("Right Digital DAC Mixer", SND_SOC_NOPM, 0, 0, + sun8i_dac_mixer_controls, + ARRAY_SIZE(sun8i_dac_mixer_controls)), /* Clocks */ SND_SOC_DAPM_SUPPLY("MODCLK AFI1", SUN8I_MOD_CLK_ENA, @@ -340,8 +335,10 @@ static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = { { "Digital Right DAC", NULL, "DAC" }, /* DAC Mixer Routes */ - { "Left DAC Mixer", "LSlot 0", "Digital Left DAC"}, - { "Right DAC Mixer", "RSlot 0", "Digital Right DAC"}, + { "Left Digital DAC Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", + "Digital Left DAC"}, + { "Right Digital DAC Mixer", "AIF1 Slot 0 Digital DAC Playback Switch ", + "Digital Right DAC"}, }; static struct snd_soc_dai_ops sun8i_codec_dai_ops = { -- cgit v1.2.1 From fa22ca4f905d7001ed966bc95bcffb890a1b8d73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Myl=C3=A8ne=20Josserand?= Date: Fri, 10 Feb 2017 10:41:32 +0100 Subject: ASoC: sun8i-codec: Convert to SOC_MIXER_ARRAY MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SOC_MIXER_ARRAY is a simplified function of SND_SOC_DAPM_MIXER which handles automatically the ARRAY_SIZE of controls. Update the driver to use SOC_MIXER_ARRAY. Signed-off-by: Mylène Josserand Acked-by: Chen-Yu Tsai Signed-off-by: Mark Brown --- sound/soc/sunxi/sun8i-codec.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c index 107fa8213600..a75a983974d9 100644 --- a/sound/soc/sunxi/sun8i-codec.c +++ b/sound/soc/sunxi/sun8i-codec.c @@ -288,12 +288,10 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = { SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_ENA, 0), /* DAC Mixers */ - SND_SOC_DAPM_MIXER("Left Digital DAC Mixer", SND_SOC_NOPM, 0, 0, - sun8i_dac_mixer_controls, - ARRAY_SIZE(sun8i_dac_mixer_controls)), - SND_SOC_DAPM_MIXER("Right Digital DAC Mixer", SND_SOC_NOPM, 0, 0, - sun8i_dac_mixer_controls, - ARRAY_SIZE(sun8i_dac_mixer_controls)), + SOC_MIXER_ARRAY("Left Digital DAC Mixer", SND_SOC_NOPM, 0, 0, + sun8i_dac_mixer_controls), + SOC_MIXER_ARRAY("Right Digital DAC Mixer", SND_SOC_NOPM, 0, 0, + sun8i_dac_mixer_controls), /* Clocks */ SND_SOC_DAPM_SUPPLY("MODCLK AFI1", SUN8I_MOD_CLK_ENA, -- cgit v1.2.1 From 998d6fb5123d5b27edd3abd85b767c822bf766fc Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Wed, 8 Mar 2017 17:47:02 +0900 Subject: ASoC: Intel: Skylake: code cleanup for pin fixup limitation As a commit 4cd9899f0d16 ("ASoC: Intel: Skylake: Add multiple pin formats") describes, 'fixups is applied to pin 0 only'. On the other hand, the commit left some codes as what they were. This might confuses readers. This commit fixes the issue. This doesn't change driver behaviour at all. Fixes: 4cd9899f0d16 ("ASoC: Intel: Skylake: Add multiple pin formats") Signed-off-by: Takashi Sakamoto Acked-by: Vinod Koul Tested-by: Subhransu S. Prusty Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-topology.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index 17a9a55026a4..e7836a2e18f0 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -310,13 +310,11 @@ static void skl_tplg_update_buffer_size(struct skl_sst *ctx, multiplier = 5; mcfg->ibs = DIV_ROUND_UP(in_fmt->s_freq, 1000) * - (mcfg->in_fmt->channels) * - (mcfg->in_fmt->bit_depth >> 3) * + in_fmt->channels * (in_fmt->bit_depth >> 3) * multiplier; - mcfg->obs = DIV_ROUND_UP(mcfg->out_fmt->s_freq, 1000) * - (mcfg->out_fmt->channels) * - (mcfg->out_fmt->bit_depth >> 3) * + mcfg->obs = DIV_ROUND_UP(out_fmt->s_freq, 1000) * + out_fmt->channels * (out_fmt->bit_depth >> 3) * multiplier; } -- cgit v1.2.1 From 1bb06ada038548b4e2449159e80badf106bb779f Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 8 Mar 2017 16:42:47 +0000 Subject: ASoC: cs35l35: Add missing return in probe A return statement is missing just before the error paths at the end of probe. This causes us to fall straight into the error path and disable the supplies and re-enable reset, as these are only controlled during probe this causes the part to no longer function. Signed-off-by: Charles Keepax Acked-by: Brian Austin Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l35.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/codecs/cs35l35.c b/sound/soc/codecs/cs35l35.c index 260ed42c71e9..48b45dc904ea 100644 --- a/sound/soc/codecs/cs35l35.c +++ b/sound/soc/codecs/cs35l35.c @@ -1509,6 +1509,8 @@ static int cs35l35_i2c_probe(struct i2c_client *i2c_client, goto err; } + return 0; + err: regulator_bulk_disable(cs35l35->num_supplies, cs35l35->supplies); -- cgit v1.2.1 From 8d45f2d23864ae1582d095c54605540cd3640169 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 8 Mar 2017 16:42:49 +0000 Subject: ASoC: cs35l35: Add for configuring drive mode in unused slots Add support for setting how the I2S pins are driven in unused slots, currently the chip will just use the default of drive 0, however this causes issues when multiple devices are attached to the same bus. Signed-off-by: Charles Keepax Acked-by: Brian Austin Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l35.c | 7 +++++++ sound/soc/codecs/cs35l35.h | 4 ++++ 2 files changed, 11 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/codecs/cs35l35.c b/sound/soc/codecs/cs35l35.c index 48b45dc904ea..5a9fe5addb86 100644 --- a/sound/soc/codecs/cs35l35.c +++ b/sound/soc/codecs/cs35l35.c @@ -789,6 +789,11 @@ static int cs35l35_codec_probe(struct snd_soc_codec *codec) CS35L35_SP_DRV_MASK, cs35l35->pdata.sp_drv_str << CS35L35_SP_DRV_SHIFT); + if (cs35l35->pdata.sp_drv_unused) + regmap_update_bits(cs35l35->regmap, CS35L35_SP_FMT_CTL3, + CS35L35_SP_I2S_DRV_MASK, + cs35l35->pdata.sp_drv_unused << + CS35L35_SP_I2S_DRV_SHIFT); if (classh->classh_algo_enable) { if (classh->classh_bst_override) @@ -1169,6 +1174,8 @@ static int cs35l35_handle_of_data(struct i2c_client *i2c_client, if (of_property_read_u32(np, "cirrus,sp-drv-strength", &val32) >= 0) pdata->sp_drv_str = val32; + if (of_property_read_u32(np, "cirrus,sp-drv-unused", &val32) >= 0) + pdata->sp_drv_unused = val32 | CS35L35_VALID_PDATA; pdata->stereo = of_property_read_bool(np, "cirrus,stereo-config"); diff --git a/sound/soc/codecs/cs35l35.h b/sound/soc/codecs/cs35l35.h index e27a7fef5fb1..c203081fc94c 100644 --- a/sound/soc/codecs/cs35l35.h +++ b/sound/soc/codecs/cs35l35.h @@ -190,6 +190,10 @@ #define CS35L35_AMP_GAIN_ZC_MASK 0x10 #define CS35L35_AMP_GAIN_ZC_SHIFT 4 +/* CS35L35_SP_FMT_CTL3 */ +#define CS35L35_SP_I2S_DRV_MASK 0x03 +#define CS35L35_SP_I2S_DRV_SHIFT 0 + /* Class H Algorithm Control */ #define CS35L35_CH_STEREO_MASK 0x40 #define CS35L35_CH_STEREO_SHIFT 6 -- cgit v1.2.1 From 1f758cd9da61a1ae2202405746d259ba640d1e8a Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 8 Mar 2017 16:42:50 +0000 Subject: ASoC: cs35l35: Add local variable for dev in probe Tidy up the code a little by adding a local variable for i2c_client->dev rather than referring to it explicitly everytime. Signed-off-by: Charles Keepax Acked-by: Brian Austin Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l35.c | 66 ++++++++++++++++++---------------------------- 1 file changed, 26 insertions(+), 40 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/cs35l35.c b/sound/soc/codecs/cs35l35.c index 5a9fe5addb86..99bcdb962359 100644 --- a/sound/soc/codecs/cs35l35.c +++ b/sound/soc/codecs/cs35l35.c @@ -1354,16 +1354,14 @@ static int cs35l35_i2c_probe(struct i2c_client *i2c_client, const struct i2c_device_id *id) { struct cs35l35_private *cs35l35; - struct cs35l35_platform_data *pdata = - dev_get_platdata(&i2c_client->dev); + struct device *dev = &i2c_client->dev; + struct cs35l35_platform_data *pdata = dev_get_platdata(dev); int i; int ret; unsigned int devid = 0; unsigned int reg; - cs35l35 = devm_kzalloc(&i2c_client->dev, - sizeof(struct cs35l35_private), - GFP_KERNEL); + cs35l35 = devm_kzalloc(dev, sizeof(struct cs35l35_private), GFP_KERNEL); if (!cs35l35) return -ENOMEM; @@ -1371,7 +1369,7 @@ static int cs35l35_i2c_probe(struct i2c_client *i2c_client, cs35l35->regmap = devm_regmap_init_i2c(i2c_client, &cs35l35_regmap); if (IS_ERR(cs35l35->regmap)) { ret = PTR_ERR(cs35l35->regmap); - dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret); + dev_err(dev, "regmap_init() failed: %d\n", ret); goto err; } @@ -1379,22 +1377,18 @@ static int cs35l35_i2c_probe(struct i2c_client *i2c_client, cs35l35->supplies[i].supply = cs35l35_supplies[i]; cs35l35->num_supplies = ARRAY_SIZE(cs35l35_supplies); - ret = devm_regulator_bulk_get(&i2c_client->dev, - cs35l35->num_supplies, - cs35l35->supplies); + ret = devm_regulator_bulk_get(dev, cs35l35->num_supplies, + cs35l35->supplies); if (ret != 0) { - dev_err(&i2c_client->dev, - "Failed to request core supplies: %d\n", - ret); + dev_err(dev, "Failed to request core supplies: %d\n", ret); return ret; } if (pdata) { cs35l35->pdata = *pdata; } else { - pdata = devm_kzalloc(&i2c_client->dev, - sizeof(struct cs35l35_platform_data), - GFP_KERNEL); + pdata = devm_kzalloc(dev, sizeof(struct cs35l35_platform_data), + GFP_KERNEL); if (!pdata) return -ENOMEM; if (i2c_client->dev.of_node) { @@ -1409,24 +1403,21 @@ static int cs35l35_i2c_probe(struct i2c_client *i2c_client, ret = regulator_bulk_enable(cs35l35->num_supplies, cs35l35->supplies); if (ret != 0) { - dev_err(&i2c_client->dev, - "Failed to enable core supplies: %d\n", - ret); + dev_err(dev, "Failed to enable core supplies: %d\n", ret); return ret; } /* returning NULL can be valid if in stereo mode */ - cs35l35->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev, - "reset", GPIOD_OUT_LOW); + cs35l35->reset_gpio = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_LOW); if (IS_ERR(cs35l35->reset_gpio)) { ret = PTR_ERR(cs35l35->reset_gpio); if (ret == -EBUSY) { - dev_info(&i2c_client->dev, + dev_info(dev, "Reset line busy, assuming shared reset\n"); cs35l35->reset_gpio = NULL; } else { - dev_err(&i2c_client->dev, - "Failed to get reset GPIO: %d\n", ret); + dev_err(dev, "Failed to get reset GPIO: %d\n", ret); goto err; } } @@ -1435,11 +1426,11 @@ static int cs35l35_i2c_probe(struct i2c_client *i2c_client, init_completion(&cs35l35->pdn_done); - ret = devm_request_threaded_irq(&i2c_client->dev, i2c_client->irq, NULL, - cs35l35_irq, IRQF_ONESHOT | IRQF_TRIGGER_LOW, - "cs35l35", cs35l35); + ret = devm_request_threaded_irq(dev, i2c_client->irq, NULL, cs35l35_irq, + IRQF_ONESHOT | IRQF_TRIGGER_LOW, + "cs35l35", cs35l35); if (ret != 0) { - dev_err(&i2c_client->dev, "Failed to request IRQ: %d\n", ret); + dev_err(dev, "Failed to request IRQ: %d\n", ret); goto err; } /* initialize codec */ @@ -1452,8 +1443,7 @@ static int cs35l35_i2c_probe(struct i2c_client *i2c_client, devid |= (reg & 0xF0) >> 4; if (devid != CS35L35_CHIP_ID) { - dev_err(&i2c_client->dev, - "CS35L35 Device ID (%X). Expected ID %X\n", + dev_err(dev, "CS35L35 Device ID (%X). Expected ID %X\n", devid, CS35L35_CHIP_ID); ret = -ENODEV; goto err; @@ -1461,21 +1451,19 @@ static int cs35l35_i2c_probe(struct i2c_client *i2c_client, ret = regmap_read(cs35l35->regmap, CS35L35_REV_ID, ®); if (ret < 0) { - dev_err(&i2c_client->dev, "Get Revision ID failed: %d\n", ret); + dev_err(dev, "Get Revision ID failed: %d\n", ret); goto err; } ret = regmap_register_patch(cs35l35->regmap, cs35l35_errata_patch, ARRAY_SIZE(cs35l35_errata_patch)); if (ret < 0) { - dev_err(&i2c_client->dev, "Failed to apply errata patch: %d\n", - ret); + dev_err(dev, "Failed to apply errata patch: %d\n", ret); goto err; } - dev_info(&i2c_client->dev, - "Cirrus Logic CS35L35 (%x), Revision: %02X\n", devid, - ret & 0xFF); + dev_info(dev, "Cirrus Logic CS35L35 (%x), Revision: %02X\n", + devid, ret & 0xFF); /* Set the INT Masks for critical errors */ regmap_write(cs35l35->regmap, CS35L35_INT_MASK_1, @@ -1507,12 +1495,10 @@ static int cs35l35_i2c_probe(struct i2c_client *i2c_client, regmap_update_bits(cs35l35->regmap, CS35L35_PROTECT_CTL, CS35L35_AMP_MUTE_MASK, 1 << CS35L35_AMP_MUTE_SHIFT); - ret = snd_soc_register_codec(&i2c_client->dev, - &soc_codec_dev_cs35l35, cs35l35_dai, - ARRAY_SIZE(cs35l35_dai)); + ret = snd_soc_register_codec(dev, &soc_codec_dev_cs35l35, cs35l35_dai, + ARRAY_SIZE(cs35l35_dai)); if (ret < 0) { - dev_err(&i2c_client->dev, - "Failed to register codec: %d\n", ret); + dev_err(dev, "Failed to register codec: %d\n", ret); goto err; } -- cgit v1.2.1 From bf5043d69c9bf33696f9151552175f1203f8c9d9 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 8 Mar 2017 16:42:51 +0000 Subject: ASoC: cs35l35: Add IRQF_SHARED to IRQ flags As it is quite common to use a stereo pair of amps but share the IRQ line between them both add the IRQF_SHARED flag whilst requesting cs35l35's IRQ. Signed-off-by: Charles Keepax Acked-by: Brian Austin Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l35.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/cs35l35.c b/sound/soc/codecs/cs35l35.c index 99bcdb962359..7c4d74ec32cb 100644 --- a/sound/soc/codecs/cs35l35.c +++ b/sound/soc/codecs/cs35l35.c @@ -1427,8 +1427,8 @@ static int cs35l35_i2c_probe(struct i2c_client *i2c_client, init_completion(&cs35l35->pdn_done); ret = devm_request_threaded_irq(dev, i2c_client->irq, NULL, cs35l35_irq, - IRQF_ONESHOT | IRQF_TRIGGER_LOW, - "cs35l35", cs35l35); + IRQF_ONESHOT | IRQF_TRIGGER_LOW | + IRQF_SHARED, "cs35l35", cs35l35); if (ret != 0) { dev_err(dev, "Failed to request IRQ: %d\n", ret); goto err; -- cgit v1.2.1 From 8f42c23a9861df7796e019d32fd5c4dea01c8e51 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 9 Mar 2017 18:18:58 -0600 Subject: ASoC: da7213: add ACPI support Add DLGS7212 and DLGS7213 HID Signed-off-by: Pierre-Louis Bossart Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/codecs/da7213.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c index 12da55882c06..6dd7578f0bb8 100644 --- a/sound/soc/codecs/da7213.c +++ b/sound/soc/codecs/da7213.c @@ -12,6 +12,7 @@ * option) any later version. */ +#include #include #include #include @@ -1528,12 +1529,23 @@ static int da7213_set_bias_level(struct snd_soc_codec *codec, return 0; } +#if defined(CONFIG_OF) /* DT */ static const struct of_device_id da7213_of_match[] = { { .compatible = "dlg,da7213", }, { } }; MODULE_DEVICE_TABLE(of, da7213_of_match); +#endif + +#ifdef CONFIG_ACPI +static const struct acpi_device_id da7213_acpi_match[] = { + { "DLGS7212", 0}, + { "DLGS7213", 0}, + { }, +}; +MODULE_DEVICE_TABLE(acpi, da7213_acpi_match); +#endif static enum da7213_micbias_voltage da7213_of_micbias_lvl(struct snd_soc_codec *codec, u32 val) @@ -1844,6 +1856,7 @@ static struct i2c_driver da7213_i2c_driver = { .driver = { .name = "da7213", .of_match_table = of_match_ptr(da7213_of_match), + .acpi_match_table = ACPI_PTR(da7213_acpi_match), }, .probe = da7213_i2c_probe, .remove = da7213_remove, -- cgit v1.2.1 From 82cf89de2c9c2efcafde452ed76f85e7ef7f6ce0 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 9 Mar 2017 18:18:59 -0600 Subject: ASoC: Intel: add machine driver for BYT/CHT + DA7213 Add new machine driver, tested with Ard-Audio-DA7212 [1] connected to MinnowBoardMAX Turbot. The MCLK is managed by the codec driver using the "mclk" handle to reuse existing code, but it could just as well be handled by this machine driver. [1] http://www.dialog-semiconductor.com/content/ard-audio-da7212 Signed-off-by: Pierre-Louis Bossart Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/Kconfig | 12 ++ sound/soc/intel/boards/Makefile | 2 + sound/soc/intel/boards/bytcht_da7213.c | 283 +++++++++++++++++++++++++++++++++ 3 files changed, 297 insertions(+) create mode 100644 sound/soc/intel/boards/bytcht_da7213.c (limited to 'sound/soc') diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 526855ad479e..8d32fc336eb8 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -202,6 +202,18 @@ config SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH platforms with MAX98090 audio codec it also can support TI jack chip as aux device. If unsure select "N". +config SND_SOC_INTEL_BYT_CHT_DA7213_MACH + tristate "ASoC Audio driver for Intel Baytrail & Cherrytrail with DA7212/7213 codec" + depends on X86_INTEL_LPSS && I2C && ACPI + select SND_SOC_DA7213 + select SND_SST_ATOM_HIFI2_PLATFORM + select SND_SST_IPC_ACPI + select SND_SOC_INTEL_SST_MATCH if ACPI + help + This adds support for ASoC machine driver for Intel(R) Baytrail & CherryTrail + platforms with DA7212/7213 audio codec. + If unsure select "N". + config SND_SOC_INTEL_SKYLAKE tristate select SND_HDA_EXT_CORE diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index 5639f10774e6..8a5d9edd16ee 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -10,6 +10,7 @@ snd-soc-sst-bytcr-rt5651-objs := bytcr_rt5651.o snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.o snd-soc-sst-cht-bsw-rt5645-objs := cht_bsw_rt5645.o snd-soc-sst-cht-bsw-max98090_ti-objs := cht_bsw_max98090_ti.o +snd-soc-sst-byt-cht-da7213-objs := bytcht_da7213.o snd-soc-skl_rt286-objs := skl_rt286.o snd-skl_nau88l25_max98357a-objs := skl_nau88l25_max98357a.o snd-soc-skl_nau88l25_ssm4567-objs := skl_nau88l25_ssm4567.o @@ -26,6 +27,7 @@ obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5651_MACH) += snd-soc-sst-bytcr-rt5651.o obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH) += snd-soc-sst-cht-bsw-rt5672.o obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH) += snd-soc-sst-cht-bsw-rt5645.o obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH) += snd-soc-sst-cht-bsw-max98090_ti.o +obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_DA7213_MACH) += snd-soc-sst-byt-cht-da7213.o obj-$(CONFIG_SND_SOC_INTEL_SKL_RT286_MACH) += snd-soc-skl_rt286.o obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH) += snd-skl_nau88l25_max98357a.o obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH) += snd-soc-skl_nau88l25_ssm4567.o diff --git a/sound/soc/intel/boards/bytcht_da7213.c b/sound/soc/intel/boards/bytcht_da7213.c new file mode 100644 index 000000000000..18873e23f404 --- /dev/null +++ b/sound/soc/intel/boards/bytcht_da7213.c @@ -0,0 +1,283 @@ +/* + * bytcht-da7213.c - ASoc Machine driver for Intel Baytrail and + * Cherrytrail-based platforms, with Dialog DA7213 codec + * + * Copyright (C) 2017 Intel Corporation + * Author: Pierre-Louis Bossart + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * 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; version 2 of the License. + * + * 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 +#include +#include +#include +#include "../../codecs/da7213.h" +#include "../atom/sst-atom-controls.h" +#include "../common/sst-acpi.h" + +static const struct snd_kcontrol_new controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Mic"), + SOC_DAPM_PIN_SWITCH("Aux In"), +}; + +static const struct snd_soc_dapm_widget dapm_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_MIC("Mic", NULL), + SND_SOC_DAPM_LINE("Aux In", NULL), +}; + +static const struct snd_soc_dapm_route audio_map[] = { + {"Headphone Jack", NULL, "HPL"}, + {"Headphone Jack", NULL, "HPR"}, + + {"AUXL", NULL, "Aux In"}, + {"AUXR", NULL, "Aux In"}, + + /* Assume Mic1 is linked to Headset and Mic2 to on-board mic */ + {"MIC1", NULL, "Headset Mic"}, + {"MIC2", NULL, "Mic"}, + + /* SOC-codec link */ + {"ssp2 Tx", NULL, "codec_out0"}, + {"ssp2 Tx", NULL, "codec_out1"}, + {"codec_in0", NULL, "ssp2 Rx"}, + {"codec_in1", NULL, "ssp2 Rx"}, + + {"Playback", NULL, "ssp2 Tx"}, + {"ssp2 Rx", NULL, "Capture"}, +}; + +static int codec_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + int ret; + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + + /* The DSP will convert the FE rate to 48k, stereo, 24bits */ + rate->min = rate->max = 48000; + channels->min = channels->max = 2; + + /* set SSP2 to 24-bit */ + params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); + + /* + * Default mode for SSP configuration is TDM 4 slot, override config + * with explicit setting to I2S 2ch 24-bit. The word length is set with + * dai_set_tdm_slot() since there is no other API exposed + */ + ret = snd_soc_dai_set_fmt(rtd->cpu_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) { + dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, 24); + if (ret < 0) { + dev_err(rtd->dev, "can't set I2S config, err %d\n", ret); + return ret; + } + + return 0; +} + +static int aif1_startup(struct snd_pcm_substream *substream) +{ + return snd_pcm_hw_constraint_single(substream->runtime, + SNDRV_PCM_HW_PARAM_RATE, 48000); +} + +static int aif1_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + int ret; + + ret = snd_soc_dai_set_sysclk(codec_dai, DA7213_CLKSRC_MCLK, + 19200000, SND_SOC_CLOCK_IN); + if (ret < 0) + dev_err(codec_dai->dev, "can't set codec sysclk configuration\n"); + + ret = snd_soc_dai_set_pll(codec_dai, 0, + DA7213_SYSCLK_PLL_SRM, 0, DA7213_PLL_FREQ_OUT_98304000); + if (ret < 0) { + dev_err(codec_dai->dev, "failed to start PLL: %d\n", ret); + return -EIO; + } + + return ret; +} + +static int aif1_hw_free(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + int ret; + + ret = snd_soc_dai_set_pll(codec_dai, 0, + DA7213_SYSCLK_MCLK, 0, 0); + if (ret < 0) { + dev_err(codec_dai->dev, "failed to stop PLL: %d\n", ret); + return -EIO; + } + + return ret; +} + +static const struct snd_soc_ops aif1_ops = { + .startup = aif1_startup, +}; + +static const struct snd_soc_ops ssp2_ops = { + .hw_params = aif1_hw_params, + .hw_free = aif1_hw_free, + +}; + +static struct snd_soc_dai_link dailink[] = { + [MERR_DPCM_AUDIO] = { + .name = "Audio Port", + .stream_name = "Audio", + .cpu_dai_name = "media-cpu-dai", + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .platform_name = "sst-mfld-platform", + .nonatomic = true, + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ops = &aif1_ops, + }, + [MERR_DPCM_DEEP_BUFFER] = { + .name = "Deep-Buffer Audio Port", + .stream_name = "Deep-Buffer Audio", + .cpu_dai_name = "deepbuffer-cpu-dai", + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .platform_name = "sst-mfld-platform", + .nonatomic = true, + .dynamic = 1, + .dpcm_playback = 1, + .ops = &aif1_ops, + }, + [MERR_DPCM_COMPR] = { + .name = "Compressed Port", + .stream_name = "Compress", + .cpu_dai_name = "compress-cpu-dai", + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .platform_name = "sst-mfld-platform", + }, + /* CODEC<->CODEC link */ + /* back ends */ + { + .name = "SSP2-Codec", + .id = 1, + .cpu_dai_name = "ssp2-port", + .platform_name = "sst-mfld-platform", + .no_pcm = 1, + .codec_dai_name = "da7213-hifi", + .codec_name = "i2c-DLGS7213:00", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBS_CFS, + .be_hw_params_fixup = codec_fixup, + .nonatomic = true, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ops = &ssp2_ops, + }, +}; + +/* SoC card */ +static struct snd_soc_card bytcht_da7213_card = { + .name = "bytcht-da7213", + .owner = THIS_MODULE, + .dai_link = dailink, + .num_links = ARRAY_SIZE(dailink), + .controls = controls, + .num_controls = ARRAY_SIZE(controls), + .dapm_widgets = dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(dapm_widgets), + .dapm_routes = audio_map, + .num_dapm_routes = ARRAY_SIZE(audio_map), +}; + +static char codec_name[16]; /* i2c-:00 with HID being 8 chars */ + +static int bytcht_da7213_probe(struct platform_device *pdev) +{ + int ret_val = 0; + int i; + struct snd_soc_card *card; + struct sst_acpi_mach *mach; + const char *i2c_name = NULL; + int dai_index = 0; + + mach = (&pdev->dev)->platform_data; + card = &bytcht_da7213_card; + card->dev = &pdev->dev; + + /* fix index of codec dai */ + dai_index = MERR_DPCM_COMPR + 1; + for (i = 0; i < ARRAY_SIZE(dailink); i++) { + if (!strcmp(dailink[i].codec_name, "i2c-DLGS7213:00")) { + dai_index = i; + break; + } + } + + /* fixup codec name based on HID */ + i2c_name = sst_acpi_find_name_from_hid(mach->id); + if (i2c_name != NULL) { + snprintf(codec_name, sizeof(codec_name), + "%s%s", "i2c-", i2c_name); + dailink[dai_index].codec_name = codec_name; + } + + ret_val = devm_snd_soc_register_card(&pdev->dev, card); + if (ret_val) { + dev_err(&pdev->dev, + "snd_soc_register_card failed %d\n", ret_val); + return ret_val; + } + platform_set_drvdata(pdev, card); + return ret_val; +} + +static struct platform_driver bytcht_da7213_driver = { + .driver = { + .name = "bytcht_da7213", + }, + .probe = bytcht_da7213_probe, +}; +module_platform_driver(bytcht_da7213_driver); + +MODULE_DESCRIPTION("ASoC Intel(R) Baytrail/Cherrytrail+DA7213 Machine driver"); +MODULE_AUTHOR("Pierre-Louis Bossart"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:bytcht_da7213"); -- cgit v1.2.1 From a63b8a117d39ba1b979daa71c6ab350a043694f5 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 9 Mar 2017 18:19:00 -0600 Subject: ASoC: Intel: Atom: enable BYT/CHT+DA7213 machine driver Add entries in HID table and reference to bytcht_da7213 driver Signed-off-by: Pierre-Louis Bossart Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst/sst_acpi.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index 747c0f393d2d..b24bf08606ae 100644 --- a/sound/soc/intel/atom/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c @@ -480,6 +480,10 @@ static struct sst_acpi_mach sst_acpi_bytcr[] = { &byt_rvp_platform_data }, {"10EC5651", "bytcr_rt5651", "intel/fw_sst_0f28.bin", "bytcr_rt5651", NULL, &byt_rvp_platform_data }, + {"DLGS7212", "bytcht_da7213", "intel/fw_sst_0f28.bin", "bytcht_da7213", NULL, + &byt_rvp_platform_data }, + {"DLGS7213", "bytcht_da7213", "intel/fw_sst_0f28.bin", "bytcht_da7213", NULL, + &byt_rvp_platform_data }, /* some Baytrail platforms rely on RT5645, use CHT machine driver */ {"10EC5645", "cht-bsw-rt5645", "intel/fw_sst_0f28.bin", "cht-bsw", NULL, &byt_rvp_platform_data }, @@ -504,6 +508,10 @@ static struct sst_acpi_mach sst_acpi_chv[] = { {"193C9890", "cht-bsw-max98090", "intel/fw_sst_22a8.bin", "cht-bsw", NULL, &chv_platform_data }, + {"DLGS7212", "bytcht_da7213", "intel/fw_sst_22a8.bin", "bytcht_da7213", NULL, + &chv_platform_data }, + {"DLGS7213", "bytcht_da7213", "intel/fw_sst_22a8.bin", "bytcht_da7213", NULL, + &chv_platform_data }, /* some CHT-T platforms rely on RT5640, use Baytrail machine driver */ {"10EC5640", "bytcr_rt5640", "intel/fw_sst_22a8.bin", "bytcr_rt5640", cht_quirk, &chv_platform_data }, -- cgit v1.2.1 From 759db1c4660b558345573c7476a45c76a6aa07d2 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 9 Mar 2017 18:19:01 -0600 Subject: ASoC: Intel: boards: add card for MinnowBoardMax/Up I2S access Add card with dummy codec and DAI to make I2S signals observable. Uses Mic and Speaker pins/widgets to control DAPM Signed-off-by: Pierre-Louis Bossart Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/Kconfig | 12 ++ sound/soc/intel/boards/Makefile | 2 + sound/soc/intel/boards/bytcht_nocodec.c | 208 ++++++++++++++++++++++++++++++++ 3 files changed, 222 insertions(+) create mode 100644 sound/soc/intel/boards/bytcht_nocodec.c (limited to 'sound/soc') diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 8d32fc336eb8..67968ef3bbda 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -214,6 +214,18 @@ config SND_SOC_INTEL_BYT_CHT_DA7213_MACH platforms with DA7212/7213 audio codec. If unsure select "N". +config SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH + tristate "ASoC Audio driver for Intel Baytrail & Cherrytrail platform with no codec (MinnowBoard MAX, Up)" + depends on X86_INTEL_LPSS && I2C && ACPI + select SND_SST_ATOM_HIFI2_PLATFORM + select SND_SST_IPC_ACPI + select SND_SOC_INTEL_SST_MATCH if ACPI + help + This adds support for ASoC machine driver for the MinnowBoard Max or + Up boards and provides access to I2S signals on the Low-Speed + connector + If unsure select "N". + config SND_SOC_INTEL_SKYLAKE tristate select SND_HDA_EXT_CORE diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index 8a5d9edd16ee..56896e09445d 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -11,6 +11,7 @@ snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.o snd-soc-sst-cht-bsw-rt5645-objs := cht_bsw_rt5645.o snd-soc-sst-cht-bsw-max98090_ti-objs := cht_bsw_max98090_ti.o snd-soc-sst-byt-cht-da7213-objs := bytcht_da7213.o +snd-soc-sst-byt-cht-nocodec-objs := bytcht_nocodec.o snd-soc-skl_rt286-objs := skl_rt286.o snd-skl_nau88l25_max98357a-objs := skl_nau88l25_max98357a.o snd-soc-skl_nau88l25_ssm4567-objs := skl_nau88l25_ssm4567.o @@ -28,6 +29,7 @@ obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH) += snd-soc-sst-cht-bsw-rt5672.o obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH) += snd-soc-sst-cht-bsw-rt5645.o obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH) += snd-soc-sst-cht-bsw-max98090_ti.o obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_DA7213_MACH) += snd-soc-sst-byt-cht-da7213.o +obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH) += snd-soc-sst-byt-cht-nocodec.o obj-$(CONFIG_SND_SOC_INTEL_SKL_RT286_MACH) += snd-soc-skl_rt286.o obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH) += snd-skl_nau88l25_max98357a.o obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH) += snd-soc-skl_nau88l25_ssm4567.o diff --git a/sound/soc/intel/boards/bytcht_nocodec.c b/sound/soc/intel/boards/bytcht_nocodec.c new file mode 100644 index 000000000000..89853eeaaf9d --- /dev/null +++ b/sound/soc/intel/boards/bytcht_nocodec.c @@ -0,0 +1,208 @@ +/* + * bytcht_nocodec.c - ASoc Machine driver for MinnowBoard Max and Up + * to make I2S signals observable on the Low-Speed connector. Audio codec + * is not managed by ASoC/DAPM + * + * Copyright (C) 2015-2017 Intel Corp + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * 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; version 2 of the License. + * + * 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 "../atom/sst-atom-controls.h" + +static const struct snd_soc_dapm_widget widgets[] = { + SND_SOC_DAPM_MIC("Mic", NULL), + SND_SOC_DAPM_SPK("Speaker", NULL), +}; + +static const struct snd_kcontrol_new controls[] = { + SOC_DAPM_PIN_SWITCH("Mic"), + SOC_DAPM_PIN_SWITCH("Speaker"), +}; + +static const struct snd_soc_dapm_route audio_map[] = { + {"ssp2 Tx", NULL, "codec_out0"}, + {"ssp2 Tx", NULL, "codec_out1"}, + {"codec_in0", NULL, "ssp2 Rx"}, + {"codec_in1", NULL, "ssp2 Rx"}, + + {"ssp2 Rx", NULL, "Mic"}, + {"Speaker", NULL, "ssp2 Tx"}, +}; + +static int codec_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + int ret; + + /* The DSP will convert the FE rate to 48k, stereo, 24bits */ + rate->min = rate->max = 48000; + channels->min = channels->max = 2; + + /* set SSP2 to 24-bit */ + params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); + + /* + * Default mode for SSP configuration is TDM 4 slot, override config + * with explicit setting to I2S 2ch 24-bit. The word length is set with + * dai_set_tdm_slot() since there is no other API exposed + */ + ret = snd_soc_dai_set_fmt(rtd->cpu_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS); + + if (ret < 0) { + dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, 24); + if (ret < 0) { + dev_err(rtd->dev, "can't set I2S config, err %d\n", ret); + return ret; + } + + return 0; +} + +static unsigned int rates_48000[] = { + 48000, +}; + +static struct snd_pcm_hw_constraint_list constraints_48000 = { + .count = ARRAY_SIZE(rates_48000), + .list = rates_48000, +}; + +static int aif1_startup(struct snd_pcm_substream *substream) +{ + return snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + &constraints_48000); +} + +static struct snd_soc_ops aif1_ops = { + .startup = aif1_startup, +}; + +static struct snd_soc_dai_link dais[] = { + [MERR_DPCM_AUDIO] = { + .name = "Audio Port", + .stream_name = "Audio", + .cpu_dai_name = "media-cpu-dai", + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .platform_name = "sst-mfld-platform", + .ignore_suspend = 1, + .nonatomic = true, + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ops = &aif1_ops, + }, + [MERR_DPCM_DEEP_BUFFER] = { + .name = "Deep-Buffer Audio Port", + .stream_name = "Deep-Buffer Audio", + .cpu_dai_name = "deepbuffer-cpu-dai", + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .platform_name = "sst-mfld-platform", + .ignore_suspend = 1, + .nonatomic = true, + .dynamic = 1, + .dpcm_playback = 1, + .ops = &aif1_ops, + }, + [MERR_DPCM_COMPR] = { + .name = "Compressed Port", + .stream_name = "Compress", + .cpu_dai_name = "compress-cpu-dai", + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .platform_name = "sst-mfld-platform", + }, + /* CODEC<->CODEC link */ + /* back ends */ + { + .name = "SSP2-LowSpeed Connector", + .id = 1, + .cpu_dai_name = "ssp2-port", + .platform_name = "sst-mfld-platform", + .no_pcm = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBS_CFS, + .be_hw_params_fixup = codec_fixup, + .ignore_suspend = 1, + .nonatomic = true, + .dpcm_playback = 1, + .dpcm_capture = 1, + }, +}; + +/* SoC card */ +static struct snd_soc_card bytcht_nocodec_card = { + .name = "bytcht-nocodec", + .owner = THIS_MODULE, + .dai_link = dais, + .num_links = ARRAY_SIZE(dais), + .dapm_widgets = widgets, + .num_dapm_widgets = ARRAY_SIZE(widgets), + .dapm_routes = audio_map, + .num_dapm_routes = ARRAY_SIZE(audio_map), + .controls = controls, + .num_controls = ARRAY_SIZE(controls), + .fully_routed = true, +}; + +static int snd_bytcht_nocodec_mc_probe(struct platform_device *pdev) +{ + int ret_val = 0; + + /* register the soc card */ + bytcht_nocodec_card.dev = &pdev->dev; + + ret_val = devm_snd_soc_register_card(&pdev->dev, &bytcht_nocodec_card); + + if (ret_val) { + dev_err(&pdev->dev, "devm_snd_soc_register_card failed %d\n", + ret_val); + return ret_val; + } + platform_set_drvdata(pdev, &bytcht_nocodec_card); + return ret_val; +} + +static struct platform_driver snd_bytcht_nocodec_mc_driver = { + .driver = { + .name = "bytcht_nocodec", + }, + .probe = snd_bytcht_nocodec_mc_probe, +}; +module_platform_driver(snd_bytcht_nocodec_mc_driver); + +MODULE_DESCRIPTION("ASoC Intel(R) Baytrail/Cherrytrail Nocodec Machine driver"); +MODULE_AUTHOR("Pierre-Louis Bossart "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:bytcht_nocodec"); -- cgit v1.2.1 From a9b6567d03196dc73ace1c34925c7496fb194447 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 9 Mar 2017 18:19:02 -0600 Subject: ASoC: Intel: Enable bytcht_nocodec machine driver Make sure this machine driver is only used if enabled explicitly and if there is no information found in the SSDT. Signed-off-by: Pierre-Louis Bossart Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst/sst_acpi.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index b24bf08606ae..18fe46ef6ac7 100644 --- a/sound/soc/intel/atom/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c @@ -489,7 +489,14 @@ static struct sst_acpi_mach sst_acpi_bytcr[] = { &byt_rvp_platform_data }, {"10EC5648", "cht-bsw-rt5645", "intel/fw_sst_0f28.bin", "cht-bsw", NULL, &byt_rvp_platform_data }, - +#if IS_ENABLED(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH) + /* + * This is always last in the table so that it is selected only when + * enabled explicitly and there is no codec-related information in SSDT + */ + {"80860F28", "bytcht_nocodec", "intel/fw_sst_0f28.bin", "bytcht_nocodec", NULL, + &byt_rvp_platform_data }, +#endif {}, }; @@ -520,6 +527,14 @@ static struct sst_acpi_mach sst_acpi_chv[] = { /* some CHT-T platforms rely on RT5651, use Baytrail machine driver */ {"10EC5651", "bytcr_rt5651", "intel/fw_sst_22a8.bin", "bytcr_rt5651", NULL, &chv_platform_data }, +#if IS_ENABLED(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH) + /* + * This is always last in the table so that it is selected only when + * enabled explicitly and there is no codec-related information in SSDT + */ + {"808622A8", "bytcht_nocodec", "intel/fw_sst_22a8.bin", "bytcht_nocodec", NULL, + &chv_platform_data }, +#endif {}, }; -- cgit v1.2.1 From 82875163a8ef1e25477402c5ebb8f5beaea5e93e Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 11 Mar 2017 20:57:07 +0800 Subject: ASoC: cs35l35: Fix display revision id Signed-off-by: Axel Lin Acked-by: Paul Handrigan Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l35.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/cs35l35.c b/sound/soc/codecs/cs35l35.c index 7c4d74ec32cb..a9e45dea309e 100644 --- a/sound/soc/codecs/cs35l35.c +++ b/sound/soc/codecs/cs35l35.c @@ -1463,7 +1463,7 @@ static int cs35l35_i2c_probe(struct i2c_client *i2c_client, } dev_info(dev, "Cirrus Logic CS35L35 (%x), Revision: %02X\n", - devid, ret & 0xFF); + devid, reg & 0xFF); /* Set the INT Masks for critical errors */ regmap_write(cs35l35->regmap, CS35L35_INT_MASK_1, -- cgit v1.2.1 From 03ff570c6b45b27e233f5cb1fd04404374fd883f Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sat, 11 Mar 2017 19:19:22 +0000 Subject: ASoC: cs35l35: trivial fix to indentation Remove extraneous tab to correct the nesting level indentation Detected by CoverityScan, CID#1416584 ("Nesting level does not match indentation") Signed-off-by: Colin Ian King Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l35.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/cs35l35.c b/sound/soc/codecs/cs35l35.c index a9e45dea309e..a5da1d511a8a 100644 --- a/sound/soc/codecs/cs35l35.c +++ b/sound/soc/codecs/cs35l35.c @@ -1375,7 +1375,8 @@ static int cs35l35_i2c_probe(struct i2c_client *i2c_client, for (i = 0; i < ARRAY_SIZE(cs35l35_supplies); i++) cs35l35->supplies[i].supply = cs35l35_supplies[i]; - cs35l35->num_supplies = ARRAY_SIZE(cs35l35_supplies); + + cs35l35->num_supplies = ARRAY_SIZE(cs35l35_supplies); ret = devm_regulator_bulk_get(dev, cs35l35->num_supplies, cs35l35->supplies); -- cgit v1.2.1 From f3a612a655c1ca585c89c654c06e56eb2f8539e4 Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Sun, 12 Mar 2017 09:11:32 +0800 Subject: ASoC: cs35l35: fix semicolon.cocci warnings sound/soc/codecs/cs35l35.c:706:2-3: Unneeded semicolon sound/soc/codecs/cs35l35.c:543:4-5: Unneeded semicolon sound/soc/codecs/cs35l35.c:553:4-5: Unneeded semicolon Remove unneeded semicolon. Generated by: scripts/coccinelle/misc/semicolon.cocci CC: Brian Austin Signed-off-by: Fengguang Wu Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l35.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/cs35l35.c b/sound/soc/codecs/cs35l35.c index a5da1d511a8a..6a266516f543 100644 --- a/sound/soc/codecs/cs35l35.c +++ b/sound/soc/codecs/cs35l35.c @@ -540,7 +540,7 @@ static int cs35l35_hw_params(struct snd_pcm_substream *substream, default: dev_err(codec->dev, "ratio not supported\n"); return -EINVAL; - }; + } } else { /* Only certain ratios supported in I2S MASTER Mode */ switch (sp_sclks) { @@ -550,7 +550,7 @@ static int cs35l35_hw_params(struct snd_pcm_substream *substream, default: dev_err(codec->dev, "ratio not supported\n"); return -EINVAL; - }; + } } ret = regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL3, @@ -703,7 +703,7 @@ static int cs35l35_codec_set_sysclk(struct snd_soc_codec *codec, default: dev_err(codec->dev, "Invalid CLK Source\n"); return -EINVAL; - }; + } switch (freq) { case 5644800: -- cgit v1.2.1 From bfe41c678d49f440de3ae80b945f7f94d5dbd340 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 13 Mar 2017 15:32:37 +0300 Subject: ASoC: cs35l35: returning uninitialized in probe() If cs35l35->pdata.stereo is false then "ret" isn't initialized. Fixes: 6387f866a2cc ("ASoC: Add support for Cirrus Logic CS35L35 Amplifier") Signed-off-by: Dan Carpenter Acked-by: Paul Handrigan Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l35.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/cs35l35.c b/sound/soc/codecs/cs35l35.c index 6a266516f543..05117fca7e3c 100644 --- a/sound/soc/codecs/cs35l35.c +++ b/sound/soc/codecs/cs35l35.c @@ -969,7 +969,7 @@ static int cs35l35_codec_probe(struct snd_soc_codec *codec) } } - return ret; + return 0; } static struct snd_soc_codec_driver soc_codec_dev_cs35l35 = { -- cgit v1.2.1 From ccd00d5911ce1e144c79799f3d105961a11e4009 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Thu, 9 Mar 2017 19:31:13 +0800 Subject: ASoC: rt5665: move set_pll to codec level Move set_pll function to codec level and people can use it at both codec and dai level. Also, lower case "source" to keep it consistent. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5665.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c index 1baa9ce2648a..b36e217345f6 100644 --- a/sound/soc/codecs/rt5665.c +++ b/sound/soc/codecs/rt5665.c @@ -4222,15 +4222,15 @@ static int rt5665_set_dai_sysclk(struct snd_soc_dai *dai, return 0; } -static int rt5665_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int Source, - unsigned int freq_in, unsigned int freq_out) +static int rt5665_set_codec_pll(struct snd_soc_codec *codec, int pll_id, + int source, unsigned int freq_in, + unsigned int freq_out) { - struct snd_soc_codec *codec = dai->codec; struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec); struct rl6231_pll_code pll_code; int ret; - if (Source == rt5665->pll_src && freq_in == rt5665->pll_in && + if (source == rt5665->pll_src && freq_in == rt5665->pll_in && freq_out == rt5665->pll_out) return 0; @@ -4244,7 +4244,7 @@ static int rt5665_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int Source, return 0; } - switch (Source) { + switch (source) { case RT5665_PLL1_S_MCLK: snd_soc_update_bits(codec, RT5665_GLB_CLK, RT5665_PLL1_SRC_MASK, RT5665_PLL1_SRC_MCLK); @@ -4262,7 +4262,7 @@ static int rt5665_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int Source, RT5665_PLL1_SRC_MASK, RT5665_PLL1_SRC_BCLK3); break; default: - dev_err(codec->dev, "Unknown PLL Source %d\n", Source); + dev_err(codec->dev, "Unknown PLL Source %d\n", source); return -EINVAL; } @@ -4284,7 +4284,7 @@ static int rt5665_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int Source, rt5665->pll_in = freq_in; rt5665->pll_out = freq_out; - rt5665->pll_src = Source; + rt5665->pll_src = source; return 0; } @@ -4403,7 +4403,6 @@ static const struct snd_soc_dai_ops rt5665_aif_dai_ops = { .set_fmt = rt5665_set_dai_fmt, .set_sysclk = rt5665_set_dai_sysclk, .set_tdm_slot = rt5665_set_tdm_slot, - .set_pll = rt5665_set_dai_pll, .set_bclk_ratio = rt5665_set_bclk_ratio, }; @@ -4512,7 +4511,8 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5665 = { .num_dapm_widgets = ARRAY_SIZE(rt5665_dapm_widgets), .dapm_routes = rt5665_dapm_routes, .num_dapm_routes = ARRAY_SIZE(rt5665_dapm_routes), - } + }, + .set_pll = rt5665_set_codec_pll, }; -- cgit v1.2.1 From 28d2ca39be43fab0caee2f13d818504e9e802ef7 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Thu, 9 Mar 2017 19:31:14 +0800 Subject: ASoC: rt5665: move set_sysclk to codec level Move set_sysclk to codec level and people can use it at both codec and dai level. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5665.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c index b36e217345f6..1d00c6078feb 100644 --- a/sound/soc/codecs/rt5665.c +++ b/sound/soc/codecs/rt5665.c @@ -4188,10 +4188,9 @@ static int rt5665_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) return 0; } -static int rt5665_set_dai_sysclk(struct snd_soc_dai *dai, - int clk_id, unsigned int freq, int dir) +static int rt5665_set_codec_sysclk(struct snd_soc_codec *codec, int clk_id, + int source, unsigned int freq, int dir) { - struct snd_soc_codec *codec = dai->codec; struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec); unsigned int reg_val = 0; @@ -4217,7 +4216,7 @@ static int rt5665_set_dai_sysclk(struct snd_soc_dai *dai, rt5665->sysclk = freq; rt5665->sysclk_src = clk_id; - dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id); + dev_dbg(codec->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id); return 0; } @@ -4401,7 +4400,6 @@ static int rt5665_resume(struct snd_soc_codec *codec) static const struct snd_soc_dai_ops rt5665_aif_dai_ops = { .hw_params = rt5665_hw_params, .set_fmt = rt5665_set_dai_fmt, - .set_sysclk = rt5665_set_dai_sysclk, .set_tdm_slot = rt5665_set_tdm_slot, .set_bclk_ratio = rt5665_set_bclk_ratio, }; @@ -4512,6 +4510,7 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5665 = { .dapm_routes = rt5665_dapm_routes, .num_dapm_routes = ARRAY_SIZE(rt5665_dapm_routes), }, + .set_sysclk = rt5665_set_codec_sysclk, .set_pll = rt5665_set_codec_pll, }; -- cgit v1.2.1 From 943b73112dfdd6747871a3347f70de6876f4dd4b Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Tue, 14 Mar 2017 01:16:40 +0530 Subject: ASoC: pxa: constify snd_soc_ops structures Declare snd_soc_ops structures as const as they are only stored in the ops field of a snd_soc_dai_link structure. This field is of type const, so snd_soc_ops structures having this property can be made const too. The .o files did not compile for all the changed .c files. Signed-off-by: Bhumika Goyal Signed-off-by: Mark Brown --- sound/soc/pxa/brownstone.c | 2 +- sound/soc/pxa/corgi.c | 2 +- sound/soc/pxa/hx4700.c | 2 +- sound/soc/pxa/imote2.c | 2 +- sound/soc/pxa/magician.c | 4 ++-- sound/soc/pxa/poodle.c | 2 +- sound/soc/pxa/raumfeld.c | 2 +- sound/soc/pxa/spitz.c | 2 +- sound/soc/pxa/tosa.c | 2 +- sound/soc/pxa/z2.c | 2 +- sound/soc/pxa/zylonite.c | 2 +- 11 files changed, 12 insertions(+), 12 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/pxa/brownstone.c b/sound/soc/pxa/brownstone.c index b6cb9950f05d..9a3f5b799720 100644 --- a/sound/soc/pxa/brownstone.c +++ b/sound/soc/pxa/brownstone.c @@ -74,7 +74,7 @@ static int brownstone_wm8994_hw_params(struct snd_pcm_substream *substream, } /* machine stream operations */ -static struct snd_soc_ops brownstone_ops = { +static const struct snd_soc_ops brownstone_ops = { .hw_params = brownstone_wm8994_hw_params, }; diff --git a/sound/soc/pxa/corgi.c b/sound/soc/pxa/corgi.c index 311774e9ca46..054e0d65db9d 100644 --- a/sound/soc/pxa/corgi.c +++ b/sound/soc/pxa/corgi.c @@ -154,7 +154,7 @@ static int corgi_hw_params(struct snd_pcm_substream *substream, return 0; } -static struct snd_soc_ops corgi_ops = { +static const struct snd_soc_ops corgi_ops = { .startup = corgi_startup, .hw_params = corgi_hw_params, .shutdown = corgi_shutdown, diff --git a/sound/soc/pxa/hx4700.c b/sound/soc/pxa/hx4700.c index 85483049b916..a9ac881c2e14 100644 --- a/sound/soc/pxa/hx4700.c +++ b/sound/soc/pxa/hx4700.c @@ -79,7 +79,7 @@ static int hx4700_hw_params(struct snd_pcm_substream *substream, return 0; } -static struct snd_soc_ops hx4700_ops = { +static const struct snd_soc_ops hx4700_ops = { .hw_params = hx4700_hw_params, }; diff --git a/sound/soc/pxa/imote2.c b/sound/soc/pxa/imote2.c index 9d0e40771ef5..78475376f971 100644 --- a/sound/soc/pxa/imote2.c +++ b/sound/soc/pxa/imote2.c @@ -42,7 +42,7 @@ static int imote2_asoc_hw_params(struct snd_pcm_substream *substream, return ret; } -static struct snd_soc_ops imote2_asoc_ops = { +static const struct snd_soc_ops imote2_asoc_ops = { .hw_params = imote2_asoc_hw_params, }; diff --git a/sound/soc/pxa/magician.c b/sound/soc/pxa/magician.c index 2d4d4455fe87..2fc012b06c43 100644 --- a/sound/soc/pxa/magician.c +++ b/sound/soc/pxa/magician.c @@ -255,12 +255,12 @@ static int magician_capture_hw_params(struct snd_pcm_substream *substream, return 0; } -static struct snd_soc_ops magician_capture_ops = { +static const struct snd_soc_ops magician_capture_ops = { .startup = magician_startup, .hw_params = magician_capture_hw_params, }; -static struct snd_soc_ops magician_playback_ops = { +static const struct snd_soc_ops magician_playback_ops = { .startup = magician_startup, .hw_params = magician_playback_hw_params, }; diff --git a/sound/soc/pxa/poodle.c b/sound/soc/pxa/poodle.c index a879aba0691f..b6693f32fc02 100644 --- a/sound/soc/pxa/poodle.c +++ b/sound/soc/pxa/poodle.c @@ -129,7 +129,7 @@ static int poodle_hw_params(struct snd_pcm_substream *substream, return 0; } -static struct snd_soc_ops poodle_ops = { +static const struct snd_soc_ops poodle_ops = { .startup = poodle_startup, .hw_params = poodle_hw_params, .shutdown = poodle_shutdown, diff --git a/sound/soc/pxa/raumfeld.c b/sound/soc/pxa/raumfeld.c index 47c91730e93c..111a907c4eb9 100644 --- a/sound/soc/pxa/raumfeld.c +++ b/sound/soc/pxa/raumfeld.c @@ -132,7 +132,7 @@ static int raumfeld_cs4270_hw_params(struct snd_pcm_substream *substream, return 0; } -static struct snd_soc_ops raumfeld_cs4270_ops = { +static const struct snd_soc_ops raumfeld_cs4270_ops = { .startup = raumfeld_cs4270_startup, .shutdown = raumfeld_cs4270_shutdown, .hw_params = raumfeld_cs4270_hw_params, diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c index d38a2b519c52..1671da648e95 100644 --- a/sound/soc/pxa/spitz.c +++ b/sound/soc/pxa/spitz.c @@ -156,7 +156,7 @@ static int spitz_hw_params(struct snd_pcm_substream *substream, return 0; } -static struct snd_soc_ops spitz_ops = { +static const struct snd_soc_ops spitz_ops = { .startup = spitz_startup, .hw_params = spitz_hw_params, }; diff --git a/sound/soc/pxa/tosa.c b/sound/soc/pxa/tosa.c index 1812748b75bf..ae9c12e1ea2a 100644 --- a/sound/soc/pxa/tosa.c +++ b/sound/soc/pxa/tosa.c @@ -85,7 +85,7 @@ static int tosa_startup(struct snd_pcm_substream *substream) return 0; } -static struct snd_soc_ops tosa_ops = { +static const struct snd_soc_ops tosa_ops = { .startup = tosa_startup, }; diff --git a/sound/soc/pxa/z2.c b/sound/soc/pxa/z2.c index 6d88d9acc666..5b0eccd2b4dd 100644 --- a/sound/soc/pxa/z2.c +++ b/sound/soc/pxa/z2.c @@ -152,7 +152,7 @@ err: return ret; } -static struct snd_soc_ops z2_ops = { +static const struct snd_soc_ops z2_ops = { .hw_params = z2_hw_params, }; diff --git a/sound/soc/pxa/zylonite.c b/sound/soc/pxa/zylonite.c index 6fbcdf02c88d..ba468e560dd2 100644 --- a/sound/soc/pxa/zylonite.c +++ b/sound/soc/pxa/zylonite.c @@ -132,7 +132,7 @@ static int zylonite_voice_hw_params(struct snd_pcm_substream *substream, return 0; } -static struct snd_soc_ops zylonite_voice_ops = { +static const struct snd_soc_ops zylonite_voice_ops = { .hw_params = zylonite_voice_hw_params, }; -- cgit v1.2.1 From 5ace37bd7947e28dec5559a57ddc6e1d997dbec5 Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Tue, 14 Mar 2017 00:42:22 +0530 Subject: ASoC: fsl: constify snd_soc_ops structures Declare snd_soc_ops structures as const as they are only stored in the ops field of a snd_soc_dai_link structure. This field is of type const, so snd_soc_ops structures having this property can be made const too. The following .o files did not compile: sound/soc/fsl/{p1022_rdk.c/p1022_ds.c/mpc8610_hpcd.c} Signed-off-by: Bhumika Goyal Signed-off-by: Mark Brown --- sound/soc/fsl/eukrea-tlv320.c | 2 +- sound/soc/fsl/imx-mc13783.c | 2 +- sound/soc/fsl/mpc8610_hpcd.c | 2 +- sound/soc/fsl/mx27vis-aic32x4.c | 2 +- sound/soc/fsl/p1022_ds.c | 2 +- sound/soc/fsl/p1022_rdk.c | 2 +- sound/soc/fsl/phycore-ac97.c | 2 +- sound/soc/fsl/wm1133-ev1.c | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/fsl/eukrea-tlv320.c b/sound/soc/fsl/eukrea-tlv320.c index 883087f2b092..84ef6385736c 100644 --- a/sound/soc/fsl/eukrea-tlv320.c +++ b/sound/soc/fsl/eukrea-tlv320.c @@ -64,7 +64,7 @@ static int eukrea_tlv320_hw_params(struct snd_pcm_substream *substream, return 0; } -static struct snd_soc_ops eukrea_tlv320_snd_ops = { +static const struct snd_soc_ops eukrea_tlv320_snd_ops = { .hw_params = eukrea_tlv320_hw_params, }; diff --git a/sound/soc/fsl/imx-mc13783.c b/sound/soc/fsl/imx-mc13783.c index bb0459018b45..9d19b808f634 100644 --- a/sound/soc/fsl/imx-mc13783.c +++ b/sound/soc/fsl/imx-mc13783.c @@ -48,7 +48,7 @@ static int imx_mc13783_hifi_hw_params(struct snd_pcm_substream *substream, return snd_soc_dai_set_tdm_slot(cpu_dai, 0x3, 0x3, 2, 16); } -static struct snd_soc_ops imx_mc13783_hifi_ops = { +static const struct snd_soc_ops imx_mc13783_hifi_ops = { .hw_params = imx_mc13783_hifi_hw_params, }; diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c index ddf49f30b23f..a639b52c16f6 100644 --- a/sound/soc/fsl/mpc8610_hpcd.c +++ b/sound/soc/fsl/mpc8610_hpcd.c @@ -174,7 +174,7 @@ static int mpc8610_hpcd_machine_remove(struct snd_soc_card *card) /** * mpc8610_hpcd_ops: ASoC machine driver operations */ -static struct snd_soc_ops mpc8610_hpcd_ops = { +static const struct snd_soc_ops mpc8610_hpcd_ops = { .startup = mpc8610_hpcd_startup, }; diff --git a/sound/soc/fsl/mx27vis-aic32x4.c b/sound/soc/fsl/mx27vis-aic32x4.c index 198eeb3f3f7a..d7ec3d20065c 100644 --- a/sound/soc/fsl/mx27vis-aic32x4.c +++ b/sound/soc/fsl/mx27vis-aic32x4.c @@ -73,7 +73,7 @@ static int mx27vis_aic32x4_hw_params(struct snd_pcm_substream *substream, return 0; } -static struct snd_soc_ops mx27vis_aic32x4_snd_ops = { +static const struct snd_soc_ops mx27vis_aic32x4_snd_ops = { .hw_params = mx27vis_aic32x4_hw_params, }; diff --git a/sound/soc/fsl/p1022_ds.c b/sound/soc/fsl/p1022_ds.c index a1f780ecadf5..41c623c55c16 100644 --- a/sound/soc/fsl/p1022_ds.c +++ b/sound/soc/fsl/p1022_ds.c @@ -184,7 +184,7 @@ static int p1022_ds_machine_remove(struct snd_soc_card *card) /** * p1022_ds_ops: ASoC machine driver operations */ -static struct snd_soc_ops p1022_ds_ops = { +static const struct snd_soc_ops p1022_ds_ops = { .startup = p1022_ds_startup, }; diff --git a/sound/soc/fsl/p1022_rdk.c b/sound/soc/fsl/p1022_rdk.c index d4d88a8cb9c0..4afbdd610bfa 100644 --- a/sound/soc/fsl/p1022_rdk.c +++ b/sound/soc/fsl/p1022_rdk.c @@ -188,7 +188,7 @@ static int p1022_rdk_machine_remove(struct snd_soc_card *card) /** * p1022_rdk_ops: ASoC machine driver operations */ -static struct snd_soc_ops p1022_rdk_ops = { +static const struct snd_soc_ops p1022_rdk_ops = { .startup = p1022_rdk_startup, }; diff --git a/sound/soc/fsl/phycore-ac97.c b/sound/soc/fsl/phycore-ac97.c index ae403c29688f..66fb6c4614d2 100644 --- a/sound/soc/fsl/phycore-ac97.c +++ b/sound/soc/fsl/phycore-ac97.c @@ -23,7 +23,7 @@ static struct snd_soc_card imx_phycore; -static struct snd_soc_ops imx_phycore_hifi_ops = { +static const struct snd_soc_ops imx_phycore_hifi_ops = { }; static struct snd_soc_dai_link imx_phycore_dai_ac97[] = { diff --git a/sound/soc/fsl/wm1133-ev1.c b/sound/soc/fsl/wm1133-ev1.c index b454972dce35..cdaf16367b47 100644 --- a/sound/soc/fsl/wm1133-ev1.c +++ b/sound/soc/fsl/wm1133-ev1.c @@ -139,7 +139,7 @@ static int wm1133_ev1_hw_params(struct snd_pcm_substream *substream, return 0; } -static struct snd_soc_ops wm1133_ev1_ops = { +static const struct snd_soc_ops wm1133_ev1_ops = { .hw_params = wm1133_ev1_hw_params, }; -- cgit v1.2.1 From 6914968b8203aef72edf936319c4d46c6d46401b Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Mon, 13 Mar 2017 22:11:23 +0530 Subject: ASoC: Intel: Skylake: Fix to delete DSP pipe after stopping pipe DSP pipe needs to stopped before deleting the pipe. Currently check is for pipe state > STARTED, which is incorrect. So changed to include pipe state STARTED to stop the pipe if it started. Signed-off-by: Jeeja KP Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-messages.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index e66870474f10..ed576965cacc 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -1098,7 +1098,7 @@ int skl_delete_pipe(struct skl_sst *ctx, struct skl_pipe *pipe) dev_dbg(ctx->dev, "%s: pipe = %d\n", __func__, pipe->ppl_id); /* If pipe is started, do stop the pipe in FW. */ - if (pipe->state > SKL_PIPE_STARTED) { + if (pipe->state >= SKL_PIPE_STARTED) { ret = skl_set_pipe_state(ctx, pipe, PPL_PAUSED); if (ret < 0) { dev_err(ctx->dev, "Failed to stop pipeline\n"); -- cgit v1.2.1 From 3b563e0a8406bf47cd39ca59f8453b3d968d996a Mon Sep 17 00:00:00 2001 From: Guneshwor Singh Date: Mon, 13 Mar 2017 22:11:24 +0530 Subject: ASoC: Intel: Skylake: Fix not to stop src pipe in pre pmd event handler If the widget is a mixin module, just unbind between source and sink and don't stop the source pipe as there can be multiple sinks connected. Signed-off-by: Guneshwor Singh Signed-off-by: Jeeja KP Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-topology.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index e7836a2e18f0..d4058d2a8023 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -973,15 +973,6 @@ static int skl_tplg_mixer_dapm_pre_pmd_event(struct snd_soc_dapm_widget *w, src_mconfig = sink_mconfig->m_in_pin[i].tgt_mcfg; if (!src_mconfig) continue; - /* - * If path_found == 1, that means pmd for source - * pipe has not occurred, source is connected to - * some other sink. so its responsibility of sink - * to unbind itself from source. - */ - ret = skl_stop_pipe(ctx, src_mconfig->pipe); - if (ret < 0) - return ret; ret = skl_unbind_modules(ctx, src_mconfig, sink_mconfig); -- cgit v1.2.1 From 5518af9f97940e84de6a4bf6fed212a95278f818 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Mon, 13 Mar 2017 22:11:25 +0530 Subject: ASoC: Intel: bxtn: Disable interrupt when DSP is in D3 When DSP is in D3, no interrupts are expected, so disable interrupt while entering D3. Signed-off-by: Jeeja KP Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/bxt-sst.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/intel/skylake/bxt-sst.c b/sound/soc/intel/skylake/bxt-sst.c index d3be1be5a372..b34c96508605 100644 --- a/sound/soc/intel/skylake/bxt-sst.c +++ b/sound/soc/intel/skylake/bxt-sst.c @@ -537,6 +537,11 @@ static int bxt_set_dsp_D3(struct sst_dsp *ctx, unsigned int core_id) "Failed to set DSP to D3:core id = %d;Continue reset\n", core_id); + if (core_id == SKL_DSP_CORE0_ID) { + /* disable Interrupt */ + skl_ipc_op_int_disable(ctx); + skl_ipc_int_disable(ctx); + } ret = skl_dsp_disable_core(ctx, core_mask); if (ret < 0) { dev_err(ctx->dev, "Failed to disable core %d\n", ret); -- cgit v1.2.1 From 1fb344a33a2f99378128281df97770e2c5182c2d Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Mon, 13 Mar 2017 22:11:26 +0530 Subject: ASoC: Intel: bxtn: Update DSP core state in D0 In system suspend, firmware needs to be re-downloaded as IMR is cleared. When firmware is downloaded in D0, core state is not set to running state causing instability with subsequent D0-D3 cycles. So set the core state correctly during D0 and check the DSP core state if not in reset to set the DSP to D3. Signed-off-by: Jeeja KP Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/bxt-sst.c | 1 + sound/soc/intel/skylake/skl-sst-dsp.c | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/intel/skylake/bxt-sst.c b/sound/soc/intel/skylake/bxt-sst.c index b34c96508605..2a2bb944cd40 100644 --- a/sound/soc/intel/skylake/bxt-sst.c +++ b/sound/soc/intel/skylake/bxt-sst.c @@ -446,6 +446,7 @@ static int bxt_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id) return ret; } } + skl->cores.state[core_id] = SKL_DSP_RUNNING; return ret; } diff --git a/sound/soc/intel/skylake/skl-sst-dsp.c b/sound/soc/intel/skylake/skl-sst-dsp.c index c3deefab65d6..08332723c700 100644 --- a/sound/soc/intel/skylake/skl-sst-dsp.c +++ b/sound/soc/intel/skylake/skl-sst-dsp.c @@ -355,12 +355,13 @@ int skl_dsp_get_core(struct sst_dsp *ctx, unsigned int core_id) ret = ctx->fw_ops.set_state_D0(ctx, core_id); if (ret < 0) { dev_err(ctx->dev, "unable to get core%d\n", core_id); - return ret; + goto out; } } skl->cores.usage_count[core_id]++; +out: dev_dbg(ctx->dev, "core id %d state %d usage_count %d\n", core_id, skl->cores.state[core_id], skl->cores.usage_count[core_id]); @@ -379,7 +380,8 @@ int skl_dsp_put_core(struct sst_dsp *ctx, unsigned int core_id) return -EINVAL; } - if (--skl->cores.usage_count[core_id] == 0) { + if ((--skl->cores.usage_count[core_id] == 0) && + (skl->cores.state[core_id] != SKL_DSP_RESET)) { ret = ctx->fw_ops.set_state_D3(ctx, core_id); if (ret < 0) { dev_err(ctx->dev, "unable to put core %d: %d\n", -- cgit v1.2.1 From 03de8c2ef82fae29d53de7eb86b0ca10501499fc Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Mon, 13 Mar 2017 22:11:27 +0530 Subject: ASoC: Intel: bxtn: Reload the firmware in case of D3 failure If D3 IPC fails or times out, firmware needs to be reloaded as driver continues the reset. So set the fw_load flag to false to reload the firmware in D0. Signed-off-by: Jeeja KP Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/bxt-sst.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/intel/skylake/bxt-sst.c b/sound/soc/intel/skylake/bxt-sst.c index 2a2bb944cd40..600d95891996 100644 --- a/sound/soc/intel/skylake/bxt-sst.c +++ b/sound/soc/intel/skylake/bxt-sst.c @@ -533,10 +533,16 @@ static int bxt_set_dsp_D3(struct sst_dsp *ctx, unsigned int core_id) ret = skl_ipc_set_dx(&skl->ipc, BXT_INSTANCE_ID, BXT_BASE_FW_MODULE_ID, &dx); - if (ret < 0) + if (ret < 0) { dev_err(ctx->dev, "Failed to set DSP to D3:core id = %d;Continue reset\n", core_id); + /* + * In case of D3 failure, re-download the firmware, so set + * fw_loaded to false. + */ + skl->fw_loaded = false; + } if (core_id == SKL_DSP_CORE0_ID) { /* disable Interrupt */ -- cgit v1.2.1 From 3643ff10d48140a283d2e50c0e0a47f290cc3e4d Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Mon, 13 Mar 2017 22:11:28 +0530 Subject: ASoC: Intel: Skylake: Remove BE prepare ops Remove BE prepare ops which enables MCLK by default. If MCLK is required to be enabled for any specific platform, it needs to be enabled in the corresponding machine driver. Signed-off-by: Jeeja KP Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-pcm.c | 18 ------------------ 1 file changed, 18 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 635cbb1e7d91..e3d206d50f3e 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -262,23 +262,6 @@ static int skl_pcm_open(struct snd_pcm_substream *substream, return 0; } -static int skl_be_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct skl *skl = get_skl_ctx(dai->dev); - struct skl_sst *ctx = skl->skl_sst; - struct skl_module_cfg *mconfig; - - if (dai->playback_widget->power || dai->capture_widget->power) - return 0; - - mconfig = skl_tplg_be_get_cpr_module(dai, substream->stream); - if (mconfig == NULL) - return -EINVAL; - - return skl_dsp_set_dma_control(ctx, mconfig); -} - static int skl_pcm_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -649,7 +632,6 @@ static struct snd_soc_dai_ops skl_dmic_dai_ops = { static struct snd_soc_dai_ops skl_be_ssp_dai_ops = { .hw_params = skl_be_hw_params, - .prepare = skl_be_prepare, }; static struct snd_soc_dai_ops skl_link_dai_ops = { -- cgit v1.2.1 From cb729d80b5c556acf38f1f04a1f0550472a75987 Mon Sep 17 00:00:00 2001 From: G Kranthi Date: Mon, 13 Mar 2017 22:11:29 +0530 Subject: ASoC: Intel: Skylake: Disable notifications at boot after DSP FW init DSP firmware sends notification every 1ms, which is disabled in runtime suspend. But if a system has no runtime pm, we keep getting notification, so disable after FW init as well. Signed-off-by: G Kranthi Signed-off-by: Jeeja KP Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-messages.c | 2 +- sound/soc/intel/skylake/skl-pcm.c | 1 + sound/soc/intel/skylake/skl-sst-dsp.h | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index ed576965cacc..29523ddcfab0 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -58,7 +58,7 @@ static int skl_free_dma_buf(struct device *dev, struct snd_dma_buffer *dmab) #define NOTIFICATION_MASK 0xf /* disable notfication for underruns/overruns from firmware module */ -static void skl_dsp_enable_notification(struct skl_sst *ctx, bool enable) +void skl_dsp_enable_notification(struct skl_sst *ctx, bool enable) { struct notification_mask mask; struct skl_ipc_large_config_msg msg = {0}; diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index e3d206d50f3e..2f90bc40be77 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -1214,6 +1214,7 @@ static int skl_platform_soc_probe(struct snd_soc_platform *platform) } skl_populate_modules(skl); skl->skl_sst->update_d0i3c = skl_update_d0i3c; + skl_dsp_enable_notification(skl->skl_sst, false); } pm_runtime_mark_last_busy(platform->dev); pm_runtime_put_autosuspend(platform->dev); diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h index 849410d0823e..e8d1e149e0cd 100644 --- a/sound/soc/intel/skylake/skl-sst-dsp.h +++ b/sound/soc/intel/skylake/skl-sst-dsp.h @@ -235,4 +235,6 @@ int skl_get_pvt_instance_id_map(struct skl_sst *ctx, void skl_freeup_uuid_list(struct skl_sst *ctx); int skl_dsp_strip_extended_manifest(struct firmware *fw); +void skl_dsp_enable_notification(struct skl_sst *ctx, bool enable); + #endif /*__SKL_SST_DSP_H__*/ -- cgit v1.2.1 From 7bd86a30599de479bd863e18472207337485d339 Mon Sep 17 00:00:00 2001 From: G Kranthi Date: Mon, 13 Mar 2017 22:11:30 +0530 Subject: ASoC: Intel: Skylake: Remove get dsp_ops in cleanup routine dsp ops is already set in init, so use this in cleanup routine instead of again retrieving it. Also constify struct skl_dsp_ops. Signed-off-by: G Kranthi Signed-off-by: Jeeja KP Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-messages.c | 8 ++------ sound/soc/intel/skylake/skl-sst-ipc.h | 2 ++ 2 files changed, 4 insertions(+), 6 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index 29523ddcfab0..ba1ec973ded7 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -274,6 +274,7 @@ int skl_init_dsp(struct skl *skl) if (ret < 0) return ret; + skl->skl_sst->dsp_ops = ops; dev_dbg(bus->dev, "dsp registration status=%d\n", ret); return ret; @@ -284,16 +285,11 @@ int skl_free_dsp(struct skl *skl) struct hdac_ext_bus *ebus = &skl->ebus; struct hdac_bus *bus = ebus_to_hbus(ebus); struct skl_sst *ctx = skl->skl_sst; - const struct skl_dsp_ops *ops; /* disable ppcap interrupt */ snd_hdac_ext_bus_ppcap_int_enable(&skl->ebus, false); - ops = skl_get_dsp_ops(skl->pci->device); - if (!ops) - return -EIO; - - ops->cleanup(bus->dev, ctx); + ctx->dsp_ops->cleanup(bus->dev, ctx); if (ctx->dsp->addr.lpe) iounmap(ctx->dsp->addr.lpe); diff --git a/sound/soc/intel/skylake/skl-sst-ipc.h b/sound/soc/intel/skylake/skl-sst-ipc.h index 9660ace379ab..7d21f055328d 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.h +++ b/sound/soc/intel/skylake/skl-sst-ipc.h @@ -105,6 +105,8 @@ struct skl_sst { void (*update_d0i3c)(struct device *dev, bool enable); struct skl_d0i3_data d0i3; + + const struct skl_dsp_ops *dsp_ops; }; struct skl_ipc_init_instance_msg { -- cgit v1.2.1 From b7d0254c51f3ce79a8931690e8a2f035208f6b55 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Mon, 13 Mar 2017 22:11:31 +0530 Subject: ASoC: Intel: Skylake: Fix module load when module size > DMA buffer size When module size > DMA buffer size, driver copies first chunk and waits for the BDL complete interrupt. BDL complete interrupt never occurs and wait time expires as module load IPC is not send to start the DMA from DSP. To fix the above issue need to follow the below steps: 1. After copying the first chunk, send the module load IPC to start the DMA. 2. Wait for the BDL interrupt. Once interrupt is received, copy the next chunk. 3. Continue step 2 till all bytes are copied. 4. When all the bytes are copied (bytes_left = 0), wait for module load IPC response 5. Handled module load IPC response messages, check the load module IPC response and wake up the thread to complete module load. Signed-off-by: Jeeja KP Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-sst-cldma.c | 26 ++++++++----- sound/soc/intel/skylake/skl-sst-cldma.h | 2 +- sound/soc/intel/skylake/skl-sst-dsp.h | 1 + sound/soc/intel/skylake/skl-sst-ipc.c | 66 ++++++++++++++++++++++----------- sound/soc/intel/skylake/skl-sst-ipc.h | 5 +++ sound/soc/intel/skylake/skl-sst.c | 53 ++++++++++++++++++++------ 6 files changed, 110 insertions(+), 43 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/intel/skylake/skl-sst-cldma.c b/sound/soc/intel/skylake/skl-sst-cldma.c index c9f6d87381db..d2b1d60fec02 100644 --- a/sound/soc/intel/skylake/skl-sst-cldma.c +++ b/sound/soc/intel/skylake/skl-sst-cldma.c @@ -164,7 +164,7 @@ static void skl_cldma_cleanup(struct sst_dsp *ctx) ctx->dsp_ops.free_dma_buf(ctx->dev, &ctx->cl_dev.dmab_bdl); } -static int skl_cldma_wait_interruptible(struct sst_dsp *ctx) +int skl_cldma_wait_interruptible(struct sst_dsp *ctx) { int ret = 0; @@ -243,9 +243,14 @@ static void skl_cldma_fill_buffer(struct sst_dsp *ctx, unsigned int size, * 2. Polling on fw register to identify if data left to transferred doesn't * fill the ring buffer. Caller takes care of polling the required status * register to identify the transfer status. + * 3. if wait flag is set, waits for DBL interrupt to copy the next chunk till + * bytes_left is 0. + * if wait flag is not set, doesn't wait for BDL interrupt. after ccopying + * the first chunk return the no of bytes_left to be copied. */ static int -skl_cldma_copy_to_buf(struct sst_dsp *ctx, const void *bin, u32 total_size) +skl_cldma_copy_to_buf(struct sst_dsp *ctx, const void *bin, + u32 total_size, bool wait) { int ret = 0; bool start = true; @@ -272,13 +277,14 @@ skl_cldma_copy_to_buf(struct sst_dsp *ctx, const void *bin, u32 total_size) size = ctx->cl_dev.bufsize; skl_cldma_fill_buffer(ctx, size, curr_pos, true, start); - start = false; - ret = skl_cldma_wait_interruptible(ctx); - if (ret < 0) { - skl_cldma_stop(ctx); - return ret; + if (wait) { + start = false; + ret = skl_cldma_wait_interruptible(ctx); + if (ret < 0) { + skl_cldma_stop(ctx); + return ret; + } } - } else { skl_cldma_int_disable(ctx); @@ -298,9 +304,11 @@ skl_cldma_copy_to_buf(struct sst_dsp *ctx, const void *bin, u32 total_size) } bytes_left -= size; curr_pos = curr_pos + size; + if (!wait) + return bytes_left; } - return ret; + return bytes_left; } void skl_cldma_process_intr(struct sst_dsp *ctx) diff --git a/sound/soc/intel/skylake/skl-sst-cldma.h b/sound/soc/intel/skylake/skl-sst-cldma.h index 99e4c86b6358..5b730a1a0ae4 100644 --- a/sound/soc/intel/skylake/skl-sst-cldma.h +++ b/sound/soc/intel/skylake/skl-sst-cldma.h @@ -213,7 +213,7 @@ struct skl_cl_dev_ops { void (*cl_trigger)(struct sst_dsp *ctx, bool enable); void (*cl_cleanup_controller)(struct sst_dsp *ctx); int (*cl_copy_to_dmabuf)(struct sst_dsp *ctx, - const void *bin, u32 size); + const void *bin, u32 size, bool wait); void (*cl_stop_dma)(struct sst_dsp *ctx); }; diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h index e8d1e149e0cd..5d7a93aa5bed 100644 --- a/sound/soc/intel/skylake/skl-sst-dsp.h +++ b/sound/soc/intel/skylake/skl-sst-dsp.h @@ -186,6 +186,7 @@ struct skl_module_table { void skl_cldma_process_intr(struct sst_dsp *ctx); void skl_cldma_int_disable(struct sst_dsp *ctx); int skl_cldma_prepare(struct sst_dsp *ctx); +int skl_cldma_wait_interruptible(struct sst_dsp *ctx); void skl_dsp_set_state_locked(struct sst_dsp *ctx, int state); struct sst_dsp *skl_dsp_ctx_init(struct device *dev, diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c index e1391dfbc9e9..e90fe2c0bf2c 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.c +++ b/sound/soc/intel/skylake/skl-sst-ipc.c @@ -34,6 +34,11 @@ #define IPC_GLB_REPLY_STATUS_MASK ((0x1 << IPC_GLB_REPLY_STATUS_SHIFT) - 1) #define IPC_GLB_REPLY_STATUS(x) ((x) << IPC_GLB_REPLY_STATUS_SHIFT) +#define IPC_GLB_REPLY_TYPE_SHIFT 29 +#define IPC_GLB_REPLY_TYPE_MASK 0x1F +#define IPC_GLB_REPLY_TYPE(x) (((x) >> IPC_GLB_REPLY_TYPE_SHIFT) \ + & IPC_GLB_RPLY_TYPE_MASK) + #define IPC_TIMEOUT_MSECS 3000 #define IPC_EMPTY_LIST_SIZE 8 @@ -387,12 +392,27 @@ static int skl_ipc_process_notification(struct sst_generic_ipc *ipc, return 0; } +static int skl_ipc_set_reply_error_code(u32 reply) +{ + switch (reply) { + case IPC_GLB_REPLY_OUT_OF_MEMORY: + return -ENOMEM; + + case IPC_GLB_REPLY_BUSY: + return -EBUSY; + + default: + return -EINVAL; + } +} + static void skl_ipc_process_reply(struct sst_generic_ipc *ipc, struct skl_ipc_header header) { struct ipc_message *msg; u32 reply = header.primary & IPC_GLB_REPLY_STATUS_MASK; u64 *ipc_header = (u64 *)(&header); + struct skl_sst *skl = container_of(ipc, struct skl_sst, ipc); msg = skl_ipc_reply_get_msg(ipc, *ipc_header); if (msg == NULL) { @@ -401,33 +421,37 @@ static void skl_ipc_process_reply(struct sst_generic_ipc *ipc, } /* first process the header */ - switch (reply) { - case IPC_GLB_REPLY_SUCCESS: + if (reply == IPC_GLB_REPLY_SUCCESS) { dev_dbg(ipc->dev, "ipc FW reply %x: success\n", header.primary); /* copy the rx data from the mailbox */ sst_dsp_inbox_read(ipc->dsp, msg->rx_data, msg->rx_size); - break; - - case IPC_GLB_REPLY_OUT_OF_MEMORY: - dev_err(ipc->dev, "ipc fw reply: %x: no memory\n", header.primary); - msg->errno = -ENOMEM; - break; - - case IPC_GLB_REPLY_BUSY: - dev_err(ipc->dev, "ipc fw reply: %x: Busy\n", header.primary); - msg->errno = -EBUSY; - break; + switch (IPC_GLB_NOTIFY_MSG_TYPE(header.primary)) { + case IPC_GLB_LOAD_MULTIPLE_MODS: + skl->mod_load_complete = true; + skl->mod_load_status = true; + wake_up(&skl->mod_load_wait); + break; - default: - dev_err(ipc->dev, "Unknown ipc reply: 0x%x\n", reply); - msg->errno = -EINVAL; - break; - } + default: + break; - if (reply != IPC_GLB_REPLY_SUCCESS) { + } + } else { + msg->errno = skl_ipc_set_reply_error_code(reply); dev_err(ipc->dev, "ipc FW reply: reply=%d\n", reply); dev_err(ipc->dev, "FW Error Code: %u\n", ipc->dsp->fw_ops.get_fw_errcode(ipc->dsp)); + switch (IPC_GLB_NOTIFY_MSG_TYPE(header.primary)) { + case IPC_GLB_LOAD_MULTIPLE_MODS: + skl->mod_load_complete = true; + skl->mod_load_status = false; + wake_up(&skl->mod_load_wait); + break; + + default: + break; + + } } list_del(&msg->list); @@ -811,8 +835,8 @@ int skl_ipc_load_modules(struct sst_generic_ipc *ipc, header.primary |= IPC_GLB_TYPE(IPC_GLB_LOAD_MULTIPLE_MODS); header.primary |= IPC_LOAD_MODULE_CNT(module_cnt); - ret = sst_ipc_tx_message_wait(ipc, *ipc_header, data, - (sizeof(u16) * module_cnt), NULL, 0); + ret = sst_ipc_tx_message_nowait(ipc, *ipc_header, data, + (sizeof(u16) * module_cnt)); if (ret < 0) dev_err(ipc->dev, "ipc: load modules failed :%d\n", ret); diff --git a/sound/soc/intel/skylake/skl-sst-ipc.h b/sound/soc/intel/skylake/skl-sst-ipc.h index 7d21f055328d..fc07c397b060 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.h +++ b/sound/soc/intel/skylake/skl-sst-ipc.h @@ -77,6 +77,11 @@ struct skl_sst { wait_queue_head_t boot_wait; bool boot_complete; + /* module load */ + wait_queue_head_t mod_load_wait; + bool mod_load_complete; + bool mod_load_status; + /* IPC messaging */ struct sst_generic_ipc ipc; diff --git a/sound/soc/intel/skylake/skl-sst.c b/sound/soc/intel/skylake/skl-sst.c index b30bd384c8d3..39d4aaac73bf 100644 --- a/sound/soc/intel/skylake/skl-sst.c +++ b/sound/soc/intel/skylake/skl-sst.c @@ -52,7 +52,8 @@ static int skl_transfer_firmware(struct sst_dsp *ctx, { int ret = 0; - ret = ctx->cl_dev.ops.cl_copy_to_dmabuf(ctx, basefw, base_fw_size); + ret = ctx->cl_dev.ops.cl_copy_to_dmabuf(ctx, basefw, base_fw_size, + true); if (ret < 0) return ret; @@ -323,22 +324,49 @@ static struct skl_module_table *skl_module_get_from_id( return NULL; } -static int skl_transfer_module(struct sst_dsp *ctx, - struct skl_load_module_info *module) +static int skl_transfer_module(struct sst_dsp *ctx, const void *data, + u32 size, u16 mod_id) { - int ret; + int ret, bytes_left, curr_pos; struct skl_sst *skl = ctx->thread_context; + skl->mod_load_complete = false; + init_waitqueue_head(&skl->mod_load_wait); - ret = ctx->cl_dev.ops.cl_copy_to_dmabuf(ctx, module->fw->data, - module->fw->size); - if (ret < 0) - return ret; + bytes_left = ctx->cl_dev.ops.cl_copy_to_dmabuf(ctx, data, size, false); + if (bytes_left < 0) + return bytes_left; - ret = skl_ipc_load_modules(&skl->ipc, SKL_NUM_MODULES, - (void *)&module->mod_id); - if (ret < 0) + ret = skl_ipc_load_modules(&skl->ipc, SKL_NUM_MODULES, &mod_id); + if (ret < 0) { dev_err(ctx->dev, "Failed to Load module: %d\n", ret); + goto out; + } + + /* + * if bytes_left > 0 then wait for BDL complete interrupt and + * copy the next chunk till bytes_left is 0. if bytes_left is + * is zero, then wait for load module IPC reply + */ + while (bytes_left > 0) { + curr_pos = size - bytes_left; + + ret = skl_cldma_wait_interruptible(ctx); + if (ret < 0) + goto out; + + bytes_left = ctx->cl_dev.ops.cl_copy_to_dmabuf(ctx, + data + curr_pos, + bytes_left, false); + } + + ret = wait_event_timeout(skl->mod_load_wait, skl->mod_load_complete, + msecs_to_jiffies(SKL_IPC_BOOT_MSECS)); + if (ret == 0 || !skl->mod_load_status) { + dev_err(ctx->dev, "Module Load failed\n"); + ret = -EIO; + } +out: ctx->cl_dev.ops.cl_stop_dma(ctx); return ret; @@ -365,7 +393,8 @@ static int skl_load_module(struct sst_dsp *ctx, u16 mod_id, u8 *guid) } if (!module_entry->usage_cnt) { - ret = skl_transfer_module(ctx, module_entry->mod_info); + ret = skl_transfer_module(ctx, module_entry->mod_info->fw->data, + module_entry->mod_info->fw->size, mod_id); if (ret < 0) { dev_err(ctx->dev, "Failed to Load module\n"); return ret; -- cgit v1.2.1 From bf3e5ef5d549f650c13bef2b2192057cfef33d38 Mon Sep 17 00:00:00 2001 From: Dharageswari R Date: Mon, 13 Mar 2017 22:11:32 +0530 Subject: ASoC: Intel: Skylake: Fix parameter overwrite for KPB Module KPB module default parameter were overwritten by the dynamic instance id once use case is executed. This will cause module crash from subsequent execution of use case as the updated parameters are used. So instead of over writing the default parameter, make a copy and update the module parameter and use this in IPC message. Signed-off-by: Dharageswari R Signed-off-by: Kranthikumar, GudishaX Signed-off-by: Jeeja KP Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-topology.c | 47 +++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 18 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index d4058d2a8023..c6bd4bb49ec0 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -678,26 +678,29 @@ static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, return 0; } -static int skl_fill_sink_instance_id(struct skl_sst *ctx, - struct skl_algo_data *alg_data) +static int skl_fill_sink_instance_id(struct skl_sst *ctx, u32 *params, + int size, struct skl_module_cfg *mcfg) { - struct skl_kpb_params *params = (struct skl_kpb_params *)alg_data->params; - struct skl_mod_inst_map *inst; int i, pvt_id; - inst = params->map; + if (mcfg->m_type == SKL_MODULE_TYPE_KPB) { + struct skl_kpb_params *kpb_params = + (struct skl_kpb_params *)params; + struct skl_mod_inst_map *inst = kpb_params->map; - for (i = 0; i < params->num_modules; i++) { - pvt_id = skl_get_pvt_instance_id_map(ctx, - inst->mod_id, inst->inst_id); - if (pvt_id < 0) - return -EINVAL; - inst->inst_id = pvt_id; - inst++; + for (i = 0; i < kpb_params->num_modules; i++) { + pvt_id = skl_get_pvt_instance_id_map(ctx, inst->mod_id, + inst->inst_id); + if (pvt_id < 0) + return -EINVAL; + + inst->inst_id = pvt_id; + inst++; + } } + return 0; } - /* * Some modules require params to be set after the module is bound to * all pins connected. @@ -714,6 +717,7 @@ static int skl_tplg_set_module_bind_params(struct snd_soc_dapm_widget *w, struct soc_bytes_ext *sb; struct skl_algo_data *bc; struct skl_specific_cfg *sp_cfg; + u32 *params; /* * check all out/in pins are in bind state. @@ -746,11 +750,18 @@ static int skl_tplg_set_module_bind_params(struct snd_soc_dapm_widget *w, bc = (struct skl_algo_data *)sb->dobj.private; if (bc->set_params == SKL_PARAM_BIND) { - if (mconfig->m_type == SKL_MODULE_TYPE_KPB) - skl_fill_sink_instance_id(ctx, bc); - ret = skl_set_module_params(ctx, - (u32 *)bc->params, bc->max, - bc->param_id, mconfig); + params = kzalloc(bc->max, GFP_KERNEL); + if (!params) + return -ENOMEM; + + memcpy(params, bc->params, bc->max); + skl_fill_sink_instance_id(ctx, params, bc->max, + mconfig); + + ret = skl_set_module_params(ctx, params, + bc->max, bc->param_id, mconfig); + kfree(params); + if (ret < 0) return ret; } -- cgit v1.2.1 From e54fde61715df828c2f06883a6eb756bb5d88006 Mon Sep 17 00:00:00 2001 From: Bryce Ferguson Date: Mon, 27 Feb 2017 08:17:42 -0600 Subject: ASoC: Add AU1761 audio codec as selectable option This commit adds the ADI AU1761 audio codec as a selectable option in the kernel config. Currently the driver can only be selected for ADI blackfin devices or if SND_SOC_ALL_CODECS is enabled. Signed-off-by: Bryce Ferguson Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 9e1718a8cb1c..71039982dae4 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -302,12 +302,14 @@ config SND_SOC_ADAU1761 select SND_SOC_ADAU17X1 config SND_SOC_ADAU1761_I2C - tristate + tristate "Analog Devices AU1761 CODEC - I2C" + depends on I2C select SND_SOC_ADAU1761 select REGMAP_I2C config SND_SOC_ADAU1761_SPI - tristate + tristate "Analog Devices AU1761 CODEC - SPI" + depends on SPI select SND_SOC_ADAU1761 select REGMAP_SPI -- cgit v1.2.1 From 3f48947d56ff3e42e2e490714025e984af817f5d Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Sun, 5 Mar 2017 21:36:58 +0800 Subject: ASoC: sun8i-codec-analog: split out mic2 Allwinner V3s features an analog codec without MIC2. Split out this part, in order to prepare for the V3s analog codec. Signed-off-by: Icenowy Zheng Acked-by: Chen-Yu Tsai Signed-off-by: Mark Brown --- sound/soc/sunxi/sun8i-codec-analog.c | 92 +++++++++++++++++++++++++++++------- 1 file changed, 76 insertions(+), 16 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sunxi/sun8i-codec-analog.c b/sound/soc/sunxi/sun8i-codec-analog.c index 72331332b72e..b95ff045cd7f 100644 --- a/sound/soc/sunxi/sun8i-codec-analog.c +++ b/sound/soc/sunxi/sun8i-codec-analog.c @@ -259,17 +259,11 @@ static const struct snd_kcontrol_new sun8i_codec_common_controls[] = { SOC_SINGLE_TLV("Mic1 Playback Volume", SUN8I_ADDA_MICIN_GCTRL, SUN8I_ADDA_MICIN_GCTRL_MIC1G, 0x7, 0, sun8i_codec_out_mixer_pregain_scale), - SOC_SINGLE_TLV("Mic2 Playback Volume", - SUN8I_ADDA_MICIN_GCTRL, SUN8I_ADDA_MICIN_GCTRL_MIC2G, - 0x7, 0, sun8i_codec_out_mixer_pregain_scale), - /* Microphone Amp boost gains */ + /* Microphone Amp boost gain */ SOC_SINGLE_TLV("Mic1 Boost Volume", SUN8I_ADDA_MIC1G_MICBIAS_CTRL, SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MIC1BOOST, 0x7, 0, sun8i_codec_mic_gain_scale), - SOC_SINGLE_TLV("Mic2 Boost Volume", SUN8I_ADDA_MIC2G_CTRL, - SUN8I_ADDA_MIC2G_CTRL_MIC2BOOST, 0x7, 0, - sun8i_codec_mic_gain_scale), /* ADC */ SOC_SINGLE_TLV("ADC Gain Capture Volume", SUN8I_ADDA_ADC_AP_EN, @@ -298,9 +292,8 @@ static const struct snd_soc_dapm_widget sun8i_codec_common_widgets[] = { /* Line In */ SND_SOC_DAPM_INPUT("LINEIN"), - /* Microphone inputs */ + /* Microphone input */ SND_SOC_DAPM_INPUT("MIC1"), - SND_SOC_DAPM_INPUT("MIC2"), /* Microphone Bias */ SND_SOC_DAPM_SUPPLY("MBIAS", SUN8I_ADDA_MIC1G_MICBIAS_CTRL, @@ -310,8 +303,6 @@ static const struct snd_soc_dapm_widget sun8i_codec_common_widgets[] = { /* Mic input path */ SND_SOC_DAPM_PGA("Mic1 Amplifier", SUN8I_ADDA_MIC1G_MICBIAS_CTRL, SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MIC1AMPEN, 0, NULL, 0), - SND_SOC_DAPM_PGA("Mic2 Amplifier", SUN8I_ADDA_MIC2G_CTRL, - SUN8I_ADDA_MIC2G_CTRL_MIC2AMPEN, 0, NULL, 0), /* Mixers */ SND_SOC_DAPM_MIXER("Left Mixer", SUN8I_ADDA_DAC_PA_SRC, @@ -335,35 +326,30 @@ static const struct snd_soc_dapm_widget sun8i_codec_common_widgets[] = { static const struct snd_soc_dapm_route sun8i_codec_common_routes[] = { /* Microphone Routes */ { "Mic1 Amplifier", NULL, "MIC1"}, - { "Mic2 Amplifier", NULL, "MIC2"}, /* Left Mixer Routes */ { "Left Mixer", "DAC Playback Switch", "Left DAC" }, { "Left Mixer", "DAC Reversed Playback Switch", "Right DAC" }, { "Left Mixer", "Line In Playback Switch", "LINEIN" }, { "Left Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" }, - { "Left Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" }, /* Right Mixer Routes */ { "Right Mixer", "DAC Playback Switch", "Right DAC" }, { "Right Mixer", "DAC Reversed Playback Switch", "Left DAC" }, { "Right Mixer", "Line In Playback Switch", "LINEIN" }, { "Right Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" }, - { "Right Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" }, /* Left ADC Mixer Routes */ { "Left ADC Mixer", "Mixer Capture Switch", "Left Mixer" }, { "Left ADC Mixer", "Mixer Reversed Capture Switch", "Right Mixer" }, { "Left ADC Mixer", "Line In Capture Switch", "LINEIN" }, { "Left ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" }, - { "Left ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" }, /* Right ADC Mixer Routes */ { "Right ADC Mixer", "Mixer Capture Switch", "Right Mixer" }, { "Right ADC Mixer", "Mixer Reversed Capture Switch", "Left Mixer" }, { "Right ADC Mixer", "Line In Capture Switch", "LINEIN" }, { "Right ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" }, - { "Right ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" }, /* ADC Routes */ { "Left ADC", NULL, "Left ADC Mixer" }, @@ -578,19 +564,87 @@ static int sun8i_codec_add_lineout(struct snd_soc_component *cmpnt) return 0; } +/* mic2 specific controls, widgets and routes */ +static const struct snd_kcontrol_new sun8i_codec_mic2_controls[] = { + /* Mixer pre-gain */ + SOC_SINGLE_TLV("Mic2 Playback Volume", + SUN8I_ADDA_MICIN_GCTRL, SUN8I_ADDA_MICIN_GCTRL_MIC2G, + 0x7, 0, sun8i_codec_out_mixer_pregain_scale), + + /* Microphone Amp boost gain */ + SOC_SINGLE_TLV("Mic2 Boost Volume", SUN8I_ADDA_MIC2G_CTRL, + SUN8I_ADDA_MIC2G_CTRL_MIC2BOOST, 0x7, 0, + sun8i_codec_mic_gain_scale), +}; + +static const struct snd_soc_dapm_widget sun8i_codec_mic2_widgets[] = { + /* Microphone input */ + SND_SOC_DAPM_INPUT("MIC2"), + + /* Mic input path */ + SND_SOC_DAPM_PGA("Mic2 Amplifier", SUN8I_ADDA_MIC2G_CTRL, + SUN8I_ADDA_MIC2G_CTRL_MIC2AMPEN, 0, NULL, 0), +}; + +static const struct snd_soc_dapm_route sun8i_codec_mic2_routes[] = { + { "Mic2 Amplifier", NULL, "MIC2"}, + + { "Left Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" }, + + { "Right Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" }, + + { "Left ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" }, + + { "Right ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" }, +}; + +static int sun8i_codec_add_mic2(struct snd_soc_component *cmpnt) +{ + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt); + struct device *dev = cmpnt->dev; + int ret; + + ret = snd_soc_add_component_controls(cmpnt, + sun8i_codec_mic2_controls, + ARRAY_SIZE(sun8i_codec_mic2_controls)); + if (ret) { + dev_err(dev, "Failed to add MIC2 controls: %d\n", ret); + return ret; + } + + ret = snd_soc_dapm_new_controls(dapm, sun8i_codec_mic2_widgets, + ARRAY_SIZE(sun8i_codec_mic2_widgets)); + if (ret) { + dev_err(dev, "Failed to add MIC2 DAPM widgets: %d\n", ret); + return ret; + } + + ret = snd_soc_dapm_add_routes(dapm, sun8i_codec_mic2_routes, + ARRAY_SIZE(sun8i_codec_mic2_routes)); + if (ret) { + dev_err(dev, "Failed to add MIC2 DAPM routes: %d\n", ret); + return ret; + } + + return 0; +} + struct sun8i_codec_analog_quirks { bool has_headphone; bool has_hmic; bool has_lineout; + bool has_mic2; }; static const struct sun8i_codec_analog_quirks sun8i_a23_quirks = { .has_headphone = true, .has_hmic = true, + .has_mic2 = true, }; static const struct sun8i_codec_analog_quirks sun8i_h3_quirks = { .has_lineout = true, + .has_mic2 = true, }; static int sun8i_codec_analog_cmpnt_probe(struct snd_soc_component *cmpnt) @@ -626,6 +680,12 @@ static int sun8i_codec_analog_cmpnt_probe(struct snd_soc_component *cmpnt) return ret; } + if (quirks->has_mic2) { + ret = sun8i_codec_add_mic2(cmpnt); + if (ret) + return ret; + } + return 0; } -- cgit v1.2.1 From 6ff4eb7e5d8aa4e5f4d6eb22be1deaae735de92c Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Sun, 5 Mar 2017 21:36:59 +0800 Subject: ASoC: sun8i-codec-analog: split out line in Allwinner V3s features an analog codec without LINEIN. Split out this part, in order to prepare for the V3s analog codec. Signed-off-by: Icenowy Zheng Acked-by: Chen-Yu Tsai Signed-off-by: Mark Brown --- sound/soc/sunxi/sun8i-codec-analog.c | 76 ++++++++++++++++++++++++++++++------ 1 file changed, 65 insertions(+), 11 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sunxi/sun8i-codec-analog.c b/sound/soc/sunxi/sun8i-codec-analog.c index b95ff045cd7f..6c17c99c2c8d 100644 --- a/sound/soc/sunxi/sun8i-codec-analog.c +++ b/sound/soc/sunxi/sun8i-codec-analog.c @@ -252,10 +252,7 @@ static const DECLARE_TLV_DB_RANGE(sun8i_codec_mic_gain_scale, ); static const struct snd_kcontrol_new sun8i_codec_common_controls[] = { - /* Mixer pre-gains */ - SOC_SINGLE_TLV("Line In Playback Volume", SUN8I_ADDA_LINEIN_GCTRL, - SUN8I_ADDA_LINEIN_GCTRL_LINEING, - 0x7, 0, sun8i_codec_out_mixer_pregain_scale), + /* Mixer pre-gain */ SOC_SINGLE_TLV("Mic1 Playback Volume", SUN8I_ADDA_MICIN_GCTRL, SUN8I_ADDA_MICIN_GCTRL_MIC1G, 0x7, 0, sun8i_codec_out_mixer_pregain_scale), @@ -289,9 +286,6 @@ static const struct snd_soc_dapm_widget sun8i_codec_common_widgets[] = { * stream widgets at the card level. */ - /* Line In */ - SND_SOC_DAPM_INPUT("LINEIN"), - /* Microphone input */ SND_SOC_DAPM_INPUT("MIC1"), @@ -330,25 +324,21 @@ static const struct snd_soc_dapm_route sun8i_codec_common_routes[] = { /* Left Mixer Routes */ { "Left Mixer", "DAC Playback Switch", "Left DAC" }, { "Left Mixer", "DAC Reversed Playback Switch", "Right DAC" }, - { "Left Mixer", "Line In Playback Switch", "LINEIN" }, { "Left Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" }, /* Right Mixer Routes */ { "Right Mixer", "DAC Playback Switch", "Right DAC" }, { "Right Mixer", "DAC Reversed Playback Switch", "Left DAC" }, - { "Right Mixer", "Line In Playback Switch", "LINEIN" }, { "Right Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" }, /* Left ADC Mixer Routes */ { "Left ADC Mixer", "Mixer Capture Switch", "Left Mixer" }, { "Left ADC Mixer", "Mixer Reversed Capture Switch", "Right Mixer" }, - { "Left ADC Mixer", "Line In Capture Switch", "LINEIN" }, { "Left ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" }, /* Right ADC Mixer Routes */ { "Right ADC Mixer", "Mixer Capture Switch", "Right Mixer" }, { "Right ADC Mixer", "Mixer Reversed Capture Switch", "Left Mixer" }, - { "Right ADC Mixer", "Line In Capture Switch", "LINEIN" }, { "Right ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" }, /* ADC Routes */ @@ -484,6 +474,61 @@ static int sun8i_codec_add_hmic(struct snd_soc_component *cmpnt) return ret; } +/* line in specific controls, widgets and rines */ +static const struct snd_kcontrol_new sun8i_codec_linein_controls[] = { + /* Mixer pre-gain */ + SOC_SINGLE_TLV("Line In Playback Volume", SUN8I_ADDA_LINEIN_GCTRL, + SUN8I_ADDA_LINEIN_GCTRL_LINEING, + 0x7, 0, sun8i_codec_out_mixer_pregain_scale), +}; + +static const struct snd_soc_dapm_widget sun8i_codec_linein_widgets[] = { + /* Line input */ + SND_SOC_DAPM_INPUT("LINEIN"), +}; + +static const struct snd_soc_dapm_route sun8i_codec_linein_routes[] = { + { "Left Mixer", "Line In Playback Switch", "LINEIN" }, + + { "Right Mixer", "Line In Playback Switch", "LINEIN" }, + + { "Left ADC Mixer", "Line In Capture Switch", "LINEIN" }, + + { "Right ADC Mixer", "Line In Capture Switch", "LINEIN" }, +}; + +static int sun8i_codec_add_linein(struct snd_soc_component *cmpnt) +{ + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt); + struct device *dev = cmpnt->dev; + int ret; + + ret = snd_soc_add_component_controls(cmpnt, + sun8i_codec_linein_controls, + ARRAY_SIZE(sun8i_codec_linein_controls)); + if (ret) { + dev_err(dev, "Failed to add Line In controls: %d\n", ret); + return ret; + } + + ret = snd_soc_dapm_new_controls(dapm, sun8i_codec_linein_widgets, + ARRAY_SIZE(sun8i_codec_linein_widgets)); + if (ret) { + dev_err(dev, "Failed to add Line In DAPM widgets: %d\n", ret); + return ret; + } + + ret = snd_soc_dapm_add_routes(dapm, sun8i_codec_linein_routes, + ARRAY_SIZE(sun8i_codec_linein_routes)); + if (ret) { + dev_err(dev, "Failed to add Line In DAPM routes: %d\n", ret); + return ret; + } + + return 0; +} + + /* line out specific controls, widgets and routes */ static const DECLARE_TLV_DB_RANGE(sun8i_codec_lineout_vol_scale, 0, 1, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1), @@ -632,6 +677,7 @@ static int sun8i_codec_add_mic2(struct snd_soc_component *cmpnt) struct sun8i_codec_analog_quirks { bool has_headphone; bool has_hmic; + bool has_linein; bool has_lineout; bool has_mic2; }; @@ -639,10 +685,12 @@ struct sun8i_codec_analog_quirks { static const struct sun8i_codec_analog_quirks sun8i_a23_quirks = { .has_headphone = true, .has_hmic = true, + .has_linein = true, .has_mic2 = true, }; static const struct sun8i_codec_analog_quirks sun8i_h3_quirks = { + .has_linein = true, .has_lineout = true, .has_mic2 = true, }; @@ -674,6 +722,12 @@ static int sun8i_codec_analog_cmpnt_probe(struct snd_soc_component *cmpnt) return ret; } + if (quirks->has_linein) { + ret = sun8i_codec_add_linein(cmpnt); + if (ret) + return ret; + } + if (quirks->has_lineout) { ret = sun8i_codec_add_lineout(cmpnt); if (ret) -- cgit v1.2.1 From 80405d44c3721c775f5c508f0cdbcc0e8498eeef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Myl=C3=A8ne=20Josserand?= Date: Thu, 9 Mar 2017 10:56:00 +0100 Subject: ASoC: sun8i-codec: Fix space on audio-routing widget MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit An unwanted space is present in an audio widget's name on the dapm routing. It causes an error on the recognition of this widget (error: ("no dapm match for AIF1 Slot 0 Right"). Remove the space fixes it. Signed-off-by: Mylène Josserand Signed-off-by: Mark Brown --- sound/soc/sunxi/sun8i-codec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c index a75a983974d9..90cda9569503 100644 --- a/sound/soc/sunxi/sun8i-codec.c +++ b/sound/soc/sunxi/sun8i-codec.c @@ -335,7 +335,7 @@ static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = { /* DAC Mixer Routes */ { "Left Digital DAC Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "Digital Left DAC"}, - { "Right Digital DAC Mixer", "AIF1 Slot 0 Digital DAC Playback Switch ", + { "Right Digital DAC Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "Digital Right DAC"}, }; -- cgit v1.2.1 From 9123aa8645463ca30ac8c62a07eb23e07c3aa091 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Myl=C3=A8ne=20Josserand?= Date: Thu, 9 Mar 2017 10:56:01 +0100 Subject: ASoC: sun8i-codec: Convert to use SND_SOC_DAPM_AIF_IN MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update the driver to use SND_SOC_DAPM_AIF_IN instead of SND_SOC_DAPM_DAC. Rename the interface's widgets to be more precise on which slot the interface is connected. Signed-off-by: Mylène Josserand Signed-off-by: Mark Brown --- sound/soc/sunxi/sun8i-codec.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c index 90cda9569503..5723c3404f6b 100644 --- a/sound/soc/sunxi/sun8i-codec.c +++ b/sound/soc/sunxi/sun8i-codec.c @@ -281,11 +281,13 @@ static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("DAC", SUN8I_DAC_DIG_CTRL, SUN8I_DAC_DIG_CTRL_ENDA, 0, NULL, 0), - /* Analog DAC */ - SND_SOC_DAPM_DAC("Digital Left DAC", "Playback", SUN8I_AIF1_DACDAT_CTRL, - SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_ENA, 0), - SND_SOC_DAPM_DAC("Digital Right DAC", "Playback", SUN8I_AIF1_DACDAT_CTRL, - SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_ENA, 0), + /* Analog DAC AIF */ + SND_SOC_DAPM_AIF_IN("AIF1 Slot 0 Left", "Playback", 0, + SUN8I_AIF1_DACDAT_CTRL, + SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_ENA, 0), + SND_SOC_DAPM_AIF_IN("AIF1 Slot 0 Right", "Playback", 0, + SUN8I_AIF1_DACDAT_CTRL, + SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_ENA, 0), /* DAC Mixers */ SOC_MIXER_ARRAY("Left Digital DAC Mixer", SND_SOC_NOPM, 0, 0, @@ -329,14 +331,14 @@ static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = { { "DAC", NULL, "MODCLK DAC" }, /* DAC Routes */ - { "Digital Left DAC", NULL, "DAC" }, - { "Digital Right DAC", NULL, "DAC" }, + { "AIF1 Slot 0 Right", NULL, "DAC" }, + { "AIF1 Slot 0 Left", NULL, "DAC" }, /* DAC Mixer Routes */ { "Left Digital DAC Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", - "Digital Left DAC"}, + "AIF1 Slot 0 Left"}, { "Right Digital DAC Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", - "Digital Right DAC"}, + "AIF1 Slot 0 Right"}, }; static struct snd_soc_dai_ops sun8i_codec_dai_ops = { -- cgit v1.2.1 From 9b5d3865b3b410d21213807642b47e84a3fc081b Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Thu, 16 Mar 2017 13:58:41 +0800 Subject: ASoC: rt5665: set i2s pin share configuration I2S2 and I2S3 are share pins. We need to configure it when i2s is active and disable it when i2s is inactive. To disable i2s pins means to set them as gpio. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5665.c | 58 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 55 insertions(+), 3 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c index 1d00c6078feb..5545d084b0b6 100644 --- a/sound/soc/codecs/rt5665.c +++ b/sound/soc/codecs/rt5665.c @@ -2604,6 +2604,55 @@ static int rt5655_set_verf(struct snd_soc_dapm_widget *w, return 0; } +static int rt5665_i2s_pin_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); + unsigned int val1, val2, mask1, mask2 = 0; + + switch (w->shift) { + case RT5665_PWR_I2S2_1_BIT: + mask1 = RT5665_GP2_PIN_MASK | RT5665_GP3_PIN_MASK | + RT5665_GP4_PIN_MASK | RT5665_GP5_PIN_MASK; + val1 = RT5665_GP2_PIN_BCLK2 | RT5665_GP3_PIN_LRCK2 | + RT5665_GP4_PIN_DACDAT2_1 | RT5665_GP5_PIN_ADCDAT2_1; + break; + case RT5665_PWR_I2S2_2_BIT: + mask1 = RT5665_GP2_PIN_MASK | RT5665_GP3_PIN_MASK | + RT5665_GP8_PIN_MASK; + val1 = RT5665_GP2_PIN_BCLK2 | RT5665_GP3_PIN_LRCK2 | + RT5665_GP8_PIN_DACDAT2_2; + mask2 = RT5665_GP9_PIN_MASK; + val2 = RT5665_GP9_PIN_ADCDAT2_2; + break; + case RT5665_PWR_I2S3_BIT: + mask1 = RT5665_GP6_PIN_MASK | RT5665_GP7_PIN_MASK | + RT5665_GP8_PIN_MASK; + val1 = RT5665_GP6_PIN_BCLK3 | RT5665_GP7_PIN_LRCK3 | + RT5665_GP8_PIN_DACDAT3; + mask2 = RT5665_GP9_PIN_MASK; + val2 = RT5665_GP9_PIN_ADCDAT3; + break; + } + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_update_bits(codec, RT5665_GPIO_CTRL_1, mask1, val1); + if (mask2) + snd_soc_update_bits(codec, RT5665_GPIO_CTRL_2, + mask2, val2); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_update_bits(codec, RT5665_GPIO_CTRL_1, mask1, 0); + if (mask2) + snd_soc_update_bits(codec, RT5665_GPIO_CTRL_2, + mask2, 0); + break; + default: + return 0; + } + + return 0; +} static const struct snd_soc_dapm_widget rt5665_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("LDO2", RT5665_PWR_ANLG_3, RT5665_PWR_LDO2_BIT, 0, @@ -2856,11 +2905,14 @@ static const struct snd_soc_dapm_widget rt5665_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("I2S1_2", RT5665_PWR_DIG_1, RT5665_PWR_I2S1_2_BIT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("I2S2_1", RT5665_PWR_DIG_1, RT5665_PWR_I2S2_1_BIT, - 0, NULL, 0), + 0, rt5665_i2s_pin_event, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_SUPPLY("I2S2_2", RT5665_PWR_DIG_1, RT5665_PWR_I2S2_2_BIT, - 0, NULL, 0), + 0, rt5665_i2s_pin_event, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_SUPPLY("I2S3", RT5665_PWR_DIG_1, RT5665_PWR_I2S3_BIT, - 0, NULL, 0), + 0, rt5665_i2s_pin_event, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_PGA("IF1 DAC1", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_PGA("IF1 DAC2", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_PGA("IF1 DAC3", SND_SOC_NOPM, 0, 0, NULL, 0), -- cgit v1.2.1 From dcee9bfe8904518266c95d44a4f435a5f1fa59a1 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Mar 2017 04:43:21 +0000 Subject: ASoC: simple-card: use defined dev on probe() Current asoc_simple_card_probe() already has dev definition, but some place doesn't use it. Let's fix this issue. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index a385ff6bfa4b..9ad05e237ee0 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -418,8 +418,8 @@ static int asoc_simple_card_probe(struct platform_device *pdev) struct simple_card_data *priv; struct snd_soc_dai_link *dai_link; struct simple_dai_props *dai_props; - struct device_node *np = pdev->dev.of_node; struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; int num, ret; /* Get the number of DAI links */ @@ -491,7 +491,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev) snd_soc_card_set_drvdata(&priv->snd_card, priv); - ret = devm_snd_soc_register_card(&pdev->dev, &priv->snd_card); + ret = devm_snd_soc_register_card(dev, &priv->snd_card); if (ret >= 0) return ret; err: -- cgit v1.2.1 From 40b68dac75a1d16266d3c89244ccf7b899afac3e Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Mar 2017 04:43:40 +0000 Subject: ASoC: simple-scu-card: use defined dev on probe() Current asoc_simple_card_probe() already has dev definition, but some place doesn't use it. Let's fix this issue. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-scu-card.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/generic/simple-scu-card.c b/sound/soc/generic/simple-scu-card.c index bb86ee042490..93d7d8980cd5 100644 --- a/sound/soc/generic/simple-scu-card.c +++ b/sound/soc/generic/simple-scu-card.c @@ -257,7 +257,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev) struct snd_soc_dai_link *dai_link; struct asoc_simple_dai *dai_props; struct device *dev = &pdev->dev; - struct device_node *np = pdev->dev.of_node; + struct device_node *np = dev->of_node; int num, ret; /* Allocate the private data */ @@ -292,7 +292,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev) snd_soc_card_set_drvdata(&priv->snd_card, priv); - ret = devm_snd_soc_register_card(&pdev->dev, &priv->snd_card); + ret = devm_snd_soc_register_card(dev, &priv->snd_card); if (ret >= 0) return ret; err: -- cgit v1.2.1 From 5be509576cf634ad384025f50fc4fcb941d14256 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Mar 2017 04:44:00 +0000 Subject: ASoC: simple-card: add new simple_priv_to_card() macro Current simple card driver is directly calling priv->snd_card everywhere, but it makes unreadable code. Let's use simple_priv_to_card() macro for it Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 41 +++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 9ad05e237ee0..948f3ba02d12 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -40,9 +40,10 @@ struct simple_card_data { struct snd_soc_dai_link *dai_link; }; -#define simple_priv_to_dev(priv) ((priv)->snd_card.dev) -#define simple_priv_to_link(priv, i) ((priv)->snd_card.dai_link + (i)) +#define simple_priv_to_card(priv) (&(priv)->snd_card) #define simple_priv_to_props(priv, i) ((priv)->dai_props + (i)) +#define simple_priv_to_dev(priv) (simple_priv_to_card(priv)->dev) +#define simple_priv_to_link(priv, i) (simple_priv_to_card(priv)->dai_link + (i)) #define DAI "sound-dai" #define CELL "#sound-dai-cells" @@ -323,6 +324,7 @@ static int asoc_simple_card_parse_aux_devs(struct device_node *node, { struct device *dev = simple_priv_to_dev(priv); struct device_node *aux_node; + struct snd_soc_card *card = simple_priv_to_card(priv); int i, n, len; if (!of_find_property(node, PREFIX "aux-devs", &len)) @@ -332,19 +334,19 @@ static int asoc_simple_card_parse_aux_devs(struct device_node *node, if (n <= 0) return -EINVAL; - priv->snd_card.aux_dev = devm_kzalloc(dev, - n * sizeof(*priv->snd_card.aux_dev), GFP_KERNEL); - if (!priv->snd_card.aux_dev) + card->aux_dev = devm_kzalloc(dev, + n * sizeof(*card->aux_dev), GFP_KERNEL); + if (!card->aux_dev) return -ENOMEM; for (i = 0; i < n; i++) { aux_node = of_parse_phandle(node, PREFIX "aux-devs", i); if (!aux_node) return -EINVAL; - priv->snd_card.aux_dev[i].codec_of_node = aux_node; + card->aux_dev[i].codec_of_node = aux_node; } - priv->snd_card.num_aux_devs = n; + card->num_aux_devs = n; return 0; } @@ -352,6 +354,7 @@ static int asoc_simple_card_parse_of(struct device_node *node, struct simple_card_data *priv) { struct device *dev = simple_priv_to_dev(priv); + struct snd_soc_card *card = simple_priv_to_card(priv); struct device_node *dai_link; int ret; @@ -362,7 +365,7 @@ static int asoc_simple_card_parse_of(struct device_node *node, /* The off-codec widgets */ if (of_property_read_bool(node, PREFIX "widgets")) { - ret = snd_soc_of_parse_audio_simple_widgets(&priv->snd_card, + ret = snd_soc_of_parse_audio_simple_widgets(card, PREFIX "widgets"); if (ret) goto card_parse_end; @@ -370,7 +373,7 @@ static int asoc_simple_card_parse_of(struct device_node *node, /* DAPM routes */ if (of_property_read_bool(node, PREFIX "routing")) { - ret = snd_soc_of_parse_audio_routing(&priv->snd_card, + ret = snd_soc_of_parse_audio_routing(card, PREFIX "routing"); if (ret) goto card_parse_end; @@ -401,7 +404,7 @@ static int asoc_simple_card_parse_of(struct device_node *node, goto card_parse_end; } - ret = asoc_simple_card_parse_card_name(&priv->snd_card, PREFIX); + ret = asoc_simple_card_parse_card_name(card, PREFIX); if (ret < 0) goto card_parse_end; @@ -420,6 +423,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev) struct simple_dai_props *dai_props; struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; + struct snd_soc_card *card; int num, ret; /* Get the number of DAI links */ @@ -442,10 +446,11 @@ static int asoc_simple_card_probe(struct platform_device *pdev) priv->dai_link = dai_link; /* Init snd_soc_card */ - priv->snd_card.owner = THIS_MODULE; - priv->snd_card.dev = dev; - priv->snd_card.dai_link = priv->dai_link; - priv->snd_card.num_links = num; + card = simple_priv_to_card(priv); + card->owner = THIS_MODULE; + card->dev = dev; + card->dai_link = priv->dai_link; + card->num_links = num; if (np && of_device_is_available(np)) { @@ -474,7 +479,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev) return -EINVAL; } - priv->snd_card.name = (cinfo->card) ? cinfo->card : cinfo->name; + card->name = (cinfo->card) ? cinfo->card : cinfo->name; dai_link->name = cinfo->name; dai_link->stream_name = cinfo->name; dai_link->platform_name = cinfo->platform; @@ -489,13 +494,13 @@ static int asoc_simple_card_probe(struct platform_device *pdev) sizeof(priv->dai_props->codec_dai)); } - snd_soc_card_set_drvdata(&priv->snd_card, priv); + snd_soc_card_set_drvdata(card, priv); - ret = devm_snd_soc_register_card(dev, &priv->snd_card); + ret = devm_snd_soc_register_card(dev, card); if (ret >= 0) return ret; err: - asoc_simple_card_clean_reference(&priv->snd_card); + asoc_simple_card_clean_reference(card); return ret; } -- cgit v1.2.1 From d27f3b4a2d81e873de4d11899e510a1a507da8e3 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Mar 2017 04:44:16 +0000 Subject: ASoC: simple-scu-card: add new simple_priv_to_card() macro Current simple card driver is directly calling priv->snd_card everywhere, but it makes unreadable code. Let's use simple_priv_to_card() macro for it Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-scu-card.c | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/generic/simple-scu-card.c b/sound/soc/generic/simple-scu-card.c index 93d7d8980cd5..cd0f3f50eebf 100644 --- a/sound/soc/generic/simple-scu-card.c +++ b/sound/soc/generic/simple-scu-card.c @@ -31,9 +31,10 @@ struct simple_card_data { u32 convert_channels; }; -#define simple_priv_to_dev(priv) ((priv)->snd_card.dev) -#define simple_priv_to_link(priv, i) ((priv)->snd_card.dai_link + (i)) +#define simple_priv_to_card(priv) (&(priv)->snd_card) #define simple_priv_to_props(priv, i) ((priv)->dai_props + (i)) +#define simple_priv_to_dev(priv) (simple_priv_to_card(priv)->dev) +#define simple_priv_to_link(priv, i) (simple_priv_to_card(priv)->dai_link + (i)) #define DAI "sound-dai" #define CELL "#sound-dai-cells" @@ -109,6 +110,7 @@ static int asoc_simple_card_dai_link_of(struct device_node *np, struct device *dev = simple_priv_to_dev(priv); struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx); struct asoc_simple_dai *dai_props = simple_priv_to_props(priv, idx); + struct snd_soc_card *card = simple_priv_to_card(priv); int ret; if (is_fe) { @@ -163,7 +165,7 @@ static int asoc_simple_card_dai_link_of(struct device_node *np, if (ret < 0) return ret; - snd_soc_of_parse_audio_prefix(&priv->snd_card, + snd_soc_of_parse_audio_prefix(card, &priv->codec_conf, dai_link->codec_of_node, PREFIX "prefix"); @@ -201,6 +203,7 @@ static int asoc_simple_card_parse_of(struct device_node *node, { struct device *dev = simple_priv_to_dev(priv); struct device_node *np; + struct snd_soc_card *card = simple_priv_to_card(priv); unsigned int daifmt = 0; bool is_fe; int ret, i; @@ -208,7 +211,7 @@ static int asoc_simple_card_parse_of(struct device_node *node, if (!node) return -EINVAL; - ret = snd_soc_of_parse_audio_routing(&priv->snd_card, PREFIX "routing"); + ret = snd_soc_of_parse_audio_routing(card, PREFIX "routing"); if (ret < 0) return ret; @@ -239,12 +242,12 @@ static int asoc_simple_card_parse_of(struct device_node *node, i++; } - ret = asoc_simple_card_parse_card_name(&priv->snd_card, PREFIX); + ret = asoc_simple_card_parse_card_name(card, PREFIX); if (ret < 0) return ret; dev_dbg(dev, "New card: %s\n", - priv->snd_card.name ? priv->snd_card.name : ""); + card->name ? card->name : ""); dev_dbg(dev, "convert_rate %d\n", priv->convert_rate); dev_dbg(dev, "convert_channels %d\n", priv->convert_channels); @@ -256,6 +259,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev) struct simple_card_data *priv; struct snd_soc_dai_link *dai_link; struct asoc_simple_dai *dai_props; + struct snd_soc_card *card; struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; int num, ret; @@ -276,12 +280,13 @@ static int asoc_simple_card_probe(struct platform_device *pdev) priv->dai_link = dai_link; /* Init snd_soc_card */ - priv->snd_card.owner = THIS_MODULE; - priv->snd_card.dev = dev; - priv->snd_card.dai_link = priv->dai_link; - priv->snd_card.num_links = num; - priv->snd_card.codec_conf = &priv->codec_conf; - priv->snd_card.num_configs = 1; + card = simple_priv_to_card(priv); + card->owner = THIS_MODULE; + card->dev = dev; + card->dai_link = priv->dai_link; + card->num_links = num; + card->codec_conf = &priv->codec_conf; + card->num_configs = 1; ret = asoc_simple_card_parse_of(np, priv); if (ret < 0) { @@ -290,13 +295,13 @@ static int asoc_simple_card_probe(struct platform_device *pdev) goto err; } - snd_soc_card_set_drvdata(&priv->snd_card, priv); + snd_soc_card_set_drvdata(card, priv); - ret = devm_snd_soc_register_card(dev, &priv->snd_card); + ret = devm_snd_soc_register_card(dev, card); if (ret >= 0) return ret; err: - asoc_simple_card_clean_reference(&priv->snd_card); + asoc_simple_card_clean_reference(card); return ret; } -- cgit v1.2.1 From 5d3d0ad688eacf9567d7d67a5eec3c436cc1064c Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Fri, 17 Mar 2017 15:44:55 +0000 Subject: ASoC: cs35l35: Stash dev pointer directly rather than CODEC pointer The driver stashes a CODEC pointer in the cs35l35_private structure, which is used to obtain a struct device pointer for error messages in the interrupt handler. However, doing so is not very safe as the interrupt is registered, as it should be in bus probe, but the CODEC pointer can't be safely stored until the ASoC level probe. This leaves a window between the two probes where if any interrupts are received a NULL pointer will be deferenced in the IRQ handler. Fix this issue by saving a pointer to the device directly and passing that to the error messages in the interrupt handler rather than using the CODEC pointer to access the device pointer. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l35.c | 29 ++++++++++++++--------------- sound/soc/codecs/cs35l35.h | 2 +- 2 files changed, 15 insertions(+), 16 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/cs35l35.c b/sound/soc/codecs/cs35l35.c index 05117fca7e3c..1d9f332b2eec 100644 --- a/sound/soc/codecs/cs35l35.c +++ b/sound/soc/codecs/cs35l35.c @@ -741,8 +741,6 @@ static int cs35l35_codec_probe(struct snd_soc_codec *codec) struct monitor_cfg *monitor_config = &cs35l35->pdata.mon_cfg; int ret; - cs35l35->codec = codec; - /* Set Platform Data */ if (cs35l35->pdata.bst_vctl) regmap_update_bits(cs35l35->regmap, CS35L35_BST_CVTR_V_CTL, @@ -1004,7 +1002,6 @@ static struct regmap_config cs35l35_regmap = { static irqreturn_t cs35l35_irq(int irq, void *data) { struct cs35l35_private *cs35l35 = data; - struct snd_soc_codec *codec = cs35l35->codec; unsigned int sticky1, sticky2, sticky3, sticky4; unsigned int mask1, mask2, mask3, mask4, current1; @@ -1032,7 +1029,7 @@ static irqreturn_t cs35l35_irq(int irq, void *data) /* handle the interrupts */ if (sticky1 & CS35L35_CAL_ERR) { - dev_crit(codec->dev, "Calibration Error\n"); + dev_crit(cs35l35->dev, "Calibration Error\n"); /* error is no longer asserted; safe to reset */ if (!(current1 & CS35L35_CAL_ERR)) { @@ -1051,10 +1048,10 @@ static irqreturn_t cs35l35_irq(int irq, void *data) } if (sticky1 & CS35L35_AMP_SHORT) { - dev_crit(codec->dev, "AMP Short Error\n"); + dev_crit(cs35l35->dev, "AMP Short Error\n"); /* error is no longer asserted; safe to reset */ if (!(current1 & CS35L35_AMP_SHORT)) { - dev_dbg(codec->dev, "Amp short error release\n"); + dev_dbg(cs35l35->dev, "Amp short error release\n"); regmap_update_bits(cs35l35->regmap, CS35L35_PROT_RELEASE_CTL, CS35L35_SHORT_RLS, 0); @@ -1069,11 +1066,11 @@ static irqreturn_t cs35l35_irq(int irq, void *data) } if (sticky1 & CS35L35_OTW) { - dev_warn(codec->dev, "Over temperature warning\n"); + dev_warn(cs35l35->dev, "Over temperature warning\n"); /* error is no longer asserted; safe to reset */ if (!(current1 & CS35L35_OTW)) { - dev_dbg(codec->dev, "Over temperature warn release\n"); + dev_dbg(cs35l35->dev, "Over temperature warn release\n"); regmap_update_bits(cs35l35->regmap, CS35L35_PROT_RELEASE_CTL, CS35L35_OTW_RLS, 0); @@ -1088,10 +1085,10 @@ static irqreturn_t cs35l35_irq(int irq, void *data) } if (sticky1 & CS35L35_OTE) { - dev_crit(codec->dev, "Over temperature error\n"); + dev_crit(cs35l35->dev, "Over temperature error\n"); /* error is no longer asserted; safe to reset */ if (!(current1 & CS35L35_OTE)) { - dev_dbg(codec->dev, "Over temperature error release\n"); + dev_dbg(cs35l35->dev, "Over temperature error release\n"); regmap_update_bits(cs35l35->regmap, CS35L35_PROT_RELEASE_CTL, CS35L35_OTE_RLS, 0); @@ -1106,7 +1103,7 @@ static irqreturn_t cs35l35_irq(int irq, void *data) } if (sticky3 & CS35L35_BST_HIGH) { - dev_crit(codec->dev, "VBST error: powering off!\n"); + dev_crit(cs35l35->dev, "VBST error: powering off!\n"); regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, CS35L35_PDN_AMP, CS35L35_PDN_AMP); regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL1, @@ -1114,7 +1111,7 @@ static irqreturn_t cs35l35_irq(int irq, void *data) } if (sticky3 & CS35L35_LBST_SHORT) { - dev_crit(codec->dev, "LBST error: powering off!\n"); + dev_crit(cs35l35->dev, "LBST error: powering off!\n"); regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, CS35L35_PDN_AMP, CS35L35_PDN_AMP); regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL1, @@ -1122,13 +1119,13 @@ static irqreturn_t cs35l35_irq(int irq, void *data) } if (sticky2 & CS35L35_VPBR_ERR) - dev_dbg(codec->dev, "Error: Reactive Brownout\n"); + dev_dbg(cs35l35->dev, "Error: Reactive Brownout\n"); if (sticky4 & CS35L35_VMON_OVFL) - dev_dbg(codec->dev, "Error: VMON overflow\n"); + dev_dbg(cs35l35->dev, "Error: VMON overflow\n"); if (sticky4 & CS35L35_IMON_OVFL) - dev_dbg(codec->dev, "Error: IMON overflow\n"); + dev_dbg(cs35l35->dev, "Error: IMON overflow\n"); return IRQ_HANDLED; } @@ -1365,6 +1362,8 @@ static int cs35l35_i2c_probe(struct i2c_client *i2c_client, if (!cs35l35) return -ENOMEM; + cs35l35->dev = dev; + i2c_set_clientdata(i2c_client, cs35l35); cs35l35->regmap = devm_regmap_init_i2c(i2c_client, &cs35l35_regmap); if (IS_ERR(cs35l35->regmap)) { diff --git a/sound/soc/codecs/cs35l35.h b/sound/soc/codecs/cs35l35.h index c203081fc94c..156d2f0e6fd8 100644 --- a/sound/soc/codecs/cs35l35.h +++ b/sound/soc/codecs/cs35l35.h @@ -265,7 +265,7 @@ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) struct cs35l35_private { - struct snd_soc_codec *codec; + struct device *dev; struct cs35l35_platform_data pdata; struct regmap *regmap; struct regulator_bulk_data supplies[2]; -- cgit v1.2.1 From b3bbef45e97526e8c56fd542d75e505776eecc01 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 20 Mar 2017 10:13:52 +0100 Subject: ASoC: wm8903: add regulator handling The WM8903 has four different voltage inputs: AVDD, CPVDD, DBVDD and DCVDD. On the Qualcomm APQ8060 Dragonboard these are all supplied from proper regulators and thus need activating and binding. This is a quick-and-dirty solution just grabbing and enabling the regulator supplies on probe() and disabling them on remove() and the errorpath. More elaborate power management is likely possible. I assume the nVidia designs using this codec have some hard-wired always-on power and will be happy with using the dummy regulators for this. But someone from the nVidia camp should probably check whether they can bind these to proper regulators instead. We also amend the DT binding document. A small change like this does not warrant a separate patch for augmenting these. Cc: devicetree@vger.kernel.org Cc: Mark Brown Cc: Liam Girdwood Cc: Stephen Warren Cc: Charles Keepax Signed-off-by: Linus Walleij Signed-off-by: Mark Brown --- sound/soc/codecs/wm8903.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index 6e887c2c42b1..237eeb9a8b97 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -115,10 +116,19 @@ static const struct reg_default wm8903_reg_defaults[] = { { 172, 0x0000 }, /* R172 - Analogue Output Bias 0 */ }; +#define WM8903_NUM_SUPPLIES 4 +static const char *wm8903_supply_names[WM8903_NUM_SUPPLIES] = { + "AVDD", + "CPVDD", + "DBVDD", + "DCVDD", +}; + struct wm8903_priv { struct wm8903_platform_data *pdata; struct device *dev; struct regmap *regmap; + struct regulator_bulk_data supplies[WM8903_NUM_SUPPLIES]; int sysclk; int irq; @@ -2030,6 +2040,23 @@ static int wm8903_i2c_probe(struct i2c_client *i2c, pdata = wm8903->pdata; + for (i = 0; i < ARRAY_SIZE(wm8903->supplies); i++) + wm8903->supplies[i].supply = wm8903_supply_names[i]; + + ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8903->supplies), + wm8903->supplies); + if (ret != 0) { + dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret); + return ret; + } + + ret = regulator_bulk_enable(ARRAY_SIZE(wm8903->supplies), + wm8903->supplies); + if (ret != 0) { + dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret); + return ret; + } + ret = regmap_read(wm8903->regmap, WM8903_SW_RESET_AND_ID, &val); if (ret != 0) { dev_err(&i2c->dev, "Failed to read chip ID: %d\n", ret); @@ -2160,6 +2187,8 @@ static int wm8903_i2c_probe(struct i2c_client *i2c, return 0; err: + regulator_bulk_disable(ARRAY_SIZE(wm8903->supplies), + wm8903->supplies); return ret; } @@ -2167,6 +2196,8 @@ static int wm8903_i2c_remove(struct i2c_client *client) { struct wm8903_priv *wm8903 = i2c_get_clientdata(client); + regulator_bulk_disable(ARRAY_SIZE(wm8903->supplies), + wm8903->supplies); if (client->irq) free_irq(client->irq, wm8903); wm8903_free_gpio(wm8903); -- cgit v1.2.1 From 17febfa6071bc673892edda6b1998ccfc7456c4e Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 20 Mar 2017 10:20:54 +0800 Subject: ASoC: rt5665: fix wrong pre div reg of IF2 and IF3 The pre divider control register of IF1 and IF2/3 are different. The driver used the same register for all interfaces which was a mistake. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5665.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c index 5545d084b0b6..285ec7495379 100644 --- a/sound/soc/codecs/rt5665.c +++ b/sound/soc/codecs/rt5665.c @@ -4080,7 +4080,7 @@ static int rt5665_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_codec *codec = dai->codec; struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec); - unsigned int val_len = 0, val_clk, mask_clk, val_bits = 0x0100; + unsigned int val_len = 0, val_clk, reg_clk, mask_clk, val_bits = 0x0100; int pre_div, frame_size; rt5665->lrck[dai->id] = params_rate(params); @@ -4124,6 +4124,7 @@ static int rt5665_hw_params(struct snd_pcm_substream *substream, if (params_channels(params) > 2) rt5665_set_tdm_slot(dai, 0xf, 0xf, params_channels(params), params_width(params)); + reg_clk = RT5665_ADDA_CLK_1; mask_clk = RT5665_I2S_PD1_MASK; val_clk = pre_div << RT5665_I2S_PD1_SFT; snd_soc_update_bits(codec, RT5665_I2S1_SDP, @@ -4131,12 +4132,14 @@ static int rt5665_hw_params(struct snd_pcm_substream *substream, break; case RT5665_AIF2_1: case RT5665_AIF2_2: + reg_clk = RT5665_ADDA_CLK_2; mask_clk = RT5665_I2S_PD2_MASK; val_clk = pre_div << RT5665_I2S_PD2_SFT; snd_soc_update_bits(codec, RT5665_I2S2_SDP, RT5665_I2S_DL_MASK, val_len); break; case RT5665_AIF3: + reg_clk = RT5665_ADDA_CLK_2; mask_clk = RT5665_I2S_PD3_MASK; val_clk = pre_div << RT5665_I2S_PD3_SFT; snd_soc_update_bits(codec, RT5665_I2S3_SDP, @@ -4147,7 +4150,7 @@ static int rt5665_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - snd_soc_update_bits(codec, RT5665_ADDA_CLK_1, mask_clk, val_clk); + snd_soc_update_bits(codec, reg_clk, mask_clk, val_clk); snd_soc_update_bits(codec, RT5665_STO1_DAC_SIL_DET, 0x3700, val_bits); switch (rt5665->lrck[dai->id]) { -- cgit v1.2.1 From 424dfbf2c0dee6f9c13d43d6d209a6e57a492d57 Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Sat, 18 Mar 2017 23:13:14 +0530 Subject: ASoC: mediatek: constify snd_soc_ops structures Declare snd_soc_ops structures as const as they are only stored in the ops field of a snd_soc_dai_link structure. This field is of type const, so snd_soc_ops structures having this property can be made const too. Signed-off-by: Bhumika Goyal Signed-off-by: Mark Brown --- sound/soc/mediatek/mt2701/mt2701-cs42448.c | 2 +- sound/soc/mediatek/mt8173/mt8173-max98090.c | 2 +- sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c | 2 +- sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c | 2 +- sound/soc/mediatek/mt8173/mt8173-rt5650.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/mediatek/mt2701/mt2701-cs42448.c b/sound/soc/mediatek/mt2701/mt2701-cs42448.c index 1e7e8d43fd8a..aa5b31b121e3 100644 --- a/sound/soc/mediatek/mt2701/mt2701-cs42448.c +++ b/sound/soc/mediatek/mt2701/mt2701-cs42448.c @@ -129,7 +129,7 @@ static int mt2701_cs42448_fe_ops_startup(struct snd_pcm_substream *substream) return 0; } -static struct snd_soc_ops mt2701_cs42448_48k_fe_ops = { +static const struct snd_soc_ops mt2701_cs42448_48k_fe_ops = { .startup = mt2701_cs42448_fe_ops_startup, }; diff --git a/sound/soc/mediatek/mt8173/mt8173-max98090.c b/sound/soc/mediatek/mt8173/mt8173-max98090.c index 46c8e6ae00b4..e0c2b23ec711 100644 --- a/sound/soc/mediatek/mt8173/mt8173-max98090.c +++ b/sound/soc/mediatek/mt8173/mt8173-max98090.c @@ -67,7 +67,7 @@ static int mt8173_max98090_hw_params(struct snd_pcm_substream *substream, SND_SOC_CLOCK_IN); } -static struct snd_soc_ops mt8173_max98090_ops = { +static const struct snd_soc_ops mt8173_max98090_ops = { .hw_params = mt8173_max98090_hw_params, }; diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c index 467f7049a288..5e383eb456a4 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c @@ -75,7 +75,7 @@ static int mt8173_rt5650_rt5514_hw_params(struct snd_pcm_substream *substream, return 0; } -static struct snd_soc_ops mt8173_rt5650_rt5514_ops = { +static const struct snd_soc_ops mt8173_rt5650_rt5514_ops = { .hw_params = mt8173_rt5650_rt5514_hw_params, }; diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c index 1b8b2a778845..fed1f15a39c2 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c @@ -79,7 +79,7 @@ static int mt8173_rt5650_rt5676_hw_params(struct snd_pcm_substream *substream, return 0; } -static struct snd_soc_ops mt8173_rt5650_rt5676_ops = { +static const struct snd_soc_ops mt8173_rt5650_rt5676_ops = { .hw_params = mt8173_rt5650_rt5676_hw_params, }; diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650.c b/sound/soc/mediatek/mt8173/mt8173-rt5650.c index ba65f4157a7e..a78470839b65 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650.c @@ -105,7 +105,7 @@ static int mt8173_rt5650_hw_params(struct snd_pcm_substream *substream, return 0; } -static struct snd_soc_ops mt8173_rt5650_ops = { +static const struct snd_soc_ops mt8173_rt5650_ops = { .hw_params = mt8173_rt5650_hw_params, }; -- cgit v1.2.1 From 2261cf1ce63ff1ca01772542a41b57eaac286841 Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Sat, 18 Mar 2017 19:34:11 +0530 Subject: ASoC: omap: constify snd_soc_ops structures Declare snd_soc_ops structures as const as they are only stored in the ops field of a snd_soc_dai_link structure. This field is of type const, so snd_soc_ops structures having this property can be made const too. Cross compiled the .o files for arm architecture. Signed-off-by: Bhumika Goyal Reviewed-by: Sebastian Reichel Acked-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/omap/am3517evm.c | 2 +- sound/soc/omap/n810.c | 2 +- sound/soc/omap/omap-abe-twl6040.c | 2 +- sound/soc/omap/omap-twl4030.c | 2 +- sound/soc/omap/omap3pandora.c | 2 +- sound/soc/omap/osk5912.c | 2 +- sound/soc/omap/rx51.c | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/omap/am3517evm.c b/sound/soc/omap/am3517evm.c index 25a33e9d417a..d5651026ec10 100644 --- a/sound/soc/omap/am3517evm.c +++ b/sound/soc/omap/am3517evm.c @@ -49,7 +49,7 @@ static int am3517evm_hw_params(struct snd_pcm_substream *substream, return ret; } -static struct snd_soc_ops am3517evm_ops = { +static const struct snd_soc_ops am3517evm_ops = { .hw_params = am3517evm_hw_params, }; diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c index fdecb7043174..71e5f31fa306 100644 --- a/sound/soc/omap/n810.c +++ b/sound/soc/omap/n810.c @@ -124,7 +124,7 @@ static int n810_hw_params(struct snd_pcm_substream *substream, return err; } -static struct snd_soc_ops n810_ops = { +static const struct snd_soc_ops n810_ops = { .startup = n810_startup, .hw_params = n810_hw_params, .shutdown = n810_shutdown, diff --git a/sound/soc/omap/omap-abe-twl6040.c b/sound/soc/omap/omap-abe-twl6040.c index 89fe95e877db..614b18d2f631 100644 --- a/sound/soc/omap/omap-abe-twl6040.c +++ b/sound/soc/omap/omap-abe-twl6040.c @@ -70,7 +70,7 @@ static int omap_abe_hw_params(struct snd_pcm_substream *substream, return ret; } -static struct snd_soc_ops omap_abe_ops = { +static const struct snd_soc_ops omap_abe_ops = { .hw_params = omap_abe_hw_params, }; diff --git a/sound/soc/omap/omap-twl4030.c b/sound/soc/omap/omap-twl4030.c index 743131473056..a24b0dedabb9 100644 --- a/sound/soc/omap/omap-twl4030.c +++ b/sound/soc/omap/omap-twl4030.c @@ -73,7 +73,7 @@ static int omap_twl4030_hw_params(struct snd_pcm_substream *substream, return snd_soc_runtime_set_dai_fmt(rtd, fmt); } -static struct snd_soc_ops omap_twl4030_ops = { +static const struct snd_soc_ops omap_twl4030_ops = { .hw_params = omap_twl4030_hw_params, }; diff --git a/sound/soc/omap/omap3pandora.c b/sound/soc/omap/omap3pandora.c index 732e749a1f8e..4e3de712159c 100644 --- a/sound/soc/omap/omap3pandora.c +++ b/sound/soc/omap/omap3pandora.c @@ -184,7 +184,7 @@ static int omap3pandora_in_init(struct snd_soc_pcm_runtime *rtd) return 0; } -static struct snd_soc_ops omap3pandora_ops = { +static const struct snd_soc_ops omap3pandora_ops = { .hw_params = omap3pandora_hw_params, }; diff --git a/sound/soc/omap/osk5912.c b/sound/soc/omap/osk5912.c index aa4053bf6710..e4096779ca05 100644 --- a/sound/soc/omap/osk5912.c +++ b/sound/soc/omap/osk5912.c @@ -68,7 +68,7 @@ static int osk_hw_params(struct snd_pcm_substream *substream, return err; } -static struct snd_soc_ops osk_ops = { +static const struct snd_soc_ops osk_ops = { .startup = osk_startup, .hw_params = osk_hw_params, .shutdown = osk_shutdown, diff --git a/sound/soc/omap/rx51.c b/sound/soc/omap/rx51.c index 086b59b7b6d7..3aeb65feaea1 100644 --- a/sound/soc/omap/rx51.c +++ b/sound/soc/omap/rx51.c @@ -123,7 +123,7 @@ static int rx51_hw_params(struct snd_pcm_substream *substream, SND_SOC_CLOCK_IN); } -static struct snd_soc_ops rx51_ops = { +static const struct snd_soc_ops rx51_ops = { .startup = rx51_startup, .hw_params = rx51_hw_params, }; -- cgit v1.2.1 From d7fba9dcf6cd74cb8a8ab1c4c2629a3f7df00bc9 Mon Sep 17 00:00:00 2001 From: Harsha Priya Date: Wed, 15 Mar 2017 16:28:25 -0700 Subject: ASoC: Intel: Update bxt_da7219_max98357a to add a new This patch adds a platform clock widget to turn off the clock only when both headset capture and headset playback are not in use. This removes turning off the clock in hw_free so that the clock is on when either capture or playback of headset is in progress. Signed-off-by: Harsha Priya Signed-off-by: Sathyanarayana Nujella Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/boards/bxt_da7219_max98357a.c | 97 +++++++++++++++------------ 1 file changed, 53 insertions(+), 44 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index 2cda06cde4d1..3a8c4d954a91 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -55,6 +55,54 @@ enum { BXT_DPCM_AUDIO_HDMI3_PB, }; +static inline struct snd_soc_dai *bxt_get_codec_dai(struct snd_soc_card *card) +{ + struct snd_soc_pcm_runtime *rtd; + + list_for_each_entry(rtd, &card->rtd_list, list) { + + if (!strncmp(rtd->codec_dai->name, BXT_DIALOG_CODEC_DAI, + strlen(BXT_DIALOG_CODEC_DAI))) + return rtd->codec_dai; + } + + return NULL; +} + +static int platform_clock_control(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + int ret = 0; + struct snd_soc_dapm_context *dapm = w->dapm; + struct snd_soc_card *card = dapm->card; + struct snd_soc_dai *codec_dai; + + codec_dai = bxt_get_codec_dai(card); + if (!codec_dai) { + dev_err(card->dev, "Codec dai not found; Unable to set/unset codec pll\n"); + return -EIO; + } + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + ret = snd_soc_dai_set_pll(codec_dai, 0, + DA7219_SYSCLK_MCLK, 0, 0); + if (ret) + dev_err(card->dev, "failed to stop PLL: %d\n", ret); + } else if(SND_SOC_DAPM_EVENT_ON(event)) { + ret = snd_soc_dai_set_sysclk(codec_dai, + DA7219_CLKSRC_MCLK, 19200000, SND_SOC_CLOCK_IN); + if (ret) + dev_err(card->dev, "can't set codec sysclk configuration\n"); + + ret = snd_soc_dai_set_pll(codec_dai, 0, + DA7219_SYSCLK_PLL_SRM, 0, DA7219_PLL_FREQ_OUT_98304); + if (ret) + dev_err(card->dev, "failed to start PLL: %d\n", ret); + } + + return ret; +} + static const struct snd_kcontrol_new broxton_controls[] = { SOC_DAPM_PIN_SWITCH("Headphone Jack"), SOC_DAPM_PIN_SWITCH("Headset Mic"), @@ -69,6 +117,8 @@ static const struct snd_soc_dapm_widget broxton_widgets[] = { SND_SOC_DAPM_SPK("HDMI1", NULL), SND_SOC_DAPM_SPK("HDMI2", NULL), SND_SOC_DAPM_SPK("HDMI3", NULL), + SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, + platform_clock_control, SND_SOC_DAPM_POST_PMD|SND_SOC_DAPM_PRE_PMU), }; static const struct snd_soc_dapm_route broxton_map[] = { @@ -109,6 +159,9 @@ static const struct snd_soc_dapm_route broxton_map[] = { /* DMIC */ {"dmic01_hifi", NULL, "DMIC01 Rx"}, {"DMIC01 Rx", NULL, "DMIC AIF"}, + + { "Headphone Jack", NULL, "Platform Clock" }, + { "Headset Mic", NULL, "Platform Clock" }, }; static int broxton_ssp_fixup(struct snd_soc_pcm_runtime *rtd, @@ -243,49 +296,6 @@ static const struct snd_soc_ops broxton_da7219_fe_ops = { .startup = bxt_fe_startup, }; -static int broxton_da7219_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai = rtd->codec_dai; - int ret; - - ret = snd_soc_dai_set_sysclk(codec_dai, - DA7219_CLKSRC_MCLK, 19200000, SND_SOC_CLOCK_IN); - if (ret < 0) - dev_err(codec_dai->dev, "can't set codec sysclk configuration\n"); - - ret = snd_soc_dai_set_pll(codec_dai, 0, - DA7219_SYSCLK_PLL_SRM, 0, DA7219_PLL_FREQ_OUT_98304); - if (ret < 0) { - dev_err(codec_dai->dev, "failed to start PLL: %d\n", ret); - return -EIO; - } - - return ret; -} - -static int broxton_da7219_hw_free(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai = rtd->codec_dai; - int ret; - - ret = snd_soc_dai_set_pll(codec_dai, 0, - DA7219_SYSCLK_MCLK, 0, 0); - if (ret < 0) { - dev_err(codec_dai->dev, "failed to stop PLL: %d\n", ret); - return -EIO; - } - - return ret; -} - -static const struct snd_soc_ops broxton_da7219_ops = { - .hw_params = broxton_da7219_hw_params, - .hw_free = broxton_da7219_hw_free, -}; - static int broxton_dmic_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { @@ -467,7 +477,6 @@ static struct snd_soc_dai_link broxton_dais[] = { SND_SOC_DAIFMT_CBS_CFS, .ignore_pmdown_time = 1, .be_hw_params_fixup = broxton_ssp_fixup, - .ops = &broxton_da7219_ops, .dpcm_playback = 1, .dpcm_capture = 1, }, -- cgit v1.2.1 From 991454e17070eaf5286a666d9e896fd6fb332c72 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 24 Mar 2017 00:13:00 +0000 Subject: ASoC: core: remove pointless auxiliary from snd_soc_component commit 1a653aa44725 ("ASoC: core: replace aux_comp_list to ...") tried to replace aux_comp_list to component_dev_list, but it failed because of binding timing. Thus, Sylwester fixuped it by commit d2e3a1358c37 ("ASoC: Fix binding and probing of auxiliary..."). One of main purpose of commit 1a653aa44725 ("ASoC: core: replace...") was remove replaceable list (= list_aux) from snd_soc_component by using new "auxiliary" flags (but it failed). Because of this background, current code has reborned card_aux_list (= same as original list_aux), and almost pointless "auxiliary" flags. Let's remove pointless "auxiliary" flags by this patch This means, it is same as revert both commit 1a653aa44725 ("ASoC: core: replace aux_comp_list to ...") and commit d2e3a1358c37 ("ASoC: Fix binding and probing of auxiliary..."). Signed-off-by: Kuninori Morimoto Tested-by: Sylwester Nawrocki Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index d29fbc7195a0..a6f840beacb0 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1776,7 +1776,6 @@ static int soc_bind_aux_dev(struct snd_soc_card *card, int num) } component->init = aux_dev->init; - component->auxiliary = 1; list_add(&component->card_aux_list, &card->aux_comp_list); return 0; @@ -1788,14 +1787,13 @@ err_defer: static int soc_probe_aux_devices(struct snd_soc_card *card) { - struct snd_soc_component *comp, *tmp; + struct snd_soc_component *comp; int order; int ret; for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; order++) { - list_for_each_entry_safe(comp, tmp, &card->aux_comp_list, - card_aux_list) { + list_for_each_entry(comp, &card->aux_comp_list, card_aux_list) { if (comp->driver->probe_order == order) { ret = soc_probe_component(card, comp); if (ret < 0) { @@ -1804,7 +1802,6 @@ static int soc_probe_aux_devices(struct snd_soc_card *card) comp->name, ret); return ret; } - list_del(&comp->card_aux_list); } } } @@ -1820,14 +1817,12 @@ static void soc_remove_aux_devices(struct snd_soc_card *card) for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; order++) { list_for_each_entry_safe(comp, _comp, - &card->component_dev_list, card_list) { - - if (!comp->auxiliary) - continue; + &card->aux_comp_list, card_aux_list) { if (comp->driver->remove_order == order) { soc_remove_component(comp); - comp->auxiliary = 0; + /* remove it from the card's aux_comp_list */ + list_del(&comp->card_aux_list); } } } -- cgit v1.2.1 From 381ca1d12e188f90ed9f36cebb4a62d46fb11274 Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Wed, 22 Mar 2017 18:21:35 +0530 Subject: ASoC: blackfin: constify snd_soc_ops structures Declare snd_soc_ops structures as const as they are only stored in the ops field of a snd_soc_dai_link structure. This field is of type const, so snd_soc_ops structures having this property can be made const too. Cross compiled the .o files for blackfin architecture. Signed-off-by: Bhumika Goyal Signed-off-by: Mark Brown --- sound/soc/blackfin/bfin-eval-adau1373.c | 2 +- sound/soc/blackfin/bfin-eval-adav80x.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/blackfin/bfin-eval-adau1373.c b/sound/soc/blackfin/bfin-eval-adau1373.c index 72ac78988426..64b88fdc1f6c 100644 --- a/sound/soc/blackfin/bfin-eval-adau1373.c +++ b/sound/soc/blackfin/bfin-eval-adau1373.c @@ -119,7 +119,7 @@ static int bfin_eval_adau1373_codec_init(struct snd_soc_pcm_runtime *rtd) return ret; } -static struct snd_soc_ops bfin_eval_adau1373_ops = { +static const struct snd_soc_ops bfin_eval_adau1373_ops = { .hw_params = bfin_eval_adau1373_hw_params, }; diff --git a/sound/soc/blackfin/bfin-eval-adav80x.c b/sound/soc/blackfin/bfin-eval-adav80x.c index 1037477d10b2..99e5ecabdcda 100644 --- a/sound/soc/blackfin/bfin-eval-adav80x.c +++ b/sound/soc/blackfin/bfin-eval-adav80x.c @@ -64,7 +64,7 @@ static int bfin_eval_adav80x_codec_init(struct snd_soc_pcm_runtime *rtd) return 0; } -static struct snd_soc_ops bfin_eval_adav80x_ops = { +static const struct snd_soc_ops bfin_eval_adav80x_ops = { .hw_params = bfin_eval_adav80x_hw_params, }; -- cgit v1.2.1 From dc2721564f6da549f6eb29ac5bca28d65beadcb7 Mon Sep 17 00:00:00 2001 From: Hiroyuki Yokoyama Date: Wed, 22 Mar 2017 05:43:35 +0000 Subject: ASoC: rcar: enable PCM RATE untile 192000 R-Car sound can handle untile 192000 rate. Signed-off-by: Hiroyuki Yokoyama Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 72966bdd3daa..3e852e00b277 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -96,7 +96,7 @@ #include #include "rsnd.h" -#define RSND_RATES SNDRV_PCM_RATE_8000_96000 +#define RSND_RATES SNDRV_PCM_RATE_8000_192000 #define RSND_FMTS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE) static const struct of_device_id rsnd_of_match[] = { -- cgit v1.2.1 From 6b8530cc056efd4a11b034ca5b1e9f7e9563f553 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 22 Mar 2017 04:02:43 +0000 Subject: ASoC: rcar: ssi: don't set SSICR.CKDV = 000 with SSIWSR.CONT R-Car Datasheet is indicating "SSICR.CKDV = 000 is invalid when SSIWSR.WS_MODE = 1 or SSIWSR.CONT = 1". Current driver will set CONT, thus, we shouldn't use CKDV = 000. This patch fixup it. Reported-by: Hiroyuki Yokoyama Signed-off-by: Kuninori Morimoto Tested-by: Hiroyuki Yokoyama Signed-off-by: Mark Brown --- sound/soc/sh/rcar/ssi.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 411bda2387ad..135c5669f796 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -227,6 +227,15 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod, */ for (j = 0; j < ARRAY_SIZE(ssi_clk_mul_table); j++) { + /* + * It will set SSIWSR.CONT here, but SSICR.CKDV = 000 + * with it is not allowed. (SSIWSR.WS_MODE with + * SSICR.CKDV = 000 is not allowed either). + * Skip it. See SSICR.CKDV + */ + if (j == 0) + continue; + /* * this driver is assuming that * system word is 32bit x chan -- cgit v1.2.1 From 73548dd316adec41172c31d63a0c35a97bf9577f Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 21 Mar 2017 16:50:43 -0700 Subject: ASoC: jack - check status of GPIO-based pins on resume For GPIO-backed pins that are not configured as wakeup sources, we may miss change in their state that happens while system is suspended. Let's use PM notifier to refresh their state upon resume. Signed-off-by: Dmitry Torokhov Signed-off-by: Mark Brown --- sound/soc/soc-jack.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c index fbaa1bb41102..a03dcbb94baf 100644 --- a/sound/soc/soc-jack.c +++ b/sound/soc/soc-jack.c @@ -19,6 +19,7 @@ #include #include #include +#include #include /** @@ -293,6 +294,27 @@ static void gpio_work(struct work_struct *work) snd_soc_jack_gpio_detect(gpio); } +static int snd_soc_jack_pm_notifier(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct snd_soc_jack_gpio *gpio = + container_of(nb, struct snd_soc_jack_gpio, pm_notifier); + + switch (action) { + case PM_POST_SUSPEND: + case PM_POST_HIBERNATION: + case PM_POST_RESTORE: + /* + * Use workqueue so we do not have to care about running + * concurrently with work triggered by the interrupt handler. + */ + queue_delayed_work(system_power_efficient_wq, &gpio->work, 0); + break; + } + + return NOTIFY_DONE; +} + /** * snd_soc_jack_add_gpios - Associate GPIO pins with an ASoC jack * @@ -369,6 +391,13 @@ got_gpio: i, ret); } + /* + * Register PM notifier so we do not miss state transitions + * happening while system is asleep. + */ + gpios[i].pm_notifier.notifier_call = snd_soc_jack_pm_notifier; + register_pm_notifier(&gpios[i].pm_notifier); + /* Expose GPIO value over sysfs for diagnostic purposes */ gpiod_export(gpios[i].desc, false); @@ -428,6 +457,7 @@ void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count, for (i = 0; i < count; i++) { gpiod_unexport(gpios[i].desc); + unregister_pm_notifier(&gpios[i].pm_notifier); free_irq(gpiod_to_irq(gpios[i].desc), &gpios[i]); cancel_delayed_work_sync(&gpios[i].work); gpiod_put(gpios[i].desc); -- cgit v1.2.1 From 3ddc97211cbb61a5f59882c26f8e3158c86e34bb Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Tue, 21 Mar 2017 17:03:24 +0200 Subject: ASoC: codec: wm8960: Refactor sysclk freq search Add a separate function for finding (sysclk, lrclk, bclk) when the clock is auto or mclk. This makes code easier to read and reduces the indentation level in wm8960_configure_clocking. Signed-off-by: Daniel Baluta Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8960.c | 80 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 61 insertions(+), 19 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index 3bf081a7e450..25a4a11929fe 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -604,12 +604,71 @@ static const int bclk_divs[] = { 120, 160, 220, 240, 320, 320, 320 }; +/** + * wm8960_configure_sysclk - checks if there is a sysclk frequency available + * The sysclk must be chosen such that: + * - sysclk = MCLK / sysclk_divs + * - lrclk = sysclk / dac_divs + * - 10 * bclk = sysclk / bclk_divs + * + * @wm8960_priv: wm8960 codec private data + * @mclk: MCLK used to derive sysclk + * @sysclk_idx: sysclk_divs index for found sysclk + * @dac_idx: dac_divs index for found lrclk + * @bclk_idx: bclk_divs index for found bclk + * + * Returns: + * -1, in case no sysclk frequency available found + * 0, in case an exact (@sysclk_idx, @dac_idx, @bclk_idx) match is found + */ +static +int wm8960_configure_sysclk(struct wm8960_priv *wm8960, int mclk, + int *sysclk_idx, int *dac_idx, int *bclk_idx) +{ + int sysclk, bclk, lrclk; + int i, j, k; + int diff; + + bclk = wm8960->bclk; + lrclk = wm8960->lrclk; + + /* check if the sysclk frequency is available. */ + for (i = 0; i < ARRAY_SIZE(sysclk_divs); ++i) { + if (sysclk_divs[i] == -1) + continue; + sysclk = mclk / sysclk_divs[i]; + for (j = 0; j < ARRAY_SIZE(dac_divs); ++j) { + if (sysclk != dac_divs[j] * lrclk) + continue; + for (k = 0; k < ARRAY_SIZE(bclk_divs); ++k) { + diff = sysclk - bclk * bclk_divs[k] / 10; + if (diff == 0) { + *sysclk_idx = i; + *dac_idx = j; + *bclk_idx = k; + break; + } + } + if (k != ARRAY_SIZE(bclk_divs)) + break; + } + if (j != ARRAY_SIZE(dac_divs)) + break; + } + + if (i != ARRAY_SIZE(sysclk_divs)) + return 0; + + return -1; +} + static int wm8960_configure_clocking(struct snd_soc_codec *codec) { struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); int sysclk, bclk, lrclk, freq_out, freq_in; u16 iface1 = snd_soc_read(codec, WM8960_IFACE1); int i, j, k; + int ret; if (!(iface1 & (1<<6))) { dev_dbg(codec->dev, @@ -643,25 +702,8 @@ static int wm8960_configure_clocking(struct snd_soc_codec *codec) } if (wm8960->clk_id != WM8960_SYSCLK_PLL) { - /* check if the sysclk frequency is available. */ - for (i = 0; i < ARRAY_SIZE(sysclk_divs); ++i) { - if (sysclk_divs[i] == -1) - continue; - sysclk = freq_out / sysclk_divs[i]; - for (j = 0; j < ARRAY_SIZE(dac_divs); ++j) { - if (sysclk != dac_divs[j] * lrclk) - continue; - for (k = 0; k < ARRAY_SIZE(bclk_divs); ++k) - if (sysclk == bclk * bclk_divs[k] / 10) - break; - if (k != ARRAY_SIZE(bclk_divs)) - break; - } - if (j != ARRAY_SIZE(dac_divs)) - break; - } - - if (i != ARRAY_SIZE(sysclk_divs)) { + ret = wm8960_configure_sysclk(wm8960, freq_out, &i, &j, &k); + if (ret == 0) { goto configure_clock; } else if (wm8960->clk_id != WM8960_SYSCLK_AUTO) { dev_err(codec->dev, "failed to configure clock\n"); -- cgit v1.2.1 From 3c01b9ee2ab9d0dffe837c12ed93740516a673d7 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Tue, 21 Mar 2017 17:03:25 +0200 Subject: ASoC: codec: wm8960: Relax bit clock computation WM8960 derives bit clock from sysclock using BCLKDIV[3:0] of R8 clocking register (See WM8960 datasheet, page 71). There are use cases, like this: aplay -Dhw:0,0 -r 48000 -c 1 -f S20_3LE -t raw audio48k20b_3LE1c.pcm where no BCLKDIV applied to sysclock can give us the exact requested bitclk, so driver fails to configure clocking and aplay fails to run. Fix this by relaxing bitclk computation, so that when no exact value can be derived from sysclk pick the closest value greater than expected bitclk. Suggested-by: Charles Keepax Signed-off-by: Daniel Baluta Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8960.c | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index 25a4a11929fe..ce159f13e7a4 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -611,6 +611,10 @@ static const int bclk_divs[] = { * - lrclk = sysclk / dac_divs * - 10 * bclk = sysclk / bclk_divs * + * If we cannot find an exact match for (sysclk, lrclk, bclk) + * triplet, we relax the bclk such that bclk is chosen as the + * closest available frequency greater than expected bclk. + * * @wm8960_priv: wm8960 codec private data * @mclk: MCLK used to derive sysclk * @sysclk_idx: sysclk_divs index for found sysclk @@ -618,8 +622,9 @@ static const int bclk_divs[] = { * @bclk_idx: bclk_divs index for found bclk * * Returns: - * -1, in case no sysclk frequency available found - * 0, in case an exact (@sysclk_idx, @dac_idx, @bclk_idx) match is found + * -1, in case no sysclk frequency available found + * >=0, in case we could derive bclk and lrclk from sysclk using + * (@sysclk_idx, @dac_idx, @bclk_idx) dividers */ static int wm8960_configure_sysclk(struct wm8960_priv *wm8960, int mclk, @@ -627,7 +632,10 @@ int wm8960_configure_sysclk(struct wm8960_priv *wm8960, int mclk, { int sysclk, bclk, lrclk; int i, j, k; - int diff; + int diff, closest = mclk; + + /* marker for no match */ + *bclk_idx = -1; bclk = wm8960->bclk; lrclk = wm8960->lrclk; @@ -648,6 +656,12 @@ int wm8960_configure_sysclk(struct wm8960_priv *wm8960, int mclk, *bclk_idx = k; break; } + if (diff > 0 && closest > diff) { + *sysclk_idx = i; + *dac_idx = j; + *bclk_idx = k; + closest = diff; + } } if (k != ARRAY_SIZE(bclk_divs)) break; @@ -655,11 +669,7 @@ int wm8960_configure_sysclk(struct wm8960_priv *wm8960, int mclk, if (j != ARRAY_SIZE(dac_divs)) break; } - - if (i != ARRAY_SIZE(sysclk_divs)) - return 0; - - return -1; + return *bclk_idx; } static int wm8960_configure_clocking(struct snd_soc_codec *codec) @@ -703,7 +713,7 @@ static int wm8960_configure_clocking(struct snd_soc_codec *codec) if (wm8960->clk_id != WM8960_SYSCLK_PLL) { ret = wm8960_configure_sysclk(wm8960, freq_out, &i, &j, &k); - if (ret == 0) { + if (ret >= 0) { goto configure_clock; } else if (wm8960->clk_id != WM8960_SYSCLK_AUTO) { dev_err(codec->dev, "failed to configure clock\n"); -- cgit v1.2.1 From 36d96039e710488b53256defed0fd291e0f1a34b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 27 Mar 2017 10:39:58 +0200 Subject: ASoC: intel: Don't print FW version repeatedly Intel SST driver spews an info message "FW Versoin xxxx" at each time the device gets initialized. Since it's triggered at each PM (or even runtime PM), it appears so ofetn, and rather becomes annoying than useful. This patch suppresses the superfluous messages by checking the currently loaded FW version with the previously loaded one. Signed-off-by: Takashi Iwai Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst/sst_ipc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/intel/atom/sst/sst_ipc.c b/sound/soc/intel/atom/sst/sst_ipc.c index 14c2d9d18180..20b01e02ed8f 100644 --- a/sound/soc/intel/atom/sst/sst_ipc.c +++ b/sound/soc/intel/atom/sst/sst_ipc.c @@ -236,7 +236,9 @@ static void process_fw_init(struct intel_sst_drv *sst_drv_ctx, retval = init->result; goto ret; } - dev_info(sst_drv_ctx->dev, "FW Version %02x.%02x.%02x.%02x\n", + if (memcmp(&sst_drv_ctx->fw_version, &init->fw_version, + sizeof(init->fw_version))) + dev_info(sst_drv_ctx->dev, "FW Version %02x.%02x.%02x.%02x\n", init->fw_version.type, init->fw_version.major, init->fw_version.minor, init->fw_version.build); dev_dbg(sst_drv_ctx->dev, "Build date %s Time %s\n", -- cgit v1.2.1 From 74a4ce4c8e13820799911c746b917efd7cc25f55 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 22 Mar 2017 14:36:44 +0000 Subject: ASoC: intel: remove unused variable data and associated code The variable 'data' is assigned null and never re-assigned. There is also a redundant check for data being non-null which is always false, so remove this and the variable data and dma_addr as they are not used once the dead code has been removed. Detected with CoverityScan, CID#1324015 ("'Constant' variable gaurds dead code") Signed-off-by: Colin Ian King Acked-by: Jie Yang Signed-off-by: Mark Brown --- sound/soc/intel/haswell/sst-haswell-ipc.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/intel/haswell/sst-haswell-ipc.c b/sound/soc/intel/haswell/sst-haswell-ipc.c index a3459d1682a6..d33bdaf92c57 100644 --- a/sound/soc/intel/haswell/sst-haswell-ipc.c +++ b/sound/soc/intel/haswell/sst-haswell-ipc.c @@ -2000,10 +2000,8 @@ int sst_hsw_module_set_param(struct sst_hsw *hsw, u32 param_size, char *param) { int ret; - unsigned char *data = NULL; u32 header = 0; u32 payload_size = 0, transfer_parameter_size = 0; - dma_addr_t dma_addr = 0; struct sst_hsw_transfer_parameter *parameter; struct device *dev = hsw->dev; @@ -2047,10 +2045,6 @@ int sst_hsw_module_set_param(struct sst_hsw *hsw, kfree(parameter); - if (data) - dma_free_coherent(hsw->dsp->dma_dev, - param_size, (void *)data, dma_addr); - return ret; } -- cgit v1.2.1 From 8e71321d19c4ed02d9eed15955b8d485bab016fc Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 27 Mar 2017 16:54:27 +0100 Subject: ASoC: cs35l35: Clear reset_gpio on the error path in probe The error path in probe attempts to put the device back into reset. Should we fail to get the reset_gpio (such as a probe defer) we will leave the error value in there, which the gpiod_set_value_cansleep on the error path will attempt to deference. Fix this issue by clearing reset_gpio before we head into the error path. Signed-off-by: Charles Keepax Acked-by: Brian Austin Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l35.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/cs35l35.c b/sound/soc/codecs/cs35l35.c index 1d9f332b2eec..9688274f7c90 100644 --- a/sound/soc/codecs/cs35l35.c +++ b/sound/soc/codecs/cs35l35.c @@ -1412,10 +1412,10 @@ static int cs35l35_i2c_probe(struct i2c_client *i2c_client, GPIOD_OUT_LOW); if (IS_ERR(cs35l35->reset_gpio)) { ret = PTR_ERR(cs35l35->reset_gpio); + cs35l35->reset_gpio = NULL; if (ret == -EBUSY) { dev_info(dev, "Reset line busy, assuming shared reset\n"); - cs35l35->reset_gpio = NULL; } else { dev_err(dev, "Failed to get reset GPIO: %d\n", ret); goto err; -- cgit v1.2.1 From 8625c1dbd87631572f8e2c05bc67736b73d6f02f Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Wed, 29 Mar 2017 16:59:31 +0800 Subject: ASoC: mediatek: Add mt2701-wm8960 machine driver Add wm8960 machine driver and config option for MT2701. Signed-off-by: Ryder Lee Signed-off-by: Mark Brown --- sound/soc/mediatek/Kconfig | 10 ++ sound/soc/mediatek/mt2701/Makefile | 1 + sound/soc/mediatek/mt2701/mt2701-afe-pcm.c | 16 +++ sound/soc/mediatek/mt2701/mt2701-wm8960.c | 176 +++++++++++++++++++++++++++++ 4 files changed, 203 insertions(+) create mode 100644 sound/soc/mediatek/mt2701/mt2701-wm8960.c (limited to 'sound/soc') diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig index d7013bde6f45..c6f39040f71f 100644 --- a/sound/soc/mediatek/Kconfig +++ b/sound/soc/mediatek/Kconfig @@ -22,6 +22,16 @@ config SND_SOC_MT2701_CS42448 Select Y if you have such device. If unsure select "N". +config SND_SOC_MT2701_WM8960 + tristate "ASoc Audio driver for MT2701 with WM8960 codec" + depends on SND_SOC_MT2701 + select SND_SOC_WM8960 + help + This adds ASoC driver for Mediatek MT2701 boards + with the WM8960 codecs. + Select Y if you have such device. + If unsure select "N". + config SND_SOC_MT8173 tristate "ASoC support for Mediatek MT8173 chip" depends on ARCH_MEDIATEK diff --git a/sound/soc/mediatek/mt2701/Makefile b/sound/soc/mediatek/mt2701/Makefile index 31c3d04d4942..c91deb6aca21 100644 --- a/sound/soc/mediatek/mt2701/Makefile +++ b/sound/soc/mediatek/mt2701/Makefile @@ -17,3 +17,4 @@ obj-$(CONFIG_SND_SOC_MT2701) += snd-soc-mt2701-afe.o # machine driver obj-$(CONFIG_SND_SOC_MT2701_CS42448) += mt2701-cs42448.o +obj-$(CONFIG_SND_SOC_MT2701_WM8960) += mt2701-wm8960.o diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c index c7fa3e663463..bc5d4db94de6 100644 --- a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c +++ b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c @@ -603,6 +603,22 @@ static struct snd_soc_dai_ops mt2701_btmrg_ops = { static struct snd_soc_dai_driver mt2701_afe_pcm_dais[] = { /* FE DAIs: memory intefaces to CPU */ + { + .name = "PCMO0", + .id = MT2701_MEMIF_DL1, + .suspend = mtk_afe_dai_suspend, + .resume = mtk_afe_dai_resume, + .playback = { + .stream_name = "DL1", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = (SNDRV_PCM_FMTBIT_S16_LE + | SNDRV_PCM_FMTBIT_S24_LE + | SNDRV_PCM_FMTBIT_S32_LE) + }, + .ops = &mt2701_single_memif_dai_ops, + }, { .name = "PCM_multi", .id = MT2701_MEMIF_DLM, diff --git a/sound/soc/mediatek/mt2701/mt2701-wm8960.c b/sound/soc/mediatek/mt2701/mt2701-wm8960.c new file mode 100644 index 000000000000..a08ce2323bdc --- /dev/null +++ b/sound/soc/mediatek/mt2701/mt2701-wm8960.c @@ -0,0 +1,176 @@ +/* + * mt2701-wm8960.c -- MT2701 WM8960 ALSA SoC machine driver + * + * Copyright (c) 2017 MediaTek Inc. + * Author: Ryder Lee + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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 "mt2701-afe-common.h" + +static const struct snd_soc_dapm_widget mt2701_wm8960_widgets[] = { + SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_MIC("AMIC", NULL), +}; + +static const struct snd_kcontrol_new mt2701_wm8960_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("AMIC"), +}; + +static int mt2701_wm8960_be_ops_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + unsigned int mclk_rate; + unsigned int rate = params_rate(params); + unsigned int div_mclk_over_bck = rate > 192000 ? 2 : 4; + unsigned int div_bck_over_lrck = 64; + + mclk_rate = rate * div_bck_over_lrck * div_mclk_over_bck; + + snd_soc_dai_set_sysclk(cpu_dai, 0, mclk_rate, SND_SOC_CLOCK_OUT); + snd_soc_dai_set_sysclk(codec_dai, 0, mclk_rate, SND_SOC_CLOCK_IN); + + return 0; +} + +static struct snd_soc_ops mt2701_wm8960_be_ops = { + .hw_params = mt2701_wm8960_be_ops_hw_params +}; + +static struct snd_soc_dai_link mt2701_wm8960_dai_links[] = { + /* FE */ + { + .name = "wm8960-playback", + .stream_name = "wm8960-playback", + .cpu_dai_name = "PCMO0", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .dynamic = 1, + .dpcm_playback = 1, + }, + { + .name = "wm8960-capture", + .stream_name = "wm8960-capture", + .cpu_dai_name = "PCM0", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .dynamic = 1, + .dpcm_capture = 1, + }, + /* BE */ + { + .name = "wm8960-codec", + .cpu_dai_name = "I2S0", + .no_pcm = 1, + .codec_dai_name = "wm8960-hifi", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS + | SND_SOC_DAIFMT_GATED, + .ops = &mt2701_wm8960_be_ops, + .dpcm_playback = 1, + .dpcm_capture = 1, + }, +}; + +static struct snd_soc_card mt2701_wm8960_card = { + .name = "mt2701-wm8960", + .owner = THIS_MODULE, + .dai_link = mt2701_wm8960_dai_links, + .num_links = ARRAY_SIZE(mt2701_wm8960_dai_links), + .controls = mt2701_wm8960_controls, + .num_controls = ARRAY_SIZE(mt2701_wm8960_controls), + .dapm_widgets = mt2701_wm8960_widgets, + .num_dapm_widgets = ARRAY_SIZE(mt2701_wm8960_widgets), +}; + +static int mt2701_wm8960_machine_probe(struct platform_device *pdev) +{ + struct snd_soc_card *card = &mt2701_wm8960_card; + struct device_node *platform_node, *codec_node; + int ret, i; + + platform_node = of_parse_phandle(pdev->dev.of_node, + "mediatek,platform", 0); + if (!platform_node) { + dev_err(&pdev->dev, "Property 'platform' missing or invalid\n"); + return -EINVAL; + } + for (i = 0; i < card->num_links; i++) { + if (mt2701_wm8960_dai_links[i].platform_name) + continue; + mt2701_wm8960_dai_links[i].platform_of_node = platform_node; + } + + card->dev = &pdev->dev; + + codec_node = of_parse_phandle(pdev->dev.of_node, + "mediatek,audio-codec", 0); + if (!codec_node) { + dev_err(&pdev->dev, + "Property 'audio-codec' missing or invalid\n"); + return -EINVAL; + } + for (i = 0; i < card->num_links; i++) { + if (mt2701_wm8960_dai_links[i].codec_name) + continue; + mt2701_wm8960_dai_links[i].codec_of_node = codec_node; + } + + ret = snd_soc_of_parse_audio_routing(card, "audio-routing"); + if (ret) { + dev_err(&pdev->dev, "failed to parse audio-routing: %d\n", ret); + return ret; + } + + ret = devm_snd_soc_register_card(&pdev->dev, card); + if (ret) + dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n", + __func__, ret); + + return ret; +} + +#ifdef CONFIG_OF +static const struct of_device_id mt2701_wm8960_machine_dt_match[] = { + {.compatible = "mediatek,mt2701-wm8960-machine",}, + {} +}; +#endif + +static struct platform_driver mt2701_wm8960_machine = { + .driver = { + .name = "mt2701-wm8960", + .owner = THIS_MODULE, +#ifdef CONFIG_OF + .of_match_table = mt2701_wm8960_machine_dt_match, +#endif + }, + .probe = mt2701_wm8960_machine_probe, +}; + +module_platform_driver(mt2701_wm8960_machine); + +/* Module information */ +MODULE_DESCRIPTION("MT2701 WM8960 ALSA SoC machine driver"); +MODULE_AUTHOR("Ryder Lee "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("mt2701 wm8960 soc card"); + -- cgit v1.2.1 From e0c4211854bfebd5507761a2bfddaa9e37074230 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 28 Mar 2017 02:31:23 +0000 Subject: ASoC: rcar: remove rsnd_kctrl_remove() Current rcar driver is trying to remove kctrl when remove time. But, 1) rcar driver can't/shouldn't remove before removing sound card driver, 2) sound card driver will call snd_ctl_dev_free() and removes all kctrls by snd_ctl_remove(). Thus, rsnd_kctrl_remove() is not necessary. Current implementation will get Oops when removing rcar driver after sound card. This patch fix this issue. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 9 --------- sound/soc/sh/rcar/dvc.c | 16 ---------------- sound/soc/sh/rcar/rsnd.h | 3 --- 3 files changed, 28 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 3e852e00b277..134fe2ea4d9e 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -1039,15 +1039,6 @@ static int __rsnd_kctrl_new(struct rsnd_mod *mod, return 0; } -void _rsnd_kctrl_remove(struct rsnd_kctrl_cfg *cfg) -{ - if (cfg->card && cfg->kctrl) - snd_ctl_remove(cfg->card, cfg->kctrl); - - cfg->card = NULL; - cfg->kctrl = NULL; -} - int rsnd_kctrl_new_m(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct snd_soc_pcm_runtime *rtd, diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index cf8f59cdd8d7..994fdb7d0034 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -218,21 +218,6 @@ static int rsnd_dvc_probe_(struct rsnd_mod *mod, return rsnd_cmd_attach(io, rsnd_mod_id(mod)); } -static int rsnd_dvc_remove_(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); - - rsnd_kctrl_remove(dvc->volume); - rsnd_kctrl_remove(dvc->mute); - rsnd_kctrl_remove(dvc->ren); - rsnd_kctrl_remove(dvc->rup); - rsnd_kctrl_remove(dvc->rdown); - - return 0; -} - static int rsnd_dvc_init(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) @@ -332,7 +317,6 @@ static struct rsnd_mod_ops rsnd_dvc_ops = { .name = DVC_NAME, .dma_req = rsnd_dvc_dma_req, .probe = rsnd_dvc_probe_, - .remove = rsnd_dvc_remove_, .init = rsnd_dvc_init, .quit = rsnd_dvc_quit, .pcm_new = rsnd_dvc_pcm_new, diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 7410ec0174db..81ef3f18834a 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -611,9 +611,6 @@ struct rsnd_kctrl_cfg_s { u32 val; }; -void _rsnd_kctrl_remove(struct rsnd_kctrl_cfg *cfg); -#define rsnd_kctrl_remove(_cfg) _rsnd_kctrl_remove(&((_cfg).cfg)) - int rsnd_kctrl_new_m(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct snd_soc_pcm_runtime *rtd, -- cgit v1.2.1 From fd8ba1e3093e2f405df20c7f6c1150187ecdb18b Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Tue, 28 Mar 2017 11:58:51 +0300 Subject: ASoC: imx-wm8962: Let codec driver enable/disable its MCLK WM8962 needs its MCLK when powerup in wm8962_resume(). Thus it's better to control the MCLK in codec driver. Thus remove the clock enable in machine driver accordingly. While at it, get rid of imx_wm8962_remove function since it is now empty. Signed-off-by: Daniel Baluta Signed-off-by: Mark Brown --- sound/soc/fsl/imx-wm8962.c | 40 ++++++++-------------------------------- 1 file changed, 8 insertions(+), 32 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/fsl/imx-wm8962.c b/sound/soc/fsl/imx-wm8962.c index 1b60958e2080..3d894d9123e0 100644 --- a/sound/soc/fsl/imx-wm8962.c +++ b/sound/soc/fsl/imx-wm8962.c @@ -33,7 +33,6 @@ struct imx_wm8962_data { struct snd_soc_card card; char codec_dai_name[DAI_NAME_SIZE]; char platform_name[DAI_NAME_SIZE]; - struct clk *codec_clk; unsigned int clk_frequency; }; @@ -163,6 +162,7 @@ static int imx_wm8962_probe(struct platform_device *pdev) struct imx_priv *priv = &card_priv; struct i2c_client *codec_dev; struct imx_wm8962_data *data; + struct clk *codec_clk; int int_port, ext_port; int ret; @@ -231,19 +231,14 @@ static int imx_wm8962_probe(struct platform_device *pdev) goto fail; } - data->codec_clk = devm_clk_get(&codec_dev->dev, NULL); - if (IS_ERR(data->codec_clk)) { - ret = PTR_ERR(data->codec_clk); + codec_clk = devm_clk_get(&codec_dev->dev, NULL); + if (IS_ERR(codec_clk)) { + ret = PTR_ERR(codec_clk); dev_err(&codec_dev->dev, "failed to get codec clk: %d\n", ret); goto fail; } - data->clk_frequency = clk_get_rate(data->codec_clk); - ret = clk_prepare_enable(data->codec_clk); - if (ret) { - dev_err(&codec_dev->dev, "failed to enable codec clk: %d\n", ret); - goto fail; - } + data->clk_frequency = clk_get_rate(codec_clk); data->dai.name = "HiFi"; data->dai.stream_name = "HiFi"; @@ -258,10 +253,10 @@ static int imx_wm8962_probe(struct platform_device *pdev) data->card.dev = &pdev->dev; ret = snd_soc_of_parse_card_name(&data->card, "model"); if (ret) - goto clk_fail; + goto fail; ret = snd_soc_of_parse_audio_routing(&data->card, "audio-routing"); if (ret) - goto clk_fail; + goto fail; data->card.num_links = 1; data->card.owner = THIS_MODULE; data->card.dai_link = &data->dai; @@ -277,16 +272,9 @@ static int imx_wm8962_probe(struct platform_device *pdev) ret = devm_snd_soc_register_card(&pdev->dev, &data->card); if (ret) { dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); - goto clk_fail; + goto fail; } - of_node_put(ssi_np); - of_node_put(codec_np); - - return 0; - -clk_fail: - clk_disable_unprepare(data->codec_clk); fail: of_node_put(ssi_np); of_node_put(codec_np); @@ -294,17 +282,6 @@ fail: return ret; } -static int imx_wm8962_remove(struct platform_device *pdev) -{ - struct snd_soc_card *card = platform_get_drvdata(pdev); - struct imx_wm8962_data *data = snd_soc_card_get_drvdata(card); - - if (!IS_ERR(data->codec_clk)) - clk_disable_unprepare(data->codec_clk); - - return 0; -} - static const struct of_device_id imx_wm8962_dt_ids[] = { { .compatible = "fsl,imx-audio-wm8962", }, { /* sentinel */ } @@ -318,7 +295,6 @@ static struct platform_driver imx_wm8962_driver = { .of_match_table = imx_wm8962_dt_ids, }, .probe = imx_wm8962_probe, - .remove = imx_wm8962_remove, }; module_platform_driver(imx_wm8962_driver); -- cgit v1.2.1 From db22d189453cee666f8da2e67419f14f4b2fd9d1 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Tue, 28 Mar 2017 11:58:52 +0300 Subject: ASoC: imx-wm8962: Fix codec_clk cleanup Resource managed devm_clk_get only works with platform's device dev. Reported-by: Nicolin Chen Signed-off-by: Daniel Baluta Signed-off-by: Mark Brown --- sound/soc/fsl/imx-wm8962.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/fsl/imx-wm8962.c b/sound/soc/fsl/imx-wm8962.c index 3d894d9123e0..52659faa2eb9 100644 --- a/sound/soc/fsl/imx-wm8962.c +++ b/sound/soc/fsl/imx-wm8962.c @@ -231,7 +231,7 @@ static int imx_wm8962_probe(struct platform_device *pdev) goto fail; } - codec_clk = devm_clk_get(&codec_dev->dev, NULL); + codec_clk = clk_get(&codec_dev->dev, NULL); if (IS_ERR(codec_clk)) { ret = PTR_ERR(codec_clk); dev_err(&codec_dev->dev, "failed to get codec clk: %d\n", ret); @@ -239,6 +239,7 @@ static int imx_wm8962_probe(struct platform_device *pdev) } data->clk_frequency = clk_get_rate(codec_clk); + clk_put(codec_clk); data->dai.name = "HiFi"; data->dai.stream_name = "HiFi"; -- cgit v1.2.1 From 7f975a385b9313a03c13fb0be0a129c626f9a54e Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Fri, 24 Mar 2017 23:10:25 +0530 Subject: ASoC: Intel: Skylake: Use the sig_bits to define dai bps capability For calculating the HDA DMA format, use the max_bps supported by the DAI caps instead of fixing it to 32/24. For host DMA the Max bps support is 32, but in case of link DMA, this depends on the codec capability. So use the sig_bits to define the bps supported by dai. Signed-off-by: Jeeja KP Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-pcm.c | 25 ++++++++++++++++++++++--- sound/soc/intel/skylake/skl-topology.c | 2 ++ sound/soc/intel/skylake/skl-topology.h | 2 ++ 3 files changed, 26 insertions(+), 3 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 2f90bc40be77..3c61dbab3d4f 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -155,7 +155,7 @@ int skl_pcm_host_dma_prepare(struct device *dev, struct skl_pipe_params *params) snd_hdac_ext_stream_decouple(ebus, stream, true); format_val = snd_hdac_calc_stream_format(params->s_freq, - params->ch, params->format, 32, 0); + params->ch, params->format, params->host_bps, 0); dev_dbg(dev, "format_val=%d, rate=%d, ch=%d, format=%d\n", format_val, params->s_freq, params->ch, params->format); @@ -190,8 +190,8 @@ int skl_pcm_link_dma_prepare(struct device *dev, struct skl_pipe_params *params) stream = stream_to_hdac_ext_stream(hstream); snd_hdac_ext_stream_decouple(ebus, stream, true); - format_val = snd_hdac_calc_stream_format(params->s_freq, - params->ch, params->format, 24, 0); + format_val = snd_hdac_calc_stream_format(params->s_freq, params->ch, + params->format, params->link_bps, 0); dev_dbg(dev, "format_val=%d, rate=%d, ch=%d, format=%d\n", format_val, params->s_freq, params->ch, params->format); @@ -309,6 +309,11 @@ static int skl_pcm_hw_params(struct snd_pcm_substream *substream, p_params.host_dma_id = dma_id; p_params.stream = substream->stream; p_params.format = params_format(params); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + p_params.host_bps = dai->driver->playback.sig_bits; + else + p_params.host_bps = dai->driver->capture.sig_bits; + m_cfg = skl_tplg_fe_get_cpr_module(dai, p_params.stream); if (m_cfg) @@ -547,6 +552,11 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream, p_params.link_index = link->index; p_params.format = params_format(params); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + p_params.link_bps = codec_dai->driver->playback.sig_bits; + else + p_params.link_bps = codec_dai->driver->capture.sig_bits; + return skl_tplg_be_update_params(dai, &p_params); } @@ -652,6 +662,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_8000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, + .sig_bits = 32, }, .capture = { .stream_name = "System Capture", @@ -659,6 +670,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { .channels_max = HDA_STEREO, .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, + .sig_bits = 32, }, }, { @@ -670,6 +682,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { .channels_max = HDA_QUAD, .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, + .sig_bits = 32, }, }, { @@ -681,6 +694,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { .channels_max = HDA_STEREO, .rates = SNDRV_PCM_RATE_48000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, + .sig_bits = 32, }, }, { @@ -692,6 +706,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { .channels_max = HDA_STEREO, .rates = SNDRV_PCM_RATE_48000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, + .sig_bits = 32, }, }, { @@ -703,6 +718,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { .channels_max = HDA_QUAD, .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, + .sig_bits = 32, }, }, { @@ -718,6 +734,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { SNDRV_PCM_RATE_192000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, + .sig_bits = 32, }, }, { @@ -733,6 +750,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { SNDRV_PCM_RATE_192000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, + .sig_bits = 32, }, }, { @@ -748,6 +766,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { SNDRV_PCM_RATE_192000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, + .sig_bits = 32, }, }, diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index c6bd4bb49ec0..43f9cb380a76 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -1242,10 +1242,12 @@ static void skl_tplg_fill_dma_id(struct skl_module_cfg *mcfg, case SKL_DEVICE_HDALINK: pipe->p_params->link_dma_id = params->link_dma_id; pipe->p_params->link_index = params->link_index; + pipe->p_params->link_bps = params->link_bps; break; case SKL_DEVICE_HDAHOST: pipe->p_params->host_dma_id = params->host_dma_id; + pipe->p_params->host_bps = params->host_bps; break; default: diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h index fefab0e99a3b..bf2c63b4ab83 100644 --- a/sound/soc/intel/skylake/skl-topology.h +++ b/sound/soc/intel/skylake/skl-topology.h @@ -257,6 +257,8 @@ struct skl_pipe_params { snd_pcm_format_t format; int link_index; int stream; + unsigned int host_bps; + unsigned int link_bps; }; struct skl_pipe { -- cgit v1.2.1 From 66d6bbc6c0beb04c1dfeb0107d4d828f3e1959ee Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Fri, 24 Mar 2017 23:10:26 +0530 Subject: ASoC: hdac_hdmi: Update sig_bits based on converter capability When creating the codec dai, use sig_bits to update the max bps based on the codec capability. So both the link DMA and codec format will be calculated based on DAI sig_bits. So update the sig_bits with converter capability and use the sig_bits for HDA format calculation. Signed-off-by: Jeeja KP Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 78fca8acd3ec..5b7694721ef7 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -469,7 +469,7 @@ static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream, format = snd_hdac_calc_stream_format(params_rate(hparams), params_channels(hparams), params_format(hparams), - 24, 0); + dai->driver->playback.sig_bits, 0); pcm = hdac_hdmi_get_pcm_from_cvt(hdmi, dai_map->cvt); if (!pcm) @@ -1419,8 +1419,8 @@ static int hdac_hdmi_create_dais(struct hdac_device *hdac, hdmi_dais[i].playback.rate_min = rate_min; hdmi_dais[i].playback.channels_min = 2; hdmi_dais[i].playback.channels_max = 2; + hdmi_dais[i].playback.sig_bits = bps; hdmi_dais[i].ops = &hdmi_dai_ops; - i++; } -- cgit v1.2.1 From e59ed0875b0681ebd1e5062b739742f98f24274c Mon Sep 17 00:00:00 2001 From: G Kranthi Date: Fri, 24 Mar 2017 23:10:27 +0530 Subject: ASoC: Intel: Skylake: Add 16-bit constraint to FE bxt_rt298 machine Add constraint to FE to restrict sample format to 16-bit for bxt_rt298 machine Signed-off-by: G Kranthi Signed-off-by: Jeeja KP Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/boards/bxt_rt298.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/intel/boards/bxt_rt298.c b/sound/soc/intel/boards/bxt_rt298.c index 176c080a9818..1a68d043c803 100644 --- a/sound/soc/intel/boards/bxt_rt298.c +++ b/sound/soc/intel/boards/bxt_rt298.c @@ -274,12 +274,15 @@ static int bxt_fe_startup(struct snd_pcm_substream *substream) * on this platform for PCM device we support: * 48Khz * stereo + * 16-bit audio */ runtime->hw.channels_max = 2; snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, &constraints_channels); + runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; + snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16); snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); -- cgit v1.2.1 From f7ea77772dfaa404ac0bcdea5c262c24e8b860db Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 24 Mar 2017 23:10:28 +0530 Subject: ASoC: Intel: Skylake: Don't unload module when in use A module may have multiple instances in DSP, so unload only when usage count is zero. Signed-off-by: Vinod Koul Signed-off-by: Jeeja KP Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-sst.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/intel/skylake/skl-sst.c b/sound/soc/intel/skylake/skl-sst.c index 39d4aaac73bf..539529729e3f 100644 --- a/sound/soc/intel/skylake/skl-sst.c +++ b/sound/soc/intel/skylake/skl-sst.c @@ -417,6 +417,11 @@ static int skl_unload_module(struct sst_dsp *ctx, u16 mod_id) dev_err(ctx->dev, "Module bad usage cnt!:%d\n", usage_cnt); return -EIO; } + + /* if module is used by others return, no need to unload */ + if (usage_cnt > 0) + return 0; + ret = skl_ipc_unload_modules(&skl->ipc, SKL_NUM_MODULES, &mod_id); if (ret < 0) { -- cgit v1.2.1 From 9a1e350709492cf512a3c4781915d567b34f8d26 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 24 Mar 2017 23:10:29 +0530 Subject: ASoC: Intel: Skylake: Remove redundant vmixer handler Initially vmixer and mixer widget handlers were bit different, but over time they became same so remove the duplicate code. Signed-off-by: Vinod Koul Signed-off-by: Jeeja KP Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-topology.c | 32 +------------------------------- 1 file changed, 1 insertion(+), 31 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index 43f9cb380a76..35d9d7b43dd2 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -1072,36 +1072,6 @@ static int skl_tplg_pga_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, return ret; } -/* - * In modelling, we assume there will be ONLY one mixer in a pipeline. If - * mixer is not required then it is treated as static mixer aka vmixer with - * a hard path to source module - * So we don't need to check if source is started or not as hard path puts - * dependency on each other - */ -static int skl_tplg_vmixer_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event) -{ - struct snd_soc_dapm_context *dapm = w->dapm; - struct skl *skl = get_skl_ctx(dapm->dev); - - switch (event) { - case SND_SOC_DAPM_PRE_PMU: - return skl_tplg_mixer_dapm_pre_pmu_event(w, skl); - - case SND_SOC_DAPM_POST_PMU: - return skl_tplg_mixer_dapm_post_pmu_event(w, skl); - - case SND_SOC_DAPM_PRE_PMD: - return skl_tplg_mixer_dapm_pre_pmd_event(w, skl); - - case SND_SOC_DAPM_POST_PMD: - return skl_tplg_mixer_dapm_post_pmd_event(w, skl); - } - - return 0; -} - /* * In modelling, we assume there will be ONLY one mixer in a pipeline. If a * second one is required that is created as another pipe entity. @@ -1570,7 +1540,7 @@ int skl_tplg_be_update_params(struct snd_soc_dai *dai, static const struct snd_soc_tplg_widget_events skl_tplg_widget_ops[] = { {SKL_MIXER_EVENT, skl_tplg_mixer_event}, - {SKL_VMIXER_EVENT, skl_tplg_vmixer_event}, + {SKL_VMIXER_EVENT, skl_tplg_mixer_event}, {SKL_PGA_EVENT, skl_tplg_pga_event}, }; -- cgit v1.2.1 From 6ad0005f179fded911e69f54f96c03e5f8cbf67a Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 24 Mar 2017 23:10:30 +0530 Subject: ASoC: Intel: Skylake: remove hard coded ACPI path We should not hard code the ACPI path to get acpi_handle. Instead use ACPI_HANDLE macro to do the job. Signed-off-by: Vinod Koul Signed-off-by: Jeeja KP Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-nhlt.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/intel/skylake/skl-nhlt.c b/sound/soc/intel/skylake/skl-nhlt.c index 7eb9c419dc7f..e3f06672fd6d 100644 --- a/sound/soc/intel/skylake/skl-nhlt.c +++ b/sound/soc/intel/skylake/skl-nhlt.c @@ -24,8 +24,6 @@ static u8 OSC_UUID[16] = {0x6E, 0x88, 0x9F, 0xA6, 0xEB, 0x6C, 0x94, 0x45, 0xA4, 0x1F, 0x7B, 0x5D, 0xCE, 0x24, 0xC5, 0x53}; -#define DSDT_NHLT_PATH "\\_SB.PCI0.HDAS" - struct nhlt_acpi_table *skl_nhlt_init(struct device *dev) { acpi_handle handle; @@ -33,8 +31,9 @@ struct nhlt_acpi_table *skl_nhlt_init(struct device *dev) struct nhlt_resource_desc *nhlt_ptr = NULL; struct nhlt_acpi_table *nhlt_table = NULL; - if (ACPI_FAILURE(acpi_get_handle(NULL, DSDT_NHLT_PATH, &handle))) { - dev_err(dev, "Requested NHLT device not found\n"); + handle = ACPI_HANDLE(dev); + if (!handle) { + dev_err(dev, "Didn't find ACPI_HANDLE\n"); return NULL; } -- cgit v1.2.1 From b26199eae86f7a1c2363d049249c3be33694f93b Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Fri, 24 Mar 2017 23:10:31 +0530 Subject: ASoC: Intel: Skylake: Rearrangement of code to cleanup SKL SST library Skylake driver topology header/driver structure is referenced and used in SST library which creates circular dependency. Hence the rearrangement. Signed-off-by: Jeeja KP Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-pcm.c | 35 +++++++++++++++---- sound/soc/intel/skylake/skl-sst-dsp.h | 24 +++++++++---- sound/soc/intel/skylake/skl-sst-ipc.h | 8 +++++ sound/soc/intel/skylake/skl-sst-utils.c | 60 +++++---------------------------- sound/soc/intel/skylake/skl-topology.c | 11 ++++-- sound/soc/intel/skylake/skl-topology.h | 13 ------- 6 files changed, 70 insertions(+), 81 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 3c61dbab3d4f..ef440d8629e8 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -1174,29 +1174,52 @@ static int skl_pcm_new(struct snd_soc_pcm_runtime *rtd) return retval; } +static int skl_get_module_info(struct skl *skl, struct skl_module_cfg *mconfig) +{ + struct skl_sst *ctx = skl->skl_sst; + struct uuid_module *module; + uuid_le *uuid_mod; + + uuid_mod = (uuid_le *)mconfig->guid; + + if (list_empty(&ctx->uuid_list)) { + dev_err(ctx->dev, "Module list is empty\n"); + return -EIO; + } + + list_for_each_entry(module, &ctx->uuid_list, list) { + if (uuid_le_cmp(*uuid_mod, module->uuid) == 0) { + mconfig->id.module_id = module->id; + mconfig->is_loadable = module->is_loadable; + return 0; + } + } + + return -EIO; +} + static int skl_populate_modules(struct skl *skl) { struct skl_pipeline *p; struct skl_pipe_module *m; struct snd_soc_dapm_widget *w; struct skl_module_cfg *mconfig; - int ret; + int ret = 0; list_for_each_entry(p, &skl->ppl_list, node) { list_for_each_entry(m, &p->pipe->w_list, node) { - w = m->w; mconfig = w->priv; - ret = snd_skl_get_module_info(skl->skl_sst, mconfig); + ret = skl_get_module_info(skl, mconfig); if (ret < 0) { dev_err(skl->skl_sst->dev, - "query module info failed:%d\n", ret); - goto err; + "query module info failed\n"); + return ret; } } } -err: + return ret; } diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h index 5d7a93aa5bed..7229a12b4c94 100644 --- a/sound/soc/intel/skylake/skl-sst-dsp.h +++ b/sound/soc/intel/skylake/skl-sst-dsp.h @@ -17,13 +17,14 @@ #define __SKL_SST_DSP_H__ #include +#include #include #include "skl-sst-cldma.h" -#include "skl-topology.h" struct sst_dsp; struct skl_sst; struct sst_dsp_device; +struct skl_lib_info; /* Intel HD Audio General DSP Registers */ #define SKL_ADSP_GEN_BASE 0x0 @@ -172,6 +173,19 @@ struct skl_dsp_loader_ops { int stream_tag); }; +#define MAX_INSTANCE_BUFF 2 + +struct uuid_module { + uuid_le uuid; + int id; + int is_loadable; + int max_instance; + u64 pvt_id[MAX_INSTANCE_BUFF]; + int *instance_id; + + struct list_head list; +}; + struct skl_load_module_info { u16 mod_id; const struct firmware *fw; @@ -223,14 +237,10 @@ int bxt_sst_init_fw(struct device *dev, struct skl_sst *ctx); void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx); void bxt_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx); -int snd_skl_get_module_info(struct skl_sst *ctx, - struct skl_module_cfg *mconfig); int snd_skl_parse_uuids(struct sst_dsp *ctx, const struct firmware *fw, unsigned int offset, int index); -int skl_get_pvt_id(struct skl_sst *ctx, - struct skl_module_cfg *mconfig); -int skl_put_pvt_id(struct skl_sst *ctx, - struct skl_module_cfg *mconfig); +int skl_get_pvt_id(struct skl_sst *ctx, uuid_le *uuid_mod, int instance_id); +int skl_put_pvt_id(struct skl_sst *ctx, uuid_le *uuid_mod, int *pvt_id); int skl_get_pvt_instance_id_map(struct skl_sst *ctx, int module_id, int instance_id); void skl_freeup_uuid_list(struct skl_sst *ctx); diff --git a/sound/soc/intel/skylake/skl-sst-ipc.h b/sound/soc/intel/skylake/skl-sst-ipc.h index fc07c397b060..4abf98c0e00e 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.h +++ b/sound/soc/intel/skylake/skl-sst-ipc.h @@ -69,6 +69,14 @@ struct skl_d0i3_data { struct delayed_work work; }; +#define SKL_LIB_NAME_LENGTH 128 +#define SKL_MAX_LIB 16 + +struct skl_lib_info { + char name[SKL_LIB_NAME_LENGTH]; + const struct firmware *fw; +}; + struct skl_sst { struct device *dev; struct sst_dsp *dsp; diff --git a/sound/soc/intel/skylake/skl-sst-utils.c b/sound/soc/intel/skylake/skl-sst-utils.c index ea162fbf68e5..6d5bff04bf65 100644 --- a/sound/soc/intel/skylake/skl-sst-utils.c +++ b/sound/soc/intel/skylake/skl-sst-utils.c @@ -94,19 +94,6 @@ struct adsp_fw_hdr { u32 load_offset; } __packed; -#define MAX_INSTANCE_BUFF 2 - -struct uuid_module { - uuid_le uuid; - int id; - int is_loadable; - int max_instance; - u64 pvt_id[MAX_INSTANCE_BUFF]; - int *instance_id; - - struct list_head list; -}; - struct skl_ext_manifest_hdr { u32 id; u32 len; @@ -115,32 +102,6 @@ struct skl_ext_manifest_hdr { u32 entries; }; -int snd_skl_get_module_info(struct skl_sst *ctx, - struct skl_module_cfg *mconfig) -{ - struct uuid_module *module; - uuid_le *uuid_mod; - - uuid_mod = (uuid_le *)mconfig->guid; - - if (list_empty(&ctx->uuid_list)) { - dev_err(ctx->dev, "Module list is empty\n"); - return -EINVAL; - } - - list_for_each_entry(module, &ctx->uuid_list, list) { - if (uuid_le_cmp(*uuid_mod, module->uuid) == 0) { - mconfig->id.module_id = module->id; - mconfig->is_loadable = module->is_loadable; - - return 0; - } - } - - return -EINVAL; -} -EXPORT_SYMBOL_GPL(snd_skl_get_module_info); - static int skl_get_pvtid_map(struct uuid_module *module, int instance_id) { int pvt_id; @@ -222,21 +183,18 @@ static inline int skl_pvtid_128(struct uuid_module *module) * This generates a 128 bit private unique id for a module TYPE so that * module instance is unique */ -int skl_get_pvt_id(struct skl_sst *ctx, struct skl_module_cfg *mconfig) +int skl_get_pvt_id(struct skl_sst *ctx, uuid_le *uuid_mod, int instance_id) { struct uuid_module *module; - uuid_le *uuid_mod; int pvt_id; - uuid_mod = (uuid_le *)mconfig->guid; - list_for_each_entry(module, &ctx->uuid_list, list) { if (uuid_le_cmp(*uuid_mod, module->uuid) == 0) { pvt_id = skl_pvtid_128(module); if (pvt_id >= 0) { - module->instance_id[pvt_id] = - mconfig->id.instance_id; + module->instance_id[pvt_id] = instance_id; + return pvt_id; } } @@ -254,23 +212,21 @@ EXPORT_SYMBOL_GPL(skl_get_pvt_id); * * This frees a 128 bit private unique id previously generated */ -int skl_put_pvt_id(struct skl_sst *ctx, struct skl_module_cfg *mconfig) +int skl_put_pvt_id(struct skl_sst *ctx, uuid_le *uuid_mod, int *pvt_id) { int i; - uuid_le *uuid_mod; struct uuid_module *module; - uuid_mod = (uuid_le *)mconfig->guid; list_for_each_entry(module, &ctx->uuid_list, list) { if (uuid_le_cmp(*uuid_mod, module->uuid) == 0) { - if (mconfig->id.pvt_id != 0) - i = (mconfig->id.pvt_id) / 64; + if (*pvt_id != 0) + i = (*pvt_id) / 64; else i = 0; - module->pvt_id[i] &= ~(1 << (mconfig->id.pvt_id)); - mconfig->id.pvt_id = -1; + module->pvt_id[i] &= ~(1 << (*pvt_id)); + *pvt_id = -1; return 0; } } diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index 35d9d7b43dd2..8bd5ded98cec 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -539,6 +539,7 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe) int ret = 0; list_for_each_entry(w_module, &pipe->w_list, node) { + uuid_le *uuid_mod; w = w_module->w; mconfig = w->priv; @@ -576,13 +577,15 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe) * FE/BE params */ skl_tplg_update_module_params(w, ctx); - mconfig->id.pvt_id = skl_get_pvt_id(ctx, mconfig); + uuid_mod = (uuid_le *)mconfig->guid; + mconfig->id.pvt_id = skl_get_pvt_id(ctx, uuid_mod, + mconfig->id.instance_id); if (mconfig->id.pvt_id < 0) return ret; skl_tplg_set_module_init_data(w); ret = skl_init_module(ctx, mconfig); if (ret < 0) { - skl_put_pvt_id(ctx, mconfig); + skl_put_pvt_id(ctx, uuid_mod, &mconfig->id.pvt_id); return ret; } skl_tplg_alloc_pipe_mcps(skl, mconfig); @@ -602,7 +605,9 @@ static int skl_tplg_unload_pipe_modules(struct skl_sst *ctx, struct skl_module_cfg *mconfig = NULL; list_for_each_entry(w_module, &pipe->w_list, node) { + uuid_le *uuid_mod; mconfig = w_module->w->priv; + uuid_mod = (uuid_le *)mconfig->guid; if (mconfig->is_loadable && ctx->dsp->fw_ops.unload_mod && mconfig->m_state > SKL_MODULE_UNINIT) { @@ -611,7 +616,7 @@ static int skl_tplg_unload_pipe_modules(struct skl_sst *ctx, if (ret < 0) return -EIO; } - skl_put_pvt_id(ctx, mconfig); + skl_put_pvt_id(ctx, uuid_mod, &mconfig->id.pvt_id); } /* no modules to unload in this path, so return */ diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h index bf2c63b4ab83..8536d03a7778 100644 --- a/sound/soc/intel/skylake/skl-topology.h +++ b/sound/soc/intel/skylake/skl-topology.h @@ -336,19 +336,6 @@ struct skl_pipeline { struct list_head node; }; -#define SKL_LIB_NAME_LENGTH 128 -#define SKL_MAX_LIB 16 - -struct skl_lib_info { - char name[SKL_LIB_NAME_LENGTH]; - const struct firmware *fw; -}; - -struct skl_manifest { - u32 lib_count; - struct skl_lib_info lib[SKL_MAX_LIB]; -}; - static inline struct skl *get_skl_ctx(struct device *dev) { struct hdac_ext_bus *ebus = dev_get_drvdata(dev); -- cgit v1.2.1 From fdd85a054b850db43c6abe39c1da28b581be5e93 Mon Sep 17 00:00:00 2001 From: Hardik T Shah Date: Fri, 24 Mar 2017 23:10:32 +0530 Subject: ASoC: Intel: Skylake: Fix DMA position reporting for capture stream As per hardware recommendation, for every capture stream completion following operations need to be done in order to reflect the actual data that is received in position buffer. 1. Wait for 20us before reading the DMA position in buffer once the interrupt is generated for stream completion. 2. Read any of the register to flush the DMA position value. This is dummy read operation. Signed-off-by: Dharageswari R Signed-off-by: Hardik T Shah Signed-off-by: Jeeja KP Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-pcm.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index ef440d8629e8..1823197c15c8 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -21,6 +21,7 @@ #include #include +#include #include #include #include "skl.h" @@ -1063,13 +1064,31 @@ static snd_pcm_uframes_t skl_platform_pcm_pointer * HAD space reflects the actual data that is transferred. * Use the position buffer for capture, as DPIB write gets * completed earlier than the actual data written to the DDR. + * + * For capture stream following workaround is required to fix the + * incorrect position reporting. + * + * 1. Wait for 20us before reading the DMA position in buffer once + * the interrupt is generated for stream completion as update happens + * on the HDA frame boundary i.e. 20.833uSec. + * 2. Read DPIB register to flush the DMA position value. This dummy + * read is required to flush DMA position value. + * 3. Read the DMA Position-in-Buffer. This value now will be equal to + * or greater than period boundary. */ - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { pos = readl(ebus->bus.remap_addr + AZX_REG_VS_SDXDPIB_XBASE + (AZX_REG_VS_SDXDPIB_XINTERVAL * hdac_stream(hstream)->index)); - else + } else { + udelay(20); + readl(ebus->bus.remap_addr + + AZX_REG_VS_SDXDPIB_XBASE + + (AZX_REG_VS_SDXDPIB_XINTERVAL * + hdac_stream(hstream)->index)); pos = snd_hdac_stream_get_pos_posbuf(hdac_stream(hstream)); + } if (pos >= hdac_stream(hstream)->bufsize) pos = 0; -- cgit v1.2.1 From 473a4d516cfe6d0668cf7223aa3002ae8367349b Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Fri, 24 Mar 2017 23:10:33 +0530 Subject: ASoC: Intel: Skylake: Fix module state after unbind and delete When DSP module is unbound, the module state needs to be in INIT_DONE state instead of UNINT. Also the state needs to be set to UNINIT after module is deleted from DSP pipeline. So, set the module state to INIT_DONE after unbind and then UNINIT after module is deleted. Signed-off-by: Jeeja KP Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-messages.c | 2 +- sound/soc/intel/skylake/skl-topology.c | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index ba1ec973ded7..09730dd8e6a3 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -862,7 +862,7 @@ static void skl_clear_module_state(struct skl_module_pin *mpin, int max, } if (!found) - mcfg->m_state = SKL_MODULE_UNINIT; + mcfg->m_state = SKL_MODULE_INIT_DONE; return; } diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index 8bd5ded98cec..e960d9f761b9 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -1037,6 +1037,11 @@ static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, skl_delete_pipe(ctx, mconfig->pipe); + list_for_each_entry(w_module, &s_pipe->w_list, node) { + src_module = w_module->w->priv; + src_module->m_state = SKL_MODULE_UNINIT; + } + return skl_tplg_unload_pipe_modules(ctx, s_pipe); } -- cgit v1.2.1 From 5f75b19ef99054736aa80b70dbdf2f7a86a22007 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 30 Mar 2017 11:09:34 +0100 Subject: ASoC: Intel: bxtn: fix spelling mistake: "Timout" -> "Timeout" trivial fix to spelling mistake in dev_err error message Signed-off-by: Colin Ian King Signed-off-by: Mark Brown --- sound/soc/intel/skylake/bxt-sst.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/intel/skylake/bxt-sst.c b/sound/soc/intel/skylake/bxt-sst.c index 600d95891996..268bdaec8042 100644 --- a/sound/soc/intel/skylake/bxt-sst.c +++ b/sound/soc/intel/skylake/bxt-sst.c @@ -171,7 +171,7 @@ static int sst_bxt_prepare_fw(struct sst_dsp *ctx, SKL_ADSP_REG_HIPCIE_DONE, BXT_INIT_TIMEOUT, "HIPCIE Done"); if (ret < 0) { - dev_err(ctx->dev, "Timout for Purge Request%d\n", ret); + dev_err(ctx->dev, "Timeout for Purge Request%d\n", ret); goto base_fw_load_failed; } -- cgit v1.2.1 From d7f298197a22f11b38059f257842dac7c30a564c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 30 Mar 2017 01:49:06 +0000 Subject: ASoC: rcar: fixup of_clk_add_provider() usage for multi clkout Current adg is calling of_clk_add_povider() multiple times, but it is not correct usage. This patch fixup its parameter and call it once. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/adg.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index 85a33ac0a5c4..56107454bdb3 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -537,16 +537,14 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv, clk = clk_register_fixed_rate(dev, clkout_name[i], parent_clk_name, 0, req_rate); - if (!IS_ERR(clk)) { - adg->onecell.clks = adg->clkout; - adg->onecell.clk_num = CLKOUTMAX; - + adg->clkout[i] = ERR_PTR(-ENOENT); + if (!IS_ERR(clk)) adg->clkout[i] = clk; - - of_clk_add_provider(np, of_clk_src_onecell_get, - &adg->onecell); - } } + adg->onecell.clks = adg->clkout; + adg->onecell.clk_num = CLKOUTMAX; + of_clk_add_provider(np, of_clk_src_onecell_get, + &adg->onecell); } adg->ckr = ckr; -- cgit v1.2.1 From b5aac5a9adf667f907c34c520e023bc19f8c226c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 30 Mar 2017 01:49:27 +0000 Subject: ASoC: rcar: call missing of_clk_del_provider() when remove adg is calling of_clk_add_provider() when probe time, thus, remove should call of_clk_del_provider(), it doesn't now. This patch fix this issue. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/adg.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index 56107454bdb3..9665c1fa7216 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -587,5 +587,10 @@ int rsnd_adg_probe(struct rsnd_priv *priv) void rsnd_adg_remove(struct rsnd_priv *priv) { + struct device *dev = rsnd_priv_to_dev(priv); + struct device_node *np = dev->of_node; + + of_clk_del_provider(np); + rsnd_adg_clk_disable(priv); } -- cgit v1.2.1 From 0636e8b380418bda5b52bb06c8ae285028de3793 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 3 Apr 2017 13:12:39 +0300 Subject: ASoC: twl6040: Add control for HS and HF mono to stereo selection The new controls will give user the ability to route the left PDM channel data to the right headset/handsfree DAC. HS mono to stereo switch: PDM channel 1 (or mono) data to both HS DAC. HF mono to stereo switch: PDM channel 3 data to both HF DAC. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/twl6040.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c index 748036e851ea..2b6ad09e0886 100644 --- a/sound/soc/codecs/twl6040.c +++ b/sound/soc/codecs/twl6040.c @@ -606,6 +606,14 @@ static const struct snd_kcontrol_new twl6040_snd_controls[] = { twl6040_headset_power_get_enum, twl6040_headset_power_put_enum), + /* Left HS PDM data routed to Right HSDAC */ + SOC_SINGLE("Headset Mono to Stereo Playback Switch", + TWL6040_REG_HSRCTL, 7, 1, 0), + + /* Left HF PDM data routed to Right HFDAC */ + SOC_SINGLE("Handsfree Mono to Stereo Playback Switch", + TWL6040_REG_HFRCTL, 5, 1, 0), + SOC_ENUM_EXT("PLL Selection", twl6040_power_mode_enum, twl6040_pll_get_enum, twl6040_pll_put_enum), }; -- cgit v1.2.1 From e1ea1879f2889a26370bd0bc29c1e95caf9d36f2 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Wed, 5 Apr 2017 11:07:59 +0100 Subject: ASoC: wm_adsp: Add support for ADSP2V2 Adds support for ADSP2V2 cores. Primary differences are that they use a 32-bit register map compared to the 16-bit register map of ADSP2V1, and there are some changes to clocking control. Signed-off-by: Richard Fitzgerald Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 187 ++++++++++++++++++++++++++++++++++----------- sound/soc/codecs/wm_adsp.h | 1 + 2 files changed, 145 insertions(+), 43 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index bbdb72f73df1..a9acf222b502 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -112,17 +112,22 @@ #define ADSP1_CLK_SEL_SHIFT 0 /* CLK_SEL_ENA */ #define ADSP1_CLK_SEL_WIDTH 3 /* CLK_SEL_ENA */ -#define ADSP2_CONTROL 0x0 -#define ADSP2_CLOCKING 0x1 -#define ADSP2_STATUS1 0x4 -#define ADSP2_WDMA_CONFIG_1 0x30 -#define ADSP2_WDMA_CONFIG_2 0x31 -#define ADSP2_RDMA_CONFIG_1 0x34 - -#define ADSP2_SCRATCH0 0x40 -#define ADSP2_SCRATCH1 0x41 -#define ADSP2_SCRATCH2 0x42 -#define ADSP2_SCRATCH3 0x43 +#define ADSP2_CONTROL 0x0 +#define ADSP2_CLOCKING 0x1 +#define ADSP2V2_CLOCKING 0x2 +#define ADSP2_STATUS1 0x4 +#define ADSP2_WDMA_CONFIG_1 0x30 +#define ADSP2_WDMA_CONFIG_2 0x31 +#define ADSP2V2_WDMA_CONFIG_2 0x32 +#define ADSP2_RDMA_CONFIG_1 0x34 + +#define ADSP2_SCRATCH0 0x40 +#define ADSP2_SCRATCH1 0x41 +#define ADSP2_SCRATCH2 0x42 +#define ADSP2_SCRATCH3 0x43 + +#define ADSP2V2_SCRATCH0_1 0x40 +#define ADSP2V2_SCRATCH2_3 0x42 /* * ADSP2 Control @@ -152,6 +157,17 @@ #define ADSP2_CLK_SEL_SHIFT 0 /* CLK_SEL_ENA */ #define ADSP2_CLK_SEL_WIDTH 3 /* CLK_SEL_ENA */ +/* + * ADSP2V2 clocking + */ +#define ADSP2V2_CLK_SEL_MASK 0x70000 /* CLK_SEL_ENA */ +#define ADSP2V2_CLK_SEL_SHIFT 16 /* CLK_SEL_ENA */ +#define ADSP2V2_CLK_SEL_WIDTH 3 /* CLK_SEL_ENA */ + +#define ADSP2V2_RATE_MASK 0x7800 /* DSP_RATE */ +#define ADSP2V2_RATE_SHIFT 11 /* DSP_RATE */ +#define ADSP2V2_RATE_WIDTH 4 /* DSP_RATE */ + /* * ADSP2 Status 1 */ @@ -683,6 +699,9 @@ static const struct soc_enum wm_adsp_fw_enum[] = { SOC_ENUM_SINGLE(0, 1, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text), SOC_ENUM_SINGLE(0, 2, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text), SOC_ENUM_SINGLE(0, 3, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text), + SOC_ENUM_SINGLE(0, 4, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text), + SOC_ENUM_SINGLE(0, 5, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text), + SOC_ENUM_SINGLE(0, 6, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text), }; const struct snd_kcontrol_new wm_adsp_fw_controls[] = { @@ -694,6 +713,12 @@ const struct snd_kcontrol_new wm_adsp_fw_controls[] = { wm_adsp_fw_get, wm_adsp_fw_put), SOC_ENUM_EXT("DSP4 Firmware", wm_adsp_fw_enum[3], wm_adsp_fw_get, wm_adsp_fw_put), + SOC_ENUM_EXT("DSP5 Firmware", wm_adsp_fw_enum[4], + wm_adsp_fw_get, wm_adsp_fw_put), + SOC_ENUM_EXT("DSP6 Firmware", wm_adsp_fw_enum[5], + wm_adsp_fw_get, wm_adsp_fw_put), + SOC_ENUM_EXT("DSP7 Firmware", wm_adsp_fw_enum[6], + wm_adsp_fw_get, wm_adsp_fw_put), }; EXPORT_SYMBOL_GPL(wm_adsp_fw_controls); @@ -750,6 +775,29 @@ static void wm_adsp2_show_fw_status(struct wm_adsp *dsp) be16_to_cpu(scratch[3])); } +static void wm_adsp2v2_show_fw_status(struct wm_adsp *dsp) +{ + u32 scratch[2]; + int ret; + + ret = regmap_raw_read(dsp->regmap, dsp->base + ADSP2V2_SCRATCH0_1, + scratch, sizeof(scratch)); + + if (ret) { + adsp_err(dsp, "Failed to read SCRATCH regs: %d\n", ret); + return; + } + + scratch[0] = be32_to_cpu(scratch[0]); + scratch[1] = be32_to_cpu(scratch[1]); + + adsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n", + scratch[0] & 0xFFFF, + scratch[0] >> 16, + scratch[1] & 0xFFFF, + scratch[1] >> 16); +} + static inline struct wm_coeff_ctl *bytes_ext_to_ctl(struct soc_bytes_ext *ext) { return container_of(ext, struct wm_coeff_ctl, bytes_ext); @@ -2435,10 +2483,17 @@ static int wm_adsp2_ena(struct wm_adsp *dsp) unsigned int val; int ret, count; - ret = regmap_update_bits_async(dsp->regmap, dsp->base + ADSP2_CONTROL, - ADSP2_SYS_ENA, ADSP2_SYS_ENA); - if (ret != 0) - return ret; + switch (dsp->rev) { + case 0: + ret = regmap_update_bits_async(dsp->regmap, + dsp->base + ADSP2_CONTROL, + ADSP2_SYS_ENA, ADSP2_SYS_ENA); + if (ret != 0) + return ret; + break; + default: + break; + } /* Wait for the RAM to start, should be near instantaneous */ for (count = 0; count < 10; ++count) { @@ -2497,11 +2552,17 @@ static void wm_adsp2_boot_work(struct work_struct *work) if (ret != 0) goto err_ena; - /* Turn DSP back off until we are ready to run */ - ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, - ADSP2_SYS_ENA, 0); - if (ret != 0) - goto err_ena; + switch (dsp->rev) { + case 0: + /* Turn DSP back off until we are ready to run */ + ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, + ADSP2_SYS_ENA, 0); + if (ret != 0) + goto err_ena; + break; + default: + break; + } dsp->booted = true; @@ -2523,12 +2584,21 @@ static void wm_adsp2_set_dspclk(struct wm_adsp *dsp, unsigned int freq) { int ret; - ret = regmap_update_bits_async(dsp->regmap, - dsp->base + ADSP2_CLOCKING, - ADSP2_CLK_SEL_MASK, - freq << ADSP2_CLK_SEL_SHIFT); - if (ret != 0) - adsp_err(dsp, "Failed to set clock rate: %d\n", ret); + switch (dsp->rev) { + case 0: + ret = regmap_update_bits_async(dsp->regmap, + dsp->base + ADSP2_CLOCKING, + ADSP2_CLK_SEL_MASK, + freq << ADSP2_CLK_SEL_SHIFT); + if (ret) { + adsp_err(dsp, "Failed to set clock rate: %d\n", ret); + return; + } + break; + default: + /* clock is handled by parent codec driver */ + break; + } } int wm_adsp2_preloader_get(struct snd_kcontrol *kcontrol, @@ -2664,22 +2734,46 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, wm_adsp_signal_event_controls(dsp, WM_ADSP_FW_EVENT_SHUTDOWN); /* Log firmware state, it can be useful for analysis */ - wm_adsp2_show_fw_status(dsp); + switch (dsp->rev) { + case 0: + wm_adsp2_show_fw_status(dsp); + break; + default: + wm_adsp2v2_show_fw_status(dsp); + break; + } mutex_lock(&dsp->pwr_lock); dsp->running = false; - regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, + regmap_update_bits(dsp->regmap, + dsp->base + ADSP2_CONTROL, ADSP2_CORE_ENA | ADSP2_START, 0); /* Make sure DMAs are quiesced */ - regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0); - regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_1, 0); - regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_2, 0); - - regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, - ADSP2_SYS_ENA, 0); + switch (dsp->rev) { + case 0: + regmap_write(dsp->regmap, + dsp->base + ADSP2_RDMA_CONFIG_1, 0); + regmap_write(dsp->regmap, + dsp->base + ADSP2_WDMA_CONFIG_1, 0); + regmap_write(dsp->regmap, + dsp->base + ADSP2_WDMA_CONFIG_2, 0); + + regmap_update_bits(dsp->regmap, + dsp->base + ADSP2_CONTROL, + ADSP2_SYS_ENA, 0); + break; + default: + regmap_write(dsp->regmap, + dsp->base + ADSP2_RDMA_CONFIG_1, 0); + regmap_write(dsp->regmap, + dsp->base + ADSP2_WDMA_CONFIG_1, 0); + regmap_write(dsp->regmap, + dsp->base + ADSP2V2_WDMA_CONFIG_2, 0); + break; + } if (wm_adsp_fw[dsp->fw].num_caps != 0) wm_adsp_buffer_free(dsp); @@ -2732,15 +2826,22 @@ int wm_adsp2_init(struct wm_adsp *dsp) { int ret; - /* - * Disable the DSP memory by default when in reset for a small - * power saving. - */ - ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, - ADSP2_MEM_ENA, 0); - if (ret != 0) { - adsp_err(dsp, "Failed to clear memory retention: %d\n", ret); - return ret; + switch (dsp->rev) { + case 0: + /* + * Disable the DSP memory by default when in reset for a small + * power saving. + */ + ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, + ADSP2_MEM_ENA, 0); + if (ret) { + adsp_err(dsp, + "Failed to clear memory retention: %d\n", ret); + return ret; + } + break; + default: + break; } INIT_LIST_HEAD(&dsp->alg_regions); diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h index 3706b11053a3..997227f4d404 100644 --- a/sound/soc/codecs/wm_adsp.h +++ b/sound/soc/codecs/wm_adsp.h @@ -40,6 +40,7 @@ struct wm_adsp_compr_buf; struct wm_adsp { const char *part; + int rev; int num; int type; struct device *dev; -- cgit v1.2.1 From 51a2c944ead91171495ef338689da057bbcaab0c Mon Sep 17 00:00:00 2001 From: Mayuresh Kulkarni Date: Wed, 5 Apr 2017 11:08:00 +0100 Subject: ASoC: wm_adsp: add support for DSP region lock Newer ADSP2V2 codecs include a memory protection unit that can be set to trap illegal accesses. When enabling an ADSPV2 core we must configure the memory region traps so that the firmware can access its own memory. Signed-off-by: Mayuresh Kulkarni Signed-off-by: Nikesh Oswal Signed-off-by: Charles Keepax Signed-off-by: Richard Fitzgerald Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 137 +++++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/wm_adsp.h | 23 ++++++++ 2 files changed, 160 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index a9acf222b502..20695b691aff 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -176,6 +176,37 @@ #define ADSP2_RAM_RDY_SHIFT 0 #define ADSP2_RAM_RDY_WIDTH 1 +/* + * ADSP2 Lock support + */ +#define ADSP2_LOCK_CODE_0 0x5555 +#define ADSP2_LOCK_CODE_1 0xAAAA + +#define ADSP2_WATCHDOG 0x0A +#define ADSP2_BUS_ERR_ADDR 0x52 +#define ADSP2_REGION_LOCK_STATUS 0x64 +#define ADSP2_LOCK_REGION_1_LOCK_REGION_0 0x66 +#define ADSP2_LOCK_REGION_3_LOCK_REGION_2 0x68 +#define ADSP2_LOCK_REGION_5_LOCK_REGION_4 0x6A +#define ADSP2_LOCK_REGION_7_LOCK_REGION_6 0x6C +#define ADSP2_LOCK_REGION_9_LOCK_REGION_8 0x6E +#define ADSP2_LOCK_REGION_CTRL 0x7A +#define ADSP2_PMEM_ERR_ADDR_XMEM_ERR_ADDR 0x7C + +#define ADSP2_REGION_LOCK_ERR_MASK 0x8000 +#define ADSP2_SLAVE_ERR_MASK 0x4000 +#define ADSP2_WDT_TIMEOUT_STS_MASK 0x2000 +#define ADSP2_CTRL_ERR_PAUSE_ENA 0x0002 +#define ADSP2_CTRL_ERR_EINT 0x0001 + +#define ADSP2_BUS_ERR_ADDR_MASK 0x00FFFFFF +#define ADSP2_XMEM_ERR_ADDR_MASK 0x0000FFFF +#define ADSP2_PMEM_ERR_ADDR_MASK 0x7FFF0000 +#define ADSP2_PMEM_ERR_ADDR_SHIFT 16 +#define ADSP2_WDT_ENA_MASK 0xFFFFFFFD + +#define ADSP2_LOCK_REGION_SHIFT 16 + #define ADSP_MAX_STD_CTRL_SIZE 512 #define WM_ADSP_ACKED_CTL_TIMEOUT_MS 100 @@ -2638,6 +2669,18 @@ int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol, } EXPORT_SYMBOL_GPL(wm_adsp2_preloader_put); +static void wm_adsp_stop_watchdog(struct wm_adsp *dsp) +{ + switch (dsp->rev) { + case 0: + case 1: + return; + default: + regmap_update_bits(dsp->regmap, dsp->base + ADSP2_WATCHDOG, + ADSP2_WDT_ENA_MASK, 0); + } +} + int wm_adsp2_early_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event, unsigned int freq) @@ -2710,6 +2753,8 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, if (ret != 0) goto err; + wm_adsp2_lock(dsp, dsp->lock_regions); + ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, ADSP2_CORE_ENA | ADSP2_START, @@ -2733,6 +2778,8 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, /* Tell the firmware to cleanup */ wm_adsp_signal_event_controls(dsp, WM_ADSP_FW_EVENT_SHUTDOWN); + wm_adsp_stop_watchdog(dsp); + /* Log firmware state, it can be useful for analysis */ switch (dsp->rev) { case 0: @@ -3624,4 +3671,94 @@ int wm_adsp_compr_copy(struct snd_compr_stream *stream, char __user *buf, } EXPORT_SYMBOL_GPL(wm_adsp_compr_copy); +int wm_adsp2_lock(struct wm_adsp *dsp, unsigned int lock_regions) +{ + struct regmap *regmap = dsp->regmap; + unsigned int code0, code1, lock_reg; + + if (!(lock_regions & WM_ADSP2_REGION_ALL)) + return 0; + + lock_regions &= WM_ADSP2_REGION_ALL; + lock_reg = dsp->base + ADSP2_LOCK_REGION_1_LOCK_REGION_0; + + while (lock_regions) { + code0 = code1 = 0; + if (lock_regions & BIT(0)) { + code0 = ADSP2_LOCK_CODE_0; + code1 = ADSP2_LOCK_CODE_1; + } + if (lock_regions & BIT(1)) { + code0 |= ADSP2_LOCK_CODE_0 << ADSP2_LOCK_REGION_SHIFT; + code1 |= ADSP2_LOCK_CODE_1 << ADSP2_LOCK_REGION_SHIFT; + } + regmap_write(regmap, lock_reg, code0); + regmap_write(regmap, lock_reg, code1); + lock_regions >>= 2; + lock_reg += 2; + } + + return 0; +} +EXPORT_SYMBOL_GPL(wm_adsp2_lock); + +irqreturn_t wm_adsp2_bus_error(struct wm_adsp *dsp) +{ + unsigned int val; + struct regmap *regmap = dsp->regmap; + int ret = 0; + + ret = regmap_read(regmap, dsp->base + ADSP2_LOCK_REGION_CTRL, &val); + if (ret) { + adsp_err(dsp, + "Failed to read Region Lock Ctrl register: %d\n", ret); + return IRQ_HANDLED; + } + + if (val & ADSP2_WDT_TIMEOUT_STS_MASK) { + adsp_err(dsp, "watchdog timeout error\n"); + wm_adsp_stop_watchdog(dsp); + } + + if (val & (ADSP2_SLAVE_ERR_MASK | ADSP2_REGION_LOCK_ERR_MASK)) { + if (val & ADSP2_SLAVE_ERR_MASK) + adsp_err(dsp, "bus error: slave error\n"); + else + adsp_err(dsp, "bus error: region lock error\n"); + + ret = regmap_read(regmap, dsp->base + ADSP2_BUS_ERR_ADDR, &val); + if (ret) { + adsp_err(dsp, + "Failed to read Bus Err Addr register: %d\n", + ret); + return IRQ_HANDLED; + } + + adsp_err(dsp, "bus error address = 0x%x\n", + val & ADSP2_BUS_ERR_ADDR_MASK); + + ret = regmap_read(regmap, + dsp->base + ADSP2_PMEM_ERR_ADDR_XMEM_ERR_ADDR, + &val); + if (ret) { + adsp_err(dsp, + "Failed to read Pmem Xmem Err Addr register: %d\n", + ret); + return IRQ_HANDLED; + } + + adsp_err(dsp, "xmem error address = 0x%x\n", + val & ADSP2_XMEM_ERR_ADDR_MASK); + adsp_err(dsp, "pmem error address = 0x%x\n", + (val & ADSP2_PMEM_ERR_ADDR_MASK) >> + ADSP2_PMEM_ERR_ADDR_SHIFT); + } + + regmap_update_bits(regmap, dsp->base + ADSP2_LOCK_REGION_CTRL, + ADSP2_CTRL_ERR_EINT, ADSP2_CTRL_ERR_EINT); + + return IRQ_HANDLED; +} +EXPORT_SYMBOL_GPL(wm_adsp2_bus_error); + MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h index 997227f4d404..41cc11c19b83 100644 --- a/sound/soc/codecs/wm_adsp.h +++ b/sound/soc/codecs/wm_adsp.h @@ -23,6 +23,23 @@ #define WM_ADSP_COMPR_OK 0 #define WM_ADSP_COMPR_VOICE_TRIGGER 1 +#define WM_ADSP2_REGION_0 BIT(0) +#define WM_ADSP2_REGION_1 BIT(1) +#define WM_ADSP2_REGION_2 BIT(2) +#define WM_ADSP2_REGION_3 BIT(3) +#define WM_ADSP2_REGION_4 BIT(4) +#define WM_ADSP2_REGION_5 BIT(5) +#define WM_ADSP2_REGION_6 BIT(6) +#define WM_ADSP2_REGION_7 BIT(7) +#define WM_ADSP2_REGION_8 BIT(8) +#define WM_ADSP2_REGION_9 BIT(9) +#define WM_ADSP2_REGION_1_9 (WM_ADSP2_REGION_1 | \ + WM_ADSP2_REGION_2 | WM_ADSP2_REGION_3 | \ + WM_ADSP2_REGION_4 | WM_ADSP2_REGION_5 | \ + WM_ADSP2_REGION_6 | WM_ADSP2_REGION_7 | \ + WM_ADSP2_REGION_8 | WM_ADSP2_REGION_9) +#define WM_ADSP2_REGION_ALL (WM_ADSP2_REGION_0 | WM_ADSP2_REGION_1_9) + struct wm_adsp_region { int type; unsigned int base; @@ -76,6 +93,8 @@ struct wm_adsp { struct mutex pwr_lock; + unsigned int lock_regions; + #ifdef CONFIG_DEBUG_FS struct dentry *debugfs_root; char *wmfw_file_name; @@ -114,6 +133,10 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w, int wm_adsp2_early_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event, unsigned int freq); + +int wm_adsp2_lock(struct wm_adsp *adsp, unsigned int regions); +irqreturn_t wm_adsp2_bus_error(struct wm_adsp *adsp); + int wm_adsp2_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event); -- cgit v1.2.1 From 56af0e4cd27c402691d0da8aa4a5233944085b44 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Tue, 4 Apr 2017 13:19:39 -0400 Subject: ASoC: max9867: export OF device ID as module aliases The I2C core always reports a MODALIAS of the form i2c: even if the device was registered via OF, this means that exporting the OF device ID table device aliases in the module is not needed. But in order to change how the core reports modaliases to user-space, it's better to export it. While there, move the MODULE_DEVICE_TABLE(i2c, max9867_i2c_id) just next to the I2C device table declaration, for consistency with other drivers. Before this patch: $ modinfo sound/soc/codecs/snd-soc-max9867.ko | grep alias alias: i2c:max9867 After this patch: $ modinfo sound/soc/codecs/snd-soc-max9867.ko | grep alias alias: i2c:max9867 alias: of:N*T*Cmaxim,max9867C* alias: of:N*T*Cmaxim,max9867 Signed-off-by: Javier Martinez Canillas Signed-off-by: Mark Brown --- sound/soc/codecs/max9867.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/max9867.c b/sound/soc/codecs/max9867.c index 42e2e407e287..3a3d5bebc24e 100644 --- a/sound/soc/codecs/max9867.c +++ b/sound/soc/codecs/max9867.c @@ -517,13 +517,13 @@ static const struct i2c_device_id max9867_i2c_id[] = { { "max9867", 0 }, { } }; +MODULE_DEVICE_TABLE(i2c, max9867_i2c_id); static const struct of_device_id max9867_of_match[] = { { .compatible = "maxim,max9867", }, { } }; - -MODULE_DEVICE_TABLE(i2c, max9867_i2c_id); +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) -- cgit v1.2.1 From 13023ff3b3372543e4197b4b57d378350780fe96 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Tue, 4 Apr 2017 14:59:30 -0400 Subject: ASoC: cs53l30: Set .of_match_table to OF device ID table The driver has an OF device ID table but the struct i2c_driver .of_match_table field is not set. Signed-off-by: Javier Martinez Canillas Signed-off-by: Mark Brown --- sound/soc/codecs/cs53l30.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound/soc') diff --git a/sound/soc/codecs/cs53l30.c b/sound/soc/codecs/cs53l30.c index cb47fb595ff4..1e0d5973b758 100644 --- a/sound/soc/codecs/cs53l30.c +++ b/sound/soc/codecs/cs53l30.c @@ -1130,6 +1130,7 @@ MODULE_DEVICE_TABLE(i2c, cs53l30_id); static struct i2c_driver cs53l30_i2c_driver = { .driver = { .name = "cs53l30", + .of_match_table = cs53l30_of_match, .pm = &cs53l30_runtime_pm, }, .id_table = cs53l30_id, -- cgit v1.2.1 From 9ba2da5f5d18daaa365ab5426b05e16f1d114786 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Tue, 4 Apr 2017 15:26:25 -0400 Subject: ASoc: rt5645: Add OF device ID table The driver doesn't have a struct of_device_id table but supported devices are registered via Device Trees. This is working on the assumption that a I2C device registered via OF will always match a legacy I2C device ID and that the MODALIAS reported will always be of the form i2c:. But this could change in the future so the correct approach is to have an OF device ID table if the devices are registered via OF. Before this patch: $ modinfo sound/soc/codecs/snd-soc-rt5645.ko | grep alias alias: acpi*:10EC3270:* alias: acpi*:10EC5640:* alias: acpi*:10EC5650:* alias: acpi*:10EC5648:* alias: acpi*:10EC5645:* alias: i2c:rt5650 alias: i2c:rt5645 After this patch: $ modinfo sound/soc/codecs/snd-soc-rt5645.ko | grep alias alias: of:N*T*Crealtek,rt5650C* alias: of:N*T*Crealtek,rt5650 alias: of:N*T*Crealtek,rt5645C* alias: of:N*T*Crealtek,rt5645 alias: acpi*:10EC3270:* alias: acpi*:10EC5640:* alias: acpi*:10EC5650:* alias: acpi*:10EC5648:* alias: acpi*:10EC5645:* alias: i2c:rt5650 alias: i2c:rt5645 Signed-off-by: Javier Martinez Canillas Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 10c2a564a715..f8550ef2261b 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3542,6 +3542,15 @@ static const struct i2c_device_id rt5645_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, rt5645_i2c_id); +#ifdef CONFIG_OF +static const struct of_device_id rt5645_of_match[] = { + { .compatible = "realtek,rt5645", }, + { .compatible = "realtek,rt5650", }, + { } +}; +MODULE_DEVICE_TABLE(of, rt5645_of_match); +#endif + #ifdef CONFIG_ACPI static const struct acpi_device_id rt5645_acpi_match[] = { { "10EC5645", 0 }, @@ -3901,6 +3910,7 @@ static void rt5645_i2c_shutdown(struct i2c_client *i2c) static struct i2c_driver rt5645_i2c_driver = { .driver = { .name = "rt5645", + .of_match_table = of_match_ptr(rt5645_of_match), .acpi_match_table = ACPI_PTR(rt5645_acpi_match), }, .probe = rt5645_i2c_probe, -- cgit v1.2.1 From 71c314d7ef2442cd798584a3dece8151215e1777 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Tue, 4 Apr 2017 15:26:26 -0400 Subject: ASoC: ssm4567: Add OF device ID table The driver doesn't have a struct of_device_id table but supported devices are registered via Device Trees. This is working on the assumption that a I2C device registered via OF will always match a legacy I2C device ID and that the MODALIAS reported will always be of the form i2c:. But this could change in the future so the correct approach is to have an OF device ID table if the devices are registered via OF. Before this patch: $ modinfo sound/soc/codecs/snd-soc-ssm4567.ko | grep alias alias: acpi*:INT343B:* alias: i2c:ssm4567 After this patch: $ modinfo sound/soc/codecs/snd-soc-ssm4567.ko | grep alias alias: acpi*:INT343B:* alias: of:N*T*Cadi,ssm4567C* alias: of:N*T*Cadi,ssm4567 alias: i2c:ssm4567 Signed-off-by: Javier Martinez Canillas Signed-off-by: Mark Brown --- sound/soc/codecs/ssm4567.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/codecs/ssm4567.c b/sound/soc/codecs/ssm4567.c index 2bb5a11c9ba1..a622623e8558 100644 --- a/sound/soc/codecs/ssm4567.c +++ b/sound/soc/codecs/ssm4567.c @@ -485,6 +485,14 @@ static const struct i2c_device_id ssm4567_i2c_ids[] = { }; MODULE_DEVICE_TABLE(i2c, ssm4567_i2c_ids); +#ifdef CONFIG_OF +static const struct of_device_id ssm4567_of_match[] = { + { .compatible = "adi,ssm4567", }, + { } +}; +MODULE_DEVICE_TABLE(of, ssm4567_of_match); +#endif + #ifdef CONFIG_ACPI static const struct acpi_device_id ssm4567_acpi_match[] = { @@ -498,6 +506,7 @@ MODULE_DEVICE_TABLE(acpi, ssm4567_acpi_match); static struct i2c_driver ssm4567_driver = { .driver = { .name = "ssm4567", + .of_match_table = of_match_ptr(ssm4567_of_match), .acpi_match_table = ACPI_PTR(ssm4567_acpi_match), }, .probe = ssm4567_i2c_probe, -- cgit v1.2.1 From 9abe464821a0e66c0343ce943f3eb343bf8990f3 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Tue, 4 Apr 2017 15:26:27 -0400 Subject: ASoC: sta529: Add OF device ID table The driver doesn't have a struct of_device_id table but supported devices are registered via Device Trees. This is working on the assumption that a I2C device registered via OF will always match a legacy I2C device ID and that the MODALIAS reported will always be of the form i2c:. But this could change in the future so the correct approach is to have an OF device ID table if the devices are registered via OF. Before this patch: $ modinfo sound/soc/codecs/snd-soc-sta529.ko | grep alias alias: i2c:sta529 After this patch: $ modinfo sound/soc/codecs/snd-soc-sta529.ko | grep alias alias: of:N*T*Cst,sta529C* alias: of:N*T*Cst,sta529 alias: i2c:sta529 Signed-off-by: Javier Martinez Canillas Signed-off-by: Mark Brown --- sound/soc/codecs/sta529.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/codecs/sta529.c b/sound/soc/codecs/sta529.c index d4b384e4b266..660734359bf3 100644 --- a/sound/soc/codecs/sta529.c +++ b/sound/soc/codecs/sta529.c @@ -375,9 +375,16 @@ static const struct i2c_device_id sta529_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, sta529_i2c_id); +static const struct of_device_id sta529_of_match[] = { + { .compatible = "st,sta529", }, + { } +}; +MODULE_DEVICE_TABLE(of, sta529_of_match); + static struct i2c_driver sta529_i2c_driver = { .driver = { .name = "sta529", + .of_match_table = sta529_of_match, }, .probe = sta529_i2c_probe, .remove = sta529_i2c_remove, -- cgit v1.2.1 From ea22a26e676ebc39a2ba7836e814864bf85324e7 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Tue, 4 Apr 2017 15:26:28 -0400 Subject: ASoC: uda1380: Add OF device ID table The driver doesn't have a struct of_device_id table but supported devices are registered via Device Trees. This is working on the assumption that a I2C device registered via OF will always match a legacy I2C device ID and that the MODALIAS reported will always be of the form i2c:. But this could change in the future so the correct approach is to have an OF device ID table if the devices are registered via OF. Before this patch: $ modinfo sound/soc/codecs/snd-soc-uda1380.ko | grep alias alias: i2c:uda1380 After this patch: $ modinfo sound/soc/codecs/snd-soc-uda1380.ko | grep alias alias: of:N*T*Cnxp,uda1380C* alias: of:N*T*Cnxp,uda1380 alias: i2c:uda1380 Signed-off-by: Javier Martinez Canillas Signed-off-by: Mark Brown --- sound/soc/codecs/uda1380.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c index 2918fdb95e58..61cdc79840e7 100644 --- a/sound/soc/codecs/uda1380.c +++ b/sound/soc/codecs/uda1380.c @@ -791,9 +791,16 @@ static const struct i2c_device_id uda1380_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, uda1380_i2c_id); +static const struct of_device_id uda1380_of_match[] = { + { .compatible = "nxp,uda1380", }, + { } +}; +MODULE_DEVICE_TABLE(of, uda1380_of_match); + static struct i2c_driver uda1380_i2c_driver = { .driver = { .name = "uda1380-codec", + .of_match_table = uda1380_of_match, }, .probe = uda1380_i2c_probe, .remove = uda1380_i2c_remove, -- cgit v1.2.1 From 5cf015d9cb02c360582b624497b0a1716881cf28 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Tue, 4 Apr 2017 15:26:29 -0400 Subject: ASoC: wm8978: Add OF device ID table The driver doesn't have a struct of_device_id table but supported devices are registered via Device Trees. This is working on the assumption that a I2C device registered via OF will always match a legacy I2C device ID and that the MODALIAS reported will always be of the form i2c:. But this could change in the future so the correct approach is to have an OF device ID table if the devices are registered via OF. Before this patch: $ modinfo sound/soc/codecs/snd-soc-wm8978.ko | grep alias alias: i2c:wm8978 After this patch: $ modinfo sound/soc/codecs/snd-soc-wm8978.ko | grep alias alias: i2c:wm8978 alias: of:N*T*Cwlf,wm8978C* alias: of:N*T*Cwlf,wm8978 Signed-off-by: Javier Martinez Canillas Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8978.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c index 90b2d418ef60..cf761e2d7546 100644 --- a/sound/soc/codecs/wm8978.c +++ b/sound/soc/codecs/wm8978.c @@ -1071,9 +1071,16 @@ static const struct i2c_device_id wm8978_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, wm8978_i2c_id); +static const struct of_device_id wm8978_of_match[] = { + { .compatible = "wlf,wm8978", }, + { } +}; +MODULE_DEVICE_TABLE(of, wm8978_of_match); + static struct i2c_driver wm8978_i2c_driver = { .driver = { .name = "wm8978", + .of_match_table = wm8978_of_match, }, .probe = wm8978_i2c_probe, .remove = wm8978_i2c_remove, -- cgit v1.2.1 From 7b87463edf3e2c16d72eeea3d1cf3c12bb5487c6 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Tue, 4 Apr 2017 15:26:30 -0400 Subject: ASoC: rt5677: Add OF device ID table The driver doesn't have a struct of_device_id table but supported devices are registered via Device Trees. This is working on the assumption that a I2C device registered via OF will always match a legacy I2C device ID and that the MODALIAS reported will always be of the form i2c:. But this could change in the future so the correct approach is to have an OF device ID table if the devices are registered via OF. Before this patch: $ modinfo sound/soc/codecs/snd-soc-rt5677.ko | grep alias alias: i2c:RT5677CE:00 alias: i2c:rt5676 alias: i2c:rt5677 After this patch: $ modinfo sound/soc/codecs/snd-soc-rt5677.ko | grep alias alias: of:N*T*Crealtek,rt5677C* alias: of:N*T*Crealtek,rt5677 alias: i2c:RT5677CE:00 alias: i2c:rt5676 alias: i2c:rt5677 Signed-off-by: Javier Martinez Canillas Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index abc802a5a479..65ac4518ad06 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -5035,6 +5035,12 @@ static const struct i2c_device_id rt5677_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, rt5677_i2c_id); +static const struct of_device_id rt5677_of_match[] = { + { .compatible = "realtek,rt5677", }, + { } +}; +MODULE_DEVICE_TABLE(of, rt5677_of_match); + static const struct acpi_gpio_params plug_det_gpio = { RT5677_GPIO_PLUG_DET, 0, false }; static const struct acpi_gpio_params mic_present_gpio = { RT5677_GPIO_MIC_PRESENT_L, 0, false }; static const struct acpi_gpio_params headphone_enable_gpio = { RT5677_GPIO_HP_AMP_SHDN_L, 0, false }; @@ -5294,6 +5300,7 @@ static int rt5677_i2c_remove(struct i2c_client *i2c) static struct i2c_driver rt5677_i2c_driver = { .driver = { .name = "rt5677", + .of_match_table = rt5677_of_match, }, .probe = rt5677_i2c_probe, .remove = rt5677_i2c_remove, -- cgit v1.2.1 From 84fdc00d519ffdf8ae6e34d7841bcc6f38928953 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Tue, 4 Apr 2017 19:45:13 +0300 Subject: ASoC: codec: wm9860: Refactor PLL out freq search Add a separate function for deriving (sysclk, lrclk, bclk) when the clock is auto or pll. Signed-off-by: Daniel Baluta Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8960.c | 93 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 64 insertions(+), 29 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index ce159f13e7a4..36c84549da23 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -672,10 +672,70 @@ int wm8960_configure_sysclk(struct wm8960_priv *wm8960, int mclk, return *bclk_idx; } +/** + * wm8960_configure_pll - checks if there is a PLL out frequency available + * The PLL out frequency must be chosen such that: + * - sysclk = lrclk * dac_divs + * - freq_out = sysclk * sysclk_divs + * - 10 * sysclk = bclk * bclk_divs + * + * @codec: codec structure + * @freq_in: input frequency used to derive freq out via PLL + * @sysclk_idx: sysclk_divs index for found sysclk + * @dac_idx: dac_divs index for found lrclk + * @bclk_idx: bclk_divs index for found bclk + * + * Returns: + * -1, in case no PLL frequency out available was found + * >=0, in case we could derive bclk, lrclk, sysclk from PLL out using + * (@sysclk_idx, @dac_idx, @bclk_idx) dividers + */ +static +int wm8960_configure_pll(struct snd_soc_codec *codec, int freq_in, + int *sysclk_idx, int *dac_idx, int *bclk_idx) +{ + struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); + int sysclk, bclk, lrclk, freq_out; + int diff, best_freq_out; + int i, j, k; + + bclk = wm8960->bclk; + lrclk = wm8960->lrclk; + + *bclk_idx = -1; + + for (i = 0; i < ARRAY_SIZE(sysclk_divs); ++i) { + if (sysclk_divs[i] == -1) + continue; + for (j = 0; j < ARRAY_SIZE(dac_divs); ++j) { + sysclk = lrclk * dac_divs[j]; + freq_out = sysclk * sysclk_divs[i]; + + for (k = 0; k < ARRAY_SIZE(bclk_divs); ++k) { + if (!is_pll_freq_available(freq_in, freq_out)) + continue; + + diff = sysclk - bclk * bclk_divs[k] / 10; + if (diff == 0) { + *sysclk_idx = i; + *dac_idx = j; + *bclk_idx = k; + best_freq_out = freq_out; + break; + } + } + } + } + + if (*bclk_idx != -1) + wm8960_set_pll(codec, freq_in, best_freq_out); + + return *bclk_idx; +} static int wm8960_configure_clocking(struct snd_soc_codec *codec) { struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); - int sysclk, bclk, lrclk, freq_out, freq_in; + int freq_out, freq_in; u16 iface1 = snd_soc_read(codec, WM8960_IFACE1); int i, j, k; int ret; @@ -692,8 +752,6 @@ static int wm8960_configure_clocking(struct snd_soc_codec *codec) } freq_in = wm8960->freq_in; - bclk = wm8960->bclk; - lrclk = wm8960->lrclk; /* * If it's sysclk auto mode, check if the MCLK can provide sysclk or * not. If MCLK can provide sysclk, using MCLK to provide sysclk @@ -720,33 +778,10 @@ static int wm8960_configure_clocking(struct snd_soc_codec *codec) return -EINVAL; } } - /* get a available pll out frequency and set pll */ - for (i = 0; i < ARRAY_SIZE(sysclk_divs); ++i) { - if (sysclk_divs[i] == -1) - continue; - for (j = 0; j < ARRAY_SIZE(dac_divs); ++j) { - sysclk = lrclk * dac_divs[j]; - freq_out = sysclk * sysclk_divs[i]; - - for (k = 0; k < ARRAY_SIZE(bclk_divs); ++k) { - if (sysclk == bclk * bclk_divs[k] / 10 && - is_pll_freq_available(freq_in, freq_out)) { - wm8960_set_pll(codec, - freq_in, freq_out); - break; - } else { - continue; - } - } - if (k != ARRAY_SIZE(bclk_divs)) - break; - } - if (j != ARRAY_SIZE(dac_divs)) - break; - } - if (i == ARRAY_SIZE(sysclk_divs)) { - dev_err(codec->dev, "failed to configure clock\n"); + ret = wm8960_configure_pll(codec, freq_in, &i, &j, &k); + if (ret < 0) { + dev_err(codec->dev, "failed to configure clock via PLL\n"); return -EINVAL; } -- cgit v1.2.1 From c12c1aad98bb75b435e79c6208b56d2018b42f8b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 3 Apr 2017 06:31:22 +0000 Subject: ASoC: soc-core: verify Sound Card normality Current ALSA SoC Sound Card basically consists of CPU/Codec/Platform components. If system uses Kernel modules, we can disable these drivers by using rmmod command. In such case, we can't disable CPU/Codec/Platform driver without disabling Sound Card driver. But on the other hand, we can disable these drivers by using unbind command. In such case, we can disable these drivers randomly. In this case, we can create dirty Sound Card which is missing necessary components. (1) If user disabled Sound Card first, but did nothing to other drivers, user can't use Sound because Sound Card is no longer exists. (2) If user disabled CPU/Codec/Platform driver randomly, but did nothing to Sound Card, user still be able to use Sound Card, because dirty Sound Card still exists. In this case, Sound system will be crashed if user started sound playback/capture. But we can't block such random unbind now. To avoid Sound Card crash in (2) case, we need to unregister Sound Card whenever CPU/Codec/Platform component were unregistered. This patch solves this issue. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index f1901bb1466e..de6d5609c252 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3076,6 +3076,11 @@ static void snd_soc_component_cleanup(struct snd_soc_component *component) static void snd_soc_component_del_unlocked(struct snd_soc_component *component) { + struct snd_soc_card *card = component->card; + + if (card) + snd_soc_unregister_card(card); + list_del(&component->list); } -- cgit v1.2.1 From fc99d23f6d3ec6b17772915114018444393e0ad1 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 6 Apr 2017 07:24:36 +0000 Subject: ASoC: rsnd: tidyup src->convert_rate reset timing Current src->convert_rate will be set on .hw_param, and be reset on .quit timing. But, .hw_param will not be called again if user did Ctrl-Z + fg. It should be reset on initial of .hw_param to keep its value. Here, ctu.c already do this. This patch solves this issue, other wise, MIXed sound will be strange if user did like below. > aplay -D plughw:0,0 sound_44100.wav & > aplay -D plughw:0,1 sound_96000.wav > Ctrl-Z > fg # 96kHz will be played as 44.1kHz Reported-by: Hiroyuki Yokoyama Signed-off-by: Kuninori Morimoto Tested-by: Hiroyuki Yokoyama Signed-off-by: Mark Brown --- sound/soc/sh/rcar/src.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 42db48db09ba..20b5b2ec625e 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -167,6 +167,7 @@ static int rsnd_src_hw_params(struct rsnd_mod *mod, * dpcm_fe_dai_hw_params() * dpcm_be_dai_hw_params() */ + src->convert_rate = 0; if (fe->dai_link->dynamic) { int stream = substream->stream; struct snd_soc_dpcm *dpcm; @@ -414,8 +415,6 @@ static int rsnd_src_quit(struct rsnd_mod *mod, rsnd_mod_power_off(mod); - src->convert_rate = 0; - /* reset sync convert_rate */ src->sync.val = 0; -- cgit v1.2.1 From 32973dcf71ebee8806a6ee552665c5fad6857e16 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 6 Apr 2017 07:25:13 +0000 Subject: ASoC: rsnd: merge rsnd_kctrl_new_m/s/e into rsnd_kctrl_new() Current rsnd driver is using rsnd_kctrl_new_m/s/e function, but the differences are very few. This patch merge these rsnd_kctrl_new_m/s/e into rsnd_kctrl_new Signed-off-by: Kuninori Morimoto Tested-by: Hiroyuki Yokoyama Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 96 +++++++++++++++++------------------------------- sound/soc/sh/rcar/dvc.c | 8 ++-- sound/soc/sh/rcar/rsnd.h | 50 ++++++++++++------------- 3 files changed, 62 insertions(+), 92 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 35c96e4bbd64..f8eb9d3d1949 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -1000,13 +1000,30 @@ static int rsnd_kctrl_put(struct snd_kcontrol *kctrl, return change; } -static int __rsnd_kctrl_new(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct snd_soc_pcm_runtime *rtd, - const unsigned char *name, - struct rsnd_kctrl_cfg *cfg, - void (*update)(struct rsnd_dai_stream *io, - struct rsnd_mod *mod)) +struct rsnd_kctrl_cfg *rsnd_kctrl_init_m(struct rsnd_kctrl_cfg_m *cfg) +{ + cfg->cfg.val = cfg->val; + + return &cfg->cfg; +} + +struct rsnd_kctrl_cfg *rsnd_kctrl_init_s(struct rsnd_kctrl_cfg_s *cfg) +{ + cfg->cfg.val = &cfg->val; + + return &cfg->cfg; +} + +int rsnd_kctrl_new(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct snd_soc_pcm_runtime *rtd, + const unsigned char *name, + void (*update)(struct rsnd_dai_stream *io, + struct rsnd_mod *mod), + struct rsnd_kctrl_cfg *cfg, + const char * const *texts, + int size, + u32 max) { struct snd_card *card = rtd->card->snd_card; struct snd_kcontrol *kctrl; @@ -1021,6 +1038,9 @@ static int __rsnd_kctrl_new(struct rsnd_mod *mod, }; int ret; + if (size > RSND_MAX_CHANNELS) + return -EINVAL; + kctrl = snd_ctl_new1(&knew, mod); if (!kctrl) return -ENOMEM; @@ -1029,65 +1049,17 @@ static int __rsnd_kctrl_new(struct rsnd_mod *mod, if (ret < 0) return ret; - cfg->update = update; - cfg->card = card; - cfg->kctrl = kctrl; - cfg->io = io; + cfg->texts = texts; + cfg->max = max; + cfg->size = size; + cfg->update = update; + cfg->card = card; + cfg->kctrl = kctrl; + cfg->io = io; return 0; } -int rsnd_kctrl_new_m(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct snd_soc_pcm_runtime *rtd, - const unsigned char *name, - void (*update)(struct rsnd_dai_stream *io, - struct rsnd_mod *mod), - struct rsnd_kctrl_cfg_m *_cfg, - int ch_size, - u32 max) -{ - if (ch_size > RSND_MAX_CHANNELS) - return -EINVAL; - - _cfg->cfg.max = max; - _cfg->cfg.size = ch_size; - _cfg->cfg.val = _cfg->val; - return __rsnd_kctrl_new(mod, io, rtd, name, &_cfg->cfg, update); -} - -int rsnd_kctrl_new_s(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct snd_soc_pcm_runtime *rtd, - const unsigned char *name, - void (*update)(struct rsnd_dai_stream *io, - struct rsnd_mod *mod), - struct rsnd_kctrl_cfg_s *_cfg, - u32 max) -{ - _cfg->cfg.max = max; - _cfg->cfg.size = 1; - _cfg->cfg.val = &_cfg->val; - return __rsnd_kctrl_new(mod, io, rtd, name, &_cfg->cfg, update); -} - -int rsnd_kctrl_new_e(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct snd_soc_pcm_runtime *rtd, - const unsigned char *name, - struct rsnd_kctrl_cfg_s *_cfg, - void (*update)(struct rsnd_dai_stream *io, - struct rsnd_mod *mod), - const char * const *texts, - u32 max) -{ - _cfg->cfg.max = max; - _cfg->cfg.size = 1; - _cfg->cfg.val = &_cfg->val; - _cfg->cfg.texts = texts; - return __rsnd_kctrl_new(mod, io, rtd, name, &_cfg->cfg, update); -} - /* * snd_soc_platform */ diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index 994fdb7d0034..463de8360985 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -285,18 +285,18 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, ret = rsnd_kctrl_new_e(mod, io, rtd, is_play ? "DVC Out Ramp Up Rate" : "DVC In Ramp Up Rate", - &dvc->rup, rsnd_dvc_volume_update, - dvc_ramp_rate, ARRAY_SIZE(dvc_ramp_rate)); + &dvc->rup, + dvc_ramp_rate); if (ret < 0) return ret; ret = rsnd_kctrl_new_e(mod, io, rtd, is_play ? "DVC Out Ramp Down Rate" : "DVC In Ramp Down Rate", - &dvc->rdown, rsnd_dvc_volume_update, - dvc_ramp_rate, ARRAY_SIZE(dvc_ramp_rate)); + &dvc->rdown, + dvc_ramp_rate); if (ret < 0) return ret; diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 81ef3f18834a..3dc9e06f5943 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -611,32 +611,30 @@ struct rsnd_kctrl_cfg_s { u32 val; }; -int rsnd_kctrl_new_m(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct snd_soc_pcm_runtime *rtd, - const unsigned char *name, - void (*update)(struct rsnd_dai_stream *io, - struct rsnd_mod *mod), - struct rsnd_kctrl_cfg_m *_cfg, - int ch_size, - u32 max); -int rsnd_kctrl_new_s(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct snd_soc_pcm_runtime *rtd, - const unsigned char *name, - void (*update)(struct rsnd_dai_stream *io, - struct rsnd_mod *mod), - struct rsnd_kctrl_cfg_s *_cfg, - u32 max); -int rsnd_kctrl_new_e(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct snd_soc_pcm_runtime *rtd, - const unsigned char *name, - struct rsnd_kctrl_cfg_s *_cfg, - void (*update)(struct rsnd_dai_stream *io, - struct rsnd_mod *mod), - const char * const *texts, - u32 max); +struct rsnd_kctrl_cfg *rsnd_kctrl_init_m(struct rsnd_kctrl_cfg_m *cfg); +struct rsnd_kctrl_cfg *rsnd_kctrl_init_s(struct rsnd_kctrl_cfg_s *cfg); +int rsnd_kctrl_new(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct snd_soc_pcm_runtime *rtd, + const unsigned char *name, + void (*update)(struct rsnd_dai_stream *io, + struct rsnd_mod *mod), + struct rsnd_kctrl_cfg *cfg, + const char * const *texts, + int size, + u32 max); + +#define rsnd_kctrl_new_m(mod, io, rtd, name, update, cfg, size, max) \ + rsnd_kctrl_new(mod, io, rtd, name, update, rsnd_kctrl_init_m(cfg), \ + NULL, size, max) + +#define rsnd_kctrl_new_s(mod, io, rtd, name, update, cfg, max) \ + rsnd_kctrl_new(mod, io, rtd, name, update, rsnd_kctrl_init_s(cfg), \ + NULL, 1, max) + +#define rsnd_kctrl_new_e(mod, io, rtd, name, update, cfg, texts) \ + rsnd_kctrl_new(mod, io, rtd, name, update, rsnd_kctrl_init_s(cfg), \ + texts, 1, ARRAY_SIZE(texts)) /* * R-Car SSI -- cgit v1.2.1 From 7c0c2000716e64151b3c0c62026c18f31537ebe9 Mon Sep 17 00:00:00 2001 From: Ryan Lee Date: Tue, 4 Apr 2017 02:23:08 +0900 Subject: ASoC: Add support for Maxim Integrated MAX98927 Amplifier Signed-off-by: Ryan Lee Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 5 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/max98927.c | 841 ++++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/max98927.h | 272 ++++++++++++++ 4 files changed, 1120 insertions(+) create mode 100644 sound/soc/codecs/max98927.c create mode 100644 sound/soc/codecs/max98927.h (limited to 'sound/soc') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 9e1718a8cb1c..65e31ab88280 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -89,6 +89,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_MAX9867 if I2C select SND_SOC_MAX98925 if I2C select SND_SOC_MAX98926 if I2C + select SND_SOC_MAX98927 if I2C select SND_SOC_MAX9850 if I2C select SND_SOC_MAX9860 if I2C select SND_SOC_MAX9768 if I2C @@ -585,6 +586,10 @@ config SND_SOC_MAX98925 config SND_SOC_MAX98926 tristate +config SND_SOC_MAX98927 + tristate "Maxim Integrated MAX98927 Speaker Amplifier" + depends on I2C + config SND_SOC_MAX9850 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 7e1dad79610b..64656c43200c 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -84,6 +84,7 @@ snd-soc-max98371-objs := max98371.o snd-soc-max9867-objs := max9867.o snd-soc-max98925-objs := max98925.o snd-soc-max98926-objs := max98926.o +snd-soc-max98927-objs := max98927.o snd-soc-max9850-objs := max9850.o snd-soc-max9860-objs := max9860.o snd-soc-mc13783-objs := mc13783.o @@ -312,6 +313,7 @@ obj-$(CONFIG_SND_SOC_MAX98357A) += snd-soc-max98357a.o obj-$(CONFIG_SND_SOC_MAX9867) += snd-soc-max9867.o obj-$(CONFIG_SND_SOC_MAX98925) += snd-soc-max98925.o obj-$(CONFIG_SND_SOC_MAX98926) += snd-soc-max98926.o +obj-$(CONFIG_SND_SOC_MAX98927) += snd-soc-max98927.o obj-$(CONFIG_SND_SOC_MAX9850) += snd-soc-max9850.o obj-$(CONFIG_SND_SOC_MAX9860) += snd-soc-max9860.o obj-$(CONFIG_SND_SOC_MC13783) += snd-soc-mc13783.o diff --git a/sound/soc/codecs/max98927.c b/sound/soc/codecs/max98927.c new file mode 100644 index 000000000000..b5ee29499e16 --- /dev/null +++ b/sound/soc/codecs/max98927.c @@ -0,0 +1,841 @@ +/* + * max98927.c -- MAX98927 ALSA Soc Audio driver + * + * Copyright (C) 2016 Maxim Integrated Products + * Author: Ryan Lee + * + * 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 +#include +#include +#include +#include +#include "max98927.h" + +static struct reg_default max98927_reg[] = { + {MAX98927_R0001_INT_RAW1, 0x00}, + {MAX98927_R0002_INT_RAW2, 0x00}, + {MAX98927_R0003_INT_RAW3, 0x00}, + {MAX98927_R0004_INT_STATE1, 0x00}, + {MAX98927_R0005_INT_STATE2, 0x00}, + {MAX98927_R0006_INT_STATE3, 0x00}, + {MAX98927_R0007_INT_FLAG1, 0x00}, + {MAX98927_R0008_INT_FLAG2, 0x00}, + {MAX98927_R0009_INT_FLAG3, 0x00}, + {MAX98927_R000A_INT_EN1, 0x00}, + {MAX98927_R000B_INT_EN2, 0x00}, + {MAX98927_R000C_INT_EN3, 0x00}, + {MAX98927_R000D_INT_FLAG_CLR1, 0x00}, + {MAX98927_R000E_INT_FLAG_CLR2, 0x00}, + {MAX98927_R000F_INT_FLAG_CLR3, 0x00}, + {MAX98927_R0010_IRQ_CTRL, 0x00}, + {MAX98927_R0011_CLK_MON, 0x00}, + {MAX98927_R0012_WDOG_CTRL, 0x00}, + {MAX98927_R0013_WDOG_RST, 0x00}, + {MAX98927_R0014_MEAS_ADC_THERM_WARN_THRESH, 0x00}, + {MAX98927_R0015_MEAS_ADC_THERM_SHDN_THRESH, 0x00}, + {MAX98927_R0016_MEAS_ADC_THERM_HYSTERESIS, 0x00}, + {MAX98927_R0017_PIN_CFG, 0x55}, + {MAX98927_R0018_PCM_RX_EN_A, 0x00}, + {MAX98927_R0019_PCM_RX_EN_B, 0x00}, + {MAX98927_R001A_PCM_TX_EN_A, 0x00}, + {MAX98927_R001B_PCM_TX_EN_B, 0x00}, + {MAX98927_R001C_PCM_TX_HIZ_CTRL_A, 0x00}, + {MAX98927_R001D_PCM_TX_HIZ_CTRL_B, 0x00}, + {MAX98927_R001E_PCM_TX_CH_SRC_A, 0x00}, + {MAX98927_R001F_PCM_TX_CH_SRC_B, 0x00}, + {MAX98927_R0020_PCM_MODE_CFG, 0x40}, + {MAX98927_R0021_PCM_MASTER_MODE, 0x00}, + {MAX98927_R0022_PCM_CLK_SETUP, 0x22}, + {MAX98927_R0023_PCM_SR_SETUP1, 0x00}, + {MAX98927_R0024_PCM_SR_SETUP2, 0x00}, + {MAX98927_R0025_PCM_TO_SPK_MONOMIX_A, 0x00}, + {MAX98927_R0026_PCM_TO_SPK_MONOMIX_B, 0x00}, + {MAX98927_R0027_ICC_RX_EN_A, 0x00}, + {MAX98927_R0028_ICC_RX_EN_B, 0x00}, + {MAX98927_R002B_ICC_TX_EN_A, 0x00}, + {MAX98927_R002C_ICC_TX_EN_B, 0x00}, + {MAX98927_R002E_ICC_HIZ_MANUAL_MODE, 0x00}, + {MAX98927_R002F_ICC_TX_HIZ_EN_A, 0x00}, + {MAX98927_R0030_ICC_TX_HIZ_EN_B, 0x00}, + {MAX98927_R0031_ICC_LNK_EN, 0x00}, + {MAX98927_R0032_PDM_TX_EN, 0x00}, + {MAX98927_R0033_PDM_TX_HIZ_CTRL, 0x00}, + {MAX98927_R0034_PDM_TX_CTRL, 0x00}, + {MAX98927_R0035_PDM_RX_CTRL, 0x00}, + {MAX98927_R0036_AMP_VOL_CTRL, 0x00}, + {MAX98927_R0037_AMP_DSP_CFG, 0x02}, + {MAX98927_R0038_TONE_GEN_DC_CFG, 0x00}, + {MAX98927_R0039_DRE_CTRL, 0x01}, + {MAX98927_R003A_AMP_EN, 0x00}, + {MAX98927_R003B_SPK_SRC_SEL, 0x00}, + {MAX98927_R003C_SPK_GAIN, 0x00}, + {MAX98927_R003D_SSM_CFG, 0x01}, + {MAX98927_R003E_MEAS_EN, 0x00}, + {MAX98927_R003F_MEAS_DSP_CFG, 0x04}, + {MAX98927_R0040_BOOST_CTRL0, 0x00}, + {MAX98927_R0041_BOOST_CTRL3, 0x00}, + {MAX98927_R0042_BOOST_CTRL1, 0x00}, + {MAX98927_R0043_MEAS_ADC_CFG, 0x00}, + {MAX98927_R0044_MEAS_ADC_BASE_MSB, 0x00}, + {MAX98927_R0045_MEAS_ADC_BASE_LSB, 0x00}, + {MAX98927_R0046_ADC_CH0_DIVIDE, 0x00}, + {MAX98927_R0047_ADC_CH1_DIVIDE, 0x00}, + {MAX98927_R0048_ADC_CH2_DIVIDE, 0x00}, + {MAX98927_R0049_ADC_CH0_FILT_CFG, 0x00}, + {MAX98927_R004A_ADC_CH1_FILT_CFG, 0x00}, + {MAX98927_R004B_ADC_CH2_FILT_CFG, 0x00}, + {MAX98927_R004C_MEAS_ADC_CH0_READ, 0x00}, + {MAX98927_R004D_MEAS_ADC_CH1_READ, 0x00}, + {MAX98927_R004E_MEAS_ADC_CH2_READ, 0x00}, + {MAX98927_R0051_BROWNOUT_STATUS, 0x00}, + {MAX98927_R0052_BROWNOUT_EN, 0x00}, + {MAX98927_R0053_BROWNOUT_INFINITE_HOLD, 0x00}, + {MAX98927_R0054_BROWNOUT_INFINITE_HOLD_CLR, 0x00}, + {MAX98927_R0055_BROWNOUT_LVL_HOLD, 0x00}, + {MAX98927_R005A_BROWNOUT_LVL1_THRESH, 0x00}, + {MAX98927_R005B_BROWNOUT_LVL2_THRESH, 0x00}, + {MAX98927_R005C_BROWNOUT_LVL3_THRESH, 0x00}, + {MAX98927_R005D_BROWNOUT_LVL4_THRESH, 0x00}, + {MAX98927_R005E_BROWNOUT_THRESH_HYSTERYSIS, 0x00}, + {MAX98927_R005F_BROWNOUT_AMP_LIMITER_ATK_REL, 0x00}, + {MAX98927_R0060_BROWNOUT_AMP_GAIN_ATK_REL, 0x00}, + {MAX98927_R0061_BROWNOUT_AMP1_CLIP_MODE, 0x00}, + {MAX98927_R0072_BROWNOUT_LVL1_CUR_LIMIT, 0x00}, + {MAX98927_R0073_BROWNOUT_LVL1_AMP1_CTRL1, 0x00}, + {MAX98927_R0074_BROWNOUT_LVL1_AMP1_CTRL2, 0x00}, + {MAX98927_R0075_BROWNOUT_LVL1_AMP1_CTRL3, 0x00}, + {MAX98927_R0076_BROWNOUT_LVL2_CUR_LIMIT, 0x00}, + {MAX98927_R0077_BROWNOUT_LVL2_AMP1_CTRL1, 0x00}, + {MAX98927_R0078_BROWNOUT_LVL2_AMP1_CTRL2, 0x00}, + {MAX98927_R0079_BROWNOUT_LVL2_AMP1_CTRL3, 0x00}, + {MAX98927_R007A_BROWNOUT_LVL3_CUR_LIMIT, 0x00}, + {MAX98927_R007B_BROWNOUT_LVL3_AMP1_CTRL1, 0x00}, + {MAX98927_R007C_BROWNOUT_LVL3_AMP1_CTRL2, 0x00}, + {MAX98927_R007D_BROWNOUT_LVL3_AMP1_CTRL3, 0x00}, + {MAX98927_R007E_BROWNOUT_LVL4_CUR_LIMIT, 0x00}, + {MAX98927_R007F_BROWNOUT_LVL4_AMP1_CTRL1, 0x00}, + {MAX98927_R0080_BROWNOUT_LVL4_AMP1_CTRL2, 0x00}, + {MAX98927_R0081_BROWNOUT_LVL4_AMP1_CTRL3, 0x00}, + {MAX98927_R0082_ENV_TRACK_VOUT_HEADROOM, 0x00}, + {MAX98927_R0083_ENV_TRACK_BOOST_VOUT_DELAY, 0x00}, + {MAX98927_R0084_ENV_TRACK_REL_RATE, 0x00}, + {MAX98927_R0085_ENV_TRACK_HOLD_RATE, 0x00}, + {MAX98927_R0086_ENV_TRACK_CTRL, 0x00}, + {MAX98927_R0087_ENV_TRACK_BOOST_VOUT_READ, 0x00}, + {MAX98927_R00FF_GLOBAL_SHDN, 0x00}, + {MAX98927_R0100_SOFT_RESET, 0x00}, + {MAX98927_R01FF_REV_ID, 0x40}, +}; + +static int max98927_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + unsigned int mode = 0; + unsigned int format = 0; + unsigned int invert = 0; + + dev_dbg(codec->dev, "%s: fmt 0x%08X\n", __func__, fmt); + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + mode = MAX98927_PCM_MASTER_MODE_SLAVE; + break; + case SND_SOC_DAIFMT_CBM_CFM: + max98927->master = true; + mode = MAX98927_PCM_MASTER_MODE_MASTER; + break; + default: + dev_err(codec->dev, "DAI clock mode unsupported"); + return -EINVAL; + } + + regmap_update_bits(max98927->regmap, + MAX98927_R0021_PCM_MASTER_MODE, + MAX98927_PCM_MASTER_MODE_MASK, + mode); + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_NF: + invert = MAX98927_PCM_MODE_CFG_PCM_BCLKEDGE; + break; + default: + dev_err(codec->dev, "DAI invert mode unsupported"); + return -EINVAL; + } + + regmap_update_bits(max98927->regmap, + MAX98927_R0020_PCM_MODE_CFG, + MAX98927_PCM_MODE_CFG_PCM_BCLKEDGE, + invert); + + /* interface format */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + max98927->iface |= SND_SOC_DAIFMT_I2S; + format = MAX98927_PCM_FORMAT_I2S; + break; + case SND_SOC_DAIFMT_LEFT_J: + max98927->iface |= SND_SOC_DAIFMT_LEFT_J; + format = MAX98927_PCM_FORMAT_LJ; + break; + case SND_SOC_DAIFMT_PDM: + max98927->iface |= SND_SOC_DAIFMT_PDM; + break; + default: + return -EINVAL; + } + + /* pcm channel configuration */ + if (max98927->iface & (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_LEFT_J)) { + regmap_update_bits(max98927->regmap, + MAX98927_R0018_PCM_RX_EN_A, + MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN, + MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN); + + regmap_update_bits(max98927->regmap, + MAX98927_R0020_PCM_MODE_CFG, + MAX98927_PCM_MODE_CFG_FORMAT_MASK, + format << MAX98927_PCM_MODE_CFG_FORMAT_SHIFT); + + regmap_update_bits(max98927->regmap, + MAX98927_R003B_SPK_SRC_SEL, + MAX98927_SPK_SRC_MASK, 0); + + } else + regmap_update_bits(max98927->regmap, + MAX98927_R0018_PCM_RX_EN_A, + MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN, 0); + + /* pdm channel configuration */ + if (max98927->iface & SND_SOC_DAIFMT_PDM) { + regmap_update_bits(max98927->regmap, + MAX98927_R0035_PDM_RX_CTRL, + MAX98927_PDM_RX_EN_MASK, 1); + + regmap_update_bits(max98927->regmap, + MAX98927_R003B_SPK_SRC_SEL, + MAX98927_SPK_SRC_MASK, 3); + } else + regmap_update_bits(max98927->regmap, + MAX98927_R0035_PDM_RX_CTRL, + MAX98927_PDM_RX_EN_MASK, 0); + return 0; +} + +/* codec MCLK rate in master mode */ +static const int rate_table[] = { + 5644800, 6000000, 6144000, 6500000, + 9600000, 11289600, 12000000, 12288000, + 13000000, 19200000, +}; + +static int max98927_set_clock(struct max98927_priv *max98927, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_codec *codec = max98927->codec; + /* BCLK/LRCLK ratio calculation */ + int blr_clk_ratio = params_channels(params) * max98927->ch_size; + int value; + + if (max98927->master) { + int i; + /* match rate to closest value */ + for (i = 0; i < ARRAY_SIZE(rate_table); i++) { + if (rate_table[i] >= max98927->sysclk) + break; + } + if (i == ARRAY_SIZE(rate_table)) { + dev_err(codec->dev, "failed to find proper clock rate.\n"); + return -EINVAL; + } + regmap_update_bits(max98927->regmap, + MAX98927_R0021_PCM_MASTER_MODE, + MAX98927_PCM_MASTER_MODE_MCLK_MASK, + i << MAX98927_PCM_MASTER_MODE_MCLK_RATE_SHIFT); + } + + switch (blr_clk_ratio) { + case 32: + value = 2; + break; + case 48: + value = 3; + break; + case 64: + value = 4; + break; + default: + return -EINVAL; + } + regmap_update_bits(max98927->regmap, + MAX98927_R0022_PCM_CLK_SETUP, + MAX98927_PCM_CLK_SETUP_BSEL_MASK, + value); + return 0; +} + +static int max98927_dai_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 max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + unsigned int sampling_rate = 0; + unsigned int chan_sz = 0; + + /* pcm mode configuration */ + switch (snd_pcm_format_width(params_format(params))) { + case 16: + chan_sz = MAX98927_PCM_MODE_CFG_CHANSZ_16; + break; + case 24: + chan_sz = MAX98927_PCM_MODE_CFG_CHANSZ_24; + break; + case 32: + chan_sz = MAX98927_PCM_MODE_CFG_CHANSZ_32; + break; + default: + dev_err(codec->dev, "format unsupported %d", + params_format(params)); + goto err; + } + + max98927->ch_size = snd_pcm_format_width(params_format(params)); + + regmap_update_bits(max98927->regmap, + MAX98927_R0020_PCM_MODE_CFG, + MAX98927_PCM_MODE_CFG_CHANSZ_MASK, chan_sz); + + dev_dbg(codec->dev, "format supported %d", + params_format(params)); + + /* sampling rate configuration */ + switch (params_rate(params)) { + case 8000: + sampling_rate = MAX98927_PCM_SR_SET1_SR_8000; + break; + case 11025: + sampling_rate = MAX98927_PCM_SR_SET1_SR_11025; + break; + case 12000: + sampling_rate = MAX98927_PCM_SR_SET1_SR_12000; + break; + case 16000: + sampling_rate = MAX98927_PCM_SR_SET1_SR_16000; + break; + case 22050: + sampling_rate = MAX98927_PCM_SR_SET1_SR_22050; + break; + case 24000: + sampling_rate = MAX98927_PCM_SR_SET1_SR_24000; + break; + case 32000: + sampling_rate = MAX98927_PCM_SR_SET1_SR_32000; + break; + case 44100: + sampling_rate = MAX98927_PCM_SR_SET1_SR_44100; + break; + case 48000: + sampling_rate = MAX98927_PCM_SR_SET1_SR_48000; + break; + default: + dev_err(codec->dev, "rate %d not supported\n", + params_rate(params)); + goto err; + } + /* set DAI_SR to correct LRCLK frequency */ + regmap_update_bits(max98927->regmap, + MAX98927_R0023_PCM_SR_SETUP1, + MAX98927_PCM_SR_SET1_SR_MASK, + sampling_rate); + regmap_update_bits(max98927->regmap, + MAX98927_R0024_PCM_SR_SETUP2, + MAX98927_PCM_SR_SET2_SR_MASK, + sampling_rate << MAX98927_PCM_SR_SET2_SR_SHIFT); + + /* set sampling rate of IV */ + if (max98927->interleave_mode && + sampling_rate > MAX98927_PCM_SR_SET1_SR_16000) + regmap_update_bits(max98927->regmap, + MAX98927_R0024_PCM_SR_SETUP2, + MAX98927_PCM_SR_SET2_IVADC_SR_MASK, + sampling_rate - 3); + else + regmap_update_bits(max98927->regmap, + MAX98927_R0024_PCM_SR_SETUP2, + MAX98927_PCM_SR_SET2_IVADC_SR_MASK, + sampling_rate); + return max98927_set_clock(max98927, params); +err: + return -EINVAL; +} + +#define MAX98927_RATES SNDRV_PCM_RATE_8000_48000 + +#define MAX98927_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) + +static int max98927_dai_set_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = dai->codec; + struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + + max98927->sysclk = freq; + return 0; +} + +static const struct snd_soc_dai_ops max98927_dai_ops = { + .set_sysclk = max98927_dai_set_sysclk, + .set_fmt = max98927_dai_set_fmt, + .hw_params = max98927_dai_hw_params, +}; + +static int max98927_dac_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); + struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_update_bits(max98927->regmap, + MAX98927_R003A_AMP_EN, + MAX98927_AMP_EN_MASK, 1); + /* enable VMON and IMON */ + regmap_update_bits(max98927->regmap, + MAX98927_R003E_MEAS_EN, + MAX98927_MEAS_V_EN | MAX98927_MEAS_I_EN, + MAX98927_MEAS_V_EN | MAX98927_MEAS_I_EN); + regmap_update_bits(max98927->regmap, + MAX98927_R00FF_GLOBAL_SHDN, + MAX98927_GLOBAL_EN_MASK, 1); + break; + case SND_SOC_DAPM_POST_PMD: + regmap_update_bits(max98927->regmap, + MAX98927_R00FF_GLOBAL_SHDN, + MAX98927_GLOBAL_EN_MASK, 0); + regmap_update_bits(max98927->regmap, + MAX98927_R003A_AMP_EN, + MAX98927_AMP_EN_MASK, 0); + /* disable VMON and IMON */ + regmap_update_bits(max98927->regmap, + MAX98927_R003E_MEAS_EN, + MAX98927_MEAS_V_EN | MAX98927_MEAS_I_EN, 0); + break; + default: + return 0; + } + return 0; +} + +static const char * const max98927_switch_text[] = { + "Left", "Right", "LeftRight"}; + +static const struct soc_enum dai_sel_enum = + SOC_ENUM_SINGLE(MAX98927_R0025_PCM_TO_SPK_MONOMIX_A, + MAX98927_PCM_TO_SPK_MONOMIX_CFG_SHIFT, + 3, max98927_switch_text); + +static const struct snd_kcontrol_new max98927_dai_controls = + SOC_DAPM_ENUM("DAI Sel", dai_sel_enum); + +static const struct snd_soc_dapm_widget max98927_dapm_widgets[] = { + SND_SOC_DAPM_AIF_IN("DAI_OUT", "HiFi Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_DAC_E("Amp Enable", "HiFi Playback", MAX98927_R003A_AMP_EN, + 0, 0, max98927_dac_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX("DAI Sel Mux", SND_SOC_NOPM, 0, 0, + &max98927_dai_controls), + SND_SOC_DAPM_OUTPUT("BE_OUT"), +}; + +static DECLARE_TLV_DB_SCALE(max98927_spk_tlv, 300, 300, 0); +static DECLARE_TLV_DB_SCALE(max98927_digital_tlv, -1600, 25, 0); + +static bool max98927_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MAX98927_R0001_INT_RAW1 ... MAX98927_R0028_ICC_RX_EN_B: + case MAX98927_R002B_ICC_TX_EN_A ... MAX98927_R002C_ICC_TX_EN_B: + case MAX98927_R002E_ICC_HIZ_MANUAL_MODE + ... MAX98927_R004E_MEAS_ADC_CH2_READ: + case MAX98927_R0051_BROWNOUT_STATUS + ... MAX98927_R0055_BROWNOUT_LVL_HOLD: + case MAX98927_R005A_BROWNOUT_LVL1_THRESH + ... MAX98927_R0061_BROWNOUT_AMP1_CLIP_MODE: + case MAX98927_R0072_BROWNOUT_LVL1_CUR_LIMIT + ... MAX98927_R0087_ENV_TRACK_BOOST_VOUT_READ: + case MAX98927_R00FF_GLOBAL_SHDN: + case MAX98927_R0100_SOFT_RESET: + case MAX98927_R01FF_REV_ID: + return true; + default: + return false; + } +}; + +static bool max98927_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MAX98927_R0001_INT_RAW1 ... MAX98927_R0009_INT_FLAG3: + return true; + default: + return false; + } +} + +static const char * const max98927_boost_voltage_text[] = { + "6.5V", "6.625V", "6.75V", "6.875V", "7V", "7.125V", "7.25V", "7.375V", + "7.5V", "7.625V", "7.75V", "7.875V", "8V", "8.125V", "8.25V", "8.375V", + "8.5V", "8.625V", "8.75V", "8.875V", "9V", "9.125V", "9.25V", "9.375V", + "9.5V", "9.625V", "9.75V", "9.875V", "10V" +}; + +static SOC_ENUM_SINGLE_DECL(max98927_boost_voltage, + MAX98927_R0040_BOOST_CTRL0, 0, + max98927_boost_voltage_text); + +static const char * const max98927_current_limit_text[] = { + "1.00A", "1.10A", "1.20A", "1.30A", "1.40A", "1.50A", "1.60A", "1.70A", + "1.80A", "1.90A", "2.00A", "2.10A", "2.20A", "2.30A", "2.40A", "2.50A", + "2.60A", "2.70A", "2.80A", "2.90A", "3.00A", "3.10A", "3.20A", "3.30A", + "3.40A", "3.50A", "3.60A", "3.70A", "3.80A", "3.90A", "4.00A", "4.10A" +}; + +static SOC_ENUM_SINGLE_DECL(max98927_current_limit, + MAX98927_R0042_BOOST_CTRL1, 1, + max98927_current_limit_text); + +static const struct snd_kcontrol_new max98927_snd_controls[] = { + SOC_SINGLE_TLV("Speaker Volume", MAX98927_R003C_SPK_GAIN, + 0, 6, 0, + max98927_spk_tlv), + SOC_SINGLE_TLV("Digital Volume", MAX98927_R0036_AMP_VOL_CTRL, + 0, (1<codec = codec; + codec->control_data = max98927->regmap; + codec->cache_bypass = 1; + + /* Software Reset */ + regmap_write(max98927->regmap, + MAX98927_R0100_SOFT_RESET, MAX98927_SOFT_RESET); + + /* IV default slot configuration */ + regmap_write(max98927->regmap, + MAX98927_R001C_PCM_TX_HIZ_CTRL_A, + 0xFF); + regmap_write(max98927->regmap, + MAX98927_R001D_PCM_TX_HIZ_CTRL_B, + 0xFF); + regmap_write(max98927->regmap, + MAX98927_R0025_PCM_TO_SPK_MONOMIX_A, + 0x80); + regmap_write(max98927->regmap, + MAX98927_R0026_PCM_TO_SPK_MONOMIX_B, + 0x1); + /* Set inital volume (+13dB) */ + regmap_write(max98927->regmap, + MAX98927_R0036_AMP_VOL_CTRL, + 0x38); + regmap_write(max98927->regmap, + MAX98927_R003C_SPK_GAIN, + 0x05); + /* Enable DC blocker */ + regmap_write(max98927->regmap, + MAX98927_R0037_AMP_DSP_CFG, + 0x03); + /* Enable IMON VMON DC blocker */ + regmap_write(max98927->regmap, + MAX98927_R003F_MEAS_DSP_CFG, + 0xF7); + /* Boost Output Voltage & Current limit */ + regmap_write(max98927->regmap, + MAX98927_R0040_BOOST_CTRL0, + 0x1C); + regmap_write(max98927->regmap, + MAX98927_R0042_BOOST_CTRL1, + 0x3E); + /* Measurement ADC config */ + regmap_write(max98927->regmap, + MAX98927_R0043_MEAS_ADC_CFG, + 0x04); + regmap_write(max98927->regmap, + MAX98927_R0044_MEAS_ADC_BASE_MSB, + 0x00); + regmap_write(max98927->regmap, + MAX98927_R0045_MEAS_ADC_BASE_LSB, + 0x24); + /* Brownout Level */ + regmap_write(max98927->regmap, + MAX98927_R007F_BROWNOUT_LVL4_AMP1_CTRL1, + 0x06); + /* Envelope Tracking configuration */ + regmap_write(max98927->regmap, + MAX98927_R0082_ENV_TRACK_VOUT_HEADROOM, + 0x08); + regmap_write(max98927->regmap, + MAX98927_R0086_ENV_TRACK_CTRL, + 0x01); + regmap_write(max98927->regmap, + MAX98927_R0087_ENV_TRACK_BOOST_VOUT_READ, + 0x10); + + /* voltage, current slot configuration */ + regmap_write(max98927->regmap, + MAX98927_R001E_PCM_TX_CH_SRC_A, + (max98927->i_l_slot<v_l_slot)&0xFF); + + if (max98927->v_l_slot < 8) { + regmap_update_bits(max98927->regmap, + MAX98927_R001C_PCM_TX_HIZ_CTRL_A, + 1 << max98927->v_l_slot, 0); + regmap_update_bits(max98927->regmap, + MAX98927_R001A_PCM_TX_EN_A, + 1 << max98927->v_l_slot, + 1 << max98927->v_l_slot); + } else { + regmap_update_bits(max98927->regmap, + MAX98927_R001D_PCM_TX_HIZ_CTRL_B, + 1 << (max98927->v_l_slot - 8), 0); + regmap_update_bits(max98927->regmap, + MAX98927_R001B_PCM_TX_EN_B, + 1 << (max98927->v_l_slot - 8), + 1 << (max98927->v_l_slot - 8)); + } + + if (max98927->i_l_slot < 8) { + regmap_update_bits(max98927->regmap, + MAX98927_R001C_PCM_TX_HIZ_CTRL_A, + 1 << max98927->i_l_slot, 0); + regmap_update_bits(max98927->regmap, + MAX98927_R001A_PCM_TX_EN_A, + 1 << max98927->i_l_slot, + 1 << max98927->i_l_slot); + } else { + regmap_update_bits(max98927->regmap, + MAX98927_R001D_PCM_TX_HIZ_CTRL_B, + 1 << (max98927->i_l_slot - 8), 0); + regmap_update_bits(max98927->regmap, + MAX98927_R001B_PCM_TX_EN_B, + 1 << (max98927->i_l_slot - 8), + 1 << (max98927->i_l_slot - 8)); + } + + /* Set interleave mode */ + if (max98927->interleave_mode) + regmap_update_bits(max98927->regmap, + MAX98927_R001F_PCM_TX_CH_SRC_B, + MAX98927_PCM_TX_CH_INTERLEAVE_MASK, + MAX98927_PCM_TX_CH_INTERLEAVE_MASK); + return 0; +} + +static const struct snd_soc_codec_driver soc_codec_dev_max98927 = { + .probe = max98927_probe, + .component_driver = { + .controls = max98927_snd_controls, + .num_controls = ARRAY_SIZE(max98927_snd_controls), + .dapm_widgets = max98927_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(max98927_dapm_widgets), + .dapm_routes = max98927_audio_map, + .num_dapm_routes = ARRAY_SIZE(max98927_audio_map), + }, +}; + +static const struct regmap_config max98927_regmap = { + .reg_bits = 16, + .val_bits = 8, + .max_register = MAX98927_R01FF_REV_ID, + .reg_defaults = max98927_reg, + .num_reg_defaults = ARRAY_SIZE(max98927_reg), + .readable_reg = max98927_readable_register, + .volatile_reg = max98927_volatile_reg, + .cache_type = REGCACHE_RBTREE, +}; + +static void max98927_slot_config(struct i2c_client *i2c, + struct max98927_priv *max98927) +{ + int value; + + if (!of_property_read_u32(i2c->dev.of_node, + "vmon-slot-no", &value)) + max98927->v_l_slot = value & 0xF; + else + max98927->v_l_slot = 0; + if (!of_property_read_u32(i2c->dev.of_node, + "imon-slot-no", &value)) + max98927->i_l_slot = value & 0xF; + else + max98927->i_l_slot = 1; +} + +static int max98927_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + + int ret = 0, value; + int reg = 0; + struct max98927_priv *max98927 = NULL; + + max98927 = devm_kzalloc(&i2c->dev, + sizeof(*max98927), GFP_KERNEL); + + if (!max98927) { + ret = -ENOMEM; + return ret; + } + i2c_set_clientdata(i2c, max98927); + + /* update interleave mode info */ + if (!of_property_read_u32(i2c->dev.of_node, + "interleave_mode", &value)) { + if (value > 0) + max98927->interleave_mode = 1; + else + max98927->interleave_mode = 0; + } else + max98927->interleave_mode = 0; + + /* regmap initialization */ + max98927->regmap + = devm_regmap_init_i2c(i2c, &max98927_regmap); + if (IS_ERR(max98927->regmap)) { + ret = PTR_ERR(max98927->regmap); + dev_err(&i2c->dev, + "Failed to allocate regmap: %d\n", ret); + return ret; + } + + /* Check Revision ID */ + ret = regmap_read(max98927->regmap, + MAX98927_R01FF_REV_ID, ®); + if (ret < 0) { + dev_err(&i2c->dev, + "Failed to read: 0x%02X\n", MAX98927_R01FF_REV_ID); + return ret; + } + dev_info(&i2c->dev, "MAX98927 revisionID: 0x%02X\n", reg); + + /* voltage/current slot configuration */ + max98927_slot_config(i2c, max98927); + + /* codec registeration */ + ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_max98927, + max98927_dai, ARRAY_SIZE(max98927_dai)); + if (ret < 0) + dev_err(&i2c->dev, "Failed to register codec: %d\n", ret); + + return ret; +} + +static int max98927_i2c_remove(struct i2c_client *client) +{ + snd_soc_unregister_codec(&client->dev); + return 0; +} + +static const struct i2c_device_id max98927_i2c_id[] = { + { "max98927", 0}, + { }, +}; + +MODULE_DEVICE_TABLE(i2c, max98927_i2c_id); + +#if defined(CONFIG_OF) +static const struct of_device_id max98927_of_match[] = { + { .compatible = "maxim,max98927", }, + { } +}; +MODULE_DEVICE_TABLE(of, max98927_of_match); +#endif + +#ifdef CONFIG_ACPI +static const struct acpi_device_id max98927_acpi_match[] = { + { "MX98927", 0 }, + {}, +}; +MODULE_DEVICE_TABLE(acpi, max98927_acpi_match); +#endif + +static struct i2c_driver max98927_i2c_driver = { + .driver = { + .name = "max98927", + .of_match_table = of_match_ptr(max98927_of_match), + .acpi_match_table = ACPI_PTR(max98927_acpi_match), + .pm = NULL, + }, + .probe = max98927_i2c_probe, + .remove = max98927_i2c_remove, + .id_table = max98927_i2c_id, +}; + +module_i2c_driver(max98927_i2c_driver) + +MODULE_DESCRIPTION("ALSA SoC MAX98927 driver"); +MODULE_AUTHOR("Ryan Lee "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/max98927.h b/sound/soc/codecs/max98927.h new file mode 100644 index 000000000000..ece6a608cbe1 --- /dev/null +++ b/sound/soc/codecs/max98927.h @@ -0,0 +1,272 @@ +/* + * max98927.h -- MAX98927 ALSA Soc Audio driver + * + * Copyright 2013-15 Maxim Integrated Products + * Author: Ryan Lee + * + * 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 _MAX98927_H +#define _MAX98927_H + +/* Register Values */ +#define MAX98927_R0001_INT_RAW1 0x0001 +#define MAX98927_R0002_INT_RAW2 0x0002 +#define MAX98927_R0003_INT_RAW3 0x0003 +#define MAX98927_R0004_INT_STATE1 0x0004 +#define MAX98927_R0005_INT_STATE2 0x0005 +#define MAX98927_R0006_INT_STATE3 0x0006 +#define MAX98927_R0007_INT_FLAG1 0x0007 +#define MAX98927_R0008_INT_FLAG2 0x0008 +#define MAX98927_R0009_INT_FLAG3 0x0009 +#define MAX98927_R000A_INT_EN1 0x000A +#define MAX98927_R000B_INT_EN2 0x000B +#define MAX98927_R000C_INT_EN3 0x000C +#define MAX98927_R000D_INT_FLAG_CLR1 0x000D +#define MAX98927_R000E_INT_FLAG_CLR2 0x000E +#define MAX98927_R000F_INT_FLAG_CLR3 0x000F +#define MAX98927_R0010_IRQ_CTRL 0x0010 +#define MAX98927_R0011_CLK_MON 0x0011 +#define MAX98927_R0012_WDOG_CTRL 0x0012 +#define MAX98927_R0013_WDOG_RST 0x0013 +#define MAX98927_R0014_MEAS_ADC_THERM_WARN_THRESH 0x0014 +#define MAX98927_R0015_MEAS_ADC_THERM_SHDN_THRESH 0x0015 +#define MAX98927_R0016_MEAS_ADC_THERM_HYSTERESIS 0x0016 +#define MAX98927_R0017_PIN_CFG 0x0017 +#define MAX98927_R0018_PCM_RX_EN_A 0x0018 +#define MAX98927_R0019_PCM_RX_EN_B 0x0019 +#define MAX98927_R001A_PCM_TX_EN_A 0x001A +#define MAX98927_R001B_PCM_TX_EN_B 0x001B +#define MAX98927_R001C_PCM_TX_HIZ_CTRL_A 0x001C +#define MAX98927_R001D_PCM_TX_HIZ_CTRL_B 0x001D +#define MAX98927_R001E_PCM_TX_CH_SRC_A 0x001E +#define MAX98927_R001F_PCM_TX_CH_SRC_B 0x001F +#define MAX98927_R0020_PCM_MODE_CFG 0x0020 +#define MAX98927_R0021_PCM_MASTER_MODE 0x0021 +#define MAX98927_R0022_PCM_CLK_SETUP 0x0022 +#define MAX98927_R0023_PCM_SR_SETUP1 0x0023 +#define MAX98927_R0024_PCM_SR_SETUP2 0x0024 +#define MAX98927_R0025_PCM_TO_SPK_MONOMIX_A 0x0025 +#define MAX98927_R0026_PCM_TO_SPK_MONOMIX_B 0x0026 +#define MAX98927_R0027_ICC_RX_EN_A 0x0027 +#define MAX98927_R0028_ICC_RX_EN_B 0x0028 +#define MAX98927_R002B_ICC_TX_EN_A 0x002B +#define MAX98927_R002C_ICC_TX_EN_B 0x002C +#define MAX98927_R002E_ICC_HIZ_MANUAL_MODE 0x002E +#define MAX98927_R002F_ICC_TX_HIZ_EN_A 0x002F +#define MAX98927_R0030_ICC_TX_HIZ_EN_B 0x0030 +#define MAX98927_R0031_ICC_LNK_EN 0x0031 +#define MAX98927_R0032_PDM_TX_EN 0x0032 +#define MAX98927_R0033_PDM_TX_HIZ_CTRL 0x0033 +#define MAX98927_R0034_PDM_TX_CTRL 0x0034 +#define MAX98927_R0035_PDM_RX_CTRL 0x0035 +#define MAX98927_R0036_AMP_VOL_CTRL 0x0036 +#define MAX98927_R0037_AMP_DSP_CFG 0x0037 +#define MAX98927_R0038_TONE_GEN_DC_CFG 0x0038 +#define MAX98927_R0039_DRE_CTRL 0x0039 +#define MAX98927_R003A_AMP_EN 0x003A +#define MAX98927_R003B_SPK_SRC_SEL 0x003B +#define MAX98927_R003C_SPK_GAIN 0x003C +#define MAX98927_R003D_SSM_CFG 0x003D +#define MAX98927_R003E_MEAS_EN 0x003E +#define MAX98927_R003F_MEAS_DSP_CFG 0x003F +#define MAX98927_R0040_BOOST_CTRL0 0x0040 +#define MAX98927_R0041_BOOST_CTRL3 0x0041 +#define MAX98927_R0042_BOOST_CTRL1 0x0042 +#define MAX98927_R0043_MEAS_ADC_CFG 0x0043 +#define MAX98927_R0044_MEAS_ADC_BASE_MSB 0x0044 +#define MAX98927_R0045_MEAS_ADC_BASE_LSB 0x0045 +#define MAX98927_R0046_ADC_CH0_DIVIDE 0x0046 +#define MAX98927_R0047_ADC_CH1_DIVIDE 0x0047 +#define MAX98927_R0048_ADC_CH2_DIVIDE 0x0048 +#define MAX98927_R0049_ADC_CH0_FILT_CFG 0x0049 +#define MAX98927_R004A_ADC_CH1_FILT_CFG 0x004A +#define MAX98927_R004B_ADC_CH2_FILT_CFG 0x004B +#define MAX98927_R004C_MEAS_ADC_CH0_READ 0x004C +#define MAX98927_R004D_MEAS_ADC_CH1_READ 0x004D +#define MAX98927_R004E_MEAS_ADC_CH2_READ 0x004E +#define MAX98927_R0051_BROWNOUT_STATUS 0x0051 +#define MAX98927_R0052_BROWNOUT_EN 0x0052 +#define MAX98927_R0053_BROWNOUT_INFINITE_HOLD 0x0053 +#define MAX98927_R0054_BROWNOUT_INFINITE_HOLD_CLR 0x0054 +#define MAX98927_R0055_BROWNOUT_LVL_HOLD 0x0055 +#define MAX98927_R005A_BROWNOUT_LVL1_THRESH 0x005A +#define MAX98927_R005B_BROWNOUT_LVL2_THRESH 0x005B +#define MAX98927_R005C_BROWNOUT_LVL3_THRESH 0x005C +#define MAX98927_R005D_BROWNOUT_LVL4_THRESH 0x005D +#define MAX98927_R005E_BROWNOUT_THRESH_HYSTERYSIS 0x005E +#define MAX98927_R005F_BROWNOUT_AMP_LIMITER_ATK_REL 0x005F +#define MAX98927_R0060_BROWNOUT_AMP_GAIN_ATK_REL 0x0060 +#define MAX98927_R0061_BROWNOUT_AMP1_CLIP_MODE 0x0061 +#define MAX98927_R0072_BROWNOUT_LVL1_CUR_LIMIT 0x0072 +#define MAX98927_R0073_BROWNOUT_LVL1_AMP1_CTRL1 0x0073 +#define MAX98927_R0074_BROWNOUT_LVL1_AMP1_CTRL2 0x0074 +#define MAX98927_R0075_BROWNOUT_LVL1_AMP1_CTRL3 0x0075 +#define MAX98927_R0076_BROWNOUT_LVL2_CUR_LIMIT 0x0076 +#define MAX98927_R0077_BROWNOUT_LVL2_AMP1_CTRL1 0x0077 +#define MAX98927_R0078_BROWNOUT_LVL2_AMP1_CTRL2 0x0078 +#define MAX98927_R0079_BROWNOUT_LVL2_AMP1_CTRL3 0x0079 +#define MAX98927_R007A_BROWNOUT_LVL3_CUR_LIMIT 0x007A +#define MAX98927_R007B_BROWNOUT_LVL3_AMP1_CTRL1 0x007B +#define MAX98927_R007C_BROWNOUT_LVL3_AMP1_CTRL2 0x007C +#define MAX98927_R007D_BROWNOUT_LVL3_AMP1_CTRL3 0x007D +#define MAX98927_R007E_BROWNOUT_LVL4_CUR_LIMIT 0x007E +#define MAX98927_R007F_BROWNOUT_LVL4_AMP1_CTRL1 0x007F +#define MAX98927_R0080_BROWNOUT_LVL4_AMP1_CTRL2 0x0080 +#define MAX98927_R0081_BROWNOUT_LVL4_AMP1_CTRL3 0x0081 +#define MAX98927_R0082_ENV_TRACK_VOUT_HEADROOM 0x0082 +#define MAX98927_R0083_ENV_TRACK_BOOST_VOUT_DELAY 0x0083 +#define MAX98927_R0084_ENV_TRACK_REL_RATE 0x0084 +#define MAX98927_R0085_ENV_TRACK_HOLD_RATE 0x0085 +#define MAX98927_R0086_ENV_TRACK_CTRL 0x0086 +#define MAX98927_R0087_ENV_TRACK_BOOST_VOUT_READ 0x0087 +#define MAX98927_R00FF_GLOBAL_SHDN 0x00FF +#define MAX98927_R0100_SOFT_RESET 0x0100 +#define MAX98927_R01FF_REV_ID 0x01FF + +/* MAX98927_R0018_PCM_RX_EN_A */ +#define MAX98927_PCM_RX_CH0_EN (0x1 << 0) +#define MAX98927_PCM_RX_CH1_EN (0x1 << 1) +#define MAX98927_PCM_RX_CH2_EN (0x1 << 2) +#define MAX98927_PCM_RX_CH3_EN (0x1 << 3) +#define MAX98927_PCM_RX_CH4_EN (0x1 << 4) +#define MAX98927_PCM_RX_CH5_EN (0x1 << 5) +#define MAX98927_PCM_RX_CH6_EN (0x1 << 6) +#define MAX98927_PCM_RX_CH7_EN (0x1 << 7) + +/* MAX98927_R001A_PCM_TX_EN_A */ +#define MAX98927_PCM_TX_CH0_EN (0x1 << 0) +#define MAX98927_PCM_TX_CH1_EN (0x1 << 1) +#define MAX98927_PCM_TX_CH2_EN (0x1 << 2) +#define MAX98927_PCM_TX_CH3_EN (0x1 << 3) +#define MAX98927_PCM_TX_CH4_EN (0x1 << 4) +#define MAX98927_PCM_TX_CH5_EN (0x1 << 5) +#define MAX98927_PCM_TX_CH6_EN (0x1 << 6) +#define MAX98927_PCM_TX_CH7_EN (0x1 << 7) + +/* MAX98927_R001E_PCM_TX_CH_SRC_A */ +#define MAX98927_PCM_TX_CH_SRC_A_V_SHIFT (0) +#define MAX98927_PCM_TX_CH_SRC_A_I_SHIFT (4) + +/* MAX98927_R001F_PCM_TX_CH_SRC_B */ +#define MAX98927_PCM_TX_CH_INTERLEAVE_MASK (0x1 << 5) + +/* MAX98927_R0020_PCM_MODE_CFG */ +#define MAX98927_PCM_MODE_CFG_PCM_BCLKEDGE (0x1 << 2) +#define MAX98927_PCM_MODE_CFG_FORMAT_MASK (0x7 << 3) +#define MAX98927_PCM_MODE_CFG_FORMAT_SHIFT (3) +#define MAX98927_PCM_FORMAT_I2S (0x0 << 0) +#define MAX98927_PCM_FORMAT_LJ (0x1 << 0) + +#define MAX98927_PCM_MODE_CFG_CHANSZ_MASK (0x3 << 6) +#define MAX98927_PCM_MODE_CFG_CHANSZ_16 (0x1 << 6) +#define MAX98927_PCM_MODE_CFG_CHANSZ_24 (0x2 << 6) +#define MAX98927_PCM_MODE_CFG_CHANSZ_32 (0x3 << 6) + +/* MAX98927_R0021_PCM_MASTER_MODE */ +#define MAX98927_PCM_MASTER_MODE_MASK (0x3 << 0) +#define MAX98927_PCM_MASTER_MODE_SLAVE (0x0 << 0) +#define MAX98927_PCM_MASTER_MODE_MASTER (0x3 << 0) + +#define MAX98927_PCM_MASTER_MODE_MCLK_MASK (0xF << 2) +#define MAX98927_PCM_MASTER_MODE_MCLK_RATE_SHIFT (2) + +/* MAX98927_R0022_PCM_CLK_SETUP */ +#define MAX98927_PCM_CLK_SETUP_BSEL_MASK (0xF << 0) + +/* MAX98927_R0023_PCM_SR_SETUP1 */ +#define MAX98927_PCM_SR_SET1_SR_MASK (0xF << 0) + +#define MAX98927_PCM_SR_SET1_SR_8000 (0x0 << 0) +#define MAX98927_PCM_SR_SET1_SR_11025 (0x1 << 0) +#define MAX98927_PCM_SR_SET1_SR_12000 (0x2 << 0) +#define MAX98927_PCM_SR_SET1_SR_16000 (0x3 << 0) +#define MAX98927_PCM_SR_SET1_SR_22050 (0x4 << 0) +#define MAX98927_PCM_SR_SET1_SR_24000 (0x5 << 0) +#define MAX98927_PCM_SR_SET1_SR_32000 (0x6 << 0) +#define MAX98927_PCM_SR_SET1_SR_44100 (0x7 << 0) +#define MAX98927_PCM_SR_SET1_SR_48000 (0x8 << 0) + +/* MAX98927_R0024_PCM_SR_SETUP2 */ +#define MAX98927_PCM_SR_SET2_SR_MASK (0xF << 4) +#define MAX98927_PCM_SR_SET2_SR_SHIFT (4) +#define MAX98927_PCM_SR_SET2_IVADC_SR_MASK (0xf << 0) + +/* MAX98927_R0025_PCM_TO_SPK_MONOMIX_A */ +#define MAX98927_PCM_TO_SPK_MONOMIX_CFG_MASK (0x3 << 6) +#define MAX98927_PCM_TO_SPK_MONOMIX_CFG_SHIFT (6) + +/* MAX98927_R0035_PDM_RX_CTRL */ +#define MAX98927_PDM_RX_EN_MASK (0x1 << 0) + +/* MAX98927_R0036_AMP_VOL_CTRL */ +#define MAX98927_AMP_VOL_SEL (0x1 << 7) +#define MAX98927_AMP_VOL_SEL_WIDTH (1) +#define MAX98927_AMP_VOL_SEL_SHIFT (7) +#define MAX98927_AMP_VOL_MASK (0x7f << 0) +#define MAX98927_AMP_VOL_WIDTH (7) +#define MAX98927_AMP_VOL_SHIFT (0) + +/* MAX98927_R0037_AMP_DSP_CFG */ +#define MAX98927_AMP_DSP_CFG_DCBLK_EN (0x1 << 0) +#define MAX98927_AMP_DSP_CFG_DITH_EN (0x1 << 1) +#define MAX98927_AMP_DSP_CFG_RMP_BYPASS (0x1 << 4) +#define MAX98927_AMP_DSP_CFG_DAC_INV (0x1 << 5) +#define MAX98927_AMP_DSP_CFG_RMP_SHIFT (4) + +/* MAX98927_R0039_DRE_CTRL */ +#define MAX98927_DRE_CTRL_DRE_EN (0x1 << 0) +#define MAX98927_DRE_EN_SHIFT 0x1 + +/* MAX98927_R003A_AMP_EN */ +#define MAX98927_AMP_EN_MASK (0x1 << 0) + +/* MAX98927_R003B_SPK_SRC_SEL */ +#define MAX98927_SPK_SRC_MASK (0x3 << 0) + +/* MAX98927_R003C_SPK_GAIN */ +#define MAX98927_SPK_PCM_GAIN_MASK (0x7 << 0) +#define MAX98927_SPK_PDM_GAIN_MASK (0x7 << 4) +#define MAX98927_SPK_GAIN_WIDTH (3) + +/* MAX98927_R003E_MEAS_EN */ +#define MAX98927_MEAS_V_EN (0x1 << 0) +#define MAX98927_MEAS_I_EN (0x1 << 1) + +/* MAX98927_R0040_BOOST_CTRL0 */ +#define MAX98927_BOOST_CTRL0_VOUT_MASK (0x1f << 0) +#define MAX98927_BOOST_CTRL0_PVDD_MASK (0x1 << 7) +#define MAX98927_BOOST_CTRL0_PVDD_EN_SHIFT (7) + +/* MAX98927_R0052_BROWNOUT_EN */ +#define MAX98927_BROWNOUT_BDE_EN (0x1 << 0) +#define MAX98927_BROWNOUT_AMP_EN (0x1 << 1) +#define MAX98927_BROWNOUT_DSP_EN (0x1 << 2) +#define MAX98927_BROWNOUT_DSP_SHIFT (2) + +/* MAX98927_R0100_SOFT_RESET */ +#define MAX98927_SOFT_RESET (0x1 << 0) + +/* MAX98927_R00FF_GLOBAL_SHDN */ +#define MAX98927_GLOBAL_EN_MASK (0x1 << 0) + +struct max98927_priv { + struct regmap *regmap; + struct snd_soc_codec *codec; + struct max98927_pdata *pdata; + unsigned int spk_gain; + unsigned int sysclk; + unsigned int v_l_slot; + unsigned int i_l_slot; + bool interleave_mode; + unsigned int ch_size; + unsigned int rate; + unsigned int iface; + unsigned int master; + unsigned int digital_gain; +}; +#endif -- cgit v1.2.1 From 303e8954af8daa087e4f42788672d280337071ab Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Thu, 6 Apr 2017 14:51:53 +0300 Subject: ASoC: codec: wm8960: Stop when a matching PLL freq is found When a matching PLL freq is found, searching continues even this is not necessary. The problem was introduced with the following refactoring commit 84fdc00d519ffd ("ASoC: codec: wm9860: Refactor PLL out freq search) Signed-off-by: Daniel Baluta Signed-off-by: Mark Brown --- sound/soc/codecs/wm8960.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index 36c84549da23..ace69da97cb8 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -724,7 +724,11 @@ int wm8960_configure_pll(struct snd_soc_codec *codec, int freq_in, break; } } + if (k != ARRAY_SIZE(bclk_divs)) + break; } + if (j != ARRAY_SIZE(dac_divs)) + break; } if (*bclk_idx != -1) -- cgit v1.2.1 From 2c84afb52ebea59e9862fcb8234126b7ae1d1960 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 6 Apr 2017 13:52:12 +0100 Subject: ASoC: cs35l35: Improve power down time Shorten the time it takes to power down the amp by disabling the volume ramp whilst doing the final shutdown. The driver has already muted the amplifier at this stage so doing the volume ramp serves no purpose. Signed-off-by: Charles Keepax Acked-by: Brian Austin Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l35.c | 8 ++++++++ sound/soc/codecs/cs35l35.h | 3 +++ 2 files changed, 11 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/codecs/cs35l35.c b/sound/soc/codecs/cs35l35.c index 9688274f7c90..1db07a6296a4 100644 --- a/sound/soc/codecs/cs35l35.c +++ b/sound/soc/codecs/cs35l35.c @@ -187,6 +187,10 @@ static int cs35l35_sdin_event(struct snd_soc_dapm_widget *w, regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL1, CS35L35_PDN_ALL_MASK, 1); + /* Already muted, so disable volume ramp for faster shutdown */ + regmap_update_bits(cs35l35->regmap, CS35L35_AMP_DIG_VOL_CTL, + CS35L35_AMP_DIGSFT_MASK, 0); + reinit_completion(&cs35l35->pdn_done); ret = wait_for_completion_timeout(&cs35l35->pdn_done, @@ -199,6 +203,10 @@ static int cs35l35_sdin_event(struct snd_soc_dapm_widget *w, regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL1, CS35L35_MCLK_DIS_MASK, 1 << CS35L35_MCLK_DIS_SHIFT); + + regmap_update_bits(cs35l35->regmap, CS35L35_AMP_DIG_VOL_CTL, + CS35L35_AMP_DIGSFT_MASK, + 1 << CS35L35_AMP_DIGSFT_SHIFT); break; default: dev_err(codec->dev, "Invalid event = 0x%x\n", event); diff --git a/sound/soc/codecs/cs35l35.h b/sound/soc/codecs/cs35l35.h index 156d2f0e6fd8..54e9ac536b20 100644 --- a/sound/soc/codecs/cs35l35.h +++ b/sound/soc/codecs/cs35l35.h @@ -190,6 +190,9 @@ #define CS35L35_AMP_GAIN_ZC_MASK 0x10 #define CS35L35_AMP_GAIN_ZC_SHIFT 4 +#define CS35L35_AMP_DIGSFT_MASK 0x02 +#define CS35L35_AMP_DIGSFT_SHIFT 1 + /* CS35L35_SP_FMT_CTL3 */ #define CS35L35_SP_I2S_DRV_MASK 0x03 #define CS35L35_SP_I2S_DRV_SHIFT 0 -- cgit v1.2.1 From 77b329d1943d38a5acdbaf9d57754975bce701d4 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 6 Apr 2017 13:52:13 +0100 Subject: ASoC: cs35l35: Correct handling of PDN_DONE with external boost When using an external boost supply the PDN_DONE bit is not set, update the handling in this case to use to use an appropriate fixed delay. Signed-off-by: Charles Keepax Acked-by: Brian Austin Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l35.c | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/cs35l35.c b/sound/soc/codecs/cs35l35.c index 1db07a6296a4..6ecb7ddae9cf 100644 --- a/sound/soc/codecs/cs35l35.c +++ b/sound/soc/codecs/cs35l35.c @@ -162,6 +162,27 @@ static bool cs35l35_precious_register(struct device *dev, unsigned int reg) } } +static int cs35l35_wait_for_pdn(struct cs35l35_private *cs35l35) +{ + int ret; + + if (cs35l35->pdata.ext_bst) { + usleep_range(5000, 5500); + return 0; + } + + reinit_completion(&cs35l35->pdn_done); + + ret = wait_for_completion_timeout(&cs35l35->pdn_done, + msecs_to_jiffies(100)); + if (ret == 0) { + dev_err(cs35l35->dev, "PDN_DONE did not complete\n"); + return -ETIMEDOUT; + } + + return 0; +} + static int cs35l35_sdin_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { @@ -191,14 +212,7 @@ static int cs35l35_sdin_event(struct snd_soc_dapm_widget *w, regmap_update_bits(cs35l35->regmap, CS35L35_AMP_DIG_VOL_CTL, CS35L35_AMP_DIGSFT_MASK, 0); - reinit_completion(&cs35l35->pdn_done); - - ret = wait_for_completion_timeout(&cs35l35->pdn_done, - msecs_to_jiffies(100)); - if (ret == 0) { - dev_err(codec->dev, "TIMEOUT PDN_DONE did not complete in 100ms\n"); - ret = -ETIMEDOUT; - } + ret = cs35l35_wait_for_pdn(cs35l35); regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL1, CS35L35_MCLK_DIS_MASK, @@ -1198,6 +1212,8 @@ static int cs35l35_handle_of_data(struct i2c_client *i2c_client, "cirrus,shared-boost"); } + pdata->ext_bst = of_property_read_bool(np, "cirrus,external-boost"); + pdata->gain_zc = of_property_read_bool(np, "cirrus,amp-gain-zc"); classh = of_get_child_by_name(np, "cirrus,classh-internal-algo"); -- cgit v1.2.1 From d05d862ead8eca5e7d4ccf82d39d9189579ee5b1 Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Tue, 28 Mar 2017 15:04:55 +0200 Subject: ASoC: STI: Fix null ptr deference in IRQ handler With RTlinux a race condition has been found that leads to NULL ptr crash: - On CPU 0: uni_player_irq_handler is called to treat XRUN "(player->state == UNIPERIF_STATE_STOPPED)" is FALSE so status is checked, dev_err(player->dev, "FIFO underflow error detected") is printed and then snd_pcm_stream_lock should be called to lock stream for stopping. - On CPU 1: application stop and close the stream. Issue is that the stop and shutdown functions are executed while "FIFO underflow error detected" is printed. So when CPU 0 calls snd_pcm_stream_lock, player->substream is already null. Signed-off-by: Arnaud Pouliquen Signed-off-by: Mark Brown --- sound/soc/sti/uniperif.h | 1 + sound/soc/sti/uniperif_player.c | 35 ++++++++++++++++++++++++----------- sound/soc/sti/uniperif_reader.c | 24 ++++++++++++++++++++---- 3 files changed, 45 insertions(+), 15 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sti/uniperif.h b/sound/soc/sti/uniperif.h index d487dd2ef016..cfcb0ea9d99d 100644 --- a/sound/soc/sti/uniperif.h +++ b/sound/soc/sti/uniperif.h @@ -1299,6 +1299,7 @@ struct uniperif { int ver; /* IP version, used by register access macros */ struct regmap_field *clk_sel; struct regmap_field *valid_sel; + spinlock_t irq_lock; /* use to prevent race condition with IRQ */ /* capabilities */ const struct snd_pcm_hardware *hw; diff --git a/sound/soc/sti/uniperif_player.c b/sound/soc/sti/uniperif_player.c index 60ae31a303ab..d7e8dd46d2cc 100644 --- a/sound/soc/sti/uniperif_player.c +++ b/sound/soc/sti/uniperif_player.c @@ -65,10 +65,13 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id) unsigned int status; unsigned int tmp; - if (player->state == UNIPERIF_STATE_STOPPED) { - /* Unexpected IRQ: do nothing */ - return IRQ_NONE; - } + spin_lock(&player->irq_lock); + if (!player->substream) + goto irq_spin_unlock; + + snd_pcm_stream_lock(player->substream); + if (player->state == UNIPERIF_STATE_STOPPED) + goto stream_unlock; /* Get interrupt status & clear them immediately */ status = GET_UNIPERIF_ITS(player); @@ -88,9 +91,7 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id) SET_UNIPERIF_ITM_BCLR_FIFO_ERROR(player); /* Stop the player */ - snd_pcm_stream_lock(player->substream); snd_pcm_stop(player->substream, SNDRV_PCM_STATE_XRUN); - snd_pcm_stream_unlock(player->substream); } ret = IRQ_HANDLED; @@ -104,9 +105,7 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id) SET_UNIPERIF_ITM_BCLR_DMA_ERROR(player); /* Stop the player */ - snd_pcm_stream_lock(player->substream); snd_pcm_stop(player->substream, SNDRV_PCM_STATE_XRUN); - snd_pcm_stream_unlock(player->substream); ret = IRQ_HANDLED; } @@ -116,7 +115,8 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id) if (!player->underflow_enabled) { dev_err(player->dev, "unexpected Underflow recovering\n"); - return -EPERM; + ret = -EPERM; + goto stream_unlock; } /* Read the underflow recovery duration */ tmp = GET_UNIPERIF_STATUS_1_UNDERFLOW_DURATION(player); @@ -138,13 +138,16 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id) dev_err(player->dev, "Underflow recovery failed\n"); /* Stop the player */ - snd_pcm_stream_lock(player->substream); snd_pcm_stop(player->substream, SNDRV_PCM_STATE_XRUN); - snd_pcm_stream_unlock(player->substream); ret = IRQ_HANDLED; } +stream_unlock: + snd_pcm_stream_unlock(player->substream); +irq_spin_unlock: + spin_unlock(&player->irq_lock); + return ret; } @@ -588,6 +591,7 @@ static int uni_player_ctl_iec958_put(struct snd_kcontrol *kcontrol, struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); struct uniperif *player = priv->dai_data.uni; struct snd_aes_iec958 *iec958 = &player->stream_settings.iec958; + unsigned long flags; mutex_lock(&player->ctrl_lock); iec958->status[0] = ucontrol->value.iec958.status[0]; @@ -596,12 +600,14 @@ static int uni_player_ctl_iec958_put(struct snd_kcontrol *kcontrol, iec958->status[3] = ucontrol->value.iec958.status[3]; mutex_unlock(&player->ctrl_lock); + spin_lock_irqsave(&player->irq_lock, flags); if (player->substream && player->substream->runtime) uni_player_set_channel_status(player, player->substream->runtime); else uni_player_set_channel_status(player, NULL); + spin_unlock_irqrestore(&player->irq_lock, flags); return 0; } @@ -686,9 +692,12 @@ static int uni_player_startup(struct snd_pcm_substream *substream, { struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); struct uniperif *player = priv->dai_data.uni; + unsigned long flags; int ret; + spin_lock_irqsave(&player->irq_lock, flags); player->substream = substream; + spin_unlock_irqrestore(&player->irq_lock, flags); player->clk_adj = 0; @@ -986,12 +995,15 @@ static void uni_player_shutdown(struct snd_pcm_substream *substream, { struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); struct uniperif *player = priv->dai_data.uni; + unsigned long flags; + spin_lock_irqsave(&player->irq_lock, flags); if (player->state != UNIPERIF_STATE_STOPPED) /* Stop the player */ uni_player_stop(player); player->substream = NULL; + spin_unlock_irqrestore(&player->irq_lock, flags); } static int uni_player_parse_dt_audio_glue(struct platform_device *pdev, @@ -1096,6 +1108,7 @@ int uni_player_init(struct platform_device *pdev, } mutex_init(&player->ctrl_lock); + spin_lock_init(&player->irq_lock); /* Ensure that disabled by default */ SET_UNIPERIF_CONFIG_BACK_STALL_REQ_DISABLE(player); diff --git a/sound/soc/sti/uniperif_reader.c b/sound/soc/sti/uniperif_reader.c index 93a8df6ed880..ee0055e60852 100644 --- a/sound/soc/sti/uniperif_reader.c +++ b/sound/soc/sti/uniperif_reader.c @@ -46,10 +46,15 @@ static irqreturn_t uni_reader_irq_handler(int irq, void *dev_id) struct uniperif *reader = dev_id; unsigned int status; + spin_lock(&reader->irq_lock); + if (!reader->substream) + goto irq_spin_unlock; + + snd_pcm_stream_lock(reader->substream); if (reader->state == UNIPERIF_STATE_STOPPED) { /* Unexpected IRQ: do nothing */ dev_warn(reader->dev, "unexpected IRQ\n"); - return IRQ_HANDLED; + goto stream_unlock; } /* Get interrupt status & clear them immediately */ @@ -60,13 +65,16 @@ static irqreturn_t uni_reader_irq_handler(int irq, void *dev_id) if (unlikely(status & UNIPERIF_ITS_FIFO_ERROR_MASK(reader))) { dev_err(reader->dev, "FIFO error detected\n"); - snd_pcm_stream_lock(reader->substream); snd_pcm_stop(reader->substream, SNDRV_PCM_STATE_XRUN); - snd_pcm_stream_unlock(reader->substream); - return IRQ_HANDLED; + ret = IRQ_HANDLED; } +stream_unlock: + snd_pcm_stream_unlock(reader->substream); +irq_spin_unlock: + spin_unlock(&reader->irq_lock); + return ret; } @@ -347,9 +355,12 @@ static int uni_reader_startup(struct snd_pcm_substream *substream, { struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); struct uniperif *reader = priv->dai_data.uni; + unsigned long flags; int ret; + spin_lock_irqsave(&reader->irq_lock, flags); reader->substream = substream; + spin_unlock_irqrestore(&reader->irq_lock, flags); if (!UNIPERIF_TYPE_IS_TDM(reader)) return 0; @@ -375,12 +386,15 @@ static void uni_reader_shutdown(struct snd_pcm_substream *substream, { struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); struct uniperif *reader = priv->dai_data.uni; + unsigned long flags; + spin_lock_irqsave(&reader->irq_lock, flags); if (reader->state != UNIPERIF_STATE_STOPPED) { /* Stop the reader */ uni_reader_stop(reader); } reader->substream = NULL; + spin_unlock_irqrestore(&reader->irq_lock, flags); } static const struct snd_soc_dai_ops uni_reader_dai_ops = { @@ -415,6 +429,8 @@ int uni_reader_init(struct platform_device *pdev, return -EBUSY; } + spin_lock_init(&reader->irq_lock); + return 0; } EXPORT_SYMBOL_GPL(uni_reader_init); -- cgit v1.2.1