arm: tegra: hsuart: Support for Bluetooth wakeup
Pradeep Goudagunta [Tue, 15 Feb 2011 11:09:08 +0000 (16:09 +0530)]
Added support to tegra_hsuart driver for bluetooth wakeup.

Bug 773186

Original-Change-Id: Id8f1face1b99942fd13949d0815a1dedd1a5a5d0
Reviewed-on: http://git-master/r/19586
Reviewed-by: Anantha Idapalapati <aidapalapati@nvidia.com>
Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>
Tested-by: Anantha Idapalapati <aidapalapati@nvidia.com>

Rebase-Id: R50674612ae84881e01f7ef632188cfd1806dacab

drivers/tty/serial/tegra_hsuart.c
include/linux/tegra_uart.h [new file with mode: 0644]

index a9e872c..0cb8187 100644 (file)
@@ -41,6 +41,8 @@
 #include <linux/debugfs.h>
 #include <linux/slab.h>
 #include <linux/workqueue.h>
+#include <linux/tegra_uart.h>
+
 #include <mach/dma.h>
 #include <mach/clk.h>
 
@@ -75,6 +77,11 @@ const int dma_req_sel[] = {
 #define TEGRA_UART_MIN_DMA             16
 #define TEGRA_UART_FIFO_SIZE           8
 
+#define TEGRA_UART_CLOSED    0
+#define TEGRA_UART_OPENED    1
+#define TEGRA_UART_CLOCK_OFF 2
+#define TEGRA_UART_SUSPEND   3
+
 /* Tx fifo trigger level setting in tegra uart is in
  * reverse way then conventional uart */
 #define TEGRA_UART_TX_TRIG_16B 0x00
@@ -114,7 +121,7 @@ struct tegra_uart_port {
 
        bool                    use_rx_dma;
        bool                    use_tx_dma;
-
+       int                     uart_state;
        bool                    rx_timeout;
        int                     rx_in_progress;
 };
@@ -593,6 +600,7 @@ static void tegra_uart_hw_deinit(struct tegra_uart_port *t)
 
        clk_disable(t->clk);
        t->baud = 0;
+       t->uart_state = TEGRA_UART_CLOSED;
 
        spin_unlock_irqrestore(&t->uport.lock, flags);
 }
@@ -710,6 +718,7 @@ static int tegra_uart_hw_init(struct tegra_uart_port *t)
        t->ier_shadow = ier;
        uart_writeb(t, ier, UART_IER);
 
+       t->uart_state = TEGRA_UART_OPENED;
        dev_vdbg(t->uport.dev, "-tegra_uart_hw_init\n");
        return 0;
 }
@@ -1183,7 +1192,17 @@ static int tegra_uart_suspend(struct platform_device *pdev, pm_message_t state)
                pr_err("Invalid Uart instance (%d)\n", pdev->id);
 
        u = &t->uport;
+       dev_dbg(t->uport.dev, "tegra_uart_suspend called\n");
+
+       /* enable clock before calling suspend so that controller
+          register can be accessible */
+       if (t->uart_state == TEGRA_UART_CLOCK_OFF) {
+               clk_enable(t->clk);
+               t->uart_state = TEGRA_UART_OPENED;
+       }
+
        uart_suspend_port(&tegra_uart_driver, u);
+       t->uart_state = TEGRA_UART_SUSPEND;
 
        return 0;
 }
@@ -1197,7 +1216,11 @@ static int tegra_uart_resume(struct platform_device *pdev)
                pr_err("Invalid Uart instance (%d)\n", pdev->id);
 
        u = &t->uport;
-       uart_resume_port(&tegra_uart_driver, u);
+       dev_dbg(t->uport.dev, "tegra_uart_resume called\n");
+
+       if (t->uart_state == TEGRA_UART_SUSPEND) {
+               uart_resume_port(&tegra_uart_driver, u);
+       }
        return 0;
 }
 
@@ -1280,13 +1303,86 @@ static int tegra_uart_probe(struct platform_device *pdev)
        snprintf(name, sizeof(name), "tegra_hsuart_%d", u->line);
        pr_info("Registered UART port %s%d\n",
                tegra_uart_driver.dev_name, u->line);
-
+       t->uart_state = TEGRA_UART_CLOSED;
        return ret;
 fail:
        kfree(t);
        return -ENODEV;
 }
 
+/* Switch off the clock of the uart controller. */
+void tegra_uart_request_clock_off(struct uart_port *uport)
+{
+       unsigned long flags;
+       struct tegra_uart_port *t;
+
+       if (IS_ERR_OR_NULL(uport))
+               BUG();
+
+       dev_vdbg(uport->dev, "tegra_uart_request_clock_off");
+
+       t = container_of(uport, struct tegra_uart_port, uport);
+       spin_lock_irqsave(&uport->lock, flags);
+       if (t->uart_state == TEGRA_UART_OPENED) {
+               clk_disable(t->clk);
+               t->uart_state = TEGRA_UART_CLOCK_OFF;
+       }
+       spin_unlock_irqrestore(&uport->lock, flags);
+       return;
+}
+
+/* Switch on the clock of the uart controller */
+void tegra_uart_request_clock_on(struct uart_port *uport)
+{
+       unsigned long flags;
+       struct tegra_uart_port *t;
+
+       if (IS_ERR_OR_NULL(uport))
+               BUG();
+
+       t = container_of(uport, struct tegra_uart_port, uport);
+       spin_lock_irqsave(&uport->lock, flags);
+       if (t->uart_state == TEGRA_UART_CLOCK_OFF) {
+               clk_enable(t->clk);
+               t->uart_state = TEGRA_UART_OPENED;
+       }
+       spin_unlock_irqrestore(&uport->lock, flags);
+       return;
+}
+
+/* Set the modem control signals state of uart controller. */
+void tegra_uart_set_mctrl(struct uart_port *uport, unsigned int mctrl)
+{
+       unsigned long flags;
+       struct tegra_uart_port *t;
+
+       t = container_of(uport, struct tegra_uart_port, uport);
+       spin_lock_irqsave(&uport->lock, flags);
+       if (mctrl & TIOCM_RTS) {
+               t->rts_active = true;
+               set_rts(t, true);
+       } else {
+               t->rts_active = false;
+               set_rts(t, false);
+       }
+
+       if (mctrl & TIOCM_DTR)
+               set_dtr(t, true);
+       else
+               set_dtr(t, false);
+       spin_unlock_irqrestore(&uport->lock, flags);
+       return;
+}
+
+/* Return the status of the transmit fifo whether empty or not.
+ * Return 0 if tx fifo is not empty.
+ * Return TIOCSER_TEMT if tx fifo is empty.
+ */
+int tegra_uart_is_tx_empty(struct uart_port *uport)
+{
+       return tegra_tx_empty(uport);
+}
+
 static int __init tegra_uart_init(void)
 {
        int ret;
diff --git a/include/linux/tegra_uart.h b/include/linux/tegra_uart.h
new file mode 100644 (file)
index 0000000..fe6167d
--- /dev/null
@@ -0,0 +1,29 @@
+/* include/linux/tegra_uart.h
+ *
+ * Copyright (C) 2011 NVIDIA Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#ifndef _TEGRA_UART_H_
+#define _TEGRA_UART_H_
+
+int tegra_uart_is_tx_empty(struct uart_port *);
+void tegra_uart_request_clock_on(struct uart_port *);
+void tegra_uart_set_mctrl(struct uart_port *, unsigned int);
+void tegra_uart_request_clock_off(struct uart_port *uport);
+
+#endif /* _TEGRA_UART_H_ */
+