aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars-Peter Clausen <lars@metafoo.de>2015-01-23 10:52:32 -0500
committerMauro Carvalho Chehab <mchehab@osg.samsung.com>2015-02-02 08:50:54 -0500
commit851a54effbd808daf8b961f1dc6156c06a96d5f1 (patch)
tree222aecd952678b7370dbb7cfd91491a94852ea71
parentb37135e395c37a8d63defafcb567d55220a672f0 (diff)
[media] adv7180: Add I2P support
Some of the devices supported by this driver have a interlaced-to- progressive converter which can optionally be enabled. This patch adds support for enabling and disabling the I2P converter on such devices. I2P mode can be enabled by selecting V4L2_FIELD_NONE instead of V4L2_FIELD_INTERLACED for the format. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> Acked-by: Federico Vaga <federico.vaga@gmail.com> Acked-by: Hans Verkuil <hans.verkuil@cisco.com> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
-rw-r--r--drivers/media/i2c/adv7180.c156
1 files changed, 148 insertions, 8 deletions
diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c
index 195d28f48c30..3c1c866d1e3c 100644
--- a/drivers/media/i2c/adv7180.c
+++ b/drivers/media/i2c/adv7180.c
@@ -124,6 +124,7 @@
124#define ADV7180_REG_NTSC_V_BIT_END 0x00E6 124#define ADV7180_REG_NTSC_V_BIT_END 0x00E6
125#define ADV7180_NTSC_V_BIT_END_MANUAL_NVEND 0x4F 125#define ADV7180_NTSC_V_BIT_END_MANUAL_NVEND 0x4F
126 126
127#define ADV7180_REG_VPP_SLAVE_ADDR 0xFD
127#define ADV7180_REG_CSI_SLAVE_ADDR 0xFE 128#define ADV7180_REG_CSI_SLAVE_ADDR 0xFE
128 129
129#define ADV7180_CSI_REG_PWRDN 0x00 130#define ADV7180_CSI_REG_PWRDN 0x00
@@ -161,12 +162,14 @@
161#define ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8 0x11 162#define ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8 0x11
162 163
163#define ADV7180_DEFAULT_CSI_I2C_ADDR 0x44 164#define ADV7180_DEFAULT_CSI_I2C_ADDR 0x44
165#define ADV7180_DEFAULT_VPP_I2C_ADDR 0x42
164 166
165struct adv7180_state; 167struct adv7180_state;
166 168
167#define ADV7180_FLAG_RESET_POWERED BIT(0) 169#define ADV7180_FLAG_RESET_POWERED BIT(0)
168#define ADV7180_FLAG_V2 BIT(1) 170#define ADV7180_FLAG_V2 BIT(1)
169#define ADV7180_FLAG_MIPI_CSI2 BIT(2) 171#define ADV7180_FLAG_MIPI_CSI2 BIT(2)
172#define ADV7180_FLAG_I2P BIT(3)
170 173
171struct adv7180_chip_info { 174struct adv7180_chip_info {
172 unsigned int flags; 175 unsigned int flags;
@@ -190,7 +193,9 @@ struct adv7180_state {
190 struct i2c_client *client; 193 struct i2c_client *client;
191 unsigned int register_page; 194 unsigned int register_page;
192 struct i2c_client *csi_client; 195 struct i2c_client *csi_client;
196 struct i2c_client *vpp_client;
193 const struct adv7180_chip_info *chip_info; 197 const struct adv7180_chip_info *chip_info;
198 enum v4l2_field field;
194}; 199};
195#define to_adv7180_sd(_ctrl) (&container_of(_ctrl->handler, \ 200#define to_adv7180_sd(_ctrl) (&container_of(_ctrl->handler, \
196 struct adv7180_state, \ 201 struct adv7180_state, \
@@ -234,6 +239,12 @@ static int adv7180_set_video_standard(struct adv7180_state *state,
234 return state->chip_info->set_std(state, std); 239 return state->chip_info->set_std(state, std);
235} 240}
236 241
242static int adv7180_vpp_write(struct adv7180_state *state, unsigned int reg,
243 unsigned int value)
244{
245 return i2c_smbus_write_byte_data(state->vpp_client, reg, value);
246}
247
237static v4l2_std_id adv7180_std_to_v4l2(u8 status1) 248static v4l2_std_id adv7180_std_to_v4l2(u8 status1)
238{ 249{
239 /* in case V4L2_IN_ST_NO_SIGNAL */ 250 /* in case V4L2_IN_ST_NO_SIGNAL */
@@ -438,6 +449,8 @@ static int adv7180_set_power(struct adv7180_state *state, bool on)
438 adv7180_csi_write(state, 0xD8, 0x65); 449 adv7180_csi_write(state, 0xD8, 0x65);
439 adv7180_csi_write(state, 0xE0, 0x09); 450 adv7180_csi_write(state, 0xE0, 0x09);
440 adv7180_csi_write(state, 0x2C, 0x00); 451 adv7180_csi_write(state, 0x2C, 0x00);
452 if (state->field == V4L2_FIELD_NONE)
453 adv7180_csi_write(state, 0x1D, 0x80);
441 adv7180_csi_write(state, 0x00, 0x00); 454 adv7180_csi_write(state, 0x00, 0x00);
442 } else { 455 } else {
443 adv7180_csi_write(state, 0x00, 0x80); 456 adv7180_csi_write(state, 0x00, 0x80);
@@ -558,25 +571,97 @@ static int adv7180_mbus_fmt(struct v4l2_subdev *sd,
558 571
559 fmt->code = MEDIA_BUS_FMT_YUYV8_2X8; 572 fmt->code = MEDIA_BUS_FMT_YUYV8_2X8;
560 fmt->colorspace = V4L2_COLORSPACE_SMPTE170M; 573 fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
561 fmt->field = V4L2_FIELD_INTERLACED;
562 fmt->width = 720; 574 fmt->width = 720;
563 fmt->height = state->curr_norm & V4L2_STD_525_60 ? 480 : 576; 575 fmt->height = state->curr_norm & V4L2_STD_525_60 ? 480 : 576;
564 576
565 return 0; 577 return 0;
566} 578}
567 579
580static int adv7180_set_field_mode(struct adv7180_state *state)
581{
582 if (!(state->chip_info->flags & ADV7180_FLAG_I2P))
583 return 0;
584
585 if (state->field == V4L2_FIELD_NONE) {
586 if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) {
587 adv7180_csi_write(state, 0x01, 0x20);
588 adv7180_csi_write(state, 0x02, 0x28);
589 adv7180_csi_write(state, 0x03, 0x38);
590 adv7180_csi_write(state, 0x04, 0x30);
591 adv7180_csi_write(state, 0x05, 0x30);
592 adv7180_csi_write(state, 0x06, 0x80);
593 adv7180_csi_write(state, 0x07, 0x70);
594 adv7180_csi_write(state, 0x08, 0x50);
595 }
596 adv7180_vpp_write(state, 0xa3, 0x00);
597 adv7180_vpp_write(state, 0x5b, 0x00);
598 adv7180_vpp_write(state, 0x55, 0x80);
599 } else {
600 if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) {
601 adv7180_csi_write(state, 0x01, 0x18);
602 adv7180_csi_write(state, 0x02, 0x18);
603 adv7180_csi_write(state, 0x03, 0x30);
604 adv7180_csi_write(state, 0x04, 0x20);
605 adv7180_csi_write(state, 0x05, 0x28);
606 adv7180_csi_write(state, 0x06, 0x40);
607 adv7180_csi_write(state, 0x07, 0x58);
608 adv7180_csi_write(state, 0x08, 0x30);
609 }
610 adv7180_vpp_write(state, 0xa3, 0x70);
611 adv7180_vpp_write(state, 0x5b, 0x80);
612 adv7180_vpp_write(state, 0x55, 0x00);
613 }
614
615 return 0;
616}
617
568static int adv7180_get_pad_format(struct v4l2_subdev *sd, 618static int adv7180_get_pad_format(struct v4l2_subdev *sd,
569 struct v4l2_subdev_fh *fh, 619 struct v4l2_subdev_fh *fh,
570 struct v4l2_subdev_format *format) 620 struct v4l2_subdev_format *format)
571{ 621{
572 return adv7180_mbus_fmt(sd, &format->format); 622 struct adv7180_state *state = to_state(sd);
623
624 if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
625 format->format = *v4l2_subdev_get_try_format(fh, 0);
626 } else {
627 adv7180_mbus_fmt(sd, &format->format);
628 format->format.field = state->field;
629 }
630
631 return 0;
573} 632}
574 633
575static int adv7180_set_pad_format(struct v4l2_subdev *sd, 634static int adv7180_set_pad_format(struct v4l2_subdev *sd,
576 struct v4l2_subdev_fh *fh, 635 struct v4l2_subdev_fh *fh,
577 struct v4l2_subdev_format *format) 636 struct v4l2_subdev_format *format)
578{ 637{
579 return adv7180_mbus_fmt(sd, &format->format); 638 struct adv7180_state *state = to_state(sd);
639 struct v4l2_mbus_framefmt *framefmt;
640
641 switch (format->format.field) {
642 case V4L2_FIELD_NONE:
643 if (!(state->chip_info->flags & ADV7180_FLAG_I2P))
644 format->format.field = V4L2_FIELD_INTERLACED;
645 break;
646 default:
647 format->format.field = V4L2_FIELD_INTERLACED;
648 break;
649 }
650
651 if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
652 framefmt = &format->format;
653 if (state->field != format->format.field) {
654 state->field = format->format.field;
655 adv7180_set_power(state, false);
656 adv7180_set_field_mode(state);
657 adv7180_set_power(state, true);
658 }
659 } else {
660 framefmt = v4l2_subdev_get_try_format(fh, 0);
661 *framefmt = format->format;
662 }
663
664 return adv7180_mbus_fmt(sd, framefmt);
580} 665}
581 666
582static int adv7180_g_mbus_config(struct v4l2_subdev *sd, 667static int adv7180_g_mbus_config(struct v4l2_subdev *sd,
@@ -684,6 +769,10 @@ static int adv7182_init(struct adv7180_state *state)
684 adv7180_write(state, ADV7180_REG_CSI_SLAVE_ADDR, 769 adv7180_write(state, ADV7180_REG_CSI_SLAVE_ADDR,
685 ADV7180_DEFAULT_CSI_I2C_ADDR << 1); 770 ADV7180_DEFAULT_CSI_I2C_ADDR << 1);
686 771
772 if (state->chip_info->flags & ADV7180_FLAG_I2P)
773 adv7180_write(state, ADV7180_REG_VPP_SLAVE_ADDR,
774 ADV7180_DEFAULT_VPP_I2C_ADDR << 1);
775
687 if (state->chip_info->flags & ADV7180_FLAG_V2) { 776 if (state->chip_info->flags & ADV7180_FLAG_V2) {
688 /* ADI recommended writes for improved video quality */ 777 /* ADI recommended writes for improved video quality */
689 adv7180_write(state, 0x0080, 0x51); 778 adv7180_write(state, 0x0080, 0x51);
@@ -858,7 +947,7 @@ static const struct adv7180_chip_info adv7182_info = {
858}; 947};
859 948
860static const struct adv7180_chip_info adv7280_info = { 949static const struct adv7180_chip_info adv7280_info = {
861 .flags = ADV7180_FLAG_V2, 950 .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_I2P,
862 .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | 951 .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) |
863 BIT(ADV7182_INPUT_CVBS_AIN2) | 952 BIT(ADV7182_INPUT_CVBS_AIN2) |
864 BIT(ADV7182_INPUT_CVBS_AIN3) | 953 BIT(ADV7182_INPUT_CVBS_AIN3) |
@@ -872,7 +961,7 @@ static const struct adv7180_chip_info adv7280_info = {
872}; 961};
873 962
874static const struct adv7180_chip_info adv7280_m_info = { 963static const struct adv7180_chip_info adv7280_m_info = {
875 .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2, 964 .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2 | ADV7180_FLAG_I2P,
876 .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | 965 .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) |
877 BIT(ADV7182_INPUT_CVBS_AIN2) | 966 BIT(ADV7182_INPUT_CVBS_AIN2) |
878 BIT(ADV7182_INPUT_CVBS_AIN3) | 967 BIT(ADV7182_INPUT_CVBS_AIN3) |
@@ -952,6 +1041,40 @@ static const struct adv7180_chip_info adv7281_ma_info = {
952 .select_input = adv7182_select_input, 1041 .select_input = adv7182_select_input,
953}; 1042};
954 1043
1044static const struct adv7180_chip_info adv7282_info = {
1045 .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_I2P,
1046 .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) |
1047 BIT(ADV7182_INPUT_CVBS_AIN2) |
1048 BIT(ADV7182_INPUT_CVBS_AIN7) |
1049 BIT(ADV7182_INPUT_CVBS_AIN8) |
1050 BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) |
1051 BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) |
1052 BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) |
1053 BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8),
1054 .init = adv7182_init,
1055 .set_std = adv7182_set_std,
1056 .select_input = adv7182_select_input,
1057};
1058
1059static const struct adv7180_chip_info adv7282_m_info = {
1060 .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2 | ADV7180_FLAG_I2P,
1061 .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) |
1062 BIT(ADV7182_INPUT_CVBS_AIN2) |
1063 BIT(ADV7182_INPUT_CVBS_AIN3) |
1064 BIT(ADV7182_INPUT_CVBS_AIN4) |
1065 BIT(ADV7182_INPUT_CVBS_AIN7) |
1066 BIT(ADV7182_INPUT_CVBS_AIN8) |
1067 BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) |
1068 BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) |
1069 BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) |
1070 BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) |
1071 BIT(ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4) |
1072 BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8),
1073 .init = adv7182_init,
1074 .set_std = adv7182_set_std,
1075 .select_input = adv7182_select_input,
1076};
1077
955static int init_device(struct adv7180_state *state) 1078static int init_device(struct adv7180_state *state)
956{ 1079{
957 int ret; 1080 int ret;
@@ -969,6 +1092,8 @@ static int init_device(struct adv7180_state *state)
969 if (ret) 1092 if (ret)
970 goto out_unlock; 1093 goto out_unlock;
971 1094
1095 adv7180_set_field_mode(state);
1096
972 /* register for interrupts */ 1097 /* register for interrupts */
973 if (state->irq > 0) { 1098 if (state->irq > 0) {
974 /* config the Interrupt pin to be active low */ 1099 /* config the Interrupt pin to be active low */
@@ -1022,6 +1147,7 @@ static int adv7180_probe(struct i2c_client *client,
1022 return -ENOMEM; 1147 return -ENOMEM;
1023 1148
1024 state->client = client; 1149 state->client = client;
1150 state->field = V4L2_FIELD_INTERLACED;
1025 state->chip_info = (struct adv7180_chip_info *)id->driver_data; 1151 state->chip_info = (struct adv7180_chip_info *)id->driver_data;
1026 1152
1027 if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) { 1153 if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) {
@@ -1031,6 +1157,15 @@ static int adv7180_probe(struct i2c_client *client,
1031 return -ENOMEM; 1157 return -ENOMEM;
1032 } 1158 }
1033 1159
1160 if (state->chip_info->flags & ADV7180_FLAG_I2P) {
1161 state->vpp_client = i2c_new_dummy(client->adapter,
1162 ADV7180_DEFAULT_VPP_I2C_ADDR);
1163 if (!state->vpp_client) {
1164 ret = -ENOMEM;
1165 goto err_unregister_csi_client;
1166 }
1167 }
1168
1034 state->irq = client->irq; 1169 state->irq = client->irq;
1035 mutex_init(&state->mutex); 1170 mutex_init(&state->mutex);
1036 state->autodetect = true; 1171 state->autodetect = true;
@@ -1045,7 +1180,7 @@ static int adv7180_probe(struct i2c_client *client,
1045 1180
1046 ret = adv7180_init_controls(state); 1181 ret = adv7180_init_controls(state);
1047 if (ret) 1182 if (ret)
1048 goto err_unregister_csi_client; 1183 goto err_unregister_vpp_client;
1049 1184
1050 state->pad.flags = MEDIA_PAD_FL_SOURCE; 1185 state->pad.flags = MEDIA_PAD_FL_SOURCE;
1051 sd->entity.flags |= MEDIA_ENT_T_V4L2_SUBDEV_DECODER; 1186 sd->entity.flags |= MEDIA_ENT_T_V4L2_SUBDEV_DECODER;
@@ -1078,6 +1213,9 @@ err_media_entity_cleanup:
1078 media_entity_cleanup(&sd->entity); 1213 media_entity_cleanup(&sd->entity);
1079err_free_ctrl: 1214err_free_ctrl:
1080 adv7180_exit_controls(state); 1215 adv7180_exit_controls(state);
1216err_unregister_vpp_client:
1217 if (state->chip_info->flags & ADV7180_FLAG_I2P)
1218 i2c_unregister_device(state->vpp_client);
1081err_unregister_csi_client: 1219err_unregister_csi_client:
1082 if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) 1220 if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2)
1083 i2c_unregister_device(state->csi_client); 1221 i2c_unregister_device(state->csi_client);
@@ -1098,6 +1236,8 @@ static int adv7180_remove(struct i2c_client *client)
1098 media_entity_cleanup(&sd->entity); 1236 media_entity_cleanup(&sd->entity);
1099 adv7180_exit_controls(state); 1237 adv7180_exit_controls(state);
1100 1238
1239 if (state->chip_info->flags & ADV7180_FLAG_I2P)
1240 i2c_unregister_device(state->vpp_client);
1101 if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) 1241 if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2)
1102 i2c_unregister_device(state->csi_client); 1242 i2c_unregister_device(state->csi_client);
1103 1243
@@ -1114,8 +1254,8 @@ static const struct i2c_device_id adv7180_id[] = {
1114 { "adv7281", (kernel_ulong_t)&adv7281_info }, 1254 { "adv7281", (kernel_ulong_t)&adv7281_info },
1115 { "adv7281-m", (kernel_ulong_t)&adv7281_m_info }, 1255 { "adv7281-m", (kernel_ulong_t)&adv7281_m_info },
1116 { "adv7281-ma", (kernel_ulong_t)&adv7281_ma_info }, 1256 { "adv7281-ma", (kernel_ulong_t)&adv7281_ma_info },
1117 { "adv7282", (kernel_ulong_t)&adv7281_info }, 1257 { "adv7282", (kernel_ulong_t)&adv7282_info },
1118 { "adv7282-m", (kernel_ulong_t)&adv7281_m_info }, 1258 { "adv7282-m", (kernel_ulong_t)&adv7282_m_info },
1119 {}, 1259 {},
1120}; 1260};
1121MODULE_DEVICE_TABLE(i2c, adv7180_id); 1261MODULE_DEVICE_TABLE(i2c, adv7180_id);