Commit 6ea3e3bb authored by Guillaume La Roque's avatar Guillaume La Roque Committed by Linus Walleij

pinctrl: meson: add support of drive-strength-microamp

drive-strength-microamp is a new feature needed for G12A SoC.
the default DS setting after boot is usually 500uA and it is not enough for
many functions. We need to be able to set the drive strength to reliably
enable things like MMC, I2C, etc ...
Signed-off-by: default avatarGuillaume La Roque <glaroque@baylibre.com>
Reviewed-by: default avatarMartin Blumenstingl <martin.blumenstingl@googlemail.com>
Tested-by: default avatarMartin Blumenstingl <martin.blumenstingl@googlemail.com>
Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
parent 9959d9a7
......@@ -220,11 +220,54 @@ static int meson_pinconf_enable_bias(struct meson_pinctrl *pc, unsigned int pin,
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, &reg, &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 drive_strength_ua;
int i, ret;
for (i = 0; i < num_configs; i++) {
......@@ -246,6 +289,14 @@ static int meson_pinconf_set(struct pinctrl_dev *pcdev, unsigned int pin,
if (ret)
return ret;
break;
case PIN_CONFIG_DRIVE_STRENGTH_UA:
drive_strength_ua =
pinconf_to_config_argument(configs[i]);
ret = meson_pinconf_set_drive_strength
(pc, pin, drive_strength_ua);
if (ret)
return ret;
break;
default:
return -ENOTSUPP;
}
......@@ -288,12 +339,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, &reg, &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:
......@@ -304,6 +398,11 @@ 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;
default:
return -ENOTSUPP;
}
......
......@@ -71,9 +71,20 @@ 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
*
......@@ -132,7 +143,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, \
......@@ -145,9 +157,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 */
......
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