Path: blob/master/arch/cris/arch-v32/mach-fs/pinmux.c
15125 views
/*1* Allocator for I/O pins. All pins are allocated to GPIO at bootup.2* Unassigned pins and GPIO pins can be allocated to a fixed interface3* or the I/O processor instead.4*5* Copyright (c) 2004-2007 Axis Communications AB.6*/78#include <linux/init.h>9#include <linux/errno.h>10#include <linux/kernel.h>11#include <linux/string.h>12#include <linux/spinlock.h>13#include <hwregs/reg_map.h>14#include <hwregs/reg_rdwr.h>15#include <pinmux.h>16#include <hwregs/pinmux_defs.h>1718#undef DEBUG1920#define PORT_PINS 1821#define PORTS 42223static char pins[PORTS][PORT_PINS];24static DEFINE_SPINLOCK(pinmux_lock);2526static void crisv32_pinmux_set(int port);2728int crisv32_pinmux_init(void)29{30static int initialized;3132if (!initialized) {33reg_pinmux_rw_pa pa = REG_RD(pinmux, regi_pinmux, rw_pa);34initialized = 1;35REG_WR_INT(pinmux, regi_pinmux, rw_hwprot, 0);36pa.pa0 = pa.pa1 = pa.pa2 = pa.pa3 =37pa.pa4 = pa.pa5 = pa.pa6 = pa.pa7 = regk_pinmux_yes;38REG_WR(pinmux, regi_pinmux, rw_pa, pa);39crisv32_pinmux_alloc(PORT_B, 0, PORT_PINS - 1, pinmux_gpio);40crisv32_pinmux_alloc(PORT_C, 0, PORT_PINS - 1, pinmux_gpio);41crisv32_pinmux_alloc(PORT_D, 0, PORT_PINS - 1, pinmux_gpio);42crisv32_pinmux_alloc(PORT_E, 0, PORT_PINS - 1, pinmux_gpio);43}4445return 0;46}4748int49crisv32_pinmux_alloc(int port, int first_pin, int last_pin, enum pin_mode mode)50{51int i;52unsigned long flags;5354crisv32_pinmux_init();5556if (port > PORTS || port < 0)57return -EINVAL;5859spin_lock_irqsave(&pinmux_lock, flags);6061for (i = first_pin; i <= last_pin; i++) {62if ((pins[port][i] != pinmux_none)63&& (pins[port][i] != pinmux_gpio)64&& (pins[port][i] != mode)) {65spin_unlock_irqrestore(&pinmux_lock, flags);66#ifdef DEBUG67panic("Pinmux alloc failed!\n");68#endif69return -EPERM;70}71}7273for (i = first_pin; i <= last_pin; i++)74pins[port][i] = mode;7576crisv32_pinmux_set(port);7778spin_unlock_irqrestore(&pinmux_lock, flags);7980return 0;81}8283int crisv32_pinmux_alloc_fixed(enum fixed_function function)84{85int ret = -EINVAL;86char saved[sizeof pins];87unsigned long flags;8889spin_lock_irqsave(&pinmux_lock, flags);9091/* Save internal data for recovery */92memcpy(saved, pins, sizeof pins);9394crisv32_pinmux_init(); /* Must be done before we read rw_hwprot */9596reg_pinmux_rw_hwprot hwprot = REG_RD(pinmux, regi_pinmux, rw_hwprot);9798switch (function) {99case pinmux_ser1:100ret = crisv32_pinmux_alloc(PORT_C, 4, 7, pinmux_fixed);101hwprot.ser1 = regk_pinmux_yes;102break;103case pinmux_ser2:104ret = crisv32_pinmux_alloc(PORT_C, 8, 11, pinmux_fixed);105hwprot.ser2 = regk_pinmux_yes;106break;107case pinmux_ser3:108ret = crisv32_pinmux_alloc(PORT_C, 12, 15, pinmux_fixed);109hwprot.ser3 = regk_pinmux_yes;110break;111case pinmux_sser0:112ret = crisv32_pinmux_alloc(PORT_C, 0, 3, pinmux_fixed);113ret |= crisv32_pinmux_alloc(PORT_C, 16, 16, pinmux_fixed);114hwprot.sser0 = regk_pinmux_yes;115break;116case pinmux_sser1:117ret = crisv32_pinmux_alloc(PORT_D, 0, 4, pinmux_fixed);118hwprot.sser1 = regk_pinmux_yes;119break;120case pinmux_ata0:121ret = crisv32_pinmux_alloc(PORT_D, 5, 7, pinmux_fixed);122ret |= crisv32_pinmux_alloc(PORT_D, 15, 17, pinmux_fixed);123hwprot.ata0 = regk_pinmux_yes;124break;125case pinmux_ata1:126ret = crisv32_pinmux_alloc(PORT_D, 0, 4, pinmux_fixed);127ret |= crisv32_pinmux_alloc(PORT_E, 17, 17, pinmux_fixed);128hwprot.ata1 = regk_pinmux_yes;129break;130case pinmux_ata2:131ret = crisv32_pinmux_alloc(PORT_C, 11, 15, pinmux_fixed);132ret |= crisv32_pinmux_alloc(PORT_E, 3, 3, pinmux_fixed);133hwprot.ata2 = regk_pinmux_yes;134break;135case pinmux_ata3:136ret = crisv32_pinmux_alloc(PORT_C, 8, 10, pinmux_fixed);137ret |= crisv32_pinmux_alloc(PORT_C, 0, 2, pinmux_fixed);138hwprot.ata2 = regk_pinmux_yes;139break;140case pinmux_ata:141ret = crisv32_pinmux_alloc(PORT_B, 0, 15, pinmux_fixed);142ret |= crisv32_pinmux_alloc(PORT_D, 8, 15, pinmux_fixed);143hwprot.ata = regk_pinmux_yes;144break;145case pinmux_eth1:146ret = crisv32_pinmux_alloc(PORT_E, 0, 17, pinmux_fixed);147hwprot.eth1 = regk_pinmux_yes;148hwprot.eth1_mgm = regk_pinmux_yes;149break;150case pinmux_timer:151ret = crisv32_pinmux_alloc(PORT_C, 16, 16, pinmux_fixed);152hwprot.timer = regk_pinmux_yes;153spin_unlock_irqrestore(&pinmux_lock, flags);154return ret;155}156157if (!ret)158REG_WR(pinmux, regi_pinmux, rw_hwprot, hwprot);159else160memcpy(pins, saved, sizeof pins);161162spin_unlock_irqrestore(&pinmux_lock, flags);163164return ret;165}166167void crisv32_pinmux_set(int port)168{169int i;170int gpio_val = 0;171int iop_val = 0;172173for (i = 0; i < PORT_PINS; i++) {174if (pins[port][i] == pinmux_gpio)175gpio_val |= (1 << i);176else if (pins[port][i] == pinmux_iop)177iop_val |= (1 << i);178}179180REG_WRITE(int, regi_pinmux + REG_RD_ADDR_pinmux_rw_pb_gio + 8 * port,181gpio_val);182REG_WRITE(int, regi_pinmux + REG_RD_ADDR_pinmux_rw_pb_iop + 8 * port,183iop_val);184185#ifdef DEBUG186crisv32_pinmux_dump();187#endif188}189190int crisv32_pinmux_dealloc(int port, int first_pin, int last_pin)191{192int i;193unsigned long flags;194195crisv32_pinmux_init();196197if (port > PORTS || port < 0)198return -EINVAL;199200spin_lock_irqsave(&pinmux_lock, flags);201202for (i = first_pin; i <= last_pin; i++)203pins[port][i] = pinmux_none;204205crisv32_pinmux_set(port);206spin_unlock_irqrestore(&pinmux_lock, flags);207208return 0;209}210211int crisv32_pinmux_dealloc_fixed(enum fixed_function function)212{213int ret = -EINVAL;214char saved[sizeof pins];215unsigned long flags;216217spin_lock_irqsave(&pinmux_lock, flags);218219/* Save internal data for recovery */220memcpy(saved, pins, sizeof pins);221222crisv32_pinmux_init(); /* Must be done before we read rw_hwprot */223224reg_pinmux_rw_hwprot hwprot = REG_RD(pinmux, regi_pinmux, rw_hwprot);225226switch (function) {227case pinmux_ser1:228ret = crisv32_pinmux_dealloc(PORT_C, 4, 7);229hwprot.ser1 = regk_pinmux_no;230break;231case pinmux_ser2:232ret = crisv32_pinmux_dealloc(PORT_C, 8, 11);233hwprot.ser2 = regk_pinmux_no;234break;235case pinmux_ser3:236ret = crisv32_pinmux_dealloc(PORT_C, 12, 15);237hwprot.ser3 = regk_pinmux_no;238break;239case pinmux_sser0:240ret = crisv32_pinmux_dealloc(PORT_C, 0, 3);241ret |= crisv32_pinmux_dealloc(PORT_C, 16, 16);242hwprot.sser0 = regk_pinmux_no;243break;244case pinmux_sser1:245ret = crisv32_pinmux_dealloc(PORT_D, 0, 4);246hwprot.sser1 = regk_pinmux_no;247break;248case pinmux_ata0:249ret = crisv32_pinmux_dealloc(PORT_D, 5, 7);250ret |= crisv32_pinmux_dealloc(PORT_D, 15, 17);251hwprot.ata0 = regk_pinmux_no;252break;253case pinmux_ata1:254ret = crisv32_pinmux_dealloc(PORT_D, 0, 4);255ret |= crisv32_pinmux_dealloc(PORT_E, 17, 17);256hwprot.ata1 = regk_pinmux_no;257break;258case pinmux_ata2:259ret = crisv32_pinmux_dealloc(PORT_C, 11, 15);260ret |= crisv32_pinmux_dealloc(PORT_E, 3, 3);261hwprot.ata2 = regk_pinmux_no;262break;263case pinmux_ata3:264ret = crisv32_pinmux_dealloc(PORT_C, 8, 10);265ret |= crisv32_pinmux_dealloc(PORT_C, 0, 2);266hwprot.ata2 = regk_pinmux_no;267break;268case pinmux_ata:269ret = crisv32_pinmux_dealloc(PORT_B, 0, 15);270ret |= crisv32_pinmux_dealloc(PORT_D, 8, 15);271hwprot.ata = regk_pinmux_no;272break;273case pinmux_eth1:274ret = crisv32_pinmux_dealloc(PORT_E, 0, 17);275hwprot.eth1 = regk_pinmux_no;276hwprot.eth1_mgm = regk_pinmux_no;277break;278case pinmux_timer:279ret = crisv32_pinmux_dealloc(PORT_C, 16, 16);280hwprot.timer = regk_pinmux_no;281spin_unlock_irqrestore(&pinmux_lock, flags);282return ret;283}284285if (!ret)286REG_WR(pinmux, regi_pinmux, rw_hwprot, hwprot);287else288memcpy(pins, saved, sizeof pins);289290spin_unlock_irqrestore(&pinmux_lock, flags);291292return ret;293}294295void crisv32_pinmux_dump(void)296{297int i, j;298299crisv32_pinmux_init();300301for (i = 0; i < PORTS; i++) {302printk(KERN_DEBUG "Port %c\n", 'B' + i);303for (j = 0; j < PORT_PINS; j++)304printk(KERN_DEBUG " Pin %d = %d\n", j, pins[i][j]);305}306}307308__initcall(crisv32_pinmux_init);309310311