LCOV - code coverage report
Current view: top level - drivers/tty/serial/8250 - 8250_bcm2835aux.c (source / functions) Hit Total Coverage
Test: Real Lines: 1 46 2.2 %
Date: 2020-10-17 15:46:16 Functions: 0 4 0.0 %
Legend: Neither, QEMU, Real, Both Branches: 0 0 -

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

Generated by: LCOV version 1.14