]> pilppa.org Git - linux-2.6-omap-h63xx.git/blob - arch/powerpc/platforms/embedded6xx/ls_uart.c
[POWERPC] Remove old includes from arch/ppc
[linux-2.6-omap-h63xx.git] / arch / powerpc / platforms / embedded6xx / ls_uart.c
1 #include <linux/workqueue.h>
2 #include <linux/string.h>
3 #include <linux/delay.h>
4 #include <linux/serial_reg.h>
5 #include <linux/serial_8250.h>
6 #include <asm/io.h>
7 #include <asm/mpc10x.h>
8 #include <asm/prom.h>
9 #include <asm/termbits.h>
10
11 static void __iomem *avr_addr;
12 static unsigned long avr_clock;
13
14 static struct work_struct wd_work;
15
16 static void wd_stop(struct work_struct *unused)
17 {
18         const char string[] = "AAAAFFFFJJJJ>>>>VVVV>>>>ZZZZVVVVKKKK";
19         int i = 0, rescue = 8;
20         int len = strlen(string);
21
22         while (rescue--) {
23                 int j;
24                 char lsr = in_8(avr_addr + UART_LSR);
25
26                 if (lsr & (UART_LSR_THRE | UART_LSR_TEMT)) {
27                         for (j = 0; j < 16 && i < len; j++, i++)
28                                 out_8(avr_addr + UART_TX, string[i]);
29                         if (i == len) {
30                                 /* Read "OK" back: 4ms for the last "KKKK"
31                                    plus a couple bytes back */
32                                 msleep(7);
33                                 printk("linkstation: disarming the AVR watchdog: ");
34                                 while (in_8(avr_addr + UART_LSR) & UART_LSR_DR)
35                                         printk("%c", in_8(avr_addr + UART_RX));
36                                 break;
37                         }
38                 }
39                 msleep(17);
40         }
41         printk("\n");
42 }
43
44 #define AVR_QUOT(clock) ((clock) + 8 * 9600) / (16 * 9600)
45
46 void avr_uart_configure(void)
47 {
48         unsigned char cval = UART_LCR_WLEN8;
49         unsigned int quot = AVR_QUOT(avr_clock);
50
51         if (!avr_addr || !avr_clock)
52                 return;
53
54         out_8(avr_addr + UART_LCR, cval);                       /* initialise UART */
55         out_8(avr_addr + UART_MCR, 0);
56         out_8(avr_addr + UART_IER, 0);
57
58         cval |= UART_LCR_STOP | UART_LCR_PARITY | UART_LCR_EPAR;
59
60         out_8(avr_addr + UART_LCR, cval);                       /* Set character format */
61
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
69 void avr_uart_send(const char c)
70 {
71         if (!avr_addr || !avr_clock)
72                 return;
73
74         out_8(avr_addr + UART_TX, c);
75         out_8(avr_addr + UART_TX, c);
76         out_8(avr_addr + UART_TX, c);
77         out_8(avr_addr + UART_TX, c);
78 }
79
80 static void __init ls_uart_init(void)
81 {
82         local_irq_disable();
83
84 #ifndef CONFIG_SERIAL_8250
85         out_8(avr_addr + UART_FCR, UART_FCR_ENABLE_FIFO);       /* enable FIFO */
86         out_8(avr_addr + UART_FCR, UART_FCR_ENABLE_FIFO |
87               UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);       /* clear FIFOs */
88         out_8(avr_addr + UART_FCR, 0);
89         out_8(avr_addr + UART_IER, 0);
90
91         /* Clear up interrupts */
92         (void) in_8(avr_addr + UART_LSR);
93         (void) in_8(avr_addr + UART_RX);
94         (void) in_8(avr_addr + UART_IIR);
95         (void) in_8(avr_addr + UART_MSR);
96 #endif
97         avr_uart_configure();
98
99         local_irq_enable();
100 }
101
102 static int __init ls_uarts_init(void)
103 {
104         struct device_node *avr;
105         phys_addr_t phys_addr;
106         int len;
107
108         avr = of_find_node_by_path("/soc10x/serial@80004500");
109         if (!avr)
110                 return -EINVAL;
111
112         avr_clock = *(u32*)of_get_property(avr, "clock-frequency", &len);
113         phys_addr = ((u32*)of_get_property(avr, "reg", &len))[0];
114
115         if (!avr_clock || !phys_addr)
116                 return -EINVAL;
117
118         avr_addr = ioremap(phys_addr, 32);
119         if (!avr_addr)
120                 return -EFAULT;
121
122         ls_uart_init();
123
124         INIT_WORK(&wd_work, wd_stop);
125         schedule_work(&wd_work);
126
127         return 0;
128 }
129
130 late_initcall(ls_uarts_init);