Path: blob/master/arch/powerpc/platforms/embedded6xx/ls_uart.c
26489 views
/*1* AVR power-management chip interface for the Buffalo Linkstation /2* Kurobox Platform.3*4* Author: 2006 (c) G. Liakhovetski5* [email protected]6*7* This file is licensed under the terms of the GNU General Public License8* version 2. This program is licensed "as is" without any warranty of9* any kind, whether express or implied.10*/11#include <linux/workqueue.h>12#include <linux/string.h>13#include <linux/delay.h>14#include <linux/serial_reg.h>15#include <linux/serial_8250.h>16#include <linux/of.h>17#include <linux/of_address.h>18#include <asm/io.h>19#include <asm/termbits.h>2021#include "mpc10x.h"2223static void __iomem *avr_addr;24static unsigned long avr_clock;2526static struct work_struct wd_work;2728static void wd_stop(struct work_struct *unused)29{30const char string[] = "AAAAFFFFJJJJ>>>>VVVV>>>>ZZZZVVVVKKKK";31int i = 0, rescue = 8;32int len = strlen(string);3334while (rescue--) {35int j;36char lsr = in_8(avr_addr + UART_LSR);3738if (lsr & (UART_LSR_THRE | UART_LSR_TEMT)) {39for (j = 0; j < 16 && i < len; j++, i++)40out_8(avr_addr + UART_TX, string[i]);41if (i == len) {42/* Read "OK" back: 4ms for the last "KKKK"43plus a couple bytes back */44msleep(7);45printk("linkstation: disarming the AVR watchdog: ");46while (in_8(avr_addr + UART_LSR) & UART_LSR_DR)47printk("%c", in_8(avr_addr + UART_RX));48break;49}50}51msleep(17);52}53printk("\n");54}5556#define AVR_QUOT(clock) ((clock) + 8 * 9600) / (16 * 9600)5758void avr_uart_configure(void)59{60unsigned char cval = UART_LCR_WLEN8;61unsigned int quot = AVR_QUOT(avr_clock);6263if (!avr_addr || !avr_clock)64return;6566out_8(avr_addr + UART_LCR, cval); /* initialise UART */67out_8(avr_addr + UART_MCR, 0);68out_8(avr_addr + UART_IER, 0);6970cval |= UART_LCR_STOP | UART_LCR_PARITY | UART_LCR_EPAR;7172out_8(avr_addr + UART_LCR, cval); /* Set character format */7374out_8(avr_addr + UART_LCR, cval | UART_LCR_DLAB); /* set DLAB */75out_8(avr_addr + UART_DLL, quot & 0xff); /* LS of divisor */76out_8(avr_addr + UART_DLM, quot >> 8); /* MS of divisor */77out_8(avr_addr + UART_LCR, cval); /* reset DLAB */78out_8(avr_addr + UART_FCR, UART_FCR_ENABLE_FIFO); /* enable FIFO */79}8081void avr_uart_send(const char c)82{83if (!avr_addr || !avr_clock)84return;8586out_8(avr_addr + UART_TX, c);87out_8(avr_addr + UART_TX, c);88out_8(avr_addr + UART_TX, c);89out_8(avr_addr + UART_TX, c);90}9192static void __init ls_uart_init(void)93{94local_irq_disable();9596#ifndef CONFIG_SERIAL_825097out_8(avr_addr + UART_FCR, UART_FCR_ENABLE_FIFO); /* enable FIFO */98out_8(avr_addr + UART_FCR, UART_FCR_ENABLE_FIFO |99UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); /* clear FIFOs */100out_8(avr_addr + UART_FCR, 0);101out_8(avr_addr + UART_IER, 0);102103/* 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);108#endif109avr_uart_configure();110111local_irq_enable();112}113114static int __init ls_uarts_init(void)115{116struct device_node *avr;117struct resource res;118int len, ret;119120avr = of_find_node_by_path("/soc10x/serial@80004500");121if (!avr)122return -EINVAL;123124avr_clock = *(u32*)of_get_property(avr, "clock-frequency", &len);125if (!avr_clock)126return -EINVAL;127128ret = of_address_to_resource(avr, 0, &res);129if (ret)130return ret;131132of_node_put(avr);133134avr_addr = ioremap(res.start, 32);135if (!avr_addr)136return -EFAULT;137138ls_uart_init();139140INIT_WORK(&wd_work, wd_stop);141schedule_work(&wd_work);142143return 0;144}145146machine_late_initcall(linkstation, ls_uarts_init);147148149