diff options
-rw-r--r-- | drivers/tty/serial/8250/8250_men_mcb.c | 125 | ||||
-rw-r--r-- | drivers/tty/serial/8250/Kconfig | 5 |
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 | |||
10 | struct serial_8250_men_mcb_data { | 17 | struct 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 | */ |
21 | static u32 men_z125_lookup_uartclk(struct mcb_device *mdev) | 28 | static 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 | ||
53 | static 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 | |||
44 | static int serial_8250_men_mcb_probe(struct mcb_device *mdev, | 69 | static 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 | ||
90 | static void serial_8250_men_mcb_remove(struct mcb_device *mdev) | 133 | static 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 | ||
98 | static const struct mcb_device_id serial_8250_men_mcb_ids[] = { | 151 | static 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 | }; |
102 | MODULE_DEVICE_TABLE(mcb, serial_8250_men_mcb_ids); | 157 | MODULE_DEVICE_TABLE(mcb, serial_8250_men_mcb_ids); |
@@ -113,6 +168,8 @@ static struct mcb_driver mcb_driver = { | |||
113 | module_mcb_driver(mcb_driver); | 168 | module_mcb_driver(mcb_driver); |
114 | 169 | ||
115 | MODULE_LICENSE("GPL v2"); | 170 | MODULE_LICENSE("GPL v2"); |
116 | MODULE_DESCRIPTION("MEN 16z125 8250 UART driver"); | 171 | MODULE_DESCRIPTION("MEN 8250 UART driver"); |
117 | MODULE_AUTHOR("Michael Moese <michael.moese@men.de"); | 172 | MODULE_AUTHOR("Michael Moese <michael.moese@men.de"); |
118 | MODULE_ALIAS("mcb:16z125"); | 173 | MODULE_ALIAS("mcb:16z125"); |
174 | MODULE_ALIAS("mcb:16z025"); | ||
175 | MODULE_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 | ||
159 | config SERIAL_8250_MEN_MCB | 159 | config 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. |