19119820bSSimon Glass /*
29119820bSSimon Glass * Copyright (C) 2015 Google, Inc
39119820bSSimon Glass * Written by Simon Glass <sjg@chromium.org>
49119820bSSimon Glass *
59119820bSSimon Glass * Based on Rockchip's drivers/power/pmic/pmic_act8846.c:
69119820bSSimon Glass * Copyright (C) 2012 rockchips
79119820bSSimon Glass * zyw <zyw@rock-chips.com>
89119820bSSimon Glass *
99119820bSSimon Glass * SPDX-License-Identifier: GPL-2.0+
109119820bSSimon Glass */
119119820bSSimon Glass
129119820bSSimon Glass #include <common.h>
139119820bSSimon Glass #include <dm.h>
149119820bSSimon Glass #include <errno.h>
159119820bSSimon Glass #include <power/act8846_pmic.h>
169119820bSSimon Glass #include <power/pmic.h>
179119820bSSimon Glass #include <power/regulator.h>
189119820bSSimon Glass
199119820bSSimon Glass static const u16 voltage_map[] = {
209119820bSSimon Glass 600, 625, 650, 675, 700, 725, 750, 775,
219119820bSSimon Glass 800, 825, 850, 875, 900, 925, 950, 975,
229119820bSSimon Glass 1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175,
239119820bSSimon Glass 1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550,
249119820bSSimon Glass 1600, 1650, 1700, 1750, 1800, 1850, 1900, 1950,
259119820bSSimon Glass 2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350,
269119820bSSimon Glass 2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100,
279119820bSSimon Glass 3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900,
289119820bSSimon Glass };
299119820bSSimon Glass
309119820bSSimon Glass enum {
319119820bSSimon Glass REG_SYS0,
329119820bSSimon Glass REG_SYS1,
339119820bSSimon Glass REG1_VOL = 0x10,
349119820bSSimon Glass REG1_CTL = 0X11,
359119820bSSimon Glass REG2_VOL0 = 0x20,
369119820bSSimon Glass REG2_VOL1,
379119820bSSimon Glass REG2_CTL,
389119820bSSimon Glass REG3_VOL0 = 0x30,
399119820bSSimon Glass REG3_VOL1,
409119820bSSimon Glass REG3_CTL,
419119820bSSimon Glass REG4_VOL0 = 0x40,
429119820bSSimon Glass REG4_VOL1,
439119820bSSimon Glass REG4_CTL,
449119820bSSimon Glass REG5_VOL = 0x50,
459119820bSSimon Glass REG5_CTL,
469119820bSSimon Glass REG6_VOL = 0X58,
479119820bSSimon Glass REG6_CTL,
489119820bSSimon Glass REG7_VOL = 0x60,
499119820bSSimon Glass REG7_CTL,
509119820bSSimon Glass REG8_VOL = 0x68,
519119820bSSimon Glass REG8_CTL,
529119820bSSimon Glass REG9_VOL = 0x70,
539119820bSSimon Glass REG9_CTL,
549119820bSSimon Glass REG10_VOL = 0x80,
559119820bSSimon Glass REG10_CTL,
569119820bSSimon Glass REG11_VOL = 0x90,
579119820bSSimon Glass REG11_CTL,
589119820bSSimon Glass REG12_VOL = 0xa0,
599119820bSSimon Glass REG12_CTL,
609119820bSSimon Glass REG13 = 0xb1,
619119820bSSimon Glass };
629119820bSSimon Glass
639119820bSSimon Glass static const u8 addr_vol[] = {
649119820bSSimon Glass 0, REG1_VOL, REG2_VOL0, REG3_VOL0, REG4_VOL0,
659119820bSSimon Glass REG5_VOL, REG6_VOL, REG7_VOL, REG8_VOL, REG9_VOL,
669119820bSSimon Glass REG10_VOL, REG11_VOL, REG12_VOL,
679119820bSSimon Glass };
689119820bSSimon Glass
699119820bSSimon Glass static const u8 addr_ctl[] = {
709119820bSSimon Glass 0, REG1_CTL, REG2_CTL, REG3_CTL, REG4_CTL,
719119820bSSimon Glass REG5_CTL, REG6_CTL, REG7_CTL, REG8_CTL, REG9_CTL,
729119820bSSimon Glass REG10_CTL, REG11_CTL, REG12_CTL,
739119820bSSimon Glass };
749119820bSSimon Glass
check_volt_table(const u16 * volt_table,int uvolt)759119820bSSimon Glass static int check_volt_table(const u16 *volt_table, int uvolt)
769119820bSSimon Glass {
779119820bSSimon Glass int i;
789119820bSSimon Glass
799119820bSSimon Glass for (i = VOL_MIN_IDX; i < VOL_MAX_IDX; i++) {
809119820bSSimon Glass if (uvolt <= (volt_table[i] * 1000))
819119820bSSimon Glass return i;
829119820bSSimon Glass }
839119820bSSimon Glass return -EINVAL;
849119820bSSimon Glass }
859119820bSSimon Glass
reg_get_value(struct udevice * dev)869119820bSSimon Glass static int reg_get_value(struct udevice *dev)
879119820bSSimon Glass {
889119820bSSimon Glass int reg = dev->driver_data;
899119820bSSimon Glass int ret;
909119820bSSimon Glass
9165f89be2SJohn Keeping ret = pmic_reg_read(dev->parent, addr_vol[reg]);
929119820bSSimon Glass if (ret < 0)
939119820bSSimon Glass return ret;
949119820bSSimon Glass
959119820bSSimon Glass return voltage_map[ret & LDO_VOL_MASK] * 1000;
969119820bSSimon Glass }
979119820bSSimon Glass
reg_set_value(struct udevice * dev,int uvolt)989119820bSSimon Glass static int reg_set_value(struct udevice *dev, int uvolt)
999119820bSSimon Glass {
1009119820bSSimon Glass int reg = dev->driver_data;
1019119820bSSimon Glass int val;
1029119820bSSimon Glass
1039119820bSSimon Glass val = check_volt_table(voltage_map, uvolt);
1049119820bSSimon Glass if (val < 0)
1059119820bSSimon Glass return val;
1069119820bSSimon Glass
1079119820bSSimon Glass return pmic_clrsetbits(dev->parent, addr_vol[reg], LDO_VOL_MASK, val);
1089119820bSSimon Glass }
1099119820bSSimon Glass
reg_set_enable(struct udevice * dev,bool enable)1109119820bSSimon Glass static int reg_set_enable(struct udevice *dev, bool enable)
1119119820bSSimon Glass {
1129119820bSSimon Glass int reg = dev->driver_data;
1139119820bSSimon Glass
1149119820bSSimon Glass return pmic_clrsetbits(dev->parent, addr_ctl[reg], LDO_EN_MASK,
1159119820bSSimon Glass enable ? LDO_EN_MASK : 0);
1169119820bSSimon Glass }
1179119820bSSimon Glass
reg_get_enable(struct udevice * dev)118*85f87de3SKeerthy static int reg_get_enable(struct udevice *dev)
1199119820bSSimon Glass {
1209119820bSSimon Glass int reg = dev->driver_data;
1219119820bSSimon Glass int ret;
1229119820bSSimon Glass
12365f89be2SJohn Keeping ret = pmic_reg_read(dev->parent, addr_ctl[reg]);
1249119820bSSimon Glass if (ret < 0)
1259119820bSSimon Glass return ret;
1269119820bSSimon Glass
1279119820bSSimon Glass return ret & LDO_EN_MASK ? true : false;
1289119820bSSimon Glass }
1299119820bSSimon Glass
act8846_reg_probe(struct udevice * dev)1309119820bSSimon Glass static int act8846_reg_probe(struct udevice *dev)
1319119820bSSimon Glass {
1329119820bSSimon Glass struct dm_regulator_uclass_platdata *uc_pdata;
1339119820bSSimon Glass int reg = dev->driver_data;
1349119820bSSimon Glass
1359119820bSSimon Glass uc_pdata = dev_get_uclass_platdata(dev);
1369119820bSSimon Glass
1379119820bSSimon Glass uc_pdata->type = reg <= 4 ? REGULATOR_TYPE_BUCK : REGULATOR_TYPE_LDO;
1389119820bSSimon Glass uc_pdata->mode_count = 0;
1399119820bSSimon Glass
1409119820bSSimon Glass return 0;
1419119820bSSimon Glass }
1429119820bSSimon Glass
1439119820bSSimon Glass static const struct dm_regulator_ops act8846_reg_ops = {
1449119820bSSimon Glass .get_value = reg_get_value,
1459119820bSSimon Glass .set_value = reg_set_value,
1469119820bSSimon Glass .get_enable = reg_get_enable,
1479119820bSSimon Glass .set_enable = reg_set_enable,
1489119820bSSimon Glass };
1499119820bSSimon Glass
1509119820bSSimon Glass U_BOOT_DRIVER(act8846_buck) = {
1519119820bSSimon Glass .name = "act8846_reg",
1529119820bSSimon Glass .id = UCLASS_REGULATOR,
1539119820bSSimon Glass .ops = &act8846_reg_ops,
1549119820bSSimon Glass .probe = act8846_reg_probe,
1559119820bSSimon Glass };
156