diff options
author | kogiidena <kogiidena@eggplant.ddo.jp> | 2006-09-27 14:53:35 +0900 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2006-09-27 14:53:35 +0900 |
commit | 94c0fa520cc169ccf661e9c03b5b95f74d1520b8 (patch) | |
tree | 2fc73ea11df222998a363083e03ef6c9e8066b28 /arch/sh/boards/landisk | |
parent | 634bf4f69b925950ddb09ef99ad7516a449a4333 (diff) | |
download | blackbird-op-linux-94c0fa520cc169ccf661e9c03b5b95f74d1520b8.tar.gz blackbird-op-linux-94c0fa520cc169ccf661e9c03b5b95f74d1520b8.zip |
sh: landisk board support.
This adds support for the I-O DATA Landisk.
Signed-off-by: kogiidena <kogiidena@eggplant.ddo.jp>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh/boards/landisk')
-rw-r--r-- | arch/sh/boards/landisk/Makefile | 7 | ||||
-rw-r--r-- | arch/sh/boards/landisk/io.c | 322 | ||||
-rw-r--r-- | arch/sh/boards/landisk/irq.c | 105 | ||||
-rw-r--r-- | arch/sh/boards/landisk/landisk_pwb.c | 348 | ||||
-rw-r--r-- | arch/sh/boards/landisk/rtc.c | 102 | ||||
-rw-r--r-- | arch/sh/boards/landisk/setup.c | 218 |
6 files changed, 1102 insertions, 0 deletions
diff --git a/arch/sh/boards/landisk/Makefile b/arch/sh/boards/landisk/Makefile new file mode 100644 index 000000000000..60e75c6db0eb --- /dev/null +++ b/arch/sh/boards/landisk/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for I-O DATA DEVICE, INC. "LANDISK Series" +# + +obj-y := setup.o io.o irq.o rtc.o landisk_pwb.o + +obj-$(CONFIG_PCI) += pci.o diff --git a/arch/sh/boards/landisk/io.c b/arch/sh/boards/landisk/io.c new file mode 100644 index 000000000000..1f1679af09d0 --- /dev/null +++ b/arch/sh/boards/landisk/io.c @@ -0,0 +1,322 @@ +/* + * arch/sh/boards/landisk/io.c + * + * Copyright (C) 2001 Ian da Silva, Jeremy Siegel + * Based largely on io_se.c. + * + * I/O routine for I-O Data Device, Inc. LANDISK. + * + * Initial version only to support LAN access; some + * placeholder code from io_landisk.c left in with the + * expectation of later SuperIO and PCMCIA access. + */ +/* + * modifed by kogiidena + * 2005.03.03 + */ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <asm/io.h> +#include <asm/landisk/iodata_landisk.h> +#include <asm/addrspace.h> + +#include <linux/module.h> +#include <linux/pci.h> +#include "../../drivers/pci/pci-sh7751.h" + +extern void *area5_io_base; /* Area 5 I/O Base address */ +extern void *area6_io_base; /* Area 6 I/O Base address */ + +/* + * The 7751R LANDISK uses the built-in PCI controller (PCIC) + * of the 7751R processor, and has a SuperIO accessible via the PCI. + * The board also includes a PCMCIA controller on its memory bus, + * like the other Solution Engine boards. + */ + +#define PCIIOBR (volatile long *)PCI_REG(SH7751_PCIIOBR) +#define PCIMBR (volatile long *)PCI_REG(SH7751_PCIMBR) +#define PCI_IO_AREA SH7751_PCI_IO_BASE +#define PCI_MEM_AREA SH7751_PCI_CONFIG_BASE + +#define PCI_IOMAP(adr) (PCI_IO_AREA + (adr & ~SH7751_PCIIOBR_MASK)) + +#define maybebadio(name,port) \ + printk("bad PC-like io %s for port 0x%lx at 0x%08x\n", \ + #name, (port), (__u32) __builtin_return_address(0)) + +static inline void delay(void) +{ + ctrl_inw(0xa0000000); +} + +static inline unsigned long port2adr(unsigned int port) +{ + if ((0x1f0 <= port && port < 0x1f8) || port == 0x3f6) + if (port == 0x3f6) + return ((unsigned long)area5_io_base + 0x2c); + else + return ((unsigned long)area5_io_base + PA_PIDE_OFFSET + + ((port - 0x1f0) << 1)); + else if ((0x170 <= port && port < 0x178) || port == 0x376) + if (port == 0x376) + return ((unsigned long)area6_io_base + 0x2c); + else + return ((unsigned long)area6_io_base + PA_SIDE_OFFSET + + ((port - 0x170) << 1)); + else + maybebadio(port2adr, (unsigned long)port); + + return port; +} + +/* In case someone configures the kernel w/o PCI support: in that */ +/* scenario, don't ever bother to check for PCI-window addresses */ + +/* NOTE: WINDOW CHECK MAY BE A BIT OFF, HIGH PCIBIOS_MIN_IO WRAPS? */ +#if defined(CONFIG_PCI) +#define CHECK_SH7751_PCIIO(port) \ + ((port >= PCIBIOS_MIN_IO) && (port < (PCIBIOS_MIN_IO + SH7751_PCI_IO_SIZE))) +#else +#define CHECK_SH_7751_PCIIO(port) (0) +#endif + +/* + * General outline: remap really low stuff [eventually] to SuperIO, + * stuff in PCI IO space (at or above window at pci.h:PCIBIOS_MIN_IO) + * is mapped through the PCI IO window. Stuff with high bits (PXSEG) + * should be way beyond the window, and is used w/o translation for + * compatibility. + */ +unsigned char landisk_inb(unsigned long port) +{ + if (PXSEG(port)) + return *(volatile unsigned char *)port; + else if (CHECK_SH7751_PCIIO(port)) + return *(volatile unsigned char *)PCI_IOMAP(port); + else + return (*(volatile unsigned short *)port2adr(port) & 0xff); +} + +unsigned char landisk_inb_p(unsigned long port) +{ + unsigned char v; + + if (PXSEG(port)) + v = *(volatile unsigned char *)port; + else if (CHECK_SH7751_PCIIO(port)) + v = *(volatile unsigned char *)PCI_IOMAP(port); + else + v = (*(volatile unsigned short *)port2adr(port) & 0xff); + delay(); + + return v; +} + +unsigned short landisk_inw(unsigned long port) +{ + if (PXSEG(port)) + return *(volatile unsigned short *)port; + else if (CHECK_SH7751_PCIIO(port)) + return *(volatile unsigned short *)PCI_IOMAP(port); + else + maybebadio(inw, port); + + return 0; +} + +unsigned int landisk_inl(unsigned long port) +{ + if (PXSEG(port)) + return *(volatile unsigned long *)port; + else if (CHECK_SH7751_PCIIO(port)) + return *(volatile unsigned long *)PCI_IOMAP(port); + else + maybebadio(inl, port); + + return 0; +} + +void landisk_outb(unsigned char value, unsigned long port) +{ + + if (PXSEG(port)) + *(volatile unsigned char *)port = value; + else if (CHECK_SH7751_PCIIO(port)) + *(volatile unsigned char *)PCI_IOMAP(port) = value; + else + *(volatile unsigned short *)port2adr(port) = value; +} + +void landisk_outb_p(unsigned char value, unsigned long port) +{ + if (PXSEG(port)) + *(volatile unsigned char *)port = value; + else if (CHECK_SH7751_PCIIO(port)) + *(volatile unsigned char *)PCI_IOMAP(port) = value; + else + *(volatile unsigned short *)port2adr(port) = value; + delay(); +} + +void landisk_outw(unsigned short value, unsigned long port) +{ + if (PXSEG(port)) + *(volatile unsigned short *)port = value; + else if (CHECK_SH7751_PCIIO(port)) + *(volatile unsigned short *)PCI_IOMAP(port) = value; + else + maybebadio(outw, port); +} + +void landisk_outl(unsigned int value, unsigned long port) +{ + if (PXSEG(port)) + *(volatile unsigned long *)port = value; + else if (CHECK_SH7751_PCIIO(port)) + *(volatile unsigned long *)PCI_IOMAP(port) = value; + else + maybebadio(outl, port); +} + +void landisk_insb(unsigned long port, void *addr, unsigned long count) +{ + if (PXSEG(port)) + while (count--) + *((unsigned char *)addr)++ = + *(volatile unsigned char *)port; + else if (CHECK_SH7751_PCIIO(port)) { + volatile __u8 *bp = (__u8 *) PCI_IOMAP(port); + + while (count--) + *((volatile unsigned char *)addr)++ = *bp; + } else { + volatile __u16 *p = (volatile unsigned short *)port2adr(port); + + while (count--) + *((unsigned char *)addr)++ = *p; + } +} + +void landisk_insw(unsigned long port, void *addr, unsigned long count) +{ + volatile __u16 *p; + + if (PXSEG(port)) + p = (volatile unsigned short *)port; + else if (CHECK_SH7751_PCIIO(port)) + p = (volatile unsigned short *)PCI_IOMAP(port); + else + p = (volatile unsigned short *)port2adr(port); + while (count--) + *((__u16 *) addr)++ = *p; +} + +void landisk_insl(unsigned long port, void *addr, unsigned long count) +{ + if (CHECK_SH7751_PCIIO(port)) { + volatile __u32 *p = (__u32 *) PCI_IOMAP(port); + + while (count--) + *((__u32 *) addr)++ = *p; + } else + maybebadio(insl, port); +} + +void landisk_outsb(unsigned long port, const void *addr, unsigned long count) +{ + if (PXSEG(port)) + while (count--) + *(volatile unsigned char *)port = + *((unsigned char *)addr)++; + else if (CHECK_SH7751_PCIIO(port)) { + volatile __u8 *bp = (__u8 *) PCI_IOMAP(port); + + while (count--) + *bp = *((volatile unsigned char *)addr)++; + } else { + volatile __u16 *p = (volatile unsigned short *)port2adr(port); + + while (count--) + *p = *((unsigned char *)addr)++; + } +} + +void landisk_outsw(unsigned long port, const void *addr, unsigned long count) +{ + volatile __u16 *p; + + if (PXSEG(port)) + p = (volatile unsigned short *)port; + else if (CHECK_SH7751_PCIIO(port)) + p = (volatile unsigned short *)PCI_IOMAP(port); + else + p = (volatile unsigned short *)port2adr(port); + while (count--) + *p = *((__u16 *) addr)++; +} + +void landisk_outsl(unsigned long port, const void *addr, unsigned long count) +{ + if (CHECK_SH7751_PCIIO(port)) { + volatile __u32 *p = (__u32 *) PCI_IOMAP(port); + + while (count--) + *p = *((__u32 *) addr)++; + } else + maybebadio(outsl, port); +} + +/* For read/write calls, just copy generic (pass-thru); PCIMBR is */ +/* already set up. For a larger memory space, these would need to */ +/* reset PCIMBR as needed on a per-call basis... */ + +unsigned char landisk_readb(unsigned long addr) +{ + return *(volatile unsigned char *)addr; +} + +unsigned short landisk_readw(unsigned long addr) +{ + return *(volatile unsigned short *)addr; +} + +unsigned int landisk_readl(unsigned long addr) +{ + return *(volatile unsigned long *)addr; +} + +void landisk_writeb(unsigned char b, unsigned long addr) +{ + *(volatile unsigned char *)addr = b; +} + +void landisk_writew(unsigned short b, unsigned long addr) +{ + *(volatile unsigned short *)addr = b; +} + +void landisk_writel(unsigned int b, unsigned long addr) +{ + *(volatile unsigned long *)addr = b; +} + +void *landisk_ioremap(unsigned long offset, unsigned long size) +{ + if (offset >= 0xfd000000) + return (void *)offset; + else + return (void *)P2SEGADDR(offset); +} + +void landisk_iounmap(void *addr) +{ +} + +/* Map ISA bus address to the real address. Only for PCMCIA. */ + +unsigned long landisk_isa_port2addr(unsigned long offset) +{ + return port2adr(offset); +} diff --git a/arch/sh/boards/landisk/irq.c b/arch/sh/boards/landisk/irq.c new file mode 100644 index 000000000000..1dcc3feb7a44 --- /dev/null +++ b/arch/sh/boards/landisk/irq.c @@ -0,0 +1,105 @@ +/* + * arch/sh/boards/landisk/irq.c + * + * Copyright (C) 2001 Ian da Silva, Jeremy Siegel + * Based largely on io_se.c. + * + * I/O routine for I-O Data Device, Inc. LANDISK. + * + * Initial version only to support LAN access; some + * placeholder code from io_landisk.c left in with the + * expectation of later SuperIO and PCMCIA access. + */ +/* + * modified by kogiidena + * 2005.03.03 + */ + +#include <linux/config.h> +#include <linux/init.h> +#include <linux/irq.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/landisk/iodata_landisk.h> + +static void enable_landisk_irq(unsigned int irq); +static void disable_landisk_irq(unsigned int irq); + +/* shutdown is same as "disable" */ +#define shutdown_landisk_irq disable_landisk_irq + +static void ack_landisk_irq(unsigned int irq); +static void end_landisk_irq(unsigned int irq); + +static unsigned int startup_landisk_irq(unsigned int irq) +{ + enable_landisk_irq(irq); + return 0; /* never anything pending */ +} + +static void disable_landisk_irq(unsigned int irq) +{ + unsigned long flags; + unsigned char val; + unsigned char mask = 0xff ^ (0x01 << (irq - 5)); + + /* Set the priority in IPR to 0 */ + local_irq_save(flags); + val = ctrl_inb(PA_IMASK); + val &= mask; + ctrl_outb(val, PA_IMASK); + local_irq_restore(flags); +} + +static void enable_landisk_irq(unsigned int irq) +{ + unsigned long flags; + unsigned char val; + unsigned char value = (0x01 << (irq - 5)); + + /* Set priority in IPR back to original value */ + local_irq_save(flags); + val = ctrl_inb(PA_IMASK); + val |= value; + ctrl_outb(val, PA_IMASK); + local_irq_restore(flags); +} + +static void ack_landisk_irq(unsigned int irq) +{ + disable_landisk_irq(irq); +} + +static void end_landisk_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) + enable_landisk_irq(irq); +} + +static struct hw_interrupt_type landisk_irq_type = { + .typename = "LANDISK IRQ", + .startup = startup_landisk_irq, + .shutdown = shutdown_landisk_irq, + .enable = enable_landisk_irq, + .disable = disable_landisk_irq, + .ack = ack_landisk_irq, + .end = end_landisk_irq +}; + +static void make_landisk_irq(unsigned int irq) +{ + disable_irq_nosync(irq); + irq_desc[irq].handler = &landisk_irq_type; + disable_landisk_irq(irq); +} + +/* + * Initialize IRQ setting + */ +void __init init_landisk_IRQ(void) +{ + int i; + + for (i = 5; i < 14; i++) + make_landisk_irq(i); +} diff --git a/arch/sh/boards/landisk/landisk_pwb.c b/arch/sh/boards/landisk/landisk_pwb.c new file mode 100644 index 000000000000..e75cb578a28b --- /dev/null +++ b/arch/sh/boards/landisk/landisk_pwb.c @@ -0,0 +1,348 @@ +/* + * arch/sh/boards/landisk/landisk_pwb.c -- driver for the Power control switch. + * + * This driver will also support the I-O DATA Device, Inc. LANDISK Board. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copylight (C) 2002 Atom Create Engineering Co., Ltd. + * + * LED control drive function added by kogiidena + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/signal.h> +#include <linux/major.h> +#include <linux/poll.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/sched.h> +#include <linux/timer.h> +#include <linux/interrupt.h> + +#include <asm/system.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/uaccess.h> +#include <asm/landisk/iodata_landisk.h> + +#define SHUTDOWN_BTN_MINOR 1 /* Shutdown button device minor no. */ +#define LED_MINOR 21 /* LED minor no. */ +#define BTN_MINOR 22 /* BUTTON minor no. */ +#define GIO_MINOR 40 /* GIO minor no. */ + +static int openCnt; +static int openCntLED; +static int openCntGio; +static int openCntBtn; +static int landisk_btn; +static int landisk_btnctrlpid; +/* + * Functions prototypes + */ + +static int gio_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg); + +static int swdrv_open(struct inode *inode, struct file *filp) +{ + int minor; + + minor = MINOR(inode->i_rdev); + filp->private_data = (void *)minor; + + if (minor == SHUTDOWN_BTN_MINOR) { + if (openCnt > 0) { + return -EALREADY; + } else { + openCnt++; + return 0; + } + } else if (minor == LED_MINOR) { + if (openCntLED > 0) { + return -EALREADY; + } else { + openCntLED++; + return 0; + } + } else if (minor == BTN_MINOR) { + if (openCntBtn > 0) { + return -EALREADY; + } else { + openCntBtn++; + return 0; + } + } else if (minor == GIO_MINOR) { + if (openCntGio > 0) { + return -EALREADY; + } else { + openCntGio++; + return 0; + } + } + return -ENOENT; + +} + +static int swdrv_close(struct inode *inode, struct file *filp) +{ + int minor; + + minor = MINOR(inode->i_rdev); + if (minor == SHUTDOWN_BTN_MINOR) { + openCnt--; + } else if (minor == LED_MINOR) { + openCntLED--; + } else if (minor == BTN_MINOR) { + openCntBtn--; + } else if (minor == GIO_MINOR) { + openCntGio--; + } + return 0; +} + +static int swdrv_read(struct file *filp, char *buff, size_t count, + loff_t * ppos) +{ + int minor; + minor = (int)(filp->private_data); + + if (!access_ok(VERIFY_WRITE, (void *)buff, count)) + return -EFAULT; + + if (minor == SHUTDOWN_BTN_MINOR) { + if (landisk_btn & 0x10) { + put_user(1, buff); + return 1; + } else { + return 0; + } + } + return 0; +} + +static int swdrv_write(struct file *filp, const char *buff, size_t count, + loff_t * ppos) +{ + int minor; + minor = (int)(filp->private_data); + + if (minor == SHUTDOWN_BTN_MINOR) { + return count; + } + return count; +} + +static irqreturn_t sw_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + landisk_btn = (0x0ff & (~ctrl_inb(PA_STATUS))); + disable_irq(IRQ_BUTTON); + disable_irq(IRQ_POWER); + ctrl_outb(0x00, PA_PWRINT_CLR); + + if (landisk_btnctrlpid != 0) { + kill_proc(landisk_btnctrlpid, SIGUSR1, 1); + landisk_btnctrlpid = 0; + } + + return IRQ_HANDLED; +} + +static struct file_operations swdrv_fops = { + .read = swdrv_read, /* read */ + .write = swdrv_write, /* write */ + .open = swdrv_open, /* open */ + .release = swdrv_close, /* release */ + .ioctl = gio_ioctl, /* ioctl */ + +}; + +static char banner[] __initdata = + KERN_INFO "LANDISK and USL-5P Button, LED and GIO driver initialized\n"; + +int __init swdrv_init(void) +{ + int error; + + printk("%s", banner); + + openCnt = 0; + openCntLED = 0; + openCntBtn = 0; + openCntGio = 0; + landisk_btn = 0; + landisk_btnctrlpid = 0; + + if ((error = register_chrdev(SHUTDOWN_BTN_MAJOR, "swdrv", &swdrv_fops))) { + printk(KERN_ERR + "Button, LED and GIO driver:Couldn't register driver, error=%d\n", + error); + return 1; + } + + if (request_irq(IRQ_POWER, sw_interrupt, 0, "SHUTDOWNSWITCH", NULL)) { + printk(KERN_ERR "Unable to get IRQ 11.\n"); + return 1; + } + if (request_irq(IRQ_BUTTON, sw_interrupt, 0, "USL-5P BUTTON", NULL)) { + printk(KERN_ERR "Unable to get IRQ 12.\n"); + return 1; + } + ctrl_outb(0x00, PA_PWRINT_CLR); + + return 0; +} + +module_init(swdrv_init); + +/* + * gio driver + * + */ + +#include <asm/landisk/gio.h> + +static int gio_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + int minor; + unsigned int data, mask; + static unsigned int addr = 0; + + minor = (int)(filp->private_data); + + /* access control */ + if (minor == GIO_MINOR) { + ; + } else if (minor == LED_MINOR) { + if (((cmd & 0x0ff) >= 9) && ((cmd & 0x0ff) < 20)) { + ; + } else { + return -EINVAL; + } + } else if (minor == BTN_MINOR) { + if (((cmd & 0x0ff) >= 20) && ((cmd & 0x0ff) < 30)) { + ; + } else { + return -EINVAL; + } + } else { + return -EINVAL; + } + + if (cmd & 0x01) { /* write */ + if (copy_from_user(&data, (int *)arg, sizeof(int))) { + return -EFAULT; + } + } + + switch (cmd) { + case GIODRV_IOCSGIOSETADDR: /* addres set */ + addr = data; + break; + + case GIODRV_IOCSGIODATA1: /* write byte */ + ctrl_outb((unsigned char)(0x0ff & data), addr); + break; + + case GIODRV_IOCSGIODATA2: /* write word */ + if (addr & 0x01) { + return -EFAULT; + } + ctrl_outw((unsigned short int)(0x0ffff & data), addr); + break; + + case GIODRV_IOCSGIODATA4: /* write long */ + if (addr & 0x03) { + return -EFAULT; + } + ctrl_outl(data, addr); + break; + + case GIODRV_IOCGGIODATA1: /* read byte */ + data = ctrl_inb(addr); + break; + + case GIODRV_IOCGGIODATA2: /* read word */ + if (addr & 0x01) { + return -EFAULT; + } + data = ctrl_inw(addr); + break; + + case GIODRV_IOCGGIODATA4: /* read long */ + if (addr & 0x03) { + return -EFAULT; + } + data = ctrl_inl(addr); + break; + case GIODRV_IOCSGIO_LED: /* write */ + mask = ((data & 0x00ffffff) << 8) + | ((data & 0x0000ffff) << 16) + | ((data & 0x000000ff) << 24); + landisk_ledparam = data & (~mask); + if (landisk_arch == 0) { /* arch == landisk */ + landisk_ledparam &= 0x03030303; + mask = (~(landisk_ledparam >> 22)) & 0x000c; + landisk_ledparam |= mask; + } else { /* arch == usl-5p */ + mask = (landisk_ledparam >> 24) & 0x0001; + landisk_ledparam |= mask; + landisk_ledparam &= 0x007f7f7f; + } + landisk_ledparam |= 0x80; + break; + case GIODRV_IOCGGIO_LED: /* read */ + data = landisk_ledparam; + if (landisk_arch == 0) { /* arch == landisk */ + data &= 0x03030303; + } else { /* arch == usl-5p */ + ; + } + data &= (~0x080); + break; + case GIODRV_IOCSGIO_BUZZER: /* write */ + landisk_buzzerparam = data; + landisk_ledparam |= 0x80; + break; + case GIODRV_IOCGGIO_LANDISK: /* read */ + data = landisk_arch & 0x01; + break; + case GIODRV_IOCGGIO_BTN: /* read */ + data = (0x0ff & ctrl_inb(PA_PWRINT_CLR)); + data <<= 8; + data |= (0x0ff & ctrl_inb(PA_IMASK)); + data <<= 8; + data |= (0x0ff & landisk_btn); + data <<= 8; + data |= (0x0ff & (~ctrl_inb(PA_STATUS))); + break; + case GIODRV_IOCSGIO_BTNPID: /* write */ + landisk_btnctrlpid = data; + landisk_btn = 0; + if (irq_desc[IRQ_BUTTON].depth) { + enable_irq(IRQ_BUTTON); + } + if (irq_desc[IRQ_POWER].depth) { + enable_irq(IRQ_POWER); + } + break; + case GIODRV_IOCGGIO_BTNPID: /* read */ + data = landisk_btnctrlpid; + break; + default: + return -EFAULT; + break; + } + + if ((cmd & 0x01) == 0) { /* read */ + if (copy_to_user((int *)arg, &data, sizeof(int))) { + return -EFAULT; + } + } + return 0; +} diff --git a/arch/sh/boards/landisk/rtc.c b/arch/sh/boards/landisk/rtc.c new file mode 100644 index 000000000000..d666aa63303f --- /dev/null +++ b/arch/sh/boards/landisk/rtc.c @@ -0,0 +1,102 @@ +/* + * arch/sh/boards/landisk/rtc.c -- RTC support + * + * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> + * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka + */ +/* + * modifed by kogiidena + * 2005.09.16 + */ + +#include <linux/config.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/time.h> +#include <linux/delay.h> +#include <linux/spinlock.h> + +#ifndef BCD_TO_BIN +#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10) +#endif + +#ifndef BIN_TO_BCD +#define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10) +#endif + +extern void (*rtc_get_time) (struct timespec *); +extern int (*rtc_set_time) (const time_t); +extern spinlock_t rtc_lock; + +extern void +rs5c313_set_cmos_time(unsigned int BCD_yr, unsigned int BCD_mon, + unsigned int BCD_day, unsigned int BCD_hr, + unsigned int BCD_min, unsigned int BCD_sec); + +extern unsigned long +rs5c313_get_cmos_time(unsigned int *BCD_yr, unsigned int *BCD_mon, + unsigned int *BCD_day, unsigned int *BCD_hr, + unsigned int *BCD_min, unsigned int *BCD_sec); + +void landisk_rtc_gettimeofday(struct timespec *tv) +{ + unsigned int BCD_yr, BCD_mon, BCD_day, BCD_hr, BCD_min, BCD_sec; + unsigned long flags; + + spin_lock_irqsave(&rtc_lock, flags); + tv->tv_sec = rs5c313_get_cmos_time + (&BCD_yr, &BCD_mon, &BCD_day, &BCD_hr, &BCD_min, &BCD_sec); + tv->tv_nsec = 0; + spin_unlock_irqrestore(&rtc_lock, flags); +} + +int landisk_rtc_settimeofday(const time_t secs) +{ + int retval = 0; + int real_seconds, real_minutes, cmos_minutes; + unsigned long flags; + unsigned long nowtime = secs; + unsigned int BCD_yr, BCD_mon, BCD_day, BCD_hr, BCD_min, BCD_sec; + + spin_lock_irqsave(&rtc_lock, flags); + + rs5c313_get_cmos_time + (&BCD_yr, &BCD_mon, &BCD_day, &BCD_hr, &BCD_min, &BCD_sec); + cmos_minutes = BCD_min; + BCD_TO_BIN(cmos_minutes); + + /* + * since we're only adjusting minutes and seconds, + * don't interfere with hour overflow. This avoids + * messing with unknown time zones but requires your + * RTC not to be off by more than 15 minutes + */ + real_seconds = nowtime % 60; + real_minutes = nowtime / 60; + if (((abs(real_minutes - cmos_minutes) + 15) / 30) & 1) + real_minutes += 30; /* correct for half hour time zone */ + real_minutes %= 60; + + if (abs(real_minutes - cmos_minutes) < 30) { + BIN_TO_BCD(real_seconds); + BIN_TO_BCD(real_minutes); + rs5c313_set_cmos_time(BCD_yr, BCD_mon, BCD_day, BCD_hr, + real_minutes, real_seconds); + } else { + printk(KERN_WARNING + "set_rtc_time: can't update from %d to %d\n", + cmos_minutes, real_minutes); + retval = -1; + } + + spin_unlock_irqrestore(&rtc_lock, flags); + return retval; +} + + +void landisk_time_init(void) +{ + rtc_get_time = landisk_rtc_gettimeofday; + rtc_set_time = landisk_rtc_settimeofday; +} diff --git a/arch/sh/boards/landisk/setup.c b/arch/sh/boards/landisk/setup.c new file mode 100644 index 000000000000..0c60eaa10ba7 --- /dev/null +++ b/arch/sh/boards/landisk/setup.c @@ -0,0 +1,218 @@ +/* + * arch/sh/boards/landisk/setup.c + * + * Copyright (C) 2002 Paul Mundt + * + * May be copied or modified under the terms of the GNU General Public + * License. See linux/COPYING for more information. + * + * Setup code for an unknown machine (internal peripherials only) + */ +/* + * linux/arch/sh/kernel/setup_landisk.c + * + * Copyright (C) 2000 Kazumoto Kojima + * + * I-O DATA Device, Inc. LANDISK Support. + * + * Modified for LANDISK by + * Atom Create Engineering Co., Ltd. 2002. + */ +/* + * modifed by kogiidena + * 2005.09.16 + */ + +#include <linux/config.h> +#include <linux/init.h> +#include <linux/irq.h> +#include <linux/pm.h> + +#include <linux/hdreg.h> +#include <linux/ide.h> +#include <linux/pci.h> + +#include <asm/machvec.h> +#include <asm/rtc.h> +#include <asm/machvec_init.h> +#include <asm/io.h> +#include <asm/landisk/iodata_landisk.h> +#include <asm/landisk/io.h> + +#include <linux/mm.h> +#include <linux/vmalloc.h> + +extern void (*board_time_init) (void); +void landisk_time_init(void); +extern void init_landisk_IRQ(void); + +int landisk_ledparam; +int landisk_buzzerparam; +int landisk_arch; + +/* defined in mm/ioremap.c */ +extern void *p3_ioremap(unsigned long phys_addr, unsigned long size, + unsigned long flags); + +/* + * Initialize the board + */ + +const char *get_system_type(void) +{ + return "LANDISK"; +} + +static void landisk_power_off(void) +{ + ctrl_outb(0x01, PA_SHUTDOWN); +} + +void check_usl5p(void) +{ + volatile unsigned char *p = (volatile unsigned char *)PA_LED; + unsigned char tmp1, tmp2; + tmp1 = *p; + *p = 0x40; + tmp2 = *p; + *p = tmp1; + landisk_arch = (tmp2 == 0x40) ? 1 : 0; + if (landisk_arch == 1) { /* arch == usl-5p */ + landisk_ledparam = 0x00000380; + landisk_ledparam |= (tmp1 & 0x07c); + } else { /* arch == landisk */ + landisk_ledparam = 0x02000180; + landisk_ledparam |= 0x04; + } + return; +} + +void __init platform_setup(void) +{ + + landisk_buzzerparam = 0; + check_usl5p(); + + printk(KERN_INFO "I-O DATA DEVICE, INC. \"LANDISK Series\" support.\n"); + board_time_init = landisk_time_init; + pm_power_off = landisk_power_off; + +} + +void *area5_io_base; +void *area6_io_base; + +int __init cf_init(void) +{ + pgprot_t prot; + unsigned long paddrbase, psize; + + /* open I/O area window */ + paddrbase = virt_to_phys((void *)PA_AREA5_IO); + psize = PAGE_SIZE; + prot = PAGE_KERNEL_PCC(1, _PAGE_PCC_IO16); + area5_io_base = p3_ioremap(paddrbase, psize, prot.pgprot); + if (!area5_io_base) { + printk("allocate_cf_area : can't open CF I/O window!\n"); + return -ENOMEM; + } + + paddrbase = virt_to_phys((void *)PA_AREA6_IO); + psize = PAGE_SIZE; + prot = PAGE_KERNEL_PCC(0, _PAGE_PCC_IO16); + area6_io_base = p3_ioremap(paddrbase, psize, prot.pgprot); + if (!area6_io_base) { + printk("allocate_cf_area : can't open HDD I/O window!\n"); + return -ENOMEM; + } + + printk(KERN_INFO "Allocate Area5/6 success.\n"); + + /* XXX : do we need attribute and common-memory area also? */ + + return 0; +} + +__initcall(cf_init); + +#include <linux/sched.h> + +/* Cycle the LED's in the clasic knightrider/Sun pattern */ + +void heartbeat_landisk(void) +{ + static unsigned int cnt = 0, blink = 0x00, period = 25; + volatile unsigned char *p = (volatile unsigned char *)PA_LED; + char data; + + if ((landisk_ledparam & 0x080) == 0) { + return; + } + cnt += 1; + if (cnt < period) { + return; + } + cnt = 0; + blink++; + + data = (blink & 0x01) ? (landisk_ledparam >> 16) : 0; + data |= (blink & 0x02) ? (landisk_ledparam >> 8) : 0; + data |= landisk_ledparam; + + /* buzzer */ + if (landisk_buzzerparam & 0x1) { + data |= 0x80; + } else { + data &= 0x7f; + } + *p = data; + + if (((landisk_ledparam & 0x007f7f00) == 0) + && (landisk_buzzerparam == 0)) { + landisk_ledparam &= (~0x0080); + } + landisk_buzzerparam >>= 1; +} + +/* + * The Machine Vector + */ + +struct sh_machine_vector mv_landisk __initmv = { + .mv_nr_irqs = 72, + .mv_inb = landisk_inb, + .mv_inw = landisk_inw, + .mv_inl = landisk_inl, + .mv_outb = landisk_outb, + .mv_outw = landisk_outw, + .mv_outl = landisk_outl, + .mv_inb_p = landisk_inb_p, + .mv_inw_p = landisk_inw, + .mv_inl_p = landisk_inl, + .mv_outb_p = landisk_outb_p, + .mv_outw_p = landisk_outw, + .mv_outl_p = landisk_outl, + .mv_insb = landisk_insb, + .mv_insw = landisk_insw, + .mv_insl = landisk_insl, + .mv_outsb = landisk_outsb, + .mv_outsw = landisk_outsw, + .mv_outsl = landisk_outsl, + .mv_readb = landisk_readb, + .mv_readw = landisk_readw, + .mv_readl = landisk_readl, + .mv_writeb = landisk_writeb, + .mv_writew = landisk_writew, + .mv_writel = landisk_writel, + .mv_ioremap = landisk_ioremap, + .mv_iounmap = landisk_iounmap, + .mv_isa_port2addr = landisk_isa_port2addr, + .mv_init_irq = init_landisk_IRQ, + +#ifdef CONFIG_HEARTBEAT + .mv_heartbeat = heartbeat_landisk, +#endif + +}; + +ALIAS_MV(landisk) |