pinctrl&gpio: add new interface to set pull-down/up

PD#142470: pinctrl&gpio: add new interface to set pull-down/up

1. add property file 'pull' in directory /sys/class/gpio/gpioX/
pull-up:      echo up > pull
pull-down:    echo down > pull
pull-disable: echo disable > pull

2. add new functions, as follows:
+ gpiod_set_pull(struct gpio_desc *desc, int value)
+ gpiod_set_pull_cansleep(struct gpio_desc *desc, int value)

'value' can be set:
GPIOD_PULL_DIS
GPIOD_PULL_DOWN
GPIOD_PULL_UP

Change-Id: Iba750729288651a897ebac827093ebc6c143f16b
Signed-off-by: xingyu.chen <xingyu.chen@amlogic.com>
This commit is contained in:
xingyu.chen
2017-06-07 16:02:31 +08:00
committed by Jianxin Pan
parent b462fea81d
commit d39d45ead6
5 changed files with 156 additions and 1 deletions

View File

@@ -658,6 +658,41 @@ static void meson_gpio_set(struct gpio_chip *chip, unsigned int gpio,
value ? BIT(bit) : 0);
}
static int meson_gpio_pull_set(struct gpio_chip *chip, unsigned int gpio,
int value)
{
struct meson_domain *domain = to_meson_domain(chip);
unsigned int reg, bit, pin;
struct meson_bank *bank;
int ret;
if ((value != GPIOD_PULL_DIS) && (value != GPIOD_PULL_DOWN)
&& (value != GPIOD_PULL_UP))
return -EINVAL;
pin = domain->data->pin_base + gpio;
ret = meson_get_bank(domain, pin, &bank);
if (ret)
return ret;
meson_calc_reg_and_bit(bank, pin, REG_PULLEN,
&reg, &bit);
ret = regmap_update_bits(domain->reg_pullen, reg,
BIT(bit),
(value == GPIOD_PULL_DIS) ? 0 : BIT(bit));
if (ret)
return ret;
meson_calc_reg_and_bit(bank, pin, REG_PULL, &reg, &bit);
ret = regmap_update_bits(domain->reg_pull, reg,
BIT(bit),
(value == GPIOD_PULL_DOWN) ? 0 : BIT(bit));
if (ret)
return ret;
return 0;
}
static int meson_gpio_get(struct gpio_chip *chip, unsigned int gpio)
{
struct meson_domain *domain = to_meson_domain(chip);
@@ -1088,6 +1123,7 @@ static int meson_gpiolib_register(struct meson_pinctrl *pc)
domain->chip.direction_output = meson_gpio_direction_output;
domain->chip.get = meson_gpio_get;
domain->chip.set = meson_gpio_set;
domain->chip.set_pull = meson_gpio_pull_set;
domain->chip.base = domain->data->pin_base;
domain->chip.ngpio = domain->data->num_pins;
domain->chip.can_sleep = false;

View File

@@ -350,6 +350,30 @@ static ssize_t active_low_store(struct device *dev,
}
static DEVICE_ATTR_RW(active_low);
#ifdef CONFIG_AMLOGIC_PINCTRL
static ssize_t pull_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct gpiod_data *data = dev_get_drvdata(dev);
struct gpio_desc *desc = data->desc;
ssize_t status;
mutex_lock(&data->mutex);
if (sysfs_streq(buf, "disable"))
status = gpiod_set_pull(desc, GPIOD_PULL_DIS);
else if (sysfs_streq(buf, "down"))
status = gpiod_set_pull(desc, GPIOD_PULL_DOWN);
else if (sysfs_streq(buf, "up"))
status = gpiod_set_pull(desc, GPIOD_PULL_UP);
else
status = -EINVAL;
mutex_unlock(&data->mutex);
return status ? : size;
}
static DEVICE_ATTR_WO(pull);
#endif
static umode_t gpio_is_visible(struct kobject *kobj, struct attribute *attr,
int n)
{
@@ -377,6 +401,9 @@ static struct attribute *gpio_attrs[] = {
&dev_attr_edge.attr,
&dev_attr_value.attr,
&dev_attr_active_low.attr,
#ifdef CONFIG_AMLOGIC_PINCTRL
&dev_attr_pull.attr,
#endif
NULL,
};

View File

@@ -2509,6 +2509,26 @@ static void _gpiod_set_raw_value(struct gpio_desc *desc, bool value)
chip->set(chip, gpio_chip_hwgpio(desc), value);
}
#ifdef CONFIG_AMLOGIC_PINCTRL
static int _gpiod_set_pull(struct gpio_desc *desc, int value)
{
struct gpio_chip *chip;
int status = -EINVAL;
chip = desc->gdev->chip;
if (!chip || !chip->set_pull) {
gpiod_warn(desc,
"%s: missing set_pull() operations\n",
__func__);
return -EIO;
}
if (test_bit(FLAG_REQUESTED, &desc->flags))
status = chip->set_pull(chip, gpio_chip_hwgpio(desc), value);
return status;
}
#endif
/*
* set multiple outputs on the same chip;
* use the chip's set_multiple function if available;
@@ -2631,6 +2651,25 @@ void gpiod_set_value(struct gpio_desc *desc, int value)
}
EXPORT_SYMBOL_GPL(gpiod_set_value);
/**
* gpiod_set_pull() - enable pull-down/up for the gpio, or disable.
* @desc: gpio whose value will be set
* @value: value to set
*
* This function should be called from contexts where we cannot sleep, and will
* complain if the GPIO chip functions potentially sleep.
*/
#ifdef CONFIG_AMLOGIC_PINCTRL
int gpiod_set_pull(struct gpio_desc *desc, int value)
{
VALIDATE_DESC(desc);
/* Should be using gpiod_set_pull_cansleep() */
WARN_ON(desc->gdev->chip->can_sleep);
return _gpiod_set_pull(desc, value);
}
EXPORT_SYMBOL_GPL(gpiod_set_pull);
#endif
/**
* gpiod_set_raw_array_value() - assign values to an array of GPIOs
* @array_size: number of elements in the descriptor / value arrays
@@ -2888,6 +2927,23 @@ void gpiod_set_value_cansleep(struct gpio_desc *desc, int value)
}
EXPORT_SYMBOL_GPL(gpiod_set_value_cansleep);
/**
* gpiod_set_pull_cansleep() - enable pull-down/up for the gpio, or disable.
* @desc: gpio whose value will be set
* @value: value to set
*
* This function is to be called from contexts that can sleep.
*/
#ifdef CONFIG_AMLOGIC_PINCTRL
int gpiod_set_pull_cansleep(struct gpio_desc *desc, int value)
{
might_sleep_if(extra_checks);
VALIDATE_DESC(desc);
return _gpiod_set_pull(desc, value);
}
EXPORT_SYMBOL_GPL(gpiod_set_pull_cansleep);
#endif
/**
* gpiod_set_raw_array_value_cansleep() - assign values to an array of GPIOs
* @array_size: number of elements in the descriptor / value arrays

View File

@@ -41,6 +41,14 @@ enum gpiod_flags {
GPIOD_FLAGS_BIT_DIR_VAL,
};
#ifdef CONFIG_AMLOGIC_PINCTRL
enum gpiod_pull_type {
GPIOD_PULL_DIS = 0,
GPIOD_PULL_DOWN = 1,
GPIOD_PULL_UP = 2,
};
#endif
#ifdef CONFIG_GPIOLIB
/* Return the number of GPIOs associated with a device / function */
@@ -100,6 +108,9 @@ 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);
#ifdef CONFIG_AMLOGIC_PINCTRL
int gpiod_set_pull(struct gpio_desc *desc, int value);
#endif
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);
@@ -111,6 +122,9 @@ void gpiod_set_raw_array_value(unsigned int array_size,
/* 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);
#ifdef CONFIG_AMLOGIC_PINCTRL
int gpiod_set_pull_scansleep(struct gpio_desc *desc, int value);
#endif
void gpiod_set_array_value_cansleep(unsigned int array_size,
struct gpio_desc **desc_array,
int *value_array);
@@ -323,6 +337,15 @@ static inline void gpiod_set_raw_value(struct gpio_desc *desc, int value)
/* GPIO can never have been requested */
WARN_ON(1);
}
#ifdef CONFIG_AMLOGIC_PINCTRL
static inline int gpiod_set_pull(struct gpio_desc *desc, int value)
{
WARN_ON(1);
return -EINVAL;
}
#endif
static inline void gpiod_set_raw_array_value(unsigned int array_size,
struct gpio_desc **desc_array,
int *value_array)
@@ -342,6 +365,15 @@ static inline void gpiod_set_value_cansleep(struct gpio_desc *desc, int value)
/* GPIO can never have been requested */
WARN_ON(1);
}
#ifdef CONFIG_AMLOGIC_PINCTRL
static inline int gpiod_set_pull_cansleep(struct gpio_desc *desc, int value)
{
WARN_ON(1);
return -EINVAL;
}
#endif
static inline void gpiod_set_array_value_cansleep(unsigned int array_size,
struct gpio_desc **desc_array,
int *value_array)

View File

@@ -58,6 +58,7 @@ enum single_ended_mode {
* if a consumer request this. The driver may return -ENOTSUPP if e.g.
* it supports just open drain but not open source and is called
* with LINE_MODE_OPEN_SOURCE as mode argument.
* @set_pull: set the current pull configuration for the GPIO.
* @to_irq: optional hook supporting non-static gpio_to_irq() mappings;
* implementation may not sleep
* @dbg_show: optional routine to show contents in debugfs; default code
@@ -156,7 +157,10 @@ struct gpio_chip {
int (*set_single_ended)(struct gpio_chip *chip,
unsigned offset,
enum single_ended_mode mode);
#ifdef CONFIG_AMLOGIC_PINCTRL
int (*set_pull)(struct gpio_chip *chip,
unsigned int offset, int value);
#endif
int (*to_irq)(struct gpio_chip *chip,
unsigned offset);