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

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

DEFINITIONS

This source file includes following definitions.
  1. serial8250_em_serial_out
  2. serial8250_em_serial_in
  3. serial8250_em_serial_dl_read
  4. serial8250_em_serial_dl_write
  5. serial8250_em_probe
  6. serial8250_em_remove

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Renesas Emma Mobile 8250 driver
   4  *
   5  *  Copyright (C) 2012 Magnus Damm
   6  */
   7 
   8 #include <linux/device.h>
   9 #include <linux/io.h>
  10 #include <linux/module.h>
  11 #include <linux/mod_devicetable.h>
  12 #include <linux/serial_8250.h>
  13 #include <linux/serial_reg.h>
  14 #include <linux/platform_device.h>
  15 #include <linux/clk.h>
  16 #include <linux/slab.h>
  17 
  18 #include "8250.h"
  19 
  20 #define UART_DLL_EM 9
  21 #define UART_DLM_EM 10
  22 
  23 struct serial8250_em_priv {
  24         struct clk *sclk;
  25         int line;
  26 };
  27 
  28 static void serial8250_em_serial_out(struct uart_port *p, int offset, int value)
  29 {
  30         switch (offset) {
  31         case UART_TX: /* TX @ 0x00 */
  32                 writeb(value, p->membase);
  33                 break;
  34         case UART_FCR: /* FCR @ 0x0c (+1) */
  35         case UART_LCR: /* LCR @ 0x10 (+1) */
  36         case UART_MCR: /* MCR @ 0x14 (+1) */
  37         case UART_SCR: /* SCR @ 0x20 (+1) */
  38                 writel(value, p->membase + ((offset + 1) << 2));
  39                 break;
  40         case UART_IER: /* IER @ 0x04 */
  41                 value &= 0x0f; /* only 4 valid bits - not Xscale */
  42                 /* fall-through */
  43         case UART_DLL_EM: /* DLL @ 0x24 (+9) */
  44         case UART_DLM_EM: /* DLM @ 0x28 (+9) */
  45                 writel(value, p->membase + (offset << 2));
  46         }
  47 }
  48 
  49 static unsigned int serial8250_em_serial_in(struct uart_port *p, int offset)
  50 {
  51         switch (offset) {
  52         case UART_RX: /* RX @ 0x00 */
  53                 return readb(p->membase);
  54         case UART_MCR: /* MCR @ 0x14 (+1) */
  55         case UART_LSR: /* LSR @ 0x18 (+1) */
  56         case UART_MSR: /* MSR @ 0x1c (+1) */
  57         case UART_SCR: /* SCR @ 0x20 (+1) */
  58                 return readl(p->membase + ((offset + 1) << 2));
  59         case UART_IER: /* IER @ 0x04 */
  60         case UART_IIR: /* IIR @ 0x08 */
  61         case UART_DLL_EM: /* DLL @ 0x24 (+9) */
  62         case UART_DLM_EM: /* DLM @ 0x28 (+9) */
  63                 return readl(p->membase + (offset << 2));
  64         }
  65         return 0;
  66 }
  67 
  68 static int serial8250_em_serial_dl_read(struct uart_8250_port *up)
  69 {
  70         return serial_in(up, UART_DLL_EM) | serial_in(up, UART_DLM_EM) << 8;
  71 }
  72 
  73 static void serial8250_em_serial_dl_write(struct uart_8250_port *up, int value)
  74 {
  75         serial_out(up, UART_DLL_EM, value & 0xff);
  76         serial_out(up, UART_DLM_EM, value >> 8 & 0xff);
  77 }
  78 
  79 static int serial8250_em_probe(struct platform_device *pdev)
  80 {
  81         struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  82         struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
  83         struct serial8250_em_priv *priv;
  84         struct uart_8250_port up;
  85         int ret;
  86 
  87         if (!regs || !irq) {
  88                 dev_err(&pdev->dev, "missing registers or irq\n");
  89                 return -EINVAL;
  90         }
  91 
  92         priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
  93         if (!priv)
  94                 return -ENOMEM;
  95 
  96         priv->sclk = devm_clk_get(&pdev->dev, "sclk");
  97         if (IS_ERR(priv->sclk)) {
  98                 dev_err(&pdev->dev, "unable to get clock\n");
  99                 return PTR_ERR(priv->sclk);
 100         }
 101 
 102         memset(&up, 0, sizeof(up));
 103         up.port.mapbase = regs->start;
 104         up.port.irq = irq->start;
 105         up.port.type = PORT_UNKNOWN;
 106         up.port.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | UPF_IOREMAP;
 107         up.port.dev = &pdev->dev;
 108         up.port.private_data = priv;
 109 
 110         clk_prepare_enable(priv->sclk);
 111         up.port.uartclk = clk_get_rate(priv->sclk);
 112 
 113         up.port.iotype = UPIO_MEM32;
 114         up.port.serial_in = serial8250_em_serial_in;
 115         up.port.serial_out = serial8250_em_serial_out;
 116         up.dl_read = serial8250_em_serial_dl_read;
 117         up.dl_write = serial8250_em_serial_dl_write;
 118 
 119         ret = serial8250_register_8250_port(&up);
 120         if (ret < 0) {
 121                 dev_err(&pdev->dev, "unable to register 8250 port\n");
 122                 clk_disable_unprepare(priv->sclk);
 123                 return ret;
 124         }
 125 
 126         priv->line = ret;
 127         platform_set_drvdata(pdev, priv);
 128         return 0;
 129 }
 130 
 131 static int serial8250_em_remove(struct platform_device *pdev)
 132 {
 133         struct serial8250_em_priv *priv = platform_get_drvdata(pdev);
 134 
 135         serial8250_unregister_port(priv->line);
 136         clk_disable_unprepare(priv->sclk);
 137         return 0;
 138 }
 139 
 140 static const struct of_device_id serial8250_em_dt_ids[] = {
 141         { .compatible = "renesas,em-uart", },
 142         {},
 143 };
 144 MODULE_DEVICE_TABLE(of, serial8250_em_dt_ids);
 145 
 146 static struct platform_driver serial8250_em_platform_driver = {
 147         .driver = {
 148                 .name           = "serial8250-em",
 149                 .of_match_table = serial8250_em_dt_ids,
 150         },
 151         .probe                  = serial8250_em_probe,
 152         .remove                 = serial8250_em_remove,
 153 };
 154 
 155 module_platform_driver(serial8250_em_platform_driver);
 156 
 157 MODULE_AUTHOR("Magnus Damm");
 158 MODULE_DESCRIPTION("Renesas Emma Mobile 8250 Driver");
 159 MODULE_LICENSE("GPL v2");

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