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