Commit 7e920426 authored by Mikael Starvik's avatar Mikael Starvik Committed by Linus Torvalds

[PATCH] CRIS update: drivers

Updates to device drivers.

* Use I/O and DMA allocators.
* Use wait_event_interruptible instead of interrutiple_sleep_on.
* Added spinlocks SMP.
* Changed restore_flags to local_irq_restore etc.
* Updated IDE driver include to fit 2.6.12.
Signed-off-by: default avatarMikael Starvik <starvik@axis.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 059163ca
...@@ -11,6 +11,9 @@ ...@@ -11,6 +11,9 @@
* partition split defined below. * partition split defined below.
* *
* $Log: axisflashmap.c,v $ * $Log: axisflashmap.c,v $
* Revision 1.11 2004/11/15 10:27:14 starvik
* Corrected typo (Thanks to Milton Miller <miltonm@bga.com>).
*
* Revision 1.10 2004/08/16 12:37:22 starvik * Revision 1.10 2004/08/16 12:37:22 starvik
* Merge of Linux 2.6.8 * Merge of Linux 2.6.8
* *
...@@ -161,7 +164,7 @@ ...@@ -161,7 +164,7 @@
#elif CONFIG_ETRAX_FLASH_BUSWIDTH==2 #elif CONFIG_ETRAX_FLASH_BUSWIDTH==2
#define flash_data __u16 #define flash_data __u16
#elif CONFIG_ETRAX_FLASH_BUSWIDTH==4 #elif CONFIG_ETRAX_FLASH_BUSWIDTH==4
#define flash_data __u16 #define flash_data __u32
#endif #endif
/* From head.S */ /* From head.S */
......
...@@ -7,6 +7,15 @@ ...@@ -7,6 +7,15 @@
*! Functions exported: ds1302_readreg, ds1302_writereg, ds1302_init *! Functions exported: ds1302_readreg, ds1302_writereg, ds1302_init
*! *!
*! $Log: ds1302.c,v $ *! $Log: ds1302.c,v $
*! Revision 1.18 2005/01/24 09:11:26 mikaelam
*! Minor changes to get DS1302 RTC chip driver to work
*!
*! Revision 1.17 2005/01/05 06:11:22 starvik
*! No need to do local_irq_disable after local_irq_save.
*!
*! Revision 1.16 2004/12/13 12:21:52 starvik
*! Added I/O and DMA allocators from Linux 2.4
*!
*! Revision 1.14 2004/08/24 06:48:43 starvik *! Revision 1.14 2004/08/24 06:48:43 starvik
*! Whitespace cleanup *! Whitespace cleanup
*! *!
...@@ -124,9 +133,9 @@ ...@@ -124,9 +133,9 @@
*! *!
*! --------------------------------------------------------------------------- *! ---------------------------------------------------------------------------
*! *!
*! (C) Copyright 1999, 2000, 2001 Axis Communications AB, LUND, SWEDEN *! (C) Copyright 1999, 2000, 2001, 2002, 2003, 2004 Axis Communications AB, LUND, SWEDEN
*! *!
*! $Id: ds1302.c,v 1.14 2004/08/24 06:48:43 starvik Exp $ *! $Id: ds1302.c,v 1.18 2005/01/24 09:11:26 mikaelam Exp $
*! *!
*!***************************************************************************/ *!***************************************************************************/
...@@ -145,6 +154,7 @@ ...@@ -145,6 +154,7 @@
#include <asm/arch/svinto.h> #include <asm/arch/svinto.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/rtc.h> #include <asm/rtc.h>
#include <asm/arch/io_interface_mux.h>
#define RTC_MAJOR_NR 121 /* local major, change later */ #define RTC_MAJOR_NR 121 /* local major, change later */
...@@ -320,7 +330,6 @@ get_rtc_time(struct rtc_time *rtc_tm) ...@@ -320,7 +330,6 @@ get_rtc_time(struct rtc_time *rtc_tm)
unsigned long flags; unsigned long flags;
local_irq_save(flags); local_irq_save(flags);
local_irq_disable();
rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS); rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS);
rtc_tm->tm_min = CMOS_READ(RTC_MINUTES); rtc_tm->tm_min = CMOS_READ(RTC_MINUTES);
...@@ -419,7 +428,6 @@ rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, ...@@ -419,7 +428,6 @@ rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
BIN_TO_BCD(yrs); BIN_TO_BCD(yrs);
local_irq_save(flags); local_irq_save(flags);
local_irq_disable();
CMOS_WRITE(yrs, RTC_YEAR); CMOS_WRITE(yrs, RTC_YEAR);
CMOS_WRITE(mon, RTC_MONTH); CMOS_WRITE(mon, RTC_MONTH);
CMOS_WRITE(day, RTC_DAY_OF_MONTH); CMOS_WRITE(day, RTC_DAY_OF_MONTH);
...@@ -548,7 +556,9 @@ ds1302_probe(void) ...@@ -548,7 +556,9 @@ ds1302_probe(void)
int __init int __init
ds1302_init(void) ds1302_init(void)
{ {
#ifdef CONFIG_ETRAX_I2C
i2c_init(); i2c_init();
#endif
if (!ds1302_probe()) { if (!ds1302_probe()) {
#ifdef CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT #ifdef CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT
...@@ -558,11 +568,28 @@ ds1302_init(void) ...@@ -558,11 +568,28 @@ ds1302_init(void)
* *
* Make sure that R_GEN_CONFIG is setup correct. * Make sure that R_GEN_CONFIG is setup correct.
*/ */
genconfig_shadow = ((genconfig_shadow & /* Allocating the ATA interface will grab almost all
~IO_MASK(R_GEN_CONFIG, ata)) | * pins in I/O groups a, b, c and d. A consequence of
(IO_STATE(R_GEN_CONFIG, ata, select))); * allocating the ATA interface is that the fixed
*R_GEN_CONFIG = genconfig_shadow; * interfaces shared RAM, parallel port 0, parallel
* port 1, parallel port W, SCSI-8 port 0, SCSI-8 port
* 1, SCSI-W, serial port 2, serial port 3,
* synchronous serial port 3 and USB port 2 and almost
* all GPIO pins on port g cannot be used.
*/
if (cris_request_io_interface(if_ata, "ds1302/ATA")) {
printk(KERN_WARNING "ds1302: Failed to get IO interface\n");
return -1;
}
#elif CONFIG_ETRAX_DS1302_RSTBIT == 0 #elif CONFIG_ETRAX_DS1302_RSTBIT == 0
if (cris_io_interface_allocate_pins(if_gpio_grp_a,
'g',
CONFIG_ETRAX_DS1302_RSTBIT,
CONFIG_ETRAX_DS1302_RSTBIT)) {
printk(KERN_WARNING "ds1302: Failed to get IO interface\n");
return -1;
}
/* Set the direction of this bit to out. */ /* Set the direction of this bit to out. */
genconfig_shadow = ((genconfig_shadow & genconfig_shadow = ((genconfig_shadow &
......
...@@ -20,6 +20,12 @@ ...@@ -20,6 +20,12 @@
*! in the spin-lock. *! in the spin-lock.
*! *!
*! $Log: eeprom.c,v $ *! $Log: eeprom.c,v $
*! Revision 1.12 2005/06/19 17:06:46 starvik
*! Merge of Linux 2.6.12.
*!
*! Revision 1.11 2005/01/26 07:14:46 starvik
*! Applied diff from kernel janitors (Nish Aravamudan).
*!
*! Revision 1.10 2003/09/11 07:29:48 starvik *! Revision 1.10 2003/09/11 07:29:48 starvik
*! Merge of Linux 2.6.0-test5 *! Merge of Linux 2.6.0-test5
*! *!
...@@ -94,6 +100,7 @@ ...@@ -94,6 +100,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/wait.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include "i2c.h" #include "i2c.h"
...@@ -526,15 +533,10 @@ static ssize_t eeprom_read(struct file * file, char * buf, size_t count, loff_t ...@@ -526,15 +533,10 @@ static ssize_t eeprom_read(struct file * file, char * buf, size_t count, loff_t
return -EFAULT; return -EFAULT;
} }
while(eeprom.busy) wait_event_interruptible(eeprom.wait_q, !eeprom.busy);
{
interruptible_sleep_on(&eeprom.wait_q);
/* bail out if we get interrupted */
if (signal_pending(current)) if (signal_pending(current))
return -EINTR; return -EINTR;
}
eeprom.busy++; eeprom.busy++;
page = (unsigned char) (p >> 8); page = (unsigned char) (p >> 8);
...@@ -604,13 +606,10 @@ static ssize_t eeprom_write(struct file * file, const char * buf, size_t count, ...@@ -604,13 +606,10 @@ static ssize_t eeprom_write(struct file * file, const char * buf, size_t count,
return -EFAULT; return -EFAULT;
} }
while(eeprom.busy) wait_event_interruptible(eeprom.wait_q, !eeprom.busy);
{
interruptible_sleep_on(&eeprom.wait_q);
/* bail out if we get interrupted */ /* bail out if we get interrupted */
if (signal_pending(current)) if (signal_pending(current))
return -EINTR; return -EINTR;
}
eeprom.busy++; eeprom.busy++;
for(i = 0; (i < EEPROM_RETRIES) && (restart > 0); i++) for(i = 0; (i < EEPROM_RETRIES) && (restart > 0); i++)
{ {
......
/* $Id: gpio.c,v 1.12 2004/08/24 07:19:59 starvik Exp $ /* $Id: gpio.c,v 1.17 2005/06/19 17:06:46 starvik Exp $
* *
* Etrax general port I/O device * Etrax general port I/O device
* *
...@@ -9,6 +9,18 @@ ...@@ -9,6 +9,18 @@
* Johan Adolfsson (read/set directions, write, port G) * Johan Adolfsson (read/set directions, write, port G)
* *
* $Log: gpio.c,v $ * $Log: gpio.c,v $
* Revision 1.17 2005/06/19 17:06:46 starvik
* Merge of Linux 2.6.12.
*
* Revision 1.16 2005/03/07 13:02:29 starvik
* Protect driver global states with spinlock
*
* Revision 1.15 2005/01/05 06:08:55 starvik
* No need to do local_irq_disable after local_irq_save.
*
* Revision 1.14 2004/12/13 12:21:52 starvik
* Added I/O and DMA allocators from Linux 2.4
*
* Revision 1.12 2004/08/24 07:19:59 starvik * Revision 1.12 2004/08/24 07:19:59 starvik
* Whitespace cleanup * Whitespace cleanup
* *
...@@ -142,6 +154,7 @@ ...@@ -142,6 +154,7 @@
#include <asm/io.h> #include <asm/io.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/arch/io_interface_mux.h>
#define GPIO_MAJOR 120 /* experimental MAJOR number */ #define GPIO_MAJOR 120 /* experimental MAJOR number */
...@@ -194,6 +207,8 @@ static struct gpio_private *alarmlist = 0; ...@@ -194,6 +207,8 @@ static struct gpio_private *alarmlist = 0;
static int gpio_some_alarms = 0; /* Set if someone uses alarm */ static int gpio_some_alarms = 0; /* Set if someone uses alarm */
static unsigned long gpio_pa_irq_enabled_mask = 0; static unsigned long gpio_pa_irq_enabled_mask = 0;
static DEFINE_SPINLOCK(gpio_lock); /* Protect directions etc */
/* Port A and B use 8 bit access, but Port G is 32 bit */ /* Port A and B use 8 bit access, but Port G is 32 bit */
#define NUM_PORTS (GPIO_MINOR_B+1) #define NUM_PORTS (GPIO_MINOR_B+1)
...@@ -241,6 +256,9 @@ static volatile unsigned char *dir_shadow[NUM_PORTS] = { ...@@ -241,6 +256,9 @@ static volatile unsigned char *dir_shadow[NUM_PORTS] = {
&port_pb_dir_shadow &port_pb_dir_shadow
}; };
/* All bits in port g that can change dir. */
static const unsigned long int changeable_dir_g_mask = 0x01FFFF01;
/* Port G is 32 bit, handle it special, some bits are both inputs /* Port G is 32 bit, handle it special, some bits are both inputs
and outputs at the same time, only some of the bits can change direction and outputs at the same time, only some of the bits can change direction
and some of them in groups of 8 bit. */ and some of them in groups of 8 bit. */
...@@ -260,6 +278,7 @@ gpio_poll(struct file *file, ...@@ -260,6 +278,7 @@ gpio_poll(struct file *file,
unsigned int mask = 0; unsigned int mask = 0;
struct gpio_private *priv = (struct gpio_private *)file->private_data; struct gpio_private *priv = (struct gpio_private *)file->private_data;
unsigned long data; unsigned long data;
spin_lock(&gpio_lock);
poll_wait(file, &priv->alarm_wq, wait); poll_wait(file, &priv->alarm_wq, wait);
if (priv->minor == GPIO_MINOR_A) { if (priv->minor == GPIO_MINOR_A) {
unsigned long flags; unsigned long flags;
...@@ -270,10 +289,10 @@ gpio_poll(struct file *file, ...@@ -270,10 +289,10 @@ gpio_poll(struct file *file,
*/ */
tmp = ~data & priv->highalarm & 0xFF; tmp = ~data & priv->highalarm & 0xFF;
tmp = (tmp << R_IRQ_MASK1_SET__pa0__BITNR); tmp = (tmp << R_IRQ_MASK1_SET__pa0__BITNR);
save_flags(flags); cli(); local_irq_save(flags);
gpio_pa_irq_enabled_mask |= tmp; gpio_pa_irq_enabled_mask |= tmp;
*R_IRQ_MASK1_SET = tmp; *R_IRQ_MASK1_SET = tmp;
restore_flags(flags); local_irq_restore(flags);
} else if (priv->minor == GPIO_MINOR_B) } else if (priv->minor == GPIO_MINOR_B)
data = *R_PORT_PB_DATA; data = *R_PORT_PB_DATA;
...@@ -287,7 +306,10 @@ gpio_poll(struct file *file, ...@@ -287,7 +306,10 @@ gpio_poll(struct file *file,
mask = POLLIN|POLLRDNORM; mask = POLLIN|POLLRDNORM;
} }
spin_unlock(&gpio_lock);
DP(printk("gpio_poll ready: mask 0x%08X\n", mask)); DP(printk("gpio_poll ready: mask 0x%08X\n", mask));
return mask; return mask;
} }
...@@ -296,6 +318,7 @@ int etrax_gpio_wake_up_check(void) ...@@ -296,6 +318,7 @@ int etrax_gpio_wake_up_check(void)
struct gpio_private *priv = alarmlist; struct gpio_private *priv = alarmlist;
unsigned long data = 0; unsigned long data = 0;
int ret = 0; int ret = 0;
spin_lock(&gpio_lock);
while (priv) { while (priv) {
if (USE_PORTS(priv)) { if (USE_PORTS(priv)) {
data = *priv->port; data = *priv->port;
...@@ -310,6 +333,7 @@ int etrax_gpio_wake_up_check(void) ...@@ -310,6 +333,7 @@ int etrax_gpio_wake_up_check(void)
} }
priv = priv->next; priv = priv->next;
} }
spin_unlock(&gpio_lock);
return ret; return ret;
} }
...@@ -327,6 +351,7 @@ static irqreturn_t ...@@ -327,6 +351,7 @@ static irqreturn_t
gpio_pa_interrupt(int irq, void *dev_id, struct pt_regs *regs) gpio_pa_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{ {
unsigned long tmp; unsigned long tmp;
spin_lock(&gpio_lock);
/* Find what PA interrupts are active */ /* Find what PA interrupts are active */
tmp = (*R_IRQ_READ1); tmp = (*R_IRQ_READ1);
...@@ -337,6 +362,8 @@ gpio_pa_interrupt(int irq, void *dev_id, struct pt_regs *regs) ...@@ -337,6 +362,8 @@ gpio_pa_interrupt(int irq, void *dev_id, struct pt_regs *regs)
*R_IRQ_MASK1_CLR = tmp; *R_IRQ_MASK1_CLR = tmp;
gpio_pa_irq_enabled_mask &= ~tmp; gpio_pa_irq_enabled_mask &= ~tmp;
spin_unlock(&gpio_lock);
if (gpio_some_alarms) { if (gpio_some_alarms) {
return IRQ_RETVAL(etrax_gpio_wake_up_check()); return IRQ_RETVAL(etrax_gpio_wake_up_check());
} }
...@@ -350,6 +377,9 @@ static ssize_t gpio_write(struct file * file, const char * buf, size_t count, ...@@ -350,6 +377,9 @@ static ssize_t gpio_write(struct file * file, const char * buf, size_t count,
struct gpio_private *priv = (struct gpio_private *)file->private_data; struct gpio_private *priv = (struct gpio_private *)file->private_data;
unsigned char data, clk_mask, data_mask, write_msb; unsigned char data, clk_mask, data_mask, write_msb;
unsigned long flags; unsigned long flags;
spin_lock(&gpio_lock);
ssize_t retval = count; ssize_t retval = count;
if (priv->minor !=GPIO_MINOR_A && priv->minor != GPIO_MINOR_B) { if (priv->minor !=GPIO_MINOR_A && priv->minor != GPIO_MINOR_B) {
return -EFAULT; return -EFAULT;
...@@ -372,7 +402,7 @@ static ssize_t gpio_write(struct file * file, const char * buf, size_t count, ...@@ -372,7 +402,7 @@ static ssize_t gpio_write(struct file * file, const char * buf, size_t count,
data = *buf++; data = *buf++;
if (priv->write_msb) { if (priv->write_msb) {
for (i = 7; i >= 0;i--) { for (i = 7; i >= 0;i--) {
local_irq_save(flags); local_irq_disable(); local_irq_save(flags);
*priv->port = *priv->shadow &= ~clk_mask; *priv->port = *priv->shadow &= ~clk_mask;
if (data & 1<<i) if (data & 1<<i)
*priv->port = *priv->shadow |= data_mask; *priv->port = *priv->shadow |= data_mask;
...@@ -384,7 +414,7 @@ static ssize_t gpio_write(struct file * file, const char * buf, size_t count, ...@@ -384,7 +414,7 @@ static ssize_t gpio_write(struct file * file, const char * buf, size_t count,
} }
} else { } else {
for (i = 0; i <= 7;i++) { for (i = 0; i <= 7;i++) {
local_irq_save(flags); local_irq_disable(); local_irq_save(flags);
*priv->port = *priv->shadow &= ~clk_mask; *priv->port = *priv->shadow &= ~clk_mask;
if (data & 1<<i) if (data & 1<<i)
*priv->port = *priv->shadow |= data_mask; *priv->port = *priv->shadow |= data_mask;
...@@ -396,6 +426,7 @@ static ssize_t gpio_write(struct file * file, const char * buf, size_t count, ...@@ -396,6 +426,7 @@ static ssize_t gpio_write(struct file * file, const char * buf, size_t count,
} }
} }
} }
spin_unlock(&gpio_lock);
return retval; return retval;
} }
...@@ -452,8 +483,13 @@ gpio_open(struct inode *inode, struct file *filp) ...@@ -452,8 +483,13 @@ gpio_open(struct inode *inode, struct file *filp)
static int static int
gpio_release(struct inode *inode, struct file *filp) gpio_release(struct inode *inode, struct file *filp)
{ {
struct gpio_private *p = alarmlist; struct gpio_private *p;
struct gpio_private *todel = (struct gpio_private *)filp->private_data; struct gpio_private *todel;
spin_lock(&gpio_lock);
p = alarmlist;
todel = (struct gpio_private *)filp->private_data;
/* unlink from alarmlist and free the private structure */ /* unlink from alarmlist and free the private structure */
...@@ -476,7 +512,7 @@ gpio_release(struct inode *inode, struct file *filp) ...@@ -476,7 +512,7 @@ gpio_release(struct inode *inode, struct file *filp)
p = p->next; p = p->next;
} }
gpio_some_alarms = 0; gpio_some_alarms = 0;
spin_unlock(&gpio_lock);
return 0; return 0;
} }
...@@ -491,14 +527,14 @@ unsigned long inline setget_input(struct gpio_private *priv, unsigned long arg) ...@@ -491,14 +527,14 @@ unsigned long inline setget_input(struct gpio_private *priv, unsigned long arg)
*/ */
unsigned long flags; unsigned long flags;
if (USE_PORTS(priv)) { if (USE_PORTS(priv)) {
local_irq_save(flags); local_irq_disable(); local_irq_save(flags);
*priv->dir = *priv->dir_shadow &= *priv->dir = *priv->dir_shadow &=
~((unsigned char)arg & priv->changeable_dir); ~((unsigned char)arg & priv->changeable_dir);
local_irq_restore(flags); local_irq_restore(flags);
return ~(*priv->dir_shadow) & 0xFF; /* Only 8 bits */ return ~(*priv->dir_shadow) & 0xFF; /* Only 8 bits */
} else if (priv->minor == GPIO_MINOR_G) { } else if (priv->minor == GPIO_MINOR_G) {
/* We must fiddle with R_GEN_CONFIG to change dir */ /* We must fiddle with R_GEN_CONFIG to change dir */
save_flags(flags); cli(); local_irq_save(flags);
if (((arg & dir_g_in_bits) != arg) && if (((arg & dir_g_in_bits) != arg) &&
(arg & changeable_dir_g)) { (arg & changeable_dir_g)) {
arg &= changeable_dir_g; arg &= changeable_dir_g;
...@@ -533,7 +569,7 @@ unsigned long inline setget_input(struct gpio_private *priv, unsigned long arg) ...@@ -533,7 +569,7 @@ unsigned long inline setget_input(struct gpio_private *priv, unsigned long arg)
/* Must be a >120 ns delay before writing this again */ /* Must be a >120 ns delay before writing this again */
} }
restore_flags(flags); local_irq_restore(flags);
return dir_g_in_bits; return dir_g_in_bits;
} }
return 0; return 0;
...@@ -543,14 +579,14 @@ unsigned long inline setget_output(struct gpio_private *priv, unsigned long arg) ...@@ -543,14 +579,14 @@ unsigned long inline setget_output(struct gpio_private *priv, unsigned long arg)
{ {
unsigned long flags; unsigned long flags;
if (USE_PORTS(priv)) { if (USE_PORTS(priv)) {
local_irq_save(flags); local_irq_disable(); local_irq_save(flags);
*priv->dir = *priv->dir_shadow |= *priv->dir = *priv->dir_shadow |=
((unsigned char)arg & priv->changeable_dir); ((unsigned char)arg & priv->changeable_dir);
local_irq_restore(flags); local_irq_restore(flags);
return *priv->dir_shadow; return *priv->dir_shadow;
} else if (priv->minor == GPIO_MINOR_G) { } else if (priv->minor == GPIO_MINOR_G) {
/* We must fiddle with R_GEN_CONFIG to change dir */ /* We must fiddle with R_GEN_CONFIG to change dir */
save_flags(flags); cli(); local_irq_save(flags);
if (((arg & dir_g_out_bits) != arg) && if (((arg & dir_g_out_bits) != arg) &&
(arg & changeable_dir_g)) { (arg & changeable_dir_g)) {
/* Set bits in genconfig to set to output */ /* Set bits in genconfig to set to output */
...@@ -583,7 +619,7 @@ unsigned long inline setget_output(struct gpio_private *priv, unsigned long arg) ...@@ -583,7 +619,7 @@ unsigned long inline setget_output(struct gpio_private *priv, unsigned long arg)
*R_GEN_CONFIG = genconfig_shadow; *R_GEN_CONFIG = genconfig_shadow;
/* Must be a >120 ns delay before writing this again */ /* Must be a >120 ns delay before writing this again */
} }
restore_flags(flags); local_irq_restore(flags);
return dir_g_out_bits & 0x7FFFFFFF; return dir_g_out_bits & 0x7FFFFFFF;
} }
return 0; return 0;
...@@ -598,22 +634,26 @@ gpio_ioctl(struct inode *inode, struct file *file, ...@@ -598,22 +634,26 @@ gpio_ioctl(struct inode *inode, struct file *file,
{ {
unsigned long flags; unsigned long flags;
unsigned long val; unsigned long val;
int ret = 0;
struct gpio_private *priv = (struct gpio_private *)file->private_data; struct gpio_private *priv = (struct gpio_private *)file->private_data;
if (_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE) { if (_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE) {
return -EINVAL; return -EINVAL;
} }
spin_lock(&gpio_lock);
switch (_IOC_NR(cmd)) { switch (_IOC_NR(cmd)) {
case IO_READBITS: /* Use IO_READ_INBITS and IO_READ_OUTBITS instead */ case IO_READBITS: /* Use IO_READ_INBITS and IO_READ_OUTBITS instead */
// read the port // read the port
if (USE_PORTS(priv)) { if (USE_PORTS(priv)) {
return *priv->port; ret = *priv->port;
} else if (priv->minor == GPIO_MINOR_G) { } else if (priv->minor == GPIO_MINOR_G) {
return (*R_PORT_G_DATA) & 0x7FFFFFFF; ret = (*R_PORT_G_DATA) & 0x7FFFFFFF;
} }
break; break;
case IO_SETBITS: case IO_SETBITS:
local_irq_save(flags); local_irq_disable(); local_irq_save(flags);
// set changeable bits with a 1 in arg // set changeable bits with a 1 in arg
if (USE_PORTS(priv)) { if (USE_PORTS(priv)) {
*priv->port = *priv->shadow |= *priv->port = *priv->shadow |=
...@@ -624,7 +664,7 @@ gpio_ioctl(struct inode *inode, struct file *file, ...@@ -624,7 +664,7 @@ gpio_ioctl(struct inode *inode, struct file *file,
local_irq_restore(flags); local_irq_restore(flags);
break; break;
case IO_CLRBITS: case IO_CLRBITS:
local_irq_save(flags); local_irq_disable(); local_irq_save(flags);
// clear changeable bits with a 1 in arg // clear changeable bits with a 1 in arg
if (USE_PORTS(priv)) { if (USE_PORTS(priv)) {
*priv->port = *priv->shadow &= *priv->port = *priv->shadow &=
...@@ -666,33 +706,34 @@ gpio_ioctl(struct inode *inode, struct file *file, ...@@ -666,33 +706,34 @@ gpio_ioctl(struct inode *inode, struct file *file,
case IO_READDIR: /* Use IO_SETGET_INPUT/OUTPUT instead! */ case IO_READDIR: /* Use IO_SETGET_INPUT/OUTPUT instead! */
/* Read direction 0=input 1=output */ /* Read direction 0=input 1=output */
if (USE_PORTS(priv)) { if (USE_PORTS(priv)) {
return *priv->dir_shadow; ret = *priv->dir_shadow;
} else if (priv->minor == GPIO_MINOR_G) { } else if (priv->minor == GPIO_MINOR_G) {
/* Note: Some bits are both in and out, /* Note: Some bits are both in and out,
* Those that are dual is set here as well. * Those that are dual is set here as well.
*/ */
return (dir_g_shadow | dir_g_out_bits) & 0x7FFFFFFF; ret = (dir_g_shadow | dir_g_out_bits) & 0x7FFFFFFF;
} }
break;
case IO_SETINPUT: /* Use IO_SETGET_INPUT instead! */ case IO_SETINPUT: /* Use IO_SETGET_INPUT instead! */
/* Set direction 0=unchanged 1=input, /* Set direction 0=unchanged 1=input,
* return mask with 1=input * return mask with 1=input
*/ */
return setget_input(priv, arg) & 0x7FFFFFFF; ret = setget_input(priv, arg) & 0x7FFFFFFF;
break; break;
case IO_SETOUTPUT: /* Use IO_SETGET_OUTPUT instead! */ case IO_SETOUTPUT: /* Use IO_SETGET_OUTPUT instead! */
/* Set direction 0=unchanged 1=output, /* Set direction 0=unchanged 1=output,
* return mask with 1=output * return mask with 1=output
*/ */
return setget_output(priv, arg) & 0x7FFFFFFF; ret = setget_output(priv, arg) & 0x7FFFFFFF;
break;
case IO_SHUTDOWN: case IO_SHUTDOWN:
SOFT_SHUTDOWN(); SOFT_SHUTDOWN();
break; break;
case IO_GET_PWR_BT: case IO_GET_PWR_BT:
#if defined (CONFIG_ETRAX_SOFT_SHUTDOWN) #if defined (CONFIG_ETRAX_SOFT_SHUTDOWN)
return (*R_PORT_G_DATA & ( 1 << CONFIG_ETRAX_POWERBUTTON_BIT)); ret = (*R_PORT_G_DATA & ( 1 << CONFIG_ETRAX_POWERBUTTON_BIT));
#else #else
return 0; ret = 0;
#endif #endif
break; break;
case IO_CFG_WRITE_MODE: case IO_CFG_WRITE_MODE:
...@@ -709,7 +750,7 @@ gpio_ioctl(struct inode *inode, struct file *file, ...@@ -709,7 +750,7 @@ gpio_ioctl(struct inode *inode, struct file *file,
{ {
priv->clk_mask = 0; priv->clk_mask = 0;
priv->data_mask = 0; priv->data_mask = 0;
return -EPERM; ret = -EPERM;
} }
break; break;
case IO_READ_INBITS: case IO_READ_INBITS:
...@@ -720,8 +761,7 @@ gpio_ioctl(struct inode *inode, struct file *file, ...@@ -720,8 +761,7 @@ gpio_ioctl(struct inode *inode, struct file *file,
val = *R_PORT_G_DATA; val = *R_PORT_G_DATA;
} }
if (copy_to_user((unsigned long*)arg, &val, sizeof(val))) if (copy_to_user((unsigned long*)arg, &val, sizeof(val)))
return -EFAULT; ret = -EFAULT;
return 0;
break; break;
case IO_READ_OUTBITS: case IO_READ_OUTBITS:
/* *arg is result of reading the output shadow */ /* *arg is result of reading the output shadow */
...@@ -731,36 +771,43 @@ gpio_ioctl(struct inode *inode, struct file *file, ...@@ -731,36 +771,43 @@ gpio_ioctl(struct inode *inode, struct file *file,
val = port_g_data_shadow; val = port_g_data_shadow;
} }
if (copy_to_user((unsigned long*)arg, &val, sizeof(val))) if (copy_to_user((unsigned long*)arg, &val, sizeof(val)))
return -EFAULT; ret = -EFAULT;
break; break;
case IO_SETGET_INPUT: case IO_SETGET_INPUT:
/* bits set in *arg is set to input, /* bits set in *arg is set to input,
* *arg updated with current input pins. * *arg updated with current input pins.
*/ */
if (copy_from_user(&val, (unsigned long*)arg, sizeof(val))) if (copy_from_user(&val, (unsigned long*)arg, sizeof(val)))
return -EFAULT; {
ret = -EFAULT;
break;
}
val = setget_input(priv, val); val = setget_input(priv, val);
if (copy_to_user((unsigned long*)arg, &val, sizeof(val))) if (copy_to_user((unsigned long*)arg, &val, sizeof(val)))
return -EFAULT; ret = -EFAULT;
break; break;
case IO_SETGET_OUTPUT: case IO_SETGET_OUTPUT:
/* bits set in *arg is set to output, /* bits set in *arg is set to output,
* *arg updated with current output pins. * *arg updated with current output pins.
*/ */
if (copy_from_user(&val, (unsigned long*)arg, sizeof(val))) if (copy_from_user(&val, (unsigned long*)arg, sizeof(val)))
return -EFAULT; {
ret = -EFAULT;
break;
}
val = setget_output(priv, val); val = setget_output(priv, val);
if (copy_to_user((unsigned long*)arg, &val, sizeof(val))) if (copy_to_user((unsigned long*)arg, &val, sizeof(val)))
return -EFAULT; ret = -EFAULT;
break; break;
default: default:
if (priv->minor == GPIO_MINOR_LEDS) if (priv->minor == GPIO_MINOR_LEDS)
return gpio_leds_ioctl(cmd, arg); ret = gpio_leds_ioctl(cmd, arg);
else else
return -EINVAL; ret = -EINVAL;
} /* switch */ } /* switch */
return 0; spin_unlock(&gpio_lock);
return ret;
} }
static int static int
...@@ -802,60 +849,20 @@ struct file_operations gpio_fops = { ...@@ -802,60 +849,20 @@ struct file_operations gpio_fops = {
}; };
static void __init gpio_init_port_g(void) void ioif_watcher(const unsigned int gpio_in_available,
const unsigned int gpio_out_available,
const unsigned char pa_available,
const unsigned char pb_available)
{ {
#define GROUPA (0x0000FF3F) unsigned long int flags;
#define GROUPB (1<<6 | 1<<7) D(printk("gpio.c: ioif_watcher called\n"));
#define GROUPC (1<<30 | 1<<31) D(printk("gpio.c: G in: 0x%08x G out: 0x%08x PA: 0x%02x PB: 0x%02x\n",
#define GROUPD (0x3FFF0000) gpio_in_available, gpio_out_available, pa_available, pb_available));
#define GROUPD_LOW (0x00FF0000)
unsigned long used_in_bits = 0;
unsigned long used_out_bits = 0;
if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, scsi0, select)){
used_in_bits |= GROUPA | GROUPB | 0 | 0;
used_out_bits |= GROUPA | GROUPB | 0 | 0;
}
if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, ata, select)) {
used_in_bits |= GROUPA | GROUPB | GROUPC | (GROUPD & ~(1<<25|1<<26));
used_out_bits |= GROUPA | GROUPB | GROUPC | GROUPD;
}
if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, par0, select)) { spin_lock_irqsave(&gpio_lock, flags);
used_in_bits |= (GROUPA & ~(1<<0)) | 0 | 0 | 0;
used_out_bits |= (GROUPA & ~(1<<0)) | 0 | 0 | 0;
}
if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, ser2, select)) {
used_in_bits |= 0 | GROUPB | 0 | 0;
used_out_bits |= 0 | GROUPB | 0 | 0;
}
/* mio same as shared RAM ? */
if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, mio, select)) {
used_in_bits |= (GROUPA & ~(1<<0)) | 0 |0 |GROUPD_LOW;
used_out_bits |= (GROUPA & ~(1<<0|1<<1|1<<2)) | 0 |0 |GROUPD_LOW;
}
if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, scsi1, select)) {
used_in_bits |= 0 | 0 | GROUPC | GROUPD;
used_out_bits |= 0 | 0 | GROUPC | GROUPD;
}
if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, scsi0w, select)) {
used_in_bits |= GROUPA | GROUPB | 0 | (GROUPD_LOW | 1<<24);
used_out_bits |= GROUPA | GROUPB | 0 | (GROUPD_LOW | 1<<24 | 1<<25|1<<26);
}
if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, par1, select)) { dir_g_in_bits = gpio_in_available;
used_in_bits |= 0 | 0 | 0 | (GROUPD & ~(1<<24)); dir_g_out_bits = gpio_out_available;
used_out_bits |= 0 | 0 | 0 | (GROUPD & ~(1<<24));
}
if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, ser3, select)) {
used_in_bits |= 0 | 0 | GROUPC | 0;
used_out_bits |= 0 | 0 | GROUPC | 0;
}
/* mio same as shared RAM-W? */
if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, mio_w, select)) {
used_in_bits |= (GROUPA & ~(1<<0)) | 0 | 0 |GROUPD_LOW;
used_out_bits |= (GROUPA & ~(1<<0|1<<1|1<<2)) | 0 | 0 |GROUPD_LOW;
}
/* TODO: USB p2, parw, sync ser3? */
/* Initialise the dir_g_shadow etc. depending on genconfig */ /* Initialise the dir_g_shadow etc. depending on genconfig */
/* 0=input 1=output */ /* 0=input 1=output */
...@@ -868,10 +875,7 @@ static void __init gpio_init_port_g(void) ...@@ -868,10 +875,7 @@ static void __init gpio_init_port_g(void)
if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, g24dir, out)) if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, g24dir, out))
dir_g_shadow |= (1 << 24); dir_g_shadow |= (1 << 24);
dir_g_in_bits = ~used_in_bits; changeable_dir_g = changeable_dir_g_mask;
dir_g_out_bits = ~used_out_bits;
changeable_dir_g = 0x01FFFF01; /* all that can change dir */
changeable_dir_g &= dir_g_out_bits; changeable_dir_g &= dir_g_out_bits;
changeable_dir_g &= dir_g_in_bits; changeable_dir_g &= dir_g_in_bits;
/* Correct the bits that can change direction */ /* Correct the bits that can change direction */
...@@ -880,6 +884,7 @@ static void __init gpio_init_port_g(void) ...@@ -880,6 +884,7 @@ static void __init gpio_init_port_g(void)
dir_g_in_bits &= ~changeable_dir_g; dir_g_in_bits &= ~changeable_dir_g;
dir_g_in_bits |= (~dir_g_shadow & changeable_dir_g); dir_g_in_bits |= (~dir_g_shadow & changeable_dir_g);
spin_unlock_irqrestore(&gpio_lock, flags);
printk(KERN_INFO "GPIO port G: in_bits: 0x%08lX out_bits: 0x%08lX val: %08lX\n", printk(KERN_INFO "GPIO port G: in_bits: 0x%08lX out_bits: 0x%08lX val: %08lX\n",
dir_g_in_bits, dir_g_out_bits, (unsigned long)*R_PORT_G_DATA); dir_g_in_bits, dir_g_out_bits, (unsigned long)*R_PORT_G_DATA);
...@@ -896,6 +901,7 @@ gpio_init(void) ...@@ -896,6 +901,7 @@ gpio_init(void)
#if defined (CONFIG_ETRAX_CSP0_LEDS) #if defined (CONFIG_ETRAX_CSP0_LEDS)
int i; int i;
#endif #endif
printk("gpio init\n");
/* do the formalities */ /* do the formalities */
...@@ -919,8 +925,13 @@ gpio_init(void) ...@@ -919,8 +925,13 @@ gpio_init(void)
#endif #endif
#endif #endif
gpio_init_port_g(); /* The I/O interface allocation watcher will be called when
printk(KERN_INFO "ETRAX 100LX GPIO driver v2.5, (c) 2001, 2002 Axis Communications AB\n"); * registering it. */
if (cris_io_interface_register_watcher(ioif_watcher)){
printk(KERN_WARNING "gpio_init: Failed to install IO if allocator watcher\n");
}
printk(KERN_INFO "ETRAX 100LX GPIO driver v2.5, (c) 2001, 2002, 2003, 2004 Axis Communications AB\n");
/* We call etrax_gpio_wake_up_check() from timer interrupt and /* We call etrax_gpio_wake_up_check() from timer interrupt and
* from cpu_idle() in kernel/process.c * from cpu_idle() in kernel/process.c
* The check in cpu_idle() reduces latency from ~15 ms to ~6 ms * The check in cpu_idle() reduces latency from ~15 ms to ~6 ms
......
...@@ -12,6 +12,15 @@ ...@@ -12,6 +12,15 @@
*! don't use PB_I2C if DS1302 uses same bits, *! don't use PB_I2C if DS1302 uses same bits,
*! use PB. *! use PB.
*! $Log: i2c.c,v $ *! $Log: i2c.c,v $
*! Revision 1.13 2005/03/07 13:13:07 starvik
*! Added spinlocks to protect states etc
*!
*! Revision 1.12 2005/01/05 06:11:22 starvik
*! No need to do local_irq_disable after local_irq_save.
*!
*! Revision 1.11 2004/12/13 12:21:52 starvik
*! Added I/O and DMA allocators from Linux 2.4
*!
*! Revision 1.9 2004/08/24 06:49:14 starvik *! Revision 1.9 2004/08/24 06:49:14 starvik
*! Whitespace cleanup *! Whitespace cleanup
*! *!
...@@ -75,7 +84,7 @@ ...@@ -75,7 +84,7 @@
*! (C) Copyright 1999-2002 Axis Communications AB, LUND, SWEDEN *! (C) Copyright 1999-2002 Axis Communications AB, LUND, SWEDEN
*! *!
*!***************************************************************************/ *!***************************************************************************/
/* $Id: i2c.c,v 1.9 2004/08/24 06:49:14 starvik Exp $ */ /* $Id: i2c.c,v 1.13 2005/03/07 13:13:07 starvik Exp $ */
/****************** INCLUDE FILES SECTION ***********************************/ /****************** INCLUDE FILES SECTION ***********************************/
...@@ -95,6 +104,7 @@ ...@@ -95,6 +104,7 @@
#include <asm/arch/svinto.h> #include <asm/arch/svinto.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/delay.h> #include <asm/delay.h>
#include <asm/arch/io_interface_mux.h>
#include "i2c.h" #include "i2c.h"
...@@ -184,6 +194,7 @@ static const char i2c_name[] = "i2c"; ...@@ -184,6 +194,7 @@ static const char i2c_name[] = "i2c";
#define i2c_delay(usecs) udelay(usecs) #define i2c_delay(usecs) udelay(usecs)
static DEFINE_SPINLOCK(i2c_lock); /* Protect directions etc */
/****************** FUNCTION DEFINITION SECTION *************************/ /****************** FUNCTION DEFINITION SECTION *************************/
...@@ -488,13 +499,14 @@ i2c_writereg(unsigned char theSlave, unsigned char theReg, ...@@ -488,13 +499,14 @@ i2c_writereg(unsigned char theSlave, unsigned char theReg,
int error, cntr = 3; int error, cntr = 3;
unsigned long flags; unsigned long flags;
spin_lock(&i2c_lock);
do { do {
error = 0; error = 0;
/* /*
* we don't like to be interrupted * we don't like to be interrupted
*/ */
local_irq_save(flags); local_irq_save(flags);
local_irq_disable();
i2c_start(); i2c_start();
/* /*
...@@ -538,6 +550,8 @@ i2c_writereg(unsigned char theSlave, unsigned char theReg, ...@@ -538,6 +550,8 @@ i2c_writereg(unsigned char theSlave, unsigned char theReg,
i2c_delay(CLOCK_LOW_TIME); i2c_delay(CLOCK_LOW_TIME);
spin_unlock(&i2c_lock);
return -error; return -error;
} }
...@@ -555,13 +569,14 @@ i2c_readreg(unsigned char theSlave, unsigned char theReg) ...@@ -555,13 +569,14 @@ i2c_readreg(unsigned char theSlave, unsigned char theReg)
int error, cntr = 3; int error, cntr = 3;
unsigned long flags; unsigned long flags;
spin_lock(&i2c_lock);
do { do {
error = 0; error = 0;
/* /*
* we don't like to be interrupted * we don't like to be interrupted
*/ */
local_irq_save(flags); local_irq_save(flags);
local_irq_disable();
/* /*
* generate start condition * generate start condition
*/ */
...@@ -620,6 +635,8 @@ i2c_readreg(unsigned char theSlave, unsigned char theReg) ...@@ -620,6 +635,8 @@ i2c_readreg(unsigned char theSlave, unsigned char theReg)
} while(error && cntr--); } while(error && cntr--);
spin_unlock(&i2c_lock);
return b; return b;
} }
...@@ -686,15 +703,26 @@ static struct file_operations i2c_fops = { ...@@ -686,15 +703,26 @@ static struct file_operations i2c_fops = {
int __init int __init
i2c_init(void) i2c_init(void)
{ {
static int res = 0;
static int first = 1;
if (!first) {
return res;
}
/* Setup and enable the Port B I2C interface */ /* Setup and enable the Port B I2C interface */
#ifndef CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C #ifndef CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C
if ((res = cris_request_io_interface(if_i2c, "I2C"))) {
printk(KERN_CRIT "i2c_init: Failed to get IO interface\n");
return res;
}
*R_PORT_PB_I2C = port_pb_i2c_shadow |= *R_PORT_PB_I2C = port_pb_i2c_shadow |=
IO_STATE(R_PORT_PB_I2C, i2c_en, on) | IO_STATE(R_PORT_PB_I2C, i2c_en, on) |
IO_FIELD(R_PORT_PB_I2C, i2c_d, 1) | IO_FIELD(R_PORT_PB_I2C, i2c_d, 1) |
IO_FIELD(R_PORT_PB_I2C, i2c_clk, 1) | IO_FIELD(R_PORT_PB_I2C, i2c_clk, 1) |
IO_STATE(R_PORT_PB_I2C, i2c_oe_, enable); IO_STATE(R_PORT_PB_I2C, i2c_oe_, enable);
#endif
port_pb_dir_shadow &= ~IO_MASK(R_PORT_PB_DIR, dir0); port_pb_dir_shadow &= ~IO_MASK(R_PORT_PB_DIR, dir0);
port_pb_dir_shadow &= ~IO_MASK(R_PORT_PB_DIR, dir1); port_pb_dir_shadow &= ~IO_MASK(R_PORT_PB_DIR, dir1);
...@@ -702,8 +730,26 @@ i2c_init(void) ...@@ -702,8 +730,26 @@ i2c_init(void)
*R_PORT_PB_DIR = (port_pb_dir_shadow |= *R_PORT_PB_DIR = (port_pb_dir_shadow |=
IO_STATE(R_PORT_PB_DIR, dir0, input) | IO_STATE(R_PORT_PB_DIR, dir0, input) |
IO_STATE(R_PORT_PB_DIR, dir1, output)); IO_STATE(R_PORT_PB_DIR, dir1, output));
#else
if ((res = cris_io_interface_allocate_pins(if_i2c,
'b',
CONFIG_ETRAX_I2C_DATA_PORT,
CONFIG_ETRAX_I2C_DATA_PORT))) {
printk(KERN_WARNING "i2c_init: Failed to get IO pin for I2C data port\n");
return res;
} else if ((res = cris_io_interface_allocate_pins(if_i2c,
'b',
CONFIG_ETRAX_I2C_CLK_PORT,
CONFIG_ETRAX_I2C_CLK_PORT))) {
cris_io_interface_free_pins(if_i2c,
'b',
CONFIG_ETRAX_I2C_DATA_PORT,
CONFIG_ETRAX_I2C_DATA_PORT);
printk(KERN_WARNING "i2c_init: Failed to get IO pin for I2C clk port\n");
}
#endif
return 0; return res;
} }
static int __init static int __init
...@@ -711,14 +757,16 @@ i2c_register(void) ...@@ -711,14 +757,16 @@ i2c_register(void)
{ {
int res; int res;
i2c_init(); res = i2c_init();
if (res < 0)
return res;
res = register_chrdev(I2C_MAJOR, i2c_name, &i2c_fops); res = register_chrdev(I2C_MAJOR, i2c_name, &i2c_fops);
if(res < 0) { if(res < 0) {
printk(KERN_ERR "i2c: couldn't get a major number.\n"); printk(KERN_ERR "i2c: couldn't get a major number.\n");
return res; return res;
} }
printk(KERN_INFO "I2C driver v2.2, (c) 1999-2001 Axis Communications AB\n"); printk(KERN_INFO "I2C driver v2.2, (c) 1999-2004 Axis Communications AB\n");
return 0; return 0;
} }
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* *
* Author: Tobias Anderberg <tobiasa@axis.com>. * Author: Tobias Anderberg <tobiasa@axis.com>.
* *
* $Id: pcf8563.c,v 1.8 2004/08/24 06:42:51 starvik Exp $ * $Id: pcf8563.c,v 1.11 2005/03/07 13:13:07 starvik Exp $
*/ */
#include <linux/config.h> #include <linux/config.h>
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,7 @@
#define PCF8563_MAJOR 121 /* Local major number. */ #define PCF8563_MAJOR 121 /* Local major number. */
#define DEVICE_NAME "rtc" /* Name which is registered in /proc/devices. */ #define DEVICE_NAME "rtc" /* Name which is registered in /proc/devices. */
#define PCF8563_NAME "PCF8563" #define PCF8563_NAME "PCF8563"
#define DRIVER_VERSION "$Revision: 1.8 $" #define DRIVER_VERSION "$Revision: 1.11 $"
/* I2C bus slave registers. */ /* I2C bus slave registers. */
#define RTC_I2C_READ 0xa3 #define RTC_I2C_READ 0xa3
...@@ -50,6 +50,8 @@ ...@@ -50,6 +50,8 @@
#define rtc_read(x) i2c_readreg(RTC_I2C_READ, x) #define rtc_read(x) i2c_readreg(RTC_I2C_READ, x)
#define rtc_write(x,y) i2c_writereg(RTC_I2C_WRITE, x, y) #define rtc_write(x,y) i2c_writereg(RTC_I2C_WRITE, x, y)
static DEFINE_SPINLOCK(rtc_lock); /* Protect state etc */
static const unsigned char days_in_month[] = static const unsigned char days_in_month[] =
{ 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
...@@ -125,9 +127,12 @@ get_rtc_time(struct rtc_time *tm) ...@@ -125,9 +127,12 @@ get_rtc_time(struct rtc_time *tm)
int __init int __init
pcf8563_init(void) pcf8563_init(void)
{ {
unsigned char ret; int ret;
i2c_init(); if ((ret = i2c_init())) {
printk(KERN_CRIT "pcf8563_init: failed to init i2c\n");
return ret;
}
/* /*
* First of all we need to reset the chip. This is done by * First of all we need to reset the chip. This is done by
...@@ -200,12 +205,15 @@ pcf8563_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned ...@@ -200,12 +205,15 @@ pcf8563_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned
{ {
struct rtc_time tm; struct rtc_time tm;
spin_lock(&rtc_lock);
get_rtc_time(&tm); get_rtc_time(&tm);
if (copy_to_user((struct rtc_time *) arg, &tm, sizeof(struct rtc_time))) { if (copy_to_user((struct rtc_time *) arg, &tm, sizeof(struct rtc_time))) {
spin_unlock(&rtc_lock);
return -EFAULT; return -EFAULT;
} }
spin_unlock(&rtc_lock);
return 0; return 0;
} }
break; break;
...@@ -251,6 +259,8 @@ pcf8563_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned ...@@ -251,6 +259,8 @@ pcf8563_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned
BIN_TO_BCD(tm.tm_sec); BIN_TO_BCD(tm.tm_sec);
tm.tm_mon |= century; tm.tm_mon |= century;
spin_lock(&rtc_lock);
rtc_write(RTC_YEAR, tm.tm_year); rtc_write(RTC_YEAR, tm.tm_year);
rtc_write(RTC_MONTH, tm.tm_mon); rtc_write(RTC_MONTH, tm.tm_mon);
rtc_write(RTC_DAY_OF_MONTH, tm.tm_mday); rtc_write(RTC_DAY_OF_MONTH, tm.tm_mday);
...@@ -258,6 +268,8 @@ pcf8563_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned ...@@ -258,6 +268,8 @@ pcf8563_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned
rtc_write(RTC_MINUTES, tm.tm_min); rtc_write(RTC_MINUTES, tm.tm_min);
rtc_write(RTC_SECONDS, tm.tm_sec); rtc_write(RTC_SECONDS, tm.tm_sec);
spin_unlock(&rtc_lock);
return 0; return 0;
#endif /* !CONFIG_ETRAX_RTC_READONLY */ #endif /* !CONFIG_ETRAX_RTC_READONLY */
} }
......
# $Id: Makefile,v 1.5 2004/06/02 08:24:38 starvik Exp $ # $Id: Makefile,v 1.6 2004/12/13 12:21:51 starvik Exp $
# #
# Makefile for the linux kernel. # Makefile for the linux kernel.
# #
...@@ -7,7 +7,8 @@ extra-y := head.o ...@@ -7,7 +7,8 @@ extra-y := head.o
obj-y := entry.o traps.o shadows.o debugport.o irq.o \ obj-y := entry.o traps.o shadows.o debugport.o irq.o \
process.o setup.o signal.o traps.o time.o ptrace.o process.o setup.o signal.o traps.o time.o ptrace.o \
dma.o io_interface_mux.o
obj-$(CONFIG_ETRAX_KGDB) += kgdb.o obj-$(CONFIG_ETRAX_KGDB) += kgdb.o
obj-$(CONFIG_ETRAX_FAST_TIMER) += fasttimer.o obj-$(CONFIG_ETRAX_FAST_TIMER) += fasttimer.o
......
/* $Id: fasttimer.c,v 1.6 2004/05/14 10:18:39 starvik Exp $ /* $Id: fasttimer.c,v 1.9 2005/03/04 08:16:16 starvik Exp $
* linux/arch/cris/kernel/fasttimer.c * linux/arch/cris/kernel/fasttimer.c
* *
* Fast timers for ETRAX100/ETRAX100LX * Fast timers for ETRAX100/ETRAX100LX
* This may be useful in other OS than Linux so use 2 space indentation... * This may be useful in other OS than Linux so use 2 space indentation...
* *
* $Log: fasttimer.c,v $ * $Log: fasttimer.c,v $
* Revision 1.9 2005/03/04 08:16:16 starvik
* Merge of Linux 2.6.11.
*
* Revision 1.8 2005/01/05 06:09:29 starvik
* cli()/sti() will be obsolete in 2.6.11.
*
* Revision 1.7 2005/01/03 13:35:46 starvik
* Removed obsolete stuff.
* Mark fast timer IRQ as not shared.
*
* Revision 1.6 2004/05/14 10:18:39 starvik * Revision 1.6 2004/05/14 10:18:39 starvik
* Export fast_timer_list * Export fast_timer_list
* *
...@@ -148,8 +158,7 @@ static int debug_log_cnt_wrapped = 0; ...@@ -148,8 +158,7 @@ static int debug_log_cnt_wrapped = 0;
#define DEBUG_LOG(string, value) \ #define DEBUG_LOG(string, value) \
{ \ { \
unsigned long log_flags; \ unsigned long log_flags; \
save_flags(log_flags); \ local_irq_save(log_flags); \
cli(); \
debug_log_string[debug_log_cnt] = (string); \ debug_log_string[debug_log_cnt] = (string); \
debug_log_value[debug_log_cnt] = (unsigned long)(value); \ debug_log_value[debug_log_cnt] = (unsigned long)(value); \
if (++debug_log_cnt >= DEBUG_LOG_MAX) \ if (++debug_log_cnt >= DEBUG_LOG_MAX) \
...@@ -157,7 +166,7 @@ static int debug_log_cnt_wrapped = 0; ...@@ -157,7 +166,7 @@ static int debug_log_cnt_wrapped = 0;
debug_log_cnt = debug_log_cnt % DEBUG_LOG_MAX; \ debug_log_cnt = debug_log_cnt % DEBUG_LOG_MAX; \
debug_log_cnt_wrapped = 1; \ debug_log_cnt_wrapped = 1; \
} \ } \
restore_flags(log_flags); \ local_irq_restore(log_flags); \
} }
#else #else
#define DEBUG_LOG(string, value) #define DEBUG_LOG(string, value)
...@@ -320,8 +329,7 @@ void start_one_shot_timer(struct fast_timer *t, ...@@ -320,8 +329,7 @@ void start_one_shot_timer(struct fast_timer *t,
D1(printk("sft %s %d us\n", name, delay_us)); D1(printk("sft %s %d us\n", name, delay_us));
save_flags(flags); local_irq_save(flags);
cli();
do_gettimeofday_fast(&t->tv_set); do_gettimeofday_fast(&t->tv_set);
tmp = fast_timer_list; tmp = fast_timer_list;
...@@ -395,7 +403,7 @@ void start_one_shot_timer(struct fast_timer *t, ...@@ -395,7 +403,7 @@ void start_one_shot_timer(struct fast_timer *t,
D2(printk("start_one_shot_timer: %d us done\n", delay_us)); D2(printk("start_one_shot_timer: %d us done\n", delay_us));
restore_flags(flags); local_irq_restore(flags);
} /* start_one_shot_timer */ } /* start_one_shot_timer */
static inline int fast_timer_pending (const struct fast_timer * t) static inline int fast_timer_pending (const struct fast_timer * t)
...@@ -425,11 +433,10 @@ int del_fast_timer(struct fast_timer * t) ...@@ -425,11 +433,10 @@ int del_fast_timer(struct fast_timer * t)
unsigned long flags; unsigned long flags;
int ret; int ret;
save_flags(flags); local_irq_save(flags);
cli();
ret = detach_fast_timer(t); ret = detach_fast_timer(t);
t->next = t->prev = NULL; t->next = t->prev = NULL;
restore_flags(flags); local_irq_restore(flags);
return ret; return ret;
} /* del_fast_timer */ } /* del_fast_timer */
...@@ -444,8 +451,7 @@ timer1_handler(int irq, void *dev_id, struct pt_regs *regs) ...@@ -444,8 +451,7 @@ timer1_handler(int irq, void *dev_id, struct pt_regs *regs)
struct fast_timer *t; struct fast_timer *t;
unsigned long flags; unsigned long flags;
save_flags(flags); local_irq_save(flags);
cli();
/* Clear timer1 irq */ /* Clear timer1 irq */
*R_IRQ_MASK0_CLR = IO_STATE(R_IRQ_MASK0_CLR, timer1, clr); *R_IRQ_MASK0_CLR = IO_STATE(R_IRQ_MASK0_CLR, timer1, clr);
...@@ -462,7 +468,7 @@ timer1_handler(int irq, void *dev_id, struct pt_regs *regs) ...@@ -462,7 +468,7 @@ timer1_handler(int irq, void *dev_id, struct pt_regs *regs)
fast_timer_running = 0; fast_timer_running = 0;
fast_timer_ints++; fast_timer_ints++;
restore_flags(flags); local_irq_restore(flags);
t = fast_timer_list; t = fast_timer_list;
while (t) while (t)
...@@ -482,8 +488,7 @@ timer1_handler(int irq, void *dev_id, struct pt_regs *regs) ...@@ -482,8 +488,7 @@ timer1_handler(int irq, void *dev_id, struct pt_regs *regs)
fast_timers_expired++; fast_timers_expired++;
/* Remove this timer before call, since it may reuse the timer */ /* Remove this timer before call, since it may reuse the timer */
save_flags(flags); local_irq_save(flags);
cli();
if (t->prev) if (t->prev)
{ {
t->prev->next = t->next; t->prev->next = t->next;
...@@ -498,7 +503,7 @@ timer1_handler(int irq, void *dev_id, struct pt_regs *regs) ...@@ -498,7 +503,7 @@ timer1_handler(int irq, void *dev_id, struct pt_regs *regs)
} }
t->prev = NULL; t->prev = NULL;
t->next = NULL; t->next = NULL;
restore_flags(flags); local_irq_restore(flags);
if (t->function != NULL) if (t->function != NULL)
{ {
...@@ -515,8 +520,7 @@ timer1_handler(int irq, void *dev_id, struct pt_regs *regs) ...@@ -515,8 +520,7 @@ timer1_handler(int irq, void *dev_id, struct pt_regs *regs)
D1(printk(".\n")); D1(printk(".\n"));
} }
save_flags(flags); local_irq_save(flags);
cli();
if ((t = fast_timer_list) != NULL) if ((t = fast_timer_list) != NULL)
{ {
/* Start next timer.. */ /* Start next timer.. */
...@@ -535,7 +539,7 @@ timer1_handler(int irq, void *dev_id, struct pt_regs *regs) ...@@ -535,7 +539,7 @@ timer1_handler(int irq, void *dev_id, struct pt_regs *regs)
#endif #endif
start_timer1(us); start_timer1(us);
} }
restore_flags(flags); local_irq_restore(flags);
break; break;
} }
else else
...@@ -546,7 +550,7 @@ timer1_handler(int irq, void *dev_id, struct pt_regs *regs) ...@@ -546,7 +550,7 @@ timer1_handler(int irq, void *dev_id, struct pt_regs *regs)
D1(printk("e! %d\n", us)); D1(printk("e! %d\n", us));
} }
} }
restore_flags(flags); local_irq_restore(flags);
} }
if (!t) if (!t)
...@@ -748,13 +752,12 @@ static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len ...@@ -748,13 +752,12 @@ static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len
#endif #endif
used += sprintf(bigbuf + used, "Active timers:\n"); used += sprintf(bigbuf + used, "Active timers:\n");
save_flags(flags); local_irq_save(flags);
cli();
t = fast_timer_list; t = fast_timer_list;
while (t != NULL && (used+100 < BIG_BUF_SIZE)) while (t != NULL && (used+100 < BIG_BUF_SIZE))
{ {
nextt = t->next; nextt = t->next;
restore_flags(flags); local_irq_restore(flags);
used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu " used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu "
"d: %6li us data: 0x%08lX" "d: %6li us data: 0x%08lX"
/* " func: 0x%08lX" */ /* " func: 0x%08lX" */
...@@ -768,14 +771,14 @@ static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len ...@@ -768,14 +771,14 @@ static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len
t->data t->data
/* , t->function */ /* , t->function */
); );
cli(); local_irq_disable();
if (t->next != nextt) if (t->next != nextt)
{ {
printk(KERN_WARNING "timer removed!\n"); printk(KERN_WARNING "timer removed!\n");
} }
t = nextt; t = nextt;
} }
restore_flags(flags); local_irq_restore(flags);
} }
if (used - offset < len) if (used - offset < len)
...@@ -963,7 +966,7 @@ void fast_timer_init(void) ...@@ -963,7 +966,7 @@ void fast_timer_init(void)
if ((fasttimer_proc_entry = create_proc_entry( "fasttimer", 0, 0 ))) if ((fasttimer_proc_entry = create_proc_entry( "fasttimer", 0, 0 )))
fasttimer_proc_entry->read_proc = proc_fasttimer_read; fasttimer_proc_entry->read_proc = proc_fasttimer_read;
#endif /* PROC_FS */ #endif /* PROC_FS */
if(request_irq(TIMER1_IRQ_NBR, timer1_handler, SA_SHIRQ, if(request_irq(TIMER1_IRQ_NBR, timer1_handler, 0,
"fast timer int", NULL)) "fast timer int", NULL))
{ {
printk("err: timer1 irq\n"); printk("err: timer1 irq\n");
......
/*
* linux/include/asm-cris/ide.h
*
* Copyright (C) 2000, 2001, 2002 Axis Communications AB
*
* Authors: Bjorn Wesen
*
*/
/*
* This file contains the ETRAX 100LX specific IDE code.
*/
#ifndef __ASMCRIS_IDE_H
#define __ASMCRIS_IDE_H
#ifdef __KERNEL__
#include <asm/arch/svinto.h>
#include <asm/io.h>
#include <asm-generic/ide_iops.h>
/* ETRAX 100 can support 4 IDE busses on the same pins (serialized) */
#define MAX_HWIFS 4
extern __inline__ int ide_default_irq(unsigned long base)
{
/* all IDE busses share the same IRQ, number 4.
* this has the side-effect that ide-probe.c will cluster our 4 interfaces
* together in a hwgroup, and will serialize accesses. this is good, because
* we can't access more than one interface at the same time on ETRAX100.
*/
return 4;
}
extern __inline__ unsigned long ide_default_io_base(int index)
{
/* we have no real I/O base address per interface, since all go through the
* same register. but in a bitfield in that register, we have the i/f number.
* so we can use the io_base to remember that bitfield.
*/
static const unsigned long io_bases[MAX_HWIFS] = {
IO_FIELD(R_ATA_CTRL_DATA, sel, 0),
IO_FIELD(R_ATA_CTRL_DATA, sel, 1),
IO_FIELD(R_ATA_CTRL_DATA, sel, 2),
IO_FIELD(R_ATA_CTRL_DATA, sel, 3)
};
return io_bases[index];
}
/* this is called once for each interface, to setup the port addresses. data_port is the result
* of the ide_default_io_base call above. ctrl_port will be 0, but that is don't care for us.
*/
extern __inline__ void ide_init_hwif_ports(hw_regs_t *hw, unsigned long data_port, unsigned long ctrl_port, int *irq)
{
int i;
/* fill in ports for ATA addresses 0 to 7 */
for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
hw->io_ports[i] = data_port |
IO_FIELD(R_ATA_CTRL_DATA, addr, i) |
IO_STATE(R_ATA_CTRL_DATA, cs0, active);
}
/* the IDE control register is at ATA address 6, with CS1 active instead of CS0 */
hw->io_ports[IDE_CONTROL_OFFSET] = data_port |
IO_FIELD(R_ATA_CTRL_DATA, addr, 6) |
IO_STATE(R_ATA_CTRL_DATA, cs1, active);
/* whats this for ? */
hw->io_ports[IDE_IRQ_OFFSET] = 0;
}
extern __inline__ void ide_init_default_hwifs(void)
{
hw_regs_t hw;
int index;
for(index = 0; index < MAX_HWIFS; index++) {
ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, NULL);
hw.irq = ide_default_irq(ide_default_io_base(index));
ide_register_hw(&hw, NULL);
}
}
/* some configuration options we don't need */
#undef SUPPORT_VLB_SYNC
#define SUPPORT_VLB_SYNC 0
#endif /* __KERNEL__ */
#endif /* __ASMCRIS_IDE_H */
#include <asm/arch/ide.h>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment