[alsa-devel] [PATCH 1/2] ASoC: Add DA7210 codec device support for ALSA
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@diasemi.com Signed-off-by: Kuninori Morimoto morimoto.kuninori@renesas.com --- 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@diasemi.com + * + * Copyright (C) 2009 Renesas Solutions Corp. + * Cleanups by Kuninori Morimoto morimoto.kuninori@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; + } + + /* 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. + */ + 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), + 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), + 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); + + /* 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); + + /* 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); + + /* 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); + + /* 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); + + /* 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@diasemi.com + * + * Copyright (C) 2009 Renesas Solutions Corp. + * Cleanups by Kuninori Morimoto morimoto.kuninori@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 +
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@diasemi.com Signed-off-by: Kuninori Morimoto morimoto.kuninori@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@diasemi.com
- Copyright (C) 2009 Renesas Solutions Corp.
- Cleanups by Kuninori Morimoto morimoto.kuninori@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@diasemi.com
- Copyright (C) 2009 Renesas Solutions Corp.
- Cleanups by Kuninori Morimoto morimoto.kuninori@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
On Wed, Dec 09, 2009 at 11:53:33AM +0900, Kuninori Morimoto wrote:
+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.
*/
As Liam noted there are a few issues with the I2C stuff - you should be able to resolve these issues by removing the I2C code in the driver with soc-cache.c usage, which is a good idea anyway.
+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),
+};
Please use individual variables rather than an array - it doesn't make much difference for small numbers of enums (like one!) but as the number increases it makes it much easier to keep track of which enum is bein referenced to by which control.
A couple of other comments of mine will be replicated from Liam's.
+/* 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),
Should be "DAC Volume" - control names are interpreted by ALSA to let it know how to present the controls to applications.
- SOC_DOUBLE("In PGA Gain", DA7210_IN_GAIN, 0, 4, 0x0F, 0),
Should be "In PGA Volume".
- SOC_SINGLE("Mic Bias", DA7210_MIC_L, 6, 1, 0),
This should be a DAPM widget.
- value = da7210_read_reg_cache(codec, reg);
- value &= mask;
- da7210_write(codec, reg, value);
snd_soc_update_bits().
- 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;
- }
Should also register the CODEC.
- /* 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);
These all look like they should be controls of some kind - either DAPM or regular - and should be fairly straightforward to convert over. Since you're already using DAPM the power stuff especially should be properly supported since a mix of DAPM and non-DAPM control often leads to confusion and bugs.
For power bits there's no point setting a default since DAPM will overwrite them on startup anyway. In general the ASoC policy is for the CODEC driver to leave things at chip default since the driver has to work on many boards and the chip default is usually chosen as it will have to be at least somewhat sane for most boards.
- /* Enable DAI */
- da7210_write(codec, DA7210_DAI_CFG3, DA7210_DAI_OE | DA7210_DAI_EN);
I suspect you should use an AIF DAPM widget for these, or possibly an AIF widget in conjunction with a supply widget.
- /* 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);
Since these aren't made configurable by the driver and are a bit more involved than controls it's OK to set defaults for these, though ideally they'd be supported by the driver.
/* Enable standbymode */
da7210_write(codec, DA7210_STARTUP2,
DA7210_LOUT1_L_STBY | DA7210_LOUT1_R_STBY |
...
/* Activate all enabled subsystem */
da7210_write(codec, DA7210_STARTUP1, DA7210_SC_MST_EN);
This definitely looks like it ought to be being handled in the bias level configuration and/or by DAPM.
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +static int da7210_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
No need to ifdef where I2C is the only control interface.
Dear Mark, Liam
Thank you for checking patch
Now I'm modifying DA7210 patch. Small / Easy problem are already modified. Thank you.
But I'm so sorry, I'm not good at DAPM / widget. So, I don't know how to modify it.
Because this original driver came from Dialog guy. My work is cleanup only. # Of course we already got acceptance from him.
Could you approve it with /* FIXME */ comment ? If you can not approve it, this time I will remove all of DAPM / widget settings, and use fixed value with "This is very simple settings" comments.
Best regards -- Kuninori Morimoto
On Thu, Dec 10, 2009 at 06:35:52PM +0900, Kuninori Morimoto wrote:
Because this original driver came from Dialog guy. My work is cleanup only. # Of course we already got acceptance from him.
Could you approve it with /* FIXME */ comment ? If you can not approve it, this time I will remove all of DAPM / widget settings, and use fixed value with "This is very simple settings" comments.
It's a bit tricky, if the code looked incomplete (as the twl4030 driver did originally) it'd not be such an issue but because it's got this odd mix of dynamic and static power management I'm reluctant to accept it as is. The code looks wrong as opposed to incomplete and so I worry that it will be fragile in the face of core development.
What's normally done in situations like this is to hook into either the bias level configuration in set_bias_level() or events on widgets to do any power control that DAPM can't do automatically. More documentation might help as well if it's not actually maintaining the power with these settings.
If it's too difficult to support then removing the DAPM support would certainly be OK for merging - it's obviously far from ideal but it doesn't have the fragility issues.
participants (3)
-
Kuninori Morimoto
-
Liam Girdwood
-
Mark Brown