From: mnzaki Date: Thu, 2 Sep 2010 11:06:17 +0000 (+0300) Subject: Initial import of patch. X-Git-Url: http://git.maemo.org/git/?p=aic34-eq;a=commitdiff_plain;h=194579cf196aa190d1f80f7f037012073c573a80;hp=ba297db7a47592b962b1af3872bcd30617241966 Initial import of patch. What we have right now: - All page 1 registers added as a u16 array of coefficients with routines to read/write the coefficients (aic3x_read_coeff_cache and aic3x_write_coeff respectively) - Added syncing coeff_cache with hardware after a suspend/resume cycle - Added ALSA controls for the 3-D depth simulation filter What's missing: A lot --- diff --git a/tlv320aic3x.c b/tlv320aic3x.c index 4f70822..b39b3ae 100644 --- a/tlv320aic3x.c +++ b/tlv320aic3x.c @@ -59,6 +59,7 @@ struct aic3x_priv { unsigned int sysclk; int master; int prepare_reset; + u16 coeff_cache[AIC3X_COEFF_CACHE_SIZE]; }; /* @@ -96,6 +97,28 @@ static const u8 aic3x_reg[AIC3X_CACHEREGNUM] = { 0x00, 0x00, 0x02, /* 100 */ }; +/* Page 1 registers store 2s compliment 16-bit numbers used for + * coefficients for effects. Each number is in 2 register, MSB followed + * by LSB. Therefore this array contains AIC3X_CACHEREGNUM/2 + 1 items. + */ +static const u16 aic3x_coeff[AIC3X_COEFF_CACHE_SIZE] = +{ + 0x00, /* Reg 0 */ + 0x6be3, 0x9666, 0x675d, 0x6be3, /* Reg 1 - 8 */ + 0x9666, 0x675d, 0x7d83, 0x84ee, /* 9 - 16 */ + 0x7d83, 0x84ee, 0x3955, 0xf32d, /* 17 - 24 */ + 0x537e, 0x6be3, 0x9666, 0x675d, /* 25 - 32 */ + 0x6be3, 0x9666, 0x675d, 0x7d83, /* 33 - 40 */ + 0x84ee, 0x7d83, 0x84ee, 0x3955, /* 41 - 48 */ + 0xf32d, 0x537e, 0x7fff, 0x0000, /* 49 - 56 */ + 0x0000, 0x0000, 0x0000, 0x0000, /* 57 - 64 */ + 0x3955, 0xf32d, 0x537e, 0x3955, /* 65 - 72 */ + 0xf32d, 0x537e, 0x0000, 0x0000, /* 73 - 80 */ + 0x0000, 0x0000, 0x0000, 0x0000, /* 81 - 88 */ + 0x0000, 0x0000, 0x0000, 0x0000, /* 89 - 96 */ + 0x0000, 0x0000, 0x0000, /* 97 - 102 */ +}; + /* * read aic3x register cache */ @@ -108,6 +131,12 @@ static inline unsigned int aic3x_read_reg_cache(struct snd_soc_codec *codec, return cache[reg]; } +static inline unsigned int aic3x_read_coeff_cache(struct snd_soc_codec *codec, + unsigned int reg) { + u16 *cache = ((struct aic3x_priv*)codec->private_data)->coeff_cache; + return cache[COEFF_OFFSET(reg)]; +} + /* * write aic3x register cache */ @@ -135,13 +164,47 @@ static int aic3x_write(struct snd_soc_codec *codec, unsigned int reg, data[0] = reg & 0xff; data[1] = value & 0xff; - aic3x_write_reg_cache(codec, data[0], data[1]); - if (codec->hw_write(codec->control_data, data, 2) == 2) + if (codec->hw_write(codec->control_data, data, 2) == 2){ + aic3x_write_reg_cache(codec, data[0], data[1]); return 0; - else + } else return -EIO; } +/* Write a coefficient to the page 1 registers. Switching the page is + * not done here and is left to the caller. + */ +static int aic3x_write_coeff(struct snd_soc_codec *codec, unsigned int msbreg, + int value) +{ + u8 i, values[2], data[2]; + u16 outp; + u16 *cache = ((struct aic3x_priv*)codec->private_data)->coeff_cache; + + if (msbreg >= AIC3X_CACHEREGNUM) + return -1; + + /* Change to 2s compliment and break into MSB and LSB */ + if (value < 0) + outp = 65536 + value; + else + outp = value; + + values[0] = (outp >> 8) & 0xff; + values[1] = outp & 0xff; + + for(i = 0; i < 2; i++){ + data[0] = (msbreg + i) & 0xff; + data[1] = values[i] & 0xff; + + if (codec->hw_write(codec->control_data, data, 2) != 2) + return -EIO; + } + + cache[COEFF_OFFSET(msbreg)] = outp; + return 0; +} + /* * read from the aic3x register space */ @@ -331,6 +394,39 @@ static int tlv320alc3x_info_volsw(struct snd_kcontrol *kcontrol, return 0; } + +static int snd_soc_get_3d_attenuation_aic3x(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int val = aic3x_read_coeff_cache(snd_kcontrol_chip(kcontrol), EFFECTS_3DATTEN); + if(val > 32767) + val = val - 65536; + val = ((val*100)/65530) + 50; + ucontrol->value.integer.value[0] = val; + return 0; +} + +static int snd_soc_put_3d_attenuation_aic3x(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + int reg = aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLA); + int val = ucontrol->value.integer.value[0]; + + if(val){ + aic3x_write(codec, AIC3X_ASD_INTF_CTRLA, reg | 0x04); + } else { + aic3x_write(codec, AIC3X_ASD_INTF_CTRLA, reg & 0xfb); + } + + val = ((val - 50) * 65535) / 100 ; + aic3x_write(codec, AIC3X_PAGE_SELECT, PAGE1_SELECT); + aic3x_write_coeff(codec, EFFECTS_3DATTEN, val); + aic3x_write(codec, AIC3X_PAGE_SELECT, PAGE0_SELECT); + + return 1; +} + static const struct snd_kcontrol_new aic3x_snd_controls[] = { /* Output */ SOC_DOUBLE_R_TLV("PCM Playback Volume", @@ -399,6 +495,9 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = { SOC_DOUBLE_R("PGA Capture Switch", LADC_VOL, RADC_VOL, 7, 0x01, 1), SOC_ENUM("ADC HPF Cut-off", aic3x_enum[ADC_HPF_ENUM]), + + SOC_SINGLE_EXT("3D Control - Depth", EFFECTS_3DATTEN, 0, 100, 0, + snd_soc_get_3d_attenuation_aic3x, snd_soc_put_3d_attenuation_aic3x), }; /* add non dapm controls */ @@ -1215,12 +1314,28 @@ static int aic3x_resume(struct platform_device *pdev) struct snd_soc_codec *codec = socdev->codec; int i; u8 data[2]; - u8 *cache = codec->reg_cache; + u8 *reg_cache = codec->reg_cache; + u16 *coeff_cache = ((struct aic3x_priv*)codec->private_data)->coeff_cache; + + /* Sync hardware with the coeff_cache first so that filters can be + * turned on safely + */ + aic3x_write(codec, AIC3X_PAGE_SELECT, PAGE1_SELECT); + for (i = 1; i < ARRAY_SIZE(aic3x_coeff); i++){ + data[0] = i*2 - 1; + data[1] = (coeff_cache[i] >> 8) && 0xff; + codec->hw_write(codec->control_data, data, 2); + + data[0]++; + data[1] = coeff_cache[i] & 0xff; + codec->hw_write(codec->control_data, data, 2); + } - /* Sync reg_cache with the hardware */ - for (i = 0; i < ARRAY_SIZE(aic3x_reg); i++) { + /* Sync hardware with the reg_cache */ + aic3x_write(codec, AIC3X_PAGE_SELECT, PAGE0_SELECT); + for (i = 1; i < ARRAY_SIZE(aic3x_reg); i++) { data[0] = i; - data[1] = cache[i]; + data[1] = reg_cache[i]; codec->hw_write(codec->control_data, data, 2); } @@ -1339,6 +1454,11 @@ static int aic3x_init(struct snd_soc_device *socdev) goto card_err; } + /* Set some defaults for coefficients */ + aic3x_write(codec, AIC3X_PAGE_SELECT, PAGE1_SELECT); + aic3x_write_coeff(codec, EFFECTS_3DATTEN, -32768); + aic3x_write(codec, AIC3X_PAGE_SELECT, PAGE0_SELECT); + return ret; card_err: @@ -1464,6 +1584,8 @@ static int aic3x_probe(struct platform_device *pdev) return -ENOMEM; aic3x = kzalloc(sizeof(struct aic3x_priv), GFP_KERNEL); + memcpy(aic3x->coeff_cache, aic3x_coeff, sizeof(aic3x_coeff)); + if (aic3x == NULL) { kfree(codec); return -ENOMEM; diff --git a/tlv320aic3x.h b/tlv320aic3x.h index 15a98aa..c71cafc 100644 --- a/tlv320aic3x.h +++ b/tlv320aic3x.h @@ -14,6 +14,8 @@ /* AIC3X register space */ #define AIC3X_CACHEREGNUM 103 +#define AIC3X_COEFF_CACHE_SIZE 52 +#define COEFF_OFFSET(msbreg) ((msbreg+1)/2) /* Page select register */ #define AIC3X_PAGE_SELECT 0 @@ -123,6 +125,62 @@ /* Clock generation control register */ #define AIC3X_CLKGEN_CTRL_REG 102 +/* Page 1 registers for setting coefficients for filters */ +/* DAC Audio Effects for Left Channel */ +#define EFFECTS_LEFT_N0 1 +#define EFFECTS_LEFT_N1 3 +#define EFFECTS_LEFT_N2 5 +#define EFFECTS_LEFT_N3 7 +#define EFFECTS_LEFT_N4 9 +#define EFFECTS_LEFT_N5 11 + +#define EFFECTS_LEFT_D1 13 +#define EFFECTS_LEFT_D2 15 +#define EFFECTS_LEFT_D4 17 +#define EFFECTS_LEFT_D5 19 + +/* DAC De-Emphasis for Left Channel */ + +#define DEEMPH_LEFT_N0 21 +#define DEEMPH_LEFT_N1 23 +#define DEEMPH_LEFT_D1 25 + +/* DAC Audio Effects for Right Channel */ + +#define EFFECTS_RIGHT_N0 27 +#define EFFECTS_RIGHT_N1 29 +#define EFFECTS_RIGHT_N2 31 +#define EFFECTS_RIGHT_N3 33 +#define EFFECTS_RIGHT_N4 35 +#define EFFECTS_RIGHT_N5 37 + +#define EFFECTS_RIGHT_D1 39 +#define EFFECTS_RIGHT_D2 41 +#define EFFECTS_RIGHT_D4 43 +#define EFFECTS_RIGHT_D5 45 + +/* DAC De-Emphasis for Right Channel */ + +#define DEEMPH_RIGHT_N0 47 +#define DEEMPH_RIGHT_N1 49 +#define DEEMPH_RIGHT_D1 51 + +/* DAC 3D Attenuation */ + +#define EFFECTS_3DATTEN 53 + +/* ADC High-Pass Filter for Left Channel */ + +#define HIGHPASS_LEFT_NO 65 +#define HIGHPASS_LEFT_N1 67 +#define HIGHPASS_LEFT_D1 69 + +/* ADC High-Pass Filter for Right Channel */ + +#define HIGHPASS_RIGHT_NO 71 +#define HIGHPASS_RIGHT_N1 73 +#define HIGHPASS_RIGHT_D1 75 + /* Page select register bits */ #define PAGE0_SELECT 0 #define PAGE1_SELECT 1