#include struct gpio_pin *gpio_pin_by_name(const char *name) { struct gpio_pin *pin; for (pin = gpio_pins; *pin->name; pin++) { if (!strcmp(pin->name, name)) { return pin; } } log_error("pin named %s not found", name); return NULL; } // A GPIO pin number must only occur once. struct gpio_pin *gpio_pin_by_num(unsigned num) { int ipin = 0; while(*(gpio_pins[ipin].name)) { if (gpio_pins[ipin].pin.gpio == num) { return &(gpio_pins[ipin]); } ipin++; } log_error("pin numbered %u not found", num); return NULL; } struct gpio_pin *gpio_pin_by_attr_name(const char *name) { struct gpio_pin *pin; for (pin = gpio_pins; *pin->name; pin++) { if (!strcmp(pin->pin.label, name)) { return pin; } } log_error("pin with attr name %s not found", name); return NULL; } /* Any gpio that could potentially get routed over an i2c bus * as opposed to a memory write to a register must call * "cansleep" versions of gpio functions. The purpose of the * function is to remind kernel driver writers that any GPIO * routed over i2c (or spi) cannot be accessed in an interrupt * handler. Interrupt handlers should use the GPIO pins * that are memory mapped. gpio_get_value and gpio_set_value * cannot be used with the PCA 9557 or a dump will result. */ ssize_t mts_attr_show_gpio_pin(struct device *dev, struct device_attribute *attr, char *buf) { int value; struct gpio_pin *pin = gpio_pin_by_attr_name(attr->attr.name); if (!pin) { return -ENODEV; } mutex_lock(&mts_io_mutex); if (pin->do_gpio_desc == 1) { value = gpiod_get_value_cansleep(pin->desc); } else { value = gpio_get_value_cansleep(pin->pin.gpio); } mutex_unlock(&mts_io_mutex); if (value < 0) { return value; } if (pin->active_low) { value = !value; } return sprintf(buf, "%d\n", value); } static ssize_t mts_attr_store_gpio_pin(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int value; struct gpio_pin *pin = gpio_pin_by_attr_name(attr->attr.name); if (!pin) { return -ENODEV; } if (sscanf(buf, "%i", &value) != 1) { return -EINVAL; } if (pin->active_low) { value = !value; } mutex_lock(&mts_io_mutex); if (pin->do_gpio_desc == 1) { gpiod_set_value_cansleep(pin->desc, value); } else { gpio_set_value_cansleep(pin->pin.gpio, value); } mutex_unlock(&mts_io_mutex); return count; } static int reset_gpio_pin(struct gpio_pin *pin, unsigned int delay_ms, unsigned int value) { if (!pin) { return -ENODEV; } if (pin->do_gpio_desc == 1) { gpiod_set_value_cansleep(pin->desc, value); } else { gpio_set_value_cansleep(pin->pin.gpio, value); } mdelay(delay_ms); if (pin->do_gpio_desc == 1) { gpiod_set_value_cansleep(pin->desc, !value); } else { gpio_set_value_cansleep(pin->pin.gpio, !value); } return 0; }