11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tea6415c - i2c-driver for the tea6415c by SGS Thomson 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Copyright (C) 1998-2003 Michael Hunold <michael@mihu.de> 5a832781cd383e70929c0ceece23f8a5b62e2152bHans Verkuil Copyright (C) 2008 Hans Verkuil <hverkuil@xs4all.nl> 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds The tea6415c is a bus controlled video-matrix-switch 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds with 8 inputs and 6 outputs. 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds It is cascadable, i.e. it can be found at the addresses 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0x86 and 0x06 on the i2c-bus. 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds For detailed informations download the specifications directly 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds from SGS Thomson at http://www.st.com 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds This program is free software; you can redistribute it and/or modify 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds it under the terms of the GNU General Public License vs published by 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds the Free Software Foundation; either version 2 of the License, or 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (at your option) any later version. 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds This program is distributed in the hope that it will be useful, 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds but WITHOUT ANY WARRANTY; without even the implied warranty of 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds GNU General Public License for more details. 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds You should have received a copy of the GNU General Public License 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds along with this program; if not, write to the Free Software 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Foundation, Inc., 675 Mvss Ave, Cambridge, MA 02139, USA. 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30a8733ca5141c256322ab5ea9fd3074942a209bbaMauro Carvalho Chehab 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioctl.h> 335a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/i2c.h> 3585d826b01751c17bc70a97bcacc1886f0c79917dHans Verkuil#include <media/v4l2-device.h> 361b8dac150a01e2312d8e3fedd6462a0ec34c96d0Hans Verkuil#include <media/v4l2-chip-ident.h> 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "tea6415c.h" 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39a832781cd383e70929c0ceece23f8a5b62e2152bHans VerkuilMODULE_AUTHOR("Michael Hunold <michael@mihu.de>"); 40a832781cd383e70929c0ceece23f8a5b62e2152bHans VerkuilMODULE_DESCRIPTION("tea6415c driver"); 41a832781cd383e70929c0ceece23f8a5b62e2152bHans VerkuilMODULE_LICENSE("GPL"); 42f87086e302300fdff1bd32049deb7a7f3e3de7daHans Verkuil 43a832781cd383e70929c0ceece23f8a5b62e2152bHans Verkuilstatic int debug; 44a832781cd383e70929c0ceece23f8a5b62e2152bHans Verkuilmodule_param(debug, int, 0644); 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 46a832781cd383e70929c0ceece23f8a5b62e2152bHans VerkuilMODULE_PARM_DESC(debug, "Debug level (0-1)"); 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 491b8dac150a01e2312d8e3fedd6462a0ec34c96d0Hans Verkuil/* makes a connection between the input-pin 'i' and the output-pin 'o' */ 505325b4272a53b43f55b82cc369c310c2fcacdca1Hans Verkuilstatic int tea6415c_s_routing(struct v4l2_subdev *sd, 515325b4272a53b43f55b82cc369c310c2fcacdca1Hans Verkuil u32 i, u32 o, u32 config) 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 531b8dac150a01e2312d8e3fedd6462a0ec34c96d0Hans Verkuil struct i2c_client *client = v4l2_get_subdevdata(sd); 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 byte = 0; 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 56a8733ca5141c256322ab5ea9fd3074942a209bbaMauro Carvalho Chehab 571b8dac150a01e2312d8e3fedd6462a0ec34c96d0Hans Verkuil v4l2_dbg(1, debug, sd, "i=%d, o=%d\n", i, o); 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* check if the pins are valid */ 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (0 == ((1 == i || 3 == i || 5 == i || 6 == i || 8 == i || 10 == i || 20 == i || 11 == i) 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && (18 == o || 17 == o || 16 == o || 15 == o || 14 == o || 13 == o))) 621b8dac150a01e2312d8e3fedd6462a0ec34c96d0Hans Verkuil return -EINVAL; 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* to understand this, have a look at the tea6415c-specs (p.5) */ 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (o) { 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 18: 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds byte = 0x00; 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 14: 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds byte = 0x20; 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 16: 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds byte = 0x10; 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 17: 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds byte = 0x08; 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 15: 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds byte = 0x18; 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 13: 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds byte = 0x28; 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }; 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (i) { 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 5: 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds byte |= 0x00; 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 8: 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds byte |= 0x04; 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 3: 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds byte |= 0x02; 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 20: 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds byte |= 0x06; 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 6: 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds byte |= 0x01; 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 10: 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds byte |= 0x05; 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 1: 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds byte |= 0x03; 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 11: 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds byte |= 0x07; 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }; 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = i2c_smbus_write_byte(client, byte); 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret) { 1151b8dac150a01e2312d8e3fedd6462a0ec34c96d0Hans Verkuil v4l2_dbg(1, debug, sd, 116a832781cd383e70929c0ceece23f8a5b62e2152bHans Verkuil "i2c_smbus_write_byte() failed, ret:%d\n", ret); 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1221b8dac150a01e2312d8e3fedd6462a0ec34c96d0Hans Verkuilstatic int tea6415c_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1241b8dac150a01e2312d8e3fedd6462a0ec34c96d0Hans Verkuil struct i2c_client *client = v4l2_get_subdevdata(sd); 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1261b8dac150a01e2312d8e3fedd6462a0ec34c96d0Hans Verkuil return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_TEA6415C, 0); 12785d826b01751c17bc70a97bcacc1886f0c79917dHans Verkuil} 12885d826b01751c17bc70a97bcacc1886f0c79917dHans Verkuil 12985d826b01751c17bc70a97bcacc1886f0c79917dHans Verkuil/* ----------------------------------------------------------------------- */ 13085d826b01751c17bc70a97bcacc1886f0c79917dHans Verkuil 13185d826b01751c17bc70a97bcacc1886f0c79917dHans Verkuilstatic const struct v4l2_subdev_core_ops tea6415c_core_ops = { 1321b8dac150a01e2312d8e3fedd6462a0ec34c96d0Hans Verkuil .g_chip_ident = tea6415c_g_chip_ident, 1331b8dac150a01e2312d8e3fedd6462a0ec34c96d0Hans Verkuil}; 1341b8dac150a01e2312d8e3fedd6462a0ec34c96d0Hans Verkuil 1351b8dac150a01e2312d8e3fedd6462a0ec34c96d0Hans Verkuilstatic const struct v4l2_subdev_video_ops tea6415c_video_ops = { 1361b8dac150a01e2312d8e3fedd6462a0ec34c96d0Hans Verkuil .s_routing = tea6415c_s_routing, 13785d826b01751c17bc70a97bcacc1886f0c79917dHans Verkuil}; 13885d826b01751c17bc70a97bcacc1886f0c79917dHans Verkuil 13985d826b01751c17bc70a97bcacc1886f0c79917dHans Verkuilstatic const struct v4l2_subdev_ops tea6415c_ops = { 14085d826b01751c17bc70a97bcacc1886f0c79917dHans Verkuil .core = &tea6415c_core_ops, 1411b8dac150a01e2312d8e3fedd6462a0ec34c96d0Hans Verkuil .video = &tea6415c_video_ops, 14285d826b01751c17bc70a97bcacc1886f0c79917dHans Verkuil}; 14385d826b01751c17bc70a97bcacc1886f0c79917dHans Verkuil 144a832781cd383e70929c0ceece23f8a5b62e2152bHans Verkuilstatic int tea6415c_probe(struct i2c_client *client, 145a832781cd383e70929c0ceece23f8a5b62e2152bHans Verkuil const struct i2c_device_id *id) 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14785d826b01751c17bc70a97bcacc1886f0c79917dHans Verkuil struct v4l2_subdev *sd; 14885d826b01751c17bc70a97bcacc1886f0c79917dHans Verkuil 149a832781cd383e70929c0ceece23f8a5b62e2152bHans Verkuil /* let's see whether this adapter can support what we need */ 150a832781cd383e70929c0ceece23f8a5b62e2152bHans Verkuil if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WRITE_BYTE)) 15176e4a9a7164263d8ffe816920f84a91e7dfee444Axel Lin return -EIO; 152a832781cd383e70929c0ceece23f8a5b62e2152bHans Verkuil 153a832781cd383e70929c0ceece23f8a5b62e2152bHans Verkuil v4l_info(client, "chip found @ 0x%x (%s)\n", 154a832781cd383e70929c0ceece23f8a5b62e2152bHans Verkuil client->addr << 1, client->adapter->name); 15580845a33165278f3236812009e9c568ba8c29938Herton Ronaldo Krzesinski sd = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL); 15685d826b01751c17bc70a97bcacc1886f0c79917dHans Verkuil if (sd == NULL) 15785d826b01751c17bc70a97bcacc1886f0c79917dHans Verkuil return -ENOMEM; 15885d826b01751c17bc70a97bcacc1886f0c79917dHans Verkuil v4l2_i2c_subdev_init(sd, client, &tea6415c_ops); 15985d826b01751c17bc70a97bcacc1886f0c79917dHans Verkuil return 0; 16085d826b01751c17bc70a97bcacc1886f0c79917dHans Verkuil} 16185d826b01751c17bc70a97bcacc1886f0c79917dHans Verkuil 16285d826b01751c17bc70a97bcacc1886f0c79917dHans Verkuilstatic int tea6415c_remove(struct i2c_client *client) 16385d826b01751c17bc70a97bcacc1886f0c79917dHans Verkuil{ 16485d826b01751c17bc70a97bcacc1886f0c79917dHans Verkuil struct v4l2_subdev *sd = i2c_get_clientdata(client); 16585d826b01751c17bc70a97bcacc1886f0c79917dHans Verkuil 16685d826b01751c17bc70a97bcacc1886f0c79917dHans Verkuil v4l2_device_unregister_subdev(sd); 16785d826b01751c17bc70a97bcacc1886f0c79917dHans Verkuil kfree(sd); 168a832781cd383e70929c0ceece23f8a5b62e2152bHans Verkuil return 0; 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 171a832781cd383e70929c0ceece23f8a5b62e2152bHans Verkuilstatic const struct i2c_device_id tea6415c_id[] = { 172a832781cd383e70929c0ceece23f8a5b62e2152bHans Verkuil { "tea6415c", 0 }, 173a832781cd383e70929c0ceece23f8a5b62e2152bHans Verkuil { } 174a832781cd383e70929c0ceece23f8a5b62e2152bHans Verkuil}; 175a832781cd383e70929c0ceece23f8a5b62e2152bHans VerkuilMODULE_DEVICE_TABLE(i2c, tea6415c_id); 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1770c748826fe55c15b7f9d7566865ca0c85af1f72fHans Verkuilstatic struct i2c_driver tea6415c_driver = { 1780c748826fe55c15b7f9d7566865ca0c85af1f72fHans Verkuil .driver = { 1790c748826fe55c15b7f9d7566865ca0c85af1f72fHans Verkuil .owner = THIS_MODULE, 1800c748826fe55c15b7f9d7566865ca0c85af1f72fHans Verkuil .name = "tea6415c", 1810c748826fe55c15b7f9d7566865ca0c85af1f72fHans Verkuil }, 1820c748826fe55c15b7f9d7566865ca0c85af1f72fHans Verkuil .probe = tea6415c_probe, 1830c748826fe55c15b7f9d7566865ca0c85af1f72fHans Verkuil .remove = tea6415c_remove, 1840c748826fe55c15b7f9d7566865ca0c85af1f72fHans Verkuil .id_table = tea6415c_id, 185a832781cd383e70929c0ceece23f8a5b62e2152bHans Verkuil}; 1860c748826fe55c15b7f9d7566865ca0c85af1f72fHans Verkuil 187c6e8d86fffd8edf1bfccbd441b1812ee919fe3d5Axel Linmodule_i2c_driver(tea6415c_driver); 188