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>
19 struct bcm2835aux_data
{
20 struct uart_8250_port uart
;
25 static int bcm2835aux_serial_probe(struct platform_device
*pdev
)
27 struct bcm2835aux_data
*data
;
31 /* allocate the custom structure */
32 data
= devm_kzalloc(&pdev
->dev
, sizeof(*data
), GFP_KERNEL
);
37 spin_lock_init(&data
->uart
.port
.lock
);
38 data
->uart
.capabilities
= UART_CAP_FIFO
| UART_CAP_MINI
;
39 data
->uart
.port
.dev
= &pdev
->dev
;
40 data
->uart
.port
.regshift
= 2;
41 data
->uart
.port
.type
= PORT_16550
;
42 data
->uart
.port
.iotype
= UPIO_MEM
;
43 data
->uart
.port
.fifosize
= 8;
44 data
->uart
.port
.flags
= UPF_SHARE_IRQ
|
49 /* get the clock - this also enables the HW */
50 data
->clk
= devm_clk_get(&pdev
->dev
, NULL
);
51 ret
= PTR_ERR_OR_ZERO(data
->clk
);
53 dev_err(&pdev
->dev
, "could not get clk: %d\n", ret
);
57 /* get the interrupt */
58 ret
= platform_get_irq(pdev
, 0);
60 dev_err(&pdev
->dev
, "irq not found - %i", ret
);
63 data
->uart
.port
.irq
= ret
;
65 /* map the main registers */
66 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
68 dev_err(&pdev
->dev
, "memory resource not found");
71 data
->uart
.port
.membase
= devm_ioremap_resource(&pdev
->dev
, res
);
72 ret
= PTR_ERR_OR_ZERO(data
->uart
.port
.membase
);
76 /* Check for a fixed line number */
77 ret
= of_alias_get_id(pdev
->dev
.of_node
, "serial");
79 data
->uart
.port
.line
= ret
;
81 /* enable the clock as a last step */
82 ret
= clk_prepare_enable(data
->clk
);
84 dev_err(&pdev
->dev
, "unable to enable uart clock - %d\n",
89 /* the HW-clock divider for bcm2835aux is 8,
90 * but 8250 expects a divider of 16,
91 * so we have to multiply the actual clock by 2
92 * to get identical baudrates.
94 data
->uart
.port
.uartclk
= clk_get_rate(data
->clk
) * 2;
96 /* register the port */
97 ret
= serial8250_register_8250_port(&data
->uart
);
99 dev_err(&pdev
->dev
, "unable to register 8250 port - %d\n",
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
->uart
.port
.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");