summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLaxman Dewangan <ldewangan@nvidia.com>2010-06-17 14:16:19 +0530
committerGary King <gking@nvidia.com>2010-06-18 14:35:48 -0700
commit98e7f2cfa2fa0a62bf09e04a90719f04a8472588 (patch)
tree19cc88c9af6bd86a3844b055226294a62c763200 /drivers
parentdcb48435e04dba5aafe87cd2ebaa1e0f09bf90cb (diff)
[arm/tegra]serial: Power control api for bluesleep power management.
Adding apis for following function to hooking up tegra serial driver with bluesleep power management: - Clock off. - Clock on. - Setting flow control to desired state. - Checking for tx fifo status. Following 4 state of uart state machine is developed to achieve this: UART_CLOSED, UART_OPENED, UART_SUSPEND, UART_CLOCK_OFF. The transitions of states are as follows: UART_CLOSED: the init state on which resource is allocated but not opened by client or when device is closed. UART_OPENED: Able to do data transfer. CLOSED to OPENED by opening the port. CLOCK_OFF to OPENED by calling function tegra_uart_request_clock_on(). SUSPEND to OPENED by calling resume(). UART_CLOCK_OFF: The controller clock is disabled and so no data transfer can happen. At this state, controller is not ready for deep power down. OPENED to CLOCK_OFF by calling tegra_uart_request_clock_off(). Can not go to this state from CLOSED and SUSPEND. UART_SUSPEND: The controller is in suspended state and ready for deep power down. UART_CLOCK_OFF to SUSPEND: OPENED to SUSPEND. Change-Id: Ib0c40547665181cadd172840be9aed2cc18ba448 Reviewed-on: http://git-master/r/2819 Reviewed-by: Anantha Idapalapati <aidapalapati@nvidia.com> Tested-by: Anantha Idapalapati <aidapalapati@nvidia.com> Reviewed-by: Udaykumar Rameshchan Raval <uraval@nvidia.com> Reviewed-by: Gary King <gking@nvidia.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/serial/tegra_hsuart.c94
1 files changed, 92 insertions, 2 deletions
diff --git a/drivers/serial/tegra_hsuart.c b/drivers/serial/tegra_hsuart.c
index 77fc79037b62..39a6035e9955 100644
--- a/drivers/serial/tegra_hsuart.c
+++ b/drivers/serial/tegra_hsuart.c
@@ -75,6 +75,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
+
struct tegra_uart_port {
struct uart_port uport;
char port_name[32];
@@ -112,6 +117,7 @@ struct tegra_uart_port {
bool use_tx_dma;
bool rx_timeout;
+ int uart_state;
};
static inline u8 uart_readb(struct tegra_uart_port *t, unsigned long reg)
@@ -539,6 +545,7 @@ static void tegra_uart_hw_deinit(struct tegra_uart_port *t)
t->baud = 0;
if (t->pinmux)
tegra_pinmux_config_tristate_table(t->pinmux, t->nr_pins, TEGRA_TRI_TRISTATE);
+ t->uart_state = TEGRA_UART_CLOSED;
}
static void tegra_uart_free_rx_dma(struct tegra_uart_port *t)
@@ -659,6 +666,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;
}
@@ -1123,10 +1131,18 @@ static int tegra_uart_suspend(struct platform_device *pdev, pm_message_t state)
dev_err(t->uport.dev, "tegra_uart_suspend called\n");
u = &t->uport;
+
+ /* 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);
if (t->pinmux)
tegra_pinmux_config_tristate_table(t->pinmux, t->nr_pins, TEGRA_TRI_TRISTATE);
-
+ t->uart_state = TEGRA_UART_SUSPEND;
return 0;
}
@@ -1142,7 +1158,11 @@ static int tegra_uart_resume(struct platform_device *pdev)
dev_err(t->uport.dev, "tegra_uart_resume called\n");
if (t->pinmux)
tegra_pinmux_config_tristate_table(t->pinmux, t->nr_pins, TEGRA_TRI_NORMAL);
- uart_resume_port(&tegra_uart_driver, u);
+
+ if (t->uart_state == TEGRA_UART_SUSPEND) {
+ uart_resume_port(&tegra_uart_driver, u);
+ t->uart_state = TEGRA_UART_OPENED;
+ }
return 0;
}
@@ -1217,12 +1237,82 @@ static int __init tegra_uart_probe(struct platform_device *pdev)
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;
+
+ 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;
+
+ 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;
+ unsigned char mcr;
+ struct tegra_uart_port *t;
+
+ t = container_of(uport, struct tegra_uart_port, uport);
+ spin_lock_irqsave(&uport->lock, flags);
+ mcr = t->mcr_shadow;
+ 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;