1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31#include <linux/module.h>
32#include <linux/types.h>
33#include <linux/ioctl.h>
34#include <asm/uaccess.h>
35#include <linux/i2c.h>
36#include <linux/i2c-id.h>
37#include <linux/videodev.h>
38#include <linux/video_encoder.h>
39#include <media/v4l2-common.h>
40#include <media/v4l2-i2c-drv-legacy.h>
41
42MODULE_DESCRIPTION("Analog Devices ADV7170 video encoder driver");
43MODULE_AUTHOR("Maxim Yevtyushkin");
44MODULE_LICENSE("GPL");
45
46static int debug;
47module_param(debug, int, 0);
48MODULE_PARM_DESC(debug, "Debug level (0-1)");
49
50
51
52struct adv7170 {
53 unsigned char reg[128];
54
55 int norm;
56 int input;
57 int enable;
58 int bright;
59 int contrast;
60 int hue;
61 int sat;
62};
63
64static char *inputs[] = { "pass_through", "play_back" };
65static char *norms[] = { "PAL", "NTSC" };
66
67
68
69static inline int adv7170_write(struct i2c_client *client, u8 reg, u8 value)
70{
71 struct adv7170 *encoder = i2c_get_clientdata(client);
72
73 encoder->reg[reg] = value;
74 return i2c_smbus_write_byte_data(client, reg, value);
75}
76
77static inline int adv7170_read(struct i2c_client *client, u8 reg)
78{
79 return i2c_smbus_read_byte_data(client, reg);
80}
81
82static int adv7170_write_block(struct i2c_client *client,
83 const u8 *data, unsigned int len)
84{
85 int ret = -1;
86 u8 reg;
87
88
89
90 if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
91
92 struct adv7170 *encoder = i2c_get_clientdata(client);
93 u8 block_data[32];
94 int block_len;
95
96 while (len >= 2) {
97 block_len = 0;
98 block_data[block_len++] = reg = data[0];
99 do {
100 block_data[block_len++] =
101 encoder->reg[reg++] = data[1];
102 len -= 2;
103 data += 2;
104 } while (len >= 2 && data[0] == reg && block_len < 32);
105 ret = i2c_master_send(client, block_data, block_len);
106 if (ret < 0)
107 break;
108 }
109 } else {
110
111 while (len >= 2) {
112 reg = *data++;
113 ret = adv7170_write(client, reg, *data++);
114 if (ret < 0)
115 break;
116 len -= 2;
117 }
118 }
119 return ret;
120}
121
122
123
124#define TR0MODE 0x4c
125#define TR0RST 0x80
126
127#define TR1CAPT 0x00
128#define TR1PLAY 0x00
129
130static const unsigned char init_NTSC[] = {
131 0x00, 0x10,
132 0x01, 0x20,
133 0x02, 0x0e,
134 0x03, 0x80,
135 0x04, 0x30,
136 0x05, 0x00,
137 0x06, 0x00,
138 0x07, TR0MODE,
139 0x08, TR1CAPT,
140 0x09, 0x16,
141 0x0a, 0x7c,
142 0x0b, 0xf0,
143 0x0c, 0x21,
144 0x0d, 0x00,
145 0x0e, 0x00,
146 0x0f, 0x00,
147 0x10, 0x00,
148 0x11, 0x00,
149 0x12, 0x00,
150 0x13, 0x00,
151 0x14, 0x00,
152 0x15, 0x00,
153 0x16, 0x00,
154 0x17, 0x00,
155 0x18, 0x00,
156 0x19, 0x00,
157};
158
159static const unsigned char init_PAL[] = {
160 0x00, 0x71,
161 0x01, 0x20,
162 0x02, 0x0e,
163 0x03, 0x80,
164 0x04, 0x30,
165 0x05, 0x00,
166 0x06, 0x00,
167 0x07, TR0MODE,
168 0x08, TR1CAPT,
169 0x09, 0xcb,
170 0x0a, 0x8a,
171 0x0b, 0x09,
172 0x0c, 0x2a,
173 0x0d, 0x00,
174 0x0e, 0x00,
175 0x0f, 0x00,
176 0x10, 0x00,
177 0x11, 0x00,
178 0x12, 0x00,
179 0x13, 0x00,
180 0x14, 0x00,
181 0x15, 0x00,
182 0x16, 0x00,
183 0x17, 0x00,
184 0x18, 0x00,
185 0x19, 0x00,
186};
187
188
189static int adv7170_command(struct i2c_client *client, unsigned cmd, void *arg)
190{
191 struct adv7170 *encoder = i2c_get_clientdata(client);
192
193 switch (cmd) {
194 case 0:
195#if 0
196
197 adv7170_write_block(client, init_common,
198 sizeof(init_common));
199 adv7170_write(client, 0x07, TR0MODE | TR0RST);
200 adv7170_write(client, 0x07, TR0MODE);
201#endif
202 break;
203
204 case ENCODER_GET_CAPABILITIES:
205 {
206 struct video_encoder_capability *cap = arg;
207
208 cap->flags = VIDEO_ENCODER_PAL |
209 VIDEO_ENCODER_NTSC;
210 cap->inputs = 2;
211 cap->outputs = 1;
212 break;
213 }
214
215 case ENCODER_SET_NORM:
216 {
217 int iarg = *(int *) arg;
218
219 v4l_dbg(1, debug, client, "set norm %d\n", iarg);
220
221 switch (iarg) {
222 case VIDEO_MODE_NTSC:
223 adv7170_write_block(client, init_NTSC,
224 sizeof(init_NTSC));
225 if (encoder->input == 0)
226 adv7170_write(client, 0x02, 0x0e);
227 adv7170_write(client, 0x07, TR0MODE | TR0RST);
228 adv7170_write(client, 0x07, TR0MODE);
229 break;
230
231 case VIDEO_MODE_PAL:
232 adv7170_write_block(client, init_PAL,
233 sizeof(init_PAL));
234 if (encoder->input == 0)
235 adv7170_write(client, 0x02, 0x0e);
236 adv7170_write(client, 0x07, TR0MODE | TR0RST);
237 adv7170_write(client, 0x07, TR0MODE);
238 break;
239
240 default:
241 v4l_dbg(1, debug, client, "illegal norm: %d\n", iarg);
242 return -EINVAL;
243 }
244 v4l_dbg(1, debug, client, "switched to %s\n", norms[iarg]);
245 encoder->norm = iarg;
246 break;
247 }
248
249 case ENCODER_SET_INPUT:
250 {
251 int iarg = *(int *) arg;
252
253
254
255
256
257 v4l_dbg(1, debug, client, "set input from %s\n",
258 iarg == 0 ? "decoder" : "ZR36060");
259
260 switch (iarg) {
261 case 0:
262 adv7170_write(client, 0x01, 0x20);
263 adv7170_write(client, 0x08, TR1CAPT);
264 adv7170_write(client, 0x02, 0x0e);
265 adv7170_write(client, 0x07, TR0MODE | TR0RST);
266 adv7170_write(client, 0x07, TR0MODE);
267
268 break;
269
270 case 1:
271 adv7170_write(client, 0x01, 0x00);
272 adv7170_write(client, 0x08, TR1PLAY);
273 adv7170_write(client, 0x02, 0x08);
274 adv7170_write(client, 0x07, TR0MODE | TR0RST);
275 adv7170_write(client, 0x07, TR0MODE);
276
277 break;
278
279 default:
280 v4l_dbg(1, debug, client, "illegal input: %d\n", iarg);
281 return -EINVAL;
282 }
283 v4l_dbg(1, debug, client, "switched to %s\n", inputs[iarg]);
284 encoder->input = iarg;
285 break;
286 }
287
288 case ENCODER_SET_OUTPUT:
289 {
290 int *iarg = arg;
291
292
293 if (*iarg != 0) {
294 return -EINVAL;
295 }
296 break;
297 }
298
299 case ENCODER_ENABLE_OUTPUT:
300 {
301 int *iarg = arg;
302
303 encoder->enable = !!*iarg;
304 break;
305 }
306
307 default:
308 return -EINVAL;
309 }
310
311 return 0;
312}
313
314
315
316static unsigned short normal_i2c[] = {
317 0xd4 >> 1, 0xd6 >> 1,
318 0x54 >> 1, 0x56 >> 1,
319 I2C_CLIENT_END
320};
321
322I2C_CLIENT_INSMOD;
323
324static int adv7170_probe(struct i2c_client *client,
325 const struct i2c_device_id *id)
326{
327 struct adv7170 *encoder;
328 int i;
329
330
331 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
332 return -ENODEV;
333
334 v4l_info(client, "chip found @ 0x%x (%s)\n",
335 client->addr << 1, client->adapter->name);
336
337 encoder = kzalloc(sizeof(struct adv7170), GFP_KERNEL);
338 if (encoder == NULL)
339 return -ENOMEM;
340 encoder->norm = VIDEO_MODE_NTSC;
341 encoder->input = 0;
342 encoder->enable = 1;
343 i2c_set_clientdata(client, encoder);
344
345 i = adv7170_write_block(client, init_NTSC, sizeof(init_NTSC));
346 if (i >= 0) {
347 i = adv7170_write(client, 0x07, TR0MODE | TR0RST);
348 i = adv7170_write(client, 0x07, TR0MODE);
349 i = adv7170_read(client, 0x12);
350 v4l_dbg(1, debug, client, "revision %d\n", i & 1);
351 }
352 if (i < 0)
353 v4l_dbg(1, debug, client, "init error 0x%x\n", i);
354 return 0;
355}
356
357static int adv7170_remove(struct i2c_client *client)
358{
359 kfree(i2c_get_clientdata(client));
360 return 0;
361}
362
363
364
365static const struct i2c_device_id adv7170_id[] = {
366 { "adv7170", 0 },
367 { "adv7171", 0 },
368 { }
369};
370MODULE_DEVICE_TABLE(i2c, adv7170_id);
371
372static struct v4l2_i2c_driver_data v4l2_i2c_data = {
373 .name = "adv7170",
374 .driverid = I2C_DRIVERID_ADV7170,
375 .command = adv7170_command,
376 .probe = adv7170_probe,
377 .remove = adv7170_remove,
378 .id_table = adv7170_id,
379};
380