Linux Audio

Check our new training course

Linux kernel drivers training

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