aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media')
-rw-r--r--drivers/media/video/saa7115.c183
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
66struct saa711x_state { 67struct 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
97static 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
95static inline int saa711x_write(struct v4l2_subdev *sd, u8 reg, u8 value) 104static 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
744static int saa711x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) 753static 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
811static int saa711x_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) 769static 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
1226static 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
1245static int saa711x_s_std(struct v4l2_subdev *sd, v4l2_std_id std) 1192static 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
1474static const struct v4l2_ctrl_ops saa711x_ctrl_ops = {
1475 .s_ctrl = saa711x_s_ctrl,
1476 .g_volatile_ctrl = saa711x_g_volatile_ctrl,
1477};
1478
1526static const struct v4l2_subdev_core_ops saa711x_core_ops = { 1479static 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}