[Armadeus-commitlog] SF.net SVN: armadeus: [771] trunk/target/linux/modules/led
Brought to you by:
sszy
|
From: <Fa...@us...> - 2008-03-12 14:24:58
|
Revision: 771
http://armadeus.svn.sourceforge.net/armadeus/?rev=771&view=rev
Author: FabM
Date: 2008-03-12 07:24:07 -0700 (Wed, 12 Mar 2008)
Log Message:
-----------
[target] Led driver with /dev, /sys and interruption
Modified Paths:
--------------
trunk/target/linux/modules/led/README
trunk/target/linux/modules/led/led.c
trunk/target/linux/modules/led/led.h
Modified: trunk/target/linux/modules/led/README
===================================================================
--- trunk/target/linux/modules/led/README 2008-03-12 11:57:53 UTC (rev 770)
+++ trunk/target/linux/modules/led/README 2008-03-12 14:24:07 UTC (rev 771)
@@ -1,26 +1,43 @@
Driver for fpga IP bus_led -> armadeus/firmware/led/
Fabien Marteau <fab...@ar...>
-To use it configure fpga with bus_led then insert led.ko with insmod :
->insmod led.ko
-Watch dmesg :
-LED: MAJOR: 253 MINOR: 0
-Led module inserted
+* Character device
-Then make a character file with wright major and minor number :
->mknod led c 253 0
+ To use it configure fpga with bus_led then insert led.ko with insmod :
+ >insmod led.ko
+
+ Watch dmesg :
+ LED: MAJOR: 253 MINOR: 0
+ Led module inserted
+
+ Then make a character file with wright major and minor number :
+ >mknod led c 253 0
+
+ Then led can be switched on/off writing a character in node file,
+ only LSB will switch led, 1 will switch off led and 0 will
+ witch on. To read value, just read the file.
-Then led can be switched on/off writing a character in node file,
-only LSB will switch led, 1 will switch off led and 0 will
-witch on. To read value, just read the file.
+ To test read/write testled.c can be used, to compile :
+ make test
+ then launch the binary :
+ >./testled led
+
+* Sysfs /sys/fpgaled/status
-To test read/write testled.c can be used, to compile :
-make test
-then launch the binary :
->./testled led
+ Sysfs is created at /sys/fpgaled/status, to print the led status:
+ >cat /sys/fpgaled/status
+ To switch the status :
+ >echo 1 > /sys/fpgaled/status
+
+* interruption
-Sysfs is created at /sys/fpgaled/status, to print the led status:
->cat /sys/fpgaled/status
-To switch the status :
->echo 1 > /sys/fpgaled/status
+ Led value is toggled on interruption, to use it, apf9328.c has to
+ be modified with line (buildroot/build_arm/linux-2.6.23.1/arch/arm/mach-imx/apf9328.c) :
+
+#ifdef CONFIG_CAN_MCP251X
+ set_irq_type( IRQ_GPIOC(CAN_MPC251X_INT_GPIOC), IRQF_TRIGGER_FALLING );
+#endif // CONFIG_CAN_MCP251X
+# define FPGA_INT_GPIOA 1
+ set_irq_type(IRQ_GPIOA(FPGA_INT_GPIOA),IRQF_TRIGGER_RISING);
+ At the end of the file.
Modified: trunk/target/linux/modules/led/led.c
===================================================================
--- trunk/target/linux/modules/led/led.c 2008-03-12 11:57:53 UTC (rev 770)
+++ trunk/target/linux/modules/led/led.c 2008-03-12 14:24:07 UTC (rev 771)
@@ -1,10 +1,55 @@
-/* Driver for bus_led fpga IP
+/* led.c
+ * Driver for bus_led fpga IP
* Fabien Marteau <fab...@ar...>
- * 4 march 2008
*/
#include "led.h"
+/*********************************
+ * simple fpga read/write
+ *********************************/
+
+static ssize_t fpga_read(void * addr,u16 *data,struct led_dev *dev){
+ *data = ioread16(addr);/* read the led value */
+ // PDEBUG( "read : value read : %x\n",*data);
+ return 2;
+}
+
+static ssize_t fpga_write(void * addr,u16 *data,struct led_dev *dev){
+ ssize_t retval;
+
+ iowrite16(*data,addr);/* write the led value */
+ retval = 2;
+ return retval;
+}
+
+/**********************************
+ * irq management
+ * ********************************/
+
+static irqreturn_t fpga_interrupt(int irq,void *dev_id,struct pt_regs *reg){
+ struct led_dev *ldev = dev_id;
+ u16 data;
+
+ if(down_trylock(&ldev->sem))
+ return IRQ_HANDLED;
+
+ /* acknoledge irq */
+ data = 0x0001;
+ fpga_write(ldev->fpga_virtual_base_address + FPGA_IRQ_ACK,&data,ldev);
+ /* read led value */
+ fpga_read(ldev->fpga_virtual_base_address,&data,ldev);
+ data = ((data&0x0001)==1)?data&0xfffe:data|0x0001;
+ fpga_write(ldev->fpga_virtual_base_address,&data,ldev);
+
+ up(&ldev->sem);
+ PDEBUG("time %ldticks\n",jiffies-ldev->previousint);
+ ldev->previousint = jiffies;
+ return IRQ_HANDLED;
+}
+
+
+
/* *********************************
* Sysfs operations
* *********************************/
@@ -36,27 +81,23 @@
static ssize_t led_show_status(struct kobject *kobj,struct attribute *attr,char *buf){
ssize_t ret_size = 0;
struct led_dev *dev;
- void * virt_addr;
u16 data;
dev = container_of(kobj,struct led_dev,kobj);
- if(down_interruptible(&dev->sem)) /* take mutex */
+ if(down_interruptible(&dev->sem)){ /* take mutex */
+ printk(KERN_WARNING "led_show_status:can't take mutex\n");
return -ERESTARTSYS;
-
- virt_addr = ioremap(IMX_CS1_PHYS,1);/* translate hardware address to virtual */
- if(virt_addr==NULL){
- printk(KERN_WARNING "ioremap error\n");
- return -EFAULT;
}
- data = ioread16(virt_addr);/* read the led value */
- PDEBUG( "show : value read : %x\n",data);
- iounmap(virt_addr);
+ if((ret_size=fpga_read(dev->fpga_virtual_base_address,&data,dev))<0)
+ goto out;
+ PDEBUG("data : %d\n",data);
if(data&0x0001)ret_size = (ssize_t)sprintf(buf,"1\n");
else ret_size = (ssize_t)sprintf(buf,"0\n");
+out:
up(&dev->sem);
return ret_size;
}
@@ -64,8 +105,6 @@
static ssize_t led_store_status(struct kobject *kobj,struct attribute *attr,
const char *buff, size_t size){
struct led_dev *ldev = container_of(kobj,struct led_dev,kobj);
- void * virt_addr;
- ssize_t retval=0;
u16 data;
if(buff[0]=='1')
@@ -78,20 +117,10 @@
if(down_interruptible(&ldev->sem))
return -ERESTARTSYS;
- virt_addr = ioremap(IMX_CS1_PHYS,1);/* translate hardware address to virtual */
- if(virt_addr==NULL){
- printk(KERN_WARNING "write : ioremap error\n");
- retval = -EFAULT;
- goto out;
- }
- iowrite16(data,virt_addr);/* write the led value */
- iounmap(virt_addr);
- PDEBUG( "write : Value wrote : %x\n",data);
+ size=fpga_write(ldev->fpga_virtual_base_address,&data,ldev);
up(&ldev->sem);
return size ;
-out:
- return retval;
}
/***********************************
@@ -99,7 +128,6 @@
* *********************************/
ssize_t led_read(struct file *fildes, char __user *buff, size_t count, loff_t *offp){
struct led_dev *ldev = fildes->private_data;
- void * virt_addr;
u16 data=0;
ssize_t retval = 0;
@@ -112,19 +140,9 @@
if(*offp + count >= 1) /* Only one word can be read */
count = 1 - *offp;
- virt_addr = ioremap(IMX_CS1_PHYS,1);/* translate hardware address to virtual */
- if(virt_addr==NULL){
- printk(KERN_WARNING "ioremap error\n");
- return -EFAULT;
- }
- PDEBUG("read : Virtual fpga adress : %lx\n",(long int)virt_addr);
- PDEBUG("read : Real fpga adress : %lx\n",(long int)IMX_CS1_PHYS);
- // rmb();
- data = ioread16(virt_addr);/* read the led value */
- PDEBUG( "read : value read : %x\n",data);
+ if((retval = fpga_read(ldev->fpga_virtual_base_address,&data,ldev))<0)
+ goto out;
- iounmap(virt_addr);
-
/* return data for user */
if(copy_to_user(buff,&data,2)){
printk(KERN_WARNING "read : copy to user data error\n");
@@ -143,7 +161,6 @@
ssize_t led_write(struct file *fildes, const char __user *buff,size_t count, loff_t *offp){
struct led_dev *ldev = fildes->private_data;
- void * virt_addr;
u16 data=0;
ssize_t retval = 0;
@@ -157,28 +174,20 @@
if(count != 1) /* Only one word can be read */
count = 1;
- virt_addr = ioremap(IMX_CS1_PHYS,1);/* translate hardware address to virtual */
- if(virt_addr==NULL){
- printk(KERN_WARNING "write : ioremap error\n");
- retval = -EFAULT;
- goto out;
- }
- PDEBUG("write : Virtual fpga adress : %lx\n",(long int)virt_addr);
- PDEBUG("write : Real fpga adress : %lx\n",(long int)IMX_CS1_PHYS);
- // rmb();
if(copy_from_user(&data,buff,1)){
printk(KERN_WARNING "write : copy from user error\n");
retval = -EFAULT;
goto out;
}
- PDEBUG( "write : user buff value %d\n",(int)data);
- iowrite16(data,virt_addr);/* write the led value */
- iounmap(virt_addr);
- PDEBUG( "write : Value wrote : %x\n",data);
- retval = 1;
+
+ if((retval=fpga_write(ldev->fpga_virtual_base_address,&data,ldev))<0){
+ goto out;
+ }
+
out:
up(&ldev->sem);
return retval;
+
}
int led_open(struct inode *inode, struct file *filp){
@@ -202,7 +211,8 @@
static int __init led_init(void){
int result; /* error return */
- int led_major,led_minor;
+ int led_major,led_minor;
+ u16 data;
led_major = 253;
led_minor = 0;
@@ -221,7 +231,7 @@
init_MUTEX(&sdev->sem);
/* Get the major and minor device numbers */
- PDEBUG("Get the major and minor device numbers");
+ PDEBUG("Get the major and minor device numbers\n");
if(led_major){
devno = MKDEV(led_major,led_minor);
result = register_chrdev_region(devno, N_DEV,"led");
@@ -240,21 +250,37 @@
sdev->cdev.owner = THIS_MODULE;
/* Add the device to the kernel, connecting cdev to major/minor number */
- PDEBUG(" Add the device to the kernel, connecting cdev to major/minor number \n");
+ PDEBUG("Add the device to the kernel, connecting cdev to major/minor number \n");
result = cdev_add(&sdev->cdev,devno,1);
if(result < 0)printk(KERN_WARNING "LED: can't add cdev\n");
/* Requested I/O memory */
PDEBUG(" Requested I/O memory \n");
- mem = request_mem_region(LED_BASE_ADDR,LED_LENGTH,"led");
+ mem = request_mem_region(IMX_CS1_PHYS,IMX_CS1_SIZE,"led");
if(mem == NULL)
printk(KERN_ERR "LED: Error memory allocation\n");
+ if((sdev->fpga_virtual_base_address = ioremap(IMX_CS1_PHYS,IMX_CS1_SIZE))==NULL){
+ printk(KERN_ERR "ioremap error\n");
+ goto error;
+ }
/* initialyzing sysfs */
- PDEBUG(" initialyzing sysfs");
+ PDEBUG(" initialyzing sysfs\n");
if(unlikely(result = init_sysinterface(sdev)))
goto error;
+ /* irq registering */
+ if(request_irq(IRQ_GPIOA(1),(irq_handler_t)fpga_interrupt,IRQF_SAMPLE_RANDOM,"fpga",sdev)<0){
+ printk(KERN_ERR "Can't request fpga irq\n");
+ goto error;
+ }
+ /* irq unmask */
+ data=1;
+ if((result=fpga_write(sdev->fpga_virtual_base_address + FPGA_IRQ_MASK,&data,sdev))<0)
+ goto error;
+
+ sdev->previousint = jiffies;
+ /* OK module inserted ! */
printk(KERN_INFO "Led module insered\n");
return 0;
@@ -269,6 +295,10 @@
}
static void free_all(void){
+
+ /* free irq*/
+ free_irq(IRQ_GPIOA(1),sdev);
+
/* unregister kobj */
kobject_unregister(&sdev->kobj);
@@ -279,7 +309,7 @@
kfree(sdev);
/* Release I/O memories */
- release_mem_region(LED_BASE_ADDR,LED_LENGTH);
+ release_mem_region(IMX_CS1_PHYS,IMX_CS1_SIZE);
/* free major and minor number */
unregister_chrdev_region(devno,N_DEV);
Modified: trunk/target/linux/modules/led/led.h
===================================================================
--- trunk/target/linux/modules/led/led.h 2008-03-12 11:57:53 UTC (rev 770)
+++ trunk/target/linux/modules/led/led.h 2008-03-12 14:24:07 UTC (rev 771)
@@ -1,6 +1,12 @@
-/* Driver for bus_led IP
+/* led.h
+ * Driver for bus_led IP
* Fabien Marteau <fab...@ar...>
- * 4 march 2008
+ * ----------------
+ * 12 march 2008
+ * switching led on interruption
+ * ----------------
+ * 4 march 2008
+ * initial version
*/
@@ -37,6 +43,13 @@
/* hardware addresses */
#include <asm/hardware.h>
+
+/* interruptions */
+#include <linux/interrupt.h>
+#include <asm/irq.h>
+
+/* measure time */
+#include <linux/jiffies.h>
#endif
/* for debugging messages*/
@@ -55,16 +68,21 @@
# define PDEBUG(fmt,args...) /* no debbuging message */
#endif
+#define FPGA_IRQ_MASK 4
+#define FPGA_IRQ_PEND 2
+#define FPGA_IRQ_ACK 2
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Fabien Marteau <fab...@ar...> - ARMadeus Systems");
MODULE_DESCRIPTION("Led device driver");
-/* cdev struct */
+/* main device structure */
struct led_dev{
struct cdev cdev; /* Char device structure */
struct semaphore sem; /* Mutex */
- struct kobject kobj;
+ struct kobject kobj; /* kobject for sysfs entry */
+ void * fpga_virtual_base_address; /* fpga register base address*/
+ unsigned long previousint; /* last interruption time */
};
static void kobj_release(struct kobject *);
@@ -121,5 +139,9 @@
.sysfs_ops = &led_status_fs_ops,
};
+static irqreturn_t fpga_interrupt(int irq,void *stuff,struct pt_regs *reg);
static void free_all(void);
+
+static ssize_t fpga_read(void * addr, u16 *data , struct led_dev *dev);
+static ssize_t fpga_write(void * addr, u16 *data, struct led_dev *dev);
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|