diff options
Diffstat (limited to 'sound/soc/codecs/tlv320aic326x.c')
-rw-r--r-- | sound/soc/codecs/tlv320aic326x.c | 1494 |
1 files changed, 869 insertions, 625 deletions
diff --git a/sound/soc/codecs/tlv320aic326x.c b/sound/soc/codecs/tlv320aic326x.c index 5b0be9bb642e..a8cde73363bf 100644 --- a/sound/soc/codecs/tlv320aic326x.c +++ b/sound/soc/codecs/tlv320aic326x.c @@ -37,9 +37,9 @@ #include <linux/delay.h> #include <linux/pm.h> #include <linux/i2c.h> +#include <linux/pm_runtime.h> #include <linux/spi/spi.h> #include <linux/platform_device.h> -#include <linux/switch.h> #include <sound/jack.h> #include <linux/irq.h> #include <linux/interrupt.h> @@ -56,30 +56,29 @@ #include <sound/soc-dapm.h> #include <sound/initval.h> #include <linux/mfd/tlv320aic3262-registers.h> -#include <linux/mfd/tlv320aic3262-core.h> -#include "aic3xxx_cfw.h" -#include "aic3xxx_cfw_ops.h" +#include <linux/mfd/tlv320aic3xxx-core.h> +#include "aic3xxx/aic3xxx_cfw.h" +#include "aic3xxx/aic3xxx_cfw_ops.h" #include "tlv320aic326x.h" -#include "aic3262_codec_ops.h" -#include "tlv320aic3262_default_fw.h" -#define SOC_DOUBLE_R_SX_TLV3262(xname, xreg_left, xreg_right, xshift,\ - xmin, xmax, tlv_array) \ + +#define SOC_DOUBLE_R_SX_TLV3262(xname, xreg_left, xreg_right, xshift, \ + xmin, xmax, tlv_array) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ - SNDRV_CTL_ELEM_ACCESS_READWRITE, \ + SNDRV_CTL_ELEM_ACCESS_READWRITE, \ .tlv.p = (tlv_array), \ .info = snd_soc_info_volsw_2r_sx, \ .get = snd_soc_get_volsw_2r_sx, \ .put = snd_soc_put_volsw_2r_sx_aic3262, \ - .private_value = (unsigned long) &(struct soc_mixer_control) \ - {.reg = xreg_left, \ - .rreg = xreg_right, .shift = xshift, \ - .min = xmin, .max = xmax} } + .private_value = (unsigned long)&(struct soc_mixer_control) \ + {.reg = xreg_left, \ + .rreg = xreg_right, .shift = xshift, \ + .min = xmin, .max = xmax} } -/***************************************************************************** +/****************************************************************************** Macros ****************************************************************************** @@ -93,9 +92,6 @@ static int aic3262_hw_params(struct snd_pcm_substream *substream, static int aic3262_mute(struct snd_soc_dai *dai, int mute); -static int aic3262_set_dai_sysclk(struct snd_soc_dai *codec_dai, - int clk_id, unsigned int freq, int dir); - static int aic3262_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt); static int aic3262_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source, @@ -111,33 +107,37 @@ static int aic3262_set_mode_put(struct snd_kcontrol *kcontrol, static int aic326x_adc_dsp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event); +static int aic3262_get_runstate(struct snd_soc_codec *codec); +static int aic3262_dsp_pwrdwn_status(struct snd_soc_codec *codec); +static int aic3262_dsp_pwrup(struct snd_soc_codec *codec, int state); +static int aic3262_restart_dsps_sync(struct snd_soc_codec *codec, int rs); -static long debug_level; -module_param(debug_level, long, 0); -MODULE_PARM_DESC(debug_level, "Debug level for printing"); +static inline unsigned int dsp_non_sync_mode(unsigned int state) + { return (!((state & 0x03) && (state & 0x30))); } /** * snd_soc_put_volsw_2r_sx - double with tlv and variable data size - * mixer put callback + * mixer put callback * @kcontrol: mixer control * @uinfo: control element information * * Returns 0 for success. */ int snd_soc_put_volsw_2r_sx_aic3262(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) + struct snd_ctl_elem_value *ucontrol) { struct soc_mixer_control *mc = - (struct soc_mixer_control *)kcontrol->private_value; + (struct soc_mixer_control *)kcontrol->private_value; struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - unsigned int mask = (1 << mc->shift) - 1; + unsigned int mask = (1<<mc->shift)-1; int min = mc->min; int ret; unsigned int val, valr; - val = ((ucontrol->value.integer.value[0] + min) & 0xff); + + val = ((ucontrol->value.integer.value[0]+min) & 0xff); val &= mask; - valr = ((ucontrol->value.integer.value[1] + min) & 0xff); + valr = ((ucontrol->value.integer.value[1]+min) & 0xff); valr &= mask; ret = 0; @@ -150,27 +150,6 @@ int snd_soc_put_volsw_2r_sx_aic3262(struct snd_kcontrol *kcontrol, return 0; } -static ssize_t debug_level_show(struct device *dev, - struct device_attribute *attr, - char *buf, size_t count) -{ - return sprintf(buf, "%ld\n", debug_level); -} - -static ssize_t debug_level_set(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - int ret; - - ret = kstrtol(buf, 10, &debug_level); - if (ret) - return ret; - return count; -} - -static DEVICE_ATTR(debug_level, 0644, debug_level_show, debug_level_set); - static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -6350, 50, 0); static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -1200, 50, 0); static const DECLARE_TLV_DB_SCALE(spk_gain_tlv, 600, 600, 0); @@ -284,7 +263,6 @@ static const struct snd_kcontrol_new aic3262_snd_controls[] = { struct snd_soc_dai_ops aic3262_asi1_dai_ops = { .hw_params = aic3262_hw_params, .digital_mute = aic3262_mute, - .set_sysclk = aic3262_set_dai_sysclk, .set_fmt = aic3262_set_dai_fmt, .set_pll = aic3262_dai_set_pll, }; @@ -292,7 +270,6 @@ struct snd_soc_dai_ops aic3262_asi1_dai_ops = { struct snd_soc_dai_ops aic3262_asi2_dai_ops = { .hw_params = aic3262_hw_params, .digital_mute = aic3262_mute, - .set_sysclk = aic3262_set_dai_sysclk, .set_fmt = aic3262_set_dai_fmt, .set_pll = aic3262_dai_set_pll, }; @@ -300,7 +277,6 @@ struct snd_soc_dai_ops aic3262_asi2_dai_ops = { struct snd_soc_dai_ops aic3262_asi3_dai_ops = { .hw_params = aic3262_hw_params, .digital_mute = aic3262_mute, - .set_sysclk = aic3262_set_dai_sysclk, .set_fmt = aic3262_set_dai_fmt, .set_pll = aic3262_dai_set_pll, }; @@ -311,14 +287,14 @@ struct snd_soc_dai_driver aic326x_dai_driver[] = { .playback = { .stream_name = "ASI1 Playback", .channels_min = 1, - .channels_max = 2, + .channels_max = 8, .rates = AIC3262_RATES, .formats = AIC3262_FORMATS, }, .capture = { .stream_name = "ASI1 Capture", .channels_min = 1, - .channels_max = 2, + .channels_max = 8, .rates = AIC3262_RATES, .formats = AIC3262_FORMATS, }, @@ -363,148 +339,150 @@ struct snd_soc_dai_driver aic326x_dai_driver[] = { }; - static const unsigned int adc_ma_tlv[] = { - TLV_DB_RANGE_HEAD(4), - 0, 29, TLV_DB_SCALE_ITEM(-1450, 500, 0), - 30, 35, TLV_DB_SCALE_ITEM(-2060, 1000, 0), - 36, 38, TLV_DB_SCALE_ITEM(-2660, 2000, 0), - 39, 40, TLV_DB_SCALE_ITEM(-3610, 5000, 0), + TLV_DB_RANGE_HEAD(7), + 1, 1, TLV_DB_SCALE_ITEM(-3610, 0, 0), + 2, 2, TLV_DB_SCALE_ITEM(-3010, 0, 0), + 3, 3, TLV_DB_SCALE_ITEM(-2660, 0, 0), + 4, 4, TLV_DB_SCALE_ITEM(-2410, 0, 0), + 5, 7, TLV_DB_SCALE_ITEM(-2210, 1500, 0), + 8, 11, TLV_DB_SCALE_ITEM(-1810, 1000, 0), + 12, 41 , TLV_DB_SCALE_ITEM(-1450, 500, 0) }; static const DECLARE_TLV_DB_SCALE(lo_hp_tlv, -7830, 50, 0); static const struct snd_kcontrol_new mal_pga_mixer_controls[] = { - SOC_DAPM_SINGLE("IN1L Switch", AIC3262_MA_CNTL, 5, 1, 0), + SOC_DAPM_SINGLE("IN1 Left Capture Switch", AIC3262_MA_CNTL, 5, 1, 0), SOC_DAPM_SINGLE_TLV("Left MicPGA Volume", AIC3262_LADC_PGA_MAL_VOL, 0, 0x3f, 1, adc_ma_tlv), }; static const struct snd_kcontrol_new mar_pga_mixer_controls[] = { - SOC_DAPM_SINGLE("IN1R Switch", AIC3262_MA_CNTL, 4, 1, 0), + SOC_DAPM_SINGLE("IN1 Right Capture Switch", AIC3262_MA_CNTL, 4, 1, 0), SOC_DAPM_SINGLE_TLV("Right MicPGA Volume", AIC3262_RADC_PGA_MAR_VOL, 0, 0x3f, 1, adc_ma_tlv), }; /* Left HPL Mixer */ static const struct snd_kcontrol_new hpl_output_mixer_controls[] = { - SOC_DAPM_SINGLE("MAL Switch", AIC3262_HP_AMP_CNTL_R1, 7, 1, + SOC_DAPM_SINGLE("MA Left Playback Switch", AIC3262_HP_AMP_CNTL_R1, 7, 1, 0), - SOC_DAPM_SINGLE("LDAC Switch", AIC3262_HP_AMP_CNTL_R1, + SOC_DAPM_SINGLE("Left DAC Playback Switch", AIC3262_HP_AMP_CNTL_R1, 5, 1, 0), - SOC_DAPM_SINGLE_TLV("LOL-B1 Volume", + SOC_DAPM_SINGLE_TLV("LO Left-B1 Playback Volume", AIC3262_HP_AMP_CNTL_R2, 0, 0x7f, 1, lo_hp_tlv), }; /* Right HPR Mixer */ static const struct snd_kcontrol_new hpr_output_mixer_controls[] = { - SOC_DAPM_SINGLE_TLV("LOR-B1 Volume", + SOC_DAPM_SINGLE_TLV("LO Right-B1 Playback Volume", AIC3262_HP_AMP_CNTL_R3, 0, 0x7f, 1, lo_hp_tlv), - SOC_DAPM_SINGLE("LDAC Switch", AIC3262_HP_AMP_CNTL_R1, + SOC_DAPM_SINGLE("Left DAC Playback Switch", AIC3262_HP_AMP_CNTL_R1, 2, 1, 0), - SOC_DAPM_SINGLE("RDAC Switch", AIC3262_HP_AMP_CNTL_R1, + SOC_DAPM_SINGLE("Right DAC Playback Switch", AIC3262_HP_AMP_CNTL_R1, 4, 1, 0), - SOC_DAPM_SINGLE("MAR Switch", AIC3262_HP_AMP_CNTL_R1, + SOC_DAPM_SINGLE("MA Right Playback Switch", AIC3262_HP_AMP_CNTL_R1, 6, 1, 0), }; /* Left LOL Mixer */ static const struct snd_kcontrol_new lol_output_mixer_controls[] = { - SOC_DAPM_SINGLE("MAL Switch", AIC3262_LINE_AMP_CNTL_R2, + SOC_DAPM_SINGLE("MA Left Playback Switch", AIC3262_LINE_AMP_CNTL_R2, 7, 1, 0), - SOC_DAPM_SINGLE("IN1L-B Switch", AIC3262_LINE_AMP_CNTL_R2, + SOC_DAPM_SINGLE("IN1 Left-B Capture Switch", AIC3262_LINE_AMP_CNTL_R2, 3, 1, 0), - SOC_DAPM_SINGLE("LDAC Switch", AIC3262_LINE_AMP_CNTL_R1, + SOC_DAPM_SINGLE("Left DAC Playback Switch", AIC3262_LINE_AMP_CNTL_R1, 7, 1, 0), - SOC_DAPM_SINGLE("RDAC Switch", AIC3262_LINE_AMP_CNTL_R1, + SOC_DAPM_SINGLE("Right DAC Playback Switch", AIC3262_LINE_AMP_CNTL_R1, 5, 1, 0), }; /* Right LOR Mixer */ static const struct snd_kcontrol_new lor_output_mixer_controls[] = { - SOC_DAPM_SINGLE("LOL Switch", AIC3262_LINE_AMP_CNTL_R1, + SOC_DAPM_SINGLE("LO Left Playback Switch", AIC3262_LINE_AMP_CNTL_R1, 2, 1, 0), - SOC_DAPM_SINGLE("RDAC Switch", AIC3262_LINE_AMP_CNTL_R1, + SOC_DAPM_SINGLE("Right DAC Playback Switch", AIC3262_LINE_AMP_CNTL_R1, 6, 1, 0), - SOC_DAPM_SINGLE("MAR Switch", AIC3262_LINE_AMP_CNTL_R2, + SOC_DAPM_SINGLE("MA Right Playback Switch", AIC3262_LINE_AMP_CNTL_R2, 6, 1, 0), - SOC_DAPM_SINGLE("IN1R-B Switch", AIC3262_LINE_AMP_CNTL_R2, + SOC_DAPM_SINGLE("IN1 Right-B Capture Switch", AIC3262_LINE_AMP_CNTL_R2, 0, 1, 0), }; /* Left SPKL Mixer */ static const struct snd_kcontrol_new spkl_output_mixer_controls[] = { - SOC_DAPM_SINGLE("MAL Switch", AIC3262_SPK_AMP_CNTL_R1, + SOC_DAPM_SINGLE("MA Left Playback Switch", AIC3262_SPK_AMP_CNTL_R1, 7, 1, 0), - SOC_DAPM_SINGLE_TLV("LOL Volume", + SOC_DAPM_SINGLE_TLV("LO Left Playback Volume", AIC3262_SPK_AMP_CNTL_R2, 0, 0x7f, 1, lo_hp_tlv), SOC_DAPM_SINGLE("SPR_IN Switch", AIC3262_SPK_AMP_CNTL_R1, 2, 1, 0), }; /* Right SPKR Mixer */ static const struct snd_kcontrol_new spkr_output_mixer_controls[] = { - SOC_DAPM_SINGLE_TLV("LOR Volume", + SOC_DAPM_SINGLE_TLV("LO Right Playback Volume", AIC3262_SPK_AMP_CNTL_R3, 0, 0x7f, 1, lo_hp_tlv), - SOC_DAPM_SINGLE("MAR Switch", + SOC_DAPM_SINGLE("MA Right Playback Switch", AIC3262_SPK_AMP_CNTL_R1, 6, 1, 0), }; /* REC Mixer */ static const struct snd_kcontrol_new rec_output_mixer_controls[] = { - SOC_DAPM_SINGLE_TLV("LOL-B2 Volume", + SOC_DAPM_SINGLE_TLV("LO Left-B2 Playback Volume", AIC3262_RAMP_CNTL_R1, 0, 0x7f, 1, lo_hp_tlv), - SOC_DAPM_SINGLE_TLV("IN1L Volume", + SOC_DAPM_SINGLE_TLV("IN1 Left Capture Volume", AIC3262_IN1L_SEL_RM, 0, 0x7f, 1, lo_hp_tlv), - SOC_DAPM_SINGLE_TLV("IN1R Volume", + SOC_DAPM_SINGLE_TLV("IN1 Right Capture Volume", AIC3262_IN1R_SEL_RM, 0, 0x7f, 1, lo_hp_tlv), - SOC_DAPM_SINGLE_TLV("LOR-B2 Volume", + SOC_DAPM_SINGLE_TLV("LO Right-B2 Playback Volume", AIC3262_RAMP_CNTL_R2, 0, 0x7f, 1, lo_hp_tlv), }; /* Left Input Mixer */ static const struct snd_kcontrol_new left_input_mixer_controls[] = { - SOC_DAPM_SINGLE("IN1L Switch", AIC3262_LMIC_PGA_PIN, + SOC_DAPM_SINGLE("IN1 Left Capture Switch", AIC3262_LMIC_PGA_PIN, 6, 3, 0), - SOC_DAPM_SINGLE("IN2L Switch", AIC3262_LMIC_PGA_PIN, + SOC_DAPM_SINGLE("IN2 Left Capture Switch", AIC3262_LMIC_PGA_PIN, 4, 3, 0), - SOC_DAPM_SINGLE("IN3L Switch", AIC3262_LMIC_PGA_PIN, + SOC_DAPM_SINGLE("IN3 Left Capture Switch", AIC3262_LMIC_PGA_PIN, 2, 3, 0), - SOC_DAPM_SINGLE("IN4L Switch", AIC3262_LMIC_PGA_PM_IN4, + SOC_DAPM_SINGLE("IN4 Left Capture Switch", AIC3262_LMIC_PGA_PM_IN4, 5, 1, 0), - SOC_DAPM_SINGLE("IN1R Switch", AIC3262_LMIC_PGA_PIN, + SOC_DAPM_SINGLE("IN1 Right Capture Switch", AIC3262_LMIC_PGA_PIN, 0, 3, 0), - SOC_DAPM_SINGLE("IN2R Switch", AIC3262_LMIC_PGA_MIN, + SOC_DAPM_SINGLE("IN2 Right Capture Switch", AIC3262_LMIC_PGA_MIN, 4, 3, 0), - SOC_DAPM_SINGLE("IN3R Switch", AIC3262_LMIC_PGA_MIN, + SOC_DAPM_SINGLE("IN3 Right Capture Switch", AIC3262_LMIC_PGA_MIN, 2, 3, 0), - SOC_DAPM_SINGLE("IN4R Switch", AIC3262_LMIC_PGA_PM_IN4, + SOC_DAPM_SINGLE("IN4 Right Capture Switch", AIC3262_LMIC_PGA_PM_IN4, 4, 1, 0), - SOC_DAPM_SINGLE("CM2L Switch", AIC3262_LMIC_PGA_MIN, + SOC_DAPM_SINGLE("CM2 Left Capture Switch", AIC3262_LMIC_PGA_MIN, 0, 3, 0), - SOC_DAPM_SINGLE("CM1L Switch", AIC3262_LMIC_PGA_MIN, + SOC_DAPM_SINGLE("CM1 Left Capture Switch", AIC3262_LMIC_PGA_MIN, 6, 3, 0), }; /* Right Input Mixer */ static const struct snd_kcontrol_new right_input_mixer_controls[] = { - SOC_DAPM_SINGLE("IN1R Switch", AIC3262_RMIC_PGA_PIN, + SOC_DAPM_SINGLE("IN1 Right Capture Switch", AIC3262_RMIC_PGA_PIN, 6, 3, 0), - SOC_DAPM_SINGLE("IN2R Switch", AIC3262_RMIC_PGA_PIN, + SOC_DAPM_SINGLE("IN2 Right Capture Switch", AIC3262_RMIC_PGA_PIN, 4, 3, 0), - SOC_DAPM_SINGLE("IN3R Switch", AIC3262_RMIC_PGA_PIN, + SOC_DAPM_SINGLE("IN3 Right Capture Switch", AIC3262_RMIC_PGA_PIN, 2, 3, 0), - SOC_DAPM_SINGLE("IN4R Switch", AIC3262_RMIC_PGA_PM_IN4, + SOC_DAPM_SINGLE("IN4 Right Capture Switch", AIC3262_RMIC_PGA_PM_IN4, 5, 1, 0), - SOC_DAPM_SINGLE("IN2L Switch", AIC3262_RMIC_PGA_PIN, + SOC_DAPM_SINGLE("IN2 Left Capture Switch", AIC3262_RMIC_PGA_PIN, 0, 3, 0), - SOC_DAPM_SINGLE("IN1L Switch", AIC3262_RMIC_PGA_MIN, + SOC_DAPM_SINGLE("IN1 Left Capture Switch", AIC3262_RMIC_PGA_MIN, 4, 3, 0), - SOC_DAPM_SINGLE("IN3L Switch", AIC3262_RMIC_PGA_MIN, + SOC_DAPM_SINGLE("IN3 Left Capture Switch", AIC3262_RMIC_PGA_MIN, 2, 3, 0), - SOC_DAPM_SINGLE("IN4L Switch", AIC3262_RMIC_PGA_PM_IN4, + SOC_DAPM_SINGLE("IN4 Left Capture Switch", AIC3262_RMIC_PGA_PM_IN4, 4, 1, 0), - SOC_DAPM_SINGLE("CM1R Switch", AIC3262_RMIC_PGA_MIN, + SOC_DAPM_SINGLE("CM1 Right Capture Switch", AIC3262_RMIC_PGA_MIN, 6, 3, 0), - SOC_DAPM_SINGLE("CM2R Switch", AIC3262_RMIC_PGA_MIN, + SOC_DAPM_SINGLE("CM2 Right Capture Switch", AIC3262_RMIC_PGA_MIN, 0, 3, 0), }; @@ -720,31 +698,69 @@ static int aic326x_hp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { int reg_mask = 0; + int mute_reg = 0; int ret_wbits = 0; + u8 hpl_hpr; - if (w->shift == 1) - reg_mask = AIC3262_HPL_POWER_MASK; - if (w->shift == 0) - reg_mask = AIC3262_HPR_POWER_MASK; + if (w->shift == 1) { + reg_mask = AIC3262_HPL_POWER_STATUS_MASK; + mute_reg = AIC3262_HPL_VOL; + } + if (w->shift == 0) { + reg_mask = AIC3262_HPR_POWER_STATUS_MASK; + mute_reg = AIC3262_HPR_VOL; + } switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_update_bits(w->codec, AIC3262_CHARGE_PUMP_CNTL, + AIC3262_DYNAMIC_OFFSET_CALIB_MASK, + AIC3262_DYNAMIC_OFFSET_CALIB); + snd_soc_write(w->codec, mute_reg, 0x80); + snd_soc_update_bits(w->codec, AIC3262_HP_CTL, + AIC3262_HP_STAGE_MASK , + AIC3262_HP_STAGE_25 << AIC3262_HP_STAGE_SHIFT); + break; + case SND_SOC_DAPM_POST_PMU: - ret_wbits = aic3262_wait_bits(w->codec->control_data, + ret_wbits = aic3xxx_wait_bits(w->codec->control_data, AIC3262_HP_FLAG, reg_mask, - reg_mask, TIME_DELAY, - DELAY_COUNTER); + reg_mask, AIC326X_TIME_DELAY, + AIC326X_DELAY_COUNTER); if (!ret_wbits) { dev_err(w->codec->dev, "HP POST_PMU timedout\n"); return -1; } + snd_soc_update_bits(w->codec, AIC3262_HP_CTL, + AIC3262_HP_STAGE_MASK , + AIC3262_HP_STAGE_100 << AIC3262_HP_STAGE_SHIFT); + break; + + case SND_SOC_DAPM_PRE_PMD: + snd_soc_update_bits(w->codec, AIC3262_HP_CTL, + AIC3262_HP_STAGE_MASK , + AIC3262_HP_STAGE_25 << AIC3262_HP_STAGE_SHIFT); + hpl_hpr = snd_soc_read(w->codec, AIC3262_HP_AMP_CNTL_R1); + if ((hpl_hpr & 0x3) == 0x3) { + snd_soc_update_bits(w->codec, AIC3262_HP_AMP_CNTL_R1, + AIC3262_HPL_POWER_MASK, 0x0); + mdelay(1); + snd_soc_update_bits(w->codec, AIC3262_HP_AMP_CNTL_R1, + AIC3262_HPR_POWER_MASK, 0x0); + } break; + case SND_SOC_DAPM_POST_PMD: - ret_wbits = aic3262_wait_bits(w->codec->control_data, + ret_wbits = aic3xxx_wait_bits(w->codec->control_data, AIC3262_HP_FLAG, reg_mask, 0, - TIME_DELAY, DELAY_COUNTER); + AIC326X_TIME_DELAY, + AIC326X_DELAY_COUNTER); if (!ret_wbits) { dev_err(w->codec->dev, "HP POST_PMD timedout\n"); return -1; } + snd_soc_write(w->codec, mute_reg, 0xb9); + snd_soc_write(w->codec, AIC3262_POWER_CONF, + snd_soc_read(w->codec, AIC3262_POWER_CONF)); break; default: BUG(); @@ -773,29 +789,31 @@ static int aic326x_dac_event(struct snd_soc_dapm_widget *w, int other_dsp = 0, run_state = 0; if (w->shift == 7) { - reg_mask = AIC3262_LDAC_POWER_MASK; - run_state_mask = AIC3262_COPS_MDSP_D_L; + reg_mask = AIC3262_LDAC_POWER_STATUS_MASK; + run_state_mask = AIC3XXX_COPS_MDSP_D_L; } if (w->shift == 6) { - reg_mask = AIC3262_RDAC_POWER_MASK; - run_state_mask = AIC3262_COPS_MDSP_D_R; + reg_mask = AIC3262_RDAC_POWER_STATUS_MASK; + run_state_mask = AIC3XXX_COPS_MDSP_D_R; } switch (event) { case SND_SOC_DAPM_POST_PMU: - ret_wbits = aic3262_wait_bits(w->codec->control_data, + ret_wbits = aic3xxx_wait_bits(w->codec->control_data, AIC3262_DAC_FLAG, reg_mask, - reg_mask, TIME_DELAY, - DELAY_COUNTER); + reg_mask, AIC326X_TIME_DELAY, + AIC326X_DELAY_COUNTER); - sync_needed = SYNC_STATE(aic3262); - non_sync_state = DSP_NON_SYNC_MODE(aic3262->dsp_runstate); - other_dsp = aic3262->dsp_runstate & AIC3262_COPS_MDSP_A; + sync_needed = aic3xxx_reg_read(w->codec->control_data, + AIC3262_DAC_PRB); + non_sync_state = dsp_non_sync_mode(aic3262->dsp_runstate); + other_dsp = aic3262->dsp_runstate & AIC3XXX_COPS_MDSP_A; if (sync_needed && non_sync_state && other_dsp) { - run_state = get_runstate(aic3262->codec->control_data); - aic3262_dsp_pwrdwn_status(aic3262); - aic3262_dsp_pwrup(aic3262, run_state); + run_state = aic3262_get_runstate( + aic3262->codec); + aic3262_dsp_pwrdwn_status(aic3262->codec); + aic3262_dsp_pwrup(aic3262->codec, run_state); } aic3262->dsp_runstate |= run_state_mask; @@ -806,9 +824,10 @@ static int aic326x_dac_event(struct snd_soc_dapm_widget *w, break; case SND_SOC_DAPM_POST_PMD: - ret_wbits = aic3262_wait_bits(w->codec->control_data, + ret_wbits = aic3xxx_wait_bits(w->codec->control_data, AIC3262_DAC_FLAG, reg_mask, 0, - TIME_DELAY, DELAY_COUNTER); + AIC326X_TIME_DELAY, + AIC326X_DELAY_COUNTER); aic3262->dsp_runstate = (aic3262->dsp_runstate & ~run_state_mask); @@ -839,9 +858,9 @@ static int aic326x_spk_event(struct snd_soc_dapm_widget *w, int reg_mask; if (w->shift == 1) - reg_mask = AIC3262_SPKL_POWER_MASK; + reg_mask = AIC3262_SPKL_POWER_STATUS_MASK; if (w->shift == 0) - reg_mask = AIC3262_SPKR_POWER_MASK; + reg_mask = AIC3262_SPKR_POWER_STATUS_MASK; switch (event) { case SND_SOC_DAPM_POST_PMU: mdelay(1); @@ -914,7 +933,6 @@ static int aic3262_set_mode_put(struct snd_kcontrol *kcontrol, else ret = aic3xxx_cfw_setmode_cfg(priv_ds->cfw_p, next_mode, next_cfg); - return ret; } @@ -939,25 +957,27 @@ static int aic326x_adc_dsp_event(struct snd_soc_dapm_widget *w, if (w->shift == 7) { reg_mask = AIC3262_LADC_POWER_MASK; - run_state_mask = AIC3262_COPS_MDSP_A_L; + run_state_mask = AIC3XXX_COPS_MDSP_A_L; } if (w->shift == 6) { reg_mask = AIC3262_RADC_POWER_MASK; - run_state_mask = AIC3262_COPS_MDSP_A_R; + run_state_mask = AIC3XXX_COPS_MDSP_A_R; } switch (event) { case SND_SOC_DAPM_POST_PMU: - ret_wbits = aic3262_wait_bits(w->codec->control_data, + ret_wbits = aic3xxx_wait_bits(w->codec->control_data, AIC3262_ADC_FLAG, reg_mask, - reg_mask, TIME_DELAY, - DELAY_COUNTER); - sync_needed = SYNC_STATE(aic3262); - non_sync_state = DSP_NON_SYNC_MODE(aic3262->dsp_runstate); - other_dsp = aic3262->dsp_runstate & AIC3262_COPS_MDSP_D; + reg_mask, AIC326X_TIME_DELAY, + AIC326X_DELAY_COUNTER); + sync_needed = aic3xxx_reg_read(w->codec->control_data, + AIC3262_DAC_PRB); + non_sync_state = dsp_non_sync_mode(aic3262->dsp_runstate); + other_dsp = aic3262->dsp_runstate & AIC3XXX_COPS_MDSP_D; if (sync_needed && non_sync_state && other_dsp) { - run_state = get_runstate(aic3262->codec->control_data); - aic3262_dsp_pwrdwn_status(aic3262); - aic3262_dsp_pwrup(aic3262, run_state); + run_state = aic3262_get_runstate( + aic3262->codec); + aic3262_dsp_pwrdwn_status(aic3262->codec); + aic3262_dsp_pwrup(aic3262->codec, run_state); } aic3262->dsp_runstate |= run_state_mask; if (!ret_wbits) { @@ -966,9 +986,10 @@ static int aic326x_adc_dsp_event(struct snd_soc_dapm_widget *w, } break; case SND_SOC_DAPM_POST_PMD: - ret_wbits = aic3262_wait_bits(w->codec->control_data, + ret_wbits = aic3xxx_wait_bits(w->codec->control_data, AIC3262_ADC_FLAG, reg_mask, 0, - TIME_DELAY, DELAY_COUNTER); + AIC326X_TIME_DELAY, + AIC326X_DELAY_COUNTER); aic3262->dsp_runstate = (aic3262->dsp_runstate & ~run_state_mask); if (!ret_wbits) { @@ -984,6 +1005,7 @@ static int aic326x_adc_dsp_event(struct snd_soc_dapm_widget *w, } static const struct snd_soc_dapm_widget aic3262_dapm_widgets[] = { + /* TODO: Can we switch these off ? */ SND_SOC_DAPM_AIF_IN("DIN1", "ASI1 Playback", 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_AIF_IN("DIN2", "ASI2 Playback", 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_AIF_IN("DIN3", "ASI3 Playback", 0, SND_SOC_NOPM, 0, 0), @@ -996,68 +1018,65 @@ static const struct snd_soc_dapm_widget aic3262_dapm_widgets[] = { SND_SOC_DAPM_POST_PMD), /* dapm widget (path domain) for HPL Output Mixer */ - SND_SOC_DAPM_MIXER("HPL Output Mixer", SND_SOC_NOPM, 0, 0, - &hpl_output_mixer_controls[0], - ARRAY_SIZE(hpl_output_mixer_controls)), + SND_SOC_DAPM_MIXER("HP Left Mixer", SND_SOC_NOPM, 0, 0, + &hpl_output_mixer_controls[0], + ARRAY_SIZE(hpl_output_mixer_controls)), /* dapm widget (path domain) for HPR Output Mixer */ - SND_SOC_DAPM_MIXER("HPR Output Mixer", SND_SOC_NOPM, 0, 0, - &hpr_output_mixer_controls[0], - ARRAY_SIZE(hpr_output_mixer_controls)), - - - SND_SOC_DAPM_PGA_E("HPL Driver", AIC3262_HP_AMP_CNTL_R1, - 1, 0, NULL, 0, aic326x_hp_event, - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_PGA_E("HPR Driver", AIC3262_HP_AMP_CNTL_R1, - 0, 0, NULL, 0, aic326x_hp_event, - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), - + SND_SOC_DAPM_MIXER("HP Right Mixer", SND_SOC_NOPM, 0, 0, + &hpr_output_mixer_controls[0], + ARRAY_SIZE(hpr_output_mixer_controls)), + + SND_SOC_DAPM_PGA_S("HP Left Playback Driver", 3, + AIC3262_HP_AMP_CNTL_R1, 1, 0, aic326x_hp_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_S("HP Right Playback Driver", 3, + AIC3262_HP_AMP_CNTL_R1, 0, 0, aic326x_hp_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), /* dapm widget (path domain) for LOL Output Mixer */ - SND_SOC_DAPM_MIXER("LOL Output Mixer", SND_SOC_NOPM, 0, 0, - &lol_output_mixer_controls[0], - ARRAY_SIZE(lol_output_mixer_controls)), + SND_SOC_DAPM_MIXER("LO Left Mixer", SND_SOC_NOPM, 0, 0, + &lol_output_mixer_controls[0], + ARRAY_SIZE(lol_output_mixer_controls)), /* dapm widget (path domain) for LOR Output Mixer mixer */ - SND_SOC_DAPM_MIXER("LOR Output Mixer", SND_SOC_NOPM, 0, 0, - &lor_output_mixer_controls[0], - ARRAY_SIZE(lor_output_mixer_controls)), - - SND_SOC_DAPM_PGA("LOL Driver", AIC3262_LINE_AMP_CNTL_R1, - 1, 0, NULL, 0), - SND_SOC_DAPM_PGA("LOR Driver", AIC3262_LINE_AMP_CNTL_R1, - 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("LO Right Mixer", SND_SOC_NOPM, 0, 0, + &lor_output_mixer_controls[0], + ARRAY_SIZE(lor_output_mixer_controls)), + SND_SOC_DAPM_PGA_S("LO Left Playback Driver", 2, + AIC3262_LINE_AMP_CNTL_R1, 1, 0, NULL, 0), + SND_SOC_DAPM_PGA_S("LO Right Playback Driver", 2, + AIC3262_LINE_AMP_CNTL_R1, 0, 0, NULL, 0), /* dapm widget (path domain) for SPKL Output Mixer */ - SND_SOC_DAPM_MIXER("SPKL Output Mixer", SND_SOC_NOPM, 0, 0, - &spkl_output_mixer_controls[0], - ARRAY_SIZE(spkl_output_mixer_controls)), + SND_SOC_DAPM_MIXER("SPK Left Mixer", SND_SOC_NOPM, 0, 0, + &spkl_output_mixer_controls[0], + ARRAY_SIZE(spkl_output_mixer_controls)), /* dapm widget (path domain) for SPKR Output Mixer */ - SND_SOC_DAPM_MIXER("SPKR Output Mixer", SND_SOC_NOPM, 0, 0, - &spkr_output_mixer_controls[0], - ARRAY_SIZE(spkr_output_mixer_controls)), - - SND_SOC_DAPM_PGA_E("SPKL Driver", AIC3262_SPK_AMP_CNTL_R1, - 1, 0, NULL, 0, aic326x_spk_event, - SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU), - SND_SOC_DAPM_PGA_E("SPKR Driver", AIC3262_SPK_AMP_CNTL_R1, - 0, 0, NULL, 0, aic326x_spk_event, - SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_MIXER("SPK Right Mixer", SND_SOC_NOPM, 0, 0, + &spkr_output_mixer_controls[0], + ARRAY_SIZE(spkr_output_mixer_controls)), + SND_SOC_DAPM_PGA_S("SPK Left Playback Driver", 3, + AIC3262_SPK_AMP_CNTL_R1, 1, 0, aic326x_spk_event, + SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PGA_S("SPK Right Playback Driver", 3, + AIC3262_SPK_AMP_CNTL_R1, 0, 0, aic326x_spk_event, + SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU), /* dapm widget (path domain) for SPKR Output Mixer */ - SND_SOC_DAPM_MIXER("REC Output Mixer", SND_SOC_NOPM, 0, 0, - &rec_output_mixer_controls[0], - ARRAY_SIZE(rec_output_mixer_controls)), - - SND_SOC_DAPM_PGA("RECP Driver", AIC3262_REC_AMP_CNTL_R5, - 7, 0, NULL, 0), - SND_SOC_DAPM_PGA("RECM Driver", AIC3262_REC_AMP_CNTL_R5, - 6, 0, NULL, 0), + SND_SOC_DAPM_MIXER("REC Mixer", SND_SOC_NOPM, 0, 0, + &rec_output_mixer_controls[0], + ARRAY_SIZE(rec_output_mixer_controls)), + SND_SOC_DAPM_PGA_S("RECP Playback Driver", 3, AIC3262_REC_AMP_CNTL_R5, + 7, 0, NULL, 0), + SND_SOC_DAPM_PGA_S("RECM Playback Driver", 3, AIC3262_REC_AMP_CNTL_R5, + 6, 0, NULL, 0), SND_SOC_DAPM_MUX("ASI1LIN Route", SND_SOC_NOPM, 0, 0, &asi1lin_control), @@ -1097,10 +1116,10 @@ static const struct snd_soc_dapm_widget aic3262_dapm_widgets[] = { SND_SOC_NOPM, 0, 0, &adcdacroute_control), SND_SOC_DAPM_PGA("CM", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_PGA("CM1L", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_PGA("CM2L", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_PGA("CM1R", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_PGA("CM2R", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("CM1 Left Capture", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("CM2 Left Capture", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("CM1 Right Capture", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("CM2 Right Capture", SND_SOC_NOPM, 0, 0, NULL, 0), /* TODO: Can we switch these off ? */ SND_SOC_DAPM_AIF_OUT("DOUT1", "ASI1 Capture", 0, SND_SOC_NOPM, 0, 0), @@ -1131,9 +1150,6 @@ static const struct snd_soc_dapm_widget aic3262_dapm_widgets[] = { SND_SOC_DAPM_PGA("ADC MiniDSP OUT2", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_PGA("ADC MiniDSP OUT3", SND_SOC_NOPM, 0, 0, NULL, 0), -/* SND_SOC_DAPM_MUX("DMICDAT Input Route", - SND_SOC_NOPM, 0, 0, &dmicinput_control),*/ - SND_SOC_DAPM_MUX("Left ADC Route", SND_SOC_NOPM, 0, 0, &adcl_mux), SND_SOC_DAPM_MUX("Right ADC Route", SND_SOC_NOPM, 0, 0, &adcr_mux), @@ -1144,72 +1160,80 @@ static const struct snd_soc_dapm_widget aic3262_dapm_widgets[] = { aic326x_adc_dsp_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_PGA("Left MicPGA", AIC3262_MICL_PGA, 7, 1, NULL, 0), - SND_SOC_DAPM_PGA("Right MicPGA", AIC3262_MICR_PGA, 7, 1, NULL, 0), + SND_SOC_DAPM_PGA_S("Left MicPGA", 0, AIC3262_MICL_PGA, 7, 1, NULL, 0), + SND_SOC_DAPM_PGA_S("Right MicPGA", 0, AIC3262_MICR_PGA, 7, 1, NULL, 0), - SND_SOC_DAPM_PGA("MAL PGA", AIC3262_MA_CNTL, - 3, 0, NULL, 0), - SND_SOC_DAPM_PGA("MAR PGA", AIC3262_MA_CNTL, - 2, 0, NULL, 0), + SND_SOC_DAPM_PGA_S("MA Left Playback PGA", 1, AIC3262_MA_CNTL, + 3, 0, NULL, 0), + SND_SOC_DAPM_PGA_S("MA Right Playback PGA", 1, AIC3262_MA_CNTL, + 2, 0, NULL, 0), /* dapm widget for MAL PGA Mixer */ - SND_SOC_DAPM_MIXER("MAL PGA Mixer", SND_SOC_NOPM, 0, 0, - &mal_pga_mixer_controls[0], - ARRAY_SIZE(mal_pga_mixer_controls)), + SND_SOC_DAPM_MIXER("MA Left PGA Mixer", SND_SOC_NOPM, 0, 0, + &mal_pga_mixer_controls[0], + ARRAY_SIZE(mal_pga_mixer_controls)), /* dapm widget for MAR PGA Mixer */ - SND_SOC_DAPM_MIXER("MAR PGA Mixer", SND_SOC_NOPM, 0, 0, - &mar_pga_mixer_controls[0], - ARRAY_SIZE(mar_pga_mixer_controls)), + SND_SOC_DAPM_MIXER("MA Right PGA Mixer", SND_SOC_NOPM, 0, 0, + &mar_pga_mixer_controls[0], + ARRAY_SIZE(mar_pga_mixer_controls)), /* dapm widget for Left Input Mixer */ SND_SOC_DAPM_MIXER("Left Input Mixer", SND_SOC_NOPM, 0, 0, - &left_input_mixer_controls[0], - ARRAY_SIZE(left_input_mixer_controls)), + &left_input_mixer_controls[0], + ARRAY_SIZE(left_input_mixer_controls)), /* dapm widget for Right Input Mixer */ SND_SOC_DAPM_MIXER("Right Input Mixer", SND_SOC_NOPM, 0, 0, - &right_input_mixer_controls[0], - ARRAY_SIZE(right_input_mixer_controls)), - - SND_SOC_DAPM_OUTPUT("HPL"), - SND_SOC_DAPM_OUTPUT("HPR"), - SND_SOC_DAPM_OUTPUT("LOL"), - SND_SOC_DAPM_OUTPUT("LOR"), - SND_SOC_DAPM_OUTPUT("SPKL"), - SND_SOC_DAPM_OUTPUT("SPKR"), - SND_SOC_DAPM_OUTPUT("RECP"), - SND_SOC_DAPM_OUTPUT("RECM"), - - SND_SOC_DAPM_INPUT("IN1L"), - SND_SOC_DAPM_INPUT("IN2L"), - SND_SOC_DAPM_INPUT("IN3L"), - SND_SOC_DAPM_INPUT("IN4L"), - SND_SOC_DAPM_INPUT("IN1R"), - SND_SOC_DAPM_INPUT("IN2R"), - SND_SOC_DAPM_INPUT("IN3R"), - SND_SOC_DAPM_INPUT("IN4R"), - SND_SOC_DAPM_INPUT("Left DMIC"), - SND_SOC_DAPM_INPUT("Right DMIC"), + &right_input_mixer_controls[0], + ARRAY_SIZE(right_input_mixer_controls)), + + SND_SOC_DAPM_OUTPUT("HP Left Playback"), + SND_SOC_DAPM_OUTPUT("HP Right Playback"), + SND_SOC_DAPM_OUTPUT("LO Left Playback"), + SND_SOC_DAPM_OUTPUT("LO Right Playback"), + SND_SOC_DAPM_OUTPUT("SPK Left Playback"), + SND_SOC_DAPM_OUTPUT("SPK Right Playback"), + SND_SOC_DAPM_OUTPUT("RECP Playback"), + SND_SOC_DAPM_OUTPUT("RECM Playback"), + + SND_SOC_DAPM_INPUT("IN1 Left Capture"), + SND_SOC_DAPM_INPUT("IN2 Left Capture"), + SND_SOC_DAPM_INPUT("IN3 Left Capture"), + SND_SOC_DAPM_INPUT("IN4 Left Capture"), + SND_SOC_DAPM_INPUT("IN1 Right Capture"), + SND_SOC_DAPM_INPUT("IN2 Right Capture"), + SND_SOC_DAPM_INPUT("IN3 Right Capture"), + SND_SOC_DAPM_INPUT("IN4 Right Capture"), + SND_SOC_DAPM_INPUT("Left DMIC Capture"), + SND_SOC_DAPM_INPUT("Right DMIC Capture"), SND_SOC_DAPM_MICBIAS("Mic Bias Ext", AIC3262_MIC_BIAS_CNTL, 6, 0), SND_SOC_DAPM_MICBIAS("Mic Bias Int", AIC3262_MIC_BIAS_CNTL, 2, 0), - SND_SOC_DAPM_SUPPLY("PLLCLK", AIC3262_PLL_PR_POW_REG, 7, 0, + SND_SOC_DAPM_SUPPLY_S("PLLCLK", 0, AIC3262_PLL_PR_POW_REG, 7, 0, pll_power_on_event, SND_SOC_DAPM_POST_PMU), - SND_SOC_DAPM_SUPPLY("DACCLK", AIC3262_NDAC_DIV_POW_REG, 7, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("CODEC_CLK_IN", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("DAC_MOD_CLK", AIC3262_MDAC_DIV_POW_REG, - 7, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("ADCCLK", AIC3262_NADC_DIV_POW_REG, 7, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("ADC_MOD_CLK", AIC3262_MADC_DIV_POW_REG, - 7, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("ASI1_BCLK", AIC3262_ASI1_BCLK_N, 7, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("ASI1_WCLK", AIC3262_ASI1_WCLK_N, 7, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("ASI2_BCLK", AIC3262_ASI2_BCLK_N, 7, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("ASI2_WCLK", AIC3262_ASI2_WCLK_N, 7, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("ASI3_BCLK", AIC3262_ASI3_BCLK_N, 7, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("ASI3_WCLK", AIC3262_ASI3_WCLK_N, 7, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DACCLK", 2, AIC3262_NDAC_DIV_POW_REG, 7, 0, + NULL, 0), + SND_SOC_DAPM_SUPPLY_S("CODEC_CLK_IN", 1, SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DAC_MOD_CLK", 3, AIC3262_MDAC_DIV_POW_REG, + 7, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ADCCLK", 2, AIC3262_NADC_DIV_POW_REG, + 7, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ADC_MOD_CLK", 3, AIC3262_MADC_DIV_POW_REG, + 7, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ASI1_BCLK", 4, AIC3262_ASI1_BCLK_N, + 7, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ASI1_WCLK", 4, AIC3262_ASI1_WCLK_N, + 7, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ASI2_BCLK", 4, AIC3262_ASI2_BCLK_N, + 7, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ASI2_WCLK", 4, AIC3262_ASI2_WCLK_N, + 7, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ASI3_BCLK", 4, AIC3262_ASI3_BCLK_N, + 7, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ASI3_WCLK", 4, AIC3262_ASI3_WCLK_N, + 7, 0, NULL, 0), SND_SOC_DAPM_MUX("ASI1_BCLK Route", SND_SOC_NOPM, 0, 0, &asi1bclk_control), SND_SOC_DAPM_MUX("ASI2_BCLK Route", @@ -1249,122 +1273,89 @@ static const struct snd_soc_dapm_route aic3262_dapm_routes[] = { {"ASI1_BCLK", NULL, "ASI1_BCLK Route"}, {"ASI2_BCLK", NULL, "ASI2_BCLK Route"}, {"ASI3_BCLK", NULL, "ASI3_BCLK Route"}, - - {"DIN1", NULL, "PLLCLK"}, - {"DIN1", NULL, "DACCLK"}, - {"DIN1", NULL, "ADCCLK"}, - {"DIN1", NULL, "DAC_MOD_CLK"}, - {"DIN1", NULL, "ADC_MOD_CLK"}, - - {"DOUT1", NULL, "PLLCLK"}, - {"DOUT1", NULL, "DACCLK"}, - {"DOUT1", NULL, "ADCCLK"}, - {"DOUT1", NULL, "DAC_MOD_CLK"}, - {"DOUT1", NULL, "ADC_MOD_CLK"}, #ifdef AIC3262_ASI1_MASTER {"DIN1", NULL, "ASI1_BCLK"}, {"DOUT1", NULL, "ASI1_BCLK"}, {"DIN1", NULL, "ASI1_WCLK"}, {"DOUT1", NULL, "ASI1_WCLK"}, -#else - #endif - {"DIN2", NULL, "PLLCLK"}, - {"DIN2", NULL, "DACCLK"}, - {"DIN2", NULL, "ADCCLK"}, - {"DIN2", NULL, "DAC_MOD_CLK"}, - {"DIN2", NULL, "ADC_MOD_CLK"}, - - {"DOUT2", NULL, "PLLCLK"}, - {"DOUT2", NULL, "DACCLK"}, - {"DOUT2", NULL, "ADCCLK"}, - {"DOUT2", NULL, "DAC_MOD_CLK"}, - {"DOUT2", NULL, "ADC_MOD_CLK"}, - #ifdef AIC3262_ASI2_MASTER {"DIN2", NULL, "ASI2_BCLK"}, {"DOUT2", NULL, "ASI2_BCLK"}, {"DIN2", NULL, "ASI2_WCLK"}, {"DOUT2", NULL, "ASI2_WCLK"}, -#else - #endif - {"DIN3", NULL, "PLLCLK"}, - {"DIN3", NULL, "DACCLK"}, - {"DIN3", NULL, "ADCCLK"}, - {"DIN3", NULL, "DAC_MOD_CLK"}, - {"DIN3", NULL, "ADC_MOD_CLK"}, - - {"DOUT3", NULL, "PLLCLK"}, - {"DOUT3", NULL, "DACCLK"}, - {"DOUT3", NULL, "ADCCLK"}, - {"DOUT3", NULL, "DAC_MOD_CLK"}, - {"DOUT3", NULL, "ADC_MOD_CLK"}, - #ifdef AIC3262_ASI3_MASTER {"DIN3", NULL, "ASI3_BCLK"}, {"DOUT3", NULL, "ASI3_BCLK"}, {"DIN3", NULL, "ASI3_WCLK"}, {"DOUT3", NULL, "ASI3_WCLK"}, -#else - #endif + {"Left DAC", NULL, "DAC_MOD_CLK"}, + {"Right DAC", NULL, "DAC_MOD_CLK"}, + /* When we are master, ASI bclk and wclk are generated by + * DAC_MOD_CLK, so we put them as dependency for ADC too. + */ + {"Left ADC", NULL, "DAC_MOD_CLK"}, + {"Right ADC", NULL, "DAC_MOD_CLK"}, + {"Left ADC", NULL, "ADC_MOD_CLK"}, + {"Right ADC", NULL, "ADC_MOD_CLK"}, /* Playback (DAC) Portion */ - {"HPL Output Mixer", "LDAC Switch", "Left DAC"}, - {"HPL Output Mixer", "MAL Switch", "MAL PGA"}, - {"HPL Output Mixer", "LOL-B1 Volume", "LOL"}, - - {"HPR Output Mixer", "LOR-B1 Volume", "LOR"}, - {"HPR Output Mixer", "LDAC Switch", "Left DAC"}, - {"HPR Output Mixer", "RDAC Switch", "Right DAC"}, - {"HPR Output Mixer", "MAR Switch", "MAR PGA"}, + {"HP Left Mixer", "Left DAC Playback Switch", "Left DAC"}, + {"HP Left Mixer", "MA Left Playback Switch", "MA Left Playback PGA"}, + {"HP Left Mixer", "LO Left-B1 Playback Volume", "LO Left Playback"}, - {"HPL Driver", NULL, "HPL Output Mixer"}, - {"HPR Driver", NULL, "HPR Output Mixer"}, + {"HP Right Mixer", "LO Right-B1 Playback Volume", "LO Right Playback"}, + {"HP Right Mixer", "Left DAC Playback Switch", "Left DAC"}, + {"HP Right Mixer", "Right DAC Playback Switch", "Right DAC"}, + {"HP Right Mixer", "MA Right Playback Switch", "MA Right Playback PGA"}, - {"HPL", NULL, "HPL Driver"}, - {"HPR", NULL, "HPR Driver"}, + {"HP Left Playback Driver", NULL, "HP Left Mixer"}, + {"HP Right Playback Driver", NULL, "HP Right Mixer"}, - {"LOL Output Mixer", "MAL Switch", "MAL PGA"}, - {"LOL Output Mixer", "IN1L-B Switch", "IN1L"}, - {"LOL Output Mixer", "LDAC Switch", "Left DAC"}, - {"LOL Output Mixer", "RDAC Switch", "Right DAC"}, + {"HP Left Playback", NULL, "HP Left Playback Driver"}, + {"HP Right Playback", NULL, "HP Right Playback Driver"}, - {"LOR Output Mixer", "LOL Switch", "LOL"}, - {"LOR Output Mixer", "RDAC Switch", "Right DAC"}, - {"LOR Output Mixer", "MAR Switch", "MAR PGA"}, - {"LOR Output Mixer", "IN1R-B Switch", "IN1R"}, + {"LO Left Mixer", "MA Left Playback Switch", "MA Left Playback PGA"}, + {"LO Left Mixer", "IN1 Left-B Capture Switch", "IN1 Left Capture"}, + {"LO Left Mixer", "Left DAC Playback Switch", "Left DAC"}, + {"LO Left Mixer", "Right DAC Playback Switch", "Right DAC"}, - {"LOL Driver", NULL, "LOL Output Mixer"}, - {"LOR Driver", NULL, "LOR Output Mixer"}, + {"LO Right Mixer", "LO Left Playback Switch", "LO Left Playback"}, + {"LO Right Mixer", "Right DAC Playback Switch", "Right DAC"}, + {"LO Right Mixer", "MA Right Playback Switch", "MA Right Playback PGA"}, + {"LO Right Mixer", "IN1 Right-B Capture Switch", "IN1 Right Capture"}, - {"LOL", NULL, "LOL Driver"}, - {"LOR", NULL, "LOR Driver"}, + {"LO Left Playback Driver", NULL, "LO Left Mixer"}, + {"LO Right Playback Driver", NULL, "LO Right Mixer"}, - {"REC Output Mixer", "LOL-B2 Volume", "LOL"}, - {"REC Output Mixer", "IN1L Volume", "IN1L"}, - {"REC Output Mixer", "IN1R Volume", "IN1R"}, - {"REC Output Mixer", "LOR-B2 Volume", "LOR"}, + {"LO Left Playback", NULL, "LO Left Playback Driver"}, + {"LO Right Playback", NULL, "LO Right Playback Driver"}, - {"RECP Driver", NULL, "REC Output Mixer"}, - {"RECM Driver", NULL, "REC Output Mixer"}, + {"REC Mixer", "LO Left-B2 Playback Volume", "LO Left Playback"}, + {"REC Mixer", "IN1 Left Capture Volume", "IN1 Left Capture"}, + {"REC Mixer", "IN1 Right Capture Volume", "IN1 Right Capture"}, + {"REC Mixer", "LO Right-B2 Playback Volume", "LO Right Playback"}, - {"RECP", NULL, "RECP Driver"}, - {"RECM", NULL, "RECM Driver"}, + {"RECP Playback Driver", NULL, "REC Mixer"}, + {"RECM Playback Driver", NULL, "REC Mixer"}, - {"SPKL Output Mixer", "MAL Switch", "MAL PGA"}, - {"SPKL Output Mixer", "LOL Volume", "LOL"}, - {"SPKL Output Mixer", "SPR_IN Switch", "SPKR Output Mixer"}, + {"RECP Playback", NULL, "RECP Playback Driver"}, + {"RECM Playback", NULL, "RECM Playback Driver"}, - {"SPKR Output Mixer", "LOR Volume", "LOR"}, - {"SPKR Output Mixer", "MAR Switch", "MAR PGA"}, + {"SPK Left Mixer", "MA Left Playback Switch", "MA Left Playback PGA"}, + {"SPK Left Mixer", "LO Left Playback Volume", "LO Left Playback"}, + {"SPK Left Mixer", "SPR_IN Switch", "SPK Right Mixer"}, + {"SPK Right Mixer", "LO Right Playback Volume", "LO Right Playback"}, + {"SPK Right Mixer", "MA Right Playback Switch", + "MA Right Playback PGA"}, - {"SPKL Driver", NULL, "SPKL Output Mixer"}, - {"SPKR Driver", NULL, "SPKR Output Mixer"}, + {"SPK Left Playback Driver", NULL, "SPK Left Mixer"}, + {"SPK Right Playback Driver", NULL, "SPK Right Mixer"}, - {"SPKL", NULL, "SPKL Driver"}, - {"SPKR", NULL, "SPKR Driver"}, + {"SPK Left Playback", NULL, "SPK Left Playback Driver"}, + {"SPK Right Playback", NULL, "SPK Right Playback Driver"}, /* ASI Input routing */ {"ASI1LIN", NULL, "DIN1"}, {"ASI1RIN", NULL, "DIN1"}, @@ -1428,18 +1419,15 @@ static const struct snd_soc_dapm_route aic3262_dapm_routes[] = { {"Right DAC", "NULL", "DAC MiniDSP IN3 Route"}, /* Mixer Amplifier */ + {"MA Left PGA Mixer", "IN1 Left Capture Switch", "IN1 Left Capture"}, + {"MA Left PGA Mixer", "Left MicPGA Volume", "Left MicPGA"}, - {"MAL PGA Mixer", "IN1L Switch", "IN1L"}, - {"MAL PGA Mixer", "Left MicPGA Volume", "Left MicPGA"}, - - {"MAL PGA", NULL, "MAL PGA Mixer"}, - + {"MA Left Playback PGA", NULL, "MA Left PGA Mixer"}, - {"MAR PGA Mixer", "IN1R Switch", "IN1R"}, - {"MAR PGA Mixer", "Right MicPGA Volume", "Right MicPGA"}, - - {"MAR PGA", NULL, "MAR PGA Mixer"}, + {"MA Right PGA Mixer", "IN1 Right Capture Switch", "IN1 Right Capture"}, + {"MA Right PGA Mixer", "Right MicPGA Volume", "Right MicPGA"}, + {"MA Right Playback PGA", NULL, "MA Right PGA Mixer"}, /* Virtual connection between DAC and ADC for miniDSP IPC */ {"ADC DAC Route", "On", "Left ADC"}, @@ -1450,46 +1438,44 @@ static const struct snd_soc_dapm_route aic3262_dapm_routes[] = { /* Capture (ADC) portions */ /* Left Positive PGA input */ - {"Left Input Mixer", "IN1L Switch", "IN1L"}, - {"Left Input Mixer", "IN2L Switch", "IN2L"}, - {"Left Input Mixer", "IN3L Switch", "IN3L"}, - {"Left Input Mixer", "IN4L Switch", "IN4L"}, - {"Left Input Mixer", "IN1R Switch", "IN1R"}, + {"Left Input Mixer", "IN1 Left Capture Switch", "IN1 Left Capture"}, + {"Left Input Mixer", "IN2 Left Capture Switch", "IN2 Left Capture"}, + {"Left Input Mixer", "IN3 Left Capture Switch", "IN3 Left Capture"}, + {"Left Input Mixer", "IN4 Left Capture Switch", "IN4 Left Capture"}, + {"Left Input Mixer", "IN1 Right Capture Switch", "IN1 Right Capture"}, /* Left Negative PGA input */ - {"Left Input Mixer", "IN2R Switch", "IN2R"}, - {"Left Input Mixer", "IN3R Switch", "IN3R"}, - {"Left Input Mixer", "IN4R Switch", "IN4R"}, - {"Left Input Mixer", "CM2L Switch", "CM2L"}, - {"Left Input Mixer", "CM1L Switch", "CM1L"}, - + {"Left Input Mixer", "IN2 Right Capture Switch", "IN2 Right Capture"}, + {"Left Input Mixer", "IN3 Right Capture Switch", "IN3 Right Capture"}, + {"Left Input Mixer", "IN4 Right Capture Switch", "IN4 Right Capture"}, + {"Left Input Mixer", "CM2 Left Capture Switch", "CM2 Left Capture"}, + {"Left Input Mixer", "CM1 Left Capture Switch", "CM1 Left Capture"}, /* Right Positive PGA Input */ - {"Right Input Mixer", "IN1R Switch", "IN1R"}, - {"Right Input Mixer", "IN2R Switch", "IN2R"}, - {"Right Input Mixer", "IN3R Switch", "IN3R"}, - {"Right Input Mixer", "IN4R Switch", "IN4R"}, - {"Right Input Mixer", "IN2L Switch", "IN2L"}, + {"Right Input Mixer", "IN1 Right Capture Switch", "IN1 Right Capture"}, + {"Right Input Mixer", "IN2 Right Capture Switch", "IN2 Right Capture"}, + {"Right Input Mixer", "IN3 Right Capture Switch", "IN3 Right Capture"}, + {"Right Input Mixer", "IN4 Right Capture Switch", "IN4 Right Capture"}, + {"Right Input Mixer", "IN2 Left Capture Switch", "IN2 Left Capture"}, /* Right Negative PGA Input */ - {"Right Input Mixer", "IN1L Switch", "IN1L"}, - {"Right Input Mixer", "IN3L Switch", "IN3L"}, - {"Right Input Mixer", "IN4L Switch", "IN4L"}, - {"Right Input Mixer", "CM1R Switch", "CM1R"}, - {"Right Input Mixer", "CM2R Switch", "CM2R"}, - + {"Right Input Mixer", "IN1 Left Capture Switch", "IN1 Left Capture"}, + {"Right Input Mixer", "IN3 Left Capture Switch", "IN3 Left Capture"}, + {"Right Input Mixer", "IN4 Left Capture Switch", "IN4 Left Capture"}, + {"Right Input Mixer", "CM1 Right Capture Switch", "CM1 Right Capture"}, + {"Right Input Mixer", "CM2 Right Capture Switch", "CM2 Right Capture"}, - {"CM1L", NULL, "CM"}, - {"CM2L", NULL, "CM"}, - {"CM1R", NULL, "CM"}, - {"CM2R", NULL, "CM"}, + {"CM1 Left Capture", NULL, "CM"}, + {"CM2 Left Capture", NULL, "CM"}, + {"CM1 Right Capture", NULL, "CM"}, + {"CM2 Right Capture", NULL, "CM"}, {"Left MicPGA", NULL, "Left Input Mixer"}, {"Right MicPGA", NULL, "Right Input Mixer"}, {"Left ADC Route", "Analog", "Left MicPGA"}, - {"Left ADC Route", "Digital", "Left DMIC"}, + {"Left ADC Route", "Digital", "Left DMIC Capture"}, {"Right ADC Route", "Analog", "Right MicPGA"}, - {"Right ADC Route", "Digital", "Right DMIC"}, + {"Right ADC Route", "Digital", "Right DMIC Capture"}, {"Left ADC", NULL, "Left ADC Route"}, {"Right ADC", NULL, "Right ADC Route"}, @@ -1555,7 +1541,7 @@ static const struct snd_soc_dapm_route aic3262_dapm_routes[] = { * * Returns 0 for success. */ -void aic3262_firmware_load(const struct firmware *fw, void *context) +static void aic3262_firmware_load(const struct firmware *fw, void *context) { struct snd_soc_codec *codec = context; struct aic3262_priv *private_ds = snd_soc_codec_get_drvdata(codec); @@ -1569,37 +1555,35 @@ void aic3262_firmware_load(const struct firmware *fw, void *context) if (fw != NULL) { dev_dbg(codec->dev, "Firmware binary load\n"); private_ds->cur_fw = (void *)fw; - ret = aic3xxx_cfw_reload(private_ds->cfw_p, - (void *)fw->data, fw->size); - if (ret < 0) { /* reload failed */ + ret = aic3xxx_cfw_reload(private_ds->cfw_p, (void *)fw->data, + fw->size); + if (ret < 0) { /* reload failed */ dev_err(codec->dev, "Firmware binary load failed\n"); release_firmware(private_ds->cur_fw); private_ds->cur_fw = NULL; fw = NULL; - } else - private_ds->isdefault_fw = 0; + } + } else { + /* request_firmware failed*/ + /* could not locate file tlv320aic3262_fw_v1.bin + under /vendor/firmare + */ + dev_err(codec->dev, "request_firmware failed\n"); + ret = -1; } - if (fw == NULL) { - /* either request_firmware or reload failed */ - dev_dbg(codec->dev, "Default firmware load\n"); - ret = aic3xxx_cfw_reload(private_ds->cfw_p, default_firmware, - sizeof(default_firmware)); - if (ret < 0) - dev_err(codec->dev, "Default firmware load failed\n"); - else - private_ds->isdefault_fw = 1; - } aic3xxx_cfw_lock(private_ds->cfw_p, 0); if (ret >= 0) { - /* init function for transition */ + /*init function for transition */ aic3xxx_cfw_transition(private_ds->cfw_p, "INIT"); - if (!private_ds->isdefault_fw) { - aic3xxx_cfw_add_modes(codec, private_ds->cfw_p); - aic3xxx_cfw_add_controls(codec, private_ds->cfw_p); - } + /* add firmware modes */ + aic3xxx_cfw_add_modes(codec, private_ds->cfw_p); + /* add runtime controls */ + aic3xxx_cfw_add_controls(codec, private_ds->cfw_p); + /* set the default firmware mode */ aic3xxx_cfw_setmode_cfg(private_ds->cfw_p, 0, 0); } + } /*========================================================= @@ -1608,6 +1592,12 @@ void aic3262_firmware_load(const struct firmware *fw, void *context) ========================================================*/ +enum headset_accessory_state { + BIT_NO_ACCESSORY = 0, + BIT_HEADSET = (1 << 0), + BIT_HEADPHONE = (1 << 1), +}; + /** * aic3262_hs_jack_report: Report jack notication to upper layor * @codec: pointer variable to codec having information related to codec @@ -1620,28 +1610,30 @@ static void aic3262_hs_jack_report(struct snd_soc_codec *codec, struct snd_soc_jack *jack, int report) { struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec); - int status, state = 0; + int status, state = 0, switch_state = BIT_NO_ACCESSORY; mutex_lock(&aic3262->mutex); /* Sync status */ status = snd_soc_read(codec, AIC3262_DAC_FLAG); - + /* We will check only stereo MIC and headphone */ switch (status & AIC3262_JACK_TYPE_MASK) { case AIC3262_JACK_WITH_MIC: state |= SND_JACK_HEADSET; break; case AIC3262_JACK_WITHOUT_MIC: state |= SND_JACK_HEADPHONE; - break; - default: - break; } mutex_unlock(&aic3262->mutex); snd_soc_jack_report(jack, state, report); + if ((state & SND_JACK_HEADSET) == SND_JACK_HEADSET) + switch_state |= BIT_HEADSET; + else if (state & SND_JACK_HEADPHONE) + switch_state |= BIT_HEADPHONE; + } /** @@ -1697,19 +1689,337 @@ static irqreturn_t aic3262_audio_handler(int irq, void *data) return IRQ_HANDLED; } -static irqreturn_t aic3262_button_handler(int irq, void *data) +/** + * Methods for CFW Operations + * + * Due to incompatibilites between structures used by MFD and CFW + * we need to transform the register format before linking to + * CFW operations. + */ +static inline unsigned int aic3262_ops_cfw2reg(unsigned int reg) +{ + union cfw_register *c = (union cfw_register *) ® + union aic3xxx_reg_union mreg; + + mreg.aic3xxx_register.offset = c->offset; + mreg.aic3xxx_register.page = c->page; + mreg.aic3xxx_register.book = c->book; + mreg.aic3xxx_register.reserved = 0; + + return mreg.aic3xxx_register_int; +} +static int aic3262_ops_reg_read(struct snd_soc_codec *codec, unsigned int reg) +{ + return aic3xxx_reg_read(codec->control_data, aic3262_ops_cfw2reg(reg)); +} + +static int aic3262_ops_reg_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned char val) { - struct snd_soc_codec *codec = data; - struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec); - input_report_key(aic3262->idev, KEY_MEDIA, 1); - mdelay(50); - input_report_key(aic3262->idev, KEY_MEDIA, 0); - input_sync(aic3262->idev); + return aic3xxx_reg_write(codec->control_data, + aic3262_ops_cfw2reg(reg), val); +} - return IRQ_HANDLED; +static int aic3262_ops_set_bits(struct snd_soc_codec *codec, unsigned int reg, + unsigned char mask, unsigned char val) +{ + return aic3xxx_set_bits(codec->control_data, + aic3262_ops_cfw2reg(reg), mask, val); + +} + +static int aic3262_ops_bulk_read(struct snd_soc_codec *codec, unsigned int reg, + int count, u8 *buf) +{ + return aic3xxx_bulk_read(codec->control_data, + aic3262_ops_cfw2reg(reg), count, buf); +} + +static int aic3262_ops_bulk_write(struct snd_soc_codec *codec, unsigned int reg, + int count, const u8 *buf) +{ + return aic3xxx_bulk_write(codec->control_data, + aic3262_ops_cfw2reg(reg), count, buf); } /** + * aic3262_ops_dlock_lock: To Read the run state of the DAC and ADC + * by reading the codec and returning the run state + * @pv: pointer argument to the codec + * + * Run state Bit format + * + * ------------------------------------------------------ + * D31|..........| D7 | D6| D5 | D4 | D3 | D2 | D1 | D0 | + * R R R LADC RADC R R LDAC RDAC + * ------------------------------------------------------ + * + * R- Reserved + * LDAC- Left DAC + * RDAC- Right DAC + * + * Return value : Integer + */ +static int aic3262_ops_lock(struct snd_soc_codec *codec) +{ + mutex_lock(&codec->mutex); + + /* Reading the run state of adc and dac */ + return aic3262_get_runstate(codec); + +} + +/** + * aic3262_ops_dlock_unlock: To unlock the mutex acqiured for reading + * run state of the codec + * @pv: pointer argument to the codec + * + * Return Value: integer returning 0 + */ +static int aic3262_ops_unlock(struct snd_soc_codec *codec) +{ + /*Releasing the lock of mutex */ + mutex_unlock(&codec->mutex); + return 0; +} + +/** + * aic3262_ops_dlock_stop: + * @pv: pointer Argument to the codec + * @mask: tells us the bit format of the codec running state + * + * Bit Format: + * ------------------------------------------------------ + * D31|..........| D7 | D6| D5 | D4 | D3 | D2 | D1 | D0 | + * R R R AL AR R R DL DR + * ------------------------------------------------------ + * R - Reserved + * A - minidsp_A + * D - minidsp_D + * + * Return: return run state + */ +static int aic3262_ops_stop(struct snd_soc_codec *codec, int mask) +{ + int run_state = 0; + + run_state = aic3262_get_runstate(codec); + + if (mask & AIC3XXX_COPS_MDSP_A) + aic3xxx_set_bits(codec->control_data, + AIC3262_ADC_DATAPATH_SETUP, 0xC0, 0); + + if (mask & AIC3XXX_COPS_MDSP_D) + aic3xxx_set_bits(codec->control_data, + AIC3262_DAC_DATAPATH_SETUP, 0xC0, 0); + + if ((mask & AIC3XXX_COPS_MDSP_A) && + !aic3xxx_wait_bits(codec->control_data, + AIC3262_ADC_FLAG, AIC3262_ADC_POWER_MASK, + 0, AIC326X_TIME_DELAY, + AIC326X_DELAY_COUNTER)) + goto err; + + if ((mask & AIC3XXX_COPS_MDSP_D) && + !aic3xxx_wait_bits(codec->control_data, + AIC3262_DAC_FLAG, AIC3262_DAC_POWER_MASK, + 0, AIC326X_TIME_DELAY, + AIC326X_DELAY_COUNTER)) + goto err; + + return run_state; +err: + dev_err(codec->dev, "Unable to turn off ADCs or DACs at [%s:%d]", + __FILE__, __LINE__); + return -EINVAL; +} + +/** + * aic3262_ops_dlock_restore: To unlock the mutex acqiured for reading + * @pv: pointer argument to the codec,run_state + * @run_state: run state of the codec and to restore the states of the dsp + * + * Return Value : integer returning 0 + */ + +static int aic3262_ops_restore(struct snd_soc_codec *codec, int run_state) +{ + int sync_state; + + /* This is for read the sync mode register state */ + sync_state = aic3xxx_reg_read(codec->control_data, AIC3262_DAC_PRB); + + /*checking whether the sync mode has been set or + not and checking the current state */ + if (((run_state & 0x30) && (run_state & 0x03)) && (sync_state & 0x80)) + aic3262_restart_dsps_sync(codec, run_state); + else + aic3262_dsp_pwrup(codec, run_state); + + return 0; +} + +/** + * aic3262_ops_adaptivebuffer_swap: To swap the coefficient buffers + * of minidsp according to mask + * @pv: pointer argument to the codec, + * @mask: tells us which dsp has to be chosen for swapping + * + * Return Value : returning 0 on success + */ +int aic3262_ops_adaptivebuffer_swap(struct snd_soc_codec *codec, int mask) +{ + const int sbuf[][2] = { + { AIC3XXX_ABUF_MDSP_A, AIC3262_ADC_ADAPTIVE_CRAM_REG }, + { AIC3XXX_ABUF_MDSP_D1, AIC3262_DAC_ADAPTIVE_BANK1_REG }, + { AIC3XXX_ABUF_MDSP_D2, AIC3262_DAC_ADAPTIVE_BANK2_REG }, + }; + int i; + + for (i = 0; i < sizeof(sbuf)/sizeof(sbuf[0]); ++i) { + if (!(mask & sbuf[i][0])) + continue; + aic3xxx_set_bits(codec->control_data, sbuf[i][1], 0x1, 0x1); + if (!aic3xxx_wait_bits(codec->control_data, + sbuf[i][1], 0x1, 0, 15, 1)) + goto err; + } + return 0; +err: + dev_err(codec->dev, "miniDSP buffer swap failure at [%s:%d]", + __FILE__, __LINE__); + return -EINVAL; +} + +/** + * get_runstate: To read the current state of the dac's and adc's + * @ps: pointer argument to the codec + * + * Return Value : returning the runstate + */ +static int aic3262_get_runstate(struct snd_soc_codec *codec) +{ + unsigned int dac, adc; + /* Read the run state */ + dac = aic3xxx_reg_read(codec->control_data, AIC3262_DAC_FLAG); + adc = aic3xxx_reg_read(codec->control_data, AIC3262_ADC_FLAG); + + return (((adc>>6)&1)<<5) | + (((adc>>2)&1)<<4) | + (((dac>>7)&1)<<1) | + (((dac>>3)&1)<<0); +} + +/** + * aic3262_dsp_pwrdwn_status: To read the status of dsp's + * @pv: pointer argument to the codec , cur_state of dac's and adc's + * + * Return Value : integer returning 0 + */ +static int aic3262_dsp_pwrdwn_status(struct snd_soc_codec *codec) +{ + + aic3xxx_set_bits(codec->control_data, + AIC3262_ADC_DATAPATH_SETUP, 0XC0, 0); + aic3xxx_set_bits(codec->control_data, + AIC3262_DAC_DATAPATH_SETUP, 0XC0, 0); + + if (!aic3xxx_wait_bits(codec->control_data, AIC3262_ADC_FLAG, + AIC3262_ADC_POWER_MASK, 0, AIC326X_TIME_DELAY, + AIC326X_DELAY_COUNTER)) + goto err; + if (!aic3xxx_wait_bits(codec->control_data, AIC3262_DAC_FLAG, + AIC3262_DAC_POWER_MASK, 0, AIC326X_TIME_DELAY, + AIC326X_DELAY_COUNTER)) + goto err; + + return 0; +err: + dev_err(codec->dev, "DAC/ADC Power down timedout at [%s:%d]", + __FILE__, __LINE__); + return -EINVAL; +} +static int aic3262_dsp_pwrup(struct snd_soc_codec *codec, int state) +{ + int adc_reg_mask = 0; + int adc_power_mask = 0; + int dac_reg_mask = 0; + int dac_power_mask = 0; + int ret_wbits; + + if (state & AIC3XXX_COPS_MDSP_A_L) { + adc_reg_mask |= 0x80; + adc_power_mask |= AIC3262_LADC_POWER_MASK; + } + if (state & AIC3XXX_COPS_MDSP_A_R) { + adc_reg_mask |= 0x40; + adc_power_mask |= AIC3262_RADC_POWER_MASK; + } + + if (state & AIC3XXX_COPS_MDSP_A) + aic3xxx_set_bits(codec->control_data, + AIC3262_ADC_DATAPATH_SETUP, 0XC0, + adc_reg_mask); + + if (state & AIC3XXX_COPS_MDSP_D_L) { + dac_reg_mask |= 0x80; + dac_power_mask |= AIC3262_LDAC_POWER_STATUS_MASK; + } + if (state & AIC3XXX_COPS_MDSP_D_R) { + dac_reg_mask |= 0x40; + dac_power_mask |= AIC3262_RDAC_POWER_STATUS_MASK; + } + + if (state & AIC3XXX_COPS_MDSP_D) + aic3xxx_set_bits(codec->control_data, + AIC3262_DAC_DATAPATH_SETUP, 0XC0, + dac_reg_mask); + + if (state & AIC3XXX_COPS_MDSP_A) { + ret_wbits = aic3xxx_wait_bits(codec->control_data, + AIC3262_ADC_FLAG, AIC3262_ADC_POWER_MASK, + adc_power_mask, AIC326X_TIME_DELAY, + AIC326X_DELAY_COUNTER); + if (!ret_wbits) + dev_err(codec->dev, "ADC Power down timedout\n"); + } + + if (state & AIC3XXX_COPS_MDSP_D) { + ret_wbits = aic3xxx_wait_bits(codec->control_data, + AIC3262_DAC_FLAG, AIC3262_DAC_POWER_MASK, + dac_power_mask, AIC326X_TIME_DELAY, + AIC326X_DELAY_COUNTER); + if (!ret_wbits) + dev_err(codec->dev, "ADC Power down timedout\n"); + } + + return 0; +} + +static int aic3262_restart_dsps_sync(struct snd_soc_codec *codec, int run_state) +{ + + aic3262_dsp_pwrdwn_status(codec); + aic3262_dsp_pwrup(codec, run_state); + + return 0; +} + +static const struct aic3xxx_codec_ops aic3262_cfw_codec_ops = { + .reg_read = aic3262_ops_reg_read, + .reg_write = aic3262_ops_reg_write, + .set_bits = aic3262_ops_set_bits, + .bulk_read = aic3262_ops_bulk_read, + .bulk_write = aic3262_ops_bulk_write, + .lock = aic3262_ops_lock, + .unlock = aic3262_ops_unlock, + .stop = aic3262_ops_stop, + .restore = aic3262_ops_restore, + .bswap = aic3262_ops_adaptivebuffer_swap, +}; + + +/** * aic3262_codec_read: provide read api to read aic3262 registe space * @codec: pointer variable to codec having codec information, * @reg: register address, @@ -1721,11 +2031,11 @@ unsigned int aic3262_codec_read(struct snd_soc_codec *codec, unsigned int reg) u8 value; - union aic326x_reg_union *aic_reg = (union aic326x_reg_union *) ® - value = aic3262_reg_read(codec->control_data, reg); + union aic3xxx_reg_union *aic_reg = (union aic3xxx_reg_union *) ® + value = aic3xxx_reg_read(codec->control_data, reg); dev_dbg(codec->dev, "p %d , r 30 %x %x\n", - aic_reg->aic326x_register.page, - aic_reg->aic326x_register.offset, value); + aic_reg->aic3xxx_register.page, + aic_reg->aic3xxx_register.offset, value); return value; } @@ -1740,40 +2050,11 @@ unsigned int aic3262_codec_read(struct snd_soc_codec *codec, unsigned int reg) int aic3262_codec_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { - union aic326x_reg_union *aic_reg = (union aic326x_reg_union *) ® + union aic3xxx_reg_union *aic_reg = (union aic3xxx_reg_union *) ® dev_dbg(codec->dev, "p %d, w 30 %x %x\n", - aic_reg->aic326x_register.page, - aic_reg->aic326x_register.offset, value); - return aic3262_reg_write(codec->control_data, reg, value); -} - -/** - * aic3262_add_widget: This function is to add the dapm widgets - * The following are the main widgets supported - * # Left DAC to Left Outputs - * # Right DAC to Right Outputs - * # Left Inputs to Left ADC - * # Right Inputs to Right ADC - * @codec: pointer variable to codec having informaton related to codec, - * - * Return: return 0 on success. - */ -static int aic3262_add_widgets(struct snd_soc_codec *codec) -{ - - snd_soc_dapm_new_controls(&codec->dapm, aic3262_dapm_widgets, - ARRAY_SIZE(aic3262_dapm_widgets)); - /* set up audio path interconnects */ - dev_dbg(codec->dev, "#Completed adding new dapm widget" - " controls size=%d\n", ARRAY_SIZE(aic3262_dapm_widgets)); - - snd_soc_dapm_add_routes(&codec->dapm, aic3262_dapm_routes, - ARRAY_SIZE(aic3262_dapm_routes)); - dev_dbg(codec->dev, "#Completed adding DAPM routes\n"); - snd_soc_dapm_new_widgets(&codec->dapm); - dev_dbg(codec->dev, "#Completed updating dapm\n"); - - return 0; + aic_reg->aic3xxx_register.page, + aic_reg->aic3xxx_register.offset, value); + return aic3xxx_reg_write(codec->control_data, reg, value); } /** @@ -1785,7 +2066,7 @@ static int aic3262_add_widgets(struct snd_soc_codec *codec) * Return: On success return 0. */ static int aic3262_set_interface_fmt(struct snd_soc_dai *dai, unsigned int fmt, - unsigned int channel) + unsigned int channel) { int aif_interface_reg; int aif_bclk_offset_reg; @@ -1816,19 +2097,14 @@ static int aic3262_set_interface_fmt(struct snd_soc_dai *dai, unsigned int fmt, iface_val = 0; break; case SND_SOC_DAIFMT_DSP_A: - dsp_a_val = 0x1; /* Intentionally falling back - to following case */ + dsp_a_val = 0x1; /* Intentionally falling through */ case SND_SOC_DAIFMT_DSP_B: - switch (channel) { - case 1: + if (channel == 1) iface_val = 0x80; /* Choose mono PCM */ - break; - case 2: - iface_val = 0x20; - break; - default: + else if (channel <= 8) + iface_val = 0x20; /* choose multichannel PCM */ + else return -EINVAL; - } break; case SND_SOC_DAIFMT_RIGHT_J: iface_val = 0x40; @@ -1841,9 +2117,9 @@ static int aic3262_set_interface_fmt(struct snd_soc_dai *dai, unsigned int fmt, return -EINVAL; } snd_soc_update_bits(codec, aif_interface_reg, - AIC3262_ASI_INTERFACE_MASK, iface_val); + AIC3262_ASI_INTERFACE_MASK, iface_val); snd_soc_update_bits(codec, aif_bclk_offset_reg, - AIC3262_BCLK_OFFSET_MASK, dsp_a_val); + AIC3262_BCLK_OFFSET_MASK, dsp_a_val); return 0; } @@ -1860,13 +2136,15 @@ static int aic3262_set_interface_fmt(struct snd_soc_dai *dai, unsigned int fmt, * Return: Return 0 on success. */ int aic3262_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_codec *codec = rtd->codec; struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec); - int asi_reg; - u8 data = 0; + int asi_reg, ret = 0; + u8 data = 0, value = 0, val = 0, wclk_div = 0, bclk_div = 0; + unsigned int channels = params_channels(params); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) aic3262->stream_status = 1; @@ -1902,11 +2180,52 @@ int aic3262_hw_params(struct snd_pcm_substream *substream, break; } + /* Configure TDM for multi chennels */ + switch (channels) { + case 4: + value = value | 0x40; + bclk_div = 0x03; + wclk_div = 0x40; + break; + case 6: + bclk_div = 0x02; + wclk_div = 0x60; + value = value | 0x80; + break; + case 8: + bclk_div = 0x01; + wclk_div = 0x00; + value = value | 0xC0; + break; + default: + bclk_div = 0x04; + wclk_div = 0x20; + } + + snd_soc_update_bits(codec, AIC3262_ASI1_CHNL_SETUP, + AIC3262_ASI1_CHNL_MASK, value); + + snd_soc_update_bits(codec, AIC3262_ASI1_BCLK_N, + AIC3262_ASI1_BCLK_N_MASK, bclk_div); + + snd_soc_update_bits(codec, AIC3262_ASI1_WCLK_N, + AIC3262_ASI1_WCLK_N_MASK, wclk_div); + + + val = snd_soc_read(codec, AIC3262_ASI1_BUS_FMT); + val = snd_soc_read(codec, AIC3262_ASI1_CHNL_SETUP); + /* configure the respective Registers for the above configuration */ snd_soc_update_bits(codec, asi_reg, AIC3262_ASI_DATA_WORD_LENGTH_MASK, data); - return aic3262_set_interface_fmt(dai, aic3262->asi_fmt[dai->id], - params_channels(params)); + ret = aic3262_set_interface_fmt(dai, aic3262->asi_fmt[dai->id], + channels); + if (ret < 0) { + dev_err(codec->dev, "failed to set hardware params for AIC3262\n"); + return ret; + } + + return 0; } /** @@ -1947,50 +2266,6 @@ static int aic3262_mute(struct snd_soc_dai *dai, int mute) return 0; } -/** - * aic3262_set_dai_sysclk: This function is to set the DAI system clock - * @codec_dai: ponter to dai Holds runtime data for a DAI, - * @freq: system clock to be set, - * @dir: integer dir, - * - * Return: return 0 on success. - */ -static int aic3262_set_dai_sysclk(struct snd_soc_dai *codec_dai, - int clk_id, unsigned int freq, int dir) -{ - struct aic3262_priv *aic3262; - struct snd_soc_codec *codec; - - codec = codec_dai->codec; - aic3262 = snd_soc_codec_get_drvdata(codec); - switch (freq) { - case AIC3262_FREQ_12000000: - aic3262->sysclk = freq; - return 0; - case AIC3262_FREQ_24000000: - aic3262->sysclk = freq; - return 0; - break; - case AIC3262_FREQ_19200000: - aic3262->sysclk = freq; - return 0; - break; - case AIC3262_FREQ_38400000: - aic3262->sysclk = freq; - dev_dbg(codec->dev, "codec: sysclk = %d\n", aic3262->sysclk); - return 0; - break; - case AIC3262_FREQ_12288000: - aic3262->sysclk = freq; - dev_dbg(codec->dev, "codec: sysclk = %d\n", aic3262->sysclk); - return 0; - break; - - } - dev_err(codec->dev, "Invalid frequency to set DAI system clock\n"); - - return -EINVAL; -} /** * aic3262_set_dai_fmt: This function is to set the DAI format @@ -2035,7 +2310,7 @@ static int aic3262_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) case SND_SOC_DAIFMT_CBS_CFS: aic3262->master = 0; break; - case SND_SOC_DAIFMT_CBS_CFM: /* new case..just for debugging */ + case SND_SOC_DAIFMT_CBS_CFM: /* new case..for debug purpose */ master |= (AIC3262_WCLK_OUT_MASK); aic3262->master = 0; break; @@ -2108,6 +2383,7 @@ static int aic3262_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source, /* TODO: How to select low/high clock range? */ aic3xxx_cfw_set_pll(aic3262->cfw_p, dai->id); + return 0; } @@ -2144,6 +2420,7 @@ static int aic3262_set_bias_level(struct snd_soc_codec *codec, */ dev_dbg(codec->dev, "set_bias_stby\n"); if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { + pm_runtime_get_sync(codec->dev); snd_soc_update_bits(codec, AIC3262_POWER_CONF, (AIC3262_AVDD_TO_DVDD_MASK | AIC3262_EXT_ANALOG_SUPPLY_MASK), @@ -2152,21 +2429,26 @@ static int aic3262_set_bias_level(struct snd_soc_codec *codec, AIC3262_CHIP_REF_PWR_ON_MASK, AIC3262_CHIP_REF_PWR_ON); mdelay(40); - } + snd_soc_update_bits(codec, AIC3262_CHARGE_PUMP_CNTL, + AIC3262_DYNAMIC_OFFSET_CALIB_MASK, + AIC3262_DYNAMIC_OFFSET_CALIB); + } break; /* Off, without power */ case SND_SOC_BIAS_OFF: dev_dbg(codec->dev, "set_bias_off\n"); + /* force all power off */ if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) { snd_soc_update_bits(codec, AIC3262_REF_PWR_DLY, - AIC3262_CHIP_REF_PWR_ON_MASK, 0x0); + AIC3262_CHIP_REF_PWR_ON_MASK, 0x0); snd_soc_update_bits(codec, AIC3262_POWER_CONF, - (AIC3262_AVDD_TO_DVDD_MASK | - AIC3262_EXT_ANALOG_SUPPLY_MASK), - (AIC3262_AVDD_TO_DVDD | - AIC3262_EXT_ANALOG_SUPPLY_OFF)); + (AIC3262_AVDD_TO_DVDD_MASK | + AIC3262_EXT_ANALOG_SUPPLY_MASK), + (AIC3262_AVDD_TO_DVDD | + AIC3262_EXT_ANALOG_SUPPLY_OFF)); + pm_runtime_put(codec->dev); } break; } @@ -2175,25 +2457,25 @@ static int aic3262_set_bias_level(struct snd_soc_codec *codec, return 0; } -/* - *---------------------------------------------------------------------------- - * Function : aic3262_suspend - * Purpose : This function is to suspend the AIC3262 driver. +/** * - *---------------------------------------------------------------------------- + * aic3262_suspend; This function is to suspend the AIC3262 driver. + * @codec: pointer variable to codec having informaton related to codec, + * + * Return: Return 0 on success. */ -static int aic3262_suspend(struct snd_soc_codec *codec, pm_message_t state) +static int aic3262_suspend(struct snd_soc_codec *codec) { aic3262_set_bias_level(codec, SND_SOC_BIAS_OFF); return 0; } -/* - *---------------------------------------------------------------------------- - * Function : aic3262_resume - * Purpose : This function is to resume the AIC3262 driver +/** + * aic3262_resume: This function is to resume the AIC3262 driver + * from off state to standby + * @codec: pointer variable to codec having informaton related to codec, * - *---------------------------------------------------------------------------- + * Return: Return 0 on success. */ static int aic3262_resume(struct snd_soc_codec *codec) { @@ -2202,20 +2484,17 @@ static int aic3262_resume(struct snd_soc_codec *codec) return 0; } -/* - *---------------------------------------------------------------------------- - * Function : aic3262_probe - * Purpose : This is first driver function called by the SoC core driver. +/** + * aic3262_probe: This is first driver function called by the SoC core driver. + * @codec: pointer variable to codec having informaton related to codec, * - *---------------------------------------------------------------------------- + * Return: Return 0 on success. */ static int aic3262_codec_probe(struct snd_soc_codec *codec) { int ret = 0; - int ret_btn = 0; - struct aic3262 *control; + struct aic3xxx *control; struct aic3262_priv *aic3262; - struct aic3262_jack_data *jack; if (codec == NULL) dev_err(codec->dev, "codec pointer is NULL.\n"); @@ -2230,56 +2509,37 @@ static int aic3262_codec_probe(struct snd_soc_codec *codec) aic3262->pdata = dev_get_platdata(codec->dev->parent); aic3262->codec = codec; aic3262->cur_fw = NULL; - aic3262->isdefault_fw = 0; aic3262->cfw_p = &(aic3262->cfw_ps); - aic3xxx_cfw_init(aic3262->cfw_p, &aic3262_cfw_codec_ops, aic3262); + aic3xxx_cfw_init(aic3262->cfw_p, &aic3262_cfw_codec_ops, + aic3262->codec); aic3262->workqueue = create_singlethread_workqueue("aic3262-codec"); if (!aic3262->workqueue) { ret = -ENOMEM; goto work_err; } - ret = device_create_file(codec->dev, &dev_attr_debug_level); - if (ret) - dev_info(codec->dev, "Failed to add debug_level sysfs\n"); INIT_DELAYED_WORK(&aic3262->delayed_work, aic3262_accessory_work); mutex_init(&aic3262->mutex); mutex_init(&codec->mutex); mutex_init(&aic3262->cfw_mutex); - aic3262->dsp_runstate = 0; - /* use switch-class based headset reporting if platform requires it */ - jack = &aic3262->hs_jack; - aic3262->idev = input_allocate_device(); - if (aic3262->idev <= 0) - printk(KERN_ERR, "Allocate failed\n"); - - input_set_capability(aic3262->idev, EV_KEY, KEY_MEDIA); - ret = input_register_device(aic3262->idev); - if (ret < 0) { - dev_err(codec->dev, "register input dev fail\n"); - goto input_dev_err; - } + pm_runtime_enable(codec->dev); + pm_runtime_resume(codec->dev); + aic3262->dsp_runstate = 0; if (control->irq) { - ret = aic3262_request_irq(codec->control_data, - AIC3262_IRQ_HEADSET_DETECT, - aic3262_audio_handler, 0, - "aic3262_irq_headset", codec); + ret = aic3xxx_request_irq(codec->control_data, + AIC3262_IRQ_HEADSET_DETECT, + aic3262_audio_handler, + IRQF_NO_SUSPEND, + "aic3262_irq_headset", codec); - if (ret) { + if (ret) { dev_err(codec->dev, "HEADSET detect irq request" "failed: %d\n", ret); goto irq_err; - } - - ret = aic3262_request_irq(codec->control_data, - AIC3262_IRQ_BUTTON_PRESS, - aic3262_button_handler, 0, "aic3262_irq_button", - codec); - - if (ret) { - dev_err(codec->dev, "button press irq request" - "failed: %d\n", ret); - goto irq_err; + } else { + /* Dynamic Headset Detection Enabled */ + snd_soc_update_bits(codec, AIC3262_HP_DETECT, + AIC3262_HEADSET_IN_MASK, AIC3262_HEADSET_IN_MASK); } } /* Keep the reference voltage ON while in$ @@ -2289,74 +2549,63 @@ static int aic3262_codec_probe(struct snd_soc_codec *codec) AIC3262_CHIP_REF_PWR_ON_MASK, AIC3262_CHIP_REF_PWR_ON); mdelay(40); - aic3262_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - ret = snd_soc_add_codec_controls(codec, aic3262_snd_controls, - ARRAY_SIZE(aic3262_snd_controls)); - if(ret) - { - printk(KERN_INFO "%s failed\n", __func__); - } + snd_soc_update_bits(codec, AIC3262_CHARGE_PUMP_CNTL, + AIC3262_DYNAMIC_OFFSET_CALIB_MASK, + AIC3262_DYNAMIC_OFFSET_CALIB); - aic3262->mute_asi = 0; + aic3262_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - aic3262_add_widgets(codec); + aic3262->mute_asi = 0; -#ifdef AIC3262_TiLoad - ret = aic3262_driver_init(codec); - if (ret < 0) - dev_err(codec->dev, "\nTiLoad Initialization failed\n"); -#endif - /* force loading the default firmware */ - aic3262_firmware_load(NULL, codec); - request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, + ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, "tlv320aic3262_fw_v1.bin", codec->dev, GFP_KERNEL, codec, aic3262_firmware_load); + if (ret < 0) { + dev_err(codec->dev, "Firmware request failed\n"); + goto firm_err; + } return 0; +firm_err: + aic3xxx_free_irq(control, + AIC3262_IRQ_HEADSET_DETECT, codec); irq_err: - input_unregister_device(aic3262->idev); - input_free_device(aic3262->idev); -input_dev_err: -reg_err: + destroy_workqueue(aic3262->workqueue); work_err: kfree(aic3262); return 0; } /* -* aic3262_remove: Cleans up and Remove aic3262 soc device -* @codec: pointer variable to codec having informaton related to codec, -* -* Return: Return 0 on success. -*/ + * aic3262_remove: Cleans up and Remove aic3262 soc device + * @codec: pointer variable to codec having informaton related to codec, + * + * Return: Return 0 on success. + */ static int aic3262_codec_remove(struct snd_soc_codec *codec) { /* power down chip */ struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec); - struct aic3262 *control = codec->control_data; - struct aic3262_jack_data *jack = &aic3262->hs_jack; + struct aic3xxx *control = codec->control_data; aic3262_set_bias_level(codec, SND_SOC_BIAS_OFF); /* free_irq if any */ switch (control->type) { case TLV320AIC3262: - if (control->irq) { - aic3262_free_irq(control, AIC3262_IRQ_HEADSET_DETECT, - codec); - aic3262_free_irq(control, AIC3262_IRQ_BUTTON_PRESS, - codec); - } + if (control->irq) + aic3xxx_free_irq(control, + AIC3262_IRQ_HEADSET_DETECT, codec); break; + default: + dev_info(codec->dev, "Coded is not TLV320AIC3262\n"); } /* release firmware if any */ if (aic3262->cur_fw != NULL) release_firmware(aic3262->cur_fw); /* destroy workqueue for jac dev */ destroy_workqueue(aic3262->workqueue); - input_unregister_device(aic3262->idev); - input_free_device(aic3262->idev); kfree(aic3262); @@ -2370,6 +2619,12 @@ static struct snd_soc_codec_driver soc_codec_driver_aic326x = { .resume = aic3262_resume, .read = aic3262_codec_read, .write = aic3262_codec_write, + .controls = aic3262_snd_controls, + .num_controls = ARRAY_SIZE(aic3262_snd_controls), + .dapm_widgets = aic3262_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(aic3262_dapm_widgets), + .dapm_routes = aic3262_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(aic3262_dapm_routes), .set_bias_level = aic3262_set_bias_level, .reg_cache_size = 0, .reg_word_size = sizeof(u8), @@ -2390,42 +2645,31 @@ static int aic326x_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id aic3262_of_match[] = { + { .compatible = "ti,aic3262", }, + { }, +}; +MODULE_DEVICE_TABLE(of, aic3262_of_match); + +static const struct platform_device_id aic3262_i2c_id[] = { + { "tlv320aic3262-codec", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, aic3262_i2c_id); + static struct platform_driver aic326x_codec_driver = { .driver = { - .name = "tlv320aic3262-codec", - .owner = THIS_MODULE, - }, + .name = "tlv320aic3262-codec", + .owner = THIS_MODULE, + .of_match_table = aic3262_of_match, + }, .probe = aic326x_probe, .remove = aic326x_remove, + .id_table = aic3262_i2c_id, }; -/* -*---------------------------------------------------------------------------- -* Function : tlv320aic3262_modinit -* Purpose : module init function. First function to run. -* -*---------------------------------------------------------------------------- -*/ -static int __init tlv320aic3262_modinit(void) -{ - return platform_driver_register(&aic326x_codec_driver); -} -module_init(tlv320aic3262_modinit); - -/* -*---------------------------------------------------------------------------- -* Function : tlv320aic3262_exit -* Purpose : module init function. First function to run. -* -*---------------------------------------------------------------------------- -*/ -static void __exit tlv320aic3262_exit(void) -{ - platform_driver_unregister(&aic326x_codec_driver); - -} +module_platform_driver(aic326x_codec_driver); -module_exit(tlv320aic3262_exit); MODULE_ALIAS("platform:tlv320aic3262-codec"); MODULE_DESCRIPTION("ASoC TLV320AIC3262 codec driver"); MODULE_AUTHOR("Y Preetam Sashank Reddy "); |