From 9042f7a974903739d42229e81510f7c030bfccb2 Mon Sep 17 00:00:00 2001 From: Chen Shunqing Date: Wed, 16 Apr 2025 10:12:24 +0800 Subject: [PATCH] media: i2c: rk628: fix i2c error when hdmirx reset Signed-off-by: Chen Shunqing Change-Id: Ia8f2a890433fd10f3fee4346e8d8a645385c5acf --- drivers/media/i2c/rk628/rk628.c | 27 ++++++++++++++++++--- drivers/media/i2c/rk628/rk628.h | 2 ++ drivers/media/i2c/rk628/rk628_bt1120_v4l2.c | 7 +++--- drivers/media/i2c/rk628/rk628_csi_v4l2.c | 17 ++++++------- drivers/media/i2c/rk628/rk628_hdmirx.c | 14 ++++------- 5 files changed, 43 insertions(+), 24 deletions(-) diff --git a/drivers/media/i2c/rk628/rk628.c b/drivers/media/i2c/rk628/rk628.c index 9f7ccec1a1f8..51d6b4d3f2be 100644 --- a/drivers/media/i2c/rk628/rk628.c +++ b/drivers/media/i2c/rk628/rk628.c @@ -276,7 +276,13 @@ int rk628_media_i2c_write(struct rk628 *rk628, u32 reg, u32 val) return -EINVAL; } - ret = regmap_write(rk628->regmap[region], reg, val); + if (region == RK628_DEV_HDMIRX) { + mutex_lock(&rk628->rst_lock); + ret = regmap_write(rk628->regmap[region], reg, val); + mutex_unlock(&rk628->rst_lock); + } else { + ret = regmap_write(rk628->regmap[region], reg, val); + } if (ret < 0) dev_err(rk628->dev, "%s: i2c err reg=0x%x, val=0x%x, ret=%d\n", __func__, reg, val, ret); @@ -296,7 +302,13 @@ int rk628_media_i2c_read(struct rk628 *rk628, u32 reg, u32 *val) return -EINVAL; } - ret = regmap_read(rk628->regmap[region], reg, val); + if (region == RK628_DEV_HDMIRX) { + mutex_lock(&rk628->rst_lock); + ret = regmap_read(rk628->regmap[region], reg, val); + mutex_unlock(&rk628->rst_lock); + } else { + ret = regmap_read(rk628->regmap[region], reg, val); + } if (ret < 0) dev_err(rk628->dev, "%s: i2c err reg=0x%x, val=0x%x ret=%d\n", __func__, reg, *val, ret); @@ -309,6 +321,7 @@ int rk628_media_i2c_update_bits(struct rk628 *rk628, u32 reg, u32 mask, u32 val) { int region = (reg >> 16) & 0xff; + int ret; if (region >= RK628_DEV_MAX) { dev_err(rk628->dev, @@ -316,7 +329,15 @@ int rk628_media_i2c_update_bits(struct rk628 *rk628, u32 reg, u32 mask, return -EINVAL; } - return regmap_update_bits(rk628->regmap[region], reg, mask, val); + if (region == RK628_DEV_HDMIRX) { + mutex_lock(&rk628->rst_lock); + ret = regmap_update_bits(rk628->regmap[region], reg, mask, val); + mutex_unlock(&rk628->rst_lock); + } else { + ret = regmap_update_bits(rk628->regmap[region], reg, mask, val); + } + + return ret; } EXPORT_SYMBOL(rk628_media_i2c_update_bits); diff --git a/drivers/media/i2c/rk628/rk628.h b/drivers/media/i2c/rk628/rk628.h index f72a34706161..f8312b71a132 100644 --- a/drivers/media/i2c/rk628/rk628.h +++ b/drivers/media/i2c/rk628/rk628.h @@ -306,6 +306,8 @@ struct rk628 { bool dual_mipi; struct mipi_timing mipi_timing[2]; struct mutex rst_lock; + int dvi_mode; + int vic; int tx_mode; int dbg_en; struct dentry *debug_dir; diff --git a/drivers/media/i2c/rk628/rk628_bt1120_v4l2.c b/drivers/media/i2c/rk628/rk628_bt1120_v4l2.c index b6484abc22ad..6c92a221257a 100644 --- a/drivers/media/i2c/rk628/rk628_bt1120_v4l2.c +++ b/drivers/media/i2c/rk628/rk628_bt1120_v4l2.c @@ -347,6 +347,7 @@ static void rk628_hdmirx_plugout(struct v4l2_subdev *sd) rk628_bt1120_enable_interrupts(sd, false); cancel_delayed_work(&bt1120->delayed_work_res_change); rk628_hdmirx_audio_cancel_work_audio(bt1120->audio_info, true); + rk628_bt1120_hdmirx_reset(sd); rk628_hdmirx_hpd_ctrl(sd, false); rk628_hdmirx_inno_phy_power_off(sd); rk628_hdmirx_verisyno_phy_power_off(bt1120->rk628); @@ -431,7 +432,7 @@ static void rk628_bt1120_delayed_work_enable_hotplug(struct work_struct *work) if (plugin) { rk628_set_io_func_to_vop(bt1120->rk628); rk628_bt1120_enable_interrupts(sd, false); - cancel_delayed_work_sync(&bt1120->delayed_work_res_change); + cancel_delayed_work(&bt1120->delayed_work_res_change); rk628_hdmirx_audio_setup(bt1120->audio_info); rk628_hdmirx_set_hdcp(bt1120->rk628, &bt1120->hdcp, bt1120->hdcp.enable); rk628_hdmirx_controller_setup(bt1120->rk628); @@ -498,6 +499,7 @@ static void rk628_delayed_work_res_change(struct work_struct *work) if (bt1120->rk628->version >= RK628F_VERSION) { rk628_bt1120_enable_interrupts(sd, false); rk628_hdmirx_audio_cancel_work_audio(bt1120->audio_info, true); + rk628_bt1120_hdmirx_reset(sd); rk628_hdmirx_verisyno_phy_power_off(bt1120->rk628); schedule_delayed_work(&bt1120->delayed_work_enable_hotplug, msecs_to_jiffies(100)); @@ -516,6 +518,7 @@ static void rk628_delayed_work_res_change(struct work_struct *work) } } else { rk628_bt1120_format_change(sd); + bt1120->nosignal = false; rk628_bt1120_enable_interrupts(sd, true); } } @@ -1120,11 +1123,9 @@ static int rk628_hdmirx_isr(struct v4l2_subdev *sd, u32 status, bool *handled) { struct rk628_bt1120 *bt1120 = to_bt1120(sd); - mutex_lock(&bt1120->rk628->rst_lock); rk628_hdmirx_general_isr(sd, status, handled); if (bt1120->cec_enable && bt1120->cec) rk628_hdmirx_cec_irq(bt1120->rk628, bt1120->cec); - mutex_unlock(&bt1120->rk628->rst_lock); rk628_bt1120_clear_hdmirx_interrupts(sd); diff --git a/drivers/media/i2c/rk628/rk628_csi_v4l2.c b/drivers/media/i2c/rk628/rk628_csi_v4l2.c index 552c90f94543..bbbb36d284ef 100644 --- a/drivers/media/i2c/rk628/rk628_csi_v4l2.c +++ b/drivers/media/i2c/rk628/rk628_csi_v4l2.c @@ -510,6 +510,7 @@ static void rk628_hdmirx_plugout(struct v4l2_subdev *sd) rk628_csi_enable_interrupts(sd, false); cancel_delayed_work(&csi->delayed_work_res_change); rk628_hdmirx_audio_cancel_work_audio(csi->audio_info, true); + rk628_csi_hdmirx_reset(sd); rk628_hdmirx_hpd_ctrl(sd, false); rk628_hdmirx_inno_phy_power_off(sd); rk628_hdmirx_verisyno_phy_power_off(csi->rk628); @@ -567,7 +568,7 @@ static void rk628_csi_delayed_work_enable_hotplug(struct work_struct *work) if (plugin) { extcon_set_state_sync(csi->extcon, EXTCON_JACK_VIDEO_IN, true); rk628_csi_enable_interrupts(sd, false); - cancel_delayed_work_sync(&csi->delayed_work_res_change); + cancel_delayed_work(&csi->delayed_work_res_change); rk628_hdmirx_audio_setup(csi->audio_info); rk628_hdmirx_set_hdcp(csi->rk628, &csi->hdcp, csi->hdcp.enable); rk628_hdmirx_controller_setup(csi->rk628); @@ -632,13 +633,14 @@ static void rk628_delayed_work_res_change(struct work_struct *work) if (csi->rk628->version >= RK628F_VERSION) { rk628_csi_enable_interrupts(sd, false); rk628_hdmirx_audio_cancel_work_audio(csi->audio_info, true); + rk628_csi_hdmirx_reset(sd); rk628_hdmirx_verisyno_phy_power_off(csi->rk628); schedule_delayed_work(&csi->delayed_work_enable_hotplug, msecs_to_jiffies(100)); } else { rk628_hdmirx_audio_cancel_work_audio(csi->audio_info, true); rk628_hdmirx_inno_phy_power_off(sd); - rk628_hdmirx_controller_reset(csi->rk628); + rk628_csi_hdmirx_reset(sd); rk628_hdmirx_audio_setup(csi->audio_info); rk628_hdmirx_set_hdcp(csi->rk628, &csi->hdcp, csi->hdcp.enable); rk628_hdmirx_controller_setup(csi->rk628); @@ -651,6 +653,7 @@ static void rk628_delayed_work_res_change(struct work_struct *work) } } else { rk628_csi_format_change(sd); + csi->nosignal = false; rk628_csi_enable_interrupts(sd, true); } } @@ -1852,11 +1855,9 @@ static int rk628_hdmirx_isr(struct v4l2_subdev *sd, u32 status, bool *handled) { struct rk628_csi *csi = to_csi(sd); - mutex_lock(&csi->rk628->rst_lock); rk628_hdmirx_general_isr(sd, status, handled); if (csi->cec_enable && csi->cec) rk628_hdmirx_cec_irq(csi->rk628, csi->cec); - mutex_unlock(&csi->rk628->rst_lock); rk628_csi_clear_hdmirx_interrupts(sd); @@ -2530,7 +2531,6 @@ static long rk628_csi_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) long ret = 0; struct rkmodule_csi_dphy_param *dphy_param; struct rkmodule_capture_info *capture_info; - u32 val; u32 stream = 0; int edid_version, i; @@ -2583,8 +2583,7 @@ static long rk628_csi_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) *(int *)arg = rk628_hdmirx_get_hdcp_enc_status(csi->rk628); break; case RK_HDMIRX_CMD_GET_INPUT_MODE: - rk628_i2c_read(csi->rk628, HDMI_RX_PDEC_STS, &val); - *(int *)arg = val & DVI_DET; + *(int *)arg = csi->rk628->dvi_mode; break; case RK_HDMIRX_CMD_GET_SIGNAL_STABLE_STATUS: *(int *)arg = !csi->nosignal; @@ -2601,10 +2600,10 @@ static long rk628_csi_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) case RK_HDMIRX_CMD_SET_EDID_MODE: break; case RK_HDMIRX_CMD_GET_COLOR_RANGE: - *(int *)arg = rk628_hdmirx_get_range(csi->rk628); + *(int *)arg = csi->rk628->color_range; break; case RK_HDMIRX_CMD_GET_COLOR_SPACE: - *(int *)arg = rk628_hdmirx_get_color_space(csi->rk628); + *(int *)arg = csi->rk628->color_space; break; case RKMODULE_GET_DSI_MODE: *(int *)arg = csi->dsi.vid_mode; diff --git a/drivers/media/i2c/rk628/rk628_hdmirx.c b/drivers/media/i2c/rk628/rk628_hdmirx.c index 373ea391b30b..1df0c40e9a75 100644 --- a/drivers/media/i2c/rk628/rk628_hdmirx.c +++ b/drivers/media/i2c/rk628/rk628_hdmirx.c @@ -1126,10 +1126,8 @@ static int rk628_hdmirx_cec_log_addr(struct cec_adapter *adap, u8 logical_addr) else cec->addresses |= BIT(logical_addr) | BIT(15); - mutex_lock(&rk628->rst_lock); rk628_i2c_write(rk628, HDMI_RX_CEC_ADDR_L, cec->addresses & 0xff); rk628_i2c_write(rk628, HDMI_RX_CEC_ADDR_H, (cec->addresses >> 8) & 0xff); - mutex_unlock(&rk628->rst_lock); return 0; } @@ -1139,7 +1137,6 @@ static int rk628_hdmirx_cec_enable(struct cec_adapter *adap, bool enable) struct rk628_hdmirx_cec *cec = cec_get_drvdata(adap); struct rk628 *rk628 = cec->rk628; - mutex_lock(&rk628->rst_lock); if (!enable) { rk628_i2c_write(rk628, HDMI_RX_AUD_CEC_IEN_CLR, ~0); rk628_i2c_update_bits(rk628, HDMI_RX_DMI_DISABLE_IF, CEC_ENABLE_MASK, 0); @@ -1156,7 +1153,6 @@ static int rk628_hdmirx_cec_enable(struct cec_adapter *adap, bool enable) irqs = ERROR_INIT_ENSET | NACK_ENSET | EOM_ENSET | DONE_ENSET; rk628_i2c_write(rk628, HDMI_RX_AUD_CEC_IEN_SET, irqs); } - mutex_unlock(&rk628->rst_lock); return 0; } @@ -1188,13 +1184,11 @@ static int rk628_hdmirx_cec_transmit(struct cec_adapter *adap, u8 attempts, if (msg_len <= 0) return 0; - mutex_lock(&rk628->rst_lock); for (i = 0; i < msg_len; i++) rk628_i2c_write(rk628, HDMI_RX_CEC_TX_DATA_0 + i * 4, msg->msg[i]); rk628_i2c_write(rk628, HDMI_RX_CEC_TX_CNT, msg_len); rk628_i2c_write(rk628, HDMI_RX_CEC_CTRL, ctrl | CEC_SEND); - mutex_unlock(&rk628->rst_lock); return 0; } @@ -1298,7 +1292,6 @@ struct rk628_hdmirx_cec *rk628_hdmirx_cec_register(struct rk628 *rk628) rk628_i2c_update_bits(rk628, HDMI_RX_DMI_DISABLE_IF, CEC_ENABLE_MASK, CEC_ENABLE_MASK); rk628_i2c_write(rk628, HDMI_RX_CEC_TX_CNT, 0); - rk628_i2c_write(rk628, HDMI_RX_CEC_RX_CNT, 0); /* clk_hdmirx_cec = 32.768k */ rk628_clk_set_rate(rk628, CGU_CLK_HDMIRX_CEC, 32768); @@ -1633,6 +1626,7 @@ static int rk628_hdmirx_read_timing(struct rk628 *rk628, rk628_i2c_read(rk628, HDMI_RX_PDEC_AVI_PB, &val); vic = (val & VID_IDENT_CODE_MASK) >> 24; + rk628->vic = vic; rk628_i2c_read(rk628, HDMI_RX_PDEC_GCP_AVMUTE, &format); format = (format & PKTDEC_GCP_CD_MASK) >> 4; video_fmt = rk628_hdmirx_get_format(rk628); @@ -1641,6 +1635,8 @@ static int rk628_hdmirx_read_timing(struct rk628 *rk628, rk628->color_range = color_range; color_space = rk628_hdmirx_get_color_space(rk628); rk628->color_space = color_space; + rk628_i2c_read(rk628, HDMI_RX_PDEC_STS, &val); + rk628->dvi_mode = val & DVI_DET; if (video_fmt == BUS_FMT_YUV420) { //format:color depth, 5: 10bit, 4: 8bit if (format == 5) { @@ -1865,12 +1861,12 @@ void rk628_hdmirx_controller_reset(struct rk628 *rk628) udelay(10); rk628_control_deassert(rk628, RGU_HDMIRX); rk628_control_deassert(rk628, RGU_HDMIRX_PON); - udelay(10); + usleep_range(20 * 1000, 20 * 1100); + mutex_unlock(&rk628->rst_lock); rk628_i2c_write(rk628, HDMI_RX_DMI_SW_RST, 0x000101ff); rk628_i2c_write(rk628, HDMI_RX_DMI_DISABLE_IF, 0x00000000); rk628_i2c_write(rk628, HDMI_RX_DMI_DISABLE_IF, 0x0000017f); rk628_i2c_write(rk628, HDMI_RX_DMI_DISABLE_IF, 0x0001017f); - mutex_unlock(&rk628->rst_lock); } EXPORT_SYMBOL(rk628_hdmirx_controller_reset);