forked from mirrors/linux
		
	gpio: add new SET_CONFIG ioctl() to gpio chardev
Add the GPIOHANDLE_SET_CONFIG_IOCTL to the gpio chardev. The ioctl allows some of the configuration of a requested handle to be changed without having to release the line. The primary use case is the changing of direction for bi-directional lines. Based on initial work by Bartosz Golaszewski <bgolaszewski@baylibre.com> Signed-off-by: Kent Gibson <warthog618@gmail.com> Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
This commit is contained in:
		
							parent
							
								
									b043ed7ef0
								
							
						
					
					
						commit
						e588bb1eae
					
				
					 2 changed files with 87 additions and 0 deletions
				
			
		|  | @ -476,6 +476,73 @@ static int linehandle_validate_flags(u32 flags) | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static void linehandle_configure_flag(unsigned long *flagsp, | ||||||
|  | 				      u32 bit, bool active) | ||||||
|  | { | ||||||
|  | 	if (active) | ||||||
|  | 		set_bit(bit, flagsp); | ||||||
|  | 	else | ||||||
|  | 		clear_bit(bit, flagsp); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static long linehandle_set_config(struct linehandle_state *lh, | ||||||
|  | 				  void __user *ip) | ||||||
|  | { | ||||||
|  | 	struct gpiohandle_config gcnf; | ||||||
|  | 	struct gpio_desc *desc; | ||||||
|  | 	int i, ret; | ||||||
|  | 	u32 lflags; | ||||||
|  | 	unsigned long *flagsp; | ||||||
|  | 
 | ||||||
|  | 	if (copy_from_user(&gcnf, ip, sizeof(gcnf))) | ||||||
|  | 		return -EFAULT; | ||||||
|  | 
 | ||||||
|  | 	lflags = gcnf.flags; | ||||||
|  | 	ret = linehandle_validate_flags(lflags); | ||||||
|  | 	if (ret) | ||||||
|  | 		return ret; | ||||||
|  | 
 | ||||||
|  | 	for (i = 0; i < lh->numdescs; i++) { | ||||||
|  | 		desc = lh->descs[i]; | ||||||
|  | 		flagsp = &desc->flags; | ||||||
|  | 
 | ||||||
|  | 		linehandle_configure_flag(flagsp, FLAG_ACTIVE_LOW, | ||||||
|  | 			lflags & GPIOHANDLE_REQUEST_ACTIVE_LOW); | ||||||
|  | 
 | ||||||
|  | 		linehandle_configure_flag(flagsp, FLAG_OPEN_DRAIN, | ||||||
|  | 			lflags & GPIOHANDLE_REQUEST_OPEN_DRAIN); | ||||||
|  | 
 | ||||||
|  | 		linehandle_configure_flag(flagsp, FLAG_OPEN_SOURCE, | ||||||
|  | 			lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE); | ||||||
|  | 
 | ||||||
|  | 		linehandle_configure_flag(flagsp, FLAG_PULL_UP, | ||||||
|  | 			lflags & GPIOHANDLE_REQUEST_BIAS_PULL_UP); | ||||||
|  | 
 | ||||||
|  | 		linehandle_configure_flag(flagsp, FLAG_PULL_DOWN, | ||||||
|  | 			lflags & GPIOHANDLE_REQUEST_BIAS_PULL_DOWN); | ||||||
|  | 
 | ||||||
|  | 		linehandle_configure_flag(flagsp, FLAG_BIAS_DISABLE, | ||||||
|  | 			lflags & GPIOHANDLE_REQUEST_BIAS_DISABLE); | ||||||
|  | 
 | ||||||
|  | 		/*
 | ||||||
|  | 		 * Lines have to be requested explicitly for input | ||||||
|  | 		 * or output, else the line will be treated "as is". | ||||||
|  | 		 */ | ||||||
|  | 		if (lflags & GPIOHANDLE_REQUEST_OUTPUT) { | ||||||
|  | 			int val = !!gcnf.default_values[i]; | ||||||
|  | 
 | ||||||
|  | 			ret = gpiod_direction_output(desc, val); | ||||||
|  | 			if (ret) | ||||||
|  | 				return ret; | ||||||
|  | 		} else if (lflags & GPIOHANDLE_REQUEST_INPUT) { | ||||||
|  | 			ret = gpiod_direction_input(desc); | ||||||
|  | 			if (ret) | ||||||
|  | 				return ret; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static long linehandle_ioctl(struct file *filep, unsigned int cmd, | static long linehandle_ioctl(struct file *filep, unsigned int cmd, | ||||||
| 			     unsigned long arg) | 			     unsigned long arg) | ||||||
| { | { | ||||||
|  | @ -526,6 +593,8 @@ static long linehandle_ioctl(struct file *filep, unsigned int cmd, | ||||||
| 					      lh->descs, | 					      lh->descs, | ||||||
| 					      NULL, | 					      NULL, | ||||||
| 					      vals); | 					      vals); | ||||||
|  | 	} else if (cmd == GPIOHANDLE_SET_CONFIG_IOCTL) { | ||||||
|  | 		return linehandle_set_config(lh, ip); | ||||||
| 	} | 	} | ||||||
| 	return -EINVAL; | 	return -EINVAL; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -100,6 +100,24 @@ struct gpiohandle_request { | ||||||
| 	int fd; | 	int fd; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * struct gpiohandle_config - Configuration for a GPIO handle request | ||||||
|  |  * @flags: updated flags for the requested GPIO lines, such as | ||||||
|  |  * GPIOHANDLE_REQUEST_OUTPUT, GPIOHANDLE_REQUEST_ACTIVE_LOW etc, OR:ed | ||||||
|  |  * together | ||||||
|  |  * @default_values: if the GPIOHANDLE_REQUEST_OUTPUT is set in flags, | ||||||
|  |  * this specifies the default output value, should be 0 (low) or | ||||||
|  |  * 1 (high), anything else than 0 or 1 will be interpreted as 1 (high) | ||||||
|  |  * @padding: reserved for future use and should be zero filled | ||||||
|  |  */ | ||||||
|  | struct gpiohandle_config { | ||||||
|  | 	__u32 flags; | ||||||
|  | 	__u8 default_values[GPIOHANDLES_MAX]; | ||||||
|  | 	__u32 padding[4]; /* padding for future use */ | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | #define GPIOHANDLE_SET_CONFIG_IOCTL _IOWR(0xB4, 0x0a, struct gpiohandle_config) | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * struct gpiohandle_data - Information of values on a GPIO handle |  * struct gpiohandle_data - Information of values on a GPIO handle | ||||||
|  * @values: when getting the state of lines this contains the current |  * @values: when getting the state of lines this contains the current | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Kent Gibson
						Kent Gibson