Linux Audio

Check our new training course

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