ls_uart.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. /*
  2. * AVR power-management chip interface for the Buffalo Linkstation /
  3. * Kurobox Platform.
  4. *
  5. * Author: 2006 (c) G. Liakhovetski
  6. * g.liakhovetski@gmx.de
  7. *
  8. * This file is licensed under the terms of the GNU General Public License
  9. * version 2. This program is licensed "as is" without any warranty of
  10. * any kind, whether express or implied.
  11. */
  12. #include <linux/workqueue.h>
  13. #include <linux/string.h>
  14. #include <linux/delay.h>
  15. #include <linux/serial_reg.h>
  16. #include <linux/serial_8250.h>
  17. #include <linux/of.h>
  18. #include <linux/of_address.h>
  19. #include <asm/io.h>
  20. #include <asm/termbits.h>
  21. #include "mpc10x.h"
  22. static void __iomem *avr_addr;
  23. static unsigned long avr_clock;
  24. static struct work_struct wd_work;
  25. static void wd_stop(struct work_struct *unused)
  26. {
  27. const char string[] = "AAAAFFFFJJJJ>>>>VVVV>>>>ZZZZVVVVKKKK";
  28. int i = 0, rescue = 8;
  29. int len = strlen(string);
  30. while (rescue--) {
  31. int j;
  32. char lsr = in_8(avr_addr + UART_LSR);
  33. if (lsr & (UART_LSR_THRE | UART_LSR_TEMT)) {
  34. for (j = 0; j < 16 && i < len; j++, i++)
  35. out_8(avr_addr + UART_TX, string[i]);
  36. if (i == len) {
  37. /* Read "OK" back: 4ms for the last "KKKK"
  38. plus a couple bytes back */
  39. msleep(7);
  40. printk("linkstation: disarming the AVR watchdog: ");
  41. while (in_8(avr_addr + UART_LSR) & UART_LSR_DR)
  42. printk("%c", in_8(avr_addr + UART_RX));
  43. break;
  44. }
  45. }
  46. msleep(17);
  47. }
  48. printk("\n");
  49. }
  50. #define AVR_QUOT(clock) ((clock) + 8 * 9600) / (16 * 9600)
  51. void avr_uart_configure(void)
  52. {
  53. unsigned char cval = UART_LCR_WLEN8;
  54. unsigned int quot = AVR_QUOT(avr_clock);
  55. if (!avr_addr || !avr_clock)
  56. return;
  57. out_8(avr_addr + UART_LCR, cval); /* initialise UART */
  58. out_8(avr_addr + UART_MCR, 0);
  59. out_8(avr_addr + UART_IER, 0);
  60. cval |= UART_LCR_STOP | UART_LCR_PARITY | UART_LCR_EPAR;
  61. out_8(avr_addr + UART_LCR, cval); /* Set character format */
  62. out_8(avr_addr + UART_LCR, cval | UART_LCR_DLAB); /* set DLAB */
  63. out_8(avr_addr + UART_DLL, quot & 0xff); /* LS of divisor */
  64. out_8(avr_addr + UART_DLM, quot >> 8); /* MS of divisor */
  65. out_8(avr_addr + UART_LCR, cval); /* reset DLAB */
  66. out_8(avr_addr + UART_FCR, UART_FCR_ENABLE_FIFO); /* enable FIFO */
  67. }
  68. void avr_uart_send(const char c)
  69. {
  70. if (!avr_addr || !avr_clock)
  71. return;
  72. out_8(avr_addr + UART_TX, c);
  73. out_8(avr_addr + UART_TX, c);
  74. out_8(avr_addr + UART_TX, c);
  75. out_8(avr_addr + UART_TX, c);
  76. }
  77. static void __init ls_uart_init(void)
  78. {
  79. local_irq_disable();
  80. #ifndef CONFIG_SERIAL_8250
  81. out_8(avr_addr + UART_FCR, UART_FCR_ENABLE_FIFO); /* enable FIFO */
  82. out_8(avr_addr + UART_FCR, UART_FCR_ENABLE_FIFO |
  83. UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); /* clear FIFOs */
  84. out_8(avr_addr + UART_FCR, 0);
  85. out_8(avr_addr + UART_IER, 0);
  86. /* Clear up interrupts */
  87. (void) in_8(avr_addr + UART_LSR);
  88. (void) in_8(avr_addr + UART_RX);
  89. (void) in_8(avr_addr + UART_IIR);
  90. (void) in_8(avr_addr + UART_MSR);
  91. #endif
  92. avr_uart_configure();
  93. local_irq_enable();
  94. }
  95. static int __init ls_uarts_init(void)
  96. {
  97. struct device_node *avr;
  98. struct resource res;
  99. int len, ret;
  100. avr = of_find_node_by_path("/soc10x/serial@80004500");
  101. if (!avr)
  102. return -EINVAL;
  103. avr_clock = *(u32*)of_get_property(avr, "clock-frequency", &len);
  104. if (!avr_clock)
  105. return -EINVAL;
  106. ret = of_address_to_resource(avr, 0, &res);
  107. if (ret)
  108. return ret;
  109. of_node_put(avr);
  110. avr_addr = ioremap(res.start, 32);
  111. if (!avr_addr)
  112. return -EFAULT;
  113. ls_uart_init();
  114. INIT_WORK(&wd_work, wd_stop);
  115. schedule_work(&wd_work);
  116. return 0;
  117. }
  118. machine_late_initcall(linkstation, ls_uarts_init);