From ef05a3ce8340c7156610b173324ab793b06e0ae2 Mon Sep 17 00:00:00 2001 From: Michal Ulianko Date: Mon, 29 Jul 2013 20:14:38 +0200 Subject: [PATCH 1/2] Added ASoC driver for i.MX233's builtin ADC/DAC codec. --- sound/soc/codecs/Kconfig | 4 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/mxs-builtin-codec.c | 1128 ++++++++++++++++++++++++++++++++++ sound/soc/codecs/mxs-builtin-codec.h | 825 +++++++++++++++++++++++++ sound/soc/mxs/Kconfig | 10 + sound/soc/mxs/Makefile | 9 + sound/soc/mxs/mxs-builtin-audio.c | 120 ++++ sound/soc/mxs/mxs-builtin-dai.c | 588 ++++++++++++++++++ sound/soc/mxs/mxs-builtin-pcm.c | 69 +++ sound/soc/mxs/mxs-builtin-pcm.h | 25 + 10 files changed, 2780 insertions(+) create mode 100644 sound/soc/codecs/mxs-builtin-codec.c create mode 100644 sound/soc/codecs/mxs-builtin-codec.h create mode 100644 sound/soc/mxs/mxs-builtin-audio.c create mode 100644 sound/soc/mxs/mxs-builtin-dai.c create mode 100644 sound/soc/mxs/mxs-builtin-pcm.c create mode 100644 sound/soc/mxs/mxs-builtin-pcm.h --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -164,6 +164,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_WM9705 if SND_SOC_AC97_BUS select SND_SOC_WM9712 if SND_SOC_AC97_BUS select SND_SOC_WM9713 if SND_SOC_AC97_BUS + select SND_SOC_MXS_BUILTIN_CODEC help Normally ASoC codec drivers are only built if a machine driver which uses them is also built since they are only usable with a machine @@ -789,6 +790,9 @@ config SND_SOC_WM9712 config SND_SOC_WM9713 tristate +config SND_SOC_MXS_BUILTIN_CODEC + tristate + # Amp config SND_SOC_LM4857 tristate --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -166,6 +166,7 @@ snd-soc-wm9705-objs := wm9705.o snd-soc-wm9712-objs := wm9712.o snd-soc-wm9713-objs := wm9713.o snd-soc-wm-hubs-objs := wm_hubs.o +snd-soc-mxs-builtin-codec-objs := mxs-builtin-codec.o # Amp snd-soc-max9877-objs := max9877.o @@ -339,6 +340,7 @@ obj-$(CONFIG_SND_SOC_WM9712) += snd-soc- obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o obj-$(CONFIG_SND_SOC_WM_ADSP) += snd-soc-wm-adsp.o obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o +obj-$(CONFIG_SND_SOC_MXS_BUILTIN_CODEC) += snd-soc-mxs-builtin-codec.o # Amp obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o --- /dev/null +++ b/sound/soc/codecs/mxs-builtin-codec.c @@ -0,0 +1,1128 @@ +/* + * mxs-builtin-codec.c -- i.MX233 built-in codec ALSA Soc Audio driver + * + * Author: Michal Ulianko + * + * Based on sound/soc/codecs/mxs-adc-codec.c for kernel 2.6.35 + * by Vladislav Buzov + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "mxs-builtin-codec.h" + +#ifndef BF +#define BF(value, field) (((value) << BP_##field) & BM_##field) +#endif + +/* TODO Delete this and use BM_RTC_PERSISTENT0_RELEASE_GND from header file + * if it works. */ +#define BP_RTC_PERSISTENT0_SPARE_ANALOG 18 +#define BM_RTC_PERSISTENT0_SPARE_ANALOG 0xFFFC0000 +#define BM_RTC_PERSISTENT0_RELEASE_GND BF(0x2, RTC_PERSISTENT0_SPARE_ANALOG) + +/* TODO Use codec IO function soc snd write etc, instead of __writel __readl */ + +struct mxs_adc_priv { + void __iomem *ain_base; + void __iomem *aout_base; + void __iomem *rtc_base; + struct clk *clk; +}; + +static unsigned int mxs_regmap[] = { + HW_AUDIOOUT_CTRL, + HW_AUDIOOUT_STAT, + HW_AUDIOOUT_DACSRR, + HW_AUDIOOUT_DACVOLUME, + HW_AUDIOOUT_DACDEBUG, + HW_AUDIOOUT_HPVOL, + HW_AUDIOOUT_PWRDN, + HW_AUDIOOUT_REFCTRL, + HW_AUDIOOUT_ANACTRL, + HW_AUDIOOUT_TEST, + HW_AUDIOOUT_BISTCTRL, + HW_AUDIOOUT_BISTSTAT0, + HW_AUDIOOUT_BISTSTAT1, + HW_AUDIOOUT_ANACLKCTRL, + HW_AUDIOOUT_DATA, + HW_AUDIOOUT_SPEAKERCTRL, + HW_AUDIOOUT_VERSION, + HW_AUDIOIN_CTRL, + HW_AUDIOIN_STAT, + HW_AUDIOIN_ADCSRR, + HW_AUDIOIN_ADCVOLUME, + HW_AUDIOIN_ADCDEBUG, + HW_AUDIOIN_ADCVOL, + HW_AUDIOIN_MICLINE, + HW_AUDIOIN_ANACLKCTRL, + HW_AUDIOIN_DATA, +}; + +static void __iomem *mxs_getreg(struct mxs_adc_priv *mxs_adc, int i) +{ + if (i <= 16) + return mxs_adc->aout_base + mxs_regmap[i]; + else if (i < ADC_REGNUM) + return mxs_adc->ain_base + mxs_regmap[i]; + else + return NULL; +} + +static u8 dac_volumn_control_word[] = { + 0x37, 0x5e, 0x7e, 0x8e, + 0x9e, 0xae, 0xb6, 0xbe, + 0xc6, 0xce, 0xd6, 0xde, + 0xe6, 0xee, 0xf6, 0xfe, +}; + +struct dac_srr { + u32 rate; + u32 basemult; + u32 src_hold; + u32 src_int; + u32 src_frac; +}; + +static struct dac_srr srr_values[] = { + {192000, 0x4, 0x0, 0x0F, 0x13FF}, + {176400, 0x4, 0x0, 0x11, 0x0037}, + {128000, 0x4, 0x0, 0x17, 0x0E00}, + {96000, 0x2, 0x0, 0x0F, 0x13FF}, + {88200, 0x2, 0x0, 0x11, 0x0037}, + {64000, 0x2, 0x0, 0x17, 0x0E00}, + {48000, 0x1, 0x0, 0x0F, 0x13FF}, + {44100, 0x1, 0x0, 0x11, 0x0037}, + {32000, 0x1, 0x0, 0x17, 0x0E00}, + {24000, 0x1, 0x1, 0x0F, 0x13FF}, + {22050, 0x1, 0x1, 0x11, 0x0037}, + {16000, 0x1, 0x1, 0x17, 0x0E00}, + {12000, 0x1, 0x3, 0x0F, 0x13FF}, + {11025, 0x1, 0x3, 0x11, 0x0037}, + {8000, 0x1, 0x3, 0x17, 0x0E00} +}; + +static inline int get_srr_values(int rate) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(srr_values); i++) + if (srr_values[i].rate == rate) + return i; + + return -1; +} + +/* SoC IO functions */ +static void mxs_codec_write_cache(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) +{ + u16 *cache = codec->reg_cache; + if (reg < ADC_REGNUM) + cache[reg] = value; +} + +static int mxs_codec_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) +{ + struct mxs_adc_priv *mxs_adc = snd_soc_codec_get_drvdata(codec); + unsigned int reg_val; + unsigned int mask = 0xffff; + + if (reg >= ADC_REGNUM) + return -EIO; + + mxs_codec_write_cache(codec, reg, value); + + if (reg & 0x1) { + mask <<= 16; + value <<= 16; + } + + reg_val = __raw_readl(mxs_getreg(mxs_adc, reg >> 1)); + reg_val = (reg_val & ~mask) | value; + __raw_writel(reg_val, mxs_getreg(mxs_adc, reg >> 1)); + + return 0; +} + +static unsigned int mxs_codec_read(struct snd_soc_codec *codec, unsigned int reg) +{ + struct mxs_adc_priv *mxs_adc = snd_soc_codec_get_drvdata(codec); + unsigned int reg_val; + + if (reg >= ADC_REGNUM) + return -1; + + reg_val = __raw_readl(mxs_getreg(mxs_adc, reg >> 1)); + if (reg & 1) + reg_val >>= 16; + + return reg_val & 0xffff; +} + +// static unsigned int mxs_codec_read_cache(struct snd_soc_codec *codec, unsigned int reg) +// { +// u16 *cache = codec->reg_cache; +// if (reg >= ADC_REGNUM) +// return -EINVAL; +// return cache[reg]; +// } + +static void mxs_codec_sync_reg_cache(struct snd_soc_codec *codec) +{ + int reg; + for (reg = 0; reg < ADC_REGNUM; reg += 1) + mxs_codec_write_cache(codec, reg, + mxs_codec_read(codec, reg)); +} + +// static int mxs_codec_restore_reg(struct snd_soc_codec *codec, unsigned int reg) +// { +// unsigned int cached_val, hw_val; +// +// cached_val = mxs_codec_read_cache(codec, reg); +// hw_val = mxs_codec_read(codec, reg); +// +// if (hw_val != cached_val) +// return mxs_codec_write(codec, reg, cached_val); +// +// return 0; +// } +/* END SoC IO functions */ + +/* Codec routines */ +#define VAG_BASE_VALUE ((1400/2 - 625)/25) + +static void mxs_codec_dac_set_vag(struct mxs_adc_priv *mxs_adc) +{ + u32 refctrl_val = __raw_readl(mxs_adc->aout_base + HW_AUDIOOUT_REFCTRL); + + refctrl_val &= ~(BM_AUDIOOUT_REFCTRL_VAG_VAL); + refctrl_val &= ~(BM_AUDIOOUT_REFCTRL_VBG_ADJ); + refctrl_val |= BF(VAG_BASE_VALUE, AUDIOOUT_REFCTRL_VAG_VAL) | + BM_AUDIOOUT_REFCTRL_ADJ_VAG | + BF(0xF, AUDIOOUT_REFCTRL_ADC_REFVAL) | + BM_AUDIOOUT_REFCTRL_ADJ_ADC | + BF(0x3, AUDIOOUT_REFCTRL_VBG_ADJ) | BM_AUDIOOUT_REFCTRL_RAISE_REF; + + __raw_writel(refctrl_val, mxs_adc->aout_base + HW_AUDIOOUT_REFCTRL); +} + +static bool mxs_codec_dac_is_capless(struct mxs_adc_priv *mxs_adc) +{ + if ((__raw_readl(mxs_adc->aout_base + HW_AUDIOOUT_PWRDN) + & BM_AUDIOOUT_PWRDN_CAPLESS) == 0) + return false; + else + return true; +} + +static void mxs_codec_dac_arm_short_cm(struct mxs_adc_priv *mxs_adc, bool bShort) +{ + __raw_writel(BF(3, AUDIOOUT_ANACTRL_SHORTMODE_CM), + mxs_adc->aout_base + HW_AUDIOOUT_ANACTRL_CLR); + __raw_writel(BM_AUDIOOUT_ANACTRL_SHORT_CM_STS, + mxs_adc->aout_base + HW_AUDIOOUT_ANACTRL_CLR); + if (bShort) + __raw_writel(BF(1, AUDIOOUT_ANACTRL_SHORTMODE_CM), + mxs_adc->aout_base + HW_AUDIOOUT_ANACTRL_SET); +} + +static void mxs_codec_dac_arm_short_lr(struct mxs_adc_priv *mxs_adc, bool bShort) +{ + __raw_writel(BF(3, AUDIOOUT_ANACTRL_SHORTMODE_LR), + mxs_adc->aout_base + HW_AUDIOOUT_ANACTRL_CLR); + __raw_writel(BM_AUDIOOUT_ANACTRL_SHORT_LR_STS, + mxs_adc->aout_base + HW_AUDIOOUT_ANACTRL_CLR); + if (bShort) + __raw_writel(BF(1, AUDIOOUT_ANACTRL_SHORTMODE_LR), + mxs_adc->aout_base + HW_AUDIOOUT_ANACTRL_SET); +} + +static void mxs_codec_dac_set_short_trip_level(struct mxs_adc_priv *mxs_adc, u8 u8level) +{ + __raw_writel(__raw_readl(mxs_adc->aout_base + + HW_AUDIOOUT_ANACTRL) + & (~BM_AUDIOOUT_ANACTRL_SHORT_LVLADJL) + & (~BM_AUDIOOUT_ANACTRL_SHORT_LVLADJR) + | BF(u8level, AUDIOOUT_ANACTRL_SHORT_LVLADJL) + | BF(u8level, AUDIOOUT_ANACTRL_SHORT_LVLADJR), + mxs_adc->aout_base + HW_AUDIOOUT_ANACTRL); +} + +static void mxs_codec_dac_arm_short(struct mxs_adc_priv *mxs_adc, bool bLatchCM, bool bLatchLR) +{ + if (bLatchCM) { + if (mxs_codec_dac_is_capless(mxs_adc)) + mxs_codec_dac_arm_short_cm(mxs_adc, true); + } else + mxs_codec_dac_arm_short_cm(mxs_adc, false); + + if (bLatchLR) + mxs_codec_dac_arm_short_lr(mxs_adc, true); + else + mxs_codec_dac_arm_short_lr(mxs_adc, false); +} + +static void +mxs_codec_dac_power_on(struct mxs_adc_priv *mxs_adc) +{ + /* Ungate DAC clocks */ + __raw_writel(BM_AUDIOOUT_CTRL_CLKGATE, + mxs_adc->aout_base + HW_AUDIOOUT_CTRL_CLR); + __raw_writel(BM_AUDIOOUT_ANACLKCTRL_CLKGATE, + mxs_adc->aout_base + HW_AUDIOOUT_ANACLKCTRL_CLR); + + /* 16 bit word length */ + __raw_writel(BM_AUDIOOUT_CTRL_WORD_LENGTH, + mxs_adc->aout_base + HW_AUDIOOUT_CTRL_SET); + + /* Arm headphone LR short protect */ + mxs_codec_dac_set_short_trip_level(mxs_adc, 0); + mxs_codec_dac_arm_short(mxs_adc, false, true); + + /* Update DAC volume over zero crossings */ + __raw_writel(BM_AUDIOOUT_DACVOLUME_EN_ZCD, + mxs_adc->aout_base + HW_AUDIOOUT_DACVOLUME_SET); + /* Mute DAC */ + __raw_writel(BM_AUDIOOUT_DACVOLUME_MUTE_LEFT | + BM_AUDIOOUT_DACVOLUME_MUTE_RIGHT, + mxs_adc->aout_base + HW_AUDIOOUT_DACVOLUME_SET); + + /* Update HP volume over zero crossings */ + __raw_writel(BM_AUDIOOUT_HPVOL_EN_MSTR_ZCD, + mxs_adc->aout_base + HW_AUDIOOUT_HPVOL_SET); + + __raw_writel(BM_AUDIOOUT_ANACTRL_HP_CLASSAB, + mxs_adc->aout_base + HW_AUDIOOUT_ANACTRL_SET); + + /* Mute HP output */ + __raw_writel(BM_AUDIOOUT_HPVOL_MUTE, + mxs_adc->aout_base + HW_AUDIOOUT_HPVOL_SET); + /* Mute speaker amp */ + __raw_writel(BM_AUDIOOUT_SPEAKERCTRL_MUTE, + mxs_adc->aout_base + HW_AUDIOOUT_SPEAKERCTRL_SET); + /* Enable the audioout */ + __raw_writel(BM_AUDIOOUT_CTRL_RUN, + mxs_adc->aout_base + HW_AUDIOOUT_CTRL_SET); +} + +static void +mxs_codec_dac_power_down(struct mxs_adc_priv *mxs_adc) +{ + /* Disable the audioout */ + __raw_writel(BM_AUDIOOUT_CTRL_RUN, + mxs_adc->aout_base + HW_AUDIOOUT_CTRL_CLR); + /* Disable class AB */ + __raw_writel(BM_AUDIOOUT_ANACTRL_HP_CLASSAB, + mxs_adc->aout_base + HW_AUDIOOUT_ANACTRL_CLR); + + /* Set hold to ground */ + __raw_writel(BM_AUDIOOUT_ANACTRL_HP_HOLD_GND, + mxs_adc->aout_base + HW_AUDIOOUT_ANACTRL_SET); + + /* Mute HP output */ + __raw_writel(BM_AUDIOOUT_HPVOL_MUTE, + mxs_adc->aout_base + HW_AUDIOOUT_HPVOL_SET); + /* Power down HP output */ + __raw_writel(BM_AUDIOOUT_PWRDN_HEADPHONE, + mxs_adc->aout_base + HW_AUDIOOUT_PWRDN_SET); + + /* Mute speaker amp */ + __raw_writel(BM_AUDIOOUT_SPEAKERCTRL_MUTE, + mxs_adc->aout_base + HW_AUDIOOUT_SPEAKERCTRL_SET); + /* Power down speaker amp */ + __raw_writel(BM_AUDIOOUT_PWRDN_SPEAKER, + mxs_adc->aout_base + HW_AUDIOOUT_PWRDN_SET); + + /* Mute DAC */ + __raw_writel(BM_AUDIOOUT_DACVOLUME_MUTE_LEFT | + BM_AUDIOOUT_DACVOLUME_MUTE_RIGHT, + mxs_adc->aout_base + HW_AUDIOOUT_DACVOLUME_SET); + /* Power down DAC */ + __raw_writel(BM_AUDIOOUT_PWRDN_DAC, + mxs_adc->aout_base + HW_AUDIOOUT_PWRDN_SET); + + /* Gate DAC clocks */ + __raw_writel(BM_AUDIOOUT_ANACLKCTRL_CLKGATE, + mxs_adc->aout_base + HW_AUDIOOUT_ANACLKCTRL_SET); + __raw_writel(BM_AUDIOOUT_CTRL_CLKGATE, + mxs_adc->aout_base + HW_AUDIOOUT_CTRL_SET); +} + +static void +mxs_codec_adc_power_on(struct mxs_adc_priv *mxs_adc) +{ + u32 reg; + + /* Ungate ADC clocks */ + __raw_writel(BM_AUDIOIN_CTRL_CLKGATE, + mxs_adc->ain_base + HW_AUDIOIN_CTRL_CLR); + __raw_writel(BM_AUDIOIN_ANACLKCTRL_CLKGATE, + mxs_adc->ain_base + HW_AUDIOIN_ANACLKCTRL_CLR); + + /* 16 bit word length */ + __raw_writel(BM_AUDIOIN_CTRL_WORD_LENGTH, + mxs_adc->ain_base + HW_AUDIOIN_CTRL_SET); + + /* Unmute ADC channels */ + __raw_writel(BM_AUDIOIN_ADCVOL_MUTE, + mxs_adc->ain_base + HW_AUDIOIN_ADCVOL_CLR); + + /* + * The MUTE_LEFT and MUTE_RIGHT fields need to be cleared. + * They aren't presented in the datasheet, so this is hardcode. + */ + __raw_writel(0x01000100, mxs_adc->ain_base + HW_AUDIOIN_ADCVOLUME_CLR); + + /* Set the Input channel gain 3dB */ + __raw_writel(BM_AUDIOIN_ADCVOL_GAIN_LEFT, + mxs_adc->ain_base + HW_AUDIOIN_ADCVOL_CLR); + __raw_writel(BM_AUDIOIN_ADCVOL_GAIN_RIGHT, + mxs_adc->ain_base + HW_AUDIOIN_ADCVOL_CLR); + __raw_writel(BF(2, AUDIOIN_ADCVOL_GAIN_LEFT), + mxs_adc->ain_base + HW_AUDIOIN_ADCVOL_SET); + __raw_writel(BF(2, AUDIOIN_ADCVOL_GAIN_RIGHT), + mxs_adc->ain_base + HW_AUDIOIN_ADCVOL_SET); + + /* Select default input - Microphone */ + __raw_writel(BM_AUDIOIN_ADCVOL_SELECT_LEFT, + mxs_adc->ain_base + HW_AUDIOIN_ADCVOL_CLR); + __raw_writel(BM_AUDIOIN_ADCVOL_SELECT_RIGHT, + mxs_adc->ain_base + HW_AUDIOIN_ADCVOL_CLR); + __raw_writel(BF + (BV_AUDIOIN_ADCVOL_SELECT__MIC, + AUDIOIN_ADCVOL_SELECT_LEFT), + mxs_adc->ain_base + HW_AUDIOIN_ADCVOL_SET); + __raw_writel(BF + (BV_AUDIOIN_ADCVOL_SELECT__MIC, + AUDIOIN_ADCVOL_SELECT_RIGHT), + mxs_adc->ain_base + HW_AUDIOIN_ADCVOL_SET); + + /* Supply bias voltage to microphone */ + __raw_writel(BF(1, AUDIOIN_MICLINE_MIC_RESISTOR), + mxs_adc->ain_base + HW_AUDIOIN_MICLINE_SET); + __raw_writel(BM_AUDIOIN_MICLINE_MIC_SELECT, + mxs_adc->ain_base + HW_AUDIOIN_MICLINE_SET); + __raw_writel(BF(1, AUDIOIN_MICLINE_MIC_GAIN), + mxs_adc->ain_base + HW_AUDIOIN_MICLINE_SET); + __raw_writel(BF(7, AUDIOIN_MICLINE_MIC_BIAS), + mxs_adc->ain_base + HW_AUDIOIN_MICLINE_SET); + + /* Set max ADC volume */ + reg = __raw_readl(mxs_adc->ain_base + HW_AUDIOIN_ADCVOLUME); + reg &= ~BM_AUDIOIN_ADCVOLUME_VOLUME_LEFT; + reg &= ~BM_AUDIOIN_ADCVOLUME_VOLUME_RIGHT; + reg |= BF(ADC_VOLUME_MAX, AUDIOIN_ADCVOLUME_VOLUME_LEFT); + reg |= BF(ADC_VOLUME_MAX, AUDIOIN_ADCVOLUME_VOLUME_RIGHT); + __raw_writel(reg, mxs_adc->ain_base + HW_AUDIOIN_ADCVOLUME); +} + +static void +mxs_codec_adc_power_down(struct mxs_adc_priv *mxs_adc) +{ + /* Mute ADC channels */ + __raw_writel(BM_AUDIOIN_ADCVOL_MUTE, + mxs_adc->ain_base + HW_AUDIOIN_ADCVOL_SET); + + /* Power Down ADC */ + __raw_writel(BM_AUDIOOUT_PWRDN_ADC | BM_AUDIOOUT_PWRDN_RIGHT_ADC, + mxs_adc->aout_base + HW_AUDIOOUT_PWRDN_SET); + + /* Gate ADC clocks */ + __raw_writel(BM_AUDIOIN_CTRL_CLKGATE, + mxs_adc->ain_base + HW_AUDIOIN_CTRL_SET); + __raw_writel(BM_AUDIOIN_ANACLKCTRL_CLKGATE, + mxs_adc->ain_base + HW_AUDIOIN_ANACLKCTRL_SET); + + /* Disable bias voltage to microphone */ + __raw_writel(BF(0, AUDIOIN_MICLINE_MIC_RESISTOR), + mxs_adc->ain_base + HW_AUDIOIN_MICLINE_SET); +} + +static void mxs_codec_dac_enable(struct mxs_adc_priv *mxs_adc) +{ + /* Move DAC codec out of reset */ + __raw_writel(BM_AUDIOOUT_CTRL_SFTRST, + mxs_adc->aout_base + HW_AUDIOOUT_CTRL_CLR); + + /* Reduce analog power */ + __raw_writel(BM_AUDIOOUT_TEST_HP_I1_ADJ, + mxs_adc->aout_base + HW_AUDIOOUT_TEST_CLR); + __raw_writel(BF(0x1, AUDIOOUT_TEST_HP_I1_ADJ), + mxs_adc->aout_base + HW_AUDIOOUT_TEST_SET); + __raw_writel(BM_AUDIOOUT_REFCTRL_LOW_PWR, + mxs_adc->aout_base + HW_AUDIOOUT_REFCTRL_SET); + __raw_writel(BM_AUDIOOUT_REFCTRL_XTAL_BGR_BIAS, + mxs_adc->aout_base + HW_AUDIOOUT_REFCTRL_SET); + __raw_writel(BM_AUDIOOUT_REFCTRL_BIAS_CTRL, + mxs_adc->aout_base + HW_AUDIOOUT_REFCTRL_CLR); + __raw_writel(BF(0x1, AUDIOOUT_REFCTRL_BIAS_CTRL), + mxs_adc->aout_base + HW_AUDIOOUT_REFCTRL_CLR); + + /* Set Vag value */ + mxs_codec_dac_set_vag(mxs_adc); + + /* Power on DAC codec */ + mxs_codec_dac_power_on(mxs_adc); +} + +static void mxs_codec_dac_disable(struct mxs_adc_priv *mxs_adc) +{ + mxs_codec_dac_power_down(mxs_adc); +} + +static void mxs_codec_adc_enable(struct mxs_adc_priv *mxs_adc) +{ + /* Move ADC codec out of reset */ + __raw_writel(BM_AUDIOIN_CTRL_SFTRST, + mxs_adc->ain_base + HW_AUDIOIN_CTRL_CLR); + + /* Power on ADC codec */ + mxs_codec_adc_power_on(mxs_adc); +} + +static void mxs_codec_adc_disable(struct mxs_adc_priv *mxs_adc) +{ + mxs_codec_adc_power_down(mxs_adc); +} + +static void mxs_codec_startup(struct snd_soc_codec *codec) +{ + struct mxs_adc_priv *mxs_adc = snd_soc_codec_get_drvdata(codec); + + /* Soft reset DAC block */ + __raw_writel(BM_AUDIOOUT_CTRL_SFTRST, + mxs_adc->aout_base + HW_AUDIOOUT_CTRL_SET); + while (!(__raw_readl(mxs_adc->aout_base + HW_AUDIOOUT_CTRL) + & BM_AUDIOOUT_CTRL_CLKGATE)){ + } + + /* Soft reset ADC block */ + __raw_writel(BM_AUDIOIN_CTRL_SFTRST, + mxs_adc->ain_base + HW_AUDIOIN_CTRL_SET); + while (!(__raw_readl(mxs_adc->ain_base + HW_AUDIOIN_CTRL) + & BM_AUDIOIN_CTRL_CLKGATE)){ + } + + mxs_codec_dac_enable(mxs_adc); + mxs_codec_adc_enable(mxs_adc); + + /* Sync regs and cache */ + mxs_codec_sync_reg_cache(codec); +} + +static void mxs_codec_stop(struct snd_soc_codec *codec) +{ + struct mxs_adc_priv *mxs_adc = snd_soc_codec_get_drvdata(codec); + + mxs_codec_dac_disable(mxs_adc); + mxs_codec_adc_disable(mxs_adc); +} +/* END Codec routines */ + +/* kcontrol */ +static int dac_info_volsw(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 2; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 0xf; + return 0; +} + +static int dac_get_volsw(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct mxs_adc_priv *mxs_adc = snd_soc_codec_get_drvdata(codec); + int reg, l, r; + int i; + + reg = __raw_readl(mxs_adc->aout_base + HW_AUDIOOUT_DACVOLUME); + + l = (reg & BM_AUDIOOUT_DACVOLUME_VOLUME_LEFT) >> + BP_AUDIOOUT_DACVOLUME_VOLUME_LEFT; + r = (reg & BM_AUDIOOUT_DACVOLUME_VOLUME_RIGHT) >> + BP_AUDIOOUT_DACVOLUME_VOLUME_RIGHT; + /*Left channel */ + i = 0; + while (i < 16) { + if (l == dac_volumn_control_word[i]) { + ucontrol->value.integer.value[0] = i; + break; + } + i++; + } + if (i == 16) + ucontrol->value.integer.value[0] = i; + /*Right channel */ + i = 0; + while (i < 16) { + if (r == dac_volumn_control_word[i]) { + ucontrol->value.integer.value[1] = i; + break; + } + i++; + } + if (i == 16) + ucontrol->value.integer.value[1] = i; + + return 0; +} + +static int dac_put_volsw(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct mxs_adc_priv *mxs_adc = snd_soc_codec_get_drvdata(codec); + int reg, l, r; + int i; + + i = ucontrol->value.integer.value[0]; + l = dac_volumn_control_word[i]; + /*Get dac volume for left channel */ + reg = BF(l, AUDIOOUT_DACVOLUME_VOLUME_LEFT); + + i = ucontrol->value.integer.value[1]; + r = dac_volumn_control_word[i]; + /*Get dac volume for right channel */ + reg = reg | BF(r, AUDIOOUT_DACVOLUME_VOLUME_RIGHT); + + /*Clear left/right dac volume */ + __raw_writel(BM_AUDIOOUT_DACVOLUME_VOLUME_LEFT | + BM_AUDIOOUT_DACVOLUME_VOLUME_RIGHT, + mxs_adc->aout_base + HW_AUDIOOUT_DACVOLUME_CLR); + __raw_writel(reg, mxs_adc->aout_base + HW_AUDIOOUT_DACVOLUME_SET); + + return 0; +} + +static const char *mxs_codec_adc_input_sel[] = { + "Mic", "Line In 1", "Head Phone", "Line In 2" }; + +static const char *mxs_codec_hp_output_sel[] = { "DAC Out", "Line In 1" }; + +static const char *mxs_codec_adc_3d_sel[] = { + "Off", "Low", "Medium", "High" }; + +static const struct soc_enum mxs_codec_enum[] = { + SOC_ENUM_SINGLE(ADC_ADCVOL_L, 12, 4, mxs_codec_adc_input_sel), + SOC_ENUM_SINGLE(ADC_ADCVOL_L, 4, 4, mxs_codec_adc_input_sel), + SOC_ENUM_SINGLE(DAC_HPVOL_H, 0, 2, mxs_codec_hp_output_sel), + SOC_ENUM_SINGLE(DAC_CTRL_L, 8, 4, mxs_codec_adc_3d_sel), +}; + +static const struct snd_kcontrol_new mxs_snd_controls[] = { + /* Playback Volume */ + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "DAC Playback Volume", + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = dac_info_volsw, + .get = dac_get_volsw, + .put = dac_put_volsw, + }, + + SOC_DOUBLE_R("DAC Playback Switch", + DAC_VOLUME_H, DAC_VOLUME_L, 8, 0x01, 1), + SOC_DOUBLE("HP Playback Volume", DAC_HPVOL_L, 8, 0, 0x7F, 1), + + /* Capture Volume */ + SOC_DOUBLE_R("ADC Capture Volume", + ADC_VOLUME_H, ADC_VOLUME_L, 0, 0xFF, 0), + SOC_DOUBLE("ADC PGA Capture Volume", ADC_ADCVOL_L, 8, 0, 0x0F, 0), + SOC_SINGLE("ADC PGA Capture Switch", ADC_ADCVOL_H, 8, 0x1, 1), + SOC_SINGLE("Mic PGA Capture Volume", ADC_MICLINE_L, 0, 0x03, 0), + + /* Virtual 3D effect */ + SOC_ENUM("3D effect", mxs_codec_enum[3]), +}; +/* END kcontrol */ + +/* DAPM */ +static int pga_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct mxs_adc_priv *mxs_adc = snd_soc_codec_get_drvdata(w->codec); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* Prepare powering up HP and SPEAKER output */ + __raw_writel(BM_AUDIOOUT_ANACTRL_HP_HOLD_GND, + mxs_adc->aout_base + HW_AUDIOOUT_ANACTRL_SET); + __raw_writel(BM_RTC_PERSISTENT0_RELEASE_GND, + mxs_adc->rtc_base + HW_RTC_PERSISTENT0_SET); + msleep(100); + break; + case SND_SOC_DAPM_POST_PMU: + __raw_writel(BM_AUDIOOUT_ANACTRL_HP_HOLD_GND, + mxs_adc->aout_base + HW_AUDIOOUT_ANACTRL_CLR); + break; + case SND_SOC_DAPM_POST_PMD: + __raw_writel(BM_RTC_PERSISTENT0_RELEASE_GND, + mxs_adc->rtc_base + HW_RTC_PERSISTENT0_CLR); + break; + } + return 0; +} + +static int adc_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct mxs_adc_priv *mxs_adc = snd_soc_codec_get_drvdata(w->codec); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + __raw_writel(BM_RTC_PERSISTENT0_RELEASE_GND, + mxs_adc->rtc_base + HW_RTC_PERSISTENT0_SET); + msleep(100); + break; + case SND_SOC_DAPM_POST_PMD: + __raw_writel(BM_RTC_PERSISTENT0_RELEASE_GND, + mxs_adc->rtc_base + HW_RTC_PERSISTENT0_CLR); + break; + } + return 0; +} + +/* Left ADC Mux */ +static const struct snd_kcontrol_new mxs_left_adc_controls = +SOC_DAPM_ENUM("Route", mxs_codec_enum[0]); + +/* Right ADC Mux */ +static const struct snd_kcontrol_new mxs_right_adc_controls = +SOC_DAPM_ENUM("Route", mxs_codec_enum[1]); + +/* Head Phone Mux */ +static const struct snd_kcontrol_new mxs_hp_controls = +SOC_DAPM_ENUM("Route", mxs_codec_enum[2]); + +static const struct snd_soc_dapm_widget mxs_dapm_widgets[] = { + SND_SOC_DAPM_ADC_E("ADC", "Capture", DAC_PWRDN_L, 8, 1, adc_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_DAC("DAC", "Playback", DAC_PWRDN_L, 12, 1), + + SND_SOC_DAPM_MUX("Left ADC Mux", SND_SOC_NOPM, 0, 0, + &mxs_left_adc_controls), + SND_SOC_DAPM_MUX("Right ADC Mux", SND_SOC_NOPM, 0, 0, + &mxs_right_adc_controls), + SND_SOC_DAPM_MUX("HP Mux", SND_SOC_NOPM, 0, 0, + &mxs_hp_controls), + SND_SOC_DAPM_PGA_E("HP AMP", DAC_PWRDN_L, 0, 1, NULL, 0, pga_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA("SPEAKER AMP", DAC_PWRDN_H, 8, 1, NULL, 0), + SND_SOC_DAPM_INPUT("LINE1L"), + SND_SOC_DAPM_INPUT("LINE1R"), + SND_SOC_DAPM_INPUT("LINE2L"), + SND_SOC_DAPM_INPUT("LINE2R"), + SND_SOC_DAPM_INPUT("MIC"), + + SND_SOC_DAPM_OUTPUT("SPEAKER"), + SND_SOC_DAPM_OUTPUT("HPL"), + SND_SOC_DAPM_OUTPUT("HPR"), +}; + +/* routes for sgtl5000 */ +static const struct snd_soc_dapm_route mxs_dapm_routes[] = { + /* Left ADC Mux */ + {"Left ADC Mux", "Mic", "MIC"}, + {"Left ADC Mux", "Line In 1", "LINE1L"}, + {"Left ADC Mux", "Line In 2", "LINE2L"}, + {"Left ADC Mux", "Head Phone", "HPL"}, + + /* Right ADC Mux */ + {"Right ADC Mux", "Mic", "MIC"}, + {"Right ADC Mux", "Line In 1", "LINE1R"}, + {"Right ADC Mux", "Line In 2", "LINE2R"}, + {"Right ADC Mux", "Head Phone", "HPR"}, + + /* ADC */ + {"ADC", NULL, "Left ADC Mux"}, + {"ADC", NULL, "Right ADC Mux"}, + + /* HP Mux */ + {"HP Mux", "DAC Out", "DAC"}, + {"HP Mux", "Line In 1", "LINE1L"}, + {"HP Mux", "Line In 1", "LINE1R"}, + + /* HP amp */ + {"HP AMP", NULL, "HP Mux"}, + /* HP output */ + {"HPR", NULL, "HP AMP"}, + {"HPL", NULL, "HP AMP"}, + + /* Speaker amp */ + {"SPEAKER AMP", NULL, "DAC"}, + {"SPEAKER", NULL, "SPEAKER AMP"}, +}; +/* END DAPM */ + +static int mxs_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + struct mxs_adc_priv *mxs_adc = snd_soc_codec_get_drvdata(codec); + + pr_debug("dapm level %d\n", level); + switch (level) { + case SND_SOC_BIAS_ON: /* full On */ + if (codec->dapm.bias_level == SND_SOC_BIAS_ON) + break; + break; + + case SND_SOC_BIAS_PREPARE: /* partial On */ + if (codec->dapm.bias_level == SND_SOC_BIAS_PREPARE) + break; + /* Set Capless mode */ + __raw_writel(BM_AUDIOOUT_PWRDN_CAPLESS, + mxs_adc->aout_base + HW_AUDIOOUT_PWRDN_CLR); + break; + + case SND_SOC_BIAS_STANDBY: /* Off, with power */ + if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) + break; + /* Unset Capless mode */ + __raw_writel(BM_AUDIOOUT_PWRDN_CAPLESS, + mxs_adc->aout_base + HW_AUDIOOUT_PWRDN_SET); + break; + + case SND_SOC_BIAS_OFF: /* Off, without power */ + if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) + break; + /* Unset Capless mode */ + __raw_writel(BM_AUDIOOUT_PWRDN_CAPLESS, + mxs_adc->aout_base + HW_AUDIOOUT_PWRDN_SET); + break; + } + + codec->dapm.bias_level = level; + return 0; +} + +/* MXS-ADC Codec DAI driver */ +static int mxs_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct mxs_adc_priv *mxs_adc = snd_soc_codec_get_drvdata(codec); + int playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 1 : 0; + int i; + u32 srr_value = 0; + u32 src_hold = 0; + + i = get_srr_values(params_rate(params)); + if (i < 0) + dev_warn(codec->dev, "codec doesn't support rate %d\n", + params_rate(params)); + else { + src_hold = srr_values[i].src_hold; + + srr_value = + BF(srr_values[i].basemult, AUDIOOUT_DACSRR_BASEMULT) | + BF(srr_values[i].src_int, AUDIOOUT_DACSRR_SRC_INT) | + BF(srr_values[i].src_frac, AUDIOOUT_DACSRR_SRC_FRAC) | + BF(src_hold, AUDIOOUT_DACSRR_SRC_HOLD); + + if (playback) + __raw_writel(srr_value, + mxs_adc->aout_base + HW_AUDIOOUT_DACSRR); + else + __raw_writel(srr_value, + mxs_adc->ain_base + HW_AUDIOIN_ADCSRR); + } + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + if (playback) + __raw_writel(BM_AUDIOOUT_CTRL_WORD_LENGTH, + mxs_adc->aout_base + HW_AUDIOOUT_CTRL_SET); + else + __raw_writel(BM_AUDIOIN_CTRL_WORD_LENGTH, + mxs_adc->ain_base + HW_AUDIOIN_CTRL_SET); + + break; + + case SNDRV_PCM_FORMAT_S32_LE: + if (playback) + __raw_writel(BM_AUDIOOUT_CTRL_WORD_LENGTH, + mxs_adc->aout_base + HW_AUDIOOUT_CTRL_CLR); + else + __raw_writel(BM_AUDIOIN_CTRL_WORD_LENGTH, + mxs_adc->ain_base + HW_AUDIOIN_CTRL_CLR); + + break; + + default: + dev_warn(codec->dev, "codec doesn't support format %d\n", + params_format(params)); + + } + + return 0; +} + +/* mute the codec used by alsa core */ +static int mxs_codec_dig_mute(struct snd_soc_dai *codec_dai, int mute) +{ + struct mxs_adc_priv *mxs_adc = snd_soc_codec_get_drvdata(codec_dai->codec); + int l, r; + int ll, rr; + u32 reg, reg1, reg2; + u32 dac_mask = BM_AUDIOOUT_DACVOLUME_MUTE_LEFT | + BM_AUDIOOUT_DACVOLUME_MUTE_RIGHT; + + if (mute) { + reg = __raw_readl(mxs_adc->aout_base + \ + HW_AUDIOOUT_DACVOLUME); + + reg1 = reg & ~BM_AUDIOOUT_DACVOLUME_VOLUME_LEFT; + reg1 = reg1 & ~BM_AUDIOOUT_DACVOLUME_VOLUME_RIGHT; + + l = (reg & BM_AUDIOOUT_DACVOLUME_VOLUME_LEFT) >> + BP_AUDIOOUT_DACVOLUME_VOLUME_LEFT; + r = (reg & BM_AUDIOOUT_DACVOLUME_VOLUME_RIGHT) >> + BP_AUDIOOUT_DACVOLUME_VOLUME_RIGHT; + + /* fade out dac vol */ + while ((l > DAC_VOLUME_MIN) || (r > DAC_VOLUME_MIN)) { + l -= 0x8; + r -= 0x8; + ll = l > DAC_VOLUME_MIN ? l : DAC_VOLUME_MIN; + rr = r > DAC_VOLUME_MIN ? r : DAC_VOLUME_MIN; + reg2 = reg1 | BF_AUDIOOUT_DACVOLUME_VOLUME_LEFT(ll) + | BF_AUDIOOUT_DACVOLUME_VOLUME_RIGHT(rr); + __raw_writel(reg2, + mxs_adc->aout_base + HW_AUDIOOUT_DACVOLUME); + msleep(1); + } + + __raw_writel(dac_mask, + mxs_adc->aout_base + HW_AUDIOOUT_DACVOLUME_SET); + reg = reg | dac_mask; + __raw_writel(reg, + mxs_adc->aout_base + HW_AUDIOOUT_DACVOLUME); + } else + __raw_writel(dac_mask, + mxs_adc->aout_base + HW_AUDIOOUT_DACVOLUME_CLR); + + return 0; +} + +#define MXS_ADC_RATES SNDRV_PCM_RATE_8000_192000 +#define MXS_ADC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE) + +static const struct snd_soc_dai_ops mxs_codec_dai_ops = { + .hw_params = mxs_pcm_hw_params, + .digital_mute = mxs_codec_dig_mute, +}; + +static struct snd_soc_dai_driver mxs_codec_dai_driver = { + .name = "mxs-builtin-codec-dai", + .playback = { + .stream_name = "Playback", + .channels_min = 2, + .channels_max = 2, + .rates = MXS_ADC_RATES, + .formats = MXS_ADC_FORMATS, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 2, + .channels_max = 2, + .rates = MXS_ADC_RATES, + .formats = MXS_ADC_FORMATS, + }, + .ops = &mxs_codec_dai_ops, +}; +/* END MXS-ADC Codec DAI driver */ + +/* MXS-ADC Codec driver */ +static int mxs_codec_driver_probe(struct snd_soc_codec *codec) +{ + int ret = 0; + /* We don't use snd_soc_codec_set_cache_io because we are using + * our own IO functions: write, read. */ + + mxs_codec_startup(codec); + + /* leading to standby state */ + ret = mxs_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + if (ret) + goto err; + + return 0; + +err: + mxs_codec_stop(codec); + + return ret; +} + +static int mxs_codec_driver_remove(struct snd_soc_codec *codec) +{ + mxs_codec_stop(codec); + + return 0; +} + +// static int mxs_codec_driver_suspend(struct snd_soc_codec *codec) +// { +// /* TODO Enable power management. */ +// return 0; +// } + +// static int mxs_codec_driver_resume(struct snd_soc_codec *codec) +// { +// /* TODO Enable power management. */ +// return 0; +// } + +static struct snd_soc_codec_driver mxs_codec_driver = { + .probe = mxs_codec_driver_probe, + .remove = mxs_codec_driver_remove, +// .suspend = mxs_codec_driver_suspend, +// .resume = mxs_codec_driver_resume, + .set_bias_level = mxs_set_bias_level, + .reg_cache_size = ADC_REGNUM, + .reg_word_size = sizeof(u16), + .reg_cache_step = 1, +// .reg_cache_default = mxsadc_regs, +// .volatile_register = sgtl5000_volatile_register, + .controls = mxs_snd_controls, + .num_controls = ARRAY_SIZE(mxs_snd_controls), + .dapm_widgets = mxs_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(mxs_dapm_widgets), + .dapm_routes = mxs_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(mxs_dapm_routes), + .write = mxs_codec_write, + .read = mxs_codec_read, +}; +/* END MXS-ADC Codec driver */ + +/* Underlying platform device that registers codec */ +static int mxs_adc_probe(struct platform_device *pdev) +{ + struct mxs_adc_priv *mxs_adc; + struct resource *r; + int ret; + + mxs_adc = devm_kzalloc(&pdev->dev, sizeof(struct mxs_adc_priv), GFP_KERNEL); + if (!mxs_adc) + return -ENOMEM; + + platform_set_drvdata(pdev, mxs_adc); + + /* audio-in IO memory */ + r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "audioin"); + if (IS_ERR(r)) { + dev_err(&pdev->dev, "failed to get resource\n"); + return PTR_ERR(r); + } + + mxs_adc->ain_base = devm_ioremap(&pdev->dev, r->start, resource_size(r)); + if (IS_ERR(mxs_adc->ain_base)) { + dev_err(&pdev->dev, "ioremap failed\n"); + return PTR_ERR(mxs_adc->ain_base); + } + + /* audio-out IO memory */ + r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "audioout"); + if (IS_ERR(r)) { + dev_err(&pdev->dev, "failed to get resource\n"); + return PTR_ERR(r); + } + + mxs_adc->aout_base = devm_ioremap(&pdev->dev, r->start, resource_size(r)); + if (IS_ERR(mxs_adc->aout_base)) { + dev_err(&pdev->dev, "ioremap failed\n"); + return PTR_ERR(mxs_adc->aout_base); + } + + /* rtc IO memory */ + r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rtc"); + if (IS_ERR(r)) { + dev_err(&pdev->dev, "failed to get resource\n"); + return PTR_ERR(r); + } + + mxs_adc->rtc_base = devm_ioremap(&pdev->dev, r->start, resource_size(r)); + if (IS_ERR(mxs_adc->rtc_base)) { + dev_err(&pdev->dev, "ioremap failed\n"); + return PTR_ERR(mxs_adc->rtc_base); + } + + /* Get audio clock */ + mxs_adc->clk = devm_clk_get(&pdev->dev, "filt"); + if (IS_ERR(mxs_adc->clk)) { + ret = PTR_ERR(mxs_adc->clk); + dev_err(&pdev->dev, "%s: Clock initialization failed\n", __func__); + return ret; + } + + /* Turn on audio clock */ + ret = clk_prepare_enable(mxs_adc->clk); + if (unlikely(ret != 0)) { + dev_err(&pdev->dev, "%s: Clock prepare or enable failed\n", __func__); + return ret; + } + + ret = snd_soc_register_codec(&pdev->dev, + &mxs_codec_driver,&mxs_codec_dai_driver, 1); + if (unlikely(ret != 0)) { + dev_err(&pdev->dev, "Codec registration failed\n"); + goto disable_clk; + } + + return 0; + +disable_clk: + clk_disable_unprepare(mxs_adc->clk); + return ret; +} + +static int mxs_adc_remove(struct platform_device *pdev) +{ + struct mxs_adc_priv *mxs_adc = platform_get_drvdata(pdev); + + clk_disable_unprepare(mxs_adc->clk); + snd_soc_unregister_codec(&pdev->dev); + + return 0; +} + +static const struct of_device_id mxs_adc_dt_ids[] = { + { .compatible = "fsl,mxs-builtin-codec", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, mxs_adc_dt_ids); + +static struct platform_driver mxs_adc_driver = { + .driver = { + .name = "mxs-builtin-codec", + .owner = THIS_MODULE, + .of_match_table = mxs_adc_dt_ids, + }, + .probe = mxs_adc_probe, + .remove = mxs_adc_remove, +}; + +module_platform_driver(mxs_adc_driver); +/* END Underlying platform device that registers codec */ + +MODULE_DESCRIPTION("Freescale MXS ADC/DAC SoC Codec Driver"); +MODULE_AUTHOR("Michal Ulianko "); +MODULE_LICENSE("GPL"); --- /dev/null +++ b/sound/soc/codecs/mxs-builtin-codec.h @@ -0,0 +1,825 @@ +#ifndef __MXS_ADC_CODEC_H + +#include + +/* MXS ADC/DAC registers */ +#define DAC_CTRL_L 0 +#define DAC_CTRL_H 1 +#define DAC_STAT_L 2 +#define DAC_STAT_H 3 +#define DAC_SRR_L 4 +#define DAC_VOLUME_L 6 +#define DAC_VOLUME_H 7 +#define DAC_DEBUG_L 8 +#define DAC_DEBUG_H 9 +#define DAC_HPVOL_L 10 +#define DAC_HPVOL_H 11 +#define DAC_PWRDN_L 12 +#define DAC_PWRDN_H 13 +#define DAC_REFCTRL_L 14 +#define DAC_REFCTRL_H 15 +#define DAC_ANACTRL_L 16 +#define DAC_ANACTRL_H 17 +#define DAC_TEST_L 18 +#define DAC_TEST_H 19 +#define DAC_BISTCTRL_L 20 +#define DAC_BISTCTRL_H 21 +#define DAC_BISTSTAT0_L 22 +#define DAC_BISTSTAT0_H 23 +#define DAC_BISTSTAT1_L 24 +#define DAC_BISTSTAT1_H 25 +#define DAC_ANACLKCTRL_L 26 +#define DAC_ANACLKCTRL_H 27 +#define DAC_DATA_L 28 +#define DAC_DATA_H 29 +#define DAC_SPEAKERCTRL_L 30 +#define DAC_SPEAKERCTRL_H 31 +#define DAC_VERSION_L 32 +#define DAC_VERSION_H 33 +#define ADC_CTRL_L 34 +#define ADC_CTRL_H 35 +#define ADC_STAT_L 36 +#define ADC_STAT_H 37 +#define ADC_SRR_L 38 +#define ADC_SRR_H 39 +#define ADC_VOLUME_L 40 +#define ADC_VOLUME_H 41 +#define ADC_DEBUG_L 42 +#define ADC_DEBUG_H 43 +#define ADC_ADCVOL_L 44 +#define ADC_ADCVOL_H 45 +#define ADC_MICLINE_L 46 +#define ADC_MICLINE_H 47 +#define ADC_ANACLKCTRL_L 48 +#define ADC_ANACLKCTRL_H 49 +#define ADC_DATA_L 50 +#define ADC_DATA_H 51 + +#define ADC_REGNUM 52 + +#define DAC_VOLUME_MIN 0x37 +#define DAC_VOLUME_MAX 0xFE +#define ADC_VOLUME_MIN 0x37 +#define ADC_VOLUME_MAX 0xFE +#define HP_VOLUME_MAX 0x0 +#define HP_VOLUME_MIN 0x7F +#define LO_VOLUME_MAX 0x0 +#define LO_VOLUME_MIN 0x1F + +/* RTC */ +#define HW_RTC_PERSISTENT0 (0x00000060) +#define HW_RTC_PERSISTENT0_SET (0x00000064) +#define HW_RTC_PERSISTENT0_CLR (0x00000068) +#define HW_RTC_PERSISTENT0_TOG (0x0000006c) + +// TODO +//#define BM_RTC_PERSISTENT0_RELEASE_GND 0x00080000 + +/* AUDIOOUT */ +#define HW_AUDIOOUT_CTRL (0x00000000) +#define HW_AUDIOOUT_CTRL_SET (0x00000004) +#define HW_AUDIOOUT_CTRL_CLR (0x00000008) +#define HW_AUDIOOUT_CTRL_TOG (0x0000000c) + +#define BM_AUDIOOUT_CTRL_SFTRST 0x80000000 +#define BM_AUDIOOUT_CTRL_CLKGATE 0x40000000 +#define BP_AUDIOOUT_CTRL_RSRVD4 21 +#define BM_AUDIOOUT_CTRL_RSRVD4 0x3FE00000 +#define BF_AUDIOOUT_CTRL_RSRVD4(v) \ + (((v) << 21) & BM_AUDIOOUT_CTRL_RSRVD4) +#define BP_AUDIOOUT_CTRL_DMAWAIT_COUNT 16 +#define BM_AUDIOOUT_CTRL_DMAWAIT_COUNT 0x001F0000 +#define BF_AUDIOOUT_CTRL_DMAWAIT_COUNT(v) \ + (((v) << 16) & BM_AUDIOOUT_CTRL_DMAWAIT_COUNT) +#define BM_AUDIOOUT_CTRL_RSRVD3 0x00008000 +#define BM_AUDIOOUT_CTRL_LR_SWAP 0x00004000 +#define BM_AUDIOOUT_CTRL_EDGE_SYNC 0x00002000 +#define BM_AUDIOOUT_CTRL_INVERT_1BIT 0x00001000 +#define BP_AUDIOOUT_CTRL_RSRVD2 10 +#define BM_AUDIOOUT_CTRL_RSRVD2 0x00000C00 +#define BF_AUDIOOUT_CTRL_RSRVD2(v) \ + (((v) << 10) & BM_AUDIOOUT_CTRL_RSRVD2) +#define BP_AUDIOOUT_CTRL_SS3D_EFFECT 8 +#define BM_AUDIOOUT_CTRL_SS3D_EFFECT 0x00000300 +#define BF_AUDIOOUT_CTRL_SS3D_EFFECT(v) \ + (((v) << 8) & BM_AUDIOOUT_CTRL_SS3D_EFFECT) +#define BM_AUDIOOUT_CTRL_RSRVD1 0x00000080 +#define BM_AUDIOOUT_CTRL_WORD_LENGTH 0x00000040 +#define BM_AUDIOOUT_CTRL_DAC_ZERO_ENABLE 0x00000020 +#define BM_AUDIOOUT_CTRL_LOOPBACK 0x00000010 +#define BM_AUDIOOUT_CTRL_FIFO_UNDERFLOW_IRQ 0x00000008 +#define BM_AUDIOOUT_CTRL_FIFO_OVERFLOW_IRQ 0x00000004 +#define BM_AUDIOOUT_CTRL_FIFO_ERROR_IRQ_EN 0x00000002 +#define BM_AUDIOOUT_CTRL_RUN 0x00000001 + +#define HW_AUDIOOUT_STAT (0x00000010) +#define HW_AUDIOOUT_STAT_SET (0x00000014) +#define HW_AUDIOOUT_STAT_CLR (0x00000018) +#define HW_AUDIOOUT_STAT_TOG (0x0000001c) + +#define BM_AUDIOOUT_STAT_DAC_PRESENT 0x80000000 +#define BP_AUDIOOUT_STAT_RSRVD1 0 +#define BM_AUDIOOUT_STAT_RSRVD1 0x7FFFFFFF +#define BF_AUDIOOUT_STAT_RSRVD1(v) \ + (((v) << 0) & BM_AUDIOOUT_STAT_RSRVD1) + +#define HW_AUDIOOUT_DACSRR (0x00000020) +#define HW_AUDIOOUT_DACSRR_SET (0x00000024) +#define HW_AUDIOOUT_DACSRR_CLR (0x00000028) +#define HW_AUDIOOUT_DACSRR_TOG (0x0000002c) + +#define BM_AUDIOOUT_DACSRR_OSR 0x80000000 +#define BV_AUDIOOUT_DACSRR_OSR__OSR6 0x0 +#define BV_AUDIOOUT_DACSRR_OSR__OSR12 0x1 +#define BP_AUDIOOUT_DACSRR_BASEMULT 28 +#define BM_AUDIOOUT_DACSRR_BASEMULT 0x70000000 +#define BF_AUDIOOUT_DACSRR_BASEMULT(v) \ + (((v) << 28) & BM_AUDIOOUT_DACSRR_BASEMULT) +#define BV_AUDIOOUT_DACSRR_BASEMULT__SINGLE_RATE 0x1 +#define BV_AUDIOOUT_DACSRR_BASEMULT__DOUBLE_RATE 0x2 +#define BV_AUDIOOUT_DACSRR_BASEMULT__QUAD_RATE 0x4 +#define BM_AUDIOOUT_DACSRR_RSRVD2 0x08000000 +#define BP_AUDIOOUT_DACSRR_SRC_HOLD 24 +#define BM_AUDIOOUT_DACSRR_SRC_HOLD 0x07000000 +#define BF_AUDIOOUT_DACSRR_SRC_HOLD(v) \ + (((v) << 24) & BM_AUDIOOUT_DACSRR_SRC_HOLD) +#define BP_AUDIOOUT_DACSRR_RSRVD1 21 +#define BM_AUDIOOUT_DACSRR_RSRVD1 0x00E00000 +#define BF_AUDIOOUT_DACSRR_RSRVD1(v) \ + (((v) << 21) & BM_AUDIOOUT_DACSRR_RSRVD1) +#define BP_AUDIOOUT_DACSRR_SRC_INT 16 +#define BM_AUDIOOUT_DACSRR_SRC_INT 0x001F0000 +#define BF_AUDIOOUT_DACSRR_SRC_INT(v) \ + (((v) << 16) & BM_AUDIOOUT_DACSRR_SRC_INT) +#define BP_AUDIOOUT_DACSRR_RSRVD0 13 +#define BM_AUDIOOUT_DACSRR_RSRVD0 0x0000E000 +#define BF_AUDIOOUT_DACSRR_RSRVD0(v) \ + (((v) << 13) & BM_AUDIOOUT_DACSRR_RSRVD0) +#define BP_AUDIOOUT_DACSRR_SRC_FRAC 0 +#define BM_AUDIOOUT_DACSRR_SRC_FRAC 0x00001FFF +#define BF_AUDIOOUT_DACSRR_SRC_FRAC(v) \ + (((v) << 0) & BM_AUDIOOUT_DACSRR_SRC_FRAC) + +#define HW_AUDIOOUT_DACVOLUME (0x00000030) +#define HW_AUDIOOUT_DACVOLUME_SET (0x00000034) +#define HW_AUDIOOUT_DACVOLUME_CLR (0x00000038) +#define HW_AUDIOOUT_DACVOLUME_TOG (0x0000003c) + +#define BP_AUDIOOUT_DACVOLUME_RSRVD4 29 +#define BM_AUDIOOUT_DACVOLUME_RSRVD4 0xE0000000 +#define BF_AUDIOOUT_DACVOLUME_RSRVD4(v) \ + (((v) << 29) & BM_AUDIOOUT_DACVOLUME_RSRVD4) +#define BM_AUDIOOUT_DACVOLUME_VOLUME_UPDATE_LEFT 0x10000000 +#define BP_AUDIOOUT_DACVOLUME_RSRVD3 26 +#define BM_AUDIOOUT_DACVOLUME_RSRVD3 0x0C000000 +#define BF_AUDIOOUT_DACVOLUME_RSRVD3(v) \ + (((v) << 26) & BM_AUDIOOUT_DACVOLUME_RSRVD3) +#define BM_AUDIOOUT_DACVOLUME_EN_ZCD 0x02000000 +#define BM_AUDIOOUT_DACVOLUME_MUTE_LEFT 0x01000000 +#define BP_AUDIOOUT_DACVOLUME_VOLUME_LEFT 16 +#define BM_AUDIOOUT_DACVOLUME_VOLUME_LEFT 0x00FF0000 +#define BF_AUDIOOUT_DACVOLUME_VOLUME_LEFT(v) \ + (((v) << 16) & BM_AUDIOOUT_DACVOLUME_VOLUME_LEFT) +#define BP_AUDIOOUT_DACVOLUME_RSRVD2 13 +#define BM_AUDIOOUT_DACVOLUME_RSRVD2 0x0000E000 +#define BF_AUDIOOUT_DACVOLUME_RSRVD2(v) \ + (((v) << 13) & BM_AUDIOOUT_DACVOLUME_RSRVD2) +#define BM_AUDIOOUT_DACVOLUME_VOLUME_UPDATE_RIGHT 0x00001000 +#define BP_AUDIOOUT_DACVOLUME_RSRVD1 9 +#define BM_AUDIOOUT_DACVOLUME_RSRVD1 0x00000E00 +#define BF_AUDIOOUT_DACVOLUME_RSRVD1(v) \ + (((v) << 9) & BM_AUDIOOUT_DACVOLUME_RSRVD1) +#define BM_AUDIOOUT_DACVOLUME_MUTE_RIGHT 0x00000100 +#define BP_AUDIOOUT_DACVOLUME_VOLUME_RIGHT 0 +#define BM_AUDIOOUT_DACVOLUME_VOLUME_RIGHT 0x000000FF +#define BF_AUDIOOUT_DACVOLUME_VOLUME_RIGHT(v) \ + (((v) << 0) & BM_AUDIOOUT_DACVOLUME_VOLUME_RIGHT) + +#define HW_AUDIOOUT_DACDEBUG (0x00000040) +#define HW_AUDIOOUT_DACDEBUG_SET (0x00000044) +#define HW_AUDIOOUT_DACDEBUG_CLR (0x00000048) +#define HW_AUDIOOUT_DACDEBUG_TOG (0x0000004c) + +#define BM_AUDIOOUT_DACDEBUG_ENABLE_DACDMA 0x80000000 +#define BP_AUDIOOUT_DACDEBUG_RSRVD2 12 +#define BM_AUDIOOUT_DACDEBUG_RSRVD2 0x7FFFF000 +#define BF_AUDIOOUT_DACDEBUG_RSRVD2(v) \ + (((v) << 12) & BM_AUDIOOUT_DACDEBUG_RSRVD2) +#define BP_AUDIOOUT_DACDEBUG_RAM_SS 8 +#define BM_AUDIOOUT_DACDEBUG_RAM_SS 0x00000F00 +#define BF_AUDIOOUT_DACDEBUG_RAM_SS(v) \ + (((v) << 8) & BM_AUDIOOUT_DACDEBUG_RAM_SS) +#define BP_AUDIOOUT_DACDEBUG_RSRVD1 6 +#define BM_AUDIOOUT_DACDEBUG_RSRVD1 0x000000C0 +#define BF_AUDIOOUT_DACDEBUG_RSRVD1(v) \ + (((v) << 6) & BM_AUDIOOUT_DACDEBUG_RSRVD1) +#define BM_AUDIOOUT_DACDEBUG_SET_INTERRUPT1_CLK_CROSS 0x00000020 +#define BM_AUDIOOUT_DACDEBUG_SET_INTERRUPT0_CLK_CROSS 0x00000010 +#define BM_AUDIOOUT_DACDEBUG_SET_INTERRUPT1_HAND_SHAKE 0x00000008 +#define BM_AUDIOOUT_DACDEBUG_SET_INTERRUPT0_HAND_SHAKE 0x00000004 +#define BM_AUDIOOUT_DACDEBUG_DMA_PREQ 0x00000002 +#define BM_AUDIOOUT_DACDEBUG_FIFO_STATUS 0x00000001 + +#define HW_AUDIOOUT_HPVOL (0x00000050) +#define HW_AUDIOOUT_HPVOL_SET (0x00000054) +#define HW_AUDIOOUT_HPVOL_CLR (0x00000058) +#define HW_AUDIOOUT_HPVOL_TOG (0x0000005c) + +#define BP_AUDIOOUT_HPVOL_RSRVD5 29 +#define BM_AUDIOOUT_HPVOL_RSRVD5 0xE0000000 +#define BF_AUDIOOUT_HPVOL_RSRVD5(v) \ + (((v) << 29) & BM_AUDIOOUT_HPVOL_RSRVD5) +#define BM_AUDIOOUT_HPVOL_VOLUME_UPDATE_PENDING 0x10000000 +#define BP_AUDIOOUT_HPVOL_RSRVD4 26 +#define BM_AUDIOOUT_HPVOL_RSRVD4 0x0C000000 +#define BF_AUDIOOUT_HPVOL_RSRVD4(v) \ + (((v) << 26) & BM_AUDIOOUT_HPVOL_RSRVD4) +#define BM_AUDIOOUT_HPVOL_EN_MSTR_ZCD 0x02000000 +#define BM_AUDIOOUT_HPVOL_MUTE 0x01000000 +#define BP_AUDIOOUT_HPVOL_RSRVD3 17 +#define BM_AUDIOOUT_HPVOL_RSRVD3 0x00FE0000 +#define BF_AUDIOOUT_HPVOL_RSRVD3(v) \ + (((v) << 17) & BM_AUDIOOUT_HPVOL_RSRVD3) +#define BM_AUDIOOUT_HPVOL_SELECT 0x00010000 +#define BM_AUDIOOUT_HPVOL_RSRVD2 0x00008000 +#define BP_AUDIOOUT_HPVOL_VOL_LEFT 8 +#define BM_AUDIOOUT_HPVOL_VOL_LEFT 0x00007F00 +#define BF_AUDIOOUT_HPVOL_VOL_LEFT(v) \ + (((v) << 8) & BM_AUDIOOUT_HPVOL_VOL_LEFT) +#define BM_AUDIOOUT_HPVOL_RSRVD1 0x00000080 +#define BP_AUDIOOUT_HPVOL_VOL_RIGHT 0 +#define BM_AUDIOOUT_HPVOL_VOL_RIGHT 0x0000007F +#define BF_AUDIOOUT_HPVOL_VOL_RIGHT(v) \ + (((v) << 0) & BM_AUDIOOUT_HPVOL_VOL_RIGHT) + +#define HW_AUDIOOUT_RESERVED (0x00000060) +#define HW_AUDIOOUT_RESERVED_SET (0x00000064) +#define HW_AUDIOOUT_RESERVED_CLR (0x00000068) +#define HW_AUDIOOUT_RESERVED_TOG (0x0000006c) + +#define BP_AUDIOOUT_RESERVED_RSRVD1 0 +#define BM_AUDIOOUT_RESERVED_RSRVD1 0xFFFFFFFF +#define BF_AUDIOOUT_RESERVED_RSRVD1(v) (v) + +#define HW_AUDIOOUT_PWRDN (0x00000070) +#define HW_AUDIOOUT_PWRDN_SET (0x00000074) +#define HW_AUDIOOUT_PWRDN_CLR (0x00000078) +#define HW_AUDIOOUT_PWRDN_TOG (0x0000007c) + +#define BP_AUDIOOUT_PWRDN_RSRVD7 25 +#define BM_AUDIOOUT_PWRDN_RSRVD7 0xFE000000 +#define BF_AUDIOOUT_PWRDN_RSRVD7(v) \ + (((v) << 25) & BM_AUDIOOUT_PWRDN_RSRVD7) +#define BM_AUDIOOUT_PWRDN_SPEAKER 0x01000000 +#define BP_AUDIOOUT_PWRDN_RSRVD6 21 +#define BM_AUDIOOUT_PWRDN_RSRVD6 0x00E00000 +#define BF_AUDIOOUT_PWRDN_RSRVD6(v) \ + (((v) << 21) & BM_AUDIOOUT_PWRDN_RSRVD6) +#define BM_AUDIOOUT_PWRDN_SELFBIAS 0x00100000 +#define BP_AUDIOOUT_PWRDN_RSRVD5 17 +#define BM_AUDIOOUT_PWRDN_RSRVD5 0x000E0000 +#define BF_AUDIOOUT_PWRDN_RSRVD5(v) \ + (((v) << 17) & BM_AUDIOOUT_PWRDN_RSRVD5) +#define BM_AUDIOOUT_PWRDN_RIGHT_ADC 0x00010000 +#define BP_AUDIOOUT_PWRDN_RSRVD4 13 +#define BM_AUDIOOUT_PWRDN_RSRVD4 0x0000E000 +#define BF_AUDIOOUT_PWRDN_RSRVD4(v) \ + (((v) << 13) & BM_AUDIOOUT_PWRDN_RSRVD4) +#define BM_AUDIOOUT_PWRDN_DAC 0x00001000 +#define BP_AUDIOOUT_PWRDN_RSRVD3 9 +#define BM_AUDIOOUT_PWRDN_RSRVD3 0x00000E00 +#define BF_AUDIOOUT_PWRDN_RSRVD3(v) \ + (((v) << 9) & BM_AUDIOOUT_PWRDN_RSRVD3) +#define BM_AUDIOOUT_PWRDN_ADC 0x00000100 +#define BP_AUDIOOUT_PWRDN_RSRVD2 5 +#define BM_AUDIOOUT_PWRDN_RSRVD2 0x000000E0 +#define BF_AUDIOOUT_PWRDN_RSRVD2(v) \ + (((v) << 5) & BM_AUDIOOUT_PWRDN_RSRVD2) +#define BM_AUDIOOUT_PWRDN_CAPLESS 0x00000010 +#define BP_AUDIOOUT_PWRDN_RSRVD1 1 +#define BM_AUDIOOUT_PWRDN_RSRVD1 0x0000000E +#define BF_AUDIOOUT_PWRDN_RSRVD1(v) \ + (((v) << 1) & BM_AUDIOOUT_PWRDN_RSRVD1) +#define BM_AUDIOOUT_PWRDN_HEADPHONE 0x00000001 + +#define HW_AUDIOOUT_REFCTRL (0x00000080) +#define HW_AUDIOOUT_REFCTRL_SET (0x00000084) +#define HW_AUDIOOUT_REFCTRL_CLR (0x00000088) +#define HW_AUDIOOUT_REFCTRL_TOG (0x0000008c) + +#define BP_AUDIOOUT_REFCTRL_RSRVD4 27 +#define BM_AUDIOOUT_REFCTRL_RSRVD4 0xF8000000 +#define BF_AUDIOOUT_REFCTRL_RSRVD4(v) \ + (((v) << 27) & BM_AUDIOOUT_REFCTRL_RSRVD4) +#define BM_AUDIOOUT_REFCTRL_FASTSETTLING 0x04000000 +#define BM_AUDIOOUT_REFCTRL_RAISE_REF 0x02000000 +#define BM_AUDIOOUT_REFCTRL_XTAL_BGR_BIAS 0x01000000 +#define BM_AUDIOOUT_REFCTRL_RSRVD3 0x00800000 +#define BP_AUDIOOUT_REFCTRL_VBG_ADJ 20 +#define BM_AUDIOOUT_REFCTRL_VBG_ADJ 0x00700000 +#define BF_AUDIOOUT_REFCTRL_VBG_ADJ(v) \ + (((v) << 20) & BM_AUDIOOUT_REFCTRL_VBG_ADJ) +#define BM_AUDIOOUT_REFCTRL_LOW_PWR 0x00080000 +#define BM_AUDIOOUT_REFCTRL_LW_REF 0x00040000 +#define BP_AUDIOOUT_REFCTRL_BIAS_CTRL 16 +#define BM_AUDIOOUT_REFCTRL_BIAS_CTRL 0x00030000 +#define BF_AUDIOOUT_REFCTRL_BIAS_CTRL(v) \ + (((v) << 16) & BM_AUDIOOUT_REFCTRL_BIAS_CTRL) +#define BM_AUDIOOUT_REFCTRL_RSRVD2 0x00008000 +#define BM_AUDIOOUT_REFCTRL_VDDXTAL_TO_VDDD 0x00004000 +#define BM_AUDIOOUT_REFCTRL_ADJ_ADC 0x00002000 +#define BM_AUDIOOUT_REFCTRL_ADJ_VAG 0x00001000 +#define BP_AUDIOOUT_REFCTRL_ADC_REFVAL 8 +#define BM_AUDIOOUT_REFCTRL_ADC_REFVAL 0x00000F00 +#define BF_AUDIOOUT_REFCTRL_ADC_REFVAL(v) \ + (((v) << 8) & BM_AUDIOOUT_REFCTRL_ADC_REFVAL) +#define BP_AUDIOOUT_REFCTRL_VAG_VAL 4 +#define BM_AUDIOOUT_REFCTRL_VAG_VAL 0x000000F0 +#define BF_AUDIOOUT_REFCTRL_VAG_VAL(v) \ + (((v) << 4) & BM_AUDIOOUT_REFCTRL_VAG_VAL) +#define BM_AUDIOOUT_REFCTRL_RSRVD1 0x00000008 +#define BP_AUDIOOUT_REFCTRL_DAC_ADJ 0 +#define BM_AUDIOOUT_REFCTRL_DAC_ADJ 0x00000007 +#define BF_AUDIOOUT_REFCTRL_DAC_ADJ(v) \ + (((v) << 0) & BM_AUDIOOUT_REFCTRL_DAC_ADJ) + +#define HW_AUDIOOUT_ANACTRL (0x00000090) +#define HW_AUDIOOUT_ANACTRL_SET (0x00000094) +#define HW_AUDIOOUT_ANACTRL_CLR (0x00000098) +#define HW_AUDIOOUT_ANACTRL_TOG (0x0000009c) + +#define BP_AUDIOOUT_ANACTRL_RSRVD8 29 +#define BM_AUDIOOUT_ANACTRL_RSRVD8 0xE0000000 +#define BF_AUDIOOUT_ANACTRL_RSRVD8(v) \ + (((v) << 29) & BM_AUDIOOUT_ANACTRL_RSRVD8) +#define BM_AUDIOOUT_ANACTRL_SHORT_CM_STS 0x10000000 +#define BP_AUDIOOUT_ANACTRL_RSRVD7 25 +#define BM_AUDIOOUT_ANACTRL_RSRVD7 0x0E000000 +#define BF_AUDIOOUT_ANACTRL_RSRVD7(v) \ + (((v) << 25) & BM_AUDIOOUT_ANACTRL_RSRVD7) +#define BM_AUDIOOUT_ANACTRL_SHORT_LR_STS 0x01000000 +#define BP_AUDIOOUT_ANACTRL_RSRVD6 22 +#define BM_AUDIOOUT_ANACTRL_RSRVD6 0x00C00000 +#define BF_AUDIOOUT_ANACTRL_RSRVD6(v) \ + (((v) << 22) & BM_AUDIOOUT_ANACTRL_RSRVD6) +#define BP_AUDIOOUT_ANACTRL_SHORTMODE_CM 20 +#define BM_AUDIOOUT_ANACTRL_SHORTMODE_CM 0x00300000 +#define BF_AUDIOOUT_ANACTRL_SHORTMODE_CM(v) \ + (((v) << 20) & BM_AUDIOOUT_ANACTRL_SHORTMODE_CM) +#define BM_AUDIOOUT_ANACTRL_RSRVD5 0x00080000 +#define BP_AUDIOOUT_ANACTRL_SHORTMODE_LR 17 +#define BM_AUDIOOUT_ANACTRL_SHORTMODE_LR 0x00060000 +#define BF_AUDIOOUT_ANACTRL_SHORTMODE_LR(v) \ + (((v) << 17) & BM_AUDIOOUT_ANACTRL_SHORTMODE_LR) +#define BP_AUDIOOUT_ANACTRL_RSRVD4 15 +#define BM_AUDIOOUT_ANACTRL_RSRVD4 0x00018000 +#define BF_AUDIOOUT_ANACTRL_RSRVD4(v) \ + (((v) << 15) & BM_AUDIOOUT_ANACTRL_RSRVD4) +#define BP_AUDIOOUT_ANACTRL_SHORT_LVLADJL 12 +#define BM_AUDIOOUT_ANACTRL_SHORT_LVLADJL 0x00007000 +#define BF_AUDIOOUT_ANACTRL_SHORT_LVLADJL(v) \ + (((v) << 12) & BM_AUDIOOUT_ANACTRL_SHORT_LVLADJL) +#define BM_AUDIOOUT_ANACTRL_RSRVD3 0x00000800 +#define BP_AUDIOOUT_ANACTRL_SHORT_LVLADJR 8 +#define BM_AUDIOOUT_ANACTRL_SHORT_LVLADJR 0x00000700 +#define BF_AUDIOOUT_ANACTRL_SHORT_LVLADJR(v) \ + (((v) << 8) & BM_AUDIOOUT_ANACTRL_SHORT_LVLADJR) +#define BP_AUDIOOUT_ANACTRL_RSRVD2 6 +#define BM_AUDIOOUT_ANACTRL_RSRVD2 0x000000C0 +#define BF_AUDIOOUT_ANACTRL_RSRVD2(v) \ + (((v) << 6) & BM_AUDIOOUT_ANACTRL_RSRVD2) +#define BM_AUDIOOUT_ANACTRL_HP_HOLD_GND 0x00000020 +#define BM_AUDIOOUT_ANACTRL_HP_CLASSAB 0x00000010 +#define BP_AUDIOOUT_ANACTRL_RSRVD1 0 +#define BM_AUDIOOUT_ANACTRL_RSRVD1 0x0000000F +#define BF_AUDIOOUT_ANACTRL_RSRVD1(v) \ + (((v) << 0) & BM_AUDIOOUT_ANACTRL_RSRVD1) + +#define HW_AUDIOOUT_TEST (0x000000a0) +#define HW_AUDIOOUT_TEST_SET (0x000000a4) +#define HW_AUDIOOUT_TEST_CLR (0x000000a8) +#define HW_AUDIOOUT_TEST_TOG (0x000000ac) + +#define BM_AUDIOOUT_TEST_RSRVD4 0x80000000 +#define BP_AUDIOOUT_TEST_HP_ANTIPOP 28 +#define BM_AUDIOOUT_TEST_HP_ANTIPOP 0x70000000 +#define BF_AUDIOOUT_TEST_HP_ANTIPOP(v) \ + (((v) << 28) & BM_AUDIOOUT_TEST_HP_ANTIPOP) +#define BM_AUDIOOUT_TEST_RSRVD3 0x08000000 +#define BM_AUDIOOUT_TEST_TM_ADCIN_TOHP 0x04000000 +#define BM_AUDIOOUT_TEST_TM_LOOP 0x02000000 +#define BM_AUDIOOUT_TEST_TM_HPCOMMON 0x01000000 +#define BP_AUDIOOUT_TEST_HP_I1_ADJ 22 +#define BM_AUDIOOUT_TEST_HP_I1_ADJ 0x00C00000 +#define BF_AUDIOOUT_TEST_HP_I1_ADJ(v) \ + (((v) << 22) & BM_AUDIOOUT_TEST_HP_I1_ADJ) +#define BP_AUDIOOUT_TEST_HP_IALL_ADJ 20 +#define BM_AUDIOOUT_TEST_HP_IALL_ADJ 0x00300000 +#define BF_AUDIOOUT_TEST_HP_IALL_ADJ(v) \ + (((v) << 20) & BM_AUDIOOUT_TEST_HP_IALL_ADJ) +#define BP_AUDIOOUT_TEST_RSRVD2 14 +#define BM_AUDIOOUT_TEST_RSRVD2 0x000FC000 +#define BF_AUDIOOUT_TEST_RSRVD2(v) \ + (((v) << 14) & BM_AUDIOOUT_TEST_RSRVD2) +#define BM_AUDIOOUT_TEST_VAG_CLASSA 0x00002000 +#define BM_AUDIOOUT_TEST_VAG_DOUBLE_I 0x00001000 +#define BP_AUDIOOUT_TEST_RSRVD1 4 +#define BM_AUDIOOUT_TEST_RSRVD1 0x00000FF0 +#define BF_AUDIOOUT_TEST_RSRVD1(v) \ + (((v) << 4) & BM_AUDIOOUT_TEST_RSRVD1) +#define BM_AUDIOOUT_TEST_ADCTODAC_LOOP 0x00000008 +#define BM_AUDIOOUT_TEST_DAC_CLASSA 0x00000004 +#define BM_AUDIOOUT_TEST_DAC_DOUBLE_I 0x00000002 +#define BM_AUDIOOUT_TEST_DAC_DIS_RTZ 0x00000001 + +#define HW_AUDIOOUT_BISTCTRL (0x000000b0) +#define HW_AUDIOOUT_BISTCTRL_SET (0x000000b4) +#define HW_AUDIOOUT_BISTCTRL_CLR (0x000000b8) +#define HW_AUDIOOUT_BISTCTRL_TOG (0x000000bc) + +#define BP_AUDIOOUT_BISTCTRL_RSVD0 4 +#define BM_AUDIOOUT_BISTCTRL_RSVD0 0xFFFFFFF0 +#define BF_AUDIOOUT_BISTCTRL_RSVD0(v) \ + (((v) << 4) & BM_AUDIOOUT_BISTCTRL_RSVD0) +#define BM_AUDIOOUT_BISTCTRL_FAIL 0x00000008 +#define BM_AUDIOOUT_BISTCTRL_PASS 0x00000004 +#define BM_AUDIOOUT_BISTCTRL_DONE 0x00000002 +#define BM_AUDIOOUT_BISTCTRL_START 0x00000001 + +#define HW_AUDIOOUT_BISTSTAT0 (0x000000c0) +#define HW_AUDIOOUT_BISTSTAT0_SET (0x000000c4) +#define HW_AUDIOOUT_BISTSTAT0_CLR (0x000000c8) +#define HW_AUDIOOUT_BISTSTAT0_TOG (0x000000cc) + +#define BP_AUDIOOUT_BISTSTAT0_RSVD0 24 +#define BM_AUDIOOUT_BISTSTAT0_RSVD0 0xFF000000 +#define BF_AUDIOOUT_BISTSTAT0_RSVD0(v) \ + (((v) << 24) & BM_AUDIOOUT_BISTSTAT0_RSVD0) +#define BP_AUDIOOUT_BISTSTAT0_DATA 0 +#define BM_AUDIOOUT_BISTSTAT0_DATA 0x00FFFFFF +#define BF_AUDIOOUT_BISTSTAT0_DATA(v) \ + (((v) << 0) & BM_AUDIOOUT_BISTSTAT0_DATA) + +#define HW_AUDIOOUT_BISTSTAT1 (0x000000d0) +#define HW_AUDIOOUT_BISTSTAT1_SET (0x000000d4) +#define HW_AUDIOOUT_BISTSTAT1_CLR (0x000000d8) +#define HW_AUDIOOUT_BISTSTAT1_TOG (0x000000dc) + +#define BP_AUDIOOUT_BISTSTAT1_RSVD1 29 +#define BM_AUDIOOUT_BISTSTAT1_RSVD1 0xE0000000 +#define BF_AUDIOOUT_BISTSTAT1_RSVD1(v) \ + (((v) << 29) & BM_AUDIOOUT_BISTSTAT1_RSVD1) +#define BP_AUDIOOUT_BISTSTAT1_STATE 24 +#define BM_AUDIOOUT_BISTSTAT1_STATE 0x1F000000 +#define BF_AUDIOOUT_BISTSTAT1_STATE(v) \ + (((v) << 24) & BM_AUDIOOUT_BISTSTAT1_STATE) +#define BP_AUDIOOUT_BISTSTAT1_RSVD0 8 +#define BM_AUDIOOUT_BISTSTAT1_RSVD0 0x00FFFF00 +#define BF_AUDIOOUT_BISTSTAT1_RSVD0(v) \ + (((v) << 8) & BM_AUDIOOUT_BISTSTAT1_RSVD0) +#define BP_AUDIOOUT_BISTSTAT1_ADDR 0 +#define BM_AUDIOOUT_BISTSTAT1_ADDR 0x000000FF +#define BF_AUDIOOUT_BISTSTAT1_ADDR(v) \ + (((v) << 0) & BM_AUDIOOUT_BISTSTAT1_ADDR) + +#define HW_AUDIOOUT_ANACLKCTRL (0x000000e0) +#define HW_AUDIOOUT_ANACLKCTRL_SET (0x000000e4) +#define HW_AUDIOOUT_ANACLKCTRL_CLR (0x000000e8) +#define HW_AUDIOOUT_ANACLKCTRL_TOG (0x000000ec) + +#define BM_AUDIOOUT_ANACLKCTRL_CLKGATE 0x80000000 +#define BP_AUDIOOUT_ANACLKCTRL_RSRVD3 5 +#define BM_AUDIOOUT_ANACLKCTRL_RSRVD3 0x7FFFFFE0 +#define BF_AUDIOOUT_ANACLKCTRL_RSRVD3(v) \ + (((v) << 5) & BM_AUDIOOUT_ANACLKCTRL_RSRVD3) +#define BM_AUDIOOUT_ANACLKCTRL_INVERT_DACCLK 0x00000010 +#define BM_AUDIOOUT_ANACLKCTRL_RSRVD2 0x00000008 +#define BP_AUDIOOUT_ANACLKCTRL_DACDIV 0 +#define BM_AUDIOOUT_ANACLKCTRL_DACDIV 0x00000007 +#define BF_AUDIOOUT_ANACLKCTRL_DACDIV(v) \ + (((v) << 0) & BM_AUDIOOUT_ANACLKCTRL_DACDIV) + +#define HW_AUDIOOUT_DATA (0x000000f0) +#define HW_AUDIOOUT_DATA_SET (0x000000f4) +#define HW_AUDIOOUT_DATA_CLR (0x000000f8) +#define HW_AUDIOOUT_DATA_TOG (0x000000fc) + +#define BP_AUDIOOUT_DATA_HIGH 16 +#define BM_AUDIOOUT_DATA_HIGH 0xFFFF0000 +#define BF_AUDIOOUT_DATA_HIGH(v) \ + (((v) << 16) & BM_AUDIOOUT_DATA_HIGH) +#define BP_AUDIOOUT_DATA_LOW 0 +#define BM_AUDIOOUT_DATA_LOW 0x0000FFFF +#define BF_AUDIOOUT_DATA_LOW(v) \ + (((v) << 0) & BM_AUDIOOUT_DATA_LOW) + +#define HW_AUDIOOUT_SPEAKERCTRL (0x00000100) +#define HW_AUDIOOUT_SPEAKERCTRL_SET (0x00000104) +#define HW_AUDIOOUT_SPEAKERCTRL_CLR (0x00000108) +#define HW_AUDIOOUT_SPEAKERCTRL_TOG (0x0000010c) + +#define BP_AUDIOOUT_SPEAKERCTRL_RSRVD2 25 +#define BM_AUDIOOUT_SPEAKERCTRL_RSRVD2 0xFE000000 +#define BF_AUDIOOUT_SPEAKERCTRL_RSRVD2(v) \ + (((v) << 25) & BM_AUDIOOUT_SPEAKERCTRL_RSRVD2) +#define BM_AUDIOOUT_SPEAKERCTRL_MUTE 0x01000000 +#define BP_AUDIOOUT_SPEAKERCTRL_I1_ADJ 22 +#define BM_AUDIOOUT_SPEAKERCTRL_I1_ADJ 0x00C00000 +#define BF_AUDIOOUT_SPEAKERCTRL_I1_ADJ(v) \ + (((v) << 22) & BM_AUDIOOUT_SPEAKERCTRL_I1_ADJ) +#define BP_AUDIOOUT_SPEAKERCTRL_IALL_ADJ 20 +#define BM_AUDIOOUT_SPEAKERCTRL_IALL_ADJ 0x00300000 +#define BF_AUDIOOUT_SPEAKERCTRL_IALL_ADJ(v) \ + (((v) << 20) & BM_AUDIOOUT_SPEAKERCTRL_IALL_ADJ) +#define BP_AUDIOOUT_SPEAKERCTRL_RSRVD1 16 +#define BM_AUDIOOUT_SPEAKERCTRL_RSRVD1 0x000F0000 +#define BF_AUDIOOUT_SPEAKERCTRL_RSRVD1(v) \ + (((v) << 16) & BM_AUDIOOUT_SPEAKERCTRL_RSRVD1) +#define BP_AUDIOOUT_SPEAKERCTRL_POSDRIVER 14 +#define BM_AUDIOOUT_SPEAKERCTRL_POSDRIVER 0x0000C000 +#define BF_AUDIOOUT_SPEAKERCTRL_POSDRIVER(v) \ + (((v) << 14) & BM_AUDIOOUT_SPEAKERCTRL_POSDRIVER) +#define BP_AUDIOOUT_SPEAKERCTRL_NEGDRIVER 12 +#define BM_AUDIOOUT_SPEAKERCTRL_NEGDRIVER 0x00003000 +#define BF_AUDIOOUT_SPEAKERCTRL_NEGDRIVER(v) \ + (((v) << 12) & BM_AUDIOOUT_SPEAKERCTRL_NEGDRIVER) +#define BP_AUDIOOUT_SPEAKERCTRL_RSRVD0 0 +#define BM_AUDIOOUT_SPEAKERCTRL_RSRVD0 0x00000FFF +#define BF_AUDIOOUT_SPEAKERCTRL_RSRVD0(v) \ + (((v) << 0) & BM_AUDIOOUT_SPEAKERCTRL_RSRVD0) + +#define HW_AUDIOOUT_VERSION (0x00000200) + +#define BP_AUDIOOUT_VERSION_MAJOR 24 +#define BM_AUDIOOUT_VERSION_MAJOR 0xFF000000 +#define BF_AUDIOOUT_VERSION_MAJOR(v) \ + (((v) << 24) & BM_AUDIOOUT_VERSION_MAJOR) +#define BP_AUDIOOUT_VERSION_MINOR 16 +#define BM_AUDIOOUT_VERSION_MINOR 0x00FF0000 +#define BF_AUDIOOUT_VERSION_MINOR(v) \ + (((v) << 16) & BM_AUDIOOUT_VERSION_MINOR) +#define BP_AUDIOOUT_VERSION_STEP 0 +#define BM_AUDIOOUT_VERSION_STEP 0x0000FFFF +#define BF_AUDIOOUT_VERSION_STEP(v) \ + (((v) << 0) & BM_AUDIOOUT_VERSION_STEP) + +/* AUDIOIN */ +#define HW_AUDIOIN_CTRL (0x00000000) +#define HW_AUDIOIN_CTRL_SET (0x00000004) +#define HW_AUDIOIN_CTRL_CLR (0x00000008) +#define HW_AUDIOIN_CTRL_TOG (0x0000000c) + +#define BM_AUDIOIN_CTRL_SFTRST 0x80000000 +#define BM_AUDIOIN_CTRL_CLKGATE 0x40000000 +#define BP_AUDIOIN_CTRL_RSRVD3 21 +#define BM_AUDIOIN_CTRL_RSRVD3 0x3FE00000 +#define BF_AUDIOIN_CTRL_RSRVD3(v) \ + (((v) << 21) & BM_AUDIOIN_CTRL_RSRVD3) +#define BP_AUDIOIN_CTRL_DMAWAIT_COUNT 16 +#define BM_AUDIOIN_CTRL_DMAWAIT_COUNT 0x001F0000 +#define BF_AUDIOIN_CTRL_DMAWAIT_COUNT(v) \ + (((v) << 16) & BM_AUDIOIN_CTRL_DMAWAIT_COUNT) +#define BP_AUDIOIN_CTRL_RSRVD1 11 +#define BM_AUDIOIN_CTRL_RSRVD1 0x0000F800 +#define BF_AUDIOIN_CTRL_RSRVD1(v) \ + (((v) << 11) & BM_AUDIOIN_CTRL_RSRVD1) +#define BM_AUDIOIN_CTRL_LR_SWAP 0x00000400 +#define BM_AUDIOIN_CTRL_EDGE_SYNC 0x00000200 +#define BM_AUDIOIN_CTRL_INVERT_1BIT 0x00000100 +#define BM_AUDIOIN_CTRL_OFFSET_ENABLE 0x00000080 +#define BM_AUDIOIN_CTRL_HPF_ENABLE 0x00000040 +#define BM_AUDIOIN_CTRL_WORD_LENGTH 0x00000020 +#define BM_AUDIOIN_CTRL_LOOPBACK 0x00000010 +#define BM_AUDIOIN_CTRL_FIFO_UNDERFLOW_IRQ 0x00000008 +#define BM_AUDIOIN_CTRL_FIFO_OVERFLOW_IRQ 0x00000004 +#define BM_AUDIOIN_CTRL_FIFO_ERROR_IRQ_EN 0x00000002 +#define BM_AUDIOIN_CTRL_RUN 0x00000001 + +#define HW_AUDIOIN_STAT (0x00000010) +#define HW_AUDIOIN_STAT_SET (0x00000014) +#define HW_AUDIOIN_STAT_CLR (0x00000018) +#define HW_AUDIOIN_STAT_TOG (0x0000001c) + +#define BM_AUDIOIN_STAT_ADC_PRESENT 0x80000000 +#define BP_AUDIOIN_STAT_RSRVD3 0 +#define BM_AUDIOIN_STAT_RSRVD3 0x7FFFFFFF +#define BF_AUDIOIN_STAT_RSRVD3(v) \ + (((v) << 0) & BM_AUDIOIN_STAT_RSRVD3) + +#define HW_AUDIOIN_ADCSRR (0x00000020) +#define HW_AUDIOIN_ADCSRR_SET (0x00000024) +#define HW_AUDIOIN_ADCSRR_CLR (0x00000028) +#define HW_AUDIOIN_ADCSRR_TOG (0x0000002c) + +#define BM_AUDIOIN_ADCSRR_OSR 0x80000000 +#define BV_AUDIOIN_ADCSRR_OSR__OSR6 0x0 +#define BV_AUDIOIN_ADCSRR_OSR__OSR12 0x1 +#define BP_AUDIOIN_ADCSRR_BASEMULT 28 +#define BM_AUDIOIN_ADCSRR_BASEMULT 0x70000000 +#define BF_AUDIOIN_ADCSRR_BASEMULT(v) \ + (((v) << 28) & BM_AUDIOIN_ADCSRR_BASEMULT) +#define BV_AUDIOIN_ADCSRR_BASEMULT__SINGLE_RATE 0x1 +#define BV_AUDIOIN_ADCSRR_BASEMULT__DOUBLE_RATE 0x2 +#define BV_AUDIOIN_ADCSRR_BASEMULT__QUAD_RATE 0x4 +#define BM_AUDIOIN_ADCSRR_RSRVD2 0x08000000 +#define BP_AUDIOIN_ADCSRR_SRC_HOLD 24 +#define BM_AUDIOIN_ADCSRR_SRC_HOLD 0x07000000 +#define BF_AUDIOIN_ADCSRR_SRC_HOLD(v) \ + (((v) << 24) & BM_AUDIOIN_ADCSRR_SRC_HOLD) +#define BP_AUDIOIN_ADCSRR_RSRVD1 21 +#define BM_AUDIOIN_ADCSRR_RSRVD1 0x00E00000 +#define BF_AUDIOIN_ADCSRR_RSRVD1(v) \ + (((v) << 21) & BM_AUDIOIN_ADCSRR_RSRVD1) +#define BP_AUDIOIN_ADCSRR_SRC_INT 16 +#define BM_AUDIOIN_ADCSRR_SRC_INT 0x001F0000 +#define BF_AUDIOIN_ADCSRR_SRC_INT(v) \ + (((v) << 16) & BM_AUDIOIN_ADCSRR_SRC_INT) +#define BP_AUDIOIN_ADCSRR_RSRVD0 13 +#define BM_AUDIOIN_ADCSRR_RSRVD0 0x0000E000 +#define BF_AUDIOIN_ADCSRR_RSRVD0(v) \ + (((v) << 13) & BM_AUDIOIN_ADCSRR_RSRVD0) +#define BP_AUDIOIN_ADCSRR_SRC_FRAC 0 +#define BM_AUDIOIN_ADCSRR_SRC_FRAC 0x00001FFF +#define BF_AUDIOIN_ADCSRR_SRC_FRAC(v) \ + (((v) << 0) & BM_AUDIOIN_ADCSRR_SRC_FRAC) + +#define HW_AUDIOIN_ADCVOLUME (0x00000030) +#define HW_AUDIOIN_ADCVOLUME_SET (0x00000034) +#define HW_AUDIOIN_ADCVOLUME_CLR (0x00000038) +#define HW_AUDIOIN_ADCVOLUME_TOG (0x0000003c) + +#define BP_AUDIOIN_ADCVOLUME_RSRVD5 29 +#define BM_AUDIOIN_ADCVOLUME_RSRVD5 0xE0000000 +#define BF_AUDIOIN_ADCVOLUME_RSRVD5(v) \ + (((v) << 29) & BM_AUDIOIN_ADCVOLUME_RSRVD5) +#define BM_AUDIOIN_ADCVOLUME_VOLUME_UPDATE_LEFT 0x10000000 +#define BP_AUDIOIN_ADCVOLUME_RSRVD4 26 +#define BM_AUDIOIN_ADCVOLUME_RSRVD4 0x0C000000 +#define BF_AUDIOIN_ADCVOLUME_RSRVD4(v) \ + (((v) << 26) & BM_AUDIOIN_ADCVOLUME_RSRVD4) +#define BM_AUDIOIN_ADCVOLUME_EN_ZCD 0x02000000 +#define BM_AUDIOIN_ADCVOLUME_RSRVD3 0x01000000 +#define BP_AUDIOIN_ADCVOLUME_VOLUME_LEFT 16 +#define BM_AUDIOIN_ADCVOLUME_VOLUME_LEFT 0x00FF0000 +#define BF_AUDIOIN_ADCVOLUME_VOLUME_LEFT(v) \ + (((v) << 16) & BM_AUDIOIN_ADCVOLUME_VOLUME_LEFT) +#define BP_AUDIOIN_ADCVOLUME_RSRVD2 13 +#define BM_AUDIOIN_ADCVOLUME_RSRVD2 0x0000E000 +#define BF_AUDIOIN_ADCVOLUME_RSRVD2(v) \ + (((v) << 13) & BM_AUDIOIN_ADCVOLUME_RSRVD2) +#define BM_AUDIOIN_ADCVOLUME_VOLUME_UPDATE_RIGHT 0x00001000 +#define BP_AUDIOIN_ADCVOLUME_RSRVD1 8 +#define BM_AUDIOIN_ADCVOLUME_RSRVD1 0x00000F00 +#define BF_AUDIOIN_ADCVOLUME_RSRVD1(v) \ + (((v) << 8) & BM_AUDIOIN_ADCVOLUME_RSRVD1) +#define BP_AUDIOIN_ADCVOLUME_VOLUME_RIGHT 0 +#define BM_AUDIOIN_ADCVOLUME_VOLUME_RIGHT 0x000000FF +#define BF_AUDIOIN_ADCVOLUME_VOLUME_RIGHT(v) \ + (((v) << 0) & BM_AUDIOIN_ADCVOLUME_VOLUME_RIGHT) + +#define HW_AUDIOIN_ADCDEBUG (0x00000040) +#define HW_AUDIOIN_ADCDEBUG_SET (0x00000044) +#define HW_AUDIOIN_ADCDEBUG_CLR (0x00000048) +#define HW_AUDIOIN_ADCDEBUG_TOG (0x0000004c) + +#define BM_AUDIOIN_ADCDEBUG_ENABLE_ADCDMA 0x80000000 +#define BP_AUDIOIN_ADCDEBUG_RSRVD1 4 +#define BM_AUDIOIN_ADCDEBUG_RSRVD1 0x7FFFFFF0 +#define BF_AUDIOIN_ADCDEBUG_RSRVD1(v) \ + (((v) << 4) & BM_AUDIOIN_ADCDEBUG_RSRVD1) +#define BM_AUDIOIN_ADCDEBUG_ADC_DMA_REQ_HAND_SHAKE_CLK_CROSS 0x00000008 +#define BM_AUDIOIN_ADCDEBUG_SET_INTERRUPT3_HAND_SHAKE 0x00000004 +#define BM_AUDIOIN_ADCDEBUG_DMA_PREQ 0x00000002 +#define BM_AUDIOIN_ADCDEBUG_FIFO_STATUS 0x00000001 + +#define HW_AUDIOIN_ADCVOL (0x00000050) +#define HW_AUDIOIN_ADCVOL_SET (0x00000054) +#define HW_AUDIOIN_ADCVOL_CLR (0x00000058) +#define HW_AUDIOIN_ADCVOL_TOG (0x0000005c) + +#define BP_AUDIOIN_ADCVOL_RSRVD4 29 +#define BM_AUDIOIN_ADCVOL_RSRVD4 0xE0000000 +#define BF_AUDIOIN_ADCVOL_RSRVD4(v) \ + (((v) << 29) & BM_AUDIOIN_ADCVOL_RSRVD4) +#define BM_AUDIOIN_ADCVOL_VOLUME_UPDATE_PENDING 0x10000000 +#define BP_AUDIOIN_ADCVOL_RSRVD3 26 +#define BM_AUDIOIN_ADCVOL_RSRVD3 0x0C000000 +#define BF_AUDIOIN_ADCVOL_RSRVD3(v) \ + (((v) << 26) & BM_AUDIOIN_ADCVOL_RSRVD3) +#define BM_AUDIOIN_ADCVOL_EN_ADC_ZCD 0x02000000 +#define BM_AUDIOIN_ADCVOL_MUTE 0x01000000 +#define BP_AUDIOIN_ADCVOL_RSRVD2 14 +#define BM_AUDIOIN_ADCVOL_RSRVD2 0x00FFC000 +#define BF_AUDIOIN_ADCVOL_RSRVD2(v) \ + (((v) << 14) & BM_AUDIOIN_ADCVOL_RSRVD2) +#define BP_AUDIOIN_ADCVOL_SELECT_LEFT 12 +#define BM_AUDIOIN_ADCVOL_SELECT_LEFT 0x00003000 +#define BF_AUDIOIN_ADCVOL_SELECT_LEFT(v) \ + (((v) << 12) & BM_AUDIOIN_ADCVOL_SELECT_LEFT) +#define BP_AUDIOIN_ADCVOL_GAIN_LEFT 8 +#define BM_AUDIOIN_ADCVOL_GAIN_LEFT 0x00000F00 +#define BF_AUDIOIN_ADCVOL_GAIN_LEFT(v) \ + (((v) << 8) & BM_AUDIOIN_ADCVOL_GAIN_LEFT) +#define BP_AUDIOIN_ADCVOL_RSRVD1 6 +#define BM_AUDIOIN_ADCVOL_RSRVD1 0x000000C0 +#define BF_AUDIOIN_ADCVOL_RSRVD1(v) \ + (((v) << 6) & BM_AUDIOIN_ADCVOL_RSRVD1) +#define BP_AUDIOIN_ADCVOL_SELECT_RIGHT 4 +#define BM_AUDIOIN_ADCVOL_SELECT_RIGHT 0x00000030 +#define BF_AUDIOIN_ADCVOL_SELECT_RIGHT(v) \ + (((v) << 4) & BM_AUDIOIN_ADCVOL_SELECT_RIGHT) +#define BP_AUDIOIN_ADCVOL_GAIN_RIGHT 0 +#define BM_AUDIOIN_ADCVOL_GAIN_RIGHT 0x0000000F +#define BF_AUDIOIN_ADCVOL_GAIN_RIGHT(v) \ + (((v) << 0) & BM_AUDIOIN_ADCVOL_GAIN_RIGHT) + +#define HW_AUDIOIN_MICLINE (0x00000060) +#define HW_AUDIOIN_MICLINE_SET (0x00000064) +#define HW_AUDIOIN_MICLINE_CLR (0x00000068) +#define HW_AUDIOIN_MICLINE_TOG (0x0000006c) + +#define BP_AUDIOIN_MICLINE_RSRVD6 30 +#define BM_AUDIOIN_MICLINE_RSRVD6 0xC0000000 +#define BF_AUDIOIN_MICLINE_RSRVD6(v) \ + (((v) << 30) & BM_AUDIOIN_MICLINE_RSRVD6) +#define BM_AUDIOIN_MICLINE_DIVIDE_LINE1 0x20000000 +#define BM_AUDIOIN_MICLINE_DIVIDE_LINE2 0x10000000 +#define BP_AUDIOIN_MICLINE_RSRVD5 25 +#define BM_AUDIOIN_MICLINE_RSRVD5 0x0E000000 +#define BF_AUDIOIN_MICLINE_RSRVD5(v) \ + (((v) << 25) & BM_AUDIOIN_MICLINE_RSRVD5) +#define BM_AUDIOIN_MICLINE_MIC_SELECT 0x01000000 +#define BP_AUDIOIN_MICLINE_RSRVD4 22 +#define BM_AUDIOIN_MICLINE_RSRVD4 0x00C00000 +#define BF_AUDIOIN_MICLINE_RSRVD4(v) \ + (((v) << 22) & BM_AUDIOIN_MICLINE_RSRVD4) +#define BP_AUDIOIN_MICLINE_MIC_RESISTOR 20 +#define BM_AUDIOIN_MICLINE_MIC_RESISTOR 0x00300000 +#define BF_AUDIOIN_MICLINE_MIC_RESISTOR(v) \ + (((v) << 20) & BM_AUDIOIN_MICLINE_MIC_RESISTOR) +#define BM_AUDIOIN_MICLINE_RSRVD3 0x00080000 +#define BP_AUDIOIN_MICLINE_MIC_BIAS 16 +#define BM_AUDIOIN_MICLINE_MIC_BIAS 0x00070000 +#define BF_AUDIOIN_MICLINE_MIC_BIAS(v) \ + (((v) << 16) & BM_AUDIOIN_MICLINE_MIC_BIAS) +#define BP_AUDIOIN_MICLINE_RSRVD2 6 +#define BM_AUDIOIN_MICLINE_RSRVD2 0x0000FFC0 +#define BF_AUDIOIN_MICLINE_RSRVD2(v) \ + (((v) << 6) & BM_AUDIOIN_MICLINE_RSRVD2) +#define BP_AUDIOIN_MICLINE_MIC_CHOPCLK 4 +#define BM_AUDIOIN_MICLINE_MIC_CHOPCLK 0x00000030 +#define BF_AUDIOIN_MICLINE_MIC_CHOPCLK(v) \ + (((v) << 4) & BM_AUDIOIN_MICLINE_MIC_CHOPCLK) +#define BP_AUDIOIN_MICLINE_RSRVD1 2 +#define BM_AUDIOIN_MICLINE_RSRVD1 0x0000000C +#define BF_AUDIOIN_MICLINE_RSRVD1(v) \ + (((v) << 2) & BM_AUDIOIN_MICLINE_RSRVD1) +#define BP_AUDIOIN_MICLINE_MIC_GAIN 0 +#define BM_AUDIOIN_MICLINE_MIC_GAIN 0x00000003 +#define BF_AUDIOIN_MICLINE_MIC_GAIN(v) \ + (((v) << 0) & BM_AUDIOIN_MICLINE_MIC_GAIN) + +#define HW_AUDIOIN_ANACLKCTRL (0x00000070) +#define HW_AUDIOIN_ANACLKCTRL_SET (0x00000074) +#define HW_AUDIOIN_ANACLKCTRL_CLR (0x00000078) +#define HW_AUDIOIN_ANACLKCTRL_TOG (0x0000007c) + +#define BM_AUDIOIN_ANACLKCTRL_CLKGATE 0x80000000 +#define BP_AUDIOIN_ANACLKCTRL_RSRVD4 11 +#define BM_AUDIOIN_ANACLKCTRL_RSRVD4 0x7FFFF800 +#define BF_AUDIOIN_ANACLKCTRL_RSRVD4(v) \ + (((v) << 11) & BM_AUDIOIN_ANACLKCTRL_RSRVD4) +#define BM_AUDIOIN_ANACLKCTRL_DITHER_OFF 0x00000400 +#define BM_AUDIOIN_ANACLKCTRL_SLOW_DITHER 0x00000200 +#define BM_AUDIOIN_ANACLKCTRL_INVERT_ADCCLK 0x00000100 +#define BP_AUDIOIN_ANACLKCTRL_RSRVD3 6 +#define BM_AUDIOIN_ANACLKCTRL_RSRVD3 0x000000C0 +#define BF_AUDIOIN_ANACLKCTRL_RSRVD3(v) \ + (((v) << 6) & BM_AUDIOIN_ANACLKCTRL_RSRVD3) +#define BP_AUDIOIN_ANACLKCTRL_ADCCLK_SHIFT 4 +#define BM_AUDIOIN_ANACLKCTRL_ADCCLK_SHIFT 0x00000030 +#define BF_AUDIOIN_ANACLKCTRL_ADCCLK_SHIFT(v) \ + (((v) << 4) & BM_AUDIOIN_ANACLKCTRL_ADCCLK_SHIFT) +#define BM_AUDIOIN_ANACLKCTRL_RSRVD2 0x00000008 +#define BP_AUDIOIN_ANACLKCTRL_ADCDIV 0 +#define BM_AUDIOIN_ANACLKCTRL_ADCDIV 0x00000007 +#define BF_AUDIOIN_ANACLKCTRL_ADCDIV(v) \ + (((v) << 0) & BM_AUDIOIN_ANACLKCTRL_ADCDIV) + +#define HW_AUDIOIN_DATA (0x00000080) +#define HW_AUDIOIN_DATA_SET (0x00000084) +#define HW_AUDIOIN_DATA_CLR (0x00000088) +#define HW_AUDIOIN_DATA_TOG (0x0000008c) + +#define BP_AUDIOIN_DATA_HIGH 16 +#define BM_AUDIOIN_DATA_HIGH 0xFFFF0000 +#define BF_AUDIOIN_DATA_HIGH(v) \ + (((v) << 16) & BM_AUDIOIN_DATA_HIGH) +#define BP_AUDIOIN_DATA_LOW 0 +#define BM_AUDIOIN_DATA_LOW 0x0000FFFF +#define BF_AUDIOIN_DATA_LOW(v) \ + (((v) << 0) & BM_AUDIOIN_DATA_LOW) + +#define BV_AUDIOIN_ADCVOL_SELECT__MIC 0x00 + +#endif /* __MXS_ADC_CODEC_H */ --- a/sound/soc/mxs/Kconfig +++ b/sound/soc/mxs/Kconfig @@ -19,3 +19,13 @@ config SND_SOC_MXS_SGTL5000 a sgtl5000 codec. endif # SND_MXS_SOC + + +config SND_MXS_SOC_BUILTIN + tristate "SoC Audio for Freescale i.MX23 built-in codec" + depends on ARCH_MXS + select SND_SOC_GENERIC_DMAENGINE_PCM + select SND_SOC_MXS_BUILTIN_CODEC + help + Say Y or M if you want to add support for codecs attached to + the MXS SAIF interface. --- a/sound/soc/mxs/Makefile +++ b/sound/soc/mxs/Makefile @@ -8,3 +8,12 @@ obj-$(CONFIG_SND_MXS_SOC) += snd-soc-mxs snd-soc-mxs-sgtl5000-objs := mxs-sgtl5000.o obj-$(CONFIG_SND_SOC_MXS_SGTL5000) += snd-soc-mxs-sgtl5000.o + +# i.MX23 built-in audio Machine and Platform support +snd-soc-mxs-builtin-pcm-objs := mxs-builtin-pcm.o +snd-soc-mxs-builtin-dai-objs := mxs-builtin-dai.o +snd-soc-mxs-builtin-audio-objs := mxs-builtin-audio.o + +obj-$(CONFIG_SND_MXS_SOC_BUILTIN) += snd-soc-mxs-builtin-pcm.o +obj-$(CONFIG_SND_MXS_SOC_BUILTIN) += snd-soc-mxs-builtin-dai.o +obj-$(CONFIG_SND_MXS_SOC_BUILTIN) += snd-soc-mxs-builtin-audio.o --- /dev/null +++ b/sound/soc/mxs/mxs-builtin-audio.c @@ -0,0 +1,120 @@ +/* + * mxs-builtin-audio.c -- i.MX233 built-in codec ALSA Soc Audio driver + * + * Author: Michal Ulianko + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct snd_soc_dai_link mxs_adc_dai_link[] = { + { + .name = "MXS ADC/DAC", + .stream_name = "MXS ADC/DAC", + .codec_dai_name = "mxs-builtin-codec-dai", +// .codec_name = "mxs-builtin-codec", +// .cpu_dai_name = "mxs-builtin-cpu-dai", +// .platform_name = "mxs-builtin-cpu-dai", +// .ops = &mxs_sgtl5000_hifi_ops, + }, +}; + +static struct snd_soc_card mxs_adc_audio = { + .name = "mxs-builtin-audio", + .owner = THIS_MODULE, + .dai_link = mxs_adc_dai_link, + .num_links = ARRAY_SIZE(mxs_adc_dai_link), +}; + +static int mxsadc_audio_probe_dt(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct device_node *cpu_dai_np, *codec_np; + int ret = 0; + + if (!np) + return 1; /* no device tree */ + + cpu_dai_np = of_parse_phandle(np, "cpu-dai", 0); + codec_np = of_parse_phandle(np, "audio-codec", 0); + if (!cpu_dai_np || !codec_np) { + dev_err(&pdev->dev, "phandle missing or invalid\n"); + return -EINVAL; + } + + mxs_adc_dai_link[0].codec_name = NULL; + mxs_adc_dai_link[0].codec_of_node = codec_np; + mxs_adc_dai_link[0].cpu_dai_name = NULL; + mxs_adc_dai_link[0].cpu_of_node = cpu_dai_np; + mxs_adc_dai_link[0].platform_name = NULL; + mxs_adc_dai_link[0].platform_of_node = cpu_dai_np; + +// of_node_put(codec_np); +// of_node_put(cpu_dai_np); + + return ret; +} + +static int mxsadc_audio_probe(struct platform_device *pdev) +{ + struct snd_soc_card *card = &mxs_adc_audio; + int ret; + + ret = mxsadc_audio_probe_dt(pdev); + if (ret < 0) + return ret; + + card->dev = &pdev->dev; + platform_set_drvdata(pdev, card); + + ret = snd_soc_register_card(card); + if (ret) { + dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); + return ret; + } + + return 0; +} + +static int mxsadc_audio_remove(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + + snd_soc_unregister_card(card); + + return 0; +} + +static const struct of_device_id mxs_adc_audio_dt_ids[] = { + { .compatible = "fsl,mxs-builtin-audio", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, mxs_adc_audio_dt_ids); + +static struct platform_driver mxs_adc_audio_driver = { + .driver = { + .name = "mxs-builtin-audio", + .owner = THIS_MODULE, + .of_match_table = mxs_adc_audio_dt_ids, + }, + .probe = mxsadc_audio_probe, + .remove = mxsadc_audio_remove, +}; + +module_platform_driver(mxs_adc_audio_driver); + +MODULE_DESCRIPTION("Freescale MXS ADC/DAC SoC Machine Driver"); +MODULE_AUTHOR("Michal Ulianko "); +MODULE_LICENSE("GPL"); --- /dev/null +++ b/sound/soc/mxs/mxs-builtin-dai.c @@ -0,0 +1,588 @@ +/* + * mxs-builtin-dai.c -- i.MX233 built-in codec ALSA Soc Audio driver + * + * Author: Michal Ulianko + * + * Based on sound/soc/mxs/mxs-adc.c for kernel 2.6.35 + * by Vladislav Buzov + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../codecs/mxs-builtin-codec.h" +#include "mxs-builtin-pcm.h" + +#define ADC_VOLUME_MIN 0x37 + +/* TODO Use codec IO function soc snd write etc, instead of __writel __readl */ + +// TODO use container_of +struct mxs_irq_data { + struct snd_pcm_substream *substream; + struct mxs_adc_priv *mxs_adc; +}; + +struct mxs_adc_priv { + struct mxs_irq_data irq_data; + int dma_adc_err_irq; + int dma_dac_err_irq; + int hp_short_irq; + void __iomem *audioin_base; + void __iomem *audioout_base; + void __iomem *rtc_base; +}; + +typedef struct { + struct work_struct work; + struct timer_list timer; + + /* target workqueue and CPU ->timer uses to queue ->work */ + struct workqueue_struct *wq; + int cpu; + + struct mxs_adc_priv *mxs_adc; +} my_delayed_work_t; + +// static struct delayed_work work; +// static struct delayed_work adc_ramp_work; +// static struct delayed_work dac_ramp_work; +// static struct delayed_work test; +static my_delayed_work_t work; +static my_delayed_work_t adc_ramp_work; +static my_delayed_work_t dac_ramp_work; +static my_delayed_work_t test; +static bool adc_ramp_done = 1; +static bool dac_ramp_done = 1; + +static inline void mxs_adc_schedule_work(struct delayed_work *work) +{ + schedule_delayed_work(work, HZ / 10); +} + +static void mxs_adc_work(struct work_struct *work) +{ + struct mxs_adc_priv *mxs_adc = ((my_delayed_work_t *)work)->mxs_adc; + /* disable irq */ + disable_irq(mxs_adc->hp_short_irq); + + while (true) { + __raw_writel(BM_AUDIOOUT_PWRDN_HEADPHONE, + mxs_adc->audioout_base + HW_AUDIOOUT_PWRDN_CLR); + msleep(10); + if ((__raw_readl(mxs_adc->audioout_base + HW_AUDIOOUT_ANACTRL) + & BM_AUDIOOUT_ANACTRL_SHORT_LR_STS) != 0) { + /* rearm the short protection */ + __raw_writel(BM_AUDIOOUT_ANACTRL_SHORTMODE_LR, + mxs_adc->audioout_base + HW_AUDIOOUT_ANACTRL_CLR); + __raw_writel(BM_AUDIOOUT_ANACTRL_SHORT_LR_STS, + mxs_adc->audioout_base + HW_AUDIOOUT_ANACTRL_CLR); + __raw_writel(BF_AUDIOOUT_ANACTRL_SHORTMODE_LR(0x1), + mxs_adc->audioout_base + HW_AUDIOOUT_ANACTRL_SET); + + __raw_writel(BM_AUDIOOUT_PWRDN_HEADPHONE, + mxs_adc->audioout_base + HW_AUDIOOUT_PWRDN_SET); + printk(KERN_WARNING "WARNING : Headphone LR short!\r\n"); + } else { + printk(KERN_WARNING "INFO : Headphone LR no longer short!\r\n"); + break; + } + msleep(1000); + } + + /* power up the HEADPHONE and un-mute the HPVOL */ + __raw_writel(BM_AUDIOOUT_HPVOL_MUTE, + mxs_adc->audioout_base + HW_AUDIOOUT_HPVOL_CLR); + __raw_writel(BM_AUDIOOUT_PWRDN_HEADPHONE, + mxs_adc->audioout_base + HW_AUDIOOUT_PWRDN_CLR); + + /* enable irq for next short detect*/ + enable_irq(mxs_adc->hp_short_irq); +} + +static void mxs_adc_schedule_ramp_work(struct delayed_work *work) +{ + schedule_delayed_work(work, msecs_to_jiffies(2)); + adc_ramp_done = 0; +} + +static void mxs_adc_ramp_work(struct work_struct *work) +{ + struct mxs_adc_priv *mxs_adc = ((my_delayed_work_t *)work)->mxs_adc; + u32 reg = 0; + u32 reg1 = 0; + u32 reg2 = 0; + u32 l, r; + u32 ll, rr; + int i; + + reg = __raw_readl(mxs_adc->audioin_base + \ + HW_AUDIOIN_ADCVOLUME); + + reg1 = reg & ~BM_AUDIOIN_ADCVOLUME_VOLUME_LEFT; + reg1 = reg1 & ~BM_AUDIOIN_ADCVOLUME_VOLUME_RIGHT; + /* minimize adc volume */ + reg2 = reg1 | + BF_AUDIOIN_ADCVOLUME_VOLUME_LEFT(ADC_VOLUME_MIN) | + BF_AUDIOIN_ADCVOLUME_VOLUME_RIGHT(ADC_VOLUME_MIN); + __raw_writel(reg2, + mxs_adc->audioin_base + HW_AUDIOIN_ADCVOLUME); + msleep(1); + + l = (reg & BM_AUDIOIN_ADCVOLUME_VOLUME_LEFT) >> + BP_AUDIOIN_ADCVOLUME_VOLUME_LEFT; + r = (reg & BM_AUDIOIN_ADCVOLUME_VOLUME_RIGHT) >> + BP_AUDIOIN_ADCVOLUME_VOLUME_RIGHT; + + /* fade in adc vol */ + for (i = ADC_VOLUME_MIN; (i < l) || (i < r);) { + i += 0x8; + ll = i < l ? i : l; + rr = i < r ? i : r; + reg2 = reg1 | + BF_AUDIOIN_ADCVOLUME_VOLUME_LEFT(ll) | + BF_AUDIOIN_ADCVOLUME_VOLUME_RIGHT(rr); + __raw_writel(reg2, + mxs_adc->audioin_base + HW_AUDIOIN_ADCVOLUME); + msleep(1); + } + adc_ramp_done = 1; +} + +static void mxs_dac_schedule_ramp_work(struct delayed_work *work) +{ + schedule_delayed_work(work, msecs_to_jiffies(2)); + dac_ramp_done = 0; +} + +static void mxs_dac_ramp_work(struct work_struct *work) +{ + struct mxs_adc_priv *mxs_adc = ((my_delayed_work_t *)work)->mxs_adc; + u32 reg = 0; + u32 reg1 = 0; + u32 l, r; + u32 ll, rr; + int i; + + /* unmute hp and speaker */ + __raw_writel(BM_AUDIOOUT_HPVOL_MUTE, + mxs_adc->audioout_base + HW_AUDIOOUT_HPVOL_CLR); + __raw_writel(BM_AUDIOOUT_SPEAKERCTRL_MUTE, + mxs_adc->audioout_base + HW_AUDIOOUT_SPEAKERCTRL_CLR); + + reg = __raw_readl(mxs_adc->audioout_base + \ + HW_AUDIOOUT_HPVOL); + + reg1 = reg & ~BM_AUDIOOUT_HPVOL_VOL_LEFT; + reg1 = reg1 & ~BM_AUDIOOUT_HPVOL_VOL_RIGHT; + + l = (reg & BM_AUDIOOUT_HPVOL_VOL_LEFT) >> + BP_AUDIOOUT_HPVOL_VOL_LEFT; + r = (reg & BM_AUDIOOUT_HPVOL_VOL_RIGHT) >> + BP_AUDIOOUT_HPVOL_VOL_RIGHT; + /* fade in hp vol */ + for (i = 0x7f; i > 0 ;) { + i -= 0x8; + ll = i > (int)l ? i : l; + rr = i > (int)r ? i : r; + reg = reg1 | BF_AUDIOOUT_HPVOL_VOL_LEFT(ll) + | BF_AUDIOOUT_HPVOL_VOL_RIGHT(rr); + __raw_writel(reg, + mxs_adc->audioout_base + HW_AUDIOOUT_HPVOL); + msleep(1); + } + dac_ramp_done = 1; +} + +/* IRQs */ +static irqreturn_t mxs_short_irq(int irq, void *dev_id) +{ + struct mxs_adc_priv *mxs_adc = dev_id; + //struct snd_pcm_substream *substream = mxs_adc->irq_data.substream; + + __raw_writel(BM_AUDIOOUT_ANACTRL_SHORTMODE_LR, + mxs_adc->audioout_base + HW_AUDIOOUT_ANACTRL_CLR); + __raw_writel(BM_AUDIOOUT_ANACTRL_SHORT_LR_STS, + mxs_adc->audioout_base + HW_AUDIOOUT_ANACTRL_CLR); + __raw_writel(BF_AUDIOOUT_ANACTRL_SHORTMODE_LR(0x1), + mxs_adc->audioout_base + HW_AUDIOOUT_ANACTRL_SET); + + __raw_writel(BM_AUDIOOUT_HPVOL_MUTE, + mxs_adc->audioout_base + HW_AUDIOOUT_HPVOL_SET); + __raw_writel(BM_AUDIOOUT_PWRDN_HEADPHONE, + mxs_adc->audioout_base + HW_AUDIOOUT_PWRDN_SET); + __raw_writel(BM_AUDIOOUT_ANACTRL_HP_CLASSAB, + mxs_adc->audioout_base + HW_AUDIOOUT_ANACTRL_SET); + + mxs_adc_schedule_work((struct delayed_work *) &work); + return IRQ_HANDLED; +} + +static irqreturn_t mxs_err_irq(int irq, void *dev_id) +{ + struct mxs_adc_priv *mxs_adc = dev_id; + struct snd_pcm_substream *substream = mxs_adc->irq_data.substream; + int playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 1 : 0; + u32 ctrl_reg; + u32 overflow_mask; + u32 underflow_mask; + + if (playback) { + ctrl_reg = __raw_readl(mxs_adc->audioout_base + HW_AUDIOOUT_CTRL); + underflow_mask = BM_AUDIOOUT_CTRL_FIFO_UNDERFLOW_IRQ; + overflow_mask = BM_AUDIOOUT_CTRL_FIFO_OVERFLOW_IRQ; + } else { + ctrl_reg = __raw_readl(mxs_adc->audioin_base + HW_AUDIOIN_CTRL); + underflow_mask = BM_AUDIOIN_CTRL_FIFO_UNDERFLOW_IRQ; + overflow_mask = BM_AUDIOIN_CTRL_FIFO_OVERFLOW_IRQ; + } + + if (ctrl_reg & underflow_mask) { + printk(KERN_DEBUG "%s underflow detected\n", + playback ? "DAC" : "ADC"); + + if (playback) + __raw_writel( + BM_AUDIOOUT_CTRL_FIFO_UNDERFLOW_IRQ, + mxs_adc->audioout_base + HW_AUDIOOUT_CTRL_CLR); + else + __raw_writel( + BM_AUDIOIN_CTRL_FIFO_UNDERFLOW_IRQ, + mxs_adc->audioin_base + HW_AUDIOIN_CTRL_CLR); + + } else if (ctrl_reg & overflow_mask) { + printk(KERN_DEBUG "%s overflow detected\n", + playback ? "DAC" : "ADC"); + + if (playback) + __raw_writel( + BM_AUDIOOUT_CTRL_FIFO_OVERFLOW_IRQ, + mxs_adc->audioout_base + HW_AUDIOOUT_CTRL_CLR); + else + __raw_writel(BM_AUDIOIN_CTRL_FIFO_OVERFLOW_IRQ, + mxs_adc->audioin_base + HW_AUDIOIN_CTRL_CLR); + } else + printk(KERN_WARNING "Unknown DAC error interrupt\n"); + + return IRQ_HANDLED; +} +/* END IRQs */ + +static int mxs_trigger(struct snd_pcm_substream *substream, + int cmd, + struct snd_soc_dai *cpu_dai) +{ + struct mxs_adc_priv *mxs_adc = snd_soc_dai_get_drvdata(cpu_dai); + int playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 1 : 0; + int ret = 0; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + + if (playback) { + /* enable the fifo error interrupt */ + __raw_writel(BM_AUDIOOUT_CTRL_FIFO_ERROR_IRQ_EN, + mxs_adc->audioout_base + HW_AUDIOOUT_CTRL_SET); + /* write a data to data reg to trigger the transfer */ + __raw_writel(0x0, + mxs_adc->audioout_base + HW_AUDIOOUT_DATA); + mxs_dac_schedule_ramp_work((struct delayed_work *) &dac_ramp_work); + } else { +// mxs_dma_get_info(prtd->dma_ch, &dma_info); +// cur_bar1 = dma_info.buf_addr; +// xfer_count1 = dma_info.xfer_count; + + __raw_writel(BM_AUDIOIN_CTRL_RUN, + mxs_adc->audioin_base + HW_AUDIOIN_CTRL_SET); + udelay(100); + +// mxs_dma_get_info(prtd->dma_ch, &dma_info); +// cur_bar2 = dma_info.buf_addr; +// xfer_count2 = dma_info.xfer_count; +// +// /* check if DMA getting stuck */ +// if ((xfer_count1 == xfer_count2) && (cur_bar1 == cur_bar2)) +// /* read a data from data reg to trigger the receive */ +// reg = __raw_readl(mxs_adc->audioin_base + HW_AUDIOIN_DATA); + + mxs_adc_schedule_ramp_work((struct delayed_work *) &adc_ramp_work); + } + break; + + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + + if (playback) { +// printk(KERN_INFO "SNDRV_PCM_TRIGGER_START\n"); +// printk(KERN_INFO "ctrl:%x\n", __raw_readl(mxs_adc->audioout_base + HW_AUDIOOUT_CTRL)); +// printk(KERN_INFO "stat:%x\n", __raw_readl(mxs_adc->audioout_base + HW_AUDIOOUT_STAT)); +// printk(KERN_INFO "srr:%x\n", __raw_readl(mxs_adc->audioout_base + HW_AUDIOOUT_DACSRR)); +// printk(KERN_INFO "vol:%x\n", __raw_readl(mxs_adc->audioout_base + HW_AUDIOOUT_DACVOLUME)); +// printk(KERN_INFO "debug:%x\n", __raw_readl(mxs_adc->audioout_base + HW_AUDIOOUT_DACDEBUG)); +// printk(KERN_INFO "hpvol:%x\n", __raw_readl(mxs_adc->audioout_base + HW_AUDIOOUT_HPVOL)); +// printk(KERN_INFO "pwrdn:%x\n", __raw_readl(mxs_adc->audioout_base + HW_AUDIOOUT_PWRDN)); +// printk(KERN_INFO "refc:%x\n", __raw_readl(mxs_adc->audioout_base + HW_AUDIOOUT_REFCTRL)); +// printk(KERN_INFO "anac:%x\n", __raw_readl(mxs_adc->audioout_base + HW_AUDIOOUT_ANACTRL)); +// printk(KERN_INFO "test:%x\n", __raw_readl(mxs_adc->audioout_base + HW_AUDIOOUT_TEST)); +// printk(KERN_INFO "bist:%x\n", __raw_readl(mxs_adc->audioout_base + HW_AUDIOOUT_BISTCTRL)); +// printk(KERN_INFO "anaclk:%x\n", __raw_readl(mxs_adc->audioout_base + HW_AUDIOOUT_ANACLKCTRL)); + + if (dac_ramp_done == 0) { + cancel_delayed_work((struct delayed_work *) &dac_ramp_work); + dac_ramp_done = 1; + } + __raw_writel(BM_AUDIOOUT_HPVOL_MUTE, + mxs_adc->audioout_base + HW_AUDIOOUT_HPVOL_SET); + __raw_writel(BM_AUDIOOUT_SPEAKERCTRL_MUTE, + mxs_adc->audioout_base + HW_AUDIOOUT_SPEAKERCTRL_SET); + /* disable the fifo error interrupt */ + __raw_writel(BM_AUDIOOUT_CTRL_FIFO_ERROR_IRQ_EN, + mxs_adc->audioout_base + HW_AUDIOOUT_CTRL_CLR); + mdelay(50); + } else { + if (adc_ramp_done == 0) { + cancel_delayed_work((struct delayed_work *) &adc_ramp_work); + adc_ramp_done = 1; + } + __raw_writel(BM_AUDIOIN_CTRL_RUN, + mxs_adc->audioin_base + HW_AUDIOIN_CTRL_CLR); + } + break; + + default: + printk(KERN_ERR "TRIGGER ERROR\n"); + ret = -EINVAL; + } + + return ret; +} + +static int mxs_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *cpu_dai) +{ + struct mxs_adc_priv *mxs_adc = snd_soc_dai_get_drvdata(cpu_dai); + int playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 1 : 0; + mxs_adc->irq_data.mxs_adc = mxs_adc; + mxs_adc->irq_data.substream = substream; + + work.mxs_adc = mxs_adc; + adc_ramp_work.mxs_adc = mxs_adc; + dac_ramp_work.mxs_adc = mxs_adc; + test.mxs_adc = mxs_adc; + INIT_DELAYED_WORK(&work, mxs_adc_work); + INIT_DELAYED_WORK(&adc_ramp_work, mxs_adc_ramp_work); + INIT_DELAYED_WORK(&dac_ramp_work, mxs_dac_ramp_work); + + /* Enable error interrupt */ + if (playback) { + __raw_writel(BM_AUDIOOUT_CTRL_FIFO_OVERFLOW_IRQ, + mxs_adc->audioout_base + HW_AUDIOOUT_CTRL_CLR); + __raw_writel(BM_AUDIOOUT_CTRL_FIFO_UNDERFLOW_IRQ, + mxs_adc->audioout_base + HW_AUDIOOUT_CTRL_CLR); + } else { + __raw_writel(BM_AUDIOIN_CTRL_FIFO_OVERFLOW_IRQ, + mxs_adc->audioin_base + HW_AUDIOIN_CTRL_CLR); + __raw_writel(BM_AUDIOIN_CTRL_FIFO_UNDERFLOW_IRQ, + mxs_adc->audioin_base + HW_AUDIOIN_CTRL_CLR); + __raw_writel(BM_AUDIOIN_CTRL_FIFO_ERROR_IRQ_EN, + mxs_adc->audioin_base + HW_AUDIOIN_CTRL_SET); + } + + return 0; +} + +static void mxs_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *cpu_dai) +{ + struct mxs_adc_priv *mxs_adc = snd_soc_dai_get_drvdata(cpu_dai); + int playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 1 : 0; + + /* Disable error interrupt */ + if (playback) { + __raw_writel(BM_AUDIOOUT_CTRL_FIFO_ERROR_IRQ_EN, + mxs_adc->audioout_base + HW_AUDIOOUT_CTRL_CLR); + } else { + __raw_writel(BM_AUDIOIN_CTRL_FIFO_ERROR_IRQ_EN, + mxs_adc->audioin_base + HW_AUDIOIN_CTRL_CLR); + } +} + +#define MXS_ADC_RATES SNDRV_PCM_RATE_8000_192000 +#define MXS_ADC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE) + +static const struct snd_soc_dai_ops mxs_adc_dai_ops = { + .startup = mxs_startup, + .trigger = mxs_trigger, + .shutdown = mxs_shutdown, +}; + +static int mxs_dai_probe(struct snd_soc_dai *dai) +{ + // TODO This does not make any sense. + struct mxs_adc_priv *mxs_adc = dev_get_drvdata(dai->dev); + + snd_soc_dai_set_drvdata(dai, mxs_adc); + + return 0; +} + +static struct snd_soc_dai_driver mxs_adc_dai = { + .name = "mxs-builtin-cpu-dai", + .probe = mxs_dai_probe, + .playback = { + .channels_min = 2, + .channels_max = 2, + .rates = MXS_ADC_RATES, + .formats = MXS_ADC_FORMATS, + }, + .capture = { + .channels_min = 2, + .channels_max = 2, + .rates = MXS_ADC_RATES, + .formats = MXS_ADC_FORMATS, + }, + .ops = &mxs_adc_dai_ops, +}; + +static const struct snd_soc_component_driver mxs_adc_component = { + .name = "mxs-xxx", //TODO change this name +}; + +static int mxs_adc_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct mxs_adc_priv *mxs_adc; + int ret = 0; + + if (!np) + return -EINVAL; + + mxs_adc = devm_kzalloc(&pdev->dev, sizeof(*mxs_adc), GFP_KERNEL); + if (!mxs_adc) + return -ENOMEM; + + mxs_adc->audioout_base = devm_ioremap(&pdev->dev, 0x80048000, 0x2000); + if (IS_ERR(mxs_adc->audioout_base)) + return PTR_ERR(mxs_adc->audioout_base); + + mxs_adc->audioin_base = devm_ioremap(&pdev->dev, 0x8004c000, 0x2000); + if (IS_ERR(mxs_adc->audioin_base)) + return PTR_ERR(mxs_adc->audioin_base); + + mxs_adc->rtc_base = devm_ioremap(&pdev->dev, 0x8005c000, 0x2000); + if (IS_ERR(mxs_adc->rtc_base)) + return PTR_ERR(mxs_adc->rtc_base); + + /* Get IRQ numbers */ + mxs_adc->dma_adc_err_irq = platform_get_irq(pdev, 0); + if (mxs_adc->dma_adc_err_irq < 0) { + ret = mxs_adc->dma_adc_err_irq; + dev_err(&pdev->dev, "failed to get ADC DMA ERR irq resource: %d\n", ret); + return ret; + } + + mxs_adc->dma_dac_err_irq = platform_get_irq(pdev, 1); + if (mxs_adc->dma_dac_err_irq < 0) { + ret = mxs_adc->dma_dac_err_irq; + dev_err(&pdev->dev, "failed to get DAC DMA ERR irq resource: %d\n", ret); + return ret; + } + + mxs_adc->hp_short_irq = platform_get_irq(pdev, 2); + if (mxs_adc->hp_short_irq < 0) { + ret = mxs_adc->hp_short_irq; + dev_err(&pdev->dev, "failed to get HP_SHORT irq resource: %d\n", ret); + return ret; + } + + /* Request IRQs */ + ret = devm_request_irq(&pdev->dev, mxs_adc->dma_adc_err_irq, mxs_err_irq, 0, "MXS DAC and ADC Error", + mxs_adc); + if (ret) { + printk(KERN_ERR "%s: Unable to request ADC/DAC error irq %d\n", + __func__, mxs_adc->dma_adc_err_irq); + return ret; + } + + ret = devm_request_irq(&pdev->dev, mxs_adc->dma_dac_err_irq, mxs_err_irq, 0, "MXS DAC and ADC Error", + mxs_adc); + if (ret) { + printk(KERN_ERR "%s: Unable to request ADC/DAC error irq %d\n", + __func__, mxs_adc->dma_dac_err_irq); + return ret; + } + + ret = devm_request_irq(&pdev->dev, mxs_adc->hp_short_irq, mxs_short_irq, + IRQF_DISABLED | IRQF_SHARED, "MXS DAC and ADC HP SHORT", mxs_adc); + if (ret) { + printk(KERN_ERR "%s: Unable to request ADC/DAC HP SHORT irq %d\n", + __func__, mxs_adc->hp_short_irq); + return ret; + } + + platform_set_drvdata(pdev, mxs_adc); + + ret = snd_soc_register_component(&pdev->dev, &mxs_adc_component, &mxs_adc_dai, 1); + if (ret) { + dev_err(&pdev->dev, "register DAI failed\n"); + return ret; + } + + ret = mxs_adc_pcm_platform_register(&pdev->dev); + if (ret) { + dev_err(&pdev->dev, "register PCM failed: %d\n", ret); + goto failed_pdev_alloc; + } + + return 0; + +failed_pdev_alloc: + snd_soc_unregister_component(&pdev->dev); + + return ret; +} + +static int mxs_adc_remove(struct platform_device *pdev) +{ + mxs_adc_pcm_platform_unregister(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); + + return 0; +} + +static const struct of_device_id mxs_adc_dai_dt_ids[] = { + { .compatible = "fsl,mxs-builtin-cpu-dai", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, mxs_adc_dai_dt_ids); + +static struct platform_driver mxs_adc_dai_driver = { + .probe = mxs_adc_probe, + .remove = mxs_adc_remove, + + .driver = { + .name = "mxs-builtin-cpu-dai", + .owner = THIS_MODULE, + .of_match_table = mxs_adc_dai_dt_ids, + }, +}; + +module_platform_driver(mxs_adc_dai_driver); + +MODULE_DESCRIPTION("Freescale MXS ADC/DAC SoC Codec DAI Driver"); +MODULE_AUTHOR("Michal Ulianko "); +MODULE_LICENSE("GPL"); --- /dev/null +++ b/sound/soc/mxs/mxs-builtin-pcm.c @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * Based on sound/soc/imx/imx-pcm-dma-mx2.c + * + * 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, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include "mxs-builtin-pcm.h" + +static const struct snd_pcm_hardware snd_mxs_hardware = { + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_RESUME | + SNDRV_PCM_INFO_INTERLEAVED, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S20_3LE | + SNDRV_PCM_FMTBIT_S24_LE, + .channels_min = 2, + .channels_max = 2, + .period_bytes_min = 32, + .period_bytes_max = 8192, + .periods_min = 1, + .periods_max = 52, + .buffer_bytes_max = 64 * 1024, + .fifo_size = 32, +}; + +static const struct snd_dmaengine_pcm_config mxs_dmaengine_pcm_config = { + .pcm_hardware = &snd_mxs_hardware, + .prealloc_buffer_size = 64 * 1024, +}; + +int mxs_adc_pcm_platform_register(struct device *dev) +{ + return snd_dmaengine_pcm_register(dev, &mxs_dmaengine_pcm_config, + SND_DMAENGINE_PCM_FLAG_NO_RESIDUE); +} +EXPORT_SYMBOL_GPL(mxs_adc_pcm_platform_register); + +void mxs_adc_pcm_platform_unregister(struct device *dev) +{ + snd_dmaengine_pcm_unregister(dev); +} +EXPORT_SYMBOL_GPL(mxs_adc_pcm_platform_unregister); + +MODULE_LICENSE("GPL"); --- /dev/null +++ b/sound/soc/mxs/mxs-builtin-pcm.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * 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, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef _MXS_PCM_H +#define _MXS_PCM_H + +int mxs_adc_pcm_platform_register(struct device *dev); +void mxs_adc_pcm_platform_unregister(struct device *dev); + +#endif