xref: /openbmc/linux/drivers/media/i2c/bt866.c (revision c02b211d)
1cb7a01acSMauro Carvalho Chehab /*
2cb7a01acSMauro Carvalho Chehab     bt866 - BT866 Digital Video Encoder (Rockwell Part)
3cb7a01acSMauro Carvalho Chehab 
4cb7a01acSMauro Carvalho Chehab     Copyright (C) 1999 Mike Bernson <mike@mlb.org>
5cb7a01acSMauro Carvalho Chehab     Copyright (C) 1998 Dave Perks <dperks@ibm.net>
6cb7a01acSMauro Carvalho Chehab 
7cb7a01acSMauro Carvalho Chehab     Modifications for LML33/DC10plus unified driver
8cb7a01acSMauro Carvalho Chehab     Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
9cb7a01acSMauro Carvalho Chehab 
10cb7a01acSMauro Carvalho Chehab     This code was modify/ported from the saa7111 driver written
11cb7a01acSMauro Carvalho Chehab     by Dave Perks.
12cb7a01acSMauro Carvalho Chehab 
13cb7a01acSMauro Carvalho Chehab     This code was adapted for the bt866 by Christer Weinigel and ported
14cb7a01acSMauro Carvalho Chehab     to 2.6 by Martin Samuelsson.
15cb7a01acSMauro Carvalho Chehab 
16cb7a01acSMauro Carvalho Chehab     This program is free software; you can redistribute it and/or modify
17cb7a01acSMauro Carvalho Chehab     it under the terms of the GNU General Public License as published by
18cb7a01acSMauro Carvalho Chehab     the Free Software Foundation; either version 2 of the License, or
19cb7a01acSMauro Carvalho Chehab     (at your option) any later version.
20cb7a01acSMauro Carvalho Chehab 
21cb7a01acSMauro Carvalho Chehab     This program is distributed in the hope that it will be useful,
22cb7a01acSMauro Carvalho Chehab     but WITHOUT ANY WARRANTY; without even the implied warranty of
23cb7a01acSMauro Carvalho Chehab     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24cb7a01acSMauro Carvalho Chehab     GNU General Public License for more details.
25cb7a01acSMauro Carvalho Chehab 
26cb7a01acSMauro Carvalho Chehab     You should have received a copy of the GNU General Public License
27cb7a01acSMauro Carvalho Chehab     along with this program; if not, write to the Free Software
28cb7a01acSMauro Carvalho Chehab     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29cb7a01acSMauro Carvalho Chehab */
30cb7a01acSMauro Carvalho Chehab 
31cb7a01acSMauro Carvalho Chehab #include <linux/module.h>
32cb7a01acSMauro Carvalho Chehab #include <linux/types.h>
33cb7a01acSMauro Carvalho Chehab #include <linux/slab.h>
34cb7a01acSMauro Carvalho Chehab #include <linux/ioctl.h>
35cb7a01acSMauro Carvalho Chehab #include <asm/uaccess.h>
36cb7a01acSMauro Carvalho Chehab #include <linux/i2c.h>
37cb7a01acSMauro Carvalho Chehab #include <linux/videodev2.h>
38cb7a01acSMauro Carvalho Chehab #include <media/v4l2-device.h>
39cb7a01acSMauro Carvalho Chehab #include <media/v4l2-chip-ident.h>
40cb7a01acSMauro Carvalho Chehab 
41cb7a01acSMauro Carvalho Chehab MODULE_DESCRIPTION("Brooktree-866 video encoder driver");
42cb7a01acSMauro Carvalho Chehab MODULE_AUTHOR("Mike Bernson & Dave Perks");
43cb7a01acSMauro Carvalho Chehab MODULE_LICENSE("GPL");
44cb7a01acSMauro Carvalho Chehab 
45cb7a01acSMauro Carvalho Chehab static int debug;
46cb7a01acSMauro Carvalho Chehab module_param(debug, int, 0);
47cb7a01acSMauro Carvalho Chehab MODULE_PARM_DESC(debug, "Debug level (0-1)");
48cb7a01acSMauro Carvalho Chehab 
49cb7a01acSMauro Carvalho Chehab 
50cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */
51cb7a01acSMauro Carvalho Chehab 
52cb7a01acSMauro Carvalho Chehab struct bt866 {
53cb7a01acSMauro Carvalho Chehab 	struct v4l2_subdev sd;
54cb7a01acSMauro Carvalho Chehab 	u8 reg[256];
55cb7a01acSMauro Carvalho Chehab };
56cb7a01acSMauro Carvalho Chehab 
57cb7a01acSMauro Carvalho Chehab static inline struct bt866 *to_bt866(struct v4l2_subdev *sd)
58cb7a01acSMauro Carvalho Chehab {
59cb7a01acSMauro Carvalho Chehab 	return container_of(sd, struct bt866, sd);
60cb7a01acSMauro Carvalho Chehab }
61cb7a01acSMauro Carvalho Chehab 
62cb7a01acSMauro Carvalho Chehab static int bt866_write(struct bt866 *encoder, u8 subaddr, u8 data)
63cb7a01acSMauro Carvalho Chehab {
64cb7a01acSMauro Carvalho Chehab 	struct i2c_client *client = v4l2_get_subdevdata(&encoder->sd);
65cb7a01acSMauro Carvalho Chehab 	u8 buffer[2];
66cb7a01acSMauro Carvalho Chehab 	int err;
67cb7a01acSMauro Carvalho Chehab 
68cb7a01acSMauro Carvalho Chehab 	buffer[0] = subaddr;
69cb7a01acSMauro Carvalho Chehab 	buffer[1] = data;
70cb7a01acSMauro Carvalho Chehab 
71cb7a01acSMauro Carvalho Chehab 	encoder->reg[subaddr] = data;
72cb7a01acSMauro Carvalho Chehab 
73cb7a01acSMauro Carvalho Chehab 	v4l_dbg(1, debug, client, "write 0x%02x = 0x%02x\n", subaddr, data);
74cb7a01acSMauro Carvalho Chehab 
75cb7a01acSMauro Carvalho Chehab 	for (err = 0; err < 3;) {
76cb7a01acSMauro Carvalho Chehab 		if (i2c_master_send(client, buffer, 2) == 2)
77cb7a01acSMauro Carvalho Chehab 			break;
78cb7a01acSMauro Carvalho Chehab 		err++;
79cb7a01acSMauro Carvalho Chehab 		v4l_warn(client, "error #%d writing to 0x%02x\n",
80cb7a01acSMauro Carvalho Chehab 				err, subaddr);
81cb7a01acSMauro Carvalho Chehab 		schedule_timeout_interruptible(msecs_to_jiffies(100));
82cb7a01acSMauro Carvalho Chehab 	}
83cb7a01acSMauro Carvalho Chehab 	if (err == 3) {
84cb7a01acSMauro Carvalho Chehab 		v4l_warn(client, "giving up\n");
85cb7a01acSMauro Carvalho Chehab 		return -1;
86cb7a01acSMauro Carvalho Chehab 	}
87cb7a01acSMauro Carvalho Chehab 
88cb7a01acSMauro Carvalho Chehab 	return 0;
89cb7a01acSMauro Carvalho Chehab }
90cb7a01acSMauro Carvalho Chehab 
91cb7a01acSMauro Carvalho Chehab static int bt866_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
92cb7a01acSMauro Carvalho Chehab {
93cb7a01acSMauro Carvalho Chehab 	v4l2_dbg(1, debug, sd, "set norm %llx\n", (unsigned long long)std);
94cb7a01acSMauro Carvalho Chehab 
95cb7a01acSMauro Carvalho Chehab 	/* Only PAL supported by this driver at the moment! */
96cb7a01acSMauro Carvalho Chehab 	if (!(std & V4L2_STD_NTSC))
97cb7a01acSMauro Carvalho Chehab 		return -EINVAL;
98cb7a01acSMauro Carvalho Chehab 	return 0;
99cb7a01acSMauro Carvalho Chehab }
100cb7a01acSMauro Carvalho Chehab 
101cb7a01acSMauro Carvalho Chehab static int bt866_s_routing(struct v4l2_subdev *sd,
102cb7a01acSMauro Carvalho Chehab 			   u32 input, u32 output, u32 config)
103cb7a01acSMauro Carvalho Chehab {
104cb7a01acSMauro Carvalho Chehab 	static const __u8 init[] = {
105cb7a01acSMauro Carvalho Chehab 		0xc8, 0xcc, /* CRSCALE */
106cb7a01acSMauro Carvalho Chehab 		0xca, 0x91, /* CBSCALE */
107cb7a01acSMauro Carvalho Chehab 		0xcc, 0x24, /* YC16 | OSDNUM */
108cb7a01acSMauro Carvalho Chehab 		0xda, 0x00, /*  */
109cb7a01acSMauro Carvalho Chehab 		0xdc, 0x24, /* SETMODE | PAL */
110cb7a01acSMauro Carvalho Chehab 		0xde, 0x02, /* EACTIVE */
111cb7a01acSMauro Carvalho Chehab 
112cb7a01acSMauro Carvalho Chehab 		/* overlay colors */
113cb7a01acSMauro Carvalho Chehab 		0x70, 0xEB, 0x90, 0x80, 0xB0, 0x80, /* white */
114cb7a01acSMauro Carvalho Chehab 		0x72, 0xA2, 0x92, 0x8E, 0xB2, 0x2C, /* yellow */
115cb7a01acSMauro Carvalho Chehab 		0x74, 0x83, 0x94, 0x2C, 0xB4, 0x9C, /* cyan */
116cb7a01acSMauro Carvalho Chehab 		0x76, 0x70, 0x96, 0x3A, 0xB6, 0x48, /* green */
117cb7a01acSMauro Carvalho Chehab 		0x78, 0x54, 0x98, 0xC6, 0xB8, 0xB8, /* magenta */
118cb7a01acSMauro Carvalho Chehab 		0x7A, 0x41, 0x9A, 0xD4, 0xBA, 0x64, /* red */
119cb7a01acSMauro Carvalho Chehab 		0x7C, 0x23, 0x9C, 0x72, 0xBC, 0xD4, /* blue */
120cb7a01acSMauro Carvalho Chehab 		0x7E, 0x10, 0x9E, 0x80, 0xBE, 0x80, /* black */
121cb7a01acSMauro Carvalho Chehab 
122cb7a01acSMauro Carvalho Chehab 		0x60, 0xEB, 0x80, 0x80, 0xc0, 0x80, /* white */
123cb7a01acSMauro Carvalho Chehab 		0x62, 0xA2, 0x82, 0x8E, 0xc2, 0x2C, /* yellow */
124cb7a01acSMauro Carvalho Chehab 		0x64, 0x83, 0x84, 0x2C, 0xc4, 0x9C, /* cyan */
125cb7a01acSMauro Carvalho Chehab 		0x66, 0x70, 0x86, 0x3A, 0xc6, 0x48, /* green */
126cb7a01acSMauro Carvalho Chehab 		0x68, 0x54, 0x88, 0xC6, 0xc8, 0xB8, /* magenta */
127cb7a01acSMauro Carvalho Chehab 		0x6A, 0x41, 0x8A, 0xD4, 0xcA, 0x64, /* red */
128cb7a01acSMauro Carvalho Chehab 		0x6C, 0x23, 0x8C, 0x72, 0xcC, 0xD4, /* blue */
129cb7a01acSMauro Carvalho Chehab 		0x6E, 0x10, 0x8E, 0x80, 0xcE, 0x80, /* black */
130cb7a01acSMauro Carvalho Chehab 	};
131cb7a01acSMauro Carvalho Chehab 	struct bt866 *encoder = to_bt866(sd);
132cb7a01acSMauro Carvalho Chehab 	u8 val;
133cb7a01acSMauro Carvalho Chehab 	int i;
134cb7a01acSMauro Carvalho Chehab 
135cb7a01acSMauro Carvalho Chehab 	for (i = 0; i < ARRAY_SIZE(init) / 2; i += 2)
136cb7a01acSMauro Carvalho Chehab 		bt866_write(encoder, init[i], init[i+1]);
137cb7a01acSMauro Carvalho Chehab 
138cb7a01acSMauro Carvalho Chehab 	val = encoder->reg[0xdc];
139cb7a01acSMauro Carvalho Chehab 
140cb7a01acSMauro Carvalho Chehab 	if (input == 0)
141cb7a01acSMauro Carvalho Chehab 		val |= 0x40; /* CBSWAP */
142cb7a01acSMauro Carvalho Chehab 	else
143cb7a01acSMauro Carvalho Chehab 		val &= ~0x40; /* !CBSWAP */
144cb7a01acSMauro Carvalho Chehab 
145cb7a01acSMauro Carvalho Chehab 	bt866_write(encoder, 0xdc, val);
146cb7a01acSMauro Carvalho Chehab 
147cb7a01acSMauro Carvalho Chehab 	val = encoder->reg[0xcc];
148cb7a01acSMauro Carvalho Chehab 	if (input == 2)
149cb7a01acSMauro Carvalho Chehab 		val |= 0x01; /* OSDBAR */
150cb7a01acSMauro Carvalho Chehab 	else
151cb7a01acSMauro Carvalho Chehab 		val &= ~0x01; /* !OSDBAR */
152cb7a01acSMauro Carvalho Chehab 	bt866_write(encoder, 0xcc, val);
153cb7a01acSMauro Carvalho Chehab 
154cb7a01acSMauro Carvalho Chehab 	v4l2_dbg(1, debug, sd, "set input %d\n", input);
155cb7a01acSMauro Carvalho Chehab 
156cb7a01acSMauro Carvalho Chehab 	switch (input) {
157cb7a01acSMauro Carvalho Chehab 	case 0:
158cb7a01acSMauro Carvalho Chehab 	case 1:
159cb7a01acSMauro Carvalho Chehab 	case 2:
160cb7a01acSMauro Carvalho Chehab 		break;
161cb7a01acSMauro Carvalho Chehab 	default:
162cb7a01acSMauro Carvalho Chehab 		return -EINVAL;
163cb7a01acSMauro Carvalho Chehab 	}
164cb7a01acSMauro Carvalho Chehab 	return 0;
165cb7a01acSMauro Carvalho Chehab }
166cb7a01acSMauro Carvalho Chehab 
167cb7a01acSMauro Carvalho Chehab #if 0
168cb7a01acSMauro Carvalho Chehab /* Code to setup square pixels, might be of some use in the future,
169cb7a01acSMauro Carvalho Chehab    but is currently unused. */
170cb7a01acSMauro Carvalho Chehab 	val = encoder->reg[0xdc];
171cb7a01acSMauro Carvalho Chehab 	if (*iarg)
172cb7a01acSMauro Carvalho Chehab 		val |= 1; /* SQUARE */
173cb7a01acSMauro Carvalho Chehab 	else
174cb7a01acSMauro Carvalho Chehab 		val &= ~1; /* !SQUARE */
175cb7a01acSMauro Carvalho Chehab 	bt866_write(client, 0xdc, val);
176cb7a01acSMauro Carvalho Chehab #endif
177cb7a01acSMauro Carvalho Chehab 
178cb7a01acSMauro Carvalho Chehab static int bt866_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
179cb7a01acSMauro Carvalho Chehab {
180cb7a01acSMauro Carvalho Chehab 	struct i2c_client *client = v4l2_get_subdevdata(sd);
181cb7a01acSMauro Carvalho Chehab 
182cb7a01acSMauro Carvalho Chehab 	return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_BT866, 0);
183cb7a01acSMauro Carvalho Chehab }
184cb7a01acSMauro Carvalho Chehab 
185cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */
186cb7a01acSMauro Carvalho Chehab 
187cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_core_ops bt866_core_ops = {
188cb7a01acSMauro Carvalho Chehab 	.g_chip_ident = bt866_g_chip_ident,
189cb7a01acSMauro Carvalho Chehab };
190cb7a01acSMauro Carvalho Chehab 
191cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_video_ops bt866_video_ops = {
192cb7a01acSMauro Carvalho Chehab 	.s_std_output = bt866_s_std_output,
193cb7a01acSMauro Carvalho Chehab 	.s_routing = bt866_s_routing,
194cb7a01acSMauro Carvalho Chehab };
195cb7a01acSMauro Carvalho Chehab 
196cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_ops bt866_ops = {
197cb7a01acSMauro Carvalho Chehab 	.core = &bt866_core_ops,
198cb7a01acSMauro Carvalho Chehab 	.video = &bt866_video_ops,
199cb7a01acSMauro Carvalho Chehab };
200cb7a01acSMauro Carvalho Chehab 
201cb7a01acSMauro Carvalho Chehab static int bt866_probe(struct i2c_client *client,
202cb7a01acSMauro Carvalho Chehab 			const struct i2c_device_id *id)
203cb7a01acSMauro Carvalho Chehab {
204cb7a01acSMauro Carvalho Chehab 	struct bt866 *encoder;
205cb7a01acSMauro Carvalho Chehab 	struct v4l2_subdev *sd;
206cb7a01acSMauro Carvalho Chehab 
207cb7a01acSMauro Carvalho Chehab 	v4l_info(client, "chip found @ 0x%x (%s)\n",
208cb7a01acSMauro Carvalho Chehab 			client->addr << 1, client->adapter->name);
209cb7a01acSMauro Carvalho Chehab 
210c02b211dSLaurent Pinchart 	encoder = devm_kzalloc(&client->dev, sizeof(*encoder), GFP_KERNEL);
211cb7a01acSMauro Carvalho Chehab 	if (encoder == NULL)
212cb7a01acSMauro Carvalho Chehab 		return -ENOMEM;
213cb7a01acSMauro Carvalho Chehab 	sd = &encoder->sd;
214cb7a01acSMauro Carvalho Chehab 	v4l2_i2c_subdev_init(sd, client, &bt866_ops);
215cb7a01acSMauro Carvalho Chehab 	return 0;
216cb7a01acSMauro Carvalho Chehab }
217cb7a01acSMauro Carvalho Chehab 
218cb7a01acSMauro Carvalho Chehab static int bt866_remove(struct i2c_client *client)
219cb7a01acSMauro Carvalho Chehab {
220cb7a01acSMauro Carvalho Chehab 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
221cb7a01acSMauro Carvalho Chehab 
222cb7a01acSMauro Carvalho Chehab 	v4l2_device_unregister_subdev(sd);
223cb7a01acSMauro Carvalho Chehab 	return 0;
224cb7a01acSMauro Carvalho Chehab }
225cb7a01acSMauro Carvalho Chehab 
226cb7a01acSMauro Carvalho Chehab static const struct i2c_device_id bt866_id[] = {
227cb7a01acSMauro Carvalho Chehab 	{ "bt866", 0 },
228cb7a01acSMauro Carvalho Chehab 	{ }
229cb7a01acSMauro Carvalho Chehab };
230cb7a01acSMauro Carvalho Chehab MODULE_DEVICE_TABLE(i2c, bt866_id);
231cb7a01acSMauro Carvalho Chehab 
232cb7a01acSMauro Carvalho Chehab static struct i2c_driver bt866_driver = {
233cb7a01acSMauro Carvalho Chehab 	.driver = {
234cb7a01acSMauro Carvalho Chehab 		.owner	= THIS_MODULE,
235cb7a01acSMauro Carvalho Chehab 		.name	= "bt866",
236cb7a01acSMauro Carvalho Chehab 	},
237cb7a01acSMauro Carvalho Chehab 	.probe		= bt866_probe,
238cb7a01acSMauro Carvalho Chehab 	.remove		= bt866_remove,
239cb7a01acSMauro Carvalho Chehab 	.id_table	= bt866_id,
240cb7a01acSMauro Carvalho Chehab };
241cb7a01acSMauro Carvalho Chehab 
242cb7a01acSMauro Carvalho Chehab module_i2c_driver(bt866_driver);
243