An LED platform driver case

This case is used for copying homework. You can quickly write the driver by directly copying and modifying it.

When you are very familiar with the driver, you don’t need to write every time. Unless you are unfamiliar with the driver, it is recommended to type the code manually; writing the program should be copy and paste, hahaha…

device part

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/err.h>

#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>

#include <linux/timer.h>
#include <linux/jiffies.h>

#include <linux/platform_device.h>



#define LED_NAME "nameLED3"
#defineCHRDEV_COUNT_MAX 1


struct led_platform_dev_t{<!-- -->
    struct cdev cdev; //Register device
    struct class *class; //class
    struct device *device; //device
    dev_t devid; //device id
    int major; //major device number
    int minor; //Minor device number


    struct device_node *nd;
    int led_gpio;


    struct timer_list timer; // timer
    
};

struct led_platform_dev_t led_platform_dev;



void led_device_release(struct device *dev)
{<!-- -->
 printk("led_device_release\r\\
");
}

static struct resource res[2] = {<!-- -->
    [0] = {<!-- -->
        .start = 0x200000001,
        .end = 0x200000005,
        .flags = IORESOURCE_MEM,
    },

     [1] = {<!-- -->
        .start = 0x200000006,
        .end = 0x200000007,
        .flags = IORESOURCE_MEM,
    },
};

static struct platform_device led_platform_device = {<!-- -->
    .name = "platform_led",//-1 means there is no such device
    .dev = {<!-- -->
        .release = led_device_release,
    },
    .num_resources = ARRAY_SIZE(res),
    .resource = res,
};


static struct file_operations led_platform_fops={<!-- -->
    .owner = THIS_MODULE,
    // .open = led3_open,
    // .release = led3_release,
    // .write = led3_write,
    // //.read = led3_read,
    // .unlocked_ioctl = led3_ioctl,
};



//Driver entry
static int __init led_platform_init(void)
{<!-- -->
    int ret = 0;

    ret = platform_device_register( & amp;led_platform_device);


    printk("led platform init\r\\
");
    return 0;
}

static void __exit led_platform_exit(void)
{<!-- -->
    platform_device_unregister( & amp;led_platform_device);

    printk("led platform exit!\r\\
");
}

//Register driver and uninstall
module_init(led_platform_init);
module_exit(led_platform_exit);


MODULE_LICENSE("GPL");
MODULE_AUTHOR("China Shanghai/zhouchenliang");



driver section

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/err.h>

#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>

#include <linux/timer.h>
#include <linux/jiffies.h>

#include <linux/ide.h>
#include <linux/ioport.h>
#include <linux/platform_device.h>



#define LED_NAME "nameLED3"
#defineCHRDEV_COUNT_MAX 1


struct led_platform_dev_t{<!-- -->
    struct cdev cdev; //Register device
    struct class *class; //class
    struct device *device; //device
    dev_t devid; //device id
    int major; //major device number
    int minor; //Minor device number


    struct device_node *nd;
    int led_gpio;

    struct timer_list timer; // timer
};

struct led_platform_dev_t led_platform_dev;



static int led_platform_open(struct inode *inode,struct file *filp)
{<!-- -->
    printk("led_platform_open\r\\
");

    filp->private_data = & amp;led_platform_dev;//File private data
    return 0;
}

static int led_platform_release(struct inode *inode,struct file *filp)
{<!-- -->
    printk("led_platform_release\r\\
");

    //struct led_platform_dev_t *dev = (struct led_platform_dev_t)filp->private_data;

    return 0;
}

static ssize_t led_platform_write(struct file *filp,const __user char *buf,size_t count, loff_t *ppos)
{<!-- -->
    int ret = 0;

    // ret = copy_from_user(writeBuf,buf,count);
    // if(ret < 0)
    // {<!-- -->
    // printk("led_write copy_from_user error\r\\
");
    // return -1;
    // }

    printk("led_platform_write\r\\
");
    return 0;
}

static struct file_operations led_platform_fops={<!-- -->
    .owner = THIS_MODULE,
    .open = led_platform_open,
    .release = led_platform_release,
    .write = led_platform_write,
    // //.read = led3_read,
    // .unlocked_ioctl = led3_ioctl,
};



static int led_driver_probe(struct platform_device *dev)
{<!-- -->
    // int i=0;
    // struct resource *led_source[2];

    //1. Get resources from the device
    // for(i=0;i<2;i + + )
    // {<!-- -->
    // led_source[i] = platform_get_resource(dev,IORESOURCE_MEM,i);
    // if(led_source[i] == NULL)
    // {<!-- -->
    // return -EINVAL;
    // }
    // }

    //memory mapping
    //IMX6U_CCM_CCGR1 = ioremap(ledsource[0]->start,resource_size(led_source[0]));


    int ret = -1;

    /*Device number registration*/
    led_platform_dev.major = 0;//Directly apply for the device number from the system
    if(led_platform_dev.major)//Given the major device number
    {<!-- -->
        led_platform_dev.devid = MKDEV(led_platform_dev.major,0);
        ret = register_chrdev_region(led_platform_dev.devid,CHRDEV_COUNT_MAX,LED_NAME);
    }
    else//No major device number is given
    {<!-- -->
        ret = alloc_chrdev_region( & amp;led_platform_dev.devid,0,CHRDEV_COUNT_MAX,LED_NAME);//Automatically apply for a device number
        led_platform_dev.major = MAJOR(led_platform_dev.devid);
        led_platform_dev.minor = MINOR(led_platform_dev.devid);
    }

    if(ret < 0)
    {<!-- -->
        printk("register_chdev_region faild!\r\\
");
        return -EIO;
    }

    /*Register character device*/
    led_platform_dev.cdev.owner = THIS_MODULE;
    cdev_init( & amp;led_platform_dev.cdev, & amp;led_platform_fops);//Initialization
    ret = cdev_add( & amp;led_platform_dev.cdev,led_platform_dev.devid,CHRDEV_COUNT_MAX);//Add function
    if(ret < 0)
    {<!-- -->
        printk("cdev_init faild!\r\\
");
        cdev_del(&led_platform_dev.cdev);
        unregister_chrdev_region(led_platform_dev.devid,CHRDEV_COUNT_MAX);
        return -EIO;
    }

    /*Automatically create device nodes*/
    led_platform_dev.class = class_create(led_platform_fops.owner,LED_NAME);
    if(IS_ERR(led_platform_dev.class))
    {<!-- -->
        cdev_del(&led_platform_dev.cdev);
        unregister_chrdev_region(led_platform_dev.devid,CHRDEV_COUNT_MAX);
        return PTR_ERR(led_platform_dev.class);
    }

    led_platform_dev.device = device_create(led_platform_dev.class,NULL,led_platform_dev.devid,NULL,LED_NAME);
    if(IS_ERR(led_platform_dev.device))
    {<!-- -->
        class_destroy(led_platform_dev.class);
        cdev_del(&led_platform_dev.cdev);
        unregister_chrdev_region(led_platform_dev.devid,CHRDEV_COUNT_MAX);
        return PTR_ERR(led_platform_dev.device);
    }

    //Device tree, get device nodes
#if 0
    led_platform_dev.nd = of_find_node_by_path("/gpioled");
    if(led_platform_dev.nd == NULL)
    {<!-- -->
        printk("of_find_node_by_path faild!\r\\
");
        return -EINVAL;
    }
#endif

    led_platform_dev.nd = dev->dev.of_node;

    // //Get the GPIO corresponding to the LED
    led_platform_dev.led_gpio = of_get_named_gpio(led_platform_dev.nd,"gpios",0);
    if(led_platform_dev.led_gpio < 0)
    {<!-- -->
        printk("of_get_named_gpio faild!\r\\
");
        return -EINVAL;
    }

    // //Apply for IO
    // ret = gpio_request(led_platform_dev.led_gpio,"gpio_pin_1");
    // if(ret)
    // {<!-- -->
    // printk("gpio_request faild!\r\\
");
    // return -EINVAL;
    // }

    // //Use IO set as output
    // ret = gpio_direction_output(led_platform_dev.led_gpio,1);
    // if(ret)
    // {<!-- -->
    // printk("gpio_direction_output faild!\r\\
");
    // return -EINVAL;
    // }

    // //Output low level, light up the LED light
    // gpio_set_value(led_platform_dev.led_gpio,1);
    
    printk("led_driver_probe\r\\
");
    return 0;
}

static int led_driver_remove(struct platform_device *dev)
{<!-- -->
    //Turn off the LED light
    // gpio_set_value(led_platform_dev.led_gpio,0);

    /*Delete character device*/
    cdev_del(&led_platform_dev.cdev);

    /*Log out character device*/
    unregister_chrdev_region(led_platform_dev.devid,CHRDEV_COUNT_MAX);

    /*Delete device*/
    device_destroy(led_platform_dev.class,led_platform_dev.devid);

    /*Delete class*/
    class_destroy(led_platform_dev.class);


    //Release IO
    gpio_free(led_platform_dev.led_gpio);

    printk("led_driver_remove\r\\
");
    return 0;
}




static const struct of_device_id led_of_match[] =
{<!-- -->
    {<!-- -->
        .compatible = "gpio-leds",
        .data = NULL
    },
    {<!-- -->
        /*Sentinel*/
    },
};

static struct platform_driver led_platform_driver = {<!-- -->
    .driver = {<!-- -->
        //.name = "sunxi-init-gpio", // used for name matching when there is no device tree
        .of_match_table = of_match_ptr(led_of_match),//Device tree matching table
    },
    .probe = led_driver_probe,
    .remove = led_driver_remove,
    
};


//Driver entry
static int __init led_platform_init(void)
{<!-- -->
    int ret = 0;

    //Register platform driver
    ret = platform_driver_register( & amp;led_platform_driver);
    if(ret){<!-- -->
pr_err("led_platform_init user platform_driver_register fail\\
");
return -1;
}

    printk("led_platform_init\r\\
");
    return ret;
}

static void __exit led_platform_exit(void)
{<!-- -->

    platform_driver_unregister( & amp;led_platform_driver);


    printk("led_platform_exit\r\\
");
}

//Register driver and uninstall
module_init(led_platform_init);
module_exit(led_platform_exit);


MODULE_LICENSE("GPL");
MODULE_AUTHOR("China Shanghai/zhouchenliang");