adv7481: Add support for interlaced HDMI and CVBS input

Set active lines based on input standard returned by SD core.
Add vid parameter to sd_timings to return number of active lines
to user. Increase SDP_NUM_TRIES to lock stable input.
Return v4l2_field type of HDMI and CVBS INPUT to userspace.

Change-Id: Ifbde4ca32fad40bc3235fed0715c11854a8aa08c
Signed-off-by: Suprith Malligere Shankaregowda <supgow@codeaurora.org>
This commit is contained in:
Suprith Malligere Shankaregowda 2018-05-14 19:58:07 +05:30 committed by Gerrit - the friendly Code Review server
parent dfabe2ca6b
commit 966acd1e07
3 changed files with 78 additions and 13 deletions

View file

@ -51,7 +51,7 @@
#define GPIO_HW_RST_DELAY_LOW 10000 #define GPIO_HW_RST_DELAY_LOW 10000
#define SDP_MIN_SLEEP 5000 #define SDP_MIN_SLEEP 5000
#define SDP_MAX_SLEEP 6000 #define SDP_MAX_SLEEP 6000
#define SDP_NUM_TRIES 30 #define SDP_NUM_TRIES 50
#define LOCK_MIN_SLEEP 5000 #define LOCK_MIN_SLEEP 5000
#define LOCK_MAX_SLEEP 6000 #define LOCK_MAX_SLEEP 6000
#define LOCK_NUM_TRIES 200 #define LOCK_NUM_TRIES 200
@ -613,7 +613,8 @@ static void adv7481_irq_delay_work(struct work_struct *work)
pr_debug("%s: dev: %d got datapath raw status: 0x%x\n", pr_debug("%s: dev: %d got datapath raw status: 0x%x\n",
__func__, state->device_num, raw_status); __func__, state->device_num, raw_status);
if (ADV_REG_GETFIELD(int_status, IO_INT_SD_ST) && if ((state->mode == ADV7481_IP_CVBS_1) &&
ADV_REG_GETFIELD(int_status, IO_INT_SD_ST) &&
ADV_REG_GETFIELD(raw_status, IO_INT_SD_RAW)) { ADV_REG_GETFIELD(raw_status, IO_INT_SD_RAW)) {
uint8_t sdp_sts = 0; uint8_t sdp_sts = 0;
@ -649,7 +650,7 @@ static void adv7481_irq_delay_work(struct work_struct *work)
adv7481_wr_byte(&state->i2c_client, adv7481_wr_byte(&state->i2c_client,
state->i2c_sdp_addr, SDP_RW_MAP_REG, state->i2c_sdp_addr, SDP_RW_MAP_REG,
0x00); 0x00);
} else { } else if (state->mode == ADV7481_IP_HDMI) {
if (ADV_REG_GETFIELD(int_status, if (ADV_REG_GETFIELD(int_status,
IO_CP_LOCK_CP_ST) && IO_CP_LOCK_CP_ST) &&
ADV_REG_GETFIELD(raw_status, ADV_REG_GETFIELD(raw_status,
@ -1212,10 +1213,12 @@ static long adv7481_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
return ret; return ret;
} }
static int adv7481_get_sd_timings(struct adv7481_state *state, int *sd_standard) static int adv7481_get_sd_timings(struct adv7481_state *state,
int *sd_standard, struct adv7481_vid_params *vid_params)
{ {
int ret = 0; int ret = 0;
int sdp_stat, sdp_stat2; int sdp_stat, sdp_stat2;
int interlace_reg = 0;
int timeout = 0; int timeout = 0;
if (sd_standard == NULL) if (sd_standard == NULL)
@ -1232,6 +1235,25 @@ static int adv7481_get_sd_timings(struct adv7481_state *state, int *sd_standard)
sdp_stat2 = adv7481_rd_byte(&state->i2c_client, sdp_stat2 = adv7481_rd_byte(&state->i2c_client,
state->i2c_sdp_addr, SDP_RO_MAIN_STATUS1_ADDR); state->i2c_sdp_addr, SDP_RO_MAIN_STATUS1_ADDR);
} while ((sdp_stat != sdp_stat2) && (timeout < SDP_NUM_TRIES)); } while ((sdp_stat != sdp_stat2) && (timeout < SDP_NUM_TRIES));
interlace_reg = adv7481_rd_byte(&state->i2c_client,
state->i2c_sdp_addr, SDP_RO_MAIN_INTERLACE_STATE_ADDR);
if (ADV_REG_GETFIELD(interlace_reg, SDP_RO_MAIN_INTERLACE_STATE))
pr_debug("%s: Interlaced video detected\n", __func__);
else
pr_debug("%s: Interlaced video not detected\n", __func__);
if (ADV_REG_GETFIELD(interlace_reg, SDP_RO_MAIN_FIELD_LEN))
pr_debug("%s: Field length is correct\n", __func__);
else
pr_debug("%s: Field length is not correct\n", __func__);
if (ADV_REG_GETFIELD(interlace_reg, SDP_RO_MAIN_SD_FIELD_RATE))
pr_debug("%s: SD 50 Hz detected\n", __func__);
else
pr_debug("%s: SD 60 Hz detected\n", __func__);
adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr, adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
SDP_RW_MAP_REG, 0x00); SDP_RW_MAP_REG, 0x00);
@ -1245,36 +1267,58 @@ static int adv7481_get_sd_timings(struct adv7481_state *state, int *sd_standard)
__func__, __LINE__, sdp_stat); __func__, __LINE__, sdp_stat);
return -EBUSY; return -EBUSY;
} }
vid_params->act_pix = 720;
vid_params->intrlcd = 1;
switch (ADV_REG_GETFIELD(sdp_stat, SDP_RO_MAIN_AD_RESULT)) { switch (ADV_REG_GETFIELD(sdp_stat, SDP_RO_MAIN_AD_RESULT)) {
case AD_NTSM_M_J: case AD_NTSM_M_J:
*sd_standard = V4L2_STD_NTSC; *sd_standard = V4L2_STD_NTSC;
pr_debug("%s, V4L2_STD_NTSC\n", __func__);
vid_params->act_lines = 507;
break; break;
case AD_NTSC_4_43: case AD_NTSC_4_43:
*sd_standard = V4L2_STD_NTSC_443; *sd_standard = V4L2_STD_NTSC_443;
pr_debug("%s, V4L2_STD_NTSC_443\n", __func__);
vid_params->act_lines = 507;
break; break;
case AD_PAL_M: case AD_PAL_M:
*sd_standard = V4L2_STD_PAL_M; *sd_standard = V4L2_STD_PAL_M;
pr_debug("%s, V4L2_STD_PAL_M\n", __func__);
vid_params->act_lines = 576;
break; break;
case AD_PAL_60: case AD_PAL_60:
*sd_standard = V4L2_STD_PAL_60; *sd_standard = V4L2_STD_PAL_60;
pr_debug("%s, V4L2_STD_PAL_60\n", __func__);
vid_params->act_lines = 576;
break; break;
case AD_PAL_B_G: case AD_PAL_B_G:
*sd_standard = V4L2_STD_PAL; *sd_standard = V4L2_STD_PAL;
pr_debug("%s, V4L2_STD_PAL\n", __func__);
vid_params->act_lines = 576;
break; break;
case AD_SECAM: case AD_SECAM:
*sd_standard = V4L2_STD_SECAM; *sd_standard = V4L2_STD_SECAM;
pr_debug("%s, V4L2_STD_SECAM\n", __func__);
vid_params->act_lines = 576;
break; break;
case AD_PAL_COMB_N: case AD_PAL_COMB_N:
*sd_standard = V4L2_STD_PAL_Nc | V4L2_STD_PAL_N; *sd_standard = V4L2_STD_PAL_Nc | V4L2_STD_PAL_N;
pr_debug("%s, V4L2_STD_PAL_Nc | V4L2_STD_PAL_N\n", __func__);
vid_params->act_lines = 576;
break; break;
case AD_SECAM_525: case AD_SECAM_525:
*sd_standard = V4L2_STD_SECAM; *sd_standard = V4L2_STD_SECAM;
pr_debug("%s, V4L2_STD_SECAM (AD_SECAM_525)\n", __func__);
vid_params->act_lines = 576;
break; break;
default: default:
*sd_standard = V4L2_STD_UNKNOWN; *sd_standard = V4L2_STD_UNKNOWN;
pr_debug("%s, V4L2_STD_UNKNOWN\n", __func__);
vid_params->act_lines = 507;
break; break;
} }
pr_debug("%s(%d), adv7481 TMDS Resolution: %d x %d\n",
__func__, __LINE__, vid_params->act_pix, vid_params->act_lines);
return ret; return ret;
} }
@ -1893,6 +1937,8 @@ static int adv7481_get_hdmi_timings(struct adv7481_state *state,
vid_params->pix_clk = hdmi_params->tmds_freq; vid_params->pix_clk = hdmi_params->tmds_freq;
vid_params->act_lines = vid_params->act_lines * fieldfactor;
switch (hdmi_params->color_depth) { switch (hdmi_params->color_depth) {
case CD_10BIT: case CD_10BIT:
vid_params->pix_clk = ((vid_params->pix_clk*4)/5); vid_params->pix_clk = ((vid_params->pix_clk*4)/5);
@ -1993,6 +2039,9 @@ static int adv7481_query_sd_std(struct v4l2_subdev *sd, v4l2_std_id *std)
struct adv7481_state *state = to_state(sd); struct adv7481_state *state = to_state(sd);
uint8_t tStatus = 0x0; uint8_t tStatus = 0x0;
uint32_t count = 0; uint32_t count = 0;
struct adv7481_vid_params vid_params;
memset(&vid_params, 0, sizeof(vid_params));
pr_debug("Enter %s\n", __func__); pr_debug("Enter %s\n", __func__);
/* Select SDP read-only main Map */ /* Select SDP read-only main Map */
@ -2033,7 +2082,7 @@ static int adv7481_query_sd_std(struct v4l2_subdev *sd, v4l2_std_id *std)
case ADV7481_IP_CVBS_6_HDMI_SIM: case ADV7481_IP_CVBS_6_HDMI_SIM:
case ADV7481_IP_CVBS_7_HDMI_SIM: case ADV7481_IP_CVBS_7_HDMI_SIM:
case ADV7481_IP_CVBS_8_HDMI_SIM: case ADV7481_IP_CVBS_8_HDMI_SIM:
ret = adv7481_get_sd_timings(state, &temp); ret = adv7481_get_sd_timings(state, &temp, &vid_params);
break; break;
default: default:
return -EINVAL; return -EINVAL;
@ -2063,6 +2112,7 @@ static int adv7481_get_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_format *format) struct v4l2_subdev_format *format)
{ {
int ret; int ret;
int sd_standard;
struct adv7481_vid_params vid_params; struct adv7481_vid_params vid_params;
struct adv7481_hdmi_params hdmi_params; struct adv7481_hdmi_params hdmi_params;
struct adv7481_state *state = to_state(sd); struct adv7481_state *state = to_state(sd);
@ -2087,8 +2137,9 @@ static int adv7481_get_fmt(struct v4l2_subdev *sd,
if (!ret) { if (!ret) {
fmt->width = vid_params.act_pix; fmt->width = vid_params.act_pix;
fmt->height = vid_params.act_lines; fmt->height = vid_params.act_lines;
fmt->field = V4L2_FIELD_NONE;
if (vid_params.intrlcd) if (vid_params.intrlcd)
fmt->height /= 2; fmt->field = V4L2_FIELD_INTERLACED;
} else { } else {
pr_err("%s: Error %d in adv7481_get_hdmi_timings\n", pr_err("%s: Error %d in adv7481_get_hdmi_timings\n",
__func__, ret); __func__, ret);
@ -2097,8 +2148,14 @@ static int adv7481_get_fmt(struct v4l2_subdev *sd,
case ADV7481_IP_CVBS_1: case ADV7481_IP_CVBS_1:
fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; fmt->code = MEDIA_BUS_FMT_UYVY8_2X8;
fmt->colorspace = V4L2_COLORSPACE_SMPTE170M; fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
fmt->width = 720; ret = adv7481_get_sd_timings(state, &sd_standard, &vid_params);
fmt->height = 507; if (!ret) {
fmt->width = vid_params.act_pix;
fmt->height = vid_params.act_lines;
fmt->field = V4L2_FIELD_INTERLACED;
} else {
pr_err("%s: Unable to get sd_timings\n", __func__);
}
break; break;
default: default:
return -EINVAL; return -EINVAL;

View file

@ -416,6 +416,13 @@
#define SDP_RO_MAIN_LOST_LOCK_SHFT 1 #define SDP_RO_MAIN_LOST_LOCK_SHFT 1
#define SDP_RO_MAIN_IN_LOCK_BMSK 0x0001 #define SDP_RO_MAIN_IN_LOCK_BMSK 0x0001
#define SDP_RO_MAIN_IN_LOCK_SHFT 0 #define SDP_RO_MAIN_IN_LOCK_SHFT 0
#define SDP_RO_MAIN_INTERLACE_STATE_ADDR 0x13
#define SDP_RO_MAIN_INTERLACE_STATE_BMSK 0x0040
#define SDP_RO_MAIN_INTERLACE_STATE_SHFT 6
#define SDP_RO_MAIN_FIELD_LEN_BMSK 0x0020
#define SDP_RO_MAIN_FIELD_LEN_SHFT 5
#define SDP_RO_MAIN_SD_FIELD_RATE_BMSK 0x0004
#define SDP_RO_MAIN_SD_FIELD_RATE_SHFT 2
/* SDP R/O Map 1 Registers */ /* SDP R/O Map 1 Registers */
#define SDP_RO_MAP_1_FIELD_ADDR 0x45 #define SDP_RO_MAP_1_FIELD_ADDR 0x45

View file

@ -347,6 +347,7 @@ int msm_ba_g_fmt(void *instance, struct v4l2_format *f)
} else { } else {
f->fmt.pix.height = sd_fmt.format.height; f->fmt.pix.height = sd_fmt.format.height;
f->fmt.pix.width = sd_fmt.format.width; f->fmt.pix.width = sd_fmt.format.width;
f->fmt.pix.field = sd_fmt.format.field;
switch (sd_fmt.format.code) { switch (sd_fmt.format.code) {
case MEDIA_BUS_FMT_YUYV8_2X8: case MEDIA_BUS_FMT_YUYV8_2X8:
f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;