写一个rv1106的led驱动3-功能函数编写

修改设备树

由于vdd_arm没有通过pwm进行调压,所以在设备树取消这个节点。

c 复制代码
	/*
	vdd_arm: vdd-arm {
		compatible = "pwm-regulator";
		pwms = <&pwm0 0 5000 1>;
		regulator-name = "vdd_arm";
		regulator-min-microvolt = <724000>;
		regulator-max-microvolt = <1078000>;
		regulator-init-microvolt = <950000>;
		regulator-always-on;
		regulator-boot-on;
		regulator-settling-time-up-us = <250>;
	};
	*/
c 复制代码
//&cpu0 {
//	cpu-supply = <&vdd_arm>;
//};

在设备树添加LED节点

c 复制代码
	led: led{
		compatible = "led";
		status = "okay";

		led1-gpios = <&gpio1 RK_PA2 GPIO_ACTIVE_HIGH>;
	};

probe函数获led节点

c 复制代码
static int led_probe(struct platform_device *pdev)
{
	int ret;
	struct led_device *ldev;

	printk("%s enter\n", __func__);

	//给私有的ledv分配内存
	ldev = devm_kzalloc(&pdev->dev, sizeof(struct led_device), GFP_KERNEL);
	if (!ldev) {
		ret = -ENOENT;
		dev_err(&pdev->dev, "kzalloc led device memery error\n");
		goto error_devm_kzalloc;
	}

	//私有的dev指向平台设备的dev
	ldev->dev = &pdev->dev;

	//互斥锁和线程锁初始化
	mutex_init(&ldev->dev_mutex);
	spin_lock_init(&ldev->slock);

	//把ldev挂到pdev
	platform_set_drvdata(pdev, ldev);

	//注册misc驱动
	ldev->misc_dev.minor = MISC_DYNAMIC_MINOR;
	ldev->misc_dev.name = "led";
	//fops指明打开,释放,操作函数
	ldev->misc_dev.fops = &led_fops;
	ret = misc_register(&ldev->misc_dev);
	if (ret < 0) {
		ret = -ENOENT;
		dev_err(&pdev->dev, "misc_register failed\n");
	}

	//获取gpio
	ret = led_request_gpio(pdev, ldev);
	if (ret) {
		printk("led_request_gpio fail\n");
		ret = -1;
		goto led_request_gpio_fail;
	}
	printk("led pin id is %d \r\n", ldev->led.led_gpio);

	printk("%s leave\n", __func__);
	return 0;
led_request_gpio_fail:

error_devm_kzalloc:
	return ret;
}
led_request_gpio函数获取gpio
c 复制代码
static int led_request_gpio(struct platform_device *pdev, struct led_device *ldev)
{
	int ret;
	int GPIO_ID_LED1 = -1;


	//获得led1的id
	GPIO_ID_LED1 = of_get_named_gpio(pdev->dev.of_node, "led1-gpios", 0);
	if (GPIO_ID_LED1 < 0) {
		printk("get LED1 named is error!\n");
		return -1;
	}

	//申请led1的gpio控制权
	ret = gpio_request(GPIO_ID_LED1, "led1_gpio");
	if (ret != 0) {
		printk("led1 gpio request is error!\n");
		return -1;
	}
	
	//设置方向
	ret = gpio_direction_output(GPIO_ID_LED1, 0);
	if (ret) {
		printk("led1 set direction fail%d\n", ret);
		goto free_gpio;
	}

	//把led的gpio保存到ldev结构体中
	ldev->led.led_gpio = GPIO_ID_LED1;
	return 0;

	free_gpio:
	if (GPIO_ID_LED1  != -1)
		gpio_free(GPIO_ID_LED1);

	return -1;
}

修改led.h文件

c 复制代码
/* ioctl cmd */
#define LED_ON          _IOW('M', 0, long)
#define LED_OFF         _IOW('M', 1, long)

struct led_device_attribute {
	bool led_status;
	int led_gpio;
};

struct led_device {
	struct miscdevice misc_dev;
	struct device *dev;
	struct mutex dev_mutex;
	spinlock_t slock;
    int led_open_flag;
	struct hrtimer led_timer;
	struct led_device_attribute led;
};

在led_device结构体加多struct led_device_attribute led元素

led_device_attribute 结构体
c 复制代码
struct led_device_attribute {
	bool led_status;
	int led_gpio;
};
操作字
c 复制代码
/* ioctl cmd */
#define LED_ON          _IOW('M', 0, long)
#define LED_OFF         _IOW('M', 1, long)

这样在probe的时候,驱动能获得gpio的控制权。

操作函数led_ioctl

c 复制代码
//操作函数
static long led_ioctl(struct file *file, unsigned int cmd, unsigned long value)
{
	struct miscdevice *dev = file->private_data;
	struct led_device *ldev = container_of(dev, struct led_device, misc_dev);
	long ret = 0;

	if (ldev->led_open_flag == 0) {
		printk("Please Open /dev/led Firstly\n");
		return -EPERM;
	}
	printk("cmd: %u\r\n", cmd);

	//判断是什么命令
	switch (cmd) {
	//开灯
	case LED_ON: {
		gpio_set_value(ldev->led.led_gpio, 1);
		break;
	}
	//关灯
	case LED_OFF: {
		gpio_set_value(ldev->led.led_gpio, 0);
		break;
	}
	//都不是
	default:
		return -EINVAL;
	}
	return ret;

}

测试程序

c 复制代码
/* ioctl cmd */
#define LED_ON          _IOW('M',0,long)
#define LED_OFF         _IOW('M',1,long)

int led_fd = -1;

void main(void)
{

    led_fd = open("/dev/led", O_RDWR);
    printf("led fd is %d\r\n", led_fd);
    ioctl(led_fd, LED_ON, 0);
    sleep(1);
    ioctl(led_fd, LED_OFF, 0);
    close(led_fd);

}

通过ioctl函数往内核发送命令

测试

重新编译内核,驱动,测试程序,进入系统后insmod led.ko,可见/dev下有led这个名称的设备,运行test_led这个测试程序,可见led灯亮了一秒,然后熄灭。

相关推荐
月白风清江有声2 小时前
vscode使用git
linux·运维·服务器
zl_dfq2 小时前
Linux 之 【文件】(ext2文件系统、目录、软硬链接)
linux
物理与数学2 小时前
Linux 内核 LRU 页面置换算法
linux·linux内核
小白同学_C4 小时前
Lab1-Xv6 and Unix utilities 配置环境的搭建以及前言 && MIT6.1810操作系统工程【持续更新】
linux·c/c++·操作系统os
haluhalu.4 小时前
深入理解Linux线程机制:线程概念,内存管理
java·linux·运维
乙酸氧铍4 小时前
【imx6ul 学习笔记】Docker 运行百问网 imx6ul_qemu
linux·docker·arm·qemu·imx6ul
不会C++的雾4 小时前
Linux操作系统(2)
linux·数据库·mysql
Code-world-14 小时前
NVIDIA Isaac Sim 安装教程
linux·人工智能·ubuntu·强化学习·isaac sim
cui__OaO5 小时前
Linux驱动--驱动编译
linux·运维·服务器