Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Renesas Emma Mobile 8250 driver
0004  *
0005  *  Copyright (C) 2012 Magnus Damm
0006  */
0007 
0008 #include <linux/device.h>
0009 #include <linux/io.h>
0010 #include <linux/module.h>
0011 #include <linux/mod_devicetable.h>
0012 #include <linux/serial_8250.h>
0013 #include <linux/serial_reg.h>
0014 #include <linux/platform_device.h>
0015 #include <linux/clk.h>
0016 #include <linux/slab.h>
0017 
0018 #include "8250.h"
0019 
0020 #define UART_DLL_EM 9
0021 #define UART_DLM_EM 10
0022 
0023 struct serial8250_em_priv {
0024     struct clk *sclk;
0025     int line;
0026 };
0027 
0028 static void serial8250_em_serial_out(struct uart_port *p, int offset, int value)
0029 {
0030     switch (offset) {
0031     case UART_TX: /* TX @ 0x00 */
0032         writeb(value, p->membase);
0033         break;
0034     case UART_FCR: /* FCR @ 0x0c (+1) */
0035     case UART_LCR: /* LCR @ 0x10 (+1) */
0036     case UART_MCR: /* MCR @ 0x14 (+1) */
0037     case UART_SCR: /* SCR @ 0x20 (+1) */
0038         writel(value, p->membase + ((offset + 1) << 2));
0039         break;
0040     case UART_IER: /* IER @ 0x04 */
0041         value &= 0x0f; /* only 4 valid bits - not Xscale */
0042         fallthrough;
0043     case UART_DLL_EM: /* DLL @ 0x24 (+9) */
0044     case UART_DLM_EM: /* DLM @ 0x28 (+9) */
0045         writel(value, p->membase + (offset << 2));
0046     }
0047 }
0048 
0049 static unsigned int serial8250_em_serial_in(struct uart_port *p, int offset)
0050 {
0051     switch (offset) {
0052     case UART_RX: /* RX @ 0x00 */
0053         return readb(p->membase);
0054     case UART_MCR: /* MCR @ 0x14 (+1) */
0055     case UART_LSR: /* LSR @ 0x18 (+1) */
0056     case UART_MSR: /* MSR @ 0x1c (+1) */
0057     case UART_SCR: /* SCR @ 0x20 (+1) */
0058         return readl(p->membase + ((offset + 1) << 2));
0059     case UART_IER: /* IER @ 0x04 */
0060     case UART_IIR: /* IIR @ 0x08 */
0061     case UART_DLL_EM: /* DLL @ 0x24 (+9) */
0062     case UART_DLM_EM: /* DLM @ 0x28 (+9) */
0063         return readl(p->membase + (offset << 2));
0064     }
0065     return 0;
0066 }
0067 
0068 static int serial8250_em_serial_dl_read(struct uart_8250_port *up)
0069 {
0070     return serial_in(up, UART_DLL_EM) | serial_in(up, UART_DLM_EM) << 8;
0071 }
0072 
0073 static void serial8250_em_serial_dl_write(struct uart_8250_port *up, int value)
0074 {
0075     serial_out(up, UART_DLL_EM, value & 0xff);
0076     serial_out(up, UART_DLM_EM, value >> 8 & 0xff);
0077 }
0078 
0079 static int serial8250_em_probe(struct platform_device *pdev)
0080 {
0081     struct serial8250_em_priv *priv;
0082     struct uart_8250_port up;
0083     struct resource *regs;
0084     int irq, ret;
0085 
0086     irq = platform_get_irq(pdev, 0);
0087     if (irq < 0)
0088         return irq;
0089 
0090     regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0091     if (!regs) {
0092         dev_err(&pdev->dev, "missing registers\n");
0093         return -EINVAL;
0094     }
0095 
0096     priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
0097     if (!priv)
0098         return -ENOMEM;
0099 
0100     priv->sclk = devm_clk_get(&pdev->dev, "sclk");
0101     if (IS_ERR(priv->sclk)) {
0102         dev_err(&pdev->dev, "unable to get clock\n");
0103         return PTR_ERR(priv->sclk);
0104     }
0105 
0106     memset(&up, 0, sizeof(up));
0107     up.port.mapbase = regs->start;
0108     up.port.irq = irq;
0109     up.port.type = PORT_UNKNOWN;
0110     up.port.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | UPF_IOREMAP;
0111     up.port.dev = &pdev->dev;
0112     up.port.private_data = priv;
0113 
0114     clk_prepare_enable(priv->sclk);
0115     up.port.uartclk = clk_get_rate(priv->sclk);
0116 
0117     up.port.iotype = UPIO_MEM32;
0118     up.port.serial_in = serial8250_em_serial_in;
0119     up.port.serial_out = serial8250_em_serial_out;
0120     up.dl_read = serial8250_em_serial_dl_read;
0121     up.dl_write = serial8250_em_serial_dl_write;
0122 
0123     ret = serial8250_register_8250_port(&up);
0124     if (ret < 0) {
0125         dev_err(&pdev->dev, "unable to register 8250 port\n");
0126         clk_disable_unprepare(priv->sclk);
0127         return ret;
0128     }
0129 
0130     priv->line = ret;
0131     platform_set_drvdata(pdev, priv);
0132     return 0;
0133 }
0134 
0135 static int serial8250_em_remove(struct platform_device *pdev)
0136 {
0137     struct serial8250_em_priv *priv = platform_get_drvdata(pdev);
0138 
0139     serial8250_unregister_port(priv->line);
0140     clk_disable_unprepare(priv->sclk);
0141     return 0;
0142 }
0143 
0144 static const struct of_device_id serial8250_em_dt_ids[] = {
0145     { .compatible = "renesas,em-uart", },
0146     {},
0147 };
0148 MODULE_DEVICE_TABLE(of, serial8250_em_dt_ids);
0149 
0150 static struct platform_driver serial8250_em_platform_driver = {
0151     .driver = {
0152         .name       = "serial8250-em",
0153         .of_match_table = serial8250_em_dt_ids,
0154     },
0155     .probe          = serial8250_em_probe,
0156     .remove         = serial8250_em_remove,
0157 };
0158 
0159 module_platform_driver(serial8250_em_platform_driver);
0160 
0161 MODULE_AUTHOR("Magnus Damm");
0162 MODULE_DESCRIPTION("Renesas Emma Mobile 8250 Driver");
0163 MODULE_LICENSE("GPL v2");