1cb7a01acSMauro Carvalho Chehab /* 2cb7a01acSMauro Carvalho Chehab tea6415c - i2c-driver for the tea6415c by SGS Thomson 3cb7a01acSMauro Carvalho Chehab 4cb7a01acSMauro Carvalho Chehab Copyright (C) 1998-2003 Michael Hunold <michael@mihu.de> 5cb7a01acSMauro Carvalho Chehab Copyright (C) 2008 Hans Verkuil <hverkuil@xs4all.nl> 6cb7a01acSMauro Carvalho Chehab 7cb7a01acSMauro Carvalho Chehab The tea6415c is a bus controlled video-matrix-switch 8cb7a01acSMauro Carvalho Chehab with 8 inputs and 6 outputs. 9cb7a01acSMauro Carvalho Chehab It is cascadable, i.e. it can be found at the addresses 10cb7a01acSMauro Carvalho Chehab 0x86 and 0x06 on the i2c-bus. 11cb7a01acSMauro Carvalho Chehab 12cb7a01acSMauro Carvalho Chehab For detailed informations download the specifications directly 13cb7a01acSMauro Carvalho Chehab from SGS Thomson at http://www.st.com 14cb7a01acSMauro Carvalho Chehab 15cb7a01acSMauro Carvalho Chehab This program is free software; you can redistribute it and/or modify 16cb7a01acSMauro Carvalho Chehab it under the terms of the GNU General Public License vs published by 17cb7a01acSMauro Carvalho Chehab the Free Software Foundation; either version 2 of the License, or 18cb7a01acSMauro Carvalho Chehab (at your option) any later version. 19cb7a01acSMauro Carvalho Chehab 20cb7a01acSMauro Carvalho Chehab This program is distributed in the hope that it will be useful, 21cb7a01acSMauro Carvalho Chehab but WITHOUT ANY WARRANTY; without even the implied warranty of 22cb7a01acSMauro Carvalho Chehab MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23cb7a01acSMauro Carvalho Chehab GNU General Public License for more details. 24cb7a01acSMauro Carvalho Chehab 25cb7a01acSMauro Carvalho Chehab You should have received a copy of the GNU General Public License 26cb7a01acSMauro Carvalho Chehab along with this program; if not, write to the Free Software 27cb7a01acSMauro Carvalho Chehab Foundation, Inc., 675 Mvss Ave, Cambridge, MA 02139, USA. 28cb7a01acSMauro Carvalho Chehab */ 29cb7a01acSMauro Carvalho Chehab 30cb7a01acSMauro Carvalho Chehab 31cb7a01acSMauro Carvalho Chehab #include <linux/module.h> 32cb7a01acSMauro Carvalho Chehab #include <linux/ioctl.h> 33cb7a01acSMauro Carvalho Chehab #include <linux/slab.h> 34cb7a01acSMauro Carvalho Chehab #include <linux/i2c.h> 35cb7a01acSMauro Carvalho Chehab #include <media/v4l2-device.h> 36cb7a01acSMauro Carvalho Chehab #include <media/v4l2-chip-ident.h> 37cb7a01acSMauro Carvalho Chehab #include "tea6415c.h" 38cb7a01acSMauro Carvalho Chehab 39cb7a01acSMauro Carvalho Chehab MODULE_AUTHOR("Michael Hunold <michael@mihu.de>"); 40cb7a01acSMauro Carvalho Chehab MODULE_DESCRIPTION("tea6415c driver"); 41cb7a01acSMauro Carvalho Chehab MODULE_LICENSE("GPL"); 42cb7a01acSMauro Carvalho Chehab 43cb7a01acSMauro Carvalho Chehab static int debug; 44cb7a01acSMauro Carvalho Chehab module_param(debug, int, 0644); 45cb7a01acSMauro Carvalho Chehab 46cb7a01acSMauro Carvalho Chehab MODULE_PARM_DESC(debug, "Debug level (0-1)"); 47cb7a01acSMauro Carvalho Chehab 48cb7a01acSMauro Carvalho Chehab 49cb7a01acSMauro Carvalho Chehab /* makes a connection between the input-pin 'i' and the output-pin 'o' */ 50cb7a01acSMauro Carvalho Chehab static int tea6415c_s_routing(struct v4l2_subdev *sd, 51cb7a01acSMauro Carvalho Chehab u32 i, u32 o, u32 config) 52cb7a01acSMauro Carvalho Chehab { 53cb7a01acSMauro Carvalho Chehab struct i2c_client *client = v4l2_get_subdevdata(sd); 54cb7a01acSMauro Carvalho Chehab u8 byte = 0; 55cb7a01acSMauro Carvalho Chehab int ret; 56cb7a01acSMauro Carvalho Chehab 57cb7a01acSMauro Carvalho Chehab v4l2_dbg(1, debug, sd, "i=%d, o=%d\n", i, o); 58cb7a01acSMauro Carvalho Chehab 59cb7a01acSMauro Carvalho Chehab /* check if the pins are valid */ 60cb7a01acSMauro Carvalho Chehab if (0 == ((1 == i || 3 == i || 5 == i || 6 == i || 8 == i || 10 == i || 20 == i || 11 == i) 61cb7a01acSMauro Carvalho Chehab && (18 == o || 17 == o || 16 == o || 15 == o || 14 == o || 13 == o))) 62cb7a01acSMauro Carvalho Chehab return -EINVAL; 63cb7a01acSMauro Carvalho Chehab 64cb7a01acSMauro Carvalho Chehab /* to understand this, have a look at the tea6415c-specs (p.5) */ 65cb7a01acSMauro Carvalho Chehab switch (o) { 66cb7a01acSMauro Carvalho Chehab case 18: 67cb7a01acSMauro Carvalho Chehab byte = 0x00; 68cb7a01acSMauro Carvalho Chehab break; 69cb7a01acSMauro Carvalho Chehab case 14: 70cb7a01acSMauro Carvalho Chehab byte = 0x20; 71cb7a01acSMauro Carvalho Chehab break; 72cb7a01acSMauro Carvalho Chehab case 16: 73cb7a01acSMauro Carvalho Chehab byte = 0x10; 74cb7a01acSMauro Carvalho Chehab break; 75cb7a01acSMauro Carvalho Chehab case 17: 76cb7a01acSMauro Carvalho Chehab byte = 0x08; 77cb7a01acSMauro Carvalho Chehab break; 78cb7a01acSMauro Carvalho Chehab case 15: 79cb7a01acSMauro Carvalho Chehab byte = 0x18; 80cb7a01acSMauro Carvalho Chehab break; 81cb7a01acSMauro Carvalho Chehab case 13: 82cb7a01acSMauro Carvalho Chehab byte = 0x28; 83cb7a01acSMauro Carvalho Chehab break; 84*3ea0a1d1SPeter Senna Tschudin } 85cb7a01acSMauro Carvalho Chehab 86cb7a01acSMauro Carvalho Chehab switch (i) { 87cb7a01acSMauro Carvalho Chehab case 5: 88cb7a01acSMauro Carvalho Chehab byte |= 0x00; 89cb7a01acSMauro Carvalho Chehab break; 90cb7a01acSMauro Carvalho Chehab case 8: 91cb7a01acSMauro Carvalho Chehab byte |= 0x04; 92cb7a01acSMauro Carvalho Chehab break; 93cb7a01acSMauro Carvalho Chehab case 3: 94cb7a01acSMauro Carvalho Chehab byte |= 0x02; 95cb7a01acSMauro Carvalho Chehab break; 96cb7a01acSMauro Carvalho Chehab case 20: 97cb7a01acSMauro Carvalho Chehab byte |= 0x06; 98cb7a01acSMauro Carvalho Chehab break; 99cb7a01acSMauro Carvalho Chehab case 6: 100cb7a01acSMauro Carvalho Chehab byte |= 0x01; 101cb7a01acSMauro Carvalho Chehab break; 102cb7a01acSMauro Carvalho Chehab case 10: 103cb7a01acSMauro Carvalho Chehab byte |= 0x05; 104cb7a01acSMauro Carvalho Chehab break; 105cb7a01acSMauro Carvalho Chehab case 1: 106cb7a01acSMauro Carvalho Chehab byte |= 0x03; 107cb7a01acSMauro Carvalho Chehab break; 108cb7a01acSMauro Carvalho Chehab case 11: 109cb7a01acSMauro Carvalho Chehab byte |= 0x07; 110cb7a01acSMauro Carvalho Chehab break; 111*3ea0a1d1SPeter Senna Tschudin } 112cb7a01acSMauro Carvalho Chehab 113cb7a01acSMauro Carvalho Chehab ret = i2c_smbus_write_byte(client, byte); 114cb7a01acSMauro Carvalho Chehab if (ret) { 115cb7a01acSMauro Carvalho Chehab v4l2_dbg(1, debug, sd, 116cb7a01acSMauro Carvalho Chehab "i2c_smbus_write_byte() failed, ret:%d\n", ret); 117cb7a01acSMauro Carvalho Chehab return -EIO; 118cb7a01acSMauro Carvalho Chehab } 119cb7a01acSMauro Carvalho Chehab return ret; 120cb7a01acSMauro Carvalho Chehab } 121cb7a01acSMauro Carvalho Chehab 122cb7a01acSMauro Carvalho Chehab static int tea6415c_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) 123cb7a01acSMauro Carvalho Chehab { 124cb7a01acSMauro Carvalho Chehab struct i2c_client *client = v4l2_get_subdevdata(sd); 125cb7a01acSMauro Carvalho Chehab 126cb7a01acSMauro Carvalho Chehab return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_TEA6415C, 0); 127cb7a01acSMauro Carvalho Chehab } 128cb7a01acSMauro Carvalho Chehab 129cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */ 130cb7a01acSMauro Carvalho Chehab 131cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_core_ops tea6415c_core_ops = { 132cb7a01acSMauro Carvalho Chehab .g_chip_ident = tea6415c_g_chip_ident, 133cb7a01acSMauro Carvalho Chehab }; 134cb7a01acSMauro Carvalho Chehab 135cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_video_ops tea6415c_video_ops = { 136cb7a01acSMauro Carvalho Chehab .s_routing = tea6415c_s_routing, 137cb7a01acSMauro Carvalho Chehab }; 138cb7a01acSMauro Carvalho Chehab 139cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_ops tea6415c_ops = { 140cb7a01acSMauro Carvalho Chehab .core = &tea6415c_core_ops, 141cb7a01acSMauro Carvalho Chehab .video = &tea6415c_video_ops, 142cb7a01acSMauro Carvalho Chehab }; 143cb7a01acSMauro Carvalho Chehab 144cb7a01acSMauro Carvalho Chehab static int tea6415c_probe(struct i2c_client *client, 145cb7a01acSMauro Carvalho Chehab const struct i2c_device_id *id) 146cb7a01acSMauro Carvalho Chehab { 147cb7a01acSMauro Carvalho Chehab struct v4l2_subdev *sd; 148cb7a01acSMauro Carvalho Chehab 149cb7a01acSMauro Carvalho Chehab /* let's see whether this adapter can support what we need */ 150cb7a01acSMauro Carvalho Chehab if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WRITE_BYTE)) 151cb7a01acSMauro Carvalho Chehab return -EIO; 152cb7a01acSMauro Carvalho Chehab 153cb7a01acSMauro Carvalho Chehab v4l_info(client, "chip found @ 0x%x (%s)\n", 154cb7a01acSMauro Carvalho Chehab client->addr << 1, client->adapter->name); 155cb7a01acSMauro Carvalho Chehab sd = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL); 156cb7a01acSMauro Carvalho Chehab if (sd == NULL) 157cb7a01acSMauro Carvalho Chehab return -ENOMEM; 158cb7a01acSMauro Carvalho Chehab v4l2_i2c_subdev_init(sd, client, &tea6415c_ops); 159cb7a01acSMauro Carvalho Chehab return 0; 160cb7a01acSMauro Carvalho Chehab } 161cb7a01acSMauro Carvalho Chehab 162cb7a01acSMauro Carvalho Chehab static int tea6415c_remove(struct i2c_client *client) 163cb7a01acSMauro Carvalho Chehab { 164cb7a01acSMauro Carvalho Chehab struct v4l2_subdev *sd = i2c_get_clientdata(client); 165cb7a01acSMauro Carvalho Chehab 166cb7a01acSMauro Carvalho Chehab v4l2_device_unregister_subdev(sd); 167cb7a01acSMauro Carvalho Chehab kfree(sd); 168cb7a01acSMauro Carvalho Chehab return 0; 169cb7a01acSMauro Carvalho Chehab } 170cb7a01acSMauro Carvalho Chehab 171cb7a01acSMauro Carvalho Chehab static const struct i2c_device_id tea6415c_id[] = { 172cb7a01acSMauro Carvalho Chehab { "tea6415c", 0 }, 173cb7a01acSMauro Carvalho Chehab { } 174cb7a01acSMauro Carvalho Chehab }; 175cb7a01acSMauro Carvalho Chehab MODULE_DEVICE_TABLE(i2c, tea6415c_id); 176cb7a01acSMauro Carvalho Chehab 177cb7a01acSMauro Carvalho Chehab static struct i2c_driver tea6415c_driver = { 178cb7a01acSMauro Carvalho Chehab .driver = { 179cb7a01acSMauro Carvalho Chehab .owner = THIS_MODULE, 180cb7a01acSMauro Carvalho Chehab .name = "tea6415c", 181cb7a01acSMauro Carvalho Chehab }, 182cb7a01acSMauro Carvalho Chehab .probe = tea6415c_probe, 183cb7a01acSMauro Carvalho Chehab .remove = tea6415c_remove, 184cb7a01acSMauro Carvalho Chehab .id_table = tea6415c_id, 185cb7a01acSMauro Carvalho Chehab }; 186cb7a01acSMauro Carvalho Chehab 187cb7a01acSMauro Carvalho Chehab module_i2c_driver(tea6415c_driver); 188