diff options
| -rw-r--r-- | drivers/power/regulator/s2mps11_regulator.c | 364 | ||||
| -rw-r--r-- | include/power/s2mps11.h | 17 |
2 files changed, 205 insertions, 176 deletions
diff --git a/drivers/power/regulator/s2mps11_regulator.c b/drivers/power/regulator/s2mps11_regulator.c index 96de55065fe..db981df53ae 100644 --- a/drivers/power/regulator/s2mps11_regulator.c +++ b/drivers/power/regulator/s2mps11_regulator.c @@ -13,6 +13,112 @@ #include <power/regulator.h> #include <power/s2mps11.h> +#define regulator_desc_s2mps11_buck(num, mask, min, step, max_hex) \ + [num] = { \ + .mode_reg = S2MPS11_REG_B##num##CTRL1, \ + .mode_mask = S2MPS11_BUCK_MODE_MASK << S2MPS11_BUCK_MODE_SHIFT, \ + .volt_reg = S2MPS11_REG_B##num##CTRL2, \ + .volt_mask = mask, \ + .volt_min = min, \ + .volt_step = step, \ + .volt_max_hex = max_hex, \ + } + +#define regulator_desc_s2mps11_buck1_2_3_4_6(num) \ + regulator_desc_s2mps11_buck(num, S2MPS11_BUCK_VOLT_MASK, \ + S2MPS11_BUCK_UV_MIN, \ + S2MPS11_BUCK_LSTEP, \ + S2MPS11_BUCK_VOLT_MAX_HEX) + +#define regulator_desc_s2mps11_buck5 \ + regulator_desc_s2mps11_buck(5, S2MPS11_BUCK_VOLT_MASK, \ + S2MPS11_BUCK_UV_MIN, \ + S2MPS11_BUCK_LSTEP, \ + S2MPS11_BUCK5_VOLT_MAX_HEX) + +#define regulator_desc_s2mps11_buck7_8_10(num) \ + regulator_desc_s2mps11_buck(num, S2MPS11_BUCK_VOLT_MASK, \ + S2MPS11_BUCK_UV_HMIN, \ + S2MPS11_BUCK_HSTEP, \ + S2MPS11_BUCK7_8_10_VOLT_MAX_HEX) + +#define regulator_desc_s2mps11_buck9 \ + regulator_desc_s2mps11_buck(9, S2MPS11_BUCK9_VOLT_MASK, \ + S2MPS11_BUCK_UV_MIN, \ + S2MPS11_BUCK9_STEP, \ + S2MPS11_BUCK9_VOLT_MAX_HEX) + +static const struct sec_regulator_desc s2mps11_buck_desc[] = { + regulator_desc_s2mps11_buck1_2_3_4_6(1), + regulator_desc_s2mps11_buck1_2_3_4_6(2), + regulator_desc_s2mps11_buck1_2_3_4_6(3), + regulator_desc_s2mps11_buck1_2_3_4_6(4), + regulator_desc_s2mps11_buck5, + regulator_desc_s2mps11_buck1_2_3_4_6(6), + regulator_desc_s2mps11_buck7_8_10(7), + regulator_desc_s2mps11_buck7_8_10(8), + regulator_desc_s2mps11_buck9, + regulator_desc_s2mps11_buck7_8_10(10), +}; + +#define regulator_desc_s2mps11_ldo(num, step) \ + [num] = { \ + .mode_reg = S2MPS11_REG_L##num##CTRL, \ + .mode_mask = S2MPS11_LDO_MODE_MASK << S2MPS11_LDO_MODE_SHIFT, \ + .volt_reg = S2MPS11_REG_L##num##CTRL, \ + .volt_mask = S2MPS11_LDO_VOLT_MASK, \ + .volt_min = S2MPS11_LDO_UV_MIN, \ + .volt_step = step, \ + .volt_max_hex = S2MPS11_LDO_VOLT_MAX_HEX \ + } + +#define regulator_desc_s2mps11_ldo_type1(num) \ + regulator_desc_s2mps11_ldo(num, S2MPS11_LDO_STEP) + +#define regulator_desc_s2mps11_ldo_type2(num) \ + regulator_desc_s2mps11_ldo(num, S2MPS11_LDO_STEP * 2) + +static const struct sec_regulator_desc s2mps11_ldo_desc[] = { + regulator_desc_s2mps11_ldo_type1(1), + regulator_desc_s2mps11_ldo_type2(2), + regulator_desc_s2mps11_ldo_type2(3), + regulator_desc_s2mps11_ldo_type2(4), + regulator_desc_s2mps11_ldo_type2(5), + regulator_desc_s2mps11_ldo_type1(6), + regulator_desc_s2mps11_ldo_type2(7), + regulator_desc_s2mps11_ldo_type2(8), + regulator_desc_s2mps11_ldo_type2(9), + regulator_desc_s2mps11_ldo_type2(10), + regulator_desc_s2mps11_ldo_type1(11), + regulator_desc_s2mps11_ldo_type2(12), + regulator_desc_s2mps11_ldo_type2(13), + regulator_desc_s2mps11_ldo_type2(14), + regulator_desc_s2mps11_ldo_type2(15), + regulator_desc_s2mps11_ldo_type2(16), + regulator_desc_s2mps11_ldo_type2(17), + regulator_desc_s2mps11_ldo_type2(18), + regulator_desc_s2mps11_ldo_type2(19), + regulator_desc_s2mps11_ldo_type2(20), + regulator_desc_s2mps11_ldo_type2(21), + regulator_desc_s2mps11_ldo_type1(22), + regulator_desc_s2mps11_ldo_type1(23), + regulator_desc_s2mps11_ldo_type2(24), + regulator_desc_s2mps11_ldo_type2(25), + regulator_desc_s2mps11_ldo_type2(26), + regulator_desc_s2mps11_ldo_type1(27), + regulator_desc_s2mps11_ldo_type2(28), + regulator_desc_s2mps11_ldo_type2(29), + regulator_desc_s2mps11_ldo_type2(30), + regulator_desc_s2mps11_ldo_type2(31), + regulator_desc_s2mps11_ldo_type2(32), + regulator_desc_s2mps11_ldo_type2(33), + regulator_desc_s2mps11_ldo_type2(34), + regulator_desc_s2mps11_ldo_type1(35), + regulator_desc_s2mps11_ldo_type2(36), + regulator_desc_s2mps11_ldo_type2(37), + regulator_desc_s2mps11_ldo_type2(38), +}; + #define MODE(_id, _val, _name) { \ .id = _id, \ .register_value = _val, \ @@ -33,94 +139,37 @@ static struct dm_regulator_mode s2mps11_ldo_modes[] = { MODE(OP_ON, S2MPS11_LDO_MODE_ON, "ON"), }; -static const char s2mps11_buck_ctrl[] = { - 0xff, 0x25, 0x27, 0x29, 0x2b, 0x2d, 0x33, 0x35, 0x37, 0x39, 0x3b -}; - -static const char s2mps11_buck_out[] = { - 0xff, 0x26, 0x28, 0x2a, 0x2c, 0x2f, 0x34, 0x36, 0x38, 0x3a, 0x3c -}; - -static int s2mps11_buck_hex2volt(int buck, int hex) +static const ulong s2mps11_get_variant(struct udevice *dev) { - unsigned int uV = 0; - - if (hex < 0) - goto bad; - - switch (buck) { - case 7: - case 8: - case 10: - if (hex > S2MPS11_BUCK7_8_10_VOLT_MAX_HEX) - goto bad; + struct udevice *parent = dev_get_parent(dev); - uV = hex * S2MPS11_BUCK_HSTEP + S2MPS11_BUCK_UV_HMIN; - break; - case 9: - if (hex > S2MPS11_BUCK9_VOLT_MAX_HEX) - goto bad; - uV = hex * S2MPS11_BUCK9_STEP * 2 + S2MPS11_BUCK9_UV_MIN; - break; - default: - if (buck == 5 && hex > S2MPS11_BUCK5_VOLT_MAX_HEX) - goto bad; - else if (buck != 5 && hex > S2MPS11_BUCK_VOLT_MAX_HEX) - goto bad; - - uV = hex * S2MPS11_BUCK_LSTEP + S2MPS11_BUCK_UV_MIN; - break; + if (!parent) { + pr_err("Parent is non-existent, this shouldn't happen!\n"); + return VARIANT_NONE; } - return uV; -bad: - pr_err("Value: %#x is wrong for BUCK%d", hex, buck); - return -EINVAL; + return dev_get_driver_data(parent); } -static int s2mps11_buck_volt2hex(int buck, int uV) +static int s2mps11_buck_val(struct udevice *dev, int op, int *uV) { - int hex; - - switch (buck) { - case 7: - case 8: - case 10: - hex = (uV - S2MPS11_BUCK_UV_HMIN) / S2MPS11_BUCK_HSTEP; - if (hex > S2MPS11_BUCK7_8_10_VOLT_MAX_HEX) - goto bad; + const struct sec_regulator_desc *buck_desc; + int num_bucks, hex, buck, ret; + u32 addr; + u8 val; - break; - case 9: - hex = (uV - S2MPS11_BUCK9_UV_MIN) / S2MPS11_BUCK9_STEP; - if (hex > S2MPS11_BUCK9_VOLT_MAX_HEX) - goto bad; + switch (s2mps11_get_variant(dev)) { + case VARIANT_S2MPS11: + buck_desc = s2mps11_buck_desc; + num_bucks = ARRAY_SIZE(s2mps11_buck_desc); break; default: - hex = (uV - S2MPS11_BUCK_UV_MIN) / S2MPS11_BUCK_LSTEP; - if (buck == 5 && hex > S2MPS11_BUCK5_VOLT_MAX_HEX) - goto bad; - else if (buck != 5 && hex > S2MPS11_BUCK_VOLT_MAX_HEX) - goto bad; - break; - }; - - if (hex >= 0) - return hex; - -bad: - pr_err("Value: %d uV is wrong for BUCK%d", uV, buck); - return -EINVAL; -} - -static int s2mps11_buck_val(struct udevice *dev, int op, int *uV) -{ - int hex, buck, ret; - u32 mask, addr; - u8 val; + pr_err("Unknown device type\n"); + return -EINVAL; + } buck = dev->driver_data; - if (buck < 1 || buck > S2MPS11_BUCK_NUM) { + if (buck < 1 || buck > num_bucks) { pr_err("Wrong buck number: %d\n", buck); return -EINVAL; } @@ -128,35 +177,25 @@ static int s2mps11_buck_val(struct udevice *dev, int op, int *uV) if (op == PMIC_OP_GET) *uV = 0; - addr = s2mps11_buck_out[buck]; - - switch (buck) { - case 9: - mask = S2MPS11_BUCK9_VOLT_MASK; - break; - default: - mask = S2MPS11_BUCK_VOLT_MASK; - break; - } + addr = buck_desc[buck].volt_reg; ret = pmic_read(dev->parent, addr, &val, 1); if (ret) return ret; if (op == PMIC_OP_GET) { - val &= mask; - ret = s2mps11_buck_hex2volt(buck, val); - if (ret < 0) - return ret; - *uV = ret; + val &= buck_desc[buck].volt_mask; + *uV = val * buck_desc[buck].volt_step + buck_desc[buck].volt_min; return 0; } - hex = s2mps11_buck_volt2hex(buck, *uV); - if (hex < 0) - return hex; + hex = (*uV - buck_desc[buck].volt_min) / buck_desc[buck].volt_step; + if (hex > buck_desc[buck].volt_max_hex) { + pr_err("Value: %d uV is wrong for LDO%d\n", *uV, buck); + return -EINVAL; + } - val &= ~mask; + val &= ~buck_desc[buck].volt_mask; val |= hex; ret = pmic_write(dev->parent, addr, &val, 1); @@ -165,24 +204,35 @@ static int s2mps11_buck_val(struct udevice *dev, int op, int *uV) static int s2mps11_buck_mode(struct udevice *dev, int op, int *opmode) { + const struct sec_regulator_desc *buck_desc; unsigned int addr, mode; unsigned char val; - int buck, ret; + int num_bucks, buck, ret; + + switch (s2mps11_get_variant(dev)) { + case VARIANT_S2MPS11: + buck_desc = s2mps11_buck_desc; + num_bucks = ARRAY_SIZE(s2mps11_buck_desc); + break; + default: + pr_err("Unknown device type\n"); + return -EINVAL; + } buck = dev->driver_data; - if (buck < 1 || buck > S2MPS11_BUCK_NUM) { + if (buck < 1 || buck > num_bucks) { pr_err("Wrong buck number: %d\n", buck); return -EINVAL; } - addr = s2mps11_buck_ctrl[buck]; + addr = buck_desc[buck].mode_reg; ret = pmic_read(dev->parent, addr, &val, 1); if (ret) return ret; if (op == PMIC_OP_GET) { - val &= (S2MPS11_BUCK_MODE_MASK << S2MPS11_BUCK_MODE_SHIFT); + val &= buck_desc[buck].mode_mask; switch (val) { case S2MPS11_BUCK_MODE_OFF: *opmode = OP_OFF; @@ -214,7 +264,7 @@ static int s2mps11_buck_mode(struct udevice *dev, int op, int *opmode) return -EINVAL; } - val &= ~(S2MPS11_BUCK_MODE_MASK << S2MPS11_BUCK_MODE_SHIFT); + val &= ~buck_desc[buck].mode_mask; val |= mode; ret = pmic_write(dev->parent, addr, &val, 1); @@ -331,95 +381,51 @@ U_BOOT_DRIVER(s2mps11_buck) = { .probe = s2mps11_buck_probe, }; -static int s2mps11_ldo_hex2volt(int ldo, int hex) +static int s2mps11_ldo_val(struct udevice *dev, int op, int *uV) { - unsigned int uV = 0; - - if (hex > S2MPS11_LDO_VOLT_MAX_HEX) { - pr_err("Value: %#x is wrong for LDO%d", hex, ldo); - return -EINVAL; - } - - switch (ldo) { - case 1: - case 6: - case 11: - case 22: - case 23: - case 27: - case 35: - uV = hex * S2MPS11_LDO_STEP + S2MPS11_LDO_UV_MIN; - break; - default: - uV = hex * S2MPS11_LDO_STEP * 2 + S2MPS11_LDO_UV_MIN; - break; - } - - return uV; -} + const struct sec_regulator_desc *ldo_desc; + unsigned int addr; + unsigned char val; + int num_ldos, hex, ldo, ret; -static int s2mps11_ldo_volt2hex(int ldo, int uV) -{ - int hex = 0; - - switch (ldo) { - case 1: - case 6: - case 11: - case 22: - case 23: - case 27: - case 35: - hex = (uV - S2MPS11_LDO_UV_MIN) / S2MPS11_LDO_STEP; + switch (s2mps11_get_variant(dev)) { + case VARIANT_S2MPS11: + ldo_desc = s2mps11_ldo_desc; + num_ldos = ARRAY_SIZE(s2mps11_ldo_desc); break; default: - hex = (uV - S2MPS11_LDO_UV_MIN) / (S2MPS11_LDO_STEP * 2); - break; + pr_err("Unknown device type\n"); + return -EINVAL; } - if (hex >= 0 && hex <= S2MPS11_LDO_VOLT_MAX_HEX) - return hex; - - pr_err("Value: %d uV is wrong for LDO%d", uV, ldo); - return -EINVAL; - - return 0; -} - -static int s2mps11_ldo_val(struct udevice *dev, int op, int *uV) -{ - unsigned int addr; - unsigned char val; - int hex, ldo, ret; - ldo = dev->driver_data; - if (ldo < 1 || ldo > S2MPS11_LDO_NUM) { + if (ldo < 1 || ldo > num_ldos) { pr_err("Wrong ldo number: %d\n", ldo); return -EINVAL; } - addr = S2MPS11_REG_L1CTRL + ldo - 1; + addr = ldo_desc[ldo].volt_reg; + + if (op == PMIC_OP_GET) + *uV = 0; ret = pmic_read(dev->parent, addr, &val, 1); if (ret) return ret; if (op == PMIC_OP_GET) { - *uV = 0; - val &= S2MPS11_LDO_VOLT_MASK; - ret = s2mps11_ldo_hex2volt(ldo, val); - if (ret < 0) - return ret; - - *uV = ret; + val &= ldo_desc[ldo].volt_mask; + *uV = val * ldo_desc[ldo].volt_step + ldo_desc[ldo].volt_min; return 0; } - hex = s2mps11_ldo_volt2hex(ldo, *uV); - if (hex < 0) - return hex; + hex = (*uV - ldo_desc[ldo].volt_min) / ldo_desc[ldo].volt_step; + if (hex > ldo_desc[ldo].volt_max_hex) { + pr_err("Value: %d uV is wrong for LDO%d\n", *uV, ldo); + return -EINVAL; + } - val &= ~S2MPS11_LDO_VOLT_MASK; + val &= ~ldo_desc[ldo].volt_mask; val |= hex; ret = pmic_write(dev->parent, addr, &val, 1); @@ -428,23 +434,35 @@ static int s2mps11_ldo_val(struct udevice *dev, int op, int *uV) static int s2mps11_ldo_mode(struct udevice *dev, int op, int *opmode) { + const struct sec_regulator_desc *ldo_desc; unsigned int addr, mode; unsigned char val; - int ldo, ret; + int num_ldos, ldo, ret; + + switch (s2mps11_get_variant(dev)) { + case VARIANT_S2MPS11: + ldo_desc = s2mps11_ldo_desc; + num_ldos = ARRAY_SIZE(s2mps11_ldo_desc); + break; + default: + pr_err("Unknown device type\n"); + return -EINVAL; + } ldo = dev->driver_data; - if (ldo < 1 || ldo > S2MPS11_LDO_NUM) { + if (ldo < 1 || ldo > num_ldos) { pr_err("Wrong ldo number: %d\n", ldo); return -EINVAL; } - addr = S2MPS11_REG_L1CTRL + ldo - 1; + + addr = ldo_desc[ldo].mode_reg; ret = pmic_read(dev->parent, addr, &val, 1); if (ret) return ret; if (op == PMIC_OP_GET) { - val &= (S2MPS11_LDO_MODE_MASK << S2MPS11_LDO_MODE_SHIFT); + val &= ldo_desc[ldo].mode_mask; switch (val) { case S2MPS11_LDO_MODE_OFF: *opmode = OP_OFF; @@ -482,7 +500,7 @@ static int s2mps11_ldo_mode(struct udevice *dev, int op, int *opmode) return -EINVAL; } - val &= ~(S2MPS11_LDO_MODE_MASK << S2MPS11_LDO_MODE_SHIFT); + val &= ~ldo_desc[ldo].mode_mask; val |= mode; ret = pmic_write(dev->parent, addr, &val, 1); diff --git a/include/power/s2mps11.h b/include/power/s2mps11.h index c08bea5a516..dfbb5f1c165 100644 --- a/include/power/s2mps11.h +++ b/include/power/s2mps11.h @@ -106,9 +106,6 @@ enum s2mps11_reg { #define S2MPS11_LDO26_ENABLE 0xec -#define S2MPS11_LDO_NUM 26 -#define S2MPS11_BUCK_NUM 10 - /* Driver name */ #define S2MPS11_BUCK_DRIVER "s2mps11_buck" #define S2MPS11_OF_BUCK_PREFIX "BUCK" @@ -153,6 +150,20 @@ enum s2mps11_reg { #define S2MPS11_LDO_MODE_STANDBY_LPM (0x2 << 6) #define S2MPS11_LDO_MODE_ON (0x3 << 6) +struct sec_regulator_desc { + /* regulator mode control */ + unsigned int mode_reg; + unsigned int mode_mask; + + /* regulator voltage control */ + unsigned int volt_reg; + unsigned int volt_mask; + + unsigned int volt_min; + unsigned int volt_step; + unsigned int volt_max_hex; +}; + enum { OP_OFF = 0, OP_LPM, |
