8250_dw.c 15.8 KB
Newer Older
J
Jamie Iles 已提交
1 2 3 4
/*
 * Synopsys DesignWare 8250 driver.
 *
 * Copyright 2011 Picochip, Jamie Iles.
5
 * Copyright 2013 Intel Corporation
J
Jamie Iles 已提交
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * The Synopsys DesignWare 8250 has an extra feature whereby it detects if the
 * LCR is written whilst busy.  If it is, then a busy detect interrupt is
 * raised, the LCR needs to be rewritten and the uart status register read.
 */
#include <linux/device.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/serial_8250.h>
#include <linux/serial_reg.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
26
#include <linux/acpi.h>
27
#include <linux/clk.h>
28
#include <linux/reset.h>
29
#include <linux/pm_runtime.h>
J
Jamie Iles 已提交
30

31 32
#include <asm/byteorder.h>

33 34
#include "8250.h"

35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
/* Offsets for the DesignWare specific registers */
#define DW_UART_USR	0x1f /* UART Status Register */
#define DW_UART_CPR	0xf4 /* Component Parameter Register */
#define DW_UART_UCV	0xf8 /* UART Component Version */

/* Component Parameter Register bits */
#define DW_UART_CPR_ABP_DATA_WIDTH	(3 << 0)
#define DW_UART_CPR_AFCE_MODE		(1 << 4)
#define DW_UART_CPR_THRE_MODE		(1 << 5)
#define DW_UART_CPR_SIR_MODE		(1 << 6)
#define DW_UART_CPR_SIR_LP_MODE		(1 << 7)
#define DW_UART_CPR_ADDITIONAL_FEATURES	(1 << 8)
#define DW_UART_CPR_FIFO_ACCESS		(1 << 9)
#define DW_UART_CPR_FIFO_STAT		(1 << 10)
#define DW_UART_CPR_SHADOW		(1 << 11)
#define DW_UART_CPR_ENCODED_PARMS	(1 << 12)
#define DW_UART_CPR_DMA_EXTRA		(1 << 13)
#define DW_UART_CPR_FIFO_MODE		(0xff << 16)
/* Helper for fifo size calculation */
#define DW_UART_CPR_FIFO_SIZE(a)	(((a >> 16) & 0xff) * 16)


J
Jamie Iles 已提交
57
struct dw8250_data {
58 59 60
	u8			usr_reg;
	int			last_mcr;
	int			line;
61 62
	int			msr_mask_on;
	int			msr_mask_off;
63
	struct clk		*clk;
64
	struct clk		*pclk;
65
	struct reset_control	*rst;
66
	struct uart_8250_dma	dma;
J
Jamie Iles 已提交
67 68
};

69 70 71 72 73 74
#define BYT_PRV_CLK			0x800
#define BYT_PRV_CLK_EN			(1 << 0)
#define BYT_PRV_CLK_M_VAL_SHIFT		1
#define BYT_PRV_CLK_N_VAL_SHIFT		16
#define BYT_PRV_CLK_UPDATE		(1 << 31)

75 76 77 78 79 80 81 82 83 84
static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value)
{
	struct dw8250_data *d = p->private_data;

	/* If reading MSR, report CTS asserted when auto-CTS/RTS enabled */
	if (offset == UART_MSR && d->last_mcr & UART_MCR_AFE) {
		value |= UART_MSR_CTS;
		value &= ~UART_MSR_DCTS;
	}

85 86 87 88 89 90
	/* Override any modem control signals if needed */
	if (offset == UART_MSR) {
		value |= d->msr_mask_on;
		value &= ~d->msr_mask_off;
	}

91 92 93
	return value;
}

94 95
static void dw8250_force_idle(struct uart_port *p)
{
96 97 98
	struct uart_8250_port *up = up_to_u8250p(p);

	serial8250_clear_and_reinit_fifos(up);
99 100 101
	(void)p->serial_in(p, UART_RX);
}

