From bd6d417743d941c3e5eabb21abbcac9737f11061 Mon Sep 17 00:00:00 2001 From: Mike Arthur Date: Tue, 18 Aug 2009 20:37:49 +0100 Subject: ASoC: Add WM8711 CODEC driver The WM8711 or WM8711L (WM8711/L) is a low power stereo DAC with an integrated headphone driver. The WM8711/L is designed specifically for portable MP3 audio and speech players. The WM8711/L is also ideal for MD, CD machines and DAT players. Signed-off-by: Mike Arthur Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 4 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/wm8711.c | 685 ++++++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/wm8711.h | 42 +++ 4 files changed, 733 insertions(+) create mode 100644 sound/soc/codecs/wm8711.c create mode 100644 sound/soc/codecs/wm8711.h (limited to 'sound') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index b6c7f7a01cb..663840e6776 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -29,6 +29,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_WM8400 if MFD_WM8400 select SND_SOC_WM8510 if SND_SOC_I2C_AND_SPI select SND_SOC_WM8580 if I2C + select SND_SOC_WM8711 if I2C select SND_SOC_WM8728 if SND_SOC_I2C_AND_SPI select SND_SOC_WM8731 if SND_SOC_I2C_AND_SPI select SND_SOC_WM8750 if SND_SOC_I2C_AND_SPI @@ -120,6 +121,9 @@ config SND_SOC_WM8510 config SND_SOC_WM8580 tristate +config SND_SOC_WM8711 + tristate + config SND_SOC_WM8728 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index f2653803ede..19950e998b6 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -17,6 +17,7 @@ snd-soc-wm8350-objs := wm8350.o snd-soc-wm8400-objs := wm8400.o snd-soc-wm8510-objs := wm8510.o snd-soc-wm8580-objs := wm8580.o +snd-soc-wm8711-objs := wm8711.o snd-soc-wm8728-objs := wm8728.o snd-soc-wm8731-objs := wm8731.o snd-soc-wm8750-objs := wm8750.o @@ -48,6 +49,7 @@ obj-$(CONFIG_SND_SOC_WM8350) += snd-soc-wm8350.o obj-$(CONFIG_SND_SOC_WM8400) += snd-soc-wm8400.o obj-$(CONFIG_SND_SOC_WM8510) += snd-soc-wm8510.o obj-$(CONFIG_SND_SOC_WM8580) += snd-soc-wm8580.o +obj-$(CONFIG_SND_SOC_WM8711) += snd-soc-wm8711.o obj-$(CONFIG_SND_SOC_WM8728) += snd-soc-wm8728.o obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c new file mode 100644 index 00000000000..84ead3f9293 --- /dev/null +++ b/sound/soc/codecs/wm8711.c @@ -0,0 +1,685 @@ +/* + * wm8711.c -- WM8711 ALSA SoC Audio driver + * + * Copyright 2006 Wolfson Microelectronics + * + * Author: Mike Arthur + * + * Based on wm8731.c by Richard Purdie + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wm8711.h" + +#define AUDIO_NAME "wm8711" +#define WM8711_VERSION "0.3" + +/* codec private data */ +struct wm8711_priv { + unsigned int sysclk; +}; + +/* + * wm8711 register cache + * We can't read the WM8711 register space when we are + * using 2 wire for device control, so we cache them instead. + * There is no point in caching the reset register + */ +static const u16 wm8711_reg[WM8711_CACHEREGNUM] = { + 0x0079, 0x0079, 0x000a, 0x0008, + 0x009f, 0x000a, 0x0000, 0x0000 +}; + +/* + * read wm8711 register cache + */ +static inline unsigned int wm8711_read_reg_cache(struct snd_soc_codec *codec, + unsigned int reg) +{ + u16 *cache = codec->reg_cache; + if (reg == WM8711_RESET) + return 0; + if (reg >= WM8711_CACHEREGNUM) + return -1; + return cache[reg]; +} + +/* + * write wm8711 register cache + */ +static inline void wm8711_write_reg_cache(struct snd_soc_codec *codec, + u16 reg, unsigned int value) +{ + u16 *cache = codec->reg_cache; + if (reg >= WM8711_CACHEREGNUM) + return; + cache[reg] = value; +} + +/* + * write to the WM8711 register space + */ +static int wm8711_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + u8 data[2]; + + /* data is + * D15..D9 WM8753 register offset + * D8...D0 register data + */ + data[0] = (reg << 1) | ((value >> 8) & 0x0001); + data[1] = value & 0x00ff; + + wm8711_write_reg_cache(codec, reg, value); + if (codec->hw_write(codec->control_data, data, 2) == 2) + return 0; + else + return -EIO; +} + +#define wm8711_reset(c) wm8711_write(c, WM8711_RESET, 0) + +static const struct snd_kcontrol_new wm8711_snd_controls[] = { + +SOC_DOUBLE_R("Master Playback Volume", WM8711_LOUT1V, WM8711_ROUT1V, + 0, 127, 0), +SOC_DOUBLE_R("Master Playback ZC Switch", WM8711_LOUT1V, WM8711_ROUT1V, + 7, 1, 0), + +}; + +/* add non dapm controls */ +static int wm8711_add_controls(struct snd_soc_codec *codec) +{ + int err, i; + + for (i = 0; i < ARRAY_SIZE(wm8711_snd_controls); i++) { + err = snd_ctl_add(codec->card, + snd_soc_cnew(&wm8711_snd_controls[i], codec, + NULL)); + if (err < 0) + return err; + } + + return 0; +} + +/* Output Mixer */ +static const struct snd_kcontrol_new wm8711_output_mixer_controls[] = { +SOC_DAPM_SINGLE("Line Bypass Switch", WM8711_APANA, 3, 1, 0), +SOC_DAPM_SINGLE("HiFi Playback Switch", WM8711_APANA, 4, 1, 0), +}; + +static const struct snd_soc_dapm_widget wm8711_dapm_widgets[] = { +SND_SOC_DAPM_MIXER("Output Mixer", WM8711_PWR, 4, 1, + &wm8711_output_mixer_controls[0], + ARRAY_SIZE(wm8711_output_mixer_controls)), +SND_SOC_DAPM_DAC("DAC", "HiFi Playback", WM8711_PWR, 3, 1), +SND_SOC_DAPM_OUTPUT("LOUT"), +SND_SOC_DAPM_OUTPUT("LHPOUT"), +SND_SOC_DAPM_OUTPUT("ROUT"), +SND_SOC_DAPM_OUTPUT("RHPOUT"), +}; + +static const struct snd_soc_dapm_route intercon[] = { + /* output mixer */ + {"Output Mixer", "Line Bypass Switch", "Line Input"}, + {"Output Mixer", "HiFi Playback Switch", "DAC"}, + + /* outputs */ + {"RHPOUT", NULL, "Output Mixer"}, + {"ROUT", NULL, "Output Mixer"}, + {"LHPOUT", NULL, "Output Mixer"}, + {"LOUT", NULL, "Output Mixer"}, +}; + +static int wm8711_add_widgets(struct snd_soc_codec *codec) +{ + snd_soc_dapm_new_controls(codec, wm8711_dapm_widgets, + ARRAY_SIZE(wm8711_dapm_widgets)); + + snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); + + snd_soc_dapm_new_widgets(codec); + return 0; +} + +struct _coeff_div { + u32 mclk; + u32 rate; + u16 fs; + u8 sr:4; + u8 bosr:1; + u8 usb:1; +}; + +/* codec mclk clock divider coefficients */ +static const struct _coeff_div coeff_div[] = { + /* 48k */ + {12288000, 48000, 256, 0x0, 0x0, 0x0}, + {18432000, 48000, 384, 0x0, 0x1, 0x0}, + {12000000, 48000, 250, 0x0, 0x0, 0x1}, + + /* 32k */ + {12288000, 32000, 384, 0x6, 0x0, 0x0}, + {18432000, 32000, 576, 0x6, 0x1, 0x0}, + {12000000, 32000, 375, 0x6, 0x0, 0x1}, + + /* 8k */ + {12288000, 8000, 1536, 0x3, 0x0, 0x0}, + {18432000, 8000, 2304, 0x3, 0x1, 0x0}, + {11289600, 8000, 1408, 0xb, 0x0, 0x0}, + {16934400, 8000, 2112, 0xb, 0x1, 0x0}, + {12000000, 8000, 1500, 0x3, 0x0, 0x1}, + + /* 96k */ + {12288000, 96000, 128, 0x7, 0x0, 0x0}, + {18432000, 96000, 192, 0x7, 0x1, 0x0}, + {12000000, 96000, 125, 0x7, 0x0, 0x1}, + + /* 44.1k */ + {11289600, 44100, 256, 0x8, 0x0, 0x0}, + {16934400, 44100, 384, 0x8, 0x1, 0x0}, + {12000000, 44100, 272, 0x8, 0x1, 0x1}, + + /* 88.2k */ + {11289600, 88200, 128, 0xf, 0x0, 0x0}, + {16934400, 88200, 192, 0xf, 0x1, 0x0}, + {12000000, 88200, 136, 0xf, 0x1, 0x1}, +}; + +static inline int get_coeff(int mclk, int rate) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(coeff_div); i++) { + if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk) + return i; + } + return 0; +} + +static int wm8711_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 wm8711_priv *wm8711 = codec->private_data; + u16 iface = wm8711_read_reg_cache(codec, WM8711_IFACE) & 0xfffc; + int i = get_coeff(wm8711->sysclk, params_rate(params)); + u16 srate = (coeff_div[i].sr << 2) | + (coeff_div[i].bosr << 1) | coeff_div[i].usb; + + wm8711_write(codec, WM8711_SRATE, srate); + + /* bit size */ + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + break; + case SNDRV_PCM_FORMAT_S20_3LE: + iface |= 0x0004; + break; + case SNDRV_PCM_FORMAT_S24_LE: + iface |= 0x0008; + break; + } + + wm8711_write(codec, WM8711_IFACE, iface); + return 0; +} + +static int wm8711_pcm_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + + /* set active */ + wm8711_write(codec, WM8711_ACTIVE, 0x0001); + + return 0; +} + +static void wm8711_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + + /* deactivate */ + if (!codec->active) { + udelay(50); + wm8711_write(codec, WM8711_ACTIVE, 0x0); + } +} + +static int wm8711_mute(struct snd_soc_dai *dai, int mute) +{ + struct snd_soc_codec *codec = dai->codec; + u16 mute_reg = wm8711_read_reg_cache(codec, WM8711_APDIGI) & 0xfff7; + + if (mute) + wm8711_write(codec, WM8711_APDIGI, mute_reg | 0x8); + else + wm8711_write(codec, WM8711_APDIGI, mute_reg); + + return 0; +} + +static int wm8711_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 wm8711_priv *wm8711 = codec->private_data; + + switch (freq) { + case 11289600: + case 12000000: + case 12288000: + case 16934400: + case 18432000: + wm8711->sysclk = freq; + return 0; + } + return -EINVAL; +} + +static int wm8711_set_dai_fmt(struct snd_soc_dai *codec_dai, + unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + u16 iface = 0; + + /* set master/slave audio interface */ + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + iface |= 0x0040; + break; + case SND_SOC_DAIFMT_CBS_CFS: + break; + default: + return -EINVAL; + } + + /* interface format */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + iface |= 0x0002; + break; + case SND_SOC_DAIFMT_RIGHT_J: + break; + case SND_SOC_DAIFMT_LEFT_J: + iface |= 0x0001; + break; + case SND_SOC_DAIFMT_DSP_A: + iface |= 0x0003; + break; + case SND_SOC_DAIFMT_DSP_B: + iface |= 0x0013; + break; + default: + return -EINVAL; + } + + /* clock inversion */ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_IF: + iface |= 0x0090; + break; + case SND_SOC_DAIFMT_IB_NF: + iface |= 0x0080; + break; + case SND_SOC_DAIFMT_NB_IF: + iface |= 0x0010; + break; + default: + return -EINVAL; + } + + /* set iface */ + wm8711_write(codec, WM8711_IFACE, iface); + return 0; +} + + +static int wm8711_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + u16 reg = wm8711_read_reg_cache(codec, WM8711_PWR) & 0xff7f; + + switch (level) { + case SND_SOC_BIAS_ON: + wm8711_write(codec, WM8711_PWR, reg); + break; + case SND_SOC_BIAS_PREPARE: + break; + case SND_SOC_BIAS_STANDBY: + wm8711_write(codec, WM8711_PWR, reg | 0x0040); + break; + case SND_SOC_BIAS_OFF: + wm8711_write(codec, WM8711_ACTIVE, 0x0); + wm8711_write(codec, WM8711_PWR, 0xffff); + break; + } + codec->bias_level = level; + return 0; +} + +#define WM8711_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ + SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\ + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\ + SNDRV_PCM_RATE_96000) + +#define WM8711_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ + SNDRV_PCM_FMTBIT_S24_LE) + +static struct snd_soc_dai_ops wm8711_ops = { + .prepare = wm8711_pcm_prepare, + .hw_params = wm8711_hw_params, + .shutdown = wm8711_shutdown, + .digital_mute = wm8711_mute, + .set_sysclk = wm8711_set_dai_sysclk, + .set_fmt = wm8711_set_dai_fmt, +}; + +struct snd_soc_dai wm8711_dai = { + .name = "WM8711", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = WM8711_RATES, + .formats = WM8711_FORMATS,}, + .ops = &wm8711_ops, +}; +EXPORT_SYMBOL_GPL(wm8711_dai); + +static int wm8711_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + + wm8711_write(codec, WM8711_ACTIVE, 0x0); + wm8711_set_bias_level(codec, SND_SOC_BIAS_OFF); + return 0; +} + +static int wm8711_resume(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + int i; + u8 data[2]; + u16 *cache = codec->reg_cache; + + /* Sync reg_cache with the hardware */ + for (i = 0; i < ARRAY_SIZE(wm8711_reg); i++) { + data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001); + data[1] = cache[i] & 0x00ff; + codec->hw_write(codec->control_data, data, 2); + } + wm8711_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + wm8711_set_bias_level(codec, codec->suspend_bias_level); + return 0; +} + +/* + * initialise the WM8711 driver + * register the mixer and dsp interfaces with the kernel + */ +static int wm8711_init(struct snd_soc_device *socdev) +{ + struct snd_soc_codec *codec = socdev->card->codec; + int reg, ret = 0; + + codec->name = "WM8711"; + codec->owner = THIS_MODULE; + codec->read = wm8711_read_reg_cache; + codec->write = wm8711_write; + codec->set_bias_level = wm8711_set_bias_level; + codec->dai = &wm8711_dai; + codec->num_dai = 1; + codec->reg_cache_size = ARRAY_SIZE(wm8711_reg); + codec->reg_cache = kmemdup(wm8711_reg, sizeof(wm8711_reg), GFP_KERNEL); + + if (codec->reg_cache == NULL) + return -ENOMEM; + + wm8711_reset(codec); + + /* register pcms */ + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) { + printk(KERN_ERR "wm8711: failed to create pcms\n"); + goto pcm_err; + } + + /* power on device */ + wm8711_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + /* set the update bits */ + reg = wm8711_read_reg_cache(codec, WM8711_LOUT1V); + wm8711_write(codec, WM8711_LOUT1V, reg | 0x0100); + reg = wm8711_read_reg_cache(codec, WM8711_ROUT1V); + wm8711_write(codec, WM8711_ROUT1V, reg | 0x0100); + + wm8711_add_controls(codec); + wm8711_add_widgets(codec); + ret = snd_soc_init_card(socdev); + if (ret < 0) { + printk(KERN_ERR "wm8711: failed to register card\n"); + goto card_err; + } + return ret; + +card_err: + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); +pcm_err: + kfree(codec->reg_cache); + return ret; +} + +static struct snd_soc_device *wm8711_socdev; + +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + +/* + * WM8711 2 wire address is determined by GPIO5 + * state during powerup. + * low = 0x1a + * high = 0x1b + */ +#define I2C_DRIVERID_WM8711 0xfefe /* liam - need a proper id */ + +static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; + +/* Magic definition of all other variables and things */ +I2C_CLIENT_INSMOD; + +static struct i2c_driver wm8711_i2c_driver; +static struct i2c_client client_template; + +/* If the i2c layer weren't so broken, we could pass this kind of data + around */ + +static int wm8711_codec_probe(struct i2c_adapter *adap, int addr, int kind) +{ + struct snd_soc_device *socdev = wm8711_socdev; + struct wm8711_setup_data *setup = socdev->codec_data; + struct snd_soc_codec *codec = socdev->card->codec; + struct i2c_client *i2c; + int ret; + + if (addr != setup->i2c_address) + return -ENODEV; + + client_template.adapter = adap; + client_template.addr = addr; + + i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); + if (i2c == NULL) { + kfree(codec); + return -ENOMEM; + } + + i2c_set_clientdata(i2c, codec); + + codec->control_data = i2c; + + ret = i2c_attach_client(i2c); + if (ret < 0) { + pr_err("failed to attach codec at addr %x\n", addr); + goto err; + } + + ret = wm8711_init(socdev); + if (ret < 0) { + pr_err("failed to initialise WM8711\n"); + goto err; + } + return ret; + +err: + kfree(codec); + kfree(i2c); + return ret; +} + +static int wm8711_i2c_detach(struct i2c_client *client) +{ + struct snd_soc_codec *codec = i2c_get_clientdata(client); + + i2c_detach_client(client); + kfree(codec->reg_cache); + kfree(client); + return 0; +} + +static int wm8711_i2c_attach(struct i2c_adapter *adap) +{ + return i2c_probe(adap, &addr_data, wm8711_codec_probe); +} + +/* corgi i2c codec control layer */ +static struct i2c_driver wm8711_i2c_driver = { + .driver = { + .name = "WM8711 I2C Codec", + .owner = THIS_MODULE, + }, + .id = I2C_DRIVERID_WM8711, + .attach_adapter = wm8711_i2c_attach, + .detach_client = wm8711_i2c_detach, + .command = NULL, +}; + +static struct i2c_client client_template = { + .name = "WM8711", + .driver = &wm8711_i2c_driver, +}; +#endif + +static int wm8711_probe(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct wm8711_setup_data *setup; + struct snd_soc_codec *codec; + struct wm8711_priv *wm8711; + int ret = 0; + + pr_info("WM8711 Audio Codec %s", WM8711_VERSION); + + setup = socdev->codec_data; + codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); + if (codec == NULL) + return -ENOMEM; + + wm8711 = kzalloc(sizeof(struct wm8711_priv), GFP_KERNEL); + if (wm8711 == NULL) { + kfree(codec); + return -ENOMEM; + } + + codec->private_data = wm8711; + socdev->card->codec = codec; + mutex_init(&codec->mutex); + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + + wm8711_socdev = socdev; +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + if (setup->i2c_address) { + normal_i2c[0] = setup->i2c_address; + codec->hw_write = (hw_write_t)i2c_master_send; + ret = i2c_add_driver(&wm8711_i2c_driver); + if (ret != 0) + printk(KERN_ERR "can't add i2c driver"); + } +#else + /* Add other interfaces here */ +#endif + return ret; +} + +/* power down chip */ +static int wm8711_remove(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + + if (codec->control_data) + wm8711_set_bias_level(codec, SND_SOC_BIAS_OFF); + + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + i2c_del_driver(&wm8711_i2c_driver); +#endif + kfree(codec->private_data); + kfree(codec); + + return 0; +} + +struct snd_soc_codec_device soc_codec_dev_wm8711 = { + .probe = wm8711_probe, + .remove = wm8711_remove, + .suspend = wm8711_suspend, + .resume = wm8711_resume, +}; +EXPORT_SYMBOL_GPL(soc_codec_dev_wm8711); + +static int __init wm8711_modinit(void) +{ + return snd_soc_register_dai(&wm8711_dai); +} +module_init(wm8711_modinit); + +static void __exit wm8711_exit(void) +{ + snd_soc_unregister_dai(&wm8711_dai); +} +module_exit(wm8711_exit); + +MODULE_DESCRIPTION("ASoC WM8711 driver"); +MODULE_AUTHOR("Mike Arthur"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8711.h b/sound/soc/codecs/wm8711.h new file mode 100644 index 00000000000..381e84a4381 --- /dev/null +++ b/sound/soc/codecs/wm8711.h @@ -0,0 +1,42 @@ +/* + * wm8711.h -- WM8711 Soc Audio driver + * + * Copyright 2006 Wolfson Microelectronics + * + * Author: Mike Arthur + * + * Based on wm8731.h + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _WM8711_H +#define _WM8711_H + +/* WM8711 register space */ + +#define WM8711_LOUT1V 0x02 +#define WM8711_ROUT1V 0x03 +#define WM8711_APANA 0x04 +#define WM8711_APDIGI 0x05 +#define WM8711_PWR 0x06 +#define WM8711_IFACE 0x07 +#define WM8711_SRATE 0x08 +#define WM8711_ACTIVE 0x09 +#define WM8711_RESET 0x0f + +#define WM8711_CACHEREGNUM 8 + +#define WM8711_SYSCLK 0 +#define WM8711_DAI 0 + +struct wm8711_setup_data { + unsigned short i2c_address; +}; + +extern struct snd_soc_dai wm8711_dai; +extern struct snd_soc_codec_device soc_codec_dev_wm8711; + +#endif -- cgit v1.2.3 From 318b0b8d90326aee6a66c994432eee95c0a9aaea Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 18 Aug 2009 20:57:33 +0100 Subject: ASoC: Update WM8711 to driver model registration method Signed-off-by: Mark Brown --- sound/soc/codecs/wm8711.c | 297 ++++++++++++++++++++-------------------------- 1 file changed, 129 insertions(+), 168 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c index 84ead3f9293..812283e2760 100644 --- a/sound/soc/codecs/wm8711.c +++ b/sound/soc/codecs/wm8711.c @@ -28,11 +28,12 @@ #include "wm8711.h" -#define AUDIO_NAME "wm8711" -#define WM8711_VERSION "0.3" +static struct snd_soc_codec *wm8711_codec; /* codec private data */ struct wm8711_priv { + struct snd_soc_codec codec; + u16 reg_cache[WM8711_CACHEREGNUM]; unsigned int sysclk; }; @@ -442,241 +443,201 @@ static int wm8711_resume(struct platform_device *pdev) return 0; } -/* - * initialise the WM8711 driver - * register the mixer and dsp interfaces with the kernel - */ -static int wm8711_init(struct snd_soc_device *socdev) +static int wm8711_probe(struct platform_device *pdev) { - struct snd_soc_codec *codec = socdev->card->codec; - int reg, ret = 0; - - codec->name = "WM8711"; - codec->owner = THIS_MODULE; - codec->read = wm8711_read_reg_cache; - codec->write = wm8711_write; - codec->set_bias_level = wm8711_set_bias_level; - codec->dai = &wm8711_dai; - codec->num_dai = 1; - codec->reg_cache_size = ARRAY_SIZE(wm8711_reg); - codec->reg_cache = kmemdup(wm8711_reg, sizeof(wm8711_reg), GFP_KERNEL); + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec; + int ret = 0; - if (codec->reg_cache == NULL) - return -ENOMEM; + if (wm8711_codec == NULL) { + dev_err(&pdev->dev, "Codec device not registered\n"); + return -ENODEV; + } - wm8711_reset(codec); + socdev->card->codec = wm8711_codec; + codec = wm8711_codec; /* register pcms */ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); if (ret < 0) { - printk(KERN_ERR "wm8711: failed to create pcms\n"); + dev_err(codec->dev, "failed to create pcms: %d\n", ret); goto pcm_err; } - /* power on device */ - wm8711_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - /* set the update bits */ - reg = wm8711_read_reg_cache(codec, WM8711_LOUT1V); - wm8711_write(codec, WM8711_LOUT1V, reg | 0x0100); - reg = wm8711_read_reg_cache(codec, WM8711_ROUT1V); - wm8711_write(codec, WM8711_ROUT1V, reg | 0x0100); - - wm8711_add_controls(codec); + snd_soc_add_controls(codec, wm8711_snd_controls, + ARRAY_SIZE(wm8711_snd_controls)); wm8711_add_widgets(codec); ret = snd_soc_init_card(socdev); if (ret < 0) { - printk(KERN_ERR "wm8711: failed to register card\n"); + dev_err(codec->dev, "failed to register card: %d\n", ret); goto card_err; } + return ret; card_err: snd_soc_free_pcms(socdev); snd_soc_dapm_free(socdev); pcm_err: - kfree(codec->reg_cache); return ret; } -static struct snd_soc_device *wm8711_socdev; - -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - -/* - * WM8711 2 wire address is determined by GPIO5 - * state during powerup. - * low = 0x1a - * high = 0x1b - */ -#define I2C_DRIVERID_WM8711 0xfefe /* liam - need a proper id */ - -static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; +/* power down chip */ +static int wm8711_remove(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); -/* Magic definition of all other variables and things */ -I2C_CLIENT_INSMOD; + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); -static struct i2c_driver wm8711_i2c_driver; -static struct i2c_client client_template; + return 0; +} -/* If the i2c layer weren't so broken, we could pass this kind of data - around */ +struct snd_soc_codec_device soc_codec_dev_wm8711 = { + .probe = wm8711_probe, + .remove = wm8711_remove, + .suspend = wm8711_suspend, + .resume = wm8711_resume, +}; +EXPORT_SYMBOL_GPL(soc_codec_dev_wm8711); -static int wm8711_codec_probe(struct i2c_adapter *adap, int addr, int kind) +static int wm8711_register(struct wm8711_priv *wm8711) { - struct snd_soc_device *socdev = wm8711_socdev; - struct wm8711_setup_data *setup = socdev->codec_data; - struct snd_soc_codec *codec = socdev->card->codec; - struct i2c_client *i2c; int ret; + struct snd_soc_codec *codec = &wm8711->codec; + u16 reg; - if (addr != setup->i2c_address) - return -ENODEV; - - client_template.adapter = adap; - client_template.addr = addr; - - i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); - if (i2c == NULL) { - kfree(codec); - return -ENOMEM; + if (wm8711_codec) { + dev_err(codec->dev, "Another WM8711 is registered\n"); + return -EINVAL; } - i2c_set_clientdata(i2c, codec); + mutex_init(&codec->mutex); + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); - codec->control_data = i2c; + codec->private_data = wm8711; + codec->name = "WM8711"; + codec->owner = THIS_MODULE; + codec->read = wm8711_read_reg_cache; + codec->write = wm8711_write; + codec->bias_level = SND_SOC_BIAS_OFF; + codec->set_bias_level = wm8711_set_bias_level; + codec->dai = &wm8711_dai; + codec->num_dai = 1; + codec->reg_cache_size = WM8711_CACHEREGNUM; + codec->reg_cache = &wm8711->reg_cache; - ret = i2c_attach_client(i2c); - if (ret < 0) { - pr_err("failed to attach codec at addr %x\n", addr); - goto err; - } + memcpy(codec->reg_cache, wm8711_reg, sizeof(wm8711_reg)); - ret = wm8711_init(socdev); + ret = wm8711_reset(codec); if (ret < 0) { - pr_err("failed to initialise WM8711\n"); - goto err; + dev_err(codec->dev, "Failed to issue reset\n"); + return ret; } - return ret; -err: - kfree(codec); - kfree(i2c); - return ret; -} + wm8711_dai.dev = codec->dev; -static int wm8711_i2c_detach(struct i2c_client *client) -{ - struct snd_soc_codec *codec = i2c_get_clientdata(client); + wm8711_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + /* Latch the update bits */ + reg = wm8711_read_reg_cache(codec, WM8711_LOUT1V); + wm8711_write(codec, WM8711_LOUT1V, reg | 0x0100); + reg = wm8711_read_reg_cache(codec, WM8711_ROUT1V); + wm8711_write(codec, WM8711_ROUT1V, reg | 0x0100); + + wm8711_codec = codec; + + ret = snd_soc_register_codec(codec); + if (ret != 0) { + dev_err(codec->dev, "Failed to register codec: %d\n", ret); + return ret; + } + + ret = snd_soc_register_dai(&wm8711_dai); + if (ret != 0) { + dev_err(codec->dev, "Failed to register DAI: %d\n", ret); + snd_soc_unregister_codec(codec); + return ret; + } - i2c_detach_client(client); - kfree(codec->reg_cache); - kfree(client); return 0; } -static int wm8711_i2c_attach(struct i2c_adapter *adap) +static void wm8711_unregister(struct wm8711_priv *wm8711) { - return i2c_probe(adap, &addr_data, wm8711_codec_probe); + wm8711_set_bias_level(&wm8711->codec, SND_SOC_BIAS_OFF); + snd_soc_unregister_dai(&wm8711_dai); + snd_soc_unregister_codec(&wm8711->codec); + kfree(wm8711); + wm8711_codec = NULL; } -/* corgi i2c codec control layer */ -static struct i2c_driver wm8711_i2c_driver = { - .driver = { - .name = "WM8711 I2C Codec", - .owner = THIS_MODULE, - }, - .id = I2C_DRIVERID_WM8711, - .attach_adapter = wm8711_i2c_attach, - .detach_client = wm8711_i2c_detach, - .command = NULL, -}; - -static struct i2c_client client_template = { - .name = "WM8711", - .driver = &wm8711_i2c_driver, -}; -#endif - -static int wm8711_probe(struct platform_device *pdev) +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +static __devinit int wm8711_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct wm8711_setup_data *setup; - struct snd_soc_codec *codec; struct wm8711_priv *wm8711; - int ret = 0; - - pr_info("WM8711 Audio Codec %s", WM8711_VERSION); - - setup = socdev->codec_data; - codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); - if (codec == NULL) - return -ENOMEM; + struct snd_soc_codec *codec; wm8711 = kzalloc(sizeof(struct wm8711_priv), GFP_KERNEL); - if (wm8711 == NULL) { - kfree(codec); + if (wm8711 == NULL) return -ENOMEM; - } - codec->private_data = wm8711; - socdev->card->codec = codec; - mutex_init(&codec->mutex); - INIT_LIST_HEAD(&codec->dapm_widgets); - INIT_LIST_HEAD(&codec->dapm_paths); - - wm8711_socdev = socdev; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - if (setup->i2c_address) { - normal_i2c[0] = setup->i2c_address; - codec->hw_write = (hw_write_t)i2c_master_send; - ret = i2c_add_driver(&wm8711_i2c_driver); - if (ret != 0) - printk(KERN_ERR "can't add i2c driver"); - } -#else - /* Add other interfaces here */ -#endif - return ret; -} + codec = &wm8711->codec; + codec->hw_write = (hw_write_t)i2c_master_send; -/* power down chip */ -static int wm8711_remove(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->card->codec; + i2c_set_clientdata(i2c, wm8711); + codec->control_data = i2c; - if (codec->control_data) - wm8711_set_bias_level(codec, SND_SOC_BIAS_OFF); + codec->dev = &i2c->dev; - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - i2c_del_driver(&wm8711_i2c_driver); -#endif - kfree(codec->private_data); - kfree(codec); + return wm8711_register(wm8711); +} +static __devexit int wm8711_i2c_remove(struct i2c_client *client) +{ + struct wm8711_priv *wm8711 = i2c_get_clientdata(client); + wm8711_unregister(wm8711); return 0; } -struct snd_soc_codec_device soc_codec_dev_wm8711 = { - .probe = wm8711_probe, - .remove = wm8711_remove, - .suspend = wm8711_suspend, - .resume = wm8711_resume, +static const struct i2c_device_id wm8711_i2c_id[] = { + { "wm8711", 0 }, + { } }; -EXPORT_SYMBOL_GPL(soc_codec_dev_wm8711); +MODULE_DEVICE_TABLE(i2c, wm8711_i2c_id); + +static struct i2c_driver wm8711_i2c_driver = { + .driver = { + .name = "WM8711 I2C Codec", + .owner = THIS_MODULE, + }, + .probe = wm8711_i2c_probe, + .remove = __devexit_p(wm8711_i2c_remove), + .id_table = wm8711_i2c_id, +}; +#endif static int __init wm8711_modinit(void) { - return snd_soc_register_dai(&wm8711_dai); + int ret; +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + ret = i2c_add_driver(&wm8711_i2c_driver); + if (ret != 0) { + printk(KERN_ERR "Failed to register WM8711 I2C driver: %d\n", + ret); + } +#endif + return 0; } module_init(wm8711_modinit); static void __exit wm8711_exit(void) { - snd_soc_unregister_dai(&wm8711_dai); +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + i2c_del_driver(&wm8711_i2c_driver); +#endif } module_exit(wm8711_exit); -- cgit v1.2.3 From d97d2e35b903b11dc6f7f8fcbe9a82fd8929e234 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 18 Aug 2009 21:12:30 +0100 Subject: ASoC: Factor out WM8711 cache I/O Signed-off-by: Mark Brown --- sound/soc/codecs/wm8711.c | 114 ++++++++++++++++------------------------------ 1 file changed, 38 insertions(+), 76 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c index 812283e2760..c7b1af89297 100644 --- a/sound/soc/codecs/wm8711.c +++ b/sound/soc/codecs/wm8711.c @@ -48,55 +48,7 @@ static const u16 wm8711_reg[WM8711_CACHEREGNUM] = { 0x009f, 0x000a, 0x0000, 0x0000 }; -/* - * read wm8711 register cache - */ -static inline unsigned int wm8711_read_reg_cache(struct snd_soc_codec *codec, - unsigned int reg) -{ - u16 *cache = codec->reg_cache; - if (reg == WM8711_RESET) - return 0; - if (reg >= WM8711_CACHEREGNUM) - return -1; - return cache[reg]; -} - -/* - * write wm8711 register cache - */ -static inline void wm8711_write_reg_cache(struct snd_soc_codec *codec, - u16 reg, unsigned int value) -{ - u16 *cache = codec->reg_cache; - if (reg >= WM8711_CACHEREGNUM) - return; - cache[reg] = value; -} - -/* - * write to the WM8711 register space - */ -static int wm8711_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - u8 data[2]; - - /* data is - * D15..D9 WM8753 register offset - * D8...D0 register data - */ - data[0] = (reg << 1) | ((value >> 8) & 0x0001); - data[1] = value & 0x00ff; - - wm8711_write_reg_cache(codec, reg, value); - if (codec->hw_write(codec->control_data, data, 2) == 2) - return 0; - else - return -EIO; -} - -#define wm8711_reset(c) wm8711_write(c, WM8711_RESET, 0) +#define wm8711_reset(c) snd_soc_write(c, WM8711_RESET, 0) static const struct snd_kcontrol_new wm8711_snd_controls[] = { @@ -224,12 +176,12 @@ static int wm8711_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_codec *codec = dai->codec; struct wm8711_priv *wm8711 = codec->private_data; - u16 iface = wm8711_read_reg_cache(codec, WM8711_IFACE) & 0xfffc; + u16 iface = snd_soc_read(codec, WM8711_IFACE) & 0xfffc; int i = get_coeff(wm8711->sysclk, params_rate(params)); u16 srate = (coeff_div[i].sr << 2) | (coeff_div[i].bosr << 1) | coeff_div[i].usb; - wm8711_write(codec, WM8711_SRATE, srate); + snd_soc_write(codec, WM8711_SRATE, srate); /* bit size */ switch (params_format(params)) { @@ -243,7 +195,7 @@ static int wm8711_hw_params(struct snd_pcm_substream *substream, break; } - wm8711_write(codec, WM8711_IFACE, iface); + snd_soc_write(codec, WM8711_IFACE, iface); return 0; } @@ -253,7 +205,7 @@ static int wm8711_pcm_prepare(struct snd_pcm_substream *substream, struct snd_soc_codec *codec = dai->codec; /* set active */ - wm8711_write(codec, WM8711_ACTIVE, 0x0001); + snd_soc_write(codec, WM8711_ACTIVE, 0x0001); return 0; } @@ -266,19 +218,19 @@ static void wm8711_shutdown(struct snd_pcm_substream *substream, /* deactivate */ if (!codec->active) { udelay(50); - wm8711_write(codec, WM8711_ACTIVE, 0x0); + snd_soc_write(codec, WM8711_ACTIVE, 0x0); } } static int wm8711_mute(struct snd_soc_dai *dai, int mute) { struct snd_soc_codec *codec = dai->codec; - u16 mute_reg = wm8711_read_reg_cache(codec, WM8711_APDIGI) & 0xfff7; + u16 mute_reg = snd_soc_read(codec, WM8711_APDIGI) & 0xfff7; if (mute) - wm8711_write(codec, WM8711_APDIGI, mute_reg | 0x8); + snd_soc_write(codec, WM8711_APDIGI, mute_reg | 0x8); else - wm8711_write(codec, WM8711_APDIGI, mute_reg); + snd_soc_write(codec, WM8711_APDIGI, mute_reg); return 0; } @@ -356,7 +308,7 @@ static int wm8711_set_dai_fmt(struct snd_soc_dai *codec_dai, } /* set iface */ - wm8711_write(codec, WM8711_IFACE, iface); + snd_soc_write(codec, WM8711_IFACE, iface); return 0; } @@ -364,20 +316,20 @@ static int wm8711_set_dai_fmt(struct snd_soc_dai *codec_dai, static int wm8711_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { - u16 reg = wm8711_read_reg_cache(codec, WM8711_PWR) & 0xff7f; + u16 reg = snd_soc_read(codec, WM8711_PWR) & 0xff7f; switch (level) { case SND_SOC_BIAS_ON: - wm8711_write(codec, WM8711_PWR, reg); + snd_soc_write(codec, WM8711_PWR, reg); break; case SND_SOC_BIAS_PREPARE: break; case SND_SOC_BIAS_STANDBY: - wm8711_write(codec, WM8711_PWR, reg | 0x0040); + snd_soc_write(codec, WM8711_PWR, reg | 0x0040); break; case SND_SOC_BIAS_OFF: - wm8711_write(codec, WM8711_ACTIVE, 0x0); - wm8711_write(codec, WM8711_PWR, 0xffff); + snd_soc_write(codec, WM8711_ACTIVE, 0x0); + snd_soc_write(codec, WM8711_PWR, 0xffff); break; } codec->bias_level = level; @@ -419,7 +371,7 @@ static int wm8711_suspend(struct platform_device *pdev, pm_message_t state) struct snd_soc_device *socdev = platform_get_drvdata(pdev); struct snd_soc_codec *codec = socdev->card->codec; - wm8711_write(codec, WM8711_ACTIVE, 0x0); + snd_soc_write(codec, WM8711_ACTIVE, 0x0); wm8711_set_bias_level(codec, SND_SOC_BIAS_OFF); return 0; } @@ -501,7 +453,8 @@ struct snd_soc_codec_device soc_codec_dev_wm8711 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8711); -static int wm8711_register(struct wm8711_priv *wm8711) +static int wm8711_register(struct wm8711_priv *wm8711, + enum snd_soc_control_type control) { int ret; struct snd_soc_codec *codec = &wm8711->codec; @@ -519,8 +472,6 @@ static int wm8711_register(struct wm8711_priv *wm8711) codec->private_data = wm8711; codec->name = "WM8711"; codec->owner = THIS_MODULE; - codec->read = wm8711_read_reg_cache; - codec->write = wm8711_write; codec->bias_level = SND_SOC_BIAS_OFF; codec->set_bias_level = wm8711_set_bias_level; codec->dai = &wm8711_dai; @@ -530,10 +481,16 @@ static int wm8711_register(struct wm8711_priv *wm8711) memcpy(codec->reg_cache, wm8711_reg, sizeof(wm8711_reg)); + ret = snd_soc_codec_set_cache_io(codec, 7, 9, control); + if (ret < 0) { + dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); + goto err; + } + ret = wm8711_reset(codec); if (ret < 0) { dev_err(codec->dev, "Failed to issue reset\n"); - return ret; + goto err; } wm8711_dai.dev = codec->dev; @@ -541,27 +498,32 @@ static int wm8711_register(struct wm8711_priv *wm8711) wm8711_set_bias_level(codec, SND_SOC_BIAS_STANDBY); /* Latch the update bits */ - reg = wm8711_read_reg_cache(codec, WM8711_LOUT1V); - wm8711_write(codec, WM8711_LOUT1V, reg | 0x0100); - reg = wm8711_read_reg_cache(codec, WM8711_ROUT1V); - wm8711_write(codec, WM8711_ROUT1V, reg | 0x0100); + reg = snd_soc_read(codec, WM8711_LOUT1V); + snd_soc_write(codec, WM8711_LOUT1V, reg | 0x0100); + reg = snd_soc_read(codec, WM8711_ROUT1V); + snd_soc_write(codec, WM8711_ROUT1V, reg | 0x0100); wm8711_codec = codec; ret = snd_soc_register_codec(codec); if (ret != 0) { dev_err(codec->dev, "Failed to register codec: %d\n", ret); - return ret; + goto err; } ret = snd_soc_register_dai(&wm8711_dai); if (ret != 0) { dev_err(codec->dev, "Failed to register DAI: %d\n", ret); - snd_soc_unregister_codec(codec); - return ret; + goto err_codec; } return 0; + +err_codec: + snd_soc_unregister_codec(codec); +err: + kfree(wm8711); + return ret; } static void wm8711_unregister(struct wm8711_priv *wm8711) @@ -592,7 +554,7 @@ static __devinit int wm8711_i2c_probe(struct i2c_client *i2c, codec->dev = &i2c->dev; - return wm8711_register(wm8711); + return wm8711_register(wm8711, SND_SOC_I2C); } static __devexit int wm8711_i2c_remove(struct i2c_client *client) -- cgit v1.2.3 From 08aff8cd7a8568588d460c4bf8875a492d430314 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 18 Aug 2009 21:15:14 +0100 Subject: ASoC: Add SPI support to WM8711 Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 2 +- sound/soc/codecs/wm8711.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index a5cfa78eb16..20ebf7437f9 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -35,7 +35,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_WM8510 if SND_SOC_I2C_AND_SPI select SND_SOC_WM8523 if I2C select SND_SOC_WM8580 if I2C - select SND_SOC_WM8711 if I2C + select SND_SOC_WM8711 if SND_SOC_I2C_AND_SPI select SND_SOC_WM8728 if SND_SOC_I2C_AND_SPI select SND_SOC_WM8731 if SND_SOC_I2C_AND_SPI select SND_SOC_WM8750 if SND_SOC_I2C_AND_SPI diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c index c7b1af89297..1a7fca7d1ef 100644 --- a/sound/soc/codecs/wm8711.c +++ b/sound/soc/codecs/wm8711.c @@ -535,6 +535,62 @@ static void wm8711_unregister(struct wm8711_priv *wm8711) wm8711_codec = NULL; } +#if defined(CONFIG_SPI_MASTER) +static int __devinit wm8711_spi_probe(struct spi_device *spi) +{ + struct snd_soc_codec *codec; + struct wm8711_priv *wm8711; + + wm8711 = kzalloc(sizeof(struct wm8711_priv), GFP_KERNEL); + if (wm8711 == NULL) + return -ENOMEM; + + codec = &wm8711->codec; + codec->control_data = spi; + codec->dev = &spi->dev; + + dev_set_drvdata(&spi->dev, wm8711); + + return wm8711_register(wm8711, SND_SOC_SPI); +} + +static int __devexit wm8711_spi_remove(struct spi_device *spi) +{ + struct wm8711_priv *wm8711 = dev_get_drvdata(&spi->dev); + + wm8711_unregister(wm8711); + + return 0; +} + +#ifdef CONFIG_PM +static int wm8711_spi_suspend(struct spi_device *spi, pm_message_t msg) +{ + return snd_soc_suspend_device(&spi->dev); +} + +static int wm8711_spi_resume(struct spi_device *spi) +{ + return snd_soc_resume_device(&spi->dev); +} +#else +#define wm8711_spi_suspend NULL +#define wm8711_spi_resume NULL +#endif + +static struct spi_driver wm8711_spi_driver = { + .driver = { + .name = "wm8711", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + .probe = wm8711_spi_probe, + .suspend = wm8711_spi_suspend, + .resume = wm8711_spi_resume, + .remove = __devexit_p(wm8711_spi_remove), +}; +#endif /* CONFIG_SPI_MASTER */ + #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) static __devinit int wm8711_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) @@ -590,6 +646,13 @@ static int __init wm8711_modinit(void) printk(KERN_ERR "Failed to register WM8711 I2C driver: %d\n", ret); } +#endif +#if defined(CONFIG_SPI_MASTER) + ret = spi_register_driver(&wm8731_spi_driver); + if (ret != 0) { + printk(KERN_ERR "Failed to register WM8731 SPI driver: %d\n", + ret); + } #endif return 0; } @@ -600,6 +663,9 @@ static void __exit wm8711_exit(void) #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) i2c_del_driver(&wm8711_i2c_driver); #endif +#if defined(CONFIG_SPI_MASTER) + spi_unregister_driver(&wm8731_spi_driver); +#endif } module_exit(wm8711_exit); -- cgit v1.2.3 From 431f7771774e8f37dde5acb3f7c4c5f6fa1109e3 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 18 Aug 2009 21:17:34 +0100 Subject: ASoC: WM8711 minor cleanups Coding style changes only. Signed-off-by: Mark Brown --- sound/soc/codecs/wm8711.c | 25 +++---------------------- 1 file changed, 3 insertions(+), 22 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c index 1a7fca7d1ef..f98c2bc32f9 100644 --- a/sound/soc/codecs/wm8711.c +++ b/sound/soc/codecs/wm8711.c @@ -59,22 +59,6 @@ SOC_DOUBLE_R("Master Playback ZC Switch", WM8711_LOUT1V, WM8711_ROUT1V, }; -/* add non dapm controls */ -static int wm8711_add_controls(struct snd_soc_codec *codec) -{ - int err, i; - - for (i = 0; i < ARRAY_SIZE(wm8711_snd_controls); i++) { - err = snd_ctl_add(codec->card, - snd_soc_cnew(&wm8711_snd_controls[i], codec, - NULL)); - if (err < 0) - return err; - } - - return 0; -} - /* Output Mixer */ static const struct snd_kcontrol_new wm8711_output_mixer_controls[] = { SOC_DAPM_SINGLE("Line Bypass Switch", WM8711_APANA, 3, 1, 0), @@ -336,11 +320,7 @@ static int wm8711_set_bias_level(struct snd_soc_codec *codec, return 0; } -#define WM8711_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ - SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ - SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\ - SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\ - SNDRV_PCM_RATE_96000) +#define WM8711_RATES SNDRV_PCM_RATE_8000_96000 #define WM8711_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ SNDRV_PCM_FMTBIT_S24_LE) @@ -361,7 +341,8 @@ struct snd_soc_dai wm8711_dai = { .channels_min = 1, .channels_max = 2, .rates = WM8711_RATES, - .formats = WM8711_FORMATS,}, + .formats = WM8711_FORMATS, + }, .ops = &wm8711_ops, }; EXPORT_SYMBOL_GPL(wm8711_dai); -- cgit v1.2.3 From b5ab887e6dfa12c32ef39827da47d5d021320a3f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 18 Aug 2009 21:29:31 +0100 Subject: ASoC: Add TLV information to WM8711 Signed-off-by: Mark Brown --- sound/soc/codecs/wm8711.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c index f98c2bc32f9..ae083eb92fb 100644 --- a/sound/soc/codecs/wm8711.c +++ b/sound/soc/codecs/wm8711.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include "wm8711.h" @@ -50,10 +51,12 @@ static const u16 wm8711_reg[WM8711_CACHEREGNUM] = { #define wm8711_reset(c) snd_soc_write(c, WM8711_RESET, 0) +static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1); + static const struct snd_kcontrol_new wm8711_snd_controls[] = { -SOC_DOUBLE_R("Master Playback Volume", WM8711_LOUT1V, WM8711_ROUT1V, - 0, 127, 0), +SOC_DOUBLE_R_TLV("Master Playback Volume", WM8711_LOUT1V, WM8711_ROUT1V, + 0, 127, 0, out_tlv), SOC_DOUBLE_R("Master Playback ZC Switch", WM8711_LOUT1V, WM8711_ROUT1V, 7, 1, 0), -- cgit v1.2.3 From 85488037bb9b533b064be66412dbe1dbcd2734d9 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 5 Sep 2009 18:52:16 +0100 Subject: ASoC: Add source argument to PLL configuration More and more devices feature PLLs and FLLs with the ability to select between multiple input clocks. In order to better support these devices a new argument, source, has been added to the set_pll() configuration API. Using set_clkdiv() is often difficult due to the need to stop the PLL/FLL before any reconfiguration can be done. Signed-off-by: Mark Brown --- sound/soc/atmel/playpaq_wm8510.c | 2 +- sound/soc/codecs/wm8350.c | 2 +- sound/soc/codecs/wm8400.c | 3 ++- sound/soc/codecs/wm8510.c | 4 ++-- sound/soc/codecs/wm8580.c | 4 ++-- sound/soc/codecs/wm8753.c | 4 ++-- sound/soc/codecs/wm8900.c | 4 ++-- sound/soc/codecs/wm8940.c | 4 ++-- sound/soc/codecs/wm8960.c | 4 ++-- sound/soc/codecs/wm8974.c | 4 ++-- sound/soc/codecs/wm8990.c | 4 ++-- sound/soc/codecs/wm8993.c | 2 +- sound/soc/codecs/wm9713.c | 4 ++-- sound/soc/imx/mx27vis_wm8974.c | 2 +- sound/soc/pxa/magician.c | 2 +- sound/soc/pxa/pxa-ssp.c | 4 ++-- sound/soc/pxa/zylonite.c | 5 +++-- sound/soc/s3c24xx/neo1973_gta02_wm8753.c | 2 +- sound/soc/s3c24xx/neo1973_wm8753.c | 2 +- sound/soc/soc-core.c | 8 +++++--- 20 files changed, 37 insertions(+), 33 deletions(-) (limited to 'sound') diff --git a/sound/soc/atmel/playpaq_wm8510.c b/sound/soc/atmel/playpaq_wm8510.c index 9eb610c2ba9..9df4c68ef00 100644 --- a/sound/soc/atmel/playpaq_wm8510.c +++ b/sound/soc/atmel/playpaq_wm8510.c @@ -268,7 +268,7 @@ static int playpaq_wm8510_hw_params(struct snd_pcm_substream *substream, #endif /* CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE */ - ret = snd_soc_dai_set_pll(codec_dai, 0, + ret = snd_soc_dai_set_pll(codec_dai, 0, 0, clk_get_rate(CODEC_CLK), pll_out); if (ret < 0) { pr_warning("playpaq_wm8510: Failed to set CODEC DAI PLL (%d)\n", diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index 71c9c4bb263..0ebd99b7493 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c @@ -1101,7 +1101,7 @@ static inline int fll_factors(struct _fll_div *fll_div, unsigned int input, } static int wm8350_set_fll(struct snd_soc_dai *codec_dai, - int pll_id, unsigned int freq_in, + int pll_id, int source, unsigned int freq_in, unsigned int freq_out) { struct snd_soc_codec *codec = codec_dai->codec; diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c index b9ef4d91522..9cb8e50f0fb 100644 --- a/sound/soc/codecs/wm8400.c +++ b/sound/soc/codecs/wm8400.c @@ -1011,7 +1011,8 @@ static int fll_factors(struct wm8400_priv *wm8400, struct fll_factors *factors, } static int wm8400_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, - unsigned int freq_in, unsigned int freq_out) + int source, unsigned int freq_in, + unsigned int freq_out) { struct snd_soc_codec *codec = codec_dai->codec; struct wm8400_priv *wm8400 = codec->private_data; diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c index 060d5d06ba9..5702435af81 100644 --- a/sound/soc/codecs/wm8510.c +++ b/sound/soc/codecs/wm8510.c @@ -271,8 +271,8 @@ static void pll_factors(unsigned int target, unsigned int source) pll_div.k = K; } -static int wm8510_set_dai_pll(struct snd_soc_dai *codec_dai, - int pll_id, unsigned int freq_in, unsigned int freq_out) +static int wm8510_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, + int source, unsigned int freq_in, unsigned int freq_out) { struct snd_soc_codec *codec = codec_dai->codec; u16 reg; diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index 6bded8c7815..3be5c0b2552 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c @@ -407,8 +407,8 @@ static int pll_factors(struct _pll_div *pll_div, unsigned int target, return 0; } -static int wm8580_set_dai_pll(struct snd_soc_dai *codec_dai, - int pll_id, unsigned int freq_in, unsigned int freq_out) +static int wm8580_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, + int source, unsigned int freq_in, unsigned int freq_out) { int offset; struct snd_soc_codec *codec = codec_dai->codec; diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index d80d414cfbb..f60f3a02d1f 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c @@ -723,8 +723,8 @@ static void pll_factors(struct _pll_div *pll_div, unsigned int target, pll_div->k = K; } -static int wm8753_set_dai_pll(struct snd_soc_dai *codec_dai, - int pll_id, unsigned int freq_in, unsigned int freq_out) +static int wm8753_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, + int source, unsigned int freq_in, unsigned int freq_out) { u16 reg, enable; int offset; diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index 5e9c855c003..882604ef768 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c @@ -814,8 +814,8 @@ reenable: return 0; } -static int wm8900_set_dai_pll(struct snd_soc_dai *codec_dai, - int pll_id, unsigned int freq_in, unsigned int freq_out) +static int wm8900_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, + int source, unsigned int freq_in, unsigned int freq_out) { return wm8900_set_fll(codec_dai->codec, pll_id, freq_in, freq_out); } diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c index da97aae475a..914d788a2b7 100644 --- a/sound/soc/codecs/wm8940.c +++ b/sound/soc/codecs/wm8940.c @@ -536,8 +536,8 @@ static void pll_factors(unsigned int target, unsigned int source) } /* Untested at the moment */ -static int wm8940_set_dai_pll(struct snd_soc_dai *codec_dai, - int pll_id, unsigned int freq_in, unsigned int freq_out) +static int wm8940_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, + int source, unsigned int freq_in, unsigned int freq_out) { struct snd_soc_codec *codec = codec_dai->codec; u16 reg; diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index f59703be61c..416fb3c1701 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -540,8 +540,8 @@ static int pll_factors(unsigned int source, unsigned int target, return 0; } -static int wm8960_set_dai_pll(struct snd_soc_dai *codec_dai, - int pll_id, unsigned int freq_in, unsigned int freq_out) +static int wm8960_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, + int source, unsigned int freq_in, unsigned int freq_out) { struct snd_soc_codec *codec = codec_dai->codec; u16 reg; diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c index d8a013ab317..fa4d85bd048 100644 --- a/sound/soc/codecs/wm8974.c +++ b/sound/soc/codecs/wm8974.c @@ -329,8 +329,8 @@ static void pll_factors(unsigned int target, unsigned int source) pll_div.k = K; } -static int wm8974_set_dai_pll(struct snd_soc_dai *codec_dai, - int pll_id, unsigned int freq_in, unsigned int freq_out) +static int wm8974_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, + int source, unsigned int freq_in, unsigned int freq_out) { struct snd_soc_codec *codec = codec_dai->codec; u16 reg; diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index 2d702db4131..f657e9a5fe2 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c @@ -972,8 +972,8 @@ static void pll_factors(struct _pll_div *pll_div, unsigned int target, pll_div->k = K; } -static int wm8990_set_dai_pll(struct snd_soc_dai *codec_dai, - int pll_id, unsigned int freq_in, unsigned int freq_out) +static int wm8990_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, + int source, unsigned int freq_in, unsigned int freq_out) { u16 reg; struct snd_soc_codec *codec = codec_dai->codec; diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c index d9987999e92..6b32a285260 100644 --- a/sound/soc/codecs/wm8993.c +++ b/sound/soc/codecs/wm8993.c @@ -422,7 +422,7 @@ static int fll_factors(struct _fll_div *fll_div, unsigned int Fref, return 0; } -static int wm8993_set_fll(struct snd_soc_dai *dai, int fll_id, +static int wm8993_set_fll(struct snd_soc_dai *dai, int fll_id, int source, unsigned int Fref, unsigned int Fout) { struct snd_soc_codec *codec = dai->codec; diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index abed37acf78..ca3d449ed89 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -800,8 +800,8 @@ static int wm9713_set_pll(struct snd_soc_codec *codec, return 0; } -static int wm9713_set_dai_pll(struct snd_soc_dai *codec_dai, - int pll_id, unsigned int freq_in, unsigned int freq_out) +static int wm9713_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, + int source, unsigned int freq_in, unsigned int freq_out) { struct snd_soc_codec *codec = codec_dai->codec; return wm9713_set_pll(codec, pll_id, freq_in, freq_out); diff --git a/sound/soc/imx/mx27vis_wm8974.c b/sound/soc/imx/mx27vis_wm8974.c index e4dcb539108..0267d2d9168 100644 --- a/sound/soc/imx/mx27vis_wm8974.c +++ b/sound/soc/imx/mx27vis_wm8974.c @@ -157,7 +157,7 @@ static int mx27vis_hifi_hw_params(struct snd_pcm_substream *substream, /* codec PLL input is 25 MHz */ - ret = codec_dai->ops->set_pll(codec_dai, IGNORED_ARG, + ret = codec_dai->ops->set_pll(codec_dai, IGNORED_ARG, IGNORED_ARG, 25000000, pll_out); if (ret < 0) { printk(KERN_ERR "Error when setting PLL input\n"); diff --git a/sound/soc/pxa/magician.c b/sound/soc/pxa/magician.c index 9f7c61e23da..4c8d99a8d38 100644 --- a/sound/soc/pxa/magician.c +++ b/sound/soc/pxa/magician.c @@ -213,7 +213,7 @@ static int magician_playback_hw_params(struct snd_pcm_substream *substream, return ret; /* set SSP audio pll clock */ - ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, acps); + ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, 0, acps); if (ret < 0) return ret; diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index 5b9ed646478..57f201c94ca 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c @@ -305,8 +305,8 @@ static int pxa_ssp_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, /* * Configure the PLL frequency pxa27x and (afaik - pxa320 only) */ -static int pxa_ssp_set_dai_pll(struct snd_soc_dai *cpu_dai, - int pll_id, unsigned int freq_in, unsigned int freq_out) +static int pxa_ssp_set_dai_pll(struct snd_soc_dai *cpu_dai, int pll_id, + int source, unsigned int freq_in, unsigned int freq_out) { struct ssp_priv *priv = cpu_dai->private_data; struct ssp_device *ssp = priv->dev.ssp; diff --git a/sound/soc/pxa/zylonite.c b/sound/soc/pxa/zylonite.c index 9a386b4c4ed..dd678ae2439 100644 --- a/sound/soc/pxa/zylonite.c +++ b/sound/soc/pxa/zylonite.c @@ -74,7 +74,8 @@ static const struct snd_soc_dapm_route audio_map[] = { static int zylonite_wm9713_init(struct snd_soc_codec *codec) { if (clk_pout) - snd_soc_dai_set_pll(&codec->dai[0], 0, clk_get_rate(pout), 0); + snd_soc_dai_set_pll(&codec->dai[0], 0, 0, + clk_get_rate(pout), 0); snd_soc_dapm_new_controls(codec, zylonite_dapm_widgets, ARRAY_SIZE(zylonite_dapm_widgets)); @@ -128,7 +129,7 @@ static int zylonite_voice_hw_params(struct snd_pcm_substream *substream, if (ret < 0) return ret; - ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, pll_out); + ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, 0, pll_out); if (ret < 0) return ret; diff --git a/sound/soc/s3c24xx/neo1973_gta02_wm8753.c b/sound/soc/s3c24xx/neo1973_gta02_wm8753.c index 0c52e36ddd8..6ddd1b3b16b 100644 --- a/sound/soc/s3c24xx/neo1973_gta02_wm8753.c +++ b/sound/soc/s3c24xx/neo1973_gta02_wm8753.c @@ -119,7 +119,7 @@ static int neo1973_gta02_hifi_hw_params(struct snd_pcm_substream *substream, return ret; /* codec PLL input is PCLK/4 */ - ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, + ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, iis_clkrate / 4, pll_out); if (ret < 0) return ret; diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c index 906709e6dd5..16009eba9cb 100644 --- a/sound/soc/s3c24xx/neo1973_wm8753.c +++ b/sound/soc/s3c24xx/neo1973_wm8753.c @@ -137,7 +137,7 @@ static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream, return ret; /* codec PLL input is PCLK/4 */ - ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, + ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, iis_clkrate / 4, pll_out); if (ret < 0) return ret; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 7ff04ad2a97..05fdc8023da 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2197,16 +2197,18 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_clkdiv); * snd_soc_dai_set_pll - configure DAI PLL. * @dai: DAI * @pll_id: DAI specific PLL ID + * @source: DAI specific source for the PLL * @freq_in: PLL input clock frequency in Hz * @freq_out: requested PLL output clock frequency in Hz * * Configures and enables PLL to generate output clock based on input clock. */ -int snd_soc_dai_set_pll(struct snd_soc_dai *dai, - int pll_id, unsigned int freq_in, unsigned int freq_out) +int snd_soc_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source, + unsigned int freq_in, unsigned int freq_out) { if (dai->ops && dai->ops->set_pll) - return dai->ops->set_pll(dai, pll_id, freq_in, freq_out); + return dai->ops->set_pll(dai, pll_id, source, + freq_in, freq_out); else return -EINVAL; } -- cgit v1.2.3 From 341c9b84bc01040bd5c75140303e32f6b10098f3 Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Mon, 7 Sep 2009 12:04:37 +0900 Subject: ASoC: Factor out I2C 8 bit address 8 bit data I/O This patch is for the AK4671 codec driver using this format. Signed-off-by: Joonyoung Shim Signed-off-by: Mark Brown --- sound/soc/soc-cache.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'sound') diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c index c8ceddc2a26..404231ee878 100644 --- a/sound/soc/soc-cache.c +++ b/sound/soc/soc-cache.c @@ -77,6 +77,35 @@ static int snd_soc_7_9_spi_write(void *control_data, const char *data, #define snd_soc_7_9_spi_write NULL #endif +static int snd_soc_8_8_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + u8 *cache = codec->reg_cache; + u8 data[2]; + + BUG_ON(codec->volatile_register); + + data[0] = reg & 0xff; + data[1] = value & 0xff; + + if (reg < codec->reg_cache_size) + cache[reg] = value; + + if (codec->hw_write(codec->control_data, data, 2) == 2) + return 0; + else + return -EIO; +} + +static unsigned int snd_soc_8_8_read(struct snd_soc_codec *codec, + unsigned int reg) +{ + u8 *cache = codec->reg_cache; + if (reg >= codec->reg_cache_size) + return -1; + return cache[reg]; +} + static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { @@ -151,6 +180,7 @@ static struct { unsigned int (*i2c_read)(struct snd_soc_codec *, unsigned int); } io_types[] = { { 7, 9, snd_soc_7_9_write, snd_soc_7_9_spi_write, snd_soc_7_9_read }, + { 8, 8, snd_soc_8_8_write, NULL, snd_soc_8_8_read, NULL }, { 8, 16, snd_soc_8_16_write, NULL, snd_soc_8_16_read, snd_soc_8_16_read_i2c }, }; -- cgit v1.2.3 From 215edda3adf502ccdf3a358ab35b616e7abd25ff Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 8 Sep 2009 18:59:05 +0100 Subject: ASoC: Allow per-route connectedness checks for supplies Some chips with complex internal supply (particularly clocking) arragements may have multiple options for some of the supply connections. Since these don't affect user-visible audio routing the expectation would be that they would be managed automatically by one of the drivers. Support these users by allowing routes to have a connected function which is queried before the connectedness of the path is checked as normal. Currently this is only done for supplies, other widgets could be supported but are not currently since the expectation for them is that audio routing will be under the control of userspace. Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 0d8b08ef873..37f7adeae32 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -718,6 +718,10 @@ static int dapm_supply_check_power(struct snd_soc_dapm_widget *w) /* Check if one of our outputs is connected */ list_for_each_entry(path, &w->sinks, list_source) { + if (path->connected && + !path->connected(path->source, path->sink)) + continue; + if (path->sink && path->sink->power_check && path->sink->power_check(path->sink)) { power = 1; @@ -1136,6 +1140,9 @@ static ssize_t dapm_widget_power_read_file(struct file *file, w->sname); list_for_each_entry(p, &w->sources, list_sink) { + if (p->connected && !p->connected(w, p->sink)) + continue; + if (p->connect) ret += snprintf(buf + ret, PAGE_SIZE - ret, " in %s %s\n", @@ -1143,6 +1150,9 @@ static ssize_t dapm_widget_power_read_file(struct file *file, p->source->name); } list_for_each_entry(p, &w->sinks, list_source) { + if (p->connected && !p->connected(w, p->sink)) + continue; + if (p->connect) ret += snprintf(buf + ret, PAGE_SIZE - ret, " out %s %s\n", @@ -1385,10 +1395,13 @@ int snd_soc_dapm_sync(struct snd_soc_codec *codec) EXPORT_SYMBOL_GPL(snd_soc_dapm_sync); static int snd_soc_dapm_add_route(struct snd_soc_codec *codec, - const char *sink, const char *control, const char *source) + const struct snd_soc_dapm_route *route) { struct snd_soc_dapm_path *path; struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w; + const char *sink = route->sink; + const char *control = route->control; + const char *source = route->source; int ret = 0; /* find src and dest widgets */ @@ -1412,6 +1425,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_codec *codec, path->source = wsource; path->sink = wsink; + path->connected = route->connected; INIT_LIST_HEAD(&path->list); INIT_LIST_HEAD(&path->list_source); INIT_LIST_HEAD(&path->list_sink); @@ -1512,8 +1526,7 @@ int snd_soc_dapm_add_routes(struct snd_soc_codec *codec, int i, ret; for (i = 0; i < num; i++) { - ret = snd_soc_dapm_add_route(codec, route->sink, - route->control, route->source); + ret = snd_soc_dapm_add_route(codec, route); if (ret < 0) { printk(KERN_ERR "Failed to add route %s->%s\n", route->source, -- cgit v1.2.3 From 2312fd8f6b252b7d3c1d74b20c75b7bff98bab65 Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Thu, 10 Sep 2009 00:12:43 +0900 Subject: ASoC: AK4671: add ak4671 codec driver The AK4671 is a stereo CODEC with a built-in Microphone-Amplifier, Receiver-Amplifier and Headphone-Amplifier. The datasheet for the ak4671 can find at the following url: http://www.asahi-kasei.co.jp/akm/en/product/ak4671/ak4671_f01e.pdf Signed-off-by: Joonyoung Shim Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 4 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/ak4671.c | 825 ++++++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/ak4671.h | 156 +++++++++ 4 files changed, 987 insertions(+) create mode 100644 sound/soc/codecs/ak4671.c create mode 100644 sound/soc/codecs/ak4671.h (limited to 'sound') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 0edca93af3b..a2bb659ec18 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -19,6 +19,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_AK4104 if SPI_MASTER select SND_SOC_AK4535 if I2C select SND_SOC_AK4642 if I2C + select SND_SOC_AK4671 if I2C select SND_SOC_CS4270 if I2C select SND_SOC_MAX9877 if I2C select SND_SOC_PCM3008 @@ -96,6 +97,9 @@ config SND_SOC_AK4535 config SND_SOC_AK4642 tristate +config SND_SOC_AK4671 + tristate + # Cirrus Logic CS4270 Codec config SND_SOC_CS4270 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index fb4af28486b..13f7b4f2a15 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -6,6 +6,7 @@ snd-soc-ad73311-objs := ad73311.o snd-soc-ak4104-objs := ak4104.o snd-soc-ak4535-objs := ak4535.o snd-soc-ak4642-objs := ak4642.o +snd-soc-ak4671-objs := ak4671.o snd-soc-cs4270-objs := cs4270.o snd-soc-cx20442-objs := cx20442.o snd-soc-l3-objs := l3.o @@ -56,6 +57,7 @@ obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o obj-$(CONFIG_SND_SOC_AK4104) += snd-soc-ak4104.o obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o obj-$(CONFIG_SND_SOC_AK4642) += snd-soc-ak4642.o +obj-$(CONFIG_SND_SOC_AK4671) += snd-soc-ak4671.o obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o diff --git a/sound/soc/codecs/ak4671.c b/sound/soc/codecs/ak4671.c new file mode 100644 index 00000000000..b61214d1c5d --- /dev/null +++ b/sound/soc/codecs/ak4671.c @@ -0,0 +1,825 @@ +/* + * ak4671.c -- audio driver for AK4671 + * + * Copyright (C) 2009 Samsung Electronics Co.Ltd + * Author: Joonyoung Shim + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ak4671.h" + +static struct snd_soc_codec *ak4671_codec; + +/* codec private data */ +struct ak4671_priv { + struct snd_soc_codec codec; + u8 reg_cache[AK4671_CACHEREGNUM]; +}; + +/* ak4671 register cache & default register settings */ +static const u8 ak4671_reg[AK4671_CACHEREGNUM] = { + 0x00, /* AK4671_AD_DA_POWER_MANAGEMENT (0x00) */ + 0xf6, /* AK4671_PLL_MODE_SELECT0 (0x01) */ + 0x00, /* AK4671_PLL_MODE_SELECT1 (0x02) */ + 0x02, /* AK4671_FORMAT_SELECT (0x03) */ + 0x00, /* AK4671_MIC_SIGNAL_SELECT (0x04) */ + 0x55, /* AK4671_MIC_AMP_GAIN (0x05) */ + 0x00, /* AK4671_MIXING_POWER_MANAGEMENT0 (0x06) */ + 0x00, /* AK4671_MIXING_POWER_MANAGEMENT1 (0x07) */ + 0xb5, /* AK4671_OUTPUT_VOLUME_CONTROL (0x08) */ + 0x00, /* AK4671_LOUT1_SIGNAL_SELECT (0x09) */ + 0x00, /* AK4671_ROUT1_SIGNAL_SELECT (0x0a) */ + 0x00, /* AK4671_LOUT2_SIGNAL_SELECT (0x0b) */ + 0x00, /* AK4671_ROUT2_SIGNAL_SELECT (0x0c) */ + 0x00, /* AK4671_LOUT3_SIGNAL_SELECT (0x0d) */ + 0x00, /* AK4671_ROUT3_SIGNAL_SELECT (0x0e) */ + 0x00, /* AK4671_LOUT1_POWER_MANAGERMENT (0x0f) */ + 0x00, /* AK4671_LOUT2_POWER_MANAGERMENT (0x10) */ + 0x80, /* AK4671_LOUT3_POWER_MANAGERMENT (0x11) */ + 0x91, /* AK4671_LCH_INPUT_VOLUME_CONTROL (0x12) */ + 0x91, /* AK4671_RCH_INPUT_VOLUME_CONTROL (0x13) */ + 0xe1, /* AK4671_ALC_REFERENCE_SELECT (0x14) */ + 0x00, /* AK4671_DIGITAL_MIXING_CONTROL (0x15) */ + 0x00, /* AK4671_ALC_TIMER_SELECT (0x16) */ + 0x00, /* AK4671_ALC_MODE_CONTROL (0x17) */ + 0x02, /* AK4671_MODE_CONTROL1 (0x18) */ + 0x01, /* AK4671_MODE_CONTROL2 (0x19) */ + 0x18, /* AK4671_LCH_OUTPUT_VOLUME_CONTROL (0x1a) */ + 0x18, /* AK4671_RCH_OUTPUT_VOLUME_CONTROL (0x1b) */ + 0x00, /* AK4671_SIDETONE_A_CONTROL (0x1c) */ + 0x02, /* AK4671_DIGITAL_FILTER_SELECT (0x1d) */ + 0x00, /* AK4671_FIL3_COEFFICIENT0 (0x1e) */ + 0x00, /* AK4671_FIL3_COEFFICIENT1 (0x1f) */ + 0x00, /* AK4671_FIL3_COEFFICIENT2 (0x20) */ + 0x00, /* AK4671_FIL3_COEFFICIENT3 (0x21) */ + 0x00, /* AK4671_EQ_COEFFICIENT0 (0x22) */ + 0x00, /* AK4671_EQ_COEFFICIENT1 (0x23) */ + 0x00, /* AK4671_EQ_COEFFICIENT2 (0x24) */ + 0x00, /* AK4671_EQ_COEFFICIENT3 (0x25) */ + 0x00, /* AK4671_EQ_COEFFICIENT4 (0x26) */ + 0x00, /* AK4671_EQ_COEFFICIENT5 (0x27) */ + 0xa9, /* AK4671_FIL1_COEFFICIENT0 (0x28) */ + 0x1f, /* AK4671_FIL1_COEFFICIENT1 (0x29) */ + 0xad, /* AK4671_FIL1_COEFFICIENT2 (0x2a) */ + 0x20, /* AK4671_FIL1_COEFFICIENT3 (0x2b) */ + 0x00, /* AK4671_FIL2_COEFFICIENT0 (0x2c) */ + 0x00, /* AK4671_FIL2_COEFFICIENT1 (0x2d) */ + 0x00, /* AK4671_FIL2_COEFFICIENT2 (0x2e) */ + 0x00, /* AK4671_FIL2_COEFFICIENT3 (0x2f) */ + 0x00, /* AK4671_DIGITAL_FILTER_SELECT2 (0x30) */ + 0x00, /* this register not used */ + 0x00, /* AK4671_E1_COEFFICIENT0 (0x32) */ + 0x00, /* AK4671_E1_COEFFICIENT1 (0x33) */ + 0x00, /* AK4671_E1_COEFFICIENT2 (0x34) */ + 0x00, /* AK4671_E1_COEFFICIENT3 (0x35) */ + 0x00, /* AK4671_E1_COEFFICIENT4 (0x36) */ + 0x00, /* AK4671_E1_COEFFICIENT5 (0x37) */ + 0x00, /* AK4671_E2_COEFFICIENT0 (0x38) */ + 0x00, /* AK4671_E2_COEFFICIENT1 (0x39) */ + 0x00, /* AK4671_E2_COEFFICIENT2 (0x3a) */ + 0x00, /* AK4671_E2_COEFFICIENT3 (0x3b) */ + 0x00, /* AK4671_E2_COEFFICIENT4 (0x3c) */ + 0x00, /* AK4671_E2_COEFFICIENT5 (0x3d) */ + 0x00, /* AK4671_E3_COEFFICIENT0 (0x3e) */ + 0x00, /* AK4671_E3_COEFFICIENT1 (0x3f) */ + 0x00, /* AK4671_E3_COEFFICIENT2 (0x40) */ + 0x00, /* AK4671_E3_COEFFICIENT3 (0x41) */ + 0x00, /* AK4671_E3_COEFFICIENT4 (0x42) */ + 0x00, /* AK4671_E3_COEFFICIENT5 (0x43) */ + 0x00, /* AK4671_E4_COEFFICIENT0 (0x44) */ + 0x00, /* AK4671_E4_COEFFICIENT1 (0x45) */ + 0x00, /* AK4671_E4_COEFFICIENT2 (0x46) */ + 0x00, /* AK4671_E4_COEFFICIENT3 (0x47) */ + 0x00, /* AK4671_E4_COEFFICIENT4 (0x48) */ + 0x00, /* AK4671_E4_COEFFICIENT5 (0x49) */ + 0x00, /* AK4671_E5_COEFFICIENT0 (0x4a) */ + 0x00, /* AK4671_E5_COEFFICIENT1 (0x4b) */ + 0x00, /* AK4671_E5_COEFFICIENT2 (0x4c) */ + 0x00, /* AK4671_E5_COEFFICIENT3 (0x4d) */ + 0x00, /* AK4671_E5_COEFFICIENT4 (0x4e) */ + 0x00, /* AK4671_E5_COEFFICIENT5 (0x4f) */ + 0x88, /* AK4671_EQ_CONTROL_250HZ_100HZ (0x50) */ + 0x88, /* AK4671_EQ_CONTROL_3500HZ_1KHZ (0x51) */ + 0x08, /* AK4671_EQ_CONTRO_10KHZ (0x52) */ + 0x00, /* AK4671_PCM_IF_CONTROL0 (0x53) */ + 0x00, /* AK4671_PCM_IF_CONTROL1 (0x54) */ + 0x00, /* AK4671_PCM_IF_CONTROL2 (0x55) */ + 0x18, /* AK4671_DIGITAL_VOLUME_B_CONTROL (0x56) */ + 0x18, /* AK4671_DIGITAL_VOLUME_C_CONTROL (0x57) */ + 0x00, /* AK4671_SIDETONE_VOLUME_CONTROL (0x58) */ + 0x00, /* AK4671_DIGITAL_MIXING_CONTROL2 (0x59) */ + 0x00, /* AK4671_SAR_ADC_CONTROL (0x5a) */ +}; + +/* + * LOUT1/ROUT1 output volume control: + * from -24 to 6 dB in 6 dB steps (mute instead of -30 dB) + */ +static DECLARE_TLV_DB_SCALE(out1_tlv, -3000, 600, 1); + +/* + * LOUT2/ROUT2 output volume control: + * from -33 to 6 dB in 3 dB steps (mute instead of -33 dB) + */ +static DECLARE_TLV_DB_SCALE(out2_tlv, -3300, 300, 1); + +/* + * LOUT3/ROUT3 output volume control: + * from -6 to 3 dB in 3 dB steps + */ +static DECLARE_TLV_DB_SCALE(out3_tlv, -600, 300, 0); + +/* + * Mic amp gain control: + * from -15 to 30 dB in 3 dB steps + * REVISIT: The actual min value(0x01) is -12 dB and the reg value 0x00 is not + * available + */ +static DECLARE_TLV_DB_SCALE(mic_amp_tlv, -1500, 300, 0); + +static const struct snd_kcontrol_new ak4671_snd_controls[] = { + /* Common playback gain controls */ + SOC_SINGLE_TLV("Line Output1 Playback Volume", + AK4671_OUTPUT_VOLUME_CONTROL, 0, 0x6, 0, out1_tlv), + SOC_SINGLE_TLV("Headphone Output2 Playback Volume", + AK4671_OUTPUT_VOLUME_CONTROL, 4, 0xd, 0, out2_tlv), + SOC_SINGLE_TLV("Line Output3 Playback Volume", + AK4671_LOUT3_POWER_MANAGERMENT, 6, 0x3, 0, out3_tlv), + + /* Common capture gain controls */ + SOC_DOUBLE_TLV("Mic Amp Capture Volume", + AK4671_MIC_AMP_GAIN, 0, 4, 0xf, 0, mic_amp_tlv), +}; + +/* event handlers */ +static int ak4671_out2_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + u8 reg; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + reg = snd_soc_read(codec, AK4671_LOUT2_POWER_MANAGERMENT); + reg |= AK4671_MUTEN; + snd_soc_write(codec, AK4671_LOUT2_POWER_MANAGERMENT, reg); + break; + case SND_SOC_DAPM_PRE_PMD: + reg = snd_soc_read(codec, AK4671_LOUT2_POWER_MANAGERMENT); + reg &= ~AK4671_MUTEN; + snd_soc_write(codec, AK4671_LOUT2_POWER_MANAGERMENT, reg); + break; + } + + return 0; +} + +/* Output Mixers */ +static const struct snd_kcontrol_new ak4671_lout1_mixer_controls[] = { + SOC_DAPM_SINGLE("DACL", AK4671_LOUT1_SIGNAL_SELECT, 0, 1, 0), + SOC_DAPM_SINGLE("LINL1", AK4671_LOUT1_SIGNAL_SELECT, 1, 1, 0), + SOC_DAPM_SINGLE("LINL2", AK4671_LOUT1_SIGNAL_SELECT, 2, 1, 0), + SOC_DAPM_SINGLE("LINL3", AK4671_LOUT1_SIGNAL_SELECT, 3, 1, 0), + SOC_DAPM_SINGLE("LINL4", AK4671_LOUT1_SIGNAL_SELECT, 4, 1, 0), + SOC_DAPM_SINGLE("LOOPL", AK4671_LOUT1_SIGNAL_SELECT, 5, 1, 0), +}; + +static const struct snd_kcontrol_new ak4671_rout1_mixer_controls[] = { + SOC_DAPM_SINGLE("DACR", AK4671_ROUT1_SIGNAL_SELECT, 0, 1, 0), + SOC_DAPM_SINGLE("RINR1", AK4671_ROUT1_SIGNAL_SELECT, 1, 1, 0), + SOC_DAPM_SINGLE("RINR2", AK4671_ROUT1_SIGNAL_SELECT, 2, 1, 0), + SOC_DAPM_SINGLE("RINR3", AK4671_ROUT1_SIGNAL_SELECT, 3, 1, 0), + SOC_DAPM_SINGLE("RINR4", AK4671_ROUT1_SIGNAL_SELECT, 4, 1, 0), + SOC_DAPM_SINGLE("LOOPR", AK4671_ROUT1_SIGNAL_SELECT, 5, 1, 0), +}; + +static const struct snd_kcontrol_new ak4671_lout2_mixer_controls[] = { + SOC_DAPM_SINGLE("DACHL", AK4671_LOUT2_SIGNAL_SELECT, 0, 1, 0), + SOC_DAPM_SINGLE("LINH1", AK4671_LOUT2_SIGNAL_SELECT, 1, 1, 0), + SOC_DAPM_SINGLE("LINH2", AK4671_LOUT2_SIGNAL_SELECT, 2, 1, 0), + SOC_DAPM_SINGLE("LINH3", AK4671_LOUT2_SIGNAL_SELECT, 3, 1, 0), + SOC_DAPM_SINGLE("LINH4", AK4671_LOUT2_SIGNAL_SELECT, 4, 1, 0), + SOC_DAPM_SINGLE("LOOPHL", AK4671_LOUT2_SIGNAL_SELECT, 5, 1, 0), +}; + +static const struct snd_kcontrol_new ak4671_rout2_mixer_controls[] = { + SOC_DAPM_SINGLE("DACHR", AK4671_ROUT2_SIGNAL_SELECT, 0, 1, 0), + SOC_DAPM_SINGLE("RINH1", AK4671_ROUT2_SIGNAL_SELECT, 1, 1, 0), + SOC_DAPM_SINGLE("RINH2", AK4671_ROUT2_SIGNAL_SELECT, 2, 1, 0), + SOC_DAPM_SINGLE("RINH3", AK4671_ROUT2_SIGNAL_SELECT, 3, 1, 0), + SOC_DAPM_SINGLE("RINH4", AK4671_ROUT2_SIGNAL_SELECT, 4, 1, 0), + SOC_DAPM_SINGLE("LOOPHR", AK4671_ROUT2_SIGNAL_SELECT, 5, 1, 0), +}; + +static const struct snd_kcontrol_new ak4671_lout3_mixer_controls[] = { + SOC_DAPM_SINGLE("DACSL", AK4671_LOUT3_SIGNAL_SELECT, 0, 1, 0), + SOC_DAPM_SINGLE("LINS1", AK4671_LOUT3_SIGNAL_SELECT, 1, 1, 0), + SOC_DAPM_SINGLE("LINS2", AK4671_LOUT3_SIGNAL_SELECT, 2, 1, 0), + SOC_DAPM_SINGLE("LINS3", AK4671_LOUT3_SIGNAL_SELECT, 3, 1, 0), + SOC_DAPM_SINGLE("LINS4", AK4671_LOUT3_SIGNAL_SELECT, 4, 1, 0), + SOC_DAPM_SINGLE("LOOPSL", AK4671_LOUT3_SIGNAL_SELECT, 5, 1, 0), +}; + +static const struct snd_kcontrol_new ak4671_rout3_mixer_controls[] = { + SOC_DAPM_SINGLE("DACSR", AK4671_ROUT3_SIGNAL_SELECT, 0, 1, 0), + SOC_DAPM_SINGLE("RINS1", AK4671_ROUT3_SIGNAL_SELECT, 1, 1, 0), + SOC_DAPM_SINGLE("RINS2", AK4671_ROUT3_SIGNAL_SELECT, 2, 1, 0), + SOC_DAPM_SINGLE("RINS3", AK4671_ROUT3_SIGNAL_SELECT, 3, 1, 0), + SOC_DAPM_SINGLE("RINS4", AK4671_ROUT3_SIGNAL_SELECT, 4, 1, 0), + SOC_DAPM_SINGLE("LOOPSR", AK4671_ROUT3_SIGNAL_SELECT, 5, 1, 0), +}; + +/* Input MUXs */ +static const char *ak4671_lin_mux_texts[] = + {"LIN1", "LIN2", "LIN3", "LIN4"}; +static const struct soc_enum ak4671_lin_mux_enum = + SOC_ENUM_SINGLE(AK4671_MIC_SIGNAL_SELECT, 0, + ARRAY_SIZE(ak4671_lin_mux_texts), + ak4671_lin_mux_texts); +static const struct snd_kcontrol_new ak4671_lin_mux_control = + SOC_DAPM_ENUM("Route", ak4671_lin_mux_enum); + +static const char *ak4671_rin_mux_texts[] = + {"RIN1", "RIN2", "RIN3", "RIN4"}; +static const struct soc_enum ak4671_rin_mux_enum = + SOC_ENUM_SINGLE(AK4671_MIC_SIGNAL_SELECT, 2, + ARRAY_SIZE(ak4671_rin_mux_texts), + ak4671_rin_mux_texts); +static const struct snd_kcontrol_new ak4671_rin_mux_control = + SOC_DAPM_ENUM("Route", ak4671_rin_mux_enum); + +static const struct snd_soc_dapm_widget ak4671_dapm_widgets[] = { + /* Inputs */ + SND_SOC_DAPM_INPUT("LIN1"), + SND_SOC_DAPM_INPUT("RIN1"), + SND_SOC_DAPM_INPUT("LIN2"), + SND_SOC_DAPM_INPUT("RIN2"), + SND_SOC_DAPM_INPUT("LIN3"), + SND_SOC_DAPM_INPUT("RIN3"), + SND_SOC_DAPM_INPUT("LIN4"), + SND_SOC_DAPM_INPUT("RIN4"), + + /* Outputs */ + SND_SOC_DAPM_OUTPUT("LOUT1"), + SND_SOC_DAPM_OUTPUT("ROUT1"), + SND_SOC_DAPM_OUTPUT("LOUT2"), + SND_SOC_DAPM_OUTPUT("ROUT2"), + SND_SOC_DAPM_OUTPUT("LOUT3"), + SND_SOC_DAPM_OUTPUT("ROUT3"), + + /* DAC */ + SND_SOC_DAPM_DAC("DAC Left", "Left HiFi Playback", + AK4671_AD_DA_POWER_MANAGEMENT, 6, 0), + SND_SOC_DAPM_DAC("DAC Right", "Right HiFi Playback", + AK4671_AD_DA_POWER_MANAGEMENT, 7, 0), + + /* ADC */ + SND_SOC_DAPM_ADC("ADC Left", "Left HiFi Capture", + AK4671_AD_DA_POWER_MANAGEMENT, 4, 0), + SND_SOC_DAPM_ADC("ADC Right", "Right HiFi Capture", + AK4671_AD_DA_POWER_MANAGEMENT, 5, 0), + + /* PGA */ + SND_SOC_DAPM_PGA("LOUT2 Mix Amp", + AK4671_LOUT2_POWER_MANAGERMENT, 5, 0, NULL, 0), + SND_SOC_DAPM_PGA("ROUT2 Mix Amp", + AK4671_LOUT2_POWER_MANAGERMENT, 6, 0, NULL, 0), + + SND_SOC_DAPM_PGA("LIN1 Mixing Circuit", + AK4671_MIXING_POWER_MANAGEMENT1, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("RIN1 Mixing Circuit", + AK4671_MIXING_POWER_MANAGEMENT1, 1, 0, NULL, 0), + SND_SOC_DAPM_PGA("LIN2 Mixing Circuit", + AK4671_MIXING_POWER_MANAGEMENT1, 2, 0, NULL, 0), + SND_SOC_DAPM_PGA("RIN2 Mixing Circuit", + AK4671_MIXING_POWER_MANAGEMENT1, 3, 0, NULL, 0), + SND_SOC_DAPM_PGA("LIN3 Mixing Circuit", + AK4671_MIXING_POWER_MANAGEMENT1, 4, 0, NULL, 0), + SND_SOC_DAPM_PGA("RIN3 Mixing Circuit", + AK4671_MIXING_POWER_MANAGEMENT1, 5, 0, NULL, 0), + SND_SOC_DAPM_PGA("LIN4 Mixing Circuit", + AK4671_MIXING_POWER_MANAGEMENT1, 6, 0, NULL, 0), + SND_SOC_DAPM_PGA("RIN4 Mixing Circuit", + AK4671_MIXING_POWER_MANAGEMENT1, 7, 0, NULL, 0), + + /* Output Mixers */ + SND_SOC_DAPM_MIXER("LOUT1 Mixer", AK4671_LOUT1_POWER_MANAGERMENT, 0, 0, + &ak4671_lout1_mixer_controls[0], + ARRAY_SIZE(ak4671_lout1_mixer_controls)), + SND_SOC_DAPM_MIXER("ROUT1 Mixer", AK4671_LOUT1_POWER_MANAGERMENT, 1, 0, + &ak4671_rout1_mixer_controls[0], + ARRAY_SIZE(ak4671_rout1_mixer_controls)), + SND_SOC_DAPM_MIXER_E("LOUT2 Mixer", AK4671_LOUT2_POWER_MANAGERMENT, + 0, 0, &ak4671_lout2_mixer_controls[0], + ARRAY_SIZE(ak4671_lout2_mixer_controls), + ak4671_out2_event, + SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_MIXER_E("ROUT2 Mixer", AK4671_LOUT2_POWER_MANAGERMENT, + 1, 0, &ak4671_rout2_mixer_controls[0], + ARRAY_SIZE(ak4671_rout2_mixer_controls), + ak4671_out2_event, + SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_MIXER("LOUT3 Mixer", AK4671_LOUT3_POWER_MANAGERMENT, 0, 0, + &ak4671_lout3_mixer_controls[0], + ARRAY_SIZE(ak4671_lout3_mixer_controls)), + SND_SOC_DAPM_MIXER("ROUT3 Mixer", AK4671_LOUT3_POWER_MANAGERMENT, 1, 0, + &ak4671_rout3_mixer_controls[0], + ARRAY_SIZE(ak4671_rout3_mixer_controls)), + + /* Input MUXs */ + SND_SOC_DAPM_MUX("LIN MUX", AK4671_AD_DA_POWER_MANAGEMENT, 2, 0, + &ak4671_lin_mux_control), + SND_SOC_DAPM_MUX("RIN MUX", AK4671_AD_DA_POWER_MANAGEMENT, 3, 0, + &ak4671_rin_mux_control), + + /* Mic Power */ + SND_SOC_DAPM_MICBIAS("Mic Bias", AK4671_AD_DA_POWER_MANAGEMENT, 1, 0), + + /* Supply */ + SND_SOC_DAPM_SUPPLY("PMPLL", AK4671_PLL_MODE_SELECT1, 0, 0, NULL, 0), +}; + +static const struct snd_soc_dapm_route intercon[] = { + {"DAC Left", "NULL", "PMPLL"}, + {"DAC Right", "NULL", "PMPLL"}, + {"ADC Left", "NULL", "PMPLL"}, + {"ADC Right", "NULL", "PMPLL"}, + + /* Outputs */ + {"LOUT1", "NULL", "LOUT1 Mixer"}, + {"ROUT1", "NULL", "ROUT1 Mixer"}, + {"LOUT2", "NULL", "LOUT2 Mix Amp"}, + {"ROUT2", "NULL", "ROUT2 Mix Amp"}, + {"LOUT3", "NULL", "LOUT3 Mixer"}, + {"ROUT3", "NULL", "ROUT3 Mixer"}, + + {"LOUT1 Mixer", "DACL", "DAC Left"}, + {"ROUT1 Mixer", "DACR", "DAC Right"}, + {"LOUT2 Mixer", "DACHL", "DAC Left"}, + {"ROUT2 Mixer", "DACHR", "DAC Right"}, + {"LOUT2 Mix Amp", "NULL", "LOUT2 Mixer"}, + {"ROUT2 Mix Amp", "NULL", "ROUT2 Mixer"}, + {"LOUT3 Mixer", "DACSL", "DAC Left"}, + {"ROUT3 Mixer", "DACSR", "DAC Right"}, + + /* Inputs */ + {"LIN MUX", "LIN1", "LIN1"}, + {"LIN MUX", "LIN2", "LIN2"}, + {"LIN MUX", "LIN3", "LIN3"}, + {"LIN MUX", "LIN4", "LIN4"}, + + {"RIN MUX", "RIN1", "RIN1"}, + {"RIN MUX", "RIN2", "RIN2"}, + {"RIN MUX", "RIN3", "RIN3"}, + {"RIN MUX", "RIN4", "RIN4"}, + + {"LIN1", NULL, "Mic Bias"}, + {"RIN1", NULL, "Mic Bias"}, + {"LIN2", NULL, "Mic Bias"}, + {"RIN2", NULL, "Mic Bias"}, + + {"ADC Left", "NULL", "LIN MUX"}, + {"ADC Right", "NULL", "RIN MUX"}, + + /* Analog Loops */ + {"LIN1 Mixing Circuit", "NULL", "LIN1"}, + {"RIN1 Mixing Circuit", "NULL", "RIN1"}, + {"LIN2 Mixing Circuit", "NULL", "LIN2"}, + {"RIN2 Mixing Circuit", "NULL", "RIN2"}, + {"LIN3 Mixing Circuit", "NULL", "LIN3"}, + {"RIN3 Mixing Circuit", "NULL", "RIN3"}, + {"LIN4 Mixing Circuit", "NULL", "LIN4"}, + {"RIN4 Mixing Circuit", "NULL", "RIN4"}, + + {"LOUT1 Mixer", "LINL1", "LIN1 Mixing Circuit"}, + {"ROUT1 Mixer", "RINR1", "RIN1 Mixing Circuit"}, + {"LOUT2 Mixer", "LINH1", "LIN1 Mixing Circuit"}, + {"ROUT2 Mixer", "RINH1", "RIN1 Mixing Circuit"}, + {"LOUT3 Mixer", "LINS1", "LIN1 Mixing Circuit"}, + {"ROUT3 Mixer", "RINS1", "RIN1 Mixing Circuit"}, + + {"LOUT1 Mixer", "LINL2", "LIN2 Mixing Circuit"}, + {"ROUT1 Mixer", "RINR2", "RIN2 Mixing Circuit"}, + {"LOUT2 Mixer", "LINH2", "LIN2 Mixing Circuit"}, + {"ROUT2 Mixer", "RINH2", "RIN2 Mixing Circuit"}, + {"LOUT3 Mixer", "LINS2", "LIN2 Mixing Circuit"}, + {"ROUT3 Mixer", "RINS2", "RIN2 Mixing Circuit"}, + + {"LOUT1 Mixer", "LINL3", "LIN3 Mixing Circuit"}, + {"ROUT1 Mixer", "RINR3", "RIN3 Mixing Circuit"}, + {"LOUT2 Mixer", "LINH3", "LIN3 Mixing Circuit"}, + {"ROUT2 Mixer", "RINH3", "RIN3 Mixing Circuit"}, + {"LOUT3 Mixer", "LINS3", "LIN3 Mixing Circuit"}, + {"ROUT3 Mixer", "RINS3", "RIN3 Mixing Circuit"}, + + {"LOUT1 Mixer", "LINL4", "LIN4 Mixing Circuit"}, + {"ROUT1 Mixer", "RINR4", "RIN4 Mixing Circuit"}, + {"LOUT2 Mixer", "LINH4", "LIN4 Mixing Circuit"}, + {"ROUT2 Mixer", "RINH4", "RIN4 Mixing Circuit"}, + {"LOUT3 Mixer", "LINS4", "LIN4 Mixing Circuit"}, + {"ROUT3 Mixer", "RINS4", "RIN4 Mixing Circuit"}, +}; + +static int ak4671_add_widgets(struct snd_soc_codec *codec) +{ + snd_soc_dapm_new_controls(codec, ak4671_dapm_widgets, + ARRAY_SIZE(ak4671_dapm_widgets)); + + snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); + + snd_soc_dapm_new_widgets(codec); + return 0; +} + +static int ak4671_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; + u8 fs; + + fs = snd_soc_read(codec, AK4671_PLL_MODE_SELECT0); + fs &= ~AK4671_FS; + + switch (params_rate(params)) { + case 8000: + fs |= AK4671_FS_8KHZ; + break; + case 12000: + fs |= AK4671_FS_12KHZ; + break; + case 16000: + fs |= AK4671_FS_16KHZ; + break; + case 24000: + fs |= AK4671_FS_24KHZ; + break; + case 11025: + fs |= AK4671_FS_11_025KHZ; + break; + case 22050: + fs |= AK4671_FS_22_05KHZ; + break; + case 32000: + fs |= AK4671_FS_32KHZ; + break; + case 44100: + fs |= AK4671_FS_44_1KHZ; + break; + case 48000: + fs |= AK4671_FS_48KHZ; + break; + default: + return -EINVAL; + } + + snd_soc_write(codec, AK4671_PLL_MODE_SELECT0, fs); + + return 0; +} + +static int ak4671_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, + unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = dai->codec; + u8 pll; + + pll = snd_soc_read(codec, AK4671_PLL_MODE_SELECT0); + pll &= ~AK4671_PLL; + + switch (freq) { + case 11289600: + pll |= AK4671_PLL_11_2896MHZ; + break; + case 12000000: + pll |= AK4671_PLL_12MHZ; + break; + case 12288000: + pll |= AK4671_PLL_12_288MHZ; + break; + case 13000000: + pll |= AK4671_PLL_13MHZ; + break; + case 13500000: + pll |= AK4671_PLL_13_5MHZ; + break; + case 19200000: + pll |= AK4671_PLL_19_2MHZ; + break; + case 24000000: + pll |= AK4671_PLL_24MHZ; + break; + case 26000000: + pll |= AK4671_PLL_26MHZ; + break; + case 27000000: + pll |= AK4671_PLL_27MHZ; + break; + default: + return -EINVAL; + } + + snd_soc_write(codec, AK4671_PLL_MODE_SELECT0, pll); + + return 0; +} + +static int ak4671_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = dai->codec; + u8 mode; + u8 format; + + /* set master/slave audio interface */ + mode = snd_soc_read(codec, AK4671_PLL_MODE_SELECT1); + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + mode |= AK4671_M_S; + break; + case SND_SOC_DAIFMT_CBM_CFS: + mode &= ~(AK4671_M_S); + break; + default: + return -EINVAL; + } + + /* interface format */ + format = snd_soc_read(codec, AK4671_FORMAT_SELECT); + format &= ~AK4671_DIF; + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + format |= AK4671_DIF_I2S_MODE; + break; + case SND_SOC_DAIFMT_LEFT_J: + format |= AK4671_DIF_MSB_MODE; + break; + case SND_SOC_DAIFMT_DSP_A: + format |= AK4671_DIF_DSP_MODE; + format |= AK4671_BCKP; + format |= AK4671_MSBS; + break; + default: + return -EINVAL; + } + + /* set mode and format */ + snd_soc_write(codec, AK4671_PLL_MODE_SELECT1, mode); + snd_soc_write(codec, AK4671_FORMAT_SELECT, format); + + return 0; +} + +static int ak4671_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + u8 reg; + + switch (level) { + case SND_SOC_BIAS_ON: + case SND_SOC_BIAS_PREPARE: + case SND_SOC_BIAS_STANDBY: + reg = snd_soc_read(codec, AK4671_AD_DA_POWER_MANAGEMENT); + snd_soc_write(codec, AK4671_AD_DA_POWER_MANAGEMENT, + reg | AK4671_PMVCM); + break; + case SND_SOC_BIAS_OFF: + snd_soc_write(codec, AK4671_AD_DA_POWER_MANAGEMENT, 0x00); + break; + } + codec->bias_level = level; + return 0; +} + +#define AK4671_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ + SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\ + SNDRV_PCM_RATE_48000) + +#define AK4671_FORMATS SNDRV_PCM_FMTBIT_S16_LE + +static struct snd_soc_dai_ops ak4671_dai_ops = { + .hw_params = ak4671_hw_params, + .set_sysclk = ak4671_set_dai_sysclk, + .set_fmt = ak4671_set_dai_fmt, +}; + +struct snd_soc_dai ak4671_dai = { + .name = "AK4671", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = AK4671_RATES, + .formats = AK4671_FORMATS,}, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + .rates = AK4671_RATES, + .formats = AK4671_FORMATS,}, + .ops = &ak4671_dai_ops, +}; +EXPORT_SYMBOL_GPL(ak4671_dai); + +static int ak4671_probe(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec; + int ret = 0; + + if (ak4671_codec == NULL) { + dev_err(&pdev->dev, "Codec device not registered\n"); + return -ENODEV; + } + + socdev->card->codec = ak4671_codec; + codec = ak4671_codec; + + /* register pcms */ + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) { + dev_err(codec->dev, "failed to create pcms: %d\n", ret); + goto pcm_err; + } + + snd_soc_add_controls(codec, ak4671_snd_controls, + ARRAY_SIZE(ak4671_snd_controls)); + ak4671_add_widgets(codec); + + ret = snd_soc_init_card(socdev); + if (ret < 0) { + dev_err(codec->dev, "failed to register card: %d\n", ret); + goto card_err; + } + + ak4671_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + return ret; + +card_err: + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); +pcm_err: + return ret; +} + +static int ak4671_remove(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); + + return 0; +} + +struct snd_soc_codec_device soc_codec_dev_ak4671 = { + .probe = ak4671_probe, + .remove = ak4671_remove, +}; +EXPORT_SYMBOL_GPL(soc_codec_dev_ak4671); + +static int ak4671_register(struct ak4671_priv *ak4671, + enum snd_soc_control_type control) +{ + int ret; + struct snd_soc_codec *codec = &ak4671->codec; + + if (ak4671_codec) { + dev_err(codec->dev, "Another AK4671 is registered\n"); + ret = -EINVAL; + goto err; + } + + mutex_init(&codec->mutex); + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + + codec->private_data = ak4671; + codec->name = "AK4671"; + codec->owner = THIS_MODULE; + codec->bias_level = SND_SOC_BIAS_OFF; + codec->set_bias_level = ak4671_set_bias_level; + codec->dai = &ak4671_dai; + codec->num_dai = 1; + codec->reg_cache_size = AK4671_CACHEREGNUM; + codec->reg_cache = &ak4671->reg_cache; + + memcpy(codec->reg_cache, ak4671_reg, sizeof(ak4671_reg)); + + ret = snd_soc_codec_set_cache_io(codec, 8, 8, control); + if (ret < 0) { + dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); + goto err; + } + + ak4671_dai.dev = codec->dev; + ak4671_codec = codec; + + ret = snd_soc_register_codec(codec); + if (ret != 0) { + dev_err(codec->dev, "Failed to register codec: %d\n", ret); + goto err; + } + + ret = snd_soc_register_dai(&ak4671_dai); + if (ret != 0) { + dev_err(codec->dev, "Failed to register DAI: %d\n", ret); + goto err_codec; + } + + return 0; + +err_codec: + snd_soc_unregister_codec(codec); +err: + kfree(ak4671); + return ret; +} + +static void ak4671_unregister(struct ak4671_priv *ak4671) +{ + ak4671_set_bias_level(&ak4671->codec, SND_SOC_BIAS_OFF); + snd_soc_unregister_dai(&ak4671_dai); + snd_soc_unregister_codec(&ak4671->codec); + kfree(ak4671); + ak4671_codec = NULL; +} + +static int __devinit ak4671_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct ak4671_priv *ak4671; + struct snd_soc_codec *codec; + + ak4671 = kzalloc(sizeof(struct ak4671_priv), GFP_KERNEL); + if (ak4671 == NULL) + return -ENOMEM; + + codec = &ak4671->codec; + codec->hw_write = (hw_write_t)i2c_master_send; + + i2c_set_clientdata(client, ak4671); + codec->control_data = client; + + codec->dev = &client->dev; + + return ak4671_register(ak4671, SND_SOC_I2C); +} + +static __devexit int ak4671_i2c_remove(struct i2c_client *client) +{ + struct ak4671_priv *ak4671 = i2c_get_clientdata(client); + + ak4671_unregister(ak4671); + + return 0; +} + +static const struct i2c_device_id ak4671_i2c_id[] = { + { "ak4671", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ak4671_i2c_id); + +static struct i2c_driver ak4671_i2c_driver = { + .driver = { + .name = "ak4671", + .owner = THIS_MODULE, + }, + .probe = ak4671_i2c_probe, + .remove = __devexit_p(ak4671_i2c_remove), + .id_table = ak4671_i2c_id, +}; + +static int __init ak4671_modinit(void) +{ + return i2c_add_driver(&ak4671_i2c_driver); +} +module_init(ak4671_modinit); + +static void __exit ak4671_exit(void) +{ + i2c_del_driver(&ak4671_i2c_driver); +} +module_exit(ak4671_exit); + +MODULE_DESCRIPTION("ASoC AK4671 codec driver"); +MODULE_AUTHOR("Joonyoung Shim "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/ak4671.h b/sound/soc/codecs/ak4671.h new file mode 100644 index 00000000000..e2fad964e88 --- /dev/null +++ b/sound/soc/codecs/ak4671.h @@ -0,0 +1,156 @@ +/* + * ak4671.h -- audio driver for AK4671 + * + * Copyright (C) 2009 Samsung Electronics Co.Ltd + * Author: Joonyoung Shim + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#ifndef _AK4671_H +#define _AK4671_H + +#define AK4671_AD_DA_POWER_MANAGEMENT 0x00 +#define AK4671_PLL_MODE_SELECT0 0x01 +#define AK4671_PLL_MODE_SELECT1 0x02 +#define AK4671_FORMAT_SELECT 0x03 +#define AK4671_MIC_SIGNAL_SELECT 0x04 +#define AK4671_MIC_AMP_GAIN 0x05 +#define AK4671_MIXING_POWER_MANAGEMENT0 0x06 +#define AK4671_MIXING_POWER_MANAGEMENT1 0x07 +#define AK4671_OUTPUT_VOLUME_CONTROL 0x08 +#define AK4671_LOUT1_SIGNAL_SELECT 0x09 +#define AK4671_ROUT1_SIGNAL_SELECT 0x0a +#define AK4671_LOUT2_SIGNAL_SELECT 0x0b +#define AK4671_ROUT2_SIGNAL_SELECT 0x0c +#define AK4671_LOUT3_SIGNAL_SELECT 0x0d +#define AK4671_ROUT3_SIGNAL_SELECT 0x0e +#define AK4671_LOUT1_POWER_MANAGERMENT 0x0f +#define AK4671_LOUT2_POWER_MANAGERMENT 0x10 +#define AK4671_LOUT3_POWER_MANAGERMENT 0x11 +#define AK4671_LCH_INPUT_VOLUME_CONTROL 0x12 +#define AK4671_RCH_INPUT_VOLUME_CONTROL 0x13 +#define AK4671_ALC_REFERENCE_SELECT 0x14 +#define AK4671_DIGITAL_MIXING_CONTROL 0x15 +#define AK4671_ALC_TIMER_SELECT 0x16 +#define AK4671_ALC_MODE_CONTROL 0x17 +#define AK4671_MODE_CONTROL1 0x18 +#define AK4671_MODE_CONTROL2 0x19 +#define AK4671_LCH_OUTPUT_VOLUME_CONTROL 0x1a +#define AK4671_RCH_OUTPUT_VOLUME_CONTROL 0x1b +#define AK4671_SIDETONE_A_CONTROL 0x1c +#define AK4671_DIGITAL_FILTER_SELECT 0x1d +#define AK4671_FIL3_COEFFICIENT0 0x1e +#define AK4671_FIL3_COEFFICIENT1 0x1f +#define AK4671_FIL3_COEFFICIENT2 0x20 +#define AK4671_FIL3_COEFFICIENT3 0x21 +#define AK4671_EQ_COEFFICIENT0 0x22 +#define AK4671_EQ_COEFFICIENT1 0x23 +#define AK4671_EQ_COEFFICIENT2 0x24 +#define AK4671_EQ_COEFFICIENT3 0x25 +#define AK4671_EQ_COEFFICIENT4 0x26 +#define AK4671_EQ_COEFFICIENT5 0x27 +#define AK4671_FIL1_COEFFICIENT0 0x28 +#define AK4671_FIL1_COEFFICIENT1 0x29 +#define AK4671_FIL1_COEFFICIENT2 0x2a +#define AK4671_FIL1_COEFFICIENT3 0x2b +#define AK4671_FIL2_COEFFICIENT0 0x2c +#define AK4671_FIL2_COEFFICIENT1 0x2d +#define AK4671_FIL2_COEFFICIENT2 0x2e +#define AK4671_FIL2_COEFFICIENT3 0x2f +#define AK4671_DIGITAL_FILTER_SELECT2 0x30 +#define AK4671_E1_COEFFICIENT0 0x32 +#define AK4671_E1_COEFFICIENT1 0x33 +#define AK4671_E1_COEFFICIENT2 0x34 +#define AK4671_E1_COEFFICIENT3 0x35 +#define AK4671_E1_COEFFICIENT4 0x36 +#define AK4671_E1_COEFFICIENT5 0x37 +#define AK4671_E2_COEFFICIENT0 0x38 +#define AK4671_E2_COEFFICIENT1 0x39 +#define AK4671_E2_COEFFICIENT2 0x3a +#define AK4671_E2_COEFFICIENT3 0x3b +#define AK4671_E2_COEFFICIENT4 0x3c +#define AK4671_E2_COEFFICIENT5 0x3d +#define AK4671_E3_COEFFICIENT0 0x3e +#define AK4671_E3_COEFFICIENT1 0x3f +#define AK4671_E3_COEFFICIENT2 0x40 +#define AK4671_E3_COEFFICIENT3 0x41 +#define AK4671_E3_COEFFICIENT4 0x42 +#define AK4671_E3_COEFFICIENT5 0x43 +#define AK4671_E4_COEFFICIENT0 0x44 +#define AK4671_E4_COEFFICIENT1 0x45 +#define AK4671_E4_COEFFICIENT2 0x46 +#define AK4671_E4_COEFFICIENT3 0x47 +#define AK4671_E4_COEFFICIENT4 0x48 +#define AK4671_E4_COEFFICIENT5 0x49 +#define AK4671_E5_COEFFICIENT0 0x4a +#define AK4671_E5_COEFFICIENT1 0x4b +#define AK4671_E5_COEFFICIENT2 0x4c +#define AK4671_E5_COEFFICIENT3 0x4d +#define AK4671_E5_COEFFICIENT4 0x4e +#define AK4671_E5_COEFFICIENT5 0x4f +#define AK4671_EQ_CONTROL_250HZ_100HZ 0x50 +#define AK4671_EQ_CONTROL_3500HZ_1KHZ 0x51 +#define AK4671_EQ_CONTRO_10KHZ 0x52 +#define AK4671_PCM_IF_CONTROL0 0x53 +#define AK4671_PCM_IF_CONTROL1 0x54 +#define AK4671_PCM_IF_CONTROL2 0x55 +#define AK4671_DIGITAL_VOLUME_B_CONTROL 0x56 +#define AK4671_DIGITAL_VOLUME_C_CONTROL 0x57 +#define AK4671_SIDETONE_VOLUME_CONTROL 0x58 +#define AK4671_DIGITAL_MIXING_CONTROL2 0x59 +#define AK4671_SAR_ADC_CONTROL 0x5a + +#define AK4671_CACHEREGNUM (AK4671_SAR_ADC_CONTROL + 1) + +/* Bitfield Definitions */ + +/* AK4671_AD_DA_POWER_MANAGEMENT (0x00) Fields */ +#define AK4671_PMVCM 0x01 + +/* AK4671_PLL_MODE_SELECT0 (0x01) Fields */ +#define AK4671_PLL 0x0f +#define AK4671_PLL_11_2896MHZ (4 << 0) +#define AK4671_PLL_12_288MHZ (5 << 0) +#define AK4671_PLL_12MHZ (6 << 0) +#define AK4671_PLL_24MHZ (7 << 0) +#define AK4671_PLL_19_2MHZ (8 << 0) +#define AK4671_PLL_13_5MHZ (12 << 0) +#define AK4671_PLL_27MHZ (13 << 0) +#define AK4671_PLL_13MHZ (14 << 0) +#define AK4671_PLL_26MHZ (15 << 0) +#define AK4671_FS 0xf0 +#define AK4671_FS_8KHZ (0 << 4) +#define AK4671_FS_12KHZ (1 << 4) +#define AK4671_FS_16KHZ (2 << 4) +#define AK4671_FS_24KHZ (3 << 4) +#define AK4671_FS_11_025KHZ (5 << 4) +#define AK4671_FS_22_05KHZ (7 << 4) +#define AK4671_FS_32KHZ (10 << 4) +#define AK4671_FS_48KHZ (11 << 4) +#define AK4671_FS_44_1KHZ (15 << 4) + +/* AK4671_PLL_MODE_SELECT1 (0x02) Fields */ +#define AK4671_PMPLL 0x01 +#define AK4671_M_S 0x02 + +/* AK4671_FORMAT_SELECT (0x03) Fields */ +#define AK4671_DIF 0x03 +#define AK4671_DIF_DSP_MODE (0 << 0) +#define AK4671_DIF_MSB_MODE (2 << 0) +#define AK4671_DIF_I2S_MODE (3 << 0) +#define AK4671_BCKP 0x04 +#define AK4671_MSBS 0x08 +#define AK4671_SDOD 0x10 + +/* AK4671_LOUT2_POWER_MANAGEMENT (0x10) Fields */ +#define AK4671_MUTEN 0x04 + +extern struct snd_soc_dai ak4671_dai; +extern struct snd_soc_codec_device soc_codec_dev_ak4671; + +#endif -- cgit v1.2.3 From 472df3cbae8da6a949f1392a11958b8d21383735 Mon Sep 17 00:00:00 2001 From: Barry Song <21cnbao@gmail.com> Date: Sat, 12 Sep 2009 01:16:29 +0800 Subject: ASoC: Provide API for reordering channels The patch adds an interface to set the relationship between audio channel number and slot number. The interface should be really useful because audio channel n doesn't always use slot n in all platforms. And for some devices, the relationship even can change with sound mode switch in 2.1,3.1,4.1,5.1,6.1,7.1 etc. Signed-off-by: Barry Song <21cnbao@gmail.com> Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 05fdc8023da..f5b356f8acf 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2252,6 +2252,30 @@ int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, } EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot); +/** + * snd_soc_dai_set_channel_map - configure DAI audio channel map + * @dai: DAI + * @tx_num: how many TX channels + * @tx_slot: pointer to an array which imply the TX slot number channel + * 0~num-1 uses + * @rx_num: how many RX channels + * @rx_slot: pointer to an array which imply the RX slot number channel + * 0~num-1 uses + * + * configure the relationship between channel number and TDM slot number. + */ +int snd_soc_dai_set_channel_map(struct snd_soc_dai *dai, + unsigned int tx_num, unsigned int *tx_slot, + unsigned int rx_num, unsigned int *rx_slot) +{ + if (dai->ops && dai->ops->set_channel_map) + return dai->ops->set_channel_map(dai, tx_num, tx_slot, + rx_num, rx_slot); + else + return -EINVAL; +} +EXPORT_SYMBOL_GPL(snd_soc_dai_set_channel_map); + /** * snd_soc_dai_set_tristate - configure DAI system or master clock. * @dai: DAI -- cgit v1.2.3 From fd5ad654e665b5c30c8d755a106309c8ea9f3e7b Mon Sep 17 00:00:00 2001 From: Jassi Date: Tue, 15 Sep 2009 19:02:38 +0900 Subject: ASoC: S3C I2S LRCLK polarity option. 1) Explicitly set LRCLK polarity for I2S Vs LSM/MSB modes. 2) Convert from numerical to bit-field values for BCLK selection. 3) Use proper error checking for return value from clk_get Signed-off-by: Jassi Signed-off-by: Mark Brown --- sound/soc/s3c24xx/s3c-i2s-v2.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.c b/sound/soc/s3c24xx/s3c-i2s-v2.c index aa7af0b8d42..819c3c086d6 100644 --- a/sound/soc/s3c24xx/s3c-i2s-v2.c +++ b/sound/soc/s3c24xx/s3c-i2s-v2.c @@ -308,12 +308,15 @@ static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai, switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_RIGHT_J: + iismod |= S3C2412_IISMOD_LR_RLOW; iismod |= S3C2412_IISMOD_SDF_MSB; break; case SND_SOC_DAIFMT_LEFT_J: + iismod |= S3C2412_IISMOD_LR_RLOW; iismod |= S3C2412_IISMOD_SDF_LSB; break; case SND_SOC_DAIFMT_I2S: + iismod &= ~S3C2412_IISMOD_LR_RLOW; iismod |= S3C2412_IISMOD_SDF_IIS; break; default: @@ -463,6 +466,31 @@ static int s3c2412_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai, switch (div_id) { case S3C_I2SV2_DIV_BCLK: + if (div > 3) { + /* convert value to bit field */ + + switch (div) { + case 16: + div = S3C2412_IISMOD_BCLK_16FS; + break; + + case 32: + div = S3C2412_IISMOD_BCLK_32FS; + break; + + case 24: + div = S3C2412_IISMOD_BCLK_24FS; + break; + + case 48: + div = S3C2412_IISMOD_BCLK_48FS; + break; + + default: + return -EINVAL; + } + } + reg = readl(i2s->regs + S3C2412_IISMOD); reg &= ~S3C2412_IISMOD_BCLK_MASK; writel(reg | div, i2s->regs + S3C2412_IISMOD); @@ -622,7 +650,7 @@ int s3c_i2sv2_probe(struct platform_device *pdev, } i2s->iis_pclk = clk_get(dev, "iis"); - if (i2s->iis_pclk == NULL) { + if (IS_ERR(i2s->iis_pclk)) { dev_err(dev, "failed to get iis_clock\n"); iounmap(i2s->regs); return -ENOENT; -- cgit v1.2.3 From 08db48f1ee1adf8919484f731d4ad6b264cfc564 Mon Sep 17 00:00:00 2001 From: Barry Song Date: Tue, 15 Sep 2009 11:24:52 +0800 Subject: ASoC: use set_channel_map api to reorder channels for AD1938 and AD1836 Signed-off-by: Barry Song Signed-off-by: Mark Brown --- sound/soc/blackfin/bf5xx-ad1836.c | 7 ++++++ sound/soc/blackfin/bf5xx-ad1938.c | 9 +++++++- sound/soc/blackfin/bf5xx-tdm-pcm.c | 9 +++++--- sound/soc/blackfin/bf5xx-tdm.c | 45 +++++++++++++++++++++++++++++++------- sound/soc/blackfin/bf5xx-tdm.h | 11 ++++++++++ 5 files changed, 69 insertions(+), 12 deletions(-) (limited to 'sound') diff --git a/sound/soc/blackfin/bf5xx-ad1836.c b/sound/soc/blackfin/bf5xx-ad1836.c index cd361e304b0..0f45a3f56be 100644 --- a/sound/soc/blackfin/bf5xx-ad1836.c +++ b/sound/soc/blackfin/bf5xx-ad1836.c @@ -52,6 +52,7 @@ static int bf5xx_ad1836_hw_params(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; + unsigned int channel_map[] = {0, 4, 1, 5, 2, 6, 3, 7}; int ret = 0; /* set cpu DAI configuration */ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A | @@ -65,6 +66,12 @@ static int bf5xx_ad1836_hw_params(struct snd_pcm_substream *substream, if (ret < 0) return ret; + /* set cpu DAI channel mapping */ + ret = snd_soc_dai_set_channel_map(cpu_dai, ARRAY_SIZE(channel_map), + channel_map, ARRAY_SIZE(channel_map), channel_map); + if (ret < 0) + return ret; + return 0; } diff --git a/sound/soc/blackfin/bf5xx-ad1938.c b/sound/soc/blackfin/bf5xx-ad1938.c index 08269e91810..2ef1e5013b8 100644 --- a/sound/soc/blackfin/bf5xx-ad1938.c +++ b/sound/soc/blackfin/bf5xx-ad1938.c @@ -61,6 +61,7 @@ static int bf5xx_ad1938_hw_params(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; + unsigned int channel_map[] = {0, 1, 2, 3, 4, 5, 6, 7}; int ret = 0; /* set cpu DAI configuration */ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A | @@ -75,7 +76,13 @@ static int bf5xx_ad1938_hw_params(struct snd_pcm_substream *substream, return ret; /* set codec DAI slots, 8 channels, all channels are enabled */ - ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xFF, 8); + ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xFF, 0xFF, 8, 32); + if (ret < 0) + return ret; + + /* set cpu DAI channel mapping */ + ret = snd_soc_dai_set_channel_map(cpu_dai, ARRAY_SIZE(channel_map), + channel_map, ARRAY_SIZE(channel_map), channel_map); if (ret < 0) return ret; diff --git a/sound/soc/blackfin/bf5xx-tdm-pcm.c b/sound/soc/blackfin/bf5xx-tdm-pcm.c index ccb5e823bd1..a8c73cbbd68 100644 --- a/sound/soc/blackfin/bf5xx-tdm-pcm.c +++ b/sound/soc/blackfin/bf5xx-tdm-pcm.c @@ -43,7 +43,7 @@ #include "bf5xx-tdm.h" #include "bf5xx-sport.h" -#define PCM_BUFFER_MAX 0x10000 +#define PCM_BUFFER_MAX 0x8000 #define FRAGMENT_SIZE_MIN (4*1024) #define FRAGMENTS_MIN 2 #define FRAGMENTS_MAX 32 @@ -177,6 +177,9 @@ out: static int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel, snd_pcm_uframes_t pos, void *buf, snd_pcm_uframes_t count) { + struct snd_pcm_runtime *runtime = substream->runtime; + struct sport_device *sport = runtime->private_data; + struct bf5xx_tdm_port *tdm_port = sport->private_data; unsigned int *src; unsigned int *dst; int i; @@ -188,7 +191,7 @@ static int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel, dst += pos * 8; while (count--) { for (i = 0; i < substream->runtime->channels; i++) - *(dst + i) = *src++; + *(dst + tdm_port->tx_map[i]) = *src++; dst += 8; } } else { @@ -198,7 +201,7 @@ static int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel, src += pos * 8; while (count--) { for (i = 0; i < substream->runtime->channels; i++) - *dst++ = *(src+i); + *dst++ = *(src + tdm_port->rx_map[i]); src += 8; } } diff --git a/sound/soc/blackfin/bf5xx-tdm.c b/sound/soc/blackfin/bf5xx-tdm.c index 3096badf09a..600987d8a87 100644 --- a/sound/soc/blackfin/bf5xx-tdm.c +++ b/sound/soc/blackfin/bf5xx-tdm.c @@ -46,14 +46,6 @@ #include "bf5xx-sport.h" #include "bf5xx-tdm.h" -struct bf5xx_tdm_port { - u16 tcr1; - u16 rcr1; - u16 tcr2; - u16 rcr2; - int configured; -}; - static struct bf5xx_tdm_port bf5xx_tdm; static int sport_num = CONFIG_SND_BF5XX_SPORT_NUM; @@ -181,6 +173,40 @@ static void bf5xx_tdm_shutdown(struct snd_pcm_substream *substream, bf5xx_tdm.configured = 0; } +static int bf5xx_tdm_set_channel_map(struct snd_soc_dai *dai, + unsigned int tx_num, unsigned int *tx_slot, + unsigned int rx_num, unsigned int *rx_slot) +{ + int i; + unsigned int slot; + unsigned int tx_mapped = 0, rx_mapped = 0; + + if ((tx_num > BFIN_TDM_DAI_MAX_SLOTS) || + (rx_num > BFIN_TDM_DAI_MAX_SLOTS)) + return -EINVAL; + + for (i = 0; i < tx_num; i++) { + slot = tx_slot[i]; + if ((slot < BFIN_TDM_DAI_MAX_SLOTS) && + (!(tx_mapped & (1 << slot)))) { + bf5xx_tdm.tx_map[i] = slot; + tx_mapped |= 1 << slot; + } else + return -EINVAL; + } + for (i = 0; i < rx_num; i++) { + slot = rx_slot[i]; + if ((slot < BFIN_TDM_DAI_MAX_SLOTS) && + (!(rx_mapped & (1 << slot)))) { + bf5xx_tdm.rx_map[i] = slot; + rx_mapped |= 1 << slot; + } else + return -EINVAL; + } + + return 0; +} + #ifdef CONFIG_PM static int bf5xx_tdm_suspend(struct snd_soc_dai *dai) { @@ -235,6 +261,7 @@ static struct snd_soc_dai_ops bf5xx_tdm_dai_ops = { .hw_params = bf5xx_tdm_hw_params, .set_fmt = bf5xx_tdm_set_dai_fmt, .shutdown = bf5xx_tdm_shutdown, + .set_channel_map = bf5xx_tdm_set_channel_map, }; struct snd_soc_dai bf5xx_tdm_dai = { @@ -300,6 +327,8 @@ static int __devinit bfin_tdm_probe(struct platform_device *pdev) pr_err("Failed to register DAI: %d\n", ret); goto sport_config_err; } + + sport_handle->private_data = &bf5xx_tdm; return 0; sport_config_err: diff --git a/sound/soc/blackfin/bf5xx-tdm.h b/sound/soc/blackfin/bf5xx-tdm.h index 618ec3d90cd..04189a18c1b 100644 --- a/sound/soc/blackfin/bf5xx-tdm.h +++ b/sound/soc/blackfin/bf5xx-tdm.h @@ -9,6 +9,17 @@ #ifndef _BF5XX_TDM_H #define _BF5XX_TDM_H +#define BFIN_TDM_DAI_MAX_SLOTS 8 +struct bf5xx_tdm_port { + u16 tcr1; + u16 rcr1; + u16 tcr2; + u16 rcr2; + unsigned int tx_map[BFIN_TDM_DAI_MAX_SLOTS]; + unsigned int rx_map[BFIN_TDM_DAI_MAX_SLOTS]; + int configured; +}; + extern struct snd_soc_dai bf5xx_tdm_dai; #endif -- cgit v1.2.3 From 9b95b166789d3ec57cea8cca0d42e602b8643ab0 Mon Sep 17 00:00:00 2001 From: Miguel Aguilar Date: Wed, 2 Sep 2009 15:33:59 -0600 Subject: ASoC: Davinci: Add audio codec support for DM365 EVM This patch enables tlv320aic3101 support on DM365 EVM and it was tested on DM365 EVM rev c. Note: this patch was created based on temp/asoc branch. Signed-off-by: Miguel Aguilar Signed-off-by: Mark Brown --- sound/soc/davinci/Kconfig | 4 ++-- sound/soc/davinci/davinci-evm.c | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/davinci/Kconfig b/sound/soc/davinci/Kconfig index 4dfd4ad9d90..047ee39418c 100644 --- a/sound/soc/davinci/Kconfig +++ b/sound/soc/davinci/Kconfig @@ -13,9 +13,9 @@ config SND_DAVINCI_SOC_MCASP tristate config SND_DAVINCI_SOC_EVM - tristate "SoC Audio support for DaVinci DM6446 or DM355 EVM" + tristate "SoC Audio support for DaVinci DM6446, DM355 or DM365 EVM" depends on SND_DAVINCI_SOC - depends on MACH_DAVINCI_EVM || MACH_DAVINCI_DM355_EVM + depends on MACH_DAVINCI_EVM || MACH_DAVINCI_DM355_EVM || MACH_DAVINCI_DM365_EVM select SND_DAVINCI_SOC_I2S select SND_SOC_TLV320AIC3X help diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c index 67414f65940..7ccbe6684fc 100644 --- a/sound/soc/davinci/davinci-evm.c +++ b/sound/soc/davinci/davinci-evm.c @@ -45,7 +45,8 @@ static int evm_hw_params(struct snd_pcm_substream *substream, unsigned sysclk; /* ASP1 on DM355 EVM is clocked by an external oscillator */ - if (machine_is_davinci_dm355_evm() || machine_is_davinci_dm6467_evm()) + if (machine_is_davinci_dm355_evm() || machine_is_davinci_dm6467_evm() || + machine_is_davinci_dm365_evm()) sysclk = 27000000; /* ASP0 in DM6446 EVM is clocked by U55, as configured by @@ -176,7 +177,7 @@ static struct snd_soc_dai_link da8xx_evm_dai = { .ops = &evm_ops, }; -/* davinci-evm audio machine driver */ +/* davinci dm6446, dm355 or dm365 evm audio machine driver */ static struct snd_soc_card snd_soc_card_evm = { .name = "DaVinci EVM", .platform = &davinci_soc_platform, @@ -243,7 +244,7 @@ static int __init evm_init(void) int index; int ret; - if (machine_is_davinci_evm()) { + if (machine_is_davinci_evm() || machine_is_davinci_dm365_evm()) { evm_snd_dev_data = &evm_snd_devdata; index = 0; } else if (machine_is_davinci_dm355_evm()) { -- cgit v1.2.3 From 8bb014895547eeeb9aa61a654f24e41e15919304 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 16 Sep 2009 19:38:53 +0100 Subject: ASoC: Add S3C64xx IIS CDCLK source selection CDCLK can either be an output generated by the CPU, intended for use as the CODEC master clock, or an input (probably from the CODEC) providing a master clock for the IIS block. Signed-off-by: Mark Brown --- sound/soc/s3c24xx/s3c64xx-i2s.c | 13 +++++++++++++ sound/soc/s3c24xx/s3c64xx-i2s.h | 1 + 2 files changed, 14 insertions(+) (limited to 'sound') diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.c b/sound/soc/s3c24xx/s3c64xx-i2s.c index 3c06c401d0f..aaf452096be 100644 --- a/sound/soc/s3c24xx/s3c64xx-i2s.c +++ b/sound/soc/s3c24xx/s3c64xx-i2s.c @@ -99,6 +99,19 @@ static int s3c64xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, iismod |= S3C64XX_IISMOD_IMS_SYSMUX; break; + case S3C64XX_CLKSRC_CDCLK: + switch (dir) { + case SND_SOC_CLOCK_IN: + iismod |= S3C64XX_IISMOD_CDCLKCON; + break; + case SND_SOC_CLOCK_OUT: + iismod &= ~S3C64XX_IISMOD_CDCLKCON; + break; + default: + return -EINVAL; + } + break; + default: return -EINVAL; } diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.h b/sound/soc/s3c24xx/s3c64xx-i2s.h index 02148cee261..abe7253b55f 100644 --- a/sound/soc/s3c24xx/s3c64xx-i2s.h +++ b/sound/soc/s3c24xx/s3c64xx-i2s.h @@ -25,6 +25,7 @@ struct clk; #define S3C64XX_CLKSRC_PCLK (0) #define S3C64XX_CLKSRC_MUX (1) +#define S3C64XX_CLKSRC_CDCLK (2) extern struct snd_soc_dai s3c64xx_i2s_dai[]; -- cgit v1.2.3 From b1cd6b9ec7c749ddfad628c8c12659591ae195e6 Mon Sep 17 00:00:00 2001 From: Jassi Date: Fri, 18 Sep 2009 15:22:27 +0900 Subject: ASoC: Return correct codec clock in s3c64xx-i2s Instead of always returnig pointer to the 'audio-bus' clock, check which clock is used to generate internal clocks and then return it's pointer. Signed-off-by: Jassi Signed-off-by: Mark Brown --- sound/soc/s3c24xx/s3c64xx-i2s.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.c b/sound/soc/s3c24xx/s3c64xx-i2s.c index aaf452096be..43fb253a342 100644 --- a/sound/soc/s3c24xx/s3c64xx-i2s.c +++ b/sound/soc/s3c24xx/s3c64xx-i2s.c @@ -124,8 +124,12 @@ static int s3c64xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, struct clk *s3c64xx_i2s_get_clock(struct snd_soc_dai *dai) { struct s3c_i2sv2_info *i2s = to_info(dai); + u32 iismod = readl(i2s->regs + S3C2412_IISMOD); - return i2s->iis_cclk; + if (iismod & S3C64XX_IISMOD_IMS_SYSMUX) + return i2s->iis_cclk; + else + return i2s->iis_pclk; } EXPORT_SYMBOL_GPL(s3c64xx_i2s_get_clock); -- cgit v1.2.3 From d0f5fa17aa63262685e43b798ca0830d89786235 Mon Sep 17 00:00:00 2001 From: jassi brar Date: Sat, 19 Sep 2009 09:46:06 +0900 Subject: ASoC: Support WM8580 based audio subsystem on SMDK64xx machines New machine driver for WM8580 I2S i/f on SMDK64XX. By default SoC-Slave is set and WM8580 is configured to use it's PLLA to generate clocks from a 12MHz crystal attached to WM8580. [Added dependency on BROKEN since the IISv4 interface hasn't been merged yet, fixed the PLL API usage and removed the disabling of the PLL in the hw_free function since that'll break simultaneous playback and record -- broonie.] Signed-off-by: Jassi Signed-off-by: Mark Brown --- sound/soc/s3c24xx/Kconfig | 9 ++ sound/soc/s3c24xx/Makefile | 2 + sound/soc/s3c24xx/smdk64xx_wm8580.c | 273 ++++++++++++++++++++++++++++++++++++ 3 files changed, 284 insertions(+) create mode 100644 sound/soc/s3c24xx/smdk64xx_wm8580.c (limited to 'sound') diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig index 923428fc1ad..d7912f1e462 100644 --- a/sound/soc/s3c24xx/Kconfig +++ b/sound/soc/s3c24xx/Kconfig @@ -56,6 +56,15 @@ config SND_S3C24XX_SOC_JIVE_WM8750 help Sat Y if you want to add support for SoC audio on the Jive. +config SND_S3C64XX_SOC_WM8580 + tristate "SoC I2S Audio support for WM8580 on SMDK64XX" + depends on SND_S3C24XX_SOC && (MACH_SMDK6400 || MACH_SMDK6410) + depends on BROKEN + select SND_SOC_WM8580 + select SND_S3C64XX_SOC_I2S + help + Sat Y if you want to add support for SoC audio on the SMDK64XX. + config SND_S3C24XX_SOC_SMDK2443_WM9710 tristate "SoC AC97 Audio support for SMDK2443 - WM9710" depends on SND_S3C24XX_SOC && MACH_SMDK2443 diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile index 99f5a7dd3fc..7790406f90b 100644 --- a/sound/soc/s3c24xx/Makefile +++ b/sound/soc/s3c24xx/Makefile @@ -23,6 +23,7 @@ snd-soc-s3c24xx-uda134x-objs := s3c24xx_uda134x.o snd-soc-s3c24xx-simtec-objs := s3c24xx_simtec.o snd-soc-s3c24xx-simtec-hermes-objs := s3c24xx_simtec_hermes.o snd-soc-s3c24xx-simtec-tlv320aic23-objs := s3c24xx_simtec_tlv320aic23.o +snd-soc-smdk64xx-wm8580-objs := smdk64xx_wm8580.o obj-$(CONFIG_SND_S3C24XX_SOC_JIVE_WM8750) += snd-soc-jive-wm8750.o obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o @@ -33,4 +34,5 @@ obj-$(CONFIG_SND_S3C24XX_SOC_S3C24XX_UDA134X) += snd-soc-s3c24xx-uda134x.o obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC) += snd-soc-s3c24xx-simtec.o obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC_HERMES) += snd-soc-s3c24xx-simtec-hermes.o obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC_TLV320AIC23) += snd-soc-s3c24xx-simtec-tlv320aic23.o +obj-$(CONFIG_SND_S3C64XX_SOC_WM8580) += snd-soc-smdk64xx-wm8580.o diff --git a/sound/soc/s3c24xx/smdk64xx_wm8580.c b/sound/soc/s3c24xx/smdk64xx_wm8580.c new file mode 100644 index 00000000000..482aaf10eff --- /dev/null +++ b/sound/soc/s3c24xx/smdk64xx_wm8580.c @@ -0,0 +1,273 @@ +/* + * smdk64xx_wm8580.c + * + * Copyright (c) 2009 Samsung Electronics Co. Ltd + * Author: Jaswinder Singh + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "../codecs/wm8580.h" +#include "s3c24xx-pcm.h" +#include "s3c64xx-i2s.h" + +#define S3C64XX_I2S_V4 2 + +/* SMDK64XX has a 12MHZ crystal attached to WM8580 */ +#define SMDK64XX_WM8580_FREQ 12000000 + +static int smdk64xx_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; + unsigned int pll_out; + int bfs, rfs, ret; + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_U8: + case SNDRV_PCM_FORMAT_S8: + bfs = 16; + break; + case SNDRV_PCM_FORMAT_U16_LE: + case SNDRV_PCM_FORMAT_S16_LE: + bfs = 32; + break; + default: + return -EINVAL; + } + + /* The Fvco for WM8580 PLLs must fall within [90,100]MHz. + * This criterion can't be met if we request PLL output + * as {8000x256, 64000x256, 11025x256}Hz. + * As a wayout, we rather change rfs to a minimum value that + * results in (params_rate(params) * rfs), and itself, acceptable + * to both - the CODEC and the CPU. + */ + switch (params_rate(params)) { + case 16000: + case 22050: + case 32000: + case 44100: + case 48000: + case 88200: + case 96000: + rfs = 256; + break; + case 64000: + rfs = 384; + break; + case 8000: + case 11025: + rfs = 512; + break; + default: + return -EINVAL; + } + pll_out = params_rate(params) * rfs; + + /* Set the Codec DAI configuration */ + ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S + | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBM_CFM); + if (ret < 0) + return ret; + + /* Set the AP DAI configuration */ + ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S + | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBM_CFM); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_sysclk(cpu_dai, S3C64XX_CLKSRC_CDCLK, + 0, SND_SOC_CLOCK_IN); + if (ret < 0) + return ret; + + /* We use PCLK for basic ops in SoC-Slave mode */ + ret = snd_soc_dai_set_sysclk(cpu_dai, S3C64XX_CLKSRC_PCLK, + 0, SND_SOC_CLOCK_IN); + if (ret < 0) + return ret; + + /* Set WM8580 to drive MCLK from it's PLLA */ + ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_MCLK, + WM8580_CLKSRC_PLLA); + if (ret < 0) + return ret; + + /* Explicitly set WM8580-DAC to source from MCLK */ + ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_DAC_CLKSEL, + WM8580_CLKSRC_MCLK); + if (ret < 0) + return ret; + + /* Assuming the CODEC driver evaluates it's rfs too from this call */ + ret = snd_soc_dai_set_pll(codec_dai, 0, WM8580_PLLA, + SMDK64XX_WM8580_FREQ, pll_out); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C_I2SV2_DIV_BCLK, bfs); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C_I2SV2_DIV_RCLK, rfs); + if (ret < 0) + return ret; + + return 0; +} + +/* + * SMDK64XX WM8580 DAI operations. + */ +static struct snd_soc_ops smdk64xx_ops = { + .hw_params = smdk64xx_hw_params, +}; + +/* SMDK64xx Playback widgets */ +static const struct snd_soc_dapm_widget wm8580_dapm_widgets_pbk[] = { + SND_SOC_DAPM_HP("Front-L/R", NULL), + SND_SOC_DAPM_HP("Center/Sub", NULL), + SND_SOC_DAPM_HP("Rear-L/R", NULL), +}; + +/* SMDK64xx Capture widgets */ +static const struct snd_soc_dapm_widget wm8580_dapm_widgets_cpt[] = { + SND_SOC_DAPM_MIC("MicIn", NULL), + SND_SOC_DAPM_LINE("LineIn", NULL), +}; + +/* SMDK-PAIFTX connections */ +static const struct snd_soc_dapm_route audio_map_tx[] = { + /* MicIn feeds AINL */ + {"AINL", NULL, "MicIn"}, + + /* LineIn feeds AINL/R */ + {"AINL", NULL, "LineIn"}, + {"AINR", NULL, "LineIn"}, +}; + +/* SMDK-PAIFRX connections */ +static const struct snd_soc_dapm_route audio_map_rx[] = { + /* Front Left/Right are fed VOUT1L/R */ + {"Front-L/R", NULL, "VOUT1L"}, + {"Front-L/R", NULL, "VOUT1R"}, + + /* Center/Sub are fed VOUT2L/R */ + {"Center/Sub", NULL, "VOUT2L"}, + {"Center/Sub", NULL, "VOUT2R"}, + + /* Rear Left/Right are fed VOUT3L/R */ + {"Rear-L/R", NULL, "VOUT3L"}, + {"Rear-L/R", NULL, "VOUT3R"}, +}; + +static int smdk64xx_wm8580_init_paiftx(struct snd_soc_codec *codec) +{ + /* Add smdk64xx specific Capture widgets */ + snd_soc_dapm_new_controls(codec, wm8580_dapm_widgets_cpt, + ARRAY_SIZE(wm8580_dapm_widgets_cpt)); + + /* Set up PAIFTX audio path */ + snd_soc_dapm_add_routes(codec, audio_map_tx, ARRAY_SIZE(audio_map_tx)); + + /* All enabled by default */ + snd_soc_dapm_enable_pin(codec, "MicIn"); + snd_soc_dapm_enable_pin(codec, "LineIn"); + + /* signal a DAPM event */ + snd_soc_dapm_sync(codec); + + return 0; +} + +static int smdk64xx_wm8580_init_paifrx(struct snd_soc_codec *codec) +{ + /* Add smdk64xx specific Playback widgets */ + snd_soc_dapm_new_controls(codec, wm8580_dapm_widgets_pbk, + ARRAY_SIZE(wm8580_dapm_widgets_pbk)); + + /* Set up PAIFRX audio path */ + snd_soc_dapm_add_routes(codec, audio_map_rx, ARRAY_SIZE(audio_map_rx)); + + /* All enabled by default */ + snd_soc_dapm_enable_pin(codec, "Front-L/R"); + snd_soc_dapm_enable_pin(codec, "Center/Sub"); + snd_soc_dapm_enable_pin(codec, "Rear-L/R"); + + /* signal a DAPM event */ + snd_soc_dapm_sync(codec); + + return 0; +} + +static struct snd_soc_dai_link smdk64xx_dai[] = { +{ /* Primary Playback i/f */ + .name = "WM8580 PAIF RX", + .stream_name = "Playback", + .cpu_dai = &s3c64xx_i2s_dai[S3C64XX_I2S_V4], + .codec_dai = &wm8580_dai[WM8580_DAI_PAIFRX], + .init = smdk64xx_wm8580_init_paifrx, + .ops = &smdk64xx_ops, +}, +{ /* Primary Capture i/f */ + .name = "WM8580 PAIF TX", + .stream_name = "Capture", + .cpu_dai = &s3c64xx_i2s_dai[S3C64XX_I2S_V4], + .codec_dai = &wm8580_dai[WM8580_DAI_PAIFTX], + .init = smdk64xx_wm8580_init_paiftx, + .ops = &smdk64xx_ops, +}, +}; + +static struct snd_soc_card smdk64xx = { + .name = "smdk64xx", + .platform = &s3c24xx_soc_platform, + .dai_link = smdk64xx_dai, + .num_links = ARRAY_SIZE(smdk64xx_dai), +}; + +static struct snd_soc_device smdk64xx_snd_devdata = { + .card = &smdk64xx, + .codec_dev = &soc_codec_dev_wm8580, +}; + +static struct platform_device *smdk64xx_snd_device; + +static int __init smdk64xx_audio_init(void) +{ + int ret; + + smdk64xx_snd_device = platform_device_alloc("soc-audio", -1); + if (!smdk64xx_snd_device) + return -ENOMEM; + + platform_set_drvdata(smdk64xx_snd_device, &smdk64xx_snd_devdata); + smdk64xx_snd_devdata.dev = &smdk64xx_snd_device->dev; + ret = platform_device_add(smdk64xx_snd_device); + + if (ret) + platform_device_put(smdk64xx_snd_device); + + return ret; +} +module_init(smdk64xx_audio_init); + +MODULE_AUTHOR("Jaswinder Singh, jassi.brar@samsung.com"); +MODULE_DESCRIPTION("ALSA SoC SMDK64XX WM8580"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From d62ab3589462d406e98731799361f46095467882 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 21 Sep 2009 04:21:47 -0700 Subject: ASoC: Convert soc-cache to use C99 style initialisers for the table Signed-off-by: Mark Brown --- sound/soc/soc-cache.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c index 404231ee878..d2505e8b06c 100644 --- a/sound/soc/soc-cache.c +++ b/sound/soc/soc-cache.c @@ -179,10 +179,20 @@ static struct { unsigned int (*read)(struct snd_soc_codec *, unsigned int); unsigned int (*i2c_read)(struct snd_soc_codec *, unsigned int); } io_types[] = { - { 7, 9, snd_soc_7_9_write, snd_soc_7_9_spi_write, snd_soc_7_9_read }, - { 8, 8, snd_soc_8_8_write, NULL, snd_soc_8_8_read, NULL }, - { 8, 16, snd_soc_8_16_write, NULL, snd_soc_8_16_read, - snd_soc_8_16_read_i2c }, + { + .addr_bits = 7, .data_bits = 9, + .write = snd_soc_7_9_write, .read = snd_soc_7_9_read, + .spi_write = snd_soc_7_9_spi_write + }, + { + .addr_bits = 8, .data_bits = 8, + .write = snd_soc_8_8_write, .read = snd_soc_8_8_read, + }, + { + .addr_bits = 8, .data_bits = 16, + .write = snd_soc_8_16_write, .read = snd_soc_8_16_read, + .i2c_read = snd_soc_8_16_read_i2c, + }, }; /** -- cgit v1.2.3 From 766df6d98f9c28dfc6f72c23a010819719e4c3e0 Mon Sep 17 00:00:00 2001 From: Barry Song Date: Wed, 23 Sep 2009 11:51:04 -0400 Subject: ASoC: Blackfin I2S: use dai state rather than local counter Since the active field of the dai already tells us the stream activity, the local counter variable is redundant and can be replaced. Signed-off-by: Barry Song Signed-off-by: Mike Frysinger Signed-off-by: Mark Brown --- sound/soc/blackfin/bf5xx-i2s.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) (limited to 'sound') diff --git a/sound/soc/blackfin/bf5xx-i2s.c b/sound/soc/blackfin/bf5xx-i2s.c index 1e9d161c76c..fe2c35ddcbf 100644 --- a/sound/soc/blackfin/bf5xx-i2s.c +++ b/sound/soc/blackfin/bf5xx-i2s.c @@ -49,7 +49,6 @@ struct bf5xx_i2s_port { u16 rcr1; u16 tcr2; u16 rcr2; - int counter; int configured; }; @@ -133,16 +132,6 @@ static int bf5xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, return ret; } -static int bf5xx_i2s_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - pr_debug("%s enter\n", __func__); - - /*this counter is used for counting how many pcm streams are opened*/ - bf5xx_i2s.counter++; - return 0; -} - static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -201,9 +190,8 @@ static void bf5xx_i2s_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { pr_debug("%s enter\n", __func__); - bf5xx_i2s.counter--; /* No active stream, SPORT is allowed to be configured again. */ - if (!bf5xx_i2s.counter) + if (!dai->active) bf5xx_i2s.configured = 0; } @@ -284,7 +272,6 @@ static int bf5xx_i2s_resume(struct snd_soc_dai *dai) SNDRV_PCM_FMTBIT_S32_LE) static struct snd_soc_dai_ops bf5xx_i2s_dai_ops = { - .startup = bf5xx_i2s_startup, .shutdown = bf5xx_i2s_shutdown, .hw_params = bf5xx_i2s_hw_params, .set_fmt = bf5xx_i2s_set_dai_fmt, -- cgit v1.2.3 From f34762b64704814838619c1d258bebf19004f5cd Mon Sep 17 00:00:00 2001 From: Graeme Gregory Date: Fri, 25 Sep 2009 13:30:26 +0100 Subject: ASoC: pxa-ssp increase max_channels to 8 When running in TDM mode there can be more than 2 channels used. Datasheet has figures for upto 8 channels so increase max_channels on all SSP interfaces to this figure. Signed-off-by: Graeme Gregory Signed-off-by: Mark Brown --- sound/soc/pxa/pxa-ssp.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index 57f201c94ca..a2b1e8fd5d8 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c @@ -760,13 +760,13 @@ struct snd_soc_dai pxa_ssp_dai[] = { .resume = pxa_ssp_resume, .playback = { .channels_min = 1, - .channels_max = 2, + .channels_max = 8, .rates = PXA_SSP_RATES, .formats = PXA_SSP_FORMATS, }, .capture = { .channels_min = 1, - .channels_max = 2, + .channels_max = 8, .rates = PXA_SSP_RATES, .formats = PXA_SSP_FORMATS, }, @@ -780,13 +780,13 @@ struct snd_soc_dai pxa_ssp_dai[] = { .resume = pxa_ssp_resume, .playback = { .channels_min = 1, - .channels_max = 2, + .channels_max = 8, .rates = PXA_SSP_RATES, .formats = PXA_SSP_FORMATS, }, .capture = { .channels_min = 1, - .channels_max = 2, + .channels_max = 8, .rates = PXA_SSP_RATES, .formats = PXA_SSP_FORMATS, }, @@ -801,13 +801,13 @@ struct snd_soc_dai pxa_ssp_dai[] = { .resume = pxa_ssp_resume, .playback = { .channels_min = 1, - .channels_max = 2, + .channels_max = 8, .rates = PXA_SSP_RATES, .formats = PXA_SSP_FORMATS, }, .capture = { .channels_min = 1, - .channels_max = 2, + .channels_max = 8, .rates = PXA_SSP_RATES, .formats = PXA_SSP_FORMATS, }, @@ -822,13 +822,13 @@ struct snd_soc_dai pxa_ssp_dai[] = { .resume = pxa_ssp_resume, .playback = { .channels_min = 1, - .channels_max = 2, + .channels_max = 8, .rates = PXA_SSP_RATES, .formats = PXA_SSP_FORMATS, }, .capture = { .channels_min = 1, - .channels_max = 2, + .channels_max = 8, .rates = PXA_SSP_RATES, .formats = PXA_SSP_FORMATS, }, -- cgit v1.2.3 From 4fa9c1a5953441e06dbde7b6a655cbf6618e61dd Mon Sep 17 00:00:00 2001 From: Chaithrika U S Date: Wed, 30 Sep 2009 17:32:27 -0400 Subject: ASoC: DaVinci: McASP FIFO related updates The DMA params for McASP with FIFO has been updated so that it works for various FIFO levels. A member- 'fifo_level' has been added to the DMA params data structure. The fifo_level can be adjusted by the tx[rx]_numevt platform data. This is relevant only for DA8xx/OMAP-L1xx platforms. This implementation has been tested for numevt values 1, 2, 4, 8. Signed-off-by: Chaithrika U S Signed-off-by: Mark Brown --- sound/soc/davinci/davinci-i2s.c | 2 ++ sound/soc/davinci/davinci-mcasp.c | 17 +++++++---------- sound/soc/davinci/davinci-pcm.c | 21 ++++++++++++++++++--- sound/soc/davinci/davinci-pcm.h | 1 + 4 files changed, 28 insertions(+), 13 deletions(-) (limited to 'sound') diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index 4ae70704802..2ab809359c0 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -397,6 +397,8 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, } dma_params->acnt = dma_params->data_type; + dma_params->fifo_level = 0; + rcr |= DAVINCI_MCBSP_RCR_RFRLEN1(1); xcr |= DAVINCI_MCBSP_XCR_XFRLEN1(1); diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index 5d1f98a4c97..50ad0519a8f 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -714,16 +714,13 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, struct davinci_pcm_dma_params *dma_params = &dev->dma_params[substream->stream]; int word_length; - u8 numevt; + u8 fifo_level; davinci_hw_common_param(dev, substream->stream); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - numevt = dev->txnumevt; + fifo_level = dev->txnumevt; else - numevt = dev->rxnumevt; - - if (!numevt) - numevt = 1; + fifo_level = dev->rxnumevt; if (dev->op_mode == DAVINCI_MCASP_DIT_MODE) davinci_hw_dit_param(dev); @@ -751,12 +748,12 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - if (dev->version == MCASP_VERSION_2) { - dma_params->data_type *= numevt; - dma_params->acnt = 4 * numevt; - } else + if (dev->version == MCASP_VERSION_2 && !fifo_level) + dma_params->acnt = 4; + else dma_params->acnt = dma_params->data_type; + dma_params->fifo_level = fifo_level; davinci_config_channel_size(dev, word_length); return 0; diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c index 359e99ec724..1152d8ba897 100644 --- a/sound/soc/davinci/davinci-pcm.c +++ b/sound/soc/davinci/davinci-pcm.c @@ -66,38 +66,53 @@ static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream) dma_addr_t dma_pos; dma_addr_t src, dst; unsigned short src_bidx, dst_bidx; + unsigned short src_cidx, dst_cidx; unsigned int data_type; unsigned short acnt; unsigned int count; + unsigned int fifo_level; period_size = snd_pcm_lib_period_bytes(substream); dma_offset = prtd->period * period_size; dma_pos = runtime->dma_addr + dma_offset; + fifo_level = prtd->params->fifo_level; pr_debug("davinci_pcm: audio_set_dma_params_play channel = %d " "dma_ptr = %x period_size=%x\n", lch, dma_pos, period_size); data_type = prtd->params->data_type; count = period_size / data_type; + if (fifo_level) + count /= fifo_level; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { src = dma_pos; dst = prtd->params->dma_addr; src_bidx = data_type; dst_bidx = 0; + src_cidx = data_type * fifo_level; + dst_cidx = 0; } else { src = prtd->params->dma_addr; dst = dma_pos; src_bidx = 0; dst_bidx = data_type; + src_cidx = 0; + dst_cidx = data_type * fifo_level; } acnt = prtd->params->acnt; edma_set_src(lch, src, INCR, W8BIT); edma_set_dest(lch, dst, INCR, W8BIT); - edma_set_src_index(lch, src_bidx, 0); - edma_set_dest_index(lch, dst_bidx, 0); - edma_set_transfer_params(lch, acnt, count, 1, 0, ASYNC); + + edma_set_src_index(lch, src_bidx, src_cidx); + edma_set_dest_index(lch, dst_bidx, dst_cidx); + + if (!fifo_level) + edma_set_transfer_params(lch, acnt, count, 1, 0, ASYNC); + else + edma_set_transfer_params(lch, acnt, fifo_level, count, + fifo_level, ABSYNC); prtd->period++; if (unlikely(prtd->period >= runtime->periods)) diff --git a/sound/soc/davinci/davinci-pcm.h b/sound/soc/davinci/davinci-pcm.h index 8746606efc8..c8b0d2baf05 100644 --- a/sound/soc/davinci/davinci-pcm.h +++ b/sound/soc/davinci/davinci-pcm.h @@ -23,6 +23,7 @@ struct davinci_pcm_dma_params { enum dma_event_q eventq_no; /* event queue number */ unsigned char data_type; /* xfer data type */ unsigned char convert_mono_stereo; + unsigned int fifo_level; }; -- cgit v1.2.3 From c36b2fc73a6c0e7b185b17d594b38398ce1f7fff Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 30 Sep 2009 14:31:38 +0100 Subject: ASoC: Clean up WM8974 PLL configuration Don't use a static for WM8974 PLL factors - we don't support more than one device so it won't happen but no sense in leaving the race condition hanging around. Also, pre_div is a single bit and it's a bit simpler if we move the handling of the factor of 4 in the output into the coefficient setup. Signed-off-by: Mark Brown --- sound/soc/codecs/wm8974.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c index 5104c8aa34f..f30f86b3bda 100644 --- a/sound/soc/codecs/wm8974.c +++ b/sound/soc/codecs/wm8974.c @@ -330,36 +330,38 @@ static int wm8974_add_widgets(struct snd_soc_codec *codec) } struct pll_ { - unsigned int pre_div:4; /* prescale - 1 */ + unsigned int pre_div:1; unsigned int n:4; unsigned int k; }; -static struct pll_ pll_div; - /* The size in bits of the pll divide multiplied by 10 * to allow rounding later */ #define FIXED_PLL_SIZE ((1 << 24) * 10) -static void pll_factors(unsigned int target, unsigned int source) +static void pll_factors(struct pll_ *pll_div, + unsigned int target, unsigned int source) { unsigned long long Kpart; unsigned int K, Ndiv, Nmod; + /* There is a fixed divide by 4 in the output path */ + target *= 4; + Ndiv = target / source; if (Ndiv < 6) { - source >>= 1; - pll_div.pre_div = 1; + source /= 2; + pll_div->pre_div = 1; Ndiv = target / source; } else - pll_div.pre_div = 0; + pll_div->pre_div = 0; if ((Ndiv < 6) || (Ndiv > 12)) printk(KERN_WARNING "WM8974 N value %u outwith recommended range!\n", Ndiv); - pll_div.n = Ndiv; + pll_div->n = Ndiv; Nmod = target % source; Kpart = FIXED_PLL_SIZE * (long long)Nmod; @@ -374,13 +376,14 @@ static void pll_factors(unsigned int target, unsigned int source) /* Move down to proper range now rounding is done */ K /= 10; - pll_div.k = K; + pll_div->k = K; } static int wm8974_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, unsigned int freq_in, unsigned int freq_out) { struct snd_soc_codec *codec = codec_dai->codec; + struct pll_ pll_div; u16 reg; if (freq_in == 0 || freq_out == 0) { @@ -394,7 +397,7 @@ static int wm8974_set_dai_pll(struct snd_soc_dai *codec_dai, return 0; } - pll_factors(freq_out*4, freq_in); + pll_factors(&pll_div, freq_out, freq_in); wm8974_write(codec, WM8974_PLLN, (pll_div.pre_div << 4) | pll_div.n); wm8974_write(codec, WM8974_PLLK1, pll_div.k >> 18); -- cgit v1.2.3 From aa983d9d63c38f596fb87754205da9b7a8d2f6fd Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 30 Sep 2009 14:16:11 +0100 Subject: ASoC: Factor out analogue platform data from WM8993 This is also shared with newer CODECs. Signed-off-by: Mark Brown --- sound/soc/codecs/wm8993.c | 36 +++++++++--------------------------- sound/soc/codecs/wm_hubs.c | 35 +++++++++++++++++++++++++++++++++++ sound/soc/codecs/wm_hubs.h | 5 +++++ 3 files changed, 49 insertions(+), 27 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c index 6b32a285260..dac39771214 100644 --- a/sound/soc/codecs/wm8993.c +++ b/sound/soc/codecs/wm8993.c @@ -1572,33 +1572,15 @@ static int wm8993_i2c_probe(struct i2c_client *i2c, /* Use automatic clock configuration */ snd_soc_update_bits(codec, WM8993_CLOCKING_4, WM8993_SR_MODE, 0); - if (!wm8993->pdata.lineout1_diff) - snd_soc_update_bits(codec, WM8993_LINE_MIXER1, - WM8993_LINEOUT1_MODE, - WM8993_LINEOUT1_MODE); - if (!wm8993->pdata.lineout2_diff) - snd_soc_update_bits(codec, WM8993_LINE_MIXER2, - WM8993_LINEOUT2_MODE, - WM8993_LINEOUT2_MODE); - - if (wm8993->pdata.lineout1fb) - snd_soc_update_bits(codec, WM8993_ADDITIONAL_CONTROL, - WM8993_LINEOUT1_FB, WM8993_LINEOUT1_FB); - - if (wm8993->pdata.lineout2fb) - snd_soc_update_bits(codec, WM8993_ADDITIONAL_CONTROL, - WM8993_LINEOUT2_FB, WM8993_LINEOUT2_FB); - - /* Apply the microphone bias/detection configuration - the - * platform data is directly applicable to the register. */ - snd_soc_update_bits(codec, WM8993_MICBIAS, - WM8993_JD_SCTHR_MASK | WM8993_JD_THR_MASK | - WM8993_MICB1_LVL | WM8993_MICB2_LVL, - wm8993->pdata.jd_scthr << WM8993_JD_SCTHR_SHIFT | - wm8993->pdata.jd_thr << WM8993_JD_THR_SHIFT | - wm8993->pdata.micbias1_lvl | - wm8993->pdata.micbias1_lvl << 1); - + wm_hubs_handle_analogue_pdata(codec, wm8993->pdata.lineout1_diff, + wm8993->pdata.lineout2_diff, + wm8993->pdata.lineout1fb, + wm8993->pdata.lineout2fb, + wm8993->pdata.jd_scthr, + wm8993->pdata.jd_thr, + wm8993->pdata.micbias1_lvl, + wm8993->pdata.micbias2_lvl); + ret = wm8993_set_bias_level(codec, SND_SOC_BIAS_STANDBY); if (ret != 0) goto err; diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c index e542027eea8..810a563d0eb 100644 --- a/sound/soc/codecs/wm_hubs.c +++ b/sound/soc/codecs/wm_hubs.c @@ -738,6 +738,41 @@ int wm_hubs_add_analogue_routes(struct snd_soc_codec *codec, } EXPORT_SYMBOL_GPL(wm_hubs_add_analogue_routes); +int wm_hubs_handle_analogue_pdata(struct snd_soc_codec *codec, + int lineout1_diff, int lineout2_diff, + int lineout1fb, int lineout2fb, + int jd_scthr, int jd_thr, int micbias1_lvl, + int micbias2_lvl) +{ + if (!lineout1_diff) + snd_soc_update_bits(codec, WM8993_LINE_MIXER1, + WM8993_LINEOUT1_MODE, + WM8993_LINEOUT1_MODE); + if (!lineout2_diff) + snd_soc_update_bits(codec, WM8993_LINE_MIXER2, + WM8993_LINEOUT2_MODE, + WM8993_LINEOUT2_MODE); + + if (lineout1fb) + snd_soc_update_bits(codec, WM8993_ADDITIONAL_CONTROL, + WM8993_LINEOUT1_FB, WM8993_LINEOUT1_FB); + + if (lineout2fb) + snd_soc_update_bits(codec, WM8993_ADDITIONAL_CONTROL, + WM8993_LINEOUT2_FB, WM8993_LINEOUT2_FB); + + snd_soc_update_bits(codec, WM8993_MICBIAS, + WM8993_JD_SCTHR_MASK | WM8993_JD_THR_MASK | + WM8993_MICB1_LVL | WM8993_MICB2_LVL, + jd_scthr << WM8993_JD_SCTHR_SHIFT | + jd_thr << WM8993_JD_THR_SHIFT | + micbias1_lvl | + micbias2_lvl << WM8993_MICB2_LVL_SHIFT); + + return 0; +} +EXPORT_SYMBOL_GPL(wm_hubs_handle_analogue_pdata); + MODULE_DESCRIPTION("Shared support for Wolfson hubs products"); MODULE_AUTHOR("Mark Brown "); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm_hubs.h b/sound/soc/codecs/wm_hubs.h index ec09cb6a293..36d3fba1de8 100644 --- a/sound/soc/codecs/wm_hubs.h +++ b/sound/soc/codecs/wm_hubs.h @@ -20,5 +20,10 @@ extern const unsigned int wm_hubs_spkmix_tlv[]; extern int wm_hubs_add_analogue_controls(struct snd_soc_codec *); extern int wm_hubs_add_analogue_routes(struct snd_soc_codec *, int, int); +extern int wm_hubs_handle_analogue_pdata(struct snd_soc_codec *, + int lineout1_diff, int lineout2_diff, + int lineout1fb, int lineout2fb, + int jd_scthr, int jd_thr, + int micbias1_lvl, int micbias2_lvl); #endif -- cgit v1.2.3 From bb26276744a80d066681836f4d49c70010b129d6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 1 Oct 2009 07:39:45 +0200 Subject: ASoC: Fix build errors of wm8711.c with SPI Fix a couple of typos and a missing header file inclusion to build wm8711.c properly with CONFIG_SPI_MASTER. Signed-off-by: Takashi Iwai --- sound/soc/codecs/wm8711.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c index ae083eb92fb..90ec8c58e2f 100644 --- a/sound/soc/codecs/wm8711.c +++ b/sound/soc/codecs/wm8711.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -632,9 +633,9 @@ static int __init wm8711_modinit(void) } #endif #if defined(CONFIG_SPI_MASTER) - ret = spi_register_driver(&wm8731_spi_driver); + ret = spi_register_driver(&wm8711_spi_driver); if (ret != 0) { - printk(KERN_ERR "Failed to register WM8731 SPI driver: %d\n", + printk(KERN_ERR "Failed to register WM8711 SPI driver: %d\n", ret); } #endif @@ -648,7 +649,7 @@ static void __exit wm8711_exit(void) i2c_del_driver(&wm8711_i2c_driver); #endif #if defined(CONFIG_SPI_MASTER) - spi_unregister_driver(&wm8731_spi_driver); + spi_unregister_driver(&wm8711_spi_driver); #endif } module_exit(wm8711_exit); -- cgit v1.2.3 From 140318aaa924ce9664ff59366993228cf1547f1d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 1 Oct 2009 08:40:32 +0200 Subject: ASoC: Fix snd_soc_dai_set_pll() calls in neo1973_*.c Fix the missing argument of snd_soc_dai_set_pll() in neo1973_*.c, which was forgotten in the commit 85488037bb. Signed-off-by: Takashi Iwai --- sound/soc/s3c24xx/neo1973_gta02_wm8753.c | 6 +++--- sound/soc/s3c24xx/neo1973_wm8753.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/soc/s3c24xx/neo1973_gta02_wm8753.c b/sound/soc/s3c24xx/neo1973_gta02_wm8753.c index 6ddd1b3b16b..26409a9cef9 100644 --- a/sound/soc/s3c24xx/neo1973_gta02_wm8753.c +++ b/sound/soc/s3c24xx/neo1973_gta02_wm8753.c @@ -133,7 +133,7 @@ static int neo1973_gta02_hifi_hw_free(struct snd_pcm_substream *substream) struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; /* disable the PLL */ - return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0); + return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0, 0); } /* @@ -183,7 +183,7 @@ static int neo1973_gta02_voice_hw_params( return ret; /* configue and enable PLL for 12.288MHz output */ - ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, + ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, iis_clkrate / 4, 12288000); if (ret < 0) return ret; @@ -197,7 +197,7 @@ static int neo1973_gta02_voice_hw_free(struct snd_pcm_substream *substream) struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; /* disable the PLL */ - return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0); + return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0, 0); } static struct snd_soc_ops neo1973_gta02_voice_ops = { diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c index 16009eba9cb..c9b794843a7 100644 --- a/sound/soc/s3c24xx/neo1973_wm8753.c +++ b/sound/soc/s3c24xx/neo1973_wm8753.c @@ -153,7 +153,7 @@ static int neo1973_hifi_hw_free(struct snd_pcm_substream *substream) pr_debug("Entered %s\n", __func__); /* disable the PLL */ - return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0); + return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0, 0); } /* @@ -203,7 +203,7 @@ static int neo1973_voice_hw_params(struct snd_pcm_substream *substream, return ret; /* configue and enable PLL for 12.288MHz output */ - ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, + ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, iis_clkrate / 4, 12288000); if (ret < 0) return ret; @@ -219,7 +219,7 @@ static int neo1973_voice_hw_free(struct snd_pcm_substream *substream) pr_debug("Entered %s\n", __func__); /* disable the PLL */ - return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0); + return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0, 0); } static struct snd_soc_ops neo1973_voice_ops = { -- cgit v1.2.3 From 88439ac793934a47f47ad285656b63d09f5937c8 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 1 Oct 2009 10:32:47 +0300 Subject: ASoC: add support for multiple cards/codecs in debugfs In order to support multiple codecs on the same system in the debugfs the directory hierarchy need to be changed by adding directory per codec under the asoc direcorty: debugfs/asoc/{dev_name(socdev->dev)}-{codec->name}/codec_reg /dapm_pop_time /dapm/{widgets} With the original implementation only the debugfs files are only created for the first codec, other codecs loaded later would fail to create the debugfs files (since they are already exist). Furthermore in this situation any of the codecs has been removed, would cause the debugfs entries to disappear, regardless if the codec, which created them are still loaded (the one which loaded first). Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index f5b356f8acf..e4ab36daf3f 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1254,21 +1254,35 @@ static const struct file_operations codec_reg_fops = { static void soc_init_codec_debugfs(struct snd_soc_codec *codec) { + char codec_root[128]; + + snprintf(codec_root, sizeof(codec_root), + "%s-%s", dev_name(codec->socdev->dev), codec->name); + + codec->debugfs_codec_root = debugfs_create_dir(codec_root, + debugfs_root); + if (!codec->debugfs_codec_root) { + printk(KERN_WARNING + "ASoC: Failed to create codec debugfs directory\n"); + return; + } + codec->debugfs_reg = debugfs_create_file("codec_reg", 0644, - debugfs_root, codec, - &codec_reg_fops); + codec->debugfs_codec_root, + codec, &codec_reg_fops); if (!codec->debugfs_reg) printk(KERN_WARNING "ASoC: Failed to create codec register debugfs file\n"); codec->debugfs_pop_time = debugfs_create_u32("dapm_pop_time", 0744, - debugfs_root, + codec->debugfs_codec_root, &codec->pop_time); if (!codec->debugfs_pop_time) printk(KERN_WARNING "Failed to create pop time debugfs file\n"); - codec->debugfs_dapm = debugfs_create_dir("dapm", debugfs_root); + codec->debugfs_dapm = debugfs_create_dir("dapm", + codec->debugfs_codec_root); if (!codec->debugfs_dapm) printk(KERN_WARNING "Failed to create DAPM debugfs directory\n"); @@ -1278,9 +1292,7 @@ static void soc_init_codec_debugfs(struct snd_soc_codec *codec) static void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec) { - debugfs_remove_recursive(codec->debugfs_dapm); - debugfs_remove(codec->debugfs_pop_time); - debugfs_remove(codec->debugfs_reg); + debugfs_remove_recursive(codec->debugfs_codec_root); } #else -- cgit v1.2.3 From ce3e3737a3361e0c7030f8598eec36bb82050de6 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 2 Oct 2009 09:17:37 +0300 Subject: ASoC: Improve the debugfs hierarchy Change the way the debugfs entries are created: If the codec->dev is valid, than use: debugfs/asoc/{codec->name}.{dev_name(codec->dev)}/ if the codec->dev is NULL: debugfs/asoc/{codec->name}/ as root for the debugfs entries. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index e4ab36daf3f..1dec9d21c55 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1256,8 +1256,12 @@ static void soc_init_codec_debugfs(struct snd_soc_codec *codec) { char codec_root[128]; - snprintf(codec_root, sizeof(codec_root), - "%s-%s", dev_name(codec->socdev->dev), codec->name); + if (codec->dev) + snprintf(codec_root, sizeof(codec_root), + "%s.%s", codec->name, dev_name(codec->dev)); + else + snprintf(codec_root, sizeof(codec_root), + "%s", codec->name); codec->debugfs_codec_root = debugfs_create_dir(codec_root, debugfs_root); -- cgit v1.2.3 From 1642e3d42a062221e4df18df260d4703d18ca519 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 5 Oct 2009 16:24:26 +0100 Subject: ASoC: Simplify code for DAPM widget updates We don't need to check for an event callback since we also check for an appropriate event flag when applying mux status changes. Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 52 ++++++++++++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 26 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 8eaf1b6e7ef..613764638c7 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -1786,19 +1786,19 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, mutex_lock(&widget->codec->mutex); widget->value = val; dapm_mux_update_power(widget, kcontrol, mask, mux, val, e); - if (widget->event) { - if (widget->event_flags & SND_SOC_DAPM_PRE_REG) { - ret = widget->event(widget, - kcontrol, SND_SOC_DAPM_PRE_REG); - if (ret < 0) - goto out; - } - ret = snd_soc_update_bits(widget->codec, e->reg, mask, val); - if (widget->event_flags & SND_SOC_DAPM_POST_REG) - ret = widget->event(widget, - kcontrol, SND_SOC_DAPM_POST_REG); - } else - ret = snd_soc_update_bits(widget->codec, e->reg, mask, val); + + if (widget->event_flags & SND_SOC_DAPM_PRE_REG) { + ret = widget->event(widget, + kcontrol, SND_SOC_DAPM_PRE_REG); + if (ret < 0) + goto out; + } + + ret = snd_soc_update_bits(widget->codec, e->reg, mask, val); + + if (widget->event_flags & SND_SOC_DAPM_POST_REG) + ret = widget->event(widget, + kcontrol, SND_SOC_DAPM_POST_REG); out: mutex_unlock(&widget->codec->mutex); @@ -1883,19 +1883,19 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, mutex_lock(&widget->codec->mutex); widget->value = val; dapm_mux_update_power(widget, kcontrol, mask, mux, val, e); - if (widget->event) { - if (widget->event_flags & SND_SOC_DAPM_PRE_REG) { - ret = widget->event(widget, - kcontrol, SND_SOC_DAPM_PRE_REG); - if (ret < 0) - goto out; - } - ret = snd_soc_update_bits(widget->codec, e->reg, mask, val); - if (widget->event_flags & SND_SOC_DAPM_POST_REG) - ret = widget->event(widget, - kcontrol, SND_SOC_DAPM_POST_REG); - } else - ret = snd_soc_update_bits(widget->codec, e->reg, mask, val); + + if (widget->event_flags & SND_SOC_DAPM_PRE_REG) { + ret = widget->event(widget, + kcontrol, SND_SOC_DAPM_PRE_REG); + if (ret < 0) + goto out; + } + + ret = snd_soc_update_bits(widget->codec, e->reg, mask, val); + + if (widget->event_flags & SND_SOC_DAPM_POST_REG) + ret = widget->event(widget, + kcontrol, SND_SOC_DAPM_POST_REG); out: mutex_unlock(&widget->codec->mutex); -- cgit v1.2.3 From 3a65577d2199a7b33c85fd32838020c39da200f3 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 5 Oct 2009 17:23:30 +0100 Subject: ASoC: Push DAPM enumeration register change test out Don't assume that enumerations are backed by registers when updating mux power. Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 613764638c7..311467b95af 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -1202,8 +1202,8 @@ void snd_soc_dapm_debugfs_init(struct snd_soc_codec *codec) /* test and update the power status of a mux widget */ static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, - struct snd_kcontrol *kcontrol, int mask, - int mux, int val, struct soc_enum *e) + struct snd_kcontrol *kcontrol, int change, + int mux, struct soc_enum *e) { struct snd_soc_dapm_path *path; int found = 0; @@ -1212,7 +1212,7 @@ static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, widget->id != snd_soc_dapm_value_mux) return -ENODEV; - if (!snd_soc_test_bits(widget->codec, e->reg, mask, val)) + if (!change) return 0; /* find dapm widget path assoc with kcontrol */ @@ -1765,7 +1765,7 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, { struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - unsigned int val, mux; + unsigned int val, mux, change; unsigned int mask, bitmask; int ret = 0; @@ -1785,7 +1785,8 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, mutex_lock(&widget->codec->mutex); widget->value = val; - dapm_mux_update_power(widget, kcontrol, mask, mux, val, e); + change = snd_soc_test_bits(widget->codec, e->reg, mask, val); + dapm_mux_update_power(widget, kcontrol, change, mux, e); if (widget->event_flags & SND_SOC_DAPM_PRE_REG) { ret = widget->event(widget, @@ -1864,7 +1865,7 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, { struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - unsigned int val, mux; + unsigned int val, mux, change; unsigned int mask; int ret = 0; @@ -1882,7 +1883,8 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, mutex_lock(&widget->codec->mutex); widget->value = val; - dapm_mux_update_power(widget, kcontrol, mask, mux, val, e); + change = snd_soc_test_bits(widget->codec, e->reg, mask, val); + dapm_mux_update_power(widget, kcontrol, change, mux, e); if (widget->event_flags & SND_SOC_DAPM_PRE_REG) { ret = widget->event(widget, -- cgit v1.2.3 From d2b247a8be57647d1745535acd58169fbcbe431a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 6 Oct 2009 15:21:04 +0100 Subject: ASoC: Add virtual enumeration support for DAPM muxes Sometimes it is desirable to have a mux which does not reflect any direct register configuration but which will instead only have an effect implicitly (for example, as a result of changing which parts of the device are powered up). Provide a virtual mux for this purpose. Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) (limited to 'sound') diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 311467b95af..d2af872e477 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -1807,6 +1807,54 @@ out: } EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double); +/** + * snd_soc_dapm_get_enum_virt - Get virtual DAPM mux + * @kcontrol: mixer control + * @ucontrol: control element information + * + * Returns 0 for success. + */ +int snd_soc_dapm_get_enum_virt(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); + + ucontrol->value.enumerated.item[0] = widget->value; + + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_virt); + +/** + * snd_soc_dapm_put_enum_virt - Set virtual DAPM mux + * @kcontrol: mixer control + * @ucontrol: control element information + * + * Returns 0 for success. + */ +int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); + struct soc_enum *e = + (struct soc_enum *)kcontrol->private_value; + int change; + int ret = 0; + + if (ucontrol->value.enumerated.item[0] >= e->max) + return -EINVAL; + + mutex_lock(&widget->codec->mutex); + + change = widget->value != ucontrol->value.enumerated.item[0]; + widget->value = ucontrol->value.enumerated.item[0]; + dapm_mux_update_power(widget, kcontrol, change, widget->value, e); + + mutex_unlock(&widget->codec->mutex); + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt); + /** * snd_soc_dapm_get_value_enum_double - dapm semi enumerated double mixer get * callback -- cgit v1.2.3 From 69d2c2ae1dffac5fcd6130e459f250ae035b678f Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Thu, 8 Oct 2009 18:19:49 +0200 Subject: ASoC: at91sam9g20ek_2mmc board uses same audio connexion as at91sam9g20ek The modified revision of at91sam9g20 Evaluation Kit rev. C and onwards share with previous ones its audio connexion to Wolfson wm8731. Modify the SoC file to extend the machine ID checking. Signed-off-by: Nicolas Ferre Signed-off-by: Mark Brown --- sound/soc/atmel/sam9g20_wm8731.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c index 885ba012557..e028744c32c 100644 --- a/sound/soc/atmel/sam9g20_wm8731.c +++ b/sound/soc/atmel/sam9g20_wm8731.c @@ -207,7 +207,7 @@ static int __init at91sam9g20ek_init(void) struct clk *pllb; int ret; - if (!machine_is_at91sam9g20ek()) + if (!(machine_is_at91sam9g20ek() || machine_is_at91sam9g20ek_2mmc())) return -ENODEV; /* -- cgit v1.2.3 From 493b67efffc462703d583389aca96f850c18d3b3 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 9 Oct 2009 15:55:41 +0300 Subject: ASoC: TPA6130A2 amplifier driver Driver for Texas Instruments TPA6130A2 stereo headphone amplifier. The driver provides playback gain control and also pre-defined DAPM_HP widgets and DAPM routings for power management. The DAPM_HP widget names are: "TPA6130A2 Headphone Left" "TPA6130A2 Headphone Right" From soc machine drivers to use with the tpa6130a2 amplifier, the tpa6130a2_add_controls has to be called, which adds the alsa controls and the DAPM routing needed for the tpa6130a2. After that the machine driver can connect the codec's output with 'TPA6130A2 Left' and 'TPA6130A2 Right': {"TPA6130A2 Left", NULL, "CODEC LEFT OUT"}, {"TPA6130A2 Right", NULL, "CODEC RIGHT OUT"}, Internally the left and right channels are powered separately. When none of the channels are needed the amplifier is powered down: hard power: valid GPIO number is passed within platform data soft power: Using the software shutdown of the amplifier Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 4 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/tpa6130a2.c | 463 +++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/tpa6130a2.h | 62 ++++++ 4 files changed, 531 insertions(+) create mode 100644 sound/soc/codecs/tpa6130a2.c create mode 100644 sound/soc/codecs/tpa6130a2.h (limited to 'sound') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 3c46f34928e..fab01c99182 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -29,6 +29,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_TLV320AIC23 if I2C select SND_SOC_TLV320AIC26 if SPI_MASTER select SND_SOC_TLV320AIC3X if I2C + select SND_SOC_TPA6130A2 if I2C select SND_SOC_TWL4030 if TWL4030_CORE select SND_SOC_UDA134X select SND_SOC_UDA1380 if I2C @@ -228,3 +229,6 @@ config SND_SOC_WM9713 # Amp config SND_SOC_MAX9877 tristate + +config SND_SOC_TPA6130A2 + tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index fc1c458cbe2..2f14391b96f 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -49,6 +49,7 @@ snd-soc-wm-hubs-objs := wm_hubs.o # Amp snd-soc-max9877-objs := max9877.o +snd-soc-tpa6130a2-objs := tpa6130a2.o obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o obj-$(CONFIG_SND_SOC_AD1836) += snd-soc-ad1836.o @@ -101,3 +102,4 @@ obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o # Amp obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o +obj-$(CONFIG_SND_SOC_TPA6130A2) += snd-soc-tpa6130a2.o diff --git a/sound/soc/codecs/tpa6130a2.c b/sound/soc/codecs/tpa6130a2.c new file mode 100644 index 00000000000..1b77c959e2d --- /dev/null +++ b/sound/soc/codecs/tpa6130a2.c @@ -0,0 +1,463 @@ +/* + * ALSA SoC Texas Instruments TPA6130A2 headset stereo amplifier driver + * + * Copyright (C) Nokia Corporation + * + * Author: Peter Ujfalusi + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tpa6130a2.h" + +struct i2c_client *tpa6130a2_client; + +/* This struct is used to save the context */ +struct tpa6130a2_data { + struct mutex mutex; + unsigned char regs[TPA6130A2_CACHEREGNUM]; + int power_gpio; + unsigned char power_state; +}; + +static int tpa6130a2_i2c_read(int reg) +{ + struct tpa6130a2_data *data; + int val; + + BUG_ON(tpa6130a2_client == NULL); + data = i2c_get_clientdata(tpa6130a2_client); + + /* If powered off, return the cached value */ + if (data->power_state) { + val = i2c_smbus_read_byte_data(tpa6130a2_client, reg); + if (val < 0) + dev_err(&tpa6130a2_client->dev, "Read failed\n"); + else + data->regs[reg] = val; + } else { + val = data->regs[reg]; + } + + return val; +} + +static int tpa6130a2_i2c_write(int reg, u8 value) +{ + struct tpa6130a2_data *data; + int val = 0; + + BUG_ON(tpa6130a2_client == NULL); + data = i2c_get_clientdata(tpa6130a2_client); + + if (data->power_state) { + val = i2c_smbus_write_byte_data(tpa6130a2_client, reg, value); + if (val < 0) + dev_err(&tpa6130a2_client->dev, "Write failed\n"); + } + + /* Either powered on or off, we save the context */ + data->regs[reg] = value; + + return val; +} + +static u8 tpa6130a2_read(int reg) +{ + struct tpa6130a2_data *data; + + BUG_ON(tpa6130a2_client == NULL); + data = i2c_get_clientdata(tpa6130a2_client); + + return data->regs[reg]; +} + +static void tpa6130a2_initialize(void) +{ + struct tpa6130a2_data *data; + int i; + + BUG_ON(tpa6130a2_client == NULL); + data = i2c_get_clientdata(tpa6130a2_client); + + for (i = 1; i < TPA6130A2_REG_VERSION; i++) + tpa6130a2_i2c_write(i, data->regs[i]); +} + +void tpa6130a2_power(int power) +{ + struct tpa6130a2_data *data; + u8 val; + + BUG_ON(tpa6130a2_client == NULL); + data = i2c_get_clientdata(tpa6130a2_client); + + mutex_lock(&data->mutex); + if (power) { + /* Power on */ + if (data->power_gpio >= 0) { + gpio_set_value(data->power_gpio, 1); + data->power_state = 1; + tpa6130a2_initialize(); + } + /* Clear SWS */ + val = tpa6130a2_read(TPA6130A2_REG_CONTROL); + val &= ~TPA6130A2_SWS; + tpa6130a2_i2c_write(TPA6130A2_REG_CONTROL, val); + } else { + /* set SWS */ + val = tpa6130a2_read(TPA6130A2_REG_CONTROL); + val |= TPA6130A2_SWS; + tpa6130a2_i2c_write(TPA6130A2_REG_CONTROL, val); + /* Power off */ + if (data->power_gpio >= 0) { + gpio_set_value(data->power_gpio, 0); + data->power_state = 0; + } + } + mutex_unlock(&data->mutex); +} + +static int tpa6130a2_get_reg(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct tpa6130a2_data *data; + unsigned int reg = mc->reg; + unsigned int shift = mc->shift; + unsigned int mask = mc->max; + unsigned int invert = mc->invert; + + BUG_ON(tpa6130a2_client == NULL); + data = i2c_get_clientdata(tpa6130a2_client); + + mutex_lock(&data->mutex); + + ucontrol->value.integer.value[0] = + (tpa6130a2_read(reg) >> shift) & mask; + + if (invert) + ucontrol->value.integer.value[0] = + mask - ucontrol->value.integer.value[0]; + + mutex_unlock(&data->mutex); + return 0; +} + +static int tpa6130a2_set_reg(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct tpa6130a2_data *data; + unsigned int reg = mc->reg; + unsigned int shift = mc->shift; + unsigned int mask = mc->max; + unsigned int invert = mc->invert; + unsigned int val = (ucontrol->value.integer.value[0] & mask); + unsigned int val_reg; + + BUG_ON(tpa6130a2_client == NULL); + data = i2c_get_clientdata(tpa6130a2_client); + + if (invert) + val = mask - val; + + mutex_lock(&data->mutex); + + val_reg = tpa6130a2_read(reg); + if (((val_reg >> shift) & mask) == val) { + mutex_unlock(&data->mutex); + return 0; + } + + val_reg &= ~(mask << shift); + val_reg |= val << shift; + tpa6130a2_i2c_write(reg, val_reg); + + mutex_unlock(&data->mutex); + + return 1; +} + +/* + * TPA6130 volume. From -59.5 to 4 dB with increasing step size when going + * down in gain. + */ +static const unsigned int tpa6130_tlv[] = { + TLV_DB_RANGE_HEAD(10), + 0, 1, TLV_DB_SCALE_ITEM(-5950, 600, 0), + 2, 3, TLV_DB_SCALE_ITEM(-5000, 250, 0), + 4, 5, TLV_DB_SCALE_ITEM(-4550, 160, 0), + 6, 7, TLV_DB_SCALE_ITEM(-4140, 190, 0), + 8, 9, TLV_DB_SCALE_ITEM(-3650, 120, 0), + 10, 11, TLV_DB_SCALE_ITEM(-3330, 160, 0), + 12, 13, TLV_DB_SCALE_ITEM(-3040, 180, 0), + 14, 20, TLV_DB_SCALE_ITEM(-2710, 110, 0), + 21, 37, TLV_DB_SCALE_ITEM(-1960, 74, 0), + 38, 63, TLV_DB_SCALE_ITEM(-720, 45, 0), +}; + +static const struct snd_kcontrol_new tpa6130a2_controls[] = { + SOC_SINGLE_EXT_TLV("TPA6130A2 Headphone Playback Volume", + TPA6130A2_REG_VOL_MUTE, 0, 0x3f, 0, + tpa6130a2_get_reg, tpa6130a2_set_reg, + tpa6130_tlv), +}; + +/* + * Enable or disable channel (left or right) + * The bit number for mute and amplifier are the same per channel: + * bit 6: Right channel + * bit 7: Left channel + * in both registers. + */ +static void tpa6130a2_channel_enable(u8 channel, int enable) +{ + struct tpa6130a2_data *data; + u8 val; + + BUG_ON(tpa6130a2_client == NULL); + data = i2c_get_clientdata(tpa6130a2_client); + + if (enable) { + /* Enable channel */ + /* Enable amplifier */ + val = tpa6130a2_read(TPA6130A2_REG_CONTROL); + val |= channel; + tpa6130a2_i2c_write(TPA6130A2_REG_CONTROL, val); + + /* Unmute channel */ + val = tpa6130a2_read(TPA6130A2_REG_VOL_MUTE); + val &= ~channel; + tpa6130a2_i2c_write(TPA6130A2_REG_VOL_MUTE, val); + } else { + /* Disable channel */ + /* Mute channel */ + val = tpa6130a2_read(TPA6130A2_REG_VOL_MUTE); + val |= channel; + tpa6130a2_i2c_write(TPA6130A2_REG_VOL_MUTE, val); + + /* Disable amplifier */ + val = tpa6130a2_read(TPA6130A2_REG_CONTROL); + val &= ~channel; + tpa6130a2_i2c_write(TPA6130A2_REG_CONTROL, val); + } +} + +static int tpa6130a2_left_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + switch (event) { + case SND_SOC_DAPM_POST_PMU: + tpa6130a2_channel_enable(TPA6130A2_HP_EN_L, 1); + break; + case SND_SOC_DAPM_POST_PMD: + tpa6130a2_channel_enable(TPA6130A2_HP_EN_L, 0); + break; + } + return 0; +} + +static int tpa6130a2_right_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + switch (event) { + case SND_SOC_DAPM_POST_PMU: + tpa6130a2_channel_enable(TPA6130A2_HP_EN_R, 1); + break; + case SND_SOC_DAPM_POST_PMD: + tpa6130a2_channel_enable(TPA6130A2_HP_EN_R, 0); + break; + } + return 0; +} + +static int tpa6130a2_supply_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + switch (event) { + case SND_SOC_DAPM_POST_PMU: + tpa6130a2_power(1); + break; + case SND_SOC_DAPM_POST_PMD: + tpa6130a2_power(0); + break; + } + return 0; +} + +static const struct snd_soc_dapm_widget tpa6130a2_dapm_widgets[] = { + SND_SOC_DAPM_PGA_E("TPA6130A2 Left", SND_SOC_NOPM, + 0, 0, NULL, 0, tpa6130a2_left_event, + SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("TPA6130A2 Right", SND_SOC_NOPM, + 0, 0, NULL, 0, tpa6130a2_right_event, + SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("TPA6130A2 Enable", SND_SOC_NOPM, + 0, 0, tpa6130a2_supply_event, + SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD), + /* Outputs */ + SND_SOC_DAPM_HP("TPA6130A2 Headphone Left", NULL), + SND_SOC_DAPM_HP("TPA6130A2 Headphone Right", NULL), +}; + +static const struct snd_soc_dapm_route audio_map[] = { + {"TPA6130A2 Headphone Left", NULL, "TPA6130A2 Left"}, + {"TPA6130A2 Headphone Right", NULL, "TPA6130A2 Right"}, + + {"TPA6130A2 Headphone Left", NULL, "TPA6130A2 Enable"}, + {"TPA6130A2 Headphone Right", NULL, "TPA6130A2 Enable"}, +}; + +int tpa6130a2_add_controls(struct snd_soc_codec *codec) +{ + snd_soc_dapm_new_controls(codec, tpa6130a2_dapm_widgets, + ARRAY_SIZE(tpa6130a2_dapm_widgets)); + + snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); + + return snd_soc_add_controls(codec, tpa6130a2_controls, + ARRAY_SIZE(tpa6130a2_controls)); + +} +EXPORT_SYMBOL_GPL(tpa6130a2_add_controls); + +static int tpa6130a2_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev; + struct tpa6130a2_data *data; + struct tpa6130a2_platform_data *pdata; + int ret; + + dev = &client->dev; + + if (client->dev.platform_data == NULL) { + dev_err(dev, "Platform data not set\n"); + dump_stack(); + return -ENODEV; + } + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (data == NULL) { + dev_err(dev, "Can not allocate memory\n"); + return -ENOMEM; + } + + tpa6130a2_client = client; + + i2c_set_clientdata(tpa6130a2_client, data); + + pdata = (struct tpa6130a2_platform_data *)client->dev.platform_data; + data->power_gpio = pdata->power_gpio; + + mutex_init(&data->mutex); + + /* Set default register values */ + data->regs[TPA6130A2_REG_CONTROL] = TPA6130A2_SWS; + data->regs[TPA6130A2_REG_VOL_MUTE] = TPA6130A2_MUTE_R | + TPA6130A2_MUTE_L; + + if (data->power_gpio >= 0) { + ret = gpio_request(data->power_gpio, "tpa6130a2 enable"); + if (ret < 0) { + dev_err(dev, "Failed to request power GPIO (%d)\n", + data->power_gpio); + goto fail; + } + gpio_direction_output(data->power_gpio, 0); + } else { + data->power_state = 1; + tpa6130a2_initialize(); + } + + tpa6130a2_power(1); + + /* Read version */ + ret = tpa6130a2_i2c_read(TPA6130A2_REG_VERSION) & + TPA6130A2_VERSION_MASK; + if ((ret != 1) && (ret != 2)) + dev_warn(dev, "UNTESTED version detected (%d)\n", ret); + + /* Disable the chip */ + tpa6130a2_power(0); + + return 0; +fail: + kfree(data); + i2c_set_clientdata(tpa6130a2_client, NULL); + tpa6130a2_client = 0; + + return ret; +} + +static int tpa6130a2_remove(struct i2c_client *client) +{ + struct tpa6130a2_data *data = i2c_get_clientdata(client); + + tpa6130a2_power(0); + + if (data->power_gpio >= 0) + gpio_free(data->power_gpio); + kfree(data); + tpa6130a2_client = 0; + + return 0; +} + +static const struct i2c_device_id tpa6130a2_id[] = { + { "tpa6130a2", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, tpa6130a2_id); + +static struct i2c_driver tpa6130a2_i2c_driver = { + .driver = { + .name = "tpa6130a2", + .owner = THIS_MODULE, + }, + .probe = tpa6130a2_probe, + .remove = __devexit_p(tpa6130a2_remove), + .id_table = tpa6130a2_id, +}; + +static int __init tpa6130a2_init(void) +{ + return i2c_add_driver(&tpa6130a2_i2c_driver); +} + +static void __exit tpa6130a2_exit(void) +{ + i2c_del_driver(&tpa6130a2_i2c_driver); +} + +MODULE_AUTHOR("Peter Ujfalusi"); +MODULE_DESCRIPTION("TPA6130A2 Headphone amplifier driver"); +MODULE_LICENSE("GPL"); + +module_init(tpa6130a2_init); +module_exit(tpa6130a2_exit); diff --git a/sound/soc/codecs/tpa6130a2.h b/sound/soc/codecs/tpa6130a2.h new file mode 100644 index 00000000000..6a794f16cee --- /dev/null +++ b/sound/soc/codecs/tpa6130a2.h @@ -0,0 +1,62 @@ +/* + * ALSA SoC TPA6130A2 amplifier driver + * + * Copyright (C) Nokia Corporation + * + * Author: Peter Ujfalusi + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __TPA6130A2_H__ +#define __TPA6130A2_H__ + +/* Register addresses */ +#define TPA6130A2_REG_CONTROL 0x01 +#define TPA6130A2_REG_VOL_MUTE 0x02 +#define TPA6130A2_REG_OUT_IMPEDANCE 0x03 +#define TPA6130A2_REG_VERSION 0x04 + +#define TPA6130A2_CACHEREGNUM (TPA6130A2_REG_VERSION + 1) + +/* Register bits */ +/* TPA6130A2_REG_CONTROL (0x01) */ +#define TPA6130A2_SWS (0x01 << 0) +#define TPA6130A2_TERMAL (0x01 << 1) +#define TPA6130A2_MODE(x) (x << 4) +#define TPA6130A2_MODE_STEREO (0x00) +#define TPA6130A2_MODE_DUAL_MONO (0x01) +#define TPA6130A2_MODE_BRIDGE (0x02) +#define TPA6130A2_MODE_MASK (0x03) +#define TPA6130A2_HP_EN_R (0x01 << 6) +#define TPA6130A2_HP_EN_L (0x01 << 7) + +/* TPA6130A2_REG_VOL_MUTE (0x02) */ +#define TPA6130A2_VOLUME(x) ((x & 0x3f) << 0) +#define TPA6130A2_MUTE_R (0x01 << 6) +#define TPA6130A2_MUTE_L (0x01 << 7) + +/* TPA6130A2_REG_OUT_IMPEDANCE (0x03) */ +#define TPA6130A2_HIZ_R (0x01 << 0) +#define TPA6130A2_HIZ_L (0x01 << 1) + +/* TPA6130A2_REG_VERSION (0x04) */ +#define TPA6130A2_VERSION_MASK (0x0f) + +extern int tpa6130a2_add_controls(struct snd_soc_codec *codec); +extern void tpa6130a2_power(int power); + +#endif /* __TPA6130A2_H__ */ -- cgit v1.2.3 From ebab1b1d07266ab8ca9f65065e68b02f05504c4e Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 9 Oct 2009 19:13:47 +0100 Subject: ASoC: Minor fixups to tpa6130a2 driver - Staticise ttpa6130a2_client. - Remove unneeded cast from void. - Use explict NULL rather than 0. Signed-off-by: Mark Brown --- sound/soc/codecs/tpa6130a2.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/tpa6130a2.c b/sound/soc/codecs/tpa6130a2.c index 1b77c959e2d..0a6e7b4ace6 100644 --- a/sound/soc/codecs/tpa6130a2.c +++ b/sound/soc/codecs/tpa6130a2.c @@ -32,7 +32,7 @@ #include "tpa6130a2.h" -struct i2c_client *tpa6130a2_client; +static struct i2c_client *tpa6130a2_client; /* This struct is used to save the context */ struct tpa6130a2_data { @@ -372,7 +372,7 @@ static int tpa6130a2_probe(struct i2c_client *client, i2c_set_clientdata(tpa6130a2_client, data); - pdata = (struct tpa6130a2_platform_data *)client->dev.platform_data; + pdata = client->dev.platform_data; data->power_gpio = pdata->power_gpio; mutex_init(&data->mutex); @@ -410,7 +410,7 @@ static int tpa6130a2_probe(struct i2c_client *client, fail: kfree(data); i2c_set_clientdata(tpa6130a2_client, NULL); - tpa6130a2_client = 0; + tpa6130a2_client = NULL; return ret; } @@ -424,7 +424,7 @@ static int tpa6130a2_remove(struct i2c_client *client) if (data->power_gpio >= 0) gpio_free(data->power_gpio); kfree(data); - tpa6130a2_client = 0; + tpa6130a2_client = NULL; return 0; } -- cgit v1.2.3 From 814b7963e50e331f129acc25ad92bd4db45c300f Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 12 Oct 2009 11:43:55 +0300 Subject: ASoC: TPA6130A2: Make tpa6130a2_power as static The power for the amplifier should be handled internally by the tpa6130a2 driver. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/tpa6130a2.c | 2 +- sound/soc/codecs/tpa6130a2.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/tpa6130a2.c b/sound/soc/codecs/tpa6130a2.c index 0a6e7b4ace6..6b650c1aa3d 100644 --- a/sound/soc/codecs/tpa6130a2.c +++ b/sound/soc/codecs/tpa6130a2.c @@ -106,7 +106,7 @@ static void tpa6130a2_initialize(void) tpa6130a2_i2c_write(i, data->regs[i]); } -void tpa6130a2_power(int power) +static void tpa6130a2_power(int power) { struct tpa6130a2_data *data; u8 val; diff --git a/sound/soc/codecs/tpa6130a2.h b/sound/soc/codecs/tpa6130a2.h index 6a794f16cee..57e867fd86d 100644 --- a/sound/soc/codecs/tpa6130a2.h +++ b/sound/soc/codecs/tpa6130a2.h @@ -57,6 +57,5 @@ #define TPA6130A2_VERSION_MASK (0x0f) extern int tpa6130a2_add_controls(struct snd_soc_codec *codec); -extern void tpa6130a2_power(int power); #endif /* __TPA6130A2_H__ */ -- cgit v1.2.3 From 8e8b2d676f3f7c1246b108793fb5690e6c6fcd26 Mon Sep 17 00:00:00 2001 From: Eero Nurkkala Date: Mon, 12 Oct 2009 08:41:59 +0300 Subject: ASoC: Serialize access to dapm_power_widgets() Access to damp_power_widgets() is assumed to be single-threaded. Concurrent accesses to dapm_power_widgets() may result in unpredictable behavior. Calls from: close_delayed_work() soc_codec_close() soc_pcm_prepare() soc_suspend() soc_resume_deferred() to snd_soc_dapm_stream_event() do not have the codec->mutex taken to cover the call to dapm_power_widgets(). Thus, take the mutex in these paths also to assure single-threaded use of dapm_power_widgets(). Signed-off-by: Eero Nurkkala Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 8de6f9dec4a..d89f6dc0090 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -2072,9 +2072,9 @@ int snd_soc_dapm_stream_event(struct snd_soc_codec *codec, } } } - mutex_unlock(&codec->mutex); dapm_power_widgets(codec, event); + mutex_unlock(&codec->mutex); dump_dapm(codec, __func__); return 0; } -- cgit v1.2.3 From ed9d040d40942e9c48167f9f37f86fab8e0e5e17 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Mon, 12 Oct 2009 21:17:09 +0100 Subject: ASoC: S3C: Remove Remove the include from arch/arm/plat-s3c/include/plat/audio.h as it provides nothing to the current kernel and is not in any future plans for the system. Signed-off-by: Ben Dooks Signed-off-by: Simtec Linux Team Signed-off-by: Mark Brown --- sound/soc/s3c24xx/neo1973_wm8753.c | 1 - sound/soc/s3c24xx/s3c-i2s-v2.c | 1 - sound/soc/s3c24xx/s3c2412-i2s.c | 1 - sound/soc/s3c24xx/s3c2443-ac97.c | 1 - sound/soc/s3c24xx/s3c24xx-i2s.c | 2 +- sound/soc/s3c24xx/s3c24xx-pcm.c | 1 - sound/soc/s3c24xx/s3c64xx-i2s.c | 1 - 7 files changed, 1 insertion(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c index c9b794843a7..77de6c5127d 100644 --- a/sound/soc/s3c24xx/neo1973_wm8753.c +++ b/sound/soc/s3c24xx/neo1973_wm8753.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.c b/sound/soc/s3c24xx/s3c-i2s-v2.c index 11c45a37c63..28b0ab25509 100644 --- a/sound/soc/s3c24xx/s3c-i2s-v2.c +++ b/sound/soc/s3c24xx/s3c-i2s-v2.c @@ -32,7 +32,6 @@ #include -#include #include #include "s3c-i2s-v2.h" diff --git a/sound/soc/s3c24xx/s3c2412-i2s.c b/sound/soc/s3c24xx/s3c2412-i2s.c index a587ec40b44..ac5e47b082f 100644 --- a/sound/soc/s3c24xx/s3c2412-i2s.c +++ b/sound/soc/s3c24xx/s3c2412-i2s.c @@ -34,7 +34,6 @@ #include -#include #include #include diff --git a/sound/soc/s3c24xx/s3c2443-ac97.c b/sound/soc/s3c24xx/s3c2443-ac97.c index fc1beb0930b..b25e9f968df 100644 --- a/sound/soc/s3c24xx/s3c2443-ac97.c +++ b/sound/soc/s3c24xx/s3c2443-ac97.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.c b/sound/soc/s3c24xx/s3c24xx-i2s.c index 40e2c4790f0..c76b8bb214b 100644 --- a/sound/soc/s3c24xx/s3c24xx-i2s.c +++ b/sound/soc/s3c24xx/s3c24xx-i2s.c @@ -32,7 +32,7 @@ #include #include #include -#include + #include #include diff --git a/sound/soc/s3c24xx/s3c24xx-pcm.c b/sound/soc/s3c24xx/s3c24xx-pcm.c index 5cbbdc80fde..27cf097c2b1 100644 --- a/sound/soc/s3c24xx/s3c24xx-pcm.c +++ b/sound/soc/s3c24xx/s3c24xx-pcm.c @@ -29,7 +29,6 @@ #include #include #include -#include #include "s3c24xx-pcm.h" diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.c b/sound/soc/s3c24xx/s3c64xx-i2s.c index 43fb253a342..b67eed59666 100644 --- a/sound/soc/s3c24xx/s3c64xx-i2s.c +++ b/sound/soc/s3c24xx/s3c64xx-i2s.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include -- cgit v1.2.3 From d2058b0cd039aad89b111d83b9c347e9d8f57a84 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 13 Oct 2009 17:39:56 +0100 Subject: ASoC: Remove snd_soc_suspend_device() The PM core will grow pm_link infrastructure in 2.6.33 which can be used to implement the intended functionality of the ASoC-specific device suspend and resume callbacks so drop them. Signed-off-by: Mark Brown --- sound/soc/codecs/cs4270.c | 20 -------------------- sound/soc/codecs/wm8350.c | 17 ----------------- sound/soc/codecs/wm8400.c | 17 ----------------- sound/soc/codecs/wm8523.c | 17 ----------------- sound/soc/codecs/wm8580.c | 17 ----------------- sound/soc/codecs/wm8711.c | 17 ----------------- sound/soc/codecs/wm8731.c | 34 ---------------------------------- sound/soc/codecs/wm8753.c | 35 ----------------------------------- sound/soc/codecs/wm8776.c | 34 ---------------------------------- sound/soc/codecs/wm8900.c | 17 ----------------- sound/soc/codecs/wm8903.c | 17 ----------------- sound/soc/codecs/wm8940.c | 17 ----------------- sound/soc/codecs/wm8960.c | 17 ----------------- sound/soc/codecs/wm8961.c | 17 ----------------- sound/soc/codecs/wm8988.c | 34 ---------------------------------- sound/soc/codecs/wm9081.c | 17 ----------------- sound/soc/soc-core.c | 39 --------------------------------------- 17 files changed, 383 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index ca1e24a8f12..59bb16d033d 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c @@ -802,22 +802,6 @@ MODULE_DEVICE_TABLE(i2c, cs4270_id); * and all registers are written back to the hardware when resuming. */ -static int cs4270_i2c_suspend(struct i2c_client *client, pm_message_t mesg) -{ - struct cs4270_private *cs4270 = i2c_get_clientdata(client); - struct snd_soc_codec *codec = &cs4270->codec; - - return snd_soc_suspend_device(codec->dev); -} - -static int cs4270_i2c_resume(struct i2c_client *client) -{ - struct cs4270_private *cs4270 = i2c_get_clientdata(client); - struct snd_soc_codec *codec = &cs4270->codec; - - return snd_soc_resume_device(codec->dev); -} - static int cs4270_soc_suspend(struct platform_device *pdev, pm_message_t mesg) { struct snd_soc_codec *codec = cs4270_codec; @@ -853,8 +837,6 @@ static int cs4270_soc_resume(struct platform_device *pdev) return snd_soc_write(codec, CS4270_PWRCTL, reg); } #else -#define cs4270_i2c_suspend NULL -#define cs4270_i2c_resume NULL #define cs4270_soc_suspend NULL #define cs4270_soc_resume NULL #endif /* CONFIG_PM */ @@ -873,8 +855,6 @@ static struct i2c_driver cs4270_i2c_driver = { .id_table = cs4270_id, .probe = cs4270_i2c_probe, .remove = cs4270_i2c_remove, - .suspend = cs4270_i2c_suspend, - .resume = cs4270_i2c_resume, }; /* diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index 72abc5a6d8d..714114b50d1 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c @@ -1680,21 +1680,6 @@ static int __devexit wm8350_codec_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM -static int wm8350_codec_suspend(struct platform_device *pdev, pm_message_t m) -{ - return snd_soc_suspend_device(&pdev->dev); -} - -static int wm8350_codec_resume(struct platform_device *pdev) -{ - return snd_soc_resume_device(&pdev->dev); -} -#else -#define wm8350_codec_suspend NULL -#define wm8350_codec_resume NULL -#endif - static struct platform_driver wm8350_codec_driver = { .driver = { .name = "wm8350-codec", @@ -1702,8 +1687,6 @@ static struct platform_driver wm8350_codec_driver = { }, .probe = wm8350_codec_probe, .remove = __devexit_p(wm8350_codec_remove), - .suspend = wm8350_codec_suspend, - .resume = wm8350_codec_resume, }; static __init int wm8350_init(void) diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c index 9cb8e50f0fb..bd7eecba20f 100644 --- a/sound/soc/codecs/wm8400.c +++ b/sound/soc/codecs/wm8400.c @@ -1559,21 +1559,6 @@ static int __exit wm8400_codec_remove(struct platform_device *dev) return 0; } -#ifdef CONFIG_PM -static int wm8400_pdev_suspend(struct platform_device *pdev, pm_message_t msg) -{ - return snd_soc_suspend_device(&pdev->dev); -} - -static int wm8400_pdev_resume(struct platform_device *pdev) -{ - return snd_soc_resume_device(&pdev->dev); -} -#else -#define wm8400_pdev_suspend NULL -#define wm8400_pdev_resume NULL -#endif - static struct platform_driver wm8400_codec_driver = { .driver = { .name = "wm8400-codec", @@ -1581,8 +1566,6 @@ static struct platform_driver wm8400_codec_driver = { }, .probe = wm8400_codec_probe, .remove = __exit_p(wm8400_codec_remove), - .suspend = wm8400_pdev_suspend, - .resume = wm8400_pdev_resume, }; static int __init wm8400_codec_init(void) diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c index 25870a4652f..268cab21c2c 100644 --- a/sound/soc/codecs/wm8523.c +++ b/sound/soc/codecs/wm8523.c @@ -638,21 +638,6 @@ static __devexit int wm8523_i2c_remove(struct i2c_client *client) return 0; } -#ifdef CONFIG_PM -static int wm8523_i2c_suspend(struct i2c_client *i2c, pm_message_t msg) -{ - return snd_soc_suspend_device(&i2c->dev); -} - -static int wm8523_i2c_resume(struct i2c_client *i2c) -{ - return snd_soc_resume_device(&i2c->dev); -} -#else -#define wm8523_i2c_suspend NULL -#define wm8523_i2c_resume NULL -#endif - static const struct i2c_device_id wm8523_i2c_id[] = { { "wm8523", 0 }, { } @@ -666,8 +651,6 @@ static struct i2c_driver wm8523_i2c_driver = { }, .probe = wm8523_i2c_probe, .remove = __devexit_p(wm8523_i2c_remove), - .suspend = wm8523_i2c_suspend, - .resume = wm8523_i2c_resume, .id_table = wm8523_i2c_id, }; #endif diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index 3be5c0b2552..a09b23e0366 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c @@ -961,21 +961,6 @@ static int wm8580_i2c_remove(struct i2c_client *client) return 0; } -#ifdef CONFIG_PM -static int wm8580_i2c_suspend(struct i2c_client *client, pm_message_t msg) -{ - return snd_soc_suspend_device(&client->dev); -} - -static int wm8580_i2c_resume(struct i2c_client *client) -{ - return snd_soc_resume_device(&client->dev); -} -#else -#define wm8580_i2c_suspend NULL -#define wm8580_i2c_resume NULL -#endif - static const struct i2c_device_id wm8580_i2c_id[] = { { "wm8580", 0 }, { } @@ -989,8 +974,6 @@ static struct i2c_driver wm8580_i2c_driver = { }, .probe = wm8580_i2c_probe, .remove = wm8580_i2c_remove, - .suspend = wm8580_i2c_suspend, - .resume = wm8580_i2c_resume, .id_table = wm8580_i2c_id, }; #endif diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c index 90ec8c58e2f..54189fbf9e9 100644 --- a/sound/soc/codecs/wm8711.c +++ b/sound/soc/codecs/wm8711.c @@ -548,21 +548,6 @@ static int __devexit wm8711_spi_remove(struct spi_device *spi) return 0; } -#ifdef CONFIG_PM -static int wm8711_spi_suspend(struct spi_device *spi, pm_message_t msg) -{ - return snd_soc_suspend_device(&spi->dev); -} - -static int wm8711_spi_resume(struct spi_device *spi) -{ - return snd_soc_resume_device(&spi->dev); -} -#else -#define wm8711_spi_suspend NULL -#define wm8711_spi_resume NULL -#endif - static struct spi_driver wm8711_spi_driver = { .driver = { .name = "wm8711", @@ -570,8 +555,6 @@ static struct spi_driver wm8711_spi_driver = { .owner = THIS_MODULE, }, .probe = wm8711_spi_probe, - .suspend = wm8711_spi_suspend, - .resume = wm8711_spi_resume, .remove = __devexit_p(wm8711_spi_remove), }; #endif /* CONFIG_SPI_MASTER */ diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index d3fd4f28d96..0e59219a59f 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -623,21 +623,6 @@ static int __devexit wm8731_spi_remove(struct spi_device *spi) return 0; } -#ifdef CONFIG_PM -static int wm8731_spi_suspend(struct spi_device *spi, pm_message_t msg) -{ - return snd_soc_suspend_device(&spi->dev); -} - -static int wm8731_spi_resume(struct spi_device *spi) -{ - return snd_soc_resume_device(&spi->dev); -} -#else -#define wm8731_spi_suspend NULL -#define wm8731_spi_resume NULL -#endif - static struct spi_driver wm8731_spi_driver = { .driver = { .name = "wm8731", @@ -645,8 +630,6 @@ static struct spi_driver wm8731_spi_driver = { .owner = THIS_MODULE, }, .probe = wm8731_spi_probe, - .suspend = wm8731_spi_suspend, - .resume = wm8731_spi_resume, .remove = __devexit_p(wm8731_spi_remove), }; #endif /* CONFIG_SPI_MASTER */ @@ -679,21 +662,6 @@ static __devexit int wm8731_i2c_remove(struct i2c_client *client) return 0; } -#ifdef CONFIG_PM -static int wm8731_i2c_suspend(struct i2c_client *i2c, pm_message_t msg) -{ - return snd_soc_suspend_device(&i2c->dev); -} - -static int wm8731_i2c_resume(struct i2c_client *i2c) -{ - return snd_soc_resume_device(&i2c->dev); -} -#else -#define wm8731_i2c_suspend NULL -#define wm8731_i2c_resume NULL -#endif - static const struct i2c_device_id wm8731_i2c_id[] = { { "wm8731", 0 }, { } @@ -707,8 +675,6 @@ static struct i2c_driver wm8731_i2c_driver = { }, .probe = wm8731_i2c_probe, .remove = __devexit_p(wm8731_i2c_remove), - .suspend = wm8731_i2c_suspend, - .resume = wm8731_i2c_resume, .id_table = wm8731_i2c_id, }; #endif diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index 9b27efb052f..8f7305257d2 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c @@ -1767,21 +1767,6 @@ static int wm8753_i2c_remove(struct i2c_client *client) return 0; } -#ifdef CONFIG_PM -static int wm8753_i2c_suspend(struct i2c_client *client, pm_message_t msg) -{ - return snd_soc_suspend_device(&client->dev); -} - -static int wm8753_i2c_resume(struct i2c_client *client) -{ - return snd_soc_resume_device(&client->dev); -} -#else -#define wm8753_i2c_suspend NULL -#define wm8753_i2c_resume NULL -#endif - static const struct i2c_device_id wm8753_i2c_id[] = { { "wm8753", 0 }, { } @@ -1795,8 +1780,6 @@ static struct i2c_driver wm8753_i2c_driver = { }, .probe = wm8753_i2c_probe, .remove = wm8753_i2c_remove, - .suspend = wm8753_i2c_suspend, - .resume = wm8753_i2c_resume, .id_table = wm8753_i2c_id, }; #endif @@ -1852,22 +1835,6 @@ static int __devexit wm8753_spi_remove(struct spi_device *spi) return 0; } -#ifdef CONFIG_PM -static int wm8753_spi_suspend(struct spi_device *spi, pm_message_t msg) -{ - return snd_soc_suspend_device(&spi->dev); -} - -static int wm8753_spi_resume(struct spi_device *spi) -{ - return snd_soc_resume_device(&spi->dev); -} - -#else -#define wm8753_spi_suspend NULL -#define wm8753_spi_resume NULL -#endif - static struct spi_driver wm8753_spi_driver = { .driver = { .name = "wm8753", @@ -1876,8 +1843,6 @@ static struct spi_driver wm8753_spi_driver = { }, .probe = wm8753_spi_probe, .remove = __devexit_p(wm8753_spi_remove), - .suspend = wm8753_spi_suspend, - .resume = wm8753_spi_resume, }; #endif diff --git a/sound/soc/codecs/wm8776.c b/sound/soc/codecs/wm8776.c index a9829aa26e5..a0bbb28eed7 100644 --- a/sound/soc/codecs/wm8776.c +++ b/sound/soc/codecs/wm8776.c @@ -616,21 +616,6 @@ static int __devexit wm8776_spi_remove(struct spi_device *spi) return 0; } -#ifdef CONFIG_PM -static int wm8776_spi_suspend(struct spi_device *spi, pm_message_t msg) -{ - return snd_soc_suspend_device(&spi->dev); -} - -static int wm8776_spi_resume(struct spi_device *spi) -{ - return snd_soc_resume_device(&spi->dev); -} -#else -#define wm8776_spi_suspend NULL -#define wm8776_spi_resume NULL -#endif - static struct spi_driver wm8776_spi_driver = { .driver = { .name = "wm8776", @@ -638,8 +623,6 @@ static struct spi_driver wm8776_spi_driver = { .owner = THIS_MODULE, }, .probe = wm8776_spi_probe, - .suspend = wm8776_spi_suspend, - .resume = wm8776_spi_resume, .remove = __devexit_p(wm8776_spi_remove), }; #endif /* CONFIG_SPI_MASTER */ @@ -673,21 +656,6 @@ static __devexit int wm8776_i2c_remove(struct i2c_client *client) return 0; } -#ifdef CONFIG_PM -static int wm8776_i2c_suspend(struct i2c_client *i2c, pm_message_t msg) -{ - return snd_soc_suspend_device(&i2c->dev); -} - -static int wm8776_i2c_resume(struct i2c_client *i2c) -{ - return snd_soc_resume_device(&i2c->dev); -} -#else -#define wm8776_i2c_suspend NULL -#define wm8776_i2c_resume NULL -#endif - static const struct i2c_device_id wm8776_i2c_id[] = { { "wm8776", 0 }, { } @@ -701,8 +669,6 @@ static struct i2c_driver wm8776_i2c_driver = { }, .probe = wm8776_i2c_probe, .remove = __devexit_p(wm8776_i2c_remove), - .suspend = wm8776_i2c_suspend, - .resume = wm8776_i2c_resume, .id_table = wm8776_i2c_id, }; #endif diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index 882604ef768..b48804b5cac 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c @@ -1312,21 +1312,6 @@ static __devexit int wm8900_i2c_remove(struct i2c_client *client) return 0; } -#ifdef CONFIG_PM -static int wm8900_i2c_suspend(struct i2c_client *client, pm_message_t msg) -{ - return snd_soc_suspend_device(&client->dev); -} - -static int wm8900_i2c_resume(struct i2c_client *client) -{ - return snd_soc_resume_device(&client->dev); -} -#else -#define wm8900_i2c_suspend NULL -#define wm8900_i2c_resume NULL -#endif - static const struct i2c_device_id wm8900_i2c_id[] = { { "wm8900", 0 }, { } @@ -1340,8 +1325,6 @@ static struct i2c_driver wm8900_i2c_driver = { }, .probe = wm8900_i2c_probe, .remove = __devexit_p(wm8900_i2c_remove), - .suspend = wm8900_i2c_suspend, - .resume = wm8900_i2c_resume, .id_table = wm8900_i2c_id, }; diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index fe1307b500c..94cdb813041 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -1655,21 +1655,6 @@ static __devexit int wm8903_i2c_remove(struct i2c_client *client) return 0; } -#ifdef CONFIG_PM -static int wm8903_i2c_suspend(struct i2c_client *client, pm_message_t msg) -{ - return snd_soc_suspend_device(&client->dev); -} - -static int wm8903_i2c_resume(struct i2c_client *client) -{ - return snd_soc_resume_device(&client->dev); -} -#else -#define wm8903_i2c_suspend NULL -#define wm8903_i2c_resume NULL -#endif - /* i2c codec control layer */ static const struct i2c_device_id wm8903_i2c_id[] = { { "wm8903", 0 }, @@ -1684,8 +1669,6 @@ static struct i2c_driver wm8903_i2c_driver = { }, .probe = wm8903_i2c_probe, .remove = __devexit_p(wm8903_i2c_remove), - .suspend = wm8903_i2c_suspend, - .resume = wm8903_i2c_resume, .id_table = wm8903_i2c_id, }; diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c index 1685cfb993c..8d4fd3c08c0 100644 --- a/sound/soc/codecs/wm8940.c +++ b/sound/soc/codecs/wm8940.c @@ -877,21 +877,6 @@ static int __devexit wm8940_i2c_remove(struct i2c_client *client) return 0; } -#ifdef CONFIG_PM -static int wm8940_i2c_suspend(struct i2c_client *client, pm_message_t msg) -{ - return snd_soc_suspend_device(&client->dev); -} - -static int wm8940_i2c_resume(struct i2c_client *client) -{ - return snd_soc_resume_device(&client->dev); -} -#else -#define wm8940_i2c_suspend NULL -#define wm8940_i2c_resume NULL -#endif - static const struct i2c_device_id wm8940_i2c_id[] = { { "wm8940", 0 }, { } @@ -905,8 +890,6 @@ static struct i2c_driver wm8940_i2c_driver = { }, .probe = wm8940_i2c_probe, .remove = __devexit_p(wm8940_i2c_remove), - .suspend = wm8940_i2c_suspend, - .resume = wm8940_i2c_resume, .id_table = wm8940_i2c_id, }; diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index 416fb3c1701..b9b096a8539 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -883,21 +883,6 @@ static __devexit int wm8960_i2c_remove(struct i2c_client *client) return 0; } -#ifdef CONFIG_PM -static int wm8960_i2c_suspend(struct i2c_client *client, pm_message_t msg) -{ - return snd_soc_suspend_device(&client->dev); -} - -static int wm8960_i2c_resume(struct i2c_client *client) -{ - return snd_soc_resume_device(&client->dev); -} -#else -#define wm8960_i2c_suspend NULL -#define wm8960_i2c_resume NULL -#endif - static const struct i2c_device_id wm8960_i2c_id[] = { { "wm8960", 0 }, { } @@ -911,8 +896,6 @@ static struct i2c_driver wm8960_i2c_driver = { }, .probe = wm8960_i2c_probe, .remove = __devexit_p(wm8960_i2c_remove), - .suspend = wm8960_i2c_suspend, - .resume = wm8960_i2c_resume, .id_table = wm8960_i2c_id, }; diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c index 50303208589..b5c6f2cd5ae 100644 --- a/sound/soc/codecs/wm8961.c +++ b/sound/soc/codecs/wm8961.c @@ -1206,21 +1206,6 @@ static __devexit int wm8961_i2c_remove(struct i2c_client *client) return 0; } -#ifdef CONFIG_PM -static int wm8961_i2c_suspend(struct i2c_client *client, pm_message_t state) -{ - return snd_soc_suspend_device(&client->dev); -} - -static int wm8961_i2c_resume(struct i2c_client *client) -{ - return snd_soc_resume_device(&client->dev); -} -#else -#define wm8961_i2c_suspend NULL -#define wm8961_i2c_resume NULL -#endif - static const struct i2c_device_id wm8961_i2c_id[] = { { "wm8961", 0 }, { } @@ -1234,8 +1219,6 @@ static struct i2c_driver wm8961_i2c_driver = { }, .probe = wm8961_i2c_probe, .remove = __devexit_p(wm8961_i2c_remove), - .suspend = wm8961_i2c_suspend, - .resume = wm8961_i2c_resume, .id_table = wm8961_i2c_id, }; diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c index 3f530f8a972..d8d8f68b81e 100644 --- a/sound/soc/codecs/wm8988.c +++ b/sound/soc/codecs/wm8988.c @@ -944,21 +944,6 @@ static int wm8988_i2c_remove(struct i2c_client *client) return 0; } -#ifdef CONFIG_PM -static int wm8988_i2c_suspend(struct i2c_client *client, pm_message_t msg) -{ - return snd_soc_suspend_device(&client->dev); -} - -static int wm8988_i2c_resume(struct i2c_client *client) -{ - return snd_soc_resume_device(&client->dev); -} -#else -#define wm8988_i2c_suspend NULL -#define wm8988_i2c_resume NULL -#endif - static const struct i2c_device_id wm8988_i2c_id[] = { { "wm8988", 0 }, { } @@ -972,8 +957,6 @@ static struct i2c_driver wm8988_i2c_driver = { }, .probe = wm8988_i2c_probe, .remove = wm8988_i2c_remove, - .suspend = wm8988_i2c_suspend, - .resume = wm8988_i2c_resume, .id_table = wm8988_i2c_id, }; #endif @@ -1006,21 +989,6 @@ static int __devexit wm8988_spi_remove(struct spi_device *spi) return 0; } -#ifdef CONFIG_PM -static int wm8988_spi_suspend(struct spi_device *spi, pm_message_t msg) -{ - return snd_soc_suspend_device(&spi->dev); -} - -static int wm8988_spi_resume(struct spi_device *spi) -{ - return snd_soc_resume_device(&spi->dev); -} -#else -#define wm8988_spi_suspend NULL -#define wm8988_spi_resume NULL -#endif - static struct spi_driver wm8988_spi_driver = { .driver = { .name = "wm8988", @@ -1029,8 +997,6 @@ static struct spi_driver wm8988_spi_driver = { }, .probe = wm8988_spi_probe, .remove = __devexit_p(wm8988_spi_remove), - .suspend = wm8988_spi_suspend, - .resume = wm8988_spi_resume, }; #endif diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c index 686e5aa9720..4cb6b104b72 100644 --- a/sound/soc/codecs/wm9081.c +++ b/sound/soc/codecs/wm9081.c @@ -1452,21 +1452,6 @@ static __devexit int wm9081_i2c_remove(struct i2c_client *client) return 0; } -#ifdef CONFIG_PM -static int wm9081_i2c_suspend(struct i2c_client *client, pm_message_t msg) -{ - return snd_soc_suspend_device(&client->dev); -} - -static int wm9081_i2c_resume(struct i2c_client *client) -{ - return snd_soc_resume_device(&client->dev); -} -#else -#define wm9081_i2c_suspend NULL -#define wm9081_i2c_resume NULL -#endif - static const struct i2c_device_id wm9081_i2c_id[] = { { "wm9081", 0 }, { } @@ -1480,8 +1465,6 @@ static struct i2c_driver wm9081_i2c_driver = { }, .probe = wm9081_i2c_probe, .remove = __devexit_p(wm9081_i2c_remove), - .suspend = wm9081_i2c_suspend, - .resume = wm9081_i2c_resume, .id_table = wm9081_i2c_id, }; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 1dec9d21c55..fa0da3cac70 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -790,45 +790,6 @@ static int soc_resume(struct device *dev) return 0; } - -/** - * snd_soc_suspend_device: Notify core of device suspend - * - * @dev: Device being suspended. - * - * In order to ensure that the entire audio subsystem is suspended in a - * coordinated fashion ASoC devices should suspend themselves when - * called by ASoC. When the standard kernel suspend process asks the - * device to suspend it should call this function to initiate a suspend - * of the entire ASoC card. - * - * \note Currently this function is stubbed out. - */ -int snd_soc_suspend_device(struct device *dev) -{ - return 0; -} -EXPORT_SYMBOL_GPL(snd_soc_suspend_device); - -/** - * snd_soc_resume_device: Notify core of device resume - * - * @dev: Device being resumed. - * - * In order to ensure that the entire audio subsystem is resumed in a - * coordinated fashion ASoC devices should resume themselves when called - * by ASoC. When the standard kernel resume process asks the device - * to resume it should call this function. Once all the components of - * the card have notified that they are ready to be resumed the card - * will be resumed. - * - * \note Currently this function is stubbed out. - */ -int snd_soc_resume_device(struct device *dev) -{ - return 0; -} -EXPORT_SYMBOL_GPL(snd_soc_resume_device); #else #define soc_suspend NULL #define soc_resume NULL -- cgit v1.2.3 From 640fb39e386a0dac9014e5b8a512de0950e30288 Mon Sep 17 00:00:00 2001 From: Igor Grinberg Date: Wed, 14 Oct 2009 09:20:26 +0200 Subject: ASoC: finally enable support for eXeda and CM-X300 Signed-off-by: Igor Grinberg Signed-off-by: Mike Rapoport CC: Mark Brown CC: alsa-devel@alsa-project.org Signed-off-by: Mark Brown --- sound/soc/pxa/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig index dcb3181bb34..d4f4031afa3 100644 --- a/sound/soc/pxa/Kconfig +++ b/sound/soc/pxa/Kconfig @@ -90,7 +90,8 @@ config SND_PXA2XX_SOC_E800 config SND_PXA2XX_SOC_EM_X270 tristate "SoC Audio support for CompuLab EM-x270, eXeda and CM-X300" - depends on SND_PXA2XX_SOC && MACH_EM_X270 + depends on SND_PXA2XX_SOC && (MACH_EM_X270 || MACH_EXEDA || \ + MACH_CM_X300) select SND_PXA2XX_SOC_AC97 select SND_SOC_WM9712 help -- cgit v1.2.3 From c8bf93f0fe8c5a509a29e30f3bac823fa0f6d96e Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 15 Oct 2009 09:03:56 +0300 Subject: ASoC: Codec driver for Texas Instruments tlv320dac33 codec Driver for Texas Instruments TLV320DAC33 (SLAS546) low power stereo audio DAC. TLV320DAC33 is a stereo audio codec with integrated 24KB FIFO for low power audio playback. The digital interface can use I2S, DSP (A or B), Right and Left justified formats. DAC33 has stereo analog input, which can be bypassed to the analog outputs. Regarding to the internal 24KB FIFO the driver implements 'FIFO bypass' mode (default) and nSample mode (FIFO is in use). a) In 'FIFO bypass' mode the internal FIFO is not in use, the codec is working synchronously as a normal codec (it needs constant stream of data on the digital interface). b) The nSample mode implementation uses one interrupt line from DAC33 to the host: Alarm threshold is set to 10ms of audio data (limit by the driver implementation). DAC33 will signal an interrupt, when the FIFO level goes under the Alarm threshold. The host will write to nSample register a value (number of stereo samples), to tell DAC33 how many samples it should read in a burst from the host. When the DAC33 received the number of samples, it disables the clocks on the I2S bus. When the FIFO use again goes under the Alarm threshold, DAC33 signals the host with an interrupt, and the process is repeated. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 4 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/tlv320dac33.c | 1237 ++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/tlv320dac33.h | 267 +++++++++ 4 files changed, 1510 insertions(+) create mode 100644 sound/soc/codecs/tlv320dac33.c create mode 100644 sound/soc/codecs/tlv320dac33.h (limited to 'sound') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index fab01c99182..d30fce71cfe 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -30,6 +30,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_TLV320AIC26 if SPI_MASTER select SND_SOC_TLV320AIC3X if I2C select SND_SOC_TPA6130A2 if I2C + select SND_SOC_TLV320DAC33 if I2C select SND_SOC_TWL4030 if TWL4030_CORE select SND_SOC_UDA134X select SND_SOC_UDA1380 if I2C @@ -142,6 +143,9 @@ config SND_SOC_TLV320AIC26 config SND_SOC_TLV320AIC3X tristate +config SND_SOC_TLV320DAC33 + tristate + config SND_SOC_TWL4030 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 2f14391b96f..8f519ee9600 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -17,6 +17,7 @@ snd-soc-stac9766-objs := stac9766.o snd-soc-tlv320aic23-objs := tlv320aic23.o snd-soc-tlv320aic26-objs := tlv320aic26.o snd-soc-tlv320aic3x-objs := tlv320aic3x.o +snd-soc-tlv320dac33-objs := tlv320dac33.o snd-soc-twl4030-objs := twl4030.o snd-soc-uda134x-objs := uda134x.o snd-soc-uda1380-objs := uda1380.o @@ -70,6 +71,7 @@ obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.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 +obj-$(CONFIG_SND_SOC_TLV320DAC33) += snd-soc-tlv320dac33.o obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o obj-$(CONFIG_SND_SOC_UDA134X) += snd-soc-uda134x.o obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c new file mode 100644 index 00000000000..3ca8934fc26 --- /dev/null +++ b/sound/soc/codecs/tlv320dac33.c @@ -0,0 +1,1237 @@ +/* + * ALSA SoC Texas Instruments TLV320DAC33 codec driver + * + * Author: Peter Ujfalusi + * + * Copyright: (C) 2009 Nokia Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "tlv320dac33.h" + +#define DAC33_BUFFER_SIZE_BYTES 24576 /* bytes, 12288 16 bit words, + * 6144 stereo */ +#define DAC33_BUFFER_SIZE_SAMPLES 6144 + +#define NSAMPLE_MAX 5700 + +#define LATENCY_TIME_MS 20 + +static struct snd_soc_codec *tlv320dac33_codec; + +enum dac33_state { + DAC33_IDLE = 0, + DAC33_PREFILL, + DAC33_PLAYBACK, + DAC33_FLUSH, +}; + +struct tlv320dac33_priv { + struct mutex mutex; + struct workqueue_struct *dac33_wq; + struct work_struct work; + struct snd_soc_codec codec; + int power_gpio; + int chip_power; + int irq; + unsigned int refclk; + + unsigned int alarm_threshold; /* set to be half of LATENCY_TIME_MS */ + unsigned int nsample_min; /* nsample should not be lower than + * this */ + unsigned int nsample_max; /* nsample should not be higher than + * this */ + unsigned int nsample_switch; /* Use FIFO or bypass FIFO switch */ + unsigned int nsample; /* burst read amount from host */ + + enum dac33_state state; +}; + +static const u8 dac33_reg[DAC33_CACHEREGNUM] = { +0x00, 0x00, 0x00, 0x00, /* 0x00 - 0x03 */ +0x00, 0x00, 0x00, 0x00, /* 0x04 - 0x07 */ +0x00, 0x00, 0x00, 0x00, /* 0x08 - 0x0b */ +0x00, 0x00, 0x00, 0x00, /* 0x0c - 0x0f */ +0x00, 0x00, 0x00, 0x00, /* 0x10 - 0x13 */ +0x00, 0x00, 0x00, 0x00, /* 0x14 - 0x17 */ +0x00, 0x00, 0x00, 0x00, /* 0x18 - 0x1b */ +0x00, 0x00, 0x00, 0x00, /* 0x1c - 0x1f */ +0x00, 0x00, 0x00, 0x00, /* 0x20 - 0x23 */ +0x00, 0x00, 0x00, 0x00, /* 0x24 - 0x27 */ +0x00, 0x00, 0x00, 0x00, /* 0x28 - 0x2b */ +0x00, 0x00, 0x00, 0x80, /* 0x2c - 0x2f */ +0x80, 0x00, 0x00, 0x00, /* 0x30 - 0x33 */ +0x00, 0x00, 0x00, 0x00, /* 0x34 - 0x37 */ +0x00, 0x00, /* 0x38 - 0x39 */ +/* Registers 0x3a - 0x3f are reserved */ + 0x00, 0x00, /* 0x3a - 0x3b */ +0x00, 0x00, 0x00, 0x00, /* 0x3c - 0x3f */ + +0x00, 0x00, 0x00, 0x00, /* 0x40 - 0x43 */ +0x00, 0x80, /* 0x44 - 0x45 */ +/* Registers 0x46 - 0x47 are reserved */ + 0x80, 0x80, /* 0x46 - 0x47 */ + +0x80, 0x00, 0x00, /* 0x48 - 0x4a */ +/* Registers 0x4b - 0x7c are reserved */ + 0x00, /* 0x4b */ +0x00, 0x00, 0x00, 0x00, /* 0x4c - 0x4f */ +0x00, 0x00, 0x00, 0x00, /* 0x50 - 0x53 */ +0x00, 0x00, 0x00, 0x00, /* 0x54 - 0x57 */ +0x00, 0x00, 0x00, 0x00, /* 0x58 - 0x5b */ +0x00, 0x00, 0x00, 0x00, /* 0x5c - 0x5f */ +0x00, 0x00, 0x00, 0x00, /* 0x60 - 0x63 */ +0x00, 0x00, 0x00, 0x00, /* 0x64 - 0x67 */ +0x00, 0x00, 0x00, 0x00, /* 0x68 - 0x6b */ +0x00, 0x00, 0x00, 0x00, /* 0x6c - 0x6f */ +0x00, 0x00, 0x00, 0x00, /* 0x70 - 0x73 */ +0x00, 0x00, 0x00, 0x00, /* 0x74 - 0x77 */ +0x00, 0x00, 0x00, 0x00, /* 0x78 - 0x7b */ +0x00, /* 0x7c */ + + 0xda, 0x33, 0x03, /* 0x7d - 0x7f */ +}; + +/* Register read and write */ +static inline unsigned int dac33_read_reg_cache(struct snd_soc_codec *codec, + unsigned reg) +{ + u8 *cache = codec->reg_cache; + if (reg >= DAC33_CACHEREGNUM) + return 0; + + return cache[reg]; +} + +static inline void dac33_write_reg_cache(struct snd_soc_codec *codec, + u8 reg, u8 value) +{ + u8 *cache = codec->reg_cache; + if (reg >= DAC33_CACHEREGNUM) + return; + + cache[reg] = value; +} + +static int dac33_read(struct snd_soc_codec *codec, unsigned int reg, + u8 *value) +{ + struct tlv320dac33_priv *dac33 = codec->private_data; + int val; + + *value = reg & 0xff; + + /* If powered off, return the cached value */ + if (dac33->chip_power) { + val = i2c_smbus_read_byte_data(codec->control_data, value[0]); + if (val < 0) { + dev_err(codec->dev, "Read failed (%d)\n", val); + value[0] = dac33_read_reg_cache(codec, reg); + } else { + value[0] = val; + dac33_write_reg_cache(codec, reg, val); + } + } else { + value[0] = dac33_read_reg_cache(codec, reg); + } + + return 0; +} + +static int dac33_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + struct tlv320dac33_priv *dac33 = codec->private_data; + u8 data[2]; + int ret = 0; + + /* + * data is + * D15..D8 dac33 register offset + * D7...D0 register data + */ + data[0] = reg & 0xff; + data[1] = value & 0xff; + + dac33_write_reg_cache(codec, data[0], data[1]); + if (dac33->chip_power) { + ret = codec->hw_write(codec->control_data, data, 2); + if (ret != 2) + dev_err(codec->dev, "Write failed (%d)\n", ret); + else + ret = 0; + } + + return ret; +} + +static int dac33_write_locked(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + struct tlv320dac33_priv *dac33 = codec->private_data; + int ret; + + mutex_lock(&dac33->mutex); + ret = dac33_write(codec, reg, value); + mutex_unlock(&dac33->mutex); + + return ret; +} + +#define DAC33_I2C_ADDR_AUTOINC 0x80 +static int dac33_write16(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + struct tlv320dac33_priv *dac33 = codec->private_data; + u8 data[3]; + int ret = 0; + + /* + * data is + * D23..D16 dac33 register offset + * D15..D8 register data MSB + * D7...D0 register data LSB + */ + data[0] = reg & 0xff; + data[1] = (value >> 8) & 0xff; + data[2] = value & 0xff; + + dac33_write_reg_cache(codec, data[0], data[1]); + dac33_write_reg_cache(codec, data[0] + 1, data[2]); + + if (dac33->chip_power) { + /* We need to set autoincrement mode for 16 bit writes */ + data[0] |= DAC33_I2C_ADDR_AUTOINC; + ret = codec->hw_write(codec->control_data, data, 3); + if (ret != 3) + dev_err(codec->dev, "Write failed (%d)\n", ret); + else + ret = 0; + } + + return ret; +} + +static void dac33_restore_regs(struct snd_soc_codec *codec) +{ + struct tlv320dac33_priv *dac33 = codec->private_data; + u8 *cache = codec->reg_cache; + u8 data[2]; + int i, ret; + + if (!dac33->chip_power) + return; + + for (i = DAC33_PWR_CTRL; i <= DAC33_INTP_CTRL_B; i++) { + data[0] = i; + data[1] = cache[i]; + /* Skip the read only registers */ + if ((i >= DAC33_INT_OSC_STATUS && + i <= DAC33_INT_OSC_FREQ_RAT_READ_B) || + (i >= DAC33_FIFO_WPTR_MSB && i <= DAC33_FIFO_IRQ_FLAG) || + i == DAC33_DAC_STATUS_FLAGS || + i == DAC33_SRC_EST_REF_CLK_RATIO_A || + i == DAC33_SRC_EST_REF_CLK_RATIO_B) + continue; + ret = codec->hw_write(codec->control_data, data, 2); + if (ret != 2) + dev_err(codec->dev, "Write failed (%d)\n", ret); + } + for (i = DAC33_LDAC_PWR_CTRL; i <= DAC33_LINEL_TO_LLO_VOL; i++) { + data[0] = i; + data[1] = cache[i]; + ret = codec->hw_write(codec->control_data, data, 2); + if (ret != 2) + dev_err(codec->dev, "Write failed (%d)\n", ret); + } + for (i = DAC33_LINER_TO_RLO_VOL; i <= DAC33_OSC_TRIM; i++) { + data[0] = i; + data[1] = cache[i]; + ret = codec->hw_write(codec->control_data, data, 2); + if (ret != 2) + dev_err(codec->dev, "Write failed (%d)\n", ret); + } +} + +static inline void dac33_soft_power(struct snd_soc_codec *codec, int power) +{ + u8 reg; + + reg = dac33_read_reg_cache(codec, DAC33_PWR_CTRL); + if (power) + reg |= DAC33_PDNALLB; + else + reg &= ~DAC33_PDNALLB; + dac33_write(codec, DAC33_PWR_CTRL, reg); +} + +static void dac33_hard_power(struct snd_soc_codec *codec, int power) +{ + struct tlv320dac33_priv *dac33 = codec->private_data; + + mutex_lock(&dac33->mutex); + if (power) { + if (dac33->power_gpio >= 0) { + gpio_set_value(dac33->power_gpio, 1); + dac33->chip_power = 1; + /* Restore registers */ + dac33_restore_regs(codec); + } + dac33_soft_power(codec, 1); + } else { + dac33_soft_power(codec, 0); + if (dac33->power_gpio >= 0) { + gpio_set_value(dac33->power_gpio, 0); + dac33->chip_power = 0; + } + } + mutex_unlock(&dac33->mutex); + +} + +static int dac33_get_nsample(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct tlv320dac33_priv *dac33 = codec->private_data; + + ucontrol->value.integer.value[0] = dac33->nsample; + + return 0; +} + +static int dac33_set_nsample(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct tlv320dac33_priv *dac33 = codec->private_data; + int ret = 0; + + if (dac33->nsample == ucontrol->value.integer.value[0]) + return 0; + + if (ucontrol->value.integer.value[0] < dac33->nsample_min || + ucontrol->value.integer.value[0] > dac33->nsample_max) + ret = -EINVAL; + else + dac33->nsample = ucontrol->value.integer.value[0]; + + return ret; +} + +static int dac33_get_nsample_switch(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct tlv320dac33_priv *dac33 = codec->private_data; + + ucontrol->value.integer.value[0] = dac33->nsample_switch; + + return 0; +} + +static int dac33_set_nsample_switch(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct tlv320dac33_priv *dac33 = codec->private_data; + int ret = 0; + + if (dac33->nsample_switch == ucontrol->value.integer.value[0]) + return 0; + /* Do not allow changes while stream is running*/ + if (codec->active) + return -EPERM; + + if (ucontrol->value.integer.value[0] < 0 || + ucontrol->value.integer.value[0] > 1) + ret = -EINVAL; + else + dac33->nsample_switch = ucontrol->value.integer.value[0]; + + return ret; +} + +/* + * DACL/R digital volume control: + * from 0 dB to -63.5 in 0.5 dB steps + * Need to be inverted later on: + * 0x00 == 0 dB + * 0x7f == -63.5 dB + */ +static DECLARE_TLV_DB_SCALE(dac_digivol_tlv, -6350, 50, 0); + +static const struct snd_kcontrol_new dac33_snd_controls[] = { + SOC_DOUBLE_R_TLV("DAC Digital Playback Volume", + DAC33_LDAC_DIG_VOL_CTRL, DAC33_RDAC_DIG_VOL_CTRL, + 0, 0x7f, 1, dac_digivol_tlv), + SOC_DOUBLE_R("DAC Digital Playback Switch", + DAC33_LDAC_DIG_VOL_CTRL, DAC33_RDAC_DIG_VOL_CTRL, 7, 1, 1), + SOC_DOUBLE_R("Line to Line Out Volume", + DAC33_LINEL_TO_LLO_VOL, DAC33_LINER_TO_RLO_VOL, 0, 127, 1), +}; + +static const struct snd_kcontrol_new dac33_nsample_snd_controls[] = { + SOC_SINGLE_EXT("nSample", 0, 0, 5900, 0, + dac33_get_nsample, dac33_set_nsample), + SOC_SINGLE_EXT("nSample Switch", 0, 0, 1, 0, + dac33_get_nsample_switch, dac33_set_nsample_switch), +}; + +/* Analog bypass */ +static const struct snd_kcontrol_new dac33_dapm_abypassl_control = + SOC_DAPM_SINGLE("Switch", DAC33_LINEL_TO_LLO_VOL, 7, 1, 1); + +static const struct snd_kcontrol_new dac33_dapm_abypassr_control = + SOC_DAPM_SINGLE("Switch", DAC33_LINER_TO_RLO_VOL, 7, 1, 1); + +static const struct snd_soc_dapm_widget dac33_dapm_widgets[] = { + SND_SOC_DAPM_OUTPUT("LEFT_LO"), + SND_SOC_DAPM_OUTPUT("RIGHT_LO"), + + SND_SOC_DAPM_INPUT("LINEL"), + SND_SOC_DAPM_INPUT("LINER"), + + SND_SOC_DAPM_DAC("DACL", "Left Playback", DAC33_LDAC_PWR_CTRL, 2, 0), + SND_SOC_DAPM_DAC("DACR", "Right Playback", DAC33_RDAC_PWR_CTRL, 2, 0), + + /* Analog bypass */ + SND_SOC_DAPM_SWITCH("Analog Left Bypass", SND_SOC_NOPM, 0, 0, + &dac33_dapm_abypassl_control), + SND_SOC_DAPM_SWITCH("Analog Right Bypass", SND_SOC_NOPM, 0, 0, + &dac33_dapm_abypassr_control), + + SND_SOC_DAPM_REG(snd_soc_dapm_mixer, "Output Left Amp Power", + DAC33_OUT_AMP_PWR_CTRL, 6, 3, 3, 0), + SND_SOC_DAPM_REG(snd_soc_dapm_mixer, "Output Right Amp Power", + DAC33_OUT_AMP_PWR_CTRL, 4, 3, 3, 0), +}; + +static const struct snd_soc_dapm_route audio_map[] = { + /* Analog bypass */ + {"Analog Left Bypass", "Switch", "LINEL"}, + {"Analog Right Bypass", "Switch", "LINER"}, + + {"Output Left Amp Power", NULL, "DACL"}, + {"Output Right Amp Power", NULL, "DACR"}, + + {"Output Left Amp Power", NULL, "Analog Left Bypass"}, + {"Output Right Amp Power", NULL, "Analog Right Bypass"}, + + /* output */ + {"LEFT_LO", NULL, "Output Left Amp Power"}, + {"RIGHT_LO", NULL, "Output Right Amp Power"}, +}; + +static int dac33_add_widgets(struct snd_soc_codec *codec) +{ + snd_soc_dapm_new_controls(codec, dac33_dapm_widgets, + ARRAY_SIZE(dac33_dapm_widgets)); + + /* set up audio path interconnects */ + snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); + snd_soc_dapm_new_widgets(codec); + + return 0; +} + +static int dac33_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + switch (level) { + case SND_SOC_BIAS_ON: + dac33_soft_power(codec, 1); + break; + case SND_SOC_BIAS_PREPARE: + break; + case SND_SOC_BIAS_STANDBY: + if (codec->bias_level == SND_SOC_BIAS_OFF) + dac33_hard_power(codec, 1); + dac33_soft_power(codec, 0); + break; + case SND_SOC_BIAS_OFF: + dac33_hard_power(codec, 0); + break; + } + codec->bias_level = level; + + return 0; +} + +static void dac33_work(struct work_struct *work) +{ + struct snd_soc_codec *codec; + struct tlv320dac33_priv *dac33; + u8 reg; + + dac33 = container_of(work, struct tlv320dac33_priv, work); + codec = &dac33->codec; + + mutex_lock(&dac33->mutex); + switch (dac33->state) { + case DAC33_PREFILL: + dac33->state = DAC33_PLAYBACK; + dac33_write16(codec, DAC33_NSAMPLE_MSB, + DAC33_THRREG(dac33->nsample)); + dac33_write16(codec, DAC33_PREFILL_MSB, + DAC33_THRREG(dac33->alarm_threshold)); + break; + case DAC33_PLAYBACK: + dac33_write16(codec, DAC33_NSAMPLE_MSB, + DAC33_THRREG(dac33->nsample)); + break; + case DAC33_IDLE: + break; + case DAC33_FLUSH: + dac33->state = DAC33_IDLE; + /* Mask all interrupts from dac33 */ + dac33_write(codec, DAC33_FIFO_IRQ_MASK, 0); + + /* flush fifo */ + reg = dac33_read_reg_cache(codec, DAC33_FIFO_CTRL_A); + reg |= DAC33_FIFOFLUSH; + dac33_write(codec, DAC33_FIFO_CTRL_A, reg); + break; + } + mutex_unlock(&dac33->mutex); +} + +static irqreturn_t dac33_interrupt_handler(int irq, void *dev) +{ + struct snd_soc_codec *codec = dev; + struct tlv320dac33_priv *dac33 = codec->private_data; + + queue_work(dac33->dac33_wq, &dac33->work); + + return IRQ_HANDLED; +} + +static void dac33_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->card->codec; + struct tlv320dac33_priv *dac33 = codec->private_data; + unsigned int pwr_ctrl; + + /* Stop pending workqueue */ + if (dac33->nsample_switch) + cancel_work_sync(&dac33->work); + + mutex_lock(&dac33->mutex); + pwr_ctrl = dac33_read_reg_cache(codec, DAC33_PWR_CTRL); + pwr_ctrl &= ~(DAC33_OSCPDNB | DAC33_DACRPDNB | DAC33_DACLPDNB); + dac33_write(codec, DAC33_PWR_CTRL, pwr_ctrl); + mutex_unlock(&dac33->mutex); +} + +static void dac33_oscwait(struct snd_soc_codec *codec) +{ + int timeout = 20; + u8 reg; + + do { + msleep(1); + dac33_read(codec, DAC33_INT_OSC_STATUS, ®); + } while (((reg & 0x03) != DAC33_OSCSTATUS_NORMAL) && timeout--); + if ((reg & 0x03) != DAC33_OSCSTATUS_NORMAL) + dev_err(codec->dev, + "internal oscillator calibration failed\n"); +} + +static int dac33_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->card->codec; + + /* Check parameters for validity */ + switch (params_rate(params)) { + case 44100: + case 48000: + break; + default: + dev_err(codec->dev, "unsupported rate %d\n", + params_rate(params)); + return -EINVAL; + } + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + break; + default: + dev_err(codec->dev, "unsupported format %d\n", + params_format(params)); + return -EINVAL; + } + + return 0; +} + +#define CALC_OSCSET(rate, refclk) ( \ + ((((rate * 10000) / refclk) * 4096) + 5000) / 10000) +#define CALC_RATIOSET(rate, refclk) ( \ + ((((refclk * 100000) / rate) * 16384) + 50000) / 100000) + +/* + * tlv320dac33 is strict on the sequence of the register writes, if the register + * writes happens in different order, than dac33 might end up in unknown state. + * Use the known, working sequence of register writes to initialize the dac33. + */ +static int dac33_prepare_chip(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->card->codec; + struct tlv320dac33_priv *dac33 = codec->private_data; + unsigned int oscset, ratioset, pwr_ctrl, reg_tmp; + u8 aictrl_a, fifoctrl_a; + + switch (substream->runtime->rate) { + case 44100: + case 48000: + oscset = CALC_OSCSET(substream->runtime->rate, dac33->refclk); + ratioset = CALC_RATIOSET(substream->runtime->rate, + dac33->refclk); + break; + default: + dev_err(codec->dev, "unsupported rate %d\n", + substream->runtime->rate); + return -EINVAL; + } + + + aictrl_a = dac33_read_reg_cache(codec, DAC33_SER_AUDIOIF_CTRL_A); + aictrl_a &= ~(DAC33_NCYCL_MASK | DAC33_WLEN_MASK); + fifoctrl_a = dac33_read_reg_cache(codec, DAC33_FIFO_CTRL_A); + fifoctrl_a &= ~DAC33_WIDTH; + switch (substream->runtime->format) { + case SNDRV_PCM_FORMAT_S16_LE: + aictrl_a |= (DAC33_NCYCL_16 | DAC33_WLEN_16); + fifoctrl_a |= DAC33_WIDTH; + break; + default: + dev_err(codec->dev, "unsupported format %d\n", + substream->runtime->format); + return -EINVAL; + } + + mutex_lock(&dac33->mutex); + dac33_soft_power(codec, 1); + + reg_tmp = dac33_read_reg_cache(codec, DAC33_INT_OSC_CTRL); + dac33_write(codec, DAC33_INT_OSC_CTRL, reg_tmp); + + /* Write registers 0x08 and 0x09 (MSB, LSB) */ + dac33_write16(codec, DAC33_INT_OSC_FREQ_RAT_A, oscset); + + /* calib time: 128 is a nice number ;) */ + dac33_write(codec, DAC33_CALIB_TIME, 128); + + /* adjustment treshold & step */ + dac33_write(codec, DAC33_INT_OSC_CTRL_B, DAC33_ADJTHRSHLD(2) | + DAC33_ADJSTEP(1)); + + /* div=4 / gain=1 / div */ + dac33_write(codec, DAC33_INT_OSC_CTRL_C, DAC33_REFDIV(4)); + + pwr_ctrl = dac33_read_reg_cache(codec, DAC33_PWR_CTRL); + pwr_ctrl |= DAC33_OSCPDNB | DAC33_DACRPDNB | DAC33_DACLPDNB; + dac33_write(codec, DAC33_PWR_CTRL, pwr_ctrl); + + dac33_oscwait(codec); + + if (dac33->nsample_switch) { + /* 50-51 : ASRC Control registers */ + dac33_write(codec, DAC33_ASRC_CTRL_A, (1 << 4)); /* div=2 */ + dac33_write(codec, DAC33_ASRC_CTRL_B, 1); /* ??? */ + + /* Write registers 0x34 and 0x35 (MSB, LSB) */ + dac33_write16(codec, DAC33_SRC_REF_CLK_RATIO_A, ratioset); + + /* Set interrupts to high active */ + dac33_write(codec, DAC33_INTP_CTRL_A, DAC33_INTPM_AHIGH); + + dac33_write(codec, DAC33_FIFO_IRQ_MODE_B, + DAC33_ATM(DAC33_FIFO_IRQ_MODE_LEVEL)); + dac33_write(codec, DAC33_FIFO_IRQ_MASK, DAC33_MAT); + } else { + /* 50-51 : ASRC Control registers */ + dac33_write(codec, DAC33_ASRC_CTRL_A, DAC33_SRCBYP); + dac33_write(codec, DAC33_ASRC_CTRL_B, 0); /* ??? */ + } + + if (dac33->nsample_switch) + fifoctrl_a &= ~DAC33_FBYPAS; + else + fifoctrl_a |= DAC33_FBYPAS; + dac33_write(codec, DAC33_FIFO_CTRL_A, fifoctrl_a); + + dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_A, aictrl_a); + reg_tmp = dac33_read_reg_cache(codec, DAC33_SER_AUDIOIF_CTRL_B); + if (dac33->nsample_switch) + reg_tmp &= ~DAC33_BCLKON; + else + reg_tmp |= DAC33_BCLKON; + dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_B, reg_tmp); + + if (dac33->nsample_switch) { + /* 20: BCLK divide ratio */ + dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_C, 3); + + dac33_write16(codec, DAC33_ATHR_MSB, + DAC33_THRREG(dac33->alarm_threshold)); + } else { + dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_C, 32); + } + + mutex_unlock(&dac33->mutex); + + return 0; +} + +static void dac33_calculate_times(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->card->codec; + struct tlv320dac33_priv *dac33 = codec->private_data; + unsigned int nsample_limit; + + /* Number of samples (16bit, stereo) in one period */ + dac33->nsample_min = snd_pcm_lib_period_bytes(substream) / 4; + + /* Number of samples (16bit, stereo) in ALSA buffer */ + dac33->nsample_max = snd_pcm_lib_buffer_bytes(substream) / 4; + /* Subtract one period from the total */ + dac33->nsample_max -= dac33->nsample_min; + + /* Number of samples for LATENCY_TIME_MS / 2 */ + dac33->alarm_threshold = substream->runtime->rate / + (1000 / (LATENCY_TIME_MS / 2)); + + /* Find and fix up the lowest nsmaple limit */ + nsample_limit = substream->runtime->rate / (1000 / LATENCY_TIME_MS); + + if (dac33->nsample_min < nsample_limit) + dac33->nsample_min = nsample_limit; + + if (dac33->nsample < dac33->nsample_min) + dac33->nsample = dac33->nsample_min; + + /* + * Find and fix up the highest nsmaple limit + * In order to not overflow the DAC33 buffer substract the + * alarm_threshold value from the size of the DAC33 buffer + */ + nsample_limit = DAC33_BUFFER_SIZE_SAMPLES - dac33->alarm_threshold; + + if (dac33->nsample_max > nsample_limit) + dac33->nsample_max = nsample_limit; + + if (dac33->nsample > dac33->nsample_max) + dac33->nsample = dac33->nsample_max; +} + +static int dac33_pcm_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + dac33_calculate_times(substream); + dac33_prepare_chip(substream); + + return 0; +} + +static int dac33_pcm_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->card->codec; + struct tlv320dac33_priv *dac33 = codec->private_data; + int ret = 0; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + if (dac33->nsample_switch) { + dac33->state = DAC33_PREFILL; + queue_work(dac33->dac33_wq, &dac33->work); + } + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + if (dac33->nsample_switch) { + dac33->state = DAC33_FLUSH; + queue_work(dac33->dac33_wq, &dac33->work); + } + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static int dac33_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 tlv320dac33_priv *dac33 = codec->private_data; + u8 ioc_reg, asrcb_reg; + + ioc_reg = dac33_read_reg_cache(codec, DAC33_INT_OSC_CTRL); + asrcb_reg = dac33_read_reg_cache(codec, DAC33_ASRC_CTRL_B); + switch (clk_id) { + case TLV320DAC33_MCLK: + ioc_reg |= DAC33_REFSEL; + asrcb_reg |= DAC33_SRCREFSEL; + break; + case TLV320DAC33_SLEEPCLK: + ioc_reg &= ~DAC33_REFSEL; + asrcb_reg &= ~DAC33_SRCREFSEL; + break; + default: + dev_err(codec->dev, "Invalid clock ID (%d)\n", clk_id); + break; + } + dac33->refclk = freq; + + dac33_write_reg_cache(codec, DAC33_INT_OSC_CTRL, ioc_reg); + dac33_write_reg_cache(codec, DAC33_ASRC_CTRL_B, asrcb_reg); + + return 0; +} + +static int dac33_set_dai_fmt(struct snd_soc_dai *codec_dai, + unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + u8 aictrl_a, aictrl_b; + + aictrl_a = dac33_read_reg_cache(codec, DAC33_SER_AUDIOIF_CTRL_A); + aictrl_b = dac33_read_reg_cache(codec, DAC33_SER_AUDIOIF_CTRL_B); + /* set master/slave audio interface */ + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + /* Codec Master */ + aictrl_a |= (DAC33_MSBCLK | DAC33_MSWCLK); + break; + case SND_SOC_DAIFMT_CBS_CFS: + /* Codec Slave */ + aictrl_a &= ~(DAC33_MSBCLK | DAC33_MSWCLK); + break; + default: + return -EINVAL; + } + + aictrl_a &= ~DAC33_AFMT_MASK; + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + aictrl_a |= DAC33_AFMT_I2S; + break; + case SND_SOC_DAIFMT_DSP_A: + aictrl_a |= DAC33_AFMT_DSP; + aictrl_b &= ~DAC33_DATA_DELAY_MASK; + aictrl_b |= DAC33_DATA_DELAY(1); /* 1 bit delay */ + break; + case SND_SOC_DAIFMT_DSP_B: + aictrl_a |= DAC33_AFMT_DSP; + aictrl_b &= ~DAC33_DATA_DELAY_MASK; /* No delay */ + break; + case SND_SOC_DAIFMT_RIGHT_J: + aictrl_a |= DAC33_AFMT_RIGHT_J; + break; + case SND_SOC_DAIFMT_LEFT_J: + aictrl_a |= DAC33_AFMT_LEFT_J; + break; + default: + dev_err(codec->dev, "Unsupported format (%u)\n", + fmt & SND_SOC_DAIFMT_FORMAT_MASK); + return -EINVAL; + } + + dac33_write_reg_cache(codec, DAC33_SER_AUDIOIF_CTRL_A, aictrl_a); + dac33_write_reg_cache(codec, DAC33_SER_AUDIOIF_CTRL_B, aictrl_b); + + return 0; +} + +static void dac33_init_chip(struct snd_soc_codec *codec) +{ + /* 44-46: DAC Control Registers */ + /* A : DAC sample rate Fsref/1.5 */ + dac33_write(codec, DAC33_DAC_CTRL_A, DAC33_DACRATE(1)); + /* B : DAC src=normal, not muted */ + dac33_write(codec, DAC33_DAC_CTRL_B, DAC33_DACSRCR_RIGHT | + DAC33_DACSRCL_LEFT); + /* C : (defaults) */ + dac33_write(codec, DAC33_DAC_CTRL_C, 0x00); + + /* 64-65 : L&R DAC power control + Line In -> OUT 1V/V Gain, DAC -> OUT 4V/V Gain*/ + dac33_write(codec, DAC33_LDAC_PWR_CTRL, DAC33_LROUT_GAIN(2)); + dac33_write(codec, DAC33_RDAC_PWR_CTRL, DAC33_LROUT_GAIN(2)); + + /* 73 : volume soft stepping control, + clock source = internal osc (?) */ + dac33_write(codec, DAC33_ANA_VOL_SOFT_STEP_CTRL, DAC33_VOLCLKEN); + + /* 66 : LOP/LOM Modes */ + dac33_write(codec, DAC33_OUT_AMP_CM_CTRL, 0xff); + + /* 68 : LOM inverted from LOP */ + dac33_write(codec, DAC33_OUT_AMP_CTRL, (3<<2)); + + dac33_write(codec, DAC33_PWR_CTRL, DAC33_PDNALLB); +} + +static int dac33_soc_probe(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec; + struct tlv320dac33_priv *dac33; + int ret = 0; + + BUG_ON(!tlv320dac33_codec); + + codec = tlv320dac33_codec; + socdev->card->codec = codec; + dac33 = codec->private_data; + + /* Power up the codec */ + dac33_hard_power(codec, 1); + /* Set default configuration */ + dac33_init_chip(codec); + + /* register pcms */ + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) { + dev_err(codec->dev, "failed to create pcms\n"); + goto pcm_err; + } + + snd_soc_add_controls(codec, dac33_snd_controls, + ARRAY_SIZE(dac33_snd_controls)); + /* Only add the nSample controls, if we have valid IRQ number */ + if (dac33->irq >= 0) + snd_soc_add_controls(codec, dac33_nsample_snd_controls, + ARRAY_SIZE(dac33_nsample_snd_controls)); + + dac33_add_widgets(codec); + + /* power on device */ + dac33_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + ret = snd_soc_init_card(socdev); + if (ret < 0) { + dev_err(codec->dev, "failed to register card\n"); + goto card_err; + } + + return 0; +card_err: + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); +pcm_err: + dac33_hard_power(codec, 0); + return ret; +} + +static int dac33_soc_remove(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + + dac33_set_bias_level(codec, SND_SOC_BIAS_OFF); + + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); + + return 0; +} + +static int dac33_soc_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + + dac33_set_bias_level(codec, SND_SOC_BIAS_OFF); + + return 0; +} + +static int dac33_soc_resume(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + + dac33_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + dac33_set_bias_level(codec, codec->suspend_bias_level); + + return 0; +} + +struct snd_soc_codec_device soc_codec_dev_tlv320dac33 = { + .probe = dac33_soc_probe, + .remove = dac33_soc_remove, + .suspend = dac33_soc_suspend, + .resume = dac33_soc_resume, +}; +EXPORT_SYMBOL_GPL(soc_codec_dev_tlv320dac33); + +#define DAC33_RATES (SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_48000) +#define DAC33_FORMATS SNDRV_PCM_FMTBIT_S16_LE + +static struct snd_soc_dai_ops dac33_dai_ops = { + .shutdown = dac33_shutdown, + .hw_params = dac33_hw_params, + .prepare = dac33_pcm_prepare, + .trigger = dac33_pcm_trigger, + .set_sysclk = dac33_set_dai_sysclk, + .set_fmt = dac33_set_dai_fmt, +}; + +struct snd_soc_dai dac33_dai = { + .name = "tlv320dac33", + .playback = { + .stream_name = "Playback", + .channels_min = 2, + .channels_max = 2, + .rates = DAC33_RATES, + .formats = DAC33_FORMATS,}, + .ops = &dac33_dai_ops, +}; +EXPORT_SYMBOL_GPL(dac33_dai); + +static int dac33_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct tlv320dac33_platform_data *pdata; + struct tlv320dac33_priv *dac33; + struct snd_soc_codec *codec; + int ret = 0; + + if (client->dev.platform_data == NULL) { + dev_err(&client->dev, "Platform data not set\n"); + return -ENODEV; + } + pdata = client->dev.platform_data; + + dac33 = kzalloc(sizeof(struct tlv320dac33_priv), GFP_KERNEL); + if (dac33 == NULL) + return -ENOMEM; + + codec = &dac33->codec; + codec->private_data = dac33; + codec->control_data = client; + + mutex_init(&codec->mutex); + mutex_init(&dac33->mutex); + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + + codec->name = "tlv320dac33"; + codec->owner = THIS_MODULE; + codec->read = dac33_read_reg_cache; + codec->write = dac33_write_locked; + codec->hw_write = (hw_write_t) i2c_master_send; + codec->bias_level = SND_SOC_BIAS_OFF; + codec->set_bias_level = dac33_set_bias_level; + codec->dai = &dac33_dai; + codec->num_dai = 1; + codec->reg_cache_size = ARRAY_SIZE(dac33_reg); + codec->reg_cache = kmemdup(dac33_reg, ARRAY_SIZE(dac33_reg), + GFP_KERNEL); + if (codec->reg_cache == NULL) { + ret = -ENOMEM; + goto error_reg; + } + + i2c_set_clientdata(client, dac33); + + dac33->power_gpio = pdata->power_gpio; + dac33->irq = client->irq; + dac33->nsample = NSAMPLE_MAX; + /* Disable FIFO use by default */ + dac33->nsample_switch = 0; + + tlv320dac33_codec = codec; + + codec->dev = &client->dev; + dac33_dai.dev = codec->dev; + + /* Check if the reset GPIO number is valid and request it */ + if (dac33->power_gpio >= 0) { + ret = gpio_request(dac33->power_gpio, "tlv320dac33 reset"); + if (ret < 0) { + dev_err(codec->dev, + "Failed to request reset GPIO (%d)\n", + dac33->power_gpio); + snd_soc_unregister_dai(&dac33_dai); + snd_soc_unregister_codec(codec); + goto error_gpio; + } + gpio_direction_output(dac33->power_gpio, 0); + } else { + dac33->chip_power = 1; + } + + /* Check if the IRQ number is valid and request it */ + if (dac33->irq >= 0) { + ret = request_irq(dac33->irq, dac33_interrupt_handler, + IRQF_TRIGGER_RISING | IRQF_DISABLED, + codec->name, codec); + if (ret < 0) { + dev_err(codec->dev, "Could not request IRQ%d (%d)\n", + dac33->irq, ret); + dac33->irq = -1; + } + if (dac33->irq != -1) { + /* Setup work queue */ + dac33->dac33_wq = create_rt_workqueue("tlv320dac33"); + if (dac33->dac33_wq == NULL) { + free_irq(dac33->irq, &dac33->codec); + ret = -ENOMEM; + goto error_wq; + } + + INIT_WORK(&dac33->work, dac33_work); + } + } + + ret = snd_soc_register_codec(codec); + if (ret != 0) { + dev_err(codec->dev, "Failed to register codec: %d\n", ret); + goto error_codec; + } + + ret = snd_soc_register_dai(&dac33_dai); + if (ret != 0) { + dev_err(codec->dev, "Failed to register DAI: %d\n", ret); + snd_soc_unregister_codec(codec); + goto error_codec; + } + + /* Shut down the codec for now */ + dac33_hard_power(codec, 0); + + return ret; + +error_codec: + if (dac33->irq >= 0) { + free_irq(dac33->irq, &dac33->codec); + destroy_workqueue(dac33->dac33_wq); + } +error_wq: + if (dac33->power_gpio >= 0) + gpio_free(dac33->power_gpio); +error_gpio: + kfree(codec->reg_cache); +error_reg: + tlv320dac33_codec = NULL; + kfree(dac33); + + return ret; +} + +static int dac33_i2c_remove(struct i2c_client *client) +{ + struct tlv320dac33_priv *dac33; + + dac33 = i2c_get_clientdata(client); + dac33_hard_power(&dac33->codec, 0); + + if (dac33->power_gpio >= 0) + gpio_free(dac33->power_gpio); + if (dac33->irq >= 0) + free_irq(dac33->irq, &dac33->codec); + + destroy_workqueue(dac33->dac33_wq); + snd_soc_unregister_dai(&dac33_dai); + snd_soc_unregister_codec(&dac33->codec); + kfree(dac33->codec.reg_cache); + kfree(dac33); + tlv320dac33_codec = NULL; + + return 0; +} + +static const struct i2c_device_id tlv320dac33_i2c_id[] = { + { + .name = "tlv320dac33", + .driver_data = 0, + }, + { }, +}; + +static struct i2c_driver tlv320dac33_i2c_driver = { + .driver = { + .name = "tlv320dac33", + .owner = THIS_MODULE, + }, + .probe = dac33_i2c_probe, + .remove = __devexit_p(dac33_i2c_remove), + .id_table = tlv320dac33_i2c_id, +}; + +static int __init dac33_module_init(void) +{ + int r; + r = i2c_add_driver(&tlv320dac33_i2c_driver); + if (r < 0) { + printk(KERN_ERR "DAC33: driver registration failed\n"); + return r; + } + return 0; +} +module_init(dac33_module_init); + +static void __exit dac33_module_exit(void) +{ + i2c_del_driver(&tlv320dac33_i2c_driver); +} +module_exit(dac33_module_exit); + + +MODULE_DESCRIPTION("ASoC TLV320DAC33 codec driver"); +MODULE_AUTHOR("Peter Ujfalusi "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/tlv320dac33.h b/sound/soc/codecs/tlv320dac33.h new file mode 100644 index 00000000000..0fedd709028 --- /dev/null +++ b/sound/soc/codecs/tlv320dac33.h @@ -0,0 +1,267 @@ +/* + * ALSA SoC Texas Instruments TLV320DAC33 codec driver + * + * Author: Peter Ujfalusi + * + * Copyright: (C) 2009 Nokia Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __TLV320DAC33_H +#define __TLV320DAC33_H + +#define DAC33_PAGE_SELECT 0x00 +#define DAC33_PWR_CTRL 0x01 +#define DAC33_PLL_CTRL_A 0x02 +#define DAC33_PLL_CTRL_B 0x03 +#define DAC33_PLL_CTRL_C 0x04 +#define DAC33_PLL_CTRL_D 0x05 +#define DAC33_PLL_CTRL_E 0x06 +#define DAC33_INT_OSC_CTRL 0x07 +#define DAC33_INT_OSC_FREQ_RAT_A 0x08 +#define DAC33_INT_OSC_FREQ_RAT_B 0x09 +#define DAC33_INT_OSC_DAC_RATIO_SET 0x0A +#define DAC33_CALIB_TIME 0x0B +#define DAC33_INT_OSC_CTRL_B 0x0C +#define DAC33_INT_OSC_CTRL_C 0x0D +#define DAC33_INT_OSC_STATUS 0x0E +#define DAC33_INT_OSC_DAC_RATIO_READ 0x0F +#define DAC33_INT_OSC_FREQ_RAT_READ_A 0x10 +#define DAC33_INT_OSC_FREQ_RAT_READ_B 0x11 +#define DAC33_SER_AUDIOIF_CTRL_A 0x12 +#define DAC33_SER_AUDIOIF_CTRL_B 0x13 +#define DAC33_SER_AUDIOIF_CTRL_C 0x14 +#define DAC33_FIFO_CTRL_A 0x15 +#define DAC33_UTHR_MSB 0x16 +#define DAC33_UTHR_LSB 0x17 +#define DAC33_ATHR_MSB 0x18 +#define DAC33_ATHR_LSB 0x19 +#define DAC33_LTHR_MSB 0x1A +#define DAC33_LTHR_LSB 0x1B +#define DAC33_PREFILL_MSB 0x1C +#define DAC33_PREFILL_LSB 0x1D +#define DAC33_NSAMPLE_MSB 0x1E +#define DAC33_NSAMPLE_LSB 0x1F +#define DAC33_FIFO_WPTR_MSB 0x20 +#define DAC33_FIFO_WPTR_LSB 0x21 +#define DAC33_FIFO_RPTR_MSB 0x22 +#define DAC33_FIFO_RPTR_LSB 0x23 +#define DAC33_FIFO_DEPTH_MSB 0x24 +#define DAC33_FIFO_DEPTH_LSB 0x25 +#define DAC33_SAMPLES_REMAINING_MSB 0x26 +#define DAC33_SAMPLES_REMAINING_LSB 0x27 +#define DAC33_FIFO_IRQ_FLAG 0x28 +#define DAC33_FIFO_IRQ_MASK 0x29 +#define DAC33_FIFO_IRQ_MODE_A 0x2A +#define DAC33_FIFO_IRQ_MODE_B 0x2B +#define DAC33_DAC_CTRL_A 0x2C +#define DAC33_DAC_CTRL_B 0x2D +#define DAC33_DAC_CTRL_C 0x2E +#define DAC33_LDAC_DIG_VOL_CTRL 0x2F +#define DAC33_RDAC_DIG_VOL_CTRL 0x30 +#define DAC33_DAC_STATUS_FLAGS 0x31 +#define DAC33_ASRC_CTRL_A 0x32 +#define DAC33_ASRC_CTRL_B 0x33 +#define DAC33_SRC_REF_CLK_RATIO_A 0x34 +#define DAC33_SRC_REF_CLK_RATIO_B 0x35 +#define DAC33_SRC_EST_REF_CLK_RATIO_A 0x36 +#define DAC33_SRC_EST_REF_CLK_RATIO_B 0x37 +#define DAC33_INTP_CTRL_A 0x38 +#define DAC33_INTP_CTRL_B 0x39 +/* Registers 0x3A - 0x3F Reserved */ +#define DAC33_LDAC_PWR_CTRL 0x40 +#define DAC33_RDAC_PWR_CTRL 0x41 +#define DAC33_OUT_AMP_CM_CTRL 0x42 +#define DAC33_OUT_AMP_PWR_CTRL 0x43 +#define DAC33_OUT_AMP_CTRL 0x44 +#define DAC33_LINEL_TO_LLO_VOL 0x45 +/* Registers 0x45 - 0x47 Reserved */ +#define DAC33_LINER_TO_RLO_VOL 0x48 +#define DAC33_ANA_VOL_SOFT_STEP_CTRL 0x49 +#define DAC33_OSC_TRIM 0x4A +/* Registers 0x4B - 0x7C Reserved */ +#define DAC33_DEVICE_ID_MSB 0x7D +#define DAC33_DEVICE_ID_LSB 0x7E +#define DAC33_DEVICE_REV_ID 0x7F + +#define DAC33_CACHEREGNUM 128 + +/* Bit definitions */ + +/* DAC33_PWR_CTRL (0x01) */ +#define DAC33_DACRPDNB (0x01 << 0) +#define DAC33_DACLPDNB (0x01 << 1) +#define DAC33_OSCPDNB (0x01 << 2) +#define DAC33_PLLPDNB (0x01 << 3) +#define DAC33_PDNALLB (0x01 << 4) +#define DAC33_SOFT_RESET (0x01 << 7) + +/* DAC33_INT_OSC_CTRL (0x07) */ +#define DAC33_REFSEL (0x01 << 1) + +/* DAC33_INT_OSC_CTRL_B (0x0C) */ +#define DAC33_ADJSTEP(x) (x << 0) +#define DAC33_ADJTHRSHLD(x) (x << 4) + +/* DAC33_INT_OSC_CTRL_C (0x0D) */ +#define DAC33_REFDIV(x) (x << 4) + +/* DAC33_INT_OSC_STATUS (0x0E) */ +#define DAC33_OSCSTATUS_IDLE_CALIB (0x00) +#define DAC33_OSCSTATUS_NORMAL (0x01) +#define DAC33_OSCSTATUS_ADJUSTMENT (0x03) +#define DAC33_OSCSTATUS_NOT_USED (0x02) + +/* DAC33_SER_AUDIOIF_CTRL_A (0x12) */ +#define DAC33_MSWCLK (0x01 << 0) +#define DAC33_MSBCLK (0x01 << 1) +#define DAC33_AFMT_MASK (0x03 << 2) +#define DAC33_AFMT_I2S (0x00 << 2) +#define DAC33_AFMT_DSP (0x01 << 2) +#define DAC33_AFMT_RIGHT_J (0x02 << 2) +#define DAC33_AFMT_LEFT_J (0x03 << 2) +#define DAC33_WLEN_MASK (0x03 << 4) +#define DAC33_WLEN_16 (0x00 << 4) +#define DAC33_WLEN_20 (0x01 << 4) +#define DAC33_WLEN_24 (0x02 << 4) +#define DAC33_WLEN_32 (0x03 << 4) +#define DAC33_NCYCL_MASK (0x03 << 6) +#define DAC33_NCYCL_16 (0x00 << 6) +#define DAC33_NCYCL_20 (0x01 << 6) +#define DAC33_NCYCL_24 (0x02 << 6) +#define DAC33_NCYCL_32 (0x03 << 6) + +/* DAC33_SER_AUDIOIF_CTRL_B (0x13) */ +#define DAC33_DATA_DELAY_MASK (0x03 << 2) +#define DAC33_DATA_DELAY(x) (x << 2) +#define DAC33_BCLKON (0x01 << 5) + +/* DAC33_FIFO_CTRL_A (0x15) */ +#define DAC33_WIDTH (0x01 << 0) +#define DAC33_FBYPAS (0x01 << 1) +#define DAC33_FAUTO (0x01 << 2) +#define DAC33_FIFOFLUSH (0x01 << 3) + +/* + * UTHR, ATHR, LTHR, PREFILL, NSAMPLE (0x16 - 0x1F) + * 13-bit values +*/ +#define DAC33_THRREG(x) (((x) & 0x1FFF) << 3) + +/* DAC33_FIFO_IRQ_MASK (0x29) */ +#define DAC33_MNS (0x01 << 0) +#define DAC33_MPS (0x01 << 1) +#define DAC33_MAT (0x01 << 2) +#define DAC33_MLT (0x01 << 3) +#define DAC33_MUT (0x01 << 4) +#define DAC33_MUF (0x01 << 5) +#define DAC33_MOF (0x01 << 6) + +#define DAC33_FIFO_IRQ_MODE_MASK (0x03) +#define DAC33_FIFO_IRQ_MODE_RISING (0x00) +#define DAC33_FIFO_IRQ_MODE_FALLING (0x01) +#define DAC33_FIFO_IRQ_MODE_LEVEL (0x02) +#define DAC33_FIFO_IRQ_MODE_EDGE (0x03) + +/* DAC33_FIFO_IRQ_MODE_A (0x2A) */ +#define DAC33_UTM(x) (x << 0) +#define DAC33_UFM(x) (x << 2) +#define DAC33_OFM(x) (x << 4) + +/* DAC33_FIFO_IRQ_MODE_B (0x2B) */ +#define DAC33_NSM(x) (x << 0) +#define DAC33_PSM(x) (x << 2) +#define DAC33_ATM(x) (x << 4) +#define DAC33_LTM(x) (x << 4) + +/* DAC33_DAC_CTRL_A (0x2C) */ +#define DAC33_DACRATE(x) (x << 0) +#define DAC33_DACDUAL (0x01 << 4) +#define DAC33_DACLKSEL_MASK (0x03 << 5) +#define DAC33_DACLKSEL_INTSOC (0x00 << 5) +#define DAC33_DACLKSEL_PLL (0x01 << 5) +#define DAC33_DACLKSEL_MCLK (0x02 << 5) +#define DAC33_DACLKSEL_BCLK (0x03 << 5) + +/* DAC33_DAC_CTRL_B (0x2D) */ +#define DAC33_DACSRCR_MASK (0x03 << 0) +#define DAC33_DACSRCR_MUTE (0x00 << 0) +#define DAC33_DACSRCR_RIGHT (0x01 << 0) +#define DAC33_DACSRCR_LEFT (0x02 << 0) +#define DAC33_DACSRCR_MONOMIX (0x03 << 0) +#define DAC33_DACSRCL_MASK (0x03 << 2) +#define DAC33_DACSRCL_MUTE (0x00 << 2) +#define DAC33_DACSRCL_LEFT (0x01 << 2) +#define DAC33_DACSRCL_RIGHT (0x02 << 2) +#define DAC33_DACSRCL_MONOMIX (0x03 << 2) +#define DAC33_DVOLSTEP_MASK (0x03 << 4) +#define DAC33_DVOLSTEP_SS_PERFS (0x00 << 4) +#define DAC33_DVOLSTEP_SS_PER2FS (0x01 << 4) +#define DAC33_DVOLSTEP_SS_DISABLED (0x02 << 4) +#define DAC33_DVOLCTRL_MASK (0x03 << 6) +#define DAC33_DVOLCTRL_LR_INDEPENDENT1 (0x00 << 6) +#define DAC33_DVOLCTRL_LR_RIGHT_CONTROL (0x01 << 6) +#define DAC33_DVOLCTRL_LR_LEFT_CONTROL (0x02 << 6) +#define DAC33_DVOLCTRL_LR_INDEPENDENT2 (0x03 << 6) + +/* DAC33_DAC_CTRL_C (0x2E) */ +#define DAC33_DEEMENR (0x01 << 0) +#define DAC33_EFFENR (0x01 << 1) +#define DAC33_DEEMENL (0x01 << 2) +#define DAC33_EFFENL (0x01 << 3) +#define DAC33_EN3D (0x01 << 4) +#define DAC33_RESYNMUTE (0x01 << 5) +#define DAC33_RESYNEN (0x01 << 6) + +/* DAC33_ASRC_CTRL_A (0x32) */ +#define DAC33_SRCBYP (0x01 << 0) +#define DAC33_SRCLKSEL_MASK (0x03 << 1) +#define DAC33_SRCLKSEL_INTSOC (0x00 << 1) +#define DAC33_SRCLKSEL_PLL (0x01 << 1) +#define DAC33_SRCLKSEL_MCLK (0x02 << 1) +#define DAC33_SRCLKSEL_BCLK (0x03 << 1) +#define DAC33_SRCLKDIV(x) (x << 3) + +/* DAC33_ASRC_CTRL_B (0x33) */ +#define DAC33_SRCSETUP(x) (x << 0) +#define DAC33_SRCREFSEL (0x01 << 4) +#define DAC33_SRCREFDIV(x) (x << 5) + +/* DAC33_INTP_CTRL_A (0x38) */ +#define DAC33_INTPSEL (0x01 << 0) +#define DAC33_INTPM_MASK (0x03 << 1) +#define DAC33_INTPM_ALOW_OPENDRAIN (0x00 << 1) +#define DAC33_INTPM_ALOW (0x01 << 1) +#define DAC33_INTPM_AHIGH (0x02 << 1) + +/* DAC33_LDAC_PWR_CTRL (0x40) */ +/* DAC33_RDAC_PWR_CTRL (0x41) */ +#define DAC33_DACLRNUM (0x01 << 2) +#define DAC33_LROUT_GAIN(x) (x << 0) + +/* DAC33_ANA_VOL_SOFT_STEP_CTRL (0x49) */ +#define DAC33_VOLCLKSEL (0x01 << 0) +#define DAC33_VOLCLKEN (0x01 << 1) +#define DAC33_VOLBYPASS (0x01 << 2) + +#define TLV320DAC33_MCLK 0 +#define TLV320DAC33_SLEEPCLK 1 + +extern struct snd_soc_dai dac33_dai; +extern struct snd_soc_codec_device soc_codec_dev_tlv320dac33; + +#endif /* __TLV320DAC33_H */ -- cgit v1.2.3 From d8707cecdf396bdb506252829d03837b2c67c939 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 19 Oct 2009 15:42:19 +0300 Subject: ASoC: TWL4030: Only update the needed bits in *set_dai_sysclk Do not rewrite the whole register, but only update the needed bits in set_dai_sysclk functions. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 4df7c6c61c7..559e9b27928 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -1785,19 +1785,21 @@ static int twl4030_set_dai_sysclk(struct snd_soc_dai *codec_dai, { struct snd_soc_codec *codec = codec_dai->codec; struct twl4030_priv *twl4030 = codec->private_data; - u8 infreq; + u8 apll_ctrl; + apll_ctrl = twl4030_read_reg_cache(codec, TWL4030_REG_APLL_CTL); + apll_ctrl &= ~TWL4030_APLL_INFREQ; switch (freq) { case 19200000: - infreq = TWL4030_APLL_INFREQ_19200KHZ; + apll_ctrl |= TWL4030_APLL_INFREQ_19200KHZ; twl4030->sysclk = 19200; break; case 26000000: - infreq = TWL4030_APLL_INFREQ_26000KHZ; + apll_ctrl |= TWL4030_APLL_INFREQ_26000KHZ; twl4030->sysclk = 26000; break; case 38400000: - infreq = TWL4030_APLL_INFREQ_38400KHZ; + apll_ctrl |= TWL4030_APLL_INFREQ_38400KHZ; twl4030->sysclk = 38400; break; default: @@ -1806,8 +1808,7 @@ static int twl4030_set_dai_sysclk(struct snd_soc_dai *codec_dai, return -EINVAL; } - infreq |= TWL4030_APLL_EN; - twl4030_write(codec, TWL4030_REG_APLL_CTL, infreq); + twl4030_write(codec, TWL4030_REG_APLL_CTL, apll_ctrl); return 0; } @@ -1989,11 +1990,13 @@ static int twl4030_voice_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; - u8 infreq; + u8 apll_ctrl; + apll_ctrl = twl4030_read_reg_cache(codec, TWL4030_REG_APLL_CTL); + apll_ctrl &= ~TWL4030_APLL_INFREQ; switch (freq) { case 26000000: - infreq = TWL4030_APLL_INFREQ_26000KHZ; + apll_ctrl |= TWL4030_APLL_INFREQ_26000KHZ; break; default: printk(KERN_ERR "TWL4030 voice set sysclk: unknown rate %d\n", @@ -2001,8 +2004,7 @@ static int twl4030_voice_set_dai_sysclk(struct snd_soc_dai *codec_dai, return -EINVAL; } - infreq |= TWL4030_APLL_EN; - twl4030_write(codec, TWL4030_REG_APLL_CTL, infreq); + twl4030_write(codec, TWL4030_REG_APLL_CTL, apll_ctrl); return 0; } -- cgit v1.2.3 From e697cd410a0c3aaea697c9915837e99933d8935b Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Mon, 19 Oct 2009 16:10:58 +0200 Subject: ASoC: au1x: psc-ac97: verify correct codec register was read Verify that the correct register has been received from the codec. Signed-off-by: Manuel Lauss Signed-off-by: Mark Brown --- sound/soc/au1x/psc-ac97.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c index a521aa90dde..efe2afd4fe2 100644 --- a/sound/soc/au1x/psc-ac97.c +++ b/sound/soc/au1x/psc-ac97.c @@ -61,7 +61,8 @@ static unsigned short au1xpsc_ac97_read(struct snd_ac97 *ac97, { /* FIXME */ struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata; - unsigned short data, retry, tmo; + unsigned short retry, tmo; + unsigned long data; au_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata)); au_sync(); @@ -79,15 +80,19 @@ static unsigned short au1xpsc_ac97_read(struct snd_ac97 *ac97, && --tmo) udelay(2); - data = au_readl(AC97_CDC(pscdata)) & 0xffff; + data = au_readl(AC97_CDC(pscdata)); au_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata)); au_sync(); mutex_unlock(&pscdata->lock); + + if (reg != ((data >> 16) & 0x7f)) + tmo = 1; /* wrong register, try again */ + } while (--retry && !tmo); - return retry ? data : 0xffff; + return retry ? data & 0xffff : 0xffff; } /* AC97 controller writes to codec register */ -- cgit v1.2.3 From 8d567b6b441bfcc20e8cbebc0dc376b2e280cd88 Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Mon, 19 Oct 2009 16:10:59 +0200 Subject: ASoC: au1x: psc-ac97: reorganize timeouts Codec read/write functions: wait 21us between the pokings of hardware. Add timeouts to unbounded loops waiting for bits to change. Signed-off-by: Manuel Lauss Signed-off-by: Mark Brown --- sound/soc/au1x/psc-ac97.c | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) (limited to 'sound') diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c index efe2afd4fe2..2a06a9c548a 100644 --- a/sound/soc/au1x/psc-ac97.c +++ b/sound/soc/au1x/psc-ac97.c @@ -75,10 +75,12 @@ static unsigned short au1xpsc_ac97_read(struct snd_ac97 *ac97, AC97_CDC(pscdata)); au_sync(); - tmo = 2000; - while ((!(au_readl(AC97_EVNT(pscdata)) & PSC_AC97EVNT_CD)) - && --tmo) - udelay(2); + tmo = 20; + do { + udelay(21); + if (au_readl(AC97_EVNT(pscdata)) & PSC_AC97EVNT_CD) + break; + } while (--tmo); data = au_readl(AC97_CDC(pscdata)); @@ -114,10 +116,12 @@ static void au1xpsc_ac97_write(struct snd_ac97 *ac97, unsigned short reg, AC97_CDC(pscdata)); au_sync(); - tmo = 2000; - while ((!(au_readl(AC97_EVNT(pscdata)) & PSC_AC97EVNT_CD)) - && --tmo) - udelay(2); + tmo = 20; + do { + udelay(21); + if (au_readl(AC97_EVNT(pscdata)) & PSC_AC97EVNT_CD) + break; + } while (--tmo); au_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata)); au_sync(); @@ -200,7 +204,7 @@ static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream, /* FIXME */ struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata; unsigned long r, ro, stat; - int chans, stype = SUBSTREAM_TYPE(substream); + int chans, t, stype = SUBSTREAM_TYPE(substream); chans = params_channels(params); @@ -242,8 +246,12 @@ static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream, au_sync(); /* ...wait for it... */ - while (au_readl(AC97_STAT(pscdata)) & PSC_AC97STAT_DR) - asm volatile ("nop"); + t = 100; + while ((au_readl(AC97_STAT(pscdata)) & PSC_AC97STAT_DR) && --t) + msleep(1); + + if (!t) + printk(KERN_ERR "PSC-AC97: can't disable!\n"); /* ...write config... */ au_writel(r, AC97_CFG(pscdata)); @@ -254,8 +262,12 @@ static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream, au_sync(); /* ...and wait for ready bit */ - while (!(au_readl(AC97_STAT(pscdata)) & PSC_AC97STAT_DR)) - asm volatile ("nop"); + t = 100; + while ((!(au_readl(AC97_STAT(pscdata)) & PSC_AC97STAT_DR)) && --t) + msleep(1); + + if (!t) + printk(KERN_ERR "PSC-AC97: can't enable!\n"); mutex_unlock(&pscdata->lock); -- cgit v1.2.3 From 4f066173fe8deb8874f41917e5d26ea2e0c46e3b Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 17 Oct 2009 08:32:56 +0200 Subject: ASoC: Move dereference after NULL test If the NULL test on jack is needed, then the derefernce should be after the NULL test. A simplified version of the semantic match that detects this problem is as follows (http://coccinelle.lip6.fr/): // @match exists@ expression x, E; identifier fld; @@ * x->fld ... when != \(x = E\|&x\) * x == NULL // Signed-off-by: Julia Lawall Signed-off-by: Mark Brown --- sound/soc/soc-jack.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c index 1d455ab7949..12124149601 100644 --- a/sound/soc/soc-jack.c +++ b/sound/soc/soc-jack.c @@ -58,7 +58,7 @@ EXPORT_SYMBOL_GPL(snd_soc_jack_new); */ void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask) { - struct snd_soc_codec *codec = jack->card->codec; + struct snd_soc_codec *codec; struct snd_soc_jack_pin *pin; int enable; int oldstatus; @@ -67,6 +67,7 @@ void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask) WARN_ON_ONCE(!jack); return; } + codec = jack->card->codec; mutex_lock(&codec->mutex); -- cgit v1.2.3 From 02a06d3042e208cb74369838b178ca9512192be4 Mon Sep 17 00:00:00 2001 From: Barry Song <21cnbao@gmail.com> Date: Fri, 16 Oct 2009 18:13:38 +0800 Subject: ASoC: Fix possible codec_dai->ops NULL pointer problems Some codec DAIs like stac9766, wm9712, wm9713, ad1980 don't register themselves then it loses to the chance to be given a null_dai_ops in snd_soc_register_dai if they have no ops. When functions like soc_pcm_open, soc_pcm_hw_params etc. access the ops field in these DAIs, panic will happen. Signed-off-by: Barry Song <21cnbao@gmail.com> Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 7ff04ad2a97..0a1b2f64bbe 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -834,6 +834,9 @@ EXPORT_SYMBOL_GPL(snd_soc_resume_device); #define soc_resume NULL #endif +static struct snd_soc_dai_ops null_dai_ops = { +}; + static void snd_soc_instantiate_card(struct snd_soc_card *card) { struct platform_device *pdev = container_of(card->dev, @@ -877,6 +880,11 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card) ac97 = 1; } + for (i = 0; i < card->num_links; i++) { + if (!card->dai_link[i].codec_dai->ops) + card->dai_link[i].codec_dai->ops = &null_dai_ops; + } + /* If we have AC97 in the system then don't wait for the * codec. This will need revisiting if we have to handle * systems with mixed AC97 and non-AC97 parts. Only check for @@ -2329,9 +2337,6 @@ static int snd_soc_unregister_card(struct snd_soc_card *card) return 0; } -static struct snd_soc_dai_ops null_dai_ops = { -}; - /** * snd_soc_register_dai - Register a DAI with the ASoC core * -- cgit v1.2.3 From ce491cf85466c3377228c5a852ea627ec5136956 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Tue, 20 Oct 2009 09:40:47 -0700 Subject: omap: headers: Move remaining headers from include/mach to include/plat Move the remaining headers under plat-omap/include/mach to plat-omap/include/plat. Also search and replace the files using these headers to include using the right path. This was done with: #!/bin/bash mach_dir_old="arch/arm/plat-omap/include/mach" plat_dir_new="arch/arm/plat-omap/include/plat" headers=$(cd $mach_dir_old && ls *.h) omap_dirs="arch/arm/*omap*/ \ drivers/video/omap \ sound/soc/omap" other_files="drivers/leds/leds-ams-delta.c \ drivers/mfd/menelaus.c \ drivers/mfd/twl4030-core.c \ drivers/mtd/nand/ams-delta.c" for header in $headers; do old="#include --- sound/soc/omap/ams-delta.c | 4 ++-- sound/soc/omap/n810.c | 2 +- sound/soc/omap/omap-mcbsp.c | 6 +++--- sound/soc/omap/omap-pcm.c | 2 +- sound/soc/omap/omap2evm.c | 2 +- sound/soc/omap/omap3beagle.c | 2 +- sound/soc/omap/omap3evm.c | 2 +- sound/soc/omap/osk5912.c | 2 +- sound/soc/omap/overo.c | 2 +- sound/soc/omap/sdp3430.c | 2 +- sound/soc/omap/zoom2.c | 2 +- 11 files changed, 14 insertions(+), 14 deletions(-) (limited to 'sound') diff --git a/sound/soc/omap/ams-delta.c b/sound/soc/omap/ams-delta.c index 5a5166ac727..3f1a6c1a035 100644 --- a/sound/soc/omap/ams-delta.c +++ b/sound/soc/omap/ams-delta.c @@ -31,8 +31,8 @@ #include -#include -#include +#include +#include #include "omap-mcbsp.h" #include "omap-pcm.h" diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c index 0a505938e42..08e09d72790 100644 --- a/sound/soc/omap/n810.c +++ b/sound/soc/omap/n810.c @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include "omap-mcbsp.h" #include "omap-pcm.h" diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index 3341f49402c..e8e63ba4087 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -31,9 +31,9 @@ #include #include -#include -#include -#include +#include +#include +#include #include "omap-mcbsp.h" #include "omap-pcm.h" diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c index 5735945788b..1169d2ec2e2 100644 --- a/sound/soc/omap/omap-pcm.c +++ b/sound/soc/omap/omap-pcm.c @@ -28,7 +28,7 @@ #include #include -#include +#include #include "omap-pcm.h" static const struct snd_pcm_hardware omap_pcm_hardware = { diff --git a/sound/soc/omap/omap2evm.c b/sound/soc/omap/omap2evm.c index 027e1a40f8a..c7adea38274 100644 --- a/sound/soc/omap/omap2evm.c +++ b/sound/soc/omap/omap2evm.c @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include "omap-mcbsp.h" #include "omap-pcm.h" diff --git a/sound/soc/omap/omap3beagle.c b/sound/soc/omap/omap3beagle.c index b0cff9f33b7..d88ad5ca526 100644 --- a/sound/soc/omap/omap3beagle.c +++ b/sound/soc/omap/omap3beagle.c @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include "omap-mcbsp.h" #include "omap-pcm.h" diff --git a/sound/soc/omap/omap3evm.c b/sound/soc/omap/omap3evm.c index 9114c263077..41a91b5cf12 100644 --- a/sound/soc/omap/omap3evm.c +++ b/sound/soc/omap/omap3evm.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include "omap-mcbsp.h" #include "omap-pcm.h" diff --git a/sound/soc/omap/osk5912.c b/sound/soc/omap/osk5912.c index a4e149b7f0e..498ca2e0351 100644 --- a/sound/soc/omap/osk5912.c +++ b/sound/soc/omap/osk5912.c @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include "omap-mcbsp.h" #include "omap-pcm.h" diff --git a/sound/soc/omap/overo.c b/sound/soc/omap/overo.c index ec4f8fd8b3a..624f40ecc47 100644 --- a/sound/soc/omap/overo.c +++ b/sound/soc/omap/overo.c @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include "omap-mcbsp.h" #include "omap-pcm.h" diff --git a/sound/soc/omap/sdp3430.c b/sound/soc/omap/sdp3430.c index 4a3f62d1f29..c071f9603a3 100644 --- a/sound/soc/omap/sdp3430.c +++ b/sound/soc/omap/sdp3430.c @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include "omap-mcbsp.h" #include "omap-pcm.h" diff --git a/sound/soc/omap/zoom2.c b/sound/soc/omap/zoom2.c index f90b45f5622..f90a2ac888c 100644 --- a/sound/soc/omap/zoom2.c +++ b/sound/soc/omap/zoom2.c @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include "omap-mcbsp.h" #include "omap-pcm.h" -- cgit v1.2.3 From 02624621a58d7030e0e56f1e3df490202e59056c Mon Sep 17 00:00:00 2001 From: Janusz Krzysztofik Date: Wed, 21 Oct 2009 04:40:55 +0200 Subject: ASoC: Amstrad Delta minor cleanups Hi Mark, Here is a patch that corrects small omissions I have found in my code. Signed-off-by: Janusz Krzysztofik Signed-off-by: Mark Brown --- sound/soc/omap/ams-delta.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/omap/ams-delta.c b/sound/soc/omap/ams-delta.c index 5a5166ac727..ae0fc9b135d 100644 --- a/sound/soc/omap/ams-delta.c +++ b/sound/soc/omap/ams-delta.c @@ -40,7 +40,7 @@ /* Board specific DAPM widgets */ - const struct snd_soc_dapm_widget ams_delta_dapm_widgets[] = { +static const struct snd_soc_dapm_widget ams_delta_dapm_widgets[] = { /* Handset */ SND_SOC_DAPM_MIC("Mouthpiece", NULL), SND_SOC_DAPM_HP("Earpiece", NULL), @@ -81,7 +81,7 @@ static const char *ams_delta_audio_mode[] = (1 << AMS_DELTA_SPEAKER)) #define AMS_DELTA_SPEAKERPHONE (AMS_DELTA_HANDSFREE | (1 << AMS_DELTA_AGC)) -unsigned short ams_delta_audio_mode_pins[] = { +static const unsigned short ams_delta_audio_mode_pins[] = { AMS_DELTA_MIXED, AMS_DELTA_HANDSET, AMS_DELTA_HANDSFREE, -- cgit v1.2.3 From 017deee63934349a70292666acfedea8e6eb6eb8 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 21 Oct 2009 09:58:35 +0300 Subject: ASoC: tlv320dac33: typo fix in the header Fix the definition of DAC33_LTM field, the LTM bits in FIFO_IRQ_MODE_B register are starting at bit 6. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320dac33.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/tlv320dac33.h b/sound/soc/codecs/tlv320dac33.h index 0fedd709028..eb8ae07f0bd 100644 --- a/sound/soc/codecs/tlv320dac33.h +++ b/sound/soc/codecs/tlv320dac33.h @@ -186,7 +186,7 @@ #define DAC33_NSM(x) (x << 0) #define DAC33_PSM(x) (x << 2) #define DAC33_ATM(x) (x << 4) -#define DAC33_LTM(x) (x << 4) +#define DAC33_LTM(x) (x << 6) /* DAC33_DAC_CTRL_A (0x2C) */ #define DAC33_DACRATE(x) (x << 0) -- cgit v1.2.3 From 0ffc11800cb2a74b05c2f5b28966ebd50b27f70c Mon Sep 17 00:00:00 2001 From: Janusz Krzysztofik Date: Wed, 21 Oct 2009 23:10:03 +0200 Subject: ASoC: OMAP: Don't try to set unsupported OMAP_DMA_DATA_BURST_16 on OMAP1 After DMA burst mode has been introduced in sound/soc/omap/omap-pcm.c, omap_pcm_prepare() unconditionally calls: omap_set_dma_src_burst_mode(prtd->dma_ch, OMAP_DMA_DATA_BURST_16); omap_set_dma_dest_burst_mode(prtd->dma_ch, OMAP_DMA_DATA_BURST_16); Current implementation of those two functions found in arch/arm/plat-ompa/dma.c doesn't support OMAP_DMA_DATA_BURST_16 on OMAP1 at all, so they both end with BUG() on that machine. That results in ASoC being completely unusable, at least on my OMAP5910 based Amstrad Delta. The patch corrects the problem by not calling those two functions when run on OMAP1 class based machines. Created against linux-2.6.32-rc5. Tested on Amstrad Delta. Signed-off-by: Janusz Krzysztofik Acked-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/omap/omap-pcm.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c index 5735945788b..6a829eef2a4 100644 --- a/sound/soc/omap/omap-pcm.c +++ b/sound/soc/omap/omap-pcm.c @@ -195,8 +195,12 @@ static int omap_pcm_prepare(struct snd_pcm_substream *substream) else omap_enable_dma_irq(prtd->dma_ch, OMAP_DMA_FRAME_IRQ); - omap_set_dma_src_burst_mode(prtd->dma_ch, OMAP_DMA_DATA_BURST_16); - omap_set_dma_dest_burst_mode(prtd->dma_ch, OMAP_DMA_DATA_BURST_16); + if (!(cpu_class_is_omap1())) { + omap_set_dma_src_burst_mode(prtd->dma_ch, + OMAP_DMA_DATA_BURST_16); + omap_set_dma_dest_burst_mode(prtd->dma_ch, + OMAP_DMA_DATA_BURST_16); + } return 0; } -- cgit v1.2.3 From b214f11fb92713fbb07d8c1f62dd1aa8077b56c9 Mon Sep 17 00:00:00 2001 From: Janusz Krzysztofik Date: Sat, 24 Oct 2009 00:06:48 +0200 Subject: ASoC: Amstrad Delta: add info about the line discipline requirement to Kconfig help text I thought it could be usefull to add some information on how to get the device fully supported by loading a line discipline on the modem line. Signed-off-by: Janusz Krzysztofik Signed-off-by: Mark Brown --- sound/soc/omap/Kconfig | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index 2dee9839be8..653a362425d 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig @@ -21,7 +21,18 @@ config SND_OMAP_SOC_AMS_DELTA select SND_OMAP_SOC_MCBSP select SND_SOC_CX20442 help - Say Y if you want to add support for SoC audio on Amstrad Delta. + Say Y if you want to add support for SoC audio device connected to + a handset and a speakerphone found on Amstrad E3 (Delta) videophone. + + Note that in order to get those devices fully supported, you have to + build the kernel with standard serial port driver included and + configured for at least 4 ports. Then, from userspace, you must load + a line discipline #19 on the modem (ttyS3) serial line. The simplest + way to achieve this is to install util-linux-ng and use the included + ldattach utility. This can be started automatically from udev, + a simple rule like this one should do the trick (it does for me): + ACTION=="add", KERNEL=="controlC0", \ + RUN+="/usr/sbin/ldattach 19 /dev/ttyS3" config SND_OMAP_SOC_OSK5912 tristate "SoC Audio support for omap osk5912" -- cgit v1.2.3 From 1f0f9b67f98a873fca8288ccb7f2a0f3c8f34371 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 22 Oct 2009 13:26:47 +0300 Subject: ASoC: TWL4030: use the twl4030-codec.h for register descriptions Remove the register descriptions from the twl4030.h file and use the linux/mfd/twl4030-codec.h instead, which has the codec related register descriptions also. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.h | 242 ++------------------------------------------- 1 file changed, 6 insertions(+), 236 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/twl4030.h b/sound/soc/codecs/twl4030.h index 2b4bfa23f98..dd6396ec9c7 100644 --- a/sound/soc/codecs/twl4030.h +++ b/sound/soc/codecs/twl4030.h @@ -22,245 +22,13 @@ #ifndef __TWL4030_AUDIO_H__ #define __TWL4030_AUDIO_H__ -#define TWL4030_REG_CODEC_MODE 0x1 -#define TWL4030_REG_OPTION 0x2 -#define TWL4030_REG_UNKNOWN 0x3 -#define TWL4030_REG_MICBIAS_CTL 0x4 -#define TWL4030_REG_ANAMICL 0x5 -#define TWL4030_REG_ANAMICR 0x6 -#define TWL4030_REG_AVADC_CTL 0x7 -#define TWL4030_REG_ADCMICSEL 0x8 -#define TWL4030_REG_DIGMIXING 0x9 -#define TWL4030_REG_ATXL1PGA 0xA -#define TWL4030_REG_ATXR1PGA 0xB -#define TWL4030_REG_AVTXL2PGA 0xC -#define TWL4030_REG_AVTXR2PGA 0xD -#define TWL4030_REG_AUDIO_IF 0xE -#define TWL4030_REG_VOICE_IF 0xF -#define TWL4030_REG_ARXR1PGA 0x10 -#define TWL4030_REG_ARXL1PGA 0x11 -#define TWL4030_REG_ARXR2PGA 0x12 -#define TWL4030_REG_ARXL2PGA 0x13 -#define TWL4030_REG_VRXPGA 0x14 -#define TWL4030_REG_VSTPGA 0x15 -#define TWL4030_REG_VRX2ARXPGA 0x16 -#define TWL4030_REG_AVDAC_CTL 0x17 -#define TWL4030_REG_ARX2VTXPGA 0x18 -#define TWL4030_REG_ARXL1_APGA_CTL 0x19 -#define TWL4030_REG_ARXR1_APGA_CTL 0x1A -#define TWL4030_REG_ARXL2_APGA_CTL 0x1B -#define TWL4030_REG_ARXR2_APGA_CTL 0x1C -#define TWL4030_REG_ATX2ARXPGA 0x1D -#define TWL4030_REG_BT_IF 0x1E -#define TWL4030_REG_BTPGA 0x1F -#define TWL4030_REG_BTSTPGA 0x20 -#define TWL4030_REG_EAR_CTL 0x21 -#define TWL4030_REG_HS_SEL 0x22 -#define TWL4030_REG_HS_GAIN_SET 0x23 -#define TWL4030_REG_HS_POPN_SET 0x24 -#define TWL4030_REG_PREDL_CTL 0x25 -#define TWL4030_REG_PREDR_CTL 0x26 -#define TWL4030_REG_PRECKL_CTL 0x27 -#define TWL4030_REG_PRECKR_CTL 0x28 -#define TWL4030_REG_HFL_CTL 0x29 -#define TWL4030_REG_HFR_CTL 0x2A -#define TWL4030_REG_ALC_CTL 0x2B -#define TWL4030_REG_ALC_SET1 0x2C -#define TWL4030_REG_ALC_SET2 0x2D -#define TWL4030_REG_BOOST_CTL 0x2E -#define TWL4030_REG_SOFTVOL_CTL 0x2F -#define TWL4030_REG_DTMF_FREQSEL 0x30 -#define TWL4030_REG_DTMF_TONEXT1H 0x31 -#define TWL4030_REG_DTMF_TONEXT1L 0x32 -#define TWL4030_REG_DTMF_TONEXT2H 0x33 -#define TWL4030_REG_DTMF_TONEXT2L 0x34 -#define TWL4030_REG_DTMF_TONOFF 0x35 -#define TWL4030_REG_DTMF_WANONOFF 0x36 -#define TWL4030_REG_I2S_RX_SCRAMBLE_H 0x37 -#define TWL4030_REG_I2S_RX_SCRAMBLE_M 0x38 -#define TWL4030_REG_I2S_RX_SCRAMBLE_L 0x39 -#define TWL4030_REG_APLL_CTL 0x3A -#define TWL4030_REG_DTMF_CTL 0x3B -#define TWL4030_REG_DTMF_PGA_CTL2 0x3C -#define TWL4030_REG_DTMF_PGA_CTL1 0x3D -#define TWL4030_REG_MISC_SET_1 0x3E -#define TWL4030_REG_PCMBTMUX 0x3F -#define TWL4030_REG_RX_PATH_SEL 0x43 -#define TWL4030_REG_VDL_APGA_CTL 0x44 -#define TWL4030_REG_VIBRA_CTL 0x45 -#define TWL4030_REG_VIBRA_SET 0x46 -#define TWL4030_REG_VIBRA_PWM_SET 0x47 -#define TWL4030_REG_ANAMIC_GAIN 0x48 -#define TWL4030_REG_MISC_SET_2 0x49 -#define TWL4030_REG_SW_SHADOW 0x4A +/* Register descriptions are here */ +#include +/* Sgadow register used by the audio driver */ +#define TWL4030_REG_SW_SHADOW 0x4A #define TWL4030_CACHEREGNUM (TWL4030_REG_SW_SHADOW + 1) -/* Bitfield Definitions */ - -/* TWL4030_CODEC_MODE (0x01) Fields */ - -#define TWL4030_APLL_RATE 0xF0 -#define TWL4030_APLL_RATE_8000 0x00 -#define TWL4030_APLL_RATE_11025 0x10 -#define TWL4030_APLL_RATE_12000 0x20 -#define TWL4030_APLL_RATE_16000 0x40 -#define TWL4030_APLL_RATE_22050 0x50 -#define TWL4030_APLL_RATE_24000 0x60 -#define TWL4030_APLL_RATE_32000 0x80 -#define TWL4030_APLL_RATE_44100 0x90 -#define TWL4030_APLL_RATE_48000 0xA0 -#define TWL4030_APLL_RATE_96000 0xE0 -#define TWL4030_SEL_16K 0x08 -#define TWL4030_CODECPDZ 0x02 -#define TWL4030_OPT_MODE 0x01 -#define TWL4030_OPTION_1 (1 << 0) -#define TWL4030_OPTION_2 (0 << 0) - -/* TWL4030_OPTION (0x02) Fields */ - -#define TWL4030_ATXL1_EN (1 << 0) -#define TWL4030_ATXR1_EN (1 << 1) -#define TWL4030_ATXL2_VTXL_EN (1 << 2) -#define TWL4030_ATXR2_VTXR_EN (1 << 3) -#define TWL4030_ARXL1_VRX_EN (1 << 4) -#define TWL4030_ARXR1_EN (1 << 5) -#define TWL4030_ARXL2_EN (1 << 6) -#define TWL4030_ARXR2_EN (1 << 7) - -/* TWL4030_REG_MICBIAS_CTL (0x04) Fields */ - -#define TWL4030_MICBIAS2_CTL 0x40 -#define TWL4030_MICBIAS1_CTL 0x20 -#define TWL4030_HSMICBIAS_EN 0x04 -#define TWL4030_MICBIAS2_EN 0x02 -#define TWL4030_MICBIAS1_EN 0x01 - -/* ANAMICL (0x05) Fields */ - -#define TWL4030_CNCL_OFFSET_START 0x80 -#define TWL4030_OFFSET_CNCL_SEL 0x60 -#define TWL4030_OFFSET_CNCL_SEL_ARX1 0x00 -#define TWL4030_OFFSET_CNCL_SEL_ARX2 0x20 -#define TWL4030_OFFSET_CNCL_SEL_VRX 0x40 -#define TWL4030_OFFSET_CNCL_SEL_ALL 0x60 -#define TWL4030_MICAMPL_EN 0x10 -#define TWL4030_CKMIC_EN 0x08 -#define TWL4030_AUXL_EN 0x04 -#define TWL4030_HSMIC_EN 0x02 -#define TWL4030_MAINMIC_EN 0x01 - -/* ANAMICR (0x06) Fields */ - -#define TWL4030_MICAMPR_EN 0x10 -#define TWL4030_AUXR_EN 0x04 -#define TWL4030_SUBMIC_EN 0x01 - -/* AVADC_CTL (0x07) Fields */ - -#define TWL4030_ADCL_EN 0x08 -#define TWL4030_AVADC_CLK_PRIORITY 0x04 -#define TWL4030_ADCR_EN 0x02 - -/* TWL4030_REG_ADCMICSEL (0x08) Fields */ - -#define TWL4030_DIGMIC1_EN 0x08 -#define TWL4030_TX2IN_SEL 0x04 -#define TWL4030_DIGMIC0_EN 0x02 -#define TWL4030_TX1IN_SEL 0x01 - -/* AUDIO_IF (0x0E) Fields */ - -#define TWL4030_AIF_SLAVE_EN 0x80 -#define TWL4030_DATA_WIDTH 0x60 -#define TWL4030_DATA_WIDTH_16S_16W 0x00 -#define TWL4030_DATA_WIDTH_32S_16W 0x40 -#define TWL4030_DATA_WIDTH_32S_24W 0x60 -#define TWL4030_AIF_FORMAT 0x18 -#define TWL4030_AIF_FORMAT_CODEC 0x00 -#define TWL4030_AIF_FORMAT_LEFT 0x08 -#define TWL4030_AIF_FORMAT_RIGHT 0x10 -#define TWL4030_AIF_FORMAT_TDM 0x18 -#define TWL4030_AIF_TRI_EN 0x04 -#define TWL4030_CLK256FS_EN 0x02 -#define TWL4030_AIF_EN 0x01 - -/* VOICE_IF (0x0F) Fields */ - -#define TWL4030_VIF_SLAVE_EN 0x80 -#define TWL4030_VIF_DIN_EN 0x40 -#define TWL4030_VIF_DOUT_EN 0x20 -#define TWL4030_VIF_SWAP 0x10 -#define TWL4030_VIF_FORMAT 0x08 -#define TWL4030_VIF_TRI_EN 0x04 -#define TWL4030_VIF_SUB_EN 0x02 -#define TWL4030_VIF_EN 0x01 - -/* EAR_CTL (0x21) */ -#define TWL4030_EAR_GAIN 0x30 - -/* HS_GAIN_SET (0x23) Fields */ - -#define TWL4030_HSR_GAIN 0x0C -#define TWL4030_HSR_GAIN_PWR_DOWN 0x00 -#define TWL4030_HSR_GAIN_PLUS_6DB 0x04 -#define TWL4030_HSR_GAIN_0DB 0x08 -#define TWL4030_HSR_GAIN_MINUS_6DB 0x0C -#define TWL4030_HSL_GAIN 0x03 -#define TWL4030_HSL_GAIN_PWR_DOWN 0x00 -#define TWL4030_HSL_GAIN_PLUS_6DB 0x01 -#define TWL4030_HSL_GAIN_0DB 0x02 -#define TWL4030_HSL_GAIN_MINUS_6DB 0x03 - -/* HS_POPN_SET (0x24) Fields */ - -#define TWL4030_VMID_EN 0x40 -#define TWL4030_EXTMUTE 0x20 -#define TWL4030_RAMP_DELAY 0x1C -#define TWL4030_RAMP_DELAY_20MS 0x00 -#define TWL4030_RAMP_DELAY_40MS 0x04 -#define TWL4030_RAMP_DELAY_81MS 0x08 -#define TWL4030_RAMP_DELAY_161MS 0x0C -#define TWL4030_RAMP_DELAY_323MS 0x10 -#define TWL4030_RAMP_DELAY_645MS 0x14 -#define TWL4030_RAMP_DELAY_1291MS 0x18 -#define TWL4030_RAMP_DELAY_2581MS 0x1C -#define TWL4030_RAMP_EN 0x02 - -/* PREDL_CTL (0x25) */ -#define TWL4030_PREDL_GAIN 0x30 - -/* PREDR_CTL (0x26) */ -#define TWL4030_PREDR_GAIN 0x30 - -/* PRECKL_CTL (0x27) */ -#define TWL4030_PRECKL_GAIN 0x30 - -/* PRECKR_CTL (0x28) */ -#define TWL4030_PRECKR_GAIN 0x30 - -/* HFL_CTL (0x29, 0x2A) Fields */ -#define TWL4030_HF_CTL_HB_EN 0x04 -#define TWL4030_HF_CTL_LOOP_EN 0x08 -#define TWL4030_HF_CTL_RAMP_EN 0x10 -#define TWL4030_HF_CTL_REF_EN 0x20 - -/* APLL_CTL (0x3A) Fields */ - -#define TWL4030_APLL_EN 0x10 -#define TWL4030_APLL_INFREQ 0x0F -#define TWL4030_APLL_INFREQ_19200KHZ 0x05 -#define TWL4030_APLL_INFREQ_26000KHZ 0x06 -#define TWL4030_APLL_INFREQ_38400KHZ 0x0F - -/* REG_MISC_SET_1 (0x3E) Fields */ - -#define TWL4030_CLK64_EN 0x80 -#define TWL4030_SCRAMBLE_EN 0x40 -#define TWL4030_FMLOOP_EN 0x20 -#define TWL4030_SMOOTH_ANAVOL_EN 0x02 -#define TWL4030_DIGMIC_LR_SWAP_EN 0x01 - /* TWL4030_REG_SW_SHADOW (0x4A) Fields */ #define TWL4030_HFL_EN 0x01 #define TWL4030_HFR_EN 0x02 @@ -279,3 +47,5 @@ struct twl4030_setup_data { }; #endif /* End of __TWL4030_AUDIO_H__ */ + + -- cgit v1.2.3 From 7a1fecf57f435e50ed86851cbb701f4b28e65135 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 22 Oct 2009 13:26:48 +0300 Subject: ASoC: TWL4030: Driver registration via twl4030_codec MFD Change the way how the twl4030 soc codec driver is loaded/probed. Use the device probing via tlw4030_codec MFD device. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 1 + sound/soc/codecs/twl4030.c | 203 ++++++++++++++++++++++++++++----------------- 2 files changed, 127 insertions(+), 77 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index d30fce71cfe..3df3497335b 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -147,6 +147,7 @@ config SND_SOC_TLV320DAC33 tristate config SND_SOC_TWL4030 + select TWL4030_CODEC tristate config SND_SOC_UDA134X diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 559e9b27928..5c5a4c0a424 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -120,6 +120,8 @@ static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = { /* codec private data */ struct twl4030_priv { + struct snd_soc_codec codec; + unsigned int bypass_state; unsigned int codec_powered; unsigned int codec_muted; @@ -183,19 +185,20 @@ static int twl4030_write(struct snd_soc_codec *codec, static void twl4030_codec_enable(struct snd_soc_codec *codec, int enable) { struct twl4030_priv *twl4030 = codec->private_data; - u8 mode; + int mode; if (enable == twl4030->codec_powered) return; - mode = twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE); if (enable) - mode |= TWL4030_CODECPDZ; + mode = twl4030_codec_enable_resource(TWL4030_CODEC_RES_POWER); else - mode &= ~TWL4030_CODECPDZ; + mode = twl4030_codec_disable_resource(TWL4030_CODEC_RES_POWER); - twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode); - twl4030->codec_powered = enable; + if (mode >= 0) { + twl4030_write_reg_cache(codec, TWL4030_REG_CODEC_MODE, mode); + twl4030->codec_powered = enable; + } /* REVISIT: this delay is present in TI sample drivers */ /* but there seems to be no TRM requirement for it */ @@ -219,22 +222,20 @@ static void twl4030_init_chip(struct snd_soc_codec *codec) static void twl4030_codec_mute(struct snd_soc_codec *codec, int mute) { struct twl4030_priv *twl4030 = codec->private_data; - u8 reg_val; + int status; if (mute == twl4030->codec_muted) return; - if (mute) { + if (mute) /* Disable PLL */ - reg_val = twl4030_read_reg_cache(codec, TWL4030_REG_APLL_CTL); - reg_val &= ~TWL4030_APLL_EN; - twl4030_write(codec, TWL4030_REG_APLL_CTL, reg_val); - } else { + status = twl4030_codec_disable_resource(TWL4030_CODEC_RES_APLL); + else /* Enable PLL */ - reg_val = twl4030_read_reg_cache(codec, TWL4030_REG_APLL_CTL); - reg_val |= TWL4030_APLL_EN; - twl4030_write(codec, TWL4030_REG_APLL_CTL, reg_val); - } + status = twl4030_codec_enable_resource(TWL4030_CODEC_RES_APLL); + + if (status >= 0) + twl4030_write_reg_cache(codec, TWL4030_REG_APLL_CTL, status); twl4030->codec_muted = mute; } @@ -2123,7 +2124,7 @@ struct snd_soc_dai twl4030_dai[] = { }; EXPORT_SYMBOL_GPL(twl4030_dai); -static int twl4030_suspend(struct platform_device *pdev, pm_message_t state) +static int twl4030_soc_suspend(struct platform_device *pdev, pm_message_t state) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); struct snd_soc_codec *codec = socdev->card->codec; @@ -2133,7 +2134,7 @@ static int twl4030_suspend(struct platform_device *pdev, pm_message_t state) return 0; } -static int twl4030_resume(struct platform_device *pdev) +static int twl4030_soc_resume(struct platform_device *pdev) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); struct snd_soc_codec *codec = socdev->card->codec; @@ -2143,32 +2144,21 @@ static int twl4030_resume(struct platform_device *pdev) return 0; } -/* - * initialize the driver - * register the mixer and dsp interfaces with the kernel - */ +static struct snd_soc_codec *twl4030_codec; -static int twl4030_init(struct snd_soc_device *socdev) +static int twl4030_soc_probe(struct platform_device *pdev) { - struct snd_soc_codec *codec = socdev->card->codec; + struct snd_soc_device *socdev = platform_get_drvdata(pdev); struct twl4030_setup_data *setup = socdev->codec_data; - struct twl4030_priv *twl4030 = codec->private_data; - int ret = 0; + struct snd_soc_codec *codec; + struct twl4030_priv *twl4030; + int ret; - printk(KERN_INFO "TWL4030 Audio Codec init \n"); + BUG_ON(!twl4030_codec); - codec->name = "twl4030"; - codec->owner = THIS_MODULE; - codec->read = twl4030_read_reg_cache; - codec->write = twl4030_write; - codec->set_bias_level = twl4030_set_bias_level; - codec->dai = twl4030_dai; - codec->num_dai = ARRAY_SIZE(twl4030_dai), - codec->reg_cache_size = sizeof(twl4030_reg); - codec->reg_cache = kmemdup(twl4030_reg, sizeof(twl4030_reg), - GFP_KERNEL); - if (codec->reg_cache == NULL) - return -ENOMEM; + codec = twl4030_codec; + twl4030 = codec->private_data; + socdev->card->codec = codec; /* Configuration for headset ramp delay from setup data */ if (setup) { @@ -2190,100 +2180,159 @@ static int twl4030_init(struct snd_soc_device *socdev) /* register pcms */ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); if (ret < 0) { - printk(KERN_ERR "twl4030: failed to create pcms\n"); - goto pcm_err; + dev_err(&pdev->dev, "failed to create pcms\n"); + return ret; } - twl4030_init_chip(codec); - - /* power on device */ - twl4030_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - snd_soc_add_controls(codec, twl4030_snd_controls, ARRAY_SIZE(twl4030_snd_controls)); twl4030_add_widgets(codec); ret = snd_soc_init_card(socdev); if (ret < 0) { - printk(KERN_ERR "twl4030: failed to register card\n"); + dev_err(&pdev->dev, "failed to register card\n"); goto card_err; } - return ret; + return 0; card_err: snd_soc_free_pcms(socdev); snd_soc_dapm_free(socdev); -pcm_err: - kfree(codec->reg_cache); + return ret; } -static struct snd_soc_device *twl4030_socdev; - -static int twl4030_probe(struct platform_device *pdev) +static int twl4030_soc_remove(struct platform_device *pdev) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + + twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF); + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); + kfree(codec->private_data); + kfree(codec); + + return 0; +} + +static int __devinit twl4030_codec_probe(struct platform_device *pdev) +{ + struct twl4030_codec_audio_data *pdata = pdev->dev.platform_data; struct snd_soc_codec *codec; struct twl4030_priv *twl4030; + int ret; - codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); - if (codec == NULL) - return -ENOMEM; + if (!pdata || !(pdata->audio_mclk == 19200000 || + pdata->audio_mclk == 26000000 || + pdata->audio_mclk == 38400000)) { + dev_err(&pdev->dev, "Invalid platform_data\n"); + return -EINVAL; + } twl4030 = kzalloc(sizeof(struct twl4030_priv), GFP_KERNEL); if (twl4030 == NULL) { - kfree(codec); + dev_err(&pdev->dev, "Can not allocate memroy\n"); return -ENOMEM; } + codec = &twl4030->codec; codec->private_data = twl4030; - socdev->card->codec = codec; + codec->dev = &pdev->dev; + twl4030_dai[0].dev = &pdev->dev; + twl4030_dai[1].dev = &pdev->dev; + mutex_init(&codec->mutex); INIT_LIST_HEAD(&codec->dapm_widgets); INIT_LIST_HEAD(&codec->dapm_paths); - twl4030_socdev = socdev; - twl4030_init(socdev); + codec->name = "twl4030"; + codec->owner = THIS_MODULE; + codec->read = twl4030_read_reg_cache; + codec->write = twl4030_write; + codec->set_bias_level = twl4030_set_bias_level; + codec->dai = twl4030_dai; + codec->num_dai = ARRAY_SIZE(twl4030_dai), + codec->reg_cache_size = sizeof(twl4030_reg); + codec->reg_cache = kmemdup(twl4030_reg, sizeof(twl4030_reg), + GFP_KERNEL); + if (codec->reg_cache == NULL) { + ret = -ENOMEM; + goto error_cache; + } + + platform_set_drvdata(pdev, twl4030); + twl4030_codec = codec; + + /* Set the defaults, and power up the codec */ + twl4030_init_chip(codec); + twl4030_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + ret = snd_soc_register_codec(codec); + if (ret != 0) { + dev_err(codec->dev, "Failed to register codec: %d\n", ret); + goto error_codec; + } + + ret = snd_soc_register_dais(&twl4030_dai[0], ARRAY_SIZE(twl4030_dai)); + if (ret != 0) { + dev_err(codec->dev, "Failed to register DAIs: %d\n", ret); + snd_soc_unregister_codec(codec); + goto error_codec; + } return 0; + +error_codec: + twl4030_power_down(codec); + kfree(codec->reg_cache); +error_cache: + kfree(twl4030); + return ret; } -static int twl4030_remove(struct platform_device *pdev) +static int __devexit twl4030_codec_remove(struct platform_device *pdev) { - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->card->codec; + struct twl4030_priv *twl4030 = platform_get_drvdata(pdev); - printk(KERN_INFO "TWL4030 Audio Codec remove\n"); - twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF); - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); - kfree(codec->private_data); - kfree(codec); + kfree(twl4030); + twl4030_codec = NULL; return 0; } -struct snd_soc_codec_device soc_codec_dev_twl4030 = { - .probe = twl4030_probe, - .remove = twl4030_remove, - .suspend = twl4030_suspend, - .resume = twl4030_resume, +MODULE_ALIAS("platform:twl4030_codec_audio"); + +static struct platform_driver twl4030_codec_driver = { + .probe = twl4030_codec_probe, + .remove = __devexit_p(twl4030_codec_remove), + .driver = { + .name = "twl4030_codec_audio", + .owner = THIS_MODULE, + }, }; -EXPORT_SYMBOL_GPL(soc_codec_dev_twl4030); static int __init twl4030_modinit(void) { - return snd_soc_register_dais(&twl4030_dai[0], ARRAY_SIZE(twl4030_dai)); + return platform_driver_register(&twl4030_codec_driver); } module_init(twl4030_modinit); static void __exit twl4030_exit(void) { - snd_soc_unregister_dais(&twl4030_dai[0], ARRAY_SIZE(twl4030_dai)); + platform_driver_unregister(&twl4030_codec_driver); } module_exit(twl4030_exit); +struct snd_soc_codec_device soc_codec_dev_twl4030 = { + .probe = twl4030_soc_probe, + .remove = twl4030_soc_remove, + .suspend = twl4030_soc_suspend, + .resume = twl4030_soc_resume, +}; +EXPORT_SYMBOL_GPL(soc_codec_dev_twl4030); + MODULE_DESCRIPTION("ASoC TWL4030 codec driver"); MODULE_AUTHOR("Steve Sakoman"); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 7dea7c01dac9b74faa9afa93fc9bb5f2d37521dc Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 26 Oct 2009 15:20:17 +0000 Subject: ASoC: Add regulator support for WM8731 Signed-off-by: Mark Brown --- sound/soc/codecs/wm8731.c | 51 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 47 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 0e59219a59f..bb95af95097 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -33,9 +34,18 @@ static struct snd_soc_codec *wm8731_codec; struct snd_soc_codec_device soc_codec_dev_wm8731; +#define WM8731_NUM_SUPPLIES 4 +static const char *wm8731_supply_names[WM8731_NUM_SUPPLIES] = { + "AVDD", + "HPVDD", + "DCVDD", + "DBVDD", +}; + /* codec private data */ struct wm8731_priv { struct snd_soc_codec codec; + struct regulator_bulk_data supplies[WM8731_NUM_SUPPLIES]; u16 reg_cache[WM8731_CACHEREGNUM]; unsigned int sysclk; }; @@ -422,9 +432,12 @@ static int wm8731_suspend(struct platform_device *pdev, pm_message_t state) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); struct snd_soc_codec *codec = socdev->card->codec; + struct wm8731_priv *wm8731 = codec->private_data; snd_soc_write(codec, WM8731_ACTIVE, 0x0); wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF); + regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), + wm8731->supplies); return 0; } @@ -432,10 +445,16 @@ static int wm8731_resume(struct platform_device *pdev) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); struct snd_soc_codec *codec = socdev->card->codec; - int i; + struct wm8731_priv *wm8731 = codec->private_data; + int i, ret; u8 data[2]; u16 *cache = codec->reg_cache; + ret = regulator_bulk_enable(ARRAY_SIZE(wm8731->supplies), + wm8731->supplies); + if (ret != 0) + return ret; + /* Sync reg_cache with the hardware */ for (i = 0; i < ARRAY_SIZE(wm8731_reg); i++) { data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001); @@ -444,6 +463,7 @@ static int wm8731_resume(struct platform_device *pdev) } wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY); wm8731_set_bias_level(codec, codec->suspend_bias_level); + return 0; } #else @@ -512,7 +532,7 @@ EXPORT_SYMBOL_GPL(soc_codec_dev_wm8731); static int wm8731_register(struct wm8731_priv *wm8731, enum snd_soc_control_type control) { - int ret; + int ret, i; struct snd_soc_codec *codec = &wm8731->codec; if (wm8731_codec) { @@ -543,10 +563,27 @@ static int wm8731_register(struct wm8731_priv *wm8731, goto err; } + for (i = 0; i < ARRAY_SIZE(wm8731->supplies); i++) + wm8731->supplies[i].supply = wm8731_supply_names[i]; + + ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8731->supplies), + wm8731->supplies); + if (ret != 0) { + dev_err(codec->dev, "Failed to request supplies: %d\n", ret); + goto err; + } + + ret = regulator_bulk_enable(ARRAY_SIZE(wm8731->supplies), + wm8731->supplies); + if (ret != 0) { + dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); + goto err_regulator_get; + } + ret = wm8731_reset(codec); if (ret < 0) { dev_err(codec->dev, "Failed to issue reset: %d\n", ret); - goto err; + goto err_regulator_enable; } wm8731_dai.dev = codec->dev; @@ -567,7 +604,7 @@ static int wm8731_register(struct wm8731_priv *wm8731, ret = snd_soc_register_codec(codec); if (ret != 0) { dev_err(codec->dev, "Failed to register codec: %d\n", ret); - goto err; + goto err_regulator_enable; } ret = snd_soc_register_dai(&wm8731_dai); @@ -581,6 +618,10 @@ static int wm8731_register(struct wm8731_priv *wm8731, err_codec: snd_soc_unregister_codec(codec); +err_regulator_enable: + regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies); +err_regulator_get: + regulator_bulk_free(ARRAY_SIZE(wm8731->supplies), wm8731->supplies); err: kfree(wm8731); return ret; @@ -591,6 +632,8 @@ static void wm8731_unregister(struct wm8731_priv *wm8731) wm8731_set_bias_level(&wm8731->codec, SND_SOC_BIAS_OFF); snd_soc_unregister_dai(&wm8731_dai); snd_soc_unregister_codec(&wm8731->codec); + regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies); + regulator_bulk_free(ARRAY_SIZE(wm8731->supplies), wm8731->supplies); kfree(wm8731); wm8731_codec = NULL; } -- cgit v1.2.3 From f8a3ae6c84e60a3f35f573ea592b8fe00dd367ab Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Fri, 16 Oct 2009 07:21:38 +0000 Subject: powerpc: Minor cleanup to sound/ppc/Kconfig We can replace PPC32 || PPC64 as a dependancy with just PPC as all powerpc platforms (32-bit and 64-bit) define PPC now. Signed-off-by: Kumar Gala Signed-off-by: Benjamin Herrenschmidt --- sound/ppc/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/ppc/Kconfig b/sound/ppc/Kconfig index bd2338ab2ce..0519c60f5be 100644 --- a/sound/ppc/Kconfig +++ b/sound/ppc/Kconfig @@ -2,7 +2,7 @@ menuconfig SND_PPC bool "PowerPC sound devices" - depends on PPC64 || PPC32 + depends on PPC default y help Support for sound devices specific to PowerPC architectures. -- cgit v1.2.3 From 78e08e2f209e5e7777e81919d32cfcddad126cfa Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 28 Oct 2009 10:57:04 +0200 Subject: ASoC: TWL4030: Remove bypass tracking Since ASoC core now handling the codec bias differently there is no need to do the tracking of bypass switch states anymore. Handling of the common bit for analog loopbacks is done with DAPM_SUPPLY for the bypass paths. Now this bit is only enabled when there is a complete analog bypass path, compared to the previous implementation, when the global switch was enabled if there were any of the analog bypass switch was on (regardless if there were complete path or not) Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 128 +++++++++++---------------------------------- 1 file changed, 30 insertions(+), 98 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 5c5a4c0a424..24002269f03 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -122,7 +122,6 @@ static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = { struct twl4030_priv { struct snd_soc_codec codec; - unsigned int bypass_state; unsigned int codec_powered; unsigned int codec_muted; @@ -725,67 +724,6 @@ static int headsetrpga_event(struct snd_soc_dapm_widget *w, return 0; } -static int bypass_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) -{ - struct soc_mixer_control *m = - (struct soc_mixer_control *)w->kcontrols->private_value; - struct twl4030_priv *twl4030 = w->codec->private_data; - unsigned char reg, misc; - - reg = twl4030_read_reg_cache(w->codec, m->reg); - - /* - * bypass_state[0:3] - analog HiFi bypass - * bypass_state[4] - analog voice bypass - * bypass_state[5] - digital voice bypass - * bypass_state[6:7] - digital HiFi bypass - */ - if (m->reg == TWL4030_REG_VSTPGA) { - /* Voice digital bypass */ - if (reg) - twl4030->bypass_state |= (1 << 5); - else - twl4030->bypass_state &= ~(1 << 5); - } else if (m->reg <= TWL4030_REG_ARXR2_APGA_CTL) { - /* Analog bypass */ - if (reg & (1 << m->shift)) - twl4030->bypass_state |= - (1 << (m->reg - TWL4030_REG_ARXL1_APGA_CTL)); - else - twl4030->bypass_state &= - ~(1 << (m->reg - TWL4030_REG_ARXL1_APGA_CTL)); - } else if (m->reg == TWL4030_REG_VDL_APGA_CTL) { - /* Analog voice bypass */ - if (reg & (1 << m->shift)) - twl4030->bypass_state |= (1 << 4); - else - twl4030->bypass_state &= ~(1 << 4); - } else { - /* Digital bypass */ - if (reg & (0x7 << m->shift)) - twl4030->bypass_state |= (1 << (m->shift ? 7 : 6)); - else - twl4030->bypass_state &= ~(1 << (m->shift ? 7 : 6)); - } - - /* Enable master analog loopback mode if any analog switch is enabled*/ - misc = twl4030_read_reg_cache(w->codec, TWL4030_REG_MISC_SET_1); - if (twl4030->bypass_state & 0x1F) - misc |= TWL4030_FMLOOP_EN; - else - misc &= ~TWL4030_FMLOOP_EN; - twl4030_write(w->codec, TWL4030_REG_MISC_SET_1, misc); - - if (w->codec->bias_level == SND_SOC_BIAS_STANDBY) { - if (twl4030->bypass_state) - twl4030_codec_mute(w->codec, 0); - else - twl4030_codec_mute(w->codec, 1); - } - return 0; -} - /* * Some of the gain controls in TWL (mostly those which are associated with * the outputs) are implemented in an interesting way: @@ -1193,32 +1131,28 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { SND_SOC_NOPM, 0, 0), /* Analog bypasses */ - SND_SOC_DAPM_SWITCH_E("Right1 Analog Loopback", SND_SOC_NOPM, 0, 0, - &twl4030_dapm_abypassr1_control, bypass_event, - SND_SOC_DAPM_POST_REG), - SND_SOC_DAPM_SWITCH_E("Left1 Analog Loopback", SND_SOC_NOPM, 0, 0, - &twl4030_dapm_abypassl1_control, - bypass_event, SND_SOC_DAPM_POST_REG), - SND_SOC_DAPM_SWITCH_E("Right2 Analog Loopback", SND_SOC_NOPM, 0, 0, - &twl4030_dapm_abypassr2_control, - bypass_event, SND_SOC_DAPM_POST_REG), - SND_SOC_DAPM_SWITCH_E("Left2 Analog Loopback", SND_SOC_NOPM, 0, 0, - &twl4030_dapm_abypassl2_control, - bypass_event, SND_SOC_DAPM_POST_REG), - SND_SOC_DAPM_SWITCH_E("Voice Analog Loopback", SND_SOC_NOPM, 0, 0, - &twl4030_dapm_abypassv_control, - bypass_event, SND_SOC_DAPM_POST_REG), + SND_SOC_DAPM_SWITCH("Right1 Analog Loopback", SND_SOC_NOPM, 0, 0, + &twl4030_dapm_abypassr1_control), + SND_SOC_DAPM_SWITCH("Left1 Analog Loopback", SND_SOC_NOPM, 0, 0, + &twl4030_dapm_abypassl1_control), + SND_SOC_DAPM_SWITCH("Right2 Analog Loopback", SND_SOC_NOPM, 0, 0, + &twl4030_dapm_abypassr2_control), + SND_SOC_DAPM_SWITCH("Left2 Analog Loopback", SND_SOC_NOPM, 0, 0, + &twl4030_dapm_abypassl2_control), + SND_SOC_DAPM_SWITCH("Voice Analog Loopback", SND_SOC_NOPM, 0, 0, + &twl4030_dapm_abypassv_control), + + /* Master analog loopback switch */ + SND_SOC_DAPM_SUPPLY("FM Loop Enable", TWL4030_REG_MISC_SET_1, 5, 0, + NULL, 0), /* Digital bypasses */ - SND_SOC_DAPM_SWITCH_E("Left Digital Loopback", SND_SOC_NOPM, 0, 0, - &twl4030_dapm_dbypassl_control, bypass_event, - SND_SOC_DAPM_POST_REG), - SND_SOC_DAPM_SWITCH_E("Right Digital Loopback", SND_SOC_NOPM, 0, 0, - &twl4030_dapm_dbypassr_control, bypass_event, - SND_SOC_DAPM_POST_REG), - SND_SOC_DAPM_SWITCH_E("Voice Digital Loopback", SND_SOC_NOPM, 0, 0, - &twl4030_dapm_dbypassv_control, bypass_event, - SND_SOC_DAPM_POST_REG), + SND_SOC_DAPM_SWITCH("Left Digital Loopback", SND_SOC_NOPM, 0, 0, + &twl4030_dapm_dbypassl_control), + SND_SOC_DAPM_SWITCH("Right Digital Loopback", SND_SOC_NOPM, 0, 0, + &twl4030_dapm_dbypassr_control), + SND_SOC_DAPM_SWITCH("Voice Digital Loopback", SND_SOC_NOPM, 0, 0, + &twl4030_dapm_dbypassv_control), /* Digital mixers, power control for the physical DACs */ SND_SOC_DAPM_MIXER("Digital R1 Playback Mixer", @@ -1490,6 +1424,13 @@ static const struct snd_soc_dapm_route intercon[] = { {"Left2 Analog Loopback", "Switch", "Analog Left"}, {"Voice Analog Loopback", "Switch", "Analog Left"}, + /* Supply for the Analog loopbacks */ + {"Right1 Analog Loopback", NULL, "FM Loop Enable"}, + {"Left1 Analog Loopback", NULL, "FM Loop Enable"}, + {"Right2 Analog Loopback", NULL, "FM Loop Enable"}, + {"Left2 Analog Loopback", NULL, "FM Loop Enable"}, + {"Voice Analog Loopback", NULL, "FM Loop Enable"}, + {"Analog R1 Playback Mixer", NULL, "Right1 Analog Loopback"}, {"Analog L1 Playback Mixer", NULL, "Left1 Analog Loopback"}, {"Analog R2 Playback Mixer", NULL, "Right2 Analog Loopback"}, @@ -1521,25 +1462,16 @@ static int twl4030_add_widgets(struct snd_soc_codec *codec) static int twl4030_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { - struct twl4030_priv *twl4030 = codec->private_data; - switch (level) { case SND_SOC_BIAS_ON: twl4030_codec_mute(codec, 0); break; case SND_SOC_BIAS_PREPARE: - twl4030_power_up(codec); - if (twl4030->bypass_state) - twl4030_codec_mute(codec, 0); - else - twl4030_codec_mute(codec, 1); break; case SND_SOC_BIAS_STANDBY: - twl4030_power_up(codec); - if (twl4030->bypass_state) - twl4030_codec_mute(codec, 0); - else - twl4030_codec_mute(codec, 1); + if (codec->bias_level == SND_SOC_BIAS_OFF) + twl4030_power_up(codec); + twl4030_codec_mute(codec, 1); break; case SND_SOC_BIAS_OFF: twl4030_power_down(codec); -- cgit v1.2.3 From 2845fa13e5cbe708ece7fafe29c91f32c66e4f59 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 28 Oct 2009 10:57:05 +0200 Subject: ASoC: TWL4030: Change codec_muted to apll_enabled codec_muted is missleading, change it to apll_enabled, which is what it is doing: enabing and disabling the APLL. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 24002269f03..9163713a030 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -123,7 +123,7 @@ struct twl4030_priv { struct snd_soc_codec codec; unsigned int codec_powered; - unsigned int codec_muted; + unsigned int apll_enabled; struct snd_pcm_substream *master_substream; struct snd_pcm_substream *slave_substream; @@ -218,25 +218,25 @@ static void twl4030_init_chip(struct snd_soc_codec *codec) } -static void twl4030_codec_mute(struct snd_soc_codec *codec, int mute) +static void twl4030_apll_enable(struct snd_soc_codec *codec, int enable) { struct twl4030_priv *twl4030 = codec->private_data; int status; - if (mute == twl4030->codec_muted) + if (enable == twl4030->apll_enabled) return; - if (mute) - /* Disable PLL */ - status = twl4030_codec_disable_resource(TWL4030_CODEC_RES_APLL); - else + if (enable) /* Enable PLL */ status = twl4030_codec_enable_resource(TWL4030_CODEC_RES_APLL); + else + /* Disable PLL */ + status = twl4030_codec_disable_resource(TWL4030_CODEC_RES_APLL); if (status >= 0) twl4030_write_reg_cache(codec, TWL4030_REG_APLL_CTL, status); - twl4030->codec_muted = mute; + twl4030->apll_enabled = enable; } static void twl4030_power_up(struct snd_soc_codec *codec) @@ -1464,14 +1464,14 @@ static int twl4030_set_bias_level(struct snd_soc_codec *codec, { switch (level) { case SND_SOC_BIAS_ON: - twl4030_codec_mute(codec, 0); + twl4030_apll_enable(codec, 1); break; case SND_SOC_BIAS_PREPARE: break; case SND_SOC_BIAS_STANDBY: if (codec->bias_level == SND_SOC_BIAS_OFF) twl4030_power_up(codec); - twl4030_codec_mute(codec, 1); + twl4030_apll_enable(codec, 0); break; case SND_SOC_BIAS_OFF: twl4030_power_down(codec); -- cgit v1.2.3 From e3d8024891dbfec6cf36c9b76177650f48118462 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Tue, 22 Sep 2009 16:48:56 +0100 Subject: ARM: S3C: Add info for supporting circular DMA buffers The S3C64XX DMA implementation will work a lot better with the ability to enqueue circular buffers as the hardware can do it's own linked-list management. Add a function s3c_dma_has_circular() to show that the system can do this and a flag for the channel. Update the s3c24xx/s3c64xx I2S DMA code to deal with this. Signed-off-by: Ben Dooks Signed-off-by: Ben Dooks Acked-by: Mark Brown --- sound/soc/s3c24xx/s3c24xx-pcm.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/s3c24xx/s3c24xx-pcm.c b/sound/soc/s3c24xx/s3c24xx-pcm.c index 5cbbdc80fde..1f35c6fcf5f 100644 --- a/sound/soc/s3c24xx/s3c24xx-pcm.c +++ b/sound/soc/s3c24xx/s3c24xx-pcm.c @@ -75,11 +75,19 @@ static void s3c24xx_pcm_enqueue(struct snd_pcm_substream *substream) { struct s3c24xx_runtime_data *prtd = substream->runtime->private_data; dma_addr_t pos = prtd->dma_pos; + unsigned int limit; int ret; pr_debug("Entered %s\n", __func__); - while (prtd->dma_loaded < prtd->dma_limit) { + if (s3c_dma_has_circular()) { + limit = (prtd->dma_end - prtd->dma_start) / prtd->dma_period; + } else + limit = prtd->dma_limit; + + pr_debug("%s: loaded %d, limit %d\n", __func__, prtd->dma_loaded, limit); + + while (prtd->dma_loaded < limit) { unsigned long len = prtd->dma_period; pr_debug("dma_loaded: %d\n", prtd->dma_loaded); @@ -123,7 +131,7 @@ static void s3c24xx_audio_buffdone(struct s3c2410_dma_chan *channel, snd_pcm_period_elapsed(substream); spin_lock(&prtd->lock); - if (prtd->state & ST_RUNNING) { + if (prtd->state & ST_RUNNING && !s3c_dma_has_circular()) { prtd->dma_loaded--; s3c24xx_pcm_enqueue(substream); } @@ -164,6 +172,11 @@ static int s3c24xx_pcm_hw_params(struct snd_pcm_substream *substream, printk(KERN_ERR "failed to get dma channel\n"); return ret; } + + /* use the circular buffering if we have it available. */ + if (s3c_dma_has_circular()) + s3c2410_dma_setflags(prtd->params->channel, + S3C2410_DMAF_CIRCULAR); } s3c2410_dma_set_buffdone_fn(prtd->params->channel, -- cgit v1.2.3 From 26d95b6e300c4847be6ec8bfe817dbd531e94d9a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 28 Oct 2009 15:47:48 +0000 Subject: ASoC: Minor SMDK64xx WM8580 cleanups Fix up some comments, remove all enable_pin() calls (edge widgets are all enabled by default) and mark the microphone as disabled by default since it requires a resistor fit to connect it. Signed-off-by: Mark Brown --- sound/soc/s3c24xx/smdk64xx_wm8580.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) (limited to 'sound') diff --git a/sound/soc/s3c24xx/smdk64xx_wm8580.c b/sound/soc/s3c24xx/smdk64xx_wm8580.c index 482aaf10eff..cb8a9161b64 100644 --- a/sound/soc/s3c24xx/smdk64xx_wm8580.c +++ b/sound/soc/s3c24xx/smdk64xx_wm8580.c @@ -103,7 +103,7 @@ static int smdk64xx_hw_params(struct snd_pcm_substream *substream, if (ret < 0) return ret; - /* Set WM8580 to drive MCLK from it's PLLA */ + /* Set WM8580 to drive MCLK from its PLLA */ ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_MCLK, WM8580_CLKSRC_PLLA); if (ret < 0) @@ -115,7 +115,6 @@ static int smdk64xx_hw_params(struct snd_pcm_substream *substream, if (ret < 0) return ret; - /* Assuming the CODEC driver evaluates it's rfs too from this call */ ret = snd_soc_dai_set_pll(codec_dai, 0, WM8580_PLLA, SMDK64XX_WM8580_FREQ, pll_out); if (ret < 0) @@ -186,9 +185,10 @@ static int smdk64xx_wm8580_init_paiftx(struct snd_soc_codec *codec) /* Set up PAIFTX audio path */ snd_soc_dapm_add_routes(codec, audio_map_tx, ARRAY_SIZE(audio_map_tx)); - /* All enabled by default */ - snd_soc_dapm_enable_pin(codec, "MicIn"); - snd_soc_dapm_enable_pin(codec, "LineIn"); + /* Enabling the microphone requires the fitting of a 0R + * resistor to connect the line from the microphone jack. + */ + snd_soc_dapm_disable_pin(codec, "MicIn"); /* signal a DAPM event */ snd_soc_dapm_sync(codec); @@ -205,11 +205,6 @@ static int smdk64xx_wm8580_init_paifrx(struct snd_soc_codec *codec) /* Set up PAIFRX audio path */ snd_soc_dapm_add_routes(codec, audio_map_rx, ARRAY_SIZE(audio_map_rx)); - /* All enabled by default */ - snd_soc_dapm_enable_pin(codec, "Front-L/R"); - snd_soc_dapm_enable_pin(codec, "Center/Sub"); - snd_soc_dapm_enable_pin(codec, "Rear-L/R"); - /* signal a DAPM event */ snd_soc_dapm_sync(codec); -- cgit v1.2.3 From 7e1aa1dcd0d886df72586e3a94b1a7382952f21f Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Thu, 29 Oct 2009 02:24:32 +0100 Subject: ASoC: CS4270: export de-emphasis filter as ALSA control The CS4270 codec features an de-emphasis filter for compensation of audio material filtered by an 50/15 uS algorithm. Not sure whether we should always enable it for 44100Hz sampling frequency, but it should at least be configurable by the user. Signed-off-by: Daniel Mack Acked-by: Timur Tabi Signed-off-by: Mark Brown --- sound/soc/codecs/cs4270.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index 59bb16d033d..565842dcfc6 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c @@ -520,6 +520,7 @@ static const struct snd_kcontrol_new cs4270_snd_controls[] = { SOC_SINGLE("Digital Sidetone Switch", CS4270_FORMAT, 5, 1, 0), SOC_SINGLE("Soft Ramp Switch", CS4270_TRANS, 6, 1, 0), SOC_SINGLE("Zero Cross Switch", CS4270_TRANS, 5, 1, 0), + SOC_SINGLE("De-emphasis filter", CS4270_TRANS, 0, 1, 0), SOC_SINGLE("Popguard Switch", CS4270_MODE, 0, 1, 1), SOC_SINGLE("Auto-Mute Switch", CS4270_MUTE, 5, 1, 0), SOC_DOUBLE("Master Capture Switch", CS4270_MUTE, 3, 4, 1, 1), -- cgit v1.2.3 From 86139a13ced74b3911c33940f0049b8f97bae07a Mon Sep 17 00:00:00 2001 From: Jari Vanhala Date: Thu, 29 Oct 2009 11:58:09 +0200 Subject: ASoC: TWL4030: Vibra motor stop fix when it is driven with audio This patch fixes vibrator playing incoherently, when driven with audio. There is something wrong in switch 3 at H-bridge and VIBRA_SET still affects PWM generator. Slowest value fixes things. Signed-off-by: Jari Vanhala Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 9163713a030..ccaeb366eb7 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -613,6 +613,13 @@ static int handsfreerpga_event(struct snd_soc_dapm_widget *w, return 0; } +static int vibramux_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + twl4030_write(w->codec, TWL4030_REG_VIBRA_SET, 0xff); + return 0; +} + static void headset_ramp(struct snd_soc_codec *codec, int ramp) { struct snd_soc_device *socdev = codec->socdev; @@ -1243,8 +1250,9 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { 0, 0, NULL, 0, handsfreerpga_event, SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD), /* Vibra */ - SND_SOC_DAPM_MUX("Vibra Mux", TWL4030_REG_VIBRA_CTL, 0, 0, - &twl4030_dapm_vibra_control), + SND_SOC_DAPM_MUX_E("Vibra Mux", TWL4030_REG_VIBRA_CTL, 0, 0, + &twl4030_dapm_vibra_control, vibramux_event, + SND_SOC_DAPM_PRE_PMU), SND_SOC_DAPM_MUX("Vibra Route", SND_SOC_NOPM, 0, 0, &twl4030_dapm_vibrapath_control), -- cgit v1.2.3 From 7729cf749350b04c80ee1652961de238afc9d5b1 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 29 Oct 2009 11:58:10 +0200 Subject: ASoC: TWL4030: Change APLL powering sequence It seams that certain part of the twl4030 codec needs the APLL enabled before they are enabled. Paths which has any digital processing needs need the APLL enabled before they can function. For example the vibra output will have some random data after it is enabled and before the APLL also enabled. If only analog components are in use (analog bypass), than it seams, that the APLL does not need to be enabled. This lowers the power consumption with around ~0.005A. Adding DAPM_SUPPLY to the Digital playback route and also to the capture route to enable and disable the APLL. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index ccaeb366eb7..277e99ce555 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -620,6 +620,20 @@ static int vibramux_event(struct snd_soc_dapm_widget *w, return 0; } +static int apll_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + twl4030_apll_enable(w->codec, 1); + break; + case SND_SOC_DAPM_POST_PMD: + twl4030_apll_enable(w->codec, 0); + break; + } + return 0; +} + static void headset_ramp(struct snd_soc_codec *codec, int ramp) { struct snd_soc_device *socdev = codec->socdev; @@ -1185,6 +1199,9 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { SND_SOC_DAPM_MIXER("Analog Voice Playback Mixer", TWL4030_REG_VDL_APGA_CTL, 0, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("APLL Enable", SND_SOC_NOPM, 0, 0, apll_event, + SND_SOC_DAPM_PRE_PMU|SND_SOC_DAPM_POST_PMD), + /* Output MIXER controls */ /* Earpiece */ SND_SOC_DAPM_MIXER("Earpiece Mixer", SND_SOC_NOPM, 0, 0, @@ -1312,6 +1329,13 @@ static const struct snd_soc_dapm_route intercon[] = { {"Digital R2 Playback Mixer", NULL, "DAC Right2"}, {"Digital Voice Playback Mixer", NULL, "DAC Voice"}, + /* Supply for the digital part (APLL) */ + {"Digital R1 Playback Mixer", NULL, "APLL Enable"}, + {"Digital L1 Playback Mixer", NULL, "APLL Enable"}, + {"Digital R2 Playback Mixer", NULL, "APLL Enable"}, + {"Digital L2 Playback Mixer", NULL, "APLL Enable"}, + {"Digital Voice Playback Mixer", NULL, "APLL Enable"}, + {"Analog L1 Playback Mixer", NULL, "Digital L1 Playback Mixer"}, {"Analog R1 Playback Mixer", NULL, "Digital R1 Playback Mixer"}, {"Analog L2 Playback Mixer", NULL, "Digital L2 Playback Mixer"}, @@ -1472,14 +1496,12 @@ static int twl4030_set_bias_level(struct snd_soc_codec *codec, { switch (level) { case SND_SOC_BIAS_ON: - twl4030_apll_enable(codec, 1); break; case SND_SOC_BIAS_PREPARE: break; case SND_SOC_BIAS_STANDBY: if (codec->bias_level == SND_SOC_BIAS_OFF) twl4030_power_up(codec); - twl4030_apll_enable(codec, 0); break; case SND_SOC_BIAS_OFF: twl4030_power_down(codec); -- cgit v1.2.3 From 1c3d20027133f145523a072e84ab55d9132920c9 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 29 Oct 2009 13:05:52 +0200 Subject: ASoC: TWL4030: Add APLL supply for the capture path Capture path also need the APLL enabled, adding DAPM_SUPPLY for the Virtual ADCs. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 277e99ce555..f9121ef7fe5 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -1449,6 +1449,11 @@ static const struct snd_soc_dapm_route intercon[] = { {"ADC Virtual Left2", NULL, "TX2 Capture Route"}, {"ADC Virtual Right2", NULL, "TX2 Capture Route"}, + {"ADC Virtual Left1", NULL, "APLL Enable"}, + {"ADC Virtual Right1", NULL, "APLL Enable"}, + {"ADC Virtual Left2", NULL, "APLL Enable"}, + {"ADC Virtual Right2", NULL, "APLL Enable"}, + /* Analog bypass routes */ {"Right1 Analog Loopback", "Switch", "Analog Right"}, {"Left1 Analog Loopback", "Switch", "Analog Left"}, -- cgit v1.2.3 From ed146aeb68b6b240a015f3c24c9eea9266d845ec Mon Sep 17 00:00:00 2001 From: Anuj Aggarwal Date: Wed, 23 Sep 2009 12:40:31 +0530 Subject: ASoC: OMAP3EVM: Use the twl4030_setup_data for headset pop-removal The pop-removal specific values are configured for TWL4030 codec for OMAP3EVM through this patch. Signed-off-by: Anuj Aggarwal Acked-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/omap/omap3evm.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'sound') diff --git a/sound/soc/omap/omap3evm.c b/sound/soc/omap/omap3evm.c index 9114c263077..8deb59bb10b 100644 --- a/sound/soc/omap/omap3evm.c +++ b/sound/soc/omap/omap3evm.c @@ -93,10 +93,17 @@ static struct snd_soc_card snd_soc_omap3evm = { .num_links = 1, }; +/* twl4030 setup */ +static struct twl4030_setup_data twl4030_setup = { + .ramp_delay_value = 4, + .sysclk = 26000, +}; + /* Audio subsystem */ static struct snd_soc_device omap3evm_snd_devdata = { .card = &snd_soc_omap3evm, .codec_dev = &soc_codec_dev_twl4030, + .codec_data = &twl4030_setup, }; static struct platform_device *omap3evm_snd_device; -- cgit v1.2.3 From 89e9abe78151de4d62fefe3976f6ef9f1f086e53 Mon Sep 17 00:00:00 2001 From: Anuj Aggarwal Date: Fri, 30 Oct 2009 00:22:30 +0530 Subject: ASoC: Adding OMAP3517 / AM3517 EVM support in ASOC Adding support for OMAP3517 / AM3517 EVM in Alsa SoC. Signed-off-by: Anuj Aggarwal Signed-off-by: Mark Brown --- sound/soc/omap/am3517evm.c | 202 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 202 insertions(+) create mode 100644 sound/soc/omap/am3517evm.c (limited to 'sound') diff --git a/sound/soc/omap/am3517evm.c b/sound/soc/omap/am3517evm.c new file mode 100644 index 00000000000..135901b2ea1 --- /dev/null +++ b/sound/soc/omap/am3517evm.c @@ -0,0 +1,202 @@ +/* + * am3517evm.c -- ALSA SoC support for OMAP3517 / AM3517 EVM + * + * Author: Anuj Aggarwal + * + * Based on sound/soc/omap/beagle.c by Steve Sakoman + * + * Copyright (C) 2009 Texas Instruments Incorporated + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, + * whether express or implied; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "omap-mcbsp.h" +#include "omap-pcm.h" + +#include "../codecs/tlv320aic23.h" + +#define CODEC_CLOCK 12000000 + +static int am3517evm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + int ret; + + /* Set codec DAI configuration */ + ret = snd_soc_dai_set_fmt(codec_dai, + SND_SOC_DAIFMT_DSP_B | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM); + if (ret < 0) { + printk(KERN_ERR "can't set codec DAI configuration\n"); + return ret; + } + + /* Set cpu DAI configuration */ + ret = snd_soc_dai_set_fmt(cpu_dai, + SND_SOC_DAIFMT_DSP_B | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM); + if (ret < 0) { + printk(KERN_ERR "can't set cpu DAI configuration\n"); + return ret; + } + + /* Set the codec system clock for DAC and ADC */ + ret = snd_soc_dai_set_sysclk(codec_dai, 0, + CODEC_CLOCK, SND_SOC_CLOCK_IN); + if (ret < 0) { + printk(KERN_ERR "can't set codec system clock\n"); + return ret; + } + + ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_MCBSP_CLKR_SRC_CLKX, 0, + SND_SOC_CLOCK_IN); + if (ret < 0) { + printk(KERN_ERR "can't set CPU system clock OMAP_MCBSP_CLKR_SRC_CLKX\n"); + return ret; + } + + snd_soc_dai_set_sysclk(cpu_dai, OMAP_MCBSP_FSR_SRC_FSX, 0, + SND_SOC_CLOCK_IN); + if (ret < 0) { + printk(KERN_ERR "can't set CPU system clock OMAP_MCBSP_FSR_SRC_FSX\n"); + return ret; + } + + return 0; +} + +static struct snd_soc_ops am3517evm_ops = { + .hw_params = am3517evm_hw_params, +}; + +/* am3517evm machine dapm widgets */ +static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = { + SND_SOC_DAPM_HP("Line Out", NULL), + SND_SOC_DAPM_LINE("Line In", NULL), + SND_SOC_DAPM_MIC("Mic In", NULL), +}; + +static const struct snd_soc_dapm_route audio_map[] = { + /* Line Out connected to LLOUT, RLOUT */ + {"Line Out", NULL, "LOUT"}, + {"Line Out", NULL, "ROUT"}, + + {"LLINEIN", NULL, "Line In"}, + {"RLINEIN", NULL, "Line In"}, + + {"MICIN", NULL, "Mic In"}, +}; + +static int am3517evm_aic23_init(struct snd_soc_codec *codec) +{ + /* Add am3517-evm specific widgets */ + snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets, + ARRAY_SIZE(tlv320aic23_dapm_widgets)); + + /* Set up davinci-evm specific audio path audio_map */ + snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); + + /* always connected */ + snd_soc_dapm_enable_pin(codec, "Line Out"); + snd_soc_dapm_enable_pin(codec, "Line In"); + snd_soc_dapm_enable_pin(codec, "Mic In"); + + snd_soc_dapm_sync(codec); + + return 0; +} + +/* Digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link am3517evm_dai = { + .name = "TLV320AIC23", + .stream_name = "AIC23", + .cpu_dai = &omap_mcbsp_dai[0], + .codec_dai = &tlv320aic23_dai, + .init = am3517evm_aic23_init, + .ops = &am3517evm_ops, +}; + +/* Audio machine driver */ +static struct snd_soc_card snd_soc_am3517evm = { + .name = "am3517evm", + .platform = &omap_soc_platform, + .dai_link = &am3517evm_dai, + .num_links = 1, +}; + +/* Audio subsystem */ +static struct snd_soc_device am3517evm_snd_devdata = { + .card = &snd_soc_am3517evm, + .codec_dev = &soc_codec_dev_tlv320aic23, +}; + +static struct platform_device *am3517evm_snd_device; + +static int __init am3517evm_soc_init(void) +{ + int ret; + + if (!machine_is_omap3517evm()) { + pr_err("Not OMAP3517 / AM3517 EVM!\n"); + return -ENODEV; + } + pr_info("OMAP3517 / AM3517 EVM SoC init\n"); + + am3517evm_snd_device = platform_device_alloc("soc-audio", -1); + if (!am3517evm_snd_device) { + printk(KERN_ERR "Platform device allocation failed\n"); + return -ENOMEM; + } + + platform_set_drvdata(am3517evm_snd_device, &am3517evm_snd_devdata); + am3517evm_snd_devdata.dev = &am3517evm_snd_device->dev; + *(unsigned int *)am3517evm_dai.cpu_dai->private_data = 0; /* McBSP1 */ + + ret = platform_device_add(am3517evm_snd_device); + if (ret) + goto err1; + + return 0; + +err1: + printk(KERN_ERR "Unable to add platform device\n"); + platform_device_put(am3517evm_snd_device); + + return ret; +} + +static void __exit am3517evm_soc_exit(void) +{ + platform_device_unregister(am3517evm_snd_device); +} + +module_init(am3517evm_soc_init); +module_exit(am3517evm_soc_exit); + +MODULE_AUTHOR("Anuj Aggarwal "); +MODULE_DESCRIPTION("ALSA SoC OMAP3517 / AM3517 EVM"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 67e646cd7b51e1d5847fb506d4419d436ea25fda Mon Sep 17 00:00:00 2001 From: Anuj Aggarwal Date: Fri, 30 Oct 2009 00:22:39 +0530 Subject: ASoC: Modifying Kconfig/Makefile for AM3517 EVM Modifying the Kconfig and Makefile in sound/soc/omap folder to add support for OMAP3517 / AM3517 EVM in Alsa SoC. Signed-off-by: Anuj Aggarwal Signed-off-by: Mark Brown --- sound/soc/omap/Kconfig | 9 +++++++++ sound/soc/omap/Makefile | 2 ++ 2 files changed, 11 insertions(+) (limited to 'sound') diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index 2dee9839be8..6344456e7a0 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig @@ -55,6 +55,15 @@ config SND_OMAP_SOC_OMAP3EVM help Say Y if you want to add support for SoC audio on the omap3evm board. +config SND_OMAP_SOC_AM3517EVM + tristate "SoC Audio support for OMAP3517 / AM3517 EVM" + depends on SND_OMAP_SOC && MACH_OMAP3517EVM && I2C + select SND_OMAP_SOC_MCBSP + select SND_SOC_TLV320AIC23 + help + Say Y if you want to add support for SoC audio on the OMAP3517 / AM3517 + EVM. + config SND_OMAP_SOC_SDP3430 tristate "SoC Audio support for Texas Instruments SDP3430" depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP_3430SDP diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile index 02d69471dcb..0c78ae4e6b9 100644 --- a/sound/soc/omap/Makefile +++ b/sound/soc/omap/Makefile @@ -12,6 +12,7 @@ snd-soc-osk5912-objs := osk5912.o snd-soc-overo-objs := overo.o snd-soc-omap2evm-objs := omap2evm.o snd-soc-omap3evm-objs := omap3evm.o +snd-soc-am3517evm-objs := am3517evm.o snd-soc-sdp3430-objs := sdp3430.o snd-soc-omap3pandora-objs := omap3pandora.o snd-soc-omap3beagle-objs := omap3beagle.o @@ -23,6 +24,7 @@ obj-$(CONFIG_SND_OMAP_SOC_OSK5912) += snd-soc-osk5912.o obj-$(CONFIG_SND_OMAP_SOC_OVERO) += snd-soc-overo.o obj-$(CONFIG_MACH_OMAP2EVM) += snd-soc-omap2evm.o obj-$(CONFIG_MACH_OMAP3EVM) += snd-soc-omap3evm.o +obj-$(CONFIG_MACH_OMAP3517EVM) += snd-soc-am3517evm.o obj-$(CONFIG_SND_OMAP_SOC_SDP3430) += snd-soc-sdp3430.o obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o obj-$(CONFIG_SND_OMAP_SOC_OMAP3_BEAGLE) += snd-soc-omap3beagle.o -- cgit v1.2.3 From 9ddc9aa910687a8787dbbdc53dcd48e738b197d9 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 30 Oct 2009 12:02:39 +0900 Subject: ASoC: sh: FSI: Remove DMA support SuperH FSI device have the hardware limitation to use DMA. If DMA is used, LCD output will be broken. Maybe there are some solution. But I don't know how to do it now. This patch remove DMA support and use soft transfer. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/Kconfig | 1 - sound/soc/sh/fsi.c | 141 ++++++++------------------------------------------- 2 files changed, 20 insertions(+), 122 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig index 9154b4363db..9e697658655 100644 --- a/sound/soc/sh/Kconfig +++ b/sound/soc/sh/Kconfig @@ -23,7 +23,6 @@ config SND_SOC_SH4_SSI config SND_SOC_SH4_FSI tristate "SH4 FSI support" depends on CPU_SUBTYPE_SH7724 - select SH_DMA help This option enables FSI sound support diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 44123248b63..9742a280ba1 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -26,8 +26,6 @@ #include #include #include -#include -#include #define DO_FMT 0x0000 #define DOFF_CTL 0x0004 @@ -97,7 +95,6 @@ struct fsi_priv { int fifo_max; int chan; - int dma_chan; int byte_offset; int period_len; @@ -308,62 +305,6 @@ static int fsi_get_fifo_residue(struct fsi_priv *fsi, int is_play) return residue; } -static int fsi_get_residue(struct fsi_priv *fsi, int is_play) -{ - int residue; - int width; - struct snd_pcm_runtime *runtime; - - runtime = fsi->substream->runtime; - - /* get 1 channel data width */ - width = frames_to_bytes(runtime, 1) / fsi->chan; - - if (2 == width) - residue = fsi_get_fifo_residue(fsi, is_play); - else - residue = get_dma_residue(fsi->dma_chan); - - return residue; -} - -/************************************************************************ - - - basic dma function - - -************************************************************************/ -#define PORTA_DMA 0 -#define PORTB_DMA 1 - -static int fsi_get_dma_chan(void) -{ - if (0 != request_dma(PORTA_DMA, "fsia")) - return -EIO; - - if (0 != request_dma(PORTB_DMA, "fsib")) { - free_dma(PORTA_DMA); - return -EIO; - } - - master->fsia.dma_chan = PORTA_DMA; - master->fsib.dma_chan = PORTB_DMA; - - return 0; -} - -static void fsi_free_dma_chan(void) -{ - dma_wait_for_completion(PORTA_DMA); - dma_wait_for_completion(PORTB_DMA); - free_dma(PORTA_DMA); - free_dma(PORTB_DMA); - - master->fsia.dma_chan = -1; - master->fsib.dma_chan = -1; -} - /************************************************************************ @@ -435,44 +376,6 @@ static void fsi_soft_all_reset(void) mdelay(10); } -static void fsi_16data_push(struct fsi_priv *fsi, - struct snd_pcm_runtime *runtime, - int send) -{ - u16 *dma_start; - u32 snd; - int i; - - /* get dma start position for FSI */ - dma_start = (u16 *)runtime->dma_area; - dma_start += fsi->byte_offset / 2; - - /* - * soft dma - * FSI can not use DMA when 16bpp - */ - for (i = 0; i < send; i++) { - snd = (u32)dma_start[i]; - fsi_reg_write(fsi, DODT, snd << 8); - } -} - -static void fsi_32data_push(struct fsi_priv *fsi, - struct snd_pcm_runtime *runtime, - int send) -{ - u32 *dma_start; - - /* get dma start position for FSI */ - dma_start = (u32 *)runtime->dma_area; - dma_start += fsi->byte_offset / 4; - - dma_wait_for_completion(fsi->dma_chan); - dma_configure_channel(fsi->dma_chan, (SM_INC|0x400|TS_32|TM_BUR)); - dma_write(fsi->dma_chan, (u32)dma_start, - (u32)(fsi->base + DODT), send * 4); -} - /* playback interrupt */ static int fsi_data_push(struct fsi_priv *fsi) { @@ -481,6 +384,8 @@ static int fsi_data_push(struct fsi_priv *fsi) int send; int fifo_free; int width; + u8 *start; + int i; if (!fsi || !fsi->substream || @@ -515,12 +420,22 @@ static int fsi_data_push(struct fsi_priv *fsi) if (fifo_free < send) send = fifo_free; - if (2 == width) - fsi_16data_push(fsi, runtime, send); - else if (4 == width) - fsi_32data_push(fsi, runtime, send); - else + start = runtime->dma_area; + start += fsi->byte_offset; + + switch (width) { + case 2: + for (i = 0; i < send; i++) + fsi_reg_write(fsi, DODT, + ((u32)*((u16 *)start + i) << 8)); + break; + case 4: + for (i = 0; i < send; i++) + fsi_reg_write(fsi, DODT, *((u32 *)start + i)); + break; + default: return -EINVAL; + } fsi->byte_offset += send * width; @@ -664,8 +579,6 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream, } fsi_reg_write(fsi, reg, data); - dev_dbg(dai->dev, "use %s format (%d channel) use %d DMAC\n", - msg, fsi->chan, fsi->dma_chan); /* * clear clk reset if master mode @@ -780,10 +693,9 @@ static snd_pcm_uframes_t fsi_pointer(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct fsi_priv *fsi = fsi_get(substream); - int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; long location; - location = (fsi->byte_offset - 1) - fsi_get_residue(fsi, is_play); + location = (fsi->byte_offset - 1); if (location < 0) location = 0; @@ -912,22 +824,13 @@ static int fsi_probe(struct platform_device *pdev) master->fsia.base = master->base; master->fsib.base = master->base + 0x40; - master->fsia.dma_chan = -1; - master->fsib.dma_chan = -1; - - ret = fsi_get_dma_chan(); - if (ret < 0) { - dev_err(&pdev->dev, "cannot get dma api\n"); - goto exit_iounmap; - } - /* FSI is based on SPU mstp */ snprintf(clk_name, sizeof(clk_name), "spu%d", pdev->id); master->clk = clk_get(NULL, clk_name); if (IS_ERR(master->clk)) { dev_err(&pdev->dev, "cannot get %s mstp\n", clk_name); ret = -EIO; - goto exit_free_dma; + goto exit_iounmap; } fsi_soc_dai[0].dev = &pdev->dev; @@ -938,7 +841,7 @@ static int fsi_probe(struct platform_device *pdev) ret = request_irq(irq, &fsi_interrupt, IRQF_DISABLED, "fsi", master); if (ret) { dev_err(&pdev->dev, "irq request err\n"); - goto exit_free_dma; + goto exit_iounmap; } ret = snd_soc_register_platform(&fsi_soc_platform); @@ -951,8 +854,6 @@ static int fsi_probe(struct platform_device *pdev) exit_free_irq: free_irq(irq, master); -exit_free_dma: - fsi_free_dma_chan(); exit_iounmap: iounmap(master->base); exit_kfree: @@ -969,8 +870,6 @@ static int fsi_remove(struct platform_device *pdev) clk_put(master->clk); - fsi_free_dma_chan(); - free_irq(master->irq, master); iounmap(master->base); -- cgit v1.2.3 From 07102f3cefc93aa742af91186830e282c0347e41 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 30 Oct 2009 12:02:44 +0900 Subject: ASoC: sh: FSI: Add capture support Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/fsi.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 86 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 9742a280ba1..e1a3d1a2b4c 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -447,6 +447,75 @@ static int fsi_data_push(struct fsi_priv *fsi) return 0; } +static int fsi_data_pop(struct fsi_priv *fsi) +{ + struct snd_pcm_runtime *runtime; + struct snd_pcm_substream *substream = NULL; + int free; + int fifo_fill; + int width; + u8 *start; + int i; + + if (!fsi || + !fsi->substream || + !fsi->substream->runtime) + return -EINVAL; + + runtime = fsi->substream->runtime; + + /* FSI FIFO has limit. + * So, this driver can not send periods data at a time + */ + if (fsi->byte_offset >= + fsi->period_len * (fsi->periods + 1)) { + + substream = fsi->substream; + fsi->periods = (fsi->periods + 1) % runtime->periods; + + if (0 == fsi->periods) + fsi->byte_offset = 0; + } + + /* get 1 channel data width */ + width = frames_to_bytes(runtime, 1) / fsi->chan; + + /* get free space for alsa */ + free = (fsi->buffer_len - fsi->byte_offset) / width; + + /* get recv size */ + fifo_fill = fsi_get_fifo_residue(fsi, 0); + + if (free < fifo_fill) + fifo_fill = free; + + start = runtime->dma_area; + start += fsi->byte_offset; + + switch (width) { + case 2: + for (i = 0; i < fifo_fill; i++) + *((u16 *)start + i) = + (u16)(fsi_reg_read(fsi, DIDT) >> 8); + break; + case 4: + for (i = 0; i < fifo_fill; i++) + *((u32 *)start + i) = fsi_reg_read(fsi, DIDT); + break; + default: + return -EINVAL; + } + + fsi->byte_offset += fifo_fill * width; + + fsi_irq_enable(fsi, 0); + + if (substream) + snd_pcm_period_elapsed(substream); + + return 0; +} + static irqreturn_t fsi_interrupt(int irq, void *data) { u32 status = fsi_master_read(SOFT_RST) & ~0x00000010; @@ -460,6 +529,10 @@ static irqreturn_t fsi_interrupt(int irq, void *data) fsi_data_push(&master->fsia); if (int_st & INT_B_OUT) fsi_data_push(&master->fsib); + if (int_st & INT_A_IN) + fsi_data_pop(&master->fsia); + if (int_st & INT_B_IN) + fsi_data_pop(&master->fsib); fsi_master_write(INT_ST, 0x0000000); @@ -612,16 +685,12 @@ static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd, int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; int ret = 0; - /* capture not supported */ - if (!is_play) - return -ENODEV; - switch (cmd) { case SNDRV_PCM_TRIGGER_START: fsi_stream_push(fsi, substream, frames_to_bytes(runtime, runtime->buffer_size), frames_to_bytes(runtime, runtime->period_size)); - ret = fsi_data_push(fsi); + ret = is_play ? fsi_data_push(fsi) : fsi_data_pop(fsi); break; case SNDRV_PCM_TRIGGER_STOP: fsi_irq_disable(fsi, is_play); @@ -757,7 +826,12 @@ struct snd_soc_dai fsi_soc_dai[] = { .channels_min = 1, .channels_max = 8, }, - /* capture not supported */ + .capture = { + .rates = FSI_RATES, + .formats = FSI_FMTS, + .channels_min = 1, + .channels_max = 8, + }, .ops = &fsi_dai_ops, }, { @@ -769,7 +843,12 @@ struct snd_soc_dai fsi_soc_dai[] = { .channels_min = 1, .channels_max = 8, }, - /* capture not supported */ + .capture = { + .rates = FSI_RATES, + .formats = FSI_FMTS, + .channels_min = 1, + .channels_max = 8, + }, .ops = &fsi_dai_ops, }, }; -- cgit v1.2.3 From 8538a119bfb9031c402a33fc65c276ab9bfafdd5 Mon Sep 17 00:00:00 2001 From: Eero Nurkkala Date: Fri, 30 Oct 2009 13:34:02 +0200 Subject: ASoC: remove io_mutex Remove the io_mutex. It has a drawback of serializing all accesses to snd_soc_update_bits() even when multiple codecs are in use. In addition, it fails to actually do its task - during snd_soc_update_bits(), dapm_update_bits() may also be accessing the same register which may result in an outdated register value. Signed-off-by: Eero Nurkkala Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 2d190df9fcc..025c5a7f8b7 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -37,7 +37,6 @@ #include static DEFINE_MUTEX(pcm_mutex); -static DEFINE_MUTEX(io_mutex); static DECLARE_WAIT_QUEUE_HEAD(soc_pm_waitq); #ifdef CONFIG_DEBUG_FS @@ -1346,14 +1345,12 @@ int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg, int change; unsigned int old, new; - mutex_lock(&io_mutex); old = snd_soc_read(codec, reg); new = (old & ~mask) | value; change = old != new; if (change) snd_soc_write(codec, reg, new); - mutex_unlock(&io_mutex); return change; } EXPORT_SYMBOL_GPL(snd_soc_update_bits); @@ -1376,11 +1373,9 @@ int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg, int change; unsigned int old, new; - mutex_lock(&io_mutex); old = snd_soc_read(codec, reg); new = (old & ~mask) | value; change = old != new; - mutex_unlock(&io_mutex); return change; } -- cgit v1.2.3 From 6c508c62f90240ef58300a5e12093ee769a44364 Mon Sep 17 00:00:00 2001 From: Eero Nurkkala Date: Fri, 30 Oct 2009 13:34:03 +0200 Subject: ASoC: refactor snd_soc_update_bits() Introduce a wrapper call snd_soc_update_bits_locked() that will take the codec mutex. This call is used when the codec mutex is not already taken. Drivers calling snd_soc_update_bits() may wish to make sure the codec mutex is taken from the driver. Signed-off-by: Eero Nurkkala Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 025c5a7f8b7..6e24654194e 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1355,6 +1355,30 @@ int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg, } EXPORT_SYMBOL_GPL(snd_soc_update_bits); +/** + * snd_soc_update_bits_locked - update codec register bits + * @codec: audio codec + * @reg: codec register + * @mask: register mask + * @value: new value + * + * Writes new register value, and takes the codec mutex. + * + * Returns 1 for change else 0. + */ +static int snd_soc_update_bits_locked(struct snd_soc_codec *codec, + unsigned short reg, unsigned int mask, + unsigned int value) +{ + int change; + + mutex_lock(&codec->mutex); + change = snd_soc_update_bits(codec, reg, mask, value); + mutex_unlock(&codec->mutex); + + return change; +} + /** * snd_soc_test_bits - test register for change * @codec: audio codec @@ -1706,7 +1730,7 @@ int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol, mask |= (bitmask - 1) << e->shift_r; } - return snd_soc_update_bits(codec, e->reg, mask, val); + return snd_soc_update_bits_locked(codec, e->reg, mask, val); } EXPORT_SYMBOL_GPL(snd_soc_put_enum_double); @@ -1780,7 +1804,7 @@ int snd_soc_put_value_enum_double(struct snd_kcontrol *kcontrol, mask |= e->mask << e->shift_r; } - return snd_soc_update_bits(codec, e->reg, mask, val); + return snd_soc_update_bits_locked(codec, e->reg, mask, val); } EXPORT_SYMBOL_GPL(snd_soc_put_value_enum_double); @@ -1941,7 +1965,7 @@ int snd_soc_put_volsw(struct snd_kcontrol *kcontrol, val_mask |= mask << rshift; val |= val2 << rshift; } - return snd_soc_update_bits(codec, reg, val_mask, val); + return snd_soc_update_bits_locked(codec, reg, val_mask, val); } EXPORT_SYMBOL_GPL(snd_soc_put_volsw); @@ -2047,11 +2071,11 @@ int snd_soc_put_volsw_2r(struct snd_kcontrol *kcontrol, val = val << shift; val2 = val2 << shift; - err = snd_soc_update_bits(codec, reg, val_mask, val); + err = snd_soc_update_bits_locked(codec, reg, val_mask, val); if (err < 0) return err; - err = snd_soc_update_bits(codec, reg2, val_mask, val2); + err = snd_soc_update_bits_locked(codec, reg2, val_mask, val2); return err; } EXPORT_SYMBOL_GPL(snd_soc_put_volsw_2r); @@ -2130,7 +2154,7 @@ int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol, val = (ucontrol->value.integer.value[0]+min) & 0xff; val |= ((ucontrol->value.integer.value[1]+min) & 0xff) << 8; - return snd_soc_update_bits(codec, reg, 0xffff, val); + return snd_soc_update_bits_locked(codec, reg, 0xffff, val); } EXPORT_SYMBOL_GPL(snd_soc_put_volsw_s8); -- cgit v1.2.3 From 0d488234fd857aae07f1c56467bbf58f1a859753 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sat, 24 Oct 2009 21:43:03 +0200 Subject: ALSA: pcmcia: use dynamic debug infrastructure, deprecate CS_CHECK (sound) Convert PCMCIA drivers to use the dynamic debug infrastructure, instead of requiring manual settings of PCMCIA_DEBUG. Also, remove all usages of the CS_CHECK macro and replace them with proper Linux style calling and return value checking. The extra error reporting may be dropped, as the PCMCIA core already complains about any (non-driver-author) errors. Signed-off-by: Dominik Brodowski Signed-off-by: Takashi Iwai --- sound/pcmcia/pdaudiocf/pdaudiocf.c | 21 ++++++++++++--------- sound/pcmcia/vx/vxpocket.c | 21 ++++++++++++--------- 2 files changed, 24 insertions(+), 18 deletions(-) (limited to 'sound') diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf.c b/sound/pcmcia/pdaudiocf/pdaudiocf.c index 7dea74b71cf..64b859925c0 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf.c @@ -217,20 +217,25 @@ static void snd_pdacf_detach(struct pcmcia_device *link) * configuration callback */ -#define CS_CHECK(fn, ret) \ -do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) - static int pdacf_config(struct pcmcia_device *link) { struct snd_pdacf *pdacf = link->priv; - int last_fn, last_ret; + int ret; snd_printdd(KERN_DEBUG "pdacf_config called\n"); link->conf.ConfigIndex = 0x5; - CS_CHECK(RequestIO, pcmcia_request_io(link, &link->io)); - CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); - CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); + ret = pcmcia_request_io(link, &link->io); + if (ret) + goto failed; + + ret = pcmcia_request_irq(link, &link->irq); + if (ret) + goto failed; + + ret = pcmcia_request_configuration(link, &link->conf); + if (ret) + goto failed; if (snd_pdacf_assign_resources(pdacf, link->io.BasePort1, link->irq.AssignedIRQ) < 0) goto failed; @@ -238,8 +243,6 @@ static int pdacf_config(struct pcmcia_device *link) link->dev_node = &pdacf->node; return 0; -cs_failed: - cs_error(link, last_fn, last_ret); failed: pcmcia_disable_device(link); return -ENODEV; diff --git a/sound/pcmcia/vx/vxpocket.c b/sound/pcmcia/vx/vxpocket.c index 7445cc8a47d..1492744ad67 100644 --- a/sound/pcmcia/vx/vxpocket.c +++ b/sound/pcmcia/vx/vxpocket.c @@ -213,14 +213,11 @@ static int snd_vxpocket_assign_resources(struct vx_core *chip, int port, int irq * configuration callback */ -#define CS_CHECK(fn, ret) \ -do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) - static int vxpocket_config(struct pcmcia_device *link) { struct vx_core *chip = link->priv; struct snd_vxpocket *vxp = (struct snd_vxpocket *)chip; - int last_fn, last_ret; + int ret; snd_printdd(KERN_DEBUG "vxpocket_config called\n"); @@ -235,9 +232,17 @@ static int vxpocket_config(struct pcmcia_device *link) strcpy(chip->card->driver, vxp440_hw.name); } - CS_CHECK(RequestIO, pcmcia_request_io(link, &link->io)); - CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); - CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); + ret = pcmcia_request_io(link, &link->io); + if (ret) + goto failed; + + ret = pcmcia_request_irq(link, &link->irq); + if (ret) + goto failed; + + ret = pcmcia_request_configuration(link, &link->conf); + if (ret) + goto failed; chip->dev = &handle_to_dev(link); snd_card_set_dev(chip->card, chip->dev); @@ -248,8 +253,6 @@ static int vxpocket_config(struct pcmcia_device *link) link->dev_node = &vxp->node; return 0; -cs_failed: - cs_error(link, last_fn, last_ret); failed: pcmcia_disable_device(link); return -ENODEV; -- cgit v1.2.3 From 0f83d639d84c99a775c60696dbde77372c2cf4ac Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Sat, 31 Oct 2009 20:15:08 +0100 Subject: ASoC: au1x: convert to platform drivers. Convert psc-ac97,i2s to platform drivers similar to the davinci ones. Signed-off-by: Manuel Lauss Signed-off-by: Mark Brown --- sound/soc/au1x/dbdma2.c | 117 +++++++++++++++++++++++----- sound/soc/au1x/psc-ac97.c | 194 ++++++++++++++++++++++++++++------------------ sound/soc/au1x/psc-i2s.c | 189 +++++++++++++++++++++++++++----------------- sound/soc/au1x/psc.h | 7 +- 4 files changed, 344 insertions(+), 163 deletions(-) (limited to 'sound') diff --git a/sound/soc/au1x/dbdma2.c b/sound/soc/au1x/dbdma2.c index 594c6c5b783..fe9f4657c95 100644 --- a/sound/soc/au1x/dbdma2.c +++ b/sound/soc/au1x/dbdma2.c @@ -2,7 +2,7 @@ * Au12x0/Au1550 PSC ALSA ASoC audio support. * * (c) 2007-2008 MSC Vertriebsges.m.b.H., - * Manuel Lauss + * Manuel Lauss * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -332,6 +332,30 @@ static int au1xpsc_pcm_new(struct snd_card *card, } static int au1xpsc_pcm_probe(struct platform_device *pdev) +{ + if (!au1xpsc_audio_pcmdma[PCM_TX] || !au1xpsc_audio_pcmdma[PCM_RX]) + return -ENODEV; + + return 0; +} + +static int au1xpsc_pcm_remove(struct platform_device *pdev) +{ + return 0; +} + +/* au1xpsc audio platform */ +struct snd_soc_platform au1xpsc_soc_platform = { + .name = "au1xpsc-pcm-dbdma", + .probe = au1xpsc_pcm_probe, + .remove = au1xpsc_pcm_remove, + .pcm_ops = &au1xpsc_pcm_ops, + .pcm_new = au1xpsc_pcm_new, + .pcm_free = au1xpsc_pcm_free_dma_buffers, +}; +EXPORT_SYMBOL_GPL(au1xpsc_soc_platform); + +static int __devinit au1xpsc_pcm_drvprobe(struct platform_device *pdev) { struct resource *r; int ret; @@ -365,7 +389,9 @@ static int au1xpsc_pcm_probe(struct platform_device *pdev) } (au1xpsc_audio_pcmdma[PCM_RX])->ddma_id = r->start; - return 0; + ret = snd_soc_register_platform(&au1xpsc_soc_platform); + if (!ret) + return ret; out2: kfree(au1xpsc_audio_pcmdma[PCM_RX]); @@ -376,10 +402,12 @@ out1: return ret; } -static int au1xpsc_pcm_remove(struct platform_device *pdev) +static int __devexit au1xpsc_pcm_drvremove(struct platform_device *pdev) { int i; + snd_soc_unregister_platform(&au1xpsc_soc_platform); + for (i = 0; i < 2; i++) { if (au1xpsc_audio_pcmdma[i]) { au1x_pcm_dbdma_free(au1xpsc_audio_pcmdma[i]); @@ -391,32 +419,83 @@ static int au1xpsc_pcm_remove(struct platform_device *pdev) return 0; } -/* au1xpsc audio platform */ -struct snd_soc_platform au1xpsc_soc_platform = { - .name = "au1xpsc-pcm-dbdma", - .probe = au1xpsc_pcm_probe, - .remove = au1xpsc_pcm_remove, - .pcm_ops = &au1xpsc_pcm_ops, - .pcm_new = au1xpsc_pcm_new, - .pcm_free = au1xpsc_pcm_free_dma_buffers, +static struct platform_driver au1xpsc_pcm_driver = { + .driver = { + .name = "au1xpsc-pcm", + .owner = THIS_MODULE, + }, + .probe = au1xpsc_pcm_drvprobe, + .remove = __devexit_p(au1xpsc_pcm_drvremove), }; -EXPORT_SYMBOL_GPL(au1xpsc_soc_platform); -static int __init au1xpsc_audio_dbdma_init(void) +static int __init au1xpsc_audio_dbdma_load(void) { au1xpsc_audio_pcmdma[PCM_TX] = NULL; au1xpsc_audio_pcmdma[PCM_RX] = NULL; - return snd_soc_register_platform(&au1xpsc_soc_platform); + return platform_driver_register(&au1xpsc_pcm_driver); } -static void __exit au1xpsc_audio_dbdma_exit(void) +static void __exit au1xpsc_audio_dbdma_unload(void) { - snd_soc_unregister_platform(&au1xpsc_soc_platform); + platform_driver_unregister(&au1xpsc_pcm_driver); +} + +module_init(au1xpsc_audio_dbdma_load); +module_exit(au1xpsc_audio_dbdma_unload); + + +struct platform_device *au1xpsc_pcm_add(struct platform_device *pdev) +{ + struct resource *res, *r; + struct platform_device *pd; + int id[2]; + int ret; + + r = platform_get_resource(pdev, IORESOURCE_DMA, 0); + if (!r) + return NULL; + id[0] = r->start; + + r = platform_get_resource(pdev, IORESOURCE_DMA, 1); + if (!r) + return NULL; + id[1] = r->start; + + res = kzalloc(sizeof(struct resource) * 2, GFP_KERNEL); + if (!res) + return NULL; + + res[0].start = res[0].end = id[0]; + res[1].start = res[1].end = id[1]; + res[0].flags = res[1].flags = IORESOURCE_DMA; + + pd = platform_device_alloc("au1xpsc-pcm", -1); + if (!pd) + goto out; + + pd->resource = res; + pd->num_resources = 2; + + ret = platform_device_add(pd); + if (!ret) + return pd; + +out: + kfree(res); + return NULL; } +EXPORT_SYMBOL_GPL(au1xpsc_pcm_add); -module_init(au1xpsc_audio_dbdma_init); -module_exit(au1xpsc_audio_dbdma_exit); +void au1xpsc_pcm_destroy(struct platform_device *dmapd) +{ + if (dmapd) { + kfree(dmapd->resource); + dmapd->resource = NULL; + platform_device_unregister(dmapd); + } +} +EXPORT_SYMBOL_GPL(au1xpsc_pcm_destroy); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Au12x0/Au1550 PSC Audio DMA driver"); -MODULE_AUTHOR("Manuel Lauss "); +MODULE_AUTHOR("Manuel Lauss"); diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c index 2a06a9c548a..340311d7fed 100644 --- a/sound/soc/au1x/psc-ac97.c +++ b/sound/soc/au1x/psc-ac97.c @@ -316,20 +316,56 @@ static int au1xpsc_ac97_trigger(struct snd_pcm_substream *substream, static int au1xpsc_ac97_probe(struct platform_device *pdev, struct snd_soc_dai *dai) +{ + return au1xpsc_ac97_workdata ? 0 : -ENODEV; +} + +static void au1xpsc_ac97_remove(struct platform_device *pdev, + struct snd_soc_dai *dai) +{ +} + +static struct snd_soc_dai_ops au1xpsc_ac97_dai_ops = { + .trigger = au1xpsc_ac97_trigger, + .hw_params = au1xpsc_ac97_hw_params, +}; + +struct snd_soc_dai au1xpsc_ac97_dai = { + .name = "au1xpsc_ac97", + .ac97_control = 1, + .probe = au1xpsc_ac97_probe, + .remove = au1xpsc_ac97_remove, + .playback = { + .rates = AC97_RATES, + .formats = AC97_FMTS, + .channels_min = 2, + .channels_max = 2, + }, + .capture = { + .rates = AC97_RATES, + .formats = AC97_FMTS, + .channels_min = 2, + .channels_max = 2, + }, + .ops = &au1xpsc_ac97_dai_ops, +}; +EXPORT_SYMBOL_GPL(au1xpsc_ac97_dai); + +static int __devinit au1xpsc_ac97_drvprobe(struct platform_device *pdev) { int ret; struct resource *r; unsigned long sel; + struct au1xpsc_audio_data *wd; if (au1xpsc_ac97_workdata) return -EBUSY; - au1xpsc_ac97_workdata = - kzalloc(sizeof(struct au1xpsc_audio_data), GFP_KERNEL); - if (!au1xpsc_ac97_workdata) + wd = kzalloc(sizeof(struct au1xpsc_audio_data), GFP_KERNEL); + if (!wd) return -ENOMEM; - mutex_init(&au1xpsc_ac97_workdata->lock); + mutex_init(&wd->lock); r = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!r) { @@ -338,81 +374,95 @@ static int au1xpsc_ac97_probe(struct platform_device *pdev, } ret = -EBUSY; - au1xpsc_ac97_workdata->ioarea = - request_mem_region(r->start, r->end - r->start + 1, + wd->ioarea = request_mem_region(r->start, r->end - r->start + 1, "au1xpsc_ac97"); - if (!au1xpsc_ac97_workdata->ioarea) + if (!wd->ioarea) goto out0; - au1xpsc_ac97_workdata->mmio = ioremap(r->start, 0xffff); - if (!au1xpsc_ac97_workdata->mmio) + wd->mmio = ioremap(r->start, 0xffff); + if (!wd->mmio) goto out1; /* configuration: max dma trigger threshold, enable ac97 */ - au1xpsc_ac97_workdata->cfg = PSC_AC97CFG_RT_FIFO8 | - PSC_AC97CFG_TT_FIFO8 | - PSC_AC97CFG_DE_ENABLE; + wd->cfg = PSC_AC97CFG_RT_FIFO8 | PSC_AC97CFG_TT_FIFO8 | + PSC_AC97CFG_DE_ENABLE; - /* preserve PSC clock source set up by platform (dev.platform_data - * is already occupied by soc layer) - */ - sel = au_readl(PSC_SEL(au1xpsc_ac97_workdata)) & PSC_SEL_CLK_MASK; - au_writel(PSC_CTRL_DISABLE, PSC_CTRL(au1xpsc_ac97_workdata)); + /* preserve PSC clock source set up by platform */ + sel = au_readl(PSC_SEL(wd)) & PSC_SEL_CLK_MASK; + au_writel(PSC_CTRL_DISABLE, PSC_CTRL(wd)); au_sync(); - au_writel(0, PSC_SEL(au1xpsc_ac97_workdata)); + au_writel(0, PSC_SEL(wd)); au_sync(); - au_writel(PSC_SEL_PS_AC97MODE | sel, PSC_SEL(au1xpsc_ac97_workdata)); + au_writel(PSC_SEL_PS_AC97MODE | sel, PSC_SEL(wd)); au_sync(); - /* next up: cold reset. Dont check for PSC-ready now since - * there may not be any codec clock yet. - */ - return 0; + ret = snd_soc_register_dai(&au1xpsc_ac97_dai); + if (ret) + goto out1; + + wd->dmapd = au1xpsc_pcm_add(pdev); + if (wd->dmapd) { + platform_set_drvdata(pdev, wd); + au1xpsc_ac97_workdata = wd; /* MDEV */ + return 0; + } + snd_soc_unregister_dai(&au1xpsc_ac97_dai); out1: - release_resource(au1xpsc_ac97_workdata->ioarea); - kfree(au1xpsc_ac97_workdata->ioarea); + release_resource(wd->ioarea); + kfree(wd->ioarea); out0: - kfree(au1xpsc_ac97_workdata); - au1xpsc_ac97_workdata = NULL; + kfree(wd); return ret; } -static void au1xpsc_ac97_remove(struct platform_device *pdev, - struct snd_soc_dai *dai) +static int __devexit au1xpsc_ac97_drvremove(struct platform_device *pdev) { + struct au1xpsc_audio_data *wd = platform_get_drvdata(pdev); + + if (wd->dmapd) + au1xpsc_pcm_destroy(wd->dmapd); + + snd_soc_unregister_dai(&au1xpsc_ac97_dai); + /* disable PSC completely */ - au_writel(0, AC97_CFG(au1xpsc_ac97_workdata)); + au_writel(0, AC97_CFG(wd)); au_sync(); - au_writel(PSC_CTRL_DISABLE, PSC_CTRL(au1xpsc_ac97_workdata)); + au_writel(PSC_CTRL_DISABLE, PSC_CTRL(wd)); au_sync(); - iounmap(au1xpsc_ac97_workdata->mmio); - release_resource(au1xpsc_ac97_workdata->ioarea); - kfree(au1xpsc_ac97_workdata->ioarea); - kfree(au1xpsc_ac97_workdata); - au1xpsc_ac97_workdata = NULL; + iounmap(wd->mmio); + release_resource(wd->ioarea); + kfree(wd->ioarea); + kfree(wd); + + au1xpsc_ac97_workdata = NULL; /* MDEV */ + + return 0; } -static int au1xpsc_ac97_suspend(struct snd_soc_dai *dai) +#ifdef CONFIG_PM +static int au1xpsc_ac97_drvsuspend(struct device *dev) { + struct au1xpsc_audio_data *wd = dev_get_drvdata(dev); + /* save interesting registers and disable PSC */ - au1xpsc_ac97_workdata->pm[0] = - au_readl(PSC_SEL(au1xpsc_ac97_workdata)); + wd->pm[0] = au_readl(PSC_SEL(wd)); - au_writel(0, AC97_CFG(au1xpsc_ac97_workdata)); + au_writel(0, AC97_CFG(wd)); au_sync(); - au_writel(PSC_CTRL_DISABLE, PSC_CTRL(au1xpsc_ac97_workdata)); + au_writel(PSC_CTRL_DISABLE, PSC_CTRL(wd)); au_sync(); return 0; } -static int au1xpsc_ac97_resume(struct snd_soc_dai *dai) +static int au1xpsc_ac97_drvresume(struct device *dev) { + struct au1xpsc_audio_data *wd = dev_get_drvdata(dev); + /* restore PSC clock config */ - au_writel(au1xpsc_ac97_workdata->pm[0] | PSC_SEL_PS_AC97MODE, - PSC_SEL(au1xpsc_ac97_workdata)); + au_writel(wd->pm[0] | PSC_SEL_PS_AC97MODE, PSC_SEL(wd)); au_sync(); /* after this point the ac97 core will cold-reset the codec. @@ -422,48 +472,44 @@ static int au1xpsc_ac97_resume(struct snd_soc_dai *dai) return 0; } -static struct snd_soc_dai_ops au1xpsc_ac97_dai_ops = { - .trigger = au1xpsc_ac97_trigger, - .hw_params = au1xpsc_ac97_hw_params, +static struct dev_pm_ops au1xpscac97_pmops = { + .suspend = au1xpsc_ac97_drvsuspend, + .resume = au1xpsc_ac97_drvresume, }; -struct snd_soc_dai au1xpsc_ac97_dai = { - .name = "au1xpsc_ac97", - .ac97_control = 1, - .probe = au1xpsc_ac97_probe, - .remove = au1xpsc_ac97_remove, - .suspend = au1xpsc_ac97_suspend, - .resume = au1xpsc_ac97_resume, - .playback = { - .rates = AC97_RATES, - .formats = AC97_FMTS, - .channels_min = 2, - .channels_max = 2, - }, - .capture = { - .rates = AC97_RATES, - .formats = AC97_FMTS, - .channels_min = 2, - .channels_max = 2, +#define AU1XPSCAC97_PMOPS &au1xpscac97_pmops + +#else + +#define AU1XPSCAC97_PMOPS NULL + +#endif + +static struct platform_driver au1xpsc_ac97_driver = { + .driver = { + .name = "au1xpsc_ac97", + .owner = THIS_MODULE, + .pm = AU1XPSCAC97_PMOPS, }, - .ops = &au1xpsc_ac97_dai_ops, + .probe = au1xpsc_ac97_drvprobe, + .remove = __devexit_p(au1xpsc_ac97_drvremove), }; -EXPORT_SYMBOL_GPL(au1xpsc_ac97_dai); -static int __init au1xpsc_ac97_init(void) +static int __init au1xpsc_ac97_load(void) { au1xpsc_ac97_workdata = NULL; - return snd_soc_register_dai(&au1xpsc_ac97_dai); + return platform_driver_register(&au1xpsc_ac97_driver); } -static void __exit au1xpsc_ac97_exit(void) +static void __exit au1xpsc_ac97_unload(void) { - snd_soc_unregister_dai(&au1xpsc_ac97_dai); + platform_driver_unregister(&au1xpsc_ac97_driver); } -module_init(au1xpsc_ac97_init); -module_exit(au1xpsc_ac97_exit); +module_init(au1xpsc_ac97_load); +module_exit(au1xpsc_ac97_unload); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Au12x0/Au1550 PSC AC97 ALSA ASoC audio driver"); -MODULE_AUTHOR("Manuel Lauss "); +MODULE_AUTHOR("Manuel Lauss"); + diff --git a/sound/soc/au1x/psc-i2s.c b/sound/soc/au1x/psc-i2s.c index bb589327ee3..0cf2ca61c77 100644 --- a/sound/soc/au1x/psc-i2s.c +++ b/sound/soc/au1x/psc-i2s.c @@ -2,7 +2,7 @@ * Au12x0/Au1550 PSC ALSA ASoC audio support. * * (c) 2007-2008 MSC Vertriebsges.m.b.H., - * Manuel Lauss + * Manuel Lauss * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -264,17 +264,53 @@ static int au1xpsc_i2s_trigger(struct snd_pcm_substream *substream, int cmd, static int au1xpsc_i2s_probe(struct platform_device *pdev, struct snd_soc_dai *dai) +{ + return au1xpsc_i2s_workdata ? 0 : -ENODEV; +} + +static void au1xpsc_i2s_remove(struct platform_device *pdev, + struct snd_soc_dai *dai) +{ +} + +static struct snd_soc_dai_ops au1xpsc_i2s_dai_ops = { + .trigger = au1xpsc_i2s_trigger, + .hw_params = au1xpsc_i2s_hw_params, + .set_fmt = au1xpsc_i2s_set_fmt, +}; + +struct snd_soc_dai au1xpsc_i2s_dai = { + .name = "au1xpsc_i2s", + .probe = au1xpsc_i2s_probe, + .remove = au1xpsc_i2s_remove, + .playback = { + .rates = AU1XPSC_I2S_RATES, + .formats = AU1XPSC_I2S_FMTS, + .channels_min = 2, + .channels_max = 8, /* 2 without external help */ + }, + .capture = { + .rates = AU1XPSC_I2S_RATES, + .formats = AU1XPSC_I2S_FMTS, + .channels_min = 2, + .channels_max = 8, /* 2 without external help */ + }, + .ops = &au1xpsc_i2s_dai_ops, +}; +EXPORT_SYMBOL(au1xpsc_i2s_dai); + +static int __init au1xpsc_i2s_drvprobe(struct platform_device *pdev) { struct resource *r; unsigned long sel; int ret; + struct au1xpsc_audio_data *wd; if (au1xpsc_i2s_workdata) return -EBUSY; - au1xpsc_i2s_workdata = - kzalloc(sizeof(struct au1xpsc_audio_data), GFP_KERNEL); - if (!au1xpsc_i2s_workdata) + wd = kzalloc(sizeof(struct au1xpsc_audio_data), GFP_KERNEL); + if (!wd) return -ENOMEM; r = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -284,131 +320,146 @@ static int au1xpsc_i2s_probe(struct platform_device *pdev, } ret = -EBUSY; - au1xpsc_i2s_workdata->ioarea = - request_mem_region(r->start, r->end - r->start + 1, + wd->ioarea = request_mem_region(r->start, r->end - r->start + 1, "au1xpsc_i2s"); - if (!au1xpsc_i2s_workdata->ioarea) + if (!wd->ioarea) goto out0; - au1xpsc_i2s_workdata->mmio = ioremap(r->start, 0xffff); - if (!au1xpsc_i2s_workdata->mmio) + wd->mmio = ioremap(r->start, 0xffff); + if (!wd->mmio) goto out1; /* preserve PSC clock source set up by platform (dev.platform_data * is already occupied by soc layer) */ - sel = au_readl(PSC_SEL(au1xpsc_i2s_workdata)) & PSC_SEL_CLK_MASK; - au_writel(PSC_CTRL_DISABLE, PSC_CTRL(au1xpsc_i2s_workdata)); + sel = au_readl(PSC_SEL(wd)) & PSC_SEL_CLK_MASK; + au_writel(PSC_CTRL_DISABLE, PSC_CTRL(wd)); au_sync(); - au_writel(PSC_SEL_PS_I2SMODE | sel, PSC_SEL(au1xpsc_i2s_workdata)); - au_writel(0, I2S_CFG(au1xpsc_i2s_workdata)); + au_writel(PSC_SEL_PS_I2SMODE | sel, PSC_SEL(wd)); + au_writel(0, I2S_CFG(wd)); au_sync(); /* preconfigure: set max rx/tx fifo depths */ - au1xpsc_i2s_workdata->cfg |= - PSC_I2SCFG_RT_FIFO8 | PSC_I2SCFG_TT_FIFO8; + wd->cfg |= PSC_I2SCFG_RT_FIFO8 | PSC_I2SCFG_TT_FIFO8; /* don't wait for I2S core to become ready now; clocks may not * be running yet; depending on clock input for PSC a wait might * time out. */ - return 0; + ret = snd_soc_register_dai(&au1xpsc_i2s_dai); + if (ret) + goto out1; + /* finally add the DMA device for this PSC */ + wd->dmapd = au1xpsc_pcm_add(pdev); + if (wd->dmapd) { + platform_set_drvdata(pdev, wd); + au1xpsc_i2s_workdata = wd; + return 0; + } + + snd_soc_unregister_dai(&au1xpsc_i2s_dai); out1: - release_resource(au1xpsc_i2s_workdata->ioarea); - kfree(au1xpsc_i2s_workdata->ioarea); + release_resource(wd->ioarea); + kfree(wd->ioarea); out0: - kfree(au1xpsc_i2s_workdata); - au1xpsc_i2s_workdata = NULL; + kfree(wd); return ret; } -static void au1xpsc_i2s_remove(struct platform_device *pdev, - struct snd_soc_dai *dai) +static int __devexit au1xpsc_i2s_drvremove(struct platform_device *pdev) { - au_writel(0, I2S_CFG(au1xpsc_i2s_workdata)); + struct au1xpsc_audio_data *wd = platform_get_drvdata(pdev); + + if (wd->dmapd) + au1xpsc_pcm_destroy(wd->dmapd); + + snd_soc_unregister_dai(&au1xpsc_i2s_dai); + + au_writel(0, I2S_CFG(wd)); au_sync(); - au_writel(PSC_CTRL_DISABLE, PSC_CTRL(au1xpsc_i2s_workdata)); + au_writel(PSC_CTRL_DISABLE, PSC_CTRL(wd)); au_sync(); - iounmap(au1xpsc_i2s_workdata->mmio); - release_resource(au1xpsc_i2s_workdata->ioarea); - kfree(au1xpsc_i2s_workdata->ioarea); - kfree(au1xpsc_i2s_workdata); - au1xpsc_i2s_workdata = NULL; + iounmap(wd->mmio); + release_resource(wd->ioarea); + kfree(wd->ioarea); + kfree(wd); + + au1xpsc_i2s_workdata = NULL; /* MDEV */ + + return 0; } -static int au1xpsc_i2s_suspend(struct snd_soc_dai *cpu_dai) +#ifdef CONFIG_PM +static int au1xpsc_i2s_drvsuspend(struct device *dev) { + struct au1xpsc_audio_data *wd = dev_get_drvdata(dev); + /* save interesting register and disable PSC */ - au1xpsc_i2s_workdata->pm[0] = - au_readl(PSC_SEL(au1xpsc_i2s_workdata)); + wd->pm[0] = au_readl(PSC_SEL(wd)); - au_writel(0, I2S_CFG(au1xpsc_i2s_workdata)); + au_writel(0, I2S_CFG(wd)); au_sync(); - au_writel(PSC_CTRL_DISABLE, PSC_CTRL(au1xpsc_i2s_workdata)); + au_writel(PSC_CTRL_DISABLE, PSC_CTRL(wd)); au_sync(); return 0; } -static int au1xpsc_i2s_resume(struct snd_soc_dai *cpu_dai) +static int au1xpsc_i2s_drvresume(struct device *dev) { + struct au1xpsc_audio_data *wd = dev_get_drvdata(dev); + /* select I2S mode and PSC clock */ - au_writel(PSC_CTRL_DISABLE, PSC_CTRL(au1xpsc_i2s_workdata)); + au_writel(PSC_CTRL_DISABLE, PSC_CTRL(wd)); au_sync(); - au_writel(0, PSC_SEL(au1xpsc_i2s_workdata)); + au_writel(0, PSC_SEL(wd)); au_sync(); - au_writel(au1xpsc_i2s_workdata->pm[0], - PSC_SEL(au1xpsc_i2s_workdata)); + au_writel(wd->pm[0], PSC_SEL(wd)); au_sync(); return 0; } -static struct snd_soc_dai_ops au1xpsc_i2s_dai_ops = { - .trigger = au1xpsc_i2s_trigger, - .hw_params = au1xpsc_i2s_hw_params, - .set_fmt = au1xpsc_i2s_set_fmt, +static struct dev_pm_ops au1xpsci2s_pmops = { + .suspend = au1xpsc_i2s_drvsuspend, + .resume = au1xpsc_i2s_drvresume, }; -struct snd_soc_dai au1xpsc_i2s_dai = { - .name = "au1xpsc_i2s", - .probe = au1xpsc_i2s_probe, - .remove = au1xpsc_i2s_remove, - .suspend = au1xpsc_i2s_suspend, - .resume = au1xpsc_i2s_resume, - .playback = { - .rates = AU1XPSC_I2S_RATES, - .formats = AU1XPSC_I2S_FMTS, - .channels_min = 2, - .channels_max = 8, /* 2 without external help */ - }, - .capture = { - .rates = AU1XPSC_I2S_RATES, - .formats = AU1XPSC_I2S_FMTS, - .channels_min = 2, - .channels_max = 8, /* 2 without external help */ +#define AU1XPSCI2S_PMOPS &au1xpsci2s_pmops + +#else + +#define AU1XPSCI2S_PMOPS NULL + +#endif + +static struct platform_driver au1xpsc_i2s_driver = { + .driver = { + .name = "au1xpsc_i2s", + .owner = THIS_MODULE, + .pm = AU1XPSCI2S_PMOPS, }, - .ops = &au1xpsc_i2s_dai_ops, + .probe = au1xpsc_i2s_drvprobe, + .remove = __devexit_p(au1xpsc_i2s_drvremove), }; -EXPORT_SYMBOL(au1xpsc_i2s_dai); -static int __init au1xpsc_i2s_init(void) +static int __init au1xpsc_i2s_load(void) { au1xpsc_i2s_workdata = NULL; - return snd_soc_register_dai(&au1xpsc_i2s_dai); + return platform_driver_register(&au1xpsc_i2s_driver); } -static void __exit au1xpsc_i2s_exit(void) +static void __exit au1xpsc_i2s_unload(void) { - snd_soc_unregister_dai(&au1xpsc_i2s_dai); + platform_driver_unregister(&au1xpsc_i2s_driver); } -module_init(au1xpsc_i2s_init); -module_exit(au1xpsc_i2s_exit); +module_init(au1xpsc_i2s_load); +module_exit(au1xpsc_i2s_unload); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Au12x0/Au1550 PSC I2S ALSA ASoC audio driver"); -MODULE_AUTHOR("Manuel Lauss "); +MODULE_AUTHOR("Manuel Lauss"); diff --git a/sound/soc/au1x/psc.h b/sound/soc/au1x/psc.h index 3f474e8ed4f..32d3807d3f5 100644 --- a/sound/soc/au1x/psc.h +++ b/sound/soc/au1x/psc.h @@ -2,7 +2,7 @@ * Au12x0/Au1550 PSC ALSA ASoC audio support. * * (c) 2007-2008 MSC Vertriebsges.m.b.H., - * Manuel Lauss + * Manuel Lauss * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -21,6 +21,10 @@ extern struct snd_soc_dai au1xpsc_i2s_dai; extern struct snd_soc_platform au1xpsc_soc_platform; extern struct snd_ac97_bus_ops soc_ac97_ops; +/* DBDMA helpers */ +extern struct platform_device *au1xpsc_pcm_add(struct platform_device *pdev); +extern void au1xpsc_pcm_destroy(struct platform_device *dmapd); + struct au1xpsc_audio_data { void __iomem *mmio; @@ -30,6 +34,7 @@ struct au1xpsc_audio_data { unsigned long pm[2]; struct resource *ioarea; struct mutex lock; + struct platform_device *dmapd; }; #define PCM_TX 0 -- cgit v1.2.3 From 23aebca486429b74c35b41ac5cac7ce97609fd6a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 2 Nov 2009 14:10:59 +0100 Subject: ALSA: dummy - Fix descriptions of pcm_substreams parameter Now up to 128 substreams are supported. Reported-by: Adrian Bridgett Signed-off-by: Takashi Iwai --- sound/drivers/dummy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c index 146ef00f94a..252e04ce602 100644 --- a/sound/drivers/dummy.c +++ b/sound/drivers/dummy.c @@ -165,7 +165,7 @@ MODULE_PARM_DESC(enable, "Enable this dummy soundcard."); module_param_array(pcm_devs, int, NULL, 0444); MODULE_PARM_DESC(pcm_devs, "PCM devices # (0-4) for dummy driver."); module_param_array(pcm_substreams, int, NULL, 0444); -MODULE_PARM_DESC(pcm_substreams, "PCM substreams # (1-16) for dummy driver."); +MODULE_PARM_DESC(pcm_substreams, "PCM substreams # (1-128) for dummy driver."); //module_param_array(midi_devs, int, NULL, 0444); //MODULE_PARM_DESC(midi_devs, "MIDI devices # (0-2) for dummy driver."); module_param(fake_buffer, bool, 0444); -- cgit v1.2.3 From 89933dee5b17c09f2673c2bfd853625a848f91f5 Mon Sep 17 00:00:00 2001 From: Neil Jones Date: Mon, 2 Nov 2009 15:14:17 +0000 Subject: ASoC: Add support for the WM8727 DAC. Add support for the Wolfson Microelectronics WM8727 DAC, this is a simple non-configurable DAC. Signed-off-by: Neil Jones Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 4 ++ sound/soc/codecs/Makefile | 2 + sound/soc/codecs/wm8727.c | 143 ++++++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/wm8727.h | 21 +++++++ 4 files changed, 170 insertions(+) create mode 100644 sound/soc/codecs/wm8727.c create mode 100644 sound/soc/codecs/wm8727.h (limited to 'sound') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 3df3497335b..4a3e8dcf24d 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -40,6 +40,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_WM8523 if I2C select SND_SOC_WM8580 if I2C select SND_SOC_WM8711 if SND_SOC_I2C_AND_SPI + select SND_SOC_WM8727 select SND_SOC_WM8728 if SND_SOC_I2C_AND_SPI select SND_SOC_WM8731 if SND_SOC_I2C_AND_SPI select SND_SOC_WM8750 if SND_SOC_I2C_AND_SPI @@ -174,6 +175,9 @@ config SND_SOC_WM8580 config SND_SOC_WM8711 tristate +config SND_SOC_WM8727 + tristate + config SND_SOC_WM8728 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 8f519ee9600..cacfc7692d7 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -27,6 +27,7 @@ snd-soc-wm8510-objs := wm8510.o snd-soc-wm8523-objs := wm8523.o snd-soc-wm8580-objs := wm8580.o snd-soc-wm8711-objs := wm8711.o +snd-soc-wm8727-objs := wm8727.o snd-soc-wm8728-objs := wm8728.o snd-soc-wm8731-objs := wm8731.o snd-soc-wm8750-objs := wm8750.o @@ -81,6 +82,7 @@ obj-$(CONFIG_SND_SOC_WM8510) += snd-soc-wm8510.o obj-$(CONFIG_SND_SOC_WM8523) += snd-soc-wm8523.o obj-$(CONFIG_SND_SOC_WM8580) += snd-soc-wm8580.o obj-$(CONFIG_SND_SOC_WM8711) += snd-soc-wm8711.o +obj-$(CONFIG_SND_SOC_WM8727) += snd-soc-wm8727.o obj-$(CONFIG_SND_SOC_WM8728) += snd-soc-wm8728.o obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o diff --git a/sound/soc/codecs/wm8727.c b/sound/soc/codecs/wm8727.c new file mode 100644 index 00000000000..b3b60dd7bc1 --- /dev/null +++ b/sound/soc/codecs/wm8727.c @@ -0,0 +1,143 @@ +/* + * wm8727.c + * + * Created on: 15-Oct-2009 + * Author: neil.jones@imgtec.com + * + * Copyright (C) 2009 Imagination Technologies Ltd. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wm8727.h" +/* + * Note this is a simple chip with no configuration interface, sample rate is + * determined automatically by examining the Master clock and Bit clock ratios + */ +#define WM8727_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\ + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |\ + SNDRV_PCM_RATE_192000) + + +struct snd_soc_dai wm8727_dai = { + .name = "WM8727", + .playback = { + .stream_name = "Playback", + .channels_min = 2, + .channels_max = 2, + .rates = WM8727_RATES, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, + }, +}; +EXPORT_SYMBOL_GPL(wm8727_dai); + +static int wm8727_soc_probe(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec; + int ret = 0; + + codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); + if (codec == NULL) + return -ENOMEM; + mutex_init(&codec->mutex); + codec->name = "WM8727"; + codec->owner = THIS_MODULE; + codec->dai = &wm8727_dai; + codec->num_dai = 1; + socdev->card->codec = codec; + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + + /* register pcms */ + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) { + printk(KERN_ERR "wm8727: failed to create pcms\n"); + goto pcm_err; + } + /* register card */ + ret = snd_soc_init_card(socdev); + if (ret < 0) { + printk(KERN_ERR "wm8727: failed to register card\n"); + goto register_err; + } + + return ret; + +register_err: + snd_soc_free_pcms(socdev); +pcm_err: + kfree(socdev->card->codec); + socdev->card->codec = NULL; + return ret; +} + +static int wm8727_soc_remove(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + + if (codec == NULL) + return 0; + snd_soc_free_pcms(socdev); + kfree(codec); + return 0; +} + +struct snd_soc_codec_device soc_codec_dev_wm8727 = { + .probe = wm8727_soc_probe, + .remove = wm8727_soc_remove, +}; +EXPORT_SYMBOL_GPL(soc_codec_dev_wm8727); + + +static __devinit int wm8727_platform_probe(struct platform_device *pdev) +{ + wm8727_dai.dev = &pdev->dev; + return snd_soc_register_dai(&wm8727_dai); +} + +static int __devexit wm8727_platform_remove(struct platform_device *pdev) +{ + snd_soc_unregister_dai(&wm8727_dai); + return 0; +} + +struct platform_driver wm8727_codec_driver = { + .driver = { + .name = "wm8727-codec", + .owner = THIS_MODULE, + }, + + .probe = wm8727_platform_probe, + .remove = __devexit_p(wm8727_platform_remove), +}; + +static int __init wm8727_init(void) +{ + return platform_driver_register(&wm8727_codec_driver); +} +module_init(wm8727_init); + +static void __exit wm8727_exit(void) +{ + platform_driver_unregister(&wm8727_codec_driver); +} +module_exit(wm8727_exit); + +MODULE_DESCRIPTION("ASoC wm8727 driver"); +MODULE_AUTHOR("Neil Jones"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8727.h b/sound/soc/codecs/wm8727.h new file mode 100644 index 00000000000..ee19aa71bcd --- /dev/null +++ b/sound/soc/codecs/wm8727.h @@ -0,0 +1,21 @@ +/* + * wm8727.h + * + * Created on: 15-Oct-2009 + * Author: neil.jones@imgtec.com + * + * Copyright (C) 2009 Imagination Technologies Ltd. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef WM8727_H_ +#define WM8727_H_ + +extern struct snd_soc_dai wm8727_dai; +extern struct snd_soc_codec_device soc_codec_dev_wm8727; + +#endif /* WM8727_H_ */ -- cgit v1.2.3 From b3f5a272a33ef06a37cd44703c46ec916b8a1c93 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 2 Nov 2009 14:34:54 +0200 Subject: ASoC: TWL4030: Make sure, that the codec is powered on startup Set the codec->bias_level to SND_SOC_BIAS_OFF before changing the initial bias level to STANDBY. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index f9121ef7fe5..c0b47dfc332 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -2234,6 +2234,7 @@ static int __devinit twl4030_codec_probe(struct platform_device *pdev) /* Set the defaults, and power up the codec */ twl4030_init_chip(codec); + codec->bias_level = SND_SOC_BIAS_OFF; twl4030_set_bias_level(codec, SND_SOC_BIAS_STANDBY); ret = snd_soc_register_codec(codec); -- cgit v1.2.3 From 529697c5463d941445db18e9526e7fc76a18e503 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 3 Nov 2009 22:13:30 +0000 Subject: ASoC: Staticise wm8727 driver structure Signed-off-by: Mark Brown --- sound/soc/codecs/wm8727.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm8727.c b/sound/soc/codecs/wm8727.c index b3b60dd7bc1..7df5a17eb73 100644 --- a/sound/soc/codecs/wm8727.c +++ b/sound/soc/codecs/wm8727.c @@ -116,7 +116,7 @@ static int __devexit wm8727_platform_remove(struct platform_device *pdev) return 0; } -struct platform_driver wm8727_codec_driver = { +static struct platform_driver wm8727_codec_driver = { .driver = { .name = "wm8727-codec", .owner = THIS_MODULE, -- cgit v1.2.3 From 2624d5fa67a5d3d720613a4ab0672e8c387ba806 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 3 Nov 2009 21:56:13 +0000 Subject: ASoC: Move sysfs and debugfs functions to head of soc-core.c A fairly hefty change in diff terms but no actual code changes, will be used by the next commit. Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 334 +++++++++++++++++++++++++-------------------------- 1 file changed, 167 insertions(+), 167 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 6e24654194e..d81a1618776 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -80,6 +80,173 @@ static int run_delayed_work(struct delayed_work *dwork) return ret; } +/* codec register dump */ +static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf) +{ + int i, step = 1, count = 0; + + if (!codec->reg_cache_size) + return 0; + + if (codec->reg_cache_step) + step = codec->reg_cache_step; + + count += sprintf(buf, "%s registers\n", codec->name); + for (i = 0; i < codec->reg_cache_size; i += step) { + if (codec->readable_register && !codec->readable_register(i)) + continue; + + count += sprintf(buf + count, "%2x: ", i); + if (count >= PAGE_SIZE - 1) + break; + + if (codec->display_register) + count += codec->display_register(codec, buf + count, + PAGE_SIZE - count, i); + else + count += snprintf(buf + count, PAGE_SIZE - count, + "%4x", codec->read(codec, i)); + + if (count >= PAGE_SIZE - 1) + break; + + count += snprintf(buf + count, PAGE_SIZE - count, "\n"); + if (count >= PAGE_SIZE - 1) + break; + } + + /* Truncate count; min() would cause a warning */ + if (count >= PAGE_SIZE) + count = PAGE_SIZE - 1; + + return count; +} +static ssize_t codec_reg_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct snd_soc_device *devdata = dev_get_drvdata(dev); + return soc_codec_reg_show(devdata->card->codec, buf); +} + +static DEVICE_ATTR(codec_reg, 0444, codec_reg_show, NULL); + +#ifdef CONFIG_DEBUG_FS +static int codec_reg_open_file(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t codec_reg_read_file(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + ssize_t ret; + struct snd_soc_codec *codec = file->private_data; + char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!buf) + return -ENOMEM; + ret = soc_codec_reg_show(codec, buf); + if (ret >= 0) + ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret); + kfree(buf); + return ret; +} + +static ssize_t codec_reg_write_file(struct file *file, + const char __user *user_buf, size_t count, loff_t *ppos) +{ + char buf[32]; + int buf_size; + char *start = buf; + unsigned long reg, value; + int step = 1; + struct snd_soc_codec *codec = file->private_data; + + buf_size = min(count, (sizeof(buf)-1)); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + buf[buf_size] = 0; + + if (codec->reg_cache_step) + step = codec->reg_cache_step; + + while (*start == ' ') + start++; + reg = simple_strtoul(start, &start, 16); + if ((reg >= codec->reg_cache_size) || (reg % step)) + return -EINVAL; + while (*start == ' ') + start++; + if (strict_strtoul(start, 16, &value)) + return -EINVAL; + codec->write(codec, reg, value); + return buf_size; +} + +static const struct file_operations codec_reg_fops = { + .open = codec_reg_open_file, + .read = codec_reg_read_file, + .write = codec_reg_write_file, +}; + +static void soc_init_codec_debugfs(struct snd_soc_codec *codec) +{ + char codec_root[128]; + + if (codec->dev) + snprintf(codec_root, sizeof(codec_root), + "%s.%s", codec->name, dev_name(codec->dev)); + else + snprintf(codec_root, sizeof(codec_root), + "%s", codec->name); + + codec->debugfs_codec_root = debugfs_create_dir(codec_root, + debugfs_root); + if (!codec->debugfs_codec_root) { + printk(KERN_WARNING + "ASoC: Failed to create codec debugfs directory\n"); + return; + } + + codec->debugfs_reg = debugfs_create_file("codec_reg", 0644, + codec->debugfs_codec_root, + codec, &codec_reg_fops); + if (!codec->debugfs_reg) + printk(KERN_WARNING + "ASoC: Failed to create codec register debugfs file\n"); + + codec->debugfs_pop_time = debugfs_create_u32("dapm_pop_time", 0744, + codec->debugfs_codec_root, + &codec->pop_time); + if (!codec->debugfs_pop_time) + printk(KERN_WARNING + "Failed to create pop time debugfs file\n"); + + codec->debugfs_dapm = debugfs_create_dir("dapm", + codec->debugfs_codec_root); + if (!codec->debugfs_dapm) + printk(KERN_WARNING + "Failed to create DAPM debugfs directory\n"); + + snd_soc_dapm_debugfs_init(codec); +} + +static void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec) +{ + debugfs_remove_recursive(codec->debugfs_codec_root); +} + +#else + +static inline void soc_init_codec_debugfs(struct snd_soc_codec *codec) +{ +} + +static inline void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec) +{ +} +#endif + #ifdef CONFIG_SND_SOC_AC97_BUS /* unregister ac97 codec */ static int soc_ac97_dev_unregister(struct snd_soc_codec *codec) @@ -1111,173 +1278,6 @@ int snd_soc_codec_volatile_register(struct snd_soc_codec *codec, int reg) } EXPORT_SYMBOL_GPL(snd_soc_codec_volatile_register); -/* codec register dump */ -static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf) -{ - int i, step = 1, count = 0; - - if (!codec->reg_cache_size) - return 0; - - if (codec->reg_cache_step) - step = codec->reg_cache_step; - - count += sprintf(buf, "%s registers\n", codec->name); - for (i = 0; i < codec->reg_cache_size; i += step) { - if (codec->readable_register && !codec->readable_register(i)) - continue; - - count += sprintf(buf + count, "%2x: ", i); - if (count >= PAGE_SIZE - 1) - break; - - if (codec->display_register) - count += codec->display_register(codec, buf + count, - PAGE_SIZE - count, i); - else - count += snprintf(buf + count, PAGE_SIZE - count, - "%4x", codec->read(codec, i)); - - if (count >= PAGE_SIZE - 1) - break; - - count += snprintf(buf + count, PAGE_SIZE - count, "\n"); - if (count >= PAGE_SIZE - 1) - break; - } - - /* Truncate count; min() would cause a warning */ - if (count >= PAGE_SIZE) - count = PAGE_SIZE - 1; - - return count; -} -static ssize_t codec_reg_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct snd_soc_device *devdata = dev_get_drvdata(dev); - return soc_codec_reg_show(devdata->card->codec, buf); -} - -static DEVICE_ATTR(codec_reg, 0444, codec_reg_show, NULL); - -#ifdef CONFIG_DEBUG_FS -static int codec_reg_open_file(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - -static ssize_t codec_reg_read_file(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - ssize_t ret; - struct snd_soc_codec *codec = file->private_data; - char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL); - if (!buf) - return -ENOMEM; - ret = soc_codec_reg_show(codec, buf); - if (ret >= 0) - ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret); - kfree(buf); - return ret; -} - -static ssize_t codec_reg_write_file(struct file *file, - const char __user *user_buf, size_t count, loff_t *ppos) -{ - char buf[32]; - int buf_size; - char *start = buf; - unsigned long reg, value; - int step = 1; - struct snd_soc_codec *codec = file->private_data; - - buf_size = min(count, (sizeof(buf)-1)); - if (copy_from_user(buf, user_buf, buf_size)) - return -EFAULT; - buf[buf_size] = 0; - - if (codec->reg_cache_step) - step = codec->reg_cache_step; - - while (*start == ' ') - start++; - reg = simple_strtoul(start, &start, 16); - if ((reg >= codec->reg_cache_size) || (reg % step)) - return -EINVAL; - while (*start == ' ') - start++; - if (strict_strtoul(start, 16, &value)) - return -EINVAL; - codec->write(codec, reg, value); - return buf_size; -} - -static const struct file_operations codec_reg_fops = { - .open = codec_reg_open_file, - .read = codec_reg_read_file, - .write = codec_reg_write_file, -}; - -static void soc_init_codec_debugfs(struct snd_soc_codec *codec) -{ - char codec_root[128]; - - if (codec->dev) - snprintf(codec_root, sizeof(codec_root), - "%s.%s", codec->name, dev_name(codec->dev)); - else - snprintf(codec_root, sizeof(codec_root), - "%s", codec->name); - - codec->debugfs_codec_root = debugfs_create_dir(codec_root, - debugfs_root); - if (!codec->debugfs_codec_root) { - printk(KERN_WARNING - "ASoC: Failed to create codec debugfs directory\n"); - return; - } - - codec->debugfs_reg = debugfs_create_file("codec_reg", 0644, - codec->debugfs_codec_root, - codec, &codec_reg_fops); - if (!codec->debugfs_reg) - printk(KERN_WARNING - "ASoC: Failed to create codec register debugfs file\n"); - - codec->debugfs_pop_time = debugfs_create_u32("dapm_pop_time", 0744, - codec->debugfs_codec_root, - &codec->pop_time); - if (!codec->debugfs_pop_time) - printk(KERN_WARNING - "Failed to create pop time debugfs file\n"); - - codec->debugfs_dapm = debugfs_create_dir("dapm", - codec->debugfs_codec_root); - if (!codec->debugfs_dapm) - printk(KERN_WARNING - "Failed to create DAPM debugfs directory\n"); - - snd_soc_dapm_debugfs_init(codec); -} - -static void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec) -{ - debugfs_remove_recursive(codec->debugfs_codec_root); -} - -#else - -static inline void soc_init_codec_debugfs(struct snd_soc_codec *codec) -{ -} - -static inline void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec) -{ -} -#endif - /** * snd_soc_new_ac97_codec - initailise AC97 device * @codec: audio codec -- cgit v1.2.3 From fe3e78e073d25308756f38019956061153267769 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 3 Nov 2009 22:13:13 +0000 Subject: ASoC: Factor out snd_soc_init_card() snd_soc_init_card() is always called as the last part of the CODEC probe function so we can factor it out into the core card setup rather than have each CODEC replicate the code to do the initialiastation. This will be required to support multiple CODECs per card. Signed-off-by: Mark Brown --- sound/soc/codecs/ac97.c | 3 - sound/soc/codecs/ad1836.c | 6 -- sound/soc/codecs/ad1938.c | 6 -- sound/soc/codecs/ad1980.c | 5 -- sound/soc/codecs/ad73311.c | 8 --- sound/soc/codecs/ak4104.c | 8 --- sound/soc/codecs/ak4535.c | 8 --- sound/soc/codecs/ak4642.c | 9 --- sound/soc/codecs/ak4671.c | 9 --- sound/soc/codecs/cs4270.c | 7 -- sound/soc/codecs/cx20442.c | 6 -- sound/soc/codecs/pcm3008.c | 9 --- sound/soc/codecs/ssm2602.c | 8 --- sound/soc/codecs/stac9766.c | 3 - sound/soc/codecs/tlv320aic23.c | 8 --- sound/soc/codecs/tlv320aic26.c | 11 ---- sound/soc/codecs/tlv320aic3x.c | 10 --- sound/soc/codecs/tlv320dac33.c | 10 +-- sound/soc/codecs/twl4030.c | 12 ---- sound/soc/codecs/uda134x.c | 9 --- sound/soc/codecs/uda1380.c | 8 --- sound/soc/codecs/wm8350.c | 11 ---- sound/soc/codecs/wm8400.c | 6 -- sound/soc/codecs/wm8510.c | 9 +-- sound/soc/codecs/wm8523.c | 8 --- sound/soc/codecs/wm8580.c | 8 --- sound/soc/codecs/wm8711.c | 8 --- sound/soc/codecs/wm8727.c | 8 --- sound/soc/codecs/wm8728.c | 8 --- sound/soc/codecs/wm8731.c | 8 --- sound/soc/codecs/wm8750.c | 8 --- sound/soc/codecs/wm8753.c | 9 --- sound/soc/codecs/wm8776.c | 9 --- sound/soc/codecs/wm8900.c | 6 -- sound/soc/codecs/wm8903.c | 9 --- sound/soc/codecs/wm8940.c | 6 -- sound/soc/codecs/wm8960.c | 8 --- sound/soc/codecs/wm8961.c | 9 --- sound/soc/codecs/wm8971.c | 9 +-- sound/soc/codecs/wm8974.c | 8 --- sound/soc/codecs/wm8988.c | 9 --- sound/soc/codecs/wm8990.c | 9 +-- sound/soc/codecs/wm8993.c | 9 --- sound/soc/codecs/wm9081.c | 9 --- sound/soc/codecs/wm9705.c | 8 --- sound/soc/codecs/wm9712.c | 8 --- sound/soc/codecs/wm9713.c | 7 +- sound/soc/soc-core.c | 141 +++++++++++++++++++---------------------- 48 files changed, 69 insertions(+), 449 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c index 932299bb5d1..69bd0acc81c 100644 --- a/sound/soc/codecs/ac97.c +++ b/sound/soc/codecs/ac97.c @@ -117,9 +117,6 @@ static int ac97_soc_probe(struct platform_device *pdev) if (ret < 0) goto bus_err; - ret = snd_soc_init_card(socdev); - if (ret < 0) - goto bus_err; return 0; bus_err: diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c index c48485f2c55..2e360c24307 100644 --- a/sound/soc/codecs/ad1836.c +++ b/sound/soc/codecs/ad1836.c @@ -387,12 +387,6 @@ static int ad1836_probe(struct platform_device *pdev) snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths)); snd_soc_dapm_new_widgets(codec); - ret = snd_soc_init_card(socdev); - if (ret < 0) { - dev_err(codec->dev, "failed to register card: %d\n", ret); - goto card_err; - } - return ret; card_err: diff --git a/sound/soc/codecs/ad1938.c b/sound/soc/codecs/ad1938.c index 34b30efc3cb..09c008ad147 100644 --- a/sound/soc/codecs/ad1938.c +++ b/sound/soc/codecs/ad1938.c @@ -596,12 +596,6 @@ static int ad1938_probe(struct platform_device *pdev) ad1938_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - ret = snd_soc_init_card(socdev); - if (ret < 0) { - dev_err(codec->dev, "failed to register card: %d\n", ret); - goto card_err; - } - return ret; card_err: diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c index d7440a982d2..39c0f7584e6 100644 --- a/sound/soc/codecs/ad1980.c +++ b/sound/soc/codecs/ad1980.c @@ -257,11 +257,6 @@ static int ad1980_soc_probe(struct platform_device *pdev) snd_soc_add_controls(codec, ad1980_snd_ac97_controls, ARRAY_SIZE(ad1980_snd_ac97_controls)); - ret = snd_soc_init_card(socdev); - if (ret < 0) { - printk(KERN_ERR "ad1980: failed to register card\n"); - goto reset_err; - } return 0; diff --git a/sound/soc/codecs/ad73311.c b/sound/soc/codecs/ad73311.c index e61dac5e7b8..d2fcc601722 100644 --- a/sound/soc/codecs/ad73311.c +++ b/sound/soc/codecs/ad73311.c @@ -64,16 +64,8 @@ static int ad73311_soc_probe(struct platform_device *pdev) goto pcm_err; } - ret = snd_soc_init_card(socdev); - if (ret < 0) { - printk(KERN_ERR "ad73311: failed to register card\n"); - goto register_err; - } - return ret; -register_err: - snd_soc_free_pcms(socdev); pcm_err: kfree(socdev->card->codec); socdev->card->codec = NULL; diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c index 4d47bc4f742..3a14c6fc4f5 100644 --- a/sound/soc/codecs/ak4104.c +++ b/sound/soc/codecs/ak4104.c @@ -313,14 +313,6 @@ static int ak4104_probe(struct platform_device *pdev) return ret; } - /* Register the socdev */ - ret = snd_soc_init_card(socdev); - if (ret < 0) { - dev_err(codec->dev, "failed to register card\n"); - snd_soc_free_pcms(socdev); - return ret; - } - return 0; } diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c index 0abec0d29a9..57a6846a9a1 100644 --- a/sound/soc/codecs/ak4535.c +++ b/sound/soc/codecs/ak4535.c @@ -485,17 +485,9 @@ static int ak4535_init(struct snd_soc_device *socdev) snd_soc_add_controls(codec, ak4535_snd_controls, ARRAY_SIZE(ak4535_snd_controls)); ak4535_add_widgets(codec); - ret = snd_soc_init_card(socdev); - if (ret < 0) { - printk(KERN_ERR "ak4535: failed to register card\n"); - goto card_err; - } return ret; -card_err: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); pcm_err: kfree(codec->reg_cache); diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index e057c7b578d..b69861d5216 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c @@ -442,18 +442,9 @@ static int ak4642_probe(struct platform_device *pdev) goto pcm_err; } - ret = snd_soc_init_card(socdev); - if (ret < 0) { - printk(KERN_ERR "ak4642: failed to register card\n"); - goto card_err; - } - dev_info(&pdev->dev, "AK4642 Audio Codec %s", AK4642_VERSION); return ret; -card_err: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); pcm_err: return ret; diff --git a/sound/soc/codecs/ak4671.c b/sound/soc/codecs/ak4671.c index b61214d1c5d..364832ccd74 100644 --- a/sound/soc/codecs/ak4671.c +++ b/sound/soc/codecs/ak4671.c @@ -662,19 +662,10 @@ static int ak4671_probe(struct platform_device *pdev) ARRAY_SIZE(ak4671_snd_controls)); ak4671_add_widgets(codec); - ret = snd_soc_init_card(socdev); - if (ret < 0) { - dev_err(codec->dev, "failed to register card: %d\n", ret); - goto card_err; - } - ak4671_set_bias_level(codec, SND_SOC_BIAS_STANDBY); return ret; -card_err: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); pcm_err: return ret; } diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index 565842dcfc6..ffe122d1cd7 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c @@ -599,13 +599,6 @@ static int cs4270_probe(struct platform_device *pdev) goto error_free_pcms; } - /* And finally, register the socdev */ - ret = snd_soc_init_card(socdev); - if (ret < 0) { - dev_err(codec->dev, "failed to register card\n"); - goto error_free_pcms; - } - return 0; error_free_pcms: diff --git a/sound/soc/codecs/cx20442.c b/sound/soc/codecs/cx20442.c index 38eac9c866e..d7f9bf18b72 100644 --- a/sound/soc/codecs/cx20442.c +++ b/sound/soc/codecs/cx20442.c @@ -355,12 +355,6 @@ static int cx20442_codec_probe(struct platform_device *pdev) cx20442_add_widgets(codec); - ret = snd_soc_init_card(socdev); - if (ret < 0) { - dev_err(&pdev->dev, "failed to register card\n"); - goto card_err; - } - return ret; card_err: diff --git a/sound/soc/codecs/pcm3008.c b/sound/soc/codecs/pcm3008.c index 5cda9e6b5a7..2afcd0a8669 100644 --- a/sound/soc/codecs/pcm3008.c +++ b/sound/soc/codecs/pcm3008.c @@ -90,13 +90,6 @@ static int pcm3008_soc_probe(struct platform_device *pdev) goto pcm_err; } - /* Register Card. */ - ret = snd_soc_init_card(socdev); - if (ret < 0) { - printk(KERN_ERR "pcm3008: failed to register card\n"); - goto card_err; - } - /* DEM1 DEM0 DE-EMPHASIS_MODE * Low Low De-emphasis 44.1 kHz ON * Low High De-emphasis OFF @@ -136,8 +129,6 @@ static int pcm3008_soc_probe(struct platform_device *pdev) gpio_err: pcm3008_gpio_free(setup); -card_err: - snd_soc_free_pcms(socdev); pcm_err: kfree(socdev->card->codec); diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c index c550750c79c..b3130339d29 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c @@ -613,17 +613,9 @@ static int ssm2602_init(struct snd_soc_device *socdev) snd_soc_add_controls(codec, ssm2602_snd_controls, ARRAY_SIZE(ssm2602_snd_controls)); ssm2602_add_widgets(codec); - ret = snd_soc_init_card(socdev); - if (ret < 0) { - pr_err("ssm2602: failed to register card\n"); - goto card_err; - } return ret; -card_err: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); pcm_err: kfree(codec->reg_cache); return ret; diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c index befc6488c39..bbc72c2ddfc 100644 --- a/sound/soc/codecs/stac9766.c +++ b/sound/soc/codecs/stac9766.c @@ -418,9 +418,6 @@ static int stac9766_codec_probe(struct platform_device *pdev) snd_soc_add_controls(codec, stac9766_snd_ac97_controls, ARRAY_SIZE(stac9766_snd_ac97_controls)); - ret = snd_soc_init_card(socdev); - if (ret < 0) - goto reset_err; return 0; reset_err: diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c index 0b8dcb5cd72..ee8cb2c08b8 100644 --- a/sound/soc/codecs/tlv320aic23.c +++ b/sound/soc/codecs/tlv320aic23.c @@ -707,17 +707,9 @@ static int tlv320aic23_init(struct snd_soc_device *socdev) snd_soc_add_controls(codec, tlv320aic23_snd_controls, ARRAY_SIZE(tlv320aic23_snd_controls)); tlv320aic23_add_widgets(codec); - ret = snd_soc_init_card(socdev); - if (ret < 0) { - printk(KERN_ERR "tlv320aic23: failed to register card\n"); - goto card_err; - } return ret; -card_err: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); pcm_err: kfree(codec->reg_cache); return ret; diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c index 3387d9e736e..357b609196e 100644 --- a/sound/soc/codecs/tlv320aic26.c +++ b/sound/soc/codecs/tlv320aic26.c @@ -356,18 +356,7 @@ static int aic26_probe(struct platform_device *pdev) ARRAY_SIZE(aic26_snd_controls)); WARN_ON(err < 0); - /* CODEC is setup, we can register the card now */ - dev_dbg(&pdev->dev, "Registering card\n"); - ret = snd_soc_init_card(socdev); - if (ret < 0) { - dev_err(&pdev->dev, "aic26: failed to register card\n"); - goto card_err; - } return 0; - - card_err: - snd_soc_free_pcms(socdev); - return ret; } static int aic26_remove(struct platform_device *pdev) diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 3395cf945d5..03cad250f58 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -1405,18 +1405,8 @@ static int aic3x_probe(struct platform_device *pdev) aic3x_add_widgets(codec); - ret = snd_soc_init_card(socdev); - if (ret < 0) { - printk(KERN_ERR "aic3x: failed to register card\n"); - goto card_err; - } - return ret; -card_err: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); - pcm_err: kfree(codec->reg_cache); return ret; diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index 3ca8934fc26..bff476d65d0 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c @@ -960,16 +960,8 @@ static int dac33_soc_probe(struct platform_device *pdev) /* power on device */ dac33_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - ret = snd_soc_init_card(socdev); - if (ret < 0) { - dev_err(codec->dev, "failed to register card\n"); - goto card_err; - } - return 0; -card_err: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); + pcm_err: dac33_hard_power(codec, 0); return ret; diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index c0b47dfc332..928257b2511 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -2155,19 +2155,7 @@ static int twl4030_soc_probe(struct platform_device *pdev) ARRAY_SIZE(twl4030_snd_controls)); twl4030_add_widgets(codec); - ret = snd_soc_init_card(socdev); - if (ret < 0) { - dev_err(&pdev->dev, "failed to register card\n"); - goto card_err; - } - return 0; - -card_err: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); - - return ret; } static int twl4030_soc_remove(struct platform_device *pdev) diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c index c33b92edbde..aa40d985138 100644 --- a/sound/soc/codecs/uda134x.c +++ b/sound/soc/codecs/uda134x.c @@ -562,17 +562,8 @@ static int uda134x_soc_probe(struct platform_device *pdev) goto pcm_err; } - ret = snd_soc_init_card(socdev); - if (ret < 0) { - printk(KERN_ERR "UDA134X: failed to register card\n"); - goto card_err; - } - return 0; -card_err: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); pcm_err: kfree(codec->reg_cache); reg_err: diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c index 92ec0344215..a42e47d9463 100644 --- a/sound/soc/codecs/uda1380.c +++ b/sound/soc/codecs/uda1380.c @@ -713,17 +713,9 @@ static int uda1380_probe(struct platform_device *pdev) snd_soc_add_controls(codec, uda1380_snd_controls, ARRAY_SIZE(uda1380_snd_controls)); uda1380_add_widgets(codec); - ret = snd_soc_init_card(socdev); - if (ret < 0) { - dev_err(codec->dev, "failed to register card: %d\n", ret); - goto card_err; - } return ret; -card_err: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); pcm_err: return ret; } diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index 714114b50d1..2e35a354b16 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c @@ -1501,18 +1501,7 @@ static int wm8350_probe(struct platform_device *pdev) wm8350_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - ret = snd_soc_init_card(socdev); - if (ret < 0) { - dev_err(&pdev->dev, "failed to register card\n"); - goto card_err; - } - return 0; - -card_err: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); - return ret; } static int wm8350_remove(struct platform_device *pdev) diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c index bd7eecba20f..0e30997c8db 100644 --- a/sound/soc/codecs/wm8400.c +++ b/sound/soc/codecs/wm8400.c @@ -1400,12 +1400,6 @@ static int wm8400_probe(struct platform_device *pdev) wm8400_add_controls(codec); wm8400_add_widgets(codec); - ret = snd_soc_init_card(socdev); - if (ret < 0) { - dev_err(&pdev->dev, "failed to register card\n"); - goto card_err; - } - return ret; card_err: diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c index 5702435af81..e3c21ebcc08 100644 --- a/sound/soc/codecs/wm8510.c +++ b/sound/soc/codecs/wm8510.c @@ -604,16 +604,9 @@ static int wm8510_init(struct snd_soc_device *socdev, snd_soc_add_controls(codec, wm8510_snd_controls, ARRAY_SIZE(wm8510_snd_controls)); wm8510_add_widgets(codec); - ret = snd_soc_init_card(socdev); - if (ret < 0) { - printk(KERN_ERR "wm8510: failed to register card\n"); - goto card_err; - } + return ret; -card_err: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); err: kfree(codec->reg_cache); return ret; diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c index 268cab21c2c..2e2b01d6c82 100644 --- a/sound/soc/codecs/wm8523.c +++ b/sound/soc/codecs/wm8523.c @@ -448,17 +448,9 @@ static int wm8523_probe(struct platform_device *pdev) snd_soc_add_controls(codec, wm8523_snd_controls, ARRAY_SIZE(wm8523_snd_controls)); wm8523_add_widgets(codec); - ret = snd_soc_init_card(socdev); - if (ret < 0) { - dev_err(codec->dev, "failed to register card: %d\n", ret); - goto card_err; - } return ret; -card_err: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); pcm_err: return ret; } diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index a09b23e0366..dde50d11818 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c @@ -800,17 +800,9 @@ static int wm8580_probe(struct platform_device *pdev) snd_soc_add_controls(codec, wm8580_snd_controls, ARRAY_SIZE(wm8580_snd_controls)); wm8580_add_widgets(codec); - ret = snd_soc_init_card(socdev); - if (ret < 0) { - dev_err(codec->dev, "failed to register card: %d\n", ret); - goto card_err; - } return ret; -card_err: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); pcm_err: return ret; } diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c index 54189fbf9e9..70e0675b5d4 100644 --- a/sound/soc/codecs/wm8711.c +++ b/sound/soc/codecs/wm8711.c @@ -404,17 +404,9 @@ static int wm8711_probe(struct platform_device *pdev) snd_soc_add_controls(codec, wm8711_snd_controls, ARRAY_SIZE(wm8711_snd_controls)); wm8711_add_widgets(codec); - ret = snd_soc_init_card(socdev); - if (ret < 0) { - dev_err(codec->dev, "failed to register card: %d\n", ret); - goto card_err; - } return ret; -card_err: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); pcm_err: return ret; } diff --git a/sound/soc/codecs/wm8727.c b/sound/soc/codecs/wm8727.c index 7df5a17eb73..d8ffbd641d7 100644 --- a/sound/soc/codecs/wm8727.c +++ b/sound/soc/codecs/wm8727.c @@ -68,17 +68,9 @@ static int wm8727_soc_probe(struct platform_device *pdev) printk(KERN_ERR "wm8727: failed to create pcms\n"); goto pcm_err; } - /* register card */ - ret = snd_soc_init_card(socdev); - if (ret < 0) { - printk(KERN_ERR "wm8727: failed to register card\n"); - goto register_err; - } return ret; -register_err: - snd_soc_free_pcms(socdev); pcm_err: kfree(socdev->card->codec); socdev->card->codec = NULL; diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c index 16e969a762c..1252a8a486a 100644 --- a/sound/soc/codecs/wm8728.c +++ b/sound/soc/codecs/wm8728.c @@ -287,17 +287,9 @@ static int wm8728_init(struct snd_soc_device *socdev, snd_soc_add_controls(codec, wm8728_snd_controls, ARRAY_SIZE(wm8728_snd_controls)); wm8728_add_widgets(codec); - ret = snd_soc_init_card(socdev); - if (ret < 0) { - printk(KERN_ERR "wm8728: failed to register card\n"); - goto card_err; - } return ret; -card_err: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); err: kfree(codec->reg_cache); return ret; diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index bb95af95097..e3675e7a981 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -495,17 +495,9 @@ static int wm8731_probe(struct platform_device *pdev) snd_soc_add_controls(codec, wm8731_snd_controls, ARRAY_SIZE(wm8731_snd_controls)); wm8731_add_widgets(codec); - ret = snd_soc_init_card(socdev); - if (ret < 0) { - dev_err(codec->dev, "failed to register card: %d\n", ret); - goto card_err; - } return ret; -card_err: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); pcm_err: return ret; } diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index 4ba1e7e93fb..50a3d659058 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c @@ -772,16 +772,8 @@ static int wm8750_init(struct snd_soc_device *socdev, snd_soc_add_controls(codec, wm8750_snd_controls, ARRAY_SIZE(wm8750_snd_controls)); wm8750_add_widgets(codec); - ret = snd_soc_init_card(socdev); - if (ret < 0) { - printk(KERN_ERR "wm8750: failed to register card\n"); - goto card_err; - } return ret; -card_err: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); err: kfree(codec->reg_cache); return ret; diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index 8f7305257d2..c652bc04cc8 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c @@ -1583,18 +1583,9 @@ static int wm8753_probe(struct platform_device *pdev) snd_soc_add_controls(codec, wm8753_snd_controls, ARRAY_SIZE(wm8753_snd_controls)); wm8753_add_widgets(codec); - ret = snd_soc_init_card(socdev); - if (ret < 0) { - printk(KERN_ERR "wm8753: failed to register card\n"); - goto card_err; - } return 0; -card_err: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); - pcm_err: return ret; } diff --git a/sound/soc/codecs/wm8776.c b/sound/soc/codecs/wm8776.c index a0bbb28eed7..ab2c0da1809 100644 --- a/sound/soc/codecs/wm8776.c +++ b/sound/soc/codecs/wm8776.c @@ -447,17 +447,8 @@ static int wm8776_probe(struct platform_device *pdev) ARRAY_SIZE(wm8776_dapm_widgets)); snd_soc_dapm_add_routes(codec, routes, ARRAY_SIZE(routes)); - ret = snd_soc_init_card(socdev); - if (ret < 0) { - dev_err(codec->dev, "failed to register card: %d\n", ret); - goto card_err; - } - return ret; -card_err: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); pcm_err: return ret; } diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index b48804b5cac..0d185cb6418 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c @@ -1353,12 +1353,6 @@ static int wm8900_probe(struct platform_device *pdev) ARRAY_SIZE(wm8900_snd_controls)); wm8900_add_widgets(codec); - ret = snd_soc_init_card(socdev); - if (ret < 0) { - dev_err(&pdev->dev, "Failed to register card\n"); - goto card_err; - } - return ret; card_err: diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index 94cdb813041..bfeff4ee5de 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -1695,17 +1695,8 @@ static int wm8903_probe(struct platform_device *pdev) ARRAY_SIZE(wm8903_snd_controls)); wm8903_add_widgets(socdev->card->codec); - ret = snd_soc_init_card(socdev); - if (ret < 0) { - dev_err(&pdev->dev, "wm8903: failed to register card\n"); - goto card_err; - } - return ret; -card_err: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); err: return ret; } diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c index 8d4fd3c08c0..fc80aa6c913 100644 --- a/sound/soc/codecs/wm8940.c +++ b/sound/soc/codecs/wm8940.c @@ -731,12 +731,6 @@ static int wm8940_probe(struct platform_device *pdev) if (ret) goto error_free_pcms; - ret = snd_soc_init_card(socdev); - if (ret < 0) { - dev_err(codec->dev, "failed to register card: %d\n", ret); - goto error_free_pcms; - } - return ret; error_free_pcms: diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index b9b096a8539..40390afa75f 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -713,17 +713,9 @@ static int wm8960_probe(struct platform_device *pdev) snd_soc_add_controls(codec, wm8960_snd_controls, ARRAY_SIZE(wm8960_snd_controls)); wm8960_add_widgets(codec); - ret = snd_soc_init_card(socdev); - if (ret < 0) { - dev_err(codec->dev, "failed to register card: %d\n", ret); - goto card_err; - } return ret; -card_err: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); pcm_err: return ret; } diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c index b5c6f2cd5ae..07e389574db 100644 --- a/sound/soc/codecs/wm8961.c +++ b/sound/soc/codecs/wm8961.c @@ -988,17 +988,8 @@ static int wm8961_probe(struct platform_device *pdev) snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths)); snd_soc_dapm_new_widgets(codec); - ret = snd_soc_init_card(socdev); - if (ret < 0) { - dev_err(codec->dev, "failed to register card: %d\n", ret); - goto card_err; - } - return ret; -card_err: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); pcm_err: return ret; } diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c index d66efb0546e..56a66e89ab9 100644 --- a/sound/soc/codecs/wm8971.c +++ b/sound/soc/codecs/wm8971.c @@ -703,16 +703,9 @@ static int wm8971_init(struct snd_soc_device *socdev, snd_soc_add_controls(codec, wm8971_snd_controls, ARRAY_SIZE(wm8971_snd_controls)); wm8971_add_widgets(codec); - ret = snd_soc_init_card(socdev); - if (ret < 0) { - printk(KERN_ERR "wm8971: failed to register card\n"); - goto card_err; - } + return ret; -card_err: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); err: kfree(codec->reg_cache); return ret; diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c index eff29331235..c245f0ee0ec 100644 --- a/sound/soc/codecs/wm8974.c +++ b/sound/soc/codecs/wm8974.c @@ -641,17 +641,9 @@ static int wm8974_probe(struct platform_device *pdev) snd_soc_add_controls(codec, wm8974_snd_controls, ARRAY_SIZE(wm8974_snd_controls)); wm8974_add_widgets(codec); - ret = snd_soc_init_card(socdev); - if (ret < 0) { - dev_err(codec->dev, "failed to register card: %d\n", ret); - goto card_err; - } return ret; -card_err: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); pcm_err: return ret; } diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c index d8d8f68b81e..bee292e37d1 100644 --- a/sound/soc/codecs/wm8988.c +++ b/sound/soc/codecs/wm8988.c @@ -792,17 +792,8 @@ static int wm8988_probe(struct platform_device *pdev) snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); snd_soc_dapm_new_widgets(codec); - ret = snd_soc_init_card(socdev); - if (ret < 0) { - dev_err(codec->dev, "failed to register card: %d\n", ret); - goto card_err; - } - return ret; -card_err: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); pcm_err: return ret; } diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index f657e9a5fe2..e43cb2c8b91 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c @@ -1409,16 +1409,9 @@ static int wm8990_init(struct snd_soc_device *socdev) snd_soc_add_controls(codec, wm8990_snd_controls, ARRAY_SIZE(wm8990_snd_controls)); wm8990_add_widgets(codec); - ret = snd_soc_init_card(socdev); - if (ret < 0) { - printk(KERN_ERR "wm8990: failed to register card\n"); - goto card_err; - } + return ret; -card_err: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); pcm_err: kfree(codec->reg_cache); return ret; diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c index dac39771214..0d4d2be92b6 100644 --- a/sound/soc/codecs/wm8993.c +++ b/sound/soc/codecs/wm8993.c @@ -1466,17 +1466,8 @@ static int wm8993_probe(struct platform_device *pdev) snd_soc_dapm_new_widgets(codec); - ret = snd_soc_init_card(socdev); - if (ret < 0) { - dev_err(codec->dev, "failed to register card\n"); - goto card_err; - } - return ret; -card_err: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); err: return ret; } diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c index 4cb6b104b72..3f1f8442131 100644 --- a/sound/soc/codecs/wm9081.c +++ b/sound/soc/codecs/wm9081.c @@ -1264,17 +1264,8 @@ static int wm9081_probe(struct platform_device *pdev) snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths)); snd_soc_dapm_new_widgets(codec); - ret = snd_soc_init_card(socdev); - if (ret < 0) { - dev_err(codec->dev, "failed to register card: %d\n", ret); - goto card_err; - } - return ret; -card_err: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); pcm_err: return ret; } diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c index e7d2840d9e5..0e817b8705c 100644 --- a/sound/soc/codecs/wm9705.c +++ b/sound/soc/codecs/wm9705.c @@ -403,16 +403,8 @@ static int wm9705_soc_probe(struct platform_device *pdev) ARRAY_SIZE(wm9705_snd_ac97_controls)); wm9705_add_widgets(codec); - ret = snd_soc_init_card(socdev); - if (ret < 0) { - printk(KERN_ERR "wm9705: failed to register card\n"); - goto reset_err; - } - return 0; -reset_err: - snd_soc_free_pcms(socdev); pcm_err: snd_soc_free_ac97_codec(codec); codec_err: diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index 1fd4e88f50c..155cacf124e 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -695,17 +695,9 @@ static int wm9712_soc_probe(struct platform_device *pdev) snd_soc_add_controls(codec, wm9712_snd_ac97_controls, ARRAY_SIZE(wm9712_snd_ac97_controls)); wm9712_add_widgets(codec); - ret = snd_soc_init_card(socdev); - if (ret < 0) { - printk(KERN_ERR "wm9712: failed to register card\n"); - goto reset_err; - } return 0; -reset_err: - snd_soc_free_pcms(socdev); - pcm_err: snd_soc_free_ac97_codec(codec); diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index ca3d449ed89..5f81ecd20a8 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -1247,13 +1247,8 @@ static int wm9713_soc_probe(struct platform_device *pdev) snd_soc_add_controls(codec, wm9713_snd_ac97_controls, ARRAY_SIZE(wm9713_snd_ac97_controls)); wm9713_add_widgets(codec); - ret = snd_soc_init_card(socdev); - if (ret < 0) - goto reset_err; - return 0; -reset_err: - snd_soc_free_pcms(socdev); + return 0; pcm_err: snd_soc_free_ac97_codec(codec); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index d81a1618776..e2b6d75f16e 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -970,6 +970,7 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card) struct platform_device, dev); struct snd_soc_codec_device *codec_dev = card->socdev->codec_dev; + struct snd_soc_codec *codec; struct snd_soc_platform *platform; struct snd_soc_dai *dai; int i, found, ret, ac97; @@ -1058,6 +1059,7 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card) if (ret < 0) goto cpu_dai_err; } + codec = card->codec; if (platform->probe) { ret = platform->probe(pdev); @@ -1072,10 +1074,72 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card) INIT_WORK(&card->deferred_resume_work, soc_resume_deferred); #endif + for (i = 0; i < card->num_links; i++) { + if (card->dai_link[i].init) { + ret = card->dai_link[i].init(codec); + if (ret < 0) { + printk(KERN_ERR "asoc: failed to init %s\n", + card->dai_link[i].stream_name); + continue; + } + } + if (card->dai_link[i].codec_dai->ac97_control) { + ac97 = 1; + snd_ac97_dev_add_pdata(codec->ac97, + card->dai_link[i].cpu_dai->ac97_pdata); + } + } + + snprintf(codec->card->shortname, sizeof(codec->card->shortname), + "%s", card->name); + snprintf(codec->card->longname, sizeof(codec->card->longname), + "%s (%s)", card->name, codec->name); + + /* Make sure all DAPM widgets are instantiated */ + snd_soc_dapm_new_widgets(codec); + + ret = snd_card_register(codec->card); + if (ret < 0) { + printk(KERN_ERR "asoc: failed to register soundcard for %s\n", + codec->name); + goto card_err; + } + + mutex_lock(&codec->mutex); +#ifdef CONFIG_SND_SOC_AC97_BUS + /* Only instantiate AC97 if not already done by the adaptor + * for the generic AC97 subsystem. + */ + if (ac97 && strcmp(codec->name, "AC97") != 0) { + ret = soc_ac97_dev_register(codec); + if (ret < 0) { + printk(KERN_ERR "asoc: AC97 device register failed\n"); + snd_card_free(codec->card); + mutex_unlock(&codec->mutex); + goto card_err; + } + } +#endif + + ret = snd_soc_dapm_sys_add(card->socdev->dev); + if (ret < 0) + printk(KERN_WARNING "asoc: failed to add dapm sysfs entries\n"); + + ret = device_create_file(card->socdev->dev, &dev_attr_codec_reg); + if (ret < 0) + printk(KERN_WARNING "asoc: failed to add codec sysfs files\n"); + + soc_init_codec_debugfs(codec); + mutex_unlock(&codec->mutex); + card->instantiated = 1; return; +card_err: + if (platform->remove) + platform->remove(pdev); + platform_err: if (codec_dev->remove) codec_dev->remove(pdev); @@ -1453,83 +1517,6 @@ int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid) } EXPORT_SYMBOL_GPL(snd_soc_new_pcms); -/** - * snd_soc_init_card - register sound card - * @socdev: the SoC audio device - * - * Register a SoC sound card. Also registers an AC97 device if the - * codec is AC97 for ad hoc devices. - * - * Returns 0 for success, else error. - */ -int snd_soc_init_card(struct snd_soc_device *socdev) -{ - struct snd_soc_card *card = socdev->card; - struct snd_soc_codec *codec = card->codec; - int ret = 0, i, ac97 = 0, err = 0; - - for (i = 0; i < card->num_links; i++) { - if (card->dai_link[i].init) { - err = card->dai_link[i].init(codec); - if (err < 0) { - printk(KERN_ERR "asoc: failed to init %s\n", - card->dai_link[i].stream_name); - continue; - } - } - if (card->dai_link[i].codec_dai->ac97_control) { - ac97 = 1; - snd_ac97_dev_add_pdata(codec->ac97, - card->dai_link[i].cpu_dai->ac97_pdata); - } - } - snprintf(codec->card->shortname, sizeof(codec->card->shortname), - "%s", card->name); - snprintf(codec->card->longname, sizeof(codec->card->longname), - "%s (%s)", card->name, codec->name); - - /* Make sure all DAPM widgets are instantiated */ - snd_soc_dapm_new_widgets(codec); - - ret = snd_card_register(codec->card); - if (ret < 0) { - printk(KERN_ERR "asoc: failed to register soundcard for %s\n", - codec->name); - goto out; - } - - mutex_lock(&codec->mutex); -#ifdef CONFIG_SND_SOC_AC97_BUS - /* Only instantiate AC97 if not already done by the adaptor - * for the generic AC97 subsystem. - */ - if (ac97 && strcmp(codec->name, "AC97") != 0) { - ret = soc_ac97_dev_register(codec); - if (ret < 0) { - printk(KERN_ERR "asoc: AC97 device register failed\n"); - snd_card_free(codec->card); - mutex_unlock(&codec->mutex); - goto out; - } - } -#endif - - err = snd_soc_dapm_sys_add(socdev->dev); - if (err < 0) - printk(KERN_WARNING "asoc: failed to add dapm sysfs entries\n"); - - err = device_create_file(socdev->dev, &dev_attr_codec_reg); - if (err < 0) - printk(KERN_WARNING "asoc: failed to add codec sysfs files\n"); - - soc_init_codec_debugfs(codec); - mutex_unlock(&codec->mutex); - -out: - return ret; -} -EXPORT_SYMBOL_GPL(snd_soc_init_card); - /** * snd_soc_free_pcms - free sound card and pcms * @socdev: the SoC audio device -- cgit v1.2.3 From 2dcf9fb99d4ecadecb2685a9eb82e6b85511c960 Mon Sep 17 00:00:00 2001 From: Graeme Gregory Date: Wed, 4 Nov 2009 17:49:22 +0000 Subject: ASoC: ADS117x ADC driver This patch adds support for the TI ADS117x family of multichannel ADCs and was sponsored by Shotspotter Inc. Signed-off-by: Graeme Gregory Signed-off-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 4 ++ sound/soc/codecs/Makefile | 2 + sound/soc/codecs/ads117x.c | 127 +++++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/ads117x.h | 13 +++++ 4 files changed, 146 insertions(+) create mode 100644 sound/soc/codecs/ads117x.c create mode 100644 sound/soc/codecs/ads117x.h (limited to 'sound') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 4a3e8dcf24d..52b005f8fed 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -15,6 +15,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_AD1836 if SPI_MASTER select SND_SOC_AD1938 if SPI_MASTER select SND_SOC_AD1980 if SND_SOC_AC97_BUS + select SND_SOC_ADS117X select SND_SOC_AD73311 if I2C select SND_SOC_AK4104 if SPI_MASTER select SND_SOC_AK4535 if I2C @@ -91,6 +92,9 @@ config SND_SOC_AD1980 config SND_SOC_AD73311 tristate + +config SND_SOC_ADS117X + tristate config SND_SOC_AK4104 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index cacfc7692d7..dbaecb133ac 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -3,6 +3,7 @@ snd-soc-ad1836-objs := ad1836.o snd-soc-ad1938-objs := ad1938.o snd-soc-ad1980-objs := ad1980.o snd-soc-ad73311-objs := ad73311.o +snd-soc-ads117x-objs := ads117x.o snd-soc-ak4104-objs := ak4104.o snd-soc-ak4535-objs := ak4535.o snd-soc-ak4642-objs := ak4642.o @@ -58,6 +59,7 @@ obj-$(CONFIG_SND_SOC_AD1836) += snd-soc-ad1836.o obj-$(CONFIG_SND_SOC_AD1938) += snd-soc-ad1938.o obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o +obj-$(CONFIG_SND_SOC_ADS117X) += snd-soc-ads117x.o obj-$(CONFIG_SND_SOC_AK4104) += snd-soc-ak4104.o obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o obj-$(CONFIG_SND_SOC_AK4642) += snd-soc-ak4642.o diff --git a/sound/soc/codecs/ads117x.c b/sound/soc/codecs/ads117x.c new file mode 100644 index 00000000000..f3230927dc6 --- /dev/null +++ b/sound/soc/codecs/ads117x.c @@ -0,0 +1,127 @@ +/* + * ads117x.c -- Driver for ads1174/8 ADC chips + * + * Copyright 2009 ShotSpotter Inc. + * Author: Graeme Gregory + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "ads117x.h" + +#define ADS117X_RATES (SNDRV_PCM_RATE_8000_48000) + +#define ADS117X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE) + +struct snd_soc_dai ads117x_dai = { +/* ADC */ + .name = "ADS117X ADC", + .id = 1, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 32, + .rates = ADS117X_RATES, + .formats = ADS117X_FORMATS,}, +}; +EXPORT_SYMBOL_GPL(ads117x_dai); + +/* + * initialise the ads117x driver + */ +static int ads117x_init(struct snd_soc_device *socdev) +{ + struct snd_soc_codec *codec = socdev->card->codec; + int ret = 0; + + codec->name = "ADS117X"; + codec->owner = THIS_MODULE; + codec->dai = &ads117x_dai; + codec->num_dai = 1; + + /* register pcms */ + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) { + printk(KERN_ERR "ads117x: failed to create pcms\n"); + return ret; + } + + ret = snd_soc_init_card(socdev); + if (ret < 0) { + printk(KERN_ERR "ads117x: failed to register card\n"); + goto card_err; + } + return ret; + +card_err: + snd_soc_free_pcms(socdev); + return ret; +} + +static int ads117x_probe(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec; + int ret; + + pr_info("ads117x ADC\n"); + + codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); + if (codec == NULL) + return -ENOMEM; + + socdev->card->codec = codec; + mutex_init(&codec->mutex); + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + + ret = ads117x_init(socdev); + if (ret != 0) + kfree(codec); + + return ret; +} + +static int ads117x_remove(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->card->codec; + + snd_soc_free_pcms(socdev); + kfree(codec); + + return 0; +} + +struct snd_soc_codec_device soc_codec_dev_ads117x = { + .probe = ads117x_probe, + .remove = ads117x_remove, +}; +EXPORT_SYMBOL_GPL(soc_codec_dev_ads117x); + +static int __init ads117x_modinit(void) +{ + return snd_soc_register_dai(&ads117x_dai); +} +module_init(ads117x_modinit); + +static void __exit ads117x_exit(void) +{ + snd_soc_unregister_dai(&ads117x_dai); +} +module_exit(ads117x_exit); + +MODULE_DESCRIPTION("ASoC ads117x driver"); +MODULE_AUTHOR("Graeme Gregory"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/ads117x.h b/sound/soc/codecs/ads117x.h new file mode 100644 index 00000000000..dbcf50ec9bd --- /dev/null +++ b/sound/soc/codecs/ads117x.h @@ -0,0 +1,13 @@ +/* + * ads117x.h -- Driver for ads1174/8 ADC chips + * + * Copyright 2009 ShotSpotter Inc. + * Author: Graeme Gregory + * + * 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. + */ +extern struct snd_soc_dai ads117x_dai; +extern struct snd_soc_codec_device soc_codec_dev_ads117x; -- cgit v1.2.3 From f3d0e82fe3cce0dd3ffcd9c59e6caa671a30f929 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 4 Nov 2009 21:43:27 +0000 Subject: ASoC: Update ads117x to current APIs Probe as a platform driver (ads117x) and remove the call to snd_soc_init_card(). Signed-off-by: Mark Brown --- sound/soc/codecs/ads117x.c | 76 ++++++++++++++++++++++------------------------ 1 file changed, 36 insertions(+), 40 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/ads117x.c b/sound/soc/codecs/ads117x.c index f3230927dc6..cc96411ca3e 100644 --- a/sound/soc/codecs/ads117x.c +++ b/sound/soc/codecs/ads117x.c @@ -37,46 +37,12 @@ struct snd_soc_dai ads117x_dai = { }; EXPORT_SYMBOL_GPL(ads117x_dai); -/* - * initialise the ads117x driver - */ -static int ads117x_init(struct snd_soc_device *socdev) -{ - struct snd_soc_codec *codec = socdev->card->codec; - int ret = 0; - - codec->name = "ADS117X"; - codec->owner = THIS_MODULE; - codec->dai = &ads117x_dai; - codec->num_dai = 1; - - /* register pcms */ - ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); - if (ret < 0) { - printk(KERN_ERR "ads117x: failed to create pcms\n"); - return ret; - } - - ret = snd_soc_init_card(socdev); - if (ret < 0) { - printk(KERN_ERR "ads117x: failed to register card\n"); - goto card_err; - } - return ret; - -card_err: - snd_soc_free_pcms(socdev); - return ret; -} - static int ads117x_probe(struct platform_device *pdev) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); struct snd_soc_codec *codec; int ret; - pr_info("ads117x ADC\n"); - codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); if (codec == NULL) return -ENOMEM; @@ -85,12 +51,20 @@ static int ads117x_probe(struct platform_device *pdev) mutex_init(&codec->mutex); INIT_LIST_HEAD(&codec->dapm_widgets); INIT_LIST_HEAD(&codec->dapm_paths); + codec->name = "ADS117X"; + codec->owner = THIS_MODULE; + codec->dai = &ads117x_dai; + codec->num_dai = 1; - ret = ads117x_init(socdev); - if (ret != 0) + /* register pcms */ + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) { + printk(KERN_ERR "ads117x: failed to create pcms\n"); kfree(codec); + return ret; + } - return ret; + return 0; } static int ads117x_remove(struct platform_device *pdev) @@ -110,15 +84,37 @@ struct snd_soc_codec_device soc_codec_dev_ads117x = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_ads117x); -static int __init ads117x_modinit(void) +static __devinit int ads117x_platform_probe(struct platform_device *pdev) { + ads117x_dai.dev = &pdev->dev; return snd_soc_register_dai(&ads117x_dai); } -module_init(ads117x_modinit); -static void __exit ads117x_exit(void) +static int __devexit ads117x_platform_remove(struct platform_device *pdev) { snd_soc_unregister_dai(&ads117x_dai); + return 0; +} + +static struct platform_driver ads117x_codec_driver = { + .driver = { + .name = "ads117x", + .owner = THIS_MODULE, + }, + + .probe = ads117x_platform_probe, + .remove = __devexit_p(ads117x_platform_remove), +}; + +static int __init ads117x_init(void) +{ + return platform_driver_register(&ads117x_codec_driver); +} +module_init(ads117x_init); + +static void __exit ads117x_exit(void) +{ + platform_driver_unregister(&ads117x_codec_driver); } module_exit(ads117x_exit); -- cgit v1.2.3 From 7e6c3989af5baee999ef9a4424e85938cba8d34a Mon Sep 17 00:00:00 2001 From: Daniel T Chen Date: Wed, 4 Nov 2009 21:03:46 -0500 Subject: ALSA: intel8x0: Mute External Amplifier by default for another Sony model BugLink: https://bugs.launchpad.net/bugs/474972 This Sony model needs External Amplifier muted for audible playback, so make sure we set the inv_eapd quirk. Signed-off-by: Daniel T Chen Signed-off-by: Takashi Iwai --- sound/pci/intel8x0.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'sound') diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 754867ed478..aac20fb4aad 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -1948,6 +1948,12 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = { .name = "HP xw4200", /* AD1981B*/ .type = AC97_TUNE_HP_ONLY }, + { + .subvendor = 0x104d, + .subdevice = 0x8144, + .name = "Sony", + .type = AC97_TUNE_INV_EAPD + }, { .subvendor = 0x104d, .subdevice = 0x8197, -- cgit v1.2.3 From f702cf463e1308fbb0c1faa9f3d8e3fa9cb5630f Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 4 Nov 2009 16:04:52 -0800 Subject: sound: Use KERN_WARNING instead of KERN_WARN, which does not exist Reported-by: Andrew Lyon Signed-off-by: Randy Dunlap Signed-off-by: Takashi Iwai --- sound/oss/sb_common.c | 4 ++-- sound/oss/sb_ess.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/oss/sb_common.c b/sound/oss/sb_common.c index 77d0e5efda7..ce4db49291f 100644 --- a/sound/oss/sb_common.c +++ b/sound/oss/sb_common.c @@ -157,7 +157,7 @@ static void sb_intr (sb_devc *devc) break; default: - /* printk(KERN_WARN "Sound Blaster: Unexpected interrupt\n"); */ + /* printk(KERN_WARNING "Sound Blaster: Unexpected interrupt\n"); */ ; } } @@ -177,7 +177,7 @@ static void sb_intr (sb_devc *devc) break; default: - /* printk(KERN_WARN "Sound Blaster: Unexpected interrupt\n"); */ + /* printk(KERN_WARNING "Sound Blaster: Unexpected interrupt\n"); */ ; } } diff --git a/sound/oss/sb_ess.c b/sound/oss/sb_ess.c index 180e95c87e3..51a3d381a59 100644 --- a/sound/oss/sb_ess.c +++ b/sound/oss/sb_ess.c @@ -782,7 +782,7 @@ printk(KERN_INFO "FKS: ess_handle_channel %s irq_mode=%d\n", channel, irq_mode); break; default:; - /* printk(KERN_WARN "ESS: Unexpected interrupt\n"); */ + /* printk(KERN_WARNING "ESS: Unexpected interrupt\n"); */ } } -- cgit v1.2.3 From d114cd84a1c5ce42bb10cd3a2da57b2bbcef909b Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Thu, 5 Nov 2009 18:32:41 +0100 Subject: ALSA: cs4236: detect chip in one pass The cs4236 was two step detection with call to the snd_wss_free() between two steps. The snd_wss_free() did not free a sound device created in the snd_wss_create(). This caused an OOPS during module removal as the same sound device was released twice. The same OOPS happened if the cs4236 module loading failed. Fix this by adapting the snd_cs4236_create() to correctly work with chips less capable then cs4236. The snd_cs4236_create() behaves the same as the snd_wss_create() if the chip is less capable than the cs4236. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai --- sound/isa/cs423x/cs4236.c | 13 +++-------- sound/isa/cs423x/cs4236_lib.c | 50 +++++++++++++++++++++++++++---------------- sound/isa/wss/wss_lib.c | 3 +-- 3 files changed, 35 insertions(+), 31 deletions(-) (limited to 'sound') diff --git a/sound/isa/cs423x/cs4236.c b/sound/isa/cs423x/cs4236.c index a076a6ce807..93fa6720d19 100644 --- a/sound/isa/cs423x/cs4236.c +++ b/sound/isa/cs423x/cs4236.c @@ -394,21 +394,15 @@ static int __devinit snd_cs423x_probe(struct snd_card *card, int dev) return -EBUSY; } - err = snd_wss_create(card, port[dev], cport[dev], + err = snd_cs4236_create(card, port[dev], cport[dev], irq[dev], dma1[dev], dma2[dev], WSS_HW_DETECT3, 0, &chip); if (err < 0) return err; + + acard->chip = chip; if (chip->hardware & WSS_HW_CS4236B_MASK) { - snd_wss_free(chip); - err = snd_cs4236_create(card, - port[dev], cport[dev], - irq[dev], dma1[dev], dma2[dev], - WSS_HW_DETECT, 0, &chip); - if (err < 0) - return err; - acard->chip = chip; err = snd_cs4236_pcm(chip, 0, &pcm); if (err < 0) @@ -418,7 +412,6 @@ static int __devinit snd_cs423x_probe(struct snd_card *card, int dev) if (err < 0) return err; } else { - acard->chip = chip; err = snd_wss_pcm(chip, 0, &pcm); if (err < 0) return err; diff --git a/sound/isa/cs423x/cs4236_lib.c b/sound/isa/cs423x/cs4236_lib.c index 38835f31298..1b1ad1cad32 100644 --- a/sound/isa/cs423x/cs4236_lib.c +++ b/sound/isa/cs423x/cs4236_lib.c @@ -87,6 +87,7 @@ #include #include #include +#include /* * @@ -264,7 +265,10 @@ static void snd_cs4236_resume(struct snd_wss *chip) } #endif /* CONFIG_PM */ - +/* + * This function does no fail if the chip is not CS4236B or compatible. + * It just an equivalent to the snd_wss_create() then. + */ int snd_cs4236_create(struct snd_card *card, unsigned long port, unsigned long cport, @@ -281,21 +285,17 @@ int snd_cs4236_create(struct snd_card *card, *rchip = NULL; if (hardware == WSS_HW_DETECT) hardware = WSS_HW_DETECT3; - if (cport < 0x100) { - snd_printk(KERN_ERR "please, specify control port " - "for CS4236+ chips\n"); - return -ENODEV; - } + err = snd_wss_create(card, port, cport, irq, dma1, dma2, hardware, hwshare, &chip); if (err < 0) return err; - if (!(chip->hardware & WSS_HW_CS4236B_MASK)) { - snd_printk(KERN_ERR "CS4236+: MODE3 and extended registers " - "not available, hardware=0x%x\n", chip->hardware); - snd_device_free(card, chip); - return -ENODEV; + if ((chip->hardware & WSS_HW_CS4236B_MASK) == 0) { + snd_printd("chip is not CS4236+, hardware=0x%x\n", + chip->hardware); + *rchip = chip; + return 0; } #if 0 { @@ -308,9 +308,16 @@ int snd_cs4236_create(struct snd_card *card, idx, snd_cs4236_ctrl_in(chip, idx)); } #endif + if (cport < 0x100 || cport == SNDRV_AUTO_PORT) { + snd_printk(KERN_ERR "please, specify control port " + "for CS4236+ chips\n"); + snd_device_free(card, chip); + return -ENODEV; + } ver1 = snd_cs4236_ctrl_in(chip, 1); ver2 = snd_cs4236_ext_in(chip, CS4236_VERSION); - snd_printdd("CS4236: [0x%lx] C1 (version) = 0x%x, ext = 0x%x\n", cport, ver1, ver2); + snd_printdd("CS4236: [0x%lx] C1 (version) = 0x%x, ext = 0x%x\n", + cport, ver1, ver2); if (ver1 != ver2) { snd_printk(KERN_ERR "CS4236+ chip detected, but " "control port 0x%lx is not valid\n", cport); @@ -321,13 +328,17 @@ int snd_cs4236_create(struct snd_card *card, snd_cs4236_ctrl_out(chip, 2, 0xff); snd_cs4236_ctrl_out(chip, 3, 0x00); snd_cs4236_ctrl_out(chip, 4, 0x80); - snd_cs4236_ctrl_out(chip, 5, ((IEC958_AES1_CON_PCM_CODER & 3) << 6) | IEC958_AES0_CON_EMPHASIS_NONE); + reg = ((IEC958_AES1_CON_PCM_CODER & 3) << 6) | + IEC958_AES0_CON_EMPHASIS_NONE; + snd_cs4236_ctrl_out(chip, 5, reg); snd_cs4236_ctrl_out(chip, 6, IEC958_AES1_CON_PCM_CODER >> 2); snd_cs4236_ctrl_out(chip, 7, 0x00); - /* 0x8c for C8 is valid for Turtle Beach Malibu - the IEC-958 output */ - /* is working with this setup, other hardware should have */ - /* different signal paths and this value should be selectable */ - /* in the future */ + /* + * 0x8c for C8 is valid for Turtle Beach Malibu - the IEC-958 + * output is working with this setup, other hardware should + * have different signal paths and this value should be + * selectable in the future + */ snd_cs4236_ctrl_out(chip, 8, 0x8c); chip->rate_constraint = snd_cs4236_xrate; chip->set_playback_format = snd_cs4236_playback_format; @@ -339,9 +350,10 @@ int snd_cs4236_create(struct snd_card *card, /* initialize extended registers */ for (reg = 0; reg < sizeof(snd_cs4236_ext_map); reg++) - snd_cs4236_ext_out(chip, CS4236_I23VAL(reg), snd_cs4236_ext_map[reg]); + snd_cs4236_ext_out(chip, CS4236_I23VAL(reg), + snd_cs4236_ext_map[reg]); - /* initialize compatible but more featured registers */ + /* initialize compatible but more featured registers */ snd_wss_out(chip, CS4231_LEFT_INPUT, 0x40); snd_wss_out(chip, CS4231_RIGHT_INPUT, 0x40); snd_wss_out(chip, CS4231_AUX1_LEFT_INPUT, 0xff); diff --git a/sound/isa/wss/wss_lib.c b/sound/isa/wss/wss_lib.c index 2ba18978b41..705db092437 100644 --- a/sound/isa/wss/wss_lib.c +++ b/sound/isa/wss/wss_lib.c @@ -1682,7 +1682,7 @@ static void snd_wss_resume(struct snd_wss *chip) } #endif /* CONFIG_PM */ -int snd_wss_free(struct snd_wss *chip) +static int snd_wss_free(struct snd_wss *chip) { release_and_free_resource(chip->res_port); release_and_free_resource(chip->res_cport); @@ -1705,7 +1705,6 @@ int snd_wss_free(struct snd_wss *chip) kfree(chip); return 0; } -EXPORT_SYMBOL(snd_wss_free); static int snd_wss_dev_free(struct snd_device *device) { -- cgit v1.2.3 From 31cef7076ed9409a33f19ea372d6dc5fdefe27ae Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 2 Nov 2009 09:34:16 +0100 Subject: control: remove snd_konctrol_volatile::owner_pid field We do not need to save the ID of the process that locked a control because that information is already available in the owner's file data. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/core/control.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/core/control.c b/sound/core/control.c index a8b7fabe645..814d2cf1a34 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -672,7 +672,7 @@ static int snd_ctl_elem_info(struct snd_ctl_file *ctl, info->access |= SNDRV_CTL_ELEM_ACCESS_LOCK; if (vd->owner == ctl) info->access |= SNDRV_CTL_ELEM_ACCESS_OWNER; - info->owner = vd->owner_pid; + info->owner = vd->owner->pid; } else { info->owner = -1; } @@ -827,7 +827,6 @@ static int snd_ctl_elem_lock(struct snd_ctl_file *file, result = -EBUSY; else { vd->owner = file; - vd->owner_pid = current->pid; result = 0; } } @@ -858,7 +857,6 @@ static int snd_ctl_elem_unlock(struct snd_ctl_file *file, result = -EPERM; else { vd->owner = NULL; - vd->owner_pid = 0; result = 0; } } -- cgit v1.2.3 From 25d27eded1f4fc728e64f443adc339b5229be5d7 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 2 Nov 2009 09:35:44 +0100 Subject: control: use reference-counted pid Instead of storing the PID number, take a reference to the task's pid structure. This protects against duplicates due to PID overflows, and using pid_vnr() ensures that the PID returned by snd_ctl_elem_info() is correct as seen from the current namespace. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/core/control.c | 5 +++-- sound/core/pcm.c | 2 +- sound/core/rawmidi.c | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/core/control.c b/sound/core/control.c index 814d2cf1a34..73dc10ac33f 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -75,7 +75,7 @@ static int snd_ctl_open(struct inode *inode, struct file *file) ctl->card = card; ctl->prefer_pcm_subdevice = -1; ctl->prefer_rawmidi_subdevice = -1; - ctl->pid = current->pid; + ctl->pid = get_pid(task_pid(current)); file->private_data = ctl; write_lock_irqsave(&card->ctl_files_rwlock, flags); list_add_tail(&ctl->list, &card->ctl_files); @@ -125,6 +125,7 @@ static int snd_ctl_release(struct inode *inode, struct file *file) control->vd[idx].owner = NULL; up_write(&card->controls_rwsem); snd_ctl_empty_read_queue(ctl); + put_pid(ctl->pid); kfree(ctl); module_put(card->module); snd_card_file_remove(card, file); @@ -672,7 +673,7 @@ static int snd_ctl_elem_info(struct snd_ctl_file *ctl, info->access |= SNDRV_CTL_ELEM_ACCESS_LOCK; if (vd->owner == ctl) info->access |= SNDRV_CTL_ELEM_ACCESS_OWNER; - info->owner = vd->owner->pid; + info->owner = pid_vnr(vd->owner->pid); } else { info->owner = -1; } diff --git a/sound/core/pcm.c b/sound/core/pcm.c index c69c60b2a48..8e2c7833614 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -809,7 +809,7 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, card = pcm->card; read_lock(&card->ctl_files_rwlock); list_for_each_entry(kctl, &card->ctl_files, list) { - if (kctl->pid == current->pid) { + if (kctl->pid == task_pid(current)) { prefer_subdevice = kctl->prefer_pcm_subdevice; if (prefer_subdevice != -1) break; diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index c0adc14c91f..8a81bdafce6 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -415,7 +415,7 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file) subdevice = -1; read_lock(&card->ctl_files_rwlock); list_for_each_entry(kctl, &card->ctl_files, list) { - if (kctl->pid == current->pid) { + if (kctl->pid == task_pid(current)) { subdevice = kctl->prefer_rawmidi_subdevice; if (subdevice != -1) break; -- cgit v1.2.3 From 4d187fb830a7aa8afb471124abe41b04caf49401 Mon Sep 17 00:00:00 2001 From: Janusz Krzysztofik Date: Wed, 21 Oct 2009 23:10:03 +0200 Subject: ASoC: OMAP: Don't try to set unsupported OMAP_DMA_DATA_BURST_16 on OMAP1 After DMA burst mode has been introduced in sound/soc/omap/omap-pcm.c, omap_pcm_prepare() unconditionally calls: omap_set_dma_src_burst_mode(prtd->dma_ch, OMAP_DMA_DATA_BURST_16); omap_set_dma_dest_burst_mode(prtd->dma_ch, OMAP_DMA_DATA_BURST_16); Current implementation of those two functions found in arch/arm/plat-ompa/dma.c doesn't support OMAP_DMA_DATA_BURST_16 on OMAP1 at all, so they both end with BUG() on that machine. That results in ASoC being completely unusable, at least on my OMAP5910 based Amstrad Delta. The patch corrects the problem by not calling those two functions when run on OMAP1 class based machines. Created against linux-2.6.32-rc5. Tested on Amstrad Delta. Signed-off-by: Janusz Krzysztofik Acked-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/omap/omap-pcm.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c index 5735945788b..6a829eef2a4 100644 --- a/sound/soc/omap/omap-pcm.c +++ b/sound/soc/omap/omap-pcm.c @@ -195,8 +195,12 @@ static int omap_pcm_prepare(struct snd_pcm_substream *substream) else omap_enable_dma_irq(prtd->dma_ch, OMAP_DMA_FRAME_IRQ); - omap_set_dma_src_burst_mode(prtd->dma_ch, OMAP_DMA_DATA_BURST_16); - omap_set_dma_dest_burst_mode(prtd->dma_ch, OMAP_DMA_DATA_BURST_16); + if (!(cpu_class_is_omap1())) { + omap_set_dma_src_burst_mode(prtd->dma_ch, + OMAP_DMA_DATA_BURST_16); + omap_set_dma_dest_burst_mode(prtd->dma_ch, + OMAP_DMA_DATA_BURST_16); + } return 0; } -- cgit v1.2.3 From 6fc786d5034ed7ce2d43c459211137de6d99dd28 Mon Sep 17 00:00:00 2001 From: Jassi Brar Date: Fri, 6 Nov 2009 18:00:24 +0900 Subject: ASoC: S3C64XX I2S: Enable audio-bus clock Added the missing clk_enable after acquiring the 'audio-bus' clock. Signed-off-by: Jassi Brar Signed-off-by: Mark Brown --- sound/soc/s3c24xx/s3c64xx-i2s.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.c b/sound/soc/s3c24xx/s3c64xx-i2s.c index 3c06c401d0f..105a77eeded 100644 --- a/sound/soc/s3c24xx/s3c64xx-i2s.c +++ b/sound/soc/s3c24xx/s3c64xx-i2s.c @@ -220,6 +220,8 @@ static __devinit int s3c64xx_iis_dev_probe(struct platform_device *pdev) goto err; } + clk_enable(i2s->iis_cclk); + ret = s3c_i2sv2_probe(pdev, dai, i2s, 0); if (ret) goto err_clk; -- cgit v1.2.3 From 70edc800a39327174d3244f9226ce8cacd01dc91 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 6 Nov 2009 22:41:29 +0000 Subject: sound: Replace old style lock initializer SPIN_LOCK_UNLOCKED is deprecated. Use __SPIN_LOCK_UNLOCKED instead. Signed-off-by: Thomas Gleixner Signed-off-by: Takashi Iwai --- sound/oss/dmasound/dmasound_core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/oss/dmasound/dmasound_core.c b/sound/oss/dmasound/dmasound_core.c index 793b7f47843..3f3c3f71db4 100644 --- a/sound/oss/dmasound/dmasound_core.c +++ b/sound/oss/dmasound/dmasound_core.c @@ -219,7 +219,9 @@ static int shared_resources_initialised; * Mid level stuff */ -struct sound_settings dmasound = { .lock = SPIN_LOCK_UNLOCKED }; +struct sound_settings dmasound = { + .lock = __SPIN_LOCK_UNLOCKED(dmasound.lock) +}; static inline void sound_silence(void) { -- cgit v1.2.3 From f495088210c8b9e20791d995a8210170c68d2deb Mon Sep 17 00:00:00 2001 From: Julian Anastasov Date: Fri, 6 Nov 2009 23:44:53 +0200 Subject: ALSA: usb-audio: fix combine_word problem Fix combine_word problem where first octet is not read properly. The only affected place seems to be the INPUT_TERMINAL type. Before now, sound controls can be created with the output terminal's name which is a fallback mechanism used only for unknown input terminal types. For example, Line can wrongly appear as Speaker. After the change it should appear as Line. The side effect of this change can be that users can expect the wrong control name in their scripts or programs while now we return the correct one. Probably, these defines should use get_unaligned_le16 and friends. Signed-off-by: Julian Anastasov Cc: Signed-off-by: Takashi Iwai --- sound/usb/usbaudio.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 8e7f78941ba..e9a3a9dca15 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -210,7 +210,7 @@ struct snd_usb_midi_endpoint_info { /* */ -#define combine_word(s) ((*s) | ((unsigned int)(s)[1] << 8)) +#define combine_word(s) ((*(s)) | ((unsigned int)(s)[1] << 8)) #define combine_triple(s) (combine_word(s) | ((unsigned int)(s)[2] << 16)) #define combine_quad(s) (combine_triple(s) | ((unsigned int)(s)[3] << 24)) -- cgit v1.2.3 From 4cae37fa98f4d50778161ec033122444e3c10a01 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sat, 7 Nov 2009 10:18:22 +0100 Subject: ASoC: Remove dead code and labels Remove the dead code and labels "card_err" in the error paths of some codec drivers. Signed-off-by: Takashi Iwai --- sound/soc/codecs/ad1836.c | 5 ----- sound/soc/codecs/ad1938.c | 5 ----- sound/soc/codecs/cx20442.c | 5 ----- sound/soc/codecs/wm8400.c | 5 ----- sound/soc/codecs/wm8900.c | 5 ----- 5 files changed, 25 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c index 2e360c24307..b4be96decf3 100644 --- a/sound/soc/codecs/ad1836.c +++ b/sound/soc/codecs/ad1836.c @@ -387,11 +387,6 @@ static int ad1836_probe(struct platform_device *pdev) snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths)); snd_soc_dapm_new_widgets(codec); - return ret; - -card_err: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); pcm_err: return ret; } diff --git a/sound/soc/codecs/ad1938.c b/sound/soc/codecs/ad1938.c index 09c008ad147..3b2222a0c80 100644 --- a/sound/soc/codecs/ad1938.c +++ b/sound/soc/codecs/ad1938.c @@ -596,11 +596,6 @@ static int ad1938_probe(struct platform_device *pdev) ad1938_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - return ret; - -card_err: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); pcm_err: return ret; } diff --git a/sound/soc/codecs/cx20442.c b/sound/soc/codecs/cx20442.c index d7f9bf18b72..dda751c885c 100644 --- a/sound/soc/codecs/cx20442.c +++ b/sound/soc/codecs/cx20442.c @@ -355,11 +355,6 @@ static int cx20442_codec_probe(struct platform_device *pdev) cx20442_add_widgets(codec); - return ret; - -card_err: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); pcm_err: return ret; } diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c index 0e30997c8db..584af68af22 100644 --- a/sound/soc/codecs/wm8400.c +++ b/sound/soc/codecs/wm8400.c @@ -1400,11 +1400,6 @@ static int wm8400_probe(struct platform_device *pdev) wm8400_add_controls(codec); wm8400_add_widgets(codec); - return ret; - -card_err: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); pcm_err: return ret; } diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index 0d185cb6418..85f67dbe211 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c @@ -1353,11 +1353,6 @@ static int wm8900_probe(struct platform_device *pdev) ARRAY_SIZE(wm8900_snd_controls)); wm8900_add_widgets(codec); - return ret; - -card_err: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); pcm_err: return ret; } -- cgit v1.2.3 From 8f159d720b89f2a6c5ae8a8cc54823933a58120b Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Sat, 7 Nov 2009 01:33:53 -0700 Subject: ASoC/mpc5200: Track DMA position by period number instead of bytes All DMA blocks are lined up to period boundaries, but the DMA handling code tracks bytes instead. This patch reworks the code to track the period index into the DMA buffer instead of the physical address pointer. Doing so makes the code simpler and easier to understand. Signed-off-by: Grant Likely Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/fsl/mpc5200_dma.c | 28 +++++++++------------------- sound/soc/fsl/mpc5200_dma.h | 8 ++------ 2 files changed, 11 insertions(+), 25 deletions(-) (limited to 'sound') diff --git a/sound/soc/fsl/mpc5200_dma.c b/sound/soc/fsl/mpc5200_dma.c index 6096d22283e..986d3c8ab6e 100644 --- a/sound/soc/fsl/mpc5200_dma.c +++ b/sound/soc/fsl/mpc5200_dma.c @@ -58,13 +58,11 @@ static void psc_dma_bcom_enqueue_next_buffer(struct psc_dma_stream *s) /* Prepare and enqueue the next buffer descriptor */ bd = bcom_prepare_next_buffer(s->bcom_task); bd->status = s->period_bytes; - bd->data[0] = s->period_next_pt; + bd->data[0] = s->runtime->dma_addr + (s->period_next * s->period_bytes); bcom_submit_next_buffer(s->bcom_task, NULL); /* Update for next period */ - s->period_next_pt += s->period_bytes; - if (s->period_next_pt >= s->period_end) - s->period_next_pt = s->period_start; + s->period_next = (s->period_next + 1) % s->runtime->periods; } static void psc_dma_bcom_enqueue_tx(struct psc_dma_stream *s) @@ -79,7 +77,7 @@ static void psc_dma_bcom_enqueue_tx(struct psc_dma_stream *s) if (bcom_queue_full(s->bcom_task)) return; - s->appl_ptr += s->period_size; + s->appl_ptr += s->runtime->period_size; psc_dma_bcom_enqueue_next_buffer(s); } @@ -91,7 +89,7 @@ static void psc_dma_bcom_enqueue_tx(struct psc_dma_stream *s) if (bcom_queue_full(s->bcom_task)) return; - s->appl_ptr += s->period_size; + s->appl_ptr += s->runtime->period_size; psc_dma_bcom_enqueue_next_buffer(s); } @@ -108,9 +106,7 @@ static irqreturn_t psc_dma_bcom_irq_tx(int irq, void *_psc_dma_stream) while (bcom_buffer_done(s->bcom_task)) { bcom_retrieve_buffer(s->bcom_task, NULL, NULL); - s->period_current_pt += s->period_bytes; - if (s->period_current_pt >= s->period_end) - s->period_current_pt = s->period_start; + s->period_current = (s->period_current+1) % s->runtime->periods; } psc_dma_bcom_enqueue_tx(s); spin_unlock(&s->psc_dma->lock); @@ -133,9 +129,7 @@ static irqreturn_t psc_dma_bcom_irq_rx(int irq, void *_psc_dma_stream) while (bcom_buffer_done(s->bcom_task)) { bcom_retrieve_buffer(s->bcom_task, NULL, NULL); - s->period_current_pt += s->period_bytes; - if (s->period_current_pt >= s->period_end) - s->period_current_pt = s->period_start; + s->period_current = (s->period_current+1) % s->runtime->periods; psc_dma_bcom_enqueue_next_buffer(s); } @@ -185,12 +179,8 @@ static int psc_dma_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_START: s->period_bytes = frames_to_bytes(runtime, runtime->period_size); - s->period_start = virt_to_phys(runtime->dma_area); - s->period_end = s->period_start + - (s->period_bytes * runtime->periods); - s->period_next_pt = s->period_start; - s->period_current_pt = s->period_start; - s->period_size = runtime->period_size; + s->period_next = 0; + s->period_current = 0; s->active = 1; /* track appl_ptr so that we have a better chance of detecting @@ -343,7 +333,7 @@ psc_dma_pointer(struct snd_pcm_substream *substream) else s = &psc_dma->playback; - count = s->period_current_pt - s->period_start; + count = s->period_current * s->period_bytes; return bytes_to_frames(substream->runtime, count); } diff --git a/sound/soc/fsl/mpc5200_dma.h b/sound/soc/fsl/mpc5200_dma.h index 8d396bb9d9f..529f7a09447 100644 --- a/sound/soc/fsl/mpc5200_dma.h +++ b/sound/soc/fsl/mpc5200_dma.h @@ -13,7 +13,6 @@ * @psc_dma: pointer back to parent psc_dma data structure * @bcom_task: bestcomm task structure * @irq: irq number for bestcomm task - * @period_start: physical address of start of DMA region * @period_end: physical address of end of DMA region * @period_next_pt: physical address of next DMA buffer to enqueue * @period_bytes: size of DMA period in bytes @@ -27,12 +26,9 @@ struct psc_dma_stream { struct bcom_task *bcom_task; int irq; struct snd_pcm_substream *stream; - dma_addr_t period_start; - dma_addr_t period_end; - dma_addr_t period_next_pt; - dma_addr_t period_current_pt; + int period_next; + int period_current; int period_bytes; - int period_size; }; /** -- cgit v1.2.3 From d56b6eb6df7f6fb92383a52d640e27f71e6262d0 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Sat, 7 Nov 2009 01:34:05 -0700 Subject: ASoC/mpc5200: get rid of the appl_ptr tracking nonsense Sound drivers PCM DMA is supposed to free-run until told to stop by the trigger callback. The current code tries to track appl_ptr, to avoid stale buffer data getting played out at the end of the data stream. Unfortunately it also results in race conditions which can cause the audio to stall. Signed-off-by: Grant Likely Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/fsl/mpc5200_dma.c | 52 +++++++-------------------------------------- sound/soc/fsl/mpc5200_dma.h | 2 -- 2 files changed, 8 insertions(+), 46 deletions(-) (limited to 'sound') diff --git a/sound/soc/fsl/mpc5200_dma.c b/sound/soc/fsl/mpc5200_dma.c index 986d3c8ab6e..4e475861f5d 100644 --- a/sound/soc/fsl/mpc5200_dma.c +++ b/sound/soc/fsl/mpc5200_dma.c @@ -65,36 +65,6 @@ static void psc_dma_bcom_enqueue_next_buffer(struct psc_dma_stream *s) s->period_next = (s->period_next + 1) % s->runtime->periods; } -static void psc_dma_bcom_enqueue_tx(struct psc_dma_stream *s) -{ - if (s->appl_ptr > s->runtime->control->appl_ptr) { - /* - * In this case s->runtime->control->appl_ptr has wrapped around. - * Play the data to the end of the boundary, then wrap our own - * appl_ptr back around. - */ - while (s->appl_ptr < s->runtime->boundary) { - if (bcom_queue_full(s->bcom_task)) - return; - - s->appl_ptr += s->runtime->period_size; - - psc_dma_bcom_enqueue_next_buffer(s); - } - s->appl_ptr -= s->runtime->boundary; - } - - while (s->appl_ptr < s->runtime->control->appl_ptr) { - - if (bcom_queue_full(s->bcom_task)) - return; - - s->appl_ptr += s->runtime->period_size; - - psc_dma_bcom_enqueue_next_buffer(s); - } -} - /* Bestcomm DMA irq handler */ static irqreturn_t psc_dma_bcom_irq_tx(int irq, void *_psc_dma_stream) { @@ -107,8 +77,9 @@ static irqreturn_t psc_dma_bcom_irq_tx(int irq, void *_psc_dma_stream) bcom_retrieve_buffer(s->bcom_task, NULL, NULL); s->period_current = (s->period_current+1) % s->runtime->periods; + + psc_dma_bcom_enqueue_next_buffer(s); } - psc_dma_bcom_enqueue_tx(s); spin_unlock(&s->psc_dma->lock); /* If the stream is active, then also inform the PCM middle layer @@ -182,28 +153,21 @@ static int psc_dma_trigger(struct snd_pcm_substream *substream, int cmd) s->period_next = 0; s->period_current = 0; s->active = 1; - - /* track appl_ptr so that we have a better chance of detecting - * end of stream and not over running it. - */ s->runtime = runtime; - s->appl_ptr = s->runtime->control->appl_ptr - - (runtime->period_size * runtime->periods); /* Fill up the bestcomm bd queue and enable DMA. * This will begin filling the PSC's fifo. */ spin_lock_irqsave(&psc_dma->lock, flags); - if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) { + if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) bcom_gen_bd_rx_reset(s->bcom_task); - for (i = 0; i < runtime->periods; i++) - if (!bcom_queue_full(s->bcom_task)) - psc_dma_bcom_enqueue_next_buffer(s); - } else { + else bcom_gen_bd_tx_reset(s->bcom_task); - psc_dma_bcom_enqueue_tx(s); - } + + for (i = 0; i < runtime->periods; i++) + if (!bcom_queue_full(s->bcom_task)) + psc_dma_bcom_enqueue_next_buffer(s); bcom_enable(s->bcom_task); spin_unlock_irqrestore(&psc_dma->lock, flags); diff --git a/sound/soc/fsl/mpc5200_dma.h b/sound/soc/fsl/mpc5200_dma.h index 529f7a09447..d9c741bf9ab 100644 --- a/sound/soc/fsl/mpc5200_dma.h +++ b/sound/soc/fsl/mpc5200_dma.h @@ -19,8 +19,6 @@ */ struct psc_dma_stream { struct snd_pcm_runtime *runtime; - snd_pcm_uframes_t appl_ptr; - int active; struct psc_dma *psc_dma; struct bcom_task *bcom_task; -- cgit v1.2.3 From c4878274750ae0bb90c351a737ac6cdcb608e546 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Sat, 7 Nov 2009 01:34:18 -0700 Subject: ASoC/mpc5200: Improve printk debug output for trigger Signed-off-by: Grant Likely Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/fsl/mpc5200_dma.c | 15 ++++++++++----- sound/soc/fsl/mpc5200_dma.h | 1 + 2 files changed, 11 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/fsl/mpc5200_dma.c b/sound/soc/fsl/mpc5200_dma.c index 4e475861f5d..658e3fa1466 100644 --- a/sound/soc/fsl/mpc5200_dma.c +++ b/sound/soc/fsl/mpc5200_dma.c @@ -77,6 +77,7 @@ static irqreturn_t psc_dma_bcom_irq_tx(int irq, void *_psc_dma_stream) bcom_retrieve_buffer(s->bcom_task, NULL, NULL); s->period_current = (s->period_current+1) % s->runtime->periods; + s->period_count++; psc_dma_bcom_enqueue_next_buffer(s); } @@ -101,6 +102,7 @@ static irqreturn_t psc_dma_bcom_irq_rx(int irq, void *_psc_dma_stream) bcom_retrieve_buffer(s->bcom_task, NULL, NULL); s->period_current = (s->period_current+1) % s->runtime->periods; + s->period_count++; psc_dma_bcom_enqueue_next_buffer(s); } @@ -142,17 +144,17 @@ static int psc_dma_trigger(struct snd_pcm_substream *substream, int cmd) else s = &psc_dma->playback; - dev_dbg(psc_dma->dev, "psc_dma_trigger(substream=%p, cmd=%i)" - " stream_id=%i\n", - substream, cmd, substream->pstr->stream); - switch (cmd) { case SNDRV_PCM_TRIGGER_START: + dev_dbg(psc_dma->dev, "START: stream=%i fbits=%u ps=%u #p=%u\n", + substream->pstr->stream, runtime->frame_bits, + (int)runtime->period_size, runtime->periods); s->period_bytes = frames_to_bytes(runtime, runtime->period_size); s->period_next = 0; s->period_current = 0; s->active = 1; + s->period_count = 0; s->runtime = runtime; /* Fill up the bestcomm bd queue and enable DMA. @@ -177,6 +179,8 @@ static int psc_dma_trigger(struct snd_pcm_substream *substream, int cmd) break; case SNDRV_PCM_TRIGGER_STOP: + dev_dbg(psc_dma->dev, "STOP: stream=%i periods_count=%i\n", + substream->pstr->stream, s->period_count); s->active = 0; spin_lock_irqsave(&psc_dma->lock, flags); @@ -190,7 +194,8 @@ static int psc_dma_trigger(struct snd_pcm_substream *substream, int cmd) break; default: - dev_dbg(psc_dma->dev, "invalid command\n"); + dev_dbg(psc_dma->dev, "unhandled trigger: stream=%i cmd=%i\n", + substream->pstr->stream, cmd); return -EINVAL; } diff --git a/sound/soc/fsl/mpc5200_dma.h b/sound/soc/fsl/mpc5200_dma.h index d9c741bf9ab..c6f29e4d093 100644 --- a/sound/soc/fsl/mpc5200_dma.h +++ b/sound/soc/fsl/mpc5200_dma.h @@ -27,6 +27,7 @@ struct psc_dma_stream { int period_next; int period_current; int period_bytes; + int period_count; }; /** -- cgit v1.2.3 From 1d8222e8df07ce4f86fb7fa80b02bdee03b57985 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Sat, 7 Nov 2009 01:34:31 -0700 Subject: ASoC/mpc5200: add to_psc_dma_stream() helper Move the resolving of the psc_dma_stream pointer to a helper function to reduce duplicate code Signed-off-by: Grant Likely Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/fsl/mpc5200_dma.c | 7 +------ sound/soc/fsl/mpc5200_dma.h | 9 +++++++++ 2 files changed, 10 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/soc/fsl/mpc5200_dma.c b/sound/soc/fsl/mpc5200_dma.c index 658e3fa1466..9c88e15ce69 100644 --- a/sound/soc/fsl/mpc5200_dma.c +++ b/sound/soc/fsl/mpc5200_dma.c @@ -133,17 +133,12 @@ static int psc_dma_trigger(struct snd_pcm_substream *substream, int cmd) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data; struct snd_pcm_runtime *runtime = substream->runtime; - struct psc_dma_stream *s; + struct psc_dma_stream *s = to_psc_dma_stream(substream, psc_dma); struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs; u16 imr; unsigned long flags; int i; - if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) - s = &psc_dma->capture; - else - s = &psc_dma->playback; - switch (cmd) { case SNDRV_PCM_TRIGGER_START: dev_dbg(psc_dma->dev, "START: stream=%i fbits=%u ps=%u #p=%u\n", diff --git a/sound/soc/fsl/mpc5200_dma.h b/sound/soc/fsl/mpc5200_dma.h index c6f29e4d093..956d6a5f5a8 100644 --- a/sound/soc/fsl/mpc5200_dma.h +++ b/sound/soc/fsl/mpc5200_dma.h @@ -68,6 +68,15 @@ struct psc_dma { } stats; }; +/* Utility for retrieving psc_dma_stream structure from a substream */ +inline struct psc_dma_stream * +to_psc_dma_stream(struct snd_pcm_substream *substream, struct psc_dma *psc_dma) +{ + if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) + return &psc_dma->capture; + return &psc_dma->playback; +} + int mpc5200_audio_dma_create(struct of_device *op); int mpc5200_audio_dma_destroy(struct of_device *op); -- cgit v1.2.3 From c939e5c82142978d9d534aca34187a8489fd13f3 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Sat, 7 Nov 2009 01:34:43 -0700 Subject: ASoC/mpc5200: fix enable/disable of AC97 slots The MPC5200 AC97 driver is disabling the slots when a stop trigger is received, but not reenabling them if the stream is started again without processing the hw_params again. This patch fixes the problem by caching the slot enable bit settings calculated at hw_params time so that they can be reapplied every time the start trigger is received. Signed-off-by: Grant Likely Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/fsl/mpc5200_dma.h | 4 ++++ sound/soc/fsl/mpc5200_psc_ac97.c | 39 +++++++++++++++++++++------------------ 2 files changed, 25 insertions(+), 18 deletions(-) (limited to 'sound') diff --git a/sound/soc/fsl/mpc5200_dma.h b/sound/soc/fsl/mpc5200_dma.h index 956d6a5f5a8..22208b373fb 100644 --- a/sound/soc/fsl/mpc5200_dma.h +++ b/sound/soc/fsl/mpc5200_dma.h @@ -16,6 +16,7 @@ * @period_end: physical address of end of DMA region * @period_next_pt: physical address of next DMA buffer to enqueue * @period_bytes: size of DMA period in bytes + * @ac97_slot_bits: Enable bits for turning on the correct AC97 slot */ struct psc_dma_stream { struct snd_pcm_runtime *runtime; @@ -28,6 +29,9 @@ struct psc_dma_stream { int period_current; int period_bytes; int period_count; + + /* AC97 state */ + u32 ac97_slot_bits; }; /** diff --git a/sound/soc/fsl/mpc5200_psc_ac97.c b/sound/soc/fsl/mpc5200_psc_ac97.c index c4ae3e096bb..3dbc7f7cd7b 100644 --- a/sound/soc/fsl/mpc5200_psc_ac97.c +++ b/sound/soc/fsl/mpc5200_psc_ac97.c @@ -130,6 +130,7 @@ static int psc_ac97_hw_analog_params(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { struct psc_dma *psc_dma = cpu_dai->private_data; + struct psc_dma_stream *s = to_psc_dma_stream(substream, psc_dma); dev_dbg(psc_dma->dev, "%s(substream=%p) p_size=%i p_bytes=%i" " periods=%i buffer_size=%i buffer_bytes=%i channels=%i" @@ -140,20 +141,10 @@ static int psc_ac97_hw_analog_params(struct snd_pcm_substream *substream, params_channels(params), params_rate(params), params_format(params)); - - if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) { - if (params_channels(params) == 1) - psc_dma->slots |= 0x00000100; - else - psc_dma->slots |= 0x00000300; - } else { - if (params_channels(params) == 1) - psc_dma->slots |= 0x01000000; - else - psc_dma->slots |= 0x03000000; - } - out_be32(&psc_dma->psc_regs->ac97_slots, psc_dma->slots); - + /* Determine the set of enable bits to turn on */ + s->ac97_slot_bits = (params_channels(params) == 1) ? 0x100 : 0x300; + if (substream->pstr->stream != SNDRV_PCM_STREAM_CAPTURE) + s->ac97_slot_bits <<= 16; return 0; } @@ -163,6 +154,8 @@ static int psc_ac97_hw_digital_params(struct snd_pcm_substream *substream, { struct psc_dma *psc_dma = cpu_dai->private_data; + dev_dbg(psc_dma->dev, "%s(substream=%p)\n", __func__, substream); + if (params_channels(params) == 1) out_be32(&psc_dma->psc_regs->ac97_slots, 0x01000000); else @@ -176,14 +169,24 @@ static int psc_ac97_trigger(struct snd_pcm_substream *substream, int cmd, { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data; + struct psc_dma_stream *s = to_psc_dma_stream(substream, psc_dma); switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + dev_dbg(psc_dma->dev, "AC97 START: stream=%i\n", + substream->pstr->stream); + + /* Set the slot enable bits */ + psc_dma->slots |= s->ac97_slot_bits; + out_be32(&psc_dma->psc_regs->ac97_slots, psc_dma->slots); + break; + case SNDRV_PCM_TRIGGER_STOP: - if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) - psc_dma->slots &= 0xFFFF0000; - else - psc_dma->slots &= 0x0000FFFF; + dev_dbg(psc_dma->dev, "AC97 STOP: stream=%i\n", + substream->pstr->stream); + /* Clear the slot enable bits */ + psc_dma->slots &= ~(s->ac97_slot_bits); out_be32(&psc_dma->psc_regs->ac97_slots, psc_dma->slots); break; } -- cgit v1.2.3 From f37325a956f0ee4356793da7d93c699a25b21d92 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sat, 7 Nov 2009 22:13:39 +0000 Subject: ALSA: snd-aica: declare MODULE_FIRMWARE Signed-off-by: Ben Hutchings Signed-off-by: Takashi Iwai --- sound/sh/aica.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/sh/aica.c b/sound/sh/aica.c index 583a3693df7..a0df401ebb9 100644 --- a/sound/sh/aica.c +++ b/sound/sh/aica.c @@ -49,6 +49,7 @@ MODULE_AUTHOR("Adrian McMenamin "); MODULE_DESCRIPTION("Dreamcast AICA sound (pcm) driver"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{Yamaha/SEGA, AICA}}"); +MODULE_FIRMWARE("aica_firmware.bin"); /* module parameters */ #define CARD_NAME "AICA" -- cgit v1.2.3 From faa1242c59311525b0f337e95ae3c324a833a8eb Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Sun, 8 Nov 2009 11:58:08 +0100 Subject: ALSA: es18xx: code improvements 1. Set the third argument of the snd_device_new to not NULL, so there is no warning about bug during chip detection. The third argument is not used in this driver. It was changed in my previous patch. 2. Remove the fm_port and mpu_port fields from the snd_es18xx structure. They can be converted to function arguments. 3. Remove the dmaN_size fields from the snd_es18xx structure. These values are used only in pointer functions and can be easily calculated. 4. Remove the ctrl_lock spinlock which is used only in one read function which is called once during chip initialization. There are many writes to the same register and they are not protected on purpose (see the comment ina the snd_es18xx_config_write()). 5. Use the first part of the text5Sources string table as the text4Soruces table (they are the same). 6. Merge the same cases for the ES1887 and ES1888 when setting chip's caps. 7. Move the snd_es18xx_reset() to __devinit section. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai --- sound/isa/es18xx.c | 91 ++++++++++++++++++++++++------------------------------ 1 file changed, 41 insertions(+), 50 deletions(-) (limited to 'sound') diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c index 5cf42b4d65f..06e871e66c9 100644 --- a/sound/isa/es18xx.c +++ b/sound/isa/es18xx.c @@ -102,8 +102,6 @@ struct snd_es18xx { unsigned long port; /* port of ESS chip */ - unsigned long mpu_port; /* MPU-401 port of ESS chip */ - unsigned long fm_port; /* FM port */ unsigned long ctrl_port; /* Control port of ESS chip */ struct resource *res_port; struct resource *res_mpu_port; @@ -116,8 +114,6 @@ struct snd_es18xx { unsigned short audio2_vol; /* volume level of audio2 */ unsigned short active; /* active channel mask */ - unsigned int dma1_size; - unsigned int dma2_size; unsigned int dma1_shift; unsigned int dma2_shift; @@ -135,7 +131,6 @@ struct snd_es18xx { spinlock_t reg_lock; spinlock_t mixer_lock; - spinlock_t ctrl_lock; #ifdef CONFIG_PM unsigned char pm_reg; #endif @@ -354,7 +349,7 @@ static inline int snd_es18xx_mixer_writable(struct snd_es18xx *chip, unsigned ch } -static int snd_es18xx_reset(struct snd_es18xx *chip) +static int __devinit snd_es18xx_reset(struct snd_es18xx *chip) { int i; outb(0x03, chip->port + 0x06); @@ -490,8 +485,6 @@ static int snd_es18xx_playback1_prepare(struct snd_es18xx *chip, unsigned int size = snd_pcm_lib_buffer_bytes(substream); unsigned int count = snd_pcm_lib_period_bytes(substream); - chip->dma2_size = size; - snd_es18xx_rate_set(chip, substream, DAC2); /* Transfer Count Reload */ @@ -591,8 +584,6 @@ static int snd_es18xx_capture_prepare(struct snd_pcm_substream *substream) unsigned int size = snd_pcm_lib_buffer_bytes(substream); unsigned int count = snd_pcm_lib_period_bytes(substream); - chip->dma1_size = size; - snd_es18xx_reset_fifo(chip); /* Set stereo/mono */ @@ -659,8 +650,6 @@ static int snd_es18xx_playback2_prepare(struct snd_es18xx *chip, unsigned int size = snd_pcm_lib_buffer_bytes(substream); unsigned int count = snd_pcm_lib_period_bytes(substream); - chip->dma1_size = size; - snd_es18xx_reset_fifo(chip); /* Set stereo/mono */ @@ -821,17 +810,18 @@ static irqreturn_t snd_es18xx_interrupt(int irq, void *dev_id) static snd_pcm_uframes_t snd_es18xx_playback_pointer(struct snd_pcm_substream *substream) { struct snd_es18xx *chip = snd_pcm_substream_chip(substream); + unsigned int size = snd_pcm_lib_buffer_bytes(substream); int pos; if (substream->number == 0 && (chip->caps & ES18XX_PCM2)) { if (!(chip->active & DAC2)) return 0; - pos = snd_dma_pointer(chip->dma2, chip->dma2_size); + pos = snd_dma_pointer(chip->dma2, size); return pos >> chip->dma2_shift; } else { if (!(chip->active & DAC1)) return 0; - pos = snd_dma_pointer(chip->dma1, chip->dma1_size); + pos = snd_dma_pointer(chip->dma1, size); return pos >> chip->dma1_shift; } } @@ -839,11 +829,12 @@ static snd_pcm_uframes_t snd_es18xx_playback_pointer(struct snd_pcm_substream *s static snd_pcm_uframes_t snd_es18xx_capture_pointer(struct snd_pcm_substream *substream) { struct snd_es18xx *chip = snd_pcm_substream_chip(substream); + unsigned int size = snd_pcm_lib_buffer_bytes(substream); int pos; if (!(chip->active & ADC1)) return 0; - pos = snd_dma_pointer(chip->dma1, chip->dma1_size); + pos = snd_dma_pointer(chip->dma1, size); return pos >> chip->dma1_shift; } @@ -974,9 +965,6 @@ static int snd_es18xx_capture_close(struct snd_pcm_substream *substream) static int snd_es18xx_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts4Source[4] = { - "Mic", "CD", "Line", "Master" - }; static char *texts5Source[5] = { "Mic", "CD", "Line", "Master", "Mix" }; @@ -994,7 +982,8 @@ static int snd_es18xx_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_ele uinfo->value.enumerated.items = 4; if (uinfo->value.enumerated.item > 3) uinfo->value.enumerated.item = 3; - strcpy(uinfo->value.enumerated.name, texts4Source[uinfo->value.enumerated.item]); + strcpy(uinfo->value.enumerated.name, + texts5Source[uinfo->value.enumerated.item]); break; case 0x1887: case 0x1888: @@ -1378,11 +1367,9 @@ ES18XX_SINGLE("Hardware Master Volume Split", 0, 0x64, 7, 1, 0), static int __devinit snd_es18xx_config_read(struct snd_es18xx *chip, unsigned char reg) { int data; - unsigned long flags; - spin_lock_irqsave(&chip->ctrl_lock, flags); + outb(reg, chip->ctrl_port); data = inb(chip->ctrl_port + 1); - spin_unlock_irqrestore(&chip->ctrl_lock, flags); return data; } @@ -1398,7 +1385,9 @@ static void __devinit snd_es18xx_config_write(struct snd_es18xx *chip, #endif } -static int __devinit snd_es18xx_initialize(struct snd_es18xx *chip) +static int __devinit snd_es18xx_initialize(struct snd_es18xx *chip, + unsigned long mpu_port, + unsigned long fm_port) { int mask = 0; @@ -1412,15 +1401,15 @@ static int __devinit snd_es18xx_initialize(struct snd_es18xx *chip) if (chip->caps & ES18XX_CONTROL) { /* Hardware volume IRQ */ snd_es18xx_config_write(chip, 0x27, chip->irq); - if (chip->fm_port > 0 && chip->fm_port != SNDRV_AUTO_PORT) { + if (fm_port > 0 && fm_port != SNDRV_AUTO_PORT) { /* FM I/O */ - snd_es18xx_config_write(chip, 0x62, chip->fm_port >> 8); - snd_es18xx_config_write(chip, 0x63, chip->fm_port & 0xff); + snd_es18xx_config_write(chip, 0x62, fm_port >> 8); + snd_es18xx_config_write(chip, 0x63, fm_port & 0xff); } - if (chip->mpu_port > 0 && chip->mpu_port != SNDRV_AUTO_PORT) { + if (mpu_port > 0 && mpu_port != SNDRV_AUTO_PORT) { /* MPU-401 I/O */ - snd_es18xx_config_write(chip, 0x64, chip->mpu_port >> 8); - snd_es18xx_config_write(chip, 0x65, chip->mpu_port & 0xff); + snd_es18xx_config_write(chip, 0x64, mpu_port >> 8); + snd_es18xx_config_write(chip, 0x65, mpu_port & 0xff); /* MPU-401 IRQ */ snd_es18xx_config_write(chip, 0x28, chip->irq); } @@ -1507,11 +1496,12 @@ static int __devinit snd_es18xx_initialize(struct snd_es18xx *chip) snd_es18xx_mixer_write(chip, 0x7A, 0x68); /* Enable and set hardware volume interrupt */ snd_es18xx_mixer_write(chip, 0x64, 0x06); - if (chip->mpu_port > 0 && chip->mpu_port != SNDRV_AUTO_PORT) { + if (mpu_port > 0 && mpu_port != SNDRV_AUTO_PORT) { /* MPU401 share irq with audio Joystick enabled FM enabled */ - snd_es18xx_mixer_write(chip, 0x40, 0x43 | (chip->mpu_port & 0xf0) >> 1); + snd_es18xx_mixer_write(chip, 0x40, + 0x43 | (mpu_port & 0xf0) >> 1); } snd_es18xx_mixer_write(chip, 0x7f, ((irqmask + 1) << 1) | 0x01); } @@ -1629,7 +1619,9 @@ static int __devinit snd_es18xx_identify(struct snd_es18xx *chip) return 0; } -static int __devinit snd_es18xx_probe(struct snd_es18xx *chip) +static int __devinit snd_es18xx_probe(struct snd_es18xx *chip, + unsigned long mpu_port, + unsigned long fm_port) { if (snd_es18xx_identify(chip) < 0) { snd_printk(KERN_ERR PFX "[0x%lx] ESS chip not found\n", chip->port); @@ -1650,8 +1642,6 @@ static int __devinit snd_es18xx_probe(struct snd_es18xx *chip) chip->caps = ES18XX_PCM2 | ES18XX_SPATIALIZER | ES18XX_RECMIX | ES18XX_NEW_RATE | ES18XX_AUXB | ES18XX_I2S | ES18XX_CONTROL | ES18XX_HWV; break; case 0x1887: - chip->caps = ES18XX_PCM2 | ES18XX_RECMIX | ES18XX_AUXB | ES18XX_DUPLEX_SAME; - break; case 0x1888: chip->caps = ES18XX_PCM2 | ES18XX_RECMIX | ES18XX_AUXB | ES18XX_DUPLEX_SAME; break; @@ -1666,7 +1656,7 @@ static int __devinit snd_es18xx_probe(struct snd_es18xx *chip) if (chip->dma1 == chip->dma2) chip->caps &= ~(ES18XX_PCM2 | ES18XX_DUPLEX_SAME); - return snd_es18xx_initialize(chip); + return snd_es18xx_initialize(chip, mpu_port, fm_port); } static struct snd_pcm_ops snd_es18xx_playback_ops = { @@ -1802,10 +1792,7 @@ static int __devinit snd_es18xx_new_device(struct snd_card *card, spin_lock_init(&chip->reg_lock); spin_lock_init(&chip->mixer_lock); - spin_lock_init(&chip->ctrl_lock); chip->port = port; - chip->mpu_port = mpu_port; - chip->fm_port = fm_port; chip->irq = -1; chip->dma1 = -1; chip->dma2 = -1; @@ -1841,11 +1828,11 @@ static int __devinit snd_es18xx_new_device(struct snd_card *card, } chip->dma2 = dma2; - if (snd_es18xx_probe(chip) < 0) { + if (snd_es18xx_probe(chip, mpu_port, fm_port) < 0) { snd_es18xx_free(card); - return -ENODEV; - } - err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, NULL, &ops); + return -ENODEV; + } + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); if (err < 0) { snd_es18xx_free(card); return err; @@ -1980,7 +1967,7 @@ static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; /* Enable this card */ #ifdef CONFIG_PNP -static int isapnp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1}; +static int isapnp[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; #endif static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x220,0x240,0x260,0x280 */ #ifndef CONFIG_PNP @@ -2160,19 +2147,23 @@ static int __devinit snd_audiodrive_probe(struct snd_card *card, int dev) return err; if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) { - if (snd_opl3_create(card, chip->fm_port, chip->fm_port + 2, OPL3_HW_OPL3, 0, &opl3) < 0) { - snd_printk(KERN_WARNING PFX "opl3 not detected at 0x%lx\n", chip->fm_port); + if (snd_opl3_create(card, fm_port[dev], fm_port[dev] + 2, + OPL3_HW_OPL3, 0, &opl3) < 0) { + snd_printk(KERN_WARNING PFX + "opl3 not detected at 0x%lx\n", + fm_port[dev]); } else { - if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) + err = snd_opl3_hwdep_new(opl3, 0, 1, NULL); + if (err < 0) return err; } } if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) { - if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_ES18XX, - chip->mpu_port, 0, - irq[dev], 0, - &chip->rmidi)) < 0) + err = snd_mpu401_uart_new(card, 0, MPU401_HW_ES18XX, + mpu_port[dev], 0, + irq[dev], 0, &chip->rmidi); + if (err < 0) return err; } -- cgit v1.2.3 From 7c5af6ffd69bb2bb3c86b374153627529d67598c Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sat, 24 Oct 2009 15:55:12 +0200 Subject: pcmcia: use dynamic debug infrastructure, deprecate CS_CHECK (sound) Convert PCMCIA drivers to use the dynamic debug infrastructure, instead of requiring manual settings of PCMCIA_DEBUG. Also, remove all usages of the CS_CHECK macro and replace them with proper Linux style calling and return value checking. The extra error reporting may be dropped, as the PCMCIA core already complains about any (non-driver-author) errors. CC: Jaroslav Kysela CC: alsa-devel@alsa-project.org Signed-off-by: Dominik Brodowski --- sound/pcmcia/pdaudiocf/pdaudiocf.c | 21 ++++++++++++--------- sound/pcmcia/vx/vxpocket.c | 21 ++++++++++++--------- 2 files changed, 24 insertions(+), 18 deletions(-) (limited to 'sound') diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf.c b/sound/pcmcia/pdaudiocf/pdaudiocf.c index 7dea74b71cf..64b859925c0 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf.c @@ -217,20 +217,25 @@ static void snd_pdacf_detach(struct pcmcia_device *link) * configuration callback */ -#define CS_CHECK(fn, ret) \ -do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) - static int pdacf_config(struct pcmcia_device *link) { struct snd_pdacf *pdacf = link->priv; - int last_fn, last_ret; + int ret; snd_printdd(KERN_DEBUG "pdacf_config called\n"); link->conf.ConfigIndex = 0x5; - CS_CHECK(RequestIO, pcmcia_request_io(link, &link->io)); - CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); - CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); + ret = pcmcia_request_io(link, &link->io); + if (ret) + goto failed; + + ret = pcmcia_request_irq(link, &link->irq); + if (ret) + goto failed; + + ret = pcmcia_request_configuration(link, &link->conf); + if (ret) + goto failed; if (snd_pdacf_assign_resources(pdacf, link->io.BasePort1, link->irq.AssignedIRQ) < 0) goto failed; @@ -238,8 +243,6 @@ static int pdacf_config(struct pcmcia_device *link) link->dev_node = &pdacf->node; return 0; -cs_failed: - cs_error(link, last_fn, last_ret); failed: pcmcia_disable_device(link); return -ENODEV; diff --git a/sound/pcmcia/vx/vxpocket.c b/sound/pcmcia/vx/vxpocket.c index 7445cc8a47d..1492744ad67 100644 --- a/sound/pcmcia/vx/vxpocket.c +++ b/sound/pcmcia/vx/vxpocket.c @@ -213,14 +213,11 @@ static int snd_vxpocket_assign_resources(struct vx_core *chip, int port, int irq * configuration callback */ -#define CS_CHECK(fn, ret) \ -do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) - static int vxpocket_config(struct pcmcia_device *link) { struct vx_core *chip = link->priv; struct snd_vxpocket *vxp = (struct snd_vxpocket *)chip; - int last_fn, last_ret; + int ret; snd_printdd(KERN_DEBUG "vxpocket_config called\n"); @@ -235,9 +232,17 @@ static int vxpocket_config(struct pcmcia_device *link) strcpy(chip->card->driver, vxp440_hw.name); } - CS_CHECK(RequestIO, pcmcia_request_io(link, &link->io)); - CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); - CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); + ret = pcmcia_request_io(link, &link->io); + if (ret) + goto failed; + + ret = pcmcia_request_irq(link, &link->irq); + if (ret) + goto failed; + + ret = pcmcia_request_configuration(link, &link->conf); + if (ret) + goto failed; chip->dev = &handle_to_dev(link); snd_card_set_dev(chip->card, chip->dev); @@ -248,8 +253,6 @@ static int vxpocket_config(struct pcmcia_device *link) link->dev_node = &vxp->node; return 0; -cs_failed: - cs_error(link, last_fn, last_ret); failed: pcmcia_disable_device(link); return -ENODEV; -- cgit v1.2.3 From 06fe9fb4182177fb046e6d934f80254dd90956ea Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Mon, 28 Sep 2009 21:43:57 -0400 Subject: tree-wide: fix a very frequent spelling mistake something-bility is spelled as something-blity so a grep for 'blit' would find these lines this is so trivial that I didn't split it by subsystem / copy additional maintainers - all changes are to comments The only purpose is to get fewer false positives when grepping around the kernel sources. Signed-off-by: Dirk Hohndel Signed-off-by: Jiri Kosina --- sound/pci/ice1712/juli.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/ice1712/juli.c b/sound/pci/ice1712/juli.c index fd948bfd9ae..9c0f78ea2c4 100644 --- a/sound/pci/ice1712/juli.c +++ b/sound/pci/ice1712/juli.c @@ -380,7 +380,7 @@ static struct snd_kcontrol_new juli_mute_controls[] __devinitdata = { * inputs) are fed from Xilinx. * * I even checked traces on board and coded a support in driver for - * an alternative possiblity - the unused I2S ICE output channels + * an alternative possibility - the unused I2S ICE output channels * switched to HW-IN/SPDIF-IN and providing the monitoring signal to * the DAC - to no avail. The I2S outputs seem to be unconnected. * -- cgit v1.2.3 From fa3012318bfb395552baef69bb1ebe87e64945c8 Mon Sep 17 00:00:00 2001 From: Michael Roth Date: Sun, 4 Oct 2009 18:14:29 +0200 Subject: Kconfig: Remove useless and sometimes wrong comments Additionally, some excessive newlines removed. Signed-off-by: Michael Roth Signed-off-by: Jiri Kosina --- sound/Kconfig | 4 ---- sound/oss/Kconfig | 2 -- 2 files changed, 6 deletions(-) (limited to 'sound') diff --git a/sound/Kconfig b/sound/Kconfig index 439e15c8faa..4b5365ad6b4 100644 --- a/sound/Kconfig +++ b/sound/Kconfig @@ -1,6 +1,3 @@ -# sound/Config.in -# - menuconfig SOUND tristate "Sound card support" depends on HAS_IOMEM @@ -136,4 +133,3 @@ config AC97_BUS sound subsystem and other function drivers completely unrelated to sound although they're sharing the AC97 bus. Concerned drivers should "select" this. - diff --git a/sound/oss/Kconfig b/sound/oss/Kconfig index bcf2a0698d5..ea0b1aeffe6 100644 --- a/sound/oss/Kconfig +++ b/sound/oss/Kconfig @@ -1,5 +1,3 @@ -# drivers/sound/Config.in -# # 18 Apr 1998, Michael Elizabeth Chastain, # More hacking for modularisation. # -- cgit v1.2.3 From b71a8eb0fa64ec6d00175f479e3ef851703568af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 6 Oct 2009 12:42:51 +0200 Subject: tree-wide: fix typos "selct" + "slect" -> "select" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch was generated by git grep -E -i -l 's(le|el)ct' | xargs -r perl -p -i -e 's/([Ss])(le|el)ct/$1elect/ with only skipping net/netfilter/xt_SECMARK.c and include/linux/netfilter/xt_SECMARK.h which have a struct member called selctx. Signed-off-by: Uwe Kleine-König Signed-off-by: Jiri Kosina --- sound/pci/hda/patch_cirrus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 8ba306856d3..7b0446fa600 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -947,7 +947,7 @@ static void init_input(struct hda_codec *codec) coef |= 0x0500; /* DMIC2 enable 2 channels, disable GPIO1 */ if (is_active_pin(codec, CS_DMIC1_PIN_NID)) coef |= 0x1800; /* DMIC1 enable 2 channels, disable GPIO0 - * No effect if SPDIF_OUT2 is slected in + * No effect if SPDIF_OUT2 is selected in * IDX_SPDIF_CTL. */ cs_vendor_coef_set(codec, IDX_ADC_CFG, coef); -- cgit v1.2.3 From 9e5d86fe6a401f7957f6ea02ee300db0f6c03d03 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Mon, 9 Nov 2009 08:44:32 +0200 Subject: ASoC: Pandora: Pass SRG input clock frequency to the OMAP McBSP DAI Upcoming change to omap-mcbsp.c require that machine drivers using OMAP as a DAI master to pass sample rate generator input clock frequency to the omap-mcbsp.c DAI driver. Pandora is using 256*Fs output from the TWL4030 codec as an input clock to the McBSP sample rate generator. Signed-off-by: Jarkko Nikula Tested-by: Grazvydas Ignotas Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/omap/omap3pandora.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) (limited to 'sound') diff --git a/sound/soc/omap/omap3pandora.c b/sound/soc/omap/omap3pandora.c index ad219aaf7cb..cace5f13792 100644 --- a/sound/soc/omap/omap3pandora.c +++ b/sound/soc/omap/omap3pandora.c @@ -40,9 +40,12 @@ #define PREFIX "ASoC omap3pandora: " -static int omap3pandora_cmn_hw_params(struct snd_soc_dai *codec_dai, - struct snd_soc_dai *cpu_dai, unsigned int fmt) +static int omap3pandora_cmn_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, unsigned int fmt) { + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; int ret; /* Set codec DAI configuration */ @@ -68,8 +71,9 @@ static int omap3pandora_cmn_hw_params(struct snd_soc_dai *codec_dai, } /* Set McBSP clock to external */ - ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_MCBSP_SYSCLK_CLKS_EXT, 0, - SND_SOC_CLOCK_IN); + ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_MCBSP_SYSCLK_CLKS_EXT, + 256 * params_rate(params), + SND_SOC_CLOCK_IN); if (ret < 0) { pr_err(PREFIX "can't set cpu system clock\n"); return ret; @@ -87,11 +91,7 @@ static int omap3pandora_cmn_hw_params(struct snd_soc_dai *codec_dai, static int omap3pandora_out_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; - - return omap3pandora_cmn_hw_params(codec_dai, cpu_dai, + return omap3pandora_cmn_hw_params(substream, params, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_CBS_CFS); @@ -100,11 +100,7 @@ static int omap3pandora_out_hw_params(struct snd_pcm_substream *substream, static int omap3pandora_in_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; - - return omap3pandora_cmn_hw_params(codec_dai, cpu_dai, + return omap3pandora_cmn_hw_params(substream, params, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); -- cgit v1.2.3 From 5f63ef9909c187581c7f2c28fbc93866a0d59f7f Mon Sep 17 00:00:00 2001 From: Graeme Gregory Date: Mon, 9 Nov 2009 19:02:15 +0000 Subject: ASoC: omap-mcbsp - add support for upto 16 channels. This patch increases the number of supported audio channels from 4 to 16 and has been sponsored by Shotspotter Inc. It also fixes a FSYNC rate calculation bug when McBSP is FSYNC master. Signed-off-by: Graeme Gregory Signed-off-by: Liam Girdwood Acked-by: Peter Ujfalusi Tested-by: Peter Ujfalusi Acked-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/omap/omap-mcbsp.c | 63 ++++++++++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 26 deletions(-) (limited to 'sound') diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index 3341f49402c..45be94201c8 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -49,6 +49,8 @@ struct omap_mcbsp_data { */ int active; int configured; + unsigned int in_freq; + int clk_div; }; #define to_mcbsp(priv) container_of((priv), struct omap_mcbsp_data, bus_id) @@ -257,7 +259,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, int dma, bus_id = mcbsp_data->bus_id, id = cpu_dai->id; int wlen, channels, wpf, sync_mode = OMAP_DMA_SYNC_ELEMENT; unsigned long port; - unsigned int format; + unsigned int format, div, framesize, master; if (cpu_class_is_omap1()) { dma = omap1_dma_reqs[bus_id][substream->stream]; @@ -294,28 +296,19 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, format = mcbsp_data->fmt & SND_SOC_DAIFMT_FORMAT_MASK; wpf = channels = params_channels(params); - switch (channels) { - case 2: - if (format == SND_SOC_DAIFMT_I2S) { - /* Use dual-phase frames */ - regs->rcr2 |= RPHASE; - regs->xcr2 |= XPHASE; - /* Set 1 word per (McBSP) frame for phase1 and phase2 */ - wpf--; - regs->rcr2 |= RFRLEN2(wpf - 1); - regs->xcr2 |= XFRLEN2(wpf - 1); - } - case 1: - case 4: - /* Set word per (McBSP) frame for phase1 */ - regs->rcr1 |= RFRLEN1(wpf - 1); - regs->xcr1 |= XFRLEN1(wpf - 1); - break; - default: - /* Unsupported number of channels */ - return -EINVAL; + if (channels == 2 && format == SND_SOC_DAIFMT_I2S) { + /* Use dual-phase frames */ + regs->rcr2 |= RPHASE; + regs->xcr2 |= XPHASE; + /* Set 1 word per (McBSP) frame for phase1 and phase2 */ + wpf--; + regs->rcr2 |= RFRLEN2(wpf - 1); + regs->xcr2 |= XFRLEN2(wpf - 1); } + regs->rcr1 |= RFRLEN1(wpf - 1); + regs->xcr1 |= XFRLEN1(wpf - 1); + switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: /* Set word lengths */ @@ -330,15 +323,30 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } + /* In McBSP master modes, FRAME (i.e. sample rate) is generated + * by _counting_ BCLKs. Calculate frame size in BCLKs */ + master = mcbsp_data->fmt & SND_SOC_DAIFMT_MASTER_MASK; + if (master == SND_SOC_DAIFMT_CBS_CFS) { + div = mcbsp_data->clk_div ? mcbsp_data->clk_div : 1; + framesize = (mcbsp_data->in_freq / div) / params_rate(params); + + if (framesize < wlen * channels) { + printk(KERN_ERR "%s: not enough bandwidth for desired rate and " + "channels\n", __func__); + return -EINVAL; + } + } else + framesize = wlen * channels; + /* Set FS period and length in terms of bit clock periods */ switch (format) { case SND_SOC_DAIFMT_I2S: - regs->srgr2 |= FPER(wlen * channels - 1); - regs->srgr1 |= FWID(wlen - 1); + regs->srgr2 |= FPER(framesize - 1); + regs->srgr1 |= FWID((framesize >> 1) - 1); break; case SND_SOC_DAIFMT_DSP_A: case SND_SOC_DAIFMT_DSP_B: - regs->srgr2 |= FPER(wlen * channels - 1); + regs->srgr2 |= FPER(framesize - 1); regs->srgr1 |= FWID(0); break; } @@ -454,6 +462,7 @@ static int omap_mcbsp_dai_set_clkdiv(struct snd_soc_dai *cpu_dai, if (div_id != OMAP_MCBSP_CLKGDV) return -ENODEV; + mcbsp_data->clk_div = div; regs->srgr1 |= CLKGDV(div - 1); return 0; @@ -554,6 +563,8 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs; int err = 0; + mcbsp_data->in_freq = freq; + switch (clk_id) { case OMAP_MCBSP_SYSCLK_CLK: regs->srgr2 |= CLKSM; @@ -598,13 +609,13 @@ static struct snd_soc_dai_ops omap_mcbsp_dai_ops = { .id = (link_id), \ .playback = { \ .channels_min = 1, \ - .channels_max = 4, \ + .channels_max = 16, \ .rates = OMAP_MCBSP_RATES, \ .formats = SNDRV_PCM_FMTBIT_S16_LE, \ }, \ .capture = { \ .channels_min = 1, \ - .channels_max = 4, \ + .channels_max = 16, \ .rates = OMAP_MCBSP_RATES, \ .formats = SNDRV_PCM_FMTBIT_S16_LE, \ }, \ -- cgit v1.2.3 From 68d019553b8cc4ddac7f861e23efbe48a1367490 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 4 Nov 2009 09:58:20 +0200 Subject: ASoC: TWL4030: Do not modify the APLL_CTL register APLL_CTL register is configured by the twl4030-codec MFD driver. Remove code, which makes changes in the APLL_CTL register, and replace those with checks against the configured audio_mclk configuration done in the MFD driver. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 76 +++++++++++++++++++--------------------------- 1 file changed, 31 insertions(+), 45 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 928257b2511..510b8b226f9 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -214,7 +214,8 @@ static void twl4030_init_chip(struct snd_soc_codec *codec) /* set all audio section registers to reasonable defaults */ for (i = TWL4030_REG_OPTION; i <= TWL4030_REG_MISC_SET_2; i++) - twl4030_write(codec, i, cache[i]); + if (i != TWL4030_REG_APLL_CTL) + twl4030_write(codec, i, cache[i]); } @@ -1753,30 +1754,23 @@ static int twl4030_set_dai_sysclk(struct snd_soc_dai *codec_dai, { struct snd_soc_codec *codec = codec_dai->codec; struct twl4030_priv *twl4030 = codec->private_data; - u8 apll_ctrl; - apll_ctrl = twl4030_read_reg_cache(codec, TWL4030_REG_APLL_CTL); - apll_ctrl &= ~TWL4030_APLL_INFREQ; switch (freq) { case 19200000: - apll_ctrl |= TWL4030_APLL_INFREQ_19200KHZ; - twl4030->sysclk = 19200; - break; case 26000000: - apll_ctrl |= TWL4030_APLL_INFREQ_26000KHZ; - twl4030->sysclk = 26000; - break; case 38400000: - apll_ctrl |= TWL4030_APLL_INFREQ_38400KHZ; - twl4030->sysclk = 38400; break; default: - printk(KERN_ERR "TWL4030 set sysclk: unknown rate %d\n", - freq); + dev_err(codec->dev, "Unsupported APLL mclk: %u\n", freq); return -EINVAL; } - twl4030_write(codec, TWL4030_REG_APLL_CTL, apll_ctrl); + if ((freq / 1000) != twl4030->sysclk) { + dev_err(codec->dev, + "Mismatch in APLL mclk: %u (configured: %u)\n", + freq, twl4030->sysclk * 1000); + return -EINVAL; + } return 0; } @@ -1874,18 +1868,16 @@ static int twl4030_voice_startup(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_codec *codec = socdev->card->codec; - u8 infreq; + struct twl4030_priv *twl4030 = codec->private_data; u8 mode; /* If the system master clock is not 26MHz, the voice PCM interface is * not avilable. */ - infreq = twl4030_read_reg_cache(codec, TWL4030_REG_APLL_CTL) - & TWL4030_APLL_INFREQ; - - if (infreq != TWL4030_APLL_INFREQ_26000KHZ) { - printk(KERN_ERR "TWL4030 voice startup: " - "MCLK is not 26MHz, call set_sysclk() on init\n"); + if (twl4030->sysclk != 26000) { + dev_err(codec->dev, "The board is configured for %u Hz, while" + "the Voice interface needs 26MHz APLL mclk\n", + twl4030->sysclk * 1000); return -EINVAL; } @@ -1958,22 +1950,19 @@ static int twl4030_voice_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; - u8 apll_ctrl; + struct twl4030_priv *twl4030 = codec->private_data; - apll_ctrl = twl4030_read_reg_cache(codec, TWL4030_REG_APLL_CTL); - apll_ctrl &= ~TWL4030_APLL_INFREQ; - switch (freq) { - case 26000000: - apll_ctrl |= TWL4030_APLL_INFREQ_26000KHZ; - break; - default: - printk(KERN_ERR "TWL4030 voice set sysclk: unknown rate %d\n", - freq); + if (freq != 26000000) { + dev_err(codec->dev, "Unsupported APLL mclk: %u, the Voice" + "interface needs 26MHz APLL mclk\n", freq); + return -EINVAL; + } + if ((freq / 1000) != twl4030->sysclk) { + dev_err(codec->dev, + "Mismatch in APLL mclk: %u (configured: %u)\n", + freq, twl4030->sysclk * 1000); return -EINVAL; } - - twl4030_write(codec, TWL4030_REG_APLL_CTL, apll_ctrl); - return 0; } @@ -2131,17 +2120,15 @@ static int twl4030_soc_probe(struct platform_device *pdev) if (setup) { unsigned char hs_pop; - if (setup->sysclk) - twl4030->sysclk = setup->sysclk; - else - twl4030->sysclk = 26000; + if (setup->sysclk != twl4030->sysclk) + dev_warn(&pdev->dev, + "Mismatch in APLL mclk: %u (configured: %u)\n", + setup->sysclk, twl4030->sysclk); hs_pop = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET); hs_pop &= ~TWL4030_RAMP_DELAY; hs_pop |= (setup->ramp_delay_value << 2); twl4030_write_reg_cache(codec, TWL4030_REG_HS_POPN_SET, hs_pop); - } else { - twl4030->sysclk = 26000; } /* register pcms */ @@ -2179,10 +2166,8 @@ static int __devinit twl4030_codec_probe(struct platform_device *pdev) struct twl4030_priv *twl4030; int ret; - if (!pdata || !(pdata->audio_mclk == 19200000 || - pdata->audio_mclk == 26000000 || - pdata->audio_mclk == 38400000)) { - dev_err(&pdev->dev, "Invalid platform_data\n"); + if (!pdata) { + dev_err(&pdev->dev, "platform_data is missing\n"); return -EINVAL; } @@ -2221,6 +2206,7 @@ static int __devinit twl4030_codec_probe(struct platform_device *pdev) twl4030_codec = codec; /* Set the defaults, and power up the codec */ + twl4030->sysclk = twl4030_codec_get_mclk() / 1000; twl4030_init_chip(codec); codec->bias_level = SND_SOC_BIAS_OFF; twl4030_set_bias_level(codec, SND_SOC_BIAS_STANDBY); -- cgit v1.2.3 From a68cc8daebdd8ba7fe457ab4b2a0ccdf3cedc9f8 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Mon, 9 Nov 2009 09:40:09 -0700 Subject: ASoC: mpc5200: remove duplicate identical IRQ handler The TX and RX irq handlers are identical. Merge them Signed-off-by: Grant Likely Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/fsl/mpc5200_dma.c | 33 +++------------------------------ 1 file changed, 3 insertions(+), 30 deletions(-) (limited to 'sound') diff --git a/sound/soc/fsl/mpc5200_dma.c b/sound/soc/fsl/mpc5200_dma.c index 9c88e15ce69..30ed568afb2 100644 --- a/sound/soc/fsl/mpc5200_dma.c +++ b/sound/soc/fsl/mpc5200_dma.c @@ -66,32 +66,7 @@ static void psc_dma_bcom_enqueue_next_buffer(struct psc_dma_stream *s) } /* Bestcomm DMA irq handler */ -static irqreturn_t psc_dma_bcom_irq_tx(int irq, void *_psc_dma_stream) -{ - struct psc_dma_stream *s = _psc_dma_stream; - - spin_lock(&s->psc_dma->lock); - /* For each finished period, dequeue the completed period buffer - * and enqueue a new one in it's place. */ - while (bcom_buffer_done(s->bcom_task)) { - bcom_retrieve_buffer(s->bcom_task, NULL, NULL); - - s->period_current = (s->period_current+1) % s->runtime->periods; - s->period_count++; - - psc_dma_bcom_enqueue_next_buffer(s); - } - spin_unlock(&s->psc_dma->lock); - - /* If the stream is active, then also inform the PCM middle layer - * of the period finished event. */ - if (s->active) - snd_pcm_period_elapsed(s->stream); - - return IRQ_HANDLED; -} - -static irqreturn_t psc_dma_bcom_irq_rx(int irq, void *_psc_dma_stream) +static irqreturn_t psc_dma_bcom_irq(int irq, void *_psc_dma_stream) { struct psc_dma_stream *s = _psc_dma_stream; @@ -486,11 +461,9 @@ int mpc5200_audio_dma_create(struct of_device *op) rc = request_irq(psc_dma->irq, &psc_dma_status_irq, IRQF_SHARED, "psc-dma-status", psc_dma); - rc |= request_irq(psc_dma->capture.irq, - &psc_dma_bcom_irq_rx, IRQF_SHARED, + rc |= request_irq(psc_dma->capture.irq, &psc_dma_bcom_irq, IRQF_SHARED, "psc-dma-capture", &psc_dma->capture); - rc |= request_irq(psc_dma->playback.irq, - &psc_dma_bcom_irq_tx, IRQF_SHARED, + rc |= request_irq(psc_dma->playback.irq, &psc_dma_bcom_irq, IRQF_SHARED, "psc-dma-playback", &psc_dma->playback); if (rc) { ret = -ENODEV; -- cgit v1.2.3 From 8579d2d7779d7ff41ea2a0183015e0e5038f1043 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Wed, 21 Oct 2009 09:09:38 +0200 Subject: sound: rawmidi: fix double init when opening MIDI device with O_APPEND Commit 9a1b64caac82aa02cb74587ffc798e6f42c6170a in 2.6.30 moved the substream initialization code to where it would be executed every time the substream is opened. This had the consequence that any further opening would drop and leak the data in the existing buffer, and that the device driver's open callback would be called multiple times, unexpectedly. Signed-off-by: Clemens Ladisch Cc: Signed-off-by: Takashi Iwai --- sound/core/rawmidi.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) (limited to 'sound') diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index c0adc14c91f..3071e6f5801 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -266,17 +266,19 @@ static int open_substream(struct snd_rawmidi *rmidi, { int err; - err = snd_rawmidi_runtime_create(substream); - if (err < 0) - return err; - err = substream->ops->open(substream); - if (err < 0) - return err; - substream->opened = 1; - if (substream->use_count++ == 0) + if (substream->use_count == 0) { + err = snd_rawmidi_runtime_create(substream); + if (err < 0) + return err; + err = substream->ops->open(substream); + if (err < 0) + return err; + substream->opened = 1; substream->active_sensing = 0; - if (mode & SNDRV_RAWMIDI_LFLG_APPEND) - substream->append = 1; + if (mode & SNDRV_RAWMIDI_LFLG_APPEND) + substream->append = 1; + } + substream->use_count++; rmidi->streams[substream->stream].substream_opened++; return 0; } -- cgit v1.2.3 From 16fb109644b5644e42ececeff644514de6f4bd03 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Wed, 21 Oct 2009 09:10:16 +0200 Subject: sound: rawmidi: fix checking of O_APPEND when opening MIDI device Commit 9a1b64caac82aa02cb74587ffc798e6f42c6170a in 2.6.30 dropped the check that a substream must already have been opened with O_APPEND to be able to open it a second time. This would make it possible for a substream to be switched to append mode, which would mean that non-atomic writes would fail unexpectedly. Signed-off-by: Clemens Ladisch Cc: Signed-off-by: Takashi Iwai --- sound/core/rawmidi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 3071e6f5801..091405385e1 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -248,7 +248,8 @@ static int assign_substream(struct snd_rawmidi *rmidi, int subdevice, list_for_each_entry(substream, &s->substreams, list) { if (substream->opened) { if (stream == SNDRV_RAWMIDI_STREAM_INPUT || - !(mode & SNDRV_RAWMIDI_LFLG_APPEND)) + !(mode & SNDRV_RAWMIDI_LFLG_APPEND) || + !substream->append) continue; } if (subdevice < 0 || subdevice == substream->number) { -- cgit v1.2.3 From b7fe750fcceda4fa6bef399b0e2812562728ea82 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Wed, 21 Oct 2009 09:11:43 +0200 Subject: sound: rawmidi: fix MIDI device O_APPEND error handling Commit 9a1b64caac82aa02cb74587ffc798e6f42c6170a in 2.6.30 broke the error handling code in rawmidi_open_priv(). If only the output substream of a RawMIDI device has been opened and if this device is then opened with O_RDWR | O_APPEND and if the initialization of the input substream fails (either because of low memory or because the device driver's open callback fails), then the runtime structure of the already open output substream will be freed and all following writes through the first handle will cause snd_rawmidi_write() to use the NULL runtime pointer. Signed-off-by: Clemens Ladisch Cc: Signed-off-by: Takashi Iwai --- sound/core/rawmidi.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) (limited to 'sound') diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 091405385e1..70d6f25ba52 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -272,8 +272,10 @@ static int open_substream(struct snd_rawmidi *rmidi, if (err < 0) return err; err = substream->ops->open(substream); - if (err < 0) + if (err < 0) { + snd_rawmidi_runtime_free(substream); return err; + } substream->opened = 1; substream->active_sensing = 0; if (mode & SNDRV_RAWMIDI_LFLG_APPEND) @@ -300,27 +302,27 @@ static int rawmidi_open_priv(struct snd_rawmidi *rmidi, int subdevice, int mode, SNDRV_RAWMIDI_STREAM_INPUT, mode, &sinput); if (err < 0) - goto __error; + return err; } if (mode & SNDRV_RAWMIDI_LFLG_OUTPUT) { err = assign_substream(rmidi, subdevice, SNDRV_RAWMIDI_STREAM_OUTPUT, mode, &soutput); if (err < 0) - goto __error; + return err; } if (sinput) { err = open_substream(rmidi, sinput, mode); if (err < 0) - goto __error; + return err; } if (soutput) { err = open_substream(rmidi, soutput, mode); if (err < 0) { if (sinput) close_substream(rmidi, sinput, 0); - goto __error; + return err; } } @@ -328,13 +330,6 @@ static int rawmidi_open_priv(struct snd_rawmidi *rmidi, int subdevice, int mode, rfile->input = sinput; rfile->output = soutput; return 0; - - __error: - if (sinput && sinput->runtime) - snd_rawmidi_runtime_free(sinput); - if (soutput && soutput->runtime) - snd_rawmidi_runtime_free(soutput); - return err; } /* called from sound/core/seq/seq_midi.c */ -- cgit v1.2.3 From 91d12c485b8949cce6c13ab641147c5bc86ce8b9 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Wed, 21 Oct 2009 09:12:26 +0200 Subject: sound: rawmidi: fix opened substreams count The substream_opened field is to count the number of opened substreams, not the number of times that any substreams have been opened. Furthermore, all substreams being opened does not imply that the next open would fail, due to the possibility of O_APPEND. With this wrong check, opening a substream multiple times would succeed only if the device had more unopened substreams. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/core/rawmidi.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 4e26563431c..818b1299ed9 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -242,8 +242,6 @@ static int assign_substream(struct snd_rawmidi *rmidi, int subdevice, return -ENXIO; if (subdevice >= 0 && subdevice >= s->substream_count) return -ENODEV; - if (s->substream_opened >= s->substream_count) - return -EAGAIN; list_for_each_entry(substream, &s->substreams, list) { if (substream->opened) { @@ -280,9 +278,9 @@ static int open_substream(struct snd_rawmidi *rmidi, substream->active_sensing = 0; if (mode & SNDRV_RAWMIDI_LFLG_APPEND) substream->append = 1; + rmidi->streams[substream->stream].substream_opened++; } substream->use_count++; - rmidi->streams[substream->stream].substream_opened++; return 0; } @@ -466,7 +464,6 @@ static void close_substream(struct snd_rawmidi *rmidi, struct snd_rawmidi_substream *substream, int cleanup) { - rmidi->streams[substream->stream].substream_opened--; if (--substream->use_count) return; @@ -491,6 +488,7 @@ static void close_substream(struct snd_rawmidi *rmidi, snd_rawmidi_runtime_free(substream); substream->opened = 0; substream->append = 0; + rmidi->streams[substream->stream].substream_opened--; } static void rawmidi_release_priv(struct snd_rawmidi_file *rfile) -- cgit v1.2.3 From e7373b702f6eab35f315e016a4159860a7a4d686 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Tue, 10 Nov 2009 10:13:30 +0100 Subject: sound: pcm: record a substream's owner process Record the pid of the task that opened a PCM substream. For sound cards with hardware mixing, this allows determining which process is associated with a specific substream's volume control. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/core/pcm.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sound') diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 8e2c7833614..6884ae031f6 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -435,6 +435,7 @@ static void snd_pcm_substream_proc_status_read(struct snd_info_entry *entry, return; } snd_iprintf(buffer, "state: %s\n", snd_pcm_state_name(status.state)); + snd_iprintf(buffer, "owner_pid : %d\n", pid_vnr(substream->pid)); snd_iprintf(buffer, "trigger_time: %ld.%09ld\n", status.trigger_tstamp.tv_sec, status.trigger_tstamp.tv_nsec); snd_iprintf(buffer, "tstamp : %ld.%09ld\n", @@ -900,6 +901,7 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, substream->private_data = pcm->private_data; substream->ref_count = 1; substream->f_flags = file->f_flags; + substream->pid = get_pid(task_pid(current)); pstr->substream_opened++; *rsubstream = substream; return 0; @@ -921,6 +923,8 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream) kfree(runtime->hw_constraints.rules); kfree(runtime); substream->runtime = NULL; + put_pid(substream->pid); + substream->pid = NULL; substream->pstr->substream_opened--; } -- cgit v1.2.3 From 7584af10cf46e0f4aa1696f1be79fa0f19a945ba Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Tue, 10 Nov 2009 10:14:04 +0100 Subject: sound: rawmidi: record a substream's owner process Record the pid of the task that opened a RawMIDI substream. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/core/rawmidi.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'sound') diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 818b1299ed9..2f766123b15 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -278,6 +278,7 @@ static int open_substream(struct snd_rawmidi *rmidi, substream->active_sensing = 0; if (mode & SNDRV_RAWMIDI_LFLG_APPEND) substream->append = 1; + substream->pid = get_pid(task_pid(current)); rmidi->streams[substream->stream].substream_opened++; } substream->use_count++; @@ -488,6 +489,8 @@ static void close_substream(struct snd_rawmidi *rmidi, snd_rawmidi_runtime_free(substream); substream->opened = 0; substream->append = 0; + put_pid(substream->pid); + substream->pid = NULL; rmidi->streams[substream->stream].substream_opened--; } @@ -1336,6 +1339,9 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry, substream->number, (unsigned long) substream->bytes); if (substream->opened) { + snd_iprintf(buffer, + " Owner PID : %d\n", + pid_vnr(substream->pid)); runtime = substream->runtime; snd_iprintf(buffer, " Mode : %s\n" @@ -1357,6 +1363,9 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry, substream->number, (unsigned long) substream->bytes); if (substream->opened) { + snd_iprintf(buffer, + " Owner PID : %d\n", + pid_vnr(substream->pid)); runtime = substream->runtime; snd_iprintf(buffer, " Buffer size : %lu\n" -- cgit v1.2.3 From 7aae816dae150caad8880357e42303935c0179a8 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 10 Nov 2009 16:08:04 +0000 Subject: ASoC: Add bit clock rate calculator utility functions Many devices need to calculate the bit clock rate desired to work out the clock configuration required for the device. Provide utility functions to do this using both hw_params structures and raw numbers. Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/Makefile | 2 +- sound/soc/soc-utils.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 sound/soc/soc-utils.c (limited to 'sound') diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 0c5eac01bf2..1470141d416 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -1,4 +1,4 @@ -snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o +snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o soc-utils.o obj-$(CONFIG_SND_SOC) += snd-soc-core.o obj-$(CONFIG_SND_SOC) += codecs/ diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c new file mode 100644 index 00000000000..b16aaaeb0aa --- /dev/null +++ b/sound/soc/soc-utils.c @@ -0,0 +1,68 @@ +/* + * soc-util.c -- ALSA SoC Audio Layer utility functions + * + * Copyright 2009 Wolfson Microelectronics PLC. + * + * Author: Mark Brown + * Liam Girdwood + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include + +int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots) +{ + return sample_size * channels * tdm_slots; +} +EXPORT_SYMBOL_GPL(snd_soc_calc_frame_size); + +int snd_soc_params_to_frame_size(struct snd_pcm_hw_params *params) +{ + int sample_size; + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + case SNDRV_PCM_FORMAT_S16_BE: + sample_size = 16; + break; + case SNDRV_PCM_FORMAT_S20_3LE: + case SNDRV_PCM_FORMAT_S20_3BE: + sample_size = 20; + break; + case SNDRV_PCM_FORMAT_S24_LE: + case SNDRV_PCM_FORMAT_S24_BE: + sample_size = 24; + break; + case SNDRV_PCM_FORMAT_S32_LE: + case SNDRV_PCM_FORMAT_S32_BE: + sample_size = 32; + break; + default: + return -ENOTSUPP; + } + + return snd_soc_calc_frame_size(sample_size, params_channels(params), + 1); +} +EXPORT_SYMBOL_GPL(snd_soc_params_to_frame_size); + +int snd_soc_params_to_bclk(struct snd_pcm_hw_params *params) +{ + int ret; + + ret = snd_soc_params_to_frame_size(params); + + if (ret > 0) + return ret * params_rate(params); + else + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_params_to_bclk); -- cgit v1.2.3 From ba2b87f5a93659a28cc4fb812ccd7b4146ac3aa9 Mon Sep 17 00:00:00 2001 From: Jassi Brar Date: Wed, 11 Nov 2009 14:02:18 +0900 Subject: ASoC: Fixed arguments passed to SMDK64xx set_pll Corrected the order of 'source' and 'pll_id' arguments. Signed-off-by: Jassi Brar Signed-off-by: Mark Brown --- sound/soc/s3c24xx/smdk64xx_wm8580.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/s3c24xx/smdk64xx_wm8580.c b/sound/soc/s3c24xx/smdk64xx_wm8580.c index cb8a9161b64..216dd1e8e37 100644 --- a/sound/soc/s3c24xx/smdk64xx_wm8580.c +++ b/sound/soc/s3c24xx/smdk64xx_wm8580.c @@ -115,7 +115,7 @@ static int smdk64xx_hw_params(struct snd_pcm_substream *substream, if (ret < 0) return ret; - ret = snd_soc_dai_set_pll(codec_dai, 0, WM8580_PLLA, + ret = snd_soc_dai_set_pll(codec_dai, WM8580_PLLA, 0, SMDK64XX_WM8580_FREQ, pll_out); if (ret < 0) return ret; -- cgit v1.2.3 From f773205300fa4a5a405f8ed6e3bb97e46c6eefb4 Mon Sep 17 00:00:00 2001 From: Barry Song <21cnbao@gmail.com> Date: Thu, 12 Nov 2009 12:01:47 +0800 Subject: ASoC: move setting ac97 platformdata earlier than ac97 read/write While probing, AC97 codec drivers and soc-core generically execute the following sequence: snd_soc_new_ac97_codec -> snd_soc_new_pcms -> reset ac-link/read AC97 ID to detect ->... -> set platform_data to ac97 by soc-core commit 474828a40f6ddab6e2a3475a19c5c84aa3ec7d60 adds platform_data to snd_ac97 instance. But ac97 platform data hasn't given to snd_ac97 before actual ac97 operations. Then while ac97_read access platform_data of snd_ac97 for detecting, NULL pointer oops will fire. That means old platform_data patch doesn't work in real-life cases. This patch moves the operation of setting ac97 platform_data earlier than ac97 reading/writing operations. Then it makes platform_data of AC97 become practically useful. Signed-off-by: Barry Song <21cnbao@gmail.com> Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index e2b6d75f16e..ef8f28284cb 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1083,11 +1083,8 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card) continue; } } - if (card->dai_link[i].codec_dai->ac97_control) { + if (card->dai_link[i].codec_dai->ac97_control) ac97 = 1; - snd_ac97_dev_add_pdata(codec->ac97, - card->dai_link[i].cpu_dai->ac97_pdata); - } } snprintf(codec->card->shortname, sizeof(codec->card->shortname), @@ -1510,6 +1507,10 @@ int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid) mutex_unlock(&codec->mutex); return ret; } + if (card->dai_link[i].codec_dai->ac97_control) { + snd_ac97_dev_add_pdata(codec->ac97, + card->dai_link[i].cpu_dai->ac97_pdata); + } } mutex_unlock(&codec->mutex); -- cgit v1.2.3 From c871a05315d1a76034ea06feeda92081e1d608bf Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Thu, 12 Nov 2009 17:14:04 +0900 Subject: ASoC: Add jack_status_check callback function for GPIO jacks The jack_status_check callback function is the interface to check the status of the jack. Some target provides the method to distinguish what is the jack inserted - headphone jack, microphone jack, tvout jack, etc, so we can implement it using the jack_status_check function. Signed-off-by: Joonyoung Shim Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/soc-jack.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound') diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c index 12124149601..3c07a94c2e3 100644 --- a/sound/soc/soc-jack.c +++ b/sound/soc/soc-jack.c @@ -163,6 +163,9 @@ static void snd_soc_jack_gpio_detect(struct snd_soc_jack_gpio *gpio) else report = 0; + if (gpio->jack_status_check) + report = gpio->jack_status_check(); + snd_soc_jack_report(jack, report, gpio->report); } -- cgit v1.2.3 From 0d26ce3403b3841fa2656df08a819fc7eaebaa17 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Thu, 12 Nov 2009 17:43:11 +0100 Subject: sound: OSS: fix error return in dma_ioctl() The returned error should stay negative Signed-off-by: Roel Kluin Signed-off-by: Takashi Iwai --- sound/oss/audio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/oss/audio.c b/sound/oss/audio.c index b69c05b7ea7..7df48a25c4e 100644 --- a/sound/oss/audio.c +++ b/sound/oss/audio.c @@ -838,7 +838,7 @@ static int dma_ioctl(int dev, unsigned int cmd, void __user *arg) if ((err = audio_devs[dev]->d->prepare_for_input(dev, dmap_in->fragment_size, dmap_in->nbufs)) < 0) { spin_unlock_irqrestore(&dmap_in->lock,flags); - return -err; + return err; } dmap_in->dma_mode = DMODE_INPUT; audio_devs[dev]->enable_bits |= PCM_ENABLE_INPUT; -- cgit v1.2.3 From 0a3f5e35aae43b20fef09fd800cf52cc9a2d61a8 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 12 Nov 2009 23:15:08 +0000 Subject: ASoC: Remove redundant snd_soc_dapm_new_widgets() calls The DAPM widgets are now insntantiated by the core when creating the card so there is no need for the individual CODEC drivers to do so. Signed-off-by: Mark Brown --- sound/soc/codecs/ad1836.c | 1 - sound/soc/codecs/ad1938.c | 1 - sound/soc/codecs/ak4535.c | 1 - sound/soc/codecs/ak4671.c | 1 - sound/soc/codecs/cx20442.c | 1 - sound/soc/codecs/ssm2602.c | 1 - sound/soc/codecs/tlv320aic23.c | 1 - sound/soc/codecs/tlv320aic3x.c | 1 - sound/soc/codecs/tlv320dac33.c | 1 - sound/soc/codecs/twl4030.c | 1 - sound/soc/codecs/uda1380.c | 1 - sound/soc/codecs/wm8350.c | 2 +- sound/soc/codecs/wm8400.c | 1 - sound/soc/codecs/wm8510.c | 1 - sound/soc/codecs/wm8523.c | 1 - sound/soc/codecs/wm8580.c | 1 - sound/soc/codecs/wm8711.c | 1 - sound/soc/codecs/wm8728.c | 2 -- sound/soc/codecs/wm8731.c | 1 - sound/soc/codecs/wm8750.c | 1 - sound/soc/codecs/wm8753.c | 1 - sound/soc/codecs/wm8900.c | 2 -- sound/soc/codecs/wm8903.c | 2 -- sound/soc/codecs/wm8940.c | 1 - sound/soc/codecs/wm8960.c | 1 - sound/soc/codecs/wm8961.c | 1 - sound/soc/codecs/wm8971.c | 2 -- sound/soc/codecs/wm8974.c | 1 - sound/soc/codecs/wm8988.c | 1 - sound/soc/codecs/wm8990.c | 1 - sound/soc/codecs/wm8993.c | 2 -- sound/soc/codecs/wm9081.c | 1 - sound/soc/codecs/wm9705.c | 1 - sound/soc/codecs/wm9712.c | 1 - sound/soc/codecs/wm9713.c | 1 - 35 files changed, 1 insertion(+), 40 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c index b4be96decf3..2c18e3d1b71 100644 --- a/sound/soc/codecs/ad1836.c +++ b/sound/soc/codecs/ad1836.c @@ -385,7 +385,6 @@ static int ad1836_probe(struct platform_device *pdev) snd_soc_dapm_new_controls(codec, ad1836_dapm_widgets, ARRAY_SIZE(ad1836_dapm_widgets)); snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths)); - snd_soc_dapm_new_widgets(codec); pcm_err: return ret; diff --git a/sound/soc/codecs/ad1938.c b/sound/soc/codecs/ad1938.c index 3b2222a0c80..5d489186c05 100644 --- a/sound/soc/codecs/ad1938.c +++ b/sound/soc/codecs/ad1938.c @@ -592,7 +592,6 @@ static int ad1938_probe(struct platform_device *pdev) snd_soc_dapm_new_controls(codec, ad1938_dapm_widgets, ARRAY_SIZE(ad1938_dapm_widgets)); snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths)); - snd_soc_dapm_new_widgets(codec); ad1938_set_bias_level(codec, SND_SOC_BIAS_STANDBY); diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c index 57a6846a9a1..ff966567e2b 100644 --- a/sound/soc/codecs/ak4535.c +++ b/sound/soc/codecs/ak4535.c @@ -294,7 +294,6 @@ static int ak4535_add_widgets(struct snd_soc_codec *codec) snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); - snd_soc_dapm_new_widgets(codec); return 0; } diff --git a/sound/soc/codecs/ak4671.c b/sound/soc/codecs/ak4671.c index 364832ccd74..82fca284d00 100644 --- a/sound/soc/codecs/ak4671.c +++ b/sound/soc/codecs/ak4671.c @@ -441,7 +441,6 @@ static int ak4671_add_widgets(struct snd_soc_codec *codec) snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); - snd_soc_dapm_new_widgets(codec); return 0; } diff --git a/sound/soc/codecs/cx20442.c b/sound/soc/codecs/cx20442.c index dda751c885c..e000cdfec1e 100644 --- a/sound/soc/codecs/cx20442.c +++ b/sound/soc/codecs/cx20442.c @@ -93,7 +93,6 @@ static int cx20442_add_widgets(struct snd_soc_codec *codec) snd_soc_dapm_add_routes(codec, cx20442_audio_map, ARRAY_SIZE(cx20442_audio_map)); - snd_soc_dapm_new_widgets(codec); return 0; } diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c index b3130339d29..d2ff1cde688 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c @@ -210,7 +210,6 @@ static int ssm2602_add_widgets(struct snd_soc_codec *codec) snd_soc_dapm_add_routes(codec, audio_conn, ARRAY_SIZE(audio_conn)); - snd_soc_dapm_new_widgets(codec); return 0; } diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c index ee8cb2c08b8..1709e3f614a 100644 --- a/sound/soc/codecs/tlv320aic23.c +++ b/sound/soc/codecs/tlv320aic23.c @@ -395,7 +395,6 @@ static int tlv320aic23_add_widgets(struct snd_soc_codec *codec) /* set up audio path interconnects */ snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); - snd_soc_dapm_new_widgets(codec); return 0; } diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 03cad250f58..2b4dc2b0b01 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -753,7 +753,6 @@ static int aic3x_add_widgets(struct snd_soc_codec *codec) /* set up audio path interconnects */ snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); - snd_soc_dapm_new_widgets(codec); return 0; } diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index bff476d65d0..2a013e46ae1 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c @@ -462,7 +462,6 @@ static int dac33_add_widgets(struct snd_soc_codec *codec) /* set up audio path interconnects */ snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); - snd_soc_dapm_new_widgets(codec); return 0; } diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 510b8b226f9..5f1681f6ca7 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -1493,7 +1493,6 @@ static int twl4030_add_widgets(struct snd_soc_codec *codec) snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); - snd_soc_dapm_new_widgets(codec); return 0; } diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c index a42e47d9463..a2763c2e734 100644 --- a/sound/soc/codecs/uda1380.c +++ b/sound/soc/codecs/uda1380.c @@ -378,7 +378,6 @@ static int uda1380_add_widgets(struct snd_soc_codec *codec) snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); - snd_soc_dapm_new_widgets(codec); return 0; } diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index 2e35a354b16..f82125d9e85 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c @@ -800,7 +800,7 @@ static int wm8350_add_widgets(struct snd_soc_codec *codec) return ret; } - return snd_soc_dapm_new_widgets(codec); + return 0; } static int wm8350_set_dai_sysclk(struct snd_soc_dai *codec_dai, diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c index 584af68af22..b432f4d4a32 100644 --- a/sound/soc/codecs/wm8400.c +++ b/sound/soc/codecs/wm8400.c @@ -915,7 +915,6 @@ static int wm8400_add_widgets(struct snd_soc_codec *codec) snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); - snd_soc_dapm_new_widgets(codec); return 0; } diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c index e3c21ebcc08..265e68c75df 100644 --- a/sound/soc/codecs/wm8510.c +++ b/sound/soc/codecs/wm8510.c @@ -219,7 +219,6 @@ static int wm8510_add_widgets(struct snd_soc_codec *codec) snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); - snd_soc_dapm_new_widgets(codec); return 0; } diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c index 2e2b01d6c82..d3a61d7ea0c 100644 --- a/sound/soc/codecs/wm8523.c +++ b/sound/soc/codecs/wm8523.c @@ -117,7 +117,6 @@ static int wm8523_add_widgets(struct snd_soc_codec *codec) snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); - snd_soc_dapm_new_widgets(codec); return 0; } diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index dde50d11818..d077df6f5e7 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c @@ -315,7 +315,6 @@ static int wm8580_add_widgets(struct snd_soc_codec *codec) snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); - snd_soc_dapm_new_widgets(codec); return 0; } diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c index 70e0675b5d4..24a35603bcf 100644 --- a/sound/soc/codecs/wm8711.c +++ b/sound/soc/codecs/wm8711.c @@ -99,7 +99,6 @@ static int wm8711_add_widgets(struct snd_soc_codec *codec) snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); - snd_soc_dapm_new_widgets(codec); return 0; } diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c index 1252a8a486a..3fb653ba363 100644 --- a/sound/soc/codecs/wm8728.c +++ b/sound/soc/codecs/wm8728.c @@ -74,8 +74,6 @@ static int wm8728_add_widgets(struct snd_soc_codec *codec) snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); - snd_soc_dapm_new_widgets(codec); - return 0; } diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index e3675e7a981..3a497810f93 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -159,7 +159,6 @@ static int wm8731_add_widgets(struct snd_soc_codec *codec) snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); - snd_soc_dapm_new_widgets(codec); return 0; } diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index 50a3d659058..475c67ac781 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c @@ -403,7 +403,6 @@ static int wm8750_add_widgets(struct snd_soc_codec *codec) snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); - snd_soc_dapm_new_widgets(codec); return 0; } diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index c652bc04cc8..d6850dacda2 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c @@ -673,7 +673,6 @@ static int wm8753_add_widgets(struct snd_soc_codec *codec) snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); - snd_soc_dapm_new_widgets(codec); return 0; } diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index 85f67dbe211..c9438dd62df 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c @@ -618,8 +618,6 @@ static int wm8900_add_widgets(struct snd_soc_codec *codec) snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); - snd_soc_dapm_new_widgets(codec); - return 0; } diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index bfeff4ee5de..b8cae175864 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -919,8 +919,6 @@ static int wm8903_add_widgets(struct snd_soc_codec *codec) snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); - snd_soc_dapm_new_widgets(codec); - return 0; } diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c index fc80aa6c913..3d850b97037 100644 --- a/sound/soc/codecs/wm8940.c +++ b/sound/soc/codecs/wm8940.c @@ -298,7 +298,6 @@ static int wm8940_add_widgets(struct snd_soc_codec *codec) ret = snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); if (ret) goto error_ret; - ret = snd_soc_dapm_new_widgets(codec); error_ret: return ret; diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index 40390afa75f..d07bcc1e1c6 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -307,7 +307,6 @@ static int wm8960_add_widgets(struct snd_soc_codec *codec) snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths)); - snd_soc_dapm_new_widgets(codec); return 0; } diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c index 07e389574db..a8007d58813 100644 --- a/sound/soc/codecs/wm8961.c +++ b/sound/soc/codecs/wm8961.c @@ -986,7 +986,6 @@ static int wm8961_probe(struct platform_device *pdev) snd_soc_dapm_new_controls(codec, wm8961_dapm_widgets, ARRAY_SIZE(wm8961_dapm_widgets)); snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths)); - snd_soc_dapm_new_widgets(codec); return ret; diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c index 56a66e89ab9..d9540d55fc8 100644 --- a/sound/soc/codecs/wm8971.c +++ b/sound/soc/codecs/wm8971.c @@ -338,8 +338,6 @@ static int wm8971_add_widgets(struct snd_soc_codec *codec) snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); - snd_soc_dapm_new_widgets(codec); - return 0; } diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c index c245f0ee0ec..81c57b5c591 100644 --- a/sound/soc/codecs/wm8974.c +++ b/sound/soc/codecs/wm8974.c @@ -276,7 +276,6 @@ static int wm8974_add_widgets(struct snd_soc_codec *codec) snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); - snd_soc_dapm_new_widgets(codec); return 0; } diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c index bee292e37d1..2862e4dced2 100644 --- a/sound/soc/codecs/wm8988.c +++ b/sound/soc/codecs/wm8988.c @@ -790,7 +790,6 @@ static int wm8988_probe(struct platform_device *pdev) snd_soc_dapm_new_controls(codec, wm8988_dapm_widgets, ARRAY_SIZE(wm8988_dapm_widgets)); snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); - snd_soc_dapm_new_widgets(codec); return ret; diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index e43cb2c8b91..341481e0e83 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c @@ -920,7 +920,6 @@ static int wm8990_add_widgets(struct snd_soc_codec *codec) /* set up the WM8990 audio map */ snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); - snd_soc_dapm_new_widgets(codec); return 0; } diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c index 0d4d2be92b6..5e32f2ed5fc 100644 --- a/sound/soc/codecs/wm8993.c +++ b/sound/soc/codecs/wm8993.c @@ -1464,8 +1464,6 @@ static int wm8993_probe(struct platform_device *pdev) wm_hubs_add_analogue_routes(codec, wm8993->pdata.lineout1_diff, wm8993->pdata.lineout2_diff); - snd_soc_dapm_new_widgets(codec); - return ret; err: diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c index 3f1f8442131..c468497314b 100644 --- a/sound/soc/codecs/wm9081.c +++ b/sound/soc/codecs/wm9081.c @@ -1262,7 +1262,6 @@ static int wm9081_probe(struct platform_device *pdev) snd_soc_dapm_new_controls(codec, wm9081_dapm_widgets, ARRAY_SIZE(wm9081_dapm_widgets)); snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths)); - snd_soc_dapm_new_widgets(codec); return ret; diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c index 0e817b8705c..dfffc6c778c 100644 --- a/sound/soc/codecs/wm9705.c +++ b/sound/soc/codecs/wm9705.c @@ -205,7 +205,6 @@ static int wm9705_add_widgets(struct snd_soc_codec *codec) snd_soc_dapm_new_controls(codec, wm9705_dapm_widgets, ARRAY_SIZE(wm9705_dapm_widgets)); snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); - snd_soc_dapm_new_widgets(codec); return 0; } diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index 155cacf124e..2a087227300 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -436,7 +436,6 @@ static int wm9712_add_widgets(struct snd_soc_codec *codec) snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); - snd_soc_dapm_new_widgets(codec); return 0; } diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index 5f81ecd20a8..00bac315fb3 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -625,7 +625,6 @@ static int wm9713_add_widgets(struct snd_soc_codec *codec) snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); - snd_soc_dapm_new_widgets(codec); return 0; } -- cgit v1.2.3 From 401de8184a4d94688962b9258fe10ab309ffda9c Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Fri, 13 Nov 2009 16:02:56 +0900 Subject: ALSA: ice1712: Use bitrev8 Signed-off-by: Akinobu Mita Signed-off-by: Takashi Iwai --- sound/i2c/cs8427.c | 15 ++------------- sound/pci/Kconfig | 1 + 2 files changed, 3 insertions(+), 13 deletions(-) (limited to 'sound') diff --git a/sound/i2c/cs8427.c b/sound/i2c/cs8427.c index 020a5d51247..04ae8704cdc 100644 --- a/sound/i2c/cs8427.c +++ b/sound/i2c/cs8427.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -55,18 +56,6 @@ struct cs8427 { struct cs8427_stream capture; }; -static unsigned char swapbits(unsigned char val) -{ - int bit; - unsigned char res = 0; - for (bit = 0; bit < 8; bit++) { - res <<= 1; - res |= val & 1; - val >>= 1; - } - return res; -} - int snd_cs8427_reg_write(struct snd_i2c_device *device, unsigned char reg, unsigned char val) { @@ -149,7 +138,7 @@ static int snd_cs8427_send_corudata(struct snd_i2c_device *device, } data[0] = CS8427_REG_AUTOINC | CS8427_REG_CORU_DATABUF; for (idx = 0; idx < count; idx++) - data[idx + 1] = swapbits(ndata[idx]); + data[idx + 1] = bitrev8(ndata[idx]); if (snd_i2c_sendbytes(device, data, count + 1) != count + 1) return -EIO; return 1; diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 75c602b5b13..351654cf7b0 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -570,6 +570,7 @@ config SND_ICE1712 tristate "ICEnsemble ICE1712 (Envy24)" select SND_MPU401_UART select SND_AC97_CODEC + select BITREVERSE help Say Y here to include support for soundcards based on the ICE1712 (Envy24) chip. -- cgit v1.2.3 From 50d40f187f9182ee8caa1b83f80a0e11e2226baa Mon Sep 17 00:00:00 2001 From: Aleksey Kunitskiy Date: Sat, 14 Nov 2009 15:18:54 +0200 Subject: ALSA: ice1724 - Patch for suspend/resume for ESI Juli@ Add proper suspend/resume code for Juli@ cards. Based on ice1724 suspend/resume work of Igor Chernyshev. Fixes bug https://bugtrack.alsa-project.org/alsa-bug/view.php?id=4413 Tested on linux-2.6.31.6 Signed-off-by: Aleksey Kunitskiy Signed-off-by: Takashi Iwai --- sound/pci/ice1712/juli.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'sound') diff --git a/sound/pci/ice1712/juli.c b/sound/pci/ice1712/juli.c index fd948bfd9ae..f5020ad99a1 100644 --- a/sound/pci/ice1712/juli.c +++ b/sound/pci/ice1712/juli.c @@ -503,6 +503,31 @@ static int __devinit juli_add_controls(struct snd_ice1712 *ice) return 0; } +/* + * suspend/resume + * */ + +#ifdef CONFIG_PM +static int juli_resume(struct snd_ice1712 *ice) +{ + struct snd_akm4xxx *ak = ice->akm; + struct juli_spec *spec = ice->spec; + /* akm4358 un-reset, un-mute */ + snd_akm4xxx_reset(ak, 0); + /* reinit ak4114 */ + snd_ak4114_reinit(spec->ak4114); + return 0; +} + +static int juli_suspend(struct snd_ice1712 *ice) +{ + struct snd_akm4xxx *ak = ice->akm; + /* akm4358 reset and soft-mute */ + snd_akm4xxx_reset(ak, 1); + return 0; +} +#endif + /* * initialize the chip */ @@ -646,6 +671,13 @@ static int __devinit juli_init(struct snd_ice1712 *ice) ice->set_spdif_clock = juli_set_spdif_clock; ice->spdif.ops.open = juli_spdif_in_open; + +#ifdef CONFIG_PM + ice->pm_resume = juli_resume; + ice->pm_suspend = juli_suspend; + ice->pm_suspend_enabled = 1; +#endif + return 0; } -- cgit v1.2.3 From 5e08fe570c2dbabb5015c37049eb9a451e55c890 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sat, 14 Nov 2009 14:37:19 +0100 Subject: ALSA: ice1724 - Fix section mismatch in prodigy_hd2_resume() Remove invlid __devinit prefix from the suspend callback. Signed-off-by: Takashi Iwai --- sound/pci/ice1712/prodigy_hifi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/ice1712/prodigy_hifi.c b/sound/pci/ice1712/prodigy_hifi.c index c75515f5be6..6a9fee3ee78 100644 --- a/sound/pci/ice1712/prodigy_hifi.c +++ b/sound/pci/ice1712/prodigy_hifi.c @@ -1100,7 +1100,7 @@ static void ak4396_init(struct snd_ice1712 *ice) } #ifdef CONFIG_PM -static int __devinit prodigy_hd2_resume(struct snd_ice1712 *ice) +static int prodigy_hd2_resume(struct snd_ice1712 *ice) { /* initialize ak4396 codec and restore previous mixer volumes */ struct prodigy_hifi_spec *spec = ice->spec; -- cgit v1.2.3 From e8e63cbf9a339c972eeb5ccf8777c8067bdfd869 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Fri, 16 Oct 2009 16:03:49 -0700 Subject: oss: Mark loadhex static in hex2hex.c Nothing outside of hex2hex.c references loadhex. Signed-off-by: Josh Triplett --- sound/oss/hex2hex.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/oss/hex2hex.c b/sound/oss/hex2hex.c index 5460faae98c..041ef5c52bc 100644 --- a/sound/oss/hex2hex.c +++ b/sound/oss/hex2hex.c @@ -12,7 +12,7 @@ #define MAX_SIZE (256*1024) unsigned char buf[MAX_SIZE]; -int loadhex(FILE *inf, unsigned char *buf) +static int loadhex(FILE *inf, unsigned char *buf) { int l=0, c, i; -- cgit v1.2.3 From bf97402052483c125a9ea7bf13df0dd9b4134078 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 16 Nov 2009 11:07:17 +0200 Subject: ALSA: ice1724 - make some bitfields unsigned This is a clean up and doesn't change the behavior. Bit fields should always be unsigned. Otherwise pm_suspend_enabled will be -1 when you want it to be 1. The other bad thing is that the sparse checker will complain 36 times if they aren't unsigned. The other bitfields in that struct are unsigned already. Signed-off-by: Dan Carpenter Signed-off-by: Takashi Iwai --- sound/pci/ice1712/ice1712.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h index 9da2dae64c5..d063149e704 100644 --- a/sound/pci/ice1712/ice1712.h +++ b/sound/pci/ice1712/ice1712.h @@ -382,8 +382,8 @@ struct snd_ice1712 { #ifdef CONFIG_PM int (*pm_suspend)(struct snd_ice1712 *); int (*pm_resume)(struct snd_ice1712 *); - int pm_suspend_enabled:1; - int pm_saved_is_spdif_master:1; + unsigned int pm_suspend_enabled:1; + unsigned int pm_saved_is_spdif_master:1; unsigned int pm_saved_spdif_ctrl; unsigned char pm_saved_spdif_cfg; unsigned int pm_saved_route; -- cgit v1.2.3 From 8df89bc35c188e389295eaf7917653f13c83ce70 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Mon, 16 Nov 2009 16:19:25 +0200 Subject: ASoC: OMAP: enable Overo driver for CM-T35 Signed-off-by: Mike Rapoport Acked-by: Liam Girdwood Acked-by: Steve Sakoman Signed-off-by: Mark Brown --- sound/soc/omap/Kconfig | 7 ++++--- sound/soc/omap/overo.c | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index bb5731a22be..4dc6b15a852 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig @@ -43,12 +43,13 @@ config SND_OMAP_SOC_OSK5912 Say Y if you want to add support for SoC audio on osk5912. config SND_OMAP_SOC_OVERO - tristate "SoC Audio support for Gumstix Overo" - depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OVERO + tristate "SoC Audio support for Gumstix Overo and CompuLab CM-T35" + depends on TWL4030_CORE && SND_OMAP_SOC && (MACH_OVERO || MACH_CM_T35) select SND_OMAP_SOC_MCBSP select SND_SOC_TWL4030 help - Say Y if you want to add support for SoC audio on the Gumstix Overo. + Say Y if you want to add support for SoC audio on the + Gumstix Overo or CompuLab CM-T35 config SND_OMAP_SOC_OMAP2EVM tristate "SoC Audio support for OMAP2EVM board" diff --git a/sound/soc/omap/overo.c b/sound/soc/omap/overo.c index ec4f8fd8b3a..97a4d6308bd 100644 --- a/sound/soc/omap/overo.c +++ b/sound/soc/omap/overo.c @@ -107,8 +107,8 @@ static int __init overo_soc_init(void) { int ret; - if (!machine_is_overo()) { - pr_debug("Not Overo!\n"); + if (!(machine_is_overo() || machine_is_cm_t35())) { + pr_debug("Incomatible machine!\n"); return -ENODEV; } printk(KERN_INFO "overo SoC init\n"); -- cgit v1.2.3 From 02bb57aeb092cbb0dfdb50c6026dbd0c60af7644 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Mon, 16 Nov 2009 17:05:02 +0100 Subject: sound: OSS: keep index within bounds of midi_devs[] When the {orig,midi}_dev equals num_midis, that's one too large already. Signed-off-by: Roel Kluin Signed-off-by: Takashi Iwai --- sound/oss/midi_synth.c | 2 +- sound/oss/mpu401.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/oss/midi_synth.c b/sound/oss/midi_synth.c index 9e450988ed3..3bc7104c537 100644 --- a/sound/oss/midi_synth.c +++ b/sound/oss/midi_synth.c @@ -426,7 +426,7 @@ midi_synth_open(int dev, int mode) int err; struct midi_input_info *inc; - if (orig_dev < 0 || orig_dev > num_midis || midi_devs[orig_dev] == NULL) + if (orig_dev < 0 || orig_dev >= num_midis || midi_devs[orig_dev] == NULL) return -ENXIO; midi2synth[orig_dev] = dev; diff --git a/sound/oss/mpu401.c b/sound/oss/mpu401.c index 734b8f9e2f7..0af9d24feb8 100644 --- a/sound/oss/mpu401.c +++ b/sound/oss/mpu401.c @@ -770,7 +770,7 @@ static int mpu_synth_ioctl(int dev, unsigned int cmd, void __user *arg) midi_dev = synth_devs[dev]->midi_dev; - if (midi_dev < 0 || midi_dev > num_midis || midi_devs[midi_dev] == NULL) + if (midi_dev < 0 || midi_dev >= num_midis || midi_devs[midi_dev] == NULL) return -ENXIO; devc = &dev_conf[midi_dev]; -- cgit v1.2.3 From baac805fc591b562f22d8f1cd0b65cdbbe9e9518 Mon Sep 17 00:00:00 2001 From: Timothy Knoll Date: Mon, 16 Nov 2009 19:55:46 -0500 Subject: sound: Kconfig typo fix Fix a typo in the help text in sound/Kconfig. Signed-off-by: Timothy Knoll Signed-off-by: Takashi Iwai --- sound/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/Kconfig b/sound/Kconfig index 439e15c8faa..b3e53e616ec 100644 --- a/sound/Kconfig +++ b/sound/Kconfig @@ -58,7 +58,7 @@ config SOUND_OSS_CORE_PRECLAIM Please read Documentation/feature-removal-schedule.txt for details. - If unusre, say Y. + If unsure, say Y. source "sound/oss/dmasound/Kconfig" -- cgit v1.2.3 From f9ede4eca01cc64ce37549c282b6fde727c0ec84 Mon Sep 17 00:00:00 2001 From: Marin Mitov Date: Mon, 16 Nov 2009 21:39:26 +0200 Subject: ASoC: Use DMA_BIT_MASK(32) instead of deprecated DMA_32BIT_MASK Signed-off-by: Marin Mitov Signed-off-by: Takashi Iwai --- sound/soc/s6000/s6000-pcm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/s6000/s6000-pcm.c b/sound/soc/s6000/s6000-pcm.c index 83b8028e209..0eb1722f658 100644 --- a/sound/soc/s6000/s6000-pcm.c +++ b/sound/soc/s6000/s6000-pcm.c @@ -423,7 +423,7 @@ static void s6000_pcm_free(struct snd_pcm *pcm) snd_pcm_lib_preallocate_free_for_all(pcm); } -static u64 s6000_pcm_dmamask = DMA_32BIT_MASK; +static u64 s6000_pcm_dmamask = DMA_BIT_MASK(32); static int s6000_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, struct snd_pcm *pcm) @@ -435,7 +435,7 @@ static int s6000_pcm_new(struct snd_card *card, if (!card->dev->dma_mask) card->dev->dma_mask = &s6000_pcm_dmamask; if (!card->dev->coherent_dma_mask) - card->dev->coherent_dma_mask = DMA_32BIT_MASK; + card->dev->coherent_dma_mask = DMA_BIT_MASK(32); if (params->dma_in) { s6dmac_disable_chan(DMA_MASK_DMAC(params->dma_in), -- cgit v1.2.3 From 0c3cee57efcb1c79d62b1238c0d22afef4599247 Mon Sep 17 00:00:00 2001 From: Javier Kohen Date: Tue, 17 Nov 2009 15:36:13 +0100 Subject: ALSA: usb - Quirk to disable master volume control in PCM2702 Disable the master volume control in the PCM2702 chipset. The datasheet documents two independent channel volume controls, one master mute control and one master volume control. All controls are fully functional except for the master volume control, which returns USB stalls on all GET requests. Signed-off-by: Javier Kohen Signed-off-by: Takashi Iwai --- sound/usb/usbmixer.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'sound') diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index 9efcfd08d74..c998220b99c 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -1071,6 +1071,15 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, unsig channels = (ftr[0] - 7) / csize - 1; master_bits = snd_usb_combine_bytes(ftr + 6, csize); + /* master configuration quirks */ + switch (state->chip->usb_id) { + case USB_ID(0x08bb, 0x2702): + snd_printk(KERN_INFO + "usbmixer: master volume quirk for PCM2702 chip\n"); + /* disable non-functional volume control */ + master_bits &= ~(1 << (USB_FEATURE_VOLUME - 1)); + break; + } if (channels > 0) first_ch_bits = snd_usb_combine_bytes(ftr + 6 + csize, csize); else -- cgit v1.2.3 From b753e03e5e7c6ee60e81cd6335c80dc26519f9d0 Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Tue, 17 Nov 2009 18:34:54 +0100 Subject: ALSA: cs4236: update control names Update control names to be more closer to their meaning. Change the "Mono" name to the "Beep" as this line is usually used to forward the PC beeper signal to sound card's output. Update names for both cs423x and wss. Clean up cs4235 controls according to the cs4235 doc. Rename some of the cs4235 controls to be consistent with the cs4236's ones. Also, delete one misnamed cs4231 register define. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai --- sound/isa/cs423x/cs4236_lib.c | 49 +++++++++++++++++++------------------------ sound/isa/wss/wss_lib.c | 8 +++---- 2 files changed, 25 insertions(+), 32 deletions(-) (limited to 'sound') diff --git a/sound/isa/cs423x/cs4236_lib.c b/sound/isa/cs423x/cs4236_lib.c index 1b1ad1cad32..4c4024a73c6 100644 --- a/sound/isa/cs423x/cs4236_lib.c +++ b/sound/isa/cs423x/cs4236_lib.c @@ -777,7 +777,7 @@ CS4236_DOUBLE("Mic Playback Switch", 0, CS4236_DOUBLE("Mic Capture Switch", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 7, 7, 1, 1), CS4236_DOUBLE("Mic Volume", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 0, 0, 31, 1), -CS4236_DOUBLE("Mic Playback Boost", 0, +CS4236_DOUBLE("Mic Playback Boost (+20dB)", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 5, 5, 1, 0), WSS_DOUBLE("Line Playback Switch", 0, @@ -798,10 +798,10 @@ WSS_DOUBLE("CD Capture Switch", 0, CS4236_DOUBLE1("Mono Output Playback Switch", 0, CS4231_MONO_CTRL, CS4236_RIGHT_MIX_CTRL, 6, 7, 1, 1), -CS4236_DOUBLE1("Mono Playback Switch", 0, +CS4236_DOUBLE1("Beep Playback Switch", 0, CS4231_MONO_CTRL, CS4236_LEFT_MIX_CTRL, 7, 7, 1, 1), -WSS_SINGLE("Mono Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1), -WSS_SINGLE("Mono Playback Bypass", 0, CS4231_MONO_CTRL, 5, 1, 0), +WSS_SINGLE("Beep Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1), +WSS_SINGLE("Beep Bypass Playback Switch", 0, CS4231_MONO_CTRL, 5, 1, 0), WSS_DOUBLE("Capture Volume", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0), @@ -815,31 +815,27 @@ CS4236_DOUBLE1("Digital Loopback Playback Volume", 0, static struct snd_kcontrol_new snd_cs4235_controls[] = { -WSS_DOUBLE("Master Switch", 0, +WSS_DOUBLE("Master Playback Switch", 0, CS4235_LEFT_MASTER, CS4235_RIGHT_MASTER, 7, 7, 1, 1), -WSS_DOUBLE("Master Volume", 0, +WSS_DOUBLE("Master Playback Volume", 0, CS4235_LEFT_MASTER, CS4235_RIGHT_MASTER, 0, 0, 31, 1), CS4235_OUTPUT_ACCU("Playback Volume", 0), -CS4236_DOUBLE("Master Digital Playback Switch", 0, - CS4236_LEFT_MASTER, CS4236_RIGHT_MASTER, 7, 7, 1, 1), -CS4236_DOUBLE("Master Digital Capture Switch", 0, - CS4236_DAC_MUTE, CS4236_DAC_MUTE, 7, 6, 1, 1), -CS4236_MASTER_DIGITAL("Master Digital Volume", 0), - -WSS_DOUBLE("Master Digital Playback Switch", 1, +WSS_DOUBLE("Synth Playback Switch", 1, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1), -WSS_DOUBLE("Master Digital Capture Switch", 1, +WSS_DOUBLE("Synth Capture Switch", 1, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 6, 6, 1, 1), -WSS_DOUBLE("Master Digital Volume", 1, +WSS_DOUBLE("Synth Volume", 1, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1), CS4236_DOUBLE("Capture Volume", 0, CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1), -WSS_DOUBLE("PCM Switch", 0, +WSS_DOUBLE("PCM Playback Switch", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1), +WSS_DOUBLE("PCM Capture Switch", 0, + CS4236_DAC_MUTE, CS4236_DAC_MUTE, 7, 6, 1, 1), WSS_DOUBLE("PCM Volume", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1), @@ -855,28 +851,25 @@ CS4236_DOUBLE("Mic Capture Switch", 0, CS4236_DOUBLE("Mic Playback Switch", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 6, 6, 1, 1), CS4236_SINGLE("Mic Volume", 0, CS4236_LEFT_MIC, 0, 31, 1), -CS4236_SINGLE("Mic Playback Boost", 0, CS4236_LEFT_MIC, 5, 1, 0), +CS4236_SINGLE("Mic Boost (+20dB)", 0, CS4236_LEFT_MIC, 5, 1, 0), -WSS_DOUBLE("Aux Playback Switch", 0, +WSS_DOUBLE("Line Playback Switch", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1), -WSS_DOUBLE("Aux Capture Switch", 0, +WSS_DOUBLE("Line Capture Switch", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 6, 6, 1, 1), -WSS_DOUBLE("Aux Volume", 0, +WSS_DOUBLE("Line Volume", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1), -WSS_DOUBLE("Aux Playback Switch", 1, +WSS_DOUBLE("CD Playback Switch", 1, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1), -WSS_DOUBLE("Aux Capture Switch", 1, +WSS_DOUBLE("CD Capture Switch", 1, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 6, 6, 1, 1), -WSS_DOUBLE("Aux Volume", 1, +WSS_DOUBLE("CD Volume", 1, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1), -CS4236_DOUBLE1("Master Mono Switch", 0, - CS4231_MONO_CTRL, CS4236_RIGHT_MIX_CTRL, 6, 7, 1, 1), - -CS4236_DOUBLE1("Mono Switch", 0, +CS4236_DOUBLE1("Beep Playback Switch", 0, CS4231_MONO_CTRL, CS4236_LEFT_MIX_CTRL, 7, 7, 1, 1), -WSS_SINGLE("Mono Volume", 0, CS4231_MONO_CTRL, 0, 15, 1), +WSS_SINGLE("Beep Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1), WSS_DOUBLE("Analog Loopback Switch", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 7, 7, 1, 0), diff --git a/sound/isa/wss/wss_lib.c b/sound/isa/wss/wss_lib.c index 705db092437..5b9d6c18bc4 100644 --- a/sound/isa/wss/wss_lib.c +++ b/sound/isa/wss/wss_lib.c @@ -2224,7 +2224,7 @@ WSS_DOUBLE_TLV("Capture Volume", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, .get = snd_wss_get_mux, .put = snd_wss_put_mux, }, -WSS_DOUBLE("Mic Boost", 0, +WSS_DOUBLE("Mic Boost (+20dB)", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 5, 5, 1, 0), WSS_SINGLE("Loopback Capture Switch", 0, CS4231_LOOPBACK, 0, 1, 0), @@ -2235,14 +2235,14 @@ WSS_DOUBLE("Line Playback Switch", 0, WSS_DOUBLE_TLV("Line Playback Volume", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1, db_scale_5bit_12db_max), -WSS_SINGLE("Mono Playback Switch", 0, +WSS_SINGLE("Beep Playback Switch", 0, CS4231_MONO_CTRL, 7, 1, 1), -WSS_SINGLE_TLV("Mono Playback Volume", 0, +WSS_SINGLE_TLV("Beep Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1, db_scale_4bit), WSS_SINGLE("Mono Output Playback Switch", 0, CS4231_MONO_CTRL, 6, 1, 1), -WSS_SINGLE("Mono Output Playback Bypass", 0, +WSS_SINGLE("Beep Bypass Playback Switch", 0, CS4231_MONO_CTRL, 5, 1, 0), }; -- cgit v1.2.3 From b67cad932c4e45edca2f4da2ee4f46001ba17363 Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Tue, 17 Nov 2009 18:35:41 +0100 Subject: ALSA: opti-miro: use variables directly in the probe function Use the fm_port and mpu_port variables directly in a probe function. This completely eliminates a need to copy the fm_port value to the snd_miro structure. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai --- sound/isa/opti9xx/miro.c | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) (limited to 'sound') diff --git a/sound/isa/opti9xx/miro.c b/sound/isa/opti9xx/miro.c index 02e30d7c6a9..b8170adeeff 100644 --- a/sound/isa/opti9xx/miro.c +++ b/sound/isa/opti9xx/miro.c @@ -118,8 +118,6 @@ struct snd_miro { int dma1; int dma2; - long fm_port; - long mpu_port; int mpu_irq; @@ -757,7 +755,6 @@ static int __devinit snd_miro_init(struct snd_miro *chip, chip->irq = -1; chip->dma1 = -1; chip->dma2 = -1; - chip->fm_port = -1; chip->mpu_port = -1; chip->mpu_irq = -1; @@ -1261,7 +1258,6 @@ static int __devinit snd_miro_probe(struct device *devptr, unsigned int n) } miro->wss_base = port; - miro->fm_port = fm_port; miro->mpu_port = mpu_port; miro->irq = irq; miro->mpu_irq = mpu_irq; @@ -1276,11 +1272,12 @@ static int __devinit snd_miro_probe(struct device *devptr, unsigned int n) } } - if (miro->mpu_port == SNDRV_AUTO_PORT) { - if ((miro->mpu_port = snd_legacy_find_free_ioport(possible_mpu_ports, 2)) < 0) { + if (mpu_port == SNDRV_AUTO_PORT) { + mpu_port = snd_legacy_find_free_ioport(possible_mpu_ports, 2); + if (mpu_port < 0) { snd_card_free(card); snd_printk(KERN_ERR "unable to find a free MPU401 port\n"); - return -EBUSY; + return -EBUSY } } if (miro->irq == SNDRV_AUTO_IRQ) { @@ -1380,20 +1377,24 @@ static int __devinit snd_miro_probe(struct device *devptr, unsigned int n) card->shortname, miro->name, pcm->name, miro->wss_base + 4, miro->irq, miro->dma1, miro->dma2); - if (miro->mpu_port <= 0 || miro->mpu_port == SNDRV_AUTO_PORT) + if (mpu_port <= 0 || mpu_port == SNDRV_AUTO_PORT) rmidi = NULL; - else - if ((error = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, - miro->mpu_port, 0, miro->mpu_irq, IRQF_DISABLED, - &rmidi))) - snd_printk(KERN_WARNING "no MPU-401 device at 0x%lx?\n", miro->mpu_port); + else { + error = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, + mpu_port, 0, miro->mpu_irq, IRQF_DISABLED, + &rmidi); + if (error < 0) + snd_printk(KERN_WARNING "no MPU-401 device at 0x%lx?\n", + mpu_port); + } - if (miro->fm_port > 0 && miro->fm_port != SNDRV_AUTO_PORT) { + if (fm_port > 0 && fm_port != SNDRV_AUTO_PORT) { struct snd_opl3 *opl3 = NULL; struct snd_opl4 *opl4; - if (snd_opl4_create(card, miro->fm_port, miro->fm_port - 8, + if (snd_opl4_create(card, fm_port, fm_port - 8, 2, &opl3, &opl4) < 0) - snd_printk(KERN_WARNING "no OPL4 device at 0x%lx\n", miro->fm_port); + snd_printk(KERN_WARNING "no OPL4 device at 0x%lx\n", + fm_port); } if ((error = snd_set_aci_init_values(miro)) < 0) { -- cgit v1.2.3 From 67f2db24fbfdb63495d995d6fbbbe42980004ee0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 18 Nov 2009 08:37:59 +0100 Subject: ALSA: opti-miro: Fix missing semicolon To fix a build error sound/isa/opti9xx/miro.c:1281: error: expected ';' before '}' token Signed-off-by: Takashi Iwai --- sound/isa/opti9xx/miro.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/isa/opti9xx/miro.c b/sound/isa/opti9xx/miro.c index b8170adeeff..17761030aff 100644 --- a/sound/isa/opti9xx/miro.c +++ b/sound/isa/opti9xx/miro.c @@ -1277,7 +1277,7 @@ static int __devinit snd_miro_probe(struct device *devptr, unsigned int n) if (mpu_port < 0) { snd_card_free(card); snd_printk(KERN_ERR "unable to find a free MPU401 port\n"); - return -EBUSY + return -EBUSY; } } if (miro->irq == SNDRV_AUTO_IRQ) { -- cgit v1.2.3 From bec145ae6f6978f0319e5600a742f45f76ecc4dd Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 18 Nov 2009 10:31:57 +0200 Subject: ALSA: remove unnecessary null check This function is only called from snd_ctl_ioctl() and the file parameter can never be null so there is no need to check it here. We dereference file at the start of the function: struct snd_card *card = file->card; and it confuses static checkers to dereference a pointer before checking it. Signed-off-by: Dan Carpenter Signed-off-by: Takashi Iwai --- sound/core/control.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/core/control.c b/sound/core/control.c index a8b7fabe645..b586019faf3 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -1120,7 +1120,7 @@ static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file, goto __kctl_end; } if (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { - if (file && vd->owner != NULL && vd->owner != file) { + if (vd->owner != NULL && vd->owner != file) { err = -EPERM; goto __kctl_end; } -- cgit v1.2.3 From faa31776e4c799d631d8cd3a13dd50cd95b0875e Mon Sep 17 00:00:00 2001 From: Jassi Brar Date: Tue, 17 Nov 2009 16:53:23 +0900 Subject: ASoC: Rename s3c24xx_pcm prefix to s3c_dma The s3c24xx_pcm prefix for the soc_platform is inappropriate when some Samsung SoCs have PCM controllers which will eventually have drivers and hence namespace ambiguities. To resolve naming ambiguities in future the following have been renamed in order 1) s3c24xx_pcm_dma_params -> s3c_dma_params 2) s3c24xx_pcm_preallocate_dma_buffer -> s3c_preallocate_dma_buffer 3) s3c24xx_pcm_dmamask -> s3c_dma_mask 4) s3c24xx_pcm_XXX -> s3c_dma_XXX Signed-off-by: Jassi Brar Acked-by: Ben Dooks Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/s3c24xx/s3c-i2s-v2.c | 2 +- sound/soc/s3c24xx/s3c-i2s-v2.h | 4 +-- sound/soc/s3c24xx/s3c2412-i2s.c | 4 +-- sound/soc/s3c24xx/s3c2443-ac97.c | 10 +++--- sound/soc/s3c24xx/s3c24xx-i2s.c | 10 +++--- sound/soc/s3c24xx/s3c24xx-pcm.c | 76 ++++++++++++++++++++-------------------- sound/soc/s3c24xx/s3c24xx-pcm.h | 6 ++-- sound/soc/s3c24xx/s3c64xx-i2s.c | 4 +-- 8 files changed, 58 insertions(+), 58 deletions(-) (limited to 'sound') diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.c b/sound/soc/s3c24xx/s3c-i2s-v2.c index 28b0ab25509..5a442aa8b87 100644 --- a/sound/soc/s3c24xx/s3c-i2s-v2.c +++ b/sound/soc/s3c24xx/s3c-i2s-v2.c @@ -394,7 +394,7 @@ static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd, int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); unsigned long irqs; int ret = 0; - int channel = ((struct s3c24xx_pcm_dma_params *) + int channel = ((struct s3c_dma_params *) rtd->dai->cpu_dai->dma_data)->channel; pr_debug("Entered %s\n", __func__); diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.h b/sound/soc/s3c24xx/s3c-i2s-v2.h index f66854a77fb..ecf8eaaed1d 100644 --- a/sound/soc/s3c24xx/s3c-i2s-v2.h +++ b/sound/soc/s3c24xx/s3c-i2s-v2.h @@ -49,8 +49,8 @@ struct s3c_i2sv2_info { unsigned char master; - struct s3c24xx_pcm_dma_params *dma_playback; - struct s3c24xx_pcm_dma_params *dma_capture; + struct s3c_dma_params *dma_playback; + struct s3c_dma_params *dma_capture; u32 suspend_iismod; u32 suspend_iiscon; diff --git a/sound/soc/s3c24xx/s3c2412-i2s.c b/sound/soc/s3c24xx/s3c2412-i2s.c index ac5e47b082f..23718ea8518 100644 --- a/sound/soc/s3c24xx/s3c2412-i2s.c +++ b/sound/soc/s3c24xx/s3c2412-i2s.c @@ -50,14 +50,14 @@ static struct s3c2410_dma_client s3c2412_dma_client_in = { .name = "I2S PCM Stereo in" }; -static struct s3c24xx_pcm_dma_params s3c2412_i2s_pcm_stereo_out = { +static struct s3c_dma_params s3c2412_i2s_pcm_stereo_out = { .client = &s3c2412_dma_client_out, .channel = DMACH_I2S_OUT, .dma_addr = S3C2410_PA_IIS + S3C2412_IISTXD, .dma_size = 4, }; -static struct s3c24xx_pcm_dma_params s3c2412_i2s_pcm_stereo_in = { +static struct s3c_dma_params s3c2412_i2s_pcm_stereo_in = { .client = &s3c2412_dma_client_in, .channel = DMACH_I2S_IN, .dma_addr = S3C2410_PA_IIS + S3C2412_IISRXD, diff --git a/sound/soc/s3c24xx/s3c2443-ac97.c b/sound/soc/s3c24xx/s3c2443-ac97.c index b25e9f968df..678b1763160 100644 --- a/sound/soc/s3c24xx/s3c2443-ac97.c +++ b/sound/soc/s3c24xx/s3c2443-ac97.c @@ -188,21 +188,21 @@ static struct s3c2410_dma_client s3c2443_dma_client_micin = { .name = "AC97 Mic Mono in" }; -static struct s3c24xx_pcm_dma_params s3c2443_ac97_pcm_stereo_out = { +static struct s3c_dma_params s3c2443_ac97_pcm_stereo_out = { .client = &s3c2443_dma_client_out, .channel = DMACH_PCM_OUT, .dma_addr = S3C2440_PA_AC97 + S3C_AC97_PCM_DATA, .dma_size = 4, }; -static struct s3c24xx_pcm_dma_params s3c2443_ac97_pcm_stereo_in = { +static struct s3c_dma_params s3c2443_ac97_pcm_stereo_in = { .client = &s3c2443_dma_client_in, .channel = DMACH_PCM_IN, .dma_addr = S3C2440_PA_AC97 + S3C_AC97_PCM_DATA, .dma_size = 4, }; -static struct s3c24xx_pcm_dma_params s3c2443_ac97_mic_mono_in = { +static struct s3c_dma_params s3c2443_ac97_mic_mono_in = { .client = &s3c2443_dma_client_micin, .channel = DMACH_MIC_IN, .dma_addr = S3C2440_PA_AC97 + S3C_AC97_MIC_DATA, @@ -290,7 +290,7 @@ static int s3c2443_ac97_trigger(struct snd_pcm_substream *substream, int cmd, { u32 ac_glbctrl; struct snd_soc_pcm_runtime *rtd = substream->private_data; - int channel = ((struct s3c24xx_pcm_dma_params *) + int channel = ((struct s3c_dma_params *) rtd->dai->cpu_dai->dma_data)->channel; ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); @@ -339,7 +339,7 @@ static int s3c2443_ac97_mic_trigger(struct snd_pcm_substream *substream, { u32 ac_glbctrl; struct snd_soc_pcm_runtime *rtd = substream->private_data; - int channel = ((struct s3c24xx_pcm_dma_params *) + int channel = ((struct s3c_dma_params *) rtd->dai->cpu_dai->dma_data)->channel; ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.c b/sound/soc/s3c24xx/s3c24xx-i2s.c index c76b8bb214b..afb4bc9033c 100644 --- a/sound/soc/s3c24xx/s3c24xx-i2s.c +++ b/sound/soc/s3c24xx/s3c24xx-i2s.c @@ -49,14 +49,14 @@ static struct s3c2410_dma_client s3c24xx_dma_client_in = { .name = "I2S PCM Stereo in" }; -static struct s3c24xx_pcm_dma_params s3c24xx_i2s_pcm_stereo_out = { +static struct s3c_dma_params s3c24xx_i2s_pcm_stereo_out = { .client = &s3c24xx_dma_client_out, .channel = DMACH_I2S_OUT, .dma_addr = S3C2410_PA_IIS + S3C2410_IISFIFO, .dma_size = 2, }; -static struct s3c24xx_pcm_dma_params s3c24xx_i2s_pcm_stereo_in = { +static struct s3c_dma_params s3c24xx_i2s_pcm_stereo_in = { .client = &s3c24xx_dma_client_in, .channel = DMACH_I2S_IN, .dma_addr = S3C2410_PA_IIS + S3C2410_IISFIFO, @@ -258,12 +258,12 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream, switch (params_format(params)) { case SNDRV_PCM_FORMAT_S8: iismod &= ~S3C2410_IISMOD_16BIT; - ((struct s3c24xx_pcm_dma_params *) + ((struct s3c_dma_params *) rtd->dai->cpu_dai->dma_data)->dma_size = 1; break; case SNDRV_PCM_FORMAT_S16_LE: iismod |= S3C2410_IISMOD_16BIT; - ((struct s3c24xx_pcm_dma_params *) + ((struct s3c_dma_params *) rtd->dai->cpu_dai->dma_data)->dma_size = 2; break; default: @@ -280,7 +280,7 @@ static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd, { int ret = 0; struct snd_soc_pcm_runtime *rtd = substream->private_data; - int channel = ((struct s3c24xx_pcm_dma_params *) + int channel = ((struct s3c_dma_params *) rtd->dai->cpu_dai->dma_data)->channel; pr_debug("Entered %s\n", __func__); diff --git a/sound/soc/s3c24xx/s3c24xx-pcm.c b/sound/soc/s3c24xx/s3c24xx-pcm.c index 151a6946326..cb49400d8c5 100644 --- a/sound/soc/s3c24xx/s3c24xx-pcm.c +++ b/sound/soc/s3c24xx/s3c24xx-pcm.c @@ -32,7 +32,7 @@ #include "s3c24xx-pcm.h" -static const struct snd_pcm_hardware s3c24xx_pcm_hardware = { +static const struct snd_pcm_hardware s3c_dma_hardware = { .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | @@ -62,15 +62,15 @@ struct s3c24xx_runtime_data { dma_addr_t dma_start; dma_addr_t dma_pos; dma_addr_t dma_end; - struct s3c24xx_pcm_dma_params *params; + struct s3c_dma_params *params; }; -/* s3c24xx_pcm_enqueue +/* s3c_dma_enqueue * * place a dma buffer onto the queue for the dma system * to handle. */ -static void s3c24xx_pcm_enqueue(struct snd_pcm_substream *substream) +static void s3c_dma_enqueue(struct snd_pcm_substream *substream) { struct s3c24xx_runtime_data *prtd = substream->runtime->private_data; dma_addr_t pos = prtd->dma_pos; @@ -132,19 +132,19 @@ static void s3c24xx_audio_buffdone(struct s3c2410_dma_chan *channel, spin_lock(&prtd->lock); if (prtd->state & ST_RUNNING && !s3c_dma_has_circular()) { prtd->dma_loaded--; - s3c24xx_pcm_enqueue(substream); + s3c_dma_enqueue(substream); } spin_unlock(&prtd->lock); } -static int s3c24xx_pcm_hw_params(struct snd_pcm_substream *substream, +static int s3c_dma_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_pcm_runtime *runtime = substream->runtime; struct s3c24xx_runtime_data *prtd = runtime->private_data; struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct s3c24xx_pcm_dma_params *dma = rtd->dai->cpu_dai->dma_data; + struct s3c_dma_params *dma = rtd->dai->cpu_dai->dma_data; unsigned long totbytes = params_buffer_bytes(params); int ret = 0; @@ -197,7 +197,7 @@ static int s3c24xx_pcm_hw_params(struct snd_pcm_substream *substream, return 0; } -static int s3c24xx_pcm_hw_free(struct snd_pcm_substream *substream) +static int s3c_dma_hw_free(struct snd_pcm_substream *substream) { struct s3c24xx_runtime_data *prtd = substream->runtime->private_data; @@ -214,7 +214,7 @@ static int s3c24xx_pcm_hw_free(struct snd_pcm_substream *substream) return 0; } -static int s3c24xx_pcm_prepare(struct snd_pcm_substream *substream) +static int s3c_dma_prepare(struct snd_pcm_substream *substream) { struct s3c24xx_runtime_data *prtd = substream->runtime->private_data; int ret = 0; @@ -247,12 +247,12 @@ static int s3c24xx_pcm_prepare(struct snd_pcm_substream *substream) prtd->dma_pos = prtd->dma_start; /* enqueue dma buffers */ - s3c24xx_pcm_enqueue(substream); + s3c_dma_enqueue(substream); return ret; } -static int s3c24xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +static int s3c_dma_trigger(struct snd_pcm_substream *substream, int cmd) { struct s3c24xx_runtime_data *prtd = substream->runtime->private_data; int ret = 0; @@ -287,7 +287,7 @@ static int s3c24xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) } static snd_pcm_uframes_t -s3c24xx_pcm_pointer(struct snd_pcm_substream *substream) +s3c_dma_pointer(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct s3c24xx_runtime_data *prtd = runtime->private_data; @@ -322,7 +322,7 @@ s3c24xx_pcm_pointer(struct snd_pcm_substream *substream) return bytes_to_frames(substream->runtime, res); } -static int s3c24xx_pcm_open(struct snd_pcm_substream *substream) +static int s3c_dma_open(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct s3c24xx_runtime_data *prtd; @@ -330,7 +330,7 @@ static int s3c24xx_pcm_open(struct snd_pcm_substream *substream) pr_debug("Entered %s\n", __func__); snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); - snd_soc_set_runtime_hwparams(substream, &s3c24xx_pcm_hardware); + snd_soc_set_runtime_hwparams(substream, &s3c_dma_hardware); prtd = kzalloc(sizeof(struct s3c24xx_runtime_data), GFP_KERNEL); if (prtd == NULL) @@ -342,7 +342,7 @@ static int s3c24xx_pcm_open(struct snd_pcm_substream *substream) return 0; } -static int s3c24xx_pcm_close(struct snd_pcm_substream *substream) +static int s3c_dma_close(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct s3c24xx_runtime_data *prtd = runtime->private_data; @@ -350,14 +350,14 @@ static int s3c24xx_pcm_close(struct snd_pcm_substream *substream) pr_debug("Entered %s\n", __func__); if (!prtd) - pr_debug("s3c24xx_pcm_close called with prtd == NULL\n"); + pr_debug("s3c_dma_close called with prtd == NULL\n"); kfree(prtd); return 0; } -static int s3c24xx_pcm_mmap(struct snd_pcm_substream *substream, +static int s3c_dma_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma) { struct snd_pcm_runtime *runtime = substream->runtime; @@ -370,23 +370,23 @@ static int s3c24xx_pcm_mmap(struct snd_pcm_substream *substream, runtime->dma_bytes); } -static struct snd_pcm_ops s3c24xx_pcm_ops = { - .open = s3c24xx_pcm_open, - .close = s3c24xx_pcm_close, +static struct snd_pcm_ops s3c_dma_ops = { + .open = s3c_dma_open, + .close = s3c_dma_close, .ioctl = snd_pcm_lib_ioctl, - .hw_params = s3c24xx_pcm_hw_params, - .hw_free = s3c24xx_pcm_hw_free, - .prepare = s3c24xx_pcm_prepare, - .trigger = s3c24xx_pcm_trigger, - .pointer = s3c24xx_pcm_pointer, - .mmap = s3c24xx_pcm_mmap, + .hw_params = s3c_dma_hw_params, + .hw_free = s3c_dma_hw_free, + .prepare = s3c_dma_prepare, + .trigger = s3c_dma_trigger, + .pointer = s3c_dma_pointer, + .mmap = s3c_dma_mmap, }; -static int s3c24xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) +static int s3c_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) { struct snd_pcm_substream *substream = pcm->streams[stream].substream; struct snd_dma_buffer *buf = &substream->dma_buffer; - size_t size = s3c24xx_pcm_hardware.buffer_bytes_max; + size_t size = s3c_dma_hardware.buffer_bytes_max; pr_debug("Entered %s\n", __func__); @@ -401,7 +401,7 @@ static int s3c24xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) return 0; } -static void s3c24xx_pcm_free_dma_buffers(struct snd_pcm *pcm) +static void s3c_dma_free_dma_buffers(struct snd_pcm *pcm) { struct snd_pcm_substream *substream; struct snd_dma_buffer *buf; @@ -424,9 +424,9 @@ static void s3c24xx_pcm_free_dma_buffers(struct snd_pcm *pcm) } } -static u64 s3c24xx_pcm_dmamask = DMA_BIT_MASK(32); +static u64 s3c_dma_mask = DMA_BIT_MASK(32); -static int s3c24xx_pcm_new(struct snd_card *card, +static int s3c_dma_new(struct snd_card *card, struct snd_soc_dai *dai, struct snd_pcm *pcm) { int ret = 0; @@ -434,19 +434,19 @@ static int s3c24xx_pcm_new(struct snd_card *card, pr_debug("Entered %s\n", __func__); if (!card->dev->dma_mask) - card->dev->dma_mask = &s3c24xx_pcm_dmamask; + card->dev->dma_mask = &s3c_dma_mask; if (!card->dev->coherent_dma_mask) card->dev->coherent_dma_mask = 0xffffffff; if (dai->playback.channels_min) { - ret = s3c24xx_pcm_preallocate_dma_buffer(pcm, + ret = s3c_preallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK); if (ret) goto out; } if (dai->capture.channels_min) { - ret = s3c24xx_pcm_preallocate_dma_buffer(pcm, + ret = s3c_preallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_CAPTURE); if (ret) goto out; @@ -457,9 +457,9 @@ static int s3c24xx_pcm_new(struct snd_card *card, struct snd_soc_platform s3c24xx_soc_platform = { .name = "s3c24xx-audio", - .pcm_ops = &s3c24xx_pcm_ops, - .pcm_new = s3c24xx_pcm_new, - .pcm_free = s3c24xx_pcm_free_dma_buffers, + .pcm_ops = &s3c_dma_ops, + .pcm_new = s3c_dma_new, + .pcm_free = s3c_dma_free_dma_buffers, }; EXPORT_SYMBOL_GPL(s3c24xx_soc_platform); @@ -476,5 +476,5 @@ static void __exit s3c24xx_soc_platform_exit(void) module_exit(s3c24xx_soc_platform_exit); MODULE_AUTHOR("Ben Dooks, "); -MODULE_DESCRIPTION("Samsung S3C24XX PCM DMA module"); +MODULE_DESCRIPTION("Samsung S3C Audio DMA module"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/s3c24xx/s3c24xx-pcm.h b/sound/soc/s3c24xx/s3c24xx-pcm.h index 0088c79822e..8cbc071124c 100644 --- a/sound/soc/s3c24xx/s3c24xx-pcm.h +++ b/sound/soc/s3c24xx/s3c24xx-pcm.h @@ -9,13 +9,13 @@ * ALSA PCM interface for the Samsung S3C24xx CPU */ -#ifndef _S3C24XX_PCM_H -#define _S3C24XX_PCM_H +#ifndef _S3C_AUDIO_H +#define _S3C_AUDIO_H #define ST_RUNNING (1<<0) #define ST_OPENED (1<<1) -struct s3c24xx_pcm_dma_params { +struct s3c_dma_params { struct s3c2410_dma_client *client; /* stream identifier */ int channel; /* Channel ID */ dma_addr_t dma_addr; diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.c b/sound/soc/s3c24xx/s3c64xx-i2s.c index d68cae15561..719d63c27fd 100644 --- a/sound/soc/s3c24xx/s3c64xx-i2s.c +++ b/sound/soc/s3c24xx/s3c64xx-i2s.c @@ -46,7 +46,7 @@ static struct s3c2410_dma_client s3c64xx_dma_client_in = { .name = "I2S PCM Stereo in" }; -static struct s3c24xx_pcm_dma_params s3c64xx_i2s_pcm_stereo_out[2] = { +static struct s3c_dma_params s3c64xx_i2s_pcm_stereo_out[2] = { [0] = { .channel = DMACH_I2S0_OUT, .client = &s3c64xx_dma_client_out, @@ -61,7 +61,7 @@ static struct s3c24xx_pcm_dma_params s3c64xx_i2s_pcm_stereo_out[2] = { }, }; -static struct s3c24xx_pcm_dma_params s3c64xx_i2s_pcm_stereo_in[2] = { +static struct s3c_dma_params s3c64xx_i2s_pcm_stereo_in[2] = { [0] = { .channel = DMACH_I2S0_IN, .client = &s3c64xx_dma_client_in, -- cgit v1.2.3 From d3ff5a3e610d62d9cdad5b7d53749c9381e244ed Mon Sep 17 00:00:00 2001 From: Jassi Brar Date: Tue, 17 Nov 2009 16:53:31 +0900 Subject: ASoC: Rename 's3c24xx-pcm' driver to 's3c-dma' Making room for namespace for the PCM Controller driver the platform driver(s3c24xx-pcm) has been renamed to SoC agnostic name 's3c-dma'. Signed-off-by: Jassi Brar Acked-by: Ben Dooks Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/s3c24xx/Makefile | 2 +- sound/soc/s3c24xx/jive_wm8750.c | 2 +- sound/soc/s3c24xx/ln2440sbc_alc650.c | 2 +- sound/soc/s3c24xx/neo1973_gta02_wm8753.c | 2 +- sound/soc/s3c24xx/neo1973_wm8753.c | 2 +- sound/soc/s3c24xx/s3c-dma.c | 481 +++++++++++++++++++++++++ sound/soc/s3c24xx/s3c-dma.h | 31 ++ sound/soc/s3c24xx/s3c-i2s-v2.c | 2 +- sound/soc/s3c24xx/s3c2412-i2s.c | 2 +- sound/soc/s3c24xx/s3c2443-ac97.c | 2 +- sound/soc/s3c24xx/s3c24xx-i2s.c | 2 +- sound/soc/s3c24xx/s3c24xx-pcm.c | 480 ------------------------ sound/soc/s3c24xx/s3c24xx-pcm.h | 31 -- sound/soc/s3c24xx/s3c24xx_simtec.c | 2 +- sound/soc/s3c24xx/s3c24xx_simtec_hermes.c | 2 +- sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c | 2 +- sound/soc/s3c24xx/s3c24xx_uda134x.c | 2 +- sound/soc/s3c24xx/s3c64xx-i2s.c | 2 +- sound/soc/s3c24xx/smdk2443_wm9710.c | 2 +- sound/soc/s3c24xx/smdk64xx_wm8580.c | 2 +- 20 files changed, 528 insertions(+), 527 deletions(-) create mode 100644 sound/soc/s3c24xx/s3c-dma.c create mode 100644 sound/soc/s3c24xx/s3c-dma.h delete mode 100644 sound/soc/s3c24xx/s3c24xx-pcm.c delete mode 100644 sound/soc/s3c24xx/s3c24xx-pcm.h (limited to 'sound') diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile index 7790406f90b..ff0a10536ef 100644 --- a/sound/soc/s3c24xx/Makefile +++ b/sound/soc/s3c24xx/Makefile @@ -1,5 +1,5 @@ # S3c24XX Platform Support -snd-soc-s3c24xx-objs := s3c24xx-pcm.o +snd-soc-s3c24xx-objs := s3c-dma.o snd-soc-s3c24xx-i2s-objs := s3c24xx-i2s.o snd-soc-s3c2412-i2s-objs := s3c2412-i2s.o snd-soc-s3c64xx-i2s-objs := s3c64xx-i2s.o diff --git a/sound/soc/s3c24xx/jive_wm8750.c b/sound/soc/s3c24xx/jive_wm8750.c index 93e6c87b739..59dc2c6b56d 100644 --- a/sound/soc/s3c24xx/jive_wm8750.c +++ b/sound/soc/s3c24xx/jive_wm8750.c @@ -25,7 +25,7 @@ #include -#include "s3c24xx-pcm.h" +#include "s3c-dma.h" #include "s3c2412-i2s.h" #include "../codecs/wm8750.h" diff --git a/sound/soc/s3c24xx/ln2440sbc_alc650.c b/sound/soc/s3c24xx/ln2440sbc_alc650.c index 12c71482d25..d00d359a03e 100644 --- a/sound/soc/s3c24xx/ln2440sbc_alc650.c +++ b/sound/soc/s3c24xx/ln2440sbc_alc650.c @@ -24,7 +24,7 @@ #include #include "../codecs/ac97.h" -#include "s3c24xx-pcm.h" +#include "s3c-dma.h" #include "s3c24xx-ac97.h" static struct snd_soc_card ln2440sbc; diff --git a/sound/soc/s3c24xx/neo1973_gta02_wm8753.c b/sound/soc/s3c24xx/neo1973_gta02_wm8753.c index 26409a9cef9..dea83d30a5c 100644 --- a/sound/soc/s3c24xx/neo1973_gta02_wm8753.c +++ b/sound/soc/s3c24xx/neo1973_gta02_wm8753.c @@ -32,7 +32,7 @@ #include #include #include "../codecs/wm8753.h" -#include "s3c24xx-pcm.h" +#include "s3c-dma.h" #include "s3c24xx-i2s.h" static struct snd_soc_card neo1973_gta02; diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c index 77de6c5127d..0cb4f86f6d1 100644 --- a/sound/soc/s3c24xx/neo1973_wm8753.c +++ b/sound/soc/s3c24xx/neo1973_wm8753.c @@ -36,7 +36,7 @@ #include "../codecs/wm8753.h" #include "lm4857.h" -#include "s3c24xx-pcm.h" +#include "s3c-dma.h" #include "s3c24xx-i2s.h" /* define the scenarios */ diff --git a/sound/soc/s3c24xx/s3c-dma.c b/sound/soc/s3c24xx/s3c-dma.c new file mode 100644 index 00000000000..7725e26d6c9 --- /dev/null +++ b/sound/soc/s3c24xx/s3c-dma.c @@ -0,0 +1,481 @@ +/* + * s3c-dma.c -- ALSA Soc Audio Layer + * + * (c) 2006 Wolfson Microelectronics PLC. + * Graeme Gregory graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com + * + * Copyright 2004-2005 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * Ben Dooks + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include "s3c-dma.h" + +static const struct snd_pcm_hardware s3c_dma_hardware = { + .info = SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_RESUME, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_U16_LE | + SNDRV_PCM_FMTBIT_U8 | + SNDRV_PCM_FMTBIT_S8, + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = 128*1024, + .period_bytes_min = PAGE_SIZE, + .period_bytes_max = PAGE_SIZE*2, + .periods_min = 2, + .periods_max = 128, + .fifo_size = 32, +}; + +struct s3c24xx_runtime_data { + spinlock_t lock; + int state; + unsigned int dma_loaded; + unsigned int dma_limit; + unsigned int dma_period; + dma_addr_t dma_start; + dma_addr_t dma_pos; + dma_addr_t dma_end; + struct s3c_dma_params *params; +}; + +/* s3c_dma_enqueue + * + * place a dma buffer onto the queue for the dma system + * to handle. +*/ +static void s3c_dma_enqueue(struct snd_pcm_substream *substream) +{ + struct s3c24xx_runtime_data *prtd = substream->runtime->private_data; + dma_addr_t pos = prtd->dma_pos; + unsigned int limit; + int ret; + + pr_debug("Entered %s\n", __func__); + + if (s3c_dma_has_circular()) + limit = (prtd->dma_end - prtd->dma_start) / prtd->dma_period; + else + limit = prtd->dma_limit; + + pr_debug("%s: loaded %d, limit %d\n", + __func__, prtd->dma_loaded, limit); + + while (prtd->dma_loaded < limit) { + unsigned long len = prtd->dma_period; + + pr_debug("dma_loaded: %d\n", prtd->dma_loaded); + + if ((pos + len) > prtd->dma_end) { + len = prtd->dma_end - pos; + pr_debug(KERN_DEBUG "%s: corrected dma len %ld\n", + __func__, len); + } + + ret = s3c2410_dma_enqueue(prtd->params->channel, + substream, pos, len); + + if (ret == 0) { + prtd->dma_loaded++; + pos += prtd->dma_period; + if (pos >= prtd->dma_end) + pos = prtd->dma_start; + } else + break; + } + + prtd->dma_pos = pos; +} + +static void s3c24xx_audio_buffdone(struct s3c2410_dma_chan *channel, + void *dev_id, int size, + enum s3c2410_dma_buffresult result) +{ + struct snd_pcm_substream *substream = dev_id; + struct s3c24xx_runtime_data *prtd; + + pr_debug("Entered %s\n", __func__); + + if (result == S3C2410_RES_ABORT || result == S3C2410_RES_ERR) + return; + + prtd = substream->runtime->private_data; + + if (substream) + snd_pcm_period_elapsed(substream); + + spin_lock(&prtd->lock); + if (prtd->state & ST_RUNNING && !s3c_dma_has_circular()) { + prtd->dma_loaded--; + s3c_dma_enqueue(substream); + } + + spin_unlock(&prtd->lock); +} + +static int s3c_dma_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct s3c24xx_runtime_data *prtd = runtime->private_data; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct s3c_dma_params *dma = rtd->dai->cpu_dai->dma_data; + unsigned long totbytes = params_buffer_bytes(params); + int ret = 0; + + pr_debug("Entered %s\n", __func__); + + /* return if this is a bufferless transfer e.g. + * codec <--> BT codec or GSM modem -- lg FIXME */ + if (!dma) + return 0; + + /* this may get called several times by oss emulation + * with different params -HW */ + if (prtd->params == NULL) { + /* prepare DMA */ + prtd->params = dma; + + pr_debug("params %p, client %p, channel %d\n", prtd->params, + prtd->params->client, prtd->params->channel); + + ret = s3c2410_dma_request(prtd->params->channel, + prtd->params->client, NULL); + + if (ret < 0) { + printk(KERN_ERR "failed to get dma channel\n"); + return ret; + } + + /* use the circular buffering if we have it available. */ + if (s3c_dma_has_circular()) + s3c2410_dma_setflags(prtd->params->channel, + S3C2410_DMAF_CIRCULAR); + } + + s3c2410_dma_set_buffdone_fn(prtd->params->channel, + s3c24xx_audio_buffdone); + + snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); + + runtime->dma_bytes = totbytes; + + spin_lock_irq(&prtd->lock); + prtd->dma_loaded = 0; + prtd->dma_limit = runtime->hw.periods_min; + prtd->dma_period = params_period_bytes(params); + prtd->dma_start = runtime->dma_addr; + prtd->dma_pos = prtd->dma_start; + prtd->dma_end = prtd->dma_start + totbytes; + spin_unlock_irq(&prtd->lock); + + return 0; +} + +static int s3c_dma_hw_free(struct snd_pcm_substream *substream) +{ + struct s3c24xx_runtime_data *prtd = substream->runtime->private_data; + + pr_debug("Entered %s\n", __func__); + + /* TODO - do we need to ensure DMA flushed */ + snd_pcm_set_runtime_buffer(substream, NULL); + + if (prtd->params) { + s3c2410_dma_free(prtd->params->channel, prtd->params->client); + prtd->params = NULL; + } + + return 0; +} + +static int s3c_dma_prepare(struct snd_pcm_substream *substream) +{ + struct s3c24xx_runtime_data *prtd = substream->runtime->private_data; + int ret = 0; + + pr_debug("Entered %s\n", __func__); + + /* return if this is a bufferless transfer e.g. + * codec <--> BT codec or GSM modem -- lg FIXME */ + if (!prtd->params) + return 0; + + /* channel needs configuring for mem=>device, increment memory addr, + * sync to pclk, half-word transfers to the IIS-FIFO. */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + s3c2410_dma_devconfig(prtd->params->channel, + S3C2410_DMASRC_MEM, + prtd->params->dma_addr); + } else { + s3c2410_dma_devconfig(prtd->params->channel, + S3C2410_DMASRC_HW, + prtd->params->dma_addr); + } + + s3c2410_dma_config(prtd->params->channel, + prtd->params->dma_size); + + /* flush the DMA channel */ + s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_FLUSH); + prtd->dma_loaded = 0; + prtd->dma_pos = prtd->dma_start; + + /* enqueue dma buffers */ + s3c_dma_enqueue(substream); + + return ret; +} + +static int s3c_dma_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct s3c24xx_runtime_data *prtd = substream->runtime->private_data; + int ret = 0; + + pr_debug("Entered %s\n", __func__); + + spin_lock(&prtd->lock); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + prtd->state |= ST_RUNNING; + s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_START); + break; + + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + prtd->state &= ~ST_RUNNING; + s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_STOP); + break; + + default: + ret = -EINVAL; + break; + } + + spin_unlock(&prtd->lock); + + return ret; +} + +static snd_pcm_uframes_t +s3c_dma_pointer(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct s3c24xx_runtime_data *prtd = runtime->private_data; + unsigned long res; + dma_addr_t src, dst; + + pr_debug("Entered %s\n", __func__); + + spin_lock(&prtd->lock); + s3c2410_dma_getposition(prtd->params->channel, &src, &dst); + + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) + res = dst - prtd->dma_start; + else + res = src - prtd->dma_start; + + spin_unlock(&prtd->lock); + + pr_debug("Pointer %x %x\n", src, dst); + + /* we seem to be getting the odd error from the pcm library due + * to out-of-bounds pointers. this is maybe due to the dma engine + * not having loaded the new values for the channel before being + * callled... (todo - fix ) + */ + + if (res >= snd_pcm_lib_buffer_bytes(substream)) { + if (res == snd_pcm_lib_buffer_bytes(substream)) + res = 0; + } + + return bytes_to_frames(substream->runtime, res); +} + +static int s3c_dma_open(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct s3c24xx_runtime_data *prtd; + + pr_debug("Entered %s\n", __func__); + + snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + snd_soc_set_runtime_hwparams(substream, &s3c_dma_hardware); + + prtd = kzalloc(sizeof(struct s3c24xx_runtime_data), GFP_KERNEL); + if (prtd == NULL) + return -ENOMEM; + + spin_lock_init(&prtd->lock); + + runtime->private_data = prtd; + return 0; +} + +static int s3c_dma_close(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct s3c24xx_runtime_data *prtd = runtime->private_data; + + pr_debug("Entered %s\n", __func__); + + if (!prtd) + pr_debug("s3c_dma_close called with prtd == NULL\n"); + + kfree(prtd); + + return 0; +} + +static int s3c_dma_mmap(struct snd_pcm_substream *substream, + struct vm_area_struct *vma) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + pr_debug("Entered %s\n", __func__); + + return dma_mmap_writecombine(substream->pcm->card->dev, vma, + runtime->dma_area, + runtime->dma_addr, + runtime->dma_bytes); +} + +static struct snd_pcm_ops s3c_dma_ops = { + .open = s3c_dma_open, + .close = s3c_dma_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = s3c_dma_hw_params, + .hw_free = s3c_dma_hw_free, + .prepare = s3c_dma_prepare, + .trigger = s3c_dma_trigger, + .pointer = s3c_dma_pointer, + .mmap = s3c_dma_mmap, +}; + +static int s3c_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) +{ + struct snd_pcm_substream *substream = pcm->streams[stream].substream; + struct snd_dma_buffer *buf = &substream->dma_buffer; + size_t size = s3c_dma_hardware.buffer_bytes_max; + + pr_debug("Entered %s\n", __func__); + + buf->dev.type = SNDRV_DMA_TYPE_DEV; + buf->dev.dev = pcm->card->dev; + buf->private_data = NULL; + buf->area = dma_alloc_writecombine(pcm->card->dev, size, + &buf->addr, GFP_KERNEL); + if (!buf->area) + return -ENOMEM; + buf->bytes = size; + return 0; +} + +static void s3c_dma_free_dma_buffers(struct snd_pcm *pcm) +{ + struct snd_pcm_substream *substream; + struct snd_dma_buffer *buf; + int stream; + + pr_debug("Entered %s\n", __func__); + + for (stream = 0; stream < 2; stream++) { + substream = pcm->streams[stream].substream; + if (!substream) + continue; + + buf = &substream->dma_buffer; + if (!buf->area) + continue; + + dma_free_writecombine(pcm->card->dev, buf->bytes, + buf->area, buf->addr); + buf->area = NULL; + } +} + +static u64 s3c_dma_mask = DMA_BIT_MASK(32); + +static int s3c_dma_new(struct snd_card *card, + struct snd_soc_dai *dai, struct snd_pcm *pcm) +{ + int ret = 0; + + pr_debug("Entered %s\n", __func__); + + if (!card->dev->dma_mask) + card->dev->dma_mask = &s3c_dma_mask; + if (!card->dev->coherent_dma_mask) + card->dev->coherent_dma_mask = 0xffffffff; + + if (dai->playback.channels_min) { + ret = s3c_preallocate_dma_buffer(pcm, + SNDRV_PCM_STREAM_PLAYBACK); + if (ret) + goto out; + } + + if (dai->capture.channels_min) { + ret = s3c_preallocate_dma_buffer(pcm, + SNDRV_PCM_STREAM_CAPTURE); + if (ret) + goto out; + } + out: + return ret; +} + +struct snd_soc_platform s3c24xx_soc_platform = { + .name = "s3c24xx-audio", + .pcm_ops = &s3c_dma_ops, + .pcm_new = s3c_dma_new, + .pcm_free = s3c_dma_free_dma_buffers, +}; +EXPORT_SYMBOL_GPL(s3c24xx_soc_platform); + +static int __init s3c24xx_soc_platform_init(void) +{ + return snd_soc_register_platform(&s3c24xx_soc_platform); +} +module_init(s3c24xx_soc_platform_init); + +static void __exit s3c24xx_soc_platform_exit(void) +{ + snd_soc_unregister_platform(&s3c24xx_soc_platform); +} +module_exit(s3c24xx_soc_platform_exit); + +MODULE_AUTHOR("Ben Dooks, "); +MODULE_DESCRIPTION("Samsung S3C Audio DMA module"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/s3c24xx/s3c-dma.h b/sound/soc/s3c24xx/s3c-dma.h new file mode 100644 index 00000000000..69bb6bf6fc1 --- /dev/null +++ b/sound/soc/s3c24xx/s3c-dma.h @@ -0,0 +1,31 @@ +/* + * s3c-dma.h -- + * + * 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. + * + * ALSA PCM interface for the Samsung S3C24xx CPU + */ + +#ifndef _S3C_AUDIO_H +#define _S3C_AUDIO_H + +#define ST_RUNNING (1<<0) +#define ST_OPENED (1<<1) + +struct s3c_dma_params { + struct s3c2410_dma_client *client; /* stream identifier */ + int channel; /* Channel ID */ + dma_addr_t dma_addr; + int dma_size; /* Size of the DMA transfer */ +}; + +#define S3C24XX_DAI_I2S 0 + +/* platform data */ +extern struct snd_soc_platform s3c24xx_soc_platform; +extern struct snd_ac97_bus_ops s3c24xx_ac97_ops; + +#endif diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.c b/sound/soc/s3c24xx/s3c-i2s-v2.c index 5a442aa8b87..e994d8374fe 100644 --- a/sound/soc/s3c24xx/s3c-i2s-v2.c +++ b/sound/soc/s3c24xx/s3c-i2s-v2.c @@ -35,7 +35,7 @@ #include #include "s3c-i2s-v2.h" -#include "s3c24xx-pcm.h" +#include "s3c-dma.h" #undef S3C_IIS_V2_SUPPORTED diff --git a/sound/soc/s3c24xx/s3c2412-i2s.c b/sound/soc/s3c24xx/s3c2412-i2s.c index 23718ea8518..359e59346ba 100644 --- a/sound/soc/s3c24xx/s3c2412-i2s.c +++ b/sound/soc/s3c24xx/s3c2412-i2s.c @@ -37,7 +37,7 @@ #include #include -#include "s3c24xx-pcm.h" +#include "s3c-dma.h" #include "s3c2412-i2s.h" #define S3C2412_I2S_DEBUG 0 diff --git a/sound/soc/s3c24xx/s3c2443-ac97.c b/sound/soc/s3c24xx/s3c2443-ac97.c index 678b1763160..0191e3acb0b 100644 --- a/sound/soc/s3c24xx/s3c2443-ac97.c +++ b/sound/soc/s3c24xx/s3c2443-ac97.c @@ -35,7 +35,7 @@ #include #include -#include "s3c24xx-pcm.h" +#include "s3c-dma.h" #include "s3c24xx-ac97.h" struct s3c24xx_ac97_info { diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.c b/sound/soc/s3c24xx/s3c24xx-i2s.c index afb4bc9033c..0bc5950b9f0 100644 --- a/sound/soc/s3c24xx/s3c24xx-i2s.c +++ b/sound/soc/s3c24xx/s3c24xx-i2s.c @@ -38,7 +38,7 @@ #include -#include "s3c24xx-pcm.h" +#include "s3c-dma.h" #include "s3c24xx-i2s.h" static struct s3c2410_dma_client s3c24xx_dma_client_out = { diff --git a/sound/soc/s3c24xx/s3c24xx-pcm.c b/sound/soc/s3c24xx/s3c24xx-pcm.c deleted file mode 100644 index cb49400d8c5..00000000000 --- a/sound/soc/s3c24xx/s3c24xx-pcm.c +++ /dev/null @@ -1,480 +0,0 @@ -/* - * s3c24xx-pcm.c -- ALSA Soc Audio Layer - * - * (c) 2006 Wolfson Microelectronics PLC. - * Graeme Gregory graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com - * - * Copyright 2004-2005 Simtec Electronics - * http://armlinux.simtec.co.uk/ - * Ben Dooks - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -#include "s3c24xx-pcm.h" - -static const struct snd_pcm_hardware s3c_dma_hardware = { - .info = SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_RESUME, - .formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_U16_LE | - SNDRV_PCM_FMTBIT_U8 | - SNDRV_PCM_FMTBIT_S8, - .channels_min = 2, - .channels_max = 2, - .buffer_bytes_max = 128*1024, - .period_bytes_min = PAGE_SIZE, - .period_bytes_max = PAGE_SIZE*2, - .periods_min = 2, - .periods_max = 128, - .fifo_size = 32, -}; - -struct s3c24xx_runtime_data { - spinlock_t lock; - int state; - unsigned int dma_loaded; - unsigned int dma_limit; - unsigned int dma_period; - dma_addr_t dma_start; - dma_addr_t dma_pos; - dma_addr_t dma_end; - struct s3c_dma_params *params; -}; - -/* s3c_dma_enqueue - * - * place a dma buffer onto the queue for the dma system - * to handle. -*/ -static void s3c_dma_enqueue(struct snd_pcm_substream *substream) -{ - struct s3c24xx_runtime_data *prtd = substream->runtime->private_data; - dma_addr_t pos = prtd->dma_pos; - unsigned int limit; - int ret; - - pr_debug("Entered %s\n", __func__); - - if (s3c_dma_has_circular()) { - limit = (prtd->dma_end - prtd->dma_start) / prtd->dma_period; - } else - limit = prtd->dma_limit; - - pr_debug("%s: loaded %d, limit %d\n", __func__, prtd->dma_loaded, limit); - - while (prtd->dma_loaded < limit) { - unsigned long len = prtd->dma_period; - - pr_debug("dma_loaded: %d\n", prtd->dma_loaded); - - if ((pos + len) > prtd->dma_end) { - len = prtd->dma_end - pos; - pr_debug(KERN_DEBUG "%s: corrected dma len %ld\n", - __func__, len); - } - - ret = s3c2410_dma_enqueue(prtd->params->channel, - substream, pos, len); - - if (ret == 0) { - prtd->dma_loaded++; - pos += prtd->dma_period; - if (pos >= prtd->dma_end) - pos = prtd->dma_start; - } else - break; - } - - prtd->dma_pos = pos; -} - -static void s3c24xx_audio_buffdone(struct s3c2410_dma_chan *channel, - void *dev_id, int size, - enum s3c2410_dma_buffresult result) -{ - struct snd_pcm_substream *substream = dev_id; - struct s3c24xx_runtime_data *prtd; - - pr_debug("Entered %s\n", __func__); - - if (result == S3C2410_RES_ABORT || result == S3C2410_RES_ERR) - return; - - prtd = substream->runtime->private_data; - - if (substream) - snd_pcm_period_elapsed(substream); - - spin_lock(&prtd->lock); - if (prtd->state & ST_RUNNING && !s3c_dma_has_circular()) { - prtd->dma_loaded--; - s3c_dma_enqueue(substream); - } - - spin_unlock(&prtd->lock); -} - -static int s3c_dma_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct s3c24xx_runtime_data *prtd = runtime->private_data; - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct s3c_dma_params *dma = rtd->dai->cpu_dai->dma_data; - unsigned long totbytes = params_buffer_bytes(params); - int ret = 0; - - pr_debug("Entered %s\n", __func__); - - /* return if this is a bufferless transfer e.g. - * codec <--> BT codec or GSM modem -- lg FIXME */ - if (!dma) - return 0; - - /* this may get called several times by oss emulation - * with different params -HW */ - if (prtd->params == NULL) { - /* prepare DMA */ - prtd->params = dma; - - pr_debug("params %p, client %p, channel %d\n", prtd->params, - prtd->params->client, prtd->params->channel); - - ret = s3c2410_dma_request(prtd->params->channel, - prtd->params->client, NULL); - - if (ret < 0) { - printk(KERN_ERR "failed to get dma channel\n"); - return ret; - } - - /* use the circular buffering if we have it available. */ - if (s3c_dma_has_circular()) - s3c2410_dma_setflags(prtd->params->channel, - S3C2410_DMAF_CIRCULAR); - } - - s3c2410_dma_set_buffdone_fn(prtd->params->channel, - s3c24xx_audio_buffdone); - - snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); - - runtime->dma_bytes = totbytes; - - spin_lock_irq(&prtd->lock); - prtd->dma_loaded = 0; - prtd->dma_limit = runtime->hw.periods_min; - prtd->dma_period = params_period_bytes(params); - prtd->dma_start = runtime->dma_addr; - prtd->dma_pos = prtd->dma_start; - prtd->dma_end = prtd->dma_start + totbytes; - spin_unlock_irq(&prtd->lock); - - return 0; -} - -static int s3c_dma_hw_free(struct snd_pcm_substream *substream) -{ - struct s3c24xx_runtime_data *prtd = substream->runtime->private_data; - - pr_debug("Entered %s\n", __func__); - - /* TODO - do we need to ensure DMA flushed */ - snd_pcm_set_runtime_buffer(substream, NULL); - - if (prtd->params) { - s3c2410_dma_free(prtd->params->channel, prtd->params->client); - prtd->params = NULL; - } - - return 0; -} - -static int s3c_dma_prepare(struct snd_pcm_substream *substream) -{ - struct s3c24xx_runtime_data *prtd = substream->runtime->private_data; - int ret = 0; - - pr_debug("Entered %s\n", __func__); - - /* return if this is a bufferless transfer e.g. - * codec <--> BT codec or GSM modem -- lg FIXME */ - if (!prtd->params) - return 0; - - /* channel needs configuring for mem=>device, increment memory addr, - * sync to pclk, half-word transfers to the IIS-FIFO. */ - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - s3c2410_dma_devconfig(prtd->params->channel, - S3C2410_DMASRC_MEM, - prtd->params->dma_addr); - } else { - s3c2410_dma_devconfig(prtd->params->channel, - S3C2410_DMASRC_HW, - prtd->params->dma_addr); - } - - s3c2410_dma_config(prtd->params->channel, - prtd->params->dma_size); - - /* flush the DMA channel */ - s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_FLUSH); - prtd->dma_loaded = 0; - prtd->dma_pos = prtd->dma_start; - - /* enqueue dma buffers */ - s3c_dma_enqueue(substream); - - return ret; -} - -static int s3c_dma_trigger(struct snd_pcm_substream *substream, int cmd) -{ - struct s3c24xx_runtime_data *prtd = substream->runtime->private_data; - int ret = 0; - - pr_debug("Entered %s\n", __func__); - - spin_lock(&prtd->lock); - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - prtd->state |= ST_RUNNING; - s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_START); - break; - - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - prtd->state &= ~ST_RUNNING; - s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_STOP); - break; - - default: - ret = -EINVAL; - break; - } - - spin_unlock(&prtd->lock); - - return ret; -} - -static snd_pcm_uframes_t -s3c_dma_pointer(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct s3c24xx_runtime_data *prtd = runtime->private_data; - unsigned long res; - dma_addr_t src, dst; - - pr_debug("Entered %s\n", __func__); - - spin_lock(&prtd->lock); - s3c2410_dma_getposition(prtd->params->channel, &src, &dst); - - if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) - res = dst - prtd->dma_start; - else - res = src - prtd->dma_start; - - spin_unlock(&prtd->lock); - - pr_debug("Pointer %x %x\n", src, dst); - - /* we seem to be getting the odd error from the pcm library due - * to out-of-bounds pointers. this is maybe due to the dma engine - * not having loaded the new values for the channel before being - * callled... (todo - fix ) - */ - - if (res >= snd_pcm_lib_buffer_bytes(substream)) { - if (res == snd_pcm_lib_buffer_bytes(substream)) - res = 0; - } - - return bytes_to_frames(substream->runtime, res); -} - -static int s3c_dma_open(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct s3c24xx_runtime_data *prtd; - - pr_debug("Entered %s\n", __func__); - - snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); - snd_soc_set_runtime_hwparams(substream, &s3c_dma_hardware); - - prtd = kzalloc(sizeof(struct s3c24xx_runtime_data), GFP_KERNEL); - if (prtd == NULL) - return -ENOMEM; - - spin_lock_init(&prtd->lock); - - runtime->private_data = prtd; - return 0; -} - -static int s3c_dma_close(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct s3c24xx_runtime_data *prtd = runtime->private_data; - - pr_debug("Entered %s\n", __func__); - - if (!prtd) - pr_debug("s3c_dma_close called with prtd == NULL\n"); - - kfree(prtd); - - return 0; -} - -static int s3c_dma_mmap(struct snd_pcm_substream *substream, - struct vm_area_struct *vma) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - pr_debug("Entered %s\n", __func__); - - return dma_mmap_writecombine(substream->pcm->card->dev, vma, - runtime->dma_area, - runtime->dma_addr, - runtime->dma_bytes); -} - -static struct snd_pcm_ops s3c_dma_ops = { - .open = s3c_dma_open, - .close = s3c_dma_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = s3c_dma_hw_params, - .hw_free = s3c_dma_hw_free, - .prepare = s3c_dma_prepare, - .trigger = s3c_dma_trigger, - .pointer = s3c_dma_pointer, - .mmap = s3c_dma_mmap, -}; - -static int s3c_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) -{ - struct snd_pcm_substream *substream = pcm->streams[stream].substream; - struct snd_dma_buffer *buf = &substream->dma_buffer; - size_t size = s3c_dma_hardware.buffer_bytes_max; - - pr_debug("Entered %s\n", __func__); - - buf->dev.type = SNDRV_DMA_TYPE_DEV; - buf->dev.dev = pcm->card->dev; - buf->private_data = NULL; - buf->area = dma_alloc_writecombine(pcm->card->dev, size, - &buf->addr, GFP_KERNEL); - if (!buf->area) - return -ENOMEM; - buf->bytes = size; - return 0; -} - -static void s3c_dma_free_dma_buffers(struct snd_pcm *pcm) -{ - struct snd_pcm_substream *substream; - struct snd_dma_buffer *buf; - int stream; - - pr_debug("Entered %s\n", __func__); - - for (stream = 0; stream < 2; stream++) { - substream = pcm->streams[stream].substream; - if (!substream) - continue; - - buf = &substream->dma_buffer; - if (!buf->area) - continue; - - dma_free_writecombine(pcm->card->dev, buf->bytes, - buf->area, buf->addr); - buf->area = NULL; - } -} - -static u64 s3c_dma_mask = DMA_BIT_MASK(32); - -static int s3c_dma_new(struct snd_card *card, - struct snd_soc_dai *dai, struct snd_pcm *pcm) -{ - int ret = 0; - - pr_debug("Entered %s\n", __func__); - - if (!card->dev->dma_mask) - card->dev->dma_mask = &s3c_dma_mask; - if (!card->dev->coherent_dma_mask) - card->dev->coherent_dma_mask = 0xffffffff; - - if (dai->playback.channels_min) { - ret = s3c_preallocate_dma_buffer(pcm, - SNDRV_PCM_STREAM_PLAYBACK); - if (ret) - goto out; - } - - if (dai->capture.channels_min) { - ret = s3c_preallocate_dma_buffer(pcm, - SNDRV_PCM_STREAM_CAPTURE); - if (ret) - goto out; - } - out: - return ret; -} - -struct snd_soc_platform s3c24xx_soc_platform = { - .name = "s3c24xx-audio", - .pcm_ops = &s3c_dma_ops, - .pcm_new = s3c_dma_new, - .pcm_free = s3c_dma_free_dma_buffers, -}; -EXPORT_SYMBOL_GPL(s3c24xx_soc_platform); - -static int __init s3c24xx_soc_platform_init(void) -{ - return snd_soc_register_platform(&s3c24xx_soc_platform); -} -module_init(s3c24xx_soc_platform_init); - -static void __exit s3c24xx_soc_platform_exit(void) -{ - snd_soc_unregister_platform(&s3c24xx_soc_platform); -} -module_exit(s3c24xx_soc_platform_exit); - -MODULE_AUTHOR("Ben Dooks, "); -MODULE_DESCRIPTION("Samsung S3C Audio DMA module"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/s3c24xx/s3c24xx-pcm.h b/sound/soc/s3c24xx/s3c24xx-pcm.h deleted file mode 100644 index 8cbc071124c..00000000000 --- a/sound/soc/s3c24xx/s3c24xx-pcm.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * s3c24xx-pcm.h -- - * - * 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. - * - * ALSA PCM interface for the Samsung S3C24xx CPU - */ - -#ifndef _S3C_AUDIO_H -#define _S3C_AUDIO_H - -#define ST_RUNNING (1<<0) -#define ST_OPENED (1<<1) - -struct s3c_dma_params { - struct s3c2410_dma_client *client; /* stream identifier */ - int channel; /* Channel ID */ - dma_addr_t dma_addr; - int dma_size; /* Size of the DMA transfer */ -}; - -#define S3C24XX_DAI_I2S 0 - -/* platform data */ -extern struct snd_soc_platform s3c24xx_soc_platform; -extern struct snd_ac97_bus_ops s3c24xx_ac97_ops; - -#endif diff --git a/sound/soc/s3c24xx/s3c24xx_simtec.c b/sound/soc/s3c24xx/s3c24xx_simtec.c index 1966e0d5652..507b2ed5d58 100644 --- a/sound/soc/s3c24xx/s3c24xx_simtec.c +++ b/sound/soc/s3c24xx/s3c24xx_simtec.c @@ -21,7 +21,7 @@ #include -#include "s3c24xx-pcm.h" +#include "s3c-dma.h" #include "s3c24xx-i2s.h" #include "s3c24xx_simtec.h" diff --git a/sound/soc/s3c24xx/s3c24xx_simtec_hermes.c b/sound/soc/s3c24xx/s3c24xx_simtec_hermes.c index 8346bd96eaf..bdf8951af8e 100644 --- a/sound/soc/s3c24xx/s3c24xx_simtec_hermes.c +++ b/sound/soc/s3c24xx/s3c24xx_simtec_hermes.c @@ -18,7 +18,7 @@ #include -#include "s3c24xx-pcm.h" +#include "s3c-dma.h" #include "s3c24xx-i2s.h" #include "s3c24xx_simtec.h" diff --git a/sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c b/sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c index 25797e09617..185c0acb5ce 100644 --- a/sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c +++ b/sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c @@ -18,7 +18,7 @@ #include -#include "s3c24xx-pcm.h" +#include "s3c-dma.h" #include "s3c24xx-i2s.h" #include "s3c24xx_simtec.h" diff --git a/sound/soc/s3c24xx/s3c24xx_uda134x.c b/sound/soc/s3c24xx/s3c24xx_uda134x.c index c215d32d632..052d59659c2 100644 --- a/sound/soc/s3c24xx/s3c24xx_uda134x.c +++ b/sound/soc/s3c24xx/s3c24xx_uda134x.c @@ -24,7 +24,7 @@ #include -#include "s3c24xx-pcm.h" +#include "s3c-dma.h" #include "s3c24xx-i2s.h" #include "../codecs/uda134x.h" diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.c b/sound/soc/s3c24xx/s3c64xx-i2s.c index 719d63c27fd..cc7edb5f792 100644 --- a/sound/soc/s3c24xx/s3c64xx-i2s.c +++ b/sound/soc/s3c24xx/s3c64xx-i2s.c @@ -35,7 +35,7 @@ #include #include -#include "s3c24xx-pcm.h" +#include "s3c-dma.h" #include "s3c64xx-i2s.h" static struct s3c2410_dma_client s3c64xx_dma_client_out = { diff --git a/sound/soc/s3c24xx/smdk2443_wm9710.c b/sound/soc/s3c24xx/smdk2443_wm9710.c index a2a4f5323c1..12b783b12fc 100644 --- a/sound/soc/s3c24xx/smdk2443_wm9710.c +++ b/sound/soc/s3c24xx/smdk2443_wm9710.c @@ -20,7 +20,7 @@ #include #include "../codecs/ac97.h" -#include "s3c24xx-pcm.h" +#include "s3c-dma.h" #include "s3c24xx-ac97.h" static struct snd_soc_card smdk2443; diff --git a/sound/soc/s3c24xx/smdk64xx_wm8580.c b/sound/soc/s3c24xx/smdk64xx_wm8580.c index 216dd1e8e37..efe4901213a 100644 --- a/sound/soc/s3c24xx/smdk64xx_wm8580.c +++ b/sound/soc/s3c24xx/smdk64xx_wm8580.c @@ -19,7 +19,7 @@ #include #include "../codecs/wm8580.h" -#include "s3c24xx-pcm.h" +#include "s3c-dma.h" #include "s3c64xx-i2s.h" #define S3C64XX_I2S_V4 2 -- cgit v1.2.3 From 357a1db94ecc5b3d605574b164d288cd7dbf8dbd Mon Sep 17 00:00:00 2001 From: Jassi Brar Date: Tue, 17 Nov 2009 16:54:03 +0900 Subject: ASoC: Added the CPU driver for PCM controllers Signed-off-by: Jassi Brar Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/s3c24xx/Kconfig | 3 + sound/soc/s3c24xx/Makefile | 2 + sound/soc/s3c24xx/s3c-pcm.c | 552 ++++++++++++++++++++++++++++++++++++++++++++ sound/soc/s3c24xx/s3c-pcm.h | 123 ++++++++++ 4 files changed, 680 insertions(+) create mode 100644 sound/soc/s3c24xx/s3c-pcm.c create mode 100644 sound/soc/s3c24xx/s3c-pcm.h (limited to 'sound') diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig index d7912f1e462..b489f1ae103 100644 --- a/sound/soc/s3c24xx/Kconfig +++ b/sound/soc/s3c24xx/Kconfig @@ -24,6 +24,9 @@ config SND_S3C64XX_SOC_I2S select SND_S3C_I2SV2_SOC select S3C64XX_DMA +config SND_S3C_SOC_PCM + tristate + config SND_S3C2443_SOC_AC97 tristate select S3C2410_DMA diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile index ff0a10536ef..b744657733d 100644 --- a/sound/soc/s3c24xx/Makefile +++ b/sound/soc/s3c24xx/Makefile @@ -5,6 +5,7 @@ snd-soc-s3c2412-i2s-objs := s3c2412-i2s.o snd-soc-s3c64xx-i2s-objs := s3c64xx-i2s.o snd-soc-s3c2443-ac97-objs := s3c2443-ac97.o snd-soc-s3c-i2s-v2-objs := s3c-i2s-v2.o +snd-soc-s3c-pcm-objs := s3c-pcm.o obj-$(CONFIG_SND_S3C24XX_SOC) += snd-soc-s3c24xx.o obj-$(CONFIG_SND_S3C24XX_SOC_I2S) += snd-soc-s3c24xx-i2s.o @@ -12,6 +13,7 @@ obj-$(CONFIG_SND_S3C2443_SOC_AC97) += snd-soc-s3c2443-ac97.o obj-$(CONFIG_SND_S3C2412_SOC_I2S) += snd-soc-s3c2412-i2s.o obj-$(CONFIG_SND_S3C64XX_SOC_I2S) += snd-soc-s3c64xx-i2s.o obj-$(CONFIG_SND_S3C_I2SV2_SOC) += snd-soc-s3c-i2s-v2.o +obj-$(CONFIG_SND_S3C_SOC_PCM) += snd-soc-s3c-pcm.o # S3C24XX Machine Support snd-soc-jive-wm8750-objs := jive_wm8750.o diff --git a/sound/soc/s3c24xx/s3c-pcm.c b/sound/soc/s3c24xx/s3c-pcm.c new file mode 100644 index 00000000000..9e61a7c2d9a --- /dev/null +++ b/sound/soc/s3c24xx/s3c-pcm.c @@ -0,0 +1,552 @@ +/* sound/soc/s3c24xx/s3c-pcm.c + * + * ALSA SoC Audio Layer - S3C PCM-Controller driver + * + * Copyright (c) 2009 Samsung Electronics Co. Ltd + * Author: Jaswinder Singh + * based upon I2S drivers by Ben Dooks. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "s3c-dma.h" +#include "s3c-pcm.h" + +static struct s3c2410_dma_client s3c_pcm_dma_client_out = { + .name = "PCM Stereo out" +}; + +static struct s3c2410_dma_client s3c_pcm_dma_client_in = { + .name = "PCM Stereo in" +}; + +static struct s3c_dma_params s3c_pcm_stereo_out[] = { + [0] = { + .client = &s3c_pcm_dma_client_out, + .dma_size = 4, + }, + [1] = { + .client = &s3c_pcm_dma_client_out, + .dma_size = 4, + }, +}; + +static struct s3c_dma_params s3c_pcm_stereo_in[] = { + [0] = { + .client = &s3c_pcm_dma_client_in, + .dma_size = 4, + }, + [1] = { + .client = &s3c_pcm_dma_client_in, + .dma_size = 4, + }, +}; + +static struct s3c_pcm_info s3c_pcm[2]; + +static inline struct s3c_pcm_info *to_info(struct snd_soc_dai *cpu_dai) +{ + return cpu_dai->private_data; +} + +static void s3c_pcm_snd_txctrl(struct s3c_pcm_info *pcm, int on) +{ + void __iomem *regs = pcm->regs; + u32 ctl, clkctl; + + clkctl = readl(regs + S3C_PCM_CLKCTL); + ctl = readl(regs + S3C_PCM_CTL); + ctl &= ~(S3C_PCM_CTL_TXDIPSTICK_MASK + << S3C_PCM_CTL_TXDIPSTICK_SHIFT); + + if (on) { + ctl |= S3C_PCM_CTL_TXDMA_EN; + ctl |= S3C_PCM_CTL_TXFIFO_EN; + ctl |= S3C_PCM_CTL_ENABLE; + ctl |= (0x20<idleclk) + clkctl |= S3C_PCM_CLKCTL_SERCLK_EN; + } + } + + writel(clkctl, regs + S3C_PCM_CLKCTL); + writel(ctl, regs + S3C_PCM_CTL); +} + +static void s3c_pcm_snd_rxctrl(struct s3c_pcm_info *pcm, int on) +{ + void __iomem *regs = pcm->regs; + u32 ctl, clkctl; + + ctl = readl(regs + S3C_PCM_CTL); + clkctl = readl(regs + S3C_PCM_CLKCTL); + + if (on) { + ctl |= S3C_PCM_CTL_RXDMA_EN; + ctl |= S3C_PCM_CTL_RXFIFO_EN; + ctl |= S3C_PCM_CTL_ENABLE; + clkctl |= S3C_PCM_CLKCTL_SERCLK_EN; + } else { + ctl &= ~S3C_PCM_CTL_RXDMA_EN; + ctl &= ~S3C_PCM_CTL_RXFIFO_EN; + + if (!(ctl & S3C_PCM_CTL_TXFIFO_EN)) { + ctl &= ~S3C_PCM_CTL_ENABLE; + if (!pcm->idleclk) + clkctl |= S3C_PCM_CLKCTL_SERCLK_EN; + } + } + + writel(clkctl, regs + S3C_PCM_CLKCTL); + writel(ctl, regs + S3C_PCM_CTL); +} + +static int s3c_pcm_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct s3c_pcm_info *pcm = to_info(rtd->dai->cpu_dai); + unsigned long flags; + + dev_dbg(pcm->dev, "Entered %s\n", __func__); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + spin_lock_irqsave(&pcm->lock, flags); + + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) + s3c_pcm_snd_rxctrl(pcm, 1); + else + s3c_pcm_snd_txctrl(pcm, 1); + + spin_unlock_irqrestore(&pcm->lock, flags); + break; + + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + spin_lock_irqsave(&pcm->lock, flags); + + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) + s3c_pcm_snd_rxctrl(pcm, 0); + else + s3c_pcm_snd_txctrl(pcm, 0); + + spin_unlock_irqrestore(&pcm->lock, flags); + break; + + default: + return -EINVAL; + } + + return 0; +} + +static int s3c_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *socdai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai_link *dai = rtd->dai; + struct s3c_pcm_info *pcm = to_info(dai->cpu_dai); + void __iomem *regs = pcm->regs; + struct clk *clk; + int sclk_div, sync_div; + unsigned long flags; + u32 clkctl; + + dev_dbg(pcm->dev, "Entered %s\n", __func__); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + dai->cpu_dai->dma_data = pcm->dma_playback; + else + dai->cpu_dai->dma_data = pcm->dma_capture; + + /* Strictly check for sample size */ + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + break; + default: + return -EINVAL; + } + + spin_lock_irqsave(&pcm->lock, flags); + + /* Get hold of the PCMSOURCE_CLK */ + clkctl = readl(regs + S3C_PCM_CLKCTL); + if (clkctl & S3C_PCM_CLKCTL_SERCLKSEL_PCLK) + clk = pcm->pclk; + else + clk = pcm->cclk; + + /* Set the SCLK divider */ + sclk_div = clk_get_rate(clk) / pcm->sclk_per_fs / + params_rate(params) / 2 - 1; + + clkctl &= ~(S3C_PCM_CLKCTL_SCLKDIV_MASK + << S3C_PCM_CLKCTL_SCLKDIV_SHIFT); + clkctl |= ((sclk_div & S3C_PCM_CLKCTL_SCLKDIV_MASK) + << S3C_PCM_CLKCTL_SCLKDIV_SHIFT); + + /* Set the SYNC divider */ + sync_div = pcm->sclk_per_fs - 1; + + clkctl &= ~(S3C_PCM_CLKCTL_SYNCDIV_MASK + << S3C_PCM_CLKCTL_SYNCDIV_SHIFT); + clkctl |= ((sync_div & S3C_PCM_CLKCTL_SYNCDIV_MASK) + << S3C_PCM_CLKCTL_SYNCDIV_SHIFT); + + writel(clkctl, regs + S3C_PCM_CLKCTL); + + spin_unlock_irqrestore(&pcm->lock, flags); + + dev_dbg(pcm->dev, "PCMSOURCE_CLK-%lu SCLK=%ufs \ + SCLK_DIV=%d SYNC_DIV=%d\n", + clk_get_rate(clk), pcm->sclk_per_fs, + sclk_div, sync_div); + + return 0; +} + +static int s3c_pcm_set_fmt(struct snd_soc_dai *cpu_dai, + unsigned int fmt) +{ + struct s3c_pcm_info *pcm = to_info(cpu_dai); + void __iomem *regs = pcm->regs; + unsigned long flags; + int ret = 0; + u32 ctl; + + dev_dbg(pcm->dev, "Entered %s\n", __func__); + + spin_lock_irqsave(&pcm->lock, flags); + + ctl = readl(regs + S3C_PCM_CTL); + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + /* Nothing to do, NB_NF by default */ + break; + default: + dev_err(pcm->dev, "Unsupported clock inversion!\n"); + ret = -EINVAL; + goto exit; + } + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + /* Nothing to do, Master by default */ + break; + default: + dev_err(pcm->dev, "Unsupported master/slave format!\n"); + ret = -EINVAL; + goto exit; + } + + switch (fmt & SND_SOC_DAIFMT_CLOCK_MASK) { + case SND_SOC_DAIFMT_CONT: + pcm->idleclk = 1; + break; + case SND_SOC_DAIFMT_GATED: + pcm->idleclk = 0; + break; + default: + dev_err(pcm->dev, "Invalid Clock gating request!\n"); + ret = -EINVAL; + goto exit; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_A: + ctl |= S3C_PCM_CTL_TXMSB_AFTER_FSYNC; + ctl |= S3C_PCM_CTL_RXMSB_AFTER_FSYNC; + break; + case SND_SOC_DAIFMT_DSP_B: + ctl &= ~S3C_PCM_CTL_TXMSB_AFTER_FSYNC; + ctl &= ~S3C_PCM_CTL_RXMSB_AFTER_FSYNC; + break; + default: + dev_err(pcm->dev, "Unsupported data format!\n"); + ret = -EINVAL; + goto exit; + } + + writel(ctl, regs + S3C_PCM_CTL); + +exit: + spin_unlock_irqrestore(&pcm->lock, flags); + + return ret; +} + +static int s3c_pcm_set_clkdiv(struct snd_soc_dai *cpu_dai, + int div_id, int div) +{ + struct s3c_pcm_info *pcm = to_info(cpu_dai); + + switch (div_id) { + case S3C_PCM_SCLK_PER_FS: + pcm->sclk_per_fs = div; + break; + + default: + return -EINVAL; + } + + return 0; +} + +static int s3c_pcm_set_sysclk(struct snd_soc_dai *cpu_dai, + int clk_id, unsigned int freq, int dir) +{ + struct s3c_pcm_info *pcm = to_info(cpu_dai); + void __iomem *regs = pcm->regs; + u32 clkctl = readl(regs + S3C_PCM_CLKCTL); + + switch (clk_id) { + case S3C_PCM_CLKSRC_PCLK: + clkctl |= S3C_PCM_CLKCTL_SERCLKSEL_PCLK; + break; + + case S3C_PCM_CLKSRC_MUX: + clkctl &= ~S3C_PCM_CLKCTL_SERCLKSEL_PCLK; + + if (clk_get_rate(pcm->cclk) != freq) + clk_set_rate(pcm->cclk, freq); + + break; + + default: + return -EINVAL; + } + + writel(clkctl, regs + S3C_PCM_CLKCTL); + + return 0; +} + +static struct snd_soc_dai_ops s3c_pcm_dai_ops = { + .set_sysclk = s3c_pcm_set_sysclk, + .set_clkdiv = s3c_pcm_set_clkdiv, + .trigger = s3c_pcm_trigger, + .hw_params = s3c_pcm_hw_params, + .set_fmt = s3c_pcm_set_fmt, +}; + +#define S3C_PCM_RATES SNDRV_PCM_RATE_8000_96000 + +#define S3C_PCM_DECLARE(n) \ +{ \ + .name = "samsung-pcm", \ + .id = (n), \ + .symmetric_rates = 1, \ + .ops = &s3c_pcm_dai_ops, \ + .playback = { \ + .channels_min = 2, \ + .channels_max = 2, \ + .rates = S3C_PCM_RATES, \ + .formats = SNDRV_PCM_FMTBIT_S16_LE, \ + }, \ + .capture = { \ + .channels_min = 2, \ + .channels_max = 2, \ + .rates = S3C_PCM_RATES, \ + .formats = SNDRV_PCM_FMTBIT_S16_LE, \ + }, \ +} + +struct snd_soc_dai s3c_pcm_dai[] = { + S3C_PCM_DECLARE(0), + S3C_PCM_DECLARE(1), +}; +EXPORT_SYMBOL_GPL(s3c_pcm_dai); + +static __devinit int s3c_pcm_dev_probe(struct platform_device *pdev) +{ + struct s3c_pcm_info *pcm; + struct snd_soc_dai *dai; + struct resource *mem_res, *dmatx_res, *dmarx_res; + struct s3c_audio_pdata *pcm_pdata; + int ret; + + /* Check for valid device index */ + if ((pdev->id < 0) || pdev->id >= ARRAY_SIZE(s3c_pcm)) { + dev_err(&pdev->dev, "id %d out of range\n", pdev->id); + return -EINVAL; + } + + pcm_pdata = pdev->dev.platform_data; + + /* Check for availability of necessary resource */ + dmatx_res = platform_get_resource(pdev, IORESOURCE_DMA, 0); + if (!dmatx_res) { + dev_err(&pdev->dev, "Unable to get PCM-TX dma resource\n"); + return -ENXIO; + } + + dmarx_res = platform_get_resource(pdev, IORESOURCE_DMA, 1); + if (!dmarx_res) { + dev_err(&pdev->dev, "Unable to get PCM-RX dma resource\n"); + return -ENXIO; + } + + mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem_res) { + dev_err(&pdev->dev, "Unable to get register resource\n"); + return -ENXIO; + } + + if (pcm_pdata && pcm_pdata->cfg_gpio && pcm_pdata->cfg_gpio(pdev)) { + dev_err(&pdev->dev, "Unable to configure gpio\n"); + return -EINVAL; + } + + pcm = &s3c_pcm[pdev->id]; + pcm->dev = &pdev->dev; + + spin_lock_init(&pcm->lock); + + dai = &s3c_pcm_dai[pdev->id]; + dai->dev = &pdev->dev; + + /* Default is 128fs */ + pcm->sclk_per_fs = 128; + + pcm->cclk = clk_get(&pdev->dev, "audio-bus"); + if (IS_ERR(pcm->cclk)) { + dev_err(&pdev->dev, "failed to get audio-bus\n"); + ret = PTR_ERR(pcm->cclk); + goto err1; + } + clk_enable(pcm->cclk); + + /* record our pcm structure for later use in the callbacks */ + dai->private_data = pcm; + + if (!request_mem_region(mem_res->start, + resource_size(mem_res), "samsung-pcm")) { + dev_err(&pdev->dev, "Unable to request register region\n"); + ret = -EBUSY; + goto err2; + } + + pcm->regs = ioremap(mem_res->start, 0x100); + if (pcm->regs == NULL) { + dev_err(&pdev->dev, "cannot ioremap registers\n"); + ret = -ENXIO; + goto err3; + } + + pcm->pclk = clk_get(&pdev->dev, "pcm"); + if (IS_ERR(pcm->pclk)) { + dev_err(&pdev->dev, "failed to get pcm_clock\n"); + ret = -ENOENT; + goto err4; + } + clk_enable(pcm->pclk); + + ret = snd_soc_register_dai(dai); + if (ret != 0) { + dev_err(&pdev->dev, "failed to get pcm_clock\n"); + goto err5; + } + + s3c_pcm_stereo_in[pdev->id].dma_addr = mem_res->start + + S3C_PCM_RXFIFO; + s3c_pcm_stereo_out[pdev->id].dma_addr = mem_res->start + + S3C_PCM_TXFIFO; + + s3c_pcm_stereo_in[pdev->id].channel = dmarx_res->start; + s3c_pcm_stereo_out[pdev->id].channel = dmatx_res->start; + + pcm->dma_capture = &s3c_pcm_stereo_in[pdev->id]; + pcm->dma_playback = &s3c_pcm_stereo_out[pdev->id]; + + return 0; + +err5: + clk_disable(pcm->pclk); + clk_put(pcm->pclk); +err4: + iounmap(pcm->regs); +err3: + release_mem_region(mem_res->start, resource_size(mem_res)); +err2: + clk_disable(pcm->cclk); + clk_put(pcm->cclk); +err1: + return ret; +} + +static __devexit int s3c_pcm_dev_remove(struct platform_device *pdev) +{ + struct s3c_pcm_info *pcm = &s3c_pcm[pdev->id]; + struct resource *mem_res; + + iounmap(pcm->regs); + + mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(mem_res->start, resource_size(mem_res)); + + clk_disable(pcm->cclk); + clk_disable(pcm->pclk); + clk_put(pcm->pclk); + clk_put(pcm->cclk); + + return 0; +} + +static struct platform_driver s3c_pcm_driver = { + .probe = s3c_pcm_dev_probe, + .remove = s3c_pcm_dev_remove, + .driver = { + .name = "samsung-pcm", + .owner = THIS_MODULE, + }, +}; + +static int __init s3c_pcm_init(void) +{ + return platform_driver_register(&s3c_pcm_driver); +} +module_init(s3c_pcm_init); + +static void __exit s3c_pcm_exit(void) +{ + platform_driver_unregister(&s3c_pcm_driver); +} +module_exit(s3c_pcm_exit); + +/* Module information */ +MODULE_AUTHOR("Jaswinder Singh, "); +MODULE_DESCRIPTION("S3C PCM Controller Driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/s3c24xx/s3c-pcm.h b/sound/soc/s3c24xx/s3c-pcm.h new file mode 100644 index 00000000000..69ff9971692 --- /dev/null +++ b/sound/soc/s3c24xx/s3c-pcm.h @@ -0,0 +1,123 @@ +/* sound/soc/s3c24xx/s3c-pcm.h + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#ifndef __S3C_PCM_H +#define __S3C_PCM_H __FILE__ + +/*Register Offsets */ +#define S3C_PCM_CTL (0x00) +#define S3C_PCM_CLKCTL (0x04) +#define S3C_PCM_TXFIFO (0x08) +#define S3C_PCM_RXFIFO (0x0C) +#define S3C_PCM_IRQCTL (0x10) +#define S3C_PCM_IRQSTAT (0x14) +#define S3C_PCM_FIFOSTAT (0x18) +#define S3C_PCM_CLRINT (0x20) + +/* PCM_CTL Bit-Fields */ +#define S3C_PCM_CTL_TXDIPSTICK_MASK (0x3f) +#define S3C_PCM_CTL_TXDIPSTICK_SHIFT (13) +#define S3C_PCM_CTL_RXDIPSTICK_MSK (0x3f<<7) +#define S3C_PCM_CTL_TXDMA_EN (0x1<<6) +#define S3C_PCM_CTL_RXDMA_EN (0x1<<5) +#define S3C_PCM_CTL_TXMSB_AFTER_FSYNC (0x1<<4) +#define S3C_PCM_CTL_RXMSB_AFTER_FSYNC (0x1<<3) +#define S3C_PCM_CTL_TXFIFO_EN (0x1<<2) +#define S3C_PCM_CTL_RXFIFO_EN (0x1<<1) +#define S3C_PCM_CTL_ENABLE (0x1<<0) + +/* PCM_CLKCTL Bit-Fields */ +#define S3C_PCM_CLKCTL_SERCLK_EN (0x1<<19) +#define S3C_PCM_CLKCTL_SERCLKSEL_PCLK (0x1<<18) +#define S3C_PCM_CLKCTL_SCLKDIV_MASK (0x1ff) +#define S3C_PCM_CLKCTL_SYNCDIV_MASK (0x1ff) +#define S3C_PCM_CLKCTL_SCLKDIV_SHIFT (9) +#define S3C_PCM_CLKCTL_SYNCDIV_SHIFT (0) + +/* PCM_TXFIFO Bit-Fields */ +#define S3C_PCM_TXFIFO_DVALID (0x1<<16) +#define S3C_PCM_TXFIFO_DATA_MSK (0xffff<<0) + +/* PCM_RXFIFO Bit-Fields */ +#define S3C_PCM_RXFIFO_DVALID (0x1<<16) +#define S3C_PCM_RXFIFO_DATA_MSK (0xffff<<0) + +/* PCM_IRQCTL Bit-Fields */ +#define S3C_PCM_IRQCTL_IRQEN (0x1<<14) +#define S3C_PCM_IRQCTL_WRDEN (0x1<<12) +#define S3C_PCM_IRQCTL_TXEMPTYEN (0x1<<11) +#define S3C_PCM_IRQCTL_TXALMSTEMPTYEN (0x1<<10) +#define S3C_PCM_IRQCTL_TXFULLEN (0x1<<9) +#define S3C_PCM_IRQCTL_TXALMSTFULLEN (0x1<<8) +#define S3C_PCM_IRQCTL_TXSTARVEN (0x1<<7) +#define S3C_PCM_IRQCTL_TXERROVRFLEN (0x1<<6) +#define S3C_PCM_IRQCTL_RXEMPTEN (0x1<<5) +#define S3C_PCM_IRQCTL_RXALMSTEMPTEN (0x1<<4) +#define S3C_PCM_IRQCTL_RXFULLEN (0x1<<3) +#define S3C_PCM_IRQCTL_RXALMSTFULLEN (0x1<<2) +#define S3C_PCM_IRQCTL_RXSTARVEN (0x1<<1) +#define S3C_PCM_IRQCTL_RXERROVRFLEN (0x1<<0) + +/* PCM_IRQSTAT Bit-Fields */ +#define S3C_PCM_IRQSTAT_IRQPND (0x1<<13) +#define S3C_PCM_IRQSTAT_WRD_XFER (0x1<<12) +#define S3C_PCM_IRQSTAT_TXEMPTY (0x1<<11) +#define S3C_PCM_IRQSTAT_TXALMSTEMPTY (0x1<<10) +#define S3C_PCM_IRQSTAT_TXFULL (0x1<<9) +#define S3C_PCM_IRQSTAT_TXALMSTFULL (0x1<<8) +#define S3C_PCM_IRQSTAT_TXSTARV (0x1<<7) +#define S3C_PCM_IRQSTAT_TXERROVRFL (0x1<<6) +#define S3C_PCM_IRQSTAT_RXEMPT (0x1<<5) +#define S3C_PCM_IRQSTAT_RXALMSTEMPT (0x1<<4) +#define S3C_PCM_IRQSTAT_RXFULL (0x1<<3) +#define S3C_PCM_IRQSTAT_RXALMSTFULL (0x1<<2) +#define S3C_PCM_IRQSTAT_RXSTARV (0x1<<1) +#define S3C_PCM_IRQSTAT_RXERROVRFL (0x1<<0) + +/* PCM_FIFOSTAT Bit-Fields */ +#define S3C_PCM_FIFOSTAT_TXCNT_MSK (0x3f<<14) +#define S3C_PCM_FIFOSTAT_TXFIFOEMPTY (0x1<<13) +#define S3C_PCM_FIFOSTAT_TXFIFOALMSTEMPTY (0x1<<12) +#define S3C_PCM_FIFOSTAT_TXFIFOFULL (0x1<<11) +#define S3C_PCM_FIFOSTAT_TXFIFOALMSTFULL (0x1<<10) +#define S3C_PCM_FIFOSTAT_RXCNT_MSK (0x3f<<4) +#define S3C_PCM_FIFOSTAT_RXFIFOEMPTY (0x1<<3) +#define S3C_PCM_FIFOSTAT_RXFIFOALMSTEMPTY (0x1<<2) +#define S3C_PCM_FIFOSTAT_RXFIFOFULL (0x1<<1) +#define S3C_PCM_FIFOSTAT_RXFIFOALMSTFULL (0x1<<0) + +#define S3C_PCM_CLKSRC_PCLK 0 +#define S3C_PCM_CLKSRC_MUX 1 + +#define S3C_PCM_SCLK_PER_FS 0 + +/** + * struct s3c_pcm_info - S3C PCM Controller information + * @dev: The parent device passed to use from the probe. + * @regs: The pointer to the device register block. + * @dma_playback: DMA information for playback channel. + * @dma_capture: DMA information for capture channel. + */ +struct s3c_pcm_info { + spinlock_t lock; + struct device *dev; + void __iomem *regs; + + unsigned int sclk_per_fs; + + /* Whether to keep PCMSCLK enabled even when idle(no active xfer) */ + unsigned int idleclk; + + struct clk *pclk; + struct clk *cclk; + + struct s3c_dma_params *dma_playback; + struct s3c_dma_params *dma_capture; +}; + +#endif /* __S3C_PCM_H */ -- cgit v1.2.3 From 57512c6432783c9695ef54f875f705584c65c733 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Mon, 16 Nov 2009 16:52:31 -0700 Subject: ASoC: DaVinci: remove requirement that dma_params is 1st in structure Remove requirement that dma_params is 1st in the structures davinci_audio_dev and davinci_mcbsp_dev. Signed-off-by: Troy Kisky Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/davinci/davinci-i2s.c | 6 +----- sound/soc/davinci/davinci-mcasp.c | 1 + sound/soc/davinci/davinci-mcasp.h | 5 ----- sound/soc/davinci/davinci-pcm.c | 7 ++++--- 4 files changed, 6 insertions(+), 13 deletions(-) (limited to 'sound') diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index 2ab809359c0..d336786683b 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -98,11 +98,6 @@ enum { }; struct davinci_mcbsp_dev { - /* - * dma_params must be first because rtd->dai->cpu_dai->private_data - * is cast to a pointer of an array of struct davinci_pcm_dma_params in - * davinci_pcm_open. - */ struct davinci_pcm_dma_params dma_params[2]; void __iomem *base; #define MOD_DSP_A 0 @@ -549,6 +544,7 @@ static int davinci_i2s_probe(struct platform_device *pdev) dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].channel = res->start; davinci_i2s_dai.private_data = dev; + davinci_i2s_dai.dma_data = dev->dma_params; ret = snd_soc_register_dai(&davinci_i2s_dai); if (ret != 0) goto err_free_mem; diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index 50ad0519a8f..0a302e1080d 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -904,6 +904,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev) dma_data->channel = res->start; davinci_mcasp_dai[pdata->op_mode].private_data = dev; + davinci_mcasp_dai[pdata->op_mode].dma_data = dev->dma_params; davinci_mcasp_dai[pdata->op_mode].dev = &pdev->dev; ret = snd_soc_register_dai(&davinci_mcasp_dai[pdata->op_mode]); diff --git a/sound/soc/davinci/davinci-mcasp.h b/sound/soc/davinci/davinci-mcasp.h index 9d179cc88f7..582c9249ef0 100644 --- a/sound/soc/davinci/davinci-mcasp.h +++ b/sound/soc/davinci/davinci-mcasp.h @@ -39,11 +39,6 @@ enum { }; struct davinci_audio_dev { - /* - * dma_params must be first because rtd->dai->cpu_dai->private_data - * is cast to a pointer of an array of struct davinci_pcm_dma_params in - * davinci_pcm_open. - */ struct davinci_pcm_dma_params dma_params[2]; void __iomem *base; int sample_rate; diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c index fb10f1d63fd..187ee965bf0 100644 --- a/sound/soc/davinci/davinci-pcm.c +++ b/sound/soc/davinci/davinci-pcm.c @@ -253,10 +253,11 @@ static int davinci_pcm_open(struct snd_pcm_substream *substream) struct davinci_runtime_data *prtd; int ret = 0; struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct davinci_pcm_dma_params *pa = rtd->dai->cpu_dai->private_data; - struct davinci_pcm_dma_params *params = &pa[substream->stream]; - if (!params) + struct davinci_pcm_dma_params *pa = rtd->dai->cpu_dai->dma_data; + struct davinci_pcm_dma_params *params; + if (!pa) return -ENODEV; + params = &pa[substream->stream]; snd_soc_set_runtime_hwparams(substream, &davinci_pcm_hardware); /* ensure that buffer size is a multiple of period size */ -- cgit v1.2.3 From bd6ddcb41d5fbdcbc1486f48d8023f234b4a7f8d Mon Sep 17 00:00:00 2001 From: Anuj Aggarwal Date: Tue, 17 Nov 2009 21:43:42 +0530 Subject: ASoC: Modifying the license string GPLv2 for OMAP3 EVM Correcting the license string from GPLv2 -> GPL v2. Found the problem while building OMAP3 ASoC driver as module. Signed-off-by: Anuj Aggarwal Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/omap/omap3evm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/omap/omap3evm.c b/sound/soc/omap/omap3evm.c index 9114c263077..13aa380de16 100644 --- a/sound/soc/omap/omap3evm.c +++ b/sound/soc/omap/omap3evm.c @@ -144,4 +144,4 @@ module_exit(omap3evm_soc_exit); MODULE_AUTHOR("Anuj Aggarwal "); MODULE_DESCRIPTION("ALSA SoC OMAP3 EVM"); -MODULE_LICENSE("GPLv2"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From f3dd70414cdc0203ca63eef83ca130c2d1903b30 Mon Sep 17 00:00:00 2001 From: Grazvydas Ignotas Date: Sat, 7 Nov 2009 23:16:12 +0200 Subject: ASoC: OMAP3 Pandora: update for TWL4030 codec changes A while ago TWL4030 had it's playback stream name changed, but pandora needs it for it's playback path. Update to correct stream name so that playback works again. Also mark VIBRA output as not connected. Signed-off-by: Grazvydas Ignotas Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/omap/omap3pandora.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/omap/omap3pandora.c b/sound/soc/omap/omap3pandora.c index ad219aaf7cb..0cd06f5dd35 100644 --- a/sound/soc/omap/omap3pandora.c +++ b/sound/soc/omap/omap3pandora.c @@ -134,7 +134,7 @@ static int omap3pandora_hp_event(struct snd_soc_dapm_widget *w, * |P| <--- TWL4030 <--------- Line In and MICs */ static const struct snd_soc_dapm_widget omap3pandora_out_dapm_widgets[] = { - SND_SOC_DAPM_DAC("PCM DAC", "Playback", SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_DAC("PCM DAC", "HiFi Playback", SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_PGA_E("Headphone Amplifier", SND_SOC_NOPM, 0, 0, NULL, 0, omap3pandora_hp_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), @@ -181,6 +181,7 @@ static int omap3pandora_out_init(struct snd_soc_codec *codec) snd_soc_dapm_nc_pin(codec, "CARKITR"); snd_soc_dapm_nc_pin(codec, "HFL"); snd_soc_dapm_nc_pin(codec, "HFR"); + snd_soc_dapm_nc_pin(codec, "VIBRA"); ret = snd_soc_dapm_new_controls(codec, omap3pandora_out_dapm_widgets, ARRAY_SIZE(omap3pandora_out_dapm_widgets)); -- cgit v1.2.3 From bab0212467e58929470ae3ae32515f17e30c3926 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Tue, 17 Nov 2009 13:51:01 -0700 Subject: ASoC: tlv320aic23 fix rate selection Fix the ordering of sr_valid_mask array. The lower bit of the index represents USB not bosr. Reported-by: Anuj Aggarwal Signed-off-by: Troy Kisky Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic23.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c index 0b8dcb5cd72..6b24d8bb02b 100644 --- a/sound/soc/codecs/tlv320aic23.c +++ b/sound/soc/codecs/tlv320aic23.c @@ -265,8 +265,8 @@ static const int bosr_usb_divisor_table[] = { #define UPPER_GROUP ((1<<8) | (1<<9) | (1<<10) | (1<<11) | (1<<15)) static const unsigned short sr_valid_mask[] = { LOWER_GROUP|UPPER_GROUP, /* Normal, bosr - 0*/ - LOWER_GROUP|UPPER_GROUP, /* Normal, bosr - 1*/ LOWER_GROUP, /* Usb, bosr - 0*/ + LOWER_GROUP|UPPER_GROUP, /* Normal, bosr - 1*/ UPPER_GROUP, /* Usb, bosr - 1*/ }; /* -- cgit v1.2.3 From 0d6c97742993a00ee2cbfbd6d68fba669c17bf50 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Wed, 18 Nov 2009 17:49:51 -0700 Subject: ASoC: DaVinci: i2s, reduce underruns by combining into 1 element Allow the left and right 16 bit samples to be shifted out as 1 32 bit sample. Signed-off-by: Troy Kisky Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/davinci/davinci-i2s.c | 74 ++++++++++++++++++++++++++++++----------- 1 file changed, 55 insertions(+), 19 deletions(-) (limited to 'sound') diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index d336786683b..b2a5372ef72 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -97,6 +97,23 @@ enum { DAVINCI_MCBSP_WORD_32, }; +static const unsigned char data_type[SNDRV_PCM_FORMAT_S32_LE + 1] = { + [SNDRV_PCM_FORMAT_S8] = 1, + [SNDRV_PCM_FORMAT_S16_LE] = 2, + [SNDRV_PCM_FORMAT_S32_LE] = 4, +}; + +static const unsigned char asp_word_length[SNDRV_PCM_FORMAT_S32_LE + 1] = { + [SNDRV_PCM_FORMAT_S8] = DAVINCI_MCBSP_WORD_8, + [SNDRV_PCM_FORMAT_S16_LE] = DAVINCI_MCBSP_WORD_16, + [SNDRV_PCM_FORMAT_S32_LE] = DAVINCI_MCBSP_WORD_32, +}; + +static const unsigned char double_fmt[SNDRV_PCM_FORMAT_S32_LE + 1] = { + [SNDRV_PCM_FORMAT_S8] = SNDRV_PCM_FORMAT_S16_LE, + [SNDRV_PCM_FORMAT_S16_LE] = SNDRV_PCM_FORMAT_S32_LE, +}; + struct davinci_mcbsp_dev { struct davinci_pcm_dma_params dma_params[2]; void __iomem *base; @@ -105,6 +122,27 @@ struct davinci_mcbsp_dev { int mode; u32 pcr; struct clk *clk; + /* + * Combining both channels into 1 element will at least double the + * amount of time between servicing the dma channel, increase + * effiency, and reduce the chance of overrun/underrun. But, + * it will result in the left & right channels being swapped. + * + * If relabeling the left and right channels is not possible, + * you may want to let the codec know to swap them back. + * + * It may allow x10 the amount of time to service dma requests, + * if the codec is master and is using an unnecessarily fast bit clock + * (ie. tlvaic23b), independent of the sample rate. So, having an + * entire frame at once means it can be serviced at the sample rate + * instead of the bit clock rate. + * + * In the now unlikely case that an underrun still + * occurs, both the left and right samples will be repeated + * so that no pops are heard, and the left and right channels + * won't end up being swapped because of the underrun. + */ + unsigned enable_channel_combine:1; }; static inline void davinci_mcbsp_write_reg(struct davinci_mcbsp_dev *dev, @@ -344,6 +382,8 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, int mcbsp_word_length; unsigned int rcr, xcr, srgr; u32 spcr; + snd_pcm_format_t fmt; + unsigned element_cnt = 1; /* general line settings */ spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); @@ -373,29 +413,24 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, xcr |= DAVINCI_MCBSP_XCR_XDATDLY(1); } /* Determine xfer data type */ - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S8: - dma_params->data_type = 1; - mcbsp_word_length = DAVINCI_MCBSP_WORD_8; - break; - case SNDRV_PCM_FORMAT_S16_LE: - dma_params->data_type = 2; - mcbsp_word_length = DAVINCI_MCBSP_WORD_16; - break; - case SNDRV_PCM_FORMAT_S32_LE: - dma_params->data_type = 4; - mcbsp_word_length = DAVINCI_MCBSP_WORD_32; - break; - default: + fmt = params_format(params); + if ((fmt > SNDRV_PCM_FORMAT_S32_LE) || !data_type[fmt]) { printk(KERN_WARNING "davinci-i2s: unsupported PCM format\n"); return -EINVAL; } - dma_params->acnt = dma_params->data_type; + if (params_channels(params) == 2) { + element_cnt = 2; + if (double_fmt[fmt] && dev->enable_channel_combine) { + element_cnt = 1; + fmt = double_fmt[fmt]; + } + } + dma_params->acnt = dma_params->data_type = data_type[fmt]; dma_params->fifo_level = 0; - - rcr |= DAVINCI_MCBSP_RCR_RFRLEN1(1); - xcr |= DAVINCI_MCBSP_XCR_XFRLEN1(1); + mcbsp_word_length = asp_word_length[fmt]; + rcr |= DAVINCI_MCBSP_RCR_RFRLEN1(element_cnt - 1); + xcr |= DAVINCI_MCBSP_XCR_XFRLEN1(element_cnt - 1); rcr |= DAVINCI_MCBSP_RCR_RWDLEN1(mcbsp_word_length) | DAVINCI_MCBSP_RCR_RWDLEN2(mcbsp_word_length); @@ -510,7 +545,8 @@ static int davinci_i2s_probe(struct platform_device *pdev) ret = -ENOMEM; goto err_release_region; } - + if (pdata) + dev->enable_channel_combine = pdata->enable_channel_combine; dev->clk = clk_get(&pdev->dev, NULL); if (IS_ERR(dev->clk)) { ret = -ENODEV; -- cgit v1.2.3 From 1587ea31572e25a0a2c9c491b7f8c937b6c0454e Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Wed, 18 Nov 2009 17:49:52 -0700 Subject: ASoC: DaVinci: pcm, rename variables in prep for ping/pong Rename variable master_lch to asp_channel Rename variable slave_lch to asp_link[0] Rename local variables: lch to link count to asp_count src to asp_src dst to asp_dst Signed-off-by: Troy Kisky Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/davinci/davinci-pcm.c | 66 ++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 33 deletions(-) (limited to 'sound') diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c index 187ee965bf0..42a657ea49c 100644 --- a/sound/soc/davinci/davinci-pcm.c +++ b/sound/soc/davinci/davinci-pcm.c @@ -51,8 +51,8 @@ static struct snd_pcm_hardware davinci_pcm_hardware = { struct davinci_runtime_data { spinlock_t lock; int period; /* current DMA period */ - int master_lch; /* Master DMA channel */ - int slave_lch; /* linked parameter RAM reload slot */ + int asp_channel; /* Master DMA channel */ + int asp_link[2]; /* asp parameter link channel, ping/pong */ struct davinci_pcm_dma_params *params; /* DMA params */ }; @@ -60,7 +60,7 @@ static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream) { struct davinci_runtime_data *prtd = substream->runtime->private_data; struct snd_pcm_runtime *runtime = substream->runtime; - int lch = prtd->slave_lch; + int link = prtd->asp_link[0]; unsigned int period_size; unsigned int dma_offset; dma_addr_t dma_pos; @@ -78,7 +78,7 @@ static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream) fifo_level = prtd->params->fifo_level; pr_debug("davinci_pcm: audio_set_dma_params_play channel = %d " - "dma_ptr = %x period_size=%x\n", lch, dma_pos, period_size); + "dma_ptr = %x period_size=%x\n", link, dma_pos, period_size); data_type = prtd->params->data_type; count = period_size / data_type; @@ -102,16 +102,16 @@ static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream) } acnt = prtd->params->acnt; - edma_set_src(lch, src, INCR, W8BIT); - edma_set_dest(lch, dst, INCR, W8BIT); + edma_set_src(link, src, INCR, W8BIT); + edma_set_dest(link, dst, INCR, W8BIT); - edma_set_src_index(lch, src_bidx, src_cidx); - edma_set_dest_index(lch, dst_bidx, dst_cidx); + edma_set_src_index(link, src_bidx, src_cidx); + edma_set_dest_index(link, dst_bidx, dst_cidx); if (!fifo_level) - edma_set_transfer_params(lch, acnt, count, 1, 0, ASYNC); + edma_set_transfer_params(link, acnt, count, 1, 0, ASYNC); else - edma_set_transfer_params(lch, acnt, fifo_level, count, + edma_set_transfer_params(link, acnt, fifo_level, count, fifo_level, ABSYNC); prtd->period++; @@ -119,12 +119,12 @@ static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream) prtd->period = 0; } -static void davinci_pcm_dma_irq(unsigned lch, u16 ch_status, void *data) +static void davinci_pcm_dma_irq(unsigned link, u16 ch_status, void *data) { struct snd_pcm_substream *substream = data; struct davinci_runtime_data *prtd = substream->runtime->private_data; - pr_debug("davinci_pcm: lch=%d, status=0x%x\n", lch, ch_status); + pr_debug("davinci_pcm: link=%d, status=0x%x\n", link, ch_status); if (unlikely(ch_status != DMA_COMPLETE)) return; @@ -150,15 +150,15 @@ static int davinci_pcm_dma_request(struct snd_pcm_substream *substream) EVENTQ_0); if (ret < 0) return ret; - prtd->master_lch = ret; + prtd->asp_channel = ret; /* Request parameter RAM reload slot */ - ret = edma_alloc_slot(EDMA_CTLR(prtd->master_lch), EDMA_SLOT_ANY); + ret = edma_alloc_slot(EDMA_CTLR(prtd->asp_channel), EDMA_SLOT_ANY); if (ret < 0) { - edma_free_channel(prtd->master_lch); + edma_free_channel(prtd->asp_channel); return ret; } - prtd->slave_lch = ret; + prtd->asp_link[0] = ret; /* Issue transfer completion IRQ when the channel completes a * transfer, then always reload from the same slot (by a kind @@ -169,10 +169,10 @@ static int davinci_pcm_dma_request(struct snd_pcm_substream *substream) * the buffer and its length (ccnt) ... use it as a template * so davinci_pcm_enqueue_dma() takes less time in IRQ. */ - edma_read_slot(prtd->slave_lch, &p_ram); - p_ram.opt |= TCINTEN | EDMA_TCC(EDMA_CHAN_SLOT(prtd->master_lch)); - p_ram.link_bcntrld = EDMA_CHAN_SLOT(prtd->slave_lch) << 5; - edma_write_slot(prtd->slave_lch, &p_ram); + edma_read_slot(prtd->asp_link[0], &p_ram); + p_ram.opt |= TCINTEN | EDMA_TCC(EDMA_CHAN_SLOT(prtd->asp_channel)); + p_ram.link_bcntrld = EDMA_CHAN_SLOT(prtd->asp_link[0]) << 5; + edma_write_slot(prtd->asp_link[0], &p_ram); return 0; } @@ -188,12 +188,12 @@ static int davinci_pcm_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - edma_start(prtd->master_lch); + edma_start(prtd->asp_channel); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - edma_stop(prtd->master_lch); + edma_stop(prtd->asp_channel); break; default: ret = -EINVAL; @@ -214,8 +214,8 @@ static int davinci_pcm_prepare(struct snd_pcm_substream *substream) davinci_pcm_enqueue_dma(substream); /* Copy self-linked parameter RAM entry into master channel */ - edma_read_slot(prtd->slave_lch, &temp); - edma_write_slot(prtd->master_lch, &temp); + edma_read_slot(prtd->asp_link[0], &temp); + edma_write_slot(prtd->asp_channel, &temp); davinci_pcm_enqueue_dma(substream); return 0; @@ -227,20 +227,20 @@ davinci_pcm_pointer(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; struct davinci_runtime_data *prtd = runtime->private_data; unsigned int offset; - dma_addr_t count; - dma_addr_t src, dst; + int asp_count; + dma_addr_t asp_src, asp_dst; spin_lock(&prtd->lock); - edma_get_position(prtd->master_lch, &src, &dst); + edma_get_position(prtd->asp_channel, &asp_src, &asp_dst); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - count = src - runtime->dma_addr; + asp_count = asp_src - runtime->dma_addr; else - count = dst - runtime->dma_addr; + asp_count = asp_dst - runtime->dma_addr; spin_unlock(&prtd->lock); - offset = bytes_to_frames(runtime, count); + offset = bytes_to_frames(runtime, asp_count); if (offset >= runtime->buffer_size) offset = 0; @@ -289,10 +289,10 @@ static int davinci_pcm_close(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; struct davinci_runtime_data *prtd = runtime->private_data; - edma_unlink(prtd->slave_lch); + edma_unlink(prtd->asp_link[0]); - edma_free_slot(prtd->slave_lch); - edma_free_channel(prtd->master_lch); + edma_free_slot(prtd->asp_link[0]); + edma_free_channel(prtd->asp_channel); kfree(prtd); -- cgit v1.2.3 From 1e224f322bf22280957a5f76164d848526ed9b08 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Wed, 18 Nov 2009 17:49:53 -0700 Subject: ASoC: DaVinci: pcm, fix underrun by using sram Fix underruns by using dma to copy 1st to sram in a ping/pong buffer style and then copying from the sram to the ASP. This also has the advantage of tolerating very long interrupt latency on dma completion. Signed-off-by: Troy Kisky Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/davinci/davinci-i2s.c | 7 +- sound/soc/davinci/davinci-pcm.c | 515 ++++++++++++++++++++++++++++++++++++---- sound/soc/davinci/davinci-pcm.h | 1 + 3 files changed, 479 insertions(+), 44 deletions(-) (limited to 'sound') diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index b2a5372ef72..6362ca05506 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -545,8 +545,13 @@ static int davinci_i2s_probe(struct platform_device *pdev) ret = -ENOMEM; goto err_release_region; } - if (pdata) + if (pdata) { dev->enable_channel_combine = pdata->enable_channel_combine; + dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].sram_size = + pdata->sram_size_playback; + dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].sram_size = + pdata->sram_size_capture; + } dev->clk = clk_get(&pdev->dev, NULL); if (IS_ERR(dev->clk)) { ret = -ENODEV; diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c index 42a657ea49c..664d4933650 100644 --- a/sound/soc/davinci/davinci-pcm.c +++ b/sound/soc/davinci/davinci-pcm.c @@ -3,6 +3,7 @@ * * Author: Vladimir Barinov, * Copyright: (C) 2007 MontaVista Software, Inc., + * added SRAM ping/pong (C) 2008 Troy Kisky * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -23,10 +24,29 @@ #include #include +#include #include "davinci-pcm.h" -static struct snd_pcm_hardware davinci_pcm_hardware = { +#ifdef DEBUG +static void print_buf_info(int slot, char *name) +{ + struct edmacc_param p; + if (slot < 0) + return; + edma_read_slot(slot, &p); + printk(KERN_DEBUG "%s: 0x%x, opt=%x, src=%x, a_b_cnt=%x dst=%x\n", + name, slot, p.opt, p.src, p.a_b_cnt, p.dst); + printk(KERN_DEBUG " src_dst_bidx=%x link_bcntrld=%x src_dst_cidx=%x ccnt=%x\n", + p.src_dst_bidx, p.link_bcntrld, p.src_dst_cidx, p.ccnt); +} +#else +static void print_buf_info(int slot, char *name) +{ +} +#endif + +static struct snd_pcm_hardware pcm_hardware_playback = { .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE), @@ -48,14 +68,80 @@ static struct snd_pcm_hardware davinci_pcm_hardware = { .fifo_size = 0, }; +static struct snd_pcm_hardware pcm_hardware_capture = { + .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_PAUSE), + .formats = (SNDRV_PCM_FMTBIT_S16_LE), + .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | + SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | + SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_KNOT), + .rate_min = 8000, + .rate_max = 96000, + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = 128 * 1024, + .period_bytes_min = 32, + .period_bytes_max = 8 * 1024, + .periods_min = 16, + .periods_max = 255, + .fifo_size = 0, +}; + +/* + * How ping/pong works.... + * + * Playback: + * ram_params - copys 2*ping_size from start of SDRAM to iram, + * links to ram_link2 + * ram_link2 - copys rest of SDRAM to iram in ping_size units, + * links to ram_link + * ram_link - copys entire SDRAM to iram in ping_size uints, + * links to self + * + * asp_params - same as asp_link[0] + * asp_link[0] - copys from lower half of iram to asp port + * links to asp_link[1], triggers iram copy event on completion + * asp_link[1] - copys from upper half of iram to asp port + * links to asp_link[0], triggers iram copy event on completion + * triggers interrupt only needed to let upper SOC levels update position + * in stream on completion + * + * When playback is started: + * ram_params started + * asp_params started + * + * Capture: + * ram_params - same as ram_link, + * links to ram_link + * ram_link - same as playback + * links to self + * + * asp_params - same as playback + * asp_link[0] - same as playback + * asp_link[1] - same as playback + * + * When capture is started: + * asp_params started + */ struct davinci_runtime_data { spinlock_t lock; int period; /* current DMA period */ int asp_channel; /* Master DMA channel */ int asp_link[2]; /* asp parameter link channel, ping/pong */ struct davinci_pcm_dma_params *params; /* DMA params */ + int ram_channel; + int ram_link; + int ram_link2; + struct edmacc_param asp_params; + struct edmacc_param ram_params; }; +/* + * Not used with ping/pong + */ static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream) { struct davinci_runtime_data *prtd = substream->runtime->private_data; @@ -124,41 +210,290 @@ static void davinci_pcm_dma_irq(unsigned link, u16 ch_status, void *data) struct snd_pcm_substream *substream = data; struct davinci_runtime_data *prtd = substream->runtime->private_data; + print_buf_info(prtd->ram_channel, "i ram_channel"); pr_debug("davinci_pcm: link=%d, status=0x%x\n", link, ch_status); if (unlikely(ch_status != DMA_COMPLETE)) return; if (snd_pcm_running(substream)) { + if (prtd->ram_channel < 0) { + /* No ping/pong must fix up link dma data*/ + spin_lock(&prtd->lock); + davinci_pcm_enqueue_dma(substream); + spin_unlock(&prtd->lock); + } snd_pcm_period_elapsed(substream); + } +} + +static int allocate_sram(struct snd_pcm_substream *substream, unsigned size, + struct snd_pcm_hardware *ppcm) +{ + struct snd_dma_buffer *buf = &substream->dma_buffer; + struct snd_dma_buffer *iram_dma = NULL; + dma_addr_t iram_phys = 0; + void *iram_virt = NULL; + + if (buf->private_data || !size) + return 0; + + ppcm->period_bytes_max = size; + iram_virt = sram_alloc(size, &iram_phys); + if (!iram_virt) + goto exit1; + iram_dma = kzalloc(sizeof(*iram_dma), GFP_KERNEL); + if (!iram_dma) + goto exit2; + iram_dma->area = iram_virt; + iram_dma->addr = iram_phys; + memset(iram_dma->area, 0, size); + iram_dma->bytes = size; + buf->private_data = iram_dma; + return 0; +exit2: + if (iram_virt) + sram_free(iram_virt, size); +exit1: + return -ENOMEM; +} - spin_lock(&prtd->lock); - davinci_pcm_enqueue_dma(substream); - spin_unlock(&prtd->lock); +/* + * Only used with ping/pong. + * This is called after runtime->dma_addr, period_bytes and data_type are valid + */ +static int ping_pong_dma_setup(struct snd_pcm_substream *substream) +{ + unsigned short ram_src_cidx, ram_dst_cidx; + struct snd_pcm_runtime *runtime = substream->runtime; + struct davinci_runtime_data *prtd = runtime->private_data; + struct snd_dma_buffer *iram_dma = + (struct snd_dma_buffer *)substream->dma_buffer.private_data; + struct davinci_pcm_dma_params *params = prtd->params; + unsigned int data_type = params->data_type; + unsigned int acnt = params->acnt; + /* divide by 2 for ping/pong */ + unsigned int ping_size = snd_pcm_lib_period_bytes(substream) >> 1; + int link = prtd->asp_link[1]; + unsigned int fifo_level = prtd->params->fifo_level; + unsigned int count; + if ((data_type == 0) || (data_type > 4)) { + printk(KERN_ERR "%s: data_type=%i\n", __func__, data_type); + return -EINVAL; + } + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + dma_addr_t asp_src_pong = iram_dma->addr + ping_size; + ram_src_cidx = ping_size; + ram_dst_cidx = -ping_size; + edma_set_src(link, asp_src_pong, INCR, W8BIT); + + link = prtd->asp_link[0]; + edma_set_src_index(link, data_type, data_type * fifo_level); + link = prtd->asp_link[1]; + edma_set_src_index(link, data_type, data_type * fifo_level); + + link = prtd->ram_link; + edma_set_src(link, runtime->dma_addr, INCR, W32BIT); + } else { + dma_addr_t asp_dst_pong = iram_dma->addr + ping_size; + ram_src_cidx = -ping_size; + ram_dst_cidx = ping_size; + edma_set_dest(link, asp_dst_pong, INCR, W8BIT); + + link = prtd->asp_link[0]; + edma_set_dest_index(link, data_type, data_type * fifo_level); + link = prtd->asp_link[1]; + edma_set_dest_index(link, data_type, data_type * fifo_level); + + link = prtd->ram_link; + edma_set_dest(link, runtime->dma_addr, INCR, W32BIT); + } + + if (!fifo_level) { + count = ping_size / data_type; + edma_set_transfer_params(prtd->asp_link[0], acnt, count, + 1, 0, ASYNC); + edma_set_transfer_params(prtd->asp_link[1], acnt, count, + 1, 0, ASYNC); + } else { + count = ping_size / (data_type * fifo_level); + edma_set_transfer_params(prtd->asp_link[0], acnt, fifo_level, + count, fifo_level, ABSYNC); + edma_set_transfer_params(prtd->asp_link[1], acnt, fifo_level, + count, fifo_level, ABSYNC); + } + + link = prtd->ram_link; + edma_set_src_index(link, ping_size, ram_src_cidx); + edma_set_dest_index(link, ping_size, ram_dst_cidx); + edma_set_transfer_params(link, ping_size, 2, + runtime->periods, 2, ASYNC); + + /* init master params */ + edma_read_slot(prtd->asp_link[0], &prtd->asp_params); + edma_read_slot(prtd->ram_link, &prtd->ram_params); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + struct edmacc_param p_ram; + /* Copy entire iram buffer before playback started */ + prtd->ram_params.a_b_cnt = (1 << 16) | (ping_size << 1); + /* 0 dst_bidx */ + prtd->ram_params.src_dst_bidx = (ping_size << 1); + /* 0 dst_cidx */ + prtd->ram_params.src_dst_cidx = (ping_size << 1); + prtd->ram_params.ccnt = 1; + + /* Skip 1st period */ + edma_read_slot(prtd->ram_link, &p_ram); + p_ram.src += (ping_size << 1); + p_ram.ccnt -= 1; + edma_write_slot(prtd->ram_link2, &p_ram); + /* + * When 1st started, ram -> iram dma channel will fill the + * entire iram. Then, whenever a ping/pong asp buffer finishes, + * 1/2 iram will be filled. + */ + prtd->ram_params.link_bcntrld = + EDMA_CHAN_SLOT(prtd->ram_link2) << 5; + } + return 0; +} + +/* 1 asp tx or rx channel using 2 parameter channels + * 1 ram to/from iram channel using 1 parameter channel + * + * Playback + * ram copy channel kicks off first, + * 1st ram copy of entire iram buffer completion kicks off asp channel + * asp tcc always kicks off ram copy of 1/2 iram buffer + * + * Record + * asp channel starts, tcc kicks off ram copy + */ +static int request_ping_pong(struct snd_pcm_substream *substream, + struct davinci_runtime_data *prtd, + struct snd_dma_buffer *iram_dma) +{ + dma_addr_t asp_src_ping; + dma_addr_t asp_dst_ping; + int link; + struct davinci_pcm_dma_params *params = prtd->params; + + /* Request ram master channel */ + link = prtd->ram_channel = edma_alloc_channel(EDMA_CHANNEL_ANY, + davinci_pcm_dma_irq, substream, + EVENTQ_1); + if (link < 0) + goto exit1; + + /* Request ram link channel */ + link = prtd->ram_link = edma_alloc_slot( + EDMA_CTLR(prtd->ram_channel), EDMA_SLOT_ANY); + if (link < 0) + goto exit2; + + link = prtd->asp_link[1] = edma_alloc_slot( + EDMA_CTLR(prtd->asp_channel), EDMA_SLOT_ANY); + if (link < 0) + goto exit3; + + prtd->ram_link2 = -1; + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + link = prtd->ram_link2 = edma_alloc_slot( + EDMA_CTLR(prtd->ram_channel), EDMA_SLOT_ANY); + if (link < 0) + goto exit4; + } + /* circle ping-pong buffers */ + edma_link(prtd->asp_link[0], prtd->asp_link[1]); + edma_link(prtd->asp_link[1], prtd->asp_link[0]); + /* circle ram buffers */ + edma_link(prtd->ram_link, prtd->ram_link); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + asp_src_ping = iram_dma->addr; + asp_dst_ping = params->dma_addr; /* fifo */ + } else { + asp_src_ping = params->dma_addr; /* fifo */ + asp_dst_ping = iram_dma->addr; } + /* ping */ + link = prtd->asp_link[0]; + edma_set_src(link, asp_src_ping, INCR, W16BIT); + edma_set_dest(link, asp_dst_ping, INCR, W16BIT); + edma_set_src_index(link, 0, 0); + edma_set_dest_index(link, 0, 0); + + edma_read_slot(link, &prtd->asp_params); + prtd->asp_params.opt &= ~(TCCMODE | EDMA_TCC(0x3f) | TCINTEN); + prtd->asp_params.opt |= TCCHEN | EDMA_TCC(prtd->ram_channel & 0x3f); + edma_write_slot(link, &prtd->asp_params); + + /* pong */ + link = prtd->asp_link[1]; + edma_set_src(link, asp_src_ping, INCR, W16BIT); + edma_set_dest(link, asp_dst_ping, INCR, W16BIT); + edma_set_src_index(link, 0, 0); + edma_set_dest_index(link, 0, 0); + + edma_read_slot(link, &prtd->asp_params); + prtd->asp_params.opt &= ~(TCCMODE | EDMA_TCC(0x3f)); + /* interrupt after every pong completion */ + prtd->asp_params.opt |= TCINTEN | TCCHEN | + EDMA_TCC(EDMA_CHAN_SLOT(prtd->ram_channel)); + edma_write_slot(link, &prtd->asp_params); + + /* ram */ + link = prtd->ram_link; + edma_set_src(link, iram_dma->addr, INCR, W32BIT); + edma_set_dest(link, iram_dma->addr, INCR, W32BIT); + pr_debug("%s: audio dma channels/slots in use for ram:%u %u %u," + "for asp:%u %u %u\n", __func__, + prtd->ram_channel, prtd->ram_link, prtd->ram_link2, + prtd->asp_channel, prtd->asp_link[0], + prtd->asp_link[1]); + return 0; +exit4: + edma_free_channel(prtd->asp_link[1]); + prtd->asp_link[1] = -1; +exit3: + edma_free_channel(prtd->ram_link); + prtd->ram_link = -1; +exit2: + edma_free_channel(prtd->ram_channel); + prtd->ram_channel = -1; +exit1: + return link; } static int davinci_pcm_dma_request(struct snd_pcm_substream *substream) { + struct snd_dma_buffer *iram_dma; struct davinci_runtime_data *prtd = substream->runtime->private_data; - struct edmacc_param p_ram; - int ret; + struct davinci_pcm_dma_params *params = prtd->params; + int link; - /* Request master DMA channel */ - ret = edma_alloc_channel(prtd->params->channel, - davinci_pcm_dma_irq, substream, - EVENTQ_0); - if (ret < 0) - return ret; - prtd->asp_channel = ret; + if (!params) + return -ENODEV; - /* Request parameter RAM reload slot */ - ret = edma_alloc_slot(EDMA_CTLR(prtd->asp_channel), EDMA_SLOT_ANY); - if (ret < 0) { - edma_free_channel(prtd->asp_channel); - return ret; + /* Request asp master DMA channel */ + link = prtd->asp_channel = edma_alloc_channel(params->channel, + davinci_pcm_dma_irq, substream, EVENTQ_0); + if (link < 0) + goto exit1; + + /* Request asp link channels */ + link = prtd->asp_link[0] = edma_alloc_slot( + EDMA_CTLR(prtd->asp_channel), EDMA_SLOT_ANY); + if (link < 0) + goto exit2; + + iram_dma = (struct snd_dma_buffer *)substream->dma_buffer.private_data; + if (iram_dma) { + if (request_ping_pong(substream, prtd, iram_dma) == 0) + return 0; + printk(KERN_WARNING "%s: dma channel allocation failed," + "not using sram\n", __func__); } - prtd->asp_link[0] = ret; /* Issue transfer completion IRQ when the channel completes a * transfer, then always reload from the same slot (by a kind @@ -169,12 +504,17 @@ static int davinci_pcm_dma_request(struct snd_pcm_substream *substream) * the buffer and its length (ccnt) ... use it as a template * so davinci_pcm_enqueue_dma() takes less time in IRQ. */ - edma_read_slot(prtd->asp_link[0], &p_ram); - p_ram.opt |= TCINTEN | EDMA_TCC(EDMA_CHAN_SLOT(prtd->asp_channel)); - p_ram.link_bcntrld = EDMA_CHAN_SLOT(prtd->asp_link[0]) << 5; - edma_write_slot(prtd->asp_link[0], &p_ram); - + edma_read_slot(link, &prtd->asp_params); + prtd->asp_params.opt |= TCINTEN | + EDMA_TCC(EDMA_CHAN_SLOT(prtd->asp_channel)); + prtd->asp_params.link_bcntrld = EDMA_CHAN_SLOT(link) << 5; + edma_write_slot(link, &prtd->asp_params); return 0; +exit2: + edma_free_channel(prtd->asp_channel); + prtd->asp_channel = -1; +exit1: + return link; } static int davinci_pcm_trigger(struct snd_pcm_substream *substream, int cmd) @@ -208,14 +548,34 @@ static int davinci_pcm_trigger(struct snd_pcm_substream *substream, int cmd) static int davinci_pcm_prepare(struct snd_pcm_substream *substream) { struct davinci_runtime_data *prtd = substream->runtime->private_data; - struct edmacc_param temp; + if (prtd->ram_channel >= 0) { + int ret = ping_pong_dma_setup(substream); + if (ret < 0) + return ret; + + edma_write_slot(prtd->ram_channel, &prtd->ram_params); + edma_write_slot(prtd->asp_channel, &prtd->asp_params); + + print_buf_info(prtd->ram_channel, "ram_channel"); + print_buf_info(prtd->ram_link, "ram_link"); + print_buf_info(prtd->ram_link2, "ram_link2"); + print_buf_info(prtd->asp_channel, "asp_channel"); + print_buf_info(prtd->asp_link[0], "asp_link[0]"); + print_buf_info(prtd->asp_link[1], "asp_link[1]"); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + /* copy 1st iram buffer */ + edma_start(prtd->ram_channel); + } + return 0; + } prtd->period = 0; davinci_pcm_enqueue_dma(substream); /* Copy self-linked parameter RAM entry into master channel */ - edma_read_slot(prtd->asp_link[0], &temp); - edma_write_slot(prtd->asp_channel, &temp); + edma_read_slot(prtd->asp_link[0], &prtd->asp_params); + edma_write_slot(prtd->asp_channel, &prtd->asp_params); davinci_pcm_enqueue_dma(substream); return 0; @@ -231,13 +591,46 @@ davinci_pcm_pointer(struct snd_pcm_substream *substream) dma_addr_t asp_src, asp_dst; spin_lock(&prtd->lock); - - edma_get_position(prtd->asp_channel, &asp_src, &asp_dst); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - asp_count = asp_src - runtime->dma_addr; - else - asp_count = asp_dst - runtime->dma_addr; - + if (prtd->ram_channel >= 0) { + int ram_count; + int mod_ram; + dma_addr_t ram_src, ram_dst; + unsigned int period_size = snd_pcm_lib_period_bytes(substream); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + /* reading ram before asp should be safe + * as long as the asp transfers less than a ping size + * of bytes between the 2 reads + */ + edma_get_position(prtd->ram_channel, + &ram_src, &ram_dst); + edma_get_position(prtd->asp_channel, + &asp_src, &asp_dst); + asp_count = asp_src - prtd->asp_params.src; + ram_count = ram_src - prtd->ram_params.src; + mod_ram = ram_count % period_size; + mod_ram -= asp_count; + if (mod_ram < 0) + mod_ram += period_size; + else if (mod_ram == 0) { + if (snd_pcm_running(substream)) + mod_ram += period_size; + } + ram_count -= mod_ram; + if (ram_count < 0) + ram_count += period_size * runtime->periods; + } else { + edma_get_position(prtd->ram_channel, + &ram_src, &ram_dst); + ram_count = ram_dst - prtd->ram_params.dst; + } + asp_count = ram_count; + } else { + edma_get_position(prtd->asp_channel, &asp_src, &asp_dst); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + asp_count = asp_src - runtime->dma_addr; + else + asp_count = asp_dst - runtime->dma_addr; + } spin_unlock(&prtd->lock); offset = bytes_to_frames(runtime, asp_count); @@ -251,6 +644,7 @@ static int davinci_pcm_open(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct davinci_runtime_data *prtd; + struct snd_pcm_hardware *ppcm; int ret = 0; struct snd_soc_pcm_runtime *rtd = substream->private_data; struct davinci_pcm_dma_params *pa = rtd->dai->cpu_dai->dma_data; @@ -259,7 +653,10 @@ static int davinci_pcm_open(struct snd_pcm_substream *substream) return -ENODEV; params = &pa[substream->stream]; - snd_soc_set_runtime_hwparams(substream, &davinci_pcm_hardware); + ppcm = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? + &pcm_hardware_playback : &pcm_hardware_capture; + allocate_sram(substream, params->sram_size, ppcm); + snd_soc_set_runtime_hwparams(substream, ppcm); /* ensure that buffer size is a multiple of period size */ ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); @@ -272,6 +669,11 @@ static int davinci_pcm_open(struct snd_pcm_substream *substream) spin_lock_init(&prtd->lock); prtd->params = params; + prtd->asp_channel = -1; + prtd->asp_link[0] = prtd->asp_link[1] = -1; + prtd->ram_channel = -1; + prtd->ram_link = -1; + prtd->ram_link2 = -1; runtime->private_data = prtd; @@ -289,10 +691,29 @@ static int davinci_pcm_close(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; struct davinci_runtime_data *prtd = runtime->private_data; - edma_unlink(prtd->asp_link[0]); - - edma_free_slot(prtd->asp_link[0]); - edma_free_channel(prtd->asp_channel); + if (prtd->ram_channel >= 0) + edma_stop(prtd->ram_channel); + if (prtd->asp_channel >= 0) + edma_stop(prtd->asp_channel); + if (prtd->asp_link[0] >= 0) + edma_unlink(prtd->asp_link[0]); + if (prtd->asp_link[1] >= 0) + edma_unlink(prtd->asp_link[1]); + if (prtd->ram_link >= 0) + edma_unlink(prtd->ram_link); + + if (prtd->asp_link[0] >= 0) + edma_free_slot(prtd->asp_link[0]); + if (prtd->asp_link[1] >= 0) + edma_free_slot(prtd->asp_link[1]); + if (prtd->asp_channel >= 0) + edma_free_channel(prtd->asp_channel); + if (prtd->ram_link >= 0) + edma_free_slot(prtd->ram_link); + if (prtd->ram_link2 >= 0) + edma_free_slot(prtd->ram_link2); + if (prtd->ram_channel >= 0) + edma_free_channel(prtd->ram_channel); kfree(prtd); @@ -334,11 +755,11 @@ static struct snd_pcm_ops davinci_pcm_ops = { .mmap = davinci_pcm_mmap, }; -static int davinci_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) +static int davinci_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream, + size_t size) { struct snd_pcm_substream *substream = pcm->streams[stream].substream; struct snd_dma_buffer *buf = &substream->dma_buffer; - size_t size = davinci_pcm_hardware.buffer_bytes_max; buf->dev.type = SNDRV_DMA_TYPE_DEV; buf->dev.dev = pcm->card->dev; @@ -363,6 +784,7 @@ static void davinci_pcm_free(struct snd_pcm *pcm) int stream; for (stream = 0; stream < 2; stream++) { + struct snd_dma_buffer *iram_dma; substream = pcm->streams[stream].substream; if (!substream) continue; @@ -374,6 +796,11 @@ static void davinci_pcm_free(struct snd_pcm *pcm) dma_free_writecombine(pcm->card->dev, buf->bytes, buf->area, buf->addr); buf->area = NULL; + iram_dma = (struct snd_dma_buffer *)buf->private_data; + if (iram_dma) { + sram_free(iram_dma->area, iram_dma->bytes); + kfree(iram_dma); + } } } @@ -391,14 +818,16 @@ static int davinci_pcm_new(struct snd_card *card, if (dai->playback.channels_min) { ret = davinci_pcm_preallocate_dma_buffer(pcm, - SNDRV_PCM_STREAM_PLAYBACK); + SNDRV_PCM_STREAM_PLAYBACK, + pcm_hardware_playback.buffer_bytes_max); if (ret) return ret; } if (dai->capture.channels_min) { ret = davinci_pcm_preallocate_dma_buffer(pcm, - SNDRV_PCM_STREAM_CAPTURE); + SNDRV_PCM_STREAM_CAPTURE, + pcm_hardware_capture.buffer_bytes_max); if (ret) return ret; } diff --git a/sound/soc/davinci/davinci-pcm.h b/sound/soc/davinci/davinci-pcm.h index c8b0d2baf05..0764944cf10 100644 --- a/sound/soc/davinci/davinci-pcm.h +++ b/sound/soc/davinci/davinci-pcm.h @@ -20,6 +20,7 @@ struct davinci_pcm_dma_params { int channel; /* sync dma channel ID */ unsigned short acnt; dma_addr_t dma_addr; /* device physical address for DMA */ + unsigned sram_size; enum dma_event_q eventq_no; /* event queue number */ unsigned char data_type; /* xfer data type */ unsigned char convert_mono_stereo; -- cgit v1.2.3 From 2b7b250df74f1f9e15cdf33fa90f6c98a419842d Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Wed, 18 Nov 2009 17:49:54 -0700 Subject: ASoC: DaVinci: use edma_pause, edma_resume Use edma_pause and edma_resume to make missing dma_events less likely. This may not be needed, but it looks better. Signed-off-by: Troy Kisky Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/davinci/davinci-pcm.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c index 664d4933650..ad4d7f47a86 100644 --- a/sound/soc/davinci/davinci-pcm.c +++ b/sound/soc/davinci/davinci-pcm.c @@ -528,12 +528,12 @@ static int davinci_pcm_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - edma_start(prtd->asp_channel); + edma_resume(prtd->asp_channel); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - edma_stop(prtd->asp_channel); + edma_pause(prtd->asp_channel); break; default: ret = -EINVAL; @@ -568,6 +568,7 @@ static int davinci_pcm_prepare(struct snd_pcm_substream *substream) /* copy 1st iram buffer */ edma_start(prtd->ram_channel); } + edma_start(prtd->asp_channel); return 0; } prtd->period = 0; @@ -577,6 +578,7 @@ static int davinci_pcm_prepare(struct snd_pcm_substream *substream) edma_read_slot(prtd->asp_link[0], &prtd->asp_params); edma_write_slot(prtd->asp_channel, &prtd->asp_params); davinci_pcm_enqueue_dma(substream); + edma_start(prtd->asp_channel); return 0; } -- cgit v1.2.3 From b2a2236d1f5e7c09c8e74b61f13d8ba3fe82f7be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enric=20Balletb=C3=B2=20i=20Serra?= Date: Wed, 18 Nov 2009 15:59:24 +0100 Subject: ASoC: Add support for IGEP v2 Signed-off-by: Enric Balletbo i Serra Signed-off-by: Mark Brown --- sound/soc/omap/Kconfig | 7 +++ sound/soc/omap/Makefile | 2 + sound/soc/omap/igep0020.c | 148 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 157 insertions(+) create mode 100644 sound/soc/omap/igep0020.c (limited to 'sound') diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index 4dc6b15a852..61952aa6cd5 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig @@ -109,3 +109,10 @@ config SND_OMAP_SOC_ZOOM2 help Say Y if you want to add support for Soc audio on Zoom2 board. +config SND_OMAP_SOC_IGEP0020 + tristate "SoC Audio support for IGEP v2" + depends on TWL4030_CORE && SND_OMAP_SOC && MACH_IGEP0020 + select SND_OMAP_SOC_MCBSP + select SND_SOC_TWL4030 + help + Say Y if you want to add support for Soc audio on IGEP v2 board. diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile index 0c78ae4e6b9..d49458a29bb 100644 --- a/sound/soc/omap/Makefile +++ b/sound/soc/omap/Makefile @@ -17,6 +17,7 @@ snd-soc-sdp3430-objs := sdp3430.o snd-soc-omap3pandora-objs := omap3pandora.o snd-soc-omap3beagle-objs := omap3beagle.o snd-soc-zoom2-objs := zoom2.o +snd-soc-igep0020-objs := igep0020.o obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o obj-$(CONFIG_SND_OMAP_SOC_AMS_DELTA) += snd-soc-ams-delta.o @@ -29,3 +30,4 @@ obj-$(CONFIG_SND_OMAP_SOC_SDP3430) += snd-soc-sdp3430.o obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o obj-$(CONFIG_SND_OMAP_SOC_OMAP3_BEAGLE) += snd-soc-omap3beagle.o obj-$(CONFIG_SND_OMAP_SOC_ZOOM2) += snd-soc-zoom2.o +obj-$(CONFIG_SND_OMAP_SOC_IGEP0020) += snd-soc-igep0020.o diff --git a/sound/soc/omap/igep0020.c b/sound/soc/omap/igep0020.c new file mode 100644 index 00000000000..3583c429f9b --- /dev/null +++ b/sound/soc/omap/igep0020.c @@ -0,0 +1,148 @@ +/* + * igep0020.c -- SoC audio for IGEP v2 + * + * Based on sound/soc/omap/overo.c by Steve Sakoman + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "omap-mcbsp.h" +#include "omap-pcm.h" +#include "../codecs/twl4030.h" + +static int igep2_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + int ret; + + /* Set codec DAI configuration */ + ret = snd_soc_dai_set_fmt(codec_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM); + if (ret < 0) { + printk(KERN_ERR "can't set codec DAI configuration\n"); + return ret; + } + + /* Set cpu DAI configuration */ + ret = snd_soc_dai_set_fmt(cpu_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM); + if (ret < 0) { + printk(KERN_ERR "can't set cpu DAI configuration\n"); + return ret; + } + + /* Set the codec system clock for DAC and ADC */ + ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000, + SND_SOC_CLOCK_IN); + if (ret < 0) { + printk(KERN_ERR "can't set codec system clock\n"); + return ret; + } + + return 0; +} + +static struct snd_soc_ops igep2_ops = { + .hw_params = igep2_hw_params, +}; + +/* Digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link igep2_dai = { + .name = "TWL4030", + .stream_name = "TWL4030", + .cpu_dai = &omap_mcbsp_dai[0], + .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI], + .ops = &igep2_ops, +}; + +/* Audio machine driver */ +static struct snd_soc_card snd_soc_card_igep2 = { + .name = "igep2", + .platform = &omap_soc_platform, + .dai_link = &igep2_dai, + .num_links = 1, +}; + +/* Audio subsystem */ +static struct snd_soc_device igep2_snd_devdata = { + .card = &snd_soc_card_igep2, + .codec_dev = &soc_codec_dev_twl4030, +}; + +static struct platform_device *igep2_snd_device; + +static int __init igep2_soc_init(void) +{ + int ret; + + if (!machine_is_igep0020()) { + pr_debug("Not IGEP v2!\n"); + return -ENODEV; + } + printk(KERN_INFO "IGEP v2 SoC init\n"); + + igep2_snd_device = platform_device_alloc("soc-audio", -1); + if (!igep2_snd_device) { + printk(KERN_ERR "Platform device allocation failed\n"); + return -ENOMEM; + } + + platform_set_drvdata(igep2_snd_device, &igep2_snd_devdata); + igep2_snd_devdata.dev = &igep2_snd_device->dev; + *(unsigned int *)igep2_dai.cpu_dai->private_data = 1; /* McBSP2 */ + + ret = platform_device_add(igep2_snd_device); + if (ret) + goto err1; + + return 0; + +err1: + printk(KERN_ERR "Unable to add platform device\n"); + platform_device_put(igep2_snd_device); + + return ret; +} +module_init(igep2_soc_init); + +static void __exit igep2_soc_exit(void) +{ + platform_device_unregister(igep2_snd_device); +} +module_exit(igep2_soc_exit); + +MODULE_AUTHOR("Enric Balletbo i Serra "); +MODULE_DESCRIPTION("ALSA SoC IGEP v2"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 4b28dca86066596721a6243c94611dab41970079 Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Wed, 18 Nov 2009 17:29:36 +0100 Subject: ALSA: cs4236: add dB scale for all volume controls Use db scale for all volume controls according to Crystal's datasheets. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai --- sound/isa/cs423x/cs4236_lib.c | 152 ++++++++++++++++++++++++++++++------------ 1 file changed, 108 insertions(+), 44 deletions(-) (limited to 'sound') diff --git a/sound/isa/cs423x/cs4236_lib.c b/sound/isa/cs423x/cs4236_lib.c index 4c4024a73c6..c5adca30063 100644 --- a/sound/isa/cs423x/cs4236_lib.c +++ b/sound/isa/cs423x/cs4236_lib.c @@ -88,6 +88,7 @@ #include #include #include +#include /* * @@ -399,6 +400,14 @@ int snd_cs4236_pcm(struct snd_wss *chip, int device, struct snd_pcm **rpcm) .get = snd_cs4236_get_single, .put = snd_cs4236_put_single, \ .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) } +#define CS4236_SINGLE_TLV(xname, xindex, reg, shift, mask, invert, xtlv) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ + .info = snd_cs4236_info_single, \ + .get = snd_cs4236_get_single, .put = snd_cs4236_put_single, \ + .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24), \ + .tlv = { .p = (xtlv) } } + static int snd_cs4236_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { int mask = (kcontrol->private_value >> 16) & 0xff; @@ -502,6 +511,16 @@ static int snd_cs4236_put_singlec(struct snd_kcontrol *kcontrol, struct snd_ctl_ .get = snd_cs4236_get_double, .put = snd_cs4236_put_double, \ .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) } +#define CS4236_DOUBLE_TLV(xname, xindex, left_reg, right_reg, shift_left, \ + shift_right, mask, invert, xtlv) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ + .info = snd_cs4236_info_double, \ + .get = snd_cs4236_get_double, .put = snd_cs4236_put_double, \ + .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | \ + (shift_right << 19) | (mask << 24) | (invert << 22), \ + .tlv = { .p = (xtlv) } } + static int snd_cs4236_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { int mask = (kcontrol->private_value >> 24) & 0xff; @@ -572,12 +591,23 @@ static int snd_cs4236_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_e return change; } -#define CS4236_DOUBLE1(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \ +#define CS4236_DOUBLE1(xname, xindex, left_reg, right_reg, shift_left, \ + shift_right, mask, invert) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ .info = snd_cs4236_info_double, \ .get = snd_cs4236_get_double1, .put = snd_cs4236_put_double1, \ .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) } +#define CS4236_DOUBLE1_TLV(xname, xindex, left_reg, right_reg, shift_left, \ + shift_right, mask, invert, xtlv) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ + .info = snd_cs4236_info_double, \ + .get = snd_cs4236_get_double1, .put = snd_cs4236_put_double1, \ + .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | \ + (shift_right << 19) | (mask << 24) | (invert << 22), \ + .tlv = { .p = (xtlv) } } + static int snd_cs4236_get_double1(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_wss *chip = snd_kcontrol_chip(kcontrol); @@ -631,16 +661,18 @@ static int snd_cs4236_put_double1(struct snd_kcontrol *kcontrol, struct snd_ctl_ return change; } -#define CS4236_MASTER_DIGITAL(xname, xindex) \ +#define CS4236_MASTER_DIGITAL(xname, xindex, xtlv) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ .info = snd_cs4236_info_double, \ .get = snd_cs4236_get_master_digital, .put = snd_cs4236_put_master_digital, \ - .private_value = 71 << 24 } + .private_value = 71 << 24, \ + .tlv = { .p = (xtlv) } } static inline int snd_cs4236_mixer_master_digital_invert_volume(int vol) { return (vol < 64) ? 63 - vol : 64 + (71 - vol); -} +} static int snd_cs4236_get_master_digital(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -673,11 +705,13 @@ static int snd_cs4236_put_master_digital(struct snd_kcontrol *kcontrol, struct s return change; } -#define CS4235_OUTPUT_ACCU(xname, xindex) \ +#define CS4235_OUTPUT_ACCU(xname, xindex, xtlv) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ .info = snd_cs4236_info_double, \ .get = snd_cs4235_get_output_accu, .put = snd_cs4235_put_output_accu, \ - .private_value = 3 << 24 } + .private_value = 3 << 24, \ + .tlv = { .p = (xtlv) } } static inline int snd_cs4235_mixer_output_accu_get_volume(int vol) { @@ -732,41 +766,56 @@ static int snd_cs4235_put_output_accu(struct snd_kcontrol *kcontrol, struct snd_ return change; } +static const DECLARE_TLV_DB_SCALE(db_scale_7bit, -9450, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_6bit_12db_max, -8250, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_5bit_22db_max, -2400, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_2bit, -1800, 600, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0); + static struct snd_kcontrol_new snd_cs4236_controls[] = { CS4236_DOUBLE("Master Digital Playback Switch", 0, CS4236_LEFT_MASTER, CS4236_RIGHT_MASTER, 7, 7, 1, 1), CS4236_DOUBLE("Master Digital Capture Switch", 0, CS4236_DAC_MUTE, CS4236_DAC_MUTE, 7, 6, 1, 1), -CS4236_MASTER_DIGITAL("Master Digital Volume", 0), +CS4236_MASTER_DIGITAL("Master Digital Volume", 0, db_scale_7bit), -CS4236_DOUBLE("Capture Boost Volume", 0, - CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1), +CS4236_DOUBLE_TLV("Capture Boost Volume", 0, + CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1, + db_scale_2bit), WSS_DOUBLE("PCM Playback Switch", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1), -WSS_DOUBLE("PCM Playback Volume", 0, - CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1), +WSS_DOUBLE_TLV("PCM Playback Volume", 0, + CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1, + db_scale_6bit), CS4236_DOUBLE("DSP Playback Switch", 0, CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 7, 7, 1, 1), -CS4236_DOUBLE("DSP Playback Volume", 0, - CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 0, 0, 63, 1), +CS4236_DOUBLE_TLV("DSP Playback Volume", 0, + CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 0, 0, 63, 1, + db_scale_6bit), CS4236_DOUBLE("FM Playback Switch", 0, CS4236_LEFT_FM, CS4236_RIGHT_FM, 7, 7, 1, 1), -CS4236_DOUBLE("FM Playback Volume", 0, - CS4236_LEFT_FM, CS4236_RIGHT_FM, 0, 0, 63, 1), +CS4236_DOUBLE_TLV("FM Playback Volume", 0, + CS4236_LEFT_FM, CS4236_RIGHT_FM, 0, 0, 63, 1, + db_scale_6bit), CS4236_DOUBLE("Wavetable Playback Switch", 0, CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 7, 7, 1, 1), -CS4236_DOUBLE("Wavetable Playback Volume", 0, - CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 0, 0, 63, 1), +CS4236_DOUBLE_TLV("Wavetable Playback Volume", 0, + CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 0, 0, 63, 1, + db_scale_6bit_12db_max), WSS_DOUBLE("Synth Playback Switch", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1), -WSS_DOUBLE("Synth Volume", 0, - CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1), +WSS_DOUBLE_TLV("Synth Volume", 0, + CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1, + db_scale_5bit_12db_max), WSS_DOUBLE("Synth Capture Switch", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 6, 6, 1, 1), WSS_DOUBLE("Synth Capture Bypass", 0, @@ -776,14 +825,16 @@ CS4236_DOUBLE("Mic Playback Switch", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 6, 6, 1, 1), CS4236_DOUBLE("Mic Capture Switch", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 7, 7, 1, 1), -CS4236_DOUBLE("Mic Volume", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 0, 0, 31, 1), +CS4236_DOUBLE_TLV("Mic Volume", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, + 0, 0, 31, 1, db_scale_5bit_22db_max), CS4236_DOUBLE("Mic Playback Boost (+20dB)", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 5, 5, 1, 0), WSS_DOUBLE("Line Playback Switch", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1), -WSS_DOUBLE("Line Volume", 0, - CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1), +WSS_DOUBLE_TLV("Line Volume", 0, + CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1, + db_scale_5bit_12db_max), WSS_DOUBLE("Line Capture Switch", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 6, 6, 1, 1), WSS_DOUBLE("Line Capture Bypass", 0, @@ -791,8 +842,9 @@ WSS_DOUBLE("Line Capture Bypass", 0, WSS_DOUBLE("CD Playback Switch", 0, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1), -WSS_DOUBLE("CD Volume", 0, - CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1), +WSS_DOUBLE_TLV("CD Volume", 0, + CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1, + db_scale_5bit_12db_max), WSS_DOUBLE("CD Capture Switch", 0, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 6, 6, 1, 1), @@ -800,44 +852,53 @@ CS4236_DOUBLE1("Mono Output Playback Switch", 0, CS4231_MONO_CTRL, CS4236_RIGHT_MIX_CTRL, 6, 7, 1, 1), CS4236_DOUBLE1("Beep Playback Switch", 0, CS4231_MONO_CTRL, CS4236_LEFT_MIX_CTRL, 7, 7, 1, 1), -WSS_SINGLE("Beep Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1), +WSS_SINGLE_TLV("Beep Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1, + db_scale_4bit), WSS_SINGLE("Beep Bypass Playback Switch", 0, CS4231_MONO_CTRL, 5, 1, 0), -WSS_DOUBLE("Capture Volume", 0, - CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0), +WSS_DOUBLE_TLV("Capture Volume", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, + 0, 0, 15, 0, db_scale_rec_gain), WSS_DOUBLE("Analog Loopback Capture Switch", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 7, 7, 1, 0), -WSS_SINGLE("Digital Loopback Playback Switch", 0, CS4231_LOOPBACK, 0, 1, 0), -CS4236_DOUBLE1("Digital Loopback Playback Volume", 0, - CS4231_LOOPBACK, CS4236_RIGHT_LOOPBACK, 2, 0, 63, 1) +WSS_SINGLE("Loopback Digital Playback Switch", 0, CS4231_LOOPBACK, 0, 1, 0), +CS4236_DOUBLE1_TLV("Loopback Digital Playback Volume", 0, + CS4231_LOOPBACK, CS4236_RIGHT_LOOPBACK, 2, 0, 63, 1, + db_scale_6bit), }; +static const DECLARE_TLV_DB_SCALE(db_scale_5bit_6db_max, -5600, 200, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_2bit_16db_max, -2400, 800, 0); + static struct snd_kcontrol_new snd_cs4235_controls[] = { WSS_DOUBLE("Master Playback Switch", 0, CS4235_LEFT_MASTER, CS4235_RIGHT_MASTER, 7, 7, 1, 1), -WSS_DOUBLE("Master Playback Volume", 0, - CS4235_LEFT_MASTER, CS4235_RIGHT_MASTER, 0, 0, 31, 1), +WSS_DOUBLE_TLV("Master Playback Volume", 0, + CS4235_LEFT_MASTER, CS4235_RIGHT_MASTER, 0, 0, 31, 1, + db_scale_5bit_6db_max), -CS4235_OUTPUT_ACCU("Playback Volume", 0), +CS4235_OUTPUT_ACCU("Playback Volume", 0, db_scale_2bit_16db_max), WSS_DOUBLE("Synth Playback Switch", 1, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1), WSS_DOUBLE("Synth Capture Switch", 1, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 6, 6, 1, 1), -WSS_DOUBLE("Synth Volume", 1, - CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1), +WSS_DOUBLE_TLV("Synth Volume", 1, + CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1, + db_scale_5bit_12db_max), -CS4236_DOUBLE("Capture Volume", 0, - CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1), +CS4236_DOUBLE_TLV("Capture Volume", 0, + CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1, + db_scale_2bit), WSS_DOUBLE("PCM Playback Switch", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1), WSS_DOUBLE("PCM Capture Switch", 0, CS4236_DAC_MUTE, CS4236_DAC_MUTE, 7, 6, 1, 1), -WSS_DOUBLE("PCM Volume", 0, - CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1), +WSS_DOUBLE_TLV("PCM Volume", 0, + CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1, + db_scale_6bit), CS4236_DOUBLE("DSP Switch", 0, CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 7, 7, 1, 1), @@ -850,22 +911,25 @@ CS4236_DOUBLE("Mic Capture Switch", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 7, 7, 1, 1), CS4236_DOUBLE("Mic Playback Switch", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 6, 6, 1, 1), -CS4236_SINGLE("Mic Volume", 0, CS4236_LEFT_MIC, 0, 31, 1), +CS4236_SINGLE_TLV("Mic Volume", 0, CS4236_LEFT_MIC, 0, 31, 1, + db_scale_5bit_22db_max), CS4236_SINGLE("Mic Boost (+20dB)", 0, CS4236_LEFT_MIC, 5, 1, 0), WSS_DOUBLE("Line Playback Switch", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1), WSS_DOUBLE("Line Capture Switch", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 6, 6, 1, 1), -WSS_DOUBLE("Line Volume", 0, - CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1), +WSS_DOUBLE_TLV("Line Volume", 0, + CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1, + db_scale_5bit_12db_max), WSS_DOUBLE("CD Playback Switch", 1, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1), WSS_DOUBLE("CD Capture Switch", 1, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 6, 6, 1, 1), -WSS_DOUBLE("CD Volume", 1, - CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1), +WSS_DOUBLE_TLV("CD Volume", 1, + CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1, + db_scale_5bit_12db_max), CS4236_DOUBLE1("Beep Playback Switch", 0, CS4231_MONO_CTRL, CS4236_LEFT_MIX_CTRL, 7, 7, 1, 1), -- cgit v1.2.3 From d867bba94513cf149cb8462a6e006848acb91d38 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Thu, 19 Nov 2009 14:34:33 +0100 Subject: sound: usb-audio: add Roland UA-1G support Add support for the Roland UA-1G audio interface. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/usb/usbquirks.h | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'sound') diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h index f6f201eb24c..a892bda03df 100644 --- a/sound/usb/usbquirks.h +++ b/sound/usb/usbquirks.h @@ -1563,6 +1563,29 @@ YAMAHA_DEVICE(0x7010, "UB99"), } } }, +{ + /* has ID 0x00ea when not in Advanced Driver mode */ + USB_DEVICE_VENDOR_SPEC(0x0582, 0x00e9), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + /* .vendor_name = "Roland", */ + /* .product_name = "UA-1G", */ + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const struct snd_usb_audio_quirk[]) { + { + .ifnum = 0, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = -1 + } + } + } +}, /* Guillemot devices */ { -- cgit v1.2.3 From fbc543915ffb8ec5c35403f294ab799f1936f42a Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Fri, 20 Nov 2009 14:56:52 +0900 Subject: ALSA: sound: usbmidi: Use hweight16 Use hweight16 instead of Brian Kernighan's/Peter Wegner's method Signed-off-by: Akinobu Mita Signed-off-by: Takashi Iwai --- sound/usb/usbmidi.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) (limited to 'sound') diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c index 0eff19ceb7e..e5b06899637 100644 --- a/sound/usb/usbmidi.c +++ b/sound/usb/usbmidi.c @@ -1062,15 +1062,6 @@ static int snd_usbmidi_in_endpoint_create(struct snd_usb_midi* umidi, return 0; } -static unsigned int snd_usbmidi_count_bits(unsigned int x) -{ - unsigned int bits; - - for (bits = 0; x; ++bits) - x &= x - 1; - return bits; -} - /* * Frees an output endpoint. * May be called when ep hasn't been initialized completely. @@ -1914,8 +1905,8 @@ int snd_usb_create_midi_interface(struct snd_usb_audio* chip, out_ports = 0; in_ports = 0; for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) { - out_ports += snd_usbmidi_count_bits(endpoints[i].out_cables); - in_ports += snd_usbmidi_count_bits(endpoints[i].in_cables); + out_ports += hweight16(endpoints[i].out_cables); + in_ports += hweight16(endpoints[i].in_cables); } err = snd_usbmidi_create_rawmidi(umidi, out_ports, in_ports); if (err < 0) { -- cgit v1.2.3 From 616ad593fe37ef265e5cb1282db6ca264197ffb2 Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Sat, 21 Nov 2009 01:01:18 +0100 Subject: ALSA: opti-miro: remove snd_card pointer from snd_miro structure Remove the snd_card pointer from the snd_miro structure and do some small code improvements. Also, move Opti chipset detection before detection of the ACI mixer, so the mci_base value is set in one place only. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai --- sound/isa/opti9xx/miro.c | 53 +++++++++++++++++++++--------------------------- 1 file changed, 23 insertions(+), 30 deletions(-) (limited to 'sound') diff --git a/sound/isa/opti9xx/miro.c b/sound/isa/opti9xx/miro.c index 17761030aff..db4a4fbdc5c 100644 --- a/sound/isa/opti9xx/miro.c +++ b/sound/isa/opti9xx/miro.c @@ -110,7 +110,6 @@ struct snd_miro { unsigned long pwd_reg; spinlock_t lock; - struct snd_card *card; struct snd_pcm *pcm; long wss_base; @@ -132,8 +131,6 @@ struct snd_miro { struct mutex aci_mutex; }; -static void snd_miro_proc_init(struct snd_miro * miro); - static char * snd_opti9xx_names[] = { "unkown", "82C928", "82C929", @@ -457,11 +454,9 @@ static int snd_miro_put_double(struct snd_kcontrol *kcontrol, right = ucontrol->value.integer.value[1]; setreg_right = (kcontrol->private_value >> 8) & 0xff; - if (setreg_right == ACI_SET_MASTER) { - setreg_left = setreg_right + 1; - } else { - setreg_left = setreg_right + 8; - } + setreg_left = setreg_right + 8; + if (setreg_right == ACI_SET_MASTER) + setreg_left -= 7; getreg_right = kcontrol->private_value & 0xff; getreg_left = getreg_right + 1; @@ -667,17 +662,15 @@ static int __devinit snd_set_aci_init_values(struct snd_miro *miro) return 0; } -static int __devinit snd_miro_mixer(struct snd_miro *miro) +static int __devinit snd_miro_mixer(struct snd_card *card, + struct snd_miro *miro) { - struct snd_card *card; unsigned int idx; int err; - if (snd_BUG_ON(!miro || !miro->card)) + if (snd_BUG_ON(!miro || !card)) return -EINVAL; - card = miro->card; - switch (miro->hardware) { case OPTi9XX_HW_82C924: strcpy(card->mixername, "ACI & OPTi924"); @@ -950,11 +943,12 @@ static void snd_miro_proc_read(struct snd_info_entry * entry, snd_iprintf(buffer, " preamp : 0x%x\n", miro->aci_preamp); } -static void __devinit snd_miro_proc_init(struct snd_miro * miro) +static void __devinit snd_miro_proc_init(struct snd_card *card, + struct snd_miro *miro) { struct snd_info_entry *entry; - if (! snd_card_proc_new(miro->card, "miro", &entry)) + if (!snd_card_proc_new(card, "miro", &entry)) snd_info_set_text_ops(entry, miro, snd_miro_proc_read); } @@ -971,20 +965,18 @@ static int __devinit snd_miro_configure(struct snd_miro *chip) unsigned char mpu_irq_bits; unsigned long flags; + snd_miro_write_mask(chip, OPTi9XX_MC_REG(1), 0x80, 0x80); + snd_miro_write_mask(chip, OPTi9XX_MC_REG(2), 0x20, 0x20); /* OPL4 */ + snd_miro_write_mask(chip, OPTi9XX_MC_REG(5), 0x02, 0x02); + switch (chip->hardware) { case OPTi9XX_HW_82C924: snd_miro_write_mask(chip, OPTi9XX_MC_REG(6), 0x02, 0x02); - snd_miro_write_mask(chip, OPTi9XX_MC_REG(1), 0x80, 0x80); - snd_miro_write_mask(chip, OPTi9XX_MC_REG(2), 0x20, 0x20); /* OPL4 */ snd_miro_write_mask(chip, OPTi9XX_MC_REG(3), 0xf0, 0xff); - snd_miro_write_mask(chip, OPTi9XX_MC_REG(5), 0x02, 0x02); break; case OPTi9XX_HW_82C929: /* untested init commands for OPTi929 */ - snd_miro_write_mask(chip, OPTi9XX_MC_REG(1), 0x80, 0x80); - snd_miro_write_mask(chip, OPTi9XX_MC_REG(2), 0x20, 0x20); /* OPL4 */ snd_miro_write_mask(chip, OPTi9XX_MC_REG(4), 0x00, 0x0c); - snd_miro_write_mask(chip, OPTi9XX_MC_REG(5), 0x02, 0x02); break; default: snd_printk(KERN_ERR "chip %d not supported\n", chip->hardware); @@ -1156,7 +1148,6 @@ static int __devinit snd_card_miro_aci_detect(struct snd_card *card, /* get ACI port from OPTi9xx MC 4 */ - miro->mc_base = 0xf8c; regval=inb(miro->mc_base + 4); miro->aci_port = (regval & 0x10) ? 0x344: 0x354; @@ -1232,7 +1223,13 @@ static int __devinit snd_miro_probe(struct device *devptr, unsigned int n) card->private_free = snd_card_miro_free; miro = card->private_data; - miro->card = card; + + error = snd_card_miro_detect(card, miro); + if (error < 0) { + snd_card_free(card); + snd_printk(KERN_ERR "unable to detect OPTi9xx chip\n"); + return -ENODEV; + } if ((error = snd_card_miro_aci_detect(card, miro)) < 0) { snd_card_free(card); @@ -1241,13 +1238,8 @@ static int __devinit snd_miro_probe(struct device *devptr, unsigned int n) } /* init proc interface */ - snd_miro_proc_init(miro); + snd_miro_proc_init(card, miro); - if ((error = snd_card_miro_detect(card, miro)) < 0) { - snd_card_free(card); - snd_printk(KERN_ERR "unable to detect OPTi9xx chip\n"); - return -ENODEV; - } if (! miro->res_mc_base && (miro->res_mc_base = request_region(miro->mc_base, miro->mc_base_size, @@ -1341,7 +1333,8 @@ static int __devinit snd_miro_probe(struct device *devptr, unsigned int n) miro->pcm = pcm; - if ((error = snd_miro_mixer(miro)) < 0) { + error = snd_miro_mixer(card, miro); + if (error < 0) { snd_card_free(card); return error; } -- cgit v1.2.3 From 9aeba6297151abcb1b34f3237e4c028aae500ce4 Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Sun, 22 Nov 2009 17:23:45 +0100 Subject: ALSA: opti-miro: make miro.h header available outside the alsa directory Move the miro.h header to the include/sound directory. It can be used in the Miro PCM20 radio driver (v4l). Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai --- sound/isa/opti9xx/miro.c | 2 +- sound/isa/opti9xx/miro.h | 73 ------------------------------------------------ 2 files changed, 1 insertion(+), 74 deletions(-) delete mode 100644 sound/isa/opti9xx/miro.h (limited to 'sound') diff --git a/sound/isa/opti9xx/miro.c b/sound/isa/opti9xx/miro.c index db4a4fbdc5c..932a067ef98 100644 --- a/sound/isa/opti9xx/miro.c +++ b/sound/isa/opti9xx/miro.c @@ -40,7 +40,7 @@ #define SNDRV_LEGACY_FIND_FREE_IRQ #define SNDRV_LEGACY_FIND_FREE_DMA #include -#include "miro.h" +#include MODULE_AUTHOR("Martin Langer "); MODULE_LICENSE("GPL"); diff --git a/sound/isa/opti9xx/miro.h b/sound/isa/opti9xx/miro.h deleted file mode 100644 index 6e1385b8e07..00000000000 --- a/sound/isa/opti9xx/miro.h +++ /dev/null @@ -1,73 +0,0 @@ -#ifndef _MIRO_H_ -#define _MIRO_H_ - -#define ACI_REG_COMMAND 0 /* write register offset */ -#define ACI_REG_STATUS 1 /* read register offset */ -#define ACI_REG_BUSY 2 /* busy register offset */ -#define ACI_REG_RDS 2 /* PCM20: RDS register offset */ -#define ACI_MINTIME 500 /* ACI time out limit */ - -#define ACI_SET_MUTE 0x0d -#define ACI_SET_POWERAMP 0x0f -#define ACI_SET_TUNERMUTE 0xa3 -#define ACI_SET_TUNERMONO 0xa4 -#define ACI_SET_IDE 0xd0 -#define ACI_SET_WSS 0xd1 -#define ACI_SET_SOLOMODE 0xd2 -#define ACI_SET_PREAMP 0x03 -#define ACI_GET_PREAMP 0x21 -#define ACI_WRITE_TUNE 0xa7 -#define ACI_READ_TUNERSTEREO 0xa8 -#define ACI_READ_TUNERSTATION 0xa9 -#define ACI_READ_VERSION 0xf1 -#define ACI_READ_IDCODE 0xf2 -#define ACI_INIT 0xff -#define ACI_STATUS 0xf0 -#define ACI_S_GENERAL 0x00 -#define ACI_ERROR_OP 0xdf - -/* ACI Mixer */ - -/* These are the values for the right channel GET registers. - Add an offset of 0x01 for the left channel register. - (left=right+0x01) */ - -#define ACI_GET_MASTER 0x03 -#define ACI_GET_MIC 0x05 -#define ACI_GET_LINE 0x07 -#define ACI_GET_CD 0x09 -#define ACI_GET_SYNTH 0x0b -#define ACI_GET_PCM 0x0d -#define ACI_GET_LINE1 0x10 /* Radio on PCM20 */ -#define ACI_GET_LINE2 0x12 - -#define ACI_GET_EQ1 0x22 /* from Bass ... */ -#define ACI_GET_EQ2 0x24 -#define ACI_GET_EQ3 0x26 -#define ACI_GET_EQ4 0x28 -#define ACI_GET_EQ5 0x2a -#define ACI_GET_EQ6 0x2c -#define ACI_GET_EQ7 0x2e /* ... to Treble */ - -/* And these are the values for the right channel SET registers. - For left channel access you have to add an offset of 0x08. - MASTER is an exception, which needs an offset of 0x01 */ - -#define ACI_SET_MASTER 0x00 -#define ACI_SET_MIC 0x30 -#define ACI_SET_LINE 0x31 -#define ACI_SET_CD 0x34 -#define ACI_SET_SYNTH 0x33 -#define ACI_SET_PCM 0x32 -#define ACI_SET_LINE1 0x35 /* Radio on PCM20 */ -#define ACI_SET_LINE2 0x36 - -#define ACI_SET_EQ1 0x40 /* from Bass ... */ -#define ACI_SET_EQ2 0x41 -#define ACI_SET_EQ3 0x42 -#define ACI_SET_EQ4 0x43 -#define ACI_SET_EQ5 0x44 -#define ACI_SET_EQ6 0x45 -#define ACI_SET_EQ7 0x46 /* ... to Treble */ - -#endif /* _MIRO_H_ */ -- cgit v1.2.3 From 9dc9120c774e1d7e3d939542200bd44829c0059d Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Sun, 22 Nov 2009 17:26:34 +0100 Subject: ALSA: opti-miro: expose ACI mixer to outside drivers The ACI mixer is used to control the radio FM module installed on the Miro PCM20 sound card. Expose ACI mixer outside the sound card driver. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai --- sound/isa/opti9xx/miro.c | 250 +++++++++++++++++++++++++++-------------------- 1 file changed, 145 insertions(+), 105 deletions(-) (limited to 'sound') diff --git a/sound/isa/opti9xx/miro.c b/sound/isa/opti9xx/miro.c index 932a067ef98..40b64cd54c8 100644 --- a/sound/isa/opti9xx/miro.c +++ b/sound/isa/opti9xx/miro.c @@ -96,7 +96,6 @@ MODULE_PARM_DESC(ide, "enable ide port"); #define OPTi9XX_MC_REG(n) n - struct snd_miro { unsigned short hardware; unsigned char password; @@ -120,17 +119,11 @@ struct snd_miro { long mpu_port; int mpu_irq; - unsigned long aci_port; - int aci_vendor; - int aci_product; - int aci_version; - int aci_amp; - int aci_preamp; - int aci_solomode; - - struct mutex aci_mutex; + struct snd_miro_aci *aci; }; +static struct snd_miro_aci aci_device; + static char * snd_opti9xx_names[] = { "unkown", "82C928", "82C929", @@ -142,13 +135,14 @@ static char * snd_opti9xx_names[] = { * ACI control */ -static int aci_busy_wait(struct snd_miro * miro) +static int aci_busy_wait(struct snd_miro_aci *aci) { long timeout; unsigned char byte; - for (timeout = 1; timeout <= ACI_MINTIME+30; timeout++) { - if (((byte=inb(miro->aci_port + ACI_REG_BUSY)) & 1) == 0) { + for (timeout = 1; timeout <= ACI_MINTIME + 30; timeout++) { + byte = inb(aci->aci_port + ACI_REG_BUSY); + if ((byte & 1) == 0) { if (timeout >= ACI_MINTIME) snd_printd("aci ready in round %ld.\n", timeout-ACI_MINTIME); @@ -174,10 +168,10 @@ static int aci_busy_wait(struct snd_miro * miro) return -EBUSY; } -static inline int aci_write(struct snd_miro * miro, unsigned char byte) +static inline int aci_write(struct snd_miro_aci *aci, unsigned char byte) { - if (aci_busy_wait(miro) >= 0) { - outb(byte, miro->aci_port + ACI_REG_COMMAND); + if (aci_busy_wait(aci) >= 0) { + outb(byte, aci->aci_port + ACI_REG_COMMAND); return 0; } else { snd_printk(KERN_ERR "aci busy, aci_write(0x%x) stopped.\n", byte); @@ -185,12 +179,12 @@ static inline int aci_write(struct snd_miro * miro, unsigned char byte) } } -static inline int aci_read(struct snd_miro * miro) +static inline int aci_read(struct snd_miro_aci *aci) { unsigned char byte; - if (aci_busy_wait(miro) >= 0) { - byte=inb(miro->aci_port + ACI_REG_STATUS); + if (aci_busy_wait(aci) >= 0) { + byte = inb(aci->aci_port + ACI_REG_STATUS); return byte; } else { snd_printk(KERN_ERR "aci busy, aci_read() stopped.\n"); @@ -198,39 +192,49 @@ static inline int aci_read(struct snd_miro * miro) } } -static int aci_cmd(struct snd_miro * miro, int write1, int write2, int write3) +int snd_aci_cmd(struct snd_miro_aci *aci, int write1, int write2, int write3) { int write[] = {write1, write2, write3}; int value, i; - if (mutex_lock_interruptible(&miro->aci_mutex)) + if (mutex_lock_interruptible(&aci->aci_mutex)) return -EINTR; for (i=0; i<3; i++) { if (write[i]< 0 || write[i] > 255) break; else { - value = aci_write(miro, write[i]); + value = aci_write(aci, write[i]); if (value < 0) goto out; } } - value = aci_read(miro); + value = aci_read(aci); -out: mutex_unlock(&miro->aci_mutex); +out: mutex_unlock(&aci->aci_mutex); return value; } +EXPORT_SYMBOL(snd_aci_cmd); + +static int aci_getvalue(struct snd_miro_aci *aci, unsigned char index) +{ + return snd_aci_cmd(aci, ACI_STATUS, index, -1); +} -static int aci_getvalue(struct snd_miro * miro, unsigned char index) +static int aci_setvalue(struct snd_miro_aci *aci, unsigned char index, + int value) { - return aci_cmd(miro, ACI_STATUS, index, -1); + return snd_aci_cmd(aci, index, value, -1); } -static int aci_setvalue(struct snd_miro * miro, unsigned char index, int value) +struct snd_miro_aci *snd_aci_get_aci(void) { - return aci_cmd(miro, index, value, -1); + if (aci_device.aci_port == 0) + return NULL; + return &aci_device; } +EXPORT_SYMBOL(snd_aci_get_aci); /* * MIXER part @@ -244,8 +248,10 @@ static int snd_miro_get_capture(struct snd_kcontrol *kcontrol, struct snd_miro *miro = snd_kcontrol_chip(kcontrol); int value; - if ((value = aci_getvalue(miro, ACI_S_GENERAL)) < 0) { - snd_printk(KERN_ERR "snd_miro_get_capture() failed: %d\n", value); + value = aci_getvalue(miro->aci, ACI_S_GENERAL); + if (value < 0) { + snd_printk(KERN_ERR "snd_miro_get_capture() failed: %d\n", + value); return value; } @@ -262,13 +268,15 @@ static int snd_miro_put_capture(struct snd_kcontrol *kcontrol, value = !(ucontrol->value.integer.value[0]); - if ((error = aci_setvalue(miro, ACI_SET_SOLOMODE, value)) < 0) { - snd_printk(KERN_ERR "snd_miro_put_capture() failed: %d\n", error); + error = aci_setvalue(miro->aci, ACI_SET_SOLOMODE, value); + if (error < 0) { + snd_printk(KERN_ERR "snd_miro_put_capture() failed: %d\n", + error); return error; } - change = (value != miro->aci_solomode); - miro->aci_solomode = value; + change = (value != miro->aci->aci_solomode); + miro->aci->aci_solomode = value; return change; } @@ -290,7 +298,7 @@ static int snd_miro_get_preamp(struct snd_kcontrol *kcontrol, struct snd_miro *miro = snd_kcontrol_chip(kcontrol); int value; - if (miro->aci_version <= 176) { + if (miro->aci->aci_version <= 176) { /* OSS says it's not readable with versions < 176. @@ -298,12 +306,14 @@ static int snd_miro_get_preamp(struct snd_kcontrol *kcontrol, which is a PCM12 with aci_version = 176. */ - ucontrol->value.integer.value[0] = miro->aci_preamp; + ucontrol->value.integer.value[0] = miro->aci->aci_preamp; return 0; } - if ((value = aci_getvalue(miro, ACI_GET_PREAMP)) < 0) { - snd_printk(KERN_ERR "snd_miro_get_preamp() failed: %d\n", value); + value = aci_getvalue(miro->aci, ACI_GET_PREAMP); + if (value < 0) { + snd_printk(KERN_ERR "snd_miro_get_preamp() failed: %d\n", + value); return value; } @@ -320,13 +330,15 @@ static int snd_miro_put_preamp(struct snd_kcontrol *kcontrol, value = ucontrol->value.integer.value[0]; - if ((error = aci_setvalue(miro, ACI_SET_PREAMP, value)) < 0) { - snd_printk(KERN_ERR "snd_miro_put_preamp() failed: %d\n", error); + error = aci_setvalue(miro->aci, ACI_SET_PREAMP, value); + if (error < 0) { + snd_printk(KERN_ERR "snd_miro_put_preamp() failed: %d\n", + error); return error; } - change = (value != miro->aci_preamp); - miro->aci_preamp = value; + change = (value != miro->aci->aci_preamp); + miro->aci->aci_preamp = value; return change; } @@ -337,7 +349,7 @@ static int snd_miro_get_amp(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_miro *miro = snd_kcontrol_chip(kcontrol); - ucontrol->value.integer.value[0] = miro->aci_amp; + ucontrol->value.integer.value[0] = miro->aci->aci_amp; return 0; } @@ -350,13 +362,14 @@ static int snd_miro_put_amp(struct snd_kcontrol *kcontrol, value = ucontrol->value.integer.value[0]; - if ((error = aci_setvalue(miro, ACI_SET_POWERAMP, value)) < 0) { + error = aci_setvalue(miro->aci, ACI_SET_POWERAMP, value); + if (error < 0) { snd_printk(KERN_ERR "snd_miro_put_amp() to %d failed: %d\n", value, error); return error; } - change = (value != miro->aci_amp); - miro->aci_amp = value; + change = (value != miro->aci->aci_amp); + miro->aci->aci_amp = value; return change; } @@ -405,12 +418,14 @@ static int snd_miro_get_double(struct snd_kcontrol *kcontrol, int right_reg = kcontrol->private_value & 0xff; int left_reg = right_reg + 1; - if ((right_val = aci_getvalue(miro, right_reg)) < 0) { + right_val = aci_getvalue(miro->aci, right_reg); + if (right_val < 0) { snd_printk(KERN_ERR "aci_getvalue(%d) failed: %d\n", right_reg, right_val); return right_val; } - if ((left_val = aci_getvalue(miro, left_reg)) < 0) { + left_val = aci_getvalue(miro->aci, left_reg); + if (left_val < 0) { snd_printk(KERN_ERR "aci_getvalue(%d) failed: %d\n", left_reg, left_val); return left_val; } @@ -446,6 +461,7 @@ static int snd_miro_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_miro *miro = snd_kcontrol_chip(kcontrol); + struct snd_miro_aci *aci = miro->aci; int left, right, left_old, right_old; int setreg_left, setreg_right, getreg_left, getreg_right; int change, error; @@ -461,12 +477,14 @@ static int snd_miro_put_double(struct snd_kcontrol *kcontrol, getreg_right = kcontrol->private_value & 0xff; getreg_left = getreg_right + 1; - if ((left_old = aci_getvalue(miro, getreg_left)) < 0) { + left_old = aci_getvalue(aci, getreg_left); + if (left_old < 0) { snd_printk(KERN_ERR "aci_getvalue(%d) failed: %d\n", getreg_left, left_old); return left_old; } - if ((right_old = aci_getvalue(miro, getreg_right)) < 0) { + right_old = aci_getvalue(aci, getreg_right); + if (right_old < 0) { snd_printk(KERN_ERR "aci_getvalue(%d) failed: %d\n", getreg_right, right_old); return right_old; } @@ -485,13 +503,15 @@ static int snd_miro_put_double(struct snd_kcontrol *kcontrol, right_old = 0x80 - right_old; if (left >= 0) { - if ((error = aci_setvalue(miro, setreg_left, left)) < 0) { + error = aci_setvalue(aci, setreg_left, left); + if (error < 0) { snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n", left, error); return error; } } else { - if ((error = aci_setvalue(miro, setreg_left, 0x80 - left)) < 0) { + error = aci_setvalue(aci, setreg_left, 0x80 - left); + if (error < 0) { snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n", 0x80 - left, error); return error; @@ -499,13 +519,15 @@ static int snd_miro_put_double(struct snd_kcontrol *kcontrol, } if (right >= 0) { - if ((error = aci_setvalue(miro, setreg_right, right)) < 0) { + error = aci_setvalue(aci, setreg_right, right); + if (error < 0) { snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n", right, error); return error; } } else { - if ((error = aci_setvalue(miro, setreg_right, 0x80 - right)) < 0) { + error = aci_setvalue(aci, setreg_right, 0x80 - right); + if (error < 0) { snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n", 0x80 - right, error); return error; @@ -523,12 +545,14 @@ static int snd_miro_put_double(struct snd_kcontrol *kcontrol, left_old = 0x20 - left_old; right_old = 0x20 - right_old; - if ((error = aci_setvalue(miro, setreg_left, 0x20 - left)) < 0) { + error = aci_setvalue(aci, setreg_left, 0x20 - left); + if (error < 0) { snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n", 0x20 - left, error); return error; } - if ((error = aci_setvalue(miro, setreg_right, 0x20 - right)) < 0) { + error = aci_setvalue(aci, setreg_right, 0x20 - right); + if (error < 0) { snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n", 0x20 - right, error); return error; @@ -626,11 +650,13 @@ static unsigned char aci_init_values[][2] __devinitdata = { static int __devinit snd_set_aci_init_values(struct snd_miro *miro) { int idx, error; + struct snd_miro_aci *aci = miro->aci; /* enable WSS on PCM1 */ - if ((miro->aci_product == 'A') && wss) { - if ((error = aci_setvalue(miro, ACI_SET_WSS, wss)) < 0) { + if ((aci->aci_product == 'A') && wss) { + error = aci_setvalue(aci, ACI_SET_WSS, wss); + if (error < 0) { snd_printk(KERN_ERR "enabling WSS mode failed\n"); return error; } @@ -639,7 +665,8 @@ static int __devinit snd_set_aci_init_values(struct snd_miro *miro) /* enable IDE port */ if (ide) { - if ((error = aci_setvalue(miro, ACI_SET_IDE, ide)) < 0) { + error = aci_setvalue(aci, ACI_SET_IDE, ide); + if (error < 0) { snd_printk(KERN_ERR "enabling IDE port failed\n"); return error; } @@ -647,17 +674,18 @@ static int __devinit snd_set_aci_init_values(struct snd_miro *miro) /* set common aci values */ - for (idx = 0; idx < ARRAY_SIZE(aci_init_values); idx++) - if ((error = aci_setvalue(miro, aci_init_values[idx][0], - aci_init_values[idx][1])) < 0) { + for (idx = 0; idx < ARRAY_SIZE(aci_init_values); idx++) { + error = aci_setvalue(aci, aci_init_values[idx][0], + aci_init_values[idx][1]); + if (error < 0) { snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n", aci_init_values[idx][0], error); return error; } - - miro->aci_amp = 0; - miro->aci_preamp = 0; - miro->aci_solomode = 1; + } + aci->aci_amp = 0; + aci->aci_preamp = 0; + aci->aci_solomode = 1; return 0; } @@ -688,7 +716,8 @@ static int __devinit snd_miro_mixer(struct snd_card *card, return err; } - if ((miro->aci_product == 'A') || (miro->aci_product == 'B')) { + if ((miro->aci->aci_product == 'A') || + (miro->aci->aci_product == 'B')) { /* PCM1/PCM12 with power-amp and Line 2 */ if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_line_control[0], miro))) < 0) return err; @@ -696,16 +725,17 @@ static int __devinit snd_miro_mixer(struct snd_card *card, return err; } - if ((miro->aci_product == 'B') || (miro->aci_product == 'C')) { + if ((miro->aci->aci_product == 'B') || + (miro->aci->aci_product == 'C')) { /* PCM12/PCM20 with mic-preamp */ if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_preamp_control[0], miro))) < 0) return err; - if (miro->aci_version >= 176) + if (miro->aci->aci_version >= 176) if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_capture_control[0], miro))) < 0) return err; } - if (miro->aci_product == 'C') { + if (miro->aci->aci_product == 'C') { /* PCM20 with radio and 7 band equalizer */ if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_radio_control[0], miro))) < 0) return err; @@ -843,14 +873,15 @@ static void snd_miro_proc_read(struct snd_info_entry * entry, struct snd_info_buffer *buffer) { struct snd_miro *miro = (struct snd_miro *) entry->private_data; + struct snd_miro_aci *aci = miro->aci; char* model = "unknown"; /* miroSOUND PCM1 pro, early PCM12 */ if ((miro->hardware == OPTi9XX_HW_82C929) && - (miro->aci_vendor == 'm') && - (miro->aci_product == 'A')) { - switch(miro->aci_version) { + (aci->aci_vendor == 'm') && + (aci->aci_product == 'A')) { + switch (aci->aci_version) { case 3: model = "miroSOUND PCM1 pro"; break; @@ -863,9 +894,9 @@ static void snd_miro_proc_read(struct snd_info_entry * entry, /* miroSOUND PCM12, PCM12 (Rev. E), PCM12 pnp */ if ((miro->hardware == OPTi9XX_HW_82C924) && - (miro->aci_vendor == 'm') && - (miro->aci_product == 'B')) { - switch(miro->aci_version) { + (aci->aci_vendor == 'm') && + (aci->aci_product == 'B')) { + switch (aci->aci_version) { case 4: model = "miroSOUND PCM12"; break; @@ -881,9 +912,9 @@ static void snd_miro_proc_read(struct snd_info_entry * entry, /* miroSOUND PCM20 radio */ if ((miro->hardware == OPTi9XX_HW_82C924) && - (miro->aci_vendor == 'm') && - (miro->aci_product == 'C')) { - switch(miro->aci_version) { + (aci->aci_vendor == 'm') && + (aci->aci_product == 'C')) { + switch (aci->aci_version) { case 7: model = "miroSOUND PCM20 radio (Rev. E)"; break; @@ -907,17 +938,17 @@ static void snd_miro_proc_read(struct snd_info_entry * entry, snd_iprintf(buffer, "ACI information:\n"); snd_iprintf(buffer, " vendor : "); - switch(miro->aci_vendor) { + switch (aci->aci_vendor) { case 'm': snd_iprintf(buffer, "Miro\n"); break; default: - snd_iprintf(buffer, "unknown (0x%x)\n", miro->aci_vendor); + snd_iprintf(buffer, "unknown (0x%x)\n", aci->aci_vendor); break; } snd_iprintf(buffer, " product : "); - switch(miro->aci_product) { + switch (aci->aci_product) { case 'A': snd_iprintf(buffer, "miroSOUND PCM1 pro / (early) PCM12\n"); break; @@ -928,19 +959,19 @@ static void snd_miro_proc_read(struct snd_info_entry * entry, snd_iprintf(buffer, "miroSOUND PCM20 radio\n"); break; default: - snd_iprintf(buffer, "unknown (0x%x)\n", miro->aci_product); + snd_iprintf(buffer, "unknown (0x%x)\n", aci->aci_product); break; } snd_iprintf(buffer, " firmware: %d (0x%x)\n", - miro->aci_version, miro->aci_version); + aci->aci_version, aci->aci_version); snd_iprintf(buffer, " port : 0x%lx-0x%lx\n", - miro->aci_port, miro->aci_port+2); + aci->aci_port, aci->aci_port+2); snd_iprintf(buffer, " wss : 0x%x\n", wss); snd_iprintf(buffer, " ide : 0x%x\n", ide); - snd_iprintf(buffer, " solomode: 0x%x\n", miro->aci_solomode); - snd_iprintf(buffer, " amp : 0x%x\n", miro->aci_amp); - snd_iprintf(buffer, " preamp : 0x%x\n", miro->aci_preamp); + snd_iprintf(buffer, " solomode: 0x%x\n", aci->aci_solomode); + snd_iprintf(buffer, " amp : 0x%x\n", aci->aci_amp); + snd_iprintf(buffer, " preamp : 0x%x\n", aci->aci_preamp); } static void __devinit snd_miro_proc_init(struct snd_card *card, @@ -1139,46 +1170,53 @@ static int __devinit snd_card_miro_detect(struct snd_card *card, } static int __devinit snd_card_miro_aci_detect(struct snd_card *card, - struct snd_miro * miro) + struct snd_miro *miro) { unsigned char regval; int i; + struct snd_miro_aci *aci = &aci_device; + + miro->aci = aci; - mutex_init(&miro->aci_mutex); + mutex_init(&aci->aci_mutex); /* get ACI port from OPTi9xx MC 4 */ regval=inb(miro->mc_base + 4); - miro->aci_port = (regval & 0x10) ? 0x344: 0x354; + aci->aci_port = (regval & 0x10) ? 0x344 : 0x354; - if ((miro->res_aci_port = request_region(miro->aci_port, 3, "miro aci")) == NULL) { + miro->res_aci_port = request_region(aci->aci_port, 3, "miro aci"); + if (miro->res_aci_port == NULL) { snd_printk(KERN_ERR "aci i/o area 0x%lx-0x%lx already used.\n", - miro->aci_port, miro->aci_port+2); + aci->aci_port, aci->aci_port+2); return -ENOMEM; } /* force ACI into a known state */ for (i = 0; i < 3; i++) - if (aci_cmd(miro, ACI_ERROR_OP, -1, -1) < 0) { + if (snd_aci_cmd(aci, ACI_ERROR_OP, -1, -1) < 0) { snd_printk(KERN_ERR "can't force aci into known state.\n"); return -ENXIO; } - if ((miro->aci_vendor=aci_cmd(miro, ACI_READ_IDCODE, -1, -1)) < 0 || - (miro->aci_product=aci_cmd(miro, ACI_READ_IDCODE, -1, -1)) < 0) { - snd_printk(KERN_ERR "can't read aci id on 0x%lx.\n", miro->aci_port); + aci->aci_vendor = snd_aci_cmd(aci, ACI_READ_IDCODE, -1, -1); + aci->aci_product = snd_aci_cmd(aci, ACI_READ_IDCODE, -1, -1); + if (aci->aci_vendor < 0 || aci->aci_product < 0) { + snd_printk(KERN_ERR "can't read aci id on 0x%lx.\n", + aci->aci_port); return -ENXIO; } - if ((miro->aci_version=aci_cmd(miro, ACI_READ_VERSION, -1, -1)) < 0) { + aci->aci_version = snd_aci_cmd(aci, ACI_READ_VERSION, -1, -1); + if (aci->aci_version < 0) { snd_printk(KERN_ERR "can't read aci version on 0x%lx.\n", - miro->aci_port); + aci->aci_port); return -ENXIO; } - if (aci_cmd(miro, ACI_INIT, -1, -1) < 0 || - aci_cmd(miro, ACI_ERROR_OP, ACI_ERROR_OP, ACI_ERROR_OP) < 0 || - aci_cmd(miro, ACI_ERROR_OP, ACI_ERROR_OP, ACI_ERROR_OP) < 0) { + if (snd_aci_cmd(aci, ACI_INIT, -1, -1) < 0 || + snd_aci_cmd(aci, ACI_ERROR_OP, ACI_ERROR_OP, ACI_ERROR_OP) < 0 || + snd_aci_cmd(aci, ACI_ERROR_OP, ACI_ERROR_OP, ACI_ERROR_OP) < 0) { snd_printk(KERN_ERR "can't initialize aci.\n"); return -ENXIO; } @@ -1191,6 +1229,7 @@ static void snd_card_miro_free(struct snd_card *card) struct snd_miro *miro = card->private_data; release_and_free_resource(miro->res_aci_port); + miro->aci->aci_port = 0; release_and_free_resource(miro->res_mc_base); } @@ -1250,7 +1289,6 @@ static int __devinit snd_miro_probe(struct device *devptr, unsigned int n) } miro->wss_base = port; - miro->mpu_port = mpu_port; miro->irq = irq; miro->mpu_irq = mpu_irq; miro->dma1 = dma1; @@ -1272,6 +1310,8 @@ static int __devinit snd_miro_probe(struct device *devptr, unsigned int n) return -EBUSY; } } + miro->mpu_port = mpu_port; + if (miro->irq == SNDRV_AUTO_IRQ) { if ((miro->irq = snd_legacy_find_free_irq(possible_irqs)) < 0) { snd_card_free(card); @@ -1339,9 +1379,9 @@ static int __devinit snd_miro_probe(struct device *devptr, unsigned int n) return error; } - if (miro->aci_vendor == 'm') { + if (miro->aci->aci_vendor == 'm') { /* It looks like a miro sound card. */ - switch (miro->aci_product) { + switch (miro->aci->aci_product) { case 'A': sprintf(card->shortname, "miroSOUND PCM1 pro / PCM12"); -- cgit v1.2.3 From 88cdca9c7376f2220171d09dfc2f9e41b4834435 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 23 Nov 2009 09:44:10 +0100 Subject: ALSA: AACI cleanup Fix the buffer size calculation to use the size which ALSA is expecting. Signed-off-by: Russell King Signed-off-by: Takashi Iwai --- sound/arm/aaci.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c index 1f0f8213e2d..a03fe80a7a7 100644 --- a/sound/arm/aaci.c +++ b/sound/arm/aaci.c @@ -18,10 +18,7 @@ #include #include #include - -#include -#include -#include +#include #include #include @@ -534,7 +531,7 @@ static int aaci_pcm_prepare(struct snd_pcm_substream *substream) struct aaci_runtime *aacirun = runtime->private_data; aacirun->start = (void *)runtime->dma_area; - aacirun->end = aacirun->start + runtime->dma_bytes; + aacirun->end = aacirun->start + snd_pcm_lib_buffer_bytes(substream); aacirun->ptr = aacirun->start; aacirun->period = aacirun->bytes = frames_to_bytes(runtime, runtime->period_size); -- cgit v1.2.3 From 50b6bce59d154b5db137907a5c0ed45a4e7a3829 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 23 Nov 2009 13:11:53 +0000 Subject: ASoC: Fix suspend with active audio streams When we get a stream suspend event force the power down since otherwise the stream would remain marked as active. In future we'll probably want to make this stream-specific and add an interface to make the power down of other widgets optional in order to support leaving bypass paths active while suspending the processor. Cc: stable@kernel.org Reported-by: Joonyoung Shim Tested-by: Joonyoung Shim Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index d89f6dc0090..66d4c165f99 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -973,9 +973,19 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event) if (!w->power_check) continue; - power = w->power_check(w); - if (power) - sys_power = 1; + /* If we're suspending then pull down all the + * power. */ + switch (event) { + case SND_SOC_DAPM_STREAM_SUSPEND: + power = 0; + break; + + default: + power = w->power_check(w); + if (power) + sys_power = 1; + break; + } if (w->power == power) continue; @@ -999,8 +1009,12 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event) case SND_SOC_DAPM_STREAM_RESUME: sys_power = 1; break; + case SND_SOC_DAPM_STREAM_SUSPEND: + sys_power = 0; + break; case SND_SOC_DAPM_STREAM_NOP: sys_power = codec->bias_level != SND_SOC_BIAS_STANDBY; + break; default: break; } -- cgit v1.2.3 From 96f61d9ade82f3e9503df36809175325e8f5eaca Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Thu, 22 Oct 2009 09:06:19 +0200 Subject: sound: usb-audio: allow switching altsetting on Roland USB MIDI devices Add a mixer control to select between the two altsettings on Roland USB MIDI devices where the input endpoint is either bulk or interrupt. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/usb/usbmidi.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 106 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c index e5b06899637..80b2845bc48 100644 --- a/sound/usb/usbmidi.c +++ b/sound/usb/usbmidi.c @@ -1,7 +1,7 @@ /* * usbmidi.c - ALSA USB MIDI driver * - * Copyright (c) 2002-2007 Clemens Ladisch + * Copyright (c) 2002-2009 Clemens Ladisch * All rights reserved. * * Based on the OSS usb-midi driver by NAGANO Daisuke, @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include "usbaudio.h" @@ -109,13 +110,17 @@ struct snd_usb_midi { struct list_head list; struct timer_list error_timer; spinlock_t disc_lock; + struct mutex mutex; struct snd_usb_midi_endpoint { struct snd_usb_midi_out_endpoint *out; struct snd_usb_midi_in_endpoint *in; } endpoints[MIDI_MAX_ENDPOINTS]; unsigned long input_triggered; + unsigned int opened; unsigned char disconnected; + + struct snd_kcontrol *roland_load_ctl; }; struct snd_usb_midi_out_endpoint { @@ -879,6 +884,50 @@ static struct usb_protocol_ops snd_usbmidi_emagic_ops = { }; +static void update_roland_altsetting(struct snd_usb_midi* umidi) +{ + struct usb_interface *intf; + struct usb_host_interface *hostif; + struct usb_interface_descriptor *intfd; + int is_light_load; + + intf = umidi->iface; + is_light_load = intf->cur_altsetting != intf->altsetting; + if (umidi->roland_load_ctl->private_value == is_light_load) + return; + hostif = &intf->altsetting[umidi->roland_load_ctl->private_value]; + intfd = get_iface_desc(hostif); + snd_usbmidi_input_stop(&umidi->list); + usb_set_interface(umidi->chip->dev, intfd->bInterfaceNumber, + intfd->bAlternateSetting); + snd_usbmidi_input_start(&umidi->list); +} + +static void substream_open(struct snd_rawmidi_substream *substream, int open) +{ + struct snd_usb_midi* umidi = substream->rmidi->private_data; + struct snd_kcontrol *ctl; + + mutex_lock(&umidi->mutex); + if (open) { + if (umidi->opened++ == 0 && umidi->roland_load_ctl) { + ctl = umidi->roland_load_ctl; + ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; + snd_ctl_notify(umidi->chip->card, + SNDRV_CTL_EVENT_MASK_INFO, &ctl->id); + update_roland_altsetting(umidi); + } + } else { + if (--umidi->opened == 0 && umidi->roland_load_ctl) { + ctl = umidi->roland_load_ctl; + ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; + snd_ctl_notify(umidi->chip->card, + SNDRV_CTL_EVENT_MASK_INFO, &ctl->id); + } + } + mutex_unlock(&umidi->mutex); +} + static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream) { struct snd_usb_midi* umidi = substream->rmidi->private_data; @@ -898,11 +947,13 @@ static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream) } substream->runtime->private_data = port; port->state = STATE_UNKNOWN; + substream_open(substream, 1); return 0; } static int snd_usbmidi_output_close(struct snd_rawmidi_substream *substream) { + substream_open(substream, 0); return 0; } @@ -954,11 +1005,13 @@ static void snd_usbmidi_output_drain(struct snd_rawmidi_substream *substream) static int snd_usbmidi_input_open(struct snd_rawmidi_substream *substream) { + substream_open(substream, 1); return 0; } static int snd_usbmidi_input_close(struct snd_rawmidi_substream *substream) { + substream_open(substream, 0); return 0; } @@ -1163,6 +1216,7 @@ static void snd_usbmidi_free(struct snd_usb_midi* umidi) if (ep->in) snd_usbmidi_in_endpoint_delete(ep->in); } + mutex_destroy(&umidi->mutex); kfree(umidi); } @@ -1524,6 +1578,52 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi* umidi, return 0; } +static int roland_load_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *info) +{ + static const char *const names[] = { "High Load", "Light Load" }; + + info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + info->count = 1; + info->value.enumerated.items = 2; + if (info->value.enumerated.item > 1) + info->value.enumerated.item = 1; + strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); + return 0; +} + +static int roland_load_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *value) +{ + value->value.enumerated.item[0] = kcontrol->private_value; + return 0; +} + +static int roland_load_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *value) +{ + struct snd_usb_midi* umidi = kcontrol->private_data; + int changed; + + if (value->value.enumerated.item[0] > 1) + return -EINVAL; + mutex_lock(&umidi->mutex); + changed = value->value.enumerated.item[0] != kcontrol->private_value; + if (changed) + kcontrol->private_value = value->value.enumerated.item[0]; + mutex_unlock(&umidi->mutex); + return changed; +} + +static struct snd_kcontrol_new roland_load_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "MIDI Input Mode", + .info = roland_load_info, + .get = roland_load_get, + .put = roland_load_put, + .private_value = 1, +}; + /* * On Roland devices, use the second alternate setting to be able to use * the interrupt input endpoint. @@ -1549,6 +1649,10 @@ static void snd_usbmidi_switch_roland_altsetting(struct snd_usb_midi* umidi) intfd->bAlternateSetting); usb_set_interface(umidi->chip->dev, intfd->bInterfaceNumber, intfd->bAlternateSetting); + + umidi->roland_load_ctl = snd_ctl_new1(&roland_load_ctl, umidi); + if (snd_ctl_add(umidi->chip->card, umidi->roland_load_ctl) < 0) + umidi->roland_load_ctl = NULL; } /* @@ -1834,6 +1938,7 @@ int snd_usb_create_midi_interface(struct snd_usb_audio* chip, umidi->usb_protocol_ops = &snd_usbmidi_standard_ops; init_timer(&umidi->error_timer); spin_lock_init(&umidi->disc_lock); + mutex_init(&umidi->mutex); umidi->error_timer.function = snd_usbmidi_error_timer; umidi->error_timer.data = (unsigned long)umidi; -- cgit v1.2.3 From d82af9f9aab69e82b86450272588c861364f8879 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 16 Nov 2009 12:23:46 +0100 Subject: sound: usb: make the USB MIDI module more independent Remove the dependecy from the USB MIDI code on the snd_usb_audio structure. This allows using the USB MIDI module from another driver without having to pretend to be the generic USB audio driver. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/usb/usbaudio.c | 38 +++++++++------- sound/usb/usbaudio.h | 7 +-- sound/usb/usbmidi.c | 96 ++++++++++++++++++++++------------------- sound/usb/usx2y/us122l.c | 22 +++++----- sound/usb/usx2y/us122l.h | 1 + sound/usb/usx2y/usX2Yhwdep.c | 2 +- sound/usb/usx2y/usbusx2y.c | 4 +- sound/usb/usx2y/usbusx2y.h | 1 + sound/usb/usx2y/usbusx2yaudio.c | 4 +- 9 files changed, 96 insertions(+), 79 deletions(-) (limited to 'sound') diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 8db0374e10d..b074a594c59 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -2893,7 +2893,9 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif) if ((altsd->bInterfaceClass == USB_CLASS_AUDIO || altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC) && altsd->bInterfaceSubClass == USB_SUBCLASS_MIDI_STREAMING) { - if (snd_usb_create_midi_interface(chip, iface, NULL) < 0) { + int err = snd_usbmidi_create(chip->card, iface, + &chip->midi_list, NULL); + if (err < 0) { snd_printk(KERN_ERR "%d:%u:%d: cannot create sequencer device\n", dev->devnum, ctrlif, j); continue; } @@ -3038,12 +3040,11 @@ static int create_uaxx_quirk(struct snd_usb_audio *chip, .type = QUIRK_MIDI_FIXED_ENDPOINT, .data = &uaxx_ep }; - if (chip->usb_id == USB_ID(0x0582, 0x002b)) - return snd_usb_create_midi_interface(chip, iface, - &ua700_quirk); - else - return snd_usb_create_midi_interface(chip, iface, - &uaxx_quirk); + const struct snd_usb_audio_quirk *quirk = + chip->usb_id == USB_ID(0x0582, 0x002b) + ? &ua700_quirk : &uaxx_quirk; + return snd_usbmidi_create(chip->card, iface, + &chip->midi_list, quirk); } if (altsd->bNumEndpoints != 1) @@ -3370,6 +3371,13 @@ static int audiophile_skip_setting_quirk(struct snd_usb_audio *chip, return 0; /* keep this altsetting */ } +static int create_any_midi_quirk(struct snd_usb_audio *chip, + struct usb_interface *intf, + const struct snd_usb_audio_quirk *quirk) +{ + return snd_usbmidi_create(chip->card, intf, &chip->midi_list, quirk); +} + /* * audio-interface quirks * @@ -3387,14 +3395,14 @@ static int snd_usb_create_quirk(struct snd_usb_audio *chip, static const quirk_func_t quirk_funcs[] = { [QUIRK_IGNORE_INTERFACE] = ignore_interface_quirk, [QUIRK_COMPOSITE] = create_composite_quirk, - [QUIRK_MIDI_STANDARD_INTERFACE] = snd_usb_create_midi_interface, - [QUIRK_MIDI_FIXED_ENDPOINT] = snd_usb_create_midi_interface, - [QUIRK_MIDI_YAMAHA] = snd_usb_create_midi_interface, - [QUIRK_MIDI_MIDIMAN] = snd_usb_create_midi_interface, - [QUIRK_MIDI_NOVATION] = snd_usb_create_midi_interface, - [QUIRK_MIDI_FASTLANE] = snd_usb_create_midi_interface, - [QUIRK_MIDI_EMAGIC] = snd_usb_create_midi_interface, - [QUIRK_MIDI_CME] = snd_usb_create_midi_interface, + [QUIRK_MIDI_STANDARD_INTERFACE] = create_any_midi_quirk, + [QUIRK_MIDI_FIXED_ENDPOINT] = create_any_midi_quirk, + [QUIRK_MIDI_YAMAHA] = create_any_midi_quirk, + [QUIRK_MIDI_MIDIMAN] = create_any_midi_quirk, + [QUIRK_MIDI_NOVATION] = create_any_midi_quirk, + [QUIRK_MIDI_FASTLANE] = create_any_midi_quirk, + [QUIRK_MIDI_EMAGIC] = create_any_midi_quirk, + [QUIRK_MIDI_CME] = create_any_midi_quirk, [QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk, [QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk, [QUIRK_AUDIO_EDIROL_UA1000] = create_ua1000_quirk, diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index e9a3a9dca15..40ba8115fb8 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -132,7 +132,6 @@ struct snd_usb_audio { int pcm_devs; struct list_head midi_list; /* list of midi interfaces */ - int next_midi_device; struct list_head mixer_list; /* list of mixer interfaces */ }; @@ -227,8 +226,10 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, int ignore_error); void snd_usb_mixer_disconnect(struct list_head *p); -int snd_usb_create_midi_interface(struct snd_usb_audio *chip, struct usb_interface *iface, - const struct snd_usb_audio_quirk *quirk); +int snd_usbmidi_create(struct snd_card *card, + struct usb_interface *iface, + struct list_head *midi_list, + const struct snd_usb_audio_quirk *quirk); void snd_usbmidi_input_stop(struct list_head* p); void snd_usbmidi_input_start(struct list_head* p); void snd_usbmidi_disconnect(struct list_head *p); diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c index 80b2845bc48..6e89b8368d9 100644 --- a/sound/usb/usbmidi.c +++ b/sound/usb/usbmidi.c @@ -102,7 +102,8 @@ struct usb_protocol_ops { }; struct snd_usb_midi { - struct snd_usb_audio *chip; + struct usb_device *dev; + struct snd_card *card; struct usb_interface *iface; const struct snd_usb_audio_quirk *quirk; struct snd_rawmidi *rmidi; @@ -111,6 +112,8 @@ struct snd_usb_midi { struct timer_list error_timer; spinlock_t disc_lock; struct mutex mutex; + u32 usb_id; + int next_midi_device; struct snd_usb_midi_endpoint { struct snd_usb_midi_out_endpoint *out; @@ -260,7 +263,7 @@ static void snd_usbmidi_in_urb_complete(struct urb* urb) } } - urb->dev = ep->umidi->chip->dev; + urb->dev = ep->umidi->dev; snd_usbmidi_submit_urb(urb, GFP_ATOMIC); } @@ -301,7 +304,7 @@ static void snd_usbmidi_do_output(struct snd_usb_midi_out_endpoint* ep) unsigned long flags; spin_lock_irqsave(&ep->buffer_lock, flags); - if (ep->umidi->chip->shutdown) { + if (ep->umidi->disconnected) { spin_unlock_irqrestore(&ep->buffer_lock, flags); return; } @@ -317,7 +320,7 @@ static void snd_usbmidi_do_output(struct snd_usb_midi_out_endpoint* ep) dump_urb("sending", urb->transfer_buffer, urb->transfer_buffer_length); - urb->dev = ep->umidi->chip->dev; + urb->dev = ep->umidi->dev; if (snd_usbmidi_submit_urb(urb, GFP_ATOMIC) < 0) break; ep->active_urbs |= 1 << urb_index; @@ -354,7 +357,7 @@ static void snd_usbmidi_error_timer(unsigned long data) if (in && in->error_resubmit) { in->error_resubmit = 0; for (j = 0; j < INPUT_URBS; ++j) { - in->urbs[j]->dev = umidi->chip->dev; + in->urbs[j]->dev = umidi->dev; snd_usbmidi_submit_urb(in->urbs[j], GFP_ATOMIC); } } @@ -374,7 +377,7 @@ static int send_bulk_static_data(struct snd_usb_midi_out_endpoint* ep, return -ENOMEM; dump_urb("sending", buf, len); if (ep->urbs[0].urb) - err = usb_bulk_msg(ep->umidi->chip->dev, ep->urbs[0].urb->pipe, + err = usb_bulk_msg(ep->umidi->dev, ep->urbs[0].urb->pipe, buf, len, NULL, 250); kfree(buf); return err; @@ -729,8 +732,7 @@ static void snd_usbmidi_us122l_output(struct snd_usb_midi_out_endpoint *ep, if (!ep->ports[0].active) return; - count = snd_usb_get_speed(ep->umidi->chip->dev) == USB_SPEED_HIGH - ? 1 : 2; + count = snd_usb_get_speed(ep->umidi->dev) == USB_SPEED_HIGH ? 1 : 2; count = snd_rawmidi_transmit(ep->ports[0].substream, urb->transfer_buffer, count); @@ -898,7 +900,7 @@ static void update_roland_altsetting(struct snd_usb_midi* umidi) hostif = &intf->altsetting[umidi->roland_load_ctl->private_value]; intfd = get_iface_desc(hostif); snd_usbmidi_input_stop(&umidi->list); - usb_set_interface(umidi->chip->dev, intfd->bInterfaceNumber, + usb_set_interface(umidi->dev, intfd->bInterfaceNumber, intfd->bAlternateSetting); snd_usbmidi_input_start(&umidi->list); } @@ -913,7 +915,7 @@ static void substream_open(struct snd_rawmidi_substream *substream, int open) if (umidi->opened++ == 0 && umidi->roland_load_ctl) { ctl = umidi->roland_load_ctl; ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; - snd_ctl_notify(umidi->chip->card, + snd_ctl_notify(umidi->card, SNDRV_CTL_EVENT_MASK_INFO, &ctl->id); update_roland_altsetting(umidi); } @@ -921,7 +923,7 @@ static void substream_open(struct snd_rawmidi_substream *substream, int open) if (--umidi->opened == 0 && umidi->roland_load_ctl) { ctl = umidi->roland_load_ctl; ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; - snd_ctl_notify(umidi->chip->card, + snd_ctl_notify(umidi->card, SNDRV_CTL_EVENT_MASK_INFO, &ctl->id); } } @@ -963,7 +965,7 @@ static void snd_usbmidi_output_trigger(struct snd_rawmidi_substream *substream, port->active = up; if (up) { - if (port->ep->umidi->chip->shutdown) { + if (port->ep->umidi->disconnected) { /* gobble up remaining bytes to prevent wait in * snd_rawmidi_drain_output */ while (!snd_rawmidi_transmit_empty(substream)) @@ -1041,7 +1043,7 @@ static struct snd_rawmidi_ops snd_usbmidi_input_ops = { static void free_urb_and_buffer(struct snd_usb_midi *umidi, struct urb *urb, unsigned int buffer_length) { - usb_buffer_free(umidi->chip->dev, buffer_length, + usb_buffer_free(umidi->dev, buffer_length, urb->transfer_buffer, urb->transfer_dma); usb_free_urb(urb); } @@ -1088,24 +1090,24 @@ static int snd_usbmidi_in_endpoint_create(struct snd_usb_midi* umidi, } } if (ep_info->in_interval) - pipe = usb_rcvintpipe(umidi->chip->dev, ep_info->in_ep); + pipe = usb_rcvintpipe(umidi->dev, ep_info->in_ep); else - pipe = usb_rcvbulkpipe(umidi->chip->dev, ep_info->in_ep); - length = usb_maxpacket(umidi->chip->dev, pipe, 0); + pipe = usb_rcvbulkpipe(umidi->dev, ep_info->in_ep); + length = usb_maxpacket(umidi->dev, pipe, 0); for (i = 0; i < INPUT_URBS; ++i) { - buffer = usb_buffer_alloc(umidi->chip->dev, length, GFP_KERNEL, + buffer = usb_buffer_alloc(umidi->dev, length, GFP_KERNEL, &ep->urbs[i]->transfer_dma); if (!buffer) { snd_usbmidi_in_endpoint_delete(ep); return -ENOMEM; } if (ep_info->in_interval) - usb_fill_int_urb(ep->urbs[i], umidi->chip->dev, + usb_fill_int_urb(ep->urbs[i], umidi->dev, pipe, buffer, length, snd_usbmidi_in_urb_complete, ep, ep_info->in_interval); else - usb_fill_bulk_urb(ep->urbs[i], umidi->chip->dev, + usb_fill_bulk_urb(ep->urbs[i], umidi->dev, pipe, buffer, length, snd_usbmidi_in_urb_complete, ep); ep->urbs[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP; @@ -1157,15 +1159,15 @@ static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi* umidi, ep->urbs[i].ep = ep; } if (ep_info->out_interval) - pipe = usb_sndintpipe(umidi->chip->dev, ep_info->out_ep); + pipe = usb_sndintpipe(umidi->dev, ep_info->out_ep); else - pipe = usb_sndbulkpipe(umidi->chip->dev, ep_info->out_ep); - if (umidi->chip->usb_id == USB_ID(0x0a92, 0x1020)) /* ESI M4U */ + pipe = usb_sndbulkpipe(umidi->dev, ep_info->out_ep); + if (umidi->usb_id == USB_ID(0x0a92, 0x1020)) /* ESI M4U */ ep->max_transfer = 4; else - ep->max_transfer = usb_maxpacket(umidi->chip->dev, pipe, 1); + ep->max_transfer = usb_maxpacket(umidi->dev, pipe, 1); for (i = 0; i < OUTPUT_URBS; ++i) { - buffer = usb_buffer_alloc(umidi->chip->dev, + buffer = usb_buffer_alloc(umidi->dev, ep->max_transfer, GFP_KERNEL, &ep->urbs[i].urb->transfer_dma); if (!buffer) { @@ -1173,12 +1175,12 @@ static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi* umidi, return -ENOMEM; } if (ep_info->out_interval) - usb_fill_int_urb(ep->urbs[i].urb, umidi->chip->dev, + usb_fill_int_urb(ep->urbs[i].urb, umidi->dev, pipe, buffer, ep->max_transfer, snd_usbmidi_out_urb_complete, &ep->urbs[i], ep_info->out_interval); else - usb_fill_bulk_urb(ep->urbs[i].urb, umidi->chip->dev, + usb_fill_bulk_urb(ep->urbs[i].urb, umidi->dev, pipe, buffer, ep->max_transfer, snd_usbmidi_out_urb_complete, &ep->urbs[i]); @@ -1412,7 +1414,7 @@ static struct port_info *find_port_info(struct snd_usb_midi* umidi, int number) int i; for (i = 0; i < ARRAY_SIZE(snd_usbmidi_port_info); ++i) { - if (snd_usbmidi_port_info[i].id == umidi->chip->usb_id && + if (snd_usbmidi_port_info[i].id == umidi->usb_id && snd_usbmidi_port_info[i].port == number) return &snd_usbmidi_port_info[i]; } @@ -1450,7 +1452,7 @@ static void snd_usbmidi_init_substream(struct snd_usb_midi* umidi, port_info = find_port_info(umidi, number); name_format = port_info ? port_info->name : "%s MIDI %d"; snprintf(substream->name, sizeof(substream->name), - name_format, umidi->chip->card->shortname, number + 1); + name_format, umidi->card->shortname, number + 1); *rsubstream = substream; } @@ -1548,7 +1550,7 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi* umidi, endpoints[epidx].out_ep = usb_endpoint_num(ep); if (usb_endpoint_xfer_int(ep)) endpoints[epidx].out_interval = ep->bInterval; - else if (snd_usb_get_speed(umidi->chip->dev) == USB_SPEED_LOW) + else if (snd_usb_get_speed(umidi->dev) == USB_SPEED_LOW) /* * Low speed bulk transfers don't exist, so * force interrupt transfers for devices like @@ -1568,7 +1570,7 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi* umidi, endpoints[epidx].in_ep = usb_endpoint_num(ep); if (usb_endpoint_xfer_int(ep)) endpoints[epidx].in_interval = ep->bInterval; - else if (snd_usb_get_speed(umidi->chip->dev) == USB_SPEED_LOW) + else if (snd_usb_get_speed(umidi->dev) == USB_SPEED_LOW) endpoints[epidx].in_interval = 1; endpoints[epidx].in_cables = (1 << ms_ep->bNumEmbMIDIJack) - 1; snd_printdd(KERN_INFO "EP %02X: %d jack(s)\n", @@ -1647,11 +1649,11 @@ static void snd_usbmidi_switch_roland_altsetting(struct snd_usb_midi* umidi) snd_printdd(KERN_INFO "switching to altsetting %d with int ep\n", intfd->bAlternateSetting); - usb_set_interface(umidi->chip->dev, intfd->bInterfaceNumber, + usb_set_interface(umidi->dev, intfd->bInterfaceNumber, intfd->bAlternateSetting); umidi->roland_load_ctl = snd_ctl_new1(&roland_load_ctl, umidi); - if (snd_ctl_add(umidi->chip->card, umidi->roland_load_ctl) < 0) + if (snd_ctl_add(umidi->card, umidi->roland_load_ctl) < 0) umidi->roland_load_ctl = NULL; } @@ -1668,7 +1670,7 @@ static int snd_usbmidi_detect_endpoints(struct snd_usb_midi* umidi, struct usb_endpoint_descriptor* epd; int i, out_eps = 0, in_eps = 0; - if (USB_ID_VENDOR(umidi->chip->usb_id) == 0x0582) + if (USB_ID_VENDOR(umidi->usb_id) == 0x0582) snd_usbmidi_switch_roland_altsetting(umidi); if (endpoint[0].out_ep || endpoint[0].in_ep) @@ -1855,12 +1857,12 @@ static int snd_usbmidi_create_rawmidi(struct snd_usb_midi* umidi, struct snd_rawmidi *rmidi; int err; - err = snd_rawmidi_new(umidi->chip->card, "USB MIDI", - umidi->chip->next_midi_device++, + err = snd_rawmidi_new(umidi->card, "USB MIDI", + umidi->next_midi_device++, out_ports, in_ports, &rmidi); if (err < 0) return err; - strcpy(rmidi->name, umidi->chip->card->shortname); + strcpy(rmidi->name, umidi->card->shortname); rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX; @@ -1899,7 +1901,7 @@ static void snd_usbmidi_input_start_ep(struct snd_usb_midi_in_endpoint* ep) return; for (i = 0; i < INPUT_URBS; ++i) { struct urb* urb = ep->urbs[i]; - urb->dev = ep->umidi->chip->dev; + urb->dev = ep->umidi->dev; snd_usbmidi_submit_urb(urb, GFP_KERNEL); } } @@ -1920,9 +1922,10 @@ void snd_usbmidi_input_start(struct list_head* p) /* * Creates and registers everything needed for a MIDI streaming interface. */ -int snd_usb_create_midi_interface(struct snd_usb_audio* chip, - struct usb_interface* iface, - const struct snd_usb_audio_quirk* quirk) +int snd_usbmidi_create(struct snd_card *card, + struct usb_interface* iface, + struct list_head *midi_list, + const struct snd_usb_audio_quirk* quirk) { struct snd_usb_midi* umidi; struct snd_usb_midi_endpoint_info endpoints[MIDI_MAX_ENDPOINTS]; @@ -1932,13 +1935,16 @@ int snd_usb_create_midi_interface(struct snd_usb_audio* chip, umidi = kzalloc(sizeof(*umidi), GFP_KERNEL); if (!umidi) return -ENOMEM; - umidi->chip = chip; + umidi->dev = interface_to_usbdev(iface); + umidi->card = card; umidi->iface = iface; umidi->quirk = quirk; umidi->usb_protocol_ops = &snd_usbmidi_standard_ops; init_timer(&umidi->error_timer); spin_lock_init(&umidi->disc_lock); mutex_init(&umidi->mutex); + umidi->usb_id = USB_ID(le16_to_cpu(umidi->dev->descriptor.idVendor), + le16_to_cpu(umidi->dev->descriptor.idProduct)); umidi->error_timer.function = snd_usbmidi_error_timer; umidi->error_timer.data = (unsigned long)umidi; @@ -1947,7 +1953,7 @@ int snd_usb_create_midi_interface(struct snd_usb_audio* chip, switch (quirk ? quirk->type : QUIRK_MIDI_STANDARD_INTERFACE) { case QUIRK_MIDI_STANDARD_INTERFACE: err = snd_usbmidi_get_ms_info(umidi, endpoints); - if (chip->usb_id == USB_ID(0x0763, 0x0150)) /* M-Audio Uno */ + if (umidi->usb_id == USB_ID(0x0763, 0x0150)) /* M-Audio Uno */ umidi->usb_protocol_ops = &snd_usbmidi_maudio_broken_running_status_ops; break; @@ -1983,7 +1989,7 @@ int snd_usb_create_midi_interface(struct snd_usb_audio* chip, * interface 0, so we have to make sure that the USB core looks * again at interface 0 by calling usb_set_interface() on it. */ - usb_set_interface(umidi->chip->dev, 0, 0); + usb_set_interface(umidi->dev, 0, 0); err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints); break; case QUIRK_MIDI_EMAGIC: @@ -2029,14 +2035,14 @@ int snd_usb_create_midi_interface(struct snd_usb_audio* chip, return err; } - list_add(&umidi->list, &umidi->chip->midi_list); + list_add_tail(&umidi->list, midi_list); for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) snd_usbmidi_input_start_ep(umidi->endpoints[i].in); return 0; } -EXPORT_SYMBOL(snd_usb_create_midi_interface); +EXPORT_SYMBOL(snd_usbmidi_create); EXPORT_SYMBOL(snd_usbmidi_input_stop); EXPORT_SYMBOL(snd_usbmidi_input_start); EXPORT_SYMBOL(snd_usbmidi_disconnect); diff --git a/sound/usb/usx2y/us122l.c b/sound/usb/usx2y/us122l.c index 00cd54c236b..0ad061e5728 100644 --- a/sound/usb/usx2y/us122l.c +++ b/sound/usb/usx2y/us122l.c @@ -62,8 +62,8 @@ static int us122l_create_usbmidi(struct snd_card *card) struct usb_device *dev = US122L(card)->chip.dev; struct usb_interface *iface = usb_ifnum_to_if(dev, 1); - return snd_usb_create_midi_interface(&US122L(card)->chip, - iface, &quirk); + return snd_usbmidi_create(card, iface, + &US122L(card)->midi_list, &quirk); } static int us144_create_usbmidi(struct snd_card *card) @@ -84,8 +84,8 @@ static int us144_create_usbmidi(struct snd_card *card) struct usb_device *dev = US122L(card)->chip.dev; struct usb_interface *iface = usb_ifnum_to_if(dev, 0); - return snd_usb_create_midi_interface(&US122L(card)->chip, - iface, &quirk); + return snd_usbmidi_create(card, iface, + &US122L(card)->midi_list, &quirk); } /* @@ -297,7 +297,7 @@ static unsigned int usb_stream_hwdep_poll(struct snd_hwdep *hw, static void us122l_stop(struct us122l *us122l) { struct list_head *p; - list_for_each(p, &us122l->chip.midi_list) + list_for_each(p, &us122l->midi_list) snd_usbmidi_input_stop(p); usb_stream_stop(&us122l->sk); @@ -363,7 +363,7 @@ static bool us122l_start(struct us122l *us122l, snd_printk(KERN_ERR "us122l_start error %i \n", err); goto out; } - list_for_each(p, &us122l->chip.midi_list) + list_for_each(p, &us122l->midi_list) snd_usbmidi_input_start(p); success = true; out: @@ -508,7 +508,7 @@ static bool us122l_create_card(struct snd_card *card) if (err < 0) { /* release the midi resources */ struct list_head *p; - list_for_each(p, &us122l->chip.midi_list) + list_for_each(p, &us122l->midi_list) snd_usbmidi_disconnect(p); us122l_stop(us122l); @@ -546,7 +546,7 @@ static int usx2y_create_card(struct usb_device *device, struct snd_card **cardp) US122L(card)->chip.card = card; mutex_init(&US122L(card)->mutex); init_waitqueue_head(&US122L(card)->sk.sleep); - INIT_LIST_HEAD(&US122L(card)->chip.midi_list); + INIT_LIST_HEAD(&US122L(card)->midi_list); strcpy(card->driver, "USB "NAME_ALLCAPS""); sprintf(card->shortname, "TASCAM "NAME_ALLCAPS""); sprintf(card->longname, "%s (%x:%x if %d at %03d/%03d)", @@ -638,7 +638,7 @@ static void snd_us122l_disconnect(struct usb_interface *intf) us122l->chip.shutdown = 1; /* release the midi resources */ - list_for_each(p, &us122l->chip.midi_list) { + list_for_each(p, &us122l->midi_list) { snd_usbmidi_disconnect(p); } @@ -667,7 +667,7 @@ static int snd_us122l_suspend(struct usb_interface *intf, pm_message_t message) if (!us122l) return 0; - list_for_each(p, &us122l->chip.midi_list) + list_for_each(p, &us122l->midi_list) snd_usbmidi_input_stop(p); mutex_lock(&us122l->mutex); @@ -720,7 +720,7 @@ static int snd_us122l_resume(struct usb_interface *intf) if (err) goto unlock; - list_for_each(p, &us122l->chip.midi_list) + list_for_each(p, &us122l->midi_list) snd_usbmidi_input_start(p); unlock: mutex_unlock(&us122l->mutex); diff --git a/sound/usb/usx2y/us122l.h b/sound/usb/usx2y/us122l.h index 3d10c4b2a0f..61ce5d7de0b 100644 --- a/sound/usb/usx2y/us122l.h +++ b/sound/usb/usx2y/us122l.h @@ -12,6 +12,7 @@ struct us122l { unsigned second_periods_polled; struct file *master; struct file *slave; + struct list_head midi_list; atomic_t mmap_count; }; diff --git a/sound/usb/usx2y/usX2Yhwdep.c b/sound/usb/usx2y/usX2Yhwdep.c index 52e04b2f35d..f96ab86259d 100644 --- a/sound/usb/usx2y/usX2Yhwdep.c +++ b/sound/usb/usx2y/usX2Yhwdep.c @@ -171,7 +171,7 @@ static int usX2Y_create_usbmidi(struct snd_card *card) &quirk_2 : &quirk_1; snd_printdd("usX2Y_create_usbmidi \n"); - return snd_usb_create_midi_interface(&usX2Y(card)->chip, iface, quirk); + return snd_usbmidi_create(card, iface, &usX2Y(card)->midi_list, quirk); } static int usX2Y_create_alsa_devices(struct snd_card *card) diff --git a/sound/usb/usx2y/usbusx2y.c b/sound/usb/usx2y/usbusx2y.c index cb4bb8373ca..181337090e4 100644 --- a/sound/usb/usx2y/usbusx2y.c +++ b/sound/usb/usx2y/usbusx2y.c @@ -354,7 +354,7 @@ static int usX2Y_create_card(struct usb_device *device, struct snd_card **cardp) usX2Y(card)->chip.card = card; init_waitqueue_head(&usX2Y(card)->prepare_wait_queue); mutex_init(&usX2Y(card)->prepare_mutex); - INIT_LIST_HEAD(&usX2Y(card)->chip.midi_list); + INIT_LIST_HEAD(&usX2Y(card)->midi_list); strcpy(card->driver, "USB "NAME_ALLCAPS""); sprintf(card->shortname, "TASCAM "NAME_ALLCAPS""); sprintf(card->longname, "%s (%x:%x if %d at %03d/%03d)", @@ -451,7 +451,7 @@ static void usX2Y_usb_disconnect(struct usb_device *device, void* ptr) usb_kill_urb(usX2Y->In04urb); snd_card_disconnect(card); /* release the midi resources */ - list_for_each(p, &usX2Y->chip.midi_list) { + list_for_each(p, &usX2Y->midi_list) { snd_usbmidi_disconnect(p); } if (usX2Y->us428ctls_sharedmem) diff --git a/sound/usb/usx2y/usbusx2y.h b/sound/usb/usx2y/usbusx2y.h index 456b5fdbc33..231866ea349 100644 --- a/sound/usb/usx2y/usbusx2y.h +++ b/sound/usb/usx2y/usbusx2y.h @@ -42,6 +42,7 @@ struct usX2Ydev { struct snd_usX2Y_substream *subs[4]; struct snd_usX2Y_substream * volatile prepare_subs; wait_queue_head_t prepare_wait_queue; + struct list_head midi_list; }; diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c index 9efd27f6b52..b8e2f469149 100644 --- a/sound/usb/usx2y/usbusx2yaudio.c +++ b/sound/usb/usx2y/usbusx2yaudio.c @@ -740,7 +740,7 @@ static int usX2Y_format_set(struct usX2Ydev *usX2Y, snd_pcm_format_t format) alternate = 1; usX2Y->stride = 4; } - list_for_each(p, &usX2Y->chip.midi_list) { + list_for_each(p, &usX2Y->midi_list) { snd_usbmidi_input_stop(p); } usb_kill_urb(usX2Y->In04urb); @@ -750,7 +750,7 @@ static int usX2Y_format_set(struct usX2Ydev *usX2Y, snd_pcm_format_t format) } usX2Y->In04urb->dev = usX2Y->chip.dev; err = usb_submit_urb(usX2Y->In04urb, GFP_KERNEL); - list_for_each(p, &usX2Y->chip.midi_list) { + list_for_each(p, &usX2Y->midi_list) { snd_usbmidi_input_start(p); } usX2Y->format = format; -- cgit v1.2.3 From a014bbadb53121e243cac254593e79e3ca89742d Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 16 Nov 2009 12:26:30 +0100 Subject: sound: usxxx: cleanup chip field The chip field is no longer needed. Move those of its fields that are actually used to the device structure itself. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/usb/usx2y/us122l.c | 68 ++++++++++++++++++++--------------------- sound/usb/usx2y/us122l.h | 3 +- sound/usb/usx2y/usX2Yhwdep.c | 6 ++-- sound/usb/usx2y/usbusx2y.c | 24 +++++++-------- sound/usb/usx2y/usbusx2y.h | 5 ++- sound/usb/usx2y/usbusx2yaudio.c | 30 +++++++++--------- sound/usb/usx2y/usx2yhwdeppcm.c | 8 ++--- 7 files changed, 72 insertions(+), 72 deletions(-) (limited to 'sound') diff --git a/sound/usb/usx2y/us122l.c b/sound/usb/usx2y/us122l.c index 0ad061e5728..f71cd28eca6 100644 --- a/sound/usb/usx2y/us122l.c +++ b/sound/usb/usx2y/us122l.c @@ -59,7 +59,7 @@ static int us122l_create_usbmidi(struct snd_card *card) .type = QUIRK_MIDI_US122L, .data = &quirk_data }; - struct usb_device *dev = US122L(card)->chip.dev; + struct usb_device *dev = US122L(card)->dev; struct usb_interface *iface = usb_ifnum_to_if(dev, 1); return snd_usbmidi_create(card, iface, @@ -81,7 +81,7 @@ static int us144_create_usbmidi(struct snd_card *card) .type = QUIRK_MIDI_US122L, .data = &quirk_data }; - struct usb_device *dev = US122L(card)->chip.dev; + struct usb_device *dev = US122L(card)->dev; struct usb_interface *iface = usb_ifnum_to_if(dev, 0); return snd_usbmidi_create(card, iface, @@ -194,11 +194,11 @@ static int usb_stream_hwdep_open(struct snd_hwdep *hw, struct file *file) if (!us122l->first) us122l->first = file; - if (us122l->chip.dev->descriptor.idProduct == USB_ID_US144) { - iface = usb_ifnum_to_if(us122l->chip.dev, 0); + if (us122l->dev->descriptor.idProduct == USB_ID_US144) { + iface = usb_ifnum_to_if(us122l->dev, 0); usb_autopm_get_interface(iface); } - iface = usb_ifnum_to_if(us122l->chip.dev, 1); + iface = usb_ifnum_to_if(us122l->dev, 1); usb_autopm_get_interface(iface); return 0; } @@ -209,11 +209,11 @@ static int usb_stream_hwdep_release(struct snd_hwdep *hw, struct file *file) struct usb_interface *iface; snd_printdd(KERN_DEBUG "%p %p\n", hw, file); - if (us122l->chip.dev->descriptor.idProduct == USB_ID_US144) { - iface = usb_ifnum_to_if(us122l->chip.dev, 0); + if (us122l->dev->descriptor.idProduct == USB_ID_US144) { + iface = usb_ifnum_to_if(us122l->dev, 0); usb_autopm_put_interface(iface); } - iface = usb_ifnum_to_if(us122l->chip.dev, 1); + iface = usb_ifnum_to_if(us122l->dev, 1); usb_autopm_put_interface(iface); if (us122l->first == file) us122l->first = NULL; @@ -330,7 +330,7 @@ static bool us122l_start(struct us122l *us122l, unsigned use_packsize = 0; bool success = false; - if (us122l->chip.dev->speed == USB_SPEED_HIGH) { + if (us122l->dev->speed == USB_SPEED_HIGH) { /* The us-122l's descriptor defaults to iso max_packsize 78, which isn't needed for samplerates <= 48000. Lets save some memory: @@ -347,11 +347,11 @@ static bool us122l_start(struct us122l *us122l, break; } } - if (!usb_stream_new(&us122l->sk, us122l->chip.dev, 1, 2, + if (!usb_stream_new(&us122l->sk, us122l->dev, 1, 2, rate, use_packsize, period_frames, 6)) goto out; - err = us122l_set_sample_rate(us122l->chip.dev, rate); + err = us122l_set_sample_rate(us122l->dev, rate); if (err < 0) { us122l_stop(us122l); snd_printk(KERN_ERR "us122l_set_sample_rate error \n"); @@ -390,7 +390,7 @@ static int usb_stream_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, err = -ENXIO; goto free; } - high_speed = us122l->chip.dev->speed == USB_SPEED_HIGH; + high_speed = us122l->dev->speed == USB_SPEED_HIGH; if ((cfg->sample_rate != 44100 && cfg->sample_rate != 48000 && (!high_speed || (cfg->sample_rate != 88200 && cfg->sample_rate != 96000))) || @@ -450,7 +450,7 @@ static int usb_stream_hwdep_new(struct snd_card *card) { int err; struct snd_hwdep *hw; - struct usb_device *dev = US122L(card)->chip.dev; + struct usb_device *dev = US122L(card)->dev; err = snd_hwdep_new(card, SND_USB_STREAM_ID, 0, &hw); if (err < 0) @@ -476,26 +476,26 @@ static bool us122l_create_card(struct snd_card *card) int err; struct us122l *us122l = US122L(card); - if (us122l->chip.dev->descriptor.idProduct == USB_ID_US144) { - err = usb_set_interface(us122l->chip.dev, 0, 1); + if (us122l->dev->descriptor.idProduct == USB_ID_US144) { + err = usb_set_interface(us122l->dev, 0, 1); if (err) { snd_printk(KERN_ERR "usb_set_interface error \n"); return false; } } - err = usb_set_interface(us122l->chip.dev, 1, 1); + err = usb_set_interface(us122l->dev, 1, 1); if (err) { snd_printk(KERN_ERR "usb_set_interface error \n"); return false; } - pt_info_set(us122l->chip.dev, 0x11); - pt_info_set(us122l->chip.dev, 0x10); + pt_info_set(us122l->dev, 0x11); + pt_info_set(us122l->dev, 0x10); if (!us122l_start(us122l, 44100, 256)) return false; - if (us122l->chip.dev->descriptor.idProduct == USB_ID_US144) + if (us122l->dev->descriptor.idProduct == USB_ID_US144) err = us144_create_usbmidi(card); else err = us122l_create_usbmidi(card); @@ -520,7 +520,7 @@ static bool us122l_create_card(struct snd_card *card) static void snd_us122l_free(struct snd_card *card) { struct us122l *us122l = US122L(card); - int index = us122l->chip.index; + int index = us122l->card_index; if (index >= 0 && index < SNDRV_CARDS) snd_us122l_card_used[index] = 0; } @@ -540,10 +540,9 @@ static int usx2y_create_card(struct usb_device *device, struct snd_card **cardp) sizeof(struct us122l), &card); if (err < 0) return err; - snd_us122l_card_used[US122L(card)->chip.index = dev] = 1; + snd_us122l_card_used[US122L(card)->card_index = dev] = 1; card->private_free = snd_us122l_free; - US122L(card)->chip.dev = device; - US122L(card)->chip.card = card; + US122L(card)->dev = device; mutex_init(&US122L(card)->mutex); init_waitqueue_head(&US122L(card)->sk.sleep); INIT_LIST_HEAD(&US122L(card)->midi_list); @@ -554,8 +553,8 @@ static int usx2y_create_card(struct usb_device *device, struct snd_card **cardp) le16_to_cpu(device->descriptor.idVendor), le16_to_cpu(device->descriptor.idProduct), 0, - US122L(card)->chip.dev->bus->busnum, - US122L(card)->chip.dev->devnum + US122L(card)->dev->bus->busnum, + US122L(card)->dev->devnum ); *cardp = card; return 0; @@ -635,16 +634,15 @@ static void snd_us122l_disconnect(struct usb_interface *intf) mutex_lock(&us122l->mutex); us122l_stop(us122l); mutex_unlock(&us122l->mutex); - us122l->chip.shutdown = 1; /* release the midi resources */ list_for_each(p, &us122l->midi_list) { snd_usbmidi_disconnect(p); } - usb_put_intf(usb_ifnum_to_if(us122l->chip.dev, 0)); - usb_put_intf(usb_ifnum_to_if(us122l->chip.dev, 1)); - usb_put_dev(us122l->chip.dev); + usb_put_intf(usb_ifnum_to_if(us122l->dev, 0)); + usb_put_intf(usb_ifnum_to_if(us122l->dev, 1)); + usb_put_dev(us122l->dev); while (atomic_read(&us122l->mmap_count)) msleep(500); @@ -694,23 +692,23 @@ static int snd_us122l_resume(struct usb_interface *intf) mutex_lock(&us122l->mutex); /* needed, doesn't restart without: */ - if (us122l->chip.dev->descriptor.idProduct == USB_ID_US144) { - err = usb_set_interface(us122l->chip.dev, 0, 1); + if (us122l->dev->descriptor.idProduct == USB_ID_US144) { + err = usb_set_interface(us122l->dev, 0, 1); if (err) { snd_printk(KERN_ERR "usb_set_interface error \n"); goto unlock; } } - err = usb_set_interface(us122l->chip.dev, 1, 1); + err = usb_set_interface(us122l->dev, 1, 1); if (err) { snd_printk(KERN_ERR "usb_set_interface error \n"); goto unlock; } - pt_info_set(us122l->chip.dev, 0x11); - pt_info_set(us122l->chip.dev, 0x10); + pt_info_set(us122l->dev, 0x11); + pt_info_set(us122l->dev, 0x10); - err = us122l_set_sample_rate(us122l->chip.dev, + err = us122l_set_sample_rate(us122l->dev, us122l->sk.s->cfg.sample_rate); if (err < 0) { snd_printk(KERN_ERR "us122l_set_sample_rate error \n"); diff --git a/sound/usb/usx2y/us122l.h b/sound/usb/usx2y/us122l.h index 61ce5d7de0b..4daf1982e82 100644 --- a/sound/usb/usx2y/us122l.h +++ b/sound/usb/usx2y/us122l.h @@ -3,7 +3,8 @@ struct us122l { - struct snd_usb_audio chip; + struct usb_device *dev; + int card_index; int stride; struct usb_stream_kernel sk; diff --git a/sound/usb/usx2y/usX2Yhwdep.c b/sound/usb/usx2y/usX2Yhwdep.c index f96ab86259d..1879b72c40f 100644 --- a/sound/usb/usx2y/usX2Yhwdep.c +++ b/sound/usb/usx2y/usX2Yhwdep.c @@ -114,7 +114,7 @@ static int snd_usX2Y_hwdep_dsp_status(struct snd_hwdep *hw, struct usX2Ydev *us428 = hw->private_data; int id = -1; - switch (le16_to_cpu(us428->chip.dev->descriptor.idProduct)) { + switch (le16_to_cpu(us428->dev->descriptor.idProduct)) { case USB_ID_US122: id = USX2Y_TYPE_122; break; @@ -164,7 +164,7 @@ static int usX2Y_create_usbmidi(struct snd_card *card) .type = QUIRK_MIDI_FIXED_ENDPOINT, .data = &quirk_data_2 }; - struct usb_device *dev = usX2Y(card)->chip.dev; + struct usb_device *dev = usX2Y(card)->dev; struct usb_interface *iface = usb_ifnum_to_if(dev, 0); struct snd_usb_audio_quirk *quirk = le16_to_cpu(dev->descriptor.idProduct) == USB_ID_US428 ? @@ -202,7 +202,7 @@ static int snd_usX2Y_hwdep_dsp_load(struct snd_hwdep *hw, snd_printdd( "dsp_load %s\n", dsp->name); if (access_ok(VERIFY_READ, dsp->image, dsp->length)) { - struct usb_device* dev = priv->chip.dev; + struct usb_device* dev = priv->dev; char *buf; buf = memdup_user(dsp->image, dsp->length); diff --git a/sound/usb/usx2y/usbusx2y.c b/sound/usb/usx2y/usbusx2y.c index 181337090e4..c42350eed2e 100644 --- a/sound/usb/usx2y/usbusx2y.c +++ b/sound/usb/usx2y/usbusx2y.c @@ -239,8 +239,8 @@ static void i_usX2Y_In04Int(struct urb *urb) for (j = 0; j < URBS_AsyncSeq && !err; ++j) if (0 == usX2Y->AS04.urb[j]->status) { struct us428_p4out *p4out = us428ctls->p4out + send; // FIXME if more than 1 p4out is new, 1 gets lost. - usb_fill_bulk_urb(usX2Y->AS04.urb[j], usX2Y->chip.dev, - usb_sndbulkpipe(usX2Y->chip.dev, 0x04), &p4out->val.vol, + usb_fill_bulk_urb(usX2Y->AS04.urb[j], usX2Y->dev, + usb_sndbulkpipe(usX2Y->dev, 0x04), &p4out->val.vol, p4out->type == eLT_Light ? sizeof(struct us428_lights) : 5, i_usX2Y_Out04Int, usX2Y); err = usb_submit_urb(usX2Y->AS04.urb[j], GFP_ATOMIC); @@ -253,7 +253,7 @@ static void i_usX2Y_In04Int(struct urb *urb) if (err) snd_printk(KERN_ERR "In04Int() usb_submit_urb err=%i\n", err); - urb->dev = usX2Y->chip.dev; + urb->dev = usX2Y->dev; usb_submit_urb(urb, GFP_ATOMIC); } @@ -273,8 +273,8 @@ int usX2Y_AsyncSeq04_init(struct usX2Ydev *usX2Y) err = -ENOMEM; break; } - usb_fill_bulk_urb( usX2Y->AS04.urb[i], usX2Y->chip.dev, - usb_sndbulkpipe(usX2Y->chip.dev, 0x04), + usb_fill_bulk_urb( usX2Y->AS04.urb[i], usX2Y->dev, + usb_sndbulkpipe(usX2Y->dev, 0x04), usX2Y->AS04.buffer + URB_DataLen_AsyncSeq*i, 0, i_usX2Y_Out04Int, usX2Y ); @@ -293,7 +293,7 @@ int usX2Y_In04_init(struct usX2Ydev *usX2Y) } init_waitqueue_head(&usX2Y->In04WaitQueue); - usb_fill_int_urb(usX2Y->In04urb, usX2Y->chip.dev, usb_rcvintpipe(usX2Y->chip.dev, 0x4), + usb_fill_int_urb(usX2Y->In04urb, usX2Y->dev, usb_rcvintpipe(usX2Y->dev, 0x4), usX2Y->In04Buf, 21, i_usX2Y_In04Int, usX2Y, 10); @@ -348,10 +348,9 @@ static int usX2Y_create_card(struct usb_device *device, struct snd_card **cardp) sizeof(struct usX2Ydev), &card); if (err < 0) return err; - snd_usX2Y_card_used[usX2Y(card)->chip.index = dev] = 1; + snd_usX2Y_card_used[usX2Y(card)->card_index = dev] = 1; card->private_free = snd_usX2Y_card_private_free; - usX2Y(card)->chip.dev = device; - usX2Y(card)->chip.card = card; + usX2Y(card)->dev = device; init_waitqueue_head(&usX2Y(card)->prepare_wait_queue); mutex_init(&usX2Y(card)->prepare_mutex); INIT_LIST_HEAD(&usX2Y(card)->midi_list); @@ -362,7 +361,7 @@ static int usX2Y_create_card(struct usb_device *device, struct snd_card **cardp) le16_to_cpu(device->descriptor.idVendor), le16_to_cpu(device->descriptor.idProduct), 0,//us428(card)->usbmidi.ifnum, - usX2Y(card)->chip.dev->bus->busnum, usX2Y(card)->chip.dev->devnum + usX2Y(card)->dev->bus->busnum, usX2Y(card)->dev->devnum ); *cardp = card; return 0; @@ -432,8 +431,8 @@ static void snd_usX2Y_card_private_free(struct snd_card *card) usb_free_urb(usX2Y(card)->In04urb); if (usX2Y(card)->us428ctls_sharedmem) snd_free_pages(usX2Y(card)->us428ctls_sharedmem, sizeof(*usX2Y(card)->us428ctls_sharedmem)); - if (usX2Y(card)->chip.index >= 0 && usX2Y(card)->chip.index < SNDRV_CARDS) - snd_usX2Y_card_used[usX2Y(card)->chip.index] = 0; + if (usX2Y(card)->card_index >= 0 && usX2Y(card)->card_index < SNDRV_CARDS) + snd_usX2Y_card_used[usX2Y(card)->card_index] = 0; } /* @@ -445,7 +444,6 @@ static void usX2Y_usb_disconnect(struct usb_device *device, void* ptr) struct snd_card *card = ptr; struct usX2Ydev *usX2Y = usX2Y(card); struct list_head *p; - usX2Y->chip.shutdown = 1; usX2Y->chip_status = USX2Y_STAT_CHIP_HUP; usX2Y_unlinkSeq(&usX2Y->AS04); usb_kill_urb(usX2Y->In04urb); diff --git a/sound/usb/usx2y/usbusx2y.h b/sound/usb/usx2y/usbusx2y.h index 231866ea349..1d174cea352 100644 --- a/sound/usb/usx2y/usbusx2y.h +++ b/sound/usb/usx2y/usbusx2y.h @@ -22,7 +22,8 @@ struct snd_usX2Y_urbSeq { #include "usx2yhwdeppcm.h" struct usX2Ydev { - struct snd_usb_audio chip; + struct usb_device *dev; + int card_index; int stride; struct urb *In04urb; void *In04Buf; @@ -43,6 +44,8 @@ struct usX2Ydev { struct snd_usX2Y_substream * volatile prepare_subs; wait_queue_head_t prepare_wait_queue; struct list_head midi_list; + struct list_head pcm_list; + int pcm_devs; }; diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c index b8e2f469149..74a67a85aa8 100644 --- a/sound/usb/usx2y/usbusx2yaudio.c +++ b/sound/usb/usx2y/usbusx2yaudio.c @@ -199,7 +199,7 @@ static int usX2Y_urb_submit(struct snd_usX2Y_substream *subs, struct urb *urb, i return -ENODEV; urb->start_frame = (frame + NRURBS * nr_of_packs()); // let hcd do rollover sanity checks urb->hcpriv = NULL; - urb->dev = subs->usX2Y->chip.dev; /* we need to set this at each time */ + urb->dev = subs->usX2Y->dev; /* we need to set this at each time */ if ((err = usb_submit_urb(urb, GFP_ATOMIC)) < 0) { snd_printk(KERN_ERR "usb_submit_urb() returned %i\n", err); return err; @@ -300,7 +300,7 @@ static void usX2Y_error_sequence(struct usX2Ydev *usX2Y, "Sequence Error!(hcd_frame=%i ep=%i%s;wait=%i,frame=%i).\n" "Most propably some urb of usb-frame %i is still missing.\n" "Cause could be too long delays in usb-hcd interrupt handling.\n", - usb_get_current_frame_number(usX2Y->chip.dev), + usb_get_current_frame_number(usX2Y->dev), subs->endpoint, usb_pipein(urb->pipe) ? "in" : "out", usX2Y->wait_iso_frame, urb->start_frame, usX2Y->wait_iso_frame); usX2Y_clients_stop(usX2Y); @@ -313,7 +313,7 @@ static void i_usX2Y_urb_complete(struct urb *urb) if (unlikely(atomic_read(&subs->state) < state_PREPARED)) { snd_printdd("hcd_frame=%i ep=%i%s status=%i start_frame=%i\n", - usb_get_current_frame_number(usX2Y->chip.dev), + usb_get_current_frame_number(usX2Y->dev), subs->endpoint, usb_pipein(urb->pipe) ? "in" : "out", urb->status, urb->start_frame); return; @@ -424,7 +424,7 @@ static int usX2Y_urbs_allocate(struct snd_usX2Y_substream *subs) int i; unsigned int pipe; int is_playback = subs == subs->usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK]; - struct usb_device *dev = subs->usX2Y->chip.dev; + struct usb_device *dev = subs->usX2Y->dev; pipe = is_playback ? usb_sndisocpipe(dev, subs->endpoint) : usb_rcvisocpipe(dev, subs->endpoint); @@ -500,7 +500,7 @@ static int usX2Y_urbs_start(struct snd_usX2Y_substream *subs) unsigned long pack; if (0 == i) atomic_set(&subs->state, state_STARTING3); - urb->dev = usX2Y->chip.dev; + urb->dev = usX2Y->dev; urb->transfer_flags = URB_ISO_ASAP; for (pack = 0; pack < nr_of_packs(); pack++) { urb->iso_frame_desc[pack].offset = subs->maxpacksize * pack; @@ -692,7 +692,7 @@ static int usX2Y_rate_set(struct usX2Ydev *usX2Y, int rate) } ((char*)(usbdata + i))[0] = ra[i].c1; ((char*)(usbdata + i))[1] = ra[i].c2; - usb_fill_bulk_urb(us->urb[i], usX2Y->chip.dev, usb_sndbulkpipe(usX2Y->chip.dev, 4), + usb_fill_bulk_urb(us->urb[i], usX2Y->dev, usb_sndbulkpipe(usX2Y->dev, 4), usbdata + i, 2, i_usX2Y_04Int, usX2Y); #ifdef OLD_USB us->urb[i]->transfer_flags = USB_QUEUE_BULK; @@ -744,11 +744,11 @@ static int usX2Y_format_set(struct usX2Ydev *usX2Y, snd_pcm_format_t format) snd_usbmidi_input_stop(p); } usb_kill_urb(usX2Y->In04urb); - if ((err = usb_set_interface(usX2Y->chip.dev, 0, alternate))) { + if ((err = usb_set_interface(usX2Y->dev, 0, alternate))) { snd_printk(KERN_ERR "usb_set_interface error \n"); return err; } - usX2Y->In04urb->dev = usX2Y->chip.dev; + usX2Y->In04urb->dev = usX2Y->dev; err = usb_submit_urb(usX2Y->In04urb, GFP_KERNEL); list_for_each(p, &usX2Y->midi_list) { snd_usbmidi_input_start(p); @@ -955,7 +955,7 @@ static int usX2Y_audio_stream_new(struct snd_card *card, int playback_endpoint, struct snd_pcm *pcm; int err, i; struct snd_usX2Y_substream **usX2Y_substream = - usX2Y(card)->subs + 2 * usX2Y(card)->chip.pcm_devs; + usX2Y(card)->subs + 2 * usX2Y(card)->pcm_devs; for (i = playback_endpoint ? SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE; i <= SNDRV_PCM_STREAM_CAPTURE; ++i) { @@ -971,7 +971,7 @@ static int usX2Y_audio_stream_new(struct snd_card *card, int playback_endpoint, usX2Y_substream[SNDRV_PCM_STREAM_PLAYBACK]->endpoint = playback_endpoint; usX2Y_substream[SNDRV_PCM_STREAM_CAPTURE]->endpoint = capture_endpoint; - err = snd_pcm_new(card, NAME_ALLCAPS" Audio", usX2Y(card)->chip.pcm_devs, + err = snd_pcm_new(card, NAME_ALLCAPS" Audio", usX2Y(card)->pcm_devs, playback_endpoint ? 1 : 0, 1, &pcm); if (err < 0) { @@ -987,7 +987,7 @@ static int usX2Y_audio_stream_new(struct snd_card *card, int playback_endpoint, pcm->private_free = snd_usX2Y_pcm_private_free; pcm->info_flags = 0; - sprintf(pcm->name, NAME_ALLCAPS" Audio #%d", usX2Y(card)->chip.pcm_devs); + sprintf(pcm->name, NAME_ALLCAPS" Audio #%d", usX2Y(card)->pcm_devs); if ((playback_endpoint && 0 > (err = snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream, @@ -1001,7 +1001,7 @@ static int usX2Y_audio_stream_new(struct snd_card *card, int playback_endpoint, snd_usX2Y_pcm_private_free(pcm); return err; } - usX2Y(card)->chip.pcm_devs++; + usX2Y(card)->pcm_devs++; return 0; } @@ -1013,14 +1013,14 @@ int usX2Y_audio_create(struct snd_card *card) { int err = 0; - INIT_LIST_HEAD(&usX2Y(card)->chip.pcm_list); + INIT_LIST_HEAD(&usX2Y(card)->pcm_list); if (0 > (err = usX2Y_audio_stream_new(card, 0xA, 0x8))) return err; - if (le16_to_cpu(usX2Y(card)->chip.dev->descriptor.idProduct) == USB_ID_US428) + if (le16_to_cpu(usX2Y(card)->dev->descriptor.idProduct) == USB_ID_US428) if (0 > (err = usX2Y_audio_stream_new(card, 0, 0xA))) return err; - if (le16_to_cpu(usX2Y(card)->chip.dev->descriptor.idProduct) != USB_ID_US122) + if (le16_to_cpu(usX2Y(card)->dev->descriptor.idProduct) != USB_ID_US122) err = usX2Y_rate_set(usX2Y(card), 44100); // Lets us428 recognize output-volume settings, disturbs us122. return err; } diff --git a/sound/usb/usx2y/usx2yhwdeppcm.c b/sound/usb/usx2y/usx2yhwdeppcm.c index 4b2304c2e02..9ed6c3956ca 100644 --- a/sound/usb/usx2y/usx2yhwdeppcm.c +++ b/sound/usb/usx2y/usx2yhwdeppcm.c @@ -234,7 +234,7 @@ static void i_usX2Y_usbpcm_urb_complete(struct urb *urb) if (unlikely(atomic_read(&subs->state) < state_PREPARED)) { snd_printdd("hcd_frame=%i ep=%i%s status=%i start_frame=%i\n", - usb_get_current_frame_number(usX2Y->chip.dev), + usb_get_current_frame_number(usX2Y->dev), subs->endpoint, usb_pipein(urb->pipe) ? "in" : "out", urb->status, urb->start_frame); return; @@ -318,7 +318,7 @@ static int usX2Y_usbpcm_urbs_allocate(struct snd_usX2Y_substream *subs) int i; unsigned int pipe; int is_playback = subs == subs->usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK]; - struct usb_device *dev = subs->usX2Y->chip.dev; + struct usb_device *dev = subs->usX2Y->dev; pipe = is_playback ? usb_sndisocpipe(dev, subs->endpoint) : usb_rcvisocpipe(dev, subs->endpoint); @@ -441,7 +441,7 @@ static int usX2Y_usbpcm_urbs_start(struct snd_usX2Y_substream *subs) unsigned long pack; if (0 == u) atomic_set(&subs->state, state_STARTING3); - urb->dev = usX2Y->chip.dev; + urb->dev = usX2Y->dev; urb->transfer_flags = URB_ISO_ASAP; for (pack = 0; pack < nr_of_packs(); pack++) { urb->iso_frame_desc[pack].offset = subs->maxpacksize * (pack + u * nr_of_packs()); @@ -741,7 +741,7 @@ int usX2Y_hwdep_pcm_new(struct snd_card *card) int err; struct snd_hwdep *hw; struct snd_pcm *pcm; - struct usb_device *dev = usX2Y(card)->chip.dev; + struct usb_device *dev = usX2Y(card)->dev; if (1 != nr_of_packs()) return 0; -- cgit v1.2.3 From bbb3c644bd9967753ce8c214c5e64b27c361d2a4 Mon Sep 17 00:00:00 2001 From: Daniel T Chen Date: Tue, 24 Nov 2009 22:51:05 -0500 Subject: ALSA: intel8x0: Mute External Amplifier by default for Gateway 4525GZ BugLink: https://bugs.launchpad.net/bugs/487884 This Gateway model needs External Amplifier muted for audible playback, so set the inv_eapd quirk for it. Signed-off-by: Daniel T Chen Signed-off-by: Takashi Iwai --- sound/pci/intel8x0.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'sound') diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index aac20fb4aad..b990143636f 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -2062,6 +2062,12 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = { .name = "MSI P4 ATX 645 Ultra", .type = AC97_TUNE_HP_ONLY }, + { + .subvendor = 0x161f, + .subdevice = 0x203a, + .name = "Gateway 4525GZ", /* AD1981B */ + .type = AC97_TUNE_INV_EAPD + }, { .subvendor = 0x1734, .subdevice = 0x0088, -- cgit v1.2.3 From c0fa59df7214e546f8a37bc677867ac7b67b5c93 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 19 Nov 2009 11:36:10 +0000 Subject: ASoC: Add BCLK calculation utility for TDM mode too Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/soc-utils.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'sound') diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c index b16aaaeb0aa..1d07b931f3d 100644 --- a/sound/soc/soc-utils.c +++ b/sound/soc/soc-utils.c @@ -54,6 +54,12 @@ int snd_soc_params_to_frame_size(struct snd_pcm_hw_params *params) } EXPORT_SYMBOL_GPL(snd_soc_params_to_frame_size); +int snd_soc_calc_bclk(int fs, int sample_size, int channels, int tdm_slots) +{ + return fs * snd_soc_calc_frame_size(sample_size, channels, tdm_slots); +} +EXPORT_SYMBOL_GPL(snd_soc_calc_bclk); + int snd_soc_params_to_bclk(struct snd_pcm_hw_params *params) { int ret; -- cgit v1.2.3 From 657b1989dacf58e83e7a76bca6d4a91a9f294cf6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 26 Nov 2009 12:40:21 +0100 Subject: ALSA: pcm - Use dma_mmap_coherent() if available Use dma_mmap_coherent() for mmapping the buffers allocated via dma_alloc_coherent() if available. Currently, only ARM has this function, so we do temporarily have an ifdef pcm_native.c. This should be handled better globally in future. Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 49 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 16 deletions(-) (limited to 'sound') diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index ab73edf2c89..f067c5b906e 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -3094,23 +3095,42 @@ static int snd_pcm_mmap_data_fault(struct vm_area_struct *area, return 0; } -static const struct vm_operations_struct snd_pcm_vm_ops_data = -{ +static const struct vm_operations_struct snd_pcm_vm_ops_data = { + .open = snd_pcm_mmap_data_open, + .close = snd_pcm_mmap_data_close, +}; + +static const struct vm_operations_struct snd_pcm_vm_ops_data_fault = { .open = snd_pcm_mmap_data_open, .close = snd_pcm_mmap_data_close, .fault = snd_pcm_mmap_data_fault, }; +#ifndef ARCH_HAS_DMA_MMAP_COHERENT +/* This should be defined / handled globally! */ +#ifdef CONFIG_ARM +#define ARCH_HAS_DMA_MMAP_COHERENT +#endif +#endif + /* * mmap the DMA buffer on RAM */ static int snd_pcm_default_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *area) { - area->vm_ops = &snd_pcm_vm_ops_data; - area->vm_private_data = substream; area->vm_flags |= VM_RESERVED; - atomic_inc(&substream->mmap_count); +#ifdef ARCH_HAS_DMA_MMAP_COHERENT + if (!substream->ops->page && + substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV) + return dma_mmap_coherent(substream->dma_buffer.dev.dev, + area, + substream->runtime->dma_area, + substream->runtime->dma_addr, + area->vm_end - area->vm_start); +#endif /* ARCH_HAS_DMA_MMAP_COHERENT */ + /* mmap with fault handler */ + area->vm_ops = &snd_pcm_vm_ops_data_fault; return 0; } @@ -3118,12 +3138,6 @@ static int snd_pcm_default_mmap(struct snd_pcm_substream *substream, * mmap the DMA buffer on I/O memory area */ #if SNDRV_PCM_INFO_MMAP_IOMEM -static const struct vm_operations_struct snd_pcm_vm_ops_data_mmio = -{ - .open = snd_pcm_mmap_data_open, - .close = snd_pcm_mmap_data_close, -}; - int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream, struct vm_area_struct *area) { @@ -3133,8 +3147,6 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream, #ifdef pgprot_noncached area->vm_page_prot = pgprot_noncached(area->vm_page_prot); #endif - area->vm_ops = &snd_pcm_vm_ops_data_mmio; - area->vm_private_data = substream; area->vm_flags |= VM_IO; size = area->vm_end - area->vm_start; offset = area->vm_pgoff << PAGE_SHIFT; @@ -3142,7 +3154,6 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream, (substream->runtime->dma_addr + offset) >> PAGE_SHIFT, size, area->vm_page_prot)) return -EAGAIN; - atomic_inc(&substream->mmap_count); return 0; } @@ -3159,6 +3170,7 @@ int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file, long size; unsigned long offset; size_t dma_bytes; + int err; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { if (!(area->vm_flags & (VM_WRITE|VM_READ))) @@ -3183,10 +3195,15 @@ int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file, if (offset > dma_bytes - size) return -EINVAL; + area->vm_ops = &snd_pcm_vm_ops_data; + area->vm_private_data = substream; if (substream->ops->mmap) - return substream->ops->mmap(substream, area); + err = substream->ops->mmap(substream, area); else - return snd_pcm_default_mmap(substream, area); + err = snd_pcm_default_mmap(substream, area); + if (!err) + atomic_inc(&substream->mmap_count); + return err; } EXPORT_SYMBOL(snd_pcm_mmap_data); -- cgit v1.2.3 From 9eb4a06788a598573c751af1a7e46639afc89513 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 26 Nov 2009 12:43:39 +0100 Subject: ALSA: pcm - define snd_pcm_default_page_ops() Add a helper (inline) function as the default page ops. Any hacks wrt the page address conversion will be applied in this function. Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index f067c5b906e..c906be26c31 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -3062,6 +3062,13 @@ static int snd_pcm_mmap_control(struct snd_pcm_substream *substream, struct file } #endif /* coherent mmap */ +static inline struct page * +snd_pcm_default_page_ops(struct snd_pcm_substream *substream, unsigned long ofs) +{ + void *vaddr = substream->runtime->dma_area + ofs; + return virt_to_page(vaddr); +} + /* * fault callback for mmapping a RAM page */ @@ -3072,7 +3079,6 @@ static int snd_pcm_mmap_data_fault(struct vm_area_struct *area, struct snd_pcm_runtime *runtime; unsigned long offset; struct page * page; - void *vaddr; size_t dma_bytes; if (substream == NULL) @@ -3082,14 +3088,12 @@ static int snd_pcm_mmap_data_fault(struct vm_area_struct *area, dma_bytes = PAGE_ALIGN(runtime->dma_bytes); if (offset > dma_bytes - PAGE_SIZE) return VM_FAULT_SIGBUS; - if (substream->ops->page) { + if (substream->ops->page) page = substream->ops->page(substream, offset); - if (!page) - return VM_FAULT_SIGBUS; - } else { - vaddr = runtime->dma_area + offset; - page = virt_to_page(vaddr); - } + else + page = snd_pcm_default_page_ops(substream, offset); + if (!page) + return VM_FAULT_SIGBUS; get_page(page); vmf->page = page; return 0; -- cgit v1.2.3 From 74ea23aa6c9a8bece71b35ddeeb7ad6ae6782cd9 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 26 Nov 2009 13:55:11 +0200 Subject: ASoC: tlv320dac33: Change RT wq to singlethread wq RT workqueue is going away in the near future, replace it with singlethread wq for now, which is still supported. Signed-off-by: Peter Ujfalusi Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320dac33.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index 2a013e46ae1..9c8903dbe64 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c @@ -1118,7 +1118,8 @@ static int dac33_i2c_probe(struct i2c_client *client, } if (dac33->irq != -1) { /* Setup work queue */ - dac33->dac33_wq = create_rt_workqueue("tlv320dac33"); + dac33->dac33_wq = + create_singlethread_workqueue("tlv320dac33"); if (dac33->dac33_wq == NULL) { free_irq(dac33->irq, &dac33->codec); ret = -ENOMEM; -- cgit v1.2.3 From 66b6cfacfc5aa2fda37b0d40cd54931ca5ef8cd7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 26 Nov 2009 12:50:01 +0100 Subject: ALSA: pcm - fix page conversion on non-coherent MIPS arch The non-coherent MIPS arch doesn't give the correct address by a simple virt_to_page() for pages allocated via dma_alloc_coherent(). Original patch by Wu Zhangjin . [Ralf mentioned: "The origins of this patch go back far further. The oldest patch I could find which is a superset of this was written by Atsushi Nemoto and various incarnations of it have been sumitted to and reject by me a number of times through the years."] A proper check of the buffer allocation type was added to avoid the wrong conversion. Note that this doesn't fix perfectly: the pages should be marked with proper pgprot value. This will be done in a future implementation like the conversion to dma_mmap_coherent(). Acked-by: Ralf Baechle Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sound') diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index c906be26c31..e48c5f61857 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -3066,6 +3066,10 @@ static inline struct page * snd_pcm_default_page_ops(struct snd_pcm_substream *substream, unsigned long ofs) { void *vaddr = substream->runtime->dma_area + ofs; +#if defined(CONFIG_MIPS) && defined(CONFIG_DMA_NONCOHERENT) + if (substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV) + return virt_to_page(CAC_ADDR(vaddr)); +#endif return virt_to_page(vaddr); } -- cgit v1.2.3 From 6985c8877a711c7c307af05203858cb7c3c89d0d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 26 Nov 2009 15:04:24 +0100 Subject: ALSA: pcm - fix page conversion on non-coherent PPC arch The non-cohernet PPC arch doesn't give the correct address by a simple virt_to_page() for pages allocated via dma_alloc_coherent(). This patch adds a hack to fix the conversion similarly like MIPS. Note that this doesn't fix perfectly: the pages should be marked with proper pgprot value. This will be done in a future implementation like the conversion to dma_mmap_coherent(). Acked-by: Benjamin Herrenschmidt Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'sound') diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index e48c5f61857..29ab46a12e1 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -3069,6 +3069,16 @@ snd_pcm_default_page_ops(struct snd_pcm_substream *substream, unsigned long ofs) #if defined(CONFIG_MIPS) && defined(CONFIG_DMA_NONCOHERENT) if (substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV) return virt_to_page(CAC_ADDR(vaddr)); +#endif +#if defined(CONFIG_PPC32) && defined(CONFIG_NOT_COHERENT_CACHE) + if (substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV) { + dma_addr_t addr = substream->runtime->dma_addr + ofs; + addr -= get_dma_offset(substream->dma_buffer.dev.dev); + /* assume dma_handle set via pfn_to_phys() in + * mm/dma-noncoherent.c + */ + return pfn_to_page(addr >> PAGE_SHIFT); + } #endif return virt_to_page(vaddr); } -- cgit v1.2.3 From d6797322231af98b9bb4afb175dd614cf511e5f7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 26 Nov 2009 15:08:54 +0100 Subject: ALSA: Remove old DMA-mmap code from arm/devdma.c The call of dma_mmap_coherent() is done in the PCM core now. Signed-off-by: Takashi Iwai --- sound/arm/Makefile | 2 +- sound/arm/aaci.c | 16 ++++------- sound/arm/devdma.c | 80 ------------------------------------------------------ sound/arm/devdma.h | 3 -- 4 files changed, 6 insertions(+), 95 deletions(-) delete mode 100644 sound/arm/devdma.c delete mode 100644 sound/arm/devdma.h (limited to 'sound') diff --git a/sound/arm/Makefile b/sound/arm/Makefile index 5a549ed6c8a..8c0c851d464 100644 --- a/sound/arm/Makefile +++ b/sound/arm/Makefile @@ -3,7 +3,7 @@ # obj-$(CONFIG_SND_ARMAACI) += snd-aaci.o -snd-aaci-objs := aaci.o devdma.o +snd-aaci-objs := aaci.o obj-$(CONFIG_SND_PXA2XX_PCM) += snd-pxa2xx-pcm.o snd-pxa2xx-pcm-objs := pxa2xx-pcm.o diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c index 1f0f8213e2d..e59372887f3 100644 --- a/sound/arm/aaci.c +++ b/sound/arm/aaci.c @@ -30,7 +30,6 @@ #include #include "aaci.h" -#include "devdma.h" #define DRIVER_NAME "aaci-pl041" @@ -492,7 +491,7 @@ static int aaci_pcm_hw_free(struct snd_pcm_substream *substream) /* * Clear out the DMA and any allocated buffers. */ - devdma_hw_free(NULL, substream); + snd_pcm_lib_free_pages(substream); return 0; } @@ -505,8 +504,8 @@ static int aaci_pcm_hw_params(struct snd_pcm_substream *substream, aaci_pcm_hw_free(substream); - err = devdma_hw_alloc(NULL, substream, - params_buffer_bytes(params)); + err = snd_pcm_lib_malloc_pages(substream, + params_buffer_bytes(params)); if (err < 0) goto out; @@ -551,11 +550,6 @@ static snd_pcm_uframes_t aaci_pcm_pointer(struct snd_pcm_substream *substream) return bytes_to_frames(runtime, bytes); } -static int aaci_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma) -{ - return devdma_mmap(NULL, substream, vma); -} - /* * Playback specific ALSA stuff @@ -722,7 +716,6 @@ static struct snd_pcm_ops aaci_playback_ops = { .prepare = aaci_pcm_prepare, .trigger = aaci_pcm_playback_trigger, .pointer = aaci_pcm_pointer, - .mmap = aaci_pcm_mmap, }; static int aaci_pcm_capture_hw_params(struct snd_pcm_substream *substream, @@ -850,7 +843,6 @@ static struct snd_pcm_ops aaci_capture_ops = { .prepare = aaci_pcm_capture_prepare, .trigger = aaci_pcm_capture_trigger, .pointer = aaci_pcm_pointer, - .mmap = aaci_pcm_mmap, }; /* @@ -1040,6 +1032,8 @@ static int __devinit aaci_init_pcm(struct aaci *aaci) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &aaci_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &aaci_capture_ops); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + NULL, 0, 64 * 104); } return ret; diff --git a/sound/arm/devdma.c b/sound/arm/devdma.c deleted file mode 100644 index 9d1e6665b54..00000000000 --- a/sound/arm/devdma.c +++ /dev/null @@ -1,80 +0,0 @@ -/* - * linux/sound/arm/devdma.c - * - * Copyright (C) 2003-2004 Russell King, All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * ARM DMA shim for ALSA. - */ -#include -#include - -#include -#include - -#include "devdma.h" - -void devdma_hw_free(struct device *dev, 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); -} - -int devdma_hw_alloc(struct device *dev, struct snd_pcm_substream *substream, size_t size) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_dma_buffer *buf = runtime->dma_buffer_p; - int ret = 0; - - if (buf) { - if (buf->bytes >= size) - goto out; - devdma_hw_free(dev, 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 = dev; - buf->area = dma_alloc_coherent(dev, 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; -} - -int devdma_mmap(struct device *dev, struct snd_pcm_substream *substream, struct vm_area_struct *vma) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - return dma_mmap_coherent(dev, vma, runtime->dma_area, runtime->dma_addr, runtime->dma_bytes); -} diff --git a/sound/arm/devdma.h b/sound/arm/devdma.h deleted file mode 100644 index d025329c8a0..00000000000 --- a/sound/arm/devdma.h +++ /dev/null @@ -1,3 +0,0 @@ -void devdma_hw_free(struct device *dev, struct snd_pcm_substream *substream); -int devdma_hw_alloc(struct device *dev, struct snd_pcm_substream *substream, size_t size); -int devdma_mmap(struct device *dev, struct snd_pcm_substream *substream, struct vm_area_struct *vma); -- cgit v1.2.3 From 8700055e0a30b3f67c1474b09200b59c32dd3796 Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Fri, 27 Nov 2009 11:20:56 +0100 Subject: ALSA: opti-miro: fix OOPS if hardware is not detected If a hardware is not detected there is a kernel crash due to not initialized snd_miro->aci pointer. This pointer is initialized after detection of the opti (miro) chip. This bug was introduced by patches to expose ACI mikser outside the snd-miro driver. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai --- sound/isa/opti9xx/miro.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/isa/opti9xx/miro.c b/sound/isa/opti9xx/miro.c index 40b64cd54c8..e374869e3e2 100644 --- a/sound/isa/opti9xx/miro.c +++ b/sound/isa/opti9xx/miro.c @@ -1229,7 +1229,8 @@ static void snd_card_miro_free(struct snd_card *card) struct snd_miro *miro = card->private_data; release_and_free_resource(miro->res_aci_port); - miro->aci->aci_port = 0; + if (miro->aci) + miro->aci->aci_port = 0; release_and_free_resource(miro->res_mc_base); } -- cgit v1.2.3 From a22eaf4ce106404f6c5283da30b4d514ede964c1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 27 Nov 2009 15:14:09 +0100 Subject: ASoC: Revert missing reset_err in wm97*.c The commit fe3e78e073d25308756f38019956061153267769 ASoC: Factor out snd_soc_init_card() removed the error paths that are still valid for wm97* codecs, causing the compile errors like sound/soc/codecs/wm9705.c:399: error: label 'reset_err' used but not defined sound/soc/codecs/wm9712.c:687: error: label 'reset_err' used but not defined sound/soc/codecs/wm9713.c:1237: error: label 'reset_err' used but not defined Revert the removed error path codes. Signed-off-by: Takashi Iwai --- sound/soc/codecs/wm9705.c | 2 ++ sound/soc/codecs/wm9712.c | 2 ++ sound/soc/codecs/wm9713.c | 2 ++ 3 files changed, 6 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c index dfffc6c778c..ec54c6da985 100644 --- a/sound/soc/codecs/wm9705.c +++ b/sound/soc/codecs/wm9705.c @@ -404,6 +404,8 @@ static int wm9705_soc_probe(struct platform_device *pdev) return 0; +reset_err: + snd_soc_free_pcms(socdev); pcm_err: snd_soc_free_ac97_codec(codec); codec_err: diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index 2a087227300..0ac1215dcd9 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -697,6 +697,8 @@ static int wm9712_soc_probe(struct platform_device *pdev) return 0; +reset_err: + snd_soc_free_pcms(socdev); pcm_err: snd_soc_free_ac97_codec(codec); diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index 00bac315fb3..4d74ecb0e56 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -1249,6 +1249,8 @@ static int wm9713_soc_probe(struct platform_device *pdev) return 0; +reset_err: + snd_soc_free_pcms(socdev); pcm_err: snd_soc_free_ac97_codec(codec); -- cgit v1.2.3 From e9ff5eb2ae018fe2298c68746c873bf828c6b10e Mon Sep 17 00:00:00 2001 From: Anuj Aggarwal Date: Fri, 27 Nov 2009 17:40:58 +0530 Subject: ASoC: AIC23: Fixing infinite loop in resume path This patch fixes two issues: a) Infinite loop in resume function b) Writes to non-existing registers in resume function Cc: stable@kernel.org Signed-off-by: Anuj Aggarwal Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic23.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c index 6b24d8bb02b..90a0264f753 100644 --- a/sound/soc/codecs/tlv320aic23.c +++ b/sound/soc/codecs/tlv320aic23.c @@ -625,11 +625,10 @@ static int tlv320aic23_resume(struct platform_device *pdev) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); struct snd_soc_codec *codec = socdev->card->codec; - int i; u16 reg; /* Sync reg_cache with the hardware */ - for (reg = 0; reg < ARRAY_SIZE(tlv320aic23_reg); i++) { + for (reg = 0; reg < TLV320AIC23_RESET; reg++) { u16 val = tlv320aic23_read_reg_cache(codec, reg); tlv320aic23_write(codec, reg, val); } -- cgit v1.2.3 From 49af574b60669a58a2e96960ac694ce953119083 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Fri, 27 Nov 2009 13:47:10 +0100 Subject: ALSA: ARM: add Raumfeld audio support Signed-off-by: Daniel Mack Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/pxa/Kconfig | 9 ++ sound/soc/pxa/Makefile | 2 + sound/soc/pxa/raumfeld.c | 335 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 346 insertions(+) create mode 100644 sound/soc/pxa/raumfeld.c (limited to 'sound') diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig index d4f4031afa3..376e14a9c27 100644 --- a/sound/soc/pxa/Kconfig +++ b/sound/soc/pxa/Kconfig @@ -118,6 +118,15 @@ config SND_SOC_ZYLONITE Say Y if you want to add support for SoC audio on the Marvell Zylonite reference platform. +config SND_SOC_RAUMFELD + tristate "SoC Audio support Raumfeld audio adapter" + depends on SND_PXA2XX_SOC && (MACH_RAUMFELD_SPEAKER || MACH_RAUMFELD_CONNECTOR) + select SND_PXA_SOC_SSP + select SND_SOC_CS4270 + select SND_SOC_AK4104 + help + Say Y if you want to add support for SoC audio on Raumfeld devices + config SND_PXA2XX_SOC_MAGICIAN tristate "SoC Audio support for HTC Magician" depends on SND_PXA2XX_SOC && MACH_MAGICIAN diff --git a/sound/soc/pxa/Makefile b/sound/soc/pxa/Makefile index 6e096b48033..f3e08fd40ca 100644 --- a/sound/soc/pxa/Makefile +++ b/sound/soc/pxa/Makefile @@ -23,6 +23,7 @@ snd-soc-zylonite-objs := zylonite.o snd-soc-magician-objs := magician.o snd-soc-mioa701-objs := mioa701_wm9713.o snd-soc-imote2-objs := imote2.o +snd-soc-raumfeld-objs := raumfeld.o obj-$(CONFIG_SND_PXA2XX_SOC_CORGI) += snd-soc-corgi.o obj-$(CONFIG_SND_PXA2XX_SOC_POODLE) += snd-soc-poodle.o @@ -37,3 +38,4 @@ obj-$(CONFIG_SND_PXA2XX_SOC_MAGICIAN) += snd-soc-magician.o obj-$(CONFIG_SND_PXA2XX_SOC_MIOA701) += snd-soc-mioa701.o obj-$(CONFIG_SND_SOC_ZYLONITE) += snd-soc-zylonite.o obj-$(CONFIG_SND_PXA2XX_SOC_IMOTE2) += snd-soc-imote2.o +obj-$(CONFIG_SND_SOC_RAUMFELD) += snd-soc-raumfeld.o diff --git a/sound/soc/pxa/raumfeld.c b/sound/soc/pxa/raumfeld.c new file mode 100644 index 00000000000..f272269c05d --- /dev/null +++ b/sound/soc/pxa/raumfeld.c @@ -0,0 +1,335 @@ +/* + * raumfeld_audio.c -- SoC audio for Raumfeld audio devices + * + * Copyright (c) 2009 Daniel Mack + * + * based on code from: + * + * Wolfson Microelectronics PLC. + * Openedhand Ltd. + * Liam Girdwood + * Richard Purdie + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "../codecs/cs4270.h" +#include "../codecs/ak4104.h" +#include "pxa2xx-pcm.h" +#include "pxa-ssp.h" + +#define GPIO_SPDIF_RESET (38) +#define GPIO_MCLK_RESET (111) +#define GPIO_CODEC_RESET (120) + +static struct i2c_client *max9486_client; +static struct i2c_board_info max9486_hwmon_info = { + I2C_BOARD_INFO("max9485", 0x63), +}; + +#define MAX9485_MCLK_FREQ_112896 0x22 +#define MAX9485_MCLK_FREQ_122880 0x23 + +static void set_max9485_clk(char clk) +{ + i2c_master_send(max9486_client, &clk, 1); +} + +static void raumfeld_enable_audio(bool en) +{ + if (en) { + gpio_set_value(GPIO_MCLK_RESET, 1); + + /* wait some time to let the clocks become stable */ + msleep(100); + + gpio_set_value(GPIO_SPDIF_RESET, 1); + gpio_set_value(GPIO_CODEC_RESET, 1); + } else { + gpio_set_value(GPIO_MCLK_RESET, 0); + gpio_set_value(GPIO_SPDIF_RESET, 0); + gpio_set_value(GPIO_CODEC_RESET, 0); + } +} + +/* CS4270 */ +static int raumfeld_cs4270_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; + + set_max9485_clk(MAX9485_MCLK_FREQ_112896); + + return snd_soc_dai_set_sysclk(codec_dai, 0, 11289600, 0); +} + +static int raumfeld_cs4270_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + unsigned int fmt, clk = 0; + int ret = 0; + + switch (params_rate(params)) { + case 8000: + case 16000: + case 48000: + case 96000: + set_max9485_clk(MAX9485_MCLK_FREQ_122880); + clk = 12288000; + break; + case 11025: + case 22050: + case 44100: + case 88200: + set_max9485_clk(MAX9485_MCLK_FREQ_112896); + clk = 11289600; + break; + } + + fmt = SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS; + + /* setup the CODEC DAI */ + ret = snd_soc_dai_set_fmt(codec_dai, fmt); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_sysclk(codec_dai, 0, clk, 0); + if (ret < 0) + return ret; + + /* setup the CPU DAI */ + ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, clk); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_fmt(cpu_dai, fmt); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_clkdiv(cpu_dai, PXA_SSP_DIV_SCR, 4); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_EXT, 0, 1); + if (ret < 0) + return ret; + + return 0; +} + +static struct snd_soc_ops raumfeld_cs4270_ops = { + .startup = raumfeld_cs4270_startup, + .hw_params = raumfeld_cs4270_hw_params, +}; + +static int raumfeld_line_suspend(struct platform_device *pdev, pm_message_t state) +{ + raumfeld_enable_audio(false); + return 0; +} + +static int raumfeld_line_resume(struct platform_device *pdev) +{ + raumfeld_enable_audio(true); + return 0; +} + +static struct snd_soc_dai_link raumfeld_line_dai = { + .name = "CS4270", + .stream_name = "CS4270", + .cpu_dai = &pxa_ssp_dai[PXA_DAI_SSP1], + .codec_dai = &cs4270_dai, + .ops = &raumfeld_cs4270_ops, +}; + +static struct snd_soc_card snd_soc_line_raumfeld = { + .name = "Raumfeld analog", + .platform = &pxa2xx_soc_platform, + .dai_link = &raumfeld_line_dai, + .suspend_post = raumfeld_line_suspend, + .resume_pre = raumfeld_line_resume, + .num_links = 1, +}; + + +/* AK4104 */ + +static int raumfeld_ak4104_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + int fmt, ret = 0, clk = 0; + + switch (params_rate(params)) { + case 8000: + case 16000: + case 48000: + case 96000: + set_max9485_clk(MAX9485_MCLK_FREQ_122880); + clk = 12288000; + break; + case 11025: + case 22050: + case 44100: + case 88200: + set_max9485_clk(MAX9485_MCLK_FREQ_112896); + clk = 11289600; + break; + } + + fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF; + + /* setup the CODEC DAI */ + ret = snd_soc_dai_set_fmt(codec_dai, fmt | SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) + return ret; + + /* setup the CPU DAI */ + ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, clk); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_fmt(cpu_dai, fmt | SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_clkdiv(cpu_dai, PXA_SSP_DIV_SCR, 4); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_EXT, 0, 1); + if (ret < 0) + return ret; + + return 0; +} + +static struct snd_soc_ops raumfeld_ak4104_ops = { + .hw_params = raumfeld_ak4104_hw_params, +}; + +static struct snd_soc_dai_link raumfeld_spdif_dai = { + .name = "ak4104", + .stream_name = "Playback", + .cpu_dai = &pxa_ssp_dai[PXA_DAI_SSP2], + .codec_dai = &ak4104_dai, + .ops = &raumfeld_ak4104_ops, +}; + +static struct snd_soc_card snd_soc_spdif_raumfeld = { + .name = "Raumfeld S/PDIF", + .platform = &pxa2xx_soc_platform, + .dai_link = &raumfeld_spdif_dai, + .num_links = 1 +}; + +/* raumfeld_audio audio subsystem */ +static struct snd_soc_device raumfeld_line_devdata = { + .card = &snd_soc_line_raumfeld, + .codec_dev = &soc_codec_device_cs4270, +}; + +static struct snd_soc_device raumfeld_spdif_devdata = { + .card = &snd_soc_spdif_raumfeld, + .codec_dev = &soc_codec_device_ak4104, +}; + +static struct platform_device *raumfeld_audio_line_device; +static struct platform_device *raumfeld_audio_spdif_device; + +static int __init raumfeld_audio_init(void) +{ + int ret; + + if (!machine_is_raumfeld_speaker() && + !machine_is_raumfeld_connector()) + return 0; + + max9486_client = i2c_new_device(i2c_get_adapter(0), + &max9486_hwmon_info); + + if (!max9486_client) + return -ENOMEM; + + set_max9485_clk(MAX9485_MCLK_FREQ_122880); + + /* LINE */ + raumfeld_audio_line_device = platform_device_alloc("soc-audio", 0); + if (!raumfeld_audio_line_device) + return -ENOMEM; + + platform_set_drvdata(raumfeld_audio_line_device, + &raumfeld_line_devdata); + raumfeld_line_devdata.dev = &raumfeld_audio_line_device->dev; + ret = platform_device_add(raumfeld_audio_line_device); + if (ret) + platform_device_put(raumfeld_audio_line_device); + + /* no S/PDIF on Speakers */ + if (machine_is_raumfeld_speaker()) + return ret; + + /* S/PDIF */ + raumfeld_audio_spdif_device = platform_device_alloc("soc-audio", 1); + if (!raumfeld_audio_spdif_device) { + platform_device_put(raumfeld_audio_line_device); + return -ENOMEM; + } + + platform_set_drvdata(raumfeld_audio_spdif_device, + &raumfeld_spdif_devdata); + raumfeld_spdif_devdata.dev = &raumfeld_audio_spdif_device->dev; + ret = platform_device_add(raumfeld_audio_spdif_device); + if (ret) { + platform_device_put(raumfeld_audio_line_device); + platform_device_put(raumfeld_audio_spdif_device); + } + + raumfeld_enable_audio(true); + + return ret; +} + +static void __exit raumfeld_audio_exit(void) +{ + raumfeld_enable_audio(false); + + platform_device_unregister(raumfeld_audio_line_device); + + if (machine_is_raumfeld_connector()) + platform_device_unregister(raumfeld_audio_spdif_device); + + i2c_unregister_device(max9486_client); + + gpio_free(GPIO_MCLK_RESET); + gpio_free(GPIO_CODEC_RESET); + gpio_free(GPIO_SPDIF_RESET); +} + +module_init(raumfeld_audio_init); +module_exit(raumfeld_audio_exit); + +/* Module information */ +MODULE_AUTHOR("Daniel Mack "); +MODULE_DESCRIPTION("Raumfeld audio SoC"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From dd2e5a156525f11754d9b1e0583f6bb49c253d62 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Tue, 3 Nov 2009 10:27:34 +0100 Subject: pcmcia: remove deprecated handle_to_dev() macro Update remaining users and remove deprecated handle_to_dev() macro CC: Harald Welte CC: netdev@vger.kernel.org CC: linux-wireless@vger.kernel.org CC: linux-serial@vger.kernel.org Signed-off-by: Dominik Brodowski --- sound/pcmcia/pdaudiocf/pdaudiocf.c | 2 +- sound/pcmcia/vx/vxpocket.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf.c b/sound/pcmcia/pdaudiocf/pdaudiocf.c index 64b859925c0..447aaaee3be 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf.c @@ -131,7 +131,7 @@ static int snd_pdacf_probe(struct pcmcia_device *link) return err; } - snd_card_set_dev(card, &handle_to_dev(link)); + snd_card_set_dev(card, &link->dev); pdacf->index = i; card_list[i] = card; diff --git a/sound/pcmcia/vx/vxpocket.c b/sound/pcmcia/vx/vxpocket.c index 1492744ad67..5a5db48a91a 100644 --- a/sound/pcmcia/vx/vxpocket.c +++ b/sound/pcmcia/vx/vxpocket.c @@ -244,7 +244,7 @@ static int vxpocket_config(struct pcmcia_device *link) if (ret) goto failed; - chip->dev = &handle_to_dev(link); + chip->dev = &link->dev; snd_card_set_dev(chip->card, chip->dev); if (snd_vxpocket_assign_resources(chip, link->io.BasePort1, link->irq.AssignedIRQ) < 0) -- cgit v1.2.3 From 5fa9167a1bf5f5a4b7282f5e7ac56a4a5a1fa044 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sun, 8 Nov 2009 17:24:46 +0100 Subject: pcmcia: rework the irq_req_t typedef Most of the irq_req_t typedef'd struct can be re-worked quite easily: (1) IRQInfo2 was unused in any case, so drop it. (2) IRQInfo1 was used write-only, so drop it. (3) Instance (private data to be passed to the IRQ handler): Most PCMCIA drivers using pcmcia_request_irq() to actually register an IRQ handler set the "dev_id" to the same pointer as the "priv" pointer in struct pcmcia_device. Modify the two exceptions (ipwireless, ibmtr_cs) to also work this waym and set the IRQ handler's "dev_id" to p_dev->priv unconditionally. (4) Handler is to be of type irq_handler_t. (5) Handler != NULL already tells whether an IRQ handler is present. Therefore, we do not need the IRQ_HANDLER_PRESENT flag in irq_req_t.Attributes. CC: netdev@vger.kernel.org CC: linux-bluetooth@vger.kernel.org CC: linux-ide@vger.kernel.org CC: linux-wireless@vger.kernel.org CC: linux-scsi@vger.kernel.org CC: alsa-devel@alsa-project.org CC: Jaroslav Kysela CC: Jiri Kosina CC: Karsten Keil for the Bluetooth parts: Acked-by: Marcel Holtmann Signed-off-by: Dominik Brodowski --- sound/pcmcia/pdaudiocf/pdaudiocf.c | 4 +--- sound/pcmcia/vx/vxpocket.c | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf.c b/sound/pcmcia/pdaudiocf/pdaudiocf.c index 447aaaee3be..7717e01fc07 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf.c @@ -142,12 +142,10 @@ static int snd_pdacf_probe(struct pcmcia_device *link) link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; link->io.NumPorts1 = 16; - link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT | IRQ_FORCED_PULSE; + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_FORCED_PULSE; // link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED; - link->irq.IRQInfo1 = 0 /* | IRQ_LEVEL_ID */; link->irq.Handler = pdacf_interrupt; - link->irq.Instance = pdacf; link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.IntType = INT_MEMORY_AND_IO; link->conf.ConfigIndex = 1; diff --git a/sound/pcmcia/vx/vxpocket.c b/sound/pcmcia/vx/vxpocket.c index 5a5db48a91a..7be3b335704 100644 --- a/sound/pcmcia/vx/vxpocket.c +++ b/sound/pcmcia/vx/vxpocket.c @@ -161,11 +161,9 @@ static int snd_vxpocket_new(struct snd_card *card, int ibl, link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; link->io.NumPorts1 = 16; - link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; - link->irq.IRQInfo1 = IRQ_LEVEL_ID; link->irq.Handler = &snd_vx_irq_handler; - link->irq.Instance = chip; link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.IntType = INT_MEMORY_AND_IO; -- cgit v1.2.3 From 70a5f1187bcb3fac93a7d5c5fcfc5fc76b9c3f55 Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Mon, 30 Nov 2009 07:45:47 +0100 Subject: ALSA: opti-miro: separate comon probing code Separate common probing code in order to use it for PnP probing. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai --- sound/isa/opti9xx/miro.c | 273 +++++++++++++++++++++++++---------------------- 1 file changed, 147 insertions(+), 126 deletions(-) (limited to 'sound') diff --git a/sound/isa/opti9xx/miro.c b/sound/isa/opti9xx/miro.c index e374869e3e2..c67bc3cd2c6 100644 --- a/sound/isa/opti9xx/miro.c +++ b/sound/isa/opti9xx/miro.c @@ -1142,28 +1142,39 @@ __skip_mpu: return 0; } +static int __devinit snd_miro_opti_check(struct snd_miro *chip) +{ + unsigned char value; + + chip->res_mc_base = request_region(chip->mc_base, chip->mc_base_size, + "OPTi9xx MC"); + if (chip->res_mc_base == NULL) + return -ENOMEM; + + value = snd_miro_read(chip, OPTi9XX_MC_REG(1)); + if (value != 0xff && value != inb(chip->mc_base + OPTi9XX_MC_REG(1))) + if (value == snd_miro_read(chip, OPTi9XX_MC_REG(1))) + return 0; + + release_and_free_resource(chip->res_mc_base); + chip->res_mc_base = NULL; + + return -ENODEV; +} + static int __devinit snd_card_miro_detect(struct snd_card *card, struct snd_miro *chip) { int i, err; - unsigned char value; for (i = OPTi9XX_HW_82C929; i <= OPTi9XX_HW_82C924; i++) { if ((err = snd_miro_init(chip, i)) < 0) return err; - if ((chip->res_mc_base = request_region(chip->mc_base, chip->mc_base_size, "OPTi9xx MC")) == NULL) - continue; - - value = snd_miro_read(chip, OPTi9XX_MC_REG(1)); - if ((value != 0xff) && (value != inb(chip->mc_base + 1))) - if (value == snd_miro_read(chip, OPTi9XX_MC_REG(1))) - return 1; - - release_and_free_resource(chip->res_mc_base); - chip->res_mc_base = NULL; - + err = snd_miro_opti_check(chip); + if (err == 0) + return 1; } return -ENODEV; @@ -1234,151 +1245,69 @@ static void snd_card_miro_free(struct snd_card *card) release_and_free_resource(miro->res_mc_base); } -static int __devinit snd_miro_match(struct device *devptr, unsigned int n) -{ - return 1; -} - -static int __devinit snd_miro_probe(struct device *devptr, unsigned int n) +static int __devinit snd_miro_probe(struct snd_card *card) { - static long possible_ports[] = {0x530, 0xe80, 0xf40, 0x604, -1}; - static long possible_mpu_ports[] = {0x330, 0x300, 0x310, 0x320, -1}; - static int possible_irqs[] = {11, 9, 10, 7, -1}; - static int possible_mpu_irqs[] = {10, 5, 9, 7, -1}; - static int possible_dma1s[] = {3, 1, 0, -1}; - static int possible_dma2s[][2] = {{1,-1}, {0,-1}, {-1,-1}, {0,-1}}; - int error; - struct snd_miro *miro; + struct snd_miro *miro = card->private_data; struct snd_wss *codec; struct snd_timer *timer; - struct snd_card *card; struct snd_pcm *pcm; struct snd_rawmidi *rmidi; - error = snd_card_create(index, id, THIS_MODULE, - sizeof(struct snd_miro), &card); - if (error < 0) - return error; - - card->private_free = snd_card_miro_free; - miro = card->private_data; - - error = snd_card_miro_detect(card, miro); - if (error < 0) { - snd_card_free(card); - snd_printk(KERN_ERR "unable to detect OPTi9xx chip\n"); - return -ENODEV; + if (!miro->res_mc_base) { + miro->res_mc_base = request_region(miro->mc_base, + miro->mc_base_size, + "miro (OPTi9xx MC)"); + if (miro->res_mc_base == NULL) { + snd_printk(KERN_ERR "request for OPTI9xx MC failed\n"); + return -ENOMEM; + } } - if ((error = snd_card_miro_aci_detect(card, miro)) < 0) { + error = snd_card_miro_aci_detect(card, miro); + if (error < 0) { snd_card_free(card); snd_printk(KERN_ERR "unable to detect aci chip\n"); return -ENODEV; } - /* init proc interface */ - snd_miro_proc_init(card, miro); - - - if (! miro->res_mc_base && - (miro->res_mc_base = request_region(miro->mc_base, miro->mc_base_size, - "miro (OPTi9xx MC)")) == NULL) { - snd_card_free(card); - snd_printk(KERN_ERR "request for OPTI9xx MC failed\n"); - return -ENOMEM; - } - miro->wss_base = port; + miro->mpu_port = mpu_port; miro->irq = irq; miro->mpu_irq = mpu_irq; miro->dma1 = dma1; miro->dma2 = dma2; - if (miro->wss_base == SNDRV_AUTO_PORT) { - if ((miro->wss_base = snd_legacy_find_free_ioport(possible_ports, 4)) < 0) { - snd_card_free(card); - snd_printk(KERN_ERR "unable to find a free WSS port\n"); - return -EBUSY; - } - } - - if (mpu_port == SNDRV_AUTO_PORT) { - mpu_port = snd_legacy_find_free_ioport(possible_mpu_ports, 2); - if (mpu_port < 0) { - snd_card_free(card); - snd_printk(KERN_ERR "unable to find a free MPU401 port\n"); - return -EBUSY; - } - } - miro->mpu_port = mpu_port; - - if (miro->irq == SNDRV_AUTO_IRQ) { - if ((miro->irq = snd_legacy_find_free_irq(possible_irqs)) < 0) { - snd_card_free(card); - snd_printk(KERN_ERR "unable to find a free IRQ\n"); - return -EBUSY; - } - } - if (miro->mpu_irq == SNDRV_AUTO_IRQ) { - if ((miro->mpu_irq = snd_legacy_find_free_irq(possible_mpu_irqs)) < 0) { - snd_card_free(card); - snd_printk(KERN_ERR "unable to find a free MPU401 IRQ\n"); - return -EBUSY; - } - } - if (miro->dma1 == SNDRV_AUTO_DMA) { - if ((miro->dma1 = snd_legacy_find_free_dma(possible_dma1s)) < 0) { - snd_card_free(card); - snd_printk(KERN_ERR "unable to find a free DMA1\n"); - return -EBUSY; - } - } - if (miro->dma2 == SNDRV_AUTO_DMA) { - if ((miro->dma2 = snd_legacy_find_free_dma(possible_dma2s[miro->dma1 % 4])) < 0) { - snd_card_free(card); - snd_printk(KERN_ERR "unable to find a free DMA2\n"); - return -EBUSY; - } - } + /* init proc interface */ + snd_miro_proc_init(card, miro); error = snd_miro_configure(miro); - if (error) { - snd_card_free(card); + if (error) return error; - } error = snd_wss_create(card, miro->wss_base + 4, -1, - miro->irq, miro->dma1, miro->dma2, - WSS_HW_AD1845, 0, &codec); - if (error < 0) { - snd_card_free(card); + miro->irq, miro->dma1, miro->dma2, + WSS_HW_DETECT, 0, &codec); + if (error < 0) return error; - } error = snd_wss_pcm(codec, 0, &pcm); - if (error < 0) { - snd_card_free(card); + if (error < 0) return error; - } + error = snd_wss_mixer(codec); - if (error < 0) { - snd_card_free(card); + if (error < 0) return error; - } + error = snd_wss_timer(codec, 0, &timer); - if (error < 0) { - snd_card_free(card); + if (error < 0) return error; - } miro->pcm = pcm; error = snd_miro_mixer(card, miro); - if (error < 0) { - snd_card_free(card); + if (error < 0) return error; - } if (miro->aci->aci_vendor == 'm') { /* It looks like a miro sound card. */ @@ -1425,20 +1354,111 @@ static int __devinit snd_miro_probe(struct device *devptr, unsigned int n) if (fm_port > 0 && fm_port != SNDRV_AUTO_PORT) { struct snd_opl3 *opl3 = NULL; struct snd_opl4 *opl4; + if (snd_opl4_create(card, fm_port, fm_port - 8, 2, &opl3, &opl4) < 0) snd_printk(KERN_WARNING "no OPL4 device at 0x%lx\n", fm_port); } - if ((error = snd_set_aci_init_values(miro)) < 0) { - snd_card_free(card); + error = snd_set_aci_init_values(miro); + if (error < 0) return error; + + return snd_card_register(card); +} + +static int __devinit snd_miro_isa_match(struct device *devptr, unsigned int n) +{ + return 1; +} + +static int __devinit snd_miro_isa_probe(struct device *devptr, unsigned int n) +{ + static long possible_ports[] = {0x530, 0xe80, 0xf40, 0x604, -1}; + static long possible_mpu_ports[] = {0x330, 0x300, 0x310, 0x320, -1}; + static int possible_irqs[] = {11, 9, 10, 7, -1}; + static int possible_mpu_irqs[] = {10, 5, 9, 7, -1}; + static int possible_dma1s[] = {3, 1, 0, -1}; + static int possible_dma2s[][2] = { {1, -1}, {0, -1}, {-1, -1}, + {0, -1} }; + + int error; + struct snd_miro *miro; + struct snd_card *card; + + error = snd_card_create(index, id, THIS_MODULE, + sizeof(struct snd_miro), &card); + if (error < 0) + return error; + + card->private_free = snd_card_miro_free; + miro = card->private_data; + + error = snd_card_miro_detect(card, miro); + if (error < 0) { + snd_card_free(card); + snd_printk(KERN_ERR "unable to detect OPTi9xx chip\n"); + return -ENODEV; + } + + if (port == SNDRV_AUTO_PORT) { + port = snd_legacy_find_free_ioport(possible_ports, 4); + if (port < 0) { + snd_card_free(card); + snd_printk(KERN_ERR "unable to find a free WSS port\n"); + return -EBUSY; + } + } + + if (mpu_port == SNDRV_AUTO_PORT) { + mpu_port = snd_legacy_find_free_ioport(possible_mpu_ports, 2); + if (mpu_port < 0) { + snd_card_free(card); + snd_printk(KERN_ERR + "unable to find a free MPU401 port\n"); + return -EBUSY; + } + } + + if (irq == SNDRV_AUTO_IRQ) { + irq = snd_legacy_find_free_irq(possible_irqs); + if (irq < 0) { + snd_card_free(card); + snd_printk(KERN_ERR "unable to find a free IRQ\n"); + return -EBUSY; + } + } + if (mpu_irq == SNDRV_AUTO_IRQ) { + mpu_irq = snd_legacy_find_free_irq(possible_mpu_irqs); + if (mpu_irq < 0) { + snd_card_free(card); + snd_printk(KERN_ERR + "unable to find a free MPU401 IRQ\n"); + return -EBUSY; + } + } + if (dma1 == SNDRV_AUTO_DMA) { + dma1 = snd_legacy_find_free_dma(possible_dma1s); + if (dma1 < 0) { + snd_card_free(card); + snd_printk(KERN_ERR "unable to find a free DMA1\n"); + return -EBUSY; + } + } + if (dma2 == SNDRV_AUTO_DMA) { + dma2 = snd_legacy_find_free_dma(possible_dma2s[dma1 % 4]); + if (dma2 < 0) { + snd_card_free(card); + snd_printk(KERN_ERR "unable to find a free DMA2\n"); + return -EBUSY; + } } snd_card_set_dev(card, devptr); - if ((error = snd_card_register(card))) { + error = snd_miro_probe(card); + if (error < 0) { snd_card_free(card); return error; } @@ -1447,7 +1467,8 @@ static int __devinit snd_miro_probe(struct device *devptr, unsigned int n) return 0; } -static int __devexit snd_miro_remove(struct device *devptr, unsigned int dev) +static int __devexit snd_miro_isa_remove(struct device *devptr, + unsigned int dev) { snd_card_free(dev_get_drvdata(devptr)); dev_set_drvdata(devptr, NULL); @@ -1457,9 +1478,9 @@ static int __devexit snd_miro_remove(struct device *devptr, unsigned int dev) #define DEV_NAME "miro" static struct isa_driver snd_miro_driver = { - .match = snd_miro_match, - .probe = snd_miro_probe, - .remove = __devexit_p(snd_miro_remove), + .match = snd_miro_isa_match, + .probe = snd_miro_isa_probe, + .remove = __devexit_p(snd_miro_isa_remove), /* FIXME: suspend/resume */ .driver = { .name = DEV_NAME -- cgit v1.2.3 From 306ecee926cf79f1b3b5f6035be09ef3d83f1b76 Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Mon, 30 Nov 2009 07:46:56 +0100 Subject: ALSA: opti-miro: add PnP detection The PCM12 and PCM20 can be set into the ISA PnP mode. The PCM12 PnP was sold as the PnP device. Add code to handle detection of these cards using ISA PnP framework. Tested on the PCM20 in PnP mode. The PCM12 PnP has the same MS Windows INF file except for a card name displayed for user. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai --- sound/isa/opti9xx/miro.c | 203 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 192 insertions(+), 11 deletions(-) (limited to 'sound') diff --git a/sound/isa/opti9xx/miro.c b/sound/isa/opti9xx/miro.c index c67bc3cd2c6..6123c753111 100644 --- a/sound/isa/opti9xx/miro.c +++ b/sound/isa/opti9xx/miro.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -60,6 +61,9 @@ static int dma1 = SNDRV_DEFAULT_DMA1; /* 0,1,3 */ static int dma2 = SNDRV_DEFAULT_DMA1; /* 0,1,3 */ static int wss; static int ide; +#ifdef CONFIG_PNP +static int isapnp = 1; /* Enable ISA PnP detection */ +#endif module_param(index, int, 0444); MODULE_PARM_DESC(index, "Index value for miro soundcard."); @@ -83,6 +87,10 @@ module_param(wss, int, 0444); MODULE_PARM_DESC(wss, "wss mode"); module_param(ide, int, 0444); MODULE_PARM_DESC(ide, "enable ide port"); +#ifdef CONFIG_PNP +module_param(isapnp, bool, 0444); +MODULE_PARM_DESC(isapnp, "Enable ISA PnP detection for specified soundcard."); +#endif #define OPTi9XX_HW_DETECT 0 #define OPTi9XX_HW_82C928 1 @@ -131,6 +139,21 @@ static char * snd_opti9xx_names[] = { "82C930", "82C931", "82C933" }; +static int snd_miro_pnp_is_probed; + +#ifdef CONFIG_PNP + +static struct pnp_card_device_id snd_miro_pnpids[] = { + /* PCM20 and PCM12 in PnP mode */ + { .id = "MIR0924", + .devs = { { "MIR0000" }, { "MIR0002" }, { "MIR0005" } }, }, + { .id = "" } +}; + +MODULE_DEVICE_TABLE(pnp_card, snd_miro_pnpids); + +#endif /* CONFIG_PNP */ + /* * ACI control */ @@ -781,17 +804,23 @@ static int __devinit snd_miro_init(struct snd_miro *chip, chip->mpu_port = -1; chip->mpu_irq = -1; + chip->pwd_reg = 3; + +#ifdef CONFIG_PNP + if (isapnp && chip->mc_base) + /* PnP resource gives the least 10 bits */ + chip->mc_base |= 0xc00; + else +#endif + chip->mc_base = 0xf8c; + switch (hardware) { case OPTi9XX_HW_82C929: - chip->mc_base = 0xf8c; chip->password = 0xe3; - chip->pwd_reg = 3; break; case OPTi9XX_HW_82C924: - chip->mc_base = 0xf8c; chip->password = 0xe5; - chip->pwd_reg = 3; break; default: @@ -1014,17 +1043,22 @@ static int __devinit snd_miro_configure(struct snd_miro *chip) return -EINVAL; } - switch (chip->wss_base) { - case 0x530: + /* PnP resource says it decodes only 10 bits of address */ + switch (chip->wss_base & 0x3ff) { + case 0x130: + chip->wss_base = 0x530; wss_base_bits = 0x00; break; - case 0x604: + case 0x204: + chip->wss_base = 0x604; wss_base_bits = 0x03; break; - case 0xe80: + case 0x280: + chip->wss_base = 0xe80; wss_base_bits = 0x01; break; - case 0xf40: + case 0x340: + chip->wss_base = 0xf40; wss_base_bits = 0x02; break; default: @@ -1238,7 +1272,7 @@ static int __devinit snd_card_miro_aci_detect(struct snd_card *card, static void snd_card_miro_free(struct snd_card *card) { struct snd_miro *miro = card->private_data; - + release_and_free_resource(miro->res_aci_port); if (miro->aci) miro->aci->aci_port = 0; @@ -1370,6 +1404,12 @@ static int __devinit snd_miro_probe(struct snd_card *card) static int __devinit snd_miro_isa_match(struct device *devptr, unsigned int n) { +#ifdef CONFIG_PNP + if (snd_miro_pnp_is_probed) + return 0; + if (isapnp) + return 0; +#endif return 1; } @@ -1487,14 +1527,155 @@ static struct isa_driver snd_miro_driver = { }, }; +#ifdef CONFIG_PNP + +static int __devinit snd_card_miro_pnp(struct snd_miro *chip, + struct pnp_card_link *card, + const struct pnp_card_device_id *pid) +{ + struct pnp_dev *pdev; + int err; + struct pnp_dev *devmpu; + struct pnp_dev *devmc; + + pdev = pnp_request_card_device(card, pid->devs[0].id, NULL); + if (pdev == NULL) + return -EBUSY; + + devmpu = pnp_request_card_device(card, pid->devs[1].id, NULL); + if (devmpu == NULL) + return -EBUSY; + + devmc = pnp_request_card_device(card, pid->devs[2].id, NULL); + if (devmc == NULL) + return -EBUSY; + + err = pnp_activate_dev(pdev); + if (err < 0) { + snd_printk(KERN_ERR "AUDIO pnp configure failure: %d\n", err); + return err; + } + + err = pnp_activate_dev(devmc); + if (err < 0) { + snd_printk(KERN_ERR "OPL syntg pnp configure failure: %d\n", + err); + return err; + } + + port = pnp_port_start(pdev, 1); + fm_port = pnp_port_start(pdev, 2) + 8; + + /* + * The MC(0) is never accessed and the miroSOUND PCM20 card does not + * include it in the PnP resource range. OPTI93x include it. + */ + chip->mc_base = pnp_port_start(devmc, 0) - 1; + chip->mc_base_size = pnp_port_len(devmc, 0) + 1; + + irq = pnp_irq(pdev, 0); + dma1 = pnp_dma(pdev, 0); + dma2 = pnp_dma(pdev, 1); + + if (mpu_port > 0) { + err = pnp_activate_dev(devmpu); + if (err < 0) { + snd_printk(KERN_ERR "MPU401 pnp configure failure\n"); + mpu_port = -1; + return err; + } + mpu_port = pnp_port_start(devmpu, 0); + mpu_irq = pnp_irq(devmpu, 0); + } + return 0; +} + +static int __devinit snd_miro_pnp_probe(struct pnp_card_link *pcard, + const struct pnp_card_device_id *pid) +{ + struct snd_card *card; + int err; + struct snd_miro *miro; + + if (snd_miro_pnp_is_probed) + return -EBUSY; + if (!isapnp) + return -ENODEV; + err = snd_card_create(index, id, THIS_MODULE, + sizeof(struct snd_miro), &card); + if (err < 0) + return err; + + card->private_free = snd_card_miro_free; + miro = card->private_data; + + err = snd_card_miro_pnp(miro, pcard, pid); + if (err) { + snd_card_free(card); + return err; + } + + /* only miroSOUND PCM20 and PCM12 == OPTi924 */ + err = snd_miro_init(miro, OPTi9XX_HW_82C924); + if (err) { + snd_card_free(card); + return err; + } + + err = snd_miro_opti_check(miro); + if (err) { + snd_printk(KERN_ERR "OPTI chip not found\n"); + snd_card_free(card); + return err; + } + + snd_card_set_dev(card, &pcard->card->dev); + err = snd_miro_probe(card); + if (err < 0) { + snd_card_free(card); + return err; + } + pnp_set_card_drvdata(pcard, card); + snd_miro_pnp_is_probed = 1; + return 0; +} + +static void __devexit snd_miro_pnp_remove(struct pnp_card_link * pcard) +{ + snd_card_free(pnp_get_card_drvdata(pcard)); + pnp_set_card_drvdata(pcard, NULL); + snd_miro_pnp_is_probed = 0; +} + +static struct pnp_card_driver miro_pnpc_driver = { + .flags = PNP_DRIVER_RES_DISABLE, + .name = "miro", + .id_table = snd_miro_pnpids, + .probe = snd_miro_pnp_probe, + .remove = __devexit_p(snd_miro_pnp_remove), +}; +#endif + static int __init alsa_card_miro_init(void) { +#ifdef CONFIG_PNP + pnp_register_card_driver(&miro_pnpc_driver); + if (snd_miro_pnp_is_probed) + return 0; + pnp_unregister_card_driver(&miro_pnpc_driver); +#endif return isa_register_driver(&snd_miro_driver, 1); } static void __exit alsa_card_miro_exit(void) { - isa_unregister_driver(&snd_miro_driver); + if (!snd_miro_pnp_is_probed) { + isa_unregister_driver(&snd_miro_driver); + return; + } +#ifdef CONFIG_PNP + pnp_unregister_card_driver(&miro_pnpc_driver); +#endif } module_init(alsa_card_miro_init) -- cgit v1.2.3 From 785d1c45ce11820d5838eb6399caa0ac98c836cf Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 30 Nov 2009 20:24:48 +0900 Subject: ASoC: sh: fsi: Add runtime PM support This patch add support runtime PM. Driver callbacks for Runtime PM are empty because the device registers are always re-initialized after pm_runtime_get_sync(). The Runtime PM functions replaces the clock framework module stop bit handling in this driver. Signed-off-by: Kuninori Morimoto Acked-by: Paul Mundt Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/sh/fsi.c | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index e1a3d1a2b4c..9c49c11c43c 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include @@ -105,7 +105,6 @@ struct fsi_priv { struct fsi_master { void __iomem *base; int irq; - struct clk *clk; struct fsi_priv fsia; struct fsi_priv fsib; struct sh_fsi_platform_info *info; @@ -559,7 +558,7 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream, int is_master; int ret = 0; - clk_enable(master->clk); + pm_runtime_get_sync(dai->dev); /* CKG1 */ data = is_play ? (1 << 0) : (1 << 4); @@ -674,7 +673,7 @@ static void fsi_dai_shutdown(struct snd_pcm_substream *substream, fsi_irq_disable(fsi, is_play); fsi_clk_ctrl(fsi, 0); - clk_disable(master->clk); + pm_runtime_put_sync(dai->dev); } static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd, @@ -872,7 +871,6 @@ EXPORT_SYMBOL_GPL(fsi_soc_platform); static int fsi_probe(struct platform_device *pdev) { struct resource *res; - char clk_name[8]; unsigned int irq; int ret; @@ -903,14 +901,8 @@ static int fsi_probe(struct platform_device *pdev) master->fsia.base = master->base; master->fsib.base = master->base + 0x40; - /* FSI is based on SPU mstp */ - snprintf(clk_name, sizeof(clk_name), "spu%d", pdev->id); - master->clk = clk_get(NULL, clk_name); - if (IS_ERR(master->clk)) { - dev_err(&pdev->dev, "cannot get %s mstp\n", clk_name); - ret = -EIO; - goto exit_iounmap; - } + pm_runtime_enable(&pdev->dev); + pm_runtime_resume(&pdev->dev); fsi_soc_dai[0].dev = &pdev->dev; fsi_soc_dai[1].dev = &pdev->dev; @@ -935,6 +927,7 @@ exit_free_irq: free_irq(irq, master); exit_iounmap: iounmap(master->base); + pm_runtime_disable(&pdev->dev); exit_kfree: kfree(master); master = NULL; @@ -947,7 +940,7 @@ static int fsi_remove(struct platform_device *pdev) snd_soc_unregister_dais(fsi_soc_dai, ARRAY_SIZE(fsi_soc_dai)); snd_soc_unregister_platform(&fsi_soc_platform); - clk_put(master->clk); + pm_runtime_disable(&pdev->dev); free_irq(master->irq, master); @@ -957,9 +950,27 @@ static int fsi_remove(struct platform_device *pdev) return 0; } +static int fsi_runtime_nop(struct device *dev) +{ + /* Runtime PM callback shared between ->runtime_suspend() + * and ->runtime_resume(). Simply returns success. + * + * This driver re-initializes all registers after + * pm_runtime_get_sync() anyway so there is no need + * to save and restore registers here. + */ + return 0; +} + +static struct dev_pm_ops fsi_pm_ops = { + .runtime_suspend = fsi_runtime_nop, + .runtime_resume = fsi_runtime_nop, +}; + static struct platform_driver fsi_driver = { .driver = { .name = "sh_fsi", + .pm = &fsi_pm_ops, }, .probe = fsi_probe, .remove = fsi_remove, -- cgit v1.2.3 From a649d1fcc9bd2299cb06b6594fabb429fa50f174 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Mon, 30 Nov 2009 14:06:37 +0100 Subject: ASoC: pxa/raumfeld: adopt new snd_soc_dai_set_pll() API ALSA's for-2.6.33 branch has a new source argument to snd_soc_dai_set_pll(). Signed-off-by: Daniel Mack Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/pxa/raumfeld.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/pxa/raumfeld.c b/sound/soc/pxa/raumfeld.c index f272269c05d..acfce1c0f1c 100644 --- a/sound/soc/pxa/raumfeld.c +++ b/sound/soc/pxa/raumfeld.c @@ -116,7 +116,7 @@ static int raumfeld_cs4270_hw_params(struct snd_pcm_substream *substream, return ret; /* setup the CPU DAI */ - ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, clk); + ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, 0, clk); if (ret < 0) return ret; @@ -205,7 +205,7 @@ static int raumfeld_ak4104_hw_params(struct snd_pcm_substream *substream, return ret; /* setup the CPU DAI */ - ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, clk); + ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, 0, clk); if (ret < 0) return ret; -- cgit v1.2.3 From 4acd57c3de62374fe5bb52e5cd24538190f4eab2 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 29 Nov 2009 16:39:52 +0000 Subject: ALSA: AACI: fix AC97 multiple-open bug Signed-off-by: Russell King Cc: Signed-off-by: Takashi Iwai --- sound/arm/aaci.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sound') diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c index 1f0f8213e2d..1cb7c282a1f 100644 --- a/sound/arm/aaci.c +++ b/sound/arm/aaci.c @@ -504,6 +504,10 @@ static int aaci_pcm_hw_params(struct snd_pcm_substream *substream, int err; aaci_pcm_hw_free(substream); + if (aacirun->pcm_open) { + snd_ac97_pcm_close(aacirun->pcm); + aacirun->pcm_open = 0; + } err = devdma_hw_alloc(NULL, substream, params_buffer_bytes(params)); -- cgit v1.2.3 From 8ee763b9c82c6ca0a59a7271ce4fa29d7baf5c09 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 29 Nov 2009 16:39:59 +0000 Subject: ALSA: AACI: fix recording bug pcm->r[1].slots is the double rate slot information, not the capture information. For capture, 'pcm' will already be the capture ac97 pcm structure. Signed-off-by: Russell King Cc: Signed-off-by: Takashi Iwai --- sound/arm/aaci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c index 1cb7c282a1f..6c160a038b2 100644 --- a/sound/arm/aaci.c +++ b/sound/arm/aaci.c @@ -521,7 +521,7 @@ static int aaci_pcm_hw_params(struct snd_pcm_substream *substream, else err = snd_ac97_pcm_open(aacirun->pcm, params_rate(params), params_channels(params), - aacirun->pcm->r[1].slots); + aacirun->pcm->r[0].slots); if (err) goto out; -- cgit v1.2.3 From e0feefc70c1bb3f51aa9bb42acfd22cd7472a5d9 Mon Sep 17 00:00:00 2001 From: Alexey Fisher Date: Tue, 1 Dec 2009 13:40:53 +0100 Subject: ALSA: usb - Fix mixer map for Hercules Gamesurround Muse Pocket LT Muse Pocket use brocken mixer names, so alsamixer and PA can't use it correctly This patch add quirk to overwirte default mixers. Signed-off-by: Alexey Fisher Signed-off-by: Takashi Iwai --- sound/usb/usbmixer_maps.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'sound') diff --git a/sound/usb/usbmixer_maps.c b/sound/usb/usbmixer_maps.c index 3e5d66cf1f5..77c35885e21 100644 --- a/sound/usb/usbmixer_maps.c +++ b/sound/usb/usbmixer_maps.c @@ -277,6 +277,22 @@ static struct usbmix_name_map scratch_live_map[] = { { 0 } /* terminator */ }; +/* "Gamesurround Muse Pocket LT" looks same like "Sound Blaster MP3+" + * most importand difference is SU[8], it should be set to "Capture Source" + * to make alsamixer and PA working properly. + * FIXME: or mp3plus_map should use "Capture Source" too, + * so this maps can be merget + */ +static struct usbmix_name_map hercules_usb51_map[] = { + { 8, "Capture Source" }, /* SU, default "PCM Capture Source" */ + { 9, "Master Playback" }, /* FU, default "Speaker Playback" */ + { 10, "Mic Boost", 7 }, /* FU, default "Auto Gain Input" */ + { 11, "Line Capture" }, /* FU, default "PCM Capture" */ + { 13, "Mic Bypass Playback" }, /* FU, default "Mic Playback" */ + { 14, "Line Bypass Playback" }, /* FU, default "Line Playback" */ + { 0 } /* terminator */ +}; + /* * Control map entries */ @@ -315,6 +331,13 @@ static struct usbmix_ctl_map usbmix_ctl_maps[] = { .id = USB_ID(0x06f8, 0xd002), .ignore_ctl_error = 1, }, + { + /* Hercules Gamesurround Muse Pocket LT + * (USB 5.1 Channel Audio Adapter) + */ + .id = USB_ID(0x06f8, 0xc000), + .map = hercules_usb51_map, + }, { .id = USB_ID(0x08bb, 0x2702), .map = linex_map, -- cgit v1.2.3 From cf5bd652c384cf58544f43bea097bbc9cf14e4f5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 1 Dec 2009 16:36:56 +0100 Subject: ALSA: aaci - Clean up duplicate code Now snd_ac97_pcm_open() is called with the exactly same arguments for both playback and capture directions. Remove the unneeded check. Signed-off-by: Takashi Iwai --- sound/arm/aaci.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c index eb715e73210..83b0328d389 100644 --- a/sound/arm/aaci.c +++ b/sound/arm/aaci.c @@ -511,15 +511,9 @@ static int aaci_pcm_hw_params(struct snd_pcm_substream *substream, if (err < 0) goto out; - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - err = snd_ac97_pcm_open(aacirun->pcm, params_rate(params), - params_channels(params), - aacirun->pcm->r[0].slots); - else - err = snd_ac97_pcm_open(aacirun->pcm, params_rate(params), - params_channels(params), - aacirun->pcm->r[0].slots); - + err = snd_ac97_pcm_open(aacirun->pcm, params_rate(params), + params_channels(params), + aacirun->pcm->r[0].slots); if (err) goto out; -- cgit v1.2.3 From d8ea23931ce83b56801976e6f1fa893462c1c477 Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Wed, 2 Dec 2009 23:27:12 +0100 Subject: ALSA: opti9xx: remove snd_opti9xx fields Remove snd_opti9xx fields which are indirect arguments to the snd_opti9xx_configure(). Pass these values as function arguments. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai --- sound/isa/opti9xx/opti92x-ad1848.c | 110 +++++++++++++++---------------------- 1 file changed, 43 insertions(+), 67 deletions(-) (limited to 'sound') diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c index 5cd555325b9..d08c3890644 100644 --- a/sound/isa/opti9xx/opti92x-ad1848.c +++ b/sound/isa/opti9xx/opti92x-ad1848.c @@ -141,15 +141,7 @@ struct snd_opti9xx { spinlock_t lock; - long wss_base; int irq; - int dma1; - int dma2; - - long fm_port; - - long mpu_port; - int mpu_irq; #ifdef CONFIG_PNP struct pnp_dev *dev; @@ -216,13 +208,7 @@ static int __devinit snd_opti9xx_init(struct snd_opti9xx *chip, spin_lock_init(&chip->lock); - chip->wss_base = -1; chip->irq = -1; - chip->dma1 = -1; - chip->dma2 = -1; - chip->fm_port = -1; - chip->mpu_port = -1; - chip->mpu_irq = -1; switch (hardware) { #ifndef OPTi93X @@ -348,7 +334,10 @@ static void snd_opti9xx_write(struct snd_opti9xx *chip, unsigned char reg, (snd_opti9xx_read(chip, reg) & ~(mask)) | ((value) & (mask))) -static int __devinit snd_opti9xx_configure(struct snd_opti9xx *chip) +static int __devinit snd_opti9xx_configure(struct snd_opti9xx *chip, + long wss_base, + int irq, int dma1, int dma2, + long mpu_port, int mpu_irq) { unsigned char wss_base_bits; unsigned char irq_bits; @@ -416,7 +405,7 @@ static int __devinit snd_opti9xx_configure(struct snd_opti9xx *chip) return -EINVAL; } - switch (chip->wss_base) { + switch (wss_base) { case 0x530: wss_base_bits = 0x00; break; @@ -430,14 +419,13 @@ static int __devinit snd_opti9xx_configure(struct snd_opti9xx *chip) wss_base_bits = 0x02; break; default: - snd_printk(KERN_WARNING "WSS port 0x%lx not valid\n", - chip->wss_base); + snd_printk(KERN_WARNING "WSS port 0x%lx not valid\n", wss_base); goto __skip_base; } snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(1), wss_base_bits << 4, 0x30); __skip_base: - switch (chip->irq) { + switch (irq) { //#ifdef OPTi93X case 5: irq_bits = 0x05; @@ -456,11 +444,11 @@ __skip_base: irq_bits = 0x04; break; default: - snd_printk(KERN_WARNING "WSS irq # %d not valid\n", chip->irq); + snd_printk(KERN_WARNING "WSS irq # %d not valid\n", irq); goto __skip_resources; } - switch (chip->dma1) { + switch (dma1) { case 0: dma_bits = 0x01; break; @@ -471,38 +459,36 @@ __skip_base: dma_bits = 0x03; break; default: - snd_printk(KERN_WARNING "WSS dma1 # %d not valid\n", - chip->dma1); + snd_printk(KERN_WARNING "WSS dma1 # %d not valid\n", dma1); goto __skip_resources; } #if defined(CS4231) || defined(OPTi93X) - if (chip->dma1 == chip->dma2) { + if (dma1 == dma2) { snd_printk(KERN_ERR "don't want to share dmas\n"); return -EBUSY; } - switch (chip->dma2) { + switch (dma2) { case 0: case 1: break; default: - snd_printk(KERN_WARNING "WSS dma2 # %d not valid\n", - chip->dma2); + snd_printk(KERN_WARNING "WSS dma2 # %d not valid\n", dma2); goto __skip_resources; } dma_bits |= 0x04; #endif /* CS4231 || OPTi93X */ #ifndef OPTi93X - outb(irq_bits << 3 | dma_bits, chip->wss_base); + outb(irq_bits << 3 | dma_bits, wss_base); #else /* OPTi93X */ snd_opti9xx_write(chip, OPTi9XX_MC_REG(3), (irq_bits << 3 | dma_bits)); #endif /* OPTi93X */ __skip_resources: if (chip->hardware > OPTi9XX_HW_82C928) { - switch (chip->mpu_port) { + switch (mpu_port) { case 0: case -1: break; @@ -520,12 +506,11 @@ __skip_resources: break; default: snd_printk(KERN_WARNING - "MPU-401 port 0x%lx not valid\n", - chip->mpu_port); + "MPU-401 port 0x%lx not valid\n", mpu_port); goto __skip_mpu; } - switch (chip->mpu_irq) { + switch (mpu_irq) { case 5: mpu_irq_bits = 0x02; break; @@ -540,12 +525,12 @@ __skip_resources: break; default: snd_printk(KERN_WARNING "MPU-401 irq # %d not valid\n", - chip->mpu_irq); + mpu_irq); goto __skip_mpu; } snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(6), - (chip->mpu_port <= 0) ? 0x00 : + (mpu_port <= 0) ? 0x00 : 0x80 | mpu_port_bits << 5 | mpu_irq_bits << 3, 0xf8); } @@ -701,6 +686,7 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card) { static long possible_ports[] = {0x530, 0xe80, 0xf40, 0x604, -1}; int error; + int xdma2; struct snd_opti9xx *chip = card->private_data; struct snd_wss *codec; #ifdef CS4231 @@ -715,31 +701,25 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card) "OPTi9xx MC")) == NULL) return -ENOMEM; - chip->wss_base = port; - chip->fm_port = fm_port; - chip->mpu_port = mpu_port; - chip->irq = irq; - chip->mpu_irq = mpu_irq; - chip->dma1 = dma1; #if defined(CS4231) || defined(OPTi93X) - chip->dma2 = dma2; + xdma2 = dma2; #else - chip->dma2 = -1; + xdma2 = -1; #endif - if (chip->wss_base == SNDRV_AUTO_PORT) { - chip->wss_base = snd_legacy_find_free_ioport(possible_ports, 4); - if (chip->wss_base < 0) { + if (port == SNDRV_AUTO_PORT) { + port = snd_legacy_find_free_ioport(possible_ports, 4); + if (port < 0) { snd_printk(KERN_ERR "unable to find a free WSS port\n"); return -EBUSY; } } - error = snd_opti9xx_configure(chip); + error = snd_opti9xx_configure(chip, port, irq, dma1, xdma2, + mpu_port, mpu_irq); if (error) return error; - error = snd_wss_create(card, chip->wss_base + 4, -1, - chip->irq, chip->dma1, chip->dma2, + error = snd_wss_create(card, port + 4, -1, irq, dma1, xdma2, #ifdef OPTi93X WSS_HW_OPTI93X, WSS_HWSHARE_IRQ, #else @@ -763,35 +743,35 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card) return error; #endif #ifdef OPTi93X - error = request_irq(chip->irq, snd_opti93x_interrupt, + error = request_irq(irq, snd_opti93x_interrupt, IRQF_DISABLED, DEV_NAME" - WSS", codec); if (error < 0) { snd_printk(KERN_ERR "opti9xx: can't grab IRQ %d\n", chip->irq); return error; } #endif + chip->irq = irq; strcpy(card->driver, chip->name); sprintf(card->shortname, "OPTi %s", card->driver); #if defined(CS4231) || defined(OPTi93X) sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d&%d", - card->shortname, pcm->name, chip->wss_base + 4, - chip->irq, chip->dma1, chip->dma2); + card->shortname, pcm->name, port + 4, irq, dma1, xdma2); #else sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d", - card->shortname, pcm->name, chip->wss_base + 4, - chip->irq, chip->dma1); + card->shortname, pcm->name, port + 4, irq, dma1); #endif /* CS4231 || OPTi93X */ - if (chip->mpu_port <= 0 || chip->mpu_port == SNDRV_AUTO_PORT) + if (mpu_port <= 0 || mpu_port == SNDRV_AUTO_PORT) rmidi = NULL; - else - if ((error = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, - chip->mpu_port, 0, chip->mpu_irq, IRQF_DISABLED, - &rmidi))) + else { + error = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, + mpu_port, 0, mpu_irq, IRQF_DISABLED, &rmidi); + if (error) snd_printk(KERN_WARNING "no MPU-401 device at 0x%lx?\n", - chip->mpu_port); + mpu_port); + } - if (chip->fm_port > 0 && chip->fm_port != SNDRV_AUTO_PORT) { + if (fm_port > 0 && fm_port != SNDRV_AUTO_PORT) { struct snd_opl3 *opl3 = NULL; #ifndef OPTi93X if (chip->hardware == OPTi9XX_HW_82C928 || @@ -801,9 +781,7 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card) /* assume we have an OPL4 */ snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(2), 0x20, 0x20); - if (snd_opl4_create(card, - chip->fm_port, - chip->fm_port - 8, + if (snd_opl4_create(card, fm_port, fm_port - 8, 2, &opl3, &opl4) < 0) { /* no luck, use OPL3 instead */ snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(2), @@ -811,12 +789,10 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card) } } #endif /* !OPTi93X */ - if (!opl3 && snd_opl3_create(card, - chip->fm_port, - chip->fm_port + 2, + if (!opl3 && snd_opl3_create(card, fm_port, fm_port + 2, OPL3_HW_AUTO, 0, &opl3) < 0) { snd_printk(KERN_WARNING "no OPL device at 0x%lx-0x%lx\n", - chip->fm_port, chip->fm_port + 4 - 1); + fm_port, fm_port + 4 - 1); } if (opl3) { error = snd_opl3_hwdep_new(opl3, 0, 1, &synth); -- cgit v1.2.3 From 1bc8079879e8edfff451b62b7550bdd18523f963 Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Tue, 1 Dec 2009 18:10:34 +0100 Subject: ASoC: au1x: dbdma2: fix oops on soc device removal. platform_device_unregister() frees resources for us, no need to do it explicitly. Fixes an oops when machine code removes the soc-audio device. Signed-off-by: Manuel Lauss Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/au1x/dbdma2.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/au1x/dbdma2.c b/sound/soc/au1x/dbdma2.c index fe9f4657c95..2ca33b09a86 100644 --- a/sound/soc/au1x/dbdma2.c +++ b/sound/soc/au1x/dbdma2.c @@ -488,11 +488,8 @@ EXPORT_SYMBOL_GPL(au1xpsc_pcm_add); void au1xpsc_pcm_destroy(struct platform_device *dmapd) { - if (dmapd) { - kfree(dmapd->resource); - dmapd->resource = NULL; + if (dmapd) platform_device_unregister(dmapd); - } } EXPORT_SYMBOL_GPL(au1xpsc_pcm_destroy); -- cgit v1.2.3 From efd9eb96d5604c2c133e500f7b8c7b3f3fbdece8 Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Tue, 1 Dec 2009 18:10:35 +0100 Subject: ASoC: au1x: dbdma2: plug memleak in pcm device creation error path free the allocated pcm platform device in the error path. Signed-off-by: Manuel Lauss Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/au1x/dbdma2.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/au1x/dbdma2.c b/sound/soc/au1x/dbdma2.c index 2ca33b09a86..19e4d37eba1 100644 --- a/sound/soc/au1x/dbdma2.c +++ b/sound/soc/au1x/dbdma2.c @@ -480,6 +480,7 @@ struct platform_device *au1xpsc_pcm_add(struct platform_device *pdev) if (!ret) return pd; + platform_device_put(pd); out: kfree(res); return NULL; -- cgit v1.2.3 From 1233faa891451dee9eaddd7f8a616ba1ddd77919 Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Fri, 27 Nov 2009 18:19:28 +0100 Subject: ALSA: tea575x-tuner: fix mute Fix mute state reporting in tea575x-tuner. This fixes mute function in kradio on SF64-PCR radio card. Signed-off-by: Ondrej Zary Signed-off-by: Takashi Iwai --- sound/i2c/other/tea575x-tuner.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/i2c/other/tea575x-tuner.c b/sound/i2c/other/tea575x-tuner.c index d31c373e076..c4c6ef73f9b 100644 --- a/sound/i2c/other/tea575x-tuner.c +++ b/sound/i2c/other/tea575x-tuner.c @@ -225,7 +225,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv, case V4L2_CID_AUDIO_MUTE: if (tea->ops->mute) { tea->ops->mute(tea, ctrl->value); - tea->mute = 1; + tea->mute = ctrl->value; return 0; } } -- cgit v1.2.3 From fb716c0b7bed36064cd41d800c8f339f41adf084 Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Fri, 27 Nov 2009 18:18:33 +0100 Subject: snd-fm801: autodetect SF64-PCR (tuner-only) card MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When primary AC97 is not found, don't fail with tons of AC97 errors. Assume that the card is SF64-PCR (tuner-only). This makes the SF64-PCR radio card work "out of the box". Also fixes a bug that can cause an oops here:         if (tea575x_tuner > 0 && (tea575x_tuner & 0x000f) < 4) { when tea575x_tuner == 16, it passes this check and causes problems a couple lines below:         chip->tea.ops = &snd_fm801_tea_ops[(tea575x_tuner & 0x000f) - 1]; Tested with SF64-PCR, but I don't have any of those sound or sound+radio cards to test if I didn't break anything. Signed-off-by: Ondrej Zary Signed-off-by: Takashi Iwai --- sound/pci/fm801.c | 40 +++++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 13 deletions(-) (limited to 'sound') diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index 60cdb9e0b68..83508b3964f 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c @@ -55,7 +55,7 @@ static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card * * 1 = MediaForte 256-PCS * 2 = MediaForte 256-PCPR * 3 = MediaForte 64-PCR - * 16 = setup tuner only (this is additional bit), i.e. SF-64-PCR FM card + * 16 = setup tuner only (this is additional bit), i.e. SF64-PCR FM card * High 16-bits are video (radio) device number + 1 */ static int tea575x_tuner[SNDRV_CARDS]; @@ -67,7 +67,10 @@ MODULE_PARM_DESC(id, "ID string for the FM801 soundcard."); module_param_array(enable, bool, NULL, 0444); MODULE_PARM_DESC(enable, "Enable FM801 soundcard."); module_param_array(tea575x_tuner, int, NULL, 0444); -MODULE_PARM_DESC(tea575x_tuner, "Enable TEA575x tuner."); +MODULE_PARM_DESC(tea575x_tuner, "TEA575x tuner access method (1 = SF256-PCS, 2=SF256-PCPR, 3=SF64-PCR, +16=tuner-only)."); + +#define TUNER_ONLY (1<<4) +#define TUNER_TYPE_MASK (~TUNER_ONLY & 0xFFFF) /* * Direct registers @@ -160,7 +163,7 @@ struct fm801 { unsigned int multichannel: 1, /* multichannel support */ secondary: 1; /* secondary codec */ unsigned char secondary_addr; /* address of the secondary codec */ - unsigned int tea575x_tuner; /* tuner flags */ + unsigned int tea575x_tuner; /* tuner access method & flags */ unsigned short ply_ctrl; /* playback control */ unsigned short cap_ctrl; /* capture control */ @@ -1287,7 +1290,7 @@ static int snd_fm801_chip_init(struct fm801 *chip, int resume) { unsigned short cmdw; - if (chip->tea575x_tuner & 0x0010) + if (chip->tea575x_tuner & TUNER_ONLY) goto __ac97_ok; /* codec cold reset + AC'97 warm reset */ @@ -1296,11 +1299,13 @@ static int snd_fm801_chip_init(struct fm801 *chip, int resume) udelay(100); outw(0, FM801_REG(chip, CODEC_CTRL)); - if (wait_for_codec(chip, 0, AC97_RESET, msecs_to_jiffies(750)) < 0) { - snd_printk(KERN_ERR "Primary AC'97 codec not found\n"); - if (! resume) - return -EIO; - } + if (wait_for_codec(chip, 0, AC97_RESET, msecs_to_jiffies(750)) < 0) + if (!resume) { + snd_printk(KERN_INFO "Primary AC'97 codec not found, " + "assume SF64-PCR (tuner-only)\n"); + chip->tea575x_tuner = 3 | TUNER_ONLY; + goto __ac97_ok; + } if (chip->multichannel) { if (chip->secondary_addr) { @@ -1414,7 +1419,7 @@ static int __devinit snd_fm801_create(struct snd_card *card, return err; } chip->port = pci_resource_start(pci, 0); - if ((tea575x_tuner & 0x0010) == 0) { + if ((tea575x_tuner & TUNER_ONLY) == 0) { if (request_irq(pci->irq, snd_fm801_interrupt, IRQF_SHARED, "FM801", chip)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", chip->irq); @@ -1429,6 +1434,14 @@ static int __devinit snd_fm801_create(struct snd_card *card, chip->multichannel = 1; snd_fm801_chip_init(chip, 0); + /* init might set tuner access method */ + tea575x_tuner = chip->tea575x_tuner; + + if (chip->irq >= 0 && (tea575x_tuner & TUNER_ONLY)) { + pci_clear_master(pci); + free_irq(chip->irq, chip); + chip->irq = -1; + } if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { snd_fm801_free(chip); @@ -1438,12 +1451,13 @@ static int __devinit snd_fm801_create(struct snd_card *card, snd_card_set_dev(card, &pci->dev); #ifdef TEA575X_RADIO - if (tea575x_tuner > 0 && (tea575x_tuner & 0x000f) < 4) { + if ((tea575x_tuner & TUNER_TYPE_MASK) > 0 && + (tea575x_tuner & TUNER_TYPE_MASK) < 4) { chip->tea.dev_nr = tea575x_tuner >> 16; chip->tea.card = card; chip->tea.freq_fixup = 10700; chip->tea.private_data = chip; - chip->tea.ops = &snd_fm801_tea_ops[(tea575x_tuner & 0x000f) - 1]; + chip->tea.ops = &snd_fm801_tea_ops[(tea575x_tuner & TUNER_TYPE_MASK) - 1]; snd_tea575x_init(&chip->tea); } #endif @@ -1483,7 +1497,7 @@ static int __devinit snd_card_fm801_probe(struct pci_dev *pci, sprintf(card->longname, "%s at 0x%lx, irq %i", card->shortname, chip->port, chip->irq); - if (tea575x_tuner[dev] & 0x0010) + if (chip->tea575x_tuner & TUNER_ONLY) goto __fm801_tuner_only; if ((err = snd_fm801_pcm(chip, 0, NULL)) < 0) { -- cgit v1.2.3 From 3482594802d80a595ca50b16d3a25bcc1eb480c8 Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Fri, 4 Dec 2009 15:12:10 +0900 Subject: ASoC: Rename controls with a / in wm_hubs This renames from a character / to : of controls. A / occurs below error messages. ASoC: Failed to create IN2RP/VXRP debugfs file ASoC: Failed to create IN2LP/VXRN debugfs file Signed-off-by: Joonyoung Shim Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/codecs/wm_hubs.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c index 810a563d0eb..d73c30536a2 100644 --- a/sound/soc/codecs/wm_hubs.c +++ b/sound/soc/codecs/wm_hubs.c @@ -438,11 +438,11 @@ static const struct snd_soc_dapm_widget analogue_dapm_widgets[] = { SND_SOC_DAPM_INPUT("IN1LN"), SND_SOC_DAPM_INPUT("IN1LP"), SND_SOC_DAPM_INPUT("IN2LN"), -SND_SOC_DAPM_INPUT("IN2LP/VXRN"), +SND_SOC_DAPM_INPUT("IN2LP:VXRN"), SND_SOC_DAPM_INPUT("IN1RN"), SND_SOC_DAPM_INPUT("IN1RP"), SND_SOC_DAPM_INPUT("IN2RN"), -SND_SOC_DAPM_INPUT("IN2RP/VXRP"), +SND_SOC_DAPM_INPUT("IN2RP:VXRP"), SND_SOC_DAPM_MICBIAS("MICBIAS2", WM8993_POWER_MANAGEMENT_1, 5, 0), SND_SOC_DAPM_MICBIAS("MICBIAS1", WM8993_POWER_MANAGEMENT_1, 4, 0), @@ -537,14 +537,14 @@ static const struct snd_soc_dapm_route analogue_routes[] = { { "IN1R PGA", "IN1RP Switch", "IN1RP" }, { "IN1R PGA", "IN1RN Switch", "IN1RN" }, - { "IN2L PGA", "IN2LP Switch", "IN2LP/VXRN" }, + { "IN2L PGA", "IN2LP Switch", "IN2LP:VXRN" }, { "IN2L PGA", "IN2LN Switch", "IN2LN" }, - { "IN2R PGA", "IN2RP Switch", "IN2RP/VXRP" }, + { "IN2R PGA", "IN2RP Switch", "IN2RP:VXRP" }, { "IN2R PGA", "IN2RN Switch", "IN2RN" }, - { "Direct Voice", NULL, "IN2LP/VXRN" }, - { "Direct Voice", NULL, "IN2RP/VXRP" }, + { "Direct Voice", NULL, "IN2LP:VXRN" }, + { "Direct Voice", NULL, "IN2RP:VXRP" }, { "MIXINL", "IN1L Switch", "IN1L PGA" }, { "MIXINL", "IN2L Switch", "IN2L PGA" }, @@ -565,7 +565,7 @@ static const struct snd_soc_dapm_route analogue_routes[] = { { "Left Output Mixer", "Right Input Switch", "MIXINR" }, { "Left Output Mixer", "IN2RN Switch", "IN2RN" }, { "Left Output Mixer", "IN2LN Switch", "IN2LN" }, - { "Left Output Mixer", "IN2LP Switch", "IN2LP/VXRN" }, + { "Left Output Mixer", "IN2LP Switch", "IN2LP:VXRN" }, { "Left Output Mixer", "IN1L Switch", "IN1L PGA" }, { "Left Output Mixer", "IN1R Switch", "IN1R PGA" }, @@ -573,7 +573,7 @@ static const struct snd_soc_dapm_route analogue_routes[] = { { "Right Output Mixer", "Right Input Switch", "MIXINR" }, { "Right Output Mixer", "IN2LN Switch", "IN2LN" }, { "Right Output Mixer", "IN2RN Switch", "IN2RN" }, - { "Right Output Mixer", "IN2RP Switch", "IN2RP/VXRP" }, + { "Right Output Mixer", "IN2RP Switch", "IN2RP:VXRP" }, { "Right Output Mixer", "IN1L Switch", "IN1L PGA" }, { "Right Output Mixer", "IN1R Switch", "IN1R PGA" }, -- cgit v1.2.3 From fbfecd3712f917ca210a55c157233d88b785896b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 28 Oct 2009 20:11:04 +0100 Subject: tree-wide: fix typos "couter" -> "counter" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch was generated by git grep -E -i -l 'couter' | xargs -r perl -p -i -e 's/couter/counter/' Signed-off-by: Uwe Kleine-König Signed-off-by: Jiri Kosina --- sound/synth/emux/soundfont.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/synth/emux/soundfont.c b/sound/synth/emux/soundfont.c index 63c8f45c0c2..67c91230c19 100644 --- a/sound/synth/emux/soundfont.c +++ b/sound/synth/emux/soundfont.c @@ -374,7 +374,7 @@ sf_zone_new(struct snd_sf_list *sflist, struct snd_soundfont *sf) /* - * increment sample couter + * increment sample counter */ static void set_sample_counter(struct snd_sf_list *sflist, struct snd_soundfont *sf, -- cgit v1.2.3 From af901ca181d92aac3a7dc265144a9081a86d8f39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Goddard=20Rosa?= Date: Sat, 14 Nov 2009 13:09:05 -0200 Subject: tree-wide: fix assorted typos all over the place MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit That is "success", "unknown", "through", "performance", "[re|un]mapping" , "access", "default", "reasonable", "[con]currently", "temperature" , "channel", "[un]used", "application", "example","hierarchy", "therefore" , "[over|under]flow", "contiguous", "threshold", "enough" and others. Signed-off-by: André Goddard Rosa Signed-off-by: Jiri Kosina --- sound/Kconfig | 2 +- sound/isa/cs423x/cs4236.c | 2 +- sound/isa/opti9xx/miro.c | 2 +- sound/isa/opti9xx/opti92x-ad1848.c | 2 +- sound/oss/dmasound/dmasound_paula.c | 2 +- sound/pci/ca0106/ca0106_proc.c | 2 +- sound/pci/cs46xx/imgs/cwcdma.asp | 9 +++++---- sound/pci/emu10k1/emu10k1x.c | 2 +- sound/pci/hda/patch_cmedia.c | 2 +- sound/pci/hda/patch_realtek.c | 2 +- sound/pci/rme9652/hdspm.c | 4 ++-- sound/soc/codecs/uda134x.c | 4 ++-- sound/soc/codecs/wm8903.c | 6 +++--- sound/soc/codecs/wm8993.c | 4 ++-- sound/soc/s3c24xx/s3c24xx_simtec.c | 2 +- sound/soc/s6000/s6000-pcm.c | 2 +- sound/sound_core.c | 2 +- 17 files changed, 26 insertions(+), 25 deletions(-) (limited to 'sound') diff --git a/sound/Kconfig b/sound/Kconfig index 4b5365ad6b4..fcad760f569 100644 --- a/sound/Kconfig +++ b/sound/Kconfig @@ -55,7 +55,7 @@ config SOUND_OSS_CORE_PRECLAIM Please read Documentation/feature-removal-schedule.txt for details. - If unusre, say Y. + If unsure, say Y. source "sound/oss/dmasound/Kconfig" diff --git a/sound/isa/cs423x/cs4236.c b/sound/isa/cs423x/cs4236.c index a076a6ce807..a828baaab63 100644 --- a/sound/isa/cs423x/cs4236.c +++ b/sound/isa/cs423x/cs4236.c @@ -177,7 +177,7 @@ static struct pnp_card_device_id snd_cs423x_pnpids[] = { { .id = "CSC0437", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } }, /* Digital PC 5000 Onboard - CS4236B */ { .id = "CSC0735", .devs = { { "CSC0000" }, { "CSC0010" } } }, - /* some uknown CS4236B */ + /* some unknown CS4236B */ { .id = "CSC0b35", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } }, /* Intel PR440FX Onboard sound */ { .id = "CSC0b36", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } }, diff --git a/sound/isa/opti9xx/miro.c b/sound/isa/opti9xx/miro.c index 02e30d7c6a9..ddad60ef3f3 100644 --- a/sound/isa/opti9xx/miro.c +++ b/sound/isa/opti9xx/miro.c @@ -137,7 +137,7 @@ struct snd_miro { static void snd_miro_proc_init(struct snd_miro * miro); static char * snd_opti9xx_names[] = { - "unkown", + "unknown", "82C928", "82C929", "82C924", "82C925", "82C930", "82C931", "82C933" diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c index 5cd555325b9..848007508ff 100644 --- a/sound/isa/opti9xx/opti92x-ad1848.c +++ b/sound/isa/opti9xx/opti92x-ad1848.c @@ -185,7 +185,7 @@ MODULE_DEVICE_TABLE(pnp_card, snd_opti9xx_pnpids); #endif static char * snd_opti9xx_names[] = { - "unkown", + "unknown", "82C928", "82C929", "82C924", "82C925", "82C930", "82C931", "82C933" diff --git a/sound/oss/dmasound/dmasound_paula.c b/sound/oss/dmasound/dmasound_paula.c index 06e9e88e4c0..bb14e4c67e8 100644 --- a/sound/oss/dmasound/dmasound_paula.c +++ b/sound/oss/dmasound/dmasound_paula.c @@ -657,7 +657,7 @@ static int AmiStateInfo(char *buffer, size_t space) len += sprintf(buffer+len, "\tsound.volume_right = %d [0...64]\n", dmasound.volume_right); if (len >= space) { - printk(KERN_ERR "dmasound_paula: overlowed state buffer alloc.\n") ; + printk(KERN_ERR "dmasound_paula: overflowed state buffer alloc.\n") ; len = space ; } return len; diff --git a/sound/pci/ca0106/ca0106_proc.c b/sound/pci/ca0106/ca0106_proc.c index c62b7d10ec6..8d13092300d 100644 --- a/sound/pci/ca0106/ca0106_proc.c +++ b/sound/pci/ca0106/ca0106_proc.c @@ -233,7 +233,7 @@ static void snd_ca0106_proc_dump_iec958( struct snd_info_buffer *buffer, u32 val snd_iprintf(buffer, "user-defined\n"); break; default: - snd_iprintf(buffer, "unkown\n"); + snd_iprintf(buffer, "unknown\n"); break; } snd_iprintf(buffer, "Sample Bits: "); diff --git a/sound/pci/cs46xx/imgs/cwcdma.asp b/sound/pci/cs46xx/imgs/cwcdma.asp index 09d24c76f03..a65e1193c89 100644 --- a/sound/pci/cs46xx/imgs/cwcdma.asp +++ b/sound/pci/cs46xx/imgs/cwcdma.asp @@ -26,10 +26,11 @@ // // // The purpose of this code is very simple: make it possible to tranfser -// the samples 'as they are' with no alteration from a PCMreader SCB (DMA from host) -// to any other SCB. This is useful for AC3 throug SPDIF. SRC (source rate converters) -// task always alters the samples in some how, however it's from 48khz -> 48khz. The -// alterations are not audible, but AC3 wont work. +// the samples 'as they are' with no alteration from a PCMreader +// SCB (DMA from host) to any other SCB. This is useful for AC3 through SPDIF. +// SRC (source rate converters) task always alters the samples in somehow, +// however it's from 48khz -> 48khz. +// The alterations are not audible, but AC3 wont work. // // ... // | diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c index 36e08bd2b3c..360e3809a60 100644 --- a/sound/pci/emu10k1/emu10k1x.c +++ b/sound/pci/emu10k1/emu10k1x.c @@ -184,7 +184,7 @@ MODULE_PARM_DESC(enable, "Enable the EMU10K1X soundcard."); * The hardware has 3 channels for playback and 1 for capture. * - channel 0 is the front channel * - channel 1 is the rear channel - * - channel 2 is the center/lfe chanel + * - channel 2 is the center/lfe channel * Volume is controlled by the AC97 for the front and rear channels by * the PCM Playback Volume, Sigmatel Surround Playback Volume and * Surround Playback Volume. The Sigmatel 4-Speaker Stereo switch affects diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c index 780e1a72114..8917071d5b6 100644 --- a/sound/pci/hda/patch_cmedia.c +++ b/sound/pci/hda/patch_cmedia.c @@ -66,7 +66,7 @@ struct cmi_spec { struct hda_pcm pcm_rec[2]; /* PCM information */ - /* pin deafault configuration */ + /* pin default configuration */ hda_nid_t pin_nid[NUM_PINS]; unsigned int def_conf[NUM_PINS]; unsigned int pin_def_confs; diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index ff20048504b..872731eb49e 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6619,7 +6619,7 @@ static struct hda_input_mux alc889A_mb31_capture_source = { /* Front Mic (0x01) unused */ { "Line", 0x2 }, /* Line 2 (0x03) unused */ - /* CD (0x04) unsused? */ + /* CD (0x04) unused? */ }, }; diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 0dce331a2a3..a1b10d1a384 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -3017,7 +3017,7 @@ snd_hdspm_proc_read_madi(struct snd_info_entry * entry, insel = "Coaxial"; break; default: - insel = "Unkown"; + insel = "Unknown"; } switch (hdspm->control_register & HDSPM_SyncRefMask) { @@ -3028,7 +3028,7 @@ snd_hdspm_proc_read_madi(struct snd_info_entry * entry, syncref = "MADI"; break; default: - syncref = "Unkown"; + syncref = "Unknown"; } snd_iprintf(buffer, "Inputsel = %s, SyncRef = %s\n", insel, syncref); diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c index c33b92edbde..8ce1c9b2e5b 100644 --- a/sound/soc/codecs/uda134x.c +++ b/sound/soc/codecs/uda134x.c @@ -101,7 +101,7 @@ static int uda134x_write(struct snd_soc_codec *codec, unsigned int reg, pr_debug("%s reg: %02X, value:%02X\n", __func__, reg, value); if (reg >= UDA134X_REGS_NUM) { - printk(KERN_ERR "%s unkown register: reg: %u", + printk(KERN_ERR "%s unknown register: reg: %u", __func__, reg); return -EINVAL; } @@ -552,7 +552,7 @@ static int uda134x_soc_probe(struct platform_device *pdev) ARRAY_SIZE(uda1341_snd_controls)); break; default: - printk(KERN_ERR "%s unkown codec type: %d", + printk(KERN_ERR "%s unknown codec type: %d", __func__, pd->model); return -EINVAL; } diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index fe1307b500c..d72347d90b7 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -607,7 +607,7 @@ SOC_SINGLE("Right Input PGA Common Mode Switch", WM8903_ANALOGUE_RIGHT_INPUT_1, SOC_SINGLE("DRC Switch", WM8903_DRC_0, 15, 1, 0), SOC_ENUM("DRC Compressor Slope R0", drc_slope_r0), SOC_ENUM("DRC Compressor Slope R1", drc_slope_r1), -SOC_SINGLE_TLV("DRC Compressor Threashold Volume", WM8903_DRC_3, 5, 124, 1, +SOC_SINGLE_TLV("DRC Compressor Threshold Volume", WM8903_DRC_3, 5, 124, 1, drc_tlv_thresh), SOC_SINGLE_TLV("DRC Volume", WM8903_DRC_3, 0, 30, 1, drc_tlv_amp), SOC_SINGLE_TLV("DRC Minimum Gain Volume", WM8903_DRC_1, 2, 3, 1, drc_tlv_min), @@ -617,11 +617,11 @@ SOC_ENUM("DRC Decay Rate", drc_decay), SOC_ENUM("DRC FF Delay", drc_ff_delay), SOC_SINGLE("DRC Anticlip Switch", WM8903_DRC_0, 1, 1, 0), SOC_SINGLE("DRC QR Switch", WM8903_DRC_0, 2, 1, 0), -SOC_SINGLE_TLV("DRC QR Threashold Volume", WM8903_DRC_0, 6, 3, 0, drc_tlv_max), +SOC_SINGLE_TLV("DRC QR Threshold Volume", WM8903_DRC_0, 6, 3, 0, drc_tlv_max), SOC_ENUM("DRC QR Decay Rate", drc_qr_decay), SOC_SINGLE("DRC Smoothing Switch", WM8903_DRC_0, 3, 1, 0), SOC_SINGLE("DRC Smoothing Hysteresis Switch", WM8903_DRC_0, 0, 1, 0), -SOC_ENUM("DRC Smoothing Threashold", drc_smoothing), +SOC_ENUM("DRC Smoothing Threshold", drc_smoothing), SOC_SINGLE_TLV("DRC Startup Volume", WM8903_DRC_0, 6, 18, 0, drc_tlv_startup), SOC_DOUBLE_R_TLV("Digital Capture Volume", WM8903_ADC_DIGITAL_VOLUME_LEFT, diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c index d9987999e92..bc033687b22 100644 --- a/sound/soc/codecs/wm8993.c +++ b/sound/soc/codecs/wm8993.c @@ -689,7 +689,7 @@ SOC_DOUBLE_TLV("Digital Sidetone Volume", WM8993_DIGITAL_SIDE_TONE, SOC_SINGLE("DRC Switch", WM8993_DRC_CONTROL_1, 15, 1, 0), SOC_ENUM("DRC Path", drc_path), -SOC_SINGLE_TLV("DRC Compressor Threashold Volume", WM8993_DRC_CONTROL_2, +SOC_SINGLE_TLV("DRC Compressor Threshold Volume", WM8993_DRC_CONTROL_2, 2, 60, 1, drc_comp_threash), SOC_SINGLE_TLV("DRC Compressor Amplitude Volume", WM8993_DRC_CONTROL_3, 11, 30, 1, drc_comp_amp), @@ -709,7 +709,7 @@ SOC_SINGLE_TLV("DRC Quick Release Volume", WM8993_DRC_CONTROL_3, 2, 3, 0, SOC_ENUM("DRC Quick Release Rate", drc_qr_rate), SOC_SINGLE("DRC Smoothing Switch", WM8993_DRC_CONTROL_1, 11, 1, 0), SOC_SINGLE("DRC Smoothing Hysteresis Switch", WM8993_DRC_CONTROL_1, 8, 1, 0), -SOC_ENUM("DRC Smoothing Hysteresis Threashold", drc_smooth), +SOC_ENUM("DRC Smoothing Hysteresis Threshold", drc_smooth), SOC_SINGLE_TLV("DRC Startup Volume", WM8993_DRC_CONTROL_4, 8, 18, 0, drc_startup_tlv), diff --git a/sound/soc/s3c24xx/s3c24xx_simtec.c b/sound/soc/s3c24xx/s3c24xx_simtec.c index 1966e0d5652..3c7ccb78b6a 100644 --- a/sound/soc/s3c24xx/s3c24xx_simtec.c +++ b/sound/soc/s3c24xx/s3c24xx_simtec.c @@ -270,7 +270,7 @@ static int attach_gpio_amp(struct device *dev, gpio_direction_output(pd->amp_gain[1], 0); } - /* note, curently we assume GPA0 isn't valid amp */ + /* note, currently we assume GPA0 isn't valid amp */ if (pdata->amp_gpio > 0) { ret = gpio_request(pd->amp_gpio, "gpio-amp"); if (ret) { diff --git a/sound/soc/s6000/s6000-pcm.c b/sound/soc/s6000/s6000-pcm.c index 83b8028e209..81d6f983f51 100644 --- a/sound/soc/s6000/s6000-pcm.c +++ b/sound/soc/s6000/s6000-pcm.c @@ -196,7 +196,7 @@ static int s6000_pcm_start(struct snd_pcm_substream *substream) 0 /* destination skip after chunk (impossible) */, 4 /* 16 byte burst size */, -1 /* don't conserve bandwidth */, - 0 /* low watermark irq descriptor theshold */, + 0 /* low watermark irq descriptor threshold */, 0 /* disable hardware timestamps */, 1 /* enable channel */); diff --git a/sound/sound_core.c b/sound/sound_core.c index 49c99818659..dbca7c909a3 100644 --- a/sound/sound_core.c +++ b/sound/sound_core.c @@ -353,7 +353,7 @@ 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 succes. On failure + * subsystem. The allocated number is returned on success. On failure * a negative error code is returned. */ -- cgit v1.2.3 From e6960e194a7dfb8197822225e04eca95fbd61a7f Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Fri, 4 Dec 2009 18:30:18 +0100 Subject: ALSA: opti93x: set MC indirect registers base from PnP data The PnP data on the OPTI931 and OPTI933 contains io port range for the MC indirect registers. Use the PnP range instead of hardwired value 0xE0E. Also, request region of MC indirect registers so it is marked as used to other drivers (this was missing previously). Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai --- sound/isa/opti9xx/opti92x-ad1848.c | 112 ++++++++++++++++++++++--------------- 1 file changed, 67 insertions(+), 45 deletions(-) (limited to 'sound') diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c index d08c3890644..8c88401c79b 100644 --- a/sound/isa/opti9xx/opti92x-ad1848.c +++ b/sound/isa/opti9xx/opti92x-ad1848.c @@ -135,6 +135,8 @@ struct snd_opti9xx { unsigned long mc_base_size; #ifdef OPTi93X unsigned long mc_indir_index; + unsigned long mc_indir_size; + struct resource *res_mc_indir; struct snd_wss *codec; #endif /* OPTi93X */ unsigned long pwd_reg; @@ -231,7 +233,10 @@ static int __devinit snd_opti9xx_init(struct snd_opti9xx *chip, case OPTi9XX_HW_82C931: case OPTi9XX_HW_82C933: chip->mc_base = (hardware == OPTi9XX_HW_82C930) ? 0xf8f : 0xf8d; - chip->mc_indir_index = 0xe0e; + if (!chip->mc_indir_index) { + chip->mc_indir_index = 0xe0e; + chip->mc_indir_size = 2; + } chip->password = 0xe4; chip->pwd_reg = 0; break; @@ -560,57 +565,69 @@ static irqreturn_t snd_opti93x_interrupt(int irq, void *dev_id) #endif /* OPTi93X */ -static int __devinit snd_card_opti9xx_detect(struct snd_card *card, - struct snd_opti9xx *chip) +static int __devinit snd_opti9xx_read_check(struct snd_opti9xx *chip) { - int i, err; + unsigned char value; +#ifdef OPTi93X + unsigned long flags; +#endif + chip->res_mc_base = request_region(chip->mc_base, chip->mc_base_size, + "OPTi9xx MC"); + if (chip->res_mc_base == NULL) + return -EBUSY; #ifndef OPTi93X - for (i = OPTi9XX_HW_82C928; i < OPTi9XX_HW_82C930; i++) { - unsigned char value; + value = snd_opti9xx_read(chip, OPTi9XX_MC_REG(1)); + if (value != 0xff && value != inb(chip->mc_base + OPTi9XX_MC_REG(1))) + if (value == snd_opti9xx_read(chip, OPTi9XX_MC_REG(1))) + return 0; +#else /* OPTi93X */ + chip->res_mc_indir = request_region(chip->mc_indir_index, + chip->mc_indir_size, + "OPTi93x MC"); + if (chip->res_mc_indir == NULL) + return -EBUSY; - if ((err = snd_opti9xx_init(chip, i)) < 0) - return err; + spin_lock_irqsave(&chip->lock, flags); + outb(chip->password, chip->mc_base + chip->pwd_reg); + outb(((chip->mc_indir_index & 0x1f0) >> 4), chip->mc_base); + spin_unlock_irqrestore(&chip->lock, flags); - if ((chip->res_mc_base = request_region(chip->mc_base, chip->mc_base_size, "OPTi9xx MC")) == NULL) - continue; + value = snd_opti9xx_read(chip, OPTi9XX_MC_REG(7)); + snd_opti9xx_write(chip, OPTi9XX_MC_REG(7), 0xff - value); + if (snd_opti9xx_read(chip, OPTi9XX_MC_REG(7)) == 0xff - value) + return 0; - value = snd_opti9xx_read(chip, OPTi9XX_MC_REG(1)); - if ((value != 0xff) && (value != inb(chip->mc_base + 1))) - if (value == snd_opti9xx_read(chip, OPTi9XX_MC_REG(1))) - return 1; + release_and_free_resource(chip->res_mc_indir); + chip->res_mc_indir = NULL; +#endif /* OPTi93X */ + release_and_free_resource(chip->res_mc_base); + chip->res_mc_base = NULL; - release_and_free_resource(chip->res_mc_base); - chip->res_mc_base = NULL; + return -ENODEV; +} - } -#else /* OPTi93X */ - for (i = OPTi9XX_HW_82C931; i >= OPTi9XX_HW_82C930; i--) { - unsigned long flags; - unsigned char value; +static int __devinit snd_card_opti9xx_detect(struct snd_card *card, + struct snd_opti9xx *chip) +{ + int i, err; - if ((err = snd_opti9xx_init(chip, i)) < 0) +#ifndef OPTi93X + for (i = OPTi9XX_HW_82C928; i < OPTi9XX_HW_82C930; i++) { +#else + for (i = OPTi9XX_HW_82C931; i >= OPTi9XX_HW_82C930; i--) { +#endif + err = snd_opti9xx_init(chip, i); + if (err < 0) return err; - if ((chip->res_mc_base = request_region(chip->mc_base, chip->mc_base_size, "OPTi9xx MC")) == NULL) - continue; - - spin_lock_irqsave(&chip->lock, flags); - outb(chip->password, chip->mc_base + chip->pwd_reg); - outb(((chip->mc_indir_index & (1 << 8)) >> 4) | - ((chip->mc_indir_index & 0xf0) >> 4), chip->mc_base); - spin_unlock_irqrestore(&chip->lock, flags); - - value = snd_opti9xx_read(chip, OPTi9XX_MC_REG(7)); - snd_opti9xx_write(chip, OPTi9XX_MC_REG(7), 0xff - value); - if (snd_opti9xx_read(chip, OPTi9XX_MC_REG(7)) == 0xff - value) + err = snd_opti9xx_read_check(chip); + if (err == 0) return 1; - - release_and_free_resource(chip->res_mc_base); - chip->res_mc_base = NULL; +#ifdef OPTi93X + chip->mc_indir_index = 0; +#endif } -#endif /* OPTi93X */ - return -ENODEV; } @@ -639,6 +656,8 @@ static int __devinit snd_card_opti9xx_pnp(struct snd_opti9xx *chip, #ifdef OPTi93X port = pnp_port_start(pdev, 0) - 4; fm_port = pnp_port_start(pdev, 1) + 8; + chip->mc_indir_index = pnp_port_start(pdev, 3) + 2; + chip->mc_indir_size = pnp_port_len(pdev, 3) - 2; #else if (pid->driver_data != 0x0924) port = pnp_port_start(pdev, 1); @@ -669,7 +688,7 @@ static int __devinit snd_card_opti9xx_pnp(struct snd_opti9xx *chip, static void snd_card_opti9xx_free(struct snd_card *card) { struct snd_opti9xx *chip = card->private_data; - + if (chip) { #ifdef OPTi93X struct snd_wss *codec = chip->codec; @@ -677,6 +696,7 @@ static void snd_card_opti9xx_free(struct snd_card *card) disable_irq(codec->irq); free_irq(codec->irq, codec); } + release_and_free_resource(chip->res_mc_indir); #endif release_and_free_resource(chip->res_mc_base); } @@ -696,11 +716,6 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card) struct snd_rawmidi *rmidi; struct snd_hwdep *synth; - if (! chip->res_mc_base && - (chip->res_mc_base = request_region(chip->mc_base, chip->mc_base_size, - "OPTi9xx MC")) == NULL) - return -ENOMEM; - #if defined(CS4231) || defined(OPTi93X) xdma2 = dma2; #else @@ -954,6 +969,13 @@ static int __devinit snd_opti9xx_pnp_probe(struct pnp_card_link *pcard, } if (hw <= OPTi9XX_HW_82C930) chip->mc_base -= 0x80; + + error = snd_opti9xx_read_check(chip); + if (error) { + snd_printk(KERN_ERR "OPTI chip not found\n"); + snd_card_free(card); + return error; + } snd_card_set_dev(card, &pcard->card->dev); if ((error = snd_opti9xx_probe(card)) < 0) { snd_card_free(card); -- cgit v1.2.3 From 2b6f6c0d11fcf6244b98d2b7490164d92d3e409f Mon Sep 17 00:00:00 2001 From: Tobias Hansen Date: Mon, 7 Dec 2009 19:08:19 +0100 Subject: ALSA: snd-usb-us122l: add product IDs of US-122MKII and US-144MKII I added the product IDs of the new revisions of the devices, so owners can test whether this suffices to make them work. Patched against ALSA snapshot 20091207. Signed-off-by: Tobias Hansen Signed-off-by: Takashi Iwai --- sound/usb/usx2y/us122l.c | 28 ++++++++++++++++++++++------ sound/usb/usx2y/us122l.h | 2 ++ 2 files changed, 24 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/usb/usx2y/us122l.c b/sound/usb/usx2y/us122l.c index f71cd28eca6..91bb29666d2 100644 --- a/sound/usb/usx2y/us122l.c +++ b/sound/usb/usx2y/us122l.c @@ -194,7 +194,8 @@ static int usb_stream_hwdep_open(struct snd_hwdep *hw, struct file *file) if (!us122l->first) us122l->first = file; - if (us122l->dev->descriptor.idProduct == USB_ID_US144) { + if (us122l->dev->descriptor.idProduct == USB_ID_US144 || + us122l->dev->descriptor.idProduct == USB_ID_US144MKII) { iface = usb_ifnum_to_if(us122l->dev, 0); usb_autopm_get_interface(iface); } @@ -209,7 +210,8 @@ static int usb_stream_hwdep_release(struct snd_hwdep *hw, struct file *file) struct usb_interface *iface; snd_printdd(KERN_DEBUG "%p %p\n", hw, file); - if (us122l->dev->descriptor.idProduct == USB_ID_US144) { + if (us122l->dev->descriptor.idProduct == USB_ID_US144 || + us122l->dev->descriptor.idProduct == USB_ID_US144MKII) { iface = usb_ifnum_to_if(us122l->dev, 0); usb_autopm_put_interface(iface); } @@ -476,7 +478,8 @@ static bool us122l_create_card(struct snd_card *card) int err; struct us122l *us122l = US122L(card); - if (us122l->dev->descriptor.idProduct == USB_ID_US144) { + if (us122l->dev->descriptor.idProduct == USB_ID_US144 || + us122l->dev->descriptor.idProduct == USB_ID_US144MKII) { err = usb_set_interface(us122l->dev, 0, 1); if (err) { snd_printk(KERN_ERR "usb_set_interface error \n"); @@ -495,7 +498,8 @@ static bool us122l_create_card(struct snd_card *card) if (!us122l_start(us122l, 44100, 256)) return false; - if (us122l->dev->descriptor.idProduct == USB_ID_US144) + if (us122l->dev->descriptor.idProduct == USB_ID_US144 || + us122l->dev->descriptor.idProduct == USB_ID_US144MKII) err = us144_create_usbmidi(card); else err = us122l_create_usbmidi(card); @@ -597,7 +601,8 @@ static int snd_us122l_probe(struct usb_interface *intf, struct snd_card *card; int err; - if (device->descriptor.idProduct == USB_ID_US144 + if ((device->descriptor.idProduct == USB_ID_US144 || + device->descriptor.idProduct == USB_ID_US144MKII) && device->speed == USB_SPEED_HIGH) { snd_printk(KERN_ERR "disable ehci-hcd to run US-144 \n"); return -ENODEV; @@ -692,7 +697,8 @@ static int snd_us122l_resume(struct usb_interface *intf) mutex_lock(&us122l->mutex); /* needed, doesn't restart without: */ - if (us122l->dev->descriptor.idProduct == USB_ID_US144) { + if (us122l->dev->descriptor.idProduct == USB_ID_US144 || + us122l->dev->descriptor.idProduct == USB_ID_US144MKII) { err = usb_set_interface(us122l->dev, 0, 1); if (err) { snd_printk(KERN_ERR "usb_set_interface error \n"); @@ -737,6 +743,16 @@ static struct usb_device_id snd_us122l_usb_id_table[] = { .idVendor = 0x0644, .idProduct = USB_ID_US144 }, + { + .match_flags = USB_DEVICE_ID_MATCH_DEVICE, + .idVendor = 0x0644, + .idProduct = USB_ID_US122MKII + }, + { + .match_flags = USB_DEVICE_ID_MATCH_DEVICE, + .idVendor = 0x0644, + .idProduct = USB_ID_US144MKII + }, { /* terminator */ } }; diff --git a/sound/usb/usx2y/us122l.h b/sound/usb/usx2y/us122l.h index 4daf1982e82..f263b3f96c8 100644 --- a/sound/usb/usx2y/us122l.h +++ b/sound/usb/usx2y/us122l.h @@ -25,5 +25,7 @@ struct us122l { #define USB_ID_US122L 0x800E #define USB_ID_US144 0x800F +#define USB_ID_US122MKII 0x8021 +#define USB_ID_US144MKII 0x8020 #endif -- cgit v1.2.3 From 370066e2b13bafa8e742673f658e617b6ed143a4 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Tue, 8 Dec 2009 01:34:22 +0100 Subject: ASoC: Wrong variable returned on error The wrong variable was returned in the case of an error Signed-off-by: Roel Kluin Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/imx/mx1_mx2-pcm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/imx/mx1_mx2-pcm.c b/sound/soc/imx/mx1_mx2-pcm.c index b8386652939..bffffcd5ff3 100644 --- a/sound/soc/imx/mx1_mx2-pcm.c +++ b/sound/soc/imx/mx1_mx2-pcm.c @@ -322,12 +322,12 @@ static int mx1_mx2_pcm_open(struct snd_pcm_substream *substream) pr_debug("%s: Requesting dma channel (%s)\n", __func__, prtd->dma_params->name); - prtd->dma_ch = imx_dma_request_by_prio(prtd->dma_params->name, - DMA_PRIO_HIGH); - if (prtd->dma_ch < 0) { + ret = imx_dma_request_by_prio(prtd->dma_params->name, DMA_PRIO_HIGH); + if (ret < 0) { printk(KERN_ERR "Error %d requesting dma channel\n", ret); return ret; } + prtd->dma_ch = ret; imx_dma_config_burstlen(prtd->dma_ch, prtd->dma_params->watermark_level); -- cgit v1.2.3 From 482e46d4b7c9bfbb2edc047fafa85cee1b0fc1e1 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 9 Dec 2009 12:43:44 +0100 Subject: ALSA: ice1724 - aureon - modify WM8770 Master & DAC volume The volume levels in original implementation are incorrect and does not match the dB scale. The real range is linear (in the sense of the dB scale) from 0dB to -100dB. Remove logaritmic table and make all volumes from range 0dB..100dB. The tests are in RedHat's bugzilla #540817. Signed-off-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/pci/ice1712/aureon.c | 31 +++++++------------------------ 1 file changed, 7 insertions(+), 24 deletions(-) (limited to 'sound') diff --git a/sound/pci/ice1712/aureon.c b/sound/pci/ice1712/aureon.c index 110d16e5273..765d7bd4c3d 100644 --- a/sound/pci/ice1712/aureon.c +++ b/sound/pci/ice1712/aureon.c @@ -689,32 +689,14 @@ static int aureon_ac97_mmute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e return change; } -static const DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1); +static const DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -10000, 100, 1); static const DECLARE_TLV_DB_SCALE(db_scale_wm_pcm, -6400, 50, 1); static const DECLARE_TLV_DB_SCALE(db_scale_wm_adc, -1200, 100, 0); static const DECLARE_TLV_DB_SCALE(db_scale_ac97_master, -4650, 150, 0); static const DECLARE_TLV_DB_SCALE(db_scale_ac97_gain, -3450, 150, 0); -/* - * Logarithmic volume values for WM8770 - * Computed as 20 * Log10(255 / x) - */ -static const unsigned char wm_vol[256] = { - 127, 48, 42, 39, 36, 34, 33, 31, 30, 29, 28, 27, 27, 26, 25, 25, 24, 24, 23, - 23, 22, 22, 21, 21, 21, 20, 20, 20, 19, 19, 19, 18, 18, 18, 18, 17, 17, 17, - 17, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 13, 13, 13, - 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0 -}; - -#define WM_VOL_MAX (sizeof(wm_vol) - 1) +#define WM_VOL_MAX 100 +#define WM_VOL_CNT 101 /* 0dB .. -100dB */ #define WM_VOL_MUTE 0x8000 static void wm_set_vol(struct snd_ice1712 *ice, unsigned int index, unsigned short vol, unsigned short master) @@ -724,7 +706,8 @@ static void wm_set_vol(struct snd_ice1712 *ice, unsigned int index, unsigned sho if ((master & WM_VOL_MUTE) || (vol & WM_VOL_MUTE)) nvol = 0; else - nvol = 127 - wm_vol[(((vol & ~WM_VOL_MUTE) * (master & ~WM_VOL_MUTE)) / 127) & WM_VOL_MAX]; + nvol = ((vol % WM_VOL_CNT) * (master % WM_VOL_CNT)) / + WM_VOL_MAX; wm_put(ice, index, nvol); wm_put_nocache(ice, index, 0x180 | nvol); @@ -820,7 +803,7 @@ static int wm_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info * uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = voices; uinfo->value.integer.min = 0; /* mute (-101dB) */ - uinfo->value.integer.max = 0x7F; /* 0dB */ + uinfo->value.integer.max = WM_VOL_MAX; /* 0dB */ return 0; } @@ -850,7 +833,7 @@ static int wm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value * snd_ice1712_save_gpio_status(ice); for (i = 0; i < voices; i++) { unsigned int vol = ucontrol->value.integer.value[i]; - if (vol > 0x7f) + if (vol > WM_VOL_MAX) continue; vol |= spec->vol[ofs+i]; if (vol != spec->vol[ofs+i]) { -- cgit v1.2.3 From 5f60e496083efb01893a899b6885828330db971f Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Wed, 9 Dec 2009 20:12:43 +0100 Subject: ALSA: opti93x: fix irq releasing if the irq cannot be allocated Use the chip->irq to check if the irq should be released so the irq is not released if it has not been allocated. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai --- sound/isa/opti9xx/opti92x-ad1848.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c index 8c88401c79b..d8eac3f2894 100644 --- a/sound/isa/opti9xx/opti92x-ad1848.c +++ b/sound/isa/opti9xx/opti92x-ad1848.c @@ -548,10 +548,13 @@ __skip_mpu: static irqreturn_t snd_opti93x_interrupt(int irq, void *dev_id) { - struct snd_wss *codec = dev_id; - struct snd_opti9xx *chip = codec->card->private_data; + struct snd_opti9xx *chip = dev_id; + struct snd_wss *codec = chip->codec; unsigned char status; + if (!codec) + return IRQ_HANDLED; + status = snd_opti9xx_read(chip, OPTi9XX_MC_REG(11)); if ((status & OPTi93X_IRQ_PLAYBACK) && codec->playback_substream) snd_pcm_period_elapsed(codec->playback_substream); @@ -691,10 +694,9 @@ static void snd_card_opti9xx_free(struct snd_card *card) if (chip) { #ifdef OPTi93X - struct snd_wss *codec = chip->codec; - if (codec && codec->irq > 0) { - disable_irq(codec->irq); - free_irq(codec->irq, codec); + if (chip->irq > 0) { + disable_irq(chip->irq); + free_irq(chip->irq, chip); } release_and_free_resource(chip->res_mc_indir); #endif @@ -759,9 +761,9 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card) #endif #ifdef OPTi93X error = request_irq(irq, snd_opti93x_interrupt, - IRQF_DISABLED, DEV_NAME" - WSS", codec); + IRQF_DISABLED, DEV_NAME" - WSS", chip); if (error < 0) { - snd_printk(KERN_ERR "opti9xx: can't grab IRQ %d\n", chip->irq); + snd_printk(KERN_ERR "opti9xx: can't grab IRQ %d\n", irq); return error; } #endif -- cgit v1.2.3 From 6b2f3d1f769be5779b479c37800229d9a4809fc3 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 27 Oct 2009 11:05:28 +0100 Subject: vfs: Implement proper O_SYNC semantics While Linux provided an O_SYNC flag basically since day 1, it took until Linux 2.4.0-test12pre2 to actually get it implemented for filesystems, since that day we had generic_osync_around with only minor changes and the great "For now, when the user asks for O_SYNC, we'll actually give O_DSYNC" comment. This patch intends to actually give us real O_SYNC semantics in addition to the O_DSYNC semantics. After Jan's O_SYNC patches which are required before this patch it's actually surprisingly simple, we just need to figure out when to set the datasync flag to vfs_fsync_range and when not. This patch renames the existing O_SYNC flag to O_DSYNC while keeping it's numerical value to keep binary compatibility, and adds a new real O_SYNC flag. To guarantee backwards compatiblity it is defined as expanding to both the O_DSYNC and the new additional binary flag (__O_SYNC) to make sure we are backwards-compatible when compiled against the new headers. This also means that all places that don't care about the differences can just check O_DSYNC and get the right behaviour for O_SYNC, too - only places that actuall care need to check __O_SYNC in addition. Drivers and network filesystems have been updated in a fail safe way to always do the full sync magic if O_DSYNC is set. The few places setting O_SYNC for lower layers are kept that way for now to stay failsafe. We enforce that O_DSYNC is set when __O_SYNC is set early in the open path to make sure we always get these sane options. Note that parisc really screwed up their headers as they already define a O_DSYNC that has always been a no-op. We try to repair it by using it for the new O_DSYNC and redefinining O_SYNC to send both the traditional O_SYNC numerical value _and_ the O_DSYNC one. Cc: Richard Henderson Cc: Ivan Kokshaysky Cc: Grant Grundler Cc: "David S. Miller" Cc: Ingo Molnar Cc: "H. Peter Anvin" Cc: Thomas Gleixner Cc: Al Viro Cc: Andreas Dilger Acked-by: Trond Myklebust Acked-by: Kyle McMartin Acked-by: Ulrich Drepper Signed-off-by: Christoph Hellwig Signed-off-by: Andrew Morton Signed-off-by: Jan Kara --- sound/core/rawmidi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 2f766123b15..0f5a194695d 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -1257,7 +1257,7 @@ static ssize_t snd_rawmidi_write(struct file *file, const char __user *buf, break; count -= count1; } - if (file->f_flags & O_SYNC) { + if (file->f_flags & O_DSYNC) { spin_lock_irq(&runtime->lock); while (runtime->avail != runtime->buffer_size) { wait_queue_t wait; -- cgit v1.2.3 From 761c9d45d14e0afa3c0b8eb84b4075602e50533b Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Thu, 10 Dec 2009 11:15:55 -0600 Subject: ASoC: Fix build of OMAP sound drivers There are build errors when building for some of the omap2/3 boards without enabling sound: sound/built-in.o:(.data+0x43bc): undefined reference to `soc_codec_dev_tlv320aic23' sound/built-in.o:(.data+0x43cc): undefined reference to `tlv320aic23_dai' Confused me quite a bit since the drivers that had references to the codec weren't enabled. Turns out the Makefile was using the wrong config option to enable them. Patch below. Reported-by: Anand Gadiyar Signed-off-by: Olof Johansson Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/omap/Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile index d49458a29bb..3db8a6c523f 100644 --- a/sound/soc/omap/Makefile +++ b/sound/soc/omap/Makefile @@ -23,9 +23,9 @@ obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o obj-$(CONFIG_SND_OMAP_SOC_AMS_DELTA) += snd-soc-ams-delta.o obj-$(CONFIG_SND_OMAP_SOC_OSK5912) += snd-soc-osk5912.o obj-$(CONFIG_SND_OMAP_SOC_OVERO) += snd-soc-overo.o -obj-$(CONFIG_MACH_OMAP2EVM) += snd-soc-omap2evm.o -obj-$(CONFIG_MACH_OMAP3EVM) += snd-soc-omap3evm.o -obj-$(CONFIG_MACH_OMAP3517EVM) += snd-soc-am3517evm.o +obj-$(CONFIG_SND_OMAP_SOC_OMAP2EVM) += snd-soc-omap2evm.o +obj-$(CONFIG_SND_OMAP_SOC_OMAP3EVM) += snd-soc-omap3evm.o +obj-$(CONFIG_SND_OMAP_SOC_OMAP3517EVM) += snd-soc-am3517evm.o obj-$(CONFIG_SND_OMAP_SOC_SDP3430) += snd-soc-sdp3430.o obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o obj-$(CONFIG_SND_OMAP_SOC_OMAP3_BEAGLE) += snd-soc-omap3beagle.o -- cgit v1.2.3 From fcfdebe70759c74e2e701f69aaa7f0e5e32cf5a6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 11 Dec 2009 12:51:05 +0100 Subject: ALSA: hrtimer - Fix lock-up The timer stop callback can be called from snd_timer_interrupt(), which is called from the hrtimer callback. Since hrtimer_cancel() waits for the callback completion, this eventually results in a lock-up. This patch fixes the problem by just toggling a flag at stop callback and call hrtimer_cancel() later. Reported-and-tested-by: Wojtek Zabolotny Cc: Signed-off-by: Takashi Iwai --- sound/core/hrtimer.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/core/hrtimer.c b/sound/core/hrtimer.c index 34c7d48f506..7f4d744ae40 100644 --- a/sound/core/hrtimer.c +++ b/sound/core/hrtimer.c @@ -37,14 +37,22 @@ static unsigned int resolution; struct snd_hrtimer { struct snd_timer *timer; struct hrtimer hrt; + atomic_t running; }; static enum hrtimer_restart snd_hrtimer_callback(struct hrtimer *hrt) { struct snd_hrtimer *stime = container_of(hrt, struct snd_hrtimer, hrt); struct snd_timer *t = stime->timer; + + if (!atomic_read(&stime->running)) + return HRTIMER_NORESTART; + hrtimer_forward_now(hrt, ns_to_ktime(t->sticks * resolution)); snd_timer_interrupt(stime->timer, t->sticks); + + if (!atomic_read(&stime->running)) + return HRTIMER_NORESTART; return HRTIMER_RESTART; } @@ -58,6 +66,7 @@ static int snd_hrtimer_open(struct snd_timer *t) hrtimer_init(&stime->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL); stime->timer = t; stime->hrt.function = snd_hrtimer_callback; + atomic_set(&stime->running, 0); t->private_data = stime; return 0; } @@ -78,16 +87,18 @@ static int snd_hrtimer_start(struct snd_timer *t) { struct snd_hrtimer *stime = t->private_data; + atomic_set(&stime->running, 0); + hrtimer_cancel(&stime->hrt); hrtimer_start(&stime->hrt, ns_to_ktime(t->sticks * resolution), HRTIMER_MODE_REL); + atomic_set(&stime->running, 1); return 0; } static int snd_hrtimer_stop(struct snd_timer *t) { struct snd_hrtimer *stime = t->private_data; - - hrtimer_cancel(&stime->hrt); + atomic_set(&stime->running, 0); return 0; } -- cgit v1.2.3 From f74890277a196949e4004fe2955e1d4fb3930f98 Mon Sep 17 00:00:00 2001 From: Steve Soule Date: Mon, 14 Dec 2009 11:06:03 -0700 Subject: ALSA: ac97_codec - increase timeout for analog sections to 5 second I have a Soundblaster 16PCI. For many years, alsa has had a bug where not all of the card's controls are detected (many alsa versions, many kernel versions). In particular, Master Playback Volume is usually not detected, and so I get no sound or extremely faint sound. The problem has always been inconsistent: sometimes all of the controls are detected correctly, and sometimes a partial set is detected. It works correctly about 10% of the time. Finally, I got around to tracking down the problem. When the driver fails, it prints the kernel message "AC'97 0 analog subsections not ready". This message is generated from the function snd_ac97_mixer() in ac97_codec.c. The message indicates that the card failed to come back after reset within the time limit. The time limit is 120 milliseconds. I tried increasing the time limit to 1 second, and found that this made the driver work about 70% of the time. I tried increasing it to 5 seconds, and it now seems to work 100% of the time. I expect that this change would be completely harmless for existing cards that work, and would only introduce additional delay for cards that do not work. ALSA bug#4032. Signed-off-by: Steve Soule Signed-off-by: Jaroslav Kysela --- sound/pci/ac97/ac97_codec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 20cb60afb20..c1192062300 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -2122,7 +2122,7 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template, } /* nothing should be in powerdown mode */ snd_ac97_write_cache(ac97, AC97_GENERAL_PURPOSE, 0); - end_time = jiffies + msecs_to_jiffies(120); + end_time = jiffies + msecs_to_jiffies(5000); do { if ((snd_ac97_read(ac97, AC97_POWERDOWN) & 0x0f) == 0x0f) goto __ready_ok; -- cgit v1.2.3 From 440b004cf953bec2bc8cd91c64ae707fd7e25327 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Sun, 20 Dec 2009 12:04:08 +0100 Subject: ALSA: hda/realtek: Remove extra .capsrc_nids initialization for ALC889_INTEL Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 8b375771b3a..2d3f4f893ef 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -9238,8 +9238,6 @@ static struct alc_config_preset alc882_presets[] = { .dac_nids = alc883_dac_nids, .num_adc_nids = ARRAY_SIZE(alc889_adc_nids), .adc_nids = alc889_adc_nids, - .capsrc_nids = alc889_capsrc_nids, - .capsrc_nids = alc889_capsrc_nids, .dig_out_nid = ALC883_DIGOUT_NID, .dig_in_nid = ALC883_DIGIN_NID, .slave_dig_outs = alc883_slave_dig_outs, -- cgit v1.2.3