diff options
author | John Rigby <jrigby@freescale.com> | 2008-01-28 12:28:56 -0500 |
---|---|---|
committer | Grant Likely <grant.likely@secretlab.ca> | 2008-02-06 16:05:40 -0500 |
commit | 25ae3a0739c69425a911925b43213895a9802b98 (patch) | |
tree | 250695da67fc1414080f96e55cd68b4d92d6da43 /drivers/serial/mpc52xx_uart.c | |
parent | 599f030cc596cd41a0f966afd4cee2e2fc48ee86 (diff) |
[POWERPC] mpc512x: Add MPC512x PSC support to MPC52xx psc driver
Add 512x support using the psc_ops framework established
with the previous patch.
All 512x PSCs share the same interrupt so add
IRQF_SHARED to irq flags.
Signed-off-by: John Rigby <jrigby@freescale.com>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
Diffstat (limited to 'drivers/serial/mpc52xx_uart.c')
-rw-r--r-- | drivers/serial/mpc52xx_uart.c | 177 |
1 files changed, 171 insertions, 6 deletions
diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c index 7ab73fa4a80f..821facd10bbc 100644 --- a/drivers/serial/mpc52xx_uart.c +++ b/drivers/serial/mpc52xx_uart.c | |||
@@ -16,6 +16,9 @@ | |||
16 | * Some of the code has been inspired/copied from the 2.4 code written | 16 | * Some of the code has been inspired/copied from the 2.4 code written |
17 | * by Dale Farnsworth <dfarnsworth@mvista.com>. | 17 | * by Dale Farnsworth <dfarnsworth@mvista.com>. |
18 | * | 18 | * |
19 | * Copyright (C) 2008 Freescale Semiconductor Inc. | ||
20 | * John Rigby <jrigby@gmail.com> | ||
21 | * Added support for MPC5121 | ||
19 | * Copyright (C) 2006 Secret Lab Technologies Ltd. | 22 | * Copyright (C) 2006 Secret Lab Technologies Ltd. |
20 | * Grant Likely <grant.likely@secretlab.ca> | 23 | * Grant Likely <grant.likely@secretlab.ca> |
21 | * Copyright (C) 2004-2006 Sylvain Munaut <tnt@246tNt.com> | 24 | * Copyright (C) 2004-2006 Sylvain Munaut <tnt@246tNt.com> |
@@ -78,6 +81,7 @@ | |||
78 | #endif | 81 | #endif |
79 | 82 | ||
80 | #include <asm/mpc52xx.h> | 83 | #include <asm/mpc52xx.h> |
84 | #include <asm/mpc512x.h> | ||
81 | #include <asm/mpc52xx_psc.h> | 85 | #include <asm/mpc52xx_psc.h> |
82 | 86 | ||
83 | #if defined(CONFIG_SERIAL_MPC52xx_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) | 87 | #if defined(CONFIG_SERIAL_MPC52xx_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) |
@@ -129,13 +133,29 @@ static irqreturn_t mpc52xx_uart_int(int irq, void *dev_id); | |||
129 | 133 | ||
130 | #if defined(CONFIG_PPC_MERGE) | 134 | #if defined(CONFIG_PPC_MERGE) |
131 | static struct of_device_id mpc52xx_uart_of_match[] = { | 135 | static struct of_device_id mpc52xx_uart_of_match[] = { |
132 | { .type = "serial", .compatible = "fsl,mpc5200-psc-uart", }, | 136 | #ifdef CONFIG_PPC_MPC52xx |
133 | { .type = "serial", .compatible = "mpc5200-psc-uart", }, /* lite5200 */ | 137 | { .compatible = "fsl,mpc5200-psc-uart", .data = &mpc52xx_psc_ops, }, |
134 | { .type = "serial", .compatible = "mpc5200-serial", }, /* efika */ | 138 | /* binding used by old lite5200 device trees: */ |
139 | { .compatible = "mpc5200-psc-uart", .data = &mpc52xx_psc_ops, }, | ||
140 | /* binding used by efika: */ | ||
141 | { .compatible = "mpc5200-serial", .data = &mpc52xx_psc_ops, }, | ||
142 | #endif | ||
143 | #ifdef CONFIG_PPC_MPC512x | ||
144 | { .compatible = "fsl,mpc5121-psc-uart", .data = &mpc512x_psc_ops, }, | ||
145 | {}, | ||
146 | #endif | ||
147 | }; | ||
148 | #if defined(CONFIG_PPC_MERGE) | ||
149 | static const struct of_device_id mpc52xx_uart_of_match[] = { | ||
150 | {.type = "serial", | ||
151 | .compatible = "mpc5200-psc-uart", | ||
152 | #endif | ||
135 | {}, | 153 | {}, |
136 | }; | 154 | }; |
137 | #endif | 155 | #endif |
138 | 156 | ||
157 | #endif | ||
158 | |||
139 | /* ======================================================================== */ | 159 | /* ======================================================================== */ |
140 | /* PSC fifo operations for isolating differences between 52xx and 512x */ | 160 | /* PSC fifo operations for isolating differences between 52xx and 512x */ |
141 | /* ======================================================================== */ | 161 | /* ======================================================================== */ |
@@ -159,6 +179,7 @@ struct psc_ops { | |||
159 | unsigned long (*getuartclk)(void *p); | 179 | unsigned long (*getuartclk)(void *p); |
160 | }; | 180 | }; |
161 | 181 | ||
182 | #ifdef CONFIG_PPC_MPC52xx | ||
162 | #define FIFO_52xx(port) ((struct mpc52xx_psc_fifo __iomem *)(PSC(port)+1)) | 183 | #define FIFO_52xx(port) ((struct mpc52xx_psc_fifo __iomem *)(PSC(port)+1)) |
163 | static void mpc52xx_psc_fifo_init(struct uart_port *port) | 184 | static void mpc52xx_psc_fifo_init(struct uart_port *port) |
164 | { | 185 | { |
@@ -291,7 +312,145 @@ static struct psc_ops mpc52xx_psc_ops = { | |||
291 | .getuartclk = mpc52xx_getuartclk, | 312 | .getuartclk = mpc52xx_getuartclk, |
292 | }; | 313 | }; |
293 | 314 | ||
294 | static struct psc_ops *psc_ops = &mpc52xx_psc_ops; | 315 | #endif /* CONFIG_MPC52xx */ |
316 | |||
317 | #ifdef CONFIG_PPC_MPC512x | ||
318 | #define FIFO_512x(port) ((struct mpc512x_psc_fifo __iomem *)(PSC(port)+1)) | ||
319 | static void mpc512x_psc_fifo_init(struct uart_port *port) | ||
320 | { | ||
321 | out_be32(&FIFO_512x(port)->txcmd, MPC512x_PSC_FIFO_RESET_SLICE); | ||
322 | out_be32(&FIFO_512x(port)->txcmd, MPC512x_PSC_FIFO_ENABLE_SLICE); | ||
323 | out_be32(&FIFO_512x(port)->txalarm, 1); | ||
324 | out_be32(&FIFO_512x(port)->tximr, 0); | ||
325 | |||
326 | out_be32(&FIFO_512x(port)->rxcmd, MPC512x_PSC_FIFO_RESET_SLICE); | ||
327 | out_be32(&FIFO_512x(port)->rxcmd, MPC512x_PSC_FIFO_ENABLE_SLICE); | ||
328 | out_be32(&FIFO_512x(port)->rxalarm, 1); | ||
329 | out_be32(&FIFO_512x(port)->rximr, 0); | ||
330 | |||
331 | out_be32(&FIFO_512x(port)->tximr, MPC512x_PSC_FIFO_ALARM); | ||
332 | out_be32(&FIFO_512x(port)->rximr, MPC512x_PSC_FIFO_ALARM); | ||
333 | } | ||
334 | |||
335 | static int mpc512x_psc_raw_rx_rdy(struct uart_port *port) | ||
336 | { | ||
337 | return !(in_be32(&FIFO_512x(port)->rxsr) & MPC512x_PSC_FIFO_EMPTY); | ||
338 | } | ||
339 | |||
340 | static int mpc512x_psc_raw_tx_rdy(struct uart_port *port) | ||
341 | { | ||
342 | return !(in_be32(&FIFO_512x(port)->txsr) & MPC512x_PSC_FIFO_FULL); | ||
343 | } | ||
344 | |||
345 | static int mpc512x_psc_rx_rdy(struct uart_port *port) | ||
346 | { | ||
347 | return in_be32(&FIFO_512x(port)->rxsr) | ||
348 | & in_be32(&FIFO_512x(port)->rximr) | ||
349 | & MPC512x_PSC_FIFO_ALARM; | ||
350 | } | ||
351 | |||
352 | static int mpc512x_psc_tx_rdy(struct uart_port *port) | ||
353 | { | ||
354 | return in_be32(&FIFO_512x(port)->txsr) | ||
355 | & in_be32(&FIFO_512x(port)->tximr) | ||
356 | & MPC512x_PSC_FIFO_ALARM; | ||
357 | } | ||
358 | |||
359 | static int mpc512x_psc_tx_empty(struct uart_port *port) | ||
360 | { | ||
361 | return in_be32(&FIFO_512x(port)->txsr) | ||
362 | & MPC512x_PSC_FIFO_EMPTY; | ||
363 | } | ||
364 | |||
365 | static void mpc512x_psc_stop_rx(struct uart_port *port) | ||
366 | { | ||
367 | unsigned long rx_fifo_imr; | ||
368 | |||
369 | rx_fifo_imr = in_be32(&FIFO_512x(port)->rximr); | ||
370 | rx_fifo_imr &= ~MPC512x_PSC_FIFO_ALARM; | ||
371 | out_be32(&FIFO_512x(port)->rximr, rx_fifo_imr); | ||
372 | } | ||
373 | |||
374 | static void mpc512x_psc_start_tx(struct uart_port *port) | ||
375 | { | ||
376 | unsigned long tx_fifo_imr; | ||
377 | |||
378 | tx_fifo_imr = in_be32(&FIFO_512x(port)->tximr); | ||
379 | tx_fifo_imr |= MPC512x_PSC_FIFO_ALARM; | ||
380 | out_be32(&FIFO_512x(port)->tximr, tx_fifo_imr); | ||
381 | } | ||
382 | |||
383 | static void mpc512x_psc_stop_tx(struct uart_port *port) | ||
384 | { | ||
385 | unsigned long tx_fifo_imr; | ||
386 | |||
387 | tx_fifo_imr = in_be32(&FIFO_512x(port)->tximr); | ||
388 | tx_fifo_imr &= ~MPC512x_PSC_FIFO_ALARM; | ||
389 | out_be32(&FIFO_512x(port)->tximr, tx_fifo_imr); | ||
390 | } | ||
391 | |||
392 | static void mpc512x_psc_rx_clr_irq(struct uart_port *port) | ||
393 | { | ||
394 | out_be32(&FIFO_512x(port)->rxisr, in_be32(&FIFO_512x(port)->rxisr)); | ||
395 | } | ||
396 | |||
397 | static void mpc512x_psc_tx_clr_irq(struct uart_port *port) | ||
398 | { | ||
399 | out_be32(&FIFO_512x(port)->txisr, in_be32(&FIFO_512x(port)->txisr)); | ||
400 | } | ||
401 | |||
402 | static void mpc512x_psc_write_char(struct uart_port *port, unsigned char c) | ||
403 | { | ||
404 | out_8(&FIFO_512x(port)->txdata_8, c); | ||
405 | } | ||
406 | |||
407 | static unsigned char mpc512x_psc_read_char(struct uart_port *port) | ||
408 | { | ||
409 | return in_8(&FIFO_512x(port)->rxdata_8); | ||
410 | } | ||
411 | |||
412 | static void mpc512x_psc_cw_disable_ints(struct uart_port *port) | ||
413 | { | ||
414 | port->read_status_mask = | ||
415 | in_be32(&FIFO_512x(port)->tximr) << 16 | | ||
416 | in_be32(&FIFO_512x(port)->rximr); | ||
417 | out_be32(&FIFO_512x(port)->tximr, 0); | ||
418 | out_be32(&FIFO_512x(port)->rximr, 0); | ||
419 | } | ||
420 | |||
421 | static void mpc512x_psc_cw_restore_ints(struct uart_port *port) | ||
422 | { | ||
423 | out_be32(&FIFO_512x(port)->tximr, | ||
424 | (port->read_status_mask >> 16) & 0x7f); | ||
425 | out_be32(&FIFO_512x(port)->rximr, port->read_status_mask & 0x7f); | ||
426 | } | ||
427 | |||
428 | static unsigned long mpc512x_getuartclk(void *p) | ||
429 | { | ||
430 | return mpc512x_find_ips_freq(p); | ||
431 | } | ||
432 | |||
433 | static struct psc_ops mpc512x_psc_ops = { | ||
434 | .fifo_init = mpc512x_psc_fifo_init, | ||
435 | .raw_rx_rdy = mpc512x_psc_raw_rx_rdy, | ||
436 | .raw_tx_rdy = mpc512x_psc_raw_tx_rdy, | ||
437 | .rx_rdy = mpc512x_psc_rx_rdy, | ||
438 | .tx_rdy = mpc512x_psc_tx_rdy, | ||
439 | .tx_empty = mpc512x_psc_tx_empty, | ||
440 | .stop_rx = mpc512x_psc_stop_rx, | ||
441 | .start_tx = mpc512x_psc_start_tx, | ||
442 | .stop_tx = mpc512x_psc_stop_tx, | ||
443 | .rx_clr_irq = mpc512x_psc_rx_clr_irq, | ||
444 | .tx_clr_irq = mpc512x_psc_tx_clr_irq, | ||
445 | .write_char = mpc512x_psc_write_char, | ||
446 | .read_char = mpc512x_psc_read_char, | ||
447 | .cw_disable_ints = mpc512x_psc_cw_disable_ints, | ||
448 | .cw_restore_ints = mpc512x_psc_cw_restore_ints, | ||
449 | .getuartclk = mpc512x_getuartclk, | ||
450 | }; | ||
451 | #endif | ||
452 | |||
453 | static struct psc_ops *psc_ops; | ||
295 | 454 | ||
296 | /* ======================================================================== */ | 455 | /* ======================================================================== */ |
297 | /* UART operations */ | 456 | /* UART operations */ |
@@ -381,7 +540,8 @@ mpc52xx_uart_startup(struct uart_port *port) | |||
381 | 540 | ||
382 | /* Request IRQ */ | 541 | /* Request IRQ */ |
383 | ret = request_irq(port->irq, mpc52xx_uart_int, | 542 | ret = request_irq(port->irq, mpc52xx_uart_int, |
384 | IRQF_DISABLED | IRQF_SAMPLE_RANDOM, "mpc52xx_psc_uart", port); | 543 | IRQF_DISABLED | IRQF_SAMPLE_RANDOM | IRQF_SHARED, |
544 | "mpc52xx_psc_uart", port); | ||
385 | if (ret) | 545 | if (ret) |
386 | return ret; | 546 | return ret; |
387 | 547 | ||
@@ -1208,15 +1368,19 @@ mpc52xx_uart_of_enumerate(void) | |||
1208 | static int enum_done; | 1368 | static int enum_done; |
1209 | struct device_node *np; | 1369 | struct device_node *np; |
1210 | const unsigned int *devno; | 1370 | const unsigned int *devno; |
1371 | const struct of_device_id *match; | ||
1211 | int i; | 1372 | int i; |
1212 | 1373 | ||
1213 | if (enum_done) | 1374 | if (enum_done) |
1214 | return; | 1375 | return; |
1215 | 1376 | ||
1216 | for_each_node_by_type(np, "serial") { | 1377 | for_each_node_by_type(np, "serial") { |
1217 | if (!of_match_node(mpc52xx_uart_of_match, np)) | 1378 | match = of_match_node(mpc52xx_uart_of_match, np); |
1379 | if (!match) | ||
1218 | continue; | 1380 | continue; |
1219 | 1381 | ||
1382 | psc_ops = match->data; | ||
1383 | |||
1220 | /* Is a particular device number requested? */ | 1384 | /* Is a particular device number requested? */ |
1221 | devno = of_get_property(np, "port-number", NULL); | 1385 | devno = of_get_property(np, "port-number", NULL); |
1222 | mpc52xx_uart_of_assign(np, devno ? *devno : -1); | 1386 | mpc52xx_uart_of_assign(np, devno ? *devno : -1); |
@@ -1277,6 +1441,7 @@ mpc52xx_uart_init(void) | |||
1277 | return ret; | 1441 | return ret; |
1278 | } | 1442 | } |
1279 | #else | 1443 | #else |
1444 | psc_ops = &mpc52xx_psc_ops; | ||
1280 | ret = platform_driver_register(&mpc52xx_uart_platform_driver); | 1445 | ret = platform_driver_register(&mpc52xx_uart_platform_driver); |
1281 | if (ret) { | 1446 | if (ret) { |
1282 | printk(KERN_ERR "%s: platform_driver_register failed (%i)\n", | 1447 | printk(KERN_ERR "%s: platform_driver_register failed (%i)\n", |