2023-03-29 linux 驱动用gpiod来控制gpio,devm_gpiod_get_optional gpiod_get_index gpiod_to_irq等的使用,带实例

一、gpiod子系统是新版的linux内核引入的控制gpio的子系统,这个子系统的功能更为强大,在很多地方都会碰到,在工作过程中尽量使用gpiod子系统,很有必要学习一下。

二、Linux 内核GPIOD介绍文档 kernel\Documentation\gpio\consumer.txt,kernel/include/linux/gpio/consumer.h 包含下面的函数

#ifndef __LINUX_GPIO_CONSUMER_H
#define __LINUX_GPIO_CONSUMER_H

#include <linux/bug.h>
#include <linux/err.h>
#include <linux/kernel.h>

struct device;

/**
 * Opaque descriptor for a GPIO. These are obtained using gpiod_get() and are
 * preferable to the old integer-based handles.
 *
 * Contrary to integers, a pointer to a gpio_desc is guaranteed to be valid
 * until the GPIO is released.
 */
struct gpio_desc;

/**
 * Struct containing an array of descriptors that can be obtained using
 * gpiod_get_array().
 */
struct gpio_descs {
	unsigned int ndescs;
	struct gpio_desc *desc[];
};

#define GPIOD_FLAGS_BIT_DIR_SET		BIT(0)
#define GPIOD_FLAGS_BIT_DIR_OUT		BIT(1)
#define GPIOD_FLAGS_BIT_DIR_VAL		BIT(2)

/**
 * Optional flags that can be passed to one of gpiod_* to configure direction
 * and output value. These values cannot be OR'd.
 */
enum gpiod_flags {
	GPIOD_ASIS	= 0,
	GPIOD_IN	= GPIOD_FLAGS_BIT_DIR_SET,
	GPIOD_OUT_LOW	= GPIOD_FLAGS_BIT_DIR_SET | GPIOD_FLAGS_BIT_DIR_OUT,
	GPIOD_OUT_HIGH	= GPIOD_FLAGS_BIT_DIR_SET | GPIOD_FLAGS_BIT_DIR_OUT |
			  GPIOD_FLAGS_BIT_DIR_VAL,
};

#ifdef CONFIG_GPIOLIB

/* Return the number of GPIOs associated with a device / function */
int gpiod_count(struct device *dev, const char *con_id);

/* Acquire and dispose GPIOs */
struct gpio_desc *__must_check gpiod_get(struct device *dev,
					 const char *con_id,
					 enum gpiod_flags flags);
struct gpio_desc *__must_check gpiod_get_index(struct device *dev,
					       const char *con_id,
					       unsigned int idx,
					       enum gpiod_flags flags);
struct gpio_desc *__must_check gpiod_get_optional(struct device *dev,
						  const char *con_id,
						  enum gpiod_flags flags);
struct gpio_desc *__must_check gpiod_get_index_optional(struct device *dev,
							const char *con_id,
							unsigned int index,
							enum gpiod_flags flags);
struct gpio_descs *__must_check gpiod_get_array(struct device *dev,
						const char *con_id,
						enum gpiod_flags flags);
struct gpio_descs *__must_check gpiod_get_array_optional(struct device *dev,
							const char *con_id,
							enum gpiod_flags flags);
void gpiod_put(struct gpio_desc *desc);
void gpiod_put_array(struct gpio_descs *descs);

struct gpio_desc *__must_check devm_gpiod_get(struct device *dev,
					      const char *con_id,
					      enum gpiod_flags flags);
struct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev,
						    const char *con_id,
						    unsigned int idx,
						    enum gpiod_flags flags);
struct gpio_desc *__must_check devm_gpiod_get_optional(struct device *dev,
						       const char *con_id,
						       enum gpiod_flags flags);
struct gpio_desc *__must_check
devm_gpiod_get_index_optional(struct device *dev, const char *con_id,
			      unsigned int index, enum gpiod_flags flags);
struct gpio_descs *__must_check devm_gpiod_get_array(struct device *dev,
						     const char *con_id,
						     enum gpiod_flags flags);
struct gpio_descs *__must_check
devm_gpiod_get_array_optional(struct device *dev, const char *con_id,
			      enum gpiod_flags flags);
void devm_gpiod_put(struct device *dev, struct gpio_desc *desc);
void devm_gpiod_put_array(struct device *dev, struct gpio_descs *descs);

