2 * AVR power-management chip interface for the Buffalo Linkstation /
5 * Author: 2006 (c) G. Liakhovetski
6 * g.liakhovetski@gmx.de
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.
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>
19 #include <asm/termbits.h>
23 static void __iomem
*avr_addr
;
24 static unsigned long avr_clock
;
26 static struct work_struct wd_work
;
28 static void wd_stop(struct work_struct
*unused
)
30 const char string
[] = "AAAAFFFFJJJJ>>>>VVVV>>>>ZZZZVVVVKKKK";
31 int i
= 0, rescue
= 8;
32 int len
= strlen(string
);
36 char lsr
= in_8(avr_addr
+ UART_LSR
);
38 if (lsr
& (UART_LSR_THRE
| UART_LSR_TEMT
)) {
39 for (j
= 0; j
< 16 && i
< len
; j
++, i
++)
40 out_8(avr_addr
+ UART_TX
, string
[i
]);
42 /* Read "OK" back: 4ms for the last "KKKK"
43 plus a couple bytes back */
45 printk("linkstation: disarming the AVR watchdog: ");
46 while (in_8(avr_addr
+ UART_LSR
) & UART_LSR_DR
)
47 printk("%c", in_8(avr_addr
+ UART_RX
));
56 #define AVR_QUOT(clock) ((clock) + 8 * 9600) / (16 * 9600)
58 void avr_uart_configure(void)
60 unsigned char cval
= UART_LCR_WLEN8
;
61 unsigned int quot
= AVR_QUOT(avr_clock
);
63 if (!avr_addr
|| !avr_clock
)
66 out_8(avr_addr
+ UART_LCR
, cval
); /* initialise UART */
67 out_8(avr_addr
+ UART_MCR
, 0);
68 out_8(avr_addr
+ UART_IER
, 0);
70 cval
|= UART_LCR_STOP
| UART_LCR_PARITY
| UART_LCR_EPAR
;
72 out_8(avr_addr
+ UART_LCR
, cval
); /* Set character format */
74 out_8(avr_addr
+ UART_LCR
, cval
| UART_LCR_DLAB
); /* set DLAB */
75 out_8(avr_addr
+ UART_DLL
, quot
& 0xff); /* LS of divisor */
76 out_8(avr_addr
+ UART_DLM
, quot
>> 8); /* MS of divisor */
77 out_8(avr_addr
+ UART_LCR
, cval
); /* reset DLAB */
78 out_8(avr_addr
+ UART_FCR
, UART_FCR_ENABLE_FIFO
); /* enable FIFO */
81 void avr_uart_send(const char c
)
83 if (!avr_addr
|| !avr_clock
)
86 out_8(avr_addr
+ UART_TX
, c
);
87 out_8(avr_addr
+ UART_TX
, c
);
88 out_8(avr_addr
+ UART_TX
, c
);
89 out_8(avr_addr
+ UART_TX
, c
);
92 static void __init
ls_uart_init(void)
96 #ifndef CONFIG_SERIAL_8250
97 out_8(avr_addr
+ UART_FCR
, UART_FCR_ENABLE_FIFO
); /* enable FIFO */
98 out_8(avr_addr
+ UART_FCR
, UART_FCR_ENABLE_FIFO
|
99 UART_FCR_CLEAR_RCVR
| UART_FCR_CLEAR_XMIT
); /* clear FIFOs */
100 out_8(avr_addr
+ UART_FCR
, 0);
101 out_8(avr_addr
+ UART_IER
, 0);
103 /* Clear up interrupts */
104 (void) in_8(avr_addr
+ UART_LSR
);
105 (void) in_8(avr_addr
+ UART_RX
);
106 (void) in_8(avr_addr
+ UART_IIR
);
107 (void) in_8(avr_addr
+ UART_MSR
);
109 avr_uart_configure();
114 static int __init
ls_uarts_init(void)
116 struct device_node
*avr
;
117 phys_addr_t phys_addr
;
120 avr
= of_find_node_by_path("/soc10x/serial@80004500");
124 avr_clock
= *(u32
*)of_get_property(avr
, "clock-frequency", &len
);
125 phys_addr
= ((u32
*)of_get_property(avr
, "reg", &len
))[0];
127 if (!avr_clock
|| !phys_addr
)
130 avr_addr
= ioremap(phys_addr
, 32);
136 INIT_WORK(&wd_work
, wd_stop
);
137 schedule_work(&wd_work
);
142 machine_late_initcall(linkstation
, ls_uarts_init
);