Path: blob/master/arch/cris/arch-v32/drivers/mach-fs/gpio.c
15131 views
/*1* ETRAX CRISv32 general port I/O device2*3* Copyright (c) 1999-2006 Axis Communications AB4*5* Authors: Bjorn Wesen (initial version)6* Ola Knutsson (LED handling)7* Johan Adolfsson (read/set directions, write, port G,8* port to ETRAX FS.9*10*/1112#include <linux/module.h>13#include <linux/sched.h>14#include <linux/slab.h>15#include <linux/ioport.h>16#include <linux/errno.h>17#include <linux/kernel.h>18#include <linux/fs.h>19#include <linux/string.h>20#include <linux/poll.h>21#include <linux/init.h>22#include <linux/interrupt.h>23#include <linux/spinlock.h>24#include <linux/mutex.h>2526#include <asm/etraxgpio.h>27#include <hwregs/reg_map.h>28#include <hwregs/reg_rdwr.h>29#include <hwregs/gio_defs.h>30#include <hwregs/intr_vect_defs.h>31#include <asm/io.h>32#include <asm/system.h>33#include <asm/irq.h>3435#ifdef CONFIG_ETRAX_VIRTUAL_GPIO36#include "../i2c.h"3738#define VIRT_I2C_ADDR 0x4039#endif4041/* The following gio ports on ETRAX FS is available:42* pa 8 bits, supports interrupts off, hi, low, set, posedge, negedge anyedge43* pb 18 bits44* pc 18 bits45* pd 18 bits46* pe 18 bits47* each port has a rw_px_dout, r_px_din and rw_px_oe register.48*/4950#define GPIO_MAJOR 120 /* experimental MAJOR number */5152#define D(x)5354#if 055static int dp_cnt;56#define DP(x) \57do { \58dp_cnt++; \59if (dp_cnt % 1000 == 0) \60x; \61} while (0)62#else63#define DP(x)64#endif6566static DEFINE_MUTEX(gpio_mutex);67static char gpio_name[] = "etrax gpio";6869#if 070static wait_queue_head_t *gpio_wq;71#endif7273#ifdef CONFIG_ETRAX_VIRTUAL_GPIO74static int virtual_gpio_ioctl(struct file *file, unsigned int cmd,75unsigned long arg);76#endif77static long gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg);78static ssize_t gpio_write(struct file *file, const char *buf, size_t count,79loff_t *off);80static int gpio_open(struct inode *inode, struct file *filp);81static int gpio_release(struct inode *inode, struct file *filp);82static unsigned int gpio_poll(struct file *filp,83struct poll_table_struct *wait);8485/* private data per open() of this driver */8687struct gpio_private {88struct gpio_private *next;89/* The IO_CFG_WRITE_MODE_VALUE only support 8 bits: */90unsigned char clk_mask;91unsigned char data_mask;92unsigned char write_msb;93unsigned char pad1;94/* These fields are generic */95unsigned long highalarm, lowalarm;96wait_queue_head_t alarm_wq;97int minor;98};99100/* linked list of alarms to check for */101102static struct gpio_private *alarmlist;103104static int gpio_some_alarms; /* Set if someone uses alarm */105static unsigned long gpio_pa_high_alarms;106static unsigned long gpio_pa_low_alarms;107108static DEFINE_SPINLOCK(alarm_lock);109110#define NUM_PORTS (GPIO_MINOR_LAST+1)111#define GIO_REG_RD_ADDR(reg) \112(volatile unsigned long *)(regi_gio + REG_RD_ADDR_gio_##reg)113#define GIO_REG_WR_ADDR(reg) \114(volatile unsigned long *)(regi_gio + REG_RD_ADDR_gio_##reg)115unsigned long led_dummy;116#ifdef CONFIG_ETRAX_VIRTUAL_GPIO117static unsigned long virtual_dummy;118static unsigned long virtual_rw_pv_oe = CONFIG_ETRAX_DEF_GIO_PV_OE;119static unsigned short cached_virtual_gpio_read;120#endif121122static volatile unsigned long *data_out[NUM_PORTS] = {123GIO_REG_WR_ADDR(rw_pa_dout),124GIO_REG_WR_ADDR(rw_pb_dout),125&led_dummy,126GIO_REG_WR_ADDR(rw_pc_dout),127GIO_REG_WR_ADDR(rw_pd_dout),128GIO_REG_WR_ADDR(rw_pe_dout),129#ifdef CONFIG_ETRAX_VIRTUAL_GPIO130&virtual_dummy,131#endif132};133134static volatile unsigned long *data_in[NUM_PORTS] = {135GIO_REG_RD_ADDR(r_pa_din),136GIO_REG_RD_ADDR(r_pb_din),137&led_dummy,138GIO_REG_RD_ADDR(r_pc_din),139GIO_REG_RD_ADDR(r_pd_din),140GIO_REG_RD_ADDR(r_pe_din),141#ifdef CONFIG_ETRAX_VIRTUAL_GPIO142&virtual_dummy,143#endif144};145146static unsigned long changeable_dir[NUM_PORTS] = {147CONFIG_ETRAX_PA_CHANGEABLE_DIR,148CONFIG_ETRAX_PB_CHANGEABLE_DIR,1490,150CONFIG_ETRAX_PC_CHANGEABLE_DIR,151CONFIG_ETRAX_PD_CHANGEABLE_DIR,152CONFIG_ETRAX_PE_CHANGEABLE_DIR,153#ifdef CONFIG_ETRAX_VIRTUAL_GPIO154CONFIG_ETRAX_PV_CHANGEABLE_DIR,155#endif156};157158static unsigned long changeable_bits[NUM_PORTS] = {159CONFIG_ETRAX_PA_CHANGEABLE_BITS,160CONFIG_ETRAX_PB_CHANGEABLE_BITS,1610,162CONFIG_ETRAX_PC_CHANGEABLE_BITS,163CONFIG_ETRAX_PD_CHANGEABLE_BITS,164CONFIG_ETRAX_PE_CHANGEABLE_BITS,165#ifdef CONFIG_ETRAX_VIRTUAL_GPIO166CONFIG_ETRAX_PV_CHANGEABLE_BITS,167#endif168};169170static volatile unsigned long *dir_oe[NUM_PORTS] = {171GIO_REG_WR_ADDR(rw_pa_oe),172GIO_REG_WR_ADDR(rw_pb_oe),173&led_dummy,174GIO_REG_WR_ADDR(rw_pc_oe),175GIO_REG_WR_ADDR(rw_pd_oe),176GIO_REG_WR_ADDR(rw_pe_oe),177#ifdef CONFIG_ETRAX_VIRTUAL_GPIO178&virtual_rw_pv_oe,179#endif180};181182183184static unsigned int gpio_poll(struct file *file, struct poll_table_struct *wait)185{186unsigned int mask = 0;187struct gpio_private *priv = file->private_data;188unsigned long data;189poll_wait(file, &priv->alarm_wq, wait);190if (priv->minor == GPIO_MINOR_A) {191reg_gio_rw_intr_cfg intr_cfg;192unsigned long tmp;193unsigned long flags;194195local_irq_save(flags);196data = REG_TYPE_CONV(unsigned long, reg_gio_r_pa_din,197REG_RD(gio, regi_gio, r_pa_din));198/* PA has support for interrupt199* lets activate high for those low and with highalarm set200*/201intr_cfg = REG_RD(gio, regi_gio, rw_intr_cfg);202203tmp = ~data & priv->highalarm & 0xFF;204if (tmp & (1 << 0))205intr_cfg.pa0 = regk_gio_hi;206if (tmp & (1 << 1))207intr_cfg.pa1 = regk_gio_hi;208if (tmp & (1 << 2))209intr_cfg.pa2 = regk_gio_hi;210if (tmp & (1 << 3))211intr_cfg.pa3 = regk_gio_hi;212if (tmp & (1 << 4))213intr_cfg.pa4 = regk_gio_hi;214if (tmp & (1 << 5))215intr_cfg.pa5 = regk_gio_hi;216if (tmp & (1 << 6))217intr_cfg.pa6 = regk_gio_hi;218if (tmp & (1 << 7))219intr_cfg.pa7 = regk_gio_hi;220/*221* lets activate low for those high and with lowalarm set222*/223tmp = data & priv->lowalarm & 0xFF;224if (tmp & (1 << 0))225intr_cfg.pa0 = regk_gio_lo;226if (tmp & (1 << 1))227intr_cfg.pa1 = regk_gio_lo;228if (tmp & (1 << 2))229intr_cfg.pa2 = regk_gio_lo;230if (tmp & (1 << 3))231intr_cfg.pa3 = regk_gio_lo;232if (tmp & (1 << 4))233intr_cfg.pa4 = regk_gio_lo;234if (tmp & (1 << 5))235intr_cfg.pa5 = regk_gio_lo;236if (tmp & (1 << 6))237intr_cfg.pa6 = regk_gio_lo;238if (tmp & (1 << 7))239intr_cfg.pa7 = regk_gio_lo;240241REG_WR(gio, regi_gio, rw_intr_cfg, intr_cfg);242local_irq_restore(flags);243} else if (priv->minor <= GPIO_MINOR_E)244data = *data_in[priv->minor];245else246return 0;247248if ((data & priv->highalarm) || (~data & priv->lowalarm))249mask = POLLIN|POLLRDNORM;250251DP(printk(KERN_DEBUG "gpio_poll ready: mask 0x%08X\n", mask));252return mask;253}254255int etrax_gpio_wake_up_check(void)256{257struct gpio_private *priv;258unsigned long data = 0;259unsigned long flags;260int ret = 0;261spin_lock_irqsave(&alarm_lock, flags);262priv = alarmlist;263while (priv) {264#ifdef CONFIG_ETRAX_VIRTUAL_GPIO265if (priv->minor == GPIO_MINOR_V)266data = (unsigned long)cached_virtual_gpio_read;267else {268data = *data_in[priv->minor];269if (priv->minor == GPIO_MINOR_A)270priv->lowalarm |= (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN);271}272#else273data = *data_in[priv->minor];274#endif275if ((data & priv->highalarm) ||276(~data & priv->lowalarm)) {277DP(printk(KERN_DEBUG278"etrax_gpio_wake_up_check %i\n", priv->minor));279wake_up_interruptible(&priv->alarm_wq);280ret = 1;281}282priv = priv->next;283}284spin_unlock_irqrestore(&alarm_lock, flags);285return ret;286}287288static irqreturn_t289gpio_poll_timer_interrupt(int irq, void *dev_id)290{291if (gpio_some_alarms)292return IRQ_RETVAL(etrax_gpio_wake_up_check());293return IRQ_NONE;294}295296static irqreturn_t297gpio_pa_interrupt(int irq, void *dev_id)298{299reg_gio_rw_intr_mask intr_mask;300reg_gio_r_masked_intr masked_intr;301reg_gio_rw_ack_intr ack_intr;302unsigned long tmp;303unsigned long tmp2;304#ifdef CONFIG_ETRAX_VIRTUAL_GPIO305unsigned char enable_gpiov_ack = 0;306#endif307308/* Find what PA interrupts are active */309masked_intr = REG_RD(gio, regi_gio, r_masked_intr);310tmp = REG_TYPE_CONV(unsigned long, reg_gio_r_masked_intr, masked_intr);311312/* Find those that we have enabled */313spin_lock(&alarm_lock);314tmp &= (gpio_pa_high_alarms | gpio_pa_low_alarms);315spin_unlock(&alarm_lock);316317#ifdef CONFIG_ETRAX_VIRTUAL_GPIO318/* Something changed on virtual GPIO. Interrupt is acked by319* reading the device.320*/321if (tmp & (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN)) {322i2c_read(VIRT_I2C_ADDR, (void *)&cached_virtual_gpio_read,323sizeof(cached_virtual_gpio_read));324enable_gpiov_ack = 1;325}326#endif327328/* Ack them */329ack_intr = REG_TYPE_CONV(reg_gio_rw_ack_intr, unsigned long, tmp);330REG_WR(gio, regi_gio, rw_ack_intr, ack_intr);331332/* Disable those interrupts.. */333intr_mask = REG_RD(gio, regi_gio, rw_intr_mask);334tmp2 = REG_TYPE_CONV(unsigned long, reg_gio_rw_intr_mask, intr_mask);335tmp2 &= ~tmp;336#ifdef CONFIG_ETRAX_VIRTUAL_GPIO337/* Do not disable interrupt on virtual GPIO. Changes on virtual338* pins are only noticed by an interrupt.339*/340if (enable_gpiov_ack)341tmp2 |= (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN);342#endif343intr_mask = REG_TYPE_CONV(reg_gio_rw_intr_mask, unsigned long, tmp2);344REG_WR(gio, regi_gio, rw_intr_mask, intr_mask);345346if (gpio_some_alarms)347return IRQ_RETVAL(etrax_gpio_wake_up_check());348return IRQ_NONE;349}350351352static ssize_t gpio_write(struct file *file, const char *buf, size_t count,353loff_t *off)354{355struct gpio_private *priv = file->private_data;356unsigned char data, clk_mask, data_mask, write_msb;357unsigned long flags;358unsigned long shadow;359volatile unsigned long *port;360ssize_t retval = count;361/* Only bits 0-7 may be used for write operations but allow all362devices except leds... */363#ifdef CONFIG_ETRAX_VIRTUAL_GPIO364if (priv->minor == GPIO_MINOR_V)365return -EFAULT;366#endif367if (priv->minor == GPIO_MINOR_LEDS)368return -EFAULT;369370if (!access_ok(VERIFY_READ, buf, count))371return -EFAULT;372clk_mask = priv->clk_mask;373data_mask = priv->data_mask;374/* It must have been configured using the IO_CFG_WRITE_MODE */375/* Perhaps a better error code? */376if (clk_mask == 0 || data_mask == 0)377return -EPERM;378write_msb = priv->write_msb;379D(printk(KERN_DEBUG "gpio_write: %lu to data 0x%02X clk 0x%02X "380"msb: %i\n", count, data_mask, clk_mask, write_msb));381port = data_out[priv->minor];382383while (count--) {384int i;385data = *buf++;386if (priv->write_msb) {387for (i = 7; i >= 0; i--) {388local_irq_save(flags);389shadow = *port;390*port = shadow &= ~clk_mask;391if (data & 1<<i)392*port = shadow |= data_mask;393else394*port = shadow &= ~data_mask;395/* For FPGA: min 5.0ns (DCC) before CCLK high */396*port = shadow |= clk_mask;397local_irq_restore(flags);398}399} else {400for (i = 0; i <= 7; i++) {401local_irq_save(flags);402shadow = *port;403*port = shadow &= ~clk_mask;404if (data & 1<<i)405*port = shadow |= data_mask;406else407*port = shadow &= ~data_mask;408/* For FPGA: min 5.0ns (DCC) before CCLK high */409*port = shadow |= clk_mask;410local_irq_restore(flags);411}412}413}414return retval;415}416417418419static int420gpio_open(struct inode *inode, struct file *filp)421{422struct gpio_private *priv;423int p = iminor(inode);424425if (p > GPIO_MINOR_LAST)426return -EINVAL;427428priv = kmalloc(sizeof(struct gpio_private), GFP_KERNEL);429if (!priv)430return -ENOMEM;431432mutex_lock(&gpio_mutex);433memset(priv, 0, sizeof(*priv));434435priv->minor = p;436437/* initialize the io/alarm struct */438439priv->clk_mask = 0;440priv->data_mask = 0;441priv->highalarm = 0;442priv->lowalarm = 0;443init_waitqueue_head(&priv->alarm_wq);444445filp->private_data = (void *)priv;446447/* link it into our alarmlist */448spin_lock_irq(&alarm_lock);449priv->next = alarmlist;450alarmlist = priv;451spin_unlock_irq(&alarm_lock);452453mutex_unlock(&gpio_mutex);454return 0;455}456457static int458gpio_release(struct inode *inode, struct file *filp)459{460struct gpio_private *p;461struct gpio_private *todel;462/* local copies while updating them: */463unsigned long a_high, a_low;464unsigned long some_alarms;465466/* unlink from alarmlist and free the private structure */467468spin_lock_irq(&alarm_lock);469p = alarmlist;470todel = filp->private_data;471472if (p == todel) {473alarmlist = todel->next;474} else {475while (p->next != todel)476p = p->next;477p->next = todel->next;478}479480kfree(todel);481/* Check if there are still any alarms set */482p = alarmlist;483some_alarms = 0;484a_high = 0;485a_low = 0;486while (p) {487if (p->minor == GPIO_MINOR_A) {488#ifdef CONFIG_ETRAX_VIRTUAL_GPIO489p->lowalarm |= (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN);490#endif491a_high |= p->highalarm;492a_low |= p->lowalarm;493}494495if (p->highalarm | p->lowalarm)496some_alarms = 1;497p = p->next;498}499500#ifdef CONFIG_ETRAX_VIRTUAL_GPIO501/* Variables 'some_alarms' and 'a_low' needs to be set here again502* to ensure that interrupt for virtual GPIO is handled.503*/504some_alarms = 1;505a_low |= (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN);506#endif507508gpio_some_alarms = some_alarms;509gpio_pa_high_alarms = a_high;510gpio_pa_low_alarms = a_low;511spin_unlock_irq(&alarm_lock);512513return 0;514}515516/* Main device API. ioctl's to read/set/clear bits, as well as to517* set alarms to wait for using a subsequent select().518*/519520inline unsigned long setget_input(struct gpio_private *priv, unsigned long arg)521{522/* Set direction 0=unchanged 1=input,523* return mask with 1=input524*/525unsigned long flags;526unsigned long dir_shadow;527528local_irq_save(flags);529dir_shadow = *dir_oe[priv->minor];530dir_shadow &= ~(arg & changeable_dir[priv->minor]);531*dir_oe[priv->minor] = dir_shadow;532local_irq_restore(flags);533534if (priv->minor == GPIO_MINOR_A)535dir_shadow ^= 0xFF; /* Only 8 bits */536#ifdef CONFIG_ETRAX_VIRTUAL_GPIO537else if (priv->minor == GPIO_MINOR_V)538dir_shadow ^= 0xFFFF; /* Only 16 bits */539#endif540else541dir_shadow ^= 0x3FFFF; /* Only 18 bits */542return dir_shadow;543544} /* setget_input */545546inline unsigned long setget_output(struct gpio_private *priv, unsigned long arg)547{548unsigned long flags;549unsigned long dir_shadow;550551local_irq_save(flags);552dir_shadow = *dir_oe[priv->minor];553dir_shadow |= (arg & changeable_dir[priv->minor]);554*dir_oe[priv->minor] = dir_shadow;555local_irq_restore(flags);556return dir_shadow;557} /* setget_output */558559static int gpio_leds_ioctl(unsigned int cmd, unsigned long arg);560561static int562gpio_ioctl_unlocked(struct file *file, unsigned int cmd, unsigned long arg)563{564unsigned long flags;565unsigned long val;566unsigned long shadow;567struct gpio_private *priv = file->private_data;568if (_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE)569return -EINVAL;570571#ifdef CONFIG_ETRAX_VIRTUAL_GPIO572if (priv->minor == GPIO_MINOR_V)573return virtual_gpio_ioctl(file, cmd, arg);574#endif575576switch (_IOC_NR(cmd)) {577case IO_READBITS: /* Use IO_READ_INBITS and IO_READ_OUTBITS instead */578/* Read the port. */579return *data_in[priv->minor];580break;581case IO_SETBITS:582local_irq_save(flags);583/* Set changeable bits with a 1 in arg. */584shadow = *data_out[priv->minor];585shadow |= (arg & changeable_bits[priv->minor]);586*data_out[priv->minor] = shadow;587local_irq_restore(flags);588break;589case IO_CLRBITS:590local_irq_save(flags);591/* Clear changeable bits with a 1 in arg. */592shadow = *data_out[priv->minor];593shadow &= ~(arg & changeable_bits[priv->minor]);594*data_out[priv->minor] = shadow;595local_irq_restore(flags);596break;597case IO_HIGHALARM:598/* Set alarm when bits with 1 in arg go high. */599priv->highalarm |= arg;600spin_lock_irqsave(&alarm_lock, flags);601gpio_some_alarms = 1;602if (priv->minor == GPIO_MINOR_A)603gpio_pa_high_alarms |= arg;604spin_unlock_irqrestore(&alarm_lock, flags);605break;606case IO_LOWALARM:607/* Set alarm when bits with 1 in arg go low. */608priv->lowalarm |= arg;609spin_lock_irqsave(&alarm_lock, flags);610gpio_some_alarms = 1;611if (priv->minor == GPIO_MINOR_A)612gpio_pa_low_alarms |= arg;613spin_unlock_irqrestore(&alarm_lock, flags);614break;615case IO_CLRALARM:616/* Clear alarm for bits with 1 in arg. */617priv->highalarm &= ~arg;618priv->lowalarm &= ~arg;619spin_lock_irqsave(&alarm_lock, flags);620if (priv->minor == GPIO_MINOR_A) {621if (gpio_pa_high_alarms & arg ||622gpio_pa_low_alarms & arg)623/* Must update the gpio_pa_*alarms masks */624;625}626spin_unlock_irqrestore(&alarm_lock, flags);627break;628case IO_READDIR: /* Use IO_SETGET_INPUT/OUTPUT instead! */629/* Read direction 0=input 1=output */630return *dir_oe[priv->minor];631case IO_SETINPUT: /* Use IO_SETGET_INPUT instead! */632/* Set direction 0=unchanged 1=input,633* return mask with 1=input634*/635return setget_input(priv, arg);636break;637case IO_SETOUTPUT: /* Use IO_SETGET_OUTPUT instead! */638/* Set direction 0=unchanged 1=output,639* return mask with 1=output640*/641return setget_output(priv, arg);642643case IO_CFG_WRITE_MODE:644{645unsigned long dir_shadow;646dir_shadow = *dir_oe[priv->minor];647648priv->clk_mask = arg & 0xFF;649priv->data_mask = (arg >> 8) & 0xFF;650priv->write_msb = (arg >> 16) & 0x01;651/* Check if we're allowed to change the bits and652* the direction is correct653*/654if (!((priv->clk_mask & changeable_bits[priv->minor]) &&655(priv->data_mask & changeable_bits[priv->minor]) &&656(priv->clk_mask & dir_shadow) &&657(priv->data_mask & dir_shadow))) {658priv->clk_mask = 0;659priv->data_mask = 0;660return -EPERM;661}662break;663}664case IO_READ_INBITS:665/* *arg is result of reading the input pins */666val = *data_in[priv->minor];667if (copy_to_user((unsigned long *)arg, &val, sizeof(val)))668return -EFAULT;669return 0;670break;671case IO_READ_OUTBITS:672/* *arg is result of reading the output shadow */673val = *data_out[priv->minor];674if (copy_to_user((unsigned long *)arg, &val, sizeof(val)))675return -EFAULT;676break;677case IO_SETGET_INPUT:678/* bits set in *arg is set to input,679* *arg updated with current input pins.680*/681if (copy_from_user(&val, (unsigned long *)arg, sizeof(val)))682return -EFAULT;683val = setget_input(priv, val);684if (copy_to_user((unsigned long *)arg, &val, sizeof(val)))685return -EFAULT;686break;687case IO_SETGET_OUTPUT:688/* bits set in *arg is set to output,689* *arg updated with current output pins.690*/691if (copy_from_user(&val, (unsigned long *)arg, sizeof(val)))692return -EFAULT;693val = setget_output(priv, val);694if (copy_to_user((unsigned long *)arg, &val, sizeof(val)))695return -EFAULT;696break;697default:698if (priv->minor == GPIO_MINOR_LEDS)699return gpio_leds_ioctl(cmd, arg);700else701return -EINVAL;702} /* switch */703704return 0;705}706707static long gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)708{709long ret;710711mutex_lock(&gpio_mutex);712ret = gpio_ioctl_unlocked(file, cmd, arg);713mutex_unlock(&gpio_mutex);714715return ret;716}717718#ifdef CONFIG_ETRAX_VIRTUAL_GPIO719static int720virtual_gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)721{722unsigned long flags;723unsigned short val;724unsigned short shadow;725struct gpio_private *priv = file->private_data;726727switch (_IOC_NR(cmd)) {728case IO_SETBITS:729local_irq_save(flags);730/* Set changeable bits with a 1 in arg. */731i2c_read(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow));732shadow |= ~*dir_oe[priv->minor];733shadow |= (arg & changeable_bits[priv->minor]);734i2c_write(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow));735local_irq_restore(flags);736break;737case IO_CLRBITS:738local_irq_save(flags);739/* Clear changeable bits with a 1 in arg. */740i2c_read(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow));741shadow |= ~*dir_oe[priv->minor];742shadow &= ~(arg & changeable_bits[priv->minor]);743i2c_write(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow));744local_irq_restore(flags);745break;746case IO_HIGHALARM:747/* Set alarm when bits with 1 in arg go high. */748priv->highalarm |= arg;749spin_lock(&alarm_lock);750gpio_some_alarms = 1;751spin_unlock(&alarm_lock);752break;753case IO_LOWALARM:754/* Set alarm when bits with 1 in arg go low. */755priv->lowalarm |= arg;756spin_lock(&alarm_lock);757gpio_some_alarms = 1;758spin_unlock(&alarm_lock);759break;760case IO_CLRALARM:761/* Clear alarm for bits with 1 in arg. */762priv->highalarm &= ~arg;763priv->lowalarm &= ~arg;764spin_lock(&alarm_lock);765spin_unlock(&alarm_lock);766break;767case IO_CFG_WRITE_MODE:768{769unsigned long dir_shadow;770dir_shadow = *dir_oe[priv->minor];771772priv->clk_mask = arg & 0xFF;773priv->data_mask = (arg >> 8) & 0xFF;774priv->write_msb = (arg >> 16) & 0x01;775/* Check if we're allowed to change the bits and776* the direction is correct777*/778if (!((priv->clk_mask & changeable_bits[priv->minor]) &&779(priv->data_mask & changeable_bits[priv->minor]) &&780(priv->clk_mask & dir_shadow) &&781(priv->data_mask & dir_shadow))) {782priv->clk_mask = 0;783priv->data_mask = 0;784return -EPERM;785}786break;787}788case IO_READ_INBITS:789/* *arg is result of reading the input pins */790val = cached_virtual_gpio_read;791val &= ~*dir_oe[priv->minor];792if (copy_to_user((unsigned long *)arg, &val, sizeof(val)))793return -EFAULT;794return 0;795break;796case IO_READ_OUTBITS:797/* *arg is result of reading the output shadow */798i2c_read(VIRT_I2C_ADDR, (void *)&val, sizeof(val));799val &= *dir_oe[priv->minor];800if (copy_to_user((unsigned long *)arg, &val, sizeof(val)))801return -EFAULT;802break;803case IO_SETGET_INPUT:804{805/* bits set in *arg is set to input,806* *arg updated with current input pins.807*/808unsigned short input_mask = ~*dir_oe[priv->minor];809if (copy_from_user(&val, (unsigned long *)arg, sizeof(val)))810return -EFAULT;811val = setget_input(priv, val);812if (copy_to_user((unsigned long *)arg, &val, sizeof(val)))813return -EFAULT;814if ((input_mask & val) != input_mask) {815/* Input pins changed. All ports desired as input816* should be set to logic 1.817*/818unsigned short change = input_mask ^ val;819i2c_read(VIRT_I2C_ADDR, (void *)&shadow,820sizeof(shadow));821shadow &= ~change;822shadow |= val;823i2c_write(VIRT_I2C_ADDR, (void *)&shadow,824sizeof(shadow));825}826break;827}828case IO_SETGET_OUTPUT:829/* bits set in *arg is set to output,830* *arg updated with current output pins.831*/832if (copy_from_user(&val, (unsigned long *)arg, sizeof(val)))833return -EFAULT;834val = setget_output(priv, val);835if (copy_to_user((unsigned long *)arg, &val, sizeof(val)))836return -EFAULT;837break;838default:839return -EINVAL;840} /* switch */841return 0;842}843#endif /* CONFIG_ETRAX_VIRTUAL_GPIO */844845static int846gpio_leds_ioctl(unsigned int cmd, unsigned long arg)847{848unsigned char green;849unsigned char red;850851switch (_IOC_NR(cmd)) {852case IO_LEDACTIVE_SET:853green = ((unsigned char) arg) & 1;854red = (((unsigned char) arg) >> 1) & 1;855CRIS_LED_ACTIVE_SET_G(green);856CRIS_LED_ACTIVE_SET_R(red);857break;858859default:860return -EINVAL;861} /* switch */862863return 0;864}865866static const struct file_operations gpio_fops = {867.owner = THIS_MODULE,868.poll = gpio_poll,869.unlocked_ioctl = gpio_ioctl,870.write = gpio_write,871.open = gpio_open,872.release = gpio_release,873.llseek = noop_llseek,874};875876#ifdef CONFIG_ETRAX_VIRTUAL_GPIO877static void878virtual_gpio_init(void)879{880reg_gio_rw_intr_cfg intr_cfg;881reg_gio_rw_intr_mask intr_mask;882unsigned short shadow;883884shadow = ~virtual_rw_pv_oe; /* Input ports should be set to logic 1 */885shadow |= CONFIG_ETRAX_DEF_GIO_PV_OUT;886i2c_write(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow));887888/* Set interrupt mask and on what state the interrupt shall trigger.889* For virtual gpio the interrupt shall trigger on logic '0'.890*/891intr_cfg = REG_RD(gio, regi_gio, rw_intr_cfg);892intr_mask = REG_RD(gio, regi_gio, rw_intr_mask);893894switch (CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN) {895case 0:896intr_cfg.pa0 = regk_gio_lo;897intr_mask.pa0 = regk_gio_yes;898break;899case 1:900intr_cfg.pa1 = regk_gio_lo;901intr_mask.pa1 = regk_gio_yes;902break;903case 2:904intr_cfg.pa2 = regk_gio_lo;905intr_mask.pa2 = regk_gio_yes;906break;907case 3:908intr_cfg.pa3 = regk_gio_lo;909intr_mask.pa3 = regk_gio_yes;910break;911case 4:912intr_cfg.pa4 = regk_gio_lo;913intr_mask.pa4 = regk_gio_yes;914break;915case 5:916intr_cfg.pa5 = regk_gio_lo;917intr_mask.pa5 = regk_gio_yes;918break;919case 6:920intr_cfg.pa6 = regk_gio_lo;921intr_mask.pa6 = regk_gio_yes;922break;923case 7:924intr_cfg.pa7 = regk_gio_lo;925intr_mask.pa7 = regk_gio_yes;926break;927}928929REG_WR(gio, regi_gio, rw_intr_cfg, intr_cfg);930REG_WR(gio, regi_gio, rw_intr_mask, intr_mask);931932gpio_pa_low_alarms |= (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN);933gpio_some_alarms = 1;934}935#endif936937/* main driver initialization routine, called from mem.c */938939static __init int940gpio_init(void)941{942int res;943944/* do the formalities */945946res = register_chrdev(GPIO_MAJOR, gpio_name, &gpio_fops);947if (res < 0) {948printk(KERN_ERR "gpio: couldn't get a major number.\n");949return res;950}951952/* Clear all leds */953CRIS_LED_NETWORK_GRP0_SET(0);954CRIS_LED_NETWORK_GRP1_SET(0);955CRIS_LED_ACTIVE_SET(0);956CRIS_LED_DISK_READ(0);957CRIS_LED_DISK_WRITE(0);958959printk(KERN_INFO "ETRAX FS GPIO driver v2.5, (c) 2003-2007 "960"Axis Communications AB\n");961/* We call etrax_gpio_wake_up_check() from timer interrupt and962* from cpu_idle() in kernel/process.c963* The check in cpu_idle() reduces latency from ~15 ms to ~6 ms964* in some tests.965*/966if (request_irq(TIMER0_INTR_VECT, gpio_poll_timer_interrupt,967IRQF_SHARED | IRQF_DISABLED, "gpio poll", &alarmlist))968printk(KERN_ERR "timer0 irq for gpio\n");969970if (request_irq(GIO_INTR_VECT, gpio_pa_interrupt,971IRQF_SHARED | IRQF_DISABLED, "gpio PA", &alarmlist))972printk(KERN_ERR "PA irq for gpio\n");973974#ifdef CONFIG_ETRAX_VIRTUAL_GPIO975virtual_gpio_init();976#endif977978return res;979}980981/* this makes sure that gpio_init is called during kernel boot */982983module_init(gpio_init);984985986