int gpiod_get_direction(struct gpio_desc *desc);
int gpiod_direction_input(struct gpio_desc *desc);
int gpiod_direction_output(struct gpio_desc *desc, int value);
int gpiod_direction_output_raw(struct gpio_desc *desc, int value);

/* Value get/set from non-sleeping context */
int gpiod_get_value(const struct gpio_desc *desc);
void gpiod_set_value(struct gpio_desc *desc, int value);
void gpiod_set_array_value(unsigned int array_size,
			   struct gpio_desc **desc_array, int *value_array);
int gpiod_get_raw_value(const struct gpio_desc *desc);
void gpiod_set_raw_value(struct gpio_desc *desc, int value);
void gpiod_set_raw_array_value(unsigned int array_size,
			       struct gpio_desc **desc_array,
			       int *value_array);

/* Value get/set from sleeping context */
int gpiod_get_value_cansleep(const struct gpio_desc *desc);
void gpiod_set_value_cansleep(struct gpio_desc *desc, int value);
void gpiod_set_array_value_cansleep(unsigned int array_size,
				    struct gpio_desc **desc_array,
				    int *value_array);
int gpiod_get_raw_value_cansleep(const struct gpio_desc *desc);
void gpiod_set_raw_value_cansleep(struct gpio_desc *desc, int value);
void gpiod_set_raw_array_value_cansleep(unsigned int array_size,
					struct gpio_desc **desc_array,
					int *value_array);

int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce);

int gpiod_is_active_low(const struct gpio_desc *desc);
int gpiod_cansleep(const struct gpio_desc *desc);

int gpiod_to_irq(const struct gpio_desc *desc);

/* Convert between the old gpio_ and new gpiod_ interfaces */
struct gpio_desc *gpio_to_desc(unsigned gpio);
int desc_to_gpio(const struct gpio_desc *desc);

/* Child properties interface */
struct fwnode_handle;

struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
					 const char *propname);
struct gpio_desc *devm_get_gpiod_from_child(struct device *dev,
					    const char *con_id,
					    struct fwnode_handle *child);
#else /* CONFIG_GPIOLIB */

static inline int gpiod_count(struct device *dev, const char *con_id)
{
	return 0;
}

static inline struct gpio_desc *__must_check gpiod_get(struct device *dev,
						       const char *con_id,
						       enum gpiod_flags flags)
{
	return ERR_PTR(-ENOSYS);
}
static inline struct gpio_desc *__must_check
gpiod_get_index(struct device *dev,
		const char *con_id,
		unsigned int idx,
		enum gpiod_flags flags)
{
	return ERR_PTR(-ENOSYS);
}

static inline struct gpio_desc *__must_check
gpiod_get_optional(struct device *dev, const char *con_id,
		   enum gpiod_flags flags)
{
	return ERR_PTR(-ENOSYS);
}

static inline struct gpio_desc *__must_check
gpiod_get_index_optional(struct device *dev, const char *con_id,
			 unsigned int index, enum gpiod_flags flags)
{
	return ERR_PTR(-ENOSYS);
}

static inline struct gpio_descs *__must_check
gpiod_get_array(struct device *dev, const char *con_id,
		enum gpiod_flags flags)
{
	return ERR_PTR(-ENOSYS);
}

static inline struct gpio_descs *__must_check
gpiod_get_array_optional(struct device *dev, const char *con_id,
			 enum gpiod_flags flags)
{
	return ERR_PTR(-ENOSYS);
}

static inline void gpiod_put(struct gpio_desc *desc)
{
	might_sleep();

	/* GPIO can never have been requested */
	WARN_ON(1);
}

static inline void gpiod_put_array(struct gpio_descs *descs)
{
	might_sleep();

	/* GPIO can never have been requested */
	WARN_ON(1);
}

static inline struct gpio_desc *__must_check
devm_gpiod_get(struct device *dev,
		 const char *con_id,
		 enum gpiod_flags flags)
{
	return ERR_PTR(-ENOSYS);
}
static inline
struct gpio_desc *__must_check
devm_gpiod_get_index(struct device *dev,
		       const char *con_id,
		       unsigned int idx,
		       enum gpiod_flags flags)
{
	return ERR_PTR(-ENOSYS);
}

static inline struct gpio_desc *__must_check
devm_gpiod_get_optional(struct device *dev, const char *con_id,
			  enum gpiod_flags flags)
{
	return ERR_PTR(-ENOSYS);
}