J
Jamie Iles 已提交
102 103 104 105
static void dw8250_serial_out(struct uart_port *p, int offset, int value)
{
	struct dw8250_data *d = p->private_data;

106 107 108 109
	if (offset == UART_MCR)
		d->last_mcr = value;

	writeb(value, p->membase + (offset << p->regshift));
110 111 112 113 114

	/* Make sure LCR write wasn't ignored */
	if (offset == UART_LCR) {
		int tries = 1000;
		while (tries--) {
115 116
			unsigned int lcr = p->serial_in(p, UART_LCR);
			if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR))
117 118 119 120
				return;
			dw8250_force_idle(p);
			writeb(value, p->membase + (UART_LCR << p->regshift));
		}
121 122 123 124
		/*
		 * FIXME: this deadlocks if port->lock is already held
		 * dev_err(p->dev, "Couldn't set LCR to %d\n", value);
		 */
125
	}
J
Jamie Iles 已提交
126 127 128 129
}

static unsigned int dw8250_serial_in(struct uart_port *p, int offset)
{
130
	unsigned int value = readb(p->membase + (offset << p->regshift));
J
Jamie Iles 已提交
131

132
	return dw8250_modify_msr(p, offset, value);
J
Jamie Iles 已提交
133 134
}

135 136
#ifdef CONFIG_64BIT
static unsigned int dw8250_serial_inq(struct uart_port *p, int offset)
137
{
138 139 140 141 142
	unsigned int value;

	value = (u8)__raw_readq(p->membase + (offset << p->regshift));

	return dw8250_modify_msr(p, offset, value);
143 144
}

145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
static void dw8250_serial_outq(struct uart_port *p, int offset, int value)
{
	struct dw8250_data *d = p->private_data;

	if (offset == UART_MCR)
		d->last_mcr = value;

	value &= 0xff;
	__raw_writeq(value, p->membase + (offset << p->regshift));
	/* Read back to ensure register write ordering. */
	__raw_readq(p->membase + (UART_LCR << p->regshift));

	/* Make sure LCR write wasn't ignored */
	if (offset == UART_LCR) {
		int tries = 1000;
		while (tries--) {
			unsigned int lcr = p->serial_in(p, UART_LCR);
			if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR))
				return;
			dw8250_force_idle(p);
			__raw_writeq(value & 0xff,
				     p->membase + (UART_LCR << p->regshift));
		}
168 169 170 171
		/*
		 * FIXME: this deadlocks if port->lock is already held
		 * dev_err(p->dev, "Couldn't set LCR to %d\n", value);
		 */
172 173 174 175
	}
}
#endif /* CONFIG_64BIT */

J
Jamie Iles 已提交
176 177 178 179
static void dw8250_serial_out32(struct uart_port *p, int offset, int value)
{
	struct dw8250_data *d = p->private_data;

180 181 182 183
	if (offset == UART_MCR)
		d->last_mcr = value;

	writel(value, p->membase + (offset << p->regshift));
184 185 186 187 188

	/* Make sure LCR write wasn't ignored */
	if (offset == UART_LCR) {
		int tries = 1000;
		while (tries--) {
189 190
			unsigned int lcr = p->serial_in(p, UART_LCR);
			if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR))
191 192 193 194
				return;
			dw8250_force_idle(p);
			writel(value, p->membase + (UART_LCR << p->regshift));
		}
195 196 197 198
		/*
		 * FIXME: this deadlocks if port->lock is already held
		 * dev_err(p->dev, "Couldn't set LCR to %d\n", value);
		 */
199
	}
J
Jamie Iles 已提交
200 201 202 203
}

static unsigned int dw8250_serial_in32(struct uart_port *p, int offset)
{
204
	unsigned int value = readl(p->membase + (offset << p->regshift));
J
Jamie Iles 已提交
205

206
	return dw8250_modify_msr(p, offset, value);
J
Jamie Iles 已提交
207 208 209 210 211 212 213 214 215 216
}

static int dw8250_handle_irq(struct uart_port *p)
{
	struct dw8250_data *d = p->private_data;
	unsigned int iir = p->serial_in(p, UART_IIR);

	if (serial8250_handle_irq(p, iir)) {
		return 1;
	} else if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
217
		/* Clear the USR */
218
		(void)p->serial_in(p, d->usr_reg);
J
Jamie Iles 已提交
219 220 221 222 223 224 225

		return 1;
	}

	return 0;
}

