diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-10-13 10:06:58 -0700 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-10-13 10:06:58 -0700 | 
| commit | be3bfbba8f7f6c8f32e8444ef895433701a3f801 (patch) | |
| tree | dfd00be7d15dbf8353f188f2505426411cb18d06 /sound | |
| parent | 20272c8994cf1e1f8ed745a2ea161dd9ad3889f2 (diff) | |
| parent | 7dc85076f83253fcffae99e6d5e6ce77840f8841 (diff) | |
| download | kernel_samsung_tuna-be3bfbba8f7f6c8f32e8444ef895433701a3f801.zip kernel_samsung_tuna-be3bfbba8f7f6c8f32e8444ef895433701a3f801.tar.gz kernel_samsung_tuna-be3bfbba8f7f6c8f32e8444ef895433701a3f801.tar.bz2  | |
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
  ...
Diffstat (limited to 'sound')
55 files changed, 2036 insertions, 601 deletions
diff --git a/sound/oss/ac97_codec.c b/sound/oss/ac97_codec.c index b63839e..456a1b4 100644 --- a/sound/oss/ac97_codec.c +++ b/sound/oss/ac97_codec.c @@ -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 diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 6ce3cbe..6e831af 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -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.   */ diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index c461baa..c590655 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -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) { diff --git a/sound/soc/at91/Kconfig b/sound/soc/at91/Kconfig index 9051865..85a8832 100644 --- a/sound/soc/at91/Kconfig +++ b/sound/soc/at91/Kconfig @@ -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. diff --git a/sound/soc/at91/Makefile b/sound/soc/at91/Makefile index f23da17..b817f11 100644 --- a/sound/soc/at91/Makefile +++ b/sound/soc/at91/Makefile @@ -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 diff --git a/sound/soc/at91/at91-ssc.c b/sound/soc/at91/at91-ssc.c index a5b1a79..1b61cc4 100644 --- a/sound/soc/at91/at91-ssc.c +++ b/sound/soc/at91/at91-ssc.c @@ -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 diff --git a/sound/soc/at91/eti_b1_wm8731.c b/sound/soc/at91/eti_b1_wm8731.c deleted file mode 100644 index 684781e..0000000 --- a/sound/soc/at91/eti_b1_wm8731.c +++ /dev/null @@ -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"); diff --git a/sound/soc/blackfin/Kconfig b/sound/soc/blackfin/Kconfig index f98331d..dc00620 100644 --- a/sound/soc/blackfin/Kconfig +++ b/sound/soc/blackfin/Kconfig @@ -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 diff --git a/sound/soc/blackfin/Makefile b/sound/soc/blackfin/Makefile index 9ea8bd9..97bb37a 100644 --- a/sound/soc/blackfin/Makefile +++ b/sound/soc/blackfin/Makefile @@ -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 diff --git a/sound/soc/blackfin/bf5xx-ac97-pcm.c b/sound/soc/blackfin/bf5xx-ac97-pcm.c index 51f4907..25e50d2 100644 --- a/sound/soc/blackfin/bf5xx-ac97-pcm.c +++ b/sound/soc/blackfin/bf5xx-ac97-pcm.c @@ -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, diff --git a/sound/soc/blackfin/bf5xx-ac97.c b/sound/soc/blackfin/bf5xx-ac97.c index c782e31..5e5aafb 100644 --- a/sound/soc/blackfin/bf5xx-ac97.c +++ b/sound/soc/blackfin/bf5xx-ac97.c @@ -129,7 +129,6 @@ static void enqueue_cmd(struct snd_ac97 *ac97, __u16 addr, __u16 data)  	struct ac97_frame *nextwrite;  	sport_incfrag(sport, &nextfrag, 1); -	sport_incfrag(sport, &nextfrag, 1);  	nextwrite = (struct ac97_frame *)(sport->tx_buf + \  			nextfrag * sport->tx_fragsize); diff --git a/sound/soc/blackfin/bf5xx-ad73311.c b/sound/soc/blackfin/bf5xx-ad73311.c new file mode 100644 index 0000000..622c9b9 --- /dev/null +++ b/sound/soc/blackfin/bf5xx-ad73311.c @@ -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"); + diff --git a/sound/soc/blackfin/bf5xx-i2s.c b/sound/soc/blackfin/bf5xx-i2s.c index 43a4092..827587f 100644 --- a/sound/soc/blackfin/bf5xx-i2s.c +++ b/sound/soc/blackfin/bf5xx-i2s.c @@ -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,}, diff --git a/sound/soc/blackfin/bf5xx-sport.h b/sound/soc/blackfin/bf5xx-sport.h index 4c16345..fcadcc0 100644 --- a/sound/soc/blackfin/bf5xx-sport.h +++ b/sound/soc/blackfin/bf5xx-sport.h @@ -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;  }; diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index e0b9869..4975d85 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -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 diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index f977978..90f0a58 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -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 diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c index 61fd96c..bd1ebdc 100644 --- a/sound/soc/codecs/ac97.c +++ b/sound/soc/codecs/ac97.c @@ -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 diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c index 4e09c1f..1397b8e 100644 --- a/sound/soc/codecs/ad1980.c +++ b/sound/soc/codecs/ad1980.c @@ -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> diff --git a/sound/soc/codecs/ad73311.c b/sound/soc/codecs/ad73311.c new file mode 100644 index 0000000..37af860 --- /dev/null +++ b/sound/soc/codecs/ad73311.c @@ -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"); diff --git a/sound/soc/codecs/ad73311.h b/sound/soc/codecs/ad73311.h new file mode 100644 index 0000000..507ce0c --- /dev/null +++ b/sound/soc/codecs/ad73311.h @@ -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 diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c index 088cf99..2a89b58 100644 --- a/sound/soc/codecs/ak4535.c +++ b/sound/soc/codecs/ak4535.c @@ -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; diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c index 940ce1c..44ef0da 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c @@ -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; diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c new file mode 100644 index 0000000..bac7815 --- /dev/null +++ b/sound/soc/codecs/tlv320aic23.c @@ -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"); diff --git a/sound/soc/codecs/tlv320aic23.h b/sound/soc/codecs/tlv320aic23.h new file mode 100644 index 0000000..79d1faf --- /dev/null +++ b/sound/soc/codecs/tlv320aic23.h @@ -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 */ diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 566a427..05336ed 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -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; diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c index d206d7f..a69ee72 100644 --- a/sound/soc/codecs/uda1380.c +++ b/sound/soc/codecs/uda1380.c @@ -36,7 +36,6 @@  #include "uda1380.h"  #define UDA1380_VERSION "0.6" -#define AUDIO_NAME "uda1380"  /*   * uda1380 register cache diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c index 9a37c8d..d8ca2da 100644 --- a/sound/soc/codecs/wm8510.c +++ b/sound/soc/codecs/wm8510.c @@ -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: +		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) @@ -796,6 +874,9 @@ static int wm8510_remove(struct platform_device *pdev)  	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);  	return 0; diff --git a/sound/soc/codecs/wm8510.h b/sound/soc/codecs/wm8510.h index c536839..bdefcf5 100644 --- a/sound/soc/codecs/wm8510.h +++ b/sound/soc/codecs/wm8510.h @@ -94,6 +94,7 @@  #define WM8510_MCLKDIV_12	(7 << 5)  struct wm8510_setup_data { +	int spi;  	int i2c_bus;  	unsigned short i2c_address;  }; diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index df1ffbe..627ebfb 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c @@ -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 { diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 7b64d9a..7f8a7e3 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -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; diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index 4892e39..9b7296e 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c @@ -29,7 +29,6 @@  #include "wm8750.h" -#define AUDIO_NAME "WM8750"  #define WM8750_VERSION "0.12"  /* codec private data */ diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index 8c4df44..d426eaa 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c @@ -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) { @@ -1798,6 +1860,9 @@ static int wm8753_remove(struct platform_device *pdev)  	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); diff --git a/sound/soc/codecs/wm8753.h b/sound/soc/codecs/wm8753.h index 7defde0..f55704c 100644 --- a/sound/soc/codecs/wm8753.h +++ b/sound/soc/codecs/wm8753.h @@ -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;  }; diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index 0b8c6d3..3b326c9 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c @@ -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> diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index a3f54ec..ce40d78 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -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, diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c index 974a4cd..f41a578 100644 --- a/sound/soc/codecs/wm8971.c +++ b/sound/soc/codecs/wm8971.c @@ -29,7 +29,6 @@  #include "wm8971.h" -#define AUDIO_NAME "wm8971"  #define WM8971_VERSION "0.9"  #define	WM8971_REG_COUNT		43 diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index 63410d7..572d22b 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c @@ -30,7 +30,6 @@  #include "wm8990.h" -#define AUDIO_NAME "wm8990"  #define WM8990_VERSION "0.2"  /* codec private data */ diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index 2f1c91b..ffb471e 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -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 diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index 441d058..aba402b 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -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 diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index aea27e7..8b7766b 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig @@ -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. diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile index d8d8d58..e09d1f2 100644 --- a/sound/soc/omap/Makefile +++ b/sound/soc/omap/Makefile @@ -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 diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c index d166b6b..fae3ad3 100644 --- a/sound/soc/omap/n810.c +++ b/sound/soc/omap/n810.c @@ -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++) { diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index 35310e1..0a063a9 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -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>"); diff --git a/sound/soc/omap/omap-mcbsp.h b/sound/soc/omap/omap-mcbsp.h index ed8afb5..df7ad13 100644 --- a/sound/soc/omap/omap-mcbsp.h +++ b/sound/soc/omap/omap-mcbsp.h @@ -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]; diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c index 690bfea..e9084fd 100644 --- a/sound/soc/omap/omap-pcm.c +++ b/sound/soc/omap/omap-pcm.c @@ -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 diff --git a/sound/soc/omap/osk5912.c b/sound/soc/omap/osk5912.c new file mode 100644 index 0000000..0fe7337 --- /dev/null +++ b/sound/soc/omap/osk5912.c @@ -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"); diff --git a/sound/soc/pxa/corgi.c b/sound/soc/pxa/corgi.c index 1a8373d..2718eaf 100644 --- a/sound/soc/pxa/corgi.c +++ b/sound/soc/pxa/corgi.c @@ -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++) { diff --git a/sound/soc/pxa/em-x270.c b/sound/soc/pxa/em-x270.c index d9c3f7b..e6ff692 100644 --- a/sound/soc/pxa/em-x270.c +++ b/sound/soc/pxa/em-x270.c @@ -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 diff --git a/sound/soc/pxa/poodle.c b/sound/soc/pxa/poodle.c index f84f7d8..4d9930c 100644 --- a/sound/soc/pxa/poodle.c +++ b/sound/soc/pxa/poodle.c @@ -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 */ diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c index 2fb5829..e758034 100644 --- a/sound/soc/pxa/pxa2xx-i2s.c +++ b/sound/soc/pxa/pxa2xx-i2s.c @@ -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"); diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c index 9a70b00..d307b67 100644 --- a/sound/soc/pxa/spitz.c +++ b/sound/soc/pxa/spitz.c @@ -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++) { diff --git a/sound/soc/pxa/tosa.c b/sound/soc/pxa/tosa.c index 2baaa75..afefe41 100644 --- a/sound/soc/pxa/tosa.c +++ b/sound/soc/pxa/tosa.c @@ -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++) { diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c index 73a50e9..87ddfef 100644 --- a/sound/soc/s3c24xx/neo1973_wm8753.c +++ b/sound/soc/s3c24xx/neo1973_wm8753.c @@ -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);  } diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index ad38113..462e635d 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -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"); diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 9ca9c08..efbd0b3 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -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 @@ -1484,6 +1483,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   * @pin: audio signal pin endpoint (or start point) @@ -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");  | 
