dm: regulator: add max77686 regulator driver
authorPrzemyslaw Marczak <p.marczak@samsung.com>
Mon, 20 Apr 2015 18:07:47 +0000 (20:07 +0200)
committerSimon Glass <sjg@chromium.org>
Fri, 15 May 2015 00:49:38 +0000 (18:49 -0600)
This commit adds support to MAX77686 regulator driver,
based on a driver model regulator's API. It implements
almost all regulator operations, beside those for setting
and geting the Current value.
For proper bind and operation it requires the MAX77686 PMIC driver.

New file: drivers/power/regulator/max77686.c
New config: CONFIG_DM_REGULATOR_MAX77686

Signed-off-by: Przemyslaw Marczak <p.marczak@samsung.com>
Acked-by: Simon Glass <sjg@chromium.org>
doc/device-tree-bindings/regulator/max77686.txt [new file with mode: 0644]
drivers/power/Makefile
drivers/power/regulator/Kconfig
drivers/power/regulator/Makefile
drivers/power/regulator/max77686.c [new file with mode: 0644]
include/power/max77686_pmic.h
include/power/regulator.h

diff --git a/doc/device-tree-bindings/regulator/max77686.txt b/doc/device-tree-bindings/regulator/max77686.txt
new file mode 100644 (file)
index 0000000..ae9b1b6
--- /dev/null
@@ -0,0 +1,70 @@
+MAXIM, MAX77686 regulators
+
+This device uses two drivers:
+- drivers/power/pmic/max77686.c (as parent I/O device)
+- drivers/power/regulator/max77686.c (for child regulators)
+
+This file describes the binding info for the REGULATOR driver.
+
+First, please read the binding info for the pmic:
+- doc/device-tree-bindings/pmic/max77686.txt
+
+Required subnode:
+- voltage-regulators: required for the PMIC driver
+
+Required properties:
+- regulator-name: used for regulator uclass platform data '.name'
+
+Optional:
+- regulator-min-microvolt: minimum allowed Voltage to set
+- regulator-max-microvolt: minimum allowed Voltage to set
+- regulator-always-on: regulator should be never disabled
+- regulator-boot-on: regulator should be enabled by the bootloader
+
+Example:
+(subnode of max77686 pmic node)
+voltage-regulators {
+       ldo1 {
+               regulator-name = "VDD_ALIVE_1.0V";
+               regulator-min-microvolt = <1000000>;
+               regulator-max-microvolt = <1000000>;
+               regulator-always-on;
+               regulator-boot-on;
+       };
+
+       ldo2 {
+               regulator-name = "VDDQ_VM1M2_1.2V";
+               regulator-min-microvolt = <1200000>;
+               regulator-max-microvolt = <1200000>;
+               regulator-always-on;
+               regulator-boot-on;
+       };
+       .
+       .
+       .
+       ldo26 {
+               regulator-name = "nc";
+               regulator-min-microvolt = <3000000>;
+               regulator-max-microvolt = <3000000>;
+               regulator-always-on;
+               regulator-boot-on;
+       };
+
+       buck1 {
+               regulator-compatible = "BUCK1";
+               regulator-name = "VDD_MIF_1.0V";
+               regulator-min-microvolt = <8500000>;
+               regulator-max-microvolt = <1100000>;
+               regulator-always-on;
+               regulator-boot-on;
+       };
+       .
+       .
+       .
+       buck9 {
+               regulator-compatible = "BUCK9";
+               regulator-name = "nc";
+               regulator-min-microvolt = <1200000>;
+               regulator-max-microvolt = <1200000>;
+       };
+};
index 214565241ed31aa9d185d0a7579f8e2cefee41dd..a2d3c047db82d1a6283a26b916800874fdb65993 100644 (file)
@@ -15,7 +15,6 @@ obj-$(CONFIG_TPS6586X_POWER)  += tps6586x.o
 obj-$(CONFIG_TWL4030_POWER)    += twl4030.o
 obj-$(CONFIG_TWL6030_POWER)    += twl6030.o
 obj-$(CONFIG_PALMAS_POWER)     += palmas.o
-
 obj-$(CONFIG_POWER) += power_core.o
 obj-$(CONFIG_DIALOG_POWER) += power_dialog.o
 obj-$(CONFIG_POWER_FSL) += power_fsl.o
index cb1516258a297dc8d06957ee1c4af31b0f47dcc0..0cdfabc5bf345c55bc286f6f35265a28a357f4d1 100644 (file)
@@ -15,3 +15,11 @@ config DM_REGULATOR
        when binding the regulator devices. The pmic_bind_childs() can be used
        for this purpose if PMIC I/O driver is implemented or dm_scan_fdt_node()
        otherwise. Detailed informations can be found in the header file.
+
+config DM_REGULATOR_MAX77686
+       bool "Enable Driver Model for REGULATOR MAX77686"
+       depends on DM_REGULATOR && DM_PMIC_MAX77686
+       ---help---
+       This config enables implementation of driver-model regulator uclass
+       features for REGULATOR MAX77686. The driver implements get/set api for:
+       value, enable and mode.
index 27c9006689c1af6eb9e8248b9bb77fc564e57f5e..f9c4e6d9ec412769b22eb28de9f1cd0b3fa439dd 100644 (file)
@@ -6,3 +6,4 @@
 #
 
 obj-$(CONFIG_DM_REGULATOR) += regulator-uclass.o
