0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
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
0026 #define BCM2835_AUX_UART_CNTL_TXEN 0x02
0027 #define BCM2835_AUX_UART_CNTL_AUTORTS 0x04
0028 #define BCM2835_AUX_UART_CNTL_AUTOCTS 0x08
0029 #define BCM2835_AUX_UART_CNTL_RTS3 0x00
0030 #define BCM2835_AUX_UART_CNTL_RTS2 0x10
0031 #define BCM2835_AUX_UART_CNTL_RTS1 0x20
0032 #define BCM2835_AUX_UART_CNTL_RTS4 0x30
0033 #define BCM2835_AUX_UART_CNTL_RTSINV 0x40
0034 #define BCM2835_AUX_UART_CNTL_CTSINV 0x80
0035
0036
0037
0038
0039
0040
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
0063
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
0097 data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
0098 if (!data)
0099 return -ENOMEM;
0100
0101
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
0116 data->cntl = BCM2835_AUX_UART_CNTL_RXEN | BCM2835_AUX_UART_CNTL_TXEN;
0117
0118 platform_set_drvdata(pdev, data);
0119
0120
0121 data->clk = devm_clk_get_optional(&pdev->dev, NULL);
0122
0123
0124 ret = platform_get_irq(pdev, 0);
0125 if (ret < 0)
0126 return ret;
0127 up.port.irq = ret;
0128
0129
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
0139
0140
0141
0142
0143
0144
0145
0146
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
0155 ret = of_alias_get_id(pdev->dev.of_node, "serial");
0156 if (ret >= 0)
0157 up.port.line = ret;
0158
0159
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
0177
0178
0179
0180
0181 up.port.uartclk = uartclk * 2;
0182
0183
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");