diff options
Diffstat (limited to 'drivers/pinctrl/meson')
-rw-r--r-- | drivers/pinctrl/meson/pinctrl-meson-g12a.c | 36 | ||||
-rw-r--r-- | drivers/pinctrl/meson/pinctrl-meson.c | 350 | ||||
-rw-r--r-- | drivers/pinctrl/meson/pinctrl-meson.h | 18 |
3 files changed, 302 insertions, 102 deletions
diff --git a/drivers/pinctrl/meson/pinctrl-meson-g12a.c b/drivers/pinctrl/meson/pinctrl-meson-g12a.c index d494492e98e9..3475cd7bd2af 100644 --- a/drivers/pinctrl/meson/pinctrl-meson-g12a.c +++ b/drivers/pinctrl/meson/pinctrl-meson-g12a.c @@ -1304,28 +1304,28 @@ static struct meson_pmx_func meson_g12a_aobus_functions[] = { }; static struct meson_bank meson_g12a_periphs_banks[] = { - /* name first last irq pullen pull dir out in */ - BANK("Z", GPIOZ_0, GPIOZ_15, 12, 27, - 4, 0, 4, 0, 12, 0, 13, 0, 14, 0), - BANK("H", GPIOH_0, GPIOH_8, 28, 36, - 3, 0, 3, 0, 9, 0, 10, 0, 11, 0), - BANK("BOOT", BOOT_0, BOOT_15, 37, 52, - 0, 0, 0, 0, 0, 0, 1, 0, 2, 0), - BANK("C", GPIOC_0, GPIOC_7, 53, 60, - 1, 0, 1, 0, 3, 0, 4, 0, 5, 0), - BANK("A", GPIOA_0, GPIOA_15, 61, 76, - 5, 0, 5, 0, 16, 0, 17, 0, 18, 0), - BANK("X", GPIOX_0, GPIOX_19, 77, 96, - 2, 0, 2, 0, 6, 0, 7, 0, 8, 0), + /* name first last irq pullen pull dir out in ds */ + BANK_DS("Z", GPIOZ_0, GPIOZ_15, 12, 27, + 4, 0, 4, 0, 12, 0, 13, 0, 14, 0, 5, 0), + BANK_DS("H", GPIOH_0, GPIOH_8, 28, 36, + 3, 0, 3, 0, 9, 0, 10, 0, 11, 0, 4, 0), + BANK_DS("BOOT", BOOT_0, BOOT_15, 37, 52, + 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0), + BANK_DS("C", GPIOC_0, GPIOC_7, 53, 60, + 1, 0, 1, 0, 3, 0, 4, 0, 5, 0, 1, 0), + BANK_DS("A", GPIOA_0, GPIOA_15, 61, 76, + 5, 0, 5, 0, 16, 0, 17, 0, 18, 0, 6, 0), + BANK_DS("X", GPIOX_0, GPIOX_19, 77, 96, + 2, 0, 2, 0, 6, 0, 7, 0, 8, 0, 2, 0), }; static struct meson_bank meson_g12a_aobus_banks[] = { - /* name first last irq pullen pull dir out in */ - BANK("AO", GPIOAO_0, GPIOAO_11, 0, 11, - 3, 0, 2, 0, 0, 0, 4, 0, 1, 0), + /* name first last irq pullen pull dir out in ds */ + BANK_DS("AO", GPIOAO_0, GPIOAO_11, 0, 11, 3, 0, 2, 0, 0, 0, 4, 0, 1, 0, + 0, 0), /* GPIOE actually located in the AO bank */ - BANK("E", GPIOE_0, GPIOE_2, 97, 99, - 3, 16, 2, 16, 0, 16, 4, 16, 1, 16), + BANK_DS("E", GPIOE_0, GPIOE_2, 97, 99, 3, 16, 2, 16, 0, 16, 4, 16, 1, + 16, 1, 0), }; static struct meson_pmx_bank meson_g12a_periphs_pmx_banks[] = { diff --git a/drivers/pinctrl/meson/pinctrl-meson.c b/drivers/pinctrl/meson/pinctrl-meson.c index 077de5925783..596786926209 100644 --- a/drivers/pinctrl/meson/pinctrl-meson.c +++ b/drivers/pinctrl/meson/pinctrl-meson.c @@ -168,68 +168,223 @@ int meson_pmx_get_groups(struct pinctrl_dev *pcdev, unsigned selector, return 0; } -static int meson_pinconf_set(struct pinctrl_dev *pcdev, unsigned int pin, - unsigned long *configs, unsigned num_configs) +static int meson_pinconf_set_gpio_bit(struct meson_pinctrl *pc, + unsigned int pin, + unsigned int reg_type, + bool arg) { - struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev); struct meson_bank *bank; - enum pin_config_param param; unsigned int reg, bit; - int i, ret; + int ret; + + ret = meson_get_bank(pc, pin, &bank); + if (ret) + return ret; + + meson_calc_reg_and_bit(bank, pin, reg_type, ®, &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, ®, &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, + unsigned int pin) +{ + struct meson_bank *bank; + unsigned int reg, bit = 0; + int ret; + + ret = meson_get_bank(pc, pin, &bank); + if (ret) + return ret; + + meson_calc_reg_and_bit(bank, pin, REG_PULLEN, ®, &bit); + ret = regmap_update_bits(pc->reg_pullen, reg, BIT(bit), 0); + if (ret) + return ret; + + return 0; +} + +static int meson_pinconf_enable_bias(struct meson_pinctrl *pc, unsigned int pin, + bool pull_up) +{ + struct meson_bank *bank; + unsigned int reg, bit, val = 0; + int ret; + + ret = meson_get_bank(pc, pin, &bank); + if (ret) + return ret; + + meson_calc_reg_and_bit(bank, pin, REG_PULL, ®, &bit); + if (pull_up) + val = BIT(bit); + + ret = regmap_update_bits(pc->reg_pull, reg, BIT(bit), val); + if (ret) + return ret; + + meson_calc_reg_and_bit(bank, pin, REG_PULLEN, ®, &bit); + ret = regmap_update_bits(pc->reg_pullen, reg, BIT(bit), BIT(bit)); + if (ret) + return ret; + + return 0; +} + +static int meson_pinconf_set_drive_strength(struct meson_pinctrl *pc, + unsigned int pin, + u16 drive_strength_ua) +{ + struct meson_bank *bank; + unsigned int reg, bit, ds_val; + int ret; + + if (!pc->reg_ds) { + dev_err(pc->dev, "drive-strength not supported\n"); + return -ENOTSUPP; + } + + ret = meson_get_bank(pc, pin, &bank); + if (ret) + return ret; + + meson_calc_reg_and_bit(bank, pin, REG_DS, ®, &bit); + bit = bit << 1; + + if (drive_strength_ua <= 500) { + ds_val = MESON_PINCONF_DRV_500UA; + } else if (drive_strength_ua <= 2500) { + ds_val = MESON_PINCONF_DRV_2500UA; + } else if (drive_strength_ua <= 3000) { + ds_val = MESON_PINCONF_DRV_3000UA; + } else if (drive_strength_ua <= 4000) { + ds_val = MESON_PINCONF_DRV_4000UA; + } else { + dev_warn_once(pc->dev, + "pin %u: invalid drive-strength : %d , default to 4mA\n", + pin, drive_strength_ua); + ds_val = MESON_PINCONF_DRV_4000UA; + } + + ret = regmap_update_bits(pc->reg_ds, reg, 0x3 << bit, ds_val << bit); + if (ret) + return ret; + + return 0; +} + +static int meson_pinconf_set(struct pinctrl_dev *pcdev, unsigned int pin, + unsigned long *configs, unsigned num_configs) +{ + struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev); + enum pin_config_param param; + unsigned int arg = 0; + int i, ret; + for (i = 0; i < num_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) { case PIN_CONFIG_BIAS_DISABLE: - dev_dbg(pc->dev, "pin %u: disable bias\n", pin); - - meson_calc_reg_and_bit(bank, pin, REG_PULLEN, ®, - &bit); - ret = regmap_update_bits(pc->reg_pullen, reg, - BIT(bit), 0); - if (ret) - return ret; + ret = meson_pinconf_disable_bias(pc, pin); break; case PIN_CONFIG_BIAS_PULL_UP: - dev_dbg(pc->dev, "pin %u: enable pull-up\n", pin); - - meson_calc_reg_and_bit(bank, pin, REG_PULLEN, - ®, &bit); - ret = regmap_update_bits(pc->reg_pullen, reg, - BIT(bit), BIT(bit)); - if (ret) - return ret; - - meson_calc_reg_and_bit(bank, pin, REG_PULL, ®, &bit); - ret = regmap_update_bits(pc->reg_pull, reg, - BIT(bit), BIT(bit)); - if (ret) - return ret; + ret = meson_pinconf_enable_bias(pc, pin, true); break; case PIN_CONFIG_BIAS_PULL_DOWN: - dev_dbg(pc->dev, "pin %u: enable pull-down\n", pin); - - meson_calc_reg_and_bit(bank, pin, REG_PULLEN, - ®, &bit); - ret = regmap_update_bits(pc->reg_pullen, reg, - BIT(bit), BIT(bit)); - if (ret) - return ret; - - meson_calc_reg_and_bit(bank, pin, REG_PULL, ®, &bit); - ret = regmap_update_bits(pc->reg_pull, reg, - BIT(bit), 0); - if (ret) - return ret; + ret = meson_pinconf_enable_bias(pc, pin, false); + break; + case PIN_CONFIG_DRIVE_STRENGTH_UA: + ret = meson_pinconf_set_drive_strength(pc, pin, arg); + break; + case PIN_CONFIG_OUTPUT_ENABLE: + ret = meson_pinconf_set_output(pc, pin, arg); + break; + case PIN_CONFIG_OUTPUT: + ret = meson_pinconf_set_output_drive(pc, pin, arg); break; default: - return -ENOTSUPP; + ret = -ENOTSUPP; } + + if (ret) + return ret; } return 0; @@ -269,12 +424,55 @@ static int meson_pinconf_get_pull(struct meson_pinctrl *pc, unsigned int pin) return conf; } +static int meson_pinconf_get_drive_strength(struct meson_pinctrl *pc, + unsigned int pin, + u16 *drive_strength_ua) +{ + struct meson_bank *bank; + unsigned int reg, bit; + unsigned int val; + int ret; + + if (!pc->reg_ds) + return -ENOTSUPP; + + ret = meson_get_bank(pc, pin, &bank); + if (ret) + return ret; + + meson_calc_reg_and_bit(bank, pin, REG_DS, ®, &bit); + + ret = regmap_read(pc->reg_ds, reg, &val); + if (ret) + return ret; + + switch ((val >> bit) & 0x3) { + case MESON_PINCONF_DRV_500UA: + *drive_strength_ua = 500; + break; + case MESON_PINCONF_DRV_2500UA: + *drive_strength_ua = 2500; + break; + case MESON_PINCONF_DRV_3000UA: + *drive_strength_ua = 3000; + break; + case MESON_PINCONF_DRV_4000UA: + *drive_strength_ua = 4000; + break; + default: + return -EINVAL; + } + + return 0; +} + static int meson_pinconf_get(struct pinctrl_dev *pcdev, unsigned int pin, unsigned long *config) { struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev); enum pin_config_param param = pinconf_to_config_param(*config); u16 arg; + int ret; switch (param) { case PIN_CONFIG_BIAS_DISABLE: @@ -285,6 +483,29 @@ static int meson_pinconf_get(struct pinctrl_dev *pcdev, unsigned int pin, else return -EINVAL; break; + case PIN_CONFIG_DRIVE_STRENGTH_UA: + ret = meson_pinconf_get_drive_strength(pc, pin, &arg); + if (ret) + return ret; + 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: return -ENOTSUPP; } @@ -329,56 +550,19 @@ static const struct pinconf_ops meson_pinconf_ops = { static int meson_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) { - struct meson_pinctrl *pc = gpiochip_get_data(chip); - 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, ®, &bit); - - return regmap_update_bits(pc->reg_gpio, reg, BIT(bit), BIT(bit)); + return meson_pinconf_set_output(gpiochip_get_data(chip), gpio, false); } static int meson_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, int value) { - struct meson_pinctrl *pc = gpiochip_get_data(chip); - 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, ®, &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, ®, &bit); - return regmap_update_bits(pc->reg_gpio, reg, BIT(bit), - value ? BIT(bit) : 0); + return meson_pinconf_set_output_drive(gpiochip_get_data(chip), + gpio, value); } static void meson_gpio_set(struct gpio_chip *chip, unsigned gpio, int value) { - struct meson_pinctrl *pc = gpiochip_get_data(chip); - 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, ®, &bit); - regmap_update_bits(pc->reg_gpio, reg, BIT(bit), - value ? BIT(bit) : 0); + meson_pinconf_set_drive(gpiochip_get_data(chip), gpio, value); } static int meson_gpio_get(struct gpio_chip *chip, unsigned gpio) diff --git a/drivers/pinctrl/meson/pinctrl-meson.h b/drivers/pinctrl/meson/pinctrl-meson.h index adab4ea078f9..c696f3241a36 100644 --- a/drivers/pinctrl/meson/pinctrl-meson.h +++ b/drivers/pinctrl/meson/pinctrl-meson.h @@ -65,10 +65,21 @@ enum meson_reg_type { REG_DIR, REG_OUT, REG_IN, + REG_DS, NUM_REG, }; /** + * enum meson_pinconf_drv - value of drive-strength supported + */ +enum meson_pinconf_drv { + MESON_PINCONF_DRV_500UA, + MESON_PINCONF_DRV_2500UA, + MESON_PINCONF_DRV_3000UA, + MESON_PINCONF_DRV_4000UA, +}; + +/** * struct meson bank * * @name: bank name @@ -126,7 +137,8 @@ struct meson_pinctrl { .num_groups = ARRAY_SIZE(fn ## _groups), \ } -#define BANK(n, f, l, fi, li, per, peb, pr, pb, dr, db, or, ob, ir, ib) \ +#define BANK_DS(n, f, l, fi, li, per, peb, pr, pb, dr, db, or, ob, ir, ib, \ + dsr, dsb) \ { \ .name = n, \ .first = f, \ @@ -139,9 +151,13 @@ struct meson_pinctrl { [REG_DIR] = { dr, db }, \ [REG_OUT] = { or, ob }, \ [REG_IN] = { ir, ib }, \ + [REG_DS] = { dsr, dsb }, \ }, \ } +#define BANK(n, f, l, fi, li, per, peb, pr, pb, dr, db, or, ob, ir, ib) \ + BANK_DS(n, f, l, fi, li, per, peb, pr, pb, dr, db, or, ob, ir, ib, 0, 0) + #define MESON_PIN(x) PINCTRL_PIN(x, #x) /* Common pmx functions */ |