linux/drivers/tty/serial/8250/8250_acorn.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 *  linux/drivers/serial/acorn.c
   4 *
   5 *  Copyright (C) 1996-2003 Russell King.
   6 */
   7#include <linux/module.h>
   8#include <linux/types.h>
   9#include <linux/tty.h>
  10#include <linux/serial_core.h>
  11#include <linux/errno.h>
  12#include <linux/ioport.h>
  13#include <linux/slab.h>
  14#include <linux/device.h>
  15#include <linux/init.h>
  16
  17#include <asm/io.h>
  18#include <asm/ecard.h>
  19#include <asm/string.h>
  20
  21#include "8250.h"
  22
  23#define MAX_PORTS       3
  24
  25struct serial_card_type {
  26        unsigned int    num_ports;
  27        unsigned int    uartclk;
  28        unsigned int    type;
  29        unsigned int    offset[MAX_PORTS];
  30};
  31
  32struct serial_card_info {
  33        unsigned int    num_ports;
  34        int             ports[MAX_PORTS];
  35        void __iomem *vaddr;
  36};
  37
  38static int
  39serial_card_probe(struct expansion_card *ec, const struct ecard_id *id)
  40{
  41        struct serial_card_info *info;
  42        struct serial_card_type *type = id->data;
  43        struct uart_8250_port uart;
  44        unsigned long bus_addr;
  45        unsigned int i;
  46
  47        info = kzalloc(sizeof(struct serial_card_info), GFP_KERNEL);
  48        if (!info)
  49                return -ENOMEM;
  50
  51        info->num_ports = type->num_ports;
  52
  53        bus_addr = ecard_resource_start(ec, type->type);
  54        info->vaddr = ecardm_iomap(ec, type->type, 0, 0);
  55        if (!info->vaddr) {
  56                kfree(info);
  57                return -ENOMEM;
  58        }
  59
  60        ecard_set_drvdata(ec, info);
  61
  62        memset(&uart, 0, sizeof(struct uart_8250_port));
  63        uart.port.irq   = ec->irq;
  64        uart.port.flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
  65        uart.port.uartclk       = type->uartclk;
  66        uart.port.iotype        = UPIO_MEM;
  67        uart.port.regshift      = 2;
  68        uart.port.dev   = &ec->dev;
  69
  70        for (i = 0; i < info->num_ports; i++) {
  71                uart.port.membase = info->vaddr + type->offset[i];
  72                uart.port.mapbase = bus_addr + type->offset[i];
  73
  74                info->ports[i] = serial8250_register_8250_port(&uart);
  75        }
  76
  77        return 0;
  78}
  79
  80static void serial_card_remove(struct expansion_card *ec)
  81{
  82        struct serial_card_info *info = ecard_get_drvdata(ec);
  83        int i;
  84
  85        ecard_set_drvdata(ec, NULL);
  86
  87        for (i = 0; i < info->num_ports; i++)
  88                if (info->ports[i] > 0)
  89                        serial8250_unregister_port(info->ports[i]);
  90
  91        kfree(info);
  92}
  93
  94static struct serial_card_type atomwide_type = {
  95        .num_ports      = 3,
  96        .uartclk        = 7372800,
  97        .type           = ECARD_RES_IOCSLOW,
  98        .offset         = { 0x2800, 0x2400, 0x2000 },
  99};
 100
 101static struct serial_card_type serport_type = {
 102        .num_ports      = 2,
 103        .uartclk        = 3686400,
 104        .type           = ECARD_RES_IOCSLOW,
 105        .offset         = { 0x2000, 0x2020 },
 106};
 107
 108static const struct ecard_id serial_cids[] = {
 109        { MANU_ATOMWIDE,        PROD_ATOMWIDE_3PSERIAL, &atomwide_type  },
 110        { MANU_SERPORT,         PROD_SERPORT_DSPORT,    &serport_type   },
 111        { 0xffff, 0xffff }
 112};
 113
 114static struct ecard_driver serial_card_driver = {
 115        .probe          = serial_card_probe,
 116        .remove         = serial_card_remove,
 117        .id_table       = serial_cids,
 118        .drv = {
 119                .name   = "8250_acorn",
 120        },
 121};
 122
 123static int __init serial_card_init(void)
 124{
 125        return ecard_register_driver(&serial_card_driver);
 126}
 127
 128static void __exit serial_card_exit(void)
 129{
 130        ecard_remove_driver(&serial_card_driver);
 131}
 132
 133MODULE_AUTHOR("Russell King");
 134MODULE_DESCRIPTION("Acorn 8250-compatible serial port expansion card driver");
 135MODULE_LICENSE("GPL");
 136
 137module_init(serial_card_init);
 138module_exit(serial_card_exit);
 139