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 dev_err(&pdev->dev, "irq not found - %i", ret); 61 return ret; 62 } 63 data->uart.port.irq = ret; 64 65 /* map the main registers */ 66 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 67 if (!res) { 68 dev_err(&pdev->dev, "memory resource not found"); 69 return -EINVAL; 70 } 71 data->uart.port.membase = devm_ioremap_resource(&pdev->dev, res); 72 ret = PTR_ERR_OR_ZERO(data->uart.port.membase); 73 if (ret) 74 return ret; 75 76 /* Check for a fixed line number */ 77 ret = of_alias_get_id(pdev->dev.of_node, "serial"); 78 if (ret >= 0) 79 data->uart.port.line = ret; 80 81 /* enable the clock as a last step */ 82 ret = clk_prepare_enable(data->clk); 83 if (ret) { 84 dev_err(&pdev->dev, "unable to enable uart clock - %d\n", 85 ret); 86 return ret; 87 } 88 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. 93 */ 94 data->uart.port.uartclk = clk_get_rate(data->clk) * 2; 95 96 /* register the port */ 97 ret = serial8250_register_8250_port(&data->uart); 98 if (ret < 0) { 99 dev_err(&pdev->dev, "unable to register 8250 port - %d\n", 100 ret); 101 goto dis_clk; 102 } 103 data->line = ret; 104 105 platform_set_drvdata(pdev, data); 106 107 return 0; 108 109 dis_clk: 110 clk_disable_unprepare(data->clk); 111 return ret; 112 } 113 114 static int bcm2835aux_serial_remove(struct platform_device *pdev) 115 { 116 struct bcm2835aux_data *data = platform_get_drvdata(pdev); 117 118 serial8250_unregister_port(data->uart.port.line); 119 clk_disable_unprepare(data->clk); 120 121 return 0; 122 } 123 124 static const struct of_device_id bcm2835aux_serial_match[] = { 125 { .compatible = "brcm,bcm2835-aux-uart" }, 126 { }, 127 }; 128 MODULE_DEVICE_TABLE(of, bcm2835aux_serial_match); 129 130 static struct platform_driver bcm2835aux_serial_driver = { 131 .driver = { 132 .name = "bcm2835-aux-uart", 133 .of_match_table = bcm2835aux_serial_match, 134 }, 135 .probe = bcm2835aux_serial_probe, 136 .remove = bcm2835aux_serial_remove, 137 }; 138 module_platform_driver(bcm2835aux_serial_driver); 139 140 MODULE_DESCRIPTION("BCM2835 auxiliar UART driver"); 141 MODULE_AUTHOR("Martin Sperl <kernel@martin.sperl.org>"); 142 MODULE_LICENSE("GPL v2"); 143