1 // SPDX-License-Identifier: GPL-2.0
3 * Serial port driver for BCM2835AUX UART
5 * Copyright (C) 2016 Martin Sperl <kernel@martin.sperl.org>
7 * Based on 8250_lpc18xx.c:
8 * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com>
10 * The bcm2835aux is capable of RTS auto flow-control, but this driver doesn't
11 * take advantage of it yet. When adding support, be sure not to enable it
12 * simultaneously to rs485.
15 #include <linux/clk.h>
17 #include <linux/module.h>
19 #include <linux/platform_device.h>
23 #define BCM2835_AUX_UART_CNTL 8
24 #define BCM2835_AUX_UART_CNTL_RXEN 0x01 /* Receiver enable */
25 #define BCM2835_AUX_UART_CNTL_TXEN 0x02 /* Transmitter enable */
26 #define BCM2835_AUX_UART_CNTL_AUTORTS 0x04 /* RTS set by RX fill level */
27 #define BCM2835_AUX_UART_CNTL_AUTOCTS 0x08 /* CTS stops transmitter */
28 #define BCM2835_AUX_UART_CNTL_RTS3 0x00 /* RTS set until 3 chars left */
29 #define BCM2835_AUX_UART_CNTL_RTS2 0x10 /* RTS set until 2 chars left */
30 #define BCM2835_AUX_UART_CNTL_RTS1 0x20 /* RTS set until 1 chars left */
31 #define BCM2835_AUX_UART_CNTL_RTS4 0x30 /* RTS set until 4 chars left */
32 #define BCM2835_AUX_UART_CNTL_RTSINV 0x40 /* Invert auto RTS polarity */
33 #define BCM2835_AUX_UART_CNTL_CTSINV 0x80 /* Invert auto CTS polarity */
36 * struct bcm2835aux_data - driver private data of BCM2835 auxiliary UART
37 * @clk: clock producer of the port's uartclk
38 * @line: index of the port's serial8250_ports[] entry
39 * @cntl: cached copy of CNTL register
41 struct bcm2835aux_data
{
47 static void bcm2835aux_rs485_start_tx(struct uart_8250_port
*up
)
49 if (!(up
->port
.rs485
.flags
& SER_RS485_RX_DURING_TX
)) {
50 struct bcm2835aux_data
*data
= dev_get_drvdata(up
->port
.dev
);
52 data
->cntl
&= ~BCM2835_AUX_UART_CNTL_RXEN
;
53 serial_out(up
, BCM2835_AUX_UART_CNTL
, data
->cntl
);
57 * On the bcm2835aux, the MCR register contains no other
58 * flags besides RTS. So no need for a read-modify-write.
60 if (up
->port
.rs485
.flags
& SER_RS485_RTS_ON_SEND
)
61 serial8250_out_MCR(up
, 0);
63 serial8250_out_MCR(up
, UART_MCR_RTS
);
66 static void bcm2835aux_rs485_stop_tx(struct uart_8250_port
*up
)
68 if (up
->port
.rs485
.flags
& SER_RS485_RTS_AFTER_SEND
)
69 serial8250_out_MCR(up
, 0);
71 serial8250_out_MCR(up
, UART_MCR_RTS
);
73 if (!(up
->port
.rs485
.flags
& SER_RS485_RX_DURING_TX
)) {
74 struct bcm2835aux_data
*data
= dev_get_drvdata(up
->port
.dev
);
76 data
->cntl
|= BCM2835_AUX_UART_CNTL_RXEN
;
77 serial_out(up
, BCM2835_AUX_UART_CNTL
, data
->cntl
);
81 static int bcm2835aux_serial_probe(struct platform_device
*pdev
)
83 struct uart_8250_port up
= { };
84 struct bcm2835aux_data
*data
;
88 /* allocate the custom structure */
89 data
= devm_kzalloc(&pdev
->dev
, sizeof(*data
), GFP_KERNEL
);
94 up
.capabilities
= UART_CAP_FIFO
| UART_CAP_MINI
;
95 up
.port
.dev
= &pdev
->dev
;
97 up
.port
.type
= PORT_16550
;
98 up
.port
.iotype
= UPIO_MEM
;
100 up
.port
.flags
= UPF_SHARE_IRQ
| UPF_FIXED_PORT
| UPF_FIXED_TYPE
|
101 UPF_SKIP_TEST
| UPF_IOREMAP
;
102 up
.port
.rs485_config
= serial8250_em485_config
;
103 up
.rs485_start_tx
= bcm2835aux_rs485_start_tx
;
104 up
.rs485_stop_tx
= bcm2835aux_rs485_stop_tx
;
106 /* initialize cached copy with power-on reset value */
107 data
->cntl
= BCM2835_AUX_UART_CNTL_RXEN
| BCM2835_AUX_UART_CNTL_TXEN
;
109 platform_set_drvdata(pdev
, data
);
111 /* get the clock - this also enables the HW */
112 data
->clk
= devm_clk_get(&pdev
->dev
, NULL
);
113 ret
= PTR_ERR_OR_ZERO(data
->clk
);
115 if (ret
!= -EPROBE_DEFER
)
116 dev_err(&pdev
->dev
, "could not get clk: %d\n", ret
);
120 /* get the interrupt */
121 ret
= platform_get_irq(pdev
, 0);
126 /* map the main registers */
127 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
129 dev_err(&pdev
->dev
, "memory resource not found");
132 up
.port
.mapbase
= res
->start
;
133 up
.port
.mapsize
= resource_size(res
);
135 /* Check for a fixed line number */
136 ret
= of_alias_get_id(pdev
->dev
.of_node
, "serial");
140 /* enable the clock as a last step */
141 ret
= clk_prepare_enable(data
->clk
);
143 dev_err(&pdev
->dev
, "unable to enable uart clock - %d\n",
148 /* the HW-clock divider for bcm2835aux is 8,
149 * but 8250 expects a divider of 16,
150 * so we have to multiply the actual clock by 2
151 * to get identical baudrates.
153 up
.port
.uartclk
= clk_get_rate(data
->clk
) * 2;
155 /* register the port */
156 ret
= serial8250_register_8250_port(&up
);
158 if (ret
!= -EPROBE_DEFER
)
160 "unable to register 8250 port - %d\n", ret
);
168 clk_disable_unprepare(data
->clk
);
172 static int bcm2835aux_serial_remove(struct platform_device
*pdev
)
174 struct bcm2835aux_data
*data
= platform_get_drvdata(pdev
);
176 serial8250_unregister_port(data
->line
);
177 clk_disable_unprepare(data
->clk
);
182 static const struct of_device_id bcm2835aux_serial_match
[] = {
183 { .compatible
= "brcm,bcm2835-aux-uart" },
186 MODULE_DEVICE_TABLE(of
, bcm2835aux_serial_match
);
188 static struct platform_driver bcm2835aux_serial_driver
= {
190 .name
= "bcm2835-aux-uart",
191 .of_match_table
= bcm2835aux_serial_match
,
193 .probe
= bcm2835aux_serial_probe
,
194 .remove
= bcm2835aux_serial_remove
,
196 module_platform_driver(bcm2835aux_serial_driver
);
198 #ifdef CONFIG_SERIAL_8250_CONSOLE
200 static int __init
early_bcm2835aux_setup(struct earlycon_device
*device
,
203 if (!device
->port
.membase
)
206 device
->port
.iotype
= UPIO_MEM32
;
207 device
->port
.regshift
= 2;
209 return early_serial8250_setup(device
, NULL
);
212 OF_EARLYCON_DECLARE(bcm2835aux
, "brcm,bcm2835-aux-uart",
213 early_bcm2835aux_setup
);
216 MODULE_DESCRIPTION("BCM2835 auxiliar UART driver");
217 MODULE_AUTHOR("Martin Sperl <kernel@martin.sperl.org>");
218 MODULE_LICENSE("GPL v2");