root/drivers/tty/serial/8250/8250_bcm2835aux.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. bcm2835aux_serial_probe
  2. bcm2835aux_serial_remove

   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->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");

/* [<][>][^][v][top][bottom][index][help] */