brintos

brintos / linux-shallow public Read only

0
0
Text · 10.4 KiB · 676d580 Raw
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