blob: d48b50641e9a6c63ed874399f6b587ccd844556d [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>
Jamie Iles7d4008e2011-08-26 19:04:50 +010020#include <linux/serial_reg.h>
21#include <linux/of.h>
22#include <linux/of_irq.h>
23#include <linux/of_platform.h>
24#include <linux/platform_device.h>
25#include <linux/slab.h>
Heikki Krogerus6a7320c2013-01-10 11:25:10 +020026#include <linux/acpi.h>
Emilio Lópeze302cd92013-03-29 00:15:49 +010027#include <linux/clk.h>
Chen-Yu Tsai7fe090b2014-07-23 23:33:06 +080028#include <linux/reset.h>
Heikki Krogerusffc3ae62013-04-10 16:58:28 +030029#include <linux/pm_runtime.h>
Jamie Iles7d4008e2011-08-26 19:04:50 +010030
David Daneyd5f1af72013-06-19 20:37:27 +000031#include <asm/byteorder.h>
32
Heikki Krogerus7277b2a2013-01-10 11:25:12 +020033#include "8250.h"
34
Heikki Krogerus30046df2013-01-10 11:25:09 +020035/* Offsets for the DesignWare specific registers */
36#define DW_UART_USR 0x1f /* UART Status Register */
37#define DW_UART_CPR 0xf4 /* Component Parameter Register */
38#define DW_UART_UCV 0xf8 /* UART Component Version */
39
40/* Component Parameter Register bits */
41#define DW_UART_CPR_ABP_DATA_WIDTH (3 << 0)
42#define DW_UART_CPR_AFCE_MODE (1 << 4)
43#define DW_UART_CPR_THRE_MODE (1 << 5)
44#define DW_UART_CPR_SIR_MODE (1 << 6)
45#define DW_UART_CPR_SIR_LP_MODE (1 << 7)
46#define DW_UART_CPR_ADDITIONAL_FEATURES (1 << 8)
47#define DW_UART_CPR_FIFO_ACCESS (1 << 9)
48#define DW_UART_CPR_FIFO_STAT (1 << 10)
49#define DW_UART_CPR_SHADOW (1 << 11)
50#define DW_UART_CPR_ENCODED_PARMS (1 << 12)
51#define DW_UART_CPR_DMA_EXTRA (1 << 13)
52#define DW_UART_CPR_FIFO_MODE (0xff << 16)
53/* Helper for fifo size calculation */
54#define DW_UART_CPR_FIFO_SIZE(a) (((a >> 16) & 0xff) * 16)
55
56
Jamie Iles7d4008e2011-08-26 19:04:50 +010057struct dw8250_data {
Heikki Krogerusfe95855532013-09-05 17:34:53 +030058 u8 usr_reg;
Heikki Krogerusfe95855532013-09-05 17:34:53 +030059 int last_mcr;
60 int line;
Desmond Liudfd37662015-02-26 16:35:57 -080061 int msr_mask_on;
62 int msr_mask_off;
Heikki Krogerusfe95855532013-09-05 17:34:53 +030063 struct clk *clk;
Heiko Stübner7d78cbe2014-06-16 15:25:17 +020064 struct clk *pclk;
Chen-Yu Tsai7fe090b2014-07-23 23:33:06 +080065 struct reset_control *rst;
Heikki Krogerusfe95855532013-09-05 17:34:53 +030066 struct uart_8250_dma dma;
Jamie Iles7d4008e2011-08-26 19:04:50 +010067};
68
Loic Poulainc439c332014-04-24 11:46:14 +020069#define BYT_PRV_CLK 0x800
70#define BYT_PRV_CLK_EN (1 << 0)
71#define BYT_PRV_CLK_M_VAL_SHIFT 1
72#define BYT_PRV_CLK_N_VAL_SHIFT 16
73#define BYT_PRV_CLK_UPDATE (1 << 31)
74
Tim Kryger33acbb82013-08-16 13:50:15 -070075static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value)
76{
77 struct dw8250_data *d = p->private_data;
78
79 /* If reading MSR, report CTS asserted when auto-CTS/RTS enabled */
80 if (offset == UART_MSR && d->last_mcr & UART_MCR_AFE) {
81 value |= UART_MSR_CTS;
82 value &= ~UART_MSR_DCTS;
83 }
84
Desmond Liudfd37662015-02-26 16:35:57 -080085 /* Override any modem control signals if needed */
86 if (offset == UART_MSR) {
87 value |= d->msr_mask_on;
88 value &= ~d->msr_mask_off;
89 }
90
Tim Kryger33acbb82013-08-16 13:50:15 -070091 return value;
92}
93
Tim Krygerc49436b2013-10-01 10:18:08 -070094static void dw8250_force_idle(struct uart_port *p)
95{
Andy Shevchenkob1261c82014-07-14 14:26:14 +030096 struct uart_8250_port *up = up_to_u8250p(p);
97
98 serial8250_clear_and_reinit_fifos(up);
Tim Krygerc49436b2013-10-01 10:18:08 -070099 (void)p->serial_in(p, UART_RX);
100}
101
Jamie Iles7d4008e2011-08-26 19:04:50 +0100102static void dw8250_serial_out(struct uart_port *p, int offset, int value)
103{
104 struct dw8250_data *d = p->private_data;
105
Tim Kryger33acbb82013-08-16 13:50:15 -0700106 if (offset == UART_MCR)
107 d->last_mcr = value;
108
109 writeb(value, p->membase + (offset << p->regshift));
Tim Krygerc49436b2013-10-01 10:18:08 -0700110
111 /* Make sure LCR write wasn't ignored */
112 if (offset == UART_LCR) {
113 int tries = 1000;
114 while (tries--) {
James Hogan6979f8d2013-12-10 22:28:04 +0000115 unsigned int lcr = p->serial_in(p, UART_LCR);
116 if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR))
Tim Krygerc49436b2013-10-01 10:18:08 -0700117 return;
118 dw8250_force_idle(p);
119 writeb(value, p->membase + (UART_LCR << p->regshift));
120 }
Peter Hurley7fd6f642015-03-11 09:19:16 -0400121 /*
122 * FIXME: this deadlocks if port->lock is already held
123 * dev_err(p->dev, "Couldn't set LCR to %d\n", value);
124 */
Tim Krygerc49436b2013-10-01 10:18:08 -0700125 }
Jamie Iles7d4008e2011-08-26 19:04:50 +0100126}
127
128static unsigned int dw8250_serial_in(struct uart_port *p, int offset)
129{
Tim Kryger33acbb82013-08-16 13:50:15 -0700130 unsigned int value = readb(p->membase + (offset << p->regshift));
Jamie Iles7d4008e2011-08-26 19:04:50 +0100131
Tim Kryger33acbb82013-08-16 13:50:15 -0700132 return dw8250_modify_msr(p, offset, value);
Jamie Iles7d4008e2011-08-26 19:04:50 +0100133}
134
David Daneybca20922014-11-14 17:26:19 +0300135#ifdef CONFIG_64BIT
136static unsigned int dw8250_serial_inq(struct uart_port *p, int offset)
David Daneyd5f1af72013-06-19 20:37:27 +0000137{
David Daneybca20922014-11-14 17:26:19 +0300138 unsigned int value;
139
140 value = (u8)__raw_readq(p->membase + (offset << p->regshift));
141
142 return dw8250_modify_msr(p, offset, value);
David Daneyd5f1af72013-06-19 20:37:27 +0000143}
144
David Daneybca20922014-11-14 17:26:19 +0300145static void dw8250_serial_outq(struct uart_port *p, int offset, int value)
146{
147 struct dw8250_data *d = p->private_data;
148
149 if (offset == UART_MCR)
150 d->last_mcr = value;
151
152 value &= 0xff;
153 __raw_writeq(value, p->membase + (offset << p->regshift));
154 /* Read back to ensure register write ordering. */
155 __raw_readq(p->membase + (UART_LCR << p->regshift));
156
157 /* Make sure LCR write wasn't ignored */
158 if (offset == UART_LCR) {
159 int tries = 1000;
160 while (tries--) {
161 unsigned int lcr = p->serial_in(p, UART_LCR);
162 if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR))
163 return;
164 dw8250_force_idle(p);
165 __raw_writeq(value & 0xff,
166 p->membase + (UART_LCR << p->regshift));
167 }
Peter Hurley7fd6f642015-03-11 09:19:16 -0400168 /*
169 * FIXME: this deadlocks if port->lock is already held
170 * dev_err(p->dev, "Couldn't set LCR to %d\n", value);
171 */
David Daneybca20922014-11-14 17:26:19 +0300172 }
173}
174#endif /* CONFIG_64BIT */
175
Jamie Iles7d4008e2011-08-26 19:04:50 +0100176static void dw8250_serial_out32(struct uart_port *p, int offset, int value)
177{
178 struct dw8250_data *d = p->private_data;
179
Tim Kryger33acbb82013-08-16 13:50:15 -0700180 if (offset == UART_MCR)
181 d->last_mcr = value;
182
183 writel(value, p->membase + (offset << p->regshift));
Tim Krygerc49436b2013-10-01 10:18:08 -0700184
185 /* Make sure LCR write wasn't ignored */
186 if (offset == UART_LCR) {
187 int tries = 1000;
188 while (tries--) {
James Hogan6979f8d2013-12-10 22:28:04 +0000189 unsigned int lcr = p->serial_in(p, UART_LCR);
190 if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR))
Tim Krygerc49436b2013-10-01 10:18:08 -0700191 return;
192 dw8250_force_idle(p);
193 writel(value, p->membase + (UART_LCR << p->regshift));
194 }
Peter Hurley7fd6f642015-03-11 09:19:16 -0400195 /*
196 * FIXME: this deadlocks if port->lock is already held
197 * dev_err(p->dev, "Couldn't set LCR to %d\n", value);
198 */
Tim Krygerc49436b2013-10-01 10:18:08 -0700199 }
Jamie Iles7d4008e2011-08-26 19:04:50 +0100200}
201
202static unsigned int dw8250_serial_in32(struct uart_port *p, int offset)
203{
Tim Kryger33acbb82013-08-16 13:50:15 -0700204 unsigned int value = readl(p->membase + (offset << p->regshift));
Jamie Iles7d4008e2011-08-26 19:04:50 +0100205
Tim Kryger33acbb82013-08-16 13:50:15 -0700206 return dw8250_modify_msr(p, offset, value);
Jamie Iles7d4008e2011-08-26 19:04:50 +0100207}
208
Jamie Iles7d4008e2011-08-26 19:04:50 +0100209static int dw8250_handle_irq(struct uart_port *p)
210{
211 struct dw8250_data *d = p->private_data;
212 unsigned int iir = p->serial_in(p, UART_IIR);
213
214 if (serial8250_handle_irq(p, iir)) {
215 return 1;
216 } else if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
Tim Krygerc49436b2013-10-01 10:18:08 -0700217 /* Clear the USR */
David Daneyd5f1af72013-06-19 20:37:27 +0000218 (void)p->serial_in(p, d->usr_reg);
Jamie Iles7d4008e2011-08-26 19:04:50 +0100219
220 return 1;
221 }
222
223 return 0;
224}
225
Heikki Krogerusffc3ae62013-04-10 16:58:28 +0300226static void
227dw8250_do_pm(struct uart_port *port, unsigned int state, unsigned int old)
228{
229 if (!state)
230 pm_runtime_get_sync(port->dev);
231
232 serial8250_do_pm(port, state, old);
233
234 if (state)
235 pm_runtime_put_sync_suspend(port->dev);
236}
237
Heikki Krogerus4e26b132014-06-05 16:51:40 +0300238static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios,
239 struct ktermios *old)
240{
241 unsigned int baud = tty_termios_baud_rate(termios);
242 struct dw8250_data *d = p->private_data;
243 unsigned int rate;
244 int ret;
245
246 if (IS_ERR(d->clk) || !old)
247 goto out;
248
249 /* Not requesting clock rates below 1.8432Mhz */
250 if (baud < 115200)
251 baud = 115200;
252
253 clk_disable_unprepare(d->clk);
254 rate = clk_round_rate(d->clk, baud * 16);
255 ret = clk_set_rate(d->clk, rate);
256 clk_prepare_enable(d->clk);
257
258 if (!ret)
259 p->uartclk = rate;
260out:
261 serial8250_do_set_termios(p, termios, old);
262}
263
Heikki Krogerus7fb8c562013-09-05 17:34:54 +0300264static bool dw8250_dma_filter(struct dma_chan *chan, void *param)
265{
Andy Shevchenko9a1870c2014-08-19 20:29:22 +0300266 return false;
Heikki Krogerus7fb8c562013-09-05 17:34:54 +0300267}
268
Heikki Krogerus30046df2013-01-10 11:25:09 +0200269static void dw8250_setup_port(struct uart_8250_port *up)
270{
271 struct uart_port *p = &up->port;
272 u32 reg = readl(p->membase + DW_UART_UCV);
273
274 /*
275 * If the Component Version Register returns zero, we know that
276 * ADDITIONAL_FEATURES are not enabled. No need to go any further.
277 */
278 if (!reg)
279 return;
280
281 dev_dbg_ratelimited(p->dev, "Designware UART version %c.%c%c\n",
282 (reg >> 24) & 0xff, (reg >> 16) & 0xff, (reg >> 8) & 0xff);
283
284 reg = readl(p->membase + DW_UART_CPR);
285 if (!reg)
286 return;
287
288 /* Select the type based on fifo */
289 if (reg & DW_UART_CPR_FIFO_MODE) {
290 p->type = PORT_16550A;
291 p->flags |= UPF_FIXED_TYPE;
292 p->fifosize = DW_UART_CPR_FIFO_SIZE(reg);
293 up->tx_loadsz = p->fifosize;
Heikki Krogerus2920adb2013-04-10 16:58:31 +0300294 up->capabilities = UART_CAP_FIFO;
Heikki Krogerus30046df2013-01-10 11:25:09 +0200295 }
Heikki Krogerus2920adb2013-04-10 16:58:31 +0300296
297 if (reg & DW_UART_CPR_AFCE_MODE)
298 up->capabilities |= UART_CAP_AFE;
Heikki Krogerus30046df2013-01-10 11:25:09 +0200299}
300
David Daneyd5f1af72013-06-19 20:37:27 +0000301static int dw8250_probe_of(struct uart_port *p,
302 struct dw8250_data *data)
303{
304 struct device_node *np = p->dev->of_node;
Andy Shevchenkob1261c82014-07-14 14:26:14 +0300305 struct uart_8250_port *up = up_to_u8250p(p);
David Daneyd5f1af72013-06-19 20:37:27 +0000306 u32 val;
307 bool has_ucv = true;
Julien CHAUVEAUf77d55a2014-11-04 11:45:55 +0100308 int id;
David Daneyd5f1af72013-06-19 20:37:27 +0000309
David Daneybca20922014-11-14 17:26:19 +0300310#ifdef CONFIG_64BIT
David Daneyd5f1af72013-06-19 20:37:27 +0000311 if (of_device_is_compatible(np, "cavium,octeon-3860-uart")) {
David Daneybca20922014-11-14 17:26:19 +0300312 p->serial_in = dw8250_serial_inq;
313 p->serial_out = dw8250_serial_outq;
Andy Shevchenkod8782c72014-06-06 15:24:10 +0300314 p->flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE;
David Daneyd5f1af72013-06-19 20:37:27 +0000315 p->type = PORT_OCTEON;
316 data->usr_reg = 0x27;
317 has_ucv = false;
David Daneybca20922014-11-14 17:26:19 +0300318 } else
319#endif
320 if (!of_property_read_u32(np, "reg-io-width", &val)) {
David Daneyd5f1af72013-06-19 20:37:27 +0000321 switch (val) {
322 case 1:
323 break;
324 case 4:
325 p->iotype = UPIO_MEM32;
326 p->serial_in = dw8250_serial_in32;
327 p->serial_out = dw8250_serial_out32;
328 break;
329 default:
330 dev_err(p->dev, "unsupported reg-io-width (%u)\n", val);
331 return -EINVAL;
332 }
333 }
334 if (has_ucv)
Andy Shevchenkob1261c82014-07-14 14:26:14 +0300335 dw8250_setup_port(up);
David Daneyd5f1af72013-06-19 20:37:27 +0000336
Ray Juia8b26e12014-10-07 17:35:47 -0700337 /* if we have a valid fifosize, try hooking up DMA here */
338 if (p->fifosize) {
339 up->dma = &data->dma;
340
341 up->dma->rxconf.src_maxburst = p->fifosize / 4;
342 up->dma->txconf.dst_maxburst = p->fifosize / 4;
343 }
344
David Daneyd5f1af72013-06-19 20:37:27 +0000345 if (!of_property_read_u32(np, "reg-shift", &val))
346 p->regshift = val;
347
Julien CHAUVEAUf77d55a2014-11-04 11:45:55 +0100348 /* get index of serial line, if found in DT aliases */
349 id = of_alias_get_id(np, "serial");
350 if (id >= 0)
351 p->line = id;
352
Desmond Liudfd37662015-02-26 16:35:57 -0800353 if (of_property_read_bool(np, "dcd-override")) {
354 /* Always report DCD as active */
355 data->msr_mask_on |= UART_MSR_DCD;
356 data->msr_mask_off |= UART_MSR_DDCD;
357 }
358
359 if (of_property_read_bool(np, "dsr-override")) {
360 /* Always report DSR as active */
361 data->msr_mask_on |= UART_MSR_DSR;
362 data->msr_mask_off |= UART_MSR_DDSR;
363 }
364
365 if (of_property_read_bool(np, "cts-override")) {
Dmitry Torokhovda291692015-03-09 17:37:31 -0700366 /* Always report CTS as active */
367 data->msr_mask_on |= UART_MSR_CTS;
368 data->msr_mask_off |= UART_MSR_DCTS;
Desmond Liudfd37662015-02-26 16:35:57 -0800369 }
370
371 if (of_property_read_bool(np, "ri-override")) {
372 /* Always report Ring indicator as inactive */
373 data->msr_mask_off |= UART_MSR_RI;
374 data->msr_mask_off |= UART_MSR_TERI;
375 }
376
David Daneyd5f1af72013-06-19 20:37:27 +0000377 return 0;
378}
379
Heikki Krogerus0788c392015-05-26 15:59:32 +0300380static bool dw8250_idma_filter(struct dma_chan *chan, void *param)
381{
382 struct device *dev = param;
383
384 if (dev != chan->device->dev->parent)
385 return false;
386
387 return true;
388}
389
Heikki Krogerusfe95855532013-09-05 17:34:53 +0300390static int dw8250_probe_acpi(struct uart_8250_port *up,
391 struct dw8250_data *data)
David Daneyd5f1af72013-06-19 20:37:27 +0000392{
David Daneyd5f1af72013-06-19 20:37:27 +0000393 struct uart_port *p = &up->port;
394
395 dw8250_setup_port(up);
396
David Daneyd5f1af72013-06-19 20:37:27 +0000397 p->iotype = UPIO_MEM32;
398 p->serial_in = dw8250_serial_in32;
399 p->serial_out = dw8250_serial_out32;
400 p->regshift = 2;
401
Heikki Krogerus0788c392015-05-26 15:59:32 +0300402 /* Platforms with iDMA */
403 if (platform_get_resource_byname(to_platform_device(up->port.dev),
404 IORESOURCE_MEM, "lpss_priv")) {
405 data->dma.rx_param = up->port.dev->parent;
406 data->dma.tx_param = up->port.dev->parent;
407 data->dma.fn = dw8250_idma_filter;
408 }
David Daneyd5f1af72013-06-19 20:37:27 +0000409
Heikki Krogerus0788c392015-05-26 15:59:32 +0300410 up->dma = &data->dma;
David Daneyd5f1af72013-06-19 20:37:27 +0000411 up->dma->rxconf.src_maxburst = p->fifosize / 4;
412 up->dma->txconf.dst_maxburst = p->fifosize / 4;
413
Heikki Krogerus4e26b132014-06-05 16:51:40 +0300414 up->port.set_termios = dw8250_set_termios;
Loic Poulainc439c332014-04-24 11:46:14 +0200415
David Daneyd5f1af72013-06-19 20:37:27 +0000416 return 0;
417}
David Daneyd5f1af72013-06-19 20:37:27 +0000418
Bill Pemberton9671f092012-11-19 13:21:50 -0500419static int dw8250_probe(struct platform_device *pdev)
Jamie Iles7d4008e2011-08-26 19:04:50 +0100420{
Alan Cox2655a2c2012-07-12 12:59:50 +0100421 struct uart_8250_port uart = {};
Jamie Iles7d4008e2011-08-26 19:04:50 +0100422 struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Alexey Brodkin833b1f72015-03-03 18:11:14 +0300423 int irq = platform_get_irq(pdev, 0);
Jamie Iles7d4008e2011-08-26 19:04:50 +0100424 struct dw8250_data *data;
Heikki Krogerusa7260c82013-01-10 11:25:08 +0200425 int err;
Jamie Iles7d4008e2011-08-26 19:04:50 +0100426
Alexey Brodkin833b1f72015-03-03 18:11:14 +0300427 if (!regs) {
428 dev_err(&pdev->dev, "no registers defined\n");
Jamie Iles7d4008e2011-08-26 19:04:50 +0100429 return -EINVAL;
430 }
431
Alexey Brodkin833b1f72015-03-03 18:11:14 +0300432 if (irq < 0) {
433 if (irq != -EPROBE_DEFER)
434 dev_err(&pdev->dev, "cannot get irq\n");
435 return irq;
436 }
437
Alan Cox2655a2c2012-07-12 12:59:50 +0100438 spin_lock_init(&uart.port.lock);
439 uart.port.mapbase = regs->start;
Alexey Brodkin833b1f72015-03-03 18:11:14 +0300440 uart.port.irq = irq;
Alan Cox2655a2c2012-07-12 12:59:50 +0100441 uart.port.handle_irq = dw8250_handle_irq;
Heikki Krogerusffc3ae62013-04-10 16:58:28 +0300442 uart.port.pm = dw8250_do_pm;
Alan Cox2655a2c2012-07-12 12:59:50 +0100443 uart.port.type = PORT_8250;
Heikki Krogerusf93366f2013-01-10 11:25:07 +0200444 uart.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_FIXED_PORT;
Alan Cox2655a2c2012-07-12 12:59:50 +0100445 uart.port.dev = &pdev->dev;
Jamie Iles7d4008e2011-08-26 19:04:50 +0100446
Heikki Krogerusb88d0822013-04-11 15:43:21 +0300447 uart.port.membase = devm_ioremap(&pdev->dev, regs->start,
448 resource_size(regs));
Heikki Krogerusf93366f2013-01-10 11:25:07 +0200449 if (!uart.port.membase)
450 return -ENOMEM;
451
Emilio Lópeze302cd92013-03-29 00:15:49 +0100452 data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
453 if (!data)
454 return -ENOMEM;
455
David Daneyd5f1af72013-06-19 20:37:27 +0000456 data->usr_reg = DW_UART_USR;
Heikki Krogerus23f5b3f2015-03-18 12:55:13 +0200457
458 /* Always ask for fixed clock rate from a property. */
459 device_property_read_u32(&pdev->dev, "clock-frequency",
460 &uart.port.uartclk);
461
462 /* If there is separate baudclk, get the rate from it. */
Heiko Stübner7d78cbe2014-06-16 15:25:17 +0200463 data->clk = devm_clk_get(&pdev->dev, "baudclk");
Chen-Yu Tsaic8ed99d2014-07-23 23:33:07 +0800464 if (IS_ERR(data->clk) && PTR_ERR(data->clk) != -EPROBE_DEFER)
Heiko Stübner7d78cbe2014-06-16 15:25:17 +0200465 data->clk = devm_clk_get(&pdev->dev, NULL);
Chen-Yu Tsaic8ed99d2014-07-23 23:33:07 +0800466 if (IS_ERR(data->clk) && PTR_ERR(data->clk) == -EPROBE_DEFER)
467 return -EPROBE_DEFER;
Heikki Krogerus23f5b3f2015-03-18 12:55:13 +0200468 if (!IS_ERR_OR_NULL(data->clk)) {
Heiko Stübner7d78cbe2014-06-16 15:25:17 +0200469 err = clk_prepare_enable(data->clk);
470 if (err)
471 dev_warn(&pdev->dev, "could not enable optional baudclk: %d\n",
472 err);
473 else
474 uart.port.uartclk = clk_get_rate(data->clk);
475 }
476
Heikki Krogerus23f5b3f2015-03-18 12:55:13 +0200477 /* If no clock rate is defined, fail. */
478 if (!uart.port.uartclk) {
479 dev_err(&pdev->dev, "clock rate not defined\n");
480 return -EINVAL;
481 }
482
Heiko Stübner7d78cbe2014-06-16 15:25:17 +0200483 data->pclk = devm_clk_get(&pdev->dev, "apb_pclk");
Chen-Yu Tsaic8ed99d2014-07-23 23:33:07 +0800484 if (IS_ERR(data->clk) && PTR_ERR(data->clk) == -EPROBE_DEFER) {
485 err = -EPROBE_DEFER;
486 goto err_clk;
487 }
Heiko Stübner7d78cbe2014-06-16 15:25:17 +0200488 if (!IS_ERR(data->pclk)) {
489 err = clk_prepare_enable(data->pclk);
490 if (err) {
491 dev_err(&pdev->dev, "could not enable apb_pclk\n");
Chen-Yu Tsaic8ed99d2014-07-23 23:33:07 +0800492 goto err_clk;
Heiko Stübner7d78cbe2014-06-16 15:25:17 +0200493 }
Emilio Lópeze302cd92013-03-29 00:15:49 +0100494 }
495
Chen-Yu Tsai7fe090b2014-07-23 23:33:06 +0800496 data->rst = devm_reset_control_get_optional(&pdev->dev, NULL);
Chen-Yu Tsaic8ed99d2014-07-23 23:33:07 +0800497 if (IS_ERR(data->rst) && PTR_ERR(data->rst) == -EPROBE_DEFER) {
498 err = -EPROBE_DEFER;
499 goto err_pclk;
500 }
Chen-Yu Tsai7fe090b2014-07-23 23:33:06 +0800501 if (!IS_ERR(data->rst))
502 reset_control_deassert(data->rst);
503
Heikki Krogerus7fb8c562013-09-05 17:34:54 +0300504 data->dma.rx_param = data;
505 data->dma.tx_param = data;
506 data->dma.fn = dw8250_dma_filter;
507
Alan Cox2655a2c2012-07-12 12:59:50 +0100508 uart.port.iotype = UPIO_MEM;
509 uart.port.serial_in = dw8250_serial_in;
510 uart.port.serial_out = dw8250_serial_out;
Emilio Lópeze302cd92013-03-29 00:15:49 +0100511 uart.port.private_data = data;
Heikki Krogerusa7260c82013-01-10 11:25:08 +0200512
513 if (pdev->dev.of_node) {
David Daneyd5f1af72013-06-19 20:37:27 +0000514 err = dw8250_probe_of(&uart.port, data);
Heikki Krogerusa7260c82013-01-10 11:25:08 +0200515 if (err)
Chen-Yu Tsaic8ed99d2014-07-23 23:33:07 +0800516 goto err_reset;
Heikki Krogerus6a7320c2013-01-10 11:25:10 +0200517 } else if (ACPI_HANDLE(&pdev->dev)) {
Heikki Krogerusfe95855532013-09-05 17:34:53 +0300518 err = dw8250_probe_acpi(&uart, data);
Heikki Krogerus6a7320c2013-01-10 11:25:10 +0200519 if (err)
Chen-Yu Tsaic8ed99d2014-07-23 23:33:07 +0800520 goto err_reset;
Heikki Krogerusa7260c82013-01-10 11:25:08 +0200521 } else {
Chen-Yu Tsaic8ed99d2014-07-23 23:33:07 +0800522 err = -ENODEV;
523 goto err_reset;
Jamie Iles7d4008e2011-08-26 19:04:50 +0100524 }
525
Alan Cox2655a2c2012-07-12 12:59:50 +0100526 data->line = serial8250_register_8250_port(&uart);
Chen-Yu Tsaic8ed99d2014-07-23 23:33:07 +0800527 if (data->line < 0) {
528 err = data->line;
529 goto err_reset;
530 }
Jamie Iles7d4008e2011-08-26 19:04:50 +0100531
532 platform_set_drvdata(pdev, data);
533
Heikki Krogerusffc3ae62013-04-10 16:58:28 +0300534 pm_runtime_set_active(&pdev->dev);
535 pm_runtime_enable(&pdev->dev);
536
Jamie Iles7d4008e2011-08-26 19:04:50 +0100537 return 0;
Chen-Yu Tsaic8ed99d2014-07-23 23:33:07 +0800538
539err_reset:
540 if (!IS_ERR(data->rst))
541 reset_control_assert(data->rst);
542
543err_pclk:
544 if (!IS_ERR(data->pclk))
545 clk_disable_unprepare(data->pclk);
546
547err_clk:
548 if (!IS_ERR(data->clk))
549 clk_disable_unprepare(data->clk);
550
551 return err;
Jamie Iles7d4008e2011-08-26 19:04:50 +0100552}
553
Bill Pembertonae8d8a12012-11-19 13:26:18 -0500554static int dw8250_remove(struct platform_device *pdev)
Jamie Iles7d4008e2011-08-26 19:04:50 +0100555{
556 struct dw8250_data *data = platform_get_drvdata(pdev);
557
Heikki Krogerusffc3ae62013-04-10 16:58:28 +0300558 pm_runtime_get_sync(&pdev->dev);
559
Jamie Iles7d4008e2011-08-26 19:04:50 +0100560 serial8250_unregister_port(data->line);
561
Chen-Yu Tsai7fe090b2014-07-23 23:33:06 +0800562 if (!IS_ERR(data->rst))
563 reset_control_assert(data->rst);
564
Heiko Stübner7d78cbe2014-06-16 15:25:17 +0200565 if (!IS_ERR(data->pclk))
566 clk_disable_unprepare(data->pclk);
567
Emilio Lópeze302cd92013-03-29 00:15:49 +0100568 if (!IS_ERR(data->clk))
569 clk_disable_unprepare(data->clk);
570
Heikki Krogerusffc3ae62013-04-10 16:58:28 +0300571 pm_runtime_disable(&pdev->dev);
572 pm_runtime_put_noidle(&pdev->dev);
573
Jamie Iles7d4008e2011-08-26 19:04:50 +0100574 return 0;
575}
576
Mika Westerberg13b949f2014-01-16 14:55:57 +0200577#ifdef CONFIG_PM_SLEEP
Heikki Krogerusffc3ae62013-04-10 16:58:28 +0300578static int dw8250_suspend(struct device *dev)
James Hoganb61c5ed2012-10-15 10:25:58 +0100579{
Heikki Krogerusffc3ae62013-04-10 16:58:28 +0300580 struct dw8250_data *data = dev_get_drvdata(dev);
James Hoganb61c5ed2012-10-15 10:25:58 +0100581
582 serial8250_suspend_port(data->line);
583
584 return 0;
585}
586
Heikki Krogerusffc3ae62013-04-10 16:58:28 +0300587static int dw8250_resume(struct device *dev)
James Hoganb61c5ed2012-10-15 10:25:58 +0100588{
Heikki Krogerusffc3ae62013-04-10 16:58:28 +0300589 struct dw8250_data *data = dev_get_drvdata(dev);
James Hoganb61c5ed2012-10-15 10:25:58 +0100590
591 serial8250_resume_port(data->line);
592
593 return 0;
594}
Mika Westerberg13b949f2014-01-16 14:55:57 +0200595#endif /* CONFIG_PM_SLEEP */
James Hoganb61c5ed2012-10-15 10:25:58 +0100596
Rafael J. Wysockid39fe4e2014-12-13 00:41:36 +0100597#ifdef CONFIG_PM
Heikki Krogerusffc3ae62013-04-10 16:58:28 +0300598static int dw8250_runtime_suspend(struct device *dev)
599{
600 struct dw8250_data *data = dev_get_drvdata(dev);
601
Ezequiel Garciadbd2df82013-05-07 08:27:16 -0300602 if (!IS_ERR(data->clk))
603 clk_disable_unprepare(data->clk);
Heikki Krogerusffc3ae62013-04-10 16:58:28 +0300604
Heiko Stübner7d78cbe2014-06-16 15:25:17 +0200605 if (!IS_ERR(data->pclk))
606 clk_disable_unprepare(data->pclk);
607
Heikki Krogerusffc3ae62013-04-10 16:58:28 +0300608 return 0;
609}
610
611static int dw8250_runtime_resume(struct device *dev)
612{
613 struct dw8250_data *data = dev_get_drvdata(dev);
614
Heiko Stübner7d78cbe2014-06-16 15:25:17 +0200615 if (!IS_ERR(data->pclk))
616 clk_prepare_enable(data->pclk);
617
Ezequiel Garciadbd2df82013-05-07 08:27:16 -0300618 if (!IS_ERR(data->clk))
619 clk_prepare_enable(data->clk);
Heikki Krogerusffc3ae62013-04-10 16:58:28 +0300620
621 return 0;
622}
623#endif
624
625static const struct dev_pm_ops dw8250_pm_ops = {
626 SET_SYSTEM_SLEEP_PM_OPS(dw8250_suspend, dw8250_resume)
627 SET_RUNTIME_PM_OPS(dw8250_runtime_suspend, dw8250_runtime_resume, NULL)
628};
629
Heikki Krogerusa7260c82013-01-10 11:25:08 +0200630static const struct of_device_id dw8250_of_match[] = {
Jamie Iles7d4008e2011-08-26 19:04:50 +0100631 { .compatible = "snps,dw-apb-uart" },
David Daneyd5f1af72013-06-19 20:37:27 +0000632 { .compatible = "cavium,octeon-3860-uart" },
Jamie Iles7d4008e2011-08-26 19:04:50 +0100633 { /* Sentinel */ }
634};
Heikki Krogerusa7260c82013-01-10 11:25:08 +0200635MODULE_DEVICE_TABLE(of, dw8250_of_match);
Jamie Iles7d4008e2011-08-26 19:04:50 +0100636
Heikki Krogerus6a7320c2013-01-10 11:25:10 +0200637static const struct acpi_device_id dw8250_acpi_match[] = {
Heikki Krogerusaea02e82013-04-10 16:58:29 +0300638 { "INT33C4", 0 },
639 { "INT33C5", 0 },
Mika Westerbergd24c1952013-12-10 12:56:59 +0200640 { "INT3434", 0 },
641 { "INT3435", 0 },
Heikki Krogerus4e26b132014-06-05 16:51:40 +0300642 { "80860F0A", 0 },
Alan Coxf1744422014-08-19 16:34:49 +0300643 { "8086228A", 0 },
Feng Kan5e1aeea2014-12-05 17:45:57 -0800644 { "APMC0D08", 0},
Ken Xue5ef86b72015-03-09 17:10:13 +0800645 { "AMD0020", 0 },
Heikki Krogerus6a7320c2013-01-10 11:25:10 +0200646 { },
647};
648MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match);
649
Jamie Iles7d4008e2011-08-26 19:04:50 +0100650static struct platform_driver dw8250_platform_driver = {
651 .driver = {
652 .name = "dw-apb-uart",
Heikki Krogerusffc3ae62013-04-10 16:58:28 +0300653 .pm = &dw8250_pm_ops,
Heikki Krogerusa7260c82013-01-10 11:25:08 +0200654 .of_match_table = dw8250_of_match,
Heikki Krogerus6a7320c2013-01-10 11:25:10 +0200655 .acpi_match_table = ACPI_PTR(dw8250_acpi_match),
Jamie Iles7d4008e2011-08-26 19:04:50 +0100656 },
657 .probe = dw8250_probe,
Bill Pemberton2d47b712012-11-19 13:21:34 -0500658 .remove = dw8250_remove,
Jamie Iles7d4008e2011-08-26 19:04:50 +0100659};
660
Axel Linc8381c152011-11-28 19:22:15 +0800661module_platform_driver(dw8250_platform_driver);
Jamie Iles7d4008e2011-08-26 19:04:50 +0100662
663MODULE_AUTHOR("Jamie Iles");
664MODULE_LICENSE("GPL");
665MODULE_DESCRIPTION("Synopsys DesignWare 8250 serial port driver");
Mika Westerbergf3ac3fc2015-02-04 15:03:48 +0200666MODULE_ALIAS("platform:dw-apb-uart");