mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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