361 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Routines for control of the TEA6330T circuit via i2c bus4 * Sound fader control circuit for car radios by Philips Semiconductors5 * Copyright (c) by Jaroslav Kysela <perex@perex.cz>6 */7 8#include <linux/init.h>9#include <linux/slab.h>10#include <linux/module.h>11#include <sound/core.h>12#include <sound/control.h>13#include <sound/tea6330t.h>14 15MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");16MODULE_DESCRIPTION("Routines for control of the TEA6330T circuit via i2c bus");17MODULE_LICENSE("GPL");18 19#define TEA6330T_ADDR (0x80>>1) /* fixed address */20 21#define TEA6330T_SADDR_VOLUME_LEFT 0x00 /* volume left */22#define TEA6330T_SADDR_VOLUME_RIGHT 0x01 /* volume right */23#define TEA6330T_SADDR_BASS 0x02 /* bass control */24#define TEA6330T_SADDR_TREBLE 0x03 /* treble control */25#define TEA6330T_SADDR_FADER 0x04 /* fader control */26#define TEA6330T_MFN 0x20 /* mute control for selected channels */27#define TEA6330T_FCH 0x10 /* select fader channels - front or rear */28#define TEA6330T_SADDR_AUDIO_SWITCH 0x05 /* audio switch */29#define TEA6330T_GMU 0x80 /* mute control, general mute */30#define TEA6330T_EQN 0x40 /* equalizer switchover (0=equalizer-on) */31 32 33struct tea6330t {34 struct snd_i2c_device *device;35 struct snd_i2c_bus *bus;36 int equalizer;37 int fader;38 unsigned char regs[8];39 unsigned char mleft, mright;40 unsigned char bass, treble;41 unsigned char max_bass, max_treble;42};43 44 45int snd_tea6330t_detect(struct snd_i2c_bus *bus, int equalizer)46{47 int res;48 49 snd_i2c_lock(bus);50 res = snd_i2c_probeaddr(bus, TEA6330T_ADDR);51 snd_i2c_unlock(bus);52 return res;53}54 55#if 056static void snd_tea6330t_set(struct tea6330t *tea,57 unsigned char addr, unsigned char value)58{59 snd_i2c_write(tea->bus, TEA6330T_ADDR, addr, value, 1);60}61#endif62 63#define TEA6330T_MASTER_VOLUME(xname, xindex) \64{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \65 .info = snd_tea6330t_info_master_volume, \66 .get = snd_tea6330t_get_master_volume, .put = snd_tea6330t_put_master_volume }67 68static int snd_tea6330t_info_master_volume(struct snd_kcontrol *kcontrol,69 struct snd_ctl_elem_info *uinfo)70{71 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;72 uinfo->count = 2;73 uinfo->value.integer.min = 0;74 uinfo->value.integer.max = 43;75 return 0;76}77 78static int snd_tea6330t_get_master_volume(struct snd_kcontrol *kcontrol,79 struct snd_ctl_elem_value *ucontrol)80{81 struct tea6330t *tea = snd_kcontrol_chip(kcontrol);82 83 snd_i2c_lock(tea->bus);84 ucontrol->value.integer.value[0] = tea->mleft - 0x14;85 ucontrol->value.integer.value[1] = tea->mright - 0x14;86 snd_i2c_unlock(tea->bus);87 return 0;88}89 90static int snd_tea6330t_put_master_volume(struct snd_kcontrol *kcontrol,91 struct snd_ctl_elem_value *ucontrol)92{93 struct tea6330t *tea = snd_kcontrol_chip(kcontrol);94 int change, count, err;95 unsigned char bytes[3];96 unsigned char val1, val2;97 98 val1 = (ucontrol->value.integer.value[0] % 44) + 0x14;99 val2 = (ucontrol->value.integer.value[1] % 44) + 0x14;100 snd_i2c_lock(tea->bus);101 change = val1 != tea->mleft || val2 != tea->mright;102 tea->mleft = val1;103 tea->mright = val2;104 count = 0;105 if (tea->regs[TEA6330T_SADDR_VOLUME_LEFT] != 0) {106 bytes[count++] = TEA6330T_SADDR_VOLUME_LEFT;107 bytes[count++] = tea->regs[TEA6330T_SADDR_VOLUME_LEFT] = tea->mleft;108 }109 if (tea->regs[TEA6330T_SADDR_VOLUME_RIGHT] != 0) {110 if (count == 0)111 bytes[count++] = TEA6330T_SADDR_VOLUME_RIGHT;112 bytes[count++] = tea->regs[TEA6330T_SADDR_VOLUME_RIGHT] = tea->mright;113 }114 if (count > 0) {115 err = snd_i2c_sendbytes(tea->device, bytes, count);116 if (err < 0)117 change = err;118 }119 snd_i2c_unlock(tea->bus);120 return change;121}122 123#define TEA6330T_MASTER_SWITCH(xname, xindex) \124{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \125 .info = snd_tea6330t_info_master_switch, \126 .get = snd_tea6330t_get_master_switch, .put = snd_tea6330t_put_master_switch }127 128#define snd_tea6330t_info_master_switch snd_ctl_boolean_stereo_info129 130static int snd_tea6330t_get_master_switch(struct snd_kcontrol *kcontrol,131 struct snd_ctl_elem_value *ucontrol)132{133 struct tea6330t *tea = snd_kcontrol_chip(kcontrol);134 135 snd_i2c_lock(tea->bus);136 ucontrol->value.integer.value[0] = tea->regs[TEA6330T_SADDR_VOLUME_LEFT] == 0 ? 0 : 1;137 ucontrol->value.integer.value[1] = tea->regs[TEA6330T_SADDR_VOLUME_RIGHT] == 0 ? 0 : 1;138 snd_i2c_unlock(tea->bus);139 return 0;140}141 142static int snd_tea6330t_put_master_switch(struct snd_kcontrol *kcontrol,143 struct snd_ctl_elem_value *ucontrol)144{145 struct tea6330t *tea = snd_kcontrol_chip(kcontrol);146 int change, err;147 unsigned char bytes[3];148 unsigned char oval1, oval2, val1, val2;149 150 val1 = ucontrol->value.integer.value[0] & 1;151 val2 = ucontrol->value.integer.value[1] & 1;152 snd_i2c_lock(tea->bus);153 oval1 = tea->regs[TEA6330T_SADDR_VOLUME_LEFT] == 0 ? 0 : 1;154 oval2 = tea->regs[TEA6330T_SADDR_VOLUME_RIGHT] == 0 ? 0 : 1;155 change = val1 != oval1 || val2 != oval2;156 tea->regs[TEA6330T_SADDR_VOLUME_LEFT] = val1 ? tea->mleft : 0;157 tea->regs[TEA6330T_SADDR_VOLUME_RIGHT] = val2 ? tea->mright : 0;158 bytes[0] = TEA6330T_SADDR_VOLUME_LEFT;159 bytes[1] = tea->regs[TEA6330T_SADDR_VOLUME_LEFT];160 bytes[2] = tea->regs[TEA6330T_SADDR_VOLUME_RIGHT];161 err = snd_i2c_sendbytes(tea->device, bytes, 3);162 if (err < 0)163 change = err;164 snd_i2c_unlock(tea->bus);165 return change;166}167 168#define TEA6330T_BASS(xname, xindex) \169{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \170 .info = snd_tea6330t_info_bass, \171 .get = snd_tea6330t_get_bass, .put = snd_tea6330t_put_bass }172 173static int snd_tea6330t_info_bass(struct snd_kcontrol *kcontrol,174 struct snd_ctl_elem_info *uinfo)175{176 struct tea6330t *tea = snd_kcontrol_chip(kcontrol);177 178 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;179 uinfo->count = 1;180 uinfo->value.integer.min = 0;181 uinfo->value.integer.max = tea->max_bass;182 return 0;183}184 185static int snd_tea6330t_get_bass(struct snd_kcontrol *kcontrol,186 struct snd_ctl_elem_value *ucontrol)187{188 struct tea6330t *tea = snd_kcontrol_chip(kcontrol);189 190 ucontrol->value.integer.value[0] = tea->bass;191 return 0;192}193 194static int snd_tea6330t_put_bass(struct snd_kcontrol *kcontrol,195 struct snd_ctl_elem_value *ucontrol)196{197 struct tea6330t *tea = snd_kcontrol_chip(kcontrol);198 int change, err;199 unsigned char bytes[2];200 unsigned char val1;201 202 val1 = ucontrol->value.integer.value[0] % (tea->max_bass + 1);203 snd_i2c_lock(tea->bus);204 tea->bass = val1;205 val1 += tea->equalizer ? 7 : 3;206 change = tea->regs[TEA6330T_SADDR_BASS] != val1;207 bytes[0] = TEA6330T_SADDR_BASS;208 bytes[1] = tea->regs[TEA6330T_SADDR_BASS] = val1;209 err = snd_i2c_sendbytes(tea->device, bytes, 2);210 if (err < 0)211 change = err;212 snd_i2c_unlock(tea->bus);213 return change;214}215 216#define TEA6330T_TREBLE(xname, xindex) \217{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \218 .info = snd_tea6330t_info_treble, \219 .get = snd_tea6330t_get_treble, .put = snd_tea6330t_put_treble }220 221static int snd_tea6330t_info_treble(struct snd_kcontrol *kcontrol,222 struct snd_ctl_elem_info *uinfo)223{224 struct tea6330t *tea = snd_kcontrol_chip(kcontrol);225 226 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;227 uinfo->count = 1;228 uinfo->value.integer.min = 0;229 uinfo->value.integer.max = tea->max_treble;230 return 0;231}232 233static int snd_tea6330t_get_treble(struct snd_kcontrol *kcontrol,234 struct snd_ctl_elem_value *ucontrol)235{236 struct tea6330t *tea = snd_kcontrol_chip(kcontrol);237 238 ucontrol->value.integer.value[0] = tea->treble;239 return 0;240}241 242static int snd_tea6330t_put_treble(struct snd_kcontrol *kcontrol,243 struct snd_ctl_elem_value *ucontrol)244{245 struct tea6330t *tea = snd_kcontrol_chip(kcontrol);246 int change, err;247 unsigned char bytes[2];248 unsigned char val1;249 250 val1 = ucontrol->value.integer.value[0] % (tea->max_treble + 1);251 snd_i2c_lock(tea->bus);252 tea->treble = val1;253 val1 += 3;254 change = tea->regs[TEA6330T_SADDR_TREBLE] != val1;255 bytes[0] = TEA6330T_SADDR_TREBLE;256 bytes[1] = tea->regs[TEA6330T_SADDR_TREBLE] = val1;257 err = snd_i2c_sendbytes(tea->device, bytes, 2);258 if (err < 0)259 change = err;260 snd_i2c_unlock(tea->bus);261 return change;262}263 264static const struct snd_kcontrol_new snd_tea6330t_controls[] = {265TEA6330T_MASTER_SWITCH("Master Playback Switch", 0),266TEA6330T_MASTER_VOLUME("Master Playback Volume", 0),267TEA6330T_BASS("Tone Control - Bass", 0),268TEA6330T_TREBLE("Tone Control - Treble", 0)269};270 271static void snd_tea6330_free(struct snd_i2c_device *device)272{273 kfree(device->private_data);274}275 276int snd_tea6330t_update_mixer(struct snd_card *card,277 struct snd_i2c_bus *bus,278 int equalizer, int fader)279{280 struct snd_i2c_device *device;281 struct tea6330t *tea;282 const struct snd_kcontrol_new *knew;283 unsigned int idx;284 int err;285 u8 default_treble, default_bass;286 unsigned char bytes[7];287 288 tea = kzalloc(sizeof(*tea), GFP_KERNEL);289 if (tea == NULL)290 return -ENOMEM;291 err = snd_i2c_device_create(bus, "TEA6330T", TEA6330T_ADDR, &device);292 if (err < 0) {293 kfree(tea);294 return err;295 }296 tea->device = device;297 tea->bus = bus;298 tea->equalizer = equalizer;299 tea->fader = fader;300 device->private_data = tea;301 device->private_free = snd_tea6330_free;302 303 snd_i2c_lock(bus);304 305 /* turn fader off and handle equalizer */306 tea->regs[TEA6330T_SADDR_FADER] = 0x3f;307 tea->regs[TEA6330T_SADDR_AUDIO_SWITCH] = equalizer ? 0 : TEA6330T_EQN;308 /* initialize mixer */309 if (!tea->equalizer) {310 tea->max_bass = 9;311 tea->max_treble = 8;312 default_bass = 3 + 4;313 tea->bass = 4;314 default_treble = 3 + 4;315 tea->treble = 4;316 } else {317 tea->max_bass = 5;318 tea->max_treble = 0;319 default_bass = 7 + 4;320 tea->bass = 4;321 default_treble = 3;322 tea->treble = 0;323 }324 tea->mleft = tea->mright = 0x14;325 tea->regs[TEA6330T_SADDR_BASS] = default_bass;326 tea->regs[TEA6330T_SADDR_TREBLE] = default_treble;327 328 /* compose I2C message and put the hardware to initial state */329 bytes[0] = TEA6330T_SADDR_VOLUME_LEFT;330 for (idx = 0; idx < 6; idx++)331 bytes[idx+1] = tea->regs[idx];332 err = snd_i2c_sendbytes(device, bytes, 7);333 if (err < 0)334 goto __error;335 336 strcat(card->mixername, ",TEA6330T");337 err = snd_component_add(card, "TEA6330T");338 if (err < 0)339 goto __error;340 341 for (idx = 0; idx < ARRAY_SIZE(snd_tea6330t_controls); idx++) {342 knew = &snd_tea6330t_controls[idx];343 if (tea->treble == 0 && !strcmp(knew->name, "Tone Control - Treble"))344 continue;345 err = snd_ctl_add(card, snd_ctl_new1(knew, tea));346 if (err < 0)347 goto __error;348 }349 350 snd_i2c_unlock(bus);351 return 0;352 353 __error:354 snd_i2c_unlock(bus);355 snd_i2c_device_free(device);356 return err;357}358 359EXPORT_SYMBOL(snd_tea6330t_detect);360EXPORT_SYMBOL(snd_tea6330t_update_mixer);361