treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 61
[linux-block.git] / drivers / media / i2c / bt866.c
CommitLineData
74ba9207 1// SPDX-License-Identifier: GPL-2.0-or-later
fbe60daa
MS
2/*
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
fbe60daa
MS
17*/
18
19#include <linux/module.h>
fbe60daa 20#include <linux/types.h>
5a0e3ad6 21#include <linux/slab.h>
c18fdcf6 22#include <linux/ioctl.h>
7c0f6ba6 23#include <linux/uaccess.h>
fbe60daa 24#include <linux/i2c.h>
8e4e1d80
HV
25#include <linux/videodev2.h>
26#include <media/v4l2-device.h>
fbe60daa 27
c18fdcf6
HV
28MODULE_DESCRIPTION("Brooktree-866 video encoder driver");
29MODULE_AUTHOR("Mike Bernson & Dave Perks");
fbe60daa
MS
30MODULE_LICENSE("GPL");
31
c18fdcf6
HV
32static int debug;
33module_param(debug, int, 0);
34MODULE_PARM_DESC(debug, "Debug level (0-1)");
fbe60daa 35
8e4e1d80 36
fbe60daa
MS
37/* ----------------------------------------------------------------------- */
38
39struct bt866 {
8e4e1d80 40 struct v4l2_subdev sd;
c18fdcf6 41 u8 reg[256];
fbe60daa
MS
42};
43
8e4e1d80 44static inline struct bt866 *to_bt866(struct v4l2_subdev *sd)
c18fdcf6 45{
8e4e1d80
HV
46 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);
c18fdcf6
HV
52 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}
fbe60daa 77
8e4e1d80 78static int bt866_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
fbe60daa 79{
cc5cef8e 80 v4l2_dbg(1, debug, sd, "set norm %llx\n", (unsigned long long)std);
fbe60daa 81
8e4e1d80
HV
82 /* Only PAL supported by this driver at the moment! */
83 if (!(std & V4L2_STD_NTSC))
84 return -EINVAL;
85 return 0;
86}
fbe60daa 87
5325b427
HV
88static int bt866_s_routing(struct v4l2_subdev *sd,
89 u32 input, u32 output, u32 config)
8e4e1d80
HV
90{
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 */
98
99 /* 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
5325b427 127 if (input == 0)
8e4e1d80
HV
128 val |= 0x40; /* CBSWAP */
129 else
130 val &= ~0x40; /* !CBSWAP */
131
132 bt866_write(encoder, 0xdc, val);
133
134 val = encoder->reg[0xcc];
5325b427 135 if (input == 2)
8e4e1d80
HV
136 val |= 0x01; /* OSDBAR */
137 else
138 val &= ~0x01; /* !OSDBAR */
139 bt866_write(encoder, 0xcc, val);
140
5325b427 141 v4l2_dbg(1, debug, sd, "set input %d\n", input);
8e4e1d80 142
5325b427 143 switch (input) {
8e4e1d80
HV
144 case 0:
145 case 1:
146 case 2:
c18fdcf6 147 break;
8e4e1d80
HV
148 default:
149 return -EINVAL;
fbe60daa 150 }
8e4e1d80
HV
151 return 0;
152}
fbe60daa 153
8e4e1d80
HV
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
8e4e1d80 165/* ----------------------------------------------------------------------- */
fbe60daa 166
8e4e1d80
HV
167static const struct v4l2_subdev_video_ops bt866_video_ops = {
168 .s_std_output = bt866_s_std_output,
169 .s_routing = bt866_s_routing,
170};
fbe60daa 171
8e4e1d80 172static const struct v4l2_subdev_ops bt866_ops = {
8e4e1d80
HV
173 .video = &bt866_video_ops,
174};
fbe60daa 175
c18fdcf6
HV
176static int bt866_probe(struct i2c_client *client,
177 const struct i2c_device_id *id)
fbe60daa
MS
178{
179 struct bt866 *encoder;
8e4e1d80 180 struct v4l2_subdev *sd;
fbe60daa 181
c18fdcf6
HV
182 v4l_info(client, "chip found @ 0x%x (%s)\n",
183 client->addr << 1, client->adapter->name);
fbe60daa 184
c02b211d 185 encoder = devm_kzalloc(&client->dev, sizeof(*encoder), GFP_KERNEL);
c18fdcf6 186 if (encoder == NULL)
fbe60daa 187 return -ENOMEM;
8e4e1d80
HV
188 sd = &encoder->sd;
189 v4l2_i2c_subdev_init(sd, client, &bt866_ops);
fbe60daa
MS
190 return 0;
191}
192
c18fdcf6 193static int bt866_remove(struct i2c_client *client)
fbe60daa 194{
8e4e1d80
HV
195 struct v4l2_subdev *sd = i2c_get_clientdata(client);
196
197 v4l2_device_unregister_subdev(sd);
fbe60daa
MS
198 return 0;
199}
200
c18fdcf6
HV
201static const struct i2c_device_id bt866_id[] = {
202 { "bt866", 0 },
203 { }
204};
205MODULE_DEVICE_TABLE(i2c, bt866_id);
206
7a49e540
HV
207static struct i2c_driver bt866_driver = {
208 .driver = {
7a49e540
HV
209 .name = "bt866",
210 },
211 .probe = bt866_probe,
212 .remove = bt866_remove,
213 .id_table = bt866_id,
c18fdcf6 214};
7a49e540 215
c6e8d86f 216module_i2c_driver(bt866_driver);