aboutsummaryrefslogtreecommitdiffstats
path: root/sound/i2c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/i2c')
-rw-r--r--sound/i2c/Makefile1
-rw-r--r--sound/i2c/other/Makefile4
-rw-r--r--sound/i2c/other/ak4114.c29
-rw-r--r--sound/i2c/other/ak4117.c2
-rw-r--r--sound/i2c/other/ak4xxx-adda.c110
-rw-r--r--sound/i2c/other/pt2258.c233
6 files changed, 344 insertions, 35 deletions
diff --git a/sound/i2c/Makefile b/sound/i2c/Makefile
index 816a2e7c88ca..45902d48c89c 100644
--- a/sound/i2c/Makefile
+++ b/sound/i2c/Makefile
@@ -16,3 +16,4 @@ obj-$(CONFIG_SND) += other/
16# Toplevel Module Dependency 16# Toplevel Module Dependency
17obj-$(CONFIG_SND_INTERWAVE_STB) += snd-tea6330t.o snd-i2c.o 17obj-$(CONFIG_SND_INTERWAVE_STB) += snd-tea6330t.o snd-i2c.o
18obj-$(CONFIG_SND_ICE1712) += snd-cs8427.o snd-i2c.o 18obj-$(CONFIG_SND_ICE1712) += snd-cs8427.o snd-i2c.o
19obj-$(CONFIG_SND_ICE1724) += snd-i2c.o
diff --git a/sound/i2c/other/Makefile b/sound/i2c/other/Makefile
index 2fe023ef00a7..77a8a7c75dd9 100644
--- a/sound/i2c/other/Makefile
+++ b/sound/i2c/other/Makefile
@@ -6,11 +6,11 @@
6snd-ak4114-objs := ak4114.o 6snd-ak4114-objs := ak4114.o
7snd-ak4117-objs := ak4117.o 7snd-ak4117-objs := ak4117.o
8snd-ak4xxx-adda-objs := ak4xxx-adda.o 8snd-ak4xxx-adda-objs := ak4xxx-adda.o
9snd-pt2258-objs := pt2258.o
9snd-tea575x-tuner-objs := tea575x-tuner.o 10snd-tea575x-tuner-objs := tea575x-tuner.o
10 11
11# Module Dependency 12# Module Dependency
12obj-$(CONFIG_SND_PDAUDIOCF) += snd-ak4117.o 13obj-$(CONFIG_SND_PDAUDIOCF) += snd-ak4117.o
13obj-$(CONFIG_SND_ICE1712) += snd-ak4xxx-adda.o 14obj-$(CONFIG_SND_ICE1712) += snd-ak4xxx-adda.o
14obj-$(CONFIG_SND_ICE1724) += snd-ak4xxx-adda.o 15obj-$(CONFIG_SND_ICE1724) += snd-ak4114.o snd-ak4xxx-adda.o snd-pt2258.o
15obj-$(CONFIG_SND_ICE1724) += snd-ak4114.o
16obj-$(CONFIG_SND_FM801_TEA575X) += snd-tea575x-tuner.o 16obj-$(CONFIG_SND_FM801_TEA575X) += snd-tea575x-tuner.o
diff --git a/sound/i2c/other/ak4114.c b/sound/i2c/other/ak4114.c
index d2f2c5078e65..adbfd5884d06 100644
--- a/sound/i2c/other/ak4114.c
+++ b/sound/i2c/other/ak4114.c
@@ -42,8 +42,8 @@ static void reg_write(struct ak4114 *ak4114, unsigned char reg, unsigned char va
42 ak4114->write(ak4114->private_data, reg, val); 42 ak4114->write(ak4114->private_data, reg, val);
43 if (reg <= AK4114_REG_INT1_MASK) 43 if (reg <= AK4114_REG_INT1_MASK)
44 ak4114->regmap[reg] = val; 44 ak4114->regmap[reg] = val;
45 else if (reg >= AK4114_REG_RXCSB0 && reg <= AK4114_REG_TXCSB4) 45 else if (reg >= AK4114_REG_TXCSB0 && reg <= AK4114_REG_TXCSB4)
46 ak4114->txcsb[reg-AK4114_REG_RXCSB0] = val; 46 ak4114->txcsb[reg-AK4114_REG_TXCSB0] = val;
47} 47}
48 48
49static inline unsigned char reg_read(struct ak4114 *ak4114, unsigned char reg) 49static inline unsigned char reg_read(struct ak4114 *ak4114, unsigned char reg)
@@ -66,10 +66,8 @@ static void snd_ak4114_free(struct ak4114 *chip)
66{ 66{
67 chip->init = 1; /* don't schedule new work */ 67 chip->init = 1; /* don't schedule new work */
68 mb(); 68 mb();
69 if (chip->workqueue != NULL) { 69 cancel_delayed_work(&chip->work);
70 flush_workqueue(chip->workqueue); 70 flush_scheduled_work();
71 destroy_workqueue(chip->workqueue);
72 }
73 kfree(chip); 71 kfree(chip);
74} 72}
75 73
@@ -82,7 +80,7 @@ static int snd_ak4114_dev_free(struct snd_device *device)
82 80
83int snd_ak4114_create(struct snd_card *card, 81int snd_ak4114_create(struct snd_card *card,
84 ak4114_read_t *read, ak4114_write_t *write, 82 ak4114_read_t *read, ak4114_write_t *write,
85 unsigned char pgm[7], unsigned char txcsb[5], 83 const unsigned char pgm[7], const unsigned char txcsb[5],
86 void *private_data, struct ak4114 **r_ak4114) 84 void *private_data, struct ak4114 **r_ak4114)
87{ 85{
88 struct ak4114 *chip; 86 struct ak4114 *chip;
@@ -100,18 +98,13 @@ int snd_ak4114_create(struct snd_card *card,
100 chip->read = read; 98 chip->read = read;
101 chip->write = write; 99 chip->write = write;
102 chip->private_data = private_data; 100 chip->private_data = private_data;
101 INIT_DELAYED_WORK(&chip->work, ak4114_stats);
103 102
104 for (reg = 0; reg < 7; reg++) 103 for (reg = 0; reg < 7; reg++)
105 chip->regmap[reg] = pgm[reg]; 104 chip->regmap[reg] = pgm[reg];
106 for (reg = 0; reg < 5; reg++) 105 for (reg = 0; reg < 5; reg++)
107 chip->txcsb[reg] = txcsb[reg]; 106 chip->txcsb[reg] = txcsb[reg];
108 107
109 chip->workqueue = create_workqueue("snd-ak4114");
110 if (chip->workqueue == NULL) {
111 kfree(chip);
112 return -ENOMEM;
113 }
114
115 snd_ak4114_reinit(chip); 108 snd_ak4114_reinit(chip);
116 109
117 chip->rcs0 = reg_read(chip, AK4114_REG_RCS0) & ~(AK4114_QINT | AK4114_CINT); 110 chip->rcs0 = reg_read(chip, AK4114_REG_RCS0) & ~(AK4114_QINT | AK4114_CINT);
@@ -134,7 +127,8 @@ void snd_ak4114_reg_write(struct ak4114 *chip, unsigned char reg, unsigned char
134 if (reg <= AK4114_REG_INT1_MASK) 127 if (reg <= AK4114_REG_INT1_MASK)
135 reg_write(chip, reg, (chip->regmap[reg] & ~mask) | val); 128 reg_write(chip, reg, (chip->regmap[reg] & ~mask) | val);
136 else if (reg >= AK4114_REG_TXCSB0 && reg <= AK4114_REG_TXCSB4) 129 else if (reg >= AK4114_REG_TXCSB0 && reg <= AK4114_REG_TXCSB4)
137 reg_write(chip, reg, (chip->txcsb[reg] & ~mask) | val); 130 reg_write(chip, reg,
131 (chip->txcsb[reg-AK4114_REG_TXCSB0] & ~mask) | val);
138} 132}
139 133
140void snd_ak4114_reinit(struct ak4114 *chip) 134void snd_ak4114_reinit(struct ak4114 *chip)
@@ -143,7 +137,7 @@ void snd_ak4114_reinit(struct ak4114 *chip)
143 137
144 chip->init = 1; 138 chip->init = 1;
145 mb(); 139 mb();
146 flush_workqueue(chip->workqueue); 140 flush_scheduled_work();
147 /* bring the chip to reset state and powerdown state */ 141 /* bring the chip to reset state and powerdown state */
148 reg_write(chip, AK4114_REG_PWRDN, old & ~(AK4114_RST|AK4114_PWN)); 142 reg_write(chip, AK4114_REG_PWRDN, old & ~(AK4114_RST|AK4114_PWN));
149 udelay(200); 143 udelay(200);
@@ -158,8 +152,7 @@ void snd_ak4114_reinit(struct ak4114 *chip)
158 reg_write(chip, AK4114_REG_PWRDN, old | AK4114_RST | AK4114_PWN); 152 reg_write(chip, AK4114_REG_PWRDN, old | AK4114_RST | AK4114_PWN);
159 /* bring up statistics / event queing */ 153 /* bring up statistics / event queing */
160 chip->init = 0; 154 chip->init = 0;
161 INIT_DELAYED_WORK(&chip->work, ak4114_stats); 155 schedule_delayed_work(&chip->work, HZ / 10);
162 queue_delayed_work(chip->workqueue, &chip->work, HZ / 10);
163} 156}
164 157
165static unsigned int external_rate(unsigned char rcs1) 158static unsigned int external_rate(unsigned char rcs1)
@@ -568,7 +561,7 @@ static void ak4114_stats(struct work_struct *work)
568 if (chip->init) 561 if (chip->init)
569 return; 562 return;
570 snd_ak4114_check_rate_and_errors(chip, 0); 563 snd_ak4114_check_rate_and_errors(chip, 0);
571 queue_delayed_work(chip->workqueue, &chip->work, HZ / 10); 564 schedule_delayed_work(&chip->work, HZ / 10);
572} 565}
573 566
574EXPORT_SYMBOL(snd_ak4114_create); 567EXPORT_SYMBOL(snd_ak4114_create);
diff --git a/sound/i2c/other/ak4117.c b/sound/i2c/other/ak4117.c
index 4e45952dd95a..c022f29da2f7 100644
--- a/sound/i2c/other/ak4117.c
+++ b/sound/i2c/other/ak4117.c
@@ -74,7 +74,7 @@ static int snd_ak4117_dev_free(struct snd_device *device)
74} 74}
75 75
76int snd_ak4117_create(struct snd_card *card, ak4117_read_t *read, ak4117_write_t *write, 76int snd_ak4117_create(struct snd_card *card, ak4117_read_t *read, ak4117_write_t *write,
77 unsigned char pgm[5], void *private_data, struct ak4117 **r_ak4117) 77 const unsigned char pgm[5], void *private_data, struct ak4117 **r_ak4117)
78{ 78{
79 struct ak4117 *chip; 79 struct ak4117 *chip;
80 int err = 0; 80 int err = 0;
diff --git a/sound/i2c/other/ak4xxx-adda.c b/sound/i2c/other/ak4xxx-adda.c
index 5da49e2eb350..8805110017a7 100644
--- a/sound/i2c/other/ak4xxx-adda.c
+++ b/sound/i2c/other/ak4xxx-adda.c
@@ -140,7 +140,7 @@ EXPORT_SYMBOL(snd_akm4xxx_reset);
140 * Used for AK4524 input/ouput attenuation, AK4528, and 140 * Used for AK4524 input/ouput attenuation, AK4528, and
141 * AK5365 input attenuation 141 * AK5365 input attenuation
142 */ 142 */
143static unsigned char vol_cvt_datt[128] = { 143static const unsigned char vol_cvt_datt[128] = {
144 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04, 144 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04,
145 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x06, 145 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x06,
146 0x06, 0x07, 0x07, 0x08, 0x08, 0x08, 0x09, 0x0a, 146 0x06, 0x07, 0x07, 0x08, 0x08, 0x08, 0x09, 0x0a,
@@ -162,17 +162,17 @@ static unsigned char vol_cvt_datt[128] = {
162/* 162/*
163 * dB tables 163 * dB tables
164 */ 164 */
165static DECLARE_TLV_DB_SCALE(db_scale_vol_datt, -6350, 50, 1); 165static const DECLARE_TLV_DB_SCALE(db_scale_vol_datt, -6350, 50, 1);
166static DECLARE_TLV_DB_SCALE(db_scale_8bit, -12750, 50, 1); 166static const DECLARE_TLV_DB_SCALE(db_scale_8bit, -12750, 50, 1);
167static DECLARE_TLV_DB_SCALE(db_scale_7bit, -6350, 50, 1); 167static const DECLARE_TLV_DB_SCALE(db_scale_7bit, -6350, 50, 1);
168static DECLARE_TLV_DB_LINEAR(db_scale_linear, TLV_DB_GAIN_MUTE, 0); 168static const DECLARE_TLV_DB_LINEAR(db_scale_linear, TLV_DB_GAIN_MUTE, 0);
169 169
170/* 170/*
171 * initialize all the ak4xxx chips 171 * initialize all the ak4xxx chips
172 */ 172 */
173void snd_akm4xxx_init(struct snd_akm4xxx *ak) 173void snd_akm4xxx_init(struct snd_akm4xxx *ak)
174{ 174{
175 static unsigned char inits_ak4524[] = { 175 static const unsigned char inits_ak4524[] = {
176 0x00, 0x07, /* 0: all power up */ 176 0x00, 0x07, /* 0: all power up */
177 0x01, 0x00, /* 1: ADC/DAC reset */ 177 0x01, 0x00, /* 1: ADC/DAC reset */
178 0x02, 0x60, /* 2: 24bit I2S */ 178 0x02, 0x60, /* 2: 24bit I2S */
@@ -184,7 +184,7 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
184 0x07, 0x00, /* 7: DAC right muted */ 184 0x07, 0x00, /* 7: DAC right muted */
185 0xff, 0xff 185 0xff, 0xff
186 }; 186 };
187 static unsigned char inits_ak4528[] = { 187 static const unsigned char inits_ak4528[] = {
188 0x00, 0x07, /* 0: all power up */ 188 0x00, 0x07, /* 0: all power up */
189 0x01, 0x00, /* 1: ADC/DAC reset */ 189 0x01, 0x00, /* 1: ADC/DAC reset */
190 0x02, 0x60, /* 2: 24bit I2S */ 190 0x02, 0x60, /* 2: 24bit I2S */
@@ -194,7 +194,7 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
194 0x05, 0x00, /* 5: ADC right muted */ 194 0x05, 0x00, /* 5: ADC right muted */
195 0xff, 0xff 195 0xff, 0xff
196 }; 196 };
197 static unsigned char inits_ak4529[] = { 197 static const unsigned char inits_ak4529[] = {
198 0x09, 0x01, /* 9: ATS=0, RSTN=1 */ 198 0x09, 0x01, /* 9: ATS=0, RSTN=1 */
199 0x0a, 0x3f, /* A: all power up, no zero/overflow detection */ 199 0x0a, 0x3f, /* A: all power up, no zero/overflow detection */
200 0x00, 0x0c, /* 0: TDM=0, 24bit I2S, SMUTE=0 */ 200 0x00, 0x0c, /* 0: TDM=0, 24bit I2S, SMUTE=0 */
@@ -210,7 +210,7 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
210 0x08, 0x55, /* 8: deemphasis all off */ 210 0x08, 0x55, /* 8: deemphasis all off */
211 0xff, 0xff 211 0xff, 0xff
212 }; 212 };
213 static unsigned char inits_ak4355[] = { 213 static const unsigned char inits_ak4355[] = {
214 0x01, 0x02, /* 1: reset and soft-mute */ 214 0x01, 0x02, /* 1: reset and soft-mute */
215 0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect, 215 0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect,
216 * disable DZF, sharp roll-off, RSTN#=0 */ 216 * disable DZF, sharp roll-off, RSTN#=0 */
@@ -227,7 +227,7 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
227 0x01, 0x01, /* 1: un-reset, unmute */ 227 0x01, 0x01, /* 1: un-reset, unmute */
228 0xff, 0xff 228 0xff, 0xff
229 }; 229 };
230 static unsigned char inits_ak4358[] = { 230 static const unsigned char inits_ak4358[] = {
231 0x01, 0x02, /* 1: reset and soft-mute */ 231 0x01, 0x02, /* 1: reset and soft-mute */
232 0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect, 232 0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect,
233 * disable DZF, sharp roll-off, RSTN#=0 */ 233 * disable DZF, sharp roll-off, RSTN#=0 */
@@ -246,7 +246,7 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
246 0x01, 0x01, /* 1: un-reset, unmute */ 246 0x01, 0x01, /* 1: un-reset, unmute */
247 0xff, 0xff 247 0xff, 0xff
248 }; 248 };
249 static unsigned char inits_ak4381[] = { 249 static const unsigned char inits_ak4381[] = {
250 0x00, 0x0c, /* 0: mode3(i2s), disable auto-clock detect */ 250 0x00, 0x0c, /* 0: mode3(i2s), disable auto-clock detect */
251 0x01, 0x02, /* 1: de-emphasis off, normal speed, 251 0x01, 0x02, /* 1: de-emphasis off, normal speed,
252 * sharp roll-off, DZF off */ 252 * sharp roll-off, DZF off */
@@ -259,7 +259,8 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
259 }; 259 };
260 260
261 int chip, num_chips; 261 int chip, num_chips;
262 unsigned char *ptr, reg, data, *inits; 262 const unsigned char *ptr, *inits;
263 unsigned char reg, data;
263 264
264 memset(ak->images, 0, sizeof(ak->images)); 265 memset(ak->images, 0, sizeof(ak->images));
265 memset(ak->volumes, 0, sizeof(ak->volumes)); 266 memset(ak->volumes, 0, sizeof(ak->volumes));
@@ -513,6 +514,66 @@ static int ak4xxx_switch_put(struct snd_kcontrol *kcontrol,
513 return change; 514 return change;
514} 515}
515 516
517#define AK5365_NUM_INPUTS 5
518
519static int ak4xxx_capture_source_info(struct snd_kcontrol *kcontrol,
520 struct snd_ctl_elem_info *uinfo)
521{
522 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
523 int mixer_ch = AK_GET_SHIFT(kcontrol->private_value);
524 const char **input_names;
525 int num_names, idx;
526
527 input_names = ak->adc_info[mixer_ch].input_names;
528
529 num_names = 0;
530 while (num_names < AK5365_NUM_INPUTS && input_names[num_names])
531 ++num_names;
532
533 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
534 uinfo->count = 1;
535 uinfo->value.enumerated.items = num_names;
536 idx = uinfo->value.enumerated.item;
537 if (idx >= num_names)
538 return -EINVAL;
539 strncpy(uinfo->value.enumerated.name, input_names[idx],
540 sizeof(uinfo->value.enumerated.name));
541 return 0;
542}
543
544static int ak4xxx_capture_source_get(struct snd_kcontrol *kcontrol,
545 struct snd_ctl_elem_value *ucontrol)
546{
547 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
548 int chip = AK_GET_CHIP(kcontrol->private_value);
549 int addr = AK_GET_ADDR(kcontrol->private_value);
550 int mask = AK_GET_MASK(kcontrol->private_value);
551 unsigned char val;
552
553 val = snd_akm4xxx_get(ak, chip, addr) & mask;
554 ucontrol->value.enumerated.item[0] = val;
555 return 0;
556}
557
558static int ak4xxx_capture_source_put(struct snd_kcontrol *kcontrol,
559 struct snd_ctl_elem_value *ucontrol)
560{
561 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
562 int chip = AK_GET_CHIP(kcontrol->private_value);
563 int addr = AK_GET_ADDR(kcontrol->private_value);
564 int mask = AK_GET_MASK(kcontrol->private_value);
565 unsigned char oval, val;
566
567 oval = snd_akm4xxx_get(ak, chip, addr);
568 val = oval & ~mask;
569 val |= ucontrol->value.enumerated.item[0] & mask;
570 if (val != oval) {
571 snd_akm4xxx_write(ak, chip, addr, val);
572 return 1;
573 }
574 return 0;
575}
576
516/* 577/*
517 * build AK4xxx controls 578 * build AK4xxx controls
518 */ 579 */
@@ -647,9 +708,10 @@ static int build_adc_controls(struct snd_akm4xxx *ak)
647 708
648 if (ak->type == SND_AK5365 && (idx % 2) == 0) { 709 if (ak->type == SND_AK5365 && (idx % 2) == 0) {
649 if (! ak->adc_info || 710 if (! ak->adc_info ||
650 ! ak->adc_info[mixer_ch].switch_name) 711 ! ak->adc_info[mixer_ch].switch_name) {
651 knew.name = "Capture Switch"; 712 knew.name = "Capture Switch";
652 else 713 knew.index = mixer_ch + ak->idx_offset * 2;
714 } else
653 knew.name = ak->adc_info[mixer_ch].switch_name; 715 knew.name = ak->adc_info[mixer_ch].switch_name;
654 knew.info = ak4xxx_switch_info; 716 knew.info = ak4xxx_switch_info;
655 knew.get = ak4xxx_switch_get; 717 knew.get = ak4xxx_switch_get;
@@ -662,6 +724,26 @@ static int build_adc_controls(struct snd_akm4xxx *ak)
662 err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak)); 724 err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
663 if (err < 0) 725 if (err < 0)
664 return err; 726 return err;
727
728 memset(&knew, 0, sizeof(knew));
729 knew.name = ak->adc_info[mixer_ch].selector_name;
730 if (!knew.name) {
731 knew.name = "Capture Channel";
732 knew.index = mixer_ch + ak->idx_offset * 2;
733 }
734
735 knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
736 knew.info = ak4xxx_capture_source_info;
737 knew.get = ak4xxx_capture_source_get;
738 knew.put = ak4xxx_capture_source_put;
739 knew.access = 0;
740 /* input selector control: reg. 1, bits 0-2.
741 * mis-use 'shift' to pass mixer_ch */
742 knew.private_value
743 = AK_COMPOSE(idx/2, 1, mixer_ch, 0x07);
744 err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
745 if (err < 0)
746 return err;
665 } 747 }
666 748
667 idx += num_stereo; 749 idx += num_stereo;
diff --git a/sound/i2c/other/pt2258.c b/sound/i2c/other/pt2258.c
new file mode 100644
index 000000000000..e91cc3b44de5
--- /dev/null
+++ b/sound/i2c/other/pt2258.c
@@ -0,0 +1,233 @@
1/*
2 * ALSA Driver for the PT2258 volume controller.
3 *
4 * Copyright (c) 2006 Jochen Voss <voss@seehuhn.de>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#include <sound/driver.h>
23#include <sound/core.h>
24#include <sound/control.h>
25#include <sound/tlv.h>
26#include <sound/i2c.h>
27#include <sound/pt2258.h>
28
29MODULE_AUTHOR("Jochen Voss <voss@seehuhn.de>");
30MODULE_DESCRIPTION("PT2258 volume controller (Princeton Technology Corp.)");
31MODULE_LICENSE("GPL");
32
33#define PT2258_CMD_RESET 0xc0
34#define PT2258_CMD_UNMUTE 0xf8
35#define PT2258_CMD_MUTE 0xf9
36
37static const unsigned char pt2258_channel_code[12] = {
38 0x80, 0x90, /* channel 1: -10dB, -1dB */
39 0x40, 0x50, /* channel 2: -10dB, -1dB */
40 0x00, 0x10, /* channel 3: -10dB, -1dB */
41 0x20, 0x30, /* channel 4: -10dB, -1dB */
42 0x60, 0x70, /* channel 5: -10dB, -1dB */
43 0xa0, 0xb0 /* channel 6: -10dB, -1dB */
44};
45
46int snd_pt2258_reset(struct snd_pt2258 *pt)
47{
48 unsigned char bytes[2];
49 int i;
50
51 /* reset chip */
52 bytes[0] = PT2258_CMD_RESET;
53 snd_i2c_lock(pt->i2c_bus);
54 if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 1) != 1)
55 goto __error;
56 snd_i2c_unlock(pt->i2c_bus);
57
58 /* mute all channels */
59 pt->mute = 1;
60 bytes[0] = PT2258_CMD_MUTE;
61 snd_i2c_lock(pt->i2c_bus);
62 if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 1) != 1)
63 goto __error;
64 snd_i2c_unlock(pt->i2c_bus);
65
66 /* set all channels to 0dB */
67 for (i = 0; i < 6; ++i)
68 pt->volume[i] = 0;
69 bytes[0] = 0xd0;
70 bytes[1] = 0xe0;
71 snd_i2c_lock(pt->i2c_bus);
72 if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 2) != 2)
73 goto __error;
74 snd_i2c_unlock(pt->i2c_bus);
75
76 return 0;
77
78 __error:
79 snd_i2c_unlock(pt->i2c_bus);
80 snd_printk(KERN_ERR "PT2258 reset failed\n");
81 return -EIO;
82}
83
84static int pt2258_stereo_volume_info(struct snd_kcontrol *kcontrol,
85 struct snd_ctl_elem_info *uinfo)
86{
87 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
88 uinfo->count = 2;
89 uinfo->value.integer.min = 0;
90 uinfo->value.integer.max = 79;
91 return 0;
92}
93
94static int pt2258_stereo_volume_get(struct snd_kcontrol *kcontrol,
95 struct snd_ctl_elem_value *ucontrol)
96{
97 struct snd_pt2258 *pt = kcontrol->private_data;
98 int base = kcontrol->private_value;
99
100 /* chip does not support register reads */
101 ucontrol->value.integer.value[0] = 79 - pt->volume[base];
102 ucontrol->value.integer.value[1] = 79 - pt->volume[base + 1];
103 return 0;
104}
105
106static int pt2258_stereo_volume_put(struct snd_kcontrol *kcontrol,
107 struct snd_ctl_elem_value *ucontrol)
108{
109 struct snd_pt2258 *pt = kcontrol->private_data;
110 int base = kcontrol->private_value;
111 unsigned char bytes[2];
112 int val0, val1;
113
114 val0 = 79 - ucontrol->value.integer.value[0];
115 val1 = 79 - ucontrol->value.integer.value[1];
116 if (val0 == pt->volume[base] && val1 == pt->volume[base + 1])
117 return 0;
118
119 pt->volume[base] = val0;
120 bytes[0] = pt2258_channel_code[2 * base] | (val0 / 10);
121 bytes[1] = pt2258_channel_code[2 * base + 1] | (val0 % 10);
122 snd_i2c_lock(pt->i2c_bus);
123 if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 2) != 2)
124 goto __error;
125 snd_i2c_unlock(pt->i2c_bus);
126
127 pt->volume[base + 1] = val1;
128 bytes[0] = pt2258_channel_code[2 * base + 2] | (val1 / 10);
129 bytes[1] = pt2258_channel_code[2 * base + 3] | (val1 % 10);
130 snd_i2c_lock(pt->i2c_bus);
131 if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 2) != 2)
132 goto __error;
133 snd_i2c_unlock(pt->i2c_bus);
134
135 return 1;
136
137 __error:
138 snd_i2c_unlock(pt->i2c_bus);
139 snd_printk(KERN_ERR "PT2258 access failed\n");
140 return -EIO;
141}
142
143static int pt2258_switch_info(struct snd_kcontrol *kcontrol,
144 struct snd_ctl_elem_info *uinfo)
145{
146 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
147 uinfo->count = 1;
148 uinfo->value.integer.min = 0;
149 uinfo->value.integer.max = 1;
150 return 0;
151}
152
153static int pt2258_switch_get(struct snd_kcontrol *kcontrol,
154 struct snd_ctl_elem_value *ucontrol)
155{
156 struct snd_pt2258 *pt = kcontrol->private_data;
157
158 ucontrol->value.integer.value[0] = !pt->mute;
159 return 0;
160}
161
162static int pt2258_switch_put(struct snd_kcontrol *kcontrol,
163 struct snd_ctl_elem_value *ucontrol)
164{
165 struct snd_pt2258 *pt = kcontrol->private_data;
166 unsigned char bytes[2];
167 int val;
168
169 val = !ucontrol->value.integer.value[0];
170 if (pt->mute == val)
171 return 0;
172
173 pt->mute = val;
174 bytes[0] = val ? PT2258_CMD_MUTE : PT2258_CMD_UNMUTE;
175 snd_i2c_lock(pt->i2c_bus);
176 if (snd_i2c_sendbytes(pt->i2c_dev, bytes, 1) != 1)
177 goto __error;
178 snd_i2c_unlock(pt->i2c_bus);
179
180 return 1;
181
182 __error:
183 snd_i2c_unlock(pt->i2c_bus);
184 snd_printk(KERN_ERR "PT2258 access failed 2\n");
185 return -EIO;
186}
187
188static const DECLARE_TLV_DB_SCALE(pt2258_db_scale, -7900, 100, 0);
189
190int snd_pt2258_build_controls(struct snd_pt2258 *pt)
191{
192 struct snd_kcontrol_new knew;
193 char *names[3] = {
194 "Mic Loopback Playback Volume",
195 "Line Loopback Playback Volume",
196 "CD Loopback Playback Volume"
197 };
198 int i, err;
199
200 for (i = 0; i < 3; ++i) {
201 memset(&knew, 0, sizeof(knew));
202 knew.name = names[i];
203 knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
204 knew.count = 1;
205 knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
206 SNDRV_CTL_ELEM_ACCESS_TLV_READ;
207 knew.private_value = 2 * i;
208 knew.info = pt2258_stereo_volume_info;
209 knew.get = pt2258_stereo_volume_get;
210 knew.put = pt2258_stereo_volume_put;
211 knew.tlv.p = pt2258_db_scale;
212
213 err = snd_ctl_add(pt->card, snd_ctl_new1(&knew, pt));
214 if (err < 0)
215 return err;
216 }
217
218 memset(&knew, 0, sizeof(knew));
219 knew.name = "Loopback Switch";
220 knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
221 knew.info = pt2258_switch_info;
222 knew.get = pt2258_switch_get;
223 knew.put = pt2258_switch_put;
224 knew.access = 0;
225 err = snd_ctl_add(pt->card, snd_ctl_new1(&knew, pt));
226 if (err < 0)
227 return err;
228
229 return 0;
230}
231
232EXPORT_SYMBOL(snd_pt2258_reset);
233EXPORT_SYMBOL(snd_pt2258_build_controls);