blob: 6ae5b8560e4d764cafb8143a8a4654a81bf21f83 [file] [log] [blame]
Jamie Iles7d4008e2011-08-26 19:04:50 +01001/*
2 * Synopsys DesignWare 8250 driver.
3 *
4 * Copyright 2011 Picochip, Jamie Iles.
Heikki Krogerus6a7320c2013-01-10 11:25:10 +02005 * Copyright 2013 Intel Corporation
Jamie Iles7d4008e2011-08-26 19:04:50 +01006 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * The Synopsys DesignWare 8250 has an extra feature whereby it detects if the
13 * LCR is written whilst busy. If it is, then a busy detect interrupt is
14 * raised, the LCR needs to be rewritten and the uart status register read.
15 */
16#include <linux/device.h>
Jamie Iles7d4008e2011-08-26 19:04:50 +010017#include <linux/io.h>
18#include <linux/module.h>
19#include <linux/serial_8250.h>
20#include <linux/serial_core.h>
21#include <linux/serial_reg.h>
22#include <linux/of.h>
23#include <linux/of_irq.h>
24#include <linux/of_platform.h>
25#include <linux/platform_device.h>
26#include <linux/slab.h>
Heikki Krogerus6a7320c2013-01-10 11:25:10 +020027#include <linux/acpi.h>
Emilio Lópeze302cd92013-03-29 00:15:49 +010028#include <linux/clk.h>
Chen-Yu Tsai7fe090b2014-07-23 23:33:06 +080029#include <linux/reset.h>
Heikki Krogerusffc3ae62013-04-10 16:58:28 +030030#include <linux/pm_runtime.h>
Jamie Iles7d4008e2011-08-26 19:04:50 +010031
David Daneyd5f1af72013-06-19 20:37:27 +000032#include <asm/byteorder.h>
33
Heikki Krogerus7277b2a2013-01-10 11:25:12 +020034#include "8250.h"
35
Heikki Krogerus30046df2013-01-10 11:25:09 +020036/* Offsets for the DesignWare specific registers */
37#define DW_UART_USR 0x1f /* UART Status Register */
38#define DW_UART_CPR 0xf4 /* Component Parameter Register */
39#define DW_UART_UCV 0xf8 /* UART Component Version */
40
41/* Component Parameter Register bits */
42#define DW_UART_CPR_ABP_DATA_WIDTH (3 << 0)
43#define DW_UART_CPR_AFCE_MODE (1 << 4)
44#define DW_UART_CPR_THRE_MODE (1 << 5)
45#define DW_UART_CPR_SIR_MODE (1 << 6)
46#define DW_UART_CPR_SIR_LP_MODE (1 << 7)
47#define DW_UART_CPR_ADDITIONAL_FEATURES (1 << 8)
48#define DW_UART_CPR_FIFO_ACCESS (1 << 9)
49#define DW_UART_CPR_FIFO_STAT (1 << 10)
50#define DW_UART_CPR_SHADOW (1 << 11)
51#define DW_UART_CPR_ENCODED_PARMS (1 << 12)
52#define DW_UART_CPR_DMA_EXTRA (1 << 13)
53#define DW_UART_CPR_FIFO_MODE (0xff << 16)
54/* Helper for fifo size calculation */
55#define DW_UART_CPR_FIFO_SIZE(a) (((a >> 16) & 0xff) * 16)
56
57
Jamie Iles7d4008e2011-08-26 19:04:50 +010058struct dw8250_data {
Heikki Krogerusfe95855532013-09-05 17:34:53 +030059 u8 usr_reg;
Heikki Krogerusfe95855532013-09-05 17:34:53 +030060 int last_mcr;
61 int line;
Desmond Liudfd37662015-02-26 16:35:57 -080062 int msr_mask_on;
63 int msr_mask_off;
Heikki Krogerusfe95855532013-09-05 17:34:53 +030064 struct clk *clk;
Heiko Stübner7d78cbe2014-06-16 15:25:17 +020065 struct clk *pclk;
Chen-Yu Tsai7fe090b2014-07-23 23:33:06 +080066 struct reset_control *rst;
Heikki Krogerusfe95855532013-09-05 17:34:53 +030067 struct uart_8250_dma dma;
Jamie Iles7d4008e2011-08-26 19:04:50 +010068};
69
Loic Poulainc439c332014-04-24 11:46:14 +020070#define BYT_PRV_CLK 0x800
71#define BYT_PRV_CLK_EN (1 << 0)
72#define BYT_PRV_CLK_M_VAL_SHIFT 1
73#define BYT_PRV_CLK_N_VAL_SHIFT 16
74#define BYT_PRV_CLK_UPDATE (1 << 31)
75
Tim Kryger33acbb82013-08-16 13:50:15 -070076static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value)
77{
78 struct dw8250_data *d = p->private_data;
79
80 /* If reading MSR, report CTS asserted when auto-CTS/RTS enabled */
81 if (offset == UART_MSR && d->last_mcr & UART_MCR_AFE) {
82 value |= UART_MSR_CTS;
83 value &= ~UART_MSR_DCTS;
84 }
85
Desmond Liudfd37662015-02-26 16:35:57 -080086 /* Override any modem control signals if needed */
87 if (offset == UART_MSR) {
88 value |= d->msr_mask_on;
89 value &= ~d->msr_mask_off;
90 }
91
Tim Kryger33acbb82013-08-16 13:50:15 -070092 return value;
93}
94
Tim Krygerc49436b2013-10-01 10:18:08 -070095static void dw8250_force_idle(struct uart_port *p)
96{
Andy Shevchenkob1261c82014-07-14 14:26:14 +030097 struct uart_8250_port *up = up_to_u8250p(p);
98
99 serial8250_clear_and_reinit_fifos(up);
Tim Krygerc49436b2013-10-01 10:18:08 -0700100 (void)p->serial_in(p, UART_RX);
101}
102
Jamie Iles7d4008e2011-08-26 19:04:50 +0100103static void dw8250_serial_out(struct uart_port *p, int offset, int value)
104{
105 struct dw8250_data *d = p->private_data;
106
Tim Kryger33acbb82013-08-16 13:50:15 -0700107 if (offset == UART_MCR)
108 d->last_mcr = value;
109
110 writeb(value, p->membase + (offset << p->regshift));
Tim Krygerc49436b2013-10-01 10:18:08 -0700111
112 /* Make sure LCR write wasn't ignored */
113 if (offset == UART_LCR) {
114 int tries = 1000;
115 while (tries--) {
James Hogan6979f8d2013-12-10 22:28:04 +0000116 unsigned int lcr = p->serial_in(p, UART_LCR);
117 if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR))
Tim Krygerc49436b2013-10-01 10:18:08 -0700118 return;
119 dw8250_force_idle(p);
120 writeb(value, p->membase + (UART_LCR << p->regshift));
121 }
Peter Hurley7fd6f642015-03-11 09:19:16 -0400122 /*
123 * FIXME: this deadlocks if port->lock is already held
124 * dev_err(p->dev, "Couldn't set LCR to %d\n", value);
125 */
Tim Krygerc49436b2013-10-01 10:18:08 -0700126 }
Jamie Iles7d4008e2011-08-26 19:04:50 +0100127}
128
129static unsigned int dw8250_serial_in(struct uart_port *p, int offset)
130{
Tim Kryger33acbb82013-08-16 13:50:15 -0700131 unsigned int value = readb(p->membase + (offset << p->regshift));
Jamie Iles7d4008e2011-08-26 19:04:50 +0100132
Tim Kryger33acbb82013-08-16 13:50:15 -0700133 return dw8250_modify_msr(p, offset, value);
Jamie Iles7d4008e2011-08-26 19:04:50 +0100134}
135
David Daneybca20922014-11-14 17:26:19 +0300136#ifdef CONFIG_64BIT
137static unsigned int dw8250_serial_inq(struct uart_port *p, int offset)
David Daneyd5f1af72013-06-19 20:37:27 +0000138{
David Daneybca20922014-11-14 17:26:19 +0300139 unsigned int value;
140
141 value = (u8)__raw_readq(p->membase + (offset << p->regshift));
142
143 return dw8250_modify_msr(p, offset, value);
David Daneyd5f1af72013-06-19 20:37:27 +0000144}
145
David Daneybca20922014-11-14 17:26:19 +0300146static void dw8250_serial_outq(struct uart_port *p, int offset, int value)
147{
148 struct dw8250_data *d = p->private_data;
149
150 if (offset == UART_MCR)
151 d->last_mcr = value;
152
153 value &= 0xff;
154 __raw_writeq(value, p->membase + (offset << p->regshift));
155 /* Read back to ensure register write ordering. */
156 __raw_readq(p->membase + (UART_LCR << p->regshift));
157
158 /* Make sure LCR write wasn't ignored */
159 if (offset == UART_LCR) {
160 int tries = 1000;
161 while (tries--) {
162 unsigned int lcr = p->serial_in(p, UART_LCR);
163 if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR))
164 return;
165 dw8250_force_idle(p);
166 __raw_writeq(value & 0xff,
167 p->membase + (UART_LCR << p->regshift));
168 }
Peter Hurley7fd6f642015-03-11 09:19:16 -0400169 /*
170 * FIXME: this deadlocks if port->lock is already held
171 * dev_err(p->dev, "Couldn't set LCR to %d\n", value);
172 */
David Daneybca20922014-11-14 17:26:19 +0300173 }
174}
175#endif /* CONFIG_64BIT */
176
Jamie Iles7d4008e2011-08-26 19:04:50 +0100177static void dw8250_serial_out32(struct uart_port *p, int offset, int value)
178{
179 struct dw8250_data *d = p->private_data;
180
Tim Kryger33acbb82013-08-16 13:50:15 -0700181 if (offset == UART_MCR)
182 d->last_mcr = value;
183
184 writel(value, p->membase + (offset << p->regshift));
Tim Krygerc49436b2013-10-01 10:18:08 -0700185
186 /* Make sure LCR write wasn't ignored */
187 if (offset == UART_LCR) {
188 int tries = 1000;
189 while (tries--) {
James Hogan6979f8d2013-12-10 22:28:04 +0000190 unsigned int lcr = p->serial_in(p, UART_LCR);
191 if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR))
Tim Krygerc49436b2013-10-01 10:18:08 -0700192 return;
193 dw8250_force_idle(p);
194 writel(value, p->membase + (UART_LCR << p->regshift));
195 }
Peter Hurley7fd6f642015-03-11 09:19:16 -0400196 /*
197 * FIXME: this deadlocks if port->lock is already held
198 * dev_err(p->dev, "Couldn't set LCR to %d\n", value);
199 */
Tim Krygerc49436b2013-10-01 10:18:08 -0700200 }
Jamie Iles7d4008e2011-08-26 19:04:50 +0100201}
202
203static unsigned int dw8250_serial_in32(struct uart_port *p, int offset)
204{
Tim Kryger33acbb82013-08-16 13:50:15 -0700205 unsigned int value = readl(p->membase + (offset << p->regshift));
Jamie Iles7d4008e2011-08-26 19:04:50 +0100206
Tim Kryger33acbb82013-08-16 13:50:15 -0700207 return dw8250_modify_msr(p, offset, value);
Jamie Iles7d4008e2011-08-26 19:04:50 +0100208}
209
Jamie Iles7d4008e2011-08-26 19:04:50 +0100210static int dw8250_handle_irq(struct uart_port *p)
211{
212 struct dw8250_data *d = p->private_data;
213 unsigned int iir = p->serial_in(p, UART_IIR);
214
215 if (serial8250_handle_irq(p, iir)) {
216 return 1;
217 } else if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
Tim Krygerc49436b2013-10-01 10:18:08 -0700218 /* Clear the USR */
David Daneyd5f1af72013-06-19 20:37:27 +0000219 (void)p->serial_in(p, d->usr_reg);
Jamie Iles7d4008e2011-08-26 19:04:50 +0100220
221 return 1;
222 }
223
224 return 0;
225}
226
Heikki Krogerusffc3ae62013-04-10 16:58:28 +0300227static void
228dw8250_do_pm(struct uart_port *port, unsigned int state, unsigned int old)
229{
230 if (!state)
231 pm_runtime_get_sync(port->dev);
232
233 serial8250_do_pm(port, state, old);
234
235 if (state)
236 pm_runtime_put_sync_suspend(port->dev);
237}
238
Heikki Krogerus4e26b132014-06-05 16:51:40 +0300239static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios,
240 struct ktermios *old)
241{
242 unsigned int baud = tty_termios_baud_rate(termios);
243 struct dw8250_data *d = p->private_data;
244 unsigned int rate;
245 int ret;
246
247 if (IS_ERR(d->clk) || !old)
248 goto out;
249
250 /* Not requesting clock rates below 1.8432Mhz */
251 if (baud < 115200)
252 baud = 115200;
253
254 clk_disable_unprepare(d->clk);
255 rate = clk_round_rate(d->clk, baud * 16);
256 ret = clk_set_rate(d->clk, rate);
257 clk_prepare_enable(d->clk);
258
259 if (!ret)
260 p->uartclk = rate;
261out:
262 serial8250_do_set_termios(p, termios, old);
263}
264
Heikki Krogerus7fb8c562013-09-05 17:34:54 +0300265static bool dw8250_dma_filter(struct dma_chan *chan, void *param)
266{
Andy Shevchenko9a1870c2014-08-19 20:29:22 +0300267 return false;
Heikki Krogerus7fb8c562013-09-05 17:34:54 +0300268}
269
Heikki Krogerus30046df2013-01-10 11:25:09 +0200270static void dw8250_setup_port(struct uart_8250_port *up)
271{
272 struct uart_port *p = &up->port;
273 u32 reg = readl(p->membase + DW_UART_UCV);
274
275 /*
276 * If the Component Version Register returns zero, we know that
277 * ADDITIONAL_FEATURES are not enabled. No need to go any further.
278 */
279 if (!reg)
280 return;
281
282 dev_dbg_ratelimited(p->dev, "Designware UART version %c.%c%c\n",
283 (reg >> 24) & 0xff, (reg >> 16) & 0xff, (reg >> 8) & 0xff);
284
285 reg = readl(p->membase + DW_UART_CPR);
286 if (!reg)
287 return;
288
289 /* Select the type based on fifo */
290 if (reg & DW_UART_CPR_FIFO_MODE) {
291 p->type = PORT_16550A;
292 p->flags |= UPF_FIXED_TYPE;
293 p->fifosize = DW_UART_CPR_FIFO_SIZE(reg);
294 up->tx_loadsz = p->fifosize;
Heikki Krogerus2920adb2013-04-10 16:58:31 +0300295 up->capabilities = UART_CAP_FIFO;
Heikki Krogerus30046df2013-01-10 11:25:09 +0200296 }
Heikki Krogerus2920adb2013-04-10 16:58:31 +0300297
298 if (reg & DW_UART_CPR_AFCE_MODE)
299 up->capabilities |= UART_CAP_AFE;
Heikki Krogerus30046df2013-01-10 11:25:09 +0200300}
301
David Daneyd5f1af72013-06-19 20:37:27 +0000302static int dw8250_probe_of(struct uart_port *p,
303 struct dw8250_data *data)
304{
305 struct device_node *np = p->dev->of_node;
Andy Shevchenkob1261c82014-07-14 14:26:14 +0300306 struct uart_8250_port *up = up_to_u8250p(p);
David Daneyd5f1af72013-06-19 20:37:27 +0000307 u32 val;
308 bool has_ucv = true;
Julien CHAUVEAUf77d55a2014-11-04 11:45:55 +0100309 int id;
David Daneyd5f1af72013-06-19 20:37:27 +0000310
David Daneybca20922014-11-14 17:26:19 +0300311#ifdef CONFIG_64BIT
David Daneyd5f1af72013-06-19 20:37:27 +0000312 if (of_device_is_compatible(np, "cavium,octeon-3860-uart")) {
David Daneybca20922014-11-14 17:26:19 +0300313 p->serial_in = dw8250_serial_inq;
314 p->serial_out = dw8250_serial_outq;
Andy Shevchenkod8782c72014-06-06 15:24:10 +0300315 p->flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE;
David Daneyd5f1af72013-06-19 20:37:27 +0000316 p->type = PORT_OCTEON;
317 data->usr_reg = 0x27;
318 has_ucv = false;
David Daneybca20922014-11-14 17:26:19 +0300319 } else
320#endif
321 if (!of_property_read_u32(np, "reg-io-width", &val)) {
David Daneyd5f1af72013-06-19 20:37:27 +0000322 switch (val) {
323 case 1:
324 break;
325 case 4:
326 p->iotype = UPIO_MEM32;
327 p->serial_in = dw8250_serial_in32;
328 p->serial_out = dw8250_serial_out32;
329 break;
330 default:
331 dev_err(p->dev, "unsupported reg-io-width (%u)\n", val);
332 return -EINVAL;
333 }
334 }
335 if (has_ucv)
Andy Shevchenkob1261c82014-07-14 14:26:14 +0300336 dw8250_setup_port(up);
David Daneyd5f1af72013-06-19 20:37:27 +0000337
Ray Juia8b26e12014-10-07 17:35:47 -0700338 /* if we have a valid fifosize, try hooking up DMA here */
339 if (p->fifosize) {
340 up->dma = &data->dma;
341
342 up->dma->rxconf.src_maxburst = p->fifosize / 4;
343 up->dma->txconf.dst_maxburst = p->fifosize / 4;
344 }
345
David Daneyd5f1af72013-06-19 20:37:27 +0000346 if (!of_property_read_u32(np, "reg-shift", &val))
347 p->regshift = val;
348
Julien CHAUVEAUf77d55a2014-11-04 11:45:55 +0100349 /* get index of serial line, if found in DT aliases */
350 id = of_alias_get_id(np, "serial");
351 if (id >= 0)
352 p->line = id;
353
Desmond Liudfd37662015-02-26 16:35:57 -0800354 if (of_property_read_bool(np, "dcd-override")) {
355 /* Always report DCD as active */
356 data->msr_mask_on |= UART_MSR_DCD;
357 data->msr_mask_off |= UART_MSR_DDCD;
358 }
359
360 if (of_property_read_bool(np, "dsr-override")) {
361 /* Always report DSR as active */
362 data->msr_mask_on |= UART_MSR_DSR;
363 data->msr_mask_off |= UART_MSR_DDSR;
364 }
365
366 if (of_property_read_bool(np, "cts-override")) {
367 /* Always report DSR as active */
368 data->msr_mask_on |= UART_MSR_DSR;
369 data->msr_mask_off |= UART_MSR_DDSR;
370 }
371
372 if (of_property_read_bool(np, "ri-override")) {
373 /* Always report Ring indicator as inactive */
374 data->msr_mask_off |= UART_MSR_RI;
375 data->msr_mask_off |= UART_MSR_TERI;
376 }
377
David Daneyd5f1af72013-06-19 20:37:27 +0000378 /* clock got configured through clk api, all done */
379 if (p->uartclk)
380 return 0;
381
382 /* try to find out clock frequency from DT as fallback */
383 if (of_property_read_u32(np, "clock-frequency", &val)) {
384 dev_err(p->dev, "clk or clock-frequency not defined\n");
385 return -EINVAL;
386 }
387 p->uartclk = val;
388
389 return 0;
390}
391
Heikki Krogerusfe95855532013-09-05 17:34:53 +0300392static int dw8250_probe_acpi(struct uart_8250_port *up,
393 struct dw8250_data *data)
David Daneyd5f1af72013-06-19 20:37:27 +0000394{
Feng Kan5e1aeea2014-12-05 17:45:57 -0800395 const struct acpi_device_id *id;
David Daneyd5f1af72013-06-19 20:37:27 +0000396 struct uart_port *p = &up->port;
397
398 dw8250_setup_port(up);
399
Feng Kan5e1aeea2014-12-05 17:45:57 -0800400 id = acpi_match_device(p->dev->driver->acpi_match_table, p->dev);
401 if (!id)
402 return -ENODEV;
403
404 if (!p->uartclk)
405 if (device_property_read_u32(p->dev, "clock-frequency",
406 &p->uartclk))
407 return -EINVAL;
408
David Daneyd5f1af72013-06-19 20:37:27 +0000409 p->iotype = UPIO_MEM32;
410 p->serial_in = dw8250_serial_in32;
411 p->serial_out = dw8250_serial_out32;
412 p->regshift = 2;
413
Heikki Krogerusfe95855532013-09-05 17:34:53 +0300414 up->dma = &data->dma;
David Daneyd5f1af72013-06-19 20:37:27 +0000415
416 up->dma->rxconf.src_maxburst = p->fifosize / 4;
417 up->dma->txconf.dst_maxburst = p->fifosize / 4;
418
Heikki Krogerus4e26b132014-06-05 16:51:40 +0300419 up->port.set_termios = dw8250_set_termios;
Loic Poulainc439c332014-04-24 11:46:14 +0200420
David Daneyd5f1af72013-06-19 20:37:27 +0000421 return 0;
422}
David Daneyd5f1af72013-06-19 20:37:27 +0000423
Bill Pemberton9671f092012-11-19 13:21:50 -0500424static int dw8250_probe(struct platform_device *pdev)
Jamie Iles7d4008e2011-08-26 19:04:50 +0100425{
Alan Cox2655a2c2012-07-12 12:59:50 +0100426 struct uart_8250_port uart = {};
Jamie Iles7d4008e2011-08-26 19:04:50 +0100427 struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
428 struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
Jamie Iles7d4008e2011-08-26 19:04:50 +0100429 struct dw8250_data *data;
Heikki Krogerusa7260c82013-01-10 11:25:08 +0200430 int err;
Jamie Iles7d4008e2011-08-26 19:04:50 +0100431
432 if (!regs || !irq) {
433 dev_err(&pdev->dev, "no registers/irq defined\n");
434 return -EINVAL;
435 }
436
Alan Cox2655a2c2012-07-12 12:59:50 +0100437 spin_lock_init(&uart.port.lock);
438 uart.port.mapbase = regs->start;
439 uart.port.irq = irq->start;
440 uart.port.handle_irq = dw8250_handle_irq;
Heikki Krogerusffc3ae62013-04-10 16:58:28 +0300441 uart.port.pm = dw8250_do_pm;
Alan Cox2655a2c2012-07-12 12:59:50 +0100442 uart.port.type = PORT_8250;
Heikki Krogerusf93366f2013-01-10 11:25:07 +0200443 uart.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_FIXED_PORT;
Alan Cox2655a2c2012-07-12 12:59:50 +0100444 uart.port.dev = &pdev->dev;
Jamie Iles7d4008e2011-08-26 19:04:50 +0100445
Heikki Krogerusb88d0822013-04-11 15:43:21 +0300446 uart.port.membase = devm_ioremap(&pdev->dev, regs->start,
447 resource_size(regs));
Heikki Krogerusf93366f2013-01-10 11:25:07 +0200448 if (!uart.port.membase)
449 return -ENOMEM;
450
Emilio Lópeze302cd92013-03-29 00:15:49 +0100451 data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
452 if (!data)
453 return -ENOMEM;
454
David Daneyd5f1af72013-06-19 20:37:27 +0000455 data->usr_reg = DW_UART_USR;
Heiko Stübner7d78cbe2014-06-16 15:25:17 +0200456 data->clk = devm_clk_get(&pdev->dev, "baudclk");
Chen-Yu Tsaic8ed99d2014-07-23 23:33:07 +0800457 if (IS_ERR(data->clk) && PTR_ERR(data->clk) != -EPROBE_DEFER)
Heiko Stübner7d78cbe2014-06-16 15:25:17 +0200458 data->clk = devm_clk_get(&pdev->dev, NULL);
Chen-Yu Tsaic8ed99d2014-07-23 23:33:07 +0800459 if (IS_ERR(data->clk) && PTR_ERR(data->clk) == -EPROBE_DEFER)
460 return -EPROBE_DEFER;
Emilio Lópeze302cd92013-03-29 00:15:49 +0100461 if (!IS_ERR(data->clk)) {
Heiko Stübner7d78cbe2014-06-16 15:25:17 +0200462 err = clk_prepare_enable(data->clk);
463 if (err)
464 dev_warn(&pdev->dev, "could not enable optional baudclk: %d\n",
465 err);
466 else
467 uart.port.uartclk = clk_get_rate(data->clk);
468 }
469
470 data->pclk = devm_clk_get(&pdev->dev, "apb_pclk");
Chen-Yu Tsaic8ed99d2014-07-23 23:33:07 +0800471 if (IS_ERR(data->clk) && PTR_ERR(data->clk) == -EPROBE_DEFER) {
472 err = -EPROBE_DEFER;
473 goto err_clk;
474 }
Heiko Stübner7d78cbe2014-06-16 15:25:17 +0200475 if (!IS_ERR(data->pclk)) {
476 err = clk_prepare_enable(data->pclk);
477 if (err) {
478 dev_err(&pdev->dev, "could not enable apb_pclk\n");
Chen-Yu Tsaic8ed99d2014-07-23 23:33:07 +0800479 goto err_clk;
Heiko Stübner7d78cbe2014-06-16 15:25:17 +0200480 }
Emilio Lópeze302cd92013-03-29 00:15:49 +0100481 }
482
Chen-Yu Tsai7fe090b2014-07-23 23:33:06 +0800483 data->rst = devm_reset_control_get_optional(&pdev->dev, NULL);
Chen-Yu Tsaic8ed99d2014-07-23 23:33:07 +0800484 if (IS_ERR(data->rst) && PTR_ERR(data->rst) == -EPROBE_DEFER) {
485 err = -EPROBE_DEFER;
486 goto err_pclk;
487 }
Chen-Yu Tsai7fe090b2014-07-23 23:33:06 +0800488 if (!IS_ERR(data->rst))
489 reset_control_deassert(data->rst);
490
Heikki Krogerus7fb8c562013-09-05 17:34:54 +0300491 data->dma.rx_param = data;
492 data->dma.tx_param = data;
493 data->dma.fn = dw8250_dma_filter;
494
Alan Cox2655a2c2012-07-12 12:59:50 +0100495 uart.port.iotype = UPIO_MEM;
496 uart.port.serial_in = dw8250_serial_in;
497 uart.port.serial_out = dw8250_serial_out;
Emilio Lópeze302cd92013-03-29 00:15:49 +0100498 uart.port.private_data = data;
Heikki Krogerusa7260c82013-01-10 11:25:08 +0200499
500 if (pdev->dev.of_node) {
David Daneyd5f1af72013-06-19 20:37:27 +0000501 err = dw8250_probe_of(&uart.port, data);
Heikki Krogerusa7260c82013-01-10 11:25:08 +0200502 if (err)
Chen-Yu Tsaic8ed99d2014-07-23 23:33:07 +0800503 goto err_reset;
Heikki Krogerus6a7320c2013-01-10 11:25:10 +0200504 } else if (ACPI_HANDLE(&pdev->dev)) {
Heikki Krogerusfe95855532013-09-05 17:34:53 +0300505 err = dw8250_probe_acpi(&uart, data);
Heikki Krogerus6a7320c2013-01-10 11:25:10 +0200506 if (err)
Chen-Yu Tsaic8ed99d2014-07-23 23:33:07 +0800507 goto err_reset;
Heikki Krogerusa7260c82013-01-10 11:25:08 +0200508 } else {
Chen-Yu Tsaic8ed99d2014-07-23 23:33:07 +0800509 err = -ENODEV;
510 goto err_reset;
Jamie Iles7d4008e2011-08-26 19:04:50 +0100511 }
512
Alan Cox2655a2c2012-07-12 12:59:50 +0100513 data->line = serial8250_register_8250_port(&uart);
Chen-Yu Tsaic8ed99d2014-07-23 23:33:07 +0800514 if (data->line < 0) {
515 err = data->line;
516 goto err_reset;
517 }
Jamie Iles7d4008e2011-08-26 19:04:50 +0100518
519 platform_set_drvdata(pdev, data);
520
Heikki Krogerusffc3ae62013-04-10 16:58:28 +0300521 pm_runtime_set_active(&pdev->dev);
522 pm_runtime_enable(&pdev->dev);
523
Jamie Iles7d4008e2011-08-26 19:04:50 +0100524 return 0;
Chen-Yu Tsaic8ed99d2014-07-23 23:33:07 +0800525
526err_reset:
527 if (!IS_ERR(data->rst))
528 reset_control_assert(data->rst);
529
530err_pclk:
531 if (!IS_ERR(data->pclk))
532 clk_disable_unprepare(data->pclk);
533
534err_clk:
535 if (!IS_ERR(data->clk))
536 clk_disable_unprepare(data->clk);
537
538 return err;
Jamie Iles7d4008e2011-08-26 19:04:50 +0100539}
540
Bill Pembertonae8d8a12012-11-19 13:26:18 -0500541static int dw8250_remove(struct platform_device *pdev)
Jamie Iles7d4008e2011-08-26 19:04:50 +0100542{
543 struct dw8250_data *data = platform_get_drvdata(pdev);
544
Heikki Krogerusffc3ae62013-04-10 16:58:28 +0300545 pm_runtime_get_sync(&pdev->dev);
546
Jamie Iles7d4008e2011-08-26 19:04:50 +0100547 serial8250_unregister_port(data->line);
548
Chen-Yu Tsai7fe090b2014-07-23 23:33:06 +0800549 if (!IS_ERR(data->rst))
550 reset_control_assert(data->rst);
551
Heiko Stübner7d78cbe2014-06-16 15:25:17 +0200552 if (!IS_ERR(data->pclk))
553 clk_disable_unprepare(data->pclk);
554
Emilio Lópeze302cd92013-03-29 00:15:49 +0100555 if (!IS_ERR(data->clk))
556 clk_disable_unprepare(data->clk);
557
Heikki Krogerusffc3ae62013-04-10 16:58:28 +0300558 pm_runtime_disable(&pdev->dev);
559 pm_runtime_put_noidle(&pdev->dev);
560
Jamie Iles7d4008e2011-08-26 19:04:50 +0100561 return 0;
562}
563
Mika Westerberg13b949f2014-01-16 14:55:57 +0200564#ifdef CONFIG_PM_SLEEP
Heikki Krogerusffc3ae62013-04-10 16:58:28 +0300565static int dw8250_suspend(struct device *dev)
James Hoganb61c5ed2012-10-15 10:25:58 +0100566{
Heikki Krogerusffc3ae62013-04-10 16:58:28 +0300567 struct dw8250_data *data = dev_get_drvdata(dev);
James Hoganb61c5ed2012-10-15 10:25:58 +0100568
569 serial8250_suspend_port(data->line);
570
571 return 0;
572}
573
Heikki Krogerusffc3ae62013-04-10 16:58:28 +0300574static int dw8250_resume(struct device *dev)
James Hoganb61c5ed2012-10-15 10:25:58 +0100575{
Heikki Krogerusffc3ae62013-04-10 16:58:28 +0300576 struct dw8250_data *data = dev_get_drvdata(dev);
James Hoganb61c5ed2012-10-15 10:25:58 +0100577
578 serial8250_resume_port(data->line);
579
580 return 0;
581}
Mika Westerberg13b949f2014-01-16 14:55:57 +0200582#endif /* CONFIG_PM_SLEEP */
James Hoganb61c5ed2012-10-15 10:25:58 +0100583
Rafael J. Wysockid39fe4e2014-12-13 00:41:36 +0100584#ifdef CONFIG_PM
Heikki Krogerusffc3ae62013-04-10 16:58:28 +0300585static int dw8250_runtime_suspend(struct device *dev)
586{
587 struct dw8250_data *data = dev_get_drvdata(dev);
588
Ezequiel Garciadbd2df82013-05-07 08:27:16 -0300589 if (!IS_ERR(data->clk))
590 clk_disable_unprepare(data->clk);
Heikki Krogerusffc3ae62013-04-10 16:58:28 +0300591
Heiko Stübner7d78cbe2014-06-16 15:25:17 +0200592 if (!IS_ERR(data->pclk))
593 clk_disable_unprepare(data->pclk);
594
Heikki Krogerusffc3ae62013-04-10 16:58:28 +0300595 return 0;
596}
597
598static int dw8250_runtime_resume(struct device *dev)
599{
600 struct dw8250_data *data = dev_get_drvdata(dev);
601
Heiko Stübner7d78cbe2014-06-16 15:25:17 +0200602 if (!IS_ERR(data->pclk))
603 clk_prepare_enable(data->pclk);
604
Ezequiel Garciadbd2df82013-05-07 08:27:16 -0300605 if (!IS_ERR(data->clk))
606 clk_prepare_enable(data->clk);
Heikki Krogerusffc3ae62013-04-10 16:58:28 +0300607
608 return 0;
609}
610#endif
611
612static const struct dev_pm_ops dw8250_pm_ops = {
613 SET_SYSTEM_SLEEP_PM_OPS(dw8250_suspend, dw8250_resume)
614 SET_RUNTIME_PM_OPS(dw8250_runtime_suspend, dw8250_runtime_resume, NULL)
615};
616
Heikki Krogerusa7260c82013-01-10 11:25:08 +0200617static const struct of_device_id dw8250_of_match[] = {
Jamie Iles7d4008e2011-08-26 19:04:50 +0100618 { .compatible = "snps,dw-apb-uart" },
David Daneyd5f1af72013-06-19 20:37:27 +0000619 { .compatible = "cavium,octeon-3860-uart" },
Jamie Iles7d4008e2011-08-26 19:04:50 +0100620 { /* Sentinel */ }
621};
Heikki Krogerusa7260c82013-01-10 11:25:08 +0200622MODULE_DEVICE_TABLE(of, dw8250_of_match);
Jamie Iles7d4008e2011-08-26 19:04:50 +0100623
Heikki Krogerus6a7320c2013-01-10 11:25:10 +0200624static const struct acpi_device_id dw8250_acpi_match[] = {
Heikki Krogerusaea02e82013-04-10 16:58:29 +0300625 { "INT33C4", 0 },
626 { "INT33C5", 0 },
Mika Westerbergd24c1952013-12-10 12:56:59 +0200627 { "INT3434", 0 },
628 { "INT3435", 0 },
Heikki Krogerus4e26b132014-06-05 16:51:40 +0300629 { "80860F0A", 0 },
Alan Coxf1744422014-08-19 16:34:49 +0300630 { "8086228A", 0 },
Feng Kan5e1aeea2014-12-05 17:45:57 -0800631 { "APMC0D08", 0},
Heikki Krogerus6a7320c2013-01-10 11:25:10 +0200632 { },
633};
634MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match);
635
Jamie Iles7d4008e2011-08-26 19:04:50 +0100636static struct platform_driver dw8250_platform_driver = {
637 .driver = {
638 .name = "dw-apb-uart",
Heikki Krogerusffc3ae62013-04-10 16:58:28 +0300639 .pm = &dw8250_pm_ops,
Heikki Krogerusa7260c82013-01-10 11:25:08 +0200640 .of_match_table = dw8250_of_match,
Heikki Krogerus6a7320c2013-01-10 11:25:10 +0200641 .acpi_match_table = ACPI_PTR(dw8250_acpi_match),
Jamie Iles7d4008e2011-08-26 19:04:50 +0100642 },
643 .probe = dw8250_probe,
Bill Pemberton2d47b712012-11-19 13:21:34 -0500644 .remove = dw8250_remove,
Jamie Iles7d4008e2011-08-26 19:04:50 +0100645};
646
Axel Linc8381c152011-11-28 19:22:15 +0800647module_platform_driver(dw8250_platform_driver);
Jamie Iles7d4008e2011-08-26 19:04:50 +0100648
649MODULE_AUTHOR("Jamie Iles");
650MODULE_LICENSE("GPL");
651MODULE_DESCRIPTION("Synopsys DesignWare 8250 serial port driver");