static inline struct gpio_desc *__must_check
devm_gpiod_get_index_optional(struct device *dev, const char *con_id,
				unsigned int index, enum gpiod_flags flags)
{
	return ERR_PTR(-ENOSYS);
}

static inline struct gpio_descs *__must_check
devm_gpiod_get_array(struct device *dev, const char *con_id,
		     enum gpiod_flags flags)
{
	return ERR_PTR(-ENOSYS);
}

static inline struct gpio_descs *__must_check
devm_gpiod_get_array_optional(struct device *dev, const char *con_id,
			      enum gpiod_flags flags)
{
	return ERR_PTR(-ENOSYS);
}

static inline void devm_gpiod_put(struct device *dev, struct gpio_desc *desc)
{
	might_sleep();

	/* GPIO can never have been requested */
	WARN_ON(1);
}

static inline void devm_gpiod_put_array(struct device *dev,
					struct gpio_descs *descs)
{
	might_sleep();

	/* GPIO can never have been requested */
	WARN_ON(1);
}


static inline int gpiod_get_direction(const struct gpio_desc *desc)
{
	/* GPIO can never have been requested */
	WARN_ON(1);
	return -ENOSYS;
}
static inline int gpiod_direction_input(struct gpio_desc *desc)
{
	/* GPIO can never have been requested */
	WARN_ON(1);
	return -ENOSYS;
}
static inline int gpiod_direction_output(struct gpio_desc *desc, int value)
{
	/* GPIO can never have been requested */
	WARN_ON(1);
	return -ENOSYS;
}
static inline int gpiod_direction_output_raw(struct gpio_desc *desc, int value)
{
	/* GPIO can never have been requested */
	WARN_ON(1);
	return -ENOSYS;
}


static inline int gpiod_get_value(const struct gpio_desc *desc)
{
	/* GPIO can never have been requested */
	WARN_ON(1);
	return 0;
}
static inline void gpiod_set_value(struct gpio_desc *desc, int value)
{
	/* GPIO can never have been requested */
	WARN_ON(1);
}
static inline void gpiod_set_array_value(unsigned int array_size,
					 struct gpio_desc **desc_array,
					 int *value_array)
{
	/* GPIO can never have been requested */
	WARN_ON(1);
}
static inline int gpiod_get_raw_value(const struct gpio_desc *desc)
{
	/* GPIO can never have been requested */
	WARN_ON(1);
	return 0;
}
static inline void gpiod_set_raw_value(struct gpio_desc *desc, int value)
{
	/* GPIO can never have been requested */
	WARN_ON(1);
}
static inline void gpiod_set_raw_array_value(unsigned int array_size,
					     struct gpio_desc **desc_array,
					     int *value_array)
{
	/* GPIO can never have been requested */
	WARN_ON(1);
}

static inline int gpiod_get_value_cansleep(const struct gpio_desc *desc)
{
	/* GPIO can never have been requested */
	WARN_ON(1);
	return 0;
}
static inline void gpiod_set_value_cansleep(struct gpio_desc *desc, int value)
{
	/* GPIO can never have been requested */
	WARN_ON(1);
}
static inline void gpiod_set_array_value_cansleep(unsigned int array_size,
					    struct gpio_desc **desc_array,
					    int *value_array)
{
	/* GPIO can never have been requested */
	WARN_ON(1);
}
static inline int gpiod_get_raw_value_cansleep(const struct gpio_desc *desc)
{
	/* GPIO can never have been requested */
	WARN_ON(1);
	return 0;
}
static inline void gpiod_set_raw_value_cansleep(struct gpio_desc *desc,
						int value)
{
	/* GPIO can never have been requested */
	WARN_ON(1);
}
static inline void gpiod_set_raw_array_value_cansleep(unsigned int array_size,
						struct gpio_desc **desc_array,
						int *value_array)
{
	/* GPIO can never have been requested */
	WARN_ON(1);
}

static inline int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce)
{
	/* GPIO can never have been requested */
	WARN_ON(1);
	return -ENOSYS;
}

static inline int gpiod_is_active_low(const struct gpio_desc *desc)
{
	/* GPIO can never have been requested */
	WARN_ON(1);
	return 0;
}
static inline int gpiod_cansleep(const struct gpio_desc *desc)
{
	/* GPIO can never have been requested */
	WARN_ON(1);
	return 0;
}

static inline int gpiod_to_irq(const struct gpio_desc *desc)
{
	/* GPIO can never have been requested */
	WARN_ON(1);
	return -EINVAL;
}

