18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Routines for control of the TEA6330T circuit via i2c bus 48c2ecf20Sopenharmony_ci * Sound fader control circuit for car radios by Philips Semiconductors 58c2ecf20Sopenharmony_ci * Copyright (c) by Jaroslav Kysela <perex@perex.cz> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/init.h> 98c2ecf20Sopenharmony_ci#include <linux/slab.h> 108c2ecf20Sopenharmony_ci#include <linux/module.h> 118c2ecf20Sopenharmony_ci#include <sound/core.h> 128c2ecf20Sopenharmony_ci#include <sound/control.h> 138c2ecf20Sopenharmony_ci#include <sound/tea6330t.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); 168c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Routines for control of the TEA6330T circuit via i2c bus"); 178c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#define TEA6330T_ADDR (0x80>>1) /* fixed address */ 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#define TEA6330T_SADDR_VOLUME_LEFT 0x00 /* volume left */ 228c2ecf20Sopenharmony_ci#define TEA6330T_SADDR_VOLUME_RIGHT 0x01 /* volume right */ 238c2ecf20Sopenharmony_ci#define TEA6330T_SADDR_BASS 0x02 /* bass control */ 248c2ecf20Sopenharmony_ci#define TEA6330T_SADDR_TREBLE 0x03 /* treble control */ 258c2ecf20Sopenharmony_ci#define TEA6330T_SADDR_FADER 0x04 /* fader control */ 268c2ecf20Sopenharmony_ci#define TEA6330T_MFN 0x20 /* mute control for selected channels */ 278c2ecf20Sopenharmony_ci#define TEA6330T_FCH 0x10 /* select fader channels - front or rear */ 288c2ecf20Sopenharmony_ci#define TEA6330T_SADDR_AUDIO_SWITCH 0x05 /* audio switch */ 298c2ecf20Sopenharmony_ci#define TEA6330T_GMU 0x80 /* mute control, general mute */ 308c2ecf20Sopenharmony_ci#define TEA6330T_EQN 0x40 /* equalizer switchover (0=equalizer-on) */ 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistruct tea6330t { 348c2ecf20Sopenharmony_ci struct snd_i2c_device *device; 358c2ecf20Sopenharmony_ci struct snd_i2c_bus *bus; 368c2ecf20Sopenharmony_ci int equalizer; 378c2ecf20Sopenharmony_ci int fader; 388c2ecf20Sopenharmony_ci unsigned char regs[8]; 398c2ecf20Sopenharmony_ci unsigned char mleft, mright; 408c2ecf20Sopenharmony_ci unsigned char bass, treble; 418c2ecf20Sopenharmony_ci unsigned char max_bass, max_treble; 428c2ecf20Sopenharmony_ci}; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ciint snd_tea6330t_detect(struct snd_i2c_bus *bus, int equalizer) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci int res; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci snd_i2c_lock(bus); 508c2ecf20Sopenharmony_ci res = snd_i2c_probeaddr(bus, TEA6330T_ADDR); 518c2ecf20Sopenharmony_ci snd_i2c_unlock(bus); 528c2ecf20Sopenharmony_ci return res; 538c2ecf20Sopenharmony_ci} 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci#if 0 568c2ecf20Sopenharmony_cistatic void snd_tea6330t_set(struct tea6330t *tea, 578c2ecf20Sopenharmony_ci unsigned char addr, unsigned char value) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci#if 0 608c2ecf20Sopenharmony_ci printk(KERN_DEBUG "set - 0x%x/0x%x\n", addr, value); 618c2ecf20Sopenharmony_ci#endif 628c2ecf20Sopenharmony_ci snd_i2c_write(tea->bus, TEA6330T_ADDR, addr, value, 1); 638c2ecf20Sopenharmony_ci} 648c2ecf20Sopenharmony_ci#endif 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci#define TEA6330T_MASTER_VOLUME(xname, xindex) \ 678c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ 688c2ecf20Sopenharmony_ci .info = snd_tea6330t_info_master_volume, \ 698c2ecf20Sopenharmony_ci .get = snd_tea6330t_get_master_volume, .put = snd_tea6330t_put_master_volume } 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistatic int snd_tea6330t_info_master_volume(struct snd_kcontrol *kcontrol, 728c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 758c2ecf20Sopenharmony_ci uinfo->count = 2; 768c2ecf20Sopenharmony_ci uinfo->value.integer.min = 0; 778c2ecf20Sopenharmony_ci uinfo->value.integer.max = 43; 788c2ecf20Sopenharmony_ci return 0; 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistatic int snd_tea6330t_get_master_volume(struct snd_kcontrol *kcontrol, 828c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci struct tea6330t *tea = snd_kcontrol_chip(kcontrol); 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci snd_i2c_lock(tea->bus); 878c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = tea->mleft - 0x14; 888c2ecf20Sopenharmony_ci ucontrol->value.integer.value[1] = tea->mright - 0x14; 898c2ecf20Sopenharmony_ci snd_i2c_unlock(tea->bus); 908c2ecf20Sopenharmony_ci return 0; 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistatic int snd_tea6330t_put_master_volume(struct snd_kcontrol *kcontrol, 948c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci struct tea6330t *tea = snd_kcontrol_chip(kcontrol); 978c2ecf20Sopenharmony_ci int change, count, err; 988c2ecf20Sopenharmony_ci unsigned char bytes[3]; 998c2ecf20Sopenharmony_ci unsigned char val1, val2; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci val1 = (ucontrol->value.integer.value[0] % 44) + 0x14; 1028c2ecf20Sopenharmony_ci val2 = (ucontrol->value.integer.value[1] % 44) + 0x14; 1038c2ecf20Sopenharmony_ci snd_i2c_lock(tea->bus); 1048c2ecf20Sopenharmony_ci change = val1 != tea->mleft || val2 != tea->mright; 1058c2ecf20Sopenharmony_ci tea->mleft = val1; 1068c2ecf20Sopenharmony_ci tea->mright = val2; 1078c2ecf20Sopenharmony_ci count = 0; 1088c2ecf20Sopenharmony_ci if (tea->regs[TEA6330T_SADDR_VOLUME_LEFT] != 0) { 1098c2ecf20Sopenharmony_ci bytes[count++] = TEA6330T_SADDR_VOLUME_LEFT; 1108c2ecf20Sopenharmony_ci bytes[count++] = tea->regs[TEA6330T_SADDR_VOLUME_LEFT] = tea->mleft; 1118c2ecf20Sopenharmony_ci } 1128c2ecf20Sopenharmony_ci if (tea->regs[TEA6330T_SADDR_VOLUME_RIGHT] != 0) { 1138c2ecf20Sopenharmony_ci if (count == 0) 1148c2ecf20Sopenharmony_ci bytes[count++] = TEA6330T_SADDR_VOLUME_RIGHT; 1158c2ecf20Sopenharmony_ci bytes[count++] = tea->regs[TEA6330T_SADDR_VOLUME_RIGHT] = tea->mright; 1168c2ecf20Sopenharmony_ci } 1178c2ecf20Sopenharmony_ci if (count > 0) { 1188c2ecf20Sopenharmony_ci if ((err = snd_i2c_sendbytes(tea->device, bytes, count)) < 0) 1198c2ecf20Sopenharmony_ci change = err; 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci snd_i2c_unlock(tea->bus); 1228c2ecf20Sopenharmony_ci return change; 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci#define TEA6330T_MASTER_SWITCH(xname, xindex) \ 1268c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ 1278c2ecf20Sopenharmony_ci .info = snd_tea6330t_info_master_switch, \ 1288c2ecf20Sopenharmony_ci .get = snd_tea6330t_get_master_switch, .put = snd_tea6330t_put_master_switch } 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci#define snd_tea6330t_info_master_switch snd_ctl_boolean_stereo_info 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_cistatic int snd_tea6330t_get_master_switch(struct snd_kcontrol *kcontrol, 1338c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 1348c2ecf20Sopenharmony_ci{ 1358c2ecf20Sopenharmony_ci struct tea6330t *tea = snd_kcontrol_chip(kcontrol); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci snd_i2c_lock(tea->bus); 1388c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = tea->regs[TEA6330T_SADDR_VOLUME_LEFT] == 0 ? 0 : 1; 1398c2ecf20Sopenharmony_ci ucontrol->value.integer.value[1] = tea->regs[TEA6330T_SADDR_VOLUME_RIGHT] == 0 ? 0 : 1; 1408c2ecf20Sopenharmony_ci snd_i2c_unlock(tea->bus); 1418c2ecf20Sopenharmony_ci return 0; 1428c2ecf20Sopenharmony_ci} 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_cistatic int snd_tea6330t_put_master_switch(struct snd_kcontrol *kcontrol, 1458c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci struct tea6330t *tea = snd_kcontrol_chip(kcontrol); 1488c2ecf20Sopenharmony_ci int change, err; 1498c2ecf20Sopenharmony_ci unsigned char bytes[3]; 1508c2ecf20Sopenharmony_ci unsigned char oval1, oval2, val1, val2; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci val1 = ucontrol->value.integer.value[0] & 1; 1538c2ecf20Sopenharmony_ci val2 = ucontrol->value.integer.value[1] & 1; 1548c2ecf20Sopenharmony_ci snd_i2c_lock(tea->bus); 1558c2ecf20Sopenharmony_ci oval1 = tea->regs[TEA6330T_SADDR_VOLUME_LEFT] == 0 ? 0 : 1; 1568c2ecf20Sopenharmony_ci oval2 = tea->regs[TEA6330T_SADDR_VOLUME_RIGHT] == 0 ? 0 : 1; 1578c2ecf20Sopenharmony_ci change = val1 != oval1 || val2 != oval2; 1588c2ecf20Sopenharmony_ci tea->regs[TEA6330T_SADDR_VOLUME_LEFT] = val1 ? tea->mleft : 0; 1598c2ecf20Sopenharmony_ci tea->regs[TEA6330T_SADDR_VOLUME_RIGHT] = val2 ? tea->mright : 0; 1608c2ecf20Sopenharmony_ci bytes[0] = TEA6330T_SADDR_VOLUME_LEFT; 1618c2ecf20Sopenharmony_ci bytes[1] = tea->regs[TEA6330T_SADDR_VOLUME_LEFT]; 1628c2ecf20Sopenharmony_ci bytes[2] = tea->regs[TEA6330T_SADDR_VOLUME_RIGHT]; 1638c2ecf20Sopenharmony_ci if ((err = snd_i2c_sendbytes(tea->device, bytes, 3)) < 0) 1648c2ecf20Sopenharmony_ci change = err; 1658c2ecf20Sopenharmony_ci snd_i2c_unlock(tea->bus); 1668c2ecf20Sopenharmony_ci return change; 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci#define TEA6330T_BASS(xname, xindex) \ 1708c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ 1718c2ecf20Sopenharmony_ci .info = snd_tea6330t_info_bass, \ 1728c2ecf20Sopenharmony_ci .get = snd_tea6330t_get_bass, .put = snd_tea6330t_put_bass } 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_cistatic int snd_tea6330t_info_bass(struct snd_kcontrol *kcontrol, 1758c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 1768c2ecf20Sopenharmony_ci{ 1778c2ecf20Sopenharmony_ci struct tea6330t *tea = snd_kcontrol_chip(kcontrol); 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 1808c2ecf20Sopenharmony_ci uinfo->count = 1; 1818c2ecf20Sopenharmony_ci uinfo->value.integer.min = 0; 1828c2ecf20Sopenharmony_ci uinfo->value.integer.max = tea->max_bass; 1838c2ecf20Sopenharmony_ci return 0; 1848c2ecf20Sopenharmony_ci} 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_cistatic int snd_tea6330t_get_bass(struct snd_kcontrol *kcontrol, 1878c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci struct tea6330t *tea = snd_kcontrol_chip(kcontrol); 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = tea->bass; 1928c2ecf20Sopenharmony_ci return 0; 1938c2ecf20Sopenharmony_ci} 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_cistatic int snd_tea6330t_put_bass(struct snd_kcontrol *kcontrol, 1968c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 1978c2ecf20Sopenharmony_ci{ 1988c2ecf20Sopenharmony_ci struct tea6330t *tea = snd_kcontrol_chip(kcontrol); 1998c2ecf20Sopenharmony_ci int change, err; 2008c2ecf20Sopenharmony_ci unsigned char bytes[2]; 2018c2ecf20Sopenharmony_ci unsigned char val1; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci val1 = ucontrol->value.integer.value[0] % (tea->max_bass + 1); 2048c2ecf20Sopenharmony_ci snd_i2c_lock(tea->bus); 2058c2ecf20Sopenharmony_ci tea->bass = val1; 2068c2ecf20Sopenharmony_ci val1 += tea->equalizer ? 7 : 3; 2078c2ecf20Sopenharmony_ci change = tea->regs[TEA6330T_SADDR_BASS] != val1; 2088c2ecf20Sopenharmony_ci bytes[0] = TEA6330T_SADDR_BASS; 2098c2ecf20Sopenharmony_ci bytes[1] = tea->regs[TEA6330T_SADDR_BASS] = val1; 2108c2ecf20Sopenharmony_ci if ((err = snd_i2c_sendbytes(tea->device, bytes, 2)) < 0) 2118c2ecf20Sopenharmony_ci change = err; 2128c2ecf20Sopenharmony_ci snd_i2c_unlock(tea->bus); 2138c2ecf20Sopenharmony_ci return change; 2148c2ecf20Sopenharmony_ci} 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci#define TEA6330T_TREBLE(xname, xindex) \ 2178c2ecf20Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ 2188c2ecf20Sopenharmony_ci .info = snd_tea6330t_info_treble, \ 2198c2ecf20Sopenharmony_ci .get = snd_tea6330t_get_treble, .put = snd_tea6330t_put_treble } 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic int snd_tea6330t_info_treble(struct snd_kcontrol *kcontrol, 2228c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci struct tea6330t *tea = snd_kcontrol_chip(kcontrol); 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 2278c2ecf20Sopenharmony_ci uinfo->count = 1; 2288c2ecf20Sopenharmony_ci uinfo->value.integer.min = 0; 2298c2ecf20Sopenharmony_ci uinfo->value.integer.max = tea->max_treble; 2308c2ecf20Sopenharmony_ci return 0; 2318c2ecf20Sopenharmony_ci} 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_cistatic int snd_tea6330t_get_treble(struct snd_kcontrol *kcontrol, 2348c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 2358c2ecf20Sopenharmony_ci{ 2368c2ecf20Sopenharmony_ci struct tea6330t *tea = snd_kcontrol_chip(kcontrol); 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = tea->treble; 2398c2ecf20Sopenharmony_ci return 0; 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_cistatic int snd_tea6330t_put_treble(struct snd_kcontrol *kcontrol, 2438c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 2448c2ecf20Sopenharmony_ci{ 2458c2ecf20Sopenharmony_ci struct tea6330t *tea = snd_kcontrol_chip(kcontrol); 2468c2ecf20Sopenharmony_ci int change, err; 2478c2ecf20Sopenharmony_ci unsigned char bytes[2]; 2488c2ecf20Sopenharmony_ci unsigned char val1; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci val1 = ucontrol->value.integer.value[0] % (tea->max_treble + 1); 2518c2ecf20Sopenharmony_ci snd_i2c_lock(tea->bus); 2528c2ecf20Sopenharmony_ci tea->treble = val1; 2538c2ecf20Sopenharmony_ci val1 += 3; 2548c2ecf20Sopenharmony_ci change = tea->regs[TEA6330T_SADDR_TREBLE] != val1; 2558c2ecf20Sopenharmony_ci bytes[0] = TEA6330T_SADDR_TREBLE; 2568c2ecf20Sopenharmony_ci bytes[1] = tea->regs[TEA6330T_SADDR_TREBLE] = val1; 2578c2ecf20Sopenharmony_ci if ((err = snd_i2c_sendbytes(tea->device, bytes, 2)) < 0) 2588c2ecf20Sopenharmony_ci change = err; 2598c2ecf20Sopenharmony_ci snd_i2c_unlock(tea->bus); 2608c2ecf20Sopenharmony_ci return change; 2618c2ecf20Sopenharmony_ci} 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_tea6330t_controls[] = { 2648c2ecf20Sopenharmony_ciTEA6330T_MASTER_SWITCH("Master Playback Switch", 0), 2658c2ecf20Sopenharmony_ciTEA6330T_MASTER_VOLUME("Master Playback Volume", 0), 2668c2ecf20Sopenharmony_ciTEA6330T_BASS("Tone Control - Bass", 0), 2678c2ecf20Sopenharmony_ciTEA6330T_TREBLE("Tone Control - Treble", 0) 2688c2ecf20Sopenharmony_ci}; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_cistatic void snd_tea6330_free(struct snd_i2c_device *device) 2718c2ecf20Sopenharmony_ci{ 2728c2ecf20Sopenharmony_ci kfree(device->private_data); 2738c2ecf20Sopenharmony_ci} 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ciint snd_tea6330t_update_mixer(struct snd_card *card, 2768c2ecf20Sopenharmony_ci struct snd_i2c_bus *bus, 2778c2ecf20Sopenharmony_ci int equalizer, int fader) 2788c2ecf20Sopenharmony_ci{ 2798c2ecf20Sopenharmony_ci struct snd_i2c_device *device; 2808c2ecf20Sopenharmony_ci struct tea6330t *tea; 2818c2ecf20Sopenharmony_ci const struct snd_kcontrol_new *knew; 2828c2ecf20Sopenharmony_ci unsigned int idx; 2838c2ecf20Sopenharmony_ci int err = -ENOMEM; 2848c2ecf20Sopenharmony_ci u8 default_treble, default_bass; 2858c2ecf20Sopenharmony_ci unsigned char bytes[7]; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci tea = kzalloc(sizeof(*tea), GFP_KERNEL); 2888c2ecf20Sopenharmony_ci if (tea == NULL) 2898c2ecf20Sopenharmony_ci return -ENOMEM; 2908c2ecf20Sopenharmony_ci if ((err = snd_i2c_device_create(bus, "TEA6330T", TEA6330T_ADDR, &device)) < 0) { 2918c2ecf20Sopenharmony_ci kfree(tea); 2928c2ecf20Sopenharmony_ci return err; 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci tea->device = device; 2958c2ecf20Sopenharmony_ci tea->bus = bus; 2968c2ecf20Sopenharmony_ci tea->equalizer = equalizer; 2978c2ecf20Sopenharmony_ci tea->fader = fader; 2988c2ecf20Sopenharmony_ci device->private_data = tea; 2998c2ecf20Sopenharmony_ci device->private_free = snd_tea6330_free; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci snd_i2c_lock(bus); 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci /* turn fader off and handle equalizer */ 3048c2ecf20Sopenharmony_ci tea->regs[TEA6330T_SADDR_FADER] = 0x3f; 3058c2ecf20Sopenharmony_ci tea->regs[TEA6330T_SADDR_AUDIO_SWITCH] = equalizer ? 0 : TEA6330T_EQN; 3068c2ecf20Sopenharmony_ci /* initialize mixer */ 3078c2ecf20Sopenharmony_ci if (!tea->equalizer) { 3088c2ecf20Sopenharmony_ci tea->max_bass = 9; 3098c2ecf20Sopenharmony_ci tea->max_treble = 8; 3108c2ecf20Sopenharmony_ci default_bass = 3 + 4; 3118c2ecf20Sopenharmony_ci tea->bass = 4; 3128c2ecf20Sopenharmony_ci default_treble = 3 + 4; 3138c2ecf20Sopenharmony_ci tea->treble = 4; 3148c2ecf20Sopenharmony_ci } else { 3158c2ecf20Sopenharmony_ci tea->max_bass = 5; 3168c2ecf20Sopenharmony_ci tea->max_treble = 0; 3178c2ecf20Sopenharmony_ci default_bass = 7 + 4; 3188c2ecf20Sopenharmony_ci tea->bass = 4; 3198c2ecf20Sopenharmony_ci default_treble = 3; 3208c2ecf20Sopenharmony_ci tea->treble = 0; 3218c2ecf20Sopenharmony_ci } 3228c2ecf20Sopenharmony_ci tea->mleft = tea->mright = 0x14; 3238c2ecf20Sopenharmony_ci tea->regs[TEA6330T_SADDR_BASS] = default_bass; 3248c2ecf20Sopenharmony_ci tea->regs[TEA6330T_SADDR_TREBLE] = default_treble; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci /* compose I2C message and put the hardware to initial state */ 3278c2ecf20Sopenharmony_ci bytes[0] = TEA6330T_SADDR_VOLUME_LEFT; 3288c2ecf20Sopenharmony_ci for (idx = 0; idx < 6; idx++) 3298c2ecf20Sopenharmony_ci bytes[idx+1] = tea->regs[idx]; 3308c2ecf20Sopenharmony_ci if ((err = snd_i2c_sendbytes(device, bytes, 7)) < 0) 3318c2ecf20Sopenharmony_ci goto __error; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci strcat(card->mixername, ",TEA6330T"); 3348c2ecf20Sopenharmony_ci if ((err = snd_component_add(card, "TEA6330T")) < 0) 3358c2ecf20Sopenharmony_ci goto __error; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci for (idx = 0; idx < ARRAY_SIZE(snd_tea6330t_controls); idx++) { 3388c2ecf20Sopenharmony_ci knew = &snd_tea6330t_controls[idx]; 3398c2ecf20Sopenharmony_ci if (tea->treble == 0 && !strcmp(knew->name, "Tone Control - Treble")) 3408c2ecf20Sopenharmony_ci continue; 3418c2ecf20Sopenharmony_ci if ((err = snd_ctl_add(card, snd_ctl_new1(knew, tea))) < 0) 3428c2ecf20Sopenharmony_ci goto __error; 3438c2ecf20Sopenharmony_ci } 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci snd_i2c_unlock(bus); 3468c2ecf20Sopenharmony_ci return 0; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci __error: 3498c2ecf20Sopenharmony_ci snd_i2c_unlock(bus); 3508c2ecf20Sopenharmony_ci snd_i2c_device_free(device); 3518c2ecf20Sopenharmony_ci return err; 3528c2ecf20Sopenharmony_ci} 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_tea6330t_detect); 3558c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_tea6330t_update_mixer); 356