tiny6410 platform led驅動

實現了對s3c6410開發板led燈的控制

led_dev.c:

#include<linux/init.h>
#include<linux/module.h>
#include<linux/platform_device.h>
#include<linux/device.h>

#define DEVICE_NAME "tiny6410_leds"

static struct resource tiny6410_leds_resource[] = {
    [0] = {
        .start = 0x7f008800,
        .end = 0x7f008800 + 16, //16字節,包括gpkcon0,gpkcon1,gpkdat,gpkpud
        .flags = IORESOURCE_MEM,
    },
};

static void tiny6410_leds_platform_device_release(struct device *dev)
{
    printk("[remove platform_device]\n");
    return ;
}

//初始化,並添加資源
static struct platform_device tiny6410_leds_platform_device = {
    .name = DEVICE_NAME,
    .id = -1, //表示同名的驅動只有一個
    .num_resources = ARRAY_SIZE(tiny6410_leds_resource),
    .resource = tiny6410_leds_resource,
    .dev = {
        .release = tiny6410_leds_platform_device_release,
    },
};

static int __init tiny6410_leds_platform_device_init(void)
{
    printk("[tiny6410_leds_platform_device init]\n");
    return platform_device_register(&tiny6410_leds_platform_device); // >0表示添加platform_device失敗
}

static void __exit tiny6410_leds_platform_device_exit(void)
{
    printk("[tiny6410_leds_platform_device exit]\n");
    platform_device_unregister(&tiny6410_leds_platform_device);
}

module_init(tiny6410_leds_platform_device_init);
module_exit(tiny6410_leds_platform_device_exit);

MODULE_AUTHOR("ZHYANG");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("tiny6410_leds_platform_device");


led_drv.c:

#include<linux/init.h>
#include<linux/module.h>
#include<linux/fs.h>
#include<linux/platform_device.h>
#include<linux/miscdevice.h>
#include<linux/device.h>
#include<linux/pci.h>
#include<linux/uaccess.h>

#define DEVICE_NAME "tiny6410_leds"

// static struct class *tiny6410_leds_class = NULL; //miscdevice會自動創建設備節點,手動申請設備號會用到
// static struct device *tiny6410_leds_device = NULL; //這邊佔不演示
// 方法:在__init函數中先class_create,再device_create
//       在__exit中先device_destroy,再class_destroy

static volatile unsigned long *gpkcon0 = NULL;
static volatile unsigned long *gpkdat = NULL;

static int tiny6410_leds_open(struct inode *inode,struct file *filp)
{
    unsigned long tmp;

    //配置GPKCON0的GPK4-GPK7位爲0001輸出
    tmp = readl(gpkcon0);
    tmp = (tmp & ~(0xffff << 16)) | (0x1111 << 16);
    writel(tmp,gpkcon0);
    //初始化GPK4-GPK7爲1,即燈滅
    tmp = readl(gpkdat);
    tmp |= (0xF << 4);
    writel(tmp,gpkdat);
    
    printk("[tiny6410_leds_open]\n");
    return 0;
}

static ssize_t tiny6410_leds_write(struct file *filp,const char __user *buf,size_t count,loff_t *ppos)
{
    char val; //1或0表示全亮滅
    unsigned long tmp;

    int ret = copy_from_user(&val,buf,count);
    // printk("[val = %c]\n",val);
    if(val=='1'){
        tmp = readl(gpkdat);
        tmp &= ~(0xf << 4);
        writel(tmp,gpkdat);
    }else{
        tmp = readl(gpkdat);
        tmp |= 0xf << 4;
        writel(tmp,gpkdat);
    }

    printk("[tiny6410_leds_write]\n");
    return ret;
}

//文件操作結構體的初始化
static struct file_operations tiny6410_leds_fops = {
    .owner = THIS_MODULE,
    .open = tiny6410_leds_open,
    .write = tiny6410_leds_write,
};

//雜項設備的初始化
static struct miscdevice tiny6410_leds_miscdevice = {
    .minor = MISC_DYNAMIC_MINOR,
    .name = DEVICE_NAME,  //特殊,name必須這麼指定,因爲Misc會自動創建設備節點
    .fops = &tiny6410_leds_fops,
};

static int __devinit tiny6410_leds_platform_driver_probe(struct platform_device *pdev)
{
    
    int ret;
    struct resource *res_gpk;

    ret = misc_register(&tiny6410_leds_miscdevice);//註冊雜項設備
    res_gpk = platform_get_resource(pdev,IORESOURCE_MEM,0); //獲取平臺設備資源0
    gpkcon0 = ioremap(res_gpk->start,16); //物理地址到虛擬地址的映射
    gpkdat = gpkcon0 + 2;
    
    printk("[tiny6410_leds_platform_driver_probe]\n");
    return ret;
}

static int __devexit tiny6410_leds_platform_driver_remove(struct platform_device *pdev)
{
    iounmap(gpkcon0); //取消映射
    misc_deregister(&tiny6410_leds_miscdevice);//註銷雜項設備

    printk("[tiny6410_leds_platform_driver_remove]\n");
    return 0;
}

//platform_driver初始化
static struct platform_driver tiny6410_leds_platform_driver = {
    .probe = tiny6410_leds_platform_driver_probe,
    .remove = tiny6410_leds_platform_driver_remove,
    .driver = {
        .owner = THIS_MODULE,
        .name = DEVICE_NAME,
    },
};

static int __init tiny6410_leds_platform_driver_init(void)
{
    printk("[tiny6410_leds_platform_driver_init]\n");

    return platform_driver_register(&tiny6410_leds_platform_driver); //註冊平臺驅動
}

static void __exit tiny6410_leds_platform_driver_exit(void)
{
    printk("[tiny6410_leds_platform_driver_exit]\n");

    platform_driver_unregister(&tiny6410_leds_platform_driver); //註銷平臺驅動
}

module_init(tiny6410_leds_platform_driver_init);
module_exit(tiny6410_leds_platform_driver_exit);

MODULE_AUTHOR("ZHYANG");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("tiny6410_leds_platform_driver");


Makefile:

obj-m := led_drv.o led_dev.o

KDIR := /opt/FriendlyARM/mini6410/linux/linux-2.6.38/

all:
    make -C $(KDIR) M=$(PWD) modules

clean:
    rm -f *.ko *.o *.mod.* *.order *.symvers


測試程序test_led.c:

#include<stdio.h>
#include<fcntl.h>

int main(int argc,char **argv)
{
    int fd;
    char on; //1亮0滅

    if(argc != 2){
        printf("usage:./test_led 0|1\n");
        return -1;
    }
    on = *argv[1];
    // printf("%c\n",on);
    fd = open("/dev/tiny6410_leds",O_RDWR);
    if(fd < 0){
        printf("open device tiny6410_leds failed\n");
        return -1;
    }
    if(write(fd,&on,1) == 0)  //0表示成功
        printf("write success\n");
    else printf("write fail\n");
    
    close(fd);
    return 0;
}


步驟:

1.make生成兩個.ko文件,裝載到板子裏,lsmod或ls /sys/bus/platform/device和driver都能看到對應的tiny6410_leds

2.arm-linux-gcc 編譯生成測試程序

3.先停止板上的led流水燈:/etc/rc.d/init.d/leds stop,然後     ./test_led 0全滅   ./test_led 1全亮

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章