static inline struct gpio_desc *gpio_to_desc(unsigned gpio)
{
	return ERR_PTR(-EINVAL);
}

static inline int desc_to_gpio(const struct gpio_desc *desc)
{
	/* GPIO can never have been requested */
	WARN_ON(1);
	return -EINVAL;
}

/* Child properties interface */
struct fwnode_handle;

static inline struct gpio_desc *fwnode_get_named_gpiod(
	struct fwnode_handle *fwnode, const char *propname)
{
	return ERR_PTR(-ENOSYS);
}

static inline struct gpio_desc *devm_get_gpiod_from_child(
	struct device *dev, const char *con_id, struct fwnode_handle *child)
{
	return ERR_PTR(-ENOSYS);
}

#endif /* CONFIG_GPIOLIB */

#if IS_ENABLED(CONFIG_GPIOLIB) && IS_ENABLED(CONFIG_GPIO_SYSFS)

int gpiod_export(struct gpio_desc *desc, bool direction_may_change);
int gpiod_export_link(struct device *dev, const char *name,
		      struct gpio_desc *desc);
void gpiod_unexport(struct gpio_desc *desc);

#else  /* CONFIG_GPIOLIB && CONFIG_GPIO_SYSFS */

static inline int gpiod_export(struct gpio_desc *desc,
			       bool direction_may_change)
{
	return -ENOSYS;
}

static inline int gpiod_export_link(struct device *dev, const char *name,
				    struct gpio_desc *desc)
{
	return -ENOSYS;
}

static inline void gpiod_unexport(struct gpio_desc *desc)
{
}

#endif /* CONFIG_GPIOLIB && CONFIG_GPIO_SYSFS */

#endif

三、实例一:三个gpio都是做为输入。

	hardware_version: hardware-version{
	   compatible = "xxx,hardwareversion";
	   hwversion-gpios = <&gpio3 RK_PB2 GPIO_ACTIVE_HIGH>,
	                     <&gpio3 RK_PB3 GPIO_ACTIVE_HIGH>,
	                     <&gpio3 RK_PB4 GPIO_ACTIVE_HIGH>;
	   status = "okay";
	};

#include <linux/init.h> 
#include <linux/module.h>
#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>

struct gpio_desc *data[3];
unsigned char hw_version = 0;


static ssize_t hardware_version_show(struct device *dev, struct device_attribute *attr, char *buf)
{
	return sprintf(buf, "%03d\n", hw_version);
}

static ssize_t hardware_version_store(struct device *dev, struct device_attribute *attr,
	   const char *buf, size_t count)
{
	  printk("[%s]buf=%s\r\n",__func__,buf);
	  return count;
}

/*
***********************************************************
cat /sys/devices/platform/hardware-version/hardware_version
************************************************************
*/
static DEVICE_ATTR(hardware_version,    0644, hardware_version_show, hardware_version_store);

int power(int num,int index) 
{
    if(index == 0)    
    {
        return 1;
    }		               
    else 
    	return num * power(num,index-1); 
}

int hardwareversion_probe(struct platform_device *pdev){
	int i,n,ret;
	n = gpiod_count(&pdev->dev, "hwversion");
    for(i = 0;i < n; i++)
	{
		data[i] = gpiod_get_index(&pdev->dev, "hwversion", i, GPIOD_IN);
		if (IS_ERR(data[i]))
			printk("Cannot find hwversion-gpios! \n");
		else 
			hw_version += gpiod_get_value(data[i]) * power(10,i);
    }

	ret = device_create_file(&pdev->dev, &dev_attr_hardware_version);
	if (ret)
	  printk("[%s] hardware_version device_create_file is error \n",__func__);
    else
	  printk("[%s] count:%d,hw_version:%d\n",__func__,n,hw_version);

	return 0;
}

int hardwareversion_remove(struct platform_device *pdev){
	printk("[%s]\n",__func__);
	return 0;
}

static const struct of_device_id hardwareversion_id[] = {
	{.compatible = "xxx,hardwareversion", 0},
	{}};

struct platform_driver hardwareversion_driver = {
	.probe = hardwareversion_probe,
	.remove = hardwareversion_remove,
	.driver={
		.owner = THIS_MODULE,
		.name = "hardwareversion",
		.of_match_table = hardwareversion_id,
	},
};

static int hardwareversion_driver_init(void){
	int ret = 0;

	ret = platform_driver_register(&hardwareversion_driver);
	if(ret < 0)
		printk("[%s] error\n",__func__);
	else 
	    printk("[%s] ok\n",__func__);
	
	return 0;
}

