/* turn clock off if TX buffer is empty, otherwise reschedule */ static enum hrtimer_restart msm_serial_clock_off(struct hrtimer *timer) { struct msm_port *msm_port = container_of(timer, struct msm_port, clk_off_timer); struct uart_port *port = &msm_port->uart; struct circ_buf *xmit = &port->info->xmit; unsigned long flags; int ret = HRTIMER_NORESTART; spin_lock_irqsave(&port->lock, flags); if (msm_port->clk_state == MSM_CLK_REQUEST_OFF) { if (uart_circ_empty(xmit)) { struct msm_port *msm_port = UART_TO_MSM(port); clk_disable(msm_port->clk); msm_port->clk_state = MSM_CLK_OFF; #ifdef CONFIG_SERIAL_MSM_RX_WAKEUP if (use_low_power_wakeup(msm_port)) { msm_port->wakeup.ignore = 1; enable_irq(msm_port->wakeup.irq); } #endif } else { hrtimer_forward_now(timer, msm_port->clk_off_delay); ret = HRTIMER_RESTART; } } spin_unlock_irqrestore(&port->lock, flags); return HRTIMER_NORESTART; }
/* request to immediately turn on uart clock. * ignored if there is a pending off request, unless force = 1. */ void msm_serial_clock_on(struct uart_port *port, int force) { unsigned long flags; struct msm_port *msm_port = UART_TO_MSM(port); spin_lock_irqsave(&port->lock, flags); switch (msm_port->clk_state) { case MSM_CLK_OFF: clk_enable(msm_port->clk); #ifdef CONFIG_SERIAL_MSM_RX_WAKEUP if (use_low_power_wakeup(msm_port)) disable_irq(msm_port->wakeup.irq); #endif force = 1; case MSM_CLK_REQUEST_OFF: if (force) { hrtimer_try_to_cancel(&msm_port->clk_off_timer); msm_port->clk_state = MSM_CLK_ON; } break; case MSM_CLK_ON: break; case MSM_CLK_PORT_OFF: break; } spin_unlock_irqrestore(&port->lock, flags); }
static void msm_shutdown(struct uart_port *port) { struct msm_port *msm_port = UART_TO_MSM(port); if (msm_port->uim) msm_write(port, UART_SIM_CFG_SIM_CLK_STOP_HIGH, UART_SIM_CFG); msm_port->imr = 0; msm_write(port, 0, UART_IMR); /* disable interrupts */ free_irq(port->irq, port); #ifdef CONFIG_SERIAL_MSM_RX_WAKEUP if (use_low_power_wakeup(msm_port)) { irq_set_irq_wake(msm_port->wakeup.irq, 0); free_irq(msm_port->wakeup.irq, msm_port); } #endif #ifndef CONFIG_PM_RUNTIME msm_deinit_clock(port); #endif pm_runtime_put_sync(port->dev); }
static void msm_shutdown(struct uart_port *port) { struct msm_port *msm_port = UART_TO_MSM(port); clk_enable(msm_port->clk); msm_port->imr = 0; msm_write(port, 0, UART_IMR); /* disable interrupts */ clk_disable(msm_port->clk); free_irq(port->irq, port); #ifdef CONFIG_SERIAL_MSM_RX_WAKEUP if (use_low_power_wakeup(msm_port)) { set_irq_wake(msm_port->wakeup.irq, 0); free_irq(msm_port->wakeup.irq, msm_port); } #endif msm_deinit_clock(port); }
static int msm_startup(struct uart_port *port) { struct msm_port *msm_port = UART_TO_MSM(port); unsigned int data, rfr_level; int ret; snprintf(msm_port->name, sizeof(msm_port->name), "msm_serial%d", port->line); ret = request_irq(port->irq, msm_irq, IRQF_TRIGGER_HIGH, msm_port->name, port); if (unlikely(ret)) return ret; msm_init_clock(port); if (likely(port->fifosize > 12)) rfr_level = port->fifosize - 12; else rfr_level = port->fifosize; /* set automatic RFR level */ data = msm_read(port, UART_MR1); data &= ~UART_MR1_AUTO_RFR_LEVEL1; data &= ~UART_MR1_AUTO_RFR_LEVEL0; data |= UART_MR1_AUTO_RFR_LEVEL1 & (rfr_level << 2); data |= UART_MR1_AUTO_RFR_LEVEL0 & rfr_level; msm_write(port, data, UART_MR1); /* make sure that RXSTALE count is non-zero */ data = msm_read(port, UART_IPR); if (unlikely(!data)) { data |= UART_IPR_RXSTALE_LAST; data |= UART_IPR_STALE_LSB; msm_write(port, data, UART_IPR); } msm_reset(port); msm_write(port, 0x05, UART_CR); /* enable TX & RX */ /* turn on RX and CTS interrupts */ msm_port->imr = UART_IMR_RXLEV | UART_IMR_RXSTALE | UART_IMR_CURRENT_CTS; msm_write(port, msm_port->imr, UART_IMR); #ifdef CONFIG_SERIAL_MSM_RX_WAKEUP if (use_low_power_wakeup(msm_port)) { ret = set_irq_wake(msm_port->wakeup.irq, 1); if (unlikely(ret)) return ret; ret = request_irq(msm_port->wakeup.irq, msm_rx_irq, IRQF_TRIGGER_FALLING, "msm_serial_wakeup", msm_port); if (unlikely(ret)) return ret; disable_irq(msm_port->wakeup.irq); } #endif return 0; }