修改设备树
由于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灯亮了一秒,然后熄灭。