ls_uart.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  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 <asm/io.h>
  18. #include <asm/prom.h>
  19. #include <asm/termbits.h>
  20. #include "mpc10x.h"
  21. static void __iomem *avr_addr;
  22. static unsigned long avr_clock;
  23. static struct work_struct wd_work;
  24. static void wd_stop(struct work_struct *unused)
  25. {
  26. const char string[] = "AAAAFFFFJJJJ>>>>VVVV>>>>ZZZZVVVVKKKK";
  27. int i = 0, rescue = 8;
  28. int len = strlen(string);
  29. while (rescue--) {
  30. int j;
  31. char lsr = in_8(avr_addr + UART_LSR);
  32. if (lsr & (UART_LSR_THRE | UART_LSR_TEMT)) {
  33. for (j = 0; j < 16 && i < len; j++, i++)
  34. out_8(avr_addr + UART_TX, string[i]);
  35. if (i == len) {
  36. /* Read "OK" back: 4ms for the last "KKKK"
  37. plus a couple bytes back */
  38. msleep(7);
  39. printk("linkstation: disarming the AVR watchdog: ");
  40. while (in_8(avr_addr + UART_LSR) & UART_LSR_DR)
  41. printk("%c", in_8(avr_addr + UART_RX));
  42. break;
  43. }
  44. }
  45. msleep(17);
  46. }
  47. printk("\n");
  48. }
  49. #define AVR_QUOT(clock) ((clock) + 8 * 9600) / (16 * 9600)
  50. void avr_uart_configure(void)
  51. {
  52. unsigned char cval = UART_LCR_WLEN8;
  53. unsigned int quot = AVR_QUOT(avr_clock);
  54. if (!avr_addr || !avr_clock)
  55. return;
  56. out_8(avr_addr + UART_LCR, cval); /* initialise UART */
  57. out_8(avr_addr + UART_MCR, 0);
  58. out_8(avr_addr + UART_IER, 0);
  59. cval |= UART_LCR_STOP | UART_LCR_PARITY | UART_LCR_EPAR;
  60. out_8(avr_addr + UART_LCR, cval); /* Set character format */
  61. out_8(avr_addr + UART_LCR, cval | UART_LCR_DLAB); /* set DLAB */
  62. out_8(avr_addr + UART_DLL, quot & 0xff); /* LS of divisor */
  63. out_8(avr_addr + UART_DLM, quot >> 8); /* MS of divisor */
  64. out_8(avr_addr + UART_LCR, cval); /* reset DLAB */
  65. out_8(avr_addr + UART_FCR, UART_FCR_ENABLE_FIFO); /* enable FIFO */
  66. }
  67. void avr_uart_send(const char c)
  68. {
  69. if (!avr_addr || !avr_clock)
  70. return;
  71. out_8(avr_addr + UART_TX, c);
  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. }
  76. static void __init ls_uart_init(void)
  77. {
  78. local_irq_disable();
  79. #ifndef CONFIG_SERIAL_8250
  80. out_8(avr_addr + UART_FCR, UART_FCR_ENABLE_FIFO); /* enable FIFO */
  81. out_8(avr_addr + UART_FCR, UART_FCR_ENABLE_FIFO |
  82. UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); /* clear FIFOs */
  83. out_8(avr_addr + UART_FCR, 0);
  84. out_8(avr_addr + UART_IER, 0);
  85. /* Clear up interrupts */
  86. (void) in_8(avr_addr + UART_LSR);
  87. (void) in_8(avr_addr + UART_RX);
  88. (void) in_8(avr_addr + UART_IIR);
  89. (void) in_8(avr_addr + UART_MSR);
  90. #endif
  91. avr_uart_configure();
  92. local_irq_enable();
  93. }
  94. static int __init ls_uarts_init(void)
  95. {
  96. struct device_node *avr;
  97. phys_addr_t phys_addr;
  98. int len;
  99. avr = of_find_node_by_path("/soc10x/serial@80004500");
  100. if (!avr)
  101. return -EINVAL;
  102. avr_clock = *(u32*)of_get_property(avr, "clock-frequency", &len);
  103. phys_addr = ((u32*)of_get_property(avr, "reg", &len))[0];
  104. if (!avr_clock || !phys_addr)
  105. return -EINVAL;
  106. avr_addr = ioremap(phys_addr, 32);
  107. if (!avr_addr)
  108. return -EFAULT;
  109. ls_uart_init();
  110. INIT_WORK(&wd_work, wd_stop);
  111. schedule_work(&wd_work);
  112. return 0;
  113. }
  114. machine_late_initcall(linkstation, ls_uarts_init);