1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun #include <linux/device.h>
3*4882a593Smuzhiyun #include <linux/kernel.h>
4*4882a593Smuzhiyun #include <linux/module.h>
5*4882a593Smuzhiyun #include <linux/io.h>
6*4882a593Smuzhiyun #include <linux/mcb.h>
7*4882a593Smuzhiyun #include <linux/serial.h>
8*4882a593Smuzhiyun #include <linux/serial_core.h>
9*4882a593Smuzhiyun #include <linux/serial_8250.h>
10*4882a593Smuzhiyun #include <uapi/linux/serial_core.h>
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun #define MEN_UART_ID_Z025 0x19
13*4882a593Smuzhiyun #define MEN_UART_ID_Z057 0x39
14*4882a593Smuzhiyun #define MEN_UART_ID_Z125 0x7d
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun #define MEN_UART_MEM_SIZE 0x10
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun struct serial_8250_men_mcb_data {
19*4882a593Smuzhiyun struct uart_8250_port uart;
20*4882a593Smuzhiyun int line;
21*4882a593Smuzhiyun };
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun /*
24*4882a593Smuzhiyun * The Z125 16550-compatible UART has no fixed base clock assigned
25*4882a593Smuzhiyun * So, depending on the board we're on, we need to adjust the
26*4882a593Smuzhiyun * parameter in order to really set the correct baudrate, and
27*4882a593Smuzhiyun * do so if possible without user interaction
28*4882a593Smuzhiyun */
men_lookup_uartclk(struct mcb_device * mdev)29*4882a593Smuzhiyun static u32 men_lookup_uartclk(struct mcb_device *mdev)
30*4882a593Smuzhiyun {
31*4882a593Smuzhiyun /* use default value if board is not available below */
32*4882a593Smuzhiyun u32 clkval = 1041666;
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun dev_info(&mdev->dev, "%s on board %s\n",
35*4882a593Smuzhiyun dev_name(&mdev->dev),
36*4882a593Smuzhiyun mdev->bus->name);
37*4882a593Smuzhiyun if (strncmp(mdev->bus->name, "F075", 4) == 0)
38*4882a593Smuzhiyun clkval = 1041666;
39*4882a593Smuzhiyun else if (strncmp(mdev->bus->name, "F216", 4) == 0)
40*4882a593Smuzhiyun clkval = 1843200;
41*4882a593Smuzhiyun else if (strncmp(mdev->bus->name, "G215", 4) == 0)
42*4882a593Smuzhiyun clkval = 1843200;
43*4882a593Smuzhiyun else if (strncmp(mdev->bus->name, "F210", 4) == 0)
44*4882a593Smuzhiyun clkval = 115200;
45*4882a593Smuzhiyun else
46*4882a593Smuzhiyun dev_info(&mdev->dev,
47*4882a593Smuzhiyun "board not detected, using default uartclk\n");
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun clkval = clkval << 4;
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun return clkval;
52*4882a593Smuzhiyun }
53*4882a593Smuzhiyun
get_num_ports(struct mcb_device * mdev,void __iomem * membase)54*4882a593Smuzhiyun static int get_num_ports(struct mcb_device *mdev,
55*4882a593Smuzhiyun void __iomem *membase)
56*4882a593Smuzhiyun {
57*4882a593Smuzhiyun switch (mdev->id) {
58*4882a593Smuzhiyun case MEN_UART_ID_Z125:
59*4882a593Smuzhiyun return 1U;
60*4882a593Smuzhiyun case MEN_UART_ID_Z025:
61*4882a593Smuzhiyun return readb(membase) >> 4;
62*4882a593Smuzhiyun case MEN_UART_ID_Z057:
63*4882a593Smuzhiyun return 4U;
64*4882a593Smuzhiyun default:
65*4882a593Smuzhiyun dev_err(&mdev->dev, "no supported device!\n");
66*4882a593Smuzhiyun return -ENODEV;
67*4882a593Smuzhiyun }
68*4882a593Smuzhiyun }
69*4882a593Smuzhiyun
serial_8250_men_mcb_probe(struct mcb_device * mdev,const struct mcb_device_id * id)70*4882a593Smuzhiyun static int serial_8250_men_mcb_probe(struct mcb_device *mdev,
71*4882a593Smuzhiyun const struct mcb_device_id *id)
72*4882a593Smuzhiyun {
73*4882a593Smuzhiyun struct serial_8250_men_mcb_data *data;
74*4882a593Smuzhiyun struct resource *mem;
75*4882a593Smuzhiyun int num_ports;
76*4882a593Smuzhiyun int i;
77*4882a593Smuzhiyun void __iomem *membase;
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun mem = mcb_get_resource(mdev, IORESOURCE_MEM);
80*4882a593Smuzhiyun if (mem == NULL)
81*4882a593Smuzhiyun return -ENXIO;
82*4882a593Smuzhiyun membase = devm_ioremap_resource(&mdev->dev, mem);
83*4882a593Smuzhiyun if (IS_ERR(membase))
84*4882a593Smuzhiyun return PTR_ERR_OR_ZERO(membase);
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun num_ports = get_num_ports(mdev, membase);
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun dev_dbg(&mdev->dev, "found a 16z%03u with %u ports\n",
89*4882a593Smuzhiyun mdev->id, num_ports);
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun if (num_ports <= 0 || num_ports > 4) {
92*4882a593Smuzhiyun dev_err(&mdev->dev, "unexpected number of ports: %u\n",
93*4882a593Smuzhiyun num_ports);
94*4882a593Smuzhiyun return -ENODEV;
95*4882a593Smuzhiyun }
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun data = devm_kcalloc(&mdev->dev, num_ports,
98*4882a593Smuzhiyun sizeof(struct serial_8250_men_mcb_data),
99*4882a593Smuzhiyun GFP_KERNEL);
100*4882a593Smuzhiyun if (!data)
101*4882a593Smuzhiyun return -ENOMEM;
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun mcb_set_drvdata(mdev, data);
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun for (i = 0; i < num_ports; i++) {
106*4882a593Smuzhiyun data[i].uart.port.dev = mdev->dma_dev;
107*4882a593Smuzhiyun spin_lock_init(&data[i].uart.port.lock);
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun data[i].uart.port.type = PORT_16550;
110*4882a593Smuzhiyun data[i].uart.port.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ
111*4882a593Smuzhiyun | UPF_FIXED_TYPE;
112*4882a593Smuzhiyun data[i].uart.port.iotype = UPIO_MEM;
113*4882a593Smuzhiyun data[i].uart.port.uartclk = men_lookup_uartclk(mdev);
114*4882a593Smuzhiyun data[i].uart.port.regshift = 0;
115*4882a593Smuzhiyun data[i].uart.port.irq = mcb_get_irq(mdev);
116*4882a593Smuzhiyun data[i].uart.port.membase = membase;
117*4882a593Smuzhiyun data[i].uart.port.fifosize = 60;
118*4882a593Smuzhiyun data[i].uart.port.mapbase = (unsigned long) mem->start
119*4882a593Smuzhiyun + i * MEN_UART_MEM_SIZE;
120*4882a593Smuzhiyun data[i].uart.port.iobase = data[i].uart.port.mapbase;
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun /* ok, register the port */
123*4882a593Smuzhiyun data[i].line = serial8250_register_8250_port(&data[i].uart);
124*4882a593Smuzhiyun if (data[i].line < 0) {
125*4882a593Smuzhiyun dev_err(&mdev->dev, "unable to register UART port\n");
126*4882a593Smuzhiyun return data[i].line;
127*4882a593Smuzhiyun }
128*4882a593Smuzhiyun dev_info(&mdev->dev, "found MCB UART: ttyS%d\n", data[i].line);
129*4882a593Smuzhiyun }
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun return 0;
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun
serial_8250_men_mcb_remove(struct mcb_device * mdev)134*4882a593Smuzhiyun static void serial_8250_men_mcb_remove(struct mcb_device *mdev)
135*4882a593Smuzhiyun {
136*4882a593Smuzhiyun int num_ports, i;
137*4882a593Smuzhiyun struct serial_8250_men_mcb_data *data = mcb_get_drvdata(mdev);
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun if (!data)
140*4882a593Smuzhiyun return;
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun num_ports = get_num_ports(mdev, data[0].uart.port.membase);
143*4882a593Smuzhiyun if (num_ports <= 0 || num_ports > 4) {
144*4882a593Smuzhiyun dev_err(&mdev->dev, "error retrieving number of ports!\n");
145*4882a593Smuzhiyun return;
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun for (i = 0; i < num_ports; i++)
149*4882a593Smuzhiyun serial8250_unregister_port(data[i].line);
150*4882a593Smuzhiyun }
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun static const struct mcb_device_id serial_8250_men_mcb_ids[] = {
153*4882a593Smuzhiyun { .device = MEN_UART_ID_Z025 },
154*4882a593Smuzhiyun { .device = MEN_UART_ID_Z057 },
155*4882a593Smuzhiyun { .device = MEN_UART_ID_Z125 },
156*4882a593Smuzhiyun { }
157*4882a593Smuzhiyun };
158*4882a593Smuzhiyun MODULE_DEVICE_TABLE(mcb, serial_8250_men_mcb_ids);
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun static struct mcb_driver mcb_driver = {
161*4882a593Smuzhiyun .driver = {
162*4882a593Smuzhiyun .name = "8250_men_mcb",
163*4882a593Smuzhiyun .owner = THIS_MODULE,
164*4882a593Smuzhiyun },
165*4882a593Smuzhiyun .probe = serial_8250_men_mcb_probe,
166*4882a593Smuzhiyun .remove = serial_8250_men_mcb_remove,
167*4882a593Smuzhiyun .id_table = serial_8250_men_mcb_ids,
168*4882a593Smuzhiyun };
169*4882a593Smuzhiyun module_mcb_driver(mcb_driver);
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
172*4882a593Smuzhiyun MODULE_DESCRIPTION("MEN 8250 UART driver");
173*4882a593Smuzhiyun MODULE_AUTHOR("Michael Moese <michael.moese@men.de");
174*4882a593Smuzhiyun MODULE_ALIAS("mcb:16z125");
175*4882a593Smuzhiyun MODULE_ALIAS("mcb:16z025");
176*4882a593Smuzhiyun MODULE_ALIAS("mcb:16z057");
177*4882a593Smuzhiyun MODULE_IMPORT_NS(MCB);
178