diff options
Diffstat (limited to 'arch/mips/mti-sead3/sead3-pic32-bus.c')
-rw-r--r-- | arch/mips/mti-sead3/sead3-pic32-bus.c | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/arch/mips/mti-sead3/sead3-pic32-bus.c b/arch/mips/mti-sead3/sead3-pic32-bus.c new file mode 100644 index 00000000000..9f0d89bc800 --- /dev/null +++ b/arch/mips/mti-sead3/sead3-pic32-bus.c @@ -0,0 +1,103 @@ +/* + * 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. + * + * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. + */ +#include <linux/delay.h> +#include <linux/kernel.h> +#include <linux/spinlock.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/errno.h> + +#define PIC32_NULL 0x00 +#define PIC32_RD 0x01 +#define PIC32_SYSRD 0x02 +#define PIC32_WR 0x10 +#define PIC32_SYSWR 0x20 +#define PIC32_IRQ_CLR 0x40 +#define PIC32_STATUS 0x80 + +#define DELAY() udelay(100) /* FIXME: needed? */ + +/* spinlock to ensure atomic access to PIC32 */ +static DEFINE_SPINLOCK(pic32_bus_lock); + +/* FIXME: io_remap these */ +static void __iomem *bus_xfer = (void __iomem *)0xbf000600; +static void __iomem *bus_status = (void __iomem *)0xbf000060; + +static inline unsigned int ioready(void) +{ + return readl(bus_status) & 1; +} + +static inline void wait_ioready(void) +{ + do { } while (!ioready()); +} + +static inline void wait_ioclear(void) +{ + do { } while (ioready()); +} + +static inline void check_ioclear(void) +{ + if (ioready()) { + pr_debug("ioclear: initially busy\n"); + do { + (void) readl(bus_xfer); + DELAY(); + } while (ioready()); + pr_debug("ioclear: cleared busy\n"); + } +} + +u32 pic32_bus_readl(u32 reg) +{ + unsigned long flags; + u32 status, val; + + spin_lock_irqsave(&pic32_bus_lock, flags); + + check_ioclear(); + + writel((PIC32_RD << 24) | (reg & 0x00ffffff), bus_xfer); + DELAY(); + wait_ioready(); + status = readl(bus_xfer); + DELAY(); + val = readl(bus_xfer); + wait_ioclear(); + + pr_debug("pic32_bus_readl: *%x -> %x (status=%x)\n", reg, val, status); + + spin_unlock_irqrestore(&pic32_bus_lock, flags); + + return val; +} + +void pic32_bus_writel(u32 val, u32 reg) +{ + unsigned long flags; + u32 status; + + spin_lock_irqsave(&pic32_bus_lock, flags); + + check_ioclear(); + + writel((PIC32_WR << 24) | (reg & 0x00ffffff), bus_xfer); + DELAY(); + writel(val, bus_xfer); + DELAY(); + wait_ioready(); + status = readl(bus_xfer); + wait_ioclear(); + + pr_debug("pic32_bus_writel: *%x <- %x (status=%x)\n", reg, val, status); + + spin_unlock_irqrestore(&pic32_bus_lock, flags); +} |