diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2012-09-28 16:29:55 +0200 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2012-09-28 16:29:55 +0200 |
commit | cb418b34caddc970c1513e515aaa535246a4bba3 (patch) | |
tree | b89720b74d6a85a9407f03bb064248c7235b9dea /arch/mips/mti-sead3/sead3-pic32-bus.c | |
parent | 77a0d763c461da81c2a3fc9a7e58162a40854a1a (diff) | |
parent | ff401e52100dcdc85e572d1ad376d3307b3fe28e (diff) |
Merge branch 'ralf-3.7' of git://git.linux-mips.org/pub/scm/sjhill/linux-sjhill into mips-for-linux-next
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 000000000000..9f0d89bc800e --- /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); +} |