基于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");
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

气血龙渊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值