1 /* 2 tea6420 - i2c-driver for the tea6420 by SGS Thomson 3 4 Copyright (C) 1998-2003 Michael Hunold <michael@mihu.de> 5 6 The tea6420 is a bus controlled audio-matrix with 5 stereo inputs, 7 4 stereo outputs and gain control for each output. 8 It is cascadable, i.e. it can be found at the adresses 0x98 9 and 0x9a on the i2c-bus. 10 11 For detailed informations download the specifications directly 12 from SGS Thomson at http://www.st.com 13 14 This program is free software; you can redistribute it and/or modify 15 it under the terms of the GNU General Public License as published by 16 the Free Software Foundation; either version 2 of the License, or 17 (at your option) any later version. 18 19 This program is distributed in the hope that it will be useful, 20 but WITHOUT ANY WARRANTY; without even the implied warranty of 21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 GNU General Public License for more details. 23 24 You should have received a copy of the GNU General Public License 25 along with this program; if not, write to the Free Software 26 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 27 */ 28 29 30#include <linux/module.h> 31#include <linux/ioctl.h> 32#include <linux/i2c.h> 33 34#include "tea6420.h" 35 36static int debug = 0; /* insmod parameter */ 37module_param(debug, int, 0644); 38MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off)."); 39#define dprintk(args...) \ 40 do { if (debug) { printk("%s: %s()[%d]: ", KBUILD_MODNAME, __FUNCTION__, __LINE__); printk(args); } } while (0) 41 42/* addresses to scan, found only at 0x4c and/or 0x4d (7-Bit) */ 43static unsigned short normal_i2c[] = { I2C_ADDR_TEA6420_1, I2C_ADDR_TEA6420_2, I2C_CLIENT_END }; 44 45/* magic definition of all other variables and things */ 46I2C_CLIENT_INSMOD; 47 48static struct i2c_driver driver; 49static struct i2c_client client_template; 50 51/* make a connection between the input 'i' and the output 'o' 52 with gain 'g' for the tea6420-client 'client' (note: i = 6 means 'mute') */ 53static int tea6420_switch(struct i2c_client *client, int i, int o, int g) 54{ 55 u8 byte = 0; 56 int ret; 57 58 dprintk("adr:0x%02x, i:%d, o:%d, g:%d\n", client->addr, i, o, g); 59 60 /* check if the paramters are valid */ 61 if (i < 1 || i > 6 || o < 1 || o > 4 || g < 0 || g > 6 || g % 2 != 0) 62 return -1; 63 64 byte = ((o - 1) << 5); 65 byte |= (i - 1); 66 67 /* to understand this, have a look at the tea6420-specs (p.5) */ 68 switch (g) { 69 case 0: 70 byte |= (3 << 3); 71 break; 72 case 2: 73 byte |= (2 << 3); 74 break; 75 case 4: 76 byte |= (1 << 3); 77 break; 78 case 6: 79 break; 80 } 81 82 ret = i2c_smbus_write_byte(client, byte); 83 if (ret) { 84 dprintk("i2c_smbus_write_byte() failed, ret:%d\n", ret); 85 return -EIO; 86 } 87 88 return 0; 89} 90 91/* this function is called by i2c_probe */ 92static int tea6420_detect(struct i2c_adapter *adapter, int address, int kind) 93{ 94 struct i2c_client *client; 95 int err = 0, i = 0; 96 97 /* let's see whether this adapter can support what we need */ 98 if (0 == i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE)) { 99 return 0; 100 } 101 102 /* allocate memory for client structure */ 103 client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); 104 if (0 == client) { 105 return -ENOMEM; 106 } 107 108 /* fill client structure */ 109 memcpy(client, &client_template, sizeof(struct i2c_client)); 110 client->addr = address; 111 client->adapter = adapter; 112 113 /* tell the i2c layer a new client has arrived */ 114 if (0 != (err = i2c_attach_client(client))) { 115 kfree(client); 116 return err; 117 } 118 119 /* set initial values: set "mute"-input to all outputs at gain 0 */ 120 err = 0; 121 for (i = 1; i < 5; i++) { 122 err += tea6420_switch(client, 6, i, 0); 123 } 124 if (err) { 125 dprintk("could not initialize tea6420\n"); 126 kfree(client); 127 return -ENODEV; 128 } 129 130 printk("tea6420: detected @ 0x%02x on adapter %s\n", address, &client->adapter->name[0]); 131 132 return 0; 133} 134 135static int attach(struct i2c_adapter *adapter) 136{ 137 /* let's see whether this is a know adapter we can attach to */ 138 if (adapter->id != I2C_HW_SAA7146) { 139 dprintk("refusing to probe on unknown adapter [name='%s',id=0x%x]\n", adapter->name, adapter->id); 140 return -ENODEV; 141 } 142 143 return i2c_probe(adapter, &addr_data, &tea6420_detect); 144} 145 146static int detach(struct i2c_client *client) 147{ 148 int ret = i2c_detach_client(client); 149 kfree(client); 150 return ret; 151} 152 153static int command(struct i2c_client *client, unsigned int cmd, void *arg) 154{ 155 struct tea6420_multiplex *a = (struct tea6420_multiplex *)arg; 156 int result = 0; 157 158 switch (cmd) { 159 case TEA6420_SWITCH: 160 result = tea6420_switch(client, a->in, a->out, a->gain); 161 break; 162 default: 163 return -ENOIOCTLCMD; 164 } 165 166 return result; 167} 168 169static struct i2c_driver driver = { 170 .driver = { 171 .name = "tea6420", 172 }, 173 .id = I2C_DRIVERID_TEA6420, 174 .attach_adapter = attach, 175 .detach_client = detach, 176 .command = command, 177}; 178 179static struct i2c_client client_template = { 180 .name = "tea6420", 181 .driver = &driver, 182}; 183 184static int __init this_module_init(void) 185{ 186 return i2c_add_driver(&driver); 187} 188 189static void __exit this_module_exit(void) 190{ 191 i2c_del_driver(&driver); 192} 193 194module_init(this_module_init); 195module_exit(this_module_exit); 196 197MODULE_AUTHOR("Michael Hunold <michael@mihu.de>"); 198MODULE_DESCRIPTION("tea6420 driver"); 199MODULE_LICENSE("GPL"); 200