Commit be3bfbba authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6: (33 commits)
  ALSA: ASoC codec: remove unused #include <version.h>
  ALSA: ASoC: update email address for Liam Girdwood
  ALSA: hda: corrected invalid mixer values
  ALSA: hda: add mixers for analog mixer on 92hd75xx codecs
  ALSA: ASoC: Add destination and source port for DMA on OMAP1
  ALSA: ASoC: Drop device registration from GTA01 lm4857 driver
  ALSA: ASoC: Fix build of GTA01 audio driver
  ALSA: ASoC: Add widgets before setting endpoints on GTA01
  ALSA: ASoC: Fix inverted input PGA mute bits in WM8903
  ALSA: ASoC: OMAP: Set DMA stream name at runtime in McBSP DAI driver
  ALSA: ASoC: OMAP: Add support for OMAP2430 and OMAP34xx in McBSP DAI driver
  ALSA: ASoC: OMAP: Add multilink support to McBSP DAI driver
  ALSA: ASoC: Make TLV320AIC26 user-visible
  ALSA: ASoC - clean up Kconfig for TLV320AIC2
  ALSA: ASoC: Make WM8510 microphone input a DAPM mixer
  ALSA: ASoC: Implement WM8510 bias level control
  ALSA: ASoC: Remove unused AUDIO_NAME define from codec drivers
  ALSA: ASoC: tlv320aic3x: Use uniform tlv320aic naming
  ALSA: ASoC: Add WM8510 SPI support
  ALSA: ASoC: Add WM8753 SPI support
  ...
