misc: cec: add wait_event for CEC ops
Shridhar Rasal [Tue, 14 May 2013 09:30:33 +0000 (14:30 +0530)]
Add wait_event to make sure that CEC functions
do not execute until CEC init completes.

Bug 1283088

Change-Id: I1d26360326338f549a14cbf109a24c2935ebe472
Signed-off-by: Shridhar Rasal <srasal@nvidia.com>
Reviewed-on: http://git-master/r/232566
Reviewed-by: Sachin Nikam <snikam@nvidia.com>

drivers/misc/tegra-cec/tegra_cec.c
drivers/misc/tegra-cec/tegra_cec.h

index 21c5bee..3ec1267 100644 (file)
@@ -46,6 +46,8 @@ int tegra_cec_open(struct inode *inode, struct file *file)
        struct tegra_cec *cec = container_of(miscdev,
                struct tegra_cec, misc_dev);
        dev_dbg(cec->dev, "%s\n", __func__);
+
+       wait_event_interruptible(cec->init_waitq, cec->init_done == 1);
        file->private_data = cec;
 
        return 0;
@@ -68,6 +70,8 @@ ssize_t tegra_cec_write(struct file *file, const char __user *buffer,
 
        count = 4;
 
+       wait_event_interruptible(cec->init_waitq, cec->init_done == 1);
+
        if (copy_from_user(&write_buff, buffer, count))
                return -EFAULT;
 
@@ -103,6 +107,8 @@ ssize_t tegra_cec_read(struct file *file, char  __user *buffer,
        unsigned short rx_buffer;
        count = 2;
 
+       wait_event_interruptible(cec->init_waitq, cec->init_done == 1);
+
        if (cec->rx_wake == 0)
                if (file->f_flags & O_NONBLOCK)
                        return -EAGAIN;
@@ -125,6 +131,8 @@ static irqreturn_t tegra_cec_irq_handler(int irq, void *data)
        struct tegra_cec *cec = dev_get_drvdata(dev);
        unsigned long status;
 
+       wait_event_interruptible(cec->init_waitq, cec->init_done == 1);
+
        status = readl(cec->cec_base + TEGRA_CEC_INT_STAT);
 
        if (!status)
@@ -178,6 +186,10 @@ static const struct file_operations tegra_cec_fops = {
 static void tegra_cec_init(struct tegra_cec *cec)
 {
 
+       dev_notice(cec->dev, "%s started\n", __func__);
+
+       cec->init_done = 0;
+
        writel(0x00, cec->cec_base + TEGRA_CEC_HW_CONTROL);
        writel(0x00, cec->cec_base + TEGRA_CEC_INT_MASK);
        writel(0xffffffff, cec->cec_base + TEGRA_CEC_INT_STAT);
@@ -234,6 +246,11 @@ static void tegra_cec_init(struct tegra_cec *cec)
            TEGRA_CEC_INT_MASK_RX_REGISTER_FULL |
            TEGRA_CEC_INT_MASK_RX_REGISTER_OVERRUN),
           cec->cec_base + TEGRA_CEC_INT_MASK);
+
+       cec->init_done = 1;
+       wake_up_interruptible(&cec->init_waitq);
+
+       dev_notice(cec->dev, "%s Done.\n", __func__);
 }
 
 static void tegra_cec_init_worker(struct work_struct *work)
@@ -303,6 +320,7 @@ static int __devinit tegra_cec_probe(struct platform_device *pdev)
        cec->tx_wake = 0;
        init_waitqueue_head(&cec->rx_waitq);
        init_waitqueue_head(&cec->tx_waitq);
+       init_waitqueue_head(&cec->init_waitq);
 
        platform_set_drvdata(pdev, cec);
        /* clear out the hardware. */
@@ -362,6 +380,7 @@ static int tegra_cec_suspend(struct platform_device *pdev, pm_message_t state)
 
        clk_disable(cec->clk);
 
+       dev_notice(&pdev->dev, "suspended\n");
        return 0;
 }
 
@@ -369,6 +388,8 @@ static int tegra_cec_resume(struct platform_device *pdev)
 {
        struct tegra_cec *cec = platform_get_drvdata(pdev);
 
+       dev_notice(&pdev->dev, "Resuming\n");
+
        clk_enable(cec->clk);
        schedule_work(&cec->work);
 
index e33eb20..dc23c42 100644 (file)
@@ -27,8 +27,10 @@ struct tegra_cec {
        int                     tegra_cec_irq;
        wait_queue_head_t       rx_waitq;
        wait_queue_head_t       tx_waitq;
+       wait_queue_head_t       init_waitq;
        unsigned int            rx_wake;
        unsigned int            tx_wake;
+       unsigned int            init_done;
        struct work_struct      work;
 };
 static int tegra_cec_remove(struct platform_device *pdev);