blob: 9bfdcebe21b9416d0e8f55aa2b1bb310f5210060 [file] [log] [blame]
Robert Love04896a72009-06-22 18:43:11 +01001/*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 * drivers/serial/msm_serial.c - driver for msm7k serial device and console
Robert Love04896a72009-06-22 18:43:11 +01003 *
4 * Copyright (C) 2007 Google, Inc.
Duy Truonge833aca2013-02-12 13:35:08 -08005 * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
Robert Love04896a72009-06-22 18:43:11 +01006 * Author: Robert Love <rlove@google.com>
7 *
8 * This software is licensed under the terms of the GNU General Public
9 * License version 2, as published by the Free Software Foundation, and
10 * may be copied, distributed, and modified under those terms.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 */
17
18#if defined(CONFIG_SERIAL_MSM_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
19# define SUPPORT_SYSRQ
20#endif
21
22#include <linux/hrtimer.h>
23#include <linux/module.h>
24#include <linux/io.h>
25#include <linux/ioport.h>
26#include <linux/irq.h>
27#include <linux/init.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070028#include <linux/delay.h>
Robert Love04896a72009-06-22 18:43:11 +010029#include <linux/console.h>
30#include <linux/tty.h>
31#include <linux/tty_flip.h>
32#include <linux/serial_core.h>
33#include <linux/serial.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070034#include <linux/nmi.h>
Robert Love04896a72009-06-22 18:43:11 +010035#include <linux/clk.h>
36#include <linux/platform_device.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070037#include <linux/pm_runtime.h>
38#include <mach/msm_serial_pdata.h>
Robert Love04896a72009-06-22 18:43:11 +010039#include "msm_serial.h"
40
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070041
42#ifdef CONFIG_SERIAL_MSM_CLOCK_CONTROL
43enum msm_clk_states_e {
44 MSM_CLK_PORT_OFF, /* uart port not in use */
45 MSM_CLK_OFF, /* clock enabled */
46 MSM_CLK_REQUEST_OFF, /* disable after TX flushed */
47 MSM_CLK_ON, /* clock disabled */
48};
49#endif
50
51#ifdef CONFIG_SERIAL_MSM_RX_WAKEUP
52/* optional low power wakeup, typically on a GPIO RX irq */
53struct msm_wakeup {
54 int irq; /* < 0 indicates low power wakeup disabled */
55 unsigned char ignore; /* bool */
56
57 /* bool: inject char into rx tty on wakeup */
58 unsigned char inject_rx;
59 char rx_to_inject;
60};
61#endif
62
Robert Love04896a72009-06-22 18:43:11 +010063struct msm_port {
64 struct uart_port uart;
65 char name[16];
66 struct clk *clk;
67 unsigned int imr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070068#ifdef CONFIG_SERIAL_MSM_CLOCK_CONTROL
69 enum msm_clk_states_e clk_state;
70 struct hrtimer clk_off_timer;
71 ktime_t clk_off_delay;
72#endif
73#ifdef CONFIG_SERIAL_MSM_RX_WAKEUP
74 struct msm_wakeup wakeup;
75#endif
Rohit Vaswani41c2dcc2012-06-21 15:20:39 -070076 int uim;
Robert Love04896a72009-06-22 18:43:11 +010077};
78
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070079#define UART_TO_MSM(uart_port) ((struct msm_port *) uart_port)
80#define is_console(port) ((port)->cons && \
81 (port)->cons->index == (port)->line)
82
83
84static inline void msm_write(struct uart_port *port, unsigned int val,
85 unsigned int off)
Stepan Moskovchenkoec8f29e2010-12-21 12:38:05 -080086{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070087 __raw_writel(val, port->membase + off);
Stepan Moskovchenkoec8f29e2010-12-21 12:38:05 -080088}
89
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070090static inline unsigned int msm_read(struct uart_port *port, unsigned int off)
91{
92 return __raw_readl(port->membase + off);
93}
94
95#ifdef CONFIG_SERIAL_MSM_RX_WAKEUP
96static inline unsigned int use_low_power_wakeup(struct msm_port *msm_port)
97{
98 return (msm_port->wakeup.irq >= 0);
99}
100#endif
101
Robert Love04896a72009-06-22 18:43:11 +0100102static void msm_stop_tx(struct uart_port *port)
103{
104 struct msm_port *msm_port = UART_TO_MSM(port);
105
106 msm_port->imr &= ~UART_IMR_TXLEV;
107 msm_write(port, msm_port->imr, UART_IMR);
108}
109
110static void msm_start_tx(struct uart_port *port)
111{
112 struct msm_port *msm_port = UART_TO_MSM(port);
113
114 msm_port->imr |= UART_IMR_TXLEV;
115 msm_write(port, msm_port->imr, UART_IMR);
116}
117
118static void msm_stop_rx(struct uart_port *port)
119{
120 struct msm_port *msm_port = UART_TO_MSM(port);
121
122 msm_port->imr &= ~(UART_IMR_RXLEV | UART_IMR_RXSTALE);
123 msm_write(port, msm_port->imr, UART_IMR);
124}
125
126static void msm_enable_ms(struct uart_port *port)
127{
128 struct msm_port *msm_port = UART_TO_MSM(port);
129
130 msm_port->imr |= UART_IMR_DELTA_CTS;
131 msm_write(port, msm_port->imr, UART_IMR);
132}
133
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700134#ifdef CONFIG_SERIAL_MSM_CLOCK_CONTROL
135/* turn clock off if TX buffer is empty, otherwise reschedule */
136static enum hrtimer_restart msm_serial_clock_off(struct hrtimer *timer) {
137 struct msm_port *msm_port = container_of(timer, struct msm_port,
138 clk_off_timer);
139 struct uart_port *port = &msm_port->uart;
140 struct circ_buf *xmit = &port->state->xmit;
141 unsigned long flags;
142 int ret = HRTIMER_NORESTART;
143
144 spin_lock_irqsave(&port->lock, flags);
145
146 if (msm_port->clk_state == MSM_CLK_REQUEST_OFF) {
147 if (uart_circ_empty(xmit)) {
148 struct msm_port *msm_port = UART_TO_MSM(port);
149 clk_disable(msm_port->clk);
150 msm_port->clk_state = MSM_CLK_OFF;
151#ifdef CONFIG_SERIAL_MSM_RX_WAKEUP
152 if (use_low_power_wakeup(msm_port)) {
153 msm_port->wakeup.ignore = 1;
154 enable_irq(msm_port->wakeup.irq);
155 }
156#endif
157 } else {
158 hrtimer_forward_now(timer, msm_port->clk_off_delay);
159 ret = HRTIMER_RESTART;
160 }
161 }
162
163 spin_unlock_irqrestore(&port->lock, flags);
164
165 return HRTIMER_NORESTART;
166}
167
168/* request to turn off uart clock once pending TX is flushed */
169void msm_serial_clock_request_off(struct uart_port *port) {
170 unsigned long flags;
Stepan Moskovchenkoec8f29e2010-12-21 12:38:05 -0800171 struct msm_port *msm_port = UART_TO_MSM(port);
172
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700173 spin_lock_irqsave(&port->lock, flags);
174 if (msm_port->clk_state == MSM_CLK_ON) {
175 msm_port->clk_state = MSM_CLK_REQUEST_OFF;
176 /* turn off TX later. unfortunately not all msm uart's have a
177 * TXDONE available, and TXLEV does not wait until completely
178 * flushed, so a timer is our only option
179 */
180 hrtimer_start(&msm_port->clk_off_timer,
181 msm_port->clk_off_delay, HRTIMER_MODE_REL);
Stepan Moskovchenkoec8f29e2010-12-21 12:38:05 -0800182 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700183 spin_unlock_irqrestore(&port->lock, flags);
Stepan Moskovchenkoec8f29e2010-12-21 12:38:05 -0800184}
185
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700186/* request to immediately turn on uart clock.
187 * ignored if there is a pending off request, unless force = 1.
188 */
189void msm_serial_clock_on(struct uart_port *port, int force) {
190 unsigned long flags;
191 struct msm_port *msm_port = UART_TO_MSM(port);
192
193 spin_lock_irqsave(&port->lock, flags);
194
195 switch (msm_port->clk_state) {
196 case MSM_CLK_OFF:
197 clk_enable(msm_port->clk);
198#ifdef CONFIG_SERIAL_MSM_RX_WAKEUP
199 if (use_low_power_wakeup(msm_port))
200 disable_irq(msm_port->wakeup.irq);
201#endif
202 force = 1;
203 case MSM_CLK_REQUEST_OFF:
204 if (force) {
205 hrtimer_try_to_cancel(&msm_port->clk_off_timer);
206 msm_port->clk_state = MSM_CLK_ON;
207 }
208 break;
209 case MSM_CLK_ON: break;
210 case MSM_CLK_PORT_OFF: break;
211 }
212
213 spin_unlock_irqrestore(&port->lock, flags);
214}
215#endif
216
217#ifdef CONFIG_SERIAL_MSM_RX_WAKEUP
218static irqreturn_t msm_rx_irq(int irq, void *dev_id)
219{
Mayank Ranaa44182a2011-09-20 15:49:47 +0530220 unsigned long flags;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700221 struct uart_port *port = dev_id;
222 struct msm_port *msm_port = UART_TO_MSM(port);
223 int inject_wakeup = 0;
224
Mayank Ranaa44182a2011-09-20 15:49:47 +0530225 spin_lock_irqsave(&port->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700226
227 if (msm_port->clk_state == MSM_CLK_OFF) {
228 /* ignore the first irq - it is a pending irq that occured
229 * before enable_irq() */
230 if (msm_port->wakeup.ignore)
231 msm_port->wakeup.ignore = 0;
232 else
233 inject_wakeup = 1;
234 }
235
236 msm_serial_clock_on(port, 0);
237
238 /* we missed an rx while asleep - it must be a wakeup indicator
239 */
240 if (inject_wakeup) {
241 struct tty_struct *tty = port->state->port.tty;
242 tty_insert_flip_char(tty, WAKE_UP_IND, TTY_NORMAL);
243 tty_flip_buffer_push(tty);
244 }
245
Mayank Ranaa44182a2011-09-20 15:49:47 +0530246 spin_unlock_irqrestore(&port->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700247 return IRQ_HANDLED;
248}
249#endif
250
Robert Love04896a72009-06-22 18:43:11 +0100251static void handle_rx(struct uart_port *port)
252{
Alan Coxebd2c8f2009-09-19 13:13:28 -0700253 struct tty_struct *tty = port->state->port.tty;
Robert Love04896a72009-06-22 18:43:11 +0100254 unsigned int sr;
255
256 /*
257 * Handle overrun. My understanding of the hardware is that overrun
258 * is not tied to the RX buffer, so we handle the case out of band.
259 */
260 if ((msm_read(port, UART_SR) & UART_SR_OVERRUN)) {
261 port->icount.overrun++;
262 tty_insert_flip_char(tty, 0, TTY_OVERRUN);
263 msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR);
264 }
265
266 /* and now the main RX loop */
267 while ((sr = msm_read(port, UART_SR)) & UART_SR_RX_READY) {
268 unsigned int c;
269 char flag = TTY_NORMAL;
270
271 c = msm_read(port, UART_RF);
272
273 if (sr & UART_SR_RX_BREAK) {
274 port->icount.brk++;
275 if (uart_handle_break(port))
276 continue;
277 } else if (sr & UART_SR_PAR_FRAME_ERR) {
278 port->icount.frame++;
279 } else {
280 port->icount.rx++;
281 }
282
283 /* Mask conditions we're ignorning. */
284 sr &= port->read_status_mask;
285
286 if (sr & UART_SR_RX_BREAK) {
287 flag = TTY_BREAK;
288 } else if (sr & UART_SR_PAR_FRAME_ERR) {
289 flag = TTY_FRAME;
290 }
291
292 if (!uart_handle_sysrq_char(port, c))
293 tty_insert_flip_char(tty, c, flag);
294 }
295
296 tty_flip_buffer_push(tty);
297}
298
299static void handle_tx(struct uart_port *port)
300{
Alan Coxebd2c8f2009-09-19 13:13:28 -0700301 struct circ_buf *xmit = &port->state->xmit;
Robert Love04896a72009-06-22 18:43:11 +0100302 struct msm_port *msm_port = UART_TO_MSM(port);
303 int sent_tx;
304
305 if (port->x_char) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700306 msm_write(port, port->x_char, UART_TF);
Robert Love04896a72009-06-22 18:43:11 +0100307 port->icount.tx++;
308 port->x_char = 0;
309 }
310
311 while (msm_read(port, UART_SR) & UART_SR_TX_READY) {
312 if (uart_circ_empty(xmit)) {
313 /* disable tx interrupts */
314 msm_port->imr &= ~UART_IMR_TXLEV;
315 msm_write(port, msm_port->imr, UART_IMR);
316 break;
317 }
318
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700319 msm_write(port, xmit->buf[xmit->tail], UART_TF);
Robert Love04896a72009-06-22 18:43:11 +0100320
321 xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
322 port->icount.tx++;
323 sent_tx = 1;
324 }
325
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700326#ifdef CONFIG_SERIAL_MSM_CLOCK_CONTROL
327 if (sent_tx && msm_port->clk_state == MSM_CLK_REQUEST_OFF)
328 /* new TX - restart the timer */
329 if (hrtimer_try_to_cancel(&msm_port->clk_off_timer) == 1)
330 hrtimer_start(&msm_port->clk_off_timer,
331 msm_port->clk_off_delay, HRTIMER_MODE_REL);
332#endif
333
Robert Love04896a72009-06-22 18:43:11 +0100334 if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
335 uart_write_wakeup(port);
336}
337
338static void handle_delta_cts(struct uart_port *port)
339{
340 msm_write(port, UART_CR_CMD_RESET_CTS, UART_CR);
341 port->icount.cts++;
Alan Coxbdc04e32009-09-19 13:13:31 -0700342 wake_up_interruptible(&port->state->port.delta_msr_wait);
Robert Love04896a72009-06-22 18:43:11 +0100343}
344
345static irqreturn_t msm_irq(int irq, void *dev_id)
346{
Mayank Ranaa44182a2011-09-20 15:49:47 +0530347 unsigned long flags;
Robert Love04896a72009-06-22 18:43:11 +0100348 struct uart_port *port = dev_id;
349 struct msm_port *msm_port = UART_TO_MSM(port);
350 unsigned int misr;
351
Mayank Ranaa44182a2011-09-20 15:49:47 +0530352 spin_lock_irqsave(&port->lock, flags);
Robert Love04896a72009-06-22 18:43:11 +0100353 misr = msm_read(port, UART_MISR);
354 msm_write(port, 0, UART_IMR); /* disable interrupt */
355
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700356 if (misr & (UART_IMR_RXLEV | UART_IMR_RXSTALE))
357 handle_rx(port);
Robert Love04896a72009-06-22 18:43:11 +0100358 if (misr & UART_IMR_TXLEV)
359 handle_tx(port);
360 if (misr & UART_IMR_DELTA_CTS)
361 handle_delta_cts(port);
362
363 msm_write(port, msm_port->imr, UART_IMR); /* restore interrupt */
Mayank Ranaa44182a2011-09-20 15:49:47 +0530364 spin_unlock_irqrestore(&port->lock, flags);
Robert Love04896a72009-06-22 18:43:11 +0100365
366 return IRQ_HANDLED;
367}
368
369static unsigned int msm_tx_empty(struct uart_port *port)
370{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700371 unsigned int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700372
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700373 ret = (msm_read(port, UART_SR) & UART_SR_TX_EMPTY) ? TIOCSER_TEMT : 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700374 return ret;
Robert Love04896a72009-06-22 18:43:11 +0100375}
376
377static unsigned int msm_get_mctrl(struct uart_port *port)
378{
379 return TIOCM_CAR | TIOCM_CTS | TIOCM_DSR | TIOCM_RTS;
380}
381
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700382static void msm_set_mctrl(struct uart_port *port, unsigned int mctrl)
Robert Love04896a72009-06-22 18:43:11 +0100383{
384 unsigned int mr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700385
Robert Love04896a72009-06-22 18:43:11 +0100386 mr = msm_read(port, UART_MR1);
387
388 if (!(mctrl & TIOCM_RTS)) {
389 mr &= ~UART_MR1_RX_RDY_CTL;
390 msm_write(port, mr, UART_MR1);
391 msm_write(port, UART_CR_CMD_RESET_RFR, UART_CR);
392 } else {
393 mr |= UART_MR1_RX_RDY_CTL;
394 msm_write(port, mr, UART_MR1);
395 }
396}
397
398static void msm_break_ctl(struct uart_port *port, int break_ctl)
399{
400 if (break_ctl)
401 msm_write(port, UART_CR_CMD_START_BREAK, UART_CR);
402 else
403 msm_write(port, UART_CR_CMD_STOP_BREAK, UART_CR);
404}
405
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700406static void msm_set_baud_rate(struct uart_port *port, unsigned int baud)
Robert Love04896a72009-06-22 18:43:11 +0100407{
408 unsigned int baud_code, rxstale, watermark;
409
410 switch (baud) {
411 case 300:
412 baud_code = UART_CSR_300;
413 rxstale = 1;
414 break;
415 case 600:
416 baud_code = UART_CSR_600;
417 rxstale = 1;
418 break;
419 case 1200:
420 baud_code = UART_CSR_1200;
421 rxstale = 1;
422 break;
423 case 2400:
424 baud_code = UART_CSR_2400;
425 rxstale = 1;
426 break;
427 case 4800:
428 baud_code = UART_CSR_4800;
429 rxstale = 1;
430 break;
431 case 9600:
432 baud_code = UART_CSR_9600;
433 rxstale = 2;
434 break;
435 case 14400:
436 baud_code = UART_CSR_14400;
437 rxstale = 3;
438 break;
439 case 19200:
440 baud_code = UART_CSR_19200;
441 rxstale = 4;
442 break;
443 case 28800:
444 baud_code = UART_CSR_28800;
445 rxstale = 6;
446 break;
447 case 38400:
448 baud_code = UART_CSR_38400;
449 rxstale = 8;
450 break;
451 case 57600:
452 baud_code = UART_CSR_57600;
453 rxstale = 16;
454 break;
455 case 115200:
456 default:
457 baud_code = UART_CSR_115200;
458 rxstale = 31;
459 break;
460 }
461
462 msm_write(port, baud_code, UART_CSR);
463
464 /* RX stale watermark */
465 watermark = UART_IPR_STALE_LSB & rxstale;
466 watermark |= UART_IPR_RXSTALE_LAST;
467 watermark |= UART_IPR_STALE_TIMEOUT_MSB & (rxstale << 2);
468 msm_write(port, watermark, UART_IPR);
469
470 /* set RX watermark */
471 watermark = (port->fifosize * 3) / 4;
472 msm_write(port, watermark, UART_RFWR);
473
474 /* set TX watermark */
475 msm_write(port, 10, UART_TFWR);
476}
477
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700478static void msm_reset(struct uart_port *port)
479{
480 /* reset everything */
481 msm_write(port, UART_CR_CMD_RESET_RX, UART_CR);
482 msm_write(port, UART_CR_CMD_RESET_TX, UART_CR);
483 msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR);
484 msm_write(port, UART_CR_CMD_RESET_BREAK_INT, UART_CR);
485 msm_write(port, UART_CR_CMD_RESET_CTS, UART_CR);
486 msm_write(port, UART_CR_CMD_SET_RFR, UART_CR);
487}
Robert Love04896a72009-06-22 18:43:11 +0100488
489static void msm_init_clock(struct uart_port *port)
490{
Mayank Rana7fa5dc92012-01-27 09:07:59 +0530491 int ret;
Robert Love04896a72009-06-22 18:43:11 +0100492 struct msm_port *msm_port = UART_TO_MSM(port);
493
Mayank Rana7fa5dc92012-01-27 09:07:59 +0530494 ret = clk_prepare_enable(msm_port->clk);
495 if (ret) {
496 pr_err("%s(): Can't enable uartclk. ret:%d\n", __func__, ret);
497 return;
498 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700499
500#ifdef CONFIG_SERIAL_MSM_CLOCK_CONTROL
501 msm_port->clk_state = MSM_CLK_ON;
502#endif
503
Rohit Vaswani41c2dcc2012-06-21 15:20:39 -0700504 if (msm_port->uim) {
505 msm_write(port,
Rohit Vaswanideaabfa2012-08-21 17:37:07 -0700506 UART_SIM_CFG_STOP_BIT_LEN_N(2) |
Rohit Vaswani41c2dcc2012-06-21 15:20:39 -0700507 UART_SIM_CFG_SIM_CLK_ON |
508 UART_SIM_CFG_SIM_CLK_STOP_HIGH |
Rohit Vaswani6ee7f092012-07-25 11:29:52 -0700509 UART_SIM_CFG_MASK_RX |
Rohit Vaswani41c2dcc2012-06-21 15:20:39 -0700510 UART_SIM_CFG_SIM_SEL,
511 UART_SIM_CFG);
512
513 /* (TCXO * 16) / (5 * 372) = TCXO * 16 / 1860 */
514 msm_write(port, 0x08, UART_MREG);
515 msm_write(port, 0x19, UART_NREG);
516 msm_write(port, 0xe8, UART_DREG);
517 msm_write(port, 0x0e, UART_MNDREG);
518 } else if (port->uartclk == 19200000) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700519 /* clock is TCXO (19.2MHz) */
520 msm_write(port, 0x06, UART_MREG);
521 msm_write(port, 0xF1, UART_NREG);
522 msm_write(port, 0x0F, UART_DREG);
523 msm_write(port, 0x1A, UART_MNDREG);
524 } else {
525 /* clock must be TCXO/4 */
526 msm_write(port, 0x18, UART_MREG);
527 msm_write(port, 0xF6, UART_NREG);
528 msm_write(port, 0x0F, UART_DREG);
529 msm_write(port, 0x0A, UART_MNDREG);
530 }
Robert Love04896a72009-06-22 18:43:11 +0100531}
532
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700533static void msm_deinit_clock(struct uart_port *port)
534{
535 struct msm_port *msm_port = UART_TO_MSM(port);
536
537#ifdef CONFIG_SERIAL_MSM_CLOCK_CONTROL
538 if (msm_port->clk_state != MSM_CLK_OFF)
539 clk_disable(msm_port->clk);
540 msm_port->clk_state = MSM_CLK_PORT_OFF;
541#else
Mayank Rana7fa5dc92012-01-27 09:07:59 +0530542 clk_disable_unprepare(msm_port->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700543#endif
544
545}
Robert Love04896a72009-06-22 18:43:11 +0100546static int msm_startup(struct uart_port *port)
547{
548 struct msm_port *msm_port = UART_TO_MSM(port);
549 unsigned int data, rfr_level;
550 int ret;
551
552 snprintf(msm_port->name, sizeof(msm_port->name),
553 "msm_serial%d", port->line);
554
555 ret = request_irq(port->irq, msm_irq, IRQF_TRIGGER_HIGH,
556 msm_port->name, port);
557 if (unlikely(ret))
558 return ret;
559
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700560 if (unlikely(irq_set_irq_wake(port->irq, 1))) {
561 free_irq(port->irq, port);
562 return -ENXIO;
563 }
564
565#ifndef CONFIG_PM_RUNTIME
Robert Love04896a72009-06-22 18:43:11 +0100566 msm_init_clock(port);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700567#endif
568 pm_runtime_get_sync(port->dev);
Robert Love04896a72009-06-22 18:43:11 +0100569
570 if (likely(port->fifosize > 12))
571 rfr_level = port->fifosize - 12;
572 else
573 rfr_level = port->fifosize;
574
575 /* set automatic RFR level */
576 data = msm_read(port, UART_MR1);
577 data &= ~UART_MR1_AUTO_RFR_LEVEL1;
578 data &= ~UART_MR1_AUTO_RFR_LEVEL0;
579 data |= UART_MR1_AUTO_RFR_LEVEL1 & (rfr_level << 2);
580 data |= UART_MR1_AUTO_RFR_LEVEL0 & rfr_level;
581 msm_write(port, data, UART_MR1);
582
583 /* make sure that RXSTALE count is non-zero */
584 data = msm_read(port, UART_IPR);
585 if (unlikely(!data)) {
586 data |= UART_IPR_RXSTALE_LAST;
587 data |= UART_IPR_STALE_LSB;
588 msm_write(port, data, UART_IPR);
589 }
590
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700591 msm_reset(port);
Robert Love04896a72009-06-22 18:43:11 +0100592
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700593 msm_write(port, 0x05, UART_CR); /* enable TX & RX */
Robert Love04896a72009-06-22 18:43:11 +0100594
595 /* turn on RX and CTS interrupts */
596 msm_port->imr = UART_IMR_RXLEV | UART_IMR_RXSTALE |
597 UART_IMR_CURRENT_CTS;
Stepan Moskovchenkoec8f29e2010-12-21 12:38:05 -0800598 msm_write(port, msm_port->imr, UART_IMR);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700599
600#ifdef CONFIG_SERIAL_MSM_RX_WAKEUP
601 if (use_low_power_wakeup(msm_port)) {
602 ret = irq_set_irq_wake(msm_port->wakeup.irq, 1);
603 if (unlikely(ret))
604 return ret;
605 ret = request_irq(msm_port->wakeup.irq, msm_rx_irq,
606 IRQF_TRIGGER_FALLING,
607 "msm_serial_wakeup", msm_port);
608 if (unlikely(ret))
609 return ret;
610 disable_irq(msm_port->wakeup.irq);
611 }
612#endif
613
Robert Love04896a72009-06-22 18:43:11 +0100614 return 0;
615}
616
617static void msm_shutdown(struct uart_port *port)
618{
619 struct msm_port *msm_port = UART_TO_MSM(port);
620
Rohit Vaswani41c2dcc2012-06-21 15:20:39 -0700621 if (msm_port->uim)
622 msm_write(port,
623 UART_SIM_CFG_SIM_CLK_STOP_HIGH,
624 UART_SIM_CFG);
625
Robert Love04896a72009-06-22 18:43:11 +0100626 msm_port->imr = 0;
627 msm_write(port, 0, UART_IMR); /* disable interrupts */
628
Robert Love04896a72009-06-22 18:43:11 +0100629 free_irq(port->irq, port);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700630
631#ifdef CONFIG_SERIAL_MSM_RX_WAKEUP
632 if (use_low_power_wakeup(msm_port)) {
633 irq_set_irq_wake(msm_port->wakeup.irq, 0);
634 free_irq(msm_port->wakeup.irq, msm_port);
635 }
636#endif
637#ifndef CONFIG_PM_RUNTIME
638 msm_deinit_clock(port);
639#endif
640 pm_runtime_put_sync(port->dev);
Robert Love04896a72009-06-22 18:43:11 +0100641}
642
643static void msm_set_termios(struct uart_port *port, struct ktermios *termios,
644 struct ktermios *old)
645{
646 unsigned long flags;
647 unsigned int baud, mr;
648
Mayank Rana216744c2012-05-01 22:43:21 -0700649 if (!termios->c_cflag)
650 return;
651
Robert Love04896a72009-06-22 18:43:11 +0100652 spin_lock_irqsave(&port->lock, flags);
653
654 /* calculate and set baud rate */
655 baud = uart_get_baud_rate(port, termios, old, 300, 115200);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700656 msm_set_baud_rate(port, baud);
Stepan Moskovchenkoec8f29e2010-12-21 12:38:05 -0800657
Robert Love04896a72009-06-22 18:43:11 +0100658 /* calculate parity */
659 mr = msm_read(port, UART_MR2);
660 mr &= ~UART_MR2_PARITY_MODE;
661 if (termios->c_cflag & PARENB) {
662 if (termios->c_cflag & PARODD)
663 mr |= UART_MR2_PARITY_MODE_ODD;
664 else if (termios->c_cflag & CMSPAR)
665 mr |= UART_MR2_PARITY_MODE_SPACE;
666 else
667 mr |= UART_MR2_PARITY_MODE_EVEN;
668 }
669
670 /* calculate bits per char */
671 mr &= ~UART_MR2_BITS_PER_CHAR;
672 switch (termios->c_cflag & CSIZE) {
673 case CS5:
674 mr |= UART_MR2_BITS_PER_CHAR_5;
675 break;
676 case CS6:
677 mr |= UART_MR2_BITS_PER_CHAR_6;
678 break;
679 case CS7:
680 mr |= UART_MR2_BITS_PER_CHAR_7;
681 break;
682 case CS8:
683 default:
684 mr |= UART_MR2_BITS_PER_CHAR_8;
685 break;
686 }
687
688 /* calculate stop bits */
689 mr &= ~(UART_MR2_STOP_BIT_LEN_ONE | UART_MR2_STOP_BIT_LEN_TWO);
690 if (termios->c_cflag & CSTOPB)
691 mr |= UART_MR2_STOP_BIT_LEN_TWO;
692 else
693 mr |= UART_MR2_STOP_BIT_LEN_ONE;
694
695 /* set parity, bits per char, and stop bit */
696 msm_write(port, mr, UART_MR2);
697
698 /* calculate and set hardware flow control */
699 mr = msm_read(port, UART_MR1);
700 mr &= ~(UART_MR1_CTS_CTL | UART_MR1_RX_RDY_CTL);
701 if (termios->c_cflag & CRTSCTS) {
702 mr |= UART_MR1_CTS_CTL;
703 mr |= UART_MR1_RX_RDY_CTL;
704 }
705 msm_write(port, mr, UART_MR1);
706
707 /* Configure status bits to ignore based on termio flags. */
708 port->read_status_mask = 0;
709 if (termios->c_iflag & INPCK)
710 port->read_status_mask |= UART_SR_PAR_FRAME_ERR;
711 if (termios->c_iflag & (BRKINT | PARMRK))
712 port->read_status_mask |= UART_SR_RX_BREAK;
713
714 uart_update_timeout(port, termios->c_cflag, baud);
Robert Love04896a72009-06-22 18:43:11 +0100715 spin_unlock_irqrestore(&port->lock, flags);
716}
717
718static const char *msm_type(struct uart_port *port)
719{
720 return "MSM";
721}
722
723static void msm_release_port(struct uart_port *port)
724{
725 struct platform_device *pdev = to_platform_device(port->dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700726 struct resource *resource;
Robert Love04896a72009-06-22 18:43:11 +0100727 resource_size_t size;
728
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700729 resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
730 if (unlikely(!resource))
Robert Love04896a72009-06-22 18:43:11 +0100731 return;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700732 size = resource->end - resource->start + 1;
Robert Love04896a72009-06-22 18:43:11 +0100733
734 release_mem_region(port->mapbase, size);
735 iounmap(port->membase);
736 port->membase = NULL;
737}
738
739static int msm_request_port(struct uart_port *port)
740{
741 struct platform_device *pdev = to_platform_device(port->dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700742 struct resource *resource;
Robert Love04896a72009-06-22 18:43:11 +0100743 resource_size_t size;
744
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700745 resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
746 if (unlikely(!resource))
Robert Love04896a72009-06-22 18:43:11 +0100747 return -ENXIO;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700748 size = resource->end - resource->start + 1;
Robert Love04896a72009-06-22 18:43:11 +0100749
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700750 if (unlikely(!request_mem_region(port->mapbase, size, "msm_serial")))
Robert Love04896a72009-06-22 18:43:11 +0100751 return -EBUSY;
752
753 port->membase = ioremap(port->mapbase, size);
754 if (!port->membase) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700755 release_mem_region(port->mapbase, size);
756 return -EBUSY;
Robert Love04896a72009-06-22 18:43:11 +0100757 }
758
759 return 0;
760}
761
762static void msm_config_port(struct uart_port *port, int flags)
763{
764 if (flags & UART_CONFIG_TYPE) {
765 port->type = PORT_MSM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700766 msm_request_port(port);
Robert Love04896a72009-06-22 18:43:11 +0100767 }
768}
769
770static int msm_verify_port(struct uart_port *port, struct serial_struct *ser)
771{
772 if (unlikely(ser->type != PORT_UNKNOWN && ser->type != PORT_MSM))
773 return -EINVAL;
774 if (unlikely(port->irq != ser->irq))
775 return -EINVAL;
776 return 0;
777}
778
779static void msm_power(struct uart_port *port, unsigned int state,
780 unsigned int oldstate)
781{
Mayank Rana7fa5dc92012-01-27 09:07:59 +0530782 int ret;
Robert Love04896a72009-06-22 18:43:11 +0100783 struct msm_port *msm_port = UART_TO_MSM(port);
784
785 switch (state) {
786 case 0:
Mayank Rana7fa5dc92012-01-27 09:07:59 +0530787 ret = clk_prepare_enable(msm_port->clk);
788 if (ret)
789 pr_err("msm_serial: %s(): Can't enable uartclk.\n",
790 __func__);
Robert Love04896a72009-06-22 18:43:11 +0100791 break;
792 case 3:
Mayank Rana7fa5dc92012-01-27 09:07:59 +0530793 clk_disable_unprepare(msm_port->clk);
Robert Love04896a72009-06-22 18:43:11 +0100794 break;
795 default:
Mayank Rana04570ab2012-01-24 09:58:32 +0530796 pr_err("msm_serial: %s(): Unknown PM state %d\n",
797 __func__, state);
Robert Love04896a72009-06-22 18:43:11 +0100798 }
799}
800
801static struct uart_ops msm_uart_pops = {
802 .tx_empty = msm_tx_empty,
803 .set_mctrl = msm_set_mctrl,
804 .get_mctrl = msm_get_mctrl,
805 .stop_tx = msm_stop_tx,
806 .start_tx = msm_start_tx,
807 .stop_rx = msm_stop_rx,
808 .enable_ms = msm_enable_ms,
809 .break_ctl = msm_break_ctl,
810 .startup = msm_startup,
811 .shutdown = msm_shutdown,
812 .set_termios = msm_set_termios,
813 .type = msm_type,
814 .release_port = msm_release_port,
815 .request_port = msm_request_port,
816 .config_port = msm_config_port,
817 .verify_port = msm_verify_port,
818 .pm = msm_power,
819};
820
821static struct msm_port msm_uart_ports[] = {
822 {
823 .uart = {
824 .iotype = UPIO_MEM,
825 .ops = &msm_uart_pops,
826 .flags = UPF_BOOT_AUTOCONF,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700827 .fifosize = 512,
Robert Love04896a72009-06-22 18:43:11 +0100828 .line = 0,
829 },
830 },
831 {
832 .uart = {
833 .iotype = UPIO_MEM,
834 .ops = &msm_uart_pops,
835 .flags = UPF_BOOT_AUTOCONF,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700836 .fifosize = 512,
Robert Love04896a72009-06-22 18:43:11 +0100837 .line = 1,
838 },
839 },
840 {
841 .uart = {
842 .iotype = UPIO_MEM,
843 .ops = &msm_uart_pops,
844 .flags = UPF_BOOT_AUTOCONF,
845 .fifosize = 64,
846 .line = 2,
847 },
848 },
849};
850
851#define UART_NR ARRAY_SIZE(msm_uart_ports)
852
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700853static inline struct uart_port * get_port_from_line(unsigned int line)
Robert Love04896a72009-06-22 18:43:11 +0100854{
855 return &msm_uart_ports[line].uart;
856}
857
858#ifdef CONFIG_SERIAL_MSM_CONSOLE
859
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700860/*
861 * Wait for transmitter & holding register to empty
862 * Derived from wait_for_xmitr in 8250 serial driver by Russell King
863 */
864static inline void wait_for_xmitr(struct uart_port *port, int bits)
865{
866 unsigned int status, mr, tmout = 10000;
867
868 /* Wait up to 10ms for the character(s) to be sent. */
869 do {
870 status = msm_read(port, UART_SR);
871
872 if (--tmout == 0)
873 break;
874 udelay(1);
875 } while ((status & bits) != bits);
876
877 mr = msm_read(port, UART_MR1);
878
879 /* Wait up to 1s for flow control if necessary */
880 if (mr & UART_MR1_CTS_CTL) {
881 unsigned int tmout;
882 for (tmout = 1000000; tmout; tmout--) {
883 unsigned int isr = msm_read(port, UART_ISR);
884
885 /* CTS input is active lo */
886 if (!(isr & UART_IMR_CURRENT_CTS))
887 break;
888 udelay(1);
889 touch_nmi_watchdog();
890 }
891 }
892}
893
894
Robert Love04896a72009-06-22 18:43:11 +0100895static void msm_console_putchar(struct uart_port *port, int c)
896{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700897 /* This call can incur significant delay if CTS flowcontrol is enabled
898 * on port and no serial cable is attached.
899 */
900 wait_for_xmitr(port, UART_SR_TX_READY);
Stepan Moskovchenkoec8f29e2010-12-21 12:38:05 -0800901
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700902 msm_write(port, c, UART_TF);
Robert Love04896a72009-06-22 18:43:11 +0100903}
904
905static void msm_console_write(struct console *co, const char *s,
906 unsigned int count)
907{
908 struct uart_port *port;
909 struct msm_port *msm_port;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700910 int locked;
Robert Love04896a72009-06-22 18:43:11 +0100911
912 BUG_ON(co->index < 0 || co->index >= UART_NR);
913
914 port = get_port_from_line(co->index);
915 msm_port = UART_TO_MSM(port);
916
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700917 /* not pretty, but we can end up here via various convoluted paths */
918 if (port->sysrq || oops_in_progress)
919 locked = spin_trylock(&port->lock);
920 else {
921 locked = 1;
922 spin_lock(&port->lock);
923 }
924
Robert Love04896a72009-06-22 18:43:11 +0100925 uart_console_write(port, s, count, msm_console_putchar);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700926
927 if (locked)
928 spin_unlock(&port->lock);
Robert Love04896a72009-06-22 18:43:11 +0100929}
930
931static int __init msm_console_setup(struct console *co, char *options)
932{
933 struct uart_port *port;
Mayank Ranacf41e612011-09-28 14:49:08 +0530934 int baud = 0, flow, bits, parity;
Robert Love04896a72009-06-22 18:43:11 +0100935
936 if (unlikely(co->index >= UART_NR || co->index < 0))
937 return -ENXIO;
938
939 port = get_port_from_line(co->index);
940
941 if (unlikely(!port->membase))
942 return -ENXIO;
943
944 port->cons = co;
945
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700946 pm_runtime_get_noresume(port->dev);
947
948#ifndef CONFIG_PM_RUNTIME
Robert Love04896a72009-06-22 18:43:11 +0100949 msm_init_clock(port);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700950#endif
951 pm_runtime_resume(port->dev);
Robert Love04896a72009-06-22 18:43:11 +0100952
953 if (options)
954 uart_parse_options(options, &baud, &parity, &bits, &flow);
955
956 bits = 8;
957 parity = 'n';
958 flow = 'n';
959 msm_write(port, UART_MR2_BITS_PER_CHAR_8 | UART_MR2_STOP_BIT_LEN_ONE,
960 UART_MR2); /* 8N1 */
961
962 if (baud < 300 || baud > 115200)
963 baud = 115200;
964 msm_set_baud_rate(port, baud);
965
966 msm_reset(port);
967
968 printk(KERN_INFO "msm_serial: console setup on port #%d\n", port->line);
969
970 return uart_set_options(port, co, baud, parity, bits, flow);
971}
972
973static struct uart_driver msm_uart_driver;
974
975static struct console msm_console = {
976 .name = "ttyMSM",
977 .write = msm_console_write,
978 .device = uart_console_device,
979 .setup = msm_console_setup,
980 .flags = CON_PRINTBUFFER,
981 .index = -1,
982 .data = &msm_uart_driver,
983};
984
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700985#define MSM_CONSOLE &msm_console
Robert Love04896a72009-06-22 18:43:11 +0100986
987#else
988#define MSM_CONSOLE NULL
989#endif
990
991static struct uart_driver msm_uart_driver = {
992 .owner = THIS_MODULE,
993 .driver_name = "msm_serial",
994 .dev_name = "ttyMSM",
995 .nr = UART_NR,
996 .cons = MSM_CONSOLE,
997};
998
999static int __init msm_serial_probe(struct platform_device *pdev)
1000{
1001 struct msm_port *msm_port;
1002 struct resource *resource;
1003 struct uart_port *port;
Roel Kluin1e091752009-12-21 16:26:49 -08001004 int irq;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001005#ifdef CONFIG_SERIAL_MSM_RX_WAKEUP
1006 struct msm_serial_platform_data *pdata = pdev->dev.platform_data;
1007#endif
Robert Love04896a72009-06-22 18:43:11 +01001008
1009 if (unlikely(pdev->id < 0 || pdev->id >= UART_NR))
1010 return -ENXIO;
1011
1012 printk(KERN_INFO "msm_serial: detected port #%d\n", pdev->id);
1013
1014 port = get_port_from_line(pdev->id);
1015 port->dev = &pdev->dev;
1016 msm_port = UART_TO_MSM(port);
1017
Matt Wagantalle2522372011-08-17 14:52:21 -07001018 msm_port->clk = clk_get(&pdev->dev, "core_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001019 if (unlikely(IS_ERR(msm_port->clk)))
1020 return PTR_ERR(msm_port->clk);
Robert Love04896a72009-06-22 18:43:11 +01001021 port->uartclk = clk_get_rate(msm_port->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001022 if (!port->uartclk)
1023 port->uartclk = 19200000;
Abhijeet Dharmapurikar18c79d72010-05-20 15:20:23 -07001024
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001025 resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Robert Love04896a72009-06-22 18:43:11 +01001026 if (unlikely(!resource))
1027 return -ENXIO;
1028 port->mapbase = resource->start;
1029
Roel Kluin1e091752009-12-21 16:26:49 -08001030 irq = platform_get_irq(pdev, 0);
1031 if (unlikely(irq < 0))
Robert Love04896a72009-06-22 18:43:11 +01001032 return -ENXIO;
Roel Kluin1e091752009-12-21 16:26:49 -08001033 port->irq = irq;
Robert Love04896a72009-06-22 18:43:11 +01001034
1035 platform_set_drvdata(pdev, port);
1036
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001037
1038#ifdef CONFIG_SERIAL_MSM_RX_WAKEUP
1039 if (pdata == NULL)
1040 msm_port->wakeup.irq = -1;
1041 else {
1042 msm_port->wakeup.irq = pdata->wakeup_irq;
1043 msm_port->wakeup.ignore = 1;
1044 msm_port->wakeup.inject_rx = pdata->inject_rx_on_wakeup;
1045 msm_port->wakeup.rx_to_inject = pdata->rx_to_inject;
1046
1047 if (unlikely(msm_port->wakeup.irq <= 0))
1048 return -EINVAL;
1049 }
1050#endif
1051
1052#ifdef CONFIG_SERIAL_MSM_CLOCK_CONTROL
1053 msm_port->clk_state = MSM_CLK_PORT_OFF;
1054 hrtimer_init(&msm_port->clk_off_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
1055 msm_port->clk_off_timer.function = msm_serial_clock_off;
1056 msm_port->clk_off_delay = ktime_set(0, 1000000); /* 1 ms */
1057#endif
1058
1059 pm_runtime_enable(port->dev);
Robert Love04896a72009-06-22 18:43:11 +01001060 return uart_add_one_port(&msm_uart_driver, port);
1061}
1062
Rohit Vaswani41c2dcc2012-06-21 15:20:39 -07001063static int __init msm_uim_probe(struct platform_device *pdev)
1064{
1065 struct msm_port *msm_port;
1066 struct resource *resource;
1067 struct uart_port *port;
1068 int irq;
1069
1070 if (unlikely(pdev->id < 0 || pdev->id >= UART_NR))
1071 return -ENXIO;
1072
1073 pr_info("msm_uim: detected port #%d\n", pdev->id);
1074
1075 port = get_port_from_line(pdev->id);
1076 port->dev = &pdev->dev;
1077 msm_port = UART_TO_MSM(port);
1078
1079 msm_port->uim = true;
1080
1081 resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1082 if (unlikely(!resource))
1083 return -ENXIO;
1084 port->mapbase = resource->start;
1085
1086 irq = platform_get_irq(pdev, 0);
1087 if (unlikely(irq < 0))
1088 return -ENXIO;
1089 port->irq = irq;
1090
1091 platform_set_drvdata(pdev, port);
1092
1093 return uart_add_one_port(&msm_uart_driver, port);
1094}
1095
Robert Love04896a72009-06-22 18:43:11 +01001096static int __devexit msm_serial_remove(struct platform_device *pdev)
1097{
1098 struct msm_port *msm_port = platform_get_drvdata(pdev);
1099
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001100 pm_runtime_put_sync(&pdev->dev);
1101 pm_runtime_disable(&pdev->dev);
1102
Robert Love04896a72009-06-22 18:43:11 +01001103 clk_put(msm_port->clk);
1104
1105 return 0;
1106}
1107
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001108#ifdef CONFIG_PM
1109static int msm_serial_suspend(struct device *dev)
1110{
1111 struct uart_port *port;
1112 struct platform_device *pdev = to_platform_device(dev);
1113 port = get_port_from_line(pdev->id);
1114
1115 if (port) {
1116 uart_suspend_port(&msm_uart_driver, port);
1117 if (is_console(port))
1118 msm_deinit_clock(port);
1119 }
1120
1121 return 0;
1122}
1123
1124static int msm_serial_resume(struct device *dev)
1125{
1126 struct uart_port *port;
1127 struct platform_device *pdev = to_platform_device(dev);
1128 port = get_port_from_line(pdev->id);
1129
1130 if (port) {
1131 if (is_console(port))
1132 msm_init_clock(port);
1133 uart_resume_port(&msm_uart_driver, port);
1134 }
1135
1136 return 0;
1137}
1138#else
1139#define msm_serial_suspend NULL
1140#define msm_serial_resume NULL
1141#endif
1142
1143static int msm_serial_runtime_suspend(struct device *dev)
1144{
1145 struct platform_device *pdev = to_platform_device(dev);
1146 struct uart_port *port;
1147 port = get_port_from_line(pdev->id);
1148
1149 dev_dbg(dev, "pm_runtime: suspending\n");
1150 msm_deinit_clock(port);
1151 return 0;
1152}
1153
1154static int msm_serial_runtime_resume(struct device *dev)
1155{
1156 struct platform_device *pdev = to_platform_device(dev);
1157 struct uart_port *port;
1158 port = get_port_from_line(pdev->id);
1159
1160 dev_dbg(dev, "pm_runtime: resuming\n");
1161 msm_init_clock(port);
1162 return 0;
1163}
1164
1165static struct dev_pm_ops msm_serial_dev_pm_ops = {
1166 .suspend = msm_serial_suspend,
1167 .resume = msm_serial_resume,
1168 .runtime_suspend = msm_serial_runtime_suspend,
1169 .runtime_resume = msm_serial_runtime_resume,
1170};
1171
Robert Love04896a72009-06-22 18:43:11 +01001172static struct platform_driver msm_platform_driver = {
Robert Love04896a72009-06-22 18:43:11 +01001173 .remove = msm_serial_remove,
1174 .driver = {
1175 .name = "msm_serial",
1176 .owner = THIS_MODULE,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001177 .pm = &msm_serial_dev_pm_ops,
Robert Love04896a72009-06-22 18:43:11 +01001178 },
1179};
1180
Rohit Vaswani41c2dcc2012-06-21 15:20:39 -07001181static struct platform_driver msm_platform_uim_driver = {
1182 .remove = msm_serial_remove,
1183 .driver = {
1184 .name = "msm_uim",
1185 .owner = THIS_MODULE,
1186 },
1187};
1188
Robert Love04896a72009-06-22 18:43:11 +01001189static int __init msm_serial_init(void)
1190{
1191 int ret;
1192
1193 ret = uart_register_driver(&msm_uart_driver);
1194 if (unlikely(ret))
1195 return ret;
1196
1197 ret = platform_driver_probe(&msm_platform_driver, msm_serial_probe);
1198 if (unlikely(ret))
1199 uart_unregister_driver(&msm_uart_driver);
1200
Rohit Vaswani41c2dcc2012-06-21 15:20:39 -07001201 platform_driver_probe(&msm_platform_uim_driver, msm_uim_probe);
1202
Robert Love04896a72009-06-22 18:43:11 +01001203 printk(KERN_INFO "msm_serial: driver initialized\n");
1204
1205 return ret;
1206}
1207
1208static void __exit msm_serial_exit(void)
1209{
1210#ifdef CONFIG_SERIAL_MSM_CONSOLE
1211 unregister_console(&msm_console);
1212#endif
1213 platform_driver_unregister(&msm_platform_driver);
1214 uart_unregister_driver(&msm_uart_driver);
1215}
1216
1217module_init(msm_serial_init);
1218module_exit(msm_serial_exit);
1219
1220MODULE_AUTHOR("Robert Love <rlove@google.com>");
1221MODULE_DESCRIPTION("Driver for msm7x serial device");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001222MODULE_LICENSE("GPL v2");