2 * Probe for F81216A LPC to 4 UART
4 * Based on drivers/tty/serial/8250_pnp.c, by Russell King, et al
6 * Copyright (C) 2014 Ricardo Ribalda, Qtechnology A/S
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License.
13 #include <linux/module.h>
14 #include <linux/pci.h>
15 #include <linux/pnp.h>
16 #include <linux/kernel.h>
17 #include <linux/serial_core.h>
25 #define CHIP_ID_0 0x1602
26 #define CHIP_ID_1 0x0501
27 #define VENDOR_ID1 0x23
28 #define VENDOR_ID1_VAL 0x19
29 #define VENDOR_ID2 0x24
30 #define VENDOR_ID2_VAL 0x34
36 #define RTS_INVERT BIT(5)
37 #define RS485_URA BIT(4)
38 #define RXW4C_IRA BIT(3)
39 #define TXW4C_IRA BIT(2)
41 #define DRIVER_NAME "8250_fintek"
50 static int fintek_8250_enter_key(u16 base_port
, u8 key
)
53 if (!request_muxed_region(base_port
, 2, DRIVER_NAME
))
56 outb(key
, base_port
+ ADDR_PORT
);
57 outb(key
, base_port
+ ADDR_PORT
);
61 static void fintek_8250_exit_key(u16 base_port
)
64 outb(EXIT_KEY
, base_port
+ ADDR_PORT
);
65 release_region(base_port
+ ADDR_PORT
, 2);
68 static int fintek_8250_check_id(u16 base_port
)
72 outb(VENDOR_ID1
, base_port
+ ADDR_PORT
);
73 if (inb(base_port
+ DATA_PORT
) != VENDOR_ID1_VAL
)
76 outb(VENDOR_ID2
, base_port
+ ADDR_PORT
);
77 if (inb(base_port
+ DATA_PORT
) != VENDOR_ID2_VAL
)
80 outb(CHIP_ID1
, base_port
+ ADDR_PORT
);
81 chip
= inb(base_port
+ DATA_PORT
);
82 outb(CHIP_ID2
, base_port
+ ADDR_PORT
);
83 chip
|= inb(base_port
+ DATA_PORT
) << 8;
85 if (chip
!= CHIP_ID_0
&& chip
!= CHIP_ID_1
)
91 static int fintek_8250_rs485_config(struct uart_port
*port
,
92 struct serial_rs485
*rs485
)
95 struct fintek_8250
*pdata
= port
->private_data
;
100 if (rs485
->flags
& SER_RS485_ENABLED
)
101 memset(rs485
->padding
, 0, sizeof(rs485
->padding
));
103 memset(rs485
, 0, sizeof(*rs485
));
105 rs485
->flags
&= SER_RS485_ENABLED
| SER_RS485_RTS_ON_SEND
|
106 SER_RS485_RTS_AFTER_SEND
;
108 if (rs485
->delay_rts_before_send
) {
109 rs485
->delay_rts_before_send
= 1;
113 if (rs485
->delay_rts_after_send
) {
114 rs485
->delay_rts_after_send
= 1;
118 if ((!!(rs485
->flags
& SER_RS485_RTS_ON_SEND
)) ==
119 (!!(rs485
->flags
& SER_RS485_RTS_AFTER_SEND
)))
120 rs485
->flags
&= SER_RS485_ENABLED
;
124 if (rs485
->flags
& SER_RS485_RTS_ON_SEND
)
125 config
|= RTS_INVERT
;
127 if (fintek_8250_enter_key(pdata
->base_port
, pdata
->key
))
130 outb(LDN
, pdata
->base_port
+ ADDR_PORT
);
131 outb(pdata
->index
, pdata
->base_port
+ DATA_PORT
);
132 outb(RS485
, pdata
->base_port
+ ADDR_PORT
);
133 outb(config
, pdata
->base_port
+ DATA_PORT
);
134 fintek_8250_exit_key(pdata
->base_port
);
136 port
->rs485
= *rs485
;
141 static int fintek_8250_base_port(u16 io_address
, u8
*key
, u8
*index
)
143 static const u16 addr
[] = {0x4e, 0x2e};
144 static const u8 keys
[] = {0x77, 0xa0, 0x87, 0x67};
147 for (i
= 0; i
< ARRAY_SIZE(addr
); i
++) {
148 for (j
= 0; j
< ARRAY_SIZE(keys
); j
++) {
150 if (fintek_8250_enter_key(addr
[i
], keys
[j
]))
152 if (fintek_8250_check_id(addr
[i
])) {
153 fintek_8250_exit_key(addr
[i
]);
157 for (k
= 0; k
< 4; k
++) {
160 outb(LDN
, addr
[i
] + ADDR_PORT
);
161 outb(k
, addr
[i
] + DATA_PORT
);
163 outb(IO_ADDR1
, addr
[i
] + ADDR_PORT
);
164 aux
= inb(addr
[i
] + DATA_PORT
);
165 outb(IO_ADDR2
, addr
[i
] + ADDR_PORT
);
166 aux
|= inb(addr
[i
] + DATA_PORT
) << 8;
167 if (aux
!= io_address
)
170 fintek_8250_exit_key(addr
[i
]);
175 fintek_8250_exit_key(addr
[i
]);
183 fintek_8250_probe(struct pnp_dev
*dev
, const struct pnp_device_id
*dev_id
)
185 struct uart_8250_port uart
;
186 struct fintek_8250
*pdata
;
191 if (!pnp_port_valid(dev
, 0))
194 base_port
= fintek_8250_base_port(pnp_port_start(dev
, 0), &key
, &index
);
198 memset(&uart
, 0, sizeof(uart
));
200 pdata
= devm_kzalloc(&dev
->dev
, sizeof(*pdata
), GFP_KERNEL
);
203 uart
.port
.private_data
= pdata
;
205 if (!pnp_irq_valid(dev
, 0))
207 uart
.port
.irq
= pnp_irq(dev
, 0);
208 uart
.port
.iobase
= pnp_port_start(dev
, 0);
209 uart
.port
.iotype
= UPIO_PORT
;
210 uart
.port
.rs485_config
= fintek_8250_rs485_config
;
212 uart
.port
.flags
|= UPF_SKIP_TEST
| UPF_BOOT_AUTOCONF
;
213 if (pnp_irq_flags(dev
, 0) & IORESOURCE_IRQ_SHAREABLE
)
214 uart
.port
.flags
|= UPF_SHARE_IRQ
;
215 uart
.port
.uartclk
= 1843200;
216 uart
.port
.dev
= &dev
->dev
;
219 pdata
->base_port
= base_port
;
220 pdata
->index
= index
;
221 pdata
->line
= serial8250_register_8250_port(&uart
);
225 pnp_set_drvdata(dev
, pdata
);
229 static void fintek_8250_remove(struct pnp_dev
*dev
)
231 struct fintek_8250
*pdata
= pnp_get_drvdata(dev
);
234 serial8250_unregister_port(pdata
->line
);
238 static int fintek_8250_suspend(struct pnp_dev
*dev
, pm_message_t state
)
240 struct fintek_8250
*pdata
= pnp_get_drvdata(dev
);
244 serial8250_suspend_port(pdata
->line
);
248 static int fintek_8250_resume(struct pnp_dev
*dev
)
250 struct fintek_8250
*pdata
= pnp_get_drvdata(dev
);
254 serial8250_resume_port(pdata
->line
);
258 #define fintek_8250_suspend NULL
259 #define fintek_8250_resume NULL
260 #endif /* CONFIG_PM */
262 static const struct pnp_device_id fintek_dev_table
[] = {
263 /* Qtechnology Panel PC / IO1000 */
268 MODULE_DEVICE_TABLE(pnp
, fintek_dev_table
);
270 static struct pnp_driver fintek_8250_driver
= {
272 .probe
= fintek_8250_probe
,
273 .remove
= fintek_8250_remove
,
274 .suspend
= fintek_8250_suspend
,
275 .resume
= fintek_8250_resume
,
276 .id_table
= fintek_dev_table
,
279 module_pnp_driver(fintek_8250_driver
);
280 MODULE_DESCRIPTION("Fintek F812164 module");
281 MODULE_AUTHOR("Ricardo Ribalda <ricardo.ribalda@gmail.com>");
282 MODULE_LICENSE("GPL");