S5PV210 基于设备树点亮LED

device tree:

/* 添加 led 节点 */
led {
	#address-cells = <1>;
	#size-cells = <1>;
	compatible = "s5pv210, led";
	ranges; /* 这个非常重要,必须添加,不然of_iomap就不能成功*/

	/* 蓝灯子节点 */
	blue_led@0xe0200240 {
		compatible = "s5pv210, blue_led";
		reg = <
				0xe0200240 0x4
				0xe0200244 0x4
		      >;
		status = "okay";
		pin = <0x3>;
	};

	/* 黄灯子节点 */
	yellow_led@0xe0200240 {
		compatible = "s5pv210, yellow_led";
		reg = <
				0xe0200240 0x4
				0xe0200244 0x4
		      >;
		status = "okay";
		pin = <0x4>;
	};

	/* 红灯子节点 */
	red_led@0xe0200240 {
		compatible = "s5pv210, red_led";
		reg = <
				0xe0200240 0x4
				0xe0200244 0x4
		      >;
		status = "okay";
		pin = <0x5>;
	};

驱动程序:

#include <linux/module.h>		
#include <linux/init.h>
#include <linux/platform_device.h>
#include <asm/io.h>
#include <linux/types.h>
#include <linux/cdev.h>
#include <linux/fs.h>

/* dts */
#include <linux/of.h>
#include <linux/of_address.h>

#define DEV_CNT		(1)
#define DEV_NAME	"s5pv210_led"

struct led_ctrl
{
	void __iomem * blue_led_reg_con;
	void __iomem * blue_led_reg_dat;
	int blue_led_pin;

	void __iomem * yellow_led_reg_con;
	void __iomem * yellow_led_reg_dat;
	int yellow_led_pin;

	void __iomem * red_led_reg_con;
	void __iomem * red_led_reg_dat;
	int red_led_pin;

	/* char device driver*/
	dev_t dev_id;
	struct cdev led_chr_dev;
	struct class * led_class;
	struct device * led_device;
};

static struct led_ctrl g_led_ctrl = {0};

static int led_chr_dev_open(struct inode *inode, struct file *filp)
{
	printk(KERN_INFO "open driver\n");
	return 0;
}

int led_chr_dev_release(struct inode *inode, struct file *filp)
{
	printk(KERN_INFO "release driver\n");
	return 0;
}

static ssize_t led_chr_dev_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{
	int ret = -1;
	unsigned int user_data = 0;
	unsigned int reg_data = 0;
	ret = copy_from_user(&user_data, buf, cnt);
	if (ret < 0)
	{
		printk(KERN_INFO "copy_from_user error\n");
		return -EINVAL;
	}
	/* bit[0:7]: blue_led, bit[8:15]: yellow led, bit[16:23]: red led*/
	if (user_data & 0xff)
	{
		reg_data = readl(g_led_ctrl.blue_led_reg_dat);
		reg_data &= ~(0x1 << g_led_ctrl.blue_led_pin );
		writel(reg_data, g_led_ctrl.blue_led_reg_dat);
	}
	else
	{
		reg_data = readl(g_led_ctrl.blue_led_reg_dat);
		reg_data &= ~(0x1 << g_led_ctrl.blue_led_pin );
		reg_data |= (0x1 << g_led_ctrl.blue_led_pin);
		writel(reg_data, g_led_ctrl.blue_led_reg_dat);
	}

	if ((user_data >> 8) & 0xff)
	{
		reg_data = readl(g_led_ctrl.yellow_led_reg_dat);
		reg_data &= ~(0x1 << g_led_ctrl.yellow_led_pin );
		writel(reg_data, g_led_ctrl.yellow_led_reg_dat);
	}
	else
	{
		reg_data = readl(g_led_ctrl.yellow_led_reg_dat);
		reg_data &= ~(0x1 << g_led_ctrl.yellow_led_pin );
		reg_data |= (0x1 << g_led_ctrl.yellow_led_pin);
		writel(reg_data, g_led_ctrl.yellow_led_reg_dat);
	}

	if ((user_data >> 16) & 0xff)
	{
		reg_data = readl(g_led_ctrl.red_led_reg_dat);
		reg_data &= ~(0x1 << g_led_ctrl.red_led_pin );
		writel(reg_data, g_led_ctrl.red_led_reg_dat);
	}
	else
	{
		reg_data = readl(g_led_ctrl.red_led_reg_dat);
		reg_data &= ~(0x1 << g_led_ctrl.red_led_pin );
		reg_data |= (0x1 << g_led_ctrl.red_led_pin);
		writel(reg_data, g_led_ctrl.red_led_reg_dat);
	}
	return 0;
}

/*字符设备操作函数集*/
static struct file_operations led_chr_dev_fops =
{
	.owner = THIS_MODULE,
	.open = led_chr_dev_open,
	.write = led_chr_dev_write,
};

static int s5pv210_led_probe(struct platform_device * device)
{
	int ret = -1;
	unsigned int reg_data = 0;
	struct device_node	* s5pv210_led = NULL;
	struct device_node	* s5pv210_led_blue = NULL;
	struct device_node	* s5pv210_led_yellow = NULL;
	struct device_node	* s5pv210_led_red = NULL;

	/*
	find led in /
	*/
	s5pv210_led = of_find_node_by_path("/led");
	if (NULL == s5pv210_led)
	{
		printk(KERN_INFO "of_find_node_by_path error\n");
		goto blue_led_reg_con_err;
	}

	/*
	child blue_led
	*/
	s5pv210_led_blue = of_find_node_by_name(s5pv210_led, "blue_led");
	if (NULL == s5pv210_led_blue)
	{
		printk(KERN_INFO "of_find_node_by_name error\n");
		goto blue_led_reg_con_err; 
	}
	ret = of_property_read_u32(s5pv210_led_blue, "pin", &(g_led_ctrl.blue_led_pin));
    if (ret)
	{
		printk(KERN_ERR "of_property_read_u32 error\n");
		goto blue_led_reg_con_err;
	}

	g_led_ctrl.blue_led_reg_con = of_iomap(s5pv210_led_blue, 0);
	if (NULL == g_led_ctrl.blue_led_reg_con)
	{
		printk(KERN_INFO "of_iomap blue_led_reg_con error\n");
		goto blue_led_reg_con_err;
	}

	g_led_ctrl.blue_led_reg_dat = of_iomap(s5pv210_led_blue, 1);
	if (NULL == g_led_ctrl.blue_led_reg_dat)
	{
		printk(KERN_INFO "of_iomap blue_led_reg_dat error\n");
		goto blue_led_reg_dat_err;
	}

	reg_data = readl(g_led_ctrl.blue_led_reg_con);
	reg_data &= ~(0xf << (g_led_ctrl.blue_led_pin * 4));
	reg_data |= (0x1 << (g_led_ctrl.blue_led_pin * 4));
	writel(reg_data, g_led_ctrl.blue_led_reg_con);

	reg_data = readl(g_led_ctrl.blue_led_reg_dat);
	reg_data &= ~(0x1 << g_led_ctrl.blue_led_pin );
	reg_data |= (0x1 << g_led_ctrl.blue_led_pin);
	writel(reg_data, g_led_ctrl.blue_led_reg_dat);

	/*
	child yellow_led
	*/
	s5pv210_led_yellow = of_find_node_by_name(s5pv210_led, "yellow_led");
	if (NULL == s5pv210_led_yellow)
	{
		printk(KERN_INFO "of_find_node_by_name error\n");
		goto blue_led_reg_dat_err; 
	}
	ret = of_property_read_u32(s5pv210_led_yellow, "pin",
		&(g_led_ctrl.yellow_led_pin));
	if (ret)
	{
		printk(KERN_ERR "of_property_read_u32 error\n");
		goto blue_led_reg_dat_err;
	}
	g_led_ctrl.yellow_led_reg_con = of_iomap(s5pv210_led_yellow, 0);
	if (NULL == g_led_ctrl.yellow_led_reg_con)
	{
		printk(KERN_INFO "of_iomap yellow_led_reg_con error\n");
		goto yellow_led_reg_con_err;
	}
	g_led_ctrl.yellow_led_reg_dat = of_iomap(s5pv210_led_yellow, 1);
	if (NULL == g_led_ctrl.yellow_led_reg_dat)
	{
		printk(KERN_INFO "of_iomap yellow_led_reg_dat error\n");
		goto yellow_led_reg_dat_err;
	}
	reg_data = readl(g_led_ctrl.yellow_led_reg_con);
	reg_data &= ~(0xf << (g_led_ctrl.yellow_led_pin * 4));
	reg_data |= (0x1 << (g_led_ctrl.yellow_led_pin * 4));
	writel(reg_data, g_led_ctrl.yellow_led_reg_con);

	reg_data = readl(g_led_ctrl.yellow_led_reg_dat);
	reg_data &= ~(0x1 << g_led_ctrl.yellow_led_pin );
	reg_data |= (0x1 << g_led_ctrl.yellow_led_pin);
	writel(reg_data, g_led_ctrl.yellow_led_reg_dat);

	/*
	child red_led
	*/
	s5pv210_led_red = of_find_node_by_name(s5pv210_led, "red_led");
	if (NULL == s5pv210_led_red)
	{
		printk(KERN_INFO "of_find_node_by_name error\n");
		goto yellow_led_reg_dat_err;
	}
	ret = of_property_read_u32(s5pv210_led_red, "pin",
		&(g_led_ctrl.red_led_pin));
	if (ret)
	{
		printk(KERN_ERR "of_property_read_u32 error\n");
		goto yellow_led_reg_dat_err;
	}
	g_led_ctrl.red_led_reg_con = of_iomap(s5pv210_led_red, 0);
	if (NULL == g_led_ctrl.red_led_reg_con)
	{
		printk(KERN_INFO "of_iomap red_led_reg_con error\n");
		goto red_led_reg_con_err;
	}
	g_led_ctrl.red_led_reg_dat = of_iomap(s5pv210_led_red, 1);
	if (NULL == g_led_ctrl.red_led_reg_dat)
	{
		printk(KERN_INFO "of_iomap red_led_reg_con error\n");
		goto red_led_reg_dat_err;
	}
	reg_data = readl(g_led_ctrl.red_led_reg_con);
	reg_data &= ~(0xf << (g_led_ctrl.red_led_pin * 4));
	reg_data |= (0x1 << (g_led_ctrl.red_led_pin * 4));
	writel(reg_data, g_led_ctrl.red_led_reg_con);

	reg_data = readl(g_led_ctrl.red_led_reg_dat);
	reg_data &= ~(0x1 << g_led_ctrl.red_led_pin );
	reg_data |= (0x1 << g_led_ctrl.red_led_pin);
	writel(reg_data, g_led_ctrl.red_led_reg_dat);

	/* char device driver*/
	ret = alloc_chrdev_region(&g_led_ctrl.dev_id, 0, DEV_CNT, DEV_NAME);
	if (ret)
	{
		printk(KERN_INFO "alloc_chrdev_region error\n");
		goto red_led_reg_dat_err;
	}
	g_led_ctrl.led_chr_dev.owner = THIS_MODULE;
	cdev_init(&g_led_ctrl.led_chr_dev, &led_chr_dev_fops);
	ret = cdev_add(&g_led_ctrl.led_chr_dev, g_led_ctrl.dev_id, DEV_CNT);
	if (ret)
	{
		printk(KERN_INFO "cdev_add error\n");
		goto cdev_add_err;
	}
	g_led_ctrl.led_class = class_create(THIS_MODULE, DEV_NAME);
	if (NULL == g_led_ctrl.led_class)
	{
		printk(KERN_INFO "class_create error\n");
		goto class_create_err;
	}
	g_led_ctrl.led_device = device_create(g_led_ctrl.led_class, NULL, g_led_ctrl.dev_id, NULL, DEV_NAME);
	if (NULL == g_led_ctrl.led_device)
	{
		printk(KERN_INFO "device_create error\n");
		goto device_create_err;
	}
	return 0;
device_create_err:
	class_destroy(g_led_ctrl.led_class);
class_create_err:
	cdev_del(&g_led_ctrl.led_chr_dev);
cdev_add_err:
	unregister_chrdev_region(g_led_ctrl.dev_id, DEV_CNT);
red_led_reg_dat_err:
	iounmap(g_led_ctrl.red_led_reg_con);
red_led_reg_con_err:
	iounmap(g_led_ctrl.yellow_led_reg_dat);
yellow_led_reg_dat_err:
	iounmap(g_led_ctrl.yellow_led_reg_con);
yellow_led_reg_con_err:
	iounmap(g_led_ctrl.blue_led_reg_dat);
blue_led_reg_dat_err:
	iounmap(g_led_ctrl.blue_led_reg_con);
blue_led_reg_con_err:
	return -EINVAL;
}

static int s5pv210_led_remove(struct platform_device * device)
{
	device_destroy(g_led_ctrl.led_class, g_led_ctrl.dev_id);
	class_destroy(g_led_ctrl.led_class);
	cdev_del(&g_led_ctrl.led_chr_dev);
	unregister_chrdev_region(g_led_ctrl.dev_id, DEV_CNT);
	iounmap(g_led_ctrl.blue_led_reg_con);
	iounmap(g_led_ctrl.blue_led_reg_dat);
	iounmap(g_led_ctrl.yellow_led_reg_con);
	iounmap(g_led_ctrl.yellow_led_reg_dat);
	iounmap(g_led_ctrl.red_led_reg_con);
	iounmap(g_led_ctrl.red_led_reg_dat);
	return 0;
}

static const struct of_device_id s5pv210_led_of_match_table[] =
{
	{.compatible = "s5pv210, led",},
	{},
};

static struct platform_driver s5pv210_led_driver = 
{
	.probe = s5pv210_led_probe,
	.remove = s5pv210_led_remove,
	.driver = {
		.name = "s5pv210_led",
		.owner = THIS_MODULE,
		.of_match_table = s5pv210_led_of_match_table,
	}
};

// 模块安装函数
static int __init chrdev_init(void)
{
	int ret = platform_driver_register(&s5pv210_led_driver);
	if (ret)
	{
		printk(KERN_INFO "platform_driver_register fail\n");
		return -EINVAL; 
	}
	printk(KERN_INFO "platform_driver_register ok\n");
	return 0;
}

// 模块卸载函数
static void __exit chrdev_exit(void)
{
	platform_driver_unregister(&s5pv210_led_driver);
	printk(KERN_INFO "platform_driver_unregister\n");
}


module_init(chrdev_init);
module_exit(chrdev_exit);

// MODULE_xxx这种宏作用是用来添加模块描述信息
MODULE_LICENSE("GPL");				// 描述模块的许可证
MODULE_AUTHOR("Mark");				// 描述模块的作者
MODULE_DESCRIPTION("test for driver");	// 描述模块的介绍信息
MODULE_ALIAS("alias test");			// 描述模块的别名信息

应用程序:

#include <iostream>
#include <thread>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#define ON   	(true)
#define OFF     (false)

#define DEVICE_NAME	"/dev/s5pv210_led"

class Led
{
public:
	Led(int on_off);
	~Led(void);

	void ctrlSubBlueLed(int on_off);
	void ctrlSubYellowLed(int on_off);
	void ctrlSubRedLed(int on_off);
	void ctrlAllLed(int on_off);
private:
	unsigned char subBlueStatus;
	unsigned char subYellowStatus;
	unsigned char subRedStatus;

	int fd;
};

Led::Led(int on_off) : fd(0)
{
	unsigned int status = 0;
	subBlueStatus = on_off;
	subYellowStatus = on_off;
	subRedStatus = on_off;

	fd = open(DEVICE_NAME, O_RDWR);
	if (fd < 0)
	{
		std::cout << DEVICE_NAME << "open fail\n";
		return;
	}
	status = (subBlueStatus) | (subYellowStatus << 8) | (subRedStatus << 16);
	write(fd, &status, sizeof(status));
}

Led::~Led(void)
{
	unsigned int status = 0;
	if (0 != fd)
	{
		write(fd, &status, sizeof(status));
		close(fd);
	}
}

void Led::ctrlSubBlueLed(int on_off)
{
	unsigned int status = 0;
	subBlueStatus = on_off;
	status |= subBlueStatus;
	write(fd, &status, sizeof(status));
}

void Led::ctrlSubYellowLed(int on_off)
{
	unsigned int status = 0;
	subYellowStatus = on_off;
	status |= (subYellowStatus << 8);
	write(fd, &status, sizeof(status));
}

void Led::ctrlSubRedLed(int on_off)
{
	unsigned int status = 0;
	subRedStatus = on_off;
	status |= (subRedStatus << 16);
	write(fd, &status, sizeof(status));
}

void Led::ctrlAllLed(int on_off)
{
	unsigned int status = 0;
	subBlueStatus = on_off;
	subYellowStatus = on_off;
	subRedStatus = on_off;
	status = (subBlueStatus) | (subYellowStatus << 8) | (subRedStatus << 16);
	write(fd, &status, sizeof(status));
}

void ledShowTask(void)
{
	Led ledCtrlObj(OFF);
	std::string cmd = "";
	while (1)
	{
		ledCtrlObj.ctrlAllLed(ON);
		usleep(500 * 1000);
		ledCtrlObj.ctrlAllLed(OFF);
		usleep(500 * 1000);
		ledCtrlObj.ctrlSubBlueLed(ON);
		usleep(500 * 1000);
		ledCtrlObj.ctrlSubBlueLed(OFF);
		usleep(500 * 1000);
		ledCtrlObj.ctrlSubYellowLed(ON);
		usleep(500 * 1000);
		ledCtrlObj.ctrlSubYellowLed(OFF);
		usleep(500 * 1000);
		ledCtrlObj.ctrlSubRedLed(ON);
		usleep(500 * 1000);
		ledCtrlObj.ctrlSubRedLed(OFF);
		usleep(500 * 1000);
	}
}

int main(int argc, char const *argv[])
{
	std::thread ledShow(ledShowTask);
	ledShow.join();
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值