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