LED驱动---流水灯

原理图
在这里插入图片描述
在这里插入图片描述

应用层程序

#include<stdlib.h>
#include<sys/ioctl.h>

#include "led.h"
int main()
{
	int fd;
	int i = 1;
	fd = open("/dev/led",O_RDWR);
	if(fd < 0)
	{
		perror("open");
		exit(1);
	}
	while(1)
	{
	//需要将用户空间的数据i传送到内核空间,这就存在数据交换
		ioctl(fd,LED_ON,&i);  //i代表第几盏灯
		usleep(5000*100);
		ioctl(fd,LED_OFF,&i);
		usleep(fd,LED_OFF,&i);
		usleep(5000*100);
		if(++i == 5)
		{
			i = 1;
		}
	}
	return 0}
#ifndef s5pv210_LED_HH
#define s5pv210_LED_HH
#define LED_MAGIC 'L'
//参数:魔数,序列号,交换数据的大小
#define LED_ON _IOW(LED_MAGIC,0,int)
#define LED_ON _IOW(LED_MAGIC,1,int)

#endif

驱动程序

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>

#include <asm/io.h>
#include <asm/uaccess.h>

#include"led.h"
MODULE_LICENSE("Dual BSD/GPL");

//把4个LED作为一个设备 
#define LED_MA 500
#define LED_MI 0
#define LED_NUM 1

//LED相关寄存器地址
#define GPF3CON 0x114001E0
#define GPF3DAT 0x114001E4

#define GPX1CON 0x11000C20
#define GPX1DAT 0x11000C24

#define GPFXCON 0x11000C40
#define GPFXDAT 0x11000C44

//内核中使用的是虚拟地址,需要用ioremap将物理地址映射为虚拟地址
//这些指针就是用来保存映射后的虚拟地址
static unsigned int *gpf3con;
static unsigned int *gpf3dat;

static unsigned int *gpx1con
static unsigned int *gpx1dat

static unsigned int *gpx2con
static unsigned int *gpx2dat

