1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Serial port driver for NXP LPC18xx/43xx UART |
4 | * |
5 | * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com> |
6 | * |
7 | * Based on 8250_mtk.c: |
8 | * Copyright (c) 2014 MundoReader S.L. |
9 | * Matthias Brugger <matthias.bgg@gmail.com> |
10 | */ |
11 | |
12 | #include <linux/clk.h> |
13 | #include <linux/io.h> |
14 | #include <linux/module.h> |
15 | #include <linux/of.h> |
16 | #include <linux/platform_device.h> |
17 | |
18 | #include "8250.h" |
19 | |
20 | /* Additional LPC18xx/43xx 8250 registers and bits */ |
21 | #define LPC18XX_UART_RS485CTRL (0x04c / sizeof(u32)) |
22 | #define LPC18XX_UART_RS485CTRL_NMMEN BIT(0) |
23 | #define LPC18XX_UART_RS485CTRL_DCTRL BIT(4) |
24 | #define LPC18XX_UART_RS485CTRL_OINV BIT(5) |
25 | #define LPC18XX_UART_RS485DLY (0x054 / sizeof(u32)) |
26 | #define LPC18XX_UART_RS485DLY_MAX 255 |
27 | |
28 | struct lpc18xx_uart_data { |
29 | struct uart_8250_dma dma; |
30 | struct clk *clk_uart; |
31 | struct clk *clk_reg; |
32 | int line; |
33 | }; |
34 | |
35 | static int lpc18xx_rs485_config(struct uart_port *port, struct ktermios *termios, |
36 | struct serial_rs485 *rs485) |
37 | { |
38 | struct uart_8250_port *up = up_to_u8250p(up: port); |
39 | u32 rs485_ctrl_reg = 0; |
40 | u32 rs485_dly_reg = 0; |
41 | unsigned baud_clk; |
42 | |
43 | if (rs485->flags & SER_RS485_ENABLED) { |
44 | rs485_ctrl_reg |= LPC18XX_UART_RS485CTRL_NMMEN | |
45 | LPC18XX_UART_RS485CTRL_DCTRL; |
46 | |
47 | if (rs485->flags & SER_RS485_RTS_ON_SEND) |
48 | rs485_ctrl_reg |= LPC18XX_UART_RS485CTRL_OINV; |
49 | } |
50 | |
51 | if (rs485->delay_rts_after_send) { |
52 | baud_clk = port->uartclk / up->dl_read(up); |
53 | rs485_dly_reg = DIV_ROUND_UP(rs485->delay_rts_after_send |
54 | * baud_clk, MSEC_PER_SEC); |
55 | |
56 | if (rs485_dly_reg > LPC18XX_UART_RS485DLY_MAX) |
57 | rs485_dly_reg = LPC18XX_UART_RS485DLY_MAX; |
58 | |
59 | /* Calculate the resulting delay in ms */ |
60 | rs485->delay_rts_after_send = (rs485_dly_reg * MSEC_PER_SEC) |
61 | / baud_clk; |
62 | } |
63 | |
64 | serial_out(up, LPC18XX_UART_RS485CTRL, value: rs485_ctrl_reg); |
65 | serial_out(up, LPC18XX_UART_RS485DLY, value: rs485_dly_reg); |
66 | |
67 | return 0; |
68 | } |
69 | |
70 | static void lpc18xx_uart_serial_out(struct uart_port *p, int offset, int value) |
71 | { |
72 | /* |
73 | * For DMA mode one must ensure that the UART_FCR_DMA_SELECT |
74 | * bit is set when FIFO is enabled. Even if DMA is not used |
75 | * setting this bit doesn't seem to affect anything. |
76 | */ |
77 | if (offset == UART_FCR && (value & UART_FCR_ENABLE_FIFO)) |
78 | value |= UART_FCR_DMA_SELECT; |
79 | |
80 | offset = offset << p->regshift; |
81 | writel(val: value, addr: p->membase + offset); |
82 | } |
83 | |
84 | static const struct serial_rs485 lpc18xx_rs485_supported = { |
85 | .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND, |
86 | .delay_rts_after_send = 1, |
87 | /* Delay RTS before send is not supported */ |
88 | }; |
89 | |
90 | static int lpc18xx_serial_probe(struct platform_device *pdev) |
91 | { |
92 | struct lpc18xx_uart_data *data; |
93 | struct uart_8250_port uart; |
94 | struct resource *res; |
95 | int ret; |
96 | |
97 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
98 | if (!res) { |
99 | dev_err(&pdev->dev, "memory resource not found" ); |
100 | return -EINVAL; |
101 | } |
102 | |
103 | memset(&uart, 0, sizeof(uart)); |
104 | |
105 | uart.port.membase = devm_ioremap(dev: &pdev->dev, offset: res->start, |
106 | size: resource_size(res)); |
107 | if (!uart.port.membase) |
108 | return -ENOMEM; |
109 | |
110 | data = devm_kzalloc(dev: &pdev->dev, size: sizeof(*data), GFP_KERNEL); |
111 | if (!data) |
112 | return -ENOMEM; |
113 | |
114 | data->clk_uart = devm_clk_get(dev: &pdev->dev, id: "uartclk" ); |
115 | if (IS_ERR(ptr: data->clk_uart)) { |
116 | dev_err(&pdev->dev, "uart clock not found\n" ); |
117 | return PTR_ERR(ptr: data->clk_uart); |
118 | } |
119 | |
120 | data->clk_reg = devm_clk_get(dev: &pdev->dev, id: "reg" ); |
121 | if (IS_ERR(ptr: data->clk_reg)) { |
122 | dev_err(&pdev->dev, "reg clock not found\n" ); |
123 | return PTR_ERR(ptr: data->clk_reg); |
124 | } |
125 | |
126 | ret = clk_prepare_enable(clk: data->clk_reg); |
127 | if (ret) { |
128 | dev_err(&pdev->dev, "unable to enable reg clock\n" ); |
129 | return ret; |
130 | } |
131 | |
132 | ret = clk_prepare_enable(clk: data->clk_uart); |
133 | if (ret) { |
134 | dev_err(&pdev->dev, "unable to enable uart clock\n" ); |
135 | goto dis_clk_reg; |
136 | } |
137 | |
138 | data->dma.rx_param = data; |
139 | data->dma.tx_param = data; |
140 | |
141 | spin_lock_init(&uart.port.lock); |
142 | uart.port.dev = &pdev->dev; |
143 | uart.port.mapbase = res->start; |
144 | uart.port.type = PORT_16550A; |
145 | uart.port.flags = UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_SKIP_TEST; |
146 | uart.port.uartclk = clk_get_rate(clk: data->clk_uart); |
147 | uart.port.private_data = data; |
148 | uart.port.rs485_config = lpc18xx_rs485_config; |
149 | uart.port.rs485_supported = lpc18xx_rs485_supported; |
150 | uart.port.serial_out = lpc18xx_uart_serial_out; |
151 | |
152 | ret = uart_read_port_properties(port: &uart.port); |
153 | if (ret) |
154 | goto dis_uart_clk; |
155 | |
156 | uart.port.iotype = UPIO_MEM32; |
157 | uart.port.regshift = 2; |
158 | |
159 | uart.dma = &data->dma; |
160 | uart.dma->rxconf.src_maxburst = 1; |
161 | uart.dma->txconf.dst_maxburst = 1; |
162 | |
163 | ret = serial8250_register_8250_port(&uart); |
164 | if (ret < 0) { |
165 | dev_err(&pdev->dev, "unable to register 8250 port\n" ); |
166 | goto dis_uart_clk; |
167 | } |
168 | |
169 | data->line = ret; |
170 | platform_set_drvdata(pdev, data); |
171 | |
172 | return 0; |
173 | |
174 | dis_uart_clk: |
175 | clk_disable_unprepare(clk: data->clk_uart); |
176 | dis_clk_reg: |
177 | clk_disable_unprepare(clk: data->clk_reg); |
178 | return ret; |
179 | } |
180 | |
181 | static void lpc18xx_serial_remove(struct platform_device *pdev) |
182 | { |
183 | struct lpc18xx_uart_data *data = platform_get_drvdata(pdev); |
184 | |
185 | serial8250_unregister_port(line: data->line); |
186 | clk_disable_unprepare(clk: data->clk_uart); |
187 | clk_disable_unprepare(clk: data->clk_reg); |
188 | } |
189 | |
190 | static const struct of_device_id lpc18xx_serial_match[] = { |
191 | { .compatible = "nxp,lpc1850-uart" }, |
192 | { }, |
193 | }; |
194 | MODULE_DEVICE_TABLE(of, lpc18xx_serial_match); |
195 | |
196 | static struct platform_driver lpc18xx_serial_driver = { |
197 | .probe = lpc18xx_serial_probe, |
198 | .remove_new = lpc18xx_serial_remove, |
199 | .driver = { |
200 | .name = "lpc18xx-uart" , |
201 | .of_match_table = lpc18xx_serial_match, |
202 | }, |
203 | }; |
204 | module_platform_driver(lpc18xx_serial_driver); |
205 | |
206 | MODULE_AUTHOR("Joachim Eastwood <manabian@gmail.com>" ); |
207 | MODULE_DESCRIPTION("Serial port driver NXP LPC18xx/43xx devices" ); |
208 | MODULE_LICENSE("GPL v2" ); |
209 | |