Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * SGI IOC3 8250 UART driver
0004  *
0005  * Copyright (C) 2019 Thomas Bogendoerfer <tbogendoerfer@suse.de>
0006  *
0007  * based on code Copyright (C) 2005 Stanislaw Skowronek <skylark@unaligned.org>
0008  *               Copyright (C) 2014 Joshua Kinard <kumba@gentoo.org>
0009  */
0010 
0011 #include <linux/module.h>
0012 #include <linux/errno.h>
0013 #include <linux/io.h>
0014 #include <linux/platform_device.h>
0015 
0016 #include "8250.h"
0017 
0018 #define IOC3_UARTCLK (22000000 / 3)
0019 
0020 struct ioc3_8250_data {
0021     int line;
0022 };
0023 
0024 static unsigned int ioc3_serial_in(struct uart_port *p, int offset)
0025 {
0026     return readb(p->membase + (offset ^ 3));
0027 }
0028 
0029 static void ioc3_serial_out(struct uart_port *p, int offset, int value)
0030 {
0031     writeb(value, p->membase + (offset ^ 3));
0032 }
0033 
0034 static int serial8250_ioc3_probe(struct platform_device *pdev)
0035 {
0036     struct ioc3_8250_data *data;
0037     struct uart_8250_port up;
0038     struct resource *r;
0039     void __iomem *membase;
0040     int irq, line;
0041 
0042     r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0043     if (!r)
0044         return -ENODEV;
0045 
0046     data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
0047     if (!data)
0048         return -ENOMEM;
0049 
0050     membase = devm_ioremap(&pdev->dev, r->start, resource_size(r));
0051     if (!membase)
0052         return -ENOMEM;
0053 
0054     irq = platform_get_irq(pdev, 0);
0055     if (irq < 0)
0056         irq = 0; /* no interrupt -> use polling */
0057 
0058     /* Register serial ports with 8250.c */
0059     memset(&up, 0, sizeof(struct uart_8250_port));
0060     up.port.iotype = UPIO_MEM;
0061     up.port.uartclk = IOC3_UARTCLK;
0062     up.port.type = PORT_16550A;
0063     up.port.irq = irq;
0064     up.port.flags = (UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ);
0065     up.port.dev = &pdev->dev;
0066     up.port.membase = membase;
0067     up.port.mapbase = r->start;
0068     up.port.serial_in = ioc3_serial_in;
0069     up.port.serial_out = ioc3_serial_out;
0070     line = serial8250_register_8250_port(&up);
0071     if (line < 0)
0072         return line;
0073 
0074     platform_set_drvdata(pdev, data);
0075     return 0;
0076 }
0077 
0078 static int serial8250_ioc3_remove(struct platform_device *pdev)
0079 {
0080     struct ioc3_8250_data *data = platform_get_drvdata(pdev);
0081 
0082     serial8250_unregister_port(data->line);
0083     return 0;
0084 }
0085 
0086 static struct platform_driver serial8250_ioc3_driver = {
0087     .probe  = serial8250_ioc3_probe,
0088     .remove = serial8250_ioc3_remove,
0089     .driver = {
0090         .name = "ioc3-serial8250",
0091     }
0092 };
0093 
0094 module_platform_driver(serial8250_ioc3_driver);
0095 
0096 MODULE_AUTHOR("Thomas Bogendoerfer <tbogendoerfer@suse.de>");
0097 MODULE_DESCRIPTION("SGI IOC3 8250 UART driver");
0098 MODULE_LICENSE("GPL");