Skip to content

Commit

Permalink
gpio: add new SET_CONFIG ioctl() to gpio chardev
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
warthog618 authored and brgl committed Nov 12, 2019
1 parent b043ed7 commit e588bb1
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 0 deletions.
69 changes: 69 additions & 0 deletions drivers/gpio/gpiolib.c
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,73 @@ static int linehandle_validate_flags(u32 flags)
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,
unsigned long arg)
{
Expand Down Expand Up @@ -526,6 +593,8 @@ static long linehandle_ioctl(struct file *filep, unsigned int cmd,
lh->descs,
NULL,
vals);
} else if (cmd == GPIOHANDLE_SET_CONFIG_IOCTL) {
return linehandle_set_config(lh, ip);
}
return -EINVAL;
}
Expand Down
18 changes: 18 additions & 0 deletions include/uapi/linux/gpio.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,24 @@ struct gpiohandle_request {
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
* @values: when getting the state of lines this contains the current
Expand Down

0 comments on commit e588bb1

Please sign in to comment.