parents 20272c89 7dc85076
......@@ -240,6 +240,7 @@ int snd_soc_dapm_sys_add(struct device *dev);
/* dapm audio pin control and status */
int snd_soc_dapm_enable_pin(struct snd_soc_codec *codec, char *pin);
int snd_soc_dapm_disable_pin(struct snd_soc_codec *codec, char *pin);
int snd_soc_dapm_nc_pin(struct snd_soc_codec *codec, char *pin);
int snd_soc_dapm_get_pin_status(struct snd_soc_codec *codec, char *pin);
int snd_soc_dapm_sync(struct snd_soc_codec *codec);
......
......@@ -30,7 +30,7 @@
**************************************************************************
*
* History
* May 02, 2003 Liam Girdwood <liam.girdwood@wolfsonmicro.com>
* May 02, 2003 Liam Girdwood <lrg@slimlogic.co.uk>
* Removed non existant WM9700
* Added support for WM9705, WM9708, WM9709, WM9710, WM9711
* WM9712 and WM9717
......
......@@ -476,7 +476,7 @@ static int patch_yamaha_ymf753(struct snd_ac97 * ac97)
}
/*
* May 2, 2003 Liam Girdwood <liam.girdwood@wolfsonmicro.com>
* May 2, 2003 Liam Girdwood <lrg@slimlogic.co.uk>
* removed broken wolfson00 patch.
* added support for WM9705,WM9708,WM9709,WM9710,WM9711,WM9712 and WM9717.
*/
......
......@@ -322,8 +322,8 @@ static hda_nid_t stac92hd71bxx_mux_nids[2] = {
0x1a, 0x1b
};
static hda_nid_t stac92hd71bxx_dmux_nids[1] = {
0x1c,
static hda_nid_t stac92hd71bxx_dmux_nids[2] = {
0x1c, 0x1d,
};
static hda_nid_t stac92hd71bxx_smux_nids[2] = {
......@@ -861,20 +861,18 @@ static struct hda_verb stac92hd71bxx_core_init[] = {
{ 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
/* connect headphone jack to dac1 */
{ 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
{ 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */
/* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
{ 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
{ 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
{ 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
};
#define HD_DISABLE_PORTF 3
#define HD_DISABLE_PORTF 2
static struct hda_verb stac92hd71bxx_analog_core_init[] = {
/* start of config #1 */
/* connect port 0f to audio mixer */
{ 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2},
{ 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */
/* unmute right and left channels for node 0x0f */
{ 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
/* start of config #2 */
......@@ -883,10 +881,6 @@ static struct hda_verb stac92hd71bxx_analog_core_init[] = {
{ 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
/* connect headphone jack to dac1 */
{ 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
/* connect port 0d to audio mixer */
{ 0x0d, AC_VERB_SET_CONNECT_SEL, 0x2},
/* unmute dac0 input in audio mixer */
{ 0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
/* unmute right and left channels for nodes 0x0a, 0xd */
{ 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
{ 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
......@@ -1107,6 +1101,7 @@ static struct snd_kcontrol_new stac92hd83xxx_mixer[] = {
static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = {
STAC_INPUT_SOURCE(2),
STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2),
HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
......@@ -1119,8 +1114,17 @@ static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = {
HDA_CODEC_MUTE("PC Beep Switch", 0x17, 0x2, HDA_INPUT),
*/
HDA_CODEC_MUTE("Analog Loopback 1", 0x17, 0x3, HDA_INPUT),
HDA_CODEC_MUTE("Analog Loopback 2", 0x17, 0x4, HDA_INPUT),
HDA_CODEC_MUTE("Import0 Mux Capture Switch", 0x17, 0x0, HDA_INPUT),
HDA_CODEC_VOLUME("Import0 Mux Capture Volume", 0x17, 0x0, HDA_INPUT),
HDA_CODEC_MUTE("Import1 Mux Capture Switch", 0x17, 0x1, HDA_INPUT),
HDA_CODEC_VOLUME("Import1 Mux Capture Volume", 0x17, 0x1, HDA_INPUT),
HDA_CODEC_MUTE("DAC0 Capture Switch", 0x17, 0x3, HDA_INPUT),
HDA_CODEC_VOLUME("DAC0 Capture Volume", 0x17, 0x3, HDA_INPUT),
HDA_CODEC_MUTE("DAC1 Capture Switch", 0x17, 0x4, HDA_INPUT),
HDA_CODEC_VOLUME("DAC1 Capture Volume", 0x17, 0x4, HDA_INPUT),
{ } /* end */
};
......@@ -1649,7 +1653,7 @@ static struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = {
static unsigned int ref92hd71bxx_pin_configs[11] = {
0x02214030, 0x02a19040, 0x01a19020, 0x01014010,
0x0181302e, 0x01114010, 0x01019020, 0x90a000f0,
0x0181302e, 0x01014010, 0x01019020, 0x90a000f0,
0x90a000f0, 0x01452050, 0x01452050,
};
......@@ -3000,7 +3004,7 @@ static int stac92xx_auto_create_mono_output_ctls(struct hda_codec *codec)
/* labels for amp mux outputs */
static const char *stac92xx_amp_labels[3] = {
"Front Microphone", "Microphone", "Line In"
"Front Microphone", "Microphone", "Line In",
};
/* create amp out controls mux on capable codecs */
......@@ -4327,6 +4331,16 @@ static struct hda_codec_ops stac92hd71bxx_patch_ops = {
#endif
};
static struct hda_input_mux stac92hd71bxx_dmux = {
.num_items = 4,
.items = {
{ "Analog Inputs", 0x00 },
{ "Mixer", 0x01 },
{ "Digital Mic 1", 0x02 },
{ "Digital Mic 2", 0x03 },
}
};
static int patch_stac92hd71bxx(struct hda_codec *codec)
{
struct sigmatel_spec *spec;
......@@ -4341,6 +4355,8 @@ static int patch_stac92hd71bxx(struct hda_codec *codec)
spec->num_pins = ARRAY_SIZE(stac92hd71bxx_pin_nids);
spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids);
spec->pin_nids = stac92hd71bxx_pin_nids;
memcpy(&spec->private_dimux, &stac92hd71bxx_dmux,
sizeof(stac92hd71bxx_dmux));
spec->board_config = snd_hda_check_board_config(codec,
STAC_92HD71BXX_MODELS,
stac92hd71bxx_models,
......@@ -4392,6 +4408,7 @@ static int patch_stac92hd71bxx(struct hda_codec *codec)
/* no output amps */
spec->num_pwrs = 0;
spec->mixer = stac92hd71bxx_analog_mixer;
spec->dinput_mux = &spec->private_dimux;
/* disable VSW */
spec->init = &stac92hd71bxx_analog_core_init[HD_DISABLE_PORTF];
......@@ -4409,12 +4426,13 @@ static int patch_stac92hd71bxx(struct hda_codec *codec)
spec->num_pwrs = 0;
/* fallthru */
default:
spec->dinput_mux = &spec->private_dimux;
spec->mixer = stac92hd71bxx_analog_mixer;
spec->init = stac92hd71bxx_analog_core_init;
codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
}
spec->aloopback_mask = 0x20;
spec->aloopback_mask = 0x50;
spec->aloopback_shift = 0;
if (spec->board_config > STAC_92HD71BXX_REF) {
......@@ -4456,6 +4474,10 @@ static int patch_stac92hd71bxx(struct hda_codec *codec)
spec->multiout.num_dacs = 1;
spec->multiout.hp_nid = 0x11;
spec->multiout.dac_nids = stac92hd71bxx_dac_nids;
if (spec->dinput_mux)
spec->private_dimux.num_items +=
spec->num_dmics -
(ARRAY_SIZE(stac92hd71bxx_dmic_nids) - 1);
err = stac92xx_parse_auto_config(codec, 0x21, 0x23);
if (!err) {
......
......@@ -8,20 +8,3 @@ config SND_AT91_SOC
config SND_AT91_SOC_SSC
tristate
config SND_AT91_SOC_ETI_B1_WM8731
tristate "SoC Audio support for WM8731-based Endrelia ETI-B1 boards"
depends on SND_AT91_SOC && (MACH_ETI_B1 || MACH_ETI_C1)
select SND_AT91_SOC_SSC
select SND_SOC_WM8731
help
Say Y if you want to add support for SoC audio on WM8731-based
Endrelia Technologies Inc ETI-B1 or ETI-C1 boards.
config SND_AT91_SOC_ETI_SLAVE
bool "Run codec in slave Mode on Endrelia boards"
depends on SND_AT91_SOC_ETI_B1_WM8731
default n
help
Say Y if you want to run with the AT91 SSC generating the BCLK
and LRC signals on Endrelia boards.
......@@ -4,8 +4,3 @@ snd-soc-at91-ssc-objs := at91-ssc.o
obj-$(CONFIG_SND_AT91_SOC) += snd-soc-at91.o
obj-$(CONFIG_SND_AT91_SOC_SSC) += snd-soc-at91-ssc.o
# AT91 Machine Support
snd-soc-eti-b1-wm8731-objs := eti_b1_wm8731.o
obj-$(CONFIG_SND_AT91_SOC_ETI_B1_WM8731) += snd-soc-eti-b1-wm8731.o
......@@ -5,7 +5,7 @@
* Endrelia Technologies Inc.
*
* Based on pxa2xx Platform drivers by
* Liam Girdwood <liam.girdwood@wolfsonmicro.com>
* Liam Girdwood <lrg@slimlogic.co.uk>
*
* 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
......
/*
* eti_b1_wm8731 -- SoC audio for AT91RM9200-based Endrelia ETI_B1 board.
*
* Author: Frank Mandarino <fmandarino@endrelia.com>
* Endrelia Technologies Inc.
* Created: Mar 29, 2006
*
* Based on corgi.c by:
*
* Copyright 2005 Wolfson Microelectronics PLC.
* Copyright 2005 Openedhand Ltd.
*
* Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
* Richard Purdie <richard@openedhand.com>
*
* 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 <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/clk.h>
#include <linux/timer.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <mach/hardware.h>
#include <mach/gpio.h>
#include "../codecs/wm8731.h"
#include "at91-pcm.h"
#include "at91-ssc.h"
#if 0
#define DBG(x...) printk(KERN_INFO "eti_b1_wm8731: " x)
#else
#define DBG(x...)
#endif
static struct clk *pck1_clk;
static struct clk *pllb_clk;
static int eti_b1_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;
struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
int ret;
/* cpu clock is the AT91 master clock sent to the SSC */
ret = snd_soc_dai_set_sysclk(cpu_dai, AT91_SYSCLK_MCK,
60000000, SND_SOC_CLOCK_IN);
if (ret < 0)
return ret;
/* codec system clock is supplied by PCK1, set to 12MHz */
ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK,
12000000, SND_SOC_CLOCK_IN);
if (ret < 0)
return ret;
/* Start PCK1 clock. */
clk_enable(pck1_clk);
DBG("pck1 started\n");
return 0;
}
static void eti_b1_shutdown(struct snd_pcm_substream *substream)
{
/* Stop PCK1 clock. */
clk_disable(pck1_clk);
DBG("pck1 stopped\n");
}
static int eti_b1_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;
#ifdef CONFIG_SND_AT91_SOC_ETI_SLAVE
unsigned int rate;
int cmr_div, period;
/* set codec DAI configuration */
ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
if (ret < 0)
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_CBS_CFS);
if (ret < 0)
return ret;
/*
* The SSC clock dividers depend on the sample rate. The CMR.DIV
* field divides the system master clock MCK to drive the SSC TK
* signal which provides the codec BCLK. The TCMR.PERIOD and
* RCMR.PERIOD fields further divide the BCLK signal to drive
* the SSC TF and RF signals which provide the codec DACLRC and
* ADCLRC clocks.
*
* The dividers were determined through trial and error, where a
* CMR.DIV value is chosen such that the resulting BCLK value is
* divisible, or almost divisible, by (2 * sample rate), and then
* the TCMR.PERIOD or RCMR.PERIOD is BCLK / (2 * sample rate) - 1.
*/
rate = params_rate(params);
switch (rate) {
case 8000:
cmr_div = 25; /* BCLK = 60MHz/(2*25) = 1.2MHz */
period = 74; /* LRC = BCLK/(2*(74+1)) = 8000Hz */
break;
case 32000:
cmr_div = 7; /* BCLK = 60MHz/(2*7) ~= 4.28571428MHz */
period = 66; /* LRC = BCLK/(2*(66+1)) = 31982.942Hz */
break;
case 48000:
cmr_div = 13; /* BCLK = 60MHz/(2*13) ~= 2.3076923MHz */
period = 23; /* LRC = BCLK/(2*(23+1)) = 48076.923Hz */
break;
default:
printk(KERN_WARNING "unsupported rate %d on ETI-B1 board\n", rate);
return -EINVAL;
}
/* set the MCK divider for BCLK */
ret = snd_soc_dai_set_clkdiv(cpu_dai, AT91SSC_CMR_DIV, cmr_div);
if (ret < 0)
return ret;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
/* set the BCLK divider for DACLRC */
ret = snd_soc_dai_set_clkdiv(cpu_dai,
AT91SSC_TCMR_PERIOD, period);
} else {
/* set the BCLK divider for ADCLRC */
ret = snd_soc_dai_set_clkdiv(cpu_dai,
AT91SSC_RCMR_PERIOD, period);
}
if (ret < 0)
return ret;
#else /* CONFIG_SND_AT91_SOC_ETI_SLAVE */
/*
* Codec in Master Mode.
*/
/* 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)
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)
return ret;
#endif /* CONFIG_SND_AT91_SOC_ETI_SLAVE */
return 0;
}
static struct snd_soc_ops eti_b1_ops = {
.startup = eti_b1_startup,
.hw_params = eti_b1_hw_params,
.shutdown = eti_b1_shutdown,
};
static const struct snd_soc_dapm_widget eti_b1_dapm_widgets[] = {
SND_SOC_DAPM_MIC("Int Mic", NULL),
SND_SOC_DAPM_SPK("Ext Spk", NULL),
};
static const struct snd_soc_dapm_route intercon[] = {
/* speaker connected to LHPOUT */
{"Ext Spk", NULL, "LHPOUT"},
/* mic is connected to Mic Jack, with WM8731 Mic Bias */
{"MICIN", NULL, "Mic Bias"},
{"Mic Bias", NULL, "Int Mic"},
};
/*
* Logic for a wm8731 as connected on a Endrelia ETI-B1 board.
*/
static int eti_b1_wm8731_init(struct snd_soc_codec *codec)
{
DBG("eti_b1_wm8731_init() called\n");
/* Add specific widgets */
snd_soc_dapm_new_controls(codec, eti_b1_dapm_widgets,
ARRAY_SIZE(eti_b1_dapm_widgets));
/* Set up specific audio path interconnects */
snd_soc_dapm_add_route(codec, intercon, ARRAY_SIZE(intercon));
/* not connected */
snd_soc_dapm_disable_pin(codec, "RLINEIN");
snd_soc_dapm_disable_pin(codec, "LLINEIN");
/* always connected */
snd_soc_dapm_enable_pin(codec, "Int Mic");
snd_soc_dapm_enable_pin(codec, "Ext Spk");
snd_soc_dapm_sync(codec);
return 0;
}
static struct snd_soc_dai_link eti_b1_dai = {
.name = "WM8731",
.stream_name = "WM8731 PCM",
.cpu_dai = &at91_ssc_dai[1],
.codec_dai = &wm8731_dai,
.init = eti_b1_wm8731_init,
.ops = &eti_b1_ops,
};
static struct snd_soc_machine snd_soc_machine_eti_b1 = {
.name = "ETI_B1_WM8731",
.dai_link = &eti_b1_dai,
.num_links = 1,
};
static struct wm8731_setup_data eti_b1_wm8731_setup = {
.i2c_bus = 0,
.i2c_address = 0x1a,
};
static struct snd_soc_device eti_b1_snd_devdata = {
.machine = &snd_soc_machine_eti_b1,
.platform = &at91_soc_platform,
.codec_dev = &soc_codec_dev_wm8731,
.codec_data = &eti_b1_wm8731_setup,
};
static struct platform_device *eti_b1_snd_device;
static int __init eti_b1_init(void)
{
int ret;
struct at91_ssc_periph *ssc = eti_b1_dai.cpu_dai->private_data;
if (!request_mem_region(AT91RM9200_BASE_SSC1, SZ_16K, "soc-audio")) {
DBG("SSC1 memory region is busy\n");
return -EBUSY;
}
ssc->base = ioremap(AT91RM9200_BASE_SSC1, SZ_16K);
if (!ssc->base) {
DBG("SSC1 memory ioremap failed\n");
ret = -ENOMEM;
goto fail_release_mem;
}
ssc->pid = AT91RM9200_ID_SSC1;
eti_b1_snd_device = platform_device_alloc("soc-audio", -1);
if (!eti_b1_snd_device) {
DBG("platform device allocation failed\n");
ret = -ENOMEM;
goto fail_io_unmap;
}
platform_set_drvdata(eti_b1_snd_device, &eti_b1_snd_devdata);
eti_b1_snd_devdata.dev = &eti_b1_snd_device->dev;
ret = platform_device_add(eti_b1_snd_device);
if (ret) {
DBG("platform device add failed\n");
platform_device_put(eti_b1_snd_device);
goto fail_io_unmap;
}
at91_set_A_periph(AT91_PIN_PB6, 0); /* TF1 */
at91_set_A_periph(AT91_PIN_PB7, 0); /* TK1 */
at91_set_A_periph(AT91_PIN_PB8, 0); /* TD1 */
at91_set_A_periph(AT91_PIN_PB9, 0); /* RD1 */
/* at91_set_A_periph(AT91_PIN_PB10, 0);*/ /* RK1 */
at91_set_A_periph(AT91_PIN_PB11, 0); /* RF1 */
/*
* Set PCK1 parent to PLLB and its rate to 12 Mhz.
*/
pllb_clk = clk_get(NULL, "pllb");
pck1_clk = clk_get(NULL, "pck1");
clk_set_parent(pck1_clk, pllb_clk);
clk_set_rate(pck1_clk, 12000000);
DBG("MCLK rate %luHz\n", clk_get_rate(pck1_clk));
/* assign the GPIO pin to PCK1 */
at91_set_B_periph(AT91_PIN_PA24, 0);
#ifdef CONFIG_SND_AT91_SOC_ETI_SLAVE
printk(KERN_INFO "eti_b1_wm8731: Codec in Slave Mode\n");
#else
printk(KERN_INFO "eti_b1_wm8731: Codec in Master Mode\n");
#endif
return ret;
fail_io_unmap:
iounmap(ssc->base);
fail_release_mem:
release_mem_region(AT91RM9200_BASE_SSC1, SZ_16K);
return ret;
}
static void __exit eti_b1_exit(void)
{
struct at91_ssc_periph *ssc = eti_b1_dai.cpu_dai->private_data;
clk_put(pck1_clk);
clk_put(pllb_clk);
platform_device_unregister(eti_b1_snd_device);
iounmap(ssc->base);
release_mem_region(AT91RM9200_BASE_SSC1, SZ_16K);
}
module_init(eti_b1_init);
module_exit(eti_b1_exit);
/* Module information */
MODULE_AUTHOR("Frank Mandarino <fmandarino@endrelia.com>");
MODULE_DESCRIPTION("ALSA SoC ETI-B1-WM8731");
MODULE_LICENSE("GPL");
......@@ -17,6 +17,22 @@ config SND_BF5XX_SOC_SSM2602
help
Say Y if you want to add support for SoC audio on BF527-EZKIT.
config SND_BF5XX_SOC_AD73311
tristate "SoC AD73311 Audio support for Blackfin"
depends on SND_BF5XX_I2S
select SND_BF5XX_SOC_I2S
select SND_SOC_AD73311
help
Say Y if you want to add support for AD73311 codec on Blackfin.
config SND_BFIN_AD73311_SE
int "PF pin for AD73311L Chip Select"
depends on SND_BF5XX_SOC_AD73311
default 4
help
Enter the GPIO used to control AD73311's SE pin. Acceptable
values are 0 to 7
config SND_BF5XX_AC97
tristate "SoC AC97 Audio for the ADI BF5xx chip"
depends on BLACKFIN && SND_SOC
......
......@@ -14,7 +14,8 @@ obj-$(CONFIG_SND_BF5XX_SOC_I2S) += snd-soc-bf5xx-i2s.o
# Blackfin Machine Support
snd-ad1980-objs := bf5xx-ad1980.o
snd-ssm2602-objs := bf5xx-ssm2602.o
snd-ad73311-objs := bf5xx-ad73311.o
obj-$(CONFIG_SND_BF5XX_SOC_AD1980) += snd-ad1980.o
obj-$(CONFIG_SND_BF5XX_SOC_SSM2602) += snd-ssm2602.o
obj-$(CONFIG_SND_BF5XX_SOC_AD73311) += snd-ad73311.o
......@@ -56,6 +56,7 @@ static void bf5xx_mmap_copy(struct snd_pcm_substream *substream,
sport->tx_pos += runtime->period_size;
if (sport->tx_pos >= runtime->buffer_size)
sport->tx_pos %= runtime->buffer_size;
sport->tx_delay_pos = sport->tx_pos;
} else {
bf5xx_ac97_to_pcm(
(struct ac97_frame *)sport->rx_dma_buf + sport->rx_pos,
......@@ -72,7 +73,15 @@ static void bf5xx_dma_irq(void *data)
struct snd_pcm_substream *pcm = data;
#if defined(CONFIG_SND_MMAP_SUPPORT)
struct snd_pcm_runtime *runtime = pcm->runtime;
struct sport_device *sport = runtime->private_data;
bf5xx_mmap_copy(pcm, runtime->period_size);
if (pcm->stream == SNDRV_PCM_STREAM_PLAYBACK) {
if (sport->once == 0) {
snd_pcm_period_elapsed(pcm);
bf5xx_mmap_copy(pcm, runtime->period_size);
sport->once = 1;
}
}
#endif
snd_pcm_period_elapsed(pcm);
}
......@@ -114,6 +123,10 @@ static int bf5xx_pcm_hw_params(struct snd_pcm_substream *substream,
static int bf5xx_pcm_hw_free(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
memset(runtime->dma_area, 0, runtime->buffer_size);
snd_pcm_lib_free_pages(substream);
return 0;
}
......@@ -127,16 +140,11 @@ static int bf5xx_pcm_prepare(struct snd_pcm_substream *substream)
* SPORT working in TMD mode(include AC97).
*/
#if defined(CONFIG_SND_MMAP_SUPPORT)
size_t size = bf5xx_pcm_hardware.buffer_bytes_max
* sizeof(struct ac97_frame) / 4;
/*clean up intermediate buffer*/
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
memset(sport->tx_dma_buf, 0, size);
sport_set_tx_callback(sport, bf5xx_dma_irq, substream);
sport_config_tx_dma(sport, sport->tx_dma_buf, runtime->periods,
runtime->period_size * sizeof(struct ac97_frame));
} else {
memset(sport->rx_dma_buf, 0, size);
sport_set_rx_callback(sport, bf5xx_dma_irq, substream);
sport_config_rx_dma(sport, sport->rx_dma_buf, runtime->periods,
runtime->period_size * sizeof(struct ac97_frame));
......@@ -164,8 +172,12 @@ static int bf5xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
pr_debug("%s enter\n", __func__);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
bf5xx_mmap_copy(substream, runtime->period_size);
snd_pcm_period_elapsed(substream);
sport->tx_delay_pos = 0;
sport_tx_start(sport);
}
else
sport_rx_start(sport);
break;
......@@ -198,7 +210,7 @@ static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream)
#if defined(CONFIG_SND_MMAP_SUPPORT)
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
curr = sport->tx_pos;
curr = sport->tx_delay_pos;
else
curr = sport->rx_pos;
#else
......@@ -237,6 +249,21 @@ static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
return ret;
}
static int bf5xx_pcm_close(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct sport_device *sport = runtime->private_data;
pr_debug("%s enter\n", __func__);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
sport->once = 0;
memset(sport->tx_dma_buf, 0, runtime->buffer_size * sizeof(struct ac97_frame));
} else
memset(sport->rx_dma_buf, 0, runtime->buffer_size * sizeof(struct ac97_frame));
return 0;
}
#ifdef CONFIG_SND_MMAP_SUPPORT
static int bf5xx_pcm_mmap(struct snd_pcm_substream *substream,
struct vm_area_struct *vma)
......@@ -272,6 +299,7 @@ static int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel,
struct snd_pcm_ops bf5xx_pcm_ac97_ops = {
.open = bf5xx_pcm_open,
.close = bf5xx_pcm_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = bf5xx_pcm_hw_params,
.hw_free = bf5xx_pcm_hw_free,
......
......@@ -128,7 +128,6 @@ static void enqueue_cmd(struct snd_ac97 *ac97, __u16 addr, __u16 data)
int nextfrag = sport_tx_curr_frag(sport);
struct ac97_frame *nextwrite;
sport_incfrag(sport, &nextfrag, 1);
sport_incfrag(sport, &nextfrag, 1);
nextwrite = (struct ac97_frame *)(sport->tx_buf + \
......
/*
* File: sound/soc/blackfin/bf5xx-ad73311.c
* Author: Cliff Cai <Cliff.Cai@analog.com>
*
* Created: Thur Sep 25 2008
* Description: Board driver for ad73311 sound chip
*
* Modified:
* Copyright 2008 Analog Devices Inc.
*
* Bugs: Enter bugs at http://blackfin.uclinux.org/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see the file COPYING, or write
* to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/pcm_params.h>
#include <asm/blackfin.h>
#include <asm/cacheflush.h>
#include <asm/irq.h>
#include <asm/dma.h>
#include <asm/portmux.h>
#include "../codecs/ad73311.h"
#include "bf5xx-sport.h"
#include "bf5xx-i2s-pcm.h"
#include "bf5xx-i2s.h"
#if CONFIG_SND_BF5XX_SPORT_NUM == 0
#define bfin_write_SPORT_TCR1 bfin_write_SPORT0_TCR1
#define bfin_read_SPORT_TCR1 bfin_read_SPORT0_TCR1
#define bfin_write_SPORT_TCR2 bfin_write_SPORT0_TCR2
#define bfin_write_SPORT_TX16 bfin_write_SPORT0_TX16
#define bfin_read_SPORT_STAT bfin_read_SPORT0_STAT
#else
#define bfin_write_SPORT_TCR1 bfin_write_SPORT1_TCR1
#define bfin_read_SPORT_TCR1 bfin_read_SPORT1_TCR1
#define bfin_write_SPORT_TCR2 bfin_write_SPORT1_TCR2
#define bfin_write_SPORT_TX16 bfin_write_SPORT1_TX16
#define bfin_read_SPORT_STAT bfin_read_SPORT1_STAT
#endif
#define GPIO_SE CONFIG_SND_BFIN_AD73311_SE
static struct snd_soc_machine bf5xx_ad73311;
static int snd_ad73311_startup(void)
{
pr_debug("%s enter\n", __func__);
/* Pull up SE pin on AD73311L */
gpio_set_value(GPIO_SE, 1);
return 0;
}
static int snd_ad73311_configure(void)
{
unsigned short ctrl_regs[6];
unsigned short status = 0;
int count = 0;
/* DMCLK = MCLK = 16.384 MHz
* SCLK = DMCLK/8 = 2.048 MHz
* Sample Rate = DMCLK/2048 = 8 KHz
*/
ctrl_regs[0] = AD_CONTROL | AD_WRITE | CTRL_REG_B | REGB_MCDIV(0) | \
REGB_SCDIV(0) | REGB_DIRATE(0);
ctrl_regs[1] = AD_CONTROL | AD_WRITE | CTRL_REG_C | REGC_PUDEV | \
REGC_PUADC | REGC_PUDAC | REGC_PUREF | REGC_REFUSE ;
ctrl_regs[2] = AD_CONTROL | AD_WRITE | CTRL_REG_D | REGD_OGS(2) | \
REGD_IGS(2);
ctrl_regs[3] = AD_CONTROL | AD_WRITE | CTRL_REG_E | REGE_DA(0x1f);
ctrl_regs[4] = AD_CONTROL | AD_WRITE | CTRL_REG_F | REGF_SEEN ;
ctrl_regs[5] = AD_CONTROL | AD_WRITE | CTRL_REG_A | REGA_MODE_DATA;
local_irq_disable();
snd_ad73311_startup();
udelay(1);
bfin_write_SPORT_TCR1(TFSR);
bfin_write_SPORT_TCR2(0xF);
SSYNC();
/* SPORT Tx Register is a 8 x 16 FIFO, all the data can be put to
* FIFO before enable SPORT to transfer the data
*/
for (count = 0; count < 6; count++)
bfin_write_SPORT_TX16(ctrl_regs[count]);
SSYNC();
bfin_write_SPORT_TCR1(bfin_read_SPORT_TCR1() | TSPEN);
SSYNC();
/* When TUVF is set, the data is already send out */
while (!(status & TUVF) && count++ < 10000) {
udelay(1);
status = bfin_read_SPORT_STAT();
SSYNC();
}
bfin_write_SPORT_TCR1(bfin_read_SPORT_TCR1() & ~TSPEN);
SSYNC();
local_irq_enable();
if (count == 10000) {
printk(KERN_ERR "ad73311: failed to configure codec\n");
return -1;
}
return 0;
}
static int bf5xx_probe(struct platform_device *pdev)
{
int err;
if (gpio_request(GPIO_SE, "AD73311_SE")) {
printk(KERN_ERR "%s: Failed ro request GPIO_%d\n", __func__, GPIO_SE);
return -EBUSY;
}
gpio_direction_output(GPIO_SE, 0);
err = snd_ad73311_configure();
if (err < 0)
return -EFAULT;
return 0;
}
static int bf5xx_ad73311_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
pr_debug("%s enter\n", __func__);
cpu_dai->private_data = sport_handle;
return 0;
}
static int bf5xx_ad73311_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;
int ret = 0;
pr_debug("%s rate %d format %x\n", __func__, params_rate(params),
params_format(params));
/* set cpu DAI configuration */
ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A |
SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
if (ret < 0)
return ret;
return 0;
}
static struct snd_soc_ops bf5xx_ad73311_ops = {
.startup = bf5xx_ad73311_startup,
.hw_params = bf5xx_ad73311_hw_params,
};
static struct snd_soc_dai_link bf5xx_ad73311_dai = {
.name = "ad73311",
.stream_name = "AD73311",
.cpu_dai = &bf5xx_i2s_dai,
.codec_dai = &ad73311_dai,
.ops = &bf5xx_ad73311_ops,
};
static struct snd_soc_machine bf5xx_ad73311 = {
.name = "bf5xx_ad73311",
.probe = bf5xx_probe,
.dai_link = &bf5xx_ad73311_dai,
.num_links = 1,
};
static struct snd_soc_device bf5xx_ad73311_snd_devdata = {
.machine = &bf5xx_ad73311,
.platform = &bf5xx_i2s_soc_platform,
.codec_dev = &soc_codec_dev_ad73311,
};
static struct platform_device *bf52x_ad73311_snd_device;
static int __init bf5xx_ad73311_init(void)
{
int ret;
pr_debug("%s enter\n", __func__);
bf52x_ad73311_snd_device = platform_device_alloc("soc-audio", -1);
if (!bf52x_ad73311_snd_device)
return -ENOMEM;
platform_set_drvdata(bf52x_ad73311_snd_device, &bf5xx_ad73311_snd_devdata);
bf5xx_ad73311_snd_devdata.dev = &bf52x_ad73311_snd_device->dev;
ret = platform_device_add(bf52x_ad73311_snd_device);
if (ret)
platform_device_put(bf52x_ad73311_snd_device);
return ret;
}
static void __exit bf5xx_ad73311_exit(void)
{
pr_debug("%s enter\n", __func__);
platform_device_unregister(bf52x_ad73311_snd_device);
}
module_init(bf5xx_ad73311_init);
module_exit(bf5xx_ad73311_exit);
/* Module information */
MODULE_AUTHOR("Cliff Cai");
MODULE_DESCRIPTION("ALSA SoC AD73311 Blackfin");
MODULE_LICENSE("GPL");
......@@ -70,6 +70,13 @@ static struct sport_param sport_params[2] = {
}
};
static u16 sport_req[][7] = {
{ P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS,
P_SPORT0_DRPRI, P_SPORT0_RSCLK, 0},
{ P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS,
P_SPORT1_DRPRI, P_SPORT1_RSCLK, 0},
};
static int bf5xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
unsigned int fmt)
{
......@@ -78,6 +85,14 @@ static int bf5xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
/* interface format:support I2S,slave mode */
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
bf5xx_i2s.tcr1 |= TFSR | TCKFE;
bf5xx_i2s.rcr1 |= RFSR | RCKFE;
bf5xx_i2s.tcr2 |= TSFSE;
bf5xx_i2s.rcr2 |= RSFSE;
break;
case SND_SOC_DAIFMT_DSP_A:
bf5xx_i2s.tcr1 |= TFSR;
bf5xx_i2s.rcr1 |= RFSR;
break;
case SND_SOC_DAIFMT_LEFT_J:
ret = -EINVAL;
......@@ -127,14 +142,17 @@ static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream,
case SNDRV_PCM_FORMAT_S16_LE:
bf5xx_i2s.tcr2 |= 15;
bf5xx_i2s.rcr2 |= 15;
sport_handle->wdsize = 2;
break;
case SNDRV_PCM_FORMAT_S24_LE:
bf5xx_i2s.tcr2 |= 23;
bf5xx_i2s.rcr2 |= 23;
sport_handle->wdsize = 3;
break;
case SNDRV_PCM_FORMAT_S32_LE:
bf5xx_i2s.tcr2 |= 31;
bf5xx_i2s.rcr2 |= 31;
sport_handle->wdsize = 4;
break;
}
......@@ -145,17 +163,17 @@ static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream,
* need to configure both of them at the time when the first
* stream is opened.
*
* CPU DAI format:I2S, slave mode.
* CPU DAI:slave mode.
*/
ret = sport_config_rx(sport_handle, RFSR | RCKFE,
RSFSE|bf5xx_i2s.rcr2, 0, 0);
ret = sport_config_rx(sport_handle, bf5xx_i2s.rcr1,
bf5xx_i2s.rcr2, 0, 0);
if (ret) {
pr_err("SPORT is busy!\n");
return -EBUSY;
}
ret = sport_config_tx(sport_handle, TFSR | TCKFE,
TSFSE|bf5xx_i2s.tcr2, 0, 0);
ret = sport_config_tx(sport_handle, bf5xx_i2s.tcr1,
bf5xx_i2s.tcr2, 0, 0);
if (ret) {
pr_err("SPORT is busy!\n");
return -EBUSY;
......@@ -174,13 +192,6 @@ static void bf5xx_i2s_shutdown(struct snd_pcm_substream *substream)
static int bf5xx_i2s_probe(struct platform_device *pdev,
struct snd_soc_dai *dai)
{
u16 sport_req[][7] = {
{ P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS,
P_SPORT0_DRPRI, P_SPORT0_RSCLK, 0},
{ P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS,
P_SPORT1_DRPRI, P_SPORT1_RSCLK, 0},
};
pr_debug("%s enter\n", __func__);
if (peripheral_request_list(&sport_req[sport_num][0], "soc-audio")) {
pr_err("Requesting Peripherals failed\n");
......@@ -198,6 +209,13 @@ static int bf5xx_i2s_probe(struct platform_device *pdev,
return 0;
}
static void bf5xx_i2s_remove(struct platform_device *pdev,
struct snd_soc_dai *dai)
{
pr_debug("%s enter\n", __func__);
peripheral_free_list(&sport_req[sport_num][0]);
}
#ifdef CONFIG_PM
static int bf5xx_i2s_suspend(struct platform_device *dev,
struct snd_soc_dai *dai)
......@@ -263,15 +281,16 @@ struct snd_soc_dai bf5xx_i2s_dai = {
.id = 0,
.type = SND_SOC_DAI_I2S,
.probe = bf5xx_i2s_probe,
.remove = bf5xx_i2s_remove,
.suspend = bf5xx_i2s_suspend,
.resume = bf5xx_i2s_resume,
.playback = {
.channels_min = 2,
.channels_min = 1,
.channels_max = 2,
.rates = BF5XX_I2S_RATES,
.formats = BF5XX_I2S_FORMATS,},
.capture = {
.channels_min = 2,
.channels_min = 1,
.channels_max = 2,
.rates = BF5XX_I2S_RATES,
.formats = BF5XX_I2S_FORMATS,},
......
......@@ -123,6 +123,8 @@ struct sport_device {
int rx_pos;
unsigned int tx_buffer_size;
unsigned int rx_buffer_size;
int tx_delay_pos;
int once;
#endif
void *private_data;
};
......
......@@ -3,9 +3,11 @@ config SND_SOC_ALL_CODECS
depends on I2C
select SPI
select SPI_MASTER
select SND_SOC_AD73311
select SND_SOC_AK4535
select SND_SOC_CS4270
select SND_SOC_SSM2602
select SND_SOC_TLV320AIC23
select SND_SOC_TLV320AIC26
select SND_SOC_TLV320AIC3X
select SND_SOC_UDA1380
......@@ -34,6 +36,9 @@ config SND_SOC_AC97_CODEC
config SND_SOC_AD1980
tristate
config SND_SOC_AD73311
tristate
config SND_SOC_AK4535
tristate
......@@ -58,9 +63,13 @@ config SND_SOC_CS4270_VD33_ERRATA
config SND_SOC_SSM2602
tristate
config SND_SOC_TLV320AIC23
tristate
depends on I2C
config SND_SOC_TLV320AIC26
tristate "TI TLV320AIC26 Codec support"
depends on SND_SOC && SPI
depends on SPI
config SND_SOC_TLV320AIC3X
tristate
......
snd-soc-ac97-objs := ac97.o
snd-soc-ad1980-objs := ad1980.o
snd-soc-ad73311-objs := ad73311.o
snd-soc-ak4535-objs := ak4535.o
snd-soc-cs4270-objs := cs4270.o
snd-soc-ssm2602-objs := ssm2602.o
snd-soc-tlv320aic23-objs := tlv320aic23.o
snd-soc-tlv320aic26-objs := tlv320aic26.o
snd-soc-tlv320aic3x-objs := tlv320aic3x.o
snd-soc-uda1380-objs := uda1380.o
......@@ -20,9 +22,11 @@ snd-soc-wm9713-objs := wm9713.o
obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o
obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o
obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o
obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o
obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o
obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.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_UDA1380) += snd-soc-uda1380.o
......
......@@ -2,8 +2,7 @@
* ac97.c -- ALSA Soc AC97 codec support
*
* Copyright 2005 Wolfson Microelectronics PLC.
* Author: Liam Girdwood
* liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
* Author: Liam Girdwood <lrg@slimlogic.co.uk>
*
* 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
......
......@@ -13,7 +13,6 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <sound/core.h>
......
/*
* ad73311.c -- ALSA Soc AD73311 codec support
*
* Copyright: Analog Device Inc.
* Author: Cliff Cai <cliff.cai@analog.com>
*
* 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.
*
* Revision history
* 25th Sep 2008 Initial version.
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/ac97_codec.h>
#include <sound/initval.h>
#include <sound/soc.h>
#include "ad73311.h"
struct snd_soc_dai ad73311_dai = {
.name = "AD73311",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
.channels_max = 1,
.rates = SNDRV_PCM_RATE_8000,
.formats = SNDRV_PCM_FMTBIT_S16_LE, },
.capture = {
.stream_name = "Capture",
.channels_min = 1,
.channels_max = 1,
.rates = SNDRV_PCM_RATE_8000,
.formats = SNDRV_PCM_FMTBIT_S16_LE, },
};
EXPORT_SYMBOL_GPL(ad73311_dai);
static int ad73311_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 = "AD73311";
codec->owner = THIS_MODULE;
codec->dai = &ad73311_dai;
codec->num_dai = 1;
socdev->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 "ad73311: failed to create pcms\n");
goto pcm_err;
}
ret = snd_soc_register_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->codec);
socdev->codec = NULL;
return ret;
}
static int ad73311_soc_remove(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
struct snd_soc_codec *codec = socdev->codec;
if (codec == NULL)
return 0;
snd_soc_free_pcms(socdev);
kfree(codec);
return 0;
}
struct snd_soc_codec_device soc_codec_dev_ad73311 = {
.probe = ad73311_soc_probe,
.remove = ad73311_soc_remove,
};
EXPORT_SYMBOL_GPL(soc_codec_dev_ad73311);
MODULE_DESCRIPTION("ASoC ad73311 driver");
MODULE_AUTHOR("Cliff Cai ");
MODULE_LICENSE("GPL");
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment