1cb7a01acSMauro Carvalho Chehab /* 2cb7a01acSMauro Carvalho Chehab * For the STS-Thompson TDA7432 audio processor chip 3cb7a01acSMauro Carvalho Chehab * 4cb7a01acSMauro Carvalho Chehab * Handles audio functions: volume, balance, tone, loudness 5cb7a01acSMauro Carvalho Chehab * This driver will not complain if used with any 6cb7a01acSMauro Carvalho Chehab * other i2c device with the same address. 7cb7a01acSMauro Carvalho Chehab * 8cb7a01acSMauro Carvalho Chehab * Muting and tone control by Jonathan Isom <jisom@ematic.com> 9cb7a01acSMauro Carvalho Chehab * 10cb7a01acSMauro Carvalho Chehab * Copyright (c) 2000 Eric Sandeen <eric_sandeen@bigfoot.com> 11cb7a01acSMauro Carvalho Chehab * Copyright (c) 2006 Mauro Carvalho Chehab <mchehab@infradead.org> 12cb7a01acSMauro Carvalho Chehab * This code is placed under the terms of the GNU General Public License 13cb7a01acSMauro Carvalho Chehab * Based on tda9855.c by Steve VanDeBogart (vandebo@uclink.berkeley.edu) 14cb7a01acSMauro Carvalho Chehab * Which was based on tda8425.c by Greg Alexander (c) 1998 15cb7a01acSMauro Carvalho Chehab * 16cb7a01acSMauro Carvalho Chehab * OPTIONS: 17cb7a01acSMauro Carvalho Chehab * debug - set to 1 if you'd like to see debug messages 18cb7a01acSMauro Carvalho Chehab * set to 2 if you'd like to be inundated with debug messages 19cb7a01acSMauro Carvalho Chehab * 20cb7a01acSMauro Carvalho Chehab * loudness - set between 0 and 15 for varying degrees of loudness effect 21cb7a01acSMauro Carvalho Chehab * 22cb7a01acSMauro Carvalho Chehab * maxvol - set maximium volume to +20db (1), default is 0db(0) 23cb7a01acSMauro Carvalho Chehab */ 24cb7a01acSMauro Carvalho Chehab 25cb7a01acSMauro Carvalho Chehab #include <linux/module.h> 26cb7a01acSMauro Carvalho Chehab #include <linux/init.h> 27cb7a01acSMauro Carvalho Chehab #include <linux/kernel.h> 28cb7a01acSMauro Carvalho Chehab #include <linux/string.h> 29cb7a01acSMauro Carvalho Chehab #include <linux/timer.h> 30cb7a01acSMauro Carvalho Chehab #include <linux/delay.h> 31cb7a01acSMauro Carvalho Chehab #include <linux/errno.h> 32cb7a01acSMauro Carvalho Chehab #include <linux/slab.h> 33cb7a01acSMauro Carvalho Chehab #include <linux/videodev2.h> 34cb7a01acSMauro Carvalho Chehab #include <linux/i2c.h> 35cb7a01acSMauro Carvalho Chehab 36cb7a01acSMauro Carvalho Chehab #include <media/v4l2-device.h> 37cb7a01acSMauro Carvalho Chehab #include <media/v4l2-ioctl.h> 38cb7a01acSMauro Carvalho Chehab #include <media/i2c-addr.h> 39cb7a01acSMauro Carvalho Chehab 40cb7a01acSMauro Carvalho Chehab #ifndef VIDEO_AUDIO_BALANCE 41cb7a01acSMauro Carvalho Chehab # define VIDEO_AUDIO_BALANCE 32 42cb7a01acSMauro Carvalho Chehab #endif 43cb7a01acSMauro Carvalho Chehab 44cb7a01acSMauro Carvalho Chehab MODULE_AUTHOR("Eric Sandeen <eric_sandeen@bigfoot.com>"); 45cb7a01acSMauro Carvalho Chehab MODULE_DESCRIPTION("bttv driver for the tda7432 audio processor chip"); 46cb7a01acSMauro Carvalho Chehab MODULE_LICENSE("GPL"); 47cb7a01acSMauro Carvalho Chehab 48cb7a01acSMauro Carvalho Chehab static int maxvol; 49cb7a01acSMauro Carvalho Chehab static int loudness; /* disable loudness by default */ 50cb7a01acSMauro Carvalho Chehab static int debug; /* insmod parameter */ 51cb7a01acSMauro Carvalho Chehab module_param(debug, int, S_IRUGO | S_IWUSR); 52cb7a01acSMauro Carvalho Chehab MODULE_PARM_DESC(debug, "Set debugging level from 0 to 3. Default is off(0)."); 53cb7a01acSMauro Carvalho Chehab module_param(loudness, int, S_IRUGO); 54cb7a01acSMauro Carvalho Chehab MODULE_PARM_DESC(loudness, "Turn loudness on(1) else off(0). Default is off(0)."); 55cb7a01acSMauro Carvalho Chehab module_param(maxvol, int, S_IRUGO | S_IWUSR); 56cb7a01acSMauro Carvalho Chehab MODULE_PARM_DESC(maxvol, "Set maximium volume to +20dB(0) else +0dB(1). Default is +20dB(0)."); 57cb7a01acSMauro Carvalho Chehab 58cb7a01acSMauro Carvalho Chehab 59cb7a01acSMauro Carvalho Chehab /* Structure of address and subaddresses for the tda7432 */ 60cb7a01acSMauro Carvalho Chehab 61cb7a01acSMauro Carvalho Chehab struct tda7432 { 62cb7a01acSMauro Carvalho Chehab struct v4l2_subdev sd; 63cb7a01acSMauro Carvalho Chehab int addr; 64cb7a01acSMauro Carvalho Chehab int input; 65cb7a01acSMauro Carvalho Chehab int volume; 66cb7a01acSMauro Carvalho Chehab int muted; 67cb7a01acSMauro Carvalho Chehab int bass, treble; 68cb7a01acSMauro Carvalho Chehab int lf, lr, rf, rr; 69cb7a01acSMauro Carvalho Chehab int loud; 70cb7a01acSMauro Carvalho Chehab }; 71cb7a01acSMauro Carvalho Chehab 72cb7a01acSMauro Carvalho Chehab static inline struct tda7432 *to_state(struct v4l2_subdev *sd) 73cb7a01acSMauro Carvalho Chehab { 74cb7a01acSMauro Carvalho Chehab return container_of(sd, struct tda7432, sd); 75cb7a01acSMauro Carvalho Chehab } 76cb7a01acSMauro Carvalho Chehab 77cb7a01acSMauro Carvalho Chehab /* The TDA7432 is made by STS-Thompson 78cb7a01acSMauro Carvalho Chehab * http://www.st.com 79cb7a01acSMauro Carvalho Chehab * http://us.st.com/stonline/books/pdf/docs/4056.pdf 80cb7a01acSMauro Carvalho Chehab * 81cb7a01acSMauro Carvalho Chehab * TDA7432: I2C-bus controlled basic audio processor 82cb7a01acSMauro Carvalho Chehab * 83cb7a01acSMauro Carvalho Chehab * The TDA7432 controls basic audio functions like volume, balance, 84cb7a01acSMauro Carvalho Chehab * and tone control (including loudness). It also has four channel 85cb7a01acSMauro Carvalho Chehab * output (for front and rear). Since most vidcap cards probably 86cb7a01acSMauro Carvalho Chehab * don't have 4 channel output, this driver will set front & rear 87cb7a01acSMauro Carvalho Chehab * together (no independent control). 88cb7a01acSMauro Carvalho Chehab */ 89cb7a01acSMauro Carvalho Chehab 90cb7a01acSMauro Carvalho Chehab /* Subaddresses for TDA7432 */ 91cb7a01acSMauro Carvalho Chehab 92cb7a01acSMauro Carvalho Chehab #define TDA7432_IN 0x00 /* Input select */ 93cb7a01acSMauro Carvalho Chehab #define TDA7432_VL 0x01 /* Volume */ 94cb7a01acSMauro Carvalho Chehab #define TDA7432_TN 0x02 /* Bass, Treble (Tone) */ 95cb7a01acSMauro Carvalho Chehab #define TDA7432_LF 0x03 /* Attenuation LF (Left Front) */ 96cb7a01acSMauro Carvalho Chehab #define TDA7432_LR 0x04 /* Attenuation LR (Left Rear) */ 97cb7a01acSMauro Carvalho Chehab #define TDA7432_RF 0x05 /* Attenuation RF (Right Front) */ 98cb7a01acSMauro Carvalho Chehab #define TDA7432_RR 0x06 /* Attenuation RR (Right Rear) */ 99cb7a01acSMauro Carvalho Chehab #define TDA7432_LD 0x07 /* Loudness */ 100cb7a01acSMauro Carvalho Chehab 101cb7a01acSMauro Carvalho Chehab 102cb7a01acSMauro Carvalho Chehab /* Masks for bits in TDA7432 subaddresses */ 103cb7a01acSMauro Carvalho Chehab 104cb7a01acSMauro Carvalho Chehab /* Many of these not used - just for documentation */ 105cb7a01acSMauro Carvalho Chehab 106cb7a01acSMauro Carvalho Chehab /* Subaddress 0x00 - Input selection and bass control */ 107cb7a01acSMauro Carvalho Chehab 108cb7a01acSMauro Carvalho Chehab /* Bits 0,1,2 control input: 109cb7a01acSMauro Carvalho Chehab * 0x00 - Stereo input 110cb7a01acSMauro Carvalho Chehab * 0x02 - Mono input 111cb7a01acSMauro Carvalho Chehab * 0x03 - Mute (Using Attenuators Plays better with modules) 112cb7a01acSMauro Carvalho Chehab * Mono probably isn't used - I'm guessing only the stereo 113cb7a01acSMauro Carvalho Chehab * input is connected on most cards, so we'll set it to stereo. 114cb7a01acSMauro Carvalho Chehab * 115cb7a01acSMauro Carvalho Chehab * Bit 3 controls bass cut: 0/1 is non-symmetric/symmetric bass cut 116cb7a01acSMauro Carvalho Chehab * Bit 4 controls bass range: 0/1 is extended/standard bass range 117cb7a01acSMauro Carvalho Chehab * 118cb7a01acSMauro Carvalho Chehab * Highest 3 bits not used 119cb7a01acSMauro Carvalho Chehab */ 120cb7a01acSMauro Carvalho Chehab 121cb7a01acSMauro Carvalho Chehab #define TDA7432_STEREO_IN 0 122cb7a01acSMauro Carvalho Chehab #define TDA7432_MONO_IN 2 /* Probably won't be used */ 123cb7a01acSMauro Carvalho Chehab #define TDA7432_BASS_SYM 1 << 3 124cb7a01acSMauro Carvalho Chehab #define TDA7432_BASS_NORM 1 << 4 125cb7a01acSMauro Carvalho Chehab 126cb7a01acSMauro Carvalho Chehab /* Subaddress 0x01 - Volume */ 127cb7a01acSMauro Carvalho Chehab 128cb7a01acSMauro Carvalho Chehab /* Lower 7 bits control volume from -79dB to +32dB in 1dB steps 129cb7a01acSMauro Carvalho Chehab * Recommended maximum is +20 dB 130cb7a01acSMauro Carvalho Chehab * 131cb7a01acSMauro Carvalho Chehab * +32dB: 0x00 132cb7a01acSMauro Carvalho Chehab * +20dB: 0x0c 133cb7a01acSMauro Carvalho Chehab * 0dB: 0x20 134cb7a01acSMauro Carvalho Chehab * -79dB: 0x6f 135cb7a01acSMauro Carvalho Chehab * 136cb7a01acSMauro Carvalho Chehab * MSB (bit 7) controls loudness: 1/0 is loudness on/off 137cb7a01acSMauro Carvalho Chehab */ 138cb7a01acSMauro Carvalho Chehab 139cb7a01acSMauro Carvalho Chehab #define TDA7432_VOL_0DB 0x20 140cb7a01acSMauro Carvalho Chehab #define TDA7432_LD_ON 1 << 7 141cb7a01acSMauro Carvalho Chehab 142cb7a01acSMauro Carvalho Chehab 143cb7a01acSMauro Carvalho Chehab /* Subaddress 0x02 - Tone control */ 144cb7a01acSMauro Carvalho Chehab 145cb7a01acSMauro Carvalho Chehab /* Bits 0,1,2 control absolute treble gain from 0dB to 14dB 146cb7a01acSMauro Carvalho Chehab * 0x0 is 14dB, 0x7 is 0dB 147cb7a01acSMauro Carvalho Chehab * 148cb7a01acSMauro Carvalho Chehab * Bit 3 controls treble attenuation/gain (sign) 149cb7a01acSMauro Carvalho Chehab * 1 = gain (+) 150cb7a01acSMauro Carvalho Chehab * 0 = attenuation (-) 151cb7a01acSMauro Carvalho Chehab * 152cb7a01acSMauro Carvalho Chehab * Bits 4,5,6 control absolute bass gain from 0dB to 14dB 153cb7a01acSMauro Carvalho Chehab * (This is only true for normal base range, set in 0x00) 154cb7a01acSMauro Carvalho Chehab * 0x0 << 4 is 14dB, 0x7 is 0dB 155cb7a01acSMauro Carvalho Chehab * 156cb7a01acSMauro Carvalho Chehab * Bit 7 controls bass attenuation/gain (sign) 157cb7a01acSMauro Carvalho Chehab * 1 << 7 = gain (+) 158cb7a01acSMauro Carvalho Chehab * 0 << 7 = attenuation (-) 159cb7a01acSMauro Carvalho Chehab * 160cb7a01acSMauro Carvalho Chehab * Example: 161cb7a01acSMauro Carvalho Chehab * 1 1 0 1 0 1 0 1 is +4dB bass, -4dB treble 162cb7a01acSMauro Carvalho Chehab */ 163cb7a01acSMauro Carvalho Chehab 164cb7a01acSMauro Carvalho Chehab #define TDA7432_TREBLE_0DB 0xf 165cb7a01acSMauro Carvalho Chehab #define TDA7432_TREBLE 7 166cb7a01acSMauro Carvalho Chehab #define TDA7432_TREBLE_GAIN 1 << 3 167cb7a01acSMauro Carvalho Chehab #define TDA7432_BASS_0DB 0xf 168cb7a01acSMauro Carvalho Chehab #define TDA7432_BASS 7 << 4 169cb7a01acSMauro Carvalho Chehab #define TDA7432_BASS_GAIN 1 << 7 170cb7a01acSMauro Carvalho Chehab 171cb7a01acSMauro Carvalho Chehab 172cb7a01acSMauro Carvalho Chehab /* Subaddress 0x03 - Left Front attenuation */ 173cb7a01acSMauro Carvalho Chehab /* Subaddress 0x04 - Left Rear attenuation */ 174cb7a01acSMauro Carvalho Chehab /* Subaddress 0x05 - Right Front attenuation */ 175cb7a01acSMauro Carvalho Chehab /* Subaddress 0x06 - Right Rear attenuation */ 176cb7a01acSMauro Carvalho Chehab 177cb7a01acSMauro Carvalho Chehab /* Bits 0,1,2,3,4 control attenuation from 0dB to -37.5dB 178cb7a01acSMauro Carvalho Chehab * in 1.5dB steps. 179cb7a01acSMauro Carvalho Chehab * 180cb7a01acSMauro Carvalho Chehab * 0x00 is 0dB 181cb7a01acSMauro Carvalho Chehab * 0x1f is -37.5dB 182cb7a01acSMauro Carvalho Chehab * 183cb7a01acSMauro Carvalho Chehab * Bit 5 mutes that channel when set (1 = mute, 0 = unmute) 184cb7a01acSMauro Carvalho Chehab * We'll use the mute on the input, though (above) 185cb7a01acSMauro Carvalho Chehab * Bits 6,7 unused 186cb7a01acSMauro Carvalho Chehab */ 187cb7a01acSMauro Carvalho Chehab 188cb7a01acSMauro Carvalho Chehab #define TDA7432_ATTEN_0DB 0x00 189cb7a01acSMauro Carvalho Chehab #define TDA7432_MUTE 0x1 << 5 190cb7a01acSMauro Carvalho Chehab 191cb7a01acSMauro Carvalho Chehab 192cb7a01acSMauro Carvalho Chehab /* Subaddress 0x07 - Loudness Control */ 193cb7a01acSMauro Carvalho Chehab 194cb7a01acSMauro Carvalho Chehab /* Bits 0,1,2,3 control loudness from 0dB to -15dB in 1dB steps 195cb7a01acSMauro Carvalho Chehab * when bit 4 is NOT set 196cb7a01acSMauro Carvalho Chehab * 197cb7a01acSMauro Carvalho Chehab * 0x0 is 0dB 198cb7a01acSMauro Carvalho Chehab * 0xf is -15dB 199cb7a01acSMauro Carvalho Chehab * 200cb7a01acSMauro Carvalho Chehab * If bit 4 is set, then there is a flat attenuation according to 201cb7a01acSMauro Carvalho Chehab * the lower 4 bits, as above. 202cb7a01acSMauro Carvalho Chehab * 203cb7a01acSMauro Carvalho Chehab * Bits 5,6,7 unused 204cb7a01acSMauro Carvalho Chehab */ 205cb7a01acSMauro Carvalho Chehab 206cb7a01acSMauro Carvalho Chehab 207cb7a01acSMauro Carvalho Chehab 208cb7a01acSMauro Carvalho Chehab /* Begin code */ 209cb7a01acSMauro Carvalho Chehab 210cb7a01acSMauro Carvalho Chehab static int tda7432_write(struct v4l2_subdev *sd, int subaddr, int val) 211cb7a01acSMauro Carvalho Chehab { 212cb7a01acSMauro Carvalho Chehab struct i2c_client *client = v4l2_get_subdevdata(sd); 213cb7a01acSMauro Carvalho Chehab unsigned char buffer[2]; 214cb7a01acSMauro Carvalho Chehab 215cb7a01acSMauro Carvalho Chehab v4l2_dbg(2, debug, sd, "In tda7432_write\n"); 216cb7a01acSMauro Carvalho Chehab v4l2_dbg(1, debug, sd, "Writing %d 0x%x\n", subaddr, val); 217cb7a01acSMauro Carvalho Chehab buffer[0] = subaddr; 218cb7a01acSMauro Carvalho Chehab buffer[1] = val; 219cb7a01acSMauro Carvalho Chehab if (2 != i2c_master_send(client, buffer, 2)) { 220cb7a01acSMauro Carvalho Chehab v4l2_err(sd, "I/O error, trying (write %d 0x%x)\n", 221cb7a01acSMauro Carvalho Chehab subaddr, val); 222cb7a01acSMauro Carvalho Chehab return -1; 223cb7a01acSMauro Carvalho Chehab } 224cb7a01acSMauro Carvalho Chehab return 0; 225cb7a01acSMauro Carvalho Chehab } 226cb7a01acSMauro Carvalho Chehab 227cb7a01acSMauro Carvalho Chehab static int tda7432_set(struct v4l2_subdev *sd) 228cb7a01acSMauro Carvalho Chehab { 229cb7a01acSMauro Carvalho Chehab struct i2c_client *client = v4l2_get_subdevdata(sd); 230cb7a01acSMauro Carvalho Chehab struct tda7432 *t = to_state(sd); 231cb7a01acSMauro Carvalho Chehab unsigned char buf[16]; 232cb7a01acSMauro Carvalho Chehab 233cb7a01acSMauro Carvalho Chehab v4l2_dbg(1, debug, sd, 234cb7a01acSMauro Carvalho Chehab "tda7432: 7432_set(0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)\n", 235cb7a01acSMauro Carvalho Chehab t->input, t->volume, t->bass, t->treble, t->lf, t->lr, 236cb7a01acSMauro Carvalho Chehab t->rf, t->rr, t->loud); 237cb7a01acSMauro Carvalho Chehab buf[0] = TDA7432_IN; 238cb7a01acSMauro Carvalho Chehab buf[1] = t->input; 239cb7a01acSMauro Carvalho Chehab buf[2] = t->volume; 240cb7a01acSMauro Carvalho Chehab buf[3] = t->bass; 241cb7a01acSMauro Carvalho Chehab buf[4] = t->treble; 242cb7a01acSMauro Carvalho Chehab buf[5] = t->lf; 243cb7a01acSMauro Carvalho Chehab buf[6] = t->lr; 244cb7a01acSMauro Carvalho Chehab buf[7] = t->rf; 245cb7a01acSMauro Carvalho Chehab buf[8] = t->rr; 246cb7a01acSMauro Carvalho Chehab buf[9] = t->loud; 247cb7a01acSMauro Carvalho Chehab if (10 != i2c_master_send(client, buf, 10)) { 248cb7a01acSMauro Carvalho Chehab v4l2_err(sd, "I/O error, trying tda7432_set\n"); 249cb7a01acSMauro Carvalho Chehab return -1; 250cb7a01acSMauro Carvalho Chehab } 251cb7a01acSMauro Carvalho Chehab 252cb7a01acSMauro Carvalho Chehab return 0; 253cb7a01acSMauro Carvalho Chehab } 254cb7a01acSMauro Carvalho Chehab 255cb7a01acSMauro Carvalho Chehab static void do_tda7432_init(struct v4l2_subdev *sd) 256cb7a01acSMauro Carvalho Chehab { 257cb7a01acSMauro Carvalho Chehab struct tda7432 *t = to_state(sd); 258cb7a01acSMauro Carvalho Chehab 259cb7a01acSMauro Carvalho Chehab v4l2_dbg(2, debug, sd, "In tda7432_init\n"); 260cb7a01acSMauro Carvalho Chehab 261cb7a01acSMauro Carvalho Chehab t->input = TDA7432_STEREO_IN | /* Main (stereo) input */ 262cb7a01acSMauro Carvalho Chehab TDA7432_BASS_SYM | /* Symmetric bass cut */ 263cb7a01acSMauro Carvalho Chehab TDA7432_BASS_NORM; /* Normal bass range */ 264cb7a01acSMauro Carvalho Chehab t->volume = 0x3b ; /* -27dB Volume */ 265cb7a01acSMauro Carvalho Chehab if (loudness) /* Turn loudness on? */ 266cb7a01acSMauro Carvalho Chehab t->volume |= TDA7432_LD_ON; 267cb7a01acSMauro Carvalho Chehab t->muted = 1; 268cb7a01acSMauro Carvalho Chehab t->treble = TDA7432_TREBLE_0DB; /* 0dB Treble */ 269cb7a01acSMauro Carvalho Chehab t->bass = TDA7432_BASS_0DB; /* 0dB Bass */ 270cb7a01acSMauro Carvalho Chehab t->lf = TDA7432_ATTEN_0DB; /* 0dB attenuation */ 271cb7a01acSMauro Carvalho Chehab t->lr = TDA7432_ATTEN_0DB; /* 0dB attenuation */ 272cb7a01acSMauro Carvalho Chehab t->rf = TDA7432_ATTEN_0DB; /* 0dB attenuation */ 273cb7a01acSMauro Carvalho Chehab t->rr = TDA7432_ATTEN_0DB; /* 0dB attenuation */ 274cb7a01acSMauro Carvalho Chehab t->loud = loudness; /* insmod parameter */ 275cb7a01acSMauro Carvalho Chehab 276cb7a01acSMauro Carvalho Chehab tda7432_set(sd); 277cb7a01acSMauro Carvalho Chehab } 278cb7a01acSMauro Carvalho Chehab 279cb7a01acSMauro Carvalho Chehab static int tda7432_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) 280cb7a01acSMauro Carvalho Chehab { 281cb7a01acSMauro Carvalho Chehab struct tda7432 *t = to_state(sd); 282cb7a01acSMauro Carvalho Chehab 283cb7a01acSMauro Carvalho Chehab switch (ctrl->id) { 284cb7a01acSMauro Carvalho Chehab case V4L2_CID_AUDIO_MUTE: 285cb7a01acSMauro Carvalho Chehab ctrl->value=t->muted; 286cb7a01acSMauro Carvalho Chehab return 0; 287cb7a01acSMauro Carvalho Chehab case V4L2_CID_AUDIO_VOLUME: 288cb7a01acSMauro Carvalho Chehab if (!maxvol){ /* max +20db */ 289cb7a01acSMauro Carvalho Chehab ctrl->value = ( 0x6f - (t->volume & 0x7F) ) * 630; 290cb7a01acSMauro Carvalho Chehab } else { /* max 0db */ 291cb7a01acSMauro Carvalho Chehab ctrl->value = ( 0x6f - (t->volume & 0x7F) ) * 829; 292cb7a01acSMauro Carvalho Chehab } 293cb7a01acSMauro Carvalho Chehab return 0; 294cb7a01acSMauro Carvalho Chehab case V4L2_CID_AUDIO_BALANCE: 295cb7a01acSMauro Carvalho Chehab { 296cb7a01acSMauro Carvalho Chehab if ( (t->lf) < (t->rf) ) 297cb7a01acSMauro Carvalho Chehab /* right is attenuated, balance shifted left */ 298cb7a01acSMauro Carvalho Chehab ctrl->value = (32768 - 1057*(t->rf)); 299cb7a01acSMauro Carvalho Chehab else 300cb7a01acSMauro Carvalho Chehab /* left is attenuated, balance shifted right */ 301cb7a01acSMauro Carvalho Chehab ctrl->value = (32768 + 1057*(t->lf)); 302cb7a01acSMauro Carvalho Chehab return 0; 303cb7a01acSMauro Carvalho Chehab } 304cb7a01acSMauro Carvalho Chehab case V4L2_CID_AUDIO_BASS: 305cb7a01acSMauro Carvalho Chehab { 306cb7a01acSMauro Carvalho Chehab /* Bass/treble 4 bits each */ 307cb7a01acSMauro Carvalho Chehab int bass=t->bass; 308cb7a01acSMauro Carvalho Chehab if(bass >= 0x8) 309cb7a01acSMauro Carvalho Chehab bass = ~(bass - 0x8) & 0xf; 310cb7a01acSMauro Carvalho Chehab ctrl->value = (bass << 12)+(bass << 8)+(bass << 4)+(bass); 311cb7a01acSMauro Carvalho Chehab return 0; 312cb7a01acSMauro Carvalho Chehab } 313cb7a01acSMauro Carvalho Chehab case V4L2_CID_AUDIO_TREBLE: 314cb7a01acSMauro Carvalho Chehab { 315cb7a01acSMauro Carvalho Chehab int treble=t->treble; 316cb7a01acSMauro Carvalho Chehab if(treble >= 0x8) 317cb7a01acSMauro Carvalho Chehab treble = ~(treble - 0x8) & 0xf; 318cb7a01acSMauro Carvalho Chehab ctrl->value = (treble << 12)+(treble << 8)+(treble << 4)+(treble); 319cb7a01acSMauro Carvalho Chehab return 0; 320cb7a01acSMauro Carvalho Chehab } 321cb7a01acSMauro Carvalho Chehab } 322cb7a01acSMauro Carvalho Chehab return -EINVAL; 323cb7a01acSMauro Carvalho Chehab } 324cb7a01acSMauro Carvalho Chehab 325cb7a01acSMauro Carvalho Chehab static int tda7432_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) 326cb7a01acSMauro Carvalho Chehab { 327cb7a01acSMauro Carvalho Chehab struct tda7432 *t = to_state(sd); 328cb7a01acSMauro Carvalho Chehab 329cb7a01acSMauro Carvalho Chehab switch (ctrl->id) { 330cb7a01acSMauro Carvalho Chehab case V4L2_CID_AUDIO_MUTE: 331cb7a01acSMauro Carvalho Chehab t->muted=ctrl->value; 332cb7a01acSMauro Carvalho Chehab break; 333cb7a01acSMauro Carvalho Chehab case V4L2_CID_AUDIO_VOLUME: 334cb7a01acSMauro Carvalho Chehab if(!maxvol){ /* max +20db */ 335cb7a01acSMauro Carvalho Chehab t->volume = 0x6f - ((ctrl->value)/630); 336cb7a01acSMauro Carvalho Chehab } else { /* max 0db */ 337cb7a01acSMauro Carvalho Chehab t->volume = 0x6f - ((ctrl->value)/829); 338cb7a01acSMauro Carvalho Chehab } 339cb7a01acSMauro Carvalho Chehab if (loudness) /* Turn on the loudness bit */ 340cb7a01acSMauro Carvalho Chehab t->volume |= TDA7432_LD_ON; 341cb7a01acSMauro Carvalho Chehab 342cb7a01acSMauro Carvalho Chehab tda7432_write(sd, TDA7432_VL, t->volume); 343cb7a01acSMauro Carvalho Chehab return 0; 344cb7a01acSMauro Carvalho Chehab case V4L2_CID_AUDIO_BALANCE: 345cb7a01acSMauro Carvalho Chehab if (ctrl->value < 32768) { 346cb7a01acSMauro Carvalho Chehab /* shifted to left, attenuate right */ 347cb7a01acSMauro Carvalho Chehab t->rr = (32768 - ctrl->value)/1057; 348cb7a01acSMauro Carvalho Chehab t->rf = t->rr; 349cb7a01acSMauro Carvalho Chehab t->lr = TDA7432_ATTEN_0DB; 350cb7a01acSMauro Carvalho Chehab t->lf = TDA7432_ATTEN_0DB; 351cb7a01acSMauro Carvalho Chehab } else if(ctrl->value > 32769) { 352cb7a01acSMauro Carvalho Chehab /* shifted to right, attenuate left */ 353cb7a01acSMauro Carvalho Chehab t->lf = (ctrl->value - 32768)/1057; 354cb7a01acSMauro Carvalho Chehab t->lr = t->lf; 355cb7a01acSMauro Carvalho Chehab t->rr = TDA7432_ATTEN_0DB; 356cb7a01acSMauro Carvalho Chehab t->rf = TDA7432_ATTEN_0DB; 357cb7a01acSMauro Carvalho Chehab } else { 358cb7a01acSMauro Carvalho Chehab /* centered */ 359cb7a01acSMauro Carvalho Chehab t->rr = TDA7432_ATTEN_0DB; 360cb7a01acSMauro Carvalho Chehab t->rf = TDA7432_ATTEN_0DB; 361cb7a01acSMauro Carvalho Chehab t->lf = TDA7432_ATTEN_0DB; 362cb7a01acSMauro Carvalho Chehab t->lr = TDA7432_ATTEN_0DB; 363cb7a01acSMauro Carvalho Chehab } 364cb7a01acSMauro Carvalho Chehab break; 365cb7a01acSMauro Carvalho Chehab case V4L2_CID_AUDIO_BASS: 366cb7a01acSMauro Carvalho Chehab t->bass = ctrl->value >> 12; 367cb7a01acSMauro Carvalho Chehab if(t->bass>= 0x8) 368cb7a01acSMauro Carvalho Chehab t->bass = (~t->bass & 0xf) + 0x8 ; 369cb7a01acSMauro Carvalho Chehab 370cb7a01acSMauro Carvalho Chehab tda7432_write(sd, TDA7432_TN, 0x10 | (t->bass << 4) | t->treble); 371cb7a01acSMauro Carvalho Chehab return 0; 372cb7a01acSMauro Carvalho Chehab case V4L2_CID_AUDIO_TREBLE: 373cb7a01acSMauro Carvalho Chehab t->treble= ctrl->value >> 12; 374cb7a01acSMauro Carvalho Chehab if(t->treble>= 0x8) 375cb7a01acSMauro Carvalho Chehab t->treble = (~t->treble & 0xf) + 0x8 ; 376cb7a01acSMauro Carvalho Chehab 377cb7a01acSMauro Carvalho Chehab tda7432_write(sd, TDA7432_TN, 0x10 | (t->bass << 4) | t->treble); 378cb7a01acSMauro Carvalho Chehab return 0; 379cb7a01acSMauro Carvalho Chehab default: 380cb7a01acSMauro Carvalho Chehab return -EINVAL; 381cb7a01acSMauro Carvalho Chehab } 382cb7a01acSMauro Carvalho Chehab 383cb7a01acSMauro Carvalho Chehab /* Used for both mute and balance changes */ 384cb7a01acSMauro Carvalho Chehab if (t->muted) 385cb7a01acSMauro Carvalho Chehab { 386cb7a01acSMauro Carvalho Chehab /* Mute & update balance*/ 387cb7a01acSMauro Carvalho Chehab tda7432_write(sd, TDA7432_LF, t->lf | TDA7432_MUTE); 388cb7a01acSMauro Carvalho Chehab tda7432_write(sd, TDA7432_LR, t->lr | TDA7432_MUTE); 389cb7a01acSMauro Carvalho Chehab tda7432_write(sd, TDA7432_RF, t->rf | TDA7432_MUTE); 390cb7a01acSMauro Carvalho Chehab tda7432_write(sd, TDA7432_RR, t->rr | TDA7432_MUTE); 391cb7a01acSMauro Carvalho Chehab } else { 392cb7a01acSMauro Carvalho Chehab tda7432_write(sd, TDA7432_LF, t->lf); 393cb7a01acSMauro Carvalho Chehab tda7432_write(sd, TDA7432_LR, t->lr); 394cb7a01acSMauro Carvalho Chehab tda7432_write(sd, TDA7432_RF, t->rf); 395cb7a01acSMauro Carvalho Chehab tda7432_write(sd, TDA7432_RR, t->rr); 396cb7a01acSMauro Carvalho Chehab } 397cb7a01acSMauro Carvalho Chehab return 0; 398cb7a01acSMauro Carvalho Chehab } 399cb7a01acSMauro Carvalho Chehab 400cb7a01acSMauro Carvalho Chehab static int tda7432_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) 401cb7a01acSMauro Carvalho Chehab { 402cb7a01acSMauro Carvalho Chehab switch (qc->id) { 403cb7a01acSMauro Carvalho Chehab case V4L2_CID_AUDIO_VOLUME: 404cb7a01acSMauro Carvalho Chehab return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 58880); 405cb7a01acSMauro Carvalho Chehab case V4L2_CID_AUDIO_MUTE: 406cb7a01acSMauro Carvalho Chehab return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0); 407cb7a01acSMauro Carvalho Chehab case V4L2_CID_AUDIO_BALANCE: 408cb7a01acSMauro Carvalho Chehab case V4L2_CID_AUDIO_BASS: 409cb7a01acSMauro Carvalho Chehab case V4L2_CID_AUDIO_TREBLE: 410cb7a01acSMauro Carvalho Chehab return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768); 411cb7a01acSMauro Carvalho Chehab } 412cb7a01acSMauro Carvalho Chehab return -EINVAL; 413cb7a01acSMauro Carvalho Chehab } 414cb7a01acSMauro Carvalho Chehab 415cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */ 416cb7a01acSMauro Carvalho Chehab 417cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_core_ops tda7432_core_ops = { 418cb7a01acSMauro Carvalho Chehab .queryctrl = tda7432_queryctrl, 419cb7a01acSMauro Carvalho Chehab .g_ctrl = tda7432_g_ctrl, 420cb7a01acSMauro Carvalho Chehab .s_ctrl = tda7432_s_ctrl, 421cb7a01acSMauro Carvalho Chehab }; 422cb7a01acSMauro Carvalho Chehab 423cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_ops tda7432_ops = { 424cb7a01acSMauro Carvalho Chehab .core = &tda7432_core_ops, 425cb7a01acSMauro Carvalho Chehab }; 426cb7a01acSMauro Carvalho Chehab 427cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */ 428cb7a01acSMauro Carvalho Chehab 429cb7a01acSMauro Carvalho Chehab /* *********************** * 430cb7a01acSMauro Carvalho Chehab * i2c interface functions * 431cb7a01acSMauro Carvalho Chehab * *********************** */ 432cb7a01acSMauro Carvalho Chehab 433cb7a01acSMauro Carvalho Chehab static int tda7432_probe(struct i2c_client *client, 434cb7a01acSMauro Carvalho Chehab const struct i2c_device_id *id) 435cb7a01acSMauro Carvalho Chehab { 436cb7a01acSMauro Carvalho Chehab struct tda7432 *t; 437cb7a01acSMauro Carvalho Chehab struct v4l2_subdev *sd; 438cb7a01acSMauro Carvalho Chehab 439cb7a01acSMauro Carvalho Chehab v4l_info(client, "chip found @ 0x%02x (%s)\n", 440cb7a01acSMauro Carvalho Chehab client->addr << 1, client->adapter->name); 441cb7a01acSMauro Carvalho Chehab 442cb7a01acSMauro Carvalho Chehab t = kzalloc(sizeof(*t), GFP_KERNEL); 443cb7a01acSMauro Carvalho Chehab if (!t) 444cb7a01acSMauro Carvalho Chehab return -ENOMEM; 445cb7a01acSMauro Carvalho Chehab sd = &t->sd; 446cb7a01acSMauro Carvalho Chehab v4l2_i2c_subdev_init(sd, client, &tda7432_ops); 447cb7a01acSMauro Carvalho Chehab if (loudness < 0 || loudness > 15) { 448cb7a01acSMauro Carvalho Chehab v4l2_warn(sd, "loudness parameter must be between 0 and 15\n"); 449cb7a01acSMauro Carvalho Chehab if (loudness < 0) 450cb7a01acSMauro Carvalho Chehab loudness = 0; 451cb7a01acSMauro Carvalho Chehab if (loudness > 15) 452cb7a01acSMauro Carvalho Chehab loudness = 15; 453cb7a01acSMauro Carvalho Chehab } 454cb7a01acSMauro Carvalho Chehab 455cb7a01acSMauro Carvalho Chehab do_tda7432_init(sd); 456cb7a01acSMauro Carvalho Chehab return 0; 457cb7a01acSMauro Carvalho Chehab } 458cb7a01acSMauro Carvalho Chehab 459cb7a01acSMauro Carvalho Chehab static int tda7432_remove(struct i2c_client *client) 460cb7a01acSMauro Carvalho Chehab { 461cb7a01acSMauro Carvalho Chehab struct v4l2_subdev *sd = i2c_get_clientdata(client); 462cb7a01acSMauro Carvalho Chehab 463cb7a01acSMauro Carvalho Chehab do_tda7432_init(sd); 464cb7a01acSMauro Carvalho Chehab v4l2_device_unregister_subdev(sd); 465cb7a01acSMauro Carvalho Chehab kfree(to_state(sd)); 466cb7a01acSMauro Carvalho Chehab return 0; 467cb7a01acSMauro Carvalho Chehab } 468cb7a01acSMauro Carvalho Chehab 469cb7a01acSMauro Carvalho Chehab static const struct i2c_device_id tda7432_id[] = { 470cb7a01acSMauro Carvalho Chehab { "tda7432", 0 }, 471cb7a01acSMauro Carvalho Chehab { } 472cb7a01acSMauro Carvalho Chehab }; 473cb7a01acSMauro Carvalho Chehab MODULE_DEVICE_TABLE(i2c, tda7432_id); 474cb7a01acSMauro Carvalho Chehab 475cb7a01acSMauro Carvalho Chehab static struct i2c_driver tda7432_driver = { 476cb7a01acSMauro Carvalho Chehab .driver = { 477cb7a01acSMauro Carvalho Chehab .owner = THIS_MODULE, 478cb7a01acSMauro Carvalho Chehab .name = "tda7432", 479cb7a01acSMauro Carvalho Chehab }, 480cb7a01acSMauro Carvalho Chehab .probe = tda7432_probe, 481cb7a01acSMauro Carvalho Chehab .remove = tda7432_remove, 482cb7a01acSMauro Carvalho Chehab .id_table = tda7432_id, 483cb7a01acSMauro Carvalho Chehab }; 484cb7a01acSMauro Carvalho Chehab 485cb7a01acSMauro Carvalho Chehab module_i2c_driver(tda7432_driver); 486