226 227 228 229 230 231 232 233 234 235 236 237
static void
dw8250_do_pm(struct uart_port *port, unsigned int state, unsigned int old)
{
	if (!state)
		pm_runtime_get_sync(port->dev);

	serial8250_do_pm(port, state, old);

	if (state)
		pm_runtime_put_sync_suspend(port->dev);
}

238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263
static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios,
			       struct ktermios *old)
{
	unsigned int baud = tty_termios_baud_rate(termios);
	struct dw8250_data *d = p->private_data;
	unsigned int rate;
	int ret;

	if (IS_ERR(d->clk) || !old)
		goto out;

	/* Not requesting clock rates below 1.8432Mhz */
	if (baud < 115200)
		baud = 115200;

	clk_disable_unprepare(d->clk);
	rate = clk_round_rate(d->clk, baud * 16);
	ret = clk_set_rate(d->clk, rate);
	clk_prepare_enable(d->clk);

	if (!ret)
		p->uartclk = rate;
out:
	serial8250_do_set_termios(p, termios, old);
}

264 265
static bool dw8250_dma_filter(struct dma_chan *chan, void *param)
{
266
	return false;
267 268
}

269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302
static void dw8250_setup_port(struct uart_8250_port *up)
{
	struct uart_port	*p = &up->port;
	u32			reg = readl(p->membase + DW_UART_UCV);

	/*
	 * If the Component Version Register returns zero, we know that
	 * ADDITIONAL_FEATURES are not enabled. No need to go any further.
	 */
	if (!reg)
		return;

	dev_dbg_ratelimited(p->dev, "Designware UART version %c.%c%c\n",
		(reg >> 24) & 0xff, (reg >> 16) & 0xff, (reg >> 8) & 0xff);

	reg = readl(p->membase + DW_UART_CPR);
	if (!reg)
		return;

	/* Select the type based on fifo */
	if (reg & DW_UART_CPR_FIFO_MODE) {
		p->type = PORT_16550A;
		p->flags |= UPF_FIXED_TYPE;
		p->fifosize = DW_UART_CPR_FIFO_SIZE(reg);
		up->tx_loadsz = p->fifosize;
		up->capabilities = UART_CAP_FIFO;
	}

	if (reg & DW_UART_CPR_AFCE_MODE)
		up->capabilities |= UART_CAP_AFE;
}

static int dw8250_probe_of(struct uart_port *p,
			   struct dw8250_data *data)
