16107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson/*
26107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson * ETRAX CRISv32 general port I/O device
36107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson *
46107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson * Copyright (c) 1999-2006 Axis Communications AB
56107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson *
66107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson * Authors:    Bjorn Wesen      (initial version)
76107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson *             Ola Knutsson     (LED handling)
86107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson *             Johan Adolfsson  (read/set directions, write, port G,
96107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson *                               port to ETRAX FS.
106107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson *
116107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson */
126107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
136107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#include <linux/module.h>
146107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#include <linux/sched.h>
156107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#include <linux/slab.h>
166107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#include <linux/ioport.h>
176107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#include <linux/errno.h>
186107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#include <linux/kernel.h>
196107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#include <linux/fs.h>
206107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#include <linux/string.h>
216107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#include <linux/poll.h>
226107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#include <linux/init.h>
236107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#include <linux/interrupt.h>
246107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#include <linux/spinlock.h>
250890b5880df6a4989336add11f3a22122b26d9e1Arnd Bergmann#include <linux/mutex.h>
266107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
276107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#include <asm/etraxgpio.h>
286107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#include <hwregs/reg_map.h>
296107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#include <hwregs/reg_rdwr.h>
306107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#include <hwregs/gio_defs.h>
316107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#include <hwregs/intr_vect_defs.h>
326107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#include <asm/io.h>
336107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#include <asm/irq.h>
346107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
356107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
366107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#include "../i2c.h"
376107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
386107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#define VIRT_I2C_ADDR 0x40
396107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#endif
406107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
416107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson/* The following gio ports on ETRAX FS is available:
426107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson * pa  8 bits, supports interrupts off, hi, low, set, posedge, negedge anyedge
436107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson * pb 18 bits
446107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson * pc 18 bits
456107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson * pd 18 bits
466107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson * pe 18 bits
476107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson * each port has a rw_px_dout, r_px_din and rw_px_oe register.
486107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson */
496107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
506107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#define GPIO_MAJOR 120  /* experimental MAJOR number */
516107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
526107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#define D(x)
536107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
546107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#if 0
556107c61fd3e6b47106b078db1726ad814564efefJesper Nilssonstatic int dp_cnt;
566107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#define DP(x) \
576107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	do { \
586107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		dp_cnt++; \
596107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		if (dp_cnt % 1000 == 0) \
606107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			x; \
616107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	} while (0)
626107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#else
636107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#define DP(x)
646107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#endif
656107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
660890b5880df6a4989336add11f3a22122b26d9e1Arnd Bergmannstatic DEFINE_MUTEX(gpio_mutex);
676107c61fd3e6b47106b078db1726ad814564efefJesper Nilssonstatic char gpio_name[] = "etrax gpio";
686107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
696107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#if 0
706107c61fd3e6b47106b078db1726ad814564efefJesper Nilssonstatic wait_queue_head_t *gpio_wq;
716107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#endif
726107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
736107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
746107c61fd3e6b47106b078db1726ad814564efefJesper Nilssonstatic int virtual_gpio_ioctl(struct file *file, unsigned int cmd,
756107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	unsigned long arg);
766107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#endif
7790276a1a64e2ab732e26e3ac68febbf3ad04c517Jesper Nilssonstatic long gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
786107c61fd3e6b47106b078db1726ad814564efefJesper Nilssonstatic ssize_t gpio_write(struct file *file, const char *buf, size_t count,
796107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	loff_t *off);
806107c61fd3e6b47106b078db1726ad814564efefJesper Nilssonstatic int gpio_open(struct inode *inode, struct file *filp);
816107c61fd3e6b47106b078db1726ad814564efefJesper Nilssonstatic int gpio_release(struct inode *inode, struct file *filp);
826107c61fd3e6b47106b078db1726ad814564efefJesper Nilssonstatic unsigned int gpio_poll(struct file *filp,
836107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	struct poll_table_struct *wait);
846107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
856107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson/* private data per open() of this driver */
866107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
876107c61fd3e6b47106b078db1726ad814564efefJesper Nilssonstruct gpio_private {
886107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	struct gpio_private *next;
896107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	/* The IO_CFG_WRITE_MODE_VALUE only support 8 bits: */
906107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	unsigned char clk_mask;
916107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	unsigned char data_mask;
926107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	unsigned char write_msb;
936107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	unsigned char pad1;
946107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	/* These fields are generic */
956107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	unsigned long highalarm, lowalarm;
966107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	wait_queue_head_t alarm_wq;
976107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	int minor;
986107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson};
996107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
1006107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson/* linked list of alarms to check for */
1016107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
1026107c61fd3e6b47106b078db1726ad814564efefJesper Nilssonstatic struct gpio_private *alarmlist;
1036107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
1046107c61fd3e6b47106b078db1726ad814564efefJesper Nilssonstatic int gpio_some_alarms; /* Set if someone uses alarm */
1056107c61fd3e6b47106b078db1726ad814564efefJesper Nilssonstatic unsigned long gpio_pa_high_alarms;
1066107c61fd3e6b47106b078db1726ad814564efefJesper Nilssonstatic unsigned long gpio_pa_low_alarms;
1076107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
1086107c61fd3e6b47106b078db1726ad814564efefJesper Nilssonstatic DEFINE_SPINLOCK(alarm_lock);
1096107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
1106107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#define NUM_PORTS (GPIO_MINOR_LAST+1)
1116107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#define GIO_REG_RD_ADDR(reg) \
1126107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	(volatile unsigned long *)(regi_gio + REG_RD_ADDR_gio_##reg)
1136107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#define GIO_REG_WR_ADDR(reg) \
1146107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	(volatile unsigned long *)(regi_gio + REG_RD_ADDR_gio_##reg)
1156107c61fd3e6b47106b078db1726ad814564efefJesper Nilssonunsigned long led_dummy;
1166107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
1176107c61fd3e6b47106b078db1726ad814564efefJesper Nilssonstatic unsigned long virtual_dummy;
1186107c61fd3e6b47106b078db1726ad814564efefJesper Nilssonstatic unsigned long virtual_rw_pv_oe = CONFIG_ETRAX_DEF_GIO_PV_OE;
1196107c61fd3e6b47106b078db1726ad814564efefJesper Nilssonstatic unsigned short cached_virtual_gpio_read;
1206107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#endif
1216107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
1226107c61fd3e6b47106b078db1726ad814564efefJesper Nilssonstatic volatile unsigned long *data_out[NUM_PORTS] = {
1236107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	GIO_REG_WR_ADDR(rw_pa_dout),
1246107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	GIO_REG_WR_ADDR(rw_pb_dout),
1256107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	&led_dummy,
1266107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	GIO_REG_WR_ADDR(rw_pc_dout),
1276107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	GIO_REG_WR_ADDR(rw_pd_dout),
1286107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	GIO_REG_WR_ADDR(rw_pe_dout),
1296107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
1306107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	&virtual_dummy,
1316107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#endif
1326107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson};
1336107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
1346107c61fd3e6b47106b078db1726ad814564efefJesper Nilssonstatic volatile unsigned long *data_in[NUM_PORTS] = {
1356107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	GIO_REG_RD_ADDR(r_pa_din),
1366107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	GIO_REG_RD_ADDR(r_pb_din),
1376107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	&led_dummy,
1386107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	GIO_REG_RD_ADDR(r_pc_din),
1396107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	GIO_REG_RD_ADDR(r_pd_din),
1406107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	GIO_REG_RD_ADDR(r_pe_din),
1416107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
1426107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	&virtual_dummy,
1436107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#endif
1446107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson};
1456107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
1466107c61fd3e6b47106b078db1726ad814564efefJesper Nilssonstatic unsigned long changeable_dir[NUM_PORTS] = {
1476107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	CONFIG_ETRAX_PA_CHANGEABLE_DIR,
1486107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	CONFIG_ETRAX_PB_CHANGEABLE_DIR,
1496107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	0,
1506107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	CONFIG_ETRAX_PC_CHANGEABLE_DIR,
1516107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	CONFIG_ETRAX_PD_CHANGEABLE_DIR,
1526107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	CONFIG_ETRAX_PE_CHANGEABLE_DIR,
1536107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
1546107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	CONFIG_ETRAX_PV_CHANGEABLE_DIR,
1556107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#endif
1566107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson};
1576107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
1586107c61fd3e6b47106b078db1726ad814564efefJesper Nilssonstatic unsigned long changeable_bits[NUM_PORTS] = {
1596107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	CONFIG_ETRAX_PA_CHANGEABLE_BITS,
1606107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	CONFIG_ETRAX_PB_CHANGEABLE_BITS,
1616107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	0,
1626107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	CONFIG_ETRAX_PC_CHANGEABLE_BITS,
1636107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	CONFIG_ETRAX_PD_CHANGEABLE_BITS,
1646107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	CONFIG_ETRAX_PE_CHANGEABLE_BITS,
1656107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
1666107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	CONFIG_ETRAX_PV_CHANGEABLE_BITS,
1676107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#endif
1686107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson};
1696107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
1706107c61fd3e6b47106b078db1726ad814564efefJesper Nilssonstatic volatile unsigned long *dir_oe[NUM_PORTS] = {
1716107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	GIO_REG_WR_ADDR(rw_pa_oe),
1726107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	GIO_REG_WR_ADDR(rw_pb_oe),
1736107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	&led_dummy,
1746107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	GIO_REG_WR_ADDR(rw_pc_oe),
1756107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	GIO_REG_WR_ADDR(rw_pd_oe),
1766107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	GIO_REG_WR_ADDR(rw_pe_oe),
1776107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
1786107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	&virtual_rw_pv_oe,
1796107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#endif
1806107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson};
1816107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
1826107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
1836107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
1842c30da717586a137b90c245820657a0d0a3a0a67Jesper Nilssonstatic unsigned int gpio_poll(struct file *file, struct poll_table_struct *wait)
1856107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson{
1866107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	unsigned int mask = 0;
18716bc0fe5ce84df89c8e802be210af88721d4cc4fJoe Perches	struct gpio_private *priv = file->private_data;
1886107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	unsigned long data;
1896107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	poll_wait(file, &priv->alarm_wq, wait);
1906107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	if (priv->minor == GPIO_MINOR_A) {
1916107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		reg_gio_rw_intr_cfg intr_cfg;
1926107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		unsigned long tmp;
1936107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		unsigned long flags;
1946107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
1956107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		local_irq_save(flags);
1966107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		data = REG_TYPE_CONV(unsigned long, reg_gio_r_pa_din,
1976107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			REG_RD(gio, regi_gio, r_pa_din));
1986107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		/* PA has support for interrupt
1996107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		 * lets activate high for those low and with highalarm set
2006107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		 */
2016107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		intr_cfg = REG_RD(gio, regi_gio, rw_intr_cfg);
2026107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
2036107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		tmp = ~data & priv->highalarm & 0xFF;
2046107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		if (tmp & (1 << 0))
2056107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			intr_cfg.pa0 = regk_gio_hi;
2066107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		if (tmp & (1 << 1))
2076107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			intr_cfg.pa1 = regk_gio_hi;
2086107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		if (tmp & (1 << 2))
2096107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			intr_cfg.pa2 = regk_gio_hi;
2106107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		if (tmp & (1 << 3))
2116107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			intr_cfg.pa3 = regk_gio_hi;
2126107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		if (tmp & (1 << 4))
2136107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			intr_cfg.pa4 = regk_gio_hi;
2146107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		if (tmp & (1 << 5))
2156107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			intr_cfg.pa5 = regk_gio_hi;
2166107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		if (tmp & (1 << 6))
2176107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			intr_cfg.pa6 = regk_gio_hi;
2186107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		if (tmp & (1 << 7))
2196107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			intr_cfg.pa7 = regk_gio_hi;
2206107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		/*
2216107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		 * lets activate low for those high and with lowalarm set
2226107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		 */
2236107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		tmp = data & priv->lowalarm & 0xFF;
2246107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		if (tmp & (1 << 0))
2256107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			intr_cfg.pa0 = regk_gio_lo;
2266107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		if (tmp & (1 << 1))
2276107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			intr_cfg.pa1 = regk_gio_lo;
2286107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		if (tmp & (1 << 2))
2296107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			intr_cfg.pa2 = regk_gio_lo;
2306107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		if (tmp & (1 << 3))
2316107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			intr_cfg.pa3 = regk_gio_lo;
2326107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		if (tmp & (1 << 4))
2336107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			intr_cfg.pa4 = regk_gio_lo;
2346107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		if (tmp & (1 << 5))
2356107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			intr_cfg.pa5 = regk_gio_lo;
2366107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		if (tmp & (1 << 6))
2376107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			intr_cfg.pa6 = regk_gio_lo;
2386107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		if (tmp & (1 << 7))
2396107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			intr_cfg.pa7 = regk_gio_lo;
2406107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
2416107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		REG_WR(gio, regi_gio, rw_intr_cfg, intr_cfg);
2426107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		local_irq_restore(flags);
2436107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	} else if (priv->minor <= GPIO_MINOR_E)
2446107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		data = *data_in[priv->minor];
2456107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	else
2466107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		return 0;
2476107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
2486107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	if ((data & priv->highalarm) || (~data & priv->lowalarm))
2496107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		mask = POLLIN|POLLRDNORM;
2506107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
2516107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	DP(printk(KERN_DEBUG "gpio_poll ready: mask 0x%08X\n", mask));
2526107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	return mask;
2536107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson}
2546107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
2556107c61fd3e6b47106b078db1726ad814564efefJesper Nilssonint etrax_gpio_wake_up_check(void)
2566107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson{
2576107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	struct gpio_private *priv;
2586107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	unsigned long data = 0;
2596107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	unsigned long flags;
2606107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	int ret = 0;
2616107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	spin_lock_irqsave(&alarm_lock, flags);
2626107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	priv = alarmlist;
2636107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	while (priv) {
2646107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
2656107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		if (priv->minor == GPIO_MINOR_V)
2666107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			data = (unsigned long)cached_virtual_gpio_read;
2676107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		else {
2686107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			data = *data_in[priv->minor];
2696107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			if (priv->minor == GPIO_MINOR_A)
2706107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson				priv->lowalarm |= (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN);
2716107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		}
2726107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#else
2736107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		data = *data_in[priv->minor];
2746107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#endif
2756107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		if ((data & priv->highalarm) ||
2766107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		    (~data & priv->lowalarm)) {
2776107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			DP(printk(KERN_DEBUG
2786107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson				"etrax_gpio_wake_up_check %i\n", priv->minor));
2796107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			wake_up_interruptible(&priv->alarm_wq);
2806107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			ret = 1;
2816107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		}
2826107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		priv = priv->next;
2836107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	}
2846107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	spin_unlock_irqrestore(&alarm_lock, flags);
2856107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	return ret;
2866107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson}
2876107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
2886107c61fd3e6b47106b078db1726ad814564efefJesper Nilssonstatic irqreturn_t
2896107c61fd3e6b47106b078db1726ad814564efefJesper Nilssongpio_poll_timer_interrupt(int irq, void *dev_id)
2906107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson{
2916107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	if (gpio_some_alarms)
2926107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		return IRQ_RETVAL(etrax_gpio_wake_up_check());
2936107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	return IRQ_NONE;
2946107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson}
2956107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
2966107c61fd3e6b47106b078db1726ad814564efefJesper Nilssonstatic irqreturn_t
2976107c61fd3e6b47106b078db1726ad814564efefJesper Nilssongpio_pa_interrupt(int irq, void *dev_id)
2986107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson{
2996107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	reg_gio_rw_intr_mask intr_mask;
3006107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	reg_gio_r_masked_intr masked_intr;
3016107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	reg_gio_rw_ack_intr ack_intr;
3026107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	unsigned long tmp;
3036107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	unsigned long tmp2;
3046107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
3056107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	unsigned char enable_gpiov_ack = 0;
3066107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#endif
3076107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
3086107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	/* Find what PA interrupts are active */
3096107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	masked_intr = REG_RD(gio, regi_gio, r_masked_intr);
3106107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	tmp = REG_TYPE_CONV(unsigned long, reg_gio_r_masked_intr, masked_intr);
3116107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
3126107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	/* Find those that we have enabled */
3136107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	spin_lock(&alarm_lock);
3146107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	tmp &= (gpio_pa_high_alarms | gpio_pa_low_alarms);
3156107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	spin_unlock(&alarm_lock);
3166107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
3176107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
3186107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	/* Something changed on virtual GPIO. Interrupt is acked by
3196107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	 * reading the device.
3206107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	 */
3216107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	if (tmp & (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN)) {
3226107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		i2c_read(VIRT_I2C_ADDR, (void *)&cached_virtual_gpio_read,
3236107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			sizeof(cached_virtual_gpio_read));
3246107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		enable_gpiov_ack = 1;
3256107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	}
3266107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#endif
3276107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
3286107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	/* Ack them */
3296107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	ack_intr = REG_TYPE_CONV(reg_gio_rw_ack_intr, unsigned long, tmp);
3306107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	REG_WR(gio, regi_gio, rw_ack_intr, ack_intr);
3316107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
3326107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	/* Disable those interrupts.. */
3336107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	intr_mask = REG_RD(gio, regi_gio, rw_intr_mask);
3346107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	tmp2 = REG_TYPE_CONV(unsigned long, reg_gio_rw_intr_mask, intr_mask);
3356107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	tmp2 &= ~tmp;
3366107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
3376107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	/* Do not disable interrupt on virtual GPIO. Changes on virtual
3386107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	 * pins are only noticed by an interrupt.
3396107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	 */
3406107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	if (enable_gpiov_ack)
3416107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		tmp2 |= (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN);
3426107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#endif
3436107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	intr_mask = REG_TYPE_CONV(reg_gio_rw_intr_mask, unsigned long, tmp2);
3446107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	REG_WR(gio, regi_gio, rw_intr_mask, intr_mask);
3456107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
3466107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	if (gpio_some_alarms)
3476107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		return IRQ_RETVAL(etrax_gpio_wake_up_check());
3486107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	return IRQ_NONE;
3496107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson}
3506107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
3516107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
3526107c61fd3e6b47106b078db1726ad814564efefJesper Nilssonstatic ssize_t gpio_write(struct file *file, const char *buf, size_t count,
3536107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	loff_t *off)
3546107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson{
35516bc0fe5ce84df89c8e802be210af88721d4cc4fJoe Perches	struct gpio_private *priv = file->private_data;
3566107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	unsigned char data, clk_mask, data_mask, write_msb;
3576107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	unsigned long flags;
3586107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	unsigned long shadow;
3596107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	volatile unsigned long *port;
3606107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	ssize_t retval = count;
3616107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	/* Only bits 0-7 may be used for write operations but allow all
3626107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	   devices except leds... */
3636107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
3646107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	if (priv->minor == GPIO_MINOR_V)
3656107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		return -EFAULT;
3666107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#endif
3676107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	if (priv->minor == GPIO_MINOR_LEDS)
3686107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		return -EFAULT;
3696107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
3706107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	if (!access_ok(VERIFY_READ, buf, count))
3716107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		return -EFAULT;
3726107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	clk_mask = priv->clk_mask;
3736107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	data_mask = priv->data_mask;
3746107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	/* It must have been configured using the IO_CFG_WRITE_MODE */
3756107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	/* Perhaps a better error code? */
3766107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	if (clk_mask == 0 || data_mask == 0)
3776107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		return -EPERM;
3786107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	write_msb = priv->write_msb;
3796107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	D(printk(KERN_DEBUG "gpio_write: %lu to data 0x%02X clk 0x%02X "
3806107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		"msb: %i\n", count, data_mask, clk_mask, write_msb));
3816107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	port = data_out[priv->minor];
3826107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
3836107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	while (count--) {
3846107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		int i;
3856107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		data = *buf++;
3866107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		if (priv->write_msb) {
3876107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			for (i = 7; i >= 0; i--) {
3886107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson				local_irq_save(flags);
3896107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson				shadow = *port;
3906107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson				*port = shadow &= ~clk_mask;
3916107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson				if (data & 1<<i)
3926107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson					*port = shadow |= data_mask;
3936107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson				else
3946107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson					*port = shadow &= ~data_mask;
3956107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			/* For FPGA: min 5.0ns (DCC) before CCLK high */
3966107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson				*port = shadow |= clk_mask;
3976107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson				local_irq_restore(flags);
3986107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			}
3996107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		} else {
4006107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			for (i = 0; i <= 7; i++) {
4016107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson				local_irq_save(flags);
4026107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson				shadow = *port;
4036107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson				*port = shadow &= ~clk_mask;
4046107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson				if (data & 1<<i)
4056107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson					*port = shadow |= data_mask;
4066107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson				else
4076107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson					*port = shadow &= ~data_mask;
4086107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			/* For FPGA: min 5.0ns (DCC) before CCLK high */
4096107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson				*port = shadow |= clk_mask;
4106107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson				local_irq_restore(flags);
4116107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			}
4126107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		}
4136107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	}
4146107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	return retval;
4156107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson}
4166107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
4176107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
4186107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
4196107c61fd3e6b47106b078db1726ad814564efefJesper Nilssonstatic int
4206107c61fd3e6b47106b078db1726ad814564efefJesper Nilssongpio_open(struct inode *inode, struct file *filp)
4216107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson{
4226107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	struct gpio_private *priv;
4236107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	int p = iminor(inode);
4246107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
4256107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	if (p > GPIO_MINOR_LAST)
4266107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		return -EINVAL;
4276107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
4286107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	priv = kmalloc(sizeof(struct gpio_private), GFP_KERNEL);
4296107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	if (!priv)
4306107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		return -ENOMEM;
4310c401df37ef9f45f35390a5574e24cbf3f916acfJonathan Corbet
4320890b5880df6a4989336add11f3a22122b26d9e1Arnd Bergmann	mutex_lock(&gpio_mutex);
4336107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	memset(priv, 0, sizeof(*priv));
4346107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
4356107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	priv->minor = p;
4366107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
4376107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	/* initialize the io/alarm struct */
4386107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
4396107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	priv->clk_mask = 0;
4406107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	priv->data_mask = 0;
4416107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	priv->highalarm = 0;
4426107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	priv->lowalarm = 0;
4436107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	init_waitqueue_head(&priv->alarm_wq);
4446107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
4456107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	filp->private_data = (void *)priv;
4466107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
4476107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	/* link it into our alarmlist */
4486107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	spin_lock_irq(&alarm_lock);
4496107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	priv->next = alarmlist;
4506107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	alarmlist = priv;
4516107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	spin_unlock_irq(&alarm_lock);
4526107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
4530890b5880df6a4989336add11f3a22122b26d9e1Arnd Bergmann	mutex_unlock(&gpio_mutex);
4546107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	return 0;
4556107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson}
4566107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
4576107c61fd3e6b47106b078db1726ad814564efefJesper Nilssonstatic int
4586107c61fd3e6b47106b078db1726ad814564efefJesper Nilssongpio_release(struct inode *inode, struct file *filp)
4596107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson{
4606107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	struct gpio_private *p;
4616107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	struct gpio_private *todel;
4626107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	/* local copies while updating them: */
4636107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	unsigned long a_high, a_low;
4646107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	unsigned long some_alarms;
4656107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
4666107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	/* unlink from alarmlist and free the private structure */
4676107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
4686107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	spin_lock_irq(&alarm_lock);
4696107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	p = alarmlist;
47016bc0fe5ce84df89c8e802be210af88721d4cc4fJoe Perches	todel = filp->private_data;
4716107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
4726107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	if (p == todel) {
4736107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		alarmlist = todel->next;
4746107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	} else {
4756107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		while (p->next != todel)
4766107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			p = p->next;
4776107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		p->next = todel->next;
4786107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	}
4796107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
4806107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	kfree(todel);
4816107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	/* Check if there are still any alarms set */
4826107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	p = alarmlist;
4836107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	some_alarms = 0;
4846107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	a_high = 0;
4856107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	a_low = 0;
4866107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	while (p) {
4876107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		if (p->minor == GPIO_MINOR_A) {
4886107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
4896107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			p->lowalarm |= (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN);
4906107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#endif
4916107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			a_high |= p->highalarm;
4926107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			a_low |= p->lowalarm;
4936107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		}
4946107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
4956107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		if (p->highalarm | p->lowalarm)
4966107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			some_alarms = 1;
4976107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		p = p->next;
4986107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	}
4996107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
5006107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
5016107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	/* Variables 'some_alarms' and 'a_low' needs to be set here again
5026107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	 * to ensure that interrupt for virtual GPIO is handled.
5036107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	 */
5046107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	some_alarms = 1;
5056107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	a_low |= (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN);
5066107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#endif
5076107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
5086107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	gpio_some_alarms = some_alarms;
5096107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	gpio_pa_high_alarms = a_high;
5106107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	gpio_pa_low_alarms = a_low;
5116107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	spin_unlock_irq(&alarm_lock);
5126107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
5136107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	return 0;
5146107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson}
5156107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
5166107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson/* Main device API. ioctl's to read/set/clear bits, as well as to
5176107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson * set alarms to wait for using a subsequent select().
5186107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson */
5196107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
5206107c61fd3e6b47106b078db1726ad814564efefJesper Nilssoninline unsigned long setget_input(struct gpio_private *priv, unsigned long arg)
5216107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson{
5226107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	/* Set direction 0=unchanged 1=input,
5236107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	 * return mask with 1=input
5246107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	 */
5256107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	unsigned long flags;
5266107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	unsigned long dir_shadow;
5276107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
5286107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	local_irq_save(flags);
5296107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	dir_shadow = *dir_oe[priv->minor];
5306107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	dir_shadow &= ~(arg & changeable_dir[priv->minor]);
5316107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	*dir_oe[priv->minor] = dir_shadow;
5326107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	local_irq_restore(flags);
5336107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
5346107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	if (priv->minor == GPIO_MINOR_A)
5356107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		dir_shadow ^= 0xFF;    /* Only 8 bits */
5366107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
5376107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	else if (priv->minor == GPIO_MINOR_V)
5386107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		dir_shadow ^= 0xFFFF;  /* Only 16 bits */
5396107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#endif
5406107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	else
5416107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		dir_shadow ^= 0x3FFFF; /* Only 18 bits */
5426107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	return dir_shadow;
5436107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
5446107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson} /* setget_input */
5456107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
5466107c61fd3e6b47106b078db1726ad814564efefJesper Nilssoninline unsigned long setget_output(struct gpio_private *priv, unsigned long arg)
5476107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson{
5486107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	unsigned long flags;
5496107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	unsigned long dir_shadow;
5506107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
5516107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	local_irq_save(flags);
5526107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	dir_shadow = *dir_oe[priv->minor];
5536107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	dir_shadow |=  (arg & changeable_dir[priv->minor]);
5546107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	*dir_oe[priv->minor] = dir_shadow;
5556107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	local_irq_restore(flags);
5566107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	return dir_shadow;
5576107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson} /* setget_output */
5586107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
55990276a1a64e2ab732e26e3ac68febbf3ad04c517Jesper Nilssonstatic int gpio_leds_ioctl(unsigned int cmd, unsigned long arg);
5606107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
5616107c61fd3e6b47106b078db1726ad814564efefJesper Nilssonstatic int
56290276a1a64e2ab732e26e3ac68febbf3ad04c517Jesper Nilssongpio_ioctl_unlocked(struct file *file, unsigned int cmd, unsigned long arg)
5636107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson{
5646107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	unsigned long flags;
5656107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	unsigned long val;
5666107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	unsigned long shadow;
56716bc0fe5ce84df89c8e802be210af88721d4cc4fJoe Perches	struct gpio_private *priv = file->private_data;
5686107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	if (_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE)
5696107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		return -EINVAL;
5706107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
5716107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
5726107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	if (priv->minor == GPIO_MINOR_V)
5736107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		return virtual_gpio_ioctl(file, cmd, arg);
5746107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#endif
5756107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
5766107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	switch (_IOC_NR(cmd)) {
5776107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	case IO_READBITS: /* Use IO_READ_INBITS and IO_READ_OUTBITS instead */
5786107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		/* Read the port. */
5796107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		return *data_in[priv->minor];
5806107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		break;
5816107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	case IO_SETBITS:
5826107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		local_irq_save(flags);
5836107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		/* Set changeable bits with a 1 in arg. */
5846107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		shadow = *data_out[priv->minor];
5856107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		shadow |=  (arg & changeable_bits[priv->minor]);
5866107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		*data_out[priv->minor] = shadow;
5876107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		local_irq_restore(flags);
5886107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		break;
5896107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	case IO_CLRBITS:
5906107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		local_irq_save(flags);
5916107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		/* Clear changeable bits with a 1 in arg. */
5926107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		shadow = *data_out[priv->minor];
5936107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		shadow &=  ~(arg & changeable_bits[priv->minor]);
5946107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		*data_out[priv->minor] = shadow;
5956107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		local_irq_restore(flags);
5966107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		break;
5976107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	case IO_HIGHALARM:
5986107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		/* Set alarm when bits with 1 in arg go high. */
5996107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		priv->highalarm |= arg;
6006107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		spin_lock_irqsave(&alarm_lock, flags);
6016107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		gpio_some_alarms = 1;
6026107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		if (priv->minor == GPIO_MINOR_A)
6036107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			gpio_pa_high_alarms |= arg;
6046107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		spin_unlock_irqrestore(&alarm_lock, flags);
6056107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		break;
6066107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	case IO_LOWALARM:
6076107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		/* Set alarm when bits with 1 in arg go low. */
6086107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		priv->lowalarm |= arg;
6096107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		spin_lock_irqsave(&alarm_lock, flags);
6106107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		gpio_some_alarms = 1;
6116107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		if (priv->minor == GPIO_MINOR_A)
6126107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			gpio_pa_low_alarms |= arg;
6136107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		spin_unlock_irqrestore(&alarm_lock, flags);
6146107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		break;
6156107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	case IO_CLRALARM:
6166107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		/* Clear alarm for bits with 1 in arg. */
6176107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		priv->highalarm &= ~arg;
6186107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		priv->lowalarm  &= ~arg;
6196107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		spin_lock_irqsave(&alarm_lock, flags);
6206107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		if (priv->minor == GPIO_MINOR_A) {
6216107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			if (gpio_pa_high_alarms & arg ||
6226107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			    gpio_pa_low_alarms & arg)
6236107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson				/* Must update the gpio_pa_*alarms masks */
6246107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson				;
6256107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		}
6266107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		spin_unlock_irqrestore(&alarm_lock, flags);
6276107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		break;
6286107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	case IO_READDIR: /* Use IO_SETGET_INPUT/OUTPUT instead! */
6296107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		/* Read direction 0=input 1=output */
6306107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		return *dir_oe[priv->minor];
6316107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	case IO_SETINPUT: /* Use IO_SETGET_INPUT instead! */
6326107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		/* Set direction 0=unchanged 1=input,
6336107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		 * return mask with 1=input
6346107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		 */
6356107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		return setget_input(priv, arg);
6366107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		break;
6376107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	case IO_SETOUTPUT: /* Use IO_SETGET_OUTPUT instead! */
6386107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		/* Set direction 0=unchanged 1=output,
6396107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		 * return mask with 1=output
6406107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		 */
6416107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		return setget_output(priv, arg);
6426107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
6436107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	case IO_CFG_WRITE_MODE:
6446107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	{
6456107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		unsigned long dir_shadow;
6466107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		dir_shadow = *dir_oe[priv->minor];
6476107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
6486107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		priv->clk_mask = arg & 0xFF;
6496107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		priv->data_mask = (arg >> 8) & 0xFF;
6506107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		priv->write_msb = (arg >> 16) & 0x01;
6516107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		/* Check if we're allowed to change the bits and
6526107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		 * the direction is correct
6536107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		 */
6546107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		if (!((priv->clk_mask & changeable_bits[priv->minor]) &&
6556107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		      (priv->data_mask & changeable_bits[priv->minor]) &&
6566107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		      (priv->clk_mask & dir_shadow) &&
6576107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		      (priv->data_mask & dir_shadow))) {
6586107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			priv->clk_mask = 0;
6596107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			priv->data_mask = 0;
6606107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			return -EPERM;
6616107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		}
6626107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		break;
6636107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	}
6646107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	case IO_READ_INBITS:
6656107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		/* *arg is result of reading the input pins */
6666107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		val = *data_in[priv->minor];
6676107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		if (copy_to_user((unsigned long *)arg, &val, sizeof(val)))
6686107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			return -EFAULT;
6696107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		return 0;
6706107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		break;
6716107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	case IO_READ_OUTBITS:
6726107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		 /* *arg is result of reading the output shadow */
6736107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		val = *data_out[priv->minor];
6746107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		if (copy_to_user((unsigned long *)arg, &val, sizeof(val)))
6756107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			return -EFAULT;
6766107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		break;
6776107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	case IO_SETGET_INPUT:
6786107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		/* bits set in *arg is set to input,
6796107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		 * *arg updated with current input pins.
6806107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		 */
6816107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		if (copy_from_user(&val, (unsigned long *)arg, sizeof(val)))
6826107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			return -EFAULT;
6836107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		val = setget_input(priv, val);
6846107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		if (copy_to_user((unsigned long *)arg, &val, sizeof(val)))
6856107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			return -EFAULT;
6866107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		break;
6876107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	case IO_SETGET_OUTPUT:
6886107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		/* bits set in *arg is set to output,
6896107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		 * *arg updated with current output pins.
6906107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		 */
6916107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		if (copy_from_user(&val, (unsigned long *)arg, sizeof(val)))
6926107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			return -EFAULT;
6936107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		val = setget_output(priv, val);
6946107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		if (copy_to_user((unsigned long *)arg, &val, sizeof(val)))
6956107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			return -EFAULT;
6966107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		break;
6976107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	default:
6986107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		if (priv->minor == GPIO_MINOR_LEDS)
6996107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			return gpio_leds_ioctl(cmd, arg);
7006107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		else
7016107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			return -EINVAL;
7026107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	} /* switch */
7036107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
7046107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	return 0;
7056107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson}
7066107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
70790276a1a64e2ab732e26e3ac68febbf3ad04c517Jesper Nilssonstatic long gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
70890276a1a64e2ab732e26e3ac68febbf3ad04c517Jesper Nilsson{
70990276a1a64e2ab732e26e3ac68febbf3ad04c517Jesper Nilsson       long ret;
71090276a1a64e2ab732e26e3ac68febbf3ad04c517Jesper Nilsson
7110890b5880df6a4989336add11f3a22122b26d9e1Arnd Bergmann       mutex_lock(&gpio_mutex);
71290276a1a64e2ab732e26e3ac68febbf3ad04c517Jesper Nilsson       ret = gpio_ioctl_unlocked(file, cmd, arg);
7130890b5880df6a4989336add11f3a22122b26d9e1Arnd Bergmann       mutex_unlock(&gpio_mutex);
71490276a1a64e2ab732e26e3ac68febbf3ad04c517Jesper Nilsson
71590276a1a64e2ab732e26e3ac68febbf3ad04c517Jesper Nilsson       return ret;
71690276a1a64e2ab732e26e3ac68febbf3ad04c517Jesper Nilsson}
71790276a1a64e2ab732e26e3ac68febbf3ad04c517Jesper Nilsson
7186107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
7196107c61fd3e6b47106b078db1726ad814564efefJesper Nilssonstatic int
7206107c61fd3e6b47106b078db1726ad814564efefJesper Nilssonvirtual_gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
7216107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson{
7226107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	unsigned long flags;
7236107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	unsigned short val;
7246107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	unsigned short shadow;
72516bc0fe5ce84df89c8e802be210af88721d4cc4fJoe Perches	struct gpio_private *priv = file->private_data;
7266107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
7276107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	switch (_IOC_NR(cmd)) {
7286107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	case IO_SETBITS:
7296107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		local_irq_save(flags);
7306107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		/* Set changeable bits with a 1 in arg. */
7316107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		i2c_read(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow));
7326107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		shadow |= ~*dir_oe[priv->minor];
7336107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		shadow |= (arg & changeable_bits[priv->minor]);
7346107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		i2c_write(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow));
7356107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		local_irq_restore(flags);
7366107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		break;
7376107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	case IO_CLRBITS:
7386107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		local_irq_save(flags);
7396107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		/* Clear changeable bits with a 1 in arg. */
7406107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		i2c_read(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow));
7416107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		shadow |= ~*dir_oe[priv->minor];
7426107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		shadow &= ~(arg & changeable_bits[priv->minor]);
7436107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		i2c_write(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow));
7446107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		local_irq_restore(flags);
7456107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		break;
7466107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	case IO_HIGHALARM:
7476107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		/* Set alarm when bits with 1 in arg go high. */
7486107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		priv->highalarm |= arg;
7496107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		spin_lock(&alarm_lock);
7506107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		gpio_some_alarms = 1;
7516107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		spin_unlock(&alarm_lock);
7526107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		break;
7536107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	case IO_LOWALARM:
7546107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		/* Set alarm when bits with 1 in arg go low. */
7556107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		priv->lowalarm |= arg;
7566107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		spin_lock(&alarm_lock);
7576107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		gpio_some_alarms = 1;
7586107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		spin_unlock(&alarm_lock);
7596107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		break;
7606107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	case IO_CLRALARM:
7616107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		/* Clear alarm for bits with 1 in arg. */
7626107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		priv->highalarm &= ~arg;
7636107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		priv->lowalarm  &= ~arg;
7646107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		spin_lock(&alarm_lock);
7656107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		spin_unlock(&alarm_lock);
7666107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		break;
7676107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	case IO_CFG_WRITE_MODE:
7686107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	{
7696107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		unsigned long dir_shadow;
7706107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		dir_shadow = *dir_oe[priv->minor];
7716107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
7726107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		priv->clk_mask = arg & 0xFF;
7736107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		priv->data_mask = (arg >> 8) & 0xFF;
7746107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		priv->write_msb = (arg >> 16) & 0x01;
7756107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		/* Check if we're allowed to change the bits and
7766107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		 * the direction is correct
7776107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		 */
7786107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		if (!((priv->clk_mask & changeable_bits[priv->minor]) &&
7796107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		      (priv->data_mask & changeable_bits[priv->minor]) &&
7806107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		      (priv->clk_mask & dir_shadow) &&
7816107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		      (priv->data_mask & dir_shadow))) {
7826107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			priv->clk_mask = 0;
7836107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			priv->data_mask = 0;
7846107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			return -EPERM;
7856107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		}
7866107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		break;
7876107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	}
7886107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	case IO_READ_INBITS:
7896107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		/* *arg is result of reading the input pins */
7906107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		val = cached_virtual_gpio_read;
7916107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		val &= ~*dir_oe[priv->minor];
7926107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		if (copy_to_user((unsigned long *)arg, &val, sizeof(val)))
7936107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			return -EFAULT;
7946107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		return 0;
7956107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		break;
7966107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	case IO_READ_OUTBITS:
7976107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		 /* *arg is result of reading the output shadow */
7986107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		i2c_read(VIRT_I2C_ADDR, (void *)&val, sizeof(val));
7996107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		val &= *dir_oe[priv->minor];
8006107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		if (copy_to_user((unsigned long *)arg, &val, sizeof(val)))
8016107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			return -EFAULT;
8026107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		break;
8036107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	case IO_SETGET_INPUT:
8046107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	{
8056107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		/* bits set in *arg is set to input,
8066107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		 * *arg updated with current input pins.
8076107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		 */
8086107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		unsigned short input_mask = ~*dir_oe[priv->minor];
8096107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		if (copy_from_user(&val, (unsigned long *)arg, sizeof(val)))
8106107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			return -EFAULT;
8116107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		val = setget_input(priv, val);
8126107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		if (copy_to_user((unsigned long *)arg, &val, sizeof(val)))
8136107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			return -EFAULT;
8146107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		if ((input_mask & val) != input_mask) {
8156107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			/* Input pins changed. All ports desired as input
8166107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			 * should be set to logic 1.
8176107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			 */
8186107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			unsigned short change = input_mask ^ val;
8196107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			i2c_read(VIRT_I2C_ADDR, (void *)&shadow,
8206107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson				sizeof(shadow));
8216107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			shadow &= ~change;
8226107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			shadow |= val;
8236107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			i2c_write(VIRT_I2C_ADDR, (void *)&shadow,
8246107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson				sizeof(shadow));
8256107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		}
8266107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		break;
8276107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	}
8286107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	case IO_SETGET_OUTPUT:
8296107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		/* bits set in *arg is set to output,
8306107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		 * *arg updated with current output pins.
8316107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		 */
8326107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		if (copy_from_user(&val, (unsigned long *)arg, sizeof(val)))
8336107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			return -EFAULT;
8346107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		val = setget_output(priv, val);
8356107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		if (copy_to_user((unsigned long *)arg, &val, sizeof(val)))
8366107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			return -EFAULT;
8376107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		break;
8386107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	default:
8396107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		return -EINVAL;
8406107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	} /* switch */
8416107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson  return 0;
8426107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson}
8436107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#endif /* CONFIG_ETRAX_VIRTUAL_GPIO */
8446107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
8456107c61fd3e6b47106b078db1726ad814564efefJesper Nilssonstatic int
8466107c61fd3e6b47106b078db1726ad814564efefJesper Nilssongpio_leds_ioctl(unsigned int cmd, unsigned long arg)
8476107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson{
8486107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	unsigned char green;
8496107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	unsigned char red;
8506107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
8516107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	switch (_IOC_NR(cmd)) {
8526107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	case IO_LEDACTIVE_SET:
8536107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		green = ((unsigned char) arg) & 1;
8546107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		red   = (((unsigned char) arg) >> 1) & 1;
8552c30da717586a137b90c245820657a0d0a3a0a67Jesper Nilsson		CRIS_LED_ACTIVE_SET_G(green);
8562c30da717586a137b90c245820657a0d0a3a0a67Jesper Nilsson		CRIS_LED_ACTIVE_SET_R(red);
8576107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		break;
8586107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
8596107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	default:
8606107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		return -EINVAL;
8616107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	} /* switch */
8626107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
8636107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	return 0;
8646107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson}
8656107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
866828c09509b9695271bcbdc53e9fc9a6a737148d2Alexey Dobriyanstatic const struct file_operations gpio_fops = {
86790276a1a64e2ab732e26e3ac68febbf3ad04c517Jesper Nilsson	.owner		= THIS_MODULE,
86890276a1a64e2ab732e26e3ac68febbf3ad04c517Jesper Nilsson	.poll		= gpio_poll,
86990276a1a64e2ab732e26e3ac68febbf3ad04c517Jesper Nilsson	.unlocked_ioctl	= gpio_ioctl,
87090276a1a64e2ab732e26e3ac68febbf3ad04c517Jesper Nilsson	.write		= gpio_write,
87190276a1a64e2ab732e26e3ac68febbf3ad04c517Jesper Nilsson	.open		= gpio_open,
87290276a1a64e2ab732e26e3ac68febbf3ad04c517Jesper Nilsson	.release	= gpio_release,
8736038f373a3dc1f1c26496e60b6c40b164716f07eArnd Bergmann	.llseek		= noop_llseek,
8746107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson};
8756107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
8766107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
8776107c61fd3e6b47106b078db1726ad814564efefJesper Nilssonstatic void
8786107c61fd3e6b47106b078db1726ad814564efefJesper Nilssonvirtual_gpio_init(void)
8796107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson{
8806107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	reg_gio_rw_intr_cfg intr_cfg;
8816107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	reg_gio_rw_intr_mask intr_mask;
8826107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	unsigned short shadow;
8836107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
8846107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	shadow = ~virtual_rw_pv_oe; /* Input ports should be set to logic 1 */
8856107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	shadow |= CONFIG_ETRAX_DEF_GIO_PV_OUT;
8866107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	i2c_write(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow));
8876107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
8886107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	/* Set interrupt mask and on what state the interrupt shall trigger.
8896107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	 * For virtual gpio the interrupt shall trigger on logic '0'.
8906107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	 */
8916107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	intr_cfg = REG_RD(gio, regi_gio, rw_intr_cfg);
8926107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	intr_mask = REG_RD(gio, regi_gio, rw_intr_mask);
8936107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
8946107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	switch (CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN) {
8956107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	case 0:
8966107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		intr_cfg.pa0 = regk_gio_lo;
8976107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		intr_mask.pa0 = regk_gio_yes;
8986107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		break;
8996107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	case 1:
9006107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		intr_cfg.pa1 = regk_gio_lo;
9016107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		intr_mask.pa1 = regk_gio_yes;
9026107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		break;
9036107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	case 2:
9046107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		intr_cfg.pa2 = regk_gio_lo;
9056107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		intr_mask.pa2 = regk_gio_yes;
9066107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		break;
9076107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	case 3:
9086107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		intr_cfg.pa3 = regk_gio_lo;
9096107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		intr_mask.pa3 = regk_gio_yes;
9106107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		break;
9116107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	case 4:
9126107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		intr_cfg.pa4 = regk_gio_lo;
9136107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		intr_mask.pa4 = regk_gio_yes;
9146107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		break;
9156107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	case 5:
9166107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		intr_cfg.pa5 = regk_gio_lo;
9176107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		intr_mask.pa5 = regk_gio_yes;
9186107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		break;
9196107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	case 6:
9206107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		intr_cfg.pa6 = regk_gio_lo;
9216107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		intr_mask.pa6 = regk_gio_yes;
9226107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		break;
9236107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	case 7:
9246107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		intr_cfg.pa7 = regk_gio_lo;
9256107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		intr_mask.pa7 = regk_gio_yes;
9266107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	break;
9276107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	}
9286107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
9296107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	REG_WR(gio, regi_gio, rw_intr_cfg, intr_cfg);
9306107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	REG_WR(gio, regi_gio, rw_intr_mask, intr_mask);
9316107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
9326107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	gpio_pa_low_alarms |= (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN);
9336107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	gpio_some_alarms = 1;
9346107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson}
9356107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#endif
9366107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
9376107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson/* main driver initialization routine, called from mem.c */
9386107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
9396107c61fd3e6b47106b078db1726ad814564efefJesper Nilssonstatic __init int
9406107c61fd3e6b47106b078db1726ad814564efefJesper Nilssongpio_init(void)
9416107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson{
9426107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	int res;
9436107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
9446107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	/* do the formalities */
9456107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
9466107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	res = register_chrdev(GPIO_MAJOR, gpio_name, &gpio_fops);
9476107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	if (res < 0) {
9486107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		printk(KERN_ERR "gpio: couldn't get a major number.\n");
9496107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		return res;
9506107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	}
9516107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
9526107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	/* Clear all leds */
9532c30da717586a137b90c245820657a0d0a3a0a67Jesper Nilsson	CRIS_LED_NETWORK_GRP0_SET(0);
9542c30da717586a137b90c245820657a0d0a3a0a67Jesper Nilsson	CRIS_LED_NETWORK_GRP1_SET(0);
9552c30da717586a137b90c245820657a0d0a3a0a67Jesper Nilsson	CRIS_LED_ACTIVE_SET(0);
9562c30da717586a137b90c245820657a0d0a3a0a67Jesper Nilsson	CRIS_LED_DISK_READ(0);
9572c30da717586a137b90c245820657a0d0a3a0a67Jesper Nilsson	CRIS_LED_DISK_WRITE(0);
9586107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
9596107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	printk(KERN_INFO "ETRAX FS GPIO driver v2.5, (c) 2003-2007 "
9606107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		"Axis Communications AB\n");
9616107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	/* We call etrax_gpio_wake_up_check() from timer interrupt and
9626107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	 * from cpu_idle() in kernel/process.c
9636107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	 * The check in cpu_idle() reduces latency from ~15 ms to ~6 ms
9646107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	 * in some tests.
9656107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	 */
9666107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	if (request_irq(TIMER0_INTR_VECT, gpio_poll_timer_interrupt,
9676107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			IRQF_SHARED | IRQF_DISABLED, "gpio poll", &alarmlist))
9686107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		printk(KERN_ERR "timer0 irq for gpio\n");
9696107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
9706107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	if (request_irq(GIO_INTR_VECT, gpio_pa_interrupt,
9716107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson			IRQF_SHARED | IRQF_DISABLED, "gpio PA", &alarmlist))
9726107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson		printk(KERN_ERR "PA irq for gpio\n");
9736107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
9746107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
9756107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	virtual_gpio_init();
9766107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson#endif
9776107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
9786107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson	return res;
9796107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson}
9806107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
9816107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson/* this makes sure that gpio_init is called during kernel boot */
9826107c61fd3e6b47106b078db1726ad814564efefJesper Nilsson
9836107c61fd3e6b47106b078db1726ad814564efefJesper Nilssonmodule_init(gpio_init);
984