summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPradeep Goudagunta <pgoudagunta@nvidia.com>2011-02-15 16:39:08 +0530
committerVarun Colbert <vcolbert@nvidia.com>2011-02-22 18:03:59 -0800
commit30f8e96200c5bb29be447456eeeb9e3e220dd0b1 (patch)
tree4b1722317720cc2de3d3f0e5f413f41e74babb70
parent65aaf50c61234103c3d9359dd8d4558306a262f8 (diff)
arm: tegra: hsuart: Support for Bluetooth wakeup
Added support to tegra_hsuart driver for bluetooth wakeup. Bug 773186 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>
-rw-r--r--drivers/serial/tegra_hsuart.c100
-rw-r--r--include/linux/tegra_uart.h6
2 files changed, 103 insertions, 3 deletions
diff --git a/drivers/serial/tegra_hsuart.c b/drivers/serial/tegra_hsuart.c
index 0250789253ea..b683a3d5d2cd 100644
--- a/drivers/serial/tegra_hsuart.c
+++ b/drivers/serial/tegra_hsuart.c
@@ -77,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
@@ -116,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;
};
@@ -553,6 +558,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);
}
@@ -684,6 +690,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;
}
@@ -1164,7 +1171,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;
}
@@ -1178,7 +1195,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;
}
@@ -1261,13 +1282,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
index b33bbb6f366a..435b4198e4be 100644
--- a/include/linux/tegra_uart.h
+++ b/include/linux/tegra_uart.h
@@ -24,4 +24,10 @@ struct tegra_uart_platform_data {
void (*wake_peer)(struct uart_port *);
};
+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_ */
+