From cf4f7fc3e7336e2e946880890e60ed36178889ea Mon Sep 17 00:00:00 2001 From: Fabio Falzoi Date: Mon, 4 Aug 2014 17:08:07 +0200 Subject: [PATCH 001/251] ASoC: fsl-ssi: Support for SND_SOC_DAIFMT_CBM_CFS Add SND_SOC_DAIFMT_CBM_CFS support for Freescale architecture. Successfully tested on i.MX 6Quad Wandboard and UDOO boards connected to the pcm1792a codec. In CBM_CFS mode, when using a sample size of 16 bits, we cannot use CCSR_SSI_SCR_I2S_MODE_MASTER since we get a frame sync every 16 bits. Signed-off-by: Michael Trimarchi Signed-off-by: Fabio Falzoi Tested-by: Angelo Adamo Acked-by: Timur Tabi Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_ssi.c | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 87eb5776a39b..2fc3e6683e4f 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -259,6 +259,11 @@ static bool fsl_ssi_is_i2s_master(struct fsl_ssi_private *ssi_private) SND_SOC_DAIFMT_CBS_CFS; } +static bool fsl_ssi_is_i2s_cbm_cfs(struct fsl_ssi_private *ssi_private) +{ + return (ssi_private->dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) == + SND_SOC_DAIFMT_CBM_CFS; +} /** * fsl_ssi_isr: SSI interrupt handler * @@ -705,6 +710,23 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, } } + if (!fsl_ssi_is_ac97(ssi_private)) { + u8 i2smode; + /* + * Switch to normal net mode in order to have a frame sync + * signal every 32 bits instead of 16 bits + */ + if (fsl_ssi_is_i2s_cbm_cfs(ssi_private) && sample_size == 16) + i2smode = CCSR_SSI_SCR_I2S_MODE_NORMAL | + CCSR_SSI_SCR_NET; + else + i2smode = ssi_private->i2s_mode; + + regmap_update_bits(regs, CCSR_SSI_SCR, + CCSR_SSI_SCR_NET | CCSR_SSI_SCR_I2S_MODE_MASK, + channels == 1 ? 0 : i2smode); + } + /* * FIXME: The documentation says that SxCCR[WL] should not be * modified while the SSI is enabled. The only time this can @@ -724,11 +746,6 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, regmap_update_bits(regs, CCSR_SSI_SRCCR, CCSR_SSI_SxCCR_WL_MASK, wl); - if (!fsl_ssi_is_ac97(ssi_private)) - regmap_update_bits(regs, CCSR_SSI_SCR, - CCSR_SSI_SCR_NET | CCSR_SSI_SCR_I2S_MODE_MASK, - channels == 1 ? 0 : ssi_private->i2s_mode); - return 0; } @@ -780,6 +797,7 @@ static int _fsl_ssi_set_dai_fmt(struct fsl_ssi_private *ssi_private, switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFS: case SND_SOC_DAIFMT_CBS_CFS: ssi_private->i2s_mode |= CCSR_SSI_SCR_I2S_MODE_MASTER; regmap_update_bits(regs, CCSR_SSI_STCCR, @@ -853,6 +871,11 @@ static int _fsl_ssi_set_dai_fmt(struct fsl_ssi_private *ssi_private, case SND_SOC_DAIFMT_CBM_CFM: scr &= ~CCSR_SSI_SCR_SYS_CLK_EN; break; + case SND_SOC_DAIFMT_CBM_CFS: + strcr &= ~CCSR_SSI_STCR_TXDIR; + strcr |= CCSR_SSI_STCR_TFDIR; + scr &= ~CCSR_SSI_SCR_SYS_CLK_EN; + break; default: return -EINVAL; } From d177143c3670aa57ee08c73880beb55ee9d8ab7c Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Fri, 8 Aug 2014 14:47:21 +0800 Subject: [PATCH 002/251] ASoC: fsl_esai: refine esai for TDM support Original driver didn't store the number of slots, just fix the slot number to 2, use this default number to calculate bclk and pins for TX/RX. In this patch, add one parameter for slots, and update the calculation of bclk and pins of TX/RX. Then driver will be compatible with slots > 2 in TDM mode. Signed-off-by: Shengjiu Wang Acked-by: Nicolin Chen Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_esai.c | 14 +++++++++++--- sound/soc/fsl/fsl_esai.h | 8 ++++---- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index 72d154e7dd03..f252370073e5 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c @@ -38,6 +38,7 @@ * @fsysclk: system clock source to derive HCK, SCK and FS * @fifo_depth: depth of tx/rx FIFO * @slot_width: width of each DAI slot + * @slots: number of slots * @hck_rate: clock rate of desired HCKx clock * @sck_rate: clock rate of desired SCKx clock * @hck_dir: the direction of HCKx pads @@ -56,6 +57,7 @@ struct fsl_esai { struct clk *fsysclk; u32 fifo_depth; u32 slot_width; + u32 slots; u32 hck_rate[2]; u32 sck_rate[2]; bool hck_dir[2]; @@ -363,6 +365,7 @@ static int fsl_esai_set_dai_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, ESAI_xSMB_xS_MASK, ESAI_xSMB_xS(rx_mask)); esai_priv->slot_width = slot_width; + esai_priv->slots = slots; return 0; } @@ -510,10 +513,11 @@ static int fsl_esai_hw_params(struct snd_pcm_substream *substream, bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; u32 width = snd_pcm_format_width(params_format(params)); u32 channels = params_channels(params); + u32 pins = DIV_ROUND_UP(channels, esai_priv->slots); u32 bclk, mask, val; int ret; - bclk = params_rate(params) * esai_priv->slot_width * 2; + bclk = params_rate(params) * esai_priv->slot_width * esai_priv->slots; ret = fsl_esai_set_bclk(dai, tx, bclk); if (ret) @@ -530,7 +534,7 @@ static int fsl_esai_hw_params(struct snd_pcm_substream *substream, mask = ESAI_xFCR_xFR_MASK | ESAI_xFCR_xWA_MASK | ESAI_xFCR_xFWM_MASK | (tx ? ESAI_xFCR_TE_MASK | ESAI_xFCR_TIEN : ESAI_xFCR_RE_MASK); val = ESAI_xFCR_xWA(width) | ESAI_xFCR_xFWM(esai_priv->fifo_depth) | - (tx ? ESAI_xFCR_TE(channels) | ESAI_xFCR_TIEN : ESAI_xFCR_RE(channels)); + (tx ? ESAI_xFCR_TE(pins) | ESAI_xFCR_TIEN : ESAI_xFCR_RE(pins)); regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx), mask, val); @@ -565,6 +569,7 @@ static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd, struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai); bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; u8 i, channels = substream->runtime->channels; + u32 pins = DIV_ROUND_UP(channels, esai_priv->slots); switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -579,7 +584,7 @@ static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd, regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), tx ? ESAI_xCR_TE_MASK : ESAI_xCR_RE_MASK, - tx ? ESAI_xCR_TE(channels) : ESAI_xCR_RE(channels)); + tx ? ESAI_xCR_TE(pins) : ESAI_xCR_RE(pins)); break; case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_STOP: @@ -783,6 +788,9 @@ static int fsl_esai_probe(struct platform_device *pdev) /* Set a default slot size */ esai_priv->slot_width = 32; + /* Set a default slot number */ + esai_priv->slots = 2; + /* Set a default master/slave state */ esai_priv->slave_mode = true; diff --git a/sound/soc/fsl/fsl_esai.h b/sound/soc/fsl/fsl_esai.h index 75e14033e8d8..91a550f4a10d 100644 --- a/sound/soc/fsl/fsl_esai.h +++ b/sound/soc/fsl/fsl_esai.h @@ -130,8 +130,8 @@ #define ESAI_xFCR_RE_WIDTH 4 #define ESAI_xFCR_TE_MASK (((1 << ESAI_xFCR_TE_WIDTH) - 1) << ESAI_xFCR_xE_SHIFT) #define ESAI_xFCR_RE_MASK (((1 << ESAI_xFCR_RE_WIDTH) - 1) << ESAI_xFCR_xE_SHIFT) -#define ESAI_xFCR_TE(x) ((ESAI_xFCR_TE_MASK >> (ESAI_xFCR_TE_WIDTH - ((x + 1) >> 1))) & ESAI_xFCR_TE_MASK) -#define ESAI_xFCR_RE(x) ((ESAI_xFCR_RE_MASK >> (ESAI_xFCR_RE_WIDTH - ((x + 1) >> 1))) & ESAI_xFCR_RE_MASK) +#define ESAI_xFCR_TE(x) ((ESAI_xFCR_TE_MASK >> (ESAI_xFCR_TE_WIDTH - x)) & ESAI_xFCR_TE_MASK) +#define ESAI_xFCR_RE(x) ((ESAI_xFCR_RE_MASK >> (ESAI_xFCR_RE_WIDTH - x)) & ESAI_xFCR_RE_MASK) #define ESAI_xFCR_xFR_SHIFT 1 #define ESAI_xFCR_xFR_MASK (1 << ESAI_xFCR_xFR_SHIFT) #define ESAI_xFCR_xFR (1 << ESAI_xFCR_xFR_SHIFT) @@ -272,8 +272,8 @@ #define ESAI_xCR_RE_WIDTH 4 #define ESAI_xCR_TE_MASK (((1 << ESAI_xCR_TE_WIDTH) - 1) << ESAI_xCR_xE_SHIFT) #define ESAI_xCR_RE_MASK (((1 << ESAI_xCR_RE_WIDTH) - 1) << ESAI_xCR_xE_SHIFT) -#define ESAI_xCR_TE(x) ((ESAI_xCR_TE_MASK >> (ESAI_xCR_TE_WIDTH - ((x + 1) >> 1))) & ESAI_xCR_TE_MASK) -#define ESAI_xCR_RE(x) ((ESAI_xCR_RE_MASK >> (ESAI_xCR_RE_WIDTH - ((x + 1) >> 1))) & ESAI_xCR_RE_MASK) +#define ESAI_xCR_TE(x) ((ESAI_xCR_TE_MASK >> (ESAI_xCR_TE_WIDTH - x)) & ESAI_xCR_TE_MASK) +#define ESAI_xCR_RE(x) ((ESAI_xCR_RE_MASK >> (ESAI_xCR_RE_WIDTH - x)) & ESAI_xCR_RE_MASK) /* * Transmit Clock Control Register -- REG_ESAI_TCCR 0xD8 From 8ad9f9efcc7656cafb56bbbcd545f817a742bf32 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Mon, 16 Jun 2014 16:33:46 +0200 Subject: [PATCH 003/251] ASoC: Drop const from struct snd_soc_dai_link *of_node members MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dropping the const qualifiers prevents "passing argument 1 of ‘of_node_put’ discards ‘const’ qualifier from pointer target type" type warnings when compiling the code dropping reference to cpu_of_node, codec_of_node or platform_of_node with with an of_node_put() function call. This lets us to avoid casting to struct device_node * or caching variables internally in drivers just to be able to properly drop a reference to the OF node on clean up paths. Signed-off-by: Sylwester Nawrocki Signed-off-by: Mark Brown --- include/sound/soc.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index be6ecae247b0..fd58371c63ff 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -897,7 +897,7 @@ struct snd_soc_dai_link { * only for codec to codec links, or systems using device tree. */ const char *cpu_name; - const struct device_node *cpu_of_node; + struct device_node *cpu_of_node; /* * You MAY specify the DAI name of the CPU DAI. If this information is * omitted, the CPU-side DAI is matched using .cpu_name/.cpu_of_node @@ -909,7 +909,7 @@ struct snd_soc_dai_link { * DT/OF node, but not both. */ const char *codec_name; - const struct device_node *codec_of_node; + struct device_node *codec_of_node; /* You MUST specify the DAI name within the codec */ const char *codec_dai_name; @@ -922,7 +922,7 @@ struct snd_soc_dai_link { * do not need a platform. */ const char *platform_name; - const struct device_node *platform_of_node; + struct device_node *platform_of_node; int be_id; /* optional ID for machine driver BE identification */ const struct snd_soc_pcm_stream *params; From eef5bb2445ca49911c93c08ed0fb2ea7363ea945 Mon Sep 17 00:00:00 2001 From: Brian Austin Date: Mon, 4 Aug 2014 15:11:16 -0500 Subject: [PATCH 004/251] ASoC: cs35l32: Add support for CS35L32 Boosted Amplifier This patch adds support for the Cirrus Logic CS35L32 Boosted Amplifier I2S output provides monitor data to the SOC/CODEC/DSP for speaker protection/enhancement algorithms Signed-off-by: Brian Austin Signed-off-by: Mark Brown --- include/dt-bindings/sound/cs35l32.h | 26 ++ sound/soc/codecs/Kconfig | 5 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/cs35l32.c | 647 ++++++++++++++++++++++++++++ sound/soc/codecs/cs35l32.h | 93 ++++ 5 files changed, 773 insertions(+) create mode 100644 include/dt-bindings/sound/cs35l32.h create mode 100644 sound/soc/codecs/cs35l32.c create mode 100644 sound/soc/codecs/cs35l32.h diff --git a/include/dt-bindings/sound/cs35l32.h b/include/dt-bindings/sound/cs35l32.h new file mode 100644 index 000000000000..0c6d6a3c15a2 --- /dev/null +++ b/include/dt-bindings/sound/cs35l32.h @@ -0,0 +1,26 @@ +#ifndef __DT_CS35L32_H +#define __DT_CS35L32_H + +#define CS35L32_BOOST_MGR_AUTO 0 +#define CS35L32_BOOST_MGR_AUTO_AUDIO 1 +#define CS35L32_BOOST_MGR_BYPASS 2 +#define CS35L32_BOOST_MGR_FIXED 3 + +#define CS35L32_DATA_CFG_LR_VP 0 +#define CS35L32_DATA_CFG_LR_STAT 1 +#define CS35L32_DATA_CFG_LR 2 +#define CS35L32_DATA_CFG_LR_VPSTAT 3 + +#define CS35L32_BATT_THRESH_3_1V 0 +#define CS35L32_BATT_THRESH_3_2V 1 +#define CS35L32_BATT_THRESH_3_3V 2 +#define CS35L32_BATT_THRESH_3_4V 3 + +#define CS35L32_BATT_RECOV_3_1V 0 +#define CS35L32_BATT_RECOV_3_2V 1 +#define CS35L32_BATT_RECOV_3_3V 2 +#define CS35L32_BATT_RECOV_3_4V 3 +#define CS35L32_BATT_RECOV_3_5V 4 +#define CS35L32_BATT_RECOV_3_6V 5 + +#endif /* __DT_CS35L32_H */ diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 8838838e25ed..77e5383b4361 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -43,6 +43,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_ALC5623 if I2C select SND_SOC_ALC5632 if I2C select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC + select SND_SOC_CS35L32 if I2C select SND_SOC_CS42L51_I2C if I2C select SND_SOC_CS42L52 if I2C && INPUT select SND_SOC_CS42L56 if I2C && INPUT @@ -323,6 +324,10 @@ config SND_SOC_ALC5632 config SND_SOC_CQ0093VC tristate +config SND_SOC_CS35L32 + tristate "Cirrus Logic CS35L32 CODEC" + depends on I2C + config SND_SOC_CS42L51 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 20afe0f0c5be..1dacefbdac3c 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -32,6 +32,7 @@ snd-soc-ak4671-objs := ak4671.o snd-soc-ak5386-objs := ak5386.o snd-soc-arizona-objs := arizona.o snd-soc-cq93vc-objs := cq93vc.o +snd-soc-cs35l32-objs := cs35l32.o snd-soc-cs42l51-objs := cs42l51.o snd-soc-cs42l51-i2c-objs := cs42l51-i2c.o snd-soc-cs42l52-objs := cs42l52.o @@ -203,6 +204,7 @@ obj-$(CONFIG_SND_SOC_ALC5623) += snd-soc-alc5623.o obj-$(CONFIG_SND_SOC_ALC5632) += snd-soc-alc5632.o obj-$(CONFIG_SND_SOC_ARIZONA) += snd-soc-arizona.o obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o +obj-$(CONFIG_SND_SOC_CS35L32) += snd-soc-cs35l32.o obj-$(CONFIG_SND_SOC_CS42L51) += snd-soc-cs42l51.o obj-$(CONFIG_SND_SOC_CS42L51_I2C) += snd-soc-cs42l51-i2c.o obj-$(CONFIG_SND_SOC_CS42L52) += snd-soc-cs42l52.o diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c new file mode 100644 index 000000000000..90565d59def7 --- /dev/null +++ b/sound/soc/codecs/cs35l32.c @@ -0,0 +1,647 @@ +/* + * cs35l32.c -- CS35L32 ALSA SoC audio driver + * + * Copyright 2014 CirrusLogic, 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 "cs35l32.h" + +#define CS35L32_NUM_SUPPLIES 2 +static const char *const cs35l32_supply_names[CS35L32_NUM_SUPPLIES] = { + "VA", + "VP", +}; + +struct cs35l32_private { + struct regmap *regmap; + struct snd_soc_codec *codec; + struct regulator_bulk_data supplies[CS35L32_NUM_SUPPLIES]; + struct cs35l32_platform_data pdata; + struct gpio_desc *reset_gpio; +}; + +static const struct reg_default cs35l32_reg_defaults[] = { + + { 0x06, 0x04 }, /* Power Ctl 1 */ + { 0x07, 0xE8 }, /* Power Ctl 2 */ + { 0x08, 0x40 }, /* Clock Ctl */ + { 0x09, 0x20 }, /* Low Battery Threshold */ + { 0x0A, 0x00 }, /* Voltage Monitor [RO] */ + { 0x0B, 0x40 }, /* Conv Peak Curr Protection CTL */ + { 0x0C, 0x07 }, /* IMON Scaling */ + { 0x0D, 0x03 }, /* Audio/LED Pwr Manager */ + { 0x0F, 0x20 }, /* Serial Port Control */ + { 0x10, 0x14 }, /* Class D Amp CTL */ + { 0x11, 0x00 }, /* Protection Release CTL */ + { 0x12, 0xFF }, /* Interrupt Mask 1 */ + { 0x13, 0xFF }, /* Interrupt Mask 2 */ + { 0x14, 0xFF }, /* Interrupt Mask 3 */ + { 0x19, 0x00 }, /* LED Flash Mode Current */ + { 0x1A, 0x00 }, /* LED Movie Mode Current */ + { 0x1B, 0x20 }, /* LED Flash Timer */ + { 0x1C, 0x00 }, /* LED Flash Inhibit Current */ +}; + +static bool cs35l32_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS35L32_DEVID_AB: + case CS35L32_DEVID_CD: + case CS35L32_DEVID_E: + case CS35L32_FAB_ID: + case CS35L32_REV_ID: + case CS35L32_PWRCTL1: + case CS35L32_PWRCTL2: + case CS35L32_CLK_CTL: + case CS35L32_BATT_THRESHOLD: + case CS35L32_VMON: + case CS35L32_BST_CPCP_CTL: + case CS35L32_IMON_SCALING: + case CS35L32_AUDIO_LED_MNGR: + case CS35L32_ADSP_CTL: + case CS35L32_CLASSD_CTL: + case CS35L32_PROTECT_CTL: + case CS35L32_INT_MASK_1: + case CS35L32_INT_MASK_2: + case CS35L32_INT_MASK_3: + case CS35L32_INT_STATUS_1: + case CS35L32_INT_STATUS_2: + case CS35L32_INT_STATUS_3: + case CS35L32_LED_STATUS: + case CS35L32_FLASH_MODE: + case CS35L32_MOVIE_MODE: + case CS35L32_FLASH_TIMER: + case CS35L32_FLASH_INHIBIT: + return true; + default: + return false; + } +} + +static bool cs35l32_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS35L32_DEVID_AB: + case CS35L32_DEVID_CD: + case CS35L32_DEVID_E: + case CS35L32_FAB_ID: + case CS35L32_REV_ID: + case CS35L32_INT_STATUS_1: + case CS35L32_INT_STATUS_2: + case CS35L32_INT_STATUS_3: + case CS35L32_LED_STATUS: + return 1; + default: + return 0; + } +} + +static bool cs35l32_precious_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS35L32_INT_STATUS_1: + case CS35L32_INT_STATUS_2: + case CS35L32_INT_STATUS_3: + case CS35L32_LED_STATUS: + return 1; + default: + return 0; + } +} + +static DECLARE_TLV_DB_SCALE(classd_ctl_tlv, 900, 300, 0); + +static const struct snd_kcontrol_new imon_ctl = + SOC_DAPM_SINGLE("Switch", CS35L32_PWRCTL2, 6, 1, 1); + +static const struct snd_kcontrol_new vmon_ctl = + SOC_DAPM_SINGLE("Switch", CS35L32_PWRCTL2, 7, 1, 1); + +static const struct snd_kcontrol_new vpmon_ctl = + SOC_DAPM_SINGLE("Switch", CS35L32_PWRCTL2, 5, 1, 1); + +static const struct snd_kcontrol_new cs35l32_snd_controls[] = { + SOC_SINGLE_TLV("Speaker Volume", CS35L32_CLASSD_CTL, + 3, 0x04, 1, classd_ctl_tlv), + SOC_SINGLE("Zero Cross Switch", CS35L32_CLASSD_CTL, 2, 1, 0), + SOC_SINGLE("Gain Manager Switch", CS35L32_AUDIO_LED_MNGR, 3, 1, 0), +}; + +static const struct snd_soc_dapm_widget cs35l32_dapm_widgets[] = { + + SND_SOC_DAPM_SUPPLY("BOOST", CS35L32_PWRCTL1, 2, 1, NULL, 0), + SND_SOC_DAPM_OUT_DRV("Speaker", CS35L32_PWRCTL1, 7, 1, NULL, 0), + + SND_SOC_DAPM_AIF_OUT("SDOUT", NULL, 0, CS35L32_PWRCTL2, 3, 1), + + SND_SOC_DAPM_INPUT("VP"), + SND_SOC_DAPM_INPUT("ISENSE"), + SND_SOC_DAPM_INPUT("VSENSE"), + + SND_SOC_DAPM_SWITCH("VMON ADC", CS35L32_PWRCTL2, 7, 1, &vmon_ctl), + SND_SOC_DAPM_SWITCH("IMON ADC", CS35L32_PWRCTL2, 6, 1, &imon_ctl), + SND_SOC_DAPM_SWITCH("VPMON ADC", CS35L32_PWRCTL2, 5, 1, &vpmon_ctl), +}; + +static const struct snd_soc_dapm_route cs35l32_audio_map[] = { + + {"Speaker", NULL, "BOOST"}, + + {"VMON ADC", NULL, "VSENSE"}, + {"IMON ADC", NULL, "ISENSE"}, + {"VPMON ADC", NULL, "VP"}, + + {"SDOUT", "Switch", "VMON ADC"}, + {"SDOUT", "Switch", "IMON ADC"}, + {"SDOUT", "Switch", "VPMON ADC"}, + + {"Capture", NULL, "SDOUT"}, +}; + +static int cs35l32_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + snd_soc_update_bits(codec, CS35L32_ADSP_CTL, + CS35L32_ADSP_MASTER_MASK, + CS35L32_ADSP_MASTER_MASK); + break; + case SND_SOC_DAIFMT_CBS_CFS: + snd_soc_update_bits(codec, CS35L32_ADSP_CTL, + CS35L32_ADSP_MASTER_MASK, 0); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int cs35l32_set_tristate(struct snd_soc_dai *dai, int tristate) +{ + struct snd_soc_codec *codec = dai->codec; + + return snd_soc_update_bits(codec, CS35L32_PWRCTL2, + CS35L32_SDOUT_3ST, tristate << 3); +} + +static const struct snd_soc_dai_ops cs35l32_ops = { + .set_fmt = cs35l32_set_dai_fmt, + .set_tristate = cs35l32_set_tristate, +}; + +static struct snd_soc_dai_driver cs35l32_dai[] = { + { + .name = "cs35l32-monitor", + .id = 0, + .capture = { + .stream_name = "Capture", + .channels_min = 2, + .channels_max = 2, + .rates = CS35L32_RATES, + .formats = CS35L32_FORMATS, + }, + .ops = &cs35l32_ops, + .symmetric_rates = 1, + } +}; + +static int cs35l32_codec_set_sysclk(struct snd_soc_codec *codec, + int clk_id, int source, unsigned int freq, int dir) +{ + + switch (freq) { + case 6000000: + snd_soc_update_bits(codec, CS35L32_CLK_CTL, + CS35L32_MCLK_DIV2_MASK, 0); + snd_soc_update_bits(codec, CS35L32_CLK_CTL, + CS35L32_MCLK_RATIO_MASK, + CS35L32_MCLK_RATIO); + break; + case 12000000: + snd_soc_update_bits(codec, CS35L32_CLK_CTL, + CS35L32_MCLK_DIV2_MASK, + CS35L32_MCLK_DIV2_MASK); + snd_soc_update_bits(codec, CS35L32_CLK_CTL, + CS35L32_MCLK_RATIO_MASK, + CS35L32_MCLK_RATIO); + break; + case 6144000: + snd_soc_update_bits(codec, CS35L32_CLK_CTL, + CS35L32_MCLK_DIV2_MASK, 0); + snd_soc_update_bits(codec, CS35L32_CLK_CTL, + CS35L32_MCLK_RATIO_MASK, 0); + break; + case 12288000: + snd_soc_update_bits(codec, CS35L32_CLK_CTL, + CS35L32_MCLK_DIV2_MASK, + CS35L32_MCLK_DIV2_MASK); + snd_soc_update_bits(codec, CS35L32_CLK_CTL, + CS35L32_MCLK_RATIO_MASK, 0); + break; + default: + return -EINVAL; + } + + return 0; +} + +static struct snd_soc_codec_driver soc_codec_dev_cs35l32 = { + .set_sysclk = cs35l32_codec_set_sysclk, + + .dapm_widgets = cs35l32_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(cs35l32_dapm_widgets), + .dapm_routes = cs35l32_audio_map, + .num_dapm_routes = ARRAY_SIZE(cs35l32_audio_map), + + .controls = cs35l32_snd_controls, + .num_controls = ARRAY_SIZE(cs35l32_snd_controls), +}; + +/* Current and threshold powerup sequence Pg37 in datasheet */ +static const struct reg_default cs35l32_monitor_patch[] = { + + { 0x00, 0x99 }, + { 0x48, 0x17 }, + { 0x49, 0x56 }, + { 0x43, 0x01 }, + { 0x3B, 0x62 }, + { 0x3C, 0x80 }, + { 0x00, 0x00 }, +}; + +static struct regmap_config cs35l32_regmap = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = CS35L32_MAX_REGISTER, + .reg_defaults = cs35l32_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(cs35l32_reg_defaults), + .volatile_reg = cs35l32_volatile_register, + .readable_reg = cs35l32_readable_register, + .precious_reg = cs35l32_precious_register, + .cache_type = REGCACHE_RBTREE, +}; + +static int cs35l32_handle_of_data(struct i2c_client *i2c_client, + struct cs35l32_platform_data *pdata) +{ + struct device_node *np = i2c_client->dev.of_node; + unsigned int val; + + if (of_property_read_u32(np, "cirrus,sdout-share", &val) >= 0) + pdata->sdout_share = val; + + of_property_read_u32(np, "cirrus,boost-manager", &val); + switch (val) { + case CS35L32_BOOST_MGR_AUTO: + case CS35L32_BOOST_MGR_AUTO_AUDIO: + case CS35L32_BOOST_MGR_BYPASS: + case CS35L32_BOOST_MGR_FIXED: + pdata->boost_mng = val; + break; + default: + dev_err(&i2c_client->dev, + "Wrong cirrus,boost-manager DT value %d\n", val); + pdata->boost_mng = CS35L32_BOOST_MGR_BYPASS; + } + + of_property_read_u32(np, "cirrus,sdout-datacfg", &val); + switch (val) { + case CS35L32_DATA_CFG_LR_VP: + case CS35L32_DATA_CFG_LR_STAT: + case CS35L32_DATA_CFG_LR: + case CS35L32_DATA_CFG_LR_VPSTAT: + pdata->sdout_datacfg = val; + break; + default: + dev_err(&i2c_client->dev, + "Wrong cirrus,sdout-datacfg DT value %d\n", val); + pdata->sdout_datacfg = CS35L32_DATA_CFG_LR; + } + + of_property_read_u32(np, "cirrus,battery-threshold", &val); + switch (val) { + case CS35L32_BATT_THRESH_3_1V: + case CS35L32_BATT_THRESH_3_2V: + case CS35L32_BATT_THRESH_3_3V: + case CS35L32_BATT_THRESH_3_4V: + pdata->batt_thresh = val; + break; + default: + dev_err(&i2c_client->dev, + "Wrong cirrus,battery-threshold DT value %d\n", val); + pdata->batt_thresh = CS35L32_BATT_THRESH_3_3V; + } + + of_property_read_u32(np, "cirrus,battery-recovery", &val); + switch (val) { + case CS35L32_BATT_RECOV_3_1V: + case CS35L32_BATT_RECOV_3_2V: + case CS35L32_BATT_RECOV_3_3V: + case CS35L32_BATT_RECOV_3_4V: + case CS35L32_BATT_RECOV_3_5V: + case CS35L32_BATT_RECOV_3_6V: + pdata->batt_recov = val; + break; + default: + dev_err(&i2c_client->dev, + "Wrong cirrus,battery-recovery DT value %d\n", val); + pdata->batt_recov = CS35L32_BATT_RECOV_3_4V; + } + + return 0; +} + +static int cs35l32_i2c_probe(struct i2c_client *i2c_client, + const struct i2c_device_id *id) +{ + struct cs35l32_private *cs35l32; + struct cs35l32_platform_data *pdata = + dev_get_platdata(&i2c_client->dev); + int ret, i; + unsigned int devid = 0; + unsigned int reg; + + + cs35l32 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs35l32_private), + GFP_KERNEL); + if (!cs35l32) { + dev_err(&i2c_client->dev, "could not allocate codec\n"); + return -ENOMEM; + } + + i2c_set_clientdata(i2c_client, cs35l32); + + cs35l32->regmap = devm_regmap_init_i2c(i2c_client, &cs35l32_regmap); + if (IS_ERR(cs35l32->regmap)) { + ret = PTR_ERR(cs35l32->regmap); + dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret); + return ret; + } + + if (pdata) { + cs35l32->pdata = *pdata; + } else { + pdata = devm_kzalloc(&i2c_client->dev, + sizeof(struct cs35l32_platform_data), + GFP_KERNEL); + if (!pdata) { + dev_err(&i2c_client->dev, "could not allocate pdata\n"); + return -ENOMEM; + } + if (i2c_client->dev.of_node) { + ret = cs35l32_handle_of_data(i2c_client, + &cs35l32->pdata); + if (ret != 0) + return ret; + } + } + + for (i = 0; i < ARRAY_SIZE(cs35l32->supplies); i++) + cs35l32->supplies[i].supply = cs35l32_supply_names[i]; + + ret = devm_regulator_bulk_get(&i2c_client->dev, + ARRAY_SIZE(cs35l32->supplies), + cs35l32->supplies); + if (ret != 0) { + dev_err(&i2c_client->dev, + "Failed to request supplies: %d\n", ret); + return ret; + } + + ret = regulator_bulk_enable(ARRAY_SIZE(cs35l32->supplies), + cs35l32->supplies); + if (ret != 0) { + dev_err(&i2c_client->dev, + "Failed to enable supplies: %d\n", ret); + return ret; + } + + /* Reset the Device */ + cs35l32->reset_gpio = devm_gpiod_get(&i2c_client->dev, + "reset-gpios"); + if (IS_ERR(cs35l32->reset_gpio)) { + ret = PTR_ERR(cs35l32->reset_gpio); + if (ret != -ENOENT && ret != -ENOSYS) + return ret; + + cs35l32->reset_gpio = NULL; + } else { + ret = gpiod_direction_output(cs35l32->reset_gpio, 0); + if (ret) + return ret; + gpiod_set_value_cansleep(cs35l32->reset_gpio, 1); + } + + /* initialize codec */ + ret = regmap_read(cs35l32->regmap, CS35L32_DEVID_AB, ®); + devid = (reg & 0xFF) << 12; + + ret = regmap_read(cs35l32->regmap, CS35L32_DEVID_CD, ®); + devid |= (reg & 0xFF) << 4; + + ret = regmap_read(cs35l32->regmap, CS35L32_DEVID_E, ®); + devid |= (reg & 0xF0) >> 4; + + if (devid != CS35L32_CHIP_ID) { + ret = -ENODEV; + dev_err(&i2c_client->dev, + "CS35L32 Device ID (%X). Expected %X\n", + devid, CS35L32_CHIP_ID); + return ret; + } + + ret = regmap_read(cs35l32->regmap, CS35L32_REV_ID, ®); + if (ret < 0) { + dev_err(&i2c_client->dev, "Get Revision ID failed\n"); + return ret; + } + + ret = regmap_register_patch(cs35l32->regmap, cs35l32_monitor_patch, + ARRAY_SIZE(cs35l32_monitor_patch)); + if (ret < 0) { + dev_err(&i2c_client->dev, "Failed to apply errata patch\n"); + return ret; + } + + dev_info(&i2c_client->dev, + "Cirrus Logic CS35L32, Revision: %02X\n", reg & 0xFF); + + /* Setup VBOOST Management */ + if (cs35l32->pdata.boost_mng) + regmap_update_bits(cs35l32->regmap, CS35L32_AUDIO_LED_MNGR, + CS35L32_BOOST_MASK, + cs35l32->pdata.boost_mng); + + /* Setup ADSP Format Config */ + if (cs35l32->pdata.sdout_share) + regmap_update_bits(cs35l32->regmap, CS35L32_ADSP_CTL, + CS35L32_ADSP_SHARE_MASK, + cs35l32->pdata.sdout_share << 3); + + /* Setup ADSP Data Configuration */ + if (cs35l32->pdata.sdout_datacfg) + regmap_update_bits(cs35l32->regmap, CS35L32_ADSP_CTL, + CS35L32_ADSP_DATACFG_MASK, + cs35l32->pdata.sdout_datacfg << 4); + + /* Setup Low Battery Recovery */ + if (cs35l32->pdata.batt_recov) + regmap_update_bits(cs35l32->regmap, CS35L32_BATT_THRESHOLD, + CS35L32_BATT_REC_MASK, + cs35l32->pdata.batt_recov << 1); + + /* Setup Low Battery Threshold */ + if (cs35l32->pdata.batt_thresh) + regmap_update_bits(cs35l32->regmap, CS35L32_BATT_THRESHOLD, + CS35L32_BATT_THRESH_MASK, + cs35l32->pdata.batt_thresh << 4); + + /* Power down the AMP */ + regmap_update_bits(cs35l32->regmap, CS35L32_PWRCTL1, CS35L32_PDN_AMP, + CS35L32_PDN_AMP); + + /* Clear MCLK Error Bit since we don't have the clock yet */ + ret = regmap_read(cs35l32->regmap, CS35L32_INT_STATUS_1, ®); + + ret = snd_soc_register_codec(&i2c_client->dev, + &soc_codec_dev_cs35l32, cs35l32_dai, + ARRAY_SIZE(cs35l32_dai)); + if (ret < 0) + goto err_disable; + + return 0; + +err_disable: + regulator_bulk_disable(ARRAY_SIZE(cs35l32->supplies), + cs35l32->supplies); +} + +static int cs35l32_i2c_remove(struct i2c_client *i2c_client) +{ + struct cs35l32_private *cs35l32 = i2c_get_clientdata(i2c_client); + + snd_soc_unregister_codec(&i2c_client->dev); + + /* Hold down reset */ + if (cs35l32->reset_gpio) + gpiod_set_value_cansleep(cs35l32->reset_gpio, 0); + + regulator_bulk_free(ARRAY_SIZE(cs35l32->supplies), cs35l32->supplies); + + return 0; +} + +#ifdef CONFIG_PM_RUNTIME +static int cs35l32_runtime_suspend(struct device *dev) +{ + struct cs35l32_private *cs35l32 = dev_get_drvdata(dev); + + regcache_cache_only(cs35l32->regmap, true); + regcache_mark_dirty(cs35l32->regmap); + + /* Hold down reset */ + if (cs35l32->reset_gpio) + gpiod_set_value_cansleep(cs35l32->reset_gpio, 0); + + /* remove power */ + regulator_bulk_disable(ARRAY_SIZE(cs35l32->supplies), + cs35l32->supplies); + + return 0; +} + +static int cs35l32_runtime_resume(struct device *dev) +{ + struct cs35l32_private *cs35l32 = dev_get_drvdata(dev); + int ret; + + /* Enable power */ + ret = regulator_bulk_enable(ARRAY_SIZE(cs35l32->supplies), + cs35l32->supplies); + if (ret != 0) { + dev_err(dev, "Failed to enable supplies: %d\n", + ret); + return ret; + } + + if (cs35l32->reset_gpio) + gpiod_set_value_cansleep(cs35l32->reset_gpio, 1); + + regcache_cache_only(cs35l32->regmap, false); + regcache_sync(cs35l32->regmap); + + return 0; +} +#endif + +static const struct dev_pm_ops cs35l32_runtime_pm = { + SET_RUNTIME_PM_OPS(cs35l32_runtime_suspend, cs35l32_runtime_resume, + NULL) +}; + +static const struct of_device_id cs35l32_of_match[] = { + { .compatible = "cirrus,cs35l32", }, + {}, +}; +MODULE_DEVICE_TABLE(of, cs35l32_of_match); + + +static const struct i2c_device_id cs35l32_id[] = { + {"cs35l32", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, cs35l32_id); + +static struct i2c_driver cs35l32_i2c_driver = { + .driver = { + .name = "cs35l32", + .owner = THIS_MODULE, + .pm = &cs35l32_runtime_pm, + .of_match_table = cs35l32_of_match, + }, + .id_table = cs35l32_id, + .probe = cs35l32_i2c_probe, + .remove = cs35l32_i2c_remove, +}; + +module_i2c_driver(cs35l32_i2c_driver); + +MODULE_DESCRIPTION("ASoC CS35L32 driver"); +MODULE_AUTHOR("Brian Austin, Cirrus Logic Inc, "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs35l32.h b/sound/soc/codecs/cs35l32.h new file mode 100644 index 000000000000..31ab804a22bc --- /dev/null +++ b/sound/soc/codecs/cs35l32.h @@ -0,0 +1,93 @@ +/* + * cs35l32.h -- CS35L32 ALSA SoC audio driver + * + * Copyright 2014 CirrusLogic, 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 __CS35L32_H__ +#define __CS35L32_H__ + +struct cs35l32_platform_data { + /* Low Battery Threshold */ + unsigned int batt_thresh; + /* Low Battery Recovery */ + unsigned int batt_recov; + /* LED Current Management*/ + unsigned int led_mng; + /* Audio Gain w/ LED */ + unsigned int audiogain_mng; + /* Boost Management */ + unsigned int boost_mng; + /* Data CFG for DUAL device */ + unsigned int sdout_datacfg; + /* SDOUT Sharing */ + unsigned int sdout_share; +}; + +#define CS35L32_CHIP_ID 0x00035A32 +#define CS35L32_DEVID_AB 0x01 /* Device ID A & B [RO] */ +#define CS35L32_DEVID_CD 0x02 /* Device ID C & D [RO] */ +#define CS35L32_DEVID_E 0x03 /* Device ID E [RO] */ +#define CS35L32_FAB_ID 0x04 /* Fab ID [RO] */ +#define CS35L32_REV_ID 0x05 /* Revision ID [RO] */ +#define CS35L32_PWRCTL1 0x06 /* Power Ctl 1 */ +#define CS35L32_PWRCTL2 0x07 /* Power Ctl 2 */ +#define CS35L32_CLK_CTL 0x08 /* Clock Ctl */ +#define CS35L32_BATT_THRESHOLD 0x09 /* Low Battery Threshold */ +#define CS35L32_VMON 0x0A /* Voltage Monitor [RO] */ +#define CS35L32_BST_CPCP_CTL 0x0B /* Conv Peak Curr Protection CTL */ +#define CS35L32_IMON_SCALING 0x0C /* IMON Scaling */ +#define CS35L32_AUDIO_LED_MNGR 0x0D /* Audio/LED Pwr Manager */ +#define CS35L32_ADSP_CTL 0x0F /* Serial Port Control */ +#define CS35L32_CLASSD_CTL 0x10 /* Class D Amp CTL */ +#define CS35L32_PROTECT_CTL 0x11 /* Protection Release CTL */ +#define CS35L32_INT_MASK_1 0x12 /* Interrupt Mask 1 */ +#define CS35L32_INT_MASK_2 0x13 /* Interrupt Mask 2 */ +#define CS35L32_INT_MASK_3 0x14 /* Interrupt Mask 3 */ +#define CS35L32_INT_STATUS_1 0x15 /* Interrupt Status 1 [RO] */ +#define CS35L32_INT_STATUS_2 0x16 /* Interrupt Status 2 [RO] */ +#define CS35L32_INT_STATUS_3 0x17 /* Interrupt Status 3 [RO] */ +#define CS35L32_LED_STATUS 0x18 /* LED Lighting Status [RO] */ +#define CS35L32_FLASH_MODE 0x19 /* LED Flash Mode Current */ +#define CS35L32_MOVIE_MODE 0x1A /* LED Movie Mode Current */ +#define CS35L32_FLASH_TIMER 0x1B /* LED Flash Timer */ +#define CS35L32_FLASH_INHIBIT 0x1C /* LED Flash Inhibit Current */ +#define CS35L32_MAX_REGISTER 0x1C + +#define CS35L32_MCLK_DIV2 0x01 +#define CS35L32_MCLK_RATIO 0x01 +#define CS35L32_MCLKDIS 0x80 +#define CS35L32_PDN_ALL 0x01 +#define CS35L32_PDN_AMP 0x80 +#define CS35L32_PDN_BOOST 0x04 +#define CS35L32_PDN_IMON 0x40 +#define CS35L32_PDN_VMON 0x80 +#define CS35L32_PDN_VPMON 0x20 +#define CS35L32_PDN_ADSP 0x08 + +#define CS35L32_MCLK_DIV2_MASK 0x40 +#define CS35L32_MCLK_RATIO_MASK 0x01 +#define CS35L32_MCLK_MASK 0x41 +#define CS35L32_ADSP_MASTER_MASK 0x40 +#define CS35L32_BOOST_MASK 0x03 +#define CS35L32_GAIN_MGR_MASK 0x08 +#define CS35L32_ADSP_SHARE_MASK 0x08 +#define CS35L32_ADSP_DATACFG_MASK 0x30 +#define CS35L32_SDOUT_3ST 0x80 +#define CS35L32_BATT_REC_MASK 0x0E +#define CS35L32_BATT_THRESH_MASK 0x30 + +#define CS35L32_RATES (SNDRV_PCM_RATE_48000) +#define CS35L32_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + + +#endif From 9cf44690204db563ba065ed856546dc8a8b742a1 Mon Sep 17 00:00:00 2001 From: Brian Austin Date: Mon, 4 Aug 2014 15:11:17 -0500 Subject: [PATCH 005/251] ASoC: cs35l32: Add bindings for CS35L32 The patch adds device tree bindings file for the Cirrus Logic CS35L32 Signed-off-by: Brian Austin Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/cs35l32.txt | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/cs35l32.txt diff --git a/Documentation/devicetree/bindings/sound/cs35l32.txt b/Documentation/devicetree/bindings/sound/cs35l32.txt new file mode 100644 index 000000000000..1417d3f5cc22 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/cs35l32.txt @@ -0,0 +1,62 @@ +CS35L32 audio CODEC + +Required properties: + + - compatible : "cirrus,cs35l32" + + - reg : the I2C address of the device for I2C. Address is determined by the level + of the AD0 pin. Level 0 is 0x40 while Level 1 is 0x41. + + - VA-supply, VP-supply : power supplies for the device, + as covered in Documentation/devicetree/bindings/regulator/regulator.txt. + +Optional properties: + + - reset-gpios : a GPIO spec for the reset pin. If specified, it will be + deasserted before communication to the codec starts. + + - cirrus,boost-manager : Boost voltage control. + 0 = Automatically managed. Boost-converter output voltage is the higher + of the two: Class G or adaptive LED voltage. + 1 = Automatically managed irrespective of audio, adapting for low-power + dissipation when LEDs are ON, and operating in Fixed-Boost Bypass Mode + if LEDs are OFF (VBST = VP). + 2 = (Default) Boost voltage fixed in Bypass Mode (VBST = VP). + 3 = Boost voltage fixed at 5 V. + + - cirrus,sdout-datacfg : Data configuration for dual CS35L32 applications only. + Determines the data packed in a two-CS35L32 configuration. + 0 = Left/right channels VMON[11:0], IMON[11:0], VPMON[7:0]. + 1 = Left/right channels VMON[11:0], IMON[11:0], STATUS. + 2 = (Default) left/right channels VMON[15:0], IMON [15:0]. + 3 = Left/right channels VPMON[7:0], STATUS. + + - cirrus,sdout-share : SDOUT sharing. Determines whether one or two CS35L32 + devices are on board sharing SDOUT. + 0 = (Default) One IC. + 1 = Two IC's. + + - cirrus,battery-recovery : Low battery nominal recovery threshold, rising VP. + 0 = 3.1V + 1 = 3.2V + 2 = 3.3V (Default) + 3 = 3.4V + + - cirrus,battery-threshold : Low battery nominal threshold, falling VP. + 0 = 3.1V + 1 = 3.2V + 2 = 3.3V + 3 = 3.4V (Default) + 4 = 3.5V + 5 = 3.6V + +Example: + +codec: codec@40 { + compatible = "cirrus,cs35l32"; + reg = <0x40>; + reset-gpios = <&gpio 10 0>; + cirrus,boost-manager = <0x03>; + cirrus,sdout-datacfg = <0x02>; + VA-supply = <®_audio>; +}; From 38f57532ede565a3c71da7b7727369f374c51acb Mon Sep 17 00:00:00 2001 From: Brian Austin Date: Thu, 7 Aug 2014 09:34:38 -0500 Subject: [PATCH 006/251] ASoC: cs35l32: fix compile warning for i2c_probe Forgot to add a return for err_disable goto statement. Causes compile warning of control reaching end of non-void Signed-off-by: Brian Austin Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l32.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c index 90565d59def7..9c6b2723d343 100644 --- a/sound/soc/codecs/cs35l32.c +++ b/sound/soc/codecs/cs35l32.c @@ -549,6 +549,7 @@ static int cs35l32_i2c_probe(struct i2c_client *i2c_client, err_disable: regulator_bulk_disable(ARRAY_SIZE(cs35l32->supplies), cs35l32->supplies); + return ret; } static int cs35l32_i2c_remove(struct i2c_client *i2c_client) From 708b4351f08c08ea93f773fb9197bdd3f3b08273 Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Wed, 30 Jul 2014 19:27:38 +0800 Subject: [PATCH 007/251] ASoC: fsl: Add Freescale Generic ASoC Sound Card with ASRC support The Freescale Generic ASoC Sound Card is a general ASoC DAI Link driver that can be used, ideally, for all Freescale CPU DAI drivers and external CODECs. The idea of this generic sound card is a bit like ASoC Simple Card. However, for Freescale SoCs (especially those released in recent years), most of them have ASRC (Documentation/devicetree/bindings/sound/fsl,asrc.txt) inside. And this is a specific feature that might be painstakingly controlled and merged into the Simple Card driver. So having this driver will allow all Freescale SoC users to benefit from the simplification to support a new card and the capability of wide sample rates support through ASRC. The driver is initially designed for sound card using I2S or PCM DAI formats. However, it's also possible to merge those non-I2S/PCM type sound cards, such as S/PDIF audio and HDMI audio, into this card as long as the merge will not break the original function and as long as there is something redundant that can be abstracted along with I2S type sound cards. As an initial version, it only supports three cards that I can test: imx-audio-cs42888, a new card that links ESAI with CS42888 CODEC imx-audio-sgtl5000, just like the old imx-sgtl5000.c driver imx-audio-wm8962, just like the old imx-wm8962.c driver The driver is also compatible with the old Device Tree bindings of WM8962 and SGTL5000. So we may consider to remove those two drivers after this driver is totally enabled. (It needs to be added into defconfig) Signed-off-by: Nicolin Chen Signed-off-by: Mark Brown --- .../bindings/sound/fsl-asoc-card.txt | 82 +++ sound/soc/fsl/Kconfig | 16 + sound/soc/fsl/Makefile | 2 + sound/soc/fsl/fsl-asoc-card.c | 573 ++++++++++++++++++ 4 files changed, 673 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/fsl-asoc-card.txt create mode 100644 sound/soc/fsl/fsl-asoc-card.c diff --git a/Documentation/devicetree/bindings/sound/fsl-asoc-card.txt b/Documentation/devicetree/bindings/sound/fsl-asoc-card.txt new file mode 100644 index 000000000000..a96774c194c8 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/fsl-asoc-card.txt @@ -0,0 +1,82 @@ +Freescale Generic ASoC Sound Card with ASRC support + +The Freescale Generic ASoC Sound Card can be used, ideally, for all Freescale +SoCs connecting with external CODECs. + +The idea of this generic sound card is a bit like ASoC Simple Card. However, +for Freescale SoCs (especially those released in recent years), most of them +have ASRC (Documentation/devicetree/bindings/sound/fsl,asrc.txt) inside. And +this is a specific feature that might be painstakingly controlled and merged +into the Simple Card. + +So having this generic sound card allows all Freescale SoC users to benefit +from the simplification of a new card support and the capability of the wide +sample rates support through ASRC. + +Note: The card is initially designed for those sound cards who use I2S and + PCM DAI formats. However, it'll be also possible to support those non + I2S/PCM type sound cards, such as S/PDIF audio and HDMI audio, as long + as the driver has been properly upgraded. + + +The compatible list for this generic sound card currently: + "fsl,imx-audio-cs42888" + + "fsl,imx-audio-wm8962" + (compatible with Documentation/devicetree/bindings/sound/imx-audio-wm8962.txt) + + "fsl,imx-audio-sgtl5000" + (compatible with Documentation/devicetree/bindings/sound/imx-audio-sgtl5000.txt) + +Required properties: + + - compatible : Contains one of entries in the compatible list. + + - model : The user-visible name of this sound complex + + - audio-cpu : The phandle of an CPU DAI controller + + - audio-codec : The phandle of an audio codec + + - audio-routing : A list of the connections between audio components. + Each entry is a pair of strings, the first being the + connection's sink, the second being the connection's + source. There're a few pre-designed board connectors: + * Line Out Jack + * Line In Jack + * Headphone Jack + * Mic Jack + * Ext Spk + * AMIC (stands for Analog Microphone Jack) + * DMIC (stands for Digital Microphone Jack) + + Note: The "Mic Jack" and "AMIC" are redundant while + coexsiting in order to support the old bindings + of wm8962 and sgtl5000. + +Optional properties: + + - audio-asrc : The phandle of ASRC. It can be absent if there's no + need to add ASRC support via DPCM. + +Example: +sound-cs42888 { + compatible = "fsl,imx-audio-cs42888"; + model = "cs42888-audio"; + audio-cpu = <&esai>; + audio-asrc = <&asrc>; + audio-codec = <&cs42888>; + audio-routing = + "Line Out Jack", "AOUT1L", + "Line Out Jack", "AOUT1R", + "Line Out Jack", "AOUT2L", + "Line Out Jack", "AOUT2R", + "Line Out Jack", "AOUT3L", + "Line Out Jack", "AOUT3R", + "Line Out Jack", "AOUT4L", + "Line Out Jack", "AOUT4R", + "AIN1L", "Line In Jack", + "AIN1R", "Line In Jack", + "AIN2L", "Line In Jack", + "AIN2R", "Line In Jack"; +}; diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index f54a8fc99291..2b99a9e86899 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -59,6 +59,22 @@ config SND_SOC_FSL_ESAI config SND_SOC_FSL_UTILS tristate +config SND_SOC_FSL_ASOC_CARD + tristate "Generic ASoC Sound Card with ASRC support" + depends on OF && I2C + select SND_SOC_IMX_PCM_DMA + select SND_SOC_FSL_ESAI + select SND_SOC_FSL_SAI + select SND_SOC_FSL_SSI + select SND_SOC_CS42XX8_I2C + select SND_SOC_SGTL5000 + select SND_SOC_WM8962 + help + ALSA SoC Audio support with ASRC feature for Freescale SoCs that have + ESAI/SAI/SSI and connect with external CODECs such as WM8962, CS42888 + and SGTL5000. + Say Y if you want to add support for Freescale Generic ASoC Sound Card. + config SND_SOC_IMX_PCM_DMA tristate select SND_SOC_GENERIC_DMAENGINE_PCM diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index 9ff59267eac9..8f6d84efa973 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile @@ -11,6 +11,7 @@ snd-soc-p1022-rdk-objs := p1022_rdk.o obj-$(CONFIG_SND_SOC_P1022_RDK) += snd-soc-p1022-rdk.o # Freescale SSI/DMA/SAI/SPDIF Support +snd-soc-fsl-asoc-card-objs := fsl-asoc-card.o snd-soc-fsl-asrc-objs := fsl_asrc.o fsl_asrc_dma.o snd-soc-fsl-sai-objs := fsl_sai.o snd-soc-fsl-ssi-y := fsl_ssi.o @@ -19,6 +20,7 @@ snd-soc-fsl-spdif-objs := fsl_spdif.o snd-soc-fsl-esai-objs := fsl_esai.o snd-soc-fsl-utils-objs := fsl_utils.o snd-soc-fsl-dma-objs := fsl_dma.o +obj-$(CONFIG_SND_SOC_FSL_ASOC_CARD) += snd-soc-fsl-asoc-card.o obj-$(CONFIG_SND_SOC_FSL_ASRC) += snd-soc-fsl-asrc.o obj-$(CONFIG_SND_SOC_FSL_SAI) += snd-soc-fsl-sai.o obj-$(CONFIG_SND_SOC_FSL_SSI) += snd-soc-fsl-ssi.o diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c new file mode 100644 index 000000000000..cf3f1f47f1e8 --- /dev/null +++ b/sound/soc/fsl/fsl-asoc-card.c @@ -0,0 +1,573 @@ +/* + * Freescale Generic ASoC Sound Card driver with ASRC + * + * Copyright (C) 2014 Freescale Semiconductor, Inc. + * + * Author: Nicolin Chen + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include + +#include "fsl_esai.h" +#include "fsl_sai.h" +#include "imx-audmux.h" + +#include "../codecs/sgtl5000.h" +#include "../codecs/wm8962.h" + +#define RX 0 +#define TX 1 + +/* Default DAI format without Master and Slave flag */ +#define DAI_FMT_BASE (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF) + +/** + * CODEC private data + * + * @mclk_freq: Clock rate of MCLK + * @mclk_id: MCLK (or main clock) id for set_sysclk() + * @fll_id: FLL (or secordary clock) id for set_sysclk() + * @pll_id: PLL id for set_pll() + */ +struct codec_priv { + unsigned long mclk_freq; + u32 mclk_id; + u32 fll_id; + u32 pll_id; +}; + +/** + * CPU private data + * + * @sysclk_freq[2]: SYSCLK rates for set_sysclk() + * @sysclk_dir[2]: SYSCLK directions for set_sysclk() + * @sysclk_id[2]: SYSCLK ids for set_sysclk() + * + * Note: [1] for tx and [0] for rx + */ +struct cpu_priv { + unsigned long sysclk_freq[2]; + u32 sysclk_dir[2]; + u32 sysclk_id[2]; +}; + +/** + * Freescale Generic ASOC card private data + * + * @dai_link[3]: DAI link structure including normal one and DPCM link + * @pdev: platform device pointer + * @codec_priv: CODEC private data + * @cpu_priv: CPU private data + * @card: ASoC card structure + * @sample_rate: Current sample rate + * @sample_format: Current sample format + * @asrc_rate: ASRC sample rate used by Back-Ends + * @asrc_format: ASRC sample format used by Back-Ends + * @dai_fmt: DAI format between CPU and CODEC + * @name: Card name + */ + +struct fsl_asoc_card_priv { + struct snd_soc_dai_link dai_link[3]; + struct platform_device *pdev; + struct codec_priv codec_priv; + struct cpu_priv cpu_priv; + struct snd_soc_card card; + u32 sample_rate; + u32 sample_format; + u32 asrc_rate; + u32 asrc_format; + u32 dai_fmt; + char name[32]; +}; + +/** + * This dapm route map exsits for DPCM link only. + * The other routes shall go through Device Tree. + */ +static const struct snd_soc_dapm_route audio_map[] = { + {"CPU-Playback", NULL, "ASRC-Playback"}, + {"Playback", NULL, "CPU-Playback"}, + {"ASRC-Capture", NULL, "CPU-Capture"}, + {"CPU-Capture", NULL, "Capture"}, +}; + +/* Add all possible widgets into here without being redundant */ +static const struct snd_soc_dapm_widget fsl_asoc_card_dapm_widgets[] = { + SND_SOC_DAPM_LINE("Line Out Jack", NULL), + SND_SOC_DAPM_LINE("Line In Jack", NULL), + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_SPK("Ext Spk", NULL), + SND_SOC_DAPM_MIC("Mic Jack", NULL), + SND_SOC_DAPM_MIC("AMIC", NULL), + SND_SOC_DAPM_MIC("DMIC", NULL), +}; + +static int fsl_asoc_card_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); + bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; + struct cpu_priv *cpu_priv = &priv->cpu_priv; + struct device *dev = rtd->card->dev; + int ret; + + priv->sample_rate = params_rate(params); + priv->sample_format = params_format(params); + + if (priv->card.set_bias_level) + return 0; + + /* Specific configurations of DAIs starts from here */ + ret = snd_soc_dai_set_sysclk(rtd->cpu_dai, cpu_priv->sysclk_id[tx], + cpu_priv->sysclk_freq[tx], + cpu_priv->sysclk_dir[tx]); + if (ret) { + dev_err(dev, "failed to set sysclk for cpu dai\n"); + return ret; + } + + return 0; +} + +static struct snd_soc_ops fsl_asoc_card_ops = { + .hw_params = fsl_asoc_card_hw_params, +}; + +static int be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); + struct snd_interval *rate; + struct snd_mask *mask; + + rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); + rate->max = rate->min = priv->asrc_rate; + + mask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + snd_mask_none(mask); + snd_mask_set(mask, priv->asrc_format); + + return 0; +} + +static struct snd_soc_dai_link fsl_asoc_card_dai[] = { + /* Default ASoC DAI Link*/ + { + .name = "HiFi", + .stream_name = "HiFi", + .ops = &fsl_asoc_card_ops, + }, + /* DPCM Link between Front-End and Back-End (Optional) */ + { + .name = "HiFi-ASRC-FE", + .stream_name = "HiFi-ASRC-FE", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .dpcm_playback = 1, + .dpcm_capture = 1, + .dynamic = 1, + }, + { + .name = "HiFi-ASRC-BE", + .stream_name = "HiFi-ASRC-BE", + .platform_name = "snd-soc-dummy", + .be_hw_params_fixup = be_hw_params_fixup, + .ops = &fsl_asoc_card_ops, + .dpcm_playback = 1, + .dpcm_capture = 1, + .no_pcm = 1, + }, +}; + +static int fsl_asoc_card_set_bias_level(struct snd_soc_card *card, + struct snd_soc_dapm_context *dapm, + enum snd_soc_bias_level level) +{ + struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(card); + struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; + struct codec_priv *codec_priv = &priv->codec_priv; + struct device *dev = card->dev; + unsigned int pll_out; + int ret; + + if (dapm->dev != codec_dai->dev) + return 0; + + switch (level) { + case SND_SOC_BIAS_PREPARE: + if (dapm->bias_level != SND_SOC_BIAS_STANDBY) + break; + + if (priv->sample_format == SNDRV_PCM_FORMAT_S24_LE) + pll_out = priv->sample_rate * 384; + else + pll_out = priv->sample_rate * 256; + + ret = snd_soc_dai_set_pll(codec_dai, codec_priv->pll_id, + codec_priv->mclk_id, + codec_priv->mclk_freq, pll_out); + if (ret) { + dev_err(dev, "failed to start FLL: %d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_sysclk(codec_dai, codec_priv->fll_id, + pll_out, SND_SOC_CLOCK_IN); + if (ret) { + dev_err(dev, "failed to set SYSCLK: %d\n", ret); + return ret; + } + break; + + case SND_SOC_BIAS_STANDBY: + if (dapm->bias_level != SND_SOC_BIAS_PREPARE) + break; + + ret = snd_soc_dai_set_sysclk(codec_dai, codec_priv->mclk_id, + codec_priv->mclk_freq, + SND_SOC_CLOCK_IN); + if (ret) { + dev_err(dev, "failed to switch away from FLL: %d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_pll(codec_dai, codec_priv->pll_id, 0, 0, 0); + if (ret) { + dev_err(dev, "failed to stop FLL: %d\n", ret); + return ret; + } + break; + + default: + break; + } + + return 0; +} + +static int fsl_asoc_card_audmux_init(struct device_node *np, + struct fsl_asoc_card_priv *priv) +{ + struct device *dev = &priv->pdev->dev; + u32 int_ptcr = 0, ext_ptcr = 0; + int int_port, ext_port; + int ret; + + ret = of_property_read_u32(np, "mux-int-port", &int_port); + if (ret) { + dev_err(dev, "mux-int-port missing or invalid\n"); + return ret; + } + ret = of_property_read_u32(np, "mux-ext-port", &ext_port); + if (ret) { + dev_err(dev, "mux-ext-port missing or invalid\n"); + return ret; + } + + /* + * The port numbering in the hardware manual starts at 1, while + * the AUDMUX API expects it starts at 0. + */ + int_port--; + ext_port--; + + /* + * Use asynchronous mode (6 wires) for all cases. + * If only 4 wires are needed, just set SSI into + * synchronous mode and enable 4 PADs in IOMUX. + */ + switch (priv->dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + int_ptcr = IMX_AUDMUX_V2_PTCR_RFSEL(8 | ext_port) | + IMX_AUDMUX_V2_PTCR_RCSEL(8 | ext_port) | + IMX_AUDMUX_V2_PTCR_TFSEL(ext_port) | + IMX_AUDMUX_V2_PTCR_TCSEL(ext_port) | + IMX_AUDMUX_V2_PTCR_RFSDIR | + IMX_AUDMUX_V2_PTCR_RCLKDIR | + IMX_AUDMUX_V2_PTCR_TFSDIR | + IMX_AUDMUX_V2_PTCR_TCLKDIR; + break; + case SND_SOC_DAIFMT_CBM_CFS: + int_ptcr = IMX_AUDMUX_V2_PTCR_RCSEL(8 | ext_port) | + IMX_AUDMUX_V2_PTCR_TCSEL(ext_port) | + IMX_AUDMUX_V2_PTCR_RCLKDIR | + IMX_AUDMUX_V2_PTCR_TCLKDIR; + ext_ptcr = IMX_AUDMUX_V2_PTCR_RFSEL(8 | int_port) | + IMX_AUDMUX_V2_PTCR_TFSEL(int_port) | + IMX_AUDMUX_V2_PTCR_RFSDIR | + IMX_AUDMUX_V2_PTCR_TFSDIR; + break; + case SND_SOC_DAIFMT_CBS_CFM: + int_ptcr = IMX_AUDMUX_V2_PTCR_RFSEL(8 | ext_port) | + IMX_AUDMUX_V2_PTCR_TFSEL(ext_port) | + IMX_AUDMUX_V2_PTCR_RFSDIR | + IMX_AUDMUX_V2_PTCR_TFSDIR; + ext_ptcr = IMX_AUDMUX_V2_PTCR_RCSEL(8 | int_port) | + IMX_AUDMUX_V2_PTCR_TCSEL(int_port) | + IMX_AUDMUX_V2_PTCR_RCLKDIR | + IMX_AUDMUX_V2_PTCR_TCLKDIR; + break; + case SND_SOC_DAIFMT_CBS_CFS: + ext_ptcr = IMX_AUDMUX_V2_PTCR_RFSEL(8 | int_port) | + IMX_AUDMUX_V2_PTCR_RCSEL(8 | int_port) | + IMX_AUDMUX_V2_PTCR_TFSEL(int_port) | + IMX_AUDMUX_V2_PTCR_TCSEL(int_port) | + IMX_AUDMUX_V2_PTCR_RFSDIR | + IMX_AUDMUX_V2_PTCR_RCLKDIR | + IMX_AUDMUX_V2_PTCR_TFSDIR | + IMX_AUDMUX_V2_PTCR_TCLKDIR; + break; + default: + return -EINVAL; + } + + /* Asynchronous mode can not be set along with RCLKDIR */ + ret = imx_audmux_v2_configure_port(int_port, 0, + IMX_AUDMUX_V2_PDCR_RXDSEL(ext_port)); + if (ret) { + dev_err(dev, "audmux internal port setup failed\n"); + return ret; + } + + ret = imx_audmux_v2_configure_port(int_port, int_ptcr, + IMX_AUDMUX_V2_PDCR_RXDSEL(ext_port)); + if (ret) { + dev_err(dev, "audmux internal port setup failed\n"); + return ret; + } + + ret = imx_audmux_v2_configure_port(ext_port, 0, + IMX_AUDMUX_V2_PDCR_RXDSEL(int_port)); + if (ret) { + dev_err(dev, "audmux external port setup failed\n"); + return ret; + } + + ret = imx_audmux_v2_configure_port(ext_port, ext_ptcr, + IMX_AUDMUX_V2_PDCR_RXDSEL(int_port)); + if (ret) { + dev_err(dev, "audmux external port setup failed\n"); + return ret; + } + + return 0; +} + +static int fsl_asoc_card_late_probe(struct snd_soc_card *card) +{ + struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(card); + struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; + struct codec_priv *codec_priv = &priv->codec_priv; + struct device *dev = card->dev; + int ret; + + ret = snd_soc_dai_set_sysclk(codec_dai, codec_priv->mclk_id, + codec_priv->mclk_freq, SND_SOC_CLOCK_IN); + if (ret) { + dev_err(dev, "failed to set sysclk in %s\n", __func__); + return ret; + } + + return 0; +} + +static int fsl_asoc_card_probe(struct platform_device *pdev) +{ + struct device_node *cpu_np, *codec_np, *asrc_np; + struct device_node *np = pdev->dev.of_node; + struct platform_device *asrc_pdev = NULL; + struct platform_device *cpu_pdev; + struct fsl_asoc_card_priv *priv; + struct i2c_client *codec_dev; + struct clk *codec_clk; + u32 width; + int ret; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + cpu_np = of_parse_phandle(np, "audio-cpu", 0); + /* Give a chance to old DT binding */ + if (!cpu_np) + cpu_np = of_parse_phandle(np, "ssi-controller", 0); + codec_np = of_parse_phandle(np, "audio-codec", 0); + if (!cpu_np || !codec_np) { + dev_err(&pdev->dev, "phandle missing or invalid\n"); + ret = -EINVAL; + goto fail; + } + + cpu_pdev = of_find_device_by_node(cpu_np); + if (!cpu_pdev) { + dev_err(&pdev->dev, "failed to find CPU DAI device\n"); + ret = -EINVAL; + goto fail; + } + + codec_dev = of_find_i2c_device_by_node(codec_np); + if (!codec_dev) { + dev_err(&pdev->dev, "failed to find codec platform device\n"); + ret = -EINVAL; + goto fail; + } + + asrc_np = of_parse_phandle(np, "audio-asrc", 0); + if (asrc_np) + asrc_pdev = of_find_device_by_node(asrc_np); + + /* Get the MCLK rate only, and leave it controlled by CODEC drivers */ + codec_clk = clk_get(&codec_dev->dev, NULL); + if (!IS_ERR(codec_clk)) { + priv->codec_priv.mclk_freq = clk_get_rate(codec_clk); + clk_put(codec_clk); + } + + /* Default sample rate and format, will be updated in hw_params() */ + priv->sample_rate = 44100; + priv->sample_format = SNDRV_PCM_FORMAT_S16_LE; + + /* Assign a default DAI format, and allow each card to overwrite it */ + priv->dai_fmt = DAI_FMT_BASE; + + /* Diversify the card configurations */ + if (of_device_is_compatible(np, "fsl,imx-audio-cs42888")) { + priv->card.set_bias_level = NULL; + priv->cpu_priv.sysclk_freq[TX] = priv->codec_priv.mclk_freq; + priv->cpu_priv.sysclk_freq[RX] = priv->codec_priv.mclk_freq; + priv->cpu_priv.sysclk_dir[TX] = SND_SOC_CLOCK_OUT; + priv->cpu_priv.sysclk_dir[RX] = SND_SOC_CLOCK_OUT; + priv->dai_fmt |= SND_SOC_DAIFMT_CBS_CFS; + } else if (of_device_is_compatible(np, "fsl,imx-audio-sgtl5000")) { + priv->codec_priv.mclk_id = SGTL5000_SYSCLK; + priv->dai_fmt |= SND_SOC_DAIFMT_CBM_CFM; + } else if (of_device_is_compatible(np, "fsl,imx-audio-wm8962")) { + priv->card.set_bias_level = fsl_asoc_card_set_bias_level; + priv->codec_priv.mclk_id = WM8962_SYSCLK_MCLK; + priv->codec_priv.fll_id = WM8962_SYSCLK_FLL; + priv->codec_priv.pll_id = WM8962_FLL; + priv->dai_fmt |= SND_SOC_DAIFMT_CBM_CFM; + } else { + dev_err(&pdev->dev, "unknown Device Tree compatible\n"); + return -EINVAL; + } + + /* Common settings for corresponding Freescale CPU DAI driver */ + if (strstr(cpu_np->name, "ssi")) { + /* Only SSI needs to configure AUDMUX */ + ret = fsl_asoc_card_audmux_init(np, priv); + if (ret) { + dev_err(&pdev->dev, "failed to init audmux\n"); + goto fail; + } + } else if (strstr(cpu_np->name, "esai")) { + priv->cpu_priv.sysclk_id[1] = ESAI_HCKT_EXTAL; + priv->cpu_priv.sysclk_id[0] = ESAI_HCKR_EXTAL; + } else if (strstr(cpu_np->name, "sai")) { + priv->cpu_priv.sysclk_id[1] = FSL_SAI_CLK_MAST1; + priv->cpu_priv.sysclk_id[0] = FSL_SAI_CLK_MAST1; + } + + sprintf(priv->name, "%s-audio", codec_dev->name); + + /* Initialize sound card */ + priv->pdev = pdev; + priv->card.dev = &pdev->dev; + priv->card.name = priv->name; + priv->card.dai_link = priv->dai_link; + priv->card.dapm_routes = audio_map; + priv->card.late_probe = fsl_asoc_card_late_probe; + priv->card.num_dapm_routes = ARRAY_SIZE(audio_map); + priv->card.dapm_widgets = fsl_asoc_card_dapm_widgets; + priv->card.num_dapm_widgets = ARRAY_SIZE(fsl_asoc_card_dapm_widgets); + + memcpy(priv->dai_link, fsl_asoc_card_dai, + sizeof(struct snd_soc_dai_link) * ARRAY_SIZE(priv->dai_link)); + + /* Normal DAI Link */ + priv->dai_link[0].cpu_of_node = cpu_np; + priv->dai_link[0].codec_of_node = codec_np; + priv->dai_link[0].codec_dai_name = codec_dev->name; + priv->dai_link[0].platform_of_node = cpu_np; + priv->dai_link[0].dai_fmt = priv->dai_fmt; + priv->card.num_links = 1; + + if (asrc_pdev) { + /* DPCM DAI Links only if ASRC exsits */ + priv->dai_link[1].cpu_of_node = asrc_np; + priv->dai_link[1].platform_of_node = asrc_np; + priv->dai_link[2].codec_dai_name = codec_dev->name; + priv->dai_link[2].codec_of_node = codec_np; + priv->dai_link[2].cpu_of_node = cpu_np; + priv->dai_link[2].dai_fmt = priv->dai_fmt; + priv->card.num_links = 3; + + ret = of_property_read_u32(asrc_np, "fsl,asrc-rate", + &priv->asrc_rate); + if (ret) { + dev_err(&pdev->dev, "failed to get output rate\n"); + ret = -EINVAL; + goto fail; + } + + ret = of_property_read_u32(asrc_np, "fsl,asrc-width", &width); + if (ret) { + dev_err(&pdev->dev, "failed to get output rate\n"); + ret = -EINVAL; + goto fail; + } + + if (width == 24) + priv->asrc_format = SNDRV_PCM_FORMAT_S24_LE; + else + priv->asrc_format = SNDRV_PCM_FORMAT_S16_LE; + } + + /* Finish card registering */ + platform_set_drvdata(pdev, priv); + snd_soc_card_set_drvdata(&priv->card, priv); + + ret = devm_snd_soc_register_card(&pdev->dev, &priv->card); + if (ret) + dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); + +fail: + of_node_put(codec_np); + of_node_put(asrc_np); + of_node_put(cpu_np); + + return ret; +} + +static const struct of_device_id fsl_asoc_card_dt_ids[] = { + { .compatible = "fsl,imx-audio-cs42888", }, + { .compatible = "fsl,imx-audio-sgtl5000", }, + { .compatible = "fsl,imx-audio-wm8962", }, + {} +}; + +static struct platform_driver fsl_asoc_card_driver = { + .probe = fsl_asoc_card_probe, + .driver = { + .name = "fsl-asoc-card", + .pm = &snd_soc_pm_ops, + .of_match_table = fsl_asoc_card_dt_ids, + }, +}; +module_platform_driver(fsl_asoc_card_driver); + +MODULE_DESCRIPTION("Freescale Generic ASoC Sound Card driver with ASRC"); +MODULE_AUTHOR("Nicolin Chen "); +MODULE_ALIAS("platform:fsl-asoc-card"); +MODULE_LICENSE("GPL"); From de0d712a6dd1eed097dc6aa4f97ee461949414fe Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Fri, 8 Aug 2014 14:47:21 +0800 Subject: [PATCH 008/251] ASoC: fsl_esai: refine esai for TDM support Original driver didn't store the number of slots, just fix the slot number to 2, use this default number to calculate bclk and pins for TX/RX. In this patch, add one parameter for slots, and update the calculation of bclk and pins of TX/RX. Then driver will be compatible with slots > 2 in TDM mode. Signed-off-by: Shengjiu Wang Acked-by: Nicolin Chen Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_esai.c | 14 +++++++++++--- sound/soc/fsl/fsl_esai.h | 8 ++++---- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index 72d154e7dd03..f252370073e5 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c @@ -38,6 +38,7 @@ * @fsysclk: system clock source to derive HCK, SCK and FS * @fifo_depth: depth of tx/rx FIFO * @slot_width: width of each DAI slot + * @slots: number of slots * @hck_rate: clock rate of desired HCKx clock * @sck_rate: clock rate of desired SCKx clock * @hck_dir: the direction of HCKx pads @@ -56,6 +57,7 @@ struct fsl_esai { struct clk *fsysclk; u32 fifo_depth; u32 slot_width; + u32 slots; u32 hck_rate[2]; u32 sck_rate[2]; bool hck_dir[2]; @@ -363,6 +365,7 @@ static int fsl_esai_set_dai_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, ESAI_xSMB_xS_MASK, ESAI_xSMB_xS(rx_mask)); esai_priv->slot_width = slot_width; + esai_priv->slots = slots; return 0; } @@ -510,10 +513,11 @@ static int fsl_esai_hw_params(struct snd_pcm_substream *substream, bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; u32 width = snd_pcm_format_width(params_format(params)); u32 channels = params_channels(params); + u32 pins = DIV_ROUND_UP(channels, esai_priv->slots); u32 bclk, mask, val; int ret; - bclk = params_rate(params) * esai_priv->slot_width * 2; + bclk = params_rate(params) * esai_priv->slot_width * esai_priv->slots; ret = fsl_esai_set_bclk(dai, tx, bclk); if (ret) @@ -530,7 +534,7 @@ static int fsl_esai_hw_params(struct snd_pcm_substream *substream, mask = ESAI_xFCR_xFR_MASK | ESAI_xFCR_xWA_MASK | ESAI_xFCR_xFWM_MASK | (tx ? ESAI_xFCR_TE_MASK | ESAI_xFCR_TIEN : ESAI_xFCR_RE_MASK); val = ESAI_xFCR_xWA(width) | ESAI_xFCR_xFWM(esai_priv->fifo_depth) | - (tx ? ESAI_xFCR_TE(channels) | ESAI_xFCR_TIEN : ESAI_xFCR_RE(channels)); + (tx ? ESAI_xFCR_TE(pins) | ESAI_xFCR_TIEN : ESAI_xFCR_RE(pins)); regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx), mask, val); @@ -565,6 +569,7 @@ static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd, struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai); bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; u8 i, channels = substream->runtime->channels; + u32 pins = DIV_ROUND_UP(channels, esai_priv->slots); switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -579,7 +584,7 @@ static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd, regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), tx ? ESAI_xCR_TE_MASK : ESAI_xCR_RE_MASK, - tx ? ESAI_xCR_TE(channels) : ESAI_xCR_RE(channels)); + tx ? ESAI_xCR_TE(pins) : ESAI_xCR_RE(pins)); break; case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_STOP: @@ -783,6 +788,9 @@ static int fsl_esai_probe(struct platform_device *pdev) /* Set a default slot size */ esai_priv->slot_width = 32; + /* Set a default slot number */ + esai_priv->slots = 2; + /* Set a default master/slave state */ esai_priv->slave_mode = true; diff --git a/sound/soc/fsl/fsl_esai.h b/sound/soc/fsl/fsl_esai.h index 75e14033e8d8..91a550f4a10d 100644 --- a/sound/soc/fsl/fsl_esai.h +++ b/sound/soc/fsl/fsl_esai.h @@ -130,8 +130,8 @@ #define ESAI_xFCR_RE_WIDTH 4 #define ESAI_xFCR_TE_MASK (((1 << ESAI_xFCR_TE_WIDTH) - 1) << ESAI_xFCR_xE_SHIFT) #define ESAI_xFCR_RE_MASK (((1 << ESAI_xFCR_RE_WIDTH) - 1) << ESAI_xFCR_xE_SHIFT) -#define ESAI_xFCR_TE(x) ((ESAI_xFCR_TE_MASK >> (ESAI_xFCR_TE_WIDTH - ((x + 1) >> 1))) & ESAI_xFCR_TE_MASK) -#define ESAI_xFCR_RE(x) ((ESAI_xFCR_RE_MASK >> (ESAI_xFCR_RE_WIDTH - ((x + 1) >> 1))) & ESAI_xFCR_RE_MASK) +#define ESAI_xFCR_TE(x) ((ESAI_xFCR_TE_MASK >> (ESAI_xFCR_TE_WIDTH - x)) & ESAI_xFCR_TE_MASK) +#define ESAI_xFCR_RE(x) ((ESAI_xFCR_RE_MASK >> (ESAI_xFCR_RE_WIDTH - x)) & ESAI_xFCR_RE_MASK) #define ESAI_xFCR_xFR_SHIFT 1 #define ESAI_xFCR_xFR_MASK (1 << ESAI_xFCR_xFR_SHIFT) #define ESAI_xFCR_xFR (1 << ESAI_xFCR_xFR_SHIFT) @@ -272,8 +272,8 @@ #define ESAI_xCR_RE_WIDTH 4 #define ESAI_xCR_TE_MASK (((1 << ESAI_xCR_TE_WIDTH) - 1) << ESAI_xCR_xE_SHIFT) #define ESAI_xCR_RE_MASK (((1 << ESAI_xCR_RE_WIDTH) - 1) << ESAI_xCR_xE_SHIFT) -#define ESAI_xCR_TE(x) ((ESAI_xCR_TE_MASK >> (ESAI_xCR_TE_WIDTH - ((x + 1) >> 1))) & ESAI_xCR_TE_MASK) -#define ESAI_xCR_RE(x) ((ESAI_xCR_RE_MASK >> (ESAI_xCR_RE_WIDTH - ((x + 1) >> 1))) & ESAI_xCR_RE_MASK) +#define ESAI_xCR_TE(x) ((ESAI_xCR_TE_MASK >> (ESAI_xCR_TE_WIDTH - x)) & ESAI_xCR_TE_MASK) +#define ESAI_xCR_RE(x) ((ESAI_xCR_RE_MASK >> (ESAI_xCR_RE_WIDTH - x)) & ESAI_xCR_RE_MASK) /* * Transmit Clock Control Register -- REG_ESAI_TCCR 0xD8 From 376d1a92ca587d3974d4791cdb99baa8b8e7f0dd Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Tue, 5 Aug 2014 17:20:21 +0800 Subject: [PATCH 009/251] ASoC: fsl_sai: Initialize with software reset This patch adds software reset code in dai_probe() so as to make a true init by clearing SAI's internal logic, including the bit clock generation, status flags, and FIFO pointers. Signed-off-by: Nicolin Chen Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_sai.c | 9 +++++++-- sound/soc/fsl/fsl_sai.h | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index faa049797897..7b1eecbc4f60 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -437,8 +437,13 @@ static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai) { struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev); - regmap_update_bits(sai->regmap, FSL_SAI_TCSR, 0xffffffff, 0x0); - regmap_update_bits(sai->regmap, FSL_SAI_RCSR, 0xffffffff, 0x0); + /* Software Reset for both Tx and Rx */ + regmap_write(sai->regmap, FSL_SAI_TCSR, FSL_SAI_CSR_SR); + regmap_write(sai->regmap, FSL_SAI_RCSR, FSL_SAI_CSR_SR); + /* Clear SR bit to finish the reset */ + regmap_write(sai->regmap, FSL_SAI_TCSR, 0); + regmap_write(sai->regmap, FSL_SAI_RCSR, 0); + regmap_update_bits(sai->regmap, FSL_SAI_TCR1, FSL_SAI_CR1_RFW_MASK, FSL_SAI_MAXBURST_TX * 2); regmap_update_bits(sai->regmap, FSL_SAI_RCR1, FSL_SAI_CR1_RFW_MASK, diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h index 0e6c9f595d75..8e1feab7c2a0 100644 --- a/sound/soc/fsl/fsl_sai.h +++ b/sound/soc/fsl/fsl_sai.h @@ -48,6 +48,7 @@ /* SAI Transmit/Recieve Control Register */ #define FSL_SAI_CSR_TERE BIT(31) #define FSL_SAI_CSR_FR BIT(25) +#define FSL_SAI_CSR_SR BIT(24) #define FSL_SAI_CSR_xF_SHIFT 16 #define FSL_SAI_CSR_xF_W_SHIFT 18 #define FSL_SAI_CSR_xF_MASK (0x1f << FSL_SAI_CSR_xF_SHIFT) From af96ff5b7448dc776dc24a5c4313c6ec1ee94e53 Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Mon, 4 Aug 2014 15:07:25 +0800 Subject: [PATCH 010/251] ASoC: fsl_sai: Set SYNC bit of TCR2 to Asynchronous Mode There is one design rule according to SAI's reference manual: If the transmitter bit clock and frame sync are to be used by both transmitter and receiver, the transmitter must be configured for asynchronous operation and the receiver for synchronous operation. And SYNC of TCR2 is a 2-width control bit: 00 Asynchronous mode. 01 Synchronous with receiver. 10 Synchronous with another SAI transmitter. 11 Synchronous with another SAI receiver. So the driver should have set SYNC bit of TCR2 to 0x0, and meanwhile set SYNC bit of RCR2 to 0x1 (Synchronous with transmitter). Signed-off-by: Nicolin Chen Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_sai.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index 7b1eecbc4f60..3d865ad466ad 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -333,8 +333,7 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd, * The transmitter bit clock and frame sync are to be * used by both the transmitter and receiver. */ - regmap_update_bits(sai->regmap, FSL_SAI_TCR2, FSL_SAI_CR2_SYNC, - ~FSL_SAI_CR2_SYNC); + regmap_update_bits(sai->regmap, FSL_SAI_TCR2, FSL_SAI_CR2_SYNC, 0); regmap_update_bits(sai->regmap, FSL_SAI_RCR2, FSL_SAI_CR2_SYNC, FSL_SAI_CR2_SYNC); From 08fdf65e37d560581233e06a659f73deeb3766f9 Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Tue, 5 Aug 2014 15:32:05 +0800 Subject: [PATCH 011/251] ASoC: fsl_sai: Add asynchronous mode support SAI supports these operation modes: 1) asynchronous mode Both Tx and Rx are set to be asynchronous. 2) synchronous mode (Rx sync with Tx) Tx is set to be asynchronous, Rx is set to be synchronous. 3) synchronous mode (Tx sync with Rx) Rx is set to be asynchronous, Tx is set to be synchronous. 4) synchronous mode (Tx/Rx sync with another SAI's Tx) 5) synchronous mode (Tx/Rx sync with another SAI's Rx) * 4) and 5) are beyond this patch because they are related with another SAI. As the initial version of this SAI driver, it supported 2) as default while the others were totally missing. So this patch just adds supports for 1) and 3). Signed-off-by: Nicolin Chen Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/fsl-sai.txt | 16 ++++++++++ sound/soc/fsl/fsl_sai.c | 30 ++++++++++++++++--- sound/soc/fsl/fsl_sai.h | 4 +++ 3 files changed, 46 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/fsl-sai.txt b/Documentation/devicetree/bindings/sound/fsl-sai.txt index 0f4e23828190..77864f4dd352 100644 --- a/Documentation/devicetree/bindings/sound/fsl-sai.txt +++ b/Documentation/devicetree/bindings/sound/fsl-sai.txt @@ -24,6 +24,22 @@ Required properties: - big-endian-data: If this property is absent, the little endian mode will be in use as default, or the big endian mode will be in use for all the fifo data. +- fsl,sai-synchronous-rx: This is a boolean property. If present, indicating + that SAI will work in the synchronous mode (sync Tx with Rx) which means + both the transimitter and receiver will send and receive data by following + receiver's bit clocks and frame sync clocks. +- fsl,sai-asynchronous: This is a boolean property. If present, indicating + that SAI will work in the asynchronous mode, which means both transimitter + and receiver will send and receive data by following their own bit clocks + and frame sync clocks separately. + +Note: +- If both fsl,sai-asynchronous and fsl,sai-synchronous-rx are absent, the + default synchronous mode (sync Rx with Tx) will be used, which means both + transimitter and receiver will send and receive data by following clocks + of transimitter. +- fsl,sai-asynchronous will be ignored if fsl,sai-synchronous-rx property is + already present. Example: sai2: sai@40031000 { diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index 3d865ad466ad..ef7c758627b1 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -330,12 +330,14 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd, u32 xcsr, count = 100; /* - * The transmitter bit clock and frame sync are to be - * used by both the transmitter and receiver. + * Asynchronous mode: Clear SYNC for both Tx and Rx. + * Rx sync with Tx clocks: Clear SYNC for Tx, set it for Rx. + * Tx sync with Rx clocks: Clear SYNC for Rx, set it for Tx. */ - regmap_update_bits(sai->regmap, FSL_SAI_TCR2, FSL_SAI_CR2_SYNC, 0); + regmap_update_bits(sai->regmap, FSL_SAI_TCR2, FSL_SAI_CR2_SYNC, + sai->synchronous[TX] ? FSL_SAI_CR2_SYNC : 0); regmap_update_bits(sai->regmap, FSL_SAI_RCR2, FSL_SAI_CR2_SYNC, - FSL_SAI_CR2_SYNC); + sai->synchronous[RX] ? FSL_SAI_CR2_SYNC : 0); /* * It is recommended that the transmitter is the last enabled @@ -625,6 +627,26 @@ static int fsl_sai_probe(struct platform_device *pdev) return ret; } + /* Sync Tx with Rx as default by following old DT binding */ + sai->synchronous[RX] = true; + sai->synchronous[TX] = false; + fsl_sai_dai.symmetric_rates = 1; + fsl_sai_dai.symmetric_channels = 1; + fsl_sai_dai.symmetric_samplebits = 1; + + if (of_find_property(np, "fsl,sai-synchronous-rx", NULL)) { + /* Sync Rx with Tx */ + sai->synchronous[RX] = false; + sai->synchronous[TX] = true; + } else if (of_find_property(np, "fsl,sai-asynchronous", NULL)) { + /* Discard all settings for asynchronous mode */ + sai->synchronous[RX] = false; + sai->synchronous[TX] = false; + fsl_sai_dai.symmetric_rates = 0; + fsl_sai_dai.symmetric_channels = 0; + fsl_sai_dai.symmetric_samplebits = 0; + } + sai->dma_params_rx.addr = res->start + FSL_SAI_RDR; sai->dma_params_tx.addr = res->start + FSL_SAI_TDR; sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX; diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h index 8e1feab7c2a0..b3d8864cd5f2 100644 --- a/sound/soc/fsl/fsl_sai.h +++ b/sound/soc/fsl/fsl_sai.h @@ -136,9 +136,13 @@ struct fsl_sai { bool big_endian_data; bool is_dsp_mode; bool sai_on_imx; + bool synchronous[2]; struct snd_dmaengine_dai_dma_data dma_params_rx; struct snd_dmaengine_dai_dma_data dma_params_tx; }; +#define TX 1 +#define RX 0 + #endif /* __FSL_SAI_H */ From ce7344a4ebabe90e064d3e087727f45624cdc942 Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Fri, 8 Aug 2014 18:41:19 +0800 Subject: [PATCH 012/251] ASoC: fsl_sai: Make Synchronous and Asynchronous modes exclusive The previous patch (ASoC: fsl_sai: Add asynchronous mode support) added new Device Tree bindings for Asynchronous and Synchronous modes support. However, these two shall not be present at the same time. So this patch just simply makes them exclusive so as to avoid incorrect Device Tree binding usage. Signed-off-by: Nicolin Chen Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/fsl-sai.txt | 3 +-- sound/soc/fsl/fsl_sai.c | 7 +++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/fsl-sai.txt b/Documentation/devicetree/bindings/sound/fsl-sai.txt index 77864f4dd352..dc9f9c356268 100644 --- a/Documentation/devicetree/bindings/sound/fsl-sai.txt +++ b/Documentation/devicetree/bindings/sound/fsl-sai.txt @@ -38,8 +38,7 @@ Note: default synchronous mode (sync Rx with Tx) will be used, which means both transimitter and receiver will send and receive data by following clocks of transimitter. -- fsl,sai-asynchronous will be ignored if fsl,sai-synchronous-rx property is - already present. +- fsl,sai-asynchronous and fsl,sai-synchronous-rx are exclusive. Example: sai2: sai@40031000 { diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index ef7c758627b1..4c9e71c2f52a 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -634,6 +634,13 @@ static int fsl_sai_probe(struct platform_device *pdev) fsl_sai_dai.symmetric_channels = 1; fsl_sai_dai.symmetric_samplebits = 1; + if (of_find_property(np, "fsl,sai-synchronous-rx", NULL) && + of_find_property(np, "fsl,sai-asynchronous", NULL)) { + /* error out if both synchronous and asynchronous are present */ + dev_err(&pdev->dev, "invalid binding for synchronous mode\n"); + return -EINVAL; + } + if (of_find_property(np, "fsl,sai-synchronous-rx", NULL)) { /* Sync Rx with Tx */ sai->synchronous[RX] = false; From ea5edfe2f1ce5b2254a5ec4c1bb224fac48c3153 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Mon, 4 Aug 2014 15:04:19 +0530 Subject: [PATCH 013/251] ASoC: Intel: Fix to use byte control interface Using a byte control interface instead of generic_params ioctl. Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/sst-mfld-platform.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sound/soc/intel/sst-mfld-platform.h b/sound/soc/intel/sst-mfld-platform.h index 6c6a42c08e24..cc3a088df7dd 100644 --- a/sound/soc/intel/sst-mfld-platform.h +++ b/sound/soc/intel/sst-mfld-platform.h @@ -63,9 +63,7 @@ enum sst_controls { SST_SND_BUFFER_POINTER = 0x05, SST_SND_STREAM_INIT = 0x06, SST_SND_START = 0x07, - SST_SET_BYTE_STREAM = 0x100A, - SST_GET_BYTE_STREAM = 0x100B, - SST_MAX_CONTROLS = SST_GET_BYTE_STREAM, + SST_MAX_CONTROLS = 0x07, }; enum sst_stream_ops { @@ -129,7 +127,7 @@ struct compress_sst_ops { struct sst_ops { int (*open) (struct snd_sst_params *str_param); int (*device_control) (int cmd, void *arg); - int (*set_generic_params)(enum sst_controls cmd, void *arg); + int (*send_byte_stream)(struct snd_sst_bytes_v2 *bytes); int (*close) (unsigned int str_id); }; From 5981c2d6db2ef16d96ee4d1c4d3ddff4ad9d8ebc Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Mon, 4 Aug 2014 15:04:20 +0530 Subject: [PATCH 014/251] ASoC: Intel: mfld-pcm: Use function instead of ioctl Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/sst-mfld-platform-pcm.c | 21 +++++++++------------ sound/soc/intel/sst-mfld-platform.h | 19 ++++++------------- 2 files changed, 15 insertions(+), 25 deletions(-) diff --git a/sound/soc/intel/sst-mfld-platform-pcm.c b/sound/soc/intel/sst-mfld-platform-pcm.c index 706212a6a68c..42766a51c17e 100644 --- a/sound/soc/intel/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/sst-mfld-platform-pcm.c @@ -314,8 +314,7 @@ static int sst_platform_init_stream(struct snd_pcm_substream *substream) stream->stream_info.arg = substream; stream->stream_info.buffer_ptr = 0; stream->stream_info.sfreq = substream->runtime->rate; - ret_val = stream->ops->device_control( - SST_SND_STREAM_INIT, &stream->stream_info); + ret_val = stream->ops->stream_init(&stream->stream_info); if (ret_val) pr_err("control_set ret error %d\n", ret_val); return ret_val; @@ -403,8 +402,7 @@ static int sst_media_prepare(struct snd_pcm_substream *substream, stream = substream->runtime->private_data; str_id = stream->stream_info.str_id; if (stream->stream_info.str_id) { - ret_val = stream->ops->device_control( - SST_SND_DROP, &str_id); + ret_val = stream->ops->stream_drop(str_id); return ret_val; } @@ -461,7 +459,7 @@ static int sst_platform_pcm_trigger(struct snd_pcm_substream *substream, { int ret_val = 0, str_id; struct sst_runtime_stream *stream; - int str_cmd, status; + int status; pr_debug("sst_platform_pcm_trigger called\n"); stream = substream->runtime->private_data; @@ -469,29 +467,29 @@ static int sst_platform_pcm_trigger(struct snd_pcm_substream *substream, switch (cmd) { case SNDRV_PCM_TRIGGER_START: pr_debug("sst: Trigger Start\n"); - str_cmd = SST_SND_START; status = SST_PLATFORM_RUNNING; stream->stream_info.arg = substream; + ret_val = stream->ops->stream_start(str_id); break; case SNDRV_PCM_TRIGGER_STOP: pr_debug("sst: in stop\n"); - str_cmd = SST_SND_DROP; status = SST_PLATFORM_DROPPED; + ret_val = stream->ops->stream_drop(str_id); break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: pr_debug("sst: in pause\n"); - str_cmd = SST_SND_PAUSE; status = SST_PLATFORM_PAUSED; + ret_val = stream->ops->stream_pause(str_id); break; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: pr_debug("sst: in pause release\n"); - str_cmd = SST_SND_RESUME; status = SST_PLATFORM_RUNNING; + ret_val = stream->ops->stream_pause_release(str_id); break; default: return -EINVAL; } - ret_val = stream->ops->device_control(str_cmd, &str_id); + if (!ret_val) sst_set_stream_status(stream, status); @@ -511,8 +509,7 @@ static snd_pcm_uframes_t sst_platform_pcm_pointer if (status == SST_PLATFORM_INIT) return 0; str_info = &stream->stream_info; - ret_val = stream->ops->device_control( - SST_SND_BUFFER_POINTER, str_info); + ret_val = stream->ops->stream_read_tstamp(str_info); if (ret_val) { pr_err("sst: error code = %d\n", ret_val); return ret_val; diff --git a/sound/soc/intel/sst-mfld-platform.h b/sound/soc/intel/sst-mfld-platform.h index cc3a088df7dd..2d6e65bbbc49 100644 --- a/sound/soc/intel/sst-mfld-platform.h +++ b/sound/soc/intel/sst-mfld-platform.h @@ -54,18 +54,6 @@ enum sst_drv_status { SST_PLATFORM_DROPPED, }; -enum sst_controls { - SST_SND_ALLOC = 0x00, - SST_SND_PAUSE = 0x01, - SST_SND_RESUME = 0x02, - SST_SND_DROP = 0x03, - SST_SND_FREE = 0x04, - SST_SND_BUFFER_POINTER = 0x05, - SST_SND_STREAM_INIT = 0x06, - SST_SND_START = 0x07, - SST_MAX_CONTROLS = 0x07, -}; - enum sst_stream_ops { STREAM_OPS_PLAYBACK = 0, STREAM_OPS_CAPTURE, @@ -126,7 +114,12 @@ struct compress_sst_ops { struct sst_ops { int (*open) (struct snd_sst_params *str_param); - int (*device_control) (int cmd, void *arg); + int (*stream_init) (struct pcm_stream_info *str_info); + int (*stream_start) (int str_id); + int (*stream_drop) (int str_id); + int (*stream_pause) (int str_id); + int (*stream_pause_release) (int str_id); + int (*stream_read_tstamp) (struct pcm_stream_info *str_info); int (*send_byte_stream)(struct snd_sst_bytes_v2 *bytes); int (*close) (unsigned int str_id); }; From b12b087c8715286b8759016f1d5c36cac0bb37f6 Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Mon, 4 Aug 2014 15:04:21 +0530 Subject: [PATCH 015/251] ASoC: Intel: mfld-pcm: Change sst_ops prototypes to take dev parameter sst_ops need to use the sst driver context. So pass sst device as argument, which can be used to retrieve sst context. Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/sst-mfld-platform-pcm.c | 19 +++++++++---------- sound/soc/intel/sst-mfld-platform.h | 18 +++++++++--------- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/sound/soc/intel/sst-mfld-platform-pcm.c b/sound/soc/intel/sst-mfld-platform-pcm.c index 42766a51c17e..a89ff7e18e1a 100644 --- a/sound/soc/intel/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/sst-mfld-platform-pcm.c @@ -277,7 +277,7 @@ static int sst_platform_alloc_stream(struct snd_pcm_substream *substream, stream->stream_info.str_id = str_params.stream_id; - ret_val = stream->ops->open(&str_params); + ret_val = stream->ops->open(sst->dev, &str_params); if (ret_val <= 0) return ret_val; @@ -314,13 +314,12 @@ static int sst_platform_init_stream(struct snd_pcm_substream *substream) stream->stream_info.arg = substream; stream->stream_info.buffer_ptr = 0; stream->stream_info.sfreq = substream->runtime->rate; - ret_val = stream->ops->stream_init(&stream->stream_info); + ret_val = stream->ops->stream_init(sst->dev, &stream->stream_info); if (ret_val) pr_err("control_set ret error %d\n", ret_val); return ret_val; } -/* end -- helper functions */ static int sst_media_open(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) @@ -372,7 +371,7 @@ static void sst_media_close(struct snd_pcm_substream *substream, stream = substream->runtime->private_data; str_id = stream->stream_info.str_id; if (str_id) - ret_val = stream->ops->close(str_id); + ret_val = stream->ops->close(sst->dev, str_id); module_put(sst->dev->driver->owner); kfree(stream); } @@ -402,7 +401,7 @@ static int sst_media_prepare(struct snd_pcm_substream *substream, stream = substream->runtime->private_data; str_id = stream->stream_info.str_id; if (stream->stream_info.str_id) { - ret_val = stream->ops->stream_drop(str_id); + ret_val = stream->ops->stream_drop(sst->dev, str_id); return ret_val; } @@ -469,22 +468,22 @@ static int sst_platform_pcm_trigger(struct snd_pcm_substream *substream, pr_debug("sst: Trigger Start\n"); status = SST_PLATFORM_RUNNING; stream->stream_info.arg = substream; - ret_val = stream->ops->stream_start(str_id); + ret_val = stream->ops->stream_start(sst->dev, str_id); break; case SNDRV_PCM_TRIGGER_STOP: pr_debug("sst: in stop\n"); status = SST_PLATFORM_DROPPED; - ret_val = stream->ops->stream_drop(str_id); + ret_val = stream->ops->stream_drop(sst->dev, str_id); break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: pr_debug("sst: in pause\n"); status = SST_PLATFORM_PAUSED; - ret_val = stream->ops->stream_pause(str_id); + ret_val = stream->ops->stream_pause(sst->dev, str_id); break; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: pr_debug("sst: in pause release\n"); status = SST_PLATFORM_RUNNING; - ret_val = stream->ops->stream_pause_release(str_id); + ret_val = stream->ops->stream_pause_release(sst->dev, str_id); break; default: return -EINVAL; @@ -509,7 +508,7 @@ static snd_pcm_uframes_t sst_platform_pcm_pointer if (status == SST_PLATFORM_INIT) return 0; str_info = &stream->stream_info; - ret_val = stream->ops->stream_read_tstamp(str_info); + ret_val = stream->ops->stream_read_tstamp(sst->dev, str_info); if (ret_val) { pr_err("sst: error code = %d\n", ret_val); return ret_val; diff --git a/sound/soc/intel/sst-mfld-platform.h b/sound/soc/intel/sst-mfld-platform.h index 2d6e65bbbc49..d4c28b8fb471 100644 --- a/sound/soc/intel/sst-mfld-platform.h +++ b/sound/soc/intel/sst-mfld-platform.h @@ -113,15 +113,15 @@ struct compress_sst_ops { }; struct sst_ops { - int (*open) (struct snd_sst_params *str_param); - int (*stream_init) (struct pcm_stream_info *str_info); - int (*stream_start) (int str_id); - int (*stream_drop) (int str_id); - int (*stream_pause) (int str_id); - int (*stream_pause_release) (int str_id); - int (*stream_read_tstamp) (struct pcm_stream_info *str_info); - int (*send_byte_stream)(struct snd_sst_bytes_v2 *bytes); - int (*close) (unsigned int str_id); + int (*open) (struct device *dev, struct snd_sst_params *str_param); + int (*stream_init) (struct device *dev, struct pcm_stream_info *str_info); + int (*stream_start) (struct device *dev, int str_id); + int (*stream_drop) (struct device *dev, int str_id); + int (*stream_pause) (struct device *dev, int str_id); + int (*stream_pause_release) (struct device *dev, int str_id); + int (*stream_read_tstamp) (struct device *dev, struct pcm_stream_info *str_info); + int (*send_byte_stream)(struct device *dev, struct snd_sst_bytes_v2 *bytes); + int (*close) (struct device *dev, unsigned int str_id); }; struct sst_runtime_stream { From d8499c9b4b03ca88d7c7b4094cb09471658df7c2 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Mon, 4 Aug 2014 15:15:55 +0530 Subject: [PATCH 016/251] ASoC: Intel: add mrfld DSP defines We define the DSP commands,structures here which will be used to send the IPCs Signed-off-by: Vinod Koul Signed-off-by: Subhransu S. Prusty Signed-off-by: Mark Brown --- sound/soc/intel/Makefile | 3 +- sound/soc/intel/sst-atom-controls.c | 39 ++++ sound/soc/intel/sst-atom-controls.h | 286 +++++++++++++++++++++++- sound/soc/intel/sst-mfld-platform-pcm.c | 8 +- sound/soc/intel/sst-mfld-platform.h | 3 + 5 files changed, 335 insertions(+), 4 deletions(-) create mode 100644 sound/soc/intel/sst-atom-controls.c diff --git a/sound/soc/intel/Makefile b/sound/soc/intel/Makefile index 7acbfc43a0c6..f841786dad15 100644 --- a/sound/soc/intel/Makefile +++ b/sound/soc/intel/Makefile @@ -2,7 +2,8 @@ snd-soc-sst-dsp-objs := sst-dsp.o sst-firmware.o snd-soc-sst-acpi-objs := sst-acpi.o -snd-soc-sst-mfld-platform-objs := sst-mfld-platform-pcm.o sst-mfld-platform-compress.o +snd-soc-sst-mfld-platform-objs := sst-mfld-platform-pcm.o \ + sst-mfld-platform-compress.o sst-atom-controls.o snd-soc-mfld-machine-objs := mfld_machine.o obj-$(CONFIG_SND_SST_MFLD_PLATFORM) += snd-soc-sst-mfld-platform.o diff --git a/sound/soc/intel/sst-atom-controls.c b/sound/soc/intel/sst-atom-controls.c new file mode 100644 index 000000000000..ace3c4a59b14 --- /dev/null +++ b/sound/soc/intel/sst-atom-controls.c @@ -0,0 +1,39 @@ +/* + * sst-atom-controls.c - Intel MID Platform driver DPCM ALSA controls for Mrfld + * + * Copyright (C) 2013-14 Intel Corp + * Author: Omair Mohammed Abdullah + * Vinod Koul + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * 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. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include "sst-mfld-platform.h" +#include "sst-atom-controls.h" + +int sst_dsp_init_v2_dpcm(struct snd_soc_platform *platform) +{ + int ret = 0; + struct sst_data *drv = snd_soc_platform_get_drvdata(platform); + + drv->byte_stream = devm_kzalloc(platform->dev, + SST_MAX_BIN_BYTES, GFP_KERNEL); + if (!drv->byte_stream) + return -ENOMEM; + + return ret; +} diff --git a/sound/soc/intel/sst-atom-controls.h b/sound/soc/intel/sst-atom-controls.h index 14063ab8c7c5..8554889c0694 100644 --- a/sound/soc/intel/sst-atom-controls.h +++ b/sound/soc/intel/sst-atom-controls.h @@ -1,4 +1,6 @@ /* + * sst-atom-controls.h - Intel MID Platform driver header file + * * Copyright (C) 2013-14 Intel Corp * Author: Ramesh Babu * Omair M Abdullah @@ -18,13 +20,293 @@ * */ -#ifndef __SST_CONTROLS_V2_H__ -#define __SST_CONTROLS_V2_H__ +#ifndef __SST_ATOM_CONTROLS_H__ +#define __SST_ATOM_CONTROLS_H__ enum { MERR_DPCM_AUDIO = 0, MERR_DPCM_COMPR, }; +/* define a bit for each mixer input */ +#define SST_MIX_IP(x) (x) + +#define SST_IP_CODEC0 SST_MIX_IP(2) +#define SST_IP_CODEC1 SST_MIX_IP(3) +#define SST_IP_LOOP0 SST_MIX_IP(4) +#define SST_IP_LOOP1 SST_MIX_IP(5) +#define SST_IP_LOOP2 SST_MIX_IP(6) +#define SST_IP_PROBE SST_MIX_IP(7) +#define SST_IP_VOIP SST_MIX_IP(12) +#define SST_IP_PCM0 SST_MIX_IP(13) +#define SST_IP_PCM1 SST_MIX_IP(14) +#define SST_IP_MEDIA0 SST_MIX_IP(17) +#define SST_IP_MEDIA1 SST_MIX_IP(18) +#define SST_IP_MEDIA2 SST_MIX_IP(19) +#define SST_IP_MEDIA3 SST_MIX_IP(20) + +#define SST_IP_LAST SST_IP_MEDIA3 + +#define SST_SWM_INPUT_COUNT (SST_IP_LAST + 1) +#define SST_CMD_SWM_MAX_INPUTS 6 + +#define SST_PATH_ID_SHIFT 8 +#define SST_DEFAULT_LOCATION_ID 0xFFFF +#define SST_DEFAULT_CELL_NBR 0xFF +#define SST_DEFAULT_MODULE_ID 0xFFFF + +/* + * Audio DSP Path Ids. Specified by the audio DSP FW + */ +enum sst_path_index { + SST_PATH_INDEX_CODEC_OUT0 = (0x02 << SST_PATH_ID_SHIFT), + SST_PATH_INDEX_CODEC_OUT1 = (0x03 << SST_PATH_ID_SHIFT), + + SST_PATH_INDEX_SPROT_LOOP_OUT = (0x04 << SST_PATH_ID_SHIFT), + SST_PATH_INDEX_MEDIA_LOOP1_OUT = (0x05 << SST_PATH_ID_SHIFT), + SST_PATH_INDEX_MEDIA_LOOP2_OUT = (0x06 << SST_PATH_ID_SHIFT), + + SST_PATH_INDEX_VOIP_OUT = (0x0C << SST_PATH_ID_SHIFT), + SST_PATH_INDEX_PCM0_OUT = (0x0D << SST_PATH_ID_SHIFT), + SST_PATH_INDEX_PCM1_OUT = (0x0E << SST_PATH_ID_SHIFT), + SST_PATH_INDEX_PCM2_OUT = (0x0F << SST_PATH_ID_SHIFT), + + SST_PATH_INDEX_MEDIA0_OUT = (0x12 << SST_PATH_ID_SHIFT), + SST_PATH_INDEX_MEDIA1_OUT = (0x13 << SST_PATH_ID_SHIFT), + + + /* Start of input paths */ + SST_PATH_INDEX_CODEC_IN0 = (0x82 << SST_PATH_ID_SHIFT), + SST_PATH_INDEX_CODEC_IN1 = (0x83 << SST_PATH_ID_SHIFT), + + SST_PATH_INDEX_SPROT_LOOP_IN = (0x84 << SST_PATH_ID_SHIFT), + SST_PATH_INDEX_MEDIA_LOOP1_IN = (0x85 << SST_PATH_ID_SHIFT), + SST_PATH_INDEX_MEDIA_LOOP2_IN = (0x86 << SST_PATH_ID_SHIFT), + + SST_PATH_INDEX_VOIP_IN = (0x8C << SST_PATH_ID_SHIFT), + + SST_PATH_INDEX_PCM0_IN = (0x8D << SST_PATH_ID_SHIFT), + SST_PATH_INDEX_PCM1_IN = (0x8E << SST_PATH_ID_SHIFT), + + SST_PATH_INDEX_MEDIA0_IN = (0x8F << SST_PATH_ID_SHIFT), + SST_PATH_INDEX_MEDIA1_IN = (0x90 << SST_PATH_ID_SHIFT), + SST_PATH_INDEX_MEDIA2_IN = (0x91 << SST_PATH_ID_SHIFT), + + SST_PATH_INDEX_MEDIA3_IN = (0x9C << SST_PATH_ID_SHIFT), + + SST_PATH_INDEX_RESERVED = (0xFF << SST_PATH_ID_SHIFT), +}; + +/* + * path IDs + */ +enum sst_swm_inputs { + SST_SWM_IN_CODEC0 = (SST_PATH_INDEX_CODEC_IN0 | SST_DEFAULT_CELL_NBR), + SST_SWM_IN_CODEC1 = (SST_PATH_INDEX_CODEC_IN1 | SST_DEFAULT_CELL_NBR), + SST_SWM_IN_SPROT_LOOP = (SST_PATH_INDEX_SPROT_LOOP_IN | SST_DEFAULT_CELL_NBR), + SST_SWM_IN_MEDIA_LOOP1 = (SST_PATH_INDEX_MEDIA_LOOP1_IN | SST_DEFAULT_CELL_NBR), + SST_SWM_IN_MEDIA_LOOP2 = (SST_PATH_INDEX_MEDIA_LOOP2_IN | SST_DEFAULT_CELL_NBR), + SST_SWM_IN_VOIP = (SST_PATH_INDEX_VOIP_IN | SST_DEFAULT_CELL_NBR), + SST_SWM_IN_PCM0 = (SST_PATH_INDEX_PCM0_IN | SST_DEFAULT_CELL_NBR), + SST_SWM_IN_PCM1 = (SST_PATH_INDEX_PCM1_IN | SST_DEFAULT_CELL_NBR), + SST_SWM_IN_MEDIA0 = (SST_PATH_INDEX_MEDIA0_IN | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */ + SST_SWM_IN_MEDIA1 = (SST_PATH_INDEX_MEDIA1_IN | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */ + SST_SWM_IN_MEDIA2 = (SST_PATH_INDEX_MEDIA2_IN | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */ + SST_SWM_IN_MEDIA3 = (SST_PATH_INDEX_MEDIA3_IN | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */ + SST_SWM_IN_END = (SST_PATH_INDEX_RESERVED | SST_DEFAULT_CELL_NBR) +}; + +/* + * path IDs + */ +enum sst_swm_outputs { + SST_SWM_OUT_CODEC0 = (SST_PATH_INDEX_CODEC_OUT0 | SST_DEFAULT_CELL_NBR), + SST_SWM_OUT_CODEC1 = (SST_PATH_INDEX_CODEC_OUT1 | SST_DEFAULT_CELL_NBR), + SST_SWM_OUT_SPROT_LOOP = (SST_PATH_INDEX_SPROT_LOOP_OUT | SST_DEFAULT_CELL_NBR), + SST_SWM_OUT_MEDIA_LOOP1 = (SST_PATH_INDEX_MEDIA_LOOP1_OUT | SST_DEFAULT_CELL_NBR), + SST_SWM_OUT_MEDIA_LOOP2 = (SST_PATH_INDEX_MEDIA_LOOP2_OUT | SST_DEFAULT_CELL_NBR), + SST_SWM_OUT_VOIP = (SST_PATH_INDEX_VOIP_OUT | SST_DEFAULT_CELL_NBR), + SST_SWM_OUT_PCM0 = (SST_PATH_INDEX_PCM0_OUT | SST_DEFAULT_CELL_NBR), + SST_SWM_OUT_PCM1 = (SST_PATH_INDEX_PCM1_OUT | SST_DEFAULT_CELL_NBR), + SST_SWM_OUT_PCM2 = (SST_PATH_INDEX_PCM2_OUT | SST_DEFAULT_CELL_NBR), + SST_SWM_OUT_MEDIA0 = (SST_PATH_INDEX_MEDIA0_OUT | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */ + SST_SWM_OUT_MEDIA1 = (SST_PATH_INDEX_MEDIA1_OUT | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */ + SST_SWM_OUT_END = (SST_PATH_INDEX_RESERVED | SST_DEFAULT_CELL_NBR), +}; + +enum sst_ipc_msg { + SST_IPC_IA_CMD = 1, + SST_IPC_IA_SET_PARAMS, + SST_IPC_IA_GET_PARAMS, +}; + +enum sst_cmd_type { + SST_CMD_BYTES_SET = 1, + SST_CMD_BYTES_GET = 2, +}; + +enum sst_task { + SST_TASK_SBA = 1, + SST_TASK_MMX, +}; + +enum sst_type { + SST_TYPE_CMD = 1, + SST_TYPE_PARAMS, +}; + +enum sst_flag { + SST_FLAG_BLOCKED = 1, + SST_FLAG_NONBLOCK, +}; + +/* + * Enumeration for indexing the gain cells in VB_SET_GAIN DSP command + */ +enum sst_gain_index { + /* GAIN IDs for SB task start here */ + SST_GAIN_INDEX_CODEC_OUT0, + SST_GAIN_INDEX_CODEC_OUT1, + SST_GAIN_INDEX_CODEC_IN0, + SST_GAIN_INDEX_CODEC_IN1, + + SST_GAIN_INDEX_SPROT_LOOP_OUT, + SST_GAIN_INDEX_MEDIA_LOOP1_OUT, + SST_GAIN_INDEX_MEDIA_LOOP2_OUT, + + SST_GAIN_INDEX_PCM0_IN_LEFT, + SST_GAIN_INDEX_PCM0_IN_RIGHT, + + SST_GAIN_INDEX_PCM1_OUT_LEFT, + SST_GAIN_INDEX_PCM1_OUT_RIGHT, + SST_GAIN_INDEX_PCM1_IN_LEFT, + SST_GAIN_INDEX_PCM1_IN_RIGHT, + SST_GAIN_INDEX_PCM2_OUT_LEFT, + + SST_GAIN_INDEX_PCM2_OUT_RIGHT, + SST_GAIN_INDEX_VOIP_OUT, + SST_GAIN_INDEX_VOIP_IN, + + /* Gain IDs for MMX task start here */ + SST_GAIN_INDEX_MEDIA0_IN_LEFT, + SST_GAIN_INDEX_MEDIA0_IN_RIGHT, + SST_GAIN_INDEX_MEDIA1_IN_LEFT, + SST_GAIN_INDEX_MEDIA1_IN_RIGHT, + + SST_GAIN_INDEX_MEDIA2_IN_LEFT, + SST_GAIN_INDEX_MEDIA2_IN_RIGHT, + + SST_GAIN_INDEX_GAIN_END +}; + +/* + * Audio DSP module IDs specified by FW spec + * TODO: Update with all modules + */ +enum sst_module_id { + SST_MODULE_ID_PCM = 0x0001, + SST_MODULE_ID_MP3 = 0x0002, + SST_MODULE_ID_MP24 = 0x0003, + SST_MODULE_ID_AAC = 0x0004, + SST_MODULE_ID_AACP = 0x0005, + SST_MODULE_ID_EAACP = 0x0006, + SST_MODULE_ID_WMA9 = 0x0007, + SST_MODULE_ID_WMA10 = 0x0008, + SST_MODULE_ID_WMA10P = 0x0009, + SST_MODULE_ID_RA = 0x000A, + SST_MODULE_ID_DDAC3 = 0x000B, + SST_MODULE_ID_TRUE_HD = 0x000C, + SST_MODULE_ID_HD_PLUS = 0x000D, + + SST_MODULE_ID_SRC = 0x0064, + SST_MODULE_ID_DOWNMIX = 0x0066, + SST_MODULE_ID_GAIN_CELL = 0x0067, + SST_MODULE_ID_SPROT = 0x006D, + SST_MODULE_ID_BASS_BOOST = 0x006E, + SST_MODULE_ID_STEREO_WDNG = 0x006F, + SST_MODULE_ID_AV_REMOVAL = 0x0070, + SST_MODULE_ID_MIC_EQ = 0x0071, + SST_MODULE_ID_SPL = 0x0072, + SST_MODULE_ID_ALGO_VTSV = 0x0073, + SST_MODULE_ID_NR = 0x0076, + SST_MODULE_ID_BWX = 0x0077, + SST_MODULE_ID_DRP = 0x0078, + SST_MODULE_ID_MDRP = 0x0079, + + SST_MODULE_ID_ANA = 0x007A, + SST_MODULE_ID_AEC = 0x007B, + SST_MODULE_ID_NR_SNS = 0x007C, + SST_MODULE_ID_SER = 0x007D, + SST_MODULE_ID_AGC = 0x007E, + + SST_MODULE_ID_CNI = 0x007F, + SST_MODULE_ID_CONTEXT_ALGO_AWARE = 0x0080, + SST_MODULE_ID_FIR_24 = 0x0081, + SST_MODULE_ID_IIR_24 = 0x0082, + + SST_MODULE_ID_ASRC = 0x0083, + SST_MODULE_ID_TONE_GEN = 0x0084, + SST_MODULE_ID_BMF = 0x0086, + SST_MODULE_ID_EDL = 0x0087, + SST_MODULE_ID_GLC = 0x0088, + + SST_MODULE_ID_FIR_16 = 0x0089, + SST_MODULE_ID_IIR_16 = 0x008A, + SST_MODULE_ID_DNR = 0x008B, + + SST_MODULE_ID_VIRTUALIZER = 0x008C, + SST_MODULE_ID_VISUALIZATION = 0x008D, + SST_MODULE_ID_LOUDNESS_OPTIMIZER = 0x008E, + SST_MODULE_ID_REVERBERATION = 0x008F, + + SST_MODULE_ID_CNI_TX = 0x0090, + SST_MODULE_ID_REF_LINE = 0x0091, + SST_MODULE_ID_VOLUME = 0x0092, + SST_MODULE_ID_FILT_DCR = 0x0094, + SST_MODULE_ID_SLV = 0x009A, + SST_MODULE_ID_NLF = 0x009B, + SST_MODULE_ID_TNR = 0x009C, + SST_MODULE_ID_WNR = 0x009D, + + SST_MODULE_ID_LOG = 0xFF00, + + SST_MODULE_ID_TASK = 0xFFFF, +}; + +enum sst_cmd { + SBA_IDLE = 14, + SBA_VB_SET_SPEECH_PATH = 26, + MMX_SET_GAIN = 33, + SBA_VB_SET_GAIN = 33, + FBA_VB_RX_CNI = 35, + MMX_SET_GAIN_TIMECONST = 36, + SBA_VB_SET_TIMECONST = 36, + SBA_VB_START = 85, + SBA_SET_SWM = 114, + SBA_SET_MDRP = 116, + SBA_HW_SET_SSP = 117, + SBA_SET_MEDIA_LOOP_MAP = 118, + SBA_SET_MEDIA_PATH = 119, + MMX_SET_MEDIA_PATH = 119, + SBA_VB_LPRO = 126, + SBA_VB_SET_FIR = 128, + SBA_VB_SET_IIR = 129, + SBA_SET_SSP_SLOT_MAP = 130, +}; + +enum sst_dsp_switch { + SST_SWITCH_OFF = 0, + SST_SWITCH_ON = 3, +}; + +enum sst_path_switch { + SST_PATH_OFF = 0, + SST_PATH_ON = 1, +}; + +enum sst_swm_state { + SST_SWM_OFF = 0, + SST_SWM_ON = 3, +}; #endif diff --git a/sound/soc/intel/sst-mfld-platform-pcm.c b/sound/soc/intel/sst-mfld-platform-pcm.c index a89ff7e18e1a..8e1e9bc27642 100644 --- a/sound/soc/intel/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/sst-mfld-platform-pcm.c @@ -550,7 +550,13 @@ static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd) return retval; } -static struct snd_soc_platform_driver sst_soc_platform_drv = { +static int sst_soc_probe(struct snd_soc_platform *platform) +{ + return sst_dsp_init_v2_dpcm(platform); +} + +static struct snd_soc_platform_driver sst_soc_platform_drv = { + .probe = sst_soc_probe, .ops = &sst_platform_ops, .compr_ops = &sst_platform_compr_ops, .pcm_new = sst_pcm_new, diff --git a/sound/soc/intel/sst-mfld-platform.h b/sound/soc/intel/sst-mfld-platform.h index d4c28b8fb471..faaba10c1dff 100644 --- a/sound/soc/intel/sst-mfld-platform.h +++ b/sound/soc/intel/sst-mfld-platform.h @@ -143,6 +143,8 @@ struct sst_device { }; struct sst_data; + +int sst_dsp_init_v2_dpcm(struct snd_soc_platform *platform); void sst_set_stream_status(struct sst_runtime_stream *stream, int state); int sst_fill_stream_params(void *substream, const struct sst_data *ctx, struct snd_sst_params *str_params, bool is_compress); @@ -157,6 +159,7 @@ struct sst_algo_int_control_v2 { struct sst_data { struct platform_device *pdev; struct sst_platform_data *pdata; + char *byte_stream; struct mutex lock; }; int sst_register_dsp(struct sst_device *sst); From a493b6a637e9d8e828d7ed4be4bdf24dfd1f9250 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 8 Aug 2014 12:07:49 +0200 Subject: [PATCH 017/251] ASoC: rsnd: delete unneeded test before of_node_put MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Of_node_put supports NULL as its argument, so the initial test is not necessary. Suggested by Uwe Kleine-König. The semantic patch that fixes this problem is as follows: (http://coccinelle.lip6.fr/) // @@ expression e; @@ -if (e) of_node_put(e); // Signed-off-by: Julia Lawall Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 19f78963e8b9..1922ec57d10a 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -798,10 +798,8 @@ if (name##_node) { \ mod_parse(src); mod_parse(dvc); - if (playback) - of_node_put(playback); - if (capture) - of_node_put(capture); + of_node_put(playback); + of_node_put(capture); } dai_i++; From 0d985b1c76623747107dbab1052044d6bac3866d Mon Sep 17 00:00:00 2001 From: Rongjun Ying Date: Wed, 13 Aug 2014 16:31:40 +0800 Subject: [PATCH 018/251] ASoC: sirf: usp: Add bitclock inversion support Signed-off-by: Rongjun Ying Signed-off-by: Mark Brown --- sound/soc/sirf/sirf-usp.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/sound/soc/sirf/sirf-usp.c b/sound/soc/sirf/sirf-usp.c index 3a730374e259..186dc7f33a55 100644 --- a/sound/soc/sirf/sirf-usp.c +++ b/sound/soc/sirf/sirf-usp.c @@ -100,6 +100,16 @@ static int sirf_usp_pcm_set_dai_fmt(struct snd_soc_dai *dai, return -EINVAL; } + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_NF: + usp->daifmt_format |= (fmt & SND_SOC_DAIFMT_INV_MASK); + break; + default: + return -EINVAL; + } + return 0; } @@ -177,7 +187,7 @@ static int sirf_usp_pcm_hw_params(struct snd_pcm_substream *substream, shifter_len = data_len; - switch (usp->daifmt_format) { + switch (usp->daifmt_format & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: regmap_update_bits(usp->regmap, USP_RX_FRAME_CTRL, USP_I2S_SYNC_CHG, USP_I2S_SYNC_CHG); @@ -193,6 +203,18 @@ static int sirf_usp_pcm_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } + switch (usp->daifmt_format & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_NF: + regmap_update_bits(usp->regmap, USP_MODE1, + USP_RXD_ACT_EDGE_FALLING | USP_TXD_ACT_EDGE_FALLING, + USP_RXD_ACT_EDGE_FALLING); + break; + default: + return -EINVAL; + } + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) regmap_update_bits(usp->regmap, USP_TX_FRAME_CTRL, USP_TXC_DATA_LEN_MASK | USP_TXC_FRAME_LEN_MASK From a7a8e994ddd004fbabfcf04c26c204297b5f826d Mon Sep 17 00:00:00 2001 From: Dan Murphy Date: Fri, 1 Aug 2014 10:57:04 -0500 Subject: [PATCH 019/251] ASoC: tas2552: Add DAPM calls for amp and PLL Add DAPM calls to enable/disable the Class D amp. Also add a DAPM call to turn off the PLL upon the stream completing. Signed-off-by: Dan Murphy Signed-off-by: Mark Brown --- sound/soc/codecs/tas2552.c | 68 +++++++++++++++++++++++++++----------- 1 file changed, 48 insertions(+), 20 deletions(-) diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c index 23b32960ff1d..1ed57a7e57b6 100644 --- a/sound/soc/codecs/tas2552.c +++ b/sound/soc/codecs/tas2552.c @@ -78,6 +78,43 @@ struct tas2552_data { unsigned int mclk; }; +/* Input mux controls */ +static const char *tas2552_input_texts[] = { + "Digital", "Analog" +}; + +static SOC_ENUM_SINGLE_DECL(tas2552_input_mux_enum, TAS2552_CFG_3, 7, + tas2552_input_texts); + +static const struct snd_kcontrol_new tas2552_input_mux_control[] = { + SOC_DAPM_ENUM("Input selection", tas2552_input_mux_enum) +}; + +static const struct snd_soc_dapm_widget tas2552_dapm_widgets[] = +{ + SND_SOC_DAPM_INPUT("IN"), + + /* MUX Controls */ + SND_SOC_DAPM_MUX("Input selection", SND_SOC_NOPM, 0, 0, + tas2552_input_mux_control), + + SND_SOC_DAPM_AIF_IN("DAC IN", "DAC Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_OUT_DRV("ClassD", TAS2552_CFG_2, 7, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("PLL", TAS2552_CFG_2, 3, 0, NULL, 0), + + SND_SOC_DAPM_OUTPUT("OUT") +}; + +static const struct snd_soc_dapm_route tas2552_audio_map[] = { + {"DAC", NULL, "DAC IN"}, + {"Input selection", "Digital", "DAC"}, + {"Input selection", "Analog", "IN"}, + {"ClassD", NULL, "Input selection"}, + {"OUT", NULL, "ClassD"}, + {"ClassD", NULL, "PLL"}, +}; + static void tas2552_sw_shutdown(struct tas2552_data *tas_data, int sw_shutdown) { u8 cfg1_reg; @@ -101,10 +138,6 @@ static int tas2552_hw_params(struct snd_pcm_substream *substream, int d; u8 p, j; - /* Turn on Class D amplifier */ - snd_soc_update_bits(codec, TAS2552_CFG_2, TAS2552_CLASSD_EN_MASK, - TAS2552_CLASSD_EN); - if (!tas2552->mclk) return -EINVAL; @@ -147,9 +180,6 @@ static int tas2552_hw_params(struct snd_pcm_substream *substream, } - snd_soc_update_bits(codec, TAS2552_CFG_2, TAS2552_PLL_ENABLE, - TAS2552_PLL_ENABLE); - return 0; } @@ -269,19 +299,10 @@ static const struct dev_pm_ops tas2552_pm = { NULL) }; -static void tas2552_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct snd_soc_codec *codec = dai->codec; - - snd_soc_update_bits(codec, TAS2552_CFG_2, TAS2552_PLL_ENABLE, 0); -} - static struct snd_soc_dai_ops tas2552_speaker_dai_ops = { .hw_params = tas2552_hw_params, .set_sysclk = tas2552_set_dai_sysclk, .set_fmt = tas2552_set_dai_fmt, - .shutdown = tas2552_shutdown, .digital_mute = tas2552_mute, }; @@ -294,7 +315,7 @@ static struct snd_soc_dai_driver tas2552_dai[] = { { .name = "tas2552-amplifier", .playback = { - .stream_name = "Speaker", + .stream_name = "Playback", .channels_min = 2, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_192000, @@ -312,6 +333,7 @@ static DECLARE_TLV_DB_SCALE(dac_tlv, -7, 100, 24); static const struct snd_kcontrol_new tas2552_snd_controls[] = { SOC_SINGLE_TLV("Speaker Driver Playback Volume", TAS2552_PGA_GAIN, 0, 0x1f, 1, dac_tlv), + SOC_DAPM_SINGLE("Playback AMP", SND_SOC_NOPM, 0, 1, 0), }; static const struct reg_default tas2552_init_regs[] = { @@ -321,6 +343,7 @@ static const struct reg_default tas2552_init_regs[] = { static int tas2552_codec_probe(struct snd_soc_codec *codec) { struct tas2552_data *tas2552 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_dapm_context *dapm = &codec->dapm; int ret; tas2552->codec = codec; @@ -362,9 +385,14 @@ static int tas2552_codec_probe(struct snd_soc_codec *codec) goto patch_fail; } - snd_soc_write(codec, TAS2552_CFG_2, TAS2552_CLASSD_EN | - TAS2552_BOOST_EN | TAS2552_APT_EN | - TAS2552_LIM_EN); + snd_soc_write(codec, TAS2552_CFG_2, TAS2552_BOOST_EN | + TAS2552_APT_EN | TAS2552_LIM_EN); + + snd_soc_dapm_new_controls(dapm, tas2552_dapm_widgets, + ARRAY_SIZE(tas2552_dapm_widgets)); + snd_soc_dapm_add_routes(dapm, tas2552_audio_map, + ARRAY_SIZE(tas2552_audio_map)); + return 0; patch_fail: From dfe8f1f3f22f9922e773ae64f5621f290cb26023 Mon Sep 17 00:00:00 2001 From: Nikesh Oswal Date: Wed, 13 Aug 2014 10:05:45 +0100 Subject: [PATCH 020/251] ASoC: wm8994: Demux the microphone detection IRQ Current code only allows direct routing of the WM8994 microphone detection signal to a GPIO this change adds support to demux the interrupt from the main interrupt line of the codec. Signed-off-by: Nikesh Oswal Signed-off-by: Mark Brown --- sound/soc/codecs/wm8994.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index 6cc0566dc29a..1fcb9f3f3097 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -4082,17 +4082,23 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) switch (control->type) { case WM8994: - if (wm8994->micdet_irq) { + if (wm8994->micdet_irq) ret = request_threaded_irq(wm8994->micdet_irq, NULL, wm8994_mic_irq, IRQF_TRIGGER_RISING, "Mic1 detect", wm8994); - if (ret != 0) - dev_warn(codec->dev, - "Failed to request Mic1 detect IRQ: %d\n", - ret); - } + else + ret = wm8994_request_irq(wm8994->wm8994, + WM8994_IRQ_MIC1_DET, + wm8994_mic_irq, "Mic 1 detect", + wm8994); + + if (ret != 0) + dev_warn(codec->dev, + "Failed to request Mic1 detect IRQ: %d\n", + ret); + ret = wm8994_request_irq(wm8994->wm8994, WM8994_IRQ_MIC1_SHRT, From d4f7facde1796c8b3eb2f79e1fd903d7b776972f Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Thu, 31 Jul 2014 10:43:35 +0800 Subject: [PATCH 021/251] devicetree: bindings: Add Everest Semicodunctor Everest Semiconductor makes audio codecs. Signed-off-by: Sean Cross Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/vendor-prefixes.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index ac7269f90764..34cc1bfcebfd 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -48,6 +48,7 @@ epfl Ecole Polytechnique Fédérale de Lausanne epson Seiko Epson Corp. est ESTeem Wireless Modems eukrea Eukréa Electromatique +everest Everest Semiconductor Co. Ltd. excito Excito fsl Freescale Semiconductor GEFanuc GE Fanuc Intelligent Platforms Embedded Systems, Inc. From 567e4f98922ce5542f8c2aa469a0c6ddf182b6ea Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Thu, 31 Jul 2014 10:43:36 +0800 Subject: [PATCH 022/251] ASoC: add es8328 codec driver Add a codec driver for the Everest ES8328. It supports two separate audio outputs and two separate audio inputs. Signed-off-by: Sean Cross Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/es8328.txt | 38 + sound/soc/codecs/Kconfig | 13 + sound/soc/codecs/Makefile | 6 + sound/soc/codecs/es8328-i2c.c | 60 ++ sound/soc/codecs/es8328-spi.c | 49 ++ sound/soc/codecs/es8328.c | 756 ++++++++++++++++++ sound/soc/codecs/es8328.h | 314 ++++++++ 7 files changed, 1236 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/es8328.txt create mode 100644 sound/soc/codecs/es8328-i2c.c create mode 100644 sound/soc/codecs/es8328-spi.c create mode 100644 sound/soc/codecs/es8328.c create mode 100644 sound/soc/codecs/es8328.h diff --git a/Documentation/devicetree/bindings/sound/es8328.txt b/Documentation/devicetree/bindings/sound/es8328.txt new file mode 100644 index 000000000000..30ea8a318ae9 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/es8328.txt @@ -0,0 +1,38 @@ +Everest ES8328 audio CODEC + +This device supports both I2C and SPI. + +Required properties: + + - compatible : "everest,es8328" + - DVDD-supply : Regulator providing digital core supply voltage 1.8 - 3.6V + - AVDD-supply : Regulator providing analog supply voltage 3.3V + - PVDD-supply : Regulator providing digital IO supply voltage 1.8 - 3.6V + - IPVDD-supply : Regulator providing analog output voltage 3.3V + - clocks : A 22.5792 or 11.2896 MHz clock + - reg : the I2C address of the device for I2C, the chip select number for SPI + +Pins on the device (for linking into audio routes): + + * LOUT1 + * LOUT2 + * ROUT1 + * ROUT2 + * LINPUT1 + * RINPUT1 + * LINPUT2 + * RINPUT2 + * Mic Bias + + +Example: + +codec: es8328@11 { + compatible = "everest,es8328"; + DVDD-supply = <®_3p3v>; + AVDD-supply = <®_3p3v>; + PVDD-supply = <®_3p3v>; + HPVDD-supply = <®_3p3v>; + clocks = <&clks 169>; + reg = <0x11>; +}; diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 8838838e25ed..8bca6343d8a3 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -57,6 +57,8 @@ config SND_SOC_ALL_CODECS select SND_SOC_DA732X if I2C select SND_SOC_DA9055 if I2C select SND_SOC_BT_SCO + select SND_SOC_ES8328_SPI if SPI_MASTER + select SND_SOC_ES8328_I2C if I2C select SND_SOC_ISABELLE if I2C select SND_SOC_JZ4740_CODEC select SND_SOC_LM4857 if I2C @@ -405,6 +407,17 @@ config SND_SOC_DMIC config SND_SOC_HDMI_CODEC tristate "HDMI stub CODEC" +config SND_SOC_ES8328 + tristate "Everest Semi ES8328 CODEC" + +config SND_SOC_ES8328_I2C + tristate + select SND_SOC_ES8328 + +config SND_SOC_ES8328_SPI + tristate + select SND_SOC_ES8328 + config SND_SOC_ISABELLE tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 20afe0f0c5be..31a8283006d1 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -49,6 +49,9 @@ snd-soc-da732x-objs := da732x.o snd-soc-da9055-objs := da9055.o snd-soc-bt-sco-objs := bt-sco.o snd-soc-dmic-objs := dmic.o +snd-soc-es8328-objs := es8328.o +snd-soc-es8328-i2c-objs := es8328-i2c.o +snd-soc-es8328-spi-objs := es8328-spi.o snd-soc-isabelle-objs := isabelle.o snd-soc-jz4740-codec-objs := jz4740.o snd-soc-l3-objs := l3.o @@ -220,6 +223,9 @@ obj-$(CONFIG_SND_SOC_DA732X) += snd-soc-da732x.o obj-$(CONFIG_SND_SOC_DA9055) += snd-soc-da9055.o obj-$(CONFIG_SND_SOC_BT_SCO) += snd-soc-bt-sco.o obj-$(CONFIG_SND_SOC_DMIC) += snd-soc-dmic.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 obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.o obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o diff --git a/sound/soc/codecs/es8328-i2c.c b/sound/soc/codecs/es8328-i2c.c new file mode 100644 index 000000000000..aae410d122ee --- /dev/null +++ b/sound/soc/codecs/es8328-i2c.c @@ -0,0 +1,60 @@ +/* + * es8328-i2c.c -- ES8328 ALSA SoC I2C Audio driver + * + * Copyright 2014 Sutajio Ko-Usagi PTE LTD + * + * Author: Sean Cross + * + * 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 "es8328.h" + +static const struct i2c_device_id es8328_id[] = { + { "everest,es8328", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, es8328_id); + +static const struct of_device_id es8328_of_match[] = { + { .compatible = "everest,es8328", }, + { } +}; +MODULE_DEVICE_TABLE(of, es8328_of_match); + +static int es8328_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + return es8328_probe(&i2c->dev, + devm_regmap_init_i2c(i2c, &es8328_regmap_config)); +} + +static int es8328_i2c_remove(struct i2c_client *i2c) +{ + snd_soc_unregister_codec(&i2c->dev); + return 0; +} + +static struct i2c_driver es8328_i2c_driver = { + .driver = { + .name = "es8328", + .of_match_table = es8328_of_match, + }, + .probe = es8328_i2c_probe, + .remove = es8328_i2c_remove, + .id_table = es8328_id, +}; + +module_i2c_driver(es8328_i2c_driver); + +MODULE_DESCRIPTION("ASoC ES8328 audio CODEC I2C driver"); +MODULE_AUTHOR("Sean Cross "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/es8328-spi.c b/sound/soc/codecs/es8328-spi.c new file mode 100644 index 000000000000..8fbd935e1c76 --- /dev/null +++ b/sound/soc/codecs/es8328-spi.c @@ -0,0 +1,49 @@ +/* + * es8328.c -- ES8328 ALSA SoC SPI Audio driver + * + * Copyright 2014 Sutajio Ko-Usagi PTE LTD + * + * Author: Sean Cross + * + * 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 "es8328.h" + +static const struct of_device_id es8328_of_match[] = { + { .compatible = "everest,es8328", }, + { } +}; +MODULE_DEVICE_TABLE(of, es8328_of_match); + +static int es8328_spi_probe(struct spi_device *spi) +{ + return es8328_probe(&spi->dev, + devm_regmap_init_spi(spi, &es8328_regmap_config)); +} + +static int es8328_spi_remove(struct spi_device *spi) +{ + snd_soc_unregister_codec(&spi->dev); + return 0; +} + +static struct spi_driver es8328_spi_driver = { + .driver = { + .name = "es8328", + .of_match_table = es8328_of_match, + }, + .probe = es8328_spi_probe, + .remove = es8328_spi_remove, +}; + +module_spi_driver(es8328_spi_driver); +MODULE_DESCRIPTION("ASoC ES8328 audio CODEC SPI driver"); +MODULE_AUTHOR("Sean Cross "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/es8328.c b/sound/soc/codecs/es8328.c new file mode 100644 index 000000000000..7a9f65ad183d --- /dev/null +++ b/sound/soc/codecs/es8328.c @@ -0,0 +1,756 @@ +/* + * es8328.c -- ES8328 ALSA SoC Audio driver + * + * Copyright 2014 Sutajio Ko-Usagi PTE LTD + * + * Author: Sean Cross + * + * 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 "es8328.h" + +#define ES8328_SYSCLK_RATE_1X 11289600 +#define ES8328_SYSCLK_RATE_2X 22579200 + +/* Run the codec at 22.5792 or 11.2896 MHz to support these rates */ +static struct { + int rate; + u8 ratio; +} mclk_ratios[] = { + { 8000, 9 }, + {11025, 7 }, + {22050, 4 }, + {44100, 2 }, +}; + +/* regulator supplies for sgtl5000, VDDD is an optional external supply */ +enum sgtl5000_regulator_supplies { + DVDD, + AVDD, + PVDD, + HPVDD, + ES8328_SUPPLY_NUM +}; + +/* vddd is optional supply */ +static const char * const supply_names[ES8328_SUPPLY_NUM] = { + "DVDD", + "AVDD", + "PVDD", + "HPVDD", +}; + +#define ES8328_RATES (SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_22050 | \ + SNDRV_PCM_RATE_11025) +#define ES8328_FORMATS (SNDRV_PCM_FMTBIT_S16_LE) + +struct es8328_priv { + struct regmap *regmap; + struct clk *clk; + int playback_fs; + bool deemph; + struct regulator_bulk_data supplies[ES8328_SUPPLY_NUM]; +}; + +/* + * ES8328 Controls + */ + +static const char * const adcpol_txt[] = {"Normal", "L Invert", "R Invert", + "L + R Invert"}; +static SOC_ENUM_SINGLE_DECL(adcpol, + ES8328_ADCCONTROL6, 6, adcpol_txt); + +static const DECLARE_TLV_DB_SCALE(play_tlv, -3000, 100, 0); +static const DECLARE_TLV_DB_SCALE(dac_adc_tlv, -9600, 50, 0); +static const DECLARE_TLV_DB_SCALE(pga_tlv, 0, 300, 0); +static const DECLARE_TLV_DB_SCALE(bypass_tlv, -1500, 300, 0); +static const DECLARE_TLV_DB_SCALE(mic_tlv, 0, 300, 0); + +static const int deemph_settings[] = { 0, 32000, 44100, 48000 }; + +static int es8328_set_deemph(struct snd_soc_codec *codec) +{ + struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec); + int val, i, best; + + /* + * If we're using deemphasis select the nearest available sample + * rate. + */ + if (es8328->deemph) { + best = 1; + for (i = 2; i < ARRAY_SIZE(deemph_settings); i++) { + if (abs(deemph_settings[i] - es8328->playback_fs) < + abs(deemph_settings[best] - es8328->playback_fs)) + best = i; + } + + val = best << 1; + } else { + val = 0; + } + + dev_dbg(codec->dev, "Set deemphasis %d\n", val); + + return snd_soc_update_bits(codec, ES8328_DACCONTROL6, 0x6, val); +} + +static int es8328_get_deemph(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.enumerated.item[0] = es8328->deemph; + return 0; +} + +static int es8328_put_deemph(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec); + int deemph = ucontrol->value.enumerated.item[0]; + int ret; + + if (deemph > 1) + return -EINVAL; + + ret = es8328_set_deemph(codec); + if (ret < 0) + return ret; + + es8328->deemph = deemph; + + return 0; +} + + + +static const struct snd_kcontrol_new es8328_snd_controls[] = { + SOC_DOUBLE_R_TLV("Capture Digital Volume", + ES8328_ADCCONTROL8, ES8328_ADCCONTROL9, + 0, 0xc0, 1, dac_adc_tlv), + SOC_SINGLE("Capture ZC Switch", ES8328_ADCCONTROL7, 6, 1, 0), + + SOC_SINGLE_BOOL_EXT("DAC Deemphasis Switch", 0, + es8328_get_deemph, es8328_put_deemph), + + SOC_ENUM("Capture Polarity", adcpol), + + SOC_SINGLE_TLV("Left Mixer Left Bypass Volume", + ES8328_DACCONTROL17, 3, 7, 1, bypass_tlv), + SOC_SINGLE_TLV("Left Mixer Right Bypass Volume", + ES8328_DACCONTROL19, 3, 7, 1, bypass_tlv), + SOC_SINGLE_TLV("Right Mixer Left Bypass Volume", + ES8328_DACCONTROL18, 3, 7, 1, bypass_tlv), + SOC_SINGLE_TLV("Right Mixer Right Bypass Volume", + ES8328_DACCONTROL20, 3, 7, 1, bypass_tlv), + + SOC_DOUBLE_R_TLV("PCM Volume", + ES8328_LDACVOL, ES8328_RDACVOL, + 0, ES8328_DACVOL_MAX, 1, dac_adc_tlv), + + SOC_DOUBLE_R_TLV("Output 1 Playback Volume", + ES8328_LOUT1VOL, ES8328_ROUT1VOL, + 0, ES8328_OUT1VOL_MAX, 0, play_tlv), + + SOC_DOUBLE_R_TLV("Output 2 Playback Volume", + ES8328_LOUT2VOL, ES8328_ROUT2VOL, + 0, ES8328_OUT2VOL_MAX, 0, play_tlv), + + SOC_DOUBLE_TLV("Mic PGA Volume", ES8328_ADCCONTROL1, + 4, 0, 8, 0, mic_tlv), +}; + +/* + * DAPM Controls + */ + +static const char * const es8328_line_texts[] = { + "Line 1", "Line 2", "PGA", "Differential"}; + +static const struct soc_enum es8328_lline_enum = + SOC_ENUM_SINGLE(ES8328_DACCONTROL16, 3, + ARRAY_SIZE(es8328_line_texts), + es8328_line_texts); +static const struct snd_kcontrol_new es8328_left_line_controls = + SOC_DAPM_ENUM("Route", es8328_lline_enum); + +static const struct soc_enum es8328_rline_enum = + SOC_ENUM_SINGLE(ES8328_DACCONTROL16, 0, + ARRAY_SIZE(es8328_line_texts), + es8328_line_texts); +static const struct snd_kcontrol_new es8328_right_line_controls = + SOC_DAPM_ENUM("Route", es8328_lline_enum); + +/* Left Mixer */ +static const struct snd_kcontrol_new es8328_left_mixer_controls[] = { + SOC_DAPM_SINGLE("Playback Switch", ES8328_DACCONTROL17, 8, 1, 0), + SOC_DAPM_SINGLE("Left Bypass Switch", ES8328_DACCONTROL17, 7, 1, 0), + SOC_DAPM_SINGLE("Right Playback Switch", ES8328_DACCONTROL18, 8, 1, 0), + SOC_DAPM_SINGLE("Right Bypass Switch", ES8328_DACCONTROL18, 7, 1, 0), +}; + +/* Right Mixer */ +static const struct snd_kcontrol_new es8328_right_mixer_controls[] = { + SOC_DAPM_SINGLE("Left Playback Switch", ES8328_DACCONTROL19, 8, 1, 0), + SOC_DAPM_SINGLE("Left Bypass Switch", ES8328_DACCONTROL19, 7, 1, 0), + SOC_DAPM_SINGLE("Playback Switch", ES8328_DACCONTROL20, 8, 1, 0), + SOC_DAPM_SINGLE("Right Bypass Switch", ES8328_DACCONTROL20, 7, 1, 0), +}; + +static const char * const es8328_pga_sel[] = { + "Line 1", "Line 2", "Line 3", "Differential"}; + +/* Left PGA Mux */ +static const struct soc_enum es8328_lpga_enum = + SOC_ENUM_SINGLE(ES8328_ADCCONTROL2, 6, + ARRAY_SIZE(es8328_pga_sel), + es8328_pga_sel); +static const struct snd_kcontrol_new es8328_left_pga_controls = + SOC_DAPM_ENUM("Route", es8328_lpga_enum); + +/* Right PGA Mux */ +static const struct soc_enum es8328_rpga_enum = + SOC_ENUM_SINGLE(ES8328_ADCCONTROL2, 4, + ARRAY_SIZE(es8328_pga_sel), + es8328_pga_sel); +static const struct snd_kcontrol_new es8328_right_pga_controls = + SOC_DAPM_ENUM("Route", es8328_rpga_enum); + +/* Differential Mux */ +static const char * const es8328_diff_sel[] = {"Line 1", "Line 2"}; +static SOC_ENUM_SINGLE_DECL(diffmux, + ES8328_ADCCONTROL3, 7, es8328_diff_sel); +static const struct snd_kcontrol_new es8328_diffmux_controls = + SOC_DAPM_ENUM("Route", diffmux); + +/* Mono ADC Mux */ +static const char * const es8328_mono_mux[] = {"Stereo", "Mono (Left)", + "Mono (Right)", "Digital Mono"}; +static SOC_ENUM_SINGLE_DECL(monomux, + ES8328_ADCCONTROL3, 3, es8328_mono_mux); +static const struct snd_kcontrol_new es8328_monomux_controls = + SOC_DAPM_ENUM("Route", monomux); + +static const struct snd_soc_dapm_widget es8328_dapm_widgets[] = { + SND_SOC_DAPM_MUX("Differential Mux", SND_SOC_NOPM, 0, 0, + &es8328_diffmux_controls), + SND_SOC_DAPM_MUX("Left ADC Mux", SND_SOC_NOPM, 0, 0, + &es8328_monomux_controls), + SND_SOC_DAPM_MUX("Right ADC Mux", SND_SOC_NOPM, 0, 0, + &es8328_monomux_controls), + + SND_SOC_DAPM_MUX("Left PGA Mux", ES8328_ADCPOWER, + ES8328_ADCPOWER_AINL_OFF, 1, + &es8328_left_pga_controls), + SND_SOC_DAPM_MUX("Right PGA Mux", ES8328_ADCPOWER, + ES8328_ADCPOWER_AINR_OFF, 1, + &es8328_right_pga_controls), + + SND_SOC_DAPM_MUX("Left Line Mux", SND_SOC_NOPM, 0, 0, + &es8328_left_line_controls), + SND_SOC_DAPM_MUX("Right Line Mux", SND_SOC_NOPM, 0, 0, + &es8328_right_line_controls), + + SND_SOC_DAPM_ADC("Right ADC", "Right Capture", ES8328_ADCPOWER, + ES8328_ADCPOWER_ADCR_OFF, 1), + SND_SOC_DAPM_ADC("Left ADC", "Left Capture", ES8328_ADCPOWER, + ES8328_ADCPOWER_ADCL_OFF, 1), + + SND_SOC_DAPM_SUPPLY("Mic Bias", ES8328_ADCPOWER, + ES8328_ADCPOWER_MIC_BIAS_OFF, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("Mic Bias Gen", ES8328_ADCPOWER, + ES8328_ADCPOWER_ADC_BIAS_GEN_OFF, 1, NULL, 0), + + SND_SOC_DAPM_SUPPLY("DAC STM", ES8328_CHIPPOWER, + ES8328_CHIPPOWER_DACSTM_RESET, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC STM", ES8328_CHIPPOWER, + ES8328_CHIPPOWER_ADCSTM_RESET, 1, NULL, 0), + + SND_SOC_DAPM_SUPPLY("DAC DIG", ES8328_CHIPPOWER, + ES8328_CHIPPOWER_DACDIG_OFF, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC DIG", ES8328_CHIPPOWER, + ES8328_CHIPPOWER_ADCDIG_OFF, 1, NULL, 0), + + SND_SOC_DAPM_SUPPLY("DAC DLL", ES8328_CHIPPOWER, + ES8328_CHIPPOWER_DACDLL_OFF, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC DLL", ES8328_CHIPPOWER, + ES8328_CHIPPOWER_ADCDLL_OFF, 1, NULL, 0), + + SND_SOC_DAPM_SUPPLY("ADC Vref", ES8328_CHIPPOWER, + ES8328_CHIPPOWER_ADCVREF_OFF, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("DAC Vref", ES8328_CHIPPOWER, + ES8328_CHIPPOWER_DACVREF_OFF, 1, NULL, 0), + + SND_SOC_DAPM_DAC("Right DAC", "Right Playback", ES8328_DACPOWER, + ES8328_DACPOWER_RDAC_OFF, 1), + SND_SOC_DAPM_DAC("Left DAC", "Left Playback", ES8328_DACPOWER, + ES8328_DACPOWER_LDAC_OFF, 1), + + SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0, + &es8328_left_mixer_controls[0], + ARRAY_SIZE(es8328_left_mixer_controls)), + SND_SOC_DAPM_MIXER("Right Mixer", SND_SOC_NOPM, 0, 0, + &es8328_right_mixer_controls[0], + ARRAY_SIZE(es8328_right_mixer_controls)), + + SND_SOC_DAPM_PGA("Right Out 2", ES8328_DACPOWER, + ES8328_DACPOWER_ROUT2_ON, 0, NULL, 0), + SND_SOC_DAPM_PGA("Left Out 2", ES8328_DACPOWER, + ES8328_DACPOWER_LOUT2_ON, 0, NULL, 0), + SND_SOC_DAPM_PGA("Right Out 1", ES8328_DACPOWER, + ES8328_DACPOWER_ROUT1_ON, 0, NULL, 0), + SND_SOC_DAPM_PGA("Left Out 1", ES8328_DACPOWER, + ES8328_DACPOWER_LOUT1_ON, 0, NULL, 0), + + SND_SOC_DAPM_OUTPUT("LOUT1"), + SND_SOC_DAPM_OUTPUT("ROUT1"), + SND_SOC_DAPM_OUTPUT("LOUT2"), + SND_SOC_DAPM_OUTPUT("ROUT2"), + + SND_SOC_DAPM_INPUT("LINPUT1"), + SND_SOC_DAPM_INPUT("LINPUT2"), + SND_SOC_DAPM_INPUT("RINPUT1"), + SND_SOC_DAPM_INPUT("RINPUT2"), +}; + +static const struct snd_soc_dapm_route es8328_dapm_routes[] = { + + { "Left Line Mux", "Line 1", "LINPUT1" }, + { "Left Line Mux", "Line 2", "LINPUT2" }, + { "Left Line Mux", "PGA", "Left PGA Mux" }, + { "Left Line Mux", "Differential", "Differential Mux" }, + + { "Right Line Mux", "Line 1", "RINPUT1" }, + { "Right Line Mux", "Line 2", "RINPUT2" }, + { "Right Line Mux", "PGA", "Right PGA Mux" }, + { "Right Line Mux", "Differential", "Differential Mux" }, + + { "Left PGA Mux", "Line 1", "LINPUT1" }, + { "Left PGA Mux", "Line 2", "LINPUT2" }, + { "Left PGA Mux", "Differential", "Differential Mux" }, + + { "Right PGA Mux", "Line 1", "RINPUT1" }, + { "Right PGA Mux", "Line 2", "RINPUT2" }, + { "Right PGA Mux", "Differential", "Differential Mux" }, + + { "Differential Mux", "Line 1", "LINPUT1" }, + { "Differential Mux", "Line 1", "RINPUT1" }, + { "Differential Mux", "Line 2", "LINPUT2" }, + { "Differential Mux", "Line 2", "RINPUT2" }, + + { "Left ADC Mux", "Stereo", "Left PGA Mux" }, + { "Left ADC Mux", "Mono (Left)", "Left PGA Mux" }, + { "Left ADC Mux", "Digital Mono", "Left PGA Mux" }, + + { "Right ADC Mux", "Stereo", "Right PGA Mux" }, + { "Right ADC Mux", "Mono (Right)", "Right PGA Mux" }, + { "Right ADC Mux", "Digital Mono", "Right PGA Mux" }, + + { "Left ADC", NULL, "Left ADC Mux" }, + { "Right ADC", NULL, "Right ADC Mux" }, + + { "ADC DIG", NULL, "ADC STM" }, + { "ADC DIG", NULL, "ADC Vref" }, + { "ADC DIG", NULL, "ADC DLL" }, + + { "Left ADC", NULL, "ADC DIG" }, + { "Right ADC", NULL, "ADC DIG" }, + + { "Mic Bias", NULL, "Mic Bias Gen" }, + + { "Left Line Mux", "Line 1", "LINPUT1" }, + { "Left Line Mux", "Line 2", "LINPUT2" }, + { "Left Line Mux", "PGA", "Left PGA Mux" }, + { "Left Line Mux", "Differential", "Differential Mux" }, + + { "Right Line Mux", "Line 1", "RINPUT1" }, + { "Right Line Mux", "Line 2", "RINPUT2" }, + { "Right Line Mux", "PGA", "Right PGA Mux" }, + { "Right Line Mux", "Differential", "Differential Mux" }, + + { "Left Out 1", NULL, "Left DAC" }, + { "Right Out 1", NULL, "Right DAC" }, + { "Left Out 2", NULL, "Left DAC" }, + { "Right Out 2", NULL, "Right DAC" }, + + { "Left Mixer", "Playback Switch", "Left DAC" }, + { "Left Mixer", "Left Bypass Switch", "Left Line Mux" }, + { "Left Mixer", "Right Playback Switch", "Right DAC" }, + { "Left Mixer", "Right Bypass Switch", "Right Line Mux" }, + + { "Right Mixer", "Left Playback Switch", "Left DAC" }, + { "Right Mixer", "Left Bypass Switch", "Left Line Mux" }, + { "Right Mixer", "Playback Switch", "Right DAC" }, + { "Right Mixer", "Right Bypass Switch", "Right Line Mux" }, + + { "DAC DIG", NULL, "DAC STM" }, + { "DAC DIG", NULL, "DAC Vref" }, + { "DAC DIG", NULL, "DAC DLL" }, + + { "Left DAC", NULL, "DAC DIG" }, + { "Right DAC", NULL, "DAC DIG" }, + + { "Left Out 1", NULL, "Left Mixer" }, + { "LOUT1", NULL, "Left Out 1" }, + { "Right Out 1", NULL, "Right Mixer" }, + { "ROUT1", NULL, "Right Out 1" }, + + { "Left Out 2", NULL, "Left Mixer" }, + { "LOUT2", NULL, "Left Out 2" }, + { "Right Out 2", NULL, "Right Mixer" }, + { "ROUT2", NULL, "Right Out 2" }, +}; + +static int es8328_mute(struct snd_soc_dai *dai, int mute) +{ + return snd_soc_update_bits(dai->codec, ES8328_DACCONTROL3, + ES8328_DACCONTROL3_DACMUTE, + mute ? ES8328_DACCONTROL3_DACMUTE : 0); +} + +static int es8328_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 es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec); + int clk_rate; + int i; + int reg; + u8 ratio; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + reg = ES8328_DACCONTROL2; + else + reg = ES8328_ADCCONTROL5; + + clk_rate = clk_get_rate(es8328->clk); + + if ((clk_rate != ES8328_SYSCLK_RATE_1X) && + (clk_rate != ES8328_SYSCLK_RATE_2X)) { + dev_err(codec->dev, + "%s: clock is running at %d Hz, not %d or %d Hz\n", + __func__, clk_rate, + ES8328_SYSCLK_RATE_1X, ES8328_SYSCLK_RATE_2X); + return -EINVAL; + } + + /* find master mode MCLK to sampling frequency ratio */ + ratio = mclk_ratios[0].rate; + for (i = 1; i < ARRAY_SIZE(mclk_ratios); i++) + if (params_rate(params) <= mclk_ratios[i].rate) + ratio = mclk_ratios[i].ratio; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + es8328->playback_fs = params_rate(params); + es8328_set_deemph(codec); + } + + return snd_soc_update_bits(codec, reg, ES8328_RATEMASK, ratio); +} + +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); + int clk_rate; + u8 mode = ES8328_DACCONTROL1_DACWL_16; + + /* set master/slave audio interface */ + if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBM_CFM) + return -EINVAL; + + /* interface format */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + mode |= ES8328_DACCONTROL1_DACFORMAT_I2S; + break; + case SND_SOC_DAIFMT_RIGHT_J: + mode |= ES8328_DACCONTROL1_DACFORMAT_RJUST; + break; + case SND_SOC_DAIFMT_LEFT_J: + mode |= ES8328_DACCONTROL1_DACFORMAT_LJUST; + break; + default: + return -EINVAL; + } + + /* clock inversion */ + if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF) + return -EINVAL; + + snd_soc_write(codec, ES8328_DACCONTROL1, mode); + snd_soc_write(codec, ES8328_ADCCONTROL4, mode); + + /* Master serial port mode, with BCLK generated automatically */ + clk_rate = clk_get_rate(es8328->clk); + if (clk_rate == ES8328_SYSCLK_RATE_1X) + snd_soc_write(codec, ES8328_MASTERMODE, + ES8328_MASTERMODE_MSC); + else + snd_soc_write(codec, ES8328_MASTERMODE, + ES8328_MASTERMODE_MCLKDIV2 | + ES8328_MASTERMODE_MSC); + + return 0; +} + +static int es8328_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + switch (level) { + case SND_SOC_BIAS_ON: + break; + + case SND_SOC_BIAS_PREPARE: + /* VREF, VMID=2x50k, digital enabled */ + snd_soc_write(codec, ES8328_CHIPPOWER, 0); + snd_soc_update_bits(codec, ES8328_CONTROL1, + ES8328_CONTROL1_VMIDSEL_MASK | + ES8328_CONTROL1_ENREF, + ES8328_CONTROL1_VMIDSEL_50k | + ES8328_CONTROL1_ENREF); + break; + + case SND_SOC_BIAS_STANDBY: + if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { + snd_soc_update_bits(codec, ES8328_CONTROL1, + ES8328_CONTROL1_VMIDSEL_MASK | + ES8328_CONTROL1_ENREF, + ES8328_CONTROL1_VMIDSEL_5k | + ES8328_CONTROL1_ENREF); + + /* Charge caps */ + msleep(100); + } + + snd_soc_write(codec, ES8328_CONTROL2, + ES8328_CONTROL2_OVERCURRENT_ON | + ES8328_CONTROL2_THERMAL_SHUTDOWN_ON); + + /* VREF, VMID=2*500k, digital stopped */ + snd_soc_update_bits(codec, ES8328_CONTROL1, + ES8328_CONTROL1_VMIDSEL_MASK | + ES8328_CONTROL1_ENREF, + ES8328_CONTROL1_VMIDSEL_500k | + ES8328_CONTROL1_ENREF); + break; + + case SND_SOC_BIAS_OFF: + snd_soc_update_bits(codec, ES8328_CONTROL1, + ES8328_CONTROL1_VMIDSEL_MASK | + ES8328_CONTROL1_ENREF, + 0); + break; + } + codec->dapm.bias_level = level; + return 0; +} + +static const struct snd_soc_dai_ops es8328_dai_ops = { + .hw_params = es8328_hw_params, + .digital_mute = es8328_mute, + .set_fmt = es8328_set_dai_fmt, +}; + +static struct snd_soc_dai_driver es8328_dai = { + .name = "es8328-hifi-analog", + .playback = { + .stream_name = "Playback", + .channels_min = 2, + .channels_max = 2, + .rates = ES8328_RATES, + .formats = ES8328_FORMATS, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 2, + .channels_max = 2, + .rates = ES8328_RATES, + .formats = ES8328_FORMATS, + }, + .ops = &es8328_dai_ops, +}; + +static int es8328_suspend(struct snd_soc_codec *codec) +{ + struct es8328_priv *es8328; + int ret; + + es8328 = snd_soc_codec_get_drvdata(codec); + + es8328_set_bias_level(codec, SND_SOC_BIAS_OFF); + + clk_disable_unprepare(es8328->clk); + + ret = regulator_bulk_disable(ARRAY_SIZE(es8328->supplies), + es8328->supplies); + if (ret) { + dev_err(codec->dev, "unable to disable regulators\n"); + return ret; + } + return 0; +} + +static int es8328_resume(struct snd_soc_codec *codec) +{ + struct regmap *regmap = dev_get_regmap(codec->dev, NULL); + struct es8328_priv *es8328; + int ret; + + es8328 = snd_soc_codec_get_drvdata(codec); + + ret = clk_prepare_enable(es8328->clk); + if (ret) { + dev_err(codec->dev, "unable to enable clock\n"); + return ret; + } + + ret = regulator_bulk_enable(ARRAY_SIZE(es8328->supplies), + es8328->supplies); + if (ret) { + dev_err(codec->dev, "unable to enable regulators\n"); + return ret; + } + + regcache_mark_dirty(regmap); + ret = regcache_sync(regmap); + if (ret) { + dev_err(codec->dev, "unable to sync regcache\n"); + return ret; + } + + es8328_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + return 0; +} + +static int es8328_codec_probe(struct snd_soc_codec *codec) +{ + struct es8328_priv *es8328; + int ret; + + es8328 = snd_soc_codec_get_drvdata(codec); + + ret = regulator_bulk_enable(ARRAY_SIZE(es8328->supplies), + es8328->supplies); + if (ret) { + dev_err(codec->dev, "unable to enable regulators\n"); + return ret; + } + + /* Setup clocks */ + es8328->clk = devm_clk_get(codec->dev, NULL); + if (IS_ERR(es8328->clk)) { + dev_err(codec->dev, "codec clock missing or invalid\n"); + goto clk_fail; + } + + ret = clk_prepare_enable(es8328->clk); + if (ret) { + dev_err(codec->dev, "unable to prepare codec clk\n"); + goto clk_fail; + } + + return 0; + +clk_fail: + regulator_bulk_disable(ARRAY_SIZE(es8328->supplies), + es8328->supplies); + return ret; +} + +static int es8328_remove(struct snd_soc_codec *codec) +{ + struct es8328_priv *es8328; + + es8328 = snd_soc_codec_get_drvdata(codec); + + if (es8328->clk) + clk_disable_unprepare(es8328->clk); + + regulator_bulk_disable(ARRAY_SIZE(es8328->supplies), + es8328->supplies); + + return 0; +} + +const struct regmap_config es8328_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = ES8328_REG_MAX, + .cache_type = REGCACHE_RBTREE, +}; +EXPORT_SYMBOL_GPL(es8328_regmap_config); + +static struct snd_soc_codec_driver es8328_codec_driver = { + .probe = es8328_codec_probe, + .suspend = es8328_suspend, + .resume = es8328_resume, + .remove = es8328_remove, + .set_bias_level = es8328_set_bias_level, + .controls = es8328_snd_controls, + .num_controls = ARRAY_SIZE(es8328_snd_controls), + .dapm_widgets = es8328_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(es8328_dapm_widgets), + .dapm_routes = es8328_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(es8328_dapm_routes), +}; + +int es8328_probe(struct device *dev, struct regmap *regmap) +{ + struct es8328_priv *es8328; + int ret; + int i; + + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + es8328 = devm_kzalloc(dev, sizeof(*es8328), GFP_KERNEL); + if (es8328 == NULL) + return -ENOMEM; + + es8328->regmap = regmap; + + for (i = 0; i < ARRAY_SIZE(es8328->supplies); i++) + es8328->supplies[i].supply = supply_names[i]; + + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(es8328->supplies), + es8328->supplies); + if (ret) { + dev_err(dev, "unable to get regulators\n"); + return ret; + } + + dev_set_drvdata(dev, es8328); + + return snd_soc_register_codec(dev, + &es8328_codec_driver, &es8328_dai, 1); +} +EXPORT_SYMBOL_GPL(es8328_probe); + +MODULE_DESCRIPTION("ASoC ES8328 driver"); +MODULE_AUTHOR("Sean Cross "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/es8328.h b/sound/soc/codecs/es8328.h new file mode 100644 index 000000000000..cb36afe10c0e --- /dev/null +++ b/sound/soc/codecs/es8328.h @@ -0,0 +1,314 @@ +/* + * es8328.h -- ES8328 ALSA SoC Audio driver + */ + +#ifndef _ES8328_H +#define _ES8328_H + +#include + +struct device; + +extern const struct regmap_config es8328_regmap_config; +int es8328_probe(struct device *dev, struct regmap *regmap); + +#define ES8328_DACLVOL 46 +#define ES8328_DACRVOL 47 +#define ES8328_DACCTL 28 +#define ES8328_RATEMASK (0x1f << 0) + +#define ES8328_CONTROL1 0x00 +#define ES8328_CONTROL1_VMIDSEL_OFF (0 << 0) +#define ES8328_CONTROL1_VMIDSEL_50k (1 << 0) +#define ES8328_CONTROL1_VMIDSEL_500k (2 << 0) +#define ES8328_CONTROL1_VMIDSEL_5k (3 << 0) +#define ES8328_CONTROL1_VMIDSEL_MASK (7 << 0) +#define ES8328_CONTROL1_ENREF (1 << 2) +#define ES8328_CONTROL1_SEQEN (1 << 3) +#define ES8328_CONTROL1_SAMEFS (1 << 4) +#define ES8328_CONTROL1_DACMCLK_ADC (0 << 5) +#define ES8328_CONTROL1_DACMCLK_DAC (1 << 5) +#define ES8328_CONTROL1_LRCM (1 << 6) +#define ES8328_CONTROL1_SCP_RESET (1 << 7) + +#define ES8328_CONTROL2 0x01 +#define ES8328_CONTROL2_VREF_BUF_OFF (1 << 0) +#define ES8328_CONTROL2_VREF_LOWPOWER (1 << 1) +#define ES8328_CONTROL2_IBIASGEN_OFF (1 << 2) +#define ES8328_CONTROL2_ANALOG_OFF (1 << 3) +#define ES8328_CONTROL2_VREF_BUF_LOWPOWER (1 << 4) +#define ES8328_CONTROL2_VCM_MOD_LOWPOWER (1 << 5) +#define ES8328_CONTROL2_OVERCURRENT_ON (1 << 6) +#define ES8328_CONTROL2_THERMAL_SHUTDOWN_ON (1 << 7) + +#define ES8328_CHIPPOWER 0x02 +#define ES8328_CHIPPOWER_DACVREF_OFF 0 +#define ES8328_CHIPPOWER_ADCVREF_OFF 1 +#define ES8328_CHIPPOWER_DACDLL_OFF 2 +#define ES8328_CHIPPOWER_ADCDLL_OFF 3 +#define ES8328_CHIPPOWER_DACSTM_RESET 4 +#define ES8328_CHIPPOWER_ADCSTM_RESET 5 +#define ES8328_CHIPPOWER_DACDIG_OFF 6 +#define ES8328_CHIPPOWER_ADCDIG_OFF 7 + +#define ES8328_ADCPOWER 0x03 +#define ES8328_ADCPOWER_INT1_LOWPOWER 0 +#define ES8328_ADCPOWER_FLASH_ADC_LOWPOWER 1 +#define ES8328_ADCPOWER_ADC_BIAS_GEN_OFF 2 +#define ES8328_ADCPOWER_MIC_BIAS_OFF 3 +#define ES8328_ADCPOWER_ADCR_OFF 4 +#define ES8328_ADCPOWER_ADCL_OFF 5 +#define ES8328_ADCPOWER_AINR_OFF 6 +#define ES8328_ADCPOWER_AINL_OFF 7 + +#define ES8328_DACPOWER 0x04 +#define ES8328_DACPOWER_OUT3_ON 0 +#define ES8328_DACPOWER_MONO_ON 1 +#define ES8328_DACPOWER_ROUT2_ON 2 +#define ES8328_DACPOWER_LOUT2_ON 3 +#define ES8328_DACPOWER_ROUT1_ON 4 +#define ES8328_DACPOWER_LOUT1_ON 5 +#define ES8328_DACPOWER_RDAC_OFF 6 +#define ES8328_DACPOWER_LDAC_OFF 7 + +#define ES8328_CHIPLOPOW1 0x05 +#define ES8328_CHIPLOPOW2 0x06 +#define ES8328_ANAVOLMANAG 0x07 + +#define ES8328_MASTERMODE 0x08 +#define ES8328_MASTERMODE_BCLKDIV (0 << 0) +#define ES8328_MASTERMODE_BCLK_INV (1 << 5) +#define ES8328_MASTERMODE_MCLKDIV2 (1 << 6) +#define ES8328_MASTERMODE_MSC (1 << 7) + +#define ES8328_ADCCONTROL1 0x09 +#define ES8328_ADCCONTROL2 0x0a +#define ES8328_ADCCONTROL3 0x0b +#define ES8328_ADCCONTROL4 0x0c +#define ES8328_ADCCONTROL5 0x0d +#define ES8328_ADCCONTROL5_RATEMASK (0x1f << 0) + +#define ES8328_ADCCONTROL6 0x0e + +#define ES8328_ADCCONTROL7 0x0f +#define ES8328_ADCCONTROL7_ADC_MUTE (1 << 2) +#define ES8328_ADCCONTROL7_ADC_LER (1 << 3) +#define ES8328_ADCCONTROL7_ADC_ZERO_CROSS (1 << 4) +#define ES8328_ADCCONTROL7_ADC_SOFT_RAMP (1 << 5) +#define ES8328_ADCCONTROL7_ADC_RAMP_RATE_4 (0 << 6) +#define ES8328_ADCCONTROL7_ADC_RAMP_RATE_8 (1 << 6) +#define ES8328_ADCCONTROL7_ADC_RAMP_RATE_16 (2 << 6) +#define ES8328_ADCCONTROL7_ADC_RAMP_RATE_32 (3 << 6) + +#define ES8328_ADCCONTROL8 0x10 +#define ES8328_ADCCONTROL9 0x11 +#define ES8328_ADCCONTROL10 0x12 +#define ES8328_ADCCONTROL11 0x13 +#define ES8328_ADCCONTROL12 0x14 +#define ES8328_ADCCONTROL13 0x15 +#define ES8328_ADCCONTROL14 0x16 + +#define ES8328_DACCONTROL1 0x17 +#define ES8328_DACCONTROL1_DACFORMAT_I2S (0 << 1) +#define ES8328_DACCONTROL1_DACFORMAT_LJUST (1 << 1) +#define ES8328_DACCONTROL1_DACFORMAT_RJUST (2 << 1) +#define ES8328_DACCONTROL1_DACFORMAT_PCM (3 << 1) +#define ES8328_DACCONTROL1_DACWL_24 (0 << 3) +#define ES8328_DACCONTROL1_DACWL_20 (1 << 3) +#define ES8328_DACCONTROL1_DACWL_18 (2 << 3) +#define ES8328_DACCONTROL1_DACWL_16 (3 << 3) +#define ES8328_DACCONTROL1_DACWL_32 (4 << 3) +#define ES8328_DACCONTROL1_DACLRP_I2S_POL_NORMAL (0 << 6) +#define ES8328_DACCONTROL1_DACLRP_I2S_POL_INV (1 << 6) +#define ES8328_DACCONTROL1_DACLRP_PCM_MSB_CLK2 (0 << 6) +#define ES8328_DACCONTROL1_DACLRP_PCM_MSB_CLK1 (1 << 6) +#define ES8328_DACCONTROL1_LRSWAP (1 << 7) + +#define ES8328_DACCONTROL2 0x18 +#define ES8328_DACCONTROL2_RATEMASK (0x1f << 0) +#define ES8328_DACCONTROL2_DOUBLESPEED (1 << 5) + +#define ES8328_DACCONTROL3 0x19 +#define ES8328_DACCONTROL3_AUTOMUTE (1 << 2) +#define ES8328_DACCONTROL3_DACMUTE (1 << 2) +#define ES8328_DACCONTROL3_LEFTGAINVOL (1 << 3) +#define ES8328_DACCONTROL3_DACZEROCROSS (1 << 4) +#define ES8328_DACCONTROL3_DACSOFTRAMP (1 << 5) +#define ES8328_DACCONTROL3_DACRAMPRATE (3 << 6) + +#define ES8328_LDACVOL 0x1a +#define ES8328_LDACVOL_MASK (0 << 0) +#define ES8328_LDACVOL_MAX (0xc0) + +#define ES8328_RDACVOL 0x1b +#define ES8328_RDACVOL_MASK (0 << 0) +#define ES8328_RDACVOL_MAX (0xc0) + +#define ES8328_DACVOL_MAX (0xc0) + +#define ES8328_DACCONTROL4 0x1a +#define ES8328_DACCONTROL5 0x1b + +#define ES8328_DACCONTROL6 0x1c +#define ES8328_DACCONTROL6_CLICKFREE (1 << 3) +#define ES8328_DACCONTROL6_DAC_INVR (1 << 4) +#define ES8328_DACCONTROL6_DAC_INVL (1 << 5) +#define ES8328_DACCONTROL6_DEEMPH_OFF (0 << 6) +#define ES8328_DACCONTROL6_DEEMPH_32k (1 << 6) +#define ES8328_DACCONTROL6_DEEMPH_44_1k (2 << 6) +#define ES8328_DACCONTROL6_DEEMPH_48k (3 << 6) + +#define ES8328_DACCONTROL7 0x1d +#define ES8328_DACCONTROL7_VPP_SCALE_3p5 (0 << 0) +#define ES8328_DACCONTROL7_VPP_SCALE_4p0 (1 << 0) +#define ES8328_DACCONTROL7_VPP_SCALE_3p0 (2 << 0) +#define ES8328_DACCONTROL7_VPP_SCALE_2p5 (3 << 0) +#define ES8328_DACCONTROL7_SHELVING_STRENGTH (1 << 2) /* In eights */ +#define ES8328_DACCONTROL7_MONO (1 << 5) +#define ES8328_DACCONTROL7_ZEROR (1 << 6) +#define ES8328_DACCONTROL7_ZEROL (1 << 7) + +/* Shelving filter */ +#define ES8328_DACCONTROL8 0x1e +#define ES8328_DACCONTROL9 0x1f +#define ES8328_DACCONTROL10 0x20 +#define ES8328_DACCONTROL11 0x21 +#define ES8328_DACCONTROL12 0x22 +#define ES8328_DACCONTROL13 0x23 +#define ES8328_DACCONTROL14 0x24 +#define ES8328_DACCONTROL15 0x25 + +#define ES8328_DACCONTROL16 0x26 +#define ES8328_DACCONTROL16_RMIXSEL_RIN1 (0 << 0) +#define ES8328_DACCONTROL16_RMIXSEL_RIN2 (1 << 0) +#define ES8328_DACCONTROL16_RMIXSEL_RIN3 (2 << 0) +#define ES8328_DACCONTROL16_RMIXSEL_RADC (3 << 0) +#define ES8328_DACCONTROL16_LMIXSEL_LIN1 (0 << 3) +#define ES8328_DACCONTROL16_LMIXSEL_LIN2 (1 << 3) +#define ES8328_DACCONTROL16_LMIXSEL_LIN3 (2 << 3) +#define ES8328_DACCONTROL16_LMIXSEL_LADC (3 << 3) + +#define ES8328_DACCONTROL17 0x27 +#define ES8328_DACCONTROL17_LI2LOVOL (7 << 3) +#define ES8328_DACCONTROL17_LI2LO (1 << 6) +#define ES8328_DACCONTROL17_LD2LO (1 << 7) + +#define ES8328_DACCONTROL18 0x28 +#define ES8328_DACCONTROL18_RI2LOVOL (7 << 3) +#define ES8328_DACCONTROL18_RI2LO (1 << 6) +#define ES8328_DACCONTROL18_RD2LO (1 << 7) + +#define ES8328_DACCONTROL19 0x29 +#define ES8328_DACCONTROL19_LI2ROVOL (7 << 3) +#define ES8328_DACCONTROL19_LI2RO (1 << 6) +#define ES8328_DACCONTROL19_LD2RO (1 << 7) + +#define ES8328_DACCONTROL20 0x2a +#define ES8328_DACCONTROL20_RI2ROVOL (7 << 3) +#define ES8328_DACCONTROL20_RI2RO (1 << 6) +#define ES8328_DACCONTROL20_RD2RO (1 << 7) + +#define ES8328_DACCONTROL21 0x2b +#define ES8328_DACCONTROL21_LI2MOVOL (7 << 3) +#define ES8328_DACCONTROL21_LI2MO (1 << 6) +#define ES8328_DACCONTROL21_LD2MO (1 << 7) + +#define ES8328_DACCONTROL22 0x2c +#define ES8328_DACCONTROL22_RI2MOVOL (7 << 3) +#define ES8328_DACCONTROL22_RI2MO (1 << 6) +#define ES8328_DACCONTROL22_RD2MO (1 << 7) + +#define ES8328_DACCONTROL23 0x2d +#define ES8328_DACCONTROL23_MOUTINV (1 << 1) +#define ES8328_DACCONTROL23_HPSWPOL (1 << 2) +#define ES8328_DACCONTROL23_HPSWEN (1 << 3) +#define ES8328_DACCONTROL23_VROI_1p5k (0 << 4) +#define ES8328_DACCONTROL23_VROI_40k (1 << 4) +#define ES8328_DACCONTROL23_OUT3_VREF (0 << 5) +#define ES8328_DACCONTROL23_OUT3_ROUT1 (1 << 5) +#define ES8328_DACCONTROL23_OUT3_MONOOUT (2 << 5) +#define ES8328_DACCONTROL23_OUT3_RIGHT_MIXER (3 << 5) +#define ES8328_DACCONTROL23_ROUT2INV (1 << 7) + +/* LOUT1 Amplifier */ +#define ES8328_LOUT1VOL 0x2e +#define ES8328_LOUT1VOL_MASK (0 << 5) +#define ES8328_LOUT1VOL_MAX (0x24) + +/* ROUT1 Amplifier */ +#define ES8328_ROUT1VOL 0x2f +#define ES8328_ROUT1VOL_MASK (0 << 5) +#define ES8328_ROUT1VOL_MAX (0x24) + +#define ES8328_OUT1VOL_MAX (0x24) + +/* LOUT2 Amplifier */ +#define ES8328_LOUT2VOL 0x30 +#define ES8328_LOUT2VOL_MASK (0 << 5) +#define ES8328_LOUT2VOL_MAX (0x24) + +/* ROUT2 Amplifier */ +#define ES8328_ROUT2VOL 0x31 +#define ES8328_ROUT2VOL_MASK (0 << 5) +#define ES8328_ROUT2VOL_MAX (0x24) + +#define ES8328_OUT2VOL_MAX (0x24) + +/* Mono Out Amplifier */ +#define ES8328_MONOOUTVOL 0x32 +#define ES8328_MONOOUTVOL_MASK (0 << 5) +#define ES8328_MONOOUTVOL_MAX (0x24) + +#define ES8328_DACCONTROL29 0x33 +#define ES8328_DACCONTROL30 0x34 + +#define ES8328_SYSCLK 0 + +#define ES8328_REG_MAX 0x35 + +#define ES8328_PLL1 0 +#define ES8328_PLL2 1 + +/* clock inputs */ +#define ES8328_MCLK 0 +#define ES8328_PCMCLK 1 + +/* clock divider id's */ +#define ES8328_PCMDIV 0 +#define ES8328_BCLKDIV 1 +#define ES8328_VXCLKDIV 2 + +/* PCM clock dividers */ +#define ES8328_PCM_DIV_1 (0 << 6) +#define ES8328_PCM_DIV_3 (2 << 6) +#define ES8328_PCM_DIV_5_5 (3 << 6) +#define ES8328_PCM_DIV_2 (4 << 6) +#define ES8328_PCM_DIV_4 (5 << 6) +#define ES8328_PCM_DIV_6 (6 << 6) +#define ES8328_PCM_DIV_8 (7 << 6) + +/* BCLK clock dividers */ +#define ES8328_BCLK_DIV_1 (0 << 7) +#define ES8328_BCLK_DIV_2 (1 << 7) +#define ES8328_BCLK_DIV_4 (2 << 7) +#define ES8328_BCLK_DIV_8 (3 << 7) + +/* VXCLK clock dividers */ +#define ES8328_VXCLK_DIV_1 (0 << 6) +#define ES8328_VXCLK_DIV_2 (1 << 6) +#define ES8328_VXCLK_DIV_4 (2 << 6) +#define ES8328_VXCLK_DIV_8 (3 << 6) +#define ES8328_VXCLK_DIV_16 (4 << 6) + +#define ES8328_DAI_HIFI 0 +#define ES8328_DAI_VOICE 1 + +#define ES8328_1536FS 1536 +#define ES8328_1024FS 1024 +#define ES8328_768FS 768 +#define ES8328_512FS 512 +#define ES8328_384FS 384 +#define ES8328_256FS 256 +#define ES8328_128FS 128 + +#endif From 7e7292dba2155c1433ce9f9a819f1acb9090747b Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Thu, 31 Jul 2014 10:43:37 +0800 Subject: [PATCH 023/251] ASoC: fsl: add imx-es8328 machine driver This adds an initial machine driver for the ES8328 audio codec on Freescale boards. The driver supports headphones and an audio regulator for an onboard speaker amp. Signed-off-by: Sean Cross Signed-off-by: Mark Brown --- .../bindings/sound/imx-audio-es8328.txt | 60 +++++ sound/soc/fsl/Kconfig | 14 ++ sound/soc/fsl/Makefile | 2 + sound/soc/fsl/imx-es8328.c | 232 ++++++++++++++++++ 4 files changed, 308 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/imx-audio-es8328.txt create mode 100644 sound/soc/fsl/imx-es8328.c diff --git a/Documentation/devicetree/bindings/sound/imx-audio-es8328.txt b/Documentation/devicetree/bindings/sound/imx-audio-es8328.txt new file mode 100644 index 000000000000..07b68ab206fb --- /dev/null +++ b/Documentation/devicetree/bindings/sound/imx-audio-es8328.txt @@ -0,0 +1,60 @@ +Freescale i.MX audio complex with ES8328 codec + +Required properties: +- compatible : "fsl,imx-audio-es8328" +- model : The user-visible name of this sound complex +- ssi-controller : The phandle of the i.MX SSI controller +- jack-gpio : Optional GPIO for headphone jack +- audio-amp-supply : Power regulator for speaker amps +- audio-codec : The phandle of the ES8328 audio codec +- audio-routing : A list of the connections between audio components. + Each entry is a pair of strings, the first being the + connection's sink, the second being the connection's + source. Valid names could be power supplies, ES8328 + pins, and the jacks on the board: + + Power supplies: + * audio-amp + + ES8328 pins: + * LOUT1 + * LOUT2 + * ROUT1 + * ROUT2 + * LINPUT1 + * LINPUT2 + * RINPUT1 + * RINPUT2 + * Mic PGA + + Board connectors: + * Headphone + * Speaker + * Mic Jack +- mux-int-port : The internal port of the i.MX audio muxer (AUDMUX) +- mux-ext-port : The external port of the i.MX audio muxer (AUDMIX) + +Note: The AUDMUX port numbering should start at 1, which is consistent with +hardware manual. + +Example: + +sound { + compatible = "fsl,imx-audio-es8328"; + model = "imx-audio-es8328"; + ssi-controller = <&ssi1>; + audio-codec = <&codec>; + jack-gpio = <&gpio5 15 0>; + audio-amp-supply = <®_audio_amp>; + audio-routing = + "Speaker", "LOUT2", + "Speaker", "ROUT2", + "Speaker", "audio-amp", + "Headphone", "ROUT1", + "Headphone", "LOUT1", + "LINPUT1", "Mic Jack", + "RINPUT1", "Mic Jack", + "Mic Jack", "Mic Bias"; + mux-int-port = <1>; + mux-ext-port = <3>; +}; diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 2b99a9e86899..fa90340dc13a 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -257,6 +257,20 @@ config SND_SOC_IMX_WM8962 Say Y if you want to add support for SoC audio on an i.MX board with a wm8962 codec. +config SND_SOC_IMX_ES8328 + tristate "SoC Audio support for i.MX boards with the ES8328 codec" + depends on OF && (I2C || SPI) + select SND_SOC_ES8328_I2C if I2C + select SND_SOC_ES8328_SPI if SPI_MASTER + select SND_SOC_IMX_PCM_DMA + select SND_SOC_IMX_AUDMUX + select SND_SOC_FSL_SSI + select SND_SOC_FSL_UTILS + select SND_SOC_IMX_PCM_FIQ + help + Say Y if you want to add support for the ES8328 audio codec connected + via SSI/I2S over either SPI or I2C. + config SND_SOC_IMX_SGTL5000 tristate "SoC Audio support for i.MX boards with sgtl5000" depends on OF && I2C diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index 8f6d84efa973..d28dc25c9375 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile @@ -52,6 +52,7 @@ snd-soc-eukrea-tlv320-objs := eukrea-tlv320.o snd-soc-phycore-ac97-objs := phycore-ac97.o snd-soc-mx27vis-aic32x4-objs := mx27vis-aic32x4.o snd-soc-wm1133-ev1-objs := wm1133-ev1.o +snd-soc-imx-es8328-objs := imx-es8328.o snd-soc-imx-sgtl5000-objs := imx-sgtl5000.o snd-soc-imx-wm8962-objs := imx-wm8962.o snd-soc-imx-spdif-objs := imx-spdif.o @@ -61,6 +62,7 @@ obj-$(CONFIG_SND_SOC_EUKREA_TLV320) += snd-soc-eukrea-tlv320.o obj-$(CONFIG_SND_SOC_PHYCORE_AC97) += snd-soc-phycore-ac97.o obj-$(CONFIG_SND_SOC_MX27VIS_AIC32X4) += snd-soc-mx27vis-aic32x4.o obj-$(CONFIG_SND_MXC_SOC_WM1133_EV1) += snd-soc-wm1133-ev1.o +obj-$(CONFIG_SND_SOC_IMX_ES8328) += snd-soc-imx-es8328.o obj-$(CONFIG_SND_SOC_IMX_SGTL5000) += snd-soc-imx-sgtl5000.o obj-$(CONFIG_SND_SOC_IMX_WM8962) += snd-soc-imx-wm8962.o obj-$(CONFIG_SND_SOC_IMX_SPDIF) += snd-soc-imx-spdif.o diff --git a/sound/soc/fsl/imx-es8328.c b/sound/soc/fsl/imx-es8328.c new file mode 100644 index 000000000000..653e66d150c8 --- /dev/null +++ b/sound/soc/fsl/imx-es8328.c @@ -0,0 +1,232 @@ +/* + * Copyright 2012 Freescale Semiconductor, Inc. + * Copyright 2012 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "imx-audmux.h" + +#define DAI_NAME_SIZE 32 +#define MUX_PORT_MAX 7 + +struct imx_es8328_data { + struct device *dev; + struct snd_soc_dai_link dai; + struct snd_soc_card card; + char codec_dai_name[DAI_NAME_SIZE]; + char platform_name[DAI_NAME_SIZE]; + int jack_gpio; +}; + +static struct snd_soc_jack_gpio headset_jack_gpios[] = { + { + .gpio = -1, + .name = "headset-gpio", + .report = SND_JACK_HEADSET, + .invert = 0, + .debounce_time = 200, + }, +}; + +static struct snd_soc_jack headset_jack; + +static int imx_es8328_dai_init(struct snd_soc_pcm_runtime *rtd) +{ + struct imx_es8328_data *data = container_of(rtd->card, + struct imx_es8328_data, card); + int ret = 0; + + /* Headphone jack detection */ + if (gpio_is_valid(data->jack_gpio)) { + ret = snd_soc_jack_new(rtd->codec, "Headphone", + SND_JACK_HEADPHONE | SND_JACK_BTN_0, + &headset_jack); + if (ret) + return ret; + + headset_jack_gpios[0].gpio = data->jack_gpio; + ret = snd_soc_jack_add_gpios(&headset_jack, + ARRAY_SIZE(headset_jack_gpios), + headset_jack_gpios); + } + + return ret; +} + +static const struct snd_soc_dapm_widget imx_es8328_dapm_widgets[] = { + SND_SOC_DAPM_MIC("Mic Jack", NULL), + SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_SPK("Speaker", NULL), + SND_SOC_DAPM_REGULATOR_SUPPLY("audio-amp", 1, 0), +}; + +static int imx_es8328_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct device_node *ssi_np, *codec_np; + struct platform_device *ssi_pdev; + struct imx_es8328_data *data; + u32 int_port, ext_port; + int ret; + struct device *dev = &pdev->dev; + + ret = of_property_read_u32(np, "mux-int-port", &int_port); + if (ret) { + dev_err(dev, "mux-int-port missing or invalid\n"); + goto fail; + } + if (int_port > MUX_PORT_MAX || int_port == 0) { + dev_err(dev, "mux-int-port: hardware only has %d mux ports\n", + MUX_PORT_MAX); + goto fail; + } + + ret = of_property_read_u32(np, "mux-ext-port", &ext_port); + if (ret) { + dev_err(dev, "mux-ext-port missing or invalid\n"); + goto fail; + } + if (ext_port > MUX_PORT_MAX || ext_port == 0) { + dev_err(dev, "mux-ext-port: hardware only has %d mux ports\n", + MUX_PORT_MAX); + goto fail; + } + + /* + * The port numbering in the hardware manual starts at 1, while + * the audmux API expects it starts at 0. + */ + int_port--; + ext_port--; + ret = imx_audmux_v2_configure_port(int_port, + IMX_AUDMUX_V2_PTCR_SYN | + IMX_AUDMUX_V2_PTCR_TFSEL(ext_port) | + IMX_AUDMUX_V2_PTCR_TCSEL(ext_port) | + IMX_AUDMUX_V2_PTCR_TFSDIR | + IMX_AUDMUX_V2_PTCR_TCLKDIR, + IMX_AUDMUX_V2_PDCR_RXDSEL(ext_port)); + if (ret) { + dev_err(dev, "audmux internal port setup failed\n"); + return ret; + } + ret = imx_audmux_v2_configure_port(ext_port, + IMX_AUDMUX_V2_PTCR_SYN, + IMX_AUDMUX_V2_PDCR_RXDSEL(int_port)); + if (ret) { + dev_err(dev, "audmux external port setup failed\n"); + return ret; + } + + ssi_np = of_parse_phandle(pdev->dev.of_node, "ssi-controller", 0); + codec_np = of_parse_phandle(pdev->dev.of_node, "audio-codec", 0); + if (!ssi_np || !codec_np) { + dev_err(dev, "phandle missing or invalid\n"); + ret = -EINVAL; + goto fail; + } + + ssi_pdev = of_find_device_by_node(ssi_np); + if (!ssi_pdev) { + dev_err(dev, "failed to find SSI platform device\n"); + ret = -EINVAL; + goto fail; + } + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) { + ret = -ENOMEM; + goto fail; + } + + data->dev = dev; + + data->jack_gpio = of_get_named_gpio(pdev->dev.of_node, "jack-gpio", 0); + + data->dai.name = "hifi"; + data->dai.stream_name = "hifi"; + data->dai.codec_dai_name = "es8328-hifi-analog"; + data->dai.codec_of_node = codec_np; + data->dai.cpu_of_node = ssi_np; + data->dai.platform_of_node = ssi_np; + data->dai.init = &imx_es8328_dai_init; + data->dai.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM; + + data->card.dev = dev; + data->card.dapm_widgets = imx_es8328_dapm_widgets; + data->card.num_dapm_widgets = ARRAY_SIZE(imx_es8328_dapm_widgets); + ret = snd_soc_of_parse_card_name(&data->card, "model"); + if (ret) { + dev_err(dev, "Unable to parse card name\n"); + goto fail; + } + ret = snd_soc_of_parse_audio_routing(&data->card, "audio-routing"); + if (ret) { + dev_err(dev, "Unable to parse routing: %d\n", ret); + goto fail; + } + data->card.num_links = 1; + data->card.owner = THIS_MODULE; + data->card.dai_link = &data->dai; + + ret = snd_soc_register_card(&data->card); + if (ret) { + dev_err(dev, "Unable to register: %d\n", ret); + goto fail; + } + + platform_set_drvdata(pdev, data); +fail: + of_node_put(ssi_np); + of_node_put(codec_np); + + return ret; +} + +static int imx_es8328_remove(struct platform_device *pdev) +{ + struct imx_es8328_data *data = platform_get_drvdata(pdev); + + snd_soc_jack_free_gpios(&headset_jack, ARRAY_SIZE(headset_jack_gpios), + headset_jack_gpios); + + snd_soc_unregister_card(&data->card); + + return 0; +} + +static const struct of_device_id imx_es8328_dt_ids[] = { + { .compatible = "fsl,imx-audio-es8328", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, imx_es8328_dt_ids); + +static struct platform_driver imx_es8328_driver = { + .driver = { + .name = "imx-es8328", + .of_match_table = imx_es8328_dt_ids, + }, + .probe = imx_es8328_probe, + .remove = imx_es8328_remove, +}; +module_platform_driver(imx_es8328_driver); + +MODULE_AUTHOR("Sean Cross "); +MODULE_DESCRIPTION("Kosagi i.MX6 ES8328 ASoC machine driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:imx-audio-es8328"); From 855675f6e6a65688a7f4cf45b9b5a98cf6c6f5c3 Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Mon, 4 Aug 2014 15:07:25 +0800 Subject: [PATCH 024/251] ASoC: fsl_sai: Set SYNC bit of TCR2 to Asynchronous Mode There is one design rule according to SAI's reference manual: If the transmitter bit clock and frame sync are to be used by both transmitter and receiver, the transmitter must be configured for asynchronous operation and the receiver for synchronous operation. And SYNC of TCR2 is a 2-width control bit: 00 Asynchronous mode. 01 Synchronous with receiver. 10 Synchronous with another SAI transmitter. 11 Synchronous with another SAI receiver. So the driver should have set SYNC bit of TCR2 to 0x0, and meanwhile set SYNC bit of RCR2 to 0x1 (Synchronous with transmitter). Signed-off-by: Nicolin Chen Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_sai.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index 4c9e71c2f52a..60fe7c77ba22 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -334,8 +334,7 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd, * Rx sync with Tx clocks: Clear SYNC for Tx, set it for Rx. * Tx sync with Rx clocks: Clear SYNC for Rx, set it for Tx. */ - regmap_update_bits(sai->regmap, FSL_SAI_TCR2, FSL_SAI_CR2_SYNC, - sai->synchronous[TX] ? FSL_SAI_CR2_SYNC : 0); + regmap_update_bits(sai->regmap, FSL_SAI_TCR2, FSL_SAI_CR2_SYNC, 0); regmap_update_bits(sai->regmap, FSL_SAI_RCR2, FSL_SAI_CR2_SYNC, sai->synchronous[RX] ? FSL_SAI_CR2_SYNC : 0); From 8a36eaa2ff4a9452a78d799503b920b4e1a0ec31 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 17 Aug 2014 12:03:05 +0200 Subject: [PATCH 025/251] ASoC: dmic: Add to SND_SOC_ALL_CODECS Improve build coverage of the dmic driver. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 8838838e25ed..e514e98e48c4 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -56,6 +56,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_DA7213 if I2C select SND_SOC_DA732X if I2C select SND_SOC_DA9055 if I2C + select SND_SOC_DMIC select SND_SOC_BT_SCO select SND_SOC_ISABELLE if I2C select SND_SOC_JZ4740_CODEC From 371e07ec837464375fe4d7ef3bd13e13cdfbb458 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 17 Aug 2014 16:18:17 +0200 Subject: [PATCH 026/251] ASoC: edma-pcm: Include edma-pcm.h edma_pcm_platform_register() is declared in edma-pcm.h and defined in edma-pcm.c. To make sure that the function signature matches for both edma-pcm.c should include edma-pcm.h Fixes the following sparse warning: sound/soc/davinci/edma-pcm.c:48:5: warning: symbol 'edma_pcm_platform_register' was not declared. Should it be static? Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/davinci/edma-pcm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/davinci/edma-pcm.c b/sound/soc/davinci/edma-pcm.c index 605e643133db..59e588abe54b 100644 --- a/sound/soc/davinci/edma-pcm.c +++ b/sound/soc/davinci/edma-pcm.c @@ -25,6 +25,8 @@ #include #include +#include "edma-pcm.h" + static const struct snd_pcm_hardware edma_pcm_hardware = { .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | From d80a12f92466d0bc4fd244c9052a8a88518c868e Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 17 Aug 2014 16:18:18 +0200 Subject: [PATCH 027/251] ASoC: odrodix2_max98090: Make non exported symbols static odroidx2_drvdata and odroidu3_drvdata are not used outside this module so make them static (and also const while we are at it). Fixes the following warnings from sparse: sound/soc/samsung/odroidx2_max98090.c:69:26: warning: symbol 'odroidx2_drvdata' was not declared. Should it be static? sound/soc/samsung/odroidx2_max98090.c:74:26: warning: symbol 'odroidu3_drvdata' was not declared. Should it be static? Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/samsung/odroidx2_max98090.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/samsung/odroidx2_max98090.c b/sound/soc/samsung/odroidx2_max98090.c index 278edf9e2a87..3c8f60423e82 100644 --- a/sound/soc/samsung/odroidx2_max98090.c +++ b/sound/soc/samsung/odroidx2_max98090.c @@ -66,12 +66,12 @@ static struct snd_soc_card odroidx2 = { .late_probe = odroidx2_late_probe, }; -struct odroidx2_drv_data odroidx2_drvdata = { +static const struct odroidx2_drv_data odroidx2_drvdata = { .dapm_widgets = odroidx2_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(odroidx2_dapm_widgets), }; -struct odroidx2_drv_data odroidu3_drvdata = { +static const struct odroidx2_drv_data odroidu3_drvdata = { .dapm_widgets = odroidu3_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(odroidu3_dapm_widgets), }; From 6c7d1dfca999f58c65ed7b10c2f0945dd92db103 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 17 Aug 2014 16:18:20 +0200 Subject: [PATCH 028/251] ASoC: sh: Fix dma direction type dmaengine_prep_slave_single() expects a enum dma_transfer_direction and not a enum dma_data_direction. Since the integer representations of both DMA_TO_DEVICE and DMA_MEM_TO_DEV aswell as DMA_FROM_DEVICE and DMA_DEV_TO_MEM have the same value the code worked fine even though it was using the wrong type. Fixes the following warnings from sparse: sound/soc/sh/fsi.c:1307:42: warning: mixing different enum types sound/soc/sh/fsi.c:1307:42: int enum dma_data_direction versus sound/soc/sh/fsi.c:1307:42: int enum dma_transfer_direction Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/sh/fsi.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index c76344350e44..66fddec9543d 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -1297,9 +1297,14 @@ static int fsi_dma_transfer(struct fsi_priv *fsi, struct fsi_stream *io) struct snd_pcm_substream *substream = io->substream; struct dma_async_tx_descriptor *desc; int is_play = fsi_stream_is_play(fsi, io); - enum dma_data_direction dir = is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE; + enum dma_transfer_direction dir; int ret = -EIO; + if (is_play) + dir = DMA_MEM_TO_DEV; + else + dir = DMA_DEV_TO_MEM; + desc = dmaengine_prep_dma_cyclic(io->chan, substream->runtime->dma_addr, snd_pcm_lib_buffer_bytes(substream), From e8a70c25b809367fc314743e1ba1dbf0159398a7 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 17 Aug 2014 16:18:21 +0200 Subject: [PATCH 029/251] ASoC: samsung idma: Add proper annotation for casting iomem pointers It is not always possible to interchange iomem pointers with normal pointers, which why we have annotations for iomem pointers and warn when casting them to a normal pointer or vice versa. In this case the casting is fine and unfortunately necessary so add the proper annotations to tell code checkers that it is intentional. This silences the following warnings from sparse: sound/soc/samsung/idma.c:354:20: warning: incorrect type in argument 1 (different address spaces) expected void volatile [noderef] *addr got unsigned char *area sound/soc/samsung/idma.c:372:22: warning: cast removes address space of expression Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/samsung/idma.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/samsung/idma.c b/sound/soc/samsung/idma.c index db6cefa18017..0e8dd985fcb3 100644 --- a/sound/soc/samsung/idma.c +++ b/sound/soc/samsung/idma.c @@ -351,7 +351,7 @@ static void idma_free(struct snd_pcm *pcm) if (!buf->area) return; - iounmap(buf->area); + iounmap((void __iomem *)buf->area); buf->area = NULL; buf->addr = 0; @@ -369,7 +369,7 @@ static int preallocate_idma_buffer(struct snd_pcm *pcm, int stream) buf->dev.type = SNDRV_DMA_TYPE_CONTINUOUS; buf->addr = idma.lp_tx_addr; buf->bytes = idma_hardware.buffer_bytes_max; - buf->area = (unsigned char *)ioremap(buf->addr, buf->bytes); + buf->area = (unsigned char * __force)ioremap(buf->addr, buf->bytes); return 0; } From 6391fffb7b6099fae0e869229279d147c47f617a Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 17 Aug 2014 16:18:22 +0200 Subject: [PATCH 030/251] ASoC: ab8500-codec: Drop bank prefix from AB8500_GPIO_DIR4_REG register define The AB8500_GPIO_DIR4_REG register define has the bank for the register in the upper 8 bits and the register itself in the lower 8 bits. When passing it to abx500_{set,get}_register_interruptible() the upper bits get truncated which generates the following warning from sparse: sound/soc/codecs/ab8500-codec.c:1972:53: warning: cast truncates bits from constant value (1013 becomes 13) sound/soc/codecs/ab8500-codec.c:1980:53: warning: cast truncates bits from constant value (1013 becomes 13) The bank is passed separately to abx500_{set,get}_register_interruptible() so the code works fine as it is. Given that all users of AB8500_GPIO_DIR4_REG always truncate the upper 8 bits just remove them from the define. Also remove the unnecessary casts to u8. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/ab8500-codec.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c index 1fb4402bf72d..62cf231f34cb 100644 --- a/sound/soc/codecs/ab8500-codec.c +++ b/sound/soc/codecs/ab8500-codec.c @@ -56,8 +56,7 @@ #define GPIO31_DIR_OUTPUT 0x40 /* Macrocell register definitions */ -#define AB8500_CTRL3_REG 0x0200 -#define AB8500_GPIO_DIR4_REG 0x1013 +#define AB8500_GPIO_DIR4_REG 0x13 /* Bank AB8500_MISC */ /* Nr of FIR/IIR-coeff banks in ANC-block */ #define AB8500_NR_OF_ANC_COEFF_BANKS 2 @@ -1968,16 +1967,16 @@ static int ab8500_audio_setup_mics(struct snd_soc_codec *codec, dev_dbg(codec->dev, "%s: Enter.\n", __func__); /* Set DMic-clocks to outputs */ - status = abx500_get_register_interruptible(codec->dev, (u8)AB8500_MISC, - (u8)AB8500_GPIO_DIR4_REG, + status = abx500_get_register_interruptible(codec->dev, AB8500_MISC, + AB8500_GPIO_DIR4_REG, &value8); if (status < 0) return status; value = value8 | GPIO27_DIR_OUTPUT | GPIO29_DIR_OUTPUT | GPIO31_DIR_OUTPUT; status = abx500_set_register_interruptible(codec->dev, - (u8)AB8500_MISC, - (u8)AB8500_GPIO_DIR4_REG, + AB8500_MISC, + AB8500_GPIO_DIR4_REG, value); if (status < 0) return status; From 5f37671e004eeca017b93f6b26f2425acbb8d411 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Mon, 18 Aug 2014 16:38:39 +0800 Subject: [PATCH 031/251] ASoC: fsl-asoc-card: Fix build warning for maybe-uninitialized When build fsl-asoc-card as module, there is following error: sound/soc/fsl/fsl-asoc-card.c: In function 'fsl_asoc_card_probe': >> sound/soc/fsl/fsl-asoc-card.c:547:13: warning: 'asrc_np' may be used uninitialized in this function [-Wmaybe-uninitialized] of_node_put(asrc_np); ^ vim +/asrc_np +547 sound/soc/fsl/fsl-asoc-card.c 531 if (width == 24) 532 priv->asrc_format = SNDRV_PCM_FORMAT_S24_LE; 533 else 534 priv->asrc_format = SNDRV_PCM_FORMAT_S16_LE; 535 } 536 537 /* Finish card registering */ 538 platform_set_drvdata(pdev, priv); 539 snd_soc_card_set_drvdata(&priv->card, priv); 540 541 ret = devm_snd_soc_register_card(&pdev->dev, &priv->card); 542 if (ret) 543 dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); 544 545 fail: 546 of_node_put(codec_np); > 547 of_node_put(asrc_np); 548 of_node_put(cpu_np); 549 550 return ret; 551 } 552 553 static const struct of_device_id fsl_asoc_card_dt_ids[] = { 554 { .compatible = "fsl,imx-audio-cs42888", }, 555 { .compatible = "fsl,imx-audio-sgtl5000", }, Add 'asrc_fail' branch for error jump after asrc_np initialized. Reported-by: kbuild test robot Signed-off-by: Shengjiu Wang Signed-off-by: Mark Brown --- sound/soc/fsl/fsl-asoc-card.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c index cf3f1f47f1e8..007c772f3cef 100644 --- a/sound/soc/fsl/fsl-asoc-card.c +++ b/sound/soc/fsl/fsl-asoc-card.c @@ -469,7 +469,7 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) ret = fsl_asoc_card_audmux_init(np, priv); if (ret) { dev_err(&pdev->dev, "failed to init audmux\n"); - goto fail; + goto asrc_fail; } } else if (strstr(cpu_np->name, "esai")) { priv->cpu_priv.sysclk_id[1] = ESAI_HCKT_EXTAL; @@ -518,14 +518,14 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) if (ret) { dev_err(&pdev->dev, "failed to get output rate\n"); ret = -EINVAL; - goto fail; + goto asrc_fail; } ret = of_property_read_u32(asrc_np, "fsl,asrc-width", &width); if (ret) { dev_err(&pdev->dev, "failed to get output rate\n"); ret = -EINVAL; - goto fail; + goto asrc_fail; } if (width == 24) @@ -542,9 +542,10 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) if (ret) dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); +asrc_fail: + of_node_put(asrc_np); fail: of_node_put(codec_np); - of_node_put(asrc_np); of_node_put(cpu_np); return ret; From 499898d66d88cc626a2e01b02c3b819536bdf169 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Mon, 18 Aug 2014 16:38:40 +0800 Subject: [PATCH 032/251] ASoC: fsl: fsl-asoc-card: Select SND_SOC_IMX_AUDMUX Building kernel with SND_SOC_IMX_AUDMUX=n leads to the following error: sound/built-in.o: In function `fsl_asoc_card_probe': >> fsl-asoc-card.c:(.text+0x1467b5): undefined reference to `imx_audmux_v2_configure_port' >> fsl-asoc-card.c:(.text+0x1467d0): undefined reference to `imx_audmux_v2_configure_port' >> fsl-asoc-card.c:(.text+0x1467ed): undefined reference to `imx_audmux_v2_configure_port' >> fsl-asoc-card.c:(.text+0x146807): undefined reference to `imx_audmux_v2_configure_port' Update Kconfig to select SND_SOC_IMX_AUDMUX when SND_SOC_FSL_ASOC_CARD=y. Reported-by: kbuild test robot Signed-off-by: Shengjiu Wang Signed-off-by: Mark Brown --- sound/soc/fsl/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index fa90340dc13a..4698c01af684 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -62,6 +62,7 @@ config SND_SOC_FSL_UTILS config SND_SOC_FSL_ASOC_CARD tristate "Generic ASoC Sound Card with ASRC support" depends on OF && I2C + select SND_SOC_IMX_AUDMUX select SND_SOC_IMX_PCM_DMA select SND_SOC_FSL_ESAI select SND_SOC_FSL_SAI From 8ea21348868f37f5b2e6ebbaf336d2a415b2b9ff Mon Sep 17 00:00:00 2001 From: Xiubo Li Date: Mon, 18 Aug 2014 15:00:15 +0800 Subject: [PATCH 033/251] ASoC: simple-card: Fix the compile warning. sound/soc/generic/simple-card.c: In function simple_card_dai_link_of: sound/soc/generic/simple-card.c:198:10: warning: passing argument 3 of asoc_simple_card_sub_parse_of from incompatible pointer type [enabled by default] &dai_link->cpu_dai_name); ^ sound/soc/generic/simple-card.c:112:1: note: expected const struct device_node ** but argument is of type struct device_node ** asoc_simple_card_sub_parse_of(struct device_node *np, ^ sound/soc/generic/simple-card.c:229:10: warning: passing argument 3 of asoc_simple_card_sub_parse_of from incompatible pointer type [enabled by default] &dai_link->codec_dai_name); ^ sound/soc/generic/simple-card.c:112:1: note: expected const struct device_node ** but argument is of type struct device_node ** asoc_simple_card_sub_parse_of(struct device_node *np, ^ Since the asoc_simple_card_sub_parse_of() is used in simple-card module only, and the third argument is just used to get the node ponters address, so there is no need it must to be 'const' type. Signed-off-by: Xiubo Li Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 159e517fa09a..21b0ea24bc1d 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -111,7 +111,7 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) static int asoc_simple_card_sub_parse_of(struct device_node *np, struct asoc_simple_dai *dai, - const struct device_node **p_node, + struct device_node **p_node, const char **name) { struct device_node *node; From e9bd0224c130617d7d6037d3a405571c33b1e097 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 12 Aug 2014 11:54:36 +0200 Subject: [PATCH 034/251] ALSA: hda - Remove obsoleted snd_hda_check_board_config() & co The helper functions snd_hda_check_board_config() and snd_hda_check_board_codec_sid_config() are no longer used since the transition to the generic parser and all quirks have been replaced with fixups. Let's kill these dead codes. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 115 -------------------------------------- sound/pci/hda/hda_local.h | 6 -- 2 files changed, 121 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index ec6a7d0d1886..0aa2e1ed1dbc 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -4816,121 +4816,6 @@ int snd_hda_build_pcms(struct hda_bus *bus) } EXPORT_SYMBOL_GPL(snd_hda_build_pcms); -/** - * snd_hda_check_board_config - compare the current codec with the config table - * @codec: the HDA codec - * @num_configs: number of config enums - * @models: array of model name strings - * @tbl: configuration table, terminated by null entries - * - * Compares the modelname or PCI subsystem id of the current codec with the - * given configuration table. If a matching entry is found, returns its - * config value (supposed to be 0 or positive). - * - * If no entries are matching, the function returns a negative value. - */ -int snd_hda_check_board_config(struct hda_codec *codec, - int num_configs, const char * const *models, - const struct snd_pci_quirk *tbl) -{ - if (codec->modelname && models) { - int i; - for (i = 0; i < num_configs; i++) { - if (models[i] && - !strcmp(codec->modelname, models[i])) { - codec_info(codec, "model '%s' is selected\n", - models[i]); - return i; - } - } - } - - if (!codec->bus->pci || !tbl) - return -1; - - tbl = snd_pci_quirk_lookup(codec->bus->pci, tbl); - if (!tbl) - return -1; - if (tbl->value >= 0 && tbl->value < num_configs) { -#ifdef CONFIG_SND_DEBUG_VERBOSE - char tmp[10]; - const char *model = NULL; - if (models) - model = models[tbl->value]; - if (!model) { - sprintf(tmp, "#%d", tbl->value); - model = tmp; - } - codec_info(codec, "model '%s' is selected for config %x:%x (%s)\n", - model, tbl->subvendor, tbl->subdevice, - (tbl->name ? tbl->name : "Unknown device")); -#endif - return tbl->value; - } - return -1; -} -EXPORT_SYMBOL_GPL(snd_hda_check_board_config); - -/** - * snd_hda_check_board_codec_sid_config - compare the current codec - subsystem ID with the - config table - - This is important for Gateway notebooks with SB450 HDA Audio - where the vendor ID of the PCI device is: - ATI Technologies Inc SB450 HDA Audio [1002:437b] - and the vendor/subvendor are found only at the codec. - - * @codec: the HDA codec - * @num_configs: number of config enums - * @models: array of model name strings - * @tbl: configuration table, terminated by null entries - * - * Compares the modelname or PCI subsystem id of the current codec with the - * given configuration table. If a matching entry is found, returns its - * config value (supposed to be 0 or positive). - * - * If no entries are matching, the function returns a negative value. - */ -int snd_hda_check_board_codec_sid_config(struct hda_codec *codec, - int num_configs, const char * const *models, - const struct snd_pci_quirk *tbl) -{ - const struct snd_pci_quirk *q; - - /* Search for codec ID */ - for (q = tbl; q->subvendor; q++) { - unsigned int mask = 0xffff0000 | q->subdevice_mask; - unsigned int id = (q->subdevice | (q->subvendor << 16)) & mask; - if ((codec->subsystem_id & mask) == id) - break; - } - - if (!q->subvendor) - return -1; - - tbl = q; - - if (tbl->value >= 0 && tbl->value < num_configs) { -#ifdef CONFIG_SND_DEBUG_VERBOSE - char tmp[10]; - const char *model = NULL; - if (models) - model = models[tbl->value]; - if (!model) { - sprintf(tmp, "#%d", tbl->value); - model = tmp; - } - codec_info(codec, "model '%s' is selected for config %x:%x (%s)\n", - model, tbl->subvendor, tbl->subdevice, - (tbl->name ? tbl->name : "Unknown device")); -#endif - return tbl->value; - } - return -1; -} -EXPORT_SYMBOL_GPL(snd_hda_check_board_codec_sid_config); - /** * snd_hda_add_new_ctls - create controls from the array * @codec: the HDA codec diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 364bb413e02a..8a018d4cbe98 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -371,12 +371,6 @@ void snd_print_pcm_bits(int pcm, char *buf, int buflen); /* * Misc */ -int snd_hda_check_board_config(struct hda_codec *codec, int num_configs, - const char * const *modelnames, - const struct snd_pci_quirk *pci_list); -int snd_hda_check_board_codec_sid_config(struct hda_codec *codec, - int num_configs, const char * const *models, - const struct snd_pci_quirk *tbl); int snd_hda_add_new_ctls(struct hda_codec *codec, const struct snd_kcontrol_new *knew); From e52faba0f3a5520fc766e24520c10cb79fee2fac Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 12 Aug 2014 11:57:05 +0200 Subject: [PATCH 035/251] ALSA: hda - Remove obsoleted EXPORT_SYMBOL_HDA() macro Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index bbc5a1392c75..9c8820f21f94 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -687,6 +687,4 @@ snd_hda_codec_load_dsp_cleanup(struct hda_codec *codec, struct snd_dma_buffer *dmab) {} #endif -#define EXPORT_SYMBOL_HDA(sym) EXPORT_SYMBOL_GPL(sym) - #endif /* __SOUND_HDA_CODEC_H */ From f2a227cd3891266f1486a21aac86fa39b3abd093 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 18 Aug 2014 13:35:22 +0200 Subject: [PATCH 036/251] ALSA: hda/realtek - Optimize alc888_coef_init() Just a refactoring using the existing helper functions. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 91 +++++++++++++++-------------------- 1 file changed, 40 insertions(+), 51 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index d71270a3f73f..c9a7a2d237da 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -128,6 +128,43 @@ struct alc_spec { unsigned int coef0; }; +/* + * COEF access helper functions + */ + +static int alc_read_coefex_idx(struct hda_codec *codec, hda_nid_t nid, + unsigned int coef_idx) +{ + unsigned int val; + + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_COEF_INDEX, coef_idx); + val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PROC_COEF, 0); + return val; +} + +#define alc_read_coef_idx(codec, coef_idx) \ + alc_read_coefex_idx(codec, 0x20, coef_idx) + +static void alc_write_coefex_idx(struct hda_codec *codec, hda_nid_t nid, + unsigned int coef_idx, unsigned int coef_val) +{ + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_COEF_INDEX, coef_idx); + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PROC_COEF, coef_val); +} + +#define alc_write_coef_idx(codec, coef_idx, coef_val) \ + alc_write_coefex_idx(codec, 0x20, coef_idx, coef_val) + +/* a special bypass for COEF 0; read the cached value at the second time */ +static unsigned int alc_get_coef0(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + if (!spec->coef0) + spec->coef0 = alc_read_coef_idx(codec, 0); + return spec->coef0; +} + /* * Append the given mixer and verb elements for the later use * The mixer array is referred in build_controls(), and init_verbs are @@ -231,19 +268,12 @@ static void alc880_unsol_event(struct hda_codec *codec, unsigned int res) /* additional initialization for ALC888 variants */ static void alc888_coef_init(struct hda_codec *codec) { - unsigned int tmp; - - snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0); - tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0); - snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7); - if ((tmp & 0xf0) == 0x20) + if (alc_get_coef0(codec) == 0x20) /* alc888S-VC */ - snd_hda_codec_read(codec, 0x20, 0, - AC_VERB_SET_PROC_COEF, 0x830); + alc_write_coef_idx(codec, 7, 0x830); else /* alc888-VB */ - snd_hda_codec_read(codec, 0x20, 0, - AC_VERB_SET_PROC_COEF, 0x3030); + alc_write_coef_idx(codec, 7, 0x3030); } /* additional initialization for ALC889 variants */ @@ -586,47 +616,6 @@ static void alc_ssid_check(struct hda_codec *codec, const hda_nid_t *ports) } } -/* - * COEF access helper functions - */ - -static int alc_read_coefex_idx(struct hda_codec *codec, - hda_nid_t nid, - unsigned int coef_idx) -{ - unsigned int val; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_COEF_INDEX, - coef_idx); - val = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PROC_COEF, 0); - return val; -} - -#define alc_read_coef_idx(codec, coef_idx) \ - alc_read_coefex_idx(codec, 0x20, coef_idx) - -static void alc_write_coefex_idx(struct hda_codec *codec, hda_nid_t nid, - unsigned int coef_idx, - unsigned int coef_val) -{ - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_COEF_INDEX, - coef_idx); - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PROC_COEF, - coef_val); -} - -#define alc_write_coef_idx(codec, coef_idx, coef_val) \ - alc_write_coefex_idx(codec, 0x20, coef_idx, coef_val) - -/* a special bypass for COEF 0; read the cached value at the second time */ -static unsigned int alc_get_coef0(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - if (!spec->coef0) - spec->coef0 = alc_read_coef_idx(codec, 0); - return spec->coef0; -} - /* */ From 1687ccc8b2229d05c579924086e9b42ada9db888 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 18 Aug 2014 13:49:35 +0200 Subject: [PATCH 037/251] ALSA: hda/realtek - Use alc_write_coef_idx() in alc269_quanta_automake() Just a refactoring. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index c9a7a2d237da..75614e53e60c 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -3355,15 +3355,8 @@ static void alc269_quanta_automute(struct hda_codec *codec) { snd_hda_gen_update_outputs(codec); - snd_hda_codec_write(codec, 0x20, 0, - AC_VERB_SET_COEF_INDEX, 0x0c); - snd_hda_codec_write(codec, 0x20, 0, - AC_VERB_SET_PROC_COEF, 0x680); - - snd_hda_codec_write(codec, 0x20, 0, - AC_VERB_SET_COEF_INDEX, 0x0c); - snd_hda_codec_write(codec, 0x20, 0, - AC_VERB_SET_PROC_COEF, 0x480); + alc_write_coef_idx(codec, 0x0c, 0x680); + alc_write_coef_idx(codec, 0x0c, 0x480); } static void alc269_fixup_quanta_mute(struct hda_codec *codec, From 98b248839474293481905562ae38dc2d6558ef20 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 18 Aug 2014 13:47:50 +0200 Subject: [PATCH 038/251] ALSA: hda/realtek - Add alc_update_coef*_idx() helper ... and rewrite a few open codes with them. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 277 ++++++++++------------------------ 1 file changed, 82 insertions(+), 195 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 75614e53e60c..fe041fa4f2c3 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -155,6 +155,20 @@ static void alc_write_coefex_idx(struct hda_codec *codec, hda_nid_t nid, #define alc_write_coef_idx(codec, coef_idx, coef_val) \ alc_write_coefex_idx(codec, 0x20, coef_idx, coef_val) +static void alc_update_coefex_idx(struct hda_codec *codec, hda_nid_t nid, + unsigned int coef_idx, unsigned int mask, + unsigned int bits_set) +{ + unsigned int val = alc_read_coefex_idx(codec, nid, coef_idx); + + if (val != -1) + alc_write_coefex_idx(codec, nid, coef_idx, + (val & ~mask) | bits_set); +} + +#define alc_update_coef_idx(codec, coef_idx, mask, bits_set) \ + alc_update_coefex_idx(codec, 0x20, coef_idx, mask, bits_set) + /* a special bypass for COEF 0; read the cached value at the second time */ static unsigned int alc_get_coef0(struct hda_codec *codec) { @@ -210,20 +224,10 @@ static const struct hda_verb alc_gpio3_init_verbs[] = { static void alc_fix_pll(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - unsigned int val; - if (!spec->pll_nid) - return; - snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX, - spec->pll_coef_idx); - val = snd_hda_codec_read(codec, spec->pll_nid, 0, - AC_VERB_GET_PROC_COEF, 0); - if (val == -1) - return; - snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX, - spec->pll_coef_idx); - snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_PROC_COEF, - val & ~(1 << spec->pll_coef_bit)); + if (spec->pll_nid) + alc_update_coefex_idx(codec, spec->pll_nid, spec->pll_coef_idx, + 1 << spec->pll_coef_bit, 0); } static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid, @@ -279,12 +283,7 @@ static void alc888_coef_init(struct hda_codec *codec) /* additional initialization for ALC889 variants */ static void alc889_coef_init(struct hda_codec *codec) { - unsigned int tmp; - - snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7); - tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0); - snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7); - snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF, tmp|0x2010); + alc_update_coef_idx(codec, 7, 0, 0x2010); } /* turn on/off EAPD control (only if available) */ @@ -325,8 +324,6 @@ static void alc_eapd_shutup(struct hda_codec *codec) /* generic EAPD initialization */ static void alc_auto_init_amp(struct hda_codec *codec, int type) { - unsigned int tmp; - alc_auto_setup_eapd(codec, true); switch (type) { case ALC_INIT_GPIO1: @@ -341,15 +338,7 @@ static void alc_auto_init_amp(struct hda_codec *codec, int type) case ALC_INIT_DEFAULT: switch (codec->vendor_id) { case 0x10ec0260: - snd_hda_codec_write(codec, 0x1a, 0, - AC_VERB_SET_COEF_INDEX, 7); - tmp = snd_hda_codec_read(codec, 0x1a, 0, - AC_VERB_GET_PROC_COEF, 0); - snd_hda_codec_write(codec, 0x1a, 0, - AC_VERB_SET_COEF_INDEX, 7); - snd_hda_codec_write(codec, 0x1a, 0, - AC_VERB_SET_PROC_COEF, - tmp | 0x2010); + alc_update_coefex_idx(codec, 0x1a, 7, 0, 0x2010); break; case 0x10ec0262: case 0x10ec0880: @@ -366,15 +355,7 @@ static void alc_auto_init_amp(struct hda_codec *codec, int type) #if 0 /* XXX: This may cause the silent output on speaker on some machines */ case 0x10ec0267: case 0x10ec0268: - snd_hda_codec_write(codec, 0x20, 0, - AC_VERB_SET_COEF_INDEX, 7); - tmp = snd_hda_codec_read(codec, 0x20, 0, - AC_VERB_GET_PROC_COEF, 0); - snd_hda_codec_write(codec, 0x20, 0, - AC_VERB_SET_COEF_INDEX, 7); - snd_hda_codec_write(codec, 0x20, 0, - AC_VERB_SET_PROC_COEF, - tmp | 0x3000); + alc_update_coef_idx(codec, 7, 0, 0x3000); break; #endif /* XXX */ } @@ -2504,13 +2485,7 @@ static int patch_alc262(struct hda_codec *codec) /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is * under-run */ - { - int tmp; - snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7); - tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0); - snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7); - snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80); - } + alc_update_coefex_idx(codec, 0x1a, 7, 0, 0x80); #endif alc_fix_pll_init(codec, 0x20, 0x0a, 10); @@ -2796,14 +2771,7 @@ static void alc286_shutup(struct hda_codec *codec) static void alc269vb_toggle_power_output(struct hda_codec *codec, int power_up) { - int val = alc_read_coef_idx(codec, 0x04); - if (val == -1) - return; - if (power_up) - val |= 1 << 11; - else - val &= ~(1 << 11); - alc_write_coef_idx(codec, 0x04, val); + alc_update_coef_idx(codec, 0x04, 1 << 11, power_up ? (1 << 11) : 0); } static void alc269_shutup(struct hda_codec *codec) @@ -2821,8 +2789,6 @@ static void alc269_shutup(struct hda_codec *codec) static void alc282_restore_default_value(struct hda_codec *codec) { - int val; - /* Power Down Control */ alc_write_coef_idx(codec, 0x03, 0x0002); /* FIFO and filter clock */ @@ -2830,11 +2796,9 @@ static void alc282_restore_default_value(struct hda_codec *codec) /* DMIC control */ alc_write_coef_idx(codec, 0x07, 0x0200); /* Analog clock */ - val = alc_read_coef_idx(codec, 0x06); - alc_write_coef_idx(codec, 0x06, (val & ~0x00f0) | 0x0); + alc_update_coef_idx(codec, 0x06, 0x00f0, 0); /* JD */ - val = alc_read_coef_idx(codec, 0x08); - alc_write_coef_idx(codec, 0x08, (val & ~0xfffc) | 0x0c2c); + alc_update_coef_idx(codec, 0x08, 0xfffc, 0x0c2c); /* JD offset1 */ alc_write_coef_idx(codec, 0x0a, 0xcccc); /* JD offset2 */ @@ -2842,27 +2806,21 @@ static void alc282_restore_default_value(struct hda_codec *codec) /* LDO1/2/3, DAC/ADC */ alc_write_coef_idx(codec, 0x0e, 0x6e00); /* JD */ - val = alc_read_coef_idx(codec, 0x0f); - alc_write_coef_idx(codec, 0x0f, (val & ~0xf800) | 0x1000); + alc_update_coef_idx(codec, 0x0f, 0xf800, 0x1000); /* Capless */ - val = alc_read_coef_idx(codec, 0x10); - alc_write_coef_idx(codec, 0x10, (val & ~0xfc00) | 0x0c00); + alc_update_coef_idx(codec, 0x10, 0xfc00, 0x0c00); /* Class D test 4 */ alc_write_coef_idx(codec, 0x6f, 0x0); /* IO power down directly */ - val = alc_read_coef_idx(codec, 0x0c); - alc_write_coef_idx(codec, 0x0c, (val & ~0xfe00) | 0x0); + alc_update_coef_idx(codec, 0x0c, 0xfe00, 0); /* ANC */ alc_write_coef_idx(codec, 0x34, 0xa0c0); /* AGC MUX */ - val = alc_read_coef_idx(codec, 0x16); - alc_write_coef_idx(codec, 0x16, (val & ~0x0008) | 0x0); + alc_update_coef_idx(codec, 0x16, 0x0008, 0); /* DAC simple content protection */ - val = alc_read_coef_idx(codec, 0x1d); - alc_write_coef_idx(codec, 0x1d, (val & ~0x00e0) | 0x0); + alc_update_coef_idx(codec, 0x1d, 0x00e0, 0); /* ADC simple content protection */ - val = alc_read_coef_idx(codec, 0x1f); - alc_write_coef_idx(codec, 0x1f, (val & ~0x00e0) | 0x0); + alc_update_coef_idx(codec, 0x1f, 0x00e0, 0); /* DAC ADC Zero Detection */ alc_write_coef_idx(codec, 0x21, 0x8804); /* PLL */ @@ -2876,20 +2834,17 @@ static void alc282_restore_default_value(struct hda_codec *codec) /* capless control 5 */ alc_write_coef_idx(codec, 0x6b, 0x0); /* class D test 2 */ - val = alc_read_coef_idx(codec, 0x6d); - alc_write_coef_idx(codec, 0x6d, (val & ~0x0fff) | 0x0900); + alc_update_coef_idx(codec, 0x6d, 0x0fff, 0x0900); /* class D test 3 */ alc_write_coef_idx(codec, 0x6e, 0x110a); /* class D test 5 */ - val = alc_read_coef_idx(codec, 0x70); - alc_write_coef_idx(codec, 0x70, (val & ~0x00f8) | 0x00d8); + alc_update_coef_idx(codec, 0x70, 0x00f8, 0x00d8); /* class D test 6 */ alc_write_coef_idx(codec, 0x71, 0x0014); /* classD OCP */ alc_write_coef_idx(codec, 0x72, 0xc2ba); /* classD pure DC test */ - val = alc_read_coef_idx(codec, 0x77); - alc_write_coef_idx(codec, 0x77, (val & ~0x0f80) | 0x0); + alc_update_coef_idx(codec, 0x77, 0x0f80, 0); /* Class D amp control */ alc_write_coef_idx(codec, 0x6c, 0xfc06); } @@ -2969,8 +2924,6 @@ static void alc282_shutup(struct hda_codec *codec) static void alc283_restore_default_value(struct hda_codec *codec) { - int val; - /* Power Down Control */ alc_write_coef_idx(codec, 0x03, 0x0002); /* FIFO and filter clock */ @@ -2978,11 +2931,9 @@ static void alc283_restore_default_value(struct hda_codec *codec) /* DMIC control */ alc_write_coef_idx(codec, 0x07, 0x0200); /* Analog clock */ - val = alc_read_coef_idx(codec, 0x06); - alc_write_coef_idx(codec, 0x06, (val & ~0x00f0) | 0x0); + alc_update_coef_idx(codec, 0x06, 0x00f0, 0); /* JD */ - val = alc_read_coef_idx(codec, 0x08); - alc_write_coef_idx(codec, 0x08, (val & ~0xfffc) | 0x0c2c); + alc_update_coef_idx(codec, 0x08, 0xfffc, 0x0c2c); /* JD offset1 */ alc_write_coef_idx(codec, 0x0a, 0xcccc); /* JD offset2 */ @@ -2990,27 +2941,21 @@ static void alc283_restore_default_value(struct hda_codec *codec) /* LDO1/2/3, DAC/ADC */ alc_write_coef_idx(codec, 0x0e, 0x6fc0); /* JD */ - val = alc_read_coef_idx(codec, 0x0f); - alc_write_coef_idx(codec, 0x0f, (val & ~0xf800) | 0x1000); + alc_update_coef_idx(codec, 0x0f, 0xf800, 0x1000); /* Capless */ - val = alc_read_coef_idx(codec, 0x10); - alc_write_coef_idx(codec, 0x10, (val & ~0xfc00) | 0x0c00); + alc_update_coef_idx(codec, 0x10, 0xfc00, 0x0c00); /* Class D test 4 */ alc_write_coef_idx(codec, 0x3a, 0x0); /* IO power down directly */ - val = alc_read_coef_idx(codec, 0x0c); - alc_write_coef_idx(codec, 0x0c, (val & ~0xfe00) | 0x0); + alc_update_coef_idx(codec, 0x0c, 0xfe00, 0x0); /* ANC */ alc_write_coef_idx(codec, 0x22, 0xa0c0); /* AGC MUX */ - val = alc_read_coefex_idx(codec, 0x53, 0x01); - alc_write_coefex_idx(codec, 0x53, 0x01, (val & ~0x000f) | 0x0008); + alc_update_coefex_idx(codec, 0x53, 0x01, 0x000f, 0x0008); /* DAC simple content protection */ - val = alc_read_coef_idx(codec, 0x1d); - alc_write_coef_idx(codec, 0x1d, (val & ~0x00e0) | 0x0); + alc_update_coef_idx(codec, 0x1d, 0x00e0, 0x0); /* ADC simple content protection */ - val = alc_read_coef_idx(codec, 0x1f); - alc_write_coef_idx(codec, 0x1f, (val & ~0x00e0) | 0x0); + alc_update_coef_idx(codec, 0x1f, 0x00e0, 0x0); /* DAC ADC Zero Detection */ alc_write_coef_idx(codec, 0x21, 0x8804); /* PLL */ @@ -3024,28 +2969,23 @@ static void alc283_restore_default_value(struct hda_codec *codec) /* capless control 5 */ alc_write_coef_idx(codec, 0x36, 0x0); /* class D test 2 */ - val = alc_read_coef_idx(codec, 0x38); - alc_write_coef_idx(codec, 0x38, (val & ~0x0fff) | 0x0900); + alc_update_coef_idx(codec, 0x38, 0x0fff, 0x0900); /* class D test 3 */ alc_write_coef_idx(codec, 0x39, 0x110a); /* class D test 5 */ - val = alc_read_coef_idx(codec, 0x3b); - alc_write_coef_idx(codec, 0x3b, (val & ~0x00f8) | 0x00d8); + alc_update_coef_idx(codec, 0x3b, 0x00f8, 0x00d8); /* class D test 6 */ alc_write_coef_idx(codec, 0x3c, 0x0014); /* classD OCP */ alc_write_coef_idx(codec, 0x3d, 0xc2ba); /* classD pure DC test */ - val = alc_read_coef_idx(codec, 0x42); - alc_write_coef_idx(codec, 0x42, (val & ~0x0f80) | 0x0); + alc_update_coef_idx(codec, 0x42, 0x0f80, 0x0); /* test mode */ alc_write_coef_idx(codec, 0x49, 0x0); /* Class D DC enable */ - val = alc_read_coef_idx(codec, 0x40); - alc_write_coef_idx(codec, 0x40, (val & ~0xf800) | 0x9800); + alc_update_coef_idx(codec, 0x40, 0xf800, 0x9800); /* DC offset */ - val = alc_read_coef_idx(codec, 0x42); - alc_write_coef_idx(codec, 0x42, (val & ~0xf000) | 0x2000); + alc_update_coef_idx(codec, 0x42, 0xf000, 0x2000); /* Class D amp control */ alc_write_coef_idx(codec, 0x37, 0xfc06); } @@ -3055,7 +2995,6 @@ static void alc283_init(struct hda_codec *codec) struct alc_spec *spec = codec->spec; hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0]; bool hp_pin_sense; - int val; if (!spec->gen.autocfg.hp_outs) { if (spec->gen.autocfg.line_out_type == AC_JACK_HP_OUT) @@ -3085,8 +3024,7 @@ static void alc283_init(struct hda_codec *codec) msleep(85); /* Index 0x46 Combo jack auto switch control 2 */ /* 3k pull low control for Headset jack. */ - val = alc_read_coef_idx(codec, 0x46); - alc_write_coef_idx(codec, 0x46, val & ~(3 << 12)); + alc_update_coef_idx(codec, 0x46, 3 << 12, 0); /* Headphone capless set to normal mode */ alc_write_coef_idx(codec, 0x43, 0x9614); } @@ -3096,7 +3034,6 @@ static void alc283_shutup(struct hda_codec *codec) struct alc_spec *spec = codec->spec; hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0]; bool hp_pin_sense; - int val; if (!spec->gen.autocfg.hp_outs) { if (spec->gen.autocfg.line_out_type == AC_JACK_HP_OUT) @@ -3121,8 +3058,7 @@ static void alc283_shutup(struct hda_codec *codec) snd_hda_codec_write(codec, hp_pin, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0); - val = alc_read_coef_idx(codec, 0x46); - alc_write_coef_idx(codec, 0x46, val | (3 << 12)); + alc_update_coef_idx(codec, 0x46, 0, 3 << 12); if (hp_pin_sense) msleep(100); @@ -3285,12 +3221,8 @@ static void alc269_fixup_pincfg_no_hp_to_lineout(struct hda_codec *codec, static void alc269_fixup_hweq(struct hda_codec *codec, const struct hda_fixup *fix, int action) { - int coef; - - if (action != HDA_FIXUP_ACT_INIT) - return; - coef = alc_read_coef_idx(codec, 0x1e); - alc_write_coef_idx(codec, 0x1e, coef | 0x80); + if (action == HDA_FIXUP_ACT_INIT) + alc_update_coef_idx(codec, 0x1e, 0, 0x80); } static void alc269_fixup_headset_mic(struct hda_codec *codec, @@ -3338,17 +3270,13 @@ static void alc269_fixup_pcm_44k(struct hda_codec *codec, static void alc269_fixup_stereo_dmic(struct hda_codec *codec, const struct hda_fixup *fix, int action) { - int coef; - - if (action != HDA_FIXUP_ACT_INIT) - return; /* The digital-mic unit sends PDM (differential signal) instead of * the standard PCM, thus you can't record a valid mono stream as is. * Below is a workaround specific to ALC269 to control the dmic * signal source as mono. */ - coef = alc_read_coef_idx(codec, 0x07); - alc_write_coef_idx(codec, 0x07, coef | 0x80); + if (action == HDA_FIXUP_ACT_INIT) + alc_update_coef_idx(codec, 0x07, 0, 0x80); } static void alc269_quanta_automute(struct hda_codec *codec) @@ -3602,8 +3530,6 @@ static void alc269_fixup_hp_line1_mic1_led(struct hda_codec *codec, static void alc_headset_mode_unplugged(struct hda_codec *codec) { - int val; - switch (codec->vendor_id) { case 0x10ec0255: /* LDO and MISC control */ @@ -3611,8 +3537,7 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec) /* UAJ function set to menual mode */ alc_write_coef_idx(codec, 0x45, 0xd089); /* Direct Drive HP Amp control(Set to verb control)*/ - val = alc_read_coefex_idx(codec, 0x57, 0x05); - alc_write_coefex_idx(codec, 0x57, 0x05, val & ~(1<<14)); + alc_update_coefex_idx(codec, 0x57, 0x05, 1<<14, 0); /* Set MIC2 Vref gate with HP */ alc_write_coef_idx(codec, 0x06, 0x6104); /* Direct Drive HP Amp control */ @@ -3622,8 +3547,7 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec) case 0x10ec0283: alc_write_coef_idx(codec, 0x1b, 0x0c0b); alc_write_coef_idx(codec, 0x45, 0xc429); - val = alc_read_coef_idx(codec, 0x35); - alc_write_coef_idx(codec, 0x35, val & 0xbfff); + alc_update_coef_idx(codec, 0x35, 0x4000, 0); alc_write_coef_idx(codec, 0x06, 0x2104); alc_write_coef_idx(codec, 0x1a, 0x0001); alc_write_coef_idx(codec, 0x26, 0x0004); @@ -3637,22 +3561,17 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec) break; case 0x10ec0293: /* SET Line1 JD to 0 */ - val = alc_read_coef_idx(codec, 0x10); - alc_write_coef_idx(codec, 0x10, (val & ~(7<<8)) | 6<<8); + alc_update_coef_idx(codec, 0x10, 7<<8, 6<<8); /* SET charge pump by verb */ - val = alc_read_coefex_idx(codec, 0x57, 0x05); - alc_write_coefex_idx(codec, 0x57, 0x05, (val & ~(1<<15|1<<13)) | 0x0); + alc_update_coefex_idx(codec, 0x57, 0x05, 1<<15|1<<13, 0x0); /* SET EN_OSW to 1 */ - val = alc_read_coefex_idx(codec, 0x57, 0x03); - alc_write_coefex_idx(codec, 0x57, 0x03, (val & ~(1<<10)) | (1<<10) ); + alc_update_coefex_idx(codec, 0x57, 0x03, 1<<10, 1<<10); /* Combo JD gating with LINE1-VREFO */ - val = alc_read_coef_idx(codec, 0x1a); - alc_write_coef_idx(codec, 0x1a, (val & ~(1<<3)) | (1<<3)); + alc_update_coef_idx(codec, 0x1a, 1<<3, 1<<3); /* Set to TRS type */ alc_write_coef_idx(codec, 0x45, 0xc429); /* Combo Jack auto detect */ - val = alc_read_coef_idx(codec, 0x4a); - alc_write_coef_idx(codec, 0x4a, (val & 0xfff0) | 0x000e); + alc_update_coef_idx(codec, 0x4a, 0x000f, 0x000e); break; case 0x10ec0668: alc_write_coef_idx(codec, 0x15, 0x0d40); @@ -3666,8 +3585,6 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec) static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin, hda_nid_t mic_pin) { - int val; - switch (codec->vendor_id) { case 0x10ec0255: alc_write_coef_idx(codec, 0x45, 0xc489); @@ -3681,8 +3598,7 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin, case 0x10ec0283: alc_write_coef_idx(codec, 0x45, 0xc429); snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); - val = alc_read_coef_idx(codec, 0x35); - alc_write_coef_idx(codec, 0x35, val | 1<<14); + alc_update_coef_idx(codec, 0x35, 0, 1<<14); alc_write_coef_idx(codec, 0x06, 0x2100); alc_write_coef_idx(codec, 0x1a, 0x0021); alc_write_coef_idx(codec, 0x26, 0x008c); @@ -3698,14 +3614,11 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin, alc_write_coef_idx(codec, 0x45, 0xc429); snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); /* SET charge pump by verb */ - val = alc_read_coefex_idx(codec, 0x57, 0x05); - alc_write_coefex_idx(codec, 0x57, 0x05, (val & ~(1<<15|1<<13)) | (1<<15|1<<13)); + alc_update_coefex_idx(codec, 0x57, 0x05, 0, 1<<15|1<<13); /* SET EN_OSW to 0 */ - val = alc_read_coefex_idx(codec, 0x57, 0x03); - alc_write_coefex_idx(codec, 0x57, 0x03, (val & ~(1<<10)) | 0x0); + alc_update_coefex_idx(codec, 0x57, 0x03, 1<<10, 0); /* Combo JD gating without LINE1-VREFO */ - val = alc_read_coef_idx(codec, 0x1a); - alc_write_coef_idx(codec, 0x1a, (val & ~(1<<3)) | 0x0); + alc_update_coef_idx(codec, 0x1a, 1<<3, 0); snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); break; case 0x10ec0668: @@ -3713,8 +3626,7 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin, snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); alc_write_coef_idx(codec, 0xb7, 0x802b); alc_write_coef_idx(codec, 0xb5, 0x1040); - val = alc_read_coef_idx(codec, 0xc3); - alc_write_coef_idx(codec, 0xc3, val | 1<<12); + alc_update_coef_idx(codec, 0xc3, 0, 1<<12); snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); break; } @@ -3723,8 +3635,6 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin, static void alc_headset_mode_default(struct hda_codec *codec) { - int val; - switch (codec->vendor_id) { case 0x10ec0255: alc_write_coef_idx(codec, 0x45, 0xc089); @@ -3745,13 +3655,11 @@ static void alc_headset_mode_default(struct hda_codec *codec) break; case 0x10ec0293: /* Combo Jack auto detect */ - val = alc_read_coef_idx(codec, 0x4a); - alc_write_coef_idx(codec, 0x4a, (val & 0xfff0) | 0x000e); + alc_update_coef_idx(codec, 0x4a, 0x000f, 0x000e); /* Set to TRS type */ alc_write_coef_idx(codec, 0x45, 0xC429); /* Combo JD gating without LINE1-VREFO */ - val = alc_read_coef_idx(codec, 0x1a); - alc_write_coef_idx(codec, 0x1a, (val & ~(1<<3)) | 0x0); + alc_update_coef_idx(codec, 0x1a, 1<<3, 0); break; case 0x10ec0668: alc_write_coef_idx(codec, 0x11, 0x0041); @@ -3765,8 +3673,6 @@ static void alc_headset_mode_default(struct hda_codec *codec) /* Iphone type */ static void alc_headset_mode_ctia(struct hda_codec *codec) { - int val; - switch (codec->vendor_id) { case 0x10ec0255: /* Set to CTIA type */ @@ -3789,8 +3695,7 @@ static void alc_headset_mode_ctia(struct hda_codec *codec) /* Set to ctia type */ alc_write_coef_idx(codec, 0x45, 0xd429); /* SET Line1 JD to 1 */ - val = alc_read_coef_idx(codec, 0x10); - alc_write_coef_idx(codec, 0x10, (val & ~(7<<8)) | 7<<8); + alc_update_coef_idx(codec, 0x10, 7<<8, 7<<8); break; case 0x10ec0668: alc_write_coef_idx(codec, 0x11, 0x0001); @@ -3804,8 +3709,6 @@ static void alc_headset_mode_ctia(struct hda_codec *codec) /* Nokia type */ static void alc_headset_mode_omtp(struct hda_codec *codec) { - int val; - switch (codec->vendor_id) { case 0x10ec0255: /* Set to OMTP Type */ @@ -3828,8 +3731,7 @@ static void alc_headset_mode_omtp(struct hda_codec *codec) /* Set to omtp type */ alc_write_coef_idx(codec, 0x45, 0xe429); /* SET Line1 JD to 1 */ - val = alc_read_coef_idx(codec, 0x10); - alc_write_coef_idx(codec, 0x10, (val & ~(7<<8)) | 7<<8); + alc_update_coef_idx(codec, 0x10, 7<<8, 7<<8); break; case 0x10ec0668: alc_write_coef_idx(codec, 0x11, 0x0001); @@ -3871,8 +3773,7 @@ static void alc_determine_headset_type(struct hda_codec *codec) break; case 0x10ec0293: /* Combo Jack auto detect */ - val = alc_read_coef_idx(codec, 0x4a); - alc_write_coef_idx(codec, 0x4a, (val & 0xfff0) | 0x0008); + alc_update_coef_idx(codec, 0x4a, 0x000f, 0x0008); /* Set to ctia type */ alc_write_coef_idx(codec, 0x45, 0xD429); msleep(300); @@ -4118,10 +4019,8 @@ static void alc_fixup_headset_mode_alc668(struct hda_codec *codec, const struct hda_fixup *fix, int action) { if (action == HDA_FIXUP_ACT_PRE_PROBE) { - int val; alc_write_coef_idx(codec, 0xc4, 0x8000); - val = alc_read_coef_idx(codec, 0xc2); - alc_write_coef_idx(codec, 0xc2, val & 0xfe); + alc_update_coef_idx(codec, 0xc2, ~0xfe, 0); snd_hda_set_pin_ctl_cache(codec, 0x18, 0); } alc_fixup_headset_mode(codec, fix, action); @@ -4217,7 +4116,6 @@ static void alc283_fixup_chromebook(struct hda_codec *codec, const struct hda_fixup *fix, int action) { struct alc_spec *spec = codec->spec; - int val; switch (action) { case HDA_FIXUP_ACT_PRE_PROBE: @@ -4228,11 +4126,9 @@ static void alc283_fixup_chromebook(struct hda_codec *codec, case HDA_FIXUP_ACT_INIT: /* MIC2-VREF control */ /* Set to manual mode */ - val = alc_read_coef_idx(codec, 0x06); - alc_write_coef_idx(codec, 0x06, val & ~0x000c); + alc_update_coef_idx(codec, 0x06, 0x000c, 0); /* Enable Line1 input control by verb */ - val = alc_read_coef_idx(codec, 0x1a); - alc_write_coef_idx(codec, 0x1a, val | (1 << 4)); + alc_update_coef_idx(codec, 0x1a, 0, 1 << 4); break; } } @@ -4241,7 +4137,6 @@ static void alc283_fixup_sense_combo_jack(struct hda_codec *codec, const struct hda_fixup *fix, int action) { struct alc_spec *spec = codec->spec; - int val; switch (action) { case HDA_FIXUP_ACT_PRE_PROBE: @@ -4250,8 +4145,7 @@ static void alc283_fixup_sense_combo_jack(struct hda_codec *codec, case HDA_FIXUP_ACT_INIT: /* MIC2-VREF control */ /* Set to manual mode */ - val = alc_read_coef_idx(codec, 0x06); - alc_write_coef_idx(codec, 0x06, val & ~0x000c); + alc_update_coef_idx(codec, 0x06, 0x000c, 0); break; } } @@ -5304,10 +5198,8 @@ static void alc269_fill_coef(struct hda_codec *codec) } if ((alc_get_coef0(codec) & 0x00ff) == 0x017) { - val = alc_read_coef_idx(codec, 0x04); /* Power up output pin */ - if (val != -1) - alc_write_coef_idx(codec, 0x04, val | (1<<11)); + alc_update_coef_idx(codec, 0x04, 0, 1<<11); } if ((alc_get_coef0(codec) & 0x00ff) == 0x018) { @@ -5323,13 +5215,11 @@ static void alc269_fill_coef(struct hda_codec *codec) } } - val = alc_read_coef_idx(codec, 0xd); /* Class D */ - if (val != -1) - alc_write_coef_idx(codec, 0xd, val | (1<<14)); + /* Class D */ + alc_update_coef_idx(codec, 0xd, 0, 1<<14); - val = alc_read_coef_idx(codec, 0x4); /* HP */ - if (val != -1) - alc_write_coef_idx(codec, 0x4, val | (1<<11)); + /* HP */ + alc_update_coef_idx(codec, 0x4, 0, 1<<11); } /* @@ -6209,16 +6099,14 @@ static const struct snd_hda_pin_quirk alc662_pin_fixup_tbl[] = { static void alc662_fill_coef(struct hda_codec *codec) { - int val, coef; + int coef; coef = alc_get_coef0(codec); switch (codec->vendor_id) { case 0x10ec0662: - if ((coef & 0x00f0) == 0x0030) { - val = alc_read_coef_idx(codec, 0x4); /* EAPD Ctrl */ - alc_write_coef_idx(codec, 0x4, val & ~(1<<10)); - } + if ((coef & 0x00f0) == 0x0030) + alc_update_coef_idx(codec, 0x4, 1<<10, 0); /* EAPD Ctrl */ break; case 0x10ec0272: case 0x10ec0273: @@ -6227,8 +6115,7 @@ static void alc662_fill_coef(struct hda_codec *codec) case 0x10ec0670: case 0x10ec0671: case 0x10ec0672: - val = alc_read_coef_idx(codec, 0xd); /* EAPD Ctrl */ - alc_write_coef_idx(codec, 0xd, val | (1<<14)); + alc_update_coef_idx(codec, 0xd, 0, 1<<14); /* EAPD Ctrl */ break; } } From 54db6c3949359ee35e9addb02506fca431721ef0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 18 Aug 2014 15:11:19 +0200 Subject: [PATCH 039/251] ALSA: hda/realtek - Use tables for batch COEF writes/updtes There are many codes doing writes or updates COEF verbs sequentially in a batch. Rewrite such open codes with tables for optimization. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 559 +++++++++++++++++++--------------- 1 file changed, 314 insertions(+), 245 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index fe041fa4f2c3..e0fff47b5740 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -179,6 +179,32 @@ static unsigned int alc_get_coef0(struct hda_codec *codec) return spec->coef0; } +/* coef writes/updates batch */ +struct coef_fw { + unsigned char nid; + unsigned char idx; + unsigned short mask; + unsigned short val; +}; + +#define UPDATE_COEFEX(_nid, _idx, _mask, _val) \ + { .nid = (_nid), .idx = (_idx), .mask = (_mask), .val = (_val) } +#define WRITE_COEFEX(_nid, _idx, _val) UPDATE_COEFEX(_nid, _idx, -1, _val) +#define WRITE_COEF(_idx, _val) WRITE_COEFEX(0x20, _idx, _val) +#define UPDATE_COEF(_idx, _mask, _val) UPDATE_COEFEX(0x20, _idx, _mask, _val) + +static void alc_process_coef_fw(struct hda_codec *codec, + const struct coef_fw *fw) +{ + for (; fw->nid; fw++) { + if (fw->mask == (unsigned short)-1) + alc_write_coefex_idx(codec, fw->nid, fw->idx, fw->val); + else + alc_update_coefex_idx(codec, fw->nid, fw->idx, + fw->mask, fw->val); + } +} + /* * Append the given mixer and verb elements for the later use * The mixer array is referred in build_controls(), and init_verbs are @@ -2787,66 +2813,42 @@ static void alc269_shutup(struct hda_codec *codec) snd_hda_shutup_pins(codec); } +static struct coef_fw alc282_coefs[] = { + WRITE_COEF(0x03, 0x0002), /* Power Down Control */ + WRITE_COEF(0x05, 0x0700), /* FIFO and filter clock */ + WRITE_COEF(0x07, 0x0200), /* DMIC control */ + UPDATE_COEF(0x06, 0x00f0, 0), /* Analog clock */ + UPDATE_COEF(0x08, 0xfffc, 0x0c2c), /* JD */ + WRITE_COEF(0x0a, 0xcccc), /* JD offset1 */ + WRITE_COEF(0x0b, 0xcccc), /* JD offset2 */ + WRITE_COEF(0x0e, 0x6e00), /* LDO1/2/3, DAC/ADC */ + UPDATE_COEF(0x0f, 0xf800, 0x1000), /* JD */ + UPDATE_COEF(0x10, 0xfc00, 0x0c00), /* Capless */ + WRITE_COEF(0x6f, 0x0), /* Class D test 4 */ + UPDATE_COEF(0x0c, 0xfe00, 0), /* IO power down directly */ + WRITE_COEF(0x34, 0xa0c0), /* ANC */ + UPDATE_COEF(0x16, 0x0008, 0), /* AGC MUX */ + UPDATE_COEF(0x1d, 0x00e0, 0), /* DAC simple content protection */ + UPDATE_COEF(0x1f, 0x00e0, 0), /* ADC simple content protection */ + WRITE_COEF(0x21, 0x8804), /* DAC ADC Zero Detection */ + WRITE_COEF(0x63, 0x2902), /* PLL */ + WRITE_COEF(0x68, 0xa080), /* capless control 2 */ + WRITE_COEF(0x69, 0x3400), /* capless control 3 */ + WRITE_COEF(0x6a, 0x2f3e), /* capless control 4 */ + WRITE_COEF(0x6b, 0x0), /* capless control 5 */ + UPDATE_COEF(0x6d, 0x0fff, 0x0900), /* class D test 2 */ + WRITE_COEF(0x6e, 0x110a), /* class D test 3 */ + UPDATE_COEF(0x70, 0x00f8, 0x00d8), /* class D test 5 */ + WRITE_COEF(0x71, 0x0014), /* class D test 6 */ + WRITE_COEF(0x72, 0xc2ba), /* classD OCP */ + UPDATE_COEF(0x77, 0x0f80, 0), /* classD pure DC test */ + WRITE_COEF(0x6c, 0xfc06), /* Class D amp control */ + {} +}; + static void alc282_restore_default_value(struct hda_codec *codec) { - /* Power Down Control */ - alc_write_coef_idx(codec, 0x03, 0x0002); - /* FIFO and filter clock */ - alc_write_coef_idx(codec, 0x05, 0x0700); - /* DMIC control */ - alc_write_coef_idx(codec, 0x07, 0x0200); - /* Analog clock */ - alc_update_coef_idx(codec, 0x06, 0x00f0, 0); - /* JD */ - alc_update_coef_idx(codec, 0x08, 0xfffc, 0x0c2c); - /* JD offset1 */ - alc_write_coef_idx(codec, 0x0a, 0xcccc); - /* JD offset2 */ - alc_write_coef_idx(codec, 0x0b, 0xcccc); - /* LDO1/2/3, DAC/ADC */ - alc_write_coef_idx(codec, 0x0e, 0x6e00); - /* JD */ - alc_update_coef_idx(codec, 0x0f, 0xf800, 0x1000); - /* Capless */ - alc_update_coef_idx(codec, 0x10, 0xfc00, 0x0c00); - /* Class D test 4 */ - alc_write_coef_idx(codec, 0x6f, 0x0); - /* IO power down directly */ - alc_update_coef_idx(codec, 0x0c, 0xfe00, 0); - /* ANC */ - alc_write_coef_idx(codec, 0x34, 0xa0c0); - /* AGC MUX */ - alc_update_coef_idx(codec, 0x16, 0x0008, 0); - /* DAC simple content protection */ - alc_update_coef_idx(codec, 0x1d, 0x00e0, 0); - /* ADC simple content protection */ - alc_update_coef_idx(codec, 0x1f, 0x00e0, 0); - /* DAC ADC Zero Detection */ - alc_write_coef_idx(codec, 0x21, 0x8804); - /* PLL */ - alc_write_coef_idx(codec, 0x63, 0x2902); - /* capless control 2 */ - alc_write_coef_idx(codec, 0x68, 0xa080); - /* capless control 3 */ - alc_write_coef_idx(codec, 0x69, 0x3400); - /* capless control 4 */ - alc_write_coef_idx(codec, 0x6a, 0x2f3e); - /* capless control 5 */ - alc_write_coef_idx(codec, 0x6b, 0x0); - /* class D test 2 */ - alc_update_coef_idx(codec, 0x6d, 0x0fff, 0x0900); - /* class D test 3 */ - alc_write_coef_idx(codec, 0x6e, 0x110a); - /* class D test 5 */ - alc_update_coef_idx(codec, 0x70, 0x00f8, 0x00d8); - /* class D test 6 */ - alc_write_coef_idx(codec, 0x71, 0x0014); - /* classD OCP */ - alc_write_coef_idx(codec, 0x72, 0xc2ba); - /* classD pure DC test */ - alc_update_coef_idx(codec, 0x77, 0x0f80, 0); - /* Class D amp control */ - alc_write_coef_idx(codec, 0x6c, 0xfc06); + alc_process_coef_fw(codec, alc282_coefs); } static void alc282_init(struct hda_codec *codec) @@ -2922,72 +2924,45 @@ static void alc282_shutup(struct hda_codec *codec) alc_write_coef_idx(codec, 0x78, coef78); } +static struct coef_fw alc283_coefs[] = { + WRITE_COEF(0x03, 0x0002), /* Power Down Control */ + WRITE_COEF(0x05, 0x0700), /* FIFO and filter clock */ + WRITE_COEF(0x07, 0x0200), /* DMIC control */ + UPDATE_COEF(0x06, 0x00f0, 0), /* Analog clock */ + UPDATE_COEF(0x08, 0xfffc, 0x0c2c), /* JD */ + WRITE_COEF(0x0a, 0xcccc), /* JD offset1 */ + WRITE_COEF(0x0b, 0xcccc), /* JD offset2 */ + WRITE_COEF(0x0e, 0x6fc0), /* LDO1/2/3, DAC/ADC */ + UPDATE_COEF(0x0f, 0xf800, 0x1000), /* JD */ + UPDATE_COEF(0x10, 0xfc00, 0x0c00), /* Capless */ + WRITE_COEF(0x3a, 0x0), /* Class D test 4 */ + UPDATE_COEF(0x0c, 0xfe00, 0x0), /* IO power down directly */ + WRITE_COEF(0x22, 0xa0c0), /* ANC */ + UPDATE_COEFEX(0x53, 0x01, 0x000f, 0x0008), /* AGC MUX */ + UPDATE_COEF(0x1d, 0x00e0, 0), /* DAC simple content protection */ + UPDATE_COEF(0x1f, 0x00e0, 0), /* ADC simple content protection */ + WRITE_COEF(0x21, 0x8804), /* DAC ADC Zero Detection */ + WRITE_COEF(0x2e, 0x2902), /* PLL */ + WRITE_COEF(0x33, 0xa080), /* capless control 2 */ + WRITE_COEF(0x34, 0x3400), /* capless control 3 */ + WRITE_COEF(0x35, 0x2f3e), /* capless control 4 */ + WRITE_COEF(0x36, 0x0), /* capless control 5 */ + UPDATE_COEF(0x38, 0x0fff, 0x0900), /* class D test 2 */ + WRITE_COEF(0x39, 0x110a), /* class D test 3 */ + UPDATE_COEF(0x3b, 0x00f8, 0x00d8), /* class D test 5 */ + WRITE_COEF(0x3c, 0x0014), /* class D test 6 */ + WRITE_COEF(0x3d, 0xc2ba), /* classD OCP */ + UPDATE_COEF(0x42, 0x0f80, 0x0), /* classD pure DC test */ + WRITE_COEF(0x49, 0x0), /* test mode */ + UPDATE_COEF(0x40, 0xf800, 0x9800), /* Class D DC enable */ + UPDATE_COEF(0x42, 0xf000, 0x2000), /* DC offset */ + WRITE_COEF(0x37, 0xfc06), /* Class D amp control */ + {} +}; + static void alc283_restore_default_value(struct hda_codec *codec) { - /* Power Down Control */ - alc_write_coef_idx(codec, 0x03, 0x0002); - /* FIFO and filter clock */ - alc_write_coef_idx(codec, 0x05, 0x0700); - /* DMIC control */ - alc_write_coef_idx(codec, 0x07, 0x0200); - /* Analog clock */ - alc_update_coef_idx(codec, 0x06, 0x00f0, 0); - /* JD */ - alc_update_coef_idx(codec, 0x08, 0xfffc, 0x0c2c); - /* JD offset1 */ - alc_write_coef_idx(codec, 0x0a, 0xcccc); - /* JD offset2 */ - alc_write_coef_idx(codec, 0x0b, 0xcccc); - /* LDO1/2/3, DAC/ADC */ - alc_write_coef_idx(codec, 0x0e, 0x6fc0); - /* JD */ - alc_update_coef_idx(codec, 0x0f, 0xf800, 0x1000); - /* Capless */ - alc_update_coef_idx(codec, 0x10, 0xfc00, 0x0c00); - /* Class D test 4 */ - alc_write_coef_idx(codec, 0x3a, 0x0); - /* IO power down directly */ - alc_update_coef_idx(codec, 0x0c, 0xfe00, 0x0); - /* ANC */ - alc_write_coef_idx(codec, 0x22, 0xa0c0); - /* AGC MUX */ - alc_update_coefex_idx(codec, 0x53, 0x01, 0x000f, 0x0008); - /* DAC simple content protection */ - alc_update_coef_idx(codec, 0x1d, 0x00e0, 0x0); - /* ADC simple content protection */ - alc_update_coef_idx(codec, 0x1f, 0x00e0, 0x0); - /* DAC ADC Zero Detection */ - alc_write_coef_idx(codec, 0x21, 0x8804); - /* PLL */ - alc_write_coef_idx(codec, 0x2e, 0x2902); - /* capless control 2 */ - alc_write_coef_idx(codec, 0x33, 0xa080); - /* capless control 3 */ - alc_write_coef_idx(codec, 0x34, 0x3400); - /* capless control 4 */ - alc_write_coef_idx(codec, 0x35, 0x2f3e); - /* capless control 5 */ - alc_write_coef_idx(codec, 0x36, 0x0); - /* class D test 2 */ - alc_update_coef_idx(codec, 0x38, 0x0fff, 0x0900); - /* class D test 3 */ - alc_write_coef_idx(codec, 0x39, 0x110a); - /* class D test 5 */ - alc_update_coef_idx(codec, 0x3b, 0x00f8, 0x00d8); - /* class D test 6 */ - alc_write_coef_idx(codec, 0x3c, 0x0014); - /* classD OCP */ - alc_write_coef_idx(codec, 0x3d, 0xc2ba); - /* classD pure DC test */ - alc_update_coef_idx(codec, 0x42, 0x0f80, 0x0); - /* test mode */ - alc_write_coef_idx(codec, 0x49, 0x0); - /* Class D DC enable */ - alc_update_coef_idx(codec, 0x40, 0xf800, 0x9800); - /* DC offset */ - alc_update_coef_idx(codec, 0x42, 0xf000, 0x2000); - /* Class D amp control */ - alc_write_coef_idx(codec, 0x37, 0xfc06); + alc_process_coef_fw(codec, alc283_coefs); } static void alc283_init(struct hda_codec *codec) @@ -3530,52 +3505,62 @@ static void alc269_fixup_hp_line1_mic1_led(struct hda_codec *codec, static void alc_headset_mode_unplugged(struct hda_codec *codec) { + static struct coef_fw coef0255[] = { + WRITE_COEF(0x1b, 0x0c0b), /* LDO and MISC control */ + WRITE_COEF(0x45, 0xd089), /* UAJ function set to menual mode */ + UPDATE_COEFEX(0x57, 0x05, 1<<14, 0), /* Direct Drive HP Amp control(Set to verb control)*/ + WRITE_COEF(0x06, 0x6104), /* Set MIC2 Vref gate with HP */ + WRITE_COEFEX(0x57, 0x03, 0x8aa6), /* Direct Drive HP Amp control */ + {} + }; + static struct coef_fw coef0233[] = { + WRITE_COEF(0x1b, 0x0c0b), + WRITE_COEF(0x45, 0xc429), + UPDATE_COEF(0x35, 0x4000, 0), + WRITE_COEF(0x06, 0x2104), + WRITE_COEF(0x1a, 0x0001), + WRITE_COEF(0x26, 0x0004), + WRITE_COEF(0x32, 0x42a3), + {} + }; + static struct coef_fw coef0292[] = { + WRITE_COEF(0x76, 0x000e), + WRITE_COEF(0x6c, 0x2400), + WRITE_COEF(0x18, 0x7308), + WRITE_COEF(0x6b, 0xc429), + {} + }; + static struct coef_fw coef0293[] = { + UPDATE_COEF(0x10, 7<<8, 6<<8), /* SET Line1 JD to 0 */ + UPDATE_COEFEX(0x57, 0x05, 1<<15|1<<13, 0x0), /* SET charge pump by verb */ + UPDATE_COEFEX(0x57, 0x03, 1<<10, 1<<10), /* SET EN_OSW to 1 */ + UPDATE_COEF(0x1a, 1<<3, 1<<3), /* Combo JD gating with LINE1-VREFO */ + WRITE_COEF(0x45, 0xc429), /* Set to TRS type */ + UPDATE_COEF(0x4a, 0x000f, 0x000e), /* Combo Jack auto detect */ + {} + }; + static struct coef_fw coef0668[] = { + WRITE_COEF(0x15, 0x0d40), + WRITE_COEF(0xb7, 0x802b), + {} + }; + switch (codec->vendor_id) { case 0x10ec0255: - /* LDO and MISC control */ - alc_write_coef_idx(codec, 0x1b, 0x0c0b); - /* UAJ function set to menual mode */ - alc_write_coef_idx(codec, 0x45, 0xd089); - /* Direct Drive HP Amp control(Set to verb control)*/ - alc_update_coefex_idx(codec, 0x57, 0x05, 1<<14, 0); - /* Set MIC2 Vref gate with HP */ - alc_write_coef_idx(codec, 0x06, 0x6104); - /* Direct Drive HP Amp control */ - alc_write_coefex_idx(codec, 0x57, 0x03, 0x8aa6); + alc_process_coef_fw(codec, coef0255); break; case 0x10ec0233: case 0x10ec0283: - alc_write_coef_idx(codec, 0x1b, 0x0c0b); - alc_write_coef_idx(codec, 0x45, 0xc429); - alc_update_coef_idx(codec, 0x35, 0x4000, 0); - alc_write_coef_idx(codec, 0x06, 0x2104); - alc_write_coef_idx(codec, 0x1a, 0x0001); - alc_write_coef_idx(codec, 0x26, 0x0004); - alc_write_coef_idx(codec, 0x32, 0x42a3); + alc_process_coef_fw(codec, coef0233); break; case 0x10ec0292: - alc_write_coef_idx(codec, 0x76, 0x000e); - alc_write_coef_idx(codec, 0x6c, 0x2400); - alc_write_coef_idx(codec, 0x18, 0x7308); - alc_write_coef_idx(codec, 0x6b, 0xc429); + alc_process_coef_fw(codec, coef0292); break; case 0x10ec0293: - /* SET Line1 JD to 0 */ - alc_update_coef_idx(codec, 0x10, 7<<8, 6<<8); - /* SET charge pump by verb */ - alc_update_coefex_idx(codec, 0x57, 0x05, 1<<15|1<<13, 0x0); - /* SET EN_OSW to 1 */ - alc_update_coefex_idx(codec, 0x57, 0x03, 1<<10, 1<<10); - /* Combo JD gating with LINE1-VREFO */ - alc_update_coef_idx(codec, 0x1a, 1<<3, 1<<3); - /* Set to TRS type */ - alc_write_coef_idx(codec, 0x45, 0xc429); - /* Combo Jack auto detect */ - alc_update_coef_idx(codec, 0x4a, 0x000f, 0x000e); + alc_process_coef_fw(codec, coef0293); break; case 0x10ec0668: - alc_write_coef_idx(codec, 0x15, 0x0d40); - alc_write_coef_idx(codec, 0xb7, 0x802b); + alc_process_coef_fw(codec, coef0668); break; } codec_dbg(codec, "Headset jack set to unplugged mode.\n"); @@ -3585,48 +3570,65 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec) static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin, hda_nid_t mic_pin) { + static struct coef_fw coef0255[] = { + WRITE_COEFEX(0x57, 0x03, 0x8aa6), + WRITE_COEF(0x06, 0x6100), /* Set MIC2 Vref gate to normal */ + {} + }; + static struct coef_fw coef0233[] = { + UPDATE_COEF(0x35, 0, 1<<14), + WRITE_COEF(0x06, 0x2100), + WRITE_COEF(0x1a, 0x0021), + WRITE_COEF(0x26, 0x008c), + {} + }; + static struct coef_fw coef0292[] = { + WRITE_COEF(0x19, 0xa208), + WRITE_COEF(0x2e, 0xacf0), + {} + }; + static struct coef_fw coef0293[] = { + UPDATE_COEFEX(0x57, 0x05, 0, 1<<15|1<<13), /* SET charge pump by verb */ + UPDATE_COEFEX(0x57, 0x03, 1<<10, 0), /* SET EN_OSW to 0 */ + UPDATE_COEF(0x1a, 1<<3, 0), /* Combo JD gating without LINE1-VREFO */ + {} + }; + static struct coef_fw coef0688[] = { + WRITE_COEF(0xb7, 0x802b), + WRITE_COEF(0xb5, 0x1040), + UPDATE_COEF(0xc3, 0, 1<<12), + {} + }; + switch (codec->vendor_id) { case 0x10ec0255: alc_write_coef_idx(codec, 0x45, 0xc489); snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); - alc_write_coefex_idx(codec, 0x57, 0x03, 0x8aa6); - /* Set MIC2 Vref gate to normal */ - alc_write_coef_idx(codec, 0x06, 0x6100); + alc_process_coef_fw(codec, coef0255); snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); break; case 0x10ec0233: case 0x10ec0283: alc_write_coef_idx(codec, 0x45, 0xc429); snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); - alc_update_coef_idx(codec, 0x35, 0, 1<<14); - alc_write_coef_idx(codec, 0x06, 0x2100); - alc_write_coef_idx(codec, 0x1a, 0x0021); - alc_write_coef_idx(codec, 0x26, 0x008c); + alc_process_coef_fw(codec, coef0233); snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); break; case 0x10ec0292: snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); - alc_write_coef_idx(codec, 0x19, 0xa208); - alc_write_coef_idx(codec, 0x2e, 0xacf0); + alc_process_coef_fw(codec, coef0292); break; case 0x10ec0293: /* Set to TRS mode */ alc_write_coef_idx(codec, 0x45, 0xc429); snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); - /* SET charge pump by verb */ - alc_update_coefex_idx(codec, 0x57, 0x05, 0, 1<<15|1<<13); - /* SET EN_OSW to 0 */ - alc_update_coefex_idx(codec, 0x57, 0x03, 1<<10, 0); - /* Combo JD gating without LINE1-VREFO */ - alc_update_coef_idx(codec, 0x1a, 1<<3, 0); + alc_process_coef_fw(codec, coef0293); snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); break; case 0x10ec0668: alc_write_coef_idx(codec, 0x11, 0x0001); snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); - alc_write_coef_idx(codec, 0xb7, 0x802b); - alc_write_coef_idx(codec, 0xb5, 0x1040); - alc_update_coef_idx(codec, 0xc3, 0, 1<<12); + alc_process_coef_fw(codec, coef0688); snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); break; } @@ -3635,36 +3637,54 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin, static void alc_headset_mode_default(struct hda_codec *codec) { + static struct coef_fw coef0255[] = { + WRITE_COEF(0x45, 0xc089), + WRITE_COEF(0x45, 0xc489), + WRITE_COEFEX(0x57, 0x03, 0x8ea6), + WRITE_COEF(0x49, 0x0049), + {} + }; + static struct coef_fw coef0233[] = { + WRITE_COEF(0x06, 0x2100), + WRITE_COEF(0x32, 0x4ea3), + {} + }; + static struct coef_fw coef0292[] = { + WRITE_COEF(0x76, 0x000e), + WRITE_COEF(0x6c, 0x2400), + WRITE_COEF(0x6b, 0xc429), + WRITE_COEF(0x18, 0x7308), + {} + }; + static struct coef_fw coef0293[] = { + UPDATE_COEF(0x4a, 0x000f, 0x000e), /* Combo Jack auto detect */ + WRITE_COEF(0x45, 0xC429), /* Set to TRS type */ + UPDATE_COEF(0x1a, 1<<3, 0), /* Combo JD gating without LINE1-VREFO */ + {} + }; + static struct coef_fw coef0688[] = { + WRITE_COEF(0x11, 0x0041), + WRITE_COEF(0x15, 0x0d40), + WRITE_COEF(0xb7, 0x802b), + {} + }; + switch (codec->vendor_id) { case 0x10ec0255: - alc_write_coef_idx(codec, 0x45, 0xc089); - alc_write_coef_idx(codec, 0x45, 0xc489); - alc_write_coefex_idx(codec, 0x57, 0x03, 0x8ea6); - alc_write_coef_idx(codec, 0x49, 0x0049); + alc_process_coef_fw(codec, coef0255); break; case 0x10ec0233: case 0x10ec0283: - alc_write_coef_idx(codec, 0x06, 0x2100); - alc_write_coef_idx(codec, 0x32, 0x4ea3); + alc_process_coef_fw(codec, coef0233); break; case 0x10ec0292: - alc_write_coef_idx(codec, 0x76, 0x000e); - alc_write_coef_idx(codec, 0x6c, 0x2400); - alc_write_coef_idx(codec, 0x6b, 0xc429); - alc_write_coef_idx(codec, 0x18, 0x7308); + alc_process_coef_fw(codec, coef0292); break; case 0x10ec0293: - /* Combo Jack auto detect */ - alc_update_coef_idx(codec, 0x4a, 0x000f, 0x000e); - /* Set to TRS type */ - alc_write_coef_idx(codec, 0x45, 0xC429); - /* Combo JD gating without LINE1-VREFO */ - alc_update_coef_idx(codec, 0x1a, 1<<3, 0); + alc_process_coef_fw(codec, coef0293); break; case 0x10ec0668: - alc_write_coef_idx(codec, 0x11, 0x0041); - alc_write_coef_idx(codec, 0x15, 0x0d40); - alc_write_coef_idx(codec, 0xb7, 0x802b); + alc_process_coef_fw(codec, coef0688); break; } codec_dbg(codec, "Headset jack set to headphone (default) mode.\n"); @@ -3673,34 +3693,52 @@ static void alc_headset_mode_default(struct hda_codec *codec) /* Iphone type */ static void alc_headset_mode_ctia(struct hda_codec *codec) { + static struct coef_fw coef0255[] = { + WRITE_COEF(0x45, 0xd489), /* Set to CTIA type */ + WRITE_COEF(0x1b, 0x0c2b), + WRITE_COEFEX(0x57, 0x03, 0x8ea6), + {} + }; + static struct coef_fw coef0233[] = { + WRITE_COEF(0x45, 0xd429), + WRITE_COEF(0x1b, 0x0c2b), + WRITE_COEF(0x32, 0x4ea3), + {} + }; + static struct coef_fw coef0292[] = { + WRITE_COEF(0x6b, 0xd429), + WRITE_COEF(0x76, 0x0008), + WRITE_COEF(0x18, 0x7388), + {} + }; + static struct coef_fw coef0293[] = { + WRITE_COEF(0x45, 0xd429), /* Set to ctia type */ + UPDATE_COEF(0x10, 7<<8, 7<<8), /* SET Line1 JD to 1 */ + {} + }; + static struct coef_fw coef0688[] = { + WRITE_COEF(0x11, 0x0001), + WRITE_COEF(0x15, 0x0d60), + WRITE_COEF(0xc3, 0x0000), + {} + }; + switch (codec->vendor_id) { case 0x10ec0255: - /* Set to CTIA type */ - alc_write_coef_idx(codec, 0x45, 0xd489); - alc_write_coef_idx(codec, 0x1b, 0x0c2b); - alc_write_coefex_idx(codec, 0x57, 0x03, 0x8ea6); + alc_process_coef_fw(codec, coef0255); break; case 0x10ec0233: case 0x10ec0283: - alc_write_coef_idx(codec, 0x45, 0xd429); - alc_write_coef_idx(codec, 0x1b, 0x0c2b); - alc_write_coef_idx(codec, 0x32, 0x4ea3); + alc_process_coef_fw(codec, coef0233); break; case 0x10ec0292: - alc_write_coef_idx(codec, 0x6b, 0xd429); - alc_write_coef_idx(codec, 0x76, 0x0008); - alc_write_coef_idx(codec, 0x18, 0x7388); + alc_process_coef_fw(codec, coef0292); break; case 0x10ec0293: - /* Set to ctia type */ - alc_write_coef_idx(codec, 0x45, 0xd429); - /* SET Line1 JD to 1 */ - alc_update_coef_idx(codec, 0x10, 7<<8, 7<<8); + alc_process_coef_fw(codec, coef0293); break; case 0x10ec0668: - alc_write_coef_idx(codec, 0x11, 0x0001); - alc_write_coef_idx(codec, 0x15, 0x0d60); - alc_write_coef_idx(codec, 0xc3, 0x0000); + alc_process_coef_fw(codec, coef0688); break; } codec_dbg(codec, "Headset jack set to iPhone-style headset mode.\n"); @@ -3709,34 +3747,52 @@ static void alc_headset_mode_ctia(struct hda_codec *codec) /* Nokia type */ static void alc_headset_mode_omtp(struct hda_codec *codec) { + static struct coef_fw coef0255[] = { + WRITE_COEF(0x45, 0xe489), /* Set to OMTP Type */ + WRITE_COEF(0x1b, 0x0c2b), + WRITE_COEFEX(0x57, 0x03, 0x8ea6), + {} + }; + static struct coef_fw coef0233[] = { + WRITE_COEF(0x45, 0xe429), + WRITE_COEF(0x1b, 0x0c2b), + WRITE_COEF(0x32, 0x4ea3), + {} + }; + static struct coef_fw coef0292[] = { + WRITE_COEF(0x6b, 0xe429), + WRITE_COEF(0x76, 0x0008), + WRITE_COEF(0x18, 0x7388), + {} + }; + static struct coef_fw coef0293[] = { + WRITE_COEF(0x45, 0xe429), /* Set to omtp type */ + UPDATE_COEF(0x10, 7<<8, 7<<8), /* SET Line1 JD to 1 */ + {} + }; + static struct coef_fw coef0688[] = { + WRITE_COEF(0x11, 0x0001), + WRITE_COEF(0x15, 0x0d50), + WRITE_COEF(0xc3, 0x0000), + {} + }; + switch (codec->vendor_id) { case 0x10ec0255: - /* Set to OMTP Type */ - alc_write_coef_idx(codec, 0x45, 0xe489); - alc_write_coef_idx(codec, 0x1b, 0x0c2b); - alc_write_coefex_idx(codec, 0x57, 0x03, 0x8ea6); + alc_process_coef_fw(codec, coef0255); break; case 0x10ec0233: case 0x10ec0283: - alc_write_coef_idx(codec, 0x45, 0xe429); - alc_write_coef_idx(codec, 0x1b, 0x0c2b); - alc_write_coef_idx(codec, 0x32, 0x4ea3); + alc_process_coef_fw(codec, coef0233); break; case 0x10ec0292: - alc_write_coef_idx(codec, 0x6b, 0xe429); - alc_write_coef_idx(codec, 0x76, 0x0008); - alc_write_coef_idx(codec, 0x18, 0x7388); + alc_process_coef_fw(codec, coef0292); break; case 0x10ec0293: - /* Set to omtp type */ - alc_write_coef_idx(codec, 0x45, 0xe429); - /* SET Line1 JD to 1 */ - alc_update_coef_idx(codec, 0x10, 7<<8, 7<<8); + alc_process_coef_fw(codec, coef0293); break; case 0x10ec0668: - alc_write_coef_idx(codec, 0x11, 0x0001); - alc_write_coef_idx(codec, 0x15, 0x0d50); - alc_write_coef_idx(codec, 0xc3, 0x0000); + alc_process_coef_fw(codec, coef0688); break; } codec_dbg(codec, "Headset jack set to Nokia-style headset mode.\n"); @@ -3747,13 +3803,28 @@ static void alc_determine_headset_type(struct hda_codec *codec) int val; bool is_ctia = false; struct alc_spec *spec = codec->spec; + static struct coef_fw coef0255[] = { + WRITE_COEF(0x45, 0xd089), /* combo jack auto switch control(Check type)*/ + WRITE_COEF(0x49, 0x0149), /* combo jack auto switch control(Vref + conteol) */ + {} + }; + static struct coef_fw coef0293[] = { + UPDATE_COEF(0x4a, 0x000f, 0x0008), /* Combo Jack auto detect */ + WRITE_COEF(0x45, 0xD429), /* Set to ctia type */ + {} + }; + static struct coef_fw coef0688[] = { + WRITE_COEF(0x11, 0x0001), + WRITE_COEF(0xb7, 0x802b), + WRITE_COEF(0x15, 0x0d60), + WRITE_COEF(0xc3, 0x0c00), + {} + }; switch (codec->vendor_id) { case 0x10ec0255: - /* combo jack auto switch control(Check type)*/ - alc_write_coef_idx(codec, 0x45, 0xd089); - /* combo jack auto switch control(Vref conteol) */ - alc_write_coef_idx(codec, 0x49, 0x0149); + alc_process_coef_fw(codec, coef0255); msleep(300); val = alc_read_coef_idx(codec, 0x46); is_ctia = (val & 0x0070) == 0x0070; @@ -3772,19 +3843,13 @@ static void alc_determine_headset_type(struct hda_codec *codec) is_ctia = (val & 0x001c) == 0x001c; break; case 0x10ec0293: - /* Combo Jack auto detect */ - alc_update_coef_idx(codec, 0x4a, 0x000f, 0x0008); - /* Set to ctia type */ - alc_write_coef_idx(codec, 0x45, 0xD429); + alc_process_coef_fw(codec, coef0293); msleep(300); val = alc_read_coef_idx(codec, 0x46); is_ctia = (val & 0x0070) == 0x0070; break; case 0x10ec0668: - alc_write_coef_idx(codec, 0x11, 0x0001); - alc_write_coef_idx(codec, 0xb7, 0x802b); - alc_write_coef_idx(codec, 0x15, 0x0d60); - alc_write_coef_idx(codec, 0xc3, 0x0c00); + alc_process_coef_fw(codec, coef0688); msleep(300); val = alc_read_coef_idx(codec, 0xbe); is_ctia = (val & 0x1c02) == 0x1c02; @@ -3920,11 +3985,15 @@ static void alc_fixup_headset_mode_no_hp_mic(struct hda_codec *codec, static void alc255_set_default_jack_type(struct hda_codec *codec) { /* Set to iphone type */ - alc_write_coef_idx(codec, 0x1b, 0x880b); - alc_write_coef_idx(codec, 0x45, 0xd089); - alc_write_coef_idx(codec, 0x1b, 0x080b); - alc_write_coef_idx(codec, 0x46, 0x0004); - alc_write_coef_idx(codec, 0x1b, 0x0c0b); + static struct coef_fw fw[] = { + WRITE_COEF(0x1b, 0x880b), + WRITE_COEF(0x45, 0xd089), + WRITE_COEF(0x1b, 0x080b), + WRITE_COEF(0x46, 0x0004), + WRITE_COEF(0x1b, 0x0c0b), + {} + }; + alc_process_coef_fw(codec, fw); msleep(30); } From cdec729765659adafba983d6b6760ad52c71d5d8 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Tue, 19 Aug 2014 12:49:34 +0800 Subject: [PATCH 040/251] ASoC: fsl: Fix building of imx-es8328 on PPC The imx-es8328 driver fails to build on PPC because it explicitly depends on SND_SOC_IMX_PCM_FIQ, which itself doesn't build on PPC. Instead, rely on the SND_SOC_FSL_SSI config option to pull in the necessary libraries. While we're at it, remove SND_SOC_FSL_UTILS, which also is not needed. Signed-off-by: Sean Cross Signed-off-by: Mark Brown --- sound/soc/fsl/Kconfig | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 4698c01af684..3154f43b11ab 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -266,8 +266,6 @@ config SND_SOC_IMX_ES8328 select SND_SOC_IMX_PCM_DMA select SND_SOC_IMX_AUDMUX select SND_SOC_FSL_SSI - select SND_SOC_FSL_UTILS - select SND_SOC_IMX_PCM_FIQ help Say Y if you want to add support for the ES8328 audio codec connected via SSI/I2S over either SPI or I2C. From 81c7cfd1b22a0ee5e40efef72ec2cd17dbf12e6d Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 19 Aug 2014 15:51:18 +0200 Subject: [PATCH 041/251] ASoC: Move debugfs registration to the component level The debugfs registration is mostly identical between platforms and CODECs. This patches consolidates the two implementations at the component level. Unfortunately there are still a couple of CODEC specific debugfs files that are related to legacy ASoC IO that need to be registered. For this a new callback is added to the component struct that will be initialized when a CODEC is registered and will be used to register the CODEC specific files. Once there are no drivers left using legacy IO this can be removed again. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- include/sound/soc.h | 20 +++++-- sound/soc/soc-core.c | 132 +++++++++++++++++++------------------------ 2 files changed, 72 insertions(+), 80 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index be6ecae247b0..0ab8b1e4a5d2 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -728,9 +728,24 @@ struct snd_soc_component { struct mutex io_mutex; +#ifdef CONFIG_DEBUG_FS + struct dentry *debugfs_root; +#endif + + /* + * DO NOT use any of the fields below in drivers, they are temporary and + * are going to be removed again soon. If you use them in driver code the + * driver will be marked as BROKEN when these fields are removed. + */ + /* Don't use these, use snd_soc_component_get_dapm() */ struct snd_soc_dapm_context dapm; struct snd_soc_dapm_context *dapm_ptr; + +#ifdef CONFIG_DEBUG_FS + void (*init_debugfs)(struct snd_soc_component *component); + const char *debugfs_prefix; +#endif }; /* SoC Audio Codec device */ @@ -766,7 +781,6 @@ struct snd_soc_codec { struct snd_soc_dapm_context dapm; #ifdef CONFIG_DEBUG_FS - struct dentry *debugfs_codec_root; struct dentry *debugfs_reg; #endif }; @@ -879,10 +893,6 @@ struct snd_soc_platform { struct list_head list; struct snd_soc_component component; - -#ifdef CONFIG_DEBUG_FS - struct dentry *debugfs_platform_root; -#endif }; struct snd_soc_dai_link { diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index d4bfd4a9076f..79371a77f324 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -270,79 +270,56 @@ static const struct file_operations codec_reg_fops = { .llseek = default_llseek, }; -static struct dentry *soc_debugfs_create_dir(struct dentry *parent, - const char *fmt, ...) +static void soc_init_component_debugfs(struct snd_soc_component *component) { - struct dentry *de; - va_list ap; - char *s; + if (component->debugfs_prefix) { + char *name; - va_start(ap, fmt); - s = kvasprintf(GFP_KERNEL, fmt, ap); - va_end(ap); + name = kasprintf(GFP_KERNEL, "%s:%s", + component->debugfs_prefix, component->name); + if (name) { + component->debugfs_root = debugfs_create_dir(name, + component->card->debugfs_card_root); + kfree(name); + } + } else { + component->debugfs_root = debugfs_create_dir(component->name, + component->card->debugfs_card_root); + } - if (!s) - return NULL; - - de = debugfs_create_dir(s, parent); - kfree(s); - - return de; -} - -static void soc_init_codec_debugfs(struct snd_soc_codec *codec) -{ - struct dentry *debugfs_card_root = codec->component.card->debugfs_card_root; - - codec->debugfs_codec_root = soc_debugfs_create_dir(debugfs_card_root, - "codec:%s", - codec->component.name); - if (!codec->debugfs_codec_root) { - dev_warn(codec->dev, - "ASoC: Failed to create codec debugfs directory\n"); + if (!component->debugfs_root) { + dev_warn(component->dev, + "ASoC: Failed to create component debugfs directory\n"); return; } - debugfs_create_bool("cache_sync", 0444, codec->debugfs_codec_root, + snd_soc_dapm_debugfs_init(snd_soc_component_get_dapm(component), + component->debugfs_root); + + if (component->init_debugfs) + component->init_debugfs(component); +} + +static void soc_cleanup_component_debugfs(struct snd_soc_component *component) +{ + debugfs_remove_recursive(component->debugfs_root); +} + +static void soc_init_codec_debugfs(struct snd_soc_component *component) +{ + struct snd_soc_codec *codec = snd_soc_component_to_codec(component); + + debugfs_create_bool("cache_sync", 0444, codec->component.debugfs_root, &codec->cache_sync); - debugfs_create_bool("cache_only", 0444, codec->debugfs_codec_root, + debugfs_create_bool("cache_only", 0444, codec->component.debugfs_root, &codec->cache_only); codec->debugfs_reg = debugfs_create_file("codec_reg", 0644, - codec->debugfs_codec_root, + codec->component.debugfs_root, codec, &codec_reg_fops); if (!codec->debugfs_reg) dev_warn(codec->dev, "ASoC: Failed to create codec register debugfs file\n"); - - snd_soc_dapm_debugfs_init(&codec->dapm, codec->debugfs_codec_root); -} - -static void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec) -{ - debugfs_remove_recursive(codec->debugfs_codec_root); -} - -static void soc_init_platform_debugfs(struct snd_soc_platform *platform) -{ - struct dentry *debugfs_card_root = platform->component.card->debugfs_card_root; - - platform->debugfs_platform_root = soc_debugfs_create_dir(debugfs_card_root, - "platform:%s", - platform->component.name); - if (!platform->debugfs_platform_root) { - dev_warn(platform->dev, - "ASoC: Failed to create platform debugfs directory\n"); - return; - } - - snd_soc_dapm_debugfs_init(&platform->component.dapm, - platform->debugfs_platform_root); -} - -static void soc_cleanup_platform_debugfs(struct snd_soc_platform *platform) -{ - debugfs_remove_recursive(platform->debugfs_platform_root); } static ssize_t codec_list_read_file(struct file *file, char __user *user_buf, @@ -474,19 +451,15 @@ static void soc_cleanup_card_debugfs(struct snd_soc_card *card) #else -static inline void soc_init_codec_debugfs(struct snd_soc_codec *codec) +#define soc_init_codec_debugfs NULL + +static inline void soc_init_component_debugfs( + struct snd_soc_component *component) { } -static inline void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec) -{ -} - -static inline void soc_init_platform_debugfs(struct snd_soc_platform *platform) -{ -} - -static inline void soc_cleanup_platform_debugfs(struct snd_soc_platform *platform) +static inline void soc_cleanup_component_debugfs( + struct snd_soc_component *component) { } @@ -1026,7 +999,7 @@ static int soc_remove_platform(struct snd_soc_platform *platform) /* Make sure all DAPM widgets are freed */ snd_soc_dapm_free(&platform->component.dapm); - soc_cleanup_platform_debugfs(platform); + soc_cleanup_component_debugfs(&platform->component); platform->probed = 0; module_put(platform->dev->driver->owner); @@ -1046,7 +1019,7 @@ static void soc_remove_codec(struct snd_soc_codec *codec) /* Make sure all DAPM widgets are freed */ snd_soc_dapm_free(&codec->dapm); - soc_cleanup_codec_debugfs(codec); + soc_cleanup_component_debugfs(&codec->component); codec->probed = 0; list_del(&codec->card_list); module_put(codec->dev->driver->owner); @@ -1187,7 +1160,7 @@ static int soc_probe_codec(struct snd_soc_card *card, if (!try_module_get(codec->dev->driver->owner)) return -ENODEV; - soc_init_codec_debugfs(codec); + soc_init_component_debugfs(&codec->component); if (driver->dapm_widgets) { ret = snd_soc_dapm_new_controls(&codec->dapm, @@ -1242,7 +1215,7 @@ static int soc_probe_codec(struct snd_soc_card *card, return 0; err_probe: - soc_cleanup_codec_debugfs(codec); + soc_cleanup_component_debugfs(&codec->component); module_put(codec->dev->driver->owner); return ret; @@ -1262,7 +1235,7 @@ static int soc_probe_platform(struct snd_soc_card *card, if (!try_module_get(platform->dev->driver->owner)) return -ENODEV; - soc_init_platform_debugfs(platform); + soc_init_component_debugfs(&platform->component); if (driver->dapm_widgets) snd_soc_dapm_new_controls(&platform->component.dapm, @@ -1302,7 +1275,7 @@ static int soc_probe_platform(struct snd_soc_card *card, return 0; err_probe: - soc_cleanup_platform_debugfs(platform); + soc_cleanup_component_debugfs(&platform->component); module_put(platform->dev->driver->owner); return ret; @@ -4266,6 +4239,10 @@ int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform, if (platform_drv->read) platform->component.read = snd_soc_platform_drv_read; +#ifdef CONFIG_DEBUG_FS + platform->component.debugfs_prefix = "platform"; +#endif + mutex_lock(&client_mutex); snd_soc_component_add_unlocked(&platform->component); list_add(&platform->list, &platform_list); @@ -4455,6 +4432,11 @@ int snd_soc_register_codec(struct device *dev, codec->component.val_bytes = codec_drv->reg_word_size; mutex_init(&codec->mutex); +#ifdef CONFIG_DEBUG_FS + codec->component.init_debugfs = soc_init_codec_debugfs; + codec->component.debugfs_prefix = "codec"; +#endif + if (!codec->component.write) { if (codec_drv->get_regmap) regmap = codec_drv->get_regmap(dev); From f1d45cc3ae96a6173129b2c164c216272faa5fc0 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 19 Aug 2014 15:51:19 +0200 Subject: [PATCH 042/251] ASoC: Consolidate platform and CODEC probe/remove The platform and CODEC probe and remove code is now largely identical. This patch consolidates it at the component level. The resulting code is slightly larger due to all the boiler plate code setting up the indirection for the table based control and DAPM registration. Once all drivers have been update to no longer use the snd_soc_codec_driver and snd_soc_platform_driver specific fields for this the indirection can be removed again. This patch contains two noteworthy hacks that are only meant to be temporary to be able to update drivers and the core in separate incremental patches. The first hack is related to that some DPCM platforms expect that the DAPM widgets for the DAIs of a snd_soc_component are created in the DAPM context of the snd_soc_platform that has the same parent device. For handling this the steal_sibling_dai_widgets attribute is introduced. It gets set for snd_soc_platforms that register DAPM elements. When creating the DAI widgets for a component this flag is checked and if it is found on one of the siblings the component will not create any DAI widgets in its own DAPM context. If the attribute is set on a platform it will look for siblings components and create DAI widgets for them in its own context. The fix for this will be to update the offending drivers to only register a single component rather than two. The second hack deals with the fact that the ASoC card suspend and resume code still needs a list of CODECs that have been registered for the card. To handle this the generic probe and remove path have a check to see if the component is CODEC and if yes add/remove it to the card's CODEC list. While it is possible to clean up the suspend/resume code to not need the CODEC list anymore this is a bit of a chicken and egg problem since it will become easier to clean up the suspend/resume code once there is a unified component layer. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- include/sound/soc.h | 27 ++- sound/soc/soc-core.c | 337 +++++++++++++------------- sound/soc/soc-generic-dmaengine-pcm.c | 4 +- 3 files changed, 195 insertions(+), 173 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 0ab8b1e4a5d2..22543acfae4b 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -697,6 +697,10 @@ struct snd_soc_component_driver { void (*seq_notifier)(struct snd_soc_component *, enum snd_soc_dapm_type, int subseq); int (*stream_event)(struct snd_soc_component *, int event); + + /* probe ordering - for components with runtime dependencies */ + int probe_order; + int remove_order; }; struct snd_soc_component { @@ -710,6 +714,7 @@ struct snd_soc_component { unsigned int ignore_pmdown_time:1; /* pmdown_time is ignored at stop */ unsigned int registered_as_component:1; + unsigned int probed:1; struct list_head list; @@ -742,6 +747,18 @@ struct snd_soc_component { struct snd_soc_dapm_context dapm; struct snd_soc_dapm_context *dapm_ptr; + const struct snd_kcontrol_new *controls; + unsigned int num_controls; + const struct snd_soc_dapm_widget *dapm_widgets; + unsigned int num_dapm_widgets; + const struct snd_soc_dapm_route *dapm_routes; + unsigned int num_dapm_routes; + bool steal_sibling_dai_widgets; + struct snd_soc_codec *codec; + + int (*probe)(struct snd_soc_component *); + void (*remove)(struct snd_soc_component *); + #ifdef CONFIG_DEBUG_FS void (*init_debugfs)(struct snd_soc_component *component); const char *debugfs_prefix; @@ -761,7 +778,6 @@ struct snd_soc_codec { struct snd_ac97 *ac97; /* for ad-hoc ac97 devices */ unsigned int cache_bypass:1; /* Suppress access to the cache */ unsigned int suspended:1; /* Codec is in suspend PM state */ - unsigned int probed:1; /* Codec has been probed */ unsigned int ac97_registered:1; /* Codec has been AC97 registered */ unsigned int ac97_created:1; /* Codec has been created by SoC */ unsigned int cache_init:1; /* codec cache has been initialized */ @@ -827,10 +843,6 @@ struct snd_soc_codec_driver { enum snd_soc_dapm_type, int); bool ignore_pmdown_time; /* Doesn't benefit from pmdown delay */ - - /* probe ordering - for components with runtime dependencies */ - int probe_order; - int remove_order; }; /* SoC platform interface */ @@ -867,10 +879,6 @@ struct snd_soc_platform_driver { /* platform stream compress ops */ const struct snd_compr_ops *compr_ops; - /* probe ordering - for components with runtime dependencies */ - int probe_order; - int remove_order; - /* platform IO - used for platform DAPM */ unsigned int (*read)(struct snd_soc_platform *, unsigned int); int (*write)(struct snd_soc_platform *, unsigned int, unsigned int); @@ -888,7 +896,6 @@ struct snd_soc_platform { const struct snd_soc_platform_driver *driver; unsigned int suspended:1; /* platform is suspended */ - unsigned int probed:1; struct list_head list; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 79371a77f324..b833cc6fd86d 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -985,44 +985,20 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) return 0; } -static int soc_remove_platform(struct snd_soc_platform *platform) +static void soc_remove_component(struct snd_soc_component *component) { - int ret; + /* This is a HACK and will be removed soon */ + if (component->codec) + list_del(&component->codec->card_list); - if (platform->driver->remove) { - ret = platform->driver->remove(platform); - if (ret < 0) - dev_err(platform->dev, "ASoC: failed to remove %d\n", - ret); - } + if (component->remove) + component->remove(component); - /* Make sure all DAPM widgets are freed */ - snd_soc_dapm_free(&platform->component.dapm); + snd_soc_dapm_free(snd_soc_component_get_dapm(component)); - soc_cleanup_component_debugfs(&platform->component); - platform->probed = 0; - module_put(platform->dev->driver->owner); - - return 0; -} - -static void soc_remove_codec(struct snd_soc_codec *codec) -{ - int err; - - if (codec->driver->remove) { - err = codec->driver->remove(codec); - if (err < 0) - dev_err(codec->dev, "ASoC: failed to remove %d\n", err); - } - - /* Make sure all DAPM widgets are freed */ - snd_soc_dapm_free(&codec->dapm); - - soc_cleanup_component_debugfs(&codec->component); - codec->probed = 0; - list_del(&codec->card_list); - module_put(codec->dev->driver->owner); + soc_cleanup_component_debugfs(component); + component->probed = 0; + module_put(component->dev->driver->owner); } static void soc_remove_codec_dai(struct snd_soc_dai *codec_dai, int order) @@ -1086,25 +1062,24 @@ static void soc_remove_link_components(struct snd_soc_card *card, int num, int i; /* remove the platform */ - if (platform && platform->probed && - platform->driver->remove_order == order) { - soc_remove_platform(platform); - } + if (platform && platform->component.probed && + platform->component.driver->remove_order == order) + soc_remove_component(&platform->component); /* remove the CODEC-side CODEC */ for (i = 0; i < rtd->num_codecs; i++) { codec = rtd->codec_dais[i]->codec; - if (codec && codec->probed && - codec->driver->remove_order == order) - soc_remove_codec(codec); + if (codec && codec->component.probed && + codec->component.driver->remove_order == order) + soc_remove_component(&codec->component); } /* remove any CPU-side CODEC */ if (cpu_dai) { codec = cpu_dai->codec; - if (codec && codec->probed && - codec->driver->remove_order == order) - soc_remove_codec(codec); + if (codec && codec->component.probed && + codec->component.driver->remove_order == order) + soc_remove_component(&codec->component); } } @@ -1146,137 +1121,108 @@ static void soc_set_name_prefix(struct snd_soc_card *card, } } -static int soc_probe_codec(struct snd_soc_card *card, - struct snd_soc_codec *codec) +static int soc_probe_component(struct snd_soc_card *card, + struct snd_soc_component *component) { - int ret = 0; - const struct snd_soc_codec_driver *driver = codec->driver; + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + struct snd_soc_component *dai_component, *component2; struct snd_soc_dai *dai; + int ret; - codec->component.card = card; - codec->dapm.card = card; - soc_set_name_prefix(card, &codec->component); + component->card = card; + dapm->card = card; + soc_set_name_prefix(card, component); - if (!try_module_get(codec->dev->driver->owner)) + if (!try_module_get(component->dev->driver->owner)) return -ENODEV; - soc_init_component_debugfs(&codec->component); + soc_init_component_debugfs(component); - if (driver->dapm_widgets) { - ret = snd_soc_dapm_new_controls(&codec->dapm, - driver->dapm_widgets, - driver->num_dapm_widgets); + if (component->dapm_widgets) { + ret = snd_soc_dapm_new_controls(dapm, component->dapm_widgets, + component->num_dapm_widgets); if (ret != 0) { - dev_err(codec->dev, + dev_err(component->dev, "Failed to create new controls %d\n", ret); goto err_probe; } } - /* Create DAPM widgets for each DAI stream */ - list_for_each_entry(dai, &codec->component.dai_list, list) { - ret = snd_soc_dapm_new_dai_widgets(&codec->dapm, dai); + /* + * This is rather ugly, but certain platforms expect that the DAPM + * widgets for the DAIs for components with the same parent device are + * created in the platforms DAPM context. Until that is fixed we need to + * keep this. + */ + if (component->steal_sibling_dai_widgets) { + dai_component = NULL; + list_for_each_entry(component2, &component_list, list) { + if (component == component2) + continue; - if (ret != 0) { - dev_err(codec->dev, - "Failed to create DAI widgets %d\n", ret); - goto err_probe; + if (component2->dev == component->dev && + !list_empty(&component2->dai_list)) { + dai_component = component2; + break; + } + } + } else { + dai_component = component; + list_for_each_entry(component2, &component_list, list) { + if (component2->dev == component->dev && + component2->steal_sibling_dai_widgets) { + dai_component = NULL; + break; + } } } - codec->dapm.idle_bias_off = driver->idle_bias_off; + if (dai_component) { + list_for_each_entry(dai, &dai_component->dai_list, list) { + snd_soc_dapm_new_dai_widgets(dapm, dai); + if (ret != 0) { + dev_err(component->dev, + "Failed to create DAI widgets %d\n", + ret); + goto err_probe; + } + } + } - if (driver->probe) { - ret = driver->probe(codec); + if (component->probe) { + ret = component->probe(component); if (ret < 0) { - dev_err(codec->dev, - "ASoC: failed to probe CODEC %d\n", ret); + dev_err(component->dev, + "ASoC: failed to probe component %d\n", ret); goto err_probe; } - WARN(codec->dapm.idle_bias_off && - codec->dapm.bias_level != SND_SOC_BIAS_OFF, + + WARN(dapm->idle_bias_off && + dapm->bias_level != SND_SOC_BIAS_OFF, "codec %s can not start from non-off bias with idle_bias_off==1\n", - codec->component.name); + component->name); } - if (driver->controls) - snd_soc_add_codec_controls(codec, driver->controls, - driver->num_controls); - if (driver->dapm_routes) - snd_soc_dapm_add_routes(&codec->dapm, driver->dapm_routes, - driver->num_dapm_routes); + if (component->controls) + snd_soc_add_component_controls(component, component->controls, + component->num_controls); + if (component->dapm_routes) + snd_soc_dapm_add_routes(dapm, component->dapm_routes, + component->num_dapm_routes); - /* mark codec as probed and add to card codec list */ - codec->probed = 1; - list_add(&codec->card_list, &card->codec_dev_list); - list_add(&codec->dapm.list, &card->dapm_list); + component->probed = 1; + list_add(&dapm->list, &card->dapm_list); + + /* This is a HACK and will be removed soon */ + if (component->codec) + list_add(&component->codec->card_list, &card->codec_dev_list); return 0; err_probe: - soc_cleanup_component_debugfs(&codec->component); - module_put(codec->dev->driver->owner); - - return ret; -} - -static int soc_probe_platform(struct snd_soc_card *card, - struct snd_soc_platform *platform) -{ - int ret = 0; - const struct snd_soc_platform_driver *driver = platform->driver; - struct snd_soc_component *component; - struct snd_soc_dai *dai; - - platform->component.card = card; - platform->component.dapm.card = card; - - if (!try_module_get(platform->dev->driver->owner)) - return -ENODEV; - - soc_init_component_debugfs(&platform->component); - - if (driver->dapm_widgets) - snd_soc_dapm_new_controls(&platform->component.dapm, - driver->dapm_widgets, driver->num_dapm_widgets); - - /* Create DAPM widgets for each DAI stream */ - list_for_each_entry(component, &component_list, list) { - if (component->dev != platform->dev) - continue; - list_for_each_entry(dai, &component->dai_list, list) - snd_soc_dapm_new_dai_widgets(&platform->component.dapm, - dai); - } - - platform->component.dapm.idle_bias_off = 1; - - if (driver->probe) { - ret = driver->probe(platform); - if (ret < 0) { - dev_err(platform->dev, - "ASoC: failed to probe platform %d\n", ret); - goto err_probe; - } - } - - if (driver->controls) - snd_soc_add_platform_controls(platform, driver->controls, - driver->num_controls); - if (driver->dapm_routes) - snd_soc_dapm_add_routes(&platform->component.dapm, - driver->dapm_routes, driver->num_dapm_routes); - - /* mark platform as probed and add to card platform list */ - platform->probed = 1; - list_add(&platform->component.dapm.list, &card->dapm_list); - - return 0; - -err_probe: - soc_cleanup_component_debugfs(&platform->component); - module_put(platform->dev->driver->owner); + soc_cleanup_component_debugfs(component); + module_put(component->dev->driver->owner); return ret; } @@ -1334,33 +1280,36 @@ static int soc_probe_link_components(struct snd_soc_card *card, int num, int order) { struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_platform *platform = rtd->platform; + struct snd_soc_component *component; int i, ret; /* probe the CPU-side component, if it is a CODEC */ - if (cpu_dai->codec && - !cpu_dai->codec->probed && - cpu_dai->codec->driver->probe_order == order) { - ret = soc_probe_codec(card, cpu_dai->codec); - if (ret < 0) - return ret; + if (rtd->cpu_dai->codec) { + component = &rtd->cpu_dai->codec->component; + if (!component->probed && + component->driver->probe_order == order) { + ret = soc_probe_component(card, component); + if (ret < 0) + return ret; + } } /* probe the CODEC-side components */ for (i = 0; i < rtd->num_codecs; i++) { - if (!rtd->codec_dais[i]->codec->probed && - rtd->codec_dais[i]->codec->driver->probe_order == order) { - ret = soc_probe_codec(card, rtd->codec_dais[i]->codec); + component = &rtd->codec_dais[i]->codec->component; + if (!component->probed && + component->driver->probe_order == order) { + ret = soc_probe_component(card, component); if (ret < 0) return ret; } } /* probe the platform */ - if (!platform->probed && - platform->driver->probe_order == order) { - ret = soc_probe_platform(card, platform); + if (!platform->component.probed && + platform->component.driver->probe_order == order) { + ret = soc_probe_component(card, &platform->component); if (ret < 0) return ret; } @@ -1647,12 +1596,12 @@ static int soc_probe_aux_dev(struct snd_soc_card *card, int num) struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num]; int ret; - if (rtd->codec->probed) { + if (rtd->codec->component.probed) { dev_err(rtd->codec->dev, "ASoC: codec already probed\n"); return -EBUSY; } - ret = soc_probe_codec(card, rtd->codec); + ret = soc_probe_component(card, &rtd->codec->component); if (ret < 0) return ret; @@ -1681,8 +1630,8 @@ static void soc_remove_aux_dev(struct snd_soc_card *card, int num) rtd->dev_registered = 0; } - if (codec && codec->probed) - soc_remove_codec(codec); + if (codec && codec->component.probed) + soc_remove_component(&codec->component); } static int snd_soc_init_codec_cache(struct snd_soc_codec *codec) @@ -4198,6 +4147,20 @@ found: } EXPORT_SYMBOL_GPL(snd_soc_unregister_component); +static int snd_soc_platform_drv_probe(struct snd_soc_component *component) +{ + struct snd_soc_platform *platform = snd_soc_component_to_platform(component); + + return platform->driver->probe(platform); +} + +static void snd_soc_platform_drv_remove(struct snd_soc_component *component) +{ + struct snd_soc_platform *platform = snd_soc_component_to_platform(component); + + platform->driver->remove(platform); +} + static int snd_soc_platform_drv_write(struct snd_soc_component *component, unsigned int reg, unsigned int val) { @@ -4234,6 +4197,24 @@ int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform, platform->dev = dev; platform->driver = platform_drv; + if (platform_drv->controls) { + platform->component.controls = platform_drv->controls; + platform->component.num_controls = platform_drv->num_controls; + } + if (platform_drv->dapm_widgets) { + platform->component.dapm_widgets = platform_drv->dapm_widgets; + platform->component.num_dapm_widgets = platform_drv->num_dapm_widgets; + platform->component.steal_sibling_dai_widgets = true; + } + if (platform_drv->dapm_routes) { + platform->component.dapm_routes = platform_drv->dapm_routes; + platform->component.num_dapm_routes = platform_drv->num_dapm_routes; + } + + if (platform_drv->probe) + platform->component.probe = snd_soc_platform_drv_probe; + if (platform_drv->remove) + platform->component.remove = snd_soc_platform_drv_remove; if (platform_drv->write) platform->component.write = snd_soc_platform_drv_write; if (platform_drv->read) @@ -4363,6 +4344,20 @@ static void fixup_codec_formats(struct snd_soc_pcm_stream *stream) stream->formats |= codec_format_map[i]; } +static int snd_soc_codec_drv_probe(struct snd_soc_component *component) +{ + struct snd_soc_codec *codec = snd_soc_component_to_codec(component); + + return codec->driver->probe(codec); +} + +static void snd_soc_codec_drv_remove(struct snd_soc_component *component) +{ + struct snd_soc_codec *codec = snd_soc_component_to_codec(component); + + codec->driver->remove(codec); +} + static int snd_soc_codec_drv_write(struct snd_soc_component *component, unsigned int reg, unsigned int val) { @@ -4411,12 +4406,30 @@ int snd_soc_register_codec(struct device *dev, return -ENOMEM; codec->component.dapm_ptr = &codec->dapm; + codec->component.codec = codec; ret = snd_soc_component_initialize(&codec->component, &codec_drv->component_driver, dev); if (ret) goto err_free; + if (codec_drv->controls) { + codec->component.controls = codec_drv->controls; + codec->component.num_controls = codec_drv->num_controls; + } + if (codec_drv->dapm_widgets) { + codec->component.dapm_widgets = codec_drv->dapm_widgets; + codec->component.num_dapm_widgets = codec_drv->num_dapm_widgets; + } + if (codec_drv->dapm_routes) { + codec->component.dapm_routes = codec_drv->dapm_routes; + codec->component.num_dapm_routes = codec_drv->num_dapm_routes; + } + + if (codec_drv->probe) + codec->component.probe = snd_soc_codec_drv_probe; + if (codec_drv->remove) + codec->component.remove = snd_soc_codec_drv_remove; if (codec_drv->write) codec->component.write = snd_soc_codec_drv_write; if (codec_drv->read) diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index 6307f85e871b..b329b84bc5af 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -336,10 +336,12 @@ static const struct snd_pcm_ops dmaengine_pcm_ops = { }; static const struct snd_soc_platform_driver dmaengine_pcm_platform = { + .component_driver = { + .probe_order = SND_SOC_COMP_ORDER_LATE, + }, .ops = &dmaengine_pcm_ops, .pcm_new = dmaengine_pcm_new, .pcm_free = dmaengine_pcm_free, - .probe_order = SND_SOC_COMP_ORDER_LATE, }; static const char * const dmaengine_pcm_dma_channel_names[] = { From 93c3ce76ccced3a8718149e8734ccaa931e9a1f1 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 19 Aug 2014 15:51:20 +0200 Subject: [PATCH 043/251] ASoC: Make rtd->codec optional There are some place in the ASoC core that expect rtd->codec to be non NULL (mainly CODEC specific sysfs files). With componentization going forward rtd->codec might be NULL in some cases. This patch prepares the core for this by not registering CODEC specific sysfs files if rtd->codec is NULL. sysfs file removal does not need to be conditionalized as it handles the removal of non-existing files just fine. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index b833cc6fd86d..1c705c28389c 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1261,17 +1261,21 @@ static int soc_post_component_init(struct snd_soc_pcm_runtime *rtd, } rtd->dev_registered = 1; - /* add DAPM sysfs entries for this codec */ - ret = snd_soc_dapm_sys_add(rtd->dev); - if (ret < 0) - dev_err(rtd->dev, - "ASoC: failed to add codec dapm sysfs entries: %d\n", ret); + if (rtd->codec) { + /* add DAPM sysfs entries for this codec */ + ret = snd_soc_dapm_sys_add(rtd->dev); + if (ret < 0) + dev_err(rtd->dev, + "ASoC: failed to add codec dapm sysfs entries: %d\n", + ret); - /* add codec sysfs entries */ - ret = device_create_file(rtd->dev, &dev_attr_codec_reg); - if (ret < 0) - dev_err(rtd->dev, - "ASoC: failed to add codec sysfs files: %d\n", ret); + /* add codec sysfs entries */ + ret = device_create_file(rtd->dev, &dev_attr_codec_reg); + if (ret < 0) + dev_err(rtd->dev, + "ASoC: failed to add codec sysfs files: %d\n", + ret); + } return 0; } From 61aca5646b736a794d40de29a197144db3f0c5ba Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 19 Aug 2014 15:51:21 +0200 Subject: [PATCH 044/251] ASoC: Add component level probe/remove support Now that we have a unified probe and remove path make sure to call them for all components. soc_{probe,remove}_component are responsible for setting up the DAPM context for the component, initialize the component prefix, manage the debugfs entries as well as do the registration of table based controls and DAPM elements. They also call the component drivers probe and remove callbacks. This patch makes these things available for generic snd_soc_component drivers rather than only having them for snd_soc_codec and snd_soc_platform drivers. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- include/sound/soc.h | 11 +++++++++++ sound/soc/soc-core.c | 42 ++++++++++++++++++++++++------------------ 2 files changed, 35 insertions(+), 18 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 22543acfae4b..4a223a895f00 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -690,6 +690,17 @@ struct snd_soc_compr_ops { struct snd_soc_component_driver { const char *name; + /* Default control and setup, added after probe() is run */ + const struct snd_kcontrol_new *controls; + unsigned int num_controls; + const struct snd_soc_dapm_widget *dapm_widgets; + unsigned int num_dapm_widgets; + const struct snd_soc_dapm_route *dapm_routes; + unsigned int num_dapm_routes; + + int (*probe)(struct snd_soc_component *); + void (*remove)(struct snd_soc_component *); + /* DT */ int (*of_xlate_dai_name)(struct snd_soc_component *component, struct of_phandle_args *args, diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 1c705c28389c..08fd85e8c751 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1058,7 +1058,7 @@ static void soc_remove_link_components(struct snd_soc_card *card, int num, struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_platform *platform = rtd->platform; - struct snd_soc_codec *codec; + struct snd_soc_component *component; int i; /* remove the platform */ @@ -1068,18 +1068,17 @@ static void soc_remove_link_components(struct snd_soc_card *card, int num, /* remove the CODEC-side CODEC */ for (i = 0; i < rtd->num_codecs; i++) { - codec = rtd->codec_dais[i]->codec; - if (codec && codec->component.probed && - codec->component.driver->remove_order == order) - soc_remove_component(&codec->component); + component = rtd->codec_dais[i]->component; + if (component->probed && + component->driver->remove_order == order) + soc_remove_component(component); } /* remove any CPU-side CODEC */ if (cpu_dai) { - codec = cpu_dai->codec; - if (codec && codec->component.probed && - codec->component.driver->remove_order == order) - soc_remove_component(&codec->component); + if (cpu_dai->component->probed && + cpu_dai->component->driver->remove_order == order) + soc_remove_component(cpu_dai->component); } } @@ -1289,19 +1288,17 @@ static int soc_probe_link_components(struct snd_soc_card *card, int num, int i, ret; /* probe the CPU-side component, if it is a CODEC */ - if (rtd->cpu_dai->codec) { - component = &rtd->cpu_dai->codec->component; - if (!component->probed && - component->driver->probe_order == order) { - ret = soc_probe_component(card, component); - if (ret < 0) - return ret; - } + component = rtd->cpu_dai->component; + if (!component->probed && + component->driver->probe_order == order) { + ret = soc_probe_component(card, component); + if (ret < 0) + return ret; } /* probe the CODEC-side components */ for (i = 0; i < rtd->num_codecs; i++) { - component = &rtd->codec_dais[i]->codec->component; + component = rtd->codec_dais[i]->component; if (!component->probed && component->driver->probe_order == order) { ret = soc_probe_component(card, component); @@ -4042,6 +4039,8 @@ static int snd_soc_component_initialize(struct snd_soc_component *component, component->dev = dev; component->driver = driver; + component->probe = component->driver->probe; + component->remove = component->driver->remove; if (!component->dapm_ptr) component->dapm_ptr = &component->dapm; @@ -4055,6 +4054,13 @@ static int snd_soc_component_initialize(struct snd_soc_component *component, if (driver->stream_event) dapm->stream_event = snd_soc_component_stream_event; + component->controls = driver->controls; + component->num_controls = driver->num_controls; + component->dapm_widgets = driver->dapm_widgets; + component->num_dapm_widgets = driver->num_dapm_widgets; + component->dapm_routes = driver->dapm_routes; + component->num_dapm_routes = driver->num_dapm_routes; + INIT_LIST_HEAD(&component->dai_list); mutex_init(&component->io_mutex); From 65d9361f0cb50a20641802ee3075145d72e4409c Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 19 Aug 2014 15:51:22 +0200 Subject: [PATCH 045/251] ASoC: Move AUX dev support to the component level This patch makes it possible to register arbitrary components as a AUX dev for a card. This was previously only possible for CODEC components. With componentization having made it possible for components to have DAPM contexts and controls there is no reason why AUX devs should be artificially limited to snd_soc_codec devices. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- include/sound/soc.h | 1 + sound/soc/soc-core.c | 48 +++++++++++++++++++++++++++++++++----------- 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 4a223a895f00..fbc2ad840244 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1140,6 +1140,7 @@ struct snd_soc_pcm_runtime { struct snd_soc_platform *platform; struct snd_soc_dai *codec_dai; struct snd_soc_dai *cpu_dai; + struct snd_soc_component *component; /* Only valid for AUX dev rtds */ struct snd_soc_dai **codec_dais; unsigned int num_codecs; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 08fd85e8c751..08c04f4c7e62 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -860,6 +860,23 @@ EXPORT_SYMBOL_GPL(snd_soc_resume); static const struct snd_soc_dai_ops null_dai_ops = { }; +static struct snd_soc_component *soc_find_component( + const struct device_node *of_node, const char *name) +{ + struct snd_soc_component *component; + + list_for_each_entry(component, &component_list, list) { + if (of_node) { + if (component->dev->of_node == of_node) + return component; + } else if (strcmp(component->name, name) == 0) { + return component; + } + } + + return NULL; +} + static struct snd_soc_codec *soc_find_codec( const struct device_node *codec_of_node, const char *codec_name) @@ -1577,17 +1594,24 @@ static int soc_bind_aux_dev(struct snd_soc_card *card, int num) { struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num]; struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num]; - const char *codecname = aux_dev->codec_name; + const char *name = aux_dev->codec_name; - rtd->codec = soc_find_codec(aux_dev->codec_of_node, codecname); - if (!rtd->codec) { + rtd->component = soc_find_component(aux_dev->codec_of_node, name); + if (!rtd->component) { if (aux_dev->codec_of_node) - codecname = of_node_full_name(aux_dev->codec_of_node); + name = of_node_full_name(aux_dev->codec_of_node); - dev_err(card->dev, "ASoC: %s not registered\n", codecname); + dev_err(card->dev, "ASoC: %s not registered\n", name); return -EPROBE_DEFER; } + /* + * Some places still reference rtd->codec, so we have to keep that + * initialized if the component is a CODEC. Once all those references + * have been removed, this code can be removed as well. + */ + rtd->codec = rtd->component->codec; + return 0; } @@ -1597,18 +1621,18 @@ static int soc_probe_aux_dev(struct snd_soc_card *card, int num) struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num]; int ret; - if (rtd->codec->component.probed) { - dev_err(rtd->codec->dev, "ASoC: codec already probed\n"); + if (rtd->component->probed) { + dev_err(rtd->dev, "ASoC: codec already probed\n"); return -EBUSY; } - ret = soc_probe_component(card, &rtd->codec->component); + ret = soc_probe_component(card, rtd->component); if (ret < 0) return ret; /* do machine specific initialization */ if (aux_dev->init) { - ret = aux_dev->init(&rtd->codec->dapm); + ret = aux_dev->init(snd_soc_component_get_dapm(rtd->component)); if (ret < 0) { dev_err(card->dev, "ASoC: failed to init %s: %d\n", aux_dev->name, ret); @@ -1622,7 +1646,7 @@ static int soc_probe_aux_dev(struct snd_soc_card *card, int num) static void soc_remove_aux_dev(struct snd_soc_card *card, int num) { struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num]; - struct snd_soc_codec *codec = rtd->codec; + struct snd_soc_component *component = rtd->component; /* unregister the rtd device */ if (rtd->dev_registered) { @@ -1631,8 +1655,8 @@ static void soc_remove_aux_dev(struct snd_soc_card *card, int num) rtd->dev_registered = 0; } - if (codec && codec->component.probed) - soc_remove_component(&codec->component); + if (component && component->probed) + soc_remove_component(component); } static int snd_soc_init_codec_cache(struct snd_soc_codec *codec) From 57bf772687700e206c760ba2e4097f78bde97887 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 19 Aug 2014 15:51:23 +0200 Subject: [PATCH 046/251] ASoC: Pass component instead of DAPM context to AUX dev init callback Given that the component is the containing structure it makes more sense to pass the component rather than the DAPM context to the AUX dev init callback. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- include/sound/soc.h | 2 +- sound/soc/samsung/speyside.c | 6 ++++-- sound/soc/soc-core.c | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index fbc2ad840244..3a0031e1f9b4 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1022,7 +1022,7 @@ struct snd_soc_aux_dev { const struct device_node *codec_of_node; /* codec/machine specific init - e.g. add machine controls */ - int (*init)(struct snd_soc_dapm_context *dapm); + int (*init)(struct snd_soc_component *component); }; /* SoC card */ diff --git a/sound/soc/samsung/speyside.c b/sound/soc/samsung/speyside.c index 9902efcb8ea1..a05482651aae 100644 --- a/sound/soc/samsung/speyside.c +++ b/sound/soc/samsung/speyside.c @@ -228,10 +228,12 @@ static struct snd_soc_dai_link speyside_dai[] = { }, }; -static int speyside_wm9081_init(struct snd_soc_dapm_context *dapm) +static int speyside_wm9081_init(struct snd_soc_component *component) { + struct snd_soc_codec *codec = snd_soc_component_to_codec(component); + /* At any time the WM9081 is active it will have this clock */ - return snd_soc_codec_set_sysclk(dapm->codec, WM9081_SYSCLK_MCLK, 0, + return snd_soc_codec_set_sysclk(codec, WM9081_SYSCLK_MCLK, 0, MCLK_AUDIO_RATE, 0); } diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 08c04f4c7e62..4393bc33d3af 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1632,7 +1632,7 @@ static int soc_probe_aux_dev(struct snd_soc_card *card, int num) /* do machine specific initialization */ if (aux_dev->init) { - ret = aux_dev->init(snd_soc_component_get_dapm(rtd->component)); + ret = aux_dev->init(rtd->component); if (ret < 0) { dev_err(card->dev, "ASoC: failed to init %s: %d\n", aux_dev->name, ret); From 70090bbb8b7d7da7a6f64969b43a61c493c560ff Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 19 Aug 2014 15:51:24 +0200 Subject: [PATCH 047/251] ASoC: Move component->probed check into soc_{remove,probe}_component() Having the check in a centralized place makes the code a bit cleaner and shorter. Note: There is a slight semantic change in this patch. soc_probe_aux_dev() will no longer return -EBUSY if the AUX dev has already been probed before. This is fine though since it will simply do nothing in that case and return success. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 4393bc33d3af..2fbfbfca48dc 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1004,6 +1004,9 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) static void soc_remove_component(struct snd_soc_component *component) { + if (!component->probed) + return; + /* This is a HACK and will be removed soon */ if (component->codec) list_del(&component->codec->card_list); @@ -1079,22 +1082,19 @@ static void soc_remove_link_components(struct snd_soc_card *card, int num, int i; /* remove the platform */ - if (platform && platform->component.probed && - platform->component.driver->remove_order == order) + if (platform && platform->component.driver->remove_order == order) soc_remove_component(&platform->component); /* remove the CODEC-side CODEC */ for (i = 0; i < rtd->num_codecs; i++) { component = rtd->codec_dais[i]->component; - if (component->probed && - component->driver->remove_order == order) + if (component->driver->remove_order == order) soc_remove_component(component); } /* remove any CPU-side CODEC */ if (cpu_dai) { - if (cpu_dai->component->probed && - cpu_dai->component->driver->remove_order == order) + if (cpu_dai->component->driver->remove_order == order) soc_remove_component(cpu_dai->component); } } @@ -1145,6 +1145,9 @@ static int soc_probe_component(struct snd_soc_card *card, struct snd_soc_dai *dai; int ret; + if (component->probed) + return 0; + component->card = card; dapm->card = card; soc_set_name_prefix(card, component); @@ -1306,8 +1309,7 @@ static int soc_probe_link_components(struct snd_soc_card *card, int num, /* probe the CPU-side component, if it is a CODEC */ component = rtd->cpu_dai->component; - if (!component->probed && - component->driver->probe_order == order) { + if (component->driver->probe_order == order) { ret = soc_probe_component(card, component); if (ret < 0) return ret; @@ -1316,8 +1318,7 @@ static int soc_probe_link_components(struct snd_soc_card *card, int num, /* probe the CODEC-side components */ for (i = 0; i < rtd->num_codecs; i++) { component = rtd->codec_dais[i]->component; - if (!component->probed && - component->driver->probe_order == order) { + if (component->driver->probe_order == order) { ret = soc_probe_component(card, component); if (ret < 0) return ret; @@ -1325,8 +1326,7 @@ static int soc_probe_link_components(struct snd_soc_card *card, int num, } /* probe the platform */ - if (!platform->component.probed && - platform->component.driver->probe_order == order) { + if (platform->component.driver->probe_order == order) { ret = soc_probe_component(card, &platform->component); if (ret < 0) return ret; @@ -1621,11 +1621,6 @@ static int soc_probe_aux_dev(struct snd_soc_card *card, int num) struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num]; int ret; - if (rtd->component->probed) { - dev_err(rtd->dev, "ASoC: codec already probed\n"); - return -EBUSY; - } - ret = soc_probe_component(card, rtd->component); if (ret < 0) return ret; From ffbd7dd72bd3ad9bcae9190788c858e57f1e8e4e Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 19 Aug 2014 15:51:25 +0200 Subject: [PATCH 048/251] ASoC: Cleanup DAI module reference counting Currently when a DAI has no CODEC associated to it the reference on the module containing the DAI driver is increased when the DAI is probed and decrease when the DAI is removed. For DAIs with CODECs the module reference count was already incremented when the CODEC is probed. Now that all components have their module reference count incremented when they are probed and all DAIs do have a component it is possible to remove the module reference counting on DAI probe and removal. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 2fbfbfca48dc..4dc2876c06de 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1067,8 +1067,6 @@ static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order) cpu_dai->name, err); } cpu_dai->probed = 0; - if (!cpu_dai->codec) - module_put(cpu_dai->dev->driver->owner); } } @@ -1422,18 +1420,12 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order) /* probe the cpu_dai */ if (!cpu_dai->probed && cpu_dai->driver->probe_order == order) { - if (!cpu_dai->codec) { - if (!try_module_get(cpu_dai->dev->driver->owner)) - return -ENODEV; - } - if (cpu_dai->driver->probe) { ret = cpu_dai->driver->probe(cpu_dai); if (ret < 0) { dev_err(cpu_dai->dev, "ASoC: failed to probe CPU DAI %s: %d\n", cpu_dai->name, ret); - module_put(cpu_dai->dev->driver->owner); return ret; } } From e60cd14f0bf6c004cd7032a24a036ba32d56e08a Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 19 Aug 2014 15:51:26 +0200 Subject: [PATCH 049/251] ASoC: Consolidate CPU and CODEC DAI removal CPU and CODEC DAI works exactly the same way. There is already a helper function for CODEC DAI removal, use that one as well for CPU DAI removal. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 34 +++++++++++----------------------- 1 file changed, 11 insertions(+), 23 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 4dc2876c06de..5f6f97874ca2 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1021,28 +1021,27 @@ static void soc_remove_component(struct snd_soc_component *component) module_put(component->dev->driver->owner); } -static void soc_remove_codec_dai(struct snd_soc_dai *codec_dai, int order) +static void soc_remove_dai(struct snd_soc_dai *dai, int order) { int err; - if (codec_dai && codec_dai->probed && - codec_dai->driver->remove_order == order) { - if (codec_dai->driver->remove) { - err = codec_dai->driver->remove(codec_dai); + if (dai && dai->probed && + dai->driver->remove_order == order) { + if (dai->driver->remove) { + err = dai->driver->remove(dai); if (err < 0) - dev_err(codec_dai->dev, + dev_err(dai->dev, "ASoC: failed to remove %s: %d\n", - codec_dai->name, err); + dai->name, err); } - codec_dai->probed = 0; + dai->probed = 0; } } static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order) { struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - int i, err; + int i; /* unregister the rtd device */ if (rtd->dev_registered) { @@ -1054,20 +1053,9 @@ static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order) /* remove the CODEC DAI */ for (i = 0; i < rtd->num_codecs; i++) - soc_remove_codec_dai(rtd->codec_dais[i], order); + soc_remove_dai(rtd->codec_dais[i], order); - /* remove the cpu_dai */ - if (cpu_dai && cpu_dai->probed && - cpu_dai->driver->remove_order == order) { - if (cpu_dai->driver->remove) { - err = cpu_dai->driver->remove(cpu_dai); - if (err < 0) - dev_err(cpu_dai->dev, - "ASoC: failed to remove %s: %d\n", - cpu_dai->name, err); - } - cpu_dai->probed = 0; - } + soc_remove_dai(rtd->cpu_dai, order); } static void soc_remove_link_components(struct snd_soc_card *card, int num, From 14621c7e5e72200ec021a7580121130ce7f2ff22 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 19 Aug 2014 15:51:27 +0200 Subject: [PATCH 050/251] ASoC: Consolidate CPU and CODEC DAI lookup The lookup of CPU and CODEC DAIs is fairly similar and can easily be consolidated into a single helper function. There are two main differences in the current implementation of the CPU and CODEC DAI lookup: 1) CPU DAIs can be looked up by the DAI name alone and do not necessarily require a component name/of_node. 2) The CODEC DAI search only considers DAIs from CODEC components. For 1) the new helper function will allow to lookup DAIs without providing a component name or of_node, but since snd_soc_register_card() already rejects CODEC DAI link components without neither a of_node or a name we'll never get into the situation where we try to lookup a CODEC DAI without a name/of_node. For 2) the new helper function just always considers all components. Componentization is now at a point where it is possible to register a CODEC as a snd_soc_component rather than a snd_soc_codec, by considering DAIs from all components it is possible to use such a CODEC in a DAI link. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 72 ++++++++++++-------------------------------- 1 file changed, 19 insertions(+), 53 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 5f6f97874ca2..140f43f91635 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -877,35 +877,23 @@ static struct snd_soc_component *soc_find_component( return NULL; } -static struct snd_soc_codec *soc_find_codec( - const struct device_node *codec_of_node, - const char *codec_name) +static struct snd_soc_dai *snd_soc_find_dai( + const struct snd_soc_dai_link_component *dlc) { - struct snd_soc_codec *codec; + struct snd_soc_component *component; + struct snd_soc_dai *dai; - list_for_each_entry(codec, &codec_list, list) { - if (codec_of_node) { - if (codec->dev->of_node != codec_of_node) + /* Find CPU DAI from registered DAIs*/ + list_for_each_entry(component, &component_list, list) { + if (dlc->of_node && component->dev->of_node != dlc->of_node) + continue; + if (dlc->name && strcmp(dev_name(component->dev), dlc->name)) + continue; + list_for_each_entry(dai, &component->dai_list, list) { + if (dlc->dai_name && strcmp(dai->name, dlc->dai_name)) continue; - } else { - if (strcmp(codec->component.name, codec_name)) - continue; - } - return codec; - } - - return NULL; -} - -static struct snd_soc_dai *soc_find_codec_dai(struct snd_soc_codec *codec, - const char *codec_dai_name) -{ - struct snd_soc_dai *codec_dai; - - list_for_each_entry(codec_dai, &codec->component.dai_list, list) { - if (!strcmp(codec_dai->name, codec_dai_name)) { - return codec_dai; + return dai; } } @@ -916,33 +904,19 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) { struct snd_soc_dai_link *dai_link = &card->dai_link[num]; struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; - struct snd_soc_component *component; struct snd_soc_dai_link_component *codecs = dai_link->codecs; + struct snd_soc_dai_link_component cpu_dai_component; struct snd_soc_dai **codec_dais = rtd->codec_dais; struct snd_soc_platform *platform; - struct snd_soc_dai *cpu_dai; const char *platform_name; int i; dev_dbg(card->dev, "ASoC: binding %s at idx %d\n", dai_link->name, num); - /* Find CPU DAI from registered DAIs*/ - list_for_each_entry(component, &component_list, list) { - if (dai_link->cpu_of_node && - component->dev->of_node != dai_link->cpu_of_node) - continue; - if (dai_link->cpu_name && - strcmp(dev_name(component->dev), dai_link->cpu_name)) - continue; - list_for_each_entry(cpu_dai, &component->dai_list, list) { - if (dai_link->cpu_dai_name && - strcmp(cpu_dai->name, dai_link->cpu_dai_name)) - continue; - - rtd->cpu_dai = cpu_dai; - } - } - + cpu_dai_component.name = dai_link->cpu_name; + cpu_dai_component.of_node = dai_link->cpu_of_node; + cpu_dai_component.dai_name = dai_link->cpu_dai_name; + rtd->cpu_dai = snd_soc_find_dai(&cpu_dai_component); if (!rtd->cpu_dai) { dev_err(card->dev, "ASoC: CPU DAI %s not registered\n", dai_link->cpu_dai_name); @@ -953,15 +927,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) /* Find CODEC from registered CODECs */ for (i = 0; i < rtd->num_codecs; i++) { - struct snd_soc_codec *codec; - codec = soc_find_codec(codecs[i].of_node, codecs[i].name); - if (!codec) { - dev_err(card->dev, "ASoC: CODEC %s not registered\n", - codecs[i].name); - return -EPROBE_DEFER; - } - - codec_dais[i] = soc_find_codec_dai(codec, codecs[i].dai_name); + codec_dais[i] = snd_soc_find_dai(&codecs[i]); if (!codec_dais[i]) { dev_err(card->dev, "ASoC: CODEC DAI %s not registered\n", codecs[i].dai_name); From 886f5692253de1a9509f5cb708432b2157afb57c Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 19 Aug 2014 15:51:28 +0200 Subject: [PATCH 051/251] ASoC: Automatically initialize regmap for all components So far regmap is only automatically initialized for CODECs. Now that we have the infrastructure in place to let components have DAPM widgets and controls that want to use the generic regmap based IO also make sure to automatically initialize regmap for all components. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- include/sound/soc.h | 3 --- sound/soc/soc-core.c | 35 +++++++++++++++++------------------ sound/soc/soc-io.c | 28 ---------------------------- 3 files changed, 17 insertions(+), 49 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 3a0031e1f9b4..8ebee30311e3 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1289,9 +1289,6 @@ void snd_soc_component_async_complete(struct snd_soc_component *component); int snd_soc_component_test_bits(struct snd_soc_component *component, unsigned int reg, unsigned int mask, unsigned int value); -int snd_soc_component_init_io(struct snd_soc_component *component, - struct regmap *regmap); - /* device driver data */ static inline void snd_soc_card_set_drvdata(struct snd_soc_card *card, diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 140f43f91635..96f286643ca1 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -4032,8 +4032,23 @@ static int snd_soc_component_initialize(struct snd_soc_component *component, return 0; } +static void snd_soc_component_init_regmap(struct snd_soc_component *component) +{ + if (!component->regmap) + component->regmap = dev_get_regmap(component->dev, NULL); + if (component->regmap) { + int val_bytes = regmap_get_val_bytes(component->regmap); + /* Errors are legitimate for non-integer byte multiples */ + if (val_bytes > 0) + component->val_bytes = val_bytes; + } +} + static void snd_soc_component_add_unlocked(struct snd_soc_component *component) { + if (!component->write && !component->read) + snd_soc_component_init_regmap(component); + list_add(&component->list, &component_list); } @@ -4371,7 +4386,6 @@ int snd_soc_register_codec(struct device *dev, { struct snd_soc_codec *codec; struct snd_soc_dai *dai; - struct regmap *regmap; int ret, i; dev_dbg(dev, "codec register %s\n", dev_name(dev)); @@ -4425,23 +4439,8 @@ int snd_soc_register_codec(struct device *dev, codec->component.debugfs_prefix = "codec"; #endif - if (!codec->component.write) { - if (codec_drv->get_regmap) - regmap = codec_drv->get_regmap(dev); - else - regmap = dev_get_regmap(dev, NULL); - - if (regmap) { - ret = snd_soc_component_init_io(&codec->component, - regmap); - if (ret) { - dev_err(codec->dev, - "Failed to set cache I/O:%d\n", - ret); - goto err_cleanup; - } - } - } + if (codec_drv->get_regmap) + codec->component.regmap = codec_drv->get_regmap(dev); for (i = 0; i < num_dai; i++) { fixup_codec_formats(&dai_drv[i].playback); diff --git a/sound/soc/soc-io.c b/sound/soc/soc-io.c index 7767fbd73eb7..9b3939049cef 100644 --- a/sound/soc/soc-io.c +++ b/sound/soc/soc-io.c @@ -271,31 +271,3 @@ int snd_soc_platform_write(struct snd_soc_platform *platform, return snd_soc_component_write(&platform->component, reg, val); } EXPORT_SYMBOL_GPL(snd_soc_platform_write); - -/** - * snd_soc_component_init_io() - Initialize regmap IO - * - * @component: component to initialize - * @regmap: regmap instance to use for IO operations - * - * Return: 0 on success, a negative error code otherwise - */ -int snd_soc_component_init_io(struct snd_soc_component *component, - struct regmap *regmap) -{ - int ret; - - if (!regmap) - return -EINVAL; - - ret = regmap_get_val_bytes(regmap); - /* Errors are legitimate for non-integer byte - * multiples */ - if (ret > 0) - component->val_bytes = ret; - - component->regmap = regmap; - - return 0; -} -EXPORT_SYMBOL_GPL(snd_soc_component_init_io); From 75af7c081982d76cef0daf26e96b5d1e8cb9d631 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 19 Aug 2014 15:51:29 +0200 Subject: [PATCH 052/251] ASoC: Remove support for legacy snd_soc_platform IO There were never any actual users of this in upstream and by we have with regmap a replacement in place, which should be used by new drivers. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- include/sound/soc.h | 3 --- sound/soc/soc-core.c | 22 ---------------------- 2 files changed, 25 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 8ebee30311e3..edbb0d72ab38 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -890,9 +890,6 @@ struct snd_soc_platform_driver { /* platform stream compress ops */ const struct snd_compr_ops *compr_ops; - /* platform IO - used for platform DAPM */ - unsigned int (*read)(struct snd_soc_platform *, unsigned int); - int (*write)(struct snd_soc_platform *, unsigned int, unsigned int); int (*bespoke_trigger)(struct snd_pcm_substream *, int); }; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 96f286643ca1..2d7a9ecbb0e3 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -4151,24 +4151,6 @@ static void snd_soc_platform_drv_remove(struct snd_soc_component *component) platform->driver->remove(platform); } -static int snd_soc_platform_drv_write(struct snd_soc_component *component, - unsigned int reg, unsigned int val) -{ - struct snd_soc_platform *platform = snd_soc_component_to_platform(component); - - return platform->driver->write(platform, reg, val); -} - -static int snd_soc_platform_drv_read(struct snd_soc_component *component, - unsigned int reg, unsigned int *val) -{ - struct snd_soc_platform *platform = snd_soc_component_to_platform(component); - - *val = platform->driver->read(platform, reg); - - return 0; -} - /** * snd_soc_add_platform - Add a platform to the ASoC core * @dev: The parent device for the platform @@ -4205,10 +4187,6 @@ int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform, platform->component.probe = snd_soc_platform_drv_probe; if (platform_drv->remove) platform->component.remove = snd_soc_platform_drv_remove; - if (platform_drv->write) - platform->component.write = snd_soc_platform_drv_write; - if (platform_drv->read) - platform->component.read = snd_soc_platform_drv_read; #ifdef CONFIG_DEBUG_FS platform->component.debugfs_prefix = "platform"; From c5599b87a8317738a541d8893cb327df5d04b007 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 19 Aug 2014 15:51:30 +0200 Subject: [PATCH 053/251] ASoC: Replace list_empty(&card->codec_dev_list) with !card->instantiated With componentization we no longer necessarily need a snd_soc_codec struct for a card. Instead of checking if the card's CODEC list is empty just use card->instantiated to check if the card has been instantiated yet. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 2d7a9ecbb0e3..c36983a133fa 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -552,10 +552,8 @@ int snd_soc_suspend(struct device *dev) struct snd_soc_codec *codec; int i, j; - /* If the initialization of this soc device failed, there is no codec - * associated with it. Just bail out in this case. - */ - if (list_empty(&card->codec_dev_list)) + /* If the card is not initialized yet there is nothing to do */ + if (!card->instantiated) return 0; /* Due to the resume being scheduled into a workqueue we could @@ -808,10 +806,8 @@ int snd_soc_resume(struct device *dev) struct snd_soc_card *card = dev_get_drvdata(dev); int i, ac97_control = 0; - /* If the initialization of this soc device failed, there is no codec - * associated with it. Just bail out in this case. - */ - if (list_empty(&card->codec_dev_list)) + /* If the card is not initialized yet there is nothing to do */ + if (!card->instantiated) return 0; /* activate pins from sleep state */ From 38c6e4bb67760db1392b9c5ee0082af07c0db20d Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Tue, 19 Aug 2014 17:36:41 +0800 Subject: [PATCH 054/251] ASoC: fsl-asoc-card: move 'config SND_SOC_FSL_ASOC_CARD' to 'if SND_IMX_SOC' Build kernel with SND_SOC_FSL_ASOC_CARD=m && SND_SOC_FSL_{SSI,SAI,ESAI}=y leads the following error: sound/built-in.o: In function `fsl_sai_probe': >> fsl_sai.c:(.text+0x5f662): undefined reference to `imx_pcm_dma_init' sound/built-in.o: In function `fsl_esai_probe': >> fsl_esai.c:(.text+0x6044b): undefined reference to `imx_pcm_dma_init' The config SND_SOC_FSL_ASOC_CARD is for IMX SOC, So move it under condition of 'if SND_IMX_SOC'. Reported-by: kbuild test robot Signed-off-by: Shengjiu Wang Signed-off-by: Mark Brown --- sound/soc/fsl/Kconfig | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 3154f43b11ab..7c1da8ede975 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -59,23 +59,6 @@ config SND_SOC_FSL_ESAI config SND_SOC_FSL_UTILS tristate -config SND_SOC_FSL_ASOC_CARD - tristate "Generic ASoC Sound Card with ASRC support" - depends on OF && I2C - select SND_SOC_IMX_AUDMUX - select SND_SOC_IMX_PCM_DMA - select SND_SOC_FSL_ESAI - select SND_SOC_FSL_SAI - select SND_SOC_FSL_SSI - select SND_SOC_CS42XX8_I2C - select SND_SOC_SGTL5000 - select SND_SOC_WM8962 - help - ALSA SoC Audio support with ASRC feature for Freescale SoCs that have - ESAI/SAI/SSI and connect with external CODECs such as WM8962, CS42888 - and SGTL5000. - Say Y if you want to add support for Freescale Generic ASoC Sound Card. - config SND_SOC_IMX_PCM_DMA tristate select SND_SOC_GENERIC_DMAENGINE_PCM @@ -298,6 +281,23 @@ config SND_SOC_IMX_MC13783 select SND_SOC_MC13783 select SND_SOC_IMX_PCM_DMA +config SND_SOC_FSL_ASOC_CARD + tristate "Generic ASoC Sound Card with ASRC support" + depends on OF && I2C + select SND_SOC_IMX_AUDMUX + select SND_SOC_IMX_PCM_DMA + select SND_SOC_FSL_ESAI + select SND_SOC_FSL_SAI + select SND_SOC_FSL_SSI + select SND_SOC_CS42XX8_I2C + select SND_SOC_SGTL5000 + select SND_SOC_WM8962 + help + ALSA SoC Audio support with ASRC feature for Freescale SoCs that have + ESAI/SAI/SSI and connect with external CODECs such as WM8962, CS42888 + and SGTL5000. + Say Y if you want to add support for Freescale Generic ASoC Sound Card. + endif # SND_IMX_SOC endmenu From 5d0ecb0e7dd53e61e034bac8508d7601b04e679d Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 19 Aug 2014 17:48:06 +0200 Subject: [PATCH 055/251] ASoC: sh: Don't opencode DMAengine API calls Use the proper wrapper functions instead of directly calling the DMAengine callback functions. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/sh/siu_pcm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/sh/siu_pcm.c b/sound/soc/sh/siu_pcm.c index 488f9becb44f..32eb6da2d2bd 100644 --- a/sound/soc/sh/siu_pcm.c +++ b/sound/soc/sh/siu_pcm.c @@ -139,7 +139,7 @@ static int siu_pcm_wr_set(struct siu_port *port_info, desc->callback = siu_dma_tx_complete; desc->callback_param = siu_stream; - cookie = desc->tx_submit(desc); + cookie = dmaengine_submit(desc); if (cookie < 0) { dev_err(dev, "Failed to submit a dma transfer\n"); return cookie; @@ -189,7 +189,7 @@ static int siu_pcm_rd_set(struct siu_port *port_info, desc->callback = siu_dma_tx_complete; desc->callback_param = siu_stream; - cookie = desc->tx_submit(desc); + cookie = dmaengine_submit(desc); if (cookie < 0) { dev_err(dev, "Failed to submit dma descriptor\n"); return cookie; From ff495d3a8ea4d46d237096e6521b24b7ba612e53 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 19 Aug 2014 17:48:07 +0200 Subject: [PATCH 056/251] ASoC: txx9: Don't opencode DMAengine API calls Use the proper wrapper functions instead of directly calling the DMAengine callback functions. Also add the missing include to linux/dmaengine.h. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/txx9/txx9aclc.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sound/soc/txx9/txx9aclc.c b/sound/soc/txx9/txx9aclc.c index f0829de28708..cd71fd889d8b 100644 --- a/sound/soc/txx9/txx9aclc.c +++ b/sound/soc/txx9/txx9aclc.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -137,7 +138,7 @@ txx9aclc_dma_submit(struct txx9aclc_dmadata *dmadata, dma_addr_t buf_dma_addr) } desc->callback = txx9aclc_dma_complete; desc->callback_param = dmadata; - desc->tx_submit(desc); + dmaengine_submit(desc); return desc; } @@ -160,7 +161,7 @@ static void txx9aclc_dma_tasklet(unsigned long data) void __iomem *base = drvdata->base; spin_unlock_irqrestore(&dmadata->dma_lock, flags); - chan->device->device_control(chan, DMA_TERMINATE_ALL, 0); + dmaengine_terminate_all(chan); /* first time */ for (i = 0; i < NR_DMA_CHAIN; i++) { desc = txx9aclc_dma_submit(dmadata, @@ -169,7 +170,7 @@ static void txx9aclc_dma_tasklet(unsigned long data) return; } dmadata->dmacount = NR_DMA_CHAIN; - chan->device->device_issue_pending(chan); + dma_async_issue_pending(chan); spin_lock_irqsave(&dmadata->dma_lock, flags); __raw_writel(ctlbit, base + ACCTLEN); dmadata->frag_count = NR_DMA_CHAIN % dmadata->frags; @@ -188,7 +189,7 @@ static void txx9aclc_dma_tasklet(unsigned long data) dmadata->frag_count * dmadata->frag_bytes); if (!desc) return; - chan->device->device_issue_pending(chan); + dma_async_issue_pending(chan); spin_lock_irqsave(&dmadata->dma_lock, flags); dmadata->frag_count++; @@ -266,7 +267,7 @@ static int txx9aclc_pcm_close(struct snd_pcm_substream *substream) struct dma_chan *chan = dmadata->dma_chan; dmadata->frag_count = -1; - chan->device->device_control(chan, DMA_TERMINATE_ALL, 0); + dmaengine_terminate_all(chan); return 0; } @@ -398,8 +399,7 @@ static int txx9aclc_pcm_remove(struct snd_soc_platform *platform) struct dma_chan *chan = dmadata->dma_chan; if (chan) { dmadata->frag_count = -1; - chan->device->device_control(chan, - DMA_TERMINATE_ALL, 0); + dmaengine_terminate_all(chan); dma_release_channel(chan); } dev->dmadata[i].dma_chan = NULL; From a18a32ce22d8b0e3174c0633fa61e46aac39e81e Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 23 Aug 2014 11:05:21 +0200 Subject: [PATCH 057/251] ASoC: ac97-codec: Remove ASoC level IO support This driver doesn't use any ASoC level IO nor does it register any controls or DAPM elements that require it. This means it can safely be removed. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/ac97.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c index e889e1b84192..bd9b1839c8b0 100644 --- a/sound/soc/codecs/ac97.c +++ b/sound/soc/codecs/ac97.c @@ -69,19 +69,6 @@ static struct snd_soc_dai_driver ac97_dai = { .ops = &ac97_dai_ops, }; -static unsigned int ac97_read(struct snd_soc_codec *codec, - unsigned int reg) -{ - return soc_ac97_ops->read(codec->ac97, reg); -} - -static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int val) -{ - soc_ac97_ops->write(codec->ac97, reg, val); - return 0; -} - static int ac97_soc_probe(struct snd_soc_codec *codec) { struct snd_ac97_bus *ac97_bus; @@ -122,8 +109,6 @@ static int ac97_soc_resume(struct snd_soc_codec *codec) #endif static struct snd_soc_codec_driver soc_codec_dev_ac97 = { - .write = ac97_write, - .read = ac97_read, .probe = ac97_soc_probe, .suspend = ac97_soc_suspend, .resume = ac97_soc_resume, From 57f2d8b797c4c8d9e65e3b9fae98246be5a93df3 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Mon, 25 Aug 2014 19:04:52 +0530 Subject: [PATCH 058/251] ALSA: ctxfi: ctpcm.c: printk replacement replaced printk with corresponding pr_err Signed-off-by: Sudip Mukherjee Signed-off-by: Takashi Iwai --- sound/pci/ctxfi/ctpcm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/pci/ctxfi/ctpcm.c b/sound/pci/ctxfi/ctpcm.c index e8a4feb1ed86..6826c2c02c44 100644 --- a/sound/pci/ctxfi/ctpcm.c +++ b/sound/pci/ctxfi/ctpcm.c @@ -217,7 +217,7 @@ static int ct_pcm_playback_prepare(struct snd_pcm_substream *substream) err = atc->pcm_playback_prepare(atc, apcm); if (err < 0) { - printk(KERN_ERR "ctxfi: Preparing pcm playback failed!!!\n"); + pr_err("ctxfi: Preparing pcm playback failed!!!\n"); return err; } @@ -324,7 +324,7 @@ static int ct_pcm_capture_prepare(struct snd_pcm_substream *substream) err = atc->pcm_capture_prepare(atc, apcm); if (err < 0) { - printk(KERN_ERR "ctxfi: Preparing pcm capture failed!!!\n"); + pr_err("ctxfi: Preparing pcm capture failed!!!\n"); return err; } @@ -435,7 +435,7 @@ int ct_alsa_pcm_create(struct ct_atc *atc, err = snd_pcm_new(atc->card, "ctxfi", device, playback_count, capture_count, &pcm); if (err < 0) { - printk(KERN_ERR "ctxfi: snd_pcm_new failed!! Err=%d\n", err); + pr_err("ctxfi: snd_pcm_new failed!! Err=%d\n", err); return err; } From 5819c2fa55d4a6eaf7fe025a393dce98fc4b2116 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 24 Aug 2014 15:36:55 +0200 Subject: [PATCH 059/251] ASoC: Restore idle_bias_off initialization This was accidentally lost in commit f1d45cc3ae96 ("ASoC: Consolidate platform and CODEC probe/remove"). Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index c36983a133fa..419682693886 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -4010,6 +4010,7 @@ static int snd_soc_component_initialize(struct snd_soc_component *component, dapm->dev = dev; dapm->component = component; dapm->bias_level = SND_SOC_BIAS_OFF; + dapm->idle_bias_off = true; if (driver->seq_notifier) dapm->seq_notifier = snd_soc_component_seq_notifier; if (driver->stream_event) @@ -4399,6 +4400,7 @@ int snd_soc_register_codec(struct device *dev, codec->component.read = snd_soc_codec_drv_read; codec->component.ignore_pmdown_time = codec_drv->ignore_pmdown_time; codec->dapm.codec = codec; + codec->dapm.idle_bias_off = codec_drv->idle_bias_off; if (codec_drv->seq_notifier) codec->dapm.seq_notifier = codec_drv->seq_notifier; if (codec_drv->set_bias_level) From e720b82027b99482ea5d1001a69bdf2200e86b79 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Tue, 26 Aug 2014 19:01:42 +0530 Subject: [PATCH 060/251] ALSA: ctxfi: prink replacement as pr_* macros are more preffered over printk, so printk replaced with corresponding pr_err and pr_alert this patch will generate a warning from checkpatch for an unnecessary space before new line and has not been fixed as this patch is only for printk replacement. Signed-off-by: Sudip Mukherjee Signed-off-by: Takashi Iwai --- sound/pci/ctxfi/ctamixer.c | 4 ++-- sound/pci/ctxfi/ctatc.c | 20 ++++++++++---------- sound/pci/ctxfi/ctdaio.c | 2 +- sound/pci/ctxfi/cthw20k1.c | 10 +++++----- sound/pci/ctxfi/cthw20k2.c | 16 ++++++++-------- sound/pci/ctxfi/ctmixer.c | 4 ++-- sound/pci/ctxfi/ctresource.c | 12 ++++++------ sound/pci/ctxfi/ctsrc.c | 4 ++-- sound/pci/ctxfi/ctvmem.c | 4 ++-- sound/pci/ctxfi/xfi.c | 8 ++++---- 10 files changed, 42 insertions(+), 42 deletions(-) diff --git a/sound/pci/ctxfi/ctamixer.c b/sound/pci/ctxfi/ctamixer.c index fee35cfc0c7f..fed6e6a57608 100644 --- a/sound/pci/ctxfi/ctamixer.c +++ b/sound/pci/ctxfi/ctamixer.c @@ -258,7 +258,7 @@ static int get_amixer_rsc(struct amixer_mgr *mgr, } spin_unlock_irqrestore(&mgr->mgr_lock, flags); if (err) { - printk(KERN_ERR "ctxfi: Can't meet AMIXER resource request!\n"); + pr_err("ctxfi: Can't meet AMIXER resource request!\n"); goto error; } @@ -411,7 +411,7 @@ static int get_sum_rsc(struct sum_mgr *mgr, } spin_unlock_irqrestore(&mgr->mgr_lock, flags); if (err) { - printk(KERN_ERR "ctxfi: Can't meet SUM resource request!\n"); + pr_err("ctxfi: Can't meet SUM resource request!\n"); goto error; } diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c index af632bd08323..ce9061aee587 100644 --- a/sound/pci/ctxfi/ctatc.c +++ b/sound/pci/ctxfi/ctatc.c @@ -185,7 +185,7 @@ static unsigned int convert_format(snd_pcm_format_t snd_format) case SNDRV_PCM_FORMAT_FLOAT_LE: return SRC_SF_F32; default: - printk(KERN_ERR "ctxfi: not recognized snd format is %d \n", + pr_err("ctxfi: not recognized snd format is %d \n", snd_format); return SRC_SF_S16; } @@ -1282,7 +1282,7 @@ static int atc_identify_card(struct ct_atc *atc, unsigned int ssid) p = snd_pci_quirk_lookup_id(vendor_id, device_id, list); if (p) { if (p->value < 0) { - printk(KERN_ERR "ctxfi: " + pr_err("ctxfi: " "Device %04x:%04x is black-listed\n", vendor_id, device_id); return -ENOENT; @@ -1315,7 +1315,7 @@ int ct_atc_create_alsa_devs(struct ct_atc *atc) err = alsa_dev_funcs[i].create(atc, i, alsa_dev_funcs[i].public_name); if (err) { - printk(KERN_ERR "ctxfi: " + pr_err("ctxfi: " "Creating alsa device %d failed!\n", i); return err; } @@ -1332,7 +1332,7 @@ static int atc_create_hw_devs(struct ct_atc *atc) err = create_hw_obj(atc->pci, atc->chip_type, atc->model, &hw); if (err) { - printk(KERN_ERR "Failed to create hw obj!!!\n"); + pr_err("Failed to create hw obj!!!\n"); return err; } atc->hw = hw; @@ -1351,7 +1351,7 @@ static int atc_create_hw_devs(struct ct_atc *atc) err = rsc_mgr_funcs[i].create(atc->hw, &atc->rsc_mgrs[i]); if (err) { - printk(KERN_ERR "ctxfi: " + pr_err("ctxfi: " "Failed to create rsc_mgr %d!!!\n", i); return err; } @@ -1399,7 +1399,7 @@ static int atc_get_resources(struct ct_atc *atc) err = daio_mgr->get_daio(daio_mgr, &da_desc, (struct daio **)&atc->daios[i]); if (err) { - printk(KERN_ERR "ctxfi: Failed to get DAIO " + pr_err("ctxfi: Failed to get DAIO " "resource %d!!!\n", i); return err; } @@ -1603,7 +1603,7 @@ static int atc_resume(struct ct_atc *atc) /* Do hardware resume. */ err = atc_hw_resume(atc); if (err < 0) { - printk(KERN_ERR "ctxfi: pci_enable_device failed, " + pr_err("ctxfi: pci_enable_device failed, " "disabling device\n"); snd_card_disconnect(atc->card); return err; @@ -1701,7 +1701,7 @@ int ct_atc_create(struct snd_card *card, struct pci_dev *pci, /* Find card model */ err = atc_identify_card(atc, ssid); if (err < 0) { - printk(KERN_ERR "ctatc: Card not recognised\n"); + pr_err("ctatc: Card not recognised\n"); goto error1; } @@ -1717,7 +1717,7 @@ int ct_atc_create(struct snd_card *card, struct pci_dev *pci, err = ct_mixer_create(atc, (struct ct_mixer **)&atc->mixer); if (err) { - printk(KERN_ERR "ctxfi: Failed to create mixer obj!!!\n"); + pr_err("ctxfi: Failed to create mixer obj!!!\n"); goto error1; } @@ -1744,6 +1744,6 @@ int ct_atc_create(struct snd_card *card, struct pci_dev *pci, error1: ct_atc_destroy(atc); - printk(KERN_ERR "ctxfi: Something wrong!!!\n"); + pr_err("ctxfi: Something wrong!!!\n"); return err; } diff --git a/sound/pci/ctxfi/ctdaio.c b/sound/pci/ctxfi/ctdaio.c index 84f86bf63b8f..6f0654ea3630 100644 --- a/sound/pci/ctxfi/ctdaio.c +++ b/sound/pci/ctxfi/ctdaio.c @@ -541,7 +541,7 @@ static int get_daio_rsc(struct daio_mgr *mgr, err = daio_mgr_get_rsc(&mgr->mgr, desc->type); spin_unlock_irqrestore(&mgr->mgr_lock, flags); if (err) { - printk(KERN_ERR "Can't meet DAIO resource request!\n"); + pr_err("Can't meet DAIO resource request!\n"); return err; } diff --git a/sound/pci/ctxfi/cthw20k1.c b/sound/pci/ctxfi/cthw20k1.c index 6ac40beb49da..782641e77653 100644 --- a/sound/pci/ctxfi/cthw20k1.c +++ b/sound/pci/ctxfi/cthw20k1.c @@ -1268,7 +1268,7 @@ static int hw_trn_init(struct hw *hw, const struct trn_conf *info) /* Set up device page table */ if ((~0UL) == info->vm_pgt_phys) { - printk(KERN_ERR "Wrong device page table page address!\n"); + pr_err("Wrong device page table page address!\n"); return -1; } @@ -1327,7 +1327,7 @@ static int hw_pll_init(struct hw *hw, unsigned int rsr) mdelay(40); } if (i >= 3) { - printk(KERN_ALERT "PLL initialization failed!!!\n"); + pr_alert("PLL initialization failed!!!\n"); return -EBUSY; } @@ -1351,7 +1351,7 @@ static int hw_auto_init(struct hw *hw) break; } if (!get_field(gctl, GCTL_AID)) { - printk(KERN_ALERT "Card Auto-init failed!!!\n"); + pr_alert("Card Auto-init failed!!!\n"); return -EBUSY; } @@ -1911,7 +1911,7 @@ static int hw_card_start(struct hw *hw) /* Set DMA transfer mask */ if (pci_set_dma_mask(pci, CT_XFI_DMA_MASK) < 0 || pci_set_consistent_dma_mask(pci, CT_XFI_DMA_MASK) < 0) { - printk(KERN_ERR "architecture does not support PCI " + pr_err("architecture does not support PCI " "busmaster DMA with mask 0x%llx\n", CT_XFI_DMA_MASK); err = -ENXIO; @@ -1942,7 +1942,7 @@ static int hw_card_start(struct hw *hw) err = request_irq(pci->irq, ct_20k1_interrupt, IRQF_SHARED, KBUILD_MODNAME, hw); if (err < 0) { - printk(KERN_ERR "XFi: Cannot get irq %d\n", pci->irq); + pr_err("XFi: Cannot get irq %d\n", pci->irq); goto error2; } hw->irq = pci->irq; diff --git a/sound/pci/ctxfi/cthw20k2.c b/sound/pci/ctxfi/cthw20k2.c index b1438861d38a..8a72fac929ca 100644 --- a/sound/pci/ctxfi/cthw20k2.c +++ b/sound/pci/ctxfi/cthw20k2.c @@ -1187,7 +1187,7 @@ static int hw_daio_init(struct hw *hw, const struct daio_conf *info) hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x21212121); hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0); } else { - printk(KERN_ALERT "ctxfi: ERROR!!! Invalid sampling rate!!!\n"); + pr_alert("ctxfi: ERROR!!! Invalid sampling rate!!!\n"); return -EINVAL; } @@ -1246,7 +1246,7 @@ static int hw_trn_init(struct hw *hw, const struct trn_conf *info) /* Set up device page table */ if ((~0UL) == info->vm_pgt_phys) { - printk(KERN_ALERT "ctxfi: " + pr_alert("ctxfi: " "Wrong device page table page address!!!\n"); return -1; } @@ -1352,7 +1352,7 @@ static int hw_pll_init(struct hw *hw, unsigned int rsr) break; } if (i >= 1000) { - printk(KERN_ALERT "ctxfi: PLL initialization failed!!!\n"); + pr_alert("ctxfi: PLL initialization failed!!!\n"); return -EBUSY; } @@ -1376,7 +1376,7 @@ static int hw_auto_init(struct hw *hw) break; } if (!get_field(gctl, GCTL_AID)) { - printk(KERN_ALERT "ctxfi: Card Auto-init failed!!!\n"); + pr_alert("ctxfi: Card Auto-init failed!!!\n"); return -EBUSY; } @@ -1847,7 +1847,7 @@ static int hw_adc_init(struct hw *hw, const struct adc_conf *info) /* Initialize I2C */ err = hw20k2_i2c_init(hw, 0x1A, 1, 1); if (err < 0) { - printk(KERN_ALERT "ctxfi: Failure to acquire I2C!!!\n"); + pr_alert("ctxfi: Failure to acquire I2C!!!\n"); goto error; } @@ -1890,7 +1890,7 @@ static int hw_adc_init(struct hw *hw, const struct adc_conf *info) hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_MMC, 0x0A), MAKE_WM8775_DATA(0x0A)); } else { - printk(KERN_ALERT "ctxfi: Invalid master sampling " + pr_alert("ctxfi: Invalid master sampling " "rate (msr %d)!!!\n", info->msr); err = -EINVAL; goto error; @@ -2034,7 +2034,7 @@ static int hw_card_start(struct hw *hw) /* Set DMA transfer mask */ if (pci_set_dma_mask(pci, CT_XFI_DMA_MASK) < 0 || pci_set_consistent_dma_mask(pci, CT_XFI_DMA_MASK) < 0) { - printk(KERN_ERR "ctxfi: architecture does not support PCI " + pr_err("ctxfi: architecture does not support PCI " "busmaster DMA with mask 0x%llx\n", CT_XFI_DMA_MASK); err = -ENXIO; goto error1; @@ -2063,7 +2063,7 @@ static int hw_card_start(struct hw *hw) err = request_irq(pci->irq, ct_20k2_interrupt, IRQF_SHARED, KBUILD_MODNAME, hw); if (err < 0) { - printk(KERN_ERR "XFi: Cannot get irq %d\n", pci->irq); + pr_err("XFi: Cannot get irq %d\n", pci->irq); goto error2; } hw->irq = pci->irq; diff --git a/sound/pci/ctxfi/ctmixer.c b/sound/pci/ctxfi/ctmixer.c index 48fe0e39c2be..8d986e45ecf6 100644 --- a/sound/pci/ctxfi/ctmixer.c +++ b/sound/pci/ctxfi/ctmixer.c @@ -854,7 +854,7 @@ static int ct_mixer_get_resources(struct ct_mixer *mixer) for (i = 0; i < (NUM_CT_SUMS * CHN_NUM); i++) { err = sum_mgr->get_sum(sum_mgr, &sum_desc, &sum); if (err) { - printk(KERN_ERR "ctxfi:Failed to get sum resources for " + pr_err("ctxfi:Failed to get sum resources for " "front output!\n"); break; } @@ -869,7 +869,7 @@ static int ct_mixer_get_resources(struct ct_mixer *mixer) for (i = 0; i < (NUM_CT_AMIXERS * CHN_NUM); i++) { err = amixer_mgr->get_amixer(amixer_mgr, &am_desc, &amixer); if (err) { - printk(KERN_ERR "ctxfi:Failed to get amixer resources " + pr_err("ctxfi:Failed to get amixer resources " "for mixer obj!\n"); break; } diff --git a/sound/pci/ctxfi/ctresource.c b/sound/pci/ctxfi/ctresource.c index 7dfaf67344d4..11ac934dcefd 100644 --- a/sound/pci/ctxfi/ctresource.c +++ b/sound/pci/ctxfi/ctresource.c @@ -162,13 +162,13 @@ int rsc_init(struct rsc *rsc, u32 idx, enum RSCTYP type, u32 msr, void *hw) case DAIO: break; default: - printk(KERN_ERR + pr_err( "ctxfi: Invalid resource type value %d!\n", type); return -EINVAL; } if (err) { - printk(KERN_ERR + pr_err( "ctxfi: Failed to get resource control block!\n"); return err; } @@ -192,7 +192,7 @@ int rsc_uninit(struct rsc *rsc) case DAIO: break; default: - printk(KERN_ERR "ctxfi: " + pr_err("ctxfi: " "Invalid resource type value %d!\n", rsc->type); break; } @@ -235,14 +235,14 @@ int rsc_mgr_init(struct rsc_mgr *mgr, enum RSCTYP type, case SUM: break; default: - printk(KERN_ERR + pr_err( "ctxfi: Invalid resource type value %d!\n", type); err = -EINVAL; goto error; } if (err) { - printk(KERN_ERR + pr_err( "ctxfi: Failed to get manager control block!\n"); goto error; } @@ -286,7 +286,7 @@ int rsc_mgr_uninit(struct rsc_mgr *mgr) case SUM: break; default: - printk(KERN_ERR "ctxfi: " + pr_err("ctxfi: " "Invalid resource type value %d!\n", mgr->type); break; } diff --git a/sound/pci/ctxfi/ctsrc.c b/sound/pci/ctxfi/ctsrc.c index 6e77e86307c2..19df9b4ed800 100644 --- a/sound/pci/ctxfi/ctsrc.c +++ b/sound/pci/ctxfi/ctsrc.c @@ -431,7 +431,7 @@ get_src_rsc(struct src_mgr *mgr, const struct src_desc *desc, struct src **rsrc) spin_unlock_irqrestore(&mgr->mgr_lock, flags); if (err) { - printk(KERN_ERR "ctxfi: Can't meet SRC resource request!\n"); + pr_err("ctxfi: Can't meet SRC resource request!\n"); return err; } @@ -739,7 +739,7 @@ static int get_srcimp_rsc(struct srcimp_mgr *mgr, } spin_unlock_irqrestore(&mgr->mgr_lock, flags); if (err) { - printk(KERN_ERR "ctxfi: Can't meet SRCIMP resource request!\n"); + pr_err("ctxfi: Can't meet SRCIMP resource request!\n"); goto error1; } diff --git a/sound/pci/ctxfi/ctvmem.c b/sound/pci/ctxfi/ctvmem.c index 6109490b83e8..5ea015bec793 100644 --- a/sound/pci/ctxfi/ctvmem.c +++ b/sound/pci/ctxfi/ctvmem.c @@ -36,7 +36,7 @@ get_vm_block(struct ct_vm *vm, unsigned int size) size = CT_PAGE_ALIGN(size); if (size > vm->size) { - printk(KERN_ERR "ctxfi: Fail! No sufficient device virtual " + pr_err("ctxfi: Fail! No sufficient device virtual " "memory space available!\n"); return NULL; } @@ -132,7 +132,7 @@ ct_vm_map(struct ct_vm *vm, struct snd_pcm_substream *substream, int size) block = get_vm_block(vm, size); if (block == NULL) { - printk(KERN_ERR "ctxfi: No virtual memory block that is big " + pr_err("ctxfi: No virtual memory block that is big " "enough to allocate!\n"); return NULL; } diff --git a/sound/pci/ctxfi/xfi.c b/sound/pci/ctxfi/xfi.c index 8f8b566a1b35..af8c49836000 100644 --- a/sound/pci/ctxfi/xfi.c +++ b/sound/pci/ctxfi/xfi.c @@ -76,16 +76,16 @@ ct_card_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) if (err) return err; if ((reference_rate != 48000) && (reference_rate != 44100)) { - printk(KERN_ERR "ctxfi: Invalid reference_rate value %u!!!\n", + pr_err("ctxfi: Invalid reference_rate value %u!!!\n", reference_rate); - printk(KERN_ERR "ctxfi: The valid values for reference_rate " + pr_err("ctxfi: The valid values for reference_rate " "are 48000 and 44100, Value 48000 is assumed.\n"); reference_rate = 48000; } if ((multiple != 1) && (multiple != 2) && (multiple != 4)) { - printk(KERN_ERR "ctxfi: Invalid multiple value %u!!!\n", + pr_err("ctxfi: Invalid multiple value %u!!!\n", multiple); - printk(KERN_ERR "ctxfi: The valid values for multiple are " + pr_err("ctxfi: The valid values for multiple are " "1, 2 and 4, Value 2 is assumed.\n"); multiple = 2; } From 62afa853cb91288e85a8da6351bd29d798402308 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Tue, 26 Aug 2014 19:01:43 +0530 Subject: [PATCH 061/251] ALSA: ctxfi: fix broken user-visible string as broken user-visible strings breaks the ability to grep for them , so this patch fixes the broken user-visible strings Signed-off-by: Sudip Mukherjee Signed-off-by: Takashi Iwai --- sound/pci/ctxfi/ctatc.c | 18 +++++++----------- sound/pci/ctxfi/cthw20k1.c | 3 +-- sound/pci/ctxfi/cthw20k2.c | 11 +++++------ sound/pci/ctxfi/ctmixer.c | 6 ++---- sound/pci/ctxfi/ctresource.c | 20 ++++++++------------ sound/pci/ctxfi/ctvmem.c | 6 ++---- sound/pci/ctxfi/xfi.c | 6 ++---- 7 files changed, 27 insertions(+), 43 deletions(-) diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c index ce9061aee587..d92a08c7a39c 100644 --- a/sound/pci/ctxfi/ctatc.c +++ b/sound/pci/ctxfi/ctatc.c @@ -185,7 +185,7 @@ static unsigned int convert_format(snd_pcm_format_t snd_format) case SNDRV_PCM_FORMAT_FLOAT_LE: return SRC_SF_F32; default: - pr_err("ctxfi: not recognized snd format is %d \n", + pr_err("ctxfi: not recognized snd format is %d\n", snd_format); return SRC_SF_S16; } @@ -1282,8 +1282,7 @@ static int atc_identify_card(struct ct_atc *atc, unsigned int ssid) p = snd_pci_quirk_lookup_id(vendor_id, device_id, list); if (p) { if (p->value < 0) { - pr_err("ctxfi: " - "Device %04x:%04x is black-listed\n", + pr_err("ctxfi: Device %04x:%04x is black-listed\n", vendor_id, device_id); return -ENOENT; } @@ -1315,8 +1314,7 @@ int ct_atc_create_alsa_devs(struct ct_atc *atc) err = alsa_dev_funcs[i].create(atc, i, alsa_dev_funcs[i].public_name); if (err) { - pr_err("ctxfi: " - "Creating alsa device %d failed!\n", i); + pr_err("ctxfi: Creating alsa device %d failed!\n", i); return err; } } @@ -1351,8 +1349,7 @@ static int atc_create_hw_devs(struct ct_atc *atc) err = rsc_mgr_funcs[i].create(atc->hw, &atc->rsc_mgrs[i]); if (err) { - pr_err("ctxfi: " - "Failed to create rsc_mgr %d!!!\n", i); + pr_err("ctxfi: Failed to create rsc_mgr %d!!!\n", i); return err; } } @@ -1399,8 +1396,8 @@ static int atc_get_resources(struct ct_atc *atc) err = daio_mgr->get_daio(daio_mgr, &da_desc, (struct daio **)&atc->daios[i]); if (err) { - pr_err("ctxfi: Failed to get DAIO " - "resource %d!!!\n", i); + pr_err("ctxfi: Failed to get DAIO resource %d!!!\n", + i); return err; } atc->n_daio++; @@ -1603,8 +1600,7 @@ static int atc_resume(struct ct_atc *atc) /* Do hardware resume. */ err = atc_hw_resume(atc); if (err < 0) { - pr_err("ctxfi: pci_enable_device failed, " - "disabling device\n"); + pr_err("ctxfi: pci_enable_device failed, disabling device\n"); snd_card_disconnect(atc->card); return err; } diff --git a/sound/pci/ctxfi/cthw20k1.c b/sound/pci/ctxfi/cthw20k1.c index 782641e77653..71d496f780e3 100644 --- a/sound/pci/ctxfi/cthw20k1.c +++ b/sound/pci/ctxfi/cthw20k1.c @@ -1911,8 +1911,7 @@ static int hw_card_start(struct hw *hw) /* Set DMA transfer mask */ if (pci_set_dma_mask(pci, CT_XFI_DMA_MASK) < 0 || pci_set_consistent_dma_mask(pci, CT_XFI_DMA_MASK) < 0) { - pr_err("architecture does not support PCI " - "busmaster DMA with mask 0x%llx\n", + pr_err("architecture does not support PCI busmaster DMA with mask 0x%llx\n", CT_XFI_DMA_MASK); err = -ENXIO; goto error1; diff --git a/sound/pci/ctxfi/cthw20k2.c b/sound/pci/ctxfi/cthw20k2.c index 8a72fac929ca..df2d8c5eb926 100644 --- a/sound/pci/ctxfi/cthw20k2.c +++ b/sound/pci/ctxfi/cthw20k2.c @@ -1246,8 +1246,7 @@ static int hw_trn_init(struct hw *hw, const struct trn_conf *info) /* Set up device page table */ if ((~0UL) == info->vm_pgt_phys) { - pr_alert("ctxfi: " - "Wrong device page table page address!!!\n"); + pr_alert("ctxfi: Wrong device page table page address!!!\n"); return -1; } @@ -1890,8 +1889,8 @@ static int hw_adc_init(struct hw *hw, const struct adc_conf *info) hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_MMC, 0x0A), MAKE_WM8775_DATA(0x0A)); } else { - pr_alert("ctxfi: Invalid master sampling " - "rate (msr %d)!!!\n", info->msr); + pr_alert("ctxfi: Invalid master sampling rate (msr %d)!!!\n", + info->msr); err = -EINVAL; goto error; } @@ -2034,8 +2033,8 @@ static int hw_card_start(struct hw *hw) /* Set DMA transfer mask */ if (pci_set_dma_mask(pci, CT_XFI_DMA_MASK) < 0 || pci_set_consistent_dma_mask(pci, CT_XFI_DMA_MASK) < 0) { - pr_err("ctxfi: architecture does not support PCI " - "busmaster DMA with mask 0x%llx\n", CT_XFI_DMA_MASK); + pr_err("ctxfi: architecture does not support PCI busmaster DMA with mask 0x%llx\n", + CT_XFI_DMA_MASK); err = -ENXIO; goto error1; } diff --git a/sound/pci/ctxfi/ctmixer.c b/sound/pci/ctxfi/ctmixer.c index 8d986e45ecf6..017fa91706d4 100644 --- a/sound/pci/ctxfi/ctmixer.c +++ b/sound/pci/ctxfi/ctmixer.c @@ -854,8 +854,7 @@ static int ct_mixer_get_resources(struct ct_mixer *mixer) for (i = 0; i < (NUM_CT_SUMS * CHN_NUM); i++) { err = sum_mgr->get_sum(sum_mgr, &sum_desc, &sum); if (err) { - pr_err("ctxfi:Failed to get sum resources for " - "front output!\n"); + pr_err("ctxfi:Failed to get sum resources for front output!\n"); break; } mixer->sums[i] = sum; @@ -869,8 +868,7 @@ static int ct_mixer_get_resources(struct ct_mixer *mixer) for (i = 0; i < (NUM_CT_AMIXERS * CHN_NUM); i++) { err = amixer_mgr->get_amixer(amixer_mgr, &am_desc, &amixer); if (err) { - pr_err("ctxfi:Failed to get amixer resources " - "for mixer obj!\n"); + pr_err("ctxfi:Failed to get amixer resources for mixer obj!\n"); break; } mixer->amixers[i] = amixer; diff --git a/sound/pci/ctxfi/ctresource.c b/sound/pci/ctxfi/ctresource.c index 11ac934dcefd..e49d2be1bfd4 100644 --- a/sound/pci/ctxfi/ctresource.c +++ b/sound/pci/ctxfi/ctresource.c @@ -162,14 +162,12 @@ int rsc_init(struct rsc *rsc, u32 idx, enum RSCTYP type, u32 msr, void *hw) case DAIO: break; default: - pr_err( - "ctxfi: Invalid resource type value %d!\n", type); + pr_err("ctxfi: Invalid resource type value %d!\n", type); return -EINVAL; } if (err) { - pr_err( - "ctxfi: Failed to get resource control block!\n"); + pr_err("ctxfi: Failed to get resource control block!\n"); return err; } @@ -192,8 +190,8 @@ int rsc_uninit(struct rsc *rsc) case DAIO: break; default: - pr_err("ctxfi: " - "Invalid resource type value %d!\n", rsc->type); + pr_err("ctxfi: Invalid resource type value %d!\n", + rsc->type); break; } @@ -235,15 +233,13 @@ int rsc_mgr_init(struct rsc_mgr *mgr, enum RSCTYP type, case SUM: break; default: - pr_err( - "ctxfi: Invalid resource type value %d!\n", type); + pr_err("ctxfi: Invalid resource type value %d!\n", type); err = -EINVAL; goto error; } if (err) { - pr_err( - "ctxfi: Failed to get manager control block!\n"); + pr_err("ctxfi: Failed to get manager control block!\n"); goto error; } @@ -286,8 +282,8 @@ int rsc_mgr_uninit(struct rsc_mgr *mgr) case SUM: break; default: - pr_err("ctxfi: " - "Invalid resource type value %d!\n", mgr->type); + pr_err("ctxfi: Invalid resource type value %d!\n", + mgr->type); break; } diff --git a/sound/pci/ctxfi/ctvmem.c b/sound/pci/ctxfi/ctvmem.c index 5ea015bec793..38163f52dd5f 100644 --- a/sound/pci/ctxfi/ctvmem.c +++ b/sound/pci/ctxfi/ctvmem.c @@ -36,8 +36,7 @@ get_vm_block(struct ct_vm *vm, unsigned int size) size = CT_PAGE_ALIGN(size); if (size > vm->size) { - pr_err("ctxfi: Fail! No sufficient device virtual " - "memory space available!\n"); + pr_err("ctxfi: Fail! No sufficient device virtual memory space available!\n"); return NULL; } @@ -132,8 +131,7 @@ ct_vm_map(struct ct_vm *vm, struct snd_pcm_substream *substream, int size) block = get_vm_block(vm, size); if (block == NULL) { - pr_err("ctxfi: No virtual memory block that is big " - "enough to allocate!\n"); + pr_err("ctxfi: No virtual memory block that is big enough to allocate!\n"); return NULL; } diff --git a/sound/pci/ctxfi/xfi.c b/sound/pci/ctxfi/xfi.c index af8c49836000..35e85ba80656 100644 --- a/sound/pci/ctxfi/xfi.c +++ b/sound/pci/ctxfi/xfi.c @@ -78,15 +78,13 @@ ct_card_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) if ((reference_rate != 48000) && (reference_rate != 44100)) { pr_err("ctxfi: Invalid reference_rate value %u!!!\n", reference_rate); - pr_err("ctxfi: The valid values for reference_rate " - "are 48000 and 44100, Value 48000 is assumed.\n"); + pr_err("ctxfi: The valid values for reference_rate are 48000 and 44100, Value 48000 is assumed.\n"); reference_rate = 48000; } if ((multiple != 1) && (multiple != 2) && (multiple != 4)) { pr_err("ctxfi: Invalid multiple value %u!!!\n", multiple); - pr_err("ctxfi: The valid values for multiple are " - "1, 2 and 4, Value 2 is assumed.\n"); + pr_err("ctxfi: The valid values for multiple are 1, 2 and 4, Value 2 is assumed.\n"); multiple = 2; } err = ct_atc_create(card, pci, reference_rate, multiple, From 890b13a308b9df78ad05fc57eb440b32399be35e Mon Sep 17 00:00:00 2001 From: Konstantinos Tsimpoukas Date: Tue, 26 Aug 2014 23:21:48 -0500 Subject: [PATCH 062/251] ALSA: ice1712: Replacing hex with #defines Adds to the readability of the ice1712 driver. Signed-off-by: Konstantinos Tsimpoukas Signed-off-by: Takashi Iwai --- sound/pci/ice1712/ice1712.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c index 87f7fc41d4f2..206ed2cbcef9 100644 --- a/sound/pci/ice1712/ice1712.c +++ b/sound/pci/ice1712/ice1712.c @@ -2528,7 +2528,7 @@ static int snd_ice1712_free(struct snd_ice1712 *ice) if (!ice->port) goto __hw_end; /* mask all interrupts */ - outb(0xc0, ICEMT(ice, IRQ)); + outb(ICE1712_MULTI_CAPTURE | ICE1712_MULTI_PLAYBACK, ICEMT(ice, IRQ)); outb(0xff, ICEREG(ice, IRQMASK)); /* --- */ __hw_end: From 2d15d974618db4ed3adafe9b9fe092db0f5076a0 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 27 Aug 2014 19:50:34 +0800 Subject: [PATCH 063/251] ASoC: rt5677: Add DMIC2 clock selection There are two pins can be used for rt5677's DMIC2 clock. This patch add the select options for it. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- include/sound/rt5677.h | 8 ++++++ sound/soc/codecs/rt5677.c | 57 +++++++++++++++++++++++++++++++++------ sound/soc/codecs/rt5677.h | 10 +++++++ 3 files changed, 67 insertions(+), 8 deletions(-) diff --git a/include/sound/rt5677.h b/include/sound/rt5677.h index 3da14313bcfc..a676717f74f4 100644 --- a/include/sound/rt5677.h +++ b/include/sound/rt5677.h @@ -12,10 +12,18 @@ #ifndef __LINUX_SND_RT5677_H #define __LINUX_SND_RT5677_H +enum rt5677_dmic2_clk { + RT5677_DMIC_CLK1 = 0, + RT5677_DMIC_CLK2 = 1, +}; + + struct rt5677_platform_data { /* IN1 IN2 can optionally be differential */ bool in1_diff; bool in2_diff; + /* DMIC2 clock source selection */ + enum rt5677_dmic2_clk dmic2_clk_pin; }; #endif diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 67f14556462f..f0b751bf1d6c 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -1700,14 +1700,19 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = { SND_SOC_DAPM_INPUT("Haptic Generator"), - SND_SOC_DAPM_PGA("DMIC1", RT5677_DMIC_CTRL1, RT5677_DMIC_1_EN_SFT, 0, - NULL, 0), - SND_SOC_DAPM_PGA("DMIC2", RT5677_DMIC_CTRL1, RT5677_DMIC_2_EN_SFT, 0, - NULL, 0), - SND_SOC_DAPM_PGA("DMIC3", RT5677_DMIC_CTRL1, RT5677_DMIC_3_EN_SFT, 0, - NULL, 0), - SND_SOC_DAPM_PGA("DMIC4", RT5677_DMIC_CTRL2, RT5677_DMIC_4_EN_SFT, 0, - NULL, 0), + SND_SOC_DAPM_PGA("DMIC1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("DMIC2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("DMIC3", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("DMIC4", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_SUPPLY("DMIC1 power", RT5677_DMIC_CTRL1, + RT5677_DMIC_1_EN_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("DMIC2 power", RT5677_DMIC_CTRL1, + RT5677_DMIC_2_EN_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("DMIC3 power", RT5677_DMIC_CTRL1, + RT5677_DMIC_3_EN_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("DMIC4 power", RT5677_DMIC_CTRL2, + RT5677_DMIC_4_EN_SFT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("DMIC CLK", SND_SOC_NOPM, 0, 0, set_dmic_clk, SND_SOC_DAPM_PRE_PMU), @@ -2130,6 +2135,13 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { { "DMIC L4", NULL, "DMIC CLK" }, { "DMIC R4", NULL, "DMIC CLK" }, + { "DMIC L1", NULL, "DMIC1 power" }, + { "DMIC R1", NULL, "DMIC1 power" }, + { "DMIC L3", NULL, "DMIC3 power" }, + { "DMIC R3", NULL, "DMIC3 power" }, + { "DMIC L4", NULL, "DMIC4 power" }, + { "DMIC R4", NULL, "DMIC4 power" }, + { "BST1", NULL, "IN1P" }, { "BST1", NULL, "IN1N" }, { "BST2", NULL, "IN2P" }, @@ -2793,6 +2805,16 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { { "PDM2R", NULL, "PDM2 R Mux" }, }; +static const struct snd_soc_dapm_route rt5677_dmic2_clk_1[] = { + { "DMIC L2", NULL, "DMIC1 power" }, + { "DMIC R2", NULL, "DMIC1 power" }, +}; + +static const struct snd_soc_dapm_route rt5677_dmic2_clk_2[] = { + { "DMIC L2", NULL, "DMIC2 power" }, + { "DMIC R2", NULL, "DMIC2 power" }, +}; + static int rt5677_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { @@ -3144,6 +3166,16 @@ static int rt5677_probe(struct snd_soc_codec *codec) rt5677->codec = codec; + if (rt5677->pdata.dmic2_clk_pin == RT5677_DMIC_CLK2) { + snd_soc_dapm_add_routes(&codec->dapm, + rt5677_dmic2_clk_2, + ARRAY_SIZE(rt5677_dmic2_clk_2)); + } else { /*use dmic1 clock by default*/ + snd_soc_dapm_add_routes(&codec->dapm, + rt5677_dmic2_clk_1, + ARRAY_SIZE(rt5677_dmic2_clk_1)); + } + rt5677_set_bias_level(codec, SND_SOC_BIAS_OFF); regmap_write(rt5677->regmap, RT5677_DIG_MISC, 0x0020); @@ -3381,6 +3413,15 @@ static int rt5677_i2c_probe(struct i2c_client *i2c, regmap_update_bits(rt5677->regmap, RT5677_IN1, RT5677_IN_DF2, RT5677_IN_DF2); + if (rt5677->pdata.dmic2_clk_pin == RT5677_DMIC_CLK2) { + regmap_update_bits(rt5677->regmap, RT5677_GEN_CTRL2, + RT5677_GPIO5_FUNC_MASK, + RT5677_GPIO5_FUNC_DMIC); + regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL2, + RT5677_GPIO5_DIR_MASK, + RT5677_GPIO5_DIR_OUT); + } + return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5677, rt5677_dai, ARRAY_SIZE(rt5677_dai)); } diff --git a/sound/soc/codecs/rt5677.h b/sound/soc/codecs/rt5677.h index 863393e62096..8791ab9637f3 100644 --- a/sound/soc/codecs/rt5677.h +++ b/sound/soc/codecs/rt5677.h @@ -1363,6 +1363,11 @@ #define RT5677_SEL_SRC_IB01 (0x1 << 0) #define RT5677_SEL_SRC_IB01_SFT 0 +/* GPIO Control 2 (0xc1) */ +#define RT5677_GPIO5_DIR_MASK (0x1 << 14) +#define RT5677_GPIO5_DIR_IN (0x0 << 14) +#define RT5677_GPIO5_DIR_OUT (0x1 << 14) + /* Virtual DSP Mixer Control (0xf7 0xf8 0xf9) */ #define RT5677_DSP_IB_01_H (0x1 << 15) #define RT5677_DSP_IB_01_H_SFT 15 @@ -1393,6 +1398,11 @@ #define RT5677_DSP_IB_9_L (0x1 << 1) #define RT5677_DSP_IB_9_L_SFT 1 +/* General Control2 (0xfc)*/ +#define RT5677_GPIO5_FUNC_MASK (0x1 << 9) +#define RT5677_GPIO5_FUNC_GPIO (0x0 << 9) +#define RT5677_GPIO5_FUNC_DMIC (0x1 << 9) + /* System Clock Source */ enum { RT5677_SCLK_S_MCLK, From bf16d883263dedefb6149916e41b3e2779bb1573 Mon Sep 17 00:00:00 2001 From: Xiubo Li Date: Mon, 25 Aug 2014 11:30:59 +0800 Subject: [PATCH 064/251] ASoC: fsl-asrc: Convert to use regmap framework's endianness method. Signed-off-by: Xiubo Li Acked-by: Nicolin Chen Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_asrc.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index 822110420b71..3b145313f93e 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c @@ -684,7 +684,7 @@ static bool fsl_asrc_writeable_reg(struct device *dev, unsigned int reg) } } -static struct regmap_config fsl_asrc_regmap_config = { +static const struct regmap_config fsl_asrc_regmap_config = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, @@ -802,10 +802,6 @@ static int fsl_asrc_probe(struct platform_device *pdev) asrc_priv->paddr = res->start; - /* Register regmap and let it prepare core clock */ - if (of_property_read_bool(np, "big-endian")) - fsl_asrc_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG; - asrc_priv->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "mem", regs, &fsl_asrc_regmap_config); if (IS_ERR(asrc_priv->regmap)) { From 92bd0334b27845f250f1fadb091242140391c99b Mon Sep 17 00:00:00 2001 From: Xiubo Li Date: Mon, 25 Aug 2014 11:31:00 +0800 Subject: [PATCH 065/251] ASoC: fsl-esai: Convert to use regmap framework's endianness method. Signed-off-by: Xiubo Li Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_esai.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index 72d154e7dd03..2882fc66a10d 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c @@ -707,7 +707,7 @@ static bool fsl_esai_writeable_reg(struct device *dev, unsigned int reg) } } -static struct regmap_config fsl_esai_regmap_config = { +static const struct regmap_config fsl_esai_regmap_config = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, @@ -733,9 +733,6 @@ static int fsl_esai_probe(struct platform_device *pdev) esai_priv->pdev = pdev; strcpy(esai_priv->name, np->name); - if (of_property_read_bool(np, "big-endian")) - fsl_esai_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG; - /* Get the addresses and IRQ */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); regs = devm_ioremap_resource(&pdev->dev, res); From 664915074e750614c5d140093d5098a165a24e3d Mon Sep 17 00:00:00 2001 From: Xiubo Li Date: Mon, 25 Aug 2014 11:31:01 +0800 Subject: [PATCH 066/251] ASoC: fsl-spdif: Convert to use regmap framework's endianness method. Signed-off-by: Xiubo Li Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_spdif.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index 70acfe4a9bd5..ae4e408810ec 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -1040,7 +1040,7 @@ static bool fsl_spdif_writeable_reg(struct device *dev, unsigned int reg) } } -static struct regmap_config fsl_spdif_regmap_config = { +static const struct regmap_config fsl_spdif_regmap_config = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, @@ -1184,9 +1184,6 @@ static int fsl_spdif_probe(struct platform_device *pdev) memcpy(&spdif_priv->cpu_dai_drv, &fsl_spdif_dai, sizeof(fsl_spdif_dai)); spdif_priv->cpu_dai_drv.name = spdif_priv->name; - if (of_property_read_bool(np, "big-endian")) - fsl_spdif_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG; - /* Get the addresses and IRQ */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); regs = devm_ioremap_resource(&pdev->dev, res); From 014fd22ef9c6a7e9536b7e16635714a1a34810a8 Mon Sep 17 00:00:00 2001 From: Xiubo Li Date: Mon, 25 Aug 2014 11:31:02 +0800 Subject: [PATCH 067/251] ASoC: fsl-sai: Convert to use regmap framework's endianness method. Signed-off-by: Xiubo Li Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/fsl-sai.txt | 7 +++---- sound/soc/fsl/fsl_sai.c | 6 +----- sound/soc/fsl/fsl_sai.h | 1 - 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/fsl-sai.txt b/Documentation/devicetree/bindings/sound/fsl-sai.txt index 0f4e23828190..5f239b8bcddd 100644 --- a/Documentation/devicetree/bindings/sound/fsl-sai.txt +++ b/Documentation/devicetree/bindings/sound/fsl-sai.txt @@ -18,9 +18,8 @@ Required properties: - pinctrl-names: Must contain a "default" entry. - pinctrl-NNN: One property must exist for each entry in pinctrl-names. See ../pinctrl/pinctrl-bindings.txt for details of the property values. -- big-endian-regs: If this property is absent, the little endian mode will - be in use as default, or the big endian mode will be in use for all the - device registers. +- big-endian: Boolean property, required if all the FTM_PWM registers + are big-endian rather than little-endian. - big-endian-data: If this property is absent, the little endian mode will be in use as default, or the big endian mode will be in use for all the fifo data. @@ -38,6 +37,6 @@ sai2: sai@40031000 { dma-names = "tx", "rx"; dmas = <&edma0 0 VF610_EDMA_MUXID0_SAI2_TX>, <&edma0 0 VF610_EDMA_MUXID0_SAI2_RX>; - big-endian-regs; + big-endian; big-endian-data; }; diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index faa049797897..52d1e9982639 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -539,7 +539,7 @@ static bool fsl_sai_writeable_reg(struct device *dev, unsigned int reg) } } -static struct regmap_config fsl_sai_regmap_config = { +static const struct regmap_config fsl_sai_regmap_config = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, @@ -568,10 +568,6 @@ static int fsl_sai_probe(struct platform_device *pdev) if (of_device_is_compatible(pdev->dev.of_node, "fsl,imx6sx-sai")) sai->sai_on_imx = true; - sai->big_endian_regs = of_property_read_bool(np, "big-endian-regs"); - if (sai->big_endian_regs) - fsl_sai_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG; - sai->big_endian_data = of_property_read_bool(np, "big-endian-data"); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h index 0e6c9f595d75..20e3e53ce6ea 100644 --- a/sound/soc/fsl/fsl_sai.h +++ b/sound/soc/fsl/fsl_sai.h @@ -131,7 +131,6 @@ struct fsl_sai { struct clk *bus_clk; struct clk *mclk_clk[FSL_SAI_MCLK_MAX]; - bool big_endian_regs; bool big_endian_data; bool is_dsp_mode; bool sai_on_imx; From 06cb1eb3de5c905da60ab91dbf99aaf96a43d043 Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Thu, 21 Aug 2014 18:20:49 +0530 Subject: [PATCH 068/251] ASoC: mfld-compress: Use dedicated function instead of ioctl Also pass sst device as an argument to function pointer prototypes of compr_ops. This will be used to derive sst driver context. Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/sst-mfld-platform-compress.c | 36 +++++++++++++++----- sound/soc/intel/sst-mfld-platform.h | 27 +++++++++------ 2 files changed, 45 insertions(+), 18 deletions(-) diff --git a/sound/soc/intel/sst-mfld-platform-compress.c b/sound/soc/intel/sst-mfld-platform-compress.c index 29c059ca19e8..59467775c9b8 100644 --- a/sound/soc/intel/sst-mfld-platform-compress.c +++ b/sound/soc/intel/sst-mfld-platform-compress.c @@ -86,7 +86,7 @@ static int sst_platform_compr_free(struct snd_compr_stream *cstream) /*need to check*/ str_id = stream->id; if (str_id) - ret_val = stream->compr_ops->close(str_id); + ret_val = stream->compr_ops->close(sst->dev, str_id); module_put(sst->dev->driver->owner); kfree(stream); pr_debug("%s: %d\n", __func__, ret_val); @@ -158,7 +158,7 @@ static int sst_platform_compr_set_params(struct snd_compr_stream *cstream, cb.drain_cb_param = cstream; cb.drain_notify = sst_drain_notify; - retval = stream->compr_ops->open(&str_params, &cb); + retval = stream->compr_ops->open(sst->dev, &str_params, &cb); if (retval < 0) { pr_err("stream allocation failed %d\n", retval); return retval; @@ -170,10 +170,30 @@ static int sst_platform_compr_set_params(struct snd_compr_stream *cstream, static int sst_platform_compr_trigger(struct snd_compr_stream *cstream, int cmd) { - struct sst_runtime_stream *stream = - cstream->runtime->private_data; + struct sst_runtime_stream *stream = cstream->runtime->private_data; - return stream->compr_ops->control(cmd, stream->id); + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + if (stream->compr_ops->stream_start) + return stream->compr_ops->stream_start(sst->dev, stream->id); + case SNDRV_PCM_TRIGGER_STOP: + if (stream->compr_ops->stream_drop) + return stream->compr_ops->stream_drop(sst->dev, stream->id); + case SND_COMPR_TRIGGER_DRAIN: + if (stream->compr_ops->stream_drain) + return stream->compr_ops->stream_drain(sst->dev, stream->id); + case SND_COMPR_TRIGGER_PARTIAL_DRAIN: + if (stream->compr_ops->stream_partial_drain) + return stream->compr_ops->stream_partial_drain(sst->dev, stream->id); + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + if (stream->compr_ops->stream_pause) + return stream->compr_ops->stream_pause(sst->dev, stream->id); + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + if (stream->compr_ops->stream_pause_release) + return stream->compr_ops->stream_pause_release(sst->dev, stream->id); + default: + return -EINVAL; + } } static int sst_platform_compr_pointer(struct snd_compr_stream *cstream, @@ -182,7 +202,7 @@ static int sst_platform_compr_pointer(struct snd_compr_stream *cstream, struct sst_runtime_stream *stream; stream = cstream->runtime->private_data; - stream->compr_ops->tstamp(stream->id, tstamp); + stream->compr_ops->tstamp(sst->dev, stream->id, tstamp); tstamp->byte_offset = tstamp->copied_total % (u32)cstream->runtime->buffer_size; pr_debug("calc bytes offset/copied bytes as %d\n", tstamp->byte_offset); @@ -195,7 +215,7 @@ static int sst_platform_compr_ack(struct snd_compr_stream *cstream, struct sst_runtime_stream *stream; stream = cstream->runtime->private_data; - stream->compr_ops->ack(stream->id, (unsigned long)bytes); + stream->compr_ops->ack(sst->dev, stream->id, (unsigned long)bytes); stream->bytes_written += bytes; return 0; @@ -225,7 +245,7 @@ static int sst_platform_compr_set_metadata(struct snd_compr_stream *cstream, struct sst_runtime_stream *stream = cstream->runtime->private_data; - return stream->compr_ops->set_metadata(stream->id, metadata); + return stream->compr_ops->set_metadata(sst->dev, stream->id, metadata); } struct snd_compr_ops sst_platform_compr_ops = { diff --git a/sound/soc/intel/sst-mfld-platform.h b/sound/soc/intel/sst-mfld-platform.h index faaba10c1dff..0c5b943daff3 100644 --- a/sound/soc/intel/sst-mfld-platform.h +++ b/sound/soc/intel/sst-mfld-platform.h @@ -99,17 +99,24 @@ struct sst_compress_cb { struct compress_sst_ops { const char *name; - int (*open) (struct snd_sst_params *str_params, - struct sst_compress_cb *cb); - int (*control) (unsigned int cmd, unsigned int str_id); - int (*tstamp) (unsigned int str_id, struct snd_compr_tstamp *tstamp); - int (*ack) (unsigned int str_id, unsigned long bytes); - int (*close) (unsigned int str_id); - int (*get_caps) (struct snd_compr_caps *caps); - int (*get_codec_caps) (struct snd_compr_codec_caps *codec); - int (*set_metadata) (unsigned int str_id, - struct snd_compr_metadata *mdata); + int (*open)(struct device *dev, + struct snd_sst_params *str_params, struct sst_compress_cb *cb); + int (*stream_start)(struct device *dev, unsigned int str_id); + int (*stream_drop)(struct device *dev, unsigned int str_id); + int (*stream_drain)(struct device *dev, unsigned int str_id); + int (*stream_partial_drain)(struct device *dev, unsigned int str_id); + int (*stream_pause)(struct device *dev, unsigned int str_id); + int (*stream_pause_release)(struct device *dev, unsigned int str_id); + int (*tstamp)(struct device *dev, unsigned int str_id, + struct snd_compr_tstamp *tstamp); + int (*ack)(struct device *dev, unsigned int str_id, + unsigned long bytes); + int (*close)(struct device *dev, unsigned int str_id); + int (*get_caps)(struct snd_compr_caps *caps); + int (*get_codec_caps)(struct snd_compr_codec_caps *codec); + int (*set_metadata)(struct device *dev, unsigned int str_id, + struct snd_compr_metadata *mdata); }; struct sst_ops { From 77c545398e33a0263a68142fcfbd4b11b0f06294 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 28 Aug 2014 14:48:24 +0200 Subject: [PATCH 069/251] ASoC: Allow SND_SOC_WM8978 to be selected manually When using a DT-based multi-platform kernel, there's not always Kconfig logic that selects the right codec driver. Allow the user to manually select WM8978. This is needed for Armadillo 800 EVA using a generic r8a7740 multi-platform kernel. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 8838838e25ed..9c400a277592 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -712,7 +712,8 @@ config SND_SOC_WM8974 tristate config SND_SOC_WM8978 - tristate + tristate "Wolfson Microelectronics WM8978 codec" + depends on I2C config SND_SOC_WM8983 tristate From 98c5d36240e10c2e0e06e2bb10496291626d1d43 Mon Sep 17 00:00:00 2001 From: Paul Handrigan Date: Thu, 28 Aug 2014 10:54:08 -0500 Subject: [PATCH 070/251] ASoC: cs4265: Add CHIP_ID as a readable register MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reported-by: Zoltán Szenczi Signed-off-by: Paul Handrigan Signed-off-by: Mark Brown --- sound/soc/codecs/cs4265.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/cs4265.c b/sound/soc/codecs/cs4265.c index a20b30ca52c0..2dad15ae0530 100644 --- a/sound/soc/codecs/cs4265.c +++ b/sound/soc/codecs/cs4265.c @@ -77,6 +77,7 @@ static bool cs4265_readable_register(struct device *dev, unsigned int reg) case CS4265_INT_MASK: case CS4265_STATUS_MODE_MSB: case CS4265_STATUS_MODE_LSB: + case CS4265_CHIP_ID: return true; default: return false; From 7eef08554ca35454e6da0de8a74f7c96bc2e58e0 Mon Sep 17 00:00:00 2001 From: Brian Austin Date: Thu, 28 Aug 2014 10:02:40 -0500 Subject: [PATCH 071/251] ASoC: cs35l32: use true/false returns for bool functions Return true or false instead of 1 and 0 Reported-by: Fengguang Wu Signed-off-by: Brian Austin Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l32.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c index 9c6b2723d343..ca897c49afdf 100644 --- a/sound/soc/codecs/cs35l32.c +++ b/sound/soc/codecs/cs35l32.c @@ -121,9 +121,9 @@ static bool cs35l32_volatile_register(struct device *dev, unsigned int reg) case CS35L32_INT_STATUS_2: case CS35L32_INT_STATUS_3: case CS35L32_LED_STATUS: - return 1; + return true; default: - return 0; + return false; } } @@ -134,9 +134,9 @@ static bool cs35l32_precious_register(struct device *dev, unsigned int reg) case CS35L32_INT_STATUS_2: case CS35L32_INT_STATUS_3: case CS35L32_LED_STATUS: - return 1; + return true; default: - return 0; + return false; } } From 5c216cc3f37a6eecb4e12ab0248b66e6386da0fe Mon Sep 17 00:00:00 2001 From: Brian Austin Date: Thu, 28 Aug 2014 10:02:41 -0500 Subject: [PATCH 072/251] ASoC: cs42l52: use true/false returns for bool functions Return true or false instead of 1 and 0 Signed-off-by: Brian Austin Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l52.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c index 969167d8b71e..da4f758cd12a 100644 --- a/sound/soc/codecs/cs42l52.c +++ b/sound/soc/codecs/cs42l52.c @@ -176,9 +176,9 @@ static bool cs42l52_volatile_register(struct device *dev, unsigned int reg) case CS42L52_BATT_LEVEL: case CS42L52_SPK_STATUS: case CS42L52_CHARGE_PUMP: - return 1; + return true; default: - return 0; + return false; } } From c2b49ae678b8bd1fd4ea3e3ae106020d663e8969 Mon Sep 17 00:00:00 2001 From: Brian Austin Date: Thu, 28 Aug 2014 10:02:42 -0500 Subject: [PATCH 073/251] ASoC: cs42l56: use true/false returns for bool functions Return true or false instead of 1 and 0 Signed-off-by: Brian Austin Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l56.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/cs42l56.c b/sound/soc/codecs/cs42l56.c index c766a5a9ce80..b1c7396c80c8 100644 --- a/sound/soc/codecs/cs42l56.c +++ b/sound/soc/codecs/cs42l56.c @@ -171,9 +171,9 @@ static bool cs42l56_volatile_register(struct device *dev, unsigned int reg) { switch (reg) { case CS42L56_INT_STATUS: - return 1; + return true; default: - return 0; + return false; } } From b792346fa8660a22a06f118cebe47709f507914f Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Thu, 28 Aug 2014 14:07:11 +0300 Subject: [PATCH 074/251] ASoC: Remove unused cache_only from struct snd_soc_codec There are no real users for cache_only in "struct snd_soc_codec" so remove it and needless debugfs node. Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- include/sound/soc.h | 1 - sound/soc/soc-core.c | 2 -- 2 files changed, 3 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index edbb0d72ab38..ce09302bfd6d 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -792,7 +792,6 @@ struct snd_soc_codec { unsigned int ac97_registered:1; /* Codec has been AC97 registered */ unsigned int ac97_created:1; /* Codec has been created by SoC */ unsigned int cache_init:1; /* codec cache has been initialized */ - u32 cache_only; /* Suppress writes to hardware */ u32 cache_sync; /* Cache needs to be synced to hardware */ /* codec IO */ diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 419682693886..1b422c5c36c8 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -311,8 +311,6 @@ static void soc_init_codec_debugfs(struct snd_soc_component *component) debugfs_create_bool("cache_sync", 0444, codec->component.debugfs_root, &codec->cache_sync); - debugfs_create_bool("cache_only", 0444, codec->component.debugfs_root, - &codec->cache_only); codec->debugfs_reg = debugfs_create_file("codec_reg", 0644, codec->component.debugfs_root, From 1a83269d5c41b77f2a4bbb3828c668c96832742e Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 28 Aug 2014 17:54:38 +0800 Subject: [PATCH 075/251] ASoC: cs35l32: Remove unneeded regulator_bulk_free call in cs35l32_i2c_remove The regulator_bulk_free() call is not required because current code is using devm_regulator_bulk_get(). Signed-off-by: Axel Lin Acked-by: Brian Austin Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l32.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c index ca897c49afdf..b32d7a9d0c0f 100644 --- a/sound/soc/codecs/cs35l32.c +++ b/sound/soc/codecs/cs35l32.c @@ -562,8 +562,6 @@ static int cs35l32_i2c_remove(struct i2c_client *i2c_client) if (cs35l32->reset_gpio) gpiod_set_value_cansleep(cs35l32->reset_gpio, 0); - regulator_bulk_free(ARRAY_SIZE(cs35l32->supplies), cs35l32->supplies); - return 0; } From a4f87cea72d78f80c0bda1b4d8a821278eb1e4e2 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 28 Aug 2014 17:55:20 +0800 Subject: [PATCH 076/251] ASoC: cs42l56: Remove unneeded regulator_bulk_free call in cs42l56_remove The regulator_bulk_free() call is not required because current code is using devm_regulator_bulk_get(). Signed-off-by: Axel Lin Acked-by: Brian Austin Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l56.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/sound/soc/codecs/cs42l56.c b/sound/soc/codecs/cs42l56.c index b1c7396c80c8..bb74dd17fa26 100644 --- a/sound/soc/codecs/cs42l56.c +++ b/sound/soc/codecs/cs42l56.c @@ -1175,11 +1175,8 @@ static int cs42l56_probe(struct snd_soc_codec *codec) static int cs42l56_remove(struct snd_soc_codec *codec) { - struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec); - cs42l56_free_beep(codec); cs42l56_set_bias_level(codec, SND_SOC_BIAS_OFF); - regulator_bulk_free(ARRAY_SIZE(cs42l56->supplies), cs42l56->supplies); return 0; } From 5f609f282b59f111840e755bac8da980387e044e Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 28 Aug 2014 16:27:56 +0800 Subject: [PATCH 077/251] ASoC: cs35l32: Simplify implementation of cs35l32_codec_set_sysclk Use single snd_soc_update_bits() call to update the register bits. Signed-off-by: Axel Lin Tested-by: Brian Austin Acked-by: Brian Austin Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l32.c | 28 +++++++--------------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c index b32d7a9d0c0f..76f628bd7f2b 100644 --- a/sound/soc/codecs/cs35l32.c +++ b/sound/soc/codecs/cs35l32.c @@ -242,41 +242,27 @@ static struct snd_soc_dai_driver cs35l32_dai[] = { static int cs35l32_codec_set_sysclk(struct snd_soc_codec *codec, int clk_id, int source, unsigned int freq, int dir) { + unsigned int val; switch (freq) { case 6000000: - snd_soc_update_bits(codec, CS35L32_CLK_CTL, - CS35L32_MCLK_DIV2_MASK, 0); - snd_soc_update_bits(codec, CS35L32_CLK_CTL, - CS35L32_MCLK_RATIO_MASK, - CS35L32_MCLK_RATIO); + val = CS35L32_MCLK_RATIO; break; case 12000000: - snd_soc_update_bits(codec, CS35L32_CLK_CTL, - CS35L32_MCLK_DIV2_MASK, - CS35L32_MCLK_DIV2_MASK); - snd_soc_update_bits(codec, CS35L32_CLK_CTL, - CS35L32_MCLK_RATIO_MASK, - CS35L32_MCLK_RATIO); + val = CS35L32_MCLK_DIV2_MASK | CS35L32_MCLK_RATIO; break; case 6144000: - snd_soc_update_bits(codec, CS35L32_CLK_CTL, - CS35L32_MCLK_DIV2_MASK, 0); - snd_soc_update_bits(codec, CS35L32_CLK_CTL, - CS35L32_MCLK_RATIO_MASK, 0); + val = 0; break; case 12288000: - snd_soc_update_bits(codec, CS35L32_CLK_CTL, - CS35L32_MCLK_DIV2_MASK, - CS35L32_MCLK_DIV2_MASK); - snd_soc_update_bits(codec, CS35L32_CLK_CTL, - CS35L32_MCLK_RATIO_MASK, 0); + val = CS35L32_MCLK_DIV2_MASK; break; default: return -EINVAL; } - return 0; + return snd_soc_update_bits(codec, CS35L32_CLK_CTL, + CS35L32_MCLK_DIV2_MASK | CS35L32_MCLK_RATIO_MASK, val); } static struct snd_soc_codec_driver soc_codec_dev_cs35l32 = { From 2d82eeb02655e32358efd42598d8276284c23364 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 27 Aug 2014 20:07:46 -0700 Subject: [PATCH 078/251] ASoC: simple-card: use asoc_simple_xxx prefix simple-card driver is using asoc_simple_xxx() prefix. simple_card_dai_link_of() should be asoc_simple_card_dai_link_of(). Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 21b0ea24bc1d..c5445b0ae9ff 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -163,11 +163,11 @@ asoc_simple_card_sub_parse_of(struct device_node *np, return 0; } -static int simple_card_dai_link_of(struct device_node *node, - struct device *dev, - struct snd_soc_dai_link *dai_link, - struct simple_dai_props *dai_props, - bool is_top_level_node) +static int asoc_simple_card_dai_link_of(struct device_node *node, + struct device *dev, + struct snd_soc_dai_link *dai_link, + struct simple_dai_props *dai_props, + bool is_top_level_node) { struct device_node *np = NULL; struct device_node *bitclkmaster = NULL; @@ -337,16 +337,18 @@ static int asoc_simple_card_parse_of(struct device_node *node, int i; for (i = 0; (np = of_get_next_child(node, np)); i++) { dev_dbg(dev, "\tlink %d:\n", i); - ret = simple_card_dai_link_of(np, dev, dai_link + i, - dai_props + i, false); + ret = asoc_simple_card_dai_link_of(np, dev, + dai_link + i, + dai_props + i, + false); if (ret < 0) { of_node_put(np); return ret; } } } else { - ret = simple_card_dai_link_of(node, dev, dai_link, dai_props, - true); + ret = asoc_simple_card_dai_link_of(node, dev, + dai_link, dai_props, true); if (ret < 0) return ret; } From 179949bc04c7157a4b2279f62a842638b61f78f9 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 27 Aug 2014 20:08:06 -0700 Subject: [PATCH 079/251] ASoC: simple-card: remove dai_link->cpu_dai_name when DT f687d900d30a61dda38db2a99239f5284a86a309 (ASoC: simple-card: cpu_dai_name creates confusion when DT case) removed dai_link->cpu_dai_name when DT case, since it uses DT phand in soc_bind_dai_link(). This binding will fail if it has cpu_dai_name. 6a91a17bd7b92b2d2aa9ece85457f52a62fd7708 (ASoC: simple-card: Handle many DAI links) added multi DAI link support to simple-card driver. Then, removing cpu_dai_name was cared only single DAI. But, it is needed in all DT cases. This patch moves it to asoc_simple_card_dai_link_of() so that care about all DAIs. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index c5445b0ae9ff..e8185a0b933f 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -285,6 +285,17 @@ static int asoc_simple_card_dai_link_of(struct device_node *node, dai_props->codec_dai.fmt, dai_props->codec_dai.sysclk); + /* + * soc_bind_dai_link() will check cpu name + * after of_node matching if dai_link has cpu_dai_name. + * but, it will never match if name was created by fmt_single_name() + * remove cpu_dai_name to escape name matching. + * see + * fmt_single_name() + * fmt_multiple_name() + */ + dai_link->cpu_dai_name = NULL; + dai_link_of_err: if (np) of_node_put(np); @@ -429,18 +440,6 @@ static int asoc_simple_card_probe(struct platform_device *pdev) goto err; } - /* - * soc_bind_dai_link() will check cpu name - * after of_node matching if dai_link has cpu_dai_name. - * but, it will never match if name was created by fmt_single_name() - * remove cpu_dai_name to escape name matching. - * see - * fmt_single_name() - * fmt_multiple_name() - */ - if (num_links == 1) - dai_link->cpu_dai_name = NULL; - } else { struct asoc_simple_card_info *cinfo; From a5960bd5984c808cdf7aa528e162e9e20e61b923 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 27 Aug 2014 20:08:27 -0700 Subject: [PATCH 080/251] ASoC: simple-card: dai_link->init should be cared when multi DAI 6a91a17bd7b92b2d2aa9ece85457f52a62fd7708 (ASoC: simple-card: Handle many DAI links) added multi DAI support on simple-card. This means priv->dai_link might be pointer of multi DAI. dai_link->init is needed for all DAI. This patch cares it for all DAIs on DT/non-DT Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index e8185a0b933f..89027047364f 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -274,6 +274,7 @@ static int asoc_simple_card_dai_link_of(struct device_node *node, dai_link->codec_dai_name); dai_link->name = dai_link->stream_name = name; dai_link->ops = &asoc_simple_card_ops; + dai_link->init = asoc_simple_card_dai_init; dev_dbg(dev, "\tname : %s\n", dai_link->stream_name); dev_dbg(dev, "\tcpu : %s / %04x / %d\n", @@ -465,6 +466,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev) dai_link->codec_name = cinfo->codec; dai_link->cpu_dai_name = cinfo->cpu_dai.name; dai_link->codec_dai_name = cinfo->codec_dai.name; + dai_link->init = asoc_simple_card_dai_init; memcpy(&priv->dai_props->cpu_dai, &cinfo->cpu_dai, sizeof(priv->dai_props->cpu_dai)); memcpy(&priv->dai_props->codec_dai, &cinfo->codec_dai, @@ -474,11 +476,6 @@ static int asoc_simple_card_probe(struct platform_device *pdev) priv->dai_props->codec_dai.fmt |= cinfo->daifmt; } - /* - * init snd_soc_dai_link - */ - dai_link->init = asoc_simple_card_dai_init; - snd_soc_card_set_drvdata(&priv->snd_card, priv); ret = devm_snd_soc_register_card(&pdev->dev, &priv->snd_card); From a44a750e5299fe2ece5aa68e8562dd6e2c2b16f4 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 27 Aug 2014 20:08:47 -0700 Subject: [PATCH 081/251] ASoC: simple-card: use common for_each_child_of_node() for loop Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 89027047364f..fd8b04588948 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -346,8 +346,9 @@ static int asoc_simple_card_parse_of(struct device_node *node, if (multi) { struct device_node *np = NULL; - int i; - for (i = 0; (np = of_get_next_child(node, np)); i++) { + int i = 0; + + for_each_child_of_node(node, np) { dev_dbg(dev, "\tlink %d:\n", i); ret = asoc_simple_card_dai_link_of(np, dev, dai_link + i, @@ -357,6 +358,7 @@ static int asoc_simple_card_parse_of(struct device_node *node, of_node_put(np); return ret; } + i++; } } else { ret = asoc_simple_card_dai_link_of(node, dev, From 085f3ec6fd6c87907c4a19481dc13f02ecfcd316 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 1 Sep 2014 12:46:37 +0300 Subject: [PATCH 082/251] ASoC: tlv320aic31xx: Correct interface register 2 variable name Rename iface_reg3 to iface_reg2 since this variable is actually used for interface register 2. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic31xx.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index 0f64c7890eed..9f9d23b94c22 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -813,7 +813,7 @@ static int aic31xx_set_dai_fmt(struct snd_soc_dai *codec_dai, { struct snd_soc_codec *codec = codec_dai->codec; u8 iface_reg1 = 0; - u8 iface_reg3 = 0; + u8 iface_reg2 = 0; u8 dsp_a_val = 0; dev_dbg(codec->dev, "## %s: fmt = 0x%x\n", __func__, fmt); @@ -838,7 +838,7 @@ static int aic31xx_set_dai_fmt(struct snd_soc_dai *codec_dai, /* NOTE: BCLKINV bit value 1 equas NB and 0 equals IB */ switch (fmt & SND_SOC_DAIFMT_INV_MASK) { case SND_SOC_DAIFMT_NB_NF: - iface_reg3 |= AIC31XX_BCLKINV_MASK; + iface_reg2 |= AIC31XX_BCLKINV_MASK; break; case SND_SOC_DAIFMT_IB_NF: break; @@ -870,7 +870,7 @@ static int aic31xx_set_dai_fmt(struct snd_soc_dai *codec_dai, dsp_a_val); snd_soc_update_bits(codec, AIC31XX_IFACE2, AIC31XX_BCLKINV_MASK, - iface_reg3); + iface_reg2); return 0; } From 75c3daaad5a2f791e0fbad732690130ce1bc55d2 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 1 Sep 2014 08:47:50 +0800 Subject: [PATCH 083/251] ASoC: es8328: fix error return code in es8328_codec_probe() Fix to return a negative error code from the error handling case instead of 0, as done elsewhere in this function. Signed-off-by: Wei Yongjun Signed-off-by: Mark Brown --- sound/soc/codecs/es8328.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/es8328.c b/sound/soc/codecs/es8328.c index 7a9f65ad183d..3ff787063304 100644 --- a/sound/soc/codecs/es8328.c +++ b/sound/soc/codecs/es8328.c @@ -665,6 +665,7 @@ static int es8328_codec_probe(struct snd_soc_codec *codec) es8328->clk = devm_clk_get(codec->dev, NULL); if (IS_ERR(es8328->clk)) { dev_err(codec->dev, "codec clock missing or invalid\n"); + ret = PTR_ERR(es8328->clk); goto clk_fail; } From eadb0019d206591e34e864b62059b292e157d8fc Mon Sep 17 00:00:00 2001 From: Xiubo Li Date: Fri, 29 Aug 2014 15:12:12 +0800 Subject: [PATCH 084/251] ASoC: fsl-sai: using 'lsb-first' property instead of 'big-endian-data'. The 'big-endian-data' property is originally used to indicate whether the LSB firstly or MSB firstly will be transmitted to the CODEC or received from the CODEC, and there has nothing relation to the memory data. Generally, if the audio data in big endian format, which will be using the bytes reversion, Here this can only be used to bits reversion. So using the 'lsb-first' instead of 'big-endian-data' can make the code to be readable easier and more easy to understand what this property is used to do. This property used for configuring whether the LSB or the MSB is transmitted first for the fifo data. Signed-off-by: Xiubo Li Acked-by: Nicolin Chen Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/fsl-sai.txt | 8 ++++---- sound/soc/fsl/fsl_sai.c | 6 +++--- sound/soc/fsl/fsl_sai.h | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/fsl-sai.txt b/Documentation/devicetree/bindings/sound/fsl-sai.txt index 06a405e7f3e7..4956b14d4b06 100644 --- a/Documentation/devicetree/bindings/sound/fsl-sai.txt +++ b/Documentation/devicetree/bindings/sound/fsl-sai.txt @@ -20,9 +20,9 @@ Required properties: See ../pinctrl/pinctrl-bindings.txt for details of the property values. - big-endian: Boolean property, required if all the FTM_PWM registers are big-endian rather than little-endian. -- big-endian-data: If this property is absent, the little endian mode will - be in use as default, or the big endian mode will be in use for all the - fifo data. +- lsb-first: Configures whether the LSB or the MSB is transmitted first for + the fifo data. If this property is absent, the MSB is transmitted first as + default, or the LSB is transmitted first. - fsl,sai-synchronous-rx: This is a boolean property. If present, indicating that SAI will work in the synchronous mode (sync Tx with Rx) which means both the transimitter and receiver will send and receive data by following @@ -53,5 +53,5 @@ sai2: sai@40031000 { dmas = <&edma0 0 VF610_EDMA_MUXID0_SAI2_TX>, <&edma0 0 VF610_EDMA_MUXID0_SAI2_RX>; big-endian; - big-endian-data; + lsb-first; }; diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index a6eb7849959c..7eeb1dd8ce27 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -175,7 +175,7 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai, bool tx = fsl_dir == FSL_FMT_TRANSMITTER; u32 val_cr2 = 0, val_cr4 = 0; - if (!sai->big_endian_data) + if (!sai->is_lsb_first) val_cr4 |= FSL_SAI_CR4_MF; /* DAI mode */ @@ -304,7 +304,7 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, val_cr5 |= FSL_SAI_CR5_WNW(word_width); val_cr5 |= FSL_SAI_CR5_W0W(word_width); - if (sai->big_endian_data) + if (sai->is_lsb_first) val_cr5 |= FSL_SAI_CR5_FBT(0); else val_cr5 |= FSL_SAI_CR5_FBT(word_width - 1); @@ -573,7 +573,7 @@ static int fsl_sai_probe(struct platform_device *pdev) if (of_device_is_compatible(pdev->dev.of_node, "fsl,imx6sx-sai")) sai->sai_on_imx = true; - sai->big_endian_data = of_property_read_bool(np, "big-endian-data"); + sai->is_lsb_first = of_property_read_bool(np, "lsb-first"); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); base = devm_ioremap_resource(&pdev->dev, res); diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h index 2cded440d567..34667209b607 100644 --- a/sound/soc/fsl/fsl_sai.h +++ b/sound/soc/fsl/fsl_sai.h @@ -132,7 +132,7 @@ struct fsl_sai { struct clk *bus_clk; struct clk *mclk_clk[FSL_SAI_MCLK_MAX]; - bool big_endian_data; + bool is_lsb_first; bool is_dsp_mode; bool sai_on_imx; bool synchronous[2]; From ae70b190fce4a09a969dd69d0bd1c33441e24e60 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 25 Aug 2014 10:20:44 +0200 Subject: [PATCH 085/251] ASoC: ab8500-codec: Revert back to regmap Commit ff795d614bfa ("ASoC: ab8500: Convert register I/O to regmap") initially converted the ab8500 CODEC driver to use regmap rather than legacy ASoC IO. This was reverted though in commit 63e6d43bf80d ("ASoC: ab8500: Revert to using custom I/O functions") since the inital conversion was not working properly. This was presumebly because the SOC_SINGLE_XR_SX controls, which are used by this driver, did not properly support regmap at that point. This has since been fixed in commit 6137a5ca326d ("ASoC: Prepare SOC_SINGLE_XR_SX controls for regmap"). So revert back to regmap again. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/ab8500-codec.c | 70 +++++++++++++++------------------ 1 file changed, 32 insertions(+), 38 deletions(-) diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c index 62cf231f34cb..fd43827bb856 100644 --- a/sound/soc/codecs/ab8500-codec.c +++ b/sound/soc/codecs/ab8500-codec.c @@ -125,6 +125,8 @@ struct ab8500_codec_drvdata_dbg { /* Private data for AB8500 device-driver */ struct ab8500_codec_drvdata { + struct regmap *regmap; + /* Sidetone */ long *sid_fir_values; enum sid_state sid_status; @@ -165,49 +167,35 @@ static inline const char *amic_type_str(enum amic_type type) */ /* Read a register from the audio-bank of AB8500 */ -static unsigned int ab8500_codec_read_reg(struct snd_soc_codec *codec, - unsigned int reg) +static int ab8500_codec_read_reg(void *context, unsigned int reg, + unsigned int *value) { + struct device *dev = context; int status; - unsigned int value = 0; u8 value8; - status = abx500_get_register_interruptible(codec->dev, AB8500_AUDIO, - reg, &value8); - if (status < 0) { - dev_err(codec->dev, - "%s: ERROR: Register (0x%02x:0x%02x) read failed (%d).\n", - __func__, (u8)AB8500_AUDIO, (u8)reg, status); - } else { - dev_dbg(codec->dev, - "%s: Read 0x%02x from register 0x%02x:0x%02x\n", - __func__, value8, (u8)AB8500_AUDIO, (u8)reg); - value = (unsigned int)value8; - } - - return value; -} - -/* Write to a register in the audio-bank of AB8500 */ -static int ab8500_codec_write_reg(struct snd_soc_codec *codec, - unsigned int reg, unsigned int value) -{ - int status; - - status = abx500_set_register_interruptible(codec->dev, AB8500_AUDIO, - reg, value); - if (status < 0) - dev_err(codec->dev, - "%s: ERROR: Register (%02x:%02x) write failed (%d).\n", - __func__, (u8)AB8500_AUDIO, (u8)reg, status); - else - dev_dbg(codec->dev, - "%s: Wrote 0x%02x into register %02x:%02x\n", - __func__, (u8)value, (u8)AB8500_AUDIO, (u8)reg); + status = abx500_get_register_interruptible(dev, AB8500_AUDIO, + reg, &value8); + *value = (unsigned int)value8; return status; } +/* Write to a register in the audio-bank of AB8500 */ +static int ab8500_codec_write_reg(void *context, unsigned int reg, + unsigned int value) +{ + struct device *dev = context; + + return abx500_set_register_interruptible(dev, AB8500_AUDIO, + reg, value); +} + +static const struct regmap_config ab8500_codec_regmap = { + .reg_read = ab8500_codec_read_reg, + .reg_write = ab8500_codec_write_reg, +}; + /* * Controls - DAPM */ @@ -2564,9 +2552,6 @@ static int ab8500_codec_probe(struct snd_soc_codec *codec) static struct snd_soc_codec_driver ab8500_codec_driver = { .probe = ab8500_codec_probe, - .read = ab8500_codec_read_reg, - .write = ab8500_codec_write_reg, - .reg_word_size = sizeof(u8), .controls = ab8500_ctrls, .num_controls = ARRAY_SIZE(ab8500_ctrls), .dapm_widgets = ab8500_dapm_widgets, @@ -2591,6 +2576,15 @@ static int ab8500_codec_driver_probe(struct platform_device *pdev) drvdata->anc_status = ANC_UNCONFIGURED; dev_set_drvdata(&pdev->dev, drvdata); + drvdata->regmap = devm_regmap_init(&pdev->dev, NULL, &pdev->dev, + &ab8500_codec_regmap); + if (IS_ERR(drvdata->regmap)) { + status = PTR_ERR(drvdata->regmap); + dev_err(&pdev->dev, "%s: Failed to allocate regmap: %d\n", + __func__, status); + return status; + } + dev_dbg(&pdev->dev, "%s: Register codec.\n", __func__); status = snd_soc_register_codec(&pdev->dev, &ab8500_codec_driver, ab8500_codec_dai, From e8818fa8c07d57242552c89d0b469892978b20fe Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Wed, 3 Sep 2014 11:31:04 +0800 Subject: [PATCH 086/251] ALSA: hda/realtek - move DELL2_MIC_NO_PRESENCE quirk for alc292 Cc: David Henningsson Signed-off-by: Hui Wang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index e0fff47b5740..16ee9e7db2e0 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4812,21 +4812,13 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x0742, "Acer AO756", ALC271_FIXUP_HP_GATE_MIC_JACK), SND_PCI_QUIRK(0x1025, 0x0775, "Acer Aspire E1-572", ALC271_FIXUP_HP_GATE_MIC_JACK_E1_572), SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z), - SND_PCI_QUIRK(0x1028, 0x05bd, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x05be, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x05c4, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x05c5, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x05c6, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x05c7, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x05c8, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x05c9, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x05ca, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x05cb, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x05cc, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x05cd, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x05da, "Dell Vostro 5460", ALC290_FIXUP_SUBWOOFER), - SND_PCI_QUIRK(0x1028, 0x05de, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x05e0, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x05e9, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x05ea, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x05eb, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), @@ -4855,9 +4847,6 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1028, 0x064b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0668, "Dell", ALC255_FIXUP_DELL2_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0669, "Dell", ALC255_FIXUP_DELL2_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x0684, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x15cc, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x15cd, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x164a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x164b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2), @@ -5209,6 +5198,30 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { {0x1d, 0x40700001}, {0x1e, 0x411111f0}, {0x21, 0x02211030}), + SND_HDA_PIN_QUIRK(0x10ec0292, 0x1028, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE, + {0x12, 0x90a60140}, + {0x13, 0x411111f0}, + {0x14, 0x90170110}, + {0x15, 0x0221401f}, + {0x16, 0x01014020}, + {0x18, 0x411111f0}, + {0x19, 0x01a19030}, + {0x1a, 0x411111f0}, + {0x1b, 0x411111f0}, + {0x1d, 0x40700001}, + {0x1e, 0x411111f0}), + SND_HDA_PIN_QUIRK(0x10ec0292, 0x1028, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE, + {0x12, 0x90a60140}, + {0x13, 0x411111f0}, + {0x14, 0x90170110}, + {0x15, 0x0221401f}, + {0x16, 0x01014020}, + {0x18, 0x02a19031}, + {0x19, 0x01a1903e}, + {0x1a, 0x411111f0}, + {0x1b, 0x411111f0}, + {0x1d, 0x40700001}, + {0x1e, 0x411111f0}), SND_HDA_PIN_QUIRK(0x10ec0292, 0x1028, "Dell", ALC269_FIXUP_DELL3_MIC_NO_PRESENCE, {0x12, 0x90a60140}, {0x13, 0x411111f0}, From bc262179a9196cb4eba266254f851253be0d3533 Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Wed, 3 Sep 2014 11:31:05 +0800 Subject: [PATCH 087/251] ALSA: hda/realtek - move DELL1_MIC_NO_PRESENCE quirk for alc283 Cc: David Henningsson Signed-off-by: Hui Wang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 32 +++++++++++--------------------- 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 16ee9e7db2e0..f8babdfbfb45 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4812,32 +4812,11 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x0742, "Acer AO756", ALC271_FIXUP_HP_GATE_MIC_JACK), SND_PCI_QUIRK(0x1025, 0x0775, "Acer Aspire E1-572", ALC271_FIXUP_HP_GATE_MIC_JACK_E1_572), SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z), - SND_PCI_QUIRK(0x1028, 0x05c4, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x05c5, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x05c6, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x05c7, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x05c8, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x05c9, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x05da, "Dell Vostro 5460", ALC290_FIXUP_SUBWOOFER), - SND_PCI_QUIRK(0x1028, 0x05e9, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x05ea, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x05eb, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x05ec, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x05ed, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x05ee, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x05f3, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x05f4, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x05f5, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x05f6, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x05f8, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x05f9, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x05fb, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x0606, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x0608, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x0609, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0610, "Dell", ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED), - SND_PCI_QUIRK(0x1028, 0x0613, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x0614, "Dell Inspiron 3135", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0615, "Dell Vostro 5470", ALC290_FIXUP_SUBWOOFER_HSJACK), SND_PCI_QUIRK(0x1028, 0x0616, "Dell Vostro 5470", ALC290_FIXUP_SUBWOOFER_HSJACK), SND_PCI_QUIRK(0x1028, 0x061f, "Dell", ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED), @@ -5198,6 +5177,17 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { {0x1d, 0x40700001}, {0x1e, 0x411111f0}, {0x21, 0x02211030}), + SND_HDA_PIN_QUIRK(0x10ec0283, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, + {0x12, 0x90a60130}, + {0x14, 0x90170110}, + {0x17, 0x40020008}, + {0x18, 0x411111f0}, + {0x19, 0x03a11020}, + {0x1a, 0x411111f0}, + {0x1b, 0x411111f0}, + {0x1d, 0x40e00001}, + {0x1e, 0x411111f0}, + {0x21, 0x0321101f}), SND_HDA_PIN_QUIRK(0x10ec0292, 0x1028, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE, {0x12, 0x90a60140}, {0x13, 0x411111f0}, From 29a4f69973eede670f8c0735a064ea4a8cd90ac5 Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Wed, 3 Sep 2014 11:31:06 +0800 Subject: [PATCH 088/251] ALSA: hda/realtek - move DELL1_MIC_NO_PRESENCE quirk for alc255 Cc: David Henningsson Signed-off-by: Hui Wang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index f8babdfbfb45..445b856796c4 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4821,7 +4821,6 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1028, 0x0616, "Dell Vostro 5470", ALC290_FIXUP_SUBWOOFER_HSJACK), SND_PCI_QUIRK(0x1028, 0x061f, "Dell", ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED), SND_PCI_QUIRK(0x1028, 0x0638, "Dell Inspiron 5439", ALC290_FIXUP_MONO_SPEAKERS_HSJACK), - SND_PCI_QUIRK(0x1028, 0x063f, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x064a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x064b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0668, "Dell", ALC255_FIXUP_DELL2_MIC_NO_PRESENCE), From c77900e63abd9e2bdf385ba846a22858a0ed50a7 Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Wed, 3 Sep 2014 11:31:07 +0800 Subject: [PATCH 089/251] ALSA: hda/realtek - move DELL2_MIC_NO_PRESENCE quirk for alc255 Cc: David Henningsson Signed-off-by: Hui Wang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 445b856796c4..b975c5a63005 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4823,8 +4823,6 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1028, 0x0638, "Dell Inspiron 5439", ALC290_FIXUP_MONO_SPEAKERS_HSJACK), SND_PCI_QUIRK(0x1028, 0x064a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x064b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x0668, "Dell", ALC255_FIXUP_DELL2_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x0669, "Dell", ALC255_FIXUP_DELL2_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x164a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x164b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2), @@ -5066,6 +5064,17 @@ static const struct hda_model_fixup alc269_fixup_models[] = { }; static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { + SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL2_MIC_NO_PRESENCE, + {0x12, 0x40300000}, + {0x14, 0x90170110}, + {0x17, 0x411111f0}, + {0x18, 0x411111f0}, + {0x19, 0x411111f0}, + {0x1a, 0x411111f0}, + {0x1b, 0x02a11030}, + {0x1d, 0x40538029}, + {0x1e, 0x411111f0}, + {0x21, 0x02211020}), SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, {0x12, 0x90a60140}, {0x14, 0x90170110}, From 2c609999759c6964d99a614e8259fa700b5b337c Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Wed, 3 Sep 2014 11:31:08 +0800 Subject: [PATCH 090/251] ALSA: hda/realtek - move HP_MUTE_LED_MIC1 quirk for alc282 Cc: David Henningsson Signed-off-by: Hui Wang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 79 ++++++++++++++++++++++++----------- 1 file changed, 55 insertions(+), 24 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index b975c5a63005..0bba21708904 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4827,19 +4827,9 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1028, 0x164b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2), SND_PCI_QUIRK(0x103c, 0x18e6, "HP", ALC269_FIXUP_HP_GPIO_LED), - SND_PCI_QUIRK(0x103c, 0x1973, "HP Pavilion", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x1983, "HP Pavilion", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x218b, "HP", ALC269_FIXUP_LIMIT_INT_MIC_BOOST_MUTE_LED), /* ALC282 */ - SND_PCI_QUIRK(0x103c, 0x21f8, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x21f9, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x220d, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x220e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x220f, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2210, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x2211, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x2212, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x2213, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2214, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2234, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x2235, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), @@ -4855,30 +4845,16 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x224b, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x224c, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x224d, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), - SND_PCI_QUIRK(0x103c, 0x2266, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x2267, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2268, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x2269, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x226a, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x226b, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x226c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x226d, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x226e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x226f, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x227a, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x227b, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x229e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x22a0, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x22b2, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x22b7, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x22bf, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x22c0, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x22c1, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x22c2, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x22cd, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x22ce, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x22cf, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x22d0, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x22da, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x22db, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x22dc, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), @@ -5163,6 +5139,61 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { {0x1d, 0x40f41905}, {0x1e, 0x411111f0}, {0x21, 0x0321101f}), + SND_HDA_PIN_QUIRK(0x10ec0282, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1, + {0x12, 0x99a30130}, + {0x14, 0x90170110}, + {0x17, 0x40020008}, + {0x18, 0x411111f0}, + {0x19, 0x03a11020}, + {0x1a, 0x411111f0}, + {0x1b, 0x411111f0}, + {0x1d, 0x40e00001}, + {0x1e, 0x411111f0}, + {0x21, 0x03211040}), + SND_HDA_PIN_QUIRK(0x10ec0282, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1, + {0x12, 0x99a30130}, + {0x14, 0x90170110}, + {0x17, 0x40000000}, + {0x18, 0x411111f0}, + {0x19, 0x03a11030}, + {0x1a, 0x411111f0}, + {0x1b, 0x411111f0}, + {0x1d, 0x40e00001}, + {0x1e, 0x411111f0}, + {0x21, 0x03211020}), + SND_HDA_PIN_QUIRK(0x10ec0282, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1, + {0x12, 0x99a30130}, + {0x14, 0x90170110}, + {0x17, 0x40000000}, + {0x18, 0x411111f0}, + {0x19, 0x03a11030}, + {0x1a, 0x411111f0}, + {0x1b, 0x411111f0}, + {0x1d, 0x40f00001}, + {0x1e, 0x411111f0}, + {0x21, 0x03211020}), + SND_HDA_PIN_QUIRK(0x10ec0282, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1, + {0x12, 0x99a30130}, + {0x14, 0x90170110}, + {0x17, 0x40000000}, + {0x18, 0x411111f0}, + {0x19, 0x04a11020}, + {0x1a, 0x411111f0}, + {0x1b, 0x411111f0}, + {0x1d, 0x40f00001}, + {0x1e, 0x411111f0}, + {0x21, 0x0421101f}), + SND_HDA_PIN_QUIRK(0x10ec0282, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1, + {0x12, 0x99a30130}, + {0x14, 0x90170110}, + {0x17, 0x40000000}, + {0x18, 0x411111f0}, + {0x19, 0x03a11030}, + {0x1a, 0x411111f0}, + {0x1b, 0x411111f0}, + {0x1d, 0x40f00001}, + {0x1e, 0x411111f0}, + {0x21, 0x04211020}), SND_HDA_PIN_QUIRK(0x10ec0283, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, {0x12, 0x90a60130}, {0x14, 0x90170110}, From e4442bcf1aa166a2b132ea9fde47036744a7f8a3 Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Wed, 3 Sep 2014 11:31:09 +0800 Subject: [PATCH 091/251] ALSA: hda/realtek - move HP_MUTE_LED_MIC1 quirk for alc290 Cc: David Henningsson Signed-off-by: Hui Wang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 104 +++++++++++++++++++++++++++++----- 1 file changed, 91 insertions(+), 13 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 0bba21708904..edb0fe1b8f1b 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4850,7 +4850,6 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x226b, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x226e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x229e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x22a0, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x22b2, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x22b7, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x22bf, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), @@ -4883,8 +4882,6 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x2259, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x225a, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x2260, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x2261, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x2262, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2263, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2264, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2265, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), @@ -4892,23 +4889,13 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x2273, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x2277, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x2278, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), - SND_PCI_QUIRK(0x103c, 0x227d, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x227e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x227f, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x2280, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x2281, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2282, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x2289, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x228a, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x228b, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x228c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x228d, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x228e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x22c5, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x22c6, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x22c7, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x22c8, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x22c3, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x22c4, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2334, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2335, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), @@ -5227,6 +5214,97 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { {0x1d, 0x40e00001}, {0x1e, 0x411111f0}, {0x21, 0x0321101f}), + SND_HDA_PIN_QUIRK(0x10ec0290, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1, + {0x12, 0x99a30130}, + {0x13, 0x40000000}, + {0x14, 0x411111f0}, + {0x15, 0x04211040}, + {0x16, 0x411111f0}, + {0x17, 0x411111f0}, + {0x18, 0x90170112}, + {0x19, 0x411111f0}, + {0x1a, 0x04a11020}, + {0x1b, 0x411111f0}, + {0x1d, 0x4075812d}, + {0x1e, 0x411111f0}), + SND_HDA_PIN_QUIRK(0x10ec0290, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1, + {0x12, 0x99a30130}, + {0x13, 0x40000000}, + {0x14, 0x411111f0}, + {0x15, 0x04211040}, + {0x16, 0x411111f0}, + {0x17, 0x411111f0}, + {0x18, 0x90170110}, + {0x19, 0x411111f0}, + {0x1a, 0x04a11020}, + {0x1b, 0x411111f0}, + {0x1d, 0x4075812d}, + {0x1e, 0x411111f0}), + SND_HDA_PIN_QUIRK(0x10ec0290, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1, + {0x12, 0x99a30130}, + {0x13, 0x40000000}, + {0x14, 0x411111f0}, + {0x15, 0x0421101f}, + {0x16, 0x411111f0}, + {0x17, 0x411111f0}, + {0x18, 0x411111f0}, + {0x19, 0x411111f0}, + {0x1a, 0x04a11020}, + {0x1b, 0x411111f0}, + {0x1d, 0x4075812d}, + {0x1e, 0x411111f0}), + SND_HDA_PIN_QUIRK(0x10ec0290, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1, + {0x12, 0x99a30130}, + {0x13, 0x40000000}, + {0x14, 0x411111f0}, + {0x15, 0x04211020}, + {0x16, 0x411111f0}, + {0x17, 0x411111f0}, + {0x18, 0x411111f0}, + {0x19, 0x411111f0}, + {0x1a, 0x04a11040}, + {0x1b, 0x411111f0}, + {0x1d, 0x4076a12d}, + {0x1e, 0x411111f0}), + SND_HDA_PIN_QUIRK(0x10ec0290, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1, + {0x12, 0x99a30130}, + {0x13, 0x40000000}, + {0x14, 0x90170110}, + {0x15, 0x04211020}, + {0x16, 0x411111f0}, + {0x17, 0x411111f0}, + {0x18, 0x411111f0}, + {0x19, 0x411111f0}, + {0x1a, 0x04a11040}, + {0x1b, 0x411111f0}, + {0x1d, 0x4076a12d}, + {0x1e, 0x411111f0}), + SND_HDA_PIN_QUIRK(0x10ec0290, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1, + {0x12, 0x99a30130}, + {0x13, 0x40000000}, + {0x14, 0x90170110}, + {0x15, 0x04211020}, + {0x16, 0x411111f0}, + {0x17, 0x411111f0}, + {0x18, 0x411111f0}, + {0x19, 0x411111f0}, + {0x1a, 0x04a11020}, + {0x1b, 0x411111f0}, + {0x1d, 0x4076a12d}, + {0x1e, 0x411111f0}), + SND_HDA_PIN_QUIRK(0x10ec0290, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1, + {0x12, 0x99a30130}, + {0x13, 0x40000000}, + {0x14, 0x90170110}, + {0x15, 0x0421101f}, + {0x16, 0x411111f0}, + {0x17, 0x411111f0}, + {0x18, 0x411111f0}, + {0x19, 0x411111f0}, + {0x1a, 0x04a11020}, + {0x1b, 0x411111f0}, + {0x1d, 0x4075812d}, + {0x1e, 0x411111f0}), SND_HDA_PIN_QUIRK(0x10ec0292, 0x1028, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE, {0x12, 0x90a60140}, {0x13, 0x411111f0}, From 200afc097c79e906ea8f420d649b3906b27647e4 Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Wed, 3 Sep 2014 11:31:10 +0800 Subject: [PATCH 092/251] ALSA: hda/realtek - move HP_LINE1_MIC1_LED quirk for alc282 Cc: David Henningsson Signed-off-by: Hui Wang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index edb0fe1b8f1b..c36144ba6c40 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4831,20 +4831,11 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { /* ALC282 */ SND_PCI_QUIRK(0x103c, 0x2210, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2214, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x2234, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), - SND_PCI_QUIRK(0x103c, 0x2235, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x2236, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x2237, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x2238, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x2239, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), - SND_PCI_QUIRK(0x103c, 0x2246, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), - SND_PCI_QUIRK(0x103c, 0x2247, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), - SND_PCI_QUIRK(0x103c, 0x2248, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), - SND_PCI_QUIRK(0x103c, 0x2249, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), - SND_PCI_QUIRK(0x103c, 0x224a, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x224b, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), - SND_PCI_QUIRK(0x103c, 0x224c, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), - SND_PCI_QUIRK(0x103c, 0x224d, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x2268, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x226a, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x226b, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), @@ -5181,6 +5172,17 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { {0x1d, 0x40f00001}, {0x1e, 0x411111f0}, {0x21, 0x04211020}), + SND_HDA_PIN_QUIRK(0x10ec0282, 0x103c, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED, + {0x12, 0x90a60140}, + {0x14, 0x90170110}, + {0x17, 0x40000000}, + {0x18, 0x411111f0}, + {0x19, 0x04a11030}, + {0x1a, 0x411111f0}, + {0x1b, 0x411111f0}, + {0x1d, 0x40f00001}, + {0x1e, 0x411111f0}, + {0x21, 0x04211020}), SND_HDA_PIN_QUIRK(0x10ec0283, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, {0x12, 0x90a60130}, {0x14, 0x90170110}, From 0279661b640317c31f288d66537d5805d4f18d05 Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Wed, 3 Sep 2014 11:31:11 +0800 Subject: [PATCH 093/251] ALSA: hda/realtek - move HP_GPIO_MIC1_LED quirk for alc280 Cc: David Henningsson Signed-off-by: Hui Wang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index c36144ba6c40..81e29171a787 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4845,20 +4845,12 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x22b7, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x22bf, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x22cf, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x22da, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), - SND_PCI_QUIRK(0x103c, 0x22db, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x22dc, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x22fb, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x8004, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), /* ALC290 */ SND_PCI_QUIRK(0x103c, 0x221b, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), - SND_PCI_QUIRK(0x103c, 0x221c, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), - SND_PCI_QUIRK(0x103c, 0x221d, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), - SND_PCI_QUIRK(0x103c, 0x2220, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x2221, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), - SND_PCI_QUIRK(0x103c, 0x2222, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), - SND_PCI_QUIRK(0x103c, 0x2223, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), - SND_PCI_QUIRK(0x103c, 0x2224, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x2225, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x2246, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x2247, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), @@ -5106,6 +5098,19 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { {0x1d, 0x40700001}, {0x1e, 0x411111f0}, {0x21, 0x02211040}), + SND_HDA_PIN_QUIRK(0x10ec0280, 0x103c, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED, + {0x12, 0x90a60140}, + {0x13, 0x40000000}, + {0x14, 0x90170110}, + {0x15, 0x0421101f}, + {0x16, 0x411111f0}, + {0x17, 0x411111f0}, + {0x18, 0x02811030}, + {0x19, 0x411111f0}, + {0x1a, 0x04a1103f}, + {0x1b, 0x02011020}, + {0x1d, 0x40700001}, + {0x1e, 0x411111f0}), SND_HDA_PIN_QUIRK(0x10ec0282, 0x103c, "HP 15 Touchsmart", ALC269_FIXUP_HP_MUTE_LED_MIC1, {0x12, 0x99a30130}, {0x14, 0x90170110}, From fea185e28e7c9f37a298f4184580f310e4eefd7b Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Wed, 3 Sep 2014 10:23:04 +0200 Subject: [PATCH 094/251] ALSA: hda - Add common pin macros for ALC269 family This will be used in a later patch to make the pin quirk table shorter. Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 81e29171a787..c7d65f035e3a 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -5009,6 +5009,37 @@ static const struct hda_model_fixup alc269_fixup_models[] = { {} }; +#define ALC255_STANDARD_PINS \ + {0x18, 0x411111f0}, \ + {0x19, 0x411111f0}, \ + {0x1a, 0x411111f0}, \ + {0x1b, 0x411111f0}, \ + {0x1e, 0x411111f0} + +#define ALC282_STANDARD_PINS \ + {0x14, 0x90170110}, \ + {0x18, 0x411111f0}, \ + {0x1a, 0x411111f0}, \ + {0x1b, 0x411111f0}, \ + {0x1e, 0x411111f0} + +#define ALC290_STANDARD_PINS \ + {0x12, 0x99a30130}, \ + {0x13, 0x40000000}, \ + {0x16, 0x411111f0}, \ + {0x17, 0x411111f0}, \ + {0x19, 0x411111f0}, \ + {0x1b, 0x411111f0}, \ + {0x1e, 0x411111f0} + +#define ALC292_STANDARD_PINS \ + {0x14, 0x90170110}, \ + {0x15, 0x0221401f}, \ + {0x1a, 0x411111f0}, \ + {0x1b, 0x411111f0}, \ + {0x1d, 0x40700001}, \ + {0x1e, 0x411111f0} + static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL2_MIC_NO_PRESENCE, {0x12, 0x40300000}, From aec856d0a8308cb34360c88a73b517c3a1fce170 Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Wed, 3 Sep 2014 10:23:05 +0200 Subject: [PATCH 095/251] ALSA: hda - Make the ALC269 pin quirk table shorter ...by factoring out common parts to the just added pin macros. Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 211 +++++++--------------------------- 1 file changed, 40 insertions(+), 171 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index c7d65f035e3a..cbc4d25e4538 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -5042,37 +5042,25 @@ static const struct hda_model_fixup alc269_fixup_models[] = { static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL2_MIC_NO_PRESENCE, + ALC255_STANDARD_PINS, {0x12, 0x40300000}, {0x14, 0x90170110}, {0x17, 0x411111f0}, - {0x18, 0x411111f0}, - {0x19, 0x411111f0}, - {0x1a, 0x411111f0}, - {0x1b, 0x02a11030}, {0x1d, 0x40538029}, - {0x1e, 0x411111f0}, {0x21, 0x02211020}), SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, + ALC255_STANDARD_PINS, {0x12, 0x90a60140}, {0x14, 0x90170110}, {0x17, 0x40000000}, - {0x18, 0x411111f0}, - {0x19, 0x411111f0}, - {0x1a, 0x411111f0}, - {0x1b, 0x411111f0}, {0x1d, 0x40700001}, - {0x1e, 0x411111f0}, {0x21, 0x02211020}), SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, + ALC255_STANDARD_PINS, {0x12, 0x90a60160}, {0x14, 0x90170120}, {0x17, 0x40000000}, - {0x18, 0x411111f0}, - {0x19, 0x411111f0}, - {0x1a, 0x411111f0}, - {0x1b, 0x411111f0}, {0x1d, 0x40700001}, - {0x1e, 0x411111f0}, {0x21, 0x02211030}), SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, {0x12, 0x90a60160}, @@ -5086,48 +5074,32 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { {0x1e, 0x411111f0}, {0x21, 0x0321102f}), SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, + ALC255_STANDARD_PINS, {0x12, 0x90a60160}, {0x14, 0x90170130}, {0x17, 0x40000000}, - {0x18, 0x411111f0}, - {0x19, 0x411111f0}, - {0x1a, 0x411111f0}, - {0x1b, 0x411111f0}, {0x1d, 0x40700001}, - {0x1e, 0x411111f0}, {0x21, 0x02211040}), SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, + ALC255_STANDARD_PINS, {0x12, 0x90a60160}, {0x14, 0x90170140}, {0x17, 0x40000000}, - {0x18, 0x411111f0}, - {0x19, 0x411111f0}, - {0x1a, 0x411111f0}, - {0x1b, 0x411111f0}, {0x1d, 0x40700001}, - {0x1e, 0x411111f0}, {0x21, 0x02211050}), SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, + ALC255_STANDARD_PINS, {0x12, 0x90a60170}, {0x14, 0x90170120}, {0x17, 0x40000000}, - {0x18, 0x411111f0}, - {0x19, 0x411111f0}, - {0x1a, 0x411111f0}, - {0x1b, 0x411111f0}, {0x1d, 0x40700001}, - {0x1e, 0x411111f0}, {0x21, 0x02211030}), SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, + ALC255_STANDARD_PINS, {0x12, 0x90a60170}, {0x14, 0x90170130}, {0x17, 0x40000000}, - {0x18, 0x411111f0}, - {0x19, 0x411111f0}, - {0x1a, 0x411111f0}, - {0x1b, 0x411111f0}, {0x1d, 0x40700001}, - {0x1e, 0x411111f0}, {0x21, 0x02211040}), SND_HDA_PIN_QUIRK(0x10ec0280, 0x103c, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED, {0x12, 0x90a60140}, @@ -5143,92 +5115,60 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { {0x1d, 0x40700001}, {0x1e, 0x411111f0}), SND_HDA_PIN_QUIRK(0x10ec0282, 0x103c, "HP 15 Touchsmart", ALC269_FIXUP_HP_MUTE_LED_MIC1, + ALC282_STANDARD_PINS, {0x12, 0x99a30130}, - {0x14, 0x90170110}, {0x17, 0x40000000}, - {0x18, 0x411111f0}, {0x19, 0x03a11020}, - {0x1a, 0x411111f0}, - {0x1b, 0x411111f0}, {0x1d, 0x40f41905}, - {0x1e, 0x411111f0}, {0x21, 0x0321101f}), SND_HDA_PIN_QUIRK(0x10ec0282, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1, + ALC282_STANDARD_PINS, {0x12, 0x99a30130}, - {0x14, 0x90170110}, {0x17, 0x40020008}, - {0x18, 0x411111f0}, {0x19, 0x03a11020}, - {0x1a, 0x411111f0}, - {0x1b, 0x411111f0}, {0x1d, 0x40e00001}, - {0x1e, 0x411111f0}, {0x21, 0x03211040}), SND_HDA_PIN_QUIRK(0x10ec0282, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1, + ALC282_STANDARD_PINS, {0x12, 0x99a30130}, - {0x14, 0x90170110}, {0x17, 0x40000000}, - {0x18, 0x411111f0}, {0x19, 0x03a11030}, - {0x1a, 0x411111f0}, - {0x1b, 0x411111f0}, {0x1d, 0x40e00001}, - {0x1e, 0x411111f0}, {0x21, 0x03211020}), SND_HDA_PIN_QUIRK(0x10ec0282, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1, + ALC282_STANDARD_PINS, {0x12, 0x99a30130}, - {0x14, 0x90170110}, {0x17, 0x40000000}, - {0x18, 0x411111f0}, {0x19, 0x03a11030}, - {0x1a, 0x411111f0}, - {0x1b, 0x411111f0}, {0x1d, 0x40f00001}, - {0x1e, 0x411111f0}, {0x21, 0x03211020}), SND_HDA_PIN_QUIRK(0x10ec0282, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1, + ALC282_STANDARD_PINS, {0x12, 0x99a30130}, - {0x14, 0x90170110}, {0x17, 0x40000000}, - {0x18, 0x411111f0}, {0x19, 0x04a11020}, - {0x1a, 0x411111f0}, - {0x1b, 0x411111f0}, {0x1d, 0x40f00001}, - {0x1e, 0x411111f0}, {0x21, 0x0421101f}), SND_HDA_PIN_QUIRK(0x10ec0282, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1, + ALC282_STANDARD_PINS, {0x12, 0x99a30130}, - {0x14, 0x90170110}, {0x17, 0x40000000}, - {0x18, 0x411111f0}, {0x19, 0x03a11030}, - {0x1a, 0x411111f0}, - {0x1b, 0x411111f0}, {0x1d, 0x40f00001}, - {0x1e, 0x411111f0}, {0x21, 0x04211020}), SND_HDA_PIN_QUIRK(0x10ec0282, 0x103c, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED, + ALC282_STANDARD_PINS, {0x12, 0x90a60140}, - {0x14, 0x90170110}, {0x17, 0x40000000}, - {0x18, 0x411111f0}, {0x19, 0x04a11030}, - {0x1a, 0x411111f0}, - {0x1b, 0x411111f0}, {0x1d, 0x40f00001}, - {0x1e, 0x411111f0}, {0x21, 0x04211020}), SND_HDA_PIN_QUIRK(0x10ec0283, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, + ALC282_STANDARD_PINS, {0x12, 0x90a60130}, - {0x14, 0x90170110}, {0x17, 0x40020008}, - {0x18, 0x411111f0}, {0x19, 0x411111f0}, - {0x1a, 0x411111f0}, - {0x1b, 0x411111f0}, {0x1d, 0x40e00001}, - {0x1e, 0x411111f0}, {0x21, 0x0321101f}), SND_HDA_PIN_QUIRK(0x10ec0283, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, {0x12, 0x90a60160}, @@ -5242,167 +5182,96 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { {0x1e, 0x411111f0}, {0x21, 0x02211030}), SND_HDA_PIN_QUIRK(0x10ec0283, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, + ALC282_STANDARD_PINS, {0x12, 0x90a60130}, - {0x14, 0x90170110}, {0x17, 0x40020008}, - {0x18, 0x411111f0}, {0x19, 0x03a11020}, - {0x1a, 0x411111f0}, - {0x1b, 0x411111f0}, {0x1d, 0x40e00001}, - {0x1e, 0x411111f0}, {0x21, 0x0321101f}), SND_HDA_PIN_QUIRK(0x10ec0290, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1, - {0x12, 0x99a30130}, - {0x13, 0x40000000}, + ALC290_STANDARD_PINS, {0x14, 0x411111f0}, {0x15, 0x04211040}, - {0x16, 0x411111f0}, - {0x17, 0x411111f0}, {0x18, 0x90170112}, - {0x19, 0x411111f0}, {0x1a, 0x04a11020}, - {0x1b, 0x411111f0}, - {0x1d, 0x4075812d}, - {0x1e, 0x411111f0}), + {0x1d, 0x4075812d}), SND_HDA_PIN_QUIRK(0x10ec0290, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1, - {0x12, 0x99a30130}, - {0x13, 0x40000000}, + ALC290_STANDARD_PINS, {0x14, 0x411111f0}, {0x15, 0x04211040}, - {0x16, 0x411111f0}, - {0x17, 0x411111f0}, {0x18, 0x90170110}, - {0x19, 0x411111f0}, {0x1a, 0x04a11020}, - {0x1b, 0x411111f0}, - {0x1d, 0x4075812d}, - {0x1e, 0x411111f0}), + {0x1d, 0x4075812d}), SND_HDA_PIN_QUIRK(0x10ec0290, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1, - {0x12, 0x99a30130}, - {0x13, 0x40000000}, + ALC290_STANDARD_PINS, {0x14, 0x411111f0}, {0x15, 0x0421101f}, - {0x16, 0x411111f0}, - {0x17, 0x411111f0}, {0x18, 0x411111f0}, - {0x19, 0x411111f0}, {0x1a, 0x04a11020}, - {0x1b, 0x411111f0}, - {0x1d, 0x4075812d}, - {0x1e, 0x411111f0}), + {0x1d, 0x4075812d}), SND_HDA_PIN_QUIRK(0x10ec0290, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1, - {0x12, 0x99a30130}, - {0x13, 0x40000000}, + ALC290_STANDARD_PINS, {0x14, 0x411111f0}, {0x15, 0x04211020}, - {0x16, 0x411111f0}, - {0x17, 0x411111f0}, {0x18, 0x411111f0}, - {0x19, 0x411111f0}, {0x1a, 0x04a11040}, - {0x1b, 0x411111f0}, - {0x1d, 0x4076a12d}, - {0x1e, 0x411111f0}), + {0x1d, 0x4076a12d}), SND_HDA_PIN_QUIRK(0x10ec0290, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1, - {0x12, 0x99a30130}, - {0x13, 0x40000000}, + ALC290_STANDARD_PINS, {0x14, 0x90170110}, {0x15, 0x04211020}, - {0x16, 0x411111f0}, - {0x17, 0x411111f0}, {0x18, 0x411111f0}, - {0x19, 0x411111f0}, {0x1a, 0x04a11040}, - {0x1b, 0x411111f0}, - {0x1d, 0x4076a12d}, - {0x1e, 0x411111f0}), + {0x1d, 0x4076a12d}), SND_HDA_PIN_QUIRK(0x10ec0290, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1, - {0x12, 0x99a30130}, - {0x13, 0x40000000}, + ALC290_STANDARD_PINS, {0x14, 0x90170110}, {0x15, 0x04211020}, - {0x16, 0x411111f0}, - {0x17, 0x411111f0}, {0x18, 0x411111f0}, - {0x19, 0x411111f0}, {0x1a, 0x04a11020}, - {0x1b, 0x411111f0}, - {0x1d, 0x4076a12d}, - {0x1e, 0x411111f0}), + {0x1d, 0x4076a12d}), SND_HDA_PIN_QUIRK(0x10ec0290, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1, - {0x12, 0x99a30130}, - {0x13, 0x40000000}, + ALC290_STANDARD_PINS, {0x14, 0x90170110}, {0x15, 0x0421101f}, - {0x16, 0x411111f0}, - {0x17, 0x411111f0}, {0x18, 0x411111f0}, - {0x19, 0x411111f0}, {0x1a, 0x04a11020}, - {0x1b, 0x411111f0}, - {0x1d, 0x4075812d}, - {0x1e, 0x411111f0}), + {0x1d, 0x4075812d}), SND_HDA_PIN_QUIRK(0x10ec0292, 0x1028, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE, + ALC292_STANDARD_PINS, {0x12, 0x90a60140}, {0x13, 0x411111f0}, - {0x14, 0x90170110}, - {0x15, 0x0221401f}, {0x16, 0x01014020}, {0x18, 0x411111f0}, - {0x19, 0x01a19030}, - {0x1a, 0x411111f0}, - {0x1b, 0x411111f0}, - {0x1d, 0x40700001}, - {0x1e, 0x411111f0}), + {0x19, 0x01a19030}), SND_HDA_PIN_QUIRK(0x10ec0292, 0x1028, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE, + ALC292_STANDARD_PINS, {0x12, 0x90a60140}, {0x13, 0x411111f0}, - {0x14, 0x90170110}, - {0x15, 0x0221401f}, {0x16, 0x01014020}, {0x18, 0x02a19031}, - {0x19, 0x01a1903e}, - {0x1a, 0x411111f0}, - {0x1b, 0x411111f0}, - {0x1d, 0x40700001}, - {0x1e, 0x411111f0}), + {0x19, 0x01a1903e}), SND_HDA_PIN_QUIRK(0x10ec0292, 0x1028, "Dell", ALC269_FIXUP_DELL3_MIC_NO_PRESENCE, + ALC292_STANDARD_PINS, {0x12, 0x90a60140}, {0x13, 0x411111f0}, - {0x14, 0x90170110}, - {0x15, 0x0221401f}, {0x16, 0x411111f0}, {0x18, 0x411111f0}, - {0x19, 0x411111f0}, - {0x1a, 0x411111f0}, - {0x1b, 0x411111f0}, - {0x1d, 0x40700001}, - {0x1e, 0x411111f0}), + {0x19, 0x411111f0}), SND_HDA_PIN_QUIRK(0x10ec0293, 0x1028, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE, + ALC292_STANDARD_PINS, {0x12, 0x40000000}, {0x13, 0x90a60140}, - {0x14, 0x90170110}, - {0x15, 0x0221401f}, {0x16, 0x21014020}, {0x18, 0x411111f0}, - {0x19, 0x21a19030}, - {0x1a, 0x411111f0}, - {0x1b, 0x411111f0}, - {0x1d, 0x40700001}, - {0x1e, 0x411111f0}), + {0x19, 0x21a19030}), SND_HDA_PIN_QUIRK(0x10ec0293, 0x1028, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE, + ALC292_STANDARD_PINS, {0x12, 0x40000000}, {0x13, 0x90a60140}, - {0x14, 0x90170110}, - {0x15, 0x0221401f}, {0x16, 0x411111f0}, {0x18, 0x411111f0}, - {0x19, 0x411111f0}, - {0x1a, 0x411111f0}, - {0x1b, 0x411111f0}, - {0x1d, 0x40700001}, - {0x1e, 0x411111f0}), + {0x19, 0x411111f0}), {} }; From 257f8cce5d40b811d229ed71602882baa0012808 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2014 15:32:29 +0200 Subject: [PATCH 096/251] ALSA: pcm: Allow nonatomic trigger operations Currently, many PCM operations are performed in a critical section protected by spinlock, typically the trigger and pointer callbacks are assumed to be atomic. This is basically because some trigger action (e.g. PCM stop after drain or xrun) is done in the interrupt handler. If a driver runs in a threaded irq, however, this doesn't have to be atomic. And many devices want to handle trigger in a non-atomic context due to lengthy communications. This patch tries all PCM calls operational in non-atomic context. What it does is very simple: replaces the substream spinlock with the corresponding substream mutex when pcm->nonatomic flag is set. The driver that wants to use the non-atomic PCM ops just needs to set the flag and keep the rest as is. (Of course, it must not handle any PCM ops in irq context.) Note that the code doesn't check whether it's atomic-safe or not, but trust in 100% that the driver sets pcm->nonatomic correctly. One possible problem is the case where linked PCM substreams have inconsistent nonatomic states. For avoiding this, snd_pcm_link() returns an error if one tries to link an inconsistent PCM substream. Signed-off-by: Takashi Iwai --- include/sound/pcm.h | 58 ++++++++++++++++++++++++------- sound/core/pcm.c | 1 + sound/core/pcm_native.c | 76 +++++++++++++++++++++++++++++++++++++---- 3 files changed, 116 insertions(+), 19 deletions(-) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 6f3e10ca0e32..bc79962f4aa6 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -365,6 +365,7 @@ struct snd_pcm_runtime { struct snd_pcm_group { /* keep linked substreams */ spinlock_t lock; + struct mutex mutex; struct list_head substreams; int count; }; @@ -460,6 +461,7 @@ struct snd_pcm { void (*private_free) (struct snd_pcm *pcm); struct device *dev; /* actual hw device this belongs to */ bool internal; /* pcm is for internal use only */ + bool nonatomic; /* whole PCM operations are in non-atomic context */ #if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE) struct snd_pcm_oss oss; #endif @@ -493,6 +495,7 @@ int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree); */ extern rwlock_t snd_pcm_link_rwlock; +extern struct rw_semaphore snd_pcm_link_rwsem; int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info); int snd_pcm_info_user(struct snd_pcm_substream *substream, @@ -539,38 +542,69 @@ static inline int snd_pcm_stream_linked(struct snd_pcm_substream *substream) static inline void snd_pcm_stream_lock(struct snd_pcm_substream *substream) { - read_lock(&snd_pcm_link_rwlock); - spin_lock(&substream->self_group.lock); + if (substream->pcm->nonatomic) { + down_read(&snd_pcm_link_rwsem); + mutex_lock(&substream->self_group.mutex); + } else { + read_lock(&snd_pcm_link_rwlock); + spin_lock(&substream->self_group.lock); + } } static inline void snd_pcm_stream_unlock(struct snd_pcm_substream *substream) { - spin_unlock(&substream->self_group.lock); - read_unlock(&snd_pcm_link_rwlock); + if (substream->pcm->nonatomic) { + mutex_unlock(&substream->self_group.mutex); + up_read(&snd_pcm_link_rwsem); + } else { + spin_unlock(&substream->self_group.lock); + read_unlock(&snd_pcm_link_rwlock); + } } static inline void snd_pcm_stream_lock_irq(struct snd_pcm_substream *substream) { - read_lock_irq(&snd_pcm_link_rwlock); - spin_lock(&substream->self_group.lock); + if (substream->pcm->nonatomic) { + down_read(&snd_pcm_link_rwsem); + mutex_lock(&substream->self_group.mutex); + } else { + read_lock_irq(&snd_pcm_link_rwlock); + spin_lock(&substream->self_group.lock); + } } static inline void snd_pcm_stream_unlock_irq(struct snd_pcm_substream *substream) { - spin_unlock(&substream->self_group.lock); - read_unlock_irq(&snd_pcm_link_rwlock); + if (substream->pcm->nonatomic) { + mutex_unlock(&substream->self_group.mutex); + up_read(&snd_pcm_link_rwsem); + } else { + spin_unlock(&substream->self_group.lock); + read_unlock_irq(&snd_pcm_link_rwlock); + } } #define snd_pcm_stream_lock_irqsave(substream, flags) \ do { \ - read_lock_irqsave(&snd_pcm_link_rwlock, (flags)); \ - spin_lock(&substream->self_group.lock); \ + if ((substream)->pcm->nonatomic) { \ + (flags) = 0; /* XXX for avoid warning */ \ + down_read(&snd_pcm_link_rwsem); \ + mutex_lock(&(substream)->self_group.mutex); \ + } else { \ + read_lock_irqsave(&snd_pcm_link_rwlock, (flags)); \ + spin_lock(&(substream)->self_group.lock); \ + } \ } while (0) #define snd_pcm_stream_unlock_irqrestore(substream, flags) \ do { \ - spin_unlock(&substream->self_group.lock); \ - read_unlock_irqrestore(&snd_pcm_link_rwlock, (flags)); \ + if ((substream)->pcm->nonatomic) { \ + mutex_unlock(&(substream)->self_group.mutex); \ + up_read(&snd_pcm_link_rwsem); \ + } else { \ + spin_unlock(&(substream)->self_group.lock); \ + read_unlock_irqrestore(&snd_pcm_link_rwlock, (flags)); \ + } \ } while (0) #define snd_pcm_group_for_each_entry(s, substream) \ diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 43932e8dce66..afccdc553ef9 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -698,6 +698,7 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count) } substream->group = &substream->self_group; spin_lock_init(&substream->self_group.lock); + mutex_init(&substream->self_group.mutex); INIT_LIST_HEAD(&substream->self_group.substreams); list_add_tail(&substream->link_list, &substream->self_group.substreams); atomic_set(&substream->mmap_count, 0); diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 8cd2f930ad0b..16d9b7e15f8b 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -77,7 +77,8 @@ static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream); DEFINE_RWLOCK(snd_pcm_link_rwlock); EXPORT_SYMBOL(snd_pcm_link_rwlock); -static DECLARE_RWSEM(snd_pcm_link_rwsem); +DECLARE_RWSEM(snd_pcm_link_rwsem); +EXPORT_SYMBOL(snd_pcm_link_rwsem); static inline mm_segment_t snd_enter_user(void) { @@ -727,9 +728,14 @@ static int snd_pcm_action_group(struct action_ops *ops, int res = 0; snd_pcm_group_for_each_entry(s, substream) { - if (do_lock && s != substream) - spin_lock_nested(&s->self_group.lock, - SINGLE_DEPTH_NESTING); + if (do_lock && s != substream) { + if (s->pcm->nonatomic) + mutex_lock_nested(&s->self_group.mutex, + SINGLE_DEPTH_NESTING); + else + spin_lock_nested(&s->self_group.lock, + SINGLE_DEPTH_NESTING); + } res = ops->pre_action(s, state); if (res < 0) goto _unlock; @@ -755,8 +761,12 @@ static int snd_pcm_action_group(struct action_ops *ops, if (do_lock) { /* unlock streams */ snd_pcm_group_for_each_entry(s1, substream) { - if (s1 != substream) - spin_unlock(&s1->self_group.lock); + if (s1 != substream) { + if (s->pcm->nonatomic) + mutex_unlock(&s1->self_group.mutex); + else + spin_unlock(&s1->self_group.lock); + } if (s1 == s) /* end */ break; } @@ -784,6 +794,27 @@ static int snd_pcm_action_single(struct action_ops *ops, return res; } +/* call in mutex-protected context */ +static int snd_pcm_action_mutex(struct action_ops *ops, + struct snd_pcm_substream *substream, + int state) +{ + int res; + + if (snd_pcm_stream_linked(substream)) { + if (!mutex_trylock(&substream->group->mutex)) { + mutex_unlock(&substream->self_group.mutex); + mutex_lock(&substream->group->mutex); + mutex_lock(&substream->self_group.mutex); + } + res = snd_pcm_action_group(ops, substream, state, 1); + mutex_unlock(&substream->group->mutex); + } else { + res = snd_pcm_action_single(ops, substream, state); + } + return res; +} + /* * Note: call with stream lock */ @@ -793,6 +824,9 @@ static int snd_pcm_action(struct action_ops *ops, { int res; + if (substream->pcm->nonatomic) + return snd_pcm_action_mutex(ops, substream, state); + if (snd_pcm_stream_linked(substream)) { if (!spin_trylock(&substream->group->lock)) { spin_unlock(&substream->self_group.lock); @@ -807,6 +841,29 @@ static int snd_pcm_action(struct action_ops *ops, return res; } +static int snd_pcm_action_lock_mutex(struct action_ops *ops, + struct snd_pcm_substream *substream, + int state) +{ + int res; + + down_read(&snd_pcm_link_rwsem); + if (snd_pcm_stream_linked(substream)) { + mutex_lock(&substream->group->mutex); + mutex_lock_nested(&substream->self_group.mutex, + SINGLE_DEPTH_NESTING); + res = snd_pcm_action_group(ops, substream, state, 1); + mutex_unlock(&substream->self_group.mutex); + mutex_unlock(&substream->group->mutex); + } else { + mutex_lock(&substream->self_group.mutex); + res = snd_pcm_action_single(ops, substream, state); + mutex_unlock(&substream->self_group.mutex); + } + up_read(&snd_pcm_link_rwsem); + return res; +} + /* * Note: don't use any locks before */ @@ -816,6 +873,9 @@ static int snd_pcm_action_lock_irq(struct action_ops *ops, { int res; + if (substream->pcm->nonatomic) + return snd_pcm_action_lock_mutex(ops, substream, state); + read_lock_irq(&snd_pcm_link_rwlock); if (snd_pcm_stream_linked(substream)) { spin_lock(&substream->group->lock); @@ -1634,7 +1694,8 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) down_write(&snd_pcm_link_rwsem); write_lock_irq(&snd_pcm_link_rwlock); if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN || - substream->runtime->status->state != substream1->runtime->status->state) { + substream->runtime->status->state != substream1->runtime->status->state || + substream->pcm->nonatomic != substream1->pcm->nonatomic) { res = -EBADFD; goto _end; } @@ -1646,6 +1707,7 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) substream->group = group; group = NULL; spin_lock_init(&substream->group->lock); + mutex_init(&substream->group->mutex); INIT_LIST_HEAD(&substream->group->substreams); list_add_tail(&substream->link_list, &substream->group->substreams); substream->group->count = 1; From 7af142f752116e86adbe2073f2922d8265a77709 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 1 Sep 2014 11:19:37 +0200 Subject: [PATCH 097/251] ALSA: pcm: Uninline snd_pcm_stream_lock() and _unlock() The previous commit for the non-atomic PCM ops added more codes to snd_pcm_stream_lock() and its variants. Since they are inlined functions, it resulted in a significant code size bloat. For reducing the size bloat, this patch changes the inline functions to the normal function calls. The export of rwlock and rwsem are removed as well, since they are referred only in pcm_native.c now. Signed-off-by: Takashi Iwai --- include/sound/pcm.h | 81 ++++++----------------------------------- sound/core/pcm_native.c | 64 ++++++++++++++++++++++++++++++-- 2 files changed, 72 insertions(+), 73 deletions(-) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index bc79962f4aa6..67e0bdb9f0fa 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -494,9 +494,6 @@ int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree); * Native I/O */ -extern rwlock_t snd_pcm_link_rwlock; -extern struct rw_semaphore snd_pcm_link_rwsem; - int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info); int snd_pcm_info_user(struct snd_pcm_substream *substream, struct snd_pcm_info __user *info); @@ -540,72 +537,18 @@ static inline int snd_pcm_stream_linked(struct snd_pcm_substream *substream) return substream->group != &substream->self_group; } -static inline void snd_pcm_stream_lock(struct snd_pcm_substream *substream) -{ - if (substream->pcm->nonatomic) { - down_read(&snd_pcm_link_rwsem); - mutex_lock(&substream->self_group.mutex); - } else { - read_lock(&snd_pcm_link_rwlock); - spin_lock(&substream->self_group.lock); - } -} - -static inline void snd_pcm_stream_unlock(struct snd_pcm_substream *substream) -{ - if (substream->pcm->nonatomic) { - mutex_unlock(&substream->self_group.mutex); - up_read(&snd_pcm_link_rwsem); - } else { - spin_unlock(&substream->self_group.lock); - read_unlock(&snd_pcm_link_rwlock); - } -} - -static inline void snd_pcm_stream_lock_irq(struct snd_pcm_substream *substream) -{ - if (substream->pcm->nonatomic) { - down_read(&snd_pcm_link_rwsem); - mutex_lock(&substream->self_group.mutex); - } else { - read_lock_irq(&snd_pcm_link_rwlock); - spin_lock(&substream->self_group.lock); - } -} - -static inline void snd_pcm_stream_unlock_irq(struct snd_pcm_substream *substream) -{ - if (substream->pcm->nonatomic) { - mutex_unlock(&substream->self_group.mutex); - up_read(&snd_pcm_link_rwsem); - } else { - spin_unlock(&substream->self_group.lock); - read_unlock_irq(&snd_pcm_link_rwlock); - } -} - -#define snd_pcm_stream_lock_irqsave(substream, flags) \ -do { \ - if ((substream)->pcm->nonatomic) { \ - (flags) = 0; /* XXX for avoid warning */ \ - down_read(&snd_pcm_link_rwsem); \ - mutex_lock(&(substream)->self_group.mutex); \ - } else { \ - read_lock_irqsave(&snd_pcm_link_rwlock, (flags)); \ - spin_lock(&(substream)->self_group.lock); \ - } \ -} while (0) - -#define snd_pcm_stream_unlock_irqrestore(substream, flags) \ -do { \ - if ((substream)->pcm->nonatomic) { \ - mutex_unlock(&(substream)->self_group.mutex); \ - up_read(&snd_pcm_link_rwsem); \ - } else { \ - spin_unlock(&(substream)->self_group.lock); \ - read_unlock_irqrestore(&snd_pcm_link_rwlock, (flags)); \ - } \ -} while (0) +void snd_pcm_stream_lock(struct snd_pcm_substream *substream); +void snd_pcm_stream_unlock(struct snd_pcm_substream *substream); +void snd_pcm_stream_lock_irq(struct snd_pcm_substream *substream); +void snd_pcm_stream_unlock_irq(struct snd_pcm_substream *substream); +unsigned long _snd_pcm_stream_lock_irqsave(struct snd_pcm_substream *substream); +#define snd_pcm_stream_lock_irqsave(substream, flags) \ + do { \ + typecheck(unsigned long, flags); \ + flags = _snd_pcm_stream_lock_irqsave(substream); \ + } while (0) +void snd_pcm_stream_unlock_irqrestore(struct snd_pcm_substream *substream, + unsigned long flags); #define snd_pcm_group_for_each_entry(s, substream) \ list_for_each_entry(s, &substream->group->substreams, link_list) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 16d9b7e15f8b..85fe1a216225 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -74,11 +74,67 @@ static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream); * */ -DEFINE_RWLOCK(snd_pcm_link_rwlock); -EXPORT_SYMBOL(snd_pcm_link_rwlock); +static DEFINE_RWLOCK(snd_pcm_link_rwlock); +static DECLARE_RWSEM(snd_pcm_link_rwsem); -DECLARE_RWSEM(snd_pcm_link_rwsem); -EXPORT_SYMBOL(snd_pcm_link_rwsem); +void snd_pcm_stream_lock(struct snd_pcm_substream *substream) +{ + if (substream->pcm->nonatomic) { + down_read(&snd_pcm_link_rwsem); + mutex_lock(&substream->self_group.mutex); + } else { + read_lock(&snd_pcm_link_rwlock); + spin_lock(&substream->self_group.lock); + } +} +EXPORT_SYMBOL_GPL(snd_pcm_stream_lock); + +void snd_pcm_stream_unlock(struct snd_pcm_substream *substream) +{ + if (substream->pcm->nonatomic) { + mutex_unlock(&substream->self_group.mutex); + up_read(&snd_pcm_link_rwsem); + } else { + spin_unlock(&substream->self_group.lock); + read_unlock(&snd_pcm_link_rwlock); + } +} +EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock); + +void snd_pcm_stream_lock_irq(struct snd_pcm_substream *substream) +{ + if (!substream->pcm->nonatomic) + local_irq_disable(); + snd_pcm_stream_lock(substream); +} +EXPORT_SYMBOL_GPL(snd_pcm_stream_lock_irq); + +void snd_pcm_stream_unlock_irq(struct snd_pcm_substream *substream) +{ + snd_pcm_stream_unlock(substream); + if (!substream->pcm->nonatomic) + local_irq_enable(); +} +EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock_irq); + +unsigned long _snd_pcm_stream_lock_irqsave(struct snd_pcm_substream *substream) +{ + unsigned long flags = 0; + if (!substream->pcm->nonatomic) + local_irq_save(flags); + snd_pcm_stream_lock(substream); + return flags; +} +EXPORT_SYMBOL_GPL(_snd_pcm_stream_lock_irqsave); + +void snd_pcm_stream_unlock_irqrestore(struct snd_pcm_substream *substream, + unsigned long flags) +{ + snd_pcm_stream_unlock(substream); + if (!substream->pcm->nonatomic) + local_irq_restore(flags); +} +EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock_irqrestore); static inline mm_segment_t snd_enter_user(void) { From 7c7b9cf53d284fe12eeab6e13d3098b18cff4692 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 2 Sep 2014 04:05:30 -0700 Subject: [PATCH 098/251] ASoC: simple-card: fixup cpu_dai_name clear case f687d900d30a61dda38db2a99239f5284a86a309 (ASoC: simple-card: cpu_dai_name creates confusion when DT case) cleared cpu_dai_name for caring fmt_single_name case, and 179949bc04c7157a4b2279f62a842638b61f78f9 (ASoC: simple-card: remove dai_link->cpu_dai_name when DT) cared multi dai-link case. but, cpu_dai_name matching is required when fmt_multiple_name was used Signed-off-by: Kuninori Morimoto Tested-by: Jean-Francois Moine Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index fd8b04588948..b63860ddb4fd 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -112,8 +112,10 @@ static int asoc_simple_card_sub_parse_of(struct device_node *np, struct asoc_simple_dai *dai, struct device_node **p_node, - const char **name) + const char **name, + int *args_count) { + struct of_phandle_args args; struct device_node *node; struct clk *clk; u32 val; @@ -123,10 +125,15 @@ asoc_simple_card_sub_parse_of(struct device_node *np, * get node via "sound-dai = <&phandle port>" * it will be used as xxx_of_node on soc_bind_dai_link() */ - node = of_parse_phandle(np, "sound-dai", 0); - if (!node) - return -ENODEV; - *p_node = node; + ret = of_parse_phandle_with_args(np, "sound-dai", + "#sound-dai-cells", 0, &args); + if (ret) + return ret; + + *p_node = args.np; + + if (args_count) + *args_count = args.args_count; /* get dai->name */ ret = snd_soc_of_get_dai_name(np, name); @@ -176,7 +183,7 @@ static int asoc_simple_card_dai_link_of(struct device_node *node, char *name; char prop[128]; char *prefix = ""; - int ret; + int ret, cpu_args; if (is_top_level_node) prefix = "simple-audio-card,"; @@ -195,7 +202,8 @@ static int asoc_simple_card_dai_link_of(struct device_node *node, ret = asoc_simple_card_sub_parse_of(np, &dai_props->cpu_dai, &dai_link->cpu_of_node, - &dai_link->cpu_dai_name); + &dai_link->cpu_dai_name, + &cpu_args); if (ret < 0) goto dai_link_of_err; @@ -226,7 +234,7 @@ static int asoc_simple_card_dai_link_of(struct device_node *node, ret = asoc_simple_card_sub_parse_of(np, &dai_props->codec_dai, &dai_link->codec_of_node, - &dai_link->codec_dai_name); + &dai_link->codec_dai_name, NULL); if (ret < 0) goto dai_link_of_err; @@ -290,12 +298,13 @@ static int asoc_simple_card_dai_link_of(struct device_node *node, * soc_bind_dai_link() will check cpu name * after of_node matching if dai_link has cpu_dai_name. * but, it will never match if name was created by fmt_single_name() - * remove cpu_dai_name to escape name matching. + * remove cpu_dai_name if cpu_args was 0. * see * fmt_single_name() * fmt_multiple_name() */ - dai_link->cpu_dai_name = NULL; + if (!cpu_args) + dai_link->cpu_dai_name = NULL; dai_link_of_err: if (np) From 7ed36e96fd05470e98e7daf648f9cf7f38609670 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Wed, 3 Sep 2014 15:52:34 +0300 Subject: [PATCH 099/251] ASoC: tlv320aic31xx: Choose PLL p divider automatically This simplifies aic31xx_divs table. There is no more need for p_val or separate lines for 12 and 24 MHz mclks. Signed-off-by: Jyri Sarha Tested-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic31xx.c | 101 +++++++++++++++---------------- 1 file changed, 50 insertions(+), 51 deletions(-) diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index 40a636f447f1..145fe5b253d4 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -167,13 +167,13 @@ struct aic31xx_priv { struct regulator_bulk_data supplies[AIC31XX_NUM_SUPPLIES]; struct aic31xx_disable_nb disable_nb[AIC31XX_NUM_SUPPLIES]; unsigned int sysclk; + u8 p_div; int rate_div_line; }; struct aic31xx_rate_divs { - u32 mclk; + u32 mclk_p; u32 rate; - u8 p_val; u8 pll_j; u16 pll_d; u16 dosr; @@ -186,62 +186,51 @@ struct aic31xx_rate_divs { /* ADC dividers can be disabled by cofiguring them to 0 */ static const struct aic31xx_rate_divs aic31xx_divs[] = { - /* mclk rate pll: p j d dosr ndac mdac aors nadc madc */ + /* mclk/p rate pll: j d dosr ndac mdac aors nadc madc */ /* 8k rate */ - {12000000, 8000, 1, 8, 1920, 128, 48, 2, 128, 48, 2}, - {12000000, 8000, 1, 8, 1920, 128, 32, 3, 128, 32, 3}, - {24000000, 8000, 2, 8, 1920, 128, 48, 2, 128, 48, 2}, - {25000000, 8000, 2, 7, 8643, 128, 48, 2, 128, 48, 2}, + {12000000, 8000, 8, 1920, 128, 48, 2, 128, 48, 2}, + {12000000, 8000, 8, 1920, 128, 32, 3, 128, 32, 3}, + {12500000, 8000, 7, 8643, 128, 48, 2, 128, 48, 2}, /* 11.025k rate */ - {12000000, 11025, 1, 7, 5264, 128, 32, 2, 128, 32, 2}, - {12000000, 11025, 1, 8, 4672, 128, 24, 3, 128, 24, 3}, - {24000000, 11025, 2, 7, 5264, 128, 32, 2, 128, 32, 2}, - {25000000, 11025, 2, 7, 2253, 128, 32, 2, 128, 32, 2}, + {12000000, 11025, 7, 5264, 128, 32, 2, 128, 32, 2}, + {12000000, 11025, 8, 4672, 128, 24, 3, 128, 24, 3}, + {12500000, 11025, 7, 2253, 128, 32, 2, 128, 32, 2}, /* 16k rate */ - {12000000, 16000, 1, 8, 1920, 128, 24, 2, 128, 24, 2}, - {12000000, 16000, 1, 8, 1920, 128, 16, 3, 128, 16, 3}, - {24000000, 16000, 2, 8, 1920, 128, 24, 2, 128, 24, 2}, - {25000000, 16000, 2, 7, 8643, 128, 24, 2, 128, 24, 2}, + {12000000, 16000, 8, 1920, 128, 24, 2, 128, 24, 2}, + {12000000, 16000, 8, 1920, 128, 16, 3, 128, 16, 3}, + {12500000, 16000, 7, 8643, 128, 24, 2, 128, 24, 2}, /* 22.05k rate */ - {12000000, 22050, 1, 7, 5264, 128, 16, 2, 128, 16, 2}, - {12000000, 22050, 1, 8, 4672, 128, 12, 3, 128, 12, 3}, - {24000000, 22050, 2, 7, 5264, 128, 16, 2, 128, 16, 2}, - {25000000, 22050, 2, 7, 2253, 128, 16, 2, 128, 16, 2}, + {12000000, 22050, 7, 5264, 128, 16, 2, 128, 16, 2}, + {12000000, 22050, 8, 4672, 128, 12, 3, 128, 12, 3}, + {12500000, 22050, 7, 2253, 128, 16, 2, 128, 16, 2}, /* 32k rate */ - {12000000, 32000, 1, 8, 1920, 128, 12, 2, 128, 12, 2}, - {12000000, 32000, 1, 8, 1920, 128, 8, 3, 128, 8, 3}, - {24000000, 32000, 2, 8, 1920, 128, 12, 2, 128, 12, 2}, - {25000000, 32000, 2, 7, 8643, 128, 12, 2, 128, 12, 2}, + {12000000, 32000, 8, 1920, 128, 12, 2, 128, 12, 2}, + {12000000, 32000, 8, 1920, 128, 8, 3, 128, 8, 3}, + {12500000, 32000, 7, 8643, 128, 12, 2, 128, 12, 2}, /* 44.1k rate */ - {12000000, 44100, 1, 7, 5264, 128, 8, 2, 128, 8, 2}, - {12000000, 44100, 1, 8, 4672, 128, 6, 3, 128, 6, 3}, - {24000000, 44100, 2, 7, 5264, 128, 8, 2, 128, 8, 2}, - {25000000, 44100, 2, 7, 2253, 128, 8, 2, 128, 8, 2}, + {12000000, 44100, 7, 5264, 128, 8, 2, 128, 8, 2}, + {12000000, 44100, 8, 4672, 128, 6, 3, 128, 6, 3}, + {12500000, 44100, 7, 2253, 128, 8, 2, 128, 8, 2}, /* 48k rate */ - {12000000, 48000, 1, 8, 1920, 128, 8, 2, 128, 8, 2}, - {12000000, 48000, 1, 7, 6800, 96, 5, 4, 96, 5, 4}, - {24000000, 48000, 2, 8, 1920, 128, 8, 2, 128, 8, 2}, - {25000000, 48000, 2, 7, 8643, 128, 8, 2, 128, 8, 2}, + {12000000, 48000, 8, 1920, 128, 8, 2, 128, 8, 2}, + {12000000, 48000, 7, 6800, 96, 5, 4, 96, 5, 4}, + {12500000, 48000, 7, 8643, 128, 8, 2, 128, 8, 2}, /* 88.2k rate */ - {12000000, 88200, 1, 7, 5264, 64, 8, 2, 64, 8, 2}, - {12000000, 88200, 1, 8, 4672, 64, 6, 3, 64, 6, 3}, - {24000000, 88200, 2, 7, 5264, 64, 8, 2, 64, 8, 2}, - {25000000, 88200, 2, 7, 2253, 64, 8, 2, 64, 8, 2}, + {12000000, 88200, 7, 5264, 64, 8, 2, 64, 8, 2}, + {12000000, 88200, 8, 4672, 64, 6, 3, 64, 6, 3}, + {12500000, 88200, 7, 2253, 64, 8, 2, 64, 8, 2}, /* 96k rate */ - {12000000, 96000, 1, 8, 1920, 64, 8, 2, 64, 8, 2}, - {12000000, 96000, 1, 7, 6800, 48, 5, 4, 48, 5, 4}, - {24000000, 96000, 2, 8, 1920, 64, 8, 2, 64, 8, 2}, - {25000000, 96000, 2, 7, 8643, 64, 8, 2, 64, 8, 2}, + {12000000, 96000, 8, 1920, 64, 8, 2, 64, 8, 2}, + {12000000, 96000, 7, 6800, 48, 5, 4, 48, 5, 4}, + {12500000, 96000, 7, 8643, 64, 8, 2, 64, 8, 2}, /* 176.4k rate */ - {12000000, 176400, 1, 7, 5264, 32, 8, 2, 32, 8, 2}, - {12000000, 176400, 1, 8, 4672, 32, 6, 3, 32, 6, 3}, - {24000000, 176400, 2, 7, 5264, 32, 8, 2, 32, 8, 2}, - {25000000, 176400, 2, 7, 2253, 32, 8, 2, 32, 8, 2}, + {12000000, 176400, 7, 5264, 32, 8, 2, 32, 8, 2}, + {12000000, 176400, 8, 4672, 32, 6, 3, 32, 6, 3}, + {12500000, 176400, 7, 2253, 32, 8, 2, 32, 8, 2}, /* 192k rate */ - {12000000, 192000, 1, 8, 1920, 32, 8, 2, 32, 8, 2}, - {12000000, 192000, 1, 7, 6800, 24, 5, 4, 24, 5, 4}, - {24000000, 192000, 2, 8, 1920, 32, 8, 2, 32, 8, 2}, - {25000000, 192000, 2, 7, 8643, 32, 8, 2, 32, 8, 2}, + {12000000, 192000, 8, 1920, 32, 8, 2, 32, 8, 2}, + {12000000, 192000, 7, 6800, 24, 5, 4, 24, 5, 4}, + {12500000, 192000, 7, 8643, 32, 8, 2, 32, 8, 2}, }; static const char * const ldac_in_text[] = { @@ -692,6 +681,7 @@ static int aic31xx_setup_pll(struct snd_soc_codec *codec, { struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec); int bclk_score = snd_soc_params_to_frame_size(params); + int mclk_p = aic31xx->sysclk / aic31xx->p_div; int bclk_n = 0; int match = -1; int i; @@ -704,7 +694,7 @@ static int aic31xx_setup_pll(struct snd_soc_codec *codec, for (i = 0; i < ARRAY_SIZE(aic31xx_divs); i++) { if (aic31xx_divs[i].rate == params_rate(params) && - aic31xx_divs[i].mclk == aic31xx->sysclk) { + aic31xx_divs[i].mclk_p == mclk_p) { int s = (aic31xx_divs[i].dosr * aic31xx_divs[i].mdac) % snd_soc_params_to_frame_size(params); int bn = (aic31xx_divs[i].dosr * aic31xx_divs[i].mdac) / @@ -738,7 +728,7 @@ static int aic31xx_setup_pll(struct snd_soc_codec *codec, /* PLL configuration */ snd_soc_update_bits(codec, AIC31XX_PLLPR, AIC31XX_PLL_MASK, - (aic31xx_divs[i].p_val << 4) | 0x01); + (aic31xx->p_div << 4) | 0x01); snd_soc_write(codec, AIC31XX_PLLJ, aic31xx_divs[i].pll_j); snd_soc_write(codec, AIC31XX_PLLDMSB, @@ -772,7 +762,7 @@ static int aic31xx_setup_pll(struct snd_soc_codec *codec, dev_dbg(codec->dev, "pll %d.%04d/%d dosr %d n %d m %d aosr %d n %d m %d bclk_n %d\n", aic31xx_divs[i].pll_j, aic31xx_divs[i].pll_d, - aic31xx_divs[i].p_val, aic31xx_divs[i].dosr, + aic31xx->p_div, aic31xx_divs[i].dosr, aic31xx_divs[i].ndac, aic31xx_divs[i].mdac, aic31xx_divs[i].aosr, aic31xx_divs[i].nadc, aic31xx_divs[i].madc, bclk_n); @@ -912,7 +902,16 @@ static int aic31xx_set_dai_sysclk(struct snd_soc_dai *codec_dai, dev_dbg(codec->dev, "## %s: clk_id = %d, freq = %d, dir = %d\n", __func__, clk_id, freq, dir); - for (i = 0; aic31xx_divs[i].mclk != freq; i++) { + for (i = 1; freq/i > 20000000 && i < 8; i++) + ; + if (freq/i > 20000000) { + dev_err(aic31xx->dev, "%s: Too high mclk frequency %u\n", + __func__, freq); + return -EINVAL; + } + aic31xx->p_div = i; + + for (i = 0; aic31xx_divs[i].mclk_p != freq/aic31xx->p_div; i++) { if (i == ARRAY_SIZE(aic31xx_divs)) { dev_err(aic31xx->dev, "%s: Unsupported frequency %d\n", __func__, freq); From b8a3ee820f7b0802c9b90a9f3426dbda54e93d09 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Wed, 3 Sep 2014 15:42:48 +0300 Subject: [PATCH 100/251] ASoC: max98090: Add recovery for PLL lock failure All MAX98090 input clocks MCLK, LRCLK and BCLK must be running and stable before powering on the codec in slave mode. Otherwise the PLL may not lock to LRCLK causing silence in playback and capture. How often that happens is somewhat hardware and clock configuration specific. Now if wanting to follow strictly this clocks must be active before powering the codec on requirement we should have a notification from DAI driver to codec driver when clocks are activated and take codec out of shutdown only after that. Plus take care of possible active bypass paths. However, when PLL unlock occurs, MAX98090 asserts the PLL Unlock Flag which can be configured as an IRQ source. This allows to workaround around the issue by toggling the codec power shortly in case of PLL lock failure. In order to prevent needlessly toggling codec power in case of short PLL unlocks at the beginning of stream this patch implements delayed activation for PLL unlock interrupt. Then workaround is run only when the PLL doesn't lock at all. Power toggling workaround for PLL unlock comes originally from Liam Girdwood and delayed activation from me. Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/codecs/max98090.c | 111 +++++++++++++++++++++++++++++++++++- sound/soc/codecs/max98090.h | 3 + 2 files changed, 112 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index 4a063fa88526..f1543653a699 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c @@ -1972,6 +1972,102 @@ static int max98090_dai_digital_mute(struct snd_soc_dai *codec_dai, int mute) return 0; } +static int max98090_dai_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + if (!max98090->master && dai->active == 1) + queue_delayed_work(system_power_efficient_wq, + &max98090->pll_det_enable_work, + msecs_to_jiffies(10)); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + if (!max98090->master && dai->active == 1) + schedule_work(&max98090->pll_det_disable_work); + break; + default: + break; + } + + return 0; +} + +static void max98090_pll_det_enable_work(struct work_struct *work) +{ + struct max98090_priv *max98090 = + container_of(work, struct max98090_priv, + pll_det_enable_work.work); + struct snd_soc_codec *codec = max98090->codec; + unsigned int status, mask; + + /* + * Clear status register in order to clear possibly already occurred + * PLL unlock. If PLL hasn't still locked, the status will be set + * again and PLL unlock interrupt will occur. + * Note this will clear all status bits + */ + regmap_read(max98090->regmap, M98090_REG_DEVICE_STATUS, &status); + + /* + * Queue jack work in case jack state has just changed but handler + * hasn't run yet + */ + regmap_read(max98090->regmap, M98090_REG_INTERRUPT_S, &mask); + status &= mask; + if (status & M98090_JDET_MASK) + queue_delayed_work(system_power_efficient_wq, + &max98090->jack_work, + msecs_to_jiffies(100)); + + /* Enable PLL unlock interrupt */ + snd_soc_update_bits(codec, M98090_REG_INTERRUPT_S, + M98090_IULK_MASK, + 1 << M98090_IULK_SHIFT); +} + +static void max98090_pll_det_disable_work(struct work_struct *work) +{ + struct max98090_priv *max98090 = + container_of(work, struct max98090_priv, pll_det_disable_work); + struct snd_soc_codec *codec = max98090->codec; + + cancel_delayed_work_sync(&max98090->pll_det_enable_work); + + /* Disable PLL unlock interrupt */ + snd_soc_update_bits(codec, M98090_REG_INTERRUPT_S, + M98090_IULK_MASK, 0); +} + +static void max98090_pll_work(struct work_struct *work) +{ + struct max98090_priv *max98090 = + container_of(work, struct max98090_priv, pll_work); + struct snd_soc_codec *codec = max98090->codec; + + if (!snd_soc_codec_is_active(codec)) + return; + + dev_info(codec->dev, "PLL unlocked\n"); + + /* Toggle shutdown OFF then ON */ + snd_soc_update_bits(codec, M98090_REG_DEVICE_SHUTDOWN, + M98090_SHDNN_MASK, 0); + msleep(10); + snd_soc_update_bits(codec, M98090_REG_DEVICE_SHUTDOWN, + M98090_SHDNN_MASK, M98090_SHDNN_MASK); + + /* Give PLL time to lock */ + msleep(10); +} + static void max98090_jack_work(struct work_struct *work) { struct max98090_priv *max98090 = container_of(work, @@ -2103,8 +2199,10 @@ static irqreturn_t max98090_interrupt(int irq, void *data) if (active & M98090_SLD_MASK) dev_dbg(codec->dev, "M98090_SLD_MASK\n"); - if (active & M98090_ULK_MASK) - dev_err(codec->dev, "M98090_ULK_MASK\n"); + if (active & M98090_ULK_MASK) { + dev_dbg(codec->dev, "M98090_ULK_MASK\n"); + schedule_work(&max98090->pll_work); + } if (active & M98090_JDET_MASK) { dev_dbg(codec->dev, "M98090_JDET_MASK\n"); @@ -2177,6 +2275,7 @@ static struct snd_soc_dai_ops max98090_dai_ops = { .set_tdm_slot = max98090_set_tdm_slot, .hw_params = max98090_dai_hw_params, .digital_mute = max98090_dai_digital_mute, + .trigger = max98090_dai_trigger, }; static struct snd_soc_dai_driver max98090_dai[] = { @@ -2258,6 +2357,11 @@ static int max98090_probe(struct snd_soc_codec *codec) max98090->jack_state = M98090_JACK_STATE_NO_HEADSET; INIT_DELAYED_WORK(&max98090->jack_work, max98090_jack_work); + INIT_DELAYED_WORK(&max98090->pll_det_enable_work, + max98090_pll_det_enable_work); + INIT_WORK(&max98090->pll_det_disable_work, + max98090_pll_det_disable_work); + INIT_WORK(&max98090->pll_work, max98090_pll_work); /* Enable jack detection */ snd_soc_write(codec, M98090_REG_JACK_DETECT, @@ -2310,6 +2414,9 @@ static int max98090_remove(struct snd_soc_codec *codec) struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec); cancel_delayed_work_sync(&max98090->jack_work); + cancel_delayed_work_sync(&max98090->pll_det_enable_work); + cancel_work_sync(&max98090->pll_det_disable_work); + cancel_work_sync(&max98090->pll_work); return 0; } diff --git a/sound/soc/codecs/max98090.h b/sound/soc/codecs/max98090.h index cf1b6062ba8c..14427a566f41 100644 --- a/sound/soc/codecs/max98090.h +++ b/sound/soc/codecs/max98090.h @@ -1532,6 +1532,9 @@ struct max98090_priv { int irq; int jack_state; struct delayed_work jack_work; + struct delayed_work pll_det_enable_work; + struct work_struct pll_det_disable_work; + struct work_struct pll_work; struct snd_soc_jack *jack; unsigned int dai_fmt; int tdm_slots; From d89c6c0c91af0344b52dd21ca48dd29821fee677 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 1 Sep 2014 10:07:04 +0200 Subject: [PATCH 101/251] ALSA: hda - Add TLV_DB_SCALE_MUTE bit for relevant controls The DACs on Sigmatel/IDT codecs do mute at the lowest volume level, and in the earlier drivers, we passed TLV_DB_SCALE_MUTE bit for each volume control element like Speaker and Headphone as well as Master. Along with the translation to the generic parser, however, the TLV bit was lost for the slave controls (e.g. Speaker) but set only to Master. In theory this should have sufficed, but apps, particularly PA, do care the slave volume bits, so we seem to see a regression in the volume controls. This patch adds a flag to hda_gen_spec to specify the DAC mute feature, and adds the TLV bit properly for all relevant volume controls. Also, the TLV bit for vmaster is set in hda_generic.c, so that we can get rid of all tricks from the codec driver side. As the similar hack is applied to Conexant 5051 stuff, we can get rid of it as well. BugLink: https://bugs.launchpad.net/bugs/1357928 Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_generic.c | 9 ++++++++- sound/pci/hda/hda_generic.h | 1 + sound/pci/hda/patch_conexant.c | 8 ++------ sound/pci/hda/patch_sigmatel.c | 5 +---- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index b956449ddada..95121e818b4d 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -31,6 +31,7 @@ #include #include #include +#include #include "hda_codec.h" #include "hda_local.h" #include "hda_auto_parser.h" @@ -1105,6 +1106,7 @@ enum { */ static int assign_out_path_ctls(struct hda_codec *codec, struct nid_path *path) { + struct hda_gen_spec *spec = codec->spec; hda_nid_t nid; unsigned int val; int badness = 0; @@ -1119,6 +1121,8 @@ static int assign_out_path_ctls(struct hda_codec *codec, struct nid_path *path) nid = look_for_out_vol_nid(codec, path); if (nid) { val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); + if (spec->dac_min_mute) + val |= HDA_AMP_VAL_MIN_MUTE; if (is_ctl_used(codec, val, NID_PATH_VOL_CTL)) badness += BAD_SHARED_VOL; else @@ -1880,9 +1884,12 @@ static int parse_output_paths(struct hda_codec *codec) path = snd_hda_get_path_from_idx(codec, spec->out_paths[0]); if (path) spec->vmaster_nid = look_for_out_vol_nid(codec, path); - if (spec->vmaster_nid) + if (spec->vmaster_nid) { snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid, HDA_OUTPUT, spec->vmaster_tlv); + if (spec->dac_min_mute) + spec->vmaster_tlv[3] |= TLV_DB_SCALE_MUTE; + } } /* set initial pinctl targets */ diff --git a/sound/pci/hda/hda_generic.h b/sound/pci/hda/hda_generic.h index bb2dea743986..3f95f1d3f1f8 100644 --- a/sound/pci/hda/hda_generic.h +++ b/sound/pci/hda/hda_generic.h @@ -231,6 +231,7 @@ struct hda_gen_spec { unsigned int add_stereo_mix_input:1; /* add aamix as a capture src */ unsigned int add_jack_modes:1; /* add i/o jack mode enum ctls */ unsigned int power_down_unused:1; /* power down unused widgets */ + unsigned int dac_min_mute:1; /* minimal = mute for DACs */ /* other internal flags */ unsigned int no_analog:1; /* digital I/O only */ diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 6f2fa838b635..c0b03c112187 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -26,7 +26,6 @@ #include #include #include -#include #include "hda_codec.h" #include "hda_local.h" @@ -779,6 +778,7 @@ static const struct hda_model_fixup cxt5066_fixup_models[] = { */ static void add_cx5051_fake_mutes(struct hda_codec *codec) { + struct conexant_spec *spec = codec->spec; static hda_nid_t out_nids[] = { 0x10, 0x11, 0 }; @@ -788,6 +788,7 @@ static void add_cx5051_fake_mutes(struct hda_codec *codec) snd_hda_override_amp_caps(codec, *p, HDA_OUTPUT, AC_AMPCAP_MIN_MUTE | query_amp_caps(codec, *p, HDA_OUTPUT)); + spec->gen.dac_min_mute = true; } static int patch_conexant_auto(struct hda_codec *codec) @@ -860,11 +861,6 @@ static int patch_conexant_auto(struct hda_codec *codec) if (err < 0) goto error; - if (codec->vendor_id == 0x14f15051) { - /* minimum value is actually mute */ - spec->gen.vmaster_tlv[3] |= TLV_DB_SCALE_MUTE; - } - codec->patch_ops = cx_auto_patch_ops; /* Some laptops with Conexant chips show stalls in S3 resume, diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index ea823e1100da..f26ec04a29b5 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -32,7 +32,6 @@ #include #include #include -#include #include "hda_codec.h" #include "hda_local.h" #include "hda_auto_parser.h" @@ -4227,9 +4226,6 @@ static int stac_parse_auto_config(struct hda_codec *codec) if (err < 0) return err; - /* minimum value is actually mute */ - spec->gen.vmaster_tlv[3] |= TLV_DB_SCALE_MUTE; - /* setup analog beep controls */ if (spec->anabeep_nid > 0) { err = stac_auto_create_beep_ctls(codec, @@ -4413,6 +4409,7 @@ static int alloc_stac_spec(struct hda_codec *codec) snd_hda_gen_spec_init(&spec->gen); codec->spec = spec; codec->no_trigger_sense = 1; /* seems common with STAC/IDT codecs */ + spec->gen.dac_min_mute = true; return 0; } From b43cfb245f7346cbb25c1919577d9607d2adb974 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 2 Sep 2014 22:20:30 +0200 Subject: [PATCH 102/251] ASoC: adau1373: Remove unnecessary suspend/resume bias level changes The ASoC core will only call the suspend/resume callbacks when the device's DAPM context is idle. Since this driver sets idle_bias_off to true this means that the device is already in SND_SOC_BIAS_OFF when the suspend callback is called, so there is no need to manually set this state again. There is also no need to go to SND_SOC_BIAS_STANDBY in the resume callback since the core will go right back to SND_SOC_BIAS_OFF. Also drop the regcache_cache_only() calls from the suspend and resume handlers. There shouldn't be any IO happening after suspend and before resume. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/adau1373.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c index 1ff7d4d027e9..194756549ef4 100644 --- a/sound/soc/codecs/adau1373.c +++ b/sound/soc/codecs/adau1373.c @@ -1454,23 +1454,10 @@ static int adau1373_remove(struct snd_soc_codec *codec) return 0; } -static int adau1373_suspend(struct snd_soc_codec *codec) -{ - struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec); - int ret; - - ret = adau1373_set_bias_level(codec, SND_SOC_BIAS_OFF); - regcache_cache_only(adau1373->regmap, true); - - return ret; -} - static int adau1373_resume(struct snd_soc_codec *codec) { struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec); - regcache_cache_only(adau1373->regmap, false); - adau1373_set_bias_level(codec, SND_SOC_BIAS_STANDBY); regcache_sync(adau1373->regmap); return 0; @@ -1502,7 +1489,6 @@ static const struct regmap_config adau1373_regmap_config = { static struct snd_soc_codec_driver adau1373_codec_driver = { .probe = adau1373_probe, .remove = adau1373_remove, - .suspend = adau1373_suspend, .resume = adau1373_resume, .set_bias_level = adau1373_set_bias_level, .idle_bias_off = true, From 8e6fe35eabc64f35eff5844a2e542c403a00db15 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 2 Sep 2014 22:20:31 +0200 Subject: [PATCH 103/251] ASoC: lm49453: Remove unnecessary suspend/resume bias level changes The ASoC core will only call the suspend/resume callbacks when the device's DAPM context is idle. Since this driver sets idle_bias_off to true this means that the device is already in SND_SOC_BIAS_OFF when the suspend callback is called, so there is no need to manually set this state again. There is also no need to go to SND_SOC_BIAS_STANDBY in the resume callback since the core will go right back to SND_SOC_BIAS_OFF. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/lm49453.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/sound/soc/codecs/lm49453.c b/sound/soc/codecs/lm49453.c index 275b3f72f3f4..c1ae5764983f 100644 --- a/sound/soc/codecs/lm49453.c +++ b/sound/soc/codecs/lm49453.c @@ -1395,18 +1395,6 @@ static struct snd_soc_dai_driver lm49453_dai[] = { }, }; -static int lm49453_suspend(struct snd_soc_codec *codec) -{ - lm49453_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - -static int lm49453_resume(struct snd_soc_codec *codec) -{ - lm49453_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - return 0; -} - /* power down chip */ static int lm49453_remove(struct snd_soc_codec *codec) { @@ -1416,8 +1404,6 @@ static int lm49453_remove(struct snd_soc_codec *codec) static struct snd_soc_codec_driver soc_codec_dev_lm49453 = { .remove = lm49453_remove, - .suspend = lm49453_suspend, - .resume = lm49453_resume, .set_bias_level = lm49453_set_bias_level, .controls = lm49453_snd_controls, .num_controls = ARRAY_SIZE(lm49453_snd_controls), From 7d1a99da0861330f02de5c0f59df1d338477cb54 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 2 Sep 2014 22:20:32 +0200 Subject: [PATCH 104/251] ASoC: tlv320aic3x: Remove unnecessary suspend/resume bias level changes The ASoC core will only call the suspend/resume callbacks when the device's DAPM context is idle. Since this driver sets idle_bias_off to true this means that the device is already in SND_SOC_BIAS_OFF when the suspend callback is called, so there is no need to manually set this state again. There is also no need to go to SND_SOC_BIAS_STANDBY in the resume callback since the core will go right back to SND_SOC_BIAS_OFF. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic3x.c | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 64f179ee9834..f2c416d16b6c 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -1222,20 +1222,6 @@ static struct snd_soc_dai_driver aic3x_dai = { .symmetric_rates = 1, }; -static int aic3x_suspend(struct snd_soc_codec *codec) -{ - aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF); - - return 0; -} - -static int aic3x_resume(struct snd_soc_codec *codec) -{ - aic3x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - return 0; -} - static void aic3x_mono_init(struct snd_soc_codec *codec) { /* DAC to Mono Line Out default volume and route to Output mixer */ @@ -1429,8 +1415,6 @@ static struct snd_soc_codec_driver soc_codec_dev_aic3x = { .idle_bias_off = true, .probe = aic3x_probe, .remove = aic3x_remove, - .suspend = aic3x_suspend, - .resume = aic3x_resume, .controls = aic3x_snd_controls, .num_controls = ARRAY_SIZE(aic3x_snd_controls), .dapm_widgets = aic3x_dapm_widgets, From a7edeba4cbbd0f3d22d6d54da7c507bda29b2658 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 2 Sep 2014 22:20:33 +0200 Subject: [PATCH 105/251] ASoC: wm8804: Remove unnecessary suspend/resume bias level changes The ASoC core will only call the suspend/resume callbacks when the device's DAPM context is idle. Since this driver sets idle_bias_off to true this means that the device is already in SND_SOC_BIAS_OFF when the suspend callback is called, so there is no need to manually set this state again. There is also no need to go to SND_SOC_BIAS_STANDBY in the resume callback since the core will go right back to SND_SOC_BIAS_OFF. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8804.c | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c index 0ea01dfcb6e1..3addc5fe5cb2 100644 --- a/sound/soc/codecs/wm8804.c +++ b/sound/soc/codecs/wm8804.c @@ -518,23 +518,6 @@ static int wm8804_set_bias_level(struct snd_soc_codec *codec, return 0; } -#ifdef CONFIG_PM -static int wm8804_suspend(struct snd_soc_codec *codec) -{ - wm8804_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - -static int wm8804_resume(struct snd_soc_codec *codec) -{ - wm8804_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - return 0; -} -#else -#define wm8804_suspend NULL -#define wm8804_resume NULL -#endif - static int wm8804_remove(struct snd_soc_codec *codec) { struct wm8804_priv *wm8804; @@ -671,8 +654,6 @@ static struct snd_soc_dai_driver wm8804_dai = { static struct snd_soc_codec_driver soc_codec_dev_wm8804 = { .probe = wm8804_probe, .remove = wm8804_remove, - .suspend = wm8804_suspend, - .resume = wm8804_resume, .set_bias_level = wm8804_set_bias_level, .idle_bias_off = true, From e02c716d2ec065fd58c2fc8100fd5f359ab61e7e Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 2 Sep 2014 22:20:34 +0200 Subject: [PATCH 106/251] ASoC: wm8995: Remove unnecessary suspend/resume bias level changes The ASoC core will only call the suspend/resume callbacks when the device's DAPM context is idle. Since this driver sets idle_bias_off to true this means that the device is already in SND_SOC_BIAS_OFF when the suspend callback is called, so there is no need to manually set this state again. There is also no need to go to SND_SOC_BIAS_STANDBY in the resume callback since the core will go right back to SND_SOC_BIAS_OFF. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8995.c | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c index cae4ac5a5730..1288edeb8c7d 100644 --- a/sound/soc/codecs/wm8995.c +++ b/sound/soc/codecs/wm8995.c @@ -1998,23 +1998,6 @@ static int wm8995_set_bias_level(struct snd_soc_codec *codec, return 0; } -#ifdef CONFIG_PM -static int wm8995_suspend(struct snd_soc_codec *codec) -{ - wm8995_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - -static int wm8995_resume(struct snd_soc_codec *codec) -{ - wm8995_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - return 0; -} -#else -#define wm8995_suspend NULL -#define wm8995_resume NULL -#endif - static int wm8995_remove(struct snd_soc_codec *codec) { struct wm8995_priv *wm8995; @@ -2220,8 +2203,6 @@ static struct snd_soc_dai_driver wm8995_dai[] = { static struct snd_soc_codec_driver soc_codec_dev_wm8995 = { .probe = wm8995_probe, .remove = wm8995_remove, - .suspend = wm8995_suspend, - .resume = wm8995_resume, .set_bias_level = wm8995_set_bias_level, .idle_bias_off = true, }; From 9cfb76905da525579d0d43c1205c86033d0ae3e5 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 4 Sep 2014 10:59:41 +0300 Subject: [PATCH 107/251] ASoC: tlv320aic31xx: Enable support for S24_LE format S24_LE is the same on the bus as S24_3LE, which means the codec can support it. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic31xx.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/tlv320aic31xx.h b/sound/soc/codecs/tlv320aic31xx.h index 52ed57c69dfa..fe16c34607bb 100644 --- a/sound/soc/codecs/tlv320aic31xx.h +++ b/sound/soc/codecs/tlv320aic31xx.h @@ -18,7 +18,8 @@ #define AIC31XX_RATES SNDRV_PCM_RATE_8000_192000 #define AIC31XX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE \ - | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) + | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE \ + | SNDRV_PCM_FMTBIT_S32_LE) #define AIC31XX_STEREO_CLASS_D_BIT 0x1 From 01e0df6647e713469466c7bb6d7157c2e3046192 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 4 Sep 2014 19:44:04 +0200 Subject: [PATCH 108/251] ASoC: Set card->instantiated to false when removing the card Set card->instantiated to false when the card is removed to make sure that operations that expect the card to be fully instantiated do not run anymore during card removal. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 1b422c5c36c8..ff9d2892f473 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3810,8 +3810,10 @@ EXPORT_SYMBOL_GPL(snd_soc_register_card); */ int snd_soc_unregister_card(struct snd_soc_card *card) { - if (card->instantiated) + if (card->instantiated) { + card->instantiated = false; soc_cleanup_card_resources(card); + } dev_dbg(card->dev, "ASoC: Unregistered card '%s'\n", card->name); return 0; From 1c325f771a88579f227fe017e4ee77d852cf5435 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 4 Sep 2014 19:44:05 +0200 Subject: [PATCH 109/251] ASoC: Shutdown DAPM contexts when removing a card Currently when a ASoC sound card is unregistered we leave the individual components in their current state, just call the remove() callback and leave it to the drivers to do the proper shutdown/cleanup. This patch introduces a call to snd_soc_dapm_shutdown() when removing the card. This will make sure that all DAPM widgets are properly powered down and all DAPM contexts are put at the SND_SOC_BIAS_OFF level. This will ensure that all components are properly powered down when the card is removed. Since a lot of drivers manually go to SND_SOC_BIAS_OFF in their remove callback this will also allow us to remove a bit of duplicated code. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index ff9d2892f473..068785fa1a06 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3812,6 +3812,7 @@ int snd_soc_unregister_card(struct snd_soc_card *card) { if (card->instantiated) { card->instantiated = false; + snd_soc_dapm_shutdown(card); soc_cleanup_card_resources(card); } dev_dbg(card->dev, "ASoC: Unregistered card '%s'\n", card->name); From 86dbf2ac6fcb2d2932d4610f2dfe0954aa0633f7 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 4 Sep 2014 19:44:06 +0200 Subject: [PATCH 110/251] ASoC: Add support for automatically going to BIAS_OFF on suspend There is a substantial amount of drivers that in go to SND_SOC_BIAS_OFF on suspend and go back to SND_SOC_BIAS_SUSPEND on resume (Often this is even the only thing done in the suspend and resume handlers). This patch introduces a new suspend_bias_off flag, which when set by a driver will let the ASoC core automatically put the device's DAPM context at the SND_SOC_BIAS_OFF level during suspend. Once the device is resumed the DAPM context will go back to SND_SOC_BIAS_STANDBY (if the context is idle, otherwise to SND_SOC_BIAS_ON). This will allow us to remove a fair bit of duplicated code from the drivers. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- include/sound/soc-dapm.h | 3 ++- include/sound/soc.h | 1 + sound/soc/soc-core.c | 1 + sound/soc/soc-dapm.c | 20 ++++++++++++++++++-- 4 files changed, 22 insertions(+), 3 deletions(-) diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index aac04ff84eea..f955d65c5656 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -587,7 +587,8 @@ struct snd_soc_dapm_context { enum snd_soc_bias_level suspend_bias_level; struct delayed_work delayed_work; unsigned int idle_bias_off:1; /* Use BIAS_OFF instead of STANDBY */ - + /* Go to BIAS_OFF in suspend if the DAPM context is idle */ + unsigned int suspend_bias_off:1; void (*seq_notifier)(struct snd_soc_dapm_context *, enum snd_soc_dapm_type, int); diff --git a/include/sound/soc.h b/include/sound/soc.h index ce09302bfd6d..ac99fc083eec 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -848,6 +848,7 @@ struct snd_soc_codec_driver { int (*set_bias_level)(struct snd_soc_codec *, enum snd_soc_bias_level level); bool idle_bias_off; + bool suspend_bias_off; void (*seq_notifier)(struct snd_soc_dapm_context *, enum snd_soc_dapm_type, int); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 068785fa1a06..2bdf9a4ac2b4 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -4402,6 +4402,7 @@ int snd_soc_register_codec(struct device *dev, codec->component.ignore_pmdown_time = codec_drv->ignore_pmdown_time; codec->dapm.codec = codec; codec->dapm.idle_bias_off = codec_drv->idle_bias_off; + codec->dapm.suspend_bias_off = codec_drv->suspend_bias_off; if (codec_drv->seq_notifier) codec->dapm.seq_notifier = codec_drv->seq_notifier; if (codec_drv->set_bias_level) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 8348352dc2c6..a2025a6b6a29 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -1683,6 +1683,22 @@ static void dapm_power_one_widget(struct snd_soc_dapm_widget *w, } } +static bool dapm_idle_bias_off(struct snd_soc_dapm_context *dapm) +{ + if (dapm->idle_bias_off) + return true; + + switch (snd_power_get_state(dapm->card->snd_card)) { + case SNDRV_CTL_POWER_D3hot: + case SNDRV_CTL_POWER_D3cold: + return dapm->suspend_bias_off; + default: + break; + } + + return false; +} + /* * Scan each dapm widget for complete audio path. * A complete path is a route that has valid endpoints i.e.:- @@ -1706,7 +1722,7 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event) trace_snd_soc_dapm_start(card); list_for_each_entry(d, &card->dapm_list, list) { - if (d->idle_bias_off) + if (dapm_idle_bias_off(d)) d->target_bias_level = SND_SOC_BIAS_OFF; else d->target_bias_level = SND_SOC_BIAS_STANDBY; @@ -1772,7 +1788,7 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event) if (d->target_bias_level > bias) bias = d->target_bias_level; list_for_each_entry(d, &card->dapm_list, list) - if (!d->idle_bias_off) + if (!dapm_idle_bias_off(d)) d->target_bias_level = bias; trace_snd_soc_dapm_walk_done(card); From a80932979a72ef9d4e66a69520c7588cc6de5699 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 4 Sep 2014 19:44:07 +0200 Subject: [PATCH 111/251] ASoC: Always run default suspend/resume code We do a bit more than just running the callbacks during suspend and resume these days (e.g. call regcache_mark_dirty() during suspend). But this is only when suspend and resume callbacks are specified for the driver, otherwise nothing is done. This means that drivers which don't want to do anything special during suspend and resume, but still want the standard operations to run, need to provide empty suspend and resume callback functions (rather than no callbacks). This patch updates the suspend and resume code to always run standard sequence regardless of whether suspend and resume handlers are provided. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 2bdf9a4ac2b4..c612900c80ff 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -637,7 +637,7 @@ int snd_soc_suspend(struct device *dev) list_for_each_entry(codec, &card->codec_dev_list, card_list) { /* If there are paths active then the CODEC will be held with * bias _ON and should not be suspended. */ - if (!codec->suspended && codec->driver->suspend) { + if (!codec->suspended) { switch (codec->dapm.bias_level) { case SND_SOC_BIAS_STANDBY: /* @@ -651,8 +651,10 @@ int snd_soc_suspend(struct device *dev) "ASoC: idle_bias_off CODEC on over suspend\n"); break; } + case SND_SOC_BIAS_OFF: - codec->driver->suspend(codec); + if (codec->driver->suspend) + codec->driver->suspend(codec); codec->suspended = 1; codec->cache_sync = 1; if (codec->component.regmap) @@ -726,11 +728,12 @@ static void soc_resume_deferred(struct work_struct *work) * left with bias OFF or STANDBY and suspended so we must now * resume. Otherwise the suspend was suppressed. */ - if (codec->driver->resume && codec->suspended) { + if (codec->suspended) { switch (codec->dapm.bias_level) { case SND_SOC_BIAS_STANDBY: case SND_SOC_BIAS_OFF: - codec->driver->resume(codec); + if (codec->driver->resume) + codec->driver->resume(codec); codec->suspended = 0; break; default: From d7858bd647cda68bf832997a280a2f44aec01f1b Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 4 Sep 2014 19:44:08 +0200 Subject: [PATCH 112/251] ASoC: adau1373: Cleanup manual bias level transitions The ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC, no need to do it manually anymore. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/adau1373.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c index 194756549ef4..7c784ad3e8b2 100644 --- a/sound/soc/codecs/adau1373.c +++ b/sound/soc/codecs/adau1373.c @@ -1448,12 +1448,6 @@ static int adau1373_set_bias_level(struct snd_soc_codec *codec, return 0; } -static int adau1373_remove(struct snd_soc_codec *codec) -{ - adau1373_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - static int adau1373_resume(struct snd_soc_codec *codec) { struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec); @@ -1488,7 +1482,6 @@ static const struct regmap_config adau1373_regmap_config = { static struct snd_soc_codec_driver adau1373_codec_driver = { .probe = adau1373_probe, - .remove = adau1373_remove, .resume = adau1373_resume, .set_bias_level = adau1373_set_bias_level, .idle_bias_off = true, From 0e0f9b960a011a9e3815004f37cc475229170dfd Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 4 Sep 2014 19:44:09 +0200 Subject: [PATCH 113/251] ASoC: adau17x1: Cleanup manual bias level transitions Set the CODEC driver's suspend_bias_off flag rather than manually going to SND_SOC_BIAS_OFF in suspend and SND_SOC_BIAS_STANDBY in resume. This makes the code a bit shorter and cleaner. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/adau1761.c | 2 +- sound/soc/codecs/adau1781.c | 2 +- sound/soc/codecs/adau17x1.c | 8 -------- sound/soc/codecs/adau17x1.h | 1 - 4 files changed, 2 insertions(+), 11 deletions(-) diff --git a/sound/soc/codecs/adau1761.c b/sound/soc/codecs/adau1761.c index 848cab839553..5518ebd6947c 100644 --- a/sound/soc/codecs/adau1761.c +++ b/sound/soc/codecs/adau1761.c @@ -714,9 +714,9 @@ static int adau1761_codec_probe(struct snd_soc_codec *codec) static const struct snd_soc_codec_driver adau1761_codec_driver = { .probe = adau1761_codec_probe, - .suspend = adau17x1_suspend, .resume = adau17x1_resume, .set_bias_level = adau1761_set_bias_level, + .suspend_bias_off = true, .controls = adau1761_controls, .num_controls = ARRAY_SIZE(adau1761_controls), diff --git a/sound/soc/codecs/adau1781.c b/sound/soc/codecs/adau1781.c index 045a61413840..e9fc00fb13dd 100644 --- a/sound/soc/codecs/adau1781.c +++ b/sound/soc/codecs/adau1781.c @@ -446,9 +446,9 @@ static int adau1781_codec_probe(struct snd_soc_codec *codec) static const struct snd_soc_codec_driver adau1781_codec_driver = { .probe = adau1781_codec_probe, - .suspend = adau17x1_suspend, .resume = adau17x1_resume, .set_bias_level = adau1781_set_bias_level, + .suspend_bias_off = true, .controls = adau1781_controls, .num_controls = ARRAY_SIZE(adau1781_controls), diff --git a/sound/soc/codecs/adau17x1.c b/sound/soc/codecs/adau17x1.c index 0b659704e60c..3e16c1c64115 100644 --- a/sound/soc/codecs/adau17x1.c +++ b/sound/soc/codecs/adau17x1.c @@ -815,13 +815,6 @@ int adau17x1_add_routes(struct snd_soc_codec *codec) } EXPORT_SYMBOL_GPL(adau17x1_add_routes); -int adau17x1_suspend(struct snd_soc_codec *codec) -{ - codec->driver->set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} -EXPORT_SYMBOL_GPL(adau17x1_suspend); - int adau17x1_resume(struct snd_soc_codec *codec) { struct adau *adau = snd_soc_codec_get_drvdata(codec); @@ -829,7 +822,6 @@ int adau17x1_resume(struct snd_soc_codec *codec) if (adau->switch_mode) adau->switch_mode(codec->dev); - codec->driver->set_bias_level(codec, SND_SOC_BIAS_STANDBY); regcache_sync(adau->regmap); return 0; diff --git a/sound/soc/codecs/adau17x1.h b/sound/soc/codecs/adau17x1.h index 3ffabaf4c7a8..e4a557fd7155 100644 --- a/sound/soc/codecs/adau17x1.h +++ b/sound/soc/codecs/adau17x1.h @@ -52,7 +52,6 @@ int adau17x1_set_micbias_voltage(struct snd_soc_codec *codec, enum adau17x1_micbias_voltage micbias); bool adau17x1_readable_register(struct device *dev, unsigned int reg); bool adau17x1_volatile_register(struct device *dev, unsigned int reg); -int adau17x1_suspend(struct snd_soc_codec *codec); int adau17x1_resume(struct snd_soc_codec *codec); extern const struct snd_soc_dai_ops adau17x1_dai_ops; From cd5d3a151118cd815be15970db099bcdb3f0ad12 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 4 Sep 2014 19:44:10 +0200 Subject: [PATCH 114/251] ASoC: adav80x: Cleanup manual bias level transitions Set the CODEC driver's suspend_bias_off flag rather than manually going to SND_SOC_BIAS_OFF in suspend and SND_SOC_BIAS_STANDBY in resume. This makes the code a bit shorter and cleaner. While we are at it also remove the regcache_cache_only() calls from suspend/resume as there shouldn't be any IO between suspend and resume. Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. The manual transition to SND_SOC_BIAS_STANDBY at the end of CODEC probe() can also be removed as the core will automatically do this after the CODEC has been probed. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/adav80x.c | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c index c43b93fdf0df..ce3cdca9fc62 100644 --- a/sound/soc/codecs/adav80x.c +++ b/sound/soc/codecs/adav80x.c @@ -812,42 +812,23 @@ static int adav80x_probe(struct snd_soc_codec *codec) /* Disable DAC zero flag */ regmap_write(adav80x->regmap, ADAV80X_DAC_CTRL3, 0x6); - return adav80x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); -} - -static int adav80x_suspend(struct snd_soc_codec *codec) -{ - struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); - int ret; - - ret = adav80x_set_bias_level(codec, SND_SOC_BIAS_OFF); - regcache_cache_only(adav80x->regmap, true); - - return ret; + return 0; } static int adav80x_resume(struct snd_soc_codec *codec) { struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); - regcache_cache_only(adav80x->regmap, false); - adav80x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); regcache_sync(adav80x->regmap); return 0; } -static int adav80x_remove(struct snd_soc_codec *codec) -{ - return adav80x_set_bias_level(codec, SND_SOC_BIAS_OFF); -} - static struct snd_soc_codec_driver adav80x_codec_driver = { .probe = adav80x_probe, - .remove = adav80x_remove, - .suspend = adav80x_suspend, .resume = adav80x_resume, .set_bias_level = adav80x_set_bias_level, + .suspend_bias_off = true, .set_pll = adav80x_set_pll, .set_sysclk = adav80x_set_sysclk, From 0f0cc5a775ebe88d9be12489874bd2799b42e242 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 4 Sep 2014 19:44:11 +0200 Subject: [PATCH 115/251] ASoC: ssm2518: Cleanup manual bias level transitions Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. The manual transition to SND_SOC_BIAS_OFF at the end of CODEC probe() can also be removed as the CODEC is already in OFF state at this point. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/ssm2518.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/sound/soc/codecs/ssm2518.c b/sound/soc/codecs/ssm2518.c index e8680bea5f86..67ea55adb307 100644 --- a/sound/soc/codecs/ssm2518.c +++ b/sound/soc/codecs/ssm2518.c @@ -646,17 +646,6 @@ static struct snd_soc_dai_driver ssm2518_dai = { .ops = &ssm2518_dai_ops, }; -static int ssm2518_probe(struct snd_soc_codec *codec) -{ - return ssm2518_set_bias_level(codec, SND_SOC_BIAS_OFF); -} - -static int ssm2518_remove(struct snd_soc_codec *codec) -{ - ssm2518_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - static int ssm2518_set_sysclk(struct snd_soc_codec *codec, int clk_id, int source, unsigned int freq, int dir) { @@ -727,8 +716,6 @@ static int ssm2518_set_sysclk(struct snd_soc_codec *codec, int clk_id, } static struct snd_soc_codec_driver ssm2518_codec_driver = { - .probe = ssm2518_probe, - .remove = ssm2518_remove, .set_bias_level = ssm2518_set_bias_level, .set_sysclk = ssm2518_set_sysclk, .idle_bias_off = true, From 85362efb80070bed890602483f71cd103be303c2 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 4 Sep 2014 19:44:12 +0200 Subject: [PATCH 116/251] ASoC: ssm2602: Cleanup manual bias level transitions Set the CODEC driver's suspend_bias_off flag rather than manually going to SND_SOC_BIAS_OFF in suspend and SND_SOC_BIAS_STANDBY in resume. This makes the code a bit shorter and cleaner. While we are at it also remove the regcache_cache_only() calls from suspend/resume as there shouldn't be any IO between suspend and resume. Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. The manual transition to SND_SOC_BIAS_STANDBY at the end of CODEC probe() can also be removed as the core will automatically do this after the CODEC has been probed. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/ssm2602.c | 24 ++---------------------- 1 file changed, 2 insertions(+), 22 deletions(-) diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c index 484b3bbe8624..0dec13648563 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c @@ -502,18 +502,11 @@ static struct snd_soc_dai_driver ssm2602_dai = { .symmetric_samplebits = 1, }; -static int ssm2602_suspend(struct snd_soc_codec *codec) -{ - ssm2602_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - static int ssm2602_resume(struct snd_soc_codec *codec) { struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec); regcache_sync(ssm2602->regmap); - ssm2602_set_bias_level(codec, SND_SOC_BIAS_STANDBY); return 0; } @@ -586,27 +579,14 @@ static int ssm260x_codec_probe(struct snd_soc_codec *codec) break; } - if (ret) - return ret; - - ssm2602_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - return 0; -} - -/* remove everything here */ -static int ssm2602_remove(struct snd_soc_codec *codec) -{ - ssm2602_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; + return ret; } static struct snd_soc_codec_driver soc_codec_dev_ssm2602 = { .probe = ssm260x_codec_probe, - .remove = ssm2602_remove, - .suspend = ssm2602_suspend, .resume = ssm2602_resume, .set_bias_level = ssm2602_set_bias_level, + .suspend_bias_off = true, .controls = ssm260x_snd_controls, .num_controls = ARRAY_SIZE(ssm260x_snd_controls), From 3d2c42d191a89ab35e3002309882e3b70fe12112 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 6 Sep 2014 14:29:31 +0200 Subject: [PATCH 117/251] ASoC: 88pm860x-codec: Cleanup manual bias level transitions Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. The manual transition to SND_SOC_BIAS_STANDBY at the end of CODEC probe() can also be removed as the core will automatically do this after the CODEC has been probed. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/88pm860x-codec.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c index 922006dd0583..4c3b0af39fd8 100644 --- a/sound/soc/codecs/88pm860x-codec.c +++ b/sound/soc/codecs/88pm860x-codec.c @@ -1337,8 +1337,6 @@ static int pm860x_probe(struct snd_soc_codec *codec) } } - pm860x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - return 0; out: @@ -1354,7 +1352,6 @@ static int pm860x_remove(struct snd_soc_codec *codec) for (i = 3; i >= 0; i--) free_irq(pm860x->irq[i], pm860x); - pm860x_set_bias_level(codec, SND_SOC_BIAS_OFF); return 0; } From 2a93f70925a56ae1629be8b46c3c6d502f98dded Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 6 Sep 2014 14:29:33 +0200 Subject: [PATCH 118/251] ASoC: jz4740: Cleanup manual bias level transitions Set the CODEC driver's suspend_bias_off flag rather than manually going to SND_SOC_BIAS_OFF in suspend and SND_SOC_BIAS_STANDBY in resume. This makes the code a bit shorter and cleaner. Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. The manual transition to SND_SOC_BIAS_STANDBY at the end of CODEC probe() can also be removed as the core will automatically do this after the CODEC has been probed. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/jz4740.c | 30 +----------------------------- 1 file changed, 1 insertion(+), 29 deletions(-) diff --git a/sound/soc/codecs/jz4740.c b/sound/soc/codecs/jz4740.c index bcebd1a9ce31..df7c01cf7072 100644 --- a/sound/soc/codecs/jz4740.c +++ b/sound/soc/codecs/jz4740.c @@ -293,41 +293,13 @@ static int jz4740_codec_dev_probe(struct snd_soc_codec *codec) regmap_update_bits(jz4740_codec->regmap, JZ4740_REG_CODEC_1, JZ4740_CODEC_1_SW2_ENABLE, JZ4740_CODEC_1_SW2_ENABLE); - jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - return 0; } -static int jz4740_codec_dev_remove(struct snd_soc_codec *codec) -{ - jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_OFF); - - return 0; -} - -#ifdef CONFIG_PM_SLEEP - -static int jz4740_codec_suspend(struct snd_soc_codec *codec) -{ - return jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_OFF); -} - -static int jz4740_codec_resume(struct snd_soc_codec *codec) -{ - return jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_STANDBY); -} - -#else -#define jz4740_codec_suspend NULL -#define jz4740_codec_resume NULL -#endif - static struct snd_soc_codec_driver soc_codec_dev_jz4740_codec = { .probe = jz4740_codec_dev_probe, - .remove = jz4740_codec_dev_remove, - .suspend = jz4740_codec_suspend, - .resume = jz4740_codec_resume, .set_bias_level = jz4740_codec_set_bias_level, + .suspend_bias_off = true, .controls = jz4740_codec_controls, .num_controls = ARRAY_SIZE(jz4740_codec_controls), From 35199a7c11d5f6a87a5b35dfd69fde3f65d37fac Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 6 Sep 2014 14:29:34 +0200 Subject: [PATCH 119/251] ASoC: ml26124: Cleanup manual bias level transitions Set the CODEC driver's suspend_bias_off flag rather than manually going to SND_SOC_BIAS_OFF in suspend and SND_SOC_BIAS_STANDBY in resume. This makes the code a bit shorter and cleaner. The manual transition to SND_SOC_BIAS_STANDBY at the end of CODEC probe() can also be removed as the core will automatically do this after the CODEC has been probed. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/ml26124.c | 24 +----------------------- 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/sound/soc/codecs/ml26124.c b/sound/soc/codecs/ml26124.c index e661e8420e3d..711f55039522 100644 --- a/sound/soc/codecs/ml26124.c +++ b/sound/soc/codecs/ml26124.c @@ -565,41 +565,19 @@ static struct snd_soc_dai_driver ml26124_dai = { .symmetric_rates = 1, }; -#ifdef CONFIG_PM -static int ml26124_suspend(struct snd_soc_codec *codec) -{ - ml26124_set_bias_level(codec, SND_SOC_BIAS_OFF); - - return 0; -} - -static int ml26124_resume(struct snd_soc_codec *codec) -{ - ml26124_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - return 0; -} -#else -#define ml26124_suspend NULL -#define ml26124_resume NULL -#endif - static int ml26124_probe(struct snd_soc_codec *codec) { /* Software Reset */ snd_soc_update_bits(codec, ML26124_SW_RST, 0x01, 1); snd_soc_update_bits(codec, ML26124_SW_RST, 0x01, 0); - ml26124_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - return 0; } static struct snd_soc_codec_driver soc_codec_dev_ml26124 = { .probe = ml26124_probe, - .suspend = ml26124_suspend, - .resume = ml26124_resume, .set_bias_level = ml26124_set_bias_level, + .suspend_bias_off = true, .dapm_widgets = ml26124_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(ml26124_dapm_widgets), .dapm_routes = ml26124_intercon, From e649057a41c24b4122e976746649e471709d4b16 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 6 Sep 2014 14:29:35 +0200 Subject: [PATCH 120/251] ASoC: sgtl5000: Cleanup bias level transitions Set the CODEC driver's suspend_bias_off flag rather than manually going to SND_SOC_BIAS_OFF in suspend and SND_SOC_BIAS_STANDBY in resume. This makes the code a bit shorter and cleaner. Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. The manual transition to SND_SOC_BIAS_STANDBY at the end of CODEC probe() can also be removed as the core will automatically do this after the CODEC has been probed. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/sgtl5000.c | 30 +----------------------------- 1 file changed, 1 insertion(+), 29 deletions(-) diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index e997d271728d..a604a225a8a3 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -1073,26 +1073,6 @@ static bool sgtl5000_readable(struct device *dev, unsigned int reg) } } -#ifdef CONFIG_SUSPEND -static int sgtl5000_suspend(struct snd_soc_codec *codec) -{ - sgtl5000_set_bias_level(codec, SND_SOC_BIAS_OFF); - - return 0; -} - -static int sgtl5000_resume(struct snd_soc_codec *codec) -{ - /* Bring the codec back up to standby to enable regulators */ - sgtl5000_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - return 0; -} -#else -#define sgtl5000_suspend NULL -#define sgtl5000_resume NULL -#endif /* CONFIG_SUSPEND */ - /* * sgtl5000 has 3 internal power supplies: * 1. VAG, normally set to vdda/2 @@ -1352,11 +1332,6 @@ static int sgtl5000_probe(struct snd_soc_codec *codec) */ snd_soc_write(codec, SGTL5000_DAP_CTRL, 0); - /* leading to standby state */ - ret = sgtl5000_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - if (ret) - goto err; - return 0; err: @@ -1373,8 +1348,6 @@ static int sgtl5000_remove(struct snd_soc_codec *codec) { struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec); - sgtl5000_set_bias_level(codec, SND_SOC_BIAS_OFF); - regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies), sgtl5000->supplies); regulator_bulk_free(ARRAY_SIZE(sgtl5000->supplies), @@ -1387,9 +1360,8 @@ static int sgtl5000_remove(struct snd_soc_codec *codec) static struct snd_soc_codec_driver sgtl5000_driver = { .probe = sgtl5000_probe, .remove = sgtl5000_remove, - .suspend = sgtl5000_suspend, - .resume = sgtl5000_resume, .set_bias_level = sgtl5000_set_bias_level, + .suspend_bias_off = true, .controls = sgtl5000_snd_controls, .num_controls = ARRAY_SIZE(sgtl5000_snd_controls), .dapm_widgets = sgtl5000_dapm_widgets, From 8d01370f59856a0ac5b222878667d52477b589f0 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 6 Sep 2014 14:29:32 +0200 Subject: [PATCH 121/251] ASoC: es8328: Cleanup manual bias level transitions Set the CODEC driver's suspend_bias_off flag rather than manually going to SND_SOC_BIAS_OFF in suspend and SND_SOC_BIAS_STANDBY in resume. This makes the code a bit shorter and cleaner. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/es8328.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/es8328.c b/sound/soc/codecs/es8328.c index 3ff787063304..f27325155ace 100644 --- a/sound/soc/codecs/es8328.c +++ b/sound/soc/codecs/es8328.c @@ -602,8 +602,6 @@ static int es8328_suspend(struct snd_soc_codec *codec) es8328 = snd_soc_codec_get_drvdata(codec); - es8328_set_bias_level(codec, SND_SOC_BIAS_OFF); - clk_disable_unprepare(es8328->clk); ret = regulator_bulk_disable(ARRAY_SIZE(es8328->supplies), @@ -643,7 +641,6 @@ static int es8328_resume(struct snd_soc_codec *codec) return ret; } - es8328_set_bias_level(codec, SND_SOC_BIAS_STANDBY); return 0; } @@ -712,6 +709,8 @@ static struct snd_soc_codec_driver es8328_codec_driver = { .resume = es8328_resume, .remove = es8328_remove, .set_bias_level = es8328_set_bias_level, + .suspend_bias_off = true, + .controls = es8328_snd_controls, .num_controls = ARRAY_SIZE(es8328_snd_controls), .dapm_widgets = es8328_dapm_widgets, From c815dbb47758bd469927849fdd45fed3ce206e73 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 20 Aug 2014 13:08:46 +0200 Subject: [PATCH 122/251] ASoC: Add snd_soc_component_{get,set}_drvdata() Add Add snd_soc_component_{get,set}_drvdata() similar to snd_soc_codec_{get,set}_drvdata() and snd_soc_platform_{get,set}_drvdata(). Also update them to use the new functions internally. Signed-off-by: Lars-Peter Clausen Reviewed-by: Vinod Koul Signed-off-by: Mark Brown --- include/sound/soc.h | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index ce09302bfd6d..f8b23dd7c3a7 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1298,26 +1298,37 @@ static inline void *snd_soc_card_get_drvdata(struct snd_soc_card *card) return card->drvdata; } +static inline void snd_soc_component_set_drvdata(struct snd_soc_component *c, + void *data) +{ + dev_set_drvdata(c->dev, data); +} + +static inline void *snd_soc_component_get_drvdata(struct snd_soc_component *c) +{ + return dev_get_drvdata(c->dev); +} + static inline void snd_soc_codec_set_drvdata(struct snd_soc_codec *codec, void *data) { - dev_set_drvdata(codec->dev, data); + snd_soc_component_set_drvdata(&codec->component, data); } static inline void *snd_soc_codec_get_drvdata(struct snd_soc_codec *codec) { - return dev_get_drvdata(codec->dev); + return snd_soc_component_get_drvdata(&codec->component); } static inline void snd_soc_platform_set_drvdata(struct snd_soc_platform *platform, void *data) { - dev_set_drvdata(platform->dev, data); + snd_soc_component_set_drvdata(&platform->component, data); } static inline void *snd_soc_platform_get_drvdata(struct snd_soc_platform *platform) { - return dev_get_drvdata(platform->dev); + return snd_soc_component_get_drvdata(&platform->component); } static inline void snd_soc_pcm_set_drvdata(struct snd_soc_pcm_runtime *rtd, From bd033808e2b160bab61cfe18b0ecb4ccc7809516 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 20 Aug 2014 13:08:47 +0200 Subject: [PATCH 123/251] ASoC: sst-haswell-pcm: Alloc state struct in driver probe() Resource allocations should happen in driver probe callback rather than in snd_soc_platform probe functions. Especially if the resource is device managed. The snd_soc_* probe/remove functions are mainly intended to be used for things that require the component to be already bound to a card. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/intel/sst-haswell-pcm.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/sound/soc/intel/sst-haswell-pcm.c b/sound/soc/intel/sst-haswell-pcm.c index 61bf6da4bb02..1de095876857 100644 --- a/sound/soc/intel/sst-haswell-pcm.c +++ b/sound/soc/intel/sst-haswell-pcm.c @@ -778,20 +778,11 @@ static const struct snd_soc_dapm_route graph[] = { static int hsw_pcm_probe(struct snd_soc_platform *platform) { + struct hsw_priv_data *priv_data = snd_soc_platform_get_drvdata(platform); struct sst_pdata *pdata = dev_get_platdata(platform->dev); - struct hsw_priv_data *priv_data; - struct device *dma_dev; + struct device *dma_dev = pdata->dma_dev; int i, ret = 0; - if (!pdata) - return -ENODEV; - - dma_dev = pdata->dma_dev; - - priv_data = devm_kzalloc(platform->dev, sizeof(*priv_data), GFP_KERNEL); - priv_data->hsw = pdata->dsp; - snd_soc_platform_set_drvdata(platform, priv_data); - /* allocate DSP buffer page tables */ for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) { @@ -863,12 +854,23 @@ static const struct snd_soc_component_driver hsw_dai_component = { static int hsw_pcm_dev_probe(struct platform_device *pdev) { struct sst_pdata *sst_pdata = dev_get_platdata(&pdev->dev); + struct hsw_priv_data *priv_data; int ret; + if (!sst_pdata) + return -EINVAL; + + priv_data = devm_kzalloc(&pdev->dev, sizeof(*priv_data), GFP_KERNEL); + if (!priv_data) + return -ENOMEM; + ret = sst_hsw_dsp_init(&pdev->dev, sst_pdata); if (ret < 0) return -ENODEV; + priv_data->hsw = sst_pdata->dsp; + platform_set_drvdata(pdev, priv_data); + ret = snd_soc_register_platform(&pdev->dev, &hsw_soc_platform); if (ret < 0) goto err_plat; From 923976a30b36ce0970e88f53ed2f2b5b61aeeb73 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 20 Aug 2014 13:08:48 +0200 Subject: [PATCH 124/251] ASoC: sst-haswell-pcm: Move controls and DAPM elements to component The sst-haswell-pcm driver registers both a snd_soc_component and a snd_soc_platform and expects that the DAPM widgets for the DAIs registered by component are added to the DAPM context of the platform. This requires us to have a hack in the ASoC core which does so. Moving the DAPM elements over to the component allows us to remove this hack. While we are at it also move the controls over to the component. The controls don't need the platform for anything other than snd_soc_platform_get_drvdata(), this can easily be replaced by snd_soc_component_get_drvdata(). As the long term goal is to register only a single component this is a step in the right direction. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/intel/sst-haswell-pcm.c | 32 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/sound/soc/intel/sst-haswell-pcm.c b/sound/soc/intel/sst-haswell-pcm.c index 1de095876857..33fc5c3abf55 100644 --- a/sound/soc/intel/sst-haswell-pcm.c +++ b/sound/soc/intel/sst-haswell-pcm.c @@ -138,11 +138,10 @@ static inline unsigned int hsw_ipc_to_mixer(u32 value) static int hsw_stream_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol); + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(cmpnt); struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - struct hsw_priv_data *pdata = - snd_soc_platform_get_drvdata(platform); struct hsw_pcm_data *pcm_data = &pdata->pcm[mc->reg]; struct sst_hsw *hsw = pdata->hsw; u32 volume; @@ -176,11 +175,10 @@ static int hsw_stream_volume_put(struct snd_kcontrol *kcontrol, static int hsw_stream_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol); + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(cmpnt); struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - struct hsw_priv_data *pdata = - snd_soc_platform_get_drvdata(platform); struct hsw_pcm_data *pcm_data = &pdata->pcm[mc->reg]; struct sst_hsw *hsw = pdata->hsw; u32 volume; @@ -208,8 +206,8 @@ static int hsw_stream_volume_get(struct snd_kcontrol *kcontrol, static int hsw_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol); - struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform); + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(cmpnt); struct sst_hsw *hsw = pdata->hsw; u32 volume; @@ -233,8 +231,8 @@ static int hsw_volume_put(struct snd_kcontrol *kcontrol, static int hsw_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol); - struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform); + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(cmpnt); struct sst_hsw *hsw = pdata->hsw; unsigned int volume = 0; @@ -839,16 +837,16 @@ static struct snd_soc_platform_driver hsw_soc_platform = { .ops = &hsw_pcm_ops, .pcm_new = hsw_pcm_new, .pcm_free = hsw_pcm_free, - .controls = hsw_volume_controls, - .num_controls = ARRAY_SIZE(hsw_volume_controls), - .dapm_widgets = widgets, - .num_dapm_widgets = ARRAY_SIZE(widgets), - .dapm_routes = graph, - .num_dapm_routes = ARRAY_SIZE(graph), }; static const struct snd_soc_component_driver hsw_dai_component = { - .name = "haswell-dai", + .name = "haswell-dai", + .controls = hsw_volume_controls, + .num_controls = ARRAY_SIZE(hsw_volume_controls), + .dapm_widgets = widgets, + .num_dapm_widgets = ARRAY_SIZE(widgets), + .dapm_routes = graph, + .num_dapm_routes = ARRAY_SIZE(graph), }; static int hsw_pcm_dev_probe(struct platform_device *pdev) From 0634814fe0f29a46c44386a03f259f99c983bf7e Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 20 Aug 2014 13:08:49 +0200 Subject: [PATCH 125/251] ASoC: Remove table based DAPM/control setup support from snd_soc_platform_driver There are no users left and new users should rather use the component_driver struct embedded in the snd_soc_platform_driver struct to do this. E.g.: static const struct snd_soc_platform_driver foobar_driver = { .component_driver = { .dapm_widgets = ..., .num_dapm_widgets = ..., ..., }, ... }; instead of static const struct snd_soc_platform_driver foobar_driver = { .dapm_widgets = ..., .num_dapm_widgets = ..., ... }; This also allows us to remove the steal_sibling_dai_widgets hack. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- include/sound/soc.h | 9 ------- sound/soc/soc-core.c | 58 +++++--------------------------------------- 2 files changed, 6 insertions(+), 61 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index f8b23dd7c3a7..cd141a156da2 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -764,7 +764,6 @@ struct snd_soc_component { unsigned int num_dapm_widgets; const struct snd_soc_dapm_route *dapm_routes; unsigned int num_dapm_routes; - bool steal_sibling_dai_widgets; struct snd_soc_codec *codec; int (*probe)(struct snd_soc_component *); @@ -868,14 +867,6 @@ struct snd_soc_platform_driver { int (*pcm_new)(struct snd_soc_pcm_runtime *); void (*pcm_free)(struct snd_pcm *); - /* Default control and setup, added after probe() is run */ - const struct snd_kcontrol_new *controls; - int num_controls; - const struct snd_soc_dapm_widget *dapm_widgets; - int num_dapm_widgets; - const struct snd_soc_dapm_route *dapm_routes; - int num_dapm_routes; - /* * For platform caused delay reporting. * Optional. diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 1b422c5c36c8..052f59c1917f 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1087,7 +1087,6 @@ static int soc_probe_component(struct snd_soc_card *card, struct snd_soc_component *component) { struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); - struct snd_soc_component *dai_component, *component2; struct snd_soc_dai *dai; int ret; @@ -1114,44 +1113,12 @@ static int soc_probe_component(struct snd_soc_card *card, } } - /* - * This is rather ugly, but certain platforms expect that the DAPM - * widgets for the DAIs for components with the same parent device are - * created in the platforms DAPM context. Until that is fixed we need to - * keep this. - */ - if (component->steal_sibling_dai_widgets) { - dai_component = NULL; - list_for_each_entry(component2, &component_list, list) { - if (component == component2) - continue; - - if (component2->dev == component->dev && - !list_empty(&component2->dai_list)) { - dai_component = component2; - break; - } - } - } else { - dai_component = component; - list_for_each_entry(component2, &component_list, list) { - if (component2->dev == component->dev && - component2->steal_sibling_dai_widgets) { - dai_component = NULL; - break; - } - } - } - - if (dai_component) { - list_for_each_entry(dai, &dai_component->dai_list, list) { - snd_soc_dapm_new_dai_widgets(dapm, dai); - if (ret != 0) { - dev_err(component->dev, - "Failed to create DAI widgets %d\n", - ret); - goto err_probe; - } + list_for_each_entry(dai, &component->dai_list, list) { + ret = snd_soc_dapm_new_dai_widgets(dapm, dai); + if (ret != 0) { + dev_err(component->dev, + "Failed to create DAI widgets %d\n", ret); + goto err_probe; } } @@ -4164,19 +4131,6 @@ int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform, platform->dev = dev; platform->driver = platform_drv; - if (platform_drv->controls) { - platform->component.controls = platform_drv->controls; - platform->component.num_controls = platform_drv->num_controls; - } - if (platform_drv->dapm_widgets) { - platform->component.dapm_widgets = platform_drv->dapm_widgets; - platform->component.num_dapm_widgets = platform_drv->num_dapm_widgets; - platform->component.steal_sibling_dai_widgets = true; - } - if (platform_drv->dapm_routes) { - platform->component.dapm_routes = platform_drv->dapm_routes; - platform->component.num_dapm_routes = platform_drv->num_dapm_routes; - } if (platform_drv->probe) platform->component.probe = snd_soc_platform_drv_probe; From 02024756e6ab3a3fcdc3b203552b16b345ebd97d Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Tue, 2 Sep 2014 18:05:56 +0530 Subject: [PATCH 126/251] ASoC: mfld: pcm: Replace pr_ with dev_ Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/sst-mfld-platform-pcm.c | 44 +++++++++++++------------ 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/sound/soc/intel/sst-mfld-platform-pcm.c b/sound/soc/intel/sst-mfld-platform-pcm.c index 8e1e9bc27642..85deecd82b92 100644 --- a/sound/soc/intel/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/sst-mfld-platform-pcm.c @@ -43,12 +43,12 @@ int sst_register_dsp(struct sst_device *dev) return -ENODEV; mutex_lock(&sst_lock); if (sst) { - pr_err("we already have a device %s\n", sst->name); + dev_err(dev->dev, "we already have a device %s\n", sst->name); module_put(dev->dev->driver->owner); mutex_unlock(&sst_lock); return -EEXIST; } - pr_debug("registering device %s\n", dev->name); + dev_dbg(dev->dev, "registering device %s\n", dev->name); sst = dev; mutex_unlock(&sst_lock); return 0; @@ -70,7 +70,7 @@ int sst_unregister_dsp(struct sst_device *dev) } module_put(sst->dev->driver->owner); - pr_debug("unreg %s\n", sst->name); + dev_dbg(dev->dev, "unreg %s\n", sst->name); sst = NULL; mutex_unlock(&sst_lock); return 0; @@ -306,9 +306,10 @@ static int sst_platform_init_stream(struct snd_pcm_substream *substream) { struct sst_runtime_stream *stream = substream->runtime->private_data; + struct snd_soc_pcm_runtime *rtd = substream->private_data; int ret_val; - pr_debug("setting buffer ptr param\n"); + dev_dbg(rtd->dev, "setting buffer ptr param\n"); sst_set_stream_status(stream, SST_PLATFORM_INIT); stream->stream_info.period_elapsed = sst_period_elapsed; stream->stream_info.arg = substream; @@ -316,7 +317,7 @@ static int sst_platform_init_stream(struct snd_pcm_substream *substream) stream->stream_info.sfreq = substream->runtime->rate; ret_val = stream->ops->stream_init(sst->dev, &stream->stream_info); if (ret_val) - pr_err("control_set ret error %d\n", ret_val); + dev_err(rtd->dev, "control_set ret error %d\n", ret_val); return ret_val; } @@ -337,7 +338,7 @@ static int sst_media_open(struct snd_pcm_substream *substream, mutex_lock(&sst_lock); if (!sst || !try_module_get(sst->dev->driver->owner)) { - pr_err("no device available to run\n"); + dev_err(dai->dev, "no device available to run\n"); ret_val = -ENODEV; goto out_ops; } @@ -385,10 +386,11 @@ static inline unsigned int get_current_pipe_id(struct snd_soc_platform *platform substream->runtime->private_data; u32 str_id = stream->stream_info.str_id; unsigned int pipe_id; + pipe_id = map[str_id].device_id; - pr_debug("%s: got pipe_id = %#x for str_id = %d\n", - __func__, pipe_id, str_id); + dev_dbg(platform->dev, "got pipe_id = %#x for str_id = %d\n", + pipe_id, str_id); return pipe_id; } @@ -459,29 +461,30 @@ static int sst_platform_pcm_trigger(struct snd_pcm_substream *substream, int ret_val = 0, str_id; struct sst_runtime_stream *stream; int status; + struct snd_soc_pcm_runtime *rtd = substream->private_data; - pr_debug("sst_platform_pcm_trigger called\n"); + dev_dbg(rtd->dev, "sst_platform_pcm_trigger called\n"); stream = substream->runtime->private_data; str_id = stream->stream_info.str_id; switch (cmd) { case SNDRV_PCM_TRIGGER_START: - pr_debug("sst: Trigger Start\n"); + dev_dbg(rtd->dev, "sst: Trigger Start\n"); status = SST_PLATFORM_RUNNING; stream->stream_info.arg = substream; ret_val = stream->ops->stream_start(sst->dev, str_id); break; case SNDRV_PCM_TRIGGER_STOP: - pr_debug("sst: in stop\n"); + dev_dbg(rtd->dev, "sst: in stop\n"); status = SST_PLATFORM_DROPPED; ret_val = stream->ops->stream_drop(sst->dev, str_id); break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - pr_debug("sst: in pause\n"); + dev_dbg(rtd->dev, "sst: in pause\n"); status = SST_PLATFORM_PAUSED; ret_val = stream->ops->stream_pause(sst->dev, str_id); break; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - pr_debug("sst: in pause release\n"); + dev_dbg(rtd->dev, "sst: in pause release\n"); status = SST_PLATFORM_RUNNING; ret_val = stream->ops->stream_pause_release(sst->dev, str_id); break; @@ -502,6 +505,7 @@ static snd_pcm_uframes_t sst_platform_pcm_pointer struct sst_runtime_stream *stream; int ret_val, status; struct pcm_stream_info *str_info; + struct snd_soc_pcm_runtime *rtd = substream->private_data; stream = substream->runtime->private_data; status = sst_get_stream_status(stream); @@ -510,7 +514,7 @@ static snd_pcm_uframes_t sst_platform_pcm_pointer str_info = &stream->stream_info; ret_val = stream->ops->stream_read_tstamp(sst->dev, str_info); if (ret_val) { - pr_err("sst: error code = %d\n", ret_val); + dev_err(rtd->dev, "sst: error code = %d\n", ret_val); return ret_val; } substream->runtime->delay = str_info->pcm_delay; @@ -526,7 +530,7 @@ static struct snd_pcm_ops sst_platform_ops = { static void sst_pcm_free(struct snd_pcm *pcm) { - pr_debug("sst_pcm_free called\n"); + dev_dbg(pcm->dev, "sst_pcm_free called\n"); snd_pcm_lib_preallocate_free_for_all(pcm); } @@ -543,7 +547,7 @@ static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd) snd_dma_continuous_data(GFP_DMA), SST_MIN_BUFFER, SST_MAX_BUFFER); if (retval) { - pr_err("dma buffer allocationf fail\n"); + dev_err(rtd->dev, "dma buffer allocationf fail\n"); return retval; } } @@ -576,13 +580,11 @@ static int sst_platform_probe(struct platform_device *pdev) drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL); if (drv == NULL) { - pr_err("kzalloc failed\n"); return -ENOMEM; } pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); if (pdata == NULL) { - pr_err("kzalloc failed for pdata\n"); return -ENOMEM; } @@ -594,14 +596,14 @@ static int sst_platform_probe(struct platform_device *pdev) ret = snd_soc_register_platform(&pdev->dev, &sst_soc_platform_drv); if (ret) { - pr_err("registering soc platform failed\n"); + dev_err(&pdev->dev, "registering soc platform failed\n"); return ret; } ret = snd_soc_register_component(&pdev->dev, &sst_component, sst_platform_dai, ARRAY_SIZE(sst_platform_dai)); if (ret) { - pr_err("registering cpu dais failed\n"); + dev_err(&pdev->dev, "registering cpu dais failed\n"); snd_soc_unregister_platform(&pdev->dev); } return ret; @@ -612,7 +614,7 @@ static int sst_platform_remove(struct platform_device *pdev) snd_soc_unregister_component(&pdev->dev); snd_soc_unregister_platform(&pdev->dev); - pr_debug("sst_platform_remove success\n"); + dev_dbg(&pdev->dev, "sst_platform_remove success\n"); return 0; } From 0f519b622151339b7754d0406ddc40940063572a Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Sun, 7 Sep 2014 21:43:07 +0200 Subject: [PATCH 127/251] ALSA: pcm: snd_interval_step: drop the min parameter The min parameter was not used by any caller. And if it were used, underflows in the calculations could lead to incorrect results. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/core/pcm_lib.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 9acc77eae487..6fd5e1ce5462 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -1113,16 +1113,16 @@ int snd_interval_list(struct snd_interval *i, unsigned int count, EXPORT_SYMBOL(snd_interval_list); -static int snd_interval_step(struct snd_interval *i, unsigned int min, unsigned int step) +static int snd_interval_step(struct snd_interval *i, unsigned int step) { unsigned int n; int changed = 0; - n = (i->min - min) % step; + n = i->min % step; if (n != 0 || i->openmin) { i->min += step - n; changed = 1; } - n = (i->max - min) % step; + n = i->max % step; if (n != 0 || i->openmax) { i->max -= n; changed = 1; @@ -1427,7 +1427,7 @@ static int snd_pcm_hw_rule_step(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) { unsigned long step = (unsigned long) rule->private; - return snd_interval_step(hw_param_interval(params, rule->var), 0, step); + return snd_interval_step(hw_param_interval(params, rule->var), step); } /** From df1e471966479526ae64b64d8851a89db26b30bb Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Sun, 7 Sep 2014 21:43:41 +0200 Subject: [PATCH 128/251] ALSA: pcm: snd_interval_step: fix changes of open intervals Changing an interval boundary to a multiple of the step size makes that boundary exact. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/core/pcm_lib.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 6fd5e1ce5462..b03c7ae5f4e3 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -1120,11 +1120,13 @@ static int snd_interval_step(struct snd_interval *i, unsigned int step) n = i->min % step; if (n != 0 || i->openmin) { i->min += step - n; + i->openmin = 0; changed = 1; } n = i->max % step; if (n != 0 || i->openmax) { i->max -= n; + i->openmax = 0; changed = 1; } if (snd_interval_checkempty(i)) { From 49f4b4d15c7c9ff8efbb18d9f8c224d3682da573 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Sun, 7 Sep 2014 21:44:29 +0200 Subject: [PATCH 129/251] ALSA: usb-audio: add MIDI port names for the Yamaha MOTIF XF Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/usb/midi.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/sound/usb/midi.c b/sound/usb/midi.c index 7b166c2be0f7..69e93a9d486a 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c @@ -1506,6 +1506,12 @@ static struct port_info { PORT_INFO(vendor, product, num, name, 0, \ SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | \ SNDRV_SEQ_PORT_TYPE_HARDWARE) +#define GM_SYNTH_PORT(vendor, product, num, name, voices) \ + PORT_INFO(vendor, product, num, name, voices, \ + SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | \ + SNDRV_SEQ_PORT_TYPE_MIDI_GM | \ + SNDRV_SEQ_PORT_TYPE_HARDWARE | \ + SNDRV_SEQ_PORT_TYPE_SYNTHESIZER) #define ROLAND_SYNTH_PORT(vendor, product, num, name, voices) \ PORT_INFO(vendor, product, num, name, voices, \ SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | \ @@ -1525,6 +1531,11 @@ static struct port_info { SNDRV_SEQ_PORT_TYPE_MIDI_MT32 | \ SNDRV_SEQ_PORT_TYPE_HARDWARE | \ SNDRV_SEQ_PORT_TYPE_SYNTHESIZER) + /* Yamaha MOTIF XF */ + GM_SYNTH_PORT(0x0499, 0x105c, 0, "%s Tone Generator", 128), + CONTROL_PORT(0x0499, 0x105c, 1, "%s Remote Control"), + EXTERNAL_PORT(0x0499, 0x105c, 2, "%s Thru"), + CONTROL_PORT(0x0499, 0x105c, 3, "%s Editor"), /* Roland UA-100 */ CONTROL_PORT(0x0582, 0x0000, 2, "%s Control"), /* Roland SC-8850 */ From dd38dc1a9bf780b619ab93b3d7a5e90ebad441f5 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Sun, 7 Sep 2014 21:45:59 +0200 Subject: [PATCH 130/251] ALSA: virtuoso: add one more headphone impedance setting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add one more option to the "Headphones Impedance" control to synchronize with recent versions of the Windows driver. Tested-by: fugazzi® Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/pci/oxygen/xonar_pcm179x.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/sound/pci/oxygen/xonar_pcm179x.c b/sound/pci/oxygen/xonar_pcm179x.c index e02605931669..3c0a679c4539 100644 --- a/sound/pci/oxygen/xonar_pcm179x.c +++ b/sound/pci/oxygen/xonar_pcm179x.c @@ -795,11 +795,11 @@ static int st_output_switch_put(struct snd_kcontrol *ctl, static int st_hp_volume_offset_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) { - static const char *const names[3] = { - "< 64 ohms", "64-300 ohms", "300-600 ohms" + static const char *const names[4] = { + "< 32 ohms", "32-64 ohms", "64-300 ohms", "300-600 ohms" }; - return snd_ctl_enum_info(info, 1, 3, names); + return snd_ctl_enum_info(info, 1, 4, names); } static int st_hp_volume_offset_get(struct snd_kcontrol *ctl, @@ -809,12 +809,14 @@ static int st_hp_volume_offset_get(struct snd_kcontrol *ctl, struct xonar_pcm179x *data = chip->model_data; mutex_lock(&chip->mutex); - if (data->hp_gain_offset < 2*-6) + if (data->hp_gain_offset < 2*-12) value->value.enumerated.item[0] = 0; - else if (data->hp_gain_offset < 0) + else if (data->hp_gain_offset < 2*-6) value->value.enumerated.item[0] = 1; - else + else if (data->hp_gain_offset < 0) value->value.enumerated.item[0] = 2; + else + value->value.enumerated.item[0] = 3; mutex_unlock(&chip->mutex); return 0; } @@ -823,13 +825,13 @@ static int st_hp_volume_offset_get(struct snd_kcontrol *ctl, static int st_hp_volume_offset_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) { - static const s8 offsets[] = { 2*-18, 2*-6, 0 }; + static const s8 offsets[] = { 2*-18, 2*-12, 2*-6, 0 }; struct oxygen *chip = ctl->private_data; struct xonar_pcm179x *data = chip->model_data; s8 offset; int changed; - if (value->value.enumerated.item[0] > 2) + if (value->value.enumerated.item[0] > 3) return -EINVAL; offset = offsets[value->value.enumerated.item[0]]; mutex_lock(&chip->mutex); From d6cc58e127a0b7df78d869a29ff073da6fb899bb Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Sun, 7 Sep 2014 21:47:33 +0200 Subject: [PATCH 131/251] ALSA: virtuoso: add Xonar Essence STX II daughterboard support Detect and handle the H6 daughterboard; it works the same as with the ST, except that there is no conflict with the CS2000 chip. Tested-by: Andreas Allacher Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/pci/oxygen/xonar_pcm179x.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/sound/pci/oxygen/xonar_pcm179x.c b/sound/pci/oxygen/xonar_pcm179x.c index 3c0a679c4539..0d6a805e8b62 100644 --- a/sound/pci/oxygen/xonar_pcm179x.c +++ b/sound/pci/oxygen/xonar_pcm179x.c @@ -419,6 +419,7 @@ static void xonar_st_init_common(struct oxygen *chip) data->generic.output_enable_bit = GPIO_ST_OUTPUT_ENABLE; data->dacs = chip->model.dac_channels_mixer / 2; + data->h6 = chip->model.dac_channels_mixer > 2; data->hp_gain_offset = 2*-18; pcm1796_init(chip); @@ -1142,8 +1143,18 @@ int get_xonar_pcm179x_model(struct oxygen *chip, break; case 0x85f4: chip->model = model_xonar_st; - /* TODO: daughterboard support */ - chip->model.shortname = "Xonar STX II"; + oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_DB_MASK); + switch (oxygen_read16(chip, OXYGEN_GPIO_DATA) & GPIO_DB_MASK) { + default: + chip->model.shortname = "Xonar STX II"; + break; + case GPIO_DB_H6: + chip->model.shortname = "Xonar STX II+H6"; + chip->model.dac_channels_pcm = 8; + chip->model.dac_channels_mixer = 8; + chip->model.dac_mclks = OXYGEN_MCLKS(256, 128, 128); + break; + } chip->model.init = xonar_stx_init; chip->model.resume = xonar_stx_resume; chip->model.set_dac_params = set_pcm1796_params; From d4288d3fac18bbc31cb6d369679b1fa1d9321ae9 Mon Sep 17 00:00:00 2001 From: Jurgen Kramer Date: Fri, 5 Sep 2014 10:47:56 +0200 Subject: [PATCH 132/251] ALSA: pcm: add new DSD sampleformat for native DSD playback on XMOS based devices XMOS based USB DACs with native DSD support expose this feature via a USB alternate setting. The audio format is either 32-bit raw or a 32-bit PCM format. To utilize this feature on linux this patch introduces a new 32-bit DSD sampleformat DSD_U32_LE. A follow up patch will add a quirk for XMOS based devices to utilize the new format. Further patches will add support to alsa-lib. Signed-off-by: Jurgen Kramer Signed-off-by: Takashi Iwai --- include/sound/pcm.h | 1 + include/uapi/sound/asound.h | 3 ++- sound/core/pcm.c | 1 + sound/core/pcm_misc.c | 4 ++++ 4 files changed, 8 insertions(+), 1 deletion(-) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 67e0bdb9f0fa..e862497f7556 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -183,6 +183,7 @@ struct snd_pcm_ops { #define SNDRV_PCM_FMTBIT_G723_40_1B _SNDRV_PCM_FMTBIT(G723_40_1B) #define SNDRV_PCM_FMTBIT_DSD_U8 _SNDRV_PCM_FMTBIT(DSD_U8) #define SNDRV_PCM_FMTBIT_DSD_U16_LE _SNDRV_PCM_FMTBIT(DSD_U16_LE) +#define SNDRV_PCM_FMTBIT_DSD_U32_LE _SNDRV_PCM_FMTBIT(DSD_U32_LE) #ifdef SNDRV_LITTLE_ENDIAN #define SNDRV_PCM_FMTBIT_S16 SNDRV_PCM_FMTBIT_S16_LE diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h index 32168f7ffce3..6ee586728df9 100644 --- a/include/uapi/sound/asound.h +++ b/include/uapi/sound/asound.h @@ -219,7 +219,8 @@ typedef int __bitwise snd_pcm_format_t; #define SNDRV_PCM_FORMAT_G723_40_1B ((__force snd_pcm_format_t) 47) /* 1 sample in 1 byte */ #define SNDRV_PCM_FORMAT_DSD_U8 ((__force snd_pcm_format_t) 48) /* DSD, 1-byte samples DSD (x8) */ #define SNDRV_PCM_FORMAT_DSD_U16_LE ((__force snd_pcm_format_t) 49) /* DSD, 2-byte samples DSD (x16), little endian */ -#define SNDRV_PCM_FORMAT_LAST SNDRV_PCM_FORMAT_DSD_U16_LE +#define SNDRV_PCM_FORMAT_DSD_U32_LE ((__force snd_pcm_format_t) 50) /* DSD, 4-byte samples DSD (x32), little endian */ +#define SNDRV_PCM_FORMAT_LAST SNDRV_PCM_FORMAT_DSD_U32_LE #ifdef SNDRV_LITTLE_ENDIAN #define SNDRV_PCM_FORMAT_S16 SNDRV_PCM_FORMAT_S16_LE diff --git a/sound/core/pcm.c b/sound/core/pcm.c index afccdc553ef9..42ded997b223 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -215,6 +215,7 @@ static char *snd_pcm_format_names[] = { FORMAT(G723_40_1B), FORMAT(DSD_U8), FORMAT(DSD_U16_LE), + FORMAT(DSD_U32_LE), }; const char *snd_pcm_format_name(snd_pcm_format_t format) diff --git a/sound/core/pcm_misc.c b/sound/core/pcm_misc.c index 4560ca0e5651..83f54e1dbac9 100644 --- a/sound/core/pcm_misc.c +++ b/sound/core/pcm_misc.c @@ -148,6 +148,10 @@ static struct pcm_format_data pcm_formats[(INT)SNDRV_PCM_FORMAT_LAST+1] = { .width = 16, .phys = 16, .le = 1, .signd = 0, .silence = {}, }, + [SNDRV_PCM_FORMAT_DSD_U32_LE] = { + .width = 32, .phys = 32, .le = 1, .signd = 0, + .silence = { 0x69, 0x69, 0x69, 0x69 }, + }, /* FIXME: the following three formats are not defined properly yet */ [SNDRV_PCM_FORMAT_MPEG] = { .le = -1, .signd = -1, From 848f3a82df50fcc68a78c9d7d45e210b626b0283 Mon Sep 17 00:00:00 2001 From: Jurgen Kramer Date: Fri, 5 Sep 2014 18:14:46 +0200 Subject: [PATCH 133/251] ALSA: usb-audio: add native DSD support for XMOS based DACs Add quirks for XMOS based DACs for native DSD playback support using the new DSD_U32_LE sample format. This version adds native DSD support for: - iFi Audio micro iDSD/nano iDSD (they use the same prod. id) - DIYINHK USB to I2S/DSD converter Changes from v2: - fix and simplify switch statement Changes from v1: - use specific product id and alt setting per XMOS based device [fixed a misc coding style issue by tiwai] Signed-off-by: Jurgen Kramer Signed-off-by: Takashi Iwai --- sound/usb/quirks.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 19a921eb75f1..d2aa45a8d895 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -1174,5 +1174,21 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip, } } + /* XMOS based USB DACs */ + switch (chip->usb_id) { + /* iFi Audio micro/nano iDSD */ + case USB_ID(0x20b1, 0x3008): + if (fp->altsetting == 2) + return SNDRV_PCM_FMTBIT_DSD_U32_LE; + break; + /* DIYINHK DSD DXD 384kHz USB to I2S/DSD */ + case USB_ID(0x20b1, 0x2009): + if (fp->altsetting == 3) + return SNDRV_PCM_FMTBIT_DSD_U32_LE; + break; + default: + break; + } + return 0; } From e7e69265b6269763799a5de9c263fbbce32cd3a3 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Mon, 8 Sep 2014 22:48:03 +0530 Subject: [PATCH 134/251] sound: pci: au88x0: printk replacement as pr_* macros are more preffered over printk, so printk replaced with corresponding pr_* macros. this patch will generate warning from checkpatch as it only did printk replacement and didnot fixed other style issues. Signed-off-by: Sudip Mukherjee Signed-off-by: Takashi Iwai --- sound/pci/au88x0/au88x0.c | 22 ++++----- sound/pci/au88x0/au88x0_a3d.c | 10 ++--- sound/pci/au88x0/au88x0_core.c | 76 ++++++++++++++++---------------- sound/pci/au88x0/au88x0_eq.c | 2 +- sound/pci/au88x0/au88x0_game.c | 2 +- sound/pci/au88x0/au88x0_mpu401.c | 2 +- sound/pci/au88x0/au88x0_pcm.c | 8 ++-- sound/pci/au88x0/au88x0_synth.c | 26 +++++------ 8 files changed, 74 insertions(+), 74 deletions(-) diff --git a/sound/pci/au88x0/au88x0.c b/sound/pci/au88x0/au88x0.c index afb1b44b741e..21ce31f636bc 100644 --- a/sound/pci/au88x0/au88x0.c +++ b/sound/pci/au88x0/au88x0.c @@ -48,10 +48,10 @@ static void vortex_fix_latency(struct pci_dev *vortex) { int rc; if (!(rc = pci_write_config_byte(vortex, 0x40, 0xff))) { - printk(KERN_INFO CARD_NAME + pr_info( CARD_NAME ": vortex latency is 0xff\n"); } else { - printk(KERN_WARNING CARD_NAME + pr_warn( CARD_NAME ": could not set vortex latency: pci error 0x%x\n", rc); } } @@ -70,10 +70,10 @@ static void vortex_fix_agp_bridge(struct pci_dev *via) if (!(rc = pci_read_config_byte(via, 0x42, &value)) && ((value & 0x10) || !(rc = pci_write_config_byte(via, 0x42, value | 0x10)))) { - printk(KERN_INFO CARD_NAME + pr_info( CARD_NAME ": bridge config is 0x%x\n", value | 0x10); } else { - printk(KERN_WARNING CARD_NAME + pr_warn( CARD_NAME ": could not set vortex latency: pci error 0x%x\n", rc); } } @@ -97,7 +97,7 @@ static void snd_vortex_workaround(struct pci_dev *vortex, int fix) PCI_DEVICE_ID_AMD_FE_GATE_7007, NULL); } if (via) { - printk(KERN_INFO CARD_NAME ": Activating latency workaround...\n"); + pr_info( CARD_NAME ": Activating latency workaround...\n"); vortex_fix_latency(vortex); vortex_fix_agp_bridge(via); } @@ -153,7 +153,7 @@ snd_vortex_create(struct snd_card *card, struct pci_dev *pci, vortex_t ** rchip) return err; if (pci_set_dma_mask(pci, DMA_BIT_MASK(32)) < 0 || pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(32)) < 0) { - printk(KERN_ERR "error to set DMA mask\n"); + pr_err( "error to set DMA mask\n"); pci_disable_device(pci); return -ENXIO; } @@ -182,7 +182,7 @@ snd_vortex_create(struct snd_card *card, struct pci_dev *pci, vortex_t ** rchip) chip->mmio = pci_ioremap_bar(pci, 0); if (!chip->mmio) { - printk(KERN_ERR "MMIO area remap failed.\n"); + pr_err( "MMIO area remap failed.\n"); err = -ENOMEM; goto ioremap_out; } @@ -191,14 +191,14 @@ snd_vortex_create(struct snd_card *card, struct pci_dev *pci, vortex_t ** rchip) * This must be done before we do request_irq otherwise we can get spurious * interrupts that we do not handle properly and make a mess of things */ if ((err = vortex_core_init(chip)) != 0) { - printk(KERN_ERR "hw core init failed\n"); + pr_err( "hw core init failed\n"); goto core_out; } if ((err = request_irq(pci->irq, vortex_interrupt, IRQF_SHARED, KBUILD_MODNAME, chip)) != 0) { - printk(KERN_ERR "cannot grab irq\n"); + pr_err( "cannot grab irq\n"); goto irq_out; } chip->irq = pci->irq; @@ -342,10 +342,10 @@ snd_vortex_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) chip->rev = pci->revision; #ifdef CHIP_AU8830 if ((chip->rev) != 0xfe && (chip->rev) != 0xfa) { - printk(KERN_ALERT + pr_alert( "vortex: The revision (%x) of your card has not been seen before.\n", chip->rev); - printk(KERN_ALERT + pr_alert( "vortex: Please email the results of 'lspci -vv' to openvortex-dev@nongnu.org.\n"); snd_card_free(card); err = -ENODEV; diff --git a/sound/pci/au88x0/au88x0_a3d.c b/sound/pci/au88x0/au88x0_a3d.c index aad831acbb17..30f760e3d2c0 100644 --- a/sound/pci/au88x0/au88x0_a3d.c +++ b/sound/pci/au88x0/au88x0_a3d.c @@ -463,7 +463,7 @@ static void a3dsrc_ZeroSliceIO(a3dsrc_t * a) static void a3dsrc_ZeroState(a3dsrc_t * a) { /* - printk(KERN_DEBUG "vortex: ZeroState slice: %d, source %d\n", + pr_debug( "vortex: ZeroState slice: %d, source %d\n", a->slice, a->source); */ a3dsrc_SetAtmosState(a, 0, 0, 0, 0); @@ -489,7 +489,7 @@ static void a3dsrc_ZeroStateA3D(a3dsrc_t * a) int i, var, var2; if ((a->vortex) == NULL) { - printk(KERN_ERR "vortex: ZeroStateA3D: ERROR: a->vortex is NULL\n"); + pr_err( "vortex: ZeroStateA3D: ERROR: a->vortex is NULL\n"); return; } @@ -628,14 +628,14 @@ static void vortex_Vort3D_connect(vortex_t * v, int en) v->mixxtlk[0] = vortex_adb_checkinout(v, v->fixed_res, en, VORTEX_RESOURCE_MIXIN); if (v->mixxtlk[0] < 0) { - printk + pr_warn ("vortex: vortex_Vort3D: ERROR: not enough free mixer resources.\n"); return; } v->mixxtlk[1] = vortex_adb_checkinout(v, v->fixed_res, en, VORTEX_RESOURCE_MIXIN); if (v->mixxtlk[1] < 0) { - printk + pr_warn ("vortex: vortex_Vort3D: ERROR: not enough free mixer resources.\n"); return; } @@ -679,7 +679,7 @@ static void vortex_Vort3D_connect(vortex_t * v, int en) static void vortex_Vort3D_InitializeSource(a3dsrc_t * a, int en) { if (a->vortex == NULL) { - printk + pr_warn ("vortex: Vort3D_InitializeSource: A3D source not initialized\n"); return; } diff --git a/sound/pci/au88x0/au88x0_core.c b/sound/pci/au88x0/au88x0_core.c index ae59dbaa53d9..72e81286b70e 100644 --- a/sound/pci/au88x0/au88x0_core.c +++ b/sound/pci/au88x0/au88x0_core.c @@ -285,7 +285,7 @@ vortex_mixer_addWTD(vortex_t * vortex, unsigned char mix, unsigned char ch) temp = hwread(vortex->mmio, prev); //printk(KERN_INFO "vortex: mixAddWTD: while addr=%x, val=%x\n", prev, temp); if ((++lifeboat) > 0xf) { - printk(KERN_ERR + pr_err( "vortex_mixer_addWTD: lifeboat overflow\n"); return 0; } @@ -303,7 +303,7 @@ vortex_mixer_delWTD(vortex_t * vortex, unsigned char mix, unsigned char ch) eax = hwread(vortex->mmio, VORTEX_MIXER_SR); if (((1 << ch) & eax) == 0) { - printk(KERN_ERR "mix ALARM %x\n", eax); + pr_err( "mix ALARM %x\n", eax); return 0; } ebp = VORTEX_MIXER_CHNBASE + (ch << 2); @@ -324,7 +324,7 @@ vortex_mixer_delWTD(vortex_t * vortex, unsigned char mix, unsigned char ch) //printk(KERN_INFO "vortex: mixdelWTD: 1 addr=%x, val=%x, src=%x\n", ebx, edx, src); while ((edx & 0xf) != mix) { if ((esi) > 0xf) { - printk(KERN_ERR + pr_err( "vortex: mixdelWTD: error lifeboat overflow\n"); return 0; } @@ -492,7 +492,7 @@ vortex_src_persist_convratio(vortex_t * vortex, unsigned char src, int ratio) hwwrite(vortex->mmio, VORTEX_SRC_CONVRATIO + (src << 2), ratio); temp = hwread(vortex->mmio, VORTEX_SRC_CONVRATIO + (src << 2)); if ((++lifeboat) > 0x9) { - printk(KERN_ERR "Vortex: Src cvr fail\n"); + pr_err( "Vortex: Src cvr fail\n"); break; } } @@ -545,7 +545,7 @@ vortex_src_checkratio(vortex_t * vortex, unsigned char src, hwwrite(vortex->mmio, VORTEX_SRC_CONVRATIO + (src << 2), desired_ratio); if ((lifeboat++) > 15) { - printk(KERN_ERR "Vortex: could not set src-%d from %d to %d\n", + pr_err( "Vortex: could not set src-%d from %d to %d\n", src, hw_ratio, desired_ratio); break; } @@ -684,7 +684,7 @@ vortex_src_addWTD(vortex_t * vortex, unsigned char src, unsigned char ch) temp = hwread(vortex->mmio, prev); //printk(KERN_INFO "vortex: srcAddWTD: while addr=%x, val=%x\n", prev, temp); if ((++lifeboat) > 0xf) { - printk(KERN_ERR + pr_err( "vortex_src_addWTD: lifeboat overflow\n"); return 0; } @@ -703,7 +703,7 @@ vortex_src_delWTD(vortex_t * vortex, unsigned char src, unsigned char ch) eax = hwread(vortex->mmio, VORTEX_SRCBLOCK_SR); if (((1 << ch) & eax) == 0) { - printk(KERN_ERR "src alarm\n"); + pr_err( "src alarm\n"); return 0; } ebp = VORTEX_SRC_CHNBASE + (ch << 2); @@ -724,7 +724,7 @@ vortex_src_delWTD(vortex_t * vortex, unsigned char src, unsigned char ch) //printk(KERN_INFO "vortex: srcdelWTD: 1 addr=%x, val=%x, src=%x\n", ebx, edx, src); while ((edx & 0xf) != src) { if ((esi) > 0xf) { - printk + pr_warn ("vortex: srcdelWTD: error, lifeboat overflow\n"); return 0; } @@ -819,7 +819,7 @@ vortex_fifo_setadbctrl(vortex_t * vortex, int fifo, int stereo, int priority, do { temp = hwread(vortex->mmio, VORTEX_FIFO_ADBCTRL + (fifo << 2)); if (lifeboat++ > 0xbb8) { - printk(KERN_ERR + pr_err( "Vortex: vortex_fifo_setadbctrl fail\n"); break; } @@ -915,7 +915,7 @@ vortex_fifo_setwtctrl(vortex_t * vortex, int fifo, int ctrl, int priority, do { temp = hwread(vortex->mmio, VORTEX_FIFO_WTCTRL + (fifo << 2)); if (lifeboat++ > 0xbb8) { - printk(KERN_ERR "Vortex: vortex_fifo_setwtctrl fail\n"); + pr_err( "Vortex: vortex_fifo_setwtctrl fail\n"); break; } } @@ -970,7 +970,7 @@ vortex_fifo_setwtctrl(vortex_t * vortex, int fifo, int ctrl, int priority, do { temp = hwread(vortex->mmio, VORTEX_FIFO_WTCTRL + (fifo << 2)); if (lifeboat++ > 0xbb8) { - printk(KERN_ERR "Vortex: vortex_fifo_setwtctrl fail (hanging)\n"); + pr_err( "Vortex: vortex_fifo_setwtctrl fail (hanging)\n"); break; } } while ((temp & FIFO_RDONLY)&&(temp & FIFO_VALID)&&(temp != 0xFFFFFFFF)); @@ -1042,7 +1042,7 @@ static void vortex_fifo_init(vortex_t * vortex) for (x = NR_ADB - 1; x >= 0; x--) { hwwrite(vortex->mmio, addr, (FIFO_U0 | FIFO_U1)); if (hwread(vortex->mmio, addr) != (FIFO_U0 | FIFO_U1)) - printk(KERN_ERR "bad adb fifo reset!"); + pr_err( "bad adb fifo reset!"); vortex_fifo_clearadbdata(vortex, x, FIFO_SIZE); addr -= 4; } @@ -1053,7 +1053,7 @@ static void vortex_fifo_init(vortex_t * vortex) for (x = NR_WT - 1; x >= 0; x--) { hwwrite(vortex->mmio, addr, FIFO_U0); if (hwread(vortex->mmio, addr) != FIFO_U0) - printk(KERN_ERR + pr_err( "bad wt fifo reset (0x%08x, 0x%08x)!\n", addr, hwread(vortex->mmio, addr)); vortex_fifo_clearwtdata(vortex, x, FIFO_SIZE); @@ -1136,7 +1136,7 @@ vortex_adbdma_setbuffers(vortex_t * vortex, int adbdma, break; } /* - printk(KERN_DEBUG "vortex: cfg0 = 0x%x\nvortex: cfg1=0x%x\n", + pr_debug( "vortex: cfg0 = 0x%x\nvortex: cfg1=0x%x\n", dma->cfg0, dma->cfg1); */ hwwrite(vortex->mmio, VORTEX_ADBDMA_BUFCFG0 + (adbdma << 3), dma->cfg0); @@ -1213,7 +1213,7 @@ static int vortex_adbdma_bufshift(vortex_t * vortex, int adbdma) if (dma->period_virt >= dma->nr_periods) dma->period_virt -= dma->nr_periods; if (delta != 1) - printk(KERN_INFO "vortex: %d virt=%d, real=%d, delta=%d\n", + pr_info( "vortex: %d virt=%d, real=%d, delta=%d\n", adbdma, dma->period_virt, dma->period_real, delta); return delta; @@ -1482,7 +1482,7 @@ static int vortex_wtdma_bufshift(vortex_t * vortex, int wtdma) dma->period_real = page; if (delta != 1) - printk(KERN_WARNING "vortex: wt virt = %d, delta = %d\n", + pr_warn( "vortex: wt virt = %d, delta = %d\n", dma->period_virt, delta); return delta; @@ -1667,7 +1667,7 @@ vortex_adb_addroutes(vortex_t * vortex, unsigned char channel, hwread(vortex->mmio, VORTEX_ADB_RTBASE + (temp << 2)) & ADB_MASK; if ((lifeboat++) > ADB_MASK) { - printk(KERN_ERR + pr_err( "vortex_adb_addroutes: unending route! 0x%x\n", *route); return; @@ -1703,7 +1703,7 @@ vortex_adb_delroutes(vortex_t * vortex, unsigned char channel, hwread(vortex->mmio, VORTEX_ADB_RTBASE + (prev << 2)) & ADB_MASK; if (((lifeboat++) > ADB_MASK) || (temp == ADB_MASK)) { - printk(KERN_ERR + pr_err( "vortex_adb_delroutes: route not found! 0x%x\n", route0); return; @@ -1967,7 +1967,7 @@ vortex_connect_codecplay(vortex_t * vortex, int en, unsigned char mixers[]) ADB_CODECOUT(0 + 4)); vortex_connection_mix_adb(vortex, en, 0x11, mixers[3], ADB_CODECOUT(1 + 4)); - /* printk(KERN_DEBUG "SDAC detected "); */ + /* pr_debug( "SDAC detected "); */ } #else // Use plain direct output to codec. @@ -2022,7 +2022,7 @@ vortex_adb_checkinout(vortex_t * vortex, int resmap[], int out, int restype) else vortex->dma_adb[i].resources[restype] |= (1 << i); /* - printk(KERN_DEBUG + pr_debug( "vortex: ResManager: type %d out %d\n", restype, i); */ @@ -2037,7 +2037,7 @@ vortex_adb_checkinout(vortex_t * vortex, int resmap[], int out, int restype) if (resmap[restype] & (1 << i)) { resmap[restype] &= ~(1 << i); /* - printk(KERN_DEBUG + pr_debug( "vortex: ResManager: type %d in %d\n", restype, i); */ @@ -2045,7 +2045,7 @@ vortex_adb_checkinout(vortex_t * vortex, int resmap[], int out, int restype) } } } - printk(KERN_ERR "vortex: FATAL: ResManager: resource type %d exhausted.\n", restype); + pr_err( "vortex: FATAL: ResManager: resource type %d exhausted.\n", restype); return -ENOMEM; } @@ -2173,7 +2173,7 @@ vortex_adb_allocroute(vortex_t *vortex, int dma, int nr_ch, int dir, memset(stream->resources, 0, sizeof(unsigned char) * VORTEX_RESOURCE_LAST); - printk(KERN_ERR "vortex: out of A3D sources. Sorry\n"); + pr_err( "vortex: out of A3D sources. Sorry\n"); return -EBUSY; } /* (De)Initialize A3D hardware source. */ @@ -2421,7 +2421,7 @@ static irqreturn_t vortex_interrupt(int irq, void *dev_id) hwread(vortex->mmio, VORTEX_IRQ_SOURCE); // Is at least one IRQ flag set? if (source == 0) { - printk(KERN_ERR "vortex: missing irq source\n"); + pr_err( "vortex: missing irq source\n"); return IRQ_NONE; } @@ -2429,19 +2429,19 @@ static irqreturn_t vortex_interrupt(int irq, void *dev_id) // Attend every interrupt source. if (unlikely(source & IRQ_ERR_MASK)) { if (source & IRQ_FATAL) { - printk(KERN_ERR "vortex: IRQ fatal error\n"); + pr_err( "vortex: IRQ fatal error\n"); } if (source & IRQ_PARITY) { - printk(KERN_ERR "vortex: IRQ parity error\n"); + pr_err( "vortex: IRQ parity error\n"); } if (source & IRQ_REG) { - printk(KERN_ERR "vortex: IRQ reg error\n"); + pr_err( "vortex: IRQ reg error\n"); } if (source & IRQ_FIFO) { - printk(KERN_ERR "vortex: IRQ fifo error\n"); + pr_err( "vortex: IRQ fifo error\n"); } if (source & IRQ_DMA) { - printk(KERN_ERR "vortex: IRQ dma error\n"); + pr_err( "vortex: IRQ dma error\n"); } handled = 1; } @@ -2489,7 +2489,7 @@ static irqreturn_t vortex_interrupt(int irq, void *dev_id) } if (!handled) { - printk(KERN_ERR "vortex: unknown irq source %x\n", source); + pr_err( "vortex: unknown irq source %x\n", source); } return IRQ_RETVAL(handled); } @@ -2546,7 +2546,7 @@ vortex_codec_write(struct snd_ac97 * codec, unsigned short addr, unsigned short while (!(hwread(card->mmio, VORTEX_CODEC_CTRL) & 0x100)) { udelay(100); if (lifeboat++ > POLL_COUNT) { - printk(KERN_ERR "vortex: ac97 codec stuck busy\n"); + pr_err( "vortex: ac97 codec stuck busy\n"); return; } } @@ -2572,7 +2572,7 @@ static unsigned short vortex_codec_read(struct snd_ac97 * codec, unsigned short while (!(hwread(card->mmio, VORTEX_CODEC_CTRL) & 0x100)) { udelay(100); if (lifeboat++ > POLL_COUNT) { - printk(KERN_ERR "vortex: ac97 codec stuck busy\n"); + pr_err( "vortex: ac97 codec stuck busy\n"); return 0xffff; } } @@ -2586,7 +2586,7 @@ static unsigned short vortex_codec_read(struct snd_ac97 * codec, unsigned short udelay(100); data = hwread(card->mmio, VORTEX_CODEC_IO); if (lifeboat++ > POLL_COUNT) { - printk(KERN_ERR "vortex: ac97 address never arrived\n"); + pr_err( "vortex: ac97 address never arrived\n"); return 0xffff; } } while ((data & VORTEX_CODEC_ADDMASK) != @@ -2683,7 +2683,7 @@ static void vortex_spdif_init(vortex_t * vortex, int spdif_sr, int spdif_mode) static int vortex_core_init(vortex_t *vortex) { - printk(KERN_INFO "Vortex: init.... "); + pr_info( "Vortex: init.... "); /* Hardware Init. */ hwwrite(vortex->mmio, VORTEX_CTRL, 0xffffffff); msleep(5); @@ -2728,7 +2728,7 @@ static int vortex_core_init(vortex_t *vortex) //vortex_enable_timer_int(vortex); //vortex_disable_timer_int(vortex); - printk(KERN_INFO "done.\n"); + pr_info( "done.\n"); spin_lock_init(&vortex->lock); return 0; @@ -2737,7 +2737,7 @@ static int vortex_core_init(vortex_t *vortex) static int vortex_core_shutdown(vortex_t * vortex) { - printk(KERN_INFO "Vortex: shutdown..."); + pr_info( "Vortex: shutdown..."); #ifndef CHIP_AU8820 vortex_eq_free(vortex); vortex_Vort3D_disable(vortex); @@ -2759,7 +2759,7 @@ static int vortex_core_shutdown(vortex_t * vortex) msleep(5); hwwrite(vortex->mmio, VORTEX_IRQ_SOURCE, 0xffff); - printk(KERN_INFO "done.\n"); + pr_info( "done.\n"); return 0; } @@ -2793,7 +2793,7 @@ static int vortex_alsafmt_aspfmt(int alsafmt) break; default: fmt = 0x8; - printk(KERN_ERR "vortex: format unsupported %d\n", alsafmt); + pr_err( "vortex: format unsupported %d\n", alsafmt); break; } return fmt; diff --git a/sound/pci/au88x0/au88x0_eq.c b/sound/pci/au88x0/au88x0_eq.c index e7220533ecfc..9404ba73eaf6 100644 --- a/sound/pci/au88x0/au88x0_eq.c +++ b/sound/pci/au88x0/au88x0_eq.c @@ -845,7 +845,7 @@ snd_vortex_peaks_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *u vortex_Eqlzr_GetAllPeaks(vortex, peaks, &count); if (count != 20) { - printk(KERN_ERR "vortex: peak count error 20 != %d \n", count); + pr_err( "vortex: peak count error 20 != %d \n", count); return -1; } for (i = 0; i < 20; i++) diff --git a/sound/pci/au88x0/au88x0_game.c b/sound/pci/au88x0/au88x0_game.c index 280f86de2230..72daf6cf8169 100644 --- a/sound/pci/au88x0/au88x0_game.c +++ b/sound/pci/au88x0/au88x0_game.c @@ -98,7 +98,7 @@ static int vortex_gameport_register(vortex_t *vortex) vortex->gameport = gp = gameport_allocate_port(); if (!gp) { - printk(KERN_ERR "vortex: cannot allocate memory for gameport\n"); + pr_err( "vortex: cannot allocate memory for gameport\n"); return -ENOMEM; } diff --git a/sound/pci/au88x0/au88x0_mpu401.c b/sound/pci/au88x0/au88x0_mpu401.c index 29e5945eef60..328c1943c0c3 100644 --- a/sound/pci/au88x0/au88x0_mpu401.c +++ b/sound/pci/au88x0/au88x0_mpu401.c @@ -73,7 +73,7 @@ static int snd_vortex_midi(vortex_t *vortex) /* Check if anything is OK. */ temp = hwread(vortex->mmio, VORTEX_MIDI_DATA); if (temp != MPU401_ACK /*0xfe */ ) { - printk(KERN_ERR "midi port doesn't acknowledge!\n"); + pr_err( "midi port doesn't acknowledge!\n"); return -ENODEV; } /* Enable MPU401 interrupts. */ diff --git a/sound/pci/au88x0/au88x0_pcm.c b/sound/pci/au88x0/au88x0_pcm.c index 9fb03b4ea925..5adc6b92ffab 100644 --- a/sound/pci/au88x0/au88x0_pcm.c +++ b/sound/pci/au88x0/au88x0_pcm.c @@ -227,11 +227,11 @@ snd_vortex_pcm_hw_params(struct snd_pcm_substream *substream, err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); if (err < 0) { - printk(KERN_ERR "Vortex: pcm page alloc failed!\n"); + pr_err( "Vortex: pcm page alloc failed!\n"); return err; } /* - printk(KERN_INFO "Vortex: periods %d, period_bytes %d, channels = %d\n", params_periods(hw_params), + pr_info( "Vortex: periods %d, period_bytes %d, channels = %d\n", params_periods(hw_params), params_period_bytes(hw_params), params_channels(hw_params)); */ spin_lock_irq(&chip->lock); @@ -371,7 +371,7 @@ static int snd_vortex_pcm_trigger(struct snd_pcm_substream *substream, int cmd) } #ifndef CHIP_AU8810 else { - printk(KERN_INFO "vortex: wt start %d\n", dma); + pr_info( "vortex: wt start %d\n", dma); vortex_wtdma_startfifo(chip, dma); } #endif @@ -384,7 +384,7 @@ static int snd_vortex_pcm_trigger(struct snd_pcm_substream *substream, int cmd) vortex_adbdma_stopfifo(chip, dma); #ifndef CHIP_AU8810 else { - printk(KERN_INFO "vortex: wt stop %d\n", dma); + pr_info( "vortex: wt stop %d\n", dma); vortex_wtdma_stopfifo(chip, dma); } #endif diff --git a/sound/pci/au88x0/au88x0_synth.c b/sound/pci/au88x0/au88x0_synth.c index 922a84bba2ef..f094bac24291 100644 --- a/sound/pci/au88x0/au88x0_synth.c +++ b/sound/pci/au88x0/au88x0_synth.c @@ -90,7 +90,7 @@ static int vortex_wt_allocroute(vortex_t * vortex, int wt, int nr_ch) hwwrite(vortex->mmio, WT_PARM(wt, 2), 0); temp = hwread(vortex->mmio, WT_PARM(wt, 3)); - printk(KERN_DEBUG "vortex: WT PARM3: %x\n", temp); + pr_debug( "vortex: WT PARM3: %x\n", temp); //hwwrite(vortex->mmio, WT_PARM(wt, 3), temp); hwwrite(vortex->mmio, WT_DELAY(wt, 0), 0); @@ -98,7 +98,7 @@ static int vortex_wt_allocroute(vortex_t * vortex, int wt, int nr_ch) hwwrite(vortex->mmio, WT_DELAY(wt, 2), 0); hwwrite(vortex->mmio, WT_DELAY(wt, 3), 0); - printk(KERN_DEBUG "vortex: WT GMODE: %x\n", hwread(vortex->mmio, WT_GMODE(wt))); + pr_debug( "vortex: WT GMODE: %x\n", hwread(vortex->mmio, WT_GMODE(wt))); hwwrite(vortex->mmio, WT_PARM(wt, 2), 0xffffffff); hwwrite(vortex->mmio, WT_PARM(wt, 3), 0xcff1c810); @@ -106,7 +106,7 @@ static int vortex_wt_allocroute(vortex_t * vortex, int wt, int nr_ch) voice->parm0 = voice->parm1 = 0xcfb23e2f; hwwrite(vortex->mmio, WT_PARM(wt, 0), voice->parm0); hwwrite(vortex->mmio, WT_PARM(wt, 1), voice->parm1); - printk(KERN_DEBUG "vortex: WT GMODE 2 : %x\n", hwread(vortex->mmio, WT_GMODE(wt))); + pr_debug( "vortex: WT GMODE 2 : %x\n", hwread(vortex->mmio, WT_GMODE(wt))); return 0; } @@ -196,14 +196,14 @@ vortex_wt_SetReg(vortex_t * vortex, unsigned char reg, int wt, if ((reg == 5) || ((reg >= 7) && (reg <= 10)) || (reg == 0xc)) { if (wt >= (NR_WT / NR_WT_PB)) { - printk + pr_warn ("vortex: WT SetReg: bank out of range. reg=0x%x, wt=%d\n", reg, wt); return 0; } } else { if (wt >= NR_WT) { - printk(KERN_ERR "vortex: WT SetReg: voice out of range\n"); + pr_err( "vortex: WT SetReg: voice out of range\n"); return 0; } } @@ -214,42 +214,42 @@ vortex_wt_SetReg(vortex_t * vortex, unsigned char reg, int wt, /* Voice specific parameters */ case 0: /* running */ /* - printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n", + pr_debug( "vortex: WT SetReg(0x%x) = 0x%08x\n", WT_RUN(wt), (int)val); */ hwwrite(vortex->mmio, WT_RUN(wt), val); return 0xc; case 1: /* param 0 */ /* - printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n", + pr_debug( "vortex: WT SetReg(0x%x) = 0x%08x\n", WT_PARM(wt,0), (int)val); */ hwwrite(vortex->mmio, WT_PARM(wt, 0), val); return 0xc; case 2: /* param 1 */ /* - printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n", + pr_debug( "vortex: WT SetReg(0x%x) = 0x%08x\n", WT_PARM(wt,1), (int)val); */ hwwrite(vortex->mmio, WT_PARM(wt, 1), val); return 0xc; case 3: /* param 2 */ /* - printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n", + pr_debug( "vortex: WT SetReg(0x%x) = 0x%08x\n", WT_PARM(wt,2), (int)val); */ hwwrite(vortex->mmio, WT_PARM(wt, 2), val); return 0xc; case 4: /* param 3 */ /* - printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n", + pr_debug( "vortex: WT SetReg(0x%x) = 0x%08x\n", WT_PARM(wt,3), (int)val); */ hwwrite(vortex->mmio, WT_PARM(wt, 3), val); return 0xc; case 6: /* mute */ /* - printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n", + pr_debug( "vortex: WT SetReg(0x%x) = 0x%08x\n", WT_MUTE(wt), (int)val); */ hwwrite(vortex->mmio, WT_MUTE(wt), val); @@ -257,7 +257,7 @@ vortex_wt_SetReg(vortex_t * vortex, unsigned char reg, int wt, case 0xb: /* delay */ /* - printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n", + pr_debug( "vortex: WT SetReg(0x%x) = 0x%08x\n", WT_DELAY(wt,0), (int)val); */ hwwrite(vortex->mmio, WT_DELAY(wt, 3), val); @@ -285,7 +285,7 @@ vortex_wt_SetReg(vortex_t * vortex, unsigned char reg, int wt, return 0; } /* - printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n", ecx, (int)val); + pr_debug( "vortex: WT SetReg(0x%x) = 0x%08x\n", ecx, (int)val); */ hwwrite(vortex->mmio, ecx, val); return 1; From 2080437d375f4d8ba2fe37254199427f3f5e7bc2 Mon Sep 17 00:00:00 2001 From: Xiubo Li Date: Wed, 3 Sep 2014 10:23:39 +0800 Subject: [PATCH 135/251] ASoC: simple-card: Merge single and muti DAI link(s) code. This patch will split the DT node into old style and new style: The new style will merge the single DAI link and muti DAI links code together, the new style will be easier to add muti DAI links from old single DAI link DTs. This patch will maintian compatibility with the old DTs. Signed-off-by: Xiubo Li Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index b63860ddb4fd..e0abe772c040 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -185,6 +185,7 @@ static int asoc_simple_card_dai_link_of(struct device_node *node, char *prefix = ""; int ret, cpu_args; + /* For single DAI link & old style of DT node */ if (is_top_level_node) prefix = "simple-audio-card,"; @@ -318,14 +319,16 @@ dai_link_of_err: static int asoc_simple_card_parse_of(struct device_node *node, struct simple_card_data *priv, - struct device *dev, - int multi) + struct device *dev) { struct snd_soc_dai_link *dai_link = priv->snd_card.dai_link; struct simple_dai_props *dai_props = priv->dai_props; u32 val; int ret; + if (!node) + return -EINVAL; + /* parsing the card name from DT */ snd_soc_of_parse_card_name(&priv->snd_card, "simple-audio-card,name"); @@ -353,7 +356,8 @@ static int asoc_simple_card_parse_of(struct device_node *node, dev_dbg(dev, "New simple-card: %s\n", priv->snd_card.name ? priv->snd_card.name : ""); - if (multi) { + /* Single/Muti DAI link(s) & New style of DT node */ + if (of_get_child_by_name(node, "simple-audio-card,dai-link")) { struct device_node *np = NULL; int i = 0; @@ -370,6 +374,7 @@ static int asoc_simple_card_parse_of(struct device_node *node, i++; } } else { + /* For single DAI link & old style of DT node */ ret = asoc_simple_card_dai_link_of(node, dev, dai_link, dai_props, true); if (ret < 0) @@ -409,16 +414,13 @@ static int asoc_simple_card_probe(struct platform_device *pdev) struct snd_soc_dai_link *dai_link; struct device_node *np = pdev->dev.of_node; struct device *dev = &pdev->dev; - int num_links, multi, ret; + int num_links, ret; /* get the number of DAI links */ - if (np && of_get_child_by_name(np, "simple-audio-card,dai-link")) { + if (np && of_get_child_by_name(np, "simple-audio-card,dai-link")) num_links = of_get_child_count(np); - multi = 1; - } else { + else num_links = 1; - multi = 0; - } /* allocate the private data and the DAI link array */ priv = devm_kzalloc(dev, @@ -445,7 +447,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev) if (np && of_device_is_available(np)) { - ret = asoc_simple_card_parse_of(np, priv, dev, multi); + ret = asoc_simple_card_parse_of(np, priv, dev); if (ret < 0) { if (ret != -EPROBE_DEFER) dev_err(dev, "parse error %d\n", ret); From 417c60e8f248a84e8e768c55d191689d1e27e05f Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 9 Sep 2014 20:42:40 +0200 Subject: [PATCH 136/251] ASoC: cs42l52: Cleanup manual bias level transitions Set the CODEC driver's suspend_bias_off flag rather than manually going to SND_SOC_BIAS_OFF in suspend and SND_SOC_BIAS_STANDBY in resume. This makes the code a bit shorter and cleaner. Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. The manual transition to SND_SOC_BIAS_STANDBY at the end of CODEC probe() can also be removed as the core will automatically do this after the CODEC has been probed. Signed-off-by: Lars-Peter Clausen Acked-by: Brian Austin Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l52.c | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c index 969167d8b71e..6efff7183b22 100644 --- a/sound/soc/codecs/cs42l52.c +++ b/sound/soc/codecs/cs42l52.c @@ -946,20 +946,6 @@ static struct snd_soc_dai_driver cs42l52_dai = { .ops = &cs42l52_ops, }; -static int cs42l52_suspend(struct snd_soc_codec *codec) -{ - cs42l52_set_bias_level(codec, SND_SOC_BIAS_OFF); - - return 0; -} - -static int cs42l52_resume(struct snd_soc_codec *codec) -{ - cs42l52_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - return 0; -} - static int beep_rates[] = { 261, 522, 585, 667, 706, 774, 889, 1000, 1043, 1200, 1333, 1412, 1600, 1714, 2000, 2182 @@ -1104,8 +1090,6 @@ static int cs42l52_probe(struct snd_soc_codec *codec) cs42l52_init_beep(codec); - cs42l52_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - cs42l52->sysclk = CS42L52_DEFAULT_CLK; cs42l52->config.format = CS42L52_DEFAULT_FORMAT; @@ -1115,7 +1099,6 @@ static int cs42l52_probe(struct snd_soc_codec *codec) static int cs42l52_remove(struct snd_soc_codec *codec) { cs42l52_free_beep(codec); - cs42l52_set_bias_level(codec, SND_SOC_BIAS_OFF); return 0; } @@ -1123,9 +1106,8 @@ static int cs42l52_remove(struct snd_soc_codec *codec) static struct snd_soc_codec_driver soc_codec_dev_cs42l52 = { .probe = cs42l52_probe, .remove = cs42l52_remove, - .suspend = cs42l52_suspend, - .resume = cs42l52_resume, .set_bias_level = cs42l52_set_bias_level, + .suspend_bias_off = true, .dapm_widgets = cs42l52_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(cs42l52_dapm_widgets), From 2a4bc751fcc50c15bd4782cfc2ea513bef92a20f Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 9 Sep 2014 20:42:41 +0200 Subject: [PATCH 137/251] ASoC: cs42l56: Cleanup manual bias level transitions Set the CODEC driver's suspend_bias_off flag rather than manually going to SND_SOC_BIAS_OFF in suspend and SND_SOC_BIAS_STANDBY in resume. This makes the code a bit shorter and cleaner. Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. The manual transition to SND_SOC_BIAS_STANDBY at the end of CODEC probe() can also be removed as the core will automatically do this after the CODEC has been probed. Signed-off-by: Lars-Peter Clausen Acked-by: Brian Austin Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l56.c | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/sound/soc/codecs/cs42l56.c b/sound/soc/codecs/cs42l56.c index bb74dd17fa26..2ddc7ac10ad7 100644 --- a/sound/soc/codecs/cs42l56.c +++ b/sound/soc/codecs/cs42l56.c @@ -1016,20 +1016,6 @@ static struct snd_soc_dai_driver cs42l56_dai = { .ops = &cs42l56_ops, }; -static int cs42l56_suspend(struct snd_soc_codec *codec) -{ - cs42l56_set_bias_level(codec, SND_SOC_BIAS_OFF); - - return 0; -} - -static int cs42l56_resume(struct snd_soc_codec *codec) -{ - cs42l56_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - return 0; -} - static int beep_freq[] = { 261, 522, 585, 667, 706, 774, 889, 1000, 1043, 1200, 1333, 1412, 1600, 1714, 2000, 2182 @@ -1168,15 +1154,12 @@ static int cs42l56_probe(struct snd_soc_codec *codec) { cs42l56_init_beep(codec); - cs42l56_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - return 0; } static int cs42l56_remove(struct snd_soc_codec *codec) { cs42l56_free_beep(codec); - cs42l56_set_bias_level(codec, SND_SOC_BIAS_OFF); return 0; } @@ -1184,9 +1167,8 @@ static int cs42l56_remove(struct snd_soc_codec *codec) static struct snd_soc_codec_driver soc_codec_dev_cs42l56 = { .probe = cs42l56_probe, .remove = cs42l56_remove, - .suspend = cs42l56_suspend, - .resume = cs42l56_resume, .set_bias_level = cs42l56_set_bias_level, + .suspend_bias_off = true, .dapm_widgets = cs42l56_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(cs42l56_dapm_widgets), From 02bf34f4b8793a23dd0dbc4fda09d611a70ca0c9 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 9 Sep 2014 20:42:42 +0200 Subject: [PATCH 138/251] ASoC: cs42l73: Cleanup manual bias level transitions Set the CODEC driver's suspend_bias_off flag rather than manually going to SND_SOC_BIAS_OFF in suspend and SND_SOC_BIAS_STANDBY in resume. This makes the code a bit shorter and cleaner. Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. The manual transition to SND_SOC_BIAS_STANDBY at the end of CODEC probe() can also be removed as the core will automatically do this after the CODEC has been probed. Signed-off-by: Lars-Peter Clausen Acked-by: Brian Austin Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l73.c | 25 +------------------------ 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c index 0e7b9eb2ba61..2f8b94683e83 100644 --- a/sound/soc/codecs/cs42l73.c +++ b/sound/soc/codecs/cs42l73.c @@ -1330,25 +1330,10 @@ static struct snd_soc_dai_driver cs42l73_dai[] = { } }; -static int cs42l73_suspend(struct snd_soc_codec *codec) -{ - cs42l73_set_bias_level(codec, SND_SOC_BIAS_OFF); - - return 0; -} - -static int cs42l73_resume(struct snd_soc_codec *codec) -{ - cs42l73_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - return 0; -} - static int cs42l73_probe(struct snd_soc_codec *codec) { struct cs42l73_private *cs42l73 = snd_soc_codec_get_drvdata(codec); - cs42l73_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - /* Set Charge Pump Frequency */ if (cs42l73->pdata.chgfreq) snd_soc_update_bits(codec, CS42L73_CPFCHC, @@ -1362,18 +1347,10 @@ static int cs42l73_probe(struct snd_soc_codec *codec) return 0; } -static int cs42l73_remove(struct snd_soc_codec *codec) -{ - cs42l73_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - static struct snd_soc_codec_driver soc_codec_dev_cs42l73 = { .probe = cs42l73_probe, - .remove = cs42l73_remove, - .suspend = cs42l73_suspend, - .resume = cs42l73_resume, .set_bias_level = cs42l73_set_bias_level, + .suspend_bias_off = true, .dapm_widgets = cs42l73_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(cs42l73_dapm_widgets), From f66a91ff8e83e95c822691270d883cbcb3244302 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 9 Sep 2014 20:42:43 +0200 Subject: [PATCH 139/251] ASoC: da732x: Remove unnecessary idle_bias_off initialization idle_bias_off is false by default, no need to set it explicitly. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/da732x.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/sound/soc/codecs/da732x.c b/sound/soc/codecs/da732x.c index 2fae31cb0067..edcbfeafc8cb 100644 --- a/sound/soc/codecs/da732x.c +++ b/sound/soc/codecs/da732x.c @@ -1511,12 +1511,9 @@ static int da732x_set_bias_level(struct snd_soc_codec *codec, static int da732x_probe(struct snd_soc_codec *codec) { struct da732x_priv *da732x = snd_soc_codec_get_drvdata(codec); - struct snd_soc_dapm_context *dapm = &codec->dapm; da732x->codec = codec; - dapm->idle_bias_off = false; - da732x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); return 0; From ee6b42ee21b16aa322758fdab0d57082761b09fd Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 9 Sep 2014 20:42:44 +0200 Subject: [PATCH 140/251] ASoC: da732x: Remove unused codec field form da732x_priv struct The field is initialized in the probe callback, but never used again. So it can be removed. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/da732x.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/sound/soc/codecs/da732x.c b/sound/soc/codecs/da732x.c index edcbfeafc8cb..c28cf339f066 100644 --- a/sound/soc/codecs/da732x.c +++ b/sound/soc/codecs/da732x.c @@ -35,7 +35,6 @@ struct da732x_priv { struct regmap *regmap; - struct snd_soc_codec *codec; unsigned int sysclk; bool pll_en; @@ -1512,8 +1511,6 @@ static int da732x_probe(struct snd_soc_codec *codec) { struct da732x_priv *da732x = snd_soc_codec_get_drvdata(codec); - da732x->codec = codec; - da732x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); return 0; From f0b99ca041258ed0eb27dc724de22d84dab78a7c Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 9 Sep 2014 20:42:45 +0200 Subject: [PATCH 141/251] ASoC: da732x: Cleanup manual bias level transitions Since the ASoC core now takes care of setting the bias level to SND_SOC_BIAS_OFF when removing the CODEC there is no need to do it manually anymore either. The manual transition to SND_SOC_BIAS_STANDBY at the end of CODEC probe() can also be removed as the core will automatically do this after the CODEC has been probed. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/da732x.c | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/sound/soc/codecs/da732x.c b/sound/soc/codecs/da732x.c index c28cf339f066..f35e83e00c8d 100644 --- a/sound/soc/codecs/da732x.c +++ b/sound/soc/codecs/da732x.c @@ -1507,26 +1507,7 @@ static int da732x_set_bias_level(struct snd_soc_codec *codec, return 0; } -static int da732x_probe(struct snd_soc_codec *codec) -{ - struct da732x_priv *da732x = snd_soc_codec_get_drvdata(codec); - - da732x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - return 0; -} - -static int da732x_remove(struct snd_soc_codec *codec) -{ - - da732x_set_bias_level(codec, SND_SOC_BIAS_OFF); - - return 0; -} - static struct snd_soc_codec_driver soc_codec_dev_da732x = { - .probe = da732x_probe, - .remove = da732x_remove, .set_bias_level = da732x_set_bias_level, .controls = da732x_snd_controls, .num_controls = ARRAY_SIZE(da732x_snd_controls), From 0dd4fc3c2f663b9124855daf3fd841d70b4dbeea Mon Sep 17 00:00:00 2001 From: Xiubo Li Date: Wed, 10 Sep 2014 09:59:55 +0800 Subject: [PATCH 142/251] ASoC: simple-card: Adjust the comments of simple card. Signed-off-by: Xiubo Li Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 48 ++++++++++++++++----------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index e0abe772c040..f79347c4c62f 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -122,7 +122,7 @@ asoc_simple_card_sub_parse_of(struct device_node *np, int ret; /* - * get node via "sound-dai = <&phandle port>" + * Get node via "sound-dai = <&phandle port>" * it will be used as xxx_of_node on soc_bind_dai_link() */ ret = of_parse_phandle_with_args(np, "sound-dai", @@ -135,19 +135,19 @@ asoc_simple_card_sub_parse_of(struct device_node *np, if (args_count) *args_count = args.args_count; - /* get dai->name */ + /* Get dai->name */ ret = snd_soc_of_get_dai_name(np, name); if (ret < 0) return ret; - /* parse TDM slot */ + /* Parse TDM slot */ ret = snd_soc_of_parse_tdm_slot(np, &dai->slots, &dai->slot_width); if (ret) return ret; /* - * dai->sysclk come from - * "clocks = <&xxx>" (if system has common clock) + * Parse dai->sysclk come from "clocks = <&xxx>" + * (if system has common clock) * or "system-clock-frequency = " * or device's module clock. */ @@ -240,9 +240,11 @@ static int asoc_simple_card_dai_link_of(struct device_node *node, goto dai_link_of_err; if (strlen(prefix) && !bitclkmaster && !framemaster) { - /* No dai-link level and master setting was not found from - sound node level, revert back to legacy DT parsing and - take the settings from codec node. */ + /* + * No DAI link level and master setting was found + * from sound node level, revert back to legacy DT + * parsing and take the settings from codec node. + */ dev_dbg(dev, "%s: Revert to legacy daifmt parsing\n", __func__); dai_props->cpu_dai.fmt = dai_props->codec_dai.fmt = @@ -271,10 +273,10 @@ static int asoc_simple_card_dai_link_of(struct device_node *node, goto dai_link_of_err; } - /* simple-card assumes platform == cpu */ + /* Simple Card assumes platform == cpu */ dai_link->platform_of_node = dai_link->cpu_of_node; - /* Link name is created from CPU/CODEC dai name */ + /* DAI link name is created from CPU/CODEC dai name */ name = devm_kzalloc(dev, strlen(dai_link->cpu_dai_name) + strlen(dai_link->codec_dai_name) + 2, @@ -296,11 +298,11 @@ static int asoc_simple_card_dai_link_of(struct device_node *node, dai_props->codec_dai.sysclk); /* - * soc_bind_dai_link() will check cpu name - * after of_node matching if dai_link has cpu_dai_name. - * but, it will never match if name was created by fmt_single_name() - * remove cpu_dai_name if cpu_args was 0. - * see + * In soc_bind_dai_link() will check cpu name after + * of_node matching if dai_link has cpu_dai_name. + * but, it will never match if name was created by + * fmt_single_name() remove cpu_dai_name if cpu_args + * was 0. See: * fmt_single_name() * fmt_multiple_name() */ @@ -329,10 +331,10 @@ static int asoc_simple_card_parse_of(struct device_node *node, if (!node) return -EINVAL; - /* parsing the card name from DT */ + /* Parse the card name from DT */ snd_soc_of_parse_card_name(&priv->snd_card, "simple-audio-card,name"); - /* off-codec widgets */ + /* The off-codec widgets */ if (of_property_read_bool(node, "simple-audio-card,widgets")) { ret = snd_soc_of_parse_audio_simple_widgets(&priv->snd_card, "simple-audio-card,widgets"); @@ -387,7 +389,7 @@ static int asoc_simple_card_parse_of(struct device_node *node, return 0; } -/* update the reference count of the devices nodes at end of probe */ +/* Decrease the reference count of the device nodes */ static int asoc_simple_card_unref(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); @@ -416,29 +418,27 @@ static int asoc_simple_card_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; int num_links, ret; - /* get the number of DAI links */ + /* Get the number of DAI links */ if (np && of_get_child_by_name(np, "simple-audio-card,dai-link")) num_links = of_get_child_count(np); else num_links = 1; - /* allocate the private data and the DAI link array */ + /* Allocate the private data and the DAI link array */ priv = devm_kzalloc(dev, sizeof(*priv) + sizeof(*dai_link) * num_links, GFP_KERNEL); if (!priv) return -ENOMEM; - /* - * init snd_soc_card - */ + /* Init snd_soc_card */ priv->snd_card.owner = THIS_MODULE; priv->snd_card.dev = dev; dai_link = priv->dai_link; priv->snd_card.dai_link = dai_link; priv->snd_card.num_links = num_links; - /* get room for the other properties */ + /* Get room for the other properties */ priv->dai_props = devm_kzalloc(dev, sizeof(*priv->dai_props) * num_links, GFP_KERNEL); From 88a60e552f114ae34796604575239fb196658067 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 8 Sep 2014 13:14:05 +0200 Subject: [PATCH 143/251] ASoC: simple-card: fix regression in clock rate lookup Commit 7c7b9cf53d284f ("ASoC: simple-card: fixup cpu_dai_name clear case") changed the way that "sound-dai" properties are handled, which leads to the clock frequency not being picked up from the node that the phandle points to, as correctly identified by gcc with this warning: sound/soc/generic/simple-card.c: In function 'asoc_simple_card_sub_parse_of': sound/soc/generic/simple-card.c:165:7: warning: 'node' may be used uninitialized in this function [-Wmaybe-uninitialized] This restores the previous behavior by using the node from of_parse_phandle_with_args() that was previously being returned from of_parse_phandle(). Signed-off-by: Arnd Bergmann Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index f79347c4c62f..106fdada8640 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -116,7 +116,6 @@ asoc_simple_card_sub_parse_of(struct device_node *np, int *args_count) { struct of_phandle_args args; - struct device_node *node; struct clk *clk; u32 val; int ret; @@ -162,7 +161,7 @@ asoc_simple_card_sub_parse_of(struct device_node *np, } else if (!of_property_read_u32(np, "system-clock-frequency", &val)) { dai->sysclk = val; } else { - clk = of_clk_get(node, 0); + clk = of_clk_get(args.np, 0); if (!IS_ERR(clk)) dai->sysclk = clk_get_rate(clk); } From 62f949bf6bf6ceb44872c44ef3913a96d93fb5d4 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 11 Sep 2014 14:06:53 +0200 Subject: [PATCH 144/251] ALSA: hda - Get rid of action field from struct hda_jack_tbl The action value assigned to each hda_jack_tbl entry is mostly superfluous. The actually used values are either the widget NID or a value specific to the callback. The former case can be simply replaced by a reference to widget NID itself. The only place doing the latter is STAC/IDT codec driver for the powermap handling. But, the code doesn't need to check the action field at all -- the function jack_update_power() is called either with a specific pin or with NULL. So the check of jack->action can be removed completely there, too. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_generic.c | 4 +--- sound/pci/hda/hda_generic.h | 6 ------ sound/pci/hda/hda_jack.c | 10 +++------- sound/pci/hda/hda_jack.h | 22 +--------------------- sound/pci/hda/patch_ca0132.c | 16 +++++++++------- sound/pci/hda/patch_cirrus.c | 3 --- sound/pci/hda/patch_hdmi.c | 4 ++-- sound/pci/hda/patch_realtek.c | 9 +++------ sound/pci/hda/patch_sigmatel.c | 18 ++++-------------- sound/pci/hda/patch_via.c | 4 ---- 10 files changed, 23 insertions(+), 73 deletions(-) diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 95121e818b4d..4d605e4ac41c 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -4180,7 +4180,7 @@ static int check_auto_mute_availability(struct hda_codec *codec) if (!is_jack_detectable(codec, nid)) continue; codec_dbg(codec, "Enable HP auto-muting on NID 0x%x\n", nid); - snd_hda_jack_detect_enable_callback(codec, nid, HDA_GEN_HP_EVENT, + snd_hda_jack_detect_enable_callback(codec, nid, call_hp_automute); spec->detect_hp = 1; } @@ -4193,7 +4193,6 @@ static int check_auto_mute_availability(struct hda_codec *codec) continue; codec_dbg(codec, "Enable Line-Out auto-muting on NID 0x%x\n", nid); snd_hda_jack_detect_enable_callback(codec, nid, - HDA_GEN_FRONT_EVENT, call_line_automute); spec->detect_lo = 1; } @@ -4235,7 +4234,6 @@ static bool auto_mic_check_imux(struct hda_codec *codec) for (i = 1; i < spec->am_num_entries; i++) snd_hda_jack_detect_enable_callback(codec, spec->am_entry[i].pin, - HDA_GEN_MIC_EVENT, call_mic_autoswitch); return true; } diff --git a/sound/pci/hda/hda_generic.h b/sound/pci/hda/hda_generic.h index 3f95f1d3f1f8..72f5624125fb 100644 --- a/sound/pci/hda/hda_generic.h +++ b/sound/pci/hda/hda_generic.h @@ -12,12 +12,6 @@ #ifndef __SOUND_HDA_GENERIC_H #define __SOUND_HDA_GENERIC_H -/* unsol event tags */ -enum { - HDA_GEN_HP_EVENT = 1, HDA_GEN_FRONT_EVENT, HDA_GEN_MIC_EVENT, - HDA_GEN_LAST_EVENT = HDA_GEN_MIC_EVENT -}; - /* table entry for multi-io paths */ struct hda_multi_io { hda_nid_t pin; /* multi-io widget pin NID */ diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c index 9746d73cec52..9c8f24f2d56b 100644 --- a/sound/pci/hda/hda_jack.c +++ b/sound/pci/hda/hda_jack.c @@ -217,7 +217,6 @@ EXPORT_SYMBOL_GPL(snd_hda_jack_detect_state); * snd_hda_jack_detect_enable - enable the jack-detection */ int snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid, - unsigned char action, hda_jack_callback cb) { struct hda_jack_tbl *jack = snd_hda_jack_tbl_new(codec, nid); @@ -226,8 +225,6 @@ int snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid, if (jack->jack_detect) return 0; /* already registered */ jack->jack_detect = 1; - if (action) - jack->action = action; if (cb) jack->callback = cb; if (codec->jackpoll_interval > 0) @@ -238,10 +235,9 @@ int snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid, } EXPORT_SYMBOL_GPL(snd_hda_jack_detect_enable_callback); -int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid, - unsigned char action) +int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid) { - return snd_hda_jack_detect_enable_callback(codec, nid, action, NULL); + return snd_hda_jack_detect_enable_callback(codec, nid, NULL); } EXPORT_SYMBOL_GPL(snd_hda_jack_detect_enable); @@ -431,7 +427,7 @@ static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid, return err; if (!phantom_jack) - return snd_hda_jack_detect_enable(codec, nid, 0); + return snd_hda_jack_detect_enable(codec, nid); return 0; } diff --git a/sound/pci/hda/hda_jack.h b/sound/pci/hda/hda_jack.h index 46e1ea83ce3c..c1abc7324d68 100644 --- a/sound/pci/hda/hda_jack.h +++ b/sound/pci/hda/hda_jack.h @@ -19,7 +19,6 @@ typedef void (*hda_jack_callback) (struct hda_codec *, struct hda_jack_tbl *); struct hda_jack_tbl { hda_nid_t nid; - unsigned char action; /* event action (0 = none) */ unsigned char tag; /* unsol event tag */ unsigned int private_data; /* arbitrary data */ hda_jack_callback callback; @@ -47,29 +46,10 @@ struct hda_jack_tbl * snd_hda_jack_tbl_new(struct hda_codec *codec, hda_nid_t nid); void snd_hda_jack_tbl_clear(struct hda_codec *codec); -/** - * snd_hda_jack_get_action - get jack-tbl entry for the tag - * - * Call this from the unsol event handler to get the assigned action for the - * event. This will mark the dirty flag for the later reporting, too. - */ -static inline unsigned char -snd_hda_jack_get_action(struct hda_codec *codec, unsigned int tag) -{ - struct hda_jack_tbl *jack = snd_hda_jack_tbl_get_from_tag(codec, tag); - if (jack) { - jack->jack_dirty = 1; - return jack->action; - } - return 0; -} - void snd_hda_jack_set_dirty_all(struct hda_codec *codec); -int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid, - unsigned char action); +int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid); int snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid, - unsigned char action, hda_jack_callback cb); int snd_hda_jack_set_gating_jack(struct hda_codec *codec, hda_nid_t gated_nid, diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 5d8455e2dacd..39fae52258f0 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -4116,8 +4116,8 @@ static void init_input(struct hda_codec *codec, hda_nid_t pin, hda_nid_t adc) static void ca0132_init_unsol(struct hda_codec *codec) { - snd_hda_jack_detect_enable(codec, UNSOL_TAG_HP, UNSOL_TAG_HP); - snd_hda_jack_detect_enable(codec, UNSOL_TAG_AMIC1, UNSOL_TAG_AMIC1); + snd_hda_jack_detect_enable(codec, UNSOL_TAG_HP); + snd_hda_jack_detect_enable(codec, UNSOL_TAG_AMIC1); } static void refresh_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir) @@ -4406,16 +4406,18 @@ static void ca0132_process_dsp_response(struct hda_codec *codec) static void ca0132_unsol_event(struct hda_codec *codec, unsigned int res) { struct ca0132_spec *spec = codec->spec; + unsigned int tag = (res >> AC_UNSOL_RES_TAG_SHIFT) & 0x3f; - if (((res >> AC_UNSOL_RES_TAG_SHIFT) & 0x3f) == UNSOL_TAG_DSP) { + if (tag == UNSOL_TAG_DSP) { ca0132_process_dsp_response(codec); } else { - res = snd_hda_jack_get_action(codec, - (res >> AC_UNSOL_RES_TAG_SHIFT) & 0x3f); + struct hda_jack_tbl *jack; codec_dbg(codec, "snd_hda_jack_get_action: 0x%x\n", res); - - switch (res) { + jack = snd_hda_jack_tbl_get_from_tag(codec, tag); + if (!jack) + return; + switch (jack->nid) { case UNSOL_TAG_HP: /* Delay enabling the HP amp, to let the mic-detection * state machine run. diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 3db724eaa53c..69b0ffc55a51 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -135,8 +135,6 @@ enum { #define CS421X_IDX_DAC_CFG 0x03 #define CS421X_IDX_SPK_CTL 0x04 -#define SPDIF_EVENT 0x04 - /* Cirrus Logic CS4213 is like CS4210 but does not have SPDIF input/output */ #define CS4213_VENDOR_NID 0x09 @@ -1019,7 +1017,6 @@ static void parse_cs421x_digital(struct hda_codec *codec) if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) { spec->spdif_detect = 1; snd_hda_jack_detect_enable_callback(codec, nid, - SPDIF_EVENT, cs4210_spdif_automute); } } diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 99d7d7fecaad..8f94527f1890 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -2165,7 +2165,7 @@ static int generic_hdmi_init(struct hda_codec *codec) hda_nid_t pin_nid = per_pin->pin_nid; hdmi_init_pin(codec, pin_nid); - snd_hda_jack_detect_enable_callback(codec, pin_nid, pin_nid, + snd_hda_jack_detect_enable_callback(codec, pin_nid, codec->jackpoll_interval > 0 ? jack_callback : NULL); } return 0; @@ -2428,7 +2428,7 @@ static int simple_playback_init(struct hda_codec *codec) if (get_wcaps(codec, pin) & AC_WCAP_OUT_AMP) snd_hda_codec_write(codec, pin, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); - snd_hda_jack_detect_enable(codec, pin, pin); + snd_hda_jack_detect_enable(codec, pin); return 0; } diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 6b1a5de07e35..ac00420e59ff 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -40,9 +40,6 @@ /* keep halting ALC5505 DSP, for power saving */ #define HALT_REALTEK_ALC5505 -/* unsol event tags */ -#define ALC_DCVOL_EVENT 0x08 - /* for GPIO Poll */ #define GPIO_MASK 0x03 @@ -1130,7 +1127,8 @@ static void alc880_fixup_vol_knob(struct hda_codec *codec, const struct hda_fixup *fix, int action) { if (action == HDA_FIXUP_ACT_PROBE) - snd_hda_jack_detect_enable_callback(codec, 0x21, ALC_DCVOL_EVENT, alc_update_knob_master); + snd_hda_jack_detect_enable_callback(codec, 0x21, + alc_update_knob_master); } static const struct hda_fixup alc880_fixups[] = { @@ -1593,7 +1591,7 @@ static void alc260_fixup_gpio1_toggle(struct hda_codec *codec, spec->gen.detect_hp = 1; spec->gen.automute_speaker = 1; spec->gen.autocfg.hp_pins[0] = 0x0f; /* copy it for automute */ - snd_hda_jack_detect_enable_callback(codec, 0x0f, HDA_GEN_HP_EVENT, + snd_hda_jack_detect_enable_callback(codec, 0x0f, snd_hda_gen_hp_automute); snd_hda_add_verbs(codec, alc_gpio1_init_verbs); } @@ -4254,7 +4252,6 @@ static void alc282_fixup_asus_tx300(struct hda_codec *codec, spec->gen.auto_mute_via_amp = 1; spec->gen.automute_hook = asus_tx300_automute; snd_hda_jack_detect_enable_callback(codec, 0x1b, - HDA_GEN_HP_EVENT, snd_hda_gen_hp_automute); break; case HDA_FIXUP_ACT_BUILD: diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 60aebd0f5e56..bc371cfb5d84 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -39,11 +39,6 @@ #include "hda_jack.h" #include "hda_generic.h" -enum { - STAC_VREF_EVENT = 8, - STAC_PWR_EVENT, -}; - enum { STAC_REF, STAC_9200_OQO, @@ -505,13 +500,11 @@ static void jack_update_power(struct hda_codec *codec, for (i = 0; i < spec->num_pwrs; i++) { hda_nid_t nid = spec->pwr_nids[i]; jack = snd_hda_jack_tbl_get(codec, nid); - if (!jack || !jack->action) + if (!jack) continue; - if (jack->action == STAC_PWR_EVENT || - jack->action <= HDA_GEN_LAST_EVENT) - stac_toggle_power_map(codec, nid, - snd_hda_jack_detect(codec, nid), - false); + stac_toggle_power_map(codec, nid, + snd_hda_jack_detect(codec, nid), + false); } snd_hda_codec_write(codec, codec->afg, 0, AC_VERB_IDT_SET_POWER_MAP, @@ -568,7 +561,6 @@ static void stac_init_power_map(struct hda_codec *codec) spec->vref_mute_led_nid != nid && is_jack_detectable(codec, nid)) { snd_hda_jack_detect_enable_callback(codec, nid, - STAC_PWR_EVENT, jack_update_power); } else { if (def_conf == AC_JACK_PORT_NONE) @@ -3028,7 +3020,6 @@ static void stac92hd71bxx_fixup_hp_m4(struct hda_codec *codec, snd_hda_codec_write_cache(codec, codec->afg, 0, AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x02); snd_hda_jack_detect_enable_callback(codec, codec->afg, - STAC_VREF_EVENT, stac_vref_event); jack = snd_hda_jack_tbl_get(codec, codec->afg); if (jack) @@ -4052,7 +4043,6 @@ static void stac9205_fixup_dell_m43(struct hda_codec *codec, snd_hda_codec_write_cache(codec, codec->afg, 0, AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x10); snd_hda_jack_detect_enable_callback(codec, codec->afg, - STAC_VREF_EVENT, stac_vref_event); jack = snd_hda_jack_tbl_get(codec, codec->afg); if (jack) diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 778166259b3e..2a8be5a5da15 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -592,8 +592,6 @@ static void via_jack_powerstate_event(struct hda_codec *codec, struct hda_jack_t set_widgets_power_state(codec); } -#define VIA_JACK_EVENT (HDA_GEN_LAST_EVENT + 1) - static void via_set_jack_unsol_events(struct hda_codec *codec) { struct via_spec *spec = codec->spec; @@ -610,7 +608,6 @@ static void via_set_jack_unsol_events(struct hda_codec *codec) if (pin && !snd_hda_jack_tbl_get(codec, pin) && is_jack_detectable(codec, pin)) snd_hda_jack_detect_enable_callback(codec, pin, - VIA_JACK_EVENT, via_jack_powerstate_event); } @@ -619,7 +616,6 @@ static void via_set_jack_unsol_events(struct hda_codec *codec) if (pin && !snd_hda_jack_tbl_get(codec, pin) && is_jack_detectable(codec, pin)) snd_hda_jack_detect_enable_callback(codec, pin, - VIA_JACK_EVENT, via_jack_powerstate_event); } } From 81965f1f58ce120a616f2fdd0594916fa183c5fc Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 11 Sep 2014 14:22:03 +0200 Subject: [PATCH 145/251] ALSA: hda - Make snd_hda_jack_tbl_new() static It's called only in hda_jack.c, so make it local. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_jack.c | 3 +-- sound/pci/hda/hda_jack.h | 2 -- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c index 9c8f24f2d56b..7f332794993f 100644 --- a/sound/pci/hda/hda_jack.c +++ b/sound/pci/hda/hda_jack.c @@ -94,7 +94,7 @@ EXPORT_SYMBOL_GPL(snd_hda_jack_tbl_get_from_tag); /** * snd_hda_jack_tbl_new - create a jack-table entry for the given NID */ -struct hda_jack_tbl * +static struct hda_jack_tbl * snd_hda_jack_tbl_new(struct hda_codec *codec, hda_nid_t nid) { struct hda_jack_tbl *jack = snd_hda_jack_tbl_get(codec, nid); @@ -108,7 +108,6 @@ snd_hda_jack_tbl_new(struct hda_codec *codec, hda_nid_t nid) jack->tag = codec->jacktbl.used; return jack; } -EXPORT_SYMBOL_GPL(snd_hda_jack_tbl_new); void snd_hda_jack_tbl_clear(struct hda_codec *codec) { diff --git a/sound/pci/hda/hda_jack.h b/sound/pci/hda/hda_jack.h index c1abc7324d68..67f42db9c89c 100644 --- a/sound/pci/hda/hda_jack.h +++ b/sound/pci/hda/hda_jack.h @@ -42,8 +42,6 @@ snd_hda_jack_tbl_get(struct hda_codec *codec, hda_nid_t nid); struct hda_jack_tbl * snd_hda_jack_tbl_get_from_tag(struct hda_codec *codec, unsigned char tag); -struct hda_jack_tbl * -snd_hda_jack_tbl_new(struct hda_codec *codec, hda_nid_t nid); void snd_hda_jack_tbl_clear(struct hda_codec *codec); void snd_hda_jack_set_dirty_all(struct hda_codec *codec); From f531913f01a07253d013a9c67a80df11154e7ae2 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 9 Sep 2014 21:37:57 -0700 Subject: [PATCH 146/251] ASoC: simple-card: tidyup use priv in parameter priv has many information about simple-card driver. Using it becomes easy to extend feature. This patch gets dev from priv as 1st step Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 106fdada8640..28aa5e2d859d 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -28,6 +28,8 @@ struct simple_card_data { struct snd_soc_dai_link dai_link[]; /* dynamically allocated */ }; +#define simple_priv_to_dev(priv) ((priv)->snd_card.dev) + static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -170,11 +172,12 @@ asoc_simple_card_sub_parse_of(struct device_node *np, } static int asoc_simple_card_dai_link_of(struct device_node *node, - struct device *dev, + struct simple_card_data *priv, struct snd_soc_dai_link *dai_link, struct simple_dai_props *dai_props, bool is_top_level_node) { + struct device *dev = simple_priv_to_dev(priv); struct device_node *np = NULL; struct device_node *bitclkmaster = NULL; struct device_node *framemaster = NULL; @@ -319,9 +322,9 @@ dai_link_of_err: } static int asoc_simple_card_parse_of(struct device_node *node, - struct simple_card_data *priv, - struct device *dev) + struct simple_card_data *priv) { + struct device *dev = simple_priv_to_dev(priv); struct snd_soc_dai_link *dai_link = priv->snd_card.dai_link; struct simple_dai_props *dai_props = priv->dai_props; u32 val; @@ -364,7 +367,7 @@ static int asoc_simple_card_parse_of(struct device_node *node, for_each_child_of_node(node, np) { dev_dbg(dev, "\tlink %d:\n", i); - ret = asoc_simple_card_dai_link_of(np, dev, + ret = asoc_simple_card_dai_link_of(np, priv, dai_link + i, dai_props + i, false); @@ -376,7 +379,7 @@ static int asoc_simple_card_parse_of(struct device_node *node, } } else { /* For single DAI link & old style of DT node */ - ret = asoc_simple_card_dai_link_of(node, dev, + ret = asoc_simple_card_dai_link_of(node, priv, dai_link, dai_props, true); if (ret < 0) return ret; @@ -446,7 +449,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev) if (np && of_device_is_available(np)) { - ret = asoc_simple_card_parse_of(np, priv, dev); + ret = asoc_simple_card_parse_of(np, priv); if (ret < 0) { if (ret != -EPROBE_DEFER) dev_err(dev, "parse error %d\n", ret); From 9810f5370b6e60c4b564f294feb51761f0e741f6 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 9 Sep 2014 21:38:24 -0700 Subject: [PATCH 147/251] ASoC: simple-card: tidyup get dai_link/dai_props from priv It can get dai_link/dai_props pointer from priv + index Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 28aa5e2d859d..a8877076bdfd 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -29,6 +29,8 @@ struct simple_card_data { }; #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_props(priv, i) ((priv)->dai_props + i) static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) @@ -173,11 +175,12 @@ asoc_simple_card_sub_parse_of(struct device_node *np, static int asoc_simple_card_dai_link_of(struct device_node *node, struct simple_card_data *priv, - struct snd_soc_dai_link *dai_link, - struct simple_dai_props *dai_props, + int idx, bool is_top_level_node) { struct device *dev = simple_priv_to_dev(priv); + struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx); + struct simple_dai_props *dai_props = simple_priv_to_props(priv, idx); struct device_node *np = NULL; struct device_node *bitclkmaster = NULL; struct device_node *framemaster = NULL; @@ -325,8 +328,6 @@ 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_dai_link *dai_link = priv->snd_card.dai_link; - struct simple_dai_props *dai_props = priv->dai_props; u32 val; int ret; @@ -368,9 +369,7 @@ static int asoc_simple_card_parse_of(struct device_node *node, for_each_child_of_node(node, np) { dev_dbg(dev, "\tlink %d:\n", i); ret = asoc_simple_card_dai_link_of(np, priv, - dai_link + i, - dai_props + i, - false); + i, false); if (ret < 0) { of_node_put(np); return ret; @@ -379,8 +378,7 @@ static int asoc_simple_card_parse_of(struct device_node *node, } } else { /* For single DAI link & old style of DT node */ - ret = asoc_simple_card_dai_link_of(node, priv, - dai_link, dai_props, true); + ret = asoc_simple_card_dai_link_of(node, priv, 0, true); if (ret < 0) return ret; } From 01605ad12875c7b5ed71b486f9badb338f4f8c21 Mon Sep 17 00:00:00 2001 From: Jianqun Date: Sat, 13 Sep 2014 08:43:13 +0800 Subject: [PATCH 148/251] ASoC: rockchip-i2s: enable "hclk" for rockchip I2S controller As "hclk" is used for rockchip I2S controller, driver must to enable it in probe. Tested on RK3288 with max98090. Signed-off-by: Jianqun Xu Signed-off-by: Mark Brown --- sound/soc/rockchip/rockchip_i2s.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c index 8d8e4b59049f..dd423c611d96 100644 --- a/sound/soc/rockchip/rockchip_i2s.c +++ b/sound/soc/rockchip/rockchip_i2s.c @@ -419,6 +419,11 @@ static int rockchip_i2s_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Can't retrieve i2s bus clock\n"); return PTR_ERR(i2s->hclk); } + ret = clk_prepare_enable(i2s->hclk); + if (ret) { + dev_err(i2s->dev, "hclock enable failed %d\n", ret); + return ret; + } i2s->mclk = devm_clk_get(&pdev->dev, "i2s_clk"); if (IS_ERR(i2s->mclk)) { From 38306afc107c53c379757e7f3146a6418328ebc9 Mon Sep 17 00:00:00 2001 From: Jianqun Date: Sat, 13 Sep 2014 08:40:19 +0800 Subject: [PATCH 149/251] ASoC: rockchip-i2s: fix rockchip i2s defination more reasonable Fix SND_ROCKCHIP_I2S to be more reasonable - SND_SOC_ROCKCHIP_I2S, SND_SOC_ROCKCHIP_I2S should select by audio driver, instead of SND_SOC_ROCKCHIP. Signed-off-by: Jianqun Xu Signed-off-by: Mark Brown --- sound/soc/rockchip/Kconfig | 3 +-- sound/soc/rockchip/Makefile | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/sound/soc/rockchip/Kconfig b/sound/soc/rockchip/Kconfig index c196a466eef6..78fc159559b0 100644 --- a/sound/soc/rockchip/Kconfig +++ b/sound/soc/rockchip/Kconfig @@ -2,11 +2,10 @@ config SND_SOC_ROCKCHIP tristate "ASoC support for Rockchip" depends on COMPILE_TEST || ARCH_ROCKCHIP select SND_SOC_GENERIC_DMAENGINE_PCM - select SND_ROCKCHIP_I2S help Say Y or M if you want to add support for codecs attached to the Rockchip SoCs' Audio interfaces. You will also need to select the audio interfaces to support below. -config SND_ROCKCHIP_I2S +config SND_SOC_ROCKCHIP_I2S tristate diff --git a/sound/soc/rockchip/Makefile b/sound/soc/rockchip/Makefile index 1006418e1394..b9219092b47f 100644 --- a/sound/soc/rockchip/Makefile +++ b/sound/soc/rockchip/Makefile @@ -1,4 +1,4 @@ # ROCKCHIP Platform Support snd-soc-i2s-objs := rockchip_i2s.o -obj-$(CONFIG_SND_ROCKCHIP_I2S) += snd-soc-i2s.o +obj-$(CONFIG_SND_SOC_ROCKCHIP_I2S) += snd-soc-i2s.o From 3b40a80216e941c518426f7b86705e52acbd413f Mon Sep 17 00:00:00 2001 From: Jianqun Date: Sat, 13 Sep 2014 08:41:38 +0800 Subject: [PATCH 150/251] ASoC: rockchip-i2s: add dma data to snd_soc_dai Add playback/capture dma data to snd_soc_dai. Test on RK3288 with max98090. Signed-off-by: Jianqun Xu Signed-off-by: Mark Brown --- sound/soc/rockchip/rockchip_i2s.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c index dd423c611d96..c8172dda8c7d 100644 --- a/sound/soc/rockchip/rockchip_i2s.c +++ b/sound/soc/rockchip/rockchip_i2s.c @@ -243,16 +243,6 @@ static int rockchip_i2s_hw_params(struct snd_pcm_substream *substream, regmap_update_bits(i2s->regmap, I2S_TXCR, I2S_TXCR_VDW_MASK, val); regmap_update_bits(i2s->regmap, I2S_RXCR, I2S_RXCR_VDW_MASK, val); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - dai->playback_dma_data = &i2s->playback_dma_data; - regmap_update_bits(i2s->regmap, I2S_DMACR, I2S_DMACR_TDL_MASK, - I2S_DMACR_TDL(1) | I2S_DMACR_TDE_ENABLE); - } else { - dai->capture_dma_data = &i2s->capture_dma_data; - regmap_update_bits(i2s->regmap, I2S_DMACR, I2S_DMACR_RDL_MASK, - I2S_DMACR_RDL(1) | I2S_DMACR_RDE_ENABLE); - } - return 0; } @@ -300,6 +290,16 @@ static int rockchip_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id, return ret; } +static int rockchip_i2s_dai_probe(struct snd_soc_dai *dai) +{ + struct rk_i2s_dev *i2s = snd_soc_dai_get_drvdata(dai); + + dai->capture_dma_data = &i2s->capture_dma_data; + dai->playback_dma_data = &i2s->playback_dma_data; + + return 0; +} + static const struct snd_soc_dai_ops rockchip_i2s_dai_ops = { .hw_params = rockchip_i2s_hw_params, .set_sysclk = rockchip_i2s_set_sysclk, @@ -308,7 +308,9 @@ static const struct snd_soc_dai_ops rockchip_i2s_dai_ops = { }; static struct snd_soc_dai_driver rockchip_i2s_dai = { + .probe = rockchip_i2s_dai_probe, .playback = { + .stream_name = "Playback", .channels_min = 2, .channels_max = 8, .rates = SNDRV_PCM_RATE_8000_192000, @@ -318,6 +320,7 @@ static struct snd_soc_dai_driver rockchip_i2s_dai = { SNDRV_PCM_FMTBIT_S24_LE), }, .capture = { + .stream_name = "Capture", .channels_min = 2, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_192000, From bda17b82bfa9601f167ec338755b0b96909db5a0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 11 Sep 2014 14:39:09 +0200 Subject: [PATCH 151/251] ALSA: hda - Make snd_hda_jack_detect_enable_callback() returning the jack object STAC/IDT driver calls snd_hda_jack_tbl_get() again after calling snd_hda_jack_detect_enable_callback(). For simplifying this, let's make snd_hda_jack_detect_enable_callback() returning the pointer while handling the error with the standard IS_ERR() & co. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_jack.c | 24 +++++++++++++++++------- sound/pci/hda/hda_jack.h | 5 +++-- sound/pci/hda/patch_sigmatel.c | 14 ++++++-------- 3 files changed, 26 insertions(+), 17 deletions(-) diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c index 7f332794993f..a5fe1b428015 100644 --- a/sound/pci/hda/hda_jack.c +++ b/sound/pci/hda/hda_jack.c @@ -214,29 +214,39 @@ EXPORT_SYMBOL_GPL(snd_hda_jack_detect_state); /** * snd_hda_jack_detect_enable - enable the jack-detection + * + * In the case of error, the return value will be a pointer embedded with + * errno. Check and handle the return value appropriately with standard + * macros such as @IS_ERR() and @PTR_ERR(). */ -int snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid, - hda_jack_callback cb) +struct hda_jack_tbl * +snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid, + hda_jack_callback cb) { struct hda_jack_tbl *jack = snd_hda_jack_tbl_new(codec, nid); + int err; + if (!jack) - return -ENOMEM; + return ERR_PTR(-ENOMEM); if (jack->jack_detect) - return 0; /* already registered */ + return jack; /* already registered */ jack->jack_detect = 1; if (cb) jack->callback = cb; if (codec->jackpoll_interval > 0) - return 0; /* No unsol if we're polling instead */ - return snd_hda_codec_write_cache(codec, nid, 0, + return jack; /* No unsol if we're polling instead */ + err = snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | jack->tag); + if (err < 0) + return ERR_PTR(err); + return jack; } EXPORT_SYMBOL_GPL(snd_hda_jack_detect_enable_callback); int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid) { - return snd_hda_jack_detect_enable_callback(codec, nid, NULL); + return PTR_ERR_OR_ZERO(snd_hda_jack_detect_enable_callback(codec, nid, NULL)); } EXPORT_SYMBOL_GPL(snd_hda_jack_detect_enable); diff --git a/sound/pci/hda/hda_jack.h b/sound/pci/hda/hda_jack.h index 67f42db9c89c..668669ce3e52 100644 --- a/sound/pci/hda/hda_jack.h +++ b/sound/pci/hda/hda_jack.h @@ -47,8 +47,9 @@ void snd_hda_jack_tbl_clear(struct hda_codec *codec); void snd_hda_jack_set_dirty_all(struct hda_codec *codec); int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid); -int snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid, - hda_jack_callback cb); +struct hda_jack_tbl * +snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid, + hda_jack_callback cb); int snd_hda_jack_set_gating_jack(struct hda_codec *codec, hda_nid_t gated_nid, hda_nid_t gating_nid); diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index bc371cfb5d84..4b338beb9449 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -3019,10 +3019,9 @@ static void stac92hd71bxx_fixup_hp_m4(struct hda_codec *codec, /* Enable VREF power saving on GPIO1 detect */ snd_hda_codec_write_cache(codec, codec->afg, 0, AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x02); - snd_hda_jack_detect_enable_callback(codec, codec->afg, - stac_vref_event); - jack = snd_hda_jack_tbl_get(codec, codec->afg); - if (jack) + jack = snd_hda_jack_detect_enable_callback(codec, codec->afg, + stac_vref_event); + if (!IS_ERR(jack)) jack->private_data = 0x02; spec->gpio_mask |= 0x02; @@ -4042,10 +4041,9 @@ static void stac9205_fixup_dell_m43(struct hda_codec *codec, /* Enable unsol response for GPIO4/Dock HP connection */ snd_hda_codec_write_cache(codec, codec->afg, 0, AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x10); - snd_hda_jack_detect_enable_callback(codec, codec->afg, - stac_vref_event); - jack = snd_hda_jack_tbl_get(codec, codec->afg); - if (jack) + jack = snd_hda_jack_detect_enable_callback(codec, codec->afg, + stac_vref_event); + if (!IS_ERR(jack)) jack->private_data = 0x01; spec->gpio_dir = 0x0b; From db0a5214b8d6cc7a90ce3336d24a85b90cbb4e67 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 9 Sep 2014 17:17:20 +0200 Subject: [PATCH 152/251] ALSA: vx: Use nonatomic PCM ops Rewrite VXpocket and VX222 drivers to use the new PCM nonatomic ops. The former irq tasklet is replaced with a threaded irq handler, and the tasklet for the PCM delayed start is simply merged into the normal PCM trigger, as well as the replacement of spinlock with mutex. Signed-off-by: Takashi Iwai --- include/sound/vx_core.h | 7 ++-- sound/drivers/vx/vx_core.c | 49 +++++++++++++------------- sound/drivers/vx/vx_mixer.c | 12 +++---- sound/drivers/vx/vx_pcm.c | 68 +++++++++++++------------------------ sound/drivers/vx/vx_uer.c | 23 ++++++------- sound/pci/vx222/vx222.c | 5 +-- sound/pcmcia/vx/vxp_ops.c | 10 +++--- sound/pcmcia/vx/vxpocket.c | 13 ++++--- 8 files changed, 78 insertions(+), 109 deletions(-) diff --git a/include/sound/vx_core.h b/include/sound/vx_core.h index f634f8f85db5..cae9c9d4ef22 100644 --- a/include/sound/vx_core.h +++ b/include/sound/vx_core.h @@ -80,8 +80,6 @@ struct vx_pipe { unsigned int references; /* an output pipe may be used for monitoring and/or playback */ struct vx_pipe *monitoring_pipe; /* pointer to the monitoring pipe (capture pipe only)*/ - - struct tasklet_struct start_tq; }; struct vx_core; @@ -165,9 +163,7 @@ struct vx_core { struct snd_vx_hardware *hw; struct snd_vx_ops *ops; - spinlock_t lock; - spinlock_t irq_lock; - struct tasklet_struct tq; + struct mutex lock; unsigned int chip_status; unsigned int pcm_running; @@ -223,6 +219,7 @@ void snd_vx_free_firmware(struct vx_core *chip); * interrupt handler; exported for pcmcia */ irqreturn_t snd_vx_irq_handler(int irq, void *dev); +irqreturn_t snd_vx_threaded_irq_handler(int irq, void *dev); /* * lowlevel functions diff --git a/sound/drivers/vx/vx_core.c b/sound/drivers/vx/vx_core.c index 83596891cde4..e8cc16993903 100644 --- a/sound/drivers/vx/vx_core.c +++ b/sound/drivers/vx/vx_core.c @@ -117,7 +117,7 @@ static int vx_reset_chk(struct vx_core *chip) * * returns 0 if successful, or a negative error code. * the error code can be VX-specific, retrieved via vx_get_error(). - * NB: call with spinlock held! + * NB: call with mutex held! */ static int vx_transfer_end(struct vx_core *chip, int cmd) { @@ -155,7 +155,7 @@ static int vx_transfer_end(struct vx_core *chip, int cmd) * * returns 0 if successful, or a negative error code. * the error code can be VX-specific, retrieved via vx_get_error(). - * NB: call with spinlock held! + * NB: call with mutex held! */ static int vx_read_status(struct vx_core *chip, struct vx_rmh *rmh) { @@ -236,7 +236,7 @@ static int vx_read_status(struct vx_core *chip, struct vx_rmh *rmh) * returns 0 if successful, or a negative error code. * the error code can be VX-specific, retrieved via vx_get_error(). * - * this function doesn't call spinlock at all. + * this function doesn't call mutex lock at all. */ int vx_send_msg_nolock(struct vx_core *chip, struct vx_rmh *rmh) { @@ -337,7 +337,7 @@ int vx_send_msg_nolock(struct vx_core *chip, struct vx_rmh *rmh) /* - * vx_send_msg - send a DSP message with spinlock + * vx_send_msg - send a DSP message with mutex * @rmh: the rmh record to send and receive * * returns 0 if successful, or a negative error code. @@ -345,12 +345,11 @@ int vx_send_msg_nolock(struct vx_core *chip, struct vx_rmh *rmh) */ int vx_send_msg(struct vx_core *chip, struct vx_rmh *rmh) { - unsigned long flags; int err; - spin_lock_irqsave(&chip->lock, flags); + mutex_lock(&chip->lock); err = vx_send_msg_nolock(chip, rmh); - spin_unlock_irqrestore(&chip->lock, flags); + mutex_unlock(&chip->lock); return err; } @@ -362,7 +361,7 @@ int vx_send_msg(struct vx_core *chip, struct vx_rmh *rmh) * returns 0 if successful, or a negative error code. * the error code can be VX-specific, retrieved via vx_get_error(). * - * this function doesn't call spinlock at all. + * this function doesn't call mutex at all. * * unlike RMH, no command is sent to DSP. */ @@ -398,19 +397,18 @@ int vx_send_rih_nolock(struct vx_core *chip, int cmd) /* - * vx_send_rih - send an RIH with spinlock + * vx_send_rih - send an RIH with mutex * @cmd: the command to send * * see vx_send_rih_nolock(). */ int vx_send_rih(struct vx_core *chip, int cmd) { - unsigned long flags; int err; - spin_lock_irqsave(&chip->lock, flags); + mutex_lock(&chip->lock); err = vx_send_rih_nolock(chip, cmd); - spin_unlock_irqrestore(&chip->lock, flags); + mutex_unlock(&chip->lock); return err; } @@ -482,30 +480,30 @@ static int vx_test_irq_src(struct vx_core *chip, unsigned int *ret) int err; vx_init_rmh(&chip->irq_rmh, CMD_TEST_IT); - spin_lock(&chip->lock); + mutex_lock(&chip->lock); err = vx_send_msg_nolock(chip, &chip->irq_rmh); if (err < 0) *ret = 0; else *ret = chip->irq_rmh.Stat[0]; - spin_unlock(&chip->lock); + mutex_unlock(&chip->lock); return err; } /* - * vx_interrupt - soft irq handler + * snd_vx_threaded_irq_handler - threaded irq handler */ -static void vx_interrupt(unsigned long private_data) +irqreturn_t snd_vx_threaded_irq_handler(int irq, void *dev) { - struct vx_core *chip = (struct vx_core *) private_data; + struct vx_core *chip = dev; unsigned int events; if (chip->chip_status & VX_STAT_IS_STALE) - return; + return IRQ_HANDLED; if (vx_test_irq_src(chip, &events) < 0) - return; + return IRQ_HANDLED; #if 0 if (events & 0x000800) @@ -519,7 +517,7 @@ static void vx_interrupt(unsigned long private_data) */ if (events & FATAL_DSP_ERROR) { snd_printk(KERN_ERR "vx_core: fatal DSP error!!\n"); - return; + return IRQ_HANDLED; } /* The start on time code conditions are filled (ie the time code @@ -534,8 +532,9 @@ static void vx_interrupt(unsigned long private_data) /* update the pcm streams */ vx_pcm_update_intr(chip, events); + return IRQ_HANDLED; } - +EXPORT_SYMBOL(snd_vx_threaded_irq_handler); /** * snd_vx_irq_handler - interrupt handler @@ -548,8 +547,8 @@ irqreturn_t snd_vx_irq_handler(int irq, void *dev) (chip->chip_status & VX_STAT_IS_STALE)) return IRQ_NONE; if (! vx_test_and_ack(chip)) - tasklet_schedule(&chip->tq); - return IRQ_HANDLED; + return IRQ_WAKE_THREAD; + return IRQ_NONE; } EXPORT_SYMBOL(snd_vx_irq_handler); @@ -790,13 +789,11 @@ struct vx_core *snd_vx_create(struct snd_card *card, struct snd_vx_hardware *hw, snd_printk(KERN_ERR "vx_core: no memory\n"); return NULL; } - spin_lock_init(&chip->lock); - spin_lock_init(&chip->irq_lock); + mutex_init(&chip->lock); chip->irq = -1; chip->hw = hw; chip->type = hw->type; chip->ops = ops; - tasklet_init(&chip->tq, vx_interrupt, (unsigned long)chip); mutex_init(&chip->mixer_mutex); chip->card = card; diff --git a/sound/drivers/vx/vx_mixer.c b/sound/drivers/vx/vx_mixer.c index c71b8d148d7f..3b6823fc0606 100644 --- a/sound/drivers/vx/vx_mixer.c +++ b/sound/drivers/vx/vx_mixer.c @@ -32,17 +32,15 @@ */ static void vx_write_codec_reg(struct vx_core *chip, int codec, unsigned int data) { - unsigned long flags; - if (snd_BUG_ON(!chip->ops->write_codec)) return; if (chip->chip_status & VX_STAT_IS_STALE) return; - spin_lock_irqsave(&chip->lock, flags); + mutex_lock(&chip->lock); chip->ops->write_codec(chip, codec, data); - spin_unlock_irqrestore(&chip->lock, flags); + mutex_unlock(&chip->lock); } /* @@ -178,14 +176,12 @@ void vx_reset_codec(struct vx_core *chip, int cold_reset) */ static void vx_change_audio_source(struct vx_core *chip, int src) { - unsigned long flags; - if (chip->chip_status & VX_STAT_IS_STALE) return; - spin_lock_irqsave(&chip->lock, flags); + mutex_lock(&chip->lock); chip->ops->change_audio_source(chip, src); - spin_unlock_irqrestore(&chip->lock, flags); + mutex_unlock(&chip->lock); } diff --git a/sound/drivers/vx/vx_pcm.c b/sound/drivers/vx/vx_pcm.c index deed5efff33c..11467272089e 100644 --- a/sound/drivers/vx/vx_pcm.c +++ b/sound/drivers/vx/vx_pcm.c @@ -229,7 +229,7 @@ static int vx_get_pipe_state(struct vx_core *chip, struct vx_pipe *pipe, int *st vx_init_rmh(&rmh, CMD_PIPE_STATE); vx_set_pipe_cmd_params(&rmh, pipe->is_capture, pipe->number, 0); - err = vx_send_msg_nolock(chip, &rmh); /* no lock needed for trigger */ + err = vx_send_msg(chip, &rmh); if (! err) *state = (rmh.Stat[0] & (1 << pipe->number)) ? 1 : 0; return err; @@ -280,7 +280,7 @@ static int vx_pipe_can_start(struct vx_core *chip, struct vx_pipe *pipe) vx_set_pipe_cmd_params(&rmh, pipe->is_capture, pipe->number, 0); rmh.Cmd[0] |= 1; - err = vx_send_msg_nolock(chip, &rmh); /* no lock needed for trigger */ + err = vx_send_msg(chip, &rmh); if (! err) { if (rmh.Stat[0]) err = 1; @@ -300,7 +300,7 @@ static int vx_conf_pipe(struct vx_core *chip, struct vx_pipe *pipe) if (pipe->is_capture) rmh.Cmd[0] |= COMMAND_RECORD_MASK; rmh.Cmd[1] = 1 << pipe->number; - return vx_send_msg_nolock(chip, &rmh); /* no lock needed for trigger */ + return vx_send_msg(chip, &rmh); } /* @@ -311,7 +311,7 @@ static int vx_send_irqa(struct vx_core *chip) struct vx_rmh rmh; vx_init_rmh(&rmh, CMD_SEND_IRQA); - return vx_send_msg_nolock(chip, &rmh); /* no lock needed for trigger */ + return vx_send_msg(chip, &rmh); } @@ -389,7 +389,7 @@ static int vx_stop_pipe(struct vx_core *chip, struct vx_pipe *pipe) struct vx_rmh rmh; vx_init_rmh(&rmh, CMD_STOP_PIPE); vx_set_pipe_cmd_params(&rmh, pipe->is_capture, pipe->number, 0); - return vx_send_msg_nolock(chip, &rmh); /* no lock needed for trigger */ + return vx_send_msg(chip, &rmh); } @@ -477,7 +477,7 @@ static int vx_start_stream(struct vx_core *chip, struct vx_pipe *pipe) vx_init_rmh(&rmh, CMD_START_ONE_STREAM); vx_set_stream_cmd_params(&rmh, pipe->is_capture, pipe->number); vx_set_differed_time(chip, &rmh, pipe); - return vx_send_msg_nolock(chip, &rmh); /* no lock needed for trigger */ + return vx_send_msg(chip, &rmh); } @@ -492,7 +492,7 @@ static int vx_stop_stream(struct vx_core *chip, struct vx_pipe *pipe) vx_init_rmh(&rmh, CMD_STOP_STREAM); vx_set_stream_cmd_params(&rmh, pipe->is_capture, pipe->number); - return vx_send_msg_nolock(chip, &rmh); /* no lock needed for trigger */ + return vx_send_msg(chip, &rmh); } @@ -520,8 +520,6 @@ static struct snd_pcm_hardware vx_pcm_playback_hw = { }; -static void vx_pcm_delayed_start(unsigned long arg); - /* * vx_pcm_playback_open - open callback for playback */ @@ -553,7 +551,6 @@ static int vx_pcm_playback_open(struct snd_pcm_substream *subs) pipe->references++; pipe->substream = subs; - tasklet_init(&pipe->start_tq, vx_pcm_delayed_start, (unsigned long)subs); chip->playback_pipes[audio] = pipe; runtime->hw = vx_pcm_playback_hw; @@ -646,12 +643,12 @@ static int vx_pcm_playback_transfer_chunk(struct vx_core *chip, /* we don't need irqsave here, because this function * is called from either trigger callback or irq handler */ - spin_lock(&chip->lock); + mutex_lock(&chip->lock); vx_pseudo_dma_write(chip, runtime, pipe, size); err = vx_notify_end_of_buffer(chip, pipe); /* disconnect the host, SIZE_HBUF command always switches to the stream mode */ vx_send_rih_nolock(chip, IRQ_CONNECT_STREAM_NEXT); - spin_unlock(&chip->lock); + mutex_unlock(&chip->lock); return err; } @@ -727,31 +724,6 @@ static void vx_pcm_playback_update(struct vx_core *chip, } } -/* - * start the stream and pipe. - * this function is called from tasklet, which is invoked by the trigger - * START callback. - */ -static void vx_pcm_delayed_start(unsigned long arg) -{ - struct snd_pcm_substream *subs = (struct snd_pcm_substream *)arg; - struct vx_core *chip = subs->pcm->private_data; - struct vx_pipe *pipe = subs->runtime->private_data; - int err; - - /* printk( KERN_DEBUG "DDDD tasklet delayed start jiffies = %ld\n", jiffies);*/ - - if ((err = vx_start_stream(chip, pipe)) < 0) { - snd_printk(KERN_ERR "vx: cannot start stream\n"); - return; - } - if ((err = vx_toggle_pipe(chip, pipe, 1)) < 0) { - snd_printk(KERN_ERR "vx: cannot start pipe\n"); - return; - } - /* printk( KERN_DEBUG "dddd tasklet delayed start jiffies = %ld \n", jiffies);*/ -} - /* * vx_pcm_playback_trigger - trigger callback for playback */ @@ -769,11 +741,17 @@ static int vx_pcm_trigger(struct snd_pcm_substream *subs, int cmd) case SNDRV_PCM_TRIGGER_RESUME: if (! pipe->is_capture) vx_pcm_playback_transfer(chip, subs, pipe, 2); - /* FIXME: - * we trigger the pipe using tasklet, so that the interrupts are - * issued surely after the trigger is completed. - */ - tasklet_schedule(&pipe->start_tq); + err = vx_start_stream(chip, pipe); + if (err < 0) { + pr_debug("vx: cannot start stream\n"); + return err; + } + err = vx_toggle_pipe(chip, pipe, 1); + if (err < 0) { + pr_debug("vx: cannot start pipe\n"); + vx_stop_stream(chip, pipe); + return err; + } chip->pcm_running++; pipe->running = 1; break; @@ -955,7 +933,6 @@ static int vx_pcm_capture_open(struct snd_pcm_substream *subs) if (err < 0) return err; pipe->substream = subs; - tasklet_init(&pipe->start_tq, vx_pcm_delayed_start, (unsigned long)subs); chip->capture_pipes[audio] = pipe; /* check if monitoring is needed */ @@ -1082,7 +1059,7 @@ static void vx_pcm_capture_update(struct vx_core *chip, struct snd_pcm_substream count -= 3; } /* disconnect the host, SIZE_HBUF command always switches to the stream mode */ - vx_send_rih_nolock(chip, IRQ_CONNECT_STREAM_NEXT); + vx_send_rih(chip, IRQ_CONNECT_STREAM_NEXT); /* read the last pending 6 bytes */ count = DMA_READ_ALIGN; while (count > 0) { @@ -1099,7 +1076,7 @@ static void vx_pcm_capture_update(struct vx_core *chip, struct snd_pcm_substream _error: /* disconnect the host, SIZE_HBUF command always switches to the stream mode */ - vx_send_rih_nolock(chip, IRQ_CONNECT_STREAM_NEXT); + vx_send_rih(chip, IRQ_CONNECT_STREAM_NEXT); return; } @@ -1275,6 +1252,7 @@ int snd_vx_pcm_new(struct vx_core *chip) pcm->private_data = chip; pcm->private_free = snd_vx_pcm_free; pcm->info_flags = 0; + pcm->nonatomic = true; strcpy(pcm->name, chip->card->shortname); chip->pcm[i] = pcm; } diff --git a/sound/drivers/vx/vx_uer.c b/sound/drivers/vx/vx_uer.c index b0560fec6bba..ef0b40c0a594 100644 --- a/sound/drivers/vx/vx_uer.c +++ b/sound/drivers/vx/vx_uer.c @@ -60,9 +60,9 @@ static int vx_modify_board_inputs(struct vx_core *chip) */ static int vx_read_one_cbit(struct vx_core *chip, int index) { - unsigned long flags; int val; - spin_lock_irqsave(&chip->lock, flags); + + mutex_lock(&chip->lock); if (chip->type >= VX_TYPE_VXPOCKET) { vx_outb(chip, CSUER, 1); /* read */ vx_outb(chip, RUER, index & XX_UER_CBITS_OFFSET_MASK); @@ -72,7 +72,7 @@ static int vx_read_one_cbit(struct vx_core *chip, int index) vx_outl(chip, RUER, index & XX_UER_CBITS_OFFSET_MASK); val = (vx_inl(chip, RUER) >> 7) & 0x01; } - spin_unlock_irqrestore(&chip->lock, flags); + mutex_unlock(&chip->lock); return val; } @@ -83,9 +83,8 @@ static int vx_read_one_cbit(struct vx_core *chip, int index) */ static void vx_write_one_cbit(struct vx_core *chip, int index, int val) { - unsigned long flags; val = !!val; /* 0 or 1 */ - spin_lock_irqsave(&chip->lock, flags); + mutex_lock(&chip->lock); if (vx_is_pcmcia(chip)) { vx_outb(chip, CSUER, 0); /* write */ vx_outb(chip, RUER, (val << 7) | (index & XX_UER_CBITS_OFFSET_MASK)); @@ -93,7 +92,7 @@ static void vx_write_one_cbit(struct vx_core *chip, int index, int val) vx_outl(chip, CSUER, 0); /* write */ vx_outl(chip, RUER, (val << 7) | (index & XX_UER_CBITS_OFFSET_MASK)); } - spin_unlock_irqrestore(&chip->lock, flags); + mutex_unlock(&chip->lock); } /* @@ -190,14 +189,12 @@ static int vx_calc_clock_from_freq(struct vx_core *chip, int freq) */ static void vx_change_clock_source(struct vx_core *chip, int source) { - unsigned long flags; - /* we mute DAC to prevent clicks */ vx_toggle_dac_mute(chip, 1); - spin_lock_irqsave(&chip->lock, flags); + mutex_lock(&chip->lock); chip->ops->set_clock_source(chip, source); chip->clock_source = source; - spin_unlock_irqrestore(&chip->lock, flags); + mutex_unlock(&chip->lock); /* unmute */ vx_toggle_dac_mute(chip, 0); } @@ -209,11 +206,11 @@ static void vx_change_clock_source(struct vx_core *chip, int source) void vx_set_internal_clock(struct vx_core *chip, unsigned int freq) { int clock; - unsigned long flags; + /* Get real clock value */ clock = vx_calc_clock_from_freq(chip, freq); snd_printdd(KERN_DEBUG "set internal clock to 0x%x from freq %d\n", clock, freq); - spin_lock_irqsave(&chip->lock, flags); + mutex_lock(&chip->lock); if (vx_is_pcmcia(chip)) { vx_outb(chip, HIFREQ, (clock >> 8) & 0x0f); vx_outb(chip, LOFREQ, clock & 0xff); @@ -221,7 +218,7 @@ void vx_set_internal_clock(struct vx_core *chip, unsigned int freq) vx_outl(chip, HIFREQ, (clock >> 8) & 0x0f); vx_outl(chip, LOFREQ, clock & 0xff); } - spin_unlock_irqrestore(&chip->lock, flags); + mutex_unlock(&chip->lock); } diff --git a/sound/pci/vx222/vx222.c b/sound/pci/vx222/vx222.c index 3dc4732142ee..c5a25e39e3a8 100644 --- a/sound/pci/vx222/vx222.c +++ b/sound/pci/vx222/vx222.c @@ -168,8 +168,9 @@ static int snd_vx222_create(struct snd_card *card, struct pci_dev *pci, for (i = 0; i < 2; i++) vx->port[i] = pci_resource_start(pci, i + 1); - if (request_irq(pci->irq, snd_vx_irq_handler, IRQF_SHARED, - KBUILD_MODNAME, chip)) { + if (request_threaded_irq(pci->irq, snd_vx_irq_handler, + snd_vx_threaded_irq_handler, IRQF_SHARED, + KBUILD_MODNAME, chip)) { dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq); snd_vx222_free(chip); return -EBUSY; diff --git a/sound/pcmcia/vx/vxp_ops.c b/sound/pcmcia/vx/vxp_ops.c index fe33e122e372..281972913c32 100644 --- a/sound/pcmcia/vx/vxp_ops.c +++ b/sound/pcmcia/vx/vxp_ops.c @@ -468,12 +468,11 @@ static void vxp_write_codec_reg(struct vx_core *chip, int codec, unsigned int da void vx_set_mic_boost(struct vx_core *chip, int boost) { struct snd_vxpocket *pchip = (struct snd_vxpocket *)chip; - unsigned long flags; if (chip->chip_status & VX_STAT_IS_STALE) return; - spin_lock_irqsave(&chip->lock, flags); + mutex_lock(&chip->lock); if (pchip->regCDSP & P24_CDSP_MICS_SEL_MASK) { if (boost) { /* boost: 38 dB */ @@ -486,7 +485,7 @@ void vx_set_mic_boost(struct vx_core *chip, int boost) } vx_outb(chip, CDSP, pchip->regCDSP); } - spin_unlock_irqrestore(&chip->lock, flags); + mutex_unlock(&chip->lock); } /* @@ -511,17 +510,16 @@ static int vx_compute_mic_level(int level) void vx_set_mic_level(struct vx_core *chip, int level) { struct snd_vxpocket *pchip = (struct snd_vxpocket *)chip; - unsigned long flags; if (chip->chip_status & VX_STAT_IS_STALE) return; - spin_lock_irqsave(&chip->lock, flags); + mutex_lock(&chip->lock); if (pchip->regCDSP & VXP_CDSP_MIC_SEL_MASK) { level = vx_compute_mic_level(level); vx_outb(chip, MICRO, level); } - spin_unlock_irqrestore(&chip->lock, flags); + mutex_unlock(&chip->lock); } diff --git a/sound/pcmcia/vx/vxpocket.c b/sound/pcmcia/vx/vxpocket.c index 786e7e139c9e..92ec11456e3a 100644 --- a/sound/pcmcia/vx/vxpocket.c +++ b/sound/pcmcia/vx/vxpocket.c @@ -62,6 +62,7 @@ static unsigned int card_alloc; */ static void vxpocket_release(struct pcmcia_device *link) { + free_irq(link->irq, link->priv); pcmcia_disable_device(link); } @@ -227,11 +228,13 @@ static int vxpocket_config(struct pcmcia_device *link) ret = pcmcia_request_io(link); if (ret) - goto failed; + goto failed_preirq; - ret = pcmcia_request_irq(link, snd_vx_irq_handler); + ret = request_threaded_irq(link->irq, snd_vx_irq_handler, + snd_vx_threaded_irq_handler, + IRQF_SHARED, link->devname, link->priv); if (ret) - goto failed; + goto failed_preirq; ret = pcmcia_enable_device(link); if (ret) @@ -245,7 +248,9 @@ static int vxpocket_config(struct pcmcia_device *link) return 0; -failed: + failed: + free_irq(link->irq, link->priv); +failed_preirq: pcmcia_disable_device(link); return -ENODEV; } From 8d3a8b5cb57da4e327bdaf7c81a90d4105b73205 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 Sep 2014 11:48:07 +0200 Subject: [PATCH 153/251] ALSA: mixart: Use nonatomic PCM ops Like the previous patch for VX boards, miXart device driver can be also rewritten to use nonatomic PCM ops. Simply spinlocks are replaced with mutex, the tasklet code is merged into the threaded irq handler. Also, now mgr->msg_mutex is superfluous, so merged to msg_lock. Signed-off-by: Takashi Iwai --- sound/pci/mixart/mixart.c | 17 +++----- sound/pci/mixart/mixart.h | 10 ++--- sound/pci/mixart/mixart_core.c | 79 ++++++++++++++-------------------- sound/pci/mixart/mixart_core.h | 2 +- 4 files changed, 44 insertions(+), 64 deletions(-) diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c index 75fc342cff2a..1faf47e81570 100644 --- a/sound/pci/mixart/mixart.c +++ b/sound/pci/mixart/mixart.c @@ -986,6 +986,7 @@ static int snd_mixart_pcm_analog(struct snd_mixart *chip) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_mixart_capture_ops); pcm->info_flags = 0; + pcm->nonatomic = true; strcpy(pcm->name, name); preallocate_buffers(chip, pcm); @@ -1018,6 +1019,7 @@ static int snd_mixart_pcm_digital(struct snd_mixart *chip) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_mixart_capture_ops); pcm->info_flags = 0; + pcm->nonatomic = true; strcpy(pcm->name, name); preallocate_buffers(chip, pcm); @@ -1303,8 +1305,9 @@ static int snd_mixart_probe(struct pci_dev *pci, } } - if (request_irq(pci->irq, snd_mixart_interrupt, IRQF_SHARED, - KBUILD_MODNAME, mgr)) { + if (request_threaded_irq(pci->irq, snd_mixart_interrupt, + snd_mixart_threaded_irq, IRQF_SHARED, + KBUILD_MODNAME, mgr)) { dev_err(&pci->dev, "unable to grab IRQ %d\n", pci->irq); snd_mixart_free(mgr); return -EBUSY; @@ -1314,24 +1317,18 @@ static int snd_mixart_probe(struct pci_dev *pci, sprintf(mgr->shortname, "Digigram miXart"); sprintf(mgr->longname, "%s at 0x%lx & 0x%lx, irq %i", mgr->shortname, mgr->mem[0].phys, mgr->mem[1].phys, mgr->irq); - /* ISR spinlock */ - spin_lock_init(&mgr->lock); - /* init mailbox */ mgr->msg_fifo_readptr = 0; mgr->msg_fifo_writeptr = 0; - spin_lock_init(&mgr->msg_lock); - mutex_init(&mgr->msg_mutex); + mutex_init(&mgr->lock); + mutex_init(&mgr->msg_lock); init_waitqueue_head(&mgr->msg_sleep); atomic_set(&mgr->msg_processed, 0); /* init setup mutex*/ mutex_init(&mgr->setup_mutex); - /* init message taslket */ - tasklet_init(&mgr->msg_taskq, snd_mixart_msg_tasklet, (unsigned long) mgr); - /* card assignment */ mgr->num_cards = MIXART_MAX_CARDS; /* 4 FIXME: configurable? */ for (i = 0; i < mgr->num_cards; i++) { diff --git a/sound/pci/mixart/mixart.h b/sound/pci/mixart/mixart.h index 561634d5c007..0cc17e0ea34a 100644 --- a/sound/pci/mixart/mixart.h +++ b/sound/pci/mixart/mixart.h @@ -78,22 +78,18 @@ struct mixart_mgr { char shortname[32]; /* short name of this soundcard */ char longname[80]; /* name of this soundcard */ - /* message tasklet */ - struct tasklet_struct msg_taskq; - /* one and only blocking message or notification may be pending */ u32 pending_event; wait_queue_head_t msg_sleep; - /* messages stored for tasklet */ + /* messages fifo */ u32 msg_fifo[MSG_FIFO_SIZE]; int msg_fifo_readptr; int msg_fifo_writeptr; atomic_t msg_processed; /* number of messages to be processed in takslet */ - spinlock_t lock; /* interrupt spinlock */ - spinlock_t msg_lock; /* mailbox spinlock */ - struct mutex msg_mutex; /* mutex for blocking_requests */ + struct mutex lock; /* interrupt lock */ + struct mutex msg_lock; /* mailbox lock */ struct mutex setup_mutex; /* mutex used in hw_params, open and close */ diff --git a/sound/pci/mixart/mixart_core.c b/sound/pci/mixart/mixart_core.c index 84f67450924e..fe80313674d9 100644 --- a/sound/pci/mixart/mixart_core.c +++ b/sound/pci/mixart/mixart_core.c @@ -76,7 +76,6 @@ static int retrieve_msg_frame(struct mixart_mgr *mgr, u32 *msg_frame) static int get_msg(struct mixart_mgr *mgr, struct mixart_msg *resp, u32 msg_frame_address ) { - unsigned long flags; u32 headptr; u32 size; int err; @@ -84,7 +83,7 @@ static int get_msg(struct mixart_mgr *mgr, struct mixart_msg *resp, unsigned int i; #endif - spin_lock_irqsave(&mgr->msg_lock, flags); + mutex_lock(&mgr->msg_lock); err = 0; /* copy message descriptor from miXart to driver */ @@ -133,7 +132,7 @@ static int get_msg(struct mixart_mgr *mgr, struct mixart_msg *resp, writel_be(headptr, MIXART_MEM(mgr, MSG_OUTBOUND_FREE_HEAD)); _clean_exit: - spin_unlock_irqrestore(&mgr->msg_lock, flags); + mutex_unlock(&mgr->msg_lock); return err; } @@ -243,28 +242,24 @@ int snd_mixart_send_msg(struct mixart_mgr *mgr, struct mixart_msg *request, int wait_queue_t wait; long timeout; - mutex_lock(&mgr->msg_mutex); - init_waitqueue_entry(&wait, current); - spin_lock_irq(&mgr->msg_lock); + mutex_lock(&mgr->msg_lock); /* send the message */ err = send_msg(mgr, request, max_resp_size, 1, &msg_frame); /* send and mark the answer pending */ if (err) { - spin_unlock_irq(&mgr->msg_lock); - mutex_unlock(&mgr->msg_mutex); + mutex_unlock(&mgr->msg_lock); return err; } set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&mgr->msg_sleep, &wait); - spin_unlock_irq(&mgr->msg_lock); + mutex_unlock(&mgr->msg_lock); timeout = schedule_timeout(MSG_TIMEOUT_JIFFIES); remove_wait_queue(&mgr->msg_sleep, &wait); if (! timeout) { /* error - no ack */ - mutex_unlock(&mgr->msg_mutex); dev_err(&mgr->pci->dev, "error: no response on msg %x\n", msg_frame); return -EIO; @@ -281,7 +276,6 @@ int snd_mixart_send_msg(struct mixart_mgr *mgr, struct mixart_msg *request, int if( request->message_id != resp.message_id ) dev_err(&mgr->pci->dev, "RESPONSE ERROR!\n"); - mutex_unlock(&mgr->msg_mutex); return err; } @@ -300,34 +294,29 @@ int snd_mixart_send_msg_wait_notif(struct mixart_mgr *mgr, if (snd_BUG_ON(notif_event & MSG_CANCEL_NOTIFY_MASK)) return -EINVAL; - mutex_lock(&mgr->msg_mutex); - init_waitqueue_entry(&wait, current); - spin_lock_irq(&mgr->msg_lock); + mutex_lock(&mgr->msg_lock); /* send the message */ err = send_msg(mgr, request, MSG_DEFAULT_SIZE, 1, ¬if_event); /* send and mark the notification event pending */ if(err) { - spin_unlock_irq(&mgr->msg_lock); - mutex_unlock(&mgr->msg_mutex); + mutex_unlock(&mgr->msg_lock); return err; } set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&mgr->msg_sleep, &wait); - spin_unlock_irq(&mgr->msg_lock); + mutex_unlock(&mgr->msg_lock); timeout = schedule_timeout(MSG_TIMEOUT_JIFFIES); remove_wait_queue(&mgr->msg_sleep, &wait); if (! timeout) { /* error - no ack */ - mutex_unlock(&mgr->msg_mutex); dev_err(&mgr->pci->dev, "error: notification %x not received\n", notif_event); return -EIO; } - mutex_unlock(&mgr->msg_mutex); return 0; } @@ -335,13 +324,12 @@ int snd_mixart_send_msg_wait_notif(struct mixart_mgr *mgr, int snd_mixart_send_msg_nonblock(struct mixart_mgr *mgr, struct mixart_msg *request) { u32 message_frame; - unsigned long flags; int err; /* just send the message (do not mark it as a pending one) */ - spin_lock_irqsave(&mgr->msg_lock, flags); + mutex_lock(&mgr->msg_lock); err = send_msg(mgr, request, MSG_DEFAULT_SIZE, 0, &message_frame); - spin_unlock_irqrestore(&mgr->msg_lock, flags); + mutex_unlock(&mgr->msg_lock); /* the answer will be handled by snd_struct mixart_msgasklet() */ atomic_inc(&mgr->msg_processed); @@ -350,19 +338,16 @@ int snd_mixart_send_msg_nonblock(struct mixart_mgr *mgr, struct mixart_msg *requ } -/* common buffer of tasklet and interrupt to send/receive messages */ +/* common buffer of interrupt to send/receive messages */ static u32 mixart_msg_data[MSG_DEFAULT_SIZE / 4]; -void snd_mixart_msg_tasklet(unsigned long arg) +static void snd_mixart_process_msg(struct mixart_mgr *mgr) { - struct mixart_mgr *mgr = ( struct mixart_mgr*)(arg); struct mixart_msg resp; u32 msg, addr, type; int err; - spin_lock(&mgr->lock); - while (mgr->msg_fifo_readptr != mgr->msg_fifo_writeptr) { msg = mgr->msg_fifo[mgr->msg_fifo_readptr]; mgr->msg_fifo_readptr++; @@ -381,7 +366,7 @@ void snd_mixart_msg_tasklet(unsigned long arg) err = get_msg(mgr, &resp, addr); if( err < 0 ) { dev_err(&mgr->pci->dev, - "tasklet: error(%d) reading mf %x\n", + "error(%d) reading mf %x\n", err, msg); break; } @@ -393,12 +378,12 @@ void snd_mixart_msg_tasklet(unsigned long arg) case MSG_STREAM_STOP_OUTPUT_STAGE_PACKET: if(mixart_msg_data[0]) dev_err(&mgr->pci->dev, - "tasklet : error MSG_STREAM_ST***_***PUT_STAGE_PACKET status=%x\n", + "error MSG_STREAM_ST***_***PUT_STAGE_PACKET status=%x\n", mixart_msg_data[0]); break; default: dev_dbg(&mgr->pci->dev, - "tasklet received mf(%x) : msg_id(%x) uid(%x, %x) size(%zd)\n", + "received mf(%x) : msg_id(%x) uid(%x, %x) size(%zd)\n", msg, resp.message_id, resp.uid.object_id, resp.uid.desc, resp.size); break; } @@ -409,7 +394,7 @@ void snd_mixart_msg_tasklet(unsigned long arg) /* get_msg() necessary */ default: dev_err(&mgr->pci->dev, - "tasklet doesn't know what to do with message %x\n", + "doesn't know what to do with message %x\n", msg); } /* switch type */ @@ -417,26 +402,17 @@ void snd_mixart_msg_tasklet(unsigned long arg) atomic_dec(&mgr->msg_processed); } /* while there is a msg in fifo */ - - spin_unlock(&mgr->lock); } irqreturn_t snd_mixart_interrupt(int irq, void *dev_id) { struct mixart_mgr *mgr = dev_id; - int err; - struct mixart_msg resp; - - u32 msg; u32 it_reg; - spin_lock(&mgr->lock); - it_reg = readl_le(MIXART_REG(mgr, MIXART_PCI_OMISR_OFFSET)); if( !(it_reg & MIXART_OIDI) ) { /* this device did not cause the interrupt */ - spin_unlock(&mgr->lock); return IRQ_NONE; } @@ -450,6 +426,17 @@ irqreturn_t snd_mixart_interrupt(int irq, void *dev_id) /* clear interrupt */ writel_le( MIXART_OIDI, MIXART_REG(mgr, MIXART_PCI_OMISR_OFFSET) ); + return IRQ_WAKE_THREAD; +} + +irqreturn_t snd_mixart_threaded_irq(int irq, void *dev_id) +{ + struct mixart_mgr *mgr = dev_id; + int err; + struct mixart_msg resp; + u32 msg; + + mutex_lock(&mgr->lock); /* process interrupt */ while (retrieve_msg_frame(mgr, &msg)) { @@ -518,9 +505,9 @@ irqreturn_t snd_mixart_interrupt(int irq, void *dev_id) stream->buf_period_frag = (u32)( sample_count - stream->abs_period_elapsed ); if(elapsed) { - spin_unlock(&mgr->lock); + mutex_unlock(&mgr->lock); snd_pcm_period_elapsed(stream->substream); - spin_lock(&mgr->lock); + mutex_lock(&mgr->lock); } } } @@ -556,7 +543,7 @@ irqreturn_t snd_mixart_interrupt(int irq, void *dev_id) /* no break, continue ! */ case MSG_TYPE_ANSWER: /* answer or notification to a message we are waiting for*/ - spin_lock(&mgr->msg_lock); + mutex_lock(&mgr->msg_lock); if( (msg & ~MSG_TYPE_MASK) == mgr->pending_event ) { wake_up(&mgr->msg_sleep); mgr->pending_event = 0; @@ -566,9 +553,9 @@ irqreturn_t snd_mixart_interrupt(int irq, void *dev_id) mgr->msg_fifo[mgr->msg_fifo_writeptr] = msg; mgr->msg_fifo_writeptr++; mgr->msg_fifo_writeptr %= MSG_FIFO_SIZE; - tasklet_schedule(&mgr->msg_taskq); + snd_mixart_process_msg(mgr); } - spin_unlock(&mgr->msg_lock); + mutex_unlock(&mgr->msg_lock); break; case MSG_TYPE_REQUEST: default: @@ -582,7 +569,7 @@ irqreturn_t snd_mixart_interrupt(int irq, void *dev_id) /* allow interrupt again */ writel_le( MIXART_ALLOW_OUTBOUND_DOORBELL, MIXART_REG( mgr, MIXART_PCI_OMIMR_OFFSET)); - spin_unlock(&mgr->lock); + mutex_unlock(&mgr->lock); return IRQ_HANDLED; } diff --git a/sound/pci/mixart/mixart_core.h b/sound/pci/mixart/mixart_core.h index c919b734756f..d1722e575409 100644 --- a/sound/pci/mixart/mixart_core.h +++ b/sound/pci/mixart/mixart_core.h @@ -564,7 +564,7 @@ int snd_mixart_send_msg_wait_notif(struct mixart_mgr *mgr, struct mixart_msg *r int snd_mixart_send_msg_nonblock(struct mixart_mgr *mgr, struct mixart_msg *request); irqreturn_t snd_mixart_interrupt(int irq, void *dev_id); -void snd_mixart_msg_tasklet(unsigned long arg); +irqreturn_t snd_mixart_threaded_irq(int irq, void *dev_id); void snd_mixart_reset_board(struct mixart_mgr *mgr); From 9bef72bdb26e291d6dffb04768741a0e49582666 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 Sep 2014 12:21:38 +0200 Subject: [PATCH 154/251] ALSA: pcxhr: Use nonatomic PCM ops This time PCXHR, another Digigram boards: like the previous patches, the conversion is straightforward, replacing spinlocks with mutexes, merging the irq tasklet into the threaded irq handler and the PCM trigger tasklet back to the trigger callback. Signed-off-by: Takashi Iwai --- sound/pci/pcxhr/pcxhr.c | 43 +++++++-------- sound/pci/pcxhr/pcxhr.h | 8 +-- sound/pci/pcxhr/pcxhr_core.c | 102 +++++++++++++++++++---------------- sound/pci/pcxhr/pcxhr_core.h | 2 +- 4 files changed, 77 insertions(+), 78 deletions(-) diff --git a/sound/pci/pcxhr/pcxhr.c b/sound/pci/pcxhr/pcxhr.c index 68a37a7906c1..b854fc5e01f5 100644 --- a/sound/pci/pcxhr/pcxhr.c +++ b/sound/pci/pcxhr/pcxhr.c @@ -702,13 +702,11 @@ static inline int pcxhr_stream_scheduled_get_pipe(struct pcxhr_stream *stream, return 0; } -static void pcxhr_trigger_tasklet(unsigned long arg) +static void pcxhr_start_linked_stream(struct pcxhr_mgr *mgr) { - unsigned long flags; int i, j, err; struct pcxhr_pipe *pipe; struct snd_pcxhr *chip; - struct pcxhr_mgr *mgr = (struct pcxhr_mgr*)(arg); int capture_mask = 0; int playback_mask = 0; @@ -736,11 +734,11 @@ static void pcxhr_trigger_tasklet(unsigned long arg) } if (capture_mask == 0 && playback_mask == 0) { mutex_unlock(&mgr->setup_mutex); - dev_err(&mgr->pci->dev, "pcxhr_trigger_tasklet : no pipes\n"); + dev_err(&mgr->pci->dev, "pcxhr_start_linked_stream : no pipes\n"); return; } - dev_dbg(&mgr->pci->dev, "pcxhr_trigger_tasklet : " + dev_dbg(&mgr->pci->dev, "pcxhr_start_linked_stream : " "playback_mask=%x capture_mask=%x\n", playback_mask, capture_mask); @@ -748,7 +746,7 @@ static void pcxhr_trigger_tasklet(unsigned long arg) err = pcxhr_set_pipe_state(mgr, playback_mask, capture_mask, 0); if (err) { mutex_unlock(&mgr->setup_mutex); - dev_err(&mgr->pci->dev, "pcxhr_trigger_tasklet : " + dev_err(&mgr->pci->dev, "pcxhr_start_linked_stream : " "error stop pipes (P%x C%x)\n", playback_mask, capture_mask); return; @@ -793,7 +791,7 @@ static void pcxhr_trigger_tasklet(unsigned long arg) err = pcxhr_set_pipe_state(mgr, playback_mask, capture_mask, 1); if (err) { mutex_unlock(&mgr->setup_mutex); - dev_err(&mgr->pci->dev, "pcxhr_trigger_tasklet : " + dev_err(&mgr->pci->dev, "pcxhr_start_linked_stream : " "error start pipes (P%x C%x)\n", playback_mask, capture_mask); return; @@ -802,7 +800,7 @@ static void pcxhr_trigger_tasklet(unsigned long arg) /* put the streams into the running state now * (increment pointer by interrupt) */ - spin_lock_irqsave(&mgr->lock, flags); + mutex_lock(&mgr->lock); for ( i =0; i < mgr->num_cards; i++) { struct pcxhr_stream *stream; chip = mgr->chip[i]; @@ -820,13 +818,13 @@ static void pcxhr_trigger_tasklet(unsigned long arg) } } } - spin_unlock_irqrestore(&mgr->lock, flags); + mutex_unlock(&mgr->lock); mutex_unlock(&mgr->setup_mutex); #ifdef CONFIG_SND_DEBUG_VERBOSE do_gettimeofday(&my_tv2); - dev_dbg(&mgr->pci->dev, "***TRIGGER TASKLET*** TIME = %ld (err = %x)\n", + dev_dbg(&mgr->pci->dev, "***TRIGGER START*** TIME = %ld (err = %x)\n", (long)(my_tv2.tv_usec - my_tv1.tv_usec), err); #endif } @@ -853,7 +851,7 @@ static int pcxhr_trigger(struct snd_pcm_substream *subs, int cmd) PCXHR_STREAM_STATUS_SCHEDULE_RUN; snd_pcm_trigger_done(s, subs); } - tasklet_schedule(&chip->mgr->trigger_taskq); + pcxhr_start_linked_stream(chip->mgr); } else { stream = subs->runtime->private_data; snd_printdd("Only one Substream %c %d\n", @@ -1127,20 +1125,19 @@ static int pcxhr_close(struct snd_pcm_substream *subs) static snd_pcm_uframes_t pcxhr_stream_pointer(struct snd_pcm_substream *subs) { - unsigned long flags; u_int32_t timer_period_frag; int timer_buf_periods; struct snd_pcxhr *chip = snd_pcm_substream_chip(subs); struct snd_pcm_runtime *runtime = subs->runtime; struct pcxhr_stream *stream = runtime->private_data; - spin_lock_irqsave(&chip->mgr->lock, flags); + mutex_lock(&chip->mgr->lock); /* get the period fragment and the nb of periods in the buffer */ timer_period_frag = stream->timer_period_frag; timer_buf_periods = stream->timer_buf_periods; - spin_unlock_irqrestore(&chip->mgr->lock, flags); + mutex_unlock(&chip->mgr->lock); return (snd_pcm_uframes_t)((timer_buf_periods * runtime->period_size) + timer_period_frag); @@ -1181,6 +1178,7 @@ int pcxhr_create_pcm(struct snd_pcxhr *chip) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcxhr_ops); pcm->info_flags = 0; + pcm->nonatomic = true; strcpy(pcm->name, name); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, @@ -1588,8 +1586,9 @@ static int pcxhr_probe(struct pci_dev *pci, mgr->pci = pci; mgr->irq = -1; - if (request_irq(pci->irq, pcxhr_interrupt, IRQF_SHARED, - KBUILD_MODNAME, mgr)) { + if (request_threaded_irq(pci->irq, pcxhr_interrupt, + pcxhr_threaded_irq, IRQF_SHARED, + KBUILD_MODNAME, mgr)) { dev_err(&pci->dev, "unable to grab IRQ %d\n", pci->irq); pcxhr_free(mgr); return -EBUSY; @@ -1601,19 +1600,13 @@ static int pcxhr_probe(struct pci_dev *pci, mgr->shortname, mgr->port[0], mgr->port[1], mgr->port[2], mgr->irq); - /* ISR spinlock */ - spin_lock_init(&mgr->lock); - spin_lock_init(&mgr->msg_lock); + /* ISR lock */ + mutex_init(&mgr->lock); + mutex_init(&mgr->msg_lock); /* init setup mutex*/ mutex_init(&mgr->setup_mutex); - /* init taslket */ - tasklet_init(&mgr->msg_taskq, pcxhr_msg_tasklet, - (unsigned long) mgr); - tasklet_init(&mgr->trigger_taskq, pcxhr_trigger_tasklet, - (unsigned long) mgr); - mgr->prmh = kmalloc(sizeof(*mgr->prmh) + sizeof(u32) * (PCXHR_SIZE_MAX_LONG_STATUS - PCXHR_SIZE_MAX_STATUS), diff --git a/sound/pci/pcxhr/pcxhr.h b/sound/pci/pcxhr/pcxhr.h index a4c602c45173..9e39e509a3ef 100644 --- a/sound/pci/pcxhr/pcxhr.h +++ b/sound/pci/pcxhr/pcxhr.h @@ -78,14 +78,10 @@ struct pcxhr_mgr { char shortname[32]; /* short name of this soundcard */ char longname[96]; /* name of this soundcard */ - /* message tasklet */ - struct tasklet_struct msg_taskq; struct pcxhr_rmh *prmh; - /* trigger tasklet */ - struct tasklet_struct trigger_taskq; - spinlock_t lock; /* interrupt spinlock */ - spinlock_t msg_lock; /* message spinlock */ + struct mutex lock; /* interrupt lock */ + struct mutex msg_lock; /* message lock */ struct mutex setup_mutex; /* mutex used in hw_params, open and close */ struct mutex mixer_mutex; /* mutex for mixer */ diff --git a/sound/pci/pcxhr/pcxhr_core.c b/sound/pci/pcxhr/pcxhr_core.c index df9371918601..a584acb61c00 100644 --- a/sound/pci/pcxhr/pcxhr_core.c +++ b/sound/pci/pcxhr/pcxhr_core.c @@ -767,11 +767,11 @@ void pcxhr_set_pipe_cmd_params(struct pcxhr_rmh *rmh, int capture, */ int pcxhr_send_msg(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh) { - unsigned long flags; int err; - spin_lock_irqsave(&mgr->msg_lock, flags); + + mutex_lock(&mgr->msg_lock); err = pcxhr_send_msg_nolock(mgr, rmh); - spin_unlock_irqrestore(&mgr->msg_lock, flags); + mutex_unlock(&mgr->msg_lock); return err; } @@ -971,17 +971,16 @@ int pcxhr_write_io_num_reg_cont(struct pcxhr_mgr *mgr, unsigned int mask, unsigned int value, int *changed) { struct pcxhr_rmh rmh; - unsigned long flags; int err; - spin_lock_irqsave(&mgr->msg_lock, flags); + mutex_lock(&mgr->msg_lock); if ((mgr->io_num_reg_cont & mask) == value) { dev_dbg(&mgr->pci->dev, "IO_NUM_REG_CONT mask %x already is set to %x\n", mask, value); if (changed) *changed = 0; - spin_unlock_irqrestore(&mgr->msg_lock, flags); + mutex_unlock(&mgr->msg_lock); return 0; /* already programmed */ } pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); @@ -996,7 +995,7 @@ int pcxhr_write_io_num_reg_cont(struct pcxhr_mgr *mgr, unsigned int mask, if (changed) *changed = 1; } - spin_unlock_irqrestore(&mgr->msg_lock, flags); + mutex_unlock(&mgr->msg_lock); return err; } @@ -1043,22 +1042,21 @@ static int pcxhr_handle_async_err(struct pcxhr_mgr *mgr, u32 err, } -void pcxhr_msg_tasklet(unsigned long arg) +static void pcxhr_msg_thread(struct pcxhr_mgr *mgr) { - struct pcxhr_mgr *mgr = (struct pcxhr_mgr *)(arg); struct pcxhr_rmh *prmh = mgr->prmh; int err; int i, j; if (mgr->src_it_dsp & PCXHR_IRQ_FREQ_CHANGE) dev_dbg(&mgr->pci->dev, - "TASKLET : PCXHR_IRQ_FREQ_CHANGE event occurred\n"); + "PCXHR_IRQ_FREQ_CHANGE event occurred\n"); if (mgr->src_it_dsp & PCXHR_IRQ_TIME_CODE) dev_dbg(&mgr->pci->dev, - "TASKLET : PCXHR_IRQ_TIME_CODE event occurred\n"); + "PCXHR_IRQ_TIME_CODE event occurred\n"); if (mgr->src_it_dsp & PCXHR_IRQ_NOTIFY) dev_dbg(&mgr->pci->dev, - "TASKLET : PCXHR_IRQ_NOTIFY event occurred\n"); + "PCXHR_IRQ_NOTIFY event occurred\n"); if (mgr->src_it_dsp & (PCXHR_IRQ_FREQ_CHANGE | PCXHR_IRQ_TIME_CODE)) { /* clear events FREQ_CHANGE and TIME_CODE */ pcxhr_init_rmh(prmh, CMD_TEST_IT); @@ -1068,7 +1066,7 @@ void pcxhr_msg_tasklet(unsigned long arg) } if (mgr->src_it_dsp & PCXHR_IRQ_ASYNC) { dev_dbg(&mgr->pci->dev, - "TASKLET : PCXHR_IRQ_ASYNC event occurred\n"); + "PCXHR_IRQ_ASYNC event occurred\n"); pcxhr_init_rmh(prmh, CMD_ASYNC); prmh->cmd[0] |= 1; /* add SEL_ASYNC_EVENTS */ @@ -1076,7 +1074,7 @@ void pcxhr_msg_tasklet(unsigned long arg) prmh->stat_len = PCXHR_SIZE_MAX_LONG_STATUS; err = pcxhr_send_msg(mgr, prmh); if (err) - dev_err(&mgr->pci->dev, "ERROR pcxhr_msg_tasklet=%x;\n", + dev_err(&mgr->pci->dev, "ERROR pcxhr_msg_thread=%x;\n", err); i = 1; while (i < prmh->stat_len) { @@ -1220,9 +1218,9 @@ static void pcxhr_update_timer_pos(struct pcxhr_mgr *mgr, } if (elapsed) { - spin_unlock(&mgr->lock); + mutex_unlock(&mgr->lock); snd_pcm_period_elapsed(stream->substream); - spin_lock(&mgr->lock); + mutex_lock(&mgr->lock); } } } @@ -1231,14 +1229,10 @@ irqreturn_t pcxhr_interrupt(int irq, void *dev_id) { struct pcxhr_mgr *mgr = dev_id; unsigned int reg; - int i, j; - struct snd_pcxhr *chip; - - spin_lock(&mgr->lock); + bool wake_thread = false; reg = PCXHR_INPL(mgr, PCXHR_PLX_IRQCS); if (! (reg & PCXHR_IRQCS_ACTIVE_PCIDB)) { - spin_unlock(&mgr->lock); /* this device did not cause the interrupt */ return IRQ_NONE; } @@ -1250,6 +1244,44 @@ irqreturn_t pcxhr_interrupt(int irq, void *dev_id) /* timer irq occurred */ if (reg & PCXHR_IRQ_TIMER) { int timer_toggle = reg & PCXHR_IRQ_TIMER; + if (timer_toggle == mgr->timer_toggle) { + dev_dbg(&mgr->pci->dev, "ERROR TIMER TOGGLE\n"); + mgr->dsp_time_err++; + } + + mgr->timer_toggle = timer_toggle; + mgr->src_it_dsp = reg; + wake_thread = true; + } + + /* other irq's handled in the thread */ + if (reg & PCXHR_IRQ_MASK) { + if (reg & PCXHR_IRQ_ASYNC) { + /* as we didn't request any async notifications, + * some kind of xrun error will probably occurred + */ + /* better resynchronize all streams next interrupt : */ + mgr->dsp_time_last = PCXHR_DSP_TIME_INVALID; + } + mgr->src_it_dsp = reg; + wake_thread = true; + } +#ifdef CONFIG_SND_DEBUG_VERBOSE + if (reg & PCXHR_FATAL_DSP_ERR) + dev_dbg(&mgr->pci->dev, "FATAL DSP ERROR : %x\n", reg); +#endif + + return wake_thread ? IRQ_WAKE_THREAD : IRQ_HANDLED; +} + +irqreturn_t pcxhr_threaded_irq(int irq, void *dev_id) +{ + struct pcxhr_mgr *mgr = dev_id; + int i, j; + struct snd_pcxhr *chip; + + mutex_lock(&mgr->lock); + if (mgr->src_it_dsp & PCXHR_IRQ_TIMER) { /* is a 24 bit counter */ int dsp_time_new = PCXHR_INPL(mgr, PCXHR_PLX_MBOX4) & PCXHR_DSP_TIME_MASK; @@ -1290,13 +1322,6 @@ irqreturn_t pcxhr_interrupt(int irq, void *dev_id) #endif mgr->dsp_time_last = dsp_time_new; - if (timer_toggle == mgr->timer_toggle) { - dev_dbg(&mgr->pci->dev, "ERROR TIMER TOGGLE\n"); - mgr->dsp_time_err++; - } - mgr->timer_toggle = timer_toggle; - - reg &= ~PCXHR_IRQ_TIMER; for (i = 0; i < mgr->num_cards; i++) { chip = mgr->chip[i]; for (j = 0; j < chip->nb_streams_capt; j++) @@ -1312,22 +1337,7 @@ irqreturn_t pcxhr_interrupt(int irq, void *dev_id) dsp_time_diff); } } - /* other irq's handled in the tasklet */ - if (reg & PCXHR_IRQ_MASK) { - if (reg & PCXHR_IRQ_ASYNC) { - /* as we didn't request any async notifications, - * some kind of xrun error will probably occurred - */ - /* better resynchronize all streams next interrupt : */ - mgr->dsp_time_last = PCXHR_DSP_TIME_INVALID; - } - mgr->src_it_dsp = reg; - tasklet_schedule(&mgr->msg_taskq); - } -#ifdef CONFIG_SND_DEBUG_VERBOSE - if (reg & PCXHR_FATAL_DSP_ERR) - dev_dbg(&mgr->pci->dev, "FATAL DSP ERROR : %x\n", reg); -#endif - spin_unlock(&mgr->lock); - return IRQ_HANDLED; /* this device caused the interrupt */ + + pcxhr_msg_thread(mgr); + return IRQ_HANDLED; } diff --git a/sound/pci/pcxhr/pcxhr_core.h b/sound/pci/pcxhr/pcxhr_core.h index a81ab6b811e7..dc267e4c1074 100644 --- a/sound/pci/pcxhr/pcxhr_core.h +++ b/sound/pci/pcxhr/pcxhr_core.h @@ -200,6 +200,6 @@ int pcxhr_write_io_num_reg_cont(struct pcxhr_mgr *mgr, unsigned int mask, /* interrupt handling */ irqreturn_t pcxhr_interrupt(int irq, void *dev_id); -void pcxhr_msg_tasklet(unsigned long arg); +irqreturn_t pcxhr_threaded_irq(int irq, void *dev_id); #endif /* __SOUND_PCXHR_CORE_H */ From 6336c20cdaee1dd13d01dfa8c07ce3b18bbc846f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 Sep 2014 14:01:05 +0200 Subject: [PATCH 155/251] ALSA: lx6464es: Use nonatomic PCM ops Like the other previous changes, this patch for lx6464es takes the same strategy for converting to nonatomic PCM ops: replacing spinlock with mutex, converting the irq tasklet to the threaded irq, and merging the trigger tasklets back to the trigger callback. Signed-off-by: Takashi Iwai --- sound/pci/lx6464es/lx6464es.c | 43 ++---- sound/pci/lx6464es/lx6464es.h | 9 +- sound/pci/lx6464es/lx_core.c | 252 ++++++++++++---------------------- sound/pci/lx6464es/lx_core.h | 4 +- 4 files changed, 108 insertions(+), 200 deletions(-) diff --git a/sound/pci/lx6464es/lx6464es.c b/sound/pci/lx6464es/lx6464es.c index a671f0865f71..601315a1f58f 100644 --- a/sound/pci/lx6464es/lx6464es.c +++ b/sound/pci/lx6464es/lx6464es.c @@ -279,7 +279,6 @@ static snd_pcm_uframes_t lx_pcm_stream_pointer(struct snd_pcm_substream { struct lx6464es *chip = snd_pcm_substream_chip(substream); snd_pcm_uframes_t pos; - unsigned long flags; int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); struct lx_stream *lx_stream = is_capture ? &chip->capture_stream : @@ -287,9 +286,9 @@ static snd_pcm_uframes_t lx_pcm_stream_pointer(struct snd_pcm_substream dev_dbg(chip->card->dev, "->lx_pcm_stream_pointer\n"); - spin_lock_irqsave(&chip->lock, flags); + mutex_lock(&chip->lock); pos = lx_stream->frame_pos * substream->runtime->period_size; - spin_unlock_irqrestore(&chip->lock, flags); + mutex_unlock(&chip->lock); dev_dbg(chip->card->dev, "stream_pointer at %ld\n", pos); return pos; @@ -485,8 +484,8 @@ static void lx_trigger_stop(struct lx6464es *chip, struct lx_stream *lx_stream) } -static void lx_trigger_tasklet_dispatch_stream(struct lx6464es *chip, - struct lx_stream *lx_stream) +static void lx_trigger_dispatch_stream(struct lx6464es *chip, + struct lx_stream *lx_stream) { switch (lx_stream->status) { case LX_STREAM_STATUS_SCHEDULE_RUN: @@ -502,24 +501,12 @@ static void lx_trigger_tasklet_dispatch_stream(struct lx6464es *chip, } } -static void lx_trigger_tasklet(unsigned long data) -{ - struct lx6464es *chip = (struct lx6464es *)data; - unsigned long flags; - - dev_dbg(chip->card->dev, "->lx_trigger_tasklet\n"); - - spin_lock_irqsave(&chip->lock, flags); - lx_trigger_tasklet_dispatch_stream(chip, &chip->capture_stream); - lx_trigger_tasklet_dispatch_stream(chip, &chip->playback_stream); - spin_unlock_irqrestore(&chip->lock, flags); -} - static int lx_pcm_trigger_dispatch(struct lx6464es *chip, struct lx_stream *lx_stream, int cmd) { int err = 0; + mutex_lock(&chip->lock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: lx_stream->status = LX_STREAM_STATUS_SCHEDULE_RUN; @@ -533,9 +520,12 @@ static int lx_pcm_trigger_dispatch(struct lx6464es *chip, err = -EINVAL; goto exit; } - tasklet_schedule(&chip->trigger_tasklet); + + lx_trigger_dispatch_stream(chip, &chip->capture_stream); + lx_trigger_dispatch_stream(chip, &chip->playback_stream); exit: + mutex_unlock(&chip->lock); return err; } @@ -861,6 +851,7 @@ static int lx_pcm_create(struct lx6464es *chip) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &lx_ops_capture); pcm->info_flags = 0; + pcm->nonatomic = true; strcpy(pcm->name, card_name); err = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, @@ -1009,15 +1000,9 @@ static int snd_lx6464es_create(struct snd_card *card, chip->irq = -1; /* initialize synchronization structs */ - spin_lock_init(&chip->lock); - spin_lock_init(&chip->msg_lock); + mutex_init(&chip->lock); + mutex_init(&chip->msg_lock); mutex_init(&chip->setup_mutex); - tasklet_init(&chip->trigger_tasklet, lx_trigger_tasklet, - (unsigned long)chip); - tasklet_init(&chip->tasklet_capture, lx_tasklet_capture, - (unsigned long)chip); - tasklet_init(&chip->tasklet_playback, lx_tasklet_playback, - (unsigned long)chip); /* request resources */ err = pci_request_regions(pci, card_name); @@ -1032,8 +1017,8 @@ static int snd_lx6464es_create(struct snd_card *card, /* dsp port */ chip->port_dsp_bar = pci_ioremap_bar(pci, 2); - err = request_irq(pci->irq, lx_interrupt, IRQF_SHARED, - KBUILD_MODNAME, chip); + err = request_threaded_irq(pci->irq, lx_interrupt, lx_threaded_irq, + IRQF_SHARED, KBUILD_MODNAME, chip); if (err) { dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq); goto request_irq_failed; diff --git a/sound/pci/lx6464es/lx6464es.h b/sound/pci/lx6464es/lx6464es.h index 6792eda9c9a5..1bec187d772f 100644 --- a/sound/pci/lx6464es/lx6464es.h +++ b/sound/pci/lx6464es/lx6464es.h @@ -71,14 +71,10 @@ struct lx6464es { u8 mac_address[6]; - spinlock_t lock; /* interrupt spinlock */ + struct mutex lock; /* interrupt lock */ struct mutex setup_mutex; /* mutex used in hw_params, open * and close */ - struct tasklet_struct trigger_tasklet; /* trigger tasklet */ - struct tasklet_struct tasklet_capture; - struct tasklet_struct tasklet_playback; - /* ports */ unsigned long port_plx; /* io port (size=256) */ void __iomem *port_plx_remapped; /* remapped plx port */ @@ -87,8 +83,9 @@ struct lx6464es { * size=8K) */ /* messaging */ - spinlock_t msg_lock; /* message spinlock */ + struct mutex msg_lock; /* message lock */ struct lx_rmh rmh; + u32 irqsrc; /* configuration */ uint freq_ratio : 2; diff --git a/sound/pci/lx6464es/lx_core.c b/sound/pci/lx6464es/lx_core.c index e8f38e5df10a..f3d62020ef66 100644 --- a/sound/pci/lx6464es/lx_core.c +++ b/sound/pci/lx6464es/lx_core.c @@ -332,27 +332,25 @@ polling_successful: int lx_dsp_get_version(struct lx6464es *chip, u32 *rdsp_version) { u16 ret; - unsigned long flags; - spin_lock_irqsave(&chip->msg_lock, flags); + mutex_lock(&chip->msg_lock); lx_message_init(&chip->rmh, CMD_01_GET_SYS_CFG); ret = lx_message_send_atomic(chip, &chip->rmh); *rdsp_version = chip->rmh.stat[1]; - spin_unlock_irqrestore(&chip->msg_lock, flags); + mutex_unlock(&chip->msg_lock); return ret; } int lx_dsp_get_clock_frequency(struct lx6464es *chip, u32 *rfreq) { u16 ret = 0; - unsigned long flags; u32 freq_raw = 0; u32 freq = 0; u32 frequency = 0; - spin_lock_irqsave(&chip->msg_lock, flags); + mutex_lock(&chip->msg_lock); lx_message_init(&chip->rmh, CMD_01_GET_SYS_CFG); ret = lx_message_send_atomic(chip, &chip->rmh); @@ -370,7 +368,7 @@ int lx_dsp_get_clock_frequency(struct lx6464es *chip, u32 *rfreq) frequency = 48000; } - spin_unlock_irqrestore(&chip->msg_lock, flags); + mutex_unlock(&chip->msg_lock); *rfreq = frequency * chip->freq_ratio; @@ -398,25 +396,23 @@ int lx_dsp_get_mac(struct lx6464es *chip) int lx_dsp_set_granularity(struct lx6464es *chip, u32 gran) { - unsigned long flags; int ret; - spin_lock_irqsave(&chip->msg_lock, flags); + mutex_lock(&chip->msg_lock); lx_message_init(&chip->rmh, CMD_02_SET_GRANULARITY); chip->rmh.cmd[0] |= gran; ret = lx_message_send_atomic(chip, &chip->rmh); - spin_unlock_irqrestore(&chip->msg_lock, flags); + mutex_unlock(&chip->msg_lock); return ret; } int lx_dsp_read_async_events(struct lx6464es *chip, u32 *data) { - unsigned long flags; int ret; - spin_lock_irqsave(&chip->msg_lock, flags); + mutex_lock(&chip->msg_lock); lx_message_init(&chip->rmh, CMD_04_GET_EVENT); chip->rmh.stat_len = 9; /* we don't necessarily need the full length */ @@ -426,7 +422,7 @@ int lx_dsp_read_async_events(struct lx6464es *chip, u32 *data) if (!ret) memcpy(data, chip->rmh.stat, chip->rmh.stat_len * sizeof(u32)); - spin_unlock_irqrestore(&chip->msg_lock, flags); + mutex_unlock(&chip->msg_lock); return ret; } @@ -440,18 +436,16 @@ int lx_pipe_allocate(struct lx6464es *chip, u32 pipe, int is_capture, int channels) { int err; - unsigned long flags; - u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); - spin_lock_irqsave(&chip->msg_lock, flags); + mutex_lock(&chip->msg_lock); lx_message_init(&chip->rmh, CMD_06_ALLOCATE_PIPE); chip->rmh.cmd[0] |= pipe_cmd; chip->rmh.cmd[0] |= channels; err = lx_message_send_atomic(chip, &chip->rmh); - spin_unlock_irqrestore(&chip->msg_lock, flags); + mutex_unlock(&chip->msg_lock); if (err != 0) dev_err(chip->card->dev, "could not allocate pipe\n"); @@ -462,17 +456,15 @@ int lx_pipe_allocate(struct lx6464es *chip, u32 pipe, int is_capture, int lx_pipe_release(struct lx6464es *chip, u32 pipe, int is_capture) { int err; - unsigned long flags; - u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); - spin_lock_irqsave(&chip->msg_lock, flags); + mutex_lock(&chip->msg_lock); lx_message_init(&chip->rmh, CMD_07_RELEASE_PIPE); chip->rmh.cmd[0] |= pipe_cmd; err = lx_message_send_atomic(chip, &chip->rmh); - spin_unlock_irqrestore(&chip->msg_lock, flags); + mutex_unlock(&chip->msg_lock); return err; } @@ -481,8 +473,6 @@ int lx_buffer_ask(struct lx6464es *chip, u32 pipe, int is_capture, u32 *r_needed, u32 *r_freed, u32 *size_array) { int err; - unsigned long flags; - u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); #ifdef CONFIG_SND_DEBUG @@ -493,7 +483,7 @@ int lx_buffer_ask(struct lx6464es *chip, u32 pipe, int is_capture, *r_needed = 0; *r_freed = 0; - spin_lock_irqsave(&chip->msg_lock, flags); + mutex_lock(&chip->msg_lock); lx_message_init(&chip->rmh, CMD_08_ASK_BUFFERS); chip->rmh.cmd[0] |= pipe_cmd; @@ -527,7 +517,7 @@ int lx_buffer_ask(struct lx6464es *chip, u32 pipe, int is_capture, } } - spin_unlock_irqrestore(&chip->msg_lock, flags); + mutex_unlock(&chip->msg_lock); return err; } @@ -535,36 +525,32 @@ int lx_buffer_ask(struct lx6464es *chip, u32 pipe, int is_capture, int lx_pipe_stop(struct lx6464es *chip, u32 pipe, int is_capture) { int err; - unsigned long flags; - u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); - spin_lock_irqsave(&chip->msg_lock, flags); + mutex_lock(&chip->msg_lock); lx_message_init(&chip->rmh, CMD_09_STOP_PIPE); chip->rmh.cmd[0] |= pipe_cmd; err = lx_message_send_atomic(chip, &chip->rmh); - spin_unlock_irqrestore(&chip->msg_lock, flags); + mutex_unlock(&chip->msg_lock); return err; } static int lx_pipe_toggle_state(struct lx6464es *chip, u32 pipe, int is_capture) { int err; - unsigned long flags; - u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); - spin_lock_irqsave(&chip->msg_lock, flags); + mutex_lock(&chip->msg_lock); lx_message_init(&chip->rmh, CMD_0B_TOGGLE_PIPE_STATE); chip->rmh.cmd[0] |= pipe_cmd; err = lx_message_send_atomic(chip, &chip->rmh); - spin_unlock_irqrestore(&chip->msg_lock, flags); + mutex_unlock(&chip->msg_lock); return err; } @@ -600,11 +586,9 @@ int lx_pipe_sample_count(struct lx6464es *chip, u32 pipe, int is_capture, u64 *rsample_count) { int err; - unsigned long flags; - u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); - spin_lock_irqsave(&chip->msg_lock, flags); + mutex_lock(&chip->msg_lock); lx_message_init(&chip->rmh, CMD_0A_GET_PIPE_SPL_COUNT); chip->rmh.cmd[0] |= pipe_cmd; @@ -621,18 +605,16 @@ int lx_pipe_sample_count(struct lx6464es *chip, u32 pipe, int is_capture, + chip->rmh.stat[1]; /* lo part */ } - spin_unlock_irqrestore(&chip->msg_lock, flags); + mutex_unlock(&chip->msg_lock); return err; } int lx_pipe_state(struct lx6464es *chip, u32 pipe, int is_capture, u16 *rstate) { int err; - unsigned long flags; - u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); - spin_lock_irqsave(&chip->msg_lock, flags); + mutex_lock(&chip->msg_lock); lx_message_init(&chip->rmh, CMD_0A_GET_PIPE_SPL_COUNT); chip->rmh.cmd[0] |= pipe_cmd; @@ -644,7 +626,7 @@ int lx_pipe_state(struct lx6464es *chip, u32 pipe, int is_capture, u16 *rstate) else *rstate = (chip->rmh.stat[0] >> PSTATE_OFFSET) & 0x0F; - spin_unlock_irqrestore(&chip->msg_lock, flags); + mutex_unlock(&chip->msg_lock); return err; } @@ -686,18 +668,16 @@ int lx_stream_set_state(struct lx6464es *chip, u32 pipe, int is_capture, enum stream_state_t state) { int err; - unsigned long flags; - u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); - spin_lock_irqsave(&chip->msg_lock, flags); + mutex_lock(&chip->msg_lock); lx_message_init(&chip->rmh, CMD_13_SET_STREAM_STATE); chip->rmh.cmd[0] |= pipe_cmd; chip->rmh.cmd[0] |= state; err = lx_message_send_atomic(chip, &chip->rmh); - spin_unlock_irqrestore(&chip->msg_lock, flags); + mutex_unlock(&chip->msg_lock); return err; } @@ -706,17 +686,14 @@ int lx_stream_set_format(struct lx6464es *chip, struct snd_pcm_runtime *runtime, u32 pipe, int is_capture) { int err; - unsigned long flags; - u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); - u32 channels = runtime->channels; if (runtime->channels != channels) dev_err(chip->card->dev, "channel count mismatch: %d vs %d", runtime->channels, channels); - spin_lock_irqsave(&chip->msg_lock, flags); + mutex_lock(&chip->msg_lock); lx_message_init(&chip->rmh, CMD_0C_DEF_STREAM); chip->rmh.cmd[0] |= pipe_cmd; @@ -732,7 +709,7 @@ int lx_stream_set_format(struct lx6464es *chip, struct snd_pcm_runtime *runtime, chip->rmh.cmd[0] |= channels-1; err = lx_message_send_atomic(chip, &chip->rmh); - spin_unlock_irqrestore(&chip->msg_lock, flags); + mutex_unlock(&chip->msg_lock); return err; } @@ -741,11 +718,9 @@ int lx_stream_state(struct lx6464es *chip, u32 pipe, int is_capture, int *rstate) { int err; - unsigned long flags; - u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); - spin_lock_irqsave(&chip->msg_lock, flags); + mutex_lock(&chip->msg_lock); lx_message_init(&chip->rmh, CMD_0E_GET_STREAM_SPL_COUNT); chip->rmh.cmd[0] |= pipe_cmd; @@ -754,7 +729,7 @@ int lx_stream_state(struct lx6464es *chip, u32 pipe, int is_capture, *rstate = (chip->rmh.stat[0] & SF_START) ? START_STATE : PAUSE_STATE; - spin_unlock_irqrestore(&chip->msg_lock, flags); + mutex_unlock(&chip->msg_lock); return err; } @@ -762,11 +737,9 @@ int lx_stream_sample_position(struct lx6464es *chip, u32 pipe, int is_capture, u64 *r_bytepos) { int err; - unsigned long flags; - u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); - spin_lock_irqsave(&chip->msg_lock, flags); + mutex_lock(&chip->msg_lock); lx_message_init(&chip->rmh, CMD_0E_GET_STREAM_SPL_COUNT); chip->rmh.cmd[0] |= pipe_cmd; @@ -777,7 +750,7 @@ int lx_stream_sample_position(struct lx6464es *chip, u32 pipe, int is_capture, << 32) /* hi part */ + chip->rmh.stat[1]; /* lo part */ - spin_unlock_irqrestore(&chip->msg_lock, flags); + mutex_unlock(&chip->msg_lock); return err; } @@ -787,11 +760,9 @@ int lx_buffer_give(struct lx6464es *chip, u32 pipe, int is_capture, u32 *r_buffer_index) { int err; - unsigned long flags; - u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); - spin_lock_irqsave(&chip->msg_lock, flags); + mutex_lock(&chip->msg_lock); lx_message_init(&chip->rmh, CMD_0F_UPDATE_BUFFER); chip->rmh.cmd[0] |= pipe_cmd; @@ -828,7 +799,7 @@ int lx_buffer_give(struct lx6464es *chip, u32 pipe, int is_capture, "lx_buffer_give EB_CMD_REFUSED\n"); done: - spin_unlock_irqrestore(&chip->msg_lock, flags); + mutex_unlock(&chip->msg_lock); return err; } @@ -836,11 +807,9 @@ int lx_buffer_free(struct lx6464es *chip, u32 pipe, int is_capture, u32 *r_buffer_size) { int err; - unsigned long flags; - u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); - spin_lock_irqsave(&chip->msg_lock, flags); + mutex_lock(&chip->msg_lock); lx_message_init(&chip->rmh, CMD_11_CANCEL_BUFFER); chip->rmh.cmd[0] |= pipe_cmd; @@ -852,7 +821,7 @@ int lx_buffer_free(struct lx6464es *chip, u32 pipe, int is_capture, if (err == 0) *r_buffer_size = chip->rmh.stat[0] & MASK_DATA_SIZE; - spin_unlock_irqrestore(&chip->msg_lock, flags); + mutex_unlock(&chip->msg_lock); return err; } @@ -860,11 +829,9 @@ int lx_buffer_cancel(struct lx6464es *chip, u32 pipe, int is_capture, u32 buffer_index) { int err; - unsigned long flags; - u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); - spin_lock_irqsave(&chip->msg_lock, flags); + mutex_lock(&chip->msg_lock); lx_message_init(&chip->rmh, CMD_11_CANCEL_BUFFER); chip->rmh.cmd[0] |= pipe_cmd; @@ -872,7 +839,7 @@ int lx_buffer_cancel(struct lx6464es *chip, u32 pipe, int is_capture, err = lx_message_send_atomic(chip, &chip->rmh); - spin_unlock_irqrestore(&chip->msg_lock, flags); + mutex_unlock(&chip->msg_lock); return err; } @@ -885,12 +852,10 @@ int lx_buffer_cancel(struct lx6464es *chip, u32 pipe, int is_capture, int lx_level_unmute(struct lx6464es *chip, int is_capture, int unmute) { int err; - unsigned long flags; - /* bit set to 1: channel muted */ u64 mute_mask = unmute ? 0 : 0xFFFFFFFFFFFFFFFFLLU; - spin_lock_irqsave(&chip->msg_lock, flags); + mutex_lock(&chip->msg_lock); lx_message_init(&chip->rmh, CMD_0D_SET_MUTE); chip->rmh.cmd[0] |= PIPE_INFO_TO_CMD(is_capture, 0); @@ -904,7 +869,7 @@ int lx_level_unmute(struct lx6464es *chip, int is_capture, int unmute) err = lx_message_send_atomic(chip, &chip->rmh); - spin_unlock_irqrestore(&chip->msg_lock, flags); + mutex_unlock(&chip->msg_lock); return err; } @@ -931,10 +896,9 @@ int lx_level_peaks(struct lx6464es *chip, int is_capture, int channels, u32 *r_levels) { int err = 0; - unsigned long flags; int i; - spin_lock_irqsave(&chip->msg_lock, flags); + mutex_lock(&chip->msg_lock); for (i = 0; i < channels; i += 4) { u32 s0, s1, s2, s3; @@ -959,7 +923,7 @@ int lx_level_peaks(struct lx6464es *chip, int is_capture, int channels, r_levels += 4; } - spin_unlock_irqrestore(&chip->msg_lock, flags); + mutex_unlock(&chip->msg_lock); return err; } @@ -1075,7 +1039,6 @@ static int lx_interrupt_request_new_buffer(struct lx6464es *chip, struct snd_pcm_substream *substream = lx_stream->stream; const unsigned int is_capture = lx_stream->is_capture; int err; - unsigned long flags; const u32 channels = substream->runtime->channels; const u32 bytes_per_frame = channels * 3; @@ -1095,7 +1058,7 @@ static int lx_interrupt_request_new_buffer(struct lx6464es *chip, dev_dbg(chip->card->dev, "->lx_interrupt_request_new_buffer\n"); - spin_lock_irqsave(&chip->lock, flags); + mutex_lock(&chip->lock); err = lx_buffer_ask(chip, 0, is_capture, &needed, &freed, size_array); dev_dbg(chip->card->dev, @@ -1109,85 +1072,28 @@ static int lx_interrupt_request_new_buffer(struct lx6464es *chip, buffer_index, (unsigned long)buf, period_bytes); lx_stream->frame_pos = next_pos; - spin_unlock_irqrestore(&chip->lock, flags); + mutex_unlock(&chip->lock); return err; } -void lx_tasklet_playback(unsigned long data) -{ - struct lx6464es *chip = (struct lx6464es *)data; - struct lx_stream *lx_stream = &chip->playback_stream; - int err; - - dev_dbg(chip->card->dev, "->lx_tasklet_playback\n"); - - err = lx_interrupt_request_new_buffer(chip, lx_stream); - if (err < 0) - dev_err(chip->card->dev, - "cannot request new buffer for playback\n"); - - snd_pcm_period_elapsed(lx_stream->stream); -} - -void lx_tasklet_capture(unsigned long data) -{ - struct lx6464es *chip = (struct lx6464es *)data; - struct lx_stream *lx_stream = &chip->capture_stream; - int err; - - dev_dbg(chip->card->dev, "->lx_tasklet_capture\n"); - err = lx_interrupt_request_new_buffer(chip, lx_stream); - if (err < 0) - dev_err(chip->card->dev, - "cannot request new buffer for capture\n"); - - snd_pcm_period_elapsed(lx_stream->stream); -} - - - -static int lx_interrupt_handle_audio_transfer(struct lx6464es *chip, - u64 notified_in_pipe_mask, - u64 notified_out_pipe_mask) -{ - int err = 0; - - if (notified_in_pipe_mask) { - dev_dbg(chip->card->dev, - "requesting audio transfer for capture\n"); - tasklet_hi_schedule(&chip->tasklet_capture); - } - - if (notified_out_pipe_mask) { - dev_dbg(chip->card->dev, - "requesting audio transfer for playback\n"); - tasklet_hi_schedule(&chip->tasklet_playback); - } - - return err; -} - - irqreturn_t lx_interrupt(int irq, void *dev_id) { struct lx6464es *chip = dev_id; int async_pending, async_escmd; u32 irqsrc; - - spin_lock(&chip->lock); + bool wake_thread = false; dev_dbg(chip->card->dev, "**************************************************\n"); if (!lx_interrupt_ack(chip, &irqsrc, &async_pending, &async_escmd)) { - spin_unlock(&chip->lock); dev_dbg(chip->card->dev, "IRQ_NONE\n"); return IRQ_NONE; /* this device did not cause the interrupt */ } if (irqsrc & MASK_SYS_STATUS_CMD_DONE) - goto exit; + return IRQ_HANDLED; if (irqsrc & MASK_SYS_STATUS_EOBI) dev_dbg(chip->card->dev, "interrupt: EOBI\n"); @@ -1202,27 +1108,8 @@ irqreturn_t lx_interrupt(int irq, void *dev_id) dev_dbg(chip->card->dev, "interrupt: ORUN\n"); if (async_pending) { - u64 notified_in_pipe_mask = 0; - u64 notified_out_pipe_mask = 0; - int freq_changed; - int err; - - /* handle async events */ - err = lx_interrupt_handle_async_events(chip, irqsrc, - &freq_changed, - ¬ified_in_pipe_mask, - ¬ified_out_pipe_mask); - if (err) - dev_err(chip->card->dev, - "error handling async events\n"); - - err = lx_interrupt_handle_audio_transfer(chip, - notified_in_pipe_mask, - notified_out_pipe_mask - ); - if (err) - dev_err(chip->card->dev, - "error during audio transfer\n"); + wake_thread = true; + chip->irqsrc = irqsrc; } if (async_escmd) { @@ -1235,9 +1122,50 @@ irqreturn_t lx_interrupt(int irq, void *dev_id) dev_dbg(chip->card->dev, "interrupt requests escmd handling\n"); } -exit: - spin_unlock(&chip->lock); - return IRQ_HANDLED; /* this device caused the interrupt */ + return wake_thread ? IRQ_WAKE_THREAD : IRQ_HANDLED; +} + +irqreturn_t lx_threaded_irq(int irq, void *dev_id) +{ + struct lx6464es *chip = dev_id; + u64 notified_in_pipe_mask = 0; + u64 notified_out_pipe_mask = 0; + int freq_changed; + int err; + + /* handle async events */ + err = lx_interrupt_handle_async_events(chip, chip->irqsrc, + &freq_changed, + ¬ified_in_pipe_mask, + ¬ified_out_pipe_mask); + if (err) + dev_err(chip->card->dev, "error handling async events\n"); + + if (notified_in_pipe_mask) { + struct lx_stream *lx_stream = &chip->capture_stream; + + dev_dbg(chip->card->dev, + "requesting audio transfer for capture\n"); + err = lx_interrupt_request_new_buffer(chip, lx_stream); + if (err < 0) + dev_err(chip->card->dev, + "cannot request new buffer for capture\n"); + snd_pcm_period_elapsed(lx_stream->stream); + } + + if (notified_out_pipe_mask) { + struct lx_stream *lx_stream = &chip->playback_stream; + + dev_dbg(chip->card->dev, + "requesting audio transfer for playback\n"); + err = lx_interrupt_request_new_buffer(chip, lx_stream); + if (err < 0) + dev_err(chip->card->dev, + "cannot request new buffer for playback\n"); + snd_pcm_period_elapsed(lx_stream->stream); + } + + return IRQ_HANDLED; } diff --git a/sound/pci/lx6464es/lx_core.h b/sound/pci/lx6464es/lx_core.h index 5ec5e04da1a5..0cc140ca98e3 100644 --- a/sound/pci/lx6464es/lx_core.h +++ b/sound/pci/lx6464es/lx_core.h @@ -181,12 +181,10 @@ int lx_level_peaks(struct lx6464es *chip, int is_capture, int channels, /* interrupt handling */ irqreturn_t lx_interrupt(int irq, void *dev_id); +irqreturn_t lx_threaded_irq(int irq, void *dev_id); void lx_irq_enable(struct lx6464es *chip); void lx_irq_disable(struct lx6464es *chip); -void lx_tasklet_capture(unsigned long data); -void lx_tasklet_playback(unsigned long data); - /* Stream Format Header Defines (for LIN and IEEE754) */ #define HEADER_FMT_BASE HEADER_FMT_BASE_LIN From 3b73cfe5598eda7f5540608acd63b86688242731 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 Sep 2014 14:58:59 +0200 Subject: [PATCH 156/251] ALSA: pdaudiocf: Use nonatomic PCM ops Like other fixes, convert the tasklet to a threaded irq and replace spinlock with mutex appropriately. ak4117_lock remains as spinlock since it's called in another spinlock context from ak4117 driver. Signed-off-by: Takashi Iwai --- sound/pcmcia/pdaudiocf/pdaudiocf.c | 13 +++++++++---- sound/pcmcia/pdaudiocf/pdaudiocf.h | 5 ++--- sound/pcmcia/pdaudiocf/pdaudiocf_core.c | 8 +++----- sound/pcmcia/pdaudiocf/pdaudiocf_irq.c | 23 ++++++++++++----------- sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c | 5 +++-- 5 files changed, 29 insertions(+), 25 deletions(-) diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf.c b/sound/pcmcia/pdaudiocf/pdaudiocf.c index 56bda124cd4a..07f4b33db3af 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf.c @@ -61,6 +61,7 @@ static void snd_pdacf_detach(struct pcmcia_device *p_dev); static void pdacf_release(struct pcmcia_device *link) { + free_irq(link->irq, link->priv); pcmcia_disable_device(link); } @@ -220,11 +221,13 @@ static int pdacf_config(struct pcmcia_device *link) ret = pcmcia_request_io(link); if (ret) - goto failed; + goto failed_preirq; - ret = pcmcia_request_irq(link, pdacf_interrupt); + ret = request_threaded_irq(link->irq, pdacf_interrupt, + pdacf_threaded_irq, + IRQF_SHARED, link->devname, link->priv); if (ret) - goto failed; + goto failed_preirq; ret = pcmcia_enable_device(link); if (ret) @@ -236,7 +239,9 @@ static int pdacf_config(struct pcmcia_device *link) return 0; -failed: + failed: + free_irq(link->irq, link->priv); +failed_preirq: pcmcia_disable_device(link); return -ENODEV; } diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf.h b/sound/pcmcia/pdaudiocf/pdaudiocf.h index ea41e57d7179..e9a7d3a784f7 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf.h +++ b/sound/pcmcia/pdaudiocf/pdaudiocf.h @@ -88,10 +88,9 @@ struct snd_pdacf { unsigned long port; int irq; - spinlock_t reg_lock; + struct mutex reg_lock; unsigned short regmap[8]; unsigned short suspend_reg_scr; - struct tasklet_struct tq; spinlock_t ak4117_lock; struct ak4117 *ak4117; @@ -136,7 +135,7 @@ int snd_pdacf_resume(struct snd_pdacf *chip); #endif int snd_pdacf_pcm_new(struct snd_pdacf *chip); irqreturn_t pdacf_interrupt(int irq, void *dev); -void pdacf_tasklet(unsigned long private_data); +irqreturn_t pdacf_threaded_irq(int irq, void *dev); void pdacf_reinit(struct snd_pdacf *chip, int resume); #endif /* __PDAUDIOCF_H */ diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf_core.c b/sound/pcmcia/pdaudiocf/pdaudiocf_core.c index ea0adfb984ad..d724ab0653cf 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf_core.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf_core.c @@ -162,9 +162,8 @@ struct snd_pdacf *snd_pdacf_create(struct snd_card *card) if (chip == NULL) return NULL; chip->card = card; - spin_lock_init(&chip->reg_lock); + mutex_init(&chip->reg_lock); spin_lock_init(&chip->ak4117_lock); - tasklet_init(&chip->tq, pdacf_tasklet, (unsigned long)chip); card->private_data = chip; pdacf_proc_init(chip); @@ -174,19 +173,18 @@ struct snd_pdacf *snd_pdacf_create(struct snd_card *card) static void snd_pdacf_ak4117_change(struct ak4117 *ak4117, unsigned char c0, unsigned char c1) { struct snd_pdacf *chip = ak4117->change_callback_private; - unsigned long flags; u16 val; if (!(c0 & AK4117_UNLCK)) return; - spin_lock_irqsave(&chip->reg_lock, flags); + mutex_lock(&chip->reg_lock); val = chip->regmap[PDAUDIOCF_REG_SCR>>1]; if (ak4117->rcs0 & AK4117_UNLCK) val |= PDAUDIOCF_BLUE_LED_OFF; else val &= ~PDAUDIOCF_BLUE_LED_OFF; pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, val); - spin_unlock_irqrestore(&chip->reg_lock, flags); + mutex_unlock(&chip->reg_lock); } int snd_pdacf_ak4117_create(struct snd_pdacf *chip) diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c b/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c index dcd32201bc8c..ecf0fbd91794 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c @@ -30,6 +30,7 @@ irqreturn_t pdacf_interrupt(int irq, void *dev) { struct snd_pdacf *chip = dev; unsigned short stat; + bool wake_thread = false; if ((chip->chip_status & (PDAUDIOCF_STAT_IS_STALE| PDAUDIOCF_STAT_IS_CONFIGURED| @@ -41,13 +42,13 @@ irqreturn_t pdacf_interrupt(int irq, void *dev) if (stat & PDAUDIOCF_IRQOVR) /* should never happen */ snd_printk(KERN_ERR "PDAUDIOCF SRAM buffer overrun detected!\n"); if (chip->pcm_substream) - tasklet_schedule(&chip->tq); + wake_thread = true; if (!(stat & PDAUDIOCF_IRQAKM)) stat |= PDAUDIOCF_IRQAKM; /* check rate */ } if (get_irq_regs() != NULL) snd_ak4117_check_rate_and_errors(chip->ak4117, 0); - return IRQ_HANDLED; + return wake_thread ? IRQ_WAKE_THREAD : IRQ_HANDLED; } static inline void pdacf_transfer_mono16(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port) @@ -256,16 +257,16 @@ static void pdacf_transfer(struct snd_pdacf *chip, unsigned int size, unsigned i } } -void pdacf_tasklet(unsigned long private_data) +irqreturn_t pdacf_threaded_irq(int irq, void *dev) { - struct snd_pdacf *chip = (struct snd_pdacf *) private_data; + struct snd_pdacf *chip = dev; int size, off, cont, rdp, wdp; if ((chip->chip_status & (PDAUDIOCF_STAT_IS_STALE|PDAUDIOCF_STAT_IS_CONFIGURED)) != PDAUDIOCF_STAT_IS_CONFIGURED) - return; + return IRQ_HANDLED; if (chip->pcm_substream == NULL || chip->pcm_substream->runtime == NULL || !snd_pcm_running(chip->pcm_substream)) - return; + return IRQ_HANDLED; rdp = inw(chip->port + PDAUDIOCF_REG_RDP); wdp = inw(chip->port + PDAUDIOCF_REG_WDP); @@ -311,15 +312,15 @@ void pdacf_tasklet(unsigned long private_data) size -= cont; } #endif - spin_lock(&chip->reg_lock); + mutex_lock(&chip->reg_lock); while (chip->pcm_tdone >= chip->pcm_period) { chip->pcm_hwptr += chip->pcm_period; chip->pcm_hwptr %= chip->pcm_size; chip->pcm_tdone -= chip->pcm_period; - spin_unlock(&chip->reg_lock); + mutex_unlock(&chip->reg_lock); snd_pcm_period_elapsed(chip->pcm_substream); - spin_lock(&chip->reg_lock); + mutex_lock(&chip->reg_lock); } - spin_unlock(&chip->reg_lock); - /* printk(KERN_DEBUG "TASKLET: end\n"); */ + mutex_unlock(&chip->reg_lock); + return IRQ_HANDLED; } diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c b/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c index 43f995a3f960..b48aa0a78c19 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c @@ -77,7 +77,7 @@ static int pdacf_pcm_trigger(struct snd_pcm_substream *subs, int cmd) default: return -EINVAL; } - spin_lock(&chip->reg_lock); + mutex_lock(&chip->reg_lock); chip->pcm_running += inc; tmp = pdacf_reg_read(chip, PDAUDIOCF_REG_SCR); if (chip->pcm_running) { @@ -91,7 +91,7 @@ static int pdacf_pcm_trigger(struct snd_pcm_substream *subs, int cmd) tmp |= val; pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, tmp); __end: - spin_unlock(&chip->reg_lock); + mutex_unlock(&chip->reg_lock); snd_ak4117_check_rate_and_errors(chip->ak4117, AK4117_CHECK_NO_RATE); return ret; } @@ -296,6 +296,7 @@ int snd_pdacf_pcm_new(struct snd_pdacf *chip) pcm->private_data = chip; pcm->info_flags = 0; + pcm->nonatomic = true; strcpy(pcm->name, chip->card->shortname); chip->pcm = pcm; From 941a74ca9e666595910751f4187797d5e1424565 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 15 Sep 2014 15:22:02 +0200 Subject: [PATCH 157/251] ALSA: Update document about PCM nonatomic ops Signed-off-by: Takashi Iwai --- .../DocBook/writing-an-alsa-driver.tmpl | 28 +++++++++++++++---- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/Documentation/DocBook/writing-an-alsa-driver.tmpl b/Documentation/DocBook/writing-an-alsa-driver.tmpl index 6f639d9530b5..784793df81ed 100644 --- a/Documentation/DocBook/writing-an-alsa-driver.tmpl +++ b/Documentation/DocBook/writing-an-alsa-driver.tmpl @@ -2742,7 +2742,9 @@ struct _snd_pcm_runtime { Another note is that this callback is non-atomic - (schedulable). This is important, because the + (schedulable) as default, i.e. when no + nonatomic flag set. + This is important, because the trigger callback is atomic (non-schedulable). That is, mutexes or any schedule-related functions are not available in @@ -2900,8 +2902,9 @@ struct _snd_pcm_runtime { - As mentioned, this callback is atomic. You cannot call - functions which may sleep. + As mentioned, this callback is atomic as default unless + nonatomic flag set, and + you cannot call functions which may sleep. The trigger callback should be as minimal as possible, just really triggering the DMA. The other stuff should be initialized hw_params and prepare callbacks properly @@ -2936,7 +2939,7 @@ struct _snd_pcm_runtime { - This callback is also atomic. + This callback is also atomic as default. @@ -2972,7 +2975,7 @@ struct _snd_pcm_runtime { is useful only for such a purpose. - This callback is atomic. + This callback is atomic as default. @@ -3175,6 +3178,21 @@ struct _snd_pcm_runtime { called with local interrupts disabled. + + The recent changes in PCM core code, however, allow all PCM + operations to be non-atomic. This assumes that the all caller + sides are in non-atomic contexts. For example, the function + snd_pcm_period_elapsed() is called + typically from the interrupt handler. But, if you set up the + driver to use a threaded interrupt handler, this call can be in + non-atomic context, too. In such a case, you can set + nonatomic filed of + snd_pcm object after creating it. + When this flag is set, mutex and rwsem are used internally in + the PCM core instead of spin and rwlocks, so that you can call + all PCM functions safely in a non-atomic context. + +
Constraints From e5b2791d2a57e9da369bd75ae2a209bcce2ad4d3 Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Mon, 15 Sep 2014 19:58:44 +0800 Subject: [PATCH 158/251] ASoC: rt5677: Revise the wrong name in the header file The patch revises the wrong name in the header file. Signed-off-by: Oder Chiou Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677.h | 44 +++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/sound/soc/codecs/rt5677.h b/sound/soc/codecs/rt5677.h index 8791ab9637f3..a334eb66cfc1 100644 --- a/sound/soc/codecs/rt5677.h +++ b/sound/soc/codecs/rt5677.h @@ -1287,16 +1287,16 @@ #define RT5677_PLL1_PD_SFT 8 #define RT5677_PLL1_PD_1 (0x0 << 8) #define RT5677_PLL1_PD_2 (0x1 << 8) -#define RT5671_DAC_OSR_MASK (0x3 << 6) -#define RT5671_DAC_OSR_SFT 6 -#define RT5671_DAC_OSR_128 (0x0 << 6) -#define RT5671_DAC_OSR_64 (0x1 << 6) -#define RT5671_DAC_OSR_32 (0x2 << 6) -#define RT5671_ADC_OSR_MASK (0x3 << 4) -#define RT5671_ADC_OSR_SFT 4 -#define RT5671_ADC_OSR_128 (0x0 << 4) -#define RT5671_ADC_OSR_64 (0x1 << 4) -#define RT5671_ADC_OSR_32 (0x2 << 4) +#define RT5677_DAC_OSR_MASK (0x3 << 6) +#define RT5677_DAC_OSR_SFT 6 +#define RT5677_DAC_OSR_128 (0x0 << 6) +#define RT5677_DAC_OSR_64 (0x1 << 6) +#define RT5677_DAC_OSR_32 (0x2 << 6) +#define RT5677_ADC_OSR_MASK (0x3 << 4) +#define RT5677_ADC_OSR_SFT 4 +#define RT5677_ADC_OSR_128 (0x0 << 4) +#define RT5677_ADC_OSR_64 (0x1 << 4) +#define RT5677_ADC_OSR_32 (0x2 << 4) /* Global Clock Control 2 (0x81) */ #define RT5677_PLL2_PR_SRC_MASK (0x1 << 15) @@ -1312,18 +1312,18 @@ #define RT5677_PLL2_SRC_BCLK4 (0x4 << 12) #define RT5677_PLL2_SRC_RCCLK (0x5 << 12) #define RT5677_PLL2_SRC_SLIM (0x6 << 12) -#define RT5671_DSP_ASRC_O_SRC (0x3 << 10) -#define RT5671_DSP_ASRC_O_SRC_SFT 10 -#define RT5671_DSP_ASRC_O_MCLK (0x0 << 10) -#define RT5671_DSP_ASRC_O_PLL1 (0x1 << 10) -#define RT5671_DSP_ASRC_O_SLIM (0x2 << 10) -#define RT5671_DSP_ASRC_O_RCCLK (0x3 << 10) -#define RT5671_DSP_ASRC_I_SRC (0x3 << 8) -#define RT5671_DSP_ASRC_I_SRC_SFT 8 -#define RT5671_DSP_ASRC_I_MCLK (0x0 << 8) -#define RT5671_DSP_ASRC_I_PLL1 (0x1 << 8) -#define RT5671_DSP_ASRC_I_SLIM (0x2 << 8) -#define RT5671_DSP_ASRC_I_RCCLK (0x3 << 8) +#define RT5677_DSP_ASRC_O_SRC (0x3 << 10) +#define RT5677_DSP_ASRC_O_SRC_SFT 10 +#define RT5677_DSP_ASRC_O_MCLK (0x0 << 10) +#define RT5677_DSP_ASRC_O_PLL1 (0x1 << 10) +#define RT5677_DSP_ASRC_O_SLIM (0x2 << 10) +#define RT5677_DSP_ASRC_O_RCCLK (0x3 << 10) +#define RT5677_DSP_ASRC_I_SRC (0x3 << 8) +#define RT5677_DSP_ASRC_I_SRC_SFT 8 +#define RT5677_DSP_ASRC_I_MCLK (0x0 << 8) +#define RT5677_DSP_ASRC_I_PLL1 (0x1 << 8) +#define RT5677_DSP_ASRC_I_SLIM (0x2 << 8) +#define RT5677_DSP_ASRC_I_RCCLK (0x3 << 8) #define RT5677_DSP_CLK_SRC_MASK (0x1 << 7) #define RT5677_DSP_CLK_SRC_SFT 7 #define RT5677_DSP_CLK_SRC_PLL2 (0x0 << 7) From 1a4f69d5aaecb39a980fc20b14ec800fd5b53061 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 11 Sep 2014 15:22:46 +0200 Subject: [PATCH 159/251] ALSA: hda - Allow multiple callbacks for jack So far, hda_jack infrastructure allows only one callback per jack, and this makes things slightly complicated when a driver wants to assign multiple tasks to a jack, e.g. the standard auto-mute with a power up/down sequence. This can be simplified if the hda_jack accepts multiple callbacks. This patch is such an extension: the callback-specific part (the function and private_data) is split to another struct from hda_jack_tbl, and multiple such objects can be assigned to a single hda_jack_tbl entry. The new struct hda_jack_callback is passed to each callback function now, thus the patch became bigger than expected. But these changes are mostly trivial. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_generic.c | 19 +++++++---- sound/pci/hda/hda_generic.h | 12 +++---- sound/pci/hda/hda_jack.c | 58 ++++++++++++++++++++++------------ sound/pci/hda/hda_jack.h | 17 +++++++--- sound/pci/hda/patch_cirrus.c | 2 +- sound/pci/hda/patch_conexant.c | 3 +- sound/pci/hda/patch_hdmi.c | 14 +++++--- sound/pci/hda/patch_realtek.c | 12 ++++--- sound/pci/hda/patch_sigmatel.c | 24 +++++++------- sound/pci/hda/patch_via.c | 11 ++++--- 10 files changed, 107 insertions(+), 65 deletions(-) diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 4d605e4ac41c..32a85f9cac4b 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -2032,7 +2032,8 @@ static int create_speaker_out_ctls(struct hda_codec *codec) * independent HP controls */ -static void call_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *jack); +static void call_hp_automute(struct hda_codec *codec, + struct hda_jack_callback *jack); static int indep_hp_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -3948,7 +3949,8 @@ static void call_update_outputs(struct hda_codec *codec) } /* standard HP-automute helper */ -void snd_hda_gen_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *jack) +void snd_hda_gen_hp_automute(struct hda_codec *codec, + struct hda_jack_callback *jack) { struct hda_gen_spec *spec = codec->spec; hda_nid_t *pins = spec->autocfg.hp_pins; @@ -3968,7 +3970,8 @@ void snd_hda_gen_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *jack) EXPORT_SYMBOL_GPL(snd_hda_gen_hp_automute); /* standard line-out-automute helper */ -void snd_hda_gen_line_automute(struct hda_codec *codec, struct hda_jack_tbl *jack) +void snd_hda_gen_line_automute(struct hda_codec *codec, + struct hda_jack_callback *jack) { struct hda_gen_spec *spec = codec->spec; @@ -3988,7 +3991,8 @@ void snd_hda_gen_line_automute(struct hda_codec *codec, struct hda_jack_tbl *jac EXPORT_SYMBOL_GPL(snd_hda_gen_line_automute); /* standard mic auto-switch helper */ -void snd_hda_gen_mic_autoswitch(struct hda_codec *codec, struct hda_jack_tbl *jack) +void snd_hda_gen_mic_autoswitch(struct hda_codec *codec, + struct hda_jack_callback *jack) { struct hda_gen_spec *spec = codec->spec; int i; @@ -4011,7 +4015,8 @@ void snd_hda_gen_mic_autoswitch(struct hda_codec *codec, struct hda_jack_tbl *ja EXPORT_SYMBOL_GPL(snd_hda_gen_mic_autoswitch); /* call appropriate hooks */ -static void call_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *jack) +static void call_hp_automute(struct hda_codec *codec, + struct hda_jack_callback *jack) { struct hda_gen_spec *spec = codec->spec; if (spec->hp_automute_hook) @@ -4021,7 +4026,7 @@ static void call_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *jack) } static void call_line_automute(struct hda_codec *codec, - struct hda_jack_tbl *jack) + struct hda_jack_callback *jack) { struct hda_gen_spec *spec = codec->spec; if (spec->line_automute_hook) @@ -4031,7 +4036,7 @@ static void call_line_automute(struct hda_codec *codec, } static void call_mic_autoswitch(struct hda_codec *codec, - struct hda_jack_tbl *jack) + struct hda_jack_callback *jack) { struct hda_gen_spec *spec = codec->spec; if (spec->mic_autoswitch_hook) diff --git a/sound/pci/hda/hda_generic.h b/sound/pci/hda/hda_generic.h index 72f5624125fb..61dd5153f512 100644 --- a/sound/pci/hda/hda_generic.h +++ b/sound/pci/hda/hda_generic.h @@ -284,11 +284,11 @@ struct hda_gen_spec { /* automute / autoswitch hooks */ void (*hp_automute_hook)(struct hda_codec *codec, - struct hda_jack_tbl *tbl); + struct hda_jack_callback *cb); void (*line_automute_hook)(struct hda_codec *codec, - struct hda_jack_tbl *tbl); + struct hda_jack_callback *cb); void (*mic_autoswitch_hook)(struct hda_codec *codec, - struct hda_jack_tbl *tbl); + struct hda_jack_callback *cb); }; int snd_hda_gen_spec_init(struct hda_gen_spec *spec); @@ -320,11 +320,11 @@ int snd_hda_gen_build_pcms(struct hda_codec *codec); /* standard jack event callbacks */ void snd_hda_gen_hp_automute(struct hda_codec *codec, - struct hda_jack_tbl *jack); + struct hda_jack_callback *jack); void snd_hda_gen_line_automute(struct hda_codec *codec, - struct hda_jack_tbl *jack); + struct hda_jack_callback *jack); void snd_hda_gen_mic_autoswitch(struct hda_codec *codec, - struct hda_jack_tbl *jack); + struct hda_jack_callback *jack); void snd_hda_gen_update_outputs(struct hda_codec *codec); #ifdef CONFIG_PM diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c index a5fe1b428015..f56765ae73a7 100644 --- a/sound/pci/hda/hda_jack.c +++ b/sound/pci/hda/hda_jack.c @@ -111,17 +111,21 @@ snd_hda_jack_tbl_new(struct hda_codec *codec, hda_nid_t nid) void snd_hda_jack_tbl_clear(struct hda_codec *codec) { + struct hda_jack_tbl *jack = codec->jacktbl.list; + int i; + + for (i = 0; i < codec->jacktbl.used; i++, jack++) { + struct hda_jack_callback *cb, *next; #ifdef CONFIG_SND_HDA_INPUT_JACK - /* free jack instances manually when clearing/reconfiguring */ - if (!codec->bus->shutdown && codec->jacktbl.list) { - struct hda_jack_tbl *jack = codec->jacktbl.list; - int i; - for (i = 0; i < codec->jacktbl.used; i++, jack++) { - if (jack->jack) - snd_device_free(codec->bus->card, jack->jack); + /* free jack instances manually when clearing/reconfiguring */ + if (!codec->bus->shutdown && jack->jack) + snd_device_free(codec->bus->card, jack->jack); +#endif + for (cb = jack->callback; cb; cb = next) { + next = cb->next; + kfree(cb); } } -#endif snd_array_free(&codec->jacktbl); } @@ -219,28 +223,38 @@ EXPORT_SYMBOL_GPL(snd_hda_jack_detect_state); * errno. Check and handle the return value appropriately with standard * macros such as @IS_ERR() and @PTR_ERR(). */ -struct hda_jack_tbl * +struct hda_jack_callback * snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid, - hda_jack_callback cb) + hda_jack_callback_fn func) { - struct hda_jack_tbl *jack = snd_hda_jack_tbl_new(codec, nid); + struct hda_jack_tbl *jack; + struct hda_jack_callback *callback = NULL; int err; + jack = snd_hda_jack_tbl_new(codec, nid); if (!jack) return ERR_PTR(-ENOMEM); + if (func) { + callback = kzalloc(sizeof(*callback), GFP_KERNEL); + if (!callback) + return ERR_PTR(-ENOMEM); + callback->func = func; + callback->tbl = jack; + callback->next = jack->callback; + jack->callback = callback; + } + if (jack->jack_detect) - return jack; /* already registered */ + return callback; /* already registered */ jack->jack_detect = 1; - if (cb) - jack->callback = cb; if (codec->jackpoll_interval > 0) - return jack; /* No unsol if we're polling instead */ + return callback; /* No unsol if we're polling instead */ err = snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | jack->tag); if (err < 0) return ERR_PTR(err); - return jack; + return callback; } EXPORT_SYMBOL_GPL(snd_hda_jack_detect_enable_callback); @@ -503,13 +517,17 @@ EXPORT_SYMBOL_GPL(snd_hda_jack_add_kctls); static void call_jack_callback(struct hda_codec *codec, struct hda_jack_tbl *jack) { - if (jack->callback) - jack->callback(codec, jack); + struct hda_jack_callback *cb; + + for (cb = jack->callback; cb; cb = cb->next) + cb->func(codec, cb); if (jack->gated_jack) { struct hda_jack_tbl *gated = snd_hda_jack_tbl_get(codec, jack->gated_jack); - if (gated && gated->callback) - gated->callback(codec, gated); + if (gated) { + for (cb = gated->callback; cb; cb = cb->next) + cb->func(codec, cb); + } } } diff --git a/sound/pci/hda/hda_jack.h b/sound/pci/hda/hda_jack.h index 668669ce3e52..b41e0a3ea1fb 100644 --- a/sound/pci/hda/hda_jack.h +++ b/sound/pci/hda/hda_jack.h @@ -14,14 +14,21 @@ struct auto_pin_cfg; struct hda_jack_tbl; +struct hda_jack_callback; -typedef void (*hda_jack_callback) (struct hda_codec *, struct hda_jack_tbl *); +typedef void (*hda_jack_callback_fn) (struct hda_codec *, struct hda_jack_callback *); + +struct hda_jack_callback { + struct hda_jack_tbl *tbl; + hda_jack_callback_fn func; + unsigned int private_data; /* arbitrary data */ + struct hda_jack_callback *next; +}; struct hda_jack_tbl { hda_nid_t nid; unsigned char tag; /* unsol event tag */ - unsigned int private_data; /* arbitrary data */ - hda_jack_callback callback; + struct hda_jack_callback *callback; /* jack-detection stuff */ unsigned int pin_sense; /* cached pin-sense value */ unsigned int jack_detect:1; /* capable of jack-detection? */ @@ -47,9 +54,9 @@ void snd_hda_jack_tbl_clear(struct hda_codec *codec); void snd_hda_jack_set_dirty_all(struct hda_codec *codec); int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid); -struct hda_jack_tbl * +struct hda_jack_callback * snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid, - hda_jack_callback cb); + hda_jack_callback_fn cb); int snd_hda_jack_set_gating_jack(struct hda_codec *codec, hda_nid_t gated_nid, hda_nid_t gating_nid); diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 69b0ffc55a51..1589c9bcce3e 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -982,7 +982,7 @@ static void cs4210_pinmux_init(struct hda_codec *codec) } static void cs4210_spdif_automute(struct hda_codec *codec, - struct hda_jack_tbl *tbl) + struct hda_jack_callback *tbl) { struct cs_spec *spec = codec->spec; bool spdif_present = false; diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index e0c5bc1d671b..d5b0582daaf0 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -393,7 +393,8 @@ static void olpc_xo_update_mic_pins(struct hda_codec *codec) } /* mic_autoswitch hook */ -static void olpc_xo_automic(struct hda_codec *codec, struct hda_jack_tbl *jack) +static void olpc_xo_automic(struct hda_codec *codec, + struct hda_jack_callback *jack) { struct conexant_spec *spec = codec->spec; int saved_cached_write = codec->cached_write; diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 8f94527f1890..39862e98551c 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -1163,17 +1163,23 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll); -static void jack_callback(struct hda_codec *codec, struct hda_jack_tbl *jack) +static void check_presence_and_report(struct hda_codec *codec, hda_nid_t nid) { struct hdmi_spec *spec = codec->spec; - int pin_idx = pin_nid_to_pin_index(codec, jack->nid); + int pin_idx = pin_nid_to_pin_index(codec, nid); + if (pin_idx < 0) return; - if (hdmi_present_sense(get_pin(spec, pin_idx), 1)) snd_hda_jack_report_sync(codec); } +static void jack_callback(struct hda_codec *codec, + struct hda_jack_callback *jack) +{ + check_presence_and_report(codec, jack->tbl->nid); +} + static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) { int tag = res >> AC_UNSOL_RES_TAG_SHIFT; @@ -1190,7 +1196,7 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) codec->addr, jack->nid, dev_entry, !!(res & AC_UNSOL_RES_IA), !!(res & AC_UNSOL_RES_PD), !!(res & AC_UNSOL_RES_ELDV)); - jack_callback(codec, jack); + check_presence_and_report(codec, jack->nid); } static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index ac00420e59ff..a109fdb085f9 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -264,7 +264,8 @@ static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid, } /* update the master volume per volume-knob's unsol event */ -static void alc_update_knob_master(struct hda_codec *codec, struct hda_jack_tbl *jack) +static void alc_update_knob_master(struct hda_codec *codec, + struct hda_jack_callback *jack) { unsigned int val; struct snd_kcontrol *kctl; @@ -276,7 +277,7 @@ static void alc_update_knob_master(struct hda_codec *codec, struct hda_jack_tbl uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); if (!uctl) return; - val = snd_hda_codec_read(codec, jack->nid, 0, + val = snd_hda_codec_read(codec, jack->tbl->nid, 0, AC_VERB_GET_VOLUME_KNOB_CONTROL, 0); val &= HDA_AMP_VOLMASK; uctl->value.integer.value[0] = val; @@ -3272,7 +3273,7 @@ static void alc269_fixup_quanta_mute(struct hda_codec *codec, } static void alc269_x101_hp_automute_hook(struct hda_codec *codec, - struct hda_jack_tbl *jack) + struct hda_jack_callback *jack) { struct alc_spec *spec = codec->spec; int vref; @@ -3926,7 +3927,8 @@ static void alc_update_headset_mode_hook(struct hda_codec *codec, alc_update_headset_mode(codec); } -static void alc_update_headset_jack_cb(struct hda_codec *codec, struct hda_jack_tbl *jack) +static void alc_update_headset_jack_cb(struct hda_codec *codec, + struct hda_jack_callback *jack) { struct alc_spec *spec = codec->spec; spec->current_headset_type = ALC_HEADSET_TYPE_UNKNOWN; @@ -4166,7 +4168,7 @@ static void alc269_fixup_limit_int_mic_boost(struct hda_codec *codec, } static void alc283_hp_automute_hook(struct hda_codec *codec, - struct hda_jack_tbl *jack) + struct hda_jack_callback *jack) { struct alc_spec *spec = codec->spec; int vref; diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 4b338beb9449..3193529607f2 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -481,7 +481,7 @@ static void stac_toggle_power_map(struct hda_codec *codec, hda_nid_t nid, /* update power bit per jack plug/unplug */ static void jack_update_power(struct hda_codec *codec, - struct hda_jack_tbl *jack) + struct hda_jack_callback *jack) { struct sigmatel_spec *spec = codec->spec; int i; @@ -489,9 +489,9 @@ static void jack_update_power(struct hda_codec *codec, if (!spec->num_pwrs) return; - if (jack && jack->nid) { - stac_toggle_power_map(codec, jack->nid, - snd_hda_jack_detect(codec, jack->nid), + if (jack && jack->tbl->nid) { + stac_toggle_power_map(codec, jack->tbl->nid, + snd_hda_jack_detect(codec, jack->tbl->nid), true); return; } @@ -499,8 +499,7 @@ static void jack_update_power(struct hda_codec *codec, /* update all jacks */ for (i = 0; i < spec->num_pwrs; i++) { hda_nid_t nid = spec->pwr_nids[i]; - jack = snd_hda_jack_tbl_get(codec, nid); - if (!jack) + if (!snd_hda_jack_tbl_get(codec, nid)) continue; stac_toggle_power_map(codec, nid, snd_hda_jack_detect(codec, nid), @@ -512,27 +511,28 @@ static void jack_update_power(struct hda_codec *codec, } static void stac_hp_automute(struct hda_codec *codec, - struct hda_jack_tbl *jack) + struct hda_jack_callback *jack) { snd_hda_gen_hp_automute(codec, jack); jack_update_power(codec, jack); } static void stac_line_automute(struct hda_codec *codec, - struct hda_jack_tbl *jack) + struct hda_jack_callback *jack) { snd_hda_gen_line_automute(codec, jack); jack_update_power(codec, jack); } static void stac_mic_autoswitch(struct hda_codec *codec, - struct hda_jack_tbl *jack) + struct hda_jack_callback *jack) { snd_hda_gen_mic_autoswitch(codec, jack); jack_update_power(codec, jack); } -static void stac_vref_event(struct hda_codec *codec, struct hda_jack_tbl *event) +static void stac_vref_event(struct hda_codec *codec, + struct hda_jack_callback *event) { unsigned int data; @@ -3011,7 +3011,7 @@ static void stac92hd71bxx_fixup_hp_m4(struct hda_codec *codec, const struct hda_fixup *fix, int action) { struct sigmatel_spec *spec = codec->spec; - struct hda_jack_tbl *jack; + struct hda_jack_callback *jack; if (action != HDA_FIXUP_ACT_PRE_PROBE) return; @@ -4033,7 +4033,7 @@ static void stac9205_fixup_dell_m43(struct hda_codec *codec, const struct hda_fixup *fix, int action) { struct sigmatel_spec *spec = codec->spec; - struct hda_jack_tbl *jack; + struct hda_jack_callback *jack; if (action == HDA_FIXUP_ACT_PRE_PROBE) { snd_hda_apply_pincfgs(codec, dell_9205_m43_pin_configs); diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 2a8be5a5da15..8d234ab9f06b 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -118,7 +118,7 @@ static void via_playback_pcm_hook(struct hda_pcm_stream *hinfo, struct hda_codec *codec, struct snd_pcm_substream *substream, int action); -static void via_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *tbl); +static void via_hp_automute(struct hda_codec *codec, struct hda_jack_callback *tbl); static struct via_spec *via_new_spec(struct hda_codec *codec) { @@ -575,19 +575,22 @@ static const struct snd_kcontrol_new vt1708_jack_detect_ctl[] = { {} /* terminator */ }; -static void via_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *tbl) +static void via_hp_automute(struct hda_codec *codec, + struct hda_jack_callback *tbl) { set_widgets_power_state(codec); snd_hda_gen_hp_automute(codec, tbl); } -static void via_line_automute(struct hda_codec *codec, struct hda_jack_tbl *tbl) +static void via_line_automute(struct hda_codec *codec, + struct hda_jack_callback *tbl) { set_widgets_power_state(codec); snd_hda_gen_line_automute(codec, tbl); } -static void via_jack_powerstate_event(struct hda_codec *codec, struct hda_jack_tbl *tbl) +static void via_jack_powerstate_event(struct hda_codec *codec, + struct hda_jack_callback *tbl) { set_widgets_power_state(codec); } From aa699c492e77ec01a038e8a8add6ce04011b9561 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 11 Sep 2014 15:29:18 +0200 Subject: [PATCH 160/251] ALSA: hda - Remove superfluous callbacks from STAC/IDT codecs Now we can register multiple callbacks to each jack, most of hooks used in STAC/IDT codecs can be removed by enabling the powermap update callback for all relevant pins. Along with this, the call of stac_init_power_map() can be moved back to stac_parse_auto_config() and the own build_controls callback can be removed, too. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 38 ++-------------------------------- 1 file changed, 2 insertions(+), 36 deletions(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 3193529607f2..4f6413e01c13 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -510,27 +510,6 @@ static void jack_update_power(struct hda_codec *codec, spec->power_map_bits); } -static void stac_hp_automute(struct hda_codec *codec, - struct hda_jack_callback *jack) -{ - snd_hda_gen_hp_automute(codec, jack); - jack_update_power(codec, jack); -} - -static void stac_line_automute(struct hda_codec *codec, - struct hda_jack_callback *jack) -{ - snd_hda_gen_line_automute(codec, jack); - jack_update_power(codec, jack); -} - -static void stac_mic_autoswitch(struct hda_codec *codec, - struct hda_jack_callback *jack) -{ - snd_hda_gen_mic_autoswitch(codec, jack); - jack_update_power(codec, jack); -} - static void stac_vref_event(struct hda_codec *codec, struct hda_jack_callback *event) { @@ -555,8 +534,6 @@ static void stac_init_power_map(struct hda_codec *codec) hda_nid_t nid = spec->pwr_nids[i]; unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid); def_conf = get_defcfg_connect(def_conf); - if (snd_hda_jack_tbl_get(codec, nid)) - continue; if (def_conf == AC_JACK_PORT_COMPLEX && spec->vref_mute_led_nid != nid && is_jack_detectable(codec, nid)) { @@ -4206,9 +4183,6 @@ static int stac_parse_auto_config(struct hda_codec *codec) spec->gen.pcm_capture_hook = stac_capture_pcm_hook; spec->gen.automute_hook = stac_update_outputs; - spec->gen.hp_automute_hook = stac_hp_automute; - spec->gen.line_automute_hook = stac_line_automute; - spec->gen.mic_autoswitch_hook = stac_mic_autoswitch; err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg); if (err < 0) @@ -4260,16 +4234,8 @@ static int stac_parse_auto_config(struct hda_codec *codec) return err; } - return 0; -} - -static int stac_build_controls(struct hda_codec *codec) -{ - int err = snd_hda_gen_build_controls(codec); - - if (err < 0) - return err; stac_init_power_map(codec); + return 0; } @@ -4383,7 +4349,7 @@ static int stac_suspend(struct hda_codec *codec) #endif /* CONFIG_PM */ static const struct hda_codec_ops stac_patch_ops = { - .build_controls = stac_build_controls, + .build_controls = snd_hda_gen_build_controls, .build_pcms = snd_hda_gen_build_pcms, .init = stac_init, .free = stac_free, From 7c3008c47b405420bf2b24fb5a21af3df5b5c323 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 11 Sep 2014 15:35:22 +0200 Subject: [PATCH 161/251] ALSA: hda - Remove superfluous hooks from VIA driver Like the previous fix for STAC/IDT codecs, the automute hooks in VIA driver can be also removed by enabling the power control callback for all pins. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_via.c | 25 ++----------------------- 1 file changed, 2 insertions(+), 23 deletions(-) diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 8d234ab9f06b..6c206b6c8d65 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -118,7 +118,6 @@ static void via_playback_pcm_hook(struct hda_pcm_stream *hinfo, struct hda_codec *codec, struct snd_pcm_substream *substream, int action); -static void via_hp_automute(struct hda_codec *codec, struct hda_jack_callback *tbl); static struct via_spec *via_new_spec(struct hda_codec *codec) { @@ -575,20 +574,6 @@ static const struct snd_kcontrol_new vt1708_jack_detect_ctl[] = { {} /* terminator */ }; -static void via_hp_automute(struct hda_codec *codec, - struct hda_jack_callback *tbl) -{ - set_widgets_power_state(codec); - snd_hda_gen_hp_automute(codec, tbl); -} - -static void via_line_automute(struct hda_codec *codec, - struct hda_jack_callback *tbl) -{ - set_widgets_power_state(codec); - snd_hda_gen_line_automute(codec, tbl); -} - static void via_jack_powerstate_event(struct hda_codec *codec, struct hda_jack_callback *tbl) { @@ -602,22 +587,16 @@ static void via_set_jack_unsol_events(struct hda_codec *codec) hda_nid_t pin; int i; - spec->gen.hp_automute_hook = via_hp_automute; - if (cfg->speaker_pins[0]) - spec->gen.line_automute_hook = via_line_automute; - for (i = 0; i < cfg->line_outs; i++) { pin = cfg->line_out_pins[i]; - if (pin && !snd_hda_jack_tbl_get(codec, pin) && - is_jack_detectable(codec, pin)) + if (pin && is_jack_detectable(codec, pin)) snd_hda_jack_detect_enable_callback(codec, pin, via_jack_powerstate_event); } for (i = 0; i < cfg->num_inputs; i++) { pin = cfg->line_out_pins[i]; - if (pin && !snd_hda_jack_tbl_get(codec, pin) && - is_jack_detectable(codec, pin)) + if (pin && is_jack_detectable(codec, pin)) snd_hda_jack_detect_enable_callback(codec, pin, via_jack_powerstate_event); } From f8fb117034847634bff8f02632151f7535981fa1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 11 Sep 2014 15:53:26 +0200 Subject: [PATCH 162/251] ALSA: hda - Use standard hda_jack infrastructure for CA0132 driver For its headphone, mic and DSP responses, we can use the standard hda_jack infrastructure in CA0132 driver, too. The only point to handle carefully is the delayed headphone jack handling. It tries to react after a certain delay. Here we use the existing block_report flag in hda_jack_tbl (that was implemented for HDMI). Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 74 ++++++++++++++++-------------------- 1 file changed, 33 insertions(+), 41 deletions(-) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 39fae52258f0..4f7ffa8c4a0d 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -3224,8 +3224,14 @@ static void ca0132_unsol_hp_delayed(struct work_struct *work) { struct ca0132_spec *spec = container_of( to_delayed_work(work), struct ca0132_spec, unsol_hp_work); + struct hda_jack_tbl *jack; + ca0132_select_out(spec->codec); - snd_hda_jack_report_sync(spec->codec); + jack = snd_hda_jack_tbl_get(spec->codec, UNSOL_TAG_HP); + if (jack) { + jack->block_report = 0; + snd_hda_jack_report_sync(spec->codec); + } } static void ca0132_set_dmic(struct hda_codec *codec, int enable); @@ -4114,12 +4120,6 @@ static void init_input(struct hda_codec *codec, hda_nid_t pin, hda_nid_t adc) } } -static void ca0132_init_unsol(struct hda_codec *codec) -{ - snd_hda_jack_detect_enable(codec, UNSOL_TAG_HP); - snd_hda_jack_detect_enable(codec, UNSOL_TAG_AMIC1); -} - static void refresh_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir) { unsigned int caps; @@ -4390,7 +4390,8 @@ static void ca0132_download_dsp(struct hda_codec *codec) ca0132_set_dsp_msr(codec, true); } -static void ca0132_process_dsp_response(struct hda_codec *codec) +static void ca0132_process_dsp_response(struct hda_codec *codec, + struct hda_jack_callback *callback) { struct ca0132_spec *spec = codec->spec; @@ -4403,38 +4404,31 @@ static void ca0132_process_dsp_response(struct hda_codec *codec) dspio_clear_response_queue(codec); } -static void ca0132_unsol_event(struct hda_codec *codec, unsigned int res) +static void hp_callback(struct hda_codec *codec, struct hda_jack_callback *cb) { struct ca0132_spec *spec = codec->spec; - unsigned int tag = (res >> AC_UNSOL_RES_TAG_SHIFT) & 0x3f; - if (tag == UNSOL_TAG_DSP) { - ca0132_process_dsp_response(codec); - } else { - struct hda_jack_tbl *jack; + /* Delay enabling the HP amp, to let the mic-detection + * state machine run. + */ + cancel_delayed_work_sync(&spec->unsol_hp_work); + queue_delayed_work(codec->bus->workq, &spec->unsol_hp_work, + msecs_to_jiffies(500)); + cb->tbl->block_report = 1; +} - codec_dbg(codec, "snd_hda_jack_get_action: 0x%x\n", res); - jack = snd_hda_jack_tbl_get_from_tag(codec, tag); - if (!jack) - return; - switch (jack->nid) { - case UNSOL_TAG_HP: - /* Delay enabling the HP amp, to let the mic-detection - * state machine run. - */ - cancel_delayed_work_sync(&spec->unsol_hp_work); - queue_delayed_work(codec->bus->workq, - &spec->unsol_hp_work, - msecs_to_jiffies(500)); - break; - case UNSOL_TAG_AMIC1: - ca0132_select_mic(codec); - snd_hda_jack_report_sync(codec); - break; - default: - break; - } - } +static void amic_callback(struct hda_codec *codec, struct hda_jack_callback *cb) +{ + ca0132_select_mic(codec); +} + +static void ca0132_init_unsol(struct hda_codec *codec) +{ + snd_hda_jack_detect_enable_callback(codec, UNSOL_TAG_HP, hp_callback); + snd_hda_jack_detect_enable_callback(codec, UNSOL_TAG_AMIC1, + amic_callback); + snd_hda_jack_detect_enable_callback(codec, UNSOL_TAG_DSP, + ca0132_process_dsp_response); } /* @@ -4445,8 +4439,6 @@ static void ca0132_unsol_event(struct hda_codec *codec, unsigned int res) static struct hda_verb ca0132_base_init_verbs[] = { /*enable ct extension*/ {0x15, VENDOR_CHIPIO_CT_EXTENSIONS_ENABLE, 0x1}, - /*enable DSP node unsol, needed for DSP download*/ - {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | UNSOL_TAG_DSP}, {} }; @@ -4563,6 +4555,8 @@ static int ca0132_init(struct hda_codec *codec) snd_hda_power_up(codec); + ca0132_init_unsol(codec); + ca0132_init_params(codec); ca0132_init_flags(codec); snd_hda_sequence_write(codec, spec->base_init_verbs); @@ -4585,8 +4579,6 @@ static int ca0132_init(struct hda_codec *codec) for (i = 0; i < spec->num_init_verbs; i++) snd_hda_sequence_write(codec, spec->init_verbs[i]); - ca0132_init_unsol(codec); - ca0132_select_out(codec); ca0132_select_mic(codec); @@ -4614,7 +4606,7 @@ static struct hda_codec_ops ca0132_patch_ops = { .build_pcms = ca0132_build_pcms, .init = ca0132_init, .free = ca0132_free, - .unsol_event = ca0132_unsol_event, + .unsol_event = snd_hda_jack_unsol_event, }; static void ca0132_config(struct hda_codec *codec) From 44caf7648064502fd1d37d18443ae92c064ebadd Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Tue, 16 Sep 2014 11:37:39 +0800 Subject: [PATCH 163/251] ASoC: rt5677: Add the GPIO function The patch adds the GPIO function. Signed-off-by: Oder Chiou Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677.c | 133 ++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/rt5677.h | 112 ++++++++++++++++++++++++++++++++ 2 files changed, 245 insertions(+) diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index f0b751bf1d6c..02bc8bd7caeb 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -3160,6 +3161,135 @@ static int rt5677_set_bias_level(struct snd_soc_codec *codec, return 0; } +#ifdef CONFIG_GPIOLIB +static inline struct rt5677_priv *gpio_to_rt5677(struct gpio_chip *chip) +{ + return container_of(chip, struct rt5677_priv, gpio_chip); +} + +static void rt5677_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +{ + struct rt5677_priv *rt5677 = gpio_to_rt5677(chip); + + switch (offset) { + case RT5677_GPIO1 ... RT5677_GPIO5: + regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL2, + 0x1 << (offset * 3 + 1), !!value << (offset * 3 + 1)); + break; + + case RT5677_GPIO6: + regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL3, + RT5677_GPIO6_OUT_MASK, !!value << RT5677_GPIO6_OUT_SFT); + break; + + default: + break; + } +} + +static int rt5677_gpio_direction_out(struct gpio_chip *chip, + unsigned offset, int value) +{ + struct rt5677_priv *rt5677 = gpio_to_rt5677(chip); + + switch (offset) { + case RT5677_GPIO1 ... RT5677_GPIO5: + regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL2, + 0x3 << (offset * 3 + 1), + (0x2 | !!value) << (offset * 3 + 1)); + break; + + case RT5677_GPIO6: + regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL3, + RT5677_GPIO6_DIR_MASK | RT5677_GPIO6_OUT_MASK, + RT5677_GPIO6_DIR_OUT | !!value << RT5677_GPIO6_OUT_SFT); + break; + + default: + break; + } + + return 0; +} + +static int rt5677_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + struct rt5677_priv *rt5677 = gpio_to_rt5677(chip); + int value, ret; + + ret = regmap_read(rt5677->regmap, RT5677_GPIO_ST, &value); + if (ret < 0) + return ret; + + return (value & (0x1 << offset)) >> offset; +} + +static int rt5677_gpio_direction_in(struct gpio_chip *chip, unsigned offset) +{ + struct rt5677_priv *rt5677 = gpio_to_rt5677(chip); + + switch (offset) { + case RT5677_GPIO1 ... RT5677_GPIO5: + regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL2, + 0x1 << (offset * 3 + 2), 0x0); + break; + + case RT5677_GPIO6: + regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL3, + RT5677_GPIO6_DIR_MASK, RT5677_GPIO6_DIR_IN); + break; + + default: + break; + } + + return 0; +} + +static struct gpio_chip rt5677_template_chip = { + .label = "rt5677", + .owner = THIS_MODULE, + .direction_output = rt5677_gpio_direction_out, + .set = rt5677_gpio_set, + .direction_input = rt5677_gpio_direction_in, + .get = rt5677_gpio_get, + .can_sleep = 1, +}; + +static void rt5677_init_gpio(struct i2c_client *i2c) +{ + struct rt5677_priv *rt5677 = i2c_get_clientdata(i2c); + int ret; + + rt5677->gpio_chip = rt5677_template_chip; + rt5677->gpio_chip.ngpio = RT5677_GPIO_NUM; + rt5677->gpio_chip.dev = &i2c->dev; + rt5677->gpio_chip.base = -1; + + ret = gpiochip_add(&rt5677->gpio_chip); + if (ret != 0) + dev_err(&i2c->dev, "Failed to add GPIOs: %d\n", ret); +} + +static void rt5677_free_gpio(struct i2c_client *i2c) +{ + struct rt5677_priv *rt5677 = i2c_get_clientdata(i2c); + int ret; + + ret = gpiochip_remove(&rt5677->gpio_chip); + if (ret != 0) + dev_err(&i2c->dev, "Failed to remove GPIOs: %d\n", ret); +} +#else +static void rt5677_init_gpio(struct i2c_client *i2c) +{ +} + +static void rt5677_free_gpio(struct i2c_client *i2c) +{ +} +#endif + static int rt5677_probe(struct snd_soc_codec *codec) { struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); @@ -3422,6 +3552,8 @@ static int rt5677_i2c_probe(struct i2c_client *i2c, RT5677_GPIO5_DIR_OUT); } + rt5677_init_gpio(i2c); + return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5677, rt5677_dai, ARRAY_SIZE(rt5677_dai)); } @@ -3429,6 +3561,7 @@ static int rt5677_i2c_probe(struct i2c_client *i2c, static int rt5677_i2c_remove(struct i2c_client *i2c) { snd_soc_unregister_codec(&i2c->dev); + rt5677_free_gpio(i2c); return 0; } diff --git a/sound/soc/codecs/rt5677.h b/sound/soc/codecs/rt5677.h index a334eb66cfc1..b61b72cfcbd7 100644 --- a/sound/soc/codecs/rt5677.h +++ b/sound/soc/codecs/rt5677.h @@ -1363,10 +1363,109 @@ #define RT5677_SEL_SRC_IB01 (0x1 << 0) #define RT5677_SEL_SRC_IB01_SFT 0 +/* GPIO status (0xbf) */ +#define RT5677_GPIO6_STATUS_MASK (0x1 << 5) +#define RT5677_GPIO6_STATUS_SFT 5 +#define RT5677_GPIO5_STATUS_MASK (0x1 << 4) +#define RT5677_GPIO5_STATUS_SFT 4 +#define RT5677_GPIO4_STATUS_MASK (0x1 << 3) +#define RT5677_GPIO4_STATUS_SFT 3 +#define RT5677_GPIO3_STATUS_MASK (0x1 << 2) +#define RT5677_GPIO3_STATUS_SFT 2 +#define RT5677_GPIO2_STATUS_MASK (0x1 << 1) +#define RT5677_GPIO2_STATUS_SFT 1 +#define RT5677_GPIO1_STATUS_MASK (0x1 << 0) +#define RT5677_GPIO1_STATUS_SFT 0 + +/* GPIO Control 1 (0xc0) */ +#define RT5677_GPIO1_PIN_MASK (0x1 << 15) +#define RT5677_GPIO1_PIN_SFT 15 +#define RT5677_GPIO1_PIN_GPIO1 (0x0 << 15) +#define RT5677_GPIO1_PIN_IRQ (0x1 << 15) +#define RT5677_IPTV_MODE_MASK (0x1 << 14) +#define RT5677_IPTV_MODE_SFT 14 +#define RT5677_IPTV_MODE_GPIO (0x0 << 14) +#define RT5677_IPTV_MODE_IPTV (0x1 << 14) +#define RT5677_FUNC_MODE_MASK (0x1 << 13) +#define RT5677_FUNC_MODE_SFT 13 +#define RT5677_FUNC_MODE_DMIC_GPIO (0x0 << 13) +#define RT5677_FUNC_MODE_JTAG (0x1 << 13) + /* GPIO Control 2 (0xc1) */ #define RT5677_GPIO5_DIR_MASK (0x1 << 14) +#define RT5677_GPIO5_DIR_SFT 14 #define RT5677_GPIO5_DIR_IN (0x0 << 14) #define RT5677_GPIO5_DIR_OUT (0x1 << 14) +#define RT5677_GPIO5_OUT_MASK (0x1 << 13) +#define RT5677_GPIO5_OUT_SFT 13 +#define RT5677_GPIO5_OUT_LO (0x0 << 13) +#define RT5677_GPIO5_OUT_HI (0x1 << 13) +#define RT5677_GPIO5_P_MASK (0x1 << 12) +#define RT5677_GPIO5_P_SFT 12 +#define RT5677_GPIO5_P_NOR (0x0 << 12) +#define RT5677_GPIO5_P_INV (0x1 << 12) +#define RT5677_GPIO4_DIR_MASK (0x1 << 11) +#define RT5677_GPIO4_DIR_SFT 11 +#define RT5677_GPIO4_DIR_IN (0x0 << 11) +#define RT5677_GPIO4_DIR_OUT (0x1 << 11) +#define RT5677_GPIO4_OUT_MASK (0x1 << 10) +#define RT5677_GPIO4_OUT_SFT 10 +#define RT5677_GPIO4_OUT_LO (0x0 << 10) +#define RT5677_GPIO4_OUT_HI (0x1 << 10) +#define RT5677_GPIO4_P_MASK (0x1 << 9) +#define RT5677_GPIO4_P_SFT 9 +#define RT5677_GPIO4_P_NOR (0x0 << 9) +#define RT5677_GPIO4_P_INV (0x1 << 9) +#define RT5677_GPIO3_DIR_MASK (0x1 << 8) +#define RT5677_GPIO3_DIR_SFT 8 +#define RT5677_GPIO3_DIR_IN (0x0 << 8) +#define RT5677_GPIO3_DIR_OUT (0x1 << 8) +#define RT5677_GPIO3_OUT_MASK (0x1 << 7) +#define RT5677_GPIO3_OUT_SFT 7 +#define RT5677_GPIO3_OUT_LO (0x0 << 7) +#define RT5677_GPIO3_OUT_HI (0x1 << 7) +#define RT5677_GPIO3_P_MASK (0x1 << 6) +#define RT5677_GPIO3_P_SFT 6 +#define RT5677_GPIO3_P_NOR (0x0 << 6) +#define RT5677_GPIO3_P_INV (0x1 << 6) +#define RT5677_GPIO2_DIR_MASK (0x1 << 5) +#define RT5677_GPIO2_DIR_SFT 5 +#define RT5677_GPIO2_DIR_IN (0x0 << 5) +#define RT5677_GPIO2_DIR_OUT (0x1 << 5) +#define RT5677_GPIO2_OUT_MASK (0x1 << 4) +#define RT5677_GPIO2_OUT_SFT 4 +#define RT5677_GPIO2_OUT_LO (0x0 << 4) +#define RT5677_GPIO2_OUT_HI (0x1 << 4) +#define RT5677_GPIO2_P_MASK (0x1 << 3) +#define RT5677_GPIO2_P_SFT 3 +#define RT5677_GPIO2_P_NOR (0x0 << 3) +#define RT5677_GPIO2_P_INV (0x1 << 3) +#define RT5677_GPIO1_DIR_MASK (0x1 << 2) +#define RT5677_GPIO1_DIR_SFT 2 +#define RT5677_GPIO1_DIR_IN (0x0 << 2) +#define RT5677_GPIO1_DIR_OUT (0x1 << 2) +#define RT5677_GPIO1_OUT_MASK (0x1 << 1) +#define RT5677_GPIO1_OUT_SFT 1 +#define RT5677_GPIO1_OUT_LO (0x0 << 1) +#define RT5677_GPIO1_OUT_HI (0x1 << 1) +#define RT5677_GPIO1_P_MASK (0x1 << 0) +#define RT5677_GPIO1_P_SFT 0 +#define RT5677_GPIO1_P_NOR (0x0 << 0) +#define RT5677_GPIO1_P_INV (0x1 << 0) + +/* GPIO Control 3 (0xc2) */ +#define RT5677_GPIO6_DIR_MASK (0x1 << 2) +#define RT5677_GPIO6_DIR_SFT 2 +#define RT5677_GPIO6_DIR_IN (0x0 << 2) +#define RT5677_GPIO6_DIR_OUT (0x1 << 2) +#define RT5677_GPIO6_OUT_MASK (0x1 << 1) +#define RT5677_GPIO6_OUT_SFT 1 +#define RT5677_GPIO6_OUT_LO (0x0 << 1) +#define RT5677_GPIO6_OUT_HI (0x1 << 1) +#define RT5677_GPIO6_P_MASK (0x1 << 0) +#define RT5677_GPIO6_P_SFT 0 +#define RT5677_GPIO6_P_NOR (0x0 << 0) +#define RT5677_GPIO6_P_INV (0x1 << 0) /* Virtual DSP Mixer Control (0xf7 0xf8 0xf9) */ #define RT5677_DSP_IB_01_H (0x1 << 15) @@ -1428,6 +1527,16 @@ enum { RT5677_AIFS, }; +enum { + RT5677_GPIO1, + RT5677_GPIO2, + RT5677_GPIO3, + RT5677_GPIO4, + RT5677_GPIO5, + RT5677_GPIO6, + RT5677_GPIO_NUM, +}; + struct rt5677_priv { struct snd_soc_codec *codec; struct rt5677_platform_data pdata; @@ -1441,6 +1550,9 @@ struct rt5677_priv { int pll_src; int pll_in; int pll_out; +#ifdef CONFIG_GPIOLIB + struct gpio_chip gpio_chip; +#endif }; #endif /* __RT5677_H__ */ From d2b16b8fa1b6352757cd0a58234591e1496a82ad Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Tue, 9 Sep 2014 15:11:24 +0530 Subject: [PATCH 164/251] ASoC: Intel: mfld-pcm: don't call trigger ops to DSP for internal streams For internal stream i.e. BE we have don't need trigger ops as that would be handled by DAPM for us in subsequent patches Signed-off-by: Vinod Koul Signed-off-by: Subhransu S. Prusty Signed-off-by: Mark Brown --- sound/soc/intel/sst-mfld-platform-pcm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/intel/sst-mfld-platform-pcm.c b/sound/soc/intel/sst-mfld-platform-pcm.c index 85deecd82b92..9906b7c1c2e1 100644 --- a/sound/soc/intel/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/sst-mfld-platform-pcm.c @@ -464,6 +464,8 @@ static int sst_platform_pcm_trigger(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; dev_dbg(rtd->dev, "sst_platform_pcm_trigger called\n"); + if (substream->pcm->internal) + return 0; stream = substream->runtime->private_data; str_id = stream->stream_info.str_id; switch (cmd) { From 10615a5c49721803ed258316280858142a24e72a Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Tue, 9 Sep 2014 15:11:25 +0530 Subject: [PATCH 165/251] ASoC: Intel: mrfld: add bytes control for modules This patch add support for various modules like eq etc for mrfld DSP. All these modules will be exposed to usermode as bytes controls. Signed-off-by: Vinod Koul Signed-off-by: Subhransu S. Prusty Signed-off-by: Mark Brown --- sound/soc/intel/sst-atom-controls.c | 179 ++++++++++++++++++++++++++++ sound/soc/intel/sst-atom-controls.h | 130 ++++++++++++++++++++ sound/soc/intel/sst-mfld-platform.h | 2 +- 3 files changed, 310 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/sst-atom-controls.c b/sound/soc/intel/sst-atom-controls.c index ace3c4a59b14..7104a34181a9 100644 --- a/sound/soc/intel/sst-atom-controls.c +++ b/sound/soc/intel/sst-atom-controls.c @@ -25,6 +25,179 @@ #include "sst-mfld-platform.h" #include "sst-atom-controls.h" +static int sst_fill_byte_control(struct sst_data *drv, + u8 ipc_msg, u8 block, + u8 task_id, u8 pipe_id, + u16 len, void *cmd_data) +{ + struct snd_sst_bytes_v2 *byte_data = drv->byte_stream; + + byte_data->type = SST_CMD_BYTES_SET; + byte_data->ipc_msg = ipc_msg; + byte_data->block = block; + byte_data->task_id = task_id; + byte_data->pipe_id = pipe_id; + + if (len > SST_MAX_BIN_BYTES - sizeof(*byte_data)) { + dev_err(&drv->pdev->dev, "command length too big (%u)", len); + return -EINVAL; + } + byte_data->len = len; + memcpy(byte_data->bytes, cmd_data, len); + print_hex_dump_bytes("writing to lpe: ", DUMP_PREFIX_OFFSET, + byte_data, len + sizeof(*byte_data)); + return 0; +} + +static int sst_fill_and_send_cmd_unlocked(struct sst_data *drv, + u8 ipc_msg, u8 block, u8 task_id, u8 pipe_id, + void *cmd_data, u16 len) +{ + int ret = 0; + + ret = sst_fill_byte_control(drv, ipc_msg, + block, task_id, pipe_id, len, cmd_data); + if (ret < 0) + return ret; + return sst->ops->send_byte_stream(sst->dev, drv->byte_stream); +} + +/** + * sst_fill_and_send_cmd - generate the IPC message and send it to the FW + * @ipc_msg: type of IPC (CMD, SET_PARAMS, GET_PARAMS) + * @cmd_data: the IPC payload + */ +static int sst_fill_and_send_cmd(struct sst_data *drv, + u8 ipc_msg, u8 block, u8 task_id, u8 pipe_id, + void *cmd_data, u16 len) +{ + int ret; + + mutex_lock(&drv->lock); + ret = sst_fill_and_send_cmd_unlocked(drv, ipc_msg, block, + task_id, pipe_id, cmd_data, len); + mutex_unlock(&drv->lock); + + return ret; +} + +static int sst_send_algo_cmd(struct sst_data *drv, + struct sst_algo_control *bc) +{ + int len, ret = 0; + struct sst_cmd_set_params *cmd; + + /*bc->max includes sizeof algos + length field*/ + len = sizeof(cmd->dst) + sizeof(cmd->command_id) + bc->max; + + cmd = kzalloc(len, GFP_KERNEL); + if (cmd == NULL) + return -ENOMEM; + + SST_FILL_DESTINATION(2, cmd->dst, bc->pipe_id, bc->module_id); + cmd->command_id = bc->cmd_id; + memcpy(cmd->params, bc->params, bc->max); + + ret = sst_fill_and_send_cmd_unlocked(drv, SST_IPC_IA_SET_PARAMS, + SST_FLAG_BLOCKED, bc->task_id, 0, cmd, len); + kfree(cmd); + return ret; +} + +static int sst_algo_bytes_ctl_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct sst_algo_control *bc = (void *)kcontrol->private_value; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; + uinfo->count = bc->max; + + return 0; +} + +static int sst_algo_control_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct sst_algo_control *bc = (void *)kcontrol->private_value; + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + + switch (bc->type) { + case SST_ALGO_PARAMS: + memcpy(ucontrol->value.bytes.data, bc->params, bc->max); + break; + default: + dev_err(component->dev, "Invalid Input- algo type:%d\n", + bc->type); + return -EINVAL; + + } + return 0; +} + +static int sst_algo_control_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ret = 0; + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct sst_data *drv = snd_soc_component_get_drvdata(cmpnt); + struct sst_algo_control *bc = (void *)kcontrol->private_value; + + dev_dbg(cmpnt->dev, "control_name=%s\n", kcontrol->id.name); + mutex_lock(&drv->lock); + switch (bc->type) { + case SST_ALGO_PARAMS: + memcpy(bc->params, ucontrol->value.bytes.data, bc->max); + break; + default: + mutex_unlock(&drv->lock); + dev_err(cmpnt->dev, "Invalid Input- algo type:%d\n", + bc->type); + return -EINVAL; + } + /*if pipe is enabled, need to send the algo params from here*/ + if (bc->w && bc->w->power) + ret = sst_send_algo_cmd(drv, bc); + mutex_unlock(&drv->lock); + + return ret; +} + +static const struct snd_kcontrol_new sst_algo_controls[] = { + SST_ALGO_KCONTROL_BYTES("media_loop1_out", "fir", 272, SST_MODULE_ID_FIR_24, + SST_PATH_INDEX_MEDIA_LOOP1_OUT, 0, SST_TASK_SBA, SBA_VB_SET_FIR), + SST_ALGO_KCONTROL_BYTES("media_loop1_out", "iir", 300, SST_MODULE_ID_IIR_24, + SST_PATH_INDEX_MEDIA_LOOP1_OUT, 0, SST_TASK_SBA, SBA_VB_SET_IIR), + SST_ALGO_KCONTROL_BYTES("media_loop1_out", "mdrp", 286, SST_MODULE_ID_MDRP, + SST_PATH_INDEX_MEDIA_LOOP1_OUT, 0, SST_TASK_SBA, SBA_SET_MDRP), + SST_ALGO_KCONTROL_BYTES("media_loop2_out", "fir", 272, SST_MODULE_ID_FIR_24, + SST_PATH_INDEX_MEDIA_LOOP2_OUT, 0, SST_TASK_SBA, SBA_VB_SET_FIR), + SST_ALGO_KCONTROL_BYTES("media_loop2_out", "iir", 300, SST_MODULE_ID_IIR_24, + SST_PATH_INDEX_MEDIA_LOOP2_OUT, 0, SST_TASK_SBA, SBA_VB_SET_IIR), + SST_ALGO_KCONTROL_BYTES("media_loop2_out", "mdrp", 286, SST_MODULE_ID_MDRP, + SST_PATH_INDEX_MEDIA_LOOP2_OUT, 0, SST_TASK_SBA, SBA_SET_MDRP), + SST_ALGO_KCONTROL_BYTES("sprot_loop_out", "lpro", 192, SST_MODULE_ID_SPROT, + SST_PATH_INDEX_SPROT_LOOP_OUT, 0, SST_TASK_SBA, SBA_VB_LPRO), + SST_ALGO_KCONTROL_BYTES("codec_in0", "dcr", 52, SST_MODULE_ID_FILT_DCR, + SST_PATH_INDEX_CODEC_IN0, 0, SST_TASK_SBA, SBA_VB_SET_IIR), + SST_ALGO_KCONTROL_BYTES("codec_in1", "dcr", 52, SST_MODULE_ID_FILT_DCR, + SST_PATH_INDEX_CODEC_IN1, 0, SST_TASK_SBA, SBA_VB_SET_IIR), + +}; + +static int sst_algo_control_init(struct device *dev) +{ + int i = 0; + struct sst_algo_control *bc; + /*allocate space to cache the algo parameters in the driver*/ + for (i = 0; i < ARRAY_SIZE(sst_algo_controls); i++) { + bc = (struct sst_algo_control *)sst_algo_controls[i].private_value; + bc->params = devm_kzalloc(dev, bc->max, GFP_KERNEL); + if (bc->params == NULL) + return -ENOMEM; + } + return 0; +} + int sst_dsp_init_v2_dpcm(struct snd_soc_platform *platform) { int ret = 0; @@ -35,5 +208,11 @@ int sst_dsp_init_v2_dpcm(struct snd_soc_platform *platform) if (!drv->byte_stream) return -ENOMEM; + /*Initialize algo control params*/ + ret = sst_algo_control_init(platform->dev); + if (ret) + return ret; + ret = snd_soc_add_platform_controls(platform, sst_algo_controls, + ARRAY_SIZE(sst_algo_controls)); return ret; } diff --git a/sound/soc/intel/sst-atom-controls.h b/sound/soc/intel/sst-atom-controls.h index 8554889c0694..a73e894b175c 100644 --- a/sound/soc/intel/sst-atom-controls.h +++ b/sound/soc/intel/sst-atom-controls.h @@ -309,4 +309,134 @@ enum sst_swm_state { SST_SWM_ON = 3, }; +#define SST_FILL_LOCATION_IDS(dst, cell_idx, pipe_id) do { \ + dst.location_id.p.cell_nbr_idx = (cell_idx); \ + dst.location_id.p.path_id = (pipe_id); \ + } while (0) +#define SST_FILL_LOCATION_ID(dst, loc_id) (\ + dst.location_id.f = (loc_id)) +#define SST_FILL_MODULE_ID(dst, mod_id) (\ + dst.module_id = (mod_id)) + +#define SST_FILL_DESTINATION1(dst, id) do { \ + SST_FILL_LOCATION_ID(dst, (id) & 0xFFFF); \ + SST_FILL_MODULE_ID(dst, ((id) & 0xFFFF0000) >> 16); \ + } while (0) +#define SST_FILL_DESTINATION2(dst, loc_id, mod_id) do { \ + SST_FILL_LOCATION_ID(dst, loc_id); \ + SST_FILL_MODULE_ID(dst, mod_id); \ + } while (0) +#define SST_FILL_DESTINATION3(dst, cell_idx, path_id, mod_id) do { \ + SST_FILL_LOCATION_IDS(dst, cell_idx, path_id); \ + SST_FILL_MODULE_ID(dst, mod_id); \ + } while (0) + +#define SST_FILL_DESTINATION(level, dst, ...) \ + SST_FILL_DESTINATION##level(dst, __VA_ARGS__) +#define SST_FILL_DEFAULT_DESTINATION(dst) \ + SST_FILL_DESTINATION(2, dst, SST_DEFAULT_LOCATION_ID, SST_DEFAULT_MODULE_ID) + +struct sst_destination_id { + union sst_location_id { + struct { + u8 cell_nbr_idx; /* module index */ + u8 path_id; /* pipe_id */ + } __packed p; /* part */ + u16 f; /* full */ + } __packed location_id; + u16 module_id; +} __packed; +struct sst_dsp_header { + struct sst_destination_id dst; + u16 command_id; + u16 length; +} __packed; + +/* + * + * Common Commands + * + */ +struct sst_cmd_generic { + struct sst_dsp_header header; +} __packed; +struct sst_cmd_set_params { + struct sst_destination_id dst; + u16 command_id; + char params[0]; +} __packed; +#define SST_CONTROL_NAME(xpname, xmname, xinstance, xtype) \ + xpname " " xmname " " #xinstance " " xtype + +#define SST_COMBO_CONTROL_NAME(xpname, xmname, xinstance, xtype, xsubmodule) \ + xpname " " xmname " " #xinstance " " xtype " " xsubmodule +enum sst_algo_kcontrol_type { + SST_ALGO_PARAMS, + SST_ALGO_BYPASS, +}; + +struct sst_algo_control { + enum sst_algo_kcontrol_type type; + int max; + u16 module_id; + u16 pipe_id; + u16 task_id; + u16 cmd_id; + bool bypass; + unsigned char *params; + struct snd_soc_dapm_widget *w; +}; + +/* size of the control = size of params + size of length field */ +#define SST_ALGO_CTL_VALUE(xcount, xtype, xpipe, xmod, xtask, xcmd) \ + (struct sst_algo_control){ \ + .max = xcount + sizeof(u16), .type = xtype, .module_id = xmod, \ + .pipe_id = xpipe, .task_id = xtask, .cmd_id = xcmd, \ + } + +#define SST_ALGO_KCONTROL(xname, xcount, xmod, xpipe, \ + xtask, xcmd, xtype, xinfo, xget, xput) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .info = xinfo, .get = xget, .put = xput, \ + .private_value = (unsigned long)& \ + SST_ALGO_CTL_VALUE(xcount, xtype, xpipe, \ + xmod, xtask, xcmd), \ +} + +#define SST_ALGO_KCONTROL_BYTES(xpname, xmname, xcount, xmod, \ + xpipe, xinstance, xtask, xcmd) \ + SST_ALGO_KCONTROL(SST_CONTROL_NAME(xpname, xmname, xinstance, "params"), \ + xcount, xmod, xpipe, xtask, xcmd, SST_ALGO_PARAMS, \ + sst_algo_bytes_ctl_info, \ + sst_algo_control_get, sst_algo_control_set) + +#define SST_ALGO_KCONTROL_BOOL(xpname, xmname, xmod, xpipe, xinstance, xtask) \ + SST_ALGO_KCONTROL(SST_CONTROL_NAME(xpname, xmname, xinstance, "bypass"), \ + 0, xmod, xpipe, xtask, 0, SST_ALGO_BYPASS, \ + snd_soc_info_bool_ext, \ + sst_algo_control_get, sst_algo_control_set) + +#define SST_ALGO_BYPASS_PARAMS(xpname, xmname, xcount, xmod, xpipe, \ + xinstance, xtask, xcmd) \ + SST_ALGO_KCONTROL_BOOL(xpname, xmname, xmod, xpipe, xinstance, xtask), \ + SST_ALGO_KCONTROL_BYTES(xpname, xmname, xcount, xmod, xpipe, xinstance, xtask, xcmd) + +#define SST_COMBO_ALGO_KCONTROL_BYTES(xpname, xmname, xsubmod, xcount, xmod, \ + xpipe, xinstance, xtask, xcmd) \ + SST_ALGO_KCONTROL(SST_COMBO_CONTROL_NAME(xpname, xmname, xinstance, "params", \ + xsubmod), \ + xcount, xmod, xpipe, xtask, xcmd, SST_ALGO_PARAMS, \ + sst_algo_bytes_ctl_info, \ + sst_algo_control_get, sst_algo_control_set) + + +struct sst_enum { + bool tx; + unsigned short reg; + unsigned int max; + const char * const *texts; + struct snd_soc_dapm_widget *w; +}; + #endif diff --git a/sound/soc/intel/sst-mfld-platform.h b/sound/soc/intel/sst-mfld-platform.h index 0c5b943daff3..7092ee3e96a3 100644 --- a/sound/soc/intel/sst-mfld-platform.h +++ b/sound/soc/intel/sst-mfld-platform.h @@ -166,7 +166,7 @@ struct sst_algo_int_control_v2 { struct sst_data { struct platform_device *pdev; struct sst_platform_data *pdata; - char *byte_stream; + struct snd_sst_bytes_v2 *byte_stream; struct mutex lock; }; int sst_register_dsp(struct sst_device *sst); From e306b6ee4d7ed7632765165749a36b8c8b4aeff2 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Tue, 16 Sep 2014 21:02:31 +0200 Subject: [PATCH 166/251] ASoC: cs35l32: remove second linux/slab.h inclusion linux/slab.h was included twice. Signed-off-by: Fabian Frederick Acked-by: Brian Austin Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l32.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c index 76f628bd7f2b..c125925da92e 100644 --- a/sound/soc/codecs/cs35l32.c +++ b/sound/soc/codecs/cs35l32.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include From 6df5d768050f31d810dd3ba0ad8210922c3e9b6d Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Tue, 9 Sep 2014 15:11:32 +0530 Subject: [PATCH 167/251] ASoC: Intel: mrfld: Use snd_soc_dai_get_drvdata to derive drv data Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/sst-mfld-platform-pcm.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/soc/intel/sst-mfld-platform-pcm.c b/sound/soc/intel/sst-mfld-platform-pcm.c index 9906b7c1c2e1..8e1b2c14291c 100644 --- a/sound/soc/intel/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/sst-mfld-platform-pcm.c @@ -252,7 +252,7 @@ int sst_fill_stream_params(void *substream, } static int sst_platform_alloc_stream(struct snd_pcm_substream *substream, - struct snd_soc_platform *platform) + struct snd_soc_dai *dai) { struct sst_runtime_stream *stream = substream->runtime->private_data; @@ -260,7 +260,7 @@ static int sst_platform_alloc_stream(struct snd_pcm_substream *substream, struct snd_sst_params str_params = {0}; struct snd_sst_alloc_params_ext alloc_params = {0}; int ret_val = 0; - struct sst_data *ctx = snd_soc_platform_get_drvdata(platform); + struct sst_data *ctx = snd_soc_dai_get_drvdata(dai); /* set codec params and inform SST driver the same */ sst_fill_pcm_params(substream, ¶m); @@ -377,10 +377,10 @@ static void sst_media_close(struct snd_pcm_substream *substream, kfree(stream); } -static inline unsigned int get_current_pipe_id(struct snd_soc_platform *platform, +static inline unsigned int get_current_pipe_id(struct snd_soc_dai *dai, struct snd_pcm_substream *substream) { - struct sst_data *sst = snd_soc_platform_get_drvdata(platform); + struct sst_data *sst = snd_soc_dai_get_drvdata(dai); struct sst_dev_stream_map *map = sst->pdata->pdev_strm_map; struct sst_runtime_stream *stream = substream->runtime->private_data; @@ -389,7 +389,7 @@ static inline unsigned int get_current_pipe_id(struct snd_soc_platform *platform pipe_id = map[str_id].device_id; - dev_dbg(platform->dev, "got pipe_id = %#x for str_id = %d\n", + dev_dbg(dai->dev, "got pipe_id = %#x for str_id = %d\n", pipe_id, str_id); return pipe_id; } @@ -407,7 +407,7 @@ static int sst_media_prepare(struct snd_pcm_substream *substream, return ret_val; } - ret_val = sst_platform_alloc_stream(substream, dai->platform); + ret_val = sst_platform_alloc_stream(substream, dai); if (ret_val <= 0) return ret_val; snprintf(substream->pcm->id, sizeof(substream->pcm->id), From 8bb1ffdf76276c040a065c4df173dfce98b5ffa3 Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Tue, 16 Sep 2014 22:51:22 +0200 Subject: [PATCH 168/251] ALSA: hda - Replace strnicmp with strncasecmp The kernel used to contain two functions for length-delimited, case-insensitive string comparison, strnicmp with correct semantics and a slightly buggy strncasecmp. The latter is the POSIX name, so strnicmp was renamed to strncasecmp, and strnicmp made into a wrapper for the new strncasecmp to avoid breaking existing users. To allow the compat wrapper strnicmp to be removed at some point in the future, and to avoid the extra indirection cost, do s/strnicmp/strncasecmp/g. Signed-off-by: Rasmus Villemoes Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_sysfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/hda_sysfs.c b/sound/pci/hda/hda_sysfs.c index e2079090ca6f..9b49f156a12e 100644 --- a/sound/pci/hda/hda_sysfs.c +++ b/sound/pci/hda/hda_sysfs.c @@ -514,7 +514,7 @@ enum { static inline int strmatch(const char *a, const char *b) { - return strnicmp(a, b, strlen(b)) == 0; + return strncasecmp(a, b, strlen(b)) == 0; } /* parse the contents after the line "[codec]" From 5d5e63af998026f0340d1081fb15ad3c26d80c81 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 17 Sep 2014 20:58:02 +0800 Subject: [PATCH 169/251] ASoC: Remove return value checking for gpiochip_remove() gpiochip_remove() will return void eventually. Thus this patch removes return value checking for gpiochip_remove(). Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677.c | 5 +---- sound/soc/codecs/wm5100.c | 5 +---- sound/soc/codecs/wm8903.c | 6 +----- sound/soc/codecs/wm8962.c | 5 +---- sound/soc/codecs/wm8996.c | 6 +----- 5 files changed, 5 insertions(+), 22 deletions(-) diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 02bc8bd7caeb..991409f90fd3 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -3274,11 +3274,8 @@ static void rt5677_init_gpio(struct i2c_client *i2c) static void rt5677_free_gpio(struct i2c_client *i2c) { struct rt5677_priv *rt5677 = i2c_get_clientdata(i2c); - int ret; - ret = gpiochip_remove(&rt5677->gpio_chip); - if (ret != 0) - dev_err(&i2c->dev, "Failed to remove GPIOs: %d\n", ret); + gpiochip_remove(&rt5677->gpio_chip); } #else static void rt5677_init_gpio(struct i2c_client *i2c) diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c index 7bb0d36d4c54..a01ad629ed61 100644 --- a/sound/soc/codecs/wm5100.c +++ b/sound/soc/codecs/wm5100.c @@ -2319,11 +2319,8 @@ static void wm5100_init_gpio(struct i2c_client *i2c) static void wm5100_free_gpio(struct i2c_client *i2c) { struct wm5100_priv *wm5100 = i2c_get_clientdata(i2c); - int ret; - ret = gpiochip_remove(&wm5100->gpio_chip); - if (ret != 0) - dev_err(&i2c->dev, "Failed to remove GPIOs: %d\n", ret); + gpiochip_remove(&wm5100->gpio_chip); } #else static void wm5100_init_gpio(struct i2c_client *i2c) diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index aa0984864e76..c038b3e04398 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -1877,11 +1877,7 @@ static void wm8903_init_gpio(struct wm8903_priv *wm8903) static void wm8903_free_gpio(struct wm8903_priv *wm8903) { - int ret; - - ret = gpiochip_remove(&wm8903->gpio_chip); - if (ret != 0) - dev_err(wm8903->dev, "Failed to remove GPIOs: %d\n", ret); + gpiochip_remove(&wm8903->gpio_chip); } #else static void wm8903_init_gpio(struct wm8903_priv *wm8903) diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index 1098ae32f1f9..9077411e62ce 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -3398,11 +3398,8 @@ static void wm8962_init_gpio(struct snd_soc_codec *codec) static void wm8962_free_gpio(struct snd_soc_codec *codec) { struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); - int ret; - ret = gpiochip_remove(&wm8962->gpio_chip); - if (ret != 0) - dev_err(codec->dev, "Failed to remove GPIOs: %d\n", ret); + gpiochip_remove(&wm8962->gpio_chip); } #else static void wm8962_init_gpio(struct snd_soc_codec *codec) diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c index f16ff4f56923..b1dcc11c1b23 100644 --- a/sound/soc/codecs/wm8996.c +++ b/sound/soc/codecs/wm8996.c @@ -2216,11 +2216,7 @@ static void wm8996_init_gpio(struct wm8996_priv *wm8996) static void wm8996_free_gpio(struct wm8996_priv *wm8996) { - int ret; - - ret = gpiochip_remove(&wm8996->gpio_chip); - if (ret != 0) - dev_err(wm8996->dev, "Failed to remove GPIOs: %d\n", ret); + gpiochip_remove(&wm8996->gpio_chip); } #else static void wm8996_init_gpio(struct wm8996_priv *wm8996) From 48561afef401876b4b0e35a303d89884c10fe468 Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Wed, 17 Sep 2014 15:12:33 +0800 Subject: [PATCH 170/251] ASoC: rt5677: Add the TDM function The patch adds the TDM function. Signed-off-by: Oder Chiou Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677.c | 54 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 02bc8bd7caeb..1d4719f5fe75 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -3107,6 +3107,59 @@ static int rt5677_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, return 0; } +static int rt5677_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 |= (1 << 12); + + switch (slots) { + case 4: + val |= (1 << 10); + break; + case 6: + val |= (2 << 10); + break; + case 8: + val |= (3 << 10); + break; + case 2: + default: + break; + } + + switch (slot_width) { + case 20: + val |= (1 << 8); + break; + case 24: + val |= (2 << 8); + break; + case 32: + val |= (3 << 8); + break; + case 16: + default: + break; + } + + switch (dai->id) { + case RT5677_AIF1: + snd_soc_update_bits(codec, RT5677_TDM1_CTRL1, 0x1f00, val); + break; + case RT5677_AIF2: + snd_soc_update_bits(codec, RT5677_TDM2_CTRL1, 0x1f00, val); + break; + default: + break; + } + + return 0; +} + static int rt5677_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { @@ -3357,6 +3410,7 @@ static struct snd_soc_dai_ops rt5677_aif_dai_ops = { .set_fmt = rt5677_set_dai_fmt, .set_sysclk = rt5677_set_dai_sysclk, .set_pll = rt5677_set_dai_pll, + .set_tdm_slot = rt5677_set_tdm_slot, }; static struct snd_soc_dai_driver rt5677_dai[] = { From f4a43caba7d495699f98532b4faee90fd9980732 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Tue, 16 Sep 2014 10:13:16 +0800 Subject: [PATCH 171/251] ASoC: fsl_ssi: refine ipg clock usage in this module Check if ipg clock is in clock-names property, then we can move the ipg clock enable and disable operation to startup and shutdown, that is only enable ipg clock when ssi is working and keep clock is disabled when ssi is in idle. But when the checking is failed, remain the clock control as before. Tested-by: Markus Pargmann Signed-off-by: Shengjiu Wang Acked-by: Nicolin Chen Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_ssi.c | 53 ++++++++++++++++++++++++++++++++++------- 1 file changed, 45 insertions(+), 8 deletions(-) diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 2fc3e6683e4f..16a1361b68b3 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -169,6 +169,7 @@ struct fsl_ssi_private { u8 i2s_mode; bool use_dma; bool use_dual_fifo; + bool has_ipg_clk_name; unsigned int fifo_depth; struct fsl_ssi_rxtx_reg_val rxtx_reg_val; @@ -530,6 +531,11 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(rtd->cpu_dai); + int ret; + + ret = clk_prepare_enable(ssi_private->clk); + if (ret) + return ret; /* When using dual fifo mode, it is safer to ensure an even period * size. If appearing to an odd number while DMA always starts its @@ -543,6 +549,21 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream, return 0; } +/** + * fsl_ssi_shutdown: shutdown the SSI + * + */ +static void fsl_ssi_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct fsl_ssi_private *ssi_private = + snd_soc_dai_get_drvdata(rtd->cpu_dai); + + clk_disable_unprepare(ssi_private->clk); + +} + /** * fsl_ssi_set_bclk - configure Digital Audio Interface bit clock * @@ -1043,6 +1064,7 @@ static int fsl_ssi_dai_probe(struct snd_soc_dai *dai) static const struct snd_soc_dai_ops fsl_ssi_dai_ops = { .startup = fsl_ssi_startup, + .shutdown = fsl_ssi_shutdown, .hw_params = fsl_ssi_hw_params, .hw_free = fsl_ssi_hw_free, .set_fmt = fsl_ssi_set_dai_fmt, @@ -1168,17 +1190,22 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev, u32 dmas[4]; int ret; - ssi_private->clk = devm_clk_get(&pdev->dev, NULL); + if (ssi_private->has_ipg_clk_name) + ssi_private->clk = devm_clk_get(&pdev->dev, "ipg"); + else + ssi_private->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(ssi_private->clk)) { ret = PTR_ERR(ssi_private->clk); dev_err(&pdev->dev, "could not get clock: %d\n", ret); return ret; } - ret = clk_prepare_enable(ssi_private->clk); - if (ret) { - dev_err(&pdev->dev, "clk_prepare_enable failed: %d\n", ret); - return ret; + if (!ssi_private->has_ipg_clk_name) { + ret = clk_prepare_enable(ssi_private->clk); + if (ret) { + dev_err(&pdev->dev, "clk_prepare_enable failed: %d\n", ret); + return ret; + } } /* For those SLAVE implementations, we ingore non-baudclk cases @@ -1236,8 +1263,9 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev, return 0; error_pcm: - clk_disable_unprepare(ssi_private->clk); + if (!ssi_private->has_ipg_clk_name) + clk_disable_unprepare(ssi_private->clk); return ret; } @@ -1246,7 +1274,8 @@ static void fsl_ssi_imx_clean(struct platform_device *pdev, { if (!ssi_private->use_dma) imx_pcm_fiq_exit(pdev); - clk_disable_unprepare(ssi_private->clk); + if (!ssi_private->has_ipg_clk_name) + clk_disable_unprepare(ssi_private->clk); } static int fsl_ssi_probe(struct platform_device *pdev) @@ -1321,8 +1350,16 @@ static int fsl_ssi_probe(struct platform_device *pdev) return -ENOMEM; } - ssi_private->regs = devm_regmap_init_mmio(&pdev->dev, iomem, + ret = of_property_match_string(np, "clock-names", "ipg"); + if (ret < 0) { + ssi_private->has_ipg_clk_name = false; + ssi_private->regs = devm_regmap_init_mmio(&pdev->dev, iomem, &fsl_ssi_regconfig); + } else { + ssi_private->has_ipg_clk_name = true; + ssi_private->regs = devm_regmap_init_mmio_clk(&pdev->dev, + "ipg", iomem, &fsl_ssi_regconfig); + } if (IS_ERR(ssi_private->regs)) { dev_err(&pdev->dev, "Failed to init register map\n"); return PTR_ERR(ssi_private->regs); From 5ae0095d00d48be60b2e3cbdb79a35a7d796d96b Mon Sep 17 00:00:00 2001 From: Harley Griggs Date: Wed, 10 Sep 2014 19:58:25 +0100 Subject: [PATCH 172/251] ALSA: virtuoso: add partial Xonar Xense support This patch adds partial support for the Xonar Xense. [trivial coding style fixes by tiwai] Signed-off-by: Harley Griggs Acked-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/pci/oxygen/virtuoso.c | 1 + sound/pci/oxygen/xonar_pcm179x.c | 133 +++++++++++++++++++++++++++++++ 2 files changed, 134 insertions(+) diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c index 7b317a28a19c..83de6fb01021 100644 --- a/sound/pci/oxygen/virtuoso.c +++ b/sound/pci/oxygen/virtuoso.c @@ -52,6 +52,7 @@ static const struct pci_device_id xonar_ids[] = { { OXYGEN_PCI_SUBID(0x1043, 0x835d) }, { OXYGEN_PCI_SUBID(0x1043, 0x835e) }, { OXYGEN_PCI_SUBID(0x1043, 0x838e) }, + { OXYGEN_PCI_SUBID(0x1043, 0x8428) }, { OXYGEN_PCI_SUBID(0x1043, 0x8522) }, { OXYGEN_PCI_SUBID(0x1043, 0x85f4) }, { OXYGEN_PCI_SUBID_BROKEN_EEPROM }, diff --git a/sound/pci/oxygen/xonar_pcm179x.c b/sound/pci/oxygen/xonar_pcm179x.c index 0d6a805e8b62..24109d37ca09 100644 --- a/sound/pci/oxygen/xonar_pcm179x.c +++ b/sound/pci/oxygen/xonar_pcm179x.c @@ -212,6 +212,9 @@ #define GPIO_ST_MAGIC 0x0040 #define GPIO_ST_HP 0x0080 +#define GPIO_XENSE_OUTPUT_ENABLE (0x0001 | 0x0010 | 0x0020) +#define GPIO_XENSE_SPEAKERS 0x0080 + #define I2C_DEVICE_PCM1796(i) (0x98 + ((i) << 1)) /* 10011, ii, /W=0 */ #define I2C_DEVICE_CS2000 0x9c /* 100111, 0, /W=0 */ @@ -500,6 +503,51 @@ static void xonar_stx_init(struct oxygen *chip) xonar_st_init_common(chip); } +static void xonar_xense_init(struct oxygen *chip) +{ + struct xonar_pcm179x *data = chip->model_data; + + data->generic.ext_power_reg = OXYGEN_GPI_DATA; + data->generic.ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK; + data->generic.ext_power_bit = GPI_EXT_POWER; + xonar_init_ext_power(chip); + + data->generic.anti_pop_delay = 100; + data->has_cs2000 = 1; + data->cs2000_regs[CS2000_FUN_CFG_1] = CS2000_REF_CLK_DIV_1; + + oxygen_write16(chip, OXYGEN_I2S_A_FORMAT, + OXYGEN_RATE_48000 | + OXYGEN_I2S_FORMAT_I2S | + OXYGEN_I2S_MCLK(MCLK_512) | + OXYGEN_I2S_BITS_16 | + OXYGEN_I2S_MASTER | + OXYGEN_I2S_BCLK_64); + + xonar_st_init_i2c(chip); + cs2000_registers_init(chip); + + data->generic.output_enable_bit = GPIO_XENSE_OUTPUT_ENABLE; + data->dacs = 1; + data->hp_gain_offset = 2*-18; + + pcm1796_init(chip); + + oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, + GPIO_INPUT_ROUTE | GPIO_ST_HP_REAR | + GPIO_ST_MAGIC | GPIO_XENSE_SPEAKERS); + oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, + GPIO_INPUT_ROUTE | GPIO_ST_HP_REAR | + GPIO_XENSE_SPEAKERS); + + xonar_init_cs53x1(chip); + xonar_enable_output(chip); + + snd_component_add(chip->card, "PCM1796"); + snd_component_add(chip->card, "CS5381"); + snd_component_add(chip->card, "CS2000"); +} + static void xonar_d2_cleanup(struct oxygen *chip) { xonar_disable_output(chip); @@ -862,6 +910,67 @@ static const struct snd_kcontrol_new st_controls[] = { }, }; +static int xense_output_switch_get(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + u16 gpio; + + gpio = oxygen_read16(chip, OXYGEN_GPIO_DATA); + if (gpio & GPIO_XENSE_SPEAKERS) + value->value.enumerated.item[0] = 0; + else if (!(gpio & GPIO_XENSE_SPEAKERS) && (gpio & GPIO_ST_HP_REAR)) + value->value.enumerated.item[0] = 1; + else + value->value.enumerated.item[0] = 2; + return 0; +} + +static int xense_output_switch_put(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + struct xonar_pcm179x *data = chip->model_data; + u16 gpio_old, gpio; + + mutex_lock(&chip->mutex); + gpio_old = oxygen_read16(chip, OXYGEN_GPIO_DATA); + gpio = gpio_old; + switch (value->value.enumerated.item[0]) { + case 0: + gpio |= GPIO_XENSE_SPEAKERS | GPIO_ST_HP_REAR; + break; + case 1: + gpio = (gpio | GPIO_ST_HP_REAR) & ~GPIO_XENSE_SPEAKERS; + break; + case 2: + gpio &= ~(GPIO_XENSE_SPEAKERS | GPIO_ST_HP_REAR); + break; + } + oxygen_write16(chip, OXYGEN_GPIO_DATA, gpio); + data->hp_active = !(gpio & GPIO_XENSE_SPEAKERS); + update_pcm1796_volume(chip); + mutex_unlock(&chip->mutex); + return gpio != gpio_old; +} + +static const struct snd_kcontrol_new xense_controls[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Analog Output", + .info = st_output_switch_info, + .get = xense_output_switch_get, + .put = xense_output_switch_put, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Headphones Impedance Playback Enum", + .info = st_hp_volume_offset_info, + .get = st_hp_volume_offset_get, + .put = st_hp_volume_offset_put, + }, +}; + static void xonar_line_mic_ac97_switch(struct oxygen *chip, unsigned int reg, unsigned int mute) { @@ -949,6 +1058,23 @@ static int xonar_st_mixer_init(struct oxygen *chip) return 0; } +static int xonar_xense_mixer_init(struct oxygen *chip) +{ + unsigned int i; + int err; + + for (i = 0; i < ARRAY_SIZE(xense_controls); ++i) { + err = snd_ctl_add(chip->card, + snd_ctl_new1(&xense_controls[i], chip)); + if (err < 0) + return err; + } + err = add_pcm1796_controls(chip); + if (err < 0) + return err; + return 0; +} + static void dump_pcm1796_registers(struct oxygen *chip, struct snd_info_buffer *buffer) { @@ -1159,6 +1285,13 @@ int get_xonar_pcm179x_model(struct oxygen *chip, chip->model.resume = xonar_stx_resume; chip->model.set_dac_params = set_pcm1796_params; break; + case 0x8428: + chip->model = model_xonar_st; + chip->model.shortname = "Xonar Xense"; + chip->model.chip = "AV100"; + chip->model.init = xonar_xense_init; + chip->model.mixer_init = xonar_xense_mixer_init; + break; default: return -EINVAL; } From 4e9c58cb1219bcbcf6e698ed6541b275048bfa88 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Sun, 21 Sep 2014 22:52:46 +0200 Subject: [PATCH 173/251] ALSA: oxygen: set fifo_size Allow the driver to report the hardware FIFO size. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/pci/oxygen/oxygen_pcm.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sound/pci/oxygen/oxygen_pcm.c b/sound/pci/oxygen/oxygen_pcm.c index cc0bcd9f3350..02828240ba15 100644 --- a/sound/pci/oxygen/oxygen_pcm.c +++ b/sound/pci/oxygen/oxygen_pcm.c @@ -29,6 +29,9 @@ /* the multichannel DMA channel has a 24-bit counter */ #define BUFFER_BYTES_MAX_MULTICH ((1 << 24) * 4) +#define FIFO_BYTES 256 +#define FIFO_BYTES_MULTICH 1024 + #define PERIOD_BYTES_MIN 64 #define DEFAULT_BUFFER_BYTES (BUFFER_BYTES_MAX / 2) @@ -60,6 +63,7 @@ static const struct snd_pcm_hardware oxygen_stereo_hardware = { .period_bytes_max = BUFFER_BYTES_MAX, .periods_min = 1, .periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN, + .fifo_size = FIFO_BYTES, }; static const struct snd_pcm_hardware oxygen_multichannel_hardware = { .info = SNDRV_PCM_INFO_MMAP | @@ -87,6 +91,7 @@ static const struct snd_pcm_hardware oxygen_multichannel_hardware = { .period_bytes_max = BUFFER_BYTES_MAX_MULTICH, .periods_min = 1, .periods_max = BUFFER_BYTES_MAX_MULTICH / PERIOD_BYTES_MIN, + .fifo_size = FIFO_BYTES_MULTICH, }; static const struct snd_pcm_hardware oxygen_ac97_hardware = { .info = SNDRV_PCM_INFO_MMAP | @@ -106,6 +111,7 @@ static const struct snd_pcm_hardware oxygen_ac97_hardware = { .period_bytes_max = BUFFER_BYTES_MAX, .periods_min = 1, .periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN, + .fifo_size = FIFO_BYTES, }; static const struct snd_pcm_hardware *const oxygen_hardware[PCM_COUNT] = { @@ -141,6 +147,10 @@ static int oxygen_open(struct snd_pcm_substream *substream, runtime->hw.rates &= ~(SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_64000); runtime->hw.rate_min = 44100; + /* fall through */ + case PCM_A: + case PCM_B: + runtime->hw.fifo_size = 0; break; case PCM_MULTICH: runtime->hw.channels_max = chip->model.dac_channels_pcm; From 90bdbb46f41c9fa670d7b0709e0c8a92ad82bdfe Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Thu, 18 Sep 2014 14:45:59 +0800 Subject: [PATCH 174/251] ASoC: rt5677: Add sidetone function Add sidetone function Signed-off-by: Anatol Pomozov Signed-off-by: Oder Chiou Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677.c | 9 +++++++++ sound/soc/codecs/rt5677.h | 4 ++++ 2 files changed, 13 insertions(+) diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 1d4719f5fe75..4a0f3dfb2a47 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -541,6 +541,7 @@ static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0); static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0); static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0); static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0); +static const DECLARE_TLV_DB_SCALE(st_vol_tlv, -4650, 150, 0); /* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */ static unsigned int bst_tlv[] = { @@ -605,6 +606,10 @@ static const struct snd_kcontrol_new rt5677_snd_controls[] = { RT5677_MONO_ADC_L_VOL_SFT, RT5677_MONO_ADC_R_VOL_SFT, 127, 0, adc_vol_tlv), + /* Sidetone Control */ + SOC_SINGLE_TLV("Sidetone Volume", RT5677_SIDETONE_CTRL, + RT5677_ST_VOL_SFT, 31, 0, st_vol_tlv), + /* ADC Boost Volume Control */ SOC_DOUBLE_TLV("STO1 ADC Boost Volume", RT5677_STO1_2_ADC_BST, RT5677_STO1_ADC_L_BST_SFT, RT5677_STO1_ADC_R_BST_SFT, 3, 0, @@ -1993,6 +1998,9 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = { /* Sidetone Mux */ SND_SOC_DAPM_MUX("Sidetone Mux", SND_SOC_NOPM, 0, 0, &rt5677_sidetone_mux), + SND_SOC_DAPM_SUPPLY("Sidetone Power", RT5677_SIDETONE_CTRL, + RT5677_ST_EN_SFT, 0, NULL, 0), + /* VAD Mux*/ SND_SOC_DAPM_MUX("VAD ADC Mux", SND_SOC_NOPM, 0, 0, &rt5677_vad_src_mux), @@ -2704,6 +2712,7 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { { "Sidetone Mux", "DMIC4 L", "DMIC L4" }, { "Sidetone Mux", "ADC1", "ADC 1" }, { "Sidetone Mux", "ADC2", "ADC 2" }, + { "Sidetone Mux", NULL, "Sidetone Power" }, { "Stereo DAC MIXL", "ST L Switch", "Sidetone Mux" }, { "Stereo DAC MIXL", "DAC1 L Switch", "DAC1 MIXL" }, diff --git a/sound/soc/codecs/rt5677.h b/sound/soc/codecs/rt5677.h index b61b72cfcbd7..1fe88727a063 100644 --- a/sound/soc/codecs/rt5677.h +++ b/sound/soc/codecs/rt5677.h @@ -382,6 +382,10 @@ #define RT5677_ST_SEL_SFT 9 #define RT5677_ST_EN (0x1 << 6) #define RT5677_ST_EN_SFT 6 +#define RT5677_ST_GAIN (0x1 << 5) +#define RT5677_ST_GAIN_SFT 5 +#define RT5677_ST_VOL_MASK (0x1f << 0) +#define RT5677_ST_VOL_SFT 0 /* Analog DAC1/2/3 Source Control (0x15) */ #define RT5677_ANA_DAC3_SRC_SEL_MASK (0x3 << 4) From e3f205a72c4554b58f51d5afd98195c4ff54d215 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 23 Sep 2014 00:56:28 +0200 Subject: [PATCH 175/251] ASoC: Remove locking in snd_soc_{new,free}_ac97_codec() snd_soc_new_ac97_codec() and snd_soc_free_ac97_codec() are called from within a CODEC's probe() and remove() callbacks. Those will not run concurrently against each other for the same CODEC instance, hence it is not necessary to protect the two functions with a mutex. This removes the last user in the ASoC core of the snd_soc_codec mutex field and will allow us to eventually remove it. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index d4bfd4a9076f..a504cf42bf0a 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2107,13 +2107,9 @@ static struct platform_driver soc_driver = { int snd_soc_new_ac97_codec(struct snd_soc_codec *codec, struct snd_ac97_bus_ops *ops, int num) { - mutex_lock(&codec->mutex); - codec->ac97 = kzalloc(sizeof(struct snd_ac97), GFP_KERNEL); - if (codec->ac97 == NULL) { - mutex_unlock(&codec->mutex); + if (codec->ac97 == NULL) return -ENOMEM; - } codec->ac97->bus = kzalloc(sizeof(struct snd_ac97_bus), GFP_KERNEL); if (codec->ac97->bus == NULL) { @@ -2132,7 +2128,6 @@ int snd_soc_new_ac97_codec(struct snd_soc_codec *codec, */ codec->ac97_created = 1; - mutex_unlock(&codec->mutex); return 0; } EXPORT_SYMBOL_GPL(snd_soc_new_ac97_codec); @@ -2302,7 +2297,6 @@ EXPORT_SYMBOL_GPL(snd_soc_set_ac97_ops_of_reset); */ void snd_soc_free_ac97_codec(struct snd_soc_codec *codec) { - mutex_lock(&codec->mutex); #ifdef CONFIG_SND_SOC_AC97_BUS soc_unregister_ac97_codec(codec); #endif @@ -2310,7 +2304,6 @@ void snd_soc_free_ac97_codec(struct snd_soc_codec *codec) kfree(codec->ac97); codec->ac97 = NULL; codec->ac97_created = 0; - mutex_unlock(&codec->mutex); } EXPORT_SYMBOL_GPL(snd_soc_free_ac97_codec); From a5062dee82826f54529c89d0e58211897b1b4c68 Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Tue, 23 Sep 2014 09:04:49 +0200 Subject: [PATCH 176/251] ALSA: hda - add explicit include of err.h Since every caller of snd_hda_jack_detect_enable_callback needs to use the macros from err.h, it makes sense to include it directly from hda_jack.h. Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_jack.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/pci/hda/hda_jack.h b/sound/pci/hda/hda_jack.h index b41e0a3ea1fb..13cb375454f6 100644 --- a/sound/pci/hda/hda_jack.h +++ b/sound/pci/hda/hda_jack.h @@ -12,6 +12,8 @@ #ifndef __SOUND_HDA_JACK_H #define __SOUND_HDA_JACK_H +#include + struct auto_pin_cfg; struct hda_jack_tbl; struct hda_jack_callback; From 8c8f2f6fc1c8eec9e14810f21386fe295a42a40f Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 23 Sep 2014 04:15:48 +0200 Subject: [PATCH 177/251] ASoC: Fix snd_soc_{new,free}_ac97_codec() locking removal Commit e3f205a72c45 ("ASoC: Remove locking in snd_soc_{new,free}_ac97_codec()") overlooked a unlock on one of the error paths. Fixes: e3f205a72c45 ("ASoC: Remove locking in snd_soc_{new,free}_ac97_codec()") Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index a504cf42bf0a..3c57f5cf2779 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2115,7 +2115,6 @@ int snd_soc_new_ac97_codec(struct snd_soc_codec *codec, if (codec->ac97->bus == NULL) { kfree(codec->ac97); codec->ac97 = NULL; - mutex_unlock(&codec->mutex); return -ENOMEM; } From 861a04ed15a48e9af7b591cd8ae3bc46aece1733 Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Tue, 23 Sep 2014 10:38:17 +0200 Subject: [PATCH 178/251] ALSA: hda - Move the function "check_amp_caps" to hda_codec.c The next patch will use it, so make it visible across modules. Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 20 ++++++++++++++++++++ sound/pci/hda/hda_generic.c | 17 ----------------- sound/pci/hda/hda_local.h | 8 ++++++++ 3 files changed, 28 insertions(+), 17 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 0aa2e1ed1dbc..15e0089492f7 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -2001,6 +2001,26 @@ u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction) } EXPORT_SYMBOL_GPL(query_amp_caps); +/** + * snd_hda_check_amp_caps - query AMP capabilities + * @codec: the HD-audio codec + * @nid: the NID to query + * @dir: either #HDA_INPUT or #HDA_OUTPUT + * + * Check whether the widget has the given amp capability for the direction. + */ +bool snd_hda_check_amp_caps(struct hda_codec *codec, hda_nid_t nid, + int dir, unsigned int bits) +{ + if (!nid) + return false; + if (get_wcaps(codec, nid) & (1 << (dir + 1))) + if (query_amp_caps(codec, nid, dir) & bits) + return true; + return false; +} +EXPORT_SYMBOL_GPL(snd_hda_check_amp_caps); + /** * snd_hda_override_amp_caps - Override the AMP capabilities * @codec: the CODEC to clean up diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 32a85f9cac4b..64220c08bd98 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -519,18 +519,6 @@ static unsigned int amp_val_replace_channels(unsigned int val, unsigned int chs) return val; } -/* check whether the widget has the given amp capability for the direction */ -static bool check_amp_caps(struct hda_codec *codec, hda_nid_t nid, - int dir, unsigned int bits) -{ - if (!nid) - return false; - if (get_wcaps(codec, nid) & (1 << (dir + 1))) - if (query_amp_caps(codec, nid, dir) & bits) - return true; - return false; -} - static bool same_amp_caps(struct hda_codec *codec, hda_nid_t nid1, hda_nid_t nid2, int dir) { @@ -540,11 +528,6 @@ static bool same_amp_caps(struct hda_codec *codec, hda_nid_t nid1, query_amp_caps(codec, nid2, dir)); } -#define nid_has_mute(codec, nid, dir) \ - check_amp_caps(codec, nid, dir, (AC_AMPCAP_MUTE | AC_AMPCAP_MIN_MUTE)) -#define nid_has_volume(codec, nid, dir) \ - check_amp_caps(codec, nid, dir, AC_AMPCAP_NUM_STEPS) - /* look for a widget suitable for assigning a mute switch in the path */ static hda_nid_t look_for_out_mute_nid(struct hda_codec *codec, struct nid_path *path) diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 8a018d4cbe98..7eb44e78e141 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -603,6 +603,14 @@ int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid); int snd_hda_override_pin_caps(struct hda_codec *codec, hda_nid_t nid, unsigned int caps); +bool snd_hda_check_amp_caps(struct hda_codec *codec, hda_nid_t nid, + int dir, unsigned int bits); + +#define nid_has_mute(codec, nid, dir) \ + snd_hda_check_amp_caps(codec, nid, dir, (AC_AMPCAP_MUTE | AC_AMPCAP_MIN_MUTE)) +#define nid_has_volume(codec, nid, dir) \ + snd_hda_check_amp_caps(codec, nid, dir, AC_AMPCAP_NUM_STEPS) + /* flags for hda_nid_item */ #define HDA_NID_ITEM_AMP (1<<0) From 95f72cf2cdf0e612aeaf36d8af51689882fd64db Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Tue, 23 Sep 2014 10:38:18 +0200 Subject: [PATCH 179/251] ALSA: hda - Sort input pins depending on amp caps If one input has a boost and another one has not, and they're equal otherwise, it's more likely you want to use the input with the boost as your primary input. See hda-emu.git/codecs/canonical/cx20590-lenovo-20b2z00bus-ccert-201305-13496 for an example. Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_auto_parser.c | 21 ++++++++++++++------- sound/pci/hda/hda_auto_parser.h | 1 + 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c index 51dea49aadd4..fcc5e478c9a1 100644 --- a/sound/pci/hda/hda_auto_parser.c +++ b/sound/pci/hda/hda_auto_parser.c @@ -57,12 +57,14 @@ static void sort_pins_by_sequence(hda_nid_t *pins, struct auto_out_pin *list, /* add the found input-pin to the cfg->inputs[] table */ -static void add_auto_cfg_input_pin(struct auto_pin_cfg *cfg, hda_nid_t nid, - int type) +static void add_auto_cfg_input_pin(struct hda_codec *codec, struct auto_pin_cfg *cfg, + hda_nid_t nid, int type) { if (cfg->num_inputs < AUTO_CFG_MAX_INS) { cfg->inputs[cfg->num_inputs].pin = nid; cfg->inputs[cfg->num_inputs].type = type; + cfg->inputs[cfg->num_inputs].has_boost_on_pin = + nid_has_volume(codec, nid, HDA_INPUT); cfg->num_inputs++; } } @@ -71,7 +73,12 @@ static int compare_input_type(const void *ap, const void *bp) { const struct auto_pin_cfg_item *a = ap; const struct auto_pin_cfg_item *b = bp; - return (int)(a->type - b->type); + if (a->type != b->type) + return (int)(a->type - b->type); + + /* In case one has boost and the other one has not, + pick the one with boost first. */ + return (int)(b->has_boost_on_pin - a->has_boost_on_pin); } /* Reorder the surround channels @@ -268,16 +275,16 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec, cfg->hp_outs++; break; case AC_JACK_MIC_IN: - add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_MIC); + add_auto_cfg_input_pin(codec, cfg, nid, AUTO_PIN_MIC); break; case AC_JACK_LINE_IN: - add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_LINE_IN); + add_auto_cfg_input_pin(codec, cfg, nid, AUTO_PIN_LINE_IN); break; case AC_JACK_CD: - add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_CD); + add_auto_cfg_input_pin(codec, cfg, nid, AUTO_PIN_CD); break; case AC_JACK_AUX: - add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_AUX); + add_auto_cfg_input_pin(codec, cfg, nid, AUTO_PIN_AUX); break; case AC_JACK_SPDIF_OUT: case AC_JACK_DIG_OTHER_OUT: diff --git a/sound/pci/hda/hda_auto_parser.h b/sound/pci/hda/hda_auto_parser.h index e941f604f5e5..2b8e29fd73e7 100644 --- a/sound/pci/hda/hda_auto_parser.h +++ b/sound/pci/hda/hda_auto_parser.h @@ -38,6 +38,7 @@ struct auto_pin_cfg_item { int type; unsigned int is_headset_mic:1; unsigned int is_headphone_mic:1; /* Mic-only in headphone jack */ + unsigned int has_boost_on_pin:1; }; struct auto_pin_cfg; From 7a7686bd0d153c0d6e120da6712c9339aaeaa2f9 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Tue, 23 Sep 2014 16:30:24 +0530 Subject: [PATCH 180/251] ALSA: ctxfi: sparse warning fixed sparse warning of incorrect type (different address spaces) in cthw20k1.c and cthw20k2.c which was being actually caused as mem_base was of the type unsigned long. Again as mem_base was previously unsigned long , so it required many typecasts in the code to convert interger to pointer. Now after giving the correct type of mem_base as void __iomem * we can also remove those typecasts maintaining the same functionality and logic of the code. Signed-off-by: Sudip Mukherjee Signed-off-by: Takashi Iwai --- sound/pci/ctxfi/cthardware.h | 2 +- sound/pci/ctxfi/cthw20k1.c | 6 +++--- sound/pci/ctxfi/cthw20k2.c | 12 ++++++------ 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/sound/pci/ctxfi/cthardware.h b/sound/pci/ctxfi/cthardware.h index 5977e9a24b5c..c5ded6a6654f 100644 --- a/sound/pci/ctxfi/cthardware.h +++ b/sound/pci/ctxfi/cthardware.h @@ -186,7 +186,7 @@ struct hw { struct pci_dev *pci; /* the pci kernel structure of this card */ int irq; unsigned long io_base; - unsigned long mem_base; + void __iomem *mem_base; enum CHIPTYP chip_type; enum CTCARDS model; diff --git a/sound/pci/ctxfi/cthw20k1.c b/sound/pci/ctxfi/cthw20k1.c index 71d496f780e3..8fc524fbaeab 100644 --- a/sound/pci/ctxfi/cthw20k1.c +++ b/sound/pci/ctxfi/cthw20k1.c @@ -1802,7 +1802,7 @@ static int uaa_to_xfi(struct pci_dev *pci) unsigned int is_uaa; unsigned int data[4] = {0}; unsigned int io_base; - void *mem_base; + void __iomem *mem_base; int i; const u32 CTLX = CTLBITS('C', 'T', 'L', 'X'); const u32 CTL_ = CTLBITS('C', 'T', 'L', '-'); @@ -1984,9 +1984,9 @@ static int hw_card_shutdown(struct hw *hw) hw->irq = -1; if (hw->mem_base) - iounmap((void *)hw->mem_base); + iounmap(hw->mem_base); - hw->mem_base = (unsigned long)NULL; + hw->mem_base = NULL; if (hw->io_base) pci_release_regions(hw->pci); diff --git a/sound/pci/ctxfi/cthw20k2.c b/sound/pci/ctxfi/cthw20k2.c index df2d8c5eb926..b2c5d5a05a95 100644 --- a/sound/pci/ctxfi/cthw20k2.c +++ b/sound/pci/ctxfi/cthw20k2.c @@ -2045,8 +2045,8 @@ static int hw_card_start(struct hw *hw) goto error1; hw->io_base = pci_resource_start(hw->pci, 2); - hw->mem_base = (unsigned long)ioremap(hw->io_base, - pci_resource_len(hw->pci, 2)); + hw->mem_base = ioremap(hw->io_base, + pci_resource_len(hw->pci, 2)); if (!hw->mem_base) { err = -ENOENT; goto error2; @@ -2106,9 +2106,9 @@ static int hw_card_shutdown(struct hw *hw) hw->irq = -1; if (hw->mem_base) - iounmap((void *)hw->mem_base); + iounmap(hw->mem_base); - hw->mem_base = (unsigned long)NULL; + hw->mem_base = NULL; if (hw->io_base) pci_release_regions(hw->pci); @@ -2228,12 +2228,12 @@ static int hw_resume(struct hw *hw, struct card_conf *info) static u32 hw_read_20kx(struct hw *hw, u32 reg) { - return readl((void *)(hw->mem_base + reg)); + return readl(hw->mem_base + reg); } static void hw_write_20kx(struct hw *hw, u32 reg, u32 data) { - writel(data, (void *)(hw->mem_base + reg)); + writel(data, hw->mem_base + reg); } static struct hw ct20k2_preset = { From 5c7c343a1159d1cb7604b6137cf547b2c1e2375d Mon Sep 17 00:00:00 2001 From: Howard Mitchell Date: Fri, 19 Sep 2014 12:50:31 +0100 Subject: [PATCH 181/251] ASoC: core: Fix volsw_range funcs so SOC_DOUBLE_R_RANGE_TLV works. This fixes a bug when using the SOC_DOUBLE_R_RANGE_TLV macro in the invert mode. In the non-invert case, e.g. SOC_DOUBLE_R_RANGE_TLV("", , , 0, 40, 255, 0, ) the range sent to the hardware is 40..255, but in the invert case: SOC_DOUBLE_R_RANGE_TLV("", , , 0, 40, 255, 1, ) the range 215..0 was being sent to the hardware. This commit corrects this to 255..40 so it is consistent with the non-invert case. Signed-off-by: Howard Mitchell Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 3c57f5cf2779..dde4b82ad41d 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3019,9 +3019,10 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol, unsigned int val, val_mask; int ret; - val = ((ucontrol->value.integer.value[0] + min) & mask); if (invert) - val = max - val; + val = (max - ucontrol->value.integer.value[0]) & mask; + else + val = ((ucontrol->value.integer.value[0] + min) & mask); val_mask = mask << shift; val = val << shift; @@ -3030,9 +3031,10 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol, return ret; if (snd_soc_volsw_is_stereo(mc)) { - val = ((ucontrol->value.integer.value[1] + min) & mask); if (invert) - val = max - val; + val = (max - ucontrol->value.integer.value[1]) & mask; + else + val = ((ucontrol->value.integer.value[1] + min) & mask); val_mask = mask << shift; val = val << shift; @@ -3077,8 +3079,9 @@ int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol, if (invert) ucontrol->value.integer.value[0] = max - ucontrol->value.integer.value[0]; - ucontrol->value.integer.value[0] = - ucontrol->value.integer.value[0] - min; + else + ucontrol->value.integer.value[0] = + ucontrol->value.integer.value[0] - min; if (snd_soc_volsw_is_stereo(mc)) { ret = snd_soc_component_read(component, rreg, &val); @@ -3089,8 +3092,9 @@ int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol, if (invert) ucontrol->value.integer.value[1] = max - ucontrol->value.integer.value[1]; - ucontrol->value.integer.value[1] = - ucontrol->value.integer.value[1] - min; + else + ucontrol->value.integer.value[1] = + ucontrol->value.integer.value[1] - min; } return 0; From 7a7f0ba03d521ac2d36c9015278bc35657b3dcc9 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Fri, 19 Sep 2014 14:48:17 +0300 Subject: [PATCH 182/251] ASoC: max98090: Move interrupt request from codec probe to i2c probe Keep MAX98090 interrupt requested after i2c device probing as long as the driver is loaded. This fixes the issue where subsequent codec probe max98090_probe() call fails in interrupt request since interrupt wasn't freed over codec remove-reprobe cycle. Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/codecs/max98090.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index f1543653a699..fe77df6a76c2 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c @@ -2159,12 +2159,16 @@ static void max98090_jack_work(struct work_struct *work) static irqreturn_t max98090_interrupt(int irq, void *data) { - struct snd_soc_codec *codec = data; - struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec); + struct max98090_priv *max98090 = data; + struct snd_soc_codec *codec = max98090->codec; int ret; unsigned int mask; unsigned int active; + /* Treat interrupt before codec is initialized as spurious */ + if (codec == NULL) + return IRQ_NONE; + dev_dbg(codec->dev, "***** max98090_interrupt *****\n"); ret = regmap_read(max98090->regmap, M98090_REG_INTERRUPT_S, &mask); @@ -2367,17 +2371,6 @@ static int max98090_probe(struct snd_soc_codec *codec) snd_soc_write(codec, M98090_REG_JACK_DETECT, M98090_JDETEN_MASK | M98090_JDEB_25MS); - /* Register for interrupts */ - dev_dbg(codec->dev, "irq = %d\n", max98090->irq); - - ret = devm_request_threaded_irq(codec->dev, max98090->irq, NULL, - max98090_interrupt, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, - "max98090_interrupt", codec); - if (ret < 0) { - dev_err(codec->dev, "request_irq failed: %d\n", - ret); - } - /* * Clear any old interrupts. * An old interrupt ocurring prior to installing the ISR @@ -2417,6 +2410,7 @@ static int max98090_remove(struct snd_soc_codec *codec) cancel_delayed_work_sync(&max98090->pll_det_enable_work); cancel_work_sync(&max98090->pll_det_disable_work); cancel_work_sync(&max98090->pll_work); + max98090->codec = NULL; return 0; } @@ -2478,6 +2472,15 @@ static int max98090_i2c_probe(struct i2c_client *i2c, goto err_enable; } + ret = devm_request_threaded_irq(&i2c->dev, max98090->irq, NULL, + max98090_interrupt, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + "max98090_interrupt", max98090); + if (ret < 0) { + dev_err(&i2c->dev, "request_irq failed: %d\n", + ret); + return ret; + } + ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_max98090, max98090_dai, ARRAY_SIZE(max98090_dai)); From ced1933db67087554abf22bcb285eb6873380b10 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Fri, 19 Sep 2014 14:48:18 +0300 Subject: [PATCH 183/251] ASoC: max98090: Remove structure member irq from private data struct max98090_priv member irq is now used only locally in max98090_i2c_probe() and can be removed. Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/codecs/max98090.c | 3 +-- sound/soc/codecs/max98090.h | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index fe77df6a76c2..3e27de1f473b 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c @@ -2463,7 +2463,6 @@ static int max98090_i2c_probe(struct i2c_client *i2c, max98090->devtype = driver_data; i2c_set_clientdata(i2c, max98090); max98090->pdata = i2c->dev.platform_data; - max98090->irq = i2c->irq; max98090->regmap = devm_regmap_init_i2c(i2c, &max98090_regmap); if (IS_ERR(max98090->regmap)) { @@ -2472,7 +2471,7 @@ static int max98090_i2c_probe(struct i2c_client *i2c, goto err_enable; } - ret = devm_request_threaded_irq(&i2c->dev, max98090->irq, NULL, + ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL, max98090_interrupt, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "max98090_interrupt", max98090); if (ret < 0) { diff --git a/sound/soc/codecs/max98090.h b/sound/soc/codecs/max98090.h index 14427a566f41..a16319512182 100644 --- a/sound/soc/codecs/max98090.h +++ b/sound/soc/codecs/max98090.h @@ -1529,7 +1529,6 @@ struct max98090_priv { unsigned int bclk; unsigned int lrclk; struct max98090_cdata dai[1]; - int irq; int jack_state; struct delayed_work jack_work; struct delayed_work pll_det_enable_work; From 3256ff6e5117c493ec20e96aad9f0a20d656d561 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Fri, 19 Sep 2014 14:48:19 +0300 Subject: [PATCH 184/251] ASoC: max98090: Remove structure member extmic_mux from private data There is no other use for extmic_mux than setting it to zero so remove it. Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/codecs/max98090.c | 1 - sound/soc/codecs/max98090.h | 1 - 2 files changed, 2 deletions(-) diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index 3e27de1f473b..f2a3f30a5d9f 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c @@ -2333,7 +2333,6 @@ static int max98090_probe(struct snd_soc_codec *codec) max98090->lin_state = 0; max98090->pa1en = 0; max98090->pa2en = 0; - max98090->extmic_mux = 0; ret = snd_soc_read(codec, M98090_REG_REVISION_ID); if (ret < 0) { diff --git a/sound/soc/codecs/max98090.h b/sound/soc/codecs/max98090.h index a16319512182..84ca3f4f4403 100644 --- a/sound/soc/codecs/max98090.h +++ b/sound/soc/codecs/max98090.h @@ -1541,7 +1541,6 @@ struct max98090_priv { u8 lin_state; unsigned int pa1en; unsigned int pa2en; - unsigned int extmic_mux; unsigned int sidetone; bool master; }; From 0e2cadf39a37f633d3b6d286318506ea3bd0b286 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Fri, 19 Sep 2014 14:48:20 +0300 Subject: [PATCH 185/251] ASoC: max98090: Remove unused version define Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/codecs/max98090.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/sound/soc/codecs/max98090.h b/sound/soc/codecs/max98090.h index 84ca3f4f4403..2613fdbb66d8 100644 --- a/sound/soc/codecs/max98090.h +++ b/sound/soc/codecs/max98090.h @@ -11,11 +11,6 @@ #ifndef _MAX98090_H #define _MAX98090_H -#include - -/* One can override the Linux version here with an explicit version number */ -#define M98090_LINUX_VERSION LINUX_VERSION_CODE - /* * MAX98090 Register Definitions */ From 99632d1077853c2030bec3530011b9d9f423cc89 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Fri, 19 Sep 2014 14:48:21 +0300 Subject: [PATCH 186/251] ASoC: max98090: Remove unused byte access macros Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/codecs/max98090.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/sound/soc/codecs/max98090.h b/sound/soc/codecs/max98090.h index 2613fdbb66d8..a5f6bada06da 100644 --- a/sound/soc/codecs/max98090.h +++ b/sound/soc/codecs/max98090.h @@ -1497,9 +1497,6 @@ #define M98090_REVID_WIDTH 8 #define M98090_REVID_NUM (1<> 8) & 0xff) -#define M98090_BYTE0(w) (w & 0xff) - /* Silicon revision number */ #define M98090_REVA 0x40 #define M98091_REVA 0x50 From f9f6a592cf4f35e7b614f1fb2e8d73969ee39a6d Mon Sep 17 00:00:00 2001 From: Anatol Pomozov Date: Wed, 17 Sep 2014 13:14:20 -0700 Subject: [PATCH 187/251] ASoC: rt5677: Add a configuration option for LDO2_POW pin Some boards have this pin statically tied and do not require any configuration, some other boards allow to enable chip using GPIO. Add an option that tells which GPIO is used to power the audio codec. Signed-off-by: Anatol Pomozov Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/rt5677.txt | 41 ++++++++++++++ sound/soc/codecs/rt5677.c | 54 +++++++++++++++++++ sound/soc/codecs/rt5677.h | 1 + 3 files changed, 96 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/rt5677.txt diff --git a/Documentation/devicetree/bindings/sound/rt5677.txt b/Documentation/devicetree/bindings/sound/rt5677.txt new file mode 100644 index 000000000000..98509fb7481b --- /dev/null +++ b/Documentation/devicetree/bindings/sound/rt5677.txt @@ -0,0 +1,41 @@ +RT5677 audio CODEC + +This device supports I2C only. + +Required properties: + +- compatible : "realtek,rt5677". + +- reg : The I2C address of the device. + +- interrupts : The CODEC's interrupt output. + +Optional properties: + +- realtek,pow-ldo2-gpio : The GPIO that controls the CODEC's POW_LDO2 pin. + +Pins on the device (for linking into audio routes): + + * IN1P + * IN1N + * IN2P + * IN2N + * MICBIAS1 + * DMIC1 + * DMIC2 + * DMIC3 + * DMIC4 + * LOUT1 + * LOUT2 + * LOUT3 + +Example: + +rt5677 { + compatible = "realtek,rt5677"; + reg = <0x2c>; + interrupt-parent = <&gpio>; + interrupts = ; + realtek,pow-ldo2-gpio = + <&gpio TEGRA_GPIO(V, 3) GPIO_ACTIVE_HIGH>; +}; diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 4a0f3dfb2a47..d2c6abf38ad2 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -3381,6 +3382,8 @@ static int rt5677_remove(struct snd_soc_codec *codec) struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); regmap_write(rt5677->regmap, RT5677_RESET, 0x10ec); + if (gpio_is_valid(rt5677->pow_ldo2)) + gpio_set_value_cansleep(rt5677->pow_ldo2, 0); return 0; } @@ -3392,6 +3395,8 @@ static int rt5677_suspend(struct snd_soc_codec *codec) regcache_cache_only(rt5677->regmap, true); regcache_mark_dirty(rt5677->regmap); + if (gpio_is_valid(rt5677->pow_ldo2)) + gpio_set_value_cansleep(rt5677->pow_ldo2, 0); return 0; } @@ -3400,6 +3405,10 @@ static int rt5677_resume(struct snd_soc_codec *codec) { struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); + if (gpio_is_valid(rt5677->pow_ldo2)) { + gpio_set_value_cansleep(rt5677->pow_ldo2, 1); + msleep(10); + } regcache_cache_only(rt5677->regmap, false); regcache_sync(rt5677->regmap); @@ -3558,6 +3567,24 @@ static const struct i2c_device_id rt5677_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, rt5677_i2c_id); +static int rt5677_parse_dt(struct rt5677_priv *rt5677, struct device_node *np) +{ + rt5677->pow_ldo2 = of_get_named_gpio(np, + "realtek,pow-ldo2-gpio", 0); + + /* + * POW_LDO2 is optional (it may be statically tied on the board). + * -ENOENT means that the property doesn't exist, i.e. there is no + * GPIO, so is not an error. Any other error code means the property + * exists, but could not be parsed. + */ + if (!gpio_is_valid(rt5677->pow_ldo2) && + (rt5677->pow_ldo2 != -ENOENT)) + return rt5677->pow_ldo2; + + return 0; +} + static int rt5677_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -3576,6 +3603,33 @@ static int rt5677_i2c_probe(struct i2c_client *i2c, if (pdata) rt5677->pdata = *pdata; + if (i2c->dev.of_node) { + ret = rt5677_parse_dt(rt5677, i2c->dev.of_node); + if (ret) { + dev_err(&i2c->dev, "Failed to parse device tree: %d\n", + ret); + return ret; + } + } else { + rt5677->pow_ldo2 = -EINVAL; + } + + if (gpio_is_valid(rt5677->pow_ldo2)) { + ret = devm_gpio_request_one(&i2c->dev, rt5677->pow_ldo2, + GPIOF_OUT_INIT_HIGH, + "RT5677 POW_LDO2"); + if (ret < 0) { + dev_err(&i2c->dev, "Failed to request POW_LDO2 %d: %d\n", + rt5677->pow_ldo2, ret); + return ret; + } + /* Wait a while until I2C bus becomes available. The datasheet + * does not specify the exact we should wait but startup + * sequence mentiones at least a few milliseconds. + */ + msleep(10); + } + rt5677->regmap = devm_regmap_init_i2c(i2c, &rt5677_regmap); if (IS_ERR(rt5677->regmap)) { ret = PTR_ERR(rt5677->regmap); diff --git a/sound/soc/codecs/rt5677.h b/sound/soc/codecs/rt5677.h index 1fe88727a063..d4eb6d5e6746 100644 --- a/sound/soc/codecs/rt5677.h +++ b/sound/soc/codecs/rt5677.h @@ -1554,6 +1554,7 @@ struct rt5677_priv { int pll_src; int pll_in; int pll_out; + int pow_ldo2; /* POW_LDO2 pin */ #ifdef CONFIG_GPIOLIB struct gpio_chip gpio_chip; #endif From e03f73a01f010b29504ceebda3c4fca25468516d Mon Sep 17 00:00:00 2001 From: Anatol Pomozov Date: Wed, 24 Sep 2014 11:17:14 -0700 Subject: [PATCH 188/251] ASoC: trace: Remove trailing new-lines in trace messages These new-lines add empty lines to trace output Signed-off-by: Anatol Pomozov Signed-off-by: Mark Brown --- include/trace/events/asoc.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/trace/events/asoc.h b/include/trace/events/asoc.h index 0194a641e4e2..b04ee7e5a466 100644 --- a/include/trace/events/asoc.h +++ b/include/trace/events/asoc.h @@ -175,7 +175,7 @@ TRACE_EVENT(snd_soc_dapm_output_path, __entry->path_sink = (long)path->sink; ), - TP_printk("%c%s -> %s -> %s\n", + TP_printk("%c%s -> %s -> %s", (int) __entry->path_sink && (int) __entry->path_connect ? '*' : ' ', __get_str(wname), __get_str(pname), __get_str(psname)) @@ -204,7 +204,7 @@ TRACE_EVENT(snd_soc_dapm_input_path, __entry->path_source = (long)path->source; ), - TP_printk("%c%s <- %s <- %s\n", + TP_printk("%c%s <- %s <- %s", (int) __entry->path_source && (int) __entry->path_connect ? '*' : ' ', __get_str(wname), __get_str(pname), __get_str(psname)) @@ -226,7 +226,7 @@ TRACE_EVENT(snd_soc_dapm_connected, __entry->stream = stream; ), - TP_printk("%s: found %d paths\n", + TP_printk("%s: found %d paths", __entry->stream ? "capture" : "playback", __entry->paths) ); From 0e612ff10c86241683f0a77e3dd0a6631b640009 Mon Sep 17 00:00:00 2001 From: Anatol Pomozov Date: Wed, 24 Sep 2014 11:31:58 -0700 Subject: [PATCH 189/251] ASoC: rt5677: Add gpio-controller DTS documentation Signed-off-by: Anatol Pomozov Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/rt5677.txt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/rt5677.txt b/Documentation/devicetree/bindings/sound/rt5677.txt index 98509fb7481b..bd28df604b7b 100644 --- a/Documentation/devicetree/bindings/sound/rt5677.txt +++ b/Documentation/devicetree/bindings/sound/rt5677.txt @@ -10,6 +10,11 @@ Required properties: - interrupts : The CODEC's interrupt output. +- gpio-controller : Indicates this device is a GPIO controller. + +- #gpio-cells : Should be two. The first cell is the pin number and the + second cell is used to specify optional parameters (currently unused). + Optional properties: - realtek,pow-ldo2-gpio : The GPIO that controls the CODEC's POW_LDO2 pin. @@ -36,6 +41,10 @@ rt5677 { reg = <0x2c>; interrupt-parent = <&gpio>; interrupts = ; + + gpio-controller; + #gpio-cells = <2>; + realtek,pow-ldo2-gpio = <&gpio TEGRA_GPIO(V, 3) GPIO_ACTIVE_HIGH>; }; From 0121327c1a68bc8c80f240c2794e682722b69051 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 19 Sep 2014 16:46:03 +0530 Subject: [PATCH 190/251] ASoC: Intel: mfld-pcm: add control for powering up/down dsp When we have PCM (FE/BE) opened or DAPM widgets triggered we need power up/down DSP accordingly. The DSP will do ref count of these requests i.e. link these runtime_get/put calls of DSP Also fix some preexisting spacing error. Signed-off-by: Vinod Koul Signed-off-by: Subhransu S. Prusty Signed-off-by: Mark Brown --- sound/soc/intel/sst-mfld-platform-pcm.c | 16 ++++++++++++++++ sound/soc/intel/sst-mfld-platform.h | 17 +++++++++-------- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/sound/soc/intel/sst-mfld-platform-pcm.c b/sound/soc/intel/sst-mfld-platform-pcm.c index 8e1b2c14291c..aa9b600dfc9b 100644 --- a/sound/soc/intel/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/sst-mfld-platform-pcm.c @@ -322,6 +322,16 @@ static int sst_platform_init_stream(struct snd_pcm_substream *substream) } +static int power_up_sst(struct sst_runtime_stream *stream) +{ + return stream->ops->power(sst->dev, true); +} + +static void power_down_sst(struct sst_runtime_stream *stream) +{ + stream->ops->power(sst->dev, false); +} + static int sst_media_open(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -351,6 +361,10 @@ static int sst_media_open(struct snd_pcm_substream *substream, /* allocate memory for SST API set */ runtime->private_data = stream; + ret_val = power_up_sst(stream); + if (ret_val < 0) + return ret_val; + /* Make sure, that the period size is always even */ snd_pcm_hw_constraint_step(substream->runtime, 0, SNDRV_PCM_HW_PARAM_PERIODS, 2); @@ -370,6 +384,8 @@ static void sst_media_close(struct snd_pcm_substream *substream, int ret_val = 0, str_id; stream = substream->runtime->private_data; + power_down_sst(stream); + str_id = stream->stream_info.str_id; if (str_id) ret_val = stream->ops->close(sst->dev, str_id); diff --git a/sound/soc/intel/sst-mfld-platform.h b/sound/soc/intel/sst-mfld-platform.h index 7092ee3e96a3..19f83ec51613 100644 --- a/sound/soc/intel/sst-mfld-platform.h +++ b/sound/soc/intel/sst-mfld-platform.h @@ -120,15 +120,16 @@ struct compress_sst_ops { }; struct sst_ops { - int (*open) (struct device *dev, struct snd_sst_params *str_param); - int (*stream_init) (struct device *dev, struct pcm_stream_info *str_info); - int (*stream_start) (struct device *dev, int str_id); - int (*stream_drop) (struct device *dev, int str_id); - int (*stream_pause) (struct device *dev, int str_id); - int (*stream_pause_release) (struct device *dev, int str_id); - int (*stream_read_tstamp) (struct device *dev, struct pcm_stream_info *str_info); + int (*open)(struct device *dev, struct snd_sst_params *str_param); + int (*stream_init)(struct device *dev, struct pcm_stream_info *str_info); + int (*stream_start)(struct device *dev, int str_id); + int (*stream_drop)(struct device *dev, int str_id); + int (*stream_pause)(struct device *dev, int str_id); + int (*stream_pause_release)(struct device *dev, int str_id); + int (*stream_read_tstamp)(struct device *dev, struct pcm_stream_info *str_info); int (*send_byte_stream)(struct device *dev, struct snd_sst_bytes_v2 *bytes); - int (*close) (struct device *dev, unsigned int str_id); + int (*close)(struct device *dev, unsigned int str_id); + int (*power)(struct device *dev, bool state); }; struct sst_runtime_stream { From 83a7fc98dc9c29c5d2d66c80fb50725303a78192 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 25 Sep 2014 16:19:30 +0200 Subject: [PATCH 191/251] ASoC: wm8741: Remove unused wm8741_suspend define This driver has no suspend callback. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/wm8741.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/codecs/wm8741.c b/sound/soc/codecs/wm8741.c index a237f1627f61..31bb4801a005 100644 --- a/sound/soc/codecs/wm8741.c +++ b/sound/soc/codecs/wm8741.c @@ -413,7 +413,6 @@ static int wm8741_resume(struct snd_soc_codec *codec) return 0; } #else -#define wm8741_suspend NULL #define wm8741_resume NULL #endif From 1ee44ce03011bab025949e7636416912185f4122 Mon Sep 17 00:00:00 2001 From: Anatol Pomozov Date: Fri, 26 Sep 2014 13:31:06 -0700 Subject: [PATCH 192/251] ASoC: ssm4567: Add driver for Analog Devices SSM4567 amplifier Analog Devices SSM4567 is a boost class-D audio amplifier. Signed-off-by: Anatol Pomozov Acked-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/ssm4567.txt | 15 + sound/soc/codecs/Kconfig | 5 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/ssm4567.c | 345 ++++++++++++++++++ 4 files changed, 367 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/ssm4567.txt create mode 100644 sound/soc/codecs/ssm4567.c diff --git a/Documentation/devicetree/bindings/sound/ssm4567.txt b/Documentation/devicetree/bindings/sound/ssm4567.txt new file mode 100644 index 000000000000..ec3d9e7004b5 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/ssm4567.txt @@ -0,0 +1,15 @@ +Analog Devices SSM4567 audio amplifier + +This device supports I2C only. + +Required properties: + - compatible : Must be "adi,ssm4567" + - reg : the I2C address of the device. This will either be 0x34 (LR_SEL/ADDR connected to AGND), + 0x35 (LR_SEL/ADDR connected to IOVDD) or 0x36 (LR_SEL/ADDR open). + +Example: + + ssm4567: ssm4567@34 { + compatible = "adi,ssm4567"; + reg = <0x34>; + }; diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 8838838e25ed..bc1fe4e9f8ea 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -90,6 +90,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_SSM2518 if I2C select SND_SOC_SSM2602_SPI if SPI_MASTER select SND_SOC_SSM2602_I2C if I2C + select SND_SOC_SSM4567 if I2C select SND_SOC_STA32X if I2C select SND_SOC_STA350 if I2C select SND_SOC_STA529 if I2C @@ -527,6 +528,10 @@ config SND_SOC_SSM2602_I2C select SND_SOC_SSM2602 tristate +config SND_SOC_SSM4567 + tristate "Analog Devices ssm4567 amplifier driver support" + depends on I2C + config SND_SOC_STA32X tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 20afe0f0c5be..bebad36fa719 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -91,6 +91,7 @@ snd-soc-ssm2518-objs := ssm2518.o snd-soc-ssm2602-objs := ssm2602.o snd-soc-ssm2602-spi-objs := ssm2602-spi.o snd-soc-ssm2602-i2c-objs := ssm2602-i2c.o +snd-soc-ssm4567-objs := ssm4567.o snd-soc-sta32x-objs := sta32x.o snd-soc-sta350-objs := sta350.o snd-soc-sta529-objs := sta529.o @@ -258,6 +259,7 @@ obj-$(CONFIG_SND_SOC_SSM2518) += snd-soc-ssm2518.o obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o obj-$(CONFIG_SND_SOC_SSM2602_SPI) += snd-soc-ssm2602-spi.o obj-$(CONFIG_SND_SOC_SSM2602_I2C) += snd-soc-ssm2602-i2c.o +obj-$(CONFIG_SND_SOC_SSM4567) += snd-soc-ssm4567.o obj-$(CONFIG_SND_SOC_STA32X) += snd-soc-sta32x.o obj-$(CONFIG_SND_SOC_STA350) += snd-soc-sta350.o obj-$(CONFIG_SND_SOC_STA529) += snd-soc-sta529.o diff --git a/sound/soc/codecs/ssm4567.c b/sound/soc/codecs/ssm4567.c new file mode 100644 index 000000000000..1dadacb94efc --- /dev/null +++ b/sound/soc/codecs/ssm4567.c @@ -0,0 +1,345 @@ +/* + * SSM4567 amplifier audio driver + * + * Copyright 2014 Google Chromium project. + * Author: Anatol Pomozov + * + * Based on code copyright/by: + * Copyright 2013 Analog Devices Inc. + * + * Licensed under the GPL-2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SSM4567_REG_POWER_CTRL 0x00 +#define SSM4567_REG_AMP_SNS_CTRL 0x01 +#define SSM4567_REG_DAC_CTRL 0x02 +#define SSM4567_REG_DAC_VOLUME 0x03 +#define SSM4567_REG_SAI_CTRL_1 0x04 +#define SSM4567_REG_SAI_CTRL_2 0x05 +#define SSM4567_REG_SAI_PLACEMENT_1 0x06 +#define SSM4567_REG_SAI_PLACEMENT_2 0x07 +#define SSM4567_REG_SAI_PLACEMENT_3 0x08 +#define SSM4567_REG_SAI_PLACEMENT_4 0x09 +#define SSM4567_REG_SAI_PLACEMENT_5 0x0a +#define SSM4567_REG_SAI_PLACEMENT_6 0x0b +#define SSM4567_REG_BATTERY_V_OUT 0x0c +#define SSM4567_REG_LIMITER_CTRL_1 0x0d +#define SSM4567_REG_LIMITER_CTRL_2 0x0e +#define SSM4567_REG_LIMITER_CTRL_3 0x0f +#define SSM4567_REG_STATUS_1 0x10 +#define SSM4567_REG_STATUS_2 0x11 +#define SSM4567_REG_FAULT_CTRL 0x12 +#define SSM4567_REG_PDM_CTRL 0x13 +#define SSM4567_REG_MCLK_RATIO 0x14 +#define SSM4567_REG_BOOST_CTRL_1 0x15 +#define SSM4567_REG_BOOST_CTRL_2 0x16 +#define SSM4567_REG_SOFT_RESET 0xff + +/* POWER_CTRL */ +#define SSM4567_POWER_APWDN_EN BIT(7) +#define SSM4567_POWER_BSNS_PWDN BIT(6) +#define SSM4567_POWER_VSNS_PWDN BIT(5) +#define SSM4567_POWER_ISNS_PWDN BIT(4) +#define SSM4567_POWER_BOOST_PWDN BIT(3) +#define SSM4567_POWER_AMP_PWDN BIT(2) +#define SSM4567_POWER_VBAT_ONLY BIT(1) +#define SSM4567_POWER_SPWDN BIT(0) + +/* DAC_CTRL */ +#define SSM4567_DAC_HV BIT(7) +#define SSM4567_DAC_MUTE BIT(6) +#define SSM4567_DAC_HPF BIT(5) +#define SSM4567_DAC_LPM BIT(4) +#define SSM4567_DAC_FS_MASK 0x7 +#define SSM4567_DAC_FS_8000_12000 0x0 +#define SSM4567_DAC_FS_16000_24000 0x1 +#define SSM4567_DAC_FS_32000_48000 0x2 +#define SSM4567_DAC_FS_64000_96000 0x3 +#define SSM4567_DAC_FS_128000_192000 0x4 + +struct ssm4567 { + struct regmap *regmap; +}; + +static const struct reg_default ssm4567_reg_defaults[] = { + { SSM4567_REG_POWER_CTRL, 0x81 }, + { SSM4567_REG_AMP_SNS_CTRL, 0x09 }, + { SSM4567_REG_DAC_CTRL, 0x32 }, + { SSM4567_REG_DAC_VOLUME, 0x40 }, + { SSM4567_REG_SAI_CTRL_1, 0x00 }, + { SSM4567_REG_SAI_CTRL_2, 0x08 }, + { SSM4567_REG_SAI_PLACEMENT_1, 0x01 }, + { SSM4567_REG_SAI_PLACEMENT_2, 0x20 }, + { SSM4567_REG_SAI_PLACEMENT_3, 0x32 }, + { SSM4567_REG_SAI_PLACEMENT_4, 0x07 }, + { SSM4567_REG_SAI_PLACEMENT_5, 0x07 }, + { SSM4567_REG_SAI_PLACEMENT_6, 0x07 }, + { SSM4567_REG_BATTERY_V_OUT, 0x00 }, + { SSM4567_REG_LIMITER_CTRL_1, 0xa4 }, + { SSM4567_REG_LIMITER_CTRL_2, 0x73 }, + { SSM4567_REG_LIMITER_CTRL_3, 0x00 }, + { SSM4567_REG_STATUS_1, 0x00 }, + { SSM4567_REG_STATUS_2, 0x00 }, + { SSM4567_REG_FAULT_CTRL, 0x30 }, + { SSM4567_REG_PDM_CTRL, 0x40 }, + { SSM4567_REG_MCLK_RATIO, 0x11 }, + { SSM4567_REG_BOOST_CTRL_1, 0x03 }, + { SSM4567_REG_BOOST_CTRL_2, 0x00 }, + { SSM4567_REG_SOFT_RESET, 0x00 }, +}; + + +static bool ssm4567_readable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case SSM4567_REG_POWER_CTRL ... SSM4567_REG_BOOST_CTRL_2: + return true; + default: + return false; + } + +} + +static bool ssm4567_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case SSM4567_REG_POWER_CTRL ... SSM4567_REG_SAI_PLACEMENT_6: + case SSM4567_REG_LIMITER_CTRL_1 ... SSM4567_REG_LIMITER_CTRL_3: + case SSM4567_REG_FAULT_CTRL ... SSM4567_REG_BOOST_CTRL_2: + /* The datasheet states that soft reset register is read-only, + * but logically it is write-only. */ + case SSM4567_REG_SOFT_RESET: + return true; + default: + return false; + } +} + +static bool ssm4567_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case SSM4567_REG_BATTERY_V_OUT: + case SSM4567_REG_STATUS_1 ... SSM4567_REG_STATUS_2: + case SSM4567_REG_SOFT_RESET: + return true; + default: + return false; + } +} + +static const DECLARE_TLV_DB_MINMAX_MUTE(ssm4567_vol_tlv, -7125, 2400); + +static const struct snd_kcontrol_new ssm4567_snd_controls[] = { + SOC_SINGLE_TLV("Master Playback Volume", SSM4567_REG_DAC_VOLUME, 0, + 0xff, 1, ssm4567_vol_tlv), + SOC_SINGLE("DAC Low Power Mode Switch", SSM4567_REG_DAC_CTRL, 4, 1, 0), +}; + +static const struct snd_soc_dapm_widget ssm4567_dapm_widgets[] = { + SND_SOC_DAPM_DAC("DAC", "HiFi Playback", SSM4567_REG_POWER_CTRL, 2, 1), + + SND_SOC_DAPM_OUTPUT("OUT"), +}; + +static const struct snd_soc_dapm_route ssm4567_routes[] = { + { "OUT", NULL, "DAC" }, +}; + +static int ssm4567_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 ssm4567 *ssm4567 = snd_soc_codec_get_drvdata(codec); + unsigned int rate = params_rate(params); + unsigned int dacfs; + + if (rate >= 8000 && rate <= 12000) + dacfs = SSM4567_DAC_FS_8000_12000; + else if (rate >= 16000 && rate <= 24000) + dacfs = SSM4567_DAC_FS_16000_24000; + else if (rate >= 32000 && rate <= 48000) + dacfs = SSM4567_DAC_FS_32000_48000; + else if (rate >= 64000 && rate <= 96000) + dacfs = SSM4567_DAC_FS_64000_96000; + else if (rate >= 64000 && rate <= 96000) + dacfs = SSM4567_DAC_FS_64000_96000; + else if (rate >= 128000 && rate <= 192000) + dacfs = SSM4567_DAC_FS_128000_192000; + else + return -EINVAL; + + return regmap_update_bits(ssm4567->regmap, SSM4567_REG_DAC_CTRL, + SSM4567_DAC_FS_MASK, dacfs); +} + +static int ssm4567_mute(struct snd_soc_dai *dai, int mute) +{ + struct ssm4567 *ssm4567 = snd_soc_codec_get_drvdata(dai->codec); + unsigned int val; + + val = mute ? SSM4567_DAC_MUTE : 0; + return regmap_update_bits(ssm4567->regmap, SSM4567_REG_DAC_CTRL, + SSM4567_DAC_MUTE, val); +} + +static int ssm4567_set_power(struct ssm4567 *ssm4567, bool enable) +{ + int ret = 0; + + if (!enable) { + ret = regmap_update_bits(ssm4567->regmap, + SSM4567_REG_POWER_CTRL, + SSM4567_POWER_SPWDN, SSM4567_POWER_SPWDN); + regcache_mark_dirty(ssm4567->regmap); + } + + regcache_cache_only(ssm4567->regmap, !enable); + + if (enable) { + ret = regmap_update_bits(ssm4567->regmap, + SSM4567_REG_POWER_CTRL, + SSM4567_POWER_SPWDN, 0x00); + regcache_sync(ssm4567->regmap); + } + + return ret; +} + +static int ssm4567_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + struct ssm4567 *ssm4567 = snd_soc_codec_get_drvdata(codec); + int ret = 0; + + switch (level) { + case SND_SOC_BIAS_ON: + break; + case SND_SOC_BIAS_PREPARE: + break; + case SND_SOC_BIAS_STANDBY: + if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) + ret = ssm4567_set_power(ssm4567, true); + break; + case SND_SOC_BIAS_OFF: + ret = ssm4567_set_power(ssm4567, false); + break; + } + + if (ret) + return ret; + + codec->dapm.bias_level = level; + + return 0; +} + +static const struct snd_soc_dai_ops ssm4567_dai_ops = { + .hw_params = ssm4567_hw_params, + .digital_mute = ssm4567_mute, +}; + +static struct snd_soc_dai_driver ssm4567_dai = { + .name = "ssm4567-hifi", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 1, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32, + }, + .ops = &ssm4567_dai_ops, +}; + +static struct snd_soc_codec_driver ssm4567_codec_driver = { + .set_bias_level = ssm4567_set_bias_level, + .idle_bias_off = true, + + .controls = ssm4567_snd_controls, + .num_controls = ARRAY_SIZE(ssm4567_snd_controls), + .dapm_widgets = ssm4567_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(ssm4567_dapm_widgets), + .dapm_routes = ssm4567_routes, + .num_dapm_routes = ARRAY_SIZE(ssm4567_routes), +}; + +static const struct regmap_config ssm4567_regmap_config = { + .val_bits = 8, + .reg_bits = 8, + + .max_register = SSM4567_REG_SOFT_RESET, + .readable_reg = ssm4567_readable_reg, + .writeable_reg = ssm4567_writeable_reg, + .volatile_reg = ssm4567_volatile_reg, + + .cache_type = REGCACHE_RBTREE, + .reg_defaults = ssm4567_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(ssm4567_reg_defaults), +}; + +static int ssm4567_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct ssm4567 *ssm4567; + int ret; + + ssm4567 = devm_kzalloc(&i2c->dev, sizeof(*ssm4567), GFP_KERNEL); + if (ssm4567 == NULL) + return -ENOMEM; + + i2c_set_clientdata(i2c, ssm4567); + + ssm4567->regmap = devm_regmap_init_i2c(i2c, &ssm4567_regmap_config); + if (IS_ERR(ssm4567->regmap)) + return PTR_ERR(ssm4567->regmap); + + ret = regmap_write(ssm4567->regmap, SSM4567_REG_SOFT_RESET, 0x00); + if (ret) + return ret; + + ret = ssm4567_set_power(ssm4567, false); + if (ret) + return ret; + + return snd_soc_register_codec(&i2c->dev, &ssm4567_codec_driver, + &ssm4567_dai, 1); +} + +static int ssm4567_i2c_remove(struct i2c_client *client) +{ + snd_soc_unregister_codec(&client->dev); + return 0; +} + +static const struct i2c_device_id ssm4567_i2c_ids[] = { + { "ssm4567", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ssm4567_i2c_ids); + +static struct i2c_driver ssm4567_driver = { + .driver = { + .name = "ssm4567", + .owner = THIS_MODULE, + }, + .probe = ssm4567_i2c_probe, + .remove = ssm4567_i2c_remove, + .id_table = ssm4567_i2c_ids, +}; +module_i2c_driver(ssm4567_driver); + +MODULE_DESCRIPTION("ASoC SSM4567 driver"); +MODULE_AUTHOR("Anatol Pomozov "); +MODULE_LICENSE("GPL"); From f69e3caa9e1855737bf1e99e1fe4488e33d74bfe Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Fri, 26 Sep 2014 16:25:37 +0300 Subject: [PATCH 193/251] ASoC: max98090: Enable both DMIC channels also when using mono configuration According to MAX98090 specification "Digital microphone clock (DMC) is enabled once both data channels are enabled.". Therefore both digital microphone data channels must be enabled also when using mono microphone configuration. Fix this by moving "DMICL_ENA" and "DMICR_ENA" supply widgets from "DMICL" and "DMICR" inputs to "DMIC Mux" in order to enable both data channels whenever there is active mono or stereo digital microphone input path. Use of "DMICL" and "DMICR" inputs are retained for informative source and in case the driver would find use for exact digital microphone configuration in the future. Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/codecs/max98090.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index f1543653a699..7e111865946a 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c @@ -1311,8 +1311,6 @@ static const struct snd_soc_dapm_route max98090_dapm_routes[] = { {"MIC1 Input", NULL, "MIC1"}, {"MIC2 Input", NULL, "MIC2"}, - {"DMICL", NULL, "DMICL_ENA"}, - {"DMICR", NULL, "DMICR_ENA"}, {"DMICL", NULL, "AHPF"}, {"DMICR", NULL, "AHPF"}, @@ -1370,6 +1368,8 @@ static const struct snd_soc_dapm_route max98090_dapm_routes[] = { {"DMIC Mux", "ADC", "ADCR"}, {"DMIC Mux", "DMIC", "DMICL"}, {"DMIC Mux", "DMIC", "DMICR"}, + {"DMIC Mux", "DMIC", "DMICL_ENA"}, + {"DMIC Mux", "DMIC", "DMICR_ENA"}, {"LBENL Mux", "Normal", "DMIC Mux"}, {"LBENL Mux", "Loopback", "LTENL Mux"}, From 969168e2e9f4a5bfd6a49344f46b820437cd9163 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Fri, 26 Sep 2014 16:25:38 +0300 Subject: [PATCH 194/251] ASoC: Intel: byt-max98090: Set card as fully routed All byt-max98090 audio connections are known and described in DAPM routing table. Set the fully_routed flag in order to disable unused codec pins. Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/intel/byt-max98090.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/intel/byt-max98090.c b/sound/soc/intel/byt-max98090.c index b8b8af571ef1..d52681e7225e 100644 --- a/sound/soc/intel/byt-max98090.c +++ b/sound/soc/intel/byt-max98090.c @@ -139,6 +139,7 @@ static struct snd_soc_card byt_max98090_card = { .num_dapm_routes = ARRAY_SIZE(byt_max98090_audio_map), .controls = byt_max98090_controls, .num_controls = ARRAY_SIZE(byt_max98090_controls), + .fully_routed = true, }; static int byt_max98090_probe(struct platform_device *pdev) From 19926c6de0c37f486f00b7531aec4ba5a09451ae Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 29 Sep 2014 17:32:17 +0200 Subject: [PATCH 195/251] ASoC: davinci: vcif must be a module if SND_DAVINCI_SOC is It is possible to configure a kernel with SND_DAVINCI_SOC=m and SND_DM365_VOICE_CODEC=y, which results in a link error: sound/built-in.o: In function `davinci_vcif_probe': sound/soc/davinci/davinci-vcif.c:223: undefined reference to `davinci_soc_platform_register' The best way to avoid this is to make SND_DM365_VOICE_CODEC a tristate option that depends on SND_DAVINCI_SOC, so it can only be a module or disabled when the base driver is a loadable module Signed-off-by: Arnd Bergmann Signed-off-by: Mark Brown --- sound/soc/davinci/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/davinci/Kconfig b/sound/soc/davinci/Kconfig index d69510c53239..8e948c63f3d9 100644 --- a/sound/soc/davinci/Kconfig +++ b/sound/soc/davinci/Kconfig @@ -63,7 +63,8 @@ config SND_DM365_AIC3X_CODEC Say Y if you want to add support for AIC3101 audio codec config SND_DM365_VOICE_CODEC - bool "Voice Codec - CQ93VC" + tristate "Voice Codec - CQ93VC" + depends on SND_DAVINCI_SOC select MFD_DAVINCI_VOICECODEC select SND_DAVINCI_SOC_VCIF select SND_SOC_CQ0093VC From 9cca023e5c5c13486d48d47a46564c359af9ae73 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 29 Sep 2014 11:40:40 +0200 Subject: [PATCH 196/251] ASoC: wm8{350,753,971}: Use snd_soc_dapm_to_codec() instead of dapm->codec The CODEC struct in the snd_soc_dapm_context struct is deprecated and scheduled for removal. Use the snd_soc_dapm_to_codec() function instead. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8350.c | 2 +- sound/soc/codecs/wm8753.c | 2 +- sound/soc/codecs/wm8971.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index 3dfdcc4197fa..628ec774cf22 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c @@ -212,7 +212,7 @@ static void wm8350_pga_work(struct work_struct *work) { struct snd_soc_dapm_context *dapm = container_of(work, struct snd_soc_dapm_context, delayed_work.work); - struct snd_soc_codec *codec = dapm->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm); struct wm8350_data *wm8350_data = snd_soc_codec_get_drvdata(codec); struct wm8350_output *out1 = &wm8350_data->out1, *out2 = &wm8350_data->out2; diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index e54e097f4fcb..21ca3a94fc96 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c @@ -1433,7 +1433,7 @@ static void wm8753_work(struct work_struct *work) struct snd_soc_dapm_context *dapm = container_of(work, struct snd_soc_dapm_context, delayed_work.work); - struct snd_soc_codec *codec = dapm->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm); wm8753_set_bias_level(codec, dapm->bias_level); } diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c index 0499cd4cfb71..39ddb9b8834c 100644 --- a/sound/soc/codecs/wm8971.c +++ b/sound/soc/codecs/wm8971.c @@ -615,7 +615,7 @@ static void wm8971_work(struct work_struct *work) struct snd_soc_dapm_context *dapm = container_of(work, struct snd_soc_dapm_context, delayed_work.work); - struct snd_soc_codec *codec = dapm->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm); wm8971_set_bias_level(codec, codec->dapm.bias_level); } From a761f87f367a2a172cbc62d0e88eabe175d349a8 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 29 Sep 2014 11:40:41 +0200 Subject: [PATCH 197/251] ASoC: rx51: Use snd_soc_dapm_to_codec() instead of dapm->codec The CODEC struct in the snd_soc_dapm_context struct is deprecated and scheduled for removal. Use the snd_soc_dapm_to_codec() function instead. Signed-off-by: Lars-Peter Clausen Acked-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/omap/rx51.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/omap/rx51.c b/sound/soc/omap/rx51.c index 943922c79f78..b10ae8074461 100644 --- a/sound/soc/omap/rx51.c +++ b/sound/soc/omap/rx51.c @@ -168,7 +168,7 @@ static int rx51_spk_event(struct snd_soc_dapm_widget *w, static int rx51_hp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) { - struct snd_soc_codec *codec = w->dapm->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); if (SND_SOC_DAPM_EVENT_ON(event)) tpa6130a2_stereo_enable(codec, 1); From 0bd2ac3dae74ee25c5ea171cb572731c7a89c248 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 29 Sep 2014 11:40:42 +0200 Subject: [PATCH 198/251] ASoC: Remove CODEC pointer from snd_soc_dapm_context The only remaining user of the CODEC pointer in the DAPM struct is to initialize the CODEC pointer in the widget struct. The later is scheduled for removal, but has still a few users left. For now use dapm->component->codec to initialize it. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- include/sound/soc-dapm.h | 1 - sound/soc/soc-core.c | 1 - sound/soc/soc-dapm.c | 2 +- 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index aac04ff84eea..d60c61b4b341 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -593,7 +593,6 @@ struct snd_soc_dapm_context { struct device *dev; /* from parent - for debug */ struct snd_soc_component *component; /* parent component */ - struct snd_soc_codec *codec; /* parent codec */ struct snd_soc_card *card; /* parent card */ /* used during DAPM updates */ diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 052f59c1917f..8d45eec141a9 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -4351,7 +4351,6 @@ int snd_soc_register_codec(struct device *dev, if (codec_drv->read) codec->component.read = snd_soc_codec_drv_read; codec->component.ignore_pmdown_time = codec_drv->ignore_pmdown_time; - codec->dapm.codec = codec; codec->dapm.idle_bias_off = codec_drv->idle_bias_off; if (codec_drv->seq_notifier) codec->dapm.seq_notifier = codec_drv->seq_notifier; diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 8348352dc2c6..1f1e9657481a 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3107,7 +3107,7 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, } w->dapm = dapm; - w->codec = dapm->codec; + w->codec = dapm->component->codec; INIT_LIST_HEAD(&w->sources); INIT_LIST_HEAD(&w->sinks); INIT_LIST_HEAD(&w->list); From ac06dd8df6e13591524f0e1bedf36af4ca0e967b Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Mon, 29 Sep 2014 16:58:15 +0300 Subject: [PATCH 199/251] ASoC: Intel: byt-rt5640: Remove IN2N pin from DAPM route table I tested couple byt-rt5640 based platforms and they have single-ended headset microphone connection to IN2P only. I guess IN2N was either defined by accident or some early platform had floating ground for headset. It's better to remove IN2N and add a custom route for such a platform if needed. Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/intel/byt-rt5640.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/intel/byt-rt5640.c b/sound/soc/intel/byt-rt5640.c index 234a58de3c53..d6d8b19c22dc 100644 --- a/sound/soc/intel/byt-rt5640.c +++ b/sound/soc/intel/byt-rt5640.c @@ -36,7 +36,6 @@ static const struct snd_soc_dapm_widget byt_rt5640_widgets[] = { static const struct snd_soc_dapm_route byt_rt5640_audio_map[] = { {"Headset Mic", NULL, "MICBIAS1"}, {"IN2P", NULL, "Headset Mic"}, - {"IN2N", NULL, "Headset Mic"}, {"DMIC1", NULL, "Internal Mic"}, {"Headphone", NULL, "HPOL"}, {"Headphone", NULL, "HPOR"}, From f8a770c2c67f28956f8f4601feb99e9bd02a16c8 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Mon, 29 Sep 2014 16:58:16 +0300 Subject: [PATCH 200/251] ASoC: Intel: byt-rt5640: Add quirk for Asus T100 Asus T100 internal microphone is not digital but analogue connected to IN1P pin of the RT564x codec with shared bias between internal and headset microphones. Because of this there is need to have machine specific DAPM routes in byt-rt5640. Add handling for them with the help of DMI quirk that is used to add custom routes in addition to common. Because "Internal Mic" connected to DMIC1 is not common to all move it as a default custom route when there is no match in quirk table. Custom "Internal Mic" -> "IN1P" with MICBIAS1 route is added for Asus T100. Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/intel/byt-rt5640.c | 53 +++++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/byt-rt5640.c b/sound/soc/intel/byt-rt5640.c index d6d8b19c22dc..c323a101214e 100644 --- a/sound/soc/intel/byt-rt5640.c +++ b/sound/soc/intel/byt-rt5640.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -36,7 +37,6 @@ static const struct snd_soc_dapm_widget byt_rt5640_widgets[] = { static const struct snd_soc_dapm_route byt_rt5640_audio_map[] = { {"Headset Mic", NULL, "MICBIAS1"}, {"IN2P", NULL, "Headset Mic"}, - {"DMIC1", NULL, "Internal Mic"}, {"Headphone", NULL, "HPOL"}, {"Headphone", NULL, "HPOR"}, {"Speaker", NULL, "SPOLP"}, @@ -45,6 +45,22 @@ static const struct snd_soc_dapm_route byt_rt5640_audio_map[] = { {"Speaker", NULL, "SPORN"}, }; +static const struct snd_soc_dapm_route byt_rt5640_intmic_dmic1_map[] = { + {"DMIC1", NULL, "Internal Mic"}, +}; + +static const struct snd_soc_dapm_route byt_rt5640_intmic_in1_map[] = { + {"Internal Mic", NULL, "MICBIAS1"}, + {"IN1P", NULL, "Internal Mic"}, +}; + +enum { + BYT_RT5640_DMIC1_MAP, + BYT_RT5640_IN1_MAP, +}; + +static unsigned long byt_rt5640_custom_map = BYT_RT5640_DMIC1_MAP; + static const struct snd_kcontrol_new byt_rt5640_controls[] = { SOC_DAPM_PIN_SWITCH("Headphone"), SOC_DAPM_PIN_SWITCH("Headset Mic"), @@ -76,12 +92,32 @@ static int byt_rt5640_hw_params(struct snd_pcm_substream *substream, return 0; } +static int byt_rt5640_quirk_cb(const struct dmi_system_id *id) +{ + byt_rt5640_custom_map = (unsigned long)id->driver_data; + return 1; +} + +static const struct dmi_system_id byt_rt5640_quirk_table[] = { + { + .callback = byt_rt5640_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "T100TA"), + }, + .driver_data = (unsigned long *)BYT_RT5640_IN1_MAP, + }, + {} +}; + static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) { int ret; struct snd_soc_codec *codec = runtime->codec; struct snd_soc_dapm_context *dapm = &codec->dapm; struct snd_soc_card *card = runtime->card; + const struct snd_soc_dapm_route *custom_map; + int num_routes; card->dapm.idle_bias_off = true; @@ -92,6 +128,21 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) return ret; } + dmi_check_system(byt_rt5640_quirk_table); + switch (byt_rt5640_custom_map) { + case BYT_RT5640_IN1_MAP: + custom_map = byt_rt5640_intmic_in1_map; + num_routes = ARRAY_SIZE(byt_rt5640_intmic_in1_map); + break; + default: + custom_map = byt_rt5640_intmic_dmic1_map; + num_routes = ARRAY_SIZE(byt_rt5640_intmic_dmic1_map); + }; + + ret = snd_soc_dapm_add_routes(dapm, custom_map, num_routes); + if (ret) + return ret; + snd_soc_dapm_ignore_suspend(dapm, "HPOL"); snd_soc_dapm_ignore_suspend(dapm, "HPOR"); From 6f67c380056ceaf5844f18d3a5d769d233247849 Mon Sep 17 00:00:00 2001 From: Anatol Pomozov Date: Fri, 26 Sep 2014 09:57:27 -0700 Subject: [PATCH 201/251] ASoC: rt5677: Add dts properties for input/output differential configuration Signed-off-by: Anatol Pomozov Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/rt5677.txt | 9 ++++++++ include/sound/rt5677.h | 5 +++- sound/soc/codecs/rt5677.c | 23 +++++++++++++++++++ 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/sound/rt5677.txt b/Documentation/devicetree/bindings/sound/rt5677.txt index bd28df604b7b..0701b834fc73 100644 --- a/Documentation/devicetree/bindings/sound/rt5677.txt +++ b/Documentation/devicetree/bindings/sound/rt5677.txt @@ -19,6 +19,14 @@ Optional properties: - realtek,pow-ldo2-gpio : The GPIO that controls the CODEC's POW_LDO2 pin. +- realtek,in1-differential +- realtek,in2-differential +- realtek,lout1-differential +- realtek,lout2-differential +- realtek,lout3-differential + Boolean. Indicate MIC1/2 input and LOUT1/2/3 outputs are differential, + rather than single-ended. + Pins on the device (for linking into audio routes): * IN1P @@ -47,4 +55,5 @@ rt5677 { realtek,pow-ldo2-gpio = <&gpio TEGRA_GPIO(V, 3) GPIO_ACTIVE_HIGH>; + realtek,in1-differential = "true"; }; diff --git a/include/sound/rt5677.h b/include/sound/rt5677.h index a676717f74f4..082670e3a353 100644 --- a/include/sound/rt5677.h +++ b/include/sound/rt5677.h @@ -19,9 +19,12 @@ enum rt5677_dmic2_clk { struct rt5677_platform_data { - /* IN1 IN2 can optionally be differential */ + /* IN1/IN2/LOUT1/LOUT2/LOUT3 can optionally be differential */ bool in1_diff; bool in2_diff; + bool lout1_diff; + bool lout2_diff; + bool lout3_diff; /* DMIC2 clock source selection */ enum rt5677_dmic2_clk dmic2_clk_pin; }; diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index d2c6abf38ad2..97dff7172fb6 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -3569,6 +3569,17 @@ MODULE_DEVICE_TABLE(i2c, rt5677_i2c_id); static int rt5677_parse_dt(struct rt5677_priv *rt5677, struct device_node *np) { + rt5677->pdata.in1_diff = of_property_read_bool(np, + "realtek,in1-differential"); + rt5677->pdata.in2_diff = of_property_read_bool(np, + "realtek,in2-differential"); + rt5677->pdata.lout1_diff = of_property_read_bool(np, + "realtek,lout1-differential"); + rt5677->pdata.lout2_diff = of_property_read_bool(np, + "realtek,lout2-differential"); + rt5677->pdata.lout3_diff = of_property_read_bool(np, + "realtek,lout3-differential"); + rt5677->pow_ldo2 = of_get_named_gpio(np, "realtek,pow-ldo2-gpio", 0); @@ -3660,6 +3671,18 @@ static int rt5677_i2c_probe(struct i2c_client *i2c, regmap_update_bits(rt5677->regmap, RT5677_IN1, RT5677_IN_DF2, RT5677_IN_DF2); + if (rt5677->pdata.lout1_diff) + regmap_update_bits(rt5677->regmap, RT5677_LOUT1, + RT5677_LOUT1_L_DF, RT5677_LOUT1_L_DF); + + if (rt5677->pdata.lout2_diff) + regmap_update_bits(rt5677->regmap, RT5677_LOUT1, + RT5677_LOUT2_L_DF, RT5677_LOUT2_L_DF); + + if (rt5677->pdata.lout3_diff) + regmap_update_bits(rt5677->regmap, RT5677_LOUT1, + RT5677_LOUT3_L_DF, RT5677_LOUT3_L_DF); + if (rt5677->pdata.dmic2_clk_pin == RT5677_DMIC_CLK2) { regmap_update_bits(rt5677->regmap, RT5677_GEN_CTRL2, RT5677_GPIO5_FUNC_MASK, From 66640898edb7b0ef452e179753e8d6130b35fd83 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Mon, 29 Sep 2014 14:33:21 +0530 Subject: [PATCH 202/251] ALSA: ctxfi: changed void * to struct hw * in the code we have void *hw and while using we are always typecasting it to (struct hw *). it is better to use void type of pointer when we store different types of pointer , but in this code we are only having struct hw. So changed all the relevant reference of void *hw to struct hw *hw, without any modification of the existing code logic. the next patch of the series will remove the typecasting which is not required now. Signed-off-by: Sudip Mukherjee Signed-off-by: Takashi Iwai --- sound/pci/ctxfi/ctamixer.c | 4 ++-- sound/pci/ctxfi/ctamixer.h | 4 ++-- sound/pci/ctxfi/ctatc.c | 4 ++-- sound/pci/ctxfi/ctatc.h | 2 +- sound/pci/ctxfi/ctdaio.c | 4 ++-- sound/pci/ctxfi/ctdaio.h | 6 +++--- sound/pci/ctxfi/ctresource.c | 5 +++-- sound/pci/ctxfi/ctresource.h | 9 +++++---- sound/pci/ctxfi/ctsrc.c | 4 ++-- sound/pci/ctxfi/ctsrc.h | 4 ++-- 10 files changed, 24 insertions(+), 22 deletions(-) diff --git a/sound/pci/ctxfi/ctamixer.c b/sound/pci/ctxfi/ctamixer.c index fed6e6a57608..4671cbe7b397 100644 --- a/sound/pci/ctxfi/ctamixer.c +++ b/sound/pci/ctxfi/ctamixer.c @@ -296,7 +296,7 @@ static int put_amixer_rsc(struct amixer_mgr *mgr, struct amixer *amixer) return 0; } -int amixer_mgr_create(void *hw, struct amixer_mgr **ramixer_mgr) +int amixer_mgr_create(struct hw *hw, struct amixer_mgr **ramixer_mgr) { int err; struct amixer_mgr *amixer_mgr; @@ -449,7 +449,7 @@ static int put_sum_rsc(struct sum_mgr *mgr, struct sum *sum) return 0; } -int sum_mgr_create(void *hw, struct sum_mgr **rsum_mgr) +int sum_mgr_create(struct hw *hw, struct sum_mgr **rsum_mgr) { int err; struct sum_mgr *sum_mgr; diff --git a/sound/pci/ctxfi/ctamixer.h b/sound/pci/ctxfi/ctamixer.h index cc49e5ab4750..6fa5eff7b89d 100644 --- a/sound/pci/ctxfi/ctamixer.h +++ b/sound/pci/ctxfi/ctamixer.h @@ -45,7 +45,7 @@ struct sum_mgr { }; /* Constructor and destructor of daio resource manager */ -int sum_mgr_create(void *hw, struct sum_mgr **rsum_mgr); +int sum_mgr_create(struct hw *hw, struct sum_mgr **rsum_mgr); int sum_mgr_destroy(struct sum_mgr *sum_mgr); /* Define the descriptor of a amixer resource */ @@ -90,7 +90,7 @@ struct amixer_mgr { }; /* Constructor and destructor of amixer resource manager */ -int amixer_mgr_create(void *hw, struct amixer_mgr **ramixer_mgr); +int amixer_mgr_create(struct hw *hw, struct amixer_mgr **ramixer_mgr); int amixer_mgr_destroy(struct amixer_mgr *amixer_mgr); #endif /* CTAMIXER_H */ diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c index d92a08c7a39c..04e54ccf5120 100644 --- a/sound/pci/ctxfi/ctatc.c +++ b/sound/pci/ctxfi/ctatc.c @@ -106,11 +106,11 @@ static struct { .public_name = "Mixer"} }; -typedef int (*create_t)(void *, void **); +typedef int (*create_t)(struct hw *, void **); typedef int (*destroy_t)(void *); static struct { - int (*create)(void *hw, void **rmgr); + int (*create)(struct hw *hw, void **rmgr); int (*destroy)(void *mgr); } rsc_mgr_funcs[NUM_RSCTYP] = { [SRC] = { .create = (create_t)src_mgr_create, diff --git a/sound/pci/ctxfi/ctatc.h b/sound/pci/ctxfi/ctatc.h index 5f11ca22fcde..56413343a9e8 100644 --- a/sound/pci/ctxfi/ctatc.h +++ b/sound/pci/ctxfi/ctatc.h @@ -131,7 +131,7 @@ struct ct_atc { /* Don't touch! Used for internal object. */ void *rsc_mgrs[NUM_RSCTYP]; /* chip resource managers */ void *mixer; /* internal mixer object */ - void *hw; /* chip specific hardware access object */ + struct hw *hw; /* chip specific hardware access object */ void **daios; /* digital audio io resources */ void **pcm; /* SUMs for collecting all pcm stream */ void **srcs; /* Sample Rate Converters for input signal */ diff --git a/sound/pci/ctxfi/ctdaio.c b/sound/pci/ctxfi/ctdaio.c index 6f0654ea3630..75416410fb0b 100644 --- a/sound/pci/ctxfi/ctdaio.c +++ b/sound/pci/ctxfi/ctdaio.c @@ -331,7 +331,7 @@ static struct dai_rsc_ops dai_ops = { static int daio_rsc_init(struct daio *daio, const struct daio_desc *desc, - void *hw) + struct hw *hw) { int err; unsigned int idx_l, idx_r; @@ -692,7 +692,7 @@ static int daio_mgr_commit_write(struct daio_mgr *mgr) return 0; } -int daio_mgr_create(void *hw, struct daio_mgr **rdaio_mgr) +int daio_mgr_create(struct hw *hw, struct daio_mgr **rdaio_mgr) { int err, i; struct daio_mgr *daio_mgr; diff --git a/sound/pci/ctxfi/ctdaio.h b/sound/pci/ctxfi/ctdaio.h index 85ccb6ee1ab4..e4817de08864 100644 --- a/sound/pci/ctxfi/ctdaio.h +++ b/sound/pci/ctxfi/ctdaio.h @@ -53,14 +53,14 @@ struct dao { struct dao_rsc_ops *ops; /* DAO specific operations */ struct imapper **imappers; struct daio_mgr *mgr; - void *hw; + struct hw *hw; void *ctrl_blk; }; struct dai { struct daio daio; struct dai_rsc_ops *ops; /* DAI specific operations */ - void *hw; + struct hw *hw; void *ctrl_blk; }; @@ -117,7 +117,7 @@ struct daio_mgr { }; /* Constructor and destructor of daio resource manager */ -int daio_mgr_create(void *hw, struct daio_mgr **rdaio_mgr); +int daio_mgr_create(struct hw *hw, struct daio_mgr **rdaio_mgr); int daio_mgr_destroy(struct daio_mgr *daio_mgr); #endif /* CTDAIO_H */ diff --git a/sound/pci/ctxfi/ctresource.c b/sound/pci/ctxfi/ctresource.c index e49d2be1bfd4..f14cbea433b2 100644 --- a/sound/pci/ctxfi/ctresource.c +++ b/sound/pci/ctxfi/ctresource.c @@ -134,7 +134,8 @@ static struct rsc_ops rsc_generic_ops = { .next_conj = rsc_next_conj, }; -int rsc_init(struct rsc *rsc, u32 idx, enum RSCTYP type, u32 msr, void *hw) +int +rsc_init(struct rsc *rsc, u32 idx, enum RSCTYP type, u32 msr, struct hw *hw) { int err = 0; @@ -206,7 +207,7 @@ int rsc_uninit(struct rsc *rsc) } int rsc_mgr_init(struct rsc_mgr *mgr, enum RSCTYP type, - unsigned int amount, void *hw_obj) + unsigned int amount, struct hw *hw_obj) { int err = 0; struct hw *hw = hw_obj; diff --git a/sound/pci/ctxfi/ctresource.h b/sound/pci/ctxfi/ctresource.h index 0838c2e84f8b..9b746c3719e6 100644 --- a/sound/pci/ctxfi/ctresource.h +++ b/sound/pci/ctxfi/ctresource.h @@ -38,7 +38,7 @@ struct rsc { u32 conj:12; /* Current conjugate index */ u32 msr:4; /* The Master Sample Rate a resource working on */ void *ctrl_blk; /* Chip specific control info block for a resource */ - void *hw; /* Chip specific object for hardware access means */ + struct hw *hw; /* Chip specific object for hardware access means */ struct rsc_ops *ops; /* Generic resource operations */ }; @@ -50,7 +50,8 @@ struct rsc_ops { int (*output_slot)(const struct rsc *rsc); }; -int rsc_init(struct rsc *rsc, u32 idx, enum RSCTYP type, u32 msr, void *hw); +int +rsc_init(struct rsc *rsc, u32 idx, enum RSCTYP type, u32 msr, struct hw *hw); int rsc_uninit(struct rsc *rsc); struct rsc_mgr { @@ -59,12 +60,12 @@ struct rsc_mgr { unsigned int avail; /* The amount of currently available resources */ unsigned char *rscs; /* The bit-map for resource allocation */ void *ctrl_blk; /* Chip specific control info block */ - void *hw; /* Chip specific object for hardware access */ + struct hw *hw; /* Chip specific object for hardware access */ }; /* Resource management is based on bit-map mechanism */ int rsc_mgr_init(struct rsc_mgr *mgr, enum RSCTYP type, - unsigned int amount, void *hw); + unsigned int amount, struct hw *hw); int rsc_mgr_uninit(struct rsc_mgr *mgr); int mgr_get_resource(struct rsc_mgr *mgr, unsigned int n, unsigned int *ridx); int mgr_put_resource(struct rsc_mgr *mgr, unsigned int n, unsigned int idx); diff --git a/sound/pci/ctxfi/ctsrc.c b/sound/pci/ctxfi/ctsrc.c index 19df9b4ed800..342008f81f23 100644 --- a/sound/pci/ctxfi/ctsrc.c +++ b/sound/pci/ctxfi/ctsrc.c @@ -543,7 +543,7 @@ static int src_mgr_commit_write(struct src_mgr *mgr) return 0; } -int src_mgr_create(void *hw, struct src_mgr **rsrc_mgr) +int src_mgr_create(struct hw *hw, struct src_mgr **rsrc_mgr) { int err, i; struct src_mgr *src_mgr; @@ -825,7 +825,7 @@ static int srcimp_imap_delete(struct srcimp_mgr *mgr, struct imapper *entry) return err; } -int srcimp_mgr_create(void *hw, struct srcimp_mgr **rsrcimp_mgr) +int srcimp_mgr_create(struct hw *hw, struct srcimp_mgr **rsrcimp_mgr) { int err; struct srcimp_mgr *srcimp_mgr; diff --git a/sound/pci/ctxfi/ctsrc.h b/sound/pci/ctxfi/ctsrc.h index 259366aabcac..6d95afbbc852 100644 --- a/sound/pci/ctxfi/ctsrc.h +++ b/sound/pci/ctxfi/ctsrc.h @@ -140,10 +140,10 @@ struct srcimp_mgr { }; /* Constructor and destructor of SRC resource manager */ -int src_mgr_create(void *hw, struct src_mgr **rsrc_mgr); +int src_mgr_create(struct hw *hw, struct src_mgr **rsrc_mgr); int src_mgr_destroy(struct src_mgr *src_mgr); /* Constructor and destructor of SRCIMP resource manager */ -int srcimp_mgr_create(void *hw, struct srcimp_mgr **rsrc_mgr); +int srcimp_mgr_create(struct hw *hw, struct srcimp_mgr **rsrc_mgr); int srcimp_mgr_destroy(struct srcimp_mgr *srcimp_mgr); #endif /* CTSRC_H */ From b6bfe86fd22a7e21c50f5b36c894f721614bafa5 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Mon, 29 Sep 2014 14:33:22 +0530 Subject: [PATCH 203/251] ALSA: ctxfi: removed typecast to (struct hw *) the previous patch of the series has converted the void * to struct hw * . Now this patch removes the typecasting to (struct hw *) which is not needed any more. Signed-off-by: Sudip Mukherjee Signed-off-by: Takashi Iwai --- sound/pci/ctxfi/ctatc.c | 2 +- sound/pci/ctxfi/ctresource.c | 26 +++++++++----------------- sound/pci/ctxfi/ctsrc.c | 6 +++--- 3 files changed, 13 insertions(+), 21 deletions(-) diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c index 04e54ccf5120..e536ab97ddeb 100644 --- a/sound/pci/ctxfi/ctatc.c +++ b/sound/pci/ctxfi/ctatc.c @@ -1235,7 +1235,7 @@ static int ct_atc_destroy(struct ct_atc *atc) } if (atc->hw) - destroy_hw_obj((struct hw *)atc->hw); + destroy_hw_obj(atc->hw); /* Destroy device virtual memory manager object */ if (atc->vm) { diff --git a/sound/pci/ctxfi/ctresource.c b/sound/pci/ctxfi/ctresource.c index f14cbea433b2..5aac63fd3bff 100644 --- a/sound/pci/ctxfi/ctresource.c +++ b/sound/pci/ctxfi/ctresource.c @@ -152,11 +152,10 @@ rsc_init(struct rsc *rsc, u32 idx, enum RSCTYP type, u32 msr, struct hw *hw) switch (type) { case SRC: - err = ((struct hw *)hw)->src_rsc_get_ctrl_blk(&rsc->ctrl_blk); + err = hw->src_rsc_get_ctrl_blk(&rsc->ctrl_blk); break; case AMIXER: - err = ((struct hw *)hw)-> - amixer_rsc_get_ctrl_blk(&rsc->ctrl_blk); + err = hw->amixer_rsc_get_ctrl_blk(&rsc->ctrl_blk); break; case SRCIMP: case SUM: @@ -180,12 +179,10 @@ int rsc_uninit(struct rsc *rsc) if ((NULL != rsc->hw) && (NULL != rsc->ctrl_blk)) { switch (rsc->type) { case SRC: - ((struct hw *)rsc->hw)-> - src_rsc_put_ctrl_blk(rsc->ctrl_blk); + rsc->hw->src_rsc_put_ctrl_blk(rsc->ctrl_blk); break; case AMIXER: - ((struct hw *)rsc->hw)-> - amixer_rsc_put_ctrl_blk(rsc->ctrl_blk); + rsc->hw->amixer_rsc_put_ctrl_blk(rsc->ctrl_blk); break; case SUM: case DAIO: @@ -207,10 +204,9 @@ int rsc_uninit(struct rsc *rsc) } int rsc_mgr_init(struct rsc_mgr *mgr, enum RSCTYP type, - unsigned int amount, struct hw *hw_obj) + unsigned int amount, struct hw *hw) { int err = 0; - struct hw *hw = hw_obj; mgr->type = NUM_RSCTYP; @@ -265,20 +261,16 @@ int rsc_mgr_uninit(struct rsc_mgr *mgr) if ((NULL != mgr->hw) && (NULL != mgr->ctrl_blk)) { switch (mgr->type) { case SRC: - ((struct hw *)mgr->hw)-> - src_mgr_put_ctrl_blk(mgr->ctrl_blk); + mgr->hw->src_mgr_put_ctrl_blk(mgr->ctrl_blk); break; case SRCIMP: - ((struct hw *)mgr->hw)-> - srcimp_mgr_put_ctrl_blk(mgr->ctrl_blk); + mgr->hw->srcimp_mgr_put_ctrl_blk(mgr->ctrl_blk); break; case AMIXER: - ((struct hw *)mgr->hw)-> - amixer_mgr_put_ctrl_blk(mgr->ctrl_blk); + mgr->hw->amixer_mgr_put_ctrl_blk(mgr->ctrl_blk); break; case DAIO: - ((struct hw *)mgr->hw)-> - daio_mgr_put_ctrl_blk(mgr->ctrl_blk); + mgr->hw->daio_mgr_put_ctrl_blk(mgr->ctrl_blk); break; case SUM: break; diff --git a/sound/pci/ctxfi/ctsrc.c b/sound/pci/ctxfi/ctsrc.c index 342008f81f23..d3ef213fad77 100644 --- a/sound/pci/ctxfi/ctsrc.c +++ b/sound/pci/ctxfi/ctsrc.c @@ -558,7 +558,7 @@ int src_mgr_create(struct hw *hw, struct src_mgr **rsrc_mgr) goto error1; spin_lock_init(&src_mgr->mgr_lock); - conj_mask = ((struct hw *)hw)->src_dirty_conj_mask(); + conj_mask = hw->src_dirty_conj_mask(); src_mgr->get_src = get_src_rsc; src_mgr->put_src = put_src_rsc; @@ -569,9 +569,9 @@ int src_mgr_create(struct hw *hw, struct src_mgr **rsrc_mgr) /* Disable all SRC resources. */ for (i = 0; i < 256; i++) - ((struct hw *)hw)->src_mgr_dsb_src(src_mgr->mgr.ctrl_blk, i); + hw->src_mgr_dsb_src(src_mgr->mgr.ctrl_blk, i); - ((struct hw *)hw)->src_mgr_commit_write(hw, src_mgr->mgr.ctrl_blk); + hw->src_mgr_commit_write(hw, src_mgr->mgr.ctrl_blk); *rsrc_mgr = src_mgr; From 3d0fdc86e4b500dfcfbf2f68039d2d6853536c2e Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Mon, 29 Sep 2014 14:33:23 +0530 Subject: [PATCH 204/251] ALSA: ctxfi: added reference of snd_card added a pointer of snd_card in some of the structures to get a reference of the card from other functions. these references of snd_card will be initialised in the next patch of this series and as of now these snd_card will be used to print the the device information when we convert the pr_* macros to dev_* in a later patch of this series. Signed-off-by: Sudip Mukherjee Signed-off-by: Takashi Iwai --- sound/pci/ctxfi/ctamixer.h | 3 +++ sound/pci/ctxfi/ctdaio.c | 34 ++++++++++++++++------------------ sound/pci/ctxfi/ctdaio.h | 2 ++ sound/pci/ctxfi/cthardware.h | 2 ++ sound/pci/ctxfi/ctsrc.h | 3 +++ 5 files changed, 26 insertions(+), 18 deletions(-) diff --git a/sound/pci/ctxfi/ctamixer.h b/sound/pci/ctxfi/ctamixer.h index 6fa5eff7b89d..72f42f27434e 100644 --- a/sound/pci/ctxfi/ctamixer.h +++ b/sound/pci/ctxfi/ctamixer.h @@ -21,6 +21,7 @@ #include "ctresource.h" #include +#include /* Define the descriptor of a summation node resource */ struct sum { @@ -35,6 +36,7 @@ struct sum_desc { struct sum_mgr { struct rsc_mgr mgr; /* Basic resource manager info */ + struct snd_card *card; /* pointer to this card */ spinlock_t mgr_lock; /* request one sum resource */ @@ -79,6 +81,7 @@ struct amixer_desc { struct amixer_mgr { struct rsc_mgr mgr; /* Basic resource manager info */ + struct snd_card *card; /* pointer to this card */ spinlock_t mgr_lock; /* request one amixer resource */ diff --git a/sound/pci/ctxfi/ctdaio.c b/sound/pci/ctxfi/ctdaio.c index 75416410fb0b..aa4aa712c285 100644 --- a/sound/pci/ctxfi/ctdaio.c +++ b/sound/pci/ctxfi/ctdaio.c @@ -140,19 +140,19 @@ static int dao_rsc_reinit(struct dao *dao, const struct dao_desc *desc); static int dao_spdif_get_spos(struct dao *dao, unsigned int *spos) { - ((struct hw *)dao->hw)->dao_get_spos(dao->ctrl_blk, spos); + dao->hw->dao_get_spos(dao->ctrl_blk, spos); return 0; } static int dao_spdif_set_spos(struct dao *dao, unsigned int spos) { - ((struct hw *)dao->hw)->dao_set_spos(dao->ctrl_blk, spos); + dao->hw->dao_set_spos(dao->ctrl_blk, spos); return 0; } static int dao_commit_write(struct dao *dao) { - ((struct hw *)dao->hw)->dao_commit_write(dao->hw, + dao->hw->dao_commit_write(dao->hw, daio_device_index(dao->daio.type, dao->hw), dao->ctrl_blk); return 0; } @@ -277,16 +277,14 @@ static struct dao_rsc_ops dao_ops = { static int dai_set_srt_srcl(struct dai *dai, struct rsc *src) { src->ops->master(src); - ((struct hw *)dai->hw)->dai_srt_set_srcm(dai->ctrl_blk, - src->ops->index(src)); + dai->hw->dai_srt_set_srcm(dai->ctrl_blk, src->ops->index(src)); return 0; } static int dai_set_srt_srcr(struct dai *dai, struct rsc *src) { src->ops->master(src); - ((struct hw *)dai->hw)->dai_srt_set_srco(dai->ctrl_blk, - src->ops->index(src)); + dai->hw->dai_srt_set_srco(dai->ctrl_blk, src->ops->index(src)); return 0; } @@ -297,25 +295,25 @@ static int dai_set_srt_msr(struct dai *dai, unsigned int msr) for (rsr = 0; msr > 1; msr >>= 1) rsr++; - ((struct hw *)dai->hw)->dai_srt_set_rsr(dai->ctrl_blk, rsr); + dai->hw->dai_srt_set_rsr(dai->ctrl_blk, rsr); return 0; } static int dai_set_enb_src(struct dai *dai, unsigned int enb) { - ((struct hw *)dai->hw)->dai_srt_set_ec(dai->ctrl_blk, enb); + dai->hw->dai_srt_set_ec(dai->ctrl_blk, enb); return 0; } static int dai_set_enb_srt(struct dai *dai, unsigned int enb) { - ((struct hw *)dai->hw)->dai_srt_set_et(dai->ctrl_blk, enb); + dai->hw->dai_srt_set_et(dai->ctrl_blk, enb); return 0; } static int dai_commit_write(struct dai *dai) { - ((struct hw *)dai->hw)->dai_commit_write(dai->hw, + dai->hw->dai_commit_write(dai->hw, daio_device_index(dai->daio.type, dai->hw), dai->ctrl_blk); return 0; } @@ -336,7 +334,7 @@ static int daio_rsc_init(struct daio *daio, int err; unsigned int idx_l, idx_r; - switch (((struct hw *)hw)->chip_type) { + switch (hw->chip_type) { case ATC20K1: idx_l = idx_20k1[desc->type].left; idx_r = idx_20k1[desc->type].right; @@ -360,7 +358,7 @@ static int daio_rsc_init(struct daio *daio, if (desc->type <= DAIO_OUT_MAX) { daio->rscl.ops = daio->rscr.ops = &daio_out_rsc_ops; } else { - switch (((struct hw *)hw)->chip_type) { + switch (hw->chip_type) { case ATC20K1: daio->rscl.ops = daio->rscr.ops = &daio_in_rsc_ops_20k1; break; @@ -445,7 +443,7 @@ static int dao_rsc_uninit(struct dao *dao) kfree(dao->imappers); dao->imappers = NULL; } - ((struct hw *)dao->hw)->dao_put_ctrl_blk(dao->ctrl_blk); + dao->hw->dao_put_ctrl_blk(dao->ctrl_blk); dao->hw = dao->ctrl_blk = NULL; daio_rsc_uninit(&dao->daio); @@ -502,7 +500,7 @@ error1: static int dai_rsc_uninit(struct dai *dai) { - ((struct hw *)dai->hw)->dai_put_ctrl_blk(dai->ctrl_blk); + dai->hw->dai_put_ctrl_blk(dai->ctrl_blk); dai->hw = dai->ctrl_blk = NULL; daio_rsc_uninit(&dai->daio); return 0; @@ -729,10 +727,10 @@ int daio_mgr_create(struct hw *hw, struct daio_mgr **rdaio_mgr) daio_mgr->commit_write = daio_mgr_commit_write; for (i = 0; i < 8; i++) { - ((struct hw *)hw)->daio_mgr_dsb_dao(daio_mgr->mgr.ctrl_blk, i); - ((struct hw *)hw)->daio_mgr_dsb_dai(daio_mgr->mgr.ctrl_blk, i); + hw->daio_mgr_dsb_dao(daio_mgr->mgr.ctrl_blk, i); + hw->daio_mgr_dsb_dai(daio_mgr->mgr.ctrl_blk, i); } - ((struct hw *)hw)->daio_mgr_commit_write(hw, daio_mgr->mgr.ctrl_blk); + hw->daio_mgr_commit_write(hw, daio_mgr->mgr.ctrl_blk); *rdaio_mgr = daio_mgr; diff --git a/sound/pci/ctxfi/ctdaio.h b/sound/pci/ctxfi/ctdaio.h index e4817de08864..0ebbf350f51a 100644 --- a/sound/pci/ctxfi/ctdaio.h +++ b/sound/pci/ctxfi/ctdaio.h @@ -23,6 +23,7 @@ #include "ctimap.h" #include #include +#include /* Define the descriptor of a daio resource */ enum DAIOTYP { @@ -98,6 +99,7 @@ struct daio_desc { struct daio_mgr { struct rsc_mgr mgr; /* Basic resource manager info */ + struct snd_card *card; /* pointer to this card */ spinlock_t mgr_lock; spinlock_t imap_lock; struct list_head imappers; diff --git a/sound/pci/ctxfi/cthardware.h b/sound/pci/ctxfi/cthardware.h index c5ded6a6654f..54cc9cb75f00 100644 --- a/sound/pci/ctxfi/cthardware.h +++ b/sound/pci/ctxfi/cthardware.h @@ -20,6 +20,7 @@ #include #include +#include enum CHIPTYP { ATC20K1, @@ -184,6 +185,7 @@ struct hw { void *irq_callback_data; struct pci_dev *pci; /* the pci kernel structure of this card */ + struct snd_card *card; /* pointer to this card */ int irq; unsigned long io_base; void __iomem *mem_base; diff --git a/sound/pci/ctxfi/ctsrc.h b/sound/pci/ctxfi/ctsrc.h index 6d95afbbc852..da7573c5db9b 100644 --- a/sound/pci/ctxfi/ctsrc.h +++ b/sound/pci/ctxfi/ctsrc.h @@ -23,6 +23,7 @@ #include "ctimap.h" #include #include +#include #define SRC_STATE_OFF 0x0 #define SRC_STATE_INIT 0x4 @@ -85,6 +86,7 @@ struct src_desc { /* Define src manager object */ struct src_mgr { struct rsc_mgr mgr; /* Basic resource manager info */ + struct snd_card *card; /* pointer to this card */ spinlock_t mgr_lock; /* request src resource */ @@ -123,6 +125,7 @@ struct srcimp_desc { struct srcimp_mgr { struct rsc_mgr mgr; /* Basic resource manager info */ + struct snd_card *card; /* pointer to this card */ spinlock_t mgr_lock; spinlock_t imap_lock; struct list_head imappers; From e5347f9ab7cdafc2dbc0d4f7f30204293be71d8e Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Mon, 29 Sep 2014 14:33:24 +0530 Subject: [PATCH 205/251] ALSA: ctxfi: initialized snd_card initialized the reference of snd_card which was added to the various structures through the previous patch of the series. these references of snd_card will be used in a later patch to convert the pr_* macros to dev_* Signed-off-by: Sudip Mukherjee Signed-off-by: Takashi Iwai --- sound/pci/ctxfi/ctamixer.c | 2 ++ sound/pci/ctxfi/ctatc.c | 1 + sound/pci/ctxfi/ctdaio.c | 1 + sound/pci/ctxfi/ctsrc.c | 2 ++ 4 files changed, 6 insertions(+) diff --git a/sound/pci/ctxfi/ctamixer.c b/sound/pci/ctxfi/ctamixer.c index 4671cbe7b397..4d389c330978 100644 --- a/sound/pci/ctxfi/ctamixer.c +++ b/sound/pci/ctxfi/ctamixer.c @@ -314,6 +314,7 @@ int amixer_mgr_create(struct hw *hw, struct amixer_mgr **ramixer_mgr) amixer_mgr->get_amixer = get_amixer_rsc; amixer_mgr->put_amixer = put_amixer_rsc; + amixer_mgr->card = hw->card; *ramixer_mgr = amixer_mgr; @@ -467,6 +468,7 @@ int sum_mgr_create(struct hw *hw, struct sum_mgr **rsum_mgr) sum_mgr->get_sum = get_sum_rsc; sum_mgr->put_sum = put_sum_rsc; + sum_mgr->card = hw->card; *rsum_mgr = sum_mgr; diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c index e536ab97ddeb..5cc8c3860b11 100644 --- a/sound/pci/ctxfi/ctatc.c +++ b/sound/pci/ctxfi/ctatc.c @@ -1333,6 +1333,7 @@ static int atc_create_hw_devs(struct ct_atc *atc) pr_err("Failed to create hw obj!!!\n"); return err; } + hw->card = atc->card; atc->hw = hw; /* Initialize card hardware. */ diff --git a/sound/pci/ctxfi/ctdaio.c b/sound/pci/ctxfi/ctdaio.c index aa4aa712c285..212280e11f6e 100644 --- a/sound/pci/ctxfi/ctdaio.c +++ b/sound/pci/ctxfi/ctdaio.c @@ -725,6 +725,7 @@ int daio_mgr_create(struct hw *hw, struct daio_mgr **rdaio_mgr) daio_mgr->imap_add = daio_imap_add; daio_mgr->imap_delete = daio_imap_delete; daio_mgr->commit_write = daio_mgr_commit_write; + daio_mgr->card = hw->card; for (i = 0; i < 8; i++) { hw->daio_mgr_dsb_dao(daio_mgr->mgr.ctrl_blk, i); diff --git a/sound/pci/ctxfi/ctsrc.c b/sound/pci/ctxfi/ctsrc.c index d3ef213fad77..50fa35bc66d2 100644 --- a/sound/pci/ctxfi/ctsrc.c +++ b/sound/pci/ctxfi/ctsrc.c @@ -566,6 +566,7 @@ int src_mgr_create(struct hw *hw, struct src_mgr **rsrc_mgr) src_mgr->src_enable = src_enable; src_mgr->src_disable = src_disable; src_mgr->commit_write = src_mgr_commit_write; + src_mgr->card = hw->card; /* Disable all SRC resources. */ for (i = 0; i < 256; i++) @@ -857,6 +858,7 @@ int srcimp_mgr_create(struct hw *hw, struct srcimp_mgr **rsrcimp_mgr) srcimp_mgr->put_srcimp = put_srcimp_rsc; srcimp_mgr->imap_add = srcimp_imap_add; srcimp_mgr->imap_delete = srcimp_imap_delete; + srcimp_mgr->card = hw->card; *rsrcimp_mgr = srcimp_mgr; From a45c4d5142595a9b7907499f6d67f702bc20aeb4 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Mon, 29 Sep 2014 14:33:25 +0530 Subject: [PATCH 206/251] ALSA: ctxfi: ctatc: added reference to snd_card added reference of the card in the convert_format function so that we can know which card has called the function. this reference of the snd_card will actually be used in a later patch to convert the pr_* macro to dev_*. Signed-off-by: Sudip Mukherjee Signed-off-by: Takashi Iwai --- sound/pci/ctxfi/ctatc.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c index 5cc8c3860b11..d62aa9e2adcd 100644 --- a/sound/pci/ctxfi/ctatc.c +++ b/sound/pci/ctxfi/ctatc.c @@ -171,7 +171,8 @@ static unsigned long atc_get_ptp_phys(struct ct_atc *atc, int index) return atc->vm->get_ptp_phys(atc->vm, index); } -static unsigned int convert_format(snd_pcm_format_t snd_format) +static unsigned int convert_format(snd_pcm_format_t snd_format, + struct snd_card *card) { switch (snd_format) { case SNDRV_PCM_FORMAT_U8: @@ -268,7 +269,8 @@ static int atc_pcm_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm) src = apcm->src; src->ops->set_pitch(src, pitch); src->ops->set_rom(src, select_rom(pitch)); - src->ops->set_sf(src, convert_format(apcm->substream->runtime->format)); + src->ops->set_sf(src, convert_format(apcm->substream->runtime->format, + atc->card)); src->ops->set_pm(src, (src->ops->next_interleave(src) != NULL)); /* Get AMIXER resource */ @@ -738,7 +740,8 @@ static int atc_pcm_capture_start(struct ct_atc *atc, struct ct_atc_pcm *apcm) /* Set up recording SRC */ src = apcm->src; - src->ops->set_sf(src, convert_format(apcm->substream->runtime->format)); + src->ops->set_sf(src, convert_format(apcm->substream->runtime->format, + atc->card)); src->ops->set_sa(src, apcm->vm_block->addr); src->ops->set_la(src, apcm->vm_block->addr + apcm->vm_block->size); src->ops->set_ca(src, apcm->vm_block->addr); @@ -807,7 +810,8 @@ static int spdif_passthru_playback_get_resources(struct ct_atc *atc, src = apcm->src; src->ops->set_pitch(src, pitch); src->ops->set_rom(src, select_rom(pitch)); - src->ops->set_sf(src, convert_format(apcm->substream->runtime->format)); + src->ops->set_sf(src, convert_format(apcm->substream->runtime->format, + atc->card)); src->ops->set_pm(src, (src->ops->next_interleave(src) != NULL)); src->ops->set_bp(src, 1); From 0cae90a96c15f2fd3bd139ba5505755c9c9ef2eb Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Mon, 29 Sep 2014 14:33:26 +0530 Subject: [PATCH 207/251] ALSA: ctxfi: pr_* replaced with dev_* pr_* macros replaced with dev_* as they are more preffered over pr_*. each file which had pr_* was reviewed manually and replaced with dev_*. here we have actually used the various snd_card which was added to some structures of ctxfi via a previous patch of this series. in the ctvmem.c file we have passed a reference of ct_atc as an argument to get_vm_block function so that it can be used from dev_*. since dev_* will print the device information , so the prefix of "ctxfi" from the various pr_* were also removed. Signed-off-by: Sudip Mukherjee Signed-off-by: Takashi Iwai --- sound/pci/ctxfi/ctamixer.c | 6 ++++-- sound/pci/ctxfi/ctatc.c | 27 ++++++++++++++++----------- sound/pci/ctxfi/ctdaio.c | 3 ++- sound/pci/ctxfi/cthw20k1.c | 15 +++++++++------ sound/pci/ctxfi/cthw20k2.c | 24 +++++++++++++++--------- sound/pci/ctxfi/ctmixer.c | 6 ++++-- sound/pci/ctxfi/ctpcm.c | 9 ++++++--- sound/pci/ctxfi/ctresource.c | 18 ++++++++++++------ sound/pci/ctxfi/ctsrc.c | 6 ++++-- sound/pci/ctxfi/ctvmem.c | 12 ++++++++---- sound/pci/ctxfi/xfi.c | 15 +++++++++------ 11 files changed, 89 insertions(+), 52 deletions(-) diff --git a/sound/pci/ctxfi/ctamixer.c b/sound/pci/ctxfi/ctamixer.c index 4d389c330978..c7dc38d41b7f 100644 --- a/sound/pci/ctxfi/ctamixer.c +++ b/sound/pci/ctxfi/ctamixer.c @@ -258,7 +258,8 @@ static int get_amixer_rsc(struct amixer_mgr *mgr, } spin_unlock_irqrestore(&mgr->mgr_lock, flags); if (err) { - pr_err("ctxfi: Can't meet AMIXER resource request!\n"); + dev_err(mgr->card->dev, + "Can't meet AMIXER resource request!\n"); goto error; } @@ -412,7 +413,8 @@ static int get_sum_rsc(struct sum_mgr *mgr, } spin_unlock_irqrestore(&mgr->mgr_lock, flags); if (err) { - pr_err("ctxfi: Can't meet SUM resource request!\n"); + dev_err(mgr->card->dev, + "Can't meet SUM resource request!\n"); goto error; } diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c index d62aa9e2adcd..454659074390 100644 --- a/sound/pci/ctxfi/ctatc.c +++ b/sound/pci/ctxfi/ctatc.c @@ -186,7 +186,7 @@ static unsigned int convert_format(snd_pcm_format_t snd_format, case SNDRV_PCM_FORMAT_FLOAT_LE: return SRC_SF_F32; default: - pr_err("ctxfi: not recognized snd format is %d\n", + dev_err(card->dev, "not recognized snd format is %d\n", snd_format); return SRC_SF_S16; } @@ -1286,8 +1286,9 @@ static int atc_identify_card(struct ct_atc *atc, unsigned int ssid) p = snd_pci_quirk_lookup_id(vendor_id, device_id, list); if (p) { if (p->value < 0) { - pr_err("ctxfi: Device %04x:%04x is black-listed\n", - vendor_id, device_id); + dev_err(atc->card->dev, + "Device %04x:%04x is black-listed\n", + vendor_id, device_id); return -ENOENT; } atc->model = p->value; @@ -1318,7 +1319,8 @@ int ct_atc_create_alsa_devs(struct ct_atc *atc) err = alsa_dev_funcs[i].create(atc, i, alsa_dev_funcs[i].public_name); if (err) { - pr_err("ctxfi: Creating alsa device %d failed!\n", i); + dev_err(atc->card->dev, + "Creating alsa device %d failed!\n", i); return err; } } @@ -1334,7 +1336,7 @@ static int atc_create_hw_devs(struct ct_atc *atc) err = create_hw_obj(atc->pci, atc->chip_type, atc->model, &hw); if (err) { - pr_err("Failed to create hw obj!!!\n"); + dev_err(atc->card->dev, "Failed to create hw obj!!!\n"); return err; } hw->card = atc->card; @@ -1354,7 +1356,8 @@ static int atc_create_hw_devs(struct ct_atc *atc) err = rsc_mgr_funcs[i].create(atc->hw, &atc->rsc_mgrs[i]); if (err) { - pr_err("ctxfi: Failed to create rsc_mgr %d!!!\n", i); + dev_err(atc->card->dev, + "Failed to create rsc_mgr %d!!!\n", i); return err; } } @@ -1401,7 +1404,8 @@ static int atc_get_resources(struct ct_atc *atc) err = daio_mgr->get_daio(daio_mgr, &da_desc, (struct daio **)&atc->daios[i]); if (err) { - pr_err("ctxfi: Failed to get DAIO resource %d!!!\n", + dev_err(atc->card->dev, + "Failed to get DAIO resource %d!!!\n", i); return err; } @@ -1605,7 +1609,8 @@ static int atc_resume(struct ct_atc *atc) /* Do hardware resume. */ err = atc_hw_resume(atc); if (err < 0) { - pr_err("ctxfi: pci_enable_device failed, disabling device\n"); + dev_err(atc->card->dev, + "pci_enable_device failed, disabling device\n"); snd_card_disconnect(atc->card); return err; } @@ -1702,7 +1707,7 @@ int ct_atc_create(struct snd_card *card, struct pci_dev *pci, /* Find card model */ err = atc_identify_card(atc, ssid); if (err < 0) { - pr_err("ctatc: Card not recognised\n"); + dev_err(card->dev, "ctatc: Card not recognised\n"); goto error1; } @@ -1718,7 +1723,7 @@ int ct_atc_create(struct snd_card *card, struct pci_dev *pci, err = ct_mixer_create(atc, (struct ct_mixer **)&atc->mixer); if (err) { - pr_err("ctxfi: Failed to create mixer obj!!!\n"); + dev_err(card->dev, "Failed to create mixer obj!!!\n"); goto error1; } @@ -1745,6 +1750,6 @@ int ct_atc_create(struct snd_card *card, struct pci_dev *pci, error1: ct_atc_destroy(atc); - pr_err("ctxfi: Something wrong!!!\n"); + dev_err(card->dev, "Something wrong!!!\n"); return err; } diff --git a/sound/pci/ctxfi/ctdaio.c b/sound/pci/ctxfi/ctdaio.c index 212280e11f6e..c1c3f8816fff 100644 --- a/sound/pci/ctxfi/ctdaio.c +++ b/sound/pci/ctxfi/ctdaio.c @@ -539,7 +539,8 @@ static int get_daio_rsc(struct daio_mgr *mgr, err = daio_mgr_get_rsc(&mgr->mgr, desc->type); spin_unlock_irqrestore(&mgr->mgr_lock, flags); if (err) { - pr_err("Can't meet DAIO resource request!\n"); + dev_err(mgr->card->dev, + "Can't meet DAIO resource request!\n"); return err; } diff --git a/sound/pci/ctxfi/cthw20k1.c b/sound/pci/ctxfi/cthw20k1.c index 8fc524fbaeab..b425aa8ee578 100644 --- a/sound/pci/ctxfi/cthw20k1.c +++ b/sound/pci/ctxfi/cthw20k1.c @@ -1268,7 +1268,8 @@ static int hw_trn_init(struct hw *hw, const struct trn_conf *info) /* Set up device page table */ if ((~0UL) == info->vm_pgt_phys) { - pr_err("Wrong device page table page address!\n"); + dev_err(hw->card->dev, + "Wrong device page table page address!\n"); return -1; } @@ -1327,7 +1328,7 @@ static int hw_pll_init(struct hw *hw, unsigned int rsr) mdelay(40); } if (i >= 3) { - pr_alert("PLL initialization failed!!!\n"); + dev_alert(hw->card->dev, "PLL initialization failed!!!\n"); return -EBUSY; } @@ -1351,7 +1352,7 @@ static int hw_auto_init(struct hw *hw) break; } if (!get_field(gctl, GCTL_AID)) { - pr_alert("Card Auto-init failed!!!\n"); + dev_alert(hw->card->dev, "Card Auto-init failed!!!\n"); return -EBUSY; } @@ -1911,8 +1912,9 @@ static int hw_card_start(struct hw *hw) /* Set DMA transfer mask */ if (pci_set_dma_mask(pci, CT_XFI_DMA_MASK) < 0 || pci_set_consistent_dma_mask(pci, CT_XFI_DMA_MASK) < 0) { - pr_err("architecture does not support PCI busmaster DMA with mask 0x%llx\n", - CT_XFI_DMA_MASK); + dev_err(hw->card->dev, + "architecture does not support PCI busmaster DMA with mask 0x%llx\n", + CT_XFI_DMA_MASK); err = -ENXIO; goto error1; } @@ -1941,7 +1943,8 @@ static int hw_card_start(struct hw *hw) err = request_irq(pci->irq, ct_20k1_interrupt, IRQF_SHARED, KBUILD_MODNAME, hw); if (err < 0) { - pr_err("XFi: Cannot get irq %d\n", pci->irq); + dev_err(hw->card->dev, + "XFi: Cannot get irq %d\n", pci->irq); goto error2; } hw->irq = pci->irq; diff --git a/sound/pci/ctxfi/cthw20k2.c b/sound/pci/ctxfi/cthw20k2.c index b2c5d5a05a95..253899d13790 100644 --- a/sound/pci/ctxfi/cthw20k2.c +++ b/sound/pci/ctxfi/cthw20k2.c @@ -1187,7 +1187,8 @@ static int hw_daio_init(struct hw *hw, const struct daio_conf *info) hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x21212121); hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0); } else { - pr_alert("ctxfi: ERROR!!! Invalid sampling rate!!!\n"); + dev_alert(hw->card->dev, + "ERROR!!! Invalid sampling rate!!!\n"); return -EINVAL; } @@ -1246,7 +1247,8 @@ static int hw_trn_init(struct hw *hw, const struct trn_conf *info) /* Set up device page table */ if ((~0UL) == info->vm_pgt_phys) { - pr_alert("ctxfi: Wrong device page table page address!!!\n"); + dev_alert(hw->card->dev, + "Wrong device page table page address!!!\n"); return -1; } @@ -1351,7 +1353,8 @@ static int hw_pll_init(struct hw *hw, unsigned int rsr) break; } if (i >= 1000) { - pr_alert("ctxfi: PLL initialization failed!!!\n"); + dev_alert(hw->card->dev, + "PLL initialization failed!!!\n"); return -EBUSY; } @@ -1375,7 +1378,7 @@ static int hw_auto_init(struct hw *hw) break; } if (!get_field(gctl, GCTL_AID)) { - pr_alert("ctxfi: Card Auto-init failed!!!\n"); + dev_alert(hw->card->dev, "Card Auto-init failed!!!\n"); return -EBUSY; } @@ -1846,7 +1849,7 @@ static int hw_adc_init(struct hw *hw, const struct adc_conf *info) /* Initialize I2C */ err = hw20k2_i2c_init(hw, 0x1A, 1, 1); if (err < 0) { - pr_alert("ctxfi: Failure to acquire I2C!!!\n"); + dev_alert(hw->card->dev, "Failure to acquire I2C!!!\n"); goto error; } @@ -1889,8 +1892,9 @@ static int hw_adc_init(struct hw *hw, const struct adc_conf *info) hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_MMC, 0x0A), MAKE_WM8775_DATA(0x0A)); } else { - pr_alert("ctxfi: Invalid master sampling rate (msr %d)!!!\n", - info->msr); + dev_alert(hw->card->dev, + "Invalid master sampling rate (msr %d)!!!\n", + info->msr); err = -EINVAL; goto error; } @@ -2033,7 +2037,8 @@ static int hw_card_start(struct hw *hw) /* Set DMA transfer mask */ if (pci_set_dma_mask(pci, CT_XFI_DMA_MASK) < 0 || pci_set_consistent_dma_mask(pci, CT_XFI_DMA_MASK) < 0) { - pr_err("ctxfi: architecture does not support PCI busmaster DMA with mask 0x%llx\n", + dev_err(hw->card->dev, + "architecture does not support PCI busmaster DMA with mask 0x%llx\n", CT_XFI_DMA_MASK); err = -ENXIO; goto error1; @@ -2062,7 +2067,8 @@ static int hw_card_start(struct hw *hw) err = request_irq(pci->irq, ct_20k2_interrupt, IRQF_SHARED, KBUILD_MODNAME, hw); if (err < 0) { - pr_err("XFi: Cannot get irq %d\n", pci->irq); + dev_err(hw->card->dev, + "XFi: Cannot get irq %d\n", pci->irq); goto error2; } hw->irq = pci->irq; diff --git a/sound/pci/ctxfi/ctmixer.c b/sound/pci/ctxfi/ctmixer.c index 017fa91706d4..4f4a2a5dedb8 100644 --- a/sound/pci/ctxfi/ctmixer.c +++ b/sound/pci/ctxfi/ctmixer.c @@ -854,7 +854,8 @@ static int ct_mixer_get_resources(struct ct_mixer *mixer) for (i = 0; i < (NUM_CT_SUMS * CHN_NUM); i++) { err = sum_mgr->get_sum(sum_mgr, &sum_desc, &sum); if (err) { - pr_err("ctxfi:Failed to get sum resources for front output!\n"); + dev_err(mixer->atc->card->dev, + "Failed to get sum resources for front output!\n"); break; } mixer->sums[i] = sum; @@ -868,7 +869,8 @@ static int ct_mixer_get_resources(struct ct_mixer *mixer) for (i = 0; i < (NUM_CT_AMIXERS * CHN_NUM); i++) { err = amixer_mgr->get_amixer(amixer_mgr, &am_desc, &amixer); if (err) { - pr_err("ctxfi:Failed to get amixer resources for mixer obj!\n"); + dev_err(mixer->atc->card->dev, + "Failed to get amixer resources for mixer obj!\n"); break; } mixer->amixers[i] = amixer; diff --git a/sound/pci/ctxfi/ctpcm.c b/sound/pci/ctxfi/ctpcm.c index 6826c2c02c44..d86c474ca5b6 100644 --- a/sound/pci/ctxfi/ctpcm.c +++ b/sound/pci/ctxfi/ctpcm.c @@ -217,7 +217,8 @@ static int ct_pcm_playback_prepare(struct snd_pcm_substream *substream) err = atc->pcm_playback_prepare(atc, apcm); if (err < 0) { - pr_err("ctxfi: Preparing pcm playback failed!!!\n"); + dev_err(atc->card->dev, + "Preparing pcm playback failed!!!\n"); return err; } @@ -324,7 +325,8 @@ static int ct_pcm_capture_prepare(struct snd_pcm_substream *substream) err = atc->pcm_capture_prepare(atc, apcm); if (err < 0) { - pr_err("ctxfi: Preparing pcm capture failed!!!\n"); + dev_err(atc->card->dev, + "Preparing pcm capture failed!!!\n"); return err; } @@ -435,7 +437,8 @@ int ct_alsa_pcm_create(struct ct_atc *atc, err = snd_pcm_new(atc->card, "ctxfi", device, playback_count, capture_count, &pcm); if (err < 0) { - pr_err("ctxfi: snd_pcm_new failed!! Err=%d\n", err); + dev_err(atc->card->dev, "snd_pcm_new failed!! Err=%d\n", + err); return err; } diff --git a/sound/pci/ctxfi/ctresource.c b/sound/pci/ctxfi/ctresource.c index 5aac63fd3bff..1a97e406d8ec 100644 --- a/sound/pci/ctxfi/ctresource.c +++ b/sound/pci/ctxfi/ctresource.c @@ -162,12 +162,14 @@ rsc_init(struct rsc *rsc, u32 idx, enum RSCTYP type, u32 msr, struct hw *hw) case DAIO: break; default: - pr_err("ctxfi: Invalid resource type value %d!\n", type); + dev_err(((struct hw *)hw)->card->dev, + "Invalid resource type value %d!\n", type); return -EINVAL; } if (err) { - pr_err("ctxfi: Failed to get resource control block!\n"); + dev_err(((struct hw *)hw)->card->dev, + "Failed to get resource control block!\n"); return err; } @@ -188,7 +190,8 @@ int rsc_uninit(struct rsc *rsc) case DAIO: break; default: - pr_err("ctxfi: Invalid resource type value %d!\n", + dev_err(((struct hw *)rsc->hw)->card->dev, + "Invalid resource type value %d!\n", rsc->type); break; } @@ -230,13 +233,15 @@ int rsc_mgr_init(struct rsc_mgr *mgr, enum RSCTYP type, case SUM: break; default: - pr_err("ctxfi: Invalid resource type value %d!\n", type); + dev_err(hw->card->dev, + "Invalid resource type value %d!\n", type); err = -EINVAL; goto error; } if (err) { - pr_err("ctxfi: Failed to get manager control block!\n"); + dev_err(hw->card->dev, + "Failed to get manager control block!\n"); goto error; } @@ -275,7 +280,8 @@ int rsc_mgr_uninit(struct rsc_mgr *mgr) case SUM: break; default: - pr_err("ctxfi: Invalid resource type value %d!\n", + dev_err(((struct hw *)mgr->hw)->card->dev, + "Invalid resource type value %d!\n", mgr->type); break; } diff --git a/sound/pci/ctxfi/ctsrc.c b/sound/pci/ctxfi/ctsrc.c index 50fa35bc66d2..ec1f08464d93 100644 --- a/sound/pci/ctxfi/ctsrc.c +++ b/sound/pci/ctxfi/ctsrc.c @@ -431,7 +431,8 @@ get_src_rsc(struct src_mgr *mgr, const struct src_desc *desc, struct src **rsrc) spin_unlock_irqrestore(&mgr->mgr_lock, flags); if (err) { - pr_err("ctxfi: Can't meet SRC resource request!\n"); + dev_err(mgr->card->dev, + "Can't meet SRC resource request!\n"); return err; } @@ -740,7 +741,8 @@ static int get_srcimp_rsc(struct srcimp_mgr *mgr, } spin_unlock_irqrestore(&mgr->mgr_lock, flags); if (err) { - pr_err("ctxfi: Can't meet SRCIMP resource request!\n"); + dev_err(mgr->card->dev, + "Can't meet SRCIMP resource request!\n"); goto error1; } diff --git a/sound/pci/ctxfi/ctvmem.c b/sound/pci/ctxfi/ctvmem.c index 38163f52dd5f..419306ef825f 100644 --- a/sound/pci/ctxfi/ctvmem.c +++ b/sound/pci/ctxfi/ctvmem.c @@ -16,6 +16,7 @@ */ #include "ctvmem.h" +#include "ctatc.h" #include #include #include @@ -29,14 +30,15 @@ * @size must be page aligned. * */ static struct ct_vm_block * -get_vm_block(struct ct_vm *vm, unsigned int size) +get_vm_block(struct ct_vm *vm, unsigned int size, struct ct_atc *atc) { struct ct_vm_block *block = NULL, *entry; struct list_head *pos; size = CT_PAGE_ALIGN(size); if (size > vm->size) { - pr_err("ctxfi: Fail! No sufficient device virtual memory space available!\n"); + dev_err(atc->card->dev, + "Fail! No sufficient device virtual memory space available!\n"); return NULL; } @@ -128,10 +130,12 @@ ct_vm_map(struct ct_vm *vm, struct snd_pcm_substream *substream, int size) unsigned int pte_start; unsigned i, pages; unsigned long *ptp; + struct ct_atc *atc = snd_pcm_substream_chip(substream); - block = get_vm_block(vm, size); + block = get_vm_block(vm, size, atc); if (block == NULL) { - pr_err("ctxfi: No virtual memory block that is big enough to allocate!\n"); + dev_err(atc->card->dev, + "No virtual memory block that is big enough to allocate!\n"); return NULL; } diff --git a/sound/pci/ctxfi/xfi.c b/sound/pci/ctxfi/xfi.c index 35e85ba80656..f2f32779de98 100644 --- a/sound/pci/ctxfi/xfi.c +++ b/sound/pci/ctxfi/xfi.c @@ -76,15 +76,18 @@ ct_card_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) if (err) return err; if ((reference_rate != 48000) && (reference_rate != 44100)) { - pr_err("ctxfi: Invalid reference_rate value %u!!!\n", - reference_rate); - pr_err("ctxfi: The valid values for reference_rate are 48000 and 44100, Value 48000 is assumed.\n"); + dev_err(card->dev, + "Invalid reference_rate value %u!!!\n", + reference_rate); + dev_err(card->dev, + "The valid values for reference_rate are 48000 and 44100, Value 48000 is assumed.\n"); reference_rate = 48000; } if ((multiple != 1) && (multiple != 2) && (multiple != 4)) { - pr_err("ctxfi: Invalid multiple value %u!!!\n", - multiple); - pr_err("ctxfi: The valid values for multiple are 1, 2 and 4, Value 2 is assumed.\n"); + dev_err(card->dev, "Invalid multiple value %u!!!\n", + multiple); + dev_err(card->dev, + "The valid values for multiple are 1, 2 and 4, Value 2 is assumed.\n"); multiple = 2; } err = ct_atc_create(card, pci, reference_rate, multiple, From 555b9ee1368a9ceddd5c963ad918db5120638674 Mon Sep 17 00:00:00 2001 From: Stefan Kristiansson Date: Mon, 29 Sep 2014 22:41:10 +0300 Subject: [PATCH 208/251] ASoC: ssm2602: add device tree bindings Allow the ssm2602/ssm2603/ssm2604 codec driver to be instantiated from the device tree. Also, add Kconfig prompts to allow manual selection of both the I2C and SPI configuration versions of the driver. Signed-off-by: Stefan Kristiansson Signed-off-by: Mark Brown Acked-by: Lars-Peter Clausen --- .../devicetree/bindings/sound/adi,ssm2602.txt | 19 +++++++++++++++++++ sound/soc/codecs/Kconfig | 8 ++++++-- sound/soc/codecs/ssm2602-i2c.c | 9 +++++++++ sound/soc/codecs/ssm2602-spi.c | 7 +++++++ 4 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/adi,ssm2602.txt diff --git a/Documentation/devicetree/bindings/sound/adi,ssm2602.txt b/Documentation/devicetree/bindings/sound/adi,ssm2602.txt new file mode 100644 index 000000000000..3b3302fe399b --- /dev/null +++ b/Documentation/devicetree/bindings/sound/adi,ssm2602.txt @@ -0,0 +1,19 @@ +Analog Devices SSM2602, SSM2603 and SSM2604 I2S audio CODEC devices + +SSM2602 support both I2C and SPI as the configuration interface, +the selection is made by the MODE strap-in pin. +SSM2603 and SSM2604 only support I2C as the configuration interface. + +Required properties: + + - compatible : One of "adi,ssm2602", "adi,ssm2603" or "adi,ssm2604" + + - reg : the I2C address of the device for I2C, the chip select + number for SPI. + + Example: + + ssm2602: ssm2602@1a { + compatible = "adi,ssm2602"; + reg = <0x1a>; + }; diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 8838838e25ed..3649e7399ec7 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -520,12 +520,16 @@ config SND_SOC_SSM2602 tristate config SND_SOC_SSM2602_SPI + tristate "Analog Devices SSM2602 CODEC - SPI" + depends on SPI_MASTER select SND_SOC_SSM2602 - tristate + select REGMAP_SPI config SND_SOC_SSM2602_I2C + tristate "Analog Devices SSM2602 CODEC - I2C" + depends on I2C select SND_SOC_SSM2602 - tristate + select REGMAP_I2C config SND_SOC_STA32X tristate diff --git a/sound/soc/codecs/ssm2602-i2c.c b/sound/soc/codecs/ssm2602-i2c.c index abd63d537173..0d9779d6bfda 100644 --- a/sound/soc/codecs/ssm2602-i2c.c +++ b/sound/soc/codecs/ssm2602-i2c.c @@ -41,10 +41,19 @@ static const struct i2c_device_id ssm2602_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, ssm2602_i2c_id); +static const struct of_device_id ssm2602_of_match[] = { + { .compatible = "adi,ssm2602", }, + { .compatible = "adi,ssm2603", }, + { .compatible = "adi,ssm2604", }, + { } +}; +MODULE_DEVICE_TABLE(of, ssm2602_of_match); + static struct i2c_driver ssm2602_i2c_driver = { .driver = { .name = "ssm2602", .owner = THIS_MODULE, + .of_match_table = ssm2602_of_match, }, .probe = ssm2602_i2c_probe, .remove = ssm2602_i2c_remove, diff --git a/sound/soc/codecs/ssm2602-spi.c b/sound/soc/codecs/ssm2602-spi.c index 2bf55e24a7bb..b5df14fbe3ad 100644 --- a/sound/soc/codecs/ssm2602-spi.c +++ b/sound/soc/codecs/ssm2602-spi.c @@ -26,10 +26,17 @@ static int ssm2602_spi_remove(struct spi_device *spi) return 0; } +static const struct of_device_id ssm2602_of_match[] = { + { .compatible = "adi,ssm2602", }, + { } +}; +MODULE_DEVICE_TABLE(of, ssm2602_of_match); + static struct spi_driver ssm2602_spi_driver = { .driver = { .name = "ssm2602", .owner = THIS_MODULE, + .of_match_table = ssm2602_of_match, }, .probe = ssm2602_spi_probe, .remove = ssm2602_spi_remove, From 3b2a0013c7d49783d5ac3df9178e9907cd6ebd73 Mon Sep 17 00:00:00 2001 From: Stefan Kristiansson Date: Mon, 29 Sep 2014 22:41:37 +0300 Subject: [PATCH 209/251] ASoC: ssm2602: add support for 11.025kHz and 22.5kHz sample rates This adds the necessary values to the constraint list and register values to the coefficient table in order to configure the device for 11.025kHz and 22.5kHz sample rates. Signed-off-by: Stefan Kristiansson Signed-off-by: Mark Brown Acked-by: Lars-Peter Clausen --- sound/soc/codecs/ssm2602.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c index 4021cd435740..7c418485716a 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c @@ -192,7 +192,7 @@ static const struct snd_pcm_hw_constraint_list ssm2602_constraints_12288000 = { }; static const unsigned int ssm2602_rates_11289600[] = { - 8000, 44100, 88200, + 8000, 11025, 22050, 44100, 88200, }; static const struct snd_pcm_hw_constraint_list ssm2602_constraints_11289600 = { @@ -237,6 +237,16 @@ static const struct ssm2602_coeff ssm2602_coeff_table[] = { {18432000, 96000, SSM2602_COEFF_SRATE(0x7, 0x1, 0x0)}, {12000000, 96000, SSM2602_COEFF_SRATE(0x7, 0x0, 0x1)}, + /* 11.025k */ + {11289600, 11025, SSM2602_COEFF_SRATE(0xc, 0x0, 0x0)}, + {16934400, 11025, SSM2602_COEFF_SRATE(0xc, 0x1, 0x0)}, + {12000000, 11025, SSM2602_COEFF_SRATE(0xc, 0x1, 0x1)}, + + /* 22.05k */ + {11289600, 22050, SSM2602_COEFF_SRATE(0xd, 0x0, 0x0)}, + {16934400, 22050, SSM2602_COEFF_SRATE(0xd, 0x1, 0x0)}, + {12000000, 22050, SSM2602_COEFF_SRATE(0xd, 0x1, 0x1)}, + /* 44.1k */ {11289600, 44100, SSM2602_COEFF_SRATE(0x8, 0x0, 0x0)}, {16934400, 44100, SSM2602_COEFF_SRATE(0x8, 0x1, 0x0)}, @@ -467,7 +477,8 @@ static int ssm2602_set_bias_level(struct snd_soc_codec *codec, return 0; } -#define SSM2602_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ +#define SSM2602_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ + SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\ SNDRV_PCM_RATE_96000) From ece1e4999606fc323aee96a1cdb9b7991c01dd09 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 29 Sep 2014 23:25:29 -0300 Subject: [PATCH 210/251] ASoC: fsl_ssi: Remove unneeded 'i2s-slave' property There is no need to use 'i2s-slave' property, since master/slave configuration are passed via machine layer. This change does not break existing users because they do check for slave mode inside sound/soc/fsl/mpc8610_hpcd.c/p1022_ds.c/p1022_rdk.c Signed-off-by: Fabio Estevam Acked-by: Timur Tabi Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_ssi.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 16a1361b68b3..f19224ee5b03 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -1314,9 +1314,6 @@ static int fsl_ssi_probe(struct platform_device *pdev) if (sprop) { if (!strcmp(sprop, "ac97-slave")) ssi_private->dai_fmt = SND_SOC_DAIFMT_AC97; - else if (!strcmp(sprop, "i2s-slave")) - ssi_private->dai_fmt = SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_CBM_CFM; } ssi_private->use_dma = !of_property_read_bool(np, From b93427b1c057841602e0fe2005153a6e82f2e658 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 29 Sep 2014 23:25:30 -0300 Subject: [PATCH 211/251] ASoC: fsl ssi doc: Remove unused properties The fsl_ssi driver only checks for the ac97 mode property, so remove the unused ones. Suggested-by: Nicolin Chen Signed-off-by: Fabio Estevam Acked-by: Timur Tabi Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/fsl,ssi.txt | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/fsl,ssi.txt b/Documentation/devicetree/bindings/sound/fsl,ssi.txt index 3aa4a8f528f4..5b76be45d18b 100644 --- a/Documentation/devicetree/bindings/sound/fsl,ssi.txt +++ b/Documentation/devicetree/bindings/sound/fsl,ssi.txt @@ -58,13 +58,7 @@ Optional properties: Documentation/devicetree/bindings/dma/dma.txt. - dma-names: Two dmas have to be defined, "tx" and "rx", if fsl,imx-fiq is not defined. -- fsl,mode: The operating mode for the SSI interface. - "i2s-slave" - I2S mode, SSI is clock slave - "i2s-master" - I2S mode, SSI is clock master - "lj-slave" - left-justified mode, SSI is clock slave - "lj-master" - l.j. mode, SSI is clock master - "rj-slave" - right-justified mode, SSI is clock slave - "rj-master" - r.j., SSI is clock master +- fsl,mode: The operating mode for the AC97 interface only. "ac97-slave" - AC97 mode, SSI is clock slave "ac97-master" - AC97 mode, SSI is clock master From 1cc0c054f380c1c477642b5d9d9d9f697f641dbc Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 1 Oct 2014 16:02:11 +0300 Subject: [PATCH 212/251] ASoC: davinci-mcasp: Convert the context save/restore to use array Instead of individual values use an array to store the registers need to be saved on suspend and restored on resume. It is going to be easier to add more registers to save and restore. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/davinci/davinci-mcasp.c | 38 ++++++++++++++----------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index c28508da34cf..63e24449eb89 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -42,14 +42,18 @@ #define MCASP_MAX_AFIFO_DEPTH 64 +static u32 context_regs[] = { + DAVINCI_MCASP_TXFMCTL_REG, + DAVINCI_MCASP_RXFMCTL_REG, + DAVINCI_MCASP_TXFMT_REG, + DAVINCI_MCASP_RXFMT_REG, + DAVINCI_MCASP_ACLKXCTL_REG, + DAVINCI_MCASP_ACLKRCTL_REG, + DAVINCI_MCASP_PDIR_REG, +}; + struct davinci_mcasp_context { - u32 txfmtctl; - u32 rxfmtctl; - u32 txfmt; - u32 rxfmt; - u32 aclkxctl; - u32 aclkrctl; - u32 pdir; + u32 config_regs[ARRAY_SIZE(context_regs)]; }; struct davinci_mcasp { @@ -857,14 +861,10 @@ static int davinci_mcasp_suspend(struct snd_soc_dai *dai) { struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai); struct davinci_mcasp_context *context = &mcasp->context; + int i; - context->txfmtctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG); - context->rxfmtctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG); - context->txfmt = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXFMT_REG); - context->rxfmt = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMT_REG); - context->aclkxctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG); - context->aclkrctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKRCTL_REG); - context->pdir = mcasp_get_reg(mcasp, DAVINCI_MCASP_PDIR_REG); + for (i = 0; i < ARRAY_SIZE(context_regs); i++) + context->config_regs[i] = mcasp_get_reg(mcasp, context_regs[i]); return 0; } @@ -873,14 +873,10 @@ static int davinci_mcasp_resume(struct snd_soc_dai *dai) { struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai); struct davinci_mcasp_context *context = &mcasp->context; + int i; - mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG, context->txfmtctl); - mcasp_set_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG, context->rxfmtctl); - mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMT_REG, context->txfmt); - mcasp_set_reg(mcasp, DAVINCI_MCASP_RXFMT_REG, context->rxfmt); - mcasp_set_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, context->aclkxctl); - mcasp_set_reg(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, context->aclkrctl); - mcasp_set_reg(mcasp, DAVINCI_MCASP_PDIR_REG, context->pdir); + for (i = 0; i < ARRAY_SIZE(context_regs); i++) + mcasp_set_reg(mcasp, context_regs[i], context->config_regs[i]); return 0; } From f114ce605daa1fb9d4efa253ea6d5bd4802902af Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 1 Oct 2014 16:02:12 +0300 Subject: [PATCH 213/251] ASoC: davinvi-mcasp: Proper suspend/resume support while audio is active If the board is sent to suspend (deep sleep) the McASP context will be lost. In case when suspend happens during active audio we need to save and restore more registers, which was configured during hw_param times as well. We need to add more config registers, AFIFO control registers and we also need to save and restore the serializer configuration as well. Since the number of serializers depends on the SoC we need to allocate the memory for it based on the num_serializer for the given McASP instance. With this patch the ongoing stream will resume after resuming from deep sleep. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/davinci/davinci-mcasp.c | 41 +++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index 63e24449eb89..5dcacc495438 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -49,11 +49,19 @@ static u32 context_regs[] = { DAVINCI_MCASP_RXFMT_REG, DAVINCI_MCASP_ACLKXCTL_REG, DAVINCI_MCASP_ACLKRCTL_REG, + DAVINCI_MCASP_AHCLKXCTL_REG, + DAVINCI_MCASP_AHCLKRCTL_REG, DAVINCI_MCASP_PDIR_REG, + DAVINCI_MCASP_RXMASK_REG, + DAVINCI_MCASP_TXMASK_REG, + DAVINCI_MCASP_RXTDM_REG, + DAVINCI_MCASP_TXTDM_REG, }; struct davinci_mcasp_context { u32 config_regs[ARRAY_SIZE(context_regs)]; + u32 afifo_regs[2]; /* for read/write fifo control registers */ + u32 *xrsr_regs; /* for serializer configuration */ }; struct davinci_mcasp { @@ -861,11 +869,25 @@ static int davinci_mcasp_suspend(struct snd_soc_dai *dai) { struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai); struct davinci_mcasp_context *context = &mcasp->context; + u32 reg; int i; for (i = 0; i < ARRAY_SIZE(context_regs); i++) context->config_regs[i] = mcasp_get_reg(mcasp, context_regs[i]); + if (mcasp->txnumevt) { + reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET; + context->afifo_regs[0] = mcasp_get_reg(mcasp, reg); + } + if (mcasp->rxnumevt) { + reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET; + context->afifo_regs[1] = mcasp_get_reg(mcasp, reg); + } + + for (i = 0; i < mcasp->num_serializer; i++) + context->xrsr_regs[i] = mcasp_get_reg(mcasp, + DAVINCI_MCASP_XRSRCTL_REG(i)); + return 0; } @@ -873,11 +895,25 @@ static int davinci_mcasp_resume(struct snd_soc_dai *dai) { struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai); struct davinci_mcasp_context *context = &mcasp->context; + u32 reg; int i; for (i = 0; i < ARRAY_SIZE(context_regs); i++) mcasp_set_reg(mcasp, context_regs[i], context->config_regs[i]); + if (mcasp->txnumevt) { + reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET; + mcasp_set_reg(mcasp, reg, context->afifo_regs[0]); + } + if (mcasp->rxnumevt) { + reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET; + mcasp_set_reg(mcasp, reg, context->afifo_regs[1]); + } + + for (i = 0; i < mcasp->num_serializer; i++) + mcasp_set_reg(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i), + context->xrsr_regs[i]); + return 0; } #else @@ -1195,6 +1231,11 @@ static int davinci_mcasp_probe(struct platform_device *pdev) mcasp->op_mode = pdata->op_mode; mcasp->tdm_slots = pdata->tdm_slots; mcasp->num_serializer = pdata->num_serializer; +#ifdef CONFIG_PM_SLEEP + mcasp->context.xrsr_regs = devm_kzalloc(&pdev->dev, + sizeof(u32) * mcasp->num_serializer, + GFP_KERNEL); +#endif mcasp->serial_dir = pdata->serial_dir; mcasp->version = pdata->version; mcasp->txnumevt = pdata->txnumevt; From cd69dc8868d64cfa2993944607d9e97927d95987 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Wed, 1 Oct 2014 15:08:14 +0300 Subject: [PATCH 214/251] ASoC: rt5640: Add function for enabling DMIC from ACPI probed machine There is no code enabling DMIC clock in systems that don't provide platform data for rt5640 after commit 71d97a794301 ("ASoC: rt5640: Use the platform data for DMIC settings"). I think it's worth to keep this static DMIC clock and alternative data pin setting during probe time. For making possible to use DMIC from ACPI probed machine (prior ACPI 5.1 with _DSD) this patch moves DMIC configuration to new exported rt5640_dmic_enable() that machine drivers can call. Please note, this patch moves DMIC configuration from i2c probe to codec probe in case platform data for rt5640 is set. Signed-off-by: Jarkko Nikula Cc: Oder Chiou Signed-off-by: Mark Brown --- sound/soc/codecs/rt5640.c | 49 ++++++++++++++++++++++++--------------- sound/soc/codecs/rt5640.h | 3 +++ 2 files changed, 33 insertions(+), 19 deletions(-) diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 6bc6efdec550..2fdcbb8e8a2a 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -1906,6 +1906,32 @@ static int rt5640_set_bias_level(struct snd_soc_codec *codec, return 0; } +int rt5640_dmic_enable(struct snd_soc_codec *codec, + bool dmic1_data_pin, bool dmic2_data_pin) +{ + struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec); + + regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1, + RT5640_GP2_PIN_MASK, RT5640_GP2_PIN_DMIC1_SCL); + + if (dmic1_data_pin) { + regmap_update_bits(rt5640->regmap, RT5640_DMIC, + RT5640_DMIC_1_DP_MASK, RT5640_DMIC_1_DP_GPIO3); + regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1, + RT5640_GP3_PIN_MASK, RT5640_GP3_PIN_DMIC1_SDA); + } + + if (dmic2_data_pin) { + regmap_update_bits(rt5640->regmap, RT5640_DMIC, + RT5640_DMIC_2_DP_MASK, RT5640_DMIC_2_DP_GPIO4); + regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1, + RT5640_GP4_PIN_MASK, RT5640_GP4_PIN_DMIC2_SDA); + } + + return 0; +} +EXPORT_SYMBOL_GPL(rt5640_dmic_enable); + static int rt5640_probe(struct snd_soc_codec *codec) { struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec); @@ -1945,6 +1971,10 @@ static int rt5640_probe(struct snd_soc_codec *codec) return -ENODEV; } + if (rt5640->pdata.dmic_en) + rt5640_dmic_enable(codec, rt5640->pdata.dmic1_data_pin, + rt5640->pdata.dmic2_data_pin); + return 0; } @@ -2194,25 +2224,6 @@ static int rt5640_i2c_probe(struct i2c_client *i2c, regmap_update_bits(rt5640->regmap, RT5640_IN3_IN4, RT5640_IN_DF2, RT5640_IN_DF2); - if (rt5640->pdata.dmic_en) { - regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1, - RT5640_GP2_PIN_MASK, RT5640_GP2_PIN_DMIC1_SCL); - - if (rt5640->pdata.dmic1_data_pin) { - regmap_update_bits(rt5640->regmap, RT5640_DMIC, - RT5640_DMIC_1_DP_MASK, RT5640_DMIC_1_DP_GPIO3); - regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1, - RT5640_GP3_PIN_MASK, RT5640_GP3_PIN_DMIC1_SDA); - } - - if (rt5640->pdata.dmic2_data_pin) { - regmap_update_bits(rt5640->regmap, RT5640_DMIC, - RT5640_DMIC_2_DP_MASK, RT5640_DMIC_2_DP_GPIO4); - regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1, - RT5640_GP4_PIN_MASK, RT5640_GP4_PIN_DMIC2_SDA); - } - } - rt5640->hp_mute = 1; return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5640, diff --git a/sound/soc/codecs/rt5640.h b/sound/soc/codecs/rt5640.h index 58ebe96b86da..3deb8babeabb 100644 --- a/sound/soc/codecs/rt5640.h +++ b/sound/soc/codecs/rt5640.h @@ -2097,4 +2097,7 @@ struct rt5640_priv { bool hp_mute; }; +int rt5640_dmic_enable(struct snd_soc_codec *codec, + bool dmic1_data_pin, bool dmic2_data_pin); + #endif From a5f0ab05b67213ef33107b716e8596a480b5875f Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Wed, 1 Oct 2014 15:08:15 +0300 Subject: [PATCH 215/251] ASoC: Intel: byt-rt5640: Enable DMIC interface for default DAPM route It turned out DMIC interface wasn't enabled/disabled runtime for active DMIC route in the rt5640 codec driver anymore after commit 71d97a794301 ("ASoC: rt5640: Use the platform data for DMIC settings"). Since DMIC interface must be enabled explicitly either by passing platform data to rt5640 codec driver or by calling new rt5640_dmic_enable() this patch adds a DMI quirk flag that is used to conditionally enable DMIC interface during sound card init time. Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/intel/byt-rt5640.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/sound/soc/intel/byt-rt5640.c b/sound/soc/intel/byt-rt5640.c index c323a101214e..8392c160d9e2 100644 --- a/sound/soc/intel/byt-rt5640.c +++ b/sound/soc/intel/byt-rt5640.c @@ -59,7 +59,11 @@ enum { BYT_RT5640_IN1_MAP, }; -static unsigned long byt_rt5640_custom_map = BYT_RT5640_DMIC1_MAP; +#define BYT_RT5640_MAP(quirk) ((quirk) & 0xff) +#define BYT_RT5640_DMIC_EN BIT(16) + +static unsigned long byt_rt5640_quirk = BYT_RT5640_DMIC1_MAP | + BYT_RT5640_DMIC_EN; static const struct snd_kcontrol_new byt_rt5640_controls[] = { SOC_DAPM_PIN_SWITCH("Headphone"), @@ -94,7 +98,7 @@ static int byt_rt5640_hw_params(struct snd_pcm_substream *substream, static int byt_rt5640_quirk_cb(const struct dmi_system_id *id) { - byt_rt5640_custom_map = (unsigned long)id->driver_data; + byt_rt5640_quirk = (unsigned long)id->driver_data; return 1; } @@ -129,7 +133,7 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) } dmi_check_system(byt_rt5640_quirk_table); - switch (byt_rt5640_custom_map) { + switch (BYT_RT5640_MAP(byt_rt5640_quirk)) { case BYT_RT5640_IN1_MAP: custom_map = byt_rt5640_intmic_in1_map; num_routes = ARRAY_SIZE(byt_rt5640_intmic_in1_map); @@ -143,6 +147,12 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) if (ret) return ret; + if (byt_rt5640_quirk & BYT_RT5640_DMIC_EN) { + ret = rt5640_dmic_enable(codec, 0, 0); + if (ret) + return ret; + } + snd_soc_dapm_ignore_suspend(dapm, "HPOL"); snd_soc_dapm_ignore_suspend(dapm, "HPOR"); From c05a11f7b8b5bc67f2c9f726c52b59f67b1bfe7d Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 30 Sep 2014 16:52:15 -0300 Subject: [PATCH 216/251] ASoC: fsl: Do not force codecs selection by SND_SOC_FSL_ASOC_CARD The wm8962 driver uses the input subsystem, but it is selected by SND_SOC_FSL_ASOC_CARD, which can be built with CONFIG_INPUT disabled, resulting in this link error: ERROR: "input_event" [sound/soc/codecs/snd-soc-wm8962.ko] undefined! ERROR: "input_register_device" [sound/soc/codecs/snd-soc-wm8962.ko] undefined! ERROR: "devm_input_allocate_device" [sound/soc/codecs/snd-soc-wm8962.ko] undefined! Do not force the selection of the codecs by SND_SOC_FSL_ASOC_CARD to avoid such problem. Reported-by: Arnd Bergmann Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown --- sound/soc/fsl/Kconfig | 3 --- 1 file changed, 3 deletions(-) diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 7c1da8ede975..0f23d1ae5be7 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -289,9 +289,6 @@ config SND_SOC_FSL_ASOC_CARD select SND_SOC_FSL_ESAI select SND_SOC_FSL_SAI select SND_SOC_FSL_SSI - select SND_SOC_CS42XX8_I2C - select SND_SOC_SGTL5000 - select SND_SOC_WM8962 help ALSA SoC Audio support with ASRC feature for Freescale SoCs that have ESAI/SAI/SSI and connect with external CODECs such as WM8962, CS42888 From f3fa1bbd836a7d6efb2abd506ed8e24096f39062 Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Fri, 19 Sep 2014 19:15:45 +0800 Subject: [PATCH 217/251] ASoC: rt5645: Add headset detect function Add headset detect function Signed-off-by: Oder Chiou Signed-off-by: Mark Brown --- include/sound/rt5645.h | 3 ++ sound/soc/codecs/rt5645.c | 99 +++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/rt5645.h | 5 ++ 3 files changed, 107 insertions(+) diff --git a/include/sound/rt5645.h b/include/sound/rt5645.h index 1de744c242f6..a5352712194b 100644 --- a/include/sound/rt5645.h +++ b/include/sound/rt5645.h @@ -20,6 +20,9 @@ struct rt5645_platform_data { /* 0 = IN2N; 1 = GPIO5; 2 = GPIO11 */ unsigned int dmic2_data_pin; /* 0 = IN2P; 1 = GPIO6; 2 = GPIO10; 3 = GPIO12 */ + + unsigned int hp_det_gpio; + bool gpio_hp_det_active_high; }; #endif diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index a7762d0a623e..3fb83bf09768 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -2103,6 +2104,77 @@ static int rt5645_set_bias_level(struct snd_soc_codec *codec, return 0; } +static int rt5645_jack_detect(struct snd_soc_codec *codec, + struct snd_soc_jack *jack) +{ + struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); + int gpio_state, jack_type = 0; + unsigned int val; + + gpio_state = gpio_get_value(rt5645->pdata.hp_det_gpio); + + dev_dbg(codec->dev, "gpio = %d(%d)\n", rt5645->pdata.hp_det_gpio, + gpio_state); + + if ((rt5645->pdata.gpio_hp_det_active_high && gpio_state) || + (!rt5645->pdata.gpio_hp_det_active_high && !gpio_state)) { + snd_soc_dapm_force_enable_pin(&codec->dapm, "micbias1"); + snd_soc_dapm_force_enable_pin(&codec->dapm, "micbias2"); + snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO2"); + snd_soc_dapm_force_enable_pin(&codec->dapm, "Mic Det Power"); + snd_soc_dapm_sync(&codec->dapm); + + snd_soc_write(codec, RT5645_IN1_CTRL1, 0x0006); + snd_soc_write(codec, RT5645_JD_CTRL3, 0x00b0); + + snd_soc_update_bits(codec, RT5645_IN1_CTRL2, + RT5645_CBJ_MN_JD, 0); + snd_soc_update_bits(codec, RT5645_IN1_CTRL2, + RT5645_CBJ_MN_JD, RT5645_CBJ_MN_JD); + + msleep(400); + val = snd_soc_read(codec, RT5645_IN1_CTRL3) & 0x7; + dev_dbg(codec->dev, "val = %d\n", val); + + if (val == 1 || val == 2) + jack_type = SND_JACK_HEADSET; + else + jack_type = SND_JACK_HEADPHONE; + + snd_soc_dapm_disable_pin(&codec->dapm, "micbias1"); + snd_soc_dapm_disable_pin(&codec->dapm, "micbias2"); + snd_soc_dapm_disable_pin(&codec->dapm, "LDO2"); + snd_soc_dapm_disable_pin(&codec->dapm, "Mic Det Power"); + snd_soc_dapm_sync(&codec->dapm); + } + + snd_soc_jack_report(rt5645->jack, jack_type, SND_JACK_HEADSET); + + return 0; +} + +int rt5645_set_jack_detect(struct snd_soc_codec *codec, + struct snd_soc_jack *jack) +{ + struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); + + rt5645->jack = jack; + + rt5645_jack_detect(codec, rt5645->jack); + + return 0; +} +EXPORT_SYMBOL_GPL(rt5645_set_jack_detect); + +static irqreturn_t rt5645_irq(int irq, void *data) +{ + struct rt5645_priv *rt5645 = data; + + rt5645_jack_detect(rt5645->codec, rt5645->jack); + + return IRQ_HANDLED; +} + static int rt5645_probe(struct snd_soc_codec *codec) { struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); @@ -2250,6 +2322,7 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, if (rt5645 == NULL) return -ENOMEM; + rt5645->i2c = i2c; i2c_set_clientdata(i2c, rt5645); if (pdata) @@ -2345,12 +2418,38 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, } + if (rt5645->i2c->irq) { + ret = request_threaded_irq(rt5645->i2c->irq, NULL, rt5645_irq, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING + | IRQF_ONESHOT, "rt5645", rt5645); + if (ret) + dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret); + } + + if (gpio_is_valid(rt5645->pdata.hp_det_gpio)) { + ret = gpio_request(rt5645->pdata.hp_det_gpio, "rt5645"); + if (ret) + dev_err(&i2c->dev, "Fail gpio_request hp_det_gpio\n"); + + ret = gpio_direction_input(rt5645->pdata.hp_det_gpio); + if (ret) + dev_err(&i2c->dev, "Fail gpio_direction hp_det_gpio\n"); + } + return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5645, rt5645_dai, ARRAY_SIZE(rt5645_dai)); } static int rt5645_i2c_remove(struct i2c_client *i2c) { + struct rt5645_priv *rt5645 = i2c_get_clientdata(i2c); + + if (i2c->irq) + free_irq(i2c->irq, rt5645); + + if (gpio_is_valid(rt5645->pdata.hp_det_gpio)) + gpio_free(rt5645->pdata.hp_det_gpio); + snd_soc_unregister_codec(&i2c->dev); return 0; diff --git a/sound/soc/codecs/rt5645.h b/sound/soc/codecs/rt5645.h index 355b7e9eefab..50c62c5668ea 100644 --- a/sound/soc/codecs/rt5645.h +++ b/sound/soc/codecs/rt5645.h @@ -2166,6 +2166,8 @@ struct rt5645_priv { struct snd_soc_codec *codec; struct rt5645_platform_data pdata; struct regmap *regmap; + struct i2c_client *i2c; + struct snd_soc_jack *jack; int sysclk; int sysclk_src; @@ -2178,4 +2180,7 @@ struct rt5645_priv { int pll_out; }; +int rt5645_set_jack_detect(struct snd_soc_codec *codec, + struct snd_soc_jack *jack); + #endif /* __RT5645_H__ */ From 24221dcc8be736a2b0b83ecaeb60b99bd7e9334c Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Thu, 2 Oct 2014 13:29:08 +0300 Subject: [PATCH 218/251] ASoC: Intel: byt-rt5640: Add quirk for Dell Venue 8 Pro tablet It was found with help of Jan-Michael Brummer that Dell Venue 8 Pro tablet has a digital microphone connected to DMIC2 interface of the RT564x. This patch adds a DAPM route to DMIC2 and a quirk using it for that tablet. Signed-off-by: Jarkko Nikula Reported-by: Jan-Michael Brummer Signed-off-by: Mark Brown --- sound/soc/intel/byt-rt5640.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/sound/soc/intel/byt-rt5640.c b/sound/soc/intel/byt-rt5640.c index 8392c160d9e2..a9619b4201f9 100644 --- a/sound/soc/intel/byt-rt5640.c +++ b/sound/soc/intel/byt-rt5640.c @@ -49,6 +49,10 @@ static const struct snd_soc_dapm_route byt_rt5640_intmic_dmic1_map[] = { {"DMIC1", NULL, "Internal Mic"}, }; +static const struct snd_soc_dapm_route byt_rt5640_intmic_dmic2_map[] = { + {"DMIC2", NULL, "Internal Mic"}, +}; + static const struct snd_soc_dapm_route byt_rt5640_intmic_in1_map[] = { {"Internal Mic", NULL, "MICBIAS1"}, {"IN1P", NULL, "Internal Mic"}, @@ -56,6 +60,7 @@ static const struct snd_soc_dapm_route byt_rt5640_intmic_in1_map[] = { enum { BYT_RT5640_DMIC1_MAP, + BYT_RT5640_DMIC2_MAP, BYT_RT5640_IN1_MAP, }; @@ -111,6 +116,15 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { }, .driver_data = (unsigned long *)BYT_RT5640_IN1_MAP, }, + { + .callback = byt_rt5640_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "DellInc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Venue 8 Pro 5830"), + }, + .driver_data = (unsigned long *)(BYT_RT5640_DMIC2_MAP | + BYT_RT5640_DMIC_EN), + }, {} }; @@ -138,6 +152,10 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) custom_map = byt_rt5640_intmic_in1_map; num_routes = ARRAY_SIZE(byt_rt5640_intmic_in1_map); break; + case BYT_RT5640_DMIC2_MAP: + custom_map = byt_rt5640_intmic_dmic2_map; + num_routes = ARRAY_SIZE(byt_rt5640_intmic_dmic2_map); + break; default: custom_map = byt_rt5640_intmic_dmic1_map; num_routes = ARRAY_SIZE(byt_rt5640_intmic_dmic1_map); From c47a39a6806d756c34eb01b1081866845fb76dc3 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Thu, 2 Oct 2014 13:29:09 +0300 Subject: [PATCH 219/251] ASoC: Intel: byt-rt5640: Set card as fully routed Although it's not known does current version of byt-rt5640 cover all possible variants it is better to set the fully_routed flag on in order to disable unused codecs pins in known machines and get regression from machines that use different routing than the default one. Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/intel/byt-rt5640.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/intel/byt-rt5640.c b/sound/soc/intel/byt-rt5640.c index a9619b4201f9..88ad57fc58b2 100644 --- a/sound/soc/intel/byt-rt5640.c +++ b/sound/soc/intel/byt-rt5640.c @@ -209,6 +209,7 @@ static struct snd_soc_card byt_rt5640_card = { .num_dapm_widgets = ARRAY_SIZE(byt_rt5640_widgets), .dapm_routes = byt_rt5640_audio_map, .num_dapm_routes = ARRAY_SIZE(byt_rt5640_audio_map), + .fully_routed = true, }; static int byt_rt5640_probe(struct platform_device *pdev) From be1aa3ea1f4179cbc84c57d3b1128c49515910ac Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 2 Oct 2014 09:28:00 +0200 Subject: [PATCH 220/251] ASoC: tas2552: Fix compilation warning for !PM_RUNTIME The tas2552_sw_shutdown() function is only used by runtime suspend support, so only build it when necessary. Signed-off-by: Thierry Reding Signed-off-by: Mark Brown --- sound/soc/codecs/tas2552.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c index 1ed57a7e57b6..f039dc825971 100644 --- a/sound/soc/codecs/tas2552.c +++ b/sound/soc/codecs/tas2552.c @@ -115,6 +115,7 @@ static const struct snd_soc_dapm_route tas2552_audio_map[] = { {"ClassD", NULL, "PLL"}, }; +#ifdef CONFIG_PM_RUNTIME static void tas2552_sw_shutdown(struct tas2552_data *tas_data, int sw_shutdown) { u8 cfg1_reg; @@ -127,6 +128,7 @@ static void tas2552_sw_shutdown(struct tas2552_data *tas_data, int sw_shutdown) snd_soc_update_bits(tas_data->codec, TAS2552_CFG_1, TAS2552_SWS_MASK, cfg1_reg); } +#endif static int tas2552_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, From 81f3dfe1908011ee12760ce4d75451e7446dff80 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 2 Oct 2014 09:27:03 +0200 Subject: [PATCH 221/251] ASoC: rt286: Fix compilation warning for !PM The rt286_index_sync() function is only called in the resume path. If PM is disabled it becomes unused and shouldn't be built either. Signed-off-by: Thierry Reding Signed-off-by: Mark Brown --- sound/soc/codecs/rt286.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c index e4f6102efc1a..2bb5a27c70f4 100644 --- a/sound/soc/codecs/rt286.c +++ b/sound/soc/codecs/rt286.c @@ -270,6 +270,7 @@ static int rt286_hw_read(void *context, unsigned int reg, unsigned int *value) return 0; } +#ifdef CONFIG_PM static void rt286_index_sync(struct snd_soc_codec *codec) { struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec); @@ -280,6 +281,7 @@ static void rt286_index_sync(struct snd_soc_codec *codec) rt286->index_cache[i].def); } } +#endif static int rt286_support_power_controls[] = { RT286_DAC_OUT1, From 7c168d5f8bda5716e1a49040b901f26a3002517d Mon Sep 17 00:00:00 2001 From: Anatol Pomozov Date: Wed, 1 Oct 2014 10:15:57 -0700 Subject: [PATCH 222/251] ASoC: ssm4567: Remove duplicated else-if branch Signed-off-by: Anatol Pomozov Acked-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/ssm4567.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/codecs/ssm4567.c b/sound/soc/codecs/ssm4567.c index 1dadacb94efc..4b5c17f8507e 100644 --- a/sound/soc/codecs/ssm4567.c +++ b/sound/soc/codecs/ssm4567.c @@ -173,8 +173,6 @@ static int ssm4567_hw_params(struct snd_pcm_substream *substream, dacfs = SSM4567_DAC_FS_32000_48000; else if (rate >= 64000 && rate <= 96000) dacfs = SSM4567_DAC_FS_64000_96000; - else if (rate >= 64000 && rate <= 96000) - dacfs = SSM4567_DAC_FS_64000_96000; else if (rate >= 128000 && rate <= 192000) dacfs = SSM4567_DAC_FS_128000_192000; else From 3fe240326cc395c66eda0518b1945ea505afd1fc Mon Sep 17 00:00:00 2001 From: Dylan Reid Date: Wed, 1 Oct 2014 14:25:20 -0700 Subject: [PATCH 223/251] ASoC: simple-card: Add mic and hp detect gpios. Allow Headphone and Microphone jack detect gpios to be specified in device tree. This will allow a few systems including rk3288_max98090 to use simple-card instead of having their own board file. Signed-off-by: Dylan Reid Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/simple-card.txt | 4 + sound/soc/generic/simple-card.c | 73 +++++++++++++++++++ 2 files changed, 77 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/simple-card.txt b/Documentation/devicetree/bindings/sound/simple-card.txt index c2e9841dfce4..72d94b7aa5f5 100644 --- a/Documentation/devicetree/bindings/sound/simple-card.txt +++ b/Documentation/devicetree/bindings/sound/simple-card.txt @@ -17,6 +17,10 @@ Optional properties: source. - simple-audio-card,mclk-fs : Multiplication factor between stream rate and codec mclk. +- simple-audio-card,hp_det_gpio : Reference to GPIO that signals when + headphones are attached. +- simple-audio-card,mic_det_gpio : Reference to GPIO that signals when + a microphone is attached. Optional subnodes: diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 709ce67849c8..fcb431fe20b4 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -10,10 +10,13 @@ */ #include #include +#include #include #include +#include #include #include +#include #include #include #include @@ -25,6 +28,8 @@ struct simple_card_data { struct asoc_simple_dai codec_dai; } *dai_props; unsigned int mclk_fs; + int gpio_hp_det; + int gpio_mic_det; struct snd_soc_dai_link dai_link[]; /* dynamically allocated */ }; @@ -54,6 +59,32 @@ static struct snd_soc_ops asoc_simple_card_ops = { .hw_params = asoc_simple_card_hw_params, }; +static struct snd_soc_jack simple_card_hp_jack; +static struct snd_soc_jack_pin simple_card_hp_jack_pins[] = { + { + .pin = "Headphones", + .mask = SND_JACK_HEADPHONE, + }, +}; +static struct snd_soc_jack_gpio simple_card_hp_jack_gpio = { + .name = "Headphone detection", + .report = SND_JACK_HEADPHONE, + .debounce_time = 150, +}; + +static struct snd_soc_jack simple_card_mic_jack; +static struct snd_soc_jack_pin simple_card_mic_jack_pins[] = { + { + .pin = "Mic Jack", + .mask = SND_JACK_MICROPHONE, + }, +}; +static struct snd_soc_jack_gpio simple_card_mic_jack_gpio = { + .name = "Mic detection", + .report = SND_JACK_MICROPHONE, + .debounce_time = 150, +}; + static int __asoc_simple_card_dai_init(struct snd_soc_dai *dai, struct asoc_simple_dai *set) { @@ -109,6 +140,28 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) if (ret < 0) return ret; + if (gpio_is_valid(priv->gpio_hp_det)) { + snd_soc_jack_new(codec->codec, "Headphones", SND_JACK_HEADPHONE, + &simple_card_hp_jack); + snd_soc_jack_add_pins(&simple_card_hp_jack, + ARRAY_SIZE(simple_card_hp_jack_pins), + simple_card_hp_jack_pins); + + simple_card_hp_jack_gpio.gpio = priv->gpio_hp_det; + snd_soc_jack_add_gpios(&simple_card_hp_jack, 1, + &simple_card_hp_jack_gpio); + } + + if (gpio_is_valid(priv->gpio_mic_det)) { + snd_soc_jack_new(codec->codec, "Mic Jack", SND_JACK_MICROPHONE, + &simple_card_mic_jack); + snd_soc_jack_add_pins(&simple_card_mic_jack, + ARRAY_SIZE(simple_card_mic_jack_pins), + simple_card_mic_jack_pins); + simple_card_mic_jack_gpio.gpio = priv->gpio_mic_det; + snd_soc_jack_add_gpios(&simple_card_mic_jack, 1, + &simple_card_mic_jack_gpio); + } return 0; } @@ -383,6 +436,16 @@ static int asoc_simple_card_parse_of(struct device_node *node, return ret; } + priv->gpio_hp_det = of_get_named_gpio(node, + "simple-audio-card,hp-det-gpio", 0); + if (priv->gpio_hp_det == -EPROBE_DEFER) + return -EPROBE_DEFER; + + priv->gpio_mic_det = of_get_named_gpio(node, + "simple-audio-card,mic-det-gpio", 0); + if (priv->gpio_mic_det == -EPROBE_DEFER) + return -EPROBE_DEFER; + if (!priv->snd_card.name) priv->snd_card.name = priv->snd_card.dai_link->name; @@ -502,6 +565,16 @@ err: static int asoc_simple_card_remove(struct platform_device *pdev) { + struct snd_soc_card *card = platform_get_drvdata(pdev); + struct simple_card_data *priv = snd_soc_card_get_drvdata(card); + + if (gpio_is_valid(priv->gpio_hp_det)) + snd_soc_jack_free_gpios(&simple_card_hp_jack, 1, + &simple_card_hp_jack_gpio); + if (gpio_is_valid(priv->gpio_mic_det)) + snd_soc_jack_free_gpios(&simple_card_mic_jack, 1, + &simple_card_mic_jack_gpio); + return asoc_simple_card_unref(pdev); } From 5dc0158a27f65e7efaa6e3cc496d93b4c4c65d19 Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Fri, 19 Sep 2014 16:46:05 +0530 Subject: [PATCH 224/251] ASoC: Export dapm_kcontrol_get_value The DSP driver needs to know widget control value in its event handler for widgets like mixers. This is required in the subsequent patches Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- include/sound/soc-dapm.h | 1 + sound/soc/soc-dapm.c | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index aac04ff84eea..6ae0a1952ad7 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -432,6 +432,7 @@ int snd_soc_dapm_force_enable_pin_unlocked(struct snd_soc_dapm_context *dapm, int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm, const char *pin); void snd_soc_dapm_auto_nc_pins(struct snd_soc_card *card); +unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol); /* Mostly internal - should not normally be used */ void dapm_mark_io_dirty(struct snd_soc_dapm_context *dapm); diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 8348352dc2c6..08c79f09034f 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -326,12 +326,13 @@ static struct list_head *dapm_kcontrol_get_path_list( list_for_each_entry(path, dapm_kcontrol_get_path_list(kcontrol), \ list_kcontrol) -static unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol) +unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol) { struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol); return data->value; } +EXPORT_SYMBOL_GPL(dapm_kcontrol_get_value); static bool dapm_kcontrol_set_value(const struct snd_kcontrol *kcontrol, unsigned int value) From a577483b6906b3d7aba9cc07e383682fc9b65318 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Fri, 3 Oct 2014 09:55:07 +0800 Subject: [PATCH 225/251] ASoC: rt286: Add depends on I2C rt286 use I2C as its I/O. So the driver can only available when I2C is selected. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 8838838e25ed..00ae24bab712 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -464,6 +464,7 @@ config SND_SOC_RL6231 config SND_SOC_RT286 tristate + depends on I2C config SND_SOC_RT5631 tristate From fa558d0130debf847b6b8cd95880a2d7556770ac Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Thu, 2 Oct 2014 16:16:50 -0300 Subject: [PATCH 226/251] ASoC: sgtl5000: Improve the error message on slave mode setting For sgtl5000 to operate in slave mode it can only work in "Synchronous SYS_MCLK input" mode. In this mode only the following rates can be supported: 256*Fs, 384*Fs, 512*Fs. Improve the error message to give a better indication as to why the clocking failed for slave mode: [ 12.515399] sgtl5000 1-000a: PLL not supported in slave mode [ 12.524124] sgtl5000 1-000a: 233 ratio is not supported. SYS_MCLK needs to be 256, 384 or 512 * fs [ 12.535938] sgtl5000 1-000a: ASoC: can't set sgtl5000 hw params: -22 Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown --- sound/soc/codecs/sgtl5000.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index e997d271728d..7ef2687b396f 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -626,6 +626,9 @@ static int sgtl5000_set_clock(struct snd_soc_codec *codec, int frame_rate) } else { dev_err(codec->dev, "PLL not supported in slave mode\n"); + dev_err(codec->dev, "%d ratio is not supported. " + "SYS_MCLK needs to be 256, 384 or 512 * fs\n", + sgtl5000->sysclk / sys_fs); return -EINVAL; } } From 6f4d2b3177ee3352e70c90f327e2dea3809c263e Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Thu, 2 Oct 2014 17:36:05 -0300 Subject: [PATCH 227/251] ASoC: sgtl5000: Do a sanity check on SYS_MCLK According to the sgtl5000 datasheet the valid range for SYS_MCLK is from 8 to 27 MHz. Add a sanity check prior to enabling SYS_MCLK. Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown --- sound/soc/codecs/sgtl5000.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index 7ef2687b396f..3e9db43ed760 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -1445,6 +1445,7 @@ static int sgtl5000_i2c_probe(struct i2c_client *client, { struct sgtl5000_priv *sgtl5000; int ret, reg, rev; + unsigned int mclk; sgtl5000 = devm_kzalloc(&client->dev, sizeof(struct sgtl5000_priv), GFP_KERNEL); @@ -1468,6 +1469,14 @@ static int sgtl5000_i2c_probe(struct i2c_client *client, return ret; } + /* SGTL5000 SYS_MCLK should be between 8 and 27 MHz */ + mclk = clk_get_rate(sgtl5000->mclk); + if (mclk < 8000000 || mclk > 27000000) { + dev_err(&client->dev, "Invalid SYS_CLK frequency: %u.%03uMHz\n", + mclk / 1000000, mclk / 1000 % 1000); + return -EINVAL; + } + ret = clk_prepare_enable(sgtl5000->mclk); if (ret) return ret; From 9766a1cfe5ef2042d1e604e2223629dc43307a21 Mon Sep 17 00:00:00 2001 From: Dylan Reid Date: Thu, 2 Oct 2014 09:42:44 -0700 Subject: [PATCH 228/251] ASoC: tegra: add mic detect gpio to tegra_max98090 Add an optional mic detect gpio property. If specified in device tree there will be a mic jack created for the given gpio. This will be used by the Tegra-based Chromebooks. Signed-off-by: Dylan Reid Reviewed-by: Stephen Warren Signed-off-by: Mark Brown --- .../sound/nvidia,tegra-audio-max98090.txt | 1 + sound/soc/tegra/tegra_max98090.c | 40 +++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-max98090.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-max98090.txt index 9c7c55c71370..c949abc2992f 100644 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-max98090.txt +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-max98090.txt @@ -25,6 +25,7 @@ Required properties: Optional properties: - nvidia,hp-det-gpios : The GPIO that detect headphones are plugged in +- nvidia,mic-det-gpios : The GPIO that detect microphones are plugged in Example: diff --git a/sound/soc/tegra/tegra_max98090.c b/sound/soc/tegra/tegra_max98090.c index b86cd9936ef1..01921d7e73fa 100644 --- a/sound/soc/tegra/tegra_max98090.c +++ b/sound/soc/tegra/tegra_max98090.c @@ -42,6 +42,7 @@ struct tegra_max98090 { struct tegra_asoc_utils_data util_data; int gpio_hp_det; + int gpio_mic_det; }; static int tegra_max98090_asoc_hw_params(struct snd_pcm_substream *substream, @@ -112,6 +113,22 @@ static struct snd_soc_jack_gpio tegra_max98090_hp_jack_gpio = { .invert = 1, }; +static struct snd_soc_jack tegra_max98090_mic_jack; + +static struct snd_soc_jack_pin tegra_max98090_mic_jack_pins[] = { + { + .pin = "Mic Jack", + .mask = SND_JACK_MICROPHONE, + }, +}; + +static struct snd_soc_jack_gpio tegra_max98090_mic_jack_gpio = { + .name = "Mic detection", + .report = SND_JACK_MICROPHONE, + .debounce_time = 150, + .invert = 1, +}; + static const struct snd_soc_dapm_widget tegra_max98090_dapm_widgets[] = { SND_SOC_DAPM_HP("Headphones", NULL), SND_SOC_DAPM_SPK("Speakers", NULL), @@ -141,6 +158,19 @@ static int tegra_max98090_asoc_init(struct snd_soc_pcm_runtime *rtd) &tegra_max98090_hp_jack_gpio); } + if (gpio_is_valid(machine->gpio_mic_det)) { + snd_soc_jack_new(codec, "Mic Jack", SND_JACK_MICROPHONE, + &tegra_max98090_mic_jack); + snd_soc_jack_add_pins(&tegra_max98090_mic_jack, + ARRAY_SIZE(tegra_max98090_mic_jack_pins), + tegra_max98090_mic_jack_pins); + + tegra_max98090_mic_jack_gpio.gpio = machine->gpio_mic_det; + snd_soc_jack_add_gpios(&tegra_max98090_mic_jack, + 1, + &tegra_max98090_mic_jack_gpio); + } + return 0; } @@ -153,6 +183,11 @@ static int tegra_max98090_card_remove(struct snd_soc_card *card) &tegra_max98090_hp_jack_gpio); } + if (gpio_is_valid(machine->gpio_mic_det)) { + snd_soc_jack_free_gpios(&tegra_max98090_mic_jack, 1, + &tegra_max98090_mic_jack_gpio); + } + return 0; } @@ -201,6 +236,11 @@ static int tegra_max98090_probe(struct platform_device *pdev) if (machine->gpio_hp_det == -EPROBE_DEFER) return -EPROBE_DEFER; + machine->gpio_mic_det = + of_get_named_gpio(np, "nvidia,mic-det-gpios", 0); + if (machine->gpio_mic_det == -EPROBE_DEFER) + return -EPROBE_DEFER; + ret = snd_soc_of_parse_card_name(card, "nvidia,model"); if (ret) goto err; From b2d9de549c30170eed5691d369cf16680e0ce03a Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Fri, 3 Oct 2014 15:32:40 +0300 Subject: [PATCH 229/251] ASoC: dapm: Fix NULL pointer dereference when registering card with widgets Commit 0bd2ac3dae74 ("ASoC: Remove CODEC pointer from snd_soc_dapm_context") introduced regression to snd_soc_dapm_new_controls() when registering a card with card->dapm_widgets set. Call chain is: snd_soc_register_card() -> snd_soc_instantiate_card() -> snd_soc_dapm_new_controls() -> snd_soc_dapm_new_control() Null pointer dereference occurs since card->dapm context doesn't have associated component. Fix this by setting widget codec pointer conditionally. Signed-off-by: Jarkko Nikula Acked-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 1f1e9657481a..231deb220506 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3107,7 +3107,8 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, } w->dapm = dapm; - w->codec = dapm->component->codec; + if (dapm->component) + w->codec = dapm->component->codec; INIT_LIST_HEAD(&w->sources); INIT_LIST_HEAD(&w->sinks); INIT_LIST_HEAD(&w->list); From 31d9f8faf9a54c851e835af489c82f45105a442f Mon Sep 17 00:00:00 2001 From: Dmitry Lavnikevich Date: Fri, 3 Oct 2014 16:18:56 +0300 Subject: [PATCH 230/251] ASoC: tlv320aic3x: fix PLL D configuration Current caching implementation during regcache_sync() call bypasses all register writes of values that are already known as default (regmap reg_defaults). Same time in TLV320AIC3x codecs register 5 (AIC3X_PLL_PROGC_REG) write should be immediately followed by register 6 write (AIC3X_PLL_PROGD_REG) even if it was not changed. Otherwise both registers will not be written. This brings to issue that appears particulary in case of 44.1kHz playback with 19.2MHz master clock. In this case AIC3X_PLL_PROGC_REG is 0x6e while AIC3X_PLL_PROGD_REG is 0x0 (same as register default). Thus AIC3X_PLL_PROGC_REG also remains not written and we get wrong playback speed. In this patch snd_soc_read() is used to get cached pll values and snd_soc_write() (unlike regcache_sync() this function doesn't bypasses hardware default values) to write them to registers. Signed-off-by: Dmitry Lavnikevich Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- sound/soc/codecs/tlv320aic3x.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 64f179ee9834..5e8626ae612b 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -1121,6 +1121,7 @@ static int aic3x_regulator_event(struct notifier_block *nb, static int aic3x_set_power(struct snd_soc_codec *codec, int power) { struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); + unsigned int pll_c, pll_d; int ret; if (power) { @@ -1138,6 +1139,18 @@ static int aic3x_set_power(struct snd_soc_codec *codec, int power) /* Sync reg_cache with the hardware */ regcache_cache_only(aic3x->regmap, false); regcache_sync(aic3x->regmap); + + /* Rewrite paired PLL D registers in case cached sync skipped + * writing one of them and thus caused other one also not + * being written + */ + pll_c = snd_soc_read(codec, AIC3X_PLL_PROGC_REG); + pll_d = snd_soc_read(codec, AIC3X_PLL_PROGD_REG); + if (pll_c == aic3x_reg[AIC3X_PLL_PROGC_REG].def || + pll_d == aic3x_reg[AIC3X_PLL_PROGD_REG].def) { + snd_soc_write(codec, AIC3X_PLL_PROGC_REG, pll_c); + snd_soc_write(codec, AIC3X_PLL_PROGD_REG, pll_d); + } } else { /* * Do soft reset to this codec instance in order to clear From 58a9014ae6422325f12d54b5dbb95531009ab70f Mon Sep 17 00:00:00 2001 From: Tomeu Vizoso Date: Fri, 3 Oct 2014 17:54:13 +0200 Subject: [PATCH 231/251] ASoC: fsl_spdif: Remove unused includes of linux/clk-private.h Signed-off-by: Tomeu Vizoso Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_spdif.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index 70acfe4a9bd5..5bda3239b2a0 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -15,7 +15,6 @@ #include #include -#include #include #include #include From 872bbb3aa35c2c73dee6ca13aeb5448b38b457ad Mon Sep 17 00:00:00 2001 From: Dylan Reid Date: Fri, 3 Oct 2014 10:06:08 -0700 Subject: [PATCH 232/251] ASoC: simple-card: Fix detect gpio documentation. The device tree property uses '-' not '_'. Signed-off-by: Dylan Reid Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/simple-card.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/simple-card.txt b/Documentation/devicetree/bindings/sound/simple-card.txt index 72d94b7aa5f5..c3cba600bf11 100644 --- a/Documentation/devicetree/bindings/sound/simple-card.txt +++ b/Documentation/devicetree/bindings/sound/simple-card.txt @@ -17,9 +17,9 @@ Optional properties: source. - simple-audio-card,mclk-fs : Multiplication factor between stream rate and codec mclk. -- simple-audio-card,hp_det_gpio : Reference to GPIO that signals when +- simple-audio-card,hp-det-gpio : Reference to GPIO that signals when headphones are attached. -- simple-audio-card,mic_det_gpio : Reference to GPIO that signals when +- simple-audio-card,mic-det-gpio : Reference to GPIO that signals when a microphone is attached. Optional subnodes: From cd9241e44af3d49977c39ddadbefbb719e2a4baf Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Sat, 4 Oct 2014 02:17:08 +0900 Subject: [PATCH 233/251] ASoC: da732x: Remove unnecessary KERN_ERR in pr_err() This patch remove unnecessary KERN_ERR in pr_err(). Signed-off-by: Masanari Iida Signed-off-by: Mark Brown --- sound/soc/codecs/da732x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/da732x.c b/sound/soc/codecs/da732x.c index 2fae31cb0067..fa15fa1c0516 100644 --- a/sound/soc/codecs/da732x.c +++ b/sound/soc/codecs/da732x.c @@ -217,7 +217,7 @@ static void da732x_set_charge_pump(struct snd_soc_codec *codec, int state) snd_soc_write(codec, DA732X_REG_CP_CTRL1, DA723X_CP_DIS); break; default: - pr_err(KERN_ERR "Wrong charge pump state\n"); + pr_err("Wrong charge pump state\n"); break; } } From 5ea5570579739a8f80231d884e2979e25d3c0992 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sat, 4 Oct 2014 11:43:41 -0300 Subject: [PATCH 234/251] ASoC: fsl_esai doc: Add "fsl,vf610-esai" as compatible string Since commit b21cc2f5fdfe224 ("ASoC: esai: Add VF610+ compatibles support.") the fsl_esai driver also accepts the "fsl,vf610-esai" compatible string. Update the documentation accordingly. Signed-off-by: Fabio Estevam Acked-by: Nicolin Chen Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/fsl,esai.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/sound/fsl,esai.txt b/Documentation/devicetree/bindings/sound/fsl,esai.txt index aeb8c4a0b88d..52f5b6bf3e8e 100644 --- a/Documentation/devicetree/bindings/sound/fsl,esai.txt +++ b/Documentation/devicetree/bindings/sound/fsl,esai.txt @@ -7,7 +7,8 @@ other DSPs. It has up to six transmitters and four receivers. Required properties: - - compatible : Compatible list, must contain "fsl,imx35-esai". + - compatible : Compatible list, must contain "fsl,imx35-esai" or + "fsl,vf610-esai" - reg : Offset and length of the register set for the device. From bb78cdd4914df22bdf233a9cd4b554a1f6e39804 Mon Sep 17 00:00:00 2001 From: Fengguang Wu Date: Sat, 4 Oct 2014 19:09:33 +0100 Subject: [PATCH 235/251] ASoC: Intel: byt-rt5640: fix coccinelle warnings sound/soc/intel/byt-rt5640.c:140:2-3: Unneeded semicolon Removes unneeded semicolon. Generated by: scripts/coccinelle/misc/semicolon.cocci Signed-off-by: Fengguang Wu Signed-off-by: Mark Brown --- sound/soc/intel/byt-rt5640.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/byt-rt5640.c b/sound/soc/intel/byt-rt5640.c index 88ad57fc58b2..e03abdf21c1b 100644 --- a/sound/soc/intel/byt-rt5640.c +++ b/sound/soc/intel/byt-rt5640.c @@ -159,7 +159,7 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) default: custom_map = byt_rt5640_intmic_dmic1_map; num_routes = ARRAY_SIZE(byt_rt5640_intmic_dmic1_map); - }; + } ret = snd_soc_dapm_add_routes(dapm, custom_map, num_routes); if (ret) From 522a7fa883e04725806308a5b663ce1f570e5870 Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Tue, 7 Oct 2014 10:18:40 +0200 Subject: [PATCH 236/251] ALSA: hda - Add inverted internal mic for Asus Aspire 4830T Alsa-info at https://launchpadlibrarian.net/186697318/alsa-info.txt.37fYWkaJRc Reported-by: Tomas Nilsson Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_conexant.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index d2eaf8bc10e1..71e4bad06345 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -752,6 +752,7 @@ static const struct hda_model_fixup cxt5051_fixup_models[] = { static const struct snd_pci_quirk cxt5066_fixups[] = { SND_PCI_QUIRK(0x1025, 0x0543, "Acer Aspire One 522", CXT_FIXUP_STEREO_DMIC), SND_PCI_QUIRK(0x1025, 0x054c, "Acer Aspire 3830TG", CXT_FIXUP_ASPIRE_DMIC), + SND_PCI_QUIRK(0x1025, 0x054f, "Acer Aspire 4830T", CXT_FIXUP_ASPIRE_DMIC), SND_PCI_QUIRK(0x1043, 0x138d, "Asus", CXT_FIXUP_HEADPHONE_MIC_PIN), SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT_FIXUP_OLPC_XO), SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410), From a33cc48d28b4ff58e2627e2613f15c63754dc376 Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Tue, 7 Oct 2014 10:18:41 +0200 Subject: [PATCH 237/251] ALSA: hda - Add Inverted Internal mic for Samsung Ativ book 9 (NP900X3G) In this case, it looks like the right channel records noise rather than the inverted signal, but the simplest way is to just call it "Inverted Internal Mic", which will cause it to be muted by default. Alsa-info at http://www.alsa-project.org/db/?f=064f0b536a1b068efd30d58c2641b5ec2348f059 BugLink: https://bugs.launchpad.net/bugs/1316518 Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index a109fdb085f9..82ea50ec978f 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4925,6 +4925,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x104d, 0x9099, "Sony VAIO S13", ALC275_FIXUP_SONY_DISABLE_AAMIX), SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook", ALC269_FIXUP_LIFEBOOK), SND_PCI_QUIRK(0x10cf, 0x1845, "Lifebook U904", ALC269_FIXUP_LIFEBOOK_EXTMIC), + SND_PCI_QUIRK(0x144d, 0xc109, "Samsung Ativ book 9 (NP900X3G)", ALC269_FIXUP_INV_DMIC), SND_PCI_QUIRK(0x1458, 0xfa53, "Gigabyte BXBT-2807", ALC283_FIXUP_BXBT2807_MIC), SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x17aa, 0x215e, "Thinkpad L512", ALC269_FIXUP_SKU_IGNORE), From 9d36a7dc4df6ef77cfc02ba78a10bc8577c2663f Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Tue, 7 Oct 2014 10:18:42 +0200 Subject: [PATCH 238/251] ALSA: hda - Make the inv dmic handling for Realtek use generic parser From what I can see, the generic parser is now good enough to handle Realtek's inverted dmic handling, so let's remove the special handling and use the generic parser instead. Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 158 ++-------------------------------- 1 file changed, 8 insertions(+), 150 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 82ea50ec978f..69d1236365e0 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -90,11 +90,6 @@ struct alc_spec { struct alc_customize_define cdefine; unsigned int parse_flags; /* flag for snd_hda_parse_pin_defcfg() */ - /* inverted dmic fix */ - unsigned int inv_dmic_fixup:1; /* has inverted digital-mic workaround */ - unsigned int inv_dmic_muted:1; /* R-ch of inv d-mic is muted? */ - hda_nid_t inv_dmic_pin; - /* mute LED for HP laptops, see alc269_fixup_mic_mute_hook() */ int mute_led_polarity; hda_nid_t mute_led_nid; @@ -625,147 +620,12 @@ static void alc_ssid_check(struct hda_codec *codec, const hda_nid_t *ports) /* */ -static hda_nid_t get_adc_nid(struct hda_codec *codec, int adc_idx, int imux_idx) -{ - struct hda_gen_spec *spec = codec->spec; - if (spec->dyn_adc_switch) - adc_idx = spec->dyn_adc_idx[imux_idx]; - return spec->adc_nids[adc_idx]; -} - -static void alc_inv_dmic_sync_adc(struct hda_codec *codec, int adc_idx) -{ - struct alc_spec *spec = codec->spec; - struct hda_input_mux *imux = &spec->gen.input_mux; - struct nid_path *path; - hda_nid_t nid; - int i, dir, parm; - unsigned int val; - - for (i = 0; i < imux->num_items; i++) { - if (spec->gen.imux_pins[i] == spec->inv_dmic_pin) - break; - } - if (i >= imux->num_items) - return; - - path = snd_hda_get_nid_path(codec, spec->inv_dmic_pin, - get_adc_nid(codec, adc_idx, i)); - val = path->ctls[NID_PATH_MUTE_CTL]; - if (!val) - return; - nid = get_amp_nid_(val); - dir = get_amp_direction_(val); - parm = AC_AMP_SET_RIGHT | - (dir == HDA_OUTPUT ? AC_AMP_SET_OUTPUT : AC_AMP_SET_INPUT); - - /* flush all cached amps at first */ - snd_hda_codec_flush_cache(codec); - - /* we care only right channel */ - val = snd_hda_codec_amp_read(codec, nid, 1, dir, 0); - if (val & 0x80) /* if already muted, we don't need to touch */ - return; - val |= 0x80; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, - parm | val); -} - -/* - * Inverted digital-mic handling - * - * First off, it's a bit tricky. The "Inverted Internal Mic Capture Switch" - * gives the additional mute only to the right channel of the digital mic - * capture stream. This is a workaround for avoiding the almost silence - * by summing the stereo stream from some (known to be ForteMedia) - * digital mic unit. - * - * The logic is to call alc_inv_dmic_sync() after each action (possibly) - * modifying ADC amp. When the mute flag is set, it mutes the R-channel - * without caching so that the cache can still keep the original value. - * The cached value is then restored when the flag is set off or any other - * than d-mic is used as the current input source. - */ -static void alc_inv_dmic_sync(struct hda_codec *codec, bool force) -{ - struct alc_spec *spec = codec->spec; - int src, nums; - - if (!spec->inv_dmic_fixup) - return; - if (!spec->inv_dmic_muted && !force) - return; - nums = spec->gen.dyn_adc_switch ? 1 : spec->gen.num_adc_nids; - for (src = 0; src < nums; src++) { - bool dmic_fixup = false; - - if (spec->inv_dmic_muted && - spec->gen.imux_pins[spec->gen.cur_mux[src]] == spec->inv_dmic_pin) - dmic_fixup = true; - if (!dmic_fixup && !force) - continue; - alc_inv_dmic_sync_adc(codec, src); - } -} - -static void alc_inv_dmic_hook(struct hda_codec *codec, - struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - alc_inv_dmic_sync(codec, false); -} - -static int alc_inv_dmic_sw_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_spec *spec = codec->spec; - - ucontrol->value.integer.value[0] = !spec->inv_dmic_muted; - return 0; -} - -static int alc_inv_dmic_sw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_spec *spec = codec->spec; - unsigned int val = !ucontrol->value.integer.value[0]; - - if (val == spec->inv_dmic_muted) - return 0; - spec->inv_dmic_muted = val; - alc_inv_dmic_sync(codec, true); - return 0; -} - -static const struct snd_kcontrol_new alc_inv_dmic_sw = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Inverted Internal Mic Capture Switch", - .info = snd_ctl_boolean_mono_info, - .get = alc_inv_dmic_sw_get, - .put = alc_inv_dmic_sw_put, -}; - -static int alc_add_inv_dmic_mixer(struct hda_codec *codec, hda_nid_t nid) +static void alc_fixup_inv_dmic(struct hda_codec *codec, + const struct hda_fixup *fix, int action) { struct alc_spec *spec = codec->spec; - if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &alc_inv_dmic_sw)) - return -ENOMEM; - spec->inv_dmic_fixup = 1; - spec->inv_dmic_muted = 0; - spec->inv_dmic_pin = nid; - spec->gen.cap_sync_hook = alc_inv_dmic_hook; - return 0; -} - -/* typically the digital mic is put at node 0x12 */ -static void alc_fixup_inv_dmic_0x12(struct hda_codec *codec, - const struct hda_fixup *fix, int action) -{ - if (action == HDA_FIXUP_ACT_PROBE) - alc_add_inv_dmic_mixer(codec, 0x12); + spec->gen.inv_dmic_split = 1; } @@ -874,7 +734,6 @@ static int alc_resume(struct hda_codec *codec) codec->patch_ops.init(codec); snd_hda_codec_resume_amp(codec); snd_hda_codec_resume_cache(codec); - alc_inv_dmic_sync(codec, true); hda_call_check_power_status(codec, 0x01); return 0; } @@ -2217,7 +2076,7 @@ static const struct hda_fixup alc882_fixups[] = { }, [ALC882_FIXUP_INV_DMIC] = { .type = HDA_FIXUP_FUNC, - .v.func = alc_fixup_inv_dmic_0x12, + .v.func = alc_fixup_inv_dmic, }, [ALC882_FIXUP_NO_PRIMARY_HP] = { .type = HDA_FIXUP_FUNC, @@ -2468,7 +2327,7 @@ static const struct hda_fixup alc262_fixups[] = { }, [ALC262_FIXUP_INV_DMIC] = { .type = HDA_FIXUP_FUNC, - .v.func = alc_fixup_inv_dmic_0x12, + .v.func = alc_fixup_inv_dmic, }, [ALC262_FIXUP_INTEL_BAYLEYBAY] = { .type = HDA_FIXUP_FUNC, @@ -2581,7 +2440,7 @@ enum { static const struct hda_fixup alc268_fixups[] = { [ALC268_FIXUP_INV_DMIC] = { .type = HDA_FIXUP_FUNC, - .v.func = alc_fixup_inv_dmic_0x12, + .v.func = alc_fixup_inv_dmic, }, [ALC268_FIXUP_HP_EAPD] = { .type = HDA_FIXUP_VERBS, @@ -3167,7 +3026,6 @@ static int alc269_resume(struct hda_codec *codec) snd_hda_codec_resume_amp(codec); snd_hda_codec_resume_cache(codec); - alc_inv_dmic_sync(codec, true); hda_call_check_power_status(codec, 0x01); /* on some machine, the BIOS will clear the codec gpio data when enter @@ -4520,7 +4378,7 @@ static const struct hda_fixup alc269_fixups[] = { }, [ALC269_FIXUP_INV_DMIC] = { .type = HDA_FIXUP_FUNC, - .v.func = alc_fixup_inv_dmic_0x12, + .v.func = alc_fixup_inv_dmic, }, [ALC269_FIXUP_NO_SHUTUP] = { .type = HDA_FIXUP_FUNC, @@ -5980,7 +5838,7 @@ static const struct hda_fixup alc662_fixups[] = { }, [ALC662_FIXUP_INV_DMIC] = { .type = HDA_FIXUP_FUNC, - .v.func = alc_fixup_inv_dmic_0x12, + .v.func = alc_fixup_inv_dmic, }, [ALC668_FIXUP_DELL_XPS13] = { .type = HDA_FIXUP_FUNC, From e5092c96c9c28f4d12811edcd02ca8eec16e748e Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Tue, 7 Oct 2014 13:41:24 +0200 Subject: [PATCH 239/251] ASoC: soc-dapm: fix use after free Coverity spotted the following possible use-after-free condition in dapm_create_or_share_mixmux_kcontrol(): If kcontrol is NULL, and (wname_in_long_name && kcname_in_long_name) validates to true, 'name' will be set to an allocated string, and be freed a few lines later via the 'long_name' alias. 'name', however, is used by dev_err() in case snd_ctl_add() fails. Fix this by adding a jump label that frees 'long_name' at the end of the function. Signed-off-by: Daniel Mack Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- sound/soc/soc-dapm.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 2c456a376ade..c61cb9cedbcd 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -592,9 +592,9 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w, int shared; struct snd_kcontrol *kcontrol; bool wname_in_long_name, kcname_in_long_name; - char *long_name; + char *long_name = NULL; const char *name; - int ret; + int ret = 0; prefix = soc_dapm_prefix(dapm); if (prefix) @@ -653,15 +653,17 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w, kcontrol = snd_soc_cnew(&w->kcontrol_news[kci], NULL, name, prefix); - kfree(long_name); - if (!kcontrol) - return -ENOMEM; + if (!kcontrol) { + ret = -ENOMEM; + goto exit_free; + } + kcontrol->private_free = dapm_kcontrol_free; ret = dapm_kcontrol_data_alloc(w, kcontrol); if (ret) { snd_ctl_free_one(kcontrol); - return ret; + goto exit_free; } ret = snd_ctl_add(card, kcontrol); @@ -669,17 +671,18 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w, dev_err(dapm->dev, "ASoC: failed to add widget %s dapm kcontrol %s: %d\n", w->name, name, ret); - return ret; + goto exit_free; } } ret = dapm_kcontrol_add_widget(kcontrol, w); - if (ret) - return ret; + if (ret == 0) + w->kcontrols[kci] = kcontrol; - w->kcontrols[kci] = kcontrol; +exit_free: + kfree(long_name); - return 0; + return ret; } /* create new dapm mixer control */ From decc27b01d584c985c231e73d3b493de6ec07af8 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Tue, 7 Oct 2014 13:41:23 +0200 Subject: [PATCH 240/251] ASoC: core: fix use after free in snd_soc_remove_platform() Coverity spotted an use-after-free condition in snd_soc_remove_platform(). Fix this by moving snd_soc_component_cleanup() after the debug print statement which uses the component's string. Signed-off-by: Daniel Mack Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- sound/soc/soc-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index ae48f1013e80..d877ec57d761 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -4315,10 +4315,10 @@ void snd_soc_remove_platform(struct snd_soc_platform *platform) snd_soc_component_del_unlocked(&platform->component); mutex_unlock(&client_mutex); - snd_soc_component_cleanup(&platform->component); - dev_dbg(platform->dev, "ASoC: Unregistered platform '%s'\n", platform->component.name); + + snd_soc_component_cleanup(&platform->component); } EXPORT_SYMBOL_GPL(snd_soc_remove_platform); From 77eca3cd461da663945eceddf454466a609d8ca4 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Tue, 7 Oct 2014 13:41:25 +0200 Subject: [PATCH 241/251] ASoC: 88pm860x-codec: Fix possibly missing string termination Coverity spotted an issue with strncpy() in pm860x_codec_probe() which does not take the \0 termination byte into account. Fix this by making the buffers one byte larger so the can really accommodate MAX_NAME_LEN bytes long strings. Signed-off-by: Daniel Mack Signed-off-by: Mark Brown --- sound/soc/codecs/88pm860x-codec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c index 4c3b0af39fd8..e88a6b67f781 100644 --- a/sound/soc/codecs/88pm860x-codec.c +++ b/sound/soc/codecs/88pm860x-codec.c @@ -146,7 +146,7 @@ struct pm860x_priv { struct pm860x_det det; int irq[4]; - unsigned char name[4][MAX_NAME_LEN]; + unsigned char name[4][MAX_NAME_LEN+1]; }; /* -9450dB to 0dB in 150dB steps ( mute instead of -9450dB) */ From 897c329bcb2206dd025cdb7ba84831a4f3c872d0 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Tue, 7 Oct 2014 14:25:13 +0200 Subject: [PATCH 242/251] ALSA: usb: caiaq: check for cdev->n_streams > 1 Coverity spotted a possible DIV0 condition when cdev->n_streams is 0. Fix this by making sure the value is > 1 in snd_usb_caiaq_audio_init(). Signed-off-by: Daniel Mack Signed-off-by: Takashi Iwai --- sound/usb/caiaq/audio.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sound/usb/caiaq/audio.c b/sound/usb/caiaq/audio.c index 7103b0908d13..272844746135 100644 --- a/sound/usb/caiaq/audio.c +++ b/sound/usb/caiaq/audio.c @@ -816,6 +816,11 @@ int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *cdev) return -EINVAL; } + if (cdev->n_streams < 2) { + dev_err(dev, "bogus number of streams: %d\n", cdev->n_streams); + return -EINVAL; + } + ret = snd_pcm_new(cdev->chip.card, cdev->product_name, 0, cdev->n_audio_out, cdev->n_audio_in, &cdev->pcm); From 6d16941aee6eb468c5a5cc78ecbaf840f3e16df5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 7 Oct 2014 17:27:02 +0200 Subject: [PATCH 243/251] ALSA: hda - Add dock support for Thinkpad T440 (17aa:2212) There is another Thinkpad T440 with SSID 17aa:2212 that has a dock port. Reported-by: Siwei Luo Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 69d1236365e0..2cc2568af016 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4799,7 +4799,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x220c, "Thinkpad T440s", ALC292_FIXUP_TPT440_DOCK), SND_PCI_QUIRK(0x17aa, 0x220e, "Thinkpad T440p", ALC292_FIXUP_TPT440_DOCK), SND_PCI_QUIRK(0x17aa, 0x2210, "Thinkpad T540p", ALC292_FIXUP_TPT440_DOCK), - SND_PCI_QUIRK(0x17aa, 0x2212, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), + SND_PCI_QUIRK(0x17aa, 0x2212, "Thinkpad T440", ALC292_FIXUP_TPT440_DOCK), SND_PCI_QUIRK(0x17aa, 0x2214, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x17aa, 0x2215, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x17aa, 0x3978, "IdeaPad Y410P", ALC269_FIXUP_NO_SHUTUP), From 5c4c99f32226321e152b1462a1884ff2dfd3b3e2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 7 Oct 2014 18:19:54 +0200 Subject: [PATCH 244/251] ASoC: imx-es8328: Fix missing return code in imx_es8328_probe() An error code was forgotten to be passed in the error path of imx_es8328_probe(). Signed-off-by: Takashi Iwai Signed-off-by: Mark Brown --- sound/soc/fsl/imx-es8328.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/fsl/imx-es8328.c b/sound/soc/fsl/imx-es8328.c index 653e66d150c8..9b8d11d04fbc 100644 --- a/sound/soc/fsl/imx-es8328.c +++ b/sound/soc/fsl/imx-es8328.c @@ -104,6 +104,7 @@ static int imx_es8328_probe(struct platform_device *pdev) if (ext_port > MUX_PORT_MAX || ext_port == 0) { dev_err(dev, "mux-ext-port: hardware only has %d mux ports\n", MUX_PORT_MAX); + ret = -EINVAL; goto fail; } From 2dbab9784db1c0de517922d81394d9ff4a33c544 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 7 Oct 2014 15:09:26 +0200 Subject: [PATCH 245/251] ASoC: simple-card: Initialize headphone and mic GPIO numbers The uninitialized default of 0 for gpio_hp_det and gpio_mic_det doesn't play well with asm-generic's gpio_is_valid(): static inline bool gpio_is_valid(int number) { return number >= 0 && number < ARCH_NR_GPIOS; } Hence on r8a7740/armadillo-legacy: sh-mobile-hdmi sh-mobile-hdmi: SH Mobile HDMI Audio Codec sh-mobile-hdmi sh-mobile-hdmi: ASoC: DAPM unknown pin Headphones sh-mobile-hdmi sh-mobile-hdmi: ASoC: DAPM unknown pin Mic Jack After that the kernel log is spammed ca. 7 times per second with: sh-mobile-hdmi sh-mobile-hdmi: ASoC: DAPM unknown pin Headphones Initialize the GPIO numbers with a negative number (-ENOENT) to fix this. Fixes: 3fe240326cc395c6 ("ASoC: simple-card: Add mic and hp detect gpios.") Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index fcb431fe20b4..d1b7293c133e 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -501,6 +501,9 @@ static int asoc_simple_card_probe(struct platform_device *pdev) priv->snd_card.dai_link = dai_link; priv->snd_card.num_links = num_links; + priv->gpio_hp_det = -ENOENT; + priv->gpio_mic_det = -ENOENT; + /* Get room for the other properties */ priv->dai_props = devm_kzalloc(dev, sizeof(*priv->dai_props) * num_links, From 5e63dfccf34d4dbf21429c4919f33c028ff49991 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Tue, 7 Oct 2014 14:33:46 +0200 Subject: [PATCH 246/251] ASoC: soc-pcm: fix sig_bits determination in soc_pcm_apply_msb() In the SNDRV_PCM_STREAM_CAPTURE branch in soc_pcm_apply_msb(), look at sig_bits of the capture stream, not the playback one. Spotted by coverity. Signed-off-by: Daniel Mack Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- sound/soc/soc-pcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 731fdb5b5f9b..14a3df1ff1ac 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -352,7 +352,7 @@ static void soc_pcm_apply_msb(struct snd_pcm_substream *substream) } else { for (i = 0; i < rtd->num_codecs; i++) { codec_dai = rtd->codec_dais[i]; - if (codec_dai->driver->playback.sig_bits == 0) { + if (codec_dai->driver->capture.sig_bits == 0) { bits = 0; break; } From 960baba41f3cfb0a97bb1f0e720334156b2eff75 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 7 Oct 2014 18:19:53 +0200 Subject: [PATCH 247/251] ASoC: imx-es8328: Fix of_node_put() call with uninitialized object The of_node_put() calls in imx_es8328_probe() may take uninitialized pointers when reached though the early error path. This patch adds the proper NULL initialization for fixing these. Signed-off-by: Takashi Iwai Signed-off-by: Mark Brown --- sound/soc/fsl/imx-es8328.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/fsl/imx-es8328.c b/sound/soc/fsl/imx-es8328.c index 653e66d150c8..d6c55c88a069 100644 --- a/sound/soc/fsl/imx-es8328.c +++ b/sound/soc/fsl/imx-es8328.c @@ -78,7 +78,7 @@ static const struct snd_soc_dapm_widget imx_es8328_dapm_widgets[] = { static int imx_es8328_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; - struct device_node *ssi_np, *codec_np; + struct device_node *ssi_np = NULL, *codec_np = NULL; struct platform_device *ssi_pdev; struct imx_es8328_data *data; u32 int_port, ext_port; From e5b50ada76f44c8742a123813689bff4db062a5a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 8 Oct 2014 12:08:38 +0200 Subject: [PATCH 248/251] ALSA: Allow pass NULL dev for snd_pci_quirk_lookup() Add a NULL check in snd_pci_quirk_lookup() so that NULL can be passed as a pci_dev pointer. This fixes the possible NULL dereferences in HD-audio drivers. Reported-by: Dan Carpenter Signed-off-by: Takashi Iwai --- sound/core/misc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/core/misc.c b/sound/core/misc.c index 30e027ecf4da..f2e8226c88fb 100644 --- a/sound/core/misc.c +++ b/sound/core/misc.c @@ -145,6 +145,8 @@ EXPORT_SYMBOL(snd_pci_quirk_lookup_id); const struct snd_pci_quirk * snd_pci_quirk_lookup(struct pci_dev *pci, const struct snd_pci_quirk *list) { + if (!pci) + return NULL; return snd_pci_quirk_lookup_id(pci->subsystem_vendor, pci->subsystem_device, list); From c497d9f917542a71e1654b31368d18153b6f1987 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 8 Oct 2014 12:14:40 +0200 Subject: [PATCH 249/251] ALSA: hda - Add dock port support to Thinkpad L440 (71aa:501e) Yet another Thinkpad model that has a dock port. Reported-by: Sascha Wilde Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 2cc2568af016..bc86c36b4bfa 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4805,6 +4805,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x3978, "IdeaPad Y410P", ALC269_FIXUP_NO_SHUTUP), SND_PCI_QUIRK(0x17aa, 0x5013, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x17aa, 0x501a, "Thinkpad", ALC283_FIXUP_INT_MIC), + SND_PCI_QUIRK(0x17aa, 0x501e, "Thinkpad L440", ALC292_FIXUP_TPT440_DOCK), SND_PCI_QUIRK(0x17aa, 0x5026, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x17aa, 0x5109, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K), From 528a82b41fda78435976c905546c3329c86bb264 Mon Sep 17 00:00:00 2001 From: Sonny Rao Date: Wed, 8 Oct 2014 00:58:51 -0700 Subject: [PATCH 250/251] ASoC: rockchip-i2s: fix infinite loop in rockchip_snd_txctrl We can get into an infinite loop if the I2S_CLR register fails to clear due to a missing break statement, so add that. Signed-off-by: Sonny Rao Signed-off-by: Mark Brown --- sound/soc/rockchip/rockchip_i2s.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c index 033487c9a164..f373e37f8305 100644 --- a/sound/soc/rockchip/rockchip_i2s.c +++ b/sound/soc/rockchip/rockchip_i2s.c @@ -108,8 +108,10 @@ static void rockchip_snd_txctrl(struct rk_i2s_dev *i2s, int on) while (val) { regmap_read(i2s->regmap, I2S_CLR, &val); retry--; - if (!retry) + if (!retry) { dev_warn(i2s->dev, "fail to clear\n"); + break; + } } } } From a66ae631a3cffb00f441b229a07fa1b4c72e738a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 8 Oct 2014 15:31:18 +0100 Subject: [PATCH 251/251] ASoC: mc13783: Ensure we only try to dereference valid of_nodes Reported-by: Takashi Iwai Signed-off-by: Mark Brown --- sound/soc/codecs/mc13783.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/mc13783.c b/sound/soc/codecs/mc13783.c index 388f90a597fa..71f775aad7c7 100644 --- a/sound/soc/codecs/mc13783.c +++ b/sound/soc/codecs/mc13783.c @@ -765,12 +765,18 @@ static int __init mc13783_codec_probe(struct platform_device *pdev) return -ENOSYS; ret = of_property_read_u32(np, "adc-port", &priv->adc_ssi_port); - if (ret) - goto out; + if (ret) { + of_node_put(np); + return ret; + } ret = of_property_read_u32(np, "dac-port", &priv->dac_ssi_port); - if (ret) - goto out; + if (ret) { + of_node_put(np); + return ret; + } + + of_node_put(np); } dev_set_drvdata(&pdev->dev, priv); @@ -783,8 +789,6 @@ static int __init mc13783_codec_probe(struct platform_device *pdev) ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_mc13783, mc13783_dai_async, ARRAY_SIZE(mc13783_dai_async)); -out: - of_node_put(np); return ret; }