static void hardwareversion_driver_exit(void){

	platform_driver_unregister(&hardwareversion_driver);
	printk("[%s]\n",__func__);
}
module_init(hardwareversion_driver_init);
module_exit(hardwareversion_driver_exit);
MODULE_LICENSE("GPL");

四、实例二:有的gpio做in,有的gpio做out。

	inoutput_gpio_ctr: inoutput-gpio-ctr{
	    compatible = "xxx,inoutputgpioctr";
	    pinctrl-names = "default";
		pinctrl-0 =<&inoutput_gpio>;
		optocouplerctroutput-gpios = <&gpio3 RK_PC2 GPIO_ACTIVE_HIGH>;
		optocouplerctrinput-gpios = <&gpio3 RK_PC1 GPIO_ACTIVE_HIGH>;
		gpioenable-gpios = <&gpio3 RK_PC0 GPIO_ACTIVE_HIGH>;
		gpio3b5-gpios = <&gpio3 RK_PB5 GPIO_ACTIVE_HIGH>;
		gpio3b7-gpios = <&gpio3 RK_PB7 GPIO_ACTIVE_HIGH>;
	    status = "okay";
	};

#include <linux/init.h> 
#include <linux/module.h>
#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>


struct gpio_desc *optocouplerctroutput;
struct gpio_desc *optocouplerctrinput;
struct gpio_desc *gpioenable;
struct gpio_desc *gpio3b5,*gpio3b7;

static ssize_t optocouplerctroutput_show(struct device *dev,
               struct device_attribute *attr, char *buf)
{
    int ret;
	ret = gpiod_get_value(optocouplerctroutput);

	return sprintf(buf, "%d\n",ret);
}

static ssize_t optocouplerctroutput_store(struct device *dev, struct device_attribute *attr,
	   const char *buf, size_t count)
{
	  if(buf[0] =='1')
	      gpiod_direction_output(optocouplerctroutput, 1);
	  else 
	  	  gpiod_direction_output(optocouplerctroutput, 0);

	  return count;
}

/*
***********************************************************
echo 1 > /sys/devices/platform/inoutput-gpio-ctr/optocouplerctroutput
echo 0 > /sys/devices/platform/inoutput-gpio-ctr/optocouplerctroutput
************************************************************
*/
static DEVICE_ATTR(optocouplerctroutput,    0644, optocouplerctroutput_show, optocouplerctroutput_store);


static ssize_t optocouplerctrinput_show(struct device *dev,
               struct device_attribute *attr, char *buf)
{
    int ret;
	ret = gpiod_get_value(optocouplerctrinput);

	return sprintf(buf, "%d\n",ret);
}

static ssize_t optocouplerctrinput_store(struct device *dev, struct device_attribute *attr,
	   const char *buf, size_t count)
{
	  return count;
}

/*
***********************************************************
cat /sys/devices/platform/inoutput-gpio-ctr/optocouplerctrinput 
************************************************************
*/
static DEVICE_ATTR(optocouplerctrinput,    0644, optocouplerctrinput_show, optocouplerctrinput_store);



static ssize_t gpio3b5_show(struct device *dev,
               struct device_attribute *attr, char *buf)
{
    int ret;
	ret = gpiod_get_value(gpio3b5);

	return sprintf(buf, "%d\n",ret);
}

static ssize_t gpio3b5_store(struct device *dev, struct device_attribute *attr,
	   const char *buf, size_t count)
{
	  if(buf[0] =='1')
	      gpiod_direction_output(gpio3b5, 1);
	  else 
	  	  gpiod_direction_output(gpio3b5, 0);

	  return count;
}

/*
***********************************************************
cat /sys/devices/platform/inoutput-gpio-ctr/gpio3b5 
************************************************************
*/
static DEVICE_ATTR(gpio3b5,    0644, gpio3b5_show, gpio3b5_store);


