diff options
Diffstat (limited to 'drivers/media')
-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 | } |