xref: /openbmc/linux/drivers/media/i2c/tea6415c.c (revision aaeb31c0)
1112a7328SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2cb7a01acSMauro Carvalho Chehab  /*
3cb7a01acSMauro Carvalho Chehab     tea6415c - i2c-driver for the tea6415c by SGS Thomson
4cb7a01acSMauro Carvalho Chehab 
5cb7a01acSMauro Carvalho Chehab     Copyright (C) 1998-2003 Michael Hunold <michael@mihu.de>
6cb7a01acSMauro Carvalho Chehab     Copyright (C) 2008 Hans Verkuil <hverkuil@xs4all.nl>
7cb7a01acSMauro Carvalho Chehab 
8cb7a01acSMauro Carvalho Chehab     The tea6415c is a bus controlled video-matrix-switch
9cb7a01acSMauro Carvalho Chehab     with 8 inputs and 6 outputs.
10cb7a01acSMauro Carvalho Chehab     It is cascadable, i.e. it can be found at the addresses
11cb7a01acSMauro Carvalho Chehab     0x86 and 0x06 on the i2c-bus.
12cb7a01acSMauro Carvalho Chehab 
13f8a7647dSMauro Carvalho Chehab     For detailed information download the specifications directly
14cb7a01acSMauro Carvalho Chehab     from SGS Thomson at http://www.st.com
15cb7a01acSMauro Carvalho Chehab 
16cb7a01acSMauro Carvalho Chehab   */
17cb7a01acSMauro Carvalho Chehab 
18cb7a01acSMauro Carvalho Chehab 
19cb7a01acSMauro Carvalho Chehab #include <linux/module.h>
20cb7a01acSMauro Carvalho Chehab #include <linux/ioctl.h>
21cb7a01acSMauro Carvalho Chehab #include <linux/slab.h>
22cb7a01acSMauro Carvalho Chehab #include <linux/i2c.h>
23cb7a01acSMauro Carvalho Chehab #include <media/v4l2-device.h>
24cb7a01acSMauro Carvalho Chehab #include "tea6415c.h"
25cb7a01acSMauro Carvalho Chehab 
26cb7a01acSMauro Carvalho Chehab MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
27cb7a01acSMauro Carvalho Chehab MODULE_DESCRIPTION("tea6415c driver");
28cb7a01acSMauro Carvalho Chehab MODULE_LICENSE("GPL");
29cb7a01acSMauro Carvalho Chehab 
30cb7a01acSMauro Carvalho Chehab static int debug;
31cb7a01acSMauro Carvalho Chehab module_param(debug, int, 0644);
32cb7a01acSMauro Carvalho Chehab 
33cb7a01acSMauro Carvalho Chehab MODULE_PARM_DESC(debug, "Debug level (0-1)");
34cb7a01acSMauro Carvalho Chehab 
35cb7a01acSMauro Carvalho Chehab 
36cb7a01acSMauro Carvalho Chehab /* makes a connection between the input-pin 'i' and the output-pin 'o' */
tea6415c_s_routing(struct v4l2_subdev * sd,u32 i,u32 o,u32 config)37cb7a01acSMauro Carvalho Chehab static int tea6415c_s_routing(struct v4l2_subdev *sd,
38cb7a01acSMauro Carvalho Chehab 			      u32 i, u32 o, u32 config)
39cb7a01acSMauro Carvalho Chehab {
40cb7a01acSMauro Carvalho Chehab 	struct i2c_client *client = v4l2_get_subdevdata(sd);
41cb7a01acSMauro Carvalho Chehab 	u8 byte = 0;
42cb7a01acSMauro Carvalho Chehab 	int ret;
43cb7a01acSMauro Carvalho Chehab 
44cb7a01acSMauro Carvalho Chehab 	v4l2_dbg(1, debug, sd, "i=%d, o=%d\n", i, o);
45cb7a01acSMauro Carvalho Chehab 
46cb7a01acSMauro Carvalho Chehab 	/* check if the pins are valid */
47cb7a01acSMauro Carvalho Chehab 	if (0 == ((1 == i ||  3 == i ||  5 == i ||  6 == i ||  8 == i || 10 == i || 20 == i || 11 == i)
48cb7a01acSMauro Carvalho Chehab 	      && (18 == o || 17 == o || 16 == o || 15 == o || 14 == o || 13 == o)))
49cb7a01acSMauro Carvalho Chehab 		return -EINVAL;
50cb7a01acSMauro Carvalho Chehab 
51cb7a01acSMauro Carvalho Chehab 	/* to understand this, have a look at the tea6415c-specs (p.5) */
52cb7a01acSMauro Carvalho Chehab 	switch (o) {
53cb7a01acSMauro Carvalho Chehab 	case 18:
54cb7a01acSMauro Carvalho Chehab 		byte = 0x00;
55cb7a01acSMauro Carvalho Chehab 		break;
56cb7a01acSMauro Carvalho Chehab 	case 14:
57cb7a01acSMauro Carvalho Chehab 		byte = 0x20;
58cb7a01acSMauro Carvalho Chehab 		break;
59cb7a01acSMauro Carvalho Chehab 	case 16:
60cb7a01acSMauro Carvalho Chehab 		byte = 0x10;
61cb7a01acSMauro Carvalho Chehab 		break;
62cb7a01acSMauro Carvalho Chehab 	case 17:
63cb7a01acSMauro Carvalho Chehab 		byte = 0x08;
64cb7a01acSMauro Carvalho Chehab 		break;
65cb7a01acSMauro Carvalho Chehab 	case 15:
66cb7a01acSMauro Carvalho Chehab 		byte = 0x18;
67cb7a01acSMauro Carvalho Chehab 		break;
68cb7a01acSMauro Carvalho Chehab 	case 13:
69cb7a01acSMauro Carvalho Chehab 		byte = 0x28;
70cb7a01acSMauro Carvalho Chehab 		break;
713ea0a1d1SPeter Senna Tschudin 	}
72cb7a01acSMauro Carvalho Chehab 
73cb7a01acSMauro Carvalho Chehab 	switch (i) {
74cb7a01acSMauro Carvalho Chehab 	case 5:
75cb7a01acSMauro Carvalho Chehab 		byte |= 0x00;
76cb7a01acSMauro Carvalho Chehab 		break;
77cb7a01acSMauro Carvalho Chehab 	case 8:
78cb7a01acSMauro Carvalho Chehab 		byte |= 0x04;
79cb7a01acSMauro Carvalho Chehab 		break;
80cb7a01acSMauro Carvalho Chehab 	case 3:
81cb7a01acSMauro Carvalho Chehab 		byte |= 0x02;
82cb7a01acSMauro Carvalho Chehab 		break;
83cb7a01acSMauro Carvalho Chehab 	case 20:
84cb7a01acSMauro Carvalho Chehab 		byte |= 0x06;
85cb7a01acSMauro Carvalho Chehab 		break;
86cb7a01acSMauro Carvalho Chehab 	case 6:
87cb7a01acSMauro Carvalho Chehab 		byte |= 0x01;
88cb7a01acSMauro Carvalho Chehab 		break;
89cb7a01acSMauro Carvalho Chehab 	case 10:
90cb7a01acSMauro Carvalho Chehab 		byte |= 0x05;
91cb7a01acSMauro Carvalho Chehab 		break;
92cb7a01acSMauro Carvalho Chehab 	case 1:
93cb7a01acSMauro Carvalho Chehab 		byte |= 0x03;
94cb7a01acSMauro Carvalho Chehab 		break;
95cb7a01acSMauro Carvalho Chehab 	case 11:
96cb7a01acSMauro Carvalho Chehab 		byte |= 0x07;
97cb7a01acSMauro Carvalho Chehab 		break;
983ea0a1d1SPeter Senna Tschudin 	}
99cb7a01acSMauro Carvalho Chehab 
100cb7a01acSMauro Carvalho Chehab 	ret = i2c_smbus_write_byte(client, byte);
101cb7a01acSMauro Carvalho Chehab 	if (ret) {
102cb7a01acSMauro Carvalho Chehab 		v4l2_dbg(1, debug, sd,
103cb7a01acSMauro Carvalho Chehab 			"i2c_smbus_write_byte() failed, ret:%d\n", ret);
104cb7a01acSMauro Carvalho Chehab 		return -EIO;
105cb7a01acSMauro Carvalho Chehab 	}
106cb7a01acSMauro Carvalho Chehab 	return ret;
107cb7a01acSMauro Carvalho Chehab }
108cb7a01acSMauro Carvalho Chehab 
109cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */
110cb7a01acSMauro Carvalho Chehab 
111cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_video_ops tea6415c_video_ops = {
112cb7a01acSMauro Carvalho Chehab 	.s_routing = tea6415c_s_routing,
113cb7a01acSMauro Carvalho Chehab };
114cb7a01acSMauro Carvalho Chehab 
115cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_ops tea6415c_ops = {
116cb7a01acSMauro Carvalho Chehab 	.video = &tea6415c_video_ops,
117cb7a01acSMauro Carvalho Chehab };
118cb7a01acSMauro Carvalho Chehab 
tea6415c_probe(struct i2c_client * client)11940fd1cc9SUwe Kleine-König static int tea6415c_probe(struct i2c_client *client)
120cb7a01acSMauro Carvalho Chehab {
121cb7a01acSMauro Carvalho Chehab 	struct v4l2_subdev *sd;
122cb7a01acSMauro Carvalho Chehab 
123cb7a01acSMauro Carvalho Chehab 	/* let's see whether this adapter can support what we need */
124cb7a01acSMauro Carvalho Chehab 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WRITE_BYTE))
125cb7a01acSMauro Carvalho Chehab 		return -EIO;
126cb7a01acSMauro Carvalho Chehab 
127cb7a01acSMauro Carvalho Chehab 	v4l_info(client, "chip found @ 0x%x (%s)\n",
128cb7a01acSMauro Carvalho Chehab 			client->addr << 1, client->adapter->name);
129c02b211dSLaurent Pinchart 	sd = devm_kzalloc(&client->dev, sizeof(*sd), GFP_KERNEL);
130cb7a01acSMauro Carvalho Chehab 	if (sd == NULL)
131cb7a01acSMauro Carvalho Chehab 		return -ENOMEM;
132cb7a01acSMauro Carvalho Chehab 	v4l2_i2c_subdev_init(sd, client, &tea6415c_ops);
133cb7a01acSMauro Carvalho Chehab 	return 0;
134cb7a01acSMauro Carvalho Chehab }
135cb7a01acSMauro Carvalho Chehab 
tea6415c_remove(struct i2c_client * client)136ed5c2f5fSUwe Kleine-König static void tea6415c_remove(struct i2c_client *client)
137cb7a01acSMauro Carvalho Chehab {
138cb7a01acSMauro Carvalho Chehab 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
139cb7a01acSMauro Carvalho Chehab 
140cb7a01acSMauro Carvalho Chehab 	v4l2_device_unregister_subdev(sd);
141cb7a01acSMauro Carvalho Chehab }
142cb7a01acSMauro Carvalho Chehab 
143cb7a01acSMauro Carvalho Chehab static const struct i2c_device_id tea6415c_id[] = {
144cb7a01acSMauro Carvalho Chehab 	{ "tea6415c", 0 },
145cb7a01acSMauro Carvalho Chehab 	{ }
146cb7a01acSMauro Carvalho Chehab };
147cb7a01acSMauro Carvalho Chehab MODULE_DEVICE_TABLE(i2c, tea6415c_id);
148cb7a01acSMauro Carvalho Chehab 
149cb7a01acSMauro Carvalho Chehab static struct i2c_driver tea6415c_driver = {
150cb7a01acSMauro Carvalho Chehab 	.driver = {
151cb7a01acSMauro Carvalho Chehab 		.name	= "tea6415c",
152cb7a01acSMauro Carvalho Chehab 	},
153*aaeb31c0SUwe Kleine-König 	.probe		= tea6415c_probe,
154cb7a01acSMauro Carvalho Chehab 	.remove		= tea6415c_remove,
155cb7a01acSMauro Carvalho Chehab 	.id_table	= tea6415c_id,
156cb7a01acSMauro Carvalho Chehab };
157cb7a01acSMauro Carvalho Chehab 
158cb7a01acSMauro Carvalho Chehab module_i2c_driver(tea6415c_driver);
159