1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Serial port driver for BCM2835AUX UART 4 * 5 * Copyright (C) 2016 Martin Sperl <kernel@martin.sperl.org> 6 * 7 * Based on 8250_lpc18xx.c: 8 * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com> 9 */ 10 11 #include <linux/clk.h> 12 #include <linux/io.h> 13 #include <linux/module.h> 14 #include <linux/of.h> 15 #include <linux/platform_device.h> 16 17 #include "8250.h" 18 19 struct bcm2835aux_data { 20 struct uart_8250_port uart; 21 struct clk *clk; 22 int line; 23 }; 24 25 static int bcm2835aux_serial_probe(struct platform_device *pdev) 26 { 27 struct bcm2835aux_data *data; 28 struct resource *res; 29 int ret; 30 31 /* allocate the custom structure */ 32 data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); 33 if (!data) 34 return -ENOMEM; 35 36 /* initialize data */ 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 | 45 UPF_FIXED_PORT | 46 UPF_FIXED_TYPE | 47 UPF_SKIP_TEST; 48 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); 52 if (ret) { 53 dev_err(&pdev->dev, "could not get clk: %d\n", ret); 54 return ret; 55 } 56 57 /* get the interrupt */ 58 ret = platform_get_irq(pdev, 0); 59 if (ret < 0) 60 return ret; 61 data->uart.port.irq = ret; 62 63 /* map the main registers */ 64 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 65 if (!res) { 66 dev_err(&pdev->dev, "memory resource not found"); 67 return -EINVAL; 68 } 69 data->uart.port.membase = devm_ioremap_resource(&pdev->dev, res); 70 ret = PTR_ERR_OR_ZERO(data->uart.port.membase); 71 if (ret) 72 return ret; 73 74 /* Check for a fixed line number */ 75 ret = of_alias_get_id(pdev->dev.of_node, "serial"); 76 if (ret >= 0) 77 data->uart.port.line = ret; 78 79 /* enable the clock as a last step */ 80 ret = clk_prepare_enable(data->clk); 81 if (ret) { 82 dev_err(&pdev->dev, "unable to enable uart clock - %d\n", 83 ret); 84 return ret; 85 } 86 87 /* the HW-clock divider for bcm2835aux is 8, 88 * but 8250 expects a divider of 16, 89 * so we have to multiply the actual clock by 2 90 * to get identical baudrates. 91 */ 92 data->uart.port.uartclk = clk_get_rate(data->clk) * 2; 93 94 /* register the port */ 95 ret = serial8250_register_8250_port(&data->uart); 96 if (ret < 0) { 97 dev_err(&pdev->dev, "unable to register 8250 port - %d\n", 98 ret); 99 goto dis_clk; 100 } 101 data->line = ret; 102 103 platform_set_drvdata(pdev, data); 104 105 return 0; 106 107 dis_clk: 108 clk_disable_unprepare(data->clk); 109 return ret; 110 } 111 112 static int bcm2835aux_serial_remove(struct platform_device *pdev) 113 { 114 struct bcm2835aux_data *data = platform_get_drvdata(pdev); 115 116 serial8250_unregister_port(data->uart.port.line); 117 clk_disable_unprepare(data->clk); 118 119 return 0; 120 } 121 122 static const struct of_device_id bcm2835aux_serial_match[] = { 123 { .compatible = "brcm,bcm2835-aux-uart" }, 124 { }, 125 }; 126 MODULE_DEVICE_TABLE(of, bcm2835aux_serial_match); 127 128 static struct platform_driver bcm2835aux_serial_driver = { 129 .driver = { 130 .name = "bcm2835-aux-uart", 131 .of_match_table = bcm2835aux_serial_match, 132 }, 133 .probe = bcm2835aux_serial_probe, 134 .remove = bcm2835aux_serial_remove, 135 }; 136 module_platform_driver(bcm2835aux_serial_driver); 137 138 MODULE_DESCRIPTION("BCM2835 auxiliar UART driver"); 139 MODULE_AUTHOR("Martin Sperl <kernel@martin.sperl.org>"); 140 MODULE_LICENSE("GPL v2"); 141