303 304
{
	struct device_node	*np = p->dev->of_node;
305
	struct uart_8250_port *up = up_to_u8250p(p);
306
	u32			val;
307
	bool has_ucv = true;
308
	int id;
309

310
#ifdef CONFIG_64BIT
311
	if (of_device_is_compatible(np, "cavium,octeon-3860-uart")) {
312 313
		p->serial_in = dw8250_serial_inq;
		p->serial_out = dw8250_serial_outq;
314
		p->flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE;
315 316 317
		p->type = PORT_OCTEON;
		data->usr_reg = 0x27;
		has_ucv = false;
318 319 320
	} else
#endif
	if (!of_property_read_u32(np, "reg-io-width", &val)) {
321 322 323 324 325 326 327 328 329 330 331 332 333
		switch (val) {
		case 1:
			break;
		case 4:
			p->iotype = UPIO_MEM32;
			p->serial_in = dw8250_serial_in32;
			p->serial_out = dw8250_serial_out32;
			break;
		default:
			dev_err(p->dev, "unsupported reg-io-width (%u)\n", val);
			return -EINVAL;
		}
	}
334
	if (has_ucv)
335
		dw8250_setup_port(up);
336

337 338 339 340 341 342 343 344
	/* if we have a valid fifosize, try hooking up DMA here */
	if (p->fifosize) {
		up->dma = &data->dma;

		up->dma->rxconf.src_maxburst = p->fifosize / 4;
		up->dma->txconf.dst_maxburst = p->fifosize / 4;
	}

345 346 347
	if (!of_property_read_u32(np, "reg-shift", &val))
		p->regshift = val;

348 349 350 351 352
	/* get index of serial line, if found in DT aliases */
	id = of_alias_get_id(np, "serial");
	if (id >= 0)
		p->line = id;

353 354 355 356 357 358 359 360 361 362 363 364 365
	if (of_property_read_bool(np, "dcd-override")) {
		/* Always report DCD as active */
		data->msr_mask_on |= UART_MSR_DCD;
		data->msr_mask_off |= UART_MSR_DDCD;
	}

	if (of_property_read_bool(np, "dsr-override")) {
		/* Always report DSR as active */
		data->msr_mask_on |= UART_MSR_DSR;
		data->msr_mask_off |= UART_MSR_DDSR;
	}

	if (of_property_read_bool(np, "cts-override")) {
366 367 368
		/* Always report CTS as active */
		data->msr_mask_on |= UART_MSR_CTS;
		data->msr_mask_off |= UART_MSR_DCTS;
369 370 371 372 373 374 375 376
	}

	if (of_property_read_bool(np, "ri-override")) {
		/* Always report Ring indicator as inactive */
		data->msr_mask_off |= UART_MSR_RI;
		data->msr_mask_off |= UART_MSR_TERI;
	}

377 378 379 380 381
	/* clock got configured through clk api, all done */
	if (p->uartclk)
		return 0;

	/* try to find out clock frequency from DT as fallback */
382
	if (of_property_read_u32(np, "clock-frequency", &val)) {
383
		dev_err(p->dev, "clk or clock-frequency not defined\n");
384 385 386 387 388 389 390
		return -EINVAL;
	}
	p->uartclk = val;

	return 0;
}

391 392
static int dw8250_probe_acpi(struct uart_8250_port *up,
			     struct dw8250_data *data)
393
{
394
	const struct acpi_device_id *id;
395
	struct uart_port *p = &up->port;
396

397 398
	dw8250_setup_port(up);

399 400 401 402 403 404 405 406 407
	id = acpi_match_device(p->dev->driver->acpi_match_table, p->dev);
	if (!id)
		return -ENODEV;

	if (!p->uartclk)
		if (device_property_read_u32(p->dev, "clock-frequency",
					     &p->uartclk))
			return -EINVAL;

408 409 410 411
	p->iotype = UPIO_MEM32;
	p->serial_in = dw8250_serial_in32;
	p->serial_out = dw8250_serial_out32;
	p->regshift = 2;
412

413
	up->dma = &data->dma;
414 415 416

	up->dma->rxconf.src_maxburst = p->fifosize / 4;
	up->dma->txconf.dst_maxburst = p->fifosize / 4;
417

418
	up->port.set_termios = dw8250_set_termios;
419

420 421 422
	return 0;
}

