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>
11 #include <linux/clk.h>
13 #include <linux/module.h>
15 #include <linux/platform_device.h>
20 * struct bcm2835aux_data - driver private data of BCM2835 auxiliary UART
21 * @clk: clock producer of the port's uartclk
22 * @line: index of the port's serial8250_ports[] entry
24 struct bcm2835aux_data
{
29 static int bcm2835aux_serial_probe(struct platform_device
*pdev
)
31 struct uart_8250_port up
= { };
32 struct bcm2835aux_data
*data
;
36 /* allocate the custom structure */
37 data
= devm_kzalloc(&pdev
->dev
, sizeof(*data
), GFP_KERNEL
);
42 up
.capabilities
= UART_CAP_FIFO
| UART_CAP_MINI
;
43 up
.port
.dev
= &pdev
->dev
;
45 up
.port
.type
= PORT_16550
;
46 up
.port
.iotype
= UPIO_MEM
;
48 up
.port
.flags
= UPF_SHARE_IRQ
| UPF_FIXED_PORT
| UPF_FIXED_TYPE
|
49 UPF_SKIP_TEST
| UPF_IOREMAP
;
51 /* get the clock - this also enables the HW */
52 data
->clk
= devm_clk_get(&pdev
->dev
, NULL
);
53 ret
= PTR_ERR_OR_ZERO(data
->clk
);
55 if (ret
!= -EPROBE_DEFER
)
56 dev_err(&pdev
->dev
, "could not get clk: %d\n", ret
);
60 /* get the interrupt */
61 ret
= platform_get_irq(pdev
, 0);
66 /* map the main registers */
67 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
69 dev_err(&pdev
->dev
, "memory resource not found");
72 up
.port
.mapbase
= res
->start
;
73 up
.port
.mapsize
= resource_size(res
);
75 /* Check for a fixed line number */
76 ret
= of_alias_get_id(pdev
->dev
.of_node
, "serial");
80 /* enable the clock as a last step */
81 ret
= clk_prepare_enable(data
->clk
);
83 dev_err(&pdev
->dev
, "unable to enable uart clock - %d\n",
88 /* the HW-clock divider for bcm2835aux is 8,
89 * but 8250 expects a divider of 16,
90 * so we have to multiply the actual clock by 2
91 * to get identical baudrates.
93 up
.port
.uartclk
= clk_get_rate(data
->clk
) * 2;
95 /* register the port */
96 ret
= serial8250_register_8250_port(&up
);
98 if (ret
!= -EPROBE_DEFER
)
100 "unable to register 8250 port - %d\n", ret
);
105 platform_set_drvdata(pdev
, data
);
110 clk_disable_unprepare(data
->clk
);
114 static int bcm2835aux_serial_remove(struct platform_device
*pdev
)
116 struct bcm2835aux_data
*data
= platform_get_drvdata(pdev
);
118 serial8250_unregister_port(data
->line
);
119 clk_disable_unprepare(data
->clk
);
124 static const struct of_device_id bcm2835aux_serial_match
[] = {
125 { .compatible
= "brcm,bcm2835-aux-uart" },
128 MODULE_DEVICE_TABLE(of
, bcm2835aux_serial_match
);
130 static struct platform_driver bcm2835aux_serial_driver
= {
132 .name
= "bcm2835-aux-uart",
133 .of_match_table
= bcm2835aux_serial_match
,
135 .probe
= bcm2835aux_serial_probe
,
136 .remove
= bcm2835aux_serial_remove
,
138 module_platform_driver(bcm2835aux_serial_driver
);
140 MODULE_DESCRIPTION("BCM2835 auxiliar UART driver");
141 MODULE_AUTHOR("Martin Sperl <kernel@martin.sperl.org>");
142 MODULE_LICENSE("GPL v2");