diff options
Diffstat (limited to 'drivers/media/video/adv7343.c')
-rw-r--r-- | drivers/media/video/adv7343.c | 167 |
1 files changed, 61 insertions, 106 deletions
diff --git a/drivers/media/video/adv7343.c b/drivers/media/video/adv7343.c index 41b2930d0ce4..021fab23070d 100644 --- a/drivers/media/video/adv7343.c +++ b/drivers/media/video/adv7343.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <media/adv7343.h> | 29 | #include <media/adv7343.h> |
30 | #include <media/v4l2-device.h> | 30 | #include <media/v4l2-device.h> |
31 | #include <media/v4l2-chip-ident.h> | 31 | #include <media/v4l2-chip-ident.h> |
32 | #include <media/v4l2-ctrls.h> | ||
32 | 33 | ||
33 | #include "adv7343_regs.h" | 34 | #include "adv7343_regs.h" |
34 | 35 | ||
@@ -41,15 +42,13 @@ MODULE_PARM_DESC(debug, "Debug level 0-1"); | |||
41 | 42 | ||
42 | struct adv7343_state { | 43 | struct adv7343_state { |
43 | struct v4l2_subdev sd; | 44 | struct v4l2_subdev sd; |
45 | struct v4l2_ctrl_handler hdl; | ||
44 | u8 reg00; | 46 | u8 reg00; |
45 | u8 reg01; | 47 | u8 reg01; |
46 | u8 reg02; | 48 | u8 reg02; |
47 | u8 reg35; | 49 | u8 reg35; |
48 | u8 reg80; | 50 | u8 reg80; |
49 | u8 reg82; | 51 | u8 reg82; |
50 | int bright; | ||
51 | int hue; | ||
52 | int gain; | ||
53 | u32 output; | 52 | u32 output; |
54 | v4l2_std_id std; | 53 | v4l2_std_id std; |
55 | }; | 54 | }; |
@@ -59,6 +58,11 @@ static inline struct adv7343_state *to_state(struct v4l2_subdev *sd) | |||
59 | return container_of(sd, struct adv7343_state, sd); | 58 | return container_of(sd, struct adv7343_state, sd); |
60 | } | 59 | } |
61 | 60 | ||
61 | static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) | ||
62 | { | ||
63 | return &container_of(ctrl->handler, struct adv7343_state, hdl)->sd; | ||
64 | } | ||
65 | |||
62 | static inline int adv7343_write(struct v4l2_subdev *sd, u8 reg, u8 value) | 66 | static inline int adv7343_write(struct v4l2_subdev *sd, u8 reg, u8 value) |
63 | { | 67 | { |
64 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 68 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
@@ -268,111 +272,22 @@ static int adv7343_log_status(struct v4l2_subdev *sd) | |||
268 | return 0; | 272 | return 0; |
269 | } | 273 | } |
270 | 274 | ||
271 | static int adv7343_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) | 275 | static int adv7343_s_ctrl(struct v4l2_ctrl *ctrl) |
272 | { | ||
273 | switch (qc->id) { | ||
274 | case V4L2_CID_BRIGHTNESS: | ||
275 | return v4l2_ctrl_query_fill(qc, ADV7343_BRIGHTNESS_MIN, | ||
276 | ADV7343_BRIGHTNESS_MAX, 1, | ||
277 | ADV7343_BRIGHTNESS_DEF); | ||
278 | case V4L2_CID_HUE: | ||
279 | return v4l2_ctrl_query_fill(qc, ADV7343_HUE_MIN, | ||
280 | ADV7343_HUE_MAX, 1 , | ||
281 | ADV7343_HUE_DEF); | ||
282 | case V4L2_CID_GAIN: | ||
283 | return v4l2_ctrl_query_fill(qc, ADV7343_GAIN_MIN, | ||
284 | ADV7343_GAIN_MAX, 1, | ||
285 | ADV7343_GAIN_DEF); | ||
286 | default: | ||
287 | break; | ||
288 | } | ||
289 | |||
290 | return 0; | ||
291 | } | ||
292 | |||
293 | static int adv7343_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | ||
294 | { | ||
295 | struct adv7343_state *state = to_state(sd); | ||
296 | int err = 0; | ||
297 | |||
298 | switch (ctrl->id) { | ||
299 | case V4L2_CID_BRIGHTNESS: | ||
300 | if (ctrl->value < ADV7343_BRIGHTNESS_MIN || | ||
301 | ctrl->value > ADV7343_BRIGHTNESS_MAX) { | ||
302 | v4l2_dbg(1, debug, sd, | ||
303 | "invalid brightness settings %d\n", | ||
304 | ctrl->value); | ||
305 | return -ERANGE; | ||
306 | } | ||
307 | |||
308 | state->bright = ctrl->value; | ||
309 | err = adv7343_write(sd, ADV7343_SD_BRIGHTNESS_WSS, | ||
310 | state->bright); | ||
311 | break; | ||
312 | |||
313 | case V4L2_CID_HUE: | ||
314 | if (ctrl->value < ADV7343_HUE_MIN || | ||
315 | ctrl->value > ADV7343_HUE_MAX) { | ||
316 | v4l2_dbg(1, debug, sd, "invalid hue settings %d\n", | ||
317 | ctrl->value); | ||
318 | return -ERANGE; | ||
319 | } | ||
320 | |||
321 | state->hue = ctrl->value; | ||
322 | err = adv7343_write(sd, ADV7343_SD_HUE_REG, state->hue); | ||
323 | break; | ||
324 | |||
325 | case V4L2_CID_GAIN: | ||
326 | if (ctrl->value < ADV7343_GAIN_MIN || | ||
327 | ctrl->value > ADV7343_GAIN_MAX) { | ||
328 | v4l2_dbg(1, debug, sd, "invalid gain settings %d\n", | ||
329 | ctrl->value); | ||
330 | return -ERANGE; | ||
331 | } | ||
332 | |||
333 | if ((ctrl->value > POSITIVE_GAIN_MAX) && | ||
334 | (ctrl->value < NEGATIVE_GAIN_MIN)) { | ||
335 | v4l2_dbg(1, debug, sd, | ||
336 | "gain settings not within the specified range\n"); | ||
337 | return -ERANGE; | ||
338 | } | ||
339 | |||
340 | state->gain = ctrl->value; | ||
341 | err = adv7343_write(sd, ADV7343_DAC2_OUTPUT_LEVEL, state->gain); | ||
342 | break; | ||
343 | |||
344 | default: | ||
345 | return -EINVAL; | ||
346 | } | ||
347 | |||
348 | if (err < 0) | ||
349 | v4l2_err(sd, "Failed to set the encoder controls\n"); | ||
350 | |||
351 | return err; | ||
352 | } | ||
353 | |||
354 | static int adv7343_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | ||
355 | { | 276 | { |
356 | struct adv7343_state *state = to_state(sd); | 277 | struct v4l2_subdev *sd = to_sd(ctrl); |
357 | 278 | ||
358 | switch (ctrl->id) { | 279 | switch (ctrl->id) { |
359 | case V4L2_CID_BRIGHTNESS: | 280 | case V4L2_CID_BRIGHTNESS: |
360 | ctrl->value = state->bright; | 281 | return adv7343_write(sd, ADV7343_SD_BRIGHTNESS_WSS, |
361 | break; | 282 | ctrl->val); |
362 | 283 | ||
363 | case V4L2_CID_HUE: | 284 | case V4L2_CID_HUE: |
364 | ctrl->value = state->hue; | 285 | return adv7343_write(sd, ADV7343_SD_HUE_REG, ctrl->val); |
365 | break; | ||
366 | 286 | ||
367 | case V4L2_CID_GAIN: | 287 | case V4L2_CID_GAIN: |
368 | ctrl->value = state->gain; | 288 | return adv7343_write(sd, ADV7343_DAC2_OUTPUT_LEVEL, ctrl->val); |
369 | break; | ||
370 | |||
371 | default: | ||
372 | return -EINVAL; | ||
373 | } | 289 | } |
374 | 290 | return -EINVAL; | |
375 | return 0; | ||
376 | } | 291 | } |
377 | 292 | ||
378 | static int adv7343_g_chip_ident(struct v4l2_subdev *sd, | 293 | static int adv7343_g_chip_ident(struct v4l2_subdev *sd, |
@@ -383,12 +298,20 @@ static int adv7343_g_chip_ident(struct v4l2_subdev *sd, | |||
383 | return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7343, 0); | 298 | return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7343, 0); |
384 | } | 299 | } |
385 | 300 | ||
301 | static const struct v4l2_ctrl_ops adv7343_ctrl_ops = { | ||
302 | .s_ctrl = adv7343_s_ctrl, | ||
303 | }; | ||
304 | |||
386 | static const struct v4l2_subdev_core_ops adv7343_core_ops = { | 305 | static const struct v4l2_subdev_core_ops adv7343_core_ops = { |
387 | .log_status = adv7343_log_status, | 306 | .log_status = adv7343_log_status, |
388 | .g_chip_ident = adv7343_g_chip_ident, | 307 | .g_chip_ident = adv7343_g_chip_ident, |
389 | .g_ctrl = adv7343_g_ctrl, | 308 | .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, |
390 | .s_ctrl = adv7343_s_ctrl, | 309 | .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, |
391 | .queryctrl = adv7343_queryctrl, | 310 | .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, |
311 | .g_ctrl = v4l2_subdev_g_ctrl, | ||
312 | .s_ctrl = v4l2_subdev_s_ctrl, | ||
313 | .queryctrl = v4l2_subdev_queryctrl, | ||
314 | .querymenu = v4l2_subdev_querymenu, | ||
392 | }; | 315 | }; |
393 | 316 | ||
394 | static int adv7343_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std) | 317 | static int adv7343_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std) |
@@ -468,6 +391,7 @@ static int adv7343_probe(struct i2c_client *client, | |||
468 | const struct i2c_device_id *id) | 391 | const struct i2c_device_id *id) |
469 | { | 392 | { |
470 | struct adv7343_state *state; | 393 | struct adv7343_state *state; |
394 | int err; | ||
471 | 395 | ||
472 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | 396 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) |
473 | return -ENODEV; | 397 | return -ENODEV; |
@@ -490,15 +414,46 @@ static int adv7343_probe(struct i2c_client *client, | |||
490 | state->std = V4L2_STD_NTSC; | 414 | state->std = V4L2_STD_NTSC; |
491 | 415 | ||
492 | v4l2_i2c_subdev_init(&state->sd, client, &adv7343_ops); | 416 | v4l2_i2c_subdev_init(&state->sd, client, &adv7343_ops); |
493 | return adv7343_initialize(&state->sd); | 417 | |
418 | v4l2_ctrl_handler_init(&state->hdl, 2); | ||
419 | v4l2_ctrl_new_std(&state->hdl, &adv7343_ctrl_ops, | ||
420 | V4L2_CID_BRIGHTNESS, ADV7343_BRIGHTNESS_MIN, | ||
421 | ADV7343_BRIGHTNESS_MAX, 1, | ||
422 | ADV7343_BRIGHTNESS_DEF); | ||
423 | v4l2_ctrl_new_std(&state->hdl, &adv7343_ctrl_ops, | ||
424 | V4L2_CID_HUE, ADV7343_HUE_MIN, | ||
425 | ADV7343_HUE_MAX, 1, | ||
426 | ADV7343_HUE_DEF); | ||
427 | v4l2_ctrl_new_std(&state->hdl, &adv7343_ctrl_ops, | ||
428 | V4L2_CID_GAIN, ADV7343_GAIN_MIN, | ||
429 | ADV7343_GAIN_MAX, 1, | ||
430 | ADV7343_GAIN_DEF); | ||
431 | state->sd.ctrl_handler = &state->hdl; | ||
432 | if (state->hdl.error) { | ||
433 | int err = state->hdl.error; | ||
434 | |||
435 | v4l2_ctrl_handler_free(&state->hdl); | ||
436 | kfree(state); | ||
437 | return err; | ||
438 | } | ||
439 | v4l2_ctrl_handler_setup(&state->hdl); | ||
440 | |||
441 | err = adv7343_initialize(&state->sd); | ||
442 | if (err) { | ||
443 | v4l2_ctrl_handler_free(&state->hdl); | ||
444 | kfree(state); | ||
445 | } | ||
446 | return err; | ||
494 | } | 447 | } |
495 | 448 | ||
496 | static int adv7343_remove(struct i2c_client *client) | 449 | static int adv7343_remove(struct i2c_client *client) |
497 | { | 450 | { |
498 | struct v4l2_subdev *sd = i2c_get_clientdata(client); | 451 | struct v4l2_subdev *sd = i2c_get_clientdata(client); |
452 | struct adv7343_state *state = to_state(sd); | ||
499 | 453 | ||
500 | v4l2_device_unregister_subdev(sd); | 454 | v4l2_device_unregister_subdev(sd); |
501 | kfree(to_state(sd)); | 455 | v4l2_ctrl_handler_free(&state->hdl); |
456 | kfree(state); | ||
502 | 457 | ||
503 | return 0; | 458 | return 0; |
504 | } | 459 | } |