xref: /openbmc/linux/drivers/media/i2c/tea6415c.c (revision cb7a01ac)
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;
84cb7a01acSMauro Carvalho Chehab 	};
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;
111cb7a01acSMauro Carvalho Chehab 	};
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