OK6410gpio控制led
led原理图如下:
由原理突分析可得:GPM*(01 2 3) -> NLED* (1 2 3 4)为低时,则VDD33V与NLED*之间有电压差,产生电流,LED亮。即GPM配置成低,LED亮,反之灭
s3c6410手册中对GPM的配置:
前面我们要把GPM*配置为低,达到点亮led的目的,那么我们要配置GPIO,通过GPM我们在芯片手册里找到了GPMCON配置寄存器,关于为什么这个寄存器是这个地址可以去看下统一编址和bank这些内容(我也不是很懂,哈哈)。
既然在芯片手册里找到了这些有用的信息,那么下一步我们就要分析手册和电亮led了。
首先我们获取了GPMCON的地址,通过芯片手册可知,它一共0—23位有效,并每四位控制一个引脚
,即一共控制6个gpio,这些gpio可以配置成8种模式,我们需要的是配置成output模式,并使其输出低电平
看下GPM的定义,当GPMCON配置成输出模式时,引脚的状态和GPMDAT中相应的位状态是一样的,即GPMDAT[i]对应GPM[i]
获取了这些硬件原理和芯片手册的信息,那么下一步我们就可以写linux驱动了
还有几点需要注意的是,在linux下我们用的时虚拟地址,我们要通过我们所直到的GPMCON和GPMDAT的物理地址获取其虚拟地址ioremp
#defineioremap(cookie,size) __arch_ioremap((cookie), (size),MT_DEVICE)
在linux的定义下它是一个和平台相关的宏实现
有了这些我们就可以写驱动了,由于能力有限, 不会写很麻烦的,都是以实现位目的的。。字符型吧。。
关于字符型设备驱动,需要的有 设备号,设备名, 和file_operations的实现
#include <linux/module.h>
#include <linux/init.h>
#include <asm/io.h>
#include <linux/cdev.h>
#include <linux/kernel.h>
#include <linux/fs.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("tyfanxzh");
#define LED_MAJOR 250
struct cdev cdev;
//定义gpio_va的目的是为了可以使定义的宏可以直接通过虚拟地址操作物理地址
static unsigned long gpio_va;
//定义我们需要的GPM控制器的地址 GPMCON: 0x7F008820 GPMDAT: 0x7F008824
#define GPMCON (*(volatile unsigned long*) (gpio_va))
#define GPMDAT (*(volatile unsigned long*) (gpio_va + 4))
//要配置的GPM的值
#define GPM_OUTPUT_MASK (~0xf)
#define GPM_OUTPUT 0x1
#define GPM_DAT 0x1
//实现cdev的fops
int led_open(struct inode *node, struct file *filp)
{
//初始化四个gpio
//初始化GPM0
printk("fanxzh led_open\n");
GPMCON = (GPMCON & ~0xf) | 0x1;
GPMDAT &= ~(0x1);
GPMCON = (GPMCON & ~(0xf << 4)) | (0x1 << 4);
GPMDAT &= ~(0x1 << 1);
GPMCON = (GPMCON & ~(0xf << 8)) | (0x1 << 8);
GPMDAT &= ~(0x1 << 2);
GPMCON = (GPMCON & ~(0xf << 12)) | (0x1 << 12);
GPMDAT &= ~(0x1 << 3);
return 0;
}
int led_close(struct inode *node, struct file *filp)
{
printk("fanxzh Close the file\n");
return 0;
}
long led_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
printk("fanxzh led_ioctl\n");
switch(cmd) {
case 0:
GPMCON = (GPMCON & ~0xf) | 0x1;
GPMDAT |= 0x1;
break;
case 1:
GPMCON = (GPMCON & ~(0xf << 4)) | (0x1 << 4);
GPMDAT |= ~(0x1 << 1);
break;
}
return 0;
}
static const struct file_operations fanxzh_fops = {
.owner = THIS_MODULE,
.open = led_open,
.unlocked_ioctl = led_ioctl,
.release = led_close,
};
int fanxzh_led_init(void)
{
int ret;
dev_t devno = MKDEV(LED_MAJOR, 0);
//test 首先映射物理地址获取其物理地址, 然后对其进行控制,配置GPMCON后然后对pin脚进行控制
gpio_va = (unsigned long)ioremap(0x7F008820, 8);
// GPMCON = (GPMCON & GPM_OUTPUT_MASK) | 0x1; //首先后四位置为0, 然后配置成output模式
// GPMDAT = GPMDAT & ~(0x1); //把最后一位置为0 ,则pin脚输出低电平
printk("Install fanxzh leds module\n");
//开始字符型设备的书写
ret = register_chrdev_region(devno, 1, "fanxzh_led");
if(ret < 0) {
return -1;
}
cdev_init(&cdev, &fanxzh_fops);
cdev.owner = THIS_MODULE;
ret = cdev_add(&cdev, devno, 1);
if(ret) {
printk(KERN_NOTICE "Error: %d adding LED\n", ret);
}
return 0;
}
void fanxzh_led_exit(void)
{
iounmap((void*)gpio_va);
printk("Remove fanxzh leds module\n");
}
module_init(fanxzh_led_init);
module_exit(fanxzh_led_exit);
终于凑了出来。。对于设备模型和gpio还是不熟, 需要继续学习