diff options
author | Olof Johansson <olof@lixom.net> | 2014-01-02 13:57:05 -0500 |
---|---|---|
committer | Olof Johansson <olof@lixom.net> | 2014-01-02 13:57:05 -0500 |
commit | c7fed591a6d5ce080482e4237bd02c99857c0d4f (patch) | |
tree | f697a76b366a228e21c222061bcef7000b973949 /drivers/tty | |
parent | efcf3d38f128cfbfc7a62c3a5dc3fb42991c12e5 (diff) | |
parent | 20bdcab8268cb05702e12ae9013be96ecc7ec3a6 (diff) |
Merge tag 'renesas-sh-sci3-for-v3.14' of git://git.kernel.org/pub/scm/linux/kernel/git/horms/renesas into next/drivers
From Simon Horman:
Third Round of Renesas SH SCI Updates for v3.14
* Add Device Tree Support
* Remove platform data mapbase and irqs fields
* Remove platform data scbrr_algo_id field
* tag 'renesas-sh-sci3-for-v3.14' of git://git.kernel.org/pub/scm/linux/kernel/git/horms/renesas:
serial: sh-sci: Add OF support
serial: sh-sci: Add device tree bindings documentation
serial: sh-sci: Remove platform data mapbase and irqs fields
serial: sh-sci: Remove platform data scbrr_algo_id field
Signed-off-by: Olof Johansson <olof@lixom.net>
Diffstat (limited to 'drivers/tty')
-rw-r--r-- | drivers/tty/serial/sh-sci.c | 187 |
1 files changed, 137 insertions, 50 deletions
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index e4bf0e435af6..be33d2b0613b 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include <linux/module.h> | 39 | #include <linux/module.h> |
40 | #include <linux/mm.h> | 40 | #include <linux/mm.h> |
41 | #include <linux/notifier.h> | 41 | #include <linux/notifier.h> |
42 | #include <linux/of.h> | ||
42 | #include <linux/platform_device.h> | 43 | #include <linux/platform_device.h> |
43 | #include <linux/pm_runtime.h> | 44 | #include <linux/pm_runtime.h> |
44 | #include <linux/scatterlist.h> | 45 | #include <linux/scatterlist.h> |
@@ -58,6 +59,23 @@ | |||
58 | 59 | ||
59 | #include "sh-sci.h" | 60 | #include "sh-sci.h" |
60 | 61 | ||
62 | /* Offsets into the sci_port->irqs array */ | ||
63 | enum { | ||
64 | SCIx_ERI_IRQ, | ||
65 | SCIx_RXI_IRQ, | ||
66 | SCIx_TXI_IRQ, | ||
67 | SCIx_BRI_IRQ, | ||
68 | SCIx_NR_IRQS, | ||
69 | |||
70 | SCIx_MUX_IRQ = SCIx_NR_IRQS, /* special case */ | ||
71 | }; | ||
72 | |||
73 | #define SCIx_IRQ_IS_MUXED(port) \ | ||
74 | ((port)->irqs[SCIx_ERI_IRQ] == \ | ||
75 | (port)->irqs[SCIx_RXI_IRQ]) || \ | ||
76 | ((port)->irqs[SCIx_ERI_IRQ] && \ | ||
77 | ((port)->irqs[SCIx_RXI_IRQ] < 0)) | ||
78 | |||
61 | struct sci_port { | 79 | struct sci_port { |
62 | struct uart_port port; | 80 | struct uart_port port; |
63 | 81 | ||
@@ -1757,17 +1775,6 @@ static unsigned int sci_scbrr_calc(struct sci_port *s, unsigned int bps, | |||
1757 | if (s->sampling_rate) | 1775 | if (s->sampling_rate) |
1758 | return DIV_ROUND_CLOSEST(freq, s->sampling_rate * bps) - 1; | 1776 | return DIV_ROUND_CLOSEST(freq, s->sampling_rate * bps) - 1; |
1759 | 1777 | ||
1760 | switch (s->cfg->scbrr_algo_id) { | ||
1761 | case SCBRR_ALGO_1: | ||
1762 | return freq / (16 * bps); | ||
1763 | case SCBRR_ALGO_2: | ||
1764 | return DIV_ROUND_CLOSEST(freq, 32 * bps) - 1; | ||
1765 | case SCBRR_ALGO_3: | ||
1766 | return freq / (8 * bps); | ||
1767 | case SCBRR_ALGO_4: | ||
1768 | return DIV_ROUND_CLOSEST(freq, 16 * bps) - 1; | ||
1769 | } | ||
1770 | |||
1771 | /* Warn, but use a safe default */ | 1778 | /* Warn, but use a safe default */ |
1772 | WARN_ON(1); | 1779 | WARN_ON(1); |
1773 | 1780 | ||
@@ -2105,36 +2112,27 @@ static int sci_init_single(struct platform_device *dev, | |||
2105 | port->iotype = UPIO_MEM; | 2112 | port->iotype = UPIO_MEM; |
2106 | port->line = index; | 2113 | port->line = index; |
2107 | 2114 | ||
2108 | if (dev->num_resources) { | 2115 | res = platform_get_resource(dev, IORESOURCE_MEM, 0); |
2109 | /* Device has resources, use them. */ | 2116 | if (res == NULL) |
2110 | res = platform_get_resource(dev, IORESOURCE_MEM, 0); | 2117 | return -ENOMEM; |
2111 | if (res == NULL) | ||
2112 | return -ENOMEM; | ||
2113 | 2118 | ||
2114 | port->mapbase = res->start; | 2119 | port->mapbase = res->start; |
2115 | 2120 | ||
2116 | for (i = 0; i < ARRAY_SIZE(sci_port->irqs); ++i) | 2121 | for (i = 0; i < ARRAY_SIZE(sci_port->irqs); ++i) |
2117 | sci_port->irqs[i] = platform_get_irq(dev, i); | 2122 | sci_port->irqs[i] = platform_get_irq(dev, i); |
2118 | 2123 | ||
2119 | /* The SCI generates several interrupts. They can be muxed | 2124 | /* The SCI generates several interrupts. They can be muxed together or |
2120 | * together or connected to different interrupt lines. In the | 2125 | * connected to different interrupt lines. In the muxed case only one |
2121 | * muxed case only one interrupt resource is specified. In the | 2126 | * interrupt resource is specified. In the non-muxed case three or four |
2122 | * non-muxed case three or four interrupt resources are | 2127 | * interrupt resources are specified, as the BRI interrupt is optional. |
2123 | * specified, as the BRI interrupt is optional. | 2128 | */ |
2124 | */ | 2129 | if (sci_port->irqs[0] < 0) |
2125 | if (sci_port->irqs[0] < 0) | 2130 | return -ENXIO; |
2126 | return -ENXIO; | ||
2127 | 2131 | ||
2128 | if (sci_port->irqs[1] < 0) { | 2132 | if (sci_port->irqs[1] < 0) { |
2129 | sci_port->irqs[1] = sci_port->irqs[0]; | 2133 | sci_port->irqs[1] = sci_port->irqs[0]; |
2130 | sci_port->irqs[2] = sci_port->irqs[0]; | 2134 | sci_port->irqs[2] = sci_port->irqs[0]; |
2131 | sci_port->irqs[3] = sci_port->irqs[0]; | 2135 | sci_port->irqs[3] = sci_port->irqs[0]; |
2132 | } | ||
2133 | } else { | ||
2134 | /* No resources, use old-style platform data. */ | ||
2135 | port->mapbase = p->mapbase; | ||
2136 | for (i = 0; i < ARRAY_SIZE(sci_port->irqs); ++i) | ||
2137 | sci_port->irqs[i] = p->irqs[i] ? p->irqs[i] : -ENXIO; | ||
2138 | } | 2136 | } |
2139 | 2137 | ||
2140 | if (p->regtype == SCIx_PROBE_REGTYPE) { | 2138 | if (p->regtype == SCIx_PROBE_REGTYPE) { |
@@ -2176,17 +2174,12 @@ static int sci_init_single(struct platform_device *dev, | |||
2176 | break; | 2174 | break; |
2177 | } | 2175 | } |
2178 | 2176 | ||
2179 | /* Set the sampling rate if the baud rate calculation algorithm isn't | 2177 | /* SCIFA on sh7723 and sh7724 need a custom sampling rate that doesn't |
2180 | * specified. | 2178 | * match the SoC datasheet, this should be investigated. Let platform |
2179 | * data override the sampling rate for now. | ||
2181 | */ | 2180 | */ |
2182 | if (p->scbrr_algo_id == SCBRR_ALGO_NONE) { | 2181 | sci_port->sampling_rate = p->sampling_rate ? p->sampling_rate |
2183 | /* SCIFA on sh7723 and sh7724 need a custom sampling rate that | 2182 | : sampling_rate; |
2184 | * doesn't match the SoC datasheet, this should be investigated. | ||
2185 | * Let platform data override the sampling rate for now. | ||
2186 | */ | ||
2187 | sci_port->sampling_rate = p->sampling_rate ? p->sampling_rate | ||
2188 | : sampling_rate; | ||
2189 | } | ||
2190 | 2183 | ||
2191 | if (!early) { | 2184 | if (!early) { |
2192 | sci_port->iclk = clk_get(&dev->dev, "sci_ick"); | 2185 | sci_port->iclk = clk_get(&dev->dev, "sci_ick"); |
@@ -2423,6 +2416,83 @@ static int sci_remove(struct platform_device *dev) | |||
2423 | return 0; | 2416 | return 0; |
2424 | } | 2417 | } |
2425 | 2418 | ||
2419 | struct sci_port_info { | ||
2420 | unsigned int type; | ||
2421 | unsigned int regtype; | ||
2422 | }; | ||
2423 | |||
2424 | static const struct of_device_id of_sci_match[] = { | ||
2425 | { | ||
2426 | .compatible = "renesas,scif", | ||
2427 | .data = (void *)&(const struct sci_port_info) { | ||
2428 | .type = PORT_SCIF, | ||
2429 | .regtype = SCIx_SH4_SCIF_REGTYPE, | ||
2430 | }, | ||
2431 | }, { | ||
2432 | .compatible = "renesas,scifa", | ||
2433 | .data = (void *)&(const struct sci_port_info) { | ||
2434 | .type = PORT_SCIFA, | ||
2435 | .regtype = SCIx_SCIFA_REGTYPE, | ||
2436 | }, | ||
2437 | }, { | ||
2438 | .compatible = "renesas,scifb", | ||
2439 | .data = (void *)&(const struct sci_port_info) { | ||
2440 | .type = PORT_SCIFB, | ||
2441 | .regtype = SCIx_SCIFB_REGTYPE, | ||
2442 | }, | ||
2443 | }, { | ||
2444 | .compatible = "renesas,hscif", | ||
2445 | .data = (void *)&(const struct sci_port_info) { | ||
2446 | .type = PORT_HSCIF, | ||
2447 | .regtype = SCIx_HSCIF_REGTYPE, | ||
2448 | }, | ||
2449 | }, { | ||
2450 | /* Terminator */ | ||
2451 | }, | ||
2452 | }; | ||
2453 | MODULE_DEVICE_TABLE(of, of_sci_match); | ||
2454 | |||
2455 | static struct plat_sci_port * | ||
2456 | sci_parse_dt(struct platform_device *pdev, unsigned int *dev_id) | ||
2457 | { | ||
2458 | struct device_node *np = pdev->dev.of_node; | ||
2459 | const struct of_device_id *match; | ||
2460 | const struct sci_port_info *info; | ||
2461 | struct plat_sci_port *p; | ||
2462 | int id; | ||
2463 | |||
2464 | if (!IS_ENABLED(CONFIG_OF) || !np) | ||
2465 | return NULL; | ||
2466 | |||
2467 | match = of_match_node(of_sci_match, pdev->dev.of_node); | ||
2468 | if (!match) | ||
2469 | return NULL; | ||
2470 | |||
2471 | info = match->data; | ||
2472 | |||
2473 | p = devm_kzalloc(&pdev->dev, sizeof(struct plat_sci_port), GFP_KERNEL); | ||
2474 | if (!p) { | ||
2475 | dev_err(&pdev->dev, "failed to allocate DT config data\n"); | ||
2476 | return NULL; | ||
2477 | } | ||
2478 | |||
2479 | /* Get the line number for the aliases node. */ | ||
2480 | id = of_alias_get_id(np, "serial"); | ||
2481 | if (id < 0) { | ||
2482 | dev_err(&pdev->dev, "failed to get alias id (%d)\n", id); | ||
2483 | return NULL; | ||
2484 | } | ||
2485 | |||
2486 | *dev_id = id; | ||
2487 | |||
2488 | p->flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF; | ||
2489 | p->type = info->type; | ||
2490 | p->regtype = info->regtype; | ||
2491 | p->scscr = SCSCR_RE | SCSCR_TE; | ||
2492 | |||
2493 | return p; | ||
2494 | } | ||
2495 | |||
2426 | static int sci_probe_single(struct platform_device *dev, | 2496 | static int sci_probe_single(struct platform_device *dev, |
2427 | unsigned int index, | 2497 | unsigned int index, |
2428 | struct plat_sci_port *p, | 2498 | struct plat_sci_port *p, |
@@ -2455,8 +2525,9 @@ static int sci_probe_single(struct platform_device *dev, | |||
2455 | 2525 | ||
2456 | static int sci_probe(struct platform_device *dev) | 2526 | static int sci_probe(struct platform_device *dev) |
2457 | { | 2527 | { |
2458 | struct plat_sci_port *p = dev_get_platdata(&dev->dev); | 2528 | struct plat_sci_port *p; |
2459 | struct sci_port *sp = &sci_ports[dev->id]; | 2529 | struct sci_port *sp; |
2530 | unsigned int dev_id; | ||
2460 | int ret; | 2531 | int ret; |
2461 | 2532 | ||
2462 | /* | 2533 | /* |
@@ -2467,9 +2538,24 @@ static int sci_probe(struct platform_device *dev) | |||
2467 | if (is_early_platform_device(dev)) | 2538 | if (is_early_platform_device(dev)) |
2468 | return sci_probe_earlyprintk(dev); | 2539 | return sci_probe_earlyprintk(dev); |
2469 | 2540 | ||
2541 | if (dev->dev.of_node) { | ||
2542 | p = sci_parse_dt(dev, &dev_id); | ||
2543 | if (p == NULL) | ||
2544 | return -EINVAL; | ||
2545 | } else { | ||
2546 | p = dev->dev.platform_data; | ||
2547 | if (p == NULL) { | ||
2548 | dev_err(&dev->dev, "no platform data supplied\n"); | ||
2549 | return -EINVAL; | ||
2550 | } | ||
2551 | |||
2552 | dev_id = dev->id; | ||
2553 | } | ||
2554 | |||
2555 | sp = &sci_ports[dev_id]; | ||
2470 | platform_set_drvdata(dev, sp); | 2556 | platform_set_drvdata(dev, sp); |
2471 | 2557 | ||
2472 | ret = sci_probe_single(dev, dev->id, p, sp); | 2558 | ret = sci_probe_single(dev, dev_id, p, sp); |
2473 | if (ret) | 2559 | if (ret) |
2474 | return ret; | 2560 | return ret; |
2475 | 2561 | ||
@@ -2521,6 +2607,7 @@ static struct platform_driver sci_driver = { | |||
2521 | .name = "sh-sci", | 2607 | .name = "sh-sci", |
2522 | .owner = THIS_MODULE, | 2608 | .owner = THIS_MODULE, |
2523 | .pm = &sci_dev_pm_ops, | 2609 | .pm = &sci_dev_pm_ops, |
2610 | .of_match_table = of_match_ptr(of_sci_match), | ||
2524 | }, | 2611 | }, |
2525 | }; | 2612 | }; |
2526 | 2613 | ||