aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/adv7170.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/adv7170.c')
-rw-r--r--drivers/media/video/adv7170.c354
1 files changed, 159 insertions, 195 deletions
diff --git a/drivers/media/video/adv7170.c b/drivers/media/video/adv7170.c
index e0eb4f321442..873c30a41bd7 100644
--- a/drivers/media/video/adv7170.c
+++ b/drivers/media/video/adv7170.c
@@ -34,15 +34,16 @@
34#include <asm/uaccess.h> 34#include <asm/uaccess.h>
35#include <linux/i2c.h> 35#include <linux/i2c.h>
36#include <linux/i2c-id.h> 36#include <linux/i2c-id.h>
37#include <linux/videodev.h> 37#include <linux/videodev2.h>
38#include <linux/video_encoder.h> 38#include <media/v4l2-device.h>
39#include <media/v4l2-common.h> 39#include <media/v4l2-chip-ident.h>
40#include <media/v4l2-i2c-drv-legacy.h> 40#include <media/v4l2-i2c-drv.h>
41 41
42MODULE_DESCRIPTION("Analog Devices ADV7170 video encoder driver"); 42MODULE_DESCRIPTION("Analog Devices ADV7170 video encoder driver");
43MODULE_AUTHOR("Maxim Yevtyushkin"); 43MODULE_AUTHOR("Maxim Yevtyushkin");
44MODULE_LICENSE("GPL"); 44MODULE_LICENSE("GPL");
45 45
46
46static int debug; 47static int debug;
47module_param(debug, int, 0); 48module_param(debug, int, 0);
48MODULE_PARM_DESC(debug, "Debug level (0-1)"); 49MODULE_PARM_DESC(debug, "Debug level (0-1)");
@@ -50,38 +51,43 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)");
50/* ----------------------------------------------------------------------- */ 51/* ----------------------------------------------------------------------- */
51 52
52struct adv7170 { 53struct adv7170 {
54 struct v4l2_subdev sd;
53 unsigned char reg[128]; 55 unsigned char reg[128];
54 56
55 int norm; 57 v4l2_std_id norm;
56 int input; 58 int input;
57 int enable;
58 int bright;
59 int contrast;
60 int hue;
61 int sat;
62}; 59};
63 60
61static inline struct adv7170 *to_adv7170(struct v4l2_subdev *sd)
62{
63 return container_of(sd, struct adv7170, sd);
64}
65
64static char *inputs[] = { "pass_through", "play_back" }; 66static char *inputs[] = { "pass_through", "play_back" };
65static char *norms[] = { "PAL", "NTSC" };
66 67
67/* ----------------------------------------------------------------------- */ 68/* ----------------------------------------------------------------------- */
68 69
69static inline int adv7170_write(struct i2c_client *client, u8 reg, u8 value) 70static inline int adv7170_write(struct v4l2_subdev *sd, u8 reg, u8 value)
70{ 71{
71 struct adv7170 *encoder = i2c_get_clientdata(client); 72 struct i2c_client *client = v4l2_get_subdevdata(sd);
73 struct adv7170 *encoder = to_adv7170(sd);
72 74
73 encoder->reg[reg] = value; 75 encoder->reg[reg] = value;
74 return i2c_smbus_write_byte_data(client, reg, value); 76 return i2c_smbus_write_byte_data(client, reg, value);
75} 77}
76 78
77static inline int adv7170_read(struct i2c_client *client, u8 reg) 79static inline int adv7170_read(struct v4l2_subdev *sd, u8 reg)
78{ 80{
81 struct i2c_client *client = v4l2_get_subdevdata(sd);
82
79 return i2c_smbus_read_byte_data(client, reg); 83 return i2c_smbus_read_byte_data(client, reg);
80} 84}
81 85
82static int adv7170_write_block(struct i2c_client *client, 86static int adv7170_write_block(struct v4l2_subdev *sd,
83 const u8 *data, unsigned int len) 87 const u8 *data, unsigned int len)
84{ 88{
89 struct i2c_client *client = v4l2_get_subdevdata(sd);
90 struct adv7170 *encoder = to_adv7170(sd);
85 int ret = -1; 91 int ret = -1;
86 u8 reg; 92 u8 reg;
87 93
@@ -89,7 +95,6 @@ static int adv7170_write_block(struct i2c_client *client,
89 * the adapter understands raw I2C */ 95 * the adapter understands raw I2C */
90 if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { 96 if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
91 /* do raw I2C, not smbus compatible */ 97 /* do raw I2C, not smbus compatible */
92 struct adv7170 *encoder = i2c_get_clientdata(client);
93 u8 block_data[32]; 98 u8 block_data[32];
94 int block_len; 99 int block_len;
95 100
@@ -110,7 +115,7 @@ static int adv7170_write_block(struct i2c_client *client,
110 /* do some slow I2C emulation kind of thing */ 115 /* do some slow I2C emulation kind of thing */
111 while (len >= 2) { 116 while (len >= 2) {
112 reg = *data++; 117 reg = *data++;
113 ret = adv7170_write(client, reg, *data++); 118 ret = adv7170_write(sd, reg, *data++);
114 if (ret < 0) 119 if (ret < 0)
115 break; 120 break;
116 len -= 2; 121 len -= 2;
@@ -128,203 +133,161 @@ static int adv7170_write_block(struct i2c_client *client,
128#define TR1PLAY 0x00 133#define TR1PLAY 0x00
129 134
130static const unsigned char init_NTSC[] = { 135static const unsigned char init_NTSC[] = {
131 0x00, 0x10, // MR0 136 0x00, 0x10, /* MR0 */
132 0x01, 0x20, // MR1 137 0x01, 0x20, /* MR1 */
133 0x02, 0x0e, // MR2 RTC control: bits 2 and 1 138 0x02, 0x0e, /* MR2 RTC control: bits 2 and 1 */
134 0x03, 0x80, // MR3 139 0x03, 0x80, /* MR3 */
135 0x04, 0x30, // MR4 140 0x04, 0x30, /* MR4 */
136 0x05, 0x00, // Reserved 141 0x05, 0x00, /* Reserved */
137 0x06, 0x00, // Reserved 142 0x06, 0x00, /* Reserved */
138 0x07, TR0MODE, // TM0 143 0x07, TR0MODE, /* TM0 */
139 0x08, TR1CAPT, // TM1 144 0x08, TR1CAPT, /* TM1 */
140 0x09, 0x16, // Fsc0 145 0x09, 0x16, /* Fsc0 */
141 0x0a, 0x7c, // Fsc1 146 0x0a, 0x7c, /* Fsc1 */
142 0x0b, 0xf0, // Fsc2 147 0x0b, 0xf0, /* Fsc2 */
143 0x0c, 0x21, // Fsc3 148 0x0c, 0x21, /* Fsc3 */
144 0x0d, 0x00, // Subcarrier Phase 149 0x0d, 0x00, /* Subcarrier Phase */
145 0x0e, 0x00, // Closed Capt. Ext 0 150 0x0e, 0x00, /* Closed Capt. Ext 0 */
146 0x0f, 0x00, // Closed Capt. Ext 1 151 0x0f, 0x00, /* Closed Capt. Ext 1 */
147 0x10, 0x00, // Closed Capt. 0 152 0x10, 0x00, /* Closed Capt. 0 */
148 0x11, 0x00, // Closed Capt. 1 153 0x11, 0x00, /* Closed Capt. 1 */
149 0x12, 0x00, // Pedestal Ctl 0 154 0x12, 0x00, /* Pedestal Ctl 0 */
150 0x13, 0x00, // Pedestal Ctl 1 155 0x13, 0x00, /* Pedestal Ctl 1 */
151 0x14, 0x00, // Pedestal Ctl 2 156 0x14, 0x00, /* Pedestal Ctl 2 */
152 0x15, 0x00, // Pedestal Ctl 3 157 0x15, 0x00, /* Pedestal Ctl 3 */
153 0x16, 0x00, // CGMS_WSS_0 158 0x16, 0x00, /* CGMS_WSS_0 */
154 0x17, 0x00, // CGMS_WSS_1 159 0x17, 0x00, /* CGMS_WSS_1 */
155 0x18, 0x00, // CGMS_WSS_2 160 0x18, 0x00, /* CGMS_WSS_2 */
156 0x19, 0x00, // Teletext Ctl 161 0x19, 0x00, /* Teletext Ctl */
157}; 162};
158 163
159static const unsigned char init_PAL[] = { 164static const unsigned char init_PAL[] = {
160 0x00, 0x71, // MR0 165 0x00, 0x71, /* MR0 */
161 0x01, 0x20, // MR1 166 0x01, 0x20, /* MR1 */
162 0x02, 0x0e, // MR2 RTC control: bits 2 and 1 167 0x02, 0x0e, /* MR2 RTC control: bits 2 and 1 */
163 0x03, 0x80, // MR3 168 0x03, 0x80, /* MR3 */
164 0x04, 0x30, // MR4 169 0x04, 0x30, /* MR4 */
165 0x05, 0x00, // Reserved 170 0x05, 0x00, /* Reserved */
166 0x06, 0x00, // Reserved 171 0x06, 0x00, /* Reserved */
167 0x07, TR0MODE, // TM0 172 0x07, TR0MODE, /* TM0 */
168 0x08, TR1CAPT, // TM1 173 0x08, TR1CAPT, /* TM1 */
169 0x09, 0xcb, // Fsc0 174 0x09, 0xcb, /* Fsc0 */
170 0x0a, 0x8a, // Fsc1 175 0x0a, 0x8a, /* Fsc1 */
171 0x0b, 0x09, // Fsc2 176 0x0b, 0x09, /* Fsc2 */
172 0x0c, 0x2a, // Fsc3 177 0x0c, 0x2a, /* Fsc3 */
173 0x0d, 0x00, // Subcarrier Phase 178 0x0d, 0x00, /* Subcarrier Phase */
174 0x0e, 0x00, // Closed Capt. Ext 0 179 0x0e, 0x00, /* Closed Capt. Ext 0 */
175 0x0f, 0x00, // Closed Capt. Ext 1 180 0x0f, 0x00, /* Closed Capt. Ext 1 */
176 0x10, 0x00, // Closed Capt. 0 181 0x10, 0x00, /* Closed Capt. 0 */
177 0x11, 0x00, // Closed Capt. 1 182 0x11, 0x00, /* Closed Capt. 1 */
178 0x12, 0x00, // Pedestal Ctl 0 183 0x12, 0x00, /* Pedestal Ctl 0 */
179 0x13, 0x00, // Pedestal Ctl 1 184 0x13, 0x00, /* Pedestal Ctl 1 */
180 0x14, 0x00, // Pedestal Ctl 2 185 0x14, 0x00, /* Pedestal Ctl 2 */
181 0x15, 0x00, // Pedestal Ctl 3 186 0x15, 0x00, /* Pedestal Ctl 3 */
182 0x16, 0x00, // CGMS_WSS_0 187 0x16, 0x00, /* CGMS_WSS_0 */
183 0x17, 0x00, // CGMS_WSS_1 188 0x17, 0x00, /* CGMS_WSS_1 */
184 0x18, 0x00, // CGMS_WSS_2 189 0x18, 0x00, /* CGMS_WSS_2 */
185 0x19, 0x00, // Teletext Ctl 190 0x19, 0x00, /* Teletext Ctl */
186}; 191};
187 192
188 193
189static int adv7170_command(struct i2c_client *client, unsigned cmd, void *arg) 194static int adv7170_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
190{ 195{
191 struct adv7170 *encoder = i2c_get_clientdata(client); 196 struct adv7170 *encoder = to_adv7170(sd);
192 197
193 switch (cmd) { 198 v4l2_dbg(1, debug, sd, "set norm %llx\n", (unsigned long long)std);
194 case 0: 199
195#if 0 200 if (std & V4L2_STD_NTSC) {
196 /* This is just for testing!!! */ 201 adv7170_write_block(sd, init_NTSC, sizeof(init_NTSC));
197 adv7170_write_block(client, init_common, 202 if (encoder->input == 0)
198 sizeof(init_common)); 203 adv7170_write(sd, 0x02, 0x0e); /* Enable genlock */
199 adv7170_write(client, 0x07, TR0MODE | TR0RST); 204 adv7170_write(sd, 0x07, TR0MODE | TR0RST);
200 adv7170_write(client, 0x07, TR0MODE); 205 adv7170_write(sd, 0x07, TR0MODE);
201#endif 206 } else if (std & V4L2_STD_PAL) {
202 break; 207 adv7170_write_block(sd, init_PAL, sizeof(init_PAL));
203 208 if (encoder->input == 0)
204 case ENCODER_GET_CAPABILITIES: 209 adv7170_write(sd, 0x02, 0x0e); /* Enable genlock */
205 { 210 adv7170_write(sd, 0x07, TR0MODE | TR0RST);
206 struct video_encoder_capability *cap = arg; 211 adv7170_write(sd, 0x07, TR0MODE);
207 212 } else {
208 cap->flags = VIDEO_ENCODER_PAL | 213 v4l2_dbg(1, debug, sd, "illegal norm: %llx\n",
209 VIDEO_ENCODER_NTSC; 214 (unsigned long long)std);
210 cap->inputs = 2; 215 return -EINVAL;
211 cap->outputs = 1;
212 break;
213 } 216 }
217 v4l2_dbg(1, debug, sd, "switched to %llx\n", (unsigned long long)std);
218 encoder->norm = std;
219 return 0;
220}
214 221
215 case ENCODER_SET_NORM: 222static int adv7170_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
216 { 223{
217 int iarg = *(int *) arg; 224 struct adv7170 *encoder = to_adv7170(sd);
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); // Enable genlock
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); // Enable genlock
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 225
249 case ENCODER_SET_INPUT: 226 /* RJ: route->input = 0: input is from decoder
250 { 227 route->input = 1: input is from ZR36060
251 int iarg = *(int *) arg; 228 route->input = 2: color bar */
252
253 /* RJ: *iarg = 0: input is from decoder
254 *iarg = 1: input is from ZR36060
255 *iarg = 2: color bar */
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); /* TR1 */
264 adv7170_write(client, 0x02, 0x0e); // Enable genlock
265 adv7170_write(client, 0x07, TR0MODE | TR0RST);
266 adv7170_write(client, 0x07, TR0MODE);
267 /* udelay(10); */
268 break;
269
270 case 1:
271 adv7170_write(client, 0x01, 0x00);
272 adv7170_write(client, 0x08, TR1PLAY); /* TR1 */
273 adv7170_write(client, 0x02, 0x08);
274 adv7170_write(client, 0x07, TR0MODE | TR0RST);
275 adv7170_write(client, 0x07, TR0MODE);
276 /* udelay(10); */
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 229
288 case ENCODER_SET_OUTPUT: 230 v4l2_dbg(1, debug, sd, "set input from %s\n",
289 { 231 route->input == 0 ? "decoder" : "ZR36060");
290 int *iarg = arg;
291 232
292 /* not much choice of outputs */ 233 switch (route->input) {
293 if (*iarg != 0) { 234 case 0:
294 return -EINVAL; 235 adv7170_write(sd, 0x01, 0x20);
295 } 236 adv7170_write(sd, 0x08, TR1CAPT); /* TR1 */
237 adv7170_write(sd, 0x02, 0x0e); /* Enable genlock */
238 adv7170_write(sd, 0x07, TR0MODE | TR0RST);
239 adv7170_write(sd, 0x07, TR0MODE);
240 /* udelay(10); */
296 break; 241 break;
297 }
298
299 case ENCODER_ENABLE_OUTPUT:
300 {
301 int *iarg = arg;
302 242
303 encoder->enable = !!*iarg; 243 case 1:
244 adv7170_write(sd, 0x01, 0x00);
245 adv7170_write(sd, 0x08, TR1PLAY); /* TR1 */
246 adv7170_write(sd, 0x02, 0x08);
247 adv7170_write(sd, 0x07, TR0MODE | TR0RST);
248 adv7170_write(sd, 0x07, TR0MODE);
249 /* udelay(10); */
304 break; 250 break;
305 }
306 251
307 default: 252 default:
253 v4l2_dbg(1, debug, sd, "illegal input: %d\n", route->input);
308 return -EINVAL; 254 return -EINVAL;
309 } 255 }
310 256 v4l2_dbg(1, debug, sd, "switched to %s\n", inputs[route->input]);
257 encoder->input = route->input;
311 return 0; 258 return 0;
312} 259}
313 260
261static int adv7170_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
262{
263 struct i2c_client *client = v4l2_get_subdevdata(sd);
264
265 return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7170, 0);
266}
267
314/* ----------------------------------------------------------------------- */ 268/* ----------------------------------------------------------------------- */
315 269
316static unsigned short normal_i2c[] = { 270static const struct v4l2_subdev_core_ops adv7170_core_ops = {
317 0xd4 >> 1, 0xd6 >> 1, /* adv7170 IDs */ 271 .g_chip_ident = adv7170_g_chip_ident,
318 0x54 >> 1, 0x56 >> 1, /* adv7171 IDs */
319 I2C_CLIENT_END
320}; 272};
321 273
322I2C_CLIENT_INSMOD; 274static const struct v4l2_subdev_video_ops adv7170_video_ops = {
275 .s_std_output = adv7170_s_std_output,
276 .s_routing = adv7170_s_routing,
277};
278
279static const struct v4l2_subdev_ops adv7170_ops = {
280 .core = &adv7170_core_ops,
281 .video = &adv7170_video_ops,
282};
283
284/* ----------------------------------------------------------------------- */
323 285
324static int adv7170_probe(struct i2c_client *client, 286static int adv7170_probe(struct i2c_client *client,
325 const struct i2c_device_id *id) 287 const struct i2c_device_id *id)
326{ 288{
327 struct adv7170 *encoder; 289 struct adv7170 *encoder;
290 struct v4l2_subdev *sd;
328 int i; 291 int i;
329 292
330 /* Check if the adapter supports the needed features */ 293 /* Check if the adapter supports the needed features */
@@ -337,26 +300,29 @@ static int adv7170_probe(struct i2c_client *client,
337 encoder = kzalloc(sizeof(struct adv7170), GFP_KERNEL); 300 encoder = kzalloc(sizeof(struct adv7170), GFP_KERNEL);
338 if (encoder == NULL) 301 if (encoder == NULL)
339 return -ENOMEM; 302 return -ENOMEM;
340 encoder->norm = VIDEO_MODE_NTSC; 303 sd = &encoder->sd;
304 v4l2_i2c_subdev_init(sd, client, &adv7170_ops);
305 encoder->norm = V4L2_STD_NTSC;
341 encoder->input = 0; 306 encoder->input = 0;
342 encoder->enable = 1;
343 i2c_set_clientdata(client, encoder);
344 307
345 i = adv7170_write_block(client, init_NTSC, sizeof(init_NTSC)); 308 i = adv7170_write_block(sd, init_NTSC, sizeof(init_NTSC));
346 if (i >= 0) { 309 if (i >= 0) {
347 i = adv7170_write(client, 0x07, TR0MODE | TR0RST); 310 i = adv7170_write(sd, 0x07, TR0MODE | TR0RST);
348 i = adv7170_write(client, 0x07, TR0MODE); 311 i = adv7170_write(sd, 0x07, TR0MODE);
349 i = adv7170_read(client, 0x12); 312 i = adv7170_read(sd, 0x12);
350 v4l_dbg(1, debug, client, "revision %d\n", i & 1); 313 v4l2_dbg(1, debug, sd, "revision %d\n", i & 1);
351 } 314 }
352 if (i < 0) 315 if (i < 0)
353 v4l_dbg(1, debug, client, "init error 0x%x\n", i); 316 v4l2_dbg(1, debug, sd, "init error 0x%x\n", i);
354 return 0; 317 return 0;
355} 318}
356 319
357static int adv7170_remove(struct i2c_client *client) 320static int adv7170_remove(struct i2c_client *client)
358{ 321{
359 kfree(i2c_get_clientdata(client)); 322 struct v4l2_subdev *sd = i2c_get_clientdata(client);
323
324 v4l2_device_unregister_subdev(sd);
325 kfree(to_adv7170(sd));
360 return 0; 326 return 0;
361} 327}
362 328
@@ -371,8 +337,6 @@ MODULE_DEVICE_TABLE(i2c, adv7170_id);
371 337
372static struct v4l2_i2c_driver_data v4l2_i2c_data = { 338static struct v4l2_i2c_driver_data v4l2_i2c_data = {
373 .name = "adv7170", 339 .name = "adv7170",
374 .driverid = I2C_DRIVERID_ADV7170,
375 .command = adv7170_command,
376 .probe = adv7170_probe, 340 .probe = adv7170_probe,
377 .remove = adv7170_remove, 341 .remove = adv7170_remove,
378 .id_table = adv7170_id, 342 .id_table = adv7170_id,