8250_men_mcb.c 4.5 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0
M
Michael Moese 已提交
2 3 4
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/module.h>
5
#include <linux/io.h>
M
Michael Moese 已提交
6 7 8 9 10 11
#include <linux/mcb.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
#include <linux/serial_8250.h>
#include <uapi/linux/serial_core.h>

12 13 14 15 16 17
#define MEN_UART_ID_Z025 0x19
#define MEN_UART_ID_Z057 0x39
#define MEN_UART_ID_Z125 0x7d

#define MEN_UART_MEM_SIZE 0x10

M
Michael Moese 已提交
18 19 20 21 22 23 24 25 26 27 28
struct serial_8250_men_mcb_data {
	struct uart_8250_port uart;
	int line;
};

/*
 * The Z125 16550-compatible UART has no fixed base clock assigned
 * So, depending on the board we're on, we need to adjust the
 * parameter in order to really set the correct baudrate, and
 * do so if possible without user interaction
 */
29
static u32 men_lookup_uartclk(struct mcb_device *mdev)
M
Michael Moese 已提交
30 31 32 33 34 35 36 37 38
{
	/* use default value if board is not available below */
	u32 clkval = 1041666;

	dev_info(&mdev->dev, "%s on board %s\n",
		dev_name(&mdev->dev),
		mdev->bus->name);
	if  (strncmp(mdev->bus->name, "F075", 4) == 0)
		clkval = 1041666;
39
	else if (strncmp(mdev->bus->name, "F216", 4) == 0)
M
Michael Moese 已提交
40 41 42
		clkval = 1843200;
	else if (strncmp(mdev->bus->name, "G215", 4) == 0)
		clkval = 1843200;
43 44
	else if (strncmp(mdev->bus->name, "F210", 4) == 0)
		clkval = 115200;
M
Michael Moese 已提交
45 46 47 48 49 50 51 52 53
	else
		dev_info(&mdev->dev,
			 "board not detected, using default uartclk\n");

	clkval = clkval  << 4;

	return clkval;
}

54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
static unsigned int get_num_ports(struct mcb_device *mdev,
				  void __iomem *membase)
{
	switch (mdev->id) {
	case MEN_UART_ID_Z125:
		return 1U;
	case MEN_UART_ID_Z025:
		return readb(membase) >> 4;
	case MEN_UART_ID_Z057:
		return 4U;
	default:
		dev_err(&mdev->dev, "no supported device!\n");
		return -ENODEV;
	}
}

M
Michael Moese 已提交
70 71 72 73 74
static int serial_8250_men_mcb_probe(struct mcb_device *mdev,
				     const struct mcb_device_id *id)
{
	struct serial_8250_men_mcb_data *data;
	struct resource *mem;
75 76 77
	unsigned int num_ports;
	unsigned int i;
	void __iomem *membase;
M
Michael Moese 已提交
78 79 80 81

	mem = mcb_get_resource(mdev, IORESOURCE_MEM);
	if (mem == NULL)
		return -ENXIO;
82 83 84
	membase = devm_ioremap_resource(&mdev->dev, mem);
	if (IS_ERR(membase))
		return PTR_ERR_OR_ZERO(membase);
M
Michael Moese 已提交
85

86
	num_ports = get_num_ports(mdev, membase);
M
Michael Moese 已提交
87

88 89
	dev_dbg(&mdev->dev, "found a 16z%03u with %u ports\n",
		mdev->id, num_ports);
M
Michael Moese 已提交
90

91 92 93 94 95
	if (num_ports == 0 || num_ports > 4) {
		dev_err(&mdev->dev, "unexpected number of ports: %u\n",
			num_ports);
		return -ENODEV;
	}
M
Michael Moese 已提交
96

97 98 99 100 101
	data = devm_kcalloc(&mdev->dev, num_ports,
			    sizeof(struct serial_8250_men_mcb_data),
			    GFP_KERNEL);
	if (!data)
		return -ENOMEM;
M
Michael Moese 已提交
102

103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
	mcb_set_drvdata(mdev, data);

	for (i = 0; i < num_ports; i++) {
		data[i].uart.port.dev = mdev->dma_dev;
		spin_lock_init(&data[i].uart.port.lock);

		data[i].uart.port.type = PORT_16550;
		data[i].uart.port.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ
					  | UPF_FIXED_TYPE;
		data[i].uart.port.iotype = UPIO_MEM;
		data[i].uart.port.uartclk = men_lookup_uartclk(mdev);
		data[i].uart.port.regshift = 0;
		data[i].uart.port.irq = mcb_get_irq(mdev);
		data[i].uart.port.membase = membase;
		data[i].uart.port.fifosize = 60;
		data[i].uart.port.mapbase = (unsigned long) mem->start
					    + i * MEN_UART_MEM_SIZE;
		data[i].uart.port.iobase = data[i].uart.port.mapbase;

		/* ok, register the port */
		data[i].line = serial8250_register_8250_port(&data[i].uart);
		if (data[i].line < 0) {
			dev_err(&mdev->dev, "unable to register UART port\n");
			return data[i].line;
		}
		dev_info(&mdev->dev, "found MCB UART: ttyS%d\n", data[i].line);
	}
M
Michael Moese 已提交
130 131 132 133 134 135

	return 0;
}

static void serial_8250_men_mcb_remove(struct mcb_device *mdev)
{
136
	unsigned int num_ports, i;
M
Michael Moese 已提交
137 138
	struct serial_8250_men_mcb_data *data = mcb_get_drvdata(mdev);

139 140 141 142 143 144 145 146 147 148 149
	if (!data)
		return;

	num_ports = get_num_ports(mdev, data[0].uart.port.membase);
	if (num_ports < 0 || num_ports > 4) {
		dev_err(&mdev->dev, "error retrieving number of ports!\n");
		return;
	}

	for (i = 0; i < num_ports; i++)
		serial8250_unregister_port(data[i].line);
M
Michael Moese 已提交
150 151 152
}

static const struct mcb_device_id serial_8250_men_mcb_ids[] = {
153 154 155
	{ .device = MEN_UART_ID_Z025 },
	{ .device = MEN_UART_ID_Z057 },
	{ .device = MEN_UART_ID_Z125 },
M
Michael Moese 已提交
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
	{ }
};
MODULE_DEVICE_TABLE(mcb, serial_8250_men_mcb_ids);

static struct mcb_driver mcb_driver = {
	.driver = {
		.name = "8250_men_mcb",
		.owner = THIS_MODULE,
	},
	.probe = serial_8250_men_mcb_probe,
	.remove = serial_8250_men_mcb_remove,
	.id_table = serial_8250_men_mcb_ids,
};
module_mcb_driver(mcb_driver);

MODULE_LICENSE("GPL v2");
172
MODULE_DESCRIPTION("MEN 8250 UART driver");
M
Michael Moese 已提交
173 174
MODULE_AUTHOR("Michael Moese <michael.moese@men.de");
MODULE_ALIAS("mcb:16z125");
175 176
MODULE_ALIAS("mcb:16z025");
MODULE_ALIAS("mcb:16z057");