int inoutputgpioctr_probe(struct platform_device *pdev){
	int err;

	gpioenable = devm_gpiod_get_optional(&pdev->dev, "gpioenable", GPIOD_OUT_HIGH);

	optocouplerctroutput   = devm_gpiod_get_optional(&pdev->dev, "optocouplerctroutput", GPIOD_OUT_LOW);
	if (IS_ERR(optocouplerctroutput)) {
		err = PTR_ERR(optocouplerctroutput);
		dev_err(&pdev->dev, "failed to request optocouplerctroutput GPIO: %d\n", err);
		return err;
	}

	optocouplerctrinput   = devm_gpiod_get_optional(&pdev->dev, "optocouplerctrinput", GPIOD_IN);
	if (IS_ERR(optocouplerctrinput)) {
		err = PTR_ERR(optocouplerctrinput);
		dev_err(&pdev->dev, "failed to request optocouplerctrinput GPIO: %d\n", err);
		return err;
	}

	gpio3b5 = devm_gpiod_get_optional(&pdev->dev, "gpio3b5", GPIOD_OUT_HIGH);
	gpio3b7 = devm_gpiod_get_optional(&pdev->dev, "gpio3b7", GPIOD_IN);

	err = device_create_file(&pdev->dev, &dev_attr_optocouplerctroutput);
	if (err)
	  printk("[%s] optocouplerctroutput device_create_file is error \n",__func__);
 
	err = device_create_file(&pdev->dev, &dev_attr_optocouplerctrinput);
	if (err)
	  printk("[%s] optocouplerctrinput device_create_file is error \n",__func__);
    
	err = device_create_file(&pdev->dev, &dev_attr_gpio3b5);
	if (err)
	  printk("[%s] gpio3b5 device_create_file is error \n",__func__);
	
	printk("[%s] \n",__func__);

	return 0;
}

int inoutputgpioctr_remove(struct platform_device *pdev){
	printk("[%s]\n",__func__);
	return 0;
}

static const struct of_device_id inoutputgpioctr_id[] = {
	{.compatible = "xxx,inoutputgpioctr", 0},
	{}};

struct platform_driver inoutputgpioctr_driver = {
	.probe = inoutputgpioctr_probe,
	.remove = inoutputgpioctr_remove,
	.driver={
		.owner = THIS_MODULE,
		.name = "inoutputgpioctr",
		.of_match_table = inoutputgpioctr_id,
	},
};

static int inoutputgpioctr_driver_init(void){
	int ret = 0;

	ret = platform_driver_register(&inoutputgpioctr_driver);
	if(ret < 0)
		printk("[%s] error\n",__func__);
	else 
	    printk("[%s] ok\n",__func__);
	
	return 0;
}

static void inoutputgpioctr_driver_exit(void){

	platform_driver_unregister(&inoutputgpioctr_driver);
	printk("[%s]\n",__func__);
}
module_init(inoutputgpioctr_driver_init);
module_exit(inoutputgpioctr_driver_exit);
MODULE_LICENSE("GPL");

五、实例三:中断方式响应输入,当输入状态有变化时,向app发送消息。


#include <linux/init.h> 
#include <linux/module.h>
#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>
#include <linux/of_platform.h>
#include <linux/of_device.h>
#include <linux/kthread.h>
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/miscdevice.h>
#include <linux/uaccess.h>


struct gpio_desc *optocouplerctroutput;
struct gpio_desc *optocouplerctrinput;
struct gpio_desc *gpioenable;
struct gpio_desc *gpio3b5,*gpio3b7;

#define DEVICE_NAME "hyper_gpio"
static struct fasync_struct *feedback_async;
bool is_ready = false;

static ssize_t optocouplerctroutput_show(struct device *dev,
               struct device_attribute *attr, char *buf)
{
    int ret;
	ret = gpiod_get_value(optocouplerctroutput);

	return sprintf(buf, "%d\n",ret);
}

static ssize_t optocouplerctroutput_store(struct device *dev, struct device_attribute *attr,
	   const char *buf, size_t count)
{
	  if(buf[0] =='1')
	      gpiod_direction_output(optocouplerctroutput, 1);
	  else 
	  	  gpiod_direction_output(optocouplerctroutput, 0);

	  return count;
}

/*
***********************************************************
echo 1 > /sys/devices/platform/inoutput-gpio-ctr/optocouplerctroutput
echo 0 > /sys/devices/platform/inoutput-gpio-ctr/optocouplerctroutput
************************************************************
*/
static DEVICE_ATTR(optocouplerctroutput,    0644, optocouplerctroutput_show, optocouplerctroutput_store);


static ssize_t optocouplerctrinput_show(struct device *dev,
               struct device_attribute *attr, char *buf)
{
    int ret;
	ret = gpiod_get_value(optocouplerctrinput);

	return sprintf(buf, "%d\n",ret);
}

static ssize_t optocouplerctrinput_store(struct device *dev, struct device_attribute *attr,
	   const char *buf, size_t count)
{
	  return count;
}

