20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34}
};
-u8 hdmi_infoframe_poll(state_struct *state)
+int hdmi_infoframe_poll(state_struct *state)
{
GENERAL_Read_Register_response regresp;
- u32 regread;
struct mxc_hdmi_rx_dev *hdmi_rx = state_to_mxc_hdmirx(state);
+ u32 regread;
+ u32 i;
/* Unmask "AVI InfoFrame received" interrupt */
CDN_API_General_Write_Register_blocking(state,
ADDR_SINK_MHL_HD + (TMDS_MHL_HD_INT_MASK << 2),
F_TMDS_MHL_HD_MASK(0xFD));
- dev_dbg(&hdmi_rx->pdev->dev, "AVI InfoFrame packet received - interrupt unmasked.\n");
/* Unmask "tmds_mhl_hd_int" interrupt */
CDN_API_General_Write_Register_blocking(state,
ADDR_SINK_MHL_HD + (MHL_HD_INT_MASK << 2),
F_MHL_HD_INT_MASK(0xE));
- dev_dbg(&hdmi_rx->pdev->dev, "tmds_mhl_hd_int interrupt unmasked.\n");
/* MHL_HD_INT_STAT */
- dev_dbg(&hdmi_rx->pdev->dev, "Waiting for tmds_mhl_hd_int...\n");
- do {
- CDN_API_General_Read_Register_blocking(state,
- ADDR_SINK_MHL_HD + (MHL_HD_INT_STAT << 2),
- ®resp);
- } while (!(regresp.val & (1 << 0)));
- dev_dbg(&hdmi_rx->pdev->dev, "Waiting for tmds_mhl_hd_int...DONE\n");
+ CDN_API_General_Read_Register_blocking(state,
+ ADDR_SINK_MHL_HD + (MHL_HD_INT_STAT << 2), ®resp);
+ for (i = 0; i < 5; i++) {
+ if (regresp.val & (1 << 0))
+ break;
+ else
+ CDN_API_General_Read_Register_blocking(state,
+ ADDR_SINK_MHL_HD + (MHL_HD_INT_STAT << 2), ®resp);
+ msleep(20);
+ }
+ if (i == 5) {
+ dev_err(&hdmi_rx->pdev->dev, "Waiting for tmds_mhl_hd_int...failed!\n");
+ return -1;
+ } else
+ dev_dbg(&hdmi_rx->pdev->dev, "Waiting for tmds_mhl_hd_int...DONE\n");
/* Mask "AVI InfoFrame received" interrupt */
CDN_API_General_Write_Register_blocking(state,
ADDR_SINK_MHL_HD + (TMDS_MHL_HD_INT_MASK << 2),
F_TMDS_MHL_HD_MASK(0xFF));
- dev_dbg(&hdmi_rx->pdev->dev, "AVI InfoFrame packet received - interrupt masked.\n");
/* Mask "tmds_mhl_hd_int" interrupt */
CDN_API_General_Write_Register_blocking(state,
ADDR_SINK_MHL_HD + (MHL_HD_INT_MASK << 2),
F_MHL_HD_INT_MASK(0xF));
- dev_dbg(&hdmi_rx->pdev->dev, "tmds_mhl_hd_int interrupt masked.\n");
/* Read back TMDS_MHL_HD_INT_STAT to clear the interrupt */
CDN_API_General_Read_Register_blocking(state,
ADDR_SINK_MHL_HD + (TMDS_MHL_HD_INT_STAT << 2),
®resp);
- dev_dbg(&hdmi_rx->pdev->dev, "AVI InfoFrame packet received - interrupt cleared.\n");
/* Packet 0 read request */
cdn_apb_write(state, ADDR_SINK_PIF + (PKT_INFO_CTRL << 2),
F_PACKET_RDN_WR(0x0) | F_PACKET_NUM(0x0));
- dev_dbg(&hdmi_rx->pdev->dev, "PIF Packet 0 read request.\n");
/* Wait for pkt_host_rdy_status */
- dev_dbg(&hdmi_rx->pdev->dev, "Waiting for packet data available for reading...\n");
- do {
- cdn_apb_read(state, ADDR_SINK_PIF + (PKT_INT_STATUS << 2), ®read);
- } while (!(regread & (1 << 16)));
- dev_dbg(&hdmi_rx->pdev->dev, "Waiting for packet data available for reading...DONE\n");
+ cdn_apb_read(state, ADDR_SINK_PIF + (PKT_INT_STATUS << 2), ®read);
+ for (i = 0; i < 5; i++) {
+ if (regread & (1 << 16))
+ break;
+ else
+ cdn_apb_read(state, ADDR_SINK_PIF + (PKT_INT_STATUS << 2), ®read);
+ msleep(20);
+ }
+ if (i == 5) {
+ dev_err(&hdmi_rx->pdev->dev, "Waiting for packet data available for reading...FAILED!\n");
+ return -1;
+ } else
+ dev_dbg(&hdmi_rx->pdev->dev, "Waiting for packet data available for reading...DONE\n");
return 0;
}
/* Exemplary code to configure the controller */
/* for the AVI_InfoFrame reception */
-static void get_avi_infoframe(state_struct *state)
+static int get_avi_infoframe(state_struct *state)
{
struct mxc_hdmi_rx_dev *hdmi_rx = state_to_mxc_hdmirx(state);
GENERAL_Read_Register_response regresp;
+ int ret;
dev_dbg(&hdmi_rx->pdev->dev, "%s\n", __func__);
/* Get VIC code and pixel encoding */
- hdmi_infoframe_poll(state);
+ ret = hdmi_infoframe_poll(state);
+ if (ret < 0)
+ return -1;
CDN_API_General_Read_Register_blocking(state, ADDR_SINK_MHL_HD + (PKT_AVI_DATA_LOW << 2), ®resp);
hdmi_rx->vic_code = (regresp.val & 0xFF000000) >> 24;
hdmi_rx->pixel_encoding = (regresp.val & 0x00000060) >> 5;
+ return 0;
}
-static void get_vendor_infoframe(state_struct *state)
+static int get_vendor_infoframe(state_struct *state)
{
struct mxc_hdmi_rx_dev *hdmi_rx = state_to_mxc_hdmirx(state);
u32 regread;
+ int ret;
dev_dbg(&hdmi_rx->pdev->dev, "%s\n", __func__);
/* Set info_type1 to vendor Info Frame */
cdn_apb_write(state, ADDR_SINK_PIF + (PKT_INFO_TYPE_CFG1 << 2),
F_INFO_TYPE1(0x81));
- hdmi_infoframe_poll(state);
+ ret = hdmi_infoframe_poll(state);
+ if (ret < 0)
+ return -1;
/* Get IEEE OUI */
cdn_apb_read(state, ADDR_SINK_PIF + (PKT_INFO_DATA1 << 2), ®read);
/* Clear info_type1 */
cdn_apb_write(state, ADDR_SINK_PIF + (PKT_INFO_TYPE_CFG1 << 2),
F_INFO_TYPE1(0x00));
+
+ return 0;
}
static void get_color_depth(struct mxc_hdmi_rx_dev *hdmi_rx,
}
}
-int hdmi_rx_init(state_struct *state)
+/* Set edid data sample */
+void hdmirx_edid_set(state_struct *state)
{
+ struct mxc_hdmi_rx_dev *hdmi_rx = state_to_mxc_hdmirx(state);
+
+ /* Set EDID - block 0 */
+ CDN_API_HDMIRX_SET_EDID_blocking(state, 0, 0, &block0[0]);
+ /* Set EDID - block 1 */
+ CDN_API_HDMIRX_SET_EDID_blocking(state, 0, 1, &block1[0]);
+ dev_dbg(&hdmi_rx->pdev->dev, "EDID block 0/1 set complete.\n");
+}
+
+/* Set SCDC data sample */
+void hdmirx_scdc_set(state_struct *state)
+{
+ struct mxc_hdmi_rx_dev *hdmi_rx = state_to_mxc_hdmirx(state);
+
+ CDN_API_HDMIRX_SET_SCDC_SLAVE_blocking(state, &scdcExampleData);
+ dev_dbg(&hdmi_rx->pdev->dev, "SCDC set complete.\n");
+}
+
+int hdmirx_init(state_struct *state)
+{
+ u8 sts;
u32 ret = 0;
+
/* Set uCPU Clock frequency for FW's use [MHz]; */
CDN_API_SetClock(state, 200);
/* Check if the firmware is running */
ret = CDN_API_CheckAlive_blocking(state);
+ if (ret < 0)
+ return ret;
+
+ /* Set driver and firmware active */
+ CDN_API_MainControl_blocking(state, 1, &sts);
+ /* set sample edid and scdc */
+ hdmirx_edid_set(state);
+ hdmirx_scdc_set(state);
+
return ret;
}
+int hdmirx_check5v(state_struct *state)
+{
+ struct mxc_hdmi_rx_dev *hdmi_rx = state_to_mxc_hdmirx(state);
+ u8 event5V = 0;
+ u32 i;
+
+ /* check for 5v to get hdmi cable state */
+ CDN_API_HDMIRX_ReadEvent(state, &event5V);
+ for (i = 0; i < 5; i++) {
+ if (event5V & (1 << HDMI_RX_EVENT_5V_VAL)) {
+ dev_dbg(&hdmi_rx->pdev->dev, "HDMI 5V present\n");
+ break;
+ }
+ msleep(20);
+ CDN_API_HDMIRX_ReadEvent(state, &event5V);
+ }
+ if (i == 5) {
+ dev_dbg(&hdmi_rx->pdev->dev, "No HDMI 5V present!!!\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+void hdmirx_hotplug_trigger(state_struct *state)
+{
+ /* Clear HPD */
+ CDN_API_HDMIRX_SetHpd_blocking(state, 0);
+ /* provide minimum low pulse length (100ms) */
+ msleep(110);
+ CDN_API_HDMIRX_SetHpd_blocking(state, 1);
+}
+
/* Bring-up sequence for the HDMI-RX */
int hdmirx_startup(state_struct *state)
{
u8 sts;
u32 rx_clk_freq;
- u8 event5V = 0;
u8 data_rate_change = 0;
u8 scrambling_en;
clk_ratio_t clk_ratio, clk_ratio_detected;
tmds_bit_clock_ratio_t tmds_bit_clock_ratio;
struct mxc_hdmi_rx_dev *hdmi_rx = state_to_mxc_hdmirx(state);
S_HDMI_SCDC_GET_MSG *scdcData = &hdmi_rx->scdcData;
- u8 ret = 0;
- u32 i;
+ int ret = 0;
/* Start from TMDS/pixel clock ratio of 1:1.
* It affects only pixel clock frequency as the character/data clocks are generated based on
* of the pixel clock ratio being programmed. */
clk_ratio = CLK_RATIO_1_1;
- /* Set driver and firmware active */
- CDN_API_MainControl_blocking(state, 1, &sts);
-
- /* Set EDID - block 0 */
- CDN_API_HDMIRX_SET_EDID_blocking(state, 0, 0, &block0[0]);
-
- /* Set EDID - block 1 */
- CDN_API_HDMIRX_SET_EDID_blocking(state, 0, 1, &block1[0]);
- dev_dbg(&hdmi_rx->pdev->dev, "EDID block 0/1 set complete.\n");
-
- /* Set SCDC data sample */
- CDN_API_HDMIRX_SET_SCDC_SLAVE_blocking(state, &scdcExampleData);
- dev_dbg(&hdmi_rx->pdev->dev, "SCDC set complete.\n");
-
/* Get TMDS_Bit_Clock_Ratio and Scrambling setting */
CDN_API_HDMIRX_GET_SCDC_SLAVE_blocking(state, scdcData);
tmds_bit_clock_ratio =
((scdcData->TMDS_Config & (1 << 1)) >> 1) ?
- TMDS_BIT_CLOCK_RATIO_1_40 : TMDS_BIT_CLOCK_RATIO_1_10;
+ TMDS_BIT_CLOCK_RATIO_1_40 : TMDS_BIT_CLOCK_RATIO_1_10;
scrambling_en = scdcData->TMDS_Config & (1 << 0);
+
dev_dbg(&hdmi_rx->pdev->dev,
"TMDS ratio: 1/%0d, Scrambling %0d).\n", tmds_bit_clock_ratio, scrambling_en);
- /* Clear HPD */
- CDN_API_HDMIRX_SetHpd_blocking(state, 0);
- dev_dbg(&hdmi_rx->pdev->dev, "Clear HDP\n");
-
- /* check for 5v to get hdmi cable state */
- CDN_API_HDMIRX_ReadEvent(state, &event5V);
- dev_dbg(&hdmi_rx->pdev->dev, "event5V = 0x%02X\n", event5V);
- for (i = 0; i < 5; i++) {
- if (event5V & (1 << HDMI_RX_EVENT_5V_VAL)) {
- dev_info(&hdmi_rx->pdev->dev, "HDMI 5V present\n");
- break;
- }
- msleep(20);
- CDN_API_HDMIRX_ReadEvent(state, &event5V);
- dev_dbg(&hdmi_rx->pdev->dev, "event5V = 0x%02X\n", event5V);
- }
- if (i == 5) {
- dev_info(&hdmi_rx->pdev->dev, "No HDMI 5V present!!!\n");
- return -1;
- }
-
- /* Got 5v, set hpd */
- msleep(100); /* provide minimum low pulse length (100ms) */
- CDN_API_HDMIRX_SetHpd_blocking(state, 1);
- dev_dbg(&hdmi_rx->pdev->dev, "Set HDP\n");
-
/* Configure the PHY */
pma_config(state);
* 5. If mismatch found - reprogram the PHY
* 6. Enable the video data path in the controller */
- get_avi_infoframe(state);
- get_vendor_infoframe(state);
+ ret = get_avi_infoframe(state);
+ if (ret < 0) {
+ pr_err("Get AVI info frame failed\n");
+ return -1;
+ }
+ ret = get_vendor_infoframe(state);
+ if (ret < 0)
+ pr_info("No Vendor info frame\n");
dev_dbg(&hdmi_rx->pdev->dev,
"get_avi_infoframe() vic_code: %0d, pixel_encoding: %0d.\n",
hdmi_rx->vic_code, hdmi_rx->pixel_encoding);
- mxc_hdmi_frame_timing(hdmi_rx);
+ ret = mxc_hdmi_frame_timing(hdmi_rx);
+ if (ret < 0) {
+ pr_err("Get frame timing failed\n\n");
+ return -1;
+ }
clk_ratio_detected = clk_ratio_detect(state, rx_clk_freq,
hdmi_rx->timings->timings.bt.
F_SINK_CEC_SYS_CLK_RSTN_EN(1));
return 0;
}
+
+/* Stop for the HDMI-RX */
+void hdmirx_stop(state_struct *state)
+{
+ CDN_API_HDMIRX_Stop_blocking(state);
+}
+
+void hdmirx_phy_pix_engine_reset(state_struct *state)
+{
+ GENERAL_Read_Register_response regresp;
+
+ CDN_API_General_Read_Register_blocking(state, ADDR_SINK_CAR +
+ (SINK_MHL_HD_CAR << 2),
+ ®resp);
+ CDN_API_General_Write_Register_blocking(state, ADDR_SINK_CAR +
+ (SINK_MHL_HD_CAR << 2),
+ regresp.val & 0x3F);
+ CDN_API_General_Write_Register_blocking(state, ADDR_SINK_CAR +
+ (SINK_MHL_HD_CAR << 2),
+ regresp.val);
+}
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
-
+#include <linux/irq.h>
#include "mxc-hdmi-rx.h"
#include "API_AFE_ss28fdsoi_hdmirx.h"
clk_disable_unprepare(hdmi_rx->pxl_link_clk);
}
-static void imx8qm_pixel_link_encoder(struct mxc_hdmi_rx_dev *hdmi_rx)
+static void mxc_hdmi_pixel_link_encoder(struct mxc_hdmi_rx_dev *hdmi_rx)
{
u32 val;
/* -----------------------------------------------------------------------------
* v4l2_subdev_video_ops
*/
+static int mxc_hdmi_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
+{
+ struct mxc_hdmi_rx_dev *hdmi_rx = imx_sd_to_hdmi(sd);
+ struct device *dev = &hdmi_rx->pdev->dev;
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ return 0;
+}
static int mxc_hdmi_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
{
u32 val;
dev_dbg(&hdmi_rx->pdev->dev, "%s\n", __func__);
- imx8qm_pixel_link_encoder(hdmi_rx);
+ mxc_hdmi_pixel_link_encoder(hdmi_rx);
if (enable) {
val = readl(hdmi_rx->mem.ss_base);
static const struct v4l2_subdev_video_ops imx_video_ops_hdmi = {
.s_stream = mxc_hdmi_s_stream,
.g_parm = mxc_hdmi_g_parm,
+ .s_parm = mxc_hdmi_s_parm,
};
/* -----------------------------------------------------------------------------
static int imx8qm_hdp_read(struct hdp_mem *mem, u32 addr, u32 *value)
{
u32 temp;
- void *tmp_addr = (addr & 0xfff) + mem->regs_base;
- void *off_addr = 0x4 + mem->ss_base;;
+ void *tmp_addr;
+ void *off_addr;
+ mutex_lock(&mem->mutex);
+ tmp_addr = (addr & 0xfff) + mem->regs_base;
+ off_addr = 0x4 + mem->ss_base;
__raw_writel(addr >> 12, off_addr);
temp = __raw_readl((volatile u32 *)tmp_addr);
*value = temp;
+ mutex_unlock(&mem->mutex);
return 0;
}
static int imx8qm_hdp_write(struct hdp_mem *mem, u32 addr, u32 value)
{
- void *tmp_addr = (addr & 0xfff) + mem->regs_base;
- void *off_addr = 0x4 + mem->ss_base;;
+ void *tmp_addr;
+ void *off_addr;
+ mutex_lock(&mem->mutex);
+ tmp_addr = (addr & 0xfff) + mem->regs_base;
+ off_addr = 0x4 + mem->ss_base;;
__raw_writel(addr >> 12, off_addr);
__raw_writel(value, (volatile u32 *) tmp_addr);
+ mutex_unlock(&mem->mutex);
return 0;
}
static int imx8qm_hdp_sread(struct hdp_mem *mem, u32 addr, u32 *value)
{
u32 temp;
- void *tmp_addr = (addr & 0xfff) + mem->regs_base;
- void *off_addr = 0xc + mem->ss_base;;
+ void *tmp_addr;
+ void *off_addr;
+ mutex_lock(&mem->mutex);
+ tmp_addr = (addr & 0xfff) + mem->regs_base;
+ off_addr = 0xc + mem->ss_base;
__raw_writel(addr >> 12, off_addr);
temp = __raw_readl((volatile u32 *)tmp_addr);
*value = temp;
+ mutex_unlock(&mem->mutex);
return 0;
}
static int imx8qm_hdp_swrite(struct hdp_mem *mem, u32 addr, u32 value)
{
- void *tmp_addr = (addr & 0xfff) + mem->regs_base;
- void *off_addr = 0xc + mem->ss_base;
+ void *tmp_addr;
+ void *off_addr;
+ mutex_lock(&mem->mutex);
+ tmp_addr = (addr & 0xfff) + mem->regs_base;
+ off_addr = 0xc + mem->ss_base;
__raw_writel(addr >> 12, off_addr);
__raw_writel(value, (volatile u32 *)tmp_addr);
+ mutex_unlock(&mem->mutex);
return 0;
}
int mxc_hdmi_init(struct mxc_hdmi_rx_dev *hdmi_rx)
{
sc_err_t sciErr;
- u32 ret = 0;
dev_dbg(&hdmi_rx->pdev->dev, "%s\n", __func__);
mxc_hdmi_state_init(hdmi_rx);
return -EINVAL;
}
- ret = hdmi_rx_init(&hdmi_rx->state);
- return ret;
+ return 0;
+}
+
+static void hpd5v_work_func(struct work_struct *work)
+{
+ struct mxc_hdmi_rx_dev *hdmi_rx = container_of(work, struct mxc_hdmi_rx_dev,
+ hpd5v_work.work);
+ char event_string[32];
+ char *envp[] = { event_string, NULL };
+ int hpd5v;
+
+ /* Check cable states before enable irq */
+ hpd5v = hdmirx_check5v(&hdmi_rx->state);
+ if (hpd5v == 0) {
+ pr_info("HDMI RX Cable Plug In\n");
+ hdmirx_hotplug_trigger(&hdmi_rx->state);
+ hdmirx_startup(&hdmi_rx->state);
+ enable_irq(hdmi_rx->irq[HPD5V_IRQ_OUT]);
+ sprintf(event_string, "EVENT=hdmirxin");
+ kobject_uevent_env(&hdmi_rx->pdev->dev.kobj, KOBJ_CHANGE, envp);
+#ifdef CONFIG_IMX_HDP_CEC
+ if (hdmi_rx->is_cec) {
+ mxc_hdmi_cec_init(hdmi_rx);
+ imx_cec_register(&hdmi_rx->cec);
+ }
+#endif
+ } else {
+ pr_info("HDMI RX Cable Plug Out\n");
+ hdmirx_stop(&hdmi_rx->state);
+#ifdef CONFIG_IMX_HDP_CEC
+ if (hdmi_rx->is_cec) {
+ imx_cec_unregister(&hdmi_rx->cec);
+ }
+#endif
+ hdmirx_phy_pix_engine_reset(&hdmi_rx->state);
+ sprintf(event_string, "EVENT=hdmirxout");
+ kobject_uevent_env(&hdmi_rx->pdev->dev.kobj, KOBJ_CHANGE, envp);
+ enable_irq(hdmi_rx->irq[HPD5V_IRQ_IN]);
+ }
+}
+
+#define HOTPLUG_DEBOUNCE_MS 200
+static irqreturn_t mxc_hdp5v_irq_thread(int irq, void *data)
+{
+ struct mxc_hdmi_rx_dev *hdmi_rx = data;
+
+ disable_irq_nosync(irq);
+
+ mod_delayed_work(system_wq, &hdmi_rx->hpd5v_work,
+ msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
+
+ return IRQ_HANDLED;
}
static int mxc_hdmi_probe(struct platform_device *pdev)
struct mxc_hdmi_rx_dev *hdmi_rx;
struct resource *res;
int ret = 0;
+ int hpd5v;
dev_dbg(dev, "%s\n", __func__);
hdmi_rx = devm_kzalloc(dev, sizeof(*hdmi_rx), GFP_KERNEL);
hdmi_rx->pdev = pdev;
- spin_lock_init(&hdmi_rx->slock);
-
+ mutex_init(&hdmi_rx->mem.mutex);
/* register map */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
hdmi_rx->mem.regs_base = devm_ioremap_resource(dev, res);
return -EINVAL;
}
-#if 0
- /* TODO B0 */
- res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (res == NULL) {
- dev_warn(dev, "Failed to get IRQ resource\n");
- return -EINVAL;
- }
+ hdmi_rx->irq[HPD5V_IRQ_IN] = platform_get_irq_byname(pdev, "plug_in");
+ if (hdmi_rx->irq[HPD5V_IRQ_IN] < 0)
+ dev_info(&pdev->dev, "No plug_in irq number\n");
+
+ hdmi_rx->irq[HPD5V_IRQ_OUT] = platform_get_irq_byname(pdev, "plug_out");
+ if (hdmi_rx->irq[HPD5V_IRQ_OUT] < 0)
+ dev_info(&pdev->dev, "No plug_out irq number\n");
+
+ INIT_DELAYED_WORK(&hdmi_rx->hpd5v_work, hpd5v_work_func);
- ret = devm_request_irq(dev, res->start, mxc_hdmi_irq_handler,
- 0, dev_name(dev), mxc_hdmi);
- if (ret < 0) {
- dev_err(dev, "failed to install irq (%d)\n", ret);
- return -EINVAL;
- }
-#endif
v4l2_subdev_init(&hdmi_rx->sd, &imx_ops_hdmi);
/* sd.dev may use by match_of */
pm_runtime_enable(dev);
pm_runtime_get_sync(dev);
ret = mxc_hdmi_init(hdmi_rx);
- if (ret) {
- dev_info(dev, "mxc hdmi rx init failed\n");
+ if (ret < 0) {
+ dev_err(dev, "mxc hdmi init failed\n");
goto failed;
}
- ret = hdmirx_startup(&hdmi_rx->state);
- if (ret) {
- dev_info(dev, "mxc hdmi rx startup failed\n");
+ ret = hdmirx_init(&hdmi_rx->state);
+ if (ret < 0) {
+ dev_err(dev, "mxc hdmi rx init failed\n");
goto failed;
}
-#ifdef CONFIG_IMX_HDP_CEC
- if (hdmi_rx->is_cec) {
- mxc_hdmi_cec_init(hdmi_rx);
- imx_cec_register(&hdmi_rx->cec);
+
+ /* Check cable states before enable irq */
+ hpd5v = hdmirx_check5v(&hdmi_rx->state);
+
+ /* Enable Hotplug Detect IRQ thread */
+ if (hdmi_rx->irq[HPD5V_IRQ_IN] > 0) {
+ irq_set_status_flags(hdmi_rx->irq[HPD5V_IRQ_IN], IRQ_NOAUTOEN);
+ ret = devm_request_threaded_irq(dev, hdmi_rx->irq[HPD5V_IRQ_IN],
+ NULL, mxc_hdp5v_irq_thread,
+ IRQF_ONESHOT, dev_name(dev), hdmi_rx);
+ if (ret) {
+ dev_err(&pdev->dev, "can't claim irq %d\n",
+ hdmi_rx->irq[HPD5V_IRQ_IN]);
+ goto failed;
+ }
+ /* Cable Disconnedted, enable Plug in IRQ */
+ if (hpd5v < 0)
+ enable_irq(hdmi_rx->irq[HPD5V_IRQ_IN]);
}
-#endif
+ if (hdmi_rx->irq[HPD5V_IRQ_OUT] > 0) {
+ irq_set_status_flags(hdmi_rx->irq[HPD5V_IRQ_OUT], IRQ_NOAUTOEN);
+ ret = devm_request_threaded_irq(dev, hdmi_rx->irq[HPD5V_IRQ_OUT],
+ NULL, mxc_hdp5v_irq_thread,
+ IRQF_ONESHOT, dev_name(dev), hdmi_rx);
+ if (ret) {
+ dev_err(&pdev->dev, "can't claim irq %d\n",
+ hdmi_rx->irq[HPD5V_IRQ_OUT]);
+ goto failed;
+ }
+ if (hpd5v == 0) {
+ hdmirx_hotplug_trigger(&hdmi_rx->state);
+ hdmirx_startup(&hdmi_rx->state);
+ /* Cable Connected, enable Plug out IRQ */
+ enable_irq(hdmi_rx->irq[HPD5V_IRQ_OUT]);
+ }
+ }
+
mxc_hdmi_rx_register_audio_driver(dev);
- dev_info(dev, "mxc hdmi rx probe successfully\n");
+ dev_info(dev, "iMX8 HDMI RX probe successfully\n");
return ret;
failed: