diff options
Diffstat (limited to 'linux/drivers/media/video/tea6415c.c')
-rw-r--r-- | linux/drivers/media/video/tea6415c.c | 223 |
1 files changed, 223 insertions, 0 deletions
diff --git a/linux/drivers/media/video/tea6415c.c b/linux/drivers/media/video/tea6415c.c new file mode 100644 index 000000000..5050fe286 --- /dev/null +++ b/linux/drivers/media/video/tea6415c.c @@ -0,0 +1,223 @@ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/poll.h> +#include <linux/slab.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include "tea6415c.h" + +#ifdef MODULE +MODULE_PARM(debug,"i"); +#endif + +static int debug = 0; /* insmod parameter */ +#define dprintk if (debug) printk + +#define TEA6415C_NUM_INPUTS 8 +#define TEA6415C_NUM_OUTPUTS 6 + +/* addresses to scan, found only at 0x03 and/or 0x43 (7-bit) */ +static unsigned short normal_i2c[] = {I2C_TEA6415C_1, I2C_TEA6415C_2, I2C_CLIENT_END}; +static unsigned short normal_i2c_range[] = {I2C_CLIENT_END}; + +/* magic definition of all other variables and things */ +I2C_CLIENT_INSMOD; + +static struct i2c_driver driver; + +/* unique ID allocation */ +static int tea6415c_id = 0; + +/* this function is called by i2c_probe */ +static int tea6415c_detect(struct i2c_adapter *adapter, int address, unsigned short flags, int kind) +{ + struct i2c_client *client = 0; + int err = 0; + + /* let's see whether this adapter can support what we need */ + if ( 0 == i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE)) { + return 0; + } + + /* allocate memory for client structure */ + client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (0 == client) { + return -ENOMEM; + } + + /* fill client structure */ + sprintf(client->name,"tea6415c (0x%02x)", address); + client->id = tea6415c_id++; + client->flags = 0; + client->addr = address; + client->adapter = adapter; + client->driver = &driver; + + /* tell the i2c layer a new client has arrived */ + if (0 != (err = i2c_attach_client(client))) { + kfree(client); + return err; + } + + printk("tea6415c.o: detected @ 0x%02x on adapter %s\n",2*address,&client->adapter->name[0]); + + return 0; +} + +static int tea6415c_attach(struct i2c_adapter *adapter) +{ + return i2c_probe(adapter,&addr_data,&tea6415c_detect); +} + +static int tea6415c_detach(struct i2c_client *client) +{ + int err = 0; + + if ( 0 != (err = i2c_detach_client(client))) { + printk("tea6415c.o: Client deregistration failed, client not detached.\n"); + return err; + } + + kfree(client); + + return 0; +} + +/* makes a connection between the input-pin 'i' and the output-pin 'o' + for the tea6415c-client 'client' */ +static int tea6415c_switch(struct i2c_client *client, int i, int o) +{ + u8 byte = 0; + + dprintk("tea6415c.o: tea6415c_switch: adr:0x%02x, i:%d, o:%d\n", client->addr, i, o); + + /* check if the pins are valid */ + if ( 0 == (( 1 == i || 3 == i || 5 == i || 6 == i || 8 == i || 10 == i || 20 == i || 11 == i ) && + (18 == o || 17 == o || 16 == o || 15 == o || 14 == o || 13 == o ))) + return -1; + + /* to understand this, have a look at the tea6415c-specs (p.5) */ + switch(o) { + case 18: + byte = 0x00; + break; + case 14: + byte = 0x20; + break; + case 16: + byte = 0x10; + break; + case 17: + byte = 0x08; + break; + case 15: + byte = 0x18; + break; + case 13: + byte = 0x28; + break; + }; + + switch(i) { + case 5: + byte |= 0x00; + break; + case 8: + byte |= 0x04; + break; + case 3: + byte |= 0x02; + break; + case 20: + byte |= 0x06; + break; + case 6: + byte |= 0x01; + break; + case 10: + byte |= 0x05; + break; + case 1: + byte |= 0x03; + break; + case 11: + byte |= 0x07; + break; + }; + + if ( 0 != i2c_smbus_write_byte(client,byte)) { + dprintk("tea6415c.o: tea6415c_switch: could not write to tea6415c\n"); + return -1; + } + + return 0; +} + +static int tea6415c_command(struct i2c_client *client, unsigned int cmd, void* arg) +{ + struct tea6415c_video_multiplex *v = (struct tea6415c_video_multiplex*)arg; + int result = 0; + + switch (cmd) { + case TEA6415C_SWITCH: { + result = tea6415c_switch(client,v->in,v->out); + break; + } + default: { + return -ENOIOCTLCMD; + } + } + + if ( 0 != result ) + return result; + + return 0; +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,51) +static void tea6415c_inc_use(struct i2c_client *client) +{ + MOD_INC_USE_COUNT; +} + +static void tea6415c_dec_use(struct i2c_client *client) +{ + MOD_DEC_USE_COUNT; +} +#endif + +static struct i2c_driver driver = { + "tea6415c driver", + I2C_DRIVERID_TEA6415C, + I2C_DF_NOTIFY, + tea6415c_attach, + tea6415c_detach, + tea6415c_command, +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,51) + tea6415c_inc_use, + tea6415c_dec_use, +#endif +}; + +EXPORT_NO_SYMBOLS; + +static int tea6415c_init_module(void) +{ + i2c_add_driver(&driver); + return 0; +} + +static void tea6415c_cleanup_module(void) +{ + i2c_del_driver(&driver); +} + +module_init(tea6415c_init_module); +module_exit(tea6415c_cleanup_module); + +#ifdef MODULE +MODULE_AUTHOR("Michael Hunold <michael@mihu.de>"); +MODULE_DESCRIPTION("tea6415c driver"); +MODULE_LICENSE("GPL"); +#endif + |