/*
***********************************************************
cat /sys/devices/platform/inoutput-gpio-ctr/optocouplerctrinput 
************************************************************
*/
static DEVICE_ATTR(optocouplerctrinput,    0644, optocouplerctrinput_show, optocouplerctrinput_store);


static ssize_t gpiolinetwo_show(struct device *dev,
               struct device_attribute *attr, char *buf)
{
    int ret;
	ret =  gpiod_direction_input(gpio3b7);
	return sprintf(buf, "%d\n",ret);
}

static ssize_t gpiolinetwo_store(struct device *dev, struct device_attribute *attr,
	   const char *buf, size_t count)
{
	  if(buf[0] =='1')
	      gpiod_direction_output(gpio3b5, 1);
	  else 
	  	  gpiod_direction_output(gpio3b5, 0);

	  return count;
}

/*
***********************************************************
cat /sys/devices/platform/inoutput-gpio-ctr/gpio3b5 
************************************************************
*/
static DEVICE_ATTR(gpiolinetwo,    0644, gpiolinetwo_show, gpiolinetwo_store);

static irqreturn_t optocouplerctrinput_irq_handler(int irq, void *data)
{
	//int ret;
	if(is_ready)
	  kill_fasync (&feedback_async, SIGIO, POLL_IN);
	//ret = gpiod_get_value(optocouplerctrinput);
	//printk("[%s] optocouplerctrinput = %d\n",__func__,ret);
	return IRQ_HANDLED;
}

static int inoutputgpioctr_drv_open(struct inode *inode, struct file *file)
{
    printk("[%s]\r\n",__func__);
	is_ready = true;
	return 0;
}

static int inoutputgpioctr_drv_release(struct inode *inode, struct file *file)
{
    printk("[%s]\r\n",__func__);
	is_ready = false;
	return 0;
}

ssize_t inoutputgpioctr_drv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{
    int ret=0;
    unsigned char val[2];
	val[0] = gpiod_get_value(optocouplerctrinput);
	val[1] = 0x32;
    ret=copy_to_user(buf,val,size);
	return size;
}

static int inoutputgpioctr_drv_fasync (int fd, struct file *filp, int on)
{
	printk("driver: inoutputgpioctr_drv_fasync successfully\n");
	return fasync_helper (fd, filp, on, &feedback_async);
}

static struct file_operations inoutputgpioctr_drv_fops = {
	.owner		= THIS_MODULE,
	.open		= inoutputgpioctr_drv_open,
	.release    = inoutputgpioctr_drv_release,
	.read		= inoutputgpioctr_drv_read,
	.fasync	 	= inoutputgpioctr_drv_fasync,
};
	
static struct miscdevice inoutputgpioctr_miscdev = 
{
	.minor	        = MISC_DYNAMIC_MINOR,
   	.name	        = DEVICE_NAME,
    .fops	        = &inoutputgpioctr_drv_fops,
};

int inoutputgpioctr_probe(struct platform_device *pdev){
	int err,ret;
	int optocouplerctrinput_irq;

	gpioenable = devm_gpiod_get_optional(&pdev->dev, "gpioenable", GPIOD_OUT_HIGH);

	optocouplerctroutput   = devm_gpiod_get_optional(&pdev->dev, "optocouplerctroutput", GPIOD_OUT_LOW);
	if (IS_ERR(optocouplerctroutput)) {
		err = PTR_ERR(optocouplerctroutput);
		dev_err(&pdev->dev, "failed to request optocouplerctroutput GPIO: %d\n", err);
		return err;
	}

	optocouplerctrinput   = devm_gpiod_get_optional(&pdev->dev, "optocouplerctrinput", GPIOD_IN);
	if (IS_ERR(optocouplerctrinput)) {
		err = PTR_ERR(optocouplerctrinput);
		dev_err(&pdev->dev, "failed to request optocouplerctrinput GPIO: %d\n", err);
		return err;
	}

	gpio3b5 = devm_gpiod_get_optional(&pdev->dev, "gpio3b5", GPIOD_OUT_HIGH);
	gpio3b7 = devm_gpiod_get_optional(&pdev->dev, "gpio3b7", GPIOD_IN);

	err = device_create_file(&pdev->dev, &dev_attr_optocouplerctroutput);
	if (err)
	  printk("[%s] optocouplerctroutput device_create_file is error \n",__func__);
 
	err = device_create_file(&pdev->dev, &dev_attr_optocouplerctrinput);
	if (err)
	  printk("[%s] optocouplerctrinput device_create_file is error \n",__func__);
    
	err = device_create_file(&pdev->dev, &dev_attr_gpiolinetwo);
	if (err)
	  printk("[%s] gpio3b5 device_create_file is error \n",__func__);


	optocouplerctrinput_irq = gpiod_to_irq(optocouplerctrinput);

	if(optocouplerctrinput_irq){
			//ret = request_irq(optocouplerctrinput_irq, optocouplerctrinput_irq_handler, IRQ_TYPE_EDGE_BOTH, "det-gpio", NULL);
			ret = devm_request_threaded_irq(&pdev->dev, optocouplerctrinput_irq, NULL,//cat /proc/interrupts
										        optocouplerctrinput_irq_handler,
												IRQF_TRIGGER_FALLING |
												IRQF_TRIGGER_RISING |
												IRQF_ONESHOT,
												"optocouplerctrinput_interrupt", NULL);	
			if (ret != 0) {
				free_irq(optocouplerctrinput_irq, NULL);
				dev_err(&pdev->dev, "request_irq failed: %d\n", ret);
				return ret;
			}
	}

	ret = misc_register(&inoutputgpioctr_miscdev);
	if (ret) {
	    printk("inoutputgpioctr_miscdev register failed!\n");
	}else
	    printk("inoutputgpioctr_miscdev register success!\n");

	printk("[%s] \n",__func__);

	return 0;
}

