diff options
-rw-r--r-- | drivers/tty/serial/sh-sci.c | 101 |
1 files changed, 98 insertions, 3 deletions
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index c4111162ec5e..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> |
@@ -2415,6 +2416,83 @@ static int sci_remove(struct platform_device *dev) | |||
2415 | return 0; | 2416 | return 0; |
2416 | } | 2417 | } |
2417 | 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 | |||
2418 | static int sci_probe_single(struct platform_device *dev, | 2496 | static int sci_probe_single(struct platform_device *dev, |
2419 | unsigned int index, | 2497 | unsigned int index, |
2420 | struct plat_sci_port *p, | 2498 | struct plat_sci_port *p, |
@@ -2447,8 +2525,9 @@ static int sci_probe_single(struct platform_device *dev, | |||
2447 | 2525 | ||
2448 | static int sci_probe(struct platform_device *dev) | 2526 | static int sci_probe(struct platform_device *dev) |
2449 | { | 2527 | { |
2450 | struct plat_sci_port *p = dev_get_platdata(&dev->dev); | 2528 | struct plat_sci_port *p; |
2451 | struct sci_port *sp = &sci_ports[dev->id]; | 2529 | struct sci_port *sp; |
2530 | unsigned int dev_id; | ||
2452 | int ret; | 2531 | int ret; |
2453 | 2532 | ||
2454 | /* | 2533 | /* |
@@ -2459,9 +2538,24 @@ static int sci_probe(struct platform_device *dev) | |||
2459 | if (is_early_platform_device(dev)) | 2538 | if (is_early_platform_device(dev)) |
2460 | return sci_probe_earlyprintk(dev); | 2539 | return sci_probe_earlyprintk(dev); |
2461 | 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]; | ||
2462 | platform_set_drvdata(dev, sp); | 2556 | platform_set_drvdata(dev, sp); |
2463 | 2557 | ||
2464 | ret = sci_probe_single(dev, dev->id, p, sp); | 2558 | ret = sci_probe_single(dev, dev_id, p, sp); |
2465 | if (ret) | 2559 | if (ret) |
2466 | return ret; | 2560 | return ret; |
2467 | 2561 | ||
@@ -2513,6 +2607,7 @@ static struct platform_driver sci_driver = { | |||
2513 | .name = "sh-sci", | 2607 | .name = "sh-sci", |
2514 | .owner = THIS_MODULE, | 2608 | .owner = THIS_MODULE, |
2515 | .pm = &sci_dev_pm_ops, | 2609 | .pm = &sci_dev_pm_ops, |
2610 | .of_match_table = of_match_ptr(of_sci_match), | ||
2516 | }, | 2611 | }, |
2517 | }; | 2612 | }; |
2518 | 2613 | ||