]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/avr32/mach-at32ap/pio.c
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/sam/kbuild...
[linux-2.6-omap-h63xx.git] / arch / avr32 / mach-at32ap / pio.c
index 405ee6bad4ce59dd888448b100daba698cf12b0c..ed81a8bcb22d44ffa733beed2b43119caca29036 100644 (file)
@@ -50,35 +50,48 @@ static struct pio_device *gpio_to_pio(unsigned int gpio)
 }
 
 /* Pin multiplexing API */
+static DEFINE_SPINLOCK(pio_lock);
 
-void __init at32_select_periph(unsigned int pin, unsigned int periph,
-                              unsigned long flags)
+void __init at32_select_periph(unsigned int port, u32 pin_mask,
+                              unsigned int periph, unsigned long flags)
 {
        struct pio_device *pio;
-       unsigned int pin_index = pin & 0x1f;
-       u32 mask = 1 << pin_index;
 
-       pio = gpio_to_pio(pin);
+       /* assign and verify pio */
+       pio = gpio_to_pio(port);
        if (unlikely(!pio)) {
-               printk("pio: invalid pin %u\n", pin);
+               printk(KERN_WARNING "pio: invalid port %u\n", port);
                goto fail;
        }
 
-       if (unlikely(test_and_set_bit(pin_index, &pio->pinmux_mask)
-                        || gpiochip_is_requested(&pio->chip, pin_index))) {
-               printk("%s: pin %u is busy\n", pio->name, pin_index);
+       /* 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_writel(pio, PUER, mask);
+       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, mask);
+               pio_writel(pio, BSR, pin_mask);
        else
-               pio_writel(pio, ASR, mask);
+               pio_writel(pio, ASR, pin_mask);
+
+       /* enable peripheral control */
+       pio_writel(pio, PDR, pin_mask);
 
-       pio_writel(pio, PDR, mask);
+       /* Disable pull ups if not requested. */
        if (!(flags & AT32_GPIOF_PULLUP))
-               pio_writel(pio, PUDR, mask);
+               pio_writel(pio, PUDR, pin_mask);
+
+       spin_unlock(&pio_lock);
 
        return;
 
@@ -134,6 +147,25 @@ fail:
        dump_stack();
 }
 
+/*
+ * Undo a previous pin reservation. Will not affect the hardware
+ * configuration.
+ */
+void at32_deselect_pin(unsigned int pin)
+{
+       struct pio_device *pio;
+       unsigned int pin_index = pin & 0x1f;
+
+       pio = gpio_to_pio(pin);
+       if (unlikely(!pio)) {
+               printk("pio: invalid pin %u\n", pin);
+               dump_stack();
+               return;
+       }
+
+       clear_bit(pin_index, &pio->pinmux_mask);
+}
+
 /* Reserve a pin, preventing anyone else from changing its configuration. */
 void __init at32_reserve_pin(unsigned int pin)
 {
@@ -382,7 +414,6 @@ static int __init pio_probe(struct platform_device *pdev)
 }
 
 static struct platform_driver pio_driver = {
-       .probe          = pio_probe,
        .driver         = {
                .name           = "pio",
        },
@@ -390,7 +421,7 @@ static struct platform_driver pio_driver = {
 
 static int __init pio_init(void)
 {
-       return platform_driver_register(&pio_driver);
+       return platform_driver_probe(&pio_driver, pio_probe);
 }
 postcore_initcall(pio_init);