B
Bill Pemberton 已提交
423
static int dw8250_probe(struct platform_device *pdev)
J
Jamie Iles 已提交
424
{
425
	struct uart_8250_port uart = {};
J
Jamie Iles 已提交
426
	struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
427
	int irq = platform_get_irq(pdev, 0);
J
Jamie Iles 已提交
428
	struct dw8250_data *data;
429
	int err;
J
Jamie Iles 已提交
430

431 432
	if (!regs) {
		dev_err(&pdev->dev, "no registers defined\n");
J
Jamie Iles 已提交
433 434 435
		return -EINVAL;
	}

436 437 438 439 440 441
	if (irq < 0) {
		if (irq != -EPROBE_DEFER)
			dev_err(&pdev->dev, "cannot get irq\n");
		return irq;
	}

442 443
	spin_lock_init(&uart.port.lock);
	uart.port.mapbase = regs->start;
444
	uart.port.irq = irq;
445
	uart.port.handle_irq = dw8250_handle_irq;
446
	uart.port.pm = dw8250_do_pm;
447
	uart.port.type = PORT_8250;
H
Heikki Krogerus 已提交
448
	uart.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_FIXED_PORT;
449
	uart.port.dev = &pdev->dev;
J
Jamie Iles 已提交
450

451 452
	uart.port.membase = devm_ioremap(&pdev->dev, regs->start,
					 resource_size(regs));
H
Heikki Krogerus 已提交
453 454 455
	if (!uart.port.membase)
		return -ENOMEM;

456 457 458 459
	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
	if (!data)
		return -ENOMEM;

460
	data->usr_reg = DW_UART_USR;
461
	data->clk = devm_clk_get(&pdev->dev, "baudclk");
462
	if (IS_ERR(data->clk) && PTR_ERR(data->clk) != -EPROBE_DEFER)
463
		data->clk = devm_clk_get(&pdev->dev, NULL);
464 465
	if (IS_ERR(data->clk) && PTR_ERR(data->clk) == -EPROBE_DEFER)
		return -EPROBE_DEFER;
466
	if (!IS_ERR(data->clk)) {
467 468 469 470 471 472 473 474 475
		err = clk_prepare_enable(data->clk);
		if (err)
			dev_warn(&pdev->dev, "could not enable optional baudclk: %d\n",
				 err);
		else
			uart.port.uartclk = clk_get_rate(data->clk);
	}

	data->pclk = devm_clk_get(&pdev->dev, "apb_pclk");
476 477 478 479
	if (IS_ERR(data->clk) && PTR_ERR(data->clk) == -EPROBE_DEFER) {
		err = -EPROBE_DEFER;
		goto err_clk;
	}
480 481 482 483
	if (!IS_ERR(data->pclk)) {
		err = clk_prepare_enable(data->pclk);
		if (err) {
			dev_err(&pdev->dev, "could not enable apb_pclk\n");
484
			goto err_clk;
485
		}
486 487
	}

488
	data->rst = devm_reset_control_get_optional(&pdev->dev, NULL);
489 490 491 492
	if (IS_ERR(data->rst) && PTR_ERR(data->rst) == -EPROBE_DEFER) {
		err = -EPROBE_DEFER;
		goto err_pclk;
	}
493 494 495
	if (!IS_ERR(data->rst))
		reset_control_deassert(data->rst);

496 497 498 499
	data->dma.rx_param = data;
	data->dma.tx_param = data;
	data->dma.fn = dw8250_dma_filter;

500 501 502
	uart.port.iotype = UPIO_MEM;
	uart.port.serial_in = dw8250_serial_in;
	uart.port.serial_out = dw8250_serial_out;
503
	uart.port.private_data = data;
504 505

	if (pdev->dev.of_node) {
506
		err = dw8250_probe_of(&uart.port, data);
507
		if (err)
508
			goto err_reset;
509
	} else if (ACPI_HANDLE(&pdev->dev)) {
510
		err = dw8250_probe_acpi(&uart, data);
511
		if (err)
512
			goto err_reset;
513
	} else {
514 515
		err = -ENODEV;
		goto err_reset;
J
Jamie Iles 已提交
516 517
	}

518
	data->line = serial8250_register_8250_port(&uart);
519 520 521 522
	if (data->line < 0) {
		err = data->line;
		goto err_reset;
	}
J
Jamie Iles 已提交
523 524 525

	platform_set_drvdata(pdev, data);

526 527 528
	pm_runtime_set_active(&pdev->dev);
	pm_runtime_enable(&pdev->dev);

J
Jamie Iles 已提交
529
	return 0;
530 531 532 533 534 535 536 537 538 539 540 541 542 543

err_reset:
	if (!IS_ERR(data->rst))
		reset_control_assert(data->rst);

err_pclk:
	if (!IS_ERR(data->pclk))
		clk_disable_unprepare(data->pclk);

err_clk:
	if (!IS_ERR(data->clk))
		clk_disable_unprepare(data->clk);

	return err;
J
Jamie Iles 已提交
544 545
}

