diff --git a/drivers/misc/tegra-cec/tegra_cec.c b/drivers/misc/tegra-cec/tegra_cec.c index 03f00715..675df587 100644 --- a/drivers/misc/tegra-cec/tegra_cec.c +++ b/drivers/misc/tegra-cec/tegra_cec.c @@ -119,10 +119,16 @@ static int tegra_cec_release(struct inode *inode, struct file *file) static inline void tegra_cec_native_tx(const struct tegra_cec *cec, u32 block) { - tegra_cec_writel(block, cec->cec_base + TEGRA_CEC_TX_REGISTER); - tegra_cec_writel(TEGRA_CEC_INT_STAT_TX_REGISTER_EMPTY, - cec->cec_base + TEGRA_CEC_INT_STAT); + u32 tx_reg, retry; + tegra_cec_writel(block, cec->cec_base + TEGRA_CEC_TX_REGISTER); + + tx_reg = tegra_cec_readl(cec->cec_base + TEGRA_CEC_TX_REGISTER); + retry = 10; + while ((tx_reg & 0x80000000) && retry--) { + udelay(31); // one clock cycle = 30.5us + tx_reg = tegra_cec_readl(cec->cec_base + TEGRA_CEC_TX_REGISTER); + } } static inline void tegra_cec_error_recovery(struct tegra_cec *cec) @@ -235,24 +241,16 @@ static ssize_t tegra_cec_read(struct file *file, char __user *buffer, if (ret) return ret; - if (cec->rx_fifo_data != 0) { - count = sizeof(cec->rx_fifo[0]) * (cec->rx_fifo_data); - if (copy_to_user(buffer, &(cec->rx_fifo_data), count)) - return -EFAULT; + count = sizeof(cec->rx_fifo[0]) * (cec->rx_fifo_data); + if (copy_to_user(buffer, &(cec->rx_fifo[0]), count)) + return -EFAULT; - dev_dbg(cec->dev, "%s: %*phC", __func__, (int)count, - &(cec->rx_fifo[0])); - } else { - count = sizeof(cec->rx_buffer); - if (copy_to_user(buffer, &(cec->rx_buffer), count)) - return -EFAULT; + dev_dbg(cec->dev, "%s: %*phC", __func__, (int)count, + &(cec->rx_fifo[0])); - dev_dbg(cec->dev, "%s: %*phC", __func__, (int)count, - &(cec->rx_buffer)); - } - - cec->rx_buffer = 0x0; + memset(&(cec->rx_fifo[0]), 0, count); cec->rx_wake = 0; + cec->rx_fifo_data = 0; return count; } @@ -332,28 +330,27 @@ static irqreturn_t tegra_cec_irq_handler(int irq, void *data) TEGRA_CEC_INT_STAT_RX_BUS_ERROR_DETECTED), cec->cec_base + TEGRA_CEC_INT_STAT); } else if (status & TEGRA_CEC_INT_STAT_RX_REGISTER_FULL) { + /* + Read TEGRA_CEC_RX_BUFFER_STAT_0 which have total number of blocks, + then read every block continuously from TEGRA_CEC_RX_REGISTER. + TEGRA_CEC_INT_STAT_RX_REGISTER_FULL sets only once and not for + every block if there are more than 1 block in FIFO. + */ + cec->rx_fifo_data = + tegra_cec_readl(cec->cec_base + TEGRA_CEC_RX_BUFFER_STAT_0); + for (i = 0; i < cec->rx_fifo_data; i++) { + cec->rx_fifo[i] = + readw(cec->cec_base + TEGRA_CEC_RX_REGISTER); + } + tegra_cec_writel(TEGRA_CEC_INT_STAT_RX_REGISTER_FULL, cec->cec_base + TEGRA_CEC_INT_STAT); - if (cec->is_tegra_cec_suspended) { - /* - Read TEGRA_CEC_RX_BUFFER_STAT_0 which have total number of blocks, - then read every block continuously from TEGRA_CEC_RX_REGISTER. - TEGRA_CEC_INT_STAT_RX_REGISTER_FULL sets only once and not for - every block if there are more than 1 block in FIFO. - */ - cec->rx_fifo_data = - tegra_cec_readl(cec->cec_base + TEGRA_CEC_RX_BUFFER_STAT_0); - for (i = 0; i < cec->rx_fifo_data; i++) { - cec->rx_fifo[i] = - readw(cec->cec_base + TEGRA_CEC_RX_REGISTER); - } - pm_wakeup_event(dev, 0); - } else { - cec->rx_buffer = readw(cec->cec_base + TEGRA_CEC_RX_REGISTER); - cec->rx_fifo_data = 0; - } - cec->rx_wake = 1; - wake_up_interruptible(&cec->rx_waitq); + + if (cec->is_tegra_cec_suspended) + pm_wakeup_event(dev, 0); + + cec->rx_wake = 1; + wake_up_interruptible(&cec->rx_waitq); } out: @@ -545,8 +542,9 @@ static void tegra_cec_init(struct tegra_cec *cec) cec->logical_addr = TEGRA_CEC_HWCTRL_RX_LADDR_UNREG; - tegra_cec_writel(TEGRA_CEC_HWCTRL_RX_LADDR(cec->logical_addr), - cec->cec_base + TEGRA_CEC_HW_CONTROL); + state = TEGRA_CEC_HWCTRL_AUTO_CLR_TX_EMPTY_INTR | + TEGRA_CEC_HWCTRL_RX_LADDR(cec->logical_addr); + tegra_cec_writel(state, cec->cec_base + TEGRA_CEC_HW_CONTROL); state = (0xff << TEGRA_CEC_RX_TIMING_1_RX_DATA_BIT_MAX_LO_TIME_MASK) | (0x22 << TEGRA_CEC_RX_TIMING_1_RX_DATA_BIT_SAMPLE_TIME_MASK) | diff --git a/drivers/misc/tegra-cec/tegra_cec.h b/drivers/misc/tegra-cec/tegra_cec.h index b666f7b4..18c109f4 100644 --- a/drivers/misc/tegra-cec/tegra_cec.h +++ b/drivers/misc/tegra-cec/tegra_cec.h @@ -34,7 +34,6 @@ struct tegra_cec { struct work_struct work; unsigned int rx_wake; unsigned int tx_wake; - u16 rx_buffer; long tx_error; u32 tx_buf[TEGRA_CEC_FRAME_MAX_LENGTH]; u8 tx_buf_cur; @@ -90,6 +89,7 @@ struct tegra_cec { #define TEGRA_CEC_HWCTRL_RX_SNOOP (1<<15) #define TEGRA_CEC_HWCTRL_RX_NAK_MODE (1<<16) #define TEGRA_CEC_HWCTRL_TX_NAK_MODE (1<<24) +#define TEGRA_CEC_HWCTRL_AUTO_CLR_TX_EMPTY_INTR (1<<29) #define TEGRA_CEC_HWCTRL_FAST_SIM_MODE (1<<30) #define TEGRA_CEC_HWCTRL_TX_RX_MODE (1<<31)