PS GPIO -- Control LED (Linux)

Problem 
Write a simple Linux device driver to turn off and turn on LED DS23 10 times with one second delay between them.

Solution
Three tasks should be done in the device driver
  • Register the region of memory map I/O, (Lines 98-102). Note that, as GPIO memory region has been registered by the Xilinx Linux device driver for GPIO this task should not be done for this example. 
  • Remap memory map I/O addresses (Lines 104-108)
  • using ioreadxx and  iowritexx function to read and write data. (Lines 111-126)

control_led_linux.c

#include <linux/fs.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#include <linux/slab.h>
#include <linux/ioport.h>
#include <asm/io.h>
#include <linux/delay.h>

#define GPIO_NR_PORTS       0x000002E8
#define DIRM_0              0x00000204
#define OEN_0               0x00000208
#define MASK_DATA_0_LSW      0x00000000

MODULE_LICENSE("Dual BSD/GPL");

dev_t dev_numbers;
struct cdev *exercise_2_cdev;
static int exercise_2_device_open = 0;


static unsigned long gpio_base = 0xE000A000;



static ssize_t  exercise_2_read(struct file *file, /* see include/linux/fs.h   */
  char __user * buffer, /* buffer to be
* filled with data */
  size_t length, /* length of the buffer     */
  loff_t * offset) {
    return 0;
}




static ssize_t exercise_2_write(struct file *file,
    const char __user * buffer, size_t length, loff_t * offset) {
    return 0;
}

long  exercise_2_ioctl(   struct file *file, /* ditto */
unsigned int ioctl_num, /* number and param for ioctl */
       unsigned long ioctl_param) {

    return 0;
}


static int exercise_2_open(struct inode *inode, struct file *file) {
    

    return 0;
}



static int exercise_2_release(struct inode *inode, struct file *file){


    return 0;
}

struct file_operations exercise_2_fops = {
.read = exercise_2_read,
.write = exercise_2_write,
.unlocked_ioctl = exercise_2_ioctl,
.open = exercise_2_open,
.release = exercise_2_release,
};

static int exercise_2_init(void) {
   
    int state; 
    char  device_name[]="exercise_2";


    state = alloc_chrdev_region(&dev_numbers, 0, 1, device_name);
    if(state!=0) {
        printk(KERN_ALERT "failed to register a region dynamically\n");
    } else {
        printk(KERN_ALERT "major number = %d\n", MAJOR(dev_numbers));
    }
  
   

    exercise_2_cdev = cdev_alloc();
    exercise_2_cdev->ops = &exercise_2_fops; 
    exercise_2_cdev->owner = THIS_MODULE;

    state = cdev_add(exercise_2_cdev, dev_numbers, 1);
    if(state < 0) {
        printk(KERN_ALERT "device failed to be added\n");
    }

/* Get required resources. */
//    if (! request_mem_region(gpio_base, GPIO_NR_PORTS, "my_gpio")) {
//        printk(KERN_ALERT "my_gpio: can't get I/O port address 0x%lx\n", gpio_base);
//        return -ENODEV;
//    }

    void* kernel_gpio_base = ioremap(gpio_base, GPIO_NR_PORTS);
    if (!kernel_gpio_base) {
        printk(KERN_ALERT "kernel remap my_gpio failed 0x%lx\n", gpio_base);
        return -ENODEV;
    }


   //just for test I have to write an ioctl function
    u32 dirm_value = ioread32(kernel_gpio_base+DIRM_0);
    dirm_value = dirm_value | 0x00000400;
    iowrite32(dirm_value, kernel_gpio_base+DIRM_0);
    u32 oen_value = ioread32(kernel_gpio_base+OEN_0);
    oen_value = oen_value | 0x00000400;
    iowrite32(oen_value, kernel_gpio_base+OEN_0);
    u32 turn_off_led_value = 0xFBFF0000;
    u32 turn_on_led_value = 0xFBFF0400;
int i;
    for (i = 0; i < 10; i++) {
        iowrite32(turn_on_led_value, kernel_gpio_base+MASK_DATA_0_LSW);
   ssleep(1);
        iowrite32(turn_off_led_value, kernel_gpio_base+MASK_DATA_0_LSW);
   ssleep(1);
    }
    


    return 0;
}

static void exercise_2_exit(void) {
   


//    release_mem_region(gpio_base,GPIO_NR_PORTS);
    cdev_del(exercise_2_cdev); 
    unregister_chrdev_region(dev_numbers, 1); 

}
module_init(exercise_2_init);
module_exit(exercise_2_exit);
exercise-02_code01