Commit b22a7f85 authored by Jerome Brunet's avatar Jerome Brunet Committed by Linus Walleij

pinctrl: meson: add output support in pinconf

Add pinconf support for PIN_CONFIG_OUTPUT_ENABLE and PIN_CONFIG_OUTPUT
in the meson pinctrl driver.
Signed-off-by: default avatarJerome Brunet <jbrunet@baylibre.com>
Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
parent 1254db24
...@@ -174,6 +174,88 @@ int meson_pmx_get_groups(struct pinctrl_dev *pcdev, unsigned selector, ...@@ -174,6 +174,88 @@ int meson_pmx_get_groups(struct pinctrl_dev *pcdev, unsigned selector,
return 0; return 0;
} }
static int meson_pinconf_set_gpio_bit(struct meson_pinctrl *pc,
unsigned int pin,
unsigned int reg_type,
bool arg)
{
struct meson_bank *bank;
unsigned int reg, bit;
int ret;
ret = meson_get_bank(pc, pin, &bank);
if (ret)
return ret;
meson_calc_reg_and_bit(bank, pin, reg_type, &reg, &bit);
return regmap_update_bits(pc->reg_gpio, reg, BIT(bit),
arg ? BIT(bit) : 0);
}
static int meson_pinconf_get_gpio_bit(struct meson_pinctrl *pc,
unsigned int pin,
unsigned int reg_type)
{
struct meson_bank *bank;
unsigned int reg, bit, val;
int ret;
ret = meson_get_bank(pc, pin, &bank);
if (ret)
return ret;
meson_calc_reg_and_bit(bank, pin, reg_type, &reg, &bit);
ret = regmap_read(pc->reg_gpio, reg, &val);
if (ret)
return ret;
return BIT(bit) & val ? 1 : 0;
}
static int meson_pinconf_set_output(struct meson_pinctrl *pc,
unsigned int pin,
bool out)
{
return meson_pinconf_set_gpio_bit(pc, pin, REG_DIR, !out);
}
static int meson_pinconf_get_output(struct meson_pinctrl *pc,
unsigned int pin)
{
int ret = meson_pinconf_get_gpio_bit(pc, pin, REG_DIR);
if (ret < 0)
return ret;
return !ret;
}
static int meson_pinconf_set_drive(struct meson_pinctrl *pc,
unsigned int pin,
bool high)
{
return meson_pinconf_set_gpio_bit(pc, pin, REG_OUT, high);
}
static int meson_pinconf_get_drive(struct meson_pinctrl *pc,
unsigned int pin)
{
return meson_pinconf_get_gpio_bit(pc, pin, REG_OUT);
}
static int meson_pinconf_set_output_drive(struct meson_pinctrl *pc,
unsigned int pin,
bool high)
{
int ret;
ret = meson_pinconf_set_output(pc, pin, true);
if (ret)
return ret;
return meson_pinconf_set_drive(pc, pin, high);
}
static int meson_pinconf_disable_bias(struct meson_pinctrl *pc, static int meson_pinconf_disable_bias(struct meson_pinctrl *pc,
unsigned int pin) unsigned int pin)
{ {
...@@ -267,39 +349,48 @@ static int meson_pinconf_set(struct pinctrl_dev *pcdev, unsigned int pin, ...@@ -267,39 +349,48 @@ static int meson_pinconf_set(struct pinctrl_dev *pcdev, unsigned int pin,
{ {
struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev); struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev);
enum pin_config_param param; enum pin_config_param param;
unsigned int drive_strength_ua; unsigned int arg = 0;
int i, ret; int i, ret;
for (i = 0; i < num_configs; i++) { for (i = 0; i < num_configs; i++) {
param = pinconf_to_config_param(configs[i]); param = pinconf_to_config_param(configs[i]);
switch (param) {
case PIN_CONFIG_DRIVE_STRENGTH_UA:
case PIN_CONFIG_OUTPUT_ENABLE:
case PIN_CONFIG_OUTPUT:
arg = pinconf_to_config_argument(configs[i]);
break;
default:
break;
}
switch (param) { switch (param) {
case PIN_CONFIG_BIAS_DISABLE: case PIN_CONFIG_BIAS_DISABLE:
ret = meson_pinconf_disable_bias(pc, pin); ret = meson_pinconf_disable_bias(pc, pin);
if (ret)
return ret;
break; break;
case PIN_CONFIG_BIAS_PULL_UP: case PIN_CONFIG_BIAS_PULL_UP:
ret = meson_pinconf_enable_bias(pc, pin, true); ret = meson_pinconf_enable_bias(pc, pin, true);
if (ret)
return ret;
break; break;
case PIN_CONFIG_BIAS_PULL_DOWN: case PIN_CONFIG_BIAS_PULL_DOWN:
ret = meson_pinconf_enable_bias(pc, pin, false); ret = meson_pinconf_enable_bias(pc, pin, false);
if (ret)
return ret;
break; break;
case PIN_CONFIG_DRIVE_STRENGTH_UA: case PIN_CONFIG_DRIVE_STRENGTH_UA:
drive_strength_ua = ret = meson_pinconf_set_drive_strength(pc, pin, arg);
pinconf_to_config_argument(configs[i]); break;
ret = meson_pinconf_set_drive_strength case PIN_CONFIG_OUTPUT_ENABLE:
(pc, pin, drive_strength_ua); ret = meson_pinconf_set_output(pc, pin, arg);
if (ret) break;
return ret; case PIN_CONFIG_OUTPUT:
ret = meson_pinconf_set_output_drive(pc, pin, arg);
break; break;
default: default:
return -ENOTSUPP; ret = -ENOTSUPP;
} }
if (ret)
return ret;
} }
return 0; return 0;
...@@ -403,6 +494,24 @@ static int meson_pinconf_get(struct pinctrl_dev *pcdev, unsigned int pin, ...@@ -403,6 +494,24 @@ static int meson_pinconf_get(struct pinctrl_dev *pcdev, unsigned int pin,
if (ret) if (ret)
return ret; return ret;
break; break;
case PIN_CONFIG_OUTPUT_ENABLE:
ret = meson_pinconf_get_output(pc, pin);
if (ret <= 0)
return -EINVAL;
arg = 1;
break;
case PIN_CONFIG_OUTPUT:
ret = meson_pinconf_get_output(pc, pin);
if (ret <= 0)
return -EINVAL;
ret = meson_pinconf_get_drive(pc, pin);
if (ret < 0)
return -EINVAL;
arg = ret;
break;
default: default:
return -ENOTSUPP; return -ENOTSUPP;
} }
...@@ -447,56 +556,19 @@ static const struct pinconf_ops meson_pinconf_ops = { ...@@ -447,56 +556,19 @@ static const struct pinconf_ops meson_pinconf_ops = {
static int meson_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) static int meson_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
{ {
struct meson_pinctrl *pc = gpiochip_get_data(chip); return meson_pinconf_set_output(gpiochip_get_data(chip), gpio, false);
unsigned int reg, bit;
struct meson_bank *bank;
int ret;
ret = meson_get_bank(pc, gpio, &bank);
if (ret)
return ret;
meson_calc_reg_and_bit(bank, gpio, REG_DIR, &reg, &bit);
return regmap_update_bits(pc->reg_gpio, reg, BIT(bit), BIT(bit));
} }
static int meson_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, static int meson_gpio_direction_output(struct gpio_chip *chip, unsigned gpio,
int value) int value)
{ {
struct meson_pinctrl *pc = gpiochip_get_data(chip); return meson_pinconf_set_output_drive(gpiochip_get_data(chip),
unsigned int reg, bit; gpio, value);
struct meson_bank *bank;
int ret;
ret = meson_get_bank(pc, gpio, &bank);
if (ret)
return ret;
meson_calc_reg_and_bit(bank, gpio, REG_DIR, &reg, &bit);
ret = regmap_update_bits(pc->reg_gpio, reg, BIT(bit), 0);
if (ret)
return ret;
meson_calc_reg_and_bit(bank, gpio, REG_OUT, &reg, &bit);
return regmap_update_bits(pc->reg_gpio, reg, BIT(bit),
value ? BIT(bit) : 0);
} }
static void meson_gpio_set(struct gpio_chip *chip, unsigned gpio, int value) static void meson_gpio_set(struct gpio_chip *chip, unsigned gpio, int value)
{ {
struct meson_pinctrl *pc = gpiochip_get_data(chip); meson_pinconf_set_drive(gpiochip_get_data(chip), gpio, value);
unsigned int reg, bit;
struct meson_bank *bank;
int ret;
ret = meson_get_bank(pc, gpio, &bank);
if (ret)
return;
meson_calc_reg_and_bit(bank, gpio, REG_OUT, &reg, &bit);
regmap_update_bits(pc->reg_gpio, reg, BIT(bit),
value ? BIT(bit) : 0);
} }
static int meson_gpio_get(struct gpio_chip *chip, unsigned gpio) static int meson_gpio_get(struct gpio_chip *chip, unsigned 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