diff options
| -rw-r--r-- | drivers/media/video/saa7115.c | 183 |
1 files changed, 83 insertions, 100 deletions
diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c index 76da74368680..ee963f4d01bc 100644 --- a/drivers/media/video/saa7115.c +++ b/drivers/media/video/saa7115.c | |||
| @@ -45,6 +45,7 @@ | |||
| 45 | #include <linux/i2c.h> | 45 | #include <linux/i2c.h> |
| 46 | #include <linux/videodev2.h> | 46 | #include <linux/videodev2.h> |
| 47 | #include <media/v4l2-device.h> | 47 | #include <media/v4l2-device.h> |
| 48 | #include <media/v4l2-ctrls.h> | ||
| 48 | #include <media/v4l2-chip-ident.h> | 49 | #include <media/v4l2-chip-ident.h> |
| 49 | #include <media/v4l2-i2c-drv.h> | 50 | #include <media/v4l2-i2c-drv.h> |
| 50 | #include <media/saa7115.h> | 51 | #include <media/saa7115.h> |
| @@ -65,16 +66,19 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)"); | |||
| 65 | 66 | ||
| 66 | struct saa711x_state { | 67 | struct saa711x_state { |
| 67 | struct v4l2_subdev sd; | 68 | struct v4l2_subdev sd; |
| 69 | struct v4l2_ctrl_handler hdl; | ||
| 70 | |||
| 71 | struct { | ||
| 72 | /* chroma gain control cluster */ | ||
| 73 | struct v4l2_ctrl *agc; | ||
| 74 | struct v4l2_ctrl *gain; | ||
| 75 | }; | ||
| 76 | |||
| 68 | v4l2_std_id std; | 77 | v4l2_std_id std; |
| 69 | int input; | 78 | int input; |
| 70 | int output; | 79 | int output; |
| 71 | int enable; | 80 | int enable; |
| 72 | int radio; | 81 | int radio; |
| 73 | int bright; | ||
| 74 | int contrast; | ||
| 75 | int hue; | ||
| 76 | int sat; | ||
| 77 | int chroma_agc; | ||
| 78 | int width; | 82 | int width; |
| 79 | int height; | 83 | int height; |
| 80 | u32 ident; | 84 | u32 ident; |
| @@ -90,6 +94,11 @@ static inline struct saa711x_state *to_state(struct v4l2_subdev *sd) | |||
| 90 | return container_of(sd, struct saa711x_state, sd); | 94 | return container_of(sd, struct saa711x_state, sd); |
| 91 | } | 95 | } |
| 92 | 96 | ||
| 97 | static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) | ||
| 98 | { | ||
| 99 | return &container_of(ctrl->handler, struct saa711x_state, hdl)->sd; | ||
| 100 | } | ||
| 101 | |||
| 93 | /* ----------------------------------------------------------------------- */ | 102 | /* ----------------------------------------------------------------------- */ |
| 94 | 103 | ||
| 95 | static inline int saa711x_write(struct v4l2_subdev *sd, u8 reg, u8 value) | 104 | static inline int saa711x_write(struct v4l2_subdev *sd, u8 reg, u8 value) |
| @@ -741,96 +750,53 @@ static int saa711x_s_clock_freq(struct v4l2_subdev *sd, u32 freq) | |||
| 741 | return 0; | 750 | return 0; |
| 742 | } | 751 | } |
| 743 | 752 | ||
| 744 | static int saa711x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | 753 | static int saa711x_g_volatile_ctrl(struct v4l2_ctrl *ctrl) |
| 745 | { | 754 | { |
| 755 | struct v4l2_subdev *sd = to_sd(ctrl); | ||
| 746 | struct saa711x_state *state = to_state(sd); | 756 | struct saa711x_state *state = to_state(sd); |
| 747 | u8 val; | ||
| 748 | 757 | ||
| 749 | switch (ctrl->id) { | 758 | switch (ctrl->id) { |
| 750 | case V4L2_CID_BRIGHTNESS: | ||
| 751 | if (ctrl->value < 0 || ctrl->value > 255) { | ||
| 752 | v4l2_err(sd, "invalid brightness setting %d\n", ctrl->value); | ||
| 753 | return -ERANGE; | ||
| 754 | } | ||
| 755 | |||
| 756 | state->bright = ctrl->value; | ||
| 757 | saa711x_write(sd, R_0A_LUMA_BRIGHT_CNTL, state->bright); | ||
| 758 | break; | ||
| 759 | |||
| 760 | case V4L2_CID_CONTRAST: | ||
| 761 | if (ctrl->value < 0 || ctrl->value > 127) { | ||
| 762 | v4l2_err(sd, "invalid contrast setting %d\n", ctrl->value); | ||
| 763 | return -ERANGE; | ||
| 764 | } | ||
| 765 | |||
| 766 | state->contrast = ctrl->value; | ||
| 767 | saa711x_write(sd, R_0B_LUMA_CONTRAST_CNTL, state->contrast); | ||
| 768 | break; | ||
| 769 | |||
| 770 | case V4L2_CID_SATURATION: | ||
| 771 | if (ctrl->value < 0 || ctrl->value > 127) { | ||
| 772 | v4l2_err(sd, "invalid saturation setting %d\n", ctrl->value); | ||
| 773 | return -ERANGE; | ||
| 774 | } | ||
| 775 | |||
| 776 | state->sat = ctrl->value; | ||
| 777 | saa711x_write(sd, R_0C_CHROMA_SAT_CNTL, state->sat); | ||
| 778 | break; | ||
| 779 | |||
| 780 | case V4L2_CID_HUE: | ||
| 781 | if (ctrl->value < -128 || ctrl->value > 127) { | ||
| 782 | v4l2_err(sd, "invalid hue setting %d\n", ctrl->value); | ||
| 783 | return -ERANGE; | ||
| 784 | } | ||
| 785 | |||
| 786 | state->hue = ctrl->value; | ||
| 787 | saa711x_write(sd, R_0D_CHROMA_HUE_CNTL, state->hue); | ||
| 788 | break; | ||
| 789 | case V4L2_CID_CHROMA_AGC: | 759 | case V4L2_CID_CHROMA_AGC: |
| 790 | val = saa711x_read(sd, R_0F_CHROMA_GAIN_CNTL); | 760 | /* chroma gain cluster */ |
| 791 | state->chroma_agc = ctrl->value; | 761 | if (state->agc->cur.val) |
| 792 | if (ctrl->value) | 762 | state->gain->cur.val = |
| 793 | val &= 0x7f; | 763 | saa711x_read(sd, R_0F_CHROMA_GAIN_CNTL) & 0x7f; |
| 794 | else | ||
| 795 | val |= 0x80; | ||
| 796 | saa711x_write(sd, R_0F_CHROMA_GAIN_CNTL, val); | ||
| 797 | break; | 764 | break; |
| 798 | case V4L2_CID_CHROMA_GAIN: | ||
| 799 | /* Chroma gain cannot be set when AGC is enabled */ | ||
| 800 | if (state->chroma_agc == 1) | ||
| 801 | return -EINVAL; | ||
| 802 | saa711x_write(sd, R_0F_CHROMA_GAIN_CNTL, ctrl->value | 0x80); | ||
| 803 | break; | ||
| 804 | default: | ||
| 805 | return -EINVAL; | ||
| 806 | } | 765 | } |
| 807 | |||
| 808 | return 0; | 766 | return 0; |
| 809 | } | 767 | } |
| 810 | 768 | ||
| 811 | static int saa711x_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | 769 | static int saa711x_s_ctrl(struct v4l2_ctrl *ctrl) |
| 812 | { | 770 | { |
| 771 | struct v4l2_subdev *sd = to_sd(ctrl); | ||
| 813 | struct saa711x_state *state = to_state(sd); | 772 | struct saa711x_state *state = to_state(sd); |
| 814 | 773 | ||
| 815 | switch (ctrl->id) { | 774 | switch (ctrl->id) { |
| 816 | case V4L2_CID_BRIGHTNESS: | 775 | case V4L2_CID_BRIGHTNESS: |
| 817 | ctrl->value = state->bright; | 776 | saa711x_write(sd, R_0A_LUMA_BRIGHT_CNTL, ctrl->val); |
| 818 | break; | 777 | break; |
| 778 | |||
| 819 | case V4L2_CID_CONTRAST: | 779 | case V4L2_CID_CONTRAST: |
| 820 | ctrl->value = state->contrast; | 780 | saa711x_write(sd, R_0B_LUMA_CONTRAST_CNTL, ctrl->val); |
| 821 | break; | 781 | break; |
| 782 | |||
| 822 | case V4L2_CID_SATURATION: | 783 | case V4L2_CID_SATURATION: |
| 823 | ctrl->value = state->sat; | 784 | saa711x_write(sd, R_0C_CHROMA_SAT_CNTL, ctrl->val); |
| 824 | break; | 785 | break; |
| 786 | |||
| 825 | case V4L2_CID_HUE: | 787 | case V4L2_CID_HUE: |
| 826 | ctrl->value = state->hue; | 788 | saa711x_write(sd, R_0D_CHROMA_HUE_CNTL, ctrl->val); |
| 827 | break; | 789 | break; |
| 790 | |||
| 828 | case V4L2_CID_CHROMA_AGC: | 791 | case V4L2_CID_CHROMA_AGC: |
| 829 | ctrl->value = state->chroma_agc; | 792 | /* chroma gain cluster */ |
| 830 | break; | 793 | if (state->agc->val) |
| 831 | case V4L2_CID_CHROMA_GAIN: | 794 | saa711x_write(sd, R_0F_CHROMA_GAIN_CNTL, state->gain->val); |
| 832 | ctrl->value = saa711x_read(sd, R_0F_CHROMA_GAIN_CNTL) & 0x7f; | 795 | else |
| 796 | saa711x_write(sd, R_0F_CHROMA_GAIN_CNTL, state->gain->val | 0x80); | ||
| 797 | v4l2_ctrl_activate(state->gain, !state->agc->val); | ||
| 833 | break; | 798 | break; |
| 799 | |||
| 834 | default: | 800 | default: |
| 835 | return -EINVAL; | 801 | return -EINVAL; |
| 836 | } | 802 | } |
| @@ -1223,25 +1189,6 @@ static int saa711x_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) | |||
| 1223 | return 0; | 1189 | return 0; |
| 1224 | } | 1190 | } |
| 1225 | 1191 | ||
| 1226 | static int saa711x_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) | ||
| 1227 | { | ||
| 1228 | switch (qc->id) { | ||
| 1229 | case V4L2_CID_BRIGHTNESS: | ||
| 1230 | return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128); | ||
| 1231 | case V4L2_CID_CONTRAST: | ||
| 1232 | case V4L2_CID_SATURATION: | ||
| 1233 | return v4l2_ctrl_query_fill(qc, 0, 127, 1, 64); | ||
| 1234 | case V4L2_CID_HUE: | ||
| 1235 | return v4l2_ctrl_query_fill(qc, -128, 127, 1, 0); | ||
| 1236 | case V4L2_CID_CHROMA_AGC: | ||
| 1237 | return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); | ||
| 1238 | case V4L2_CID_CHROMA_GAIN: | ||
| 1239 | return v4l2_ctrl_query_fill(qc, 0, 127, 1, 48); | ||
| 1240 | default: | ||
| 1241 | return -EINVAL; | ||
| 1242 | } | ||
| 1243 | } | ||
| 1244 | |||
| 1245 | static int saa711x_s_std(struct v4l2_subdev *sd, v4l2_std_id std) | 1192 | static int saa711x_s_std(struct v4l2_subdev *sd, v4l2_std_id std) |
| 1246 | { | 1193 | { |
| 1247 | struct saa711x_state *state = to_state(sd); | 1194 | struct saa711x_state *state = to_state(sd); |
| @@ -1518,17 +1465,27 @@ static int saa711x_log_status(struct v4l2_subdev *sd) | |||
| 1518 | break; | 1465 | break; |
| 1519 | } | 1466 | } |
| 1520 | v4l2_info(sd, "Width, Height: %d, %d\n", state->width, state->height); | 1467 | v4l2_info(sd, "Width, Height: %d, %d\n", state->width, state->height); |
| 1468 | v4l2_ctrl_handler_log_status(&state->hdl, sd->name); | ||
| 1521 | return 0; | 1469 | return 0; |
| 1522 | } | 1470 | } |
| 1523 | 1471 | ||
| 1524 | /* ----------------------------------------------------------------------- */ | 1472 | /* ----------------------------------------------------------------------- */ |
| 1525 | 1473 | ||
| 1474 | static const struct v4l2_ctrl_ops saa711x_ctrl_ops = { | ||
| 1475 | .s_ctrl = saa711x_s_ctrl, | ||
| 1476 | .g_volatile_ctrl = saa711x_g_volatile_ctrl, | ||
| 1477 | }; | ||
| 1478 | |||
| 1526 | static const struct v4l2_subdev_core_ops saa711x_core_ops = { | 1479 | static const struct v4l2_subdev_core_ops saa711x_core_ops = { |
| 1527 | .log_status = saa711x_log_status, | 1480 | .log_status = saa711x_log_status, |
| 1528 | .g_chip_ident = saa711x_g_chip_ident, | 1481 | .g_chip_ident = saa711x_g_chip_ident, |
| 1529 | .g_ctrl = saa711x_g_ctrl, | 1482 | .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, |
| 1530 | .s_ctrl = saa711x_s_ctrl, | 1483 | .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, |
| 1531 | .queryctrl = saa711x_queryctrl, | 1484 | .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, |
| 1485 | .g_ctrl = v4l2_subdev_g_ctrl, | ||
| 1486 | .s_ctrl = v4l2_subdev_s_ctrl, | ||
| 1487 | .queryctrl = v4l2_subdev_queryctrl, | ||
| 1488 | .querymenu = v4l2_subdev_querymenu, | ||
| 1532 | .s_std = saa711x_s_std, | 1489 | .s_std = saa711x_s_std, |
| 1533 | .reset = saa711x_reset, | 1490 | .reset = saa711x_reset, |
| 1534 | .s_gpio = saa711x_s_gpio, | 1491 | .s_gpio = saa711x_s_gpio, |
| @@ -1579,8 +1536,9 @@ static int saa711x_probe(struct i2c_client *client, | |||
| 1579 | { | 1536 | { |
| 1580 | struct saa711x_state *state; | 1537 | struct saa711x_state *state; |
| 1581 | struct v4l2_subdev *sd; | 1538 | struct v4l2_subdev *sd; |
| 1582 | int i; | 1539 | struct v4l2_ctrl_handler *hdl; |
| 1583 | char name[17]; | 1540 | int i; |
| 1541 | char name[17]; | ||
| 1584 | char chip_id; | 1542 | char chip_id; |
| 1585 | int autodetect = !id || id->driver_data == 1; | 1543 | int autodetect = !id || id->driver_data == 1; |
| 1586 | 1544 | ||
| @@ -1619,15 +1577,38 @@ static int saa711x_probe(struct i2c_client *client, | |||
| 1619 | return -ENOMEM; | 1577 | return -ENOMEM; |
| 1620 | sd = &state->sd; | 1578 | sd = &state->sd; |
| 1621 | v4l2_i2c_subdev_init(sd, client, &saa711x_ops); | 1579 | v4l2_i2c_subdev_init(sd, client, &saa711x_ops); |
| 1580 | |||
| 1581 | hdl = &state->hdl; | ||
| 1582 | v4l2_ctrl_handler_init(hdl, 6); | ||
| 1583 | /* add in ascending ID order */ | ||
| 1584 | v4l2_ctrl_new_std(hdl, &saa711x_ctrl_ops, | ||
| 1585 | V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); | ||
| 1586 | v4l2_ctrl_new_std(hdl, &saa711x_ctrl_ops, | ||
| 1587 | V4L2_CID_CONTRAST, 0, 127, 1, 64); | ||
| 1588 | v4l2_ctrl_new_std(hdl, &saa711x_ctrl_ops, | ||
| 1589 | V4L2_CID_SATURATION, 0, 127, 1, 64); | ||
| 1590 | v4l2_ctrl_new_std(hdl, &saa711x_ctrl_ops, | ||
| 1591 | V4L2_CID_HUE, -128, 127, 1, 0); | ||
| 1592 | state->agc = v4l2_ctrl_new_std(hdl, &saa711x_ctrl_ops, | ||
| 1593 | V4L2_CID_CHROMA_AGC, 0, 1, 1, 1); | ||
| 1594 | state->gain = v4l2_ctrl_new_std(hdl, &saa711x_ctrl_ops, | ||
| 1595 | V4L2_CID_CHROMA_GAIN, 0, 127, 1, 40); | ||
| 1596 | state->gain->is_volatile = 1; | ||
| 1597 | sd->ctrl_handler = hdl; | ||
| 1598 | if (hdl->error) { | ||
| 1599 | int err = hdl->error; | ||
| 1600 | |||
| 1601 | v4l2_ctrl_handler_free(hdl); | ||
| 1602 | kfree(state); | ||
| 1603 | return err; | ||
| 1604 | } | ||
| 1605 | state->agc->flags |= V4L2_CTRL_FLAG_UPDATE; | ||
| 1606 | v4l2_ctrl_cluster(2, &state->agc); | ||
| 1607 | |||
| 1622 | state->input = -1; | 1608 | state->input = -1; |
| 1623 | state->output = SAA7115_IPORT_ON; | 1609 | state->output = SAA7115_IPORT_ON; |
| 1624 | state->enable = 1; | 1610 | state->enable = 1; |
| 1625 | state->radio = 0; | 1611 | state->radio = 0; |
| 1626 | state->bright = 128; | ||
| 1627 | state->contrast = 64; | ||
| 1628 | state->hue = 0; | ||
| 1629 | state->sat = 64; | ||
| 1630 | state->chroma_agc = 1; | ||
| 1631 | switch (chip_id) { | 1612 | switch (chip_id) { |
| 1632 | case '1': | 1613 | case '1': |
| 1633 | state->ident = V4L2_IDENT_SAA7111; | 1614 | state->ident = V4L2_IDENT_SAA7111; |
| @@ -1675,6 +1656,7 @@ static int saa711x_probe(struct i2c_client *client, | |||
| 1675 | if (state->ident > V4L2_IDENT_SAA7111A) | 1656 | if (state->ident > V4L2_IDENT_SAA7111A) |
| 1676 | saa711x_writeregs(sd, saa7115_init_misc); | 1657 | saa711x_writeregs(sd, saa7115_init_misc); |
| 1677 | saa711x_set_v4lstd(sd, V4L2_STD_NTSC); | 1658 | saa711x_set_v4lstd(sd, V4L2_STD_NTSC); |
| 1659 | v4l2_ctrl_handler_setup(hdl); | ||
| 1678 | 1660 | ||
| 1679 | v4l2_dbg(1, debug, sd, "status: (1E) 0x%02x, (1F) 0x%02x\n", | 1661 | v4l2_dbg(1, debug, sd, "status: (1E) 0x%02x, (1F) 0x%02x\n", |
| 1680 | saa711x_read(sd, R_1E_STATUS_BYTE_1_VD_DEC), | 1662 | saa711x_read(sd, R_1E_STATUS_BYTE_1_VD_DEC), |
| @@ -1689,6 +1671,7 @@ static int saa711x_remove(struct i2c_client *client) | |||
| 1689 | struct v4l2_subdev *sd = i2c_get_clientdata(client); | 1671 | struct v4l2_subdev *sd = i2c_get_clientdata(client); |
| 1690 | 1672 | ||
| 1691 | v4l2_device_unregister_subdev(sd); | 1673 | v4l2_device_unregister_subdev(sd); |
| 1674 | v4l2_ctrl_handler_free(sd->ctrl_handler); | ||
| 1692 | kfree(to_state(sd)); | 1675 | kfree(to_state(sd)); |
| 1693 | return 0; | 1676 | return 0; |
| 1694 | } | 1677 | } |
