blob: 1a8df9f18ffb6cd738cb8ef063a0b57d28dd1c9d [file] [log] [blame]
Thomas Gleixner74ba9202019-05-20 09:19:02 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Martin Samuelssonfbe60da2006-04-27 10:17:00 -03002/*
3 bt866 - BT866 Digital Video Encoder (Rockwell Part)
4
5 Copyright (C) 1999 Mike Bernson <mike@mlb.org>
6 Copyright (C) 1998 Dave Perks <dperks@ibm.net>
7
8 Modifications for LML33/DC10plus unified driver
9 Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
10
11 This code was modify/ported from the saa7111 driver written
12 by Dave Perks.
13
14 This code was adapted for the bt866 by Christer Weinigel and ported
15 to 2.6 by Martin Samuelsson.
16
Martin Samuelssonfbe60da2006-04-27 10:17:00 -030017*/
18
19#include <linux/module.h>
Martin Samuelssonfbe60da2006-04-27 10:17:00 -030020#include <linux/types.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090021#include <linux/slab.h>
Hans Verkuilc18fdcf2008-09-07 07:59:54 -030022#include <linux/ioctl.h>
Linus Torvalds7c0f6ba2016-12-24 11:46:01 -080023#include <linux/uaccess.h>
Hans Verkuilc18fdcf2008-09-07 07:59:54 -030024#include <linux/i2c.h>
Hans Verkuil8e4e1d82009-02-19 04:49:29 -030025#include <linux/videodev2.h>
26#include <media/v4l2-device.h>
Martin Samuelssonfbe60da2006-04-27 10:17:00 -030027
Hans Verkuilc18fdcf2008-09-07 07:59:54 -030028MODULE_DESCRIPTION("Brooktree-866 video encoder driver");
29MODULE_AUTHOR("Mike Bernson & Dave Perks");
Martin Samuelssonfbe60da2006-04-27 10:17:00 -030030MODULE_LICENSE("GPL");
31
Hans Verkuilc18fdcf2008-09-07 07:59:54 -030032static int debug;
33module_param(debug, int, 0);
34MODULE_PARM_DESC(debug, "Debug level (0-1)");
Martin Samuelssonfbe60da2006-04-27 10:17:00 -030035
Hans Verkuil8e4e1d82009-02-19 04:49:29 -030036
Martin Samuelssonfbe60da2006-04-27 10:17:00 -030037/* ----------------------------------------------------------------------- */
38
39struct bt866 {
Hans Verkuil8e4e1d82009-02-19 04:49:29 -030040 struct v4l2_subdev sd;
Hans Verkuilc18fdcf2008-09-07 07:59:54 -030041 u8 reg[256];
Martin Samuelssonfbe60da2006-04-27 10:17:00 -030042};
43
Hans Verkuil8e4e1d82009-02-19 04:49:29 -030044static inline struct bt866 *to_bt866(struct v4l2_subdev *sd)
Martin Samuelssonfbe60da2006-04-27 10:17:00 -030045{
Hans Verkuil8e4e1d82009-02-19 04:49:29 -030046 return container_of(sd, struct bt866, sd);
47}
48
49static int bt866_write(struct bt866 *encoder, u8 subaddr, u8 data)
50{
51 struct i2c_client *client = v4l2_get_subdevdata(&encoder->sd);
Hans Verkuilc18fdcf2008-09-07 07:59:54 -030052 u8 buffer[2];
53 int err;
54
55 buffer[0] = subaddr;
56 buffer[1] = data;
57
58 encoder->reg[subaddr] = data;
59
60 v4l_dbg(1, debug, client, "write 0x%02x = 0x%02x\n", subaddr, data);
61
62 for (err = 0; err < 3;) {
63 if (i2c_master_send(client, buffer, 2) == 2)
64 break;
65 err++;
66 v4l_warn(client, "error #%d writing to 0x%02x\n",
67 err, subaddr);
68 schedule_timeout_interruptible(msecs_to_jiffies(100));
69 }
70 if (err == 3) {
71 v4l_warn(client, "giving up\n");
72 return -1;
73 }
74
75 return 0;
76}
77
Hans Verkuil8e4e1d82009-02-19 04:49:29 -030078static int bt866_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
Hans Verkuilc18fdcf2008-09-07 07:59:54 -030079{
Hans Verkuilcc5cef82009-03-06 10:15:01 -030080 v4l2_dbg(1, debug, sd, "set norm %llx\n", (unsigned long long)std);
Hans Verkuilc18fdcf2008-09-07 07:59:54 -030081
Hans Verkuil8e4e1d82009-02-19 04:49:29 -030082 /* Only PAL supported by this driver at the moment! */
83 if (!(std & V4L2_STD_NTSC))
Martin Samuelssonfbe60da2006-04-27 10:17:00 -030084 return -EINVAL;
Martin Samuelssonfbe60da2006-04-27 10:17:00 -030085 return 0;
86}
87
Hans Verkuil5325b422009-04-02 11:26:22 -030088static int bt866_s_routing(struct v4l2_subdev *sd,
89 u32 input, u32 output, u32 config)
Hans Verkuil8e4e1d82009-02-19 04:49:29 -030090{
91 static const __u8 init[] = {
92 0xc8, 0xcc, /* CRSCALE */
93 0xca, 0x91, /* CBSCALE */
94 0xcc, 0x24, /* YC16 | OSDNUM */
95 0xda, 0x00, /* */
96 0xdc, 0x24, /* SETMODE | PAL */
97 0xde, 0x02, /* EACTIVE */
Martin Samuelssonfbe60da2006-04-27 10:17:00 -030098
Hans Verkuil8e4e1d82009-02-19 04:49:29 -030099 /* overlay colors */
100 0x70, 0xEB, 0x90, 0x80, 0xB0, 0x80, /* white */
101 0x72, 0xA2, 0x92, 0x8E, 0xB2, 0x2C, /* yellow */
102 0x74, 0x83, 0x94, 0x2C, 0xB4, 0x9C, /* cyan */
103 0x76, 0x70, 0x96, 0x3A, 0xB6, 0x48, /* green */
104 0x78, 0x54, 0x98, 0xC6, 0xB8, 0xB8, /* magenta */
105 0x7A, 0x41, 0x9A, 0xD4, 0xBA, 0x64, /* red */
106 0x7C, 0x23, 0x9C, 0x72, 0xBC, 0xD4, /* blue */
107 0x7E, 0x10, 0x9E, 0x80, 0xBE, 0x80, /* black */
108
109 0x60, 0xEB, 0x80, 0x80, 0xc0, 0x80, /* white */
110 0x62, 0xA2, 0x82, 0x8E, 0xc2, 0x2C, /* yellow */
111 0x64, 0x83, 0x84, 0x2C, 0xc4, 0x9C, /* cyan */
112 0x66, 0x70, 0x86, 0x3A, 0xc6, 0x48, /* green */
113 0x68, 0x54, 0x88, 0xC6, 0xc8, 0xB8, /* magenta */
114 0x6A, 0x41, 0x8A, 0xD4, 0xcA, 0x64, /* red */
115 0x6C, 0x23, 0x8C, 0x72, 0xcC, 0xD4, /* blue */
116 0x6E, 0x10, 0x8E, 0x80, 0xcE, 0x80, /* black */
117 };
118 struct bt866 *encoder = to_bt866(sd);
119 u8 val;
120 int i;
121
122 for (i = 0; i < ARRAY_SIZE(init) / 2; i += 2)
123 bt866_write(encoder, init[i], init[i+1]);
124
125 val = encoder->reg[0xdc];
126
Hans Verkuil5325b422009-04-02 11:26:22 -0300127 if (input == 0)
Hans Verkuil8e4e1d82009-02-19 04:49:29 -0300128 val |= 0x40; /* CBSWAP */
129 else
130 val &= ~0x40; /* !CBSWAP */
131
132 bt866_write(encoder, 0xdc, val);
133
134 val = encoder->reg[0xcc];
Hans Verkuil5325b422009-04-02 11:26:22 -0300135 if (input == 2)
Hans Verkuil8e4e1d82009-02-19 04:49:29 -0300136 val |= 0x01; /* OSDBAR */
137 else
138 val &= ~0x01; /* !OSDBAR */
139 bt866_write(encoder, 0xcc, val);
140
Hans Verkuil5325b422009-04-02 11:26:22 -0300141 v4l2_dbg(1, debug, sd, "set input %d\n", input);
Hans Verkuil8e4e1d82009-02-19 04:49:29 -0300142
Hans Verkuil5325b422009-04-02 11:26:22 -0300143 switch (input) {
Hans Verkuil8e4e1d82009-02-19 04:49:29 -0300144 case 0:
145 case 1:
146 case 2:
147 break;
148 default:
149 return -EINVAL;
150 }
151 return 0;
152}
153
154#if 0
155/* Code to setup square pixels, might be of some use in the future,
156 but is currently unused. */
157 val = encoder->reg[0xdc];
158 if (*iarg)
159 val |= 1; /* SQUARE */
160 else
161 val &= ~1; /* !SQUARE */
162 bt866_write(client, 0xdc, val);
163#endif
164
Hans Verkuil8e4e1d82009-02-19 04:49:29 -0300165/* ----------------------------------------------------------------------- */
166
Hans Verkuil8e4e1d82009-02-19 04:49:29 -0300167static const struct v4l2_subdev_video_ops bt866_video_ops = {
168 .s_std_output = bt866_s_std_output,
169 .s_routing = bt866_s_routing,
170};
171
172static const struct v4l2_subdev_ops bt866_ops = {
Hans Verkuil8e4e1d82009-02-19 04:49:29 -0300173 .video = &bt866_video_ops,
174};
Martin Samuelssonfbe60da2006-04-27 10:17:00 -0300175
Hans Verkuilc18fdcf2008-09-07 07:59:54 -0300176static int bt866_probe(struct i2c_client *client,
177 const struct i2c_device_id *id)
Martin Samuelssonfbe60da2006-04-27 10:17:00 -0300178{
179 struct bt866 *encoder;
Hans Verkuil8e4e1d82009-02-19 04:49:29 -0300180 struct v4l2_subdev *sd;
Martin Samuelssonfbe60da2006-04-27 10:17:00 -0300181
Hans Verkuilc18fdcf2008-09-07 07:59:54 -0300182 v4l_info(client, "chip found @ 0x%x (%s)\n",
183 client->addr << 1, client->adapter->name);
Martin Samuelssonfbe60da2006-04-27 10:17:00 -0300184
Laurent Pinchartc02b2112013-05-02 08:29:43 -0300185 encoder = devm_kzalloc(&client->dev, sizeof(*encoder), GFP_KERNEL);
Hans Verkuilc18fdcf2008-09-07 07:59:54 -0300186 if (encoder == NULL)
Martin Samuelssonfbe60da2006-04-27 10:17:00 -0300187 return -ENOMEM;
Hans Verkuil8e4e1d82009-02-19 04:49:29 -0300188 sd = &encoder->sd;
189 v4l2_i2c_subdev_init(sd, client, &bt866_ops);
Martin Samuelssonfbe60da2006-04-27 10:17:00 -0300190 return 0;
191}
192
Hans Verkuilc18fdcf2008-09-07 07:59:54 -0300193static int bt866_remove(struct i2c_client *client)
Martin Samuelssonfbe60da2006-04-27 10:17:00 -0300194{
Hans Verkuil8e4e1d82009-02-19 04:49:29 -0300195 struct v4l2_subdev *sd = i2c_get_clientdata(client);
196
197 v4l2_device_unregister_subdev(sd);
Martin Samuelssonfbe60da2006-04-27 10:17:00 -0300198 return 0;
199}
200
Hans Verkuilc18fdcf2008-09-07 07:59:54 -0300201static const struct i2c_device_id bt866_id[] = {
202 { "bt866", 0 },
203 { }
204};
205MODULE_DEVICE_TABLE(i2c, bt866_id);
Martin Samuelssonfbe60da2006-04-27 10:17:00 -0300206
Hans Verkuil7a49e542010-09-15 15:24:03 -0300207static struct i2c_driver bt866_driver = {
208 .driver = {
Hans Verkuil7a49e542010-09-15 15:24:03 -0300209 .name = "bt866",
210 },
211 .probe = bt866_probe,
212 .remove = bt866_remove,
213 .id_table = bt866_id,
Hans Verkuilc18fdcf2008-09-07 07:59:54 -0300214};
Hans Verkuil7a49e542010-09-15 15:24:03 -0300215
Axel Linc6e8d862012-02-12 06:56:32 -0300216module_i2c_driver(bt866_driver);