Branch data Line data Source code
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 : 0 : 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 : 0 : data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); 33 [ # # ]: 0 : if (!data) 34 : : return -ENOMEM; 35 : : 36 : : /* initialize data */ 37 : 0 : spin_lock_init(&data->uart.port.lock); 38 : 0 : data->uart.capabilities = UART_CAP_FIFO | UART_CAP_MINI; 39 : 0 : data->uart.port.dev = &pdev->dev; 40 : 0 : data->uart.port.regshift = 2; 41 : 0 : data->uart.port.type = PORT_16550; 42 : 0 : data->uart.port.iotype = UPIO_MEM; 43 : 0 : data->uart.port.fifosize = 8; 44 : 0 : 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 : 0 : data->clk = devm_clk_get(&pdev->dev, NULL); 51 : : ret = PTR_ERR_OR_ZERO(data->clk); 52 [ # # ]: 0 : if (ret) { 53 [ # # ]: 0 : if (ret != -EPROBE_DEFER) 54 : 0 : dev_err(&pdev->dev, "could not get clk: %d\n", ret); 55 : 0 : return ret; 56 : : } 57 : : 58 : : /* get the interrupt */ 59 : 0 : ret = platform_get_irq(pdev, 0); 60 [ # # ]: 0 : if (ret < 0) 61 : : return ret; 62 : 0 : data->uart.port.irq = ret; 63 : : 64 : : /* map the main registers */ 65 : 0 : res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 66 [ # # ]: 0 : if (!res) { 67 : 0 : dev_err(&pdev->dev, "memory resource not found"); 68 : 0 : return -EINVAL; 69 : : } 70 : 0 : data->uart.port.membase = devm_ioremap_resource(&pdev->dev, res); 71 : : ret = PTR_ERR_OR_ZERO(data->uart.port.membase); 72 [ # # ]: 0 : if (ret) 73 : : return ret; 74 : : 75 : : /* Check for a fixed line number */ 76 : 0 : ret = of_alias_get_id(pdev->dev.of_node, "serial"); 77 [ # # ]: 0 : if (ret >= 0) 78 : 0 : data->uart.port.line = ret; 79 : : 80 : : /* enable the clock as a last step */ 81 : 0 : ret = clk_prepare_enable(data->clk); 82 [ # # ]: 0 : if (ret) { 83 : 0 : dev_err(&pdev->dev, "unable to enable uart clock - %d\n", 84 : : ret); 85 : 0 : return ret; 86 : : } 87 : : 88 : : /* the HW-clock divider for bcm2835aux is 8, 89 : : * but 8250 expects a divider of 16, 90 : : * so we have to multiply the actual clock by 2 91 : : * to get identical baudrates. 92 : : */ 93 : 0 : data->uart.port.uartclk = clk_get_rate(data->clk) * 2; 94 : : 95 : : /* The clock is only queried at probe time, which means we get one shot 96 : : * at this. A zero clock is never going to work and is almost certainly 97 : : * due to a parent not being ready, so prefer to defer. 98 : : */ 99 [ # # ]: 0 : if (!data->uart.port.uartclk) 100 : : return -EPROBE_DEFER; 101 : : 102 : : /* register the port */ 103 : 0 : ret = serial8250_register_8250_port(&data->uart); 104 [ # # ]: 0 : if (ret < 0) { 105 : 0 : dev_err(&pdev->dev, "unable to register 8250 port - %d\n", 106 : : ret); 107 : : goto dis_clk; 108 : : } 109 : 0 : data->line = ret; 110 : : 111 : : platform_set_drvdata(pdev, data); 112 : : 113 : 0 : return 0; 114 : : 115 : : dis_clk: 116 : 0 : clk_disable_unprepare(data->clk); 117 : 0 : return ret; 118 : : } 119 : : 120 : 0 : static int bcm2835aux_serial_remove(struct platform_device *pdev) 121 : : { 122 : : struct bcm2835aux_data *data = platform_get_drvdata(pdev); 123 : : 124 : 0 : serial8250_unregister_port(data->line); 125 : 0 : clk_disable_unprepare(data->clk); 126 : : 127 : 0 : return 0; 128 : : } 129 : : 130 : : static const struct of_device_id bcm2835aux_serial_match[] = { 131 : : { .compatible = "brcm,bcm2835-aux-uart" }, 132 : : { }, 133 : : }; 134 : : MODULE_DEVICE_TABLE(of, bcm2835aux_serial_match); 135 : : 136 : : static struct platform_driver bcm2835aux_serial_driver = { 137 : : .driver = { 138 : : .name = "bcm2835-aux-uart", 139 : : .of_match_table = bcm2835aux_serial_match, 140 : : }, 141 : : .probe = bcm2835aux_serial_probe, 142 : : .remove = bcm2835aux_serial_remove, 143 : : }; 144 : 207 : module_platform_driver(bcm2835aux_serial_driver); 145 : : 146 : : MODULE_DESCRIPTION("BCM2835 auxiliar UART driver"); 147 : : MODULE_AUTHOR("Martin Sperl <kernel@martin.sperl.org>"); 148 : : MODULE_LICENSE("GPL v2");