cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

tea6330t.c (10724B)


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