led驱动程序框架

//led_app.c
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/ioctl.h>

#define LED_MAGIC 'L'

#define LED_ON	_IOW(LED_MAGIC, 0, int)
#define LED_OFF	_IOW(LED_MAGIC, 1, int)

int main(int argc, char **argv)
{
	int fd;

	fd = open("/dev/led", O_RDWR);
	if (fd < 0) {
		perror("open");
		exit(1);
	}

	while(1)
	{
		ioctl(fd, LED_ON);
		usleep(100000);
		ioctl(fd, LED_OFF);
		usleep(100000);
	}

	return 0;
}
//led_driver.c
//这种不需要配置设备树,直接就操作寄存器了
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>

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

MODULE_LICENSE("Dual BSD/GPL");

#define LED_MAGIC 'L'
/*
 * need arg = 1/2 
 */

#define LED_ON	_IOW(LED_MAGIC, 0, int)
#define LED_OFF	_IOW(LED_MAGIC, 1, int)


#define LED_MA 500
#define LED_MI 0
#define LED_NUM 1

#define FS4412_GPX2CON	0x11000C40
#define FS4412_GPX2DAT	0x11000C44

static unsigned int *gpx2con;
static unsigned int *gpx2dat;

struct cdev cdev;

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 long s5pv210_led_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
	int nr;

	switch (cmd) {
		case LED_ON:
			writel(readl(gpx2dat) | 1 << 7, gpx2dat);
			break;
		case LED_OFF:
			writel(readl(gpx2dat) & ~(1 << 7), gpx2dat);
			break;
	}

	return 0;
}
	
struct file_operations s5pv210_led_fops = {
	.owner = THIS_MODULE,
	.open = s5pv210_led_open,
	.release = s5pv210_led_release,
	.unlocked_ioctl = s5pv210_led_unlocked_ioctl,
};

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_chrdev_region\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\n");
		goto err1;
	}

	gpx2con = ioremap(FS4412_GPX2CON, 4);
	if (gpx2con == NULL) {
		printk("ioremap gpx2con\n");
		ret = -ENOMEM;
		goto err2;
	}

	gpx2dat = ioremap(FS4412_GPX2DAT, 4);
	if (gpx2dat == NULL) {
		printk("ioremap gpx2dat\n");
		ret = -ENOMEM;
		goto err3;
	}
        
        //配置GPIO为输出
	writel((readl(gpx2con) & ~(0xf << 28)) | (0x1 << 28), gpx2con);
	writel(readl(gpx2dat) & ~(0x1<<7), gpx2dat);

	printk("Led init\n");

	return 0;
err3:
	iounmap(gpx2con);
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);

	iounmap(gpx2dat);
	iounmap(gpx2con);
	cdev_del(&cdev);
	unregister_chrdev_region(devno, LED_NUM);
	printk("Led exit\n");
}

module_init(s5pv210_led_init);
module_exit(s5pv210_led_exit);
//led_platform_driver.c
//平台设备驱动的优势在于设备可以通过设备树去配置了
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>

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

MODULE_LICENSE("Dual BSD/GPL");

#define LED_MAGIC 'L'
/*
 * need arg = 1/2 
 */

#define LED_ON	_IOW(LED_MAGIC, 0, int)
#define LED_OFF	_IOW(LED_MAGIC, 1, int)


#define LED_MA 500
#define LED_MI 0
#define LED_NUM 1

#define FS4412_GPX2CON	0x11000C40
#define FS4412_GPX2DAT	0x11000C44

struct cdev cdev;
struct device_node *dn = NULL;
int gpio;

	
static long hello_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
	switch (cmd) {
		case LED_ON:
			gpio_set_value_cansleep(gpio, 1);
			break;
		case LED_OFF:
			gpio_set_value_cansleep(gpio, 0);
			break;
	}

	return 0;
}
	
struct file_operations hello_fops = {
	.owner = THIS_MODULE,
	.unlocked_ioctl = hello_ioctl,
};


int hello_probe(struct platform_device *dev)
{
	dev_t devno = MKDEV(LED_MA, LED_MI); 
	int ret;

	printk("hello_probe\n");
	ret = register_chrdev_region(devno, LED_NUM, "newled");
	if (ret < 0) {
		printk("register_chrdev_region\n");
		return ret;
	}

	cdev_init(&cdev, &hello_fops);
	cdev.owner = THIS_MODULE;
	ret = cdev_add(&cdev, devno, LED_NUM);
	if (ret < 0) {
		printk("cdev_add\n");
		goto err1;
	}

	dn = of_find_node_by_path("/fs4412led");
	if (dn==NULL) {
		printk("of_find_node_by_path error\n");
		goto err2;
	}

	gpio = of_get_named_gpio(dn, "led2", 0);
	if (!gpio_is_valid(gpio)) {
		printk("gpio is not valid: %d\n", gpio);
		goto err2;
	}

	if (gpio_request(gpio, NULL)) {
		printk("gpio_request error\n");
		goto err2;
	}
		
	gpio_direction_output(gpio, 0);

	printk("Led init\n");

	return 0;

err2:
	cdev_del(&cdev);
err1:
	unregister_chrdev_region(devno, LED_NUM);
	return ret;
}

int hello_remove(struct platform_device *dev)
{
	dev_t devno = MKDEV(LED_MA, LED_MI);
	cdev_del(&cdev);
	unregister_chrdev_region(devno, LED_NUM);
	printk("hello_remove\n");
	return 0;
}

static const struct of_device_id hello_of_match[] = {
	{ .compatible = "haha,led" },
	{/* Sentinel */ }
};

struct platform_driver hello_driver = {
	.probe      = hello_probe,
	.remove     = hello_remove,
	.driver     = {
		.name   = "hello_17031", //如果设备是由device.c编写的,则由这个进行匹配
		.owner  = THIS_MODULE,
		.of_match_table = hello_of_match,  //因为设备是用设备树编的,那么设备和驱动匹配就是靠这个,而不是靠上面那个.name
	},  
};

static int hello_init(void)
{
	printk("hello_init\n");	
	return platform_driver_register(&hello_driver);
}

static void hello_exit(void)
{
	platform_driver_unregister(&hello_driver);
	printk("hello_exit\n");
}

module_init(hello_init);
module_exit(hello_exit);

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值