Introduction to driver for "s3c6410 LED"
折腾着非得写个LED driver出来~不然心里都不舒服...
内核版本:3.0.1
环境: Ubuntu14.0 TSL
开发板上嵌有4个LED灯
4个LED对应的ARM芯片上的引脚
易知,这里4个LED对应的IO引脚就是GPM0~GPM3
三个寄存器控制这里的GPIO -- GPM0~GPM3
- GPMCON
- GPMDAT
- GPMPUD
这里gpio-bank-m.h定义了GPM相关的寄存器地址~这是一层爽歪歪的封装~(发现这是飞凌添加的header file...)
/* linux/arch/arm/plat-s3c64xx/include/plat/gpio-bank-m.h
*
* Copyright 2008 Openmoko, Inc.
* Copyright 2008 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
* http://armlinux.simtec.co.uk/
*
* GPIO Bank M register and configuration definitions
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#define S3C64XX_GPMCON (S3C64XX_GPM_BASE + 0x00)
#define S3C64XX_GPMDAT (S3C64XX_GPM_BASE + 0x04)
#define S3C64XX_GPMPUD (S3C64XX_GPM_BASE + 0x08)
#define S3C64XX_GPM_CONMASK(__gpio) (0x3 << ((__gpio) * 2))
#define S3C64XX_GPM_INPUT(__gpio) (0x0 << ((__gpio) * 2))
#define S3C64XX_GPM_OUTPUT(__gpio) (0x1 << ((__gpio) * 2))
#define S3C64XX_GPM0_HOSTIF_CS (0x02 << 0)
#define S3C64XX_GPM0_EINT23 (0x03 << 0)
#define S3C64XX_GPM0_RESERVED1 (0x04 << 0)
#define S3C64XX_GPM0_DATA_CF10 (0x05 << 0)
#define S3C64XX_GPM0_CE_CF0 (0x06 << 0)
#define S3C64XX_GPM0_RESERVED2 (0x07 << 0)
#define S3C64XX_GPM1_HOSTIF_CS_M (0x02 << 0)
#define S3C64XX_GPM1_EINT24 (0x03 << 0)
#define S3C64XX_GPM1_RESERVED1 (0x04 << 0)
#define S3C64XX_GPM1_DATA_CF11 (0x05 << 0)
#define S3C64XX_GPM1_CE_CF1 (0x06 << 0)
#define S3C64XX_GPM1_RESERVED2 (0x07 << 0)
#define S3C64XX_GPM2_HOSTIF_IF_CS_S (0x02 << 0)
#define S3C64XX_GPM2_EINT25 (0x03 << 0)
#define S3C64XX_GPM2_HOSTIF_MDP_VSYNC (0x04 << 0)
#define S3C64XX_GPM2_DATA_CF12 (0x05 << 0)
#define S3C64XX_GPM2_IORD_CF (0x06 << 0)
#define S3C64XX_GPM2_RESERVED2 (0x07 << 0)
#define S3C64XX_GPM3_HOSTIF_WE (0x02 << 0)
#define S3C64XX_GPM3_EINT26 (0x03 << 0)
#define S3C64XX_GPM3_RESERVED1 (0x04 << 0)
#define S3C64XX_GPM3_DATA_CF13 (0x05 << 0)
#define S3C64XX_GPM3_IOWR_CF (0x06 << 0)
#define S3C64XX_GPM3_RESERVED2 (0x07 << 0)
#define S3C64XX_GPM4_HOSTIF_OE (0x02 << 0)
#define S3C64XX_GPM4_EINT27 (0x03 << 0)
#define S3C64XX_GPM4_RESERVED1 (0x04 << 0)
#define S3C64XX_GPM4_DATA_CF14 (0x05 << 0)
#define S3C64XX_GPM4_IORDY_CF (0x06 << 0)
#define S3C64XX_GPM4_RESERVED2 (0x07 << 0)
#define S3C64XX_GPM5_HOSTIF_INTR (0x02 << 0)
#define S3C64XX_GPM5_CF_DATA_DIR (0x03 << 0)
#define S3C64XX_GPM5_RESERVED1 (0x04 << 0)
#define S3C64XX_GPM5_DATA_CF15 (0x05 << 0)
#define S3C64XX_GPM5_RESERVED2 (0x06 << 0)
#define S3C64XX_GPM5_RESERVED3 (0x07 << 0)
相关的有宏定义
S3C64XX_GPM_BASE
这个在regs-gpio.h 里面
节选了部分,不全部贴出了
...
#define S3C64XX_GPL_BASE S3C64XX_GPIOREG(0x0810)
#define S3C64XX_GPM_BASE S3C64XX_GPIOREG(0x0820)
#define S3C64XX_GPN_BASE S3C64XX_GPIOREG(0x0830)
...
Here my source code for my led-device driver.
/*
code writer : EOF
code date : 2014.08.19.com
code file : led_by_EOF.c
e-mail : jasonleaster@gmail.com
code purpos:
This code is a demo for beginner how to write a
character device to drive IO port.
If you find there is something wrong with my code
and change it into a better version , please touch me
by e-mail. Thank you.
*/
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <asm/uaccess.h> /* for 'copy_from_user' */
#include <linux/cdev.h>
#include <linux/kdev_t.h>
#include <linux/types.h>
#include <mach/gpio-bank-m.h>
#include <mach/regs-gpio.h>
#include <mach/map.h>
#include <linux/pci.h>
#include <linux/device.h>
#include <linux/delay.h> /* for 'msleep' */
MODULE_AUTHOR("EOF");
MODULE_LICENSE("Dual BSD/GPL");
#define DEVICE_NAME "led_by_EOF"
#define DEVICE_MAJOR_NUMBER 0
#define USE_IMMEDIATE
static dev_t dev_number = DEVICE_MAJOR_NUMBER;
static struct class* led_class;
static struct cdev my_led_cdev;
static int led_open(struct inode* node,struct file* file)
{
printk(KERN_ALERT "Device Opened successful!\n");
return 0;
}
static ssize_t led_write(struct file* file,const char __user* buf,size_t count,loff_t* ppos)
{
int kbuf;
int ret = 0;
kbuf = readl(S3C64XX_GPMCON);
kbuf &= (~0xFFFF);
kbuf |= 0x1111;
writel(kbuf,S3C64XX_GPMCON);
printk(KERN_ALERT "before writing... &kbuf:%p buf:%p\n",&kbuf,buf);
ret = __copy_from_user(&kbuf,buf,count);
if(ret != 0)
{
printk(KERN_ALERT "'__copy_from_user' failed! ret:%d\n",ret);
return -1;
}
printk(KERN_ALERT "writing... kbuf:%x \n",kbuf);
writel(kbuf,S3C64XX_GPMDAT);
return 0;
}
static int led_release(struct inode* inode,struct file*file)
{
printk(KERN_ALERT "Device released\n");
return 0;
}
static struct file_operations led_fops =
{
.owner = THIS_MODULE,
.open = led_open,
.write = led_write,
.release= led_release,
};
int led_init(void)
{
int kbuf;
if(alloc_chrdev_region(&dev_number,0,1,DEVICE_NAME) < 0)
{
printk(KERN_ALERT "Error in function '%s' : can't register device\n",__FUNCTION__);
return -1;
}
led_class = class_create(THIS_MODULE,DEVICE_NAME);
if(IS_ERR(led_class))
{
printk(KERN_ALERT "Bad class create\n");
return -1;
}
cdev_init(&my_led_cdev,&led_fops);
/*
** GPM0~GPM3 pull up
*/
kbuf = readl(S3C64XX_GPMPUD);
kbuf &= (~0xFF);
kbuf |= 0xaa;//1010 1010
writel(kbuf,S3C64XX_GPMPUD);
/*
** GPM0~3 output mode
*/
kbuf = readl(S3C64XX_GPMCON);
kbuf &= (~0xFFFF);
kbuf |= 0x1111;
writel(kbuf,S3C64XX_GPMCON);
/*
** GPM0~GPM3 output 0 and light up all LED
*/
kbuf = __raw_readl(S3C64XX_GPMDAT);
kbuf |= 0x10;
writel(kbuf,S3C64XX_GPMDAT);
if(cdev_add(&my_led_cdev,dev_number,1))
{
printk(KERN_ALERT "Bad cdev add\n");
return 1;
}
device_create(led_class,NULL,dev_number,NULL,DEVICE_NAME);
return 0;
}
void led_cleanup(void)
{
device_destroy(led_class,MKDEV(MAJOR(dev_number),0));
class_destroy(led_class);
unregister_chrdev_region(MAJOR(dev_number),1);
printk(KERN_ALERT "See you! My LED\n");
}
module_init(led_init);
module_exit(led_cleanup);
Test code:
/*
code writer : EOF
code date : 2014.08.19.com
code file : led_by_EOF.c
e-mail : jasonleaster@gmail.com
code purpos:
This code is a demo for test my led-device.
If you find there is something wrong with my code
and change it into a better version , please touch me
by e-mail. Thank you.
*/
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
int main()
{
int fd = 0;
int ret = 0;
if((fd = open("/dev/led_by_EOF",O_RDWR)) < 0)
{
printf("line %d open failed\n",__LINE__);
return 0;
}
int buf = 0;
int time = 0;
buf = 0x0;
for(time = 0,buf = 0;time < 5;time++)
{
if((ret = write(fd,&buf,sizeof(buf))) < 0)
{
printf("write error!\n ret : %d\n",ret);
//goto failed;
}
else
{
printf("write successful! ret %d,buf:%d &buf:%p\n",ret,buf,&buf);
}
buf = ~buf;
sleep(2);
}
failed:
close(fd);
return 0;
}
最后灯会闪亮