From ec1ba3e519c0f46523cf40b83dc71562171b7c08 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 22 Mar 2018 11:17:40 +0100 Subject: [PATCH 01/57] regulator: ab8500: Drop AB8540/9540 support The AB8540 was an evolved version of the AB8500, but it was never mass produced or put into products, only reference designs exist. The upstream support was never completed and it is unlikely that this will happen so drop the support for now to simplify maintenance of the AB8500. Cc: Loic Pallardy Signed-off-by: Linus Walleij Signed-off-by: Mark Brown --- drivers/regulator/ab8500.c | 1407 +----------------------------- include/linux/regulator/ab8500.h | 157 +--- 2 files changed, 2 insertions(+), 1562 deletions(-) diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index 0f97514e3474..83dba3fbfe0c 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -132,33 +132,6 @@ static const unsigned int ldo_vaux56_voltages[] = { 2790000, }; -static const unsigned int ldo_vaux3_ab8540_voltages[] = { - 1200000, - 1500000, - 1800000, - 2100000, - 2500000, - 2750000, - 2790000, - 2910000, - 3050000, -}; - -static const unsigned int ldo_vaux56_ab8540_voltages[] = { - 750000, 760000, 770000, 780000, 790000, 800000, - 810000, 820000, 830000, 840000, 850000, 860000, - 870000, 880000, 890000, 900000, 910000, 920000, - 930000, 940000, 950000, 960000, 970000, 980000, - 990000, 1000000, 1010000, 1020000, 1030000, - 1040000, 1050000, 1060000, 1070000, 1080000, - 1090000, 1100000, 1110000, 1120000, 1130000, - 1140000, 1150000, 1160000, 1170000, 1180000, - 1190000, 1200000, 1210000, 1220000, 1230000, - 1240000, 1250000, 1260000, 1270000, 1280000, - 1290000, 1300000, 1310000, 1320000, 1330000, - 1340000, 1350000, 1360000, 1800000, 2790000, -}; - static const unsigned int ldo_vintcore_voltages[] = { 1200000, 1225000, @@ -232,8 +205,6 @@ static const unsigned int ldo_vdmic_voltages[] = { static DEFINE_MUTEX(shared_mode_mutex); static struct ab8500_shared_mode ldo_anamic1_shared; static struct ab8500_shared_mode ldo_anamic2_shared; -static struct ab8500_shared_mode ab8540_ldo_anamic1_shared; -static struct ab8500_shared_mode ab8540_ldo_anamic2_shared; static int ab8500_regulator_enable(struct regulator_dev *rdev) { @@ -507,53 +478,6 @@ static int ab8500_regulator_get_voltage_sel(struct regulator_dev *rdev) return (regval & info->voltage_mask) >> voltage_shift; } -static int ab8540_aux3_regulator_get_voltage_sel(struct regulator_dev *rdev) -{ - int ret, voltage_shift; - struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); - u8 regval, regval_expand; - - if (info == NULL) { - dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); - return -EINVAL; - } - - ret = abx500_get_register_interruptible(info->dev, - info->expand_register.voltage_bank, - info->expand_register.voltage_reg, ®val_expand); - if (ret < 0) { - dev_err(rdev_get_dev(rdev), - "couldn't read voltage expand reg for regulator\n"); - return ret; - } - - dev_vdbg(rdev_get_dev(rdev), - "%s-get_voltage expand (bank, reg, mask, value): 0x%x, 0x%x, 0x%x, 0x%x\n", - info->desc.name, info->expand_register.voltage_bank, - info->expand_register.voltage_reg, - info->expand_register.voltage_mask, regval_expand); - - if (regval_expand & info->expand_register.voltage_mask) - return info->expand_register.voltage_limit; - - ret = abx500_get_register_interruptible(info->dev, - info->voltage_bank, info->voltage_reg, ®val); - if (ret < 0) { - dev_err(rdev_get_dev(rdev), - "couldn't read voltage reg for regulator\n"); - return ret; - } - - dev_vdbg(rdev_get_dev(rdev), - "%s-get_voltage (bank, reg, mask, value): 0x%x, 0x%x, 0x%x, 0x%x\n", - info->desc.name, info->voltage_bank, info->voltage_reg, - info->voltage_mask, regval); - - voltage_shift = ffs(info->voltage_mask) - 1; - - return (regval & info->voltage_mask) >> voltage_shift; -} - static int ab8500_regulator_set_voltage_sel(struct regulator_dev *rdev, unsigned selector) { @@ -586,61 +510,6 @@ static int ab8500_regulator_set_voltage_sel(struct regulator_dev *rdev, return ret; } -static int ab8540_aux3_regulator_set_voltage_sel(struct regulator_dev *rdev, - unsigned selector) -{ - int ret; - struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); - u8 regval, regval_expand; - - if (info == NULL) { - dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); - return -EINVAL; - } - - if (selector < info->expand_register.voltage_limit) { - int voltage_shift = ffs(info->voltage_mask) - 1; - - regval = (u8)selector << voltage_shift; - ret = abx500_mask_and_set_register_interruptible(info->dev, - info->voltage_bank, info->voltage_reg, - info->voltage_mask, regval); - if (ret < 0) { - dev_err(rdev_get_dev(rdev), - "couldn't set voltage reg for regulator\n"); - return ret; - } - - dev_vdbg(rdev_get_dev(rdev), - "%s-set_voltage (bank, reg, mask, value): 0x%x, 0x%x, 0x%x, 0x%x\n", - info->desc.name, info->voltage_bank, info->voltage_reg, - info->voltage_mask, regval); - - regval_expand = 0; - } else { - regval_expand = info->expand_register.voltage_mask; - } - - ret = abx500_mask_and_set_register_interruptible(info->dev, - info->expand_register.voltage_bank, - info->expand_register.voltage_reg, - info->expand_register.voltage_mask, - regval_expand); - if (ret < 0) { - dev_err(rdev_get_dev(rdev), - "couldn't set expand voltage reg for regulator\n"); - return ret; - } - - dev_vdbg(rdev_get_dev(rdev), - "%s-set_voltage expand (bank, reg, mask, value): 0x%x, 0x%x, 0x%x, 0x%x\n", - info->desc.name, info->expand_register.voltage_bank, - info->expand_register.voltage_reg, - info->expand_register.voltage_mask, regval_expand); - - return 0; -} - static struct regulator_ops ab8500_regulator_volt_mode_ops = { .enable = ab8500_regulator_enable, .disable = ab8500_regulator_disable, @@ -653,18 +522,6 @@ static struct regulator_ops ab8500_regulator_volt_mode_ops = { .list_voltage = regulator_list_voltage_table, }; -static struct regulator_ops ab8540_aux3_regulator_volt_mode_ops = { - .enable = ab8500_regulator_enable, - .disable = ab8500_regulator_disable, - .get_optimum_mode = ab8500_regulator_get_optimum_mode, - .set_mode = ab8500_regulator_set_mode, - .get_mode = ab8500_regulator_get_mode, - .is_enabled = ab8500_regulator_is_enabled, - .get_voltage_sel = ab8540_aux3_regulator_get_voltage_sel, - .set_voltage_sel = ab8540_aux3_regulator_set_voltage_sel, - .list_voltage = regulator_list_voltage_table, -}; - static struct regulator_ops ab8500_regulator_volt_ops = { .enable = ab8500_regulator_enable, .disable = ab8500_regulator_disable, @@ -1217,562 +1074,6 @@ static struct ab8500_regulator_info }, }; -/* AB9540 regulator information */ -static struct ab8500_regulator_info - ab9540_regulator_info[AB9540_NUM_REGULATORS] = { - /* - * Variable Voltage Regulators - * name, min mV, max mV, - * update bank, reg, mask, enable val - * volt bank, reg, mask - */ - [AB9540_LDO_AUX1] = { - .desc = { - .name = "LDO-AUX1", - .ops = &ab8500_regulator_volt_mode_ops, - .type = REGULATOR_VOLTAGE, - .id = AB9540_LDO_AUX1, - .owner = THIS_MODULE, - .n_voltages = ARRAY_SIZE(ldo_vauxn_voltages), - .volt_table = ldo_vauxn_voltages, - }, - .load_lp_uA = 5000, - .update_bank = 0x04, - .update_reg = 0x09, - .update_mask = 0x03, - .update_val = 0x01, - .update_val_idle = 0x03, - .update_val_normal = 0x01, - .voltage_bank = 0x04, - .voltage_reg = 0x1f, - .voltage_mask = 0x0f, - }, - [AB9540_LDO_AUX2] = { - .desc = { - .name = "LDO-AUX2", - .ops = &ab8500_regulator_volt_mode_ops, - .type = REGULATOR_VOLTAGE, - .id = AB9540_LDO_AUX2, - .owner = THIS_MODULE, - .n_voltages = ARRAY_SIZE(ldo_vauxn_voltages), - .volt_table = ldo_vauxn_voltages, - }, - .load_lp_uA = 5000, - .update_bank = 0x04, - .update_reg = 0x09, - .update_mask = 0x0c, - .update_val = 0x04, - .update_val_idle = 0x0c, - .update_val_normal = 0x04, - .voltage_bank = 0x04, - .voltage_reg = 0x20, - .voltage_mask = 0x0f, - }, - [AB9540_LDO_AUX3] = { - .desc = { - .name = "LDO-AUX3", - .ops = &ab8500_regulator_volt_mode_ops, - .type = REGULATOR_VOLTAGE, - .id = AB9540_LDO_AUX3, - .owner = THIS_MODULE, - .n_voltages = ARRAY_SIZE(ldo_vaux3_voltages), - .volt_table = ldo_vaux3_voltages, - }, - .load_lp_uA = 5000, - .update_bank = 0x04, - .update_reg = 0x0a, - .update_mask = 0x03, - .update_val = 0x01, - .update_val_idle = 0x03, - .update_val_normal = 0x01, - .voltage_bank = 0x04, - .voltage_reg = 0x21, - .voltage_mask = 0x07, - }, - [AB9540_LDO_AUX4] = { - .desc = { - .name = "LDO-AUX4", - .ops = &ab8500_regulator_volt_mode_ops, - .type = REGULATOR_VOLTAGE, - .id = AB9540_LDO_AUX4, - .owner = THIS_MODULE, - .n_voltages = ARRAY_SIZE(ldo_vauxn_voltages), - .volt_table = ldo_vauxn_voltages, - }, - .load_lp_uA = 5000, - /* values for Vaux4Regu register */ - .update_bank = 0x04, - .update_reg = 0x2e, - .update_mask = 0x03, - .update_val = 0x01, - .update_val_idle = 0x03, - .update_val_normal = 0x01, - /* values for Vaux4SEL register */ - .voltage_bank = 0x04, - .voltage_reg = 0x2f, - .voltage_mask = 0x0f, - }, - [AB9540_LDO_INTCORE] = { - .desc = { - .name = "LDO-INTCORE", - .ops = &ab8500_regulator_volt_mode_ops, - .type = REGULATOR_VOLTAGE, - .id = AB9540_LDO_INTCORE, - .owner = THIS_MODULE, - .n_voltages = ARRAY_SIZE(ldo_vintcore_voltages), - .volt_table = ldo_vintcore_voltages, - }, - .load_lp_uA = 5000, - .update_bank = 0x03, - .update_reg = 0x80, - .update_mask = 0x44, - .update_val = 0x44, - .update_val_idle = 0x44, - .update_val_normal = 0x04, - .voltage_bank = 0x03, - .voltage_reg = 0x80, - .voltage_mask = 0x38, - }, - - /* - * Fixed Voltage Regulators - * name, fixed mV, - * update bank, reg, mask, enable val - */ - [AB9540_LDO_TVOUT] = { - .desc = { - .name = "LDO-TVOUT", - .ops = &ab8500_regulator_mode_ops, - .type = REGULATOR_VOLTAGE, - .id = AB9540_LDO_TVOUT, - .owner = THIS_MODULE, - .n_voltages = 1, - .volt_table = fixed_2000000_voltage, - .enable_time = 10000, - }, - .load_lp_uA = 1000, - .update_bank = 0x03, - .update_reg = 0x80, - .update_mask = 0x82, - .update_val = 0x02, - .update_val_idle = 0x82, - .update_val_normal = 0x02, - }, - [AB9540_LDO_USB] = { - .desc = { - .name = "LDO-USB", - .ops = &ab8500_regulator_ops, - .type = REGULATOR_VOLTAGE, - .id = AB9540_LDO_USB, - .owner = THIS_MODULE, - .n_voltages = 1, - .volt_table = fixed_3300000_voltage, - }, - .update_bank = 0x03, - .update_reg = 0x82, - .update_mask = 0x03, - .update_val = 0x01, - .update_val_idle = 0x03, - .update_val_normal = 0x01, - }, - [AB9540_LDO_AUDIO] = { - .desc = { - .name = "LDO-AUDIO", - .ops = &ab8500_regulator_ops, - .type = REGULATOR_VOLTAGE, - .id = AB9540_LDO_AUDIO, - .owner = THIS_MODULE, - .n_voltages = 1, - .volt_table = fixed_2000000_voltage, - }, - .update_bank = 0x03, - .update_reg = 0x83, - .update_mask = 0x02, - .update_val = 0x02, - }, - [AB9540_LDO_ANAMIC1] = { - .desc = { - .name = "LDO-ANAMIC1", - .ops = &ab8500_regulator_ops, - .type = REGULATOR_VOLTAGE, - .id = AB9540_LDO_ANAMIC1, - .owner = THIS_MODULE, - .n_voltages = 1, - .volt_table = fixed_2050000_voltage, - }, - .update_bank = 0x03, - .update_reg = 0x83, - .update_mask = 0x08, - .update_val = 0x08, - }, - [AB9540_LDO_ANAMIC2] = { - .desc = { - .name = "LDO-ANAMIC2", - .ops = &ab8500_regulator_ops, - .type = REGULATOR_VOLTAGE, - .id = AB9540_LDO_ANAMIC2, - .owner = THIS_MODULE, - .n_voltages = 1, - .volt_table = fixed_2050000_voltage, - }, - .update_bank = 0x03, - .update_reg = 0x83, - .update_mask = 0x10, - .update_val = 0x10, - }, - [AB9540_LDO_DMIC] = { - .desc = { - .name = "LDO-DMIC", - .ops = &ab8500_regulator_ops, - .type = REGULATOR_VOLTAGE, - .id = AB9540_LDO_DMIC, - .owner = THIS_MODULE, - .n_voltages = 1, - .volt_table = fixed_1800000_voltage, - }, - .update_bank = 0x03, - .update_reg = 0x83, - .update_mask = 0x04, - .update_val = 0x04, - }, - - /* - * Regulators with fixed voltage and normal/idle modes - */ - [AB9540_LDO_ANA] = { - .desc = { - .name = "LDO-ANA", - .ops = &ab8500_regulator_mode_ops, - .type = REGULATOR_VOLTAGE, - .id = AB9540_LDO_ANA, - .owner = THIS_MODULE, - .n_voltages = 1, - .volt_table = fixed_1200000_voltage, - }, - .load_lp_uA = 1000, - .update_bank = 0x04, - .update_reg = 0x06, - .update_mask = 0x0c, - .update_val = 0x08, - .update_val_idle = 0x0c, - .update_val_normal = 0x08, - }, -}; - -/* AB8540 regulator information */ -static struct ab8500_regulator_info - ab8540_regulator_info[AB8540_NUM_REGULATORS] = { - /* - * Variable Voltage Regulators - * name, min mV, max mV, - * update bank, reg, mask, enable val - * volt bank, reg, mask - */ - [AB8540_LDO_AUX1] = { - .desc = { - .name = "LDO-AUX1", - .ops = &ab8500_regulator_volt_mode_ops, - .type = REGULATOR_VOLTAGE, - .id = AB8540_LDO_AUX1, - .owner = THIS_MODULE, - .n_voltages = ARRAY_SIZE(ldo_vauxn_voltages), - .volt_table = ldo_vauxn_voltages, - }, - .load_lp_uA = 5000, - .update_bank = 0x04, - .update_reg = 0x09, - .update_mask = 0x03, - .update_val = 0x01, - .update_val_idle = 0x03, - .update_val_normal = 0x01, - .voltage_bank = 0x04, - .voltage_reg = 0x1f, - .voltage_mask = 0x0f, - }, - [AB8540_LDO_AUX2] = { - .desc = { - .name = "LDO-AUX2", - .ops = &ab8500_regulator_volt_mode_ops, - .type = REGULATOR_VOLTAGE, - .id = AB8540_LDO_AUX2, - .owner = THIS_MODULE, - .n_voltages = ARRAY_SIZE(ldo_vauxn_voltages), - .volt_table = ldo_vauxn_voltages, - }, - .load_lp_uA = 5000, - .update_bank = 0x04, - .update_reg = 0x09, - .update_mask = 0x0c, - .update_val = 0x04, - .update_val_idle = 0x0c, - .update_val_normal = 0x04, - .voltage_bank = 0x04, - .voltage_reg = 0x20, - .voltage_mask = 0x0f, - }, - [AB8540_LDO_AUX3] = { - .desc = { - .name = "LDO-AUX3", - .ops = &ab8540_aux3_regulator_volt_mode_ops, - .type = REGULATOR_VOLTAGE, - .id = AB8540_LDO_AUX3, - .owner = THIS_MODULE, - .n_voltages = ARRAY_SIZE(ldo_vaux3_ab8540_voltages), - .volt_table = ldo_vaux3_ab8540_voltages, - }, - .load_lp_uA = 5000, - .update_bank = 0x04, - .update_reg = 0x0a, - .update_mask = 0x03, - .update_val = 0x01, - .update_val_idle = 0x03, - .update_val_normal = 0x01, - .voltage_bank = 0x04, - .voltage_reg = 0x21, - .voltage_mask = 0x07, - .expand_register = { - .voltage_limit = 8, - .voltage_bank = 0x04, - .voltage_reg = 0x01, - .voltage_mask = 0x10, - } - }, - [AB8540_LDO_AUX4] = { - .desc = { - .name = "LDO-AUX4", - .ops = &ab8500_regulator_volt_mode_ops, - .type = REGULATOR_VOLTAGE, - .id = AB8540_LDO_AUX4, - .owner = THIS_MODULE, - .n_voltages = ARRAY_SIZE(ldo_vauxn_voltages), - .volt_table = ldo_vauxn_voltages, - }, - .load_lp_uA = 5000, - /* values for Vaux4Regu register */ - .update_bank = 0x04, - .update_reg = 0x2e, - .update_mask = 0x03, - .update_val = 0x01, - .update_val_idle = 0x03, - .update_val_normal = 0x01, - /* values for Vaux4SEL register */ - .voltage_bank = 0x04, - .voltage_reg = 0x2f, - .voltage_mask = 0x0f, - }, - [AB8540_LDO_AUX5] = { - .desc = { - .name = "LDO-AUX5", - .ops = &ab8500_regulator_volt_mode_ops, - .type = REGULATOR_VOLTAGE, - .id = AB8540_LDO_AUX5, - .owner = THIS_MODULE, - .n_voltages = ARRAY_SIZE(ldo_vaux56_ab8540_voltages), - .volt_table = ldo_vaux56_ab8540_voltages, - }, - .load_lp_uA = 20000, - /* values for Vaux5Regu register */ - .update_bank = 0x04, - .update_reg = 0x32, - .update_mask = 0x03, - .update_val = 0x01, - .update_val_idle = 0x03, - .update_val_normal = 0x01, - /* values for Vaux5SEL register */ - .voltage_bank = 0x04, - .voltage_reg = 0x33, - .voltage_mask = 0x3f, - }, - [AB8540_LDO_AUX6] = { - .desc = { - .name = "LDO-AUX6", - .ops = &ab8500_regulator_volt_mode_ops, - .type = REGULATOR_VOLTAGE, - .id = AB8540_LDO_AUX6, - .owner = THIS_MODULE, - .n_voltages = ARRAY_SIZE(ldo_vaux56_ab8540_voltages), - .volt_table = ldo_vaux56_ab8540_voltages, - }, - .load_lp_uA = 20000, - /* values for Vaux6Regu register */ - .update_bank = 0x04, - .update_reg = 0x35, - .update_mask = 0x03, - .update_val = 0x01, - .update_val_idle = 0x03, - .update_val_normal = 0x01, - /* values for Vaux6SEL register */ - .voltage_bank = 0x04, - .voltage_reg = 0x36, - .voltage_mask = 0x3f, - }, - [AB8540_LDO_INTCORE] = { - .desc = { - .name = "LDO-INTCORE", - .ops = &ab8500_regulator_volt_mode_ops, - .type = REGULATOR_VOLTAGE, - .id = AB8540_LDO_INTCORE, - .owner = THIS_MODULE, - .n_voltages = ARRAY_SIZE(ldo_vintcore_voltages), - .volt_table = ldo_vintcore_voltages, - }, - .load_lp_uA = 5000, - .update_bank = 0x03, - .update_reg = 0x80, - .update_mask = 0x44, - .update_val = 0x44, - .update_val_idle = 0x44, - .update_val_normal = 0x04, - .voltage_bank = 0x03, - .voltage_reg = 0x80, - .voltage_mask = 0x38, - }, - - /* - * Fixed Voltage Regulators - * name, fixed mV, - * update bank, reg, mask, enable val - */ - [AB8540_LDO_TVOUT] = { - .desc = { - .name = "LDO-TVOUT", - .ops = &ab8500_regulator_mode_ops, - .type = REGULATOR_VOLTAGE, - .id = AB8540_LDO_TVOUT, - .owner = THIS_MODULE, - .n_voltages = 1, - .volt_table = fixed_2000000_voltage, - .enable_time = 10000, - }, - .load_lp_uA = 1000, - .update_bank = 0x03, - .update_reg = 0x80, - .update_mask = 0x82, - .update_val = 0x02, - .update_val_idle = 0x82, - .update_val_normal = 0x02, - }, - [AB8540_LDO_AUDIO] = { - .desc = { - .name = "LDO-AUDIO", - .ops = &ab8500_regulator_ops, - .type = REGULATOR_VOLTAGE, - .id = AB8540_LDO_AUDIO, - .owner = THIS_MODULE, - .n_voltages = 1, - .volt_table = fixed_2000000_voltage, - }, - .update_bank = 0x03, - .update_reg = 0x83, - .update_mask = 0x02, - .update_val = 0x02, - }, - [AB8540_LDO_ANAMIC1] = { - .desc = { - .name = "LDO-ANAMIC1", - .ops = &ab8500_regulator_anamic_mode_ops, - .type = REGULATOR_VOLTAGE, - .id = AB8540_LDO_ANAMIC1, - .owner = THIS_MODULE, - .n_voltages = 1, - .volt_table = fixed_2050000_voltage, - }, - .shared_mode = &ab8540_ldo_anamic1_shared, - .update_bank = 0x03, - .update_reg = 0x83, - .update_mask = 0x08, - .update_val = 0x08, - .mode_bank = 0x03, - .mode_reg = 0x83, - .mode_mask = 0x20, - .mode_val_idle = 0x20, - .mode_val_normal = 0x00, - }, - [AB8540_LDO_ANAMIC2] = { - .desc = { - .name = "LDO-ANAMIC2", - .ops = &ab8500_regulator_anamic_mode_ops, - .type = REGULATOR_VOLTAGE, - .id = AB8540_LDO_ANAMIC2, - .owner = THIS_MODULE, - .n_voltages = 1, - .volt_table = fixed_2050000_voltage, - }, - .shared_mode = &ab8540_ldo_anamic2_shared, - .update_bank = 0x03, - .update_reg = 0x83, - .update_mask = 0x10, - .update_val = 0x10, - .mode_bank = 0x03, - .mode_reg = 0x83, - .mode_mask = 0x20, - .mode_val_idle = 0x20, - .mode_val_normal = 0x00, - }, - [AB8540_LDO_DMIC] = { - .desc = { - .name = "LDO-DMIC", - .ops = &ab8500_regulator_volt_mode_ops, - .type = REGULATOR_VOLTAGE, - .id = AB8540_LDO_DMIC, - .owner = THIS_MODULE, - .n_voltages = ARRAY_SIZE(ldo_vdmic_voltages), - .volt_table = ldo_vdmic_voltages, - }, - .load_lp_uA = 1000, - .update_bank = 0x03, - .update_reg = 0x83, - .update_mask = 0x04, - .update_val = 0x04, - .voltage_bank = 0x03, - .voltage_reg = 0x83, - .voltage_mask = 0xc0, - }, - - /* - * Regulators with fixed voltage and normal/idle modes - */ - [AB8540_LDO_ANA] = { - .desc = { - .name = "LDO-ANA", - .ops = &ab8500_regulator_mode_ops, - .type = REGULATOR_VOLTAGE, - .id = AB8540_LDO_ANA, - .owner = THIS_MODULE, - .n_voltages = 1, - .volt_table = fixed_1200000_voltage, - }, - .load_lp_uA = 1000, - .update_bank = 0x04, - .update_reg = 0x06, - .update_mask = 0x0c, - .update_val = 0x04, - .update_val_idle = 0x0c, - .update_val_normal = 0x04, - }, - [AB8540_LDO_SDIO] = { - .desc = { - .name = "LDO-SDIO", - .ops = &ab8500_regulator_volt_mode_ops, - .type = REGULATOR_VOLTAGE, - .id = AB8540_LDO_SDIO, - .owner = THIS_MODULE, - .n_voltages = ARRAY_SIZE(ldo_sdio_voltages), - .volt_table = ldo_sdio_voltages, - }, - .load_lp_uA = 5000, - .update_bank = 0x03, - .update_reg = 0x88, - .update_mask = 0x30, - .update_val = 0x10, - .update_val_idle = 0x30, - .update_val_normal = 0x10, - .voltage_bank = 0x03, - .voltage_reg = 0x88, - .voltage_mask = 0x07, - }, -}; - static struct ab8500_shared_mode ldo_anamic1_shared = { .shared_regulator = &ab8505_regulator_info[AB8505_LDO_ANAMIC2], }; @@ -1781,14 +1082,6 @@ static struct ab8500_shared_mode ldo_anamic2_shared = { .shared_regulator = &ab8505_regulator_info[AB8505_LDO_ANAMIC1], }; -static struct ab8500_shared_mode ab8540_ldo_anamic1_shared = { - .shared_regulator = &ab8540_regulator_info[AB8540_LDO_ANAMIC2], -}; - -static struct ab8500_shared_mode ab8540_ldo_anamic2_shared = { - .shared_regulator = &ab8540_regulator_info[AB8540_LDO_ANAMIC1], -}; - struct ab8500_reg_init { u8 bank; u8 addr; @@ -2243,659 +1536,6 @@ static struct ab8500_reg_init ab8505_reg_init[] = { REG_INIT(AB8505_CTRLVAUX6, 0x01, 0x56, 0x9f), }; -/* AB9540 register init */ -static struct ab8500_reg_init ab9540_reg_init[] = { - /* - * 0x03, VarmRequestCtrl - * 0x0c, VapeRequestCtrl - * 0x30, Vsmps1RequestCtrl - * 0xc0, Vsmps2RequestCtrl - */ - REG_INIT(AB9540_REGUREQUESTCTRL1, 0x03, 0x03, 0xff), - /* - * 0x03, Vsmps3RequestCtrl - * 0x0c, VpllRequestCtrl - * 0x30, VanaRequestCtrl - * 0xc0, VextSupply1RequestCtrl - */ - REG_INIT(AB9540_REGUREQUESTCTRL2, 0x03, 0x04, 0xff), - /* - * 0x03, VextSupply2RequestCtrl - * 0x0c, VextSupply3RequestCtrl - * 0x30, Vaux1RequestCtrl - * 0xc0, Vaux2RequestCtrl - */ - REG_INIT(AB9540_REGUREQUESTCTRL3, 0x03, 0x05, 0xff), - /* - * 0x03, Vaux3RequestCtrl - * 0x04, SwHPReq - */ - REG_INIT(AB9540_REGUREQUESTCTRL4, 0x03, 0x06, 0x07), - /* - * 0x01, Vsmps1SysClkReq1HPValid - * 0x02, Vsmps2SysClkReq1HPValid - * 0x04, Vsmps3SysClkReq1HPValid - * 0x08, VanaSysClkReq1HPValid - * 0x10, VpllSysClkReq1HPValid - * 0x20, Vaux1SysClkReq1HPValid - * 0x40, Vaux2SysClkReq1HPValid - * 0x80, Vaux3SysClkReq1HPValid - */ - REG_INIT(AB9540_REGUSYSCLKREQ1HPVALID1, 0x03, 0x07, 0xff), - /* - * 0x01, VapeSysClkReq1HPValid - * 0x02, VarmSysClkReq1HPValid - * 0x04, VbbSysClkReq1HPValid - * 0x08, VmodSysClkReq1HPValid - * 0x10, VextSupply1SysClkReq1HPValid - * 0x20, VextSupply2SysClkReq1HPValid - * 0x40, VextSupply3SysClkReq1HPValid - */ - REG_INIT(AB9540_REGUSYSCLKREQ1HPVALID2, 0x03, 0x08, 0x7f), - /* - * 0x01, Vsmps1HwHPReq1Valid - * 0x02, Vsmps2HwHPReq1Valid - * 0x04, Vsmps3HwHPReq1Valid - * 0x08, VanaHwHPReq1Valid - * 0x10, VpllHwHPReq1Valid - * 0x20, Vaux1HwHPReq1Valid - * 0x40, Vaux2HwHPReq1Valid - * 0x80, Vaux3HwHPReq1Valid - */ - REG_INIT(AB9540_REGUHWHPREQ1VALID1, 0x03, 0x09, 0xff), - /* - * 0x01, VextSupply1HwHPReq1Valid - * 0x02, VextSupply2HwHPReq1Valid - * 0x04, VextSupply3HwHPReq1Valid - * 0x08, VmodHwHPReq1Valid - */ - REG_INIT(AB9540_REGUHWHPREQ1VALID2, 0x03, 0x0a, 0x0f), - /* - * 0x01, Vsmps1HwHPReq2Valid - * 0x02, Vsmps2HwHPReq2Valid - * 0x03, Vsmps3HwHPReq2Valid - * 0x08, VanaHwHPReq2Valid - * 0x10, VpllHwHPReq2Valid - * 0x20, Vaux1HwHPReq2Valid - * 0x40, Vaux2HwHPReq2Valid - * 0x80, Vaux3HwHPReq2Valid - */ - REG_INIT(AB9540_REGUHWHPREQ2VALID1, 0x03, 0x0b, 0xff), - /* - * 0x01, VextSupply1HwHPReq2Valid - * 0x02, VextSupply2HwHPReq2Valid - * 0x04, VextSupply3HwHPReq2Valid - * 0x08, VmodHwHPReq2Valid - */ - REG_INIT(AB9540_REGUHWHPREQ2VALID2, 0x03, 0x0c, 0x0f), - /* - * 0x01, VapeSwHPReqValid - * 0x02, VarmSwHPReqValid - * 0x04, Vsmps1SwHPReqValid - * 0x08, Vsmps2SwHPReqValid - * 0x10, Vsmps3SwHPReqValid - * 0x20, VanaSwHPReqValid - * 0x40, VpllSwHPReqValid - * 0x80, Vaux1SwHPReqValid - */ - REG_INIT(AB9540_REGUSWHPREQVALID1, 0x03, 0x0d, 0xff), - /* - * 0x01, Vaux2SwHPReqValid - * 0x02, Vaux3SwHPReqValid - * 0x04, VextSupply1SwHPReqValid - * 0x08, VextSupply2SwHPReqValid - * 0x10, VextSupply3SwHPReqValid - * 0x20, VmodSwHPReqValid - */ - REG_INIT(AB9540_REGUSWHPREQVALID2, 0x03, 0x0e, 0x3f), - /* - * 0x02, SysClkReq2Valid1 - * ... - * 0x80, SysClkReq8Valid1 - */ - REG_INIT(AB9540_REGUSYSCLKREQVALID1, 0x03, 0x0f, 0xfe), - /* - * 0x02, SysClkReq2Valid2 - * ... - * 0x80, SysClkReq8Valid2 - */ - REG_INIT(AB9540_REGUSYSCLKREQVALID2, 0x03, 0x10, 0xfe), - /* - * 0x01, Vaux4SwHPReqValid - * 0x02, Vaux4HwHPReq2Valid - * 0x04, Vaux4HwHPReq1Valid - * 0x08, Vaux4SysClkReq1HPValid - */ - REG_INIT(AB9540_REGUVAUX4REQVALID, 0x03, 0x11, 0x0f), - /* - * 0x02, VTVoutEna - * 0x04, Vintcore12Ena - * 0x38, Vintcore12Sel - * 0x40, Vintcore12LP - * 0x80, VTVoutLP - */ - REG_INIT(AB9540_REGUMISC1, 0x03, 0x80, 0xfe), - /* - * 0x02, VaudioEna - * 0x04, VdmicEna - * 0x08, Vamic1Ena - * 0x10, Vamic2Ena - */ - REG_INIT(AB9540_VAUDIOSUPPLY, 0x03, 0x83, 0x1e), - /* - * 0x01, Vamic1_dzout - * 0x02, Vamic2_dzout - */ - REG_INIT(AB9540_REGUCTRL1VAMIC, 0x03, 0x84, 0x03), - /* - * 0x03, Vsmps1Regu - * 0x0c, Vsmps1SelCtrl - * 0x10, Vsmps1AutoMode - * 0x20, Vsmps1PWMMode - */ - REG_INIT(AB9540_VSMPS1REGU, 0x04, 0x03, 0x3f), - /* - * 0x03, Vsmps2Regu - * 0x0c, Vsmps2SelCtrl - * 0x10, Vsmps2AutoMode - * 0x20, Vsmps2PWMMode - */ - REG_INIT(AB9540_VSMPS2REGU, 0x04, 0x04, 0x3f), - /* - * 0x03, Vsmps3Regu - * 0x0c, Vsmps3SelCtrl - * NOTE! PRCMU register - */ - REG_INIT(AB9540_VSMPS3REGU, 0x04, 0x05, 0x0f), - /* - * 0x03, VpllRegu - * 0x0c, VanaRegu - */ - REG_INIT(AB9540_VPLLVANAREGU, 0x04, 0x06, 0x0f), - /* - * 0x03, VextSupply1Regu - * 0x0c, VextSupply2Regu - * 0x30, VextSupply3Regu - * 0x40, ExtSupply2Bypass - * 0x80, ExtSupply3Bypass - */ - REG_INIT(AB9540_EXTSUPPLYREGU, 0x04, 0x08, 0xff), - /* - * 0x03, Vaux1Regu - * 0x0c, Vaux2Regu - */ - REG_INIT(AB9540_VAUX12REGU, 0x04, 0x09, 0x0f), - /* - * 0x0c, Vrf1Regu - * 0x03, Vaux3Regu - */ - REG_INIT(AB9540_VRF1VAUX3REGU, 0x04, 0x0a, 0x0f), - /* - * 0x3f, Vsmps1Sel1 - */ - REG_INIT(AB9540_VSMPS1SEL1, 0x04, 0x13, 0x3f), - /* - * 0x3f, Vsmps1Sel2 - */ - REG_INIT(AB9540_VSMPS1SEL2, 0x04, 0x14, 0x3f), - /* - * 0x3f, Vsmps1Sel3 - */ - REG_INIT(AB9540_VSMPS1SEL3, 0x04, 0x15, 0x3f), - /* - * 0x3f, Vsmps2Sel1 - */ - REG_INIT(AB9540_VSMPS2SEL1, 0x04, 0x17, 0x3f), - /* - * 0x3f, Vsmps2Sel2 - */ - REG_INIT(AB9540_VSMPS2SEL2, 0x04, 0x18, 0x3f), - /* - * 0x3f, Vsmps2Sel3 - */ - REG_INIT(AB9540_VSMPS2SEL3, 0x04, 0x19, 0x3f), - /* - * 0x7f, Vsmps3Sel1 - * NOTE! PRCMU register - */ - REG_INIT(AB9540_VSMPS3SEL1, 0x04, 0x1b, 0x7f), - /* - * 0x7f, Vsmps3Sel2 - * NOTE! PRCMU register - */ - REG_INIT(AB9540_VSMPS3SEL2, 0x04, 0x1c, 0x7f), - /* - * 0x0f, Vaux1Sel - */ - REG_INIT(AB9540_VAUX1SEL, 0x04, 0x1f, 0x0f), - /* - * 0x0f, Vaux2Sel - */ - REG_INIT(AB9540_VAUX2SEL, 0x04, 0x20, 0x0f), - /* - * 0x07, Vaux3Sel - * 0x30, Vrf1Sel - */ - REG_INIT(AB9540_VRF1VAUX3SEL, 0x04, 0x21, 0x37), - /* - * 0x01, VextSupply12LP - */ - REG_INIT(AB9540_REGUCTRL2SPARE, 0x04, 0x22, 0x01), - /* - * 0x03, Vaux4RequestCtrl - */ - REG_INIT(AB9540_VAUX4REQCTRL, 0x04, 0x2d, 0x03), - /* - * 0x03, Vaux4Regu - */ - REG_INIT(AB9540_VAUX4REGU, 0x04, 0x2e, 0x03), - /* - * 0x08, Vaux4Sel - */ - REG_INIT(AB9540_VAUX4SEL, 0x04, 0x2f, 0x0f), - /* - * 0x01, VpllDisch - * 0x02, Vrf1Disch - * 0x04, Vaux1Disch - * 0x08, Vaux2Disch - * 0x10, Vaux3Disch - * 0x20, Vintcore12Disch - * 0x40, VTVoutDisch - * 0x80, VaudioDisch - */ - REG_INIT(AB9540_REGUCTRLDISCH, 0x04, 0x43, 0xff), - /* - * 0x01, VsimDisch - * 0x02, VanaDisch - * 0x04, VdmicPullDownEna - * 0x08, VpllPullDownEna - * 0x10, VdmicDisch - */ - REG_INIT(AB9540_REGUCTRLDISCH2, 0x04, 0x44, 0x1f), - /* - * 0x01, Vaux4Disch - */ - REG_INIT(AB9540_REGUCTRLDISCH3, 0x04, 0x48, 0x01), -}; - -/* AB8540 register init */ -static struct ab8500_reg_init ab8540_reg_init[] = { - /* - * 0x01, VSimSycClkReq1Valid - * 0x02, VSimSycClkReq2Valid - * 0x04, VSimSycClkReq3Valid - * 0x08, VSimSycClkReq4Valid - * 0x10, VSimSycClkReq5Valid - * 0x20, VSimSycClkReq6Valid - * 0x40, VSimSycClkReq7Valid - * 0x80, VSimSycClkReq8Valid - */ - REG_INIT(AB8540_VSIMSYSCLKCTRL, 0x02, 0x33, 0xff), - /* - * 0x03, VarmRequestCtrl - * 0x0c, VapeRequestCtrl - * 0x30, Vsmps1RequestCtrl - * 0xc0, Vsmps2RequestCtrl - */ - REG_INIT(AB8540_REGUREQUESTCTRL1, 0x03, 0x03, 0xff), - /* - * 0x03, Vsmps3RequestCtrl - * 0x0c, VpllRequestCtrl - * 0x30, VanaRequestCtrl - * 0xc0, VextSupply1RequestCtrl - */ - REG_INIT(AB8540_REGUREQUESTCTRL2, 0x03, 0x04, 0xff), - /* - * 0x03, VextSupply2RequestCtrl - * 0x0c, VextSupply3RequestCtrl - * 0x30, Vaux1RequestCtrl - * 0xc0, Vaux2RequestCtrl - */ - REG_INIT(AB8540_REGUREQUESTCTRL3, 0x03, 0x05, 0xff), - /* - * 0x03, Vaux3RequestCtrl - * 0x04, SwHPReq - */ - REG_INIT(AB8540_REGUREQUESTCTRL4, 0x03, 0x06, 0x07), - /* - * 0x01, Vsmps1SysClkReq1HPValid - * 0x02, Vsmps2SysClkReq1HPValid - * 0x04, Vsmps3SysClkReq1HPValid - * 0x08, VanaSysClkReq1HPValid - * 0x10, VpllSysClkReq1HPValid - * 0x20, Vaux1SysClkReq1HPValid - * 0x40, Vaux2SysClkReq1HPValid - * 0x80, Vaux3SysClkReq1HPValid - */ - REG_INIT(AB8540_REGUSYSCLKREQ1HPVALID1, 0x03, 0x07, 0xff), - /* - * 0x01, VapeSysClkReq1HPValid - * 0x02, VarmSysClkReq1HPValid - * 0x04, VbbSysClkReq1HPValid - * 0x10, VextSupply1SysClkReq1HPValid - * 0x20, VextSupply2SysClkReq1HPValid - * 0x40, VextSupply3SysClkReq1HPValid - */ - REG_INIT(AB8540_REGUSYSCLKREQ1HPVALID2, 0x03, 0x08, 0x77), - /* - * 0x01, Vsmps1HwHPReq1Valid - * 0x02, Vsmps2HwHPReq1Valid - * 0x04, Vsmps3HwHPReq1Valid - * 0x08, VanaHwHPReq1Valid - * 0x10, VpllHwHPReq1Valid - * 0x20, Vaux1HwHPReq1Valid - * 0x40, Vaux2HwHPReq1Valid - * 0x80, Vaux3HwHPReq1Valid - */ - REG_INIT(AB8540_REGUHWHPREQ1VALID1, 0x03, 0x09, 0xff), - /* - * 0x01, VextSupply1HwHPReq1Valid - * 0x02, VextSupply2HwHPReq1Valid - * 0x04, VextSupply3HwHPReq1Valid - */ - REG_INIT(AB8540_REGUHWHPREQ1VALID2, 0x03, 0x0a, 0x07), - /* - * 0x01, Vsmps1HwHPReq2Valid - * 0x02, Vsmps2HwHPReq2Valid - * 0x03, Vsmps3HwHPReq2Valid - * 0x08, VanaHwHPReq2Valid - * 0x10, VpllHwHPReq2Valid - * 0x20, Vaux1HwHPReq2Valid - * 0x40, Vaux2HwHPReq2Valid - * 0x80, Vaux3HwHPReq2Valid - */ - REG_INIT(AB8540_REGUHWHPREQ2VALID1, 0x03, 0x0b, 0xff), - /* - * 0x01, VextSupply1HwHPReq2Valid - * 0x02, VextSupply2HwHPReq2Valid - * 0x04, VextSupply3HwHPReq2Valid - */ - REG_INIT(AB8540_REGUHWHPREQ2VALID2, 0x03, 0x0c, 0x07), - /* - * 0x01, VapeSwHPReqValid - * 0x02, VarmSwHPReqValid - * 0x04, Vsmps1SwHPReqValid - * 0x08, Vsmps2SwHPReqValid - * 0x10, Vsmps3SwHPReqValid - * 0x20, VanaSwHPReqValid - * 0x40, VpllSwHPReqValid - * 0x80, Vaux1SwHPReqValid - */ - REG_INIT(AB8540_REGUSWHPREQVALID1, 0x03, 0x0d, 0xff), - /* - * 0x01, Vaux2SwHPReqValid - * 0x02, Vaux3SwHPReqValid - * 0x04, VextSupply1SwHPReqValid - * 0x08, VextSupply2SwHPReqValid - * 0x10, VextSupply3SwHPReqValid - */ - REG_INIT(AB8540_REGUSWHPREQVALID2, 0x03, 0x0e, 0x1f), - /* - * 0x02, SysClkReq2Valid1 - * ... - * 0x80, SysClkReq8Valid1 - */ - REG_INIT(AB8540_REGUSYSCLKREQVALID1, 0x03, 0x0f, 0xff), - /* - * 0x02, SysClkReq2Valid2 - * ... - * 0x80, SysClkReq8Valid2 - */ - REG_INIT(AB8540_REGUSYSCLKREQVALID2, 0x03, 0x10, 0xff), - /* - * 0x01, Vaux4SwHPReqValid - * 0x02, Vaux4HwHPReq2Valid - * 0x04, Vaux4HwHPReq1Valid - * 0x08, Vaux4SysClkReq1HPValid - */ - REG_INIT(AB8540_REGUVAUX4REQVALID, 0x03, 0x11, 0x0f), - /* - * 0x01, Vaux5SwHPReqValid - * 0x02, Vaux5HwHPReq2Valid - * 0x04, Vaux5HwHPReq1Valid - * 0x08, Vaux5SysClkReq1HPValid - */ - REG_INIT(AB8540_REGUVAUX5REQVALID, 0x03, 0x12, 0x0f), - /* - * 0x01, Vaux6SwHPReqValid - * 0x02, Vaux6HwHPReq2Valid - * 0x04, Vaux6HwHPReq1Valid - * 0x08, Vaux6SysClkReq1HPValid - */ - REG_INIT(AB8540_REGUVAUX6REQVALID, 0x03, 0x13, 0x0f), - /* - * 0x01, VclkbSwHPReqValid - * 0x02, VclkbHwHPReq2Valid - * 0x04, VclkbHwHPReq1Valid - * 0x08, VclkbSysClkReq1HPValid - */ - REG_INIT(AB8540_REGUVCLKBREQVALID, 0x03, 0x14, 0x0f), - /* - * 0x01, Vrf1SwHPReqValid - * 0x02, Vrf1HwHPReq2Valid - * 0x04, Vrf1HwHPReq1Valid - * 0x08, Vrf1SysClkReq1HPValid - */ - REG_INIT(AB8540_REGUVRF1REQVALID, 0x03, 0x15, 0x0f), - /* - * 0x02, VTVoutEna - * 0x04, Vintcore12Ena - * 0x38, Vintcore12Sel - * 0x40, Vintcore12LP - * 0x80, VTVoutLP - */ - REG_INIT(AB8540_REGUMISC1, 0x03, 0x80, 0xfe), - /* - * 0x02, VaudioEna - * 0x04, VdmicEna - * 0x08, Vamic1Ena - * 0x10, Vamic2Ena - * 0x20, Vamic12LP - * 0xC0, VdmicSel - */ - REG_INIT(AB8540_VAUDIOSUPPLY, 0x03, 0x83, 0xfe), - /* - * 0x01, Vamic1_dzout - * 0x02, Vamic2_dzout - */ - REG_INIT(AB8540_REGUCTRL1VAMIC, 0x03, 0x84, 0x03), - /* - * 0x07, VHSICSel - * 0x08, VHSICOffState - * 0x10, VHSIEna - * 0x20, VHSICLP - */ - REG_INIT(AB8540_VHSIC, 0x03, 0x87, 0x3f), - /* - * 0x07, VSDIOSel - * 0x08, VSDIOOffState - * 0x10, VSDIOEna - * 0x20, VSDIOLP - */ - REG_INIT(AB8540_VSDIO, 0x03, 0x88, 0x3f), - /* - * 0x03, Vsmps1Regu - * 0x0c, Vsmps1SelCtrl - * 0x10, Vsmps1AutoMode - * 0x20, Vsmps1PWMMode - */ - REG_INIT(AB8540_VSMPS1REGU, 0x04, 0x03, 0x3f), - /* - * 0x03, Vsmps2Regu - * 0x0c, Vsmps2SelCtrl - * 0x10, Vsmps2AutoMode - * 0x20, Vsmps2PWMMode - */ - REG_INIT(AB8540_VSMPS2REGU, 0x04, 0x04, 0x3f), - /* - * 0x03, Vsmps3Regu - * 0x0c, Vsmps3SelCtrl - * 0x10, Vsmps3AutoMode - * 0x20, Vsmps3PWMMode - * NOTE! PRCMU register - */ - REG_INIT(AB8540_VSMPS3REGU, 0x04, 0x05, 0x0f), - /* - * 0x03, VpllRegu - * 0x0c, VanaRegu - */ - REG_INIT(AB8540_VPLLVANAREGU, 0x04, 0x06, 0x0f), - /* - * 0x03, VextSupply1Regu - * 0x0c, VextSupply2Regu - * 0x30, VextSupply3Regu - * 0x40, ExtSupply2Bypass - * 0x80, ExtSupply3Bypass - */ - REG_INIT(AB8540_EXTSUPPLYREGU, 0x04, 0x08, 0xff), - /* - * 0x03, Vaux1Regu - * 0x0c, Vaux2Regu - */ - REG_INIT(AB8540_VAUX12REGU, 0x04, 0x09, 0x0f), - /* - * 0x0c, VRF1Regu - * 0x03, Vaux3Regu - */ - REG_INIT(AB8540_VRF1VAUX3REGU, 0x04, 0x0a, 0x0f), - /* - * 0x3f, Vsmps1Sel1 - */ - REG_INIT(AB8540_VSMPS1SEL1, 0x04, 0x13, 0x3f), - /* - * 0x3f, Vsmps1Sel2 - */ - REG_INIT(AB8540_VSMPS1SEL2, 0x04, 0x14, 0x3f), - /* - * 0x3f, Vsmps1Sel3 - */ - REG_INIT(AB8540_VSMPS1SEL3, 0x04, 0x15, 0x3f), - /* - * 0x3f, Vsmps2Sel1 - */ - REG_INIT(AB8540_VSMPS2SEL1, 0x04, 0x17, 0x3f), - /* - * 0x3f, Vsmps2Sel2 - */ - REG_INIT(AB8540_VSMPS2SEL2, 0x04, 0x18, 0x3f), - /* - * 0x3f, Vsmps2Sel3 - */ - REG_INIT(AB8540_VSMPS2SEL3, 0x04, 0x19, 0x3f), - /* - * 0x7f, Vsmps3Sel1 - * NOTE! PRCMU register - */ - REG_INIT(AB8540_VSMPS3SEL1, 0x04, 0x1b, 0x7f), - /* - * 0x7f, Vsmps3Sel2 - * NOTE! PRCMU register - */ - REG_INIT(AB8540_VSMPS3SEL2, 0x04, 0x1c, 0x7f), - /* - * 0x0f, Vaux1Sel - */ - REG_INIT(AB8540_VAUX1SEL, 0x04, 0x1f, 0x0f), - /* - * 0x0f, Vaux2Sel - */ - REG_INIT(AB8540_VAUX2SEL, 0x04, 0x20, 0x0f), - /* - * 0x07, Vaux3Sel - * 0x70, Vrf1Sel - */ - REG_INIT(AB8540_VRF1VAUX3SEL, 0x04, 0x21, 0x77), - /* - * 0x01, VextSupply12LP - */ - REG_INIT(AB8540_REGUCTRL2SPARE, 0x04, 0x22, 0x01), - /* - * 0x07, Vanasel - * 0x30, Vpllsel - */ - REG_INIT(AB8540_VANAVPLLSEL, 0x04, 0x29, 0x37), - /* - * 0x03, Vaux4RequestCtrl - */ - REG_INIT(AB8540_VAUX4REQCTRL, 0x04, 0x2d, 0x03), - /* - * 0x03, Vaux4Regu - */ - REG_INIT(AB8540_VAUX4REGU, 0x04, 0x2e, 0x03), - /* - * 0x0f, Vaux4Sel - */ - REG_INIT(AB8540_VAUX4SEL, 0x04, 0x2f, 0x0f), - /* - * 0x03, Vaux5RequestCtrl - */ - REG_INIT(AB8540_VAUX5REQCTRL, 0x04, 0x31, 0x03), - /* - * 0x03, Vaux5Regu - */ - REG_INIT(AB8540_VAUX5REGU, 0x04, 0x32, 0x03), - /* - * 0x3f, Vaux5Sel - */ - REG_INIT(AB8540_VAUX5SEL, 0x04, 0x33, 0x3f), - /* - * 0x03, Vaux6RequestCtrl - */ - REG_INIT(AB8540_VAUX6REQCTRL, 0x04, 0x34, 0x03), - /* - * 0x03, Vaux6Regu - */ - REG_INIT(AB8540_VAUX6REGU, 0x04, 0x35, 0x03), - /* - * 0x3f, Vaux6Sel - */ - REG_INIT(AB8540_VAUX6SEL, 0x04, 0x36, 0x3f), - /* - * 0x03, VCLKBRequestCtrl - */ - REG_INIT(AB8540_VCLKBREQCTRL, 0x04, 0x37, 0x03), - /* - * 0x03, VCLKBRegu - */ - REG_INIT(AB8540_VCLKBREGU, 0x04, 0x38, 0x03), - /* - * 0x07, VCLKBSel - */ - REG_INIT(AB8540_VCLKBSEL, 0x04, 0x39, 0x07), - /* - * 0x03, Vrf1RequestCtrl - */ - REG_INIT(AB8540_VRF1REQCTRL, 0x04, 0x3a, 0x03), - /* - * 0x01, VpllDisch - * 0x02, Vrf1Disch - * 0x04, Vaux1Disch - * 0x08, Vaux2Disch - * 0x10, Vaux3Disch - * 0x20, Vintcore12Disch - * 0x40, VTVoutDisch - * 0x80, VaudioDisch - */ - REG_INIT(AB8540_REGUCTRLDISCH, 0x04, 0x43, 0xff), - /* - * 0x02, VanaDisch - * 0x04, VdmicPullDownEna - * 0x08, VpllPullDownEna - * 0x10, VdmicDisch - */ - REG_INIT(AB8540_REGUCTRLDISCH2, 0x04, 0x44, 0x1e), - /* - * 0x01, Vaux4Disch - */ - REG_INIT(AB8540_REGUCTRLDISCH3, 0x04, 0x48, 0x01), - /* - * 0x01, Vaux5Disch - * 0x02, Vaux6Disch - * 0x04, VCLKBDisch - */ - REG_INIT(AB8540_REGUCTRLDISCH4, 0x04, 0x49, 0x07), -}; - static struct of_regulator_match ab8500_regulator_match[] = { { .name = "ab8500_ldo_aux1", .driver_data = (void *) AB8500_LDO_AUX1, }, { .name = "ab8500_ldo_aux2", .driver_data = (void *) AB8500_LDO_AUX2, }, @@ -2925,37 +1565,6 @@ static struct of_regulator_match ab8505_regulator_match[] = { { .name = "ab8500_ldo_ana", .driver_data = (void *) AB8505_LDO_ANA, }, }; -static struct of_regulator_match ab8540_regulator_match[] = { - { .name = "ab8500_ldo_aux1", .driver_data = (void *) AB8540_LDO_AUX1, }, - { .name = "ab8500_ldo_aux2", .driver_data = (void *) AB8540_LDO_AUX2, }, - { .name = "ab8500_ldo_aux3", .driver_data = (void *) AB8540_LDO_AUX3, }, - { .name = "ab8500_ldo_aux4", .driver_data = (void *) AB8540_LDO_AUX4, }, - { .name = "ab8500_ldo_aux5", .driver_data = (void *) AB8540_LDO_AUX5, }, - { .name = "ab8500_ldo_aux6", .driver_data = (void *) AB8540_LDO_AUX6, }, - { .name = "ab8500_ldo_intcore", .driver_data = (void *) AB8540_LDO_INTCORE, }, - { .name = "ab8500_ldo_tvout", .driver_data = (void *) AB8540_LDO_TVOUT, }, - { .name = "ab8500_ldo_audio", .driver_data = (void *) AB8540_LDO_AUDIO, }, - { .name = "ab8500_ldo_anamic1", .driver_data = (void *) AB8540_LDO_ANAMIC1, }, - { .name = "ab8500_ldo_anamic2", .driver_data = (void *) AB8540_LDO_ANAMIC2, }, - { .name = "ab8500_ldo_dmic", .driver_data = (void *) AB8540_LDO_DMIC, }, - { .name = "ab8500_ldo_ana", .driver_data = (void *) AB8540_LDO_ANA, }, - { .name = "ab8500_ldo_sdio", .driver_data = (void *) AB8540_LDO_SDIO, }, -}; - -static struct of_regulator_match ab9540_regulator_match[] = { - { .name = "ab8500_ldo_aux1", .driver_data = (void *) AB9540_LDO_AUX1, }, - { .name = "ab8500_ldo_aux2", .driver_data = (void *) AB9540_LDO_AUX2, }, - { .name = "ab8500_ldo_aux3", .driver_data = (void *) AB9540_LDO_AUX3, }, - { .name = "ab8500_ldo_aux4", .driver_data = (void *) AB9540_LDO_AUX4, }, - { .name = "ab8500_ldo_intcore", .driver_data = (void *) AB9540_LDO_INTCORE, }, - { .name = "ab8500_ldo_tvout", .driver_data = (void *) AB9540_LDO_TVOUT, }, - { .name = "ab8500_ldo_audio", .driver_data = (void *) AB9540_LDO_AUDIO, }, - { .name = "ab8500_ldo_anamic1", .driver_data = (void *) AB9540_LDO_ANAMIC1, }, - { .name = "ab8500_ldo_anamic2", .driver_data = (void *) AB9540_LDO_ANAMIC2, }, - { .name = "ab8500_ldo_dmic", .driver_data = (void *) AB9540_LDO_DMIC, }, - { .name = "ab8500_ldo_ana", .driver_data = (void *) AB9540_LDO_ANA, }, -}; - static struct { struct ab8500_regulator_info *info; int info_size; @@ -2967,27 +1576,13 @@ static struct { static void abx500_get_regulator_info(struct ab8500 *ab8500) { - if (is_ab9540(ab8500)) { - abx500_regulator.info = ab9540_regulator_info; - abx500_regulator.info_size = ARRAY_SIZE(ab9540_regulator_info); - abx500_regulator.init = ab9540_reg_init; - abx500_regulator.init_size = AB9540_NUM_REGULATOR_REGISTERS; - abx500_regulator.match = ab9540_regulator_match; - abx500_regulator.match_size = ARRAY_SIZE(ab9540_regulator_match); - } else if (is_ab8505(ab8500)) { + if (is_ab8505(ab8500)) { abx500_regulator.info = ab8505_regulator_info; abx500_regulator.info_size = ARRAY_SIZE(ab8505_regulator_info); abx500_regulator.init = ab8505_reg_init; abx500_regulator.init_size = AB8505_NUM_REGULATOR_REGISTERS; abx500_regulator.match = ab8505_regulator_match; abx500_regulator.match_size = ARRAY_SIZE(ab8505_regulator_match); - } else if (is_ab8540(ab8500)) { - abx500_regulator.info = ab8540_regulator_info; - abx500_regulator.info_size = ARRAY_SIZE(ab8540_regulator_info); - abx500_regulator.init = ab8540_reg_init; - abx500_regulator.init_size = AB8540_NUM_REGULATOR_REGISTERS; - abx500_regulator.match = ab8540_regulator_match; - abx500_regulator.match_size = ARRAY_SIZE(ab8540_regulator_match); } else { abx500_regulator.info = ab8500_regulator_info; abx500_regulator.info_size = ARRAY_SIZE(ab8500_regulator_info); diff --git a/include/linux/regulator/ab8500.h b/include/linux/regulator/ab8500.h index d8ecefaf63ca..6d46f962685d 100644 --- a/include/linux/regulator/ab8500.h +++ b/include/linux/regulator/ab8500.h @@ -49,47 +49,7 @@ enum ab8505_regulator_id { AB8505_NUM_REGULATORS, }; -/* AB9540 regulators */ -enum ab9540_regulator_id { - AB9540_LDO_AUX1, - AB9540_LDO_AUX2, - AB9540_LDO_AUX3, - AB9540_LDO_AUX4, - AB9540_LDO_INTCORE, - AB9540_LDO_TVOUT, - AB9540_LDO_USB, - AB9540_LDO_AUDIO, - AB9540_LDO_ANAMIC1, - AB9540_LDO_ANAMIC2, - AB9540_LDO_DMIC, - AB9540_LDO_ANA, - AB9540_SYSCLKREQ_2, - AB9540_SYSCLKREQ_4, - AB9540_NUM_REGULATORS, -}; - -/* AB8540 regulators */ -enum ab8540_regulator_id { - AB8540_LDO_AUX1, - AB8540_LDO_AUX2, - AB8540_LDO_AUX3, - AB8540_LDO_AUX4, - AB8540_LDO_AUX5, - AB8540_LDO_AUX6, - AB8540_LDO_INTCORE, - AB8540_LDO_TVOUT, - AB8540_LDO_AUDIO, - AB8540_LDO_ANAMIC1, - AB8540_LDO_ANAMIC2, - AB8540_LDO_DMIC, - AB8540_LDO_ANA, - AB8540_LDO_SDIO, - AB8540_SYSCLKREQ_2, - AB8540_SYSCLKREQ_4, - AB8540_NUM_REGULATORS, -}; - -/* AB8500, AB8505, and AB9540 register initialization */ +/* AB8500 and AB8505 register initialization */ struct ab8500_regulator_reg_init { int id; u8 mask; @@ -185,121 +145,6 @@ enum ab8505_regulator_reg { AB8505_NUM_REGULATOR_REGISTERS, }; -/* AB9540 registers */ -enum ab9540_regulator_reg { - AB9540_REGUREQUESTCTRL1, - AB9540_REGUREQUESTCTRL2, - AB9540_REGUREQUESTCTRL3, - AB9540_REGUREQUESTCTRL4, - AB9540_REGUSYSCLKREQ1HPVALID1, - AB9540_REGUSYSCLKREQ1HPVALID2, - AB9540_REGUHWHPREQ1VALID1, - AB9540_REGUHWHPREQ1VALID2, - AB9540_REGUHWHPREQ2VALID1, - AB9540_REGUHWHPREQ2VALID2, - AB9540_REGUSWHPREQVALID1, - AB9540_REGUSWHPREQVALID2, - AB9540_REGUSYSCLKREQVALID1, - AB9540_REGUSYSCLKREQVALID2, - AB9540_REGUVAUX4REQVALID, - AB9540_REGUMISC1, - AB9540_VAUDIOSUPPLY, - AB9540_REGUCTRL1VAMIC, - AB9540_VSMPS1REGU, - AB9540_VSMPS2REGU, - AB9540_VSMPS3REGU, /* NOTE! PRCMU register */ - AB9540_VPLLVANAREGU, - AB9540_EXTSUPPLYREGU, - AB9540_VAUX12REGU, - AB9540_VRF1VAUX3REGU, - AB9540_VSMPS1SEL1, - AB9540_VSMPS1SEL2, - AB9540_VSMPS1SEL3, - AB9540_VSMPS2SEL1, - AB9540_VSMPS2SEL2, - AB9540_VSMPS2SEL3, - AB9540_VSMPS3SEL1, /* NOTE! PRCMU register */ - AB9540_VSMPS3SEL2, /* NOTE! PRCMU register */ - AB9540_VAUX1SEL, - AB9540_VAUX2SEL, - AB9540_VRF1VAUX3SEL, - AB9540_REGUCTRL2SPARE, - AB9540_VAUX4REQCTRL, - AB9540_VAUX4REGU, - AB9540_VAUX4SEL, - AB9540_REGUCTRLDISCH, - AB9540_REGUCTRLDISCH2, - AB9540_REGUCTRLDISCH3, - AB9540_NUM_REGULATOR_REGISTERS, -}; - -/* AB8540 registers */ -enum ab8540_regulator_reg { - AB8540_REGUREQUESTCTRL1, - AB8540_REGUREQUESTCTRL2, - AB8540_REGUREQUESTCTRL3, - AB8540_REGUREQUESTCTRL4, - AB8540_REGUSYSCLKREQ1HPVALID1, - AB8540_REGUSYSCLKREQ1HPVALID2, - AB8540_REGUHWHPREQ1VALID1, - AB8540_REGUHWHPREQ1VALID2, - AB8540_REGUHWHPREQ2VALID1, - AB8540_REGUHWHPREQ2VALID2, - AB8540_REGUSWHPREQVALID1, - AB8540_REGUSWHPREQVALID2, - AB8540_REGUSYSCLKREQVALID1, - AB8540_REGUSYSCLKREQVALID2, - AB8540_REGUVAUX4REQVALID, - AB8540_REGUVAUX5REQVALID, - AB8540_REGUVAUX6REQVALID, - AB8540_REGUVCLKBREQVALID, - AB8540_REGUVRF1REQVALID, - AB8540_REGUMISC1, - AB8540_VAUDIOSUPPLY, - AB8540_REGUCTRL1VAMIC, - AB8540_VHSIC, - AB8540_VSDIO, - AB8540_VSMPS1REGU, - AB8540_VSMPS2REGU, - AB8540_VSMPS3REGU, - AB8540_VPLLVANAREGU, - AB8540_EXTSUPPLYREGU, - AB8540_VAUX12REGU, - AB8540_VRF1VAUX3REGU, - AB8540_VSMPS1SEL1, - AB8540_VSMPS1SEL2, - AB8540_VSMPS1SEL3, - AB8540_VSMPS2SEL1, - AB8540_VSMPS2SEL2, - AB8540_VSMPS2SEL3, - AB8540_VSMPS3SEL1, - AB8540_VSMPS3SEL2, - AB8540_VAUX1SEL, - AB8540_VAUX2SEL, - AB8540_VRF1VAUX3SEL, - AB8540_REGUCTRL2SPARE, - AB8540_VAUX4REQCTRL, - AB8540_VAUX4REGU, - AB8540_VAUX4SEL, - AB8540_VAUX5REQCTRL, - AB8540_VAUX5REGU, - AB8540_VAUX5SEL, - AB8540_VAUX6REQCTRL, - AB8540_VAUX6REGU, - AB8540_VAUX6SEL, - AB8540_VCLKBREQCTRL, - AB8540_VCLKBREGU, - AB8540_VCLKBSEL, - AB8540_VRF1REQCTRL, - AB8540_REGUCTRLDISCH, - AB8540_REGUCTRLDISCH2, - AB8540_REGUCTRLDISCH3, - AB8540_REGUCTRLDISCH4, - AB8540_VSIMSYSCLKCTRL, - AB8540_VANAVPLLSEL, - AB8540_NUM_REGULATOR_REGISTERS, -}; - /* AB8500 external regulators */ struct ab8500_ext_regulator_cfg { bool hwreq; /* requires hw mode or high power mode */ From 2d045e94f3b4da9ac116adb7a7145b46861436ac Mon Sep 17 00:00:00 2001 From: Keerthy Date: Tue, 17 Apr 2018 13:48:11 +0530 Subject: [PATCH 02/57] regulator: lp87565: Add margin while populating ramp_delay The slew rate might need a +/- 15% margin as per the latest data manual: http://www.ti.com/lit/ds/snvsb22/snvsb22.pdf Hence take a conservative approach to program 85% of the original hardware slew rate so that the software accommodates the margin delay while voltage switching. Hence reduce the default ramp_delay populated in the descriptors also by 15%. Signed-off-by: Keerthy Signed-off-by: Mark Brown --- drivers/regulator/lp87565-regulator.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/regulator/lp87565-regulator.c b/drivers/regulator/lp87565-regulator.c index cfdbe294fb6a..5a4ea996e1dc 100644 --- a/drivers/regulator/lp87565-regulator.c +++ b/drivers/regulator/lp87565-regulator.c @@ -95,6 +95,10 @@ static int lp87565_buck_set_ramp_delay(struct regulator_dev *rdev, rdev->constraints->ramp_delay = lp87565_buck_ramp_delay[reg]; + /* Conservatively give a 15% margin */ + rdev->constraints->ramp_delay = + rdev->constraints->ramp_delay * 85 / 100; + return 0; } @@ -154,32 +158,32 @@ static const struct lp87565_regulator regulators[] = { LP87565_REGULATOR("BUCK0", LP87565_BUCK_0, "buck0", lp87565_buck_ops, 256, LP87565_REG_BUCK0_VOUT, LP87565_BUCK_VSET, LP87565_REG_BUCK0_CTRL_1, - LP87565_BUCK_CTRL_1_EN, 3800, + LP87565_BUCK_CTRL_1_EN, 3230, buck0_1_2_3_ranges, LP87565_REG_BUCK0_CTRL_2), LP87565_REGULATOR("BUCK1", LP87565_BUCK_1, "buck1", lp87565_buck_ops, 256, LP87565_REG_BUCK1_VOUT, LP87565_BUCK_VSET, LP87565_REG_BUCK1_CTRL_1, - LP87565_BUCK_CTRL_1_EN, 3800, + LP87565_BUCK_CTRL_1_EN, 3230, buck0_1_2_3_ranges, LP87565_REG_BUCK1_CTRL_2), LP87565_REGULATOR("BUCK2", LP87565_BUCK_2, "buck2", lp87565_buck_ops, 256, LP87565_REG_BUCK2_VOUT, LP87565_BUCK_VSET, LP87565_REG_BUCK2_CTRL_1, - LP87565_BUCK_CTRL_1_EN, 3800, + LP87565_BUCK_CTRL_1_EN, 3230, buck0_1_2_3_ranges, LP87565_REG_BUCK2_CTRL_2), LP87565_REGULATOR("BUCK3", LP87565_BUCK_3, "buck3", lp87565_buck_ops, 256, LP87565_REG_BUCK3_VOUT, LP87565_BUCK_VSET, LP87565_REG_BUCK3_CTRL_1, - LP87565_BUCK_CTRL_1_EN, 3800, + LP87565_BUCK_CTRL_1_EN, 3230, buck0_1_2_3_ranges, LP87565_REG_BUCK3_CTRL_2), LP87565_REGULATOR("BUCK10", LP87565_BUCK_10, "buck10", lp87565_buck_ops, 256, LP87565_REG_BUCK0_VOUT, LP87565_BUCK_VSET, LP87565_REG_BUCK0_CTRL_1, - LP87565_BUCK_CTRL_1_EN, 3800, + LP87565_BUCK_CTRL_1_EN, 3230, buck0_1_2_3_ranges, LP87565_REG_BUCK0_CTRL_2), LP87565_REGULATOR("BUCK23", LP87565_BUCK_23, "buck23", lp87565_buck_ops, 256, LP87565_REG_BUCK2_VOUT, LP87565_BUCK_VSET, LP87565_REG_BUCK2_CTRL_1, - LP87565_BUCK_CTRL_1_EN, 3800, + LP87565_BUCK_CTRL_1_EN, 3230, buck0_1_2_3_ranges, LP87565_REG_BUCK2_CTRL_2), }; From 2f51a26041f2c192dfcf426c04a0753f3e68db95 Mon Sep 17 00:00:00 2001 From: Keerthy Date: Tue, 17 Apr 2018 14:21:55 +0530 Subject: [PATCH 03/57] regulator: lp87565: Enable LP87565_BUCK_CTRL_1_FPWM_MP_0_2 Buck10 is a multi(dual) phase regulator. So as part of enabling it turn on the LP87565_BUCK_CTRL_1_FPWM_MP_0_2 bit which forces it to operate always in multiphase and forced-PWM operation mode. This helps improve the transient voltage response while switching OPP. Signed-off-by: Keerthy Signed-off-by: Mark Brown --- drivers/regulator/lp87565-regulator.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/regulator/lp87565-regulator.c b/drivers/regulator/lp87565-regulator.c index 5a4ea996e1dc..c192357d1dea 100644 --- a/drivers/regulator/lp87565-regulator.c +++ b/drivers/regulator/lp87565-regulator.c @@ -178,7 +178,8 @@ static const struct lp87565_regulator regulators[] = { LP87565_REGULATOR("BUCK10", LP87565_BUCK_10, "buck10", lp87565_buck_ops, 256, LP87565_REG_BUCK0_VOUT, LP87565_BUCK_VSET, LP87565_REG_BUCK0_CTRL_1, - LP87565_BUCK_CTRL_1_EN, 3230, + LP87565_BUCK_CTRL_1_EN | + LP87565_BUCK_CTRL_1_FPWM_MP_0_2, 3230, buck0_1_2_3_ranges, LP87565_REG_BUCK0_CTRL_2), LP87565_REGULATOR("BUCK23", LP87565_BUCK_23, "buck23", lp87565_buck_ops, 256, LP87565_REG_BUCK2_VOUT, LP87565_BUCK_VSET, From 1dced996ee702e6af82a57c7b6c56b0cceaa6425 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Sun, 18 Mar 2018 11:23:21 +0800 Subject: [PATCH 04/57] regulator: pfuze100: update voltage setting for pfuze3000 sw1a pfuze3000 datasheet(Rev.9.0) from: https://www.nxp.com/docs/en/data-sheet/PF3000.pdf updates sw1a's voltage range, the settings for 1.450V and 1.475V are replaced with 1.8V and 3.3V: 5b'11110 1.450 (SW1B), 1.8 (SW1A/SW1AB) 5b'11111 1.475 (SW1B), 3.3 (SW1A/SW1AB) the voltage calculation using steps is NOT available for sw1a now, use voltage table instead. Signed-off-by: Anson Huang Signed-off-by: Robin Gong Signed-off-by: Mark Brown --- drivers/regulator/pfuze100-regulator.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/regulator/pfuze100-regulator.c b/drivers/regulator/pfuze100-regulator.c index 63922a2167e5..680f076e3d85 100644 --- a/drivers/regulator/pfuze100-regulator.c +++ b/drivers/regulator/pfuze100-regulator.c @@ -86,6 +86,13 @@ static const int pfuze100_coin[] = { 2500000, 2700000, 2800000, 2900000, 3000000, 3100000, 3200000, 3300000, }; +static const int pfuze3000_sw1a[] = { + 700000, 725000, 750000, 775000, 800000, 825000, 850000, 875000, + 900000, 925000, 950000, 975000, 1000000, 1025000, 1050000, 1075000, + 1100000, 1125000, 1150000, 1175000, 1200000, 1225000, 1250000, 1275000, + 1300000, 1325000, 1350000, 1375000, 1400000, 1425000, 1800000, 3300000, +}; + static const int pfuze3000_sw2lo[] = { 1500000, 1550000, 1600000, 1650000, 1700000, 1750000, 1800000, 1850000, }; @@ -343,7 +350,7 @@ static struct pfuze_regulator pfuze200_regulators[] = { }; static struct pfuze_regulator pfuze3000_regulators[] = { - PFUZE100_SW_REG(PFUZE3000, SW1A, PFUZE100_SW1ABVOL, 700000, 1475000, 25000), + PFUZE100_SWB_REG(PFUZE3000, SW1A, PFUZE100_SW1ABVOL, 0x1f, pfuze3000_sw1a), PFUZE100_SW_REG(PFUZE3000, SW1B, PFUZE100_SW1CVOL, 700000, 1475000, 25000), PFUZE100_SWB_REG(PFUZE3000, SW2, PFUZE100_SW2VOL, 0x7, pfuze3000_sw2lo), PFUZE3000_SW3_REG(PFUZE3000, SW3, PFUZE100_SW3AVOL, 900000, 1650000, 50000), From 669ca0303ac93adba0e046d414165250861efdb7 Mon Sep 17 00:00:00 2001 From: ryang Date: Thu, 19 Apr 2018 12:18:50 -0400 Subject: [PATCH 05/57] regulator: tps6586x: Add support for TPS658624 This version is exists in the Samsung Galaxy Tab 10.1 which is based on the Nvidia Tegra 2 board. The TPS658624 has the same SM2 voltage table as TPS658623. Signed-off-by: ryang Acked-by: Lee Jones Signed-off-by: Mark Brown --- drivers/regulator/tps6586x-regulator.c | 1 + include/linux/mfd/tps6586x.h | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/regulator/tps6586x-regulator.c b/drivers/regulator/tps6586x-regulator.c index 9e9d22038017..ba3dae7b2d2d 100644 --- a/drivers/regulator/tps6586x-regulator.c +++ b/drivers/regulator/tps6586x-regulator.c @@ -342,6 +342,7 @@ static struct tps6586x_regulator *find_regulator_info(int id, int version) switch (version) { case TPS658623: + case TPS658624: table = tps658623_regulator; num = ARRAY_SIZE(tps658623_regulator); break; diff --git a/include/linux/mfd/tps6586x.h b/include/linux/mfd/tps6586x.h index 2fe68e481230..b19c2801a30e 100644 --- a/include/linux/mfd/tps6586x.h +++ b/include/linux/mfd/tps6586x.h @@ -18,6 +18,7 @@ #define TPS658621A 0x15 #define TPS658621CD 0x2c #define TPS658623 0x1b +#define TPS658624 0x0a #define TPS658640 0x01 #define TPS658640v2 0x02 #define TPS658643 0x03 From 02f3703934a42417021405ef336fe45add13c3d1 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Wed, 18 Apr 2018 08:54:18 -0700 Subject: [PATCH 06/57] regulator: Don't return or expect -errno from of_map_mode() In of_get_regulation_constraints() we were taking the result of of_map_mode() (an unsigned int) and assigning it to an int. We were then checking whether this value was -EINVAL. Some implementers of of_map_mode() were returning -EINVAL (even though the return type of their function needed to be unsigned int) because they needed to signal an error back to of_get_regulation_constraints(). In general in the regulator framework the mode is always referred to as an unsigned int. While we could fix this to be a signed int (the highest value we store in there right now is 0x8), it's actually pretty clean to just define the regulator mode 0x0 (the lack of any bits set) as an invalid mode. Let's do that. Fixes: 5e5e3a42c653 ("regulator: of: Add support for parsing initial and suspend modes") Suggested-by: Javier Martinez Canillas Signed-off-by: Douglas Anderson Reviewed-by: Javier Martinez Canillas Signed-off-by: Mark Brown --- drivers/regulator/cpcap-regulator.c | 2 +- drivers/regulator/of_regulator.c | 13 +++++++------ drivers/regulator/twl-regulator.c | 2 +- include/linux/regulator/consumer.h | 1 + 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/regulator/cpcap-regulator.c b/drivers/regulator/cpcap-regulator.c index f541b80f1b54..bd910fe123d9 100644 --- a/drivers/regulator/cpcap-regulator.c +++ b/drivers/regulator/cpcap-regulator.c @@ -222,7 +222,7 @@ static unsigned int cpcap_map_mode(unsigned int mode) case CPCAP_BIT_AUDIO_LOW_PWR: return REGULATOR_MODE_STANDBY; default: - return -EINVAL; + return REGULATOR_MODE_INVALID; } } diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c index f47264fa1940..0d3f73eacb99 100644 --- a/drivers/regulator/of_regulator.c +++ b/drivers/regulator/of_regulator.c @@ -31,6 +31,7 @@ static void of_get_regulation_constraints(struct device_node *np, struct regulation_constraints *constraints = &(*init_data)->constraints; struct regulator_state *suspend_state; struct device_node *suspend_np; + unsigned int mode; int ret, i; u32 pval; @@ -124,11 +125,11 @@ static void of_get_regulation_constraints(struct device_node *np, if (!of_property_read_u32(np, "regulator-initial-mode", &pval)) { if (desc && desc->of_map_mode) { - ret = desc->of_map_mode(pval); - if (ret == -EINVAL) + mode = desc->of_map_mode(pval); + if (mode == REGULATOR_MODE_INVALID) pr_err("%s: invalid mode %u\n", np->name, pval); else - constraints->initial_mode = ret; + constraints->initial_mode = mode; } else { pr_warn("%s: mapping for mode %d not defined\n", np->name, pval); @@ -163,12 +164,12 @@ static void of_get_regulation_constraints(struct device_node *np, if (!of_property_read_u32(suspend_np, "regulator-mode", &pval)) { if (desc && desc->of_map_mode) { - ret = desc->of_map_mode(pval); - if (ret == -EINVAL) + mode = desc->of_map_mode(pval); + if (mode == REGULATOR_MODE_INVALID) pr_err("%s: invalid mode %u\n", np->name, pval); else - suspend_state->mode = ret; + suspend_state->mode = mode; } else { pr_warn("%s: mapping for mode %d not defined\n", np->name, pval); diff --git a/drivers/regulator/twl-regulator.c b/drivers/regulator/twl-regulator.c index a4456db5849d..884c7505ed91 100644 --- a/drivers/regulator/twl-regulator.c +++ b/drivers/regulator/twl-regulator.c @@ -274,7 +274,7 @@ static inline unsigned int twl4030reg_map_mode(unsigned int mode) case RES_STATE_SLEEP: return REGULATOR_MODE_STANDBY; default: - return -EINVAL; + return REGULATOR_MODE_INVALID; } } diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h index df176d7c2b87..25602afd4844 100644 --- a/include/linux/regulator/consumer.h +++ b/include/linux/regulator/consumer.h @@ -80,6 +80,7 @@ struct regmap; * These modes can be OR'ed together to make up a mask of valid register modes. */ +#define REGULATOR_MODE_INVALID 0x0 #define REGULATOR_MODE_FAST 0x1 #define REGULATOR_MODE_NORMAL 0x2 #define REGULATOR_MODE_IDLE 0x4 From f97a236801b29f6a8e2ba3957789c3932a908966 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 20 Apr 2018 10:26:23 +0100 Subject: [PATCH 07/57] regulator: wm8350: fix missing increment of loop index i It seems that the loop index i is not being incremented and hence potentially the while loop could spin forever. Fortunately with the data being used this does not appear to happen at the moment. Signed-off-by: Colin Ian King Acked-by: Charles Keepax Signed-off-by: Mark Brown --- drivers/regulator/wm8350-regulator.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c index da9106bd2109..8ad11b074b49 100644 --- a/drivers/regulator/wm8350-regulator.c +++ b/drivers/regulator/wm8350-regulator.c @@ -911,6 +911,7 @@ static unsigned int get_mode(int uA, const struct wm8350_dcdc_efficiency *eff) while (eff[i].uA_load_min != -1) { if (uA >= eff[i].uA_load_min && uA <= eff[i].uA_load_max) return eff[i].mode; + i++; } return REGULATOR_MODE_NORMAL; } From 1f5d6462b5856ddd44d4500ac80b7862faff351b Mon Sep 17 00:00:00 2001 From: Jagan Teki Date: Mon, 23 Apr 2018 12:02:37 +0530 Subject: [PATCH 08/57] regulator: axp20x: add drivevbus support for axp803 Like axp221, axp223, axp813 the axp803 is also supporting external regulator to drive the OTG VBus through N_VBUSEN PMIC pin. Add support for it. Signed-off-by: Jagan Teki Reviewed-by: Rob Herring Reviewed-by: Chen-Yu Tsai Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/mfd/axp20x.txt | 3 ++- drivers/regulator/axp20x-regulator.c | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/mfd/axp20x.txt b/Documentation/devicetree/bindings/mfd/axp20x.txt index 9455503b0299..d1762f3b30af 100644 --- a/Documentation/devicetree/bindings/mfd/axp20x.txt +++ b/Documentation/devicetree/bindings/mfd/axp20x.txt @@ -43,7 +43,7 @@ Optional properties: regulator to drive the OTG VBus, rather then as an input pin which signals whether the board is driving OTG VBus or not. - (axp221 / axp223 / axp813 only) + (axp221 / axp223 / axp803/ axp813 only) - x-powers,master-mode: Boolean (axp806 only). Set this when the PMIC is wired for master mode. The default is slave mode. @@ -132,6 +132,7 @@ FLDO2 : LDO : fldoin-supply : shared supply LDO_IO0 : LDO : ips-supply : GPIO 0 LDO_IO1 : LDO : ips-supply : GPIO 1 RTC_LDO : LDO : ips-supply : always on +DRIVEVBUS : Enable output : drivevbus-supply : external regulator AXP806 regulators, type, and corresponding input supply names: diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c index 181622b2813d..91b8ff8bac15 100644 --- a/drivers/regulator/axp20x-regulator.c +++ b/drivers/regulator/axp20x-regulator.c @@ -721,6 +721,8 @@ static int axp20x_regulator_probe(struct platform_device *pdev) case AXP803_ID: regulators = axp803_regulators; nregulators = AXP803_REG_ID_MAX; + drivevbus = of_property_read_bool(pdev->dev.parent->of_node, + "x-powers,drive-vbus-en"); break; case AXP806_ID: regulators = axp806_regulators; From c85964de544cae98c3d8d29c936b6d13258e4a10 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 18 Apr 2018 15:18:01 +0200 Subject: [PATCH 09/57] dt-bindings: mfd: bd9571mwv: Document DDR Backup Mode properties Document the new optional properties related to DDR Backup Mode and toggle/momentary power switches. Signed-off-by: Geert Uytterhoeven Reviewed-by: Rob Herring Acked-by: Lee Jones Signed-off-by: Mark Brown --- .../devicetree/bindings/mfd/bd9571mwv.txt | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/Documentation/devicetree/bindings/mfd/bd9571mwv.txt b/Documentation/devicetree/bindings/mfd/bd9571mwv.txt index 9ab216a851d5..25d1f697eb25 100644 --- a/Documentation/devicetree/bindings/mfd/bd9571mwv.txt +++ b/Documentation/devicetree/bindings/mfd/bd9571mwv.txt @@ -25,6 +25,25 @@ Required properties: Each child node is defined using the standard binding for regulators. +Optional properties: + - rohm,ddr-backup-power : Value to use for DDR-Backup Power (default 0). + This is a bitmask that specifies which DDR power + rails need to be kept powered when backup mode is + entered, for system suspend: + - bit 0: DDR0 + - bit 1: DDR1 + - bit 2: DDR0C + - bit 3: DDR1C + These bits match the KEEPON_DDR* bits in the + documentation for the "BKUP Mode Cnt" register. + - rohm,rstbmode-level: The RSTB signal is configured for level mode, to + accommodate a toggle power switch (the RSTBMODE pin is + strapped low). + - rohm,rstbmode-pulse: The RSTB signal is configured for pulse mode, to + accommodate a momentary power switch (the RSTBMODE pin + is strapped high). + The two properties above are mutually exclusive. + Example: pmic: pmic@30 { @@ -36,6 +55,8 @@ Example: #interrupt-cells = <2>; gpio-controller; #gpio-cells = <2>; + rohm,ddr-backup-power = <0xf>; + rohm,rstbmode-pulse; regulators { dvfs: dvfs { From 2ff0dab80a8999e99a93fd70f8d701ec3deab207 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 18 Apr 2018 15:18:02 +0200 Subject: [PATCH 10/57] mfd: bd9571mwv: Add DDR Backup Power register bit definitions Add definitions for the KEEPON_* bits in the "BKUP Mode Cnt" register, which control the DDR rails to be kept powered when backup mode is enabled. Signed-off-by: Geert Uytterhoeven Acked-by: Lee Jones Signed-off-by: Mark Brown --- include/linux/mfd/bd9571mwv.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/linux/mfd/bd9571mwv.h b/include/linux/mfd/bd9571mwv.h index f0708ba4cbba..eb05569f752b 100644 --- a/include/linux/mfd/bd9571mwv.h +++ b/include/linux/mfd/bd9571mwv.h @@ -33,6 +33,11 @@ #define BD9571MWV_I2C_MD2_E1_BIT_2 0x12 #define BD9571MWV_BKUP_MODE_CNT 0x20 +#define BD9571MWV_BKUP_MODE_CNT_KEEPON_MASK GENMASK(3, 0) +#define BD9571MWV_BKUP_MODE_CNT_KEEPON_DDR0 BIT(0) +#define BD9571MWV_BKUP_MODE_CNT_KEEPON_DDR1 BIT(1) +#define BD9571MWV_BKUP_MODE_CNT_KEEPON_DDR0C BIT(2) +#define BD9571MWV_BKUP_MODE_CNT_KEEPON_DDR1C BIT(3) #define BD9571MWV_BKUP_MODE_STATUS 0x21 #define BD9571MWV_BKUP_RECOVERY_CNT 0x22 #define BD9571MWV_BKUP_CTRL_TIM_CNT 0x23 From 7b569bcb2a2f985fe2d1407aed705882af30cb77 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 18 Apr 2018 15:18:03 +0200 Subject: [PATCH 11/57] mfd: bd9571mwv: Allow DDR Backup Power register access Enable read/write access to the BD9571MWV_BKUP_MODE_CNT register, which is amongst others used to configure DDR Backup Power. Signed-off-by: Geert Uytterhoeven Acked-by: Lee Jones Signed-off-by: Mark Brown --- drivers/mfd/bd9571mwv.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/mfd/bd9571mwv.c b/drivers/mfd/bd9571mwv.c index 64e088dfe7b0..503979c81dae 100644 --- a/drivers/mfd/bd9571mwv.c +++ b/drivers/mfd/bd9571mwv.c @@ -29,6 +29,7 @@ static const struct mfd_cell bd9571mwv_cells[] = { static const struct regmap_range bd9571mwv_readable_yes_ranges[] = { regmap_reg_range(BD9571MWV_VENDOR_CODE, BD9571MWV_PRODUCT_REVISION), + regmap_reg_range(BD9571MWV_BKUP_MODE_CNT, BD9571MWV_BKUP_MODE_CNT), regmap_reg_range(BD9571MWV_AVS_SET_MONI, BD9571MWV_AVS_DVFS_VID(3)), regmap_reg_range(BD9571MWV_VD18_VID, BD9571MWV_VD33_VID), regmap_reg_range(BD9571MWV_DVFS_VINIT, BD9571MWV_DVFS_VINIT), @@ -44,6 +45,7 @@ static const struct regmap_access_table bd9571mwv_readable_table = { }; static const struct regmap_range bd9571mwv_writable_yes_ranges[] = { + regmap_reg_range(BD9571MWV_BKUP_MODE_CNT, BD9571MWV_BKUP_MODE_CNT), regmap_reg_range(BD9571MWV_AVS_VD09_VID(0), BD9571MWV_AVS_VD09_VID(3)), regmap_reg_range(BD9571MWV_DVFS_SETVID, BD9571MWV_DVFS_SETVID), regmap_reg_range(BD9571MWV_GPIO_DIR, BD9571MWV_GPIO_OUT), From 6eb0bfae6973eb6a7790f9d21e294022fe2da6ad Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 18 Apr 2018 15:18:04 +0200 Subject: [PATCH 12/57] regulator: bd9571mwv: Add support for backup mode The BD9571MWV PMIC supports backup mode, which keeps one or more DDR rails powered while the main SoC is powered down. Which DDR rails are to be kept powered is board-specific, and controlled using the optional "rohm,ddr-backup-power" DT property. In the absence of this property, backup mode is not available. Backup mode can be enabled or disabled by the user using the standard "wakeup" virtual file in sysfs, e.g. to enable: echo enabled > /sys/devices/platform/soc/e60b0000.i2c/i2c-7/7-0030/bd9571mwv-regulator.2.auto/power/wakeup When the PMIC is configured for backup mode, the role of the accessory power switch changes from a power switch to a wake-up switch. Two types of switches (or signals) can be used: A. With a momentary power switch (or pulse signal), the PMIC is configured for backup mode in the PMIC driver's suspend callback, during system suspend. Backup mode is enabled by default, as there is no further impact during normal system operation. B. With a toggle power switch (or level signal), the following steps must be followed exactly: 1. Configure PMIC for backup mode, 2. Switch accessory power switch off, to prepare for system suspend, which is a manual step not controlled by software, 3. Suspend system. This mode is not yet supported by the driver. As the switch type is board-specific, and cannot be determined automatically, it is obtained from the presence of one of the "rohm,rstbmode-*" properties in DT. Signed-off-by: Geert Uytterhoeven Acked-by: Lee Jones Signed-off-by: Mark Brown --- drivers/regulator/bd9571mwv-regulator.c | 127 +++++++++++++++++++++++- 1 file changed, 126 insertions(+), 1 deletion(-) diff --git a/drivers/regulator/bd9571mwv-regulator.c b/drivers/regulator/bd9571mwv-regulator.c index c67a83d53c4c..be574eb444eb 100644 --- a/drivers/regulator/bd9571mwv-regulator.c +++ b/drivers/regulator/bd9571mwv-regulator.c @@ -24,6 +24,18 @@ #include +struct bd9571mwv_reg { + struct bd9571mwv *bd; + + /* DDR Backup Power */ + u8 bkup_mode_cnt_keepon; /* from "rohm,ddr-backup-power" */ + u8 bkup_mode_cnt_saved; + + /* Power switch type */ + bool rstbmode_level; + bool rstbmode_pulse; +}; + enum bd9571mwv_regulators { VD09, VD18, VD25, VD33, DVFS }; #define BD9571MWV_REG(_name, _of, _id, _ops, _vr, _vm, _nv, _min, _step, _lmin)\ @@ -131,14 +143,99 @@ static struct regulator_desc regulators[] = { 0x80, 600000, 10000, 0x3c), }; +#ifdef CONFIG_PM_SLEEP +static int bd9571mwv_bkup_mode_read(struct bd9571mwv *bd, unsigned int *mode) +{ + int ret; + + ret = regmap_read(bd->regmap, BD9571MWV_BKUP_MODE_CNT, mode); + if (ret) { + dev_err(bd->dev, "failed to read backup mode (%d)\n", ret); + return ret; + } + + return 0; +} + +static int bd9571mwv_bkup_mode_write(struct bd9571mwv *bd, unsigned int mode) +{ + int ret; + + ret = regmap_write(bd->regmap, BD9571MWV_BKUP_MODE_CNT, mode); + if (ret) { + dev_err(bd->dev, "failed to configure backup mode 0x%x (%d)\n", + mode, ret); + return ret; + } + + return 0; +} + +static int bd9571mwv_suspend(struct device *dev) +{ + struct bd9571mwv_reg *bdreg = dev_get_drvdata(dev); + unsigned int mode; + int ret; + + if (!device_may_wakeup(dev)) + return 0; + + /* Save DDR Backup Mode */ + ret = bd9571mwv_bkup_mode_read(bdreg->bd, &mode); + if (ret) + return ret; + + bdreg->bkup_mode_cnt_saved = mode; + + if (!bdreg->rstbmode_pulse) + return 0; + + /* Enable DDR Backup Mode */ + mode &= ~BD9571MWV_BKUP_MODE_CNT_KEEPON_MASK; + mode |= bdreg->bkup_mode_cnt_keepon; + + if (mode != bdreg->bkup_mode_cnt_saved) + return bd9571mwv_bkup_mode_write(bdreg->bd, mode); + + return 0; +} + +static int bd9571mwv_resume(struct device *dev) +{ + struct bd9571mwv_reg *bdreg = dev_get_drvdata(dev); + + if (!device_may_wakeup(dev)) + return 0; + + /* Restore DDR Backup Mode */ + return bd9571mwv_bkup_mode_write(bdreg->bd, bdreg->bkup_mode_cnt_saved); +} + +static const struct dev_pm_ops bd9571mwv_pm = { + SET_SYSTEM_SLEEP_PM_OPS(bd9571mwv_suspend, bd9571mwv_resume) +}; + +#define DEV_PM_OPS &bd9571mwv_pm +#else +#define DEV_PM_OPS NULL +#endif /* CONFIG_PM_SLEEP */ + static int bd9571mwv_regulator_probe(struct platform_device *pdev) { struct bd9571mwv *bd = dev_get_drvdata(pdev->dev.parent); struct regulator_config config = { }; + struct bd9571mwv_reg *bdreg; struct regulator_dev *rdev; + unsigned int val; int i; - platform_set_drvdata(pdev, bd); + bdreg = devm_kzalloc(&pdev->dev, sizeof(*bdreg), GFP_KERNEL); + if (!bdreg) + return -ENOMEM; + + bdreg->bd = bd; + + platform_set_drvdata(pdev, bdreg); config.dev = &pdev->dev; config.dev->of_node = bd->dev->of_node; @@ -155,6 +252,33 @@ static int bd9571mwv_regulator_probe(struct platform_device *pdev) } } + val = 0; + of_property_read_u32(bd->dev->of_node, "rohm,ddr-backup-power", &val); + if (val & ~BD9571MWV_BKUP_MODE_CNT_KEEPON_MASK) { + dev_err(bd->dev, "invalid %s mode %u\n", + "rohm,ddr-backup-power", val); + return -EINVAL; + } + bdreg->bkup_mode_cnt_keepon = val; + + bdreg->rstbmode_level = of_property_read_bool(bd->dev->of_node, + "rohm,rstbmode-level"); + bdreg->rstbmode_pulse = of_property_read_bool(bd->dev->of_node, + "rohm,rstbmode-pulse"); + if (bdreg->rstbmode_level && bdreg->rstbmode_pulse) { + dev_err(bd->dev, "only one rohm,rstbmode-* may be specified"); + return -EINVAL; + } + + if (bdreg->bkup_mode_cnt_keepon) { + device_set_wakeup_capable(&pdev->dev, true); + /* + * Wakeup is enabled by default in pulse mode, but needs + * explicit user setup in level mode. + */ + device_set_wakeup_enable(&pdev->dev, bdreg->rstbmode_pulse); + } + return 0; } @@ -167,6 +291,7 @@ MODULE_DEVICE_TABLE(platform, bd9571mwv_regulator_id_table); static struct platform_driver bd9571mwv_regulator_driver = { .driver = { .name = "bd9571mwv-regulator", + .pm = DEV_PM_OPS, }, .probe = bd9571mwv_regulator_probe, .id_table = bd9571mwv_regulator_id_table, From d2a66ddfe8acd91aca81af2ef39abd5813d5dc65 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Tue, 1 May 2018 03:50:45 +0200 Subject: [PATCH 13/57] regulator: ltc3676: Assure PGOOD mask is set before changing voltage Make sure the DVBxB bit 5, PGOOD mask, is set before changing voltage on the buck converters. If the PGOOD mask bit is not set, the PMIC may deassert the PGOOD signal during the voltage transition. On systems that use the PGOOD signal as a power OK indication for the board or SoC, which should be the case on correct designs, deasserting the PGOOD signal will lead to system reset or shutdown, which is not the expected behavior when changing PMIC buck converter voltage. Signed-off-by: Marek Vasut Signed-off-by: Mark Brown --- drivers/regulator/ltc3676.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/drivers/regulator/ltc3676.c b/drivers/regulator/ltc3676.c index 662ee05ea44d..9dec1609ff66 100644 --- a/drivers/regulator/ltc3676.c +++ b/drivers/regulator/ltc3676.c @@ -52,6 +52,7 @@ #define LTC3676_CLIRQ 0x1F #define LTC3676_DVBxA_REF_SELECT BIT(5) +#define LTC3676_DVBxB_PGOOD_MASK BIT(5) #define LTC3676_IRQSTAT_PGOOD_TIMEOUT BIT(3) #define LTC3676_IRQSTAT_UNDERVOLT_WARN BIT(4) @@ -123,6 +124,23 @@ static int ltc3676_set_suspend_mode(struct regulator_dev *rdev, mask, val); } +static int ltc3676_set_voltage_sel(struct regulator_dev *rdev, unsigned selector) +{ + struct ltc3676 *ltc3676 = rdev_get_drvdata(rdev); + struct device *dev = ltc3676->dev; + int ret, dcdc = rdev_get_id(rdev); + + dev_dbg(dev, "%s id=%d selector=%d\n", __func__, dcdc, selector); + + ret = regmap_update_bits(ltc3676->regmap, rdev->desc->vsel_reg + 1, + LTC3676_DVBxB_PGOOD_MASK, + LTC3676_DVBxB_PGOOD_MASK); + if (ret) + return ret; + + return regulator_set_voltage_sel_regmap(rdev, selector); +} + static inline unsigned int ltc3676_scale(unsigned int uV, u32 r1, u32 r2) { uint64_t tmp; @@ -166,7 +184,7 @@ static const struct regulator_ops ltc3676_linear_regulator_ops = { .disable = regulator_disable_regmap, .is_enabled = regulator_is_enabled_regmap, .list_voltage = regulator_list_voltage_linear, - .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_voltage_sel = ltc3676_set_voltage_sel, .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_suspend_voltage = ltc3676_set_suspend_voltage, .set_suspend_mode = ltc3676_set_suspend_mode, From 60891ceb8075e02cbf841ac1e7f7437d711ffc5f Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Fri, 4 May 2018 22:17:13 -0300 Subject: [PATCH 14/57] regulator: pfuze100: Make the node name generic According to Devicetree Specification v0.2 document: "The name of a node should be somewhat generic, reflecting the function of the device and not its precise programming model." Do as suggested in the binding example. Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/regulator/pfuze100.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/regulator/pfuze100.txt b/Documentation/devicetree/bindings/regulator/pfuze100.txt index c6dd3f5e485b..f0ada3b14d70 100644 --- a/Documentation/devicetree/bindings/regulator/pfuze100.txt +++ b/Documentation/devicetree/bindings/regulator/pfuze100.txt @@ -21,7 +21,7 @@ Each regulator is defined using the standard binding for regulators. Example 1: PFUZE100 - pmic: pfuze100@8 { + pfuze100: pmic@8 { compatible = "fsl,pfuze100"; reg = <0x08>; @@ -122,7 +122,7 @@ Example 1: PFUZE100 Example 2: PFUZE200 - pmic: pfuze200@8 { + pfuze200: pmic@8 { compatible = "fsl,pfuze200"; reg = <0x08>; @@ -216,7 +216,7 @@ Example 2: PFUZE200 Example 3: PFUZE3000 - pmic: pfuze3000@8 { + pfuze3000: pmic@8 { compatible = "fsl,pfuze3000"; reg = <0x08>; From 08813e0ec1cb48e53c86a24d88d26b26878e7b6e Mon Sep 17 00:00:00 2001 From: Changbin Du Date: Wed, 2 May 2018 21:44:57 +0800 Subject: [PATCH 15/57] regulator: add dummy function of_find_regulator_by_node If device tree is not enabled, of_find_regulator_by_node() should have a dummy function since the function call is still there. This is to fix build error after CONFIG_NO_AUTO_INLINE is introduced. If this option is enabled, GCC will not auto-inline functions that are not explicitly marked as inline. In this case (no CONFIG_OF), the copmiler will report error in function regulator_dev_lookup(). W/O NO_AUTO_INLINE, function of_get_regulator() is auto-inlined and then the call to of_find_regulator_by_node() is optimized out since of_get_regulator() always return NULL. W/ NO_AUTO_INLINE, the return value of of_get_regulator() is a variable so the call to of_find_regulator_by_node() cannot be optimized out. So we need a stub of_find_regulator_by_node(). static struct regulator_dev *regulator_dev_lookup(struct device *dev, const char *supply) { struct regulator_dev *r = NULL; struct device_node *node; struct regulator_map *map; const char *devname = NULL; regulator_supply_alias(&dev, &supply); /* first do a dt based lookup */ if (dev && dev->of_node) { node = of_get_regulator(dev, supply); if (node) { r = of_find_regulator_by_node(node); if (r) return r; ... Signed-off-by: Changbin Du Signed-off-by: Mark Brown --- drivers/regulator/internal.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/regulator/internal.h b/drivers/regulator/internal.h index abfd56e8c78a..24fde1e08f3a 100644 --- a/drivers/regulator/internal.h +++ b/drivers/regulator/internal.h @@ -56,14 +56,19 @@ static inline struct regulator_dev *dev_to_rdev(struct device *dev) return container_of(dev, struct regulator_dev, dev); } -struct regulator_dev *of_find_regulator_by_node(struct device_node *np); - #ifdef CONFIG_OF +struct regulator_dev *of_find_regulator_by_node(struct device_node *np); struct regulator_init_data *regulator_of_get_init_data(struct device *dev, const struct regulator_desc *desc, struct regulator_config *config, struct device_node **node); #else +static inline struct regulator_dev * +of_find_regulator_by_node(struct device_node *np) +{ + return NULL; +} + static inline struct regulator_init_data * regulator_of_get_init_data(struct device *dev, const struct regulator_desc *desc, From 32aba834f2a9fe126ff5e624371113ac1defa06e Mon Sep 17 00:00:00 2001 From: Ondrej Jirman Date: Mon, 7 May 2018 20:29:40 +0800 Subject: [PATCH 16/57] regulator: add binding for the SY8106A voltage regulator SY8106A is an I2C-controlled adjustable voltage regulator made by Silergy Corp. Add its device tree binding. Signed-off-by: Ondrej Jirman [Icenowy: Change commit message and slight fixes] Signed-off-by: Icenowy Zheng Reviewed-by: Chen-Yu Tsai Acked-by: Rob Herring Signed-off-by: Mark Brown --- .../bindings/regulator/sy8106a-regulator.txt | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 Documentation/devicetree/bindings/regulator/sy8106a-regulator.txt diff --git a/Documentation/devicetree/bindings/regulator/sy8106a-regulator.txt b/Documentation/devicetree/bindings/regulator/sy8106a-regulator.txt new file mode 100644 index 000000000000..39a8ca73f572 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/sy8106a-regulator.txt @@ -0,0 +1,23 @@ +SY8106A Voltage regulator + +Required properties: +- compatible: Must be "silergy,sy8106a" +- reg: I2C slave address - must be <0x65> +- silergy,fixed-microvolt - the voltage when I2C regulating is disabled (set + by external resistor like a fixed voltage) + +Any property defined as part of the core regulator binding, defined in +./regulator.txt, can also be used. + +Example: + + sy8106a { + compatible = "silergy,sy8106a"; + reg = <0x65>; + regulator-name = "sy8106a-vdd"; + silergy,fixed-microvolt = <1200000>; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1400000>; + regulator-boot-on; + regulator-always-on; + }; From 8878302ebbc580d64f390c0acc509e5e8276598c Mon Sep 17 00:00:00 2001 From: Ondrej Jirman Date: Mon, 7 May 2018 20:29:41 +0800 Subject: [PATCH 17/57] regulator: add support for SY8106A regulator SY8106A is an I2C attached single output regulator made by Silergy Corp, which is used on several Allwinner H3/H5 SBCs to control the power supply of the ARM cores. Add a driver for it. Signed-off-by: Ondrej Jirman [Icenowy: Change commit message, remove enable/disable code, add default ramp_delay, add comment for go bit, add code for fixed mode voltage] Signed-off-by: Icenowy Zheng Reviewed-by: Chen-Yu Tsai Signed-off-by: Mark Brown --- MAINTAINERS | 6 + drivers/regulator/Kconfig | 7 ++ drivers/regulator/Makefile | 2 +- drivers/regulator/sy8106a-regulator.c | 167 ++++++++++++++++++++++++++ 4 files changed, 181 insertions(+), 1 deletion(-) create mode 100644 drivers/regulator/sy8106a-regulator.c diff --git a/MAINTAINERS b/MAINTAINERS index 0a1410d5a621..971300930067 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13461,6 +13461,12 @@ S: Supported F: net/switchdev/ F: include/net/switchdev.h +SY8106A REGULATOR DRIVER +M: Icenowy Zheng +S: Maintained +F: drivers/regulator/sy8106a-regulator.c +F: Documentation/devicetree/bindings/regulator/sy8106a-regulator.txt + SYNC FILE FRAMEWORK M: Sumit Semwal R: Gustavo Padovan diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 097f61784a7d..4efae3b7e746 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -801,6 +801,13 @@ config REGULATOR_STW481X_VMMC This driver supports the internal VMMC regulator in the STw481x PMIC chips. +config REGULATOR_SY8106A + tristate "Silergy SY8106A regulator" + depends on I2C && (OF || COMPILE_TEST) + select REGMAP_I2C + help + This driver supports SY8106A single output regulator. + config REGULATOR_TPS51632 tristate "TI TPS51632 Power Regulator" depends on I2C diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 590674fbecd7..d81fb02bd6e9 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -100,6 +100,7 @@ obj-$(CONFIG_REGULATOR_SC2731) += sc2731-regulator.o obj-$(CONFIG_REGULATOR_SKY81452) += sky81452-regulator.o obj-$(CONFIG_REGULATOR_STM32_VREFBUF) += stm32-vrefbuf.o obj-$(CONFIG_REGULATOR_STW481X_VMMC) += stw481x-vmmc.o +obj-$(CONFIG_REGULATOR_SY8106A) += sy8106a-regulator.o obj-$(CONFIG_REGULATOR_TI_ABB) += ti-abb-regulator.o obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o obj-$(CONFIG_REGULATOR_TPS62360) += tps62360-regulator.o @@ -125,5 +126,4 @@ obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o obj-$(CONFIG_REGULATOR_WM8994) += wm8994-regulator.o - ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG diff --git a/drivers/regulator/sy8106a-regulator.c b/drivers/regulator/sy8106a-regulator.c new file mode 100644 index 000000000000..65fbd1f0b612 --- /dev/null +++ b/drivers/regulator/sy8106a-regulator.c @@ -0,0 +1,167 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// sy8106a-regulator.c - Regulator device driver for SY8106A +// +// Copyright (C) 2016 OndÅ™ej Jirman +// Copyright (c) 2017-2018 Icenowy Zheng + +#include +#include +#include +#include +#include +#include + +#define SY8106A_REG_VOUT1_SEL 0x01 +#define SY8106A_REG_VOUT_COM 0x02 +#define SY8106A_REG_VOUT1_SEL_MASK 0x7f +#define SY8106A_DISABLE_REG BIT(0) +/* + * The I2C controlled voltage will only work when this bit is set; otherwise + * it will behave like a fixed regulator. + */ +#define SY8106A_GO_BIT BIT(7) + +struct sy8106a { + struct regulator_dev *rdev; + struct regmap *regmap; + u32 fixed_voltage; +}; + +static const struct regmap_config sy8106a_regmap_config = { + .reg_bits = 8, + .val_bits = 8, +}; + +static const struct regulator_ops sy8106a_ops = { + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .list_voltage = regulator_list_voltage_linear, + /* Enabling/disabling the regulator is not yet implemented */ +}; + +/* Default limits measured in millivolts */ +#define SY8106A_MIN_MV 680 +#define SY8106A_MAX_MV 1950 +#define SY8106A_STEP_MV 10 + +static const struct regulator_desc sy8106a_reg = { + .name = "SY8106A", + .id = 0, + .ops = &sy8106a_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = ((SY8106A_MAX_MV - SY8106A_MIN_MV) / SY8106A_STEP_MV) + 1, + .min_uV = (SY8106A_MIN_MV * 1000), + .uV_step = (SY8106A_STEP_MV * 1000), + .vsel_reg = SY8106A_REG_VOUT1_SEL, + .vsel_mask = SY8106A_REG_VOUT1_SEL_MASK, + /* + * This ramp_delay is a conservative default value which works on + * H3/H5 boards VDD-CPUX situations. + */ + .ramp_delay = 200, + .owner = THIS_MODULE, +}; + +/* + * I2C driver interface functions + */ +static int sy8106a_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct sy8106a *chip; + struct device *dev = &i2c->dev; + struct regulator_dev *rdev = NULL; + struct regulator_config config = { }; + unsigned int reg, vsel; + int error; + + chip = devm_kzalloc(&i2c->dev, sizeof(struct sy8106a), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + error = of_property_read_u32(dev->of_node, "silergy,fixed-microvolt", + &chip->fixed_voltage); + if (error) + return error; + + if (chip->fixed_voltage < SY8106A_MIN_MV * 1000 || + chip->fixed_voltage > SY8106A_MAX_MV * 1000) + return -EINVAL; + + chip->regmap = devm_regmap_init_i2c(i2c, &sy8106a_regmap_config); + if (IS_ERR(chip->regmap)) { + error = PTR_ERR(chip->regmap); + dev_err(dev, "Failed to allocate register map: %d\n", error); + return error; + } + + config.dev = &i2c->dev; + config.regmap = chip->regmap; + config.driver_data = chip; + + config.of_node = dev->of_node; + config.init_data = of_get_regulator_init_data(dev, dev->of_node, + &sy8106a_reg); + + if (!config.init_data) + return -ENOMEM; + + /* Ensure GO_BIT is enabled when probing */ + error = regmap_read(chip->regmap, SY8106A_REG_VOUT1_SEL, ®); + if (error) + return error; + + if (!(reg & SY8106A_GO_BIT)) { + vsel = (chip->fixed_voltage / 1000 - SY8106A_MIN_MV) / + SY8106A_STEP_MV; + + error = regmap_write(chip->regmap, SY8106A_REG_VOUT1_SEL, + vsel | SY8106A_GO_BIT); + if (error) + return error; + } + + /* Probe regulator */ + rdev = devm_regulator_register(&i2c->dev, &sy8106a_reg, &config); + if (IS_ERR(rdev)) { + error = PTR_ERR(rdev); + dev_err(&i2c->dev, "Failed to register SY8106A regulator: %d\n", error); + return error; + } + + chip->rdev = rdev; + + i2c_set_clientdata(i2c, chip); + + return 0; +} + +static const struct of_device_id sy8106a_i2c_of_match[] = { + { .compatible = "silergy,sy8106a" }, + { }, +}; +MODULE_DEVICE_TABLE(of, sy8106a_i2c_of_match); + +static const struct i2c_device_id sy8106a_i2c_id[] = { + { "sy8106a", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, sy8106a_i2c_id); + +static struct i2c_driver sy8106a_regulator_driver = { + .driver = { + .name = "sy8106a", + .of_match_table = of_match_ptr(sy8106a_i2c_of_match), + }, + .probe = sy8106a_i2c_probe, + .id_table = sy8106a_i2c_id, +}; + +module_i2c_driver(sy8106a_regulator_driver); + +MODULE_AUTHOR("OndÅ™ej Jirman "); +MODULE_AUTHOR("Icenowy Zheng "); +MODULE_DESCRIPTION("Regulator device driver for Silergy SY8106A"); +MODULE_LICENSE("GPL"); From 84b3a7c9c6befe5ab4d49070fe7bcab2da22637e Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Tue, 15 May 2018 15:07:17 -0700 Subject: [PATCH 18/57] regulator: core: Allow for regulators that can't be read at bootup Regulators attached via RPMh on Qualcomm sdm845 apparently are write-only. Specifically you can send a request for a certain voltage but you can't read back to see what voltage you've requested. What this means is that at bootup we have absolutely no idea what voltage we could be at. As discussed in the patches to try to support the RPMh regulators [1], the fact that regulators are write-only means that its driver's get_voltage_sel() should return an error code if it's called before any calls to set_voltage_sel(). This causes problems in machine_constraints_voltage() when trying to apply the constraints. A proposed fix was to come up with an error code that could be returned by get_voltage_sel() which would cause the regulator framework to simply try setting the voltage with the current constraints. In this patch I propose the error code -ENOTRECOVERABLE. In errno.h this error is described as "State not recoverable". Though the error code was originally intended "for robust mutexes", the description of the error code seems to apply here because we can't read the state of the regulator. Also note that the only existing user of this error code in the regulator framework is tps65090-regulator.c which returns this error code from the enable() call (not get_voltage() or get_voltage_sel()), so there should be no existing regulators that might accidentally get the new behavior. (Side note is that tps65090 seems to interpret this error code to mean an error that you can't recover from rather than some data that can't be recovered). [1] https://patchwork.kernel.org/patch/10340897/ Signed-off-by: Douglas Anderson Signed-off-by: Mark Brown --- drivers/regulator/core.c | 12 ++++++++++++ include/linux/regulator/driver.h | 7 +++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index d4803460a557..fe314ff56772 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -886,6 +886,18 @@ static int machine_constraints_voltage(struct regulator_dev *rdev, rdev->constraints->min_uV && rdev->constraints->max_uV) { int target_min, target_max; int current_uV = _regulator_get_voltage(rdev); + + if (current_uV == -ENOTRECOVERABLE) { + /* This regulator can't be read and must be initted */ + rdev_info(rdev, "Setting %d-%duV\n", + rdev->constraints->min_uV, + rdev->constraints->max_uV); + _regulator_do_set_voltage(rdev, + rdev->constraints->min_uV, + rdev->constraints->max_uV); + current_uV = _regulator_get_voltage(rdev); + } + if (current_uV < 0) { rdev_err(rdev, "failed to get the current voltage(%d)\n", diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index 4fc96cb8e5d7..14e512ad6d4f 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -81,9 +81,12 @@ struct regulator_linear_range { * @set_voltage_sel: Set the voltage for the regulator using the specified * selector. * @map_voltage: Convert a voltage into a selector - * @get_voltage: Return the currently configured voltage for the regulator. + * @get_voltage: Return the currently configured voltage for the regulator; + * return -ENOTRECOVERABLE if regulator can't be read at + * bootup and hasn't been set yet. * @get_voltage_sel: Return the currently configured voltage selector for the - * regulator. + * regulator; return -ENOTRECOVERABLE if regulator can't + * be read at bootup and hasn't been set yet. * @list_voltage: Return one of the supported voltages, in microvolts; zero * if the selector indicates a voltage that is unusable on this system; * or negative errno. Selectors range from zero to one less than From d73e2842a3e236a1f58ba498e4d6ae58e18f660a Mon Sep 17 00:00:00 2001 From: David Collins Date: Fri, 11 May 2018 18:46:46 -0700 Subject: [PATCH 19/57] regulator: of: add property for allowed modes specification Add a common device tree property for regulator nodes to support the specification of allowed operating modes. Signed-off-by: David Collins Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/regulator/regulator.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/regulator/regulator.txt b/Documentation/devicetree/bindings/regulator/regulator.txt index 2babe15b618d..c627aa08f0da 100644 --- a/Documentation/devicetree/bindings/regulator/regulator.txt +++ b/Documentation/devicetree/bindings/regulator/regulator.txt @@ -59,6 +59,11 @@ Optional properties: - regulator-initial-mode: initial operating mode. The set of possible operating modes depends on the capabilities of every hardware so each device binding documentation explains which values the regulator supports. +- regulator-allowed-modes: list of operating modes that software is allowed to + configure for the regulator at run-time. Elements may be specified in any + order. The set of possible operating modes depends on the capabilities of + every hardware so each device binding document explains which values the + regulator supports. - regulator-system-load: Load in uA present on regulator that is not captured by any consumer request. - regulator-pull-down: Enable pull down resistor when the regulator is disabled. From 54557ad9737e28b06b632cce723ef2373fe6bf12 Mon Sep 17 00:00:00 2001 From: David Collins Date: Fri, 11 May 2018 18:46:47 -0700 Subject: [PATCH 20/57] regulator: of: add support for allowed modes configuration Add support for configuring the machine constraints valid_modes_mask element based on a list of allowed modes specified via a device tree property. Signed-off-by: David Collins Signed-off-by: Mark Brown --- drivers/regulator/of_regulator.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c index 0d3f73eacb99..d61fed28fdb9 100644 --- a/drivers/regulator/of_regulator.c +++ b/drivers/regulator/of_regulator.c @@ -32,7 +32,7 @@ static void of_get_regulation_constraints(struct device_node *np, struct regulator_state *suspend_state; struct device_node *suspend_np; unsigned int mode; - int ret, i; + int ret, i, len; u32 pval; constraints->name = of_get_property(np, "regulator-name", NULL); @@ -136,6 +136,33 @@ static void of_get_regulation_constraints(struct device_node *np, } } + len = of_property_count_elems_of_size(np, "regulator-allowed-modes", + sizeof(u32)); + if (len > 0) { + if (desc && desc->of_map_mode) { + for (i = 0; i < len; i++) { + ret = of_property_read_u32_index(np, + "regulator-allowed-modes", i, &pval); + if (ret) { + pr_err("%s: couldn't read allowed modes index %d, ret=%d\n", + np->name, i, ret); + break; + } + mode = desc->of_map_mode(pval); + if (mode == REGULATOR_MODE_INVALID) + pr_err("%s: invalid regulator-allowed-modes element %u\n", + np->name, pval); + else + constraints->valid_modes_mask |= mode; + } + if (constraints->valid_modes_mask) + constraints->valid_ops_mask + |= REGULATOR_CHANGE_MODE; + } else { + pr_warn("%s: mode mapping not defined\n", np->name); + } + } + if (!of_property_read_u32(np, "regulator-system-load", &pval)) constraints->system_load = pval; From c1472737914fe5246a672fef6e85c9455de8473f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Chmiel?= Date: Fri, 27 Apr 2018 18:02:59 +0200 Subject: [PATCH 21/57] regulator: max8998: Fix platform data retrieval. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since the max8998 MFD driver supports instantiation by DT, platform data retrieval is handled in MFD probe and cell drivers should get use the pdata field of max8998_dev struct to obtain them. Fixes: ee999fb3f17f ("mfd: max8998: Add support for Device Tree") Signed-off-by: PaweÅ‚ Chmiel Signed-off-by: Mark Brown --- drivers/regulator/max8998.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/regulator/max8998.c b/drivers/regulator/max8998.c index 3027e7ce100b..6a2b61c012b5 100644 --- a/drivers/regulator/max8998.c +++ b/drivers/regulator/max8998.c @@ -309,8 +309,7 @@ static int max8998_set_voltage_buck_sel(struct regulator_dev *rdev, unsigned selector) { struct max8998_data *max8998 = rdev_get_drvdata(rdev); - struct max8998_platform_data *pdata = - dev_get_platdata(max8998->iodev->dev); + struct max8998_platform_data *pdata = max8998->iodev->pdata; struct i2c_client *i2c = max8998->iodev->i2c; int buck = rdev_get_id(rdev); int reg, shift = 0, mask, ret, j; From e1739e86f0cb9c48e8745a610e6981a4e24cadad Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 14 May 2018 10:06:24 +0200 Subject: [PATCH 22/57] regulator: arizona-ldo1: Look up a descriptor and pass to the core Instead of passing a global GPIO number, pass a descriptor looked up with the standard devm_gpiod_get_optional() call. We have augmented the GPIO core to look up the regulator special GPIO "wlf,ldoena" in commit 6a537d48461d "gpio: of: Support regulator nonstandard GPIO properties". Signed-off-by: Linus Walleij Acked-by: Charles Keepax Signed-off-by: Mark Brown --- arch/arm/mach-s3c64xx/mach-crag6410-module.c | 28 +++++++++++++++----- drivers/regulator/arizona-ldo1.c | 19 +++++-------- include/linux/regulator/arizona-ldo1.h | 3 --- 3 files changed, 28 insertions(+), 22 deletions(-) diff --git a/arch/arm/mach-s3c64xx/mach-crag6410-module.c b/arch/arm/mach-s3c64xx/mach-crag6410-module.c index f00988705408..5aa472892465 100644 --- a/arch/arm/mach-s3c64xx/mach-crag6410-module.c +++ b/arch/arm/mach-s3c64xx/mach-crag6410-module.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -206,9 +207,6 @@ static const struct i2c_board_info wm1277_devs[] = { }; static struct arizona_pdata wm5102_reva_pdata = { - .ldo1 = { - .ldoena = S3C64XX_GPN(7), - }, .gpio_base = CODEC_GPIO_BASE, .irq_flags = IRQF_TRIGGER_HIGH, .micd_pol_gpio = CODEC_GPIO_BASE + 4, @@ -237,10 +235,16 @@ static struct spi_board_info wm5102_reva_spi_devs[] = { }, }; -static struct arizona_pdata wm5102_pdata = { - .ldo1 = { - .ldoena = S3C64XX_GPN(7), +static struct gpiod_lookup_table wm5102_reva_gpiod_table = { + .dev_id = "spi0.1", /* SPI device name */ + .table = { + GPIO_LOOKUP("GPION", 7, + "wlf,ldoena", GPIO_ACTIVE_HIGH), + { }, }, +}; + +static struct arizona_pdata wm5102_pdata = { .gpio_base = CODEC_GPIO_BASE, .irq_flags = IRQF_TRIGGER_HIGH, .micd_pol_gpio = CODEC_GPIO_BASE + 2, @@ -264,6 +268,15 @@ static struct spi_board_info wm5102_spi_devs[] = { }, }; +static struct gpiod_lookup_table wm5102_gpiod_table = { + .dev_id = "spi0.1", /* SPI device name */ + .table = { + GPIO_LOOKUP("GPION", 7, + "wlf,ldo1ena", GPIO_ACTIVE_HIGH), + { }, + }, +}; + static struct spi_board_info wm5110_spi_devs[] = { [0] = { .modalias = "wm5110", @@ -366,6 +379,9 @@ static int wlf_gf_module_probe(struct i2c_client *i2c, rev == gf_mods[i].rev)) break; + gpiod_add_lookup_table(&wm5102_reva_gpiod_table); + gpiod_add_lookup_table(&wm5102_gpiod_table); + if (i < ARRAY_SIZE(gf_mods)) { dev_info(&i2c->dev, "%s revision %d\n", gf_mods[i].name, rev + 1); diff --git a/drivers/regulator/arizona-ldo1.c b/drivers/regulator/arizona-ldo1.c index 96fddfff5dc4..f6d6a4ad9e8a 100644 --- a/drivers/regulator/arizona-ldo1.c +++ b/drivers/regulator/arizona-ldo1.c @@ -17,12 +17,11 @@ #include #include #include -#include +#include #include #include #include #include -#include #include #include @@ -198,16 +197,6 @@ static int arizona_ldo1_of_get_pdata(struct arizona_ldo1_pdata *pdata, struct device_node *init_node, *dcvdd_node; struct regulator_init_data *init_data; - pdata->ldoena = of_get_named_gpio(np, "wlf,ldoena", 0); - if (pdata->ldoena < 0) { - dev_warn(config->dev, - "LDOENA GPIO property missing/malformed: %d\n", - pdata->ldoena); - pdata->ldoena = 0; - } else { - config->ena_gpio_initialized = true; - } - init_node = of_get_child_by_name(np, "ldo1"); dcvdd_node = of_parse_phandle(np, "DCVDD-supply", 0); @@ -264,7 +253,11 @@ static int arizona_ldo1_common_init(struct platform_device *pdev, } } - config.ena_gpio = pdata->ldoena; + /* We assume that high output = regulator off */ + config.ena_gpiod = devm_gpiod_get_optional(&pdev->dev, "wlf,ldoena", + GPIOD_OUT_HIGH); + if (IS_ERR(config.ena_gpiod)) + return PTR_ERR(config.ena_gpiod); if (pdata->init_data) config.init_data = pdata->init_data; diff --git a/include/linux/regulator/arizona-ldo1.h b/include/linux/regulator/arizona-ldo1.h index c685f1277c63..fe74ab9990e6 100644 --- a/include/linux/regulator/arizona-ldo1.h +++ b/include/linux/regulator/arizona-ldo1.h @@ -14,9 +14,6 @@ struct regulator_init_data; struct arizona_ldo1_pdata { - /** GPIO controlling LDOENA, if any */ - int ldoena; - /** Regulator configuration for LDO1 */ const struct regulator_init_data *init_data; }; From c89c00e2b8f034891d2550df5ba6fae39f3bf563 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 14 May 2018 10:06:26 +0200 Subject: [PATCH 23/57] regulator: max77686: Pass descriptor instead of GPIO number Instead of passing a global GPIO number, pass a descriptor looked up from the device tree configuration node. Signed-off-by: Linus Walleij Reviewed-by: Krzysztof Kozlowski Tested-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- drivers/regulator/max77686-regulator.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/drivers/regulator/max77686-regulator.c b/drivers/regulator/max77686-regulator.c index c301f3733475..37f98a8350f0 100644 --- a/drivers/regulator/max77686-regulator.c +++ b/drivers/regulator/max77686-regulator.c @@ -25,8 +25,7 @@ #include #include #include -#include -#include +#include #include #include #include @@ -90,6 +89,7 @@ enum max77686_ramp_rate { }; struct max77686_data { + struct device *dev; DECLARE_BITMAP(gpio_enabled, MAX77686_REGULATORS); /* Array indexed by regulator id */ @@ -269,16 +269,20 @@ static int max77686_of_parse_cb(struct device_node *np, case MAX77686_BUCK8: case MAX77686_BUCK9: case MAX77686_LDO20 ... MAX77686_LDO22: - config->ena_gpio = of_get_named_gpio(np, - "maxim,ena-gpios", 0); - config->ena_gpio_flags = GPIOF_OUT_INIT_HIGH; - config->ena_gpio_initialized = true; + config->ena_gpiod = devm_gpiod_get_from_of_node(max77686->dev, + np, + "maxim,ena", + 0, + GPIOD_OUT_HIGH, + "max77686-regulator"); + if (IS_ERR(config->ena_gpiod)) + config->ena_gpiod = NULL; break; default: return 0; } - if (gpio_is_valid(config->ena_gpio)) { + if (config->ena_gpiod) { set_bit(desc->id, max77686->gpio_enabled); return regmap_update_bits(config->regmap, desc->enable_reg, @@ -521,6 +525,7 @@ static int max77686_pmic_probe(struct platform_device *pdev) if (!max77686) return -ENOMEM; + max77686->dev = &pdev->dev; config.dev = iodev->dev; config.regmap = iodev->regmap; config.driver_data = max77686; From 0369e02b75e6381f892e3bd45f1d8d6330d855fb Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 14 May 2018 10:06:31 +0200 Subject: [PATCH 24/57] regulator: s2mps11: Pass descriptor instead of GPIO number Instead of passing a global GPIO number for the enable GPIO, pass a descriptor looked up with the standard devm_gpiod_get_optional() call. This regulator supports passing platform data, but enable/sleep regulators are looked up from the device tree exclusively, so we can need not touch other files. Signed-off-by: Linus Walleij Reviewed-by: Krzysztof Kozlowski Tested-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- drivers/regulator/s2mps11.c | 46 ++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c index 7726b874e539..9a1dca26362e 100644 --- a/drivers/regulator/s2mps11.c +++ b/drivers/regulator/s2mps11.c @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include #include @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -57,7 +56,7 @@ struct s2mps11_info { * Array (size: number of regulators) with GPIO-s for external * sleep control. */ - int *ext_control_gpio; + struct gpio_desc **ext_control_gpiod; }; static int get_ramp_delay(int ramp_delay) @@ -524,7 +523,7 @@ static int s2mps14_regulator_enable(struct regulator_dev *rdev) case S2MPS14X: if (test_bit(rdev_get_id(rdev), s2mps11->suspend_state)) val = S2MPS14_ENABLE_SUSPEND; - else if (gpio_is_valid(s2mps11->ext_control_gpio[rdev_get_id(rdev)])) + else if (s2mps11->ext_control_gpiod[rdev_get_id(rdev)]) val = S2MPS14_ENABLE_EXT_CONTROL; else val = rdev->desc->enable_mask; @@ -818,7 +817,7 @@ static int s2mps14_pmic_enable_ext_control(struct s2mps11_info *s2mps11, static void s2mps14_pmic_dt_parse_ext_control_gpio(struct platform_device *pdev, struct of_regulator_match *rdata, struct s2mps11_info *s2mps11) { - int *gpio = s2mps11->ext_control_gpio; + struct gpio_desc **gpio = s2mps11->ext_control_gpiod; unsigned int i; unsigned int valid_regulators[3] = { S2MPS14_LDO10, S2MPS14_LDO11, S2MPS14_LDO12 }; @@ -829,11 +828,20 @@ static void s2mps14_pmic_dt_parse_ext_control_gpio(struct platform_device *pdev, if (!rdata[reg].init_data || !rdata[reg].of_node) continue; - gpio[reg] = of_get_named_gpio(rdata[reg].of_node, - "samsung,ext-control-gpios", 0); - if (gpio_is_valid(gpio[reg])) - dev_dbg(&pdev->dev, "Using GPIO %d for ext-control over %d/%s\n", - gpio[reg], reg, rdata[reg].name); + gpio[reg] = devm_gpiod_get_from_of_node(&pdev->dev, + rdata[reg].of_node, + "samsung,ext-control-gpios", + 0, + GPIOD_OUT_HIGH, + "s2mps11-LDO"); + if (IS_ERR(gpio[reg])) { + dev_err(&pdev->dev, "Failed to get control GPIO for %d/%s\n", + reg, rdata[reg].name); + continue; + } + if (gpio[reg]) + dev_dbg(&pdev->dev, "Using GPIO for ext-control over %d/%s\n", + reg, rdata[reg].name); } } @@ -1139,17 +1147,11 @@ static int s2mps11_pmic_probe(struct platform_device *pdev) return -EINVAL; } - s2mps11->ext_control_gpio = devm_kmalloc(&pdev->dev, - sizeof(*s2mps11->ext_control_gpio) * rdev_num, + s2mps11->ext_control_gpiod = devm_kmalloc(&pdev->dev, + sizeof(*s2mps11->ext_control_gpiod) * rdev_num, GFP_KERNEL); - if (!s2mps11->ext_control_gpio) + if (!s2mps11->ext_control_gpiod) return -ENOMEM; - /* - * 0 is a valid GPIO so initialize all GPIO-s to negative value - * to indicate that external control won't be used for this regulator. - */ - for (i = 0; i < rdev_num; i++) - s2mps11->ext_control_gpio[i] = -EINVAL; if (!iodev->dev->of_node) { if (iodev->pdata) { @@ -1179,8 +1181,6 @@ common_reg: config.dev = &pdev->dev; config.regmap = iodev->regmap_pmic; config.driver_data = s2mps11; - config.ena_gpio_flags = GPIOF_OUT_INIT_HIGH; - config.ena_gpio_initialized = true; for (i = 0; i < rdev_num; i++) { struct regulator_dev *regulator; @@ -1191,7 +1191,7 @@ common_reg: config.init_data = rdata[i].init_data; config.of_node = rdata[i].of_node; } - config.ena_gpio = s2mps11->ext_control_gpio[i]; + config.ena_gpiod = s2mps11->ext_control_gpiod[i]; regulator = devm_regulator_register(&pdev->dev, ®ulators[i], &config); @@ -1202,7 +1202,7 @@ common_reg: goto out; } - if (gpio_is_valid(s2mps11->ext_control_gpio[i])) { + if (s2mps11->ext_control_gpiod[i]) { ret = s2mps14_pmic_enable_ext_control(s2mps11, regulator); if (ret < 0) { From 66cf9a7e0192734c1c94751e628bd075be62cff4 Mon Sep 17 00:00:00 2001 From: Maciej Purski Date: Mon, 23 Apr 2018 16:33:37 +0200 Subject: [PATCH 25/57] regulator: core: Make locks re-entrant Setting voltage, enabling/disabling regulators requires operations on all regulators related with the regulator being changed. Therefore, all of them should be locked for the whole operation. With the current locking implementation, adding additional dependency (regulators coupling) causes deadlocks in some cases. Introduce a possibility to attempt to lock a mutex multiple times by the same task without waiting on a mutex. This should handle all reasonable coupling-supplying combinations, especially when two coupled regulators share common supplies. The only situation that should be forbidden is simultaneous coupling and supplying between a pair of regulators. The idea is based on clk core. Signed-off-by: Maciej Purski Signed-off-by: Mark Brown --- drivers/regulator/core.c | 132 +++++++++++++++++++++---------- include/linux/regulator/driver.h | 2 + 2 files changed, 93 insertions(+), 41 deletions(-) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index fe314ff56772..0ca941b53571 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -146,6 +146,56 @@ static inline struct regulator_dev *rdev_get_supply(struct regulator_dev *rdev) return NULL; } +/** + * regulator_lock_nested - lock a single regulator + * @rdev: regulator source + * @subclass: mutex subclass used for lockdep + * + * This function can be called many times by one task on + * a single regulator and its mutex will be locked only + * once. If a task, which is calling this function is other + * than the one, which initially locked the mutex, it will + * wait on mutex. + */ +static void regulator_lock_nested(struct regulator_dev *rdev, + unsigned int subclass) +{ + if (!mutex_trylock(&rdev->mutex)) { + if (rdev->mutex_owner == current) { + rdev->ref_cnt++; + return; + } + mutex_lock_nested(&rdev->mutex, subclass); + } + + rdev->ref_cnt = 1; + rdev->mutex_owner = current; +} + +static inline void regulator_lock(struct regulator_dev *rdev) +{ + regulator_lock_nested(rdev, 0); +} + +/** + * regulator_unlock - unlock a single regulator + * @rdev: regulator_source + * + * This function unlocks the mutex when the + * reference counter reaches 0. + */ +static void regulator_unlock(struct regulator_dev *rdev) +{ + if (rdev->ref_cnt != 0) { + rdev->ref_cnt--; + + if (!rdev->ref_cnt) { + rdev->mutex_owner = NULL; + mutex_unlock(&rdev->mutex); + } + } +} + /** * regulator_lock_supply - lock a regulator and its supplies * @rdev: regulator source @@ -155,7 +205,7 @@ static void regulator_lock_supply(struct regulator_dev *rdev) int i; for (i = 0; rdev; rdev = rdev_get_supply(rdev), i++) - mutex_lock_nested(&rdev->mutex, i); + regulator_lock_nested(rdev, i); } /** @@ -167,7 +217,7 @@ static void regulator_unlock_supply(struct regulator_dev *rdev) struct regulator *supply; while (1) { - mutex_unlock(&rdev->mutex); + regulator_unlock(rdev); supply = rdev->supply; if (!rdev->supply) @@ -350,9 +400,9 @@ static ssize_t regulator_uV_show(struct device *dev, struct regulator_dev *rdev = dev_get_drvdata(dev); ssize_t ret; - mutex_lock(&rdev->mutex); + regulator_lock(rdev); ret = sprintf(buf, "%d\n", _regulator_get_voltage(rdev)); - mutex_unlock(&rdev->mutex); + regulator_unlock(rdev); return ret; } @@ -416,9 +466,9 @@ static ssize_t regulator_state_show(struct device *dev, struct regulator_dev *rdev = dev_get_drvdata(dev); ssize_t ret; - mutex_lock(&rdev->mutex); + regulator_lock(rdev); ret = regulator_print_state(buf, _regulator_is_enabled(rdev)); - mutex_unlock(&rdev->mutex); + regulator_unlock(rdev); return ret; } @@ -526,10 +576,10 @@ static ssize_t regulator_total_uA_show(struct device *dev, struct regulator *regulator; int uA = 0; - mutex_lock(&rdev->mutex); + regulator_lock(rdev); list_for_each_entry(regulator, &rdev->consumer_list, list) uA += regulator->uA_load; - mutex_unlock(&rdev->mutex); + regulator_unlock(rdev); return sprintf(buf, "%d\n", uA); } static DEVICE_ATTR(requested_microamps, 0444, regulator_total_uA_show, NULL); @@ -1333,7 +1383,7 @@ static struct regulator *create_regulator(struct regulator_dev *rdev, if (regulator == NULL) return NULL; - mutex_lock(&rdev->mutex); + regulator_lock(rdev); regulator->rdev = rdev; list_add(®ulator->list, &rdev->consumer_list); @@ -1388,12 +1438,12 @@ static struct regulator *create_regulator(struct regulator_dev *rdev, _regulator_is_enabled(rdev)) regulator->always_on = true; - mutex_unlock(&rdev->mutex); + regulator_unlock(rdev); return regulator; overflow_err: list_del(®ulator->list); kfree(regulator); - mutex_unlock(&rdev->mutex); + regulator_unlock(rdev); return NULL; } @@ -1782,13 +1832,13 @@ static void _regulator_put(struct regulator *regulator) /* remove any sysfs entries */ if (regulator->dev) sysfs_remove_link(&rdev->dev.kobj, regulator->supply_name); - mutex_lock(&rdev->mutex); + regulator_lock(rdev); list_del(®ulator->list); rdev->open_count--; rdev->exclusive = 0; put_device(&rdev->dev); - mutex_unlock(&rdev->mutex); + regulator_unlock(rdev); kfree_const(regulator->supply_name); kfree(regulator); @@ -2396,7 +2446,7 @@ static void regulator_disable_work(struct work_struct *work) disable_work.work); int count, i, ret; - mutex_lock(&rdev->mutex); + regulator_lock(rdev); BUG_ON(!rdev->deferred_disables); @@ -2417,7 +2467,7 @@ static void regulator_disable_work(struct work_struct *work) rdev_err(rdev, "Deferred disable failed: %d\n", ret); } - mutex_unlock(&rdev->mutex); + regulator_unlock(rdev); if (rdev->supply) { for (i = 0; i < count; i++) { @@ -2452,11 +2502,11 @@ int regulator_disable_deferred(struct regulator *regulator, int ms) if (!ms) return regulator_disable(regulator); - mutex_lock(&rdev->mutex); + regulator_lock(rdev); rdev->deferred_disables++; mod_delayed_work(system_power_efficient_wq, &rdev->disable_work, msecs_to_jiffies(ms)); - mutex_unlock(&rdev->mutex); + regulator_unlock(rdev); return 0; } @@ -2488,10 +2538,10 @@ static int _regulator_list_voltage(struct regulator_dev *rdev, if (selector >= rdev->desc->n_voltages) return -EINVAL; if (lock) - mutex_lock(&rdev->mutex); + regulator_lock(rdev); ret = ops->list_voltage(rdev, selector); if (lock) - mutex_unlock(&rdev->mutex); + regulator_unlock(rdev); } else if (rdev->is_switch && rdev->supply) { ret = _regulator_list_voltage(rdev->supply->rdev, selector, lock); @@ -3264,7 +3314,7 @@ int regulator_sync_voltage(struct regulator *regulator) struct regulator_voltage *voltage = ®ulator->voltage[PM_SUSPEND_ON]; int ret, min_uV, max_uV; - mutex_lock(&rdev->mutex); + regulator_lock(rdev); if (!rdev->desc->ops->set_voltage && !rdev->desc->ops->set_voltage_sel) { @@ -3293,7 +3343,7 @@ int regulator_sync_voltage(struct regulator *regulator) ret = _regulator_do_set_voltage(rdev, min_uV, max_uV); out: - mutex_unlock(&rdev->mutex); + regulator_unlock(rdev); return ret; } EXPORT_SYMBOL_GPL(regulator_sync_voltage); @@ -3386,7 +3436,7 @@ int regulator_set_current_limit(struct regulator *regulator, struct regulator_dev *rdev = regulator->rdev; int ret; - mutex_lock(&rdev->mutex); + regulator_lock(rdev); /* sanity check */ if (!rdev->desc->ops->set_current_limit) { @@ -3401,7 +3451,7 @@ int regulator_set_current_limit(struct regulator *regulator, ret = rdev->desc->ops->set_current_limit(rdev, min_uA, max_uA); out: - mutex_unlock(&rdev->mutex); + regulator_unlock(rdev); return ret; } EXPORT_SYMBOL_GPL(regulator_set_current_limit); @@ -3410,7 +3460,7 @@ static int _regulator_get_current_limit(struct regulator_dev *rdev) { int ret; - mutex_lock(&rdev->mutex); + regulator_lock(rdev); /* sanity check */ if (!rdev->desc->ops->get_current_limit) { @@ -3420,7 +3470,7 @@ static int _regulator_get_current_limit(struct regulator_dev *rdev) ret = rdev->desc->ops->get_current_limit(rdev); out: - mutex_unlock(&rdev->mutex); + regulator_unlock(rdev); return ret; } @@ -3456,7 +3506,7 @@ int regulator_set_mode(struct regulator *regulator, unsigned int mode) int ret; int regulator_curr_mode; - mutex_lock(&rdev->mutex); + regulator_lock(rdev); /* sanity check */ if (!rdev->desc->ops->set_mode) { @@ -3480,7 +3530,7 @@ int regulator_set_mode(struct regulator *regulator, unsigned int mode) ret = rdev->desc->ops->set_mode(rdev, mode); out: - mutex_unlock(&rdev->mutex); + regulator_unlock(rdev); return ret; } EXPORT_SYMBOL_GPL(regulator_set_mode); @@ -3489,7 +3539,7 @@ static unsigned int _regulator_get_mode(struct regulator_dev *rdev) { int ret; - mutex_lock(&rdev->mutex); + regulator_lock(rdev); /* sanity check */ if (!rdev->desc->ops->get_mode) { @@ -3499,7 +3549,7 @@ static unsigned int _regulator_get_mode(struct regulator_dev *rdev) ret = rdev->desc->ops->get_mode(rdev); out: - mutex_unlock(&rdev->mutex); + regulator_unlock(rdev); return ret; } @@ -3520,7 +3570,7 @@ static int _regulator_get_error_flags(struct regulator_dev *rdev, { int ret; - mutex_lock(&rdev->mutex); + regulator_lock(rdev); /* sanity check */ if (!rdev->desc->ops->get_error_flags) { @@ -3530,7 +3580,7 @@ static int _regulator_get_error_flags(struct regulator_dev *rdev, ret = rdev->desc->ops->get_error_flags(rdev, flags); out: - mutex_unlock(&rdev->mutex); + regulator_unlock(rdev); return ret; } @@ -3579,10 +3629,10 @@ int regulator_set_load(struct regulator *regulator, int uA_load) struct regulator_dev *rdev = regulator->rdev; int ret; - mutex_lock(&rdev->mutex); + regulator_lock(rdev); regulator->uA_load = uA_load; ret = drms_uA_update(rdev); - mutex_unlock(&rdev->mutex); + regulator_unlock(rdev); return ret; } @@ -3610,7 +3660,7 @@ int regulator_allow_bypass(struct regulator *regulator, bool enable) if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_BYPASS)) return 0; - mutex_lock(&rdev->mutex); + regulator_lock(rdev); if (enable && !regulator->bypass) { rdev->bypass_count++; @@ -3634,7 +3684,7 @@ int regulator_allow_bypass(struct regulator *regulator, bool enable) if (ret == 0) regulator->bypass = enable; - mutex_unlock(&rdev->mutex); + regulator_unlock(rdev); return ret; } @@ -4300,9 +4350,9 @@ static int _regulator_suspend_late(struct device *dev, void *data) suspend_state_t *state = data; int ret; - mutex_lock(&rdev->mutex); + regulator_lock(rdev); ret = suspend_set_state(rdev, *state); - mutex_unlock(&rdev->mutex); + regulator_unlock(rdev); return ret; } @@ -4332,14 +4382,14 @@ static int _regulator_resume_early(struct device *dev, void *data) if (rstate == NULL) return 0; - mutex_lock(&rdev->mutex); + regulator_lock(rdev); if (rdev->desc->ops->resume_early && (rstate->enabled == ENABLE_IN_SUSPEND || rstate->enabled == DISABLE_IN_SUSPEND)) ret = rdev->desc->ops->resume_early(rdev); - mutex_unlock(&rdev->mutex); + regulator_unlock(rdev); return ret; } @@ -4641,7 +4691,7 @@ static int __init regulator_late_cleanup(struct device *dev, void *data) if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_STATUS)) return 0; - mutex_lock(&rdev->mutex); + regulator_lock(rdev); if (rdev->use_count) goto unlock; @@ -4672,7 +4722,7 @@ static int __init regulator_late_cleanup(struct device *dev, void *data) } unlock: - mutex_unlock(&rdev->mutex); + regulator_unlock(rdev); return 0; } diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index 14e512ad6d4f..c2a181fa7287 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -434,6 +434,8 @@ struct regulator_dev { struct blocking_notifier_head notifier; struct mutex mutex; /* consumer lock */ + struct task_struct *mutex_owner; + int ref_cnt; struct module *owner; struct device dev; struct regulation_constraints *constraints; From f98618b34542706eddc3b66abc271f1c8d8c4a05 Mon Sep 17 00:00:00 2001 From: Maciej Purski Date: Mon, 23 Apr 2018 16:33:38 +0200 Subject: [PATCH 26/57] regulator: bindings: Add properties for coupled regulators Some regulators require keeping their voltage spread below defined max_spread. Add properties to provide information on regulators' coupling. Signed-off-by: Maciej Purski Reviewed-by: Rob Herring Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/regulator/regulator.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/regulator/regulator.txt b/Documentation/devicetree/bindings/regulator/regulator.txt index c627aa08f0da..a7cd36877bfe 100644 --- a/Documentation/devicetree/bindings/regulator/regulator.txt +++ b/Documentation/devicetree/bindings/regulator/regulator.txt @@ -73,6 +73,11 @@ Optional properties: 0: Disable active discharge. 1: Enable active discharge. Absence of this property will leave configuration to default. +- regulator-coupled-with: Regulators with which the regulator + is coupled. The linkage is 2-way - all coupled regulators should be linked + with each other. A regulator should not be coupled with its supplier. +- regulator-coupled-max-spread: Max spread between voltages of coupled regulators + in microvolts. Deprecated properties: - regulator-compatible: If a regulator chip contains multiple From a085a31af566254fb8f7721911c828c8fa797894 Mon Sep 17 00:00:00 2001 From: Maciej Purski Date: Mon, 23 Apr 2018 16:33:39 +0200 Subject: [PATCH 27/57] regulator: core: Parse coupled regulators properties On Odroid XU3/4 and other Exynos5422 based boards there is a case, that different devices on the board are supplied by different regulators with non-fixed voltages. If one of these devices temporarily requires higher voltage, there might occur a situation that the spread between devices' voltages is so high, that there is a risk of changing 'high' and 'low' states on the interconnection between devices powered by those regulators. Add new structure "coupling_desc" to regulator_dev, which contains pointers to all coupled regulators including the owner of the structure, number of coupled regulators and counter of currently resolved regulators. Add of_functions to parse all data needed in regulator coupling. Provide method to check DTS data consistency. Check if each coupled regulator's max_spread is equal and if their lists of regulators match. Signed-off-by: Maciej Purski Signed-off-by: Mark Brown --- drivers/regulator/internal.h | 28 +++++- drivers/regulator/of_regulator.c | 151 ++++++++++++++++++++++++++++++ include/linux/regulator/driver.h | 18 ++++ include/linux/regulator/machine.h | 4 + 4 files changed, 199 insertions(+), 2 deletions(-) diff --git a/drivers/regulator/internal.h b/drivers/regulator/internal.h index 24fde1e08f3a..943926a156f2 100644 --- a/drivers/regulator/internal.h +++ b/drivers/regulator/internal.h @@ -62,6 +62,14 @@ struct regulator_init_data *regulator_of_get_init_data(struct device *dev, const struct regulator_desc *desc, struct regulator_config *config, struct device_node **node); + +struct regulator_dev *of_parse_coupled_regulator(struct regulator_dev *rdev, + int index); + +int of_get_n_coupled(struct regulator_dev *rdev); + +bool of_check_coupling_data(struct regulator_dev *rdev); + #else static inline struct regulator_dev * of_find_regulator_by_node(struct device_node *np) @@ -77,8 +85,25 @@ regulator_of_get_init_data(struct device *dev, { return NULL; } -#endif +static inline struct regulator_dev * +of_parse_coupled_regulator(struct regulator_dev *rdev, + int index) +{ + return NULL; +} + +static inline int of_get_n_coupled(struct regulator_dev *rdev) +{ + return 0; +} + +static inline bool of_check_coupling_data(struct regulator_dev *rdev) +{ + return false; +} + +#endif enum regulator_get_type { NORMAL_GET, EXCLUSIVE_GET, @@ -88,5 +113,4 @@ enum regulator_get_type { struct regulator *_regulator_get(struct device *dev, const char *id, enum regulator_get_type get_type); - #endif diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c index d61fed28fdb9..638f17d4c848 100644 --- a/drivers/regulator/of_regulator.c +++ b/drivers/regulator/of_regulator.c @@ -166,6 +166,10 @@ static void of_get_regulation_constraints(struct device_node *np, if (!of_property_read_u32(np, "regulator-system-load", &pval)) constraints->system_load = pval; + if (!of_property_read_u32(np, "regulator-coupled-max-spread", + &pval)) + constraints->max_spread = pval; + constraints->over_current_protection = of_property_read_bool(np, "regulator-over-current-protection"); @@ -435,3 +439,150 @@ struct regulator_dev *of_find_regulator_by_node(struct device_node *np) return dev ? dev_to_rdev(dev) : NULL; } + +/* + * Returns number of regulators coupled with rdev. + */ +int of_get_n_coupled(struct regulator_dev *rdev) +{ + struct device_node *node = rdev->dev.of_node; + int n_phandles; + + n_phandles = of_count_phandle_with_args(node, + "regulator-coupled-with", + NULL); + + return (n_phandles > 0) ? n_phandles : 0; +} + +/* Looks for "to_find" device_node in src's "regulator-coupled-with" property */ +static bool of_coupling_find_node(struct device_node *src, + struct device_node *to_find) +{ + int n_phandles, i; + bool found = false; + + n_phandles = of_count_phandle_with_args(src, + "regulator-coupled-with", + NULL); + + for (i = 0; i < n_phandles; i++) { + struct device_node *tmp = of_parse_phandle(src, + "regulator-coupled-with", i); + + if (!tmp) + break; + + /* found */ + if (tmp == to_find) + found = true; + + of_node_put(tmp); + + if (found) + break; + } + + return found; +} + +/** + * of_check_coupling_data - Parse rdev's coupling properties and check data + * consistency + * @rdev - pointer to regulator_dev whose data is checked + * + * Function checks if all the following conditions are met: + * - rdev's max_spread is greater than 0 + * - all coupled regulators have the same max_spread + * - all coupled regulators have the same number of regulator_dev phandles + * - all regulators are linked to each other + * + * Returns true if all conditions are met. + */ +bool of_check_coupling_data(struct regulator_dev *rdev) +{ + int max_spread = rdev->constraints->max_spread; + struct device_node *node = rdev->dev.of_node; + int n_phandles = of_get_n_coupled(rdev); + struct device_node *c_node; + int i; + bool ret = true; + + if (max_spread <= 0) { + dev_err(&rdev->dev, "max_spread value invalid\n"); + return false; + } + + /* iterate over rdev's phandles */ + for (i = 0; i < n_phandles; i++) { + int c_max_spread, c_n_phandles; + + c_node = of_parse_phandle(node, + "regulator-coupled-with", i); + + if (!c_node) + ret = false; + + c_n_phandles = of_count_phandle_with_args(c_node, + "regulator-coupled-with", + NULL); + + if (c_n_phandles != n_phandles) { + dev_err(&rdev->dev, "number of couped reg phandles mismatch\n"); + ret = false; + goto clean; + } + + if (of_property_read_u32(c_node, "regulator-coupled-max-spread", + &c_max_spread)) { + ret = false; + goto clean; + } + + if (c_max_spread != max_spread) { + dev_err(&rdev->dev, + "coupled regulators max_spread mismatch\n"); + ret = false; + goto clean; + } + + if (!of_coupling_find_node(c_node, node)) { + dev_err(&rdev->dev, "missing 2-way linking for coupled regulators\n"); + ret = false; + } + +clean: + of_node_put(c_node); + if (!ret) + break; + } + + return ret; +} + +/** + * of_parse_coupled regulator - Get regulator_dev pointer from rdev's property + * @rdev: Pointer to regulator_dev, whose DTS is used as a source to parse + * "regulator-coupled-with" property + * @index: Index in phandles array + * + * Returns the regulator_dev pointer parsed from DTS. If it has not been yet + * registered, returns NULL + */ +struct regulator_dev *of_parse_coupled_regulator(struct regulator_dev *rdev, + int index) +{ + struct device_node *node = rdev->dev.of_node; + struct device_node *c_node; + struct regulator_dev *c_rdev; + + c_node = of_parse_phandle(node, "regulator-coupled-with", index); + if (!c_node) + return NULL; + + c_rdev = of_find_regulator_by_node(c_node); + + of_node_put(c_node); + + return c_rdev; +} diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index c2a181fa7287..fc2dc8df476f 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -15,6 +15,8 @@ #ifndef __LINUX_REGULATOR_DRIVER_H_ #define __LINUX_REGULATOR_DRIVER_H_ +#define MAX_COUPLED 4 + #include #include #include @@ -409,6 +411,20 @@ struct regulator_config { unsigned int ena_gpio_flags; }; +/* + * struct coupling_desc + * + * Describes coupling of regulators. Each regulator should have + * at least a pointer to itself in coupled_rdevs array. + * When a new coupled regulator is resolved, n_resolved is + * incremented. + */ +struct coupling_desc { + struct regulator_dev *coupled_rdevs[MAX_COUPLED]; + int n_resolved; + int n_coupled; +}; + /* * struct regulator_dev * @@ -432,6 +448,8 @@ struct regulator_dev { /* lists we own */ struct list_head consumer_list; /* consumers we supply */ + struct coupling_desc coupling_desc; + struct blocking_notifier_head notifier; struct mutex mutex; /* consumer lock */ struct task_struct *mutex_owner; diff --git a/include/linux/regulator/machine.h b/include/linux/regulator/machine.h index 93a04893c739..3468703d663a 100644 --- a/include/linux/regulator/machine.h +++ b/include/linux/regulator/machine.h @@ -103,6 +103,7 @@ struct regulator_state { * @ilim_uA: Maximum input current. * @system_load: Load that isn't captured by any consumer requests. * + * @max_spread: Max possible spread between coupled regulators * @valid_modes_mask: Mask of modes which may be configured by consumers. * @valid_ops_mask: Operations which may be performed by consumers. * @@ -154,6 +155,9 @@ struct regulation_constraints { int system_load; + /* used for coupled regulators */ + int max_spread; + /* valid regulator operating modes for this machine */ unsigned int valid_modes_mask; From d3d64537c33956c94cfa2376b87d8917868a0f5e Mon Sep 17 00:00:00 2001 From: Maciej Purski Date: Mon, 23 Apr 2018 16:33:40 +0200 Subject: [PATCH 28/57] regulator: core: Resolve coupled regulators On Odroid XU3/4 and other Exynos5422 based boards there is a case, that different devices on the board are supplied by different regulators with non-fixed voltages. If one of these devices temporarily requires higher voltage, there might occur a situation that the spread between two devices' voltages is so high, that there is a risk of changing 'high' and 'low' states on the interconnection between devices powered by those regulators. Fill coupling descriptor with data obtained from DTS using previously defined of_functions. Fail to register a regulator, if some data inconsistency occurs. If some coupled regulators are not yet registered, don't fail to register, but try to resolve them in late init call. Signed-off-by: Maciej Purski Signed-off-by: Mark Brown --- drivers/regulator/core.c | 100 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 0ca941b53571..6ed568b96c0e 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -4129,6 +4129,96 @@ static int regulator_register_resolve_supply(struct device *dev, void *data) return 0; } +static int regulator_fill_coupling_array(struct regulator_dev *rdev) +{ + struct coupling_desc *c_desc = &rdev->coupling_desc; + int n_coupled = c_desc->n_coupled; + struct regulator_dev *c_rdev; + int i; + + for (i = 1; i < n_coupled; i++) { + /* already resolved */ + if (c_desc->coupled_rdevs[i]) + continue; + + c_rdev = of_parse_coupled_regulator(rdev, i - 1); + + if (c_rdev) { + c_desc->coupled_rdevs[i] = c_rdev; + c_desc->n_resolved++; + } + } + + if (rdev->coupling_desc.n_resolved < n_coupled) + return -1; + else + return 0; +} + +static int regulator_register_fill_coupling_array(struct device *dev, + void *data) +{ + struct regulator_dev *rdev = dev_to_rdev(dev); + + if (!IS_ENABLED(CONFIG_OF)) + return 0; + + if (regulator_fill_coupling_array(rdev)) + rdev_dbg(rdev, "unable to resolve coupling\n"); + + return 0; +} + +static int regulator_resolve_coupling(struct regulator_dev *rdev) +{ + int n_phandles; + + if (!IS_ENABLED(CONFIG_OF)) + n_phandles = 0; + else + n_phandles = of_get_n_coupled(rdev); + + if (n_phandles + 1 > MAX_COUPLED) { + rdev_err(rdev, "too many regulators coupled\n"); + return -EPERM; + } + + /* + * Every regulator should always have coupling descriptor filled with + * at least pointer to itself. + */ + rdev->coupling_desc.coupled_rdevs[0] = rdev; + rdev->coupling_desc.n_coupled = n_phandles + 1; + rdev->coupling_desc.n_resolved++; + + /* regulator isn't coupled */ + if (n_phandles == 0) + return 0; + + /* regulator, which can't change its voltage, can't be coupled */ + if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_VOLTAGE)) { + rdev_err(rdev, "voltage operation not allowed\n"); + return -EPERM; + } + + if (rdev->constraints->max_spread <= 0) { + rdev_err(rdev, "wrong max_spread value\n"); + return -EPERM; + } + + if (!of_check_coupling_data(rdev)) + return -EPERM; + + /* + * After everything has been checked, try to fill rdevs array + * with pointers to regulators parsed from device tree. If some + * regulators are not registered yet, retry in late init call + */ + regulator_fill_coupling_array(rdev); + + return 0; +} + /** * regulator_register - register regulator * @regulator_desc: regulator to register @@ -4262,6 +4352,13 @@ regulator_register(const struct regulator_desc *regulator_desc, if (ret < 0) goto wash; + mutex_lock(®ulator_list_mutex); + ret = regulator_resolve_coupling(rdev); + mutex_unlock(®ulator_list_mutex); + + if (ret != 0) + goto wash; + /* add consumers devices */ if (init_data) { mutex_lock(®ulator_list_mutex); @@ -4756,6 +4853,9 @@ static int __init regulator_init_complete(void) class_for_each_device(®ulator_class, NULL, NULL, regulator_late_cleanup); + class_for_each_device(®ulator_class, NULL, NULL, + regulator_register_fill_coupling_array); + return 0; } late_initcall_sync(regulator_init_complete); From 696861761a58d8c93605b5663824929fb6540f16 Mon Sep 17 00:00:00 2001 From: Maciej Purski Date: Mon, 23 Apr 2018 16:33:41 +0200 Subject: [PATCH 29/57] regulator: core: Add voltage balancing mechanism On Odroid XU3/4 and other Exynos5422 based boards there is a case, that different devices on the board are supplied by different regulators with non-fixed voltages. If one of these devices temporarily requires higher voltage, there might occur a situation that the spread between two devices' voltages is so high, that there is a risk of changing 'high' and 'low' states on the interconnection between devices powered by those regulators. Introduce new function regulator_balance_voltage(), which keeps max_spread constraint fulfilled between a group of coupled regulators. It should be called if a regulator changes its voltage or after disabling or enabling. Disabled regulators should follow changes of the enabled ones, but their consumers' demands shouldn't be taken into account while calculating voltage of other coupled regulators. Find voltages, which are closest to suiting all the consumers' demands, while fulfilling max_spread constraint, keeping the following rules: - if one regulator is about to rise its voltage, rise others voltages in order to keep the max_spread - if a regulator, which has caused rising other regulators, is lowered, lower other regulators if possible - if one regulator is about to lower its voltage, but it hasn't caused rising other regulators, don't change its voltage if it breaks the max_spread Change regulators' voltages step by step, keeping max_spread constraint fulfilled all the time. Function regulator_get_optimal_voltage() should find the best possible change for the regulator, which doesn't break max_spread constraint. In function regulator_balance_voltage() optimize number of steps by finding highest voltage difference on each iteration. If a regulator, which is about to change its voltage, is not coupled, method regulator_get_optimal_voltage() should simply return the lowest voltage fulfilling consumers' demands. Coupling should be checked only if the system is in PM_SUSPEND_ON state. Signed-off-by: Maciej Purski Signed-off-by: Mark Brown --- drivers/regulator/core.c | 192 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 192 insertions(+) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 6ed568b96c0e..225eaca24921 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -105,6 +105,8 @@ static int _notifier_call_chain(struct regulator_dev *rdev, unsigned long event, void *data); static int _regulator_do_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV); +static int regulator_balance_voltage(struct regulator_dev *rdev, + suspend_state_t state); static struct regulator *create_regulator(struct regulator_dev *rdev, struct device *dev, const char *supply_name); @@ -3102,6 +3104,196 @@ out2: return ret; } +static int regulator_get_optimal_voltage(struct regulator_dev *rdev) +{ + struct coupling_desc *c_desc = &rdev->coupling_desc; + struct regulator_dev **c_rdevs = c_desc->coupled_rdevs; + int max_spread = rdev->constraints->max_spread; + int n_coupled = c_desc->n_coupled; + int desired_min_uV, desired_max_uV, min_current_uV = INT_MAX; + int max_current_uV = 0, highest_min_uV = 0, target_uV, possible_uV; + int i, ret; + + /* If consumers don't provide any demands, set voltage to min_uV */ + desired_min_uV = rdev->constraints->min_uV; + desired_max_uV = rdev->constraints->max_uV; + ret = regulator_check_consumers(rdev, + &desired_min_uV, + &desired_max_uV, PM_SUSPEND_ON); + if (ret < 0) + goto out; + + /* + * If there are no coupled regulators, simply set the voltage demanded + * by consumers. + */ + if (n_coupled == 1) { + ret = desired_min_uV; + goto out; + } + + /* Find highest min desired voltage */ + for (i = 0; i < n_coupled; i++) { + int tmp_min = 0; + int tmp_max = INT_MAX; + + if (!_regulator_is_enabled(c_rdevs[i])) + continue; + + ret = regulator_check_consumers(c_rdevs[i], + &tmp_min, + &tmp_max, PM_SUSPEND_ON); + if (ret < 0) + goto out; + + if (tmp_min > highest_min_uV) + highest_min_uV = tmp_min; + } + + /* + * Let target_uV be equal to the desired one if possible. + * If not, set it to minimum voltage, allowed by other coupled + * regulators. + */ + target_uV = max(desired_min_uV, highest_min_uV - max_spread); + + /* + * Find min and max voltages, which currently aren't + * violating max_spread + */ + for (i = 0; i < n_coupled; i++) { + int tmp_act; + + /* + * Don't check the regulator, which is about + * to change voltage + */ + if (c_rdevs[i] == rdev) + continue; + if (!_regulator_is_enabled(c_rdevs[i])) + continue; + + tmp_act = _regulator_get_voltage(c_rdevs[i]); + if (tmp_act < 0) { + ret = tmp_act; + goto out; + } + + if (tmp_act < min_current_uV) + min_current_uV = tmp_act; + + if (tmp_act > max_current_uV) + max_current_uV = tmp_act; + } + + /* There aren't any other regulators enabled */ + if (max_current_uV == 0) { + possible_uV = target_uV; + } else { + /* + * Correct target voltage, so as it currently isn't + * violating max_spread + */ + possible_uV = max(target_uV, max_current_uV - max_spread); + possible_uV = min(possible_uV, min_current_uV + max_spread); + } + + if (possible_uV > desired_max_uV) { + ret = -EINVAL; + goto out; + } + ret = possible_uV; + +out: + return ret; +} + +static int regulator_balance_voltage(struct regulator_dev *rdev, + suspend_state_t state) +{ + struct regulator_dev **c_rdevs; + struct regulator_dev *best_rdev; + struct coupling_desc *c_desc = &rdev->coupling_desc; + int n_coupled; + int i, best_delta, best_uV, ret = 1; + + c_rdevs = c_desc->coupled_rdevs; + n_coupled = c_desc->n_coupled; + + /* + * if system is in a state other than PM_SUSPEND_ON, don't check + * other coupled regulators + */ + if (state != PM_SUSPEND_ON) + n_coupled = 1; + + /* + * Find the best possible voltage change on each loop. Leave the loop + * if there isn't any possible change. + */ + while (1) { + best_delta = 0; + best_uV = 0; + best_rdev = NULL; + + /* + * Find highest difference between optimal voltage + * and current voltage. + */ + for (i = 0; i < n_coupled; i++) { + /* + * optimal_uV is the best voltage that can be set for + * i-th regulator at the moment without violating + * max_spread constraint in order to balance + * the coupled voltages. + */ + int optimal_uV, current_uV; + + optimal_uV = regulator_get_optimal_voltage(c_rdevs[i]); + if (optimal_uV < 0) { + ret = optimal_uV; + goto out; + } + + current_uV = _regulator_get_voltage(c_rdevs[i]); + if (current_uV < 0) { + ret = optimal_uV; + goto out; + } + + if (abs(best_delta) < abs(optimal_uV - current_uV)) { + best_delta = optimal_uV - current_uV; + best_rdev = c_rdevs[i]; + best_uV = optimal_uV; + } + } + + /* Nothing to change, return successfully */ + if (!best_rdev) { + ret = 0; + goto out; + } + + /* + * Lock just the supply regulators, as the regulator itself + * is already locked by regulator_lock_coupled(). + */ + if (best_rdev->supply) + regulator_lock_supply(best_rdev->supply->rdev); + + ret = regulator_set_voltage_rdev(best_rdev, best_uV, + best_uV, state); + if (best_rdev->supply) + regulator_unlock_supply(best_rdev->supply->rdev); + + if (ret < 0) + goto out; + } + +out: + return ret; +} + /** * regulator_set_voltage - set regulator output voltage * @regulator: regulator source From 456e7cdf3b1a14e2606b8b687385ab2e3f23a49a Mon Sep 17 00:00:00 2001 From: Maciej Purski Date: Mon, 23 Apr 2018 16:33:42 +0200 Subject: [PATCH 30/57] regulator: core: Change voltage setting path On Odroid XU3/4 and other Exynos5422 based boards there is a case, that different devices on the board are supplied by different regulators with non-fixed voltages. If one of these devices temporarily requires higher voltage, there might occur a situation that the spread between two devices' voltages is so high, that there is a risk of changing 'high' and 'low' states on the interconnection between devices powered by those regulators. Uncoupled regulators should be a special case of coupled regulators, so they should share a common voltage setting path. When enabling, disabling or setting voltage of a coupled regulator, all coupled regulators should be locked. Regulator's supplies should be locked, when setting voltage of a single regulator. Enabling a coupled regulator or setting its voltage should not be possible if some of its coupled regulators, has not been registered. Add function for locking coupled regulators and supplies. Extract a new function regulator_set_voltage_rdev() from regulator_set_voltage_unlocked(), which is called when setting voltage of a single regulator. Signed-off-by: Maciej Purski Signed-off-by: Mark Brown --- drivers/regulator/core.c | 159 ++++++++++++++++++++++++++------------- 1 file changed, 107 insertions(+), 52 deletions(-) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 225eaca24921..ac97e21bff10 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -107,6 +107,9 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV); static int regulator_balance_voltage(struct regulator_dev *rdev, suspend_state_t state); +static int regulator_set_voltage_rdev(struct regulator_dev *rdev, + int min_uV, int max_uV, + suspend_state_t state); static struct regulator *create_regulator(struct regulator_dev *rdev, struct device *dev, const char *supply_name); @@ -198,37 +201,66 @@ static void regulator_unlock(struct regulator_dev *rdev) } } -/** - * regulator_lock_supply - lock a regulator and its supplies - * @rdev: regulator source - */ -static void regulator_lock_supply(struct regulator_dev *rdev) +static int regulator_lock_recursive(struct regulator_dev *rdev, + unsigned int subclass) { + struct regulator_dev *c_rdev; int i; - for (i = 0; rdev; rdev = rdev_get_supply(rdev), i++) - regulator_lock_nested(rdev, i); + for (i = 0; i < rdev->coupling_desc.n_coupled; i++) { + c_rdev = rdev->coupling_desc.coupled_rdevs[i]; + + if (!c_rdev) + continue; + + regulator_lock_nested(c_rdev, subclass++); + + if (c_rdev->supply) + subclass = + regulator_lock_recursive(c_rdev->supply->rdev, + subclass); + } + + return subclass; } /** - * regulator_unlock_supply - unlock a regulator and its supplies - * @rdev: regulator source + * regulator_unlock_dependent - unlock regulator's suppliers and coupled + * regulators + * @rdev: regulator source + * + * Unlock all regulators related with rdev by coupling or suppling. */ -static void regulator_unlock_supply(struct regulator_dev *rdev) +static void regulator_unlock_dependent(struct regulator_dev *rdev) { - struct regulator *supply; + struct regulator_dev *c_rdev; + int i; - while (1) { - regulator_unlock(rdev); - supply = rdev->supply; + for (i = 0; i < rdev->coupling_desc.n_coupled; i++) { + c_rdev = rdev->coupling_desc.coupled_rdevs[i]; - if (!rdev->supply) - return; + if (!c_rdev) + continue; - rdev = supply->rdev; + regulator_unlock(c_rdev); + + if (c_rdev->supply) + regulator_unlock_dependent(c_rdev->supply->rdev); } } +/** + * regulator_lock_dependent - lock regulator's suppliers and coupled regulators + * @rdev: regulator source + * + * This function as a wrapper on regulator_lock_recursive(), which locks + * all regulators related with rdev by coupling or suppling. + */ +static inline void regulator_lock_dependent(struct regulator_dev *rdev) +{ + regulator_lock_recursive(rdev, 0); +} + /** * of_get_regulator - get a regulator device node based on supply name * @dev: Device pointer for the consumer (of regulator) device @@ -2261,6 +2293,11 @@ int regulator_enable(struct regulator *regulator) struct regulator_dev *rdev = regulator->rdev; int ret = 0; + if (rdev->coupling_desc.n_resolved != rdev->coupling_desc.n_coupled) { + rdev_err(rdev, "not all coupled regulators registered\n"); + return -EPERM; + } + if (regulator->always_on) return 0; @@ -2270,9 +2307,12 @@ int regulator_enable(struct regulator *regulator) return ret; } - mutex_lock(&rdev->mutex); + regulator_lock_dependent(rdev); ret = _regulator_enable(rdev); - mutex_unlock(&rdev->mutex); + /* balance only if there are regulators coupled */ + if (rdev->coupling_desc.n_coupled > 1) + regulator_balance_voltage(rdev, PM_SUSPEND_ON); + regulator_unlock_dependent(rdev); if (ret != 0 && rdev->supply) regulator_disable(rdev->supply); @@ -2378,9 +2418,11 @@ int regulator_disable(struct regulator *regulator) if (regulator->always_on) return 0; - mutex_lock(&rdev->mutex); + regulator_lock_dependent(rdev); ret = _regulator_disable(rdev); - mutex_unlock(&rdev->mutex); + if (rdev->coupling_desc.n_coupled > 1) + regulator_balance_voltage(rdev, PM_SUSPEND_ON); + regulator_unlock_dependent(rdev); if (ret == 0 && rdev->supply) regulator_disable(rdev->supply); @@ -2429,10 +2471,12 @@ int regulator_force_disable(struct regulator *regulator) struct regulator_dev *rdev = regulator->rdev; int ret; - mutex_lock(&rdev->mutex); + regulator_lock_dependent(rdev); regulator->uA_load = 0; ret = _regulator_force_disable(regulator->rdev); - mutex_unlock(&rdev->mutex); + if (rdev->coupling_desc.n_coupled > 1) + regulator_balance_voltage(rdev, PM_SUSPEND_ON); + regulator_unlock_dependent(rdev); if (rdev->supply) while (rdev->open_count--) @@ -2580,9 +2624,9 @@ int regulator_is_enabled(struct regulator *regulator) if (regulator->always_on) return 1; - mutex_lock(®ulator->rdev->mutex); + regulator_lock_dependent(regulator->rdev); ret = _regulator_is_enabled(regulator->rdev); - mutex_unlock(®ulator->rdev->mutex); + regulator_unlock_dependent(regulator->rdev); return ret; } @@ -2991,8 +3035,12 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator, int ret = 0; int old_min_uV, old_max_uV; int current_uV; - int best_supply_uV = 0; - int supply_change_uV = 0; + + if (rdev->coupling_desc.n_resolved != rdev->coupling_desc.n_coupled) { + rdev_err(rdev, "not all coupled regulators registered\n"); + ret = -EPERM; + goto out; + } /* If we're setting the same range as last time the change * should be a noop (some cpufreq implementations use the same @@ -3036,6 +3084,27 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator, if (ret < 0) goto out2; + /* for not coupled regulators this will just set the voltage */ + ret = regulator_balance_voltage(rdev, state); + if (ret < 0) + goto out2; + +out: + return 0; +out2: + voltage->min_uV = old_min_uV; + voltage->max_uV = old_max_uV; + + return ret; +} + +static int regulator_set_voltage_rdev(struct regulator_dev *rdev, int min_uV, + int max_uV, suspend_state_t state) +{ + int best_supply_uV = 0; + int supply_change_uV = 0; + int ret; + if (rdev->supply && regulator_ops_is_valid(rdev->supply->rdev, REGULATOR_CHANGE_VOLTAGE) && @@ -3047,13 +3116,13 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator, selector = regulator_map_voltage(rdev, min_uV, max_uV); if (selector < 0) { ret = selector; - goto out2; + goto out; } best_supply_uV = _regulator_list_voltage(rdev, selector, 0); if (best_supply_uV < 0) { ret = best_supply_uV; - goto out2; + goto out; } best_supply_uV += rdev->desc->min_dropout_uV; @@ -3061,7 +3130,7 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator, current_supply_uV = _regulator_get_voltage(rdev->supply->rdev); if (current_supply_uV < 0) { ret = current_supply_uV; - goto out2; + goto out; } supply_change_uV = best_supply_uV - current_supply_uV; @@ -3073,7 +3142,7 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator, if (ret) { dev_err(&rdev->dev, "Failed to increase supply voltage: %d\n", ret); - goto out2; + goto out; } } @@ -3083,7 +3152,7 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator, ret = _regulator_do_set_suspend_voltage(rdev, min_uV, max_uV, state); if (ret < 0) - goto out2; + goto out; if (supply_change_uV < 0) { ret = regulator_set_voltage_unlocked(rdev->supply, @@ -3096,11 +3165,6 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator, } out: - return ret; -out2: - voltage->min_uV = old_min_uV; - voltage->max_uV = old_max_uV; - return ret; } @@ -3274,17 +3338,8 @@ static int regulator_balance_voltage(struct regulator_dev *rdev, goto out; } - /* - * Lock just the supply regulators, as the regulator itself - * is already locked by regulator_lock_coupled(). - */ - if (best_rdev->supply) - regulator_lock_supply(best_rdev->supply->rdev); - ret = regulator_set_voltage_rdev(best_rdev, best_uV, best_uV, state); - if (best_rdev->supply) - regulator_unlock_supply(best_rdev->supply->rdev); if (ret < 0) goto out; @@ -3316,12 +3371,12 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV) { int ret = 0; - regulator_lock_supply(regulator->rdev); + regulator_lock_dependent(regulator->rdev); ret = regulator_set_voltage_unlocked(regulator, min_uV, max_uV, PM_SUSPEND_ON); - regulator_unlock_supply(regulator->rdev); + regulator_unlock_dependent(regulator->rdev); return ret; } @@ -3399,12 +3454,12 @@ int regulator_set_suspend_voltage(struct regulator *regulator, int min_uV, if (regulator_check_states(state) || state == PM_SUSPEND_ON) return -EINVAL; - regulator_lock_supply(regulator->rdev); + regulator_lock_dependent(regulator->rdev); ret = _regulator_set_suspend_voltage(regulator, min_uV, max_uV, state); - regulator_unlock_supply(regulator->rdev); + regulator_unlock_dependent(regulator->rdev); return ret; } @@ -3596,11 +3651,11 @@ int regulator_get_voltage(struct regulator *regulator) { int ret; - regulator_lock_supply(regulator->rdev); + regulator_lock_dependent(regulator->rdev); ret = _regulator_get_voltage(regulator->rdev); - regulator_unlock_supply(regulator->rdev); + regulator_unlock_dependent(regulator->rdev); return ret; } From 3c6b38d45fa51c7c51c5e2347fc1a6bef6a46525 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 14 May 2018 10:06:34 +0200 Subject: [PATCH 31/57] regulator: wm8994: Pass descriptor instead of GPIO number Instead of passing a global GPIO number for the enable GPIO, pass a descriptor looked up from the device tree node or the board file decriptor table for the regulator. There is a single board file passing the GPIOs for LDO1 and LDO2 through platform data, so augment this to pass descriptors associated with the i2c device as well. The special GPIO enable DT property for the enable GPIO is nonstandard but this was accomodated in commit 6a537d48461deacc57c07ed86d9915e5aa4b3539 "gpio: of: Support regulator nonstandard GPIO properties". Signed-off-by: Linus Walleij Acked-by: Charles Keepax Acked-by: Lee Jones Signed-off-by: Mark Brown --- arch/arm/mach-s3c64xx/mach-crag6410-module.c | 17 +++++++++++++++-- drivers/mfd/wm8994-core.c | 9 --------- drivers/regulator/wm8994-regulator.c | 19 +++++++++++-------- include/linux/mfd/wm8994/pdata.h | 3 --- 4 files changed, 26 insertions(+), 22 deletions(-) diff --git a/arch/arm/mach-s3c64xx/mach-crag6410-module.c b/arch/arm/mach-s3c64xx/mach-crag6410-module.c index 5aa472892465..76c4855a03bc 100644 --- a/arch/arm/mach-s3c64xx/mach-crag6410-module.c +++ b/arch/arm/mach-s3c64xx/mach-crag6410-module.c @@ -194,8 +194,8 @@ static struct wm8994_pdata wm8994_pdata = { 0x3, /* IRQ out, active high, CMOS */ }, .ldo = { - { .enable = S3C64XX_GPN(6), .init_data = &wm8994_ldo1, }, - { .enable = S3C64XX_GPN(4), .init_data = &wm8994_ldo2, }, + { .init_data = &wm8994_ldo1, }, + { .init_data = &wm8994_ldo2, }, }, }; @@ -203,6 +203,18 @@ static const struct i2c_board_info wm1277_devs[] = { { I2C_BOARD_INFO("wm8958", 0x1a), /* WM8958 is the superset */ .platform_data = &wm8994_pdata, .irq = GLENFARCLAS_PMIC_IRQ_BASE + WM831X_IRQ_GPIO_2, + .dev_name = "wm8958", + }, +}; + +static struct gpiod_lookup_table wm8994_gpiod_table = { + .dev_id = "i2c-wm8958", /* I2C device name */ + .table = { + GPIO_LOOKUP("GPION", 6, + "wlf,ldo1ena", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("GPION", 4, + "wlf,ldo2ena", GPIO_ACTIVE_HIGH), + { }, }, }; @@ -381,6 +393,7 @@ static int wlf_gf_module_probe(struct i2c_client *i2c, gpiod_add_lookup_table(&wm5102_reva_gpiod_table); gpiod_add_lookup_table(&wm5102_gpiod_table); + gpiod_add_lookup_table(&wm8994_gpiod_table); if (i < ARRAY_SIZE(gf_mods)) { dev_info(&i2c->dev, "%s revision %d\n", diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c index 953d0790ffd5..c409464231f6 100644 --- a/drivers/mfd/wm8994-core.c +++ b/drivers/mfd/wm8994-core.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include @@ -302,14 +301,6 @@ static int wm8994_set_pdata_from_of(struct wm8994 *wm8994) if (of_find_property(np, "wlf,ldoena-always-driven", NULL)) pdata->lineout2fb = true; - pdata->ldo[0].enable = of_get_named_gpio(np, "wlf,ldo1ena", 0); - if (pdata->ldo[0].enable < 0) - pdata->ldo[0].enable = 0; - - pdata->ldo[1].enable = of_get_named_gpio(np, "wlf,ldo2ena", 0); - if (pdata->ldo[1].enable < 0) - pdata->ldo[1].enable = 0; - return 0; } #else diff --git a/drivers/regulator/wm8994-regulator.c b/drivers/regulator/wm8994-regulator.c index 7a4ce6df4f22..d3a5f48119c2 100644 --- a/drivers/regulator/wm8994-regulator.c +++ b/drivers/regulator/wm8994-regulator.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include @@ -129,6 +129,7 @@ static int wm8994_ldo_probe(struct platform_device *pdev) int id = pdev->id % ARRAY_SIZE(pdata->ldo); struct regulator_config config = { }; struct wm8994_ldo *ldo; + struct gpio_desc *gpiod; int ret; dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1); @@ -145,12 +146,14 @@ static int wm8994_ldo_probe(struct platform_device *pdev) config.driver_data = ldo; config.regmap = wm8994->regmap; config.init_data = &ldo->init_data; - if (pdata) { - config.ena_gpio = pdata->ldo[id].enable; - } else if (wm8994->dev->of_node) { - config.ena_gpio = wm8994->pdata.ldo[id].enable; - config.ena_gpio_initialized = true; - } + + /* Look up LDO enable GPIO from the parent device node */ + gpiod = devm_gpiod_get_optional(pdev->dev.parent, + id ? "wlf,ldo2ena" : "wlf,ldo1ena", + GPIOD_OUT_LOW); + if (IS_ERR(gpiod)) + return PTR_ERR(gpiod); + config.ena_gpiod = gpiod; /* Use default constraints if none set up */ if (!pdata || !pdata->ldo[id].init_data || wm8994->dev->of_node) { @@ -159,7 +162,7 @@ static int wm8994_ldo_probe(struct platform_device *pdev) ldo->init_data = wm8994_ldo_default[id]; ldo->init_data.consumer_supplies = &ldo->supply; - if (!config.ena_gpio) + if (!gpiod) ldo->init_data.constraints.valid_ops_mask = 0; } else { ldo->init_data = *pdata->ldo[id].init_data; diff --git a/include/linux/mfd/wm8994/pdata.h b/include/linux/mfd/wm8994/pdata.h index 90c60524a496..fca67bd194e2 100644 --- a/include/linux/mfd/wm8994/pdata.h +++ b/include/linux/mfd/wm8994/pdata.h @@ -20,9 +20,6 @@ #define WM8994_NUM_AIF 3 struct wm8994_ldo_pdata { - /** GPIOs to enable regulator, 0 or less if not available */ - int enable; - const struct regulator_init_data *init_data; }; From 5fe156f1cab4f340ddb6283c993912be77594016 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Thu, 17 May 2018 15:27:21 +0800 Subject: [PATCH 32/57] regulator: pfuze100: add enable/disable for switch Add enable/disable support for switch regulator on pfuze100. Based on Robin Gong's patch from the NXP kernel tree. Signed-off-by: Anson Huang Signed-off-by: Mark Brown --- drivers/regulator/pfuze100-regulator.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/regulator/pfuze100-regulator.c b/drivers/regulator/pfuze100-regulator.c index 680f076e3d85..053eb1ecf18d 100644 --- a/drivers/regulator/pfuze100-regulator.c +++ b/drivers/regulator/pfuze100-regulator.c @@ -155,6 +155,9 @@ static const struct regulator_ops pfuze100_fixed_regulator_ops = { }; static const struct regulator_ops pfuze100_sw_regulator_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, .list_voltage = regulator_list_voltage_linear, .set_voltage_sel = regulator_set_voltage_sel_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, @@ -200,6 +203,11 @@ static const struct regulator_ops pfuze100_swb_regulator_ops = { .uV_step = (step), \ .vsel_reg = (base) + PFUZE100_VOL_OFFSET, \ .vsel_mask = 0x3f, \ + .enable_reg = (base) + PFUZE100_MODE_OFFSET, \ + .enable_val = 0xc, \ + .disable_val = 0x0, \ + .enable_mask = 0xf, \ + .enable_time = 500, \ }, \ .stby_reg = (base) + PFUZE100_STANDBY_OFFSET, \ .stby_mask = 0x3f, \ From 0b01fd3d40fe6402e5fa3b491ef23109feb1aaa5 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Thu, 17 May 2018 15:27:22 +0800 Subject: [PATCH 33/57] regulator: pfuze100: add .is_enable() for pfuze100_swb_regulator_ops If is_enabled() is not defined, regulator core will assume this regulator is already enabled, then it can NOT be really enabled after disabled. Based on Li Jun's patch from the NXP kernel tree. Signed-off-by: Anson Huang Signed-off-by: Mark Brown --- drivers/regulator/pfuze100-regulator.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/regulator/pfuze100-regulator.c b/drivers/regulator/pfuze100-regulator.c index 053eb1ecf18d..677a070eeb1c 100644 --- a/drivers/regulator/pfuze100-regulator.c +++ b/drivers/regulator/pfuze100-regulator.c @@ -168,6 +168,7 @@ static const struct regulator_ops pfuze100_sw_regulator_ops = { static const struct regulator_ops pfuze100_swb_regulator_ops = { .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, .list_voltage = regulator_list_voltage_table, .map_voltage = regulator_map_voltage_ascend, .set_voltage_sel = regulator_set_voltage_sel_regmap, From 809858cd44c5e28a95fcba953d8ddf58ab53180c Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 23 May 2018 16:17:34 -0300 Subject: [PATCH 34/57] regulator: pfuze100: Switch to SPDX identifier Adopt the SPDX license identifier headers to ease license compliance management. Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown --- drivers/regulator/pfuze100-regulator.c | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/drivers/regulator/pfuze100-regulator.c b/drivers/regulator/pfuze100-regulator.c index 677a070eeb1c..26a5cd9b4637 100644 --- a/drivers/regulator/pfuze100-regulator.c +++ b/drivers/regulator/pfuze100-regulator.c @@ -1,20 +1,7 @@ -/* - * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved. + #include #include #include From c07bbfe70263a443a59ec20f1af87af469a1e5b2 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 23 May 2018 16:17:35 -0300 Subject: [PATCH 35/57] regulator: anatop: Switch to SPDX identifier Adopt the SPDX license identifier headers to ease license compliance management. Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown --- drivers/regulator/anatop-regulator.c | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/drivers/regulator/anatop-regulator.c b/drivers/regulator/anatop-regulator.c index 7d6478e6a503..d9d8155ed8cb 100644 --- a/drivers/regulator/anatop-regulator.c +++ b/drivers/regulator/anatop-regulator.c @@ -1,22 +1,6 @@ -/* - * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved. - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved. #include #include From acd70ba4354684d77dc06309a16540fe60f24835 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 23 May 2018 16:17:36 -0300 Subject: [PATCH 36/57] regulator: mc13783: Switch to SPDX identifier Adopt the SPDX license identifier headers to ease license compliance management. Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown --- drivers/regulator/mc13783-regulator.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/drivers/regulator/mc13783-regulator.c b/drivers/regulator/mc13783-regulator.c index fe4c7d677f9c..3db9ebc76b79 100644 --- a/drivers/regulator/mc13783-regulator.c +++ b/drivers/regulator/mc13783-regulator.c @@ -1,14 +1,10 @@ -/* - * Regulator Driver for Freescale MC13783 PMIC - * - * Copyright 2010 Yong Shen - * Copyright (C) 2008 Sascha Hauer, Pengutronix - * Copyright 2009 Alberto Panizzo - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ +// SPDX-License-Identifier: GPL-2.0 +// +// Regulator Driver for Freescale MC13783 PMIC +// +// Copyright 2010 Yong Shen +// Copyright (C) 2008 Sascha Hauer, Pengutronix +// Copyright 2009 Alberto Panizzo #include #include From 0f56839902fedfb95cb00d30342dd0ce5a69f7c3 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 23 May 2018 16:17:37 -0300 Subject: [PATCH 37/57] regulator: mc13892: Switch to SPDX identifier Adopt the SPDX license identifier headers to ease license compliance management. Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown --- drivers/regulator/mc13892-regulator.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/drivers/regulator/mc13892-regulator.c b/drivers/regulator/mc13892-regulator.c index 0d17c9206816..ab309ab693ba 100644 --- a/drivers/regulator/mc13892-regulator.c +++ b/drivers/regulator/mc13892-regulator.c @@ -1,14 +1,10 @@ -/* - * Regulator Driver for Freescale MC13892 PMIC - * - * Copyright 2010 Yong Shen - * - * Based on draft driver from Arnaud Patard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ +// SPDX-License-Identifier: GPL-2.0 +// +// Regulator Driver for Freescale MC13892 PMIC +// +// Copyright 2010 Yong Shen +// +// Based on draft driver from Arnaud Patard #include #include From 910adc0e1bf50cc4c9eddf1d8764e6fe4055adf4 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 23 May 2018 16:17:38 -0300 Subject: [PATCH 38/57] regulator: mc13xxx-core: Switch to SPDX identifier Adopt the SPDX license identifier headers to ease license compliance management. Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown --- drivers/regulator/mc13xxx-regulator-core.c | 28 ++++++++++------------ 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/drivers/regulator/mc13xxx-regulator-core.c b/drivers/regulator/mc13xxx-regulator-core.c index 0281c31ae2ed..41271aeea63e 100644 --- a/drivers/regulator/mc13xxx-regulator-core.c +++ b/drivers/regulator/mc13xxx-regulator-core.c @@ -1,19 +1,15 @@ -/* - * Regulator Driver for Freescale MC13xxx PMIC - * - * Copyright 2010 Yong Shen - * - * Based on mc13783 regulator driver : - * Copyright (C) 2008 Sascha Hauer, Pengutronix - * Copyright 2009 Alberto Panizzo - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Regs infos taken from mc13xxx drivers from freescale and mc13xxx.pdf file - * from freescale - */ +// SPDX-License-Identifier: GPL-2.0 +// +// Regulator Driver for Freescale MC13xxx PMIC +// +// Copyright 2010 Yong Shen +// +// Based on mc13783 regulator driver : +// Copyright (C) 2008 Sascha Hauer, Pengutronix +// Copyright 2009 Alberto Panizzo +// +// Regs infos taken from mc13xxx drivers from freescale and mc13xxx.pdf file +// from freescale #include #include From e7d2be696faa3c8add5b21006ad8fec6b6ed85f1 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 14 May 2018 10:06:25 +0200 Subject: [PATCH 39/57] regulator: max8973: Pass descriptor instead of GPIO number Instead of passing a global GPIO number, pass a descriptor looked up with the standard devm_gpiod_get_optional() call. Signed-off-by: Linus Walleij Signed-off-by: Mark Brown --- drivers/regulator/max8973-regulator.c | 54 ++++++++++++++------------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/drivers/regulator/max8973-regulator.c b/drivers/regulator/max8973-regulator.c index e0c747aa9f85..7cd493ec6315 100644 --- a/drivers/regulator/max8973-regulator.c +++ b/drivers/regulator/max8973-regulator.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -114,7 +115,6 @@ struct max8973_chip { struct regulator_desc desc; struct regmap *regmap; bool enable_external_control; - int enable_gpio; int dvs_gpio; int lru_index[MAX8973_MAX_VOUT_REG]; int curr_vout_val[MAX8973_MAX_VOUT_REG]; @@ -567,7 +567,6 @@ static struct max8973_regulator_platform_data *max8973_parse_dt( pdata->enable_ext_control = of_property_read_bool(np, "maxim,externally-enable"); - pdata->enable_gpio = of_get_named_gpio(np, "maxim,enable-gpio", 0); pdata->dvs_gpio = of_get_named_gpio(np, "maxim,dvs-gpio", 0); ret = of_property_read_u32(np, "maxim,dvs-default-state", &pval); @@ -633,6 +632,8 @@ static int max8973_probe(struct i2c_client *client, struct max8973_chip *max; bool pdata_from_dt = false; unsigned int chip_id; + struct gpio_desc *gpiod; + enum gpiod_flags gflags; int ret; pdata = dev_get_platdata(&client->dev); @@ -647,8 +648,7 @@ static int max8973_probe(struct i2c_client *client, return -EIO; } - if ((pdata->dvs_gpio == -EPROBE_DEFER) || - (pdata->enable_gpio == -EPROBE_DEFER)) + if (pdata->dvs_gpio == -EPROBE_DEFER) return -EPROBE_DEFER; max = devm_kzalloc(&client->dev, sizeof(*max), GFP_KERNEL); @@ -696,15 +696,11 @@ static int max8973_probe(struct i2c_client *client, max->desc.n_voltages = MAX8973_BUCK_N_VOLTAGE; max->dvs_gpio = (pdata->dvs_gpio) ? pdata->dvs_gpio : -EINVAL; - max->enable_gpio = (pdata->enable_gpio) ? pdata->enable_gpio : -EINVAL; max->enable_external_control = pdata->enable_ext_control; max->curr_gpio_val = pdata->dvs_def_state; max->curr_vout_reg = MAX8973_VOUT + pdata->dvs_def_state; max->junction_temp_warning = pdata->junction_temp_warning; - if (gpio_is_valid(max->enable_gpio)) - max->enable_external_control = true; - max->lru_index[0] = max->curr_vout_reg; if (gpio_is_valid(max->dvs_gpio)) { @@ -757,27 +753,35 @@ static int max8973_probe(struct i2c_client *client, break; } - if (gpio_is_valid(max->enable_gpio)) { - config.ena_gpio_flags = GPIOF_OUT_INIT_LOW; - if (ridata && (ridata->constraints.always_on || - ridata->constraints.boot_on)) - config.ena_gpio_flags = GPIOF_OUT_INIT_HIGH; - config.ena_gpio = max->enable_gpio; + if (ridata && (ridata->constraints.always_on || + ridata->constraints.boot_on)) + gflags = GPIOD_OUT_HIGH; + else + gflags = GPIOD_OUT_LOW; + gpiod = devm_gpiod_get_optional(&client->dev, + "maxim,enable", + gflags); + if (IS_ERR(gpiod)) + return PTR_ERR(gpiod); + if (gpiod) { + config.ena_gpiod = gpiod; + max->enable_external_control = true; } + break; case MAX77621: - if (gpio_is_valid(max->enable_gpio)) { - ret = devm_gpio_request_one(&client->dev, - max->enable_gpio, GPIOF_OUT_INIT_HIGH, - "max8973-en-gpio"); - if (ret) { - dev_err(&client->dev, - "gpio_request for gpio %d failed: %d\n", - max->enable_gpio, ret); - return ret; - } - } + /* + * We do not let the core switch this regulator on/off, + * we just leave it on. + */ + gpiod = devm_gpiod_get_optional(&client->dev, + "maxim,enable", + GPIOD_OUT_HIGH); + if (IS_ERR(gpiod)) + return PTR_ERR(gpiod); + if (gpiod) + max->enable_external_control = true; max->desc.enable_reg = MAX8973_VOUT; max->desc.enable_mask = MAX8973_VOUT_ENABLE; From b2d751b7f69b352de0280d2279765a9506ed54f0 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 14 May 2018 10:06:27 +0200 Subject: [PATCH 40/57] regulator: lm363x: Pass descriptor instead of GPIO number Instead of passing a global GPIO number, pass a descriptor looked up with the standard devm_gpiod_get_index_optional() call. Signed-off-by: Linus Walleij Signed-off-by: Mark Brown --- drivers/regulator/lm363x-regulator.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/regulator/lm363x-regulator.c b/drivers/regulator/lm363x-regulator.c index ce5f7d9ad475..b615a413ca9f 100644 --- a/drivers/regulator/lm363x-regulator.c +++ b/drivers/regulator/lm363x-regulator.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include @@ -219,7 +219,7 @@ static const struct regulator_desc lm363x_regulator_desc[] = { }, }; -static int lm363x_regulator_of_get_enable_gpio(struct device_node *np, int id) +static struct gpio_desc *lm363x_regulator_of_get_enable_gpio(struct device *dev, int id) { /* * Check LCM_EN1/2_GPIO is configured. @@ -227,11 +227,11 @@ static int lm363x_regulator_of_get_enable_gpio(struct device_node *np, int id) */ switch (id) { case LM3632_LDO_POS: - return of_get_named_gpio(np, "enable-gpios", 0); + return devm_gpiod_get_index_optional(dev, "enable", 0, GPIOD_OUT_LOW); case LM3632_LDO_NEG: - return of_get_named_gpio(np, "enable-gpios", 1); + return devm_gpiod_get_index_optional(dev, "enable", 1, GPIOD_OUT_LOW); default: - return -EINVAL; + return NULL; } } @@ -243,7 +243,8 @@ static int lm363x_regulator_probe(struct platform_device *pdev) struct regulator_dev *rdev; struct device *dev = &pdev->dev; int id = pdev->id; - int ret, ena_gpio; + struct gpio_desc *gpiod; + int ret; cfg.dev = dev; cfg.regmap = regmap; @@ -252,10 +253,9 @@ static int lm363x_regulator_probe(struct platform_device *pdev) * LM3632 LDOs can be controlled by external pin. * Register update is required if the pin is used. */ - ena_gpio = lm363x_regulator_of_get_enable_gpio(dev->of_node, id); - if (gpio_is_valid(ena_gpio)) { - cfg.ena_gpio = ena_gpio; - cfg.ena_gpio_flags = GPIOF_OUT_INIT_LOW; + gpiod = lm363x_regulator_of_get_enable_gpio(dev, id); + if (gpiod) { + cfg.ena_gpiod = gpiod; ret = regmap_update_bits(regmap, LM3632_REG_BIAS_CONFIG, LM3632_EXT_EN_MASK, From 2468f0d51548b23507ceb3bba5f4e3acaea117ba Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 14 May 2018 10:06:28 +0200 Subject: [PATCH 41/57] regulator: lp8788-ldo: Pass descriptor instead of GPIO number Instead of passing a global GPIO number, pass a descriptor looked up with the standard devm_gpiod_get_index_optional() call. This driver has supported passing a LDO enable GPIO for years, yet this facility has never been put to use in the upstream kernel. If someone desires to put in place GPIO control for the LDOs, this can be done by adding a GPIO descriptor table in the MFD nexus in drivers/mfd/lp8788.c for the LDO device when spawning the MFD children, or using a board file. Signed-off-by: Linus Walleij Acked-by: Lee Jones Signed-off-by: Mark Brown --- drivers/regulator/lp8788-ldo.c | 32 ++++++++++++++++---------------- include/linux/mfd/lp8788.h | 16 ---------------- 2 files changed, 16 insertions(+), 32 deletions(-) diff --git a/drivers/regulator/lp8788-ldo.c b/drivers/regulator/lp8788-ldo.c index cbfd35873575..f2347474a106 100644 --- a/drivers/regulator/lp8788-ldo.c +++ b/drivers/regulator/lp8788-ldo.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include /* register address */ @@ -85,8 +85,6 @@ #define LP8788_STARTUP_TIME_S 3 #define ENABLE_TIME_USEC 32 -#define ENABLE GPIOF_OUT_INIT_HIGH -#define DISABLE GPIOF_OUT_INIT_LOW enum lp8788_ldo_id { DLDO1, @@ -117,7 +115,7 @@ struct lp8788_ldo { struct lp8788 *lp; struct regulator_desc *desc; struct regulator_dev *regulator; - struct lp8788_ldo_enable_pin *en_pin; + struct gpio_desc *ena_gpiod; }; /* DLDO 1, 2, 3, 9 voltage table */ @@ -469,7 +467,6 @@ static int lp8788_config_ldo_enable_mode(struct platform_device *pdev, enum lp8788_ldo_id id) { struct lp8788 *lp = ldo->lp; - struct lp8788_platform_data *pdata = lp->pdata; enum lp8788_ext_ldo_en_id enable_id; u8 en_mask[] = { [EN_ALDO1] = LP8788_EN_SEL_ALDO1_M, @@ -504,11 +501,18 @@ static int lp8788_config_ldo_enable_mode(struct platform_device *pdev, return 0; } - /* if no platform data for ldo pin, then set default enable mode */ - if (!pdata || !pdata->ldo_pin || !pdata->ldo_pin[enable_id]) + /* FIXME: check default mode for GPIO here: high or low? */ + ldo->ena_gpiod = devm_gpiod_get_index_optional(&pdev->dev, + "enable", + enable_id, + GPIOD_OUT_HIGH); + if (IS_ERR(ldo->ena_gpiod)) + return PTR_ERR(ldo->ena_gpiod); + + /* if no GPIO for ldo pin, then set default enable mode */ + if (!ldo->ena_gpiod) goto set_default_ldo_enable_mode; - ldo->en_pin = pdata->ldo_pin[enable_id]; return 0; set_default_ldo_enable_mode: @@ -533,10 +537,8 @@ static int lp8788_dldo_probe(struct platform_device *pdev) if (ret) return ret; - if (ldo->en_pin) { - cfg.ena_gpio = ldo->en_pin->gpio; - cfg.ena_gpio_flags = ldo->en_pin->init_state; - } + if (ldo->ena_gpiod) + cfg.ena_gpiod = ldo->ena_gpiod; cfg.dev = pdev->dev.parent; cfg.init_data = lp->pdata ? lp->pdata->dldo_data[id] : NULL; @@ -582,10 +584,8 @@ static int lp8788_aldo_probe(struct platform_device *pdev) if (ret) return ret; - if (ldo->en_pin) { - cfg.ena_gpio = ldo->en_pin->gpio; - cfg.ena_gpio_flags = ldo->en_pin->init_state; - } + if (ldo->ena_gpiod) + cfg.ena_gpiod = ldo->ena_gpiod; cfg.dev = pdev->dev.parent; cfg.init_data = lp->pdata ? lp->pdata->aldo_data[id] : NULL; diff --git a/include/linux/mfd/lp8788.h b/include/linux/mfd/lp8788.h index 786bf6679a28..2010e0de3e34 100644 --- a/include/linux/mfd/lp8788.h +++ b/include/linux/mfd/lp8788.h @@ -181,20 +181,6 @@ struct lp8788_buck2_dvs { enum lp8788_dvs_sel vsel; }; -/* - * struct lp8788_ldo_enable_pin - * - * Basically, all LDOs are enabled through the I2C commands. - * But ALDO 1 ~ 5, 7, DLDO 7, 9, 11 can be enabled by external gpio pins. - * - * @gpio : gpio number which is used for enabling ldos - * @init_state : initial gpio state (ex. GPIOF_OUT_INIT_LOW) - */ -struct lp8788_ldo_enable_pin { - int gpio; - int init_state; -}; - /* * struct lp8788_chg_param * @addr : charging control register address (range : 0x11 ~ 0x1C) @@ -288,7 +274,6 @@ struct lp8788_vib_platform_data { * @aldo_data : regulator initial data for analog ldo * @buck1_dvs : gpio configurations for buck1 dvs * @buck2_dvs : gpio configurations for buck2 dvs - * @ldo_pin : gpio configurations for enabling LDOs * @chg_pdata : platform data for charger driver * @alarm_sel : rtc alarm selection (1 or 2) * @bl_pdata : configurable data for backlight driver @@ -306,7 +291,6 @@ struct lp8788_platform_data { struct regulator_init_data *aldo_data[LP8788_NUM_ALDOS]; struct lp8788_buck1_dvs *buck1_dvs; struct lp8788_buck2_dvs *buck2_dvs; - struct lp8788_ldo_enable_pin *ldo_pin[EN_LDOS_MAX]; /* charger */ struct lp8788_charger_platform_data *chg_pdata; From d7a261c2d1f233260c48651b4e68987ce1206139 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 14 May 2018 10:06:29 +0200 Subject: [PATCH 42/57] regulator: max8952: Pass descriptor instead of GPIO number Instead of passing a global GPIO number for the enable GPIO, pass a descriptor looked up with the standard devm_gpiod_get_optional() call. All users of this regulator use device tree so the transition is pretty smooth. Signed-off-by: Linus Walleij Signed-off-by: Mark Brown --- drivers/regulator/max8952.c | 18 +++++++++++++----- include/linux/regulator/max8952.h | 1 - 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/drivers/regulator/max8952.c b/drivers/regulator/max8952.c index 1096546c05e9..f1e77ed5dfec 100644 --- a/drivers/regulator/max8952.c +++ b/drivers/regulator/max8952.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -148,7 +149,6 @@ static struct max8952_platform_data *max8952_parse_dt(struct device *dev) pd->gpio_vid0 = of_get_named_gpio(np, "max8952,vid-gpios", 0); pd->gpio_vid1 = of_get_named_gpio(np, "max8952,vid-gpios", 1); - pd->gpio_en = of_get_named_gpio(np, "max8952,en-gpio", 0); if (of_property_read_u32(np, "max8952,default-mode", &pd->default_mode)) dev_warn(dev, "Default mode not specified, assuming 0\n"); @@ -197,6 +197,8 @@ static int max8952_pmic_probe(struct i2c_client *client, struct regulator_config config = { }; struct max8952_data *max8952; struct regulator_dev *rdev; + struct gpio_desc *gpiod; + enum gpiod_flags gflags; int ret = 0, err = 0; @@ -224,11 +226,17 @@ static int max8952_pmic_probe(struct i2c_client *client, config.driver_data = max8952; config.of_node = client->dev.of_node; - config.ena_gpio = pdata->gpio_en; - if (client->dev.of_node) - config.ena_gpio_initialized = true; if (pdata->reg_data->constraints.boot_on) - config.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH; + gflags = GPIOD_OUT_HIGH; + else + gflags = GPIOD_OUT_LOW; + gpiod = devm_gpiod_get_optional(&client->dev, + "max8952,en", + gflags); + if (IS_ERR(gpiod)) + return PTR_ERR(gpiod); + if (gpiod) + config.ena_gpiod = gpiod; rdev = devm_regulator_register(&client->dev, ®ulator, &config); if (IS_ERR(rdev)) { diff --git a/include/linux/regulator/max8952.h b/include/linux/regulator/max8952.h index 4dbb63a1d4ab..686c42c041b5 100644 --- a/include/linux/regulator/max8952.h +++ b/include/linux/regulator/max8952.h @@ -120,7 +120,6 @@ enum { struct max8952_platform_data { int gpio_vid0; int gpio_vid1; - int gpio_en; u32 default_mode; u32 dvs_mode[MAX8952_NUM_DVS_MODE]; /* MAX8952_DVS_MODEx_XXXXmV */ From 5389ac0ac7d95cf23a5f4e27430ceb2ed815cd5d Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 14 May 2018 10:06:30 +0200 Subject: [PATCH 43/57] regulator: pfuze100: Delete reference to ena_gpio We now pass a GPIO descriptor to the core instead of a global GPIO number, if this descriptor is NULL the GPIO line is not used. Just delete the assignment of an invalid GPIO line. Signed-off-by: Linus Walleij Signed-off-by: Mark Brown --- drivers/regulator/pfuze100-regulator.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/regulator/pfuze100-regulator.c b/drivers/regulator/pfuze100-regulator.c index 26a5cd9b4637..8d9dbcc775ea 100644 --- a/drivers/regulator/pfuze100-regulator.c +++ b/drivers/regulator/pfuze100-regulator.c @@ -651,7 +651,6 @@ static int pfuze100_regulator_probe(struct i2c_client *client, config.init_data = init_data; config.driver_data = pfuze_chip; config.of_node = match_of_node(i); - config.ena_gpio = -EINVAL; pfuze_chip->regulators[i] = devm_regulator_register(&client->dev, desc, &config); From 9ae5cc75ceaacf69cc50b9fd4713276c2aa62eb9 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 14 May 2018 10:06:32 +0200 Subject: [PATCH 44/57] regulator: s5m8767: Pass descriptor instead of GPIO number Instead of passing a global GPIO number for the enable GPIO, pass a descriptor looked up from the device tree node for the regulator. This regulator supports passing platform data, but enable/sleep regulators are looked up from the device tree exclusively, so we can need not touch other files. Signed-off-by: Linus Walleij Acked-by: Lee Jones Signed-off-by: Mark Brown --- drivers/regulator/s5m8767.c | 26 +++++++++++++++----------- include/linux/mfd/samsung/core.h | 4 +++- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c index 4836947e1521..b8443a360646 100644 --- a/drivers/regulator/s5m8767.c +++ b/drivers/regulator/s5m8767.c @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -459,15 +460,14 @@ static void s5m8767_regulator_config_ext_control(struct s5m8767_info *s5m8767, return; } - if (!gpio_is_valid(rdata->ext_control_gpio)) { + if (!rdata->ext_control_gpiod) { dev_warn(s5m8767->dev, "ext-control for %s: GPIO not valid, ignoring\n", - rdata->reg_node->name); + rdata->reg_node->name); return; } - config->ena_gpio = rdata->ext_control_gpio; - config->ena_gpio_flags = GPIOF_OUT_INIT_HIGH; + config->ena_gpiod = rdata->ext_control_gpiod; } /* @@ -577,8 +577,14 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev, continue; } - rdata->ext_control_gpio = of_get_named_gpio(reg_np, - "s5m8767,pmic-ext-control-gpios", 0); + rdata->ext_control_gpiod = devm_gpiod_get_from_of_node(&pdev->dev, + reg_np, + "s5m8767,pmic-ext-control-gpios", + 0, + GPIOD_OUT_HIGH, + "s5m8767"); + if (IS_ERR(rdata->ext_control_gpiod)) + return PTR_ERR(rdata->ext_control_gpiod); rdata->id = i; rdata->initdata = of_get_regulator_init_data( @@ -954,10 +960,8 @@ static int s5m8767_pmic_probe(struct platform_device *pdev) config.driver_data = s5m8767; config.regmap = iodev->regmap_pmic; config.of_node = pdata->regulators[i].reg_node; - config.ena_gpio = -EINVAL; - config.ena_gpio_flags = 0; - config.ena_gpio_initialized = true; - if (gpio_is_valid(pdata->regulators[i].ext_control_gpio)) + config.ena_gpiod = NULL; + if (pdata->regulators[i].ext_control_gpiod) s5m8767_regulator_config_ext_control(s5m8767, &pdata->regulators[i], &config); @@ -970,7 +974,7 @@ static int s5m8767_pmic_probe(struct platform_device *pdev) return ret; } - if (gpio_is_valid(pdata->regulators[i].ext_control_gpio)) { + if (pdata->regulators[i].ext_control_gpiod) { ret = s5m8767_enable_ext_control(s5m8767, rdev); if (ret < 0) { dev_err(s5m8767->dev, diff --git a/include/linux/mfd/samsung/core.h b/include/linux/mfd/samsung/core.h index 5a23dd4df432..28f4ae76271d 100644 --- a/include/linux/mfd/samsung/core.h +++ b/include/linux/mfd/samsung/core.h @@ -39,6 +39,8 @@ #define STEP_12_5_MV 12500 #define STEP_6_25_MV 6250 +struct gpio_desc; + enum sec_device_type { S5M8751X, S5M8763X, @@ -151,7 +153,7 @@ struct sec_regulator_data { int id; struct regulator_init_data *initdata; struct device_node *reg_node; - int ext_control_gpio; + struct gpio_desc *ext_control_gpiod; }; /* From 3012e81446d011c1bd99812e562e2292f21060fb Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 14 May 2018 10:06:33 +0200 Subject: [PATCH 45/57] regulator: tps65090: Pass descriptor instead of GPIO number Instead of passing a global GPIO number for the enable GPIO, pass a descriptor looked up from the device tree node for the regulator. This regulator supports passing platform data, but enable/sleep regulators are looked up from the device tree exclusively, so we can need not touch other files. Signed-off-by: Linus Walleij Acked-by: Lee Jones Signed-off-by: Mark Brown --- drivers/regulator/tps65090-regulator.c | 50 ++++++++++++-------------- include/linux/mfd/tps65090.h | 8 +++-- 2 files changed, 28 insertions(+), 30 deletions(-) diff --git a/drivers/regulator/tps65090-regulator.c b/drivers/regulator/tps65090-regulator.c index 395f35dc8cdb..2d398fa3b720 100644 --- a/drivers/regulator/tps65090-regulator.c +++ b/drivers/regulator/tps65090-regulator.c @@ -19,8 +19,8 @@ #include #include #include -#include -#include +#include +#include #include #include #include @@ -300,26 +300,6 @@ static int tps65090_regulator_disable_ext_control( return tps65090_config_ext_control(ri, false); } -static void tps65090_configure_regulator_config( - struct tps65090_regulator_plat_data *tps_pdata, - struct regulator_config *config) -{ - if (gpio_is_valid(tps_pdata->gpio)) { - int gpio_flag = GPIOF_OUT_INIT_LOW; - - if (tps_pdata->reg_init_data->constraints.always_on || - tps_pdata->reg_init_data->constraints.boot_on) - gpio_flag = GPIOF_OUT_INIT_HIGH; - - config->ena_gpio = tps_pdata->gpio; - config->ena_gpio_initialized = true; - config->ena_gpio_flags = gpio_flag; - } else { - config->ena_gpio = -EINVAL; - config->ena_gpio_initialized = false; - } -} - #ifdef CONFIG_OF static struct of_regulator_match tps65090_matches[] = { { .name = "dcdc1", }, @@ -385,9 +365,26 @@ static struct tps65090_platform_data *tps65090_parse_dt_reg_data( rpdata->enable_ext_control = of_property_read_bool( tps65090_matches[idx].of_node, "ti,enable-ext-control"); - if (rpdata->enable_ext_control) - rpdata->gpio = of_get_named_gpio(np, - "dcdc-ext-control-gpios", 0); + if (rpdata->enable_ext_control) { + enum gpiod_flags gflags; + + if (ri_data->constraints.always_on || + ri_data->constraints.boot_on) + gflags = GPIOD_OUT_HIGH; + else + gflags = GPIOD_OUT_LOW; + + rpdata->gpiod = devm_gpiod_get_from_of_node(&pdev->dev, + tps65090_matches[idx].of_node, + "dcdc-ext-control-gpios", 0, + gflags, + "tps65090"); + if (IS_ERR(rpdata->gpiod)) + return ERR_CAST(rpdata->gpiod); + if (!rpdata->gpiod) + dev_err(&pdev->dev, + "could not find DCDC external control GPIO\n"); + } if (of_property_read_u32(tps65090_matches[idx].of_node, "ti,overcurrent-wait", @@ -455,8 +452,7 @@ static int tps65090_regulator_probe(struct platform_device *pdev) */ if (tps_pdata && is_dcdc(num) && tps_pdata->reg_init_data) { if (tps_pdata->enable_ext_control) { - tps65090_configure_regulator_config( - tps_pdata, &config); + config.ena_gpiod = tps_pdata->gpiod; ri->desc->ops = &tps65090_ext_control_ops; } else { ret = tps65090_regulator_disable_ext_control( diff --git a/include/linux/mfd/tps65090.h b/include/linux/mfd/tps65090.h index 67d144b3b8f9..f05bf4a146e2 100644 --- a/include/linux/mfd/tps65090.h +++ b/include/linux/mfd/tps65090.h @@ -83,6 +83,8 @@ enum { #define TPS65090_MAX_REG TPS65090_REG_AD_OUT2 #define TPS65090_NUM_REGS (TPS65090_MAX_REG + 1) +struct gpio_desc; + struct tps65090 { struct device *dev; struct regmap *rmap; @@ -95,8 +97,8 @@ struct tps65090 { * @reg_init_data: The regulator init data. * @enable_ext_control: Enable extrenal control or not. Only available for * DCDC1, DCDC2 and DCDC3. - * @gpio: Gpio number if external control is enabled and controlled through - * gpio. + * @gpiod: Gpio descriptor if external control is enabled and controlled through + * gpio * @overcurrent_wait_valid: True if the overcurrent_wait should be applied. * @overcurrent_wait: Value to set as the overcurrent wait time. This is the * actual bitfield value, not a time in ms (valid value are 0 - 3). @@ -104,7 +106,7 @@ struct tps65090 { struct tps65090_regulator_plat_data { struct regulator_init_data *reg_init_data; bool enable_ext_control; - int gpio; + struct gpio_desc *gpiod; bool overcurrent_wait_valid; int overcurrent_wait; }; From 0caecaa87202b667591d57e8ca233ee1b548ba13 Mon Sep 17 00:00:00 2001 From: Ilia Lin Date: Mon, 21 May 2018 14:25:30 +0300 Subject: [PATCH 46/57] regulator: qcom_spmi: Add support for SAW Add support for SAW controlled regulators. The regulators defined as SAW controlled in the device tree will be controlled through special CPU registers instead of direct SPMI accesses. This is required especially for CPU supply regulators to synchronize with clock scaling and for Automatic Voltage Switching. Signed-off-by: Ilia Lin Signed-off-by: Mark Brown --- drivers/regulator/qcom_spmi-regulator.c | 133 +++++++++++++++++++++++- 1 file changed, 130 insertions(+), 3 deletions(-) diff --git a/drivers/regulator/qcom_spmi-regulator.c b/drivers/regulator/qcom_spmi-regulator.c index 63c7a0c17777..9817f1a75342 100644 --- a/drivers/regulator/qcom_spmi-regulator.c +++ b/drivers/regulator/qcom_spmi-regulator.c @@ -25,6 +25,8 @@ #include #include #include +#include +#include /* Pin control enable input pins. */ #define SPMI_REGULATOR_PIN_CTRL_ENABLE_NONE 0x00 @@ -181,6 +183,23 @@ enum spmi_boost_byp_registers { SPMI_BOOST_BYP_REG_CURRENT_LIMIT = 0x4b, }; +enum spmi_saw3_registers { + SAW3_SECURE = 0x00, + SAW3_ID = 0x04, + SAW3_SPM_STS = 0x0C, + SAW3_AVS_STS = 0x10, + SAW3_PMIC_STS = 0x14, + SAW3_RST = 0x18, + SAW3_VCTL = 0x1C, + SAW3_AVS_CTL = 0x20, + SAW3_AVS_LIMIT = 0x24, + SAW3_AVS_DLY = 0x28, + SAW3_AVS_HYSTERESIS = 0x2C, + SAW3_SPM_STS2 = 0x38, + SAW3_SPM_PMIC_DATA_3 = 0x4C, + SAW3_VERSION = 0xFD0, +}; + /* Used for indexing into ctrl_reg. These are offets from 0x40 */ enum spmi_common_control_register_index { SPMI_COMMON_IDX_VOLTAGE_RANGE = 0, @@ -1035,6 +1054,89 @@ static irqreturn_t spmi_regulator_vs_ocp_isr(int irq, void *data) return IRQ_HANDLED; } +#define SAW3_VCTL_DATA_MASK 0xFF +#define SAW3_VCTL_CLEAR_MASK 0x700FF +#define SAW3_AVS_CTL_EN_MASK 0x1 +#define SAW3_AVS_CTL_TGGL_MASK 0x8000000 +#define SAW3_AVS_CTL_CLEAR_MASK 0x7efc00 + +static struct regmap *saw_regmap = NULL; + +static void spmi_saw_set_vdd(void *data) +{ + u32 vctl, data3, avs_ctl, pmic_sts; + bool avs_enabled = false; + unsigned long timeout; + u8 voltage_sel = *(u8 *)data; + + regmap_read(saw_regmap, SAW3_AVS_CTL, &avs_ctl); + regmap_read(saw_regmap, SAW3_VCTL, &vctl); + regmap_read(saw_regmap, SAW3_SPM_PMIC_DATA_3, &data3); + + /* select the band */ + vctl &= ~SAW3_VCTL_CLEAR_MASK; + vctl |= (u32)voltage_sel; + + data3 &= ~SAW3_VCTL_CLEAR_MASK; + data3 |= (u32)voltage_sel; + + /* If AVS is enabled, switch it off during the voltage change */ + avs_enabled = SAW3_AVS_CTL_EN_MASK & avs_ctl; + if (avs_enabled) { + avs_ctl &= ~SAW3_AVS_CTL_TGGL_MASK; + regmap_write(saw_regmap, SAW3_AVS_CTL, avs_ctl); + } + + regmap_write(saw_regmap, SAW3_RST, 1); + regmap_write(saw_regmap, SAW3_VCTL, vctl); + regmap_write(saw_regmap, SAW3_SPM_PMIC_DATA_3, data3); + + timeout = jiffies + usecs_to_jiffies(100); + do { + regmap_read(saw_regmap, SAW3_PMIC_STS, &pmic_sts); + pmic_sts &= SAW3_VCTL_DATA_MASK; + if (pmic_sts == (u32)voltage_sel) + break; + + cpu_relax(); + + } while (time_before(jiffies, timeout)); + + /* After successful voltage change, switch the AVS back on */ + if (avs_enabled) { + pmic_sts &= 0x3f; + avs_ctl &= ~SAW3_AVS_CTL_CLEAR_MASK; + avs_ctl |= ((pmic_sts - 4) << 10); + avs_ctl |= (pmic_sts << 17); + avs_ctl |= SAW3_AVS_CTL_TGGL_MASK; + regmap_write(saw_regmap, SAW3_AVS_CTL, avs_ctl); + } +} + +static int +spmi_regulator_saw_set_voltage(struct regulator_dev *rdev, unsigned selector) +{ + struct spmi_regulator *vreg = rdev_get_drvdata(rdev); + int ret; + u8 range_sel, voltage_sel; + + ret = spmi_sw_selector_to_hw(vreg, selector, &range_sel, &voltage_sel); + if (ret) + return ret; + + if (0 != range_sel) { + dev_dbg(&rdev->dev, "range_sel = %02X voltage_sel = %02X", \ + range_sel, voltage_sel); + return -EINVAL; + } + + /* Always do the SAW register writes on the first CPU */ + return smp_call_function_single(0, spmi_saw_set_vdd, \ + &voltage_sel, true); +} + +static struct regulator_ops spmi_saw_ops = {}; + static struct regulator_ops spmi_smps_ops = { .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, @@ -1250,6 +1352,7 @@ static int spmi_regulator_match(struct spmi_regulator *vreg, u16 force_type) } dig_major_rev = version[SPMI_COMMON_REG_DIG_MAJOR_REV - SPMI_COMMON_REG_DIG_MAJOR_REV]; + if (!force_type) { type = version[SPMI_COMMON_REG_TYPE - SPMI_COMMON_REG_DIG_MAJOR_REV]; @@ -1648,7 +1751,9 @@ static int qcom_spmi_regulator_probe(struct platform_device *pdev) struct regmap *regmap; const char *name; struct device *dev = &pdev->dev; - int ret; + struct device_node *node = pdev->dev.of_node; + struct device_node *syscon; + int ret, lenp; struct list_head *vreg_list; vreg_list = devm_kzalloc(dev, sizeof(*vreg_list), GFP_KERNEL); @@ -1665,7 +1770,22 @@ static int qcom_spmi_regulator_probe(struct platform_device *pdev) if (!match) return -ENODEV; + if (of_find_property(node, "qcom,saw-reg", &lenp)) { + syscon = of_parse_phandle(node, "qcom,saw-reg", 0); + saw_regmap = syscon_node_to_regmap(syscon); + of_node_put(syscon); + if (IS_ERR(regmap)) + dev_err(dev, "ERROR reading SAW regmap\n"); + } + for (reg = match->data; reg->name; reg++) { + + if (saw_regmap && \ + of_find_property(of_find_node_by_name(node, reg->name), \ + "qcom,saw-slave", &lenp)) { + continue; + } + vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL); if (!vreg) return -ENOMEM; @@ -1673,7 +1793,6 @@ static int qcom_spmi_regulator_probe(struct platform_device *pdev) vreg->dev = dev; vreg->base = reg->base; vreg->regmap = regmap; - if (reg->ocp) { vreg->ocp_irq = platform_get_irq_byname(pdev, reg->ocp); if (vreg->ocp_irq < 0) { @@ -1681,7 +1800,6 @@ static int qcom_spmi_regulator_probe(struct platform_device *pdev) goto err; } } - vreg->desc.id = -1; vreg->desc.owner = THIS_MODULE; vreg->desc.type = REGULATOR_VOLTAGE; @@ -1698,6 +1816,15 @@ static int qcom_spmi_regulator_probe(struct platform_device *pdev) if (ret) continue; + if (saw_regmap && \ + of_find_property(of_find_node_by_name(node, reg->name), \ + "qcom,saw-leader", &lenp)) { + spmi_saw_ops = *(vreg->desc.ops); + spmi_saw_ops.set_voltage_sel = \ + spmi_regulator_saw_set_voltage; + vreg->desc.ops = &spmi_saw_ops; + } + config.dev = dev; config.driver_data = vreg; config.regmap = regmap; From f50e5ddae899d1599e4d6ccb46eadd78b7ed14bc Mon Sep 17 00:00:00 2001 From: Ilia Lin Date: Mon, 21 May 2018 14:25:31 +0300 Subject: [PATCH 47/57] dt-bindings: qcom_spmi: Document SAW support Document the DT bindings for the SAW regulators. The saw-leader is the only property that is configurable in DT. The saw-slave property allows ganging (grouping) of several regulators so that their outputs can be combined. Signed-off-by: Ilia Lin Reviewed-by: Rob Herring Signed-off-by: Mark Brown --- .../regulator/qcom,spmi-regulator.txt | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.txt b/Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.txt index 57d2c65899df..406f2e570c50 100644 --- a/Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.txt @@ -110,6 +110,11 @@ Qualcomm SPMI Regulators Definition: Reference to regulator supplying the input pin, as described in the data sheet. +- qcom,saw-reg: + Usage: optional + Value type: + Description: Reference to syscon node defining the SAW registers. + The regulator node houses sub-nodes for each regulator within the device. Each sub-node is identified using the node's name, with valid values listed for each @@ -201,6 +206,17 @@ see regulator.txt - with additional custom properties described below: 2 = 0.55 uA 3 = 0.75 uA +- qcom,saw-slave: + Usage: optional + Value type: + Description: SAW controlled gang slave. Will not be configured. + +- qcom,saw-leader: + Usage: optional + Value type: + Description: SAW controlled gang leader. Will be configured as + SAW regulator. + Example: regulators { @@ -221,3 +237,32 @@ Example: .... }; + +Example 2: + + saw3: syscon@9A10000 { + compatible = "syscon"; + reg = <0x9A10000 0x1000>; + }; + + ... + + spm-regulators { + compatible = "qcom,pm8994-regulators"; + qcom,saw-reg = <&saw3>; + s8 { + qcom,saw-slave; + }; + s9 { + qcom,saw-slave; + }; + s10 { + qcom,saw-slave; + }; + pm8994_s11_saw: s11 { + qcom,saw-leader; + regulator-always-on; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1140000>; + }; + }; From 37fa23dbccbd97663acc085bd79246f427e603a1 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 26 May 2018 11:03:17 +0100 Subject: [PATCH 48/57] regulator: s2mps11: Fix boot on Odroid XU3 The change to descriptors in 0369e02b75 "regulator: s2mps11: Pass descriptor instead of GPIO number" has broken the boot on Odroid XU3 according to kernelci so let's revert that for now. We get a NULL pointer defererence in: [ 2.467929] [] (validate_desc) from [] (gpiod_set_value_cansleep+0x14/0x30) [ 2.476591] [] (gpiod_set_value_cansleep) from [] (_regulator_do_enable+0x2f8/0x370) [ 2.486032] [] (_regulator_do_enable) from [] (regulator_register+0xc54/0x1280) [ 2.495045] [] (regulator_register) from [] (devm_regulator_register+0x40/0x7c) [ 2.504057] [] (devm_regulator_register) from [] (s2mps11_pmic_probe+0x1c0/0x444) [ 2.513243] [] (s2mps11_pmic_probe) from [] (platform_drv_probe+0x6c/0xa4) Signed-off-by: Mark Brown --- drivers/regulator/s2mps11.c | 46 ++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c index 9a1dca26362e..7726b874e539 100644 --- a/drivers/regulator/s2mps11.c +++ b/drivers/regulator/s2mps11.c @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include #include @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -56,7 +57,7 @@ struct s2mps11_info { * Array (size: number of regulators) with GPIO-s for external * sleep control. */ - struct gpio_desc **ext_control_gpiod; + int *ext_control_gpio; }; static int get_ramp_delay(int ramp_delay) @@ -523,7 +524,7 @@ static int s2mps14_regulator_enable(struct regulator_dev *rdev) case S2MPS14X: if (test_bit(rdev_get_id(rdev), s2mps11->suspend_state)) val = S2MPS14_ENABLE_SUSPEND; - else if (s2mps11->ext_control_gpiod[rdev_get_id(rdev)]) + else if (gpio_is_valid(s2mps11->ext_control_gpio[rdev_get_id(rdev)])) val = S2MPS14_ENABLE_EXT_CONTROL; else val = rdev->desc->enable_mask; @@ -817,7 +818,7 @@ static int s2mps14_pmic_enable_ext_control(struct s2mps11_info *s2mps11, static void s2mps14_pmic_dt_parse_ext_control_gpio(struct platform_device *pdev, struct of_regulator_match *rdata, struct s2mps11_info *s2mps11) { - struct gpio_desc **gpio = s2mps11->ext_control_gpiod; + int *gpio = s2mps11->ext_control_gpio; unsigned int i; unsigned int valid_regulators[3] = { S2MPS14_LDO10, S2MPS14_LDO11, S2MPS14_LDO12 }; @@ -828,20 +829,11 @@ static void s2mps14_pmic_dt_parse_ext_control_gpio(struct platform_device *pdev, if (!rdata[reg].init_data || !rdata[reg].of_node) continue; - gpio[reg] = devm_gpiod_get_from_of_node(&pdev->dev, - rdata[reg].of_node, - "samsung,ext-control-gpios", - 0, - GPIOD_OUT_HIGH, - "s2mps11-LDO"); - if (IS_ERR(gpio[reg])) { - dev_err(&pdev->dev, "Failed to get control GPIO for %d/%s\n", - reg, rdata[reg].name); - continue; - } - if (gpio[reg]) - dev_dbg(&pdev->dev, "Using GPIO for ext-control over %d/%s\n", - reg, rdata[reg].name); + gpio[reg] = of_get_named_gpio(rdata[reg].of_node, + "samsung,ext-control-gpios", 0); + if (gpio_is_valid(gpio[reg])) + dev_dbg(&pdev->dev, "Using GPIO %d for ext-control over %d/%s\n", + gpio[reg], reg, rdata[reg].name); } } @@ -1147,11 +1139,17 @@ static int s2mps11_pmic_probe(struct platform_device *pdev) return -EINVAL; } - s2mps11->ext_control_gpiod = devm_kmalloc(&pdev->dev, - sizeof(*s2mps11->ext_control_gpiod) * rdev_num, + s2mps11->ext_control_gpio = devm_kmalloc(&pdev->dev, + sizeof(*s2mps11->ext_control_gpio) * rdev_num, GFP_KERNEL); - if (!s2mps11->ext_control_gpiod) + if (!s2mps11->ext_control_gpio) return -ENOMEM; + /* + * 0 is a valid GPIO so initialize all GPIO-s to negative value + * to indicate that external control won't be used for this regulator. + */ + for (i = 0; i < rdev_num; i++) + s2mps11->ext_control_gpio[i] = -EINVAL; if (!iodev->dev->of_node) { if (iodev->pdata) { @@ -1181,6 +1179,8 @@ common_reg: config.dev = &pdev->dev; config.regmap = iodev->regmap_pmic; config.driver_data = s2mps11; + config.ena_gpio_flags = GPIOF_OUT_INIT_HIGH; + config.ena_gpio_initialized = true; for (i = 0; i < rdev_num; i++) { struct regulator_dev *regulator; @@ -1191,7 +1191,7 @@ common_reg: config.init_data = rdata[i].init_data; config.of_node = rdata[i].of_node; } - config.ena_gpiod = s2mps11->ext_control_gpiod[i]; + config.ena_gpio = s2mps11->ext_control_gpio[i]; regulator = devm_regulator_register(&pdev->dev, ®ulators[i], &config); @@ -1202,7 +1202,7 @@ common_reg: goto out; } - if (s2mps11->ext_control_gpiod[i]) { + if (gpio_is_valid(s2mps11->ext_control_gpio[i])) { ret = s2mps14_pmic_enable_ext_control(s2mps11, regulator); if (ret < 0) { From 6059577cb28d8b15d2b7dad51eb90d885f1ed9ab Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 14 May 2018 10:06:22 +0200 Subject: [PATCH 49/57] regulator: fixed: Convert to use GPIO descriptor only As we augmented the regulator core to accept a GPIO descriptor instead of a GPIO number, we can augment the fixed GPIO regulator to look up and pass that descriptor directly from device tree or board GPIO descriptor look up tables. Some boards just auto-enumerate their fixed regulator platform devices and I have assumed they get names like "fixed-regulator.0" but it's pretty hard to guess this. I need some testing from board maintainers to be sure. Other boards are straight forward, using just plain "fixed-regulator" (ID -1) or "fixed-regulator.1" hammering down the device ID. The OMAP didn't have proper label names on its GPIO chips so I have fixed this with a separate patch to the GPIO tree, see commit 088413bc0bd5f5fb66ca22a19d66a49d7154ba4c "gpio: omap: Give unique labels to each GPIO bank/chip" It seems the da9055 and da9211 has never got around to actually passing any enable gpio into its platform data (not the in-tree code anyway) so we can just decide to simply pass a descriptor instead. The fixed GPIO-controlled regulator in mach-pxa/ezx.c was confusingly named "*_dummy_supply_device" while it is a very real device backed by a GPIO line. There is nothing dummy about it at all, so I renamed it with the infix *_regulator_* as part of this patch set. For the patch hunk hitting arch/blackfin I would say I do not expect testing, review or ACKs anymore so if it works, it works. The hunk hitting the x86 BCM43xx driver is especially tricky as the number comes out of SFI which is a mystery to me. I definately need someone to look at this. (Hi Andy.) Cc: Andy Shevchenko # Check the x86 BCM stuff Cc: Alexander Shiyan # i.MX boards user Cc: Haojian Zhuang # MMP2 maintainer Cc: Aaro Koskinen # OMAP1 maintainer Cc: Tony Lindgren # OMAP1,2,3 maintainer Cc: Mike Rapoport # EM-X270 maintainer Cc: Robert Jarzmik # EZX maintainer Cc: Philipp Zabel # Magician maintainer Cc: Daniel Mack # Raumfeld maintainer Cc: Marc Zyngier # Zeus maintainer Cc: Geert Uytterhoeven # SuperH pinctrl/GPIO maintainer Cc: Russell King # SA1100 Signed-off-by: Linus Walleij Acked-by: Andy Shevchenko Acked-by: Tony Lindgren Signed-off-by: Mark Brown --- arch/arm/mach-imx/mach-mx21ads.c | 13 +++++++- arch/arm/mach-imx/mach-mx27ads.c | 12 ++++++- arch/arm/mach-mmp/brownstone.c | 12 ++++++- arch/arm/mach-omap1/board-ams-delta.c | 14 +++++++- arch/arm/mach-omap2/pdata-quirks.c | 16 ++++++++- arch/arm/mach-pxa/em-x270.c | 1 - arch/arm/mach-pxa/ezx.c | 33 ++++++++++++------- arch/arm/mach-pxa/magician.c | 2 +- arch/arm/mach-pxa/raumfeld.c | 12 +++++-- arch/arm/mach-pxa/zeus.c | 23 +++++++++++-- arch/arm/mach-s3c64xx/mach-crag6410.c | 1 - arch/arm/mach-s3c64xx/mach-smdk6410.c | 1 - arch/arm/mach-sa1100/assabet.c | 21 ++++++++---- arch/arm/mach-sa1100/generic.c | 5 +-- arch/arm/mach-sa1100/generic.h | 3 +- arch/arm/mach-sa1100/shannon.c | 4 +-- arch/sh/boards/mach-ecovec24/setup.c | 22 +++++++++++-- .../intel-mid/device_libs/platform_bcm43xx.c | 17 ++++++++-- drivers/regulator/fixed-helper.c | 1 - drivers/regulator/fixed.c | 33 +++++++++---------- include/linux/regulator/fixed.h | 3 -- 21 files changed, 187 insertions(+), 62 deletions(-) diff --git a/arch/arm/mach-imx/mach-mx21ads.c b/arch/arm/mach-imx/mach-mx21ads.c index 5e366824814f..5d3b6b4fe6db 100644 --- a/arch/arm/mach-imx/mach-mx21ads.c +++ b/arch/arm/mach-imx/mach-mx21ads.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -175,6 +176,7 @@ static struct resource mx21ads_mmgpio_resource = DEFINE_RES_MEM_NAMED(MX21ADS_IO_REG, SZ_2, "dat"); static struct bgpio_pdata mx21ads_mmgpio_pdata = { + .label = "mx21ads-mmgpio", .base = MX21ADS_MMGPIO_BASE, .ngpio = 16, }; @@ -203,7 +205,6 @@ static struct regulator_init_data mx21ads_lcd_regulator_init_data = { static struct fixed_voltage_config mx21ads_lcd_regulator_pdata = { .supply_name = "LCD", .microvolts = 3300000, - .gpio = MX21ADS_IO_LCDON, .enable_high = 1, .init_data = &mx21ads_lcd_regulator_init_data, }; @@ -216,6 +217,15 @@ static struct platform_device mx21ads_lcd_regulator = { }, }; +static struct gpiod_lookup_table mx21ads_lcd_regulator_gpiod_table = { + .dev_id = "reg-fixed-voltage.0", /* Let's hope ID 0 is what we get */ + .table = { + GPIO_LOOKUP("mx21ads-mmgpio", 9, + "enable", GPIO_ACTIVE_HIGH), + { }, + }, +}; + /* * Connected is a portrait Sharp-QVGA display * of type: LQ035Q7DB02 @@ -311,6 +321,7 @@ static void __init mx21ads_late_init(void) { imx21_add_mxc_mmc(0, &mx21ads_sdhc_pdata); + gpiod_add_lookup_table(&mx21ads_lcd_regulator_gpiod_table); platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices)); mx21ads_cs8900_resources[1].start = diff --git a/arch/arm/mach-imx/mach-mx27ads.c b/arch/arm/mach-imx/mach-mx27ads.c index a04bb094ded1..0fdb88db0cbd 100644 --- a/arch/arm/mach-imx/mach-mx27ads.c +++ b/arch/arm/mach-imx/mach-mx27ads.c @@ -16,6 +16,7 @@ #include /* Needed for gpio_to_irq() */ #include +#include #include #include #include @@ -230,10 +231,17 @@ static struct regulator_init_data mx27ads_lcd_regulator_init_data = { static struct fixed_voltage_config mx27ads_lcd_regulator_pdata = { .supply_name = "LCD", .microvolts = 3300000, - .gpio = MX27ADS_LCD_GPIO, .init_data = &mx27ads_lcd_regulator_init_data, }; +static struct gpiod_lookup_table mx27ads_lcd_regulator_gpiod_table = { + .dev_id = "reg-fixed-voltage.0", /* Let's hope ID 0 is what we get */ + .table = { + GPIO_LOOKUP("LCD", 0, "enable", GPIO_ACTIVE_HIGH), + { }, + }, +}; + static void __init mx27ads_regulator_init(void) { struct gpio_chip *vchip; @@ -247,6 +255,8 @@ static void __init mx27ads_regulator_init(void) vchip->set = vgpio_set; gpiochip_add_data(vchip, NULL); + gpiod_add_lookup_table(&mx27ads_lcd_regulator_gpiod_table); + platform_device_register_data(NULL, "reg-fixed-voltage", PLATFORM_DEVID_AUTO, &mx27ads_lcd_regulator_pdata, diff --git a/arch/arm/mach-mmp/brownstone.c b/arch/arm/mach-mmp/brownstone.c index d1613b954926..563b5a278d65 100644 --- a/arch/arm/mach-mmp/brownstone.c +++ b/arch/arm/mach-mmp/brownstone.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -148,7 +149,6 @@ static struct regulator_init_data brownstone_v_5vp_data = { static struct fixed_voltage_config brownstone_v_5vp = { .supply_name = "v_5vp", .microvolts = 5000000, - .gpio = GPIO_5V_ENABLE, .enable_high = 1, .enabled_at_boot = 1, .init_data = &brownstone_v_5vp_data, @@ -162,6 +162,15 @@ static struct platform_device brownstone_v_5vp_device = { }, }; +static struct gpiod_lookup_table brownstone_v_5vp_gpiod_table = { + .dev_id = "reg-fixed-voltage.1", /* .id set to 1 above */ + .table = { + GPIO_LOOKUP("gpio-pxa", GPIO_5V_ENABLE, + "enable", GPIO_ACTIVE_HIGH), + { }, + }, +}; + static struct max8925_platform_data brownstone_max8925_info = { .irq_base = MMP_NR_IRQS, }; @@ -217,6 +226,7 @@ static void __init brownstone_init(void) mmp2_add_isram(&mmp2_isram_platdata); /* enable 5v regulator */ + gpiod_add_lookup_table(&brownstone_v_5vp_gpiod_table); platform_device_register(&brownstone_v_5vp_device); } diff --git a/arch/arm/mach-omap1/board-ams-delta.c b/arch/arm/mach-omap1/board-ams-delta.c index 52e8e53ca154..759fa18f6ab4 100644 --- a/arch/arm/mach-omap1/board-ams-delta.c +++ b/arch/arm/mach-omap1/board-ams-delta.c @@ -12,6 +12,7 @@ * published by the Free Software Foundation. */ #include +#include #include #include #include @@ -203,6 +204,7 @@ static struct resource latch2_resources[] = { }; static struct bgpio_pdata latch2_pdata = { + .label = "ams-delta-latch2", .base = AMS_DELTA_LATCH2_GPIO_BASE, .ngpio = AMS_DELTA_LATCH2_NGPIO, }; @@ -272,7 +274,6 @@ static struct regulator_init_data modem_nreset_data = { static struct fixed_voltage_config modem_nreset_config = { .supply_name = "modem_nreset", .microvolts = 3300000, - .gpio = AMS_DELTA_GPIO_PIN_MODEM_NRESET, .startup_delay = 25000, .enable_high = 1, .enabled_at_boot = 1, @@ -287,6 +288,16 @@ static struct platform_device modem_nreset_device = { }, }; +static struct gpiod_lookup_table modem_nreset_gpiod_table = { + .dev_id = "reg-fixed-voltage", + .table = { + /* The AMS_DELTA_GPIO_PIN_MODEM_NRESET is at offset 12 */ + GPIO_LOOKUP("ams-delta-latch2", 12, + "enable", GPIO_ACTIVE_HIGH), + { }, + }, +}; + struct modem_private_data { struct regulator *regulator; }; @@ -570,6 +581,7 @@ static int __init late_init(void) platform_add_devices(late_devices, ARRAY_SIZE(late_devices)); + gpiod_add_lookup_table(&modem_nreset_gpiod_table); err = platform_device_register(&modem_nreset_device); if (err) { pr_err("Couldn't register the modem regulator device\n"); diff --git a/arch/arm/mach-omap2/pdata-quirks.c b/arch/arm/mach-omap2/pdata-quirks.c index 6459816c2879..7d1447204fb8 100644 --- a/arch/arm/mach-omap2/pdata-quirks.c +++ b/arch/arm/mach-omap2/pdata-quirks.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -330,7 +331,6 @@ static struct regulator_init_data pandora_vmmc3 = { static struct fixed_voltage_config pandora_vwlan = { .supply_name = "vwlan", .microvolts = 1800000, /* 1.8V */ - .gpio = PANDORA_WIFI_NRESET_GPIO, .startup_delay = 50000, /* 50ms */ .enable_high = 1, .init_data = &pandora_vmmc3, @@ -344,6 +344,19 @@ static struct platform_device pandora_vwlan_device = { }, }; +static struct gpiod_lookup_table pandora_vwlan_gpiod_table = { + .dev_id = "reg-fixed-voltage.1", + .table = { + /* + * As this is a low GPIO number it should be at the first + * GPIO bank. + */ + GPIO_LOOKUP("gpio-0-31", PANDORA_WIFI_NRESET_GPIO, + "enable", GPIO_ACTIVE_HIGH), + { }, + }, +}; + static void pandora_wl1251_init_card(struct mmc_card *card) { /* @@ -405,6 +418,7 @@ fail: static void __init omap3_pandora_legacy_init(void) { platform_device_register(&pandora_backlight); + gpiod_add_lookup_table(&pandora_vwlan_gpiod_table); platform_device_register(&pandora_vwlan_device); omap_hsmmc_init(pandora_mmc3); omap_hsmmc_late_init(pandora_mmc3); diff --git a/arch/arm/mach-pxa/em-x270.c b/arch/arm/mach-pxa/em-x270.c index 49022ad338e9..6d7d93981098 100644 --- a/arch/arm/mach-pxa/em-x270.c +++ b/arch/arm/mach-pxa/em-x270.c @@ -987,7 +987,6 @@ static struct fixed_voltage_config camera_dummy_config = { .supply_name = "camera_vdd", .input_supply = "vcc cam", .microvolts = 2800000, - .gpio = -1, .enable_high = 0, .init_data = &camera_dummy_initdata, }; diff --git a/arch/arm/mach-pxa/ezx.c b/arch/arm/mach-pxa/ezx.c index 2c90b58f347d..2b4bd6d94855 100644 --- a/arch/arm/mach-pxa/ezx.c +++ b/arch/arm/mach-pxa/ezx.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -698,31 +699,39 @@ static struct pxa27x_keypad_platform_data e2_keypad_platform_data = { #if defined(CONFIG_MACH_EZX_A780) || defined(CONFIG_MACH_EZX_A910) /* camera */ -static struct regulator_consumer_supply camera_dummy_supplies[] = { +static struct regulator_consumer_supply camera_regulator_supplies[] = { REGULATOR_SUPPLY("vdd", "0-005d"), }; -static struct regulator_init_data camera_dummy_initdata = { - .consumer_supplies = camera_dummy_supplies, - .num_consumer_supplies = ARRAY_SIZE(camera_dummy_supplies), +static struct regulator_init_data camera_regulator_initdata = { + .consumer_supplies = camera_regulator_supplies, + .num_consumer_supplies = ARRAY_SIZE(camera_regulator_supplies), .constraints = { .valid_ops_mask = REGULATOR_CHANGE_STATUS, }, }; -static struct fixed_voltage_config camera_dummy_config = { +static struct fixed_voltage_config camera_regulator_config = { .supply_name = "camera_vdd", .microvolts = 2800000, - .gpio = GPIO50_nCAM_EN, .enable_high = 0, - .init_data = &camera_dummy_initdata, + .init_data = &camera_regulator_initdata, }; -static struct platform_device camera_supply_dummy_device = { +static struct platform_device camera_supply_regulator_device = { .name = "reg-fixed-voltage", .id = 1, .dev = { - .platform_data = &camera_dummy_config, + .platform_data = &camera_regulator_config, + }, +}; + +static struct gpiod_lookup_table camera_supply_gpiod_table = { + .dev_id = "reg-fixed-voltage.1", + .table = { + GPIO_LOOKUP("gpio-pxa", GPIO50_nCAM_EN, + "enable", GPIO_ACTIVE_HIGH), + { }, }, }; #endif @@ -800,7 +809,7 @@ static struct i2c_board_info a780_i2c_board_info[] = { static struct platform_device *a780_devices[] __initdata = { &a780_gpio_keys, - &camera_supply_dummy_device, + &camera_supply_regulator_device, }; static void __init a780_init(void) @@ -823,6 +832,7 @@ static void __init a780_init(void) if (a780_camera_init() == 0) pxa_set_camera_info(&a780_pxacamera_platform_data); + gpiod_add_lookup_table(&camera_supply_gpiod_table); pwm_add_table(ezx_pwm_lookup, ARRAY_SIZE(ezx_pwm_lookup)); platform_add_devices(ARRAY_AND_SIZE(ezx_devices)); platform_add_devices(ARRAY_AND_SIZE(a780_devices)); @@ -892,6 +902,7 @@ static void __init e680_init(void) pxa_set_keypad_info(&e680_keypad_platform_data); + gpiod_add_lookup_table(&camera_supply_gpiod_table); pwm_add_table(ezx_pwm_lookup, ARRAY_SIZE(ezx_pwm_lookup)); platform_add_devices(ARRAY_AND_SIZE(ezx_devices)); platform_add_devices(ARRAY_AND_SIZE(e680_devices)); @@ -1098,7 +1109,7 @@ static struct i2c_board_info __initdata a910_i2c_board_info[] = { static struct platform_device *a910_devices[] __initdata = { &a910_gpio_keys, - &camera_supply_dummy_device, + &camera_supply_regulator_device, }; static void __init a910_init(void) diff --git a/arch/arm/mach-pxa/magician.c b/arch/arm/mach-pxa/magician.c index c5325d1ae77b..14c0f80bc9e7 100644 --- a/arch/arm/mach-pxa/magician.c +++ b/arch/arm/mach-pxa/magician.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -696,7 +697,6 @@ static struct regulator_init_data vads7846_regulator = { static struct fixed_voltage_config vads7846 = { .supply_name = "vads7846", .microvolts = 3300000, /* probably */ - .gpio = -EINVAL, .startup_delay = 0, .init_data = &vads7846_regulator, }; diff --git a/arch/arm/mach-pxa/raumfeld.c b/arch/arm/mach-pxa/raumfeld.c index 034345546f84..ee766e4ebddc 100644 --- a/arch/arm/mach-pxa/raumfeld.c +++ b/arch/arm/mach-pxa/raumfeld.c @@ -886,7 +886,6 @@ static struct regulator_init_data audio_va_initdata = { static struct fixed_voltage_config audio_va_config = { .supply_name = "audio_va", .microvolts = 5000000, - .gpio = GPIO_AUDIO_VA_ENABLE, .enable_high = 1, .enabled_at_boot = 0, .init_data = &audio_va_initdata, @@ -900,6 +899,15 @@ static struct platform_device audio_va_device = { }, }; +static struct gpiod_lookup_table audio_va_gpiod_table = { + .dev_id = "reg-fixed-voltage.0", + .table = { + GPIO_LOOKUP("gpio-pxa", GPIO_AUDIO_VA_ENABLE, + "enable", GPIO_ACTIVE_HIGH), + { }, + }, +}; + /* Dummy supplies for Codec's VD/VLC */ static struct regulator_consumer_supply audio_dummy_supplies[] = { @@ -918,7 +926,6 @@ static struct regulator_init_data audio_dummy_initdata = { static struct fixed_voltage_config audio_dummy_config = { .supply_name = "audio_vd", .microvolts = 3300000, - .gpio = -1, .init_data = &audio_dummy_initdata, }; @@ -1033,6 +1040,7 @@ static void __init raumfeld_audio_init(void) else gpio_direction_output(GPIO_MCLK_RESET, 1); + gpiod_add_lookup_table(&audio_va_gpiod_table); platform_add_devices(ARRAY_AND_SIZE(audio_regulator_devices)); } diff --git a/arch/arm/mach-pxa/zeus.c b/arch/arm/mach-pxa/zeus.c index e3851795d6d7..58e05afcece0 100644 --- a/arch/arm/mach-pxa/zeus.c +++ b/arch/arm/mach-pxa/zeus.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -410,7 +411,6 @@ static struct regulator_init_data can_regulator_init_data = { static struct fixed_voltage_config can_regulator_pdata = { .supply_name = "CAN_SHDN", .microvolts = 3300000, - .gpio = ZEUS_CAN_SHDN_GPIO, .init_data = &can_regulator_init_data, }; @@ -422,6 +422,15 @@ static struct platform_device can_regulator_device = { }, }; +static struct gpiod_lookup_table can_regulator_gpiod_table = { + .dev_id = "reg-fixed-voltage.0", + .table = { + GPIO_LOOKUP("gpio-pxa", ZEUS_CAN_SHDN_GPIO, + "enable", GPIO_ACTIVE_HIGH), + { }, + }, +}; + static struct mcp251x_platform_data zeus_mcp2515_pdata = { .oscillator_frequency = 16*1000*1000, }; @@ -538,7 +547,6 @@ static struct regulator_init_data zeus_ohci_regulator_data = { static struct fixed_voltage_config zeus_ohci_regulator_config = { .supply_name = "vbus2", .microvolts = 5000000, /* 5.0V */ - .gpio = ZEUS_USB2_PWREN_GPIO, .enable_high = 1, .startup_delay = 0, .init_data = &zeus_ohci_regulator_data, @@ -552,6 +560,15 @@ static struct platform_device zeus_ohci_regulator_device = { }, }; +static struct gpiod_lookup_table zeus_ohci_regulator_gpiod_table = { + .dev_id = "reg-fixed-voltage.0", + .table = { + GPIO_LOOKUP("gpio-pxa", ZEUS_USB2_PWREN_GPIO, + "enable", GPIO_ACTIVE_HIGH), + { }, + }, +}; + static struct pxaohci_platform_data zeus_ohci_platform_data = { .port_mode = PMM_NPS_MODE, /* Clear Power Control Polarity Low and set Power Sense @@ -855,6 +872,8 @@ static void __init zeus_init(void) pxa2xx_mfp_config(ARRAY_AND_SIZE(zeus_pin_config)); + gpiod_add_lookup_table(&can_regulator_gpiod_table); + gpiod_add_lookup_table(&zeus_ohci_regulator_gpiod_table); platform_add_devices(zeus_devices, ARRAY_SIZE(zeus_devices)); zeus_register_ohci(); diff --git a/arch/arm/mach-s3c64xx/mach-crag6410.c b/arch/arm/mach-s3c64xx/mach-crag6410.c index f04650297487..379424d72ae7 100644 --- a/arch/arm/mach-s3c64xx/mach-crag6410.c +++ b/arch/arm/mach-s3c64xx/mach-crag6410.c @@ -352,7 +352,6 @@ static struct fixed_voltage_config wallvdd_pdata = { .supply_name = "WALLVDD", .microvolts = 5000000, .init_data = &wallvdd_data, - .gpio = -EINVAL, }; static struct platform_device wallvdd_device = { diff --git a/arch/arm/mach-s3c64xx/mach-smdk6410.c b/arch/arm/mach-s3c64xx/mach-smdk6410.c index c46fa5dfd2e0..908e5aa831c8 100644 --- a/arch/arm/mach-s3c64xx/mach-smdk6410.c +++ b/arch/arm/mach-s3c64xx/mach-smdk6410.c @@ -222,7 +222,6 @@ static struct fixed_voltage_config smdk6410_b_pwr_5v_pdata = { .supply_name = "B_PWR_5V", .microvolts = 5000000, .init_data = &smdk6410_b_pwr_5v_data, - .gpio = -EINVAL, }; static struct platform_device smdk6410_b_pwr_5v = { diff --git a/arch/arm/mach-sa1100/assabet.c b/arch/arm/mach-sa1100/assabet.c index 575ec085cffa..dbb53c520165 100644 --- a/arch/arm/mach-sa1100/assabet.c +++ b/arch/arm/mach-sa1100/assabet.c @@ -101,7 +101,7 @@ static int __init assabet_init_gpio(void __iomem *reg, u32 def_val) assabet_bcr_gc = gc; - return gc->base; + return 0; } /* @@ -471,6 +471,14 @@ static struct fixed_voltage_config assabet_cf_vcc_pdata __initdata = { .enable_high = 1, }; +static struct gpiod_lookup_table assabet_cf_vcc_gpio_table = { + .dev_id = "reg-fixed-voltage.0", + .table = { + GPIO_LOOKUP("assabet", 0, "enable", GPIO_ACTIVE_HIGH), + { }, + }, +}; + static void __init assabet_init(void) { /* @@ -517,9 +525,11 @@ static void __init assabet_init(void) neponset_resources, ARRAY_SIZE(neponset_resources)); #endif } else { + gpiod_add_lookup_table(&assabet_cf_vcc_gpio_table); sa11x0_register_fixed_regulator(0, &assabet_cf_vcc_pdata, - assabet_cf_vcc_consumers, - ARRAY_SIZE(assabet_cf_vcc_consumers)); + assabet_cf_vcc_consumers, + ARRAY_SIZE(assabet_cf_vcc_consumers), + true); } @@ -802,7 +812,6 @@ fs_initcall(assabet_leds_init); void __init assabet_init_irq(void) { - unsigned int assabet_gpio_base; u32 def_val; sa1100_init_irq(); @@ -817,9 +826,7 @@ void __init assabet_init_irq(void) * * This must precede any driver calls to BCR_set() or BCR_clear(). */ - assabet_gpio_base = assabet_init_gpio((void *)&ASSABET_BCR, def_val); - - assabet_cf_vcc_pdata.gpio = assabet_gpio_base + 0; + assabet_init_gpio((void *)&ASSABET_BCR, def_val); } MACHINE_START(ASSABET, "Intel-Assabet") diff --git a/arch/arm/mach-sa1100/generic.c b/arch/arm/mach-sa1100/generic.c index 7167ddf84a0e..800321c6cbd8 100644 --- a/arch/arm/mach-sa1100/generic.c +++ b/arch/arm/mach-sa1100/generic.c @@ -348,7 +348,8 @@ void __init sa11x0_init_late(void) int __init sa11x0_register_fixed_regulator(int n, struct fixed_voltage_config *cfg, - struct regulator_consumer_supply *supplies, unsigned num_supplies) + struct regulator_consumer_supply *supplies, unsigned num_supplies, + bool uses_gpio) { struct regulator_init_data *id; @@ -356,7 +357,7 @@ int __init sa11x0_register_fixed_regulator(int n, if (!cfg->init_data) return -ENOMEM; - if (cfg->gpio < 0) + if (!uses_gpio) id->constraints.always_on = 1; id->constraints.name = cfg->supply_name; id->constraints.min_uV = cfg->microvolts; diff --git a/arch/arm/mach-sa1100/generic.h b/arch/arm/mach-sa1100/generic.h index 5f3cb52fa6ab..158a4fd5ca24 100644 --- a/arch/arm/mach-sa1100/generic.h +++ b/arch/arm/mach-sa1100/generic.h @@ -54,4 +54,5 @@ void sa11x0_register_pcmcia(int socket, struct gpiod_lookup_table *); struct fixed_voltage_config; struct regulator_consumer_supply; int sa11x0_register_fixed_regulator(int n, struct fixed_voltage_config *cfg, - struct regulator_consumer_supply *supplies, unsigned num_supplies); + struct regulator_consumer_supply *supplies, unsigned num_supplies, + bool uses_gpio); diff --git a/arch/arm/mach-sa1100/shannon.c b/arch/arm/mach-sa1100/shannon.c index 22f7fe0b809f..5bc82e2671c6 100644 --- a/arch/arm/mach-sa1100/shannon.c +++ b/arch/arm/mach-sa1100/shannon.c @@ -102,14 +102,14 @@ static struct fixed_voltage_config shannon_cf_vcc_pdata __initdata = { .supply_name = "cf-power", .microvolts = 3300000, .enabled_at_boot = 1, - .gpio = -EINVAL, }; static void __init shannon_init(void) { sa11x0_register_fixed_regulator(0, &shannon_cf_vcc_pdata, shannon_cf_vcc_consumers, - ARRAY_SIZE(shannon_cf_vcc_consumers)); + ARRAY_SIZE(shannon_cf_vcc_consumers), + false); sa11x0_register_pcmcia(0, &shannon_pcmcia0_gpio_table); sa11x0_register_pcmcia(1, &shannon_pcmcia1_gpio_table); sa11x0_ppc_configure_mcp(); diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c index adc61d14172c..c296b5c399b7 100644 --- a/arch/sh/boards/mach-ecovec24/setup.c +++ b/arch/sh/boards/mach-ecovec24/setup.c @@ -633,7 +633,6 @@ static struct regulator_init_data cn12_power_init_data = { static struct fixed_voltage_config cn12_power_info = { .supply_name = "CN12 SD/MMC Vdd", .microvolts = 3300000, - .gpio = GPIO_PTB7, .enable_high = 1, .init_data = &cn12_power_init_data, }; @@ -646,6 +645,16 @@ static struct platform_device cn12_power = { }, }; +static struct gpiod_lookup_table cn12_power_gpiod_table = { + .dev_id = "reg-fixed-voltage.0", + .table = { + /* Offset 7 on port B */ + GPIO_LOOKUP("sh7724_pfc", GPIO_PTB7, + "enable", GPIO_ACTIVE_HIGH), + { }, + }, +}; + #if defined(CONFIG_MMC_SDHI) || defined(CONFIG_MMC_SDHI_MODULE) /* SDHI0 */ static struct regulator_consumer_supply sdhi0_power_consumers[] = @@ -665,7 +674,6 @@ static struct regulator_init_data sdhi0_power_init_data = { static struct fixed_voltage_config sdhi0_power_info = { .supply_name = "CN11 SD/MMC Vdd", .microvolts = 3300000, - .gpio = GPIO_PTB6, .enable_high = 1, .init_data = &sdhi0_power_init_data, }; @@ -678,6 +686,16 @@ static struct platform_device sdhi0_power = { }, }; +static struct gpiod_lookup_table sdhi0_power_gpiod_table = { + .dev_id = "reg-fixed-voltage.1", + .table = { + /* Offset 6 on port B */ + GPIO_LOOKUP("sh7724_pfc", GPIO_PTB6, + "enable", GPIO_ACTIVE_HIGH), + { }, + }, +}; + static struct tmio_mmc_data sdhi0_info = { .chan_priv_tx = (void *)SHDMA_SLAVE_SDHI0_TX, .chan_priv_rx = (void *)SHDMA_SLAVE_SDHI0_RX, diff --git a/arch/x86/platform/intel-mid/device_libs/platform_bcm43xx.c b/arch/x86/platform/intel-mid/device_libs/platform_bcm43xx.c index 4392c15ed9e0..fc77d69e51d7 100644 --- a/arch/x86/platform/intel-mid/device_libs/platform_bcm43xx.c +++ b/arch/x86/platform/intel-mid/device_libs/platform_bcm43xx.c @@ -10,7 +10,7 @@ * of the License. */ -#include +#include #include #include #include @@ -43,7 +43,6 @@ static struct fixed_voltage_config bcm43xx_vmmc = { * real voltage and signaling are still 1.8V. */ .microvolts = 2000000, /* 1.8V */ - .gpio = -EINVAL, .startup_delay = 250 * 1000, /* 250ms */ .enable_high = 1, /* active high */ .enabled_at_boot = 0, /* disabled at boot */ @@ -58,11 +57,23 @@ static struct platform_device bcm43xx_vmmc_regulator = { }, }; +static struct gpiod_lookup_table bcm43xx_vmmc_gpio_table = { + .dev_id = "reg-fixed-voltage.0", + .table = { + GPIO_LOOKUP("0000:00:0c.0", -1, "enable", GPIO_ACTIVE_LOW), + {} + }, +}; + static int __init bcm43xx_regulator_register(void) { + struct gpiod_lookup_table *table = &bcm43xx_vmmc_gpio_table; + struct gpiod_lookup *lookup = table->table; int ret; - bcm43xx_vmmc.gpio = get_gpio_by_name(WLAN_SFI_GPIO_ENABLE_NAME); + lookup[0].chip_hwnum = get_gpio_by_name(WLAN_SFI_GPIO_ENABLE_NAME); + gpiod_add_lookup_table(table); + ret = platform_device_register(&bcm43xx_vmmc_regulator); if (ret) { pr_err("%s: vmmc regulator register failed\n", __func__); diff --git a/drivers/regulator/fixed-helper.c b/drivers/regulator/fixed-helper.c index 777fac6fb4cb..2c6098e6f4bc 100644 --- a/drivers/regulator/fixed-helper.c +++ b/drivers/regulator/fixed-helper.c @@ -43,7 +43,6 @@ struct platform_device *regulator_register_always_on(int id, const char *name, } data->cfg.microvolts = uv; - data->cfg.gpio = -EINVAL; data->cfg.enabled_at_boot = 1; data->cfg.init_data = &data->init_data; diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c index 988a7472c2ab..1142f195529b 100644 --- a/drivers/regulator/fixed.c +++ b/drivers/regulator/fixed.c @@ -24,10 +24,9 @@ #include #include #include -#include +#include #include #include -#include #include #include @@ -78,10 +77,6 @@ of_get_fixed_voltage_config(struct device *dev, if (init_data->constraints.boot_on) config->enabled_at_boot = true; - config->gpio = of_get_named_gpio(np, "gpio", 0); - if ((config->gpio < 0) && (config->gpio != -ENOENT)) - return ERR_PTR(config->gpio); - of_property_read_u32(np, "startup-delay-us", &config->startup_delay); config->enable_high = of_property_read_bool(np, "enable-active-high"); @@ -102,6 +97,7 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev) struct fixed_voltage_config *config; struct fixed_voltage_data *drvdata; struct regulator_config cfg = { }; + enum gpiod_flags gflags; int ret; drvdata = devm_kzalloc(&pdev->dev, sizeof(struct fixed_voltage_data), @@ -150,25 +146,28 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev) drvdata->desc.fixed_uV = config->microvolts; - if (gpio_is_valid(config->gpio)) { - cfg.ena_gpio = config->gpio; - if (pdev->dev.of_node) - cfg.ena_gpio_initialized = true; - } cfg.ena_gpio_invert = !config->enable_high; if (config->enabled_at_boot) { if (config->enable_high) - cfg.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH; + gflags = GPIOD_OUT_HIGH; else - cfg.ena_gpio_flags |= GPIOF_OUT_INIT_LOW; + gflags = GPIOD_OUT_LOW; } else { if (config->enable_high) - cfg.ena_gpio_flags |= GPIOF_OUT_INIT_LOW; + gflags = GPIOD_OUT_LOW; else - cfg.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH; + gflags = GPIOD_OUT_HIGH; } - if (config->gpio_is_open_drain) - cfg.ena_gpio_flags |= GPIOF_OPEN_DRAIN; + if (config->gpio_is_open_drain) { + if (gflags == GPIOD_OUT_HIGH) + gflags = GPIOD_OUT_HIGH_OPEN_DRAIN; + else + gflags = GPIOD_OUT_LOW_OPEN_DRAIN; + } + + cfg.ena_gpiod = devm_gpiod_get_optional(&pdev->dev, NULL, gflags); + if (IS_ERR(cfg.ena_gpiod)) + return PTR_ERR(cfg.ena_gpiod); cfg.dev = &pdev->dev; cfg.init_data = config->init_data; diff --git a/include/linux/regulator/fixed.h b/include/linux/regulator/fixed.h index 48918be649d4..1a4340ed8e2b 100644 --- a/include/linux/regulator/fixed.h +++ b/include/linux/regulator/fixed.h @@ -24,8 +24,6 @@ struct regulator_init_data; * @supply_name: Name of the regulator supply * @input_supply: Name of the input regulator supply * @microvolts: Output voltage of regulator - * @gpio: GPIO to use for enable control - * set to -EINVAL if not used * @startup_delay: Start-up time in microseconds * @gpio_is_open_drain: Gpio pin is open drain or normal type. * If it is open drain type then HIGH will be set @@ -49,7 +47,6 @@ struct fixed_voltage_config { const char *supply_name; const char *input_supply; int microvolts; - int gpio; unsigned startup_delay; unsigned gpio_is_open_drain:1; unsigned enable_high:1; From 37bed97f00734ce329495823d9682181028b51e4 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 14 May 2018 10:06:23 +0200 Subject: [PATCH 50/57] regulator: gpio: Get enable GPIO using GPIO descriptor We augment the GPIO regulator to get the *enable* regulator GPIO line (not the other lines) using a descriptor rather than a global number. We then pass this into the regulator core which has been prepared to hande enable descriptors in a separate patch. Switch over the two boardfiles using this facility and clean up so we only pass descriptors around. Cc: Philipp Zabel # HX4700/Magician maintainer Signed-off-by: Linus Walleij Signed-off-by: Mark Brown --- arch/arm/mach-pxa/hx4700.c | 12 +++++++++++- arch/arm/mach-pxa/magician.c | 11 ++++++++++- drivers/regulator/gpio-regulator.c | 23 +++++++++++------------ include/linux/regulator/gpio-regulator.h | 3 --- 4 files changed, 32 insertions(+), 17 deletions(-) diff --git a/arch/arm/mach-pxa/hx4700.c b/arch/arm/mach-pxa/hx4700.c index e2e7f247a645..6717a10180eb 100644 --- a/arch/arm/mach-pxa/hx4700.c +++ b/arch/arm/mach-pxa/hx4700.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -711,7 +712,6 @@ static struct gpio_regulator_state bq24022_states[] = { static struct gpio_regulator_config bq24022_info = { .supply_name = "bq24022", - .enable_gpio = GPIO72_HX4700_BQ24022_nCHARGE_EN, .enable_high = 0, .enabled_at_boot = 0, @@ -733,6 +733,15 @@ static struct platform_device bq24022 = { }, }; +static struct gpiod_lookup_table bq24022_gpiod_table = { + .dev_id = "gpio-regulator", + .table = { + GPIO_LOOKUP("gpio-pxa", GPIO72_HX4700_BQ24022_nCHARGE_EN, + "enable", GPIO_ACTIVE_HIGH), + { }, + }, +}; + /* * StrataFlash */ @@ -875,6 +884,7 @@ static void __init hx4700_init(void) pxa_set_btuart_info(NULL); pxa_set_stuart_info(NULL); + gpiod_add_lookup_table(&bq24022_gpiod_table); platform_add_devices(devices, ARRAY_SIZE(devices)); pwm_add_table(hx4700_pwm_lookup, ARRAY_SIZE(hx4700_pwm_lookup)); diff --git a/arch/arm/mach-pxa/magician.c b/arch/arm/mach-pxa/magician.c index 14c0f80bc9e7..9a5bda3ea194 100644 --- a/arch/arm/mach-pxa/magician.c +++ b/arch/arm/mach-pxa/magician.c @@ -657,7 +657,6 @@ static struct gpio_regulator_state bq24022_states[] = { static struct gpio_regulator_config bq24022_info = { .supply_name = "bq24022", - .enable_gpio = GPIO30_MAGICIAN_BQ24022_nCHARGE_EN, .enable_high = 0, .enabled_at_boot = 1, @@ -679,6 +678,15 @@ static struct platform_device bq24022 = { }, }; +static struct gpiod_lookup_table bq24022_gpiod_table = { + .dev_id = "gpio-regulator", + .table = { + GPIO_LOOKUP("gpio-pxa", GPIO30_MAGICIAN_BQ24022_nCHARGE_EN, + "enable", GPIO_ACTIVE_HIGH), + { }, + }, +}; + /* * fixed regulator for ads7846 */ @@ -1007,6 +1015,7 @@ static void __init magician_init(void) regulator_register_always_on(0, "power", pwm_backlight_supply, ARRAY_SIZE(pwm_backlight_supply), 5000000); + gpiod_add_lookup_table(&bq24022_gpiod_table); platform_add_devices(ARRAY_AND_SIZE(devices)); } diff --git a/drivers/regulator/gpio-regulator.c b/drivers/regulator/gpio-regulator.c index a86b8997bb54..9d6094c4d71c 100644 --- a/drivers/regulator/gpio-regulator.c +++ b/drivers/regulator/gpio-regulator.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -161,10 +162,6 @@ of_get_gpio_regulator_config(struct device *dev, struct device_node *np, of_property_read_u32(np, "startup-delay-us", &config->startup_delay); - config->enable_gpio = of_get_named_gpio(np, "enable-gpio", 0); - if (config->enable_gpio < 0 && config->enable_gpio != -ENOENT) - return ERR_PTR(config->enable_gpio); - /* Fetch GPIOs. - optional property*/ ret = of_gpio_count(np); if ((ret < 0) && (ret != -ENOENT)) @@ -255,6 +252,7 @@ static int gpio_regulator_probe(struct platform_device *pdev) struct device_node *np = pdev->dev.of_node; struct gpio_regulator_data *drvdata; struct regulator_config cfg = { }; + enum gpiod_flags gflags; int ptr, ret, state; drvdata = devm_kzalloc(&pdev->dev, sizeof(struct gpio_regulator_data), @@ -340,21 +338,22 @@ static int gpio_regulator_probe(struct platform_device *pdev) cfg.driver_data = drvdata; cfg.of_node = np; - if (gpio_is_valid(config->enable_gpio)) { - cfg.ena_gpio = config->enable_gpio; - cfg.ena_gpio_initialized = true; - } cfg.ena_gpio_invert = !config->enable_high; if (config->enabled_at_boot) { if (config->enable_high) - cfg.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH; + gflags = GPIOD_OUT_HIGH; else - cfg.ena_gpio_flags |= GPIOF_OUT_INIT_LOW; + gflags = GPIOD_OUT_LOW; } else { if (config->enable_high) - cfg.ena_gpio_flags |= GPIOF_OUT_INIT_LOW; + gflags = GPIOD_OUT_LOW; else - cfg.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH; + gflags = GPIOD_OUT_HIGH; + } + cfg.ena_gpiod = devm_gpiod_get_optional(&pdev->dev, "enable", gflags); + if (IS_ERR(cfg.ena_gpiod)) { + ret = PTR_ERR(cfg.ena_gpiod); + goto err_stategpio; } drvdata->dev = regulator_register(&drvdata->desc, &cfg); diff --git a/include/linux/regulator/gpio-regulator.h b/include/linux/regulator/gpio-regulator.h index 19fbd267406d..536cab86f2d5 100644 --- a/include/linux/regulator/gpio-regulator.h +++ b/include/linux/regulator/gpio-regulator.h @@ -44,8 +44,6 @@ struct gpio_regulator_state { /** * struct gpio_regulator_config - config structure * @supply_name: Name of the regulator supply - * @enable_gpio: GPIO to use for enable control - * set to -EINVAL if not used * @enable_high: Polarity of enable GPIO * 1 = Active high, 0 = Active low * @enabled_at_boot: Whether regulator has been enabled at @@ -69,7 +67,6 @@ struct gpio_regulator_state { struct gpio_regulator_config { const char *supply_name; - int enable_gpio; unsigned enable_high:1; unsigned enabled_at_boot:1; unsigned startup_delay; From 196c813570afd0d52d453ef3b77c4c15ca760327 Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Wed, 30 May 2018 11:42:32 +0300 Subject: [PATCH 51/57] regulator: bd71837: Devicetree bindings for BD71837 regulators Document devicetree bindings for ROHM BD71837 PMIC regulators. Signed-off-by: Matti Vaittinen Signed-off-by: Mark Brown --- .../regulator/rohm,bd71837-regulator.txt | 126 ++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 Documentation/devicetree/bindings/regulator/rohm,bd71837-regulator.txt diff --git a/Documentation/devicetree/bindings/regulator/rohm,bd71837-regulator.txt b/Documentation/devicetree/bindings/regulator/rohm,bd71837-regulator.txt new file mode 100644 index 000000000000..4edf3137d9f7 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/rohm,bd71837-regulator.txt @@ -0,0 +1,126 @@ +ROHM BD71837 Power Management Integrated Circuit (PMIC) regulator bindings + +BD71837MWV is a programmable Power Management +IC (PMIC) for powering single-core, dual-core, and +quad-core SoC’s such as NXP-i.MX 8M. It is optimized +for low BOM cost and compact solution footprint. It +integrates 8 Buck regulators and 7 LDO’s to provide all +the power rails required by the SoC and the commonly +used peripherals. + +Required properties: + - regulator-name: should be "buck1", ..., "buck8" and "ldo1", ..., "ldo7" + +List of regulators provided by this controller. BD71837 regulators node +should be sub node of the BD71837 MFD node. See BD71837 MFD bindings at +Documentation/devicetree/bindings/mfd/rohm,bd71837-pmic.txt +Regulator nodes should be named to BUCK_ and LDO_. The +definition for each of these nodes is defined using the standard +binding for regulators at +Documentation/devicetree/bindings/regulator/regulator.txt. +Note that if BD71837 starts at RUN state you probably want to use +regulator-boot-on at least for BUCK6 and BUCK7 so that those are not +disabled by driver at startup. LDO5 and LDO6 are supplied by those and +if they are disabled at startup the voltage monitoring for LDO5/LDO6 will +cause PMIC to reset. + +The valid names for regulator nodes are: +BUCK1, BUCK2, BUCK3, BUCK4, BUCK5, BUCK6, BUCK7, BUCK8 +LDO1, LDO2, LDO3, LDO4, LDO5, LDO6, LDO7 + +Optional properties: +- Any optional property defined in bindings/regulator/regulator.txt + +Example: +regulators { + buck1: BUCK1 { + regulator-name = "buck1"; + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1300000>; + regulator-boot-on; + regulator-ramp-delay = <1250>; + }; + buck2: BUCK2 { + regulator-name = "buck2"; + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1300000>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <1250>; + }; + buck3: BUCK3 { + regulator-name = "buck3"; + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1300000>; + regulator-boot-on; + }; + buck4: BUCK4 { + regulator-name = "buck4"; + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1300000>; + regulator-boot-on; + }; + buck5: BUCK5 { + regulator-name = "buck5"; + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1350000>; + regulator-boot-on; + }; + buck6: BUCK6 { + regulator-name = "buck6"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + }; + buck7: BUCK7 { + regulator-name = "buck7"; + regulator-min-microvolt = <1605000>; + regulator-max-microvolt = <1995000>; + regulator-boot-on; + }; + buck8: BUCK8 { + regulator-name = "buck8"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1400000>; + }; + + ldo1: LDO1 { + regulator-name = "ldo1"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + }; + ldo2: LDO2 { + regulator-name = "ldo2"; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <900000>; + regulator-boot-on; + }; + ldo3: LDO3 { + regulator-name = "ldo3"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + }; + ldo4: LDO4 { + regulator-name = "ldo4"; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1800000>; + }; + ldo5: LDO5 { + regulator-name = "ldo5"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + }; + ldo6: LDO6 { + regulator-name = "ldo6"; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1800000>; + }; + ldo7_reg: LDO7 { + regulator-name = "ldo7"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + }; +}; + + From ba08799e90b5935a3df20766a73b5841046f6832 Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Wed, 30 May 2018 11:43:43 +0300 Subject: [PATCH 52/57] regulator: bd71837: BD71837 PMIC regulator driver Support for controlling the 8 bucks and 7 LDOs the PMIC contains. Signed-off-by: Matti Vaittinen Signed-off-by: Mark Brown --- drivers/regulator/Kconfig | 11 + drivers/regulator/Makefile | 1 + drivers/regulator/bd71837-regulator.c | 640 ++++++++++++++++++++++++++ 3 files changed, 652 insertions(+) create mode 100644 drivers/regulator/bd71837-regulator.c diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 4efae3b7e746..5dbccf5f3037 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -180,6 +180,17 @@ config REGULATOR_BCM590XX BCM590xx PMUs. This will enable support for the software controllable LDO/Switching regulators. +config REGULATOR_BD71837 + tristate "ROHM BD71837 Power Regulator" + depends on MFD_BD71837 + help + This driver supports voltage regulators on ROHM BD71837 PMIC. + This will enable support for the software controllable buck + and LDO regulators. + + This driver can also be built as a module. If so, the module + will be called bd71837-regulator. + config REGULATOR_BD9571MWV tristate "ROHM BD9571MWV Regulators" depends on MFD_BD9571MWV diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index d81fb02bd6e9..bd818ceb7c72 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_REGULATOR_AS3711) += as3711-regulator.o obj-$(CONFIG_REGULATOR_AS3722) += as3722-regulator.o obj-$(CONFIG_REGULATOR_AXP20X) += axp20x-regulator.o obj-$(CONFIG_REGULATOR_BCM590XX) += bcm590xx-regulator.o +obj-$(CONFIG_REGULATOR_BD71837) += bd71837-regulator.o obj-$(CONFIG_REGULATOR_BD9571MWV) += bd9571mwv-regulator.o obj-$(CONFIG_REGULATOR_DA903X) += da903x.o obj-$(CONFIG_REGULATOR_DA9052) += da9052-regulator.o diff --git a/drivers/regulator/bd71837-regulator.c b/drivers/regulator/bd71837-regulator.c new file mode 100644 index 000000000000..6eae4d0432a2 --- /dev/null +++ b/drivers/regulator/bd71837-regulator.c @@ -0,0 +1,640 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2018 ROHM Semiconductors +// bd71837-regulator.c ROHM BD71837MWV regulator driver + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct bd71837_pmic { + struct regulator_desc descs[BD71837_REGULATOR_CNT]; + struct bd71837 *mfd; + struct platform_device *pdev; + struct regulator_dev *rdev[BD71837_REGULATOR_CNT]; +}; + +/* + * BUCK1/2/3/4 + * BUCK1RAMPRATE[1:0] BUCK1 DVS ramp rate setting + * 00: 10.00mV/usec 10mV 1uS + * 01: 5.00mV/usec 10mV 2uS + * 10: 2.50mV/usec 10mV 4uS + * 11: 1.25mV/usec 10mV 8uS + */ +static int bd71837_buck1234_set_ramp_delay(struct regulator_dev *rdev, + int ramp_delay) +{ + struct bd71837_pmic *pmic = rdev_get_drvdata(rdev); + struct bd71837 *mfd = pmic->mfd; + int id = rdev->desc->id; + unsigned int ramp_value = BUCK_RAMPRATE_10P00MV; + + dev_dbg(&(pmic->pdev->dev), "Buck[%d] Set Ramp = %d\n", id + 1, + ramp_delay); + switch (ramp_delay) { + case 1 ... 1250: + ramp_value = BUCK_RAMPRATE_1P25MV; + break; + case 1251 ... 2500: + ramp_value = BUCK_RAMPRATE_2P50MV; + break; + case 2501 ... 5000: + ramp_value = BUCK_RAMPRATE_5P00MV; + break; + case 5001 ... 10000: + ramp_value = BUCK_RAMPRATE_10P00MV; + break; + default: + ramp_value = BUCK_RAMPRATE_10P00MV; + dev_err(&pmic->pdev->dev, + "%s: ramp_delay: %d not supported, setting 10000mV//us\n", + rdev->desc->name, ramp_delay); + } + + return regmap_update_bits(mfd->regmap, BD71837_REG_BUCK1_CTRL + id, + BUCK_RAMPRATE_MASK, ramp_value << 6); +} + +/* Bucks 1 to 4 support DVS. PWM mode is used when voltage is changed. + * Bucks 5 to 8 and LDOs can use PFM and must be disabled when voltage + * is changed. Hence we return -EBUSY for these if voltage is changed + * when BUCK/LDO is enabled. + */ +static int bd71837_set_voltage_sel_restricted(struct regulator_dev *rdev, + unsigned int sel) +{ + int ret; + + ret = regulator_is_enabled_regmap(rdev); + if (!ret) + ret = regulator_set_voltage_sel_regmap(rdev, sel); + else if (ret == 1) + ret = -EBUSY; + return ret; +} + +static struct regulator_ops bd71837_ldo_regulator_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .list_voltage = regulator_list_voltage_linear_range, + .set_voltage_sel = bd71837_set_voltage_sel_restricted, + .get_voltage_sel = regulator_get_voltage_sel_regmap, +}; + +static struct regulator_ops bd71837_ldo_regulator_nolinear_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .list_voltage = regulator_list_voltage_table, + .set_voltage_sel = bd71837_set_voltage_sel_restricted, + .get_voltage_sel = regulator_get_voltage_sel_regmap, +}; + +static struct regulator_ops bd71837_buck_regulator_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .list_voltage = regulator_list_voltage_linear_range, + .set_voltage_sel = bd71837_set_voltage_sel_restricted, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, +}; + +static struct regulator_ops bd71837_buck_regulator_nolinear_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .list_voltage = regulator_list_voltage_table, + .set_voltage_sel = bd71837_set_voltage_sel_restricted, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, +}; + +static struct regulator_ops bd71837_buck1234_regulator_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .list_voltage = regulator_list_voltage_linear_range, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .set_ramp_delay = bd71837_buck1234_set_ramp_delay, +}; + +/* + * BUCK1/2/3/4 + * 0.70 to 1.30V (10mV step) + */ +static const struct regulator_linear_range bd71837_buck1234_voltage_ranges[] = { + REGULATOR_LINEAR_RANGE(700000, 0x00, 0x3C, 10000), + REGULATOR_LINEAR_RANGE(1300000, 0x3D, 0x3F, 0), +}; + +/* + * BUCK5 + * 0.9V to 1.35V () + */ +static const struct regulator_linear_range bd71837_buck5_voltage_ranges[] = { + REGULATOR_LINEAR_RANGE(700000, 0x00, 0x03, 100000), + REGULATOR_LINEAR_RANGE(1050000, 0x04, 0x05, 50000), + REGULATOR_LINEAR_RANGE(1200000, 0x06, 0x07, 150000), +}; + +/* + * BUCK6 + * 3.0V to 3.3V (step 100mV) + */ +static const struct regulator_linear_range bd71837_buck6_voltage_ranges[] = { + REGULATOR_LINEAR_RANGE(3000000, 0x00, 0x03, 100000), +}; + +/* + * BUCK7 + * 000 = 1.605V + * 001 = 1.695V + * 010 = 1.755V + * 011 = 1.8V (Initial) + * 100 = 1.845V + * 101 = 1.905V + * 110 = 1.95V + * 111 = 1.995V + */ +static const unsigned int buck_7_volts[] = { + 1605000, 1695000, 1755000, 1800000, 1845000, 1905000, 1950000, 1995000 +}; + +/* + * BUCK8 + * 0.8V to 1.40V (step 10mV) + */ +static const struct regulator_linear_range bd71837_buck8_voltage_ranges[] = { + REGULATOR_LINEAR_RANGE(800000, 0x00, 0x3C, 10000), + REGULATOR_LINEAR_RANGE(1400000, 0x3D, 0x3F, 0), +}; + +/* + * LDO1 + * 3.0 to 3.3V (100mV step) + */ +static const struct regulator_linear_range bd71837_ldo1_voltage_ranges[] = { + REGULATOR_LINEAR_RANGE(3000000, 0x00, 0x03, 100000), +}; + +/* + * LDO2 + * 0.8 or 0.9V + */ +const unsigned int ldo_2_volts[] = { + 900000, 800000 +}; + +/* + * LDO3 + * 1.8 to 3.3V (100mV step) + */ +static const struct regulator_linear_range bd71837_ldo3_voltage_ranges[] = { + REGULATOR_LINEAR_RANGE(1800000, 0x00, 0x0F, 100000), +}; + +/* + * LDO4 + * 0.9 to 1.8V (100mV step) + */ +static const struct regulator_linear_range bd71837_ldo4_voltage_ranges[] = { + REGULATOR_LINEAR_RANGE(900000, 0x00, 0x09, 100000), + REGULATOR_LINEAR_RANGE(1800000, 0x0A, 0x0F, 0), +}; + +/* + * LDO5 + * 1.8 to 3.3V (100mV step) + */ +static const struct regulator_linear_range bd71837_ldo5_voltage_ranges[] = { + REGULATOR_LINEAR_RANGE(1800000, 0x00, 0x0F, 100000), +}; + +/* + * LDO6 + * 0.9 to 1.8V (100mV step) + */ +static const struct regulator_linear_range bd71837_ldo6_voltage_ranges[] = { + REGULATOR_LINEAR_RANGE(900000, 0x00, 0x09, 100000), + REGULATOR_LINEAR_RANGE(1800000, 0x0A, 0x0F, 0), +}; + +/* + * LDO7 + * 1.8 to 3.3V (100mV step) + */ +static const struct regulator_linear_range bd71837_ldo7_voltage_ranges[] = { + REGULATOR_LINEAR_RANGE(1800000, 0x00, 0x0F, 100000), +}; + +static const struct regulator_desc bd71837_regulators[] = { + { + .name = "buck1", + .of_match = of_match_ptr("BUCK1"), + .regulators_node = of_match_ptr("regulators"), + .id = BD71837_BUCK1, + .ops = &bd71837_buck1234_regulator_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = BD71837_BUCK1_VOLTAGE_NUM, + .linear_ranges = bd71837_buck1234_voltage_ranges, + .n_linear_ranges = ARRAY_SIZE(bd71837_buck1234_voltage_ranges), + .vsel_reg = BD71837_REG_BUCK1_VOLT_RUN, + .vsel_mask = BUCK1_RUN_MASK, + .enable_reg = BD71837_REG_BUCK1_CTRL, + .enable_mask = BD71837_BUCK_EN, + .owner = THIS_MODULE, + }, + { + .name = "buck2", + .of_match = of_match_ptr("BUCK2"), + .regulators_node = of_match_ptr("regulators"), + .id = BD71837_BUCK2, + .ops = &bd71837_buck1234_regulator_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = BD71837_BUCK2_VOLTAGE_NUM, + .linear_ranges = bd71837_buck1234_voltage_ranges, + .n_linear_ranges = ARRAY_SIZE(bd71837_buck1234_voltage_ranges), + .vsel_reg = BD71837_REG_BUCK2_VOLT_RUN, + .vsel_mask = BUCK2_RUN_MASK, + .enable_reg = BD71837_REG_BUCK2_CTRL, + .enable_mask = BD71837_BUCK_EN, + .owner = THIS_MODULE, + }, + { + .name = "buck3", + .of_match = of_match_ptr("BUCK3"), + .regulators_node = of_match_ptr("regulators"), + .id = BD71837_BUCK3, + .ops = &bd71837_buck1234_regulator_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = BD71837_BUCK3_VOLTAGE_NUM, + .linear_ranges = bd71837_buck1234_voltage_ranges, + .n_linear_ranges = ARRAY_SIZE(bd71837_buck1234_voltage_ranges), + .vsel_reg = BD71837_REG_BUCK3_VOLT_RUN, + .vsel_mask = BUCK3_RUN_MASK, + .enable_reg = BD71837_REG_BUCK3_CTRL, + .enable_mask = BD71837_BUCK_EN, + .owner = THIS_MODULE, + }, + { + .name = "buck4", + .of_match = of_match_ptr("BUCK4"), + .regulators_node = of_match_ptr("regulators"), + .id = BD71837_BUCK4, + .ops = &bd71837_buck1234_regulator_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = BD71837_BUCK4_VOLTAGE_NUM, + .linear_ranges = bd71837_buck1234_voltage_ranges, + .n_linear_ranges = ARRAY_SIZE(bd71837_buck1234_voltage_ranges), + .vsel_reg = BD71837_REG_BUCK4_VOLT_RUN, + .vsel_mask = BUCK4_RUN_MASK, + .enable_reg = BD71837_REG_BUCK4_CTRL, + .enable_mask = BD71837_BUCK_EN, + .owner = THIS_MODULE, + }, + { + .name = "buck5", + .of_match = of_match_ptr("BUCK5"), + .regulators_node = of_match_ptr("regulators"), + .id = BD71837_BUCK5, + .ops = &bd71837_buck_regulator_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = BD71837_BUCK5_VOLTAGE_NUM, + .linear_ranges = bd71837_buck5_voltage_ranges, + .n_linear_ranges = ARRAY_SIZE(bd71837_buck5_voltage_ranges), + .vsel_reg = BD71837_REG_BUCK5_VOLT, + .vsel_mask = BUCK5_MASK, + .enable_reg = BD71837_REG_BUCK5_CTRL, + .enable_mask = BD71837_BUCK_EN, + .owner = THIS_MODULE, + }, + { + .name = "buck6", + .of_match = of_match_ptr("BUCK6"), + .regulators_node = of_match_ptr("regulators"), + .id = BD71837_BUCK6, + .ops = &bd71837_buck_regulator_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = BD71837_BUCK6_VOLTAGE_NUM, + .linear_ranges = bd71837_buck6_voltage_ranges, + .n_linear_ranges = ARRAY_SIZE(bd71837_buck6_voltage_ranges), + .vsel_reg = BD71837_REG_BUCK6_VOLT, + .vsel_mask = BUCK6_MASK, + .enable_reg = BD71837_REG_BUCK6_CTRL, + .enable_mask = BD71837_BUCK_EN, + .owner = THIS_MODULE, + }, + { + .name = "buck7", + .of_match = of_match_ptr("BUCK7"), + .regulators_node = of_match_ptr("regulators"), + .id = BD71837_BUCK7, + .ops = &bd71837_buck_regulator_nolinear_ops, + .type = REGULATOR_VOLTAGE, + .volt_table = &buck_7_volts[0], + .n_voltages = ARRAY_SIZE(buck_7_volts), + .vsel_reg = BD71837_REG_BUCK7_VOLT, + .vsel_mask = BUCK7_MASK, + .enable_reg = BD71837_REG_BUCK7_CTRL, + .enable_mask = BD71837_BUCK_EN, + .owner = THIS_MODULE, + }, + { + .name = "buck8", + .of_match = of_match_ptr("BUCK8"), + .regulators_node = of_match_ptr("regulators"), + .id = BD71837_BUCK8, + .ops = &bd71837_buck_regulator_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = BD71837_BUCK8_VOLTAGE_NUM, + .linear_ranges = bd71837_buck8_voltage_ranges, + .n_linear_ranges = ARRAY_SIZE(bd71837_buck8_voltage_ranges), + .vsel_reg = BD71837_REG_BUCK8_VOLT, + .vsel_mask = BUCK8_MASK, + .enable_reg = BD71837_REG_BUCK8_CTRL, + .enable_mask = BD71837_BUCK_EN, + .owner = THIS_MODULE, + }, + { + .name = "ldo1", + .of_match = of_match_ptr("LDO1"), + .regulators_node = of_match_ptr("regulators"), + .id = BD71837_LDO1, + .ops = &bd71837_ldo_regulator_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = BD71837_LDO1_VOLTAGE_NUM, + .linear_ranges = bd71837_ldo1_voltage_ranges, + .n_linear_ranges = ARRAY_SIZE(bd71837_ldo1_voltage_ranges), + .vsel_reg = BD71837_REG_LDO1_VOLT, + .vsel_mask = LDO1_MASK, + .enable_reg = BD71837_REG_LDO1_VOLT, + .enable_mask = BD71837_LDO_EN, + .owner = THIS_MODULE, + }, + { + .name = "ldo2", + .of_match = of_match_ptr("LDO2"), + .regulators_node = of_match_ptr("regulators"), + .id = BD71837_LDO2, + .ops = &bd71837_ldo_regulator_nolinear_ops, + .type = REGULATOR_VOLTAGE, + .volt_table = &ldo_2_volts[0], + .vsel_reg = BD71837_REG_LDO2_VOLT, + .vsel_mask = LDO2_MASK, + .n_voltages = ARRAY_SIZE(ldo_2_volts), + .n_voltages = BD71837_LDO2_VOLTAGE_NUM, + .enable_reg = BD71837_REG_LDO2_VOLT, + .enable_mask = BD71837_LDO_EN, + .owner = THIS_MODULE, + }, + { + .name = "ldo3", + .of_match = of_match_ptr("LDO3"), + .regulators_node = of_match_ptr("regulators"), + .id = BD71837_LDO3, + .ops = &bd71837_ldo_regulator_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = BD71837_LDO3_VOLTAGE_NUM, + .linear_ranges = bd71837_ldo3_voltage_ranges, + .n_linear_ranges = ARRAY_SIZE(bd71837_ldo3_voltage_ranges), + .vsel_reg = BD71837_REG_LDO3_VOLT, + .vsel_mask = LDO3_MASK, + .enable_reg = BD71837_REG_LDO3_VOLT, + .enable_mask = BD71837_LDO_EN, + .owner = THIS_MODULE, + }, + { + .name = "ldo4", + .of_match = of_match_ptr("LDO4"), + .regulators_node = of_match_ptr("regulators"), + .id = BD71837_LDO4, + .ops = &bd71837_ldo_regulator_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = BD71837_LDO4_VOLTAGE_NUM, + .linear_ranges = bd71837_ldo4_voltage_ranges, + .n_linear_ranges = ARRAY_SIZE(bd71837_ldo4_voltage_ranges), + .vsel_reg = BD71837_REG_LDO4_VOLT, + .vsel_mask = LDO4_MASK, + .enable_reg = BD71837_REG_LDO4_VOLT, + .enable_mask = BD71837_LDO_EN, + .owner = THIS_MODULE, + }, + { + .name = "ldo5", + .of_match = of_match_ptr("LDO5"), + .regulators_node = of_match_ptr("regulators"), + .id = BD71837_LDO5, + .ops = &bd71837_ldo_regulator_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = BD71837_LDO5_VOLTAGE_NUM, + .linear_ranges = bd71837_ldo5_voltage_ranges, + .n_linear_ranges = ARRAY_SIZE(bd71837_ldo5_voltage_ranges), + /* LDO5 is supplied by buck6 */ + .supply_name = "buck6", + .vsel_reg = BD71837_REG_LDO5_VOLT, + .vsel_mask = LDO5_MASK, + .enable_reg = BD71837_REG_LDO5_VOLT, + .enable_mask = BD71837_LDO_EN, + .owner = THIS_MODULE, + }, + { + .name = "ldo6", + .of_match = of_match_ptr("LDO6"), + .regulators_node = of_match_ptr("regulators"), + .id = BD71837_LDO6, + .ops = &bd71837_ldo_regulator_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = BD71837_LDO6_VOLTAGE_NUM, + .linear_ranges = bd71837_ldo6_voltage_ranges, + .n_linear_ranges = ARRAY_SIZE(bd71837_ldo6_voltage_ranges), + /* LDO6 is supplied by buck7 */ + .supply_name = "buck7", + .vsel_reg = BD71837_REG_LDO6_VOLT, + .vsel_mask = LDO6_MASK, + .enable_reg = BD71837_REG_LDO6_VOLT, + .enable_mask = BD71837_LDO_EN, + .owner = THIS_MODULE, + }, + { + .name = "ldo7", + .of_match = of_match_ptr("LDO7"), + .regulators_node = of_match_ptr("regulators"), + .id = BD71837_LDO7, + .ops = &bd71837_ldo_regulator_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = BD71837_LDO7_VOLTAGE_NUM, + .linear_ranges = bd71837_ldo7_voltage_ranges, + .n_linear_ranges = ARRAY_SIZE(bd71837_ldo7_voltage_ranges), + .vsel_reg = BD71837_REG_LDO7_VOLT, + .vsel_mask = LDO7_MASK, + .enable_reg = BD71837_REG_LDO7_VOLT, + .enable_mask = BD71837_LDO_EN, + .owner = THIS_MODULE, + }, +}; + +struct reg_init { + unsigned int reg; + unsigned int mask; +}; + +static int bd71837_probe(struct platform_device *pdev) +{ + struct bd71837_pmic *pmic; + struct bd71837_board *pdata; + struct regulator_config config = { 0 }; + struct reg_init pmic_regulator_inits[] = { + { + .reg = BD71837_REG_BUCK1_CTRL, + .mask = BD71837_BUCK_SEL, + }, { + .reg = BD71837_REG_BUCK2_CTRL, + .mask = BD71837_BUCK_SEL, + }, { + .reg = BD71837_REG_BUCK3_CTRL, + .mask = BD71837_BUCK_SEL, + }, { + .reg = BD71837_REG_BUCK4_CTRL, + .mask = BD71837_BUCK_SEL, + }, { + .reg = BD71837_REG_BUCK5_CTRL, + .mask = BD71837_BUCK_SEL, + }, { + .reg = BD71837_REG_BUCK6_CTRL, + .mask = BD71837_BUCK_SEL, + }, { + .reg = BD71837_REG_BUCK7_CTRL, + .mask = BD71837_BUCK_SEL, + }, { + .reg = BD71837_REG_BUCK8_CTRL, + .mask = BD71837_BUCK_SEL, + }, { + .reg = BD71837_REG_LDO1_VOLT, + .mask = BD71837_LDO_SEL, + }, { + .reg = BD71837_REG_LDO2_VOLT, + .mask = BD71837_LDO_SEL, + }, { + .reg = BD71837_REG_LDO3_VOLT, + .mask = BD71837_LDO_SEL, + }, { + .reg = BD71837_REG_LDO4_VOLT, + .mask = BD71837_LDO_SEL, + }, { + .reg = BD71837_REG_LDO5_VOLT, + .mask = BD71837_LDO_SEL, + }, { + .reg = BD71837_REG_LDO6_VOLT, + .mask = BD71837_LDO_SEL, + }, { + .reg = BD71837_REG_LDO7_VOLT, + .mask = BD71837_LDO_SEL, + } + }; + + int i, err; + + pmic = devm_kzalloc(&pdev->dev, sizeof(struct bd71837_pmic), + GFP_KERNEL); + if (!pmic) + return -ENOMEM; + + memcpy(pmic->descs, bd71837_regulators, sizeof(pmic->descs)); + + pmic->pdev = pdev; + pmic->mfd = dev_get_drvdata(pdev->dev.parent); + + if (!pmic->mfd) { + dev_err(&pdev->dev, "No MFD driver data\n"); + err = -EINVAL; + goto err; + } + platform_set_drvdata(pdev, pmic); + pdata = dev_get_platdata(pmic->mfd->dev); + + /* Register LOCK release */ + err = regmap_update_bits(pmic->mfd->regmap, BD71837_REG_REGLOCK, + (REGLOCK_PWRSEQ | REGLOCK_VREG), 0); + if (err) { + dev_err(&pmic->pdev->dev, "Failed to unlock PMIC (%d)\n", err); + goto err; + } else { + dev_dbg(&pmic->pdev->dev, "%s: Unlocked lock register 0x%x\n", + __func__, BD71837_REG_REGLOCK); + } + + for (i = 0; i < ARRAY_SIZE(pmic_regulator_inits); i++) { + + struct regulator_desc *desc; + struct regulator_dev *rdev; + + desc = &pmic->descs[i]; + + if (pdata) + config.init_data = pdata->init_data[i]; + + config.dev = pdev->dev.parent; + config.driver_data = pmic; + config.regmap = pmic->mfd->regmap; + + rdev = devm_regulator_register(&pdev->dev, desc, &config); + if (IS_ERR(rdev)) { + dev_err(pmic->mfd->dev, + "failed to register %s regulator\n", + desc->name); + err = PTR_ERR(rdev); + goto err; + } + /* Regulator register gets the regulator constraints and + * applies them (set_machine_constraints). This should have + * turned the control register(s) to correct values and we + * can now switch the control from PMIC state machine to the + * register interface + */ + err = regmap_update_bits(pmic->mfd->regmap, + pmic_regulator_inits[i].reg, + pmic_regulator_inits[i].mask, + 0xFFFFFFFF); + if (err) { + dev_err(&pmic->pdev->dev, + "Failed to write BUCK/LDO SEL bit for (%s)\n", + desc->name); + goto err; + } + + pmic->rdev[i] = rdev; + } + + return 0; + +err: + return err; +} + +static struct platform_driver bd71837_regulator = { + .driver = { + .name = "bd71837-pmic", + .owner = THIS_MODULE, + }, + .probe = bd71837_probe, +}; + +module_platform_driver(bd71837_regulator); + +MODULE_AUTHOR("Matti Vaittinen "); +MODULE_DESCRIPTION("BD71837 voltage regulator driver"); +MODULE_LICENSE("GPL"); From d1dae72fab2c377ff463742eefd8ac0f9e99b7b9 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 30 May 2018 15:13:42 +0100 Subject: [PATCH 53/57] regulator: max77686: Fix shared GPIOs This reverts commit c89c00e2b8f0 "regulator: max77686: Pass descriptor instead of GPIO number" as it has problems with shared GPIOs similar to that on s2mps11. Reported-by: Bartlomiej Zolnierkiewicz Signed-off-by: Mark Brown --- drivers/regulator/max77686-regulator.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/drivers/regulator/max77686-regulator.c b/drivers/regulator/max77686-regulator.c index 37f98a8350f0..c301f3733475 100644 --- a/drivers/regulator/max77686-regulator.c +++ b/drivers/regulator/max77686-regulator.c @@ -25,7 +25,8 @@ #include #include #include -#include +#include +#include #include #include #include @@ -89,7 +90,6 @@ enum max77686_ramp_rate { }; struct max77686_data { - struct device *dev; DECLARE_BITMAP(gpio_enabled, MAX77686_REGULATORS); /* Array indexed by regulator id */ @@ -269,20 +269,16 @@ static int max77686_of_parse_cb(struct device_node *np, case MAX77686_BUCK8: case MAX77686_BUCK9: case MAX77686_LDO20 ... MAX77686_LDO22: - config->ena_gpiod = devm_gpiod_get_from_of_node(max77686->dev, - np, - "maxim,ena", - 0, - GPIOD_OUT_HIGH, - "max77686-regulator"); - if (IS_ERR(config->ena_gpiod)) - config->ena_gpiod = NULL; + config->ena_gpio = of_get_named_gpio(np, + "maxim,ena-gpios", 0); + config->ena_gpio_flags = GPIOF_OUT_INIT_HIGH; + config->ena_gpio_initialized = true; break; default: return 0; } - if (config->ena_gpiod) { + if (gpio_is_valid(config->ena_gpio)) { set_bit(desc->id, max77686->gpio_enabled); return regmap_update_bits(config->regmap, desc->enable_reg, @@ -525,7 +521,6 @@ static int max77686_pmic_probe(struct platform_device *pdev) if (!max77686) return -ENOMEM; - max77686->dev = &pdev->dev; config.dev = iodev->dev; config.regmap = iodev->regmap; config.driver_data = max77686; From ab4d11e2c2329cf7cb7be31ff22489aae4dee5dc Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 30 May 2018 15:15:20 +0100 Subject: [PATCH 54/57] regulator: wm8994: Fix shared GPIOs This reverts commit 3c6b38d45fa51c7c51 "regulator: wm8994: Pass descriptor instead of GPIO number" as it has problems with shared GPIOs similar to that on s2mps11. Reported-by: Marek Szyprowski Signed-off-by: Mark Brown --- arch/arm/mach-s3c64xx/mach-crag6410-module.c | 17 ++--------------- drivers/mfd/wm8994-core.c | 9 +++++++++ drivers/regulator/wm8994-regulator.c | 19 ++++++++----------- include/linux/mfd/wm8994/pdata.h | 3 +++ 4 files changed, 22 insertions(+), 26 deletions(-) diff --git a/arch/arm/mach-s3c64xx/mach-crag6410-module.c b/arch/arm/mach-s3c64xx/mach-crag6410-module.c index 76c4855a03bc..5aa472892465 100644 --- a/arch/arm/mach-s3c64xx/mach-crag6410-module.c +++ b/arch/arm/mach-s3c64xx/mach-crag6410-module.c @@ -194,8 +194,8 @@ static struct wm8994_pdata wm8994_pdata = { 0x3, /* IRQ out, active high, CMOS */ }, .ldo = { - { .init_data = &wm8994_ldo1, }, - { .init_data = &wm8994_ldo2, }, + { .enable = S3C64XX_GPN(6), .init_data = &wm8994_ldo1, }, + { .enable = S3C64XX_GPN(4), .init_data = &wm8994_ldo2, }, }, }; @@ -203,18 +203,6 @@ static const struct i2c_board_info wm1277_devs[] = { { I2C_BOARD_INFO("wm8958", 0x1a), /* WM8958 is the superset */ .platform_data = &wm8994_pdata, .irq = GLENFARCLAS_PMIC_IRQ_BASE + WM831X_IRQ_GPIO_2, - .dev_name = "wm8958", - }, -}; - -static struct gpiod_lookup_table wm8994_gpiod_table = { - .dev_id = "i2c-wm8958", /* I2C device name */ - .table = { - GPIO_LOOKUP("GPION", 6, - "wlf,ldo1ena", GPIO_ACTIVE_HIGH), - GPIO_LOOKUP("GPION", 4, - "wlf,ldo2ena", GPIO_ACTIVE_HIGH), - { }, }, }; @@ -393,7 +381,6 @@ static int wlf_gf_module_probe(struct i2c_client *i2c, gpiod_add_lookup_table(&wm5102_reva_gpiod_table); gpiod_add_lookup_table(&wm5102_gpiod_table); - gpiod_add_lookup_table(&wm8994_gpiod_table); if (i < ARRAY_SIZE(gf_mods)) { dev_info(&i2c->dev, "%s revision %d\n", diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c index c409464231f6..953d0790ffd5 100644 --- a/drivers/mfd/wm8994-core.c +++ b/drivers/mfd/wm8994-core.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -301,6 +302,14 @@ static int wm8994_set_pdata_from_of(struct wm8994 *wm8994) if (of_find_property(np, "wlf,ldoena-always-driven", NULL)) pdata->lineout2fb = true; + pdata->ldo[0].enable = of_get_named_gpio(np, "wlf,ldo1ena", 0); + if (pdata->ldo[0].enable < 0) + pdata->ldo[0].enable = 0; + + pdata->ldo[1].enable = of_get_named_gpio(np, "wlf,ldo2ena", 0); + if (pdata->ldo[1].enable < 0) + pdata->ldo[1].enable = 0; + return 0; } #else diff --git a/drivers/regulator/wm8994-regulator.c b/drivers/regulator/wm8994-regulator.c index d3a5f48119c2..7a4ce6df4f22 100644 --- a/drivers/regulator/wm8994-regulator.c +++ b/drivers/regulator/wm8994-regulator.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include @@ -129,7 +129,6 @@ static int wm8994_ldo_probe(struct platform_device *pdev) int id = pdev->id % ARRAY_SIZE(pdata->ldo); struct regulator_config config = { }; struct wm8994_ldo *ldo; - struct gpio_desc *gpiod; int ret; dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1); @@ -146,14 +145,12 @@ static int wm8994_ldo_probe(struct platform_device *pdev) config.driver_data = ldo; config.regmap = wm8994->regmap; config.init_data = &ldo->init_data; - - /* Look up LDO enable GPIO from the parent device node */ - gpiod = devm_gpiod_get_optional(pdev->dev.parent, - id ? "wlf,ldo2ena" : "wlf,ldo1ena", - GPIOD_OUT_LOW); - if (IS_ERR(gpiod)) - return PTR_ERR(gpiod); - config.ena_gpiod = gpiod; + if (pdata) { + config.ena_gpio = pdata->ldo[id].enable; + } else if (wm8994->dev->of_node) { + config.ena_gpio = wm8994->pdata.ldo[id].enable; + config.ena_gpio_initialized = true; + } /* Use default constraints if none set up */ if (!pdata || !pdata->ldo[id].init_data || wm8994->dev->of_node) { @@ -162,7 +159,7 @@ static int wm8994_ldo_probe(struct platform_device *pdev) ldo->init_data = wm8994_ldo_default[id]; ldo->init_data.consumer_supplies = &ldo->supply; - if (!gpiod) + if (!config.ena_gpio) ldo->init_data.constraints.valid_ops_mask = 0; } else { ldo->init_data = *pdata->ldo[id].init_data; diff --git a/include/linux/mfd/wm8994/pdata.h b/include/linux/mfd/wm8994/pdata.h index fca67bd194e2..90c60524a496 100644 --- a/include/linux/mfd/wm8994/pdata.h +++ b/include/linux/mfd/wm8994/pdata.h @@ -20,6 +20,9 @@ #define WM8994_NUM_AIF 3 struct wm8994_ldo_pdata { + /** GPIOs to enable regulator, 0 or less if not available */ + int enable; + const struct regulator_init_data *init_data; }; From 38de19fa7159838fbe180e859cb46501d9fca4f4 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 30 May 2018 15:20:03 +0100 Subject: [PATCH 55/57] regulator: Revert coupled regulator support again Revert the last two commits of the voltage coupling mechanism patch set: 456e7cdf3b1a14e2606b8 regulator: core: Change voltage setting path 696861761a58d8c93605b regulator: core: Add voltage balancing mechanism as they broke boot on OMAP again. Reported-by: Tony Lindgren Signed-off-by: Mark Brown --- drivers/regulator/core.c | 329 +++++---------------------------------- 1 file changed, 41 insertions(+), 288 deletions(-) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index ac97e21bff10..6ed568b96c0e 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -105,11 +105,6 @@ static int _notifier_call_chain(struct regulator_dev *rdev, unsigned long event, void *data); static int _regulator_do_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV); -static int regulator_balance_voltage(struct regulator_dev *rdev, - suspend_state_t state); -static int regulator_set_voltage_rdev(struct regulator_dev *rdev, - int min_uV, int max_uV, - suspend_state_t state); static struct regulator *create_regulator(struct regulator_dev *rdev, struct device *dev, const char *supply_name); @@ -201,66 +196,37 @@ static void regulator_unlock(struct regulator_dev *rdev) } } -static int regulator_lock_recursive(struct regulator_dev *rdev, - unsigned int subclass) +/** + * regulator_lock_supply - lock a regulator and its supplies + * @rdev: regulator source + */ +static void regulator_lock_supply(struct regulator_dev *rdev) { - struct regulator_dev *c_rdev; int i; - for (i = 0; i < rdev->coupling_desc.n_coupled; i++) { - c_rdev = rdev->coupling_desc.coupled_rdevs[i]; - - if (!c_rdev) - continue; - - regulator_lock_nested(c_rdev, subclass++); - - if (c_rdev->supply) - subclass = - regulator_lock_recursive(c_rdev->supply->rdev, - subclass); - } - - return subclass; + for (i = 0; rdev; rdev = rdev_get_supply(rdev), i++) + regulator_lock_nested(rdev, i); } /** - * regulator_unlock_dependent - unlock regulator's suppliers and coupled - * regulators - * @rdev: regulator source - * - * Unlock all regulators related with rdev by coupling or suppling. + * regulator_unlock_supply - unlock a regulator and its supplies + * @rdev: regulator source */ -static void regulator_unlock_dependent(struct regulator_dev *rdev) +static void regulator_unlock_supply(struct regulator_dev *rdev) { - struct regulator_dev *c_rdev; - int i; + struct regulator *supply; - for (i = 0; i < rdev->coupling_desc.n_coupled; i++) { - c_rdev = rdev->coupling_desc.coupled_rdevs[i]; + while (1) { + regulator_unlock(rdev); + supply = rdev->supply; - if (!c_rdev) - continue; + if (!rdev->supply) + return; - regulator_unlock(c_rdev); - - if (c_rdev->supply) - regulator_unlock_dependent(c_rdev->supply->rdev); + rdev = supply->rdev; } } -/** - * regulator_lock_dependent - lock regulator's suppliers and coupled regulators - * @rdev: regulator source - * - * This function as a wrapper on regulator_lock_recursive(), which locks - * all regulators related with rdev by coupling or suppling. - */ -static inline void regulator_lock_dependent(struct regulator_dev *rdev) -{ - regulator_lock_recursive(rdev, 0); -} - /** * of_get_regulator - get a regulator device node based on supply name * @dev: Device pointer for the consumer (of regulator) device @@ -2293,11 +2259,6 @@ int regulator_enable(struct regulator *regulator) struct regulator_dev *rdev = regulator->rdev; int ret = 0; - if (rdev->coupling_desc.n_resolved != rdev->coupling_desc.n_coupled) { - rdev_err(rdev, "not all coupled regulators registered\n"); - return -EPERM; - } - if (regulator->always_on) return 0; @@ -2307,12 +2268,9 @@ int regulator_enable(struct regulator *regulator) return ret; } - regulator_lock_dependent(rdev); + mutex_lock(&rdev->mutex); ret = _regulator_enable(rdev); - /* balance only if there are regulators coupled */ - if (rdev->coupling_desc.n_coupled > 1) - regulator_balance_voltage(rdev, PM_SUSPEND_ON); - regulator_unlock_dependent(rdev); + mutex_unlock(&rdev->mutex); if (ret != 0 && rdev->supply) regulator_disable(rdev->supply); @@ -2418,11 +2376,9 @@ int regulator_disable(struct regulator *regulator) if (regulator->always_on) return 0; - regulator_lock_dependent(rdev); + mutex_lock(&rdev->mutex); ret = _regulator_disable(rdev); - if (rdev->coupling_desc.n_coupled > 1) - regulator_balance_voltage(rdev, PM_SUSPEND_ON); - regulator_unlock_dependent(rdev); + mutex_unlock(&rdev->mutex); if (ret == 0 && rdev->supply) regulator_disable(rdev->supply); @@ -2471,12 +2427,10 @@ int regulator_force_disable(struct regulator *regulator) struct regulator_dev *rdev = regulator->rdev; int ret; - regulator_lock_dependent(rdev); + mutex_lock(&rdev->mutex); regulator->uA_load = 0; ret = _regulator_force_disable(regulator->rdev); - if (rdev->coupling_desc.n_coupled > 1) - regulator_balance_voltage(rdev, PM_SUSPEND_ON); - regulator_unlock_dependent(rdev); + mutex_unlock(&rdev->mutex); if (rdev->supply) while (rdev->open_count--) @@ -2624,9 +2578,9 @@ int regulator_is_enabled(struct regulator *regulator) if (regulator->always_on) return 1; - regulator_lock_dependent(regulator->rdev); + mutex_lock(®ulator->rdev->mutex); ret = _regulator_is_enabled(regulator->rdev); - regulator_unlock_dependent(regulator->rdev); + mutex_unlock(®ulator->rdev->mutex); return ret; } @@ -3035,12 +2989,8 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator, int ret = 0; int old_min_uV, old_max_uV; int current_uV; - - if (rdev->coupling_desc.n_resolved != rdev->coupling_desc.n_coupled) { - rdev_err(rdev, "not all coupled regulators registered\n"); - ret = -EPERM; - goto out; - } + int best_supply_uV = 0; + int supply_change_uV = 0; /* If we're setting the same range as last time the change * should be a noop (some cpufreq implementations use the same @@ -3084,27 +3034,6 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator, if (ret < 0) goto out2; - /* for not coupled regulators this will just set the voltage */ - ret = regulator_balance_voltage(rdev, state); - if (ret < 0) - goto out2; - -out: - return 0; -out2: - voltage->min_uV = old_min_uV; - voltage->max_uV = old_max_uV; - - return ret; -} - -static int regulator_set_voltage_rdev(struct regulator_dev *rdev, int min_uV, - int max_uV, suspend_state_t state) -{ - int best_supply_uV = 0; - int supply_change_uV = 0; - int ret; - if (rdev->supply && regulator_ops_is_valid(rdev->supply->rdev, REGULATOR_CHANGE_VOLTAGE) && @@ -3116,13 +3045,13 @@ static int regulator_set_voltage_rdev(struct regulator_dev *rdev, int min_uV, selector = regulator_map_voltage(rdev, min_uV, max_uV); if (selector < 0) { ret = selector; - goto out; + goto out2; } best_supply_uV = _regulator_list_voltage(rdev, selector, 0); if (best_supply_uV < 0) { ret = best_supply_uV; - goto out; + goto out2; } best_supply_uV += rdev->desc->min_dropout_uV; @@ -3130,7 +3059,7 @@ static int regulator_set_voltage_rdev(struct regulator_dev *rdev, int min_uV, current_supply_uV = _regulator_get_voltage(rdev->supply->rdev); if (current_supply_uV < 0) { ret = current_supply_uV; - goto out; + goto out2; } supply_change_uV = best_supply_uV - current_supply_uV; @@ -3142,7 +3071,7 @@ static int regulator_set_voltage_rdev(struct regulator_dev *rdev, int min_uV, if (ret) { dev_err(&rdev->dev, "Failed to increase supply voltage: %d\n", ret); - goto out; + goto out2; } } @@ -3152,7 +3081,7 @@ static int regulator_set_voltage_rdev(struct regulator_dev *rdev, int min_uV, ret = _regulator_do_set_suspend_voltage(rdev, min_uV, max_uV, state); if (ret < 0) - goto out; + goto out2; if (supply_change_uV < 0) { ret = regulator_set_voltage_unlocked(rdev->supply, @@ -3166,186 +3095,10 @@ static int regulator_set_voltage_rdev(struct regulator_dev *rdev, int min_uV, out: return ret; -} +out2: + voltage->min_uV = old_min_uV; + voltage->max_uV = old_max_uV; -static int regulator_get_optimal_voltage(struct regulator_dev *rdev) -{ - struct coupling_desc *c_desc = &rdev->coupling_desc; - struct regulator_dev **c_rdevs = c_desc->coupled_rdevs; - int max_spread = rdev->constraints->max_spread; - int n_coupled = c_desc->n_coupled; - int desired_min_uV, desired_max_uV, min_current_uV = INT_MAX; - int max_current_uV = 0, highest_min_uV = 0, target_uV, possible_uV; - int i, ret; - - /* If consumers don't provide any demands, set voltage to min_uV */ - desired_min_uV = rdev->constraints->min_uV; - desired_max_uV = rdev->constraints->max_uV; - ret = regulator_check_consumers(rdev, - &desired_min_uV, - &desired_max_uV, PM_SUSPEND_ON); - if (ret < 0) - goto out; - - /* - * If there are no coupled regulators, simply set the voltage demanded - * by consumers. - */ - if (n_coupled == 1) { - ret = desired_min_uV; - goto out; - } - - /* Find highest min desired voltage */ - for (i = 0; i < n_coupled; i++) { - int tmp_min = 0; - int tmp_max = INT_MAX; - - if (!_regulator_is_enabled(c_rdevs[i])) - continue; - - ret = regulator_check_consumers(c_rdevs[i], - &tmp_min, - &tmp_max, PM_SUSPEND_ON); - if (ret < 0) - goto out; - - if (tmp_min > highest_min_uV) - highest_min_uV = tmp_min; - } - - /* - * Let target_uV be equal to the desired one if possible. - * If not, set it to minimum voltage, allowed by other coupled - * regulators. - */ - target_uV = max(desired_min_uV, highest_min_uV - max_spread); - - /* - * Find min and max voltages, which currently aren't - * violating max_spread - */ - for (i = 0; i < n_coupled; i++) { - int tmp_act; - - /* - * Don't check the regulator, which is about - * to change voltage - */ - if (c_rdevs[i] == rdev) - continue; - if (!_regulator_is_enabled(c_rdevs[i])) - continue; - - tmp_act = _regulator_get_voltage(c_rdevs[i]); - if (tmp_act < 0) { - ret = tmp_act; - goto out; - } - - if (tmp_act < min_current_uV) - min_current_uV = tmp_act; - - if (tmp_act > max_current_uV) - max_current_uV = tmp_act; - } - - /* There aren't any other regulators enabled */ - if (max_current_uV == 0) { - possible_uV = target_uV; - } else { - /* - * Correct target voltage, so as it currently isn't - * violating max_spread - */ - possible_uV = max(target_uV, max_current_uV - max_spread); - possible_uV = min(possible_uV, min_current_uV + max_spread); - } - - if (possible_uV > desired_max_uV) { - ret = -EINVAL; - goto out; - } - ret = possible_uV; - -out: - return ret; -} - -static int regulator_balance_voltage(struct regulator_dev *rdev, - suspend_state_t state) -{ - struct regulator_dev **c_rdevs; - struct regulator_dev *best_rdev; - struct coupling_desc *c_desc = &rdev->coupling_desc; - int n_coupled; - int i, best_delta, best_uV, ret = 1; - - c_rdevs = c_desc->coupled_rdevs; - n_coupled = c_desc->n_coupled; - - /* - * if system is in a state other than PM_SUSPEND_ON, don't check - * other coupled regulators - */ - if (state != PM_SUSPEND_ON) - n_coupled = 1; - - /* - * Find the best possible voltage change on each loop. Leave the loop - * if there isn't any possible change. - */ - while (1) { - best_delta = 0; - best_uV = 0; - best_rdev = NULL; - - /* - * Find highest difference between optimal voltage - * and current voltage. - */ - for (i = 0; i < n_coupled; i++) { - /* - * optimal_uV is the best voltage that can be set for - * i-th regulator at the moment without violating - * max_spread constraint in order to balance - * the coupled voltages. - */ - int optimal_uV, current_uV; - - optimal_uV = regulator_get_optimal_voltage(c_rdevs[i]); - if (optimal_uV < 0) { - ret = optimal_uV; - goto out; - } - - current_uV = _regulator_get_voltage(c_rdevs[i]); - if (current_uV < 0) { - ret = optimal_uV; - goto out; - } - - if (abs(best_delta) < abs(optimal_uV - current_uV)) { - best_delta = optimal_uV - current_uV; - best_rdev = c_rdevs[i]; - best_uV = optimal_uV; - } - } - - /* Nothing to change, return successfully */ - if (!best_rdev) { - ret = 0; - goto out; - } - - ret = regulator_set_voltage_rdev(best_rdev, best_uV, - best_uV, state); - - if (ret < 0) - goto out; - } - -out: return ret; } @@ -3371,12 +3124,12 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV) { int ret = 0; - regulator_lock_dependent(regulator->rdev); + regulator_lock_supply(regulator->rdev); ret = regulator_set_voltage_unlocked(regulator, min_uV, max_uV, PM_SUSPEND_ON); - regulator_unlock_dependent(regulator->rdev); + regulator_unlock_supply(regulator->rdev); return ret; } @@ -3454,12 +3207,12 @@ int regulator_set_suspend_voltage(struct regulator *regulator, int min_uV, if (regulator_check_states(state) || state == PM_SUSPEND_ON) return -EINVAL; - regulator_lock_dependent(regulator->rdev); + regulator_lock_supply(regulator->rdev); ret = _regulator_set_suspend_voltage(regulator, min_uV, max_uV, state); - regulator_unlock_dependent(regulator->rdev); + regulator_unlock_supply(regulator->rdev); return ret; } @@ -3651,11 +3404,11 @@ int regulator_get_voltage(struct regulator *regulator) { int ret; - regulator_lock_dependent(regulator->rdev); + regulator_lock_supply(regulator->rdev); ret = _regulator_get_voltage(regulator->rdev); - regulator_unlock_dependent(regulator->rdev); + regulator_unlock_supply(regulator->rdev); return ret; } From 2b6c00c157c5bf80417f6b814f1088da2dc588ee Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 30 May 2018 23:24:58 +0200 Subject: [PATCH 56/57] ARM: pxa, regulator: fix building ezx e680 The reference to camera_supply_gpiod_table was added in the wrong function, as observed from this randconfig build failure: arch/arm/mach-pxa/ezx.c: In function 'e680_init': arch/arm/mach-pxa/ezx.c:905:26: error: 'camera_supply_gpiod_table' undeclared (first use in this function) gpiod_add_lookup_table(&camera_supply_gpiod_table); Fixes: 6059577cb28d ("regulator: fixed: Convert to use GPIO descriptor only") Signed-off-by: Arnd Bergmann Signed-off-by: Mark Brown --- arch/arm/mach-pxa/ezx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-pxa/ezx.c b/arch/arm/mach-pxa/ezx.c index 2b4bd6d94855..4f33eea73f9a 100644 --- a/arch/arm/mach-pxa/ezx.c +++ b/arch/arm/mach-pxa/ezx.c @@ -902,7 +902,6 @@ static void __init e680_init(void) pxa_set_keypad_info(&e680_keypad_platform_data); - gpiod_add_lookup_table(&camera_supply_gpiod_table); pwm_add_table(ezx_pwm_lookup, ARRAY_SIZE(ezx_pwm_lookup)); platform_add_devices(ARRAY_AND_SIZE(ezx_devices)); platform_add_devices(ARRAY_AND_SIZE(e680_devices)); @@ -1132,6 +1131,7 @@ static void __init a910_init(void) if (a910_camera_init() == 0) pxa_set_camera_info(&a910_pxacamera_platform_data); + gpiod_add_lookup_table(&camera_supply_gpiod_table); pwm_add_table(ezx_pwm_lookup, ARRAY_SIZE(ezx_pwm_lookup)); platform_add_devices(ARRAY_AND_SIZE(ezx_devices)); platform_add_devices(ARRAY_AND_SIZE(a910_devices)); From e536700ef5bf9788af185bf890a52f296d055ed7 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 7 Jun 2018 14:10:56 +0100 Subject: [PATCH 57/57] regulator: gpio: Revert regulator: fixed/gpio: Revert GPIO descriptor changes due to platform breakage Commit 6059577cb28 "regulator: fixed: Convert to use GPIO descriptor only" broke at least the ams-delta platform since the lookup tables added to the board files use the function name "enable" while the driver uses NULL causing the regulator to not acquire and control the enable GPIOs. Revert that and a couple of other commits that are caught up with it to fix the issue: 2b6c00c157c5bf80 "ARM: pxa, regulator: fix building ezx e680" 6059577cb28d8b15 "regulator: fixed: Convert to use GPIO descriptor only" 37bed97f00734ce3 "regulator: gpio: Get enable GPIO using GPIO descriptor" Reported-by: Janusz Krzysztofik Signed-off-by: Mark Brown --- arch/arm/mach-imx/mach-mx21ads.c | 13 +------- arch/arm/mach-imx/mach-mx27ads.c | 12 +------ arch/arm/mach-mmp/brownstone.c | 12 +------ arch/arm/mach-omap1/board-ams-delta.c | 14 +------- arch/arm/mach-omap2/pdata-quirks.c | 16 +-------- arch/arm/mach-pxa/em-x270.c | 1 + arch/arm/mach-pxa/ezx.c | 33 +++++++------------ arch/arm/mach-pxa/hx4700.c | 12 +------ arch/arm/mach-pxa/magician.c | 13 ++------ arch/arm/mach-pxa/raumfeld.c | 12 ++----- arch/arm/mach-pxa/zeus.c | 23 ++----------- arch/arm/mach-s3c64xx/mach-crag6410.c | 1 + arch/arm/mach-s3c64xx/mach-smdk6410.c | 1 + arch/arm/mach-sa1100/assabet.c | 21 ++++-------- arch/arm/mach-sa1100/generic.c | 5 ++- arch/arm/mach-sa1100/generic.h | 3 +- arch/arm/mach-sa1100/shannon.c | 4 +-- arch/sh/boards/mach-ecovec24/setup.c | 22 ++----------- .../intel-mid/device_libs/platform_bcm43xx.c | 17 ++-------- drivers/regulator/fixed-helper.c | 1 + drivers/regulator/fixed.c | 33 ++++++++++--------- drivers/regulator/gpio-regulator.c | 23 ++++++------- include/linux/regulator/fixed.h | 3 ++ include/linux/regulator/gpio-regulator.h | 3 ++ 24 files changed, 79 insertions(+), 219 deletions(-) diff --git a/arch/arm/mach-imx/mach-mx21ads.c b/arch/arm/mach-imx/mach-mx21ads.c index 5d3b6b4fe6db..5e366824814f 100644 --- a/arch/arm/mach-imx/mach-mx21ads.c +++ b/arch/arm/mach-imx/mach-mx21ads.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -176,7 +175,6 @@ static struct resource mx21ads_mmgpio_resource = DEFINE_RES_MEM_NAMED(MX21ADS_IO_REG, SZ_2, "dat"); static struct bgpio_pdata mx21ads_mmgpio_pdata = { - .label = "mx21ads-mmgpio", .base = MX21ADS_MMGPIO_BASE, .ngpio = 16, }; @@ -205,6 +203,7 @@ static struct regulator_init_data mx21ads_lcd_regulator_init_data = { static struct fixed_voltage_config mx21ads_lcd_regulator_pdata = { .supply_name = "LCD", .microvolts = 3300000, + .gpio = MX21ADS_IO_LCDON, .enable_high = 1, .init_data = &mx21ads_lcd_regulator_init_data, }; @@ -217,15 +216,6 @@ static struct platform_device mx21ads_lcd_regulator = { }, }; -static struct gpiod_lookup_table mx21ads_lcd_regulator_gpiod_table = { - .dev_id = "reg-fixed-voltage.0", /* Let's hope ID 0 is what we get */ - .table = { - GPIO_LOOKUP("mx21ads-mmgpio", 9, - "enable", GPIO_ACTIVE_HIGH), - { }, - }, -}; - /* * Connected is a portrait Sharp-QVGA display * of type: LQ035Q7DB02 @@ -321,7 +311,6 @@ static void __init mx21ads_late_init(void) { imx21_add_mxc_mmc(0, &mx21ads_sdhc_pdata); - gpiod_add_lookup_table(&mx21ads_lcd_regulator_gpiod_table); platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices)); mx21ads_cs8900_resources[1].start = diff --git a/arch/arm/mach-imx/mach-mx27ads.c b/arch/arm/mach-imx/mach-mx27ads.c index 0fdb88db0cbd..a04bb094ded1 100644 --- a/arch/arm/mach-imx/mach-mx27ads.c +++ b/arch/arm/mach-imx/mach-mx27ads.c @@ -16,7 +16,6 @@ #include /* Needed for gpio_to_irq() */ #include -#include #include #include #include @@ -231,17 +230,10 @@ static struct regulator_init_data mx27ads_lcd_regulator_init_data = { static struct fixed_voltage_config mx27ads_lcd_regulator_pdata = { .supply_name = "LCD", .microvolts = 3300000, + .gpio = MX27ADS_LCD_GPIO, .init_data = &mx27ads_lcd_regulator_init_data, }; -static struct gpiod_lookup_table mx27ads_lcd_regulator_gpiod_table = { - .dev_id = "reg-fixed-voltage.0", /* Let's hope ID 0 is what we get */ - .table = { - GPIO_LOOKUP("LCD", 0, "enable", GPIO_ACTIVE_HIGH), - { }, - }, -}; - static void __init mx27ads_regulator_init(void) { struct gpio_chip *vchip; @@ -255,8 +247,6 @@ static void __init mx27ads_regulator_init(void) vchip->set = vgpio_set; gpiochip_add_data(vchip, NULL); - gpiod_add_lookup_table(&mx27ads_lcd_regulator_gpiod_table); - platform_device_register_data(NULL, "reg-fixed-voltage", PLATFORM_DEVID_AUTO, &mx27ads_lcd_regulator_pdata, diff --git a/arch/arm/mach-mmp/brownstone.c b/arch/arm/mach-mmp/brownstone.c index 563b5a278d65..d1613b954926 100644 --- a/arch/arm/mach-mmp/brownstone.c +++ b/arch/arm/mach-mmp/brownstone.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include @@ -149,6 +148,7 @@ static struct regulator_init_data brownstone_v_5vp_data = { static struct fixed_voltage_config brownstone_v_5vp = { .supply_name = "v_5vp", .microvolts = 5000000, + .gpio = GPIO_5V_ENABLE, .enable_high = 1, .enabled_at_boot = 1, .init_data = &brownstone_v_5vp_data, @@ -162,15 +162,6 @@ static struct platform_device brownstone_v_5vp_device = { }, }; -static struct gpiod_lookup_table brownstone_v_5vp_gpiod_table = { - .dev_id = "reg-fixed-voltage.1", /* .id set to 1 above */ - .table = { - GPIO_LOOKUP("gpio-pxa", GPIO_5V_ENABLE, - "enable", GPIO_ACTIVE_HIGH), - { }, - }, -}; - static struct max8925_platform_data brownstone_max8925_info = { .irq_base = MMP_NR_IRQS, }; @@ -226,7 +217,6 @@ static void __init brownstone_init(void) mmp2_add_isram(&mmp2_isram_platdata); /* enable 5v regulator */ - gpiod_add_lookup_table(&brownstone_v_5vp_gpiod_table); platform_device_register(&brownstone_v_5vp_device); } diff --git a/arch/arm/mach-omap1/board-ams-delta.c b/arch/arm/mach-omap1/board-ams-delta.c index 759fa18f6ab4..52e8e53ca154 100644 --- a/arch/arm/mach-omap1/board-ams-delta.c +++ b/arch/arm/mach-omap1/board-ams-delta.c @@ -12,7 +12,6 @@ * published by the Free Software Foundation. */ #include -#include #include #include #include @@ -204,7 +203,6 @@ static struct resource latch2_resources[] = { }; static struct bgpio_pdata latch2_pdata = { - .label = "ams-delta-latch2", .base = AMS_DELTA_LATCH2_GPIO_BASE, .ngpio = AMS_DELTA_LATCH2_NGPIO, }; @@ -274,6 +272,7 @@ static struct regulator_init_data modem_nreset_data = { static struct fixed_voltage_config modem_nreset_config = { .supply_name = "modem_nreset", .microvolts = 3300000, + .gpio = AMS_DELTA_GPIO_PIN_MODEM_NRESET, .startup_delay = 25000, .enable_high = 1, .enabled_at_boot = 1, @@ -288,16 +287,6 @@ static struct platform_device modem_nreset_device = { }, }; -static struct gpiod_lookup_table modem_nreset_gpiod_table = { - .dev_id = "reg-fixed-voltage", - .table = { - /* The AMS_DELTA_GPIO_PIN_MODEM_NRESET is at offset 12 */ - GPIO_LOOKUP("ams-delta-latch2", 12, - "enable", GPIO_ACTIVE_HIGH), - { }, - }, -}; - struct modem_private_data { struct regulator *regulator; }; @@ -581,7 +570,6 @@ static int __init late_init(void) platform_add_devices(late_devices, ARRAY_SIZE(late_devices)); - gpiod_add_lookup_table(&modem_nreset_gpiod_table); err = platform_device_register(&modem_nreset_device); if (err) { pr_err("Couldn't register the modem regulator device\n"); diff --git a/arch/arm/mach-omap2/pdata-quirks.c b/arch/arm/mach-omap2/pdata-quirks.c index 7d1447204fb8..6459816c2879 100644 --- a/arch/arm/mach-omap2/pdata-quirks.c +++ b/arch/arm/mach-omap2/pdata-quirks.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -331,6 +330,7 @@ static struct regulator_init_data pandora_vmmc3 = { static struct fixed_voltage_config pandora_vwlan = { .supply_name = "vwlan", .microvolts = 1800000, /* 1.8V */ + .gpio = PANDORA_WIFI_NRESET_GPIO, .startup_delay = 50000, /* 50ms */ .enable_high = 1, .init_data = &pandora_vmmc3, @@ -344,19 +344,6 @@ static struct platform_device pandora_vwlan_device = { }, }; -static struct gpiod_lookup_table pandora_vwlan_gpiod_table = { - .dev_id = "reg-fixed-voltage.1", - .table = { - /* - * As this is a low GPIO number it should be at the first - * GPIO bank. - */ - GPIO_LOOKUP("gpio-0-31", PANDORA_WIFI_NRESET_GPIO, - "enable", GPIO_ACTIVE_HIGH), - { }, - }, -}; - static void pandora_wl1251_init_card(struct mmc_card *card) { /* @@ -418,7 +405,6 @@ fail: static void __init omap3_pandora_legacy_init(void) { platform_device_register(&pandora_backlight); - gpiod_add_lookup_table(&pandora_vwlan_gpiod_table); platform_device_register(&pandora_vwlan_device); omap_hsmmc_init(pandora_mmc3); omap_hsmmc_late_init(pandora_mmc3); diff --git a/arch/arm/mach-pxa/em-x270.c b/arch/arm/mach-pxa/em-x270.c index 6d7d93981098..49022ad338e9 100644 --- a/arch/arm/mach-pxa/em-x270.c +++ b/arch/arm/mach-pxa/em-x270.c @@ -987,6 +987,7 @@ static struct fixed_voltage_config camera_dummy_config = { .supply_name = "camera_vdd", .input_supply = "vcc cam", .microvolts = 2800000, + .gpio = -1, .enable_high = 0, .init_data = &camera_dummy_initdata, }; diff --git a/arch/arm/mach-pxa/ezx.c b/arch/arm/mach-pxa/ezx.c index 4f33eea73f9a..2c90b58f347d 100644 --- a/arch/arm/mach-pxa/ezx.c +++ b/arch/arm/mach-pxa/ezx.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include @@ -699,39 +698,31 @@ static struct pxa27x_keypad_platform_data e2_keypad_platform_data = { #if defined(CONFIG_MACH_EZX_A780) || defined(CONFIG_MACH_EZX_A910) /* camera */ -static struct regulator_consumer_supply camera_regulator_supplies[] = { +static struct regulator_consumer_supply camera_dummy_supplies[] = { REGULATOR_SUPPLY("vdd", "0-005d"), }; -static struct regulator_init_data camera_regulator_initdata = { - .consumer_supplies = camera_regulator_supplies, - .num_consumer_supplies = ARRAY_SIZE(camera_regulator_supplies), +static struct regulator_init_data camera_dummy_initdata = { + .consumer_supplies = camera_dummy_supplies, + .num_consumer_supplies = ARRAY_SIZE(camera_dummy_supplies), .constraints = { .valid_ops_mask = REGULATOR_CHANGE_STATUS, }, }; -static struct fixed_voltage_config camera_regulator_config = { +static struct fixed_voltage_config camera_dummy_config = { .supply_name = "camera_vdd", .microvolts = 2800000, + .gpio = GPIO50_nCAM_EN, .enable_high = 0, - .init_data = &camera_regulator_initdata, + .init_data = &camera_dummy_initdata, }; -static struct platform_device camera_supply_regulator_device = { +static struct platform_device camera_supply_dummy_device = { .name = "reg-fixed-voltage", .id = 1, .dev = { - .platform_data = &camera_regulator_config, - }, -}; - -static struct gpiod_lookup_table camera_supply_gpiod_table = { - .dev_id = "reg-fixed-voltage.1", - .table = { - GPIO_LOOKUP("gpio-pxa", GPIO50_nCAM_EN, - "enable", GPIO_ACTIVE_HIGH), - { }, + .platform_data = &camera_dummy_config, }, }; #endif @@ -809,7 +800,7 @@ static struct i2c_board_info a780_i2c_board_info[] = { static struct platform_device *a780_devices[] __initdata = { &a780_gpio_keys, - &camera_supply_regulator_device, + &camera_supply_dummy_device, }; static void __init a780_init(void) @@ -832,7 +823,6 @@ static void __init a780_init(void) if (a780_camera_init() == 0) pxa_set_camera_info(&a780_pxacamera_platform_data); - gpiod_add_lookup_table(&camera_supply_gpiod_table); pwm_add_table(ezx_pwm_lookup, ARRAY_SIZE(ezx_pwm_lookup)); platform_add_devices(ARRAY_AND_SIZE(ezx_devices)); platform_add_devices(ARRAY_AND_SIZE(a780_devices)); @@ -1108,7 +1098,7 @@ static struct i2c_board_info __initdata a910_i2c_board_info[] = { static struct platform_device *a910_devices[] __initdata = { &a910_gpio_keys, - &camera_supply_regulator_device, + &camera_supply_dummy_device, }; static void __init a910_init(void) @@ -1131,7 +1121,6 @@ static void __init a910_init(void) if (a910_camera_init() == 0) pxa_set_camera_info(&a910_pxacamera_platform_data); - gpiod_add_lookup_table(&camera_supply_gpiod_table); pwm_add_table(ezx_pwm_lookup, ARRAY_SIZE(ezx_pwm_lookup)); platform_add_devices(ARRAY_AND_SIZE(ezx_devices)); platform_add_devices(ARRAY_AND_SIZE(a910_devices)); diff --git a/arch/arm/mach-pxa/hx4700.c b/arch/arm/mach-pxa/hx4700.c index 6717a10180eb..e2e7f247a645 100644 --- a/arch/arm/mach-pxa/hx4700.c +++ b/arch/arm/mach-pxa/hx4700.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -712,6 +711,7 @@ static struct gpio_regulator_state bq24022_states[] = { static struct gpio_regulator_config bq24022_info = { .supply_name = "bq24022", + .enable_gpio = GPIO72_HX4700_BQ24022_nCHARGE_EN, .enable_high = 0, .enabled_at_boot = 0, @@ -733,15 +733,6 @@ static struct platform_device bq24022 = { }, }; -static struct gpiod_lookup_table bq24022_gpiod_table = { - .dev_id = "gpio-regulator", - .table = { - GPIO_LOOKUP("gpio-pxa", GPIO72_HX4700_BQ24022_nCHARGE_EN, - "enable", GPIO_ACTIVE_HIGH), - { }, - }, -}; - /* * StrataFlash */ @@ -884,7 +875,6 @@ static void __init hx4700_init(void) pxa_set_btuart_info(NULL); pxa_set_stuart_info(NULL); - gpiod_add_lookup_table(&bq24022_gpiod_table); platform_add_devices(devices, ARRAY_SIZE(devices)); pwm_add_table(hx4700_pwm_lookup, ARRAY_SIZE(hx4700_pwm_lookup)); diff --git a/arch/arm/mach-pxa/magician.c b/arch/arm/mach-pxa/magician.c index 9a5bda3ea194..c5325d1ae77b 100644 --- a/arch/arm/mach-pxa/magician.c +++ b/arch/arm/mach-pxa/magician.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -657,6 +656,7 @@ static struct gpio_regulator_state bq24022_states[] = { static struct gpio_regulator_config bq24022_info = { .supply_name = "bq24022", + .enable_gpio = GPIO30_MAGICIAN_BQ24022_nCHARGE_EN, .enable_high = 0, .enabled_at_boot = 1, @@ -678,15 +678,6 @@ static struct platform_device bq24022 = { }, }; -static struct gpiod_lookup_table bq24022_gpiod_table = { - .dev_id = "gpio-regulator", - .table = { - GPIO_LOOKUP("gpio-pxa", GPIO30_MAGICIAN_BQ24022_nCHARGE_EN, - "enable", GPIO_ACTIVE_HIGH), - { }, - }, -}; - /* * fixed regulator for ads7846 */ @@ -705,6 +696,7 @@ static struct regulator_init_data vads7846_regulator = { static struct fixed_voltage_config vads7846 = { .supply_name = "vads7846", .microvolts = 3300000, /* probably */ + .gpio = -EINVAL, .startup_delay = 0, .init_data = &vads7846_regulator, }; @@ -1015,7 +1007,6 @@ static void __init magician_init(void) regulator_register_always_on(0, "power", pwm_backlight_supply, ARRAY_SIZE(pwm_backlight_supply), 5000000); - gpiod_add_lookup_table(&bq24022_gpiod_table); platform_add_devices(ARRAY_AND_SIZE(devices)); } diff --git a/arch/arm/mach-pxa/raumfeld.c b/arch/arm/mach-pxa/raumfeld.c index ee766e4ebddc..034345546f84 100644 --- a/arch/arm/mach-pxa/raumfeld.c +++ b/arch/arm/mach-pxa/raumfeld.c @@ -886,6 +886,7 @@ static struct regulator_init_data audio_va_initdata = { static struct fixed_voltage_config audio_va_config = { .supply_name = "audio_va", .microvolts = 5000000, + .gpio = GPIO_AUDIO_VA_ENABLE, .enable_high = 1, .enabled_at_boot = 0, .init_data = &audio_va_initdata, @@ -899,15 +900,6 @@ static struct platform_device audio_va_device = { }, }; -static struct gpiod_lookup_table audio_va_gpiod_table = { - .dev_id = "reg-fixed-voltage.0", - .table = { - GPIO_LOOKUP("gpio-pxa", GPIO_AUDIO_VA_ENABLE, - "enable", GPIO_ACTIVE_HIGH), - { }, - }, -}; - /* Dummy supplies for Codec's VD/VLC */ static struct regulator_consumer_supply audio_dummy_supplies[] = { @@ -926,6 +918,7 @@ static struct regulator_init_data audio_dummy_initdata = { static struct fixed_voltage_config audio_dummy_config = { .supply_name = "audio_vd", .microvolts = 3300000, + .gpio = -1, .init_data = &audio_dummy_initdata, }; @@ -1040,7 +1033,6 @@ static void __init raumfeld_audio_init(void) else gpio_direction_output(GPIO_MCLK_RESET, 1); - gpiod_add_lookup_table(&audio_va_gpiod_table); platform_add_devices(ARRAY_AND_SIZE(audio_regulator_devices)); } diff --git a/arch/arm/mach-pxa/zeus.c b/arch/arm/mach-pxa/zeus.c index 58e05afcece0..e3851795d6d7 100644 --- a/arch/arm/mach-pxa/zeus.c +++ b/arch/arm/mach-pxa/zeus.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include @@ -411,6 +410,7 @@ static struct regulator_init_data can_regulator_init_data = { static struct fixed_voltage_config can_regulator_pdata = { .supply_name = "CAN_SHDN", .microvolts = 3300000, + .gpio = ZEUS_CAN_SHDN_GPIO, .init_data = &can_regulator_init_data, }; @@ -422,15 +422,6 @@ static struct platform_device can_regulator_device = { }, }; -static struct gpiod_lookup_table can_regulator_gpiod_table = { - .dev_id = "reg-fixed-voltage.0", - .table = { - GPIO_LOOKUP("gpio-pxa", ZEUS_CAN_SHDN_GPIO, - "enable", GPIO_ACTIVE_HIGH), - { }, - }, -}; - static struct mcp251x_platform_data zeus_mcp2515_pdata = { .oscillator_frequency = 16*1000*1000, }; @@ -547,6 +538,7 @@ static struct regulator_init_data zeus_ohci_regulator_data = { static struct fixed_voltage_config zeus_ohci_regulator_config = { .supply_name = "vbus2", .microvolts = 5000000, /* 5.0V */ + .gpio = ZEUS_USB2_PWREN_GPIO, .enable_high = 1, .startup_delay = 0, .init_data = &zeus_ohci_regulator_data, @@ -560,15 +552,6 @@ static struct platform_device zeus_ohci_regulator_device = { }, }; -static struct gpiod_lookup_table zeus_ohci_regulator_gpiod_table = { - .dev_id = "reg-fixed-voltage.0", - .table = { - GPIO_LOOKUP("gpio-pxa", ZEUS_USB2_PWREN_GPIO, - "enable", GPIO_ACTIVE_HIGH), - { }, - }, -}; - static struct pxaohci_platform_data zeus_ohci_platform_data = { .port_mode = PMM_NPS_MODE, /* Clear Power Control Polarity Low and set Power Sense @@ -872,8 +855,6 @@ static void __init zeus_init(void) pxa2xx_mfp_config(ARRAY_AND_SIZE(zeus_pin_config)); - gpiod_add_lookup_table(&can_regulator_gpiod_table); - gpiod_add_lookup_table(&zeus_ohci_regulator_gpiod_table); platform_add_devices(zeus_devices, ARRAY_SIZE(zeus_devices)); zeus_register_ohci(); diff --git a/arch/arm/mach-s3c64xx/mach-crag6410.c b/arch/arm/mach-s3c64xx/mach-crag6410.c index 379424d72ae7..f04650297487 100644 --- a/arch/arm/mach-s3c64xx/mach-crag6410.c +++ b/arch/arm/mach-s3c64xx/mach-crag6410.c @@ -352,6 +352,7 @@ static struct fixed_voltage_config wallvdd_pdata = { .supply_name = "WALLVDD", .microvolts = 5000000, .init_data = &wallvdd_data, + .gpio = -EINVAL, }; static struct platform_device wallvdd_device = { diff --git a/arch/arm/mach-s3c64xx/mach-smdk6410.c b/arch/arm/mach-s3c64xx/mach-smdk6410.c index 908e5aa831c8..c46fa5dfd2e0 100644 --- a/arch/arm/mach-s3c64xx/mach-smdk6410.c +++ b/arch/arm/mach-s3c64xx/mach-smdk6410.c @@ -222,6 +222,7 @@ static struct fixed_voltage_config smdk6410_b_pwr_5v_pdata = { .supply_name = "B_PWR_5V", .microvolts = 5000000, .init_data = &smdk6410_b_pwr_5v_data, + .gpio = -EINVAL, }; static struct platform_device smdk6410_b_pwr_5v = { diff --git a/arch/arm/mach-sa1100/assabet.c b/arch/arm/mach-sa1100/assabet.c index dbb53c520165..575ec085cffa 100644 --- a/arch/arm/mach-sa1100/assabet.c +++ b/arch/arm/mach-sa1100/assabet.c @@ -101,7 +101,7 @@ static int __init assabet_init_gpio(void __iomem *reg, u32 def_val) assabet_bcr_gc = gc; - return 0; + return gc->base; } /* @@ -471,14 +471,6 @@ static struct fixed_voltage_config assabet_cf_vcc_pdata __initdata = { .enable_high = 1, }; -static struct gpiod_lookup_table assabet_cf_vcc_gpio_table = { - .dev_id = "reg-fixed-voltage.0", - .table = { - GPIO_LOOKUP("assabet", 0, "enable", GPIO_ACTIVE_HIGH), - { }, - }, -}; - static void __init assabet_init(void) { /* @@ -525,11 +517,9 @@ static void __init assabet_init(void) neponset_resources, ARRAY_SIZE(neponset_resources)); #endif } else { - gpiod_add_lookup_table(&assabet_cf_vcc_gpio_table); sa11x0_register_fixed_regulator(0, &assabet_cf_vcc_pdata, - assabet_cf_vcc_consumers, - ARRAY_SIZE(assabet_cf_vcc_consumers), - true); + assabet_cf_vcc_consumers, + ARRAY_SIZE(assabet_cf_vcc_consumers)); } @@ -812,6 +802,7 @@ fs_initcall(assabet_leds_init); void __init assabet_init_irq(void) { + unsigned int assabet_gpio_base; u32 def_val; sa1100_init_irq(); @@ -826,7 +817,9 @@ void __init assabet_init_irq(void) * * This must precede any driver calls to BCR_set() or BCR_clear(). */ - assabet_init_gpio((void *)&ASSABET_BCR, def_val); + assabet_gpio_base = assabet_init_gpio((void *)&ASSABET_BCR, def_val); + + assabet_cf_vcc_pdata.gpio = assabet_gpio_base + 0; } MACHINE_START(ASSABET, "Intel-Assabet") diff --git a/arch/arm/mach-sa1100/generic.c b/arch/arm/mach-sa1100/generic.c index 800321c6cbd8..7167ddf84a0e 100644 --- a/arch/arm/mach-sa1100/generic.c +++ b/arch/arm/mach-sa1100/generic.c @@ -348,8 +348,7 @@ void __init sa11x0_init_late(void) int __init sa11x0_register_fixed_regulator(int n, struct fixed_voltage_config *cfg, - struct regulator_consumer_supply *supplies, unsigned num_supplies, - bool uses_gpio) + struct regulator_consumer_supply *supplies, unsigned num_supplies) { struct regulator_init_data *id; @@ -357,7 +356,7 @@ int __init sa11x0_register_fixed_regulator(int n, if (!cfg->init_data) return -ENOMEM; - if (!uses_gpio) + if (cfg->gpio < 0) id->constraints.always_on = 1; id->constraints.name = cfg->supply_name; id->constraints.min_uV = cfg->microvolts; diff --git a/arch/arm/mach-sa1100/generic.h b/arch/arm/mach-sa1100/generic.h index 158a4fd5ca24..5f3cb52fa6ab 100644 --- a/arch/arm/mach-sa1100/generic.h +++ b/arch/arm/mach-sa1100/generic.h @@ -54,5 +54,4 @@ void sa11x0_register_pcmcia(int socket, struct gpiod_lookup_table *); struct fixed_voltage_config; struct regulator_consumer_supply; int sa11x0_register_fixed_regulator(int n, struct fixed_voltage_config *cfg, - struct regulator_consumer_supply *supplies, unsigned num_supplies, - bool uses_gpio); + struct regulator_consumer_supply *supplies, unsigned num_supplies); diff --git a/arch/arm/mach-sa1100/shannon.c b/arch/arm/mach-sa1100/shannon.c index 5bc82e2671c6..22f7fe0b809f 100644 --- a/arch/arm/mach-sa1100/shannon.c +++ b/arch/arm/mach-sa1100/shannon.c @@ -102,14 +102,14 @@ static struct fixed_voltage_config shannon_cf_vcc_pdata __initdata = { .supply_name = "cf-power", .microvolts = 3300000, .enabled_at_boot = 1, + .gpio = -EINVAL, }; static void __init shannon_init(void) { sa11x0_register_fixed_regulator(0, &shannon_cf_vcc_pdata, shannon_cf_vcc_consumers, - ARRAY_SIZE(shannon_cf_vcc_consumers), - false); + ARRAY_SIZE(shannon_cf_vcc_consumers)); sa11x0_register_pcmcia(0, &shannon_pcmcia0_gpio_table); sa11x0_register_pcmcia(1, &shannon_pcmcia1_gpio_table); sa11x0_ppc_configure_mcp(); diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c index c296b5c399b7..adc61d14172c 100644 --- a/arch/sh/boards/mach-ecovec24/setup.c +++ b/arch/sh/boards/mach-ecovec24/setup.c @@ -633,6 +633,7 @@ static struct regulator_init_data cn12_power_init_data = { static struct fixed_voltage_config cn12_power_info = { .supply_name = "CN12 SD/MMC Vdd", .microvolts = 3300000, + .gpio = GPIO_PTB7, .enable_high = 1, .init_data = &cn12_power_init_data, }; @@ -645,16 +646,6 @@ static struct platform_device cn12_power = { }, }; -static struct gpiod_lookup_table cn12_power_gpiod_table = { - .dev_id = "reg-fixed-voltage.0", - .table = { - /* Offset 7 on port B */ - GPIO_LOOKUP("sh7724_pfc", GPIO_PTB7, - "enable", GPIO_ACTIVE_HIGH), - { }, - }, -}; - #if defined(CONFIG_MMC_SDHI) || defined(CONFIG_MMC_SDHI_MODULE) /* SDHI0 */ static struct regulator_consumer_supply sdhi0_power_consumers[] = @@ -674,6 +665,7 @@ static struct regulator_init_data sdhi0_power_init_data = { static struct fixed_voltage_config sdhi0_power_info = { .supply_name = "CN11 SD/MMC Vdd", .microvolts = 3300000, + .gpio = GPIO_PTB6, .enable_high = 1, .init_data = &sdhi0_power_init_data, }; @@ -686,16 +678,6 @@ static struct platform_device sdhi0_power = { }, }; -static struct gpiod_lookup_table sdhi0_power_gpiod_table = { - .dev_id = "reg-fixed-voltage.1", - .table = { - /* Offset 6 on port B */ - GPIO_LOOKUP("sh7724_pfc", GPIO_PTB6, - "enable", GPIO_ACTIVE_HIGH), - { }, - }, -}; - static struct tmio_mmc_data sdhi0_info = { .chan_priv_tx = (void *)SHDMA_SLAVE_SDHI0_TX, .chan_priv_rx = (void *)SHDMA_SLAVE_SDHI0_RX, diff --git a/arch/x86/platform/intel-mid/device_libs/platform_bcm43xx.c b/arch/x86/platform/intel-mid/device_libs/platform_bcm43xx.c index fc77d69e51d7..4392c15ed9e0 100644 --- a/arch/x86/platform/intel-mid/device_libs/platform_bcm43xx.c +++ b/arch/x86/platform/intel-mid/device_libs/platform_bcm43xx.c @@ -10,7 +10,7 @@ * of the License. */ -#include +#include #include #include #include @@ -43,6 +43,7 @@ static struct fixed_voltage_config bcm43xx_vmmc = { * real voltage and signaling are still 1.8V. */ .microvolts = 2000000, /* 1.8V */ + .gpio = -EINVAL, .startup_delay = 250 * 1000, /* 250ms */ .enable_high = 1, /* active high */ .enabled_at_boot = 0, /* disabled at boot */ @@ -57,23 +58,11 @@ static struct platform_device bcm43xx_vmmc_regulator = { }, }; -static struct gpiod_lookup_table bcm43xx_vmmc_gpio_table = { - .dev_id = "reg-fixed-voltage.0", - .table = { - GPIO_LOOKUP("0000:00:0c.0", -1, "enable", GPIO_ACTIVE_LOW), - {} - }, -}; - static int __init bcm43xx_regulator_register(void) { - struct gpiod_lookup_table *table = &bcm43xx_vmmc_gpio_table; - struct gpiod_lookup *lookup = table->table; int ret; - lookup[0].chip_hwnum = get_gpio_by_name(WLAN_SFI_GPIO_ENABLE_NAME); - gpiod_add_lookup_table(table); - + bcm43xx_vmmc.gpio = get_gpio_by_name(WLAN_SFI_GPIO_ENABLE_NAME); ret = platform_device_register(&bcm43xx_vmmc_regulator); if (ret) { pr_err("%s: vmmc regulator register failed\n", __func__); diff --git a/drivers/regulator/fixed-helper.c b/drivers/regulator/fixed-helper.c index 2c6098e6f4bc..777fac6fb4cb 100644 --- a/drivers/regulator/fixed-helper.c +++ b/drivers/regulator/fixed-helper.c @@ -43,6 +43,7 @@ struct platform_device *regulator_register_always_on(int id, const char *name, } data->cfg.microvolts = uv; + data->cfg.gpio = -EINVAL; data->cfg.enabled_at_boot = 1; data->cfg.init_data = &data->init_data; diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c index 1142f195529b..988a7472c2ab 100644 --- a/drivers/regulator/fixed.c +++ b/drivers/regulator/fixed.c @@ -24,9 +24,10 @@ #include #include #include -#include +#include #include #include +#include #include #include @@ -77,6 +78,10 @@ of_get_fixed_voltage_config(struct device *dev, if (init_data->constraints.boot_on) config->enabled_at_boot = true; + config->gpio = of_get_named_gpio(np, "gpio", 0); + if ((config->gpio < 0) && (config->gpio != -ENOENT)) + return ERR_PTR(config->gpio); + of_property_read_u32(np, "startup-delay-us", &config->startup_delay); config->enable_high = of_property_read_bool(np, "enable-active-high"); @@ -97,7 +102,6 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev) struct fixed_voltage_config *config; struct fixed_voltage_data *drvdata; struct regulator_config cfg = { }; - enum gpiod_flags gflags; int ret; drvdata = devm_kzalloc(&pdev->dev, sizeof(struct fixed_voltage_data), @@ -146,28 +150,25 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev) drvdata->desc.fixed_uV = config->microvolts; + if (gpio_is_valid(config->gpio)) { + cfg.ena_gpio = config->gpio; + if (pdev->dev.of_node) + cfg.ena_gpio_initialized = true; + } cfg.ena_gpio_invert = !config->enable_high; if (config->enabled_at_boot) { if (config->enable_high) - gflags = GPIOD_OUT_HIGH; + cfg.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH; else - gflags = GPIOD_OUT_LOW; + cfg.ena_gpio_flags |= GPIOF_OUT_INIT_LOW; } else { if (config->enable_high) - gflags = GPIOD_OUT_LOW; + cfg.ena_gpio_flags |= GPIOF_OUT_INIT_LOW; else - gflags = GPIOD_OUT_HIGH; + cfg.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH; } - if (config->gpio_is_open_drain) { - if (gflags == GPIOD_OUT_HIGH) - gflags = GPIOD_OUT_HIGH_OPEN_DRAIN; - else - gflags = GPIOD_OUT_LOW_OPEN_DRAIN; - } - - cfg.ena_gpiod = devm_gpiod_get_optional(&pdev->dev, NULL, gflags); - if (IS_ERR(cfg.ena_gpiod)) - return PTR_ERR(cfg.ena_gpiod); + if (config->gpio_is_open_drain) + cfg.ena_gpio_flags |= GPIOF_OPEN_DRAIN; cfg.dev = &pdev->dev; cfg.init_data = config->init_data; diff --git a/drivers/regulator/gpio-regulator.c b/drivers/regulator/gpio-regulator.c index 9d6094c4d71c..a86b8997bb54 100644 --- a/drivers/regulator/gpio-regulator.c +++ b/drivers/regulator/gpio-regulator.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include @@ -162,6 +161,10 @@ of_get_gpio_regulator_config(struct device *dev, struct device_node *np, of_property_read_u32(np, "startup-delay-us", &config->startup_delay); + config->enable_gpio = of_get_named_gpio(np, "enable-gpio", 0); + if (config->enable_gpio < 0 && config->enable_gpio != -ENOENT) + return ERR_PTR(config->enable_gpio); + /* Fetch GPIOs. - optional property*/ ret = of_gpio_count(np); if ((ret < 0) && (ret != -ENOENT)) @@ -252,7 +255,6 @@ static int gpio_regulator_probe(struct platform_device *pdev) struct device_node *np = pdev->dev.of_node; struct gpio_regulator_data *drvdata; struct regulator_config cfg = { }; - enum gpiod_flags gflags; int ptr, ret, state; drvdata = devm_kzalloc(&pdev->dev, sizeof(struct gpio_regulator_data), @@ -338,22 +340,21 @@ static int gpio_regulator_probe(struct platform_device *pdev) cfg.driver_data = drvdata; cfg.of_node = np; + if (gpio_is_valid(config->enable_gpio)) { + cfg.ena_gpio = config->enable_gpio; + cfg.ena_gpio_initialized = true; + } cfg.ena_gpio_invert = !config->enable_high; if (config->enabled_at_boot) { if (config->enable_high) - gflags = GPIOD_OUT_HIGH; + cfg.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH; else - gflags = GPIOD_OUT_LOW; + cfg.ena_gpio_flags |= GPIOF_OUT_INIT_LOW; } else { if (config->enable_high) - gflags = GPIOD_OUT_LOW; + cfg.ena_gpio_flags |= GPIOF_OUT_INIT_LOW; else - gflags = GPIOD_OUT_HIGH; - } - cfg.ena_gpiod = devm_gpiod_get_optional(&pdev->dev, "enable", gflags); - if (IS_ERR(cfg.ena_gpiod)) { - ret = PTR_ERR(cfg.ena_gpiod); - goto err_stategpio; + cfg.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH; } drvdata->dev = regulator_register(&drvdata->desc, &cfg); diff --git a/include/linux/regulator/fixed.h b/include/linux/regulator/fixed.h index 1a4340ed8e2b..48918be649d4 100644 --- a/include/linux/regulator/fixed.h +++ b/include/linux/regulator/fixed.h @@ -24,6 +24,8 @@ struct regulator_init_data; * @supply_name: Name of the regulator supply * @input_supply: Name of the input regulator supply * @microvolts: Output voltage of regulator + * @gpio: GPIO to use for enable control + * set to -EINVAL if not used * @startup_delay: Start-up time in microseconds * @gpio_is_open_drain: Gpio pin is open drain or normal type. * If it is open drain type then HIGH will be set @@ -47,6 +49,7 @@ struct fixed_voltage_config { const char *supply_name; const char *input_supply; int microvolts; + int gpio; unsigned startup_delay; unsigned gpio_is_open_drain:1; unsigned enable_high:1; diff --git a/include/linux/regulator/gpio-regulator.h b/include/linux/regulator/gpio-regulator.h index 536cab86f2d5..19fbd267406d 100644 --- a/include/linux/regulator/gpio-regulator.h +++ b/include/linux/regulator/gpio-regulator.h @@ -44,6 +44,8 @@ struct gpio_regulator_state { /** * struct gpio_regulator_config - config structure * @supply_name: Name of the regulator supply + * @enable_gpio: GPIO to use for enable control + * set to -EINVAL if not used * @enable_high: Polarity of enable GPIO * 1 = Active high, 0 = Active low * @enabled_at_boot: Whether regulator has been enabled at @@ -67,6 +69,7 @@ struct gpio_regulator_state { struct gpio_regulator_config { const char *supply_name; + int enable_gpio; unsigned enable_high:1; unsigned enabled_at_boot:1; unsigned startup_delay;