linux_module_learn/led_dev/led.c

197 lines
4.9 KiB
C

#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/wait.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/device.h>
#include <linux/io.h>
#include "led.h"
static dev_t devno = 0;
static uint32_t led_major = LED_MAJOR;
static uint32_t led_minor = 0;
static struct class *led_class;
static struct led_chrdev led_cdev[DEV_CNT] = {
{.pa_dr = 0x0209C000,.pa_gdir = 0x0209C004,.pa_iomuxc_mux =
0x20E006C,.pa_ccm_ccgrx = 0x20C406C,.pa_iomux_pad =
0x20E02F8,.led_pin = 4,.clock_offset = 26},
{.pa_dr = 0x20A8000,.pa_gdir = 0x20A8004,.pa_iomuxc_mux =
0x20E01E0,.pa_ccm_ccgrx = 0x20C4074,.pa_iomux_pad =
0x20E046C,.led_pin = 20,.clock_offset = 12},
{.pa_dr = 0x20A8000,.pa_gdir = 0x20A8004,.pa_iomuxc_mux =
0x20E01DC,.pa_ccm_ccgrx = 0x20C4074,.pa_iomux_pad =
0x20E0468,.led_pin = 19,.clock_offset = 12},
};
static int led_open(struct inode *inode, struct file *filp)
{
uint32_t val = 0;
struct led_chrdev *my_led_dev = NULL;
PDEBUG("led open %d:%d...\n",MAJOR(inode->i_rdev),MINOR(inode->i_rdev));
my_led_dev = container_of(inode->i_cdev, struct led_chrdev, dev);
filp->private_data = my_led_dev;
my_led_dev->va_ccm_ccgrx = ioremap(my_led_dev->pa_ccm_ccgrx,4);
my_led_dev->va_dr = ioremap(my_led_dev->pa_dr,4);
my_led_dev->va_gdir = ioremap(my_led_dev->pa_gdir,4);
my_led_dev->va_iomuxc_mux = ioremap(my_led_dev->pa_iomuxc_mux,4);
my_led_dev->va_iomux_pad = ioremap(my_led_dev->pa_iomux_pad,4);
val = ioread32(my_led_dev->va_ccm_ccgrx);
val &= ~(3 << my_led_dev->clock_offset);
val |= 3 << my_led_dev->clock_offset;
iowrite32(val, my_led_dev->va_ccm_ccgrx);
iowrite32(5, my_led_dev->va_iomuxc_mux);
iowrite32(0x1F838, my_led_dev->va_iomux_pad);
val = ioread32(my_led_dev->va_gdir);
val &= ~(1 << my_led_dev->led_pin);
val |= (1 << my_led_dev->led_pin);
iowrite32(val, my_led_dev->va_gdir);
val = ioread32(my_led_dev->va_dr);
val |= (0x01 << my_led_dev->led_pin);
iowrite32(val, my_led_dev->va_dr);
return 0;
}
static ssize_t led_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{
return cnt;
}
static ssize_t led_write(struct file *filp,const char __user *buf,size_t cnt, loff_t *offt)
{
uint32_t val = 0;
uint32_t ret = 0;
struct led_chrdev *my_led_dev = NULL;
PDEBUG("led write...\n");
my_led_dev = filp->private_data;
kstrtoul_from_user(buf,cnt,10,&ret);
PDEBUG("ret = %u\n",ret);
val = ioread32(my_led_dev->va_dr);
if (ret)
val &= ~(0x01 << my_led_dev->led_pin);
else
val |= (0x01 << my_led_dev->led_pin);
iowrite32(val, my_led_dev->va_dr);
*offt += cnt;
return cnt;
}
static int led_release(struct inode *inode, struct file *filp)
{
struct led_chrdev *my_led_dev = NULL;
my_led_dev = container_of(inode->i_cdev, struct led_chrdev, dev);
iounmap(my_led_dev->va_ccm_ccgrx);
iounmap(my_led_dev->va_dr);
iounmap(my_led_dev->va_gdir);
iounmap(my_led_dev->va_iomuxc_mux);
iounmap(my_led_dev->va_iomux_pad);
return 0;
}
static struct file_operations led_fops = {
.owner = THIS_MODULE,
.open = led_open,
.read = led_read,
.write = led_write,
.release = led_release,
};
static int __init my_led_init(void)
{
uint32_t ret = 0;
uint32_t i = 0;
dev_t cur_dev = 0;
printk(KERN_INFO "led Module Init start\n");
if(led_major){
devno = MKDEV(led_major,led_minor);
ret = register_chrdev_region(devno, DEV_CNT, "led");
}
else{
ret = alloc_chrdev_region(&devno, 0, DEV_CNT, "led");
led_major = MAJOR(devno);
}
if(ret < 0){
printk(KERN_ERR "chrdev alloc region failed\n");
return ret;
}
printk(KERN_INFO "devno is %u(0x%x)(major:%u,minor:%u)\n",devno,devno,led_major,led_minor);
led_class = class_create(THIS_MODULE, "led_class");
if(IS_ERR(led_class))
{
printk(KERN_ERR" create class faild!/n");
return -EBUSY;
}
for(i = 0; i< DEV_CNT; i++)
{
cdev_init(&led_cdev[i].dev, &led_fops);
led_cdev[i].dev.owner = THIS_MODULE;
cur_dev = MKDEV(MAJOR(devno), MINOR(devno) + i);
cdev_add(&led_cdev[i].dev, cur_dev, 1);
device_create(led_class,NULL,cur_dev,NULL,"led_%s",(i == 0)?"red":((i == 1)? "green":"blue"));
}
return ret;
}
static void __exit my_led_exit(void)
{
uint32_t i = 0;
dev_t cur_dev = 0;
for(i =0 ; i < DEV_CNT; i++){
cur_dev = MKDEV(MAJOR(devno), MINOR(devno) + i);
device_destroy(led_class,cur_dev);
cdev_del(&led_cdev[i].dev);
}
class_destroy(led_class);
if(!devno)
unregister_chrdev_region(devno, DEV_CNT);
printk("LED Module Exit\n");
}
module_init(my_led_init);
module_exit(my_led_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("liuchao");