diff options
| author | Manoj Rao <manojraj@codeaurora.org> | 2013-05-21 21:05:57 -0700 |
|---|---|---|
| committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-23 20:17:28 -0700 |
| commit | 5a7132a5b85bcbcbe2152dda3b93123da0a53feb (patch) | |
| tree | abb1d2cfdbd32a2f1eed28adaea055540f750f60 | |
| parent | 84674f0108858ec868e4633b3643852bb3227837 (diff) | |
msm8974: mhl_sii8334: disable intrs in low-pwr
Set appropriate interrupt mask to disable interrupts
in low power to prevent possible interrupt triggers
in low power mode. Enable interrupts appropriately when
chipset is brought out of low power state.
Change-Id: I267c41fd953e8afde3f157ee58228f26ee1ac20d
Signed-off-by: Manoj Rao <manojraj@codeaurora.org>
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_hdmi_tx.c | 7 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_hdmi_tx.h | 3 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mhl_sii8334.c | 98 |
3 files changed, 87 insertions, 21 deletions
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.c b/drivers/video/fbdev/msm/mdss_hdmi_tx.c index ec1e0cb92dad..684e7e4d8f6c 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_tx.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.c @@ -391,6 +391,10 @@ static ssize_t hdmi_tx_sysfs_wta_hpd(struct device *dev, return rc; } + if (hdmi_ctrl->mhl_max_pclk && hpd && + (!hdmi_ctrl->mhl_hpd_on || hdmi_ctrl->hpd_feature_on)) + return 0; + if (0 == hpd && hdmi_ctrl->hpd_feature_on) { rc = hdmi_tx_sysfs_enable_hpd(hdmi_ctrl, false); } else if (1 == hpd && !hdmi_ctrl->hpd_feature_on) { @@ -2508,6 +2512,9 @@ static int hdmi_tx_set_mhl_hpd(struct platform_device *pdev, uint8_t on) return -EINVAL; } + /* mhl status should override */ + hdmi_ctrl->mhl_hpd_on = on; + if (!on && hdmi_ctrl->hpd_feature_on) { rc = hdmi_tx_sysfs_enable_hpd(hdmi_ctrl, false); } else if (on && !hdmi_ctrl->hpd_feature_on) { diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.h b/drivers/video/fbdev/msm/mdss_hdmi_tx.h index ce3c00c1333a..d4f8e67ff4ab 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_tx.h +++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -62,6 +62,7 @@ struct hdmi_tx_ctrl { u32 hpd_initialized; u8 timing_gen_on; u32 mhl_max_pclk; + u8 mhl_hpd_on; struct completion hpd_done; struct work_struct hpd_int_work; diff --git a/drivers/video/fbdev/msm/mhl_sii8334.c b/drivers/video/fbdev/msm/mhl_sii8334.c index a1053fb30ae0..9cae4319c815 100644 --- a/drivers/video/fbdev/msm/mhl_sii8334.c +++ b/drivers/video/fbdev/msm/mhl_sii8334.c @@ -361,7 +361,7 @@ static int mhl_sii_wait_for_rgnd(struct mhl_tx_ctrl *mhl_ctrl) pr_debug("%s:%u\n", __func__, __LINE__); INIT_COMPLETION(mhl_ctrl->rgnd_done); timeout = wait_for_completion_interruptible_timeout - (&mhl_ctrl->rgnd_done, HZ/2); + (&mhl_ctrl->rgnd_done, HZ); if (!timeout) { /* most likely nothing plugged in USB */ /* USB HOST connected or already in USB mode */ @@ -377,6 +377,12 @@ static int mhl_sii_device_discovery(void *data, int id, { int rc; struct mhl_tx_ctrl *mhl_ctrl = data; + struct i2c_client *client = mhl_ctrl->i2c_handle; + unsigned long flags; + + enable_irq(client->irq); + /* wait for i2c interrupt line to be activated */ + msleep(300); if (id) { /* When MHL cable is disconnected we get a sii8334 @@ -396,11 +402,16 @@ static int mhl_sii_device_discovery(void *data, int id, mhl_ctrl->notify_usb_online = usb_notify_cb; if (!mhl_ctrl->disc_enabled) { + spin_lock_irqsave(&mhl_ctrl->lock, flags); + mhl_ctrl->tx_powered_off = false; + spin_unlock_irqrestore(&mhl_ctrl->lock, flags); mhl_sii_reset_pin(mhl_ctrl, 0); msleep(50); mhl_sii_reset_pin(mhl_ctrl, 1); - /* TX PR-guide requires a 100 ms wait here */ - msleep(100); + /* chipset PR recommends waiting for at least 100 ms + * the chipset needs longer to come out of D3 state. + */ + msleep(300); mhl_init_reg_settings(mhl_ctrl, true); rc = mhl_sii_wait_for_rgnd(mhl_ctrl); } else { @@ -690,8 +701,8 @@ static void mhl_init_reg_settings(struct mhl_tx_ctrl *mhl_ctrl, MHL_SII_PAGE3_WR(0x3C, 0x80); - if (mhl_ctrl->cur_state != POWER_STATE_D3) - MHL_SII_REG_NAME_MOD(REG_INT_CTRL, BIT6 | BIT5 | BIT4, BIT4); + MHL_SII_REG_NAME_MOD(REG_INT_CTRL, + (BIT6 | BIT5 | BIT4), (BIT6 | BIT4)); /* Enable Auto Soft RESET */ MHL_SII_REG_NAME_WR(REG_SRST, 0x084); @@ -858,11 +869,6 @@ static void mhl_msm_connection(struct mhl_tx_ctrl *mhl_ctrl) static void mhl_msm_disconnection(struct mhl_tx_ctrl *mhl_ctrl) { struct i2c_client *client = mhl_ctrl->i2c_handle; - unsigned long flags; - - spin_lock_irqsave(&mhl_ctrl->lock, flags); - mhl_ctrl->dwnstream_hpd &= ~BIT6; - spin_unlock_irqrestore(&mhl_ctrl->lock, flags); /* disabling Tx termination */ MHL_SII_REG_NAME_WR(REG_MHLTX_CTL1, 0xD0); @@ -870,7 +876,7 @@ static void mhl_msm_disconnection(struct mhl_tx_ctrl *mhl_ctrl) mhl_msc_clear(mhl_ctrl); } -static int mhl_msm_read_rgnd_int(struct mhl_tx_ctrl *mhl_ctrl) +static int mhl_msm_read_rgnd_int(struct mhl_tx_ctrl *mhl_ctrl) { uint8_t rgnd_imp; struct i2c_client *client = mhl_ctrl->i2c_handle; @@ -967,12 +973,12 @@ static int dev_detect_isr(struct mhl_tx_ctrl *mhl_ctrl) if ((0x00 == status) &&\ (mhl_ctrl->cur_state == POWER_STATE_D3)) { - pr_err("%s: invalid intr\n", __func__); + pr_warn("%s: invalid intr\n", __func__); return 0; } if (0xFF == status) { - pr_debug("%s: invalid intr 0xff\n", __func__); + pr_warn("%s: invalid intr 0xff\n", __func__); MHL_SII_REG_NAME_WR(REG_INTR4, status); return 0; } @@ -999,13 +1005,14 @@ static int dev_detect_isr(struct mhl_tx_ctrl *mhl_ctrl) power_supply_changed(&mhl_ctrl->mhl_psy); if (mhl_ctrl->notify_usb_online) mhl_ctrl->notify_usb_online(0); - return -EACCES; + return 0; } if (status & BIT5) { /* clr intr - reg int4 */ pr_debug("%s: mhl discon: int4 st=%02X\n", __func__, (int)status); + mhl_ctrl->mhl_det_discon = true; reg = MHL_SII_REG_NAME_RD(REG_INTR4); MHL_SII_REG_NAME_WR(REG_INTR4, reg); @@ -1013,7 +1020,7 @@ static int dev_detect_isr(struct mhl_tx_ctrl *mhl_ctrl) power_supply_changed(&mhl_ctrl->mhl_psy); if (mhl_ctrl->notify_usb_online) mhl_ctrl->notify_usb_online(0); - return -EACCES; + return 0; } if ((mhl_ctrl->cur_state != POWER_STATE_D0_NO_MHL) &&\ @@ -1054,6 +1061,32 @@ static void mhl_misc_isr(struct mhl_tx_ctrl *mhl_ctrl) MHL_SII_REG_NAME_WR(REG_INTR5, intr_5_stat); } +static void mhl_tx_down(struct mhl_tx_ctrl *mhl_ctrl) +{ + struct i2c_client *client = mhl_ctrl->i2c_handle; + unsigned long flags; + uint8_t reg; + + switch_mode(mhl_ctrl, POWER_STATE_D3, true); + + reg = MHL_SII_REG_NAME_RD(REG_INTR1); + MHL_SII_REG_NAME_WR(REG_INTR1, reg); + + reg = MHL_SII_REG_NAME_RD(REG_INTR4); + MHL_SII_REG_NAME_WR(REG_INTR4, reg); + + /* disable INTR1 and INTR4 */ + MHL_SII_REG_NAME_MOD(REG_INTR1_MASK, BIT6, 0x0); + MHL_SII_REG_NAME_MOD(REG_INTR4_MASK, + (BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT5 | BIT6), 0x0); + + MHL_SII_PAGE1_MOD(0x003D, BIT0, 0x00); + spin_lock_irqsave(&mhl_ctrl->lock, flags); + mhl_ctrl->tx_powered_off = true; + spin_unlock_irqrestore(&mhl_ctrl->lock, flags); + pr_debug("%s: disabled\n", __func__); + disable_irq_nosync(client->irq); +} static void mhl_hpd_stat_isr(struct mhl_tx_ctrl *mhl_ctrl) { @@ -1085,20 +1118,24 @@ static void mhl_hpd_stat_isr(struct mhl_tx_ctrl *mhl_ctrl) spin_lock_irqsave(&mhl_ctrl->lock, flags); t = mhl_ctrl->dwnstream_hpd; + pr_debug("%s: %u: dwnstrm_hpd=0x%02x\n", + __func__, __LINE__, mhl_ctrl->dwnstream_hpd); spin_unlock_irqrestore(&mhl_ctrl->lock, flags); if (BIT6 & (cbus_stat ^ t)) { u8 status = cbus_stat & BIT6; mhl_drive_hpd(mhl_ctrl, status ? HPD_UP : HPD_DOWN); - if (!status) { - MHL_SII_PAGE1_MOD(0x003D, BIT0, 0x00); - spin_lock_irqsave(&mhl_ctrl->lock, flags); - mhl_ctrl->tx_powered_off = true; - spin_unlock_irqrestore(&mhl_ctrl->lock, flags); + if (!status && mhl_ctrl->mhl_det_discon) { + pr_debug("%s:%u: power_down\n", + __func__, __LINE__); + mhl_tx_down(mhl_ctrl); } spin_lock_irqsave(&mhl_ctrl->lock, flags); mhl_ctrl->dwnstream_hpd = cbus_stat; + pr_debug("%s: %u: dwnstrm_hpd=0x%02x\n", + __func__, __LINE__, mhl_ctrl->dwnstream_hpd); spin_unlock_irqrestore(&mhl_ctrl->lock, flags); + mhl_ctrl->mhl_det_discon = false; } } } @@ -1252,6 +1289,7 @@ static void mhl_cbus_isr(struct mhl_tx_ctrl *mhl_ctrl) uint8_t cmd_data = 0x0; int msc_msg_recved = 0; int rc = -1; + unsigned long flags; struct i2c_client *client = mhl_ctrl->i2c_handle; regval = MHL_SII_REG_NAME_RD(REG_CBUS_INTR_STATUS); @@ -1292,6 +1330,14 @@ static void mhl_cbus_isr(struct mhl_tx_ctrl *mhl_ctrl) intr = MHL_SII_REG_NAME_RD(REG_CBUS_SET_INT_0); MHL_SII_REG_NAME_WR(REG_CBUS_SET_INT_0, intr); mhl_msc_recv_set_int(mhl_ctrl, 0, intr); + if (intr & MHL_INT_DCAP_CHG) { + /* No need to go to low power mode */ + spin_lock_irqsave(&mhl_ctrl->lock, flags); + mhl_ctrl->dwnstream_hpd = 0x00; + pr_debug("%s: %u: dwnstrm_hpd=0x%02x\n", + __func__, __LINE__, mhl_ctrl->dwnstream_hpd); + spin_unlock_irqrestore(&mhl_ctrl->lock, flags); + } pr_debug("%s: MHL_INT_0 = %02x\n", __func__, intr); intr = MHL_SII_REG_NAME_RD(REG_CBUS_SET_INT_1); @@ -1337,8 +1383,18 @@ static irqreturn_t mhl_tx_isr(int irq, void *data) { int rc; struct mhl_tx_ctrl *mhl_ctrl = (struct mhl_tx_ctrl *)data; + unsigned long flags; + pr_debug("%s: Getting Interrupts\n", __func__); + spin_lock_irqsave(&mhl_ctrl->lock, flags); + if (mhl_ctrl->tx_powered_off) { + pr_warn("%s: powered off\n", __func__); + spin_unlock_irqrestore(&mhl_ctrl->lock, flags); + return IRQ_HANDLED; + } + spin_unlock_irqrestore(&mhl_ctrl->lock, flags); + /* * Check RGND, MHL_EST, CBUS_LOCKOUT, SCDT * interrupts. In D3, we get only RGND @@ -1398,6 +1454,8 @@ static int mhl_tx_chip_init(struct mhl_tx_ctrl *mhl_ctrl) */ mhl_init_reg_settings(mhl_ctrl, true); switch_mode(mhl_ctrl, POWER_STATE_D3, true); + pr_debug("%s:%u: power_down\n", __func__, __LINE__); + mhl_tx_down(mhl_ctrl); return 0; } |
