From 8f5f5e0f459d37273f841e3f8da38b4e242c8e94 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Fri, 15 Feb 2013 17:07:35 -0700 Subject: ASoC: tegra_wm8903: assume CONFIG_OF, remove platform data Tegra only supports, and always enables, device tree. Remove all runtime checks for DT support from the driver. This allows removal of the hard-coded Harmony ASoC mapping table, since Harmony only boots with DT now. All board-specific configuration now comes from device tree, so there is no need to have a platform_data structure. Rework the driver to parse the device tree directly into struct tegra_wm8903. Also some slight re-ordering of probe() so that the code more closely resembles other drivers for easier comparison. Inparticular, the GPIO DT parsing and initial programming are moved together for each GPIO. Signed-off-by: Stephen Warren Signed-off-by: Mark Brown --- include/sound/tegra_wm8903.h | 26 -------------------------- 1 file changed, 26 deletions(-) delete mode 100644 include/sound/tegra_wm8903.h (limited to 'include/sound') diff --git a/include/sound/tegra_wm8903.h b/include/sound/tegra_wm8903.h deleted file mode 100644 index 57b202ee97c3..000000000000 --- a/include/sound/tegra_wm8903.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2011 NVIDIA, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * 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. - * - */ - -#ifndef __SOUND_TEGRA_WM38903_H -#define __SOUND_TEGRA_WM38903_H - -struct tegra_wm8903_platform_data { - int gpio_spkr_en; - int gpio_hp_det; - int gpio_hp_mute; - int gpio_int_mic_en; - int gpio_ext_mic_en; -}; - -#endif -- cgit v1.2.3 From e383c467ceeee3b040444d6dcd27f331d72b1426 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 8 Mar 2013 13:44:26 +0100 Subject: ASoC: core: Drop unused "dapm" field form soc_enum struct This field was added in commit 2e72f8e ("ASoC: New enum type: value_enum"), but has never been used since. Considering that the soc_enum struct is usually shared between all instances of a CODEC, it also doesn't make much sense to have a pointer to DAPM specific data in it. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- include/sound/soc.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include/sound') diff --git a/include/sound/soc.h b/include/sound/soc.h index a6a059ca3874..c84062b22221 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1086,7 +1086,6 @@ struct soc_enum { unsigned int mask; const char * const *texts; const unsigned int *values; - void *dapm; }; /* codec IO */ -- cgit v1.2.3 From a93f8e76a446e0a146a169cc2cc82bf1e145ad35 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 8 Mar 2013 13:44:27 +0100 Subject: ASoC: core: Remove unused "n_widgets" field from snd_soc_dapm struct Commit 497098be ("ASoC: dapm: Remove bodges for no-widget CODECs") removed the last user of the n_widgets field. Currently it is incremented for each widget added, but the value is never used, so we can remove it. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- include/sound/soc-dapm.h | 1 - sound/soc/soc-dapm.c | 1 - 2 files changed, 2 deletions(-) (limited to 'include/sound') diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index e1ef63d4a5c4..d4c004929ae5 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -565,7 +565,6 @@ struct snd_soc_dapm_update { /* DAPM context */ struct snd_soc_dapm_context { - int n_widgets; /* number of widgets in this context */ enum snd_soc_bias_level bias_level; enum snd_soc_bias_level suspend_bias_level; struct delayed_work delayed_work; diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 1d6a9b3ceb27..625d4824abbb 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3123,7 +3123,6 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, break; } - dapm->n_widgets++; w->dapm = dapm; w->codec = dapm->codec; w->platform = dapm->platform; -- cgit v1.2.3 From 4fa89346fbc34750f96ec0c1b2b59b15596ab333 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Fri, 8 Mar 2013 13:52:09 +0100 Subject: ALSA: ASoC: add codec driver for TI TAS5086 This patch adds a driver for TI's TA5086 6-channel PWM processor. This chip has a very unusual register layout, specifically because the registers are of unequal size, and multi-byte registers require bulk writes to take effect. Regmap does not support these kind of mappings. Currently, the driver does not touch any of the registers >= 0x20, so it doesn't matter, because the register map is mapped to an 8-bit array. In case more features will be added in the future that require access to higher registers, the entire regmap H/W I/O routines have to be open-coded. Signed-off-by: Daniel Mack Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/ti,tas5086.txt | 32 ++ include/sound/tas5086.h | 7 + sound/soc/codecs/Kconfig | 4 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/tas5086.c | 601 +++++++++++++++++++++ 5 files changed, 646 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/ti,tas5086.txt create mode 100644 include/sound/tas5086.h create mode 100644 sound/soc/codecs/tas5086.c (limited to 'include/sound') diff --git a/Documentation/devicetree/bindings/sound/ti,tas5086.txt b/Documentation/devicetree/bindings/sound/ti,tas5086.txt new file mode 100644 index 000000000000..8ea4f5b4818d --- /dev/null +++ b/Documentation/devicetree/bindings/sound/ti,tas5086.txt @@ -0,0 +1,32 @@ +Texas Instruments TAS5086 6-channel PWM Processor + +Required properties: + + - compatible: Should contain "ti,tas5086". + - reg: The i2c address. Should contain <0x1b>. + +Optional properties: + + - reset-gpio: A GPIO spec to define which pin is connected to the + chip's !RESET pin. If specified, the driver will + assert a hardware reset at probe time. + + - ti,charge-period: This property should contain the time in microseconds + that closely matches the external single-ended + split-capacitor charge period. The hardware chip + waits for this period of time before starting the + PWM signals. This helps reduce pops and clicks. + + When not specified, the hardware default of 1300ms + is retained. + +Examples: + + i2c_bus { + tas5086@1b { + compatible = "ti,tas5086"; + reg = <0x1b>; + reset-gpio = <&gpio 23 0>; + ti,charge-period = <156000>; + }; + }; diff --git a/include/sound/tas5086.h b/include/sound/tas5086.h new file mode 100644 index 000000000000..aac481b7db8f --- /dev/null +++ b/include/sound/tas5086.h @@ -0,0 +1,7 @@ +#ifndef _SND_SOC_CODEC_TAS5086_H_ +#define _SND_SOC_CODEC_TAS5086_H_ + +#define TAS5086_CLK_IDX_MCLK 0 +#define TAS5086_CLK_IDX_SCLK 1 + +#endif /* _SND_SOC_CODEC_TAS5086_H_ */ diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 45b72561c615..86b35245e559 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -63,6 +63,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_STA32X if I2C select SND_SOC_STA529 if I2C select SND_SOC_STAC9766 if SND_SOC_AC97_BUS + select SND_SOC_TAS5086 if I2C select SND_SOC_TLV320AIC23 if I2C select SND_SOC_TLV320AIC26 if SPI_MASTER select SND_SOC_TLV320AIC32X4 if I2C @@ -320,6 +321,9 @@ config SND_SOC_STA529 config SND_SOC_STAC9766 tristate +config SND_SOC_TAS5086 + tristate + config SND_SOC_TLV320AIC23 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 6a3b3c3b8b41..8077bc2b4f43 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -55,6 +55,7 @@ snd-soc-ssm2602-objs := ssm2602.o snd-soc-sta32x-objs := sta32x.o snd-soc-sta529-objs := sta529.o snd-soc-stac9766-objs := stac9766.o +snd-soc-tas5086-objs := tas5086.o snd-soc-tlv320aic23-objs := tlv320aic23.o snd-soc-tlv320aic26-objs := tlv320aic26.o snd-soc-tlv320aic3x-objs := tlv320aic3x.o @@ -177,6 +178,7 @@ obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o obj-$(CONFIG_SND_SOC_STA32X) += snd-soc-sta32x.o obj-$(CONFIG_SND_SOC_STA529) += snd-soc-sta529.o obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o +obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o obj-$(CONFIG_SND_SOC_TLV320AIC26) += snd-soc-tlv320aic26.o obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o diff --git a/sound/soc/codecs/tas5086.c b/sound/soc/codecs/tas5086.c new file mode 100644 index 000000000000..008bea4d6208 --- /dev/null +++ b/sound/soc/codecs/tas5086.c @@ -0,0 +1,601 @@ +/* + * TAS5086 ASoC codec driver + * + * Copyright (c) 2013 Daniel Mack + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * TODO: + * - implement DAPM and input muxing + * - implement modulation limit + * - implement non-default PWM start + * + * Note that this chip has a very unusual register layout, specifically + * because the registers are of unequal size, and multi-byte registers + * require bulk writes to take effect. Regmap does not support that kind + * of devices. + * + * Currently, the driver does not touch any of the registers >= 0x20, so + * it doesn't matter because the entire map can be accessed as 8-bit + * array. In case more features will be added in the future + * that require access to higher registers, the entire regmap H/W I/O + * routines have to be open-coded. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TAS5086_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_3LE) + +#define TAS5086_PCM_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | \ + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | \ + SNDRV_PCM_RATE_192000) + +/* + * TAS5086 registers + */ +#define TAS5086_CLOCK_CONTROL 0x00 /* Clock control register */ +#define TAS5086_CLOCK_RATE(val) (val << 5) +#define TAS5086_CLOCK_RATE_MASK (0x7 << 5) +#define TAS5086_CLOCK_RATIO(val) (val << 2) +#define TAS5086_CLOCK_RATIO_MASK (0x7 << 2) +#define TAS5086_CLOCK_SCLK_RATIO_48 (1 << 1) +#define TAS5086_CLOCK_VALID (1 << 0) + +#define TAS5086_DEEMPH_MASK 0x03 +#define TAS5086_SOFT_MUTE_ALL 0x3f + +#define TAS5086_DEV_ID 0x01 /* Device ID register */ +#define TAS5086_ERROR_STATUS 0x02 /* Error status register */ +#define TAS5086_SYS_CONTROL_1 0x03 /* System control register 1 */ +#define TAS5086_SERIAL_DATA_IF 0x04 /* Serial data interface register */ +#define TAS5086_SYS_CONTROL_2 0x05 /* System control register 2 */ +#define TAS5086_SOFT_MUTE 0x06 /* Soft mute register */ +#define TAS5086_MASTER_VOL 0x07 /* Master volume */ +#define TAS5086_CHANNEL_VOL(X) (0x08 + (X)) /* Channel 1-6 volume */ +#define TAS5086_VOLUME_CONTROL 0x09 /* Volume control register */ +#define TAS5086_MOD_LIMIT 0x10 /* Modulation limit register */ +#define TAS5086_PWM_START 0x18 /* PWM start register */ +#define TAS5086_SURROUND 0x19 /* Surround register */ +#define TAS5086_SPLIT_CAP_CHARGE 0x1a /* Split cap charge period register */ +#define TAS5086_OSC_TRIM 0x1b /* Oscillator trim register */ +#define TAS5086_BKNDERR 0x1c + +/* + * Default TAS5086 power-up configuration + */ +static const struct reg_default tas5086_reg_defaults[] = { + { 0x00, 0x6c }, + { 0x01, 0x03 }, + { 0x02, 0x00 }, + { 0x03, 0xa0 }, + { 0x04, 0x05 }, + { 0x05, 0x60 }, + { 0x06, 0x00 }, + { 0x07, 0xff }, + { 0x08, 0x30 }, + { 0x09, 0x30 }, + { 0x0a, 0x30 }, + { 0x0b, 0x30 }, + { 0x0c, 0x30 }, + { 0x0d, 0x30 }, + { 0x0e, 0xb1 }, + { 0x0f, 0x00 }, + { 0x10, 0x02 }, + { 0x11, 0x00 }, + { 0x12, 0x00 }, + { 0x13, 0x00 }, + { 0x14, 0x00 }, + { 0x15, 0x00 }, + { 0x16, 0x00 }, + { 0x17, 0x00 }, + { 0x18, 0x3f }, + { 0x19, 0x00 }, + { 0x1a, 0x18 }, + { 0x1b, 0x82 }, + { 0x1c, 0x05 }, +}; + +static bool tas5086_accessible_reg(struct device *dev, unsigned int reg) +{ + return !((reg == 0x0f) || (reg >= 0x11 && reg <= 0x17)); +} + +static bool tas5086_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TAS5086_DEV_ID: + case TAS5086_ERROR_STATUS: + return true; + } + + return false; +} + +static bool tas5086_writeable_reg(struct device *dev, unsigned int reg) +{ + return tas5086_accessible_reg(dev, reg) && (reg != TAS5086_DEV_ID); +} + +struct tas5086_private { + struct regmap *regmap; + unsigned int mclk, sclk; + unsigned int format; + bool deemph; + /* Current sample rate for de-emphasis control */ + int rate; + /* GPIO driving Reset pin, if any */ + int gpio_nreset; +}; + +static int tas5086_deemph[] = { 0, 32000, 44100, 48000 }; + +static int tas5086_set_deemph(struct snd_soc_codec *codec) +{ + struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec); + int i, val = 0; + + if (priv->deemph) + for (i = 0; i < ARRAY_SIZE(tas5086_deemph); i++) + if (tas5086_deemph[i] == priv->rate) + val = i; + + return regmap_update_bits(priv->regmap, TAS5086_SYS_CONTROL_1, + TAS5086_DEEMPH_MASK, val); +} + +static int tas5086_get_deemph(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.enumerated.item[0] = priv->deemph; + + return 0; +} + +static int tas5086_put_deemph(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec); + + priv->deemph = ucontrol->value.enumerated.item[0]; + + return tas5086_set_deemph(codec); +} + + +static int tas5086_set_dai_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec); + + switch (clk_id) { + case TAS5086_CLK_IDX_MCLK: + priv->mclk = freq; + break; + case TAS5086_CLK_IDX_SCLK: + priv->sclk = freq; + break; + } + + return 0; +} + +static int tas5086_set_dai_fmt(struct snd_soc_dai *codec_dai, + unsigned int format) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec); + + /* The TAS5086 can only be slave to all clocks */ + if ((format & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) { + dev_err(codec->dev, "Invalid clocking mode\n"); + return -EINVAL; + } + + /* we need to refer to the data format from hw_params() */ + priv->format = format; + + return 0; +} + +static const int tas5086_sample_rates[] = { + 32000, 38000, 44100, 48000, 88200, 96000, 176400, 192000 +}; + +static const int tas5086_ratios[] = { + 64, 128, 192, 256, 384, 512 +}; + +static int index_in_array(const int *array, int len, int needle) +{ + int i; + + for (i = 0; i < len; i++) + if (array[i] == needle) + return i; + + return -ENOENT; +} + +static int tas5086_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 tas5086_private *priv = snd_soc_codec_get_drvdata(codec); + unsigned int val; + int ret; + + priv->rate = params_rate(params); + + /* Look up the sample rate and refer to the offset in the list */ + val = index_in_array(tas5086_sample_rates, + ARRAY_SIZE(tas5086_sample_rates), priv->rate); + + if (val < 0) { + dev_err(codec->dev, "Invalid sample rate\n"); + return -EINVAL; + } + + ret = regmap_update_bits(priv->regmap, TAS5086_CLOCK_CONTROL, + TAS5086_CLOCK_RATE_MASK, + TAS5086_CLOCK_RATE(val)); + if (ret < 0) + return ret; + + /* MCLK / Fs ratio */ + val = index_in_array(tas5086_ratios, ARRAY_SIZE(tas5086_ratios), + priv->mclk / priv->rate); + if (val < 0) { + dev_err(codec->dev, "Inavlid MCLK / Fs ratio\n"); + return -EINVAL; + } + + ret = regmap_update_bits(priv->regmap, TAS5086_CLOCK_CONTROL, + TAS5086_CLOCK_RATIO_MASK, + TAS5086_CLOCK_RATIO(val)); + if (ret < 0) + return ret; + + + ret = regmap_update_bits(priv->regmap, TAS5086_CLOCK_CONTROL, + TAS5086_CLOCK_SCLK_RATIO_48, + (priv->sclk == 48 * priv->rate) ? + TAS5086_CLOCK_SCLK_RATIO_48 : 0); + if (ret < 0) + return ret; + + /* + * The chip has a very unituitive register mapping and muxes information + * about data format and sample depth into the same register, but not on + * a logical bit-boundary. Hence, we have to refer to the format passed + * in the set_dai_fmt() callback and set up everything from here. + * + * First, determine the 'base' value, using the format ... + */ + switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_RIGHT_J: + val = 0x00; + break; + case SND_SOC_DAIFMT_I2S: + val = 0x03; + break; + case SND_SOC_DAIFMT_LEFT_J: + val = 0x06; + break; + default: + dev_err(codec->dev, "Invalid DAI format\n"); + return -EINVAL; + } + + /* ... then add the offset for the sample bit depth. */ + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + val += 0; + break; + case SNDRV_PCM_FORMAT_S20_3LE: + val += 1; + break; + case SNDRV_PCM_FORMAT_S24_3LE: + val += 2; + break; + default: + dev_err(codec->dev, "Invalid bit width\n"); + return -EINVAL; + }; + + ret = regmap_write(priv->regmap, TAS5086_SERIAL_DATA_IF, val); + if (ret < 0) + return ret; + + /* clock is considered valid now */ + ret = regmap_update_bits(priv->regmap, TAS5086_CLOCK_CONTROL, + TAS5086_CLOCK_VALID, TAS5086_CLOCK_VALID); + if (ret < 0) + return ret; + + return tas5086_set_deemph(codec); +} + +static int tas5086_mute_stream(struct snd_soc_dai *dai, int mute, int stream) +{ + struct snd_soc_codec *codec = dai->codec; + struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec); + unsigned int val = 0; + + if (mute) + val = TAS5086_SOFT_MUTE_ALL; + + return regmap_write(priv->regmap, TAS5086_SOFT_MUTE, val); +} + +/* TAS5086 controls */ +static const DECLARE_TLV_DB_SCALE(tas5086_dac_tlv, -10350, 50, 1); + +static const struct snd_kcontrol_new tas5086_controls[] = { + SOC_SINGLE_TLV("Master Playback Volume", TAS5086_MASTER_VOL, + 0, 0xff, 1, tas5086_dac_tlv), + SOC_DOUBLE_R_TLV("Channel 1/2 Playback Volume", + TAS5086_CHANNEL_VOL(0), TAS5086_CHANNEL_VOL(1), + 0, 0xff, 1, tas5086_dac_tlv), + SOC_DOUBLE_R_TLV("Channel 3/4 Playback Volume", + TAS5086_CHANNEL_VOL(2), TAS5086_CHANNEL_VOL(3), + 0, 0xff, 1, tas5086_dac_tlv), + SOC_DOUBLE_R_TLV("Channel 5/6 Playback Volume", + TAS5086_CHANNEL_VOL(4), TAS5086_CHANNEL_VOL(5), + 0, 0xff, 1, tas5086_dac_tlv), + SOC_SINGLE_BOOL_EXT("De-emphasis Switch", 0, + tas5086_get_deemph, tas5086_put_deemph), +}; + +static const struct snd_soc_dai_ops tas5086_dai_ops = { + .hw_params = tas5086_hw_params, + .set_sysclk = tas5086_set_dai_sysclk, + .set_fmt = tas5086_set_dai_fmt, + .mute_stream = tas5086_mute_stream, +}; + +static struct snd_soc_dai_driver tas5086_dai = { + .name = "tas5086-hifi", + .playback = { + .stream_name = "Playback", + .channels_min = 2, + .channels_max = 6, + .rates = TAS5086_PCM_RATES, + .formats = TAS5086_PCM_FORMATS, + }, + .ops = &tas5086_dai_ops, +}; + +#ifdef CONFIG_PM +static int tas5086_soc_resume(struct snd_soc_codec *codec) +{ + struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec); + + /* Restore codec state */ + return regcache_sync(priv->regmap); +} +#else +#define tas5086_soc_resume NULL +#endif /* CONFIG_PM */ + +#ifdef CONFIG_OF +static const struct of_device_id tas5086_dt_ids[] = { + { .compatible = "ti,tas5086", }, + { } +}; +MODULE_DEVICE_TABLE(of, tas5086_dt_ids); +#endif + +/* charge period values in microseconds */ +static const int tas5086_charge_period[] = { + 13000, 16900, 23400, 31200, 41600, 54600, 72800, 96200, + 130000, 156000, 234000, 312000, 416000, 546000, 728000, 962000, + 1300000, 169000, 2340000, 3120000, 4160000, 5460000, 7280000, 9620000, +}; + +static int tas5086_probe(struct snd_soc_codec *codec) +{ + struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec); + int charge_period = 1300000; /* hardware default is 1300 ms */ + int i, ret; + + if (of_match_device(of_match_ptr(tas5086_dt_ids), codec->dev)) { + struct device_node *of_node = codec->dev->of_node; + of_property_read_u32(of_node, "ti,charge-period", &charge_period); + } + + /* lookup and set split-capacitor charge period */ + if (charge_period == 0) { + regmap_write(priv->regmap, TAS5086_SPLIT_CAP_CHARGE, 0); + } else { + i = index_in_array(tas5086_charge_period, + ARRAY_SIZE(tas5086_charge_period), + charge_period); + if (i >= 0) + regmap_write(priv->regmap, TAS5086_SPLIT_CAP_CHARGE, + i + 0x08); + else + dev_warn(codec->dev, + "Invalid split-cap charge period of %d ns.\n", + charge_period); + } + + /* enable factory trim */ + ret = regmap_write(priv->regmap, TAS5086_OSC_TRIM, 0x00); + if (ret < 0) + return ret; + + /* start all channels */ + ret = regmap_write(priv->regmap, TAS5086_SYS_CONTROL_2, 0x20); + if (ret < 0) + return ret; + + /* set master volume to 0 dB */ + ret = regmap_write(priv->regmap, TAS5086_MASTER_VOL, 0x30); + if (ret < 0) + return ret; + + /* mute all channels for now */ + ret = regmap_write(priv->regmap, TAS5086_SOFT_MUTE, + TAS5086_SOFT_MUTE_ALL); + if (ret < 0) + return ret; + + return 0; +} + +static int tas5086_remove(struct snd_soc_codec *codec) +{ + struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec); + + if (gpio_is_valid(priv->gpio_nreset)) + /* Set codec to the reset state */ + gpio_set_value(priv->gpio_nreset, 0); + + return 0; +}; + +static struct snd_soc_codec_driver soc_codec_dev_tas5086 = { + .probe = tas5086_probe, + .remove = tas5086_remove, + .resume = tas5086_soc_resume, + .controls = tas5086_controls, + .num_controls = ARRAY_SIZE(tas5086_controls), +}; + +static const struct i2c_device_id tas5086_i2c_id[] = { + { "tas5086", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, tas5086_i2c_id); + +static const struct regmap_config tas5086_regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = ARRAY_SIZE(tas5086_reg_defaults), + .reg_defaults = tas5086_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(tas5086_reg_defaults), + .cache_type = REGCACHE_RBTREE, + .volatile_reg = tas5086_volatile_reg, + .writeable_reg = tas5086_writeable_reg, + .readable_reg = tas5086_accessible_reg, +}; + +static int tas5086_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct tas5086_private *priv; + struct device *dev = &i2c->dev; + int gpio_nreset = -EINVAL; + int i, ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->regmap = devm_regmap_init_i2c(i2c, &tas5086_regmap); + if (IS_ERR(priv->regmap)) { + ret = PTR_ERR(priv->regmap); + dev_err(&i2c->dev, "Failed to create regmap: %d\n", ret); + return ret; + } + + i2c_set_clientdata(i2c, priv); + + if (of_match_device(of_match_ptr(tas5086_dt_ids), dev)) { + struct device_node *of_node = dev->of_node; + gpio_nreset = of_get_named_gpio(of_node, "reset-gpio", 0); + } + + if (gpio_is_valid(gpio_nreset)) + if (devm_gpio_request(dev, gpio_nreset, "TAS5086 Reset")) + gpio_nreset = -EINVAL; + + if (gpio_is_valid(gpio_nreset)) { + /* Reset codec - minimum assertion time is 400ns */ + gpio_direction_output(gpio_nreset, 0); + udelay(1); + gpio_set_value(gpio_nreset, 1); + + /* Codec needs ~15ms to wake up */ + msleep(15); + } + + priv->gpio_nreset = gpio_nreset; + + /* The TAS5086 always returns 0x03 in its TAS5086_DEV_ID register */ + ret = regmap_read(priv->regmap, TAS5086_DEV_ID, &i); + if (ret < 0) + return ret; + + if (i != 0x3) { + dev_err(dev, + "Failed to identify TAS5086 codec (got %02x)\n", i); + return -ENODEV; + } + + return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_tas5086, + &tas5086_dai, 1); +} + +static int tas5086_i2c_remove(struct i2c_client *i2c) +{ + snd_soc_unregister_codec(&i2c->dev); + return 0; +} + +static struct i2c_driver tas5086_i2c_driver = { + .driver = { + .name = "tas5086", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(tas5086_dt_ids), + }, + .id_table = tas5086_i2c_id, + .probe = tas5086_i2c_probe, + .remove = tas5086_i2c_remove, +}; + +static int __init tas5086_modinit(void) +{ + return i2c_add_driver(&tas5086_i2c_driver); +} +module_init(tas5086_modinit); + +static void __exit tas5086_modexit(void) +{ + i2c_del_driver(&tas5086_i2c_driver); +} +module_exit(tas5086_modexit); + +MODULE_AUTHOR("Daniel Mack "); +MODULE_DESCRIPTION("Texas Instruments TAS5086 ALSA SoC Codec Driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From d5702162f85526319c848c667df49ee1754dccef Mon Sep 17 00:00:00 2001 From: Christine Spang Date: Mon, 4 Mar 2013 17:02:59 -0500 Subject: ALSA: Make snd_BUG_ON() always evaluate and return the conditional expression Having snd_BUG_ON() only evaluate its conditional when CONFIG_SND_DEBUG is set leads to frequent bugs, since other similar macros in the kernel have different behavior. Let's make snd_BUG_ON() act like those macros so it will stop being accidentally misused. Signed-off-by: Christine Spang Signed-off-by: Takashi Iwai --- Documentation/DocBook/writing-an-alsa-driver.tmpl | 12 +++++------- include/sound/core.h | 24 ++++++++--------------- 2 files changed, 13 insertions(+), 23 deletions(-) (limited to 'include/sound') diff --git a/Documentation/DocBook/writing-an-alsa-driver.tmpl b/Documentation/DocBook/writing-an-alsa-driver.tmpl index bd6fee22c4dd..06741e925985 100644 --- a/Documentation/DocBook/writing-an-alsa-driver.tmpl +++ b/Documentation/DocBook/writing-an-alsa-driver.tmpl @@ -6164,14 +6164,12 @@ struct _snd_pcm_runtime { The macro takes an conditional expression to evaluate. - When CONFIG_SND_DEBUG, is set, the - expression is actually evaluated. If it's non-zero, it shows - the warning message such as + When CONFIG_SND_DEBUG, is set, if the + expression is non-zero, it shows the warning message such as BUG? (xxx) - normally followed by stack trace. It returns the evaluated - value. - When no CONFIG_SND_DEBUG is set, this - macro always returns zero. + normally followed by stack trace. + + In both cases it returns the evaluated value. diff --git a/include/sound/core.h b/include/sound/core.h index 7cede2d6aa86..a63680b9819d 100644 --- a/include/sound/core.h +++ b/include/sound/core.h @@ -379,18 +379,10 @@ void __snd_printk(unsigned int level, const char *file, int line, * snd_BUG_ON - debugging check macro * @cond: condition to evaluate * - * When CONFIG_SND_DEBUG is set, this macro evaluates the given condition, - * and call WARN() and returns the value if it's non-zero. - * - * When CONFIG_SND_DEBUG is not set, this just returns zero, and the given - * condition is ignored. - * - * NOTE: the argument won't be evaluated at all when CONFIG_SND_DEBUG=n. - * Thus, don't put any statement that influences on the code behavior, - * such as pre/post increment, to the argument of this macro. - * If you want to evaluate and give a warning, use standard WARN_ON(). + * Has the same behavior as WARN_ON when CONFIG_SND_DEBUG is set, + * otherwise just evaluates the conditional and returns the value. */ -#define snd_BUG_ON(cond) WARN((cond), "BUG? (%s)\n", __stringify(cond)) +#define snd_BUG_ON(cond) WARN_ON((cond)) #else /* !CONFIG_SND_DEBUG */ @@ -400,11 +392,11 @@ __printf(2, 3) static inline void _snd_printd(int level, const char *format, ...) {} #define snd_BUG() do { } while (0) -static inline int __snd_bug_on(int cond) -{ - return 0; -} -#define snd_BUG_ON(cond) __snd_bug_on(0 && (cond)) /* always false */ + +#define snd_BUG_ON(condition) ({ \ + int __ret_warn_on = !!(condition); \ + unlikely(__ret_warn_on); \ +}) #endif /* CONFIG_SND_DEBUG */ -- cgit v1.2.3 From eb7c06e8e9c93b495e355421cffd3c43c266d7d2 Mon Sep 17 00:00:00 2001 From: Yacine Belkadi Date: Mon, 11 Mar 2013 22:05:14 +0100 Subject: ALSA: add/change some comments describing function return values script/kernel-doc reports the following type of warnings (when run in verbose mode): Warning(sound/core/init.c:152): No description found for return value of 'snd_card_create' To fix that: - add missing descriptions of function return values - use "Return:" sections to describe those return values Along the way: - complete some descriptions - fix some typos Signed-off-by: Yacine Belkadi Signed-off-by: Takashi Iwai --- include/sound/control.h | 5 +++- include/sound/core.h | 2 +- include/sound/pcm.h | 23 +++++++++------- sound/core/control.c | 41 ++++++++++++++++------------- sound/core/device.c | 8 +++--- sound/core/hwdep.c | 2 +- sound/core/info.c | 16 +++++------ sound/core/init.c | 16 ++++++----- sound/core/isadma.c | 2 +- sound/core/jack.c | 6 +++-- sound/core/memalloc.c | 20 +++++++------- sound/core/memory.c | 4 +-- sound/core/pcm.c | 6 ++--- sound/core/pcm_lib.c | 54 ++++++++++++++++++++++++++++++-------- sound/core/pcm_memory.c | 19 +++++++++----- sound/core/pcm_misc.c | 28 ++++++++++---------- sound/core/pcm_native.c | 13 +++++++++ sound/core/rawmidi.c | 14 +++++----- sound/core/sound.c | 7 +++-- sound/core/vmaster.c | 7 +++-- sound/drivers/mpu401/mpu401_uart.c | 6 ++++- sound/pci/ac97/ac97_codec.c | 16 ++++++----- sound/pci/ac97/ac97_pcm.c | 10 ++++++- sound/sound_core.c | 22 +++++++++++----- 24 files changed, 221 insertions(+), 126 deletions(-) (limited to 'include/sound') diff --git a/include/sound/control.h b/include/sound/control.h index 8332e865c759..34bc93d80d55 100644 --- a/include/sound/control.h +++ b/include/sound/control.h @@ -189,7 +189,6 @@ int _snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave, * * Add a virtual slave control to the given master element created via * snd_ctl_create_virtual_master() beforehand. - * Returns zero if successful or a negative error code. * * All slaves must be the same type (returning the same information * via info callback). The function doesn't check it, so it's your @@ -199,6 +198,8 @@ int _snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave, * at most two channels, * logarithmic volume control (dB level) thus no linear volume, * master can only attenuate the volume without gain + * + * Return: Zero if successful or a negative error code. */ static inline int snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave) @@ -219,6 +220,8 @@ snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave) * When the control peeks the hardware values directly and the value * can be changed by other means than the put callback of the element, * this function should be used to keep the value always up-to-date. + * + * Return: Zero if successful or a negative error code. */ static inline int snd_ctl_add_slave_uncached(struct snd_kcontrol *master, diff --git a/include/sound/core.h b/include/sound/core.h index a63680b9819d..5bfe5136441c 100644 --- a/include/sound/core.h +++ b/include/sound/core.h @@ -229,7 +229,7 @@ int snd_register_device_for_dev(int type, struct snd_card *card, * This function uses the card's device pointer to link to the * correct &struct device. * - * Returns zero if successful, or a negative error code on failure. + * Return: Zero if successful, or a negative error code on failure. */ static inline int snd_register_device(int type, struct snd_card *card, int dev, const struct file_operations *f_ops, diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 45c1981c9ca2..aa7b0a8385cb 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -659,7 +659,7 @@ static inline snd_pcm_sframes_t snd_pcm_capture_hw_avail(struct snd_pcm_runtime * * Checks whether enough free space is available on the playback buffer. * - * Returns non-zero if available, or zero if not. + * Return: Non-zero if available, or zero if not. */ static inline int snd_pcm_playback_ready(struct snd_pcm_substream *substream) { @@ -673,7 +673,7 @@ static inline int snd_pcm_playback_ready(struct snd_pcm_substream *substream) * * Checks whether enough capture data is available on the capture buffer. * - * Returns non-zero if available, or zero if not. + * Return: Non-zero if available, or zero if not. */ static inline int snd_pcm_capture_ready(struct snd_pcm_substream *substream) { @@ -685,10 +685,10 @@ static inline int snd_pcm_capture_ready(struct snd_pcm_substream *substream) * snd_pcm_playback_data - check whether any data exists on the playback buffer * @substream: the pcm substream instance * - * Checks whether any data exists on the playback buffer. If stop_threshold - * is bigger or equal to boundary, then this function returns always non-zero. + * Checks whether any data exists on the playback buffer. * - * Returns non-zero if exists, or zero if not. + * Return: Non-zero if any data exists, or zero if not. If stop_threshold + * is bigger or equal to boundary, then this function returns always non-zero. */ static inline int snd_pcm_playback_data(struct snd_pcm_substream *substream) { @@ -705,7 +705,7 @@ static inline int snd_pcm_playback_data(struct snd_pcm_substream *substream) * * Checks whether the playback buffer is empty. * - * Returns non-zero if empty, or zero if not. + * Return: Non-zero if empty, or zero if not. */ static inline int snd_pcm_playback_empty(struct snd_pcm_substream *substream) { @@ -719,7 +719,7 @@ static inline int snd_pcm_playback_empty(struct snd_pcm_substream *substream) * * Checks whether the capture buffer is empty. * - * Returns non-zero if empty, or zero if not. + * Return: Non-zero if empty, or zero if not. */ static inline int snd_pcm_capture_empty(struct snd_pcm_substream *substream) { @@ -852,7 +852,7 @@ int snd_pcm_format_big_endian(snd_pcm_format_t format); * snd_pcm_format_cpu_endian - Check the PCM format is CPU-endian * @format: the format to check * - * Returns 1 if the given PCM format is CPU-endian, 0 if + * Return: 1 if the given PCM format is CPU-endian, 0 if * opposite, or a negative error code if endian not specified. */ int snd_pcm_format_cpu_endian(snd_pcm_format_t format); @@ -963,7 +963,7 @@ struct page *snd_pcm_lib_get_vmalloc_page(struct snd_pcm_substream *substream, * contiguous in kernel virtual space, but not in physical memory. Use this * if the buffer is accessed by kernel code but not by device DMA. * - * Returns 1 if the buffer was changed, 0 if not changed, or a negative error + * Return: 1 if the buffer was changed, 0 if not changed, or a negative error * code. */ static int snd_pcm_lib_alloc_vmalloc_buffer @@ -975,6 +975,9 @@ static int snd_pcm_lib_alloc_vmalloc_buffer * * This function works like snd_pcm_lib_alloc_vmalloc_buffer(), but uses * vmalloc_32(), i.e., the pages are allocated from 32-bit-addressable memory. + * + * Return: 1 if the buffer was changed, 0 if not changed, or a negative error + * code. */ static int snd_pcm_lib_alloc_vmalloc_32_buffer (struct snd_pcm_substream *substream, size_t size); @@ -1070,6 +1073,8 @@ const char *snd_pcm_format_name(snd_pcm_format_t format); /** * snd_pcm_stream_str - Get a string naming the direction of a stream * @substream: the pcm substream instance + * + * Return: A string naming the direction of the stream. */ static inline const char *snd_pcm_stream_str(struct snd_pcm_substream *substream) { diff --git a/sound/core/control.c b/sound/core/control.c index 8c7c2c9bba61..d8aa206e8bde 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -190,7 +190,7 @@ EXPORT_SYMBOL(snd_ctl_notify); * Allocates a new struct snd_kcontrol instance and copies the given template * to the new instance. It does not copy volatile data (access). * - * Returns the pointer of the new instance, or NULL on failure. + * Return: The pointer of the new instance, or %NULL on failure. */ static struct snd_kcontrol *snd_ctl_new(struct snd_kcontrol *control, unsigned int access) @@ -224,7 +224,7 @@ static struct snd_kcontrol *snd_ctl_new(struct snd_kcontrol *control, * template. When the access field of ncontrol is 0, it's assumed as * READWRITE access. When the count field is 0, it's assumes as one. * - * Returns the pointer of the newly generated instance, or NULL on failure. + * Return: The pointer of the newly generated instance, or %NULL on failure. */ struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new *ncontrol, void *private_data) @@ -322,9 +322,10 @@ static int snd_ctl_find_hole(struct snd_card *card, unsigned int count) * snd_ctl_new1() to the given card. Assigns also an unique * numid used for fast search. * - * Returns zero if successful, or a negative error code on failure. - * * It frees automatically the control which cannot be added. + * + * Return: Zero if successful, or a negative error code on failure. + * */ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol) { @@ -380,9 +381,9 @@ EXPORT_SYMBOL(snd_ctl_add); * and the add_on_replace flag is set, the control is added. If the * control exists, it is destroyed first. * - * Returns zero if successful, or a negative error code on failure. - * * It frees automatically the control which cannot be added or replaced. + * + * Return: Zero if successful, or a negative error code on failure. */ int snd_ctl_replace(struct snd_card *card, struct snd_kcontrol *kcontrol, bool add_on_replace) @@ -442,8 +443,8 @@ EXPORT_SYMBOL(snd_ctl_replace); * Removes the control from the card and then releases the instance. * You don't need to call snd_ctl_free_one(). You must be in * the write lock - down_write(&card->controls_rwsem). - * - * Returns 0 if successful, or a negative error code on failure. + * + * Return: 0 if successful, or a negative error code on failure. */ int snd_ctl_remove(struct snd_card *card, struct snd_kcontrol *kcontrol) { @@ -470,8 +471,8 @@ EXPORT_SYMBOL(snd_ctl_remove); * * Finds the control instance with the given id, removes it from the * card list and releases it. - * - * Returns 0 if successful, or a negative error code on failure. + * + * Return: 0 if successful, or a negative error code on failure. */ int snd_ctl_remove_id(struct snd_card *card, struct snd_ctl_elem_id *id) { @@ -498,8 +499,8 @@ EXPORT_SYMBOL(snd_ctl_remove_id); * * Finds the control instance with the given id, removes it from the * card list and releases it. - * - * Returns 0 if successful, or a negative error code on failure. + * + * Return: 0 if successful, or a negative error code on failure. */ static int snd_ctl_remove_user_ctl(struct snd_ctl_file * file, struct snd_ctl_elem_id *id) @@ -541,7 +542,7 @@ error: * Finds the control instance with the given id, and activate or * inactivate the control together with notification, if changed. * - * Returns 0 if unchanged, 1 if changed, or a negative error code on failure. + * Return: 0 if unchanged, 1 if changed, or a negative error code on failure. */ int snd_ctl_activate_id(struct snd_card *card, struct snd_ctl_elem_id *id, int active) @@ -587,7 +588,7 @@ EXPORT_SYMBOL_GPL(snd_ctl_activate_id); * Finds the control with the old id from the card, and replaces the * id with the new one. * - * Returns zero if successful, or a negative error code on failure. + * Return: Zero if successful, or a negative error code on failure. */ int snd_ctl_rename_id(struct snd_card *card, struct snd_ctl_elem_id *src_id, struct snd_ctl_elem_id *dst_id) @@ -616,10 +617,11 @@ EXPORT_SYMBOL(snd_ctl_rename_id); * * Finds the control instance with the given number-id from the card. * - * Returns the pointer of the instance if found, or NULL if not. - * * The caller must down card->controls_rwsem before calling this function * (if the race condition can happen). + * + * Return: The pointer of the instance if found, or %NULL if not. + * */ struct snd_kcontrol *snd_ctl_find_numid(struct snd_card *card, unsigned int numid) { @@ -643,10 +645,11 @@ EXPORT_SYMBOL(snd_ctl_find_numid); * * Finds the control instance with the given id from the card. * - * Returns the pointer of the instance if found, or NULL if not. - * * The caller must down card->controls_rwsem before calling this function * (if the race condition can happen). + * + * Return: The pointer of the instance if found, or %NULL if not. + * */ struct snd_kcontrol *snd_ctl_find_id(struct snd_card *card, struct snd_ctl_elem_id *id) @@ -1710,6 +1713,8 @@ EXPORT_SYMBOL(snd_ctl_boolean_stereo_info); * Sets all required fields in @info to their appropriate values. * If the control's accessibility is not the default (readable and writable), * the caller has to fill @info->access. + * + * Return: Zero. */ int snd_ctl_enum_info(struct snd_ctl_elem_info *info, unsigned int channels, unsigned int items, const char *const names[]) diff --git a/sound/core/device.c b/sound/core/device.c index f03cb5444a5a..df88defed176 100644 --- a/sound/core/device.c +++ b/sound/core/device.c @@ -39,7 +39,7 @@ * The data pointer plays a role as the identifier, too, so the * pointer address must be unique and unchanged. * - * Returns zero if successful, or a negative error code on failure. + * Return: Zero if successful, or a negative error code on failure. */ int snd_device_new(struct snd_card *card, snd_device_type_t type, void *device_data, struct snd_device_ops *ops) @@ -73,7 +73,7 @@ EXPORT_SYMBOL(snd_device_new); * callbacks, dev_disconnect and dev_free, corresponding to the state. * Then release the device. * - * Returns zero if successful, or a negative error code on failure or if the + * Return: Zero if successful, or a negative error code on failure or if the * device not found. */ int snd_device_free(struct snd_card *card, void *device_data) @@ -116,7 +116,7 @@ EXPORT_SYMBOL(snd_device_free); * * Usually called from snd_card_disconnect(). * - * Returns zero if successful, or a negative error code on failure or if the + * Return: Zero if successful, or a negative error code on failure or if the * device not found. */ int snd_device_disconnect(struct snd_card *card, void *device_data) @@ -151,7 +151,7 @@ int snd_device_disconnect(struct snd_card *card, void *device_data) * but it can be called later if any new devices are created after * invocation of snd_card_register(). * - * Returns zero if successful, or a negative error code on failure or if the + * Return: Zero if successful, or a negative error code on failure or if the * device not found. */ int snd_device_register(struct snd_card *card, void *device_data) diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c index 3f7f6628cf7b..d105073298cb 100644 --- a/sound/core/hwdep.c +++ b/sound/core/hwdep.c @@ -356,7 +356,7 @@ static const struct file_operations snd_hwdep_f_ops = * The callbacks (hwdep->ops) must be set on the returned instance * after this call manually by the caller. * - * Returns zero if successful, or a negative error code on failure. + * Return: Zero if successful, or a negative error code on failure. */ int snd_hwdep_new(struct snd_card *card, char *id, int device, struct snd_hwdep **rhwdep) diff --git a/sound/core/info.c b/sound/core/info.c index 5bb97e7d325a..db308dbc8911 100644 --- a/sound/core/info.c +++ b/sound/core/info.c @@ -105,7 +105,7 @@ static int resize_info_buffer(struct snd_info_buffer *buffer, * * Outputs the string on the procfs buffer just like printf(). * - * Returns the size of output string. + * Return: The size of output string, or a negative error code. */ int snd_iprintf(struct snd_info_buffer *buffer, const char *fmt, ...) { @@ -694,7 +694,7 @@ int snd_info_card_free(struct snd_card *card) * * Reads one line from the buffer and stores the string. * - * Returns zero if successful, or 1 if error or EOF. + * Return: Zero if successful, or 1 if error or EOF. */ int snd_info_get_line(struct snd_info_buffer *buffer, char *line, int len) { @@ -735,7 +735,7 @@ EXPORT_SYMBOL(snd_info_get_line); * Parses the original string and copy a token to the given * string buffer. * - * Returns the updated pointer of the original string so that + * Return: The updated pointer of the original string so that * it can be used for the next call. */ const char *snd_info_get_str(char *dest, const char *src, int len) @@ -774,7 +774,7 @@ EXPORT_SYMBOL(snd_info_get_str); * Usually called from other functions such as * snd_info_create_card_entry(). * - * Returns the pointer of the new instance, or NULL on failure. + * Return: The pointer of the new instance, or %NULL on failure. */ static struct snd_info_entry *snd_info_create_entry(const char *name) { @@ -803,7 +803,7 @@ static struct snd_info_entry *snd_info_create_entry(const char *name) * * Creates a new info entry and assigns it to the given module. * - * Returns the pointer of the new instance, or NULL on failure. + * Return: The pointer of the new instance, or %NULL on failure. */ struct snd_info_entry *snd_info_create_module_entry(struct module * module, const char *name, @@ -827,7 +827,7 @@ EXPORT_SYMBOL(snd_info_create_module_entry); * * Creates a new info entry and assigns it to the given card. * - * Returns the pointer of the new instance, or NULL on failure. + * Return: The pointer of the new instance, or %NULL on failure. */ struct snd_info_entry *snd_info_create_card_entry(struct snd_card *card, const char *name, @@ -893,7 +893,7 @@ static int snd_info_dev_register_entry(struct snd_device *device) * For releasing this entry, use snd_device_free() instead of * snd_info_free_entry(). * - * Returns zero if successful, or a negative error code on failure. + * Return: Zero if successful, or a negative error code on failure. */ int snd_card_proc_new(struct snd_card *card, const char *name, struct snd_info_entry **entryp) @@ -949,7 +949,7 @@ EXPORT_SYMBOL(snd_info_free_entry); * * Registers the proc info entry. * - * Returns zero if successful, or a negative error code on failure. + * Return: Zero if successful, or a negative error code on failure. */ int snd_info_register(struct snd_info_entry * entry) { diff --git a/sound/core/init.c b/sound/core/init.c index 7b012d15c2cf..6ef06400dfc8 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -144,7 +144,7 @@ static inline int init_info_for_card(struct snd_card *card) * space for the driver to use freely. The allocated struct is stored * in the given card_ret pointer. * - * Returns zero if successful or a negative error code. + * Return: Zero if successful or a negative error code. */ int snd_card_create(int idx, const char *xid, struct module *module, int extra_size, @@ -337,7 +337,7 @@ static const struct file_operations snd_shutdown_f_ops = * * Disconnects all APIs from the file-operations (user space). * - * Returns zero, otherwise a negative error code. + * Return: Zero, otherwise a negative error code. * * Note: The current implementation replaces all active file->f_op with special * dummy file operations (they do nothing except release). @@ -415,7 +415,7 @@ EXPORT_SYMBOL(snd_card_disconnect); * devices automatically. That is, you don't have to release the devices * by yourself. * - * Returns zero. Frees all associated devices and frees the control + * Return: Zero. Frees all associated devices and frees the control * interface associated to given soundcard. */ static int snd_card_do_free(struct snd_card *card) @@ -677,7 +677,7 @@ static struct device_attribute card_number_attrs = * external accesses. Thus, you should call this function at the end * of the initialization of the card. * - * Returns zero otherwise a negative error code if the registration failed. + * Return: Zero otherwise a negative error code if the registration failed. */ int snd_card_register(struct snd_card *card) { @@ -849,7 +849,7 @@ int __exit snd_card_info_done(void) * This function adds the component id string to the supported list. * The component can be referred from the alsa-lib. * - * Returns zero otherwise a negative error code. + * Return: Zero otherwise a negative error code. */ int snd_component_add(struct snd_card *card, const char *component) @@ -883,7 +883,7 @@ EXPORT_SYMBOL(snd_component_add); * This linked-list is used to keep tracking the connection state, * and to avoid the release of busy resources by hotplug. * - * Returns zero or a negative error code. + * Return: zero or a negative error code. */ int snd_card_file_add(struct snd_card *card, struct file *file) { @@ -920,7 +920,7 @@ EXPORT_SYMBOL(snd_card_file_add); * called beforehand, it processes the pending release of * resources. * - * Returns zero or a negative error code. + * Return: Zero or a negative error code. */ int snd_card_file_remove(struct snd_card *card, struct file *file) { @@ -959,6 +959,8 @@ EXPORT_SYMBOL(snd_card_file_remove); * * Waits until the power-state is changed. * + * Return: Zero if successful, or a negative error code. + * * Note: the power lock must be active before call. */ int snd_power_wait(struct snd_card *card, unsigned int power_state) diff --git a/sound/core/isadma.c b/sound/core/isadma.c index c0f1208bb7df..e2b386156a4c 100644 --- a/sound/core/isadma.c +++ b/sound/core/isadma.c @@ -81,7 +81,7 @@ EXPORT_SYMBOL(snd_dma_disable); * @dma: the dma number * @size: the dma transfer size * - * Returns the current pointer in DMA tranfer buffer in bytes + * Return: The current pointer in DMA transfer buffer in bytes. */ unsigned int snd_dma_pointer(unsigned long dma, unsigned int size) { diff --git a/sound/core/jack.c b/sound/core/jack.c index a06b1651fcba..b35fe7345c20 100644 --- a/sound/core/jack.c +++ b/sound/core/jack.c @@ -98,8 +98,8 @@ static int snd_jack_dev_register(struct snd_device *device) * * Creates a new jack object. * - * Returns zero if successful, or a negative error code on failure. - * On success jjack will be initialised. + * Return: Zero if successful, or a negative error code on failure. + * On success @jjack will be initialised. */ int snd_jack_new(struct snd_card *card, const char *id, int type, struct snd_jack **jjack) @@ -189,6 +189,8 @@ EXPORT_SYMBOL(snd_jack_set_parent); * using this abstraction. * * This function may only be called prior to registration of the jack. + * + * Return: Zero if successful, or a negative error code on failure. */ int snd_jack_set_key(struct snd_jack *jack, enum snd_jack_types type, int keytype) diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c index 691569238435..bdf826f4fe0c 100644 --- a/sound/core/memalloc.c +++ b/sound/core/memalloc.c @@ -81,7 +81,7 @@ static inline void dec_snd_pages(int order) * * Allocates the physically contiguous pages with the given size. * - * Returns the pointer of the buffer, or NULL if no enoguh memory. + * Return: The pointer of the buffer, or %NULL if no enough memory. */ void *snd_malloc_pages(size_t size, gfp_t gfp_flags) { @@ -175,9 +175,9 @@ static void snd_free_dev_pages(struct device *dev, size_t size, void *ptr, * * Calls the memory-allocator function for the corresponding * buffer type. - * - * Returns zero if the buffer with the given size is allocated successfully, - * other a negative value at error. + * + * Return: Zero if the buffer with the given size is allocated successfully, + * otherwise a negative value on error. */ int snd_dma_alloc_pages(int type, struct device *device, size_t size, struct snd_dma_buffer *dmab) @@ -229,9 +229,9 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size, * buffer type. When no space is left, this function reduces the size and * tries to allocate again. The size actually allocated is stored in * res_size argument. - * - * Returns zero if the buffer with the given size is allocated successfully, - * other a negative value at error. + * + * Return: Zero if the buffer with the given size is allocated successfully, + * otherwise a negative value on error. */ int snd_dma_alloc_pages_fallback(int type, struct device *device, size_t size, struct snd_dma_buffer *dmab) @@ -292,7 +292,7 @@ void snd_dma_free_pages(struct snd_dma_buffer *dmab) * Looks for the reserved-buffer list and re-uses if the same buffer * is found in the list. When the buffer is found, it's removed from the free list. * - * Returns the size of buffer if the buffer is found, or zero if not found. + * Return: The size of buffer if the buffer is found, or zero if not found. */ size_t snd_dma_get_reserved_buf(struct snd_dma_buffer *dmab, unsigned int id) { @@ -326,8 +326,8 @@ size_t snd_dma_get_reserved_buf(struct snd_dma_buffer *dmab, unsigned int id) * @id: the buffer id * * Reserves the given buffer as a reserved buffer. - * - * Returns zero if successful, or a negative code at error. + * + * Return: Zero if successful, or a negative code on error. */ int snd_dma_reserve_buf(struct snd_dma_buffer *dmab, unsigned int id) { diff --git a/sound/core/memory.c b/sound/core/memory.c index 66a278d0b04e..36c0f1a2e189 100644 --- a/sound/core/memory.c +++ b/sound/core/memory.c @@ -33,7 +33,7 @@ * * Copies the data from mmio-space to user-space. * - * Returns zero if successful, or non-zero on failure. + * Return: Zero if successful, or non-zero on failure. */ int copy_to_user_fromio(void __user *dst, const volatile void __iomem *src, size_t count) { @@ -66,7 +66,7 @@ EXPORT_SYMBOL(copy_to_user_fromio); * * Copies the data from user-space to mmio-space. * - * Returns zero if successful, or non-zero on failure. + * Return: Zero if successful, or non-zero on failure. */ int copy_from_user_toio(volatile void __iomem *dst, const void __user *src, size_t count) { diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 61798f85d030..578327e2bc26 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -637,7 +637,7 @@ static inline int snd_pcm_substream_proc_done(struct snd_pcm_substream *substrea * calling this, i.e. zero must be given to the argument of * snd_pcm_new(). * - * Returns zero if successful, or a negative error code on failure. + * Return: Zero if successful, or a negative error code on failure. */ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count) { @@ -759,7 +759,7 @@ static int _snd_pcm_new(struct snd_card *card, const char *id, int device, * The pcm operators have to be set afterwards to the new instance * via snd_pcm_set_ops(). * - * Returns zero if successful, or a negative error code on failure. + * Return: Zero if successful, or a negative error code on failure. */ int snd_pcm_new(struct snd_card *card, const char *id, int device, int playback_count, int capture_count, struct snd_pcm **rpcm) @@ -787,7 +787,7 @@ EXPORT_SYMBOL(snd_pcm_new); * The pcm operators have to be set afterwards to the new instance * via snd_pcm_set_ops(). * - * Returns zero if successful, or a negative error code on failure. + * Return: Zero if successful, or a negative error code on failure. */ int snd_pcm_new_internal(struct snd_card *card, const char *id, int device, int playback_count, int capture_count, diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index c4840ff75d00..41b3dfe68698 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -666,7 +666,8 @@ static inline unsigned int muldiv32(unsigned int a, unsigned int b, * The interval is changed to the range satisfying both intervals. * The interval status (min, max, integer, etc.) are evaluated. * - * Returns non-zero if the value is changed, zero if not changed. + * Return: Positive if the value is changed, zero if it's not changed, or a + * negative error code. */ int snd_interval_refine(struct snd_interval *i, const struct snd_interval *v) { @@ -865,7 +866,8 @@ void snd_interval_mulkdiv(const struct snd_interval *a, unsigned int k, * @nump: pointer to store the resultant numerator * @denp: pointer to store the resultant denominator * - * Returns non-zero if the value is changed, zero if not changed. + * Return: Positive if the value is changed, zero if it's not changed, or a + * negative error code. */ int snd_interval_ratnum(struct snd_interval *i, unsigned int rats_count, struct snd_ratnum *rats, @@ -983,7 +985,8 @@ EXPORT_SYMBOL(snd_interval_ratnum); * @nump: pointer to store the resultant numerator * @denp: pointer to store the resultant denominator * - * Returns non-zero if the value is changed, zero if not changed. + * Return: Positive if the value is changed, zero if it's not changed, or a + * negative error code. */ static int snd_interval_ratden(struct snd_interval *i, unsigned int rats_count, struct snd_ratden *rats, @@ -1082,7 +1085,8 @@ static int snd_interval_ratden(struct snd_interval *i, * When mask is non-zero, only the elements corresponding to bit 1 are * evaluated. * - * Returns non-zero if the value is changed, zero if not changed. + * Return: Positive if the value is changed, zero if it's not changed, or a + * negative error code. */ int snd_interval_list(struct snd_interval *i, unsigned int count, const unsigned int *list, unsigned int mask) @@ -1142,7 +1146,7 @@ static int snd_interval_step(struct snd_interval *i, unsigned int min, unsigned * @private: the private data pointer passed to function * @dep: the dependent variables * - * Returns zero if successful, or a negative error code on failure. + * Return: Zero if successful, or a negative error code on failure. */ int snd_pcm_hw_rule_add(struct snd_pcm_runtime *runtime, unsigned int cond, int var, @@ -1200,6 +1204,8 @@ EXPORT_SYMBOL(snd_pcm_hw_rule_add); * @mask: the bitmap mask * * Apply the constraint of the given bitmap mask to a 32-bit mask parameter. + * + * Return: Zero if successful, or a negative error code on failure. */ int snd_pcm_hw_constraint_mask(struct snd_pcm_runtime *runtime, snd_pcm_hw_param_t var, u_int32_t mask) @@ -1220,6 +1226,8 @@ int snd_pcm_hw_constraint_mask(struct snd_pcm_runtime *runtime, snd_pcm_hw_param * @mask: the 64bit bitmap mask * * Apply the constraint of the given bitmap mask to a 64-bit mask parameter. + * + * Return: Zero if successful, or a negative error code on failure. */ int snd_pcm_hw_constraint_mask64(struct snd_pcm_runtime *runtime, snd_pcm_hw_param_t var, u_int64_t mask) @@ -1240,6 +1248,9 @@ int snd_pcm_hw_constraint_mask64(struct snd_pcm_runtime *runtime, snd_pcm_hw_par * @var: hw_params variable to apply the integer constraint * * Apply the constraint of integer to an interval parameter. + * + * Return: Positive if the value is changed, zero if it's not changed, or a + * negative error code. */ int snd_pcm_hw_constraint_integer(struct snd_pcm_runtime *runtime, snd_pcm_hw_param_t var) { @@ -1257,6 +1268,9 @@ EXPORT_SYMBOL(snd_pcm_hw_constraint_integer); * @max: the maximal value * * Apply the min/max range constraint to an interval parameter. + * + * Return: Positive if the value is changed, zero if it's not changed, or a + * negative error code. */ int snd_pcm_hw_constraint_minmax(struct snd_pcm_runtime *runtime, snd_pcm_hw_param_t var, unsigned int min, unsigned int max) @@ -1288,6 +1302,8 @@ static int snd_pcm_hw_rule_list(struct snd_pcm_hw_params *params, * @l: list * * Apply the list of constraints to an interval parameter. + * + * Return: Zero if successful, or a negative error code on failure. */ int snd_pcm_hw_constraint_list(struct snd_pcm_runtime *runtime, unsigned int cond, @@ -1322,6 +1338,8 @@ static int snd_pcm_hw_rule_ratnums(struct snd_pcm_hw_params *params, * @cond: condition bits * @var: hw_params variable to apply the ratnums constraint * @r: struct snd_ratnums constriants + * + * Return: Zero if successful, or a negative error code on failure. */ int snd_pcm_hw_constraint_ratnums(struct snd_pcm_runtime *runtime, unsigned int cond, @@ -1355,6 +1373,8 @@ static int snd_pcm_hw_rule_ratdens(struct snd_pcm_hw_params *params, * @cond: condition bits * @var: hw_params variable to apply the ratdens constraint * @r: struct snd_ratdens constriants + * + * Return: Zero if successful, or a negative error code on failure. */ int snd_pcm_hw_constraint_ratdens(struct snd_pcm_runtime *runtime, unsigned int cond, @@ -1386,6 +1406,8 @@ static int snd_pcm_hw_rule_msbits(struct snd_pcm_hw_params *params, * @cond: condition bits * @width: sample bits width * @msbits: msbits width + * + * Return: Zero if successful, or a negative error code on failure. */ int snd_pcm_hw_constraint_msbits(struct snd_pcm_runtime *runtime, unsigned int cond, @@ -1414,6 +1436,8 @@ static int snd_pcm_hw_rule_step(struct snd_pcm_hw_params *params, * @cond: condition bits * @var: hw_params variable to apply the step constraint * @step: step size + * + * Return: Zero if successful, or a negative error code on failure. */ int snd_pcm_hw_constraint_step(struct snd_pcm_runtime *runtime, unsigned int cond, @@ -1444,6 +1468,8 @@ static int snd_pcm_hw_rule_pow2(struct snd_pcm_hw_params *params, struct snd_pcm * @runtime: PCM runtime instance * @cond: condition bits * @var: hw_params variable to apply the power-of-2 constraint + * + * Return: Zero if successful, or a negative error code on failure. */ int snd_pcm_hw_constraint_pow2(struct snd_pcm_runtime *runtime, unsigned int cond, @@ -1470,6 +1496,8 @@ static int snd_pcm_hw_rule_noresample_func(struct snd_pcm_hw_params *params, * snd_pcm_hw_rule_noresample - add a rule to allow disabling hw resampling * @runtime: PCM runtime instance * @base_rate: the rate at which the hardware does not resample + * + * Return: Zero if successful, or a negative error code on failure. */ int snd_pcm_hw_rule_noresample(struct snd_pcm_runtime *runtime, unsigned int base_rate) @@ -1519,8 +1547,8 @@ EXPORT_SYMBOL(_snd_pcm_hw_params_any); * @var: parameter to retrieve * @dir: pointer to the direction (-1,0,1) or %NULL * - * Return the value for field @var if it's fixed in configuration space - * defined by @params. Return -%EINVAL otherwise. + * Return: The value for field @var if it's fixed in configuration space + * defined by @params. -%EINVAL otherwise. */ int snd_pcm_hw_param_value(const struct snd_pcm_hw_params *params, snd_pcm_hw_param_t var, int *dir) @@ -1591,7 +1619,8 @@ static int _snd_pcm_hw_param_first(struct snd_pcm_hw_params *params, * * Inside configuration space defined by @params remove from @var all * values > minimum. Reduce configuration space accordingly. - * Return the minimum. + * + * Return: The minimum, or a negative error code on failure. */ int snd_pcm_hw_param_first(struct snd_pcm_substream *pcm, struct snd_pcm_hw_params *params, @@ -1637,7 +1666,8 @@ static int _snd_pcm_hw_param_last(struct snd_pcm_hw_params *params, * * Inside configuration space defined by @params remove from @var all * values < maximum. Reduce configuration space accordingly. - * Return the maximum. + * + * Return: The maximum, or a negative error code on failure. */ int snd_pcm_hw_param_last(struct snd_pcm_substream *pcm, struct snd_pcm_hw_params *params, @@ -1665,6 +1695,8 @@ EXPORT_SYMBOL(snd_pcm_hw_param_last); * The configuration chosen is that obtained fixing in this order: * first access, first format, first subformat, min channels, * min rate, min period time, max buffer size, min tick time + * + * Return: Zero if successful, or a negative error code on failure. */ int snd_pcm_hw_params_choose(struct snd_pcm_substream *pcm, struct snd_pcm_hw_params *params) @@ -1771,7 +1803,7 @@ static int snd_pcm_lib_ioctl_fifo_size(struct snd_pcm_substream *substream, * Processes the generic ioctl commands for PCM. * Can be passed as the ioctl callback for PCM ops. * - * Returns zero if successful, or a negative error code on failure. + * Return: Zero if successful, or a negative error code on failure. */ int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream, unsigned int cmd, void *arg) @@ -2510,7 +2542,7 @@ static void pcm_chmap_ctl_private_free(struct snd_kcontrol *kcontrol) * @info_ret: store struct snd_pcm_chmap instance if non-NULL * * Create channel-mapping control elements assigned to the given PCM stream(s). - * Returns zero if succeed, or a negative error value. + * Return: Zero if successful, or a negative error value. */ int snd_pcm_add_chmap_ctls(struct snd_pcm *pcm, int stream, const struct snd_pcm_chmap_elem *chmap, diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c index 69e01c4fc32d..0af622c34e19 100644 --- a/sound/core/pcm_memory.c +++ b/sound/core/pcm_memory.c @@ -95,7 +95,7 @@ static void snd_pcm_lib_preallocate_dma_free(struct snd_pcm_substream *substream * * Releases the pre-allocated buffer of the given substream. * - * Returns zero if successful, or a negative error code on failure. + * Return: Zero if successful, or a negative error code on failure. */ int snd_pcm_lib_preallocate_free(struct snd_pcm_substream *substream) { @@ -115,7 +115,7 @@ int snd_pcm_lib_preallocate_free(struct snd_pcm_substream *substream) * * Releases all the pre-allocated buffers on the given pcm. * - * Returns zero if successful, or a negative error code on failure. + * Return: Zero if successful, or a negative error code on failure. */ int snd_pcm_lib_preallocate_free_for_all(struct snd_pcm *pcm) { @@ -265,7 +265,7 @@ static int snd_pcm_lib_preallocate_pages1(struct snd_pcm_substream *substream, * destruction time. The dma_buf_id must be unique for all systems * (in the same DMA buffer type) e.g. using snd_dma_pci_buf_id(). * - * Returns zero if successful, or a negative error code on failure. + * Return: Zero if successful, or a negative error code on failure. */ int snd_pcm_lib_preallocate_pages(struct snd_pcm_substream *substream, int type, struct device *data, @@ -289,7 +289,7 @@ EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages); * Do pre-allocation to all substreams of the given pcm for the * specified DMA type. * - * Returns zero if successful, or a negative error code on failure. + * Return: Zero if successful, or a negative error code on failure. */ int snd_pcm_lib_preallocate_pages_for_all(struct snd_pcm *pcm, int type, void *data, @@ -313,8 +313,9 @@ EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages_for_all); * @substream: the pcm substream instance * @offset: the buffer offset * - * Returns the page struct at the given buffer offset. * Used as the page callback of PCM ops. + * + * Return: The page struct at the given buffer offset. %NULL on failure. */ struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream, unsigned long offset) { @@ -337,7 +338,7 @@ EXPORT_SYMBOL(snd_pcm_sgbuf_ops_page); * Allocates the DMA buffer on the BUS type given earlier to * snd_pcm_lib_preallocate_xxx_pages(). * - * Returns 1 if the buffer is changed, 0 if not changed, or a negative + * Return: 1 if the buffer is changed, 0 if not changed, or a negative * code on failure. */ int snd_pcm_lib_malloc_pages(struct snd_pcm_substream *substream, size_t size) @@ -390,7 +391,7 @@ EXPORT_SYMBOL(snd_pcm_lib_malloc_pages); * * Releases the DMA buffer allocated via snd_pcm_lib_malloc_pages(). * - * Returns zero if successful, or a negative error code on failure. + * Return: Zero if successful, or a negative error code on failure. */ int snd_pcm_lib_free_pages(struct snd_pcm_substream *substream) { @@ -437,6 +438,8 @@ EXPORT_SYMBOL(_snd_pcm_lib_alloc_vmalloc_buffer); * snd_pcm_lib_free_vmalloc_buffer - free vmalloc buffer * @substream: the substream with a buffer allocated by * snd_pcm_lib_alloc_vmalloc_buffer() + * + * Return: Zero if successful, or a negative error code on failure. */ int snd_pcm_lib_free_vmalloc_buffer(struct snd_pcm_substream *substream) { @@ -458,6 +461,8 @@ EXPORT_SYMBOL(snd_pcm_lib_free_vmalloc_buffer); * @offset: offset in the buffer * * This function is to be used as the page callback in the PCM ops. + * + * Return: The page struct, or %NULL on failure. */ struct page *snd_pcm_lib_get_vmalloc_page(struct snd_pcm_substream *substream, unsigned long offset) diff --git a/sound/core/pcm_misc.c b/sound/core/pcm_misc.c index d4fc1bfbe457..b875b19f2d55 100644 --- a/sound/core/pcm_misc.c +++ b/sound/core/pcm_misc.c @@ -213,7 +213,7 @@ static struct pcm_format_data pcm_formats[(INT)SNDRV_PCM_FORMAT_LAST+1] = { * snd_pcm_format_signed - Check the PCM format is signed linear * @format: the format to check * - * Returns 1 if the given PCM format is signed linear, 0 if unsigned + * Return: 1 if the given PCM format is signed linear, 0 if unsigned * linear, and a negative error code for non-linear formats. */ int snd_pcm_format_signed(snd_pcm_format_t format) @@ -232,7 +232,7 @@ EXPORT_SYMBOL(snd_pcm_format_signed); * snd_pcm_format_unsigned - Check the PCM format is unsigned linear * @format: the format to check * - * Returns 1 if the given PCM format is unsigned linear, 0 if signed + * Return: 1 if the given PCM format is unsigned linear, 0 if signed * linear, and a negative error code for non-linear formats. */ int snd_pcm_format_unsigned(snd_pcm_format_t format) @@ -251,7 +251,7 @@ EXPORT_SYMBOL(snd_pcm_format_unsigned); * snd_pcm_format_linear - Check the PCM format is linear * @format: the format to check * - * Returns 1 if the given PCM format is linear, 0 if not. + * Return: 1 if the given PCM format is linear, 0 if not. */ int snd_pcm_format_linear(snd_pcm_format_t format) { @@ -264,7 +264,7 @@ EXPORT_SYMBOL(snd_pcm_format_linear); * snd_pcm_format_little_endian - Check the PCM format is little-endian * @format: the format to check * - * Returns 1 if the given PCM format is little-endian, 0 if + * Return: 1 if the given PCM format is little-endian, 0 if * big-endian, or a negative error code if endian not specified. */ int snd_pcm_format_little_endian(snd_pcm_format_t format) @@ -283,7 +283,7 @@ EXPORT_SYMBOL(snd_pcm_format_little_endian); * snd_pcm_format_big_endian - Check the PCM format is big-endian * @format: the format to check * - * Returns 1 if the given PCM format is big-endian, 0 if + * Return: 1 if the given PCM format is big-endian, 0 if * little-endian, or a negative error code if endian not specified. */ int snd_pcm_format_big_endian(snd_pcm_format_t format) @@ -302,7 +302,7 @@ EXPORT_SYMBOL(snd_pcm_format_big_endian); * snd_pcm_format_width - return the bit-width of the format * @format: the format to check * - * Returns the bit-width of the format, or a negative error code + * Return: The bit-width of the format, or a negative error code * if unknown format. */ int snd_pcm_format_width(snd_pcm_format_t format) @@ -321,7 +321,7 @@ EXPORT_SYMBOL(snd_pcm_format_width); * snd_pcm_format_physical_width - return the physical bit-width of the format * @format: the format to check * - * Returns the physical bit-width of the format, or a negative error code + * Return: The physical bit-width of the format, or a negative error code * if unknown format. */ int snd_pcm_format_physical_width(snd_pcm_format_t format) @@ -341,7 +341,7 @@ EXPORT_SYMBOL(snd_pcm_format_physical_width); * @format: the format to check * @samples: sampling rate * - * Returns the byte size of the given samples for the format, or a + * Return: The byte size of the given samples for the format, or a * negative error code if unknown format. */ ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples) @@ -358,7 +358,7 @@ EXPORT_SYMBOL(snd_pcm_format_size); * snd_pcm_format_silence_64 - return the silent data in 8 bytes array * @format: the format to check * - * Returns the format pattern to fill or NULL if error. + * Return: The format pattern to fill or %NULL if error. */ const unsigned char *snd_pcm_format_silence_64(snd_pcm_format_t format) { @@ -379,7 +379,7 @@ EXPORT_SYMBOL(snd_pcm_format_silence_64); * * Sets the silence data on the buffer for the given samples. * - * Returns zero if successful, or a negative error code on failure. + * Return: Zero if successful, or a negative error code on failure. */ int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int samples) { @@ -449,7 +449,7 @@ EXPORT_SYMBOL(snd_pcm_format_set_silence); * Determines the rate_min and rate_max fields from the rates bits of * the given runtime->hw. * - * Returns zero if successful. + * Return: Zero if successful. */ int snd_pcm_limit_hw_rates(struct snd_pcm_runtime *runtime) { @@ -475,7 +475,7 @@ EXPORT_SYMBOL(snd_pcm_limit_hw_rates); * snd_pcm_rate_to_rate_bit - converts sample rate to SNDRV_PCM_RATE_xxx bit * @rate: the sample rate to convert * - * Returns the SNDRV_PCM_RATE_xxx flag that corresponds to the given rate, or + * Return: The SNDRV_PCM_RATE_xxx flag that corresponds to the given rate, or * SNDRV_PCM_RATE_KNOT for an unknown rate. */ unsigned int snd_pcm_rate_to_rate_bit(unsigned int rate) @@ -493,8 +493,8 @@ EXPORT_SYMBOL(snd_pcm_rate_to_rate_bit); * snd_pcm_rate_bit_to_rate - converts SNDRV_PCM_RATE_xxx bit to sample rate * @rate_bit: the rate bit to convert * - * Returns the sample rate that corresponds to the given SNDRV_PCM_RATE_xxx flag - * or 0 for an unknown rate bit + * Return: The sample rate that corresponds to the given SNDRV_PCM_RATE_xxx flag + * or 0 for an unknown rate bit. */ unsigned int snd_pcm_rate_bit_to_rate(unsigned int rate_bit) { diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 71ae86ca64ac..5bce9152b64e 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -898,6 +898,8 @@ static struct action_ops snd_pcm_action_start = { /** * snd_pcm_start - start all linked streams * @substream: the PCM substream instance + * + * Return: Zero if successful, or a negative error code. */ int snd_pcm_start(struct snd_pcm_substream *substream) { @@ -951,6 +953,8 @@ static struct action_ops snd_pcm_action_stop = { * @state: PCM state after stopping the stream * * The state of each stream is then changed to the given state unconditionally. + * + * Return: Zero if succesful, or a negative error code. */ int snd_pcm_stop(struct snd_pcm_substream *substream, snd_pcm_state_t state) { @@ -965,6 +969,8 @@ EXPORT_SYMBOL(snd_pcm_stop); * * After stopping, the state is changed to SETUP. * Unlike snd_pcm_stop(), this affects only the given stream. + * + * Return: Zero if succesful, or a negative error code. */ int snd_pcm_drain_done(struct snd_pcm_substream *substream) { @@ -1098,6 +1104,9 @@ static struct action_ops snd_pcm_action_suspend = { * @substream: the PCM substream * * After this call, all streams are changed to SUSPENDED state. + * + * Return: Zero if successful (or @substream is %NULL), or a negative error + * code. */ int snd_pcm_suspend(struct snd_pcm_substream *substream) { @@ -1120,6 +1129,8 @@ EXPORT_SYMBOL(snd_pcm_suspend); * @pcm: the PCM instance * * After this call, all streams are changed to SUSPENDED state. + * + * Return: Zero if successful (or @pcm is %NULL), or a negative error code. */ int snd_pcm_suspend_all(struct snd_pcm *pcm) { @@ -1343,6 +1354,8 @@ static struct action_ops snd_pcm_action_prepare = { * snd_pcm_prepare - prepare the PCM substream to be triggerable * @substream: the PCM substream instance * @file: file to refer f_flags + * + * Return: Zero if successful, or a negative error code. */ static int snd_pcm_prepare(struct snd_pcm_substream *substream, struct file *file) diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 1bb95aeea084..7b596b5751db 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -863,7 +863,7 @@ static int snd_rawmidi_control_ioctl(struct snd_card *card, * * Reads the data from the internal buffer. * - * Returns the size of read data, or a negative error code on failure. + * Return: The size of read data, or a negative error code on failure. */ int snd_rawmidi_receive(struct snd_rawmidi_substream *substream, const unsigned char *buffer, int count) @@ -1024,8 +1024,8 @@ static ssize_t snd_rawmidi_read(struct file *file, char __user *buf, size_t coun /** * snd_rawmidi_transmit_empty - check whether the output buffer is empty * @substream: the rawmidi substream - * - * Returns 1 if the internal output buffer is empty, 0 if not. + * + * Return: 1 if the internal output buffer is empty, 0 if not. */ int snd_rawmidi_transmit_empty(struct snd_rawmidi_substream *substream) { @@ -1055,7 +1055,7 @@ int snd_rawmidi_transmit_empty(struct snd_rawmidi_substream *substream) * and call snd_rawmidi_transmit_ack() after the transmission is * finished. * - * Returns the size of copied data, or a negative error code on failure. + * Return: The size of copied data, or a negative error code on failure. */ int snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream, unsigned char *buffer, int count) @@ -1107,7 +1107,7 @@ int snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream, * the given size and updates the condition. * Call after the transmission is finished. * - * Returns the advanced size if successful, or a negative error code on failure. + * Return: The advanced size if successful, or a negative error code on failure. */ int snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count) { @@ -1140,7 +1140,7 @@ int snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count) * * Copies data from the buffer to the device and advances the pointer. * - * Returns the copied size if successful, or a negative error code on failure. + * Return: The copied size if successful, or a negative error code on failure. */ int snd_rawmidi_transmit(struct snd_rawmidi_substream *substream, unsigned char *buffer, int count) @@ -1438,7 +1438,7 @@ static int snd_rawmidi_alloc_substreams(struct snd_rawmidi *rmidi, * Creates a new rawmidi instance. * Use snd_rawmidi_set_ops() to set the operators to the new instance. * - * Returns zero if successful, or a negative error code on failure. + * Return: Zero if successful, or a negative error code on failure. */ int snd_rawmidi_new(struct snd_card *card, char *id, int device, int output_count, int input_count, diff --git a/sound/core/sound.c b/sound/core/sound.c index 70ccdab74153..f002bd911dae 100644 --- a/sound/core/sound.c +++ b/sound/core/sound.c @@ -102,6 +102,9 @@ static void snd_request_other(int minor) * This function increments the reference counter of the card instance * if an associated instance with the given minor number and type is found. * The caller must call snd_card_unref() appropriately later. + * + * Return: The user data pointer if the specified device is found. %NULL + * otherwise. */ void *snd_lookup_minor_data(unsigned int minor, int type) { @@ -261,7 +264,7 @@ static int snd_kernel_minor(int type, struct snd_card *card, int dev) * Registers an ALSA device file for the given card. * The operators have to be set in reg parameter. * - * Returns zero if successful, or a negative error code on failure. + * Return: Zero if successful, or a negative error code on failure. */ int snd_register_device_for_dev(int type, struct snd_card *card, int dev, const struct file_operations *f_ops, @@ -339,7 +342,7 @@ static int find_snd_minor(int type, struct snd_card *card, int dev) * Unregisters the device file already registered via * snd_register_device(). * - * Returns zero if sucecessful, or a negative error code on failure + * Return: Zero if successful, or a negative error code on failure. */ int snd_unregister_device(int type, struct snd_card *card, int dev) { diff --git a/sound/core/vmaster.c b/sound/core/vmaster.c index 857586135d18..55c9d8c8d3c1 100644 --- a/sound/core/vmaster.c +++ b/sound/core/vmaster.c @@ -362,8 +362,7 @@ static void master_free(struct snd_kcontrol *kcontrol) * @name: name string of the control element to create * @tlv: optional TLV int array for dB information * - * Creates a virtual matster control with the given name string. - * Returns the created control element, or NULL for errors (ENOMEM). + * Creates a virtual master control with the given name string. * * After creating a vmaster element, you can add the slave controls * via snd_ctl_add_slave() or snd_ctl_add_slave_uncached(). @@ -372,6 +371,8 @@ static void master_free(struct snd_kcontrol *kcontrol) * for dB scale of the master control. It should be a single element * with #SNDRV_CTL_TLVT_DB_SCALE, #SNDRV_CTL_TLV_DB_MINMAX or * #SNDRV_CTL_TLVT_DB_MINMAX_MUTE type, and should be the max 0dB. + * + * Return: The created control element, or %NULL for errors (ENOMEM). */ struct snd_kcontrol *snd_ctl_make_virtual_master(char *name, const unsigned int *tlv) @@ -423,6 +424,8 @@ EXPORT_SYMBOL(snd_ctl_make_virtual_master); * * Adds the given hook to the vmaster control element so that it's called * at each time when the value is changed. + * + * Return: Zero. */ int snd_ctl_add_vmaster_hook(struct snd_kcontrol *kcontrol, void (*hook)(void *private_data, int), diff --git a/sound/drivers/mpu401/mpu401_uart.c b/sound/drivers/mpu401/mpu401_uart.c index 4608c2ca43f8..e3a90d043f03 100644 --- a/sound/drivers/mpu401/mpu401_uart.c +++ b/sound/drivers/mpu401/mpu401_uart.c @@ -129,6 +129,8 @@ static void _snd_mpu401_uart_interrupt(struct snd_mpu401 *mpu) * @dev_id: mpu401 instance * * Processes the interrupt for MPU401-UART i/o. + * + * Return: %IRQ_HANDLED if the interrupt was handled. %IRQ_NONE otherwise. */ irqreturn_t snd_mpu401_uart_interrupt(int irq, void *dev_id) { @@ -148,6 +150,8 @@ EXPORT_SYMBOL(snd_mpu401_uart_interrupt); * @dev_id: mpu401 instance * * Processes the interrupt for MPU401-UART output. + * + * Return: %IRQ_HANDLED if the interrupt was handled. %IRQ_NONE otherwise. */ irqreturn_t snd_mpu401_uart_interrupt_tx(int irq, void *dev_id) { @@ -519,7 +523,7 @@ static void snd_mpu401_uart_free(struct snd_rawmidi *rmidi) * not the mpu401 instance itself. To access to the mpu401 instance, * cast from rawmidi->private_data (with struct snd_mpu401 magic-cast). * - * Returns zero if successful, or a negative error code. + * Return: Zero if successful, or a negative error code. */ int snd_mpu401_uart_new(struct snd_card *card, int device, unsigned short hardware, diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 8b0f99688303..d37c683cfd7a 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -299,7 +299,7 @@ EXPORT_SYMBOL(snd_ac97_write); * Reads a value from the given register. This will invoke the read * callback directly after the register check. * - * Returns the read value. + * Return: The read value. */ unsigned short snd_ac97_read(struct snd_ac97 *ac97, unsigned short reg) { @@ -352,7 +352,7 @@ EXPORT_SYMBOL(snd_ac97_write_cache); * Compares the value with the register cache and updates the value * only when the value is changed. * - * Returns 1 if the value is changed, 0 if no change, or a negative + * Return: 1 if the value is changed, 0 if no change, or a negative * code on failure. */ int snd_ac97_update(struct snd_ac97 *ac97, unsigned short reg, unsigned short value) @@ -384,7 +384,7 @@ EXPORT_SYMBOL(snd_ac97_update); * Updates the masked-bits on the given register only when the value * is changed. * - * Returns 1 if the bits are changed, 0 if no change, or a negative + * Return: 1 if the bits are changed, 0 if no change, or a negative * code on failure. */ int snd_ac97_update_bits(struct snd_ac97 *ac97, unsigned short reg, unsigned short mask, unsigned short value) @@ -1836,7 +1836,7 @@ void snd_ac97_get_name(struct snd_ac97 *ac97, unsigned int id, char *name, int m * snd_ac97_get_short_name - retrieve codec name * @ac97: the codec instance * - * Returns the short identifying name of the codec. + * Return: The short identifying name of the codec. */ const char *snd_ac97_get_short_name(struct snd_ac97 *ac97) { @@ -1910,7 +1910,7 @@ static int ac97_reset_wait(struct snd_ac97 *ac97, int timeout, int with_modem) * The AC97 bus instance is registered as a low-level device, so you don't * have to release it manually. * - * Returns zero if successful, or a negative error code on failure. + * Return: Zero if successful, or a negative error code on failure. */ int snd_ac97_bus(struct snd_card *card, int num, struct snd_ac97_bus_ops *ops, void *private_data, struct snd_ac97_bus **rbus) @@ -2006,7 +2006,7 @@ static void do_update_power(struct work_struct *work) * The ac97 instance is registered as a low-level device, so you don't * have to release it manually. * - * Returns zero if successful, or a negative error code on failure. + * Return: Zero if successful, or a negative error code on failure. */ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template, struct snd_ac97 **rac97) { @@ -2373,6 +2373,8 @@ static struct ac97_power_reg power_regs[PWIDX_SIZE] = { * @powerup: non-zero when power up the part * * Update the AC97 powerdown register bits of the given part. + * + * Return: Zero. */ int snd_ac97_update_power(struct snd_ac97 *ac97, int reg, int powerup) { @@ -2885,7 +2887,7 @@ static int apply_quirk_str(struct snd_ac97 *ac97, const char *typestr) * headphone (true line-out) control as "Master". * The quirk-list must be terminated with a zero-filled entry. * - * Returns zero if successful, or a negative error code on failure. + * Return: Zero if successful, or a negative error code on failure. */ int snd_ac97_tune_hardware(struct snd_ac97 *ac97, struct ac97_quirk *quirk, const char *override) diff --git a/sound/pci/ac97/ac97_pcm.c b/sound/pci/ac97/ac97_pcm.c index f1488fc176d5..eab0fc9ff2e0 100644 --- a/sound/pci/ac97/ac97_pcm.c +++ b/sound/pci/ac97/ac97_pcm.c @@ -253,7 +253,7 @@ static int set_spdif_rate(struct snd_ac97 *ac97, unsigned short rate) * AC97_SPDIF is accepted as a pseudo register to modify the SPDIF * status bits. * - * Returns zero if successful, or a negative error code on failure. + * Return: Zero if successful, or a negative error code on failure. */ int snd_ac97_set_rate(struct snd_ac97 *ac97, int reg, unsigned int rate) { @@ -440,6 +440,8 @@ static unsigned int get_rates(struct ac97_pcm *pcm, unsigned int cidx, unsigned * It assigns available AC97 slots for given PCMs. If none or only * some slots are available, pcm->xxx.slots and pcm->xxx.rslots[] members * are reduced and might be zero. + * + * Return: Zero if successful, or a negative error code on failure. */ int snd_ac97_pcm_assign(struct snd_ac97_bus *bus, unsigned short pcms_count, @@ -562,6 +564,8 @@ EXPORT_SYMBOL(snd_ac97_pcm_assign); * @slots: a subset of allocated slots (snd_ac97_pcm_assign) for this pcm * * It locks the specified slots and sets the given rate to AC97 registers. + * + * Return: Zero if successful, or a negative error code on failure. */ int snd_ac97_pcm_open(struct ac97_pcm *pcm, unsigned int rate, enum ac97_pcm_cfg cfg, unsigned short slots) @@ -644,6 +648,8 @@ EXPORT_SYMBOL(snd_ac97_pcm_open); * @pcm: the ac97 pcm instance * * It frees the locked AC97 slots. + * + * Return: Zero. */ int snd_ac97_pcm_close(struct ac97_pcm *pcm) { @@ -718,6 +724,8 @@ static int double_rate_hw_constraint_channels(struct snd_pcm_hw_params *params, * * Installs the hardware constraint rules to prevent using double rates and * more than two channels at the same time. + * + * Return: Zero if successful, or a negative error code on failure. */ int snd_ac97_pcm_double_rate_rules(struct snd_pcm_runtime *runtime) { diff --git a/sound/sound_core.c b/sound/sound_core.c index bb23009edc8d..359753fc24e1 100644 --- a/sound/sound_core.c +++ b/sound/sound_core.c @@ -352,7 +352,9 @@ static struct sound_unit *chains[SOUND_STEP]; * @dev: device pointer * * Allocate a special sound device by minor number from the sound - * subsystem. The allocated number is returned on success. On failure + * subsystem. + * + * Return: The allocated number is returned on success. On failure, * a negative error code is returned. */ @@ -436,8 +438,10 @@ EXPORT_SYMBOL(register_sound_special); * @dev: Unit number to allocate * * Allocate a mixer device. Unit is the number of the mixer requested. - * Pass -1 to request the next free mixer unit. On success the allocated - * number is returned, on failure a negative error code is returned. + * Pass -1 to request the next free mixer unit. + * + * Return: On success, the allocated number is returned. On failure, + * a negative error code is returned. */ int register_sound_mixer(const struct file_operations *fops, int dev) @@ -454,8 +458,10 @@ EXPORT_SYMBOL(register_sound_mixer); * @dev: Unit number to allocate * * Allocate a midi device. Unit is the number of the midi device requested. - * Pass -1 to request the next free midi unit. On success the allocated - * number is returned, on failure a negative error code is returned. + * Pass -1 to request the next free midi unit. + * + * Return: On success, the allocated number is returned. On failure, + * a negative error code is returned. */ int register_sound_midi(const struct file_operations *fops, int dev) @@ -477,11 +483,13 @@ EXPORT_SYMBOL(register_sound_midi); * @dev: Unit number to allocate * * Allocate a DSP device. Unit is the number of the DSP requested. - * Pass -1 to request the next free DSP unit. On success the allocated - * number is returned, on failure a negative error code is returned. + * Pass -1 to request the next free DSP unit. * * This function allocates both the audio and dsp device entries together * and will always allocate them as a matching pair - eg dsp3/audio3 + * + * Return: On success, the allocated number is returned. On failure, + * a negative error code is returned. */ int register_sound_dsp(const struct file_operations *fops, int dev) -- cgit v1.2.3 From 030e79f658de11da43d32e7ad814b5d2d64c8bac Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 11 Mar 2013 18:27:21 -0700 Subject: ASoC: add snd_soc_register_component() Current ASoC has register function for platform/codec/dai/card, but doesn't have for cpu. It often produces confusion and fault on ASoC. As result of ASoC community discussion, we consider new struct snd_soc_component for CPU/CODEC, and will switch over to use it. This patch adds very basic struct snd_soc_component, and register function for it. Signed-off-by: Kuninori Morimoto Acked-by: Liam Girdwood Reviewed-by: Stephen Warren Signed-off-by: Mark Brown --- include/sound/soc.h | 19 +++++++++++++ sound/soc/soc-core.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+) (limited to 'include/sound') diff --git a/include/sound/soc.h b/include/sound/soc.h index a6a059ca3874..8c46d0a7e2c0 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -324,6 +324,8 @@ struct snd_soc_dai_link; struct snd_soc_platform_driver; struct snd_soc_codec; struct snd_soc_codec_driver; +struct snd_soc_component; +struct snd_soc_component_driver; struct soc_enum; struct snd_soc_jack; struct snd_soc_jack_zone; @@ -377,6 +379,10 @@ int snd_soc_register_codec(struct device *dev, const struct snd_soc_codec_driver *codec_drv, struct snd_soc_dai_driver *dai_drv, int num_dai); void snd_soc_unregister_codec(struct device *dev); +int snd_soc_register_component(struct device *dev, + const struct snd_soc_component_driver *cmpnt_drv, + struct snd_soc_dai_driver *dai_drv, int num_dai); +void snd_soc_unregister_component(struct device *dev); int snd_soc_codec_volatile_register(struct snd_soc_codec *codec, unsigned int reg); int snd_soc_codec_readable_register(struct snd_soc_codec *codec, @@ -841,6 +847,19 @@ struct snd_soc_platform { #endif }; +struct snd_soc_component_driver { +}; + +struct snd_soc_component { + const char *name; + int id; + int num_dai; + struct device *dev; + struct list_head list; + + const struct snd_soc_component_driver *driver; +}; + struct snd_soc_dai_link { /* config - must be set by machine driver */ const char *name; /* Codec name */ diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index b7e84a7cd9ee..9e6118573fef 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -58,6 +58,7 @@ static DEFINE_MUTEX(client_mutex); static LIST_HEAD(dai_list); static LIST_HEAD(platform_list); static LIST_HEAD(codec_list); +static LIST_HEAD(component_list); /* * This is a timeout to do a DAPM powerdown after a stream is closed(). @@ -4137,6 +4138,82 @@ found: } EXPORT_SYMBOL_GPL(snd_soc_unregister_codec); + +/** + * snd_soc_register_component - Register a component with the ASoC core + * + */ +int snd_soc_register_component(struct device *dev, + const struct snd_soc_component_driver *cmpnt_drv, + struct snd_soc_dai_driver *dai_drv, + int num_dai) +{ + struct snd_soc_component *cmpnt; + int ret; + + dev_dbg(dev, "component register %s\n", dev_name(dev)); + + cmpnt = devm_kzalloc(dev, sizeof(*cmpnt), GFP_KERNEL); + if (!cmpnt) { + dev_err(dev, "ASoC: Failed to allocate memory\n"); + return -ENOMEM; + } + + cmpnt->name = fmt_single_name(dev, &cmpnt->id); + if (!cmpnt->name) { + dev_err(dev, "ASoC: Failed to simplifying name\n"); + return -ENOMEM; + } + + cmpnt->dev = dev; + cmpnt->driver = cmpnt_drv; + cmpnt->num_dai = num_dai; + + ret = snd_soc_register_dais(dev, dai_drv, num_dai); + if (ret < 0) { + dev_err(dev, "ASoC: Failed to regster DAIs: %d\n", ret); + goto error_component_name; + } + + mutex_lock(&client_mutex); + list_add(&cmpnt->list, &component_list); + mutex_unlock(&client_mutex); + + dev_dbg(cmpnt->dev, "ASoC: Registered component '%s'\n", cmpnt->name); + + return ret; + +error_component_name: + kfree(cmpnt->name); + + return ret; +} + +/** + * snd_soc_unregister_component - Unregister a component from the ASoC core + * + */ +void snd_soc_unregister_component(struct device *dev) +{ + struct snd_soc_component *cmpnt; + + list_for_each_entry(cmpnt, &component_list, list) { + if (dev == cmpnt->dev) + goto found; + } + return; + +found: + snd_soc_unregister_dais(dev, cmpnt->num_dai); + + mutex_lock(&client_mutex); + list_del(&cmpnt->list); + mutex_unlock(&client_mutex); + + dev_dbg(dev, "ASoC: Unregistered component '%s'\n", cmpnt->name); + kfree(cmpnt->name); +} + /* Retrieve a card's name from device tree */ int snd_soc_of_parse_card_name(struct snd_soc_card *card, const char *propname) -- cgit v1.2.3 From 61782e4f5eb593958582524aad9b14dc98b1b56c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 14 Mar 2013 00:18:41 -0700 Subject: ASoC: add .name for snd_soc_component_driver This patch adds .name member on snd_soc_component_driver. But this patch doesn't care about whether cmpnt_drv was NULL, and/or its name was NULL in snd_soc_register_component() at this point. Because, it is easy to switch over to snd_soc_register_component() from snd_soc_register_dais() if it doesn't care cmpnt_drv was NULL. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/soc.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/sound') diff --git a/include/sound/soc.h b/include/sound/soc.h index 8c46d0a7e2c0..44c9cbdc9fa2 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -848,6 +848,7 @@ struct snd_soc_platform { }; struct snd_soc_component_driver { + const char *name; }; struct snd_soc_component { -- cgit v1.2.3 From b1bd7f62cf2b854316a9a8b2442a8014dbe29a47 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 22 Mar 2013 14:12:14 +0100 Subject: ASoC: dmaengine-pcm: Remove snd_dmaengine_pcm_{set,get}_data These functions were initially added to be able to support some oddball dma drivers, but all users have been updated to deal with the situation without the help of snd_dmaengine_pcm_{set,get}_data, so these two functions can be removed. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- include/sound/dmaengine_pcm.h | 3 --- sound/soc/soc-dmaengine-pcm.c | 29 ----------------------------- 2 files changed, 32 deletions(-) (limited to 'include/sound') diff --git a/include/sound/dmaengine_pcm.h b/include/sound/dmaengine_pcm.h index b877334bbb0f..f8a70312adb8 100644 --- a/include/sound/dmaengine_pcm.h +++ b/include/sound/dmaengine_pcm.h @@ -32,9 +32,6 @@ snd_pcm_substream_to_dma_direction(const struct snd_pcm_substream *substream) return DMA_DEV_TO_MEM; } -void snd_dmaengine_pcm_set_data(struct snd_pcm_substream *substream, void *data); -void *snd_dmaengine_pcm_get_data(struct snd_pcm_substream *substream); - int snd_hwparams_to_dma_slave_config(const struct snd_pcm_substream *substream, const struct snd_pcm_hw_params *params, struct dma_slave_config *slave_config); int snd_dmaengine_pcm_trigger(struct snd_pcm_substream *substream, int cmd); diff --git a/sound/soc/soc-dmaengine-pcm.c b/sound/soc/soc-dmaengine-pcm.c index 111b7d921e89..e8b1215b8c1b 100644 --- a/sound/soc/soc-dmaengine-pcm.c +++ b/sound/soc/soc-dmaengine-pcm.c @@ -33,8 +33,6 @@ struct dmaengine_pcm_runtime_data { dma_cookie_t cookie; unsigned int pos; - - void *data; }; static inline struct dmaengine_pcm_runtime_data *substream_to_prtd( @@ -43,33 +41,6 @@ static inline struct dmaengine_pcm_runtime_data *substream_to_prtd( return substream->runtime->private_data; } -/** - * snd_dmaengine_pcm_set_data - Set dmaengine substream private data - * @substream: PCM substream - * @data: Data to set - */ -void snd_dmaengine_pcm_set_data(struct snd_pcm_substream *substream, void *data) -{ - struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream); - - prtd->data = data; -} -EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_set_data); - -/** - * snd_dmaengine_pcm_get_data - Get dmaeinge substream private data - * @substream: PCM substream - * - * Returns the data previously set with snd_dmaengine_pcm_set_data - */ -void *snd_dmaengine_pcm_get_data(struct snd_pcm_substream *substream) -{ - struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream); - - return prtd->data; -} -EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_get_data); - struct dma_chan *snd_dmaengine_pcm_get_chan(struct snd_pcm_substream *substream) { struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream); -- cgit v1.2.3 From f53179c026b11bef674d75154f5ea47ca3248ca9 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 21 Mar 2013 03:38:30 -0700 Subject: ASoC: snd_soc_[un]register_dai[s]() become non global function All drivers are using snd_soc_register_component() instead of snd_soc_register_dai[s]() snd_soc_[un]register_dai[s]() are no longer needed Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 8 -------- sound/soc/soc-core.c | 12 ++++-------- 2 files changed, 4 insertions(+), 16 deletions(-) (limited to 'include/sound') diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 3d84808952b9..ae9a227d35d3 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -95,14 +95,6 @@ struct snd_soc_dai_driver; struct snd_soc_dai; struct snd_ac97_bus_ops; -/* Digital Audio Interface registration */ -int snd_soc_register_dai(struct device *dev, - struct snd_soc_dai_driver *dai_drv); -void snd_soc_unregister_dai(struct device *dev); -int snd_soc_register_dais(struct device *dev, - struct snd_soc_dai_driver *dai_drv, size_t count); -void snd_soc_unregister_dais(struct device *dev, size_t count); - /* Digital Audio Interface clocking API.*/ int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int freq, int dir); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 2ecaaf13e319..f6cda7b6ce44 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3739,7 +3739,7 @@ static inline char *fmt_multiple_name(struct device *dev, * * @dai: DAI to register */ -int snd_soc_register_dai(struct device *dev, +static int snd_soc_register_dai(struct device *dev, struct snd_soc_dai_driver *dai_drv) { struct snd_soc_codec *codec; @@ -3786,14 +3786,13 @@ int snd_soc_register_dai(struct device *dev, return 0; } -EXPORT_SYMBOL_GPL(snd_soc_register_dai); /** * snd_soc_unregister_dai - Unregister a DAI from the ASoC core * * @dai: DAI to unregister */ -void snd_soc_unregister_dai(struct device *dev) +static void snd_soc_unregister_dai(struct device *dev) { struct snd_soc_dai *dai; @@ -3812,7 +3811,6 @@ found: kfree(dai->name); kfree(dai); } -EXPORT_SYMBOL_GPL(snd_soc_unregister_dai); /** * snd_soc_register_dais - Register multiple DAIs with the ASoC core @@ -3820,7 +3818,7 @@ EXPORT_SYMBOL_GPL(snd_soc_unregister_dai); * @dai: Array of DAIs to register * @count: Number of DAIs */ -int snd_soc_register_dais(struct device *dev, +static int snd_soc_register_dais(struct device *dev, struct snd_soc_dai_driver *dai_drv, size_t count) { struct snd_soc_codec *codec; @@ -3884,7 +3882,6 @@ err: return ret; } -EXPORT_SYMBOL_GPL(snd_soc_register_dais); /** * snd_soc_unregister_dais - Unregister multiple DAIs from the ASoC core @@ -3892,14 +3889,13 @@ EXPORT_SYMBOL_GPL(snd_soc_register_dais); * @dai: Array of DAIs to unregister * @count: Number of DAIs */ -void snd_soc_unregister_dais(struct device *dev, size_t count) +static void snd_soc_unregister_dais(struct device *dev, size_t count) { int i; for (i = 0; i < count; i++) snd_soc_unregister_dai(dev); } -EXPORT_SYMBOL_GPL(snd_soc_unregister_dais); /** * snd_soc_register_platform - Register a platform with the ASoC core -- cgit v1.2.3 From d79e57db84f8359bc96418900f86b8fc4189eff9 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 27 Mar 2013 12:02:22 +0100 Subject: ASoC: Constify the 'driver' field of snd_soc_platform The ASoC core does no not modify the driver of a platform. Making it const allows ASoC platform drivers to declare the snd_soc_platform_driver struct as const. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- include/sound/soc.h | 4 ++-- sound/soc/soc-core.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'include/sound') diff --git a/include/sound/soc.h b/include/sound/soc.h index c84062b22221..5fb70d1e8cce 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -371,7 +371,7 @@ int snd_soc_suspend(struct device *dev); int snd_soc_resume(struct device *dev); int snd_soc_poweroff(struct device *dev); int snd_soc_register_platform(struct device *dev, - struct snd_soc_platform_driver *platform_drv); + const struct snd_soc_platform_driver *platform_drv); void snd_soc_unregister_platform(struct device *dev); int snd_soc_register_codec(struct device *dev, const struct snd_soc_codec_driver *codec_drv, @@ -823,7 +823,7 @@ struct snd_soc_platform { const char *name; int id; struct device *dev; - struct snd_soc_platform_driver *driver; + const struct snd_soc_platform_driver *driver; struct mutex mutex; unsigned int suspended:1; /* platform is suspended */ diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 0ce075c47b25..4d24b5ea3ba7 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3906,7 +3906,7 @@ EXPORT_SYMBOL_GPL(snd_soc_unregister_dais); * @platform: platform to register */ int snd_soc_register_platform(struct device *dev, - struct snd_soc_platform_driver *platform_drv) + const struct snd_soc_platform_driver *platform_drv) { struct snd_soc_platform *platform; -- cgit v1.2.3 From 1f03f55b0ca679f950148954e807feb22cff325c Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 27 Mar 2013 12:02:23 +0100 Subject: ASoC: Constify the 'ops' field of snd_soc_platform_driver The ASoC core does not modify a platform driver's ops structure. Making it const allows ASoC platform drivers to declare their snd_pcm_ops struct as const. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- include/sound/soc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/sound') diff --git a/include/sound/soc.h b/include/sound/soc.h index 5fb70d1e8cce..966a854fc054 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -801,7 +801,7 @@ struct snd_soc_platform_driver { struct snd_soc_dai *); /* platform stream pcm ops */ - struct snd_pcm_ops *ops; + const struct snd_pcm_ops *ops; /* platform stream compress ops */ struct snd_compr_ops *compr_ops; -- cgit v1.2.3 From ef03c9ae967bf1b40bec1456f7e744033853a01d Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 27 Mar 2013 12:02:24 +0100 Subject: ASoC: Constify the 'compr_ops' field of snd_soc_platform_driver The ASoC core does not modify a platform driver's compr_ops structure. Making it const allows ASoC platform drivers to declare their snd_compr_ops struct as const. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- include/sound/soc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/sound') diff --git a/include/sound/soc.h b/include/sound/soc.h index 966a854fc054..f619905f0a65 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -804,7 +804,7 @@ struct snd_soc_platform_driver { const struct snd_pcm_ops *ops; /* platform stream compress ops */ - struct snd_compr_ops *compr_ops; + const struct snd_compr_ops *compr_ops; /* platform stream completion event */ int (*stream_event)(struct snd_soc_dapm_context *dapm, int event); -- cgit v1.2.3 From 85c9f9c5f9d09ea43daf4f1a8b81d3c7b7394d27 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 3 Apr 2013 11:06:02 +0200 Subject: ASoC: dmaengine-pcm: Add a common DAI DMA data struct This patch adds a common DMA data struct which can be used by DAI drivers to communicate their DMA configuration requirements to the DMA pcm driver. Having a common data structure for this allows us to implement common functions on top of them, which can be used by multiple platforms. This patch also introduces a new function to initialize certain fields of a dma_slave_config struct from the common DAI DMA data struct. Signed-off-by: Lars-Peter Clausen Reviewed-by: Stephen Warren Tested-by: Stephen Warren Signed-off-by: Mark Brown --- include/sound/dmaengine_pcm.h | 24 ++++++++++++++++++++++++ sound/soc/soc-dmaengine-pcm.c | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) (limited to 'include/sound') diff --git a/include/sound/dmaengine_pcm.h b/include/sound/dmaengine_pcm.h index f8a70312adb8..95620428a59b 100644 --- a/include/sound/dmaengine_pcm.h +++ b/include/sound/dmaengine_pcm.h @@ -44,4 +44,28 @@ int snd_dmaengine_pcm_close(struct snd_pcm_substream *substream); struct dma_chan *snd_dmaengine_pcm_get_chan(struct snd_pcm_substream *substream); +/** + * struct snd_dmaengine_dai_dma_data - DAI DMA configuration data + * @addr: Address of the DAI data source or destination register. + * @addr_width: Width of the DAI data source or destination register. + * @maxburst: Maximum number of words(note: words, as in units of the + * src_addr_width member, not bytes) that can be send to or received from the + * DAI in one burst. + * @slave_id: Slave requester id for the DMA channel. + * @filter_data: Custom DMA channel filter data, this will usually be used when + * requesting the DMA channel. + */ +struct snd_dmaengine_dai_dma_data { + dma_addr_t addr; + enum dma_slave_buswidth addr_width; + u32 maxburst; + unsigned int slave_id; + void *filter_data; +}; + +void snd_dmaengine_pcm_set_config_from_dai_data( + const struct snd_pcm_substream *substream, + const struct snd_dmaengine_dai_dma_data *dma_data, + struct dma_slave_config *config); + #endif diff --git a/sound/soc/soc-dmaengine-pcm.c b/sound/soc/soc-dmaengine-pcm.c index 7c24dedff971..a9a300acb506 100644 --- a/sound/soc/soc-dmaengine-pcm.c +++ b/sound/soc/soc-dmaengine-pcm.c @@ -95,6 +95,43 @@ int snd_hwparams_to_dma_slave_config(const struct snd_pcm_substream *substream, } EXPORT_SYMBOL_GPL(snd_hwparams_to_dma_slave_config); +/** + * snd_dmaengine_pcm_set_config_from_dai_data() - Initializes a dma slave config + * using DAI DMA data. + * @substream: PCM substream + * @dma_data: DAI DMA data + * @slave_config: DMA slave configuration + * + * Initializes the {dst,src}_addr, {dst,src}_maxburst, {dst,src}_addr_width and + * slave_id fields of the DMA slave config from the same fields of the DAI DMA + * data struct. The src and dst fields will be initialized depending on the + * direction of the substream. If the substream is a playback stream the dst + * fields will be initialized, if it is a capture stream the src fields will be + * initialized. The {dst,src}_addr_width field will only be initialized if the + * addr_width field of the DAI DMA data struct is not equal to + * DMA_SLAVE_BUSWIDTH_UNDEFINED. + */ +void snd_dmaengine_pcm_set_config_from_dai_data( + const struct snd_pcm_substream *substream, + const struct snd_dmaengine_dai_dma_data *dma_data, + struct dma_slave_config *slave_config) +{ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + slave_config->dst_addr = dma_data->addr; + slave_config->dst_maxburst = dma_data->maxburst; + if (dma_data->addr_width != DMA_SLAVE_BUSWIDTH_UNDEFINED) + slave_config->dst_addr_width = dma_data->addr_width; + } else { + slave_config->src_addr = dma_data->addr; + slave_config->src_maxburst = dma_data->maxburst; + if (dma_data->addr_width != DMA_SLAVE_BUSWIDTH_UNDEFINED) + slave_config->src_addr_width = dma_data->addr_width; + } + + slave_config->slave_id = dma_data->slave_id; +} +EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_set_config_from_dai_data); + static void dmaengine_pcm_dma_complete(void *arg) { struct snd_pcm_substream *substream = arg; -- cgit v1.2.3 From 7c1c1d4a7b4ca1266057a3632d27450f5575caf9 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 15 Apr 2013 19:19:48 +0200 Subject: ASoC: dmaengine-pcm: Make requesting the DMA channel at PCM open optional Refactor the dmaengine PCM library to allow the DMA channel to be requested before opening a PCM substream. snd_dmaengine_pcm_open() now expects a DMA channel instead of a filter function and filter parameter as its parameters. snd_dmaengine_pcm_close() is updated to not release the DMA channel. This allows a dmaengine based PCM driver to request its channels before the substream is opened. The patch also introduces two new functions, snd_dmaengine_pcm_open_request_chan() and snd_dmaengine_pcm_close_release_chan(), which have the same signature and behaviour of the old snd_dmaengine_pcm_{open,close}() and internally use the new variants of these functions. All users of snd_dmaengine_pcm_{open,close}() are updated to use snd_dmaengine_pcm_open_request_chan() and snd_dmaengine_pcm_close_release_chan(). Signed-off-by: Lars-Peter Clausen Tested-by: Stephen Warren Tested-by: Shawn Guo Signed-off-by: Mark Brown --- include/sound/dmaengine_pcm.h | 6 +++- sound/soc/atmel/atmel-pcm-dma.c | 6 ++-- sound/soc/cirrus/ep93xx-pcm.c | 5 +-- sound/soc/fsl/imx-pcm-dma.c | 2 +- sound/soc/mxs/mxs-pcm.c | 4 +-- sound/soc/omap/omap-pcm.c | 7 ++-- sound/soc/pxa/mmp-pcm.c | 5 +-- sound/soc/soc-dmaengine-pcm.c | 72 ++++++++++++++++++++++++++++------------- sound/soc/spear/spear_pcm.c | 5 +-- sound/soc/tegra/tegra_pcm.c | 4 +-- sound/soc/ux500/ux500_pcm.c | 6 ++-- 11 files changed, 78 insertions(+), 44 deletions(-) (limited to 'include/sound') diff --git a/include/sound/dmaengine_pcm.h b/include/sound/dmaengine_pcm.h index 95620428a59b..d015d67e75c3 100644 --- a/include/sound/dmaengine_pcm.h +++ b/include/sound/dmaengine_pcm.h @@ -39,9 +39,13 @@ snd_pcm_uframes_t snd_dmaengine_pcm_pointer(struct snd_pcm_substream *substream) snd_pcm_uframes_t snd_dmaengine_pcm_pointer_no_residue(struct snd_pcm_substream *substream); int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream, - dma_filter_fn filter_fn, void *filter_data); + struct dma_chan *chan); int snd_dmaengine_pcm_close(struct snd_pcm_substream *substream); +int snd_dmaengine_pcm_open_request_chan(struct snd_pcm_substream *substream, + dma_filter_fn filter_fn, void *filter_data); +int snd_dmaengine_pcm_close_release_chan(struct snd_pcm_substream *substream); + struct dma_chan *snd_dmaengine_pcm_get_chan(struct snd_pcm_substream *substream); /** diff --git a/sound/soc/atmel/atmel-pcm-dma.c b/sound/soc/atmel/atmel-pcm-dma.c index bb07989762d5..1d38fd0bc4e2 100644 --- a/sound/soc/atmel/atmel-pcm-dma.c +++ b/sound/soc/atmel/atmel-pcm-dma.c @@ -155,7 +155,7 @@ static int atmel_pcm_hw_params(struct snd_pcm_substream *substream, if (ssc->pdev) sdata = ssc->pdev->dev.platform_data; - ret = snd_dmaengine_pcm_open(substream, filter, sdata); + ret = snd_dmaengine_pcm_open_request_chan(substream, filter, sdata); if (ret) { pr_err("atmel-pcm: dmaengine pcm open failed\n"); return -EINVAL; @@ -171,7 +171,7 @@ static int atmel_pcm_hw_params(struct snd_pcm_substream *substream, return 0; err: - snd_dmaengine_pcm_close(substream); + snd_dmaengine_pcm_close_release_chan(substream); return ret; } @@ -197,7 +197,7 @@ static int atmel_pcm_open(struct snd_pcm_substream *substream) static struct snd_pcm_ops atmel_pcm_ops = { .open = atmel_pcm_open, - .close = snd_dmaengine_pcm_close, + .close = snd_dmaengine_pcm_close_release_chan, .ioctl = snd_pcm_lib_ioctl, .hw_params = atmel_pcm_hw_params, .prepare = atmel_pcm_dma_prepare, diff --git a/sound/soc/cirrus/ep93xx-pcm.c b/sound/soc/cirrus/ep93xx-pcm.c index 298946f790eb..488032690378 100644 --- a/sound/soc/cirrus/ep93xx-pcm.c +++ b/sound/soc/cirrus/ep93xx-pcm.c @@ -69,7 +69,8 @@ static int ep93xx_pcm_open(struct snd_pcm_substream *substream) snd_soc_set_runtime_hwparams(substream, &ep93xx_pcm_hardware); - return snd_dmaengine_pcm_open(substream, ep93xx_pcm_dma_filter, + return snd_dmaengine_pcm_open_request_chan(substream, + ep93xx_pcm_dma_filter, snd_soc_dai_get_dma_data(rtd->cpu_dai, substream)); } @@ -100,7 +101,7 @@ static int ep93xx_pcm_mmap(struct snd_pcm_substream *substream, static struct snd_pcm_ops ep93xx_pcm_ops = { .open = ep93xx_pcm_open, - .close = snd_dmaengine_pcm_close, + .close = snd_dmaengine_pcm_close_release_chan, .ioctl = snd_pcm_lib_ioctl, .hw_params = ep93xx_pcm_hw_params, .hw_free = ep93xx_pcm_hw_free, diff --git a/sound/soc/fsl/imx-pcm-dma.c b/sound/soc/fsl/imx-pcm-dma.c index ee838c8a3b11..c6647825bdd5 100644 --- a/sound/soc/fsl/imx-pcm-dma.c +++ b/sound/soc/fsl/imx-pcm-dma.c @@ -100,7 +100,7 @@ static int snd_imx_open(struct snd_pcm_substream *substream) static struct snd_pcm_ops imx_pcm_ops = { .open = snd_imx_open, - .close = snd_dmaengine_pcm_close, + .close = snd_dmaengine_pcm_close_release_chan, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_imx_pcm_hw_params, .trigger = snd_dmaengine_pcm_trigger, diff --git a/sound/soc/mxs/mxs-pcm.c b/sound/soc/mxs/mxs-pcm.c index ebbef8597554..7bceb16d0fd9 100644 --- a/sound/soc/mxs/mxs-pcm.c +++ b/sound/soc/mxs/mxs-pcm.c @@ -87,7 +87,7 @@ static int snd_mxs_open(struct snd_pcm_substream *substream) snd_soc_set_runtime_hwparams(substream, &snd_mxs_hardware); - return snd_dmaengine_pcm_open(substream, filter, + return snd_dmaengine_pcm_open_request_chan(substream, filter, snd_soc_dai_get_dma_data(rtd->cpu_dai, substream)); } @@ -104,7 +104,7 @@ static int snd_mxs_pcm_mmap(struct snd_pcm_substream *substream, static struct snd_pcm_ops mxs_pcm_ops = { .open = snd_mxs_open, - .close = snd_dmaengine_pcm_close, + .close = snd_dmaengine_pcm_close_release_chan, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_mxs_pcm_hw_params, .trigger = snd_dmaengine_pcm_trigger, diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c index c8e272f9c2de..c28e042f2208 100644 --- a/sound/soc/omap/omap-pcm.c +++ b/sound/soc/omap/omap-pcm.c @@ -118,8 +118,9 @@ static int omap_pcm_open(struct snd_pcm_substream *substream) dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); - return snd_dmaengine_pcm_open(substream, omap_dma_filter_fn, - dma_data->filter_data); + return snd_dmaengine_pcm_open_request_chan(substream, + omap_dma_filter_fn, + dma_data->filter_data); } static int omap_pcm_mmap(struct snd_pcm_substream *substream, @@ -135,7 +136,7 @@ static int omap_pcm_mmap(struct snd_pcm_substream *substream, static struct snd_pcm_ops omap_pcm_ops = { .open = omap_pcm_open, - .close = snd_dmaengine_pcm_close, + .close = snd_dmaengine_pcm_close_release_chan, .ioctl = snd_pcm_lib_ioctl, .hw_params = omap_pcm_hw_params, .hw_free = omap_pcm_hw_free, diff --git a/sound/soc/pxa/mmp-pcm.c b/sound/soc/pxa/mmp-pcm.c index 6c3980252bf6..349930015264 100644 --- a/sound/soc/pxa/mmp-pcm.c +++ b/sound/soc/pxa/mmp-pcm.c @@ -131,7 +131,8 @@ static int mmp_pcm_open(struct snd_pcm_substream *substream) dma_data.dma_res = r; dma_data.ssp_id = cpu_dai->id; - return snd_dmaengine_pcm_open(substream, filter, &dma_data); + return snd_dmaengine_pcm_open_request_chan(substream, filter, + &dma_data); } static int mmp_pcm_mmap(struct snd_pcm_substream *substream, @@ -148,7 +149,7 @@ static int mmp_pcm_mmap(struct snd_pcm_substream *substream, struct snd_pcm_ops mmp_pcm_ops = { .open = mmp_pcm_open, - .close = snd_dmaengine_pcm_close, + .close = snd_dmaengine_pcm_close_release_chan, .ioctl = snd_pcm_lib_ioctl, .hw_params = mmp_pcm_hw_params, .trigger = snd_dmaengine_pcm_trigger, diff --git a/sound/soc/soc-dmaengine-pcm.c b/sound/soc/soc-dmaengine-pcm.c index a9a300acb506..b0420a75f412 100644 --- a/sound/soc/soc-dmaengine-pcm.c +++ b/sound/soc/soc-dmaengine-pcm.c @@ -254,44 +254,38 @@ snd_pcm_uframes_t snd_dmaengine_pcm_pointer(struct snd_pcm_substream *substream) } EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_pointer); -static int dmaengine_pcm_request_channel(struct dmaengine_pcm_runtime_data *prtd, - dma_filter_fn filter_fn, void *filter_data) +static struct dma_chan *dmaengine_pcm_request_channel(dma_filter_fn filter_fn, + void *filter_data) { dma_cap_mask_t mask; dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); dma_cap_set(DMA_CYCLIC, mask); - prtd->dma_chan = dma_request_channel(mask, filter_fn, filter_data); - - if (!prtd->dma_chan) - return -ENXIO; - return 0; + return dma_request_channel(mask, filter_fn, filter_data); } /** * snd_dmaengine_pcm_open - Open a dmaengine based PCM substream * @substream: PCM substream - * @filter_fn: Filter function used to request the DMA channel - * @filter_data: Data passed to the DMA filter function + * @chan: DMA channel to use for data transfers * * Returns 0 on success, a negative error code otherwise. * - * This function will request a DMA channel using the passed filter function and - * data. The function should usually be called from the pcm open callback. - * - * Note that this function will use private_data field of the substream's - * runtime. So it is not availabe to your pcm driver implementation. If you need - * to keep additional data attached to a substream use - * snd_dmaengine_pcm_{set,get}_data. + * The function should usually be called from the pcm open callback. Note that + * this function will use private_data field of the substream's runtime. So it + * is not availabe to your pcm driver implementation. */ int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream, - dma_filter_fn filter_fn, void *filter_data) + struct dma_chan *chan) { struct dmaengine_pcm_runtime_data *prtd; int ret; + if (!chan) + return -ENXIO; + ret = snd_pcm_hw_constraint_integer(substream->runtime, SNDRV_PCM_HW_PARAM_PERIODS); if (ret < 0) @@ -301,11 +295,7 @@ int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream, if (!prtd) return -ENOMEM; - ret = dmaengine_pcm_request_channel(prtd, filter_fn, filter_data); - if (ret < 0) { - kfree(prtd); - return ret; - } + prtd->dma_chan = chan; substream->runtime->private_data = prtd; @@ -313,6 +303,27 @@ int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream, } EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_open); +/** + * snd_dmaengine_pcm_open_request_chan - Open a dmaengine based PCM substream and request channel + * @substream: PCM substream + * @filter_fn: Filter function used to request the DMA channel + * @filter_data: Data passed to the DMA filter function + * + * Returns 0 on success, a negative error code otherwise. + * + * This function will request a DMA channel using the passed filter function and + * data. The function should usually be called from the pcm open callback. Note + * that this function will use private_data field of the substream's runtime. So + * it is not availabe to your pcm driver implementation. + */ +int snd_dmaengine_pcm_open_request_chan(struct snd_pcm_substream *substream, + dma_filter_fn filter_fn, void *filter_data) +{ + return snd_dmaengine_pcm_open(substream, + dmaengine_pcm_request_channel(filter_fn, filter_data)); +} +EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_open_request_chan); + /** * snd_dmaengine_pcm_close - Close a dmaengine based PCM substream * @substream: PCM substream @@ -321,11 +332,26 @@ int snd_dmaengine_pcm_close(struct snd_pcm_substream *substream) { struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream); - dma_release_channel(prtd->dma_chan); kfree(prtd); return 0; } EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_close); +/** + * snd_dmaengine_pcm_release_chan_close - Close a dmaengine based PCM substream and release channel + * @substream: PCM substream + * + * Releases the DMA channel associated with the PCM substream. + */ +int snd_dmaengine_pcm_close_release_chan(struct snd_pcm_substream *substream) +{ + struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream); + + dma_release_channel(prtd->dma_chan); + + return snd_dmaengine_pcm_close(substream); +} +EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_close_release_chan); + MODULE_LICENSE("GPL"); diff --git a/sound/soc/spear/spear_pcm.c b/sound/soc/spear/spear_pcm.c index db75d72c4805..ba66a3f370a3 100644 --- a/sound/soc/spear/spear_pcm.c +++ b/sound/soc/spear/spear_pcm.c @@ -64,7 +64,8 @@ static int spear_pcm_open(struct snd_pcm_substream *substream) if (ret) return ret; - return snd_dmaengine_pcm_open(substream, dma_data->filter, dma_data) + return snd_dmaengine_pcm_open_request_chan(substream, dma_data->filter, + dma_data); } static int spear_pcm_mmap(struct snd_pcm_substream *substream, @@ -79,7 +80,7 @@ static int spear_pcm_mmap(struct snd_pcm_substream *substream, static struct snd_pcm_ops spear_pcm_ops = { .open = spear_pcm_open, - .close = snd_dmaengine_pcm_close, + .close = snd_dmaengine_pcm_close_release_chan, .ioctl = snd_pcm_lib_ioctl, .hw_params = spear_pcm_hw_params, .hw_free = spear_pcm_hw_free, diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c index f91d08bc1753..32d08119dd87 100644 --- a/sound/soc/tegra/tegra_pcm.c +++ b/sound/soc/tegra/tegra_pcm.c @@ -66,7 +66,7 @@ static int tegra_pcm_open(struct snd_pcm_substream *substream) /* Set HW params now that initialization is complete */ snd_soc_set_runtime_hwparams(substream, &tegra_pcm_hardware); - ret = snd_dmaengine_pcm_open(substream, NULL, NULL); + ret = snd_dmaengine_pcm_open_request_chan(substream, NULL, NULL); if (ret) { dev_err(dev, "dmaengine pcm open failed with err %d\n", ret); return ret; @@ -144,7 +144,7 @@ static int tegra_pcm_mmap(struct snd_pcm_substream *substream, static struct snd_pcm_ops tegra_pcm_ops = { .open = tegra_pcm_open, - .close = snd_dmaengine_pcm_close, + .close = snd_dmaengine_pcm_close_release_chan, .ioctl = snd_pcm_lib_ioctl, .hw_params = tegra_pcm_hw_params, .hw_free = tegra_pcm_hw_free, diff --git a/sound/soc/ux500/ux500_pcm.c b/sound/soc/ux500/ux500_pcm.c index 09b5364e5095..a7d4f04e5964 100644 --- a/sound/soc/ux500/ux500_pcm.c +++ b/sound/soc/ux500/ux500_pcm.c @@ -125,8 +125,8 @@ static int ux500_pcm_open(struct snd_pcm_substream *substream) dma_cfg->dst_info.data_width = mem_data_width; } - - ret = snd_dmaengine_pcm_open(substream, stedma40_filter, dma_cfg); + ret = snd_dmaengine_pcm_open_request_chan(substream, stedma40_filter, + dma_cfg); if (ret) { dev_dbg(dai->dev, "%s: ERROR: snd_dmaengine_pcm_open failed (%d)!\n", @@ -211,7 +211,7 @@ static int ux500_pcm_mmap(struct snd_pcm_substream *substream, static struct snd_pcm_ops ux500_pcm_ops = { .open = ux500_pcm_open, - .close = snd_dmaengine_pcm_close, + .close = snd_dmaengine_pcm_close_release_chan, .ioctl = snd_pcm_lib_ioctl, .hw_params = ux500_pcm_hw_params, .hw_free = ux500_pcm_hw_free, -- cgit v1.2.3 From 71a45cda444f9c47bd63516cf4c24fb6d1ccb151 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 15 Apr 2013 19:19:49 +0200 Subject: ASoC: Add snd_soc_{add, remove}_platform snd_soc_{add,remove}_platform are similar to snd_soc_register_platform and snd_soc_unregister_platform with the difference that they won't allocate and free the snd_soc_platform structure. Also add snd_soc_lookup_platform which looks up a platform by the device it has been registered for. Signed-off-by: Lars-Peter Clausen Tested-by: Stephen Warren Tested-by: Shawn Guo Signed-off-by: Mark Brown --- include/sound/soc.h | 4 +++ sound/soc/soc-core.c | 85 ++++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 66 insertions(+), 23 deletions(-) (limited to 'include/sound') diff --git a/include/sound/soc.h b/include/sound/soc.h index f619905f0a65..4429254aa195 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -373,6 +373,10 @@ int snd_soc_poweroff(struct device *dev); int snd_soc_register_platform(struct device *dev, const struct snd_soc_platform_driver *platform_drv); void snd_soc_unregister_platform(struct device *dev); +int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform, + const struct snd_soc_platform_driver *platform_drv); +void snd_soc_remove_platform(struct snd_soc_platform *platform); +struct snd_soc_platform *snd_soc_lookup_platform(struct device *dev); int snd_soc_register_codec(struct device *dev, const struct snd_soc_codec_driver *codec_drv, struct snd_soc_dai_driver *dai_drv, int num_dai); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 4d24b5ea3ba7..0e64af1a7df9 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3901,21 +3901,14 @@ void snd_soc_unregister_dais(struct device *dev, size_t count) EXPORT_SYMBOL_GPL(snd_soc_unregister_dais); /** - * snd_soc_register_platform - Register a platform with the ASoC core - * - * @platform: platform to register + * snd_soc_add_platform - Add a platform to the ASoC core + * @dev: The parent device for the platform + * @platform: The platform to add + * @platform_driver: The driver for the platform */ -int snd_soc_register_platform(struct device *dev, +int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform, const struct snd_soc_platform_driver *platform_drv) { - struct snd_soc_platform *platform; - - dev_dbg(dev, "ASoC: platform register %s\n", dev_name(dev)); - - platform = kzalloc(sizeof(struct snd_soc_platform), GFP_KERNEL); - if (platform == NULL) - return -ENOMEM; - /* create platform component name */ platform->name = fmt_single_name(dev, &platform->id); if (platform->name == NULL) { @@ -3938,30 +3931,76 @@ int snd_soc_register_platform(struct device *dev, return 0; } -EXPORT_SYMBOL_GPL(snd_soc_register_platform); +EXPORT_SYMBOL_GPL(snd_soc_add_platform); /** - * snd_soc_unregister_platform - Unregister a platform from the ASoC core + * snd_soc_register_platform - Register a platform with the ASoC core * - * @platform: platform to unregister + * @platform: platform to register */ -void snd_soc_unregister_platform(struct device *dev) +int snd_soc_register_platform(struct device *dev, + const struct snd_soc_platform_driver *platform_drv) { struct snd_soc_platform *platform; + int ret; - list_for_each_entry(platform, &platform_list, list) { - if (dev == platform->dev) - goto found; - } - return; + dev_dbg(dev, "ASoC: platform register %s\n", dev_name(dev)); -found: + platform = kzalloc(sizeof(struct snd_soc_platform), GFP_KERNEL); + if (platform == NULL) + return -ENOMEM; + + ret = snd_soc_add_platform(dev, platform, platform_drv); + if (ret) + kfree(platform); + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_register_platform); + +/** + * snd_soc_remove_platform - Remove a platform from the ASoC core + * @platform: the platform to remove + */ +void snd_soc_remove_platform(struct snd_soc_platform *platform) +{ mutex_lock(&client_mutex); list_del(&platform->list); mutex_unlock(&client_mutex); - dev_dbg(dev, "ASoC: Unregistered platform '%s'\n", platform->name); + dev_dbg(platform->dev, "ASoC: Unregistered platform '%s'\n", + platform->name); kfree(platform->name); +} +EXPORT_SYMBOL_GPL(snd_soc_remove_platform); + +struct snd_soc_platform *snd_soc_lookup_platform(struct device *dev) +{ + struct snd_soc_platform *platform; + + list_for_each_entry(platform, &platform_list, list) { + if (dev == platform->dev) + return platform; + } + + return NULL; +} +EXPORT_SYMBOL_GPL(snd_soc_lookup_platform); + +/** + * snd_soc_unregister_platform - Unregister a platform from the ASoC core + * + * @platform: platform to unregister + */ +void snd_soc_unregister_platform(struct device *dev) +{ + struct snd_soc_platform *platform; + + platform = snd_soc_lookup_platform(dev); + if (!platform) + return; + + snd_soc_remove_platform(platform); kfree(platform); } EXPORT_SYMBOL_GPL(snd_soc_unregister_platform); -- cgit v1.2.3 From 28c4468b00a1e55e08cc20117de968f7c6275441 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 15 Apr 2013 19:19:50 +0200 Subject: ASoC: Add a generic dmaengine_pcm driver This patch adds a generic dmaengine PCM driver. It builds on top of the dmaengine PCM library and adds the missing pieces like DMA channel management, buffer management and channel configuration. It will be able to replace the majority of the existing platform specific dmaengine based PCM drivers. Devicetree is used to map the DMA channels to the PCM device. Signed-off-by: Lars-Peter Clausen Tested-by: Stephen Warren Tested-by: Shawn Guo Signed-off-by: Mark Brown --- include/sound/dmaengine_pcm.h | 25 ++++ sound/soc/Kconfig | 4 + sound/soc/Makefile | 4 + sound/soc/soc-generic-dmaengine-pcm.c | 241 ++++++++++++++++++++++++++++++++++ 4 files changed, 274 insertions(+) create mode 100644 sound/soc/soc-generic-dmaengine-pcm.c (limited to 'include/sound') diff --git a/include/sound/dmaengine_pcm.h b/include/sound/dmaengine_pcm.h index d015d67e75c3..e0bf24e90669 100644 --- a/include/sound/dmaengine_pcm.h +++ b/include/sound/dmaengine_pcm.h @@ -72,4 +72,29 @@ void snd_dmaengine_pcm_set_config_from_dai_data( const struct snd_dmaengine_dai_dma_data *dma_data, struct dma_slave_config *config); +/** + * struct snd_dmaengine_pcm_config - Configuration data for dmaengine based PCM + * @prepare_slave_config: Callback used to fill in the DMA slave_config for a + * PCM substream. Will be called from the PCM drivers hwparams callback. + * @pcm_hardware: snd_pcm_hardware struct to be used for the PCM. + * @prealloc_buffer_size: Size of the preallocated audio buffer. + */ +struct snd_dmaengine_pcm_config { + int (*prepare_slave_config)(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct dma_slave_config *slave_config); + + const struct snd_pcm_hardware *pcm_hardware; + unsigned int prealloc_buffer_size; +}; + +int snd_dmaengine_pcm_register(struct device *dev, + const struct snd_dmaengine_pcm_config *config, + unsigned int flags); +void snd_dmaengine_pcm_unregister(struct device *dev); + +int snd_dmaengine_pcm_prepare_slave_config(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct dma_slave_config *slave_config); + #endif diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index 5da8ca7aee05..9e675c76436c 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -29,6 +29,10 @@ config SND_SOC_AC97_BUS config SND_SOC_DMAENGINE_PCM bool +config SND_SOC_GENERIC_DMAENGINE_PCM + bool + select SND_SOC_DMAENGINE_PCM + # All the supported SoCs source "sound/soc/atmel/Kconfig" source "sound/soc/au1x/Kconfig" diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 99f32f7c0692..197b6ae54c8d 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -5,6 +5,10 @@ ifneq ($(CONFIG_SND_SOC_DMAENGINE_PCM),) snd-soc-core-objs += soc-dmaengine-pcm.o endif +ifneq ($(CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM),) +snd-soc-core-objs += soc-generic-dmaengine-pcm.o +endif + obj-$(CONFIG_SND_SOC) += snd-soc-core.o obj-$(CONFIG_SND_SOC) += codecs/ obj-$(CONFIG_SND_SOC) += generic/ diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c new file mode 100644 index 000000000000..acfc92698995 --- /dev/null +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2013, Analog Devices Inc. + * Author: Lars-Peter Clausen + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +struct dmaengine_pcm { + struct dma_chan *chan[SNDRV_PCM_STREAM_CAPTURE + 1]; + const struct snd_dmaengine_pcm_config *config; + struct snd_soc_platform platform; +}; + +static struct dmaengine_pcm *soc_platform_to_pcm(struct snd_soc_platform *p) +{ + return container_of(p, struct dmaengine_pcm, platform); +} + +/** + * snd_dmaengine_pcm_prepare_slave_config() - Generic prepare_slave_config callback + * @substream: PCM substream + * @params: hw_params + * @slave_config: DMA slave config to prepare + * + * This function can be used as a generic prepare_slave_config callback for + * platforms which make use of the snd_dmaengine_dai_dma_data struct for their + * DAI DMA data. Internally the function will first call + * snd_hwparams_to_dma_slave_config to fill in the slave config based on the + * hw_params, followed by snd_dmaengine_set_config_from_dai_data to fill in the + * remaining fields based on the DAI DMA data. + */ +int snd_dmaengine_pcm_prepare_slave_config(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, struct dma_slave_config *slave_config) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_dmaengine_dai_dma_data *dma_data; + int ret; + + dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); + + ret = snd_hwparams_to_dma_slave_config(substream, params, slave_config); + if (ret) + return ret; + + snd_dmaengine_pcm_set_config_from_dai_data(substream, dma_data, + slave_config); + + return 0; +} +EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_prepare_slave_config); + +static int dmaengine_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform); + struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream); + struct dma_slave_config slave_config; + int ret; + + if (pcm->config->prepare_slave_config) { + ret = pcm->config->prepare_slave_config(substream, params, + &slave_config); + if (ret) + return ret; + + ret = dmaengine_slave_config(chan, &slave_config); + if (ret) + return ret; + } + + return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); +} + +static int dmaengine_pcm_open(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform); + struct dma_chan *chan = pcm->chan[substream->stream]; + int ret; + + ret = snd_soc_set_runtime_hwparams(substream, + pcm->config->pcm_hardware); + if (ret) + return ret; + + return snd_dmaengine_pcm_open(substream, chan); +} + +static struct device *dmaengine_dma_dev(struct dmaengine_pcm *pcm, + struct snd_pcm_substream *substream) +{ + if (!pcm->chan[substream->stream]) + return NULL; + + return pcm->chan[substream->stream]->device->dev; +} + +static void dmaengine_pcm_free(struct snd_pcm *pcm) +{ + snd_pcm_lib_preallocate_free_for_all(pcm); +} + +static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd) +{ + struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform); + const struct snd_dmaengine_pcm_config *config = pcm->config; + struct snd_pcm_substream *substream; + unsigned int i; + int ret; + + for (i = SNDRV_PCM_STREAM_PLAYBACK; i <= SNDRV_PCM_STREAM_CAPTURE; i++) { + substream = rtd->pcm->streams[i].substream; + if (!substream) + continue; + + if (!pcm->chan[i]) { + dev_err(rtd->platform->dev, + "Missing dma channel for stream: %d\n", i); + ret = -EINVAL; + goto err_free; + } + + ret = snd_pcm_lib_preallocate_pages(substream, + SNDRV_DMA_TYPE_DEV, + dmaengine_dma_dev(pcm, substream), + config->prealloc_buffer_size, + config->pcm_hardware->buffer_bytes_max); + if (ret) + goto err_free; + } + + return 0; + +err_free: + dmaengine_pcm_free(rtd->pcm); + return ret; +} + +static const struct snd_pcm_ops dmaengine_pcm_ops = { + .open = dmaengine_pcm_open, + .close = snd_dmaengine_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = dmaengine_pcm_hw_params, + .hw_free = snd_pcm_lib_free_pages, + .trigger = snd_dmaengine_pcm_trigger, + .pointer = snd_dmaengine_pcm_pointer, +}; + +static const struct snd_soc_platform_driver dmaengine_pcm_platform = { + .ops = &dmaengine_pcm_ops, + .pcm_new = dmaengine_pcm_new, + .pcm_free = dmaengine_pcm_free, +}; + +static const char * const dmaengine_pcm_dma_channel_names[] = { + [SNDRV_PCM_STREAM_PLAYBACK] = "tx", + [SNDRV_PCM_STREAM_CAPTURE] = "rx", +}; + +/** + * snd_dmaengine_pcm_register - Register a dmaengine based PCM device + * @dev: The parent device for the PCM device + * @config: Platform specific PCM configuration + * @flags: Platform specific quirks + */ +int snd_dmaengine_pcm_register(struct device *dev, + const struct snd_dmaengine_pcm_config *config, unsigned int flags) +{ + struct dmaengine_pcm *pcm; + unsigned int i; + + if (!dev->of_node) + return -EINVAL; + + pcm = kzalloc(sizeof(*pcm), GFP_KERNEL); + if (!pcm) + return -ENOMEM; + + pcm->config = config; + + for (i = SNDRV_PCM_STREAM_PLAYBACK; i <= SNDRV_PCM_STREAM_CAPTURE; i++) { + pcm->chan[i] = of_dma_request_slave_channel(dev->of_node, + dmaengine_pcm_dma_channel_names[i]); + } + + return snd_soc_add_platform(dev, &pcm->platform, + &dmaengine_pcm_platform); +} +EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_register); + +/** + * snd_dmaengine_pcm_unregister - Removes a dmaengine based PCM device + * @dev: Parent device the PCM was register with + * + * Removes a dmaengine based PCM device previously registered with + * snd_dmaengine_pcm_register. + */ +void snd_dmaengine_pcm_unregister(struct device *dev) +{ + struct snd_soc_platform *platform; + struct dmaengine_pcm *pcm; + unsigned int i; + + platform = snd_soc_lookup_platform(dev); + if (!platform) + return; + + pcm = soc_platform_to_pcm(platform); + + for (i = SNDRV_PCM_STREAM_PLAYBACK; i <= SNDRV_PCM_STREAM_CAPTURE; i++) { + if (pcm->chan[i]) + dma_release_channel(pcm->chan[i]); + } + + snd_soc_remove_platform(platform); + kfree(pcm); +} +EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_unregister); + +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From c999836d37c6c1125e856f68877ae13952baa61a Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 15 Apr 2013 19:19:51 +0200 Subject: ASoC: dmaengine_pcm: Add support for compat platforms Add support for platforms which don't use devicetree yet or have to optionally support a non-devicetree way to request the DMA channel. The patch adds the compat_request_channel and compat_filter_fn callbacks to the snd_dmaengine_pcm_config struct. If the compat_request_channel is implemented it will be used to request the DMA channel. If not dma_request_channel with compat_filter_fn as the filter function will be used to request the channel. The patch also exports the snd_dmaengine_pcm_request_chan() function, since compat platforms will want to use it to request their DMA channel. Signed-off-by: Lars-Peter Clausen Tested-by: Stephen Warren Tested-by: Shawn Guo Signed-off-by: Mark Brown --- include/sound/dmaengine_pcm.h | 29 +++++++++++++++++++++++++++++ sound/soc/soc-dmaengine-pcm.c | 14 ++++++++++++-- sound/soc/soc-generic-dmaengine-pcm.c | 32 +++++++++++++++++++++++++++----- 3 files changed, 68 insertions(+), 7 deletions(-) (limited to 'include/sound') diff --git a/include/sound/dmaengine_pcm.h b/include/sound/dmaengine_pcm.h index e0bf24e90669..1a7897ab3572 100644 --- a/include/sound/dmaengine_pcm.h +++ b/include/sound/dmaengine_pcm.h @@ -16,6 +16,7 @@ #define __SOUND_DMAENGINE_PCM_H__ #include +#include #include /** @@ -46,6 +47,8 @@ int snd_dmaengine_pcm_open_request_chan(struct snd_pcm_substream *substream, dma_filter_fn filter_fn, void *filter_data); int snd_dmaengine_pcm_close_release_chan(struct snd_pcm_substream *substream); +struct dma_chan *snd_dmaengine_pcm_request_channel(dma_filter_fn filter_fn, + void *filter_data); struct dma_chan *snd_dmaengine_pcm_get_chan(struct snd_pcm_substream *substream); /** @@ -72,17 +75,43 @@ void snd_dmaengine_pcm_set_config_from_dai_data( const struct snd_dmaengine_dai_dma_data *dma_data, struct dma_slave_config *config); + +/* + * Try to request the DMA channel using compat_request_channel or + * compat_filter_fn if it couldn't be requested through devicetree. + */ +#define SND_DMAENGINE_PCM_FLAG_COMPAT BIT(0) +/* + * Don't try to request the DMA channels through devicetree. This flag only + * makes sense if SND_DMAENGINE_PCM_FLAG_COMPAT is set as well. + */ +#define SND_DMAENGINE_PCM_FLAG_NO_DT BIT(1) + /** * struct snd_dmaengine_pcm_config - Configuration data for dmaengine based PCM * @prepare_slave_config: Callback used to fill in the DMA slave_config for a * PCM substream. Will be called from the PCM drivers hwparams callback. + * @compat_request_channel: Callback to request a DMA channel for platforms + * which do not use devicetree. + * @compat_filter_fn: Will be used as the filter function when requesting a + * channel for platforms which do not use devicetree. The filter parameter + * will be the DAI's DMA data. * @pcm_hardware: snd_pcm_hardware struct to be used for the PCM. * @prealloc_buffer_size: Size of the preallocated audio buffer. + * + * Note: If both compat_request_channel and compat_filter_fn are set + * compat_request_channel will be used to request the channel and + * compat_filter_fn will be ignored. Otherwise the channel will be requested + * using dma_request_channel with compat_filter_fn as the filter function. */ struct snd_dmaengine_pcm_config { int (*prepare_slave_config)(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct dma_slave_config *slave_config); + struct dma_chan *(*compat_request_channel)( + struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_substream *substream); + dma_filter_fn compat_filter_fn; const struct snd_pcm_hardware *pcm_hardware; unsigned int prealloc_buffer_size; diff --git a/sound/soc/soc-dmaengine-pcm.c b/sound/soc/soc-dmaengine-pcm.c index b0420a75f412..aa924d9b7986 100644 --- a/sound/soc/soc-dmaengine-pcm.c +++ b/sound/soc/soc-dmaengine-pcm.c @@ -254,7 +254,16 @@ snd_pcm_uframes_t snd_dmaengine_pcm_pointer(struct snd_pcm_substream *substream) } EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_pointer); -static struct dma_chan *dmaengine_pcm_request_channel(dma_filter_fn filter_fn, +/** + * snd_dmaengine_pcm_request_channel - Request channel for the dmaengine PCM + * @filter_fn: Filter function used to request the DMA channel + * @filter_data: Data passed to the DMA filter function + * + * Returns NULL or the requested DMA channel. + * + * This function request a DMA channel for usage with dmaengine PCM. + */ +struct dma_chan *snd_dmaengine_pcm_request_channel(dma_filter_fn filter_fn, void *filter_data) { dma_cap_mask_t mask; @@ -265,6 +274,7 @@ static struct dma_chan *dmaengine_pcm_request_channel(dma_filter_fn filter_fn, return dma_request_channel(mask, filter_fn, filter_data); } +EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_request_channel); /** * snd_dmaengine_pcm_open - Open a dmaengine based PCM substream @@ -320,7 +330,7 @@ int snd_dmaengine_pcm_open_request_chan(struct snd_pcm_substream *substream, dma_filter_fn filter_fn, void *filter_data) { return snd_dmaengine_pcm_open(substream, - dmaengine_pcm_request_channel(filter_fn, filter_data)); + snd_dmaengine_pcm_request_channel(filter_fn, filter_data)); } EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_open_request_chan); diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index acfc92698995..d6e638056389 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -29,6 +29,7 @@ struct dmaengine_pcm { struct dma_chan *chan[SNDRV_PCM_STREAM_CAPTURE + 1]; const struct snd_dmaengine_pcm_config *config; struct snd_soc_platform platform; + bool compat; }; static struct dmaengine_pcm *soc_platform_to_pcm(struct snd_soc_platform *p) @@ -121,6 +122,19 @@ static void dmaengine_pcm_free(struct snd_pcm *pcm) snd_pcm_lib_preallocate_free_for_all(pcm); } +static struct dma_chan *dmaengine_pcm_compat_request_channel( + struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_substream *substream) +{ + struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform); + + if (pcm->config->compat_request_channel) + return pcm->config->compat_request_channel(rtd, substream); + + return snd_dmaengine_pcm_request_channel(pcm->config->compat_filter_fn, + snd_soc_dai_get_dma_data(rtd->cpu_dai, substream)); +} + static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd) { struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform); @@ -134,6 +148,11 @@ static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd) if (!substream) continue; + if (!pcm->chan[i] && pcm->compat) { + pcm->chan[i] = dmaengine_pcm_compat_request_channel(rtd, + substream); + } + if (!pcm->chan[i]) { dev_err(rtd->platform->dev, "Missing dma channel for stream: %d\n", i); @@ -171,6 +190,7 @@ static const struct snd_soc_platform_driver dmaengine_pcm_platform = { .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[] = { @@ -190,18 +210,20 @@ int snd_dmaengine_pcm_register(struct device *dev, struct dmaengine_pcm *pcm; unsigned int i; - if (!dev->of_node) - return -EINVAL; - pcm = kzalloc(sizeof(*pcm), GFP_KERNEL); if (!pcm) return -ENOMEM; pcm->config = config; - for (i = SNDRV_PCM_STREAM_PLAYBACK; i <= SNDRV_PCM_STREAM_CAPTURE; i++) { - pcm->chan[i] = of_dma_request_slave_channel(dev->of_node, + if (flags & SND_DMAENGINE_PCM_FLAG_COMPAT) + pcm->compat = true; + + if (!(flags & SND_DMAENGINE_PCM_FLAG_NO_DT) && dev->of_node) { + for (i = SNDRV_PCM_STREAM_PLAYBACK; i <= SNDRV_PCM_STREAM_CAPTURE; i++) { + pcm->chan[i] = of_dma_request_slave_channel(dev->of_node, dmaengine_pcm_dma_channel_names[i]); + } } return snd_soc_add_platform(dev, &pcm->platform, -- cgit v1.2.3 From 610f780050090db1af024bd060f819478a656cd0 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 15 Apr 2013 19:19:55 +0200 Subject: ASoC: dmaengine-pcm: Add support for platforms which can't report residue Unfortunately there are still quite a few platforms with a dmaengine driver which do not support reporting the number of bytes left to transfer. If we want to support these platforms in the generic dmaengine PCM driver we have. Signed-off-by: Lars-Peter Clausen Tested-by: Stephen Warren Tested-by: Shawn Guo Signed-off-by: Mark Brown --- include/sound/dmaengine_pcm.h | 5 +++++ sound/soc/soc-generic-dmaengine-pcm.c | 23 ++++++++++++++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) (limited to 'include/sound') diff --git a/include/sound/dmaengine_pcm.h b/include/sound/dmaengine_pcm.h index 1a7897ab3572..e7052862d6b2 100644 --- a/include/sound/dmaengine_pcm.h +++ b/include/sound/dmaengine_pcm.h @@ -86,6 +86,11 @@ void snd_dmaengine_pcm_set_config_from_dai_data( * makes sense if SND_DMAENGINE_PCM_FLAG_COMPAT is set as well. */ #define SND_DMAENGINE_PCM_FLAG_NO_DT BIT(1) +/* + * The platforms dmaengine driver does not support reporting the ammount of + * bytes that are still left to transfer. + */ +#define SND_DMAENGINE_PCM_FLAG_NO_RESIDUE BIT(2) /** * struct snd_dmaengine_pcm_config - Configuration data for dmaengine based PCM diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index d6e638056389..ae0c37e66ae0 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -193,6 +193,23 @@ static const struct snd_soc_platform_driver dmaengine_pcm_platform = { .probe_order = SND_SOC_COMP_ORDER_LATE, }; +static const struct snd_pcm_ops dmaengine_no_residue_pcm_ops = { + .open = dmaengine_pcm_open, + .close = snd_dmaengine_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = dmaengine_pcm_hw_params, + .hw_free = snd_pcm_lib_free_pages, + .trigger = snd_dmaengine_pcm_trigger, + .pointer = snd_dmaengine_pcm_pointer_no_residue, +}; + +static const struct snd_soc_platform_driver dmaengine_no_residue_pcm_platform = { + .ops = &dmaengine_no_residue_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[] = { [SNDRV_PCM_STREAM_PLAYBACK] = "tx", [SNDRV_PCM_STREAM_CAPTURE] = "rx", @@ -226,7 +243,11 @@ int snd_dmaengine_pcm_register(struct device *dev, } } - return snd_soc_add_platform(dev, &pcm->platform, + if (flags & SND_DMAENGINE_PCM_FLAG_NO_RESIDUE) + return snd_soc_add_platform(dev, &pcm->platform, + &dmaengine_no_residue_pcm_platform); + else + return snd_soc_add_platform(dev, &pcm->platform, &dmaengine_pcm_platform); } EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_register); -- cgit v1.2.3 From ef7a4f979bd8201324b2bcd30277c14aba889f50 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 17 Apr 2013 00:01:36 +0800 Subject: ALSA: add DSD formats This patch adds two formats for Direct Stream Digital (DSD), a pulse-density encoding format which is described here: https://en.wikipedia.org/wiki/Direct_Stream_Digital DSD operates on 2.8, 5.6 or 11.2MHz sample rates and as a 1-bit stream. The two new types added by this patch describe streams that are capable of handling DSD samples in DOP format as 8-bit or in 16-bit (or at a x8 or x16 data rate, respectively). DSD itself specifies samples in *bit*, while DOP and ALSA handle them as *bytes*. Hence, a factor of 8 or 16 has to be applied for the sample rare configuration, according to the following table: configured hardware 176.4KHz 352.8kHz 705.6KHz <---- sample rate 8-bit 2.8MHz 5.6MHz 16-bit 2.8Mhz 5.6MHz 11.2MHz `-----------------------------' actual DSD sample rates Signed-off-by: Daniel Mack Signed-off-by: Takashi Iwai --- include/sound/pcm.h | 2 ++ include/uapi/sound/asound.h | 4 +++- sound/core/pcm.c | 2 ++ sound/core/pcm_misc.c | 8 ++++++++ 4 files changed, 15 insertions(+), 1 deletion(-) (limited to 'include/sound') diff --git a/include/sound/pcm.h b/include/sound/pcm.h index aa7b0a8385cb..1b0c6484e71a 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -181,6 +181,8 @@ struct snd_pcm_ops { #define SNDRV_PCM_FMTBIT_G723_24_1B _SNDRV_PCM_FMTBIT(G723_24_1B) #define SNDRV_PCM_FMTBIT_G723_40 _SNDRV_PCM_FMTBIT(G723_40) #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) #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 1774a5c3ef10..e3983d508272 100644 --- a/include/uapi/sound/asound.h +++ b/include/uapi/sound/asound.h @@ -214,7 +214,9 @@ typedef int __bitwise snd_pcm_format_t; #define SNDRV_PCM_FORMAT_G723_24_1B ((__force snd_pcm_format_t) 45) /* 1 sample in 1 byte */ #define SNDRV_PCM_FORMAT_G723_40 ((__force snd_pcm_format_t) 46) /* 8 Samples in 5 bytes */ #define SNDRV_PCM_FORMAT_G723_40_1B ((__force snd_pcm_format_t) 47) /* 1 sample in 1 byte */ -#define SNDRV_PCM_FORMAT_LAST SNDRV_PCM_FORMAT_G723_40_1B +#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 #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 578327e2bc26..17f45e8aa89c 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -209,6 +209,8 @@ static char *snd_pcm_format_names[] = { FORMAT(G723_24_1B), FORMAT(G723_40), FORMAT(G723_40_1B), + FORMAT(DSD_U8), + FORMAT(DSD_U16_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 b875b19f2d55..43f24cce3dec 100644 --- a/sound/core/pcm_misc.c +++ b/sound/core/pcm_misc.c @@ -140,6 +140,14 @@ static struct pcm_format_data pcm_formats[(INT)SNDRV_PCM_FORMAT_LAST+1] = { .width = 5, .phys = 5, .le = -1, .signd = -1, .silence = {}, }, + [SNDRV_PCM_FORMAT_DSD_U8] = { + .width = 8, .phys = 8, .le = 1, .signd = 0, + .silence = {}, + }, + [SNDRV_PCM_FORMAT_DSD_U16_LE] = { + .width = 16, .phys = 16, .le = 1, .signd = 0, + .silence = {}, + }, /* FIXME: the following three formats are not defined properly yet */ [SNDRV_PCM_FORMAT_MPEG] = { .le = -1, .signd = -1, -- cgit v1.2.3 From 22f38f792ec53e2a93be13ecb609bbe911ed8ff9 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 15 Apr 2013 19:20:04 +0200 Subject: ASoC: ux500: Use generic dmaengine PCM Use the generic dmaengine PCM driver instead of a custom implemention. There is a minor functional change, the ux500 PCM driver did not preallocate the audio buffer, while the generic dmaengine PCM driver will do this. Signed-off-by: Lars-Peter Clausen Acked-by: Lee Jones Signed-off-by: Mark Brown --- include/sound/dmaengine_pcm.h | 2 +- sound/soc/ux500/Kconfig | 2 +- sound/soc/ux500/ux500_pcm.c | 159 +++++------------------------------------- 3 files changed, 19 insertions(+), 144 deletions(-) (limited to 'include/sound') diff --git a/include/sound/dmaengine_pcm.h b/include/sound/dmaengine_pcm.h index e7052862d6b2..b1d1150c1d60 100644 --- a/include/sound/dmaengine_pcm.h +++ b/include/sound/dmaengine_pcm.h @@ -87,7 +87,7 @@ void snd_dmaengine_pcm_set_config_from_dai_data( */ #define SND_DMAENGINE_PCM_FLAG_NO_DT BIT(1) /* - * The platforms dmaengine driver does not support reporting the ammount of + * The platforms dmaengine driver does not support reporting the amount of * bytes that are still left to transfer. */ #define SND_DMAENGINE_PCM_FLAG_NO_RESIDUE BIT(2) diff --git a/sound/soc/ux500/Kconfig b/sound/soc/ux500/Kconfig index 069330d82be5..c73c5907eb11 100644 --- a/sound/soc/ux500/Kconfig +++ b/sound/soc/ux500/Kconfig @@ -16,7 +16,7 @@ config SND_SOC_UX500_PLAT_MSP_I2S config SND_SOC_UX500_PLAT_DMA tristate "Platform - DB8500 (DMA)" depends on SND_SOC_UX500 - select SND_SOC_DMAENGINE_PCM + select SND_SOC_GENERIC_DMAENGINE_PCM help Say Y if you want to enable the Ux500 platform-driver. diff --git a/sound/soc/ux500/ux500_pcm.c b/sound/soc/ux500/ux500_pcm.c index a7d4f04e5964..b6e5ae277299 100644 --- a/sound/soc/ux500/ux500_pcm.c +++ b/sound/soc/ux500/ux500_pcm.c @@ -40,7 +40,7 @@ #define UX500_PLATFORM_PERIODS_MAX 48 #define UX500_PLATFORM_BUFFER_BYTES_MAX (2048 * PAGE_SIZE) -static struct snd_pcm_hardware ux500_pcm_hw = { +static const struct snd_pcm_hardware ux500_pcm_hw = { .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_RESUME | @@ -61,43 +61,23 @@ static struct snd_pcm_hardware ux500_pcm_hw = { .periods_max = UX500_PLATFORM_PERIODS_MAX, }; -static void ux500_pcm_dma_hw_free(struct device *dev, - struct snd_pcm_substream *substream) +static struct dma_chan *ux500_pcm_request_chan(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_substream *substream) { - struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_dma_buffer *buf = runtime->dma_buffer_p; - - if (runtime->dma_area == NULL) - return; - - if (buf != &substream->dma_buffer) { - dma_free_coherent(buf->dev.dev, buf->bytes, buf->area, - buf->addr); - kfree(runtime->dma_buffer_p); - } - - snd_pcm_set_runtime_buffer(substream, NULL); -} - -static int ux500_pcm_open(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *dai = rtd->cpu_dai; struct device *dev = dai->dev; - int ret; - struct ux500_msp_dma_params *dma_params; u16 per_data_width, mem_data_width; struct stedma40_chan_cfg *dma_cfg; + struct ux500_msp_dma_params *dma_params; dev_dbg(dev, "%s: MSP %d (%s): Enter.\n", __func__, dai->id, snd_pcm_stream_str(substream)); - dev_dbg(dev, "%s: Set runtime hwparams.\n", __func__); - snd_soc_set_runtime_hwparams(substream, &ux500_pcm_hw); + dma_params = snd_soc_dai_get_dma_data(dai, substream); + dma_cfg = dma_params->dma_cfg; mem_data_width = STEDMA40_HALFWORD_WIDTH; - dma_params = snd_soc_dai_get_dma_data(dai, substream); switch (dma_params->data_size) { case 32: per_data_width = STEDMA40_WORD_WIDTH; @@ -110,13 +90,8 @@ static int ux500_pcm_open(struct snd_pcm_substream *substream) break; default: per_data_width = STEDMA40_WORD_WIDTH; - dev_warn(rtd->platform->dev, - "%s: Unknown data-size (%d)! Assuming 32 bits.\n", - __func__, dma_params->data_size); } - dma_cfg = dma_params->dma_cfg; - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { dma_cfg->src_info.data_width = mem_data_width; dma_cfg->dst_info.data_width = per_data_width; @@ -125,123 +100,24 @@ static int ux500_pcm_open(struct snd_pcm_substream *substream) dma_cfg->dst_info.data_width = mem_data_width; } - ret = snd_dmaengine_pcm_open_request_chan(substream, stedma40_filter, - dma_cfg); - if (ret) { - dev_dbg(dai->dev, - "%s: ERROR: snd_dmaengine_pcm_open failed (%d)!\n", - __func__, ret); - return ret; - } - - return 0; -} - -static int ux500_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_dma_buffer *buf = runtime->dma_buffer_p; - struct snd_soc_pcm_runtime *rtd = substream->private_data; - int ret = 0; - int size; - - dev_dbg(rtd->platform->dev, "%s: Enter\n", __func__); - - size = params_buffer_bytes(hw_params); - - if (buf) { - if (buf->bytes >= size) - goto out; - ux500_pcm_dma_hw_free(NULL, substream); - } - - if (substream->dma_buffer.area != NULL && - substream->dma_buffer.bytes >= size) { - buf = &substream->dma_buffer; - } else { - buf = kmalloc(sizeof(struct snd_dma_buffer), GFP_KERNEL); - if (!buf) - goto nomem; - - buf->dev.type = SNDRV_DMA_TYPE_DEV; - buf->dev.dev = NULL; - buf->area = dma_alloc_coherent(NULL, size, &buf->addr, - GFP_KERNEL); - buf->bytes = size; - buf->private_data = NULL; - - if (!buf->area) - goto free; - } - snd_pcm_set_runtime_buffer(substream, buf); - ret = 1; - out: - runtime->dma_bytes = size; - return ret; - - free: - kfree(buf); - nomem: - return -ENOMEM; -} - -static int ux500_pcm_hw_free(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - - dev_dbg(rtd->platform->dev, "%s: Enter\n", __func__); - - ux500_pcm_dma_hw_free(NULL, substream); - - return 0; + return snd_dmaengine_pcm_request_channel(stedma40_filter, dma_cfg); } -static int ux500_pcm_mmap(struct snd_pcm_substream *substream, - struct vm_area_struct *vma) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_soc_pcm_runtime *rtd = substream->private_data; - - dev_dbg(rtd->platform->dev, "%s: Enter.\n", __func__); - - return dma_mmap_coherent(NULL, vma, runtime->dma_area, - runtime->dma_addr, runtime->dma_bytes); -} - -static struct snd_pcm_ops ux500_pcm_ops = { - .open = ux500_pcm_open, - .close = snd_dmaengine_pcm_close_release_chan, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = ux500_pcm_hw_params, - .hw_free = ux500_pcm_hw_free, - .trigger = snd_dmaengine_pcm_trigger, - .pointer = snd_dmaengine_pcm_pointer_no_residue, - .mmap = ux500_pcm_mmap -}; - -int ux500_pcm_new(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_pcm *pcm = rtd->pcm; - - dev_dbg(rtd->platform->dev, "%s: Enter (id = '%s').\n", __func__, - pcm->id); - - pcm->info_flags = 0; - - return 0; -} - -static struct snd_soc_platform_driver ux500_pcm_soc_drv = { - .ops = &ux500_pcm_ops, - .pcm_new = ux500_pcm_new, +static const struct snd_dmaengine_pcm_config ux500_dmaengine_pcm_config = { + .pcm_hardware = &ux500_pcm_hw, + .compat_request_channel = ux500_pcm_request_chan, + .prealloc_buffer_size = 128 * 1024, }; int ux500_pcm_register_platform(struct platform_device *pdev) { int ret; - ret = snd_soc_register_platform(&pdev->dev, &ux500_pcm_soc_drv); + ret = snd_dmaengine_pcm_register(&pdev->dev, + &ux500_dmaengine_pcm_config, + SND_DMAENGINE_PCM_FLAG_NO_RESIDUE | + SND_DMAENGINE_PCM_FLAG_COMPAT | + SND_DMAENGINE_PCM_FLAG_NO_DT); if (ret < 0) { dev_err(&pdev->dev, "%s: ERROR: Failed to register platform '%s' (%d)!\n", @@ -255,8 +131,7 @@ EXPORT_SYMBOL_GPL(ux500_pcm_register_platform); int ux500_pcm_unregister_platform(struct platform_device *pdev) { - snd_soc_unregister_platform(&pdev->dev); - + snd_dmaengine_pcm_unregister(&pdev->dev); return 0; } EXPORT_SYMBOL_GPL(ux500_pcm_unregister_platform); -- cgit v1.2.3 From 4daf891cdea2eb63b51cb35a3ac12706f8c50156 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 18 Apr 2013 11:01:38 +0100 Subject: ALSA: compress_core: Deconstify copy callback buffer The buffer passed to the copy callback should not be const because the copy callback can be used for capture and playback. Signed-off-by: Charles Keepax Signed-off-by: Richard Fitzgerald Acked-by: Vinod Koul Signed-off-by: Takashi Iwai --- include/sound/compress_driver.h | 2 +- sound/core/compress_offload.c | 8 +++++--- sound/soc/soc-compress.c | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) (limited to 'include/sound') diff --git a/include/sound/compress_driver.h b/include/sound/compress_driver.h index ff6c74153fa1..db8273a5175a 100644 --- a/include/sound/compress_driver.h +++ b/include/sound/compress_driver.h @@ -121,7 +121,7 @@ struct snd_compr_ops { int (*trigger)(struct snd_compr_stream *stream, int cmd); int (*pointer)(struct snd_compr_stream *stream, struct snd_compr_tstamp *tstamp); - int (*copy)(struct snd_compr_stream *stream, const char __user *buf, + int (*copy)(struct snd_compr_stream *stream, char __user *buf, size_t count); int (*mmap)(struct snd_compr_stream *stream, struct vm_area_struct *vma); diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c index 1f69863a83d2..52ca4cce1462 100644 --- a/sound/core/compress_offload.c +++ b/sound/core/compress_offload.c @@ -272,10 +272,12 @@ static ssize_t snd_compr_write(struct file *f, const char __user *buf, if (avail > count) avail = count; - if (stream->ops->copy) - retval = stream->ops->copy(stream, buf, avail); - else + if (stream->ops->copy) { + char __user* cbuf = (char __user*)buf; + retval = stream->ops->copy(stream, cbuf, avail); + } else { retval = snd_compr_write_data(stream, buf, avail); + } if (retval > 0) stream->runtime->total_bytes_available += retval; diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index 29093a306ea2..da83e5658f62 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -315,7 +315,7 @@ static int soc_compr_pointer(struct snd_compr_stream *cstream, } static int soc_compr_copy(struct snd_compr_stream *cstream, - const char __user *buf, size_t count) + char __user *buf, size_t count) { struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_platform *platform = rtd->platform; -- cgit v1.2.3 From ccf17b13ca615a044c980f1e9a94a07b3f99926d Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 18 Apr 2013 11:03:10 +0100 Subject: ALSA: compress_core: Remove unused hw_pointer Only tested as far as build. Signed-off-by: Charles Keepax Signed-off-by: Richard Fitzgerald Acked-by: Vinod Koul Signed-off-by: Takashi Iwai --- include/sound/compress_driver.h | 1 - sound/core/compress_offload.c | 2 -- 2 files changed, 3 deletions(-) (limited to 'include/sound') diff --git a/include/sound/compress_driver.h b/include/sound/compress_driver.h index db8273a5175a..2d7de9610f11 100644 --- a/include/sound/compress_driver.h +++ b/include/sound/compress_driver.h @@ -56,7 +56,6 @@ struct snd_compr_runtime { u64 buffer_size; u32 fragment_size; u32 fragments; - u64 hw_pointer; u64 app_pointer; u64 total_bytes_available; u64 total_bytes_transferred; diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c index 52a276510b18..36d7688fe69a 100644 --- a/sound/core/compress_offload.c +++ b/sound/core/compress_offload.c @@ -152,7 +152,6 @@ static int snd_compr_update_tstamp(struct snd_compr_stream *stream, stream->ops->pointer(stream, tstamp); pr_debug("dsp consumed till %d total %d bytes\n", tstamp->byte_offset, tstamp->copied_total); - stream->runtime->hw_pointer = tstamp->byte_offset; if (stream->direction == SND_COMPRESS_PLAYBACK) stream->runtime->total_bytes_transferred = tstamp->copied_total; else @@ -657,7 +656,6 @@ static int snd_compr_stop(struct snd_compr_stream *stream) if (!retval) { stream->runtime->state = SNDRV_PCM_STATE_SETUP; wake_up(&stream->runtime->sleep); - stream->runtime->hw_pointer = 0; stream->runtime->app_pointer = 0; stream->runtime->total_bytes_available = 0; stream->runtime->total_bytes_transferred = 0; -- cgit v1.2.3 From f0283b58d01d36910fcd195d1fc365a3356b2be0 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 18 Apr 2013 11:03:46 +0100 Subject: ALSA: compress_core: Rework writes to use cumulative values This patch reworks the writes to use cumulative values thus making the app_pointer unecessary and removing it. Only tested as far as build. Signed-off-by: Charles Keepax Signed-off-by: Richard Fitzgerald Acked-by: Vinod Koul Signed-off-by: Takashi Iwai --- include/sound/compress_driver.h | 1 - sound/core/compress_offload.c | 18 +++++++++++------- 2 files changed, 11 insertions(+), 8 deletions(-) (limited to 'include/sound') diff --git a/include/sound/compress_driver.h b/include/sound/compress_driver.h index 2d7de9610f11..9031a26249b5 100644 --- a/include/sound/compress_driver.h +++ b/include/sound/compress_driver.h @@ -56,7 +56,6 @@ struct snd_compr_runtime { u64 buffer_size; u32 fragment_size; u32 fragments; - u64 app_pointer; u64 total_bytes_available; u64 total_bytes_transferred; wait_queue_head_t sleep; diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c index 36d7688fe69a..7941ace78283 100644 --- a/sound/core/compress_offload.c +++ b/sound/core/compress_offload.c @@ -28,11 +28,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -223,21 +225,24 @@ static int snd_compr_write_data(struct snd_compr_stream *stream, void *dstn; size_t copy; struct snd_compr_runtime *runtime = stream->runtime; + /* 64-bit Modulus */ + u64 app_pointer = div64_u64(runtime->total_bytes_available, + runtime->buffer_size); + app_pointer = runtime->total_bytes_available - + (app_pointer * runtime->buffer_size); - dstn = runtime->buffer + runtime->app_pointer; + dstn = runtime->buffer + app_pointer; pr_debug("copying %ld at %lld\n", - (unsigned long)count, runtime->app_pointer); - if (count < runtime->buffer_size - runtime->app_pointer) { + (unsigned long)count, app_pointer); + if (count < runtime->buffer_size - app_pointer) { if (copy_from_user(dstn, buf, count)) return -EFAULT; - runtime->app_pointer += count; } else { - copy = runtime->buffer_size - runtime->app_pointer; + copy = runtime->buffer_size - app_pointer; if (copy_from_user(dstn, buf, copy)) return -EFAULT; if (copy_from_user(runtime->buffer, buf + copy, count - copy)) return -EFAULT; - runtime->app_pointer = count - copy; } /* if DSP cares, let it know data has been written */ if (stream->ops->ack) @@ -656,7 +661,6 @@ static int snd_compr_stop(struct snd_compr_stream *stream) if (!retval) { stream->runtime->state = SNDRV_PCM_STATE_SETUP; wake_up(&stream->runtime->sleep); - stream->runtime->app_pointer = 0; stream->runtime->total_bytes_available = 0; stream->runtime->total_bytes_transferred = 0; } -- cgit v1.2.3 From d1e1406c6ed0b92200a7de2a09fbab65661dba3c Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 20 Apr 2013 19:29:00 +0200 Subject: ASoC: generic-dmaengine-pcm: Add support for half-duplex Some platforms which are half-duplex share the same DMA channel between the playback and capture stream. Add support for this to the generic dmaengine PCM driver. Signed-off-by: Lars-Peter Clausen Tested-by: Shawn Guo Signed-off-by: Mark Brown --- include/sound/dmaengine_pcm.h | 5 ++++ sound/soc/soc-generic-dmaengine-pcm.c | 43 ++++++++++++++++++++++++----------- 2 files changed, 35 insertions(+), 13 deletions(-) (limited to 'include/sound') diff --git a/include/sound/dmaengine_pcm.h b/include/sound/dmaengine_pcm.h index b1d1150c1d60..f11c35cd5532 100644 --- a/include/sound/dmaengine_pcm.h +++ b/include/sound/dmaengine_pcm.h @@ -91,6 +91,11 @@ void snd_dmaengine_pcm_set_config_from_dai_data( * bytes that are still left to transfer. */ #define SND_DMAENGINE_PCM_FLAG_NO_RESIDUE BIT(2) +/* + * The PCM is half duplex and the DMA channel is shared between capture and + * playback. + */ +#define SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX BIT(3) /** * struct snd_dmaengine_pcm_config - Configuration data for dmaengine based PCM diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index ae0c37e66ae0..5fd5ed4c0a96 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -29,7 +29,7 @@ struct dmaengine_pcm { struct dma_chan *chan[SNDRV_PCM_STREAM_CAPTURE + 1]; const struct snd_dmaengine_pcm_config *config; struct snd_soc_platform platform; - bool compat; + unsigned int flags; }; static struct dmaengine_pcm *soc_platform_to_pcm(struct snd_soc_platform *p) @@ -128,6 +128,9 @@ static struct dma_chan *dmaengine_pcm_compat_request_channel( { struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform); + if ((pcm->flags & SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX) && pcm->chan[0]) + return pcm->chan[0]; + if (pcm->config->compat_request_channel) return pcm->config->compat_request_channel(rtd, substream); @@ -148,7 +151,7 @@ static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd) if (!substream) continue; - if (!pcm->chan[i] && pcm->compat) { + if (!pcm->chan[i] && (pcm->flags & SND_DMAENGINE_PCM_FLAG_COMPAT)) { pcm->chan[i] = dmaengine_pcm_compat_request_channel(rtd, substream); } @@ -215,6 +218,25 @@ static const char * const dmaengine_pcm_dma_channel_names[] = { [SNDRV_PCM_STREAM_CAPTURE] = "rx", }; +static void dmaengine_pcm_request_chan_of(struct dmaengine_pcm *pcm, + struct device_node *of_node) +{ + unsigned int i; + + if ((pcm->flags & SND_DMAENGINE_PCM_FLAG_NO_DT) || !of_node) + return; + + if (pcm->flags & SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX) { + pcm->chan[0] = of_dma_request_slave_channel(of_node, "tx_rx"); + pcm->chan[1] = pcm->chan[0]; + } else { + for (i = SNDRV_PCM_STREAM_PLAYBACK; i <= SNDRV_PCM_STREAM_CAPTURE; i++) { + pcm->chan[i] = of_dma_request_slave_channel(of_node, + dmaengine_pcm_dma_channel_names[i]); + } + } +} + /** * snd_dmaengine_pcm_register - Register a dmaengine based PCM device * @dev: The parent device for the PCM device @@ -225,23 +247,15 @@ int snd_dmaengine_pcm_register(struct device *dev, const struct snd_dmaengine_pcm_config *config, unsigned int flags) { struct dmaengine_pcm *pcm; - unsigned int i; pcm = kzalloc(sizeof(*pcm), GFP_KERNEL); if (!pcm) return -ENOMEM; pcm->config = config; + pcm->flags = flags; - if (flags & SND_DMAENGINE_PCM_FLAG_COMPAT) - pcm->compat = true; - - if (!(flags & SND_DMAENGINE_PCM_FLAG_NO_DT) && dev->of_node) { - for (i = SNDRV_PCM_STREAM_PLAYBACK; i <= SNDRV_PCM_STREAM_CAPTURE; i++) { - pcm->chan[i] = of_dma_request_slave_channel(dev->of_node, - dmaengine_pcm_dma_channel_names[i]); - } - } + dmaengine_pcm_request_chan_of(pcm, dev->of_node); if (flags & SND_DMAENGINE_PCM_FLAG_NO_RESIDUE) return snd_soc_add_platform(dev, &pcm->platform, @@ -272,8 +286,11 @@ void snd_dmaengine_pcm_unregister(struct device *dev) pcm = soc_platform_to_pcm(platform); for (i = SNDRV_PCM_STREAM_PLAYBACK; i <= SNDRV_PCM_STREAM_CAPTURE; i++) { - if (pcm->chan[i]) + if (pcm->chan[i]) { dma_release_channel(pcm->chan[i]); + if (pcm->flags & SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX) + break; + } } snd_soc_remove_platform(platform); -- cgit v1.2.3 From e08b34e86dfdb72a62196ce0f03d33f48958d8b9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 24 Apr 2013 07:55:20 +0200 Subject: ALSA: emu10k1: Fix dock firmware loading The commit [b209c4df: ALSA: emu10k1: cache emu1010 firmware] broke the firmware loading of the dock, just (mistakenly) ignoring a different firmware for docks on some models. This patch revives them again. Bugzilla: https://bugs.archlinux.org/task/34865 Reported-and-tested-by: Tobias Powalowski Cc: [v3.8+] Signed-off-by: Takashi Iwai --- include/sound/emu10k1.h | 1 + sound/pci/emu10k1/emu10k1_main.c | 39 +++++++++++++++++++++++++++++++++------ 2 files changed, 34 insertions(+), 6 deletions(-) (limited to 'include/sound') diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index f841ba4bacb8..dfb42ca6d043 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h @@ -1787,6 +1787,7 @@ struct snd_emu10k1 { unsigned int next_free_voice; const struct firmware *firmware; + const struct firmware *dock_fw; #ifdef CONFIG_PM_SLEEP unsigned int *saved_ptr; diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index e6b016693240..bdd888ec9a84 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -657,14 +657,14 @@ static int snd_emu10k1_cardbus_init(struct snd_emu10k1 *emu) return 0; } -static int snd_emu1010_load_firmware(struct snd_emu10k1 *emu) +static int snd_emu1010_load_firmware(struct snd_emu10k1 *emu, + const struct firmware *fw_entry) { int n, i; int reg; int value; unsigned int write_post; unsigned long flags; - const struct firmware *fw_entry = emu->firmware; if (!fw_entry) return -EIO; @@ -725,9 +725,34 @@ static int emu1010_firmware_thread(void *data) /* Return to Audio Dock programming mode */ snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware\n"); snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, EMU_HANA_FPGA_CONFIG_AUDIODOCK); - err = snd_emu1010_load_firmware(emu); - if (err != 0) - continue; + + if (!emu->dock_fw) { + const char *filename = NULL; + switch (emu->card_capabilities->emu_model) { + case EMU_MODEL_EMU1010: + filename = DOCK_FILENAME; + break; + case EMU_MODEL_EMU1010B: + filename = MICRO_DOCK_FILENAME; + break; + case EMU_MODEL_EMU1616: + filename = MICRO_DOCK_FILENAME; + break; + } + if (filename) { + err = request_firmware(&emu->dock_fw, + filename, + &emu->pci->dev); + if (err) + continue; + } + } + + if (emu->dock_fw) { + err = snd_emu1010_load_firmware(emu, emu->dock_fw); + if (err) + continue; + } snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0); snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, ®); @@ -862,7 +887,7 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu) filename, emu->firmware->size); } - err = snd_emu1010_load_firmware(emu); + err = snd_emu1010_load_firmware(emu, emu->firmware); if (err != 0) { snd_printk(KERN_INFO "emu1010: Loading Firmware failed\n"); return err; @@ -1253,6 +1278,8 @@ static int snd_emu10k1_free(struct snd_emu10k1 *emu) kthread_stop(emu->emu1010.firmware_thread); if (emu->firmware) release_firmware(emu->firmware); + if (emu->dock_fw) + release_firmware(emu->dock_fw); if (emu->irq >= 0) free_irq(emu->irq, emu); /* remove reserved page */ -- cgit v1.2.3 From 74c34ca1cc12884703c70d34ed333517d978c2e7 Mon Sep 17 00:00:00 2001 From: Eldad Zack Date: Tue, 23 Apr 2013 01:00:41 +0200 Subject: ALSA: pcm_format_to_bits strong-typed conversion Add a function to handle conversion from snd_pcm_format_t to bitwise with proper typing. Change such conversions to use this function and silence sparse warnings. Signed-off-by: Eldad Zack Signed-off-by: Takashi Iwai --- include/sound/pcm.h | 6 ++++++ sound/aoa/soundbus/i2sbus/pcm.c | 2 +- sound/atmel/ac97c.c | 4 ++-- sound/drivers/aloop.c | 2 +- sound/pci/asihpi/asihpi.c | 4 ++-- sound/usb/format.c | 5 +++-- sound/usb/pcm.c | 4 ++-- sound/usb/proc.c | 2 +- 8 files changed, 18 insertions(+), 11 deletions(-) (limited to 'include/sound') diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 1b0c6484e71a..5357ecbecc48 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -1133,4 +1133,10 @@ int snd_pcm_add_chmap_ctls(struct snd_pcm *pcm, int stream, unsigned long private_value, struct snd_pcm_chmap **info_ret); +/* Strong-typed conversion of pcm_format to bitwise */ +static inline u64 pcm_format_to_bits(snd_pcm_format_t pcm_format) +{ + return 1ULL << (__force int) pcm_format; +} + #endif /* __SOUND_PCM_H */ diff --git a/sound/aoa/soundbus/i2sbus/pcm.c b/sound/aoa/soundbus/i2sbus/pcm.c index 19491ed9292f..7b74a4ba75f8 100644 --- a/sound/aoa/soundbus/i2sbus/pcm.c +++ b/sound/aoa/soundbus/i2sbus/pcm.c @@ -179,7 +179,7 @@ static int i2sbus_pcm_open(struct i2sbus_dev *i2sdev, int in) */ if (other->active) { /* FIXME: is this guaranteed by the alsa api? */ - hw->formats &= (1ULL << i2sdev->format); + hw->formats &= pcm_format_to_bits(i2sdev->format); /* see above, restrict rates to the one we already have */ hw->rate_min = i2sdev->rate; hw->rate_max = i2sdev->rate; diff --git a/sound/atmel/ac97c.c b/sound/atmel/ac97c.c index 79d6bda58753..6b7e2b5a72de 100644 --- a/sound/atmel/ac97c.c +++ b/sound/atmel/ac97c.c @@ -182,7 +182,7 @@ static int atmel_ac97c_playback_open(struct snd_pcm_substream *substream) runtime->hw.rate_max = chip->cur_rate; } if (chip->cur_format) - runtime->hw.formats = (1ULL << chip->cur_format); + runtime->hw.formats = pcm_format_to_bits(chip->cur_format); mutex_unlock(&opened_mutex); chip->playback_substream = substream; return 0; @@ -201,7 +201,7 @@ static int atmel_ac97c_capture_open(struct snd_pcm_substream *substream) runtime->hw.rate_max = chip->cur_rate; } if (chip->cur_format) - runtime->hw.formats = (1ULL << chip->cur_format); + runtime->hw.formats = pcm_format_to_bits(chip->cur_format); mutex_unlock(&opened_mutex); chip->capture_substream = substream; return 0; diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index 64d534710b51..6f78de9c6fb6 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c @@ -325,7 +325,7 @@ static void params_change(struct snd_pcm_substream *substream) struct loopback_pcm *dpcm = runtime->private_data; struct loopback_cable *cable = dpcm->cable; - cable->hw.formats = (1ULL << runtime->format); + cable->hw.formats = pcm_format_to_bits(runtime->format); cable->hw.rate_min = runtime->rate; cable->hw.rate_max = runtime->rate; cable->hw.channels_min = runtime->channels; diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c index 0aabfedeecba..160cf830d327 100644 --- a/sound/pci/asihpi/asihpi.c +++ b/sound/pci/asihpi/asihpi.c @@ -966,7 +966,7 @@ static u64 snd_card_asihpi_playback_formats(struct snd_card_asihpi *asihpi, if (!err) err = hpi_outstream_query_format(h_stream, &hpi_format); if (!err && (hpi_to_alsa_formats[format] != -1)) - formats |= (1ULL << hpi_to_alsa_formats[format]); + formats |= pcm_format_to_bits(hpi_to_alsa_formats[format]); } return formats; } @@ -1142,7 +1142,7 @@ static u64 snd_card_asihpi_capture_formats(struct snd_card_asihpi *asihpi, if (!err) err = hpi_instream_query_format(h_stream, &hpi_format); if (!err) - formats |= (1ULL << hpi_to_alsa_formats[format]); + formats |= pcm_format_to_bits(hpi_to_alsa_formats[format]); } return formats; } diff --git a/sound/usb/format.c b/sound/usb/format.c index 020ede0259eb..99299ffb33ac 100644 --- a/sound/usb/format.c +++ b/sound/usb/format.c @@ -365,7 +365,8 @@ static int parse_audio_format_i(struct snd_usb_audio *chip, { struct usb_interface_descriptor *altsd = get_iface_desc(iface); int protocol = altsd->bInterfaceProtocol; - int pcm_format, ret; + snd_pcm_format_t pcm_format; + int ret; if (fmt->bFormatType == UAC_FORMAT_TYPE_III) { /* FIXME: the format type is really IECxxx @@ -384,7 +385,7 @@ static int parse_audio_format_i(struct snd_usb_audio *chip, default: pcm_format = SNDRV_PCM_FORMAT_S16_LE; } - fp->formats = 1uLL << pcm_format; + fp->formats = pcm_format_to_bits(pcm_format); } else { fp->formats = parse_audio_format_i_type(chip, fp, format, fmt, protocol); diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 9723f3ceb155..93b6e32cfead 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -100,7 +100,7 @@ static struct audioformat *find_format(struct snd_usb_substream *subs) int cur_attr = 0, attr; list_for_each_entry(fp, &subs->fmt_list, list) { - if (!(fp->formats & (1uLL << subs->pcm_format))) + if (!(fp->formats & pcm_format_to_bits(subs->pcm_format))) continue; if (fp->channels != subs->channels) continue; @@ -478,7 +478,7 @@ static int match_endpoint_audioformats(struct audioformat *fp, return 0; } - if (!(fp->formats & (1ULL << pcm_format))) { + if (!(fp->formats & pcm_format_to_bits(pcm_format))) { snd_printdd("%s: (fmt @%p) no match for format %d\n", __func__, fp, pcm_format); return 0; diff --git a/sound/usb/proc.c b/sound/usb/proc.c index 0182ef634d8b..135c76871063 100644 --- a/sound/usb/proc.c +++ b/sound/usb/proc.c @@ -85,7 +85,7 @@ static void proc_dump_substream_formats(struct snd_usb_substream *subs, struct s snd_iprintf(buffer, " Altset %d\n", fp->altsetting); snd_iprintf(buffer, " Format:"); for (fmt = 0; fmt <= SNDRV_PCM_FORMAT_LAST; ++fmt) - if (fp->formats & (1uLL << fmt)) + if (fp->formats & pcm_format_to_bits(fmt)) snd_iprintf(buffer, " %s", snd_pcm_format_name(fmt)); snd_iprintf(buffer, "\n"); -- cgit v1.2.3