一、设备树和bit
在设备树中PL下添加一个GPIO,这里使用标号56。
ch_emio {
compatible = "ch,emio_led";
enable_pin {
label = "enable";
gpios = <&gpio0 56 0>;
};
};
vivado 工程打开GPIO,并约束好引脚到LED。编译生成新的.bit文件。
二、程序
/*
* LEDs driver for GPIOs
*
* Copyright (C) 2007 8D Technologies inc.
* Raphael Assenat <[email protected]>
* Copyright (C) 2008 Freescale Semiconductor, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <asm/atomic.h>
#include <asm/unaligned.h>
#include <linux/uaccess.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/string.h>
#include <linux/io.h>
#define DEVICE_NAME "emio_led"
struct gpio_emio{
char name[10];
struct gpio_desc *gpiod;
struct device *gpio_dev;
}gpio_emio_dev;
static int gpio_emio_major;
static struct class* gpio_emio_class = NULL;
static struct device* gpio_emio_device = NULL;
static ssize_t gpio_emio_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos)
{
int ret;
unsigned char val;
ret = copy_from_user(&val,buf,1);
if(ret != 0){
printk("gpio_emio : copy_from_user ret = %d \n",ret);
return -1;
}
printk("gpio_emio_write : gpio = %d \n",val);
gpiod_direction_output(gpio_emio_dev.gpiod, val);
return 0;
}
static const struct file_operations gpio_emio_fops = {
.owner = THIS_MODULE,
.write = gpio_emio_write,
};
static int gpio_emio_init(void)
{
int ret = 0;
char reset_dev_compatible[40] = "ch,emio_led";
char lable_name[40] = "enable";
const char *ledname = lable_name;
struct device_node *reset_dev_node;
struct platform_device *reset_pdev;
struct fwnode_handle *reset_child;
reset_dev_node = of_find_compatible_node(NULL,NULL,reset_dev_compatible);
if(reset_dev_node == NULL)
{
printk("gpio_emio_init : can't find emio_led \n");
return -ENODEV;
}
reset_pdev = of_find_device_by_node(reset_dev_node);
gpio_emio_dev.gpio_dev = &(reset_pdev->dev);
ret = device_get_child_node_count(gpio_emio_dev.gpio_dev);
if(!ret)
{
printk("gpio_emio_init : gpio device get child node count %d \n",ret);
return -ENODEV;
}
reset_child = device_get_next_child_node(gpio_emio_dev.gpio_dev,NULL);
if(!reset_child)
{
printk("gpio_emio_init: device get next child node NULL\n");
return -ENODEV;
}
gpio_emio_dev.gpiod = devm_fwnode_get_gpiod_from_child(gpio_emio_dev.gpio_dev, NULL, reset_child,GPIOD_ASIS,ledname);
if(IS_ERR(gpio_emio_dev.gpiod))
{
printk("gpio_emio_init: devm_get_gpiod_from_child NULL\n");
return -ENODEV;
}
gpiod_direction_output(gpio_emio_dev.gpiod, 1);
//////////////////////////////////////////////////////////////////////////
gpio_emio_major = register_chrdev(0,DEVICE_NAME,&gpio_emio_fops);
if(gpio_emio_major < 0 )
{
printk("emio_init:failed to register device.\n");
return -1;
}
gpio_emio_class = class_create(THIS_MODULE ,"gpio_emio_driver");
if(IS_ERR(gpio_emio_class)){
printk("emio_init:failed to create gpio_emio module class.\n");
unregister_chrdev(gpio_emio_major,DEVICE_NAME);
return -1;
}
gpio_emio_device = device_create(gpio_emio_class,NULL,MKDEV(gpio_emio_major,0),NULL,"gpio0");
if(IS_ERR(gpio_emio_device))
{
printk("gpio_emio_init: failed to create device \n");
class_unregister(gpio_emio_class);
class_destroy(gpio_emio_class);
unregister_chrdev(gpio_emio_major,DEVICE_NAME);
return -1;
}
printk("gpio_emio init done\n");
return 0;
}
static void gpio_emio_exit(void)
{
gpiod_direction_output(gpio_emio_dev.gpiod,0);
devm_gpiod_put(gpio_emio_dev.gpio_dev,gpio_emio_dev.gpiod);
device_destroy(gpio_emio_class,MKDEV(gpio_emio_major,0));
class_unregister(gpio_emio_class);
class_destroy(gpio_emio_class);
unregister_chrdev(gpio_emio_major,DEVICE_NAME);
printk("gpio_emio exit done \n");
}
module_init(gpio_emio_init);
module_exit(gpio_emio_exit);
MODULE_AUTHOR("emio");
MODULE_DESCRIPTION("gpio_emio dirver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("gpio_emio");
三、结果
测试程序同上,改下设备名。