//建立映射关系
int fs4412_led_ioremap(void)
{
	int ret;
	gpf3con = ioremap(FS4412_GPF3CON,4);
	if(gpf3con == NULL)
	{
		printk("ioremap gpf3con\n");
		ret = -ENOMEM;
		return ret;
	}
	gpf3dat = ioremap(FS4412_GPF3DAT,4);
	if(gpf3dat == NULL)
	{
		printk("ioremap gpx2dat\n");
	    ret = -ENOMEM;
	    return ret;
	}
	gpfx1con = ioremap(FS4412_GPX1CON,4);
	if(gpx1con == NULL)
	{
		printk("ioremap gpx1con\n");
		ret = -ENOMEM;
		return ret;
	}
	gpfx1dat = ioremap(FS4412_GPX1DAT,4);
	if(gpx1dat == NULL)
	{
		printk("ioremap gpx1dat\n");
		ret = -ENOMEM;
		return ret;
	}
	
	gpfx2con = ioremap(FS4412_GPX2CON,4);
	if(gpx2con == NULL)
	{
		printk("ioremap gpx2con\n");
		ret = -ENOMEM;
		return ret;
	}
	gpfx2dat = ioremap(FS4412_GPX2DAT,4);
	if(gpx2dat == NULL)
	{
		printk("ioremap gpx2dat\n");
		ret = -ENOMEM;
		return ret;
	}	
}
//解除映射,最后映射的,最先解除
void fs4412_led_iounmap(void)
{
	iounmap(gpf3con);
	iounmap(gpf3dat);
	iounmap(gpx1con);
	iounmap(gpx1dat);
	iounmap(gpx2con);
	iounmap(gpx2dat);
}
//初始化,让led输出低电平
void fs4412_led_io_init(void)
{
	writel((readl(gpf3con) & ~(0xff << 16) | (0x11 << 16),gpf3con));
	writel(readl(gpf3dat) & ~(0x3 << 4),gpf3dat);

	writel((readl(gpx1con) & ~(0xf << 0)) |(0x1 << 0),gpx1con);
	writel(readl(gpx1dat) & ~(0x1 <<0),gpx1dat);
	
	writel((readl(gpx2con) &~(0xf << 28)) | (0x1<<28),gpx2con);
	writel(readl(gpx2dat)&~(0x1<<7),gpx2dat);
}
struct file_operations s5pv210_led_fops = {
	.owner = THIS_MODULE,
	.open = s5pv210_led_open,
	.release = s5pv210_led_release,
	.unlocked_ioctl = s5pv210_led_unlocked_ioctl,
};
//ioctl
static long s5pv210_led_unlocked_ioctl(struct file *file,unsigned int cmd,unsigned long arg)
{
	int nr;
	//将用户层的arg放入nr中
	if(copy_from_user((void*)&nr,(void *)arg,sizeof(nr)))
	return -EFAULT;
	if(nr < 1 || nr > 4)
	return -EINVAL;
	switch(cmd)
	{
		case LED_ON:
			fs4412_led_on(nr);
			break;
		case LED_OFF:
			fs4412_led_off(nr);
			break;
		default:
			printk("Invalid argment");
			return EINVAL;
	}
}
//定义一个字符设备
struct cdev cdev;
//点亮led
void fs4412_led_on(int nr)
{
	switch(nr)
	case 1:
		writel(readl(gpx2dat) | 1 << 7,gpx2dat)
		break;
    case 2:
		writel(readl(gpx1dat) | 1 << 0,gpx1dat)
		break;
	case 3:
		writel(readl(gpf3dat) | 1 << 4,gpf3dat)
		break;
	case 4:
		writel(readl(gpf3dat) | 1 << 5,gpf3dat)
		break;
}
//熄灭led
void fs4412_led_on(int nr)
{
	switch(nr)
	case 1:
		writel(readl(gpx2dat) | & ~(1 << 7),gpx2dat)
		break;
    case 2:
		writel(readl(gpx1dat) | & ~(1 << 0),gpx1dat)
		break;
	case 3:
		writel(readl(gpf3dat) | &~(1 << 4),gpf3dat)
		break;
	case 4:
		writel(readl(gpf3dat) | ~(1 << 5),gpf3dat)
		break;
}
static int s5pv210_led_open(struct inode*inode,struct file *file)
{
	return 0;
}
static int s5pv210_led_release(struct inode*inode,struct file*file)
{
	return 0;
}
//加载函数
static int s5pv210_led_init(void)
{
	dev_t devno = MKDEV(LED_MA,LED_MI);
	int ret;
	ret = register_chrdev_region(devno,LED_NUM,"newled");
	if(ret < 0)
	{
		printk("register error\n");
		return ret;
	}
	cdev_init(&cdev,&s5pv210_led_fops);
	cdev.owner = THIS_MODULE;
	ret = cdev_add(&cdev,devno,LED_NUM);
	if(ret < 0)
	{
		printk("cdev_add");
		goto err1;
	}
	//建立映射关系,物理地址-->虚拟地址
	ret = fs4412_led_ioremap();
	if(ret < 0)
	{
		goto err2;
	}
	//led初始化
	fs4412_led_io_init();
	printk("led init\n");
	return 0;
err2:
	cdev_del(&cdev);
err1:
	unregister_chrdev_region(devno,LED_NUM);
	return ret;
}
//字符设备卸载函数
static void s5pv210_led_exit(void)
{
	dev_t devno = MKDEV(LED_MA,LED_MI);
	//解除映射
	fs4412_led_ioupmap();
	cdev_del(&cdev);
	unregister_chrdev_region(devno,LED_NUM);
	printk("LED EXIT\n");
}
module_init(s5pv210_led_init);
module_exit(s5pv210_led_exit);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

<( ̄︶ ̄)Okay.

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

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

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

打赏作者

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

抵扣说明:

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

余额充值