Path: blob/master/arch/cris/arch-v10/drivers/gpio.c
15126 views
/*1* Etrax general port I/O device2*3* Copyright (c) 1999-2007 Axis Communications AB4*5* Authors: Bjorn Wesen (initial version)6* Ola Knutsson (LED handling)7* Johan Adolfsson (read/set directions, write, port G)8*/91011#include <linux/module.h>12#include <linux/sched.h>13#include <linux/slab.h>14#include <linux/ioport.h>15#include <linux/errno.h>16#include <linux/kernel.h>17#include <linux/fs.h>18#include <linux/string.h>19#include <linux/poll.h>20#include <linux/init.h>21#include <linux/interrupt.h>2223#include <asm/etraxgpio.h>24#include <arch/svinto.h>25#include <asm/io.h>26#include <asm/system.h>27#include <asm/irq.h>28#include <arch/io_interface_mux.h>2930#define GPIO_MAJOR 120 /* experimental MAJOR number */3132#define D(x)3334#if 035static int dp_cnt;36#define DP(x) do { dp_cnt++; if (dp_cnt % 1000 == 0) x; }while(0)37#else38#define DP(x)39#endif4041static char gpio_name[] = "etrax gpio";4243#if 044static wait_queue_head_t *gpio_wq;45#endif4647static long gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg);48static ssize_t gpio_write(struct file *file, const char __user *buf,49size_t count, loff_t *off);50static int gpio_open(struct inode *inode, struct file *filp);51static int gpio_release(struct inode *inode, struct file *filp);52static unsigned int gpio_poll(struct file *filp, struct poll_table_struct *wait);5354/* private data per open() of this driver */5556struct gpio_private {57struct gpio_private *next;58/* These fields are for PA and PB only */59volatile unsigned char *port, *shadow;60volatile unsigned char *dir, *dir_shadow;61unsigned char changeable_dir;62unsigned char changeable_bits;63unsigned char clk_mask;64unsigned char data_mask;65unsigned char write_msb;66unsigned char pad1, pad2, pad3;67/* These fields are generic */68unsigned long highalarm, lowalarm;69wait_queue_head_t alarm_wq;70int minor;71};7273/* linked list of alarms to check for */7475static struct gpio_private *alarmlist;7677static int gpio_some_alarms; /* Set if someone uses alarm */78static unsigned long gpio_pa_irq_enabled_mask;7980static DEFINE_SPINLOCK(gpio_lock); /* Protect directions etc */8182/* Port A and B use 8 bit access, but Port G is 32 bit */83#define NUM_PORTS (GPIO_MINOR_B+1)8485static volatile unsigned char *ports[NUM_PORTS] = {86R_PORT_PA_DATA,87R_PORT_PB_DATA,88};89static volatile unsigned char *shads[NUM_PORTS] = {90&port_pa_data_shadow,91&port_pb_data_shadow92};9394/* What direction bits that are user changeable 1=changeable*/95#ifndef CONFIG_ETRAX_PA_CHANGEABLE_DIR96#define CONFIG_ETRAX_PA_CHANGEABLE_DIR 0x0097#endif98#ifndef CONFIG_ETRAX_PB_CHANGEABLE_DIR99#define CONFIG_ETRAX_PB_CHANGEABLE_DIR 0x00100#endif101102#ifndef CONFIG_ETRAX_PA_CHANGEABLE_BITS103#define CONFIG_ETRAX_PA_CHANGEABLE_BITS 0xFF104#endif105#ifndef CONFIG_ETRAX_PB_CHANGEABLE_BITS106#define CONFIG_ETRAX_PB_CHANGEABLE_BITS 0xFF107#endif108109110static unsigned char changeable_dir[NUM_PORTS] = {111CONFIG_ETRAX_PA_CHANGEABLE_DIR,112CONFIG_ETRAX_PB_CHANGEABLE_DIR113};114static unsigned char changeable_bits[NUM_PORTS] = {115CONFIG_ETRAX_PA_CHANGEABLE_BITS,116CONFIG_ETRAX_PB_CHANGEABLE_BITS117};118119static volatile unsigned char *dir[NUM_PORTS] = {120R_PORT_PA_DIR,121R_PORT_PB_DIR122};123124static volatile unsigned char *dir_shadow[NUM_PORTS] = {125&port_pa_dir_shadow,126&port_pb_dir_shadow127};128129/* All bits in port g that can change dir. */130static const unsigned long int changeable_dir_g_mask = 0x01FFFF01;131132/* Port G is 32 bit, handle it special, some bits are both inputs133and outputs at the same time, only some of the bits can change direction134and some of them in groups of 8 bit. */135static unsigned long changeable_dir_g;136static unsigned long dir_g_in_bits;137static unsigned long dir_g_out_bits;138static unsigned long dir_g_shadow; /* 1=output */139140#define USE_PORTS(priv) ((priv)->minor <= GPIO_MINOR_B)141142143static unsigned int gpio_poll(struct file *file, poll_table *wait)144{145unsigned int mask = 0;146struct gpio_private *priv = file->private_data;147unsigned long data;148unsigned long flags;149150spin_lock_irqsave(&gpio_lock, flags);151152poll_wait(file, &priv->alarm_wq, wait);153if (priv->minor == GPIO_MINOR_A) {154unsigned long tmp;155data = *R_PORT_PA_DATA;156/* PA has support for high level interrupt -157* lets activate for those low and with highalarm set158*/159tmp = ~data & priv->highalarm & 0xFF;160tmp = (tmp << R_IRQ_MASK1_SET__pa0__BITNR);161162gpio_pa_irq_enabled_mask |= tmp;163*R_IRQ_MASK1_SET = tmp;164} else if (priv->minor == GPIO_MINOR_B)165data = *R_PORT_PB_DATA;166else if (priv->minor == GPIO_MINOR_G)167data = *R_PORT_G_DATA;168else {169mask = 0;170goto out;171}172173if ((data & priv->highalarm) ||174(~data & priv->lowalarm)) {175mask = POLLIN|POLLRDNORM;176}177178out:179spin_unlock_irqrestore(&gpio_lock, flags);180DP(printk("gpio_poll ready: mask 0x%08X\n", mask));181182return mask;183}184185int etrax_gpio_wake_up_check(void)186{187struct gpio_private *priv;188unsigned long data = 0;189int ret = 0;190unsigned long flags;191192spin_lock_irqsave(&gpio_lock, flags);193priv = alarmlist;194while (priv) {195if (USE_PORTS(priv))196data = *priv->port;197else if (priv->minor == GPIO_MINOR_G)198data = *R_PORT_G_DATA;199200if ((data & priv->highalarm) ||201(~data & priv->lowalarm)) {202DP(printk("etrax_gpio_wake_up_check %i\n",priv->minor));203wake_up_interruptible(&priv->alarm_wq);204ret = 1;205}206priv = priv->next;207}208spin_unlock_irqrestore(&gpio_lock, flags);209return ret;210}211212static irqreturn_t213gpio_poll_timer_interrupt(int irq, void *dev_id)214{215if (gpio_some_alarms) {216etrax_gpio_wake_up_check();217return IRQ_HANDLED;218}219return IRQ_NONE;220}221222static irqreturn_t223gpio_interrupt(int irq, void *dev_id)224{225unsigned long tmp;226unsigned long flags;227228spin_lock_irqsave(&gpio_lock, flags);229230/* Find what PA interrupts are active */231tmp = (*R_IRQ_READ1);232233/* Find those that we have enabled */234tmp &= gpio_pa_irq_enabled_mask;235236/* Clear them.. */237*R_IRQ_MASK1_CLR = tmp;238gpio_pa_irq_enabled_mask &= ~tmp;239240spin_unlock_irqrestore(&gpio_lock, flags);241242if (gpio_some_alarms)243return IRQ_RETVAL(etrax_gpio_wake_up_check());244245return IRQ_NONE;246}247248static void gpio_write_bit(struct gpio_private *priv,249unsigned char data, int bit)250{251*priv->port = *priv->shadow &= ~(priv->clk_mask);252if (data & 1 << bit)253*priv->port = *priv->shadow |= priv->data_mask;254else255*priv->port = *priv->shadow &= ~(priv->data_mask);256257/* For FPGA: min 5.0ns (DCC) before CCLK high */258*priv->port = *priv->shadow |= priv->clk_mask;259}260261static void gpio_write_byte(struct gpio_private *priv, unsigned char data)262{263int i;264265if (priv->write_msb)266for (i = 7; i >= 0; i--)267gpio_write_bit(priv, data, i);268else269for (i = 0; i <= 7; i++)270gpio_write_bit(priv, data, i);271}272273static ssize_t gpio_write(struct file *file, const char __user *buf,274size_t count, loff_t *off)275{276struct gpio_private *priv = file->private_data;277unsigned long flags;278ssize_t retval = count;279280if (priv->minor != GPIO_MINOR_A && priv->minor != GPIO_MINOR_B)281return -EFAULT;282283if (!access_ok(VERIFY_READ, buf, count))284return -EFAULT;285286spin_lock_irqsave(&gpio_lock, flags);287288/* It must have been configured using the IO_CFG_WRITE_MODE */289/* Perhaps a better error code? */290if (priv->clk_mask == 0 || priv->data_mask == 0) {291retval = -EPERM;292goto out;293}294295D(printk(KERN_DEBUG "gpio_write: %02X to data 0x%02X "296"clk 0x%02X msb: %i\n",297count, priv->data_mask, priv->clk_mask, priv->write_msb));298299while (count--)300gpio_write_byte(priv, *buf++);301302out:303spin_unlock_irqrestore(&gpio_lock, flags);304return retval;305}306307308309static int310gpio_open(struct inode *inode, struct file *filp)311{312struct gpio_private *priv;313int p = iminor(inode);314unsigned long flags;315316if (p > GPIO_MINOR_LAST)317return -EINVAL;318319priv = kzalloc(sizeof(struct gpio_private), GFP_KERNEL);320321if (!priv)322return -ENOMEM;323324priv->minor = p;325326/* initialize the io/alarm struct */327328if (USE_PORTS(priv)) { /* A and B */329priv->port = ports[p];330priv->shadow = shads[p];331priv->dir = dir[p];332priv->dir_shadow = dir_shadow[p];333priv->changeable_dir = changeable_dir[p];334priv->changeable_bits = changeable_bits[p];335} else {336priv->port = NULL;337priv->shadow = NULL;338priv->dir = NULL;339priv->dir_shadow = NULL;340priv->changeable_dir = 0;341priv->changeable_bits = 0;342}343344priv->highalarm = 0;345priv->lowalarm = 0;346priv->clk_mask = 0;347priv->data_mask = 0;348init_waitqueue_head(&priv->alarm_wq);349350filp->private_data = priv;351352/* link it into our alarmlist */353spin_lock_irqsave(&gpio_lock, flags);354priv->next = alarmlist;355alarmlist = priv;356spin_unlock_irqrestore(&gpio_lock, flags);357358return 0;359}360361static int362gpio_release(struct inode *inode, struct file *filp)363{364struct gpio_private *p;365struct gpio_private *todel;366unsigned long flags;367368spin_lock_irqsave(&gpio_lock, flags);369370p = alarmlist;371todel = filp->private_data;372373/* unlink from alarmlist and free the private structure */374375if (p == todel) {376alarmlist = todel->next;377} else {378while (p->next != todel)379p = p->next;380p->next = todel->next;381}382383kfree(todel);384/* Check if there are still any alarms set */385p = alarmlist;386while (p) {387if (p->highalarm | p->lowalarm) {388gpio_some_alarms = 1;389goto out;390}391p = p->next;392}393gpio_some_alarms = 0;394out:395spin_unlock_irqrestore(&gpio_lock, flags);396return 0;397}398399/* Main device API. ioctl's to read/set/clear bits, as well as to400* set alarms to wait for using a subsequent select().401*/402unsigned long inline setget_input(struct gpio_private *priv, unsigned long arg)403{404/* Set direction 0=unchanged 1=input,405* return mask with 1=input */406if (USE_PORTS(priv)) {407*priv->dir = *priv->dir_shadow &=408~((unsigned char)arg & priv->changeable_dir);409return ~(*priv->dir_shadow) & 0xFF; /* Only 8 bits */410}411412if (priv->minor != GPIO_MINOR_G)413return 0;414415/* We must fiddle with R_GEN_CONFIG to change dir */416if (((arg & dir_g_in_bits) != arg) &&417(arg & changeable_dir_g)) {418arg &= changeable_dir_g;419/* Clear bits in genconfig to set to input */420if (arg & (1<<0)) {421genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, g0dir);422dir_g_in_bits |= (1<<0);423dir_g_out_bits &= ~(1<<0);424}425if ((arg & 0x0000FF00) == 0x0000FF00) {426genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, g8_15dir);427dir_g_in_bits |= 0x0000FF00;428dir_g_out_bits &= ~0x0000FF00;429}430if ((arg & 0x00FF0000) == 0x00FF0000) {431genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, g16_23dir);432dir_g_in_bits |= 0x00FF0000;433dir_g_out_bits &= ~0x00FF0000;434}435if (arg & (1<<24)) {436genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, g24dir);437dir_g_in_bits |= (1<<24);438dir_g_out_bits &= ~(1<<24);439}440D(printk(KERN_DEBUG "gpio: SETINPUT on port G set "441"genconfig to 0x%08lX "442"in_bits: 0x%08lX "443"out_bits: 0x%08lX\n",444(unsigned long)genconfig_shadow,445dir_g_in_bits, dir_g_out_bits));446*R_GEN_CONFIG = genconfig_shadow;447/* Must be a >120 ns delay before writing this again */448449}450return dir_g_in_bits;451} /* setget_input */452453unsigned long inline setget_output(struct gpio_private *priv, unsigned long arg)454{455if (USE_PORTS(priv)) {456*priv->dir = *priv->dir_shadow |=457((unsigned char)arg & priv->changeable_dir);458return *priv->dir_shadow;459}460if (priv->minor != GPIO_MINOR_G)461return 0;462463/* We must fiddle with R_GEN_CONFIG to change dir */464if (((arg & dir_g_out_bits) != arg) &&465(arg & changeable_dir_g)) {466/* Set bits in genconfig to set to output */467if (arg & (1<<0)) {468genconfig_shadow |= IO_MASK(R_GEN_CONFIG, g0dir);469dir_g_out_bits |= (1<<0);470dir_g_in_bits &= ~(1<<0);471}472if ((arg & 0x0000FF00) == 0x0000FF00) {473genconfig_shadow |= IO_MASK(R_GEN_CONFIG, g8_15dir);474dir_g_out_bits |= 0x0000FF00;475dir_g_in_bits &= ~0x0000FF00;476}477if ((arg & 0x00FF0000) == 0x00FF0000) {478genconfig_shadow |= IO_MASK(R_GEN_CONFIG, g16_23dir);479dir_g_out_bits |= 0x00FF0000;480dir_g_in_bits &= ~0x00FF0000;481}482if (arg & (1<<24)) {483genconfig_shadow |= IO_MASK(R_GEN_CONFIG, g24dir);484dir_g_out_bits |= (1<<24);485dir_g_in_bits &= ~(1<<24);486}487D(printk(KERN_INFO "gpio: SETOUTPUT on port G set "488"genconfig to 0x%08lX "489"in_bits: 0x%08lX "490"out_bits: 0x%08lX\n",491(unsigned long)genconfig_shadow,492dir_g_in_bits, dir_g_out_bits));493*R_GEN_CONFIG = genconfig_shadow;494/* Must be a >120 ns delay before writing this again */495}496return dir_g_out_bits & 0x7FFFFFFF;497} /* setget_output */498499static int500gpio_leds_ioctl(unsigned int cmd, unsigned long arg);501502static long gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)503{504unsigned long flags;505unsigned long val;506int ret = 0;507508struct gpio_private *priv = file->private_data;509if (_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE)510return -EINVAL;511512switch (_IOC_NR(cmd)) {513case IO_READBITS: /* Use IO_READ_INBITS and IO_READ_OUTBITS instead */514// read the port515spin_lock_irqsave(&gpio_lock, flags);516if (USE_PORTS(priv)) {517ret = *priv->port;518} else if (priv->minor == GPIO_MINOR_G) {519ret = (*R_PORT_G_DATA) & 0x7FFFFFFF;520}521spin_unlock_irqrestore(&gpio_lock, flags);522523break;524case IO_SETBITS:525// set changeable bits with a 1 in arg526spin_lock_irqsave(&gpio_lock, flags);527528if (USE_PORTS(priv)) {529*priv->port = *priv->shadow |=530((unsigned char)arg & priv->changeable_bits);531} else if (priv->minor == GPIO_MINOR_G) {532*R_PORT_G_DATA = port_g_data_shadow |= (arg & dir_g_out_bits);533}534spin_unlock_irqrestore(&gpio_lock, flags);535536break;537case IO_CLRBITS:538// clear changeable bits with a 1 in arg539spin_lock_irqsave(&gpio_lock, flags);540if (USE_PORTS(priv)) {541*priv->port = *priv->shadow &=542~((unsigned char)arg & priv->changeable_bits);543} else if (priv->minor == GPIO_MINOR_G) {544*R_PORT_G_DATA = port_g_data_shadow &= ~((unsigned long)arg & dir_g_out_bits);545}546spin_unlock_irqrestore(&gpio_lock, flags);547break;548case IO_HIGHALARM:549// set alarm when bits with 1 in arg go high550spin_lock_irqsave(&gpio_lock, flags);551priv->highalarm |= arg;552gpio_some_alarms = 1;553spin_unlock_irqrestore(&gpio_lock, flags);554break;555case IO_LOWALARM:556// set alarm when bits with 1 in arg go low557spin_lock_irqsave(&gpio_lock, flags);558priv->lowalarm |= arg;559gpio_some_alarms = 1;560spin_unlock_irqrestore(&gpio_lock, flags);561break;562case IO_CLRALARM:563/* clear alarm for bits with 1 in arg */564spin_lock_irqsave(&gpio_lock, flags);565priv->highalarm &= ~arg;566priv->lowalarm &= ~arg;567{568/* Must update gpio_some_alarms */569struct gpio_private *p = alarmlist;570int some_alarms;571p = alarmlist;572some_alarms = 0;573while (p) {574if (p->highalarm | p->lowalarm) {575some_alarms = 1;576break;577}578p = p->next;579}580gpio_some_alarms = some_alarms;581}582spin_unlock_irqrestore(&gpio_lock, flags);583break;584case IO_READDIR: /* Use IO_SETGET_INPUT/OUTPUT instead! */585/* Read direction 0=input 1=output */586spin_lock_irqsave(&gpio_lock, flags);587if (USE_PORTS(priv)) {588ret = *priv->dir_shadow;589} else if (priv->minor == GPIO_MINOR_G) {590/* Note: Some bits are both in and out,591* Those that are dual is set here as well.592*/593ret = (dir_g_shadow | dir_g_out_bits) & 0x7FFFFFFF;594}595spin_unlock_irqrestore(&gpio_lock, flags);596break;597case IO_SETINPUT: /* Use IO_SETGET_INPUT instead! */598/* Set direction 0=unchanged 1=input,599* return mask with 1=input600*/601spin_lock_irqsave(&gpio_lock, flags);602ret = setget_input(priv, arg) & 0x7FFFFFFF;603spin_unlock_irqrestore(&gpio_lock, flags);604break;605case IO_SETOUTPUT: /* Use IO_SETGET_OUTPUT instead! */606/* Set direction 0=unchanged 1=output,607* return mask with 1=output608*/609spin_lock_irqsave(&gpio_lock, flags);610ret = setget_output(priv, arg) & 0x7FFFFFFF;611spin_unlock_irqrestore(&gpio_lock, flags);612break;613case IO_SHUTDOWN:614spin_lock_irqsave(&gpio_lock, flags);615SOFT_SHUTDOWN();616spin_unlock_irqrestore(&gpio_lock, flags);617break;618case IO_GET_PWR_BT:619spin_lock_irqsave(&gpio_lock, flags);620#if defined (CONFIG_ETRAX_SOFT_SHUTDOWN)621ret = (*R_PORT_G_DATA & ( 1 << CONFIG_ETRAX_POWERBUTTON_BIT));622#else623ret = 0;624#endif625spin_unlock_irqrestore(&gpio_lock, flags);626break;627case IO_CFG_WRITE_MODE:628spin_lock_irqsave(&gpio_lock, flags);629priv->clk_mask = arg & 0xFF;630priv->data_mask = (arg >> 8) & 0xFF;631priv->write_msb = (arg >> 16) & 0x01;632/* Check if we're allowed to change the bits and633* the direction is correct634*/635if (!((priv->clk_mask & priv->changeable_bits) &&636(priv->data_mask & priv->changeable_bits) &&637(priv->clk_mask & *priv->dir_shadow) &&638(priv->data_mask & *priv->dir_shadow)))639{640priv->clk_mask = 0;641priv->data_mask = 0;642ret = -EPERM;643}644spin_unlock_irqrestore(&gpio_lock, flags);645break;646case IO_READ_INBITS:647/* *arg is result of reading the input pins */648spin_lock_irqsave(&gpio_lock, flags);649if (USE_PORTS(priv)) {650val = *priv->port;651} else if (priv->minor == GPIO_MINOR_G) {652val = *R_PORT_G_DATA;653}654spin_unlock_irqrestore(&gpio_lock, flags);655if (copy_to_user((void __user *)arg, &val, sizeof(val)))656ret = -EFAULT;657break;658case IO_READ_OUTBITS:659/* *arg is result of reading the output shadow */660spin_lock_irqsave(&gpio_lock, flags);661if (USE_PORTS(priv)) {662val = *priv->shadow;663} else if (priv->minor == GPIO_MINOR_G) {664val = port_g_data_shadow;665}666spin_unlock_irqrestore(&gpio_lock, flags);667if (copy_to_user((void __user *)arg, &val, sizeof(val)))668ret = -EFAULT;669break;670case IO_SETGET_INPUT:671/* bits set in *arg is set to input,672* *arg updated with current input pins.673*/674if (copy_from_user(&val, (void __user *)arg, sizeof(val)))675{676ret = -EFAULT;677break;678}679spin_lock_irqsave(&gpio_lock, flags);680val = setget_input(priv, val);681spin_unlock_irqrestore(&gpio_lock, flags);682if (copy_to_user((void __user *)arg, &val, sizeof(val)))683ret = -EFAULT;684break;685case IO_SETGET_OUTPUT:686/* bits set in *arg is set to output,687* *arg updated with current output pins.688*/689if (copy_from_user(&val, (void __user *)arg, sizeof(val))) {690ret = -EFAULT;691break;692}693spin_lock_irqsave(&gpio_lock, flags);694val = setget_output(priv, val);695spin_unlock_irqrestore(&gpio_lock, flags);696if (copy_to_user((void __user *)arg, &val, sizeof(val)))697ret = -EFAULT;698break;699default:700spin_lock_irqsave(&gpio_lock, flags);701if (priv->minor == GPIO_MINOR_LEDS)702ret = gpio_leds_ioctl(cmd, arg);703else704ret = -EINVAL;705spin_unlock_irqrestore(&gpio_lock, flags);706} /* switch */707708return ret;709}710711static int712gpio_leds_ioctl(unsigned int cmd, unsigned long arg)713{714unsigned char green;715unsigned char red;716717switch (_IOC_NR(cmd)) {718case IO_LEDACTIVE_SET:719green = ((unsigned char)arg) & 1;720red = (((unsigned char)arg) >> 1) & 1;721CRIS_LED_ACTIVE_SET_G(green);722CRIS_LED_ACTIVE_SET_R(red);723break;724725case IO_LED_SETBIT:726CRIS_LED_BIT_SET(arg);727break;728729case IO_LED_CLRBIT:730CRIS_LED_BIT_CLR(arg);731break;732733default:734return -EINVAL;735} /* switch */736737return 0;738}739740static const struct file_operations gpio_fops = {741.owner = THIS_MODULE,742.poll = gpio_poll,743.unlocked_ioctl = gpio_ioctl,744.write = gpio_write,745.open = gpio_open,746.release = gpio_release,747.llseek = noop_llseek,748};749750static void ioif_watcher(const unsigned int gpio_in_available,751const unsigned int gpio_out_available,752const unsigned char pa_available,753const unsigned char pb_available)754{755unsigned long int flags;756757D(printk(KERN_DEBUG "gpio.c: ioif_watcher called\n"));758D(printk(KERN_DEBUG "gpio.c: G in: 0x%08x G out: 0x%08x "759"PA: 0x%02x PB: 0x%02x\n",760gpio_in_available, gpio_out_available,761pa_available, pb_available));762763spin_lock_irqsave(&gpio_lock, flags);764765dir_g_in_bits = gpio_in_available;766dir_g_out_bits = gpio_out_available;767768/* Initialise the dir_g_shadow etc. depending on genconfig */769/* 0=input 1=output */770if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, g0dir, out))771dir_g_shadow |= (1 << 0);772if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, g8_15dir, out))773dir_g_shadow |= 0x0000FF00;774if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, g16_23dir, out))775dir_g_shadow |= 0x00FF0000;776if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, g24dir, out))777dir_g_shadow |= (1 << 24);778779changeable_dir_g = changeable_dir_g_mask;780changeable_dir_g &= dir_g_out_bits;781changeable_dir_g &= dir_g_in_bits;782783/* Correct the bits that can change direction */784dir_g_out_bits &= ~changeable_dir_g;785dir_g_out_bits |= dir_g_shadow;786dir_g_in_bits &= ~changeable_dir_g;787dir_g_in_bits |= (~dir_g_shadow & changeable_dir_g);788789spin_unlock_irqrestore(&gpio_lock, flags);790791printk(KERN_INFO "GPIO port G: in_bits: 0x%08lX out_bits: 0x%08lX "792"val: %08lX\n",793dir_g_in_bits, dir_g_out_bits, (unsigned long)*R_PORT_G_DATA);794printk(KERN_INFO "GPIO port G: dir: %08lX changeable: %08lX\n",795dir_g_shadow, changeable_dir_g);796}797798/* main driver initialization routine, called from mem.c */799800static int __init gpio_init(void)801{802int res;803#if defined (CONFIG_ETRAX_CSP0_LEDS)804int i;805#endif806807res = register_chrdev(GPIO_MAJOR, gpio_name, &gpio_fops);808if (res < 0) {809printk(KERN_ERR "gpio: couldn't get a major number.\n");810return res;811}812813/* Clear all leds */814#if defined (CONFIG_ETRAX_CSP0_LEDS) || defined (CONFIG_ETRAX_PA_LEDS) || defined (CONFIG_ETRAX_PB_LEDS)815CRIS_LED_NETWORK_SET(0);816CRIS_LED_ACTIVE_SET(0);817CRIS_LED_DISK_READ(0);818CRIS_LED_DISK_WRITE(0);819820#if defined (CONFIG_ETRAX_CSP0_LEDS)821for (i = 0; i < 32; i++)822CRIS_LED_BIT_SET(i);823#endif824825#endif826/* The I/O interface allocation watcher will be called when827* registering it. */828if (cris_io_interface_register_watcher(ioif_watcher)){829printk(KERN_WARNING "gpio_init: Failed to install IO "830"if allocator watcher\n");831}832833printk(KERN_INFO "ETRAX 100LX GPIO driver v2.5, (c) 2001-2008 "834"Axis Communications AB\n");835/* We call etrax_gpio_wake_up_check() from timer interrupt and836* from cpu_idle() in kernel/process.c837* The check in cpu_idle() reduces latency from ~15 ms to ~6 ms838* in some tests.839*/840res = request_irq(TIMER0_IRQ_NBR, gpio_poll_timer_interrupt,841IRQF_SHARED | IRQF_DISABLED, "gpio poll", gpio_name);842if (res) {843printk(KERN_CRIT "err: timer0 irq for gpio\n");844return res;845}846res = request_irq(PA_IRQ_NBR, gpio_interrupt,847IRQF_SHARED | IRQF_DISABLED, "gpio PA", gpio_name);848if (res)849printk(KERN_CRIT "err: PA irq for gpio\n");850851return res;852}853854/* this makes sure that gpio_init is called during kernel boot */855module_init(gpio_init);856857858859