B
Bill Pemberton 已提交
546
static int dw8250_remove(struct platform_device *pdev)
J
Jamie Iles 已提交
547 548 549
{
	struct dw8250_data *data = platform_get_drvdata(pdev);

550 551
	pm_runtime_get_sync(&pdev->dev);

J
Jamie Iles 已提交
552 553
	serial8250_unregister_port(data->line);

554 555 556
	if (!IS_ERR(data->rst))
		reset_control_assert(data->rst);

557 558 559
	if (!IS_ERR(data->pclk))
		clk_disable_unprepare(data->pclk);

560 561 562
	if (!IS_ERR(data->clk))
		clk_disable_unprepare(data->clk);

563 564 565
	pm_runtime_disable(&pdev->dev);
	pm_runtime_put_noidle(&pdev->dev);

J
Jamie Iles 已提交
566 567 568
	return 0;
}

569
#ifdef CONFIG_PM_SLEEP
570
static int dw8250_suspend(struct device *dev)
571
{
572
	struct dw8250_data *data = dev_get_drvdata(dev);
573 574 575 576 577 578

	serial8250_suspend_port(data->line);

	return 0;
}

579
static int dw8250_resume(struct device *dev)
580
{
581
	struct dw8250_data *data = dev_get_drvdata(dev);
582 583 584 585 586

	serial8250_resume_port(data->line);

	return 0;
}
587
#endif /* CONFIG_PM_SLEEP */
588

589
#ifdef CONFIG_PM
590 591 592 593
static int dw8250_runtime_suspend(struct device *dev)
{
	struct dw8250_data *data = dev_get_drvdata(dev);

594 595
	if (!IS_ERR(data->clk))
		clk_disable_unprepare(data->clk);
596

597 598 599
	if (!IS_ERR(data->pclk))
		clk_disable_unprepare(data->pclk);

600 601 602 603 604 605 606
	return 0;
}

static int dw8250_runtime_resume(struct device *dev)
{
	struct dw8250_data *data = dev_get_drvdata(dev);

607 608 609
	if (!IS_ERR(data->pclk))
		clk_prepare_enable(data->pclk);

610 611
	if (!IS_ERR(data->clk))
		clk_prepare_enable(data->clk);
612 613 614 615 616 617 618 619 620 621

	return 0;
}
#endif

static const struct dev_pm_ops dw8250_pm_ops = {
	SET_SYSTEM_SLEEP_PM_OPS(dw8250_suspend, dw8250_resume)
	SET_RUNTIME_PM_OPS(dw8250_runtime_suspend, dw8250_runtime_resume, NULL)
};

622
static const struct of_device_id dw8250_of_match[] = {
J
Jamie Iles 已提交
623
	{ .compatible = "snps,dw-apb-uart" },
624
	{ .compatible = "cavium,octeon-3860-uart" },
J
Jamie Iles 已提交
625 626
	{ /* Sentinel */ }
};
627
MODULE_DEVICE_TABLE(of, dw8250_of_match);
J
Jamie Iles 已提交
628

629
static const struct acpi_device_id dw8250_acpi_match[] = {
630 631
	{ "INT33C4", 0 },
	{ "INT33C5", 0 },
632 633
	{ "INT3434", 0 },
	{ "INT3435", 0 },
634
	{ "80860F0A", 0 },
635
	{ "8086228A", 0 },
636
	{ "APMC0D08", 0},
637 638 639 640
	{ },
};
MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match);

J
Jamie Iles 已提交
641 642 643
static struct platform_driver dw8250_platform_driver = {
	.driver = {
		.name		= "dw-apb-uart",
644
		.pm		= &dw8250_pm_ops,
645
		.of_match_table	= dw8250_of_match,
646
		.acpi_match_table = ACPI_PTR(dw8250_acpi_match),
J
Jamie Iles 已提交
647 648
	},
	.probe			= dw8250_probe,
649
	.remove			= dw8250_remove,
J
Jamie Iles 已提交
650 651
};

652
module_platform_driver(dw8250_platform_driver);
J
Jamie Iles 已提交
653 654 655 656

MODULE_AUTHOR("Jamie Iles");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Synopsys DesignWare 8250 serial port driver");
657
MODULE_ALIAS("platform:dw-apb-uart");