mirror of
https://github.com/adulau/aha.git
synced 2024-12-28 03:36:19 +00:00
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 ...
This commit is contained in:
commit
be3bfbba8f
56 changed files with 2038 additions and 602 deletions
|
@ -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 @@ again:
|
|||
/* 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 @@ again:
|
|||
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 @@ again:
|
|||
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
|
||||
|
|
|
@ -1,349 +0,0 @@
|
|||
/*
|
||||
* 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 + \
|
||||
|
|
240
sound/soc/blackfin/bf5xx-ad73311.c
Normal file
240
sound/soc/blackfin/bf5xx-ad73311.c
Normal file
|
@ -0,0 +1,240 @@
|
|||
/*
|
||||
* 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
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
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>
|
||||
|
|
107
sound/soc/codecs/ad73311.c
Normal file
107
sound/soc/codecs/ad73311.c
Normal file
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* 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");
|
90
sound/soc/codecs/ad73311.h
Normal file
90
sound/soc/codecs/ad73311.h
Normal file
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* File: sound/soc/codec/ad73311.h
|
||||
* Based on:
|
||||
* Author: Cliff Cai <cliff.cai@analog.com>
|
||||
*
|
||||
* Created: Thur Sep 25, 2008
|
||||
* Description: definitions for AD73311 registers
|
||||
*
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2006 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
|
||||
*/
|
||||
|
||||
#ifndef __AD73311_H__
|
||||
#define __AD73311_H__
|
||||
|
||||
#define AD_CONTROL 0x8000
|
||||
#define AD_DATA 0x0000
|
||||
#define AD_READ 0x4000
|
||||
#define AD_WRITE 0x0000
|
||||
|
||||
/* Control register A */
|
||||
#define CTRL_REG_A (0 << 8)
|
||||
|
||||
#define REGA_MODE_PRO 0x00
|
||||
#define REGA_MODE_DATA 0x01
|
||||
#define REGA_MODE_MIXED 0x03
|
||||
#define REGA_DLB 0x04
|
||||
#define REGA_SLB 0x08
|
||||
#define REGA_DEVC(x) ((x & 0x7) << 4)
|
||||
#define REGA_RESET 0x80
|
||||
|
||||
/* Control register B */
|
||||
#define CTRL_REG_B (1 << 8)
|
||||
|
||||
#define REGB_DIRATE(x) (x & 0x3)
|
||||
#define REGB_SCDIV(x) ((x & 0x3) << 2)
|
||||
#define REGB_MCDIV(x) ((x & 0x7) << 4)
|
||||
#define REGB_CEE (1 << 7)
|
||||
|
||||
/* Control register C */
|
||||
#define CTRL_REG_C (2 << 8)
|
||||
|
||||
#define REGC_PUDEV (1 << 0)
|
||||
#define REGC_PUADC (1 << 3)
|
||||
#define REGC_PUDAC (1 << 4)
|
||||
#define REGC_PUREF (1 << 5)
|
||||
#define REGC_REFUSE (1 << 6)
|
||||
|
||||
/* Control register D */
|
||||
#define CTRL_REG_D (3 << 8)
|
||||
|
||||
#define REGD_IGS(x) (x & 0x7)
|
||||
#define REGD_RMOD (1 << 3)
|
||||
#define REGD_OGS(x) ((x & 0x7) << 4)
|
||||
#define REGD_MUTE (x << 7)
|
||||
|
||||
/* Control register E */
|
||||
#define CTRL_REG_E (4 << 8)
|
||||
|
||||
#define REGE_DA(x) (x & 0x1f)
|
||||
#define REGE_IBYP (1 << 5)
|
||||
|
||||
/* Control register F */
|
||||
#define CTRL_REG_F (5 << 8)
|
||||
|
||||
#define REGF_SEEN (1 << 5)
|
||||
#define REGF_INV (1 << 6)
|
||||
#define REGF_ALB (1 << 7)
|
||||
|
||||
extern struct snd_soc_dai ad73311_dai;
|
||||
extern struct snd_soc_codec_device soc_codec_dev_ad73311;
|
||||
#endif
|
|
@ -28,7 +28,6 @@
|
|||
|
||||
#include "ak4535.h"
|
||||
|
||||
#define AUDIO_NAME "ak4535"
|
||||
#define AK4535_VERSION "0.3"
|
||||
|
||||
struct snd_soc_codec_device soc_codec_dev_ak4535;
|
||||
|
|
|
@ -42,7 +42,6 @@
|
|||
|
||||
#include "ssm2602.h"
|
||||
|
||||
#define AUDIO_NAME "ssm2602"
|
||||
#define SSM2602_VERSION "0.1"
|
||||
|
||||
struct snd_soc_codec_device soc_codec_dev_ssm2602;
|
||||
|
|
714
sound/soc/codecs/tlv320aic23.c
Normal file
714
sound/soc/codecs/tlv320aic23.c
Normal file
|
@ -0,0 +1,714 @@
|
|||
/*
|
||||
* ALSA SoC TLV320AIC23 codec driver
|
||||
*
|
||||
* Author: Arun KS, <arunks@mistralsolutions.com>
|
||||
* Copyright: (C) 2008 Mistral Solutions Pvt Ltd.,
|
||||
*
|
||||
* Based on sound/soc/codecs/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.
|
||||
*
|
||||
* Notes:
|
||||
* The AIC23 is a driver for a low power stereo audio
|
||||
* codec tlv320aic23
|
||||
*
|
||||
* The machine layer should disable unsupported inputs/outputs by
|
||||
* snd_soc_dapm_disable_pin(codec, "LHPOUT"), etc.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/soc-dapm.h>
|
||||
#include <sound/tlv.h>
|
||||
#include <sound/initval.h>
|
||||
|
||||
#include "tlv320aic23.h"
|
||||
|
||||
#define AIC23_VERSION "0.1"
|
||||
|
||||
struct tlv320aic23_srate_reg_info {
|
||||
u32 sample_rate;
|
||||
u8 control; /* SR3, SR2, SR1, SR0 and BOSR */
|
||||
u8 divider; /* if 0 CLKIN = MCLK, if 1 CLKIN = MCLK/2 */
|
||||
};
|
||||
|
||||
/*
|
||||
* AIC23 register cache
|
||||
*/
|
||||
static const u16 tlv320aic23_reg[] = {
|
||||
0x0097, 0x0097, 0x00F9, 0x00F9, /* 0 */
|
||||
0x001A, 0x0004, 0x0007, 0x0001, /* 4 */
|
||||
0x0020, 0x0000, 0x0000, 0x0000, /* 8 */
|
||||
0x0000, 0x0000, 0x0000, 0x0000, /* 12 */
|
||||
};
|
||||
|
||||
/*
|
||||
* read tlv320aic23 register cache
|
||||
*/
|
||||
static inline unsigned int tlv320aic23_read_reg_cache(struct snd_soc_codec
|
||||
*codec, unsigned int reg)
|
||||
{
|
||||
u16 *cache = codec->reg_cache;
|
||||
if (reg >= ARRAY_SIZE(tlv320aic23_reg))
|
||||
return -1;
|
||||
return cache[reg];
|
||||
}
|
||||
|
||||
/*
|
||||
* write tlv320aic23 register cache
|
||||
*/
|
||||
static inline void tlv320aic23_write_reg_cache(struct snd_soc_codec *codec,
|
||||
u8 reg, u16 value)
|
||||
{
|
||||
u16 *cache = codec->reg_cache;
|
||||
if (reg >= ARRAY_SIZE(tlv320aic23_reg))
|
||||
return;
|
||||
cache[reg] = value;
|
||||
}
|
||||
|
||||
/*
|
||||
* write to the tlv320aic23 register space
|
||||
*/
|
||||
static int tlv320aic23_write(struct snd_soc_codec *codec, unsigned int reg,
|
||||
unsigned int value)
|
||||
{
|
||||
|
||||
u8 data;
|
||||
|
||||
/* TLV320AIC23 has 7 bit address and 9 bits of data
|
||||
* so we need to switch one data bit into reg and rest
|
||||
* of data into val
|
||||
*/
|
||||
|
||||
if ((reg < 0 || reg > 9) && (reg != 15)) {
|
||||
printk(KERN_WARNING "%s Invalid register R%d\n", __func__, reg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
data = (reg << 1) | (value >> 8 & 0x01);
|
||||
|
||||
tlv320aic23_write_reg_cache(codec, reg, value);
|
||||
|
||||
if (codec->hw_write(codec->control_data, data,
|
||||
(value & 0xff)) == 0)
|
||||
return 0;
|
||||
|
||||
printk(KERN_ERR "%s cannot write %03x to register R%d\n", __func__,
|
||||
value, reg);
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static const char *rec_src_text[] = { "Line", "Mic" };
|
||||
static const char *deemph_text[] = {"None", "32Khz", "44.1Khz", "48Khz"};
|
||||
|
||||
static const struct soc_enum rec_src_enum =
|
||||
SOC_ENUM_SINGLE(TLV320AIC23_ANLG, 2, 2, rec_src_text);
|
||||
|
||||
static const struct snd_kcontrol_new tlv320aic23_rec_src_mux_controls =
|
||||
SOC_DAPM_ENUM("Input Select", rec_src_enum);
|
||||
|
||||
static const struct soc_enum tlv320aic23_rec_src =
|
||||
SOC_ENUM_SINGLE(TLV320AIC23_ANLG, 2, 2, rec_src_text);
|
||||
static const struct soc_enum tlv320aic23_deemph =
|
||||
SOC_ENUM_SINGLE(TLV320AIC23_DIGT, 1, 4, deemph_text);
|
||||
|
||||
static const DECLARE_TLV_DB_SCALE(out_gain_tlv, -12100, 100, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(input_gain_tlv, -1725, 75, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(sidetone_vol_tlv, -1800, 300, 0);
|
||||
|
||||
static int snd_soc_tlv320aic23_put_volsw(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
u16 val, reg;
|
||||
|
||||
val = (ucontrol->value.integer.value[0] & 0x07);
|
||||
|
||||
/* linear conversion to userspace
|
||||
* 000 = -6db
|
||||
* 001 = -9db
|
||||
* 010 = -12db
|
||||
* 011 = -18db (Min)
|
||||
* 100 = 0db (Max)
|
||||
*/
|
||||
val = (val >= 4) ? 4 : (3 - val);
|
||||
|
||||
reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_ANLG) & (~0x1C0);
|
||||
tlv320aic23_write(codec, TLV320AIC23_ANLG, reg | (val << 6));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_soc_tlv320aic23_get_volsw(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
u16 val;
|
||||
|
||||
val = tlv320aic23_read_reg_cache(codec, TLV320AIC23_ANLG) & (0x1C0);
|
||||
val = val >> 6;
|
||||
val = (val >= 4) ? 4 : (3 - val);
|
||||
ucontrol->value.integer.value[0] = val;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
#define SOC_TLV320AIC23_SINGLE_TLV(xname, reg, shift, max, invert, tlv_array) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
|
||||
SNDRV_CTL_ELEM_ACCESS_READWRITE,\
|
||||
.tlv.p = (tlv_array), \
|
||||
.info = snd_soc_info_volsw, .get = snd_soc_tlv320aic23_get_volsw,\
|
||||
.put = snd_soc_tlv320aic23_put_volsw, \
|
||||
.private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) }
|
||||
|
||||
static const struct snd_kcontrol_new tlv320aic23_snd_controls[] = {
|
||||
SOC_DOUBLE_R_TLV("Digital Playback Volume", TLV320AIC23_LCHNVOL,
|
||||
TLV320AIC23_RCHNVOL, 0, 127, 0, out_gain_tlv),
|
||||
SOC_SINGLE("Digital Playback Switch", TLV320AIC23_DIGT, 3, 1, 1),
|
||||
SOC_DOUBLE_R("Line Input Switch", TLV320AIC23_LINVOL,
|
||||
TLV320AIC23_RINVOL, 7, 1, 0),
|
||||
SOC_DOUBLE_R_TLV("Line Input Volume", TLV320AIC23_LINVOL,
|
||||
TLV320AIC23_RINVOL, 0, 31, 0, input_gain_tlv),
|
||||
SOC_SINGLE("Mic Input Switch", TLV320AIC23_ANLG, 1, 1, 1),
|
||||
SOC_SINGLE("Mic Booster Switch", TLV320AIC23_ANLG, 0, 1, 0),
|
||||
SOC_TLV320AIC23_SINGLE_TLV("Sidetone Volume", TLV320AIC23_ANLG,
|
||||
6, 4, 0, sidetone_vol_tlv),
|
||||
SOC_ENUM("Playback De-emphasis", tlv320aic23_deemph),
|
||||
};
|
||||
|
||||
/* add non dapm controls */
|
||||
static int tlv320aic23_add_controls(struct snd_soc_codec *codec)
|
||||
{
|
||||
|
||||
int err, i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(tlv320aic23_snd_controls); i++) {
|
||||
err = snd_ctl_add(codec->card,
|
||||
snd_soc_cnew(&tlv320aic23_snd_controls[i],
|
||||
codec, NULL));
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/* PGA Mixer controls for Line and Mic switch */
|
||||
static const struct snd_kcontrol_new tlv320aic23_output_mixer_controls[] = {
|
||||
SOC_DAPM_SINGLE("Line Bypass Switch", TLV320AIC23_ANLG, 3, 1, 0),
|
||||
SOC_DAPM_SINGLE("Mic Sidetone Switch", TLV320AIC23_ANLG, 5, 1, 0),
|
||||
SOC_DAPM_SINGLE("Playback Switch", TLV320AIC23_ANLG, 4, 1, 0),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_DAC("DAC", "Playback", TLV320AIC23_PWR, 3, 1),
|
||||
SND_SOC_DAPM_ADC("ADC", "Capture", TLV320AIC23_PWR, 2, 1),
|
||||
SND_SOC_DAPM_MUX("Capture Source", SND_SOC_NOPM, 0, 0,
|
||||
&tlv320aic23_rec_src_mux_controls),
|
||||
SND_SOC_DAPM_MIXER("Output Mixer", TLV320AIC23_PWR, 4, 1,
|
||||
&tlv320aic23_output_mixer_controls[0],
|
||||
ARRAY_SIZE(tlv320aic23_output_mixer_controls)),
|
||||
SND_SOC_DAPM_PGA("Line Input", TLV320AIC23_PWR, 0, 1, NULL, 0),
|
||||
SND_SOC_DAPM_PGA("Mic Input", TLV320AIC23_PWR, 1, 1, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_OUTPUT("LHPOUT"),
|
||||
SND_SOC_DAPM_OUTPUT("RHPOUT"),
|
||||
SND_SOC_DAPM_OUTPUT("LOUT"),
|
||||
SND_SOC_DAPM_OUTPUT("ROUT"),
|
||||
|
||||
SND_SOC_DAPM_INPUT("LLINEIN"),
|
||||
SND_SOC_DAPM_INPUT("RLINEIN"),
|
||||
|
||||
SND_SOC_DAPM_INPUT("MICIN"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route intercon[] = {
|
||||
/* Output Mixer */
|
||||
{"Output Mixer", "Line Bypass Switch", "Line Input"},
|
||||
{"Output Mixer", "Playback Switch", "DAC"},
|
||||
{"Output Mixer", "Mic Sidetone Switch", "Mic Input"},
|
||||
|
||||
/* Outputs */
|
||||
{"RHPOUT", NULL, "Output Mixer"},
|
||||
{"LHPOUT", NULL, "Output Mixer"},
|
||||
{"LOUT", NULL, "Output Mixer"},
|
||||
{"ROUT", NULL, "Output Mixer"},
|
||||
|
||||
/* Inputs */
|
||||
{"Line Input", "NULL", "LLINEIN"},
|
||||
{"Line Input", "NULL", "RLINEIN"},
|
||||
|
||||
{"Mic Input", "NULL", "MICIN"},
|
||||
|
||||
/* input mux */
|
||||
{"Capture Source", "Line", "Line Input"},
|
||||
{"Capture Source", "Mic", "Mic Input"},
|
||||
{"ADC", NULL, "Capture Source"},
|
||||
|
||||
};
|
||||
|
||||
/* tlv320aic23 related */
|
||||
static const struct tlv320aic23_srate_reg_info srate_reg_info[] = {
|
||||
{4000, 0x06, 1}, /* 4000 */
|
||||
{8000, 0x06, 0}, /* 8000 */
|
||||
{16000, 0x0C, 1}, /* 16000 */
|
||||
{22050, 0x11, 1}, /* 22050 */
|
||||
{24000, 0x00, 1}, /* 24000 */
|
||||
{32000, 0x0C, 0}, /* 32000 */
|
||||
{44100, 0x11, 0}, /* 44100 */
|
||||
{48000, 0x00, 0}, /* 48000 */
|
||||
{88200, 0x1F, 0}, /* 88200 */
|
||||
{96000, 0x0E, 0}, /* 96000 */
|
||||
};
|
||||
|
||||
static int tlv320aic23_add_widgets(struct snd_soc_codec *codec)
|
||||
{
|
||||
snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets,
|
||||
ARRAY_SIZE(tlv320aic23_dapm_widgets));
|
||||
|
||||
/* set up audio path interconnects */
|
||||
snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
|
||||
|
||||
snd_soc_dapm_new_widgets(codec);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tlv320aic23_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_device *socdev = rtd->socdev;
|
||||
struct snd_soc_codec *codec = socdev->codec;
|
||||
u16 iface_reg, data;
|
||||
u8 count = 0;
|
||||
|
||||
iface_reg =
|
||||
tlv320aic23_read_reg_cache(codec,
|
||||
TLV320AIC23_DIGT_FMT) & ~(0x03 << 2);
|
||||
|
||||
/* Search for the right sample rate */
|
||||
/* Verify what happens if the rate is not supported
|
||||
* now it goes to 96Khz */
|
||||
while ((srate_reg_info[count].sample_rate != params_rate(params)) &&
|
||||
(count < ARRAY_SIZE(srate_reg_info))) {
|
||||
count++;
|
||||
}
|
||||
|
||||
data = (srate_reg_info[count].divider << TLV320AIC23_CLKIN_SHIFT) |
|
||||
(srate_reg_info[count]. control << TLV320AIC23_BOSR_SHIFT) |
|
||||
TLV320AIC23_USB_CLK_ON;
|
||||
|
||||
tlv320aic23_write(codec, TLV320AIC23_SRATE, data);
|
||||
|
||||
switch (params_format(params)) {
|
||||
case SNDRV_PCM_FORMAT_S16_LE:
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S20_3LE:
|
||||
iface_reg |= (0x01 << 2);
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S24_LE:
|
||||
iface_reg |= (0x02 << 2);
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S32_LE:
|
||||
iface_reg |= (0x03 << 2);
|
||||
break;
|
||||
}
|
||||
tlv320aic23_write(codec, TLV320AIC23_DIGT_FMT, iface_reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tlv320aic23_pcm_prepare(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->codec;
|
||||
|
||||
/* set active */
|
||||
tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0001);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tlv320aic23_shutdown(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->codec;
|
||||
|
||||
/* deactivate */
|
||||
if (!codec->active) {
|
||||
udelay(50);
|
||||
tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0);
|
||||
}
|
||||
}
|
||||
|
||||
static int tlv320aic23_mute(struct snd_soc_dai *dai, int mute)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
u16 reg;
|
||||
|
||||
reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_DIGT);
|
||||
if (mute)
|
||||
reg |= TLV320AIC23_DACM_MUTE;
|
||||
|
||||
else
|
||||
reg &= ~TLV320AIC23_DACM_MUTE;
|
||||
|
||||
tlv320aic23_write(codec, TLV320AIC23_DIGT, reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tlv320aic23_set_dai_fmt(struct snd_soc_dai *codec_dai,
|
||||
unsigned int fmt)
|
||||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
u16 iface_reg;
|
||||
|
||||
iface_reg =
|
||||
tlv320aic23_read_reg_cache(codec, TLV320AIC23_DIGT_FMT) & (~0x03);
|
||||
|
||||
/* set master/slave audio interface */
|
||||
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
|
||||
case SND_SOC_DAIFMT_CBM_CFM:
|
||||
iface_reg |= TLV320AIC23_MS_MASTER;
|
||||
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_reg |= TLV320AIC23_FOR_I2S;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_DSP_A:
|
||||
iface_reg |= TLV320AIC23_FOR_DSP;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_RIGHT_J:
|
||||
break;
|
||||
case SND_SOC_DAIFMT_LEFT_J:
|
||||
iface_reg |= TLV320AIC23_FOR_LJUST;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
||||
}
|
||||
|
||||
tlv320aic23_write(codec, TLV320AIC23_DIGT_FMT, iface_reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tlv320aic23_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;
|
||||
|
||||
switch (freq) {
|
||||
case 12000000:
|
||||
return 0;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int tlv320aic23_set_bias_level(struct snd_soc_codec *codec,
|
||||
enum snd_soc_bias_level level)
|
||||
{
|
||||
u16 reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_PWR) & 0xff7f;
|
||||
|
||||
switch (level) {
|
||||
case SND_SOC_BIAS_ON:
|
||||
/* vref/mid, osc on, dac unmute */
|
||||
tlv320aic23_write(codec, TLV320AIC23_PWR, reg);
|
||||
break;
|
||||
case SND_SOC_BIAS_PREPARE:
|
||||
break;
|
||||
case SND_SOC_BIAS_STANDBY:
|
||||
/* everything off except vref/vmid, */
|
||||
tlv320aic23_write(codec, TLV320AIC23_PWR, reg | 0x0040);
|
||||
break;
|
||||
case SND_SOC_BIAS_OFF:
|
||||
/* everything off, dac mute, inactive */
|
||||
tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0);
|
||||
tlv320aic23_write(codec, TLV320AIC23_PWR, 0xffff);
|
||||
break;
|
||||
}
|
||||
codec->bias_level = level;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define AIC23_RATES SNDRV_PCM_RATE_8000_96000
|
||||
#define AIC23_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
|
||||
SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
|
||||
|
||||
struct snd_soc_dai tlv320aic23_dai = {
|
||||
.name = "tlv320aic23",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.rates = AIC23_RATES,
|
||||
.formats = AIC23_FORMATS,},
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.rates = AIC23_RATES,
|
||||
.formats = AIC23_FORMATS,},
|
||||
.ops = {
|
||||
.prepare = tlv320aic23_pcm_prepare,
|
||||
.hw_params = tlv320aic23_hw_params,
|
||||
.shutdown = tlv320aic23_shutdown,
|
||||
},
|
||||
.dai_ops = {
|
||||
.digital_mute = tlv320aic23_mute,
|
||||
.set_fmt = tlv320aic23_set_dai_fmt,
|
||||
.set_sysclk = tlv320aic23_set_dai_sysclk,
|
||||
}
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(tlv320aic23_dai);
|
||||
|
||||
static int tlv320aic23_suspend(struct platform_device *pdev,
|
||||
pm_message_t state)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->codec;
|
||||
|
||||
tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0);
|
||||
tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tlv320aic23_resume(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->codec;
|
||||
int i;
|
||||
u16 reg;
|
||||
|
||||
/* Sync reg_cache with the hardware */
|
||||
for (reg = 0; reg < ARRAY_SIZE(tlv320aic23_reg); i++) {
|
||||
u16 val = tlv320aic23_read_reg_cache(codec, reg);
|
||||
tlv320aic23_write(codec, reg, val);
|
||||
}
|
||||
|
||||
tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
tlv320aic23_set_bias_level(codec, codec->suspend_bias_level);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* initialise the AIC23 driver
|
||||
* register the mixer and dsp interfaces with the kernel
|
||||
*/
|
||||
static int tlv320aic23_init(struct snd_soc_device *socdev)
|
||||
{
|
||||
struct snd_soc_codec *codec = socdev->codec;
|
||||
int ret = 0;
|
||||
u16 reg;
|
||||
|
||||
codec->name = "tlv320aic23";
|
||||
codec->owner = THIS_MODULE;
|
||||
codec->read = tlv320aic23_read_reg_cache;
|
||||
codec->write = tlv320aic23_write;
|
||||
codec->set_bias_level = tlv320aic23_set_bias_level;
|
||||
codec->dai = &tlv320aic23_dai;
|
||||
codec->num_dai = 1;
|
||||
codec->reg_cache_size = ARRAY_SIZE(tlv320aic23_reg);
|
||||
codec->reg_cache =
|
||||
kmemdup(tlv320aic23_reg, sizeof(tlv320aic23_reg), GFP_KERNEL);
|
||||
if (codec->reg_cache == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Reset codec */
|
||||
tlv320aic23_write(codec, TLV320AIC23_RESET, 0);
|
||||
|
||||
/* register pcms */
|
||||
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
|
||||
if (ret < 0) {
|
||||
printk(KERN_ERR "tlv320aic23: failed to create pcms\n");
|
||||
goto pcm_err;
|
||||
}
|
||||
|
||||
/* power on device */
|
||||
tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
|
||||
tlv320aic23_write(codec, TLV320AIC23_DIGT, TLV320AIC23_DEEMP_44K);
|
||||
|
||||
/* Unmute input */
|
||||
reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_LINVOL);
|
||||
tlv320aic23_write(codec, TLV320AIC23_LINVOL,
|
||||
(reg & (~TLV320AIC23_LIM_MUTED)) |
|
||||
(TLV320AIC23_LRS_ENABLED));
|
||||
|
||||
reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_RINVOL);
|
||||
tlv320aic23_write(codec, TLV320AIC23_RINVOL,
|
||||
(reg & (~TLV320AIC23_LIM_MUTED)) |
|
||||
TLV320AIC23_LRS_ENABLED);
|
||||
|
||||
reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_ANLG);
|
||||
tlv320aic23_write(codec, TLV320AIC23_ANLG,
|
||||
(reg) & (~TLV320AIC23_BYPASS_ON) &
|
||||
(~TLV320AIC23_MICM_MUTED));
|
||||
|
||||
/* Default output volume */
|
||||
tlv320aic23_write(codec, TLV320AIC23_LCHNVOL,
|
||||
TLV320AIC23_DEFAULT_OUT_VOL &
|
||||
TLV320AIC23_OUT_VOL_MASK);
|
||||
tlv320aic23_write(codec, TLV320AIC23_RCHNVOL,
|
||||
TLV320AIC23_DEFAULT_OUT_VOL &
|
||||
TLV320AIC23_OUT_VOL_MASK);
|
||||
|
||||
tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x1);
|
||||
|
||||
tlv320aic23_add_controls(codec);
|
||||
tlv320aic23_add_widgets(codec);
|
||||
ret = snd_soc_register_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;
|
||||
}
|
||||
static struct snd_soc_device *tlv320aic23_socdev;
|
||||
|
||||
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
|
||||
/*
|
||||
* If the i2c layer weren't so broken, we could pass this kind of data
|
||||
* around
|
||||
*/
|
||||
static int tlv320aic23_codec_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *i2c_id)
|
||||
{
|
||||
struct snd_soc_device *socdev = tlv320aic23_socdev;
|
||||
struct snd_soc_codec *codec = socdev->codec;
|
||||
int ret;
|
||||
|
||||
if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
return -EINVAL;
|
||||
|
||||
i2c_set_clientdata(i2c, codec);
|
||||
codec->control_data = i2c;
|
||||
|
||||
ret = tlv320aic23_init(socdev);
|
||||
if (ret < 0) {
|
||||
printk(KERN_ERR "tlv320aic23: failed to initialise AIC23\n");
|
||||
goto err;
|
||||
}
|
||||
return ret;
|
||||
|
||||
err:
|
||||
kfree(codec);
|
||||
kfree(i2c);
|
||||
return ret;
|
||||
}
|
||||
static int __exit tlv320aic23_i2c_remove(struct i2c_client *i2c)
|
||||
{
|
||||
put_device(&i2c->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id tlv320aic23_id[] = {
|
||||
{"tlv320aic23", 0},
|
||||
{}
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(i2c, tlv320aic23_id);
|
||||
|
||||
static struct i2c_driver tlv320aic23_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "tlv320aic23",
|
||||
},
|
||||
.probe = tlv320aic23_codec_probe,
|
||||
.remove = __exit_p(tlv320aic23_i2c_remove),
|
||||
.id_table = tlv320aic23_id,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
static int tlv320aic23_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec;
|
||||
int ret = 0;
|
||||
|
||||
printk(KERN_INFO "AIC23 Audio Codec %s\n", AIC23_VERSION);
|
||||
|
||||
codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
|
||||
if (codec == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
socdev->codec = codec;
|
||||
mutex_init(&codec->mutex);
|
||||
INIT_LIST_HEAD(&codec->dapm_widgets);
|
||||
INIT_LIST_HEAD(&codec->dapm_paths);
|
||||
|
||||
tlv320aic23_socdev = socdev;
|
||||
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
|
||||
codec->hw_write = (hw_write_t) i2c_smbus_write_byte_data;
|
||||
codec->hw_read = NULL;
|
||||
ret = i2c_add_driver(&tlv320aic23_i2c_driver);
|
||||
if (ret != 0)
|
||||
printk(KERN_ERR "can't add i2c driver");
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tlv320aic23_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->codec;
|
||||
|
||||
if (codec->control_data)
|
||||
tlv320aic23_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(&tlv320aic23_i2c_driver);
|
||||
#endif
|
||||
kfree(codec->reg_cache);
|
||||
kfree(codec);
|
||||
|
||||
return 0;
|
||||
}
|
||||
struct snd_soc_codec_device soc_codec_dev_tlv320aic23 = {
|
||||
.probe = tlv320aic23_probe,
|
||||
.remove = tlv320aic23_remove,
|
||||
.suspend = tlv320aic23_suspend,
|
||||
.resume = tlv320aic23_resume,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(soc_codec_dev_tlv320aic23);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC TLV320AIC23 codec driver");
|
||||
MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>");
|
||||
MODULE_LICENSE("GPL");
|
122
sound/soc/codecs/tlv320aic23.h
Normal file
122
sound/soc/codecs/tlv320aic23.h
Normal file
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* ALSA SoC TLV320AIC23 codec driver
|
||||
*
|
||||
* Author: Arun KS, <arunks@mistralsolutions.com>
|
||||
* Copyright: (C) 2008 Mistral Solutions Pvt Ltd
|
||||
*
|
||||
* 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 _TLV320AIC23_H
|
||||
#define _TLV320AIC23_H
|
||||
|
||||
/* Codec TLV320AIC23 */
|
||||
#define TLV320AIC23_LINVOL 0x00
|
||||
#define TLV320AIC23_RINVOL 0x01
|
||||
#define TLV320AIC23_LCHNVOL 0x02
|
||||
#define TLV320AIC23_RCHNVOL 0x03
|
||||
#define TLV320AIC23_ANLG 0x04
|
||||
#define TLV320AIC23_DIGT 0x05
|
||||
#define TLV320AIC23_PWR 0x06
|
||||
#define TLV320AIC23_DIGT_FMT 0x07
|
||||
#define TLV320AIC23_SRATE 0x08
|
||||
#define TLV320AIC23_ACTIVE 0x09
|
||||
#define TLV320AIC23_RESET 0x0F
|
||||
|
||||
/* Left (right) line input volume control register */
|
||||
#define TLV320AIC23_LRS_ENABLED 0x0100
|
||||
#define TLV320AIC23_LIM_MUTED 0x0080
|
||||
#define TLV320AIC23_LIV_DEFAULT 0x0017
|
||||
#define TLV320AIC23_LIV_MAX 0x001f
|
||||
#define TLV320AIC23_LIV_MIN 0x0000
|
||||
|
||||
/* Left (right) channel headphone volume control register */
|
||||
#define TLV320AIC23_LZC_ON 0x0080
|
||||
#define TLV320AIC23_LHV_DEFAULT 0x0079
|
||||
#define TLV320AIC23_LHV_MAX 0x007f
|
||||
#define TLV320AIC23_LHV_MIN 0x0000
|
||||
|
||||
/* Analog audio path control register */
|
||||
#define TLV320AIC23_STA_REG(x) ((x)<<6)
|
||||
#define TLV320AIC23_STE_ENABLED 0x0020
|
||||
#define TLV320AIC23_DAC_SELECTED 0x0010
|
||||
#define TLV320AIC23_BYPASS_ON 0x0008
|
||||
#define TLV320AIC23_INSEL_MIC 0x0004
|
||||
#define TLV320AIC23_MICM_MUTED 0x0002
|
||||
#define TLV320AIC23_MICB_20DB 0x0001
|
||||
|
||||
/* Digital audio path control register */
|
||||
#define TLV320AIC23_DACM_MUTE 0x0008
|
||||
#define TLV320AIC23_DEEMP_32K 0x0002
|
||||
#define TLV320AIC23_DEEMP_44K 0x0004
|
||||
#define TLV320AIC23_DEEMP_48K 0x0006
|
||||
#define TLV320AIC23_ADCHP_ON 0x0001
|
||||
|
||||
/* Power control down register */
|
||||
#define TLV320AIC23_DEVICE_PWR_OFF 0x0080
|
||||
#define TLV320AIC23_CLK_OFF 0x0040
|
||||
#define TLV320AIC23_OSC_OFF 0x0020
|
||||
#define TLV320AIC23_OUT_OFF 0x0010
|
||||
#define TLV320AIC23_DAC_OFF 0x0008
|
||||
#define TLV320AIC23_ADC_OFF 0x0004
|
||||
#define TLV320AIC23_MIC_OFF 0x0002
|
||||
#define TLV320AIC23_LINE_OFF 0x0001
|
||||
|
||||
/* Digital audio interface register */
|
||||
#define TLV320AIC23_MS_MASTER 0x0040
|
||||
#define TLV320AIC23_LRSWAP_ON 0x0020
|
||||
#define TLV320AIC23_LRP_ON 0x0010
|
||||
#define TLV320AIC23_IWL_16 0x0000
|
||||
#define TLV320AIC23_IWL_20 0x0004
|
||||
#define TLV320AIC23_IWL_24 0x0008
|
||||
#define TLV320AIC23_IWL_32 0x000C
|
||||
#define TLV320AIC23_FOR_I2S 0x0002
|
||||
#define TLV320AIC23_FOR_DSP 0x0003
|
||||
#define TLV320AIC23_FOR_LJUST 0x0001
|
||||
|
||||
/* Sample rate control register */
|
||||
#define TLV320AIC23_CLKOUT_HALF 0x0080
|
||||
#define TLV320AIC23_CLKIN_HALF 0x0040
|
||||
#define TLV320AIC23_BOSR_384fs 0x0002 /* BOSR_272fs in USB mode */
|
||||
#define TLV320AIC23_USB_CLK_ON 0x0001
|
||||
#define TLV320AIC23_SR_MASK 0xf
|
||||
#define TLV320AIC23_CLKOUT_SHIFT 7
|
||||
#define TLV320AIC23_CLKIN_SHIFT 6
|
||||
#define TLV320AIC23_SR_SHIFT 2
|
||||
#define TLV320AIC23_BOSR_SHIFT 1
|
||||
|
||||
/* Digital interface register */
|
||||
#define TLV320AIC23_ACT_ON 0x0001
|
||||
|
||||
/*
|
||||
* AUDIO related MACROS
|
||||
*/
|
||||
|
||||
#define TLV320AIC23_DEFAULT_OUT_VOL 0x70
|
||||
#define TLV320AIC23_DEFAULT_IN_VOLUME 0x10
|
||||
|
||||
#define TLV320AIC23_OUT_VOL_MIN TLV320AIC23_LHV_MIN
|
||||
#define TLV320AIC23_OUT_VOL_MAX TLV320AIC23_LHV_MAX
|
||||
#define TLV320AIC23_OUT_VO_RANGE (TLV320AIC23_OUT_VOL_MAX - \
|
||||
TLV320AIC23_OUT_VOL_MIN)
|
||||
#define TLV320AIC23_OUT_VOL_MASK TLV320AIC23_OUT_VOL_MAX
|
||||
|
||||
#define TLV320AIC23_IN_VOL_MIN TLV320AIC23_LIV_MIN
|
||||
#define TLV320AIC23_IN_VOL_MAX TLV320AIC23_LIV_MAX
|
||||
#define TLV320AIC23_IN_VOL_RANGE (TLV320AIC23_IN_VOL_MAX - \
|
||||
TLV320AIC23_IN_VOL_MIN)
|
||||
#define TLV320AIC23_IN_VOL_MASK TLV320AIC23_IN_VOL_MAX
|
||||
|
||||
#define TLV320AIC23_SIDETONE_MASK 0x1c0
|
||||
#define TLV320AIC23_SIDETONE_0 0x100
|
||||
#define TLV320AIC23_SIDETONE_6 0x000
|
||||
#define TLV320AIC23_SIDETONE_9 0x040
|
||||
#define TLV320AIC23_SIDETONE_12 0x080
|
||||
#define TLV320AIC23_SIDETONE_18 0x0c0
|
||||
|
||||
extern struct snd_soc_dai tlv320aic23_dai;
|
||||
extern struct snd_soc_codec_device soc_codec_dev_tlv320aic23;
|
||||
|
||||
#endif /* _TLV320AIC23_H */
|
|
@ -48,7 +48,6 @@
|
|||
|
||||
#include "tlv320aic3x.h"
|
||||
|
||||
#define AUDIO_NAME "aic3x"
|
||||
#define AIC3X_VERSION "0.2"
|
||||
|
||||
/* codec private data */
|
||||
|
@ -991,7 +990,7 @@ EXPORT_SYMBOL_GPL(aic3x_headset_detected);
|
|||
SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
|
||||
|
||||
struct snd_soc_dai aic3x_dai = {
|
||||
.name = "aic3x",
|
||||
.name = "tlv320aic3x",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 1,
|
||||
|
@ -1055,7 +1054,7 @@ static int aic3x_init(struct snd_soc_device *socdev)
|
|||
struct aic3x_setup_data *setup = socdev->codec_data;
|
||||
int reg, ret = 0;
|
||||
|
||||
codec->name = "aic3x";
|
||||
codec->name = "tlv320aic3x";
|
||||
codec->owner = THIS_MODULE;
|
||||
codec->read = aic3x_read_reg_cache;
|
||||
codec->write = aic3x_write;
|
||||
|
|
|
@ -36,7 +36,6 @@
|
|||
#include "uda1380.h"
|
||||
|
||||
#define UDA1380_VERSION "0.6"
|
||||
#define AUDIO_NAME "uda1380"
|
||||
|
||||
/*
|
||||
* uda1380 register cache
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* Copyright 2006 Wolfson Microelectronics PLC.
|
||||
*
|
||||
* Author: Liam Girdwood <liam.girdwood@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 version 2 as
|
||||
|
@ -18,6 +18,7 @@
|
|||
#include <linux/pm.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
|
@ -27,7 +28,6 @@
|
|||
|
||||
#include "wm8510.h"
|
||||
|
||||
#define AUDIO_NAME "wm8510"
|
||||
#define WM8510_VERSION "0.6"
|
||||
|
||||
struct snd_soc_codec_device soc_codec_dev_wm8510;
|
||||
|
@ -55,6 +55,9 @@ static const u16 wm8510_reg[WM8510_CACHEREGNUM] = {
|
|||
0x0001,
|
||||
};
|
||||
|
||||
#define WM8510_POWER1_BIASEN 0x08
|
||||
#define WM8510_POWER1_BUFIOEN 0x10
|
||||
|
||||
/*
|
||||
* read wm8510 register cache
|
||||
*/
|
||||
|
@ -224,9 +227,9 @@ SND_SOC_DAPM_PGA("SpkN Out", WM8510_POWER3, 5, 0, NULL, 0),
|
|||
SND_SOC_DAPM_PGA("SpkP Out", WM8510_POWER3, 6, 0, NULL, 0),
|
||||
SND_SOC_DAPM_PGA("Mono Out", WM8510_POWER3, 7, 0, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_PGA("Mic PGA", WM8510_POWER2, 2, 0,
|
||||
&wm8510_micpga_controls[0],
|
||||
ARRAY_SIZE(wm8510_micpga_controls)),
|
||||
SND_SOC_DAPM_MIXER("Mic PGA", WM8510_POWER2, 2, 0,
|
||||
&wm8510_micpga_controls[0],
|
||||
ARRAY_SIZE(wm8510_micpga_controls)),
|
||||
SND_SOC_DAPM_MIXER("Boost Mixer", WM8510_POWER2, 4, 0,
|
||||
&wm8510_boost_controls[0],
|
||||
ARRAY_SIZE(wm8510_boost_controls)),
|
||||
|
@ -526,23 +529,35 @@ static int wm8510_mute(struct snd_soc_dai *dai, int mute)
|
|||
static int wm8510_set_bias_level(struct snd_soc_codec *codec,
|
||||
enum snd_soc_bias_level level)
|
||||
{
|
||||
u16 power1 = wm8510_read_reg_cache(codec, WM8510_POWER1) & ~0x3;
|
||||
|
||||
switch (level) {
|
||||
case SND_SOC_BIAS_ON:
|
||||
wm8510_write(codec, WM8510_POWER1, 0x1ff);
|
||||
wm8510_write(codec, WM8510_POWER2, 0x1ff);
|
||||
wm8510_write(codec, WM8510_POWER3, 0x1ff);
|
||||
break;
|
||||
case SND_SOC_BIAS_PREPARE:
|
||||
case SND_SOC_BIAS_STANDBY:
|
||||
power1 |= 0x1; /* VMID 50k */
|
||||
wm8510_write(codec, WM8510_POWER1, power1);
|
||||
break;
|
||||
|
||||
case SND_SOC_BIAS_STANDBY:
|
||||
power1 |= WM8510_POWER1_BIASEN | WM8510_POWER1_BUFIOEN;
|
||||
|
||||
if (codec->bias_level == SND_SOC_BIAS_OFF) {
|
||||
/* Initial cap charge at VMID 5k */
|
||||
wm8510_write(codec, WM8510_POWER1, power1 | 0x3);
|
||||
mdelay(100);
|
||||
}
|
||||
|
||||
power1 |= 0x2; /* VMID 500k */
|
||||
wm8510_write(codec, WM8510_POWER1, power1);
|
||||
break;
|
||||
|
||||
case SND_SOC_BIAS_OFF:
|
||||
/* everything off, dac mute, inactive */
|
||||
wm8510_write(codec, WM8510_POWER1, 0x0);
|
||||
wm8510_write(codec, WM8510_POWER2, 0x0);
|
||||
wm8510_write(codec, WM8510_POWER3, 0x0);
|
||||
wm8510_write(codec, WM8510_POWER1, 0);
|
||||
wm8510_write(codec, WM8510_POWER2, 0);
|
||||
wm8510_write(codec, WM8510_POWER3, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
codec->bias_level = level;
|
||||
return 0;
|
||||
}
|
||||
|
@ -640,6 +655,7 @@ static int wm8510_init(struct snd_soc_device *socdev)
|
|||
}
|
||||
|
||||
/* power on device */
|
||||
codec->bias_level = SND_SOC_BIAS_OFF;
|
||||
wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
wm8510_add_controls(codec);
|
||||
wm8510_add_widgets(codec);
|
||||
|
@ -747,6 +763,62 @@ err_driver:
|
|||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SPI_MASTER)
|
||||
static int __devinit wm8510_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
struct snd_soc_device *socdev = wm8510_socdev;
|
||||
struct snd_soc_codec *codec = socdev->codec;
|
||||
int ret;
|
||||
|
||||
codec->control_data = spi;
|
||||
|
||||
ret = wm8510_init(socdev);
|
||||
if (ret < 0)
|
||||
dev_err(&spi->dev, "failed to initialise WM8510\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit wm8510_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct spi_driver wm8510_spi_driver = {
|
||||
.driver = {
|
||||
.name = "wm8510",
|
||||
.bus = &spi_bus_type,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = wm8510_spi_probe,
|
||||
.remove = __devexit_p(wm8510_spi_remove),
|
||||
};
|
||||
|
||||
static int wm8510_spi_write(struct spi_device *spi, const char *data, int len)
|
||||
{
|
||||
struct spi_transfer t;
|
||||
struct spi_message m;
|
||||
u8 msg[2];
|
||||
|
||||
if (len <= 0)
|
||||
return 0;
|
||||
|
||||
msg[0] = data[0];
|
||||
msg[1] = data[1];
|
||||
|
||||
spi_message_init(&m);
|
||||
memset(&t, 0, (sizeof t));
|
||||
|
||||
t.tx_buf = &msg[0];
|
||||
t.len = len;
|
||||
|
||||
spi_message_add_tail(&t, &m);
|
||||
spi_sync(spi, &m);
|
||||
|
||||
return len;
|
||||
}
|
||||
#endif /* CONFIG_SPI_MASTER */
|
||||
|
||||
static int wm8510_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
|
@ -772,8 +844,14 @@ static int wm8510_probe(struct platform_device *pdev)
|
|||
codec->hw_write = (hw_write_t)i2c_master_send;
|
||||
ret = wm8510_add_i2c_device(pdev, setup);
|
||||
}
|
||||
#else
|
||||
/* Add other interfaces here */
|
||||
#endif
|
||||
#if defined(CONFIG_SPI_MASTER)
|
||||
if (setup->spi) {
|
||||
codec->hw_write = (hw_write_t)wm8510_spi_write;
|
||||
ret = spi_register_driver(&wm8510_spi_driver);
|
||||
if (ret != 0)
|
||||
printk(KERN_ERR "can't add spi driver");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ret != 0)
|
||||
|
@ -795,6 +873,9 @@ static int wm8510_remove(struct platform_device *pdev)
|
|||
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
|
||||
i2c_unregister_device(codec->control_data);
|
||||
i2c_del_driver(&wm8510_i2c_driver);
|
||||
#endif
|
||||
#if defined(CONFIG_SPI_MASTER)
|
||||
spi_unregister_driver(&wm8510_spi_driver);
|
||||
#endif
|
||||
kfree(codec);
|
||||
|
||||
|
|
|
@ -94,6 +94,7 @@
|
|||
#define WM8510_MCLKDIV_12 (7 << 5)
|
||||
|
||||
struct wm8510_setup_data {
|
||||
int spi;
|
||||
int i2c_bus;
|
||||
unsigned short i2c_address;
|
||||
};
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
|
@ -36,7 +35,6 @@
|
|||
|
||||
#include "wm8580.h"
|
||||
|
||||
#define AUDIO_NAME "wm8580"
|
||||
#define WM8580_VERSION "0.1"
|
||||
|
||||
struct pll_state {
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
|
||||
#include "wm8731.h"
|
||||
|
||||
#define AUDIO_NAME "wm8731"
|
||||
#define WM8731_VERSION "0.13"
|
||||
|
||||
struct snd_soc_codec_device soc_codec_dev_wm8731;
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
|
||||
#include "wm8750.h"
|
||||
|
||||
#define AUDIO_NAME "WM8750"
|
||||
#define WM8750_VERSION "0.12"
|
||||
|
||||
/* codec private data */
|
||||
|
|
|
@ -2,8 +2,7 @@
|
|||
* wm8753.c -- WM8753 ALSA Soc Audio driver
|
||||
*
|
||||
* Copyright 2003 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
|
||||
|
@ -40,6 +39,7 @@
|
|||
#include <linux/pm.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
|
@ -51,7 +51,6 @@
|
|||
|
||||
#include "wm8753.h"
|
||||
|
||||
#define AUDIO_NAME "wm8753"
|
||||
#define WM8753_VERSION "0.16"
|
||||
|
||||
static int caps_charge = 2000;
|
||||
|
@ -1719,6 +1718,63 @@ err_driver:
|
|||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SPI_MASTER)
|
||||
static int __devinit wm8753_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
struct snd_soc_device *socdev = wm8753_socdev;
|
||||
struct snd_soc_codec *codec = socdev->codec;
|
||||
int ret;
|
||||
|
||||
codec->control_data = spi;
|
||||
|
||||
ret = wm8753_init(socdev);
|
||||
if (ret < 0)
|
||||
dev_err(&spi->dev, "failed to initialise WM8753\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit wm8753_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct spi_driver wm8753_spi_driver = {
|
||||
.driver = {
|
||||
.name = "wm8753",
|
||||
.bus = &spi_bus_type,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = wm8753_spi_probe,
|
||||
.remove = __devexit_p(wm8753_spi_remove),
|
||||
};
|
||||
|
||||
static int wm8753_spi_write(struct spi_device *spi, const char *data, int len)
|
||||
{
|
||||
struct spi_transfer t;
|
||||
struct spi_message m;
|
||||
u8 msg[2];
|
||||
|
||||
if (len <= 0)
|
||||
return 0;
|
||||
|
||||
msg[0] = data[0];
|
||||
msg[1] = data[1];
|
||||
|
||||
spi_message_init(&m);
|
||||
memset(&t, 0, (sizeof t));
|
||||
|
||||
t.tx_buf = &msg[0];
|
||||
t.len = len;
|
||||
|
||||
spi_message_add_tail(&t, &m);
|
||||
spi_sync(spi, &m);
|
||||
|
||||
return len;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static int wm8753_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
|
@ -1753,8 +1809,14 @@ static int wm8753_probe(struct platform_device *pdev)
|
|||
codec->hw_write = (hw_write_t)i2c_master_send;
|
||||
ret = wm8753_add_i2c_device(pdev, setup);
|
||||
}
|
||||
#else
|
||||
/* Add other interfaces here */
|
||||
#endif
|
||||
#if defined(CONFIG_SPI_MASTER)
|
||||
if (setup->spi) {
|
||||
codec->hw_write = (hw_write_t)wm8753_spi_write;
|
||||
ret = spi_register_driver(&wm8753_spi_driver);
|
||||
if (ret != 0)
|
||||
printk(KERN_ERR "can't add spi driver");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ret != 0) {
|
||||
|
@ -1797,6 +1859,9 @@ static int wm8753_remove(struct platform_device *pdev)
|
|||
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
|
||||
i2c_unregister_device(codec->control_data);
|
||||
i2c_del_driver(&wm8753_i2c_driver);
|
||||
#endif
|
||||
#if defined(CONFIG_SPI_MASTER)
|
||||
spi_unregister_driver(&wm8753_spi_driver);
|
||||
#endif
|
||||
kfree(codec->private_data);
|
||||
kfree(codec);
|
||||
|
|
|
@ -2,8 +2,7 @@
|
|||
* wm8753.h -- audio driver for WM8753
|
||||
*
|
||||
* Copyright 2003 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
|
||||
|
@ -79,6 +78,7 @@
|
|||
#define WM8753_ADCTL2 0x3f
|
||||
|
||||
struct wm8753_setup_data {
|
||||
int spi;
|
||||
int i2c_bus;
|
||||
unsigned short i2c_address;
|
||||
};
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
|
|
|
@ -653,14 +653,14 @@ static const struct snd_kcontrol_new wm8903_snd_controls[] = {
|
|||
|
||||
/* Input PGAs - No TLV since the scale depends on PGA mode */
|
||||
SOC_SINGLE("Left Input PGA Switch", WM8903_ANALOGUE_LEFT_INPUT_0,
|
||||
7, 1, 0),
|
||||
7, 1, 1),
|
||||
SOC_SINGLE("Left Input PGA Volume", WM8903_ANALOGUE_LEFT_INPUT_0,
|
||||
0, 31, 0),
|
||||
SOC_SINGLE("Left Input PGA Common Mode Switch", WM8903_ANALOGUE_LEFT_INPUT_1,
|
||||
6, 1, 0),
|
||||
|
||||
SOC_SINGLE("Right Input PGA Switch", WM8903_ANALOGUE_RIGHT_INPUT_0,
|
||||
7, 1, 0),
|
||||
7, 1, 1),
|
||||
SOC_SINGLE("Right Input PGA Volume", WM8903_ANALOGUE_RIGHT_INPUT_0,
|
||||
0, 31, 0),
|
||||
SOC_SINGLE("Right Input PGA Common Mode Switch", WM8903_ANALOGUE_RIGHT_INPUT_1,
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
|
||||
#include "wm8971.h"
|
||||
|
||||
#define AUDIO_NAME "wm8971"
|
||||
#define WM8971_VERSION "0.9"
|
||||
|
||||
#define WM8971_REG_COUNT 43
|
||||
|
|
|
@ -30,7 +30,6 @@
|
|||
|
||||
#include "wm8990.h"
|
||||
|
||||
#define AUDIO_NAME "wm8990"
|
||||
#define WM8990_VERSION "0.2"
|
||||
|
||||
/* codec private data */
|
||||
|
|
|
@ -2,8 +2,7 @@
|
|||
* wm9712.c -- ALSA Soc WM9712 codec support
|
||||
*
|
||||
* Copyright 2006 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
|
||||
|
|
|
@ -2,8 +2,7 @@
|
|||
* wm9713.c -- ALSA Soc WM9713 codec support
|
||||
*
|
||||
* Copyright 2006 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,3 +13,11 @@ config SND_OMAP_SOC_N810
|
|||
select SND_SOC_TLV320AIC3X
|
||||
help
|
||||
Say Y if you want to add support for SoC audio on Nokia N810.
|
||||
|
||||
config SND_OMAP_SOC_OSK5912
|
||||
tristate "SoC Audio support for omap osk5912"
|
||||
depends on SND_OMAP_SOC && MACH_OMAP_OSK
|
||||
select SND_OMAP_SOC_MCBSP
|
||||
select SND_SOC_TLV320AIC23
|
||||
help
|
||||
Say Y if you want to add support for SoC audio on osk5912.
|
||||
|
|
|
@ -7,5 +7,7 @@ obj-$(CONFIG_SND_OMAP_SOC_MCBSP) += snd-soc-omap-mcbsp.o
|
|||
|
||||
# OMAP Machine Support
|
||||
snd-soc-n810-objs := n810.o
|
||||
snd-soc-osk5912-objs := osk5912.o
|
||||
|
||||
obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o
|
||||
obj-$(CONFIG_SND_OMAP_SOC_OSK5912) += snd-soc-osk5912.o
|
||||
|
|
|
@ -247,9 +247,9 @@ static int n810_aic33_init(struct snd_soc_codec *codec)
|
|||
int i, err;
|
||||
|
||||
/* Not connected */
|
||||
snd_soc_dapm_disable_pin(codec, "MONO_LOUT");
|
||||
snd_soc_dapm_disable_pin(codec, "HPLCOM");
|
||||
snd_soc_dapm_disable_pin(codec, "HPRCOM");
|
||||
snd_soc_dapm_nc_pin(codec, "MONO_LOUT");
|
||||
snd_soc_dapm_nc_pin(codec, "HPLCOM");
|
||||
snd_soc_dapm_nc_pin(codec, "HPRCOM");
|
||||
|
||||
/* Add N810 specific controls */
|
||||
for (i = 0; i < ARRAY_SIZE(aic33_n810_controls); i++) {
|
||||
|
|
|
@ -59,12 +59,7 @@ static struct omap_mcbsp_data mcbsp_data[NUM_LINKS];
|
|||
* Stream DMA parameters. DMA request line and port address are set runtime
|
||||
* since they are different between OMAP1 and later OMAPs
|
||||
*/
|
||||
static struct omap_pcm_dma_data omap_mcbsp_dai_dma_params[NUM_LINKS][2] = {
|
||||
{
|
||||
{ .name = "I2S PCM Stereo out", },
|
||||
{ .name = "I2S PCM Stereo in", },
|
||||
},
|
||||
};
|
||||
static struct omap_pcm_dma_data omap_mcbsp_dai_dma_params[NUM_LINKS][2];
|
||||
|
||||
#if defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX)
|
||||
static const int omap1_dma_reqs[][2] = {
|
||||
|
@ -84,11 +79,22 @@ static const unsigned long omap1_mcbsp_port[][2] = {
|
|||
static const int omap1_dma_reqs[][2] = {};
|
||||
static const unsigned long omap1_mcbsp_port[][2] = {};
|
||||
#endif
|
||||
#if defined(CONFIG_ARCH_OMAP2420)
|
||||
static const int omap2420_dma_reqs[][2] = {
|
||||
|
||||
#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
|
||||
static const int omap24xx_dma_reqs[][2] = {
|
||||
{ OMAP24XX_DMA_MCBSP1_TX, OMAP24XX_DMA_MCBSP1_RX },
|
||||
{ OMAP24XX_DMA_MCBSP2_TX, OMAP24XX_DMA_MCBSP2_RX },
|
||||
#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP34XX)
|
||||
{ OMAP24XX_DMA_MCBSP3_TX, OMAP24XX_DMA_MCBSP3_RX },
|
||||
{ OMAP24XX_DMA_MCBSP4_TX, OMAP24XX_DMA_MCBSP4_RX },
|
||||
{ OMAP24XX_DMA_MCBSP5_TX, OMAP24XX_DMA_MCBSP5_RX },
|
||||
#endif
|
||||
};
|
||||
#else
|
||||
static const int omap24xx_dma_reqs[][2] = {};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_ARCH_OMAP2420)
|
||||
static const unsigned long omap2420_mcbsp_port[][2] = {
|
||||
{ OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DXR1,
|
||||
OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DRR1 },
|
||||
|
@ -96,10 +102,43 @@ static const unsigned long omap2420_mcbsp_port[][2] = {
|
|||
OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DRR1 },
|
||||
};
|
||||
#else
|
||||
static const int omap2420_dma_reqs[][2] = {};
|
||||
static const unsigned long omap2420_mcbsp_port[][2] = {};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_ARCH_OMAP2430)
|
||||
static const unsigned long omap2430_mcbsp_port[][2] = {
|
||||
{ OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DXR,
|
||||
OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DRR },
|
||||
{ OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DXR,
|
||||
OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DRR },
|
||||
{ OMAP2430_MCBSP3_BASE + OMAP_MCBSP_REG_DXR,
|
||||
OMAP2430_MCBSP3_BASE + OMAP_MCBSP_REG_DRR },
|
||||
{ OMAP2430_MCBSP4_BASE + OMAP_MCBSP_REG_DXR,
|
||||
OMAP2430_MCBSP4_BASE + OMAP_MCBSP_REG_DRR },
|
||||
{ OMAP2430_MCBSP5_BASE + OMAP_MCBSP_REG_DXR,
|
||||
OMAP2430_MCBSP5_BASE + OMAP_MCBSP_REG_DRR },
|
||||
};
|
||||
#else
|
||||
static const unsigned long omap2430_mcbsp_port[][2] = {};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_ARCH_OMAP34XX)
|
||||
static const unsigned long omap34xx_mcbsp_port[][2] = {
|
||||
{ OMAP34XX_MCBSP1_BASE + OMAP_MCBSP_REG_DXR,
|
||||
OMAP34XX_MCBSP1_BASE + OMAP_MCBSP_REG_DRR },
|
||||
{ OMAP34XX_MCBSP2_BASE + OMAP_MCBSP_REG_DXR,
|
||||
OMAP34XX_MCBSP2_BASE + OMAP_MCBSP_REG_DRR },
|
||||
{ OMAP34XX_MCBSP3_BASE + OMAP_MCBSP_REG_DXR,
|
||||
OMAP34XX_MCBSP3_BASE + OMAP_MCBSP_REG_DRR },
|
||||
{ OMAP34XX_MCBSP4_BASE + OMAP_MCBSP_REG_DXR,
|
||||
OMAP34XX_MCBSP4_BASE + OMAP_MCBSP_REG_DRR },
|
||||
{ OMAP34XX_MCBSP5_BASE + OMAP_MCBSP_REG_DXR,
|
||||
OMAP34XX_MCBSP5_BASE + OMAP_MCBSP_REG_DRR },
|
||||
};
|
||||
#else
|
||||
static const unsigned long omap34xx_mcbsp_port[][2] = {};
|
||||
#endif
|
||||
|
||||
static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
|
@ -167,14 +206,19 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
|
|||
dma = omap1_dma_reqs[bus_id][substream->stream];
|
||||
port = omap1_mcbsp_port[bus_id][substream->stream];
|
||||
} else if (cpu_is_omap2420()) {
|
||||
dma = omap2420_dma_reqs[bus_id][substream->stream];
|
||||
dma = omap24xx_dma_reqs[bus_id][substream->stream];
|
||||
port = omap2420_mcbsp_port[bus_id][substream->stream];
|
||||
} else if (cpu_is_omap2430()) {
|
||||
dma = omap24xx_dma_reqs[bus_id][substream->stream];
|
||||
port = omap2430_mcbsp_port[bus_id][substream->stream];
|
||||
} else if (cpu_is_omap343x()) {
|
||||
dma = omap24xx_dma_reqs[bus_id][substream->stream];
|
||||
port = omap34xx_mcbsp_port[bus_id][substream->stream];
|
||||
} else {
|
||||
/*
|
||||
* TODO: Add support for 2430 and 3430
|
||||
*/
|
||||
return -ENODEV;
|
||||
}
|
||||
omap_mcbsp_dai_dma_params[id][substream->stream].name =
|
||||
substream->stream ? "Audio Capture" : "Audio Playback";
|
||||
omap_mcbsp_dai_dma_params[id][substream->stream].dma_req = dma;
|
||||
omap_mcbsp_dai_dma_params[id][substream->stream].port_addr = port;
|
||||
cpu_dai->dma_data = &omap_mcbsp_dai_dma_params[id][substream->stream];
|
||||
|
@ -245,6 +289,11 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai,
|
|||
regs->rcr2 |= RDATDLY(1);
|
||||
regs->xcr2 |= XDATDLY(1);
|
||||
break;
|
||||
case SND_SOC_DAIFMT_DSP_A:
|
||||
/* 0-bit data delay */
|
||||
regs->rcr2 |= RDATDLY(0);
|
||||
regs->xcr2 |= XDATDLY(0);
|
||||
break;
|
||||
default:
|
||||
/* Unsupported data format */
|
||||
return -EINVAL;
|
||||
|
@ -310,7 +359,7 @@ static int omap_mcbsp_dai_set_clks_src(struct omap_mcbsp_data *mcbsp_data,
|
|||
int clk_id)
|
||||
{
|
||||
int sel_bit;
|
||||
u16 reg;
|
||||
u16 reg, reg_devconf1 = OMAP243X_CONTROL_DEVCONF1;
|
||||
|
||||
if (cpu_class_is_omap1()) {
|
||||
/* OMAP1's can use only external source clock */
|
||||
|
@ -320,6 +369,12 @@ static int omap_mcbsp_dai_set_clks_src(struct omap_mcbsp_data *mcbsp_data,
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (cpu_is_omap2420() && mcbsp_data->bus_id > 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (cpu_is_omap343x())
|
||||
reg_devconf1 = OMAP343X_CONTROL_DEVCONF1;
|
||||
|
||||
switch (mcbsp_data->bus_id) {
|
||||
case 0:
|
||||
reg = OMAP2_CONTROL_DEVCONF0;
|
||||
|
@ -329,20 +384,26 @@ static int omap_mcbsp_dai_set_clks_src(struct omap_mcbsp_data *mcbsp_data,
|
|||
reg = OMAP2_CONTROL_DEVCONF0;
|
||||
sel_bit = 6;
|
||||
break;
|
||||
/* TODO: Support for ports 3 - 5 in OMAP2430 and OMAP34xx */
|
||||
case 2:
|
||||
reg = reg_devconf1;
|
||||
sel_bit = 0;
|
||||
break;
|
||||
case 3:
|
||||
reg = reg_devconf1;
|
||||
sel_bit = 2;
|
||||
break;
|
||||
case 4:
|
||||
reg = reg_devconf1;
|
||||
sel_bit = 4;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (cpu_class_is_omap2()) {
|
||||
if (clk_id == OMAP_MCBSP_SYSCLK_CLKS_FCLK) {
|
||||
omap_ctrl_writel(omap_ctrl_readl(reg) &
|
||||
~(1 << sel_bit), reg);
|
||||
} else {
|
||||
omap_ctrl_writel(omap_ctrl_readl(reg) |
|
||||
(1 << sel_bit), reg);
|
||||
}
|
||||
}
|
||||
if (clk_id == OMAP_MCBSP_SYSCLK_CLKS_FCLK)
|
||||
omap_ctrl_writel(omap_ctrl_readl(reg) & ~(1 << sel_bit), reg);
|
||||
else
|
||||
omap_ctrl_writel(omap_ctrl_readl(reg) | (1 << sel_bit), reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -376,37 +437,49 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
|
|||
return err;
|
||||
}
|
||||
|
||||
struct snd_soc_dai omap_mcbsp_dai[NUM_LINKS] = {
|
||||
{
|
||||
.name = "omap-mcbsp-dai",
|
||||
.id = 0,
|
||||
.type = SND_SOC_DAI_I2S,
|
||||
.playback = {
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.rates = OMAP_MCBSP_RATES,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
},
|
||||
.capture = {
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.rates = OMAP_MCBSP_RATES,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
},
|
||||
.ops = {
|
||||
.startup = omap_mcbsp_dai_startup,
|
||||
.shutdown = omap_mcbsp_dai_shutdown,
|
||||
.trigger = omap_mcbsp_dai_trigger,
|
||||
.hw_params = omap_mcbsp_dai_hw_params,
|
||||
},
|
||||
.dai_ops = {
|
||||
.set_fmt = omap_mcbsp_dai_set_dai_fmt,
|
||||
.set_clkdiv = omap_mcbsp_dai_set_clkdiv,
|
||||
.set_sysclk = omap_mcbsp_dai_set_dai_sysclk,
|
||||
},
|
||||
.private_data = &mcbsp_data[0].bus_id,
|
||||
},
|
||||
#define OMAP_MCBSP_DAI_BUILDER(link_id) \
|
||||
{ \
|
||||
.name = "omap-mcbsp-dai-(link_id)", \
|
||||
.id = (link_id), \
|
||||
.type = SND_SOC_DAI_I2S, \
|
||||
.playback = { \
|
||||
.channels_min = 2, \
|
||||
.channels_max = 2, \
|
||||
.rates = OMAP_MCBSP_RATES, \
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE, \
|
||||
}, \
|
||||
.capture = { \
|
||||
.channels_min = 2, \
|
||||
.channels_max = 2, \
|
||||
.rates = OMAP_MCBSP_RATES, \
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE, \
|
||||
}, \
|
||||
.ops = { \
|
||||
.startup = omap_mcbsp_dai_startup, \
|
||||
.shutdown = omap_mcbsp_dai_shutdown, \
|
||||
.trigger = omap_mcbsp_dai_trigger, \
|
||||
.hw_params = omap_mcbsp_dai_hw_params, \
|
||||
}, \
|
||||
.dai_ops = { \
|
||||
.set_fmt = omap_mcbsp_dai_set_dai_fmt, \
|
||||
.set_clkdiv = omap_mcbsp_dai_set_clkdiv, \
|
||||
.set_sysclk = omap_mcbsp_dai_set_dai_sysclk, \
|
||||
}, \
|
||||
.private_data = &mcbsp_data[(link_id)].bus_id, \
|
||||
}
|
||||
|
||||
struct snd_soc_dai omap_mcbsp_dai[] = {
|
||||
OMAP_MCBSP_DAI_BUILDER(0),
|
||||
OMAP_MCBSP_DAI_BUILDER(1),
|
||||
#if NUM_LINKS >= 3
|
||||
OMAP_MCBSP_DAI_BUILDER(2),
|
||||
#endif
|
||||
#if NUM_LINKS == 5
|
||||
OMAP_MCBSP_DAI_BUILDER(3),
|
||||
OMAP_MCBSP_DAI_BUILDER(4),
|
||||
#endif
|
||||
};
|
||||
|
||||
EXPORT_SYMBOL_GPL(omap_mcbsp_dai);
|
||||
|
||||
MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@nokia.com>");
|
||||
|
|
|
@ -38,11 +38,17 @@ enum omap_mcbsp_div {
|
|||
OMAP_MCBSP_CLKGDV, /* Sample rate generator divider */
|
||||
};
|
||||
|
||||
/*
|
||||
* REVISIT: Preparation for the ASoC v2. Let the number of available links to
|
||||
* be same than number of McBSP ports found in OMAP(s) we are compiling for.
|
||||
*/
|
||||
#define NUM_LINKS 1
|
||||
#if defined(CONFIG_ARCH_OMAP2420)
|
||||
#define NUM_LINKS 2
|
||||
#endif
|
||||
#if defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX)
|
||||
#undef NUM_LINKS
|
||||
#define NUM_LINKS 3
|
||||
#endif
|
||||
#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP34XX)
|
||||
#undef NUM_LINKS
|
||||
#define NUM_LINKS 5
|
||||
#endif
|
||||
|
||||
extern struct snd_soc_dai omap_mcbsp_dai[NUM_LINKS];
|
||||
|
||||
|
|
|
@ -97,7 +97,7 @@ static int omap_pcm_hw_params(struct snd_pcm_substream *substream,
|
|||
prtd->dma_data = dma_data;
|
||||
err = omap_request_dma(dma_data->dma_req, dma_data->name,
|
||||
omap_pcm_dma_irq, substream, &prtd->dma_ch);
|
||||
if (!cpu_is_omap1510()) {
|
||||
if (!err & !cpu_is_omap1510()) {
|
||||
/*
|
||||
* Link channel with itself so DMA doesn't need any
|
||||
* reprogramming while looping the buffer
|
||||
|
@ -147,12 +147,14 @@ static int omap_pcm_prepare(struct snd_pcm_substream *substream)
|
|||
dma_params.src_or_dst_synch = OMAP_DMA_DST_SYNC;
|
||||
dma_params.src_start = runtime->dma_addr;
|
||||
dma_params.dst_start = dma_data->port_addr;
|
||||
dma_params.dst_port = OMAP_DMA_PORT_MPUI;
|
||||
} else {
|
||||
dma_params.src_amode = OMAP_DMA_AMODE_CONSTANT;
|
||||
dma_params.dst_amode = OMAP_DMA_AMODE_POST_INC;
|
||||
dma_params.src_or_dst_synch = OMAP_DMA_SRC_SYNC;
|
||||
dma_params.src_start = dma_data->port_addr;
|
||||
dma_params.dst_start = runtime->dma_addr;
|
||||
dma_params.src_port = OMAP_DMA_PORT_MPUI;
|
||||
}
|
||||
/*
|
||||
* Set DMA transfer frame size equal to ALSA period size and frame
|
||||
|
|
232
sound/soc/omap/osk5912.c
Normal file
232
sound/soc/omap/osk5912.c
Normal file
|
@ -0,0 +1,232 @@
|
|||
/*
|
||||
* osk5912.c -- SoC audio for OSK 5912
|
||||
*
|
||||
* Copyright (C) 2008 Mistral Solutions
|
||||
*
|
||||
* Contact: Arun KS <arunks@mistralsolutions.com>
|
||||
*
|
||||
* 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 <linux/clk.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/soc-dapm.h>
|
||||
|
||||
#include <asm/mach-types.h>
|
||||
#include <mach/hardware.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <mach/mcbsp.h>
|
||||
|
||||
#include "omap-mcbsp.h"
|
||||
#include "omap-pcm.h"
|
||||
#include "../codecs/tlv320aic23.h"
|
||||
|
||||
#define CODEC_CLOCK 12000000
|
||||
|
||||
static struct clk *tlv320aic23_mclk;
|
||||
|
||||
static int osk_startup(struct snd_pcm_substream *substream)
|
||||
{
|
||||
return clk_enable(tlv320aic23_mclk);
|
||||
}
|
||||
|
||||
static void osk_shutdown(struct snd_pcm_substream *substream)
|
||||
{
|
||||
clk_disable(tlv320aic23_mclk);
|
||||
}
|
||||
|
||||
static int osk_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 err;
|
||||
|
||||
/* Set codec DAI configuration */
|
||||
err = snd_soc_dai_set_fmt(codec_dai,
|
||||
SND_SOC_DAIFMT_DSP_A |
|
||||
SND_SOC_DAIFMT_NB_IF |
|
||||
SND_SOC_DAIFMT_CBM_CFM);
|
||||
if (err < 0) {
|
||||
printk(KERN_ERR "can't set codec DAI configuration\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Set cpu DAI configuration */
|
||||
err = snd_soc_dai_set_fmt(cpu_dai,
|
||||
SND_SOC_DAIFMT_DSP_A |
|
||||
SND_SOC_DAIFMT_NB_IF |
|
||||
SND_SOC_DAIFMT_CBM_CFM);
|
||||
if (err < 0) {
|
||||
printk(KERN_ERR "can't set cpu DAI configuration\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Set the codec system clock for DAC and ADC */
|
||||
err =
|
||||
snd_soc_dai_set_sysclk(codec_dai, 0, CODEC_CLOCK, SND_SOC_CLOCK_IN);
|
||||
|
||||
if (err < 0) {
|
||||
printk(KERN_ERR "can't set codec system clock\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct snd_soc_ops osk_ops = {
|
||||
.startup = osk_startup,
|
||||
.hw_params = osk_hw_params,
|
||||
.shutdown = osk_shutdown,
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_HP("Headphone Jack", NULL),
|
||||
SND_SOC_DAPM_LINE("Line In", NULL),
|
||||
SND_SOC_DAPM_MIC("Mic Jack", NULL),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route audio_map[] = {
|
||||
{"Headphone Jack", NULL, "LHPOUT"},
|
||||
{"Headphone Jack", NULL, "RHPOUT"},
|
||||
|
||||
{"LLINEIN", NULL, "Line In"},
|
||||
{"RLINEIN", NULL, "Line In"},
|
||||
|
||||
{"MICIN", NULL, "Mic Jack"},
|
||||
};
|
||||
|
||||
static int osk_tlv320aic23_init(struct snd_soc_codec *codec)
|
||||
{
|
||||
|
||||
/* Add osk5912 specific widgets */
|
||||
snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets,
|
||||
ARRAY_SIZE(tlv320aic23_dapm_widgets));
|
||||
|
||||
/* Set up osk5912 specific audio path audio_map */
|
||||
snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
|
||||
|
||||
snd_soc_dapm_enable_pin(codec, "Headphone Jack");
|
||||
snd_soc_dapm_enable_pin(codec, "Line In");
|
||||
snd_soc_dapm_enable_pin(codec, "Mic Jack");
|
||||
|
||||
snd_soc_dapm_sync(codec);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Digital audio interface glue - connects codec <--> CPU */
|
||||
static struct snd_soc_dai_link osk_dai = {
|
||||
.name = "TLV320AIC23",
|
||||
.stream_name = "AIC23",
|
||||
.cpu_dai = &omap_mcbsp_dai[0],
|
||||
.codec_dai = &tlv320aic23_dai,
|
||||
.init = osk_tlv320aic23_init,
|
||||
.ops = &osk_ops,
|
||||
};
|
||||
|
||||
/* Audio machine driver */
|
||||
static struct snd_soc_machine snd_soc_machine_osk = {
|
||||
.name = "OSK5912",
|
||||
.dai_link = &osk_dai,
|
||||
.num_links = 1,
|
||||
};
|
||||
|
||||
/* Audio subsystem */
|
||||
static struct snd_soc_device osk_snd_devdata = {
|
||||
.machine = &snd_soc_machine_osk,
|
||||
.platform = &omap_soc_platform,
|
||||
.codec_dev = &soc_codec_dev_tlv320aic23,
|
||||
};
|
||||
|
||||
static struct platform_device *osk_snd_device;
|
||||
|
||||
static int __init osk_soc_init(void)
|
||||
{
|
||||
int err;
|
||||
u32 curRate;
|
||||
struct device *dev;
|
||||
|
||||
if (!(machine_is_omap_osk()))
|
||||
return -ENODEV;
|
||||
|
||||
osk_snd_device = platform_device_alloc("soc-audio", -1);
|
||||
if (!osk_snd_device)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(osk_snd_device, &osk_snd_devdata);
|
||||
osk_snd_devdata.dev = &osk_snd_device->dev;
|
||||
*(unsigned int *)osk_dai.cpu_dai->private_data = 0; /* McBSP1 */
|
||||
err = platform_device_add(osk_snd_device);
|
||||
if (err)
|
||||
goto err1;
|
||||
|
||||
dev = &osk_snd_device->dev;
|
||||
|
||||
tlv320aic23_mclk = clk_get(dev, "mclk");
|
||||
if (IS_ERR(tlv320aic23_mclk)) {
|
||||
printk(KERN_ERR "Could not get mclk clock\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (clk_get_usecount(tlv320aic23_mclk) > 0) {
|
||||
/* MCLK is already in use */
|
||||
printk(KERN_WARNING
|
||||
"MCLK in use at %d Hz. We change it to %d Hz\n",
|
||||
(uint) clk_get_rate(tlv320aic23_mclk), CODEC_CLOCK);
|
||||
}
|
||||
|
||||
/*
|
||||
* Configure 12 MHz output on MCLK.
|
||||
*/
|
||||
curRate = (uint) clk_get_rate(tlv320aic23_mclk);
|
||||
if (curRate != CODEC_CLOCK) {
|
||||
if (clk_set_rate(tlv320aic23_mclk, CODEC_CLOCK)) {
|
||||
printk(KERN_ERR "Cannot set MCLK for AIC23 CODEC\n");
|
||||
err = -ECANCELED;
|
||||
goto err1;
|
||||
}
|
||||
}
|
||||
|
||||
printk(KERN_INFO "MCLK = %d [%d], usecount = %d\n",
|
||||
(uint) clk_get_rate(tlv320aic23_mclk), CODEC_CLOCK,
|
||||
clk_get_usecount(tlv320aic23_mclk));
|
||||
|
||||
return 0;
|
||||
err1:
|
||||
clk_put(tlv320aic23_mclk);
|
||||
platform_device_del(osk_snd_device);
|
||||
platform_device_put(osk_snd_device);
|
||||
|
||||
return err;
|
||||
|
||||
}
|
||||
|
||||
static void __exit osk_soc_exit(void)
|
||||
{
|
||||
platform_device_unregister(osk_snd_device);
|
||||
}
|
||||
|
||||
module_init(osk_soc_init);
|
||||
module_exit(osk_soc_exit);
|
||||
|
||||
MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>");
|
||||
MODULE_DESCRIPTION("ALSA SoC OSK 5912");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -4,7 +4,7 @@
|
|||
* Copyright 2005 Wolfson Microelectronics PLC.
|
||||
* Copyright 2005 Openedhand Ltd.
|
||||
*
|
||||
* Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
|
||||
* Authors: Liam Girdwood <lrg@slimlogic.co.uk>
|
||||
* Richard Purdie <richard@openedhand.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
|
@ -281,8 +281,8 @@ static int corgi_wm8731_init(struct snd_soc_codec *codec)
|
|||
{
|
||||
int i, err;
|
||||
|
||||
snd_soc_dapm_disable_pin(codec, "LLINEIN");
|
||||
snd_soc_dapm_disable_pin(codec, "RLINEIN");
|
||||
snd_soc_dapm_nc_pin(codec, "LLINEIN");
|
||||
snd_soc_dapm_nc_pin(codec, "RLINEIN");
|
||||
|
||||
/* Add corgi specific controls */
|
||||
for (i = 0; i < ARRAY_SIZE(wm8731_corgi_controls); i++) {
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
* Copyright 2005 Wolfson Microelectronics PLC.
|
||||
* Copyright 2005 Openedhand Ltd.
|
||||
*
|
||||
* Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
|
||||
* Authors: Liam Girdwood <lrg@slimlogic.co.uk>
|
||||
* Richard Purdie <richard@openedhand.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* Copyright 2005 Wolfson Microelectronics PLC.
|
||||
* Copyright 2005 Openedhand Ltd.
|
||||
*
|
||||
* Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
|
||||
* Authors: Liam Girdwood <lrg@slimlogic.co.uk>
|
||||
* Richard Purdie <richard@openedhand.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
|
@ -242,8 +242,8 @@ static int poodle_wm8731_init(struct snd_soc_codec *codec)
|
|||
{
|
||||
int i, err;
|
||||
|
||||
snd_soc_dapm_disable_pin(codec, "LLINEIN");
|
||||
snd_soc_dapm_disable_pin(codec, "RLINEIN");
|
||||
snd_soc_dapm_nc_pin(codec, "LLINEIN");
|
||||
snd_soc_dapm_nc_pin(codec, "RLINEIN");
|
||||
snd_soc_dapm_enable_pin(codec, "MICIN");
|
||||
|
||||
/* Add poodle specific controls */
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* Copyright 2005 Wolfson Microelectronics PLC.
|
||||
* Author: Liam Girdwood
|
||||
* liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
|
||||
* 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
|
||||
|
@ -405,6 +405,6 @@ module_init(pxa2xx_i2s_init);
|
|||
module_exit(pxa2xx_i2s_exit);
|
||||
|
||||
/* Module information */
|
||||
MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
|
||||
MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
|
||||
MODULE_DESCRIPTION("pxa2xx I2S SoC Interface");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* Copyright 2005 Wolfson Microelectronics PLC.
|
||||
* Copyright 2005 Openedhand Ltd.
|
||||
*
|
||||
* Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
|
||||
* Authors: Liam Girdwood <lrg@slimlogic.co.uk>
|
||||
* Richard Purdie <richard@openedhand.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
|
@ -281,13 +281,13 @@ static int spitz_wm8750_init(struct snd_soc_codec *codec)
|
|||
int i, err;
|
||||
|
||||
/* NC codec pins */
|
||||
snd_soc_dapm_disable_pin(codec, "RINPUT1");
|
||||
snd_soc_dapm_disable_pin(codec, "LINPUT2");
|
||||
snd_soc_dapm_disable_pin(codec, "RINPUT2");
|
||||
snd_soc_dapm_disable_pin(codec, "LINPUT3");
|
||||
snd_soc_dapm_disable_pin(codec, "RINPUT3");
|
||||
snd_soc_dapm_disable_pin(codec, "OUT3");
|
||||
snd_soc_dapm_disable_pin(codec, "MONO1");
|
||||
snd_soc_dapm_nc_pin(codec, "RINPUT1");
|
||||
snd_soc_dapm_nc_pin(codec, "LINPUT2");
|
||||
snd_soc_dapm_nc_pin(codec, "RINPUT2");
|
||||
snd_soc_dapm_nc_pin(codec, "LINPUT3");
|
||||
snd_soc_dapm_nc_pin(codec, "RINPUT3");
|
||||
snd_soc_dapm_nc_pin(codec, "OUT3");
|
||||
snd_soc_dapm_nc_pin(codec, "MONO1");
|
||||
|
||||
/* Add spitz specific controls */
|
||||
for (i = 0; i < ARRAY_SIZE(wm8750_spitz_controls); i++) {
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* Copyright 2005 Wolfson Microelectronics PLC.
|
||||
* Copyright 2005 Openedhand Ltd.
|
||||
*
|
||||
* Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
|
||||
* Authors: Liam Girdwood <lrg@slimlogic.co.uk>
|
||||
* Richard Purdie <richard@openedhand.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
|
@ -190,8 +190,8 @@ static int tosa_ac97_init(struct snd_soc_codec *codec)
|
|||
{
|
||||
int i, err;
|
||||
|
||||
snd_soc_dapm_disable_pin(codec, "OUT3");
|
||||
snd_soc_dapm_disable_pin(codec, "MONOOUT");
|
||||
snd_soc_dapm_nc_pin(codec, "OUT3");
|
||||
snd_soc_dapm_nc_pin(codec, "MONOOUT");
|
||||
|
||||
/* add tosa specific controls */
|
||||
for (i = 0; i < ARRAY_SIZE(tosa_controls); i++) {
|
||||
|
|
|
@ -511,21 +511,20 @@ static int neo1973_wm8753_init(struct snd_soc_codec *codec)
|
|||
DBG("Entered %s\n", __func__);
|
||||
|
||||
/* set up NC codec pins */
|
||||
snd_soc_dapm_disable_pin(codec, "LOUT2");
|
||||
snd_soc_dapm_disable_pin(codec, "ROUT2");
|
||||
snd_soc_dapm_disable_pin(codec, "OUT3");
|
||||
snd_soc_dapm_disable_pin(codec, "OUT4");
|
||||
snd_soc_dapm_disable_pin(codec, "LINE1");
|
||||
snd_soc_dapm_disable_pin(codec, "LINE2");
|
||||
|
||||
|
||||
/* set endpoints to default mode */
|
||||
set_scenario_endpoints(codec, NEO_AUDIO_OFF);
|
||||
snd_soc_dapm_nc_pin(codec, "LOUT2");
|
||||
snd_soc_dapm_nc_pin(codec, "ROUT2");
|
||||
snd_soc_dapm_nc_pin(codec, "OUT3");
|
||||
snd_soc_dapm_nc_pin(codec, "OUT4");
|
||||
snd_soc_dapm_nc_pin(codec, "LINE1");
|
||||
snd_soc_dapm_nc_pin(codec, "LINE2");
|
||||
|
||||
/* Add neo1973 specific widgets */
|
||||
snd_soc_dapm_new_controls(codec, wm8753_dapm_widgets,
|
||||
ARRAY_SIZE(wm8753_dapm_widgets));
|
||||
|
||||
/* set endpoints to default mode */
|
||||
set_scenario_endpoints(codec, NEO_AUDIO_OFF);
|
||||
|
||||
/* add neo1973 specific controls */
|
||||
for (i = 0; i < ARRAY_SIZE(wm8753_neo1973_controls); i++) {
|
||||
err = snd_ctl_add(codec->card,
|
||||
|
@ -603,6 +602,8 @@ static int lm4857_i2c_probe(struct i2c_client *client,
|
|||
{
|
||||
DBG("Entered %s\n", __func__);
|
||||
|
||||
i2c = client;
|
||||
|
||||
lm4857_write_regs();
|
||||
return 0;
|
||||
}
|
||||
|
@ -611,6 +612,8 @@ static int lm4857_i2c_remove(struct i2c_client *client)
|
|||
{
|
||||
DBG("Entered %s\n", __func__);
|
||||
|
||||
i2c = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -650,7 +653,7 @@ static void lm4857_shutdown(struct i2c_client *dev)
|
|||
}
|
||||
|
||||
static const struct i2c_device_id lm4857_i2c_id[] = {
|
||||
{ "neo1973_lm4857", 0 }
|
||||
{ "neo1973_lm4857", 0 },
|
||||
{ }
|
||||
};
|
||||
|
||||
|
@ -668,48 +671,6 @@ static struct i2c_driver lm4857_i2c_driver = {
|
|||
};
|
||||
|
||||
static struct platform_device *neo1973_snd_device;
|
||||
static struct i2c_client *lm4857_client;
|
||||
|
||||
static int __init neo1973_add_lm4857_device(struct platform_device *pdev,
|
||||
int i2c_bus,
|
||||
unsigned short i2c_address)
|
||||
{
|
||||
struct i2c_board_info info;
|
||||
struct i2c_adapter *adapter;
|
||||
struct i2c_client *client;
|
||||
int ret;
|
||||
|
||||
ret = i2c_add_driver(&lm4857_i2c_driver);
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev, "can't add lm4857 driver\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
memset(&info, 0, sizeof(struct i2c_board_info));
|
||||
info.addr = i2c_address;
|
||||
strlcpy(info.type, "neo1973_lm4857", I2C_NAME_SIZE);
|
||||
|
||||
adapter = i2c_get_adapter(i2c_bus);
|
||||
if (!adapter) {
|
||||
dev_err(&pdev->dev, "can't get i2c adapter %d\n", i2c_bus);
|
||||
goto err_driver;
|
||||
}
|
||||
|
||||
client = i2c_new_device(adapter, &info);
|
||||
i2c_put_adapter(adapter);
|
||||
if (!client) {
|
||||
dev_err(&pdev->dev, "can't add lm4857 device at 0x%x\n",
|
||||
(unsigned int)info.addr);
|
||||
goto err_driver;
|
||||
}
|
||||
|
||||
lm4857_client = client;
|
||||
return 0;
|
||||
|
||||
err_driver:
|
||||
i2c_del_driver(&lm4857_i2c_driver);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static int __init neo1973_init(void)
|
||||
{
|
||||
|
@ -736,8 +697,8 @@ static int __init neo1973_init(void)
|
|||
return ret;
|
||||
}
|
||||
|
||||
ret = neo1973_add_lm4857_device(neo1973_snd_device,
|
||||
neo1973_wm8753_setup, 0x7C);
|
||||
ret = i2c_add_driver(&lm4857_i2c_driver);
|
||||
|
||||
if (ret != 0)
|
||||
platform_device_unregister(neo1973_snd_device);
|
||||
|
||||
|
@ -748,7 +709,6 @@ static void __exit neo1973_exit(void)
|
|||
{
|
||||
DBG("Entered %s\n", __func__);
|
||||
|
||||
i2c_unregister_device(lm4857_client);
|
||||
i2c_del_driver(&lm4857_i2c_driver);
|
||||
platform_device_unregister(neo1973_snd_device);
|
||||
}
|
||||
|
|
|
@ -4,8 +4,7 @@
|
|||
* Copyright 2005 Wolfson Microelectronics PLC.
|
||||
* Copyright 2005 Openedhand Ltd.
|
||||
*
|
||||
* Author: Liam Girdwood
|
||||
* liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
|
||||
* Author: Liam Girdwood <lrg@slimlogic.co.uk>
|
||||
* with code, comments and ideas from :-
|
||||
* Richard Purdie <richard@openedhand.com>
|
||||
*
|
||||
|
@ -1886,7 +1885,7 @@ module_init(snd_soc_init);
|
|||
module_exit(snd_soc_exit);
|
||||
|
||||
/* Module information */
|
||||
MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
|
||||
MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
|
||||
MODULE_DESCRIPTION("ALSA SoC Core");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:soc-audio");
|
||||
|
|
|
@ -2,8 +2,7 @@
|
|||
* soc-dapm.c -- ALSA SoC Dynamic Audio Power Management
|
||||
*
|
||||
* 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
|
||||
|
@ -1483,6 +1482,26 @@ int snd_soc_dapm_disable_pin(struct snd_soc_codec *codec, char *pin)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin);
|
||||
|
||||
/**
|
||||
* snd_soc_dapm_nc_pin - permanently disable pin.
|
||||
* @codec: SoC codec
|
||||
* @pin: pin name
|
||||
*
|
||||
* Marks the specified pin as being not connected, disabling it along
|
||||
* any parent or child widgets. At present this is identical to
|
||||
* snd_soc_dapm_disable_pin() but in future it will be extended to do
|
||||
* additional things such as disabling controls which only affect
|
||||
* paths through the pin.
|
||||
*
|
||||
* NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
|
||||
* do any widget power switching.
|
||||
*/
|
||||
int snd_soc_dapm_nc_pin(struct snd_soc_codec *codec, char *pin)
|
||||
{
|
||||
return snd_soc_dapm_set_pin(codec, pin, 0);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin);
|
||||
|
||||
/**
|
||||
* snd_soc_dapm_get_pin_status - get audio pin status
|
||||
* @codec: audio codec
|
||||
|
@ -1521,6 +1540,6 @@ void snd_soc_dapm_free(struct snd_soc_device *socdev)
|
|||
EXPORT_SYMBOL_GPL(snd_soc_dapm_free);
|
||||
|
||||
/* Module information */
|
||||
MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
|
||||
MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
|
||||
MODULE_DESCRIPTION("Dynamic Audio Power Management core for ALSA SoC");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
Loading…
Reference in a new issue