This source file includes following definitions.
- to_adv7170
- adv7170_write
- adv7170_read
- adv7170_write_block
- adv7170_s_std_output
- adv7170_s_routing
- adv7170_enum_mbus_code
- adv7170_get_fmt
- adv7170_set_fmt
- adv7170_probe
- adv7170_remove
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 #include <linux/module.h>
19 #include <linux/types.h>
20 #include <linux/slab.h>
21 #include <linux/ioctl.h>
22 #include <linux/uaccess.h>
23 #include <linux/i2c.h>
24 #include <linux/videodev2.h>
25 #include <media/v4l2-device.h>
26
27 MODULE_DESCRIPTION("Analog Devices ADV7170 video encoder driver");
28 MODULE_AUTHOR("Maxim Yevtyushkin");
29 MODULE_LICENSE("GPL");
30
31
32 static int debug;
33 module_param(debug, int, 0);
34 MODULE_PARM_DESC(debug, "Debug level (0-1)");
35
36
37
38 struct adv7170 {
39 struct v4l2_subdev sd;
40 unsigned char reg[128];
41
42 v4l2_std_id norm;
43 int input;
44 };
45
46 static inline struct adv7170 *to_adv7170(struct v4l2_subdev *sd)
47 {
48 return container_of(sd, struct adv7170, sd);
49 }
50
51 static char *inputs[] = { "pass_through", "play_back" };
52
53 static u32 adv7170_codes[] = {
54 MEDIA_BUS_FMT_UYVY8_2X8,
55 MEDIA_BUS_FMT_UYVY8_1X16,
56 };
57
58
59
60 static inline int adv7170_write(struct v4l2_subdev *sd, u8 reg, u8 value)
61 {
62 struct i2c_client *client = v4l2_get_subdevdata(sd);
63 struct adv7170 *encoder = to_adv7170(sd);
64
65 encoder->reg[reg] = value;
66 return i2c_smbus_write_byte_data(client, reg, value);
67 }
68
69 static inline int adv7170_read(struct v4l2_subdev *sd, u8 reg)
70 {
71 struct i2c_client *client = v4l2_get_subdevdata(sd);
72
73 return i2c_smbus_read_byte_data(client, reg);
74 }
75
76 static int adv7170_write_block(struct v4l2_subdev *sd,
77 const u8 *data, unsigned int len)
78 {
79 struct i2c_client *client = v4l2_get_subdevdata(sd);
80 struct adv7170 *encoder = to_adv7170(sd);
81 int ret = -1;
82 u8 reg;
83
84
85
86 if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
87
88 u8 block_data[32];
89 int block_len;
90
91 while (len >= 2) {
92 block_len = 0;
93 block_data[block_len++] = reg = data[0];
94 do {
95 block_data[block_len++] =
96 encoder->reg[reg++] = data[1];
97 len -= 2;
98 data += 2;
99 } while (len >= 2 && data[0] == reg && block_len < 32);
100 ret = i2c_master_send(client, block_data, block_len);
101 if (ret < 0)
102 break;
103 }
104 } else {
105
106 while (len >= 2) {
107 reg = *data++;
108 ret = adv7170_write(sd, reg, *data++);
109 if (ret < 0)
110 break;
111 len -= 2;
112 }
113 }
114 return ret;
115 }
116
117
118
119 #define TR0MODE 0x4c
120 #define TR0RST 0x80
121
122 #define TR1CAPT 0x00
123 #define TR1PLAY 0x00
124
125 static const unsigned char init_NTSC[] = {
126 0x00, 0x10,
127 0x01, 0x20,
128 0x02, 0x0e,
129 0x03, 0x80,
130 0x04, 0x30,
131 0x05, 0x00,
132 0x06, 0x00,
133 0x07, TR0MODE,
134 0x08, TR1CAPT,
135 0x09, 0x16,
136 0x0a, 0x7c,
137 0x0b, 0xf0,
138 0x0c, 0x21,
139 0x0d, 0x00,
140 0x0e, 0x00,
141 0x0f, 0x00,
142 0x10, 0x00,
143 0x11, 0x00,
144 0x12, 0x00,
145 0x13, 0x00,
146 0x14, 0x00,
147 0x15, 0x00,
148 0x16, 0x00,
149 0x17, 0x00,
150 0x18, 0x00,
151 0x19, 0x00,
152 };
153
154 static const unsigned char init_PAL[] = {
155 0x00, 0x71,
156 0x01, 0x20,
157 0x02, 0x0e,
158 0x03, 0x80,
159 0x04, 0x30,
160 0x05, 0x00,
161 0x06, 0x00,
162 0x07, TR0MODE,
163 0x08, TR1CAPT,
164 0x09, 0xcb,
165 0x0a, 0x8a,
166 0x0b, 0x09,
167 0x0c, 0x2a,
168 0x0d, 0x00,
169 0x0e, 0x00,
170 0x0f, 0x00,
171 0x10, 0x00,
172 0x11, 0x00,
173 0x12, 0x00,
174 0x13, 0x00,
175 0x14, 0x00,
176 0x15, 0x00,
177 0x16, 0x00,
178 0x17, 0x00,
179 0x18, 0x00,
180 0x19, 0x00,
181 };
182
183
184 static int adv7170_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
185 {
186 struct adv7170 *encoder = to_adv7170(sd);
187
188 v4l2_dbg(1, debug, sd, "set norm %llx\n", (unsigned long long)std);
189
190 if (std & V4L2_STD_NTSC) {
191 adv7170_write_block(sd, init_NTSC, sizeof(init_NTSC));
192 if (encoder->input == 0)
193 adv7170_write(sd, 0x02, 0x0e);
194 adv7170_write(sd, 0x07, TR0MODE | TR0RST);
195 adv7170_write(sd, 0x07, TR0MODE);
196 } else if (std & V4L2_STD_PAL) {
197 adv7170_write_block(sd, init_PAL, sizeof(init_PAL));
198 if (encoder->input == 0)
199 adv7170_write(sd, 0x02, 0x0e);
200 adv7170_write(sd, 0x07, TR0MODE | TR0RST);
201 adv7170_write(sd, 0x07, TR0MODE);
202 } else {
203 v4l2_dbg(1, debug, sd, "illegal norm: %llx\n",
204 (unsigned long long)std);
205 return -EINVAL;
206 }
207 v4l2_dbg(1, debug, sd, "switched to %llx\n", (unsigned long long)std);
208 encoder->norm = std;
209 return 0;
210 }
211
212 static int adv7170_s_routing(struct v4l2_subdev *sd,
213 u32 input, u32 output, u32 config)
214 {
215 struct adv7170 *encoder = to_adv7170(sd);
216
217
218
219
220
221 v4l2_dbg(1, debug, sd, "set input from %s\n",
222 input == 0 ? "decoder" : "ZR36060");
223
224 switch (input) {
225 case 0:
226 adv7170_write(sd, 0x01, 0x20);
227 adv7170_write(sd, 0x08, TR1CAPT);
228 adv7170_write(sd, 0x02, 0x0e);
229 adv7170_write(sd, 0x07, TR0MODE | TR0RST);
230 adv7170_write(sd, 0x07, TR0MODE);
231
232 break;
233
234 case 1:
235 adv7170_write(sd, 0x01, 0x00);
236 adv7170_write(sd, 0x08, TR1PLAY);
237 adv7170_write(sd, 0x02, 0x08);
238 adv7170_write(sd, 0x07, TR0MODE | TR0RST);
239 adv7170_write(sd, 0x07, TR0MODE);
240
241 break;
242
243 default:
244 v4l2_dbg(1, debug, sd, "illegal input: %d\n", input);
245 return -EINVAL;
246 }
247 v4l2_dbg(1, debug, sd, "switched to %s\n", inputs[input]);
248 encoder->input = input;
249 return 0;
250 }
251
252 static int adv7170_enum_mbus_code(struct v4l2_subdev *sd,
253 struct v4l2_subdev_pad_config *cfg,
254 struct v4l2_subdev_mbus_code_enum *code)
255 {
256 if (code->pad || code->index >= ARRAY_SIZE(adv7170_codes))
257 return -EINVAL;
258
259 code->code = adv7170_codes[code->index];
260 return 0;
261 }
262
263 static int adv7170_get_fmt(struct v4l2_subdev *sd,
264 struct v4l2_subdev_pad_config *cfg,
265 struct v4l2_subdev_format *format)
266 {
267 struct v4l2_mbus_framefmt *mf = &format->format;
268 u8 val = adv7170_read(sd, 0x7);
269
270 if (format->pad)
271 return -EINVAL;
272
273 if ((val & 0x40) == (1 << 6))
274 mf->code = MEDIA_BUS_FMT_UYVY8_1X16;
275 else
276 mf->code = MEDIA_BUS_FMT_UYVY8_2X8;
277
278 mf->colorspace = V4L2_COLORSPACE_SMPTE170M;
279 mf->width = 0;
280 mf->height = 0;
281 mf->field = V4L2_FIELD_ANY;
282
283 return 0;
284 }
285
286 static int adv7170_set_fmt(struct v4l2_subdev *sd,
287 struct v4l2_subdev_pad_config *cfg,
288 struct v4l2_subdev_format *format)
289 {
290 struct v4l2_mbus_framefmt *mf = &format->format;
291 u8 val = adv7170_read(sd, 0x7);
292
293 if (format->pad)
294 return -EINVAL;
295
296 switch (mf->code) {
297 case MEDIA_BUS_FMT_UYVY8_2X8:
298 val &= ~0x40;
299 break;
300
301 case MEDIA_BUS_FMT_UYVY8_1X16:
302 val |= 0x40;
303 break;
304
305 default:
306 v4l2_dbg(1, debug, sd,
307 "illegal v4l2_mbus_framefmt code: %d\n", mf->code);
308 return -EINVAL;
309 }
310
311 if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
312 return adv7170_write(sd, 0x7, val);
313
314 return 0;
315 }
316
317
318
319 static const struct v4l2_subdev_video_ops adv7170_video_ops = {
320 .s_std_output = adv7170_s_std_output,
321 .s_routing = adv7170_s_routing,
322 };
323
324 static const struct v4l2_subdev_pad_ops adv7170_pad_ops = {
325 .enum_mbus_code = adv7170_enum_mbus_code,
326 .get_fmt = adv7170_get_fmt,
327 .set_fmt = adv7170_set_fmt,
328 };
329
330 static const struct v4l2_subdev_ops adv7170_ops = {
331 .video = &adv7170_video_ops,
332 .pad = &adv7170_pad_ops,
333 };
334
335
336
337 static int adv7170_probe(struct i2c_client *client,
338 const struct i2c_device_id *id)
339 {
340 struct adv7170 *encoder;
341 struct v4l2_subdev *sd;
342 int i;
343
344
345 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
346 return -ENODEV;
347
348 v4l_info(client, "chip found @ 0x%x (%s)\n",
349 client->addr << 1, client->adapter->name);
350
351 encoder = devm_kzalloc(&client->dev, sizeof(*encoder), GFP_KERNEL);
352 if (encoder == NULL)
353 return -ENOMEM;
354 sd = &encoder->sd;
355 v4l2_i2c_subdev_init(sd, client, &adv7170_ops);
356 encoder->norm = V4L2_STD_NTSC;
357 encoder->input = 0;
358
359 i = adv7170_write_block(sd, init_NTSC, sizeof(init_NTSC));
360 if (i >= 0) {
361 i = adv7170_write(sd, 0x07, TR0MODE | TR0RST);
362 i = adv7170_write(sd, 0x07, TR0MODE);
363 i = adv7170_read(sd, 0x12);
364 v4l2_dbg(1, debug, sd, "revision %d\n", i & 1);
365 }
366 if (i < 0)
367 v4l2_dbg(1, debug, sd, "init error 0x%x\n", i);
368 return 0;
369 }
370
371 static int adv7170_remove(struct i2c_client *client)
372 {
373 struct v4l2_subdev *sd = i2c_get_clientdata(client);
374
375 v4l2_device_unregister_subdev(sd);
376 return 0;
377 }
378
379
380
381 static const struct i2c_device_id adv7170_id[] = {
382 { "adv7170", 0 },
383 { "adv7171", 0 },
384 { }
385 };
386 MODULE_DEVICE_TABLE(i2c, adv7170_id);
387
388 static struct i2c_driver adv7170_driver = {
389 .driver = {
390 .name = "adv7170",
391 },
392 .probe = adv7170_probe,
393 .remove = adv7170_remove,
394 .id_table = adv7170_id,
395 };
396
397 module_i2c_driver(adv7170_driver);