blob: 987008dfb04d828395c6011c60e51c22d2db82d2 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/*
2 * drivers/serial/msm_serial.c - driver for msm7k serial device and console
3 *
4 * Copyright (C) 2007 Google, Inc.
Mayank Rana22e4b382012-01-11 21:35:00 +05305 * Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006 *
7 * This software is licensed under the terms of the GNU General Public
8 * License version 2, as published by the Free Software Foundation, and
9 * may be copied, distributed, and modified under those terms.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16
17/* Acknowledgements:
18 * This file is based on msm_serial.c, originally
19 * Written by Robert Love <rlove@google.com> */
20
21#if defined(CONFIG_SERIAL_MSM_HSL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
22#define SUPPORT_SYSRQ
23#endif
24
Sathish Ambley3d50c762011-10-25 15:26:00 -070025#include <linux/atomic.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070026#include <linux/hrtimer.h>
27#include <linux/module.h>
28#include <linux/io.h>
29#include <linux/ioport.h>
30#include <linux/irq.h>
31#include <linux/init.h>
32#include <linux/delay.h>
33#include <linux/console.h>
34#include <linux/tty.h>
35#include <linux/tty_flip.h>
36#include <linux/serial_core.h>
37#include <linux/serial.h>
38#include <linux/nmi.h>
39#include <linux/clk.h>
40#include <linux/platform_device.h>
41#include <linux/pm_runtime.h>
42#include <linux/gpio.h>
Mayank Rana8dddd752011-07-13 11:19:58 +053043#include <linux/debugfs.h>
Sathish Ambley3d50c762011-10-25 15:26:00 -070044#include <linux/of.h>
45#include <linux/of_device.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070046#include <mach/board.h>
47#include <mach/msm_serial_hs_lite.h>
48#include <asm/mach-types.h>
49#include "msm_serial_hs_hwreg.h"
50
51struct msm_hsl_port {
52 struct uart_port uart;
53 char name[16];
54 struct clk *clk;
55 struct clk *pclk;
Mayank Rana8dddd752011-07-13 11:19:58 +053056 struct dentry *loopback_dir;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070057 unsigned int imr;
58 unsigned int *uart_csr_code;
59 unsigned int *gsbi_mapbase;
60 unsigned int *mapped_gsbi;
61 int is_uartdm;
62 unsigned int old_snap_state;
Sathish Ambley99e2a242011-10-25 15:49:53 -070063 unsigned int ver_id;
Stepan Moskovchenko1d4731e2012-02-21 20:18:23 -080064 int tx_timeout;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070065};
66
Sathish Ambley99e2a242011-10-25 15:49:53 -070067#define UARTDM_VERSION_11_13 0
68#define UARTDM_VERSION_14 1
69
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070070#define UART_TO_MSM(uart_port) ((struct msm_hsl_port *) uart_port)
71#define is_console(port) ((port)->cons && \
72 (port)->cons->index == (port)->line)
Sathish Ambley99e2a242011-10-25 15:49:53 -070073
74static const unsigned int regmap[][UARTDM_LAST] = {
75 [UARTDM_VERSION_11_13] = {
76 [UARTDM_MR1] = UARTDM_MR1_ADDR,
77 [UARTDM_MR2] = UARTDM_MR2_ADDR,
78 [UARTDM_IMR] = UARTDM_IMR_ADDR,
79 [UARTDM_SR] = UARTDM_SR_ADDR,
80 [UARTDM_CR] = UARTDM_CR_ADDR,
81 [UARTDM_CSR] = UARTDM_CSR_ADDR,
82 [UARTDM_IPR] = UARTDM_IPR_ADDR,
83 [UARTDM_ISR] = UARTDM_ISR_ADDR,
84 [UARTDM_RX_TOTAL_SNAP] = UARTDM_RX_TOTAL_SNAP_ADDR,
85 [UARTDM_TFWR] = UARTDM_TFWR_ADDR,
86 [UARTDM_RFWR] = UARTDM_RFWR_ADDR,
87 [UARTDM_RF] = UARTDM_RF_ADDR,
88 [UARTDM_TF] = UARTDM_TF_ADDR,
89 [UARTDM_MISR] = UARTDM_MISR_ADDR,
90 [UARTDM_DMRX] = UARTDM_DMRX_ADDR,
91 [UARTDM_NCF_TX] = UARTDM_NCF_TX_ADDR,
92 [UARTDM_DMEN] = UARTDM_DMEN_ADDR,
Stepan Moskovchenko1d4731e2012-02-21 20:18:23 -080093 [UARTDM_TXFS] = UARTDM_TXFS_ADDR,
94 [UARTDM_RXFS] = UARTDM_RXFS_ADDR,
Sathish Ambley99e2a242011-10-25 15:49:53 -070095 },
96 [UARTDM_VERSION_14] = {
97 [UARTDM_MR1] = 0x0,
98 [UARTDM_MR2] = 0x4,
99 [UARTDM_IMR] = 0xb0,
100 [UARTDM_SR] = 0xa4,
101 [UARTDM_CR] = 0xa8,
102 [UARTDM_CSR] = 0xa0,
103 [UARTDM_IPR] = 0x18,
104 [UARTDM_ISR] = 0xb4,
105 [UARTDM_RX_TOTAL_SNAP] = 0xbc,
106 [UARTDM_TFWR] = 0x1c,
107 [UARTDM_RFWR] = 0x20,
108 [UARTDM_RF] = 0x140,
109 [UARTDM_TF] = 0x100,
110 [UARTDM_MISR] = 0xac,
111 [UARTDM_DMRX] = 0x34,
112 [UARTDM_NCF_TX] = 0x40,
113 [UARTDM_DMEN] = 0x3c,
Stepan Moskovchenko1d4731e2012-02-21 20:18:23 -0800114 [UARTDM_TXFS] = 0x4c,
115 [UARTDM_RXFS] = 0x50,
Sathish Ambley99e2a242011-10-25 15:49:53 -0700116 },
117};
118
Sathish Ambley3d50c762011-10-25 15:26:00 -0700119static struct of_device_id msm_hsl_match_table[] = {
Sathish Ambley99e2a242011-10-25 15:49:53 -0700120 { .compatible = "qcom,msm-lsuart-v14",
121 .data = (void *)UARTDM_VERSION_14
122 },
Sathish Ambley3d50c762011-10-25 15:26:00 -0700123 {}
124};
Stepan Moskovchenko51fc4e62012-06-19 17:04:21 -0700125
126#ifdef CONFIG_SERIAL_MSM_HSL_CONSOLE
127static int get_console_state(struct uart_port *port);
128#else
129static inline int get_console_state(struct uart_port *port) { return -ENODEV; };
130#endif
131
Mayank Rana8dddd752011-07-13 11:19:58 +0530132static struct dentry *debug_base;
Stepan Moskovchenko9ec24842012-05-15 13:58:58 -0700133static inline void wait_for_xmitr(struct uart_port *port);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700134static inline void msm_hsl_write(struct uart_port *port,
135 unsigned int val, unsigned int off)
136{
137 iowrite32(val, port->membase + off);
138}
139static inline unsigned int msm_hsl_read(struct uart_port *port,
140 unsigned int off)
141{
142 return ioread32(port->membase + off);
143}
144
145static unsigned int msm_serial_hsl_has_gsbi(struct uart_port *port)
146{
147 return UART_TO_MSM(port)->is_uartdm;
148}
149
Stepan Moskovchenko798fe552012-03-29 19:47:19 -0700150static int get_line(struct platform_device *pdev)
151{
152 const struct msm_serial_hslite_platform_data *pdata =
153 pdev->dev.platform_data;
154 if (pdata)
155 return pdata->line;
156
157 return pdev->id;
158}
159
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700160static int clk_en(struct uart_port *port, int enable)
161{
162 struct msm_hsl_port *msm_hsl_port = UART_TO_MSM(port);
163 int ret = 0;
164
165 if (enable) {
166
Mayank Rana5d0252a2012-01-24 13:58:43 +0530167 ret = clk_prepare_enable(msm_hsl_port->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700168 if (ret)
169 goto err;
170 if (msm_hsl_port->pclk) {
Mayank Rana5d0252a2012-01-24 13:58:43 +0530171 ret = clk_prepare_enable(msm_hsl_port->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700172 if (ret) {
Mayank Rana5d0252a2012-01-24 13:58:43 +0530173 clk_disable_unprepare(msm_hsl_port->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700174 goto err;
175 }
176 }
177 } else {
Mayank Rana5d0252a2012-01-24 13:58:43 +0530178
179 clk_disable_unprepare(msm_hsl_port->clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700180 if (msm_hsl_port->pclk)
Mayank Rana5d0252a2012-01-24 13:58:43 +0530181 clk_disable_unprepare(msm_hsl_port->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700182 }
183err:
184 return ret;
185}
Mayank Rana8dddd752011-07-13 11:19:58 +0530186static int msm_hsl_loopback_enable_set(void *data, u64 val)
187{
188 struct msm_hsl_port *msm_hsl_port = data;
189 struct uart_port *port = &(msm_hsl_port->uart);
Sathish Ambley99e2a242011-10-25 15:49:53 -0700190 unsigned int vid;
Mayank Rana8dddd752011-07-13 11:19:58 +0530191 unsigned long flags;
192 int ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700193
Mayank Rana9825dc62011-07-26 10:47:46 +0530194 ret = clk_set_rate(msm_hsl_port->clk, 7372800);
Mayank Rana8dddd752011-07-13 11:19:58 +0530195 if (!ret)
196 clk_en(port, 1);
197 else {
198 pr_err("%s(): Error: Setting the clock rate\n", __func__);
199 return -EINVAL;
200 }
201
Sathish Ambley99e2a242011-10-25 15:49:53 -0700202 vid = msm_hsl_port->ver_id;
Mayank Rana8dddd752011-07-13 11:19:58 +0530203 if (val) {
204 spin_lock_irqsave(&port->lock, flags);
Sathish Ambley99e2a242011-10-25 15:49:53 -0700205 ret = msm_hsl_read(port, regmap[vid][UARTDM_MR2]);
Mayank Rana8dddd752011-07-13 11:19:58 +0530206 ret |= UARTDM_MR2_LOOP_MODE_BMSK;
Sathish Ambley99e2a242011-10-25 15:49:53 -0700207 msm_hsl_write(port, ret, regmap[vid][UARTDM_MR2]);
Mayank Rana8dddd752011-07-13 11:19:58 +0530208 spin_unlock_irqrestore(&port->lock, flags);
209 } else {
210 spin_lock_irqsave(&port->lock, flags);
Sathish Ambley99e2a242011-10-25 15:49:53 -0700211 ret = msm_hsl_read(port, regmap[vid][UARTDM_MR2]);
Mayank Rana8dddd752011-07-13 11:19:58 +0530212 ret &= ~UARTDM_MR2_LOOP_MODE_BMSK;
Sathish Ambley99e2a242011-10-25 15:49:53 -0700213 msm_hsl_write(port, ret, regmap[vid][UARTDM_MR2]);
Mayank Rana8dddd752011-07-13 11:19:58 +0530214 spin_unlock_irqrestore(&port->lock, flags);
215 }
216
217 clk_en(port, 0);
218 return 0;
219}
220static int msm_hsl_loopback_enable_get(void *data, u64 *val)
221{
222 struct msm_hsl_port *msm_hsl_port = data;
223 struct uart_port *port = &(msm_hsl_port->uart);
224 unsigned long flags;
225 int ret = 0;
226
Mayank Rana9825dc62011-07-26 10:47:46 +0530227 ret = clk_set_rate(msm_hsl_port->clk, 7372800);
Mayank Rana8dddd752011-07-13 11:19:58 +0530228 if (!ret)
229 clk_en(port, 1);
230 else {
231 pr_err("%s(): Error setting clk rate\n", __func__);
232 return -EINVAL;
233 }
234
235 spin_lock_irqsave(&port->lock, flags);
Sathish Ambley99e2a242011-10-25 15:49:53 -0700236 ret = msm_hsl_read(port, regmap[msm_hsl_port->ver_id][UARTDM_MR2]);
Mayank Rana8dddd752011-07-13 11:19:58 +0530237 spin_unlock_irqrestore(&port->lock, flags);
238 clk_en(port, 0);
239
240 *val = (ret & UARTDM_MR2_LOOP_MODE_BMSK) ? 1 : 0;
241 return 0;
242}
243DEFINE_SIMPLE_ATTRIBUTE(loopback_enable_fops, msm_hsl_loopback_enable_get,
244 msm_hsl_loopback_enable_set, "%llu\n");
245/*
246 * msm_serial_hsl debugfs node: <debugfs_root>/msm_serial_hsl/loopback.<id>
247 * writing 1 turns on internal loopback mode in HW. Useful for automation
248 * test scripts.
249 * writing 0 disables the internal loopback mode. Default is disabled.
250 */
251static void msm_hsl_debugfs_init(struct msm_hsl_port *msm_uport,
252 int id)
253{
254 char node_name[15];
255
256 snprintf(node_name, sizeof(node_name), "loopback.%d", id);
257 msm_uport->loopback_dir = debugfs_create_file(node_name,
258 S_IRUGO | S_IWUSR,
259 debug_base,
260 msm_uport,
261 &loopback_enable_fops);
262
263 if (IS_ERR_OR_NULL(msm_uport->loopback_dir))
264 pr_err("%s(): Cannot create loopback.%d debug entry",
265 __func__, id);
266}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700267static void msm_hsl_stop_tx(struct uart_port *port)
268{
269 struct msm_hsl_port *msm_hsl_port = UART_TO_MSM(port);
270
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700271 msm_hsl_port->imr &= ~UARTDM_ISR_TXLEV_BMSK;
Sathish Ambley99e2a242011-10-25 15:49:53 -0700272 msm_hsl_write(port, msm_hsl_port->imr,
273 regmap[msm_hsl_port->ver_id][UARTDM_IMR]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700274}
275
276static void msm_hsl_start_tx(struct uart_port *port)
277{
278 struct msm_hsl_port *msm_hsl_port = UART_TO_MSM(port);
279
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700280 msm_hsl_port->imr |= UARTDM_ISR_TXLEV_BMSK;
Sathish Ambley99e2a242011-10-25 15:49:53 -0700281 msm_hsl_write(port, msm_hsl_port->imr,
282 regmap[msm_hsl_port->ver_id][UARTDM_IMR]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700283}
284
285static void msm_hsl_stop_rx(struct uart_port *port)
286{
287 struct msm_hsl_port *msm_hsl_port = UART_TO_MSM(port);
288
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700289 msm_hsl_port->imr &= ~(UARTDM_ISR_RXLEV_BMSK |
290 UARTDM_ISR_RXSTALE_BMSK);
Sathish Ambley99e2a242011-10-25 15:49:53 -0700291 msm_hsl_write(port, msm_hsl_port->imr,
292 regmap[msm_hsl_port->ver_id][UARTDM_IMR]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700293}
294
295static void msm_hsl_enable_ms(struct uart_port *port)
296{
297 struct msm_hsl_port *msm_hsl_port = UART_TO_MSM(port);
298
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700299 msm_hsl_port->imr |= UARTDM_ISR_DELTA_CTS_BMSK;
Sathish Ambley99e2a242011-10-25 15:49:53 -0700300 msm_hsl_write(port, msm_hsl_port->imr,
301 regmap[msm_hsl_port->ver_id][UARTDM_IMR]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700302}
303
304static void handle_rx(struct uart_port *port, unsigned int misr)
305{
306 struct tty_struct *tty = port->state->port.tty;
Sathish Ambley99e2a242011-10-25 15:49:53 -0700307 unsigned int vid;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700308 unsigned int sr;
309 int count = 0;
310 struct msm_hsl_port *msm_hsl_port = UART_TO_MSM(port);
311
Sathish Ambley99e2a242011-10-25 15:49:53 -0700312 vid = msm_hsl_port->ver_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700313 /*
314 * Handle overrun. My understanding of the hardware is that overrun
315 * is not tied to the RX buffer, so we handle the case out of band.
316 */
Sathish Ambley99e2a242011-10-25 15:49:53 -0700317 if ((msm_hsl_read(port, regmap[vid][UARTDM_SR]) &
318 UARTDM_SR_OVERRUN_BMSK)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700319 port->icount.overrun++;
320 tty_insert_flip_char(tty, 0, TTY_OVERRUN);
Sathish Ambley99e2a242011-10-25 15:49:53 -0700321 msm_hsl_write(port, RESET_ERROR_STATUS,
322 regmap[vid][UARTDM_CR]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700323 }
324
325 if (misr & UARTDM_ISR_RXSTALE_BMSK) {
Sathish Ambley99e2a242011-10-25 15:49:53 -0700326 count = msm_hsl_read(port,
327 regmap[vid][UARTDM_RX_TOTAL_SNAP]) -
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700328 msm_hsl_port->old_snap_state;
329 msm_hsl_port->old_snap_state = 0;
330 } else {
Sathish Ambley99e2a242011-10-25 15:49:53 -0700331 count = 4 * (msm_hsl_read(port, regmap[vid][UARTDM_RFWR]));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700332 msm_hsl_port->old_snap_state += count;
333 }
334
335 /* and now the main RX loop */
336 while (count > 0) {
337 unsigned int c;
338 char flag = TTY_NORMAL;
339
Sathish Ambley99e2a242011-10-25 15:49:53 -0700340 sr = msm_hsl_read(port, regmap[vid][UARTDM_SR]);
341 if ((sr & UARTDM_SR_RXRDY_BMSK) == 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700342 msm_hsl_port->old_snap_state -= count;
343 break;
344 }
Sathish Ambley99e2a242011-10-25 15:49:53 -0700345 c = msm_hsl_read(port, regmap[vid][UARTDM_RF]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700346 if (sr & UARTDM_SR_RX_BREAK_BMSK) {
347 port->icount.brk++;
348 if (uart_handle_break(port))
349 continue;
350 } else if (sr & UARTDM_SR_PAR_FRAME_BMSK) {
351 port->icount.frame++;
352 } else {
353 port->icount.rx++;
354 }
355
356 /* Mask conditions we're ignorning. */
357 sr &= port->read_status_mask;
358 if (sr & UARTDM_SR_RX_BREAK_BMSK)
359 flag = TTY_BREAK;
360 else if (sr & UARTDM_SR_PAR_FRAME_BMSK)
361 flag = TTY_FRAME;
362
363 /* TODO: handle sysrq */
364 /* if (!uart_handle_sysrq_char(port, c)) */
365 tty_insert_flip_string(tty, (char *) &c,
366 (count > 4) ? 4 : count);
367 count -= 4;
368 }
369
370 tty_flip_buffer_push(tty);
371}
372
373static void handle_tx(struct uart_port *port)
374{
375 struct circ_buf *xmit = &port->state->xmit;
376 int sent_tx;
377 int tx_count;
378 int x;
379 unsigned int tf_pointer = 0;
Sathish Ambley99e2a242011-10-25 15:49:53 -0700380 unsigned int vid;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700381
Sathish Ambley99e2a242011-10-25 15:49:53 -0700382 vid = UART_TO_MSM(port)->ver_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700383 tx_count = uart_circ_chars_pending(xmit);
384
385 if (tx_count > (UART_XMIT_SIZE - xmit->tail))
386 tx_count = UART_XMIT_SIZE - xmit->tail;
387 if (tx_count >= port->fifosize)
388 tx_count = port->fifosize;
389
390 /* Handle x_char */
391 if (port->x_char) {
Stepan Moskovchenko9ec24842012-05-15 13:58:58 -0700392 wait_for_xmitr(port);
Stepan Moskovchenko4f1025f2012-05-15 13:00:05 -0700393 msm_hsl_write(port, tx_count + 1, regmap[vid][UARTDM_NCF_TX]);
394 msm_hsl_read(port, regmap[vid][UARTDM_NCF_TX]);
Sathish Ambley99e2a242011-10-25 15:49:53 -0700395 msm_hsl_write(port, port->x_char, regmap[vid][UARTDM_TF]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700396 port->icount.tx++;
397 port->x_char = 0;
398 } else if (tx_count) {
Stepan Moskovchenko9ec24842012-05-15 13:58:58 -0700399 wait_for_xmitr(port);
Sathish Ambley99e2a242011-10-25 15:49:53 -0700400 msm_hsl_write(port, tx_count, regmap[vid][UARTDM_NCF_TX]);
Stepan Moskovchenko4f1025f2012-05-15 13:00:05 -0700401 msm_hsl_read(port, regmap[vid][UARTDM_NCF_TX]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700402 }
403 if (!tx_count) {
404 msm_hsl_stop_tx(port);
405 return;
406 }
407
408 while (tf_pointer < tx_count) {
Sathish Ambley99e2a242011-10-25 15:49:53 -0700409 if (unlikely(!(msm_hsl_read(port, regmap[vid][UARTDM_SR]) &
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700410 UARTDM_SR_TXRDY_BMSK)))
411 continue;
412 switch (tx_count - tf_pointer) {
413 case 1: {
414 x = xmit->buf[xmit->tail];
415 port->icount.tx++;
416 break;
417 }
418 case 2: {
419 x = xmit->buf[xmit->tail]
420 | xmit->buf[xmit->tail+1] << 8;
421 port->icount.tx += 2;
422 break;
423 }
424 case 3: {
425 x = xmit->buf[xmit->tail]
426 | xmit->buf[xmit->tail+1] << 8
427 | xmit->buf[xmit->tail + 2] << 16;
428 port->icount.tx += 3;
429 break;
430 }
431 default: {
432 x = *((int *)&(xmit->buf[xmit->tail]));
433 port->icount.tx += 4;
434 break;
435 }
436 }
Sathish Ambley99e2a242011-10-25 15:49:53 -0700437 msm_hsl_write(port, x, regmap[vid][UARTDM_TF]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700438 xmit->tail = ((tx_count - tf_pointer < 4) ?
439 (tx_count - tf_pointer + xmit->tail) :
440 (xmit->tail + 4)) & (UART_XMIT_SIZE - 1);
441 tf_pointer += 4;
442 sent_tx = 1;
443 }
444
445 if (uart_circ_empty(xmit))
446 msm_hsl_stop_tx(port);
447
448 if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
449 uart_write_wakeup(port);
450
451}
452
453static void handle_delta_cts(struct uart_port *port)
454{
Sathish Ambley99e2a242011-10-25 15:49:53 -0700455 unsigned int vid = UART_TO_MSM(port)->ver_id;
456
457 msm_hsl_write(port, RESET_CTS, regmap[vid][UARTDM_CR]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700458 port->icount.cts++;
459 wake_up_interruptible(&port->state->port.delta_msr_wait);
460}
461
462static irqreturn_t msm_hsl_irq(int irq, void *dev_id)
463{
464 struct uart_port *port = dev_id;
465 struct msm_hsl_port *msm_hsl_port = UART_TO_MSM(port);
Sathish Ambley99e2a242011-10-25 15:49:53 -0700466 unsigned int vid;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700467 unsigned int misr;
468 unsigned long flags;
469
470 spin_lock_irqsave(&port->lock, flags);
Sathish Ambley99e2a242011-10-25 15:49:53 -0700471 vid = msm_hsl_port->ver_id;
472 misr = msm_hsl_read(port, regmap[vid][UARTDM_MISR]);
473 /* disable interrupt */
474 msm_hsl_write(port, 0, regmap[vid][UARTDM_IMR]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700475
476 if (misr & (UARTDM_ISR_RXSTALE_BMSK | UARTDM_ISR_RXLEV_BMSK)) {
477 handle_rx(port, misr);
478 if (misr & (UARTDM_ISR_RXSTALE_BMSK))
Sathish Ambley99e2a242011-10-25 15:49:53 -0700479 msm_hsl_write(port, RESET_STALE_INT,
480 regmap[vid][UARTDM_CR]);
481 msm_hsl_write(port, 6500, regmap[vid][UARTDM_DMRX]);
482 msm_hsl_write(port, STALE_EVENT_ENABLE, regmap[vid][UARTDM_CR]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700483 }
484 if (misr & UARTDM_ISR_TXLEV_BMSK)
485 handle_tx(port);
486
487 if (misr & UARTDM_ISR_DELTA_CTS_BMSK)
488 handle_delta_cts(port);
489
490 /* restore interrupt */
Sathish Ambley99e2a242011-10-25 15:49:53 -0700491 msm_hsl_write(port, msm_hsl_port->imr, regmap[vid][UARTDM_IMR]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700492 spin_unlock_irqrestore(&port->lock, flags);
493
494 return IRQ_HANDLED;
495}
496
497static unsigned int msm_hsl_tx_empty(struct uart_port *port)
498{
499 unsigned int ret;
Mayank Ranaa4ad7b32012-01-24 10:23:48 +0530500 unsigned int vid = UART_TO_MSM(port)->ver_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700501
Sathish Ambley99e2a242011-10-25 15:49:53 -0700502 ret = (msm_hsl_read(port, regmap[vid][UARTDM_SR]) &
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700503 UARTDM_SR_TXEMT_BMSK) ? TIOCSER_TEMT : 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700504 return ret;
505}
506
507static void msm_hsl_reset(struct uart_port *port)
508{
Sathish Ambley99e2a242011-10-25 15:49:53 -0700509 unsigned int vid = UART_TO_MSM(port)->ver_id;
510
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700511 /* reset everything */
Sathish Ambley99e2a242011-10-25 15:49:53 -0700512 msm_hsl_write(port, RESET_RX, regmap[vid][UARTDM_CR]);
513 msm_hsl_write(port, RESET_TX, regmap[vid][UARTDM_CR]);
514 msm_hsl_write(port, RESET_ERROR_STATUS, regmap[vid][UARTDM_CR]);
515 msm_hsl_write(port, RESET_BREAK_INT, regmap[vid][UARTDM_CR]);
516 msm_hsl_write(port, RESET_CTS, regmap[vid][UARTDM_CR]);
517 msm_hsl_write(port, RFR_LOW, regmap[vid][UARTDM_CR]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700518}
519
520static unsigned int msm_hsl_get_mctrl(struct uart_port *port)
521{
522 return TIOCM_CAR | TIOCM_CTS | TIOCM_DSR | TIOCM_RTS;
523}
524
525static void msm_hsl_set_mctrl(struct uart_port *port, unsigned int mctrl)
526{
Sathish Ambley99e2a242011-10-25 15:49:53 -0700527 unsigned int vid = UART_TO_MSM(port)->ver_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700528 unsigned int mr;
529 unsigned int loop_mode;
530
Sathish Ambley99e2a242011-10-25 15:49:53 -0700531 mr = msm_hsl_read(port, regmap[vid][UARTDM_MR1]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700532
533 if (!(mctrl & TIOCM_RTS)) {
534 mr &= ~UARTDM_MR1_RX_RDY_CTL_BMSK;
Sathish Ambley99e2a242011-10-25 15:49:53 -0700535 msm_hsl_write(port, mr, regmap[vid][UARTDM_MR1]);
536 msm_hsl_write(port, RFR_HIGH, regmap[vid][UARTDM_CR]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700537 } else {
538 mr |= UARTDM_MR1_RX_RDY_CTL_BMSK;
Sathish Ambley99e2a242011-10-25 15:49:53 -0700539 msm_hsl_write(port, mr, regmap[vid][UARTDM_MR1]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700540 }
541
542 loop_mode = TIOCM_LOOP & mctrl;
543 if (loop_mode) {
Sathish Ambley99e2a242011-10-25 15:49:53 -0700544 mr = msm_hsl_read(port, regmap[vid][UARTDM_MR2]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700545 mr |= UARTDM_MR2_LOOP_MODE_BMSK;
Sathish Ambley99e2a242011-10-25 15:49:53 -0700546 msm_hsl_write(port, mr, regmap[vid][UARTDM_MR2]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700547
548 /* Reset TX */
549 msm_hsl_reset(port);
550
551 /* Turn on Uart Receiver & Transmitter*/
552 msm_hsl_write(port, UARTDM_CR_RX_EN_BMSK
Sathish Ambley99e2a242011-10-25 15:49:53 -0700553 | UARTDM_CR_TX_EN_BMSK, regmap[vid][UARTDM_CR]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700554 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700555}
556
557static void msm_hsl_break_ctl(struct uart_port *port, int break_ctl)
558{
Sathish Ambley99e2a242011-10-25 15:49:53 -0700559 unsigned int vid = UART_TO_MSM(port)->ver_id;
560
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700561 if (break_ctl)
Sathish Ambley99e2a242011-10-25 15:49:53 -0700562 msm_hsl_write(port, START_BREAK, regmap[vid][UARTDM_CR]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700563 else
Sathish Ambley99e2a242011-10-25 15:49:53 -0700564 msm_hsl_write(port, STOP_BREAK, regmap[vid][UARTDM_CR]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700565}
566
567static void msm_hsl_set_baud_rate(struct uart_port *port, unsigned int baud)
568{
569 unsigned int baud_code, rxstale, watermark;
Mayank Ranae9a54342011-06-29 20:27:08 +0530570 unsigned int data;
Sathish Ambley99e2a242011-10-25 15:49:53 -0700571 unsigned int vid;
Mayank Ranae9a54342011-06-29 20:27:08 +0530572 struct msm_hsl_port *msm_hsl_port = UART_TO_MSM(port);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700573
574 switch (baud) {
575 case 300:
Mayank Rana9825dc62011-07-26 10:47:46 +0530576 baud_code = UARTDM_CSR_75;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700577 rxstale = 1;
578 break;
579 case 600:
Mayank Rana9825dc62011-07-26 10:47:46 +0530580 baud_code = UARTDM_CSR_150;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700581 rxstale = 1;
582 break;
583 case 1200:
Mayank Rana9825dc62011-07-26 10:47:46 +0530584 baud_code = UARTDM_CSR_300;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700585 rxstale = 1;
586 break;
587 case 2400:
Mayank Rana9825dc62011-07-26 10:47:46 +0530588 baud_code = UARTDM_CSR_600;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700589 rxstale = 1;
590 break;
591 case 4800:
Mayank Rana9825dc62011-07-26 10:47:46 +0530592 baud_code = UARTDM_CSR_1200;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700593 rxstale = 1;
594 break;
595 case 9600:
Mayank Rana9825dc62011-07-26 10:47:46 +0530596 baud_code = UARTDM_CSR_2400;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700597 rxstale = 2;
598 break;
599 case 14400:
Mayank Rana9825dc62011-07-26 10:47:46 +0530600 baud_code = UARTDM_CSR_3600;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700601 rxstale = 3;
602 break;
603 case 19200:
Mayank Rana9825dc62011-07-26 10:47:46 +0530604 baud_code = UARTDM_CSR_4800;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700605 rxstale = 4;
606 break;
607 case 28800:
Mayank Rana9825dc62011-07-26 10:47:46 +0530608 baud_code = UARTDM_CSR_7200;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700609 rxstale = 6;
610 break;
611 case 38400:
Mayank Rana9825dc62011-07-26 10:47:46 +0530612 baud_code = UARTDM_CSR_9600;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700613 rxstale = 8;
614 break;
615 case 57600:
Mayank Rana9825dc62011-07-26 10:47:46 +0530616 baud_code = UARTDM_CSR_14400;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700617 rxstale = 16;
618 break;
619 case 115200:
Mayank Rana9825dc62011-07-26 10:47:46 +0530620 baud_code = UARTDM_CSR_28800;
621 rxstale = 31;
622 break;
623 case 230400:
624 baud_code = UARTDM_CSR_57600;
625 rxstale = 31;
626 break;
627 case 460800:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700628 baud_code = UARTDM_CSR_115200;
629 rxstale = 31;
630 break;
Mayank Rana9825dc62011-07-26 10:47:46 +0530631 default: /* 115200 baud rate */
632 baud_code = UARTDM_CSR_28800;
633 rxstale = 31;
634 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700635 }
636
Stepan Moskovchenko71db70c2012-06-19 13:25:46 -0700637 /* Set timeout to be ~600x the character transmit time */
638 msm_hsl_port->tx_timeout = (1000000000 / baud) * 6;
Stepan Moskovchenko1d4731e2012-02-21 20:18:23 -0800639
Sathish Ambley99e2a242011-10-25 15:49:53 -0700640 vid = msm_hsl_port->ver_id;
641 msm_hsl_write(port, baud_code, regmap[vid][UARTDM_CSR]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700642
643 /* RX stale watermark */
644 watermark = UARTDM_IPR_STALE_LSB_BMSK & rxstale;
645 watermark |= UARTDM_IPR_STALE_TIMEOUT_MSB_BMSK & (rxstale << 2);
Sathish Ambley99e2a242011-10-25 15:49:53 -0700646 msm_hsl_write(port, watermark, regmap[vid][UARTDM_IPR]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700647
Mayank Ranaad56d5f2011-08-16 09:07:04 +0530648 /* Set RX watermark
649 * Configure Rx Watermark as 3/4 size of Rx FIFO.
650 * RFWR register takes value in Words for UARTDM Core
651 * whereas it is consider to be in Bytes for UART Core.
652 * Hence configuring Rx Watermark as 12 Words.
653 */
654 watermark = (port->fifosize * 3) / (4*4);
Sathish Ambley99e2a242011-10-25 15:49:53 -0700655 msm_hsl_write(port, watermark, regmap[vid][UARTDM_RFWR]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700656
657 /* set TX watermark */
Sathish Ambley99e2a242011-10-25 15:49:53 -0700658 msm_hsl_write(port, 0, regmap[vid][UARTDM_TFWR]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700659
Sathish Ambley99e2a242011-10-25 15:49:53 -0700660 msm_hsl_write(port, CR_PROTECTION_EN, regmap[vid][UARTDM_CR]);
Mayank Ranae9a54342011-06-29 20:27:08 +0530661 msm_hsl_reset(port);
662
663 data = UARTDM_CR_TX_EN_BMSK;
664 data |= UARTDM_CR_RX_EN_BMSK;
665 /* enable TX & RX */
Sathish Ambley99e2a242011-10-25 15:49:53 -0700666 msm_hsl_write(port, data, regmap[vid][UARTDM_CR]);
Mayank Ranae9a54342011-06-29 20:27:08 +0530667
Mayank Rana9717aba2012-02-27 18:20:38 +0530668 msm_hsl_write(port, RESET_STALE_INT, regmap[vid][UARTDM_CR]);
Mayank Ranae9a54342011-06-29 20:27:08 +0530669 /* turn on RX and CTS interrupts */
670 msm_hsl_port->imr = UARTDM_ISR_RXSTALE_BMSK
671 | UARTDM_ISR_DELTA_CTS_BMSK | UARTDM_ISR_RXLEV_BMSK;
Sathish Ambley99e2a242011-10-25 15:49:53 -0700672 msm_hsl_write(port, msm_hsl_port->imr, regmap[vid][UARTDM_IMR]);
673 msm_hsl_write(port, 6500, regmap[vid][UARTDM_DMRX]);
674 msm_hsl_write(port, STALE_EVENT_ENABLE, regmap[vid][UARTDM_CR]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700675}
676
677static void msm_hsl_init_clock(struct uart_port *port)
678{
679 clk_en(port, 1);
680}
681
682static void msm_hsl_deinit_clock(struct uart_port *port)
683{
684 clk_en(port, 0);
685}
686
687static int msm_hsl_startup(struct uart_port *port)
688{
689 struct msm_hsl_port *msm_hsl_port = UART_TO_MSM(port);
690 struct platform_device *pdev = to_platform_device(port->dev);
691 const struct msm_serial_hslite_platform_data *pdata =
692 pdev->dev.platform_data;
693 unsigned int data, rfr_level;
Sathish Ambley99e2a242011-10-25 15:49:53 -0700694 unsigned int vid;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700695 int ret;
696 unsigned long flags;
697
698 snprintf(msm_hsl_port->name, sizeof(msm_hsl_port->name),
699 "msm_serial_hsl%d", port->line);
700
701 if (!(is_console(port)) || (!port->cons) ||
702 (port->cons && (!(port->cons->flags & CON_ENABLED)))) {
703
704 if (msm_serial_hsl_has_gsbi(port))
705 if ((ioread32(msm_hsl_port->mapped_gsbi +
706 GSBI_CONTROL_ADDR) & GSBI_PROTOCOL_I2C_UART)
707 != GSBI_PROTOCOL_I2C_UART)
708 iowrite32(GSBI_PROTOCOL_I2C_UART,
709 msm_hsl_port->mapped_gsbi +
710 GSBI_CONTROL_ADDR);
711
712 if (pdata && pdata->config_gpio) {
713 ret = gpio_request(pdata->uart_tx_gpio,
714 "UART_TX_GPIO");
715 if (unlikely(ret)) {
716 pr_err("%s: gpio request failed for:%d\n",
717 __func__, pdata->uart_tx_gpio);
718 return ret;
719 }
720
721 ret = gpio_request(pdata->uart_rx_gpio, "UART_RX_GPIO");
722 if (unlikely(ret)) {
723 pr_err("%s: gpio request failed for:%d\n",
724 __func__, pdata->uart_rx_gpio);
725 gpio_free(pdata->uart_tx_gpio);
726 return ret;
727 }
728 }
729 }
730#ifndef CONFIG_PM_RUNTIME
731 msm_hsl_init_clock(port);
732#endif
733 pm_runtime_get_sync(port->dev);
734
Mayank Ranaffdf5302011-08-17 20:54:34 +0530735 /* Set RFR Level as 3/4 of UARTDM FIFO Size */
736 if (likely(port->fifosize > 48))
737 rfr_level = port->fifosize - 16;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700738 else
739 rfr_level = port->fifosize;
740
Mayank Ranaffdf5302011-08-17 20:54:34 +0530741 /*
742 * Use rfr_level value in Words to program
743 * MR1 register for UARTDM Core.
744 */
745 rfr_level = (rfr_level / 4);
746
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700747 spin_lock_irqsave(&port->lock, flags);
748
Sathish Ambley99e2a242011-10-25 15:49:53 -0700749 vid = msm_hsl_port->ver_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700750 /* set automatic RFR level */
Sathish Ambley99e2a242011-10-25 15:49:53 -0700751 data = msm_hsl_read(port, regmap[vid][UARTDM_MR1]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700752 data &= ~UARTDM_MR1_AUTO_RFR_LEVEL1_BMSK;
753 data &= ~UARTDM_MR1_AUTO_RFR_LEVEL0_BMSK;
754 data |= UARTDM_MR1_AUTO_RFR_LEVEL1_BMSK & (rfr_level << 2);
755 data |= UARTDM_MR1_AUTO_RFR_LEVEL0_BMSK & rfr_level;
Sathish Ambley99e2a242011-10-25 15:49:53 -0700756 msm_hsl_write(port, data, regmap[vid][UARTDM_MR1]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700757 spin_unlock_irqrestore(&port->lock, flags);
758
759 ret = request_irq(port->irq, msm_hsl_irq, IRQF_TRIGGER_HIGH,
760 msm_hsl_port->name, port);
761 if (unlikely(ret)) {
762 printk(KERN_ERR "%s: failed to request_irq\n", __func__);
763 return ret;
764 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700765 return 0;
766}
767
768static void msm_hsl_shutdown(struct uart_port *port)
769{
770 struct msm_hsl_port *msm_hsl_port = UART_TO_MSM(port);
771 struct platform_device *pdev = to_platform_device(port->dev);
772 const struct msm_serial_hslite_platform_data *pdata =
773 pdev->dev.platform_data;
774
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700775 msm_hsl_port->imr = 0;
Sathish Ambley99e2a242011-10-25 15:49:53 -0700776 /* disable interrupts */
777 msm_hsl_write(port, 0, regmap[msm_hsl_port->ver_id][UARTDM_IMR]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700778
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700779 free_irq(port->irq, port);
780
781#ifndef CONFIG_PM_RUNTIME
782 msm_hsl_deinit_clock(port);
783#endif
784 pm_runtime_put_sync(port->dev);
785 if (!(is_console(port)) || (!port->cons) ||
786 (port->cons && (!(port->cons->flags & CON_ENABLED)))) {
787 if (pdata && pdata->config_gpio) {
788 gpio_free(pdata->uart_tx_gpio);
789 gpio_free(pdata->uart_rx_gpio);
790 }
791 }
792}
793
794static void msm_hsl_set_termios(struct uart_port *port,
795 struct ktermios *termios,
796 struct ktermios *old)
797{
798 unsigned long flags;
799 unsigned int baud, mr;
Sathish Ambley99e2a242011-10-25 15:49:53 -0700800 unsigned int vid;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700801
Mayank Rana216744c2012-05-01 22:43:21 -0700802 if (!termios->c_cflag)
803 return;
804
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700805 spin_lock_irqsave(&port->lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700806
807 /* calculate and set baud rate */
Mayank Rana9825dc62011-07-26 10:47:46 +0530808 baud = uart_get_baud_rate(port, termios, old, 300, 460800);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700809
810 msm_hsl_set_baud_rate(port, baud);
811
Sathish Ambley99e2a242011-10-25 15:49:53 -0700812 vid = UART_TO_MSM(port)->ver_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700813 /* calculate parity */
Sathish Ambley99e2a242011-10-25 15:49:53 -0700814 mr = msm_hsl_read(port, regmap[vid][UARTDM_MR2]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700815 mr &= ~UARTDM_MR2_PARITY_MODE_BMSK;
816 if (termios->c_cflag & PARENB) {
817 if (termios->c_cflag & PARODD)
818 mr |= ODD_PARITY;
819 else if (termios->c_cflag & CMSPAR)
820 mr |= SPACE_PARITY;
821 else
822 mr |= EVEN_PARITY;
823 }
824
825 /* calculate bits per char */
826 mr &= ~UARTDM_MR2_BITS_PER_CHAR_BMSK;
827 switch (termios->c_cflag & CSIZE) {
828 case CS5:
829 mr |= FIVE_BPC;
830 break;
831 case CS6:
832 mr |= SIX_BPC;
833 break;
834 case CS7:
835 mr |= SEVEN_BPC;
836 break;
837 case CS8:
838 default:
839 mr |= EIGHT_BPC;
840 break;
841 }
842
843 /* calculate stop bits */
844 mr &= ~(STOP_BIT_ONE | STOP_BIT_TWO);
845 if (termios->c_cflag & CSTOPB)
846 mr |= STOP_BIT_TWO;
847 else
848 mr |= STOP_BIT_ONE;
849
850 /* set parity, bits per char, and stop bit */
Sathish Ambley99e2a242011-10-25 15:49:53 -0700851 msm_hsl_write(port, mr, regmap[vid][UARTDM_MR2]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700852
853 /* calculate and set hardware flow control */
Sathish Ambley99e2a242011-10-25 15:49:53 -0700854 mr = msm_hsl_read(port, regmap[vid][UARTDM_MR1]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700855 mr &= ~(UARTDM_MR1_CTS_CTL_BMSK | UARTDM_MR1_RX_RDY_CTL_BMSK);
856 if (termios->c_cflag & CRTSCTS) {
857 mr |= UARTDM_MR1_CTS_CTL_BMSK;
858 mr |= UARTDM_MR1_RX_RDY_CTL_BMSK;
859 }
Sathish Ambley99e2a242011-10-25 15:49:53 -0700860 msm_hsl_write(port, mr, regmap[vid][UARTDM_MR1]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700861
862 /* Configure status bits to ignore based on termio flags. */
863 port->read_status_mask = 0;
864 if (termios->c_iflag & INPCK)
865 port->read_status_mask |= UARTDM_SR_PAR_FRAME_BMSK;
866 if (termios->c_iflag & (BRKINT | PARMRK))
867 port->read_status_mask |= UARTDM_SR_RX_BREAK_BMSK;
868
869 uart_update_timeout(port, termios->c_cflag, baud);
870
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700871 spin_unlock_irqrestore(&port->lock, flags);
872}
873
874static const char *msm_hsl_type(struct uart_port *port)
875{
876 return "MSM";
877}
878
879static void msm_hsl_release_port(struct uart_port *port)
880{
881 struct msm_hsl_port *msm_hsl_port = UART_TO_MSM(port);
882 struct platform_device *pdev = to_platform_device(port->dev);
883 struct resource *uart_resource;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700884 resource_size_t size;
885
886 uart_resource = platform_get_resource_byname(pdev, IORESOURCE_MEM,
887 "uartdm_resource");
Sathish Ambley3d50c762011-10-25 15:26:00 -0700888 if (!uart_resource)
889 uart_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700890 if (unlikely(!uart_resource))
891 return;
892 size = uart_resource->end - uart_resource->start + 1;
893
894 release_mem_region(port->mapbase, size);
895 iounmap(port->membase);
896 port->membase = NULL;
897
898 if (msm_serial_hsl_has_gsbi(port)) {
899 iowrite32(GSBI_PROTOCOL_IDLE, msm_hsl_port->mapped_gsbi +
900 GSBI_CONTROL_ADDR);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700901 iounmap(msm_hsl_port->mapped_gsbi);
902 msm_hsl_port->mapped_gsbi = NULL;
903 }
904}
905
906static int msm_hsl_request_port(struct uart_port *port)
907{
908 struct msm_hsl_port *msm_hsl_port = UART_TO_MSM(port);
909 struct platform_device *pdev = to_platform_device(port->dev);
910 struct resource *uart_resource;
911 struct resource *gsbi_resource;
912 resource_size_t size;
913
914 uart_resource = platform_get_resource_byname(pdev, IORESOURCE_MEM,
915 "uartdm_resource");
Sathish Ambley3d50c762011-10-25 15:26:00 -0700916 if (!uart_resource)
917 uart_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700918 if (unlikely(!uart_resource)) {
919 pr_err("%s: can't get uartdm resource\n", __func__);
920 return -ENXIO;
921 }
922 size = uart_resource->end - uart_resource->start + 1;
923
924 if (unlikely(!request_mem_region(port->mapbase, size,
925 "msm_serial_hsl"))) {
926 pr_err("%s: can't get mem region for uartdm\n", __func__);
927 return -EBUSY;
928 }
929
930 port->membase = ioremap(port->mapbase, size);
931 if (!port->membase) {
932 release_mem_region(port->mapbase, size);
933 return -EBUSY;
934 }
935
936 if (msm_serial_hsl_has_gsbi(port)) {
937 gsbi_resource = platform_get_resource_byname(pdev,
938 IORESOURCE_MEM,
939 "gsbi_resource");
Sathish Ambley3d50c762011-10-25 15:26:00 -0700940 if (!gsbi_resource)
941 gsbi_resource = platform_get_resource(pdev,
942 IORESOURCE_MEM, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700943 if (unlikely(!gsbi_resource)) {
944 pr_err("%s: can't get gsbi resource\n", __func__);
945 return -ENXIO;
946 }
947
948 size = gsbi_resource->end - gsbi_resource->start + 1;
949 msm_hsl_port->mapped_gsbi = ioremap(gsbi_resource->start,
950 size);
951 if (!msm_hsl_port->mapped_gsbi) {
952 return -EBUSY;
953 }
954 }
955
956 return 0;
957}
958
959static void msm_hsl_config_port(struct uart_port *port, int flags)
960{
961 struct msm_hsl_port *msm_hsl_port = UART_TO_MSM(port);
962 if (flags & UART_CONFIG_TYPE) {
963 port->type = PORT_MSM;
964 if (msm_hsl_request_port(port))
965 return;
966 }
Stepan Moskovchenko131d2e72011-07-11 17:06:38 -0700967 if (msm_serial_hsl_has_gsbi(port)) {
968 if (msm_hsl_port->pclk)
Mayank Rana5d0252a2012-01-24 13:58:43 +0530969 clk_prepare_enable(msm_hsl_port->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700970 if ((ioread32(msm_hsl_port->mapped_gsbi + GSBI_CONTROL_ADDR) &
971 GSBI_PROTOCOL_I2C_UART) != GSBI_PROTOCOL_I2C_UART)
972 iowrite32(GSBI_PROTOCOL_I2C_UART,
973 msm_hsl_port->mapped_gsbi + GSBI_CONTROL_ADDR);
Stepan Moskovchenko131d2e72011-07-11 17:06:38 -0700974 if (msm_hsl_port->pclk)
Mayank Rana5d0252a2012-01-24 13:58:43 +0530975 clk_disable_unprepare(msm_hsl_port->pclk);
Stepan Moskovchenko131d2e72011-07-11 17:06:38 -0700976 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700977}
978
979static int msm_hsl_verify_port(struct uart_port *port,
980 struct serial_struct *ser)
981{
982 if (unlikely(ser->type != PORT_UNKNOWN && ser->type != PORT_MSM))
983 return -EINVAL;
984 if (unlikely(port->irq != ser->irq))
985 return -EINVAL;
986 return 0;
987}
988
989static void msm_hsl_power(struct uart_port *port, unsigned int state,
990 unsigned int oldstate)
991{
992 int ret;
993 struct msm_hsl_port *msm_hsl_port = UART_TO_MSM(port);
994
995 switch (state) {
996 case 0:
Mayank Rana9825dc62011-07-26 10:47:46 +0530997 ret = clk_set_rate(msm_hsl_port->clk, 7372800);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700998 if (ret)
999 pr_err("%s(): Error setting UART clock rate\n",
1000 __func__);
1001 clk_en(port, 1);
1002 break;
1003 case 3:
1004 clk_en(port, 0);
Mayank Rana22e4b382012-01-11 21:35:00 +05301005 ret = clk_set_rate(msm_hsl_port->clk, 0);
1006 if (ret)
1007 pr_err("%s(): Error setting UART clock rate to zero.\n",
1008 __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001009 break;
1010 default:
1011 pr_err("%s(): msm_serial_hsl: Unknown PM state %d\n",
1012 __func__, state);
1013 }
1014}
1015
1016static struct uart_ops msm_hsl_uart_pops = {
1017 .tx_empty = msm_hsl_tx_empty,
1018 .set_mctrl = msm_hsl_set_mctrl,
1019 .get_mctrl = msm_hsl_get_mctrl,
1020 .stop_tx = msm_hsl_stop_tx,
1021 .start_tx = msm_hsl_start_tx,
1022 .stop_rx = msm_hsl_stop_rx,
1023 .enable_ms = msm_hsl_enable_ms,
1024 .break_ctl = msm_hsl_break_ctl,
1025 .startup = msm_hsl_startup,
1026 .shutdown = msm_hsl_shutdown,
1027 .set_termios = msm_hsl_set_termios,
1028 .type = msm_hsl_type,
1029 .release_port = msm_hsl_release_port,
1030 .request_port = msm_hsl_request_port,
1031 .config_port = msm_hsl_config_port,
1032 .verify_port = msm_hsl_verify_port,
1033 .pm = msm_hsl_power,
1034};
1035
1036static struct msm_hsl_port msm_hsl_uart_ports[] = {
1037 {
1038 .uart = {
1039 .iotype = UPIO_MEM,
1040 .ops = &msm_hsl_uart_pops,
1041 .flags = UPF_BOOT_AUTOCONF,
1042 .fifosize = 64,
1043 .line = 0,
1044 },
1045 },
1046 {
1047 .uart = {
1048 .iotype = UPIO_MEM,
1049 .ops = &msm_hsl_uart_pops,
1050 .flags = UPF_BOOT_AUTOCONF,
1051 .fifosize = 64,
1052 .line = 1,
1053 },
1054 },
1055 {
1056 .uart = {
1057 .iotype = UPIO_MEM,
1058 .ops = &msm_hsl_uart_pops,
1059 .flags = UPF_BOOT_AUTOCONF,
1060 .fifosize = 64,
1061 .line = 2,
1062 },
1063 },
1064};
1065
1066#define UART_NR ARRAY_SIZE(msm_hsl_uart_ports)
1067
1068static inline struct uart_port *get_port_from_line(unsigned int line)
1069{
1070 return &msm_hsl_uart_ports[line].uart;
1071}
1072
Stepan Moskovchenko1d4731e2012-02-21 20:18:23 -08001073static unsigned int msm_hsl_console_state[8];
1074
1075static void dump_hsl_regs(struct uart_port *port)
1076{
1077 struct msm_hsl_port *msm_hsl_port = UART_TO_MSM(port);
1078 unsigned int vid = msm_hsl_port->ver_id;
1079 unsigned int sr, isr, mr1, mr2, ncf, txfs, rxfs, con_state;
1080
1081 sr = msm_hsl_read(port, regmap[vid][UARTDM_SR]);
1082 isr = msm_hsl_read(port, regmap[vid][UARTDM_ISR]);
1083 mr1 = msm_hsl_read(port, regmap[vid][UARTDM_MR1]);
1084 mr2 = msm_hsl_read(port, regmap[vid][UARTDM_MR2]);
1085 ncf = msm_hsl_read(port, regmap[vid][UARTDM_NCF_TX]);
1086 txfs = msm_hsl_read(port, regmap[vid][UARTDM_TXFS]);
1087 rxfs = msm_hsl_read(port, regmap[vid][UARTDM_RXFS]);
1088 con_state = get_console_state(port);
1089
1090 msm_hsl_console_state[0] = sr;
1091 msm_hsl_console_state[1] = isr;
1092 msm_hsl_console_state[2] = mr1;
1093 msm_hsl_console_state[3] = mr2;
1094 msm_hsl_console_state[4] = ncf;
1095 msm_hsl_console_state[5] = txfs;
1096 msm_hsl_console_state[6] = rxfs;
1097 msm_hsl_console_state[7] = con_state;
1098
1099 pr_info("%s(): Timeout: %d uS\n", __func__, msm_hsl_port->tx_timeout);
1100 pr_info("%s(): SR: %08x\n", __func__, sr);
1101 pr_info("%s(): ISR: %08x\n", __func__, isr);
1102 pr_info("%s(): MR1: %08x\n", __func__, mr1);
1103 pr_info("%s(): MR2: %08x\n", __func__, mr2);
1104 pr_info("%s(): NCF: %08x\n", __func__, ncf);
1105 pr_info("%s(): TXFS: %08x\n", __func__, txfs);
1106 pr_info("%s(): RXFS: %08x\n", __func__, rxfs);
1107 pr_info("%s(): Console state: %d\n", __func__, con_state);
1108}
1109
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001110/*
1111 * Wait for transmitter & holding register to empty
1112 * Derived from wait_for_xmitr in 8250 serial driver by Russell King */
Stepan Moskovchenko9ec24842012-05-15 13:58:58 -07001113static void wait_for_xmitr(struct uart_port *port)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001114{
Stepan Moskovchenko1d4731e2012-02-21 20:18:23 -08001115 struct msm_hsl_port *msm_hsl_port = UART_TO_MSM(port);
1116 unsigned int vid = msm_hsl_port->ver_id;
1117 int count = 0;
Sathish Ambley99e2a242011-10-25 15:49:53 -07001118
1119 if (!(msm_hsl_read(port, regmap[vid][UARTDM_SR]) &
1120 UARTDM_SR_TXEMT_BMSK)) {
Stepan Moskovchenko9ec24842012-05-15 13:58:58 -07001121 while (!(msm_hsl_read(port, regmap[vid][UARTDM_ISR]) &
Stepan Moskovchenkod4a62ab202012-05-15 14:43:31 -07001122 UARTDM_ISR_TX_READY_BMSK) &&
1123 !(msm_hsl_read(port, regmap[vid][UARTDM_SR]) &
1124 UARTDM_SR_TXEMT_BMSK)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001125 udelay(1);
1126 touch_nmi_watchdog();
1127 cpu_relax();
Stepan Moskovchenko1d4731e2012-02-21 20:18:23 -08001128 if (++count == msm_hsl_port->tx_timeout) {
1129 dump_hsl_regs(port);
1130 panic("MSM HSL wait_for_xmitr is stuck!");
1131 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001132 }
Sathish Ambley99e2a242011-10-25 15:49:53 -07001133 msm_hsl_write(port, CLEAR_TX_READY, regmap[vid][UARTDM_CR]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001134 }
1135}
1136
1137#ifdef CONFIG_SERIAL_MSM_HSL_CONSOLE
1138static void msm_hsl_console_putchar(struct uart_port *port, int ch)
1139{
Sathish Ambley99e2a242011-10-25 15:49:53 -07001140 unsigned int vid = UART_TO_MSM(port)->ver_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001141
Stepan Moskovchenko9ec24842012-05-15 13:58:58 -07001142 wait_for_xmitr(port);
Sathish Ambley99e2a242011-10-25 15:49:53 -07001143 msm_hsl_write(port, 1, regmap[vid][UARTDM_NCF_TX]);
Mayank Ranaec41e932012-02-24 16:24:54 +05301144 /*
1145 * Dummy read to add 1 AHB clock delay to fix UART hardware bug.
1146 * Bug: Delay required on TX-transfer-init. after writing to
1147 * NO_CHARS_FOR_TX register.
1148 */
1149 msm_hsl_read(port, regmap[vid][UARTDM_SR]);
Sathish Ambley99e2a242011-10-25 15:49:53 -07001150 msm_hsl_write(port, ch, regmap[vid][UARTDM_TF]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001151}
1152
1153static void msm_hsl_console_write(struct console *co, const char *s,
1154 unsigned int count)
1155{
1156 struct uart_port *port;
1157 struct msm_hsl_port *msm_hsl_port;
Sathish Ambley99e2a242011-10-25 15:49:53 -07001158 unsigned int vid;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001159 int locked;
1160
1161 BUG_ON(co->index < 0 || co->index >= UART_NR);
1162
1163 port = get_port_from_line(co->index);
1164 msm_hsl_port = UART_TO_MSM(port);
Sathish Ambley99e2a242011-10-25 15:49:53 -07001165 vid = msm_hsl_port->ver_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001166
1167 /* not pretty, but we can end up here via various convoluted paths */
1168 if (port->sysrq || oops_in_progress)
1169 locked = spin_trylock(&port->lock);
1170 else {
1171 locked = 1;
1172 spin_lock(&port->lock);
1173 }
Sathish Ambley99e2a242011-10-25 15:49:53 -07001174 msm_hsl_write(port, 0, regmap[vid][UARTDM_IMR]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001175 uart_console_write(port, s, count, msm_hsl_console_putchar);
Sathish Ambley99e2a242011-10-25 15:49:53 -07001176 msm_hsl_write(port, msm_hsl_port->imr, regmap[vid][UARTDM_IMR]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001177 if (locked == 1)
1178 spin_unlock(&port->lock);
1179}
1180
Mayank Rana930c99c2011-09-05 18:22:02 +05301181static int msm_hsl_console_setup(struct console *co, char *options)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001182{
1183 struct uart_port *port;
Sathish Ambley99e2a242011-10-25 15:49:53 -07001184 unsigned int vid;
Stepan Moskovchenkoe4b0d792012-05-10 14:10:44 -07001185 int baud = 0, flow, bits, parity, mr2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001186 int ret;
1187
1188 if (unlikely(co->index >= UART_NR || co->index < 0))
1189 return -ENXIO;
1190
1191 port = get_port_from_line(co->index);
Sathish Ambley99e2a242011-10-25 15:49:53 -07001192 vid = UART_TO_MSM(port)->ver_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001193
1194 if (unlikely(!port->membase))
1195 return -ENXIO;
1196
1197 port->cons = co;
1198
1199 pm_runtime_get_noresume(port->dev);
1200
1201#ifndef CONFIG_PM_RUNTIME
1202 msm_hsl_init_clock(port);
1203#endif
1204 pm_runtime_resume(port->dev);
1205
1206 if (options)
1207 uart_parse_options(options, &baud, &parity, &bits, &flow);
1208
1209 bits = 8;
1210 parity = 'n';
1211 flow = 'n';
1212 msm_hsl_write(port, UARTDM_MR2_BITS_PER_CHAR_8 | STOP_BIT_ONE,
Sathish Ambley99e2a242011-10-25 15:49:53 -07001213 regmap[vid][UARTDM_MR2]); /* 8N1 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001214
1215 if (baud < 300 || baud > 115200)
1216 baud = 115200;
1217 msm_hsl_set_baud_rate(port, baud);
1218
1219 ret = uart_set_options(port, co, baud, parity, bits, flow);
Stepan Moskovchenkoe4b0d792012-05-10 14:10:44 -07001220
1221 mr2 = msm_hsl_read(port, regmap[vid][UARTDM_MR2]);
1222 mr2 |= UARTDM_MR2_RX_ERROR_CHAR_OFF;
1223 mr2 |= UARTDM_MR2_RX_BREAK_ZERO_CHAR_OFF;
1224 msm_hsl_write(port, mr2, regmap[vid][UARTDM_MR2]);
1225
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001226 msm_hsl_reset(port);
1227 /* Enable transmitter */
Sathish Ambley99e2a242011-10-25 15:49:53 -07001228 msm_hsl_write(port, CR_PROTECTION_EN, regmap[vid][UARTDM_CR]);
1229 msm_hsl_write(port, UARTDM_CR_TX_EN_BMSK, regmap[vid][UARTDM_CR]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001230
Stepan Moskovchenkof525c112012-05-15 14:10:26 -07001231 msm_hsl_write(port, 1, regmap[vid][UARTDM_NCF_TX]);
1232 msm_hsl_read(port, regmap[vid][UARTDM_NCF_TX]);
1233
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001234 printk(KERN_INFO "msm_serial_hsl: console setup on port #%d\n",
1235 port->line);
1236
1237 return ret;
1238}
1239
1240static struct uart_driver msm_hsl_uart_driver;
1241
1242static struct console msm_hsl_console = {
1243 .name = "ttyHSL",
1244 .write = msm_hsl_console_write,
1245 .device = uart_console_device,
1246 .setup = msm_hsl_console_setup,
1247 .flags = CON_PRINTBUFFER,
1248 .index = -1,
1249 .data = &msm_hsl_uart_driver,
1250};
1251
1252#define MSM_HSL_CONSOLE (&msm_hsl_console)
Mayank Rana930c99c2011-09-05 18:22:02 +05301253/*
1254 * get_console_state - check the per-port serial console state.
1255 * @port: uart_port structure describing the port
1256 *
1257 * Return the state of serial console availability on port.
1258 * return 1: If serial console is enabled on particular UART port.
1259 * return 0: If serial console is disabled on particular UART port.
1260 */
1261static int get_console_state(struct uart_port *port)
1262{
1263 if (is_console(port) && (port->cons->flags & CON_ENABLED))
1264 return 1;
1265 else
1266 return 0;
1267}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001268
Mayank Rana930c99c2011-09-05 18:22:02 +05301269/* show_msm_console - provide per-port serial console state. */
1270static ssize_t show_msm_console(struct device *dev,
1271 struct device_attribute *attr, char *buf)
1272{
1273 int enable;
1274 struct uart_port *port;
1275
1276 struct platform_device *pdev = to_platform_device(dev);
Stepan Moskovchenko798fe552012-03-29 19:47:19 -07001277 port = get_port_from_line(get_line(pdev));
Mayank Rana930c99c2011-09-05 18:22:02 +05301278
1279 enable = get_console_state(port);
1280
1281 return snprintf(buf, sizeof(enable), "%d\n", enable);
1282}
1283
1284/*
1285 * set_msm_console - allow to enable/disable serial console on port.
1286 *
1287 * writing 1 enables serial console on UART port.
1288 * writing 0 disables serial console on UART port.
1289 */
1290static ssize_t set_msm_console(struct device *dev,
1291 struct device_attribute *attr,
1292 const char *buf, size_t count)
1293{
1294 int enable, cur_state;
1295 struct uart_port *port;
1296
1297 struct platform_device *pdev = to_platform_device(dev);
Stepan Moskovchenko798fe552012-03-29 19:47:19 -07001298 port = get_port_from_line(get_line(pdev));
Mayank Rana930c99c2011-09-05 18:22:02 +05301299
1300 cur_state = get_console_state(port);
1301 enable = buf[0] - '0';
1302
1303 if (enable == cur_state)
1304 return count;
1305
1306 switch (enable) {
1307 case 0:
1308 pr_debug("%s(): Calling stop_console\n", __func__);
1309 console_stop(port->cons);
1310 pr_debug("%s(): Calling unregister_console\n", __func__);
1311 unregister_console(port->cons);
1312 pm_runtime_put_sync(&pdev->dev);
1313 pm_runtime_disable(&pdev->dev);
1314 /*
1315 * Disable UART Core clk
1316 * 3 - to disable the UART clock
1317 * Thid parameter is not used here, but used in serial core.
1318 */
1319 msm_hsl_power(port, 3, 1);
1320 break;
1321 case 1:
1322 pr_debug("%s(): Calling register_console\n", __func__);
1323 /*
1324 * Disable UART Core clk
1325 * 0 - to enable the UART clock
1326 * Thid parameter is not used here, but used in serial core.
1327 */
1328 msm_hsl_power(port, 0, 1);
1329 pm_runtime_enable(&pdev->dev);
1330 register_console(port->cons);
1331 break;
1332 default:
1333 return -EINVAL;
1334 }
1335
1336 return count;
1337}
1338static DEVICE_ATTR(console, S_IWUSR | S_IRUGO, show_msm_console,
1339 set_msm_console);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001340#else
1341#define MSM_HSL_CONSOLE NULL
1342#endif
1343
1344static struct uart_driver msm_hsl_uart_driver = {
1345 .owner = THIS_MODULE,
1346 .driver_name = "msm_serial_hsl",
1347 .dev_name = "ttyHSL",
1348 .nr = UART_NR,
1349 .cons = MSM_HSL_CONSOLE,
1350};
1351
Sathish Ambley3d50c762011-10-25 15:26:00 -07001352static atomic_t msm_serial_hsl_next_id = ATOMIC_INIT(0);
1353
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001354static int __devinit msm_serial_hsl_probe(struct platform_device *pdev)
1355{
1356 struct msm_hsl_port *msm_hsl_port;
1357 struct resource *uart_resource;
1358 struct resource *gsbi_resource;
1359 struct uart_port *port;
Sathish Ambley99e2a242011-10-25 15:49:53 -07001360 const struct of_device_id *match;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001361 int ret;
1362
Sathish Ambley3d50c762011-10-25 15:26:00 -07001363 if (pdev->id == -1)
1364 pdev->id = atomic_inc_return(&msm_serial_hsl_next_id) - 1;
1365
Stepan Moskovchenko798fe552012-03-29 19:47:19 -07001366 if (unlikely(get_line(pdev) < 0 || get_line(pdev) >= UART_NR))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001367 return -ENXIO;
1368
1369 printk(KERN_INFO "msm_serial_hsl: detected port #%d\n", pdev->id);
1370
Stepan Moskovchenko798fe552012-03-29 19:47:19 -07001371 port = get_port_from_line(get_line(pdev));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001372 port->dev = &pdev->dev;
1373 msm_hsl_port = UART_TO_MSM(port);
1374
Sathish Ambley99e2a242011-10-25 15:49:53 -07001375 match = of_match_device(msm_hsl_match_table, &pdev->dev);
1376 if (!match)
1377 msm_hsl_port->ver_id = UARTDM_VERSION_11_13;
1378 else
1379 msm_hsl_port->ver_id = (unsigned int)match->data;
1380
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001381 gsbi_resource = platform_get_resource_byname(pdev,
1382 IORESOURCE_MEM,
1383 "gsbi_resource");
Sathish Ambley3d50c762011-10-25 15:26:00 -07001384 if (!gsbi_resource)
1385 gsbi_resource = platform_get_resource(pdev, IORESOURCE_MEM, 1);
Matt Wagantalle2522372011-08-17 14:52:21 -07001386 msm_hsl_port->clk = clk_get(&pdev->dev, "core_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001387 if (gsbi_resource) {
1388 msm_hsl_port->is_uartdm = 1;
Matt Wagantalle2522372011-08-17 14:52:21 -07001389 msm_hsl_port->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001390 } else {
1391 msm_hsl_port->is_uartdm = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001392 msm_hsl_port->pclk = NULL;
1393 }
1394
1395 if (unlikely(IS_ERR(msm_hsl_port->clk))) {
1396 printk(KERN_ERR "%s: Error getting clk\n", __func__);
1397 return PTR_ERR(msm_hsl_port->clk);
1398 }
1399 if (unlikely(IS_ERR(msm_hsl_port->pclk))) {
1400 printk(KERN_ERR "%s: Error getting pclk\n", __func__);
1401 return PTR_ERR(msm_hsl_port->pclk);
1402 }
1403
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001404 uart_resource = platform_get_resource_byname(pdev,
1405 IORESOURCE_MEM,
1406 "uartdm_resource");
Sathish Ambley3d50c762011-10-25 15:26:00 -07001407 if (!uart_resource)
1408 uart_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001409 if (unlikely(!uart_resource)) {
1410 printk(KERN_ERR "getting uartdm_resource failed\n");
1411 return -ENXIO;
1412 }
1413 port->mapbase = uart_resource->start;
1414
1415 port->irq = platform_get_irq(pdev, 0);
Mayank Rana72fef232011-09-28 12:42:57 +05301416 if (unlikely((int)port->irq < 0)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001417 printk(KERN_ERR "%s: getting irq failed\n", __func__);
1418 return -ENXIO;
1419 }
1420
1421 device_set_wakeup_capable(&pdev->dev, 1);
1422 platform_set_drvdata(pdev, port);
1423 pm_runtime_enable(port->dev);
Mayank Rana930c99c2011-09-05 18:22:02 +05301424#ifdef CONFIG_SERIAL_MSM_HSL_CONSOLE
1425 ret = device_create_file(&pdev->dev, &dev_attr_console);
1426 if (unlikely(ret))
1427 pr_err("%s():Can't create console attribute\n", __func__);
1428#endif
Stepan Moskovchenko798fe552012-03-29 19:47:19 -07001429 msm_hsl_debugfs_init(msm_hsl_port, get_line(pdev));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001430
Stepan Moskovchenko72029d62011-08-23 17:08:55 -07001431 /* Temporarily increase the refcount on the GSBI clock to avoid a race
1432 * condition with the earlyprintk handover mechanism.
1433 */
1434 if (msm_hsl_port->pclk)
Mayank Rana5d0252a2012-01-24 13:58:43 +05301435 clk_prepare_enable(msm_hsl_port->pclk);
Stepan Moskovchenko72029d62011-08-23 17:08:55 -07001436 ret = uart_add_one_port(&msm_hsl_uart_driver, port);
1437 if (msm_hsl_port->pclk)
Mayank Rana5d0252a2012-01-24 13:58:43 +05301438 clk_disable_unprepare(msm_hsl_port->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001439 return ret;
1440}
1441
1442static int __devexit msm_serial_hsl_remove(struct platform_device *pdev)
1443{
1444 struct msm_hsl_port *msm_hsl_port = platform_get_drvdata(pdev);
1445 struct uart_port *port;
1446
Stepan Moskovchenko798fe552012-03-29 19:47:19 -07001447 port = get_port_from_line(get_line(pdev));
Mayank Rana930c99c2011-09-05 18:22:02 +05301448#ifdef CONFIG_SERIAL_MSM_HSL_CONSOLE
1449 device_remove_file(&pdev->dev, &dev_attr_console);
1450#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001451 pm_runtime_put_sync(&pdev->dev);
1452 pm_runtime_disable(&pdev->dev);
1453
1454 device_set_wakeup_capable(&pdev->dev, 0);
1455 platform_set_drvdata(pdev, NULL);
1456 uart_remove_one_port(&msm_hsl_uart_driver, port);
1457
1458 clk_put(msm_hsl_port->pclk);
1459 clk_put(msm_hsl_port->clk);
Mayank Rana8dddd752011-07-13 11:19:58 +05301460 debugfs_remove(msm_hsl_port->loopback_dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001461
1462 return 0;
1463}
1464
1465#ifdef CONFIG_PM
1466static int msm_serial_hsl_suspend(struct device *dev)
1467{
1468 struct platform_device *pdev = to_platform_device(dev);
1469 struct uart_port *port;
Stepan Moskovchenko798fe552012-03-29 19:47:19 -07001470 port = get_port_from_line(get_line(pdev));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001471
1472 if (port) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001473
1474 if (is_console(port))
1475 msm_hsl_deinit_clock(port);
Mayank Rana70a8e7d2011-09-02 14:29:18 +05301476
1477 uart_suspend_port(&msm_hsl_uart_driver, port);
1478 if (device_may_wakeup(dev))
1479 enable_irq_wake(port->irq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001480 }
1481
1482 return 0;
1483}
1484
1485static int msm_serial_hsl_resume(struct device *dev)
1486{
1487 struct platform_device *pdev = to_platform_device(dev);
1488 struct uart_port *port;
Stepan Moskovchenko798fe552012-03-29 19:47:19 -07001489 port = get_port_from_line(get_line(pdev));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001490
1491 if (port) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001492
Mayank Rana70a8e7d2011-09-02 14:29:18 +05301493 uart_resume_port(&msm_hsl_uart_driver, port);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001494 if (device_may_wakeup(dev))
1495 disable_irq_wake(port->irq);
Mayank Rana70a8e7d2011-09-02 14:29:18 +05301496
1497 if (is_console(port))
1498 msm_hsl_init_clock(port);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001499 }
1500
1501 return 0;
1502}
1503#else
1504#define msm_serial_hsl_suspend NULL
1505#define msm_serial_hsl_resume NULL
1506#endif
1507
1508static int msm_hsl_runtime_suspend(struct device *dev)
1509{
1510 struct platform_device *pdev = to_platform_device(dev);
1511 struct uart_port *port;
Stepan Moskovchenko798fe552012-03-29 19:47:19 -07001512 port = get_port_from_line(get_line(pdev));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001513
1514 dev_dbg(dev, "pm_runtime: suspending\n");
1515 msm_hsl_deinit_clock(port);
1516 return 0;
1517}
1518
1519static int msm_hsl_runtime_resume(struct device *dev)
1520{
1521 struct platform_device *pdev = to_platform_device(dev);
1522 struct uart_port *port;
Stepan Moskovchenko798fe552012-03-29 19:47:19 -07001523 port = get_port_from_line(get_line(pdev));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001524
1525 dev_dbg(dev, "pm_runtime: resuming\n");
1526 msm_hsl_init_clock(port);
1527 return 0;
1528}
1529
1530static struct dev_pm_ops msm_hsl_dev_pm_ops = {
1531 .suspend = msm_serial_hsl_suspend,
1532 .resume = msm_serial_hsl_resume,
1533 .runtime_suspend = msm_hsl_runtime_suspend,
1534 .runtime_resume = msm_hsl_runtime_resume,
1535};
1536
1537static struct platform_driver msm_hsl_platform_driver = {
1538 .probe = msm_serial_hsl_probe,
1539 .remove = __devexit_p(msm_serial_hsl_remove),
1540 .driver = {
1541 .name = "msm_serial_hsl",
1542 .owner = THIS_MODULE,
1543 .pm = &msm_hsl_dev_pm_ops,
Sathish Ambley3d50c762011-10-25 15:26:00 -07001544 .of_match_table = msm_hsl_match_table,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001545 },
1546};
1547
1548static int __init msm_serial_hsl_init(void)
1549{
1550 int ret;
1551
1552 ret = uart_register_driver(&msm_hsl_uart_driver);
1553 if (unlikely(ret))
1554 return ret;
1555
Mayank Rana8dddd752011-07-13 11:19:58 +05301556 debug_base = debugfs_create_dir("msm_serial_hsl", NULL);
1557 if (IS_ERR_OR_NULL(debug_base))
1558 pr_err("%s():Cannot create debugfs dir\n", __func__);
1559
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001560 ret = platform_driver_register(&msm_hsl_platform_driver);
1561 if (unlikely(ret))
1562 uart_unregister_driver(&msm_hsl_uart_driver);
1563
1564 printk(KERN_INFO "msm_serial_hsl: driver initialized\n");
1565
1566 return ret;
1567}
1568
1569static void __exit msm_serial_hsl_exit(void)
1570{
Mayank Rana8dddd752011-07-13 11:19:58 +05301571 debugfs_remove_recursive(debug_base);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001572#ifdef CONFIG_SERIAL_MSM_HSL_CONSOLE
1573 unregister_console(&msm_hsl_console);
1574#endif
1575 platform_driver_unregister(&msm_hsl_platform_driver);
1576 uart_unregister_driver(&msm_hsl_uart_driver);
1577}
1578
1579module_init(msm_serial_hsl_init);
1580module_exit(msm_serial_hsl_exit);
1581
1582MODULE_DESCRIPTION("Driver for msm HSUART serial device");
1583MODULE_LICENSE("GPL v2");