linux内核驱动学习--GPIO+Pinctrl子系统LED实验

驱动文件

gpio_led.c

#include "gpio_led.h"


struct gpioled_dev  gpioled;

static int gpioled_open (struct inode *inode, struct file *filp)
{
    filp->private_data = &gpioled;
    return 0;
}

static int gpioled_release (struct inode *inode, struct file *filp)
{
    struct gpioled_dev *dev = (struct gpioled_dev *)filp->private_data;
    return 0;
}

static ssize_t gpioled_write (struct file *filp, const char __user *buf, size_t count, loff_t *ppos)
{
    struct gpioled_dev *dev = (struct gpioled_dev *)filp->private_data;
    int retval = 0;
    unsigned char buffer[1] = { 0 };

    retval = copy_from_user(buffer, buf, count);
    if ( retval < 0 ) {
        printk("kernel write failed\r\n");
        return -EFAULT;
    }
    printk("read sta = %d\r\n", buffer[0]);
    //判断开灯还是关灯
    if(buffer[0] == LEDON) {
        gpio_set_value(dev->led_gpio, 0); /* 打开 LED 灯 */
    } else if(buffer[0] == LEDOFF) {
        gpio_set_value(dev->led_gpio, 1); /* 关闭 LED 灯 */
    }
    
    return 0;
}


static struct file_operations gpioled_fops = {
    .owner   = THIS_MODULE,
    .open    = gpioled_open,
    .release = gpioled_release,
    .write   = gpioled_write,
};

static int __init dts_led_start(void)
{
    int ret = 0;
    
    /* 注册字符设备驱动 */

    /* 1、创建设备号 */
    if (gpioled.major) {    /* 定义了设备号 */
        gpioled.devid = MKDEV(gpioled.major, 0);
        ret = register_chrdev_region(gpioled.major, DTSLED_CNT, DTSLED_NAME);
    }
    else {                 /* 未定义设备号 */
        ret = alloc_chrdev_region(&(gpioled.devid), 0, DTSLED_CNT, DTSLED_NAME);
        gpioled.major = MAJOR(gpioled.devid);
        gpioled.minor = MINOR(gpioled.devid);
    }
    if (ret < 0) {
        goto FAILED_DEVID;
    }
    printk("gpioled major=%d,minor=%d\r\n",gpioled.major, gpioled.minor);
    
    /* 2. 添加字符设备 */
    cdev_init(&(gpioled.ledCdev), &gpioled_fops);
    ret = cdev_add(&(gpioled.ledCdev), gpioled.devid, DTSLED_CNT);
    if (ret < 0) {
        printk("添加字符设备错误\r\n");
        goto FAILED_CDEV;
    }

    /* 自动创建设备节点 */
    gpioled.ledClass = class_create(THIS_MODULE, DTSLED_NAME);
    if (IS_ERR(gpioled.ledClass)) {
        ret = PTR_ERR(gpioled.ledClass);
        goto FAILED_CLASS;
    }
    
    gpioled.ledDevice = device_create(gpioled.ledClass, NULL, gpioled.devid, NULL, DTSLED_NAME);
    if (IS_ERR(gpioled.ledDevice)) {
        ret = PTR_ERR(gpioled.ledDevice);
        goto FAILED_DEVICE;
    }

    /* 获取设备树属性内容 */
    gpioled.nd = of_find_node_by_path("/gpioled");
    if (gpioled.nd == NULL) {
        ret = -EINVAL;
        printk("gpioled node cant not found!\r\n");
        goto FAILED_GETDTSNODE;
    }
    else {
        printk("gpioled node has been found!\r\n");
    }

    /* 获取设备树中的 gpio 属性,得到 LED 所使用的 LED 编号 */
    gpioled.led_gpio = of_get_named_gpio(gpioled.nd, "led-gpio", 0);
    if (gpioled.led_gpio < 0) {
        printk("can't get led-gpio");
        ret = -EINVAL;
        goto FAILED_GETDTSNODE;
    }
    printk("led-gpio num = %d\r\n", gpioled.led_gpio);

    /* 设置 GPIO1_IO03 为输出,并且输出高电平,默认关闭 LED 灯 */
    gpio_request(gpioled.led_gpio, "led");
    ret = gpio_direction_output(gpioled.led_gpio, 1);
    if(ret < 0) {
        printk("can't set gpio!\r\n");
    }
    
    return 0;

FAILED_GETDTSNODE:
    device_destroy(gpioled.ledClass, gpioled.devid);

FAILED_DEVICE:
    class_destroy(gpioled.ledClass);

FAILED_CLASS:
    cdev_del(&(gpioled.ledCdev));

FAILED_CDEV:
    unregister_chrdev_region(gpioled.devid, DTSLED_CNT);

FAILED_DEVID:
    return ret;
}


static void __exit dts_led_exit(void)
{
    /* 关闭 LED 灯 */
    gpio_set_value(gpioled.led_gpio, 1); 
    /* 销毁设备节点 */
    device_destroy(gpioled.ledClass, gpioled.devid);
    class_destroy(gpioled.ledClass);
    /* 删除字符设备 */
    cdev_del(&(gpioled.ledCdev));
    /* 释放设备号 */
    unregister_chrdev_region(gpioled.devid, DTSLED_CNT);
}

module_init(dts_led_start);
module_exit(dts_led_exit);
MODULE_LICENSE("GPL");


头文件

gpio_led.h

#ifndef __GPIO_LED_H
#define __GPIO_LED_H

#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <linux/gpio.h>
#include <asm/io.h>
#include <linux/fs.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>





#define DTSLED_CNT          1           /* 设备号个数 */
#define DTSLED_NAME         "gpioled"    /* 设备名字 */
#define LEDOFF              0           /* 关灯 */
#define LEDON               1           /* 开灯 */


/* 映射后的寄存器虚拟地址指针 */

/* dtsled 设备结构体 */
struct gpioled_dev{
    dev_t               devid;
    struct cdev         ledCdev;
    struct class       *ledClass;
    struct device      *ledDevice;
    int                 major;
    int                 minor;
    struct device_node *nd;        /* 设备节点 */
    unsigned int        led_gpio;  /* led 所使用的 GPIO 编号 */
};
extern struct gpioled_dev  gpioled;

#endif


测试文件

gpioled_test.c

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

int main(int argc, char *argv[])
{
    int fd;
    unsigned char sta = 0;
    int i;
    fd = open("/dev/gpioled", O_RDWR);
    if (fd == -1) {
        printf("/dev/dtsled open failed\r\n");
        return -1;
    }

    for (i = 0; i < 10; i++) {
        sta = i % 2;
        printf("sta = %d\r\n", sta);
        write(fd, &sta, sizeof(sta));
        sleep(1);
    }

    close(fd);
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值