8250_fintek.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. /*
  2. * Probe for F81216A LPC to 4 UART
  3. *
  4. * Based on drivers/tty/serial/8250_pnp.c, by Russell King, et al
  5. *
  6. * Copyright (C) 2014 Ricardo Ribalda, Qtechnology A/S
  7. *
  8. *
  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.
  12. */
  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>
  18. #include "8250.h"
  19. #define ADDR_PORT 0
  20. #define DATA_PORT 1
  21. #define EXIT_KEY 0xAA
  22. #define CHIP_ID1 0x20
  23. #define CHIP_ID2 0x21
  24. #define CHIP_ID_0 0x1602
  25. #define CHIP_ID_1 0x0501
  26. #define VENDOR_ID1 0x23
  27. #define VENDOR_ID1_VAL 0x19
  28. #define VENDOR_ID2 0x24
  29. #define VENDOR_ID2_VAL 0x34
  30. #define IO_ADDR1 0x61
  31. #define IO_ADDR2 0x60
  32. #define LDN 0x7
  33. #define RS485 0xF0
  34. #define RTS_INVERT BIT(5)
  35. #define RS485_URA BIT(4)
  36. #define RXW4C_IRA BIT(3)
  37. #define TXW4C_IRA BIT(2)
  38. #define DRIVER_NAME "8250_fintek"
  39. struct fintek_8250 {
  40. u16 base_port;
  41. u8 index;
  42. u8 key;
  43. long line;
  44. };
  45. static int fintek_8250_enter_key(u16 base_port, u8 key)
  46. {
  47. if (!request_muxed_region(base_port, 2, DRIVER_NAME))
  48. return -EBUSY;
  49. outb(key, base_port + ADDR_PORT);
  50. outb(key, base_port + ADDR_PORT);
  51. return 0;
  52. }
  53. static void fintek_8250_exit_key(u16 base_port)
  54. {
  55. outb(EXIT_KEY, base_port + ADDR_PORT);
  56. release_region(base_port + ADDR_PORT, 2);
  57. }
  58. static int fintek_8250_check_id(u16 base_port)
  59. {
  60. u16 chip;
  61. outb(VENDOR_ID1, base_port + ADDR_PORT);
  62. if (inb(base_port + DATA_PORT) != VENDOR_ID1_VAL)
  63. return -ENODEV;
  64. outb(VENDOR_ID2, base_port + ADDR_PORT);
  65. if (inb(base_port + DATA_PORT) != VENDOR_ID2_VAL)
  66. return -ENODEV;
  67. outb(CHIP_ID1, base_port + ADDR_PORT);
  68. chip = inb(base_port + DATA_PORT);
  69. outb(CHIP_ID2, base_port + ADDR_PORT);
  70. chip |= inb(base_port + DATA_PORT) << 8;
  71. if (chip != CHIP_ID_0 && chip != CHIP_ID_1)
  72. return -ENODEV;
  73. return 0;
  74. }
  75. static int fintek_8250_rs485_config(struct uart_port *port,
  76. struct serial_rs485 *rs485)
  77. {
  78. uint8_t config = 0;
  79. struct fintek_8250 *pdata = port->private_data;
  80. if (!pdata)
  81. return -EINVAL;
  82. if (rs485->flags & SER_RS485_ENABLED)
  83. memset(rs485->padding, 0, sizeof(rs485->padding));
  84. else
  85. memset(rs485, 0, sizeof(*rs485));
  86. rs485->flags &= SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND |
  87. SER_RS485_RTS_AFTER_SEND;
  88. if (rs485->delay_rts_before_send) {
  89. rs485->delay_rts_before_send = 1;
  90. config |= TXW4C_IRA;
  91. }
  92. if (rs485->delay_rts_after_send) {
  93. rs485->delay_rts_after_send = 1;
  94. config |= RXW4C_IRA;
  95. }
  96. if ((!!(rs485->flags & SER_RS485_RTS_ON_SEND)) ==
  97. (!!(rs485->flags & SER_RS485_RTS_AFTER_SEND)))
  98. rs485->flags &= ~SER_RS485_ENABLED;
  99. else
  100. config |= RS485_URA;
  101. if (rs485->flags & SER_RS485_RTS_ON_SEND)
  102. config |= RTS_INVERT;
  103. if (fintek_8250_enter_key(pdata->base_port, pdata->key))
  104. return -EBUSY;
  105. outb(LDN, pdata->base_port + ADDR_PORT);
  106. outb(pdata->index, pdata->base_port + DATA_PORT);
  107. outb(RS485, pdata->base_port + ADDR_PORT);
  108. outb(config, pdata->base_port + DATA_PORT);
  109. fintek_8250_exit_key(pdata->base_port);
  110. port->rs485 = *rs485;
  111. return 0;
  112. }
  113. static int fintek_8250_base_port(u16 io_address, u8 *key, u8 *index)
  114. {
  115. static const u16 addr[] = {0x4e, 0x2e};
  116. static const u8 keys[] = {0x77, 0xa0, 0x87, 0x67};
  117. int i, j, k;
  118. for (i = 0; i < ARRAY_SIZE(addr); i++) {
  119. for (j = 0; j < ARRAY_SIZE(keys); j++) {
  120. if (fintek_8250_enter_key(addr[i], keys[j]))
  121. continue;
  122. if (fintek_8250_check_id(addr[i])) {
  123. fintek_8250_exit_key(addr[i]);
  124. continue;
  125. }
  126. for (k = 0; k < 4; k++) {
  127. u16 aux;
  128. outb(LDN, addr[i] + ADDR_PORT);
  129. outb(k, addr[i] + DATA_PORT);
  130. outb(IO_ADDR1, addr[i] + ADDR_PORT);
  131. aux = inb(addr[i] + DATA_PORT);
  132. outb(IO_ADDR2, addr[i] + ADDR_PORT);
  133. aux |= inb(addr[i] + DATA_PORT) << 8;
  134. if (aux != io_address)
  135. continue;
  136. fintek_8250_exit_key(addr[i]);
  137. *key = keys[j];
  138. *index = k;
  139. return addr[i];
  140. }
  141. fintek_8250_exit_key(addr[i]);
  142. }
  143. }
  144. return -ENODEV;
  145. }
  146. static int
  147. fintek_8250_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
  148. {
  149. struct uart_8250_port uart;
  150. struct fintek_8250 *pdata;
  151. int base_port;
  152. u8 key;
  153. u8 index;
  154. if (!pnp_port_valid(dev, 0))
  155. return -ENODEV;
  156. base_port = fintek_8250_base_port(pnp_port_start(dev, 0), &key, &index);
  157. if (base_port < 0)
  158. return -ENODEV;
  159. memset(&uart, 0, sizeof(uart));
  160. pdata = devm_kzalloc(&dev->dev, sizeof(*pdata), GFP_KERNEL);
  161. if (!pdata)
  162. return -ENOMEM;
  163. uart.port.private_data = pdata;
  164. if (!pnp_irq_valid(dev, 0))
  165. return -ENODEV;
  166. uart.port.irq = pnp_irq(dev, 0);
  167. uart.port.iobase = pnp_port_start(dev, 0);
  168. uart.port.iotype = UPIO_PORT;
  169. uart.port.rs485_config = fintek_8250_rs485_config;
  170. uart.port.flags |= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
  171. if (pnp_irq_flags(dev, 0) & IORESOURCE_IRQ_SHAREABLE)
  172. uart.port.flags |= UPF_SHARE_IRQ;
  173. uart.port.uartclk = 1843200;
  174. uart.port.dev = &dev->dev;
  175. pdata->key = key;
  176. pdata->base_port = base_port;
  177. pdata->index = index;
  178. pdata->line = serial8250_register_8250_port(&uart);
  179. if (pdata->line < 0)
  180. return -ENODEV;
  181. pnp_set_drvdata(dev, pdata);
  182. return 0;
  183. }
  184. static void fintek_8250_remove(struct pnp_dev *dev)
  185. {
  186. struct fintek_8250 *pdata = pnp_get_drvdata(dev);
  187. if (pdata)
  188. serial8250_unregister_port(pdata->line);
  189. }
  190. #ifdef CONFIG_PM
  191. static int fintek_8250_suspend(struct pnp_dev *dev, pm_message_t state)
  192. {
  193. struct fintek_8250 *pdata = pnp_get_drvdata(dev);
  194. if (!pdata)
  195. return -ENODEV;
  196. serial8250_suspend_port(pdata->line);
  197. return 0;
  198. }
  199. static int fintek_8250_resume(struct pnp_dev *dev)
  200. {
  201. struct fintek_8250 *pdata = pnp_get_drvdata(dev);
  202. if (!pdata)
  203. return -ENODEV;
  204. serial8250_resume_port(pdata->line);
  205. return 0;
  206. }
  207. #else
  208. #define fintek_8250_suspend NULL
  209. #define fintek_8250_resume NULL
  210. #endif /* CONFIG_PM */
  211. static const struct pnp_device_id fintek_dev_table[] = {
  212. /* Qtechnology Panel PC / IO1000 */
  213. { "PNP0501"},
  214. {}
  215. };
  216. MODULE_DEVICE_TABLE(pnp, fintek_dev_table);
  217. static struct pnp_driver fintek_8250_driver = {
  218. .name = DRIVER_NAME,
  219. .probe = fintek_8250_probe,
  220. .remove = fintek_8250_remove,
  221. .suspend = fintek_8250_suspend,
  222. .resume = fintek_8250_resume,
  223. .id_table = fintek_dev_table,
  224. };
  225. module_pnp_driver(fintek_8250_driver);
  226. MODULE_DESCRIPTION("Fintek F812164 module");
  227. MODULE_AUTHOR("Ricardo Ribalda <ricardo.ribalda@gmail.com>");
  228. MODULE_LICENSE("GPL");