[alsa-devel] [PATCH 1/2] ASoC: Add DA7210 codec device support for ALSA

Liam Girdwood lrg at slimlogic.co.uk
Wed Dec 9 11:59:51 CET 2009


On Wed, 2009-12-09 at 11:53 +0900, Kuninori Morimoto wrote:
> This original driver was created by Dialog Semiconductor,
> and cleanuped by Kuninori Morimoto.
> Special thanks to David Chen.
> This is very simple ASoC codec driver.
> It was tested by EcoVec24 board.
> 
> Signed-off-by: David Chen <Dajun.chen at diasemi.com>
> Signed-off-by: Kuninori Morimoto <morimoto.kuninori at renesas.com>


Just had a quick look and have identified some minor issues below.

>  sound/soc/codecs/Kconfig  |    4 +
>  sound/soc/codecs/Makefile |    2 +
>  sound/soc/codecs/da7210.c |  773 +++++++++++++++++++++++++++++++++++++++++++++
>  sound/soc/codecs/da7210.h |   24 ++
>  4 files changed, 803 insertions(+), 0 deletions(-)
>  create mode 100644 sound/soc/codecs/da7210.c
>  create mode 100644 sound/soc/codecs/da7210.h
> 
> diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
> index 52b005f..ff33b02 100644
> --- a/sound/soc/codecs/Kconfig
> +++ b/sound/soc/codecs/Kconfig
> @@ -23,6 +23,7 @@ config SND_SOC_ALL_CODECS
>  	select SND_SOC_AK4671 if I2C
>  	select SND_SOC_CS4270 if I2C
>  	select SND_SOC_MAX9877 if I2C
> +	select SND_SOC_DA7210 if I2C
>  	select SND_SOC_PCM3008
>  	select SND_SOC_SPDIF
>  	select SND_SOC_SSM2602 if I2C
> @@ -112,6 +113,9 @@ config SND_SOC_AK4671
>  config SND_SOC_CS4270
>  	tristate
>  
> +config SND_SOC_DA7210
> +        tristate
> +
>  # Cirrus Logic CS4270 Codec VD = 3.3V Errata
>  # Select if you are affected by the errata where the part will not function
>  # if MCLK divide-by-1.5 is selected and VD is set to 3.3V.  The driver will
> diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
> index dbaecb1..a495bf8 100644
> --- a/sound/soc/codecs/Makefile
> +++ b/sound/soc/codecs/Makefile
> @@ -10,6 +10,7 @@ snd-soc-ak4642-objs := ak4642.o
>  snd-soc-ak4671-objs := ak4671.o
>  snd-soc-cs4270-objs := cs4270.o
>  snd-soc-cx20442-objs := cx20442.o
> +snd-soc-da7210-objs := da7210.o
>  snd-soc-l3-objs := l3.o
>  snd-soc-pcm3008-objs := pcm3008.o
>  snd-soc-spdif-objs := spdif_transciever.o
> @@ -66,6 +67,7 @@ obj-$(CONFIG_SND_SOC_AK4642)	+= snd-soc-ak4642.o
>  obj-$(CONFIG_SND_SOC_AK4671)	+= snd-soc-ak4671.o
>  obj-$(CONFIG_SND_SOC_CS4270)	+= snd-soc-cs4270.o
>  obj-$(CONFIG_SND_SOC_CX20442)	+= snd-soc-cx20442.o
> +obj-$(CONFIG_SND_SOC_DA7210)	+= snd-soc-da7210.o
>  obj-$(CONFIG_SND_SOC_L3)	+= snd-soc-l3.o
>  obj-$(CONFIG_SND_SOC_PCM3008)	+= snd-soc-pcm3008.o
>  obj-$(CONFIG_SND_SOC_SPDIF)	+= snd-soc-spdif.o
> diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c
> new file mode 100644
> index 0000000..1356b90
> --- /dev/null
> +++ b/sound/soc/codecs/da7210.c
> @@ -0,0 +1,773 @@
> +/*
> + * DA7210 ALSA Soc codec driver
> + *
> + * Copyright (c) 2009 Dialog Semiconductor
> + * Written by David Chen <Dajun.chen at diasemi.com>
> + *
> + * Copyright (C) 2009 Renesas Solutions Corp.
> + * Cleanups by Kuninori Morimoto <morimoto.kuninori at renesas.com>
> + *
> + * Tested on SuperH Ecovec24 board with S16/S24 LE in 48KHz using I2S
> + *
> + * 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/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 <asm/div64.h>
> +
> +#include "da7210.h"
> +
> +/* DA7210 register space */
> +#define DA7210_STATUS			0x02
> +#define DA7210_STARTUP1			0x03
> +#define DA7210_STARTUP2			0x04
> +#define DA7210_STARTUP3			0x05
> +#define DA7210_MIC_L			0x07
> +#define DA7210_MIC_R			0x08
> +#define DA7210_IN_GAIN			0x0C
> +#define DA7210_INMIX_L			0x0D
> +#define DA7210_INMIX_R			0x0E
> +#define DA7210_ADC_HPF			0x0F
> +#define DA7210_ADC			0x10
> +#define DA7210_DAC_HPF			0x14
> +#define DA7210_DAC_L			0x15
> +#define DA7210_DAC_R			0x16
> +#define DA7210_DAC_SEL			0x17
> +#define DA7210_OUTMIX_L			0x1C
> +#define DA7210_OUTMIX_R			0x1D
> +#define DA7210_OUT2			0x20
> +#define DA7210_HP_L_VOL			0x21
> +#define DA7210_HP_R_VOL			0x22
> +#define DA7210_HP_CFG			0x23
> +#define DA7210_DAI_SRC_SEL		0x25
> +#define DA7210_DAI_CFG1			0x26
> +#define DA7210_DAI_CFG3			0x28
> +#define DA7210_PLL_DIV3			0x2B
> +#define DA7210_PLL			0x2C
> +
> +/* STARTUP1 bit fields */
> +#define DA7210_SC_MST_EN		(1 << 0)
> +
> +/* STARTUP2 bit fields */
> +#define DA7210_LOUT1_L_STBY		(1 << 0)
> +#define DA7210_LOUT1_R_STBY		(1 << 1)
> +#define DA7210_LOUT2_STBY		(1 << 2)
> +#define DA7210_HP_L_STBY		(1 << 3)
> +#define DA7210_HP_R_STBY		(1 << 4)
> +#define DA7210_DAC_L_STBY		(1 << 5)
> +#define DA7210_DAC_R_STBY		(1 << 6)
> +
> +/* STARTUP3 bit fields */
> +#define DA7210_MIC_L_STBY		(1 << 0)
> +#define DA7210_MIC_R_STBY		(1 << 1)
> +#define DA7210_LIN1_L_STBY		(1 << 2)
> +#define DA7210_LIN1_R_STBY		(1 << 3)
> +#define DA7210_LIN2_STBY		(1 << 4)
> +#define DA7210_ADC_L_STBY		(1 << 5)
> +#define DA7210_ADC_R_STBY		(1 << 6)
> +
> +/* MIC_L bit fields */
> +#define DA7210_MICBIAS_EN		(1 << 6)
> +#define DA7210_MIC_L_EN			(1 << 7)
> +
> +/* MIC_R bit fields */
> +#define DA7210_MIC_R_EN			(1 << 7)
> +
> +/* INMIX_L bit fields */
> +#define DA7210_IN_L_EN			(1 << 7)
> +
> +/* INMIX_R bit fields */
> +#define DA7210_IN_R_EN			(1 << 7)
> +
> +/* ADC_HPF bit fields */
> +#define DA7210_ADC_HPF_EN		(1 << 3)
> +#define DA7210_ADC_VOICE_EN		(1 << 7)
> +
> +/* ADC bit fields */
> +#define DA7210_ADC_L_EN			(1 << 3)
> +#define DA7210_ADC_R_EN			(1 << 7)
> +
> +/* DAC_HPF bit fields */
> +#define DA7210_DAC_HPF_EN		(1 << 3)
> +#define DA7210_DAC_VOICE_EN		(1 << 7)
> +
> +/* DAC_SEL bit fields */
> +#define DA7210_DAC_L_SRC_DAI_L		(4 << 0)
> +#define DA7210_DAC_L_EN			(1 << 3)
> +#define DA7210_DAC_R_SRC_DAI_R		(5 << 4)
> +#define DA7210_DAC_R_EN			(1 << 7)
> +
> +/* OUTMIX_L bit fields */
> +#define DA7210_OUT_L_EN			(1 << 7)
> +
> +/* OUTMIX_R bit fields */
> +#define DA7210_OUT_R_EN			(1 << 7)
> +
> +/* HP_CFG bit fields */
> +#define DA7210_HP_2CAP_MODE		(1 << 1)
> +#define DA7210_HP_SENSE_EN		(1 << 2)
> +#define DA7210_HP_L_EN			(1 << 3)
> +#define DA7210_HP_MODE			(1 << 6)
> +#define DA7210_HP_R_EN			(1 << 7)
> +
> +/* DAI_SRC_SEL bit fields */
> +#define DA7210_DAI_OUT_L_SRC		(6 << 0)
> +#define DA7210_DAI_OUT_R_SRC		(7 << 4)
> +
> +/* DAI_CFG1 bit fields */
> +#define DA7210_DAI_WORD_S16_LE		(0 << 0)
> +#define DA7210_DAI_WORD_S24_LE		(2 << 0)
> +#define DA7210_DAI_FLEN_64BIT		(1 << 2)
> +#define DA7210_DAI_MODE_MASTER		(1 << 7)
> +
> +/* DAI_CFG3 bit fields */
> +#define DA7210_DAI_FORMAT_I2SMODE	(0 << 0)
> +#define DA7210_DAI_OE			(1 << 3)
> +#define DA7210_DAI_EN			(1 << 7)
> +
> +/*PLL_DIV3 bit fields */
> +#define DA7210_MCLK_RANGE_10_20_MHZ	(1 << 4)
> +#define DA7210_PLL_BYP			(1 << 6)
> +
> +/* PLL bit fields */
> +#define DA7210_PLL_FS_48000		(11 << 0)
> +
> +#define DA7210_VERSION "0.0.1"
> +
> +/* Codec private data */
> +struct da7210_priv {
> +	struct snd_soc_codec codec;
> +};
> +
> +static struct snd_soc_codec *da7210_codec;
> +
> +/*
> + * Register cache
> + */
> +static const u8 da7210_reg[] = {
> +	0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* R0  - R7  */
> +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,	/* R8  - RF  */
> +	0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x10, 0x54,	/* R10 - R17 */
> +	0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* R18 - R1F */
> +	0x00, 0x00, 0x00, 0x02, 0x00, 0x76, 0x00, 0x00,	/* R20 - R27 */
> +	0x04, 0x00, 0x00, 0x30, 0x2A, 0x00, 0x40, 0x00,	/* R28 - R2F */
> +	0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00,	/* R30 - R37 */
> +	0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00,	/* R38 - R3F */
> +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* R40 - R4F */
> +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* R48 - R4F */
> +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* R50 - R57 */
> +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* R58 - R5F */
> +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* R60 - R67 */
> +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* R68 - R6F */
> +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* R70 - R77 */
> +	0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x54, 0x00,	/* R78 - R7F */
> +	0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00,	/* R80 - R87 */
> +	0x00,						/* R88       */
> +};
> +
> +/*
> + * Read da7210 register cache
> + */
> +static inline unsigned int da7210_read_reg_cache(struct snd_soc_codec *codec,
> +						 unsigned int reg)
> +{
> +	u8 *cache = codec->reg_cache;
> +	BUG_ON(reg > ARRAY_SIZE(da7210_reg));
> +	return cache[reg];
> +}
> +
> +/*
> + * Write da7210 register cache
> + */
> +static inline void da7210_write_reg_cache(struct snd_soc_codec *codec,
> +					  unsigned int reg, unsigned int value)
> +{
> +	u8 *cache = codec->reg_cache;
> +
> +	cache[reg] = value;
> +}
> +
> +/*
> + * Write to the da7210 register space
> + */
> +static int da7210_write(struct snd_soc_codec *codec, unsigned int reg,
> +			unsigned int value)
> +{
> +
> +	u8 data[2];
> +
> +	/* data[0] da7210 register offset */
> +	/* data[1] register data */
> +	data[0] = reg & 0xff;
> +	data[1] = value & 0xff;
> +
> +	if (2 != codec->hw_write(codec->control_data, data, 2)) {
> +		dev_warn(codec->dev, "I2C write Failed!\n");
> +		return -EIO;
> +	}
> +

Why not use #define register width here than use the number 2.

> +	/* write the cache only if hardware write is successful */
> +	if (data[0] < ARRAY_SIZE(da7210_reg))
> +		da7210_write_reg_cache(codec, data[0], data[1]);
> +
> +	return 0;
> +}
> +
> +/*
> + * Read from the da7210 register space.
> + */
> +static inline unsigned int da7210_read(struct snd_soc_codec *codec,
> +				       unsigned int reg)
> +{
> +	/* FIXME !!
> +	 *
> +	 * we should read status from I2C.
> +	 * But not supported now.
> +	 */

Any particular reason for I2C read back not being supported atm. If I2C
write works, then read should too. 

> +	if (DA7210_STATUS == reg)
> +		return -EIO;
> +
> +	return da7210_read_reg_cache(codec, reg);
> +}
> +
> +static const char *da7210_mic_bias_voltage[] = { "1.5", "1.6", "2.2", "2.3" };
> +
> +static const struct soc_enum da7210_enum[] = {
> +	SOC_ENUM_SINGLE(DA7210_MIC_L, 4, 4, da7210_mic_bias_voltage),
> +};
> +
> +/* Add non DAPM controls */
> +static const struct snd_kcontrol_new da7210_snd_controls[] = {
> +	/* Mixer Playback controls */
> +	SOC_DOUBLE_R("DAC Gain", DA7210_DAC_L, DA7210_DAC_R, 0, 0x37, 1),

"DAC Volume"

> +	SOC_DOUBLE_R("HeadPhone Playback Volume",
> +		     DA7210_HP_L_VOL, DA7210_HP_R_VOL, 0, 0x3f, 0),
> +	/* Mixer Capture controls */
> +	SOC_DOUBLE_R("Mic Capture Volume",
> +		     DA7210_MIC_L, DA7210_MIC_R, 0, 0x07, 0),
> +	SOC_DOUBLE("In PGA Gain", DA7210_IN_GAIN, 0, 4, 0x0F, 0),

Best to use volume instead of gain.

> +	SOC_SINGLE("Mic Bias", DA7210_MIC_L, 6, 1, 0),
> +	SOC_ENUM("Mic Bias Voltage", da7210_enum[0]),
> +};
> +
> +/* ----------------------------Capture Mixers--------------------------- */
> +
> +/* In Mixer Left */
> +static const struct snd_kcontrol_new da7210_in_left_mixer_controls[] = {
> +	SOC_DAPM_SINGLE("MIC_L Switch",  DA7210_INMIX_L, 0, 1, 0),
> +	SOC_DAPM_SINGLE("MIC_R Switch",  DA7210_INMIX_L, 1, 1, 0),
> +	SOC_DAPM_SINGLE("Aux1_L Switch", DA7210_INMIX_L, 2, 1, 0),
> +	SOC_DAPM_SINGLE("Aux2 Switch",   DA7210_INMIX_L, 3, 1, 0),
> +	SOC_DAPM_SINGLE("DAC_L Switch",  DA7210_INMIX_L, 4, 1, 0),
> +};
> +
> +/* In Mixer Right */
> +static const struct snd_kcontrol_new da7210_in_right_mixer_controls[] = {
> +	SOC_DAPM_SINGLE("MIC_R Switch",   DA7210_INMIX_R, 0, 1, 0),
> +	SOC_DAPM_SINGLE("MIC_L Switch",   DA7210_INMIX_R, 1, 1, 0),
> +	SOC_DAPM_SINGLE("Aux1_R Switch",  DA7210_INMIX_R, 2, 1, 0),
> +	SOC_DAPM_SINGLE("Aux2 Switch",    DA7210_INMIX_R, 3, 1, 0),
> +	SOC_DAPM_SINGLE("DAC_R Switch",   DA7210_INMIX_R, 4, 1, 0),
> +	SOC_DAPM_SINGLE("INPGA_L Switch", DA7210_INMIX_R, 5, 1, 0),
> +};
> +
> +/*----------------------------Playback Mixers---------------------------*/
> +/* Out Mixer Left */
> +static const struct snd_kcontrol_new da7210_out_mixer_left_controls[] = {
> +	SOC_DAPM_SINGLE("AUX1_L Switch", DA7210_OUTMIX_L, 0, 1, 0),
> +	SOC_DAPM_SINGLE("AUX2 Switch",   DA7210_OUTMIX_L, 1, 1, 0),
> +	SOC_DAPM_SINGLE("IN_L Switch",   DA7210_OUTMIX_L, 2, 1, 0),
> +	SOC_DAPM_SINGLE("IN_R Switch",   DA7210_OUTMIX_L, 3, 1, 0),
> +	SOC_DAPM_SINGLE("DAC_L Switch",  DA7210_OUTMIX_L, 4, 1, 0),
> +};
> +
> +/* Out Mixer Right */
> +static const struct snd_kcontrol_new da7210_out_mixer_right_controls[] = {
> +	SOC_DAPM_SINGLE("AUX1_R Switch", DA7210_OUTMIX_R, 0, 1, 0),
> +	SOC_DAPM_SINGLE("AUX2 Switch",   DA7210_OUTMIX_R, 1, 1, 0),
> +	SOC_DAPM_SINGLE("IN_L Switch",   DA7210_OUTMIX_R, 2, 1, 0),
> +	SOC_DAPM_SINGLE("IN_R Switch",   DA7210_OUTMIX_R, 3, 1, 0),
> +	SOC_DAPM_SINGLE("DAC_R Switch",  DA7210_OUTMIX_R, 4, 1, 0),
> +};
> +
> +/* Mono Mixer */
> +static const struct snd_kcontrol_new da7210_mono_mixer_controls[] = {
> +	SOC_DAPM_SINGLE("IN_L Switch",  DA7210_OUT2, 3, 1, 0),
> +	SOC_DAPM_SINGLE("IN_R Switch",  DA7210_OUT2, 4, 1, 0),
> +	SOC_DAPM_SINGLE("DAC_L Switch", DA7210_OUT2, 5, 1, 0),
> +	SOC_DAPM_SINGLE("DAC_R Switch", DA7210_OUT2, 6, 1, 0),
> +};
> +
> +static const struct snd_kcontrol_new da7210_headphone_left_control =
> +	SOC_DAPM_SINGLE("Switch", DA7210_STARTUP2, 3, 1, 1);
> +static const struct snd_kcontrol_new da7210_headphone_right_control =
> +	SOC_DAPM_SINGLE("Switch", DA7210_STARTUP2, 4, 1, 1);
> +static const struct snd_kcontrol_new da7210_MicIn_left_control =
> +	SOC_DAPM_SINGLE("Switch", DA7210_STARTUP3, 0, 1, 1);
> +static const struct snd_kcontrol_new da7210_MicIn_right_control =
> +	SOC_DAPM_SINGLE("Switch", DA7210_STARTUP3, 1, 1, 1);
> +
> +/* DAPM widgets */
> +static const struct snd_soc_dapm_widget da7210_dapm_widgets[] = {
> +	/* DAMP stream domain - DAC. Enabled when playback is started */
> +	SND_SOC_DAPM_DAC("DAC Left", "Playback", DA7210_STARTUP2, 5, 1),
> +	SND_SOC_DAPM_DAC("DAC Right", "Playback", DA7210_STARTUP2, 6, 1),
> +
> +	/* DAMP stream domain - ADC. Enabled when capture is started */
> +	SND_SOC_DAPM_ADC("ADC Left", "Capture", DA7210_STARTUP3, 5, 1),
> +	SND_SOC_DAPM_ADC("ADC Right", "Capture", DA7210_STARTUP3, 6, 1),
> +
> +	/* DAPM path domain - switches and mixers */
> +	/* Automatically set when mixer settings are changed by the user */
> +	SND_SOC_DAPM_SWITCH("HPL Enable", SND_SOC_NOPM, 0, 0,
> +			    &da7210_headphone_left_control),
> +	SND_SOC_DAPM_SWITCH("HPR Enable", SND_SOC_NOPM, 0, 0,
> +			    &da7210_headphone_right_control),
> +	SND_SOC_DAPM_SWITCH("MicL Enable", SND_SOC_NOPM, 0, 0,
> +			    &da7210_MicIn_left_control),
> +	SND_SOC_DAPM_SWITCH("MicR Enable", SND_SOC_NOPM, 0, 0,
> +			    &da7210_MicIn_right_control),
> +
> +	SND_SOC_DAPM_MIXER("Out Mixer Left", SND_SOC_NOPM, 0, 0,
> +			   &da7210_out_mixer_left_controls[0],
> +			   ARRAY_SIZE(da7210_out_mixer_left_controls)),
> +
> +	SND_SOC_DAPM_MIXER("Out Mixer Right", SND_SOC_NOPM, 0, 0,
> +			   &da7210_out_mixer_right_controls[0],
> +			   ARRAY_SIZE(da7210_out_mixer_right_controls)),
> +
> +	SND_SOC_DAPM_MIXER("In Mixer Left", SND_SOC_NOPM, 0, 0,
> +			   &da7210_in_left_mixer_controls[0],
> +			   ARRAY_SIZE(da7210_in_left_mixer_controls)),
> +
> +	SND_SOC_DAPM_MIXER("In Mixer Right", SND_SOC_NOPM, 0, 0,
> +			   &da7210_in_right_mixer_controls[0],
> +			   ARRAY_SIZE(da7210_in_right_mixer_controls)),
> +
> +	/* DAPM Platform domain. Physically connected input and ouput pins */
> +	SND_SOC_DAPM_OUTPUT("HPL"),   /*Headphone Out left*/
> +	SND_SOC_DAPM_OUTPUT("HPR"),   /*Headphone out Right*/
> +	SND_SOC_DAPM_INPUT("MICL"),   /*MicIn left*/
> +	SND_SOC_DAPM_INPUT("MICR"),   /*MicIn Right*/
> +};
> +
> +/* DAPM audio route definition */
> +static const struct snd_soc_dapm_route audio_map[] = {
> +	/*Out Mixer Left*/
> +	{"Out Mixer Left", "DAC_L Switch", "DAC Left"},
> +
> +	/*Out Mixer Right*/
> +	{"Out Mixer Right", "DAC_R Switch", "DAC Right"},
> +
> +	/*In Mixer Left*/
> +	{"In Mixer Left", "MIC_L Switch", "MicL Enable"},
> +
> +	/*In Mixer Right*/
> +	{"In Mixer Right", "MIC_R Switch", "MicR Enable"},
> +
> +	/*HPL*/
> +	{"HPL", NULL, "HPL Enable"},
> +	{"HPL Enable", "Switch", "Out Mixer Left"},
> +
> +	/*HPR*/
> +	{"HPR", NULL, "HPR Enable"},
> +	{"HPR Enable", "Switch", "Out Mixer Right"},
> +
> +	/*MICL*/
> +	{"ADC Left", NULL, "In Mixer Left"},
> +	{"MicL Enable", "Switch", "MICL"},
> +
> +	/*MICR*/
> +	{"ADC Right", NULL, "In Mixer Right"},
> +	{"MicR Enable", "Switch", "MICR"},
> +};
> +
> +static int da7210_add_widgets(struct snd_soc_codec *codec)
> +{
> +	snd_soc_dapm_new_controls(codec, da7210_dapm_widgets,
> +				  ARRAY_SIZE(da7210_dapm_widgets));
> +	snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
> +	snd_soc_dapm_new_widgets(codec);
> +	return 0;
> +}
> +
> +/*
> + * Set PCM DAI word length.
> + * Enable Voice Filter if Fs <= 16KHz
> + */
> +static int da7210_hw_params(struct snd_pcm_substream *substream,
> +			    struct snd_pcm_hw_params *params,
> +			    struct snd_soc_dai *dai)
> +{
> +	struct snd_soc_pcm_runtime *rtd = substream->private_data;
> +	struct snd_soc_device *socdev = rtd->socdev;
> +	struct snd_soc_codec *codec = socdev->card->codec;
> +	unsigned int dai_cfg1;
> +	unsigned int value, reg, mask;
> +
> +	dai_cfg1 = 0xFC & da7210_read(codec, DA7210_DAI_CFG1);
> +
> +	switch (params_format(params)) {
> +	case SNDRV_PCM_FORMAT_S16_LE:
> +		dai_cfg1 |= DA7210_DAI_WORD_S16_LE;
> +		break;
> +	case SNDRV_PCM_FORMAT_S24_LE:
> +		dai_cfg1 |= DA7210_DAI_WORD_S24_LE;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	da7210_write(codec, DA7210_DAI_CFG1, dai_cfg1);
> +
> +	/* FIXME
> +	 *
> +	 * It support 48K only now
> +	 */
> +	switch (params_rate(params)) {
> +	case 48000:
> +		if (SNDRV_PCM_STREAM_PLAYBACK == substream->stream) {
> +			reg  =  DA7210_DAC_HPF;
> +			mask = ~DA7210_DAC_VOICE_EN;
> +		} else {
> +			reg  =  DA7210_ADC_HPF;
> +			mask = ~DA7210_ADC_VOICE_EN;
> +		}
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	value  = da7210_read_reg_cache(codec, reg);
> +	value &= mask;
> +	da7210_write(codec, reg, value);
> +
> +	return 0;
> +}
> +
> +/*
> + * Set DAI mode and Format
> + */
> +static int da7210_set_dai_fmt(struct snd_soc_dai *codec_dai,
> +			      unsigned int fmt)
> +{
> +	struct snd_soc_codec *codec = codec_dai->codec;
> +	unsigned int dai_cfg1;
> +	unsigned int dai_cfg3;
> +
> +	dai_cfg1 = 0x7f & da7210_read(codec, DA7210_DAI_CFG1);
> +	dai_cfg3 = 0xfc & da7210_read(codec, DA7210_DAI_CFG3);
> +
> +	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
> +	case SND_SOC_DAIFMT_CBM_CFM:
> +		dai_cfg1 |= DA7210_DAI_MODE_MASTER;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	/* FIXME
> +	 *
> +	 * It support I2S only now
> +	 */
> +	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
> +	case SND_SOC_DAIFMT_I2S:
> +		dai_cfg3 |= DA7210_DAI_FORMAT_I2SMODE;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	/* FIXME
> +	 *
> +	 * It support 64bit data transmission only now
> +	 */
> +	dai_cfg1 |= DA7210_DAI_FLEN_64BIT;
> +
> +	da7210_write(codec, DA7210_DAI_CFG1, dai_cfg1);
> +	da7210_write(codec, DA7210_DAI_CFG3, dai_cfg3);
> +
> +	return 0;
> +}
> +
> +#define DA7210_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
> +
> +/* DAI operations */
> +static struct snd_soc_dai_ops da7210_dai_ops = {
> +	.hw_params	= da7210_hw_params,
> +	.set_fmt	= da7210_set_dai_fmt,
> +};
> +
> +struct snd_soc_dai da7210_dai = {
> +	.name = "DA7210 IIS",
> +	.id = 0,
> +	/* playback capabilities */
> +	.playback = {
> +		.stream_name = "Playback",
> +		.channels_min = 1,
> +		.channels_max = 2,
> +		.rates = SNDRV_PCM_RATE_8000_96000,
> +		.formats = DA7210_FORMATS,
> +	},
> +	/* capture capabilities */
> +	.capture = {
> +		.stream_name = "Capture",
> +		.channels_min = 1,
> +		.channels_max = 2,
> +		.rates = SNDRV_PCM_RATE_8000_96000,
> +		.formats = DA7210_FORMATS,
> +	},
> +	.ops = &da7210_dai_ops,
> +};
> +EXPORT_SYMBOL_GPL(da7210_dai);
> +
> +/*
> + * Initialize the DA7210 driver
> + * register the mixer and dsp interfaces with the kernel
> + */
> +static int da7210_init(struct da7210_priv *da7210)
> +{
> +	struct snd_soc_codec *codec = &da7210->codec;
> +	int ret = 0;
> +
> +	if (da7210_codec) {
> +		dev_err(codec->dev, "Another da7210 is registered\n");
> +		return -EINVAL;
> +	}
> +
> +	mutex_init(&codec->mutex);
> +	INIT_LIST_HEAD(&codec->dapm_widgets);
> +	INIT_LIST_HEAD(&codec->dapm_paths);
> +
> +	codec->private_data	= da7210;
> +	codec->name		= "DA7210";
> +	codec->owner		= THIS_MODULE;
> +	codec->read		= da7210_read;
> +	codec->write		= da7210_write;
> +	codec->dai		= &da7210_dai;
> +	codec->num_dai		= 1;
> +	codec->hw_write		= (hw_write_t)i2c_master_send;
> +	codec->reg_cache_size	= ARRAY_SIZE(da7210_reg);
> +	codec->reg_cache	= kmemdup(da7210_reg,
> +					  sizeof(da7210_reg), GFP_KERNEL);
> +
> +	if (!codec->reg_cache)
> +		return -ENOMEM;
> +
> +	da7210_dai.dev = codec->dev;
> +	da7210_codec = codec;
> +
> +	ret = snd_soc_register_dai(&da7210_dai);
> +	if (ret) {
> +		dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
> +		return -ENOMEM;
> +	}
> +
> +	/*
> +	 * ADC settings
> +	 */
> +
> +	/* Enable Left & Right MIC PGA and Mic Bias */
> +	da7210_write(codec, DA7210_MIC_L, DA7210_MIC_L_EN | DA7210_MICBIAS_EN);
> +	da7210_write(codec, DA7210_MIC_R, DA7210_MIC_R_EN);
> +
> +	/* Enable Left and Right input PGA */
> +	da7210_write(codec, DA7210_INMIX_L, DA7210_IN_L_EN);
> +	da7210_write(codec, DA7210_INMIX_R, DA7210_IN_R_EN);
> +
> +	/* Enable ADC Highpass Filter */
> +	da7210_write(codec, DA7210_ADC_HPF, DA7210_ADC_HPF_EN);
> +
> +	/* Enable Left and Right ADC */
> +	da7210_write(codec, DA7210_ADC, DA7210_ADC_L_EN | DA7210_ADC_R_EN);
> +
> +	/*
> +	 * DAC settings
> +	 */
> +
> +	/* Enable DAC Highpass Filter */
> +	da7210_write(codec, DA7210_DAC_HPF, DA7210_DAC_HPF_EN);

This could be a mixer control.

> +
> +	/* Enable Left and Right DAC */
> +	da7210_write(codec, DA7210_DAC_SEL,
> +		     DA7210_DAC_L_SRC_DAI_L | DA7210_DAC_L_EN |
> +		     DA7210_DAC_R_SRC_DAI_R | DA7210_DAC_R_EN);
> +
> +	/* Enable Left and Right out PGA */
> +	da7210_write(codec, DA7210_OUTMIX_L, DA7210_OUT_L_EN);
> +	da7210_write(codec, DA7210_OUTMIX_R, DA7210_OUT_R_EN);
> +
> +	/* Enable Left and Right HeadPhone PGA */
> +	da7210_write(codec, DA7210_HP_CFG,
> +		     DA7210_HP_2CAP_MODE | DA7210_HP_SENSE_EN |
> +		     DA7210_HP_L_EN | DA7210_HP_MODE | DA7210_HP_R_EN);
> +

Are these all enabling codec functionality by powering on codec blocks.
If so, DAPM should take care of them. 

> +	/* set DAI source to Left and Right ADC */
> +	da7210_write(codec, DA7210_DAI_SRC_SEL,
> +		     DA7210_DAI_OUT_R_SRC | DA7210_DAI_OUT_L_SRC);
> +
> +	/* Enable DAI */
> +	da7210_write(codec, DA7210_DAI_CFG3, DA7210_DAI_OE | DA7210_DAI_EN);
> +

These should really be in hw_params().

> +	/* Diable PLL and bypass it */
> +	da7210_write(codec, DA7210_PLL, DA7210_PLL_FS_48000);
> +


> +	/* Bypass PLL and set MCLK freq rang to 10-20MHz */
> +	da7210_write(codec, DA7210_PLL_DIV3,
> +		     DA7210_MCLK_RANGE_10_20_MHZ | DA7210_PLL_BYP);
> +

In set_clk()

> +	/* Enable standbymode */
> +	da7210_write(codec, DA7210_STARTUP2,
> +		     DA7210_LOUT1_L_STBY | DA7210_LOUT1_R_STBY |
> +		     DA7210_LOUT2_STBY | DA7210_HP_L_STBY |
> +		     DA7210_HP_R_STBY | DA7210_DAC_L_STBY | DA7210_DAC_R_STBY);
> +	da7210_write(codec, DA7210_STARTUP3,
> +		     DA7210_LIN1_L_STBY | DA7210_LIN1_R_STBY |
> +		     DA7210_LIN2_STBY | DA7210_MIC_L_STBY |
> +		     DA7210_MIC_R_STBY | DA7210_ADC_L_STBY | DA7210_ADC_R_STBY);
> +

Some of these settings above are correct but in the wrong code function.
Have a look at the codec and alsa pcm ops for the correct places.

> +	/* Activate all enabled subsystem */
> +	da7210_write(codec, DA7210_STARTUP1, DA7210_SC_MST_EN);
> +
> +	return ret;
> +}
> +
> +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
> +static int da7210_i2c_probe(struct i2c_client *i2c,
> +			    const struct i2c_device_id *id)
> +{
> +	struct da7210_priv *da7210;
> +	struct snd_soc_codec *codec;
> +	int ret;
> +
> +	da7210 = kzalloc(sizeof(struct da7210_priv), GFP_KERNEL);
> +	if (!da7210)
> +		return -ENOMEM;
> +
> +	codec = &da7210->codec;
> +	codec->dev = &i2c->dev;
> +
> +	i2c_set_clientdata(i2c, da7210);
> +	codec->control_data = i2c;
> +
> +	ret = da7210_init(da7210);
> +	if (ret < 0)
> +		pr_err("Failed to initialise da7210 audio codec\n");
> +
> +	return ret;
> +}
> +
> +static int da7210_i2c_remove(struct i2c_client *client)
> +{
> +	struct da7210_priv *da7210 = i2c_get_clientdata(client);
> +
> +	snd_soc_unregister_dai(&da7210_dai);
> +	kfree(da7210->codec.reg_cache);
> +	kfree(da7210);
> +	da7210_codec = NULL;
> +
> +	return 0;
> +}
> +
> +static const struct i2c_device_id da7210_i2c_id[] = {
> +	{ "da7210", 0 },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(i2c, da7210_i2c_id);
> +
> +/* I2C codec control layer */
> +static struct i2c_driver da7210_i2c_driver = {
> +	.driver = {
> +		.name = "DA7210 I2C Codec",
> +		.owner = THIS_MODULE,
> +	},
> +	.probe = da7210_i2c_probe,
> +	.remove =  __devexit_p(da7210_i2c_remove),
> +	.id_table = da7210_i2c_id,
> +};
> +#endif
> +
> +static int da7210_probe(struct platform_device *pdev)
> +{
> +	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
> +	struct snd_soc_codec *codec;
> +	int ret;
> +
> +	if (!da7210_codec) {
> +		dev_err(&pdev->dev, "Codec device not registered\n");
> +		return -ENODEV;
> +	}
> +
> +	socdev->card->codec = da7210_codec;
> +	codec = da7210_codec;
> +
> +	/* Register pcms */
> +	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
> +	if (ret < 0)
> +		goto pcm_err;
> +
> +	dev_info(&pdev->dev, "DA7210 Audio Codec %s\n", DA7210_VERSION);
> +
> +	/* Add the dapm controls */
> +	snd_soc_add_controls(codec, da7210_snd_controls,
> +			     ARRAY_SIZE(da7210_snd_controls));
> +	da7210_add_widgets(codec);
> +
> +pcm_err:
> +	return ret;
> +}
> +
> +static int da7210_remove(struct platform_device *pdev)
> +{
> +	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
> +
> +	snd_soc_free_pcms(socdev);
> +	snd_soc_dapm_free(socdev);
> +
> +	return 0;
> +}
> +
> +struct snd_soc_codec_device soc_codec_dev_da7210 = {
> +	.probe =	da7210_probe,
> +	.remove =	da7210_remove,
> +};
> +EXPORT_SYMBOL_GPL(soc_codec_dev_da7210);
> +
> +static int __init da7210_modinit(void)
> +{
> +	int ret;
> +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
> +	ret = i2c_add_driver(&da7210_i2c_driver);
> +#endif
> +	return ret;
> +}
> +module_init(da7210_modinit);
> +
> +static void __exit da7210_exit(void)
> +{
> +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
> +	i2c_del_driver(&da7210_i2c_driver);
> +#endif
> +}
> +module_exit(da7210_exit);
> +
> +MODULE_DESCRIPTION("ASoC DA7210 driver");
> +MODULE_AUTHOR("David Chen, Kuninori Morimoto");
> +MODULE_LICENSE("GPL");
> diff --git a/sound/soc/codecs/da7210.h b/sound/soc/codecs/da7210.h
> new file mode 100644
> index 0000000..390d621
> --- /dev/null
> +++ b/sound/soc/codecs/da7210.h
> @@ -0,0 +1,24 @@
> +/*
> + * da7210.h  --  audio driver for da7210
> + *
> + * Copyright (c) 2009 Dialog Semiconductor
> + * Written by David Chen <Dajun.chen at diasemi.com>
> + *
> + * Copyright (C) 2009 Renesas Solutions Corp.
> + * Cleanups by Kuninori Morimoto <morimoto.kuninori at renesas.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.
> + *
> + */
> +
> +#ifndef _DA7210_H
> +#define _DA7210_H
> +
> +extern struct snd_soc_dai da7210_dai;
> +extern struct snd_soc_codec_device soc_codec_dev_da7210;
> +
> +#endif
> +




More information about the Alsa-devel mailing list