diff options
author | Pavel Hofman <pavel.hofman@ivitera.com> | 2009-09-16 16:25:36 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2009-09-21 09:44:51 -0400 |
commit | 8f34692f63d66805b51ff408f4067748d3c1c3fd (patch) | |
tree | dc2bd50fb2743b862c97bac848200bb8e26f0f53 /sound/i2c | |
parent | c0a9eedf9acafb083adf3ddbff0a1e4d6d9a6949 (diff) |
ALSA: ak4620 support, codec regs listed in proc
* complete support for ak4620
* codec regs listed in proc for all codecs/chips
* adding total regs for each codec
* fixing nb. of steps in input attenuation controls
Signed-off-by: Pavel Hofman <pavel.hofman@ivitera.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/i2c')
-rw-r--r-- | sound/i2c/other/ak4xxx-adda.c | 136 |
1 files changed, 104 insertions, 32 deletions
diff --git a/sound/i2c/other/ak4xxx-adda.c b/sound/i2c/other/ak4xxx-adda.c index ee47abab764e..1adb8a3c2b62 100644 --- a/sound/i2c/other/ak4xxx-adda.c +++ b/sound/i2c/other/ak4xxx-adda.c | |||
@@ -19,7 +19,7 @@ | |||
19 | * along with this program; if not, write to the Free Software | 19 | * along with this program; if not, write to the Free Software |
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 | * | 21 | * |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <asm/io.h> | 24 | #include <asm/io.h> |
25 | #include <linux/delay.h> | 25 | #include <linux/delay.h> |
@@ -29,6 +29,7 @@ | |||
29 | #include <sound/control.h> | 29 | #include <sound/control.h> |
30 | #include <sound/tlv.h> | 30 | #include <sound/tlv.h> |
31 | #include <sound/ak4xxx-adda.h> | 31 | #include <sound/ak4xxx-adda.h> |
32 | #include <sound/info.h> | ||
32 | 33 | ||
33 | MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, Takashi Iwai <tiwai@suse.de>"); | 34 | MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, Takashi Iwai <tiwai@suse.de>"); |
34 | MODULE_DESCRIPTION("Routines for control of AK452x / AK43xx AD/DA converters"); | 35 | MODULE_DESCRIPTION("Routines for control of AK452x / AK43xx AD/DA converters"); |
@@ -52,26 +53,21 @@ EXPORT_SYMBOL(snd_akm4xxx_write); | |||
52 | static void ak4524_reset(struct snd_akm4xxx *ak, int state) | 53 | static void ak4524_reset(struct snd_akm4xxx *ak, int state) |
53 | { | 54 | { |
54 | unsigned int chip; | 55 | unsigned int chip; |
55 | unsigned char reg, maxreg; | 56 | unsigned char reg; |
56 | 57 | ||
57 | if (ak->type == SND_AK4528) | ||
58 | maxreg = 0x06; | ||
59 | else | ||
60 | maxreg = 0x08; | ||
61 | for (chip = 0; chip < ak->num_dacs/2; chip++) { | 58 | for (chip = 0; chip < ak->num_dacs/2; chip++) { |
62 | snd_akm4xxx_write(ak, chip, 0x01, state ? 0x00 : 0x03); | 59 | snd_akm4xxx_write(ak, chip, 0x01, state ? 0x00 : 0x03); |
63 | if (state) | 60 | if (state) |
64 | continue; | 61 | continue; |
65 | /* DAC volumes */ | 62 | /* DAC volumes */ |
66 | for (reg = 0x04; reg < maxreg; reg++) | 63 | for (reg = 0x04; reg < ak->total_regs; reg++) |
67 | snd_akm4xxx_write(ak, chip, reg, | 64 | snd_akm4xxx_write(ak, chip, reg, |
68 | snd_akm4xxx_get(ak, chip, reg)); | 65 | snd_akm4xxx_get(ak, chip, reg)); |
69 | } | 66 | } |
70 | } | 67 | } |
71 | 68 | ||
72 | /* reset procedure for AK4355 and AK4358 */ | 69 | /* reset procedure for AK4355 and AK4358 */ |
73 | static void ak435X_reset(struct snd_akm4xxx *ak, int state, | 70 | static void ak435X_reset(struct snd_akm4xxx *ak, int state) |
74 | unsigned char total_regs) | ||
75 | { | 71 | { |
76 | unsigned char reg; | 72 | unsigned char reg; |
77 | 73 | ||
@@ -79,7 +75,7 @@ static void ak435X_reset(struct snd_akm4xxx *ak, int state, | |||
79 | snd_akm4xxx_write(ak, 0, 0x01, 0x02); /* reset and soft-mute */ | 75 | snd_akm4xxx_write(ak, 0, 0x01, 0x02); /* reset and soft-mute */ |
80 | return; | 76 | return; |
81 | } | 77 | } |
82 | for (reg = 0x00; reg < total_regs; reg++) | 78 | for (reg = 0x00; reg < ak->total_regs; reg++) |
83 | if (reg != 0x01) | 79 | if (reg != 0x01) |
84 | snd_akm4xxx_write(ak, 0, reg, | 80 | snd_akm4xxx_write(ak, 0, reg, |
85 | snd_akm4xxx_get(ak, 0, reg)); | 81 | snd_akm4xxx_get(ak, 0, reg)); |
@@ -91,12 +87,11 @@ static void ak4381_reset(struct snd_akm4xxx *ak, int state) | |||
91 | { | 87 | { |
92 | unsigned int chip; | 88 | unsigned int chip; |
93 | unsigned char reg; | 89 | unsigned char reg; |
94 | |||
95 | for (chip = 0; chip < ak->num_dacs/2; chip++) { | 90 | for (chip = 0; chip < ak->num_dacs/2; chip++) { |
96 | snd_akm4xxx_write(ak, chip, 0x00, state ? 0x0c : 0x0f); | 91 | snd_akm4xxx_write(ak, chip, 0x00, state ? 0x0c : 0x0f); |
97 | if (state) | 92 | if (state) |
98 | continue; | 93 | continue; |
99 | for (reg = 0x01; reg < 0x05; reg++) | 94 | for (reg = 0x01; reg < ak->total_regs; reg++) |
100 | snd_akm4xxx_write(ak, chip, reg, | 95 | snd_akm4xxx_write(ak, chip, reg, |
101 | snd_akm4xxx_get(ak, chip, reg)); | 96 | snd_akm4xxx_get(ak, chip, reg)); |
102 | } | 97 | } |
@@ -113,16 +108,17 @@ void snd_akm4xxx_reset(struct snd_akm4xxx *ak, int state) | |||
113 | switch (ak->type) { | 108 | switch (ak->type) { |
114 | case SND_AK4524: | 109 | case SND_AK4524: |
115 | case SND_AK4528: | 110 | case SND_AK4528: |
111 | case SND_AK4620: | ||
116 | ak4524_reset(ak, state); | 112 | ak4524_reset(ak, state); |
117 | break; | 113 | break; |
118 | case SND_AK4529: | 114 | case SND_AK4529: |
119 | /* FIXME: needed for ak4529? */ | 115 | /* FIXME: needed for ak4529? */ |
120 | break; | 116 | break; |
121 | case SND_AK4355: | 117 | case SND_AK4355: |
122 | ak435X_reset(ak, state, 0x0b); | 118 | ak435X_reset(ak, state); |
123 | break; | 119 | break; |
124 | case SND_AK4358: | 120 | case SND_AK4358: |
125 | ak435X_reset(ak, state, 0x10); | 121 | ak435X_reset(ak, state); |
126 | break; | 122 | break; |
127 | case SND_AK4381: | 123 | case SND_AK4381: |
128 | ak4381_reset(ak, state); | 124 | ak4381_reset(ak, state); |
@@ -139,7 +135,7 @@ EXPORT_SYMBOL(snd_akm4xxx_reset); | |||
139 | * Volume conversion table for non-linear volumes | 135 | * Volume conversion table for non-linear volumes |
140 | * from -63.5dB (mute) to 0dB step 0.5dB | 136 | * from -63.5dB (mute) to 0dB step 0.5dB |
141 | * | 137 | * |
142 | * Used for AK4524 input/ouput attenuation, AK4528, and | 138 | * Used for AK4524/AK4620 input/ouput attenuation, AK4528, and |
143 | * AK5365 input attenuation | 139 | * AK5365 input attenuation |
144 | */ | 140 | */ |
145 | static const unsigned char vol_cvt_datt[128] = { | 141 | static const unsigned char vol_cvt_datt[128] = { |
@@ -259,8 +255,22 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak) | |||
259 | 0x00, 0x0f, /* 0: power-up, un-reset */ | 255 | 0x00, 0x0f, /* 0: power-up, un-reset */ |
260 | 0xff, 0xff | 256 | 0xff, 0xff |
261 | }; | 257 | }; |
258 | static const unsigned char inits_ak4620[] = { | ||
259 | 0x00, 0x07, /* 0: normal */ | ||
260 | 0x01, 0x00, /* 0: reset */ | ||
261 | 0x01, 0x02, /* 1: RSTAD */ | ||
262 | 0x01, 0x03, /* 1: RSTDA */ | ||
263 | 0x01, 0x0f, /* 1: normal */ | ||
264 | 0x02, 0x60, /* 2: 24bit I2S */ | ||
265 | 0x03, 0x01, /* 3: deemphasis off */ | ||
266 | 0x04, 0x00, /* 4: LIN muted */ | ||
267 | 0x05, 0x00, /* 5: RIN muted */ | ||
268 | 0x06, 0x00, /* 6: LOUT muted */ | ||
269 | 0x07, 0x00, /* 7: ROUT muted */ | ||
270 | 0xff, 0xff | ||
271 | }; | ||
262 | 272 | ||
263 | int chip, num_chips; | 273 | int chip; |
264 | const unsigned char *ptr, *inits; | 274 | const unsigned char *ptr, *inits; |
265 | unsigned char reg, data; | 275 | unsigned char reg, data; |
266 | 276 | ||
@@ -270,42 +280,64 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak) | |||
270 | switch (ak->type) { | 280 | switch (ak->type) { |
271 | case SND_AK4524: | 281 | case SND_AK4524: |
272 | inits = inits_ak4524; | 282 | inits = inits_ak4524; |
273 | num_chips = ak->num_dacs / 2; | 283 | ak->num_chips = ak->num_dacs / 2; |
284 | ak->name = "ak4524"; | ||
285 | ak->total_regs = 0x08; | ||
274 | break; | 286 | break; |
275 | case SND_AK4528: | 287 | case SND_AK4528: |
276 | inits = inits_ak4528; | 288 | inits = inits_ak4528; |
277 | num_chips = ak->num_dacs / 2; | 289 | ak->num_chips = ak->num_dacs / 2; |
290 | ak->name = "ak4528"; | ||
291 | ak->total_regs = 0x06; | ||
278 | break; | 292 | break; |
279 | case SND_AK4529: | 293 | case SND_AK4529: |
280 | inits = inits_ak4529; | 294 | inits = inits_ak4529; |
281 | num_chips = 1; | 295 | ak->num_chips = 1; |
296 | ak->name = "ak4529"; | ||
297 | ak->total_regs = 0x0d; | ||
282 | break; | 298 | break; |
283 | case SND_AK4355: | 299 | case SND_AK4355: |
284 | inits = inits_ak4355; | 300 | inits = inits_ak4355; |
285 | num_chips = 1; | 301 | ak->num_chips = 1; |
302 | ak->name = "ak4355"; | ||
303 | ak->total_regs = 0x0b; | ||
286 | break; | 304 | break; |
287 | case SND_AK4358: | 305 | case SND_AK4358: |
288 | inits = inits_ak4358; | 306 | inits = inits_ak4358; |
289 | num_chips = 1; | 307 | ak->num_chips = 1; |
308 | ak->name = "ak4358"; | ||
309 | ak->total_regs = 0x10; | ||
290 | break; | 310 | break; |
291 | case SND_AK4381: | 311 | case SND_AK4381: |
292 | inits = inits_ak4381; | 312 | inits = inits_ak4381; |
293 | num_chips = ak->num_dacs / 2; | 313 | ak->num_chips = ak->num_dacs / 2; |
314 | ak->name = "ak4381"; | ||
315 | ak->total_regs = 0x05; | ||
294 | break; | 316 | break; |
295 | case SND_AK5365: | 317 | case SND_AK5365: |
296 | /* FIXME: any init sequence? */ | 318 | /* FIXME: any init sequence? */ |
319 | ak->num_chips = 1; | ||
320 | ak->name = "ak5365"; | ||
321 | ak->total_regs = 0x08; | ||
297 | return; | 322 | return; |
323 | case SND_AK4620: | ||
324 | inits = inits_ak4620; | ||
325 | ak->num_chips = ak->num_dacs / 2; | ||
326 | ak->name = "ak4620"; | ||
327 | ak->total_regs = 0x08; | ||
328 | break; | ||
298 | default: | 329 | default: |
299 | snd_BUG(); | 330 | snd_BUG(); |
300 | return; | 331 | return; |
301 | } | 332 | } |
302 | 333 | ||
303 | for (chip = 0; chip < num_chips; chip++) { | 334 | for (chip = 0; chip < ak->num_chips; chip++) { |
304 | ptr = inits; | 335 | ptr = inits; |
305 | while (*ptr != 0xff) { | 336 | while (*ptr != 0xff) { |
306 | reg = *ptr++; | 337 | reg = *ptr++; |
307 | data = *ptr++; | 338 | data = *ptr++; |
308 | snd_akm4xxx_write(ak, chip, reg, data); | 339 | snd_akm4xxx_write(ak, chip, reg, data); |
340 | udelay(10); | ||
309 | } | 341 | } |
310 | } | 342 | } |
311 | } | 343 | } |
@@ -688,6 +720,12 @@ static int build_dac_controls(struct snd_akm4xxx *ak) | |||
688 | AK_COMPOSE(idx/2, (idx%2) + 3, 0, 255); | 720 | AK_COMPOSE(idx/2, (idx%2) + 3, 0, 255); |
689 | knew.tlv.p = db_scale_linear; | 721 | knew.tlv.p = db_scale_linear; |
690 | break; | 722 | break; |
723 | case SND_AK4620: | ||
724 | /* register 6 & 7 */ | ||
725 | knew.private_value = | ||
726 | AK_COMPOSE(idx/2, (idx%2) + 6, 0, 255); | ||
727 | knew.tlv.p = db_scale_linear; | ||
728 | break; | ||
691 | default: | 729 | default: |
692 | return -EINVAL; | 730 | return -EINVAL; |
693 | } | 731 | } |
@@ -704,10 +742,12 @@ static int build_dac_controls(struct snd_akm4xxx *ak) | |||
704 | 742 | ||
705 | static int build_adc_controls(struct snd_akm4xxx *ak) | 743 | static int build_adc_controls(struct snd_akm4xxx *ak) |
706 | { | 744 | { |
707 | int idx, err, mixer_ch, num_stereo; | 745 | int idx, err, mixer_ch, num_stereo, max_steps; |
708 | struct snd_kcontrol_new knew; | 746 | struct snd_kcontrol_new knew; |
709 | 747 | ||
710 | mixer_ch = 0; | 748 | mixer_ch = 0; |
749 | if (ak->type == SND_AK4528) | ||
750 | return 0; /* no controls */ | ||
711 | for (idx = 0; idx < ak->num_adcs;) { | 751 | for (idx = 0; idx < ak->num_adcs;) { |
712 | memset(&knew, 0, sizeof(knew)); | 752 | memset(&knew, 0, sizeof(knew)); |
713 | if (! ak->adc_info || ! ak->adc_info[mixer_ch].name) { | 753 | if (! ak->adc_info || ! ak->adc_info[mixer_ch].name) { |
@@ -733,13 +773,12 @@ static int build_adc_controls(struct snd_akm4xxx *ak) | |||
733 | } | 773 | } |
734 | /* register 4 & 5 */ | 774 | /* register 4 & 5 */ |
735 | if (ak->type == SND_AK5365) | 775 | if (ak->type == SND_AK5365) |
736 | knew.private_value = | 776 | max_steps = 152; |
737 | AK_COMPOSE(idx/2, (idx%2) + 4, 0, 151) | | ||
738 | AK_VOL_CVT | AK_IPGA; | ||
739 | else | 777 | else |
740 | knew.private_value = | 778 | max_steps = 164; |
741 | AK_COMPOSE(idx/2, (idx%2) + 4, 0, 163) | | 779 | knew.private_value = |
742 | AK_VOL_CVT | AK_IPGA; | 780 | AK_COMPOSE(idx/2, (idx%2) + 4, 0, max_steps) | |
781 | AK_VOL_CVT | AK_IPGA; | ||
743 | knew.tlv.p = db_scale_vol_datt; | 782 | knew.tlv.p = db_scale_vol_datt; |
744 | err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak)); | 783 | err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak)); |
745 | if (err < 0) | 784 | if (err < 0) |
@@ -808,6 +847,7 @@ static int build_deemphasis(struct snd_akm4xxx *ak, int num_emphs) | |||
808 | switch (ak->type) { | 847 | switch (ak->type) { |
809 | case SND_AK4524: | 848 | case SND_AK4524: |
810 | case SND_AK4528: | 849 | case SND_AK4528: |
850 | case SND_AK4620: | ||
811 | /* register 3 */ | 851 | /* register 3 */ |
812 | knew.private_value = AK_COMPOSE(idx, 3, 0, 0); | 852 | knew.private_value = AK_COMPOSE(idx, 3, 0, 0); |
813 | break; | 853 | break; |
@@ -834,6 +874,35 @@ static int build_deemphasis(struct snd_akm4xxx *ak, int num_emphs) | |||
834 | return 0; | 874 | return 0; |
835 | } | 875 | } |
836 | 876 | ||
877 | #ifdef CONFIG_PROC_FS | ||
878 | static void proc_regs_read(struct snd_info_entry *entry, | ||
879 | struct snd_info_buffer *buffer) | ||
880 | { | ||
881 | struct snd_akm4xxx *ak = (struct snd_akm4xxx *)entry->private_data; | ||
882 | int reg, val, chip; | ||
883 | for (chip = 0; chip < ak->num_chips; chip++) { | ||
884 | for (reg = 0; reg < ak->total_regs; reg++) { | ||
885 | val = snd_akm4xxx_get(ak, chip, reg); | ||
886 | snd_iprintf(buffer, "chip %d: 0x%02x = 0x%02x\n", chip, | ||
887 | reg, val); | ||
888 | } | ||
889 | } | ||
890 | } | ||
891 | |||
892 | static int proc_init(struct snd_akm4xxx *ak) | ||
893 | { | ||
894 | struct snd_info_entry *entry; | ||
895 | int err; | ||
896 | err = snd_card_proc_new(ak->card, ak->name, &entry); | ||
897 | if (err < 0) | ||
898 | return err; | ||
899 | snd_info_set_text_ops(entry, ak, proc_regs_read); | ||
900 | return 0; | ||
901 | } | ||
902 | #else /* !CONFIG_PROC_FS */ | ||
903 | static int proc_init(struct snd_akm4xxx *ak) {} | ||
904 | #endif | ||
905 | |||
837 | int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak) | 906 | int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak) |
838 | { | 907 | { |
839 | int err, num_emphs; | 908 | int err, num_emphs; |
@@ -845,18 +914,21 @@ int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak) | |||
845 | err = build_adc_controls(ak); | 914 | err = build_adc_controls(ak); |
846 | if (err < 0) | 915 | if (err < 0) |
847 | return err; | 916 | return err; |
848 | |||
849 | if (ak->type == SND_AK4355 || ak->type == SND_AK4358) | 917 | if (ak->type == SND_AK4355 || ak->type == SND_AK4358) |
850 | num_emphs = 1; | 918 | num_emphs = 1; |
919 | else if (ak->type == SND_AK4620) | ||
920 | num_emphs = 0; | ||
851 | else | 921 | else |
852 | num_emphs = ak->num_dacs / 2; | 922 | num_emphs = ak->num_dacs / 2; |
853 | err = build_deemphasis(ak, num_emphs); | 923 | err = build_deemphasis(ak, num_emphs); |
854 | if (err < 0) | 924 | if (err < 0) |
855 | return err; | 925 | return err; |
926 | err = proc_init(ak); | ||
927 | if (err < 0) | ||
928 | return err; | ||
856 | 929 | ||
857 | return 0; | 930 | return 0; |
858 | } | 931 | } |
859 | |||
860 | EXPORT_SYMBOL(snd_akm4xxx_build_controls); | 932 | EXPORT_SYMBOL(snd_akm4xxx_build_controls); |
861 | 933 | ||
862 | static int __init alsa_akm4xxx_module_init(void) | 934 | static int __init alsa_akm4xxx_module_init(void) |