diff options
Diffstat (limited to 'drivers/media/video/saa7185.c')
-rw-r--r-- | drivers/media/video/saa7185.c | 217 |
1 files changed, 119 insertions, 98 deletions
diff --git a/drivers/media/video/saa7185.c b/drivers/media/video/saa7185.c index fc51e6c9cb95..b4eb66253bc2 100644 --- a/drivers/media/video/saa7185.c +++ b/drivers/media/video/saa7185.c | |||
@@ -30,51 +30,61 @@ | |||
30 | #include <asm/uaccess.h> | 30 | #include <asm/uaccess.h> |
31 | #include <linux/i2c.h> | 31 | #include <linux/i2c.h> |
32 | #include <linux/i2c-id.h> | 32 | #include <linux/i2c-id.h> |
33 | #include <linux/videodev.h> | 33 | #include <linux/videodev2.h> |
34 | #include <linux/video_encoder.h> | 34 | #include <media/v4l2-device.h> |
35 | #include <media/v4l2-common.h> | 35 | #include <media/v4l2-chip-ident.h> |
36 | #include <media/v4l2-i2c-drv-legacy.h> | 36 | #include <media/v4l2-i2c-drv-legacy.h> |
37 | 37 | ||
38 | MODULE_DESCRIPTION("Philips SAA7185 video encoder driver"); | 38 | MODULE_DESCRIPTION("Philips SAA7185 video encoder driver"); |
39 | MODULE_AUTHOR("Dave Perks"); | 39 | MODULE_AUTHOR("Dave Perks"); |
40 | MODULE_LICENSE("GPL"); | 40 | MODULE_LICENSE("GPL"); |
41 | 41 | ||
42 | |||
43 | static int debug; | 42 | static int debug; |
44 | module_param(debug, int, 0); | 43 | module_param(debug, int, 0); |
45 | MODULE_PARM_DESC(debug, "Debug level (0-1)"); | 44 | MODULE_PARM_DESC(debug, "Debug level (0-1)"); |
46 | 45 | ||
46 | static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END }; | ||
47 | |||
48 | I2C_CLIENT_INSMOD; | ||
49 | |||
47 | /* ----------------------------------------------------------------------- */ | 50 | /* ----------------------------------------------------------------------- */ |
48 | 51 | ||
49 | struct saa7185 { | 52 | struct saa7185 { |
53 | struct v4l2_subdev sd; | ||
50 | unsigned char reg[128]; | 54 | unsigned char reg[128]; |
51 | 55 | ||
52 | v4l2_std_id norm; | 56 | v4l2_std_id norm; |
53 | int bright; | ||
54 | int contrast; | ||
55 | int hue; | ||
56 | int sat; | ||
57 | }; | 57 | }; |
58 | 58 | ||
59 | static inline struct saa7185 *to_saa7185(struct v4l2_subdev *sd) | ||
60 | { | ||
61 | return container_of(sd, struct saa7185, sd); | ||
62 | } | ||
63 | |||
59 | /* ----------------------------------------------------------------------- */ | 64 | /* ----------------------------------------------------------------------- */ |
60 | 65 | ||
61 | static inline int saa7185_read(struct i2c_client *client) | 66 | static inline int saa7185_read(struct v4l2_subdev *sd) |
62 | { | 67 | { |
68 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
69 | |||
63 | return i2c_smbus_read_byte(client); | 70 | return i2c_smbus_read_byte(client); |
64 | } | 71 | } |
65 | 72 | ||
66 | static int saa7185_write(struct i2c_client *client, u8 reg, u8 value) | 73 | static int saa7185_write(struct v4l2_subdev *sd, u8 reg, u8 value) |
67 | { | 74 | { |
68 | struct saa7185 *encoder = i2c_get_clientdata(client); | 75 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
76 | struct saa7185 *encoder = to_saa7185(sd); | ||
69 | 77 | ||
70 | v4l_dbg(1, debug, client, "%02x set to %02x\n", reg, value); | 78 | v4l2_dbg(1, debug, sd, "%02x set to %02x\n", reg, value); |
71 | encoder->reg[reg] = value; | 79 | encoder->reg[reg] = value; |
72 | return i2c_smbus_write_byte_data(client, reg, value); | 80 | return i2c_smbus_write_byte_data(client, reg, value); |
73 | } | 81 | } |
74 | 82 | ||
75 | static int saa7185_write_block(struct i2c_client *client, | 83 | static int saa7185_write_block(struct v4l2_subdev *sd, |
76 | const u8 *data, unsigned int len) | 84 | const u8 *data, unsigned int len) |
77 | { | 85 | { |
86 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
87 | struct saa7185 *encoder = to_saa7185(sd); | ||
78 | int ret = -1; | 88 | int ret = -1; |
79 | u8 reg; | 89 | u8 reg; |
80 | 90 | ||
@@ -82,7 +92,6 @@ static int saa7185_write_block(struct i2c_client *client, | |||
82 | * the adapter understands raw I2C */ | 92 | * the adapter understands raw I2C */ |
83 | if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { | 93 | if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { |
84 | /* do raw I2C, not smbus compatible */ | 94 | /* do raw I2C, not smbus compatible */ |
85 | struct saa7185 *encoder = i2c_get_clientdata(client); | ||
86 | u8 block_data[32]; | 95 | u8 block_data[32]; |
87 | int block_len; | 96 | int block_len; |
88 | 97 | ||
@@ -103,7 +112,7 @@ static int saa7185_write_block(struct i2c_client *client, | |||
103 | /* do some slow I2C emulation kind of thing */ | 112 | /* do some slow I2C emulation kind of thing */ |
104 | while (len >= 2) { | 113 | while (len >= 2) { |
105 | reg = *data++; | 114 | reg = *data++; |
106 | ret = saa7185_write(client, reg, *data++); | 115 | ret = saa7185_write(sd, reg, *data++); |
107 | if (ret < 0) | 116 | if (ret < 0) |
108 | break; | 117 | break; |
109 | len -= 2; | 118 | len -= 2; |
@@ -212,101 +221,111 @@ static const unsigned char init_ntsc[] = { | |||
212 | 0x66, 0x21, /* FSC3 */ | 221 | 0x66, 0x21, /* FSC3 */ |
213 | }; | 222 | }; |
214 | 223 | ||
215 | static int saa7185_command(struct i2c_client *client, unsigned cmd, void *arg) | 224 | |
225 | static int saa7185_init(struct v4l2_subdev *sd, u32 val) | ||
226 | { | ||
227 | struct saa7185 *encoder = to_saa7185(sd); | ||
228 | |||
229 | saa7185_write_block(sd, init_common, sizeof(init_common)); | ||
230 | if (encoder->norm & V4L2_STD_NTSC) | ||
231 | saa7185_write_block(sd, init_ntsc, sizeof(init_ntsc)); | ||
232 | else | ||
233 | saa7185_write_block(sd, init_pal, sizeof(init_pal)); | ||
234 | return 0; | ||
235 | } | ||
236 | |||
237 | static int saa7185_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std) | ||
238 | { | ||
239 | struct saa7185 *encoder = to_saa7185(sd); | ||
240 | |||
241 | if (std & V4L2_STD_NTSC) | ||
242 | saa7185_write_block(sd, init_ntsc, sizeof(init_ntsc)); | ||
243 | else if (std & V4L2_STD_PAL) | ||
244 | saa7185_write_block(sd, init_pal, sizeof(init_pal)); | ||
245 | else | ||
246 | return -EINVAL; | ||
247 | encoder->norm = std; | ||
248 | return 0; | ||
249 | } | ||
250 | |||
251 | static int saa7185_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route) | ||
216 | { | 252 | { |
217 | struct saa7185 *encoder = i2c_get_clientdata(client); | 253 | struct saa7185 *encoder = to_saa7185(sd); |
218 | 254 | ||
219 | switch (cmd) { | 255 | /* RJ: route->input = 0: input is from SA7111 |
220 | case VIDIOC_INT_INIT: | 256 | route->input = 1: input is from ZR36060 */ |
221 | saa7185_write_block(client, init_common, | 257 | |
222 | sizeof(init_common)); | 258 | switch (route->input) { |
223 | if (encoder->norm & V4L2_STD_NTSC) | 259 | case 0: |
224 | saa7185_write_block(client, init_ntsc, | 260 | /* turn off colorbar */ |
225 | sizeof(init_ntsc)); | 261 | saa7185_write(sd, 0x3a, 0x0f); |
226 | else | 262 | /* Switch RTCE to 1 */ |
227 | saa7185_write_block(client, init_pal, | 263 | saa7185_write(sd, 0x61, (encoder->reg[0x61] & 0xf7) | 0x08); |
228 | sizeof(init_pal)); | 264 | saa7185_write(sd, 0x6e, 0x01); |
229 | break; | 265 | break; |
230 | 266 | ||
231 | case VIDIOC_INT_S_STD_OUTPUT: | 267 | case 1: |
232 | { | 268 | /* turn off colorbar */ |
233 | v4l2_std_id *iarg = arg; | 269 | saa7185_write(sd, 0x3a, 0x0f); |
234 | 270 | /* Switch RTCE to 0 */ | |
235 | //saa7185_write_block(client, init_common, sizeof(init_common)); | 271 | saa7185_write(sd, 0x61, (encoder->reg[0x61] & 0xf7) | 0x00); |
236 | 272 | /* SW: a slight sync problem... */ | |
237 | if (*iarg & V4L2_STD_NTSC) | 273 | saa7185_write(sd, 0x6e, 0x00); |
238 | saa7185_write_block(client, init_ntsc, | ||
239 | sizeof(init_ntsc)); | ||
240 | else if (*iarg & V4L2_STD_PAL) | ||
241 | saa7185_write_block(client, init_pal, | ||
242 | sizeof(init_pal)); | ||
243 | else | ||
244 | return -EINVAL; | ||
245 | encoder->norm = *iarg; | ||
246 | break; | 274 | break; |
247 | } | ||
248 | 275 | ||
249 | case VIDIOC_INT_S_VIDEO_ROUTING: | 276 | case 2: |
250 | { | 277 | /* turn on colorbar */ |
251 | struct v4l2_routing *route = arg; | 278 | saa7185_write(sd, 0x3a, 0x8f); |
252 | 279 | /* Switch RTCE to 0 */ | |
253 | /* RJ: route->input = 0: input is from SA7111 | 280 | saa7185_write(sd, 0x61, (encoder->reg[0x61] & 0xf7) | 0x08); |
254 | route->input = 1: input is from ZR36060 */ | 281 | /* SW: a slight sync problem... */ |
255 | 282 | saa7185_write(sd, 0x6e, 0x01); | |
256 | switch (route->input) { | ||
257 | case 0: | ||
258 | /* turn off colorbar */ | ||
259 | saa7185_write(client, 0x3a, 0x0f); | ||
260 | /* Switch RTCE to 1 */ | ||
261 | saa7185_write(client, 0x61, | ||
262 | (encoder->reg[0x61] & 0xf7) | 0x08); | ||
263 | saa7185_write(client, 0x6e, 0x01); | ||
264 | break; | ||
265 | |||
266 | case 1: | ||
267 | /* turn off colorbar */ | ||
268 | saa7185_write(client, 0x3a, 0x0f); | ||
269 | /* Switch RTCE to 0 */ | ||
270 | saa7185_write(client, 0x61, | ||
271 | (encoder->reg[0x61] & 0xf7) | 0x00); | ||
272 | /* SW: a slight sync problem... */ | ||
273 | saa7185_write(client, 0x6e, 0x00); | ||
274 | break; | ||
275 | |||
276 | case 2: | ||
277 | /* turn on colorbar */ | ||
278 | saa7185_write(client, 0x3a, 0x8f); | ||
279 | /* Switch RTCE to 0 */ | ||
280 | saa7185_write(client, 0x61, | ||
281 | (encoder->reg[0x61] & 0xf7) | 0x08); | ||
282 | /* SW: a slight sync problem... */ | ||
283 | saa7185_write(client, 0x6e, 0x01); | ||
284 | break; | ||
285 | |||
286 | default: | ||
287 | return -EINVAL; | ||
288 | } | ||
289 | break; | 283 | break; |
290 | } | ||
291 | 284 | ||
292 | default: | 285 | default: |
293 | return -EINVAL; | 286 | return -EINVAL; |
294 | } | 287 | } |
295 | |||
296 | return 0; | 288 | return 0; |
297 | } | 289 | } |
298 | 290 | ||
291 | static int saa7185_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) | ||
292 | { | ||
293 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
294 | |||
295 | return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_SAA7185, 0); | ||
296 | } | ||
297 | |||
298 | static int saa7185_command(struct i2c_client *client, unsigned cmd, void *arg) | ||
299 | { | ||
300 | return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg); | ||
301 | } | ||
302 | |||
299 | /* ----------------------------------------------------------------------- */ | 303 | /* ----------------------------------------------------------------------- */ |
300 | 304 | ||
301 | static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END }; | 305 | static const struct v4l2_subdev_core_ops saa7185_core_ops = { |
306 | .g_chip_ident = saa7185_g_chip_ident, | ||
307 | .init = saa7185_init, | ||
308 | }; | ||
302 | 309 | ||
303 | I2C_CLIENT_INSMOD; | 310 | static const struct v4l2_subdev_video_ops saa7185_video_ops = { |
311 | .s_std_output = saa7185_s_std_output, | ||
312 | .s_routing = saa7185_s_routing, | ||
313 | }; | ||
314 | |||
315 | static const struct v4l2_subdev_ops saa7185_ops = { | ||
316 | .core = &saa7185_core_ops, | ||
317 | .video = &saa7185_video_ops, | ||
318 | }; | ||
319 | |||
320 | |||
321 | /* ----------------------------------------------------------------------- */ | ||
304 | 322 | ||
305 | static int saa7185_probe(struct i2c_client *client, | 323 | static int saa7185_probe(struct i2c_client *client, |
306 | const struct i2c_device_id *id) | 324 | const struct i2c_device_id *id) |
307 | { | 325 | { |
308 | int i; | 326 | int i; |
309 | struct saa7185 *encoder; | 327 | struct saa7185 *encoder; |
328 | struct v4l2_subdev *sd; | ||
310 | 329 | ||
311 | /* Check if the adapter supports the needed features */ | 330 | /* Check if the adapter supports the needed features */ |
312 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | 331 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) |
@@ -319,26 +338,28 @@ static int saa7185_probe(struct i2c_client *client, | |||
319 | if (encoder == NULL) | 338 | if (encoder == NULL) |
320 | return -ENOMEM; | 339 | return -ENOMEM; |
321 | encoder->norm = V4L2_STD_NTSC; | 340 | encoder->norm = V4L2_STD_NTSC; |
322 | i2c_set_clientdata(client, encoder); | 341 | sd = &encoder->sd; |
342 | v4l2_i2c_subdev_init(sd, client, &saa7185_ops); | ||
323 | 343 | ||
324 | i = saa7185_write_block(client, init_common, sizeof(init_common)); | 344 | i = saa7185_write_block(sd, init_common, sizeof(init_common)); |
325 | if (i >= 0) | 345 | if (i >= 0) |
326 | i = saa7185_write_block(client, init_ntsc, sizeof(init_ntsc)); | 346 | i = saa7185_write_block(sd, init_ntsc, sizeof(init_ntsc)); |
327 | if (i < 0) | 347 | if (i < 0) |
328 | v4l_dbg(1, debug, client, "init error %d\n", i); | 348 | v4l2_dbg(1, debug, sd, "init error %d\n", i); |
329 | else | 349 | else |
330 | v4l_dbg(1, debug, client, "revision 0x%x\n", | 350 | v4l2_dbg(1, debug, sd, "revision 0x%x\n", |
331 | saa7185_read(client) >> 5); | 351 | saa7185_read(sd) >> 5); |
332 | return 0; | 352 | return 0; |
333 | } | 353 | } |
334 | 354 | ||
335 | static int saa7185_remove(struct i2c_client *client) | 355 | static int saa7185_remove(struct i2c_client *client) |
336 | { | 356 | { |
337 | struct saa7185 *encoder = i2c_get_clientdata(client); | 357 | struct v4l2_subdev *sd = i2c_get_clientdata(client); |
338 | 358 | struct saa7185 *encoder = to_saa7185(sd); | |
339 | saa7185_write(client, 0x61, (encoder->reg[0x61]) | 0x40); /* SW: output off is active */ | ||
340 | //saa7185_write(client, 0x3a, (encoder->reg[0x3a]) | 0x80); /* SW: color bar */ | ||
341 | 359 | ||
360 | v4l2_device_unregister_subdev(sd); | ||
361 | /* SW: output off is active */ | ||
362 | saa7185_write(sd, 0x61, (encoder->reg[0x61]) | 0x40); | ||
342 | kfree(encoder); | 363 | kfree(encoder); |
343 | return 0; | 364 | return 0; |
344 | } | 365 | } |