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