diff options
-rw-r--r-- | drivers/media/i2c/adv7180.c | 156 |
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 | ||
165 | struct adv7180_state; | 167 | struct 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 | ||
171 | struct adv7180_chip_info { | 174 | struct 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 | ||
242 | static 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 | |||
237 | static v4l2_std_id adv7180_std_to_v4l2(u8 status1) | 248 | static 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 | ||
580 | static 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 | |||
568 | static int adv7180_get_pad_format(struct v4l2_subdev *sd, | 618 | static 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 | ||
575 | static int adv7180_set_pad_format(struct v4l2_subdev *sd, | 634 | static 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 | ||
582 | static int adv7180_g_mbus_config(struct v4l2_subdev *sd, | 667 | static 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 | ||
860 | static const struct adv7180_chip_info adv7280_info = { | 949 | static 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 | ||
874 | static const struct adv7180_chip_info adv7280_m_info = { | 963 | static 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 | ||
1044 | static 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 | |||
1059 | static 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 | |||
955 | static int init_device(struct adv7180_state *state) | 1078 | static 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); |
1079 | err_free_ctrl: | 1214 | err_free_ctrl: |
1080 | adv7180_exit_controls(state); | 1215 | adv7180_exit_controls(state); |
1216 | err_unregister_vpp_client: | ||
1217 | if (state->chip_info->flags & ADV7180_FLAG_I2P) | ||
1218 | i2c_unregister_device(state->vpp_client); | ||
1081 | err_unregister_csi_client: | 1219 | err_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 | }; |
1121 | MODULE_DEVICE_TABLE(i2c, adv7180_id); | 1261 | MODULE_DEVICE_TABLE(i2c, adv7180_id); |