基于iTOP-4412开发板(精英版)的linux 4.14.2系统LED字符驱动程序设计
Posted 气血龙渊
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于iTOP-4412开发板(精英版)的linux 4.14.2系统LED字符驱动程序设计相关的知识,希望对你有一定的参考价值。
一、电路原理图
1、LED灯原理图
开发板底板上有两个LED灯,在开发板使用手册中能够找到其电路原理图如下:
LED2和LED3都用三极管驱动,且三极管基极高电平时导通点亮LED。其中LED2驱动三极管基极与核心板 KP_COL0 引脚连接,LED3驱动三极管基极与核心板 VDD50_EN 引脚连接。
2、核心板原理图
在核心板原理图中我们可以看出KP_COL0 引脚连接到CPU的AA4引脚,也就是说连接到GPL2的D0上了:
在核心板原理图中我们可以看出VDD50_EN 引脚连接到CPU的J2引脚,也就是说连接到GPK1的D1上了:
二、GPIO口操作
1、GPIO口简介
从上面陈述过程能够看出,三星猎户座4412处理器诸多GPIO当中GPK1和GPL2与LED有关,见下图:
2、GPIO口地址
4412的GPIO是通过寄存器操控的,其中GPK与GPL的基地址相同,为:0x1100_0000。GPK1各寄存器如下图:
GPL2各寄存器如下图:
3、GPIO配置寄存器与数据寄存器
GPK1CON寄存器如下图:
从上表中可以看出LED3连接的GPK1_1对应配置寄存器的4至7位,并且赋值为0x1时为输出模式。
GPK1DAT寄存器如下图:
GPL2CON寄存器如下图:
从上表中可以看出LED2连接的GPL2_0对应配置寄存器的0至3位,并且赋值为0x1时为输出模式。
GPL2DAT寄存器如下图:
三、C代码访问GPIO
在linux系统中C语言访问IO内存使用writel()和readl()函数,这两个函数被定义在头文件在io.h当中。
1、配置LED2和LED3引脚为输出引脚
因为LED2连接GPL2_0,所以代码如下:
writel((~(0xf<<0)&readl(GPL2CON_VA))|(0x1<<0),GPL2CON_VA);
因为LED3连接GPK1_1,所以代码如下:
writel((~(0xf<<4)&readl(GPK1CON_VA))|(0x1<<4),GPK1CON_VA);
2、点亮LED2和LED3
因为LED2连接GPL2_0,所以代码如下:
writel(readl(GPL2DAT_VA)|(0x1<<0), GPL2DAT_VA);
因为LED3连接GPK1_1,所以代码如下:
writel(readl(GPK1DAT_VA)|(0x1<<4), GPK1DAT_VA);
3、熄灭LED2和LED3
因为LED2连接GPL2_0,所以代码如下:
writel(readl(GPL2DAT_VA) &(~(0x1<<0)), GPL2DAT_VA);
因为LED3连接GPK1_1,所以代码如下:
writel(readl(GPK1DAT_VA) &(~(0x1<<4)), GPK1DAT_VA);
四、标准字符驱动实现
字符驱动中的基本功能包括设备的注册、设备硬件资源注册、命令接收和LED控制几个部分。代码如下:
#include <linux/module.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/io.h>
#define DRV_NAME "drv_led"
#define DEV_NAME "cdev_led"
#define GPK1_CON_VA GPK1_VA_BASE
#define GPK1_DAT_VA GPK1_VA_BASE+0x1
#define GPK1_PA_BASE 0x11000060
#define GPL2_CON_VA GPL2_VA_BASE
#define GPL2_DAT_VA GPL2_VA_BASE+0x1
#define GPL2_PA_BASE 0x11000100
unsigned int *GPK1_VA_BASE;
unsigned int *GPL2_VA_BASE;
struct cdev cdev;
static struct class *cdev_class;
dev_t dev_id;
int initGPIO(void)
{
writel((readl(GPL2_CON_VA)& ~(0xF<<0)) |(0x1<<0),GPL2_CON_VA);
writel((readl(GPK1_CON_VA)& ~(0xF<<4)) |(0x1<<4),GPK1_CON_VA);
return 0;
}
int led_open(struct inode *node, struct file *filp)
{
initGPIO();
return 0;
}
int setLedData(unsigned int cmd)
{
switch (cmd)
{
case 0:
writel(readl(GPL2_DAT_VA) &(~(0x1<<0)), GPL2_DAT_VA);
writel(readl(GPK1_DAT_VA) &(~(0x1<<1)), GPK1_DAT_VA);
break;
case 1:
writel(readl(GPL2_DAT_VA) |(0x1<<0), GPL2_DAT_VA);
writel(readl(GPK1_DAT_VA) &(~(0x1<<1)), GPK1_DAT_VA);
break;
case 2:
writel(readl(GPL2_DAT_VA) &(~(0x1<<0)), GPL2_DAT_VA);
writel(readl(GPK1_DAT_VA) |(0x1<<1), GPK1_DAT_VA);
break;
case 3:
writel(readl(GPL2_DAT_VA) |(0x1<<0), GPL2_DAT_VA);
writel(readl(GPK1_DAT_VA) |(0x1<<1), GPK1_DAT_VA);
break;
default:
writel(readl(GPL2_DAT_VA) &(~(0x1<<0)), GPL2_DAT_VA);
writel(readl(GPK1_DAT_VA) &(~(0x1<<1)), GPK1_DAT_VA);
}
return 0;
}
long drv_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
if(arg<4) printk("arg is: %d\\n",arg);
setLedData(arg); //arg can be set 00,01,10,11
return 0;
}
static struct file_operations drv_fops =
{
.open = led_open,
.unlocked_ioctl = drv_ioctl,
};
static int cdev_led_init(void)
{
alloc_chrdev_region(&dev_id, 0 , 1 , DEV_NAME);
cdev_init(&cdev,&drv_fops);
cdev_add(&cdev, dev_id, 1);
cdev_class = class_create(THIS_MODULE,DEV_NAME);
device_create(cdev_class,NULL, dev_id, 0, DEV_NAME);
request_mem_region(GPK1_PA_BASE,0x08,"led_io_mem1");
GPK1_VA_BASE = ioremap(GPK1_PA_BASE,0x08);
request_mem_region(GPL2_PA_BASE,0x08,"led_io_mem2");
GPL2_VA_BASE = ioremap(GPL2_PA_BASE,0x08);
printk("GPK1_VA: 0x%08x\\n",(unsigned int)GPK1_VA_BASE);
printk("GPL2_VA: 0x%08x\\n",(unsigned int)GPL2_VA_BASE);
return 0;
}
static void cdev_led_exit(void)
{
device_destroy(cdev_class,dev_id);
class_destroy(cdev_class);
cdev_del(&cdev);
unregister_chrdev_region(dev_id,1);
}
module_init(cdev_led_init);
module_exit(cdev_led_exit);
MODULE_LICENSE("GPL");
以上是关于基于iTOP-4412开发板(精英版)的linux 4.14.2系统LED字符驱动程序设计的主要内容,如果未能解决你的问题,请参考以下文章
基于iTOP-4412开发板(精英版)的linux 4.14.2内核移植
基于iTOP-4412开发板(精英版)的linux 4.14.2内核移植
基于iTOP-4412开发板(精英版)的linux 4.14.2系统LED字符驱动程序设计
基于iTOP-4412开发板(精英版)的linux 4.14.2根文件系统移植