diff options
Diffstat (limited to 'drivers/video/mxc_hdmi.c')
-rw-r--r-- | drivers/video/mxc_hdmi.c | 136 |
1 files changed, 49 insertions, 87 deletions
diff --git a/drivers/video/mxc_hdmi.c b/drivers/video/mxc_hdmi.c index ca3f7fa4201..c3c0164b224 100644 --- a/drivers/video/mxc_hdmi.c +++ b/drivers/video/mxc_hdmi.c @@ -68,13 +68,6 @@ #define NUM_CEA_VIDEO_MODES 64 #define DEFAULT_VIDEO_MODE 16 /* 1080P */ -#define HDMI_IH_PHY_RX_SENSE (HDMI_IH_PHY_STAT0_RX_SENSE0 |\ - HDMI_IH_PHY_STAT0_RX_SENSE1 |\ - HDMI_IH_PHY_STAT0_RX_SENSE2 |\ - HDMI_IH_PHY_STAT0_RX_SENSE3) -#define HDMI_PHY_RX_SENSE (HDMI_PHY_RX_SENSE0 | HDMI_PHY_RX_SENSE1 |\ - HDMI_PHY_RX_SENSE2 | HDMI_PHY_RX_SENSE3) - #define RGB 0 #define YCBCR444 1 #define YCBCR422_16BITS 2 @@ -140,6 +133,7 @@ struct mxc_hdmi { bool cable_plugin; u8 latest_intr_stat; bool irq_enabled; + spinlock_t irq_lock; }; struct i2c_client *hdmi_i2c; @@ -1262,11 +1256,11 @@ static void mxc_hdmi_poweroff(struct mxc_hdmi *hdmi) plat->disable_pins(); } -static void mxc_hdmi_rx_powerup(struct mxc_hdmi *hdmi) +static void mxc_hdmi_enable(struct mxc_hdmi *hdmi) { u8 val; - dev_dbg(&hdmi->pdev->dev, "rx power up\n"); + dev_dbg(&hdmi->pdev->dev, "hdmi enable\n"); clk_enable(hdmi->hdmi_iahb_clk); @@ -1290,11 +1284,11 @@ static void mxc_hdmi_rx_powerup(struct mxc_hdmi *hdmi) } } -static void mxc_hdmi_rx_powerdown(struct mxc_hdmi *hdmi) +static void mxc_hdmi_disable(struct mxc_hdmi *hdmi) { u8 val; - dev_dbg(&hdmi->pdev->dev, "rx power down\n"); + dev_dbg(&hdmi->pdev->dev, "hdmi disable\n"); /* Disable HDMI PHY - Set PDDQ=1 and TXPWRON=0 */ val = hdmi_readb(HDMI_PHY_CONF0); @@ -1370,16 +1364,16 @@ static void det_worker(struct work_struct *work) container_of(delay_work, struct mxc_hdmi, det_work); u32 phy_int_stat, phy_int_pol, phy_int_mask; u8 val; - bool rx_powerdown = false; + bool hdmi_disable = false; int irq = platform_get_irq(hdmi->pdev, 0); + unsigned long flags; if (!hdmi->irq_enabled) { clk_enable(hdmi->hdmi_iahb_clk); /* Capture status - used in det_worker ISR */ phy_int_stat = hdmi_readb(HDMI_IH_PHY_STAT0); - if ((phy_int_stat & - (HDMI_IH_PHY_RX_SENSE | HDMI_IH_PHY_STAT0_HPD)) == 0) { + if ((phy_int_stat & HDMI_IH_PHY_STAT0_HPD) == 0) { clk_disable(hdmi->hdmi_iahb_clk); return; /* No interrupts to handle */ } @@ -1388,17 +1382,11 @@ static void det_worker(struct work_struct *work) /* Unmask interrupts until handled */ val = hdmi_readb(HDMI_PHY_MASK0); - val |= HDMI_PHY_RX_SENSE | HDMI_PHY_HPD; + val |= HDMI_PHY_HPD; hdmi_writeb(val, HDMI_PHY_MASK0); - /* Clear Hotplug/RX Sense interrupts */ - hdmi_writeb(HDMI_IH_PHY_STAT0_HPD | - HDMI_IH_PHY_STAT0_TX_PHY_LOCK | - HDMI_IH_PHY_STAT0_RX_SENSE0 | - HDMI_IH_PHY_STAT0_RX_SENSE1 | - HDMI_IH_PHY_STAT0_RX_SENSE2 | - HDMI_IH_PHY_STAT0_RX_SENSE3, - HDMI_IH_PHY_STAT0); + /* Clear Hotplug interrupts */ + hdmi_writeb(HDMI_IH_PHY_STAT0_HPD, HDMI_IH_PHY_STAT0); phy_int_pol = hdmi_readb(HDMI_PHY_POL0); @@ -1418,6 +1406,7 @@ static void det_worker(struct work_struct *work) if (phy_int_pol & HDMI_PHY_HPD) { dev_dbg(&hdmi->pdev->dev, "EVENT=plugin\n"); mxc_hdmi_cable_connected(hdmi); + mxc_hdmi_enable(hdmi); /* Make HPD intr active low to capture unplug event */ val = hdmi_readb(HDMI_PHY_POL0); @@ -1426,6 +1415,7 @@ static void det_worker(struct work_struct *work) } else if (!(phy_int_pol & HDMI_PHY_HPD)) { dev_dbg(&hdmi->pdev->dev, "EVENT=plugout\n"); mxc_hdmi_cable_disconnected(hdmi); + hdmi_disable = true; /* Make HPD intr active high to capture plugin event */ val = hdmi_readb(HDMI_PHY_POL0); @@ -1435,34 +1425,19 @@ static void det_worker(struct work_struct *work) dev_dbg(&hdmi->pdev->dev, "EVENT=none?\n"); } - /* check rx power */ - if (phy_int_stat & HDMI_IH_PHY_RX_SENSE) { - if ((phy_int_pol & HDMI_PHY_RX_SENSE)) { - mxc_hdmi_rx_powerup(hdmi); - - /* Change RX Sense pol to capture RX disable */ - val = hdmi_readb(HDMI_PHY_POL0); - val &= ~HDMI_PHY_RX_SENSE; - hdmi_writeb(val, HDMI_PHY_POL0); - } else if (!(phy_int_pol & HDMI_PHY_RX_SENSE)) { - rx_powerdown = true; - - /* Change RX Sense pol to capture RX enable */ - val = hdmi_readb(HDMI_PHY_POL0); - val |= HDMI_PHY_RX_SENSE; - hdmi_writeb(val, HDMI_PHY_POL0); - } else - dev_err(&hdmi->pdev->dev, - "Received RX sense event but no change\n"); - } + /* Lock here to ensure full powerdown sequence + * completed before next interrupt processed */ + spin_lock_irqsave(&hdmi->irq_lock, flags); - /* Re-enable RX Sense and HPD interrupts */ + /* Re-enable HPD interrupts */ phy_int_mask = hdmi_readb(HDMI_PHY_MASK0); - phy_int_mask &= ~(HDMI_PHY_RX_SENSE | HDMI_PHY_HPD); + phy_int_mask &= ~HDMI_PHY_HPD; hdmi_writeb(phy_int_mask, HDMI_PHY_MASK0); - if (rx_powerdown) - mxc_hdmi_rx_powerdown(hdmi); + if (hdmi_disable) + mxc_hdmi_disable(hdmi); + + spin_unlock_irqrestore(&hdmi->irq_lock, flags); } static irqreturn_t mxc_hdmi_hotplug(int irq, void *data) @@ -1470,6 +1445,9 @@ static irqreturn_t mxc_hdmi_hotplug(int irq, void *data) struct mxc_hdmi *hdmi = data; unsigned int ret; u8 val, intr_stat; + unsigned long flags; + + spin_lock_irqsave(&hdmi->irq_lock, flags); /* * We have to disable the irq, rather than just masking @@ -1483,8 +1461,7 @@ static irqreturn_t mxc_hdmi_hotplug(int irq, void *data) if (ret == IRQ_DISABLE_FAIL) { /* Capture status - used in det_worker ISR */ intr_stat = hdmi_readb(HDMI_IH_PHY_STAT0); - if ((intr_stat & - (HDMI_IH_PHY_RX_SENSE | HDMI_IH_PHY_STAT0_HPD)) == 0) + if ((intr_stat & HDMI_IH_PHY_STAT0_HPD) == 0) return IRQ_HANDLED; dev_dbg(&hdmi->pdev->dev, "Hotplug interrupt received\n"); @@ -1492,17 +1469,11 @@ static irqreturn_t mxc_hdmi_hotplug(int irq, void *data) /* Unmask interrupts until handled */ val = hdmi_readb(HDMI_PHY_MASK0); - val |= HDMI_PHY_RX_SENSE | HDMI_PHY_HPD; + val |= HDMI_PHY_HPD; hdmi_writeb(val, HDMI_PHY_MASK0); - /* Clear Hotplug/RX Sense interrupts */ - hdmi_writeb(HDMI_IH_PHY_STAT0_HPD | - HDMI_IH_PHY_STAT0_TX_PHY_LOCK | - HDMI_IH_PHY_STAT0_RX_SENSE0 | - HDMI_IH_PHY_STAT0_RX_SENSE1 | - HDMI_IH_PHY_STAT0_RX_SENSE2 | - HDMI_IH_PHY_STAT0_RX_SENSE3, - HDMI_IH_PHY_STAT0); + /* Clear Hotplug interrupts */ + hdmi_writeb(HDMI_IH_PHY_STAT0_HPD, HDMI_IH_PHY_STAT0); hdmi->irq_enabled = true; } else @@ -1510,6 +1481,8 @@ static irqreturn_t mxc_hdmi_hotplug(int irq, void *data) schedule_delayed_work(&(hdmi->det_work), msecs_to_jiffies(20)); + spin_unlock_irqrestore(&hdmi->irq_lock, flags); + return IRQ_HANDLED; } @@ -1736,44 +1709,22 @@ static int mxc_hdmi_disp_init(struct mxc_dispdrv_entry *disp) } } - ret = request_irq(irq, mxc_hdmi_hotplug, IRQF_SHARED, - dev_name(&hdmi->pdev->dev), hdmi); - if (ret < 0) { - dev_err(&hdmi->pdev->dev, - "Unable to request irq: %d\n", ret); - goto ereqirq; - } - - /* Initialize IRQ at HDMI core level */ - hdmi_irq_init(); + spin_lock_init(&hdmi->irq_lock); INIT_DELAYED_WORK(&(hdmi->det_work), det_worker); /* Configure registers related to HDMI interrupt * generation before registering IRQ. */ - hdmi_writeb(HDMI_PHY_RX_SENSE | HDMI_PHY_HPD, - HDMI_PHY_POL0); + hdmi_writeb(HDMI_PHY_HPD, HDMI_PHY_POL0); /* enable cable hot plug irq */ - val = HDMI_PHY_RX_SENSE | HDMI_PHY_HPD; - val = ~val; + val = ~HDMI_PHY_HPD; hdmi_writeb(val, HDMI_PHY_MASK0); - /* Clear Hotplug/RX Sense interrupts */ - hdmi_writeb(HDMI_IH_PHY_STAT0_HPD | - HDMI_IH_PHY_STAT0_TX_PHY_LOCK | - HDMI_IH_PHY_STAT0_RX_SENSE0 | - HDMI_IH_PHY_STAT0_RX_SENSE1 | - HDMI_IH_PHY_STAT0_RX_SENSE2 | - HDMI_IH_PHY_STAT0_RX_SENSE3, - HDMI_IH_PHY_STAT0); - - hdmi_writeb(~(HDMI_IH_PHY_STAT0_HPD | - HDMI_IH_PHY_STAT0_RX_SENSE0 | - HDMI_IH_PHY_STAT0_RX_SENSE1 | - HDMI_IH_PHY_STAT0_RX_SENSE2 | - HDMI_IH_PHY_STAT0_RX_SENSE3), - HDMI_IH_MUTE_PHY_STAT0); + /* Clear Hotplug interrupts */ + hdmi_writeb(HDMI_IH_PHY_STAT0_HPD, HDMI_IH_PHY_STAT0); + + hdmi_writeb(~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0); hdmi->nb.notifier_call = mxc_hdmi_fb_event; ret = fb_register_client(&hdmi->nb); @@ -1788,6 +1739,17 @@ static int mxc_hdmi_disp_init(struct mxc_dispdrv_entry *disp) * ISFR clock must remain enabled for hotplug to work. */ clk_disable(hdmi->hdmi_iahb_clk); + /* Initialize IRQ at HDMI core level */ + hdmi_irq_init(); + + ret = request_irq(irq, mxc_hdmi_hotplug, IRQF_SHARED, + dev_name(&hdmi->pdev->dev), hdmi); + if (ret < 0) { + dev_err(&hdmi->pdev->dev, + "Unable to request irq: %d\n", ret); + goto ereqirq; + } + return ret; efbclient: |