+obj-$(CONFIG_DM_REGULATOR_MAX77686) += max77686.o
diff --git a/drivers/power/regulator/max77686.c b/drivers/power/regulator/max77686.c
new file mode 100644 (file)
index 0000000..37ebe94
--- /dev/null
@@ -0,0 +1,825 @@
+/*
+ *  Copyright (C) 2012-2015 Samsung Electronics
+ *
+ *  Rajeshwari Shinde <rajeshwari.s@samsung.com>
+ *  Przemyslaw Marczak <p.marczak@samsung.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <fdtdec.h>
+#include <errno.h>
+#include <dm.h>
+#include <i2c.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+#include <power/max77686_pmic.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define MODE(_id, _val, _name) { \
+       .id = _id, \
+       .register_value = _val, \
+       .name = _name, \
+}
+
+/* LDO: 1,3,4,5,9,17,18,19,20,21,22,23,24,26,26,27 */
+static struct dm_regulator_mode max77686_ldo_mode_standby1[] = {
+       MODE(OPMODE_OFF, MAX77686_LDO_MODE_OFF, "OFF"),
+       MODE(OPMODE_LPM, MAX77686_LDO_MODE_LPM, "LPM"),
+       MODE(OPMODE_STANDBY_LPM, MAX77686_LDO_MODE_STANDBY_LPM, "ON/LPM"),
+       MODE(OPMODE_ON, MAX77686_LDO_MODE_ON, "ON"),
+};
+
+/* LDO: 2,6,7,8,10,11,12,14,15,16 */
+static struct dm_regulator_mode max77686_ldo_mode_standby2[] = {
+       MODE(OPMODE_OFF, MAX77686_LDO_MODE_OFF, "OFF"),
+       MODE(OPMODE_STANDBY, MAX77686_LDO_MODE_STANDBY, "ON/OFF"),
+       MODE(OPMODE_STANDBY_LPM, MAX77686_LDO_MODE_STANDBY_LPM, "ON/LPM"),
+       MODE(OPMODE_ON, MAX77686_LDO_MODE_ON, "ON"),
+};
+
+/* Buck: 1 */
+static struct dm_regulator_mode max77686_buck_mode_standby[] = {
+       MODE(OPMODE_OFF, MAX77686_BUCK_MODE_OFF, "OFF"),
+       MODE(OPMODE_STANDBY, MAX77686_BUCK_MODE_STANDBY, "ON/OFF"),
+       MODE(OPMODE_ON, MAX77686_BUCK_MODE_ON, "ON"),
+};
+
+/* Buck: 2,3,4 */
+static struct dm_regulator_mode max77686_buck_mode_lpm[] = {
+       MODE(OPMODE_OFF, MAX77686_BUCK_MODE_OFF, "OFF"),
+       MODE(OPMODE_STANDBY, MAX77686_BUCK_MODE_STANDBY, "ON/OFF"),
+       MODE(OPMODE_LPM, MAX77686_BUCK_MODE_LPM, "LPM"),
+       MODE(OPMODE_ON, MAX77686_BUCK_MODE_ON, "ON"),
+};
+
+/* Buck: 5,6,7,8,9 */
+static struct dm_regulator_mode max77686_buck_mode_onoff[] = {
+       MODE(OPMODE_OFF, MAX77686_BUCK_MODE_OFF, "OFF"),
+       MODE(OPMODE_ON, MAX77686_BUCK_MODE_ON, "ON"),
+};
+
+static const char max77686_buck_addr[] = {
+       0xff, 0x10, 0x12, 0x1c, 0x26, 0x30, 0x32, 0x34, 0x36, 0x38
+};
+
+static int max77686_buck_volt2hex(int buck, int uV)
+{
+       unsigned int hex = 0;
+       unsigned int hex_max = 0;
+
+       switch (buck) {
+       case 2:
+       case 3:
+       case 4:
+               /* hex = (uV - 600000) / 12500; */
+               hex = (uV - MAX77686_BUCK_UV_LMIN) / MAX77686_BUCK_UV_LSTEP;
+               hex_max = MAX77686_BUCK234_VOLT_MAX_HEX;
+               /**
+                * Those use voltage scaller - temporary not implemented
+                * so return just 0
+                */
+               return -ENOSYS;
+       default:
+               /* hex = (uV - 750000) / 50000; */
+               hex = (uV - MAX77686_BUCK_UV_HMIN) / MAX77686_BUCK_UV_HSTEP;
+               hex_max = MAX77686_BUCK_VOLT_MAX_HEX;
+               break;
+       }
+
+       if (hex >= 0 && hex <= hex_max)
+               return hex;
+
+       error("Value: %d uV is wrong for BUCK%d", uV, buck);
+       return -EINVAL;
+}
+
+static int max77686_buck_hex2volt(int buck, int hex)
+{
+       unsigned uV = 0;
+       unsigned int hex_max = 0;
+
+       if (hex < 0)
+               goto bad_hex;
+
+       switch (buck) {
+       case 2:
+       case 3:
+       case 4:
+               hex_max = MAX77686_BUCK234_VOLT_MAX_HEX;
+               if (hex > hex_max)
+                       goto bad_hex;
+
+               /* uV = hex * 12500 + 600000; */
+               uV = hex * MAX77686_BUCK_UV_LSTEP + MAX77686_BUCK_UV_LMIN;
+               break;
+       default:
+               hex_max = MAX77686_BUCK_VOLT_MAX_HEX;
+               if (hex > hex_max)
+                       goto bad_hex;
+
+               /* uV = hex * 50000 + 750000; */
+               uV = hex * MAX77686_BUCK_UV_HSTEP + MAX77686_BUCK_UV_HMIN;
+               break;
+       }
+
+       return uV;
+
+bad_hex:
+       error("Value: %#x is wrong for BUCK%d", hex, buck);
+       return -EINVAL;
+}
+
+static int max77686_ldo_volt2hex(int ldo, int uV)
+{
+       unsigned int hex = 0;
+
+       switch (ldo) {
+       case 1:
+       case 2:
+       case 6:
+       case 7:
+       case 8:
+       case 15:
+               hex = (uV - MAX77686_LDO_UV_MIN) / MAX77686_LDO_UV_LSTEP;
+               /* hex = (uV - 800000) / 25000; */
+               break;
+       default:
+               hex = (uV - MAX77686_LDO_UV_MIN) / MAX77686_LDO_UV_HSTEP;
+               /* hex = (uV - 800000) / 50000; */
+       }
+
+       if (hex >= 0 && hex <= MAX77686_LDO_VOLT_MAX_HEX)
+               return hex;
+
+       error("Value: %d uV is wrong for LDO%d", uV, ldo);
+       return -EINVAL;
+}
+
+static int max77686_ldo_hex2volt(int ldo, int hex)
+{
+       unsigned int uV = 0;
+
+       if (hex > MAX77686_LDO_VOLT_MAX_HEX)
+               goto bad_hex;
+
+       switch (ldo) {
+       case 1:
+       case 2:
+       case 6:
+       case 7:
+       case 8:
+       case 15:
+               /* uV = hex * 25000 + 800000; */
+               uV = hex * MAX77686_LDO_UV_LSTEP + MAX77686_LDO_UV_MIN;
+               break;
+       default:
+               /* uV = hex * 50000 + 800000; */
+               uV = hex * MAX77686_LDO_UV_HSTEP + MAX77686_LDO_UV_MIN;
+       }
+
+       return uV;
+
+bad_hex:
+       error("Value: %#x is wrong for ldo%d", hex, ldo);
+       return -EINVAL;
+}
+
+static int max77686_ldo_hex2mode(int ldo, int hex)
+{
+       if (hex > MAX77686_LDO_MODE_MASK)
+               return -EINVAL;
+
+       switch (hex) {
+       case MAX77686_LDO_MODE_OFF:
+               return OPMODE_OFF;
+       case MAX77686_LDO_MODE_LPM: /* == MAX77686_LDO_MODE_STANDBY: */
+               /* The same mode values but different meaning for each ldo */
+               switch (ldo) {
+               case 2:
+               case 6:
+               case 7:
+               case 8:
+               case 10:
+               case 11:
+               case 12:
+               case 14:
+               case 15:
+               case 16:
+                       return OPMODE_STANDBY;
+               default:
+                       return OPMODE_LPM;
+               }
+       case MAX77686_LDO_MODE_STANDBY_LPM:
+               return OPMODE_STANDBY_LPM;
+       case MAX77686_LDO_MODE_ON:
+               return OPMODE_ON;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int max77686_buck_hex2mode(int buck, int hex)
+{
+       if (hex > MAX77686_BUCK_MODE_MASK)
+               return -EINVAL;
+
+       switch (hex) {
+       case MAX77686_BUCK_MODE_OFF:
+               return OPMODE_OFF;
+       case MAX77686_BUCK_MODE_ON:
+               return OPMODE_ON;
+       case MAX77686_BUCK_MODE_STANDBY:
+               switch (buck) {
+               case 1:
+               case 2:
+               case 3:
+               case 4:
+                       return OPMODE_STANDBY;
+               default:
+                       return -EINVAL;
+               }
+       case MAX77686_BUCK_MODE_LPM:
+               switch (buck) {
+               case 2:
+               case 3:
+               case 4:
+                       return OPMODE_LPM;
+               default:
+                       return -EINVAL;
+               }
+       default:
+               return -EINVAL;
+       }
+}
+
+static int max77686_buck_modes(int buck, struct dm_regulator_mode **modesp)
+{
+       int ret = -EINVAL;
+
+       if (buck < 1 || buck > MAX77686_BUCK_NUM)
+               return ret;
+
+       switch (buck) {
+       case 1:
+               *modesp = max77686_buck_mode_standby;
+               ret = ARRAY_SIZE(max77686_buck_mode_standby);
+               break;
+       case 2:
+       case 3:
+       case 4:
+               *modesp = max77686_buck_mode_lpm;
+               ret = ARRAY_SIZE(max77686_buck_mode_lpm);
+               break;
+       default:
+               *modesp = max77686_buck_mode_onoff;
+               ret = ARRAY_SIZE(max77686_buck_mode_onoff);
+       }
+
+       return ret;
+}
+
+static int max77686_ldo_modes(int ldo, struct dm_regulator_mode **modesp,
+                               struct udevice *dev)
+{
+       int ret = -EINVAL;
+
+       if (ldo < 1 || ldo > MAX77686_LDO_NUM)
+               return ret;
+
+       switch (ldo) {
+       case 2:
+       case 6:
+       case 7:
+       case 8:
+       case 10:
+       case 11:
+       case 12:
+       case 14:
+       case 15:
+       case 16:
+               *modesp = max77686_ldo_mode_standby2;
+               ret = ARRAY_SIZE(max77686_ldo_mode_standby2);
+               break;
+       default:
+               *modesp = max77686_ldo_mode_standby1;
+               ret = ARRAY_SIZE(max77686_ldo_mode_standby1);
+       }
+
+       return ret;
+}
+
+static int max77686_ldo_val(struct udevice *dev, int op, int *uV)
+{
+       unsigned int ret, hex, adr;
+       unsigned char val;
+       int ldo;
+
+       if (op == PMIC_OP_GET)
+               *uV = 0;
+
+       ldo = dev->driver_data;
+       if (ldo < 1 || ldo > MAX77686_LDO_NUM) {
+               error("Wrong ldo number: %d", ldo);
+               return -EINVAL;
+       }
+
+       adr = MAX77686_REG_PMIC_LDO1CTRL1 + ldo - 1;
+
+       ret = pmic_read(dev->parent, adr, &val, 1);
+       if (ret)
+               return ret;
+
+       if (op == PMIC_OP_GET) {
+               val &= MAX77686_LDO_VOLT_MASK;
+               ret = max77686_ldo_hex2volt(ldo, val);
+               if (ret < 0)
+                       return ret;
+               *uV = ret;
+               return 0;
+       }
+
+       hex = max77686_ldo_volt2hex(ldo, *uV);
+       if (hex < 0)
+               return hex;
+
+       val &= ~MAX77686_LDO_VOLT_MASK;
+       val |= hex;
+       ret = pmic_write(dev->parent, adr, &val, 1);
+
+       return ret;
+}
+
+static int max77686_buck_val(struct udevice *dev, int op, int *uV)
+{
+       unsigned int hex, ret, mask, adr;
+       unsigned char val;
+       int buck;
+
+       buck = dev->driver_data;
+       if (buck < 1 || buck > MAX77686_BUCK_NUM) {
+               error("Wrong buck number: %d", buck);
+               return -EINVAL;
+       }
+
+       if (op == PMIC_OP_GET)
+               *uV = 0;
+
+       /* &buck_out = ctrl + 1 */
+       adr = max77686_buck_addr[buck] + 1;
+
+       /* mask */
+       switch (buck) {
+       case 2:
+       case 3:
+       case 4:
+               /* Those use voltage scallers - will support in the future */
+               mask = MAX77686_BUCK234_VOLT_MASK;
+               return -ENOSYS;
+       default:
+               mask = MAX77686_BUCK_VOLT_MASK;
+       }
+
+       ret = pmic_read(dev->parent, adr, &val, 1);
+       if (ret)
+               return ret;
+
+       if (op == PMIC_OP_GET) {
+               val &= mask;
+               ret = max77686_buck_hex2volt(buck, val);
+               if (ret < 0)
+                       return ret;
+               *uV = ret;
+               return 0;
+       }
+
+       hex = max77686_buck_volt2hex(buck, *uV);
+       if (hex < 0)
+               return hex;
+
+       val &= ~mask;
+       val |= hex;
+       ret = pmic_write(dev->parent, adr, &val, 1);
+
+       return ret;
+}
+
+static int max77686_ldo_mode(struct udevice *dev, int op, int *opmode)
+{
+       unsigned int ret, adr, mode;
+       unsigned char val;
+       int ldo;
+
+       if (op == PMIC_OP_GET)
+               *opmode = -EINVAL;
+
+       ldo = dev->driver_data;
+       if (ldo < 1 || ldo > MAX77686_LDO_NUM) {
+               error("Wrong ldo number: %d", ldo);
+               return -EINVAL;
+       }
+
+       adr = MAX77686_REG_PMIC_LDO1CTRL1 + ldo - 1;
+
+       ret = pmic_read(dev->parent, adr, &val, 1);
+       if (ret)
+               return ret;
+
+       if (op == PMIC_OP_GET) {
+               val &= MAX77686_LDO_MODE_MASK;
+               ret = max77686_ldo_hex2mode(ldo, val);
+               if (ret < 0)
+                       return ret;
+               *opmode = ret;
+               return 0;
+       }
+
+       /* mode */
+       switch (*opmode) {
+       case OPMODE_OFF:
+               mode = MAX77686_LDO_MODE_OFF;
+               break;
+       case OPMODE_LPM:
+               switch (ldo) {
+               case 2:
+               case 6:
+               case 7:
+               case 8:
+               case 10:
+               case 11:
+               case 12:
+               case 14:
+               case 15:
+               case 16:
+                       return -EINVAL;
+               default:
+                       mode = MAX77686_LDO_MODE_LPM;
+               }
+               break;
+       case OPMODE_STANDBY:
+               switch (ldo) {
+               case 2:
+               case 6:
+               case 7:
+               case 8:
+               case 10:
+               case 11:
+               case 12:
+               case 14:
+               case 15:
+               case 16:
+                       mode = MAX77686_LDO_MODE_STANDBY;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+       case OPMODE_STANDBY_LPM:
+               mode = MAX77686_LDO_MODE_STANDBY_LPM;
+               break;
+       case OPMODE_ON:
+               mode = MAX77686_LDO_MODE_ON;
+               break;
+       default:
+               mode = 0xff;
+       }
+
+       if (mode == 0xff) {
+               error("Wrong mode: %d for ldo%d", *opmode, ldo);
+               return -EINVAL;
+       }
+
+       val &= ~MAX77686_LDO_MODE_MASK;
+       val |= mode;
+       ret = pmic_write(dev->parent, adr, &val, 1);
+
+       return ret;
+}
+
+static int max77686_ldo_enable(struct udevice *dev, int op, bool *enable)
+{
+       int ret, on_off;
+
+       if (op == PMIC_OP_GET) {
+               ret = max77686_ldo_mode(dev, op, &on_off);
+               if (ret)
+                       return ret;
+
+               switch (on_off) {
+               case OPMODE_OFF:
+                       *enable = 0;
+                       break;
+               case OPMODE_ON:
+                       *enable = 1;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+       } else if (op == PMIC_OP_SET) {
+               switch (*enable) {
+               case 0:
+                       on_off = OPMODE_OFF;
+                       break;
+               case 1:
+                       on_off = OPMODE_ON;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
+               ret = max77686_ldo_mode(dev, op, &on_off);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int max77686_buck_mode(struct udevice *dev, int op, int *opmode)
+{
+       unsigned int ret, mask, adr, mode, mode_shift;
+       unsigned char val;
+       int buck;
+
+       buck = dev->driver_data;
+       if (buck < 1 || buck > MAX77686_BUCK_NUM) {
+               error("Wrong buck number: %d", buck);
+               return -EINVAL;
+       }
+
+       adr = max77686_buck_addr[buck];
+
+       /* mask */
+       switch (buck) {
+       case 2:
+       case 3:
+       case 4:
+               mode_shift = MAX77686_BUCK_MODE_SHIFT_2;
+               break;
+       default:
+               mode_shift = MAX77686_BUCK_MODE_SHIFT_1;
+       }
+
+       mask = MAX77686_BUCK_MODE_MASK << mode_shift;
+
+       ret = pmic_read(dev->parent, adr, &val, 1);
+       if (ret)
+               return ret;
+
+       if (op == PMIC_OP_GET) {
+               val &= mask;
+               val >>= mode_shift;
+               ret = max77686_buck_hex2mode(buck, val);
+               if (ret < 0)
+                       return ret;
+               *opmode = ret;
+               return 0;
+       }
+
+       /* mode */
+       switch (*opmode) {
+       case OPMODE_OFF:
+               mode = MAX77686_BUCK_MODE_OFF;
+               break;
+       case OPMODE_STANDBY:
+               switch (buck) {
+               case 1:
+               case 2:
+               case 3:
+               case 4:
+                       mode = MAX77686_BUCK_MODE_STANDBY << mode_shift;
+                       break;
+               default:
+                       mode = 0xff;
+               }
+               break;
+       case OPMODE_LPM:
+               switch (buck) {
+               case 2:
+               case 3:
+               case 4:
+                       mode = MAX77686_BUCK_MODE_LPM << mode_shift;
+                       break;
+               default:
+                       mode = 0xff;
+               }
+               break;
+       case OPMODE_ON:
+               mode = MAX77686_BUCK_MODE_ON << mode_shift;
+               break;
+       default:
+               mode = 0xff;
+       }
+
+       if (mode == 0xff) {
+               error("Wrong mode: %d for buck: %d\n", *opmode, buck);
+               return -EINVAL;
+       }
+
+       val &= ~mask;
+       val |= mode;
+       ret = pmic_write(dev->parent, adr, &val, 1);
+
+       return ret;
+}
+
+static int max77686_buck_enable(struct udevice *dev, int op, bool *enable)
+{
+       int ret, on_off;
+
+       if (op == PMIC_OP_GET) {
+               ret = max77686_buck_mode(dev, op, &on_off);
+               if (ret)
+                       return ret;
+
+               switch (on_off) {
+               case OPMODE_OFF:
+                       *enable = false;
+                       break;
+               case OPMODE_ON:
+                       *enable = true;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+       } else if (op == PMIC_OP_SET) {
+               switch (*enable) {
+               case 0:
+                       on_off = OPMODE_OFF;
+                       break;
+               case 1:
+                       on_off = OPMODE_ON;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
+               ret = max77686_buck_mode(dev, op, &on_off);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int max77686_ldo_probe(struct udevice *dev)
+{
+       struct dm_regulator_uclass_platdata *uc_pdata;
+
+       uc_pdata = dev_get_uclass_platdata(dev);
+
+       uc_pdata->type = REGULATOR_TYPE_LDO;
+       uc_pdata->mode_count = max77686_ldo_modes(dev->driver_data,
+                                                 &uc_pdata->mode, dev);
+
+       return 0;
+}
+
+static int ldo_get_value(struct udevice *dev)
+{
+       int uV;
+       int ret;
+
+       ret = max77686_ldo_val(dev, PMIC_OP_GET, &uV);
+       if (ret)
+               return ret;
+
+       return uV;
+}
+
+static int ldo_set_value(struct udevice *dev, int uV)
+{
+       return max77686_ldo_val(dev, PMIC_OP_SET, &uV);
+}
+
+static bool ldo_get_enable(struct udevice *dev)
+{
+       bool enable = false;
+       int ret;
+
+       ret = max77686_ldo_enable(dev, PMIC_OP_GET, &enable);
+       if (ret)
+               return ret;
+
+       return enable;
+}
+
+static int ldo_set_enable(struct udevice *dev, bool enable)
+{
+       return max77686_ldo_enable(dev, PMIC_OP_SET, &enable);
+}
+
+static int ldo_get_mode(struct udevice *dev)
+{
+       int mode;
+       int ret;
+
+       ret = max77686_ldo_mode(dev, PMIC_OP_GET, &mode);
+       if (ret)
+               return ret;
+
+       return mode;
+}
+
+static int ldo_set_mode(struct udevice *dev, int mode)
+{
+       return max77686_ldo_mode(dev, PMIC_OP_SET, &mode);
+}
+
+static int max77686_buck_probe(struct udevice *dev)
+{
+       struct dm_regulator_uclass_platdata *uc_pdata;
+
+       uc_pdata = dev_get_uclass_platdata(dev);
+
+       uc_pdata->type = REGULATOR_TYPE_BUCK;
+       uc_pdata->mode_count = max77686_buck_modes(dev->driver_data,
+                                                  &uc_pdata->mode);
+
+       return 0;
+}
+
+static int buck_get_value(struct udevice *dev)
+{
+       int uV;
+       int ret;
+
+       ret = max77686_buck_val(dev, PMIC_OP_GET, &uV);
+       if (ret)
+               return ret;
+
+       return uV;
+}
+
+static int buck_set_value(struct udevice *dev, int uV)
+{
+       return max77686_buck_val(dev, PMIC_OP_SET, &uV);
+}
+
+static bool buck_get_enable(struct udevice *dev)
+{
+       bool enable = false;
+       int ret;
+
+       ret = max77686_buck_enable(dev, PMIC_OP_GET, &enable);
+       if (ret)
+               return ret;
+
+       return enable;
+}
+
+static int buck_set_enable(struct udevice *dev, bool enable)
+{
+       return max77686_buck_enable(dev, PMIC_OP_SET, &enable);
+}
+
+static int buck_get_mode(struct udevice *dev)
+{
+       int mode;
+       int ret;
+
+       ret = max77686_buck_mode(dev, PMIC_OP_GET, &mode);
+       if (ret)
+               return ret;
+
+       return mode;
+}
+
+static int buck_set_mode(struct udevice *dev, int mode)
+{
+       return max77686_buck_mode(dev, PMIC_OP_SET, &mode);
+}
+
+static const struct dm_regulator_ops max77686_ldo_ops = {
+       .get_value  = ldo_get_value,
+       .set_value  = ldo_set_value,
+       .get_enable = ldo_get_enable,
+       .set_enable = ldo_set_enable,
+       .get_mode   = ldo_get_mode,
+       .set_mode   = ldo_set_mode,
+};
+
+U_BOOT_DRIVER(max77686_ldo) = {
+       .name = MAX77686_LDO_DRIVER,
+       .id = UCLASS_REGULATOR,
+       .ops = &max77686_ldo_ops,
+       .probe = max77686_ldo_probe,
+};
+
+static const struct dm_regulator_ops max77686_buck_ops = {
+       .get_value  = buck_get_value,
+       .set_value  = buck_set_value,
+       .get_enable = buck_get_enable,
+       .set_enable = buck_set_enable,
+       .get_mode   = buck_get_mode,
+       .set_mode   = buck_set_mode,
+};
+
+U_BOOT_DRIVER(max77686_buck) = {
+       .name = MAX77686_BUCK_DRIVER,
+       .id = UCLASS_REGULATOR,
+       .ops = &max77686_buck_ops,
+       .probe = max77686_buck_probe,
+};
index 95597db503225771fdff3c3745005eb883d449d5..230035249623ea34bb12b571f8544231350e5370 100644 (file)
@@ -149,23 +149,29 @@ enum {
 
 enum {
        OPMODE_OFF = 0,
-       OPMODE_STANDBY,
        OPMODE_LPM,
+       OPMODE_STANDBY,
+       OPMODE_STANDBY_LPM,
        OPMODE_ON,
 };
 
+#ifdef CONFIG_POWER
 int max77686_set_ldo_voltage(struct pmic *p, int ldo, ulong uV);
 int max77686_set_ldo_mode(struct pmic *p, int ldo, char opmode);
 int max77686_set_buck_voltage(struct pmic *p, int buck, ulong uV);
 int max77686_set_buck_mode(struct pmic *p, int buck, char opmode);
+#endif
 
 #define MAX77686_LDO_VOLT_MAX_HEX      0x3f
 #define MAX77686_LDO_VOLT_MASK         0x3f
 #define MAX77686_LDO_MODE_MASK         0xc0
 #define MAX77686_LDO_MODE_OFF          (0x00 << 0x06)
+#define MAX77686_LDO_MODE_LPM          (0x01 << 0x06)
 #define MAX77686_LDO_MODE_STANDBY      (0x01 << 0x06)
-#define MAX77686_LDO_MODE_LPM          (0x02 << 0x06)
+#define MAX77686_LDO_MODE_STANDBY_LPM  (0x02 << 0x06)
 #define MAX77686_LDO_MODE_ON           (0x03 << 0x06)
+#define MAX77686_BUCK234_VOLT_MAX_HEX  0xff
+#define MAX77686_BUCK234_VOLT_MASK     0xff
 #define MAX77686_BUCK_VOLT_MAX_HEX     0x3f
 #define MAX77686_BUCK_VOLT_MASK                0x3f
 #define MAX77686_BUCK_MODE_MASK                0x03
@@ -176,6 +182,15 @@ int max77686_set_buck_mode(struct pmic *p, int buck, char opmode);
 #define MAX77686_BUCK_MODE_LPM         0x02
 #define MAX77686_BUCK_MODE_ON          0x03
 
+/* For regulator hex<->volt conversion */
+#define MAX77686_LDO_UV_MIN            800000 /* Minimum LDO uV value */
+#define MAX77686_LDO_UV_LSTEP          25000 /* uV lower value step */
+#define MAX77686_LDO_UV_HSTEP          50000 /* uV higher value step */
+#define MAX77686_BUCK_UV_LMIN          600000 /* Lower minimun BUCK value */
+#define MAX77686_BUCK_UV_HMIN          750000 /* Higher minimun BUCK value */
+#define MAX77686_BUCK_UV_LSTEP         12500  /* uV lower value step */
+#define MAX77686_BUCK_UV_HSTEP         50000  /* uV higher value step */
+
 /* Buck1 1 volt value */
 #define MAX77686_BUCK1OUT_1V   0x5
 /* Buck1 1.05 volt value */
index 0302c1dc6659c868929b44277634e386852445e5..6916660255d38b2ee141ae0c508b4bade222b8a0 100644 (file)
@@ -170,7 +170,7 @@ struct dm_regulator_ops {
         * @dev          - regulator device
         * Sets:
         * @uV           - set the output value [micro Volts]
-        * Returns: output value [uV] on success or negative errno if fail.
+        * @return output value [uV] on success or negative errno if fail.
         */
        int (*get_value)(struct udevice *dev);
        int (*set_value)(struct udevice *dev, int uV);
@@ -182,7 +182,7 @@ struct dm_regulator_ops {
         * @dev            - regulator device
         * Sets:
         * @uA           - set the output current [micro Amps]
-        * Returns: output value [uA] on success or negative errno if fail.
+        * @return output value [uA] on success or negative errno if fail.
         */
        int (*get_current)(struct udevice *dev);
        int (*set_current)(struct udevice *dev, int uA);
@@ -194,13 +194,13 @@ struct dm_regulator_ops {
         * @dev           - regulator device
         * Sets:
         * @enable         - set true - enable or false - disable
-        * Returns: true/false for get; or 0 / -errno for set.
+        * @return true/false for get; or 0 / -errno for set.
         */
        bool (*get_enable)(struct udevice *dev);
        int (*set_enable)(struct udevice *dev, bool enable);
 
        /**
-        * The 'get/set_mode()' function calls should operate on a driver
+        * The 'get/set_mode()' function calls should operate on a driver-
         * specific mode definitions, which should be found in:
         * field 'mode' of struct mode_desc.
         *
@@ -208,7 +208,7 @@ struct dm_regulator_ops {
         * @dev         - regulator device
         * Sets
         * @mode_id     - set output mode id (struct dm_regulator_mode->id)
-        * Returns: id/0 for get/set on success or negative errno if fail.
+        * @return id/0 for get/set on success or negative errno if fail.
         * Note:
         * The field 'id' of struct type 'dm_regulator_mode', should be always
         * positive number, since the negative is reserved for the error.
@@ -222,7 +222,7 @@ struct dm_regulator_ops {
  *
  * @dev        - pointer to the regulator device
  * @modep      - pointer to the returned mode info array
- * Returns     - count of modep entries on success or negative errno if fail.
+ * @return     - count of modep entries on success or negative errno if fail.
  */
 int regulator_mode(struct udevice *dev, struct dm_regulator_mode **modep);
 
@@ -230,7 +230,7 @@ int regulator_mode(struct udevice *dev, struct dm_regulator_mode **modep);
  * regulator_get_value: get microvoltage voltage value of a given regulator
  *
  * @dev    - pointer to the regulator device
- * Returns - positive output value [uV] on success or negative errno if fail.
+ * @return - positive output value [uV] on success or negative errno if fail.
  */
 int regulator_get_value(struct udevice *dev);
 
@@ -239,7 +239,7 @@ int regulator_get_value(struct udevice *dev);
  *
  * @dev    - pointer to the regulator device
  * @uV     - the output value to set [micro Volts]
- * Returns - 0 on success or -errno val if fails
+ * @return - 0 on success or -errno val if fails
  */
 int regulator_set_value(struct udevice *dev, int uV);
 
@@ -247,7 +247,7 @@ int regulator_set_value(struct udevice *dev, int uV);
  * regulator_get_current: get microampere value of a given regulator
  *
  * @dev    - pointer to the regulator device
- * Returns - positive output current [uA] on success or negative errno if fail.
+ * @return - positive output current [uA] on success or negative errno if fail.
  */
 int regulator_get_current(struct udevice *dev);
 
@@ -256,7 +256,7 @@ int regulator_get_current(struct udevice *dev);
  *
  * @dev    - pointer to the regulator device
  * @uA     - set the output current [micro Amps]
- * Returns - 0 on success or -errno val if fails
+ * @return - 0 on success or -errno val if fails
  */
 int regulator_set_current(struct udevice *dev, int uA);
 
@@ -264,7 +264,7 @@ int regulator_set_current(struct udevice *dev, int uA);
  * regulator_get_enable: get regulator device enable state.
  *
  * @dev    - pointer to the regulator device
- * Returns - true/false of enable state
+ * @return - true/false of enable state
  */
 bool regulator_get_enable(struct udevice *dev);
 
@@ -273,7 +273,7 @@ bool regulator_get_enable(struct udevice *dev);
  *
  * @dev    - pointer to the regulator device
  * @enable - set true or false
- * Returns - 0 on success or -errno val if fails
+ * @return - 0 on success or -errno val if fails
  */
 int regulator_set_enable(struct udevice *dev, bool enable);
 
@@ -281,7 +281,7 @@ int regulator_set_enable(struct udevice *dev, bool enable);
  * regulator_get_mode: get mode of a given device regulator
  *
  * @dev    - pointer to the regulator device
- * Returns - positive  mode number on success or -errno val if fails
+ * @return - positive  mode number on success or -errno val if fails
  * Note:
  * The regulator driver should return one of defined, mode number rather, than
  * the raw register value. The struct type 'mode_desc' provides a field 'mode'
@@ -294,7 +294,7 @@ int regulator_get_mode(struct udevice *dev);
  *
  * @dev    - pointer to the regulator device
  * @mode   - mode type (field 'mode' of struct mode_desc)
- * Returns - 0 on success or -errno value if fails
+ * @return - 0 on success or -errno value if fails
  * Note:
  * The regulator driver should take one of defined, mode number rather
  * than a raw register value. The struct type 'regulator_mode_desc' has
@@ -308,14 +308,14 @@ int regulator_set_mode(struct udevice *dev, int mode);
  * in device's uclass's platform data (struct dm_regulator_uclass_platdata):
  * - Voltage value - will set - if '.min_uV' and '.max_uV' values are equal
  * - Current limit - will set - if '.min_uA' and '.max_uA' values are equal
- * - Enable - will set - if '.always_on' or '.boot_on' are set to true
+ * - Enable - will set - if any of: '.always_on' or '.boot_on', is set to true
  *
  * The function returns on first encountered error.
  *
  * @platname - expected string for dm_regulator_uclass_platdata .name field
  * @devp      - returned pointer to the regulator device - if non-NULL passed
  * @verbose   - (true/false) print regulator setup info, or be quiet
- * Returns: 0 on success or negative value of errno.
+ * @return: 0 on success or negative value of errno.
  *
  * The returned 'regulator' device can be used with:
  * - regulator_get/set_*
@@ -340,7 +340,7 @@ int regulator_by_platname_autoset_and_enable(const char *platname,
  * @list_devp     - an array of returned pointers to the successfully setup
  *                  regulator devices if non-NULL passed
  * @verbose       - (true/false) print each regulator setup info, or be quiet
- * Returns: 0 on successfully setup of all list entries or 1 otwerwise.
+ * @return 0 on successfully setup of all list entries or 1 otwerwise.
  *
  * The returned 'regulator' devices can be used with:
  * - regulator_get/set_*
@@ -360,8 +360,8 @@ int regulator_by_platname_list_autoset_and_enable(const char *list_platname[],
  *                       Search by name, found in regulator device's name.
  *
  * @devname - expected string for 'dev->name' of regulator device
- * @devp     - returned pointer to the regulator device
- * Returns: 0 on success or negative value of errno.
+ * @devp    - returned pointer to the regulator device
+ * @return 0 on success or negative value of errno.
  *
  * The returned 'regulator' device can be used with:
  * - regulator_get/set_*
@@ -372,9 +372,9 @@ int regulator_by_devname(const char *devname, struct udevice **devp);
  * regulator_by_platname: returns the pointer to the pmic regulator device.
  *                        Search by name, found in regulator uclass platdata.
  *
- * @platname - expected string for dm_regulator_uclass_platdata .name field
+ * @platname - expected string for uc_pdata->name of regulator uclass platdata
  * @devp     - returned pointer to the regulator device
- * Returns: 0 on success or negative value of errno.
+ * @return 0 on success or negative value of errno.
  *
  * The returned 'regulator' device can be used with:
  * - regulator_get/set_*