Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Serial port driver for BCM2835AUX UART
0004  *
0005  * Copyright (C) 2016 Martin Sperl <kernel@martin.sperl.org>
0006  *
0007  * Based on 8250_lpc18xx.c:
0008  * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com>
0009  *
0010  * The bcm2835aux is capable of RTS auto flow-control, but this driver doesn't
0011  * take advantage of it yet.  When adding support, be sure not to enable it
0012  * simultaneously to rs485.
0013  */
0014 
0015 #include <linux/clk.h>
0016 #include <linux/io.h>
0017 #include <linux/module.h>
0018 #include <linux/of.h>
0019 #include <linux/platform_device.h>
0020 #include <linux/property.h>
0021 
0022 #include "8250.h"
0023 
0024 #define BCM2835_AUX_UART_CNTL       8
0025 #define BCM2835_AUX_UART_CNTL_RXEN  0x01 /* Receiver enable */
0026 #define BCM2835_AUX_UART_CNTL_TXEN  0x02 /* Transmitter enable */
0027 #define BCM2835_AUX_UART_CNTL_AUTORTS   0x04 /* RTS set by RX fill level */
0028 #define BCM2835_AUX_UART_CNTL_AUTOCTS   0x08 /* CTS stops transmitter */
0029 #define BCM2835_AUX_UART_CNTL_RTS3  0x00 /* RTS set until 3 chars left */
0030 #define BCM2835_AUX_UART_CNTL_RTS2  0x10 /* RTS set until 2 chars left */
0031 #define BCM2835_AUX_UART_CNTL_RTS1  0x20 /* RTS set until 1 chars left */
0032 #define BCM2835_AUX_UART_CNTL_RTS4  0x30 /* RTS set until 4 chars left */
0033 #define BCM2835_AUX_UART_CNTL_RTSINV    0x40 /* Invert auto RTS polarity */
0034 #define BCM2835_AUX_UART_CNTL_CTSINV    0x80 /* Invert auto CTS polarity */
0035 
0036 /**
0037  * struct bcm2835aux_data - driver private data of BCM2835 auxiliary UART
0038  * @clk: clock producer of the port's uartclk
0039  * @line: index of the port's serial8250_ports[] entry
0040  * @cntl: cached copy of CNTL register
0041  */
0042 struct bcm2835aux_data {
0043     struct clk *clk;
0044     int line;
0045     u32 cntl;
0046 };
0047 
0048 struct bcm2835_aux_serial_driver_data {
0049     resource_size_t offset;
0050 };
0051 
0052 static void bcm2835aux_rs485_start_tx(struct uart_8250_port *up)
0053 {
0054     if (!(up->port.rs485.flags & SER_RS485_RX_DURING_TX)) {
0055         struct bcm2835aux_data *data = dev_get_drvdata(up->port.dev);
0056 
0057         data->cntl &= ~BCM2835_AUX_UART_CNTL_RXEN;
0058         serial_out(up, BCM2835_AUX_UART_CNTL, data->cntl);
0059     }
0060 
0061     /*
0062      * On the bcm2835aux, the MCR register contains no other
0063      * flags besides RTS.  So no need for a read-modify-write.
0064      */
0065     if (up->port.rs485.flags & SER_RS485_RTS_ON_SEND)
0066         serial8250_out_MCR(up, 0);
0067     else
0068         serial8250_out_MCR(up, UART_MCR_RTS);
0069 }
0070 
0071 static void bcm2835aux_rs485_stop_tx(struct uart_8250_port *up)
0072 {
0073     if (up->port.rs485.flags & SER_RS485_RTS_AFTER_SEND)
0074         serial8250_out_MCR(up, 0);
0075     else
0076         serial8250_out_MCR(up, UART_MCR_RTS);
0077 
0078     if (!(up->port.rs485.flags & SER_RS485_RX_DURING_TX)) {
0079         struct bcm2835aux_data *data = dev_get_drvdata(up->port.dev);
0080 
0081         data->cntl |= BCM2835_AUX_UART_CNTL_RXEN;
0082         serial_out(up, BCM2835_AUX_UART_CNTL, data->cntl);
0083     }
0084 }
0085 
0086 static int bcm2835aux_serial_probe(struct platform_device *pdev)
0087 {
0088     const struct bcm2835_aux_serial_driver_data *bcm_data;
0089     struct uart_8250_port up = { };
0090     struct bcm2835aux_data *data;
0091     resource_size_t offset = 0;
0092     struct resource *res;
0093     unsigned int uartclk;
0094     int ret;
0095 
0096     /* allocate the custom structure */
0097     data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
0098     if (!data)
0099         return -ENOMEM;
0100 
0101     /* initialize data */
0102     up.capabilities = UART_CAP_FIFO | UART_CAP_MINI;
0103     up.port.dev = &pdev->dev;
0104     up.port.regshift = 2;
0105     up.port.type = PORT_16550;
0106     up.port.iotype = UPIO_MEM;
0107     up.port.fifosize = 8;
0108     up.port.flags = UPF_SHARE_IRQ | UPF_FIXED_PORT | UPF_FIXED_TYPE |
0109             UPF_SKIP_TEST | UPF_IOREMAP;
0110     up.port.rs485_config = serial8250_em485_config;
0111     up.port.rs485_supported = serial8250_em485_supported;
0112     up.rs485_start_tx = bcm2835aux_rs485_start_tx;
0113     up.rs485_stop_tx = bcm2835aux_rs485_stop_tx;
0114 
0115     /* initialize cached copy with power-on reset value */
0116     data->cntl = BCM2835_AUX_UART_CNTL_RXEN | BCM2835_AUX_UART_CNTL_TXEN;
0117 
0118     platform_set_drvdata(pdev, data);
0119 
0120     /* get the clock - this also enables the HW */
0121     data->clk = devm_clk_get_optional(&pdev->dev, NULL);
0122 
0123     /* get the interrupt */
0124     ret = platform_get_irq(pdev, 0);
0125     if (ret < 0)
0126         return ret;
0127     up.port.irq = ret;
0128 
0129     /* map the main registers */
0130     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0131     if (!res) {
0132         dev_err(&pdev->dev, "memory resource not found");
0133         return -EINVAL;
0134     }
0135 
0136     bcm_data = device_get_match_data(&pdev->dev);
0137 
0138     /* Some UEFI implementations (e.g. tianocore/edk2 for the Raspberry Pi)
0139      * describe the miniuart with a base address that encompasses the auxiliary
0140      * registers shared between the miniuart and spi.
0141      *
0142      * This is due to historical reasons, see discussion here :
0143      * https://edk2.groups.io/g/devel/topic/87501357#84349
0144      *
0145      * We need to add the offset between the miniuart and auxiliary
0146      * registers to get the real miniuart base address.
0147      */
0148     if (bcm_data)
0149         offset = bcm_data->offset;
0150 
0151     up.port.mapbase = res->start + offset;
0152     up.port.mapsize = resource_size(res) - offset;
0153 
0154     /* Check for a fixed line number */
0155     ret = of_alias_get_id(pdev->dev.of_node, "serial");
0156     if (ret >= 0)
0157         up.port.line = ret;
0158 
0159     /* enable the clock as a last step */
0160     ret = clk_prepare_enable(data->clk);
0161     if (ret) {
0162         dev_err(&pdev->dev, "unable to enable uart clock - %d\n",
0163             ret);
0164         return ret;
0165     }
0166 
0167     uartclk = clk_get_rate(data->clk);
0168     if (!uartclk) {
0169         ret = device_property_read_u32(&pdev->dev, "clock-frequency", &uartclk);
0170         if (ret) {
0171             dev_err_probe(&pdev->dev, ret, "could not get clk rate\n");
0172             goto dis_clk;
0173         }
0174     }
0175 
0176     /* the HW-clock divider for bcm2835aux is 8,
0177      * but 8250 expects a divider of 16,
0178      * so we have to multiply the actual clock by 2
0179      * to get identical baudrates.
0180      */
0181     up.port.uartclk = uartclk * 2;
0182 
0183     /* register the port */
0184     ret = serial8250_register_8250_port(&up);
0185     if (ret < 0) {
0186         dev_err_probe(&pdev->dev, ret, "unable to register 8250 port\n");
0187         goto dis_clk;
0188     }
0189     data->line = ret;
0190 
0191     return 0;
0192 
0193 dis_clk:
0194     clk_disable_unprepare(data->clk);
0195     return ret;
0196 }
0197 
0198 static int bcm2835aux_serial_remove(struct platform_device *pdev)
0199 {
0200     struct bcm2835aux_data *data = platform_get_drvdata(pdev);
0201 
0202     serial8250_unregister_port(data->line);
0203     clk_disable_unprepare(data->clk);
0204 
0205     return 0;
0206 }
0207 
0208 static const struct bcm2835_aux_serial_driver_data bcm2835_acpi_data = {
0209     .offset = 0x40,
0210 };
0211 
0212 static const struct of_device_id bcm2835aux_serial_match[] = {
0213     { .compatible = "brcm,bcm2835-aux-uart" },
0214     { },
0215 };
0216 MODULE_DEVICE_TABLE(of, bcm2835aux_serial_match);
0217 
0218 static const struct acpi_device_id bcm2835aux_serial_acpi_match[] = {
0219     { "BCM2836", (kernel_ulong_t)&bcm2835_acpi_data },
0220     { }
0221 };
0222 MODULE_DEVICE_TABLE(acpi, bcm2835aux_serial_acpi_match);
0223 
0224 static struct platform_driver bcm2835aux_serial_driver = {
0225     .driver = {
0226         .name = "bcm2835-aux-uart",
0227         .of_match_table = bcm2835aux_serial_match,
0228         .acpi_match_table = bcm2835aux_serial_acpi_match,
0229     },
0230     .probe  = bcm2835aux_serial_probe,
0231     .remove = bcm2835aux_serial_remove,
0232 };
0233 module_platform_driver(bcm2835aux_serial_driver);
0234 
0235 #ifdef CONFIG_SERIAL_8250_CONSOLE
0236 
0237 static int __init early_bcm2835aux_setup(struct earlycon_device *device,
0238                     const char *options)
0239 {
0240     if (!device->port.membase)
0241         return -ENODEV;
0242 
0243     device->port.iotype = UPIO_MEM32;
0244     device->port.regshift = 2;
0245 
0246     return early_serial8250_setup(device, NULL);
0247 }
0248 
0249 OF_EARLYCON_DECLARE(bcm2835aux, "brcm,bcm2835-aux-uart",
0250             early_bcm2835aux_setup);
0251 #endif
0252 
0253 MODULE_DESCRIPTION("BCM2835 auxiliar UART driver");
0254 MODULE_AUTHOR("Martin Sperl <kernel@martin.sperl.org>");
0255 MODULE_LICENSE("GPL v2");