diff options
| -rw-r--r-- | Documentation/devicetree/bindings/tty/serial/sccnxp-serial.txt | 53 | ||||
| -rw-r--r-- | drivers/tty/serial/sccnxp.c | 46 | ||||
| -rw-r--r-- | include/linux/platform_data/serial-sccnxp.h | 6 |
3 files changed, 93 insertions, 12 deletions
diff --git a/Documentation/devicetree/bindings/tty/serial/sccnxp-serial.txt b/Documentation/devicetree/bindings/tty/serial/sccnxp-serial.txt new file mode 100644 index 000000000000..d18b1698133e --- /dev/null +++ b/Documentation/devicetree/bindings/tty/serial/sccnxp-serial.txt | |||
| @@ -0,0 +1,53 @@ | |||
| 1 | * NXP (Philips) SCC+++(SCN+++) serial driver | ||
| 2 | |||
| 3 | Required properties: | ||
| 4 | - compatible: Should be "nxp,<ictype>". The supported ICs include sc2681, | ||
| 5 | sc2691, sc2692, sc2891, sc2892, sc28202, sc68681 and sc68692. | ||
| 6 | - reg: Address and length of the register set for the device. | ||
| 7 | - interrupts: Should contain the interrupt number. If omitted, | ||
| 8 | polling mode will be used instead, so "poll-interval" property should | ||
| 9 | be populated in this case. | ||
| 10 | |||
| 11 | Optional properties: | ||
| 12 | - clocks: Phandle to input clock. If omitted, default IC frequency will be | ||
| 13 | used instead. | ||
| 14 | - poll-interval: Poll interval time in nanoseconds. | ||
| 15 | - vcc-supply: The regulator supplying the VCC to drive the chip. | ||
| 16 | - nxp,sccnxp-io-cfg: Array contains values for the emulated modem signals. | ||
| 17 | The number of values depends on the UART-number in the selected chip. | ||
| 18 | Each value should be composed according to the following rules: | ||
| 19 | (LINE1 << SIGNAL1) | ... | (LINEX << SIGNALX), where: | ||
| 20 | LINE - VALUE: | ||
| 21 | OP0 - 1 | ||
| 22 | OP1 - 2 | ||
| 23 | OP2 - 3 | ||
| 24 | OP3 - 4 | ||
| 25 | OP4 - 5 | ||
| 26 | OP5 - 6 | ||
| 27 | OP6 - 7 | ||
| 28 | OP7 - 8 | ||
| 29 | IP0 - 9 | ||
| 30 | IP1 - 10 | ||
| 31 | IP2 - 11 | ||
| 32 | IP3 - 12 | ||
| 33 | IP4 - 13 | ||
| 34 | IP5 - 14 | ||
| 35 | IP6 - 15 | ||
| 36 | SIGNAL - VALUE: | ||
| 37 | DTR - 0 | ||
| 38 | RTS - 4 | ||
| 39 | DSR - 8 | ||
| 40 | CTS - 12 | ||
| 41 | DCD - 16 | ||
| 42 | RNG - 20 | ||
| 43 | DIR - 24 | ||
| 44 | |||
| 45 | Example (Dual UART with direction control on OP0 & OP1): | ||
| 46 | sc2892@10100000 { | ||
| 47 | compatible = "nxp,sc2892"; | ||
| 48 | reg = <0x10100000 0x10>; | ||
| 49 | poll-interval = <10000>; | ||
| 50 | clocks = <&sc2892_clk>; | ||
| 51 | vcc-supply = <&sc2892_reg>; | ||
| 52 | nxp,sccnxp-io-cfg = <0x01000000 0x02000000>; | ||
| 53 | }; | ||
diff --git a/drivers/tty/serial/sccnxp.c b/drivers/tty/serial/sccnxp.c index 49e9bbfe6cab..67f73d1a8e7b 100644 --- a/drivers/tty/serial/sccnxp.c +++ b/drivers/tty/serial/sccnxp.c | |||
| @@ -20,6 +20,8 @@ | |||
| 20 | #include <linux/module.h> | 20 | #include <linux/module.h> |
| 21 | #include <linux/device.h> | 21 | #include <linux/device.h> |
| 22 | #include <linux/console.h> | 22 | #include <linux/console.h> |
| 23 | #include <linux/of.h> | ||
| 24 | #include <linux/of_device.h> | ||
| 23 | #include <linux/serial_core.h> | 25 | #include <linux/serial_core.h> |
| 24 | #include <linux/serial.h> | 26 | #include <linux/serial.h> |
| 25 | #include <linux/io.h> | 27 | #include <linux/io.h> |
| @@ -853,10 +855,25 @@ static const struct platform_device_id sccnxp_id_table[] = { | |||
| 853 | }; | 855 | }; |
| 854 | MODULE_DEVICE_TABLE(platform, sccnxp_id_table); | 856 | MODULE_DEVICE_TABLE(platform, sccnxp_id_table); |
| 855 | 857 | ||
| 858 | static const struct of_device_id sccnxp_dt_id_table[] = { | ||
| 859 | { .compatible = "nxp,sc2681", .data = &sc2681, }, | ||
| 860 | { .compatible = "nxp,sc2691", .data = &sc2691, }, | ||
| 861 | { .compatible = "nxp,sc2692", .data = &sc2692, }, | ||
| 862 | { .compatible = "nxp,sc2891", .data = &sc2891, }, | ||
| 863 | { .compatible = "nxp,sc2892", .data = &sc2892, }, | ||
| 864 | { .compatible = "nxp,sc28202", .data = &sc28202, }, | ||
| 865 | { .compatible = "nxp,sc68681", .data = &sc68681, }, | ||
| 866 | { .compatible = "nxp,sc68692", .data = &sc68692, }, | ||
| 867 | { } | ||
| 868 | }; | ||
| 869 | MODULE_DEVICE_TABLE(of, sccnxp_dt_id_table); | ||
| 870 | |||
| 856 | static int sccnxp_probe(struct platform_device *pdev) | 871 | static int sccnxp_probe(struct platform_device *pdev) |
| 857 | { | 872 | { |
| 858 | struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 873 | struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 859 | struct sccnxp_pdata *pdata = dev_get_platdata(&pdev->dev); | 874 | struct sccnxp_pdata *pdata = dev_get_platdata(&pdev->dev); |
| 875 | const struct of_device_id *of_id = | ||
| 876 | of_match_device(sccnxp_dt_id_table, &pdev->dev); | ||
| 860 | int i, ret, uartclk; | 877 | int i, ret, uartclk; |
| 861 | struct sccnxp_port *s; | 878 | struct sccnxp_port *s; |
| 862 | void __iomem *membase; | 879 | void __iomem *membase; |
| @@ -875,7 +892,22 @@ static int sccnxp_probe(struct platform_device *pdev) | |||
| 875 | 892 | ||
| 876 | spin_lock_init(&s->lock); | 893 | spin_lock_init(&s->lock); |
| 877 | 894 | ||
| 878 | s->chip = (struct sccnxp_chip *)pdev->id_entry->driver_data; | 895 | if (of_id) { |
| 896 | s->chip = (struct sccnxp_chip *)of_id->data; | ||
| 897 | |||
| 898 | of_property_read_u32(pdev->dev.of_node, "poll-interval", | ||
| 899 | &s->pdata.poll_time_us); | ||
| 900 | of_property_read_u32(pdev->dev.of_node, "reg-shift", | ||
| 901 | &s->pdata.reg_shift); | ||
| 902 | of_property_read_u32_array(pdev->dev.of_node, | ||
| 903 | "nxp,sccnxp-io-cfg", | ||
| 904 | s->pdata.mctrl_cfg, s->chip->nr); | ||
| 905 | } else { | ||
| 906 | s->chip = (struct sccnxp_chip *)pdev->id_entry->driver_data; | ||
| 907 | |||
| 908 | if (pdata) | ||
| 909 | memcpy(&s->pdata, pdata, sizeof(struct sccnxp_pdata)); | ||
| 910 | } | ||
| 879 | 911 | ||
| 880 | s->regulator = devm_regulator_get(&pdev->dev, "vcc"); | 912 | s->regulator = devm_regulator_get(&pdev->dev, "vcc"); |
| 881 | if (!IS_ERR(s->regulator)) { | 913 | if (!IS_ERR(s->regulator)) { |
| @@ -906,16 +938,11 @@ static int sccnxp_probe(struct platform_device *pdev) | |||
| 906 | goto err_out; | 938 | goto err_out; |
| 907 | } | 939 | } |
| 908 | 940 | ||
| 909 | if (pdata) | ||
| 910 | memcpy(&s->pdata, pdata, sizeof(struct sccnxp_pdata)); | ||
| 911 | |||
| 912 | if (s->pdata.poll_time_us) { | 941 | if (s->pdata.poll_time_us) { |
| 913 | dev_info(&pdev->dev, "Using poll mode, resolution %u usecs\n", | 942 | dev_info(&pdev->dev, "Using poll mode, resolution %u usecs\n", |
| 914 | s->pdata.poll_time_us); | 943 | s->pdata.poll_time_us); |
| 915 | s->poll = 1; | 944 | s->poll = 1; |
| 916 | } | 945 | } else { |
| 917 | |||
| 918 | if (!s->poll) { | ||
| 919 | s->irq = platform_get_irq(pdev, 0); | 946 | s->irq = platform_get_irq(pdev, 0); |
| 920 | if (s->irq < 0) { | 947 | if (s->irq < 0) { |
| 921 | dev_err(&pdev->dev, "Missing irq resource data\n"); | 948 | dev_err(&pdev->dev, "Missing irq resource data\n"); |
| @@ -1016,8 +1043,9 @@ static int sccnxp_remove(struct platform_device *pdev) | |||
| 1016 | 1043 | ||
| 1017 | static struct platform_driver sccnxp_uart_driver = { | 1044 | static struct platform_driver sccnxp_uart_driver = { |
| 1018 | .driver = { | 1045 | .driver = { |
| 1019 | .name = SCCNXP_NAME, | 1046 | .name = SCCNXP_NAME, |
| 1020 | .owner = THIS_MODULE, | 1047 | .owner = THIS_MODULE, |
| 1048 | .of_match_table = sccnxp_dt_id_table, | ||
| 1021 | }, | 1049 | }, |
| 1022 | .probe = sccnxp_probe, | 1050 | .probe = sccnxp_probe, |
| 1023 | .remove = sccnxp_remove, | 1051 | .remove = sccnxp_remove, |
diff --git a/include/linux/platform_data/serial-sccnxp.h b/include/linux/platform_data/serial-sccnxp.h index af0c8c3b89ae..98373d6add27 100644 --- a/include/linux/platform_data/serial-sccnxp.h +++ b/include/linux/platform_data/serial-sccnxp.h | |||
| @@ -78,11 +78,11 @@ | |||
| 78 | /* SCCNXP platform data structure */ | 78 | /* SCCNXP platform data structure */ |
| 79 | struct sccnxp_pdata { | 79 | struct sccnxp_pdata { |
| 80 | /* Shift for A0 line */ | 80 | /* Shift for A0 line */ |
| 81 | const u8 reg_shift; | 81 | u32 reg_shift; |
| 82 | /* Modem control lines configuration */ | 82 | /* Modem control lines configuration */ |
| 83 | const u32 mctrl_cfg[SCCNXP_MAX_UARTS]; | 83 | u32 mctrl_cfg[SCCNXP_MAX_UARTS]; |
| 84 | /* Timer value for polling mode (usecs) */ | 84 | /* Timer value for polling mode (usecs) */ |
| 85 | const unsigned int poll_time_us; | 85 | u32 poll_time_us; |
| 86 | }; | 86 | }; |
| 87 | 87 | ||
| 88 | #endif | 88 | #endif |
