Commit 92de6bc3 authored by Linus Walleij's avatar Linus Walleij

Merge branch 'ib-pca953x-config' into devel

parents 5340f23d 15add068
...@@ -67,6 +67,18 @@ Optional standard bitfield specifiers for the last cell: ...@@ -67,6 +67,18 @@ Optional standard bitfield specifiers for the last cell:
https://en.wikipedia.org/wiki/Open_collector https://en.wikipedia.org/wiki/Open_collector
- Bit 3: 0 means the output should be maintained during sleep/low-power mode - Bit 3: 0 means the output should be maintained during sleep/low-power mode
1 means the output state can be lost during sleep/low-power mode 1 means the output state can be lost during sleep/low-power mode
- Bit 4: 0 means no pull-up resistor should be enabled
1 means a pull-up resistor should be enabled
This setting only applies to hardware with a simple on/off
control for pull-up configuration. If the hardware has more
elaborate pull-up configuration, it should be represented
using a pin control binding.
- Bit 5: 0 means no pull-down resistor should be enabled
1 means a pull-down resistor should be enabled
This setting only applies to hardware with a simple on/off
control for pull-down configuration. If the hardware has more
elaborate pull-down configuration, it should be represented
using a pin control binding.
1.1) GPIO specifier best practices 1.1) GPIO specifier best practices
---------------------------------- ----------------------------------
......
...@@ -179,6 +179,8 @@ static int pca953x_bank_shift(struct pca953x_chip *chip) ...@@ -179,6 +179,8 @@ static int pca953x_bank_shift(struct pca953x_chip *chip)
#define PCA957x_BANK_OUTPUT BIT(5) #define PCA957x_BANK_OUTPUT BIT(5)
#define PCAL9xxx_BANK_IN_LATCH BIT(8 + 2) #define PCAL9xxx_BANK_IN_LATCH BIT(8 + 2)
#define PCAL9xxx_BANK_PULL_EN BIT(8 + 3)
#define PCAL9xxx_BANK_PULL_SEL BIT(8 + 4)
#define PCAL9xxx_BANK_IRQ_MASK BIT(8 + 5) #define PCAL9xxx_BANK_IRQ_MASK BIT(8 + 5)
#define PCAL9xxx_BANK_IRQ_STAT BIT(8 + 6) #define PCAL9xxx_BANK_IRQ_STAT BIT(8 + 6)
...@@ -200,6 +202,8 @@ static int pca953x_bank_shift(struct pca953x_chip *chip) ...@@ -200,6 +202,8 @@ static int pca953x_bank_shift(struct pca953x_chip *chip)
* - Extended set, above 0x40, often chip specific. * - Extended set, above 0x40, often chip specific.
* - PCAL6524/PCAL9555A with custom PCAL IRQ handling: * - PCAL6524/PCAL9555A with custom PCAL IRQ handling:
* Input latch register 0x40 + 2 * bank_size RW * Input latch register 0x40 + 2 * bank_size RW
* Pull-up/pull-down enable reg 0x40 + 3 * bank_size RW
* Pull-up/pull-down select reg 0x40 + 4 * bank_size RW
* Interrupt mask register 0x40 + 5 * bank_size RW * Interrupt mask register 0x40 + 5 * bank_size RW
* Interrupt status register 0x40 + 6 * bank_size R * Interrupt status register 0x40 + 6 * bank_size R
* *
...@@ -248,7 +252,8 @@ static bool pca953x_readable_register(struct device *dev, unsigned int reg) ...@@ -248,7 +252,8 @@ static bool pca953x_readable_register(struct device *dev, unsigned int reg)
} }
if (chip->driver_data & PCA_PCAL) { if (chip->driver_data & PCA_PCAL) {
bank |= PCAL9xxx_BANK_IN_LATCH | PCAL9xxx_BANK_IRQ_MASK | bank |= PCAL9xxx_BANK_IN_LATCH | PCAL9xxx_BANK_PULL_EN |
PCAL9xxx_BANK_PULL_SEL | PCAL9xxx_BANK_IRQ_MASK |
PCAL9xxx_BANK_IRQ_STAT; PCAL9xxx_BANK_IRQ_STAT;
} }
...@@ -269,7 +274,8 @@ static bool pca953x_writeable_register(struct device *dev, unsigned int reg) ...@@ -269,7 +274,8 @@ static bool pca953x_writeable_register(struct device *dev, unsigned int reg)
} }
if (chip->driver_data & PCA_PCAL) if (chip->driver_data & PCA_PCAL)
bank |= PCAL9xxx_BANK_IN_LATCH | PCAL9xxx_BANK_IRQ_MASK; bank |= PCAL9xxx_BANK_IN_LATCH | PCAL9xxx_BANK_PULL_EN |
PCAL9xxx_BANK_PULL_SEL | PCAL9xxx_BANK_IRQ_MASK;
return pca953x_check_register(chip, reg, bank); return pca953x_check_register(chip, reg, bank);
} }
...@@ -474,6 +480,61 @@ static void pca953x_gpio_set_multiple(struct gpio_chip *gc, ...@@ -474,6 +480,61 @@ static void pca953x_gpio_set_multiple(struct gpio_chip *gc,
mutex_unlock(&chip->i2c_lock); mutex_unlock(&chip->i2c_lock);
} }
static int pca953x_gpio_set_pull_up_down(struct pca953x_chip *chip,
unsigned int offset,
unsigned long config)
{
u8 pull_en_reg = pca953x_recalc_addr(chip, PCAL953X_PULL_EN, offset,
true, false);
u8 pull_sel_reg = pca953x_recalc_addr(chip, PCAL953X_PULL_SEL, offset,
true, false);
u8 bit = BIT(offset % BANK_SZ);
int ret;
/*
* pull-up/pull-down configuration requires PCAL extended
* registers
*/
if (!(chip->driver_data & PCA_PCAL))
return -ENOTSUPP;
mutex_lock(&chip->i2c_lock);
/* Disable pull-up/pull-down */
ret = regmap_write_bits(chip->regmap, pull_en_reg, bit, 0);
if (ret)
goto exit;
/* Configure pull-up/pull-down */
if (config == PIN_CONFIG_BIAS_PULL_UP)
ret = regmap_write_bits(chip->regmap, pull_sel_reg, bit, bit);
else if (config == PIN_CONFIG_BIAS_PULL_DOWN)
ret = regmap_write_bits(chip->regmap, pull_sel_reg, bit, 0);
if (ret)
goto exit;
/* Enable pull-up/pull-down */
ret = regmap_write_bits(chip->regmap, pull_en_reg, bit, bit);
exit:
mutex_unlock(&chip->i2c_lock);
return ret;
}
static int pca953x_gpio_set_config(struct gpio_chip *gc, unsigned int offset,
unsigned long config)
{
struct pca953x_chip *chip = gpiochip_get_data(gc);
switch (config) {
case PIN_CONFIG_BIAS_PULL_UP:
case PIN_CONFIG_BIAS_PULL_DOWN:
return pca953x_gpio_set_pull_up_down(chip, offset, config);
default:
return -ENOTSUPP;
}
}
static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios) static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios)
{ {
struct gpio_chip *gc; struct gpio_chip *gc;
...@@ -486,6 +547,7 @@ static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios) ...@@ -486,6 +547,7 @@ static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios)
gc->set = pca953x_gpio_set_value; gc->set = pca953x_gpio_set_value;
gc->get_direction = pca953x_gpio_get_direction; gc->get_direction = pca953x_gpio_get_direction;
gc->set_multiple = pca953x_gpio_set_multiple; gc->set_multiple = pca953x_gpio_set_multiple;
gc->set_config = pca953x_gpio_set_config;
gc->can_sleep = true; gc->can_sleep = true;
gc->base = chip->gpio_start; gc->base = chip->gpio_start;
......
...@@ -345,6 +345,11 @@ struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, ...@@ -345,6 +345,11 @@ struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
if (of_flags & OF_GPIO_TRANSITORY) if (of_flags & OF_GPIO_TRANSITORY)
*flags |= GPIO_TRANSITORY; *flags |= GPIO_TRANSITORY;
if (of_flags & OF_GPIO_PULL_UP)
*flags |= GPIO_PULL_UP;
if (of_flags & OF_GPIO_PULL_DOWN)
*flags |= GPIO_PULL_DOWN;
return desc; return desc;
} }
......
...@@ -2555,6 +2555,14 @@ EXPORT_SYMBOL_GPL(gpiochip_free_own_desc); ...@@ -2555,6 +2555,14 @@ EXPORT_SYMBOL_GPL(gpiochip_free_own_desc);
* rely on gpio_request() having been called beforehand. * rely on gpio_request() having been called beforehand.
*/ */
static int gpio_set_config(struct gpio_chip *gc, unsigned offset,
enum pin_config_param mode)
{
unsigned long config = { PIN_CONF_PACKED(mode, 0) };
return gc->set_config ? gc->set_config(gc, offset, config) : -ENOTSUPP;
}
/** /**
* gpiod_direction_input - set the GPIO direction to input * gpiod_direction_input - set the GPIO direction to input
* @desc: GPIO to set to input * @desc: GPIO to set to input
...@@ -2602,20 +2610,19 @@ int gpiod_direction_input(struct gpio_desc *desc) ...@@ -2602,20 +2610,19 @@ int gpiod_direction_input(struct gpio_desc *desc)
if (status == 0) if (status == 0)
clear_bit(FLAG_IS_OUT, &desc->flags); clear_bit(FLAG_IS_OUT, &desc->flags);
if (test_bit(FLAG_PULL_UP, &desc->flags))
gpio_set_config(chip, gpio_chip_hwgpio(desc),
PIN_CONFIG_BIAS_PULL_UP);
else if (test_bit(FLAG_PULL_DOWN, &desc->flags))
gpio_set_config(chip, gpio_chip_hwgpio(desc),
PIN_CONFIG_BIAS_PULL_DOWN);
trace_gpio_direction(desc_to_gpio(desc), 1, status); trace_gpio_direction(desc_to_gpio(desc), 1, status);
return status; return status;
} }
EXPORT_SYMBOL_GPL(gpiod_direction_input); EXPORT_SYMBOL_GPL(gpiod_direction_input);
static int gpio_set_drive_single_ended(struct gpio_chip *gc, unsigned offset,
enum pin_config_param mode)
{
unsigned long config = { PIN_CONF_PACKED(mode, 0) };
return gc->set_config ? gc->set_config(gc, offset, config) : -ENOTSUPP;
}
static int gpiod_direction_output_raw_commit(struct gpio_desc *desc, int value) static int gpiod_direction_output_raw_commit(struct gpio_desc *desc, int value)
{ {
struct gpio_chip *gc = desc->gdev->chip; struct gpio_chip *gc = desc->gdev->chip;
...@@ -2712,8 +2719,8 @@ int gpiod_direction_output(struct gpio_desc *desc, int value) ...@@ -2712,8 +2719,8 @@ int gpiod_direction_output(struct gpio_desc *desc, int value)
gc = desc->gdev->chip; gc = desc->gdev->chip;
if (test_bit(FLAG_OPEN_DRAIN, &desc->flags)) { if (test_bit(FLAG_OPEN_DRAIN, &desc->flags)) {
/* First see if we can enable open drain in hardware */ /* First see if we can enable open drain in hardware */
ret = gpio_set_drive_single_ended(gc, gpio_chip_hwgpio(desc), ret = gpio_set_config(gc, gpio_chip_hwgpio(desc),
PIN_CONFIG_DRIVE_OPEN_DRAIN); PIN_CONFIG_DRIVE_OPEN_DRAIN);
if (!ret) if (!ret)
goto set_output_value; goto set_output_value;
/* Emulate open drain by not actively driving the line high */ /* Emulate open drain by not actively driving the line high */
...@@ -2721,16 +2728,16 @@ int gpiod_direction_output(struct gpio_desc *desc, int value) ...@@ -2721,16 +2728,16 @@ int gpiod_direction_output(struct gpio_desc *desc, int value)
return gpiod_direction_input(desc); return gpiod_direction_input(desc);
} }
else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags)) { else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags)) {
ret = gpio_set_drive_single_ended(gc, gpio_chip_hwgpio(desc), ret = gpio_set_config(gc, gpio_chip_hwgpio(desc),
PIN_CONFIG_DRIVE_OPEN_SOURCE); PIN_CONFIG_DRIVE_OPEN_SOURCE);
if (!ret) if (!ret)
goto set_output_value; goto set_output_value;
/* Emulate open source by not actively driving the line low */ /* Emulate open source by not actively driving the line low */
if (!value) if (!value)
return gpiod_direction_input(desc); return gpiod_direction_input(desc);
} else { } else {
gpio_set_drive_single_ended(gc, gpio_chip_hwgpio(desc), gpio_set_config(gc, gpio_chip_hwgpio(desc),
PIN_CONFIG_DRIVE_PUSH_PULL); PIN_CONFIG_DRIVE_PUSH_PULL);
} }
set_output_value: set_output_value:
...@@ -2762,7 +2769,7 @@ int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce) ...@@ -2762,7 +2769,7 @@ int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce)
} }
config = pinconf_to_config_packed(PIN_CONFIG_INPUT_DEBOUNCE, debounce); config = pinconf_to_config_packed(PIN_CONFIG_INPUT_DEBOUNCE, debounce);
return chip->set_config(chip, gpio_chip_hwgpio(desc), config); return gpio_set_config(chip, gpio_chip_hwgpio(desc), config);
} }
EXPORT_SYMBOL_GPL(gpiod_set_debounce); EXPORT_SYMBOL_GPL(gpiod_set_debounce);
...@@ -2799,7 +2806,7 @@ int gpiod_set_transitory(struct gpio_desc *desc, bool transitory) ...@@ -2799,7 +2806,7 @@ int gpiod_set_transitory(struct gpio_desc *desc, bool transitory)
packed = pinconf_to_config_packed(PIN_CONFIG_PERSIST_STATE, packed = pinconf_to_config_packed(PIN_CONFIG_PERSIST_STATE,
!transitory); !transitory);
gpio = gpio_chip_hwgpio(desc); gpio = gpio_chip_hwgpio(desc);
rc = chip->set_config(chip, gpio, packed); rc = gpio_set_config(chip, gpio, packed);
if (rc == -ENOTSUPP) { if (rc == -ENOTSUPP) {
dev_dbg(&desc->gdev->dev, "Persistence not supported for GPIO %d\n", dev_dbg(&desc->gdev->dev, "Persistence not supported for GPIO %d\n",
gpio); gpio);
...@@ -4087,6 +4094,17 @@ int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id, ...@@ -4087,6 +4094,17 @@ int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id,
if (lflags & GPIO_OPEN_SOURCE) if (lflags & GPIO_OPEN_SOURCE)
set_bit(FLAG_OPEN_SOURCE, &desc->flags); set_bit(FLAG_OPEN_SOURCE, &desc->flags);
if ((lflags & GPIO_PULL_UP) && (lflags & GPIO_PULL_DOWN)) {
gpiod_err(desc,
"both pull-up and pull-down enabled, invalid configuration\n");
return -EINVAL;
}
if (lflags & GPIO_PULL_UP)
set_bit(FLAG_PULL_UP, &desc->flags);
else if (lflags & GPIO_PULL_DOWN)
set_bit(FLAG_PULL_DOWN, &desc->flags);
status = gpiod_set_transitory(desc, (lflags & GPIO_TRANSITORY)); status = gpiod_set_transitory(desc, (lflags & GPIO_TRANSITORY));
if (status < 0) if (status < 0)
return status; return status;
......
...@@ -219,6 +219,8 @@ struct gpio_desc { ...@@ -219,6 +219,8 @@ struct gpio_desc {
#define FLAG_IRQ_IS_ENABLED 10 /* GPIO is connected to an enabled IRQ */ #define FLAG_IRQ_IS_ENABLED 10 /* GPIO is connected to an enabled IRQ */
#define FLAG_IS_HOGGED 11 /* GPIO is hogged */ #define FLAG_IS_HOGGED 11 /* GPIO is hogged */
#define FLAG_TRANSITORY 12 /* GPIO may lose value in sleep or reset */ #define FLAG_TRANSITORY 12 /* GPIO may lose value in sleep or reset */
#define FLAG_PULL_UP 13 /* GPIO has pull up enabled */
#define FLAG_PULL_DOWN 14 /* GPIO has pull down enabled */
/* Connection label */ /* Connection label */
const char *label; const char *label;
......
...@@ -33,4 +33,10 @@ ...@@ -33,4 +33,10 @@
#define GPIO_PERSISTENT 0 #define GPIO_PERSISTENT 0
#define GPIO_TRANSITORY 8 #define GPIO_TRANSITORY 8
/* Bit 4 express pull up */
#define GPIO_PULL_UP 16
/* Bit 5 express pull down */
#define GPIO_PULL_DOWN 32
#endif #endif
...@@ -12,6 +12,8 @@ enum gpio_lookup_flags { ...@@ -12,6 +12,8 @@ enum gpio_lookup_flags {
GPIO_OPEN_SOURCE = (1 << 2), GPIO_OPEN_SOURCE = (1 << 2),
GPIO_PERSISTENT = (0 << 3), GPIO_PERSISTENT = (0 << 3),
GPIO_TRANSITORY = (1 << 3), GPIO_TRANSITORY = (1 << 3),
GPIO_PULL_UP = (1 << 4),
GPIO_PULL_DOWN = (1 << 5),
}; };
/** /**
......
...@@ -28,6 +28,8 @@ enum of_gpio_flags { ...@@ -28,6 +28,8 @@ enum of_gpio_flags {
OF_GPIO_SINGLE_ENDED = 0x2, OF_GPIO_SINGLE_ENDED = 0x2,
OF_GPIO_OPEN_DRAIN = 0x4, OF_GPIO_OPEN_DRAIN = 0x4,
OF_GPIO_TRANSITORY = 0x8, OF_GPIO_TRANSITORY = 0x8,
OF_GPIO_PULL_UP = 0x10,
OF_GPIO_PULL_DOWN = 0x20,
}; };
#ifdef CONFIG_OF_GPIO #ifdef CONFIG_OF_GPIO
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment