]>
Commit | Line | Data |
---|---|---|
e3b3d0f5 | 1 | // SPDX-License-Identifier: GPL-2.0 |
28e3fb6c RR |
2 | /* |
3 | * Probe for F81216A LPC to 4 UART | |
4 | * | |
fa01e2ca | 5 | * Copyright (C) 2014-2016 Ricardo Ribalda, Qtechnology A/S |
28e3fb6c RR |
6 | */ |
7 | #include <linux/module.h> | |
8 | #include <linux/pci.h> | |
9 | #include <linux/pnp.h> | |
10 | #include <linux/kernel.h> | |
11 | #include <linux/serial_core.h> | |
4da22f14 | 12 | #include <linux/irq.h> |
28e3fb6c RR |
13 | #include "8250.h" |
14 | ||
017bec38 RR |
15 | #define ADDR_PORT 0 |
16 | #define DATA_PORT 1 | |
28e3fb6c RR |
17 | #define EXIT_KEY 0xAA |
18 | #define CHIP_ID1 0x20 | |
28e3fb6c | 19 | #define CHIP_ID2 0x21 |
de48b099 | 20 | #define CHIP_ID_F81865 0x0407 |
da60d6af | 21 | #define CHIP_ID_F81866 0x1010 |
423d9118 | 22 | #define CHIP_ID_F81966 0x0215 |
c2236fac JZHPH |
23 | #define CHIP_ID_F81216AD 0x1602 |
24 | #define CHIP_ID_F81216H 0x0501 | |
1e26c472 | 25 | #define CHIP_ID_F81216 0x0802 |
28e3fb6c RR |
26 | #define VENDOR_ID1 0x23 |
27 | #define VENDOR_ID1_VAL 0x19 | |
28 | #define VENDOR_ID2 0x24 | |
29 | #define VENDOR_ID2_VAL 0x34 | |
29d58642 RR |
30 | #define IO_ADDR1 0x61 |
31 | #define IO_ADDR2 0x60 | |
28e3fb6c RR |
32 | #define LDN 0x7 |
33 | ||
87a713c8 | 34 | #define FINTEK_IRQ_MODE 0x70 |
4da22f14 JZHPH |
35 | #define IRQ_SHARE BIT(4) |
36 | #define IRQ_MODE_MASK (BIT(6) | BIT(5)) | |
37 | #define IRQ_LEVEL_LOW 0 | |
38 | #define IRQ_EDGE_HIGH BIT(5) | |
39 | ||
58178914 JZHPH |
40 | /* |
41 | * F81216H clock source register, the value and mask is the same with F81866, | |
42 | * but it's on F0h. | |
43 | * | |
44 | * Clock speeds for UART (register F0h) | |
45 | * 00: 1.8432MHz. | |
46 | * 01: 18.432MHz. | |
47 | * 10: 24MHz. | |
48 | * 11: 14.769MHz. | |
49 | */ | |
28e3fb6c RR |
50 | #define RS485 0xF0 |
51 | #define RTS_INVERT BIT(5) | |
52 | #define RS485_URA BIT(4) | |
53 | #define RXW4C_IRA BIT(3) | |
54 | #define TXW4C_IRA BIT(2) | |
55 | ||
c2236fac JZHPH |
56 | #define FIFO_CTRL 0xF6 |
57 | #define FIFO_MODE_MASK (BIT(1) | BIT(0)) | |
58 | #define FIFO_MODE_128 (BIT(1) | BIT(0)) | |
59 | #define RXFTHR_MODE_MASK (BIT(5) | BIT(4)) | |
60 | #define RXFTHR_MODE_4X BIT(5) | |
61 | ||
da60d6af JZHPH |
62 | #define F81216_LDN_LOW 0x0 |
63 | #define F81216_LDN_HIGH 0x4 | |
64 | ||
65 | /* | |
423d9118 | 66 | * F81866/966 registers |
da60d6af | 67 | * |
423d9118 | 68 | * The IRQ setting mode of F81866/966 is not the same with F81216 series. |
da60d6af JZHPH |
69 | * Level/Low: IRQ_MODE0:0, IRQ_MODE1:0 |
70 | * Edge/High: IRQ_MODE0:1, IRQ_MODE1:0 | |
fab8a02b LR |
71 | * |
72 | * Clock speeds for UART (register F2h) | |
73 | * 00: 1.8432MHz. | |
74 | * 01: 18.432MHz. | |
75 | * 10: 24MHz. | |
76 | * 11: 14.769MHz. | |
da60d6af JZHPH |
77 | */ |
78 | #define F81866_IRQ_MODE 0xf0 | |
79 | #define F81866_IRQ_SHARE BIT(0) | |
80 | #define F81866_IRQ_MODE0 BIT(1) | |
81 | ||
82 | #define F81866_FIFO_CTRL FIFO_CTRL | |
83 | #define F81866_IRQ_MODE1 BIT(3) | |
84 | ||
85 | #define F81866_LDN_LOW 0x10 | |
86 | #define F81866_LDN_HIGH 0x16 | |
87 | ||
fab8a02b LR |
88 | #define F81866_UART_CLK 0xF2 |
89 | #define F81866_UART_CLK_MASK (BIT(1) | BIT(0)) | |
90 | #define F81866_UART_CLK_1_8432MHZ 0 | |
91 | #define F81866_UART_CLK_14_769MHZ (BIT(1) | BIT(0)) | |
92 | #define F81866_UART_CLK_18_432MHZ BIT(0) | |
93 | #define F81866_UART_CLK_24MHZ BIT(1) | |
94 | ||
92a5f11a | 95 | struct fintek_8250 { |
c2236fac | 96 | u16 pid; |
017bec38 | 97 | u16 base_port; |
92a5f11a | 98 | u8 index; |
ce8c267e | 99 | u8 key; |
92a5f11a RR |
100 | }; |
101 | ||
f1232ac2 JZHPH |
102 | static u8 sio_read_reg(struct fintek_8250 *pdata, u8 reg) |
103 | { | |
104 | outb(reg, pdata->base_port + ADDR_PORT); | |
105 | return inb(pdata->base_port + DATA_PORT); | |
106 | } | |
107 | ||
108 | static void sio_write_reg(struct fintek_8250 *pdata, u8 reg, u8 data) | |
109 | { | |
110 | outb(reg, pdata->base_port + ADDR_PORT); | |
111 | outb(data, pdata->base_port + DATA_PORT); | |
112 | } | |
113 | ||
114 | static void sio_write_mask_reg(struct fintek_8250 *pdata, u8 reg, u8 mask, | |
115 | u8 data) | |
116 | { | |
117 | u8 tmp; | |
118 | ||
119 | tmp = (sio_read_reg(pdata, reg) & ~mask) | (mask & data); | |
120 | sio_write_reg(pdata, reg, tmp); | |
121 | } | |
122 | ||
ce8c267e | 123 | static int fintek_8250_enter_key(u16 base_port, u8 key) |
017bec38 | 124 | { |
fa01e2ca | 125 | if (!request_muxed_region(base_port, 2, "8250_fintek")) |
28e3fb6c RR |
126 | return -EBUSY; |
127 | ||
fd97e66c JZHPH |
128 | /* Force to deactive all SuperIO in this base_port */ |
129 | outb(EXIT_KEY, base_port + ADDR_PORT); | |
130 | ||
ce8c267e RR |
131 | outb(key, base_port + ADDR_PORT); |
132 | outb(key, base_port + ADDR_PORT); | |
28e3fb6c RR |
133 | return 0; |
134 | } | |
135 | ||
017bec38 RR |
136 | static void fintek_8250_exit_key(u16 base_port) |
137 | { | |
28e3fb6c | 138 | |
017bec38 RR |
139 | outb(EXIT_KEY, base_port + ADDR_PORT); |
140 | release_region(base_port + ADDR_PORT, 2); | |
28e3fb6c RR |
141 | } |
142 | ||
f1232ac2 | 143 | static int fintek_8250_check_id(struct fintek_8250 *pdata) |
28e3fb6c | 144 | { |
dae77f75 | 145 | u16 chip; |
28e3fb6c | 146 | |
f1232ac2 | 147 | if (sio_read_reg(pdata, VENDOR_ID1) != VENDOR_ID1_VAL) |
28e3fb6c RR |
148 | return -ENODEV; |
149 | ||
f1232ac2 | 150 | if (sio_read_reg(pdata, VENDOR_ID2) != VENDOR_ID2_VAL) |
28e3fb6c RR |
151 | return -ENODEV; |
152 | ||
f1232ac2 JZHPH |
153 | chip = sio_read_reg(pdata, CHIP_ID1); |
154 | chip |= sio_read_reg(pdata, CHIP_ID2) << 8; | |
dae77f75 | 155 | |
1e26c472 | 156 | switch (chip) { |
de48b099 | 157 | case CHIP_ID_F81865: |
da60d6af | 158 | case CHIP_ID_F81866: |
423d9118 | 159 | case CHIP_ID_F81966: |
1e26c472 JZHPH |
160 | case CHIP_ID_F81216AD: |
161 | case CHIP_ID_F81216H: | |
162 | case CHIP_ID_F81216: | |
163 | break; | |
164 | default: | |
dae77f75 | 165 | return -ENODEV; |
1e26c472 | 166 | } |
dae77f75 | 167 | |
c2236fac | 168 | pdata->pid = chip; |
28e3fb6c RR |
169 | return 0; |
170 | } | |
171 | ||
da60d6af JZHPH |
172 | static int fintek_8250_get_ldn_range(struct fintek_8250 *pdata, int *min, |
173 | int *max) | |
174 | { | |
175 | switch (pdata->pid) { | |
423d9118 | 176 | case CHIP_ID_F81966: |
de48b099 | 177 | case CHIP_ID_F81865: |
da60d6af JZHPH |
178 | case CHIP_ID_F81866: |
179 | *min = F81866_LDN_LOW; | |
180 | *max = F81866_LDN_HIGH; | |
181 | return 0; | |
182 | ||
183 | case CHIP_ID_F81216AD: | |
184 | case CHIP_ID_F81216H: | |
185 | case CHIP_ID_F81216: | |
186 | *min = F81216_LDN_LOW; | |
187 | *max = F81216_LDN_HIGH; | |
188 | return 0; | |
189 | } | |
190 | ||
191 | return -ENODEV; | |
192 | } | |
193 | ||
41e69093 | 194 | static int fintek_8250_rs485_config(struct uart_port *port, |
28e3fb6c RR |
195 | struct serial_rs485 *rs485) |
196 | { | |
197 | uint8_t config = 0; | |
92a5f11a | 198 | struct fintek_8250 *pdata = port->private_data; |
28e3fb6c | 199 | |
92a5f11a | 200 | if (!pdata) |
28e3fb6c RR |
201 | return -EINVAL; |
202 | ||
7ecc7701 RR |
203 | /* Hardware do not support same RTS level on send and receive */ |
204 | if (!(rs485->flags & SER_RS485_RTS_ON_SEND) == | |
205 | !(rs485->flags & SER_RS485_RTS_AFTER_SEND)) | |
206 | return -EINVAL; | |
207 | ||
208 | if (rs485->flags & SER_RS485_ENABLED) { | |
28e3fb6c | 209 | memset(rs485->padding, 0, sizeof(rs485->padding)); |
7ecc7701 RR |
210 | config |= RS485_URA; |
211 | } else { | |
28e3fb6c | 212 | memset(rs485, 0, sizeof(*rs485)); |
7ecc7701 | 213 | } |
28e3fb6c RR |
214 | |
215 | rs485->flags &= SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | | |
216 | SER_RS485_RTS_AFTER_SEND; | |
217 | ||
21c4e7f2 RR |
218 | /* Only the first port supports delays */ |
219 | if (pdata->index) { | |
220 | rs485->delay_rts_before_send = 0; | |
221 | rs485->delay_rts_after_send = 0; | |
222 | } | |
223 | ||
28e3fb6c RR |
224 | if (rs485->delay_rts_before_send) { |
225 | rs485->delay_rts_before_send = 1; | |
226 | config |= TXW4C_IRA; | |
227 | } | |
228 | ||
229 | if (rs485->delay_rts_after_send) { | |
230 | rs485->delay_rts_after_send = 1; | |
231 | config |= RXW4C_IRA; | |
232 | } | |
233 | ||
28e3fb6c RR |
234 | if (rs485->flags & SER_RS485_RTS_ON_SEND) |
235 | config |= RTS_INVERT; | |
236 | ||
ce8c267e | 237 | if (fintek_8250_enter_key(pdata->base_port, pdata->key)) |
28e3fb6c RR |
238 | return -EBUSY; |
239 | ||
f1232ac2 JZHPH |
240 | sio_write_reg(pdata, LDN, pdata->index); |
241 | sio_write_reg(pdata, RS485, config); | |
017bec38 | 242 | fintek_8250_exit_key(pdata->base_port); |
28e3fb6c | 243 | |
41e69093 RR |
244 | port->rs485 = *rs485; |
245 | ||
28e3fb6c RR |
246 | return 0; |
247 | } | |
248 | ||
06e39572 JZHPH |
249 | static void fintek_8250_set_irq_mode(struct fintek_8250 *pdata, bool is_level) |
250 | { | |
251 | sio_write_reg(pdata, LDN, pdata->index); | |
da60d6af JZHPH |
252 | |
253 | switch (pdata->pid) { | |
423d9118 | 254 | case CHIP_ID_F81966: |
da60d6af JZHPH |
255 | case CHIP_ID_F81866: |
256 | sio_write_mask_reg(pdata, F81866_FIFO_CTRL, F81866_IRQ_MODE1, | |
257 | 0); | |
df561f66 | 258 | fallthrough; |
de48b099 | 259 | case CHIP_ID_F81865: |
da60d6af JZHPH |
260 | sio_write_mask_reg(pdata, F81866_IRQ_MODE, F81866_IRQ_SHARE, |
261 | F81866_IRQ_SHARE); | |
262 | sio_write_mask_reg(pdata, F81866_IRQ_MODE, F81866_IRQ_MODE0, | |
263 | is_level ? 0 : F81866_IRQ_MODE0); | |
264 | break; | |
265 | ||
266 | case CHIP_ID_F81216AD: | |
267 | case CHIP_ID_F81216H: | |
268 | case CHIP_ID_F81216: | |
269 | sio_write_mask_reg(pdata, FINTEK_IRQ_MODE, IRQ_SHARE, | |
270 | IRQ_SHARE); | |
271 | sio_write_mask_reg(pdata, FINTEK_IRQ_MODE, IRQ_MODE_MASK, | |
272 | is_level ? IRQ_LEVEL_LOW : IRQ_EDGE_HIGH); | |
273 | break; | |
274 | } | |
06e39572 JZHPH |
275 | } |
276 | ||
c2236fac JZHPH |
277 | static void fintek_8250_set_max_fifo(struct fintek_8250 *pdata) |
278 | { | |
279 | switch (pdata->pid) { | |
280 | case CHIP_ID_F81216H: /* 128Bytes FIFO */ | |
423d9118 | 281 | case CHIP_ID_F81966: |
da60d6af | 282 | case CHIP_ID_F81866: |
c2236fac JZHPH |
283 | sio_write_mask_reg(pdata, FIFO_CTRL, |
284 | FIFO_MODE_MASK | RXFTHR_MODE_MASK, | |
285 | FIFO_MODE_128 | RXFTHR_MODE_4X); | |
286 | break; | |
287 | ||
288 | default: /* Default 16Bytes FIFO */ | |
289 | break; | |
290 | } | |
291 | } | |
292 | ||
fab8a02b LR |
293 | static void fintek_8250_goto_highspeed(struct uart_8250_port *uart, |
294 | struct fintek_8250 *pdata) | |
295 | { | |
296 | sio_write_reg(pdata, LDN, pdata->index); | |
297 | ||
298 | switch (pdata->pid) { | |
423d9118 | 299 | case CHIP_ID_F81966: |
fab8a02b LR |
300 | case CHIP_ID_F81866: /* set uart clock for high speed serial mode */ |
301 | sio_write_mask_reg(pdata, F81866_UART_CLK, | |
302 | F81866_UART_CLK_MASK, | |
303 | F81866_UART_CLK_14_769MHZ); | |
304 | ||
4c3897b1 | 305 | uart->port.uartclk = 921600 * 16; |
fab8a02b LR |
306 | break; |
307 | default: /* leave clock speed untouched */ | |
308 | break; | |
309 | } | |
310 | } | |
311 | ||
9828def3 Y |
312 | static void fintek_8250_set_termios(struct uart_port *port, |
313 | struct ktermios *termios, | |
314 | struct ktermios *old) | |
195638b6 JZHPH |
315 | { |
316 | struct fintek_8250 *pdata = port->private_data; | |
317 | unsigned int baud = tty_termios_baud_rate(termios); | |
318 | int i; | |
58178914 | 319 | u8 reg; |
195638b6 JZHPH |
320 | static u32 baudrate_table[] = {115200, 921600, 1152000, 1500000}; |
321 | static u8 clock_table[] = { F81866_UART_CLK_1_8432MHZ, | |
322 | F81866_UART_CLK_14_769MHZ, F81866_UART_CLK_18_432MHZ, | |
323 | F81866_UART_CLK_24MHZ }; | |
324 | ||
07a708f0 JZHPH |
325 | /* |
326 | * We'll use serial8250_do_set_termios() for baud = 0, otherwise It'll | |
327 | * crash on baudrate_table[i] % baud with "division by zero". | |
328 | */ | |
329 | if (!baud) | |
330 | goto exit; | |
331 | ||
58178914 JZHPH |
332 | switch (pdata->pid) { |
333 | case CHIP_ID_F81216H: | |
334 | reg = RS485; | |
335 | break; | |
423d9118 | 336 | case CHIP_ID_F81966: |
58178914 JZHPH |
337 | case CHIP_ID_F81866: |
338 | reg = F81866_UART_CLK; | |
339 | break; | |
340 | default: | |
341 | /* Don't change clocksource with unknown PID */ | |
342 | dev_warn(port->dev, | |
343 | "%s: pid: %x Not support. use default set_termios.\n", | |
344 | __func__, pdata->pid); | |
07a708f0 | 345 | goto exit; |
58178914 JZHPH |
346 | } |
347 | ||
195638b6 JZHPH |
348 | for (i = 0; i < ARRAY_SIZE(baudrate_table); ++i) { |
349 | if (baud > baudrate_table[i] || baudrate_table[i] % baud != 0) | |
350 | continue; | |
351 | ||
352 | if (port->uartclk == baudrate_table[i] * 16) | |
353 | break; | |
354 | ||
355 | if (fintek_8250_enter_key(pdata->base_port, pdata->key)) | |
356 | continue; | |
357 | ||
358 | port->uartclk = baudrate_table[i] * 16; | |
359 | ||
360 | sio_write_reg(pdata, LDN, pdata->index); | |
58178914 JZHPH |
361 | sio_write_mask_reg(pdata, reg, F81866_UART_CLK_MASK, |
362 | clock_table[i]); | |
195638b6 JZHPH |
363 | |
364 | fintek_8250_exit_key(pdata->base_port); | |
365 | break; | |
366 | } | |
367 | ||
368 | if (i == ARRAY_SIZE(baudrate_table)) { | |
369 | baud = tty_termios_baud_rate(old); | |
370 | tty_termios_encode_baud_rate(termios, baud, baud); | |
371 | } | |
372 | ||
07a708f0 | 373 | exit: |
195638b6 JZHPH |
374 | serial8250_do_set_termios(port, termios, old); |
375 | } | |
376 | ||
377 | static void fintek_8250_set_termios_handler(struct uart_8250_port *uart) | |
378 | { | |
379 | struct fintek_8250 *pdata = uart->port.private_data; | |
380 | ||
381 | switch (pdata->pid) { | |
58178914 | 382 | case CHIP_ID_F81216H: |
423d9118 | 383 | case CHIP_ID_F81966: |
195638b6 JZHPH |
384 | case CHIP_ID_F81866: |
385 | uart->port.set_termios = fintek_8250_set_termios; | |
386 | break; | |
387 | ||
388 | default: | |
389 | break; | |
390 | } | |
391 | } | |
392 | ||
fab8a02b LR |
393 | static int probe_setup_port(struct fintek_8250 *pdata, |
394 | struct uart_8250_port *uart) | |
017bec38 RR |
395 | { |
396 | static const u16 addr[] = {0x4e, 0x2e}; | |
ce8c267e | 397 | static const u8 keys[] = {0x77, 0xa0, 0x87, 0x67}; |
06e39572 JZHPH |
398 | struct irq_data *irq_data; |
399 | bool level_mode = false; | |
da60d6af | 400 | int i, j, k, min, max; |
017bec38 RR |
401 | |
402 | for (i = 0; i < ARRAY_SIZE(addr); i++) { | |
ce8c267e | 403 | for (j = 0; j < ARRAY_SIZE(keys); j++) { |
f1232ac2 JZHPH |
404 | pdata->base_port = addr[i]; |
405 | pdata->key = keys[j]; | |
ce8c267e RR |
406 | |
407 | if (fintek_8250_enter_key(addr[i], keys[j])) | |
408 | continue; | |
da60d6af JZHPH |
409 | if (fintek_8250_check_id(pdata) || |
410 | fintek_8250_get_ldn_range(pdata, &min, &max)) { | |
29d58642 RR |
411 | fintek_8250_exit_key(addr[i]); |
412 | continue; | |
413 | } | |
414 | ||
da60d6af | 415 | for (k = min; k < max; k++) { |
29d58642 RR |
416 | u16 aux; |
417 | ||
f1232ac2 JZHPH |
418 | sio_write_reg(pdata, LDN, k); |
419 | aux = sio_read_reg(pdata, IO_ADDR1); | |
420 | aux |= sio_read_reg(pdata, IO_ADDR2) << 8; | |
fab8a02b | 421 | if (aux != uart->port.iobase) |
29d58642 RR |
422 | continue; |
423 | ||
fa01e2ca RR |
424 | pdata->index = k; |
425 | ||
fab8a02b | 426 | irq_data = irq_get_irq_data(uart->port.irq); |
06e39572 JZHPH |
427 | if (irq_data) |
428 | level_mode = | |
429 | irqd_is_level_type(irq_data); | |
430 | ||
431 | fintek_8250_set_irq_mode(pdata, level_mode); | |
c2236fac | 432 | fintek_8250_set_max_fifo(pdata); |
fab8a02b LR |
433 | fintek_8250_goto_highspeed(uart, pdata); |
434 | ||
06e39572 JZHPH |
435 | fintek_8250_exit_key(addr[i]); |
436 | ||
fa01e2ca | 437 | return 0; |
ce8c267e | 438 | } |
fa01e2ca | 439 | |
29d58642 | 440 | fintek_8250_exit_key(addr[i]); |
ce8c267e | 441 | } |
017bec38 RR |
442 | } |
443 | ||
444 | return -ENODEV; | |
445 | } | |
446 | ||
1e26c472 JZHPH |
447 | static void fintek_8250_set_rs485_handler(struct uart_8250_port *uart) |
448 | { | |
449 | struct fintek_8250 *pdata = uart->port.private_data; | |
450 | ||
451 | switch (pdata->pid) { | |
452 | case CHIP_ID_F81216AD: | |
453 | case CHIP_ID_F81216H: | |
423d9118 | 454 | case CHIP_ID_F81966: |
da60d6af | 455 | case CHIP_ID_F81866: |
de48b099 | 456 | case CHIP_ID_F81865: |
1e26c472 JZHPH |
457 | uart->port.rs485_config = fintek_8250_rs485_config; |
458 | break; | |
459 | ||
460 | default: /* No RS485 Auto direction functional */ | |
461 | break; | |
462 | } | |
463 | } | |
464 | ||
fa01e2ca | 465 | int fintek_8250_probe(struct uart_8250_port *uart) |
28e3fb6c | 466 | { |
92a5f11a | 467 | struct fintek_8250 *pdata; |
fa01e2ca | 468 | struct fintek_8250 probe_data; |
28e3fb6c | 469 | |
fab8a02b | 470 | if (probe_setup_port(&probe_data, uart)) |
28e3fb6c RR |
471 | return -ENODEV; |
472 | ||
fa01e2ca | 473 | pdata = devm_kzalloc(uart->port.dev, sizeof(*pdata), GFP_KERNEL); |
92a5f11a RR |
474 | if (!pdata) |
475 | return -ENOMEM; | |
92a5f11a | 476 | |
fa01e2ca | 477 | memcpy(pdata, &probe_data, sizeof(probe_data)); |
fa01e2ca | 478 | uart->port.private_data = pdata; |
1e26c472 | 479 | fintek_8250_set_rs485_handler(uart); |
195638b6 | 480 | fintek_8250_set_termios_handler(uart); |
28e3fb6c | 481 | |
06e39572 | 482 | return 0; |
28e3fb6c | 483 | } |