linux/arch/cris/arch-v32/kernel/pinmux.c
<<
>>
Prefs
   1/*
   2 * Allocator for I/O pins. All pins are allocated to GPIO at bootup.
   3 * Unassigned pins and GPIO pins can be allocated to a fixed interface
   4 * or the I/O processor instead.
   5 *
   6 * Copyright (c) 2004 Axis Communications AB.
   7 */
   8
   9#include <linux/init.h>
  10#include <linux/errno.h>
  11#include <linux/kernel.h>
  12#include <linux/string.h>
  13#include <linux/spinlock.h>
  14#include <arch/hwregs/reg_map.h>
  15#include <arch/hwregs/reg_rdwr.h>
  16#include <arch/pinmux.h>
  17#include <arch/hwregs/pinmux_defs.h>
  18
  19#undef DEBUG
  20
  21#define PORT_PINS 18
  22#define PORTS 4
  23
  24static char pins[PORTS][PORT_PINS];
  25static DEFINE_SPINLOCK(pinmux_lock);
  26
  27static void crisv32_pinmux_set(int port);
  28
  29int
  30crisv32_pinmux_init(void)
  31{
  32        static int initialized = 0;
  33
  34        if (!initialized) {
  35                reg_pinmux_rw_pa pa = REG_RD(pinmux, regi_pinmux, rw_pa);
  36                initialized = 1;
  37                pa.pa0 = pa.pa1 = pa.pa2 = pa.pa3 =
  38                pa.pa4 = pa.pa5 = pa.pa6 = pa.pa7 = regk_pinmux_yes;
  39                REG_WR(pinmux, regi_pinmux, rw_pa, pa);
  40                crisv32_pinmux_alloc(PORT_B, 0, PORT_PINS - 1, pinmux_gpio);
  41                crisv32_pinmux_alloc(PORT_C, 0, PORT_PINS - 1, pinmux_gpio);
  42                crisv32_pinmux_alloc(PORT_D, 0, PORT_PINS - 1, pinmux_gpio);
  43                crisv32_pinmux_alloc(PORT_E, 0, PORT_PINS - 1, pinmux_gpio);
  44        }
  45
  46        return 0;
  47}
  48
  49int
  50crisv32_pinmux_alloc(int port, int first_pin, int last_pin, enum pin_mode mode)
  51{
  52        int i;
  53        unsigned long flags;
  54
  55        crisv32_pinmux_init();
  56
  57        if (port > PORTS)
  58                return -EINVAL;
  59
  60        spin_lock_irqsave(&pinmux_lock, flags);
  61
  62        for (i = first_pin; i <= last_pin; i++)
  63        {
  64                if ((pins[port][i] != pinmux_none) && (pins[port][i] != pinmux_gpio) &&
  65                    (pins[port][i] != mode))
  66                {
  67                        spin_unlock_irqrestore(&pinmux_lock, flags);
  68#ifdef DEBUG
  69                        panic("Pinmux alloc failed!\n");
  70#endif
  71                        return -EPERM;
  72                }
  73        }
  74
  75        for (i = first_pin; i <= last_pin; i++)
  76                pins[port][i] = mode;
  77
  78        crisv32_pinmux_set(port);
  79
  80        spin_unlock_irqrestore(&pinmux_lock, flags);
  81
  82        return 0;
  83}
  84
  85int
  86crisv32_pinmux_alloc_fixed(enum fixed_function function)
  87{
  88        int ret = -EINVAL;
  89        char saved[sizeof pins];
  90        unsigned long flags;
  91
  92        spin_lock_irqsave(&pinmux_lock, flags);
  93
  94        /* Save internal data for recovery */
  95        memcpy(saved, pins, sizeof pins);
  96
  97        reg_pinmux_rw_hwprot hwprot = REG_RD(pinmux, regi_pinmux, rw_hwprot);
  98
  99        switch(function)
 100        {
 101        case pinmux_ser1:
 102                ret = crisv32_pinmux_alloc(PORT_C, 4, 7, pinmux_fixed);
 103                hwprot.ser1 = regk_pinmux_yes;
 104                break;
 105        case pinmux_ser2:
 106                ret = crisv32_pinmux_alloc(PORT_C, 8, 11, pinmux_fixed);
 107                hwprot.ser2 = regk_pinmux_yes;
 108                break;
 109        case pinmux_ser3:
 110                ret = crisv32_pinmux_alloc(PORT_C, 12, 15, pinmux_fixed);
 111                hwprot.ser3 = regk_pinmux_yes;
 112                break;
 113        case pinmux_sser0:
 114                ret = crisv32_pinmux_alloc(PORT_C, 0, 3, pinmux_fixed);
 115                ret |= crisv32_pinmux_alloc(PORT_C, 16, 16, pinmux_fixed);
 116                hwprot.sser0 = regk_pinmux_yes;
 117                break;
 118        case pinmux_sser1:
 119                ret = crisv32_pinmux_alloc(PORT_D, 0, 4, pinmux_fixed);
 120                hwprot.sser1 = regk_pinmux_yes;
 121                break;
 122        case pinmux_ata0:
 123                ret = crisv32_pinmux_alloc(PORT_D, 5, 7, pinmux_fixed);
 124                ret |= crisv32_pinmux_alloc(PORT_D, 15, 17, pinmux_fixed);
 125                hwprot.ata0 = regk_pinmux_yes;
 126                break;
 127        case pinmux_ata1:
 128                ret = crisv32_pinmux_alloc(PORT_D, 0, 4, pinmux_fixed);
 129                ret |= crisv32_pinmux_alloc(PORT_E, 17, 17, pinmux_fixed);
 130                hwprot.ata1 = regk_pinmux_yes;
 131                break;
 132        case pinmux_ata2:
 133                ret = crisv32_pinmux_alloc(PORT_C, 11, 15, pinmux_fixed);
 134                ret |= crisv32_pinmux_alloc(PORT_E, 3, 3, pinmux_fixed);
 135                hwprot.ata2 = regk_pinmux_yes;
 136                break;
 137        case pinmux_ata3:
 138                ret = crisv32_pinmux_alloc(PORT_C, 8, 10, pinmux_fixed);
 139                ret |= crisv32_pinmux_alloc(PORT_C, 0, 2, pinmux_fixed);
 140                hwprot.ata2 = regk_pinmux_yes;
 141                break;
 142        case pinmux_ata:
 143                ret = crisv32_pinmux_alloc(PORT_B, 0, 15, pinmux_fixed);
 144                ret |= crisv32_pinmux_alloc(PORT_D, 8, 15, pinmux_fixed);
 145                hwprot.ata = regk_pinmux_yes;
 146                break;
 147        case pinmux_eth1:
 148                ret = crisv32_pinmux_alloc(PORT_E, 0, 17, pinmux_fixed);
 149                hwprot.eth1 = regk_pinmux_yes;
 150                hwprot.eth1_mgm = regk_pinmux_yes;
 151                break;
 152        case pinmux_timer:
 153                ret = crisv32_pinmux_alloc(PORT_C, 16, 16, pinmux_fixed);
 154                hwprot.timer = regk_pinmux_yes;
 155                spin_unlock_irqrestore(&pinmux_lock, flags);
 156                return ret;
 157        }
 158
 159        if (!ret)
 160                REG_WR(pinmux, regi_pinmux, rw_hwprot, hwprot);
 161        else
 162                memcpy(pins, saved, sizeof pins);
 163
 164  spin_unlock_irqrestore(&pinmux_lock, flags);
 165
 166  return ret;
 167}
 168
 169void
 170crisv32_pinmux_set(int port)
 171{
 172        int i;
 173        int gpio_val = 0;
 174        int iop_val = 0;
 175
 176        for (i = 0; i < PORT_PINS; i++)
 177        {
 178                if (pins[port][i] == pinmux_gpio)
 179                        gpio_val |= (1 << i);
 180                else if (pins[port][i] == pinmux_iop)
 181                        iop_val |= (1 << i);
 182        }
 183
 184        REG_WRITE(int, regi_pinmux + REG_RD_ADDR_pinmux_rw_pb_gio + 8*port, gpio_val);
 185        REG_WRITE(int, regi_pinmux + REG_RD_ADDR_pinmux_rw_pb_iop + 8*port, iop_val);
 186
 187#ifdef DEBUG
 188       crisv32_pinmux_dump();
 189#endif
 190}
 191
 192int
 193crisv32_pinmux_dealloc(int port, int first_pin, int last_pin)
 194{
 195        int i;
 196        unsigned long flags;
 197
 198        crisv32_pinmux_init();
 199
 200        if (port > PORTS)
 201                return -EINVAL;
 202
 203        spin_lock_irqsave(&pinmux_lock, flags);
 204
 205        for (i = first_pin; i <= last_pin; i++)
 206                pins[port][i] = pinmux_none;
 207
 208        crisv32_pinmux_set(port);
 209        spin_unlock_irqrestore(&pinmux_lock, flags);
 210
 211        return 0;
 212}
 213
 214void
 215crisv32_pinmux_dump(void)
 216{
 217        int i, j;
 218
 219        crisv32_pinmux_init();
 220
 221        for (i = 0; i < PORTS; i++)
 222        {
 223                printk("Port %c\n", 'B'+i);
 224                for (j = 0; j < PORT_PINS; j++)
 225                        printk("  Pin %d = %d\n", j, pins[i][j]);
 226        }
 227}
 228
 229__initcall(crisv32_pinmux_init);
 230