blob: ce197befbfb4b5f347dee696bb7f52d81532d846 [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]) &
1122 UARTDM_ISR_TX_READY_BMSK)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001123 udelay(1);
1124 touch_nmi_watchdog();
1125 cpu_relax();
Stepan Moskovchenko1d4731e2012-02-21 20:18:23 -08001126 if (++count == msm_hsl_port->tx_timeout) {
1127 dump_hsl_regs(port);
1128 panic("MSM HSL wait_for_xmitr is stuck!");
1129 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001130 }
Sathish Ambley99e2a242011-10-25 15:49:53 -07001131 msm_hsl_write(port, CLEAR_TX_READY, regmap[vid][UARTDM_CR]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001132 }
1133}
1134
1135#ifdef CONFIG_SERIAL_MSM_HSL_CONSOLE
1136static void msm_hsl_console_putchar(struct uart_port *port, int ch)
1137{
Sathish Ambley99e2a242011-10-25 15:49:53 -07001138 unsigned int vid = UART_TO_MSM(port)->ver_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001139
Stepan Moskovchenko9ec24842012-05-15 13:58:58 -07001140 wait_for_xmitr(port);
Sathish Ambley99e2a242011-10-25 15:49:53 -07001141 msm_hsl_write(port, 1, regmap[vid][UARTDM_NCF_TX]);
Mayank Ranaec41e932012-02-24 16:24:54 +05301142 /*
1143 * Dummy read to add 1 AHB clock delay to fix UART hardware bug.
1144 * Bug: Delay required on TX-transfer-init. after writing to
1145 * NO_CHARS_FOR_TX register.
1146 */
1147 msm_hsl_read(port, regmap[vid][UARTDM_SR]);
Sathish Ambley99e2a242011-10-25 15:49:53 -07001148 msm_hsl_write(port, ch, regmap[vid][UARTDM_TF]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001149}
1150
1151static void msm_hsl_console_write(struct console *co, const char *s,
1152 unsigned int count)
1153{
1154 struct uart_port *port;
1155 struct msm_hsl_port *msm_hsl_port;
Sathish Ambley99e2a242011-10-25 15:49:53 -07001156 unsigned int vid;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001157 int locked;
1158
1159 BUG_ON(co->index < 0 || co->index >= UART_NR);
1160
1161 port = get_port_from_line(co->index);
1162 msm_hsl_port = UART_TO_MSM(port);
Sathish Ambley99e2a242011-10-25 15:49:53 -07001163 vid = msm_hsl_port->ver_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001164
1165 /* not pretty, but we can end up here via various convoluted paths */
1166 if (port->sysrq || oops_in_progress)
1167 locked = spin_trylock(&port->lock);
1168 else {
1169 locked = 1;
1170 spin_lock(&port->lock);
1171 }
Sathish Ambley99e2a242011-10-25 15:49:53 -07001172 msm_hsl_write(port, 0, regmap[vid][UARTDM_IMR]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001173 uart_console_write(port, s, count, msm_hsl_console_putchar);
Sathish Ambley99e2a242011-10-25 15:49:53 -07001174 msm_hsl_write(port, msm_hsl_port->imr, regmap[vid][UARTDM_IMR]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001175 if (locked == 1)
1176 spin_unlock(&port->lock);
1177}
1178
Mayank Rana930c99c2011-09-05 18:22:02 +05301179static int msm_hsl_console_setup(struct console *co, char *options)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001180{
1181 struct uart_port *port;
Sathish Ambley99e2a242011-10-25 15:49:53 -07001182 unsigned int vid;
Stepan Moskovchenkoe4b0d792012-05-10 14:10:44 -07001183 int baud = 0, flow, bits, parity, mr2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001184 int ret;
1185
1186 if (unlikely(co->index >= UART_NR || co->index < 0))
1187 return -ENXIO;
1188
1189 port = get_port_from_line(co->index);
Sathish Ambley99e2a242011-10-25 15:49:53 -07001190 vid = UART_TO_MSM(port)->ver_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001191
1192 if (unlikely(!port->membase))
1193 return -ENXIO;
1194
1195 port->cons = co;
1196
1197 pm_runtime_get_noresume(port->dev);
1198
1199#ifndef CONFIG_PM_RUNTIME
1200 msm_hsl_init_clock(port);
1201#endif
1202 pm_runtime_resume(port->dev);
1203
1204 if (options)
1205 uart_parse_options(options, &baud, &parity, &bits, &flow);
1206
1207 bits = 8;
1208 parity = 'n';
1209 flow = 'n';
1210 msm_hsl_write(port, UARTDM_MR2_BITS_PER_CHAR_8 | STOP_BIT_ONE,
Sathish Ambley99e2a242011-10-25 15:49:53 -07001211 regmap[vid][UARTDM_MR2]); /* 8N1 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001212
1213 if (baud < 300 || baud > 115200)
1214 baud = 115200;
1215 msm_hsl_set_baud_rate(port, baud);
1216
1217 ret = uart_set_options(port, co, baud, parity, bits, flow);
Stepan Moskovchenkoe4b0d792012-05-10 14:10:44 -07001218
1219 mr2 = msm_hsl_read(port, regmap[vid][UARTDM_MR2]);
1220 mr2 |= UARTDM_MR2_RX_ERROR_CHAR_OFF;
1221 mr2 |= UARTDM_MR2_RX_BREAK_ZERO_CHAR_OFF;
1222 msm_hsl_write(port, mr2, regmap[vid][UARTDM_MR2]);
1223
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001224 msm_hsl_reset(port);
1225 /* Enable transmitter */
Sathish Ambley99e2a242011-10-25 15:49:53 -07001226 msm_hsl_write(port, CR_PROTECTION_EN, regmap[vid][UARTDM_CR]);
1227 msm_hsl_write(port, UARTDM_CR_TX_EN_BMSK, regmap[vid][UARTDM_CR]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001228
Stepan Moskovchenkof525c112012-05-15 14:10:26 -07001229 msm_hsl_write(port, 1, regmap[vid][UARTDM_NCF_TX]);
1230 msm_hsl_read(port, regmap[vid][UARTDM_NCF_TX]);
1231
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001232 printk(KERN_INFO "msm_serial_hsl: console setup on port #%d\n",
1233 port->line);
1234
1235 return ret;
1236}
1237
1238static struct uart_driver msm_hsl_uart_driver;
1239
1240static struct console msm_hsl_console = {
1241 .name = "ttyHSL",
1242 .write = msm_hsl_console_write,
1243 .device = uart_console_device,
1244 .setup = msm_hsl_console_setup,
1245 .flags = CON_PRINTBUFFER,
1246 .index = -1,
1247 .data = &msm_hsl_uart_driver,
1248};
1249
1250#define MSM_HSL_CONSOLE (&msm_hsl_console)
Mayank Rana930c99c2011-09-05 18:22:02 +05301251/*
1252 * get_console_state - check the per-port serial console state.
1253 * @port: uart_port structure describing the port
1254 *
1255 * Return the state of serial console availability on port.
1256 * return 1: If serial console is enabled on particular UART port.
1257 * return 0: If serial console is disabled on particular UART port.
1258 */
1259static int get_console_state(struct uart_port *port)
1260{
1261 if (is_console(port) && (port->cons->flags & CON_ENABLED))
1262 return 1;
1263 else
1264 return 0;
1265}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001266
Mayank Rana930c99c2011-09-05 18:22:02 +05301267/* show_msm_console - provide per-port serial console state. */
1268static ssize_t show_msm_console(struct device *dev,
1269 struct device_attribute *attr, char *buf)
1270{
1271 int enable;
1272 struct uart_port *port;
1273
1274 struct platform_device *pdev = to_platform_device(dev);
Stepan Moskovchenko798fe552012-03-29 19:47:19 -07001275 port = get_port_from_line(get_line(pdev));
Mayank Rana930c99c2011-09-05 18:22:02 +05301276
1277 enable = get_console_state(port);
1278
1279 return snprintf(buf, sizeof(enable), "%d\n", enable);
1280}
1281
1282/*
1283 * set_msm_console - allow to enable/disable serial console on port.
1284 *
1285 * writing 1 enables serial console on UART port.
1286 * writing 0 disables serial console on UART port.
1287 */
1288static ssize_t set_msm_console(struct device *dev,
1289 struct device_attribute *attr,
1290 const char *buf, size_t count)
1291{
1292 int enable, cur_state;
1293 struct uart_port *port;
1294
1295 struct platform_device *pdev = to_platform_device(dev);
Stepan Moskovchenko798fe552012-03-29 19:47:19 -07001296 port = get_port_from_line(get_line(pdev));
Mayank Rana930c99c2011-09-05 18:22:02 +05301297
1298 cur_state = get_console_state(port);
1299 enable = buf[0] - '0';
1300
1301 if (enable == cur_state)
1302 return count;
1303
1304 switch (enable) {
1305 case 0:
1306 pr_debug("%s(): Calling stop_console\n", __func__);
1307 console_stop(port->cons);
1308 pr_debug("%s(): Calling unregister_console\n", __func__);
1309 unregister_console(port->cons);
1310 pm_runtime_put_sync(&pdev->dev);
1311 pm_runtime_disable(&pdev->dev);
1312 /*
1313 * Disable UART Core clk
1314 * 3 - to disable the UART clock
1315 * Thid parameter is not used here, but used in serial core.
1316 */
1317 msm_hsl_power(port, 3, 1);
1318 break;
1319 case 1:
1320 pr_debug("%s(): Calling register_console\n", __func__);
1321 /*
1322 * Disable UART Core clk
1323 * 0 - to enable the UART clock
1324 * Thid parameter is not used here, but used in serial core.
1325 */
1326 msm_hsl_power(port, 0, 1);
1327 pm_runtime_enable(&pdev->dev);
1328 register_console(port->cons);
1329 break;
1330 default:
1331 return -EINVAL;
1332 }
1333
1334 return count;
1335}
1336static DEVICE_ATTR(console, S_IWUSR | S_IRUGO, show_msm_console,
1337 set_msm_console);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001338#else
1339#define MSM_HSL_CONSOLE NULL
1340#endif
1341
1342static struct uart_driver msm_hsl_uart_driver = {
1343 .owner = THIS_MODULE,
1344 .driver_name = "msm_serial_hsl",
1345 .dev_name = "ttyHSL",
1346 .nr = UART_NR,
1347 .cons = MSM_HSL_CONSOLE,
1348};
1349
Sathish Ambley3d50c762011-10-25 15:26:00 -07001350static atomic_t msm_serial_hsl_next_id = ATOMIC_INIT(0);
1351
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001352static int __devinit msm_serial_hsl_probe(struct platform_device *pdev)
1353{
1354 struct msm_hsl_port *msm_hsl_port;
1355 struct resource *uart_resource;
1356 struct resource *gsbi_resource;
1357 struct uart_port *port;
Sathish Ambley99e2a242011-10-25 15:49:53 -07001358 const struct of_device_id *match;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001359 int ret;
1360
Sathish Ambley3d50c762011-10-25 15:26:00 -07001361 if (pdev->id == -1)
1362 pdev->id = atomic_inc_return(&msm_serial_hsl_next_id) - 1;
1363
Stepan Moskovchenko798fe552012-03-29 19:47:19 -07001364 if (unlikely(get_line(pdev) < 0 || get_line(pdev) >= UART_NR))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001365 return -ENXIO;
1366
1367 printk(KERN_INFO "msm_serial_hsl: detected port #%d\n", pdev->id);
1368
Stepan Moskovchenko798fe552012-03-29 19:47:19 -07001369 port = get_port_from_line(get_line(pdev));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001370 port->dev = &pdev->dev;
1371 msm_hsl_port = UART_TO_MSM(port);
1372
Sathish Ambley99e2a242011-10-25 15:49:53 -07001373 match = of_match_device(msm_hsl_match_table, &pdev->dev);
1374 if (!match)
1375 msm_hsl_port->ver_id = UARTDM_VERSION_11_13;
1376 else
1377 msm_hsl_port->ver_id = (unsigned int)match->data;
1378
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001379 gsbi_resource = platform_get_resource_byname(pdev,
1380 IORESOURCE_MEM,
1381 "gsbi_resource");
Sathish Ambley3d50c762011-10-25 15:26:00 -07001382 if (!gsbi_resource)
1383 gsbi_resource = platform_get_resource(pdev, IORESOURCE_MEM, 1);
Matt Wagantalle2522372011-08-17 14:52:21 -07001384 msm_hsl_port->clk = clk_get(&pdev->dev, "core_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001385 if (gsbi_resource) {
1386 msm_hsl_port->is_uartdm = 1;
Matt Wagantalle2522372011-08-17 14:52:21 -07001387 msm_hsl_port->pclk = clk_get(&pdev->dev, "iface_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001388 } else {
1389 msm_hsl_port->is_uartdm = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001390 msm_hsl_port->pclk = NULL;
1391 }
1392
1393 if (unlikely(IS_ERR(msm_hsl_port->clk))) {
1394 printk(KERN_ERR "%s: Error getting clk\n", __func__);
1395 return PTR_ERR(msm_hsl_port->clk);
1396 }
1397 if (unlikely(IS_ERR(msm_hsl_port->pclk))) {
1398 printk(KERN_ERR "%s: Error getting pclk\n", __func__);
1399 return PTR_ERR(msm_hsl_port->pclk);
1400 }
1401
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001402 uart_resource = platform_get_resource_byname(pdev,
1403 IORESOURCE_MEM,
1404 "uartdm_resource");
Sathish Ambley3d50c762011-10-25 15:26:00 -07001405 if (!uart_resource)
1406 uart_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001407 if (unlikely(!uart_resource)) {
1408 printk(KERN_ERR "getting uartdm_resource failed\n");
1409 return -ENXIO;
1410 }
1411 port->mapbase = uart_resource->start;
1412
1413 port->irq = platform_get_irq(pdev, 0);
Mayank Rana72fef232011-09-28 12:42:57 +05301414 if (unlikely((int)port->irq < 0)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001415 printk(KERN_ERR "%s: getting irq failed\n", __func__);
1416 return -ENXIO;
1417 }
1418
1419 device_set_wakeup_capable(&pdev->dev, 1);
1420 platform_set_drvdata(pdev, port);
1421 pm_runtime_enable(port->dev);
Mayank Rana930c99c2011-09-05 18:22:02 +05301422#ifdef CONFIG_SERIAL_MSM_HSL_CONSOLE
1423 ret = device_create_file(&pdev->dev, &dev_attr_console);
1424 if (unlikely(ret))
1425 pr_err("%s():Can't create console attribute\n", __func__);
1426#endif
Stepan Moskovchenko798fe552012-03-29 19:47:19 -07001427 msm_hsl_debugfs_init(msm_hsl_port, get_line(pdev));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001428
Stepan Moskovchenko72029d62011-08-23 17:08:55 -07001429 /* Temporarily increase the refcount on the GSBI clock to avoid a race
1430 * condition with the earlyprintk handover mechanism.
1431 */
1432 if (msm_hsl_port->pclk)
Mayank Rana5d0252a2012-01-24 13:58:43 +05301433 clk_prepare_enable(msm_hsl_port->pclk);
Stepan Moskovchenko72029d62011-08-23 17:08:55 -07001434 ret = uart_add_one_port(&msm_hsl_uart_driver, port);
1435 if (msm_hsl_port->pclk)
Mayank Rana5d0252a2012-01-24 13:58:43 +05301436 clk_disable_unprepare(msm_hsl_port->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001437 return ret;
1438}
1439
1440static int __devexit msm_serial_hsl_remove(struct platform_device *pdev)
1441{
1442 struct msm_hsl_port *msm_hsl_port = platform_get_drvdata(pdev);
1443 struct uart_port *port;
1444
Stepan Moskovchenko798fe552012-03-29 19:47:19 -07001445 port = get_port_from_line(get_line(pdev));
Mayank Rana930c99c2011-09-05 18:22:02 +05301446#ifdef CONFIG_SERIAL_MSM_HSL_CONSOLE
1447 device_remove_file(&pdev->dev, &dev_attr_console);
1448#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001449 pm_runtime_put_sync(&pdev->dev);
1450 pm_runtime_disable(&pdev->dev);
1451
1452 device_set_wakeup_capable(&pdev->dev, 0);
1453 platform_set_drvdata(pdev, NULL);
1454 uart_remove_one_port(&msm_hsl_uart_driver, port);
1455
1456 clk_put(msm_hsl_port->pclk);
1457 clk_put(msm_hsl_port->clk);
Mayank Rana8dddd752011-07-13 11:19:58 +05301458 debugfs_remove(msm_hsl_port->loopback_dir);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001459
1460 return 0;
1461}
1462
1463#ifdef CONFIG_PM
1464static int msm_serial_hsl_suspend(struct device *dev)
1465{
1466 struct platform_device *pdev = to_platform_device(dev);
1467 struct uart_port *port;
Stepan Moskovchenko798fe552012-03-29 19:47:19 -07001468 port = get_port_from_line(get_line(pdev));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001469
1470 if (port) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001471
1472 if (is_console(port))
1473 msm_hsl_deinit_clock(port);
Mayank Rana70a8e7d2011-09-02 14:29:18 +05301474
1475 uart_suspend_port(&msm_hsl_uart_driver, port);
1476 if (device_may_wakeup(dev))
1477 enable_irq_wake(port->irq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001478 }
1479
1480 return 0;
1481}
1482
1483static int msm_serial_hsl_resume(struct device *dev)
1484{
1485 struct platform_device *pdev = to_platform_device(dev);
1486 struct uart_port *port;
Stepan Moskovchenko798fe552012-03-29 19:47:19 -07001487 port = get_port_from_line(get_line(pdev));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001488
1489 if (port) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001490
Mayank Rana70a8e7d2011-09-02 14:29:18 +05301491 uart_resume_port(&msm_hsl_uart_driver, port);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001492 if (device_may_wakeup(dev))
1493 disable_irq_wake(port->irq);
Mayank Rana70a8e7d2011-09-02 14:29:18 +05301494
1495 if (is_console(port))
1496 msm_hsl_init_clock(port);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001497 }
1498
1499 return 0;
1500}
1501#else
1502#define msm_serial_hsl_suspend NULL
1503#define msm_serial_hsl_resume NULL
1504#endif
1505
1506static int msm_hsl_runtime_suspend(struct device *dev)
1507{
1508 struct platform_device *pdev = to_platform_device(dev);
1509 struct uart_port *port;
Stepan Moskovchenko798fe552012-03-29 19:47:19 -07001510 port = get_port_from_line(get_line(pdev));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001511
1512 dev_dbg(dev, "pm_runtime: suspending\n");
1513 msm_hsl_deinit_clock(port);
1514 return 0;
1515}
1516
1517static int msm_hsl_runtime_resume(struct device *dev)
1518{
1519 struct platform_device *pdev = to_platform_device(dev);
1520 struct uart_port *port;
Stepan Moskovchenko798fe552012-03-29 19:47:19 -07001521 port = get_port_from_line(get_line(pdev));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001522
1523 dev_dbg(dev, "pm_runtime: resuming\n");
1524 msm_hsl_init_clock(port);
1525 return 0;
1526}
1527
1528static struct dev_pm_ops msm_hsl_dev_pm_ops = {
1529 .suspend = msm_serial_hsl_suspend,
1530 .resume = msm_serial_hsl_resume,
1531 .runtime_suspend = msm_hsl_runtime_suspend,
1532 .runtime_resume = msm_hsl_runtime_resume,
1533};
1534
1535static struct platform_driver msm_hsl_platform_driver = {
1536 .probe = msm_serial_hsl_probe,
1537 .remove = __devexit_p(msm_serial_hsl_remove),
1538 .driver = {
1539 .name = "msm_serial_hsl",
1540 .owner = THIS_MODULE,
1541 .pm = &msm_hsl_dev_pm_ops,
Sathish Ambley3d50c762011-10-25 15:26:00 -07001542 .of_match_table = msm_hsl_match_table,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001543 },
1544};
1545
1546static int __init msm_serial_hsl_init(void)
1547{
1548 int ret;
1549
1550 ret = uart_register_driver(&msm_hsl_uart_driver);
1551 if (unlikely(ret))
1552 return ret;
1553
Mayank Rana8dddd752011-07-13 11:19:58 +05301554 debug_base = debugfs_create_dir("msm_serial_hsl", NULL);
1555 if (IS_ERR_OR_NULL(debug_base))
1556 pr_err("%s():Cannot create debugfs dir\n", __func__);
1557
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001558 ret = platform_driver_register(&msm_hsl_platform_driver);
1559 if (unlikely(ret))
1560 uart_unregister_driver(&msm_hsl_uart_driver);
1561
1562 printk(KERN_INFO "msm_serial_hsl: driver initialized\n");
1563
1564 return ret;
1565}
1566
1567static void __exit msm_serial_hsl_exit(void)
1568{
Mayank Rana8dddd752011-07-13 11:19:58 +05301569 debugfs_remove_recursive(debug_base);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001570#ifdef CONFIG_SERIAL_MSM_HSL_CONSOLE
1571 unregister_console(&msm_hsl_console);
1572#endif
1573 platform_driver_unregister(&msm_hsl_platform_driver);
1574 uart_unregister_driver(&msm_hsl_uart_driver);
1575}
1576
1577module_init(msm_serial_hsl_init);
1578module_exit(msm_serial_hsl_exit);
1579
1580MODULE_DESCRIPTION("Driver for msm HSUART serial device");
1581MODULE_LICENSE("GPL v2");