int inoutputgpioctr_remove(struct platform_device *pdev){
	printk("[%s]\n",__func__);
	return 0;
}

static const struct of_device_id inoutputgpioctr_id[] = {
	{.compatible = "hyper,inoutputgpioctr", 0},
	{}};

struct platform_driver inoutputgpioctr_driver = {
	.probe = inoutputgpioctr_probe,
	.remove = inoutputgpioctr_remove,
	.driver={
		.owner = THIS_MODULE,
		.name = "inoutputgpioctr",
		.of_match_table = inoutputgpioctr_id,
	},
};

static int inoutputgpioctr_driver_init(void){
	int ret = 0;

	ret = platform_driver_register(&inoutputgpioctr_driver);
	if(ret < 0)
		printk("[%s] error\n",__func__);
	else 
	    printk("[%s] ok\n",__func__);
	
	return 0;
}

static void inoutputgpioctr_driver_exit(void){

	platform_driver_unregister(&inoutputgpioctr_driver);
	printk("[%s]\n",__func__);
}
module_init(inoutputgpioctr_driver_init);
module_exit(inoutputgpioctr_driver_exit);
MODULE_LICENSE("GPL");
#include <stdio.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <linux/watchdog.h>

#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>

int m_fd;

#define DEVICE_NAME "/dev/hyper_gpio"


void hyper_gpio_signal_fun(int sig)
{
	unsigned char val[2];
	read(m_fd, val, 2);
	printf("\n optocouplerctrinput=%d,input_line_two=%d\n",val[0],val[1]);
}

int main(int argc, char *argv[])
{	
    int ret = 0;
    int Oflags;
	printf("hyper_gpio start to work\n");
	signal(SIGIO, hyper_gpio_signal_fun);

	if((m_fd = open(DEVICE_NAME, O_RDWR)) == -1) {
		printf("Failed to open device file /dev/hyper_gpio -- %s.", strerror(errno));
		return -EFAULT;
	}else
		printf("Open  file /dev/hyper_gpio successfully.\n");	
			
	fcntl(m_fd, F_SETOWN, getpid());
	Oflags = fcntl(m_fd, F_GETFL); 
	fcntl(m_fd, F_SETFL, Oflags | FASYNC);

	while(1)
	{
	   usleep(1000);
	}
	
	return ret;
}

六、参考文章

GPIO系列(2)——Linux的GPIO控制“gpiod_”和“gpio_”浅析_杨涂涂的博客-CSDN博客

linux驱动开发学习笔记十六:gpio相关OF函数和子系统API函数_of_gpio_count_耐心的小黑的博客-CSDN博客

linux设备树之gpio_操作系统架构的博客-CSDN博客

Linux下的gpio,gpiod_嵌入式Linux,的博客-CSDN博客

Linux子系统之GPIO_linux gpio子系统_niuiniuiniu的博客-CSDN博客

猜你喜欢

转载自blog.csdn.net/qq_37858386/article/details/129841108
今日推荐