|
@@ -0,0 +1,110 @@
|
|
|
+/*
|
|
|
+ * Atmel PIO2 Port Multiplexer support
|
|
|
+ *
|
|
|
+ * Copyright (C) 2004-2006 Atmel Corporation
|
|
|
+ *
|
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
|
+ * it under the terms of the GNU General Public License version 2 as
|
|
|
+ * published by the Free Software Foundation.
|
|
|
+ */
|
|
|
+
|
|
|
+#include <linux/clk.h>
|
|
|
+#include <linux/debugfs.h>
|
|
|
+#include <linux/export.h>
|
|
|
+#include <linux/fs.h>
|
|
|
+#include <linux/platform_device.h>
|
|
|
+#include <linux/irq.h>
|
|
|
+
|
|
|
+#include <asm/gpio.h>
|
|
|
+#include <asm/io.h>
|
|
|
+
|
|
|
+#include <mach/portmux.h>
|
|
|
+
|
|
|
+#include "pio.h"
|
|
|
+
|
|
|
+#define MAX_NR_PIO_DEVICES 8
|
|
|
+
|
|
|
+struct pio_device {
|
|
|
+ struct gpio_chip chip;
|
|
|
+ void __iomem *regs;
|
|
|
+ const struct platform_device *pdev;
|
|
|
+ struct clk *clk;
|
|
|
+ u32 pinmux_mask;
|
|
|
+ char name[8];
|
|
|
+};
|
|
|
+
|
|
|
+static struct pio_device pio_dev[MAX_NR_PIO_DEVICES];
|
|
|
+
|
|
|
+static struct pio_device *gpio_to_pio(unsigned int gpio)
|
|
|
+{
|
|
|
+ struct pio_device *pio;
|
|
|
+ unsigned int index;
|
|
|
+
|
|
|
+ index = gpio >> 5;
|
|
|
+ if (index >= MAX_NR_PIO_DEVICES)
|
|
|
+ return NULL;
|
|
|
+ pio = &pio_dev[index];
|
|
|
+ if (!pio->regs)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ return pio;
|
|
|
+}
|
|
|
+
|
|
|
+/* Pin multiplexing API */
|
|
|
+static DEFINE_SPINLOCK(pio_lock);
|
|
|
+
|
|
|
+void __init at32_select_periph(unsigned int port, u32 pin_mask,
|
|
|
+ unsigned int periph, unsigned long flags)
|
|
|
+{
|
|
|
+ struct pio_device *pio;
|
|
|
+
|
|
|
+ /* assign and verify pio */
|
|
|
+ pio = gpio_to_pio(port);
|
|
|
+ if (unlikely(!pio)) {
|
|
|
+ printk(KERN_WARNING "pio: invalid port %u\n", port);
|
|
|
+ goto fail;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Test if any of the requested pins is already muxed */
|
|
|
+ spin_lock(&pio_lock);
|
|
|
+ if (unlikely(pio->pinmux_mask & pin_mask)) {
|
|
|
+ printk(KERN_WARNING "%s: pin(s) busy (requested 0x%x, busy 0x%x)\n",
|
|
|
+ pio->name, pin_mask, pio->pinmux_mask & pin_mask);
|
|
|
+ spin_unlock(&pio_lock);
|
|
|
+ goto fail;
|
|
|
+ }
|
|
|
+
|
|
|
+ pio->pinmux_mask |= pin_mask;
|
|
|
+
|
|
|
+ /* enable pull ups */
|
|
|
+ pio_writel(pio, PUER, pin_mask);
|
|
|
+
|
|
|
+ /* select either peripheral A or B */
|
|
|
+ if (periph)
|
|
|
+ pio_writel(pio, BSR, pin_mask);
|
|
|
+ else
|
|
|
+ pio_writel(pio, ASR, pin_mask);
|
|
|
+
|
|
|
+ /* enable peripheral control */
|
|
|
+ pio_writel(pio, PDR, pin_mask);
|
|
|
+
|
|
|
+ /* Disable pull ups if not requested. */
|
|
|
+ if (!(flags & AT32_GPIOF_PULLUP))
|
|
|
+ pio_writel(pio, PUDR, pin_mask);
|
|
|
+
|
|
|
+ spin_unlock(&pio_lock);
|
|
|
+
|
|
|
+ return;
|
|
|
+
|
|
|
+fail:
|
|
|
+ dump_stack();
|
|
|
+}
|
|
|
+
|
|
|
+void __init at32_select_gpio(unsigned int pin, unsigned long flags)
|
|
|
+{
|
|
|
+ struct pio_device *pio;
|
|
|
+ unsigned int pin_index = pin & 0x1f;
|
|
|
+ u32 mask = 1 << pin_index;
|
|
|
+
|
|
|
+ pio = gpio_to_pio(pin);
|
|
|
+ if (unlikely(!pio)) {
|