Skip to contentSkip to conversation

Power(full) framework based on Driver Model

RFC PATCH New Przemyslaw Marczak 6 participants 218 messages Oct 8, 2014 – Apr 24, 2015 Page 3 of 3

Subsystems (4)
lore
Share & tools
lore
#134 lore raw

PATCH v3 13/17 doc: driver-model: pmic and regulator uclass documentation

In reply to Simon Glass

Hello Simon,

Quoted 411 lines · Simon Glass

Hi Przemyslaw,

Quoted 81 lines · Przemyslaw Marczak

---
Changes v2, V3:
- update documentation with the framework api changes
- remove doc file name 'dm' prefix

---
  doc/driver-model/pmic-framework.txt | 350 ++++++++++++++++++++++++++++++++++++
  1 file changed, 350 insertions(+)

create mode 100644 doc/driver-model/pmic-framework.txt

doc/driver-model/pmic-framework.txt new file +65 -0
new file mode 100644
index 0000000..72651dc
@@ -0,0 +1,350 @@
+#
+# (C) Copyright 2014-2015 Samsung Electronics
+# Przemyslaw Marczak <[email protected]>
+#
+# SPDX-License-Identifier:      GPL-2.0+
+#
+
+PMIC framework based on Driver Model
+====================================
+TOC:
+1. Introduction
+2. How does it work
+3. Pmic driver api
+4. Pmic driver
+5. Pmic command
+6. Regulator driver api
+7. Regulator driver
+8. Regulator command
+
+1. Introduction
+===============
+This is an introduction to driver-model multi uclass PMIC devices support.
+At present it is based on two uclass types:
+
+- UCLASS_PMIC      - basic uclass type for PMIC I/O, which provides common
+                     read/write interface.
+- UCLASS_REGULATOR - additional uclass type for specific PMIC features, which
+                     are various voltage regulators.
+
+New files:
+UCLASS_PMIC:
+- drivers/power/pmic-uclass.c
+- include/power/pmic.h
+UCLASS_REGULATOR:
+- drivers/power/regulator-uclass.c
+- include/power/regulator.h
+
+Commands:
+- lib/cmd_pmic.c
+- lib/cmd_regulator.c
+
+2. How doees it work
+====================
+The Power Management Integrated Circuits (PMIC) are used in embedded systems
+to provide stable, precise and specific voltage power source with over-voltage
+and thermal protection circuits.
+
+The single PMIC can provide various functionalities with single or multiple
+interfaces, like in the example below.
+
+-- SoC
+ |
+ |            ______________________________________
+ | BUS 0     |       Multi interface PMIC IC        |--> LDO out 1
+ | e.g.I2C0  |                                      |--> LDO out N
+ |-----------|---- PMIC device 0 (READ/WRITE ops)   |
+ | or SPI0   |    |_ REGULATOR device (ldo/... ops) |--> BUCK out 1
+ |           |    |_ CHARGER device (charger ops)   |--> BUCK out M
+ |           |    |_ MUIC device (microUSB con ops) |
+ | BUS 1     |    |_ ...                            |---> BATTERY
+ | e.g.I2C1  |                                      |
+ |-----------|---- PMIC device 1 (READ/WRITE ops)   |---> USB in 1
+ . or SPI1   |    |_ RTC device (rtc ops)           |---> USB in 2
+ .           |______________________________________|---> USB out
+ .

doc/driver-model/pmic-framework.txt line 75

Quoted 10 lines
doc/driver-model/pmic-framework.txt new file +10 -0
+
+Since U-Boot provides driver model features for I2C and SPI bus drivers,
+the PMIC devices should also support this. With the new basic uclass types
+for PMIC I/O and regulator features, PMIC drivers can simply provide common
+features, with multiple interface and instance support.
+
+Basic design assumptions:
+
+- Common I/O api - UCLASS_PMIC
+The main assumption is to use UCLASS_PMIC device to provide I/O interface,

an I/O interface

doc/driver-model/pmic-framework.txt line 77

Quoted 2 lines
doc/driver-model/pmic-framework.txt new file +2 -0
+for devices other uclass types. It is no matter what is the type of device
+physical I/O interface.

devices of other uclass types. It doesn't matter what type of physical I/O interface is used.

Usually PMIC devices are using SPI or I2C interface,

s/are using/use/

doc/driver-model/pmic-framework.txt line 82

Quoted 5 lines
doc/driver-model/pmic-framework.txt new file +5 -0
+but use of any other interface (e.g. when PMIC is not directly connected
+to the SoC) - is now possible. Drivers can use the same read/write api.
+
+- Common regulator api - UCLASS_REGULATOR
+For setting the attributes of verious types of regulators with common api,

various

with a common

doc/driver-model/pmic-framework.txt line 83

Quoted 1 line
doc/driver-model/pmic-framework.txt new file +1 -0
+this uclass can be implemented. This allows to drive the each regulator output

allows driving each regulator's output

doc/driver-model/pmic-framework.txt line 84

Quoted 1 line
doc/driver-model/pmic-framework.txt new file +1 -0
+value, on/off state and custom defined operation modes. It also provides the

custom-defined

or perhaps just 'particular'

doc/driver-model/pmic-framework.txt line 86

Quoted 2 lines
doc/driver-model/pmic-framework.txt new file +2 -0
+user interface for all operations.
+For the very simple implementation, the regulator drivers are not required,

For simple implementations, regulator drivers are not required, so the code can use pmic read/write directly.

Quoted 100 lines
doc/driver-model/pmic-framework.txt new file +100 -0
+so the code could base on pmic read/write only.
+
+When board device-tree file includes pmic subnode and the U_Boot compatible
+driver exists, then the pmic device bind should looks like this:
+
+|_ root - will bind the device for I2C/SPI bus node
+  |_ i2c/spi - should bind a device for pmic node
+    |_ pmic (parent) - should bind child devices for its features
+      |_ regulator (child)
+      |_ charger   (child)
+      |_ other     (child)
+
+Usually PMIC design provides:
+ - single I/O interface (single UCLASS_PMIC driver)
+   Then UCLASS_PMIC device should be a parent of all pmic devices, where each
+   is usually different uclass type, but need to access the same interface
+
+ - multiple I/O interfaces (UCLASS_PMIC driver for each)
+   For each interface the UCLASS_PMIC device should be a parent of only those
+   devices (different uclass types), which needs to access the specified
+   interface.
+
+3. Pmic driver api
+===================
+To use the pmic API, config: CONFIG_DM_PMIC is required.
+The new driver API is very simple and is based on 'struct dm_pmic_ops',
+which define two basic operations: device read and write.
+
+The platform data is introduced as 'struct pmic_platdata', to keep an info
+about the device interface.
+
+The api is described in file: 'include/power/pmic.h'
+Getting the device:
+- by name  -  int pmic_get(char *name, struct udevice **pmic);
+
+Device I/O interface
+Can be used with UCLASS_PMIC devices:
+- Read from the device 'len' bytes at 'reg' into the buffer:
+  int pmic_read(struct udevice *dev, uint reg, uint8_t *buffer, int len);
+
+- Write to the device 'len' bytes at 'reg' from the buffer:
+  int pmic_write(struct udevice *dev, uint reg, uint8_t *buffer, int len);
+
+4. Pmic driver
+============================
+As an example of the pmic driver, please take a look into the MAX77686 driver
+'drivers/power/pmic/max77686.c' and the description in 'include/power/pmic.h'
+
+The pmic driver can be defined by U_BOOT_DRIVER() macro:
+
+U_BOOT_DRIVER(pmic_max77686) = {
+       .name = "max77686 pmic",
+       .id = UCLASS_PMIC,
+       .of_match = max77686_ids,     - Allows to bind by compatible
+       .bind = max77686_bind,        - Function called at device bind
+       .ops = &max77686_ops,         - Pmic api function calls
+       .platdata_auto_alloc_size = sizeof(struct pmic_platdata),
+};
+
+To bind the pmic device, field '.of_match' is required with proper compatible.
+
+Driver ops:
+.reg_count = MAX77686_NUM_OF_REGS - number of pmic registers
+.read = max77686_read() - allows to use pmic_read()
+.write = max77686_write() - allows to use pmic_write()
+
+Driver bind:
+- max77686_bind(): called on bind and calls pmic_child_node_scan() to bind the
+  childs which are int "voltage-regulators" subnode. The bind is done using
+  "voltage-regulators" property name.
+
+5. Pmic command
+===============
+To use the pmic command, config: CONFIG_DM_PMIC_CMD is required.
+The new pmic command allows to:
+- list pmic devices
+- choose the current device (like the mmc command)
+- read or write the pmic register
+- dump all pmic registers
+
+This command can use only UCLASS_PMIC devices, since this uclass is designed
+for pmic I/O operations only.
+
+Command options (pmic [option]):
+- list                     - list available PMICs
+- dev <id>                 - set id to current pmic device
+- pmic dump                - dump registers
+- pmic read <reg>          - read register
+- pmic write <reg> <value> - write register
+
+Example of usage:
+# pmic list           - chose one dev Id, e.g. 3
+# pmic dev 0          - set dev seq 0 as current device
+# pmic dump           - dump the registers of the current pmic dev
+# pmic read 0x0       - read the register at address 0x0
+# pmic write 0x0 0x1  - write 0x1 to the register at addres 0x0
+
+6. Regulator driver API
+===================================
+To use the regulator API, config: CONFIG_DM_REGULATOR is required.

doc/driver-model/pmic-framework.txt line 196

Quoted 10 lines
doc/driver-model/pmic-framework.txt new file +10 -0
+The api is described in file: 'include/power/regulator.h'
+The api is based on structure types:
+- 'dm_regulator_info' - dev->uc_priv (auto-allocated)
+- 'dm_regulator_mode' - included in regualtor info
+
+Regulator info keeps the constraints taken from the device-tree and also device
+modes set by the driver (single or array).
+
+The fixed-regulator common driver keeps provides private structure type, to keep
+its gpio attributes. The structure type 'fixed_regulator_priv' is keept in field

kept

Quoted 137 lines
doc/driver-model/pmic-framework.txt new file +137 -0
+'dev->priv' and is allocated by the driver.
+
+6.1 Regulator device-tree node:
+The regulator node should looks like in the example:
+ldo1 {
+        regulator-compatible = "LDO1"; (not used here, but required for bind)
+        regulator-name = "VDD_MMC_1.8V"; (mandatory) *
+        regulator-min-microvolt = <1000000>; (mandatory) *
+        regulator-max-microvolt = <1000000>; (mandatory) *
+        regulator-min-microamp = <1000>; (optional) *
+        regulator-max-microamp = <1000>; (optional) *
+        regulator-always-on; (optional) *
+        regulator-boot-on; (optional) *
+};
+
+For the fixed-voltage regulator, voltage min and max must be equal:
+VDD_MMC: regulator at 0 {
+        compatible = "regulator-fixed";
+        regulator-name = "VDD_MMC"; (mandatory) *
+        regulator-min-microvolt = <2800000>; (mandatory) *
+        regulator-max-microvolt = <2800000>; (mandatory) *
+        regulator-always-on; (optional)
+        regulator-boot-on; (optional)
+        gpio = <&gpc 1 GPIO_ACTIVE_HIGH>; (optional)
+        gpio-open-drain; (optional)
+        enable-active-high; (optional)
+        startup-delay-us
+};
+
+The attributes signed with '*' can be taken by the common function which is
+regulator_ofdata_to_platdata(). The rest attributes for fixed-regulator, are
+taken by the driver.
+
+6.2 Getting the device:
+- by name - int regulator_get(char *name, struct udevice **regulator);
+
+6.3 Device I/O interface
+According to the framework assumptions, where uclass pmic device is a parent
+of pmic devices other uclass types, the regulator devices should use uclass
+pmic interface, with the parent as the device, like this:
+- pmic_read(regulator->parent, some_reg, &some_buff, count);
+- pmic_write(regulator->parent, some_reg, &some_buff, count);
+
+6.4 Device regulator operations
+The regulator function calls are based on few data types:
+- enum regulator_type {...} - standard types: LDO, BUCK, DVS, FIXED
+- struct dm_regulator_info {...} - output name and value limits
+- struct dm_regulator_mode {...} - output operation mode value and name
+- struct dm_regulator_ops {...} - regulator driver function calls
+
+The first argument is always device. And the device uclass id must be always:
+- 'UCLASS_REGULATOR'
+
+Function details are described in regulator header. The basic features are:
+- regulator_info()            - get the regulator info structure
+- regulator_mode()            - get the regulator mode info structure
+- regulator_get/set_value()   - get/set the regulator output voltage
+- regulator_get/set_current() - get/set the regulator output current
+- regulator_get/set_enable()  - get/set the regulator output enable state
+- regulator_get/set_mode()    - get/set the regulator output operation mode
+
+7. Regulator driver
+======================================
+As an example of the regulator driver, please take a look into the MAX77686
+regulator driver (drivers/power/regulator/max77686.c). It implements two drivers
+for the buck and ldo regulators. The buck driver structure:
+
+U_BOOT_DRIVER(max77686_buck) = {
+        .name = "max77686 buck",
+        .id = UCLASS_REGULATOR,
+        .ops = &max77686_buck_ops,
+        .of_match = max77686_buck_ids,
+        .ofdata_to_platdata = max77686_buck_ofdata_to_platdata,
+};
+
+The device-tree buck compatibles:
+static const struct udevice_id max77686_buck_ids[] = {
+        { .compatible = "BUCK1", .data = 1 },
+        { .compatible = "BUCK2", .data = 2 },
+        ...
+        { }, (need always put null at the end)
+};
+
+For each compatible, the data is set as a number of buck. This allows to get
+the device number without parsing the compatible.
+
+The buck driver '.ofdata_to_platdata' call implementation:
+static int max77686_buck_ofdata_to_platdata(struct udevice *dev)
+{
+        struct dm_regulator_info *info = dev->uclass_priv;
+        int ret;
+
+       /* Get the regulation constraints by the common function */
+        ret = regulator_ofdata_to_platdata(dev);
+        if (ret)
+                return ret;
+
+        info->type = REGULATOR_TYPE_BUCK;
+        /**
+         * The device mode array is filled by internal driver function with
+         * the proper name for each mode id.
+         */
+        info->mode_count = max77686_buck_modes(dev2num(dev), &info->mode);
+
+        return 0;
+}
+
+And the call to regulator_ofdata_to_platdata() is responsible for filling the
+regulator output constraints, which are keepts in device-tree regulator nodes,
+e.g. 'arch/arm/dts/exynos4412-odroid.dts'
+
+For the I/O, this driver uses pmic_read/write calls, with the parent device
+as the first argument, e.g.: pmic_read(dev->parent, adr, &val, 1);
+
+8. Regulator command
+====================
+To use the pmic command, config: CONFIG_DM_REGULATOR_CMD is required.
+
+This command is based on driver model regulator api.
+User interface features:
+- list                   - list UCLASS regulator devices
+- regulator dev [id]     - show or [set] operating regulator device
+- regulator [info]       - print constraints info
+- regulator [status]     - print operating status
+- regulator [value] [-f] - print/[set] voltage value [uV] (force)
+- regulator [current]    - print/[set] current value [uA]
+- regulator [mode_id]    - print/[set] operating mode id
+- regulator [enable]     - enable the regulator output
+- regulator [disable]    - disable the regulator output
+
+If pmic device driver provides support to this another pmic uclass, then this
+command provides useful user interface. It was designed to allow safe I/O access
+to the pmic device, without the pmic documentation. If driver provide regulator
+output - value and mode info - then user can operate on it.
+
+Example of usage:
+regulator list              - look after regulator 'seq' number

doc/driver-model/pmic-framework.txt line 343

Quoted 10 lines
doc/driver-model/pmic-framework.txt new file +10 -0
+regulator dev 'seq'         - set current device
+regulator status            - show device status
+regulator info              - list device available regulation constraints
+regulator value             - prints device voltage value
+regulator value 1000000     - set device voltage value to 1000000 uV
+regulator value 1200000 -f  - if value exceeds limits - set force
+regulator mode              - print device operation mode id
+regulator mode 5            - set devices operation mode to '5' (mode id)
+
+The -f option (forcibly) or mode - only if descriptor is available

I think something like this would be clearer:

The -f option (forcibly) and 'mode' sub-command are only available if the regulator descriptor is available

doc/driver-model/pmic-framework.txt line 350

Quoted 7 lines
doc/driver-model/pmic-framework.txt new file +7 -0
+
+Note:
+The regulator descriptor, 'min' and 'max' limits prevents setting unsafe value.
+But sometimes it is useful to change the regulator value for some test - so the
+force option (-f) is available. This option is not available for change the mode
+since this depends on a pmic device design, but the required voltage value can
+change, e.g. if some hardware uses pins header.

changed.

Quoted 3 lines

What does "e..g. if some hardware uses pins header" mean? Can you reword that to be clearer?

Right, this was unclear.
I meant the hardware connected by I/O expansion header, which can be replaced by other. And each could be supplied by a different voltage value.

Quoted 7 lines
Quoted 3 lines

--
1.9.1

Regards,
Simon

I didn't clean this file too much, last time. Will fix in next version. Thanks for help!

Signature · 4 lines
Przemyslaw Marczak
Samsung R&D Institute Poland
Samsung Electronics
p.marczak at samsung.com
#135 lore raw

PATCH v3 14/17 dm: board:samsung: power_init_board: add requirement of CONFIG_DM_PMIC

In reply to Przemyslaw Marczak

In the power_init_board function call, regulator driver init is called, so before compile, make sure that any power framework is defined.

---
 board/samsung/common/board.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
board/samsung/common/board.c +2 -2
index 2e17da8..c4cbb63 100644
@@ -21,9 +21,9 @@
 #include <asm/arch/pinmux.h>
 #include <asm/arch/power.h>
 #include <asm/arch/system.h>
-#include <power/pmic.h>
 #include <asm/arch/sromc.h>
 #include <lcd.h>
+#include <i2c.h>
 #include <samsung/misc.h>
 
 DECLARE_GLOBAL_DATA_PTR;
@@ -168,7 +168,7 @@ int board_early_init_f(void)
 }
 #endif
 
-#if defined(CONFIG_POWER)
+#if defined(CONFIG_POWER) || defined(CONFIG_DM_PMIC)
 int power_init_board(void)
 {
 	set_ps_hold_ctrl();
Signature · 1 line
1.9.1
#136 lore raw

PATCH v3 14/17 dm: board:samsung: power_init_board: add requirement of CONFIG_DM_PMIC

Quoted 7 lines · Przemyslaw Marczak

In the power_init_board function call, regulator driver init is called, so before compile, make sure that any power framework is defined.

---
 board/samsung/common/board.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
Quoted 28 lines
board/samsung/common/board.c +2 -3
index 2e17da8..c4cbb63 100644
@@ -21,9 +21,9 @@
 #include <asm/arch/pinmux.h>
 #include <asm/arch/power.h>
 #include <asm/arch/system.h>
-#include <power/pmic.h>
 #include <asm/arch/sromc.h>
 #include <lcd.h>
+#include <i2c.h>
 #include <samsung/misc.h>
 
 DECLARE_GLOBAL_DATA_PTR;
@@ -168,7 +168,7 @@ int board_early_init_f(void)
 }
 #endif
 
-#if defined(CONFIG_POWER)
+#if defined(CONFIG_POWER) || defined(CONFIG_DM_PMIC)
 int power_init_board(void)
 {
        set_ps_hold_ctrl();
--

1.9.1

#137 lore raw

PATCH v3 15/17 odroid: board: add support to dm pmic api

In reply to Przemyslaw Marczak

This commit change the old pmic framework calls with the new ones.

---
Changes v2:
- remove board_init_i2c() call
- update regulator calls
- update headers
- samsung/misc.c: include required header

Changes v3:
- adjust regulator calls to new api

---
 board/samsung/common/misc.c   |   1 +
 board/samsung/odroid/odroid.c | 113 +++++++++++++++++++++++++++++++++---------
 2 files changed, 91 insertions(+), 23 deletions(-)
board/samsung/common/misc.c +1 -0
index 1a77c82..f0d69d4 100644
@@ -16,6 +16,7 @@
 #include <asm/arch/cpu.h>
 #include <asm/gpio.h>
 #include <linux/input.h>
+#include <dm.h>
 #include <power/pmic.h>
 #include <mmc.h>
 
board/samsung/odroid/odroid.c +90 -23

159 lines not on this page · raw message

Signature · 1 line
1.9.1
#138 lore raw

PATCH v3 15/17 odroid: board: add support to dm pmic api

Hi Przemyslaw,

Quoted 60 lines · Przemyslaw Marczak

This commit change the old pmic framework calls with the new ones.

---
Changes v2:
- remove board_init_i2c() call
- update regulator calls
- update headers
- samsung/misc.c: include required header

Changes v3:
- adjust regulator calls to new api

---
 board/samsung/common/misc.c   |   1 +
 board/samsung/odroid/odroid.c | 113 +++++++++++++++++++++++++++++++++---------
 2 files changed, 91 insertions(+), 23 deletions(-)
board/samsung/common/misc.c +1 -0
index 1a77c82..f0d69d4 100644
@@ -16,6 +16,7 @@
 #include <asm/arch/cpu.h>
 #include <asm/gpio.h>
 #include <linux/input.h>
+#include <dm.h>
 #include <power/pmic.h>
 #include <mmc.h>
 
board/samsung/odroid/odroid.c +11 -3
index ae41c29..aa3b0ff 100644
@@ -12,7 +12,9 @@
 #include <asm/arch/gpio.h>
 #include <asm/gpio.h>
 #include <asm/arch/cpu.h>
+#include <dm.h>
 #include <power/pmic.h>
+#include <power/regulator.h>
 #include <power/max77686_pmic.h>
 #include <errno.h>
 #include <mmc.h>
@@ -405,15 +407,62 @@ static void board_gpio_init(void)
 
 static int pmic_init_max77686(void)
 {
-       struct pmic *p = pmic_get("MAX77686_PMIC");
+       struct udevice *dev;
+       int ret;
 
-       if (pmic_probe(p))
-               return -ENODEV;
+       ret = regulator_get("VDDQ_EMMC_1.8V", &dev);
+       if (ret) {
+               error("Regulator get error: %d", ret);
+               return ret;
+       }
+
+       ret = regulator_set_value(dev, 1800000);

board/samsung/odroid/odroid.c static void board_gpio_init(void) · line 429

Quoted 10 lines
board/samsung/odroid/odroid.c +10 -0
+       if (ret) {
+               error("Regulator %s value setting error: %d", dev->name, ret);
+               return ret;
+       }
+
+       ret = regulator_set_enable(dev, true);
+       if (ret) {
+               error("Regulator %s enable error: %d", dev->name, ret);
+               return ret;
+       }

How about adding a function that finds a regulator, sets its voltage and enables it? Then you can avoid duplicating the same code 3 times.

Quoted 129 lines
board/samsung/odroid/odroid.c +69 -21
+
+       ret = regulator_get("TFLASH_2.8V", &dev);
+       if (ret) {
+               error("Regulator get error: %d", ret);
+               return ret;
+       }
+
+       ret = regulator_set_value(dev, 2800000);
+       if (ret) {
+               error("Regulator %s value setting error: %d", dev->name, ret);
+               return ret;
+       }
+
+       ret = regulator_set_enable(dev, true);
+       if (ret) {
+               error("Regulator %s enable error: %d", dev->name, ret);
+               return ret;
+       }
+
+       ret = regulator_get("VDDQ_EMMC_2.8V", &dev);
+       if (ret) {
+               error("Regulator get error: %d", ret);
+               return ret;
+       }
 
-       /* Set LDO Voltage */
-       max77686_set_ldo_voltage(p, 20, 1800000);       /* LDO20 eMMC */
-       max77686_set_ldo_voltage(p, 21, 2800000);       /* LDO21 SD */
-       max77686_set_ldo_voltage(p, 22, 2800000);       /* LDO22 eMMC */
+       ret = regulator_set_value(dev, 2800000);
+       if (ret) {
+               error("Regulator %s value setting error: %d", dev->name, ret);
+               return ret;
+       }
+
+       ret = regulator_set_enable(dev, true);
+       if (ret) {
+               error("Regulator %s enable error: %d", dev->name, ret);
+               return ret;
+       }
 
        return 0;
 }
@@ -434,7 +483,6 @@ int exynos_init(void)
 
 int exynos_power_init(void)
 {
-       pmic_init(0);
        pmic_init_max77686();
 
        return 0;
@@ -443,19 +491,20 @@ int exynos_power_init(void)
 #ifdef CONFIG_USB_GADGET
 static int s5pc210_phy_control(int on)
 {
-       struct pmic *p_pmic;
-
-       p_pmic = pmic_get("MAX77686_PMIC");
-       if (!p_pmic)
-               return -ENODEV;
+       struct udevice *dev;
+       int ret;
 
-       if (pmic_probe(p_pmic))
-               return -1;
+       ret = regulator_get("VDD_UOTG_3.0V", &dev);
+       if (ret) {
+               error("Regulator get error: %d", ret);
+               return ret;
+       }
 
        if (on)
-               return max77686_set_ldo_mode(p_pmic, 12, OPMODE_ON);
+               return regulator_set_mode(dev, OPMODE_ON);
        else
-               return max77686_set_ldo_mode(p_pmic, 12, OPMODE_LPM);
+               return regulator_set_mode(dev, OPMODE_LPM);
+
 }
 
 struct s3c_plat_otg_data s5pc210_otg_data = {
@@ -472,7 +521,8 @@ struct s3c_plat_otg_data s5pc210_otg_data = {
 int board_usb_init(int index, enum usb_init_type init)
 {
 #ifdef CONFIG_CMD_USB
-       struct pmic *p_pmic;
+       struct udevice *dev;
+       int ret;
 
        /* Set Ref freq 0 => 24MHz, 1 => 26MHz*/
        /* Odroid Us have it at 24MHz, Odroid Xs at 26MHz */
@@ -490,14 +540,31 @@ int board_usb_init(int index, enum usb_init_type init)
        /* Power off and on BUCK8 for LAN9730 */
        debug("LAN9730 - Turning power buck 8 OFF and ON.\n");
 
-       p_pmic = pmic_get("MAX77686_PMIC");
-       if (p_pmic && !pmic_probe(p_pmic)) {
-               max77686_set_buck_voltage(p_pmic, 8, 750000);
-               max77686_set_buck_voltage(p_pmic, 8, 3300000);
+       ret = regulator_get("VCC_P3V3_2.85V", &dev);
+       if (ret) {
+               error("Regulator get error: %d", ret);
+               return ret;
        }
 
-#endif
+       ret = regulator_set_enable(dev, true);
+       if (ret) {
+               error("Regulator %s enable setting error: %d", dev->name, ret);
+               return ret;
+       }
+
+       ret = regulator_set_value(dev, 750000);
+       if (ret) {
+               error("Regulator %s value setting error: %d", dev->name, ret);
+               return ret;
+       }
 
+       ret = regulator_set_value(dev, 3300000);
+       if (ret) {
+               error("Regulator %s value setting error: %d", dev->name, ret);
+               return ret;
+       }
+
+#endif
        debug("USB_udc_probe\n");
        return s3c_udc_probe(&s5pc210_otg_data);
 }
--
Quoted 2 lines

1.9.1

Regards,
Simon

#139 lore raw

PATCH v3 15/17 odroid: board: add support to dm pmic api

Hello Simon,

Quoted 68 lines · Simon Glass

Hi Przemyslaw,

Quoted 65 lines · Przemyslaw Marczak

This commit change the old pmic framework calls with the new ones.

---
Changes v2:
- remove board_init_i2c() call
- update regulator calls
- update headers
- samsung/misc.c: include required header

Changes v3:
- adjust regulator calls to new api

---
  board/samsung/common/misc.c   |   1 +
  board/samsung/odroid/odroid.c | 113 +++++++++++++++++++++++++++++++++---------
  2 files changed, 91 insertions(+), 23 deletions(-)
board/samsung/common/misc.c +1 -0
index 1a77c82..f0d69d4 100644
@@ -16,6 +16,7 @@
  #include <asm/arch/cpu.h>
  #include <asm/gpio.h>
  #include <linux/input.h>
+#include <dm.h>
  #include <power/pmic.h>
  #include <mmc.h>
 
board/samsung/odroid/odroid.c +16 -3
index ae41c29..aa3b0ff 100644
@@ -12,7 +12,9 @@
  #include <asm/arch/gpio.h>
  #include <asm/gpio.h>
  #include <asm/arch/cpu.h>
+#include <dm.h>
  #include <power/pmic.h>
+#include <power/regulator.h>
  #include <power/max77686_pmic.h>
  #include <errno.h>
  #include <mmc.h>
@@ -405,15 +407,62 @@ static void board_gpio_init(void)
 
  static int pmic_init_max77686(void)
  {
-       struct pmic *p = pmic_get("MAX77686_PMIC");
+       struct udevice *dev;
+       int ret;
 
-       if (pmic_probe(p))
-               return -ENODEV;
+       ret = regulator_get("VDDQ_EMMC_1.8V", &dev);
+       if (ret) {
+               error("Regulator get error: %d", ret);
+               return ret;
+       }
+
+       ret = regulator_set_value(dev, 1800000);
+       if (ret) {
+               error("Regulator %s value setting error: %d", dev->name, ret);
+               return ret;
+       }
+
Quoted 9 lines

board/samsung/odroid/odroid.c static void board_gpio_init(void) · line 429

Quoted 5 lines
board/samsung/odroid/odroid.c +5 -0
+       ret = regulator_set_enable(dev, true);
+       if (ret) {
+               error("Regulator %s enable error: %d", dev->name, ret);
+               return ret;
+       }

How about adding a function that finds a regulator, sets its voltage and enables it? Then you can avoid duplicating the same code 3 times.

Yes, will add something like this.

Quoted 118 lines
Quoted 118 lines
board/samsung/odroid/odroid.c +62 -20
+
+       ret = regulator_get("TFLASH_2.8V", &dev);
+       if (ret) {
+               error("Regulator get error: %d", ret);
+               return ret;
+       }
+
+       ret = regulator_set_value(dev, 2800000);
+       if (ret) {
+               error("Regulator %s value setting error: %d", dev->name, ret);
+               return ret;
+       }
+
+       ret = regulator_set_enable(dev, true);
+       if (ret) {
+               error("Regulator %s enable error: %d", dev->name, ret);
+               return ret;
+       }
+
+       ret = regulator_get("VDDQ_EMMC_2.8V", &dev);
+       if (ret) {
+               error("Regulator get error: %d", ret);
+               return ret;
+       }
 
-       /* Set LDO Voltage */
-       max77686_set_ldo_voltage(p, 20, 1800000);       /* LDO20 eMMC */
-       max77686_set_ldo_voltage(p, 21, 2800000);       /* LDO21 SD */
-       max77686_set_ldo_voltage(p, 22, 2800000);       /* LDO22 eMMC */
+       ret = regulator_set_value(dev, 2800000);
+       if (ret) {
+               error("Regulator %s value setting error: %d", dev->name, ret);
+               return ret;
+       }
+
+       ret = regulator_set_enable(dev, true);
+       if (ret) {
+               error("Regulator %s enable error: %d", dev->name, ret);
+               return ret;
+       }
 
         return 0;
  }
@@ -434,7 +483,6 @@ int exynos_init(void)
 
  int exynos_power_init(void)
  {
-       pmic_init(0);
         pmic_init_max77686();
 
         return 0;
@@ -443,19 +491,20 @@ int exynos_power_init(void)
  #ifdef CONFIG_USB_GADGET
  static int s5pc210_phy_control(int on)
  {
-       struct pmic *p_pmic;
-
-       p_pmic = pmic_get("MAX77686_PMIC");
-       if (!p_pmic)
-               return -ENODEV;
+       struct udevice *dev;
+       int ret;
 
-       if (pmic_probe(p_pmic))
-               return -1;
+       ret = regulator_get("VDD_UOTG_3.0V", &dev);
+       if (ret) {
+               error("Regulator get error: %d", ret);
+               return ret;
+       }
 
         if (on)
-               return max77686_set_ldo_mode(p_pmic, 12, OPMODE_ON);
+               return regulator_set_mode(dev, OPMODE_ON);
         else
-               return max77686_set_ldo_mode(p_pmic, 12, OPMODE_LPM);
+               return regulator_set_mode(dev, OPMODE_LPM);
+
  }
 
  struct s3c_plat_otg_data s5pc210_otg_data = {
@@ -472,7 +521,8 @@ struct s3c_plat_otg_data s5pc210_otg_data = {
  int board_usb_init(int index, enum usb_init_type init)
  {
  #ifdef CONFIG_CMD_USB
-       struct pmic *p_pmic;
+       struct udevice *dev;
+       int ret;
 
         /* Set Ref freq 0 => 24MHz, 1 => 26MHz*/
         /* Odroid Us have it at 24MHz, Odroid Xs at 26MHz */
@@ -490,14 +540,31 @@ int board_usb_init(int index, enum usb_init_type init)
         /* Power off and on BUCK8 for LAN9730 */
         debug("LAN9730 - Turning power buck 8 OFF and ON.\n");
 
-       p_pmic = pmic_get("MAX77686_PMIC");
-       if (p_pmic && !pmic_probe(p_pmic)) {
-               max77686_set_buck_voltage(p_pmic, 8, 750000);
-               max77686_set_buck_voltage(p_pmic, 8, 3300000);
+       ret = regulator_get("VCC_P3V3_2.85V", &dev);
+       if (ret) {
+               error("Regulator get error: %d", ret);
+               return ret;
         }
 
-#endif
+       ret = regulator_set_enable(dev, true);
+       if (ret) {
+               error("Regulator %s enable setting error: %d", dev->name, ret);
+               return ret;
+       }
+
+       ret = regulator_set_value(dev, 750000);
+       if (ret) {
+               error("Regulator %s value setting error: %d", dev->name, ret);
+               return ret;
+       }
 
Quoted 17 lines
Quoted 11 lines
board/samsung/odroid/odroid.c +7 -1
+       ret = regulator_set_value(dev, 3300000);
+       if (ret) {
+               error("Regulator %s value setting error: %d", dev->name, ret);
+               return ret;
+       }
+
+#endif
         debug("USB_udc_probe\n");
         return s3c_udc_probe(&s5pc210_otg_data);
  }
--
Quoted 2 lines

1.9.1

Regards,
Simon

Thanks,

Signature · 4 lines
Przemyslaw Marczak
Samsung R&D Institute Poland
Samsung Electronics
p.marczak at samsung.com
#140 lore raw

PATCH v3 16/17 odroid: dts: add 'voltage-regulators' description to max77686 node

In reply to Przemyslaw Marczak

Adding regulators subnode to fdt max77686 node, allows properly init regulators by the max77686 regulator driver. This enables the complete functionality of the regulator command.

---
Changes V2:
- odroid: dts: remove pmic alias

Changes V3:
- none

---
 arch/arm/dts/exynos4412-odroid.dts | 247 +++++++++++++++++++++++++++++++++++++
 1 file changed, 247 insertions(+)
arch/arm/dts/exynos4412-odroid.dts +247 -0
index 5507d9a..bc516a0 100644
@@ -40,6 +40,253 @@
 			interrupts = <7 0>;
 			reg = <0x09 0 0>;
 			#clock-cells = <1>;
+
+			voltage-regulators {
+				ldo1_reg: ldo1 {
+					regulator-compatible = "LDO1";
+					regulator-name = "VDD_ALIVE_1.0V";
+					regulator-min-microvolt = <1000000>;
+					regulator-max-microvolt = <1000000>;
+				};
+
+				ldo2_reg: ldo2 {
+					regulator-compatible = "LDO2";
+					regulator-name = "VDDQ_VM1M2_1.2V";
+					regulator-min-microvolt = <1200000>;
+					regulator-max-microvolt = <1200000>;
+				};
+
+				ldo3_reg: ldo3 {
+					regulator-compatible = "LDO3";
+					regulator-name = "VCC_1.8V_AP";
+					regulator-min-microvolt = <1800000>;
+					regulator-max-microvolt = <1800000>;
+				};
+
+				ldo4_reg: ldo4 {
+					regulator-compatible = "LDO4";
+					regulator-name = "VDDQ_MMC2_2.8V";
+					regulator-min-microvolt = <2800000>;
+					regulator-max-microvolt = <2800000>;
+				};
+
+				ldo5_reg: ldo5 {
+					regulator-compatible = "LDO5";
+					regulator-name = "VDDQ_MMC0/1/3_1.8V";
+					regulator-min-microvolt = <1800000>;
+					regulator-max-microvolt = <1800000>;
+				};
+
+				ldo6_reg: ldo6 {
+					regulator-compatible = "LDO6";
+					regulator-name = "VMPLL_1.0V";
+					regulator-min-microvolt = <1100000>;
+					regulator-max-microvolt = <1100000>;
+				};
+
+				ldo7_reg: ldo7 {
+					regulator-compatible = "LDO7";
+					regulator-name = "VPLL_1.1V";
+					regulator-min-microvolt = <1100000>;
+					regulator-max-microvolt = <1100000>;
+				};
+
+				ldo8_reg: ldo8 {
+					regulator-compatible = "LDO8";
+					regulator-name = "VDD_MIPI/HDMI_1.0V";
+					regulator-min-microvolt = <1000000>;
+					regulator-max-microvolt = <1000000>;
+				};
+
+				ldo9_reg: ldo9 {
+					regulator-compatible = "LDO9";
+					regulator-name = "nc";
+					regulator-min-microvolt = <1800000>;
+					regulator-max-microvolt = <1800000>;
+				};
+
+				ldo10_reg: ldo10 {
+					regulator-compatible = "LDO10";
+					regulator-name = "VDD_MIPI/HDMI_1.8V";
+					regulator-min-microvolt = <1800000>;
+					regulator-max-microvolt = <1800000>;
+				};
+
+				ldo11_reg: ldo11 {
+					regulator-compatible = "LDO11";
+					regulator-name = "VDD_ABB1_1.8V";
+					regulator-min-microvolt = <1800000>;
+					regulator-max-microvolt = <1800000>;
+				};
+
+				ldo12_reg: ldo12 {
+					regulator-compatible = "LDO12";
+					regulator-name = "VDD_UOTG_3.0V";
+					regulator-min-microvolt = <3000000>;
+					regulator-max-microvolt = <3000000>;
+				};
+
+				ldo13_reg: ldo13 {
+					regulator-compatible = "LDO13";
+					regulator-name = "VDD_C2C_1.8V";
+					regulator-min-microvolt = <1800000>;
+					regulator-max-microvolt = <1800000>;
+				};
+
+				ldo14_reg: ldo14 {
+					regulator-compatible = "LDO14";
+					regulator-name = "VDD_ABB02_1.8V";
+					regulator-min-microvolt = <1800000>;
+					regulator-max-microvolt = <1800000>;
+				};
+
+				ldo15_reg: ldo15 {
+					regulator-compatible = "LDO15";
+					regulator-name = "VDD_HSIC/OTG_1.0V";
+					regulator-min-microvolt = <1000000>;
+					regulator-max-microvolt = <1000000>;
+				};
+
+				ldo16_reg: ldo16 {
+					regulator-compatible = "LDO16";
+					regulator-name = "VDD_HSIC_1.8V";
+					regulator-min-microvolt = <1800000>;
+					regulator-max-microvolt = <1800000>;
+				};
+
+				ldo17_reg: ldo17 {
+					regulator-compatible = "LDO17";
+					regulator-name = "VDDQ_CAM_1.2V";
+					regulator-min-microvolt = <1200000>;
+					regulator-max-microvolt = <1200000>;
+				};
+
+				ldo18_reg: ldo18 {
+					regulator-compatible = "LDO18";
+					regulator-name = "nc";
+					regulator-min-microvolt = <1800000>;
+					regulator-max-microvolt = <1800000>;
+				};
+
+				ldo19_reg: ldo19 {
+					regulator-compatible = "LDO19";
+					regulator-name = "nc";
+					regulator-min-microvolt = <1800000>;
+					regulator-max-microvolt = <1800000>;
+				};
+
+				ldo20_reg: ldo20 {
+					regulator-compatible = "LDO20";
+					regulator-name = "VDDQ_EMMC_1.8V";
+					regulator-min-microvolt = <1800000>;
+					regulator-max-microvolt = <1800000>;
+				};
+
+				ldo21_reg: ldo21 {
+					regulator-compatible = "LDO21";
+					regulator-name = "TFLASH_2.8V";
+					regulator-min-microvolt = <2800000>;
+					regulator-max-microvolt = <2800000>;
+				};
+
+				ldo22_reg: ldo22 {
+					regulator-compatible = "LDO22";
+					regulator-name = "VDDQ_EMMC_2.8V";
+					regulator-min-microvolt = <2800000>;
+					regulator-max-microvolt = <2800000>;
+				};
+
+				ldo23_reg: ldo23 {
+					regulator-compatible = "LDO23";
+					regulator-name = "nc";
+					regulator-min-microvolt = <3300000>;
+					regulator-max-microvolt = <3300000>;
+				};
+
+				ldo24_reg: ldo24 {
+					regulator-compatible = "LDO24";
+					regulator-name = "nc";
+					regulator-min-microvolt = <3000000>;
+					regulator-max-microvolt = <3000000>;
+				};
+
+				ldo25_reg: ldo25 {
+					regulator-compatible = "LDO25";
+					regulator-name = "VDDQ_LCD_3.0V";
+					regulator-min-microvolt = <3000000>;
+					regulator-max-microvolt = <3000000>;
+				};
+
+				ldo26_reg: ldo26 {
+					regulator-compatible = "LDO26";
+					regulator-name = "nc";
+					regulator-min-microvolt = <3000000>;
+					regulator-max-microvolt = <3000000>;
+				};
+
+				buck1_reg: buck1 {
+					regulator-compatible = "BUCK1";
+					regulator-name = "VDD_MIF_1.0V";
+					regulator-min-microvolt = <8500000>;
+					regulator-max-microvolt = <1100000>;
+				};
+
+				buck2_reg: buck2 {
+					regulator-compatible = "BUCK2";
+					regulator-name = "VDD_ARM_1.0V";
+					regulator-min-microvolt = <850000>;
+					regulator-max-microvolt = <1500000>;
+				};
+
+				buck3_reg: buck3 {
+					regulator-compatible = "BUCK3";
+					regulator-name = "VDD_INT_1.1V";
+					regulator-min-microvolt = <850000>;
+					regulator-max-microvolt = <1150000>;
+				};
+
+				buck4_reg: buck4 {
+					regulator-compatible = "BUCK4";
+					regulator-name = "VDD_G3D_1.0V";
+					regulator-min-microvolt = <850000>;
+					regulator-max-microvolt = <1150000>;
+				};
+
+				buck5_reg: buck5 {
+					regulator-compatible = "BUCK5";
+					regulator-name = "VDDQ_AP_1.2V";
+					regulator-min-microvolt = <1200000>;
+					regulator-max-microvolt = <1200000>;
+				};
+
+				buck6_reg: buck6 {
+					regulator-compatible = "BUCK6";
+					regulator-name = "VCC_INL1/7_1.35V";
+					regulator-min-microvolt = <1350000>;
+					regulator-max-microvolt = <1350000>;
+				};
+
+				buck7_reg: buck7 {
+					regulator-compatible = "BUCK7";
+					regulator-name = "VCC_INL2/3/5_2.0V";
+					regulator-min-microvolt = <2000000>;
+					regulator-max-microvolt = <2000000>;
+				};
+
+				buck8_reg: buck8 {
+					regulator-compatible = "BUCK8";
+					regulator-name = "VCC_P3V3_2.85V";
+					regulator-min-microvolt = <2850000>;
+					regulator-max-microvolt = <3300000>;
+				};
+
+				buck9_reg: buck9 {
+					regulator-compatible = "BUCK9";
+					regulator-name = "nc";
+					regulator-min-microvolt = <1200000>;
+					regulator-max-microvolt = <1200000>;
+				};
+			};
 		};
 	};
 
Signature · 1 line
1.9.1
#141 lore raw

PATCH v3 16/17 odroid: dts: add 'voltage-regulators' description to max77686 node

Quoted 9 lines · Przemyslaw Marczak

Adding regulators subnode to fdt max77686 node, allows properly init regulators by the max77686 regulator driver. This enables the complete functionality of the regulator command.

---
Changes V2:
- odroid: dts: remove pmic alias

Quoted 5 lines

Changes V3:
- none

---
 arch/arm/dts/exynos4412-odroid.dts | 247 +++++++++++++++++++++++++++++++++++++
 1 file changed, 247 insertions(+)
#142 lore raw

PATCH v3 17/17 odroid: config: enable dm pmic, dm regulator and max77686 driver

In reply to Przemyslaw Marczak

This change enables the configs required to init and setup max77686 regulator driver, using the new driver model pmic and regulator API.

This commits enables:
- CONFIG_ERRNO_STR
- CONFIG_DM_PMIC
- CONFIG_DM_PMIC_CMD
- CONFIG_DM_PMIC_MAX77686
- CONFIG_DM_REGULATOR
- CONFIG_DM_REGULATOR_CMD
- CONFIG_DM_REGULATOR_MAX77686

And removes the unused:
- CONFIG_DM_I2C_COMPAT
- CONFIG_POWER
- CONFIG_POWER_I2C
- CONFIG_POWER_MAX77686

---
Changes V2:
- config: enable dm i2c; cleanup
- remove CONFIG_DM_I2C_COMPAT
- enable regulator command

Changes V3:
- move options to defconfig

---
 configs/odroid_defconfig | 8 +++++++-
 include/configs/odroid.h | 5 -----
 2 files changed, 7 insertions(+), 6 deletions(-)
configs/odroid_defconfig +7 -1
index d32b5b5..1e29abe 100644
@@ -4,5 +4,11 @@ CONFIG_TARGET_ODROID=y
 CONFIG_OF_CONTROL=y
 CONFIG_DEFAULT_DEVICE_TREE="exynos4412-odroid"
 CONFIG_DM_I2C=y
-CONFIG_DM_I2C_COMPAT=y
 # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+CONFIG_ERRNO_STR=y
+CONFIG_DM_PMIC=y
+CONFIG_DM_PMIC_CMD=y
+CONFIG_DM_PMIC_MAX77686=y
+CONFIG_DM_REGULATOR=y
+CONFIG_DM_REGULATOR_CMD=y
+CONFIG_DM_REGULATOR_MAX77686=y
include/configs/odroid.h +0 -5
index 5ee0abe..3874baa 100644
@@ -182,11 +182,6 @@
 #define CONFIG_SYS_I2C_S3C24X0_SPEED	100000
 #define CONFIG_SYS_I2C_S3C24X0_SLAVE	0
 
-/* POWER */
-#define CONFIG_POWER
-#define CONFIG_POWER_I2C
-#define CONFIG_POWER_MAX77686
-
 /* GPT */
 #define CONFIG_RANDOM_UUID
 
Signature · 1 line
1.9.1
#143 lore raw

PATCH v3 17/17 odroid: config: enable dm pmic, dm regulator and max77686 driver

Quoted 12 lines · Przemyslaw Marczak

This change enables the configs required to init and setup max77686 regulator driver, using the new driver model pmic and regulator API.

This commits enables:
- CONFIG_ERRNO_STR
- CONFIG_DM_PMIC
- CONFIG_DM_PMIC_CMD
- CONFIG_DM_PMIC_MAX77686
- CONFIG_DM_REGULATOR
- CONFIG_DM_REGULATOR_CMD
- CONFIG_DM_REGULATOR_MAX77686

Quoted 7 lines

And removes the unused:
- CONFIG_DM_I2C_COMPAT
- CONFIG_POWER
- CONFIG_POWER_I2C
- CONFIG_POWER_MAX77686

(but pelase rename the commands so that they are CONFIG_CMD_DM_PCI and CONFIG_CMD_DM_REGULATOR)

Quoted 49 lines

---
Changes V2:
- config: enable dm i2c; cleanup
- remove CONFIG_DM_I2C_COMPAT
- enable regulator command

Changes V3:
- move options to defconfig

---
 configs/odroid_defconfig | 8 +++++++-
 include/configs/odroid.h | 5 -----
 2 files changed, 7 insertions(+), 6 deletions(-)
configs/odroid_defconfig +7 -1
index d32b5b5..1e29abe 100644
@@ -4,5 +4,11 @@ CONFIG_TARGET_ODROID=y
 CONFIG_OF_CONTROL=y
 CONFIG_DEFAULT_DEVICE_TREE="exynos4412-odroid"
 CONFIG_DM_I2C=y
-CONFIG_DM_I2C_COMPAT=y
 # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+CONFIG_ERRNO_STR=y
+CONFIG_DM_PMIC=y
+CONFIG_DM_PMIC_CMD=y
+CONFIG_DM_PMIC_MAX77686=y
+CONFIG_DM_REGULATOR=y
+CONFIG_DM_REGULATOR_CMD=y
+CONFIG_DM_REGULATOR_MAX77686=y
include/configs/odroid.h +0 -6
index 5ee0abe..3874baa 100644
@@ -182,11 +182,6 @@
 #define CONFIG_SYS_I2C_S3C24X0_SPEED   100000
 #define CONFIG_SYS_I2C_S3C24X0_SLAVE   0
 
-/* POWER */
-#define CONFIG_POWER
-#define CONFIG_POWER_I2C
-#define CONFIG_POWER_MAX77686
-
 /* GPT */
 #define CONFIG_RANDOM_UUID
 
--

1.9.1

#144 lore raw

PATCH v3 17/17 odroid: config: enable dm pmic, dm regulator and max77686 driver

Hello Simon,

Quoted 19 lines · Simon Glass
Quoted 18 lines · Przemyslaw Marczak

This change enables the configs required to init and setup max77686 regulator driver, using the new driver model pmic and regulator API.

This commits enables:
- CONFIG_ERRNO_STR
- CONFIG_DM_PMIC
- CONFIG_DM_PMIC_CMD
- CONFIG_DM_PMIC_MAX77686
- CONFIG_DM_REGULATOR
- CONFIG_DM_REGULATOR_CMD
- CONFIG_DM_REGULATOR_MAX77686

And removes the unused:
- CONFIG_DM_I2C_COMPAT
- CONFIG_POWER
- CONFIG_POWER_I2C
- CONFIG_POWER_MAX77686

Quoted 7 lines
Quoted 1 line

(but pelase rename the commands so that they are CONFIG_CMD_DM_PCI and CONFIG_CMD_DM_REGULATOR)

Yes, will do this.

Quoted 46 lines
Quoted 46 lines

---
Changes V2:
- config: enable dm i2c; cleanup
- remove CONFIG_DM_I2C_COMPAT
- enable regulator command

Changes V3:
- move options to defconfig

---
  configs/odroid_defconfig | 8 +++++++-
  include/configs/odroid.h | 5 -----
  2 files changed, 7 insertions(+), 6 deletions(-)
configs/odroid_defconfig +7 -1
index d32b5b5..1e29abe 100644
@@ -4,5 +4,11 @@ CONFIG_TARGET_ODROID=y
  CONFIG_OF_CONTROL=y
  CONFIG_DEFAULT_DEVICE_TREE="exynos4412-odroid"
  CONFIG_DM_I2C=y
-CONFIG_DM_I2C_COMPAT=y
  # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+CONFIG_ERRNO_STR=y
+CONFIG_DM_PMIC=y
+CONFIG_DM_PMIC_CMD=y
+CONFIG_DM_PMIC_MAX77686=y
+CONFIG_DM_REGULATOR=y
+CONFIG_DM_REGULATOR_CMD=y
+CONFIG_DM_REGULATOR_MAX77686=y
include/configs/odroid.h +0 -5
index 5ee0abe..3874baa 100644
@@ -182,11 +182,6 @@
  #define CONFIG_SYS_I2C_S3C24X0_SPEED   100000
  #define CONFIG_SYS_I2C_S3C24X0_SLAVE   0
 
-/* POWER */
-#define CONFIG_POWER
-#define CONFIG_POWER_I2C
-#define CONFIG_POWER_MAX77686
-
  /* GPT */
  #define CONFIG_RANDOM_UUID
 
Quoted 4 lines
Quoted 3 lines

--
1.9.1

Thanks,

Signature · 4 lines
Przemyslaw Marczak
Samsung R&D Institute Poland
Samsung Electronics
p.marczak at samsung.com
#145 lore raw

v3 cover Power(full) framework based on Driver Model

In reply to Przemyslaw Marczak

Hello,

Quoted 65 lines · Przemyslaw Marczak

Hello,
Here is the third RFC version of the new PMIC framework.Big thanks to Simon Glass, your comments were really helpful, and I think, that this version is much more better to discuss, than the previous. The changes made in this version are described below each commit. Sorry that I didn't reply to each patch, I agreed with most and just started the work.

Best regards

Przemyslaw Marczak (17):
exynos5: fix build break by adding CONFIG_POWER
fdt_ro.c: add new function: fdt_node_check_prop_compatible()
dm: core: lists.c: add new function lists_bind_fdt_by_prop()
lib: Kconfig: add entry for errno_str() function
dm: pmic: add implementation of driver model pmic uclass
dm: regulator: add implementation of driver model regulator uclass
dm: pmic: add pmic command
dm: regulator: add regulator command
pmic: max77686 set the same compatible as in the kernel
dm: pmic: add max77686 pmic driver
dm: regulator: add max77686 regulator driver
dm: regulator: add fixed voltage regulator driver
doc: driver-model: pmic and regulator uclass documentation
dm: board:samsung: power_init_board: add requirement of CONFIG_DM_PMIC
odroid: board: add support to dm pmic api
odroid: dts: add 'voltage-regulators' description to max77686 node
odroid: config: enable dm pmic, dm regulator and max77686 driver

  Makefile                             |   1 +
  arch/arm/dts/exynos4412-odroid.dts   | 249 +++++++++-
  arch/arm/dts/exynos4412-trats2.dts   |   2 +-
  arch/arm/dts/exynos5250-smdk5250.dts |   2 +-
  arch/arm/dts/exynos5250-snow.dts     |   2 +-
  board/samsung/common/board.c         |   4 +-
  board/samsung/common/misc.c          |   1 +
  board/samsung/odroid/odroid.c        | 113 ++++-
  common/Kconfig                       |  36 ++
  common/Makefile                      |   4 +
  common/cmd_pmic.c                    | 210 +++++++++
  common/cmd_regulator.c               | 385 +++++++++++++++
  configs/odroid_defconfig             |   8 +-
  doc/driver-model/pmic-framework.txt  | 350 ++++++++++++++
  drivers/core/lists.c                 |  28 +-
  drivers/power/Kconfig                | 124 ++++-
  drivers/power/Makefile               |   3 +-
  drivers/power/pmic-uclass.c          | 130 ++++++
  drivers/power/pmic/Makefile          |   1 +
  drivers/power/pmic/max77686.c        |  76 +++
  drivers/power/pmic/pmic_max77686.c   |   2 +-
  drivers/power/regulator-uclass.c     | 219 +++++++++
  drivers/power/regulator/Makefile     |   9 +
  drivers/power/regulator/fixed.c      | 124 +++++
  drivers/power/regulator/max77686.c   | 876 +++++++++++++++++++++++++++++++++++
  include/configs/exynos5-common.h     |   4 +
  include/configs/odroid.h             |   5 -
  include/dm/lists.h                   |  18 +
  include/dm/uclass-id.h               |   4 +
  include/libfdt.h                     |  27 ++
  include/power/max77686_pmic.h        |  26 +-
  include/power/pmic.h                 | 210 +++++++++
  include/power/regulator.h            | 259 +++++++++++
  lib/Kconfig                          |   8 +
  lib/fdtdec.c                         |   2 +-
  lib/libfdt/fdt_ro.c                  |  14 +-
  36 files changed, 3481 insertions(+), 55 deletions(-)
Quoted 11 lines

create mode 100644 common/cmd_pmic.c
create mode 100644 common/cmd_regulator.c create mode 100644 doc/driver-model/pmic-framework.txt create mode 100644 drivers/power/pmic-uclass.c create mode 100644 drivers/power/pmic/max77686.c create mode 100644 drivers/power/regulator-uclass.c create mode 100644 drivers/power/regulator/Makefile create mode 100644 drivers/power/regulator/fixed.c create mode 100644 drivers/power/regulator/max77686.c create mode 100644 include/power/regulator.h

This patchset is available at:
https://github.com/bobenstein/u-boot
branch: dm-pmic-v3

Best regards,

Signature · 4 lines
Przemyslaw Marczak
Samsung R&D Institute Poland
Samsung Electronics
p.marczak at samsung.com
#146 lore raw

v3 cover Power(full) framework based on Driver Model

In reply to Przemyslaw Marczak

Hi Przemyslaw,

Quoted 6 lines · Przemyslaw Marczak

Hello,
Here is the third RFC version of the new PMIC framework.Big thanks to Simon Glass, your comments were really helpful, and I think, that this version is much more better to discuss, than the previous. The changes made in this version are described below each commit. Sorry that I didn't reply to each patch, I agreed with most and just started the work.

This is looking really good. Here are a few overall comments.

1. There is one oddity that I'd like to address before merging.

I don't think the fdt_node_check_prop_compatible() is a good idea, nor necessary. I don't think we should consider the regulator-compatible property to be a compatible string. It has values like LDO8, LDO9 and these don't look like compatible strings, which are normally unique and point to a driver. Here they point to a particular device.

A similar problem is faced in pinctrl and if you look at gpio_exynos_bind() you will see that it works through the sub-nodes, creating devices as needed.

I don't think using udevice_id is right here either.

Here is my suggestion:

a. Create a new structure like this:

struct pmic_child_info {
const char *prefix; // "LDO" or "BUCK"
const char *driver_name; // "max77686_ldo" or "max77686_buck"
};

b. Pass a list of these to pmic_child_node_scan(). In your case there will be three entries, one for LDO, one for BUCK, plus a NULL termination entry,

c. It can work through the subnodes looking for the given prefixes. It then calls device_bind_driver() on each. Then it changes the returned device's of_data to hold the correct value (obtained with strtol() on the part of the name that follows the prefix - e.g. 17 for "LDO17"). This will be easier if you rebase on u-boot-dm/usb-working, where the data is just a long, not a device tree pointer.

d. Now you have the same effect as before, but you can drop the tables like max77686_ldo_ids[] and avoid misappropriating driver model's device lookup.

2. Should we put the regulator stuff in drivers/regulator, as with Linux?

3. Can you please bring in the regulator and pmic device tree binding files, plus max77686?

4. We really do need tests! I suspect that you could create a sandbox I2C pmic that has a few registers and regulators. See i2c_eeprom_emul.c for a basic example. Then you can write some tests that find the pmi,c find the regulator, read and write a few registers, and read and write a few regulators. That would be enough test coverage to get us started. I know this is different from previous U-Boot policy, but tests are a big win during development and also for years to come (as people can change the framework and have some confidence that they did not break anything).

It can be a follow-on patch separate from your series but I'm really not keen on bringing in a major new driver model framework with no tests. If you are struggling for time, let me know and I can try to help by writing a sandbox I2C PMIC for example.

Regards,
Simon

Quoted 73 lines

Best regards

Przemyslaw Marczak (17):
exynos5: fix build break by adding CONFIG_POWER
fdt_ro.c: add new function: fdt_node_check_prop_compatible()
dm: core: lists.c: add new function lists_bind_fdt_by_prop()
lib: Kconfig: add entry for errno_str() function
dm: pmic: add implementation of driver model pmic uclass
dm: regulator: add implementation of driver model regulator uclass
dm: pmic: add pmic command
dm: regulator: add regulator command
pmic: max77686 set the same compatible as in the kernel
dm: pmic: add max77686 pmic driver
dm: regulator: add max77686 regulator driver
dm: regulator: add fixed voltage regulator driver
doc: driver-model: pmic and regulator uclass documentation
dm: board:samsung: power_init_board: add requirement of CONFIG_DM_PMIC
odroid: board: add support to dm pmic api
odroid: dts: add 'voltage-regulators' description to max77686 node
odroid: config: enable dm pmic, dm regulator and max77686 driver

 Makefile                             |   1 +
 arch/arm/dts/exynos4412-odroid.dts   | 249 +++++++++-
 arch/arm/dts/exynos4412-trats2.dts   |   2 +-
 arch/arm/dts/exynos5250-smdk5250.dts |   2 +-
 arch/arm/dts/exynos5250-snow.dts     |   2 +-
 board/samsung/common/board.c         |   4 +-
 board/samsung/common/misc.c          |   1 +
 board/samsung/odroid/odroid.c        | 113 ++++-
 common/Kconfig                       |  36 ++
 common/Makefile                      |   4 +
 common/cmd_pmic.c                    | 210 +++++++++
 common/cmd_regulator.c               | 385 +++++++++++++++
 configs/odroid_defconfig             |   8 +-
 doc/driver-model/pmic-framework.txt  | 350 ++++++++++++++
 drivers/core/lists.c                 |  28 +-
 drivers/power/Kconfig                | 124 ++++-
 drivers/power/Makefile               |   3 +-
 drivers/power/pmic-uclass.c          | 130 ++++++
 drivers/power/pmic/Makefile          |   1 +
 drivers/power/pmic/max77686.c        |  76 +++
 drivers/power/pmic/pmic_max77686.c   |   2 +-
 drivers/power/regulator-uclass.c     | 219 +++++++++
 drivers/power/regulator/Makefile     |   9 +
 drivers/power/regulator/fixed.c      | 124 +++++
 drivers/power/regulator/max77686.c   | 876 +++++++++++++++++++++++++++++++++++
 include/configs/exynos5-common.h     |   4 +
 include/configs/odroid.h             |   5 -
 include/dm/lists.h                   |  18 +
 include/dm/uclass-id.h               |   4 +
 include/libfdt.h                     |  27 ++
 include/power/max77686_pmic.h        |  26 +-
 include/power/pmic.h                 | 210 +++++++++
 include/power/regulator.h            | 259 +++++++++++
 lib/Kconfig                          |   8 +
 lib/fdtdec.c                         |   2 +-
 lib/libfdt/fdt_ro.c                  |  14 +-
 36 files changed, 3481 insertions(+), 55 deletions(-)
 create mode 100644 common/cmd_pmic.c
 create mode 100644 common/cmd_regulator.c
 create mode 100644 doc/driver-model/pmic-framework.txt
 create mode 100644 drivers/power/pmic-uclass.c
 create mode 100644 drivers/power/pmic/max77686.c
 create mode 100644 drivers/power/regulator-uclass.c
 create mode 100644 drivers/power/regulator/Makefile
 create mode 100644 drivers/power/regulator/fixed.c
 create mode 100644 drivers/power/regulator/max77686.c
 create mode 100644 include/power/regulator.h

--
1.9.1

#147 lore raw

v3 cover Power(full) framework based on Driver Model

Hello Simon,

Quoted 12 lines · Simon Glass

Hi Przemyslaw,

Quoted 6 lines · Przemyslaw Marczak

Hello,
Here is the third RFC version of the new PMIC framework.Big thanks to Simon Glass, your comments were really helpful, and I think, that this version is much more better to discuss, than the previous. The changes made in this version are described below each commit. Sorry that I didn't reply to each patch, I agreed with most and just started the work.

This is looking really good. Here are a few overall comments.

Quoted 8 lines

1. There is one oddity that I'd like to address before merging.

I don't think the fdt_node_check_prop_compatible() is a good idea, nor necessary. I don't think we should consider the regulator-compatible property to be a compatible string. It has values like LDO8, LDO9 and these don't look like compatible strings, which are normally unique and point to a driver. Here they point to a particular device.

Right, those compatibles don't point to a driver. This is a specific case of use from the kernel.

Quoted 6 lines

A similar problem is faced in pinctrl and if you look at gpio_exynos_bind() you will see that it works through the sub-nodes, creating devices as needed.

I don't think using udevice_id is right here either.

Yes, I know how it's done. But we haven't the compatibles for each GPIO as for the regulators, and each GPIO driver, bind the childs by its own implementation.

I tried to reuse the existing code. It was nice, but I missed one thing...if there are more, than one driver with the same e.g. "LDO1" compatible, then the first one will bind - and it could be the wrong one...

But, it could be tune-up, to get the right drivers list by arg.

Quoted 4 lines

Here is my suggestion:

a. Create a new structure like this:

Quoted 9 lines

struct pmic_child_info {
const char *prefix; // "LDO" or "BUCK"
const char *driver_name; // "max77686_ldo" or "max77686_buck"
};

b. Pass a list of these to pmic_child_node_scan(). In your case there will be three entries, one for LDO, one for BUCK, plus a NULL termination entry,

Ok, this could be good.

Quoted 6 lines

c. It can work through the subnodes looking for the given prefixes. It then calls device_bind_driver() on each. Then it changes the returned device's of_data to hold the correct value (obtained with strtol() on the part of the name that follows the prefix - e.g. 17 for "LDO17"). This will be easier if you rebase on u-boot-dm/usb-working, where the data is just a long, not a device tree pointer.

Yes, it's easy. I made something like this in the first version of this patchset, to parse the nodes and fill the max77686 regulator descriptors in function get_desc_for_compat(), from this patch:
http://lists.denx.de/pipermail/u-boot/2014-October/191024.html

Quoted 4 lines

d. Now you have the same effect as before, but you can drop the tables like max77686_ldo_ids[] and avoid misappropriating driver model's device lookup.

Yes, this is an advantage.

I wonder about the usage of "struct udevice_id", which should contain the data, defined only by the driver, right?

In the method you mentioned, we bind the pmic childs and then we modify the "dev->of_id->data" by putting the regulator number from matched prefix in it.

This is ok, but I think, that the second part of this idea should be done by the driver. I think, that the external function shouldn't modify this driver data on bind.

This could be solved by leave this job for the device driver. For example on max77686, we could leave the dev->of_id as null and use dev->priv for the node prefix id.

So, it's not a big problem.

Here, I would like mention the problem with the regulator_get() by name, for which we want use the "regulator-name" constraint.

For this version, it requires probing of all regulator devices, since it uses the dev->uclass_priv, which I think, is a good place to provide the framework-specific structure type for regulator constraints and mode descriptors.

What about moving it back to dev->platdata? Then:
- the structure type: "dm_regulator_info", will move to "dm_regulator_platdata"

- only its .name field could be assigned at regulator bind stage from the "regulator-name" constraint

- the bind could fail, when the constraint name not found

- the rest of constraints will assign in .ofdata_to_platdata() function call as it is at the present version

Then, we also don't need probe each regulator device, when using regulator_get() function.

Quoted 2 lines

2. Should we put the regulator stuff in drivers/regulator, as with Linux?

I will do this in the next version.

Quoted 3 lines

3. Can you please bring in the regulator and pmic device tree binding files, plus max77686?

Right, I forgot about this.

Quoted 11 lines

4. We really do need tests! I suspect that you could create a sandbox I2C pmic that has a few registers and regulators. See i2c_eeprom_emul.c for a basic example. Then you can write some tests that find the pmi,c find the regulator, read and write a few registers, and read and write a few regulators. That would be enough test coverage to get us started. I know this is different from previous U-Boot policy, but tests are a big win during development and also for years to come (as people can change the framework and have some confidence that they did not break anything).

Quoted 8 lines

It can be a follow-on patch separate from your series but I'm really not keen on bringing in a major new driver model framework with no tests. If you are struggling for time, let me know and I can try to help by writing a sandbox I2C PMIC for example.

Regards,
Simon

Ok, I will add sandbox drivers for this all, but first let's prepare the final patchset version of this framework, and then I will send a separate patchset for sandbox before merge of this part.

Quoted 70 lines
Quoted 70 lines

Best regards

Przemyslaw Marczak (17):
exynos5: fix build break by adding CONFIG_POWER
fdt_ro.c: add new function: fdt_node_check_prop_compatible()
dm: core: lists.c: add new function lists_bind_fdt_by_prop()
lib: Kconfig: add entry for errno_str() function
dm: pmic: add implementation of driver model pmic uclass
dm: regulator: add implementation of driver model regulator uclass
dm: pmic: add pmic command
dm: regulator: add regulator command
pmic: max77686 set the same compatible as in the kernel
dm: pmic: add max77686 pmic driver
dm: regulator: add max77686 regulator driver
dm: regulator: add fixed voltage regulator driver
doc: driver-model: pmic and regulator uclass documentation
dm: board:samsung: power_init_board: add requirement of CONFIG_DM_PMIC
odroid: board: add support to dm pmic api
odroid: dts: add 'voltage-regulators' description to max77686 node
odroid: config: enable dm pmic, dm regulator and max77686 driver

  Makefile                             |   1 +
  arch/arm/dts/exynos4412-odroid.dts   | 249 +++++++++-
  arch/arm/dts/exynos4412-trats2.dts   |   2 +-
  arch/arm/dts/exynos5250-smdk5250.dts |   2 +-
  arch/arm/dts/exynos5250-snow.dts     |   2 +-
  board/samsung/common/board.c         |   4 +-
  board/samsung/common/misc.c          |   1 +
  board/samsung/odroid/odroid.c        | 113 ++++-
  common/Kconfig                       |  36 ++
  common/Makefile                      |   4 +
  common/cmd_pmic.c                    | 210 +++++++++
  common/cmd_regulator.c               | 385 +++++++++++++++
  configs/odroid_defconfig             |   8 +-
  doc/driver-model/pmic-framework.txt  | 350 ++++++++++++++
  drivers/core/lists.c                 |  28 +-
  drivers/power/Kconfig                | 124 ++++-
  drivers/power/Makefile               |   3 +-
  drivers/power/pmic-uclass.c          | 130 ++++++
  drivers/power/pmic/Makefile          |   1 +
  drivers/power/pmic/max77686.c        |  76 +++
  drivers/power/pmic/pmic_max77686.c   |   2 +-
  drivers/power/regulator-uclass.c     | 219 +++++++++
  drivers/power/regulator/Makefile     |   9 +
  drivers/power/regulator/fixed.c      | 124 +++++
  drivers/power/regulator/max77686.c   | 876 +++++++++++++++++++++++++++++++++++
  include/configs/exynos5-common.h     |   4 +
  include/configs/odroid.h             |   5 -
  include/dm/lists.h                   |  18 +
  include/dm/uclass-id.h               |   4 +
  include/libfdt.h                     |  27 ++
  include/power/max77686_pmic.h        |  26 +-
  include/power/pmic.h                 | 210 +++++++++
  include/power/regulator.h            | 259 +++++++++++
  lib/Kconfig                          |   8 +
  lib/fdtdec.c                         |   2 +-
  lib/libfdt/fdt_ro.c                  |  14 +-
  36 files changed, 3481 insertions(+), 55 deletions(-)

create mode 100644 common/cmd_pmic.c
create mode 100644 common/cmd_regulator.c create mode 100644 doc/driver-model/pmic-framework.txt create mode 100644 drivers/power/pmic-uclass.c create mode 100644 drivers/power/pmic/max77686.c create mode 100644 drivers/power/regulator-uclass.c create mode 100644 drivers/power/regulator/Makefile create mode 100644 drivers/power/regulator/fixed.c create mode 100644 drivers/power/regulator/max77686.c create mode 100644 include/power/regulator.h

Quoted 4 lines
Quoted 3 lines

--
1.9.1

Thank you again for the review!
I will send the next version probably on 7-8-th April.

Best regards,

Signature · 4 lines
Przemyslaw Marczak
Samsung R&D Institute Poland
Samsung Electronics
p.marczak at samsung.com
#148 lore raw

v3 cover Power(full) framework based on Driver Model

Hi Przemyslaw,

Quoted 72 lines · Przemyslaw Marczak

Hello Simon,

Quoted 16 lines · Simon Glass

Hi Przemyslaw,

Quoted 7 lines · Przemyslaw Marczak

Hello,
Here is the third RFC version of the new PMIC framework.Big thanks to Simon Glass, your comments were really helpful, and I think, that this version is much more better to discuss, than the previous. The changes made in this version are described below each commit. Sorry that I didn't reply to each patch, I agreed with most and just started the work.

This is looking really good. Here are a few overall comments.

Quoted 8 lines

1. There is one oddity that I'd like to address before merging.

I don't think the fdt_node_check_prop_compatible() is a good idea, nor necessary. I don't think we should consider the regulator-compatible property to be a compatible string. It has values like LDO8, LDO9 and these don't look like compatible strings, which are normally unique and point to a driver. Here they point to a particular device.

Right, those compatibles don't point to a driver. This is a specific case of use from the kernel.

Quoted 6 lines

A similar problem is faced in pinctrl and if you look at gpio_exynos_bind() you will see that it works through the sub-nodes, creating devices as needed.

I don't think using udevice_id is right here either.

Yes, I know how it's done. But we haven't the compatibles for each GPIO as for the regulators, and each GPIO driver, bind the childs by its own implementation.

I tried to reuse the existing code. It was nice, but I missed one thing...if there are more, than one driver with the same e.g. "LDO1" compatible, then the first one will bind - and it could be the wrong one...

But, it could be tune-up, to get the right drivers list by arg.

Quoted 4 lines

Here is my suggestion:

a. Create a new structure like this:

Quoted 9 lines

struct pmic_child_info {
const char *prefix; // "LDO" or "BUCK"
const char *driver_name; // "max77686_ldo" or "max77686_buck"
};

b. Pass a list of these to pmic_child_node_scan(). In your case there will be three entries, one for LDO, one for BUCK, plus a NULL termination entry,

Ok, this could be good.

Quoted 6 lines

c. It can work through the subnodes looking for the given prefixes. It then calls device_bind_driver() on each. Then it changes the returned device's of_data to hold the correct value (obtained with strtol() on the part of the name that follows the prefix - e.g. 17 for "LDO17"). This will be easier if you rebase on u-boot-dm/usb-working, where the data is just a long, not a device tree pointer.

Quoted 5 lines

Yes, it's easy. I made something like this in the first version of this patchset, to parse the nodes and fill the max77686 regulator descriptors in function get_desc_for_compat(), from this patch:
http://lists.denx.de/pipermail/u-boot/2014-October/191024.html

Yes I see.

Quoted 19 lines
Quoted 4 lines

d. Now you have the same effect as before, but you can drop the tables like max77686_ldo_ids[] and avoid misappropriating driver model's device lookup.

Yes, this is an advantage.

I wonder about the usage of "struct udevice_id", which should contain the data, defined only by the driver, right?

In the method you mentioned, we bind the pmic childs and then we modify the "dev->of_id->data" by putting the regulator number from matched prefix in it.

This is ok, but I think, that the second part of this idea should be done by the driver. I think, that the external function shouldn't modify this driver data on bind.

Quoted 5 lines

This could be solved by leave this job for the device driver. For example on max77686, we could leave the dev->of_id as null and use dev->priv for the node prefix id.

So, it's not a big problem.

As I see it the regulator number (e.g. 1 for LDO1, 3 for BUCK3) is picked up from the name string, so it feels like this is common code. You would be calling a helper function from the driver, so yes you can always have it return the regulator number, and then store it in driver_data in the driver.

But you should rebase on dm/usb-working to get the new driver_data member of struct udevice.

My only concern with using driver_data is that this is normally used to specify the device type where the driver supports multiple hardware variants. The regulator number is more correctly considered to be platform data. This leads on to your point below.

Quoted 17 lines

Here, I would like mention the problem with the regulator_get() by name, for which we want use the "regulator-name" constraint.

For this version, it requires probing of all regulator devices, since it uses the dev->uclass_priv, which I think, is a good place to provide the framework-specific structure type for regulator constraints and mode descriptors.

What about moving it back to dev->platdata? Then:
- the structure type: "dm_regulator_info", will move to "dm_regulator_platdata"

- only its .name field could be assigned at regulator bind stage from the "regulator-name" constraint

Quoted 7 lines

- the bind could fail, when the constraint name not found

- the rest of constraints will assign in .ofdata_to_platdata() function call as it is at the present version

Then, we also don't need probe each regulator device, when using regulator_get() function.

Here is my understanding on this one:

The regulator name is the device name, so looking up by name should be easy. It just involves scanning through the regulator uclass comparing device names.

Based on what you said above, the regulator number should go in platform data for the regulator as you say. It can be worked out when the PMIC is bound (perhaps in the PMIC uclass' post_bind method).

The idea is that the PMIC is responsible for binding its children so that at start-up we know about all the regulators and can find them, even through none is probed yet.

Quoted 30 lines
Quoted 3 lines

2. Should we put the regulator stuff in drivers/regulator, as with Linux?

I will do this in the next version.

Quoted 3 lines

3. Can you please bring in the regulator and pmic device tree binding files, plus max77686?

Right, I forgot about this.

Quoted 16 lines

4. We really do need tests! I suspect that you could create a sandbox I2C pmic that has a few registers and regulators. See i2c_eeprom_emul.c for a basic example. Then you can write some tests that find the pmi,c find the regulator, read and write a few registers, and read and write a few regulators. That would be enough test coverage to get us started. I know this is different from previous U-Boot policy, but tests are a big win during development and also for years to come (as people can change the framework and have some confidence that they did not break anything).

It can be a follow-on patch separate from your series but I'm really not keen on bringing in a major new driver model framework with no tests. If you are struggling for time, let me know and I can try to help by writing a sandbox I2C PMIC for example.

Quoted 7 lines
Quoted 3 lines

Regards,
Simon

Ok, I will add sandbox drivers for this all, but first let's prepare the final patchset version of this framework, and then I will send a separate patchset for sandbox before merge of this part.

OK sounds good.

Quoted 73 lines
Quoted 73 lines
Quoted 73 lines

Best regards

Przemyslaw Marczak (17):
exynos5: fix build break by adding CONFIG_POWER
fdt_ro.c: add new function: fdt_node_check_prop_compatible()
dm: core: lists.c: add new function lists_bind_fdt_by_prop()
lib: Kconfig: add entry for errno_str() function
dm: pmic: add implementation of driver model pmic uclass
dm: regulator: add implementation of driver model regulator uclass
dm: pmic: add pmic command
dm: regulator: add regulator command
pmic: max77686 set the same compatible as in the kernel
dm: pmic: add max77686 pmic driver
dm: regulator: add max77686 regulator driver
dm: regulator: add fixed voltage regulator driver
doc: driver-model: pmic and regulator uclass documentation
dm: board:samsung: power_init_board: add requirement of CONFIG_DM_PMIC
odroid: board: add support to dm pmic api
odroid: dts: add 'voltage-regulators' description to max77686 node
odroid: config: enable dm pmic, dm regulator and max77686 driver

  Makefile                             |   1 +
  arch/arm/dts/exynos4412-odroid.dts   | 249 +++++++++-
  arch/arm/dts/exynos4412-trats2.dts   |   2 +-
  arch/arm/dts/exynos5250-smdk5250.dts |   2 +-
  arch/arm/dts/exynos5250-snow.dts     |   2 +-
  board/samsung/common/board.c         |   4 +-
  board/samsung/common/misc.c          |   1 +
  board/samsung/odroid/odroid.c        | 113 ++++-
  common/Kconfig                       |  36 ++
  common/Makefile                      |   4 +
  common/cmd_pmic.c                    | 210 +++++++++
  common/cmd_regulator.c               | 385 +++++++++++++++
  configs/odroid_defconfig             |   8 +-
  doc/driver-model/pmic-framework.txt  | 350 ++++++++++++++
  drivers/core/lists.c                 |  28 +-
  drivers/power/Kconfig                | 124 ++++-
  drivers/power/Makefile               |   3 +-
  drivers/power/pmic-uclass.c          | 130 ++++++
  drivers/power/pmic/Makefile          |   1 +
  drivers/power/pmic/max77686.c        |  76 +++
  drivers/power/pmic/pmic_max77686.c   |   2 +-
  drivers/power/regulator-uclass.c     | 219 +++++++++
  drivers/power/regulator/Makefile     |   9 +
  drivers/power/regulator/fixed.c      | 124 +++++
  drivers/power/regulator/max77686.c   | 876
+++++++++++++++++++++++++++++++++++
  include/configs/exynos5-common.h     |   4 +
  include/configs/odroid.h             |   5 -
  include/dm/lists.h                   |  18 +
  include/dm/uclass-id.h               |   4 +
  include/libfdt.h                     |  27 ++
  include/power/max77686_pmic.h        |  26 +-
  include/power/pmic.h                 | 210 +++++++++
  include/power/regulator.h            | 259 +++++++++++
  lib/Kconfig                          |   8 +
  lib/fdtdec.c                         |   2 +-
  lib/libfdt/fdt_ro.c                  |  14 +-
  36 files changed, 3481 insertions(+), 55 deletions(-)

create mode 100644 common/cmd_pmic.c
create mode 100644 common/cmd_regulator.c create mode 100644 doc/driver-model/pmic-framework.txt create mode 100644 drivers/power/pmic-uclass.c create mode 100644 drivers/power/pmic/max77686.c create mode 100644 drivers/power/regulator-uclass.c create mode 100644 drivers/power/regulator/Makefile create mode 100644 drivers/power/regulator/fixed.c create mode 100644 drivers/power/regulator/max77686.c create mode 100644 include/power/regulator.h

Quoted 7 lines
Quoted 4 lines
Quoted 3 lines

--
1.9.1

Thank you again for the review!
I will send the next version probably on 7-8-th April.

Regards,
Simon

#149 lore raw

v4 cover Power(full) framework based on Driver Model

In reply to Przemyslaw Marczak

Hello,
Again the next version. The changes are described below each commit message. This is rebased on last u-boot-dm/master after apply this patchset:
https://patchwork.ozlabs.org/patch/462775/
https://patchwork.ozlabs.org/patch/462777/
https://patchwork.ozlabs.org/patch/462776/

This all can be found in here:
https://github.com/bobenstein/u-boot/tree/dm-pmic-v4

Best regards,

Przemyslaw Marczak (16):
exynos5: fix build break by adding CONFIG_POWER
exynos4-common: remove the unsued CONFIG_CMD_PMIC
lib: Kconfig: add entry for errno_str() function
dm: pmic: add implementation of driver model pmic uclass
dm: regulator: add implementation of driver model regulator uclass
dm: pmic: add pmic command
dm: regulator: add regulator command
pmic: max77686 set the same compatible as in the kernel
dm: pmic: add max77686 pmic driver
dm: regulator: add max77686 regulator driver
dm: regulator: add fixed voltage regulator driver
doc: driver-model: pmic and regulator uclass documentation
dm: board:samsung: power_init_board: add requirement of CONFIG_DM_PMIC
odroid: board: add support to dm pmic api
odroid: dts: add 'voltage-regulators' description to max77686 node
odroid: config: enable dm pmic, dm regulator and max77686 driver

 Makefile                                         |   3 +-
 arch/arm/dts/exynos4412-odroid.dts               | 255 ++++++-
 arch/arm/dts/exynos4412-trats2.dts               |   2 +-
 arch/arm/dts/exynos5250-smdk5250.dts             |   2 +-
 arch/arm/dts/exynos5250-snow.dts                 |   2 +-
 board/samsung/common/board.c                     |   4 +-
 board/samsung/common/misc.c                      |   1 +
 board/samsung/odroid/odroid.c                    |  77 ++-
 common/Kconfig                                   |  36 +
 common/Makefile                                  |   4 +
 common/cmd_pmic.c                                | 231 +++++++
 common/cmd_regulator.c                           | 403 +++++++++++
 configs/odroid_defconfig                         |   8 +-
 doc/device-tree-bindings/pmic/max77686.txt       |  36 +
 doc/device-tree-bindings/regulator/fixed.txt     |  38 ++
 doc/device-tree-bindings/regulator/max77686.txt  |  70 ++
 doc/device-tree-bindings/regulator/regulator.txt |  55 ++
 doc/driver-model/pmic-framework.txt              | 142 ++++
 drivers/power/Kconfig                            |   8 +
 drivers/power/Makefile                           |   1 -
 drivers/power/pmic/Kconfig                       |  18 +
 drivers/power/pmic/Makefile                      |   2 +
 drivers/power/pmic/max77686.c                    |  87 +++
 drivers/power/pmic/pmic-uclass.c                 | 158 +++++
 drivers/power/pmic/pmic_max77686.c               |   2 +-
 drivers/power/regulator/Kconfig                  |  33 +
 drivers/power/regulator/Makefile                 |  10 +
 drivers/power/regulator/fixed.c                  | 126 ++++
 drivers/power/regulator/max77686.c               | 825 +++++++++++++++++++++++
 drivers/power/regulator/regulator-uclass.c       | 300 +++++++++
 include/configs/exynos4-common.h                 |   1 -
 include/configs/exynos5-common.h                 |   4 +
 include/configs/odroid.h                         |   5 -
 include/dm/uclass-id.h                           |   4 +
 include/power/max77686_pmic.h                    |  29 +-
 include/power/pmic.h                             | 189 ++++++
 include/power/regulator.h                        | 384 +++++++++++
 lib/Kconfig                                      |   8 +
 lib/fdtdec.c                                     |   2 +-
 39 files changed, 3512 insertions(+), 53 deletions(-)
 create mode 100644 common/cmd_pmic.c
 create mode 100644 common/cmd_regulator.c
 create mode 100644 doc/device-tree-bindings/pmic/max77686.txt
 create mode 100644 doc/device-tree-bindings/regulator/fixed.txt
 create mode 100644 doc/device-tree-bindings/regulator/max77686.txt
 create mode 100644 doc/device-tree-bindings/regulator/regulator.txt
 create mode 100644 doc/driver-model/pmic-framework.txt
 create mode 100644 drivers/power/pmic/Kconfig
 create mode 100644 drivers/power/pmic/max77686.c
 create mode 100644 drivers/power/pmic/pmic-uclass.c
 create mode 100644 drivers/power/regulator/Kconfig
 create mode 100644 drivers/power/regulator/Makefile
 create mode 100644 drivers/power/regulator/fixed.c
 create mode 100644 drivers/power/regulator/max77686.c
 create mode 100644 drivers/power/regulator/regulator-uclass.c
 create mode 100644 include/power/regulator.h
Signature · 1 line
1.9.1
#150 lore raw

PATCH v4 1/16 exynos5: fix build break by adding CONFIG_POWER

Move the configs listed below from exynos5-dt-common.h to exynos5-common.h:
- CONFIG_POWER
- CONFIG_POWER_I2C
fixes build break for Arndale and Smdk5250 boards.

---
 include/configs/exynos5-common.h | 4 ++++
 1 file changed, 4 insertions(+)
include/configs/exynos5-common.h +4 -0
index 2eddb07..5476248 100644
@@ -149,6 +149,10 @@
 #define CONFIG_OF_SPI
 #endif
 
+/* Power */
+#define CONFIG_POWER
+#define CONFIG_POWER_I2C
+
 #ifdef CONFIG_ENV_IS_IN_SPI_FLASH
 #define CONFIG_ENV_SPI_MODE	SPI_MODE_0
 #define CONFIG_ENV_SECT_SIZE	CONFIG_ENV_SIZE
Signature · 1 line
1.9.1
#151 lore raw

PATCH v4 1/16 exynos5: fix build break by adding CONFIG_POWER

Quoted 10 lines · Przemyslaw Marczak

Move the configs listed below from exynos5-dt-common.h to exynos5-common.h:
- CONFIG_POWER
- CONFIG_POWER_I2C
fixes build break for Arndale and Smdk5250 boards.

---
 include/configs/exynos5-common.h | 4 ++++
 1 file changed, 4 insertions(+)
#152 lore raw

PATCH v4 1/16 exynos5: fix build break by adding CONFIG_POWER

Quoted 7 lines · Simon Glass
Quoted 6 lines · Przemyslaw Marczak

Move the configs listed below from exynos5-dt-common.h to exynos5-common.h:
- CONFIG_POWER
- CONFIG_POWER_I2C
fixes build break for Arndale and Smdk5250 boards.

Quoted 6 lines
Quoted 4 lines
---
 include/configs/exynos5-common.h | 4 ++++
 1 file changed, 4 insertions(+)

Applied to u-boot-dm/next, thanks!

#153 lore raw

PATCH v4 2/16 exynos4-common: remove the unsued CONFIG_CMD_PMIC

In reply to Przemyslaw Marczak

This config name was never used, because the present pmic command was precompiled for the CONFIG_POWER.

---
 include/configs/exynos4-common.h | 1 -
 1 file changed, 1 deletion(-)
include/configs/exynos4-common.h +0 -1
index 577afe7..dbe05e4 100644
@@ -31,7 +31,6 @@
 #undef CONFIG_CMD_MTDPARTS
 #define CONFIG_CMD_DFU
 #define CONFIG_CMD_GPT
-#define CONFIG_CMD_PMIC
 #define CONFIG_CMD_SETEXPR
 
 /* USB Composite download gadget - g_dnl */
Signature · 1 line
1.9.1
#155 lore raw

PATCH v4 2/16 exynos4-common: remove the unsued CONFIG_CMD_PMIC

Quoted 10 lines · Simon Glass
Quoted 7 lines · Przemyslaw Marczak

This config name was never used, because the present pmic command was precompiled for the CONFIG_POWER.

---
 include/configs/exynos4-common.h | 1 -
 1 file changed, 1 deletion(-)

Applied to u-boot-dm/next, thanks!

#156 lore raw

PATCH v4 3/16 lib: Kconfig: add entry for errno_str() function

In reply to Przemyslaw Marczak
---
 lib/Kconfig | 8 ++++++++
 1 file changed, 8 insertions(+)
lib/Kconfig +8 -0
index d7fd219..b64cd92 100644
@@ -74,4 +74,12 @@ config SHA_PROG_HW_ACCEL
 	  is performed in hardware.
 endmenu
 
+config ERRNO_STR
+	bool "Enable function for getting errno-related string message"
+	help
+	  The function errno_str(int errno), returns a pointer to the errno
+	  corresponding text message:
+	  - if errno is null or positive number - a pointer to "Success" message
+	  - if errno is negative - a pointer to errno related message
+
 endmenu
Signature · 1 line
1.9.1
#159 lore raw

PATCH v4 4/16 dm: pmic: add implementation of driver model pmic uclass

In reply to Przemyslaw Marczak

This commit introduces the PMIC uclass implementation. It allows providing the basic I/O interface for PMIC devices. For the multi-function PMIC devices, this can be used as I/O parent device, for each IC's interface. Then, each PMIC particular function can be provided by the child device's operations, and the child devices will use its parent for read/write by the common API.

Core files:
- 'include/power/pmic.h'
- 'drivers/power/pmic/pmic-uclass.c'

The old pmic framework is still kept and is independent.

For more detailed informations, please look into the header file.

Changes:
- new uclass-id: UCLASS_PMIC
- new config: CONFIG_DM_PMIC

---
Changes V2:
- pmic uclass: adjust uclass code to the mainline changes
- pmic uclass: remove pmic_i2c and pmic_spi
- pmic uclass: modify pmic_platdata
- pmic uclass: add pmic_if_* functions
- pmic uclass: remove pmic_init_dm()
- pmic uclass: cleanup
- pmic.h: define pmic ops structure (read/write operations)
- pmic.h: add comments to functions

Changes V3:
- pmic-uclass.c and pmic.h:
-- remove pmic_if_* functions
-- add new function pmic_child_node_scan()
- add Kconfig entry

Changes V4:
- move drivers/power/pmic-uclass.c to drivers/power/pmic/pmic-uclass.c
- move DM_PMIC Kconfig entry: drivers/power/Kconfig to drivers/power/pmic/Kconfig
- drivers/power/Kconfig: Add menu "Power" and include pmic Kconfig
- Kconfig: provide only the general information about the PMIC
- pmic-uclass.c: add pmic_bind_childs()
- pmic-uclass.c: add debug
- pmic-uclass.c: cleanup includes
- pmic-uclass.c: remove pmic_get_uclass_ops() and use of dev_get_driver_ops()
- pmic-uclass.c: use of uclass_get_device_by_name()
- pmic-uclass.c: add str_get_num() - for get number from string
- include/power/pmic.h - start comments rewording
- power/pmic.h: comments update

---
 drivers/power/Kconfig            |   6 ++
 drivers/power/pmic/Kconfig       |  11 +++
 drivers/power/pmic/Makefile      |   1 +
 drivers/power/pmic/pmic-uclass.c | 158 ++++++++++++++++++++++++++++++++
 include/dm/uclass-id.h           |   3 +
 include/power/pmic.h             | 189 +++++++++++++++++++++++++++++++++++++++
 6 files changed, 368 insertions(+)
 create mode 100644 drivers/power/pmic/Kconfig
 create mode 100644 drivers/power/pmic/pmic-uclass.c
drivers/power/Kconfig +6 -0
index f8f0239..d03626e 100644
@@ -1,3 +1,7 @@
+menu "Power"
+
+source "drivers/power/pmic/Kconfig"
+
 config AXP221_POWER
 	boolean "axp221 / axp223 pmic support"
 	depends on MACH_SUN6I || MACH_SUN8I
@@ -73,3 +77,5 @@ config AXP221_ELDO3_VOLT
 	disable eldo3. On some A31(s) tablets it might be used to supply
 	1.2V for the SSD2828 chip (converter of parallel LCD interface
 	into MIPI DSI).
+
+endmenu
drivers/power/pmic/Kconfig new file +11 -0
new file mode 100644
index 0000000..d06d632
@@ -0,0 +1,11 @@
+config DM_PMIC
+	bool "Enable Driver Model for PMIC drivers (UCLASS_PMIC)"
+	depends on DM
+	---help---
+	This config enables the driver-model PMIC support.
+	UCLASS_PMIC - designed to provide an I/O interface for PMIC devices.
+	For the multi-function PMIC devices, this can be used as parent I/O
+	device for each IC's interface. Then, each children uses its parent
+	for read/write. For detailed description, please refer to the files:
+	- 'drivers/power/pmic/pmic-uclass.c'
+	- 'include/power/pmic.h'
drivers/power/pmic/Makefile +1 -0
index 985cfdb..594f620 100644
@@ -5,6 +5,7 @@
 # SPDX-License-Identifier:	GPL-2.0+
 #
 
+obj-$(CONFIG_DM_PMIC) += pmic-uclass.o
 obj-$(CONFIG_POWER_LTC3676) += pmic_ltc3676.o
 obj-$(CONFIG_POWER_MAX8998) += pmic_max8998.o
 obj-$(CONFIG_POWER_MAX8997) += pmic_max8997.o
drivers/power/pmic/pmic-uclass.c new file +158 -0

158 lines not on this page · raw message

include/dm/uclass-id.h +3 -0
index fddfd35..23b3eb9 100644
@@ -46,6 +46,9 @@ enum uclass_id {
 	UCLASS_USB_DEV_GENERIC,	/* USB generic device */
 	UCLASS_MASS_STORAGE,	/* Mass storage device */
 
+	/* Power Management */
+	UCLASS_PMIC,		/* PMIC I/O device */
+
 	UCLASS_COUNT,
 	UCLASS_INVALID = -1,
 };
include/power/pmic.h +189 -0

216 lines not on this page · raw message

Signature · 1 line
1.9.1
#160 lore raw

PATCH v4 4/16 dm: pmic: add implementation of driver model pmic uclass

Hi Przemyslaw,

Quoted 50 lines · Przemyslaw Marczak

This commit introduces the PMIC uclass implementation. It allows providing the basic I/O interface for PMIC devices. For the multi-function PMIC devices, this can be used as I/O parent device, for each IC's interface. Then, each PMIC particular function can be provided by the child device's operations, and the child devices will use its parent for read/write by the common API.

Core files:
- 'include/power/pmic.h'
- 'drivers/power/pmic/pmic-uclass.c'

The old pmic framework is still kept and is independent.

For more detailed informations, please look into the header file.

Changes:
- new uclass-id: UCLASS_PMIC
- new config: CONFIG_DM_PMIC

---
Changes V2:
- pmic uclass: adjust uclass code to the mainline changes
- pmic uclass: remove pmic_i2c and pmic_spi
- pmic uclass: modify pmic_platdata
- pmic uclass: add pmic_if_* functions
- pmic uclass: remove pmic_init_dm()
- pmic uclass: cleanup
- pmic.h: define pmic ops structure (read/write operations)
- pmic.h: add comments to functions

Changes V3:
- pmic-uclass.c and pmic.h:
-- remove pmic_if_* functions
-- add new function pmic_child_node_scan()
- add Kconfig entry

Changes V4:
- move drivers/power/pmic-uclass.c to drivers/power/pmic/pmic-uclass.c
- move DM_PMIC Kconfig entry: drivers/power/Kconfig to drivers/power/pmic/Kconfig
- drivers/power/Kconfig: Add menu "Power" and include pmic Kconfig
- Kconfig: provide only the general information about the PMIC
- pmic-uclass.c: add pmic_bind_childs()
- pmic-uclass.c: add debug
- pmic-uclass.c: cleanup includes
- pmic-uclass.c: remove pmic_get_uclass_ops() and use of dev_get_driver_ops()
- pmic-uclass.c: use of uclass_get_device_by_name()
- pmic-uclass.c: add str_get_num() - for get number from string
- include/power/pmic.h - start comments rewording
- power/pmic.h: comments update

Quoted 10 lines
---
 drivers/power/Kconfig            |   6 ++
 drivers/power/pmic/Kconfig       |  11 +++
 drivers/power/pmic/Makefile      |   1 +
 drivers/power/pmic/pmic-uclass.c | 158 ++++++++++++++++++++++++++++++++
 include/dm/uclass-id.h           |   3 +
 include/power/pmic.h             | 189 +++++++++++++++++++++++++++++++++++++++
 6 files changed, 368 insertions(+)
 create mode 100644 drivers/power/pmic/Kconfig
 create mode 100644 drivers/power/pmic/pmic-uclass.c

I have a few nits below - perhaps they can be targeted in a follow-up patch or two? I'd like to merge this soon and it is not worth holding up the series for nits.

Quoted 156 lines
drivers/power/Kconfig +6 -0
index f8f0239..d03626e 100644
@@ -1,3 +1,7 @@
+menu "Power"
+
+source "drivers/power/pmic/Kconfig"
+
 config AXP221_POWER
        boolean "axp221 / axp223 pmic support"
        depends on MACH_SUN6I || MACH_SUN8I
@@ -73,3 +77,5 @@ config AXP221_ELDO3_VOLT
        disable eldo3. On some A31(s) tablets it might be used to supply
        1.2V for the SSD2828 chip (converter of parallel LCD interface
        into MIPI DSI).
+
+endmenu
drivers/power/pmic/Kconfig new file +11 -0
new file mode 100644
index 0000000..d06d632
@@ -0,0 +1,11 @@
+config DM_PMIC
+       bool "Enable Driver Model for PMIC drivers (UCLASS_PMIC)"
+       depends on DM
+       ---help---
+       This config enables the driver-model PMIC support.
+       UCLASS_PMIC - designed to provide an I/O interface for PMIC devices.
+       For the multi-function PMIC devices, this can be used as parent I/O
+       device for each IC's interface. Then, each children uses its parent
+       for read/write. For detailed description, please refer to the files:
+       - 'drivers/power/pmic/pmic-uclass.c'
+       - 'include/power/pmic.h'
drivers/power/pmic/Makefile +1 -0
index 985cfdb..594f620 100644
@@ -5,6 +5,7 @@
 # SPDX-License-Identifier:     GPL-2.0+
 #
 
+obj-$(CONFIG_DM_PMIC) += pmic-uclass.o
 obj-$(CONFIG_POWER_LTC3676) += pmic_ltc3676.o
 obj-$(CONFIG_POWER_MAX8998) += pmic_max8998.o
 obj-$(CONFIG_POWER_MAX8997) += pmic_max8997.o
drivers/power/pmic/pmic-uclass.c new file +102 -0
new file mode 100644
index 0000000..d82d3da
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2014-2015 Samsung Electronics
+ * Przemyslaw Marczak <[email protected]>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <fdtdec.h>
+#include <errno.h>
+#include <dm.h>
+#include <dm/lists.h>
+#include <dm/device-internal.h>
+#include <dm/uclass-internal.h>
+#include <power/pmic.h>
+#include <linux/ctype.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static ulong str_get_num(const char *ptr, const char *maxptr)
+{
+       if (!ptr || !maxptr)
+               return 0;
+
+       while (!isdigit(*ptr) && ptr++ < maxptr);
+
+       return simple_strtoul(ptr, NULL, 0);
+}
+
+int pmic_bind_childs(struct udevice *pmic, int offset,
+                    const struct pmic_child_info *child_info)
+{
+       const struct pmic_child_info *info;
+       const void *blob = gd->fdt_blob;
+       struct driver *drv;
+       struct udevice *child;
+       const char *node_name;
+       int node_name_len;
+       int bind_count = 0;
+       int node;
+       int prefix_len;
+       int ret;
+
+       debug("%s for '%s' at node offset: %d\n", __func__, pmic->name,
+             pmic->of_offset);
+
+       for (node = fdt_first_subnode(blob, offset);
+            node > 0;
+            node = fdt_next_subnode(blob, node)) {
+               node_name = fdt_get_name(blob, node, &node_name_len);
+
+               debug("* Found child node: '%s' at offset:%d\n", node_name,
+                                                                node);
+
+               child = NULL;
+               info = child_info;
+               while (info->prefix) {
+                       prefix_len = strlen(info->prefix);
+                       if (strncasecmp(info->prefix, node_name, prefix_len) ||
+                           !info->driver) {
+                               info++;
+                               continue;
+                       }
+
+                       debug("  - compatible prefix: '%s'\n", info->prefix);
+
+                       drv = lists_driver_lookup_name(info->driver);
+                       if (!drv) {
+                               debug("  - driver: '%s' not found!\n",
+                                     info->driver);
+                               continue;
+                       }
+
+                       debug("  - found child driver: '%s'\n", drv->name);
+
+                       ret = device_bind(pmic, drv, node_name, NULL,
+                                         node, &child);
+                       if (ret) {
+                               debug("  - child binding error: %d\n", ret);
+                               continue;
+                       }
+
+                       debug("  - bound child device: '%s'\n", child->name);
+
+                       child->driver_data = str_get_num(node_name +
+                                                        prefix_len,
+                                                        node_name +
+                                                        node_name_len);
+
+                       debug("  - set 'child->driver_data': %lu\n",
+                             child->driver_data);
+                       break;
+               }
+
+               if (child)
+                       bind_count++;
+               else
+                       debug("  - compatible prefix not found\n");
+       }
+
+       debug("Bound: %d childs for PMIC: '%s'\n", bind_count, pmic->name);
+       return bind_count;

drivers/power/pmic/pmic-uclass.c line 112

Quoted 10 lines
drivers/power/pmic/pmic-uclass.c new file +10 -0
+}
+
+int pmic_get(const char *name, struct udevice **devp)
+{
+       return uclass_get_device_by_name(UCLASS_PMIC, name, devp);
+}
+
+int pmic_reg_count(struct udevice *dev)
+{
+       const struct dm_pmic_ops *ops = dev_get_driver_ops(dev);

blank line here

Quoted 73 lines
drivers/power/pmic/pmic-uclass.c new file +46 -0
+       if (!ops)
+               return -ENOSYS;
+
+       return ops->reg_count;
+}
+
+int pmic_read(struct udevice *dev, uint reg, uint8_t *buffer, int len)
+{
+       const struct dm_pmic_ops *ops = dev_get_driver_ops(dev);
+       int ret;
+
+       if (!buffer)
+               return -EFAULT;
+
+       if (!ops || !ops->read)
+               return -ENOSYS;
+
+       ret = ops->read(dev, reg, buffer, len);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+int pmic_write(struct udevice *dev, uint reg, const uint8_t *buffer, int len)
+{
+       const struct dm_pmic_ops *ops = dev_get_driver_ops(dev);
+       int ret;
+
+       if (!buffer)
+               return -EFAULT;
+
+       if (!ops || !ops->write)
+               return -ENOSYS;
+
+       ret = ops->write(dev, reg, buffer, len);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+UCLASS_DRIVER(pmic) = {
+       .id             = UCLASS_PMIC,
+       .name           = "pmic",
+};
include/dm/uclass-id.h +3 -0
index fddfd35..23b3eb9 100644
@@ -46,6 +46,9 @@ enum uclass_id {
        UCLASS_USB_DEV_GENERIC, /* USB generic device */
        UCLASS_MASS_STORAGE,    /* Mass storage device */
 
+       /* Power Management */
+       UCLASS_PMIC,            /* PMIC I/O device */
+
        UCLASS_COUNT,
        UCLASS_INVALID = -1,
 };
include/power/pmic.h +3 -0
index afbc5aa..f7ae781 100644
@@ -1,4 +1,7 @@
 /*
+ *  Copyright (C) 2014-2015 Samsung Electronics
+ *  Przemyslaw Marczak <[email protected]>
+ *
  *  Copyright (C) 2011-2012 Samsung Electronics
  *  Lukasz Majewski <[email protected]>
  *

include/power/pmic.h line 17

Quoted 6 lines
include/power/pmic.h +1 -0
@@ -9,10 +12,13 @@
 #define __CORE_PMIC_H_
 
 #include <linux/list.h>
+#include <spi.h>
 #include <i2c.h>
 #include <power/power_chrg.h>

At some point can you update the ordering of this lot? I think it should be:

i2c.g
spi.h
linux/
power/

Quoted 9 lines
include/power/pmic.h +2 -0
 enum { PMIC_I2C, PMIC_SPI, PMIC_NONE};
+
+#ifdef CONFIG_POWER
 enum { I2C_PMIC, I2C_NUM, };
 enum { PMIC_READ, PMIC_WRITE, };
 enum { PMIC_SENSOR_BYTE_ORDER_LITTLE, PMIC_SENSOR_BYTE_ORDER_BIG, };
@@ -77,7 +83,189 @@ struct pmic {
        struct pmic *parent;

include/power/pmic.h struct pmic { · line 93

Quoted 10 lines
include/power/pmic.h +8 -0
        struct list_head list;
 };
+#endif /* CONFIG_POWER */
+
+#ifdef CONFIG_DM_PMIC
+/**
+ * U-Boot PMIC Framework
+ * =====================
+ *
+ * UCLASS_PMIC - The is designed to provide an I/O interface for PMIC devices.

This is designed

include/power/pmic.h struct pmic { · line 96

Quoted 3 lines
include/power/pmic.h +3 -0
+ *
+ * For the multi-function PMIC devices, this can be used as parent I/O device
+ * for each IC's interface. Then, each children uses its parent for read/write.

each child

Quoted 9 lines
include/power/pmic.h +9 -0
+ *
+ * The driver model tree could look like this:
+ *
+ *_ root device
+ * |_ BUS 0 device (e.g. I2C0)                 - UCLASS_I2C/SPI/...
+ * | |_ PMIC device (READ/WRITE ops)           - UCLASS_PMIC
+ * |   |_ REGULATOR device (ldo/buck/... ops)  - UCLASS_REGULATOR
+ * |   |_ CHARGER device (charger ops)         - UCLASS_CHARGER (in the future)
+ * |   |_ MUIC device (microUSB connector ops) - UCLASS_MUIC    (in the future)

include/power/pmic.h struct pmic { · line 115

Quoted 10 lines
include/power/pmic.h +10 -0
+ * |   |_ ...
+ * |
+ * |_ BUS 1 device (e.g. I2C1)                 - UCLASS_I2C/SPI/...
+ *   |_ PMIC device (READ/WRITE ops)           - UCLASS_PMIC
+ *     |_ RTC device (rtc ops)                 - UCLASS_RTC     (in the future)
+ *
+ * We can find two PMIC cases in boards design:
+ * - single I/O interface
+ * - multiple I/O interfaces
+ * We bind single PMIC device for each interface, to provide an I/O as a parent,

a single

Quoted 9 lines
include/power/pmic.h +9 -0
+ * of proper child devices. Each child usually implements a different function,
+ * controlled by the same interface.
+ *
+ * The binding should be done automatically. If device tree nodes/subnodes are
+ * proper defined, then:
+ *
+ * |_ the ROOT driver will bind the device for I2C/SPI node:
+ *   |_ the I2C/SPI driver should bind a device for pmic node:
+ *     |_ the PMIC driver should bind devices for its childs:

include/power/pmic.h struct pmic { · line 134

Quoted 10 lines
include/power/pmic.h +10 -0
+ *       |_ regulator (child)
+ *       |_ charger   (child)
+ *       |_ other     (child)
+ *
+ * The same for other device nodes, for multi-interface PMIC.
+ *
+ * Note:
+ * Each PMIC interface driver should use a different compatible string.
+ *
+ * If each pmic child device driver need access the PMIC-specific registers,

If a pmic child device driver needs

include/power/pmic.h struct pmic { · line 144

Quoted 10 lines
include/power/pmic.h +10 -0
+ * it need know only the register address and the access can be done through
+ * the parent pmic driver. Like in the example:
+ *
+ *_ root driver
+ * |_ dev: bus I2C0                                         - UCLASS_I2C
+ * | |_ dev: my_pmic (read/write)              (is parent)  - UCLASS_PMIC
+ * |   |_ dev: my_regulator (set value/etc..)  (is child)   - UCLASS_REGULATOR
+ *
+ * To ensure such device relationship, the pmic device driver should also bind
+ * all its child devices, like in the example below. It should be done by call

by calling pmic_bind_childs()

(which you should rename to pmic_bind_children() I think)

Quoted 10 lines
include/power/pmic.h +10 -0
+ * the 'pmic_bind_childs()' - please refer to the description of this function
+ * in this header file. This function, should be called in the driver's '.bind'
+ * method.
+ *
+ * For the example driver, please refer the MAX77686 driver:
+ * - 'drivers/power/pmic/max77686.c'
+ */
+
+/**
+ * struct dm_pmic_ops - PMIC device I/O interface

include/power/pmic.h struct pmic { · line 164

Quoted 10 lines
include/power/pmic.h +10 -0
+ *
+ * Should be implemented by UCLASS_PMIC device drivers. The standard
+ * device operations provides the I/O interface for it's childs.
+ *
+ * @reg_count: devices register count
+ * @read:      read 'len' bytes at "reg" and store it into the 'buffer'
+ * @write:     write 'len' bytes from the 'buffer' to the register at 'reg' address
+ */
+struct dm_pmic_ops {
+       int reg_count;

This should not be in ops as it is not an operation. Perhaps add a function for it, or put it in the uclass platform data?

include/power/pmic.h struct pmic { · line 170

Quoted 6 lines
include/power/pmic.h +6 -0
+       int (*read)(struct udevice *dev, uint reg, uint8_t *buffer, int len);
+       int (*write)(struct udevice *dev, uint reg, const uint8_t *buffer,
+                    int len);
+};
+
+/* enum pmic_op_type - used for various pmic devices operation calls,

/**
* enum pmic_op_type -

Quoted 50 lines
include/power/pmic.h +50 -0
+ * for reduce a number of lines with the same code for read/write or get/set.
+ *
+ * @PMIC_OP_GET - get operation
+ * @PMIC_OP_SET - set operation
+*/
+enum pmic_op_type {
+       PMIC_OP_GET,
+       PMIC_OP_SET,
+};
+
+/**
+ * struct pmic_child_info - basic device's child info for bind child nodes with
+ * the driver by the node name prefix and driver name. This is a helper struct
+ * for function: pmic_bind_childs().
+ *
+ * @prefix - child node name prefix (or its name if is unique or single)
+ * @driver - driver name for the sub-node with prefix
+ */
+struct pmic_child_info {
+       const char *prefix;
+       const char *driver;
+};
+
+/* drivers/power/pmic-uclass.c */
+
+/**
+ * pmic_bind_childs() - bind drivers for given parent pmic, using child info
+ * found in 'child_info' array.
+ *
+ * @pmic       - pmic device - the parent of found child's
+ * @child_info - N-childs info array
+ * @return a positive number of childs, or 0 if no child found (error)
+ *
+ * Note: For N-childs the child_info array should have N+1 entries and the last
+ * entry prefix should be NULL - the same as for drivers compatible.
+ *
+ * For example, a single prefix info (N=1):
+ * static const struct pmic_child_info bind_info[] = {
+ *     { .prefix = "ldo", .driver = "ldo_driver" },
+ *     { },
+ * };
+ *
+ * This function is useful for regulator sub-nodes:
+ * my_regulator at 0xa {
+ *     reg = <0xa>;
+ *     (pmic - bind automatically by compatible)
+ *     compatible = "my_pmic";
+ *     ...
+ *     (pmic's childs - bind by pmic_bind_childs())
+ *     (nodes prefix: "ldo", driver: "my_regulator_ldo")

include/power/pmic.h struct pmic { · line 230

Quoted 10 lines
include/power/pmic.h +10 -0
+ *     ldo1 { ... };
+ *     ldo2 { ... };
+ *
+ *     (nodes prefix: "buck", driver: "my_regulator_buck")
+ *     buck1 { ... };
+ *     buck2 { ... };
+ * };
+ */
+int pmic_bind_childs(struct udevice *pmic, int offset,
+                    const struct pmic_child_info *child_info);

pmic_bind_children

Quoted 50 lines
include/power/pmic.h +38 -1
+
+/**
+ * pmic_get: get the pmic device using its name
+ *
+ * @name - device name
+ * @devp - returned pointer to the pmic device
+ * @return 0 on success or negative value of errno.
+ *
+ * The returned devp device can be used with pmic_read/write calls
+ */
+int pmic_get(const char *name, struct udevice **devp);
+
+/**
+ * pmic_reg_count: get the pmic register count
+ *
+ * The required pmic device can be obtained by 'pmic_get()'
+ *
+ * @dev - pointer to the UCLASS_PMIC device
+ * @return register count value on success or negative value of errno.
+ */
+int pmic_reg_count(struct udevice *dev);
+
+/**
+ * pmic_read/write: read/write to the UCLASS_PMIC device
+ *
+ * The required pmic device can be obtained by 'pmic_get()'
+ *
+ * @pmic   - pointer to the UCLASS_PMIC device
+ * @reg    - device register offset
+ * @buffer - pointer to read/write buffer
+ * @len    - byte count for read/write
+ * @return 0 on success or negative value of errno.
+ */
+int pmic_read(struct udevice *dev, uint reg, uint8_t *buffer, int len);
+int pmic_write(struct udevice *dev, uint reg, const uint8_t *buffer, int len);
+#endif /* CONFIG_DM_PMIC */
 
+#ifdef CONFIG_POWER
 int pmic_init(unsigned char bus);
 int power_init_board(void);
 int pmic_dialog_init(unsigned char bus);
@@ -88,6 +276,7 @@ int pmic_probe(struct pmic *p);
 int pmic_reg_read(struct pmic *p, u32 reg, u32 *val);
 int pmic_reg_write(struct pmic *p, u32 reg, u32 val);
 int pmic_set_output(struct pmic *p, u32 reg, int ldo, int on);
+#endif
 
 #define pmic_i2c_addr (p->hw.i2c.addr)
 #define pmic_i2c_tx_num (p->hw.i2c.tx_num)
--
Quoted 2 lines

1.9.1

Regards,
Simon

#161 lore raw

PATCH v4 4/16 dm: pmic: add implementation of driver model pmic uclass

Quoted 64 lines · Simon Glass

Hi Przemyslaw,

Quoted 50 lines · Przemyslaw Marczak

This commit introduces the PMIC uclass implementation. It allows providing the basic I/O interface for PMIC devices. For the multi-function PMIC devices, this can be used as I/O parent device, for each IC's interface. Then, each PMIC particular function can be provided by the child device's operations, and the child devices will use its parent for read/write by the common API.

Core files:
- 'include/power/pmic.h'
- 'drivers/power/pmic/pmic-uclass.c'

The old pmic framework is still kept and is independent.

For more detailed informations, please look into the header file.

Changes:
- new uclass-id: UCLASS_PMIC
- new config: CONFIG_DM_PMIC

---
Changes V2:
- pmic uclass: adjust uclass code to the mainline changes
- pmic uclass: remove pmic_i2c and pmic_spi
- pmic uclass: modify pmic_platdata
- pmic uclass: add pmic_if_* functions
- pmic uclass: remove pmic_init_dm()
- pmic uclass: cleanup
- pmic.h: define pmic ops structure (read/write operations)
- pmic.h: add comments to functions

Changes V3:
- pmic-uclass.c and pmic.h:
-- remove pmic_if_* functions
-- add new function pmic_child_node_scan()
- add Kconfig entry

Changes V4:
- move drivers/power/pmic-uclass.c to drivers/power/pmic/pmic-uclass.c
- move DM_PMIC Kconfig entry: drivers/power/Kconfig to drivers/power/pmic/Kconfig
- drivers/power/Kconfig: Add menu "Power" and include pmic Kconfig
- Kconfig: provide only the general information about the PMIC
- pmic-uclass.c: add pmic_bind_childs()
- pmic-uclass.c: add debug
- pmic-uclass.c: cleanup includes
- pmic-uclass.c: remove pmic_get_uclass_ops() and use of dev_get_driver_ops()
- pmic-uclass.c: use of uclass_get_device_by_name()
- pmic-uclass.c: add str_get_num() - for get number from string
- include/power/pmic.h - start comments rewording
- power/pmic.h: comments update

Quoted 10 lines
---
 drivers/power/Kconfig            |   6 ++
 drivers/power/pmic/Kconfig       |  11 +++
 drivers/power/pmic/Makefile      |   1 +
 drivers/power/pmic/pmic-uclass.c | 158 ++++++++++++++++++++++++++++++++
 include/dm/uclass-id.h           |   3 +
 include/power/pmic.h             | 189 +++++++++++++++++++++++++++++++++++++++
 6 files changed, 368 insertions(+)
 create mode 100644 drivers/power/pmic/Kconfig
 create mode 100644 drivers/power/pmic/pmic-uclass.c
Quoted 5 lines

I have a few nits below - perhaps they can be targeted in a follow-up patch or two? I'd like to merge this soon and it is not worth holding up the series for nits.

Applied to u-boot-dm/next, thanks!

#162 lore raw

PATCH v4 4/16 dm: pmic: add implementation of driver model pmic uclass

In reply to Simon Glass

Hello Simon,

Quoted 64 lines · Simon Glass

Hi Przemyslaw,

Quoted 58 lines · Przemyslaw Marczak

This commit introduces the PMIC uclass implementation. It allows providing the basic I/O interface for PMIC devices. For the multi-function PMIC devices, this can be used as I/O parent device, for each IC's interface. Then, each PMIC particular function can be provided by the child device's operations, and the child devices will use its parent for read/write by the common API.

Core files:
- 'include/power/pmic.h'
- 'drivers/power/pmic/pmic-uclass.c'

The old pmic framework is still kept and is independent.

For more detailed informations, please look into the header file.

Changes:
- new uclass-id: UCLASS_PMIC
- new config: CONFIG_DM_PMIC

---
Changes V2:
- pmic uclass: adjust uclass code to the mainline changes
- pmic uclass: remove pmic_i2c and pmic_spi
- pmic uclass: modify pmic_platdata
- pmic uclass: add pmic_if_* functions
- pmic uclass: remove pmic_init_dm()
- pmic uclass: cleanup
- pmic.h: define pmic ops structure (read/write operations)
- pmic.h: add comments to functions

Changes V3:
- pmic-uclass.c and pmic.h:
-- remove pmic_if_* functions
-- add new function pmic_child_node_scan()
- add Kconfig entry

Changes V4:
- move drivers/power/pmic-uclass.c to drivers/power/pmic/pmic-uclass.c
- move DM_PMIC Kconfig entry: drivers/power/Kconfig to drivers/power/pmic/Kconfig
- drivers/power/Kconfig: Add menu "Power" and include pmic Kconfig
- Kconfig: provide only the general information about the PMIC
- pmic-uclass.c: add pmic_bind_childs()
- pmic-uclass.c: add debug
- pmic-uclass.c: cleanup includes
- pmic-uclass.c: remove pmic_get_uclass_ops() and use of dev_get_driver_ops()
- pmic-uclass.c: use of uclass_get_device_by_name()
- pmic-uclass.c: add str_get_num() - for get number from string
- include/power/pmic.h - start comments rewording
- power/pmic.h: comments update

---
  drivers/power/Kconfig            |   6 ++
  drivers/power/pmic/Kconfig       |  11 +++
  drivers/power/pmic/Makefile      |   1 +
  drivers/power/pmic/pmic-uclass.c | 158 ++++++++++++++++++++++++++++++++
  include/dm/uclass-id.h           |   3 +
  include/power/pmic.h             | 189 +++++++++++++++++++++++++++++++++++++++
  6 files changed, 368 insertions(+)
Quoted 2 lines

create mode 100644 drivers/power/pmic/Kconfig create mode 100644 drivers/power/pmic/pmic-uclass.c

Quoted 6 lines

I have a few nits below - perhaps they can be targeted in a follow-up patch or two? I'd like to merge this soon and it is not worth holding up the series for nits.

That's good information. I will fix it all and resend ASAP.

Quoted 358 lines
Quoted 156 lines
drivers/power/Kconfig +6 -0
index f8f0239..d03626e 100644
@@ -1,3 +1,7 @@
+menu "Power"
+
+source "drivers/power/pmic/Kconfig"
+
  config AXP221_POWER
         boolean "axp221 / axp223 pmic support"
         depends on MACH_SUN6I || MACH_SUN8I
@@ -73,3 +77,5 @@ config AXP221_ELDO3_VOLT
         disable eldo3. On some A31(s) tablets it might be used to supply
         1.2V for the SSD2828 chip (converter of parallel LCD interface
         into MIPI DSI).
+
+endmenu
drivers/power/pmic/Kconfig new file +11 -0
new file mode 100644
index 0000000..d06d632
@@ -0,0 +1,11 @@
+config DM_PMIC
+       bool "Enable Driver Model for PMIC drivers (UCLASS_PMIC)"
+       depends on DM
+       ---help---
+       This config enables the driver-model PMIC support.
+       UCLASS_PMIC - designed to provide an I/O interface for PMIC devices.
+       For the multi-function PMIC devices, this can be used as parent I/O
+       device for each IC's interface. Then, each children uses its parent
+       for read/write. For detailed description, please refer to the files:
+       - 'drivers/power/pmic/pmic-uclass.c'
+       - 'include/power/pmic.h'
drivers/power/pmic/Makefile +1 -0
index 985cfdb..594f620 100644
@@ -5,6 +5,7 @@
  # SPDX-License-Identifier:     GPL-2.0+
  #
 
+obj-$(CONFIG_DM_PMIC) += pmic-uclass.o
  obj-$(CONFIG_POWER_LTC3676) += pmic_ltc3676.o
  obj-$(CONFIG_POWER_MAX8998) += pmic_max8998.o
  obj-$(CONFIG_POWER_MAX8997) += pmic_max8997.o
drivers/power/pmic/pmic-uclass.c new file +102 -0
new file mode 100644
index 0000000..d82d3da
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2014-2015 Samsung Electronics
+ * Przemyslaw Marczak <[email protected]>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <fdtdec.h>
+#include <errno.h>
+#include <dm.h>
+#include <dm/lists.h>
+#include <dm/device-internal.h>
+#include <dm/uclass-internal.h>
+#include <power/pmic.h>
+#include <linux/ctype.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static ulong str_get_num(const char *ptr, const char *maxptr)
+{
+       if (!ptr || !maxptr)
+               return 0;
+
+       while (!isdigit(*ptr) && ptr++ < maxptr);
+
+       return simple_strtoul(ptr, NULL, 0);
+}
+
+int pmic_bind_childs(struct udevice *pmic, int offset,
+                    const struct pmic_child_info *child_info)
+{
+       const struct pmic_child_info *info;
+       const void *blob = gd->fdt_blob;
+       struct driver *drv;
+       struct udevice *child;
+       const char *node_name;
+       int node_name_len;
+       int bind_count = 0;
+       int node;
+       int prefix_len;
+       int ret;
+
+       debug("%s for '%s' at node offset: %d\n", __func__, pmic->name,
+             pmic->of_offset);
+
+       for (node = fdt_first_subnode(blob, offset);
+            node > 0;
+            node = fdt_next_subnode(blob, node)) {
+               node_name = fdt_get_name(blob, node, &node_name_len);
+
+               debug("* Found child node: '%s' at offset:%d\n", node_name,
+                                                                node);
+
+               child = NULL;
+               info = child_info;
+               while (info->prefix) {
+                       prefix_len = strlen(info->prefix);
+                       if (strncasecmp(info->prefix, node_name, prefix_len) ||
+                           !info->driver) {
+                               info++;
+                               continue;
+                       }
+
+                       debug("  - compatible prefix: '%s'\n", info->prefix);
+
+                       drv = lists_driver_lookup_name(info->driver);
+                       if (!drv) {
+                               debug("  - driver: '%s' not found!\n",
+                                     info->driver);
+                               continue;
+                       }
+
+                       debug("  - found child driver: '%s'\n", drv->name);
+
+                       ret = device_bind(pmic, drv, node_name, NULL,
+                                         node, &child);
+                       if (ret) {
+                               debug("  - child binding error: %d\n", ret);
+                               continue;
+                       }
+
+                       debug("  - bound child device: '%s'\n", child->name);
+
+                       child->driver_data = str_get_num(node_name +
+                                                        prefix_len,
+                                                        node_name +
+                                                        node_name_len);
+
+                       debug("  - set 'child->driver_data': %lu\n",
+                             child->driver_data);
+                       break;
+               }
+
+               if (child)
+                       bind_count++;
+               else
+                       debug("  - compatible prefix not found\n");
+       }
+
+       debug("Bound: %d childs for PMIC: '%s'\n", bind_count, pmic->name);
+       return bind_count;

drivers/power/pmic/pmic-uclass.c line 112

Quoted 10 lines
drivers/power/pmic/pmic-uclass.c new file +10 -0
+}
+
+int pmic_get(const char *name, struct udevice **devp)
+{
+       return uclass_get_device_by_name(UCLASS_PMIC, name, devp);
+}
+
+int pmic_reg_count(struct udevice *dev)
+{
+       const struct dm_pmic_ops *ops = dev_get_driver_ops(dev);

blank line here

Quoted 73 lines
drivers/power/pmic/pmic-uclass.c new file +46 -0
+       if (!ops)
+               return -ENOSYS;
+
+       return ops->reg_count;
+}
+
+int pmic_read(struct udevice *dev, uint reg, uint8_t *buffer, int len)
+{
+       const struct dm_pmic_ops *ops = dev_get_driver_ops(dev);
+       int ret;
+
+       if (!buffer)
+               return -EFAULT;
+
+       if (!ops || !ops->read)
+               return -ENOSYS;
+
+       ret = ops->read(dev, reg, buffer, len);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+int pmic_write(struct udevice *dev, uint reg, const uint8_t *buffer, int len)
+{
+       const struct dm_pmic_ops *ops = dev_get_driver_ops(dev);
+       int ret;
+
+       if (!buffer)
+               return -EFAULT;
+
+       if (!ops || !ops->write)
+               return -ENOSYS;
+
+       ret = ops->write(dev, reg, buffer, len);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+UCLASS_DRIVER(pmic) = {
+       .id             = UCLASS_PMIC,
+       .name           = "pmic",
+};
include/dm/uclass-id.h +3 -0
index fddfd35..23b3eb9 100644
@@ -46,6 +46,9 @@ enum uclass_id {
         UCLASS_USB_DEV_GENERIC, /* USB generic device */
         UCLASS_MASS_STORAGE,    /* Mass storage device */
 
+       /* Power Management */
+       UCLASS_PMIC,            /* PMIC I/O device */
+
         UCLASS_COUNT,
         UCLASS_INVALID = -1,
  };
include/power/pmic.h +3 -0
index afbc5aa..f7ae781 100644
@@ -1,4 +1,7 @@
  /*
+ *  Copyright (C) 2014-2015 Samsung Electronics
+ *  Przemyslaw Marczak <[email protected]>
+ *
   *  Copyright (C) 2011-2012 Samsung Electronics
   *  Lukasz Majewski <[email protected]>
   *

include/power/pmic.h line 17

Quoted 6 lines
include/power/pmic.h +1 -0
@@ -9,10 +12,13 @@
  #define __CORE_PMIC_H_
 
  #include <linux/list.h>
+#include <spi.h>
  #include <i2c.h>
  #include <power/power_chrg.h>

At some point can you update the ordering of this lot? I think it should be:

i2c.g
spi.h
linux/
power/

Quoted 9 lines
include/power/pmic.h +2 -0
  enum { PMIC_I2C, PMIC_SPI, PMIC_NONE};
+
+#ifdef CONFIG_POWER
  enum { I2C_PMIC, I2C_NUM, };
  enum { PMIC_READ, PMIC_WRITE, };
  enum { PMIC_SENSOR_BYTE_ORDER_LITTLE, PMIC_SENSOR_BYTE_ORDER_BIG, };
@@ -77,7 +83,189 @@ struct pmic {
         struct pmic *parent;

include/power/pmic.h struct pmic { · line 93

Quoted 10 lines
include/power/pmic.h +8 -0
         struct list_head list;
  };
+#endif /* CONFIG_POWER */
+
+#ifdef CONFIG_DM_PMIC
+/**
+ * U-Boot PMIC Framework
+ * =====================
+ *
+ * UCLASS_PMIC - The is designed to provide an I/O interface for PMIC devices.

This is designed

include/power/pmic.h struct pmic { · line 96

Quoted 3 lines
include/power/pmic.h +3 -0
+ *
+ * For the multi-function PMIC devices, this can be used as parent I/O device
+ * for each IC's interface. Then, each children uses its parent for read/write.

each child

Quoted 9 lines
include/power/pmic.h +9 -0
+ *
+ * The driver model tree could look like this:
+ *
+ *_ root device
+ * |_ BUS 0 device (e.g. I2C0)                 - UCLASS_I2C/SPI/...
+ * | |_ PMIC device (READ/WRITE ops)           - UCLASS_PMIC
+ * |   |_ REGULATOR device (ldo/buck/... ops)  - UCLASS_REGULATOR
+ * |   |_ CHARGER device (charger ops)         - UCLASS_CHARGER (in the future)
+ * |   |_ MUIC device (microUSB connector ops) - UCLASS_MUIC    (in the future)

include/power/pmic.h struct pmic { · line 115

Quoted 10 lines
include/power/pmic.h +10 -0
+ * |   |_ ...
+ * |
+ * |_ BUS 1 device (e.g. I2C1)                 - UCLASS_I2C/SPI/...
+ *   |_ PMIC device (READ/WRITE ops)           - UCLASS_PMIC
+ *     |_ RTC device (rtc ops)                 - UCLASS_RTC     (in the future)
+ *
+ * We can find two PMIC cases in boards design:
+ * - single I/O interface
+ * - multiple I/O interfaces
+ * We bind single PMIC device for each interface, to provide an I/O as a parent,

a single

Quoted 9 lines
include/power/pmic.h +9 -0
+ * of proper child devices. Each child usually implements a different function,
+ * controlled by the same interface.
+ *
+ * The binding should be done automatically. If device tree nodes/subnodes are
+ * proper defined, then:
+ *
+ * |_ the ROOT driver will bind the device for I2C/SPI node:
+ *   |_ the I2C/SPI driver should bind a device for pmic node:
+ *     |_ the PMIC driver should bind devices for its childs:

include/power/pmic.h struct pmic { · line 134

Quoted 10 lines
include/power/pmic.h +10 -0
+ *       |_ regulator (child)
+ *       |_ charger   (child)
+ *       |_ other     (child)
+ *
+ * The same for other device nodes, for multi-interface PMIC.
+ *
+ * Note:
+ * Each PMIC interface driver should use a different compatible string.
+ *
+ * If each pmic child device driver need access the PMIC-specific registers,

If a pmic child device driver needs

include/power/pmic.h struct pmic { · line 144

Quoted 10 lines
include/power/pmic.h +10 -0
+ * it need know only the register address and the access can be done through
+ * the parent pmic driver. Like in the example:
+ *
+ *_ root driver
+ * |_ dev: bus I2C0                                         - UCLASS_I2C
+ * | |_ dev: my_pmic (read/write)              (is parent)  - UCLASS_PMIC
+ * |   |_ dev: my_regulator (set value/etc..)  (is child)   - UCLASS_REGULATOR
+ *
+ * To ensure such device relationship, the pmic device driver should also bind
+ * all its child devices, like in the example below. It should be done by call

by calling pmic_bind_childs()

(which you should rename to pmic_bind_children() I think)

Quoted 15 lines
include/power/pmic.h +15 -0
+ * the 'pmic_bind_childs()' - please refer to the description of this function
+ * in this header file. This function, should be called in the driver's '.bind'
+ * method.
+ *
+ * For the example driver, please refer the MAX77686 driver:
+ * - 'drivers/power/pmic/max77686.c'
+ */
+
+/**
+ * struct dm_pmic_ops - PMIC device I/O interface
+ *
+ * Should be implemented by UCLASS_PMIC device drivers. The standard
+ * device operations provides the I/O interface for it's childs.
+ *
+ * @reg_count: devices register count
Quoted 9 lines

include/power/pmic.h struct pmic { · line 164

Quoted 5 lines
include/power/pmic.h +5 -0
+ * @read:      read 'len' bytes at "reg" and store it into the 'buffer'
+ * @write:     write 'len' bytes from the 'buffer' to the register at 'reg' address
+ */
+struct dm_pmic_ops {
+       int reg_count;

This should not be in ops as it is not an operation. Perhaps add a function for it, or put it in the uclass platform data?

Adding this to uclass platform data will add another problem - choosing the right place for setting this value, because it's usually not given in dts, however the device node "reg" property could also provide the address length as it is for the memory.
But probably you will agree, that this is a job for I2C/SPI subsystem, and moreover has no sense, since usually the dts files don't provide the "reg" property as "<reg length>" for i2c/spi devices.

So maybe putting here an 'ops' function is better idea. int (*get_reg_count)(struct udevice *dev);

This is used only for the PMIC command, so if return -ENOSYS, then just "dump" command will no available for the device.

Quoted 120 lines

include/power/pmic.h struct pmic { · line 170

Quoted 6 lines
include/power/pmic.h +6 -0
+       int (*read)(struct udevice *dev, uint reg, uint8_t *buffer, int len);
+       int (*write)(struct udevice *dev, uint reg, const uint8_t *buffer,
+                    int len);
+};
+
+/* enum pmic_op_type - used for various pmic devices operation calls,

/**
* enum pmic_op_type -

Quoted 50 lines
include/power/pmic.h +50 -0
+ * for reduce a number of lines with the same code for read/write or get/set.
+ *
+ * @PMIC_OP_GET - get operation
+ * @PMIC_OP_SET - set operation
+*/
+enum pmic_op_type {
+       PMIC_OP_GET,
+       PMIC_OP_SET,
+};
+
+/**
+ * struct pmic_child_info - basic device's child info for bind child nodes with
+ * the driver by the node name prefix and driver name. This is a helper struct
+ * for function: pmic_bind_childs().
+ *
+ * @prefix - child node name prefix (or its name if is unique or single)
+ * @driver - driver name for the sub-node with prefix
+ */
+struct pmic_child_info {
+       const char *prefix;
+       const char *driver;
+};
+
+/* drivers/power/pmic-uclass.c */
+
+/**
+ * pmic_bind_childs() - bind drivers for given parent pmic, using child info
+ * found in 'child_info' array.
+ *
+ * @pmic       - pmic device - the parent of found child's
+ * @child_info - N-childs info array
+ * @return a positive number of childs, or 0 if no child found (error)
+ *
+ * Note: For N-childs the child_info array should have N+1 entries and the last
+ * entry prefix should be NULL - the same as for drivers compatible.
+ *
+ * For example, a single prefix info (N=1):
+ * static const struct pmic_child_info bind_info[] = {
+ *     { .prefix = "ldo", .driver = "ldo_driver" },
+ *     { },
+ * };
+ *
+ * This function is useful for regulator sub-nodes:
+ * my_regulator at 0xa {
+ *     reg = <0xa>;
+ *     (pmic - bind automatically by compatible)
+ *     compatible = "my_pmic";
+ *     ...
+ *     (pmic's childs - bind by pmic_bind_childs())
+ *     (nodes prefix: "ldo", driver: "my_regulator_ldo")

include/power/pmic.h struct pmic { · line 230

Quoted 10 lines
include/power/pmic.h +10 -0
+ *     ldo1 { ... };
+ *     ldo2 { ... };
+ *
+ *     (nodes prefix: "buck", driver: "my_regulator_buck")
+ *     buck1 { ... };
+ *     buck2 { ... };
+ * };
+ */
+int pmic_bind_childs(struct udevice *pmic, int offset,
+                    const struct pmic_child_info *child_info);

pmic_bind_children

Quoted 47 lines
include/power/pmic.h +38 -0
+
+/**
+ * pmic_get: get the pmic device using its name
+ *
+ * @name - device name
+ * @devp - returned pointer to the pmic device
+ * @return 0 on success or negative value of errno.
+ *
+ * The returned devp device can be used with pmic_read/write calls
+ */
+int pmic_get(const char *name, struct udevice **devp);
+
+/**
+ * pmic_reg_count: get the pmic register count
+ *
+ * The required pmic device can be obtained by 'pmic_get()'
+ *
+ * @dev - pointer to the UCLASS_PMIC device
+ * @return register count value on success or negative value of errno.
+ */
+int pmic_reg_count(struct udevice *dev);
+
+/**
+ * pmic_read/write: read/write to the UCLASS_PMIC device
+ *
+ * The required pmic device can be obtained by 'pmic_get()'
+ *
+ * @pmic   - pointer to the UCLASS_PMIC device
+ * @reg    - device register offset
+ * @buffer - pointer to read/write buffer
+ * @len    - byte count for read/write
+ * @return 0 on success or negative value of errno.
+ */
+int pmic_read(struct udevice *dev, uint reg, uint8_t *buffer, int len);
+int pmic_write(struct udevice *dev, uint reg, const uint8_t *buffer, int len);
+#endif /* CONFIG_DM_PMIC */
 
+#ifdef CONFIG_POWER
  int pmic_init(unsigned char bus);
  int power_init_board(void);
  int pmic_dialog_init(unsigned char bus);
@@ -88,6 +276,7 @@ int pmic_probe(struct pmic *p);
  int pmic_reg_read(struct pmic *p, u32 reg, u32 *val);
  int pmic_reg_write(struct pmic *p, u32 reg, u32 val);
  int pmic_set_output(struct pmic *p, u32 reg, int ldo, int on);
+#endif
 
Quoted 9 lines
Quoted 5 lines
include/power/pmic.h +0 -1
  #define pmic_i2c_addr (p->hw.i2c.addr)
  #define pmic_i2c_tx_num (p->hw.i2c.tx_num)
--

1.9.1

Regards,
Simon

Thanks for the review.

Best regards,

Signature · 4 lines
Przemyslaw Marczak
Samsung R&D Institute Poland
Samsung Electronics
p.marczak at samsung.com
#163 lore raw

PATCH v4 4/16 dm: pmic: add implementation of driver model pmic uclass

Hi Przemyslaw,

Quoted 501 lines · Przemyslaw Marczak

Hello Simon,

Quoted 71 lines · Simon Glass

Hi Przemyslaw,

Quoted 62 lines · Przemyslaw Marczak

This commit introduces the PMIC uclass implementation. It allows providing the basic I/O interface for PMIC devices. For the multi-function PMIC devices, this can be used as I/O parent device, for each IC's interface. Then, each PMIC particular function can be provided by the child device's operations, and the child devices will use its parent for read/write by the common API.

Core files:
- 'include/power/pmic.h'
- 'drivers/power/pmic/pmic-uclass.c'

The old pmic framework is still kept and is independent.

For more detailed informations, please look into the header file.

Changes:
- new uclass-id: UCLASS_PMIC
- new config: CONFIG_DM_PMIC

---
Changes V2:
- pmic uclass: adjust uclass code to the mainline changes
- pmic uclass: remove pmic_i2c and pmic_spi
- pmic uclass: modify pmic_platdata
- pmic uclass: add pmic_if_* functions
- pmic uclass: remove pmic_init_dm()
- pmic uclass: cleanup
- pmic.h: define pmic ops structure (read/write operations)
- pmic.h: add comments to functions

Changes V3:
- pmic-uclass.c and pmic.h:
-- remove pmic_if_* functions
-- add new function pmic_child_node_scan()
- add Kconfig entry

Changes V4:
- move drivers/power/pmic-uclass.c to drivers/power/pmic/pmic-uclass.c
- move DM_PMIC Kconfig entry: drivers/power/Kconfig to drivers/power/pmic/Kconfig
- drivers/power/Kconfig: Add menu "Power" and include pmic Kconfig
- Kconfig: provide only the general information about the PMIC
- pmic-uclass.c: add pmic_bind_childs()
- pmic-uclass.c: add debug
- pmic-uclass.c: cleanup includes
- pmic-uclass.c: remove pmic_get_uclass_ops() and use of dev_get_driver_ops()
- pmic-uclass.c: use of uclass_get_device_by_name()
- pmic-uclass.c: add str_get_num() - for get number from string
- include/power/pmic.h - start comments rewording
- power/pmic.h: comments update

---
  drivers/power/Kconfig            |   6 ++
  drivers/power/pmic/Kconfig       |  11 +++
  drivers/power/pmic/Makefile      |   1 +
  drivers/power/pmic/pmic-uclass.c | 158 ++++++++++++++++++++++++++++++++
  include/dm/uclass-id.h           |   3 +
  include/power/pmic.h             | 189
+++++++++++++++++++++++++++++++++++++++
  6 files changed, 368 insertions(+)
Quoted 2 lines

create mode 100644 drivers/power/pmic/Kconfig create mode 100644 drivers/power/pmic/pmic-uclass.c

Quoted 6 lines

I have a few nits below - perhaps they can be targeted in a follow-up patch or two? I'd like to merge this soon and it is not worth holding up the series for nits.

That's good information. I will fix it all and resend ASAP.

Quoted 398 lines
Quoted 168 lines
drivers/power/Kconfig +6 -0
index f8f0239..d03626e 100644
@@ -1,3 +1,7 @@
+menu "Power"
+
+source "drivers/power/pmic/Kconfig"
+
  config AXP221_POWER
         boolean "axp221 / axp223 pmic support"
         depends on MACH_SUN6I || MACH_SUN8I
@@ -73,3 +77,5 @@ config AXP221_ELDO3_VOLT
         disable eldo3. On some A31(s) tablets it might be used to supply
         1.2V for the SSD2828 chip (converter of parallel LCD interface
         into MIPI DSI).
+
+endmenu
drivers/power/pmic/Kconfig new file +6 -0
new file mode 100644
index 0000000..d06d632
@@ -0,0 +1,11 @@
+config DM_PMIC
+       bool "Enable Driver Model for PMIC drivers (UCLASS_PMIC)"
+       depends on DM
+       ---help---
+       This config enables the driver-model PMIC support.
+       UCLASS_PMIC - designed to provide an I/O interface for PMIC

devices.
+ For the multi-function PMIC devices, this can be used as parent
I/O
+ device for each IC's interface. Then, each children uses its
parent
+ for read/write. For detailed description, please refer to the
files:

drivers/power/pmic/Kconfig new file +2 -0
+       - 'drivers/power/pmic/pmic-uclass.c'
+       - 'include/power/pmic.h'
drivers/power/pmic/Makefile +1 -0
index 985cfdb..594f620 100644
@@ -5,6 +5,7 @@
  # SPDX-License-Identifier:     GPL-2.0+
  #
 
+obj-$(CONFIG_DM_PMIC) += pmic-uclass.o
  obj-$(CONFIG_POWER_LTC3676) += pmic_ltc3676.o
  obj-$(CONFIG_POWER_MAX8998) += pmic_max8998.o
  obj-$(CONFIG_POWER_MAX8997) += pmic_max8997.o
drivers/power/pmic/pmic-uclass.c new file +52 -0
new file mode 100644
index 0000000..d82d3da
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2014-2015 Samsung Electronics
+ * Przemyslaw Marczak <[email protected]>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <fdtdec.h>
+#include <errno.h>
+#include <dm.h>
+#include <dm/lists.h>
+#include <dm/device-internal.h>
+#include <dm/uclass-internal.h>
+#include <power/pmic.h>
+#include <linux/ctype.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static ulong str_get_num(const char *ptr, const char *maxptr)
+{
+       if (!ptr || !maxptr)
+               return 0;
+
+       while (!isdigit(*ptr) && ptr++ < maxptr);
+
+       return simple_strtoul(ptr, NULL, 0);
+}
+
+int pmic_bind_childs(struct udevice *pmic, int offset,
+                    const struct pmic_child_info *child_info)
+{
+       const struct pmic_child_info *info;
+       const void *blob = gd->fdt_blob;
+       struct driver *drv;
+       struct udevice *child;
+       const char *node_name;
+       int node_name_len;
+       int bind_count = 0;
+       int node;
+       int prefix_len;
+       int ret;
+
+       debug("%s for '%s' at node offset: %d\n", __func__, pmic->name,
+             pmic->of_offset);
+
+       for (node = fdt_first_subnode(blob, offset);
+            node > 0;
+            node = fdt_next_subnode(blob, node)) {
+               node_name = fdt_get_name(blob, node, &node_name_len);
+
+               debug("* Found child node: '%s' at offset:%d\n",

node_name,

drivers/power/pmic/pmic-uclass.c new file +7 -0
+                                                                node);
+
+               child = NULL;
+               info = child_info;
+               while (info->prefix) {
+                       prefix_len = strlen(info->prefix);
+                       if (strncasecmp(info->prefix, node_name,

prefix_len) ||

drivers/power/pmic/pmic-uclass.c new file +6 -0
+                           !info->driver) {
+                               info++;
+                               continue;
+                       }
+
+                       debug("  - compatible prefix: '%s'\n",

info->prefix);

drivers/power/pmic/pmic-uclass.c new file +9 -0
+
+                       drv = lists_driver_lookup_name(info->driver);
+                       if (!drv) {
+                               debug("  - driver: '%s' not found!\n",
+                                     info->driver);
+                               continue;
+                       }
+
+                       debug("  - found child driver: '%s'\n",

drv->name);

drivers/power/pmic/pmic-uclass.c new file +5 -0
+
+                       ret = device_bind(pmic, drv, node_name, NULL,
+                                         node, &child);
+                       if (ret) {
+                               debug("  - child binding error: %d\n",

ret);

drivers/power/pmic/pmic-uclass.c new file +4 -0
+                               continue;
+                       }
+
+                       debug("  - bound child device: '%s'\n",

child->name);

drivers/power/pmic/pmic-uclass.c new file +18 -0
+
+                       child->driver_data = str_get_num(node_name +
+                                                        prefix_len,
+                                                        node_name +
+                                                        node_name_len);
+
+                       debug("  - set 'child->driver_data': %lu\n",
+                             child->driver_data);
+                       break;
+               }
+
+               if (child)
+                       bind_count++;
+               else
+                       debug("  - compatible prefix not found\n");
+       }
+
+       debug("Bound: %d childs for PMIC: '%s'\n", bind_count,

pmic->name);

drivers/power/pmic/pmic-uclass.c new file +1 -0
+       return bind_count;

drivers/power/pmic/pmic-uclass.c line 112

Quoted 10 lines
drivers/power/pmic/pmic-uclass.c new file +10 -0
+}
+
+int pmic_get(const char *name, struct udevice **devp)
+{
+       return uclass_get_device_by_name(UCLASS_PMIC, name, devp);
+}
+
+int pmic_reg_count(struct udevice *dev)
+{
+       const struct dm_pmic_ops *ops = dev_get_driver_ops(dev);

blank line here

Quoted 74 lines
drivers/power/pmic/pmic-uclass.c new file +25 -0
+       if (!ops)
+               return -ENOSYS;
+
+       return ops->reg_count;
+}
+
+int pmic_read(struct udevice *dev, uint reg, uint8_t *buffer, int len)
+{
+       const struct dm_pmic_ops *ops = dev_get_driver_ops(dev);
+       int ret;
+
+       if (!buffer)
+               return -EFAULT;
+
+       if (!ops || !ops->read)
+               return -ENOSYS;
+
+       ret = ops->read(dev, reg, buffer, len);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+int pmic_write(struct udevice *dev, uint reg, const uint8_t *buffer, int

len)

drivers/power/pmic/pmic-uclass.c new file +21 -0
+{
+       const struct dm_pmic_ops *ops = dev_get_driver_ops(dev);
+       int ret;
+
+       if (!buffer)
+               return -EFAULT;
+
+       if (!ops || !ops->write)
+               return -ENOSYS;
+
+       ret = ops->write(dev, reg, buffer, len);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+UCLASS_DRIVER(pmic) = {
+       .id             = UCLASS_PMIC,
+       .name           = "pmic",
+};
include/dm/uclass-id.h +3 -0
index fddfd35..23b3eb9 100644
@@ -46,6 +46,9 @@ enum uclass_id {
         UCLASS_USB_DEV_GENERIC, /* USB generic device */
         UCLASS_MASS_STORAGE,    /* Mass storage device */
 
+       /* Power Management */
+       UCLASS_PMIC,            /* PMIC I/O device */
+
         UCLASS_COUNT,
         UCLASS_INVALID = -1,
  };
include/power/pmic.h +3 -0
index afbc5aa..f7ae781 100644
@@ -1,4 +1,7 @@
  /*
+ *  Copyright (C) 2014-2015 Samsung Electronics
+ *  Przemyslaw Marczak <[email protected]>
+ *
   *  Copyright (C) 2011-2012 Samsung Electronics
   *  Lukasz Majewski <[email protected]>
   *

include/power/pmic.h line 17

Quoted 6 lines
include/power/pmic.h +1 -0
@@ -9,10 +12,13 @@
  #define __CORE_PMIC_H_
 
  #include <linux/list.h>
+#include <spi.h>
  #include <i2c.h>
  #include <power/power_chrg.h>

At some point can you update the ordering of this lot? I think it should be:

i2c.g
spi.h
linux/
power/

Quoted 19 lines
include/power/pmic.h +10 -0
  enum { PMIC_I2C, PMIC_SPI, PMIC_NONE};
+
+#ifdef CONFIG_POWER
  enum { I2C_PMIC, I2C_NUM, };
  enum { PMIC_READ, PMIC_WRITE, };
  enum { PMIC_SENSOR_BYTE_ORDER_LITTLE, PMIC_SENSOR_BYTE_ORDER_BIG, };
@@ -77,7 +83,189 @@ struct pmic {
         struct pmic *parent;
         struct list_head list;
  };
+#endif /* CONFIG_POWER */
+
+#ifdef CONFIG_DM_PMIC
+/**
+ * U-Boot PMIC Framework
+ * =====================
+ *
+ * UCLASS_PMIC - The is designed to provide an I/O interface for PMIC
Quoted 1 line

devices.

This is designed

Quoted 5 lines

+ *
+ * For the multi-function PMIC devices, this can be used as parent I/O device
+ * for each IC's interface. Then, each children uses its parent for read/write.

each child

Quoted 14 lines

+ *
+ * The driver model tree could look like this:
+ *
+ *_ root device

+ * |_ BUS 0 device (e.g. I2C0)                 - UCLASS_I2C/SPI/...
+ * | |_ PMIC device (READ/WRITE ops)           - UCLASS_PMIC
+ * |   |_ REGULATOR device (ldo/buck/... ops)  - UCLASS_REGULATOR
+ * |   |_ CHARGER device (charger ops)         - UCLASS_CHARGER (in the
future)
+ * |   |_ MUIC device (microUSB connector ops) - UCLASS_MUIC    (in the
future)
+ * |   |_ ...
+ * |
+ * |_ BUS 1 device (e.g. I2C1)                 - UCLASS_I2C/SPI/...
Quoted 9 lines

+ * |_ PMIC device (READ/WRITE ops) - UCLASS_PMIC
+ * |_ RTC device (rtc ops) - UCLASS_RTC (in the
future)
+ *
+ * We can find two PMIC cases in boards design:
+ * - single I/O interface
+ * - multiple I/O interfaces
+ * We bind single PMIC device for each interface, to provide an I/O as a parent,

a single

Quoted 14 lines

+ * of proper child devices. Each child usually implements a different function,
+ * controlled by the same interface.
+ *
+ * The binding should be done automatically. If device tree nodes/subnodes are
+ * proper defined, then:
+ *
+ * |_ the ROOT driver will bind the device for I2C/SPI node:
+ * |_ the I2C/SPI driver should bind a device for pmic node:
+ * |_ the PMIC driver should bind devices for its childs:

+ *       |_ regulator (child)
+ *       |_ charger   (child)
+ *       |_ other     (child)
Quoted 8 lines

+ *
+ * The same for other device nodes, for multi-interface PMIC.
+ *
+ * Note:
+ * Each PMIC interface driver should use a different compatible string.
+ *
+ * If each pmic child device driver need access the PMIC-specific registers,

If a pmic child device driver needs

Quoted 7 lines

+ * it need know only the register address and the access can be done through
+ * the parent pmic driver. Like in the example:
+ *
+ *_ root driver

+ * |_ dev: bus I2C0                                         - UCLASS_I2C
+ * | |_ dev: my_pmic (read/write)              (is parent)  -
Quoted 8 lines

UCLASS_PMIC
+ * | |_ dev: my_regulator (set value/etc..) (is child) -
UCLASS_REGULATOR
+ *
+ * To ensure such device relationship, the pmic device driver should also bind
+ * all its child devices, like in the example below. It should be done by call

by calling pmic_bind_childs()

(which you should rename to pmic_bind_children() I think)

Quoted 19 lines

+ * the 'pmic_bind_childs()' - please refer to the description of this function
+ * in this header file. This function, should be called in the driver's '.bind'
+ * method.
+ *
+ * For the example driver, please refer the MAX77686 driver:
+ * - 'drivers/power/pmic/max77686.c'
+ */

include/power/pmic.h +10 -0
+
+/**
+ * struct dm_pmic_ops - PMIC device I/O interface
+ *
+ * Should be implemented by UCLASS_PMIC device drivers. The standard
+ * device operations provides the I/O interface for it's childs.
+ *
+ * @reg_count: devices register count
+ * @read:      read 'len' bytes at "reg" and store it into the 'buffer'
+ * @write:     write 'len' bytes from the 'buffer' to the register at
Quoted 9 lines

include/power/pmic.h struct pmic { · line 164

Quoted 4 lines

'reg' address
+ */

include/power/pmic.h +2 -0
+struct dm_pmic_ops {
+       int reg_count;

This should not be in ops as it is not an operation. Perhaps add a function for it, or put it in the uclass platform data?

Adding this to uclass platform data will add another problem - choosing the right place for setting this value, because it's usually not given in dts, however the device node "reg" property could also provide the address length as it is for the memory.
But probably you will agree, that this is a job for I2C/SPI subsystem, and moreover has no sense, since usually the dts files don't provide the "reg" property as "<reg length>" for i2c/spi devices.

Quoted 5 lines

So maybe putting here an 'ops' function is better idea. int (*get_reg_count)(struct udevice *dev);

This is used only for the PMIC command, so if return -ENOSYS, then just "dump" command will no available for the device.

Yes I think turning this value into a function is fine. I just don't think we should have values in the operations struct.

Quoted 132 lines
Quoted 132 lines

include/power/pmic.h struct pmic { · line 170

Quoted 10 lines

+ int (*read)(struct udevice *dev, uint reg, uint8_t *buffer, int
len);
+ int (*write)(struct udevice *dev, uint reg, const uint8_t
*buffer,

include/power/pmic.h +4 -0
+                    int len);
+};
+
+/* enum pmic_op_type - used for various pmic devices operation calls,

/**
* enum pmic_op_type -

Quoted 63 lines

+ * for reduce a number of lines with the same code for read/write or get/set.
+ *
+ * @PMIC_OP_GET - get operation
+ * @PMIC_OP_SET - set operation

include/power/pmic.h +8 -0
+*/
+enum pmic_op_type {
+       PMIC_OP_GET,
+       PMIC_OP_SET,
+};
+
+/**
+ * struct pmic_child_info - basic device's child info for bind child

nodes with
+ * the driver by the node name prefix and driver name. This is a helper struct
+ * for function: pmic_bind_childs().
+ *
+ * @prefix - child node name prefix (or its name if is unique or single)
+ * @driver - driver name for the sub-node with prefix
+ */

include/power/pmic.h +9 -0
+struct pmic_child_info {
+       const char *prefix;
+       const char *driver;
+};
+
+/* drivers/power/pmic-uclass.c */
+
+/**
+ * pmic_bind_childs() - bind drivers for given parent pmic, using child

info
+ * found in 'child_info' array.
+ *
+ * @pmic - pmic device - the parent of found child's
+ * @child_info - N-childs info array
+ * @return a positive number of childs, or 0 if no child found (error)
+ *
+ * Note: For N-childs the child_info array should have N+1 entries and the last
+ * entry prefix should be NULL - the same as for drivers compatible.
+ *
+ * For example, a single prefix info (N=1):
+ * static const struct pmic_child_info bind_info[] = {
+ * { .prefix = "ldo", .driver = "ldo_driver" },
+ * { },
+ * };
+ *
+ * This function is useful for regulator sub-nodes:
+ * my_regulator at 0xa {

+ *     reg = <0xa>;
+ *     (pmic - bind automatically by compatible)
+ *     compatible = "my_pmic";
+ *     ...
+ *     (pmic's childs - bind by pmic_bind_childs())
+ *     (nodes prefix: "ldo", driver: "my_regulator_ldo")
+ *     ldo1 { ... };
+ *     ldo2 { ... };
+ *
+ *     (nodes prefix: "buck", driver: "my_regulator_buck")
+ *     buck1 { ... };
+ *     buck2 { ... };

+ * };
+ */

include/power/pmic.h struct pmic { · line 230

Quoted 2 lines
include/power/pmic.h +2 -0
+int pmic_bind_childs(struct udevice *pmic, int offset,
+                    const struct pmic_child_info *child_info);

pmic_bind_children

Quoted 48 lines
include/power/pmic.h +35 -0
+
+/**
+ * pmic_get: get the pmic device using its name
+ *
+ * @name - device name
+ * @devp - returned pointer to the pmic device
+ * @return 0 on success or negative value of errno.
+ *
+ * The returned devp device can be used with pmic_read/write calls
+ */
+int pmic_get(const char *name, struct udevice **devp);
+
+/**
+ * pmic_reg_count: get the pmic register count
+ *
+ * The required pmic device can be obtained by 'pmic_get()'
+ *
+ * @dev - pointer to the UCLASS_PMIC device
+ * @return register count value on success or negative value of errno.
+ */
+int pmic_reg_count(struct udevice *dev);
+
+/**
+ * pmic_read/write: read/write to the UCLASS_PMIC device
+ *
+ * The required pmic device can be obtained by 'pmic_get()'
+ *
+ * @pmic   - pointer to the UCLASS_PMIC device
+ * @reg    - device register offset
+ * @buffer - pointer to read/write buffer
+ * @len    - byte count for read/write
+ * @return 0 on success or negative value of errno.
+ */
+int pmic_read(struct udevice *dev, uint reg, uint8_t *buffer, int len);
+int pmic_write(struct udevice *dev, uint reg, const uint8_t *buffer, int

len);

include/power/pmic.h +3 -0
+#endif /* CONFIG_DM_PMIC */
 
+#ifdef CONFIG_POWER
  int pmic_init(unsigned char bus);
  int power_init_board(void);
  int pmic_dialog_init(unsigned char bus);
@@ -88,6 +276,7 @@ int pmic_probe(struct pmic *p);
  int pmic_reg_read(struct pmic *p, u32 reg, u32 *val);
  int pmic_reg_write(struct pmic *p, u32 reg, u32 val);
  int pmic_set_output(struct pmic *p, u32 reg, int ldo, int on);
+#endif
 
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
include/power/pmic.h +0 -1
  #define pmic_i2c_addr (p->hw.i2c.addr)
  #define pmic_i2c_tx_num (p->hw.i2c.tx_num)
--

1.9.1

Regards,
Simon

#164 lore raw

PATCH v4 5/16 dm: regulator: add implementation of driver model regulator uclass

In reply to Przemyslaw Marczak

This commit introduces the implementation of dm regulator API. Device tree support allows for auto binding. And by the basic uclass operations, it allows to driving the devices in a common way. For detailed informations, please look into the header file.

Core files:
- drivers/power/regulator-uclass.c - provides regulator common functions api
- include/power/regulator.h - define all structures required by the regulator

Changes:
- new uclass-id: UCLASS_REGULATOR
- new config: CONFIG_DM_REGULATOR

---
Changes V2:
- new operations for regulator uclass:
-- get/set output state - for output on/off setting --- add enum: REGULATOR_OFF, REGULATOR_ON

- regulator uclass code rework and cleanup:
-- change name of:
--- enum 'regulator_desc_type' to 'regulator_type' --- add type DVS
--- struct 'regulator_desc' to 'regulator_value_desc'

-- regulator ops function calls:
--- remove 'ldo/buck' from naming
--- add new argument 'type' for define regulator type

-- regulator.h - update comments

Changes V3:
- regulator-uclass.c and regulator.h:
-- api cleanup
-- new function regulator_ofdata_to_platdata()
-- update of comments
-- add Kconfig

Changes V4:
- move file drivers/power/regulator-uclass.c to drivers/power/regulator/regulator-uclass.c
- move DM_REGULATOR Kconfig entry from: drivers/power/Kconfig to drivers/power/regulator/Kconfig
- drivers/power/Kconfig: include regulator Kconfig path
- Kconfig: provide only general informations
- regulator-uclass.c: cleanup
- regulator-uclass.c: allow init regulator with name only
- regulator-uclass.c: remove pmic_get_uclass_ops and use dev_get_driver_ops
- regulator-uclass.c: add use of uclass_get_device_by_name()
- regulator.h: add 'struct dm_regulator_uclass_platdata'
- regulator.h: API documentation cleanup
- regulator - add binding info

---
 Makefile                                         |   3 +-
 doc/device-tree-bindings/regulator/regulator.txt |  55 ++++
 drivers/power/Kconfig                            |   2 +
 drivers/power/regulator/Kconfig                  |  17 +
 drivers/power/regulator/Makefile                 |   8 +
 drivers/power/regulator/regulator-uclass.c       | 300 ++++++++++++++++++
 include/dm/uclass-id.h                           |   1 +
 include/power/regulator.h                        | 384 +++++++++++++++++++++++
 8 files changed, 769 insertions(+), 1 deletion(-)
 create mode 100644 doc/device-tree-bindings/regulator/regulator.txt
 create mode 100644 drivers/power/regulator/Kconfig
 create mode 100644 drivers/power/regulator/Makefile
 create mode 100644 drivers/power/regulator/regulator-uclass.c
 create mode 100644 include/power/regulator.h
Makefile +2 -1
index dc25f70..dfb0d56 100644
@@ -645,7 +645,8 @@ libs-y += drivers/power/ \
 	drivers/power/fuel_gauge/ \
 	drivers/power/mfd/ \
 	drivers/power/pmic/ \
-	drivers/power/battery/
+	drivers/power/battery/ \
+	drivers/power/regulator/
 libs-y += drivers/spi/
 libs-$(CONFIG_FMAN_ENET) += drivers/net/fm/
 libs-$(CONFIG_SYS_FSL_DDR) += drivers/ddr/fsl/
doc/device-tree-bindings/regulator/regulator.txt new file +55 -0

55 lines not on this page · raw message

drivers/power/Kconfig +2 -0
index d03626e..23cdd71 100644
@@ -2,6 +2,8 @@ menu "Power"
 
 source "drivers/power/pmic/Kconfig"
 
+source "drivers/power/regulator/Kconfig"
+
 config AXP221_POWER
 	boolean "axp221 / axp223 pmic support"
 	depends on MACH_SUN6I || MACH_SUN8I
drivers/power/regulator/Kconfig new file +17 -0
new file mode 100644
index 0000000..cb15162
@@ -0,0 +1,17 @@
+config DM_REGULATOR
+	bool "Enable Driver Model for REGULATOR drivers (UCLASS_REGULATOR)"
+	depends on DM
+	---help---
+	This config enables the driver model regulator support.
+	UCLASS_REGULATOR - designed to provide a common API for basic regulator's
+	functions, like get/set Voltage or Current value, enable state, etc...
+	Note:
+	When enabling this, please read the description, found in the files:
+	- 'include/power/pmic.h'
+	- 'include/power/regulator.h'
+	- 'drivers/power/pmic/pmic-uclass.c'
+	- 'drivers/power/pmic/regulator-uclass.c'
+	It's important to call the device_bind() with the proper node offset,
+	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.
drivers/power/regulator/Makefile new file +8 -0
new file mode 100644
index 0000000..27c9006
@@ -0,0 +1,8 @@
+#
+# Copyright (C) 2015 Samsung Electronics
+# Przemyslaw Marczak <[email protected]>
+#
+# SPDX-License-Identifier:     GPL-2.0+
+#
+
+obj-$(CONFIG_DM_REGULATOR) += regulator-uclass.o
drivers/power/regulator/regulator-uclass.c new file +300 -0

300 lines not on this page · raw message

include/dm/uclass-id.h +1 -0
index 23b3eb9..3c572d7 100644
@@ -48,6 +48,7 @@ enum uclass_id {
 
 	/* Power Management */
 	UCLASS_PMIC,		/* PMIC I/O device */
+	UCLASS_REGULATOR,	/* REGULATOR device */
 
 	UCLASS_COUNT,
 	UCLASS_INVALID = -1,
include/power/regulator.h new file +384 -0

384 lines not on this page · raw message

Signature · 1 line
1.9.1
#165 lore raw

PATCH v4 5/16 dm: regulator: add implementation of driver model regulator uclass

Hi Przemyslaw,

Quoted 54 lines · Przemyslaw Marczak

This commit introduces the implementation of dm regulator API. Device tree support allows for auto binding. And by the basic uclass operations, it allows to driving the devices in a common way. For detailed informations, please look into the header file.

Core files:
- drivers/power/regulator-uclass.c - provides regulator common functions api
- include/power/regulator.h - define all structures required by the regulator

Changes:
- new uclass-id: UCLASS_REGULATOR
- new config: CONFIG_DM_REGULATOR

---
Changes V2:
- new operations for regulator uclass:
-- get/set output state - for output on/off setting --- add enum: REGULATOR_OFF, REGULATOR_ON

- regulator uclass code rework and cleanup:
-- change name of:
--- enum 'regulator_desc_type' to 'regulator_type' --- add type DVS
--- struct 'regulator_desc' to 'regulator_value_desc'

-- regulator ops function calls:
--- remove 'ldo/buck' from naming
--- add new argument 'type' for define regulator type

-- regulator.h - update comments

Changes V3:
- regulator-uclass.c and regulator.h:
-- api cleanup
-- new function regulator_ofdata_to_platdata()
-- update of comments
-- add Kconfig

Changes V4:
- move file drivers/power/regulator-uclass.c to drivers/power/regulator/regulator-uclass.c
- move DM_REGULATOR Kconfig entry from: drivers/power/Kconfig to drivers/power/regulator/Kconfig
- drivers/power/Kconfig: include regulator Kconfig path
- Kconfig: provide only general informations
- regulator-uclass.c: cleanup
- regulator-uclass.c: allow init regulator with name only
- regulator-uclass.c: remove pmic_get_uclass_ops and use dev_get_driver_ops
- regulator-uclass.c: add use of uclass_get_device_by_name()
- regulator.h: add 'struct dm_regulator_uclass_platdata'
- regulator.h: API documentation cleanup
- regulator - add binding info

Quoted 15 lines
---
 Makefile                                         |   3 +-
 doc/device-tree-bindings/regulator/regulator.txt |  55 ++++
 drivers/power/Kconfig                            |   2 +
 drivers/power/regulator/Kconfig                  |  17 +
 drivers/power/regulator/Makefile                 |   8 +
 drivers/power/regulator/regulator-uclass.c       | 300 ++++++++++++++++++
 include/dm/uclass-id.h                           |   1 +
 include/power/regulator.h                        | 384 +++++++++++++++++++++++
 8 files changed, 769 insertions(+), 1 deletion(-)
 create mode 100644 doc/device-tree-bindings/regulator/regulator.txt
 create mode 100644 drivers/power/regulator/Kconfig
 create mode 100644 drivers/power/regulator/Makefile
 create mode 100644 drivers/power/regulator/regulator-uclass.c
 create mode 100644 include/power/regulator.h

A few more nits for later.

Quoted 233 lines
Makefile +2 -1
index dc25f70..dfb0d56 100644
@@ -645,7 +645,8 @@ libs-y += drivers/power/ \
        drivers/power/fuel_gauge/ \
        drivers/power/mfd/ \
        drivers/power/pmic/ \
-       drivers/power/battery/
+       drivers/power/battery/ \
+       drivers/power/regulator/
 libs-y += drivers/spi/
 libs-$(CONFIG_FMAN_ENET) += drivers/net/fm/
 libs-$(CONFIG_SYS_FSL_DDR) += drivers/ddr/fsl/
doc/device-tree-bindings/regulator/regulator.txt new file +55 -0
new file mode 100644
index 0000000..249e0f5
@@ -0,0 +1,55 @@
+Voltage/Current regulator
+
+Binding:
+The regulator devices don't use the "compatible" property. The binding is done
+by the prefix of regulator node's name. Usually the pmic I/O driver will provide
+the array of 'struct pmic_child_info' with the prefixes and compatible drivers.
+The bind is done by calling function: pmic_bind_childs().
+Example drivers:
+pmic: drivers/power/pmic/max77686.c
+regulator: drivers/power/regulator/max77686.c
+
+For the node name e.g.: "prefix[:alpha:]num { ... }":
+- the driver prefix should be: "prefix" or "PREFIX" - case insensitive
+- the node name's "num" is set as "dev->driver_data" on bind
+
+Example the prefix "ldo" will pass for: "ldo1", "ldo at 1", "LDO1", "LDOREG at 1"...
+
+Required properties:
+- regulator-name: a string, required by the regulator uclass
+
+Note
+The "regulator-name" constraint is used for setting the device's uclass
+platform data '.name' field. And the regulator device name is set from
+it's node name.
+
+Optional properties:
+- regulator-min-microvolt: a minimum allowed Voltage value
+- regulator-max-microvolt: a maximum allowed Voltage value
+- regulator-min-microamp: a minimum allowed Current value
+- regulator-max-microamp: a maximum allowed Current value
+- regulator-always-on: regulator should never be disabled
+- regulator-boot-on: enabled by bootloader/firmware
+
+Other kernel-style properties, are currently not used.
+
+Note:
+For the regulator autoset from constraints, the framework expects that:
+- regulator-min-microvolt is equal to regulator-max-microvolt
+- regulator-min-microamp is equal to regulator-max-microamp
+- regulator-always-on or regulator-boot-on is set
+
+Example:
+ldo0 {
+       /* Mandatory */
+       regulator-name = "VDDQ_EMMC_1.8V";
+
+       /* Optional */
+       regulator-min-microvolt = <1800000>;
+       regulator-max-microvolt = <1800000>;
+       regulator-min-microamp = <100000>;
+       regulator-max-microamp = <100000>;
+       regulator-always-on;
+       regulator-boot-on;
+};
+
drivers/power/Kconfig +2 -0
index d03626e..23cdd71 100644
@@ -2,6 +2,8 @@ menu "Power"
 
 source "drivers/power/pmic/Kconfig"
 
+source "drivers/power/regulator/Kconfig"
+
 config AXP221_POWER
        boolean "axp221 / axp223 pmic support"
        depends on MACH_SUN6I || MACH_SUN8I
drivers/power/regulator/Kconfig new file +17 -0
new file mode 100644
index 0000000..cb15162
@@ -0,0 +1,17 @@
+config DM_REGULATOR
+       bool "Enable Driver Model for REGULATOR drivers (UCLASS_REGULATOR)"
+       depends on DM
+       ---help---
+       This config enables the driver model regulator support.
+       UCLASS_REGULATOR - designed to provide a common API for basic regulator's
+       functions, like get/set Voltage or Current value, enable state, etc...
+       Note:
+       When enabling this, please read the description, found in the files:
+       - 'include/power/pmic.h'
+       - 'include/power/regulator.h'
+       - 'drivers/power/pmic/pmic-uclass.c'
+       - 'drivers/power/pmic/regulator-uclass.c'
+       It's important to call the device_bind() with the proper node offset,
+       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.
drivers/power/regulator/Makefile new file +8 -0
new file mode 100644
index 0000000..27c9006
@@ -0,0 +1,8 @@
+#
+# Copyright (C) 2015 Samsung Electronics
+# Przemyslaw Marczak <[email protected]>
+#
+# SPDX-License-Identifier:     GPL-2.0+
+#
+
+obj-$(CONFIG_DM_REGULATOR) += regulator-uclass.o
drivers/power/regulator/regulator-uclass.c new file +101 -0
new file mode 100644
index 0000000..07ce286
@@ -0,0 +1,300 @@
+/*
+ * Copyright (C) 2014-2015 Samsung Electronics
+ * Przemyslaw Marczak <[email protected]>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+#include <common.h>
+#include <fdtdec.h>
+#include <errno.h>
+#include <dm.h>
+#include <dm/uclass-internal.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int regulator_mode(struct udevice *dev, struct dm_regulator_mode **modep)
+{
+       struct dm_regulator_uclass_platdata *uc_pdata;
+
+       *modep = NULL;
+
+       uc_pdata = dev_get_uclass_platdata(dev);
+       if (!uc_pdata)
+               return -ENXIO;
+
+       *modep = uc_pdata->mode;
+       return uc_pdata->mode_count;
+}
+
+int regulator_get_value(struct udevice *dev)
+{
+       const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
+
+       if (!ops || !ops->get_value)
+               return -ENOSYS;
+
+       return ops->get_value(dev);
+}
+
+int regulator_set_value(struct udevice *dev, int uV)
+{
+       const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
+
+       if (!ops || !ops->set_value)
+               return -ENOSYS;
+
+       return ops->set_value(dev, uV);
+}
+
+int regulator_get_current(struct udevice *dev)
+{
+       const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
+
+       if (!ops || !ops->get_current)
+               return -ENOSYS;
+
+       return ops->get_current(dev);
+}
+
+int regulator_set_current(struct udevice *dev, int uA)
+{
+       const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
+
+       if (!ops || !ops->set_current)
+               return -ENOSYS;
+
+       return ops->set_current(dev, uA);
+}
+
+bool regulator_get_enable(struct udevice *dev)
+{
+       const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
+
+       if (!ops || !ops->get_enable)
+               return -ENOSYS;
+
+       return ops->get_enable(dev);
+}
+
+int regulator_set_enable(struct udevice *dev, bool enable)
+{
+       const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
+
+       if (!ops || !ops->set_enable)
+               return -ENOSYS;
+
+       return ops->set_enable(dev, enable);
+}
+
+int regulator_get_mode(struct udevice *dev)
+{
+       const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
+
+       if (!ops || !ops->get_mode)
+               return -ENOSYS;
+
+       return ops->get_mode(dev);
+}
+
+int regulator_set_mode(struct udevice *dev, int mode)

drivers/power/regulator/regulator-uclass.c line 111

Quoted 10 lines
drivers/power/regulator/regulator-uclass.c new file +10 -0
+{
+       const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
+
+       if (!ops || !ops->set_mode)
+               return -ENOSYS;
+
+       return ops->set_mode(dev, mode);
+}
+
+int regulator_by_platname(const char *plat_name, struct udevice **devp)

regulator_get_by_platname()

since it does probe the device

Quoted 12 lines
drivers/power/regulator/regulator-uclass.c new file +12 -0
+{
+       struct dm_regulator_uclass_platdata *uc_pdata;
+       struct udevice *dev;
+
+       *devp = NULL;
+
+       for (uclass_find_first_device(UCLASS_REGULATOR, &dev);
+            dev;
+            uclass_find_next_device(&dev)) {
+               uc_pdata = dev_get_uclass_platdata(dev);
+               if (!uc_pdata || strcmp(plat_name, uc_pdata->name))
+                       continue;

drivers/power/regulator/regulator-uclass.c line 133

Quoted 10 lines
drivers/power/regulator/regulator-uclass.c new file +10 -0
+
+               return uclass_get_device_tail(dev, 0, devp);
+       }
+
+       debug("%s: can't find: %s\n", __func__, plat_name);
+
+       return -ENODEV;
+}
+
+int regulator_by_devname(const char *devname, struct udevice **devp)

regulator_get_by_devname

Quoted 7 lines
drivers/power/regulator/regulator-uclass.c new file +7 -0
+{
+       return uclass_get_device_by_name(UCLASS_REGULATOR, devname, devp);
+}
+
+static int setting_failed(int ret, bool verbose, const char *fmt, ...)
+{
+       va_list args;

drivers/power/regulator/regulator-uclass.c line 150

Quoted 10 lines
drivers/power/regulator/regulator-uclass.c new file +10 -0
+       char buf[64];
+
+       if (verbose == false)
+               return ret;
+
+       va_start(args, fmt);
+       vscnprintf(buf, sizeof(buf), fmt, args);
+       va_end(args);
+
+       printf(buf);

I wonder if we should have a vprintf() in U-Boot?

Quoted 6 lines
drivers/power/regulator/regulator-uclass.c new file +6 -0
+
+       if (!ret)
+               return 0;
+
+       printf(" (ret: %d)", ret);
+

drivers/power/regulator/regulator-uclass.c line 166

Quoted 10 lines
drivers/power/regulator/regulator-uclass.c new file +10 -0
+       return ret;
+}
+
+int regulator_by_platname_autoset_and_enable(const char *platname,
+                                            struct udevice **devp,
+                                            bool verbose)
+{
+       struct dm_regulator_uclass_platdata *uc_pdata;
+       struct udevice *dev;
+       bool v = verbose;

Can we drop this local var and just use 'verbose'

Quoted 48 lines
drivers/power/regulator/regulator-uclass.c new file +48 -0
+       int ret;
+
+       if (devp)
+               *devp = NULL;
+
+       ret = regulator_by_platname(platname, &dev);
+       if (ret) {
+               error("Can get the regulator: %s!", platname);
+               return ret;
+       }
+
+       uc_pdata = dev_get_uclass_platdata(dev);
+       if (!uc_pdata) {
+               error("Can get the regulator %s uclass platdata!", platname);
+               return -ENXIO;
+       }
+
+       if (v)
+               printf("%s@%s: ", dev->name, uc_pdata->name);
+
+       /* Those values are optional (-ENODATA if unset) */
+       if ((uc_pdata->min_uV != -ENODATA) &&
+           (uc_pdata->max_uV != -ENODATA) &&
+           (uc_pdata->min_uV == uc_pdata->max_uV)) {
+               ret = regulator_set_value(dev, uc_pdata->min_uV);
+               if (setting_failed(ret, v, "set %d uV", uc_pdata->min_uV))
+                       goto exit;
+       }
+
+       /* Those values are optional (-ENODATA if unset) */
+       if ((uc_pdata->min_uA != -ENODATA) &&
+           (uc_pdata->max_uA != -ENODATA) &&
+           (uc_pdata->min_uA == uc_pdata->max_uA)) {
+               ret = regulator_set_current(dev, uc_pdata->min_uA);
+               if (setting_failed(ret, v, "; set %d uA", uc_pdata->min_uA))
+                       goto exit;
+       }
+
+       if (!uc_pdata->always_on && !uc_pdata->boot_on)
+               goto retdev;
+
+       ret = regulator_set_enable(dev, true);
+       if (setting_failed(ret, v, "; enabling", uc_pdata->min_uA))
+               goto exit;
+
+retdev:
+       if (devp)
+               *devp = dev;

drivers/power/regulator/regulator-uclass.c line 224

Quoted 10 lines
drivers/power/regulator/regulator-uclass.c new file +10 -0
+exit:
+       if (v)
+               printf("\n");
+       return ret;
+}
+
+int regulator_by_platname_list_autoset_and_enable(const char *list_platname[],
+                                                 int list_entries,
+                                                 struct udevice *list_devp[],
+                                                 bool verbose)

I wonder if you could shorten this (e.g. to regulator_list_autoset())?

Quoted 6 lines
drivers/power/regulator/regulator-uclass.c new file +6 -0
+{
+       struct udevice *dev;
+       int i, ret, success = 0;
+
+       for (i = 0; i < list_entries; i++) {
+               ret = regulator_autoset(list_platname[i], &dev, verbose);

drivers/power/regulator/regulator-uclass.c line 240

Quoted 10 lines
drivers/power/regulator/regulator-uclass.c new file +10 -0
+               if (!ret)
+                       success++;
+
+               if (!list_devp)
+                       continue;
+
+               if (ret)
+                       list_devp[i] = NULL;
+               else
+                       list_devp[i] = dev;

Shouldn't dev be NULL if ret is non-zero anyway?

drivers/power/regulator/regulator-uclass.c line 243

Quoted 3 lines
drivers/power/regulator/regulator-uclass.c new file +3 -0
+       }
+
+       return (success != list_entries);

return success == list_entries ? 0 : -EIO

or something. Better would be to record the first error you get and return that.

Quoted 8 lines
drivers/power/regulator/regulator-uclass.c new file +8 -0
+}
+
+static int regulator_post_bind(struct udevice *dev)
+{
+       struct dm_regulator_uclass_platdata *uc_pdata;
+       int offset = dev->of_offset;
+       const void *blob = gd->fdt_blob;
+

drivers/power/regulator/regulator-uclass.c line 261

Quoted 10 lines
drivers/power/regulator/regulator-uclass.c new file +10 -0
+       uc_pdata = dev_get_uclass_platdata(dev);
+       if (!uc_pdata)
+               return -ENXIO;
+
+       /* Regulator's mandatory constraint */
+       uc_pdata->name = fdt_getprop(blob, offset, "regulator-name", NULL);
+       if (!uc_pdata->name) {
+               debug("%s: dev: %s has no property 'regulator-name'\n",
+                     __func__, dev->name);
+               return -ENXIO;

-EINVAL as it indicates invalid device tree data.

Quoted 93 lines
drivers/power/regulator/regulator-uclass.c new file +39 -0
+       }
+
+       return 0;
+}
+
+static int regulator_pre_probe(struct udevice *dev)
+{
+       struct dm_regulator_uclass_platdata *uc_pdata;
+       int offset = dev->of_offset;
+
+       uc_pdata = dev_get_uclass_platdata(dev);
+       if (!uc_pdata)
+               return -ENXIO;
+
+       /* Regulator's optional constraints */
+       uc_pdata->min_uV = fdtdec_get_int(gd->fdt_blob, offset,
+                                         "regulator-min-microvolt", -ENODATA);
+       uc_pdata->max_uV = fdtdec_get_int(gd->fdt_blob, offset,
+                                         "regulator-max-microvolt", -ENODATA);
+       uc_pdata->min_uA = fdtdec_get_int(gd->fdt_blob, offset,
+                                         "regulator-min-microamp", -ENODATA);
+       uc_pdata->max_uA = fdtdec_get_int(gd->fdt_blob, offset,
+                                         "regulator-max-microamp", -ENODATA);
+       uc_pdata->always_on = fdtdec_get_bool(gd->fdt_blob, offset,
+                                             "regulator-always-on");
+       uc_pdata->boot_on = fdtdec_get_bool(gd->fdt_blob, offset,
+                                           "regulator-boot-on");
+
+       return 0;
+}
+
+UCLASS_DRIVER(regulator) = {
+       .id             = UCLASS_REGULATOR,
+       .name           = "regulator",
+       .post_bind      = regulator_post_bind,
+       .pre_probe      = regulator_pre_probe,
+       .per_device_platdata_auto_alloc_size =
+                               sizeof(struct dm_regulator_uclass_platdata),
+};
include/dm/uclass-id.h +1 -0
index 23b3eb9..3c572d7 100644
@@ -48,6 +48,7 @@ enum uclass_id {
 
        /* Power Management */
        UCLASS_PMIC,            /* PMIC I/O device */
+       UCLASS_REGULATOR,       /* REGULATOR device */
 
        UCLASS_COUNT,
        UCLASS_INVALID = -1,
include/power/regulator.h new file +36 -0
new file mode 100644
index 0000000..0302c1d
@@ -0,0 +1,384 @@
+/*
+ *  Copyright (C) 2014-2015 Samsung Electronics
+ *  Przemyslaw Marczak <[email protected]>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef _INCLUDE_REGULATOR_H_
+#define _INCLUDE_REGULATOR_H_
+
+/**
+ * U-Boot Voltage/Current Regulator
+ * ================================
+ *
+ * The regulator API is based on a driver model, with the device tree support.
+ * And this header describes the functions and data types for the uclass id:
+ * 'UCLASS_REGULATOR' and the regulator driver API.
+ *
+ * The regulator uclass - is based on uclass platform data which is allocated,
+ * automatically for each regulator device on bind and 'dev->uclass_platdata'
+ * points to it. The data type is: 'struct dm_regulator_uclass_platdata'.
+ * The uclass file: 'drivers/power/regulator/regulator-uclass.c'
+ *
+ * The regulator device - is based on driver's model 'struct udevice'.
+ * The API can use regulator name in two meanings:
+ * - devname  - the regulator device's name: 'dev->name'
+ * - platname - the device's platdata's name. So in the code it looks like:
+ *              'uc_pdata = dev->uclass_platdata'; 'name = uc_pdata->name'.
+ *
+ * The regulator device driver - provide an implementation of uclass operations
+ * pointed by 'dev->driver->ops' as a struct of type 'struct dm_regulator_ops'.
+ *
+ * To proper bind the regulator device, the device tree node should provide
+ * regulator constraints, like in the example below:
+ *
+ * ldo1 {

include/power/regulator.h line 46

Quoted 10 lines
include/power/regulator.h new file +10 -0
+ *      regulator-name = "VDD_MMC_1.8V";     (mandatory for bind)
+ *      regulator-min-microvolt = <1000000>; (optional)
+ *      regulator-max-microvolt = <1000000>; (optional)
+ *      regulator-min-microamp = <1000>;     (optional)
+ *      regulator-max-microamp = <1000>;     (optional)
+ *      regulator-always-on;                 (optional)
+ *      regulator-boot-on;                   (optional)
+ * };
+ *
+ * Please take a notice, that for the proper operation at least name constraint

Please note that for the proper

or

Note: For the proper

include/power/regulator.h line 52

Quoted 6 lines
include/power/regulator.h new file +6 -0
+ * is needed, e.g. for call the device_by_platname(...).
+ *
+ * Regulator bind:
+ * For each regulator device, the device_bind() should be called with passed
+ * device tree offset. This is required for this uclass's '.post_bind' method,
+ * which do the scan on the device node, for the 'regulator-name' constraint.

s/do/does/

include/power/regulator.h line 58

Quoted 6 lines
include/power/regulator.h new file +6 -0
+ * If the parent is not a PMIC device, and the child is not bind by function:
+ * 'pmic_bind_childs()', then it's recommended to bind the device by call to
+ * dm_scan_fdt_node() - this is usually done automatically for bus devices,
+ * as a post bind method.
+ * Having the device's name constraint, we can call regulator_by_platname(),
+ * to find interesting regulator. Before return, the regulator is probed,

How about:

s/to find interesting regulator/to find the required regulator/

include/power/regulator.h line 67

Quoted 9 lines
include/power/regulator.h new file +9 -0
+ * and the rest of its constraints are put into the device's uclass platform
+ * data, by the uclass regulator '.pre_probe' method.
+ *
+ * For more info about PMIC bind, please refer to file: 'include/power/pmic.h'
+ *
+ * Note:
+ * Please do not use the device_bind_by_name() function, since it pass '-1' as
+ * device node offset - and the bind will fail on uclass .post_bind method,
+ * because of missing 'regulator-name' constraint.

Indeed. BTW I think i'm going to add a similar function which allows the node to be passed.

Quoted 211 lines
include/power/regulator.h new file +211 -0
+ *
+ *
+ * Fixed Voltage/Current Regulator
+ * ===============================
+ *
+ * When fixed voltage regulator is needed, then enable the config:
+ * - CONFIG_DM_REGULATOR_FIXED
+ *
+ * The driver file: 'drivers/power/regulator/fixed.c', provides basic support
+ * for control the GPIO, and return the device tree constraint values.
+ *
+ * To bind the fixed voltage regulator device, we usually use a 'simple-bus'
+ * node as a parent. And 'regulator-fixed' for the driver compatible. This is
+ * the same as in the kernel. The example node of fixed regulator:
+ *
+ * simple-bus {
+ *     compatible = "simple-bus";
+ *     #address-cells = <1>;
+ *     #size-cells = <0>;
+ *
+ *     blue_led {
+ *         compatible = "regulator-fixed";
+ *         regulator-name = "VDD_LED_3.3V";
+ *         regulator-min-microvolt = <3300000>;
+ *         regulator-max-microvolt = <3300000>;
+ *         gpio = <&gpc1 0 GPIO_ACTIVE_LOW>;
+ *     };
+ * };
+ *
+ * The fixed regulator devices also provide regulator uclass platform data. And
+ * devices bound from such node, can use the regulator drivers API.
+*/
+
+/* enum regulator_type - used for regulator_*() variant calls */
+enum regulator_type {
+       REGULATOR_TYPE_LDO = 0,
+       REGULATOR_TYPE_BUCK,
+       REGULATOR_TYPE_DVS,
+       REGULATOR_TYPE_FIXED,
+       REGULATOR_TYPE_OTHER,
+};
+
+/**
+ * struct dm_regulator_mode - this structure holds an information about
+ * each regulator operation mode. Probably in most cases - an array.
+ * This will be probably a driver-static data, since it is device-specific.
+ *
+ * @id             - a driver-specific mode id
+ * @register_value - a driver-specific value for its mode id
+ * @name           - the name of mode - used for regulator command
+ * Note:
+ * The field 'id', should be always a positive number, since the negative values
+ * are reserved for the errno numbers when returns the mode id.
+ */
+struct dm_regulator_mode {
+       int id; /* Set only as >= 0 (negative value is reserved for errno) */
+       int register_value;
+       const char *name;
+};
+
+/**
+ * struct dm_regulator_uclass_platdata - pointed by dev->uclass_platdata, and
+ * allocated on each regulator bind. This structure holds an information
+ * about each regulator's constraints and supported operation modes.
+ * There is no "step" voltage value - so driver should take care of this.
+ *
+ * @type       - one of 'enum regulator_type'
+ * @mode       - pointer to the regulator mode (array if more than one)
+ * @mode_count - number of '.mode' entries
+ * @min_uV*    - minimum voltage (micro Volts)
+ * @max_uV*    - maximum voltage (micro Volts)
+ * @min_uA*    - minimum amperage (micro Amps)
+ * @max_uA*    - maximum amperage (micro Amps)
+ * @always_on* - bool type, true or false
+ * @boot_on*   - bool type, true or false
+ * @name**     - fdt regulator name - should be taken from the device tree
+ *
+ * Note:
+ * *  - set automatically on device probe by the uclass's '.pre_probe' method.
+ * ** - set automatically on device bind by the uclass's '.post_bind' method.
+ * The constraints: type, mode, mode_count, can be set by device driver, e.g.
+ * by the driver '.probe' method.
+ */
+struct dm_regulator_uclass_platdata {
+       enum regulator_type type;
+       struct dm_regulator_mode *mode;
+       int mode_count;
+       int min_uV;
+       int max_uV;
+       int min_uA;
+       int max_uA;
+       bool always_on;
+       bool boot_on;
+       const char *name;
+};
+
+/* Regulator device operations */
+struct dm_regulator_ops {
+       /**
+        * The regulator output value function calls operates on a micro Volts.
+        *
+        * get/set_value - get/set output value of the given output number
+        * @dev          - regulator device
+        * Sets:
+        * @uV           - set the output value [micro Volts]
+        * Returns: output value [uV] on success or negative errno if fail.
+        */
+       int (*get_value)(struct udevice *dev);
+       int (*set_value)(struct udevice *dev, int uV);
+
+       /**
+        * The regulator output current function calls operates on a micro Amps.
+        *
+        * get/set_current - get/set output current of the given output number
+        * @dev            - regulator device
+        * Sets:
+        * @uA           - set the output current [micro Amps]
+        * Returns: output value [uA] on success or negative errno if fail.
+        */
+       int (*get_current)(struct udevice *dev);
+       int (*set_current)(struct udevice *dev, int uA);
+
+       /**
+        * The most basic feature of the regulator output is its enable state.
+        *
+        * get/set_enable - get/set enable state of the given output number
+        * @dev           - regulator device
+        * Sets:
+        * @enable         - set true - enable or false - disable
+        * Returns: 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
+        * specific mode definitions, which should be found in:
+        * field 'mode' of struct mode_desc.
+        *
+        * get/set_mode - get/set operation mode of the given output number
+        * @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.
+        * Note:
+        * The field 'id' of struct type 'dm_regulator_mode', should be always
+        * positive number, since the negative is reserved for the error.
+        */
+       int (*get_mode)(struct udevice *dev);
+       int (*set_mode)(struct udevice *dev, int mode_id);
+};
+
+/**
+ * regulator_mode: returns a pointer to the array of regulator mode info
+ *
+ * @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.
+ */
+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.
+ */
+int regulator_get_value(struct udevice *dev);
+
+/**
+ * regulator_set_value: set the microvoltage value of a given regulator.
+ *
+ * @dev    - pointer to the regulator device
+ * @uV     - the output value to set [micro Volts]
+ * Returns - 0 on success or -errno val if fails
+ */
+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.
+ */
+int regulator_get_current(struct udevice *dev);
+
+/**
+ * regulator_set_current: set the microampere value of a given regulator.
+ *
+ * @dev    - pointer to the regulator device
+ * @uA     - set the output current [micro Amps]
+ * Returns - 0 on success or -errno val if fails
+ */
+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
+ */
+bool regulator_get_enable(struct udevice *dev);
+
+/**
+ * regulator_set_enable: set regulator enable state
+ *
+ * @dev    - pointer to the regulator device
+ * @enable - set true or false
+ * Returns - 0 on success or -errno val if fails
+ */
+int regulator_set_enable(struct udevice *dev, bool enable);

include/power/regulator.h line 288

Quoted 10 lines
include/power/regulator.h new file +10 -0
+
+/**
+ * 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
+ * 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'
+ * for this purpose and register_value for a raw register value.

Can you please reword the first sentence? I don't understand what it is trying to say. Similar below.

Quoted 32 lines
include/power/regulator.h new file +32 -0
+ */
+int regulator_get_mode(struct udevice *dev);
+
+/**
+ * regulator_set_mode: set given regulator mode
+ *
+ * @dev    - pointer to the regulator device
+ * @mode   - mode type (field 'mode' of struct mode_desc)
+ * Returns - 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
+ * a mode field for this purpose and register_value for a raw register value.
+ */
+int regulator_set_mode(struct udevice *dev, int mode);
+
+/**
+ * regulator_by_platname_autoset_and_enable: setup the regulator given by
+ * its uclass's platform data '.name'. The setup depends on constraints found
+ * 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
+ *
+ * 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.
+ *
+ * The returned 'regulator' device can be used with:

include/power/regulator.h line 330

Quoted 10 lines
include/power/regulator.h new file +10 -0
+ * - regulator_get/set_*
+ * For shorter call name, the below macro regulator_autoset() can be used.
+ */
+int regulator_by_platname_autoset_and_enable(const char *platname,
+                                            struct udevice **devp,
+                                            bool verbose);
+
+#define regulator_autoset(platname, devp, verbose) \
+       regulator_by_platname_autoset_and_enable(platname, devp, verbose)
+

Can we just use the shorter name for the function and avoid this #ifdef?

include/power/regulator.h line 343

Quoted 13 lines
include/power/regulator.h new file +13 -0
+/**
+ * regulator_by_platname_list_autoset_and_enable: setup the regulators given by
+ * list of its uclass's platform data '.name'. The setup depends on constraints
+ * found in device's uclass's platform data. The function loops with calls to:
+ * regulator_by_platname_autoset_and_enable() for each name of list.
+ *
+ * @list_platname - an array of expected strings for .name field of each
+ *                  regulator's uclass platdata
+ * @list_entries  - number of regulator's name list entries
+ * @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.

otherwise

include/power/regulator.h line 356

Quoted 13 lines
include/power/regulator.h new file +13 -0
+ *
+ * The returned 'regulator' devices can be used with:
+ * - regulator_get/set_*
+ * For shorter call name, the below macro regulator_list_autoset() can be used.
+ */
+int regulator_by_platname_list_autoset_and_enable(const char *list_platname[],
+                                                 int list_entries,
+                                                 struct udevice *list_devp[],
+                                                 bool verbose);
+
+#define regulator_list_autoset(namelist, entries, devlist, verbose)      \
+       regulator_by_platname_list_autoset_and_enable(namelist, entries, \
+                                                     devlist, verbose)

As above. With #defines it changes the name in the map output or debugger, which confuses people. An inline function is better, but in this case it may be better to just rename the function.

include/power/regulator.h line 369

Quoted 13 lines
include/power/regulator.h new file +13 -0
+
+/**
+ * regulator_by_devname: returns the pointer to the pmic regulator device.
+ *                       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.
+ *
+ * The returned 'regulator' device can be used with:
+ * - regulator_get/set_*
+ */
+int regulator_by_devname(const char *devname, struct udevice **devp);

regulator_get_by_devname

include/power/regulator.h line 382

Quoted 13 lines
include/power/regulator.h new file +13 -0
+
+/**
+ * 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
+ * @devp     - returned pointer to the regulator device
+ * Returns: 0 on success or negative value of errno.
+ *
+ * The returned 'regulator' device can be used with:
+ * - regulator_get/set_*
+ */
+int regulator_by_platname(const char *platname, struct udevice **devp);

regulator_get_by_platname

Quoted 5 lines
include/power/regulator.h new file +2 -1
+
+#endif /* _INCLUDE_REGULATOR_H_ */
--

1.9.1

Regards,
Simon

#166 lore raw

PATCH v4 5/16 dm: regulator: add implementation of driver model regulator uclass

Quoted 57 lines · Simon Glass

Hi Przemyslaw,

Quoted 54 lines · Przemyslaw Marczak

This commit introduces the implementation of dm regulator API. Device tree support allows for auto binding. And by the basic uclass operations, it allows to driving the devices in a common way. For detailed informations, please look into the header file.

Core files:
- drivers/power/regulator-uclass.c - provides regulator common functions api
- include/power/regulator.h - define all structures required by the regulator

Changes:
- new uclass-id: UCLASS_REGULATOR
- new config: CONFIG_DM_REGULATOR

---
Changes V2:
- new operations for regulator uclass:
-- get/set output state - for output on/off setting --- add enum: REGULATOR_OFF, REGULATOR_ON

- regulator uclass code rework and cleanup:
-- change name of:
--- enum 'regulator_desc_type' to 'regulator_type' --- add type DVS
--- struct 'regulator_desc' to 'regulator_value_desc'

-- regulator ops function calls:
--- remove 'ldo/buck' from naming
--- add new argument 'type' for define regulator type

-- regulator.h - update comments

Changes V3:
- regulator-uclass.c and regulator.h:
-- api cleanup
-- new function regulator_ofdata_to_platdata()
-- update of comments
-- add Kconfig

Changes V4:
- move file drivers/power/regulator-uclass.c to drivers/power/regulator/regulator-uclass.c
- move DM_REGULATOR Kconfig entry from: drivers/power/Kconfig to drivers/power/regulator/Kconfig
- drivers/power/Kconfig: include regulator Kconfig path
- Kconfig: provide only general informations
- regulator-uclass.c: cleanup
- regulator-uclass.c: allow init regulator with name only
- regulator-uclass.c: remove pmic_get_uclass_ops and use dev_get_driver_ops
- regulator-uclass.c: add use of uclass_get_device_by_name()
- regulator.h: add 'struct dm_regulator_uclass_platdata'
- regulator.h: API documentation cleanup
- regulator - add binding info

Quoted 15 lines
Quoted 15 lines
---
 Makefile                                         |   3 +-
 doc/device-tree-bindings/regulator/regulator.txt |  55 ++++
 drivers/power/Kconfig                            |   2 +
 drivers/power/regulator/Kconfig                  |  17 +
 drivers/power/regulator/Makefile                 |   8 +
 drivers/power/regulator/regulator-uclass.c       | 300 ++++++++++++++++++
 include/dm/uclass-id.h                           |   1 +
 include/power/regulator.h                        | 384 +++++++++++++++++++++++
 8 files changed, 769 insertions(+), 1 deletion(-)
 create mode 100644 doc/device-tree-bindings/regulator/regulator.txt
 create mode 100644 drivers/power/regulator/Kconfig
 create mode 100644 drivers/power/regulator/Makefile
 create mode 100644 drivers/power/regulator/regulator-uclass.c
 create mode 100644 include/power/regulator.h
#167 lore raw

PATCH v4 5/16 dm: regulator: add implementation of driver model regulator uclass

Quoted 59 lines · Simon Glass
Quoted 57 lines · Simon Glass

Hi Przemyslaw,

Quoted 54 lines · Przemyslaw Marczak

This commit introduces the implementation of dm regulator API. Device tree support allows for auto binding. And by the basic uclass operations, it allows to driving the devices in a common way. For detailed informations, please look into the header file.

Core files:
- drivers/power/regulator-uclass.c - provides regulator common functions api
- include/power/regulator.h - define all structures required by the regulator

Changes:
- new uclass-id: UCLASS_REGULATOR
- new config: CONFIG_DM_REGULATOR

---
Changes V2:
- new operations for regulator uclass:
-- get/set output state - for output on/off setting --- add enum: REGULATOR_OFF, REGULATOR_ON

- regulator uclass code rework and cleanup:
-- change name of:
--- enum 'regulator_desc_type' to 'regulator_type' --- add type DVS
--- struct 'regulator_desc' to 'regulator_value_desc'

-- regulator ops function calls:
--- remove 'ldo/buck' from naming
--- add new argument 'type' for define regulator type

-- regulator.h - update comments

Changes V3:
- regulator-uclass.c and regulator.h:
-- api cleanup
-- new function regulator_ofdata_to_platdata()
-- update of comments
-- add Kconfig

Changes V4:
- move file drivers/power/regulator-uclass.c to drivers/power/regulator/regulator-uclass.c
- move DM_REGULATOR Kconfig entry from: drivers/power/Kconfig to drivers/power/regulator/Kconfig
- drivers/power/Kconfig: include regulator Kconfig path
- Kconfig: provide only general informations
- regulator-uclass.c: cleanup
- regulator-uclass.c: allow init regulator with name only
- regulator-uclass.c: remove pmic_get_uclass_ops and use dev_get_driver_ops
- regulator-uclass.c: add use of uclass_get_device_by_name()
- regulator.h: add 'struct dm_regulator_uclass_platdata'
- regulator.h: API documentation cleanup
- regulator - add binding info

Quoted 1 line

Applied to u-boot-dm/next, thanks!

#168 lore raw

PATCH v4 5/16 dm: regulator: add implementation of driver model regulator uclass

In reply to Simon Glass

Hello Simon,

Quoted 321 lines · Simon Glass

Hi Przemyslaw,

Quoted 64 lines · Przemyslaw Marczak

This commit introduces the implementation of dm regulator API. Device tree support allows for auto binding. And by the basic uclass operations, it allows to driving the devices in a common way. For detailed informations, please look into the header file.

Core files:
- drivers/power/regulator-uclass.c - provides regulator common functions api
- include/power/regulator.h - define all structures required by the regulator

Changes:
- new uclass-id: UCLASS_REGULATOR
- new config: CONFIG_DM_REGULATOR

---
Changes V2:
- new operations for regulator uclass:
-- get/set output state - for output on/off setting --- add enum: REGULATOR_OFF, REGULATOR_ON

- regulator uclass code rework and cleanup:
-- change name of:
--- enum 'regulator_desc_type' to 'regulator_type' --- add type DVS
--- struct 'regulator_desc' to 'regulator_value_desc'

-- regulator ops function calls:
--- remove 'ldo/buck' from naming
--- add new argument 'type' for define regulator type

-- regulator.h - update comments

Changes V3:
- regulator-uclass.c and regulator.h:
-- api cleanup
-- new function regulator_ofdata_to_platdata()
-- update of comments
-- add Kconfig

Changes V4:
- move file drivers/power/regulator-uclass.c to drivers/power/regulator/regulator-uclass.c
- move DM_REGULATOR Kconfig entry from: drivers/power/Kconfig to drivers/power/regulator/Kconfig
- drivers/power/Kconfig: include regulator Kconfig path
- Kconfig: provide only general informations
- regulator-uclass.c: cleanup
- regulator-uclass.c: allow init regulator with name only
- regulator-uclass.c: remove pmic_get_uclass_ops and use dev_get_driver_ops
- regulator-uclass.c: add use of uclass_get_device_by_name()
- regulator.h: add 'struct dm_regulator_uclass_platdata'
- regulator.h: API documentation cleanup
- regulator - add binding info

---
  Makefile                                         |   3 +-
  doc/device-tree-bindings/regulator/regulator.txt |  55 ++++
  drivers/power/Kconfig                            |   2 +
  drivers/power/regulator/Kconfig                  |  17 +
  drivers/power/regulator/Makefile                 |   8 +
  drivers/power/regulator/regulator-uclass.c       | 300 ++++++++++++++++++
  include/dm/uclass-id.h                           |   1 +
  include/power/regulator.h                        | 384 +++++++++++++++++++++++
  8 files changed, 769 insertions(+), 1 deletion(-)
Quoted 5 lines

create mode 100644 doc/device-tree-bindings/regulator/regulator.txt create mode 100644 drivers/power/regulator/Kconfig create mode 100644 drivers/power/regulator/Makefile create mode 100644 drivers/power/regulator/regulator-uclass.c create mode 100644 include/power/regulator.h

A few more nits for later.

Quoted 233 lines
Makefile +2 -1
index dc25f70..dfb0d56 100644
@@ -645,7 +645,8 @@ libs-y += drivers/power/ \
         drivers/power/fuel_gauge/ \
         drivers/power/mfd/ \
         drivers/power/pmic/ \
-       drivers/power/battery/
+       drivers/power/battery/ \
+       drivers/power/regulator/
  libs-y += drivers/spi/
  libs-$(CONFIG_FMAN_ENET) += drivers/net/fm/
  libs-$(CONFIG_SYS_FSL_DDR) += drivers/ddr/fsl/
doc/device-tree-bindings/regulator/regulator.txt new file +55 -0
new file mode 100644
index 0000000..249e0f5
@@ -0,0 +1,55 @@
+Voltage/Current regulator
+
+Binding:
+The regulator devices don't use the "compatible" property. The binding is done
+by the prefix of regulator node's name. Usually the pmic I/O driver will provide
+the array of 'struct pmic_child_info' with the prefixes and compatible drivers.
+The bind is done by calling function: pmic_bind_childs().
+Example drivers:
+pmic: drivers/power/pmic/max77686.c
+regulator: drivers/power/regulator/max77686.c
+
+For the node name e.g.: "prefix[:alpha:]num { ... }":
+- the driver prefix should be: "prefix" or "PREFIX" - case insensitive
+- the node name's "num" is set as "dev->driver_data" on bind
+
+Example the prefix "ldo" will pass for: "ldo1", "ldo at 1", "LDO1", "LDOREG at 1"...
+
+Required properties:
+- regulator-name: a string, required by the regulator uclass
+
+Note
+The "regulator-name" constraint is used for setting the device's uclass
+platform data '.name' field. And the regulator device name is set from
+it's node name.
+
+Optional properties:
+- regulator-min-microvolt: a minimum allowed Voltage value
+- regulator-max-microvolt: a maximum allowed Voltage value
+- regulator-min-microamp: a minimum allowed Current value
+- regulator-max-microamp: a maximum allowed Current value
+- regulator-always-on: regulator should never be disabled
+- regulator-boot-on: enabled by bootloader/firmware
+
+Other kernel-style properties, are currently not used.
+
+Note:
+For the regulator autoset from constraints, the framework expects that:
+- regulator-min-microvolt is equal to regulator-max-microvolt
+- regulator-min-microamp is equal to regulator-max-microamp
+- regulator-always-on or regulator-boot-on is set
+
+Example:
+ldo0 {
+       /* Mandatory */
+       regulator-name = "VDDQ_EMMC_1.8V";
+
+       /* Optional */
+       regulator-min-microvolt = <1800000>;
+       regulator-max-microvolt = <1800000>;
+       regulator-min-microamp = <100000>;
+       regulator-max-microamp = <100000>;
+       regulator-always-on;
+       regulator-boot-on;
+};
+
drivers/power/Kconfig +2 -0
index d03626e..23cdd71 100644
@@ -2,6 +2,8 @@ menu "Power"
 
  source "drivers/power/pmic/Kconfig"
 
+source "drivers/power/regulator/Kconfig"
+
  config AXP221_POWER
         boolean "axp221 / axp223 pmic support"
         depends on MACH_SUN6I || MACH_SUN8I
drivers/power/regulator/Kconfig new file +17 -0
new file mode 100644
index 0000000..cb15162
@@ -0,0 +1,17 @@
+config DM_REGULATOR
+       bool "Enable Driver Model for REGULATOR drivers (UCLASS_REGULATOR)"
+       depends on DM
+       ---help---
+       This config enables the driver model regulator support.
+       UCLASS_REGULATOR - designed to provide a common API for basic regulator's
+       functions, like get/set Voltage or Current value, enable state, etc...
+       Note:
+       When enabling this, please read the description, found in the files:
+       - 'include/power/pmic.h'
+       - 'include/power/regulator.h'
+       - 'drivers/power/pmic/pmic-uclass.c'
+       - 'drivers/power/pmic/regulator-uclass.c'
+       It's important to call the device_bind() with the proper node offset,
+       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.
drivers/power/regulator/Makefile new file +8 -0
new file mode 100644
index 0000000..27c9006
@@ -0,0 +1,8 @@
+#
+# Copyright (C) 2015 Samsung Electronics
+# Przemyslaw Marczak <[email protected]>
+#
+# SPDX-License-Identifier:     GPL-2.0+
+#
+
+obj-$(CONFIG_DM_REGULATOR) += regulator-uclass.o
drivers/power/regulator/regulator-uclass.c new file +101 -0
new file mode 100644
index 0000000..07ce286
@@ -0,0 +1,300 @@
+/*
+ * Copyright (C) 2014-2015 Samsung Electronics
+ * Przemyslaw Marczak <[email protected]>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+#include <common.h>
+#include <fdtdec.h>
+#include <errno.h>
+#include <dm.h>
+#include <dm/uclass-internal.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int regulator_mode(struct udevice *dev, struct dm_regulator_mode **modep)
+{
+       struct dm_regulator_uclass_platdata *uc_pdata;
+
+       *modep = NULL;
+
+       uc_pdata = dev_get_uclass_platdata(dev);
+       if (!uc_pdata)
+               return -ENXIO;
+
+       *modep = uc_pdata->mode;
+       return uc_pdata->mode_count;
+}
+
+int regulator_get_value(struct udevice *dev)
+{
+       const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
+
+       if (!ops || !ops->get_value)
+               return -ENOSYS;
+
+       return ops->get_value(dev);
+}
+
+int regulator_set_value(struct udevice *dev, int uV)
+{
+       const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
+
+       if (!ops || !ops->set_value)
+               return -ENOSYS;
+
+       return ops->set_value(dev, uV);
+}
+
+int regulator_get_current(struct udevice *dev)
+{
+       const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
+
+       if (!ops || !ops->get_current)
+               return -ENOSYS;
+
+       return ops->get_current(dev);
+}
+
+int regulator_set_current(struct udevice *dev, int uA)
+{
+       const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
+
+       if (!ops || !ops->set_current)
+               return -ENOSYS;
+
+       return ops->set_current(dev, uA);
+}
+
+bool regulator_get_enable(struct udevice *dev)
+{
+       const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
+
+       if (!ops || !ops->get_enable)
+               return -ENOSYS;
+
+       return ops->get_enable(dev);
+}
+
+int regulator_set_enable(struct udevice *dev, bool enable)
+{
+       const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
+
+       if (!ops || !ops->set_enable)
+               return -ENOSYS;
+
+       return ops->set_enable(dev, enable);
+}
+
+int regulator_get_mode(struct udevice *dev)
+{
+       const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
+
+       if (!ops || !ops->get_mode)
+               return -ENOSYS;
+
+       return ops->get_mode(dev);
+}
+
+int regulator_set_mode(struct udevice *dev, int mode)

drivers/power/regulator/regulator-uclass.c line 111

Quoted 10 lines
drivers/power/regulator/regulator-uclass.c new file +10 -0
+{
+       const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
+
+       if (!ops || !ops->set_mode)
+               return -ENOSYS;
+
+       return ops->set_mode(dev, mode);
+}
+
+int regulator_by_platname(const char *plat_name, struct udevice **devp)

regulator_get_by_platname()

Quoted 2 lines

since it does probe the device

Ok.

Quoted 16 lines
Quoted 16 lines
drivers/power/regulator/regulator-uclass.c new file +16 -0
+{
+       struct dm_regulator_uclass_platdata *uc_pdata;
+       struct udevice *dev;
+
+       *devp = NULL;
+
+       for (uclass_find_first_device(UCLASS_REGULATOR, &dev);
+            dev;
+            uclass_find_next_device(&dev)) {
+               uc_pdata = dev_get_uclass_platdata(dev);
+               if (!uc_pdata || strcmp(plat_name, uc_pdata->name))
+                       continue;
+
+               return uclass_get_device_tail(dev, 0, devp);
+       }
+
Quoted 9 lines

drivers/power/regulator/regulator-uclass.c line 133

Quoted 6 lines
drivers/power/regulator/regulator-uclass.c new file +6 -0
+       debug("%s: can't find: %s\n", __func__, plat_name);
+
+       return -ENODEV;
+}
+
+int regulator_by_devname(const char *devname, struct udevice **devp)

regulator_get_by_devname

Ok.

Quoted 11 lines
Quoted 11 lines
drivers/power/regulator/regulator-uclass.c new file +11 -0
+{
+       return uclass_get_device_by_name(UCLASS_REGULATOR, devname, devp);
+}
+
+static int setting_failed(int ret, bool verbose, const char *fmt, ...)
+{
+       va_list args;
+       char buf[64];
+
+       if (verbose == false)
+               return ret;
Quoted 9 lines

drivers/power/regulator/regulator-uclass.c line 150

Quoted 6 lines
drivers/power/regulator/regulator-uclass.c new file +6 -0
+
+       va_start(args, fmt);
+       vscnprintf(buf, sizeof(buf), fmt, args);
+       va_end(args);
+
+       printf(buf);

I wonder if we should have a vprintf() in U-Boot?

Yes, it could be useful.

Quoted 10 lines
Quoted 10 lines
drivers/power/regulator/regulator-uclass.c new file +10 -0
+
+       if (!ret)
+               return 0;
+
+       printf(" (ret: %d)", ret);
+
+       return ret;
+}
+
+int regulator_by_platname_autoset_and_enable(const char *platname,
Quoted 9 lines

drivers/power/regulator/regulator-uclass.c line 166

Quoted 6 lines
drivers/power/regulator/regulator-uclass.c new file +6 -0
+                                            struct udevice **devp,
+                                            bool verbose)
+{
+       struct dm_regulator_uclass_platdata *uc_pdata;
+       struct udevice *dev;
+       bool v = verbose;

Can we drop this local var and just use 'verbose'

I added this to avoid breaking the line of call to setting_failed(). So I will use just failed(), and then can put the verbose with no line breaking inside 'if' brackets.

Quoted 52 lines
Quoted 52 lines
drivers/power/regulator/regulator-uclass.c new file +52 -0
+       int ret;
+
+       if (devp)
+               *devp = NULL;
+
+       ret = regulator_by_platname(platname, &dev);
+       if (ret) {
+               error("Can get the regulator: %s!", platname);
+               return ret;
+       }
+
+       uc_pdata = dev_get_uclass_platdata(dev);
+       if (!uc_pdata) {
+               error("Can get the regulator %s uclass platdata!", platname);
+               return -ENXIO;
+       }
+
+       if (v)
+               printf("%s@%s: ", dev->name, uc_pdata->name);
+
+       /* Those values are optional (-ENODATA if unset) */
+       if ((uc_pdata->min_uV != -ENODATA) &&
+           (uc_pdata->max_uV != -ENODATA) &&
+           (uc_pdata->min_uV == uc_pdata->max_uV)) {
+               ret = regulator_set_value(dev, uc_pdata->min_uV);
+               if (setting_failed(ret, v, "set %d uV", uc_pdata->min_uV))
+                       goto exit;
+       }
+
+       /* Those values are optional (-ENODATA if unset) */
+       if ((uc_pdata->min_uA != -ENODATA) &&
+           (uc_pdata->max_uA != -ENODATA) &&
+           (uc_pdata->min_uA == uc_pdata->max_uA)) {
+               ret = regulator_set_current(dev, uc_pdata->min_uA);
+               if (setting_failed(ret, v, "; set %d uA", uc_pdata->min_uA))
+                       goto exit;
+       }
+
+       if (!uc_pdata->always_on && !uc_pdata->boot_on)
+               goto retdev;
+
+       ret = regulator_set_enable(dev, true);
+       if (setting_failed(ret, v, "; enabling", uc_pdata->min_uA))
+               goto exit;
+
+retdev:
+       if (devp)
+               *devp = dev;
+exit:
+       if (v)
+               printf("\n");
+       return ret;
Quoted 9 lines

drivers/power/regulator/regulator-uclass.c line 224

Quoted 6 lines
drivers/power/regulator/regulator-uclass.c new file +6 -0
+}
+
+int regulator_by_platname_list_autoset_and_enable(const char *list_platname[],
+                                                 int list_entries,
+                                                 struct udevice *list_devp[],
+                                                 bool verbose)

I wonder if you could shorten this (e.g. to regulator_list_autoset())?

I introduced macro: "regulator_list_autoset()" in
include/power/regulator.h. Is it good?

Quoted 10 lines
Quoted 10 lines
drivers/power/regulator/regulator-uclass.c new file +10 -0
+{
+       struct udevice *dev;
+       int i, ret, success = 0;
+
+       for (i = 0; i < list_entries; i++) {
+               ret = regulator_autoset(list_platname[i], &dev, verbose);
+               if (!ret)
+                       success++;
+
+               if (!list_devp)
Quoted 9 lines

drivers/power/regulator/regulator-uclass.c line 240

Quoted 6 lines
drivers/power/regulator/regulator-uclass.c new file +6 -0
+                       continue;
+
+               if (ret)
+                       list_devp[i] = NULL;
+               else
+                       list_devp[i] = dev;

Shouldn't dev be NULL if ret is non-zero anyway?

Right, it always be if given. Will fix.

Quoted 8 lines

drivers/power/regulator/regulator-uclass.c line 243

Quoted 3 lines
drivers/power/regulator/regulator-uclass.c new file +3 -0
+       }
+
+       return (success != list_entries);

return success == list_entries ? 0 : -EIO

or something. Better would be to record the first error you get and return that.

Ok, I will tune it.

Quoted 12 lines
Quoted 12 lines
drivers/power/regulator/regulator-uclass.c new file +12 -0
+}
+
+static int regulator_post_bind(struct udevice *dev)
+{
+       struct dm_regulator_uclass_platdata *uc_pdata;
+       int offset = dev->of_offset;
+       const void *blob = gd->fdt_blob;
+
+       uc_pdata = dev_get_uclass_platdata(dev);
+       if (!uc_pdata)
+               return -ENXIO;
+
Quoted 9 lines

drivers/power/regulator/regulator-uclass.c line 261

Quoted 6 lines
drivers/power/regulator/regulator-uclass.c new file +6 -0
+       /* Regulator's mandatory constraint */
+       uc_pdata->name = fdt_getprop(blob, offset, "regulator-name", NULL);
+       if (!uc_pdata->name) {
+               debug("%s: dev: %s has no property 'regulator-name'\n",
+                     __func__, dev->name);
+               return -ENXIO;

-EINVAL as it indicates invalid device tree data.

Ok.

Quoted 106 lines
Quoted 93 lines
drivers/power/regulator/regulator-uclass.c new file +39 -0
+       }
+
+       return 0;
+}
+
+static int regulator_pre_probe(struct udevice *dev)
+{
+       struct dm_regulator_uclass_platdata *uc_pdata;
+       int offset = dev->of_offset;
+
+       uc_pdata = dev_get_uclass_platdata(dev);
+       if (!uc_pdata)
+               return -ENXIO;
+
+       /* Regulator's optional constraints */
+       uc_pdata->min_uV = fdtdec_get_int(gd->fdt_blob, offset,
+                                         "regulator-min-microvolt", -ENODATA);
+       uc_pdata->max_uV = fdtdec_get_int(gd->fdt_blob, offset,
+                                         "regulator-max-microvolt", -ENODATA);
+       uc_pdata->min_uA = fdtdec_get_int(gd->fdt_blob, offset,
+                                         "regulator-min-microamp", -ENODATA);
+       uc_pdata->max_uA = fdtdec_get_int(gd->fdt_blob, offset,
+                                         "regulator-max-microamp", -ENODATA);
+       uc_pdata->always_on = fdtdec_get_bool(gd->fdt_blob, offset,
+                                             "regulator-always-on");
+       uc_pdata->boot_on = fdtdec_get_bool(gd->fdt_blob, offset,
+                                           "regulator-boot-on");
+
+       return 0;
+}
+
+UCLASS_DRIVER(regulator) = {
+       .id             = UCLASS_REGULATOR,
+       .name           = "regulator",
+       .post_bind      = regulator_post_bind,
+       .pre_probe      = regulator_pre_probe,
+       .per_device_platdata_auto_alloc_size =
+                               sizeof(struct dm_regulator_uclass_platdata),
+};
include/dm/uclass-id.h +1 -0
index 23b3eb9..3c572d7 100644
@@ -48,6 +48,7 @@ enum uclass_id {
 
         /* Power Management */
         UCLASS_PMIC,            /* PMIC I/O device */
+       UCLASS_REGULATOR,       /* REGULATOR device */
 
         UCLASS_COUNT,
         UCLASS_INVALID = -1,
include/power/regulator.h new file +36 -0
new file mode 100644
index 0000000..0302c1d
@@ -0,0 +1,384 @@
+/*
+ *  Copyright (C) 2014-2015 Samsung Electronics
+ *  Przemyslaw Marczak <[email protected]>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef _INCLUDE_REGULATOR_H_
+#define _INCLUDE_REGULATOR_H_
+
+/**
+ * U-Boot Voltage/Current Regulator
+ * ================================
+ *
+ * The regulator API is based on a driver model, with the device tree support.
+ * And this header describes the functions and data types for the uclass id:
+ * 'UCLASS_REGULATOR' and the regulator driver API.
+ *
+ * The regulator uclass - is based on uclass platform data which is allocated,
+ * automatically for each regulator device on bind and 'dev->uclass_platdata'
+ * points to it. The data type is: 'struct dm_regulator_uclass_platdata'.
+ * The uclass file: 'drivers/power/regulator/regulator-uclass.c'
+ *
+ * The regulator device - is based on driver's model 'struct udevice'.
+ * The API can use regulator name in two meanings:
+ * - devname  - the regulator device's name: 'dev->name'
+ * - platname - the device's platdata's name. So in the code it looks like:
+ *              'uc_pdata = dev->uclass_platdata'; 'name = uc_pdata->name'.
+ *
+ * The regulator device driver - provide an implementation of uclass operations
+ * pointed by 'dev->driver->ops' as a struct of type 'struct dm_regulator_ops'.
+ *
+ * To proper bind the regulator device, the device tree node should provide
+ * regulator constraints, like in the example below:
+ *
+ * ldo1 {

include/power/regulator.h line 46

Quoted 10 lines
include/power/regulator.h new file +10 -0
+ *      regulator-name = "VDD_MMC_1.8V";     (mandatory for bind)
+ *      regulator-min-microvolt = <1000000>; (optional)
+ *      regulator-max-microvolt = <1000000>; (optional)
+ *      regulator-min-microamp = <1000>;     (optional)
+ *      regulator-max-microamp = <1000>;     (optional)
+ *      regulator-always-on;                 (optional)
+ *      regulator-boot-on;                   (optional)
+ * };
+ *
+ * Please take a notice, that for the proper operation at least name constraint

Please note that for the proper

Quoted 4 lines

or

Note: For the proper

Ok.

Quoted 9 lines

include/power/regulator.h line 52

Quoted 6 lines
include/power/regulator.h new file +6 -0
+ * is needed, e.g. for call the device_by_platname(...).
+ *
+ * Regulator bind:
+ * For each regulator device, the device_bind() should be called with passed
+ * device tree offset. This is required for this uclass's '.post_bind' method,
+ * which do the scan on the device node, for the 'regulator-name' constraint.

s/do/does/

Ok.

Quoted 11 lines

include/power/regulator.h line 58

Quoted 6 lines
include/power/regulator.h new file +6 -0
+ * If the parent is not a PMIC device, and the child is not bind by function:
+ * 'pmic_bind_childs()', then it's recommended to bind the device by call to
+ * dm_scan_fdt_node() - this is usually done automatically for bus devices,
+ * as a post bind method.
+ * Having the device's name constraint, we can call regulator_by_platname(),
+ * to find interesting regulator. Before return, the regulator is probed,

How about:

s/to find interesting regulator/to find the required regulator/

Ok.

Quoted 10 lines

include/power/regulator.h line 67

Quoted 9 lines
include/power/regulator.h new file +9 -0
+ * and the rest of its constraints are put into the device's uclass platform
+ * data, by the uclass regulator '.pre_probe' method.
+ *
+ * For more info about PMIC bind, please refer to file: 'include/power/pmic.h'
+ *
+ * Note:
+ * Please do not use the device_bind_by_name() function, since it pass '-1' as
+ * device node offset - and the bind will fail on uclass .post_bind method,
+ * because of missing 'regulator-name' constraint.
Quoted 3 lines

Indeed. BTW I think i'm going to add a similar function which allows the node to be passed.

That's great, would be usefull.

Quoted 216 lines
Quoted 216 lines
include/power/regulator.h new file +216 -0
+ *
+ *
+ * Fixed Voltage/Current Regulator
+ * ===============================
+ *
+ * When fixed voltage regulator is needed, then enable the config:
+ * - CONFIG_DM_REGULATOR_FIXED
+ *
+ * The driver file: 'drivers/power/regulator/fixed.c', provides basic support
+ * for control the GPIO, and return the device tree constraint values.
+ *
+ * To bind the fixed voltage regulator device, we usually use a 'simple-bus'
+ * node as a parent. And 'regulator-fixed' for the driver compatible. This is
+ * the same as in the kernel. The example node of fixed regulator:
+ *
+ * simple-bus {
+ *     compatible = "simple-bus";
+ *     #address-cells = <1>;
+ *     #size-cells = <0>;
+ *
+ *     blue_led {
+ *         compatible = "regulator-fixed";
+ *         regulator-name = "VDD_LED_3.3V";
+ *         regulator-min-microvolt = <3300000>;
+ *         regulator-max-microvolt = <3300000>;
+ *         gpio = <&gpc1 0 GPIO_ACTIVE_LOW>;
+ *     };
+ * };
+ *
+ * The fixed regulator devices also provide regulator uclass platform data. And
+ * devices bound from such node, can use the regulator drivers API.
+*/
+
+/* enum regulator_type - used for regulator_*() variant calls */
+enum regulator_type {
+       REGULATOR_TYPE_LDO = 0,
+       REGULATOR_TYPE_BUCK,
+       REGULATOR_TYPE_DVS,
+       REGULATOR_TYPE_FIXED,
+       REGULATOR_TYPE_OTHER,
+};
+
+/**
+ * struct dm_regulator_mode - this structure holds an information about
+ * each regulator operation mode. Probably in most cases - an array.
+ * This will be probably a driver-static data, since it is device-specific.
+ *
+ * @id             - a driver-specific mode id
+ * @register_value - a driver-specific value for its mode id
+ * @name           - the name of mode - used for regulator command
+ * Note:
+ * The field 'id', should be always a positive number, since the negative values
+ * are reserved for the errno numbers when returns the mode id.
+ */
+struct dm_regulator_mode {
+       int id; /* Set only as >= 0 (negative value is reserved for errno) */
+       int register_value;
+       const char *name;
+};
+
+/**
+ * struct dm_regulator_uclass_platdata - pointed by dev->uclass_platdata, and
+ * allocated on each regulator bind. This structure holds an information
+ * about each regulator's constraints and supported operation modes.
+ * There is no "step" voltage value - so driver should take care of this.
+ *
+ * @type       - one of 'enum regulator_type'
+ * @mode       - pointer to the regulator mode (array if more than one)
+ * @mode_count - number of '.mode' entries
+ * @min_uV*    - minimum voltage (micro Volts)
+ * @max_uV*    - maximum voltage (micro Volts)
+ * @min_uA*    - minimum amperage (micro Amps)
+ * @max_uA*    - maximum amperage (micro Amps)
+ * @always_on* - bool type, true or false
+ * @boot_on*   - bool type, true or false
+ * @name**     - fdt regulator name - should be taken from the device tree
+ *
+ * Note:
+ * *  - set automatically on device probe by the uclass's '.pre_probe' method.
+ * ** - set automatically on device bind by the uclass's '.post_bind' method.
+ * The constraints: type, mode, mode_count, can be set by device driver, e.g.
+ * by the driver '.probe' method.
+ */
+struct dm_regulator_uclass_platdata {
+       enum regulator_type type;
+       struct dm_regulator_mode *mode;
+       int mode_count;
+       int min_uV;
+       int max_uV;
+       int min_uA;
+       int max_uA;
+       bool always_on;
+       bool boot_on;
+       const char *name;
+};
+
+/* Regulator device operations */
+struct dm_regulator_ops {
+       /**
+        * The regulator output value function calls operates on a micro Volts.
+        *
+        * get/set_value - get/set output value of the given output number
+        * @dev          - regulator device
+        * Sets:
+        * @uV           - set the output value [micro Volts]
+        * Returns: output value [uV] on success or negative errno if fail.
+        */
+       int (*get_value)(struct udevice *dev);
+       int (*set_value)(struct udevice *dev, int uV);
+
+       /**
+        * The regulator output current function calls operates on a micro Amps.
+        *
+        * get/set_current - get/set output current of the given output number
+        * @dev            - regulator device
+        * Sets:
+        * @uA           - set the output current [micro Amps]
+        * Returns: output value [uA] on success or negative errno if fail.
+        */
+       int (*get_current)(struct udevice *dev);
+       int (*set_current)(struct udevice *dev, int uA);
+
+       /**
+        * The most basic feature of the regulator output is its enable state.
+        *
+        * get/set_enable - get/set enable state of the given output number
+        * @dev           - regulator device
+        * Sets:
+        * @enable         - set true - enable or false - disable
+        * Returns: 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
+        * specific mode definitions, which should be found in:
+        * field 'mode' of struct mode_desc.
+        *
+        * get/set_mode - get/set operation mode of the given output number
+        * @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.
+        * Note:
+        * The field 'id' of struct type 'dm_regulator_mode', should be always
+        * positive number, since the negative is reserved for the error.
+        */
+       int (*get_mode)(struct udevice *dev);
+       int (*set_mode)(struct udevice *dev, int mode_id);
+};
+
+/**
+ * regulator_mode: returns a pointer to the array of regulator mode info
+ *
+ * @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.
+ */
+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.
+ */
+int regulator_get_value(struct udevice *dev);
+
+/**
+ * regulator_set_value: set the microvoltage value of a given regulator.
+ *
+ * @dev    - pointer to the regulator device
+ * @uV     - the output value to set [micro Volts]
+ * Returns - 0 on success or -errno val if fails
+ */
+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.
+ */
+int regulator_get_current(struct udevice *dev);
+
+/**
+ * regulator_set_current: set the microampere value of a given regulator.
+ *
+ * @dev    - pointer to the regulator device
+ * @uA     - set the output current [micro Amps]
+ * Returns - 0 on success or -errno val if fails
+ */
+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
+ */
+bool regulator_get_enable(struct udevice *dev);
+
+/**
+ * regulator_set_enable: set regulator enable state
+ *
+ * @dev    - pointer to the regulator device
+ * @enable - set true or false
+ * Returns - 0 on success or -errno val if fails
+ */
+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
Quoted 9 lines

include/power/regulator.h line 288

Quoted 5 lines
include/power/regulator.h new file +5 -0
+ * Returns - 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'
+ * for this purpose and register_value for a raw register value.

Can you please reword the first sentence? I don't understand what it is trying to say. Similar below.

Ok, will fix this.

Quoted 36 lines
Quoted 36 lines
include/power/regulator.h new file +36 -0
+ */
+int regulator_get_mode(struct udevice *dev);
+
+/**
+ * regulator_set_mode: set given regulator mode
+ *
+ * @dev    - pointer to the regulator device
+ * @mode   - mode type (field 'mode' of struct mode_desc)
+ * Returns - 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
+ * a mode field for this purpose and register_value for a raw register value.
+ */
+int regulator_set_mode(struct udevice *dev, int mode);
+
+/**
+ * regulator_by_platname_autoset_and_enable: setup the regulator given by
+ * its uclass's platform data '.name'. The setup depends on constraints found
+ * 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
+ *
+ * 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.
+ *
+ * The returned 'regulator' device can be used with:
+ * - regulator_get/set_*
+ * For shorter call name, the below macro regulator_autoset() can be used.
+ */
+int regulator_by_platname_autoset_and_enable(const char *platname,
Quoted 9 lines

include/power/regulator.h line 330

Quoted 6 lines
include/power/regulator.h new file +6 -0
+                                            struct udevice **devp,
+                                            bool verbose);
+
+#define regulator_autoset(platname, devp, verbose) \
+       regulator_by_platname_autoset_and_enable(platname, devp, verbose)
+

Can we just use the shorter name for the function and avoid this #ifdef?

Ok.

Quoted 25 lines

include/power/regulator.h line 343

Quoted 13 lines
include/power/regulator.h new file +13 -0
+/**
+ * regulator_by_platname_list_autoset_and_enable: setup the regulators given by
+ * list of its uclass's platform data '.name'. The setup depends on constraints
+ * found in device's uclass's platform data. The function loops with calls to:
+ * regulator_by_platname_autoset_and_enable() for each name of list.
+ *
+ * @list_platname - an array of expected strings for .name field of each
+ *                  regulator's uclass platdata
+ * @list_entries  - number of regulator's name list entries
+ * @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.

otherwise

Quoted 9 lines
include/power/regulator.h new file +9 -0
+ *
+ * The returned 'regulator' devices can be used with:
+ * - regulator_get/set_*
+ * For shorter call name, the below macro regulator_list_autoset() can be used.
+ */
+int regulator_by_platname_list_autoset_and_enable(const char *list_platname[],
+                                                 int list_entries,
+                                                 struct udevice *list_devp[],
+                                                 bool verbose);
Quoted 9 lines

include/power/regulator.h line 356

Quoted 4 lines
include/power/regulator.h new file +4 -0
+
+#define regulator_list_autoset(namelist, entries, devlist, verbose)      \
+       regulator_by_platname_list_autoset_and_enable(namelist, entries, \
+                                                     devlist, verbose)

As above. With #defines it changes the name in the map output or debugger, which confuses people. An inline function is better, but in this case it may be better to just rename the function.

Okay, will fix both.

Quoted 16 lines

include/power/regulator.h line 369

Quoted 13 lines
include/power/regulator.h new file +13 -0
+
+/**
+ * regulator_by_devname: returns the pointer to the pmic regulator device.
+ *                       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.
+ *
+ * The returned 'regulator' device can be used with:
+ * - regulator_get/set_*
+ */
+int regulator_by_devname(const char *devname, struct udevice **devp);

regulator_get_by_devname

Quoted 16 lines

include/power/regulator.h line 382

Quoted 13 lines
include/power/regulator.h new file +13 -0
+
+/**
+ * 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
+ * @devp     - returned pointer to the regulator device
+ * Returns: 0 on success or negative value of errno.
+ *
+ * The returned 'regulator' device can be used with:
+ * - regulator_get/set_*
+ */
+int regulator_by_platname(const char *platname, struct udevice **devp);

regulator_get_by_platname

Also, will fix both.

Quoted 9 lines
Quoted 5 lines
include/power/regulator.h new file +2 -1
+
+#endif /* _INCLUDE_REGULATOR_H_ */
--

1.9.1

Regards,
Simon

Thank you again, will resend ASAP.

Best regards,

Signature · 4 lines
Przemyslaw Marczak
Samsung R&D Institute Poland
Samsung Electronics
p.marczak at samsung.com
#169 lore raw

PATCH v4 6/16 dm: pmic: add pmic command

In reply to Przemyslaw Marczak

This is new command for the PMIC devices based on driver model PMIC API. Command features are unchanged:
- list UCLASS pmic devices
- show or [set] operating pmic device (NEW)
- dump registers
- read byte of register at address
- write byte to register at address

The only one change for this command is 'dev' subcommand.

---
Changes v3:
- new file
- add Kconfig

Changes V4:
- common/cmd_pmic.c: cleanup
- move config name: CONFIG_DM_PMIC_CMD to CONFIG_CMD_PMIC

---
 common/Kconfig    |  14 ++++
 common/Makefile   |   3 +
 common/cmd_pmic.c | 231 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 248 insertions(+)
 create mode 100644 common/cmd_pmic.c
common/Kconfig +14 -0
index 17930a4..4666f8e 100644
@@ -457,4 +457,18 @@ config BOOTSTAGE_STASH_SIZE
 
 endmenu
 
+menu "Power commands"
+config CMD_PMIC
+	bool "Enable Driver Model PMIC command"
+	depends on DM_PMIC
+	help
+	  This is the pmic command, based on a driver model pmic's API.
+	  Command features are unchanged:
+	  - list               - list pmic devices
+	  - pmic dev <id>      - show or [set] operating pmic device (NEW)
+	  - pmic dump          - dump registers
+	  - pmic read address  - read byte of register at address
+	  - pmic write address - write byte to register at address
+	  The only one change for this command is 'dev' subcommand.
+endmenu
 endmenu
common/Makefile +3 -0
index 252fbf1..87a3efe 100644
@@ -209,6 +209,9 @@ obj-$(CONFIG_UPDATE_TFTP) += update.o
 obj-$(CONFIG_USB_KEYBOARD) += usb_kbd.o
 obj-$(CONFIG_CMD_DFU) += cmd_dfu.o
 obj-$(CONFIG_CMD_GPT) += cmd_gpt.o
+
+# Power
+obj-$(CONFIG_CMD_PMIC) += cmd_pmic.o
 endif
 
 ifdef CONFIG_SPL_BUILD
common/cmd_pmic.c new file +231 -0

231 lines not on this page · raw message

Signature · 1 line
1.9.1
#170 lore raw

PATCH v4 6/16 dm: pmic: add pmic command

Quoted 19 lines · Przemyslaw Marczak

This is new command for the PMIC devices based on driver model PMIC API. Command features are unchanged:
- list UCLASS pmic devices
- show or [set] operating pmic device (NEW)
- dump registers
- read byte of register at address
- write byte to register at address

The only one change for this command is 'dev' subcommand.

---
Changes v3:
- new file
- add Kconfig

Changes V4:
- common/cmd_pmic.c: cleanup
- move config name: CONFIG_DM_PMIC_CMD to CONFIG_CMD_PMIC

Quoted 6 lines
---
 common/Kconfig    |  14 ++++
 common/Makefile   |   3 +
 common/cmd_pmic.c | 231 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 248 insertions(+)
 create mode 100644 common/cmd_pmic.c
#171 lore raw

PATCH v4 6/16 dm: pmic: add pmic command

Quoted 27 lines · Simon Glass
Quoted 19 lines · Przemyslaw Marczak

This is new command for the PMIC devices based on driver model PMIC API. Command features are unchanged:
- list UCLASS pmic devices
- show or [set] operating pmic device (NEW)
- dump registers
- read byte of register at address
- write byte to register at address

The only one change for this command is 'dev' subcommand.

---
Changes v3:
- new file
- add Kconfig

Changes V4:
- common/cmd_pmic.c: cleanup
- move config name: CONFIG_DM_PMIC_CMD to CONFIG_CMD_PMIC

Quoted 6 lines
---
 common/Kconfig    |  14 ++++
 common/Makefile   |   3 +
 common/cmd_pmic.c | 231 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 248 insertions(+)
 create mode 100644 common/cmd_pmic.c
Quoted 1 line

Applied to u-boot-dm/next, thanks!

#172 lore raw

PATCH v4 7/16 dm: regulator: add regulator command

In reply to Przemyslaw Marczak

This command is based on driver model regulator's API. The user interface provides:
- list UCLASS regulator devices
- show or [set] operating regulator device
- print constraints info
- print operating status
- print/[set] voltage value [uV] (force)
- print/[set] current value [uA]
- print/[set] operating mode id
- enable the regulator output
- disable the regulator output

The 'force' option can be used for setting the value which exceeds the constraints min/max limits.

---
Changes v3:
- new file
- Kconfig entry

Changes V4:
- cmd regulator: move platdata to uc pdata
- cmd_regulator: includes cleanup
- cmd_regulator: add get_curr_dev_and_pl() check type
- move config name: CONFIG_DM_REGULATOR_CMD to CONFIG_CMD_REGULATOR
- common/Kconfig - cleanup

---
 common/Kconfig         |  22 +++
 common/Makefile        |   1 +
 common/cmd_regulator.c | 403 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 426 insertions(+)
 create mode 100644 common/cmd_regulator.c
common/Kconfig +22 -0
index 4666f8e..52f8bb1 100644
@@ -470,5 +470,27 @@ config CMD_PMIC
 	  - pmic read address  - read byte of register at address
 	  - pmic write address - write byte to register at address
 	  The only one change for this command is 'dev' subcommand.
+
+config CMD_REGULATOR
+	bool "Enable Driver Model REGULATOR command"
+	depends on DM_REGULATOR
+	help
+	  This command is based on driver model regulator's API.
+	  User interface features:
+	  - list               - list regulator devices
+	  - regulator dev <id> - show or [set] operating regulator device
+	  - regulator info     - print constraints info
+	  - regulator status   - print operating status
+	  - regulator value <val] <-f> - print/[set] voltage value [uV]
+	  - regulator current <val>    - print/[set] current value [uA]
+	  - regulator mode <id>        - print/[set] operating mode id
+	  - regulator enable           - enable the regulator output
+	  - regulator disable          - disable the regulator output
+
+	  The '-f' (force) option can be used for set the value which exceeds
+	  the limits, which are found in device-tree and are kept in regulator's
+	  uclass platdata structure.
+
 endmenu
+
 endmenu
common/Makefile +1 -0
index 87a3efe..93bded3 100644
@@ -212,6 +212,7 @@ obj-$(CONFIG_CMD_GPT) += cmd_gpt.o
 
 # Power
 obj-$(CONFIG_CMD_PMIC) += cmd_pmic.o
+obj-$(CONFIG_CMD_REGULATOR) += cmd_regulator.o
 endif
 
 ifdef CONFIG_SPL_BUILD
common/cmd_regulator.c new file +403 -0

403 lines not on this page · raw message

Signature · 1 line
1.9.1
#173 lore raw

PATCH v4 7/16 dm: regulator: add regulator command

Hi Przemyslaw,

Quoted 27 lines · Przemyslaw Marczak

This command is based on driver model regulator's API. The user interface provides:
- list UCLASS regulator devices
- show or [set] operating regulator device
- print constraints info
- print operating status
- print/[set] voltage value [uV] (force)
- print/[set] current value [uA]
- print/[set] operating mode id
- enable the regulator output
- disable the regulator output

The 'force' option can be used for setting the value which exceeds the constraints min/max limits.

---
Changes v3:
- new file
- Kconfig entry

Changes V4:
- cmd regulator: move platdata to uc pdata
- cmd_regulator: includes cleanup
- cmd_regulator: add get_curr_dev_and_pl() check type
- move config name: CONFIG_DM_REGULATOR_CMD to CONFIG_CMD_REGULATOR
- common/Kconfig - cleanup

Quoted 6 lines
---
 common/Kconfig         |  22 +++
 common/Makefile        |   1 +
 common/cmd_regulator.c | 403 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 426 insertions(+)
 create mode 100644 common/cmd_regulator.c

I have a few nits that could be dealt with by a follow-on patch.

Quoted 65 lines
common/Kconfig +22 -0
index 4666f8e..52f8bb1 100644
@@ -470,5 +470,27 @@ config CMD_PMIC
          - pmic read address  - read byte of register at address
          - pmic write address - write byte to register at address
          The only one change for this command is 'dev' subcommand.
+
+config CMD_REGULATOR
+       bool "Enable Driver Model REGULATOR command"
+       depends on DM_REGULATOR
+       help
+         This command is based on driver model regulator's API.
+         User interface features:
+         - list               - list regulator devices
+         - regulator dev <id> - show or [set] operating regulator device
+         - regulator info     - print constraints info
+         - regulator status   - print operating status
+         - regulator value <val] <-f> - print/[set] voltage value [uV]
+         - regulator current <val>    - print/[set] current value [uA]
+         - regulator mode <id>        - print/[set] operating mode id
+         - regulator enable           - enable the regulator output
+         - regulator disable          - disable the regulator output
+
+         The '-f' (force) option can be used for set the value which exceeds
+         the limits, which are found in device-tree and are kept in regulator's
+         uclass platdata structure.
+
 endmenu
+
 endmenu
common/Makefile +1 -0
index 87a3efe..93bded3 100644
@@ -212,6 +212,7 @@ obj-$(CONFIG_CMD_GPT) += cmd_gpt.o
 
 # Power
 obj-$(CONFIG_CMD_PMIC) += cmd_pmic.o
+obj-$(CONFIG_CMD_REGULATOR) += cmd_regulator.o
 endif
 
 ifdef CONFIG_SPL_BUILD
common/cmd_regulator.c new file +14 -0
new file mode 100644
index 0000000..b1b9e87
@@ -0,0 +1,403 @@
+/*
+ * Copyright (C) 2014-2015 Samsung Electronics
+ * Przemyslaw Marczak <[email protected]>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+#include <common.h>
+#include <errno.h>
+#include <dm.h>
+#include <dm/uclass-internal.h>
+#include <power/regulator.h>
+
+#define LIMIT_SEQ      3
+#define LIMIT_DEVNAME  20

common/cmd_regulator.c line 24

Quoted 10 lines
common/cmd_regulator.c new file +10 -0
+#define LIMIT_OFNAME   20
+#define LIMIT_INFO     16
+
+static struct udevice *currdev;
+
+static int failed(const char *getset, const char *thing,
+                 const char *for_dev, int ret)
+{
+       printf("Can't %s %s %s.\nError: %d (%s)\n", getset, thing, for_dev,
+                                                   ret, errno_str(ret));

blank line here.

I worry that if someone gets one of these messages they will not be able to find it in the source code. How about passing in the full printf() string in each case, or just using printf() in situ? I don't think the code space saving is significant.

common/cmd_regulator.c line 28

Quoted 4 lines
common/cmd_regulator.c new file +4 -0
+       return CMD_RET_FAILURE;
+}
+
+static int regulator_get(bool list_only, int get_seq, struct udevice **devp)

This function seems to do multiple things (find and list). Should we split it into two?

common/cmd_regulator.c line 38

Quoted 10 lines
common/cmd_regulator.c new file +10 -0
+{
+       struct dm_regulator_uclass_platdata *uc_pdata;
+       struct udevice *dev;
+       int ret;
+
+       if (devp)
+               *devp = NULL;
+
+       for (ret = uclass_first_device(UCLASS_REGULATOR, &dev); dev;
+            ret = uclass_next_device(&dev)) {

This will probe all regulators that it checks. I think it should avoid that. Do you mean to use

Quoted 42 lines
common/cmd_regulator.c new file +42 -0
+               if (list_only) {
+                       uc_pdata = dev_get_uclass_platdata(dev);
+                       printf("|%*d | %*.*s @ %-*.*s| %s @ %s\n",
+                              LIMIT_SEQ, dev->seq,
+                              LIMIT_DEVNAME, LIMIT_DEVNAME, dev->name,
+                              LIMIT_OFNAME, LIMIT_OFNAME, uc_pdata->name,
+                              dev->parent->name,
+                              dev_get_uclass_name(dev->parent));
+                       continue;
+               }
+
+               if (dev->seq == get_seq) {
+                       if (devp)
+                               *devp = dev;
+                       else
+                               return -EINVAL;
+
+                       return 0;
+               }
+       }
+
+       if (list_only)
+               return ret;
+
+       return -ENODEV;
+}
+
+static int do_dev(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       struct dm_regulator_uclass_platdata *uc_pdata;
+       int seq, ret = -ENXIO;
+
+       switch (argc) {
+       case 2:
+               seq = simple_strtoul(argv[1], NULL, 0);
+               ret = uclass_get_device_by_seq(UCLASS_REGULATOR, seq, &currdev);
+               if (ret && (ret = regulator_get(false, seq, &currdev)))
+                       goto failed;
+       case 1:
+               uc_pdata = dev_get_uclass_platdata(currdev);
+               if (!uc_pdata)
+                       goto failed;

common/cmd_regulator.c line 90

Quoted 10 lines
common/cmd_regulator.c new file +10 -0
+
+               printf("dev: %d @ %s\n", currdev->seq, uc_pdata->name);
+       }
+
+       return CMD_RET_SUCCESS;
+failed:
+       return failed("get", "the", "device", ret);
+}
+
+static int get_curr_dev_and_pl(struct udevice **devp,

What is pl? The name does not seem very meaningful to me.

Quoted 314 lines
common/cmd_regulator.c new file +313 -1
+                              struct dm_regulator_uclass_platdata **uc_pdata,
+                              bool allow_type_fixed)
+{
+       *devp = NULL;
+       *uc_pdata = NULL;
+
+       if (!currdev)
+               return failed("get", "current", "device", -ENODEV);
+
+       *devp = currdev;
+
+       *uc_pdata = dev_get_uclass_platdata(*devp);
+       if (!*uc_pdata)
+               return failed("get", "regulator", "platdata", -ENXIO);
+
+       if (!allow_type_fixed && (*uc_pdata)->type == REGULATOR_TYPE_FIXED) {
+               printf("Operation not allowed for fixed regulator!\n");
+               return CMD_RET_FAILURE;
+       }
+
+       return CMD_RET_SUCCESS;
+}
+
+static int do_list(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       int ret;
+
+       printf("|%*s | %*.*s @ %-*.*s| %s @ %s\n",
+              LIMIT_SEQ, "Seq",
+              LIMIT_DEVNAME, LIMIT_DEVNAME, "Name",
+              LIMIT_OFNAME, LIMIT_OFNAME, "fdtname",
+              "Parent", "uclass");
+
+       ret = regulator_get(true, 0, NULL);
+       if (ret)
+               return CMD_RET_FAILURE;
+
+       return CMD_RET_SUCCESS;
+}
+
+static int constraint(const char *name, int val, const char *val_name)
+{
+       printf("%-*s", LIMIT_INFO, name);
+       if (val < 0) {
+               printf(" %s (err: %d)\n", errno_str(val), val);
+               return val;
+       }
+
+       if (val_name)
+               printf(" %d (%s)\n", val, val_name);
+       else
+               printf(" %d\n", val);
+
+       return 0;
+}
+
+static const char *get_mode_name(struct dm_regulator_mode *mode,
+                                int mode_count,
+                                int mode_id)
+{
+       while (mode_count--) {
+               if (mode->id == mode_id)
+                       return mode->name;
+               mode++;
+       }
+
+       return NULL;
+}
+
+static int do_info(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       struct udevice *dev;
+       struct dm_regulator_uclass_platdata *uc_pdata;
+       struct dm_regulator_mode *modes;
+       const char *parent_uc;
+       int mode_count;
+       int ret;
+       int i;
+
+       ret = get_curr_dev_and_pl(&dev, &uc_pdata, true);
+       if (ret)
+               return ret;
+
+       parent_uc = dev_get_uclass_name(dev->parent);
+
+       printf("Uclass regulator dev %d info:\n", dev->seq);
+       printf("%-*s %s @ %s\n%-*s %s\n%-*s %s\n%-*s\n",
+              LIMIT_INFO, "* parent:", dev->parent->name, parent_uc,
+              LIMIT_INFO, "* dev name:", dev->name,
+              LIMIT_INFO, "* fdt name:", uc_pdata->name,
+              LIMIT_INFO, "* constraints:");
+
+       constraint("  - min uV:", uc_pdata->min_uV, NULL);
+       constraint("  - max uV:", uc_pdata->max_uV, NULL);
+       constraint("  - min uA:", uc_pdata->min_uA, NULL);
+       constraint("  - max uA:", uc_pdata->max_uA, NULL);
+       constraint("  - always on:", uc_pdata->always_on,
+                  uc_pdata->always_on ? "true" : "false");
+       constraint("  - boot on:", uc_pdata->boot_on,
+                  uc_pdata->boot_on ? "true" : "false");
+
+       mode_count = regulator_mode(dev, &modes);
+       constraint("* op modes:", mode_count, NULL);
+
+       for (i = 0; i < mode_count; i++, modes++)
+               constraint("  - mode id:", modes->id, modes->name);
+
+       return CMD_RET_SUCCESS;
+}
+
+static int do_status(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       struct dm_regulator_uclass_platdata *uc_pdata;
+       int current, value, mode, ret;
+       const char *mode_name = NULL;
+       struct udevice *dev;
+       bool enabled;
+
+       ret = get_curr_dev_and_pl(&dev, &uc_pdata, true);
+       if (ret)
+               return ret;
+
+       enabled = regulator_get_enable(dev);
+       constraint(" * enable:", enabled, enabled ? "true" : "false");
+
+       value = regulator_get_value(dev);
+       constraint(" * value uV:", value, NULL);
+
+       current = regulator_get_current(dev);
+       constraint(" * current uA:", current, NULL);
+
+       mode = regulator_get_mode(dev);
+       mode_name = get_mode_name(uc_pdata->mode, uc_pdata->mode_count, mode);
+       constraint(" * mode id:", mode, mode_name);
+
+       return CMD_RET_SUCCESS;
+}
+
+static int do_value(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       struct udevice *dev;
+       struct dm_regulator_uclass_platdata *uc_pdata;
+       int value;
+       int force;
+       int ret;
+
+       ret = get_curr_dev_and_pl(&dev, &uc_pdata, argc == 1);
+       if (ret)
+               return ret;
+
+       if (argc == 1) {
+               value = regulator_get_value(dev);
+               if (value < 0)
+                       return failed("get", uc_pdata->name, "voltage", value);
+
+               printf("%d uV\n", value);
+               return CMD_RET_SUCCESS;
+       }
+
+       if (argc == 3)
+               force = !strcmp("-f", argv[2]);
+       else
+               force = 0;
+
+       value = simple_strtoul(argv[1], NULL, 0);
+       if ((value < uc_pdata->min_uV || value > uc_pdata->max_uV) && !force) {
+               printf("Value exceeds regulator constraint limits\n");
+               return CMD_RET_FAILURE;
+       }
+
+       ret = regulator_set_value(dev, value);
+       if (ret)
+               return failed("set", uc_pdata->name, "voltage value", ret);
+
+       return CMD_RET_SUCCESS;
+}
+
+static int do_current(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       struct udevice *dev;
+       struct dm_regulator_uclass_platdata *uc_pdata;
+       int current;
+       int ret;
+
+       ret = get_curr_dev_and_pl(&dev, &uc_pdata, argc == 1);
+       if (ret)
+               return ret;
+
+       if (argc == 1) {
+               current = regulator_get_current(dev);
+               if (current < 0)
+                       return failed("get", uc_pdata->name, "current", current);
+
+               printf("%d uA\n", current);
+               return CMD_RET_SUCCESS;
+       }
+
+       current = simple_strtoul(argv[1], NULL, 0);
+       if (current < uc_pdata->min_uA || current > uc_pdata->max_uA) {
+               printf("Current exceeds regulator constraint limits\n");
+               return CMD_RET_FAILURE;
+       }
+
+       ret = regulator_set_current(dev, current);
+       if (ret)
+               return failed("set", uc_pdata->name, "current value", ret);
+
+       return CMD_RET_SUCCESS;
+}
+
+static int do_mode(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       struct udevice *dev;
+       struct dm_regulator_uclass_platdata *uc_pdata;
+       int new_mode;
+       int mode;
+       int ret;
+
+       ret = get_curr_dev_and_pl(&dev, &uc_pdata, false);
+       if (ret)
+               return ret;
+
+       if (argc == 1) {
+               mode = regulator_get_mode(dev);
+               if (mode < 0)
+                       return failed("get", uc_pdata->name, "mode", mode);
+
+               printf("mode id: %d\n", mode);
+               return CMD_RET_SUCCESS;
+       }
+
+       new_mode = simple_strtoul(argv[1], NULL, 0);
+
+       ret = regulator_set_mode(dev, new_mode);
+       if (ret)
+               return failed("set", uc_pdata->name, "mode", ret);
+
+       return CMD_RET_SUCCESS;
+}
+
+static int do_enable(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       struct udevice *dev;
+       struct dm_regulator_uclass_platdata *uc_pdata;
+       int ret;
+
+       ret = get_curr_dev_and_pl(&dev, &uc_pdata, true);
+       if (ret)
+               return ret;
+
+       ret = regulator_set_enable(dev, true);
+       if (ret)
+               return failed("enable", "regulator", uc_pdata->name, ret);
+
+       return CMD_RET_SUCCESS;
+}
+
+static int do_disable(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       struct udevice *dev;
+       struct dm_regulator_uclass_platdata *uc_pdata;
+       int ret;
+
+       ret = get_curr_dev_and_pl(&dev, &uc_pdata, true);
+       if (ret)
+               return ret;
+
+       ret = regulator_set_enable(dev, false);
+       if (ret)
+               return failed("disable", "regulator", uc_pdata->name, ret);
+
+       return CMD_RET_SUCCESS;
+}
+
+static cmd_tbl_t subcmd[] = {
+       U_BOOT_CMD_MKENT(dev, 2, 1, do_dev, "", ""),
+       U_BOOT_CMD_MKENT(list, 1, 1, do_list, "", ""),
+       U_BOOT_CMD_MKENT(info, 2, 1, do_info, "", ""),
+       U_BOOT_CMD_MKENT(status, 2, 1, do_status, "", ""),
+       U_BOOT_CMD_MKENT(value, 3, 1, do_value, "", ""),
+       U_BOOT_CMD_MKENT(current, 3, 1, do_current, "", ""),
+       U_BOOT_CMD_MKENT(mode, 2, 1, do_mode, "", ""),
+       U_BOOT_CMD_MKENT(enable, 1, 1, do_enable, "", ""),
+       U_BOOT_CMD_MKENT(disable, 1, 1, do_disable, "", ""),
+};
+
+static int do_regulator(cmd_tbl_t *cmdtp, int flag, int argc,
+                       char * const argv[])
+{
+       cmd_tbl_t *cmd;
+
+       argc--;
+       argv++;
+
+       cmd = find_cmd_tbl(argv[0], subcmd, ARRAY_SIZE(subcmd));
+       if (cmd == NULL || argc > cmd->maxargs)
+               return CMD_RET_USAGE;
+
+       return cmd->cmd(cmdtp, flag, argc, argv);
+}
+
+U_BOOT_CMD(regulator, CONFIG_SYS_MAXARGS, 1, do_regulator,
+       "uclass operations",
+       "list         - list UCLASS regulator devices\n"
+       "regulator dev [id]     - show or [set] operating regulator device\n"
+       "regulator [info]       - print constraints info\n"
+       "regulator [status]     - print operating status\n"
+       "regulator [value] [-f] - print/[set] voltage value [uV] (force)\n"
+       "regulator [current]    - print/[set] current value [uA]\n"
+       "regulator [mode_id]    - print/[set] operating mode id\n"
+       "regulator [enable]     - enable the regulator output\n"
+       "regulator [disable]    - disable the regulator output\n"
+);
--
Quoted 2 lines

1.9.1

Regards,
Simon

#174 lore raw

PATCH v4 7/16 dm: regulator: add regulator command

Quoted 37 lines · Simon Glass

Hi Przemyslaw,

Quoted 27 lines · Przemyslaw Marczak

This command is based on driver model regulator's API. The user interface provides:
- list UCLASS regulator devices
- show or [set] operating regulator device
- print constraints info
- print operating status
- print/[set] voltage value [uV] (force)
- print/[set] current value [uA]
- print/[set] operating mode id
- enable the regulator output
- disable the regulator output

The 'force' option can be used for setting the value which exceeds the constraints min/max limits.

---
Changes v3:
- new file
- Kconfig entry

Changes V4:
- cmd regulator: move platdata to uc pdata
- cmd_regulator: includes cleanup
- cmd_regulator: add get_curr_dev_and_pl() check type
- move config name: CONFIG_DM_REGULATOR_CMD to CONFIG_CMD_REGULATOR
- common/Kconfig - cleanup

Quoted 6 lines
---
 common/Kconfig         |  22 +++
 common/Makefile        |   1 +
 common/cmd_regulator.c | 403 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 426 insertions(+)
 create mode 100644 common/cmd_regulator.c
Quoted 3 lines

I have a few nits that could be dealt with by a follow-on patch.

Applied to u-boot-dm/next, thanks!

#175 lore raw

PATCH v4 7/16 dm: regulator: add regulator command

In reply to Simon Glass

Hello Simon,

Quoted 37 lines · Simon Glass

Hi Przemyslaw,

Quoted 27 lines · Przemyslaw Marczak

This command is based on driver model regulator's API. The user interface provides:
- list UCLASS regulator devices
- show or [set] operating regulator device
- print constraints info
- print operating status
- print/[set] voltage value [uV] (force)
- print/[set] current value [uA]
- print/[set] operating mode id
- enable the regulator output
- disable the regulator output

The 'force' option can be used for setting the value which exceeds the constraints min/max limits.

---
Changes v3:
- new file
- Kconfig entry

Changes V4:
- cmd regulator: move platdata to uc pdata
- cmd_regulator: includes cleanup
- cmd_regulator: add get_curr_dev_and_pl() check type
- move config name: CONFIG_DM_REGULATOR_CMD to CONFIG_CMD_REGULATOR
- common/Kconfig - cleanup

Quoted 6 lines
---
  common/Kconfig         |  22 +++
  common/Makefile        |   1 +
  common/cmd_regulator.c | 403 +++++++++++++++++++++++++++++++++++++++++++++++++
  3 files changed, 426 insertions(+)

create mode 100644 common/cmd_regulator.c

Quoted 4 lines

I have a few nits that could be dealt with by a follow-on patch.

Ok.

Quoted 69 lines
Quoted 69 lines
common/Kconfig +22 -0
index 4666f8e..52f8bb1 100644
@@ -470,5 +470,27 @@ config CMD_PMIC
           - pmic read address  - read byte of register at address
           - pmic write address - write byte to register at address
           The only one change for this command is 'dev' subcommand.
+
+config CMD_REGULATOR
+       bool "Enable Driver Model REGULATOR command"
+       depends on DM_REGULATOR
+       help
+         This command is based on driver model regulator's API.
+         User interface features:
+         - list               - list regulator devices
+         - regulator dev <id> - show or [set] operating regulator device
+         - regulator info     - print constraints info
+         - regulator status   - print operating status
+         - regulator value <val] <-f> - print/[set] voltage value [uV]
+         - regulator current <val>    - print/[set] current value [uA]
+         - regulator mode <id>        - print/[set] operating mode id
+         - regulator enable           - enable the regulator output
+         - regulator disable          - disable the regulator output
+
+         The '-f' (force) option can be used for set the value which exceeds
+         the limits, which are found in device-tree and are kept in regulator's
+         uclass platdata structure.
+
  endmenu
+
  endmenu
common/Makefile +1 -0
index 87a3efe..93bded3 100644
@@ -212,6 +212,7 @@ obj-$(CONFIG_CMD_GPT) += cmd_gpt.o
 
  # Power
  obj-$(CONFIG_CMD_PMIC) += cmd_pmic.o
+obj-$(CONFIG_CMD_REGULATOR) += cmd_regulator.o
  endif
 
  ifdef CONFIG_SPL_BUILD
common/cmd_regulator.c new file +18 -0
new file mode 100644
index 0000000..b1b9e87
@@ -0,0 +1,403 @@
+/*
+ * Copyright (C) 2014-2015 Samsung Electronics
+ * Przemyslaw Marczak <[email protected]>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+#include <common.h>
+#include <errno.h>
+#include <dm.h>
+#include <dm/uclass-internal.h>
+#include <power/regulator.h>
+
+#define LIMIT_SEQ      3
+#define LIMIT_DEVNAME  20
+#define LIMIT_OFNAME   20
+#define LIMIT_INFO     16
+
+static struct udevice *currdev;
Quoted 8 lines

common/cmd_regulator.c line 24

Quoted 6 lines
common/cmd_regulator.c new file +6 -0
+
+static int failed(const char *getset, const char *thing,
+                 const char *for_dev, int ret)
+{
+       printf("Can't %s %s %s.\nError: %d (%s)\n", getset, thing, for_dev,
+                                                   ret, errno_str(ret));

blank line here.

I don't see the blank line here in the patch, which I send.

Quoted 6 lines

I worry that if someone gets one of these messages they will not be able to find it in the source code. How about passing in the full printf() string in each case, or just using printf() in situ? I don't think the code space saving is significant.

It's not a debug message. And each one is different, and easy to grep "failed". The code is a little cleaner with this. Also the command code is not complicated.

Quoted 8 lines

common/cmd_regulator.c line 28

Quoted 4 lines
common/cmd_regulator.c new file +4 -0
+       return CMD_RET_FAILURE;
+}
+
+static int regulator_get(bool list_only, int get_seq, struct udevice **devp)

This function seems to do multiple things (find and list). Should we split it into two?

Quoted 14 lines

common/cmd_regulator.c line 38

Quoted 10 lines
common/cmd_regulator.c new file +10 -0
+{
+       struct dm_regulator_uclass_platdata *uc_pdata;
+       struct udevice *dev;
+       int ret;
+
+       if (devp)
+               *devp = NULL;
+
+       for (ret = uclass_first_device(UCLASS_REGULATOR, &dev); dev;
+            ret = uclass_next_device(&dev)) {

This will probe all regulators that it checks. I think it should avoid that. Do you mean to use

Regarding the two above comments, we have two problems:

1. Getting the regulator by sequencial number (dev->seq). I think it's required, because only this method returns the right device. Disadvantage: need to probe all devices.

2. Getting the regulator by "regulator-name" (regulator_uclass_platdata->name).
This would be clean, but unreliable if we have few regulators with the same name - I think we should keep this in mind. Advantage: can use for non-probed devices.

And about the doing multiple things by the regulator_get(). Following your comments about avoiding the code duplication, I put those things into one function, since both actually do the same - loops over the uclass's devices.

So we can threat it as a subcommands:
- regulator_get list
- regulator_get dev
Maybe the enum { GET_LIST, GET_DEV } would be better, than the bool.

Is that really bad?

Quoted 46 lines
Quoted 46 lines
common/cmd_regulator.c new file +46 -0
+               if (list_only) {
+                       uc_pdata = dev_get_uclass_platdata(dev);
+                       printf("|%*d | %*.*s @ %-*.*s| %s @ %s\n",
+                              LIMIT_SEQ, dev->seq,
+                              LIMIT_DEVNAME, LIMIT_DEVNAME, dev->name,
+                              LIMIT_OFNAME, LIMIT_OFNAME, uc_pdata->name,
+                              dev->parent->name,
+                              dev_get_uclass_name(dev->parent));
+                       continue;
+               }
+
+               if (dev->seq == get_seq) {
+                       if (devp)
+                               *devp = dev;
+                       else
+                               return -EINVAL;
+
+                       return 0;
+               }
+       }
+
+       if (list_only)
+               return ret;
+
+       return -ENODEV;
+}
+
+static int do_dev(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       struct dm_regulator_uclass_platdata *uc_pdata;
+       int seq, ret = -ENXIO;
+
+       switch (argc) {
+       case 2:
+               seq = simple_strtoul(argv[1], NULL, 0);
+               ret = uclass_get_device_by_seq(UCLASS_REGULATOR, seq, &currdev);
+               if (ret && (ret = regulator_get(false, seq, &currdev)))
+                       goto failed;
+       case 1:
+               uc_pdata = dev_get_uclass_platdata(currdev);
+               if (!uc_pdata)
+                       goto failed;
+
+               printf("dev: %d @ %s\n", currdev->seq, uc_pdata->name);
+       }
+
Quoted 9 lines

common/cmd_regulator.c line 90

Quoted 6 lines
common/cmd_regulator.c new file +6 -0
+       return CMD_RET_SUCCESS;
+failed:
+       return failed("get", "the", "device", ret);
+}
+
+static int get_curr_dev_and_pl(struct udevice **devp,

What is pl? The name does not seem very meaningful to me.

The platdata, ok I will tune it.

Quoted 311 lines
Quoted 311 lines
common/cmd_regulator.c new file +311 -0
+                              struct dm_regulator_uclass_platdata **uc_pdata,
+                              bool allow_type_fixed)
+{
+       *devp = NULL;
+       *uc_pdata = NULL;
+
+       if (!currdev)
+               return failed("get", "current", "device", -ENODEV);
+
+       *devp = currdev;
+
+       *uc_pdata = dev_get_uclass_platdata(*devp);
+       if (!*uc_pdata)
+               return failed("get", "regulator", "platdata", -ENXIO);
+
+       if (!allow_type_fixed && (*uc_pdata)->type == REGULATOR_TYPE_FIXED) {
+               printf("Operation not allowed for fixed regulator!\n");
+               return CMD_RET_FAILURE;
+       }
+
+       return CMD_RET_SUCCESS;
+}
+
+static int do_list(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       int ret;
+
+       printf("|%*s | %*.*s @ %-*.*s| %s @ %s\n",
+              LIMIT_SEQ, "Seq",
+              LIMIT_DEVNAME, LIMIT_DEVNAME, "Name",
+              LIMIT_OFNAME, LIMIT_OFNAME, "fdtname",
+              "Parent", "uclass");
+
+       ret = regulator_get(true, 0, NULL);
+       if (ret)
+               return CMD_RET_FAILURE;
+
+       return CMD_RET_SUCCESS;
+}
+
+static int constraint(const char *name, int val, const char *val_name)
+{
+       printf("%-*s", LIMIT_INFO, name);
+       if (val < 0) {
+               printf(" %s (err: %d)\n", errno_str(val), val);
+               return val;
+       }
+
+       if (val_name)
+               printf(" %d (%s)\n", val, val_name);
+       else
+               printf(" %d\n", val);
+
+       return 0;
+}
+
+static const char *get_mode_name(struct dm_regulator_mode *mode,
+                                int mode_count,
+                                int mode_id)
+{
+       while (mode_count--) {
+               if (mode->id == mode_id)
+                       return mode->name;
+               mode++;
+       }
+
+       return NULL;
+}
+
+static int do_info(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       struct udevice *dev;
+       struct dm_regulator_uclass_platdata *uc_pdata;
+       struct dm_regulator_mode *modes;
+       const char *parent_uc;
+       int mode_count;
+       int ret;
+       int i;
+
+       ret = get_curr_dev_and_pl(&dev, &uc_pdata, true);
+       if (ret)
+               return ret;
+
+       parent_uc = dev_get_uclass_name(dev->parent);
+
+       printf("Uclass regulator dev %d info:\n", dev->seq);
+       printf("%-*s %s @ %s\n%-*s %s\n%-*s %s\n%-*s\n",
+              LIMIT_INFO, "* parent:", dev->parent->name, parent_uc,
+              LIMIT_INFO, "* dev name:", dev->name,
+              LIMIT_INFO, "* fdt name:", uc_pdata->name,
+              LIMIT_INFO, "* constraints:");
+
+       constraint("  - min uV:", uc_pdata->min_uV, NULL);
+       constraint("  - max uV:", uc_pdata->max_uV, NULL);
+       constraint("  - min uA:", uc_pdata->min_uA, NULL);
+       constraint("  - max uA:", uc_pdata->max_uA, NULL);
+       constraint("  - always on:", uc_pdata->always_on,
+                  uc_pdata->always_on ? "true" : "false");
+       constraint("  - boot on:", uc_pdata->boot_on,
+                  uc_pdata->boot_on ? "true" : "false");
+
+       mode_count = regulator_mode(dev, &modes);
+       constraint("* op modes:", mode_count, NULL);
+
+       for (i = 0; i < mode_count; i++, modes++)
+               constraint("  - mode id:", modes->id, modes->name);
+
+       return CMD_RET_SUCCESS;
+}
+
+static int do_status(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       struct dm_regulator_uclass_platdata *uc_pdata;
+       int current, value, mode, ret;
+       const char *mode_name = NULL;
+       struct udevice *dev;
+       bool enabled;
+
+       ret = get_curr_dev_and_pl(&dev, &uc_pdata, true);
+       if (ret)
+               return ret;
+
+       enabled = regulator_get_enable(dev);
+       constraint(" * enable:", enabled, enabled ? "true" : "false");
+
+       value = regulator_get_value(dev);
+       constraint(" * value uV:", value, NULL);
+
+       current = regulator_get_current(dev);
+       constraint(" * current uA:", current, NULL);
+
+       mode = regulator_get_mode(dev);
+       mode_name = get_mode_name(uc_pdata->mode, uc_pdata->mode_count, mode);
+       constraint(" * mode id:", mode, mode_name);
+
+       return CMD_RET_SUCCESS;
+}
+
+static int do_value(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       struct udevice *dev;
+       struct dm_regulator_uclass_platdata *uc_pdata;
+       int value;
+       int force;
+       int ret;
+
+       ret = get_curr_dev_and_pl(&dev, &uc_pdata, argc == 1);
+       if (ret)
+               return ret;
+
+       if (argc == 1) {
+               value = regulator_get_value(dev);
+               if (value < 0)
+                       return failed("get", uc_pdata->name, "voltage", value);
+
+               printf("%d uV\n", value);
+               return CMD_RET_SUCCESS;
+       }
+
+       if (argc == 3)
+               force = !strcmp("-f", argv[2]);
+       else
+               force = 0;
+
+       value = simple_strtoul(argv[1], NULL, 0);
+       if ((value < uc_pdata->min_uV || value > uc_pdata->max_uV) && !force) {
+               printf("Value exceeds regulator constraint limits\n");
+               return CMD_RET_FAILURE;
+       }
+
+       ret = regulator_set_value(dev, value);
+       if (ret)
+               return failed("set", uc_pdata->name, "voltage value", ret);
+
+       return CMD_RET_SUCCESS;
+}
+
+static int do_current(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       struct udevice *dev;
+       struct dm_regulator_uclass_platdata *uc_pdata;
+       int current;
+       int ret;
+
+       ret = get_curr_dev_and_pl(&dev, &uc_pdata, argc == 1);
+       if (ret)
+               return ret;
+
+       if (argc == 1) {
+               current = regulator_get_current(dev);
+               if (current < 0)
+                       return failed("get", uc_pdata->name, "current", current);
+
+               printf("%d uA\n", current);
+               return CMD_RET_SUCCESS;
+       }
+
+       current = simple_strtoul(argv[1], NULL, 0);
+       if (current < uc_pdata->min_uA || current > uc_pdata->max_uA) {
+               printf("Current exceeds regulator constraint limits\n");
+               return CMD_RET_FAILURE;
+       }
+
+       ret = regulator_set_current(dev, current);
+       if (ret)
+               return failed("set", uc_pdata->name, "current value", ret);
+
+       return CMD_RET_SUCCESS;
+}
+
+static int do_mode(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       struct udevice *dev;
+       struct dm_regulator_uclass_platdata *uc_pdata;
+       int new_mode;
+       int mode;
+       int ret;
+
+       ret = get_curr_dev_and_pl(&dev, &uc_pdata, false);
+       if (ret)
+               return ret;
+
+       if (argc == 1) {
+               mode = regulator_get_mode(dev);
+               if (mode < 0)
+                       return failed("get", uc_pdata->name, "mode", mode);
+
+               printf("mode id: %d\n", mode);
+               return CMD_RET_SUCCESS;
+       }
+
+       new_mode = simple_strtoul(argv[1], NULL, 0);
+
+       ret = regulator_set_mode(dev, new_mode);
+       if (ret)
+               return failed("set", uc_pdata->name, "mode", ret);
+
+       return CMD_RET_SUCCESS;
+}
+
+static int do_enable(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       struct udevice *dev;
+       struct dm_regulator_uclass_platdata *uc_pdata;
+       int ret;
+
+       ret = get_curr_dev_and_pl(&dev, &uc_pdata, true);
+       if (ret)
+               return ret;
+
+       ret = regulator_set_enable(dev, true);
+       if (ret)
+               return failed("enable", "regulator", uc_pdata->name, ret);
+
+       return CMD_RET_SUCCESS;
+}
+
+static int do_disable(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       struct udevice *dev;
+       struct dm_regulator_uclass_platdata *uc_pdata;
+       int ret;
+
+       ret = get_curr_dev_and_pl(&dev, &uc_pdata, true);
+       if (ret)
+               return ret;
+
+       ret = regulator_set_enable(dev, false);
+       if (ret)
+               return failed("disable", "regulator", uc_pdata->name, ret);
+
+       return CMD_RET_SUCCESS;
+}
+
+static cmd_tbl_t subcmd[] = {
+       U_BOOT_CMD_MKENT(dev, 2, 1, do_dev, "", ""),
+       U_BOOT_CMD_MKENT(list, 1, 1, do_list, "", ""),
+       U_BOOT_CMD_MKENT(info, 2, 1, do_info, "", ""),
+       U_BOOT_CMD_MKENT(status, 2, 1, do_status, "", ""),
+       U_BOOT_CMD_MKENT(value, 3, 1, do_value, "", ""),
+       U_BOOT_CMD_MKENT(current, 3, 1, do_current, "", ""),
+       U_BOOT_CMD_MKENT(mode, 2, 1, do_mode, "", ""),
+       U_BOOT_CMD_MKENT(enable, 1, 1, do_enable, "", ""),
+       U_BOOT_CMD_MKENT(disable, 1, 1, do_disable, "", ""),
+};
+
+static int do_regulator(cmd_tbl_t *cmdtp, int flag, int argc,
+                       char * const argv[])
+{
+       cmd_tbl_t *cmd;
+
+       argc--;
+       argv++;
+
+       cmd = find_cmd_tbl(argv[0], subcmd, ARRAY_SIZE(subcmd));
+       if (cmd == NULL || argc > cmd->maxargs)
+               return CMD_RET_USAGE;
+
+       return cmd->cmd(cmdtp, flag, argc, argv);
+}
+
+U_BOOT_CMD(regulator, CONFIG_SYS_MAXARGS, 1, do_regulator,
+       "uclass operations",
+       "list         - list UCLASS regulator devices\n"
+       "regulator dev [id]     - show or [set] operating regulator device\n"
+       "regulator [info]       - print constraints info\n"
+       "regulator [status]     - print operating status\n"
+       "regulator [value] [-f] - print/[set] voltage value [uV] (force)\n"
+       "regulator [current]    - print/[set] current value [uA]\n"
+       "regulator [mode_id]    - print/[set] operating mode id\n"
+       "regulator [enable]     - enable the regulator output\n"
Quoted 9 lines
Quoted 5 lines
common/cmd_regulator.c new file +2 -1
+       "regulator [disable]    - disable the regulator output\n"
+);
--

1.9.1

Regards,
Simon

Best regards,

Signature · 4 lines
Przemyslaw Marczak
Samsung R&D Institute Poland
Samsung Electronics
p.marczak at samsung.com
#176 lore raw

PATCH v4 7/16 dm: regulator: add regulator command

Hi Przemyslaw,

Quoted 137 lines · Przemyslaw Marczak

Hello Simon,

Quoted 42 lines · Simon Glass

Hi Przemyslaw,

Quoted 28 lines · Przemyslaw Marczak

This command is based on driver model regulator's API. The user interface provides:
- list UCLASS regulator devices
- show or [set] operating regulator device
- print constraints info
- print operating status
- print/[set] voltage value [uV] (force)
- print/[set] current value [uA]
- print/[set] operating mode id
- enable the regulator output
- disable the regulator output

The 'force' option can be used for setting the value which exceeds the constraints min/max limits.

---
Changes v3:
- new file
- Kconfig entry

Changes V4:
- cmd regulator: move platdata to uc pdata
- cmd_regulator: includes cleanup
- cmd_regulator: add get_curr_dev_and_pl() check type
- move config name: CONFIG_DM_REGULATOR_CMD to CONFIG_CMD_REGULATOR
- common/Kconfig - cleanup

Quoted 7 lines
---
  common/Kconfig         |  22 +++
  common/Makefile        |   1 +
  common/cmd_regulator.c | 403
+++++++++++++++++++++++++++++++++++++++++++++++++
  3 files changed, 426 insertions(+)

create mode 100644 common/cmd_regulator.c

Quoted 4 lines

I have a few nits that could be dealt with by a follow-on patch.

Ok.

Quoted 73 lines
Quoted 73 lines
common/Kconfig +18 -0
index 4666f8e..52f8bb1 100644
@@ -470,5 +470,27 @@ config CMD_PMIC
           - pmic read address  - read byte of register at address
           - pmic write address - write byte to register at address
           The only one change for this command is 'dev' subcommand.
+
+config CMD_REGULATOR
+       bool "Enable Driver Model REGULATOR command"
+       depends on DM_REGULATOR
+       help
+         This command is based on driver model regulator's API.
+         User interface features:
+         - list               - list regulator devices
+         - regulator dev <id> - show or [set] operating regulator device
+         - regulator info     - print constraints info
+         - regulator status   - print operating status
+         - regulator value <val] <-f> - print/[set] voltage value [uV]
+         - regulator current <val>    - print/[set] current value [uA]
+         - regulator mode <id>        - print/[set] operating mode id
+         - regulator enable           - enable the regulator output
+         - regulator disable          - disable the regulator output
+
+         The '-f' (force) option can be used for set the value which

exceeds
+ the limits, which are found in device-tree and are kept in
regulator's

common/Kconfig +3 -0
+         uclass platdata structure.
+
  endmenu
+
  endmenu
common/Makefile +1 -0
index 87a3efe..93bded3 100644
@@ -212,6 +212,7 @@ obj-$(CONFIG_CMD_GPT) += cmd_gpt.o
 
  # Power
  obj-$(CONFIG_CMD_PMIC) += cmd_pmic.o
+obj-$(CONFIG_CMD_REGULATOR) += cmd_regulator.o
  endif
 
  ifdef CONFIG_SPL_BUILD
common/cmd_regulator.c new file +20 -0
new file mode 100644
index 0000000..b1b9e87
@@ -0,0 +1,403 @@
+/*
+ * Copyright (C) 2014-2015 Samsung Electronics
+ * Przemyslaw Marczak <[email protected]>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+#include <common.h>
+#include <errno.h>
+#include <dm.h>
+#include <dm/uclass-internal.h>
+#include <power/regulator.h>
+
+#define LIMIT_SEQ      3
+#define LIMIT_DEVNAME  20
+#define LIMIT_OFNAME   20
+#define LIMIT_INFO     16
+
+static struct udevice *currdev;
+
+static int failed(const char *getset, const char *thing,
Quoted 8 lines
Quoted 5 lines
common/cmd_regulator.c new file +3 -0
+                 const char *for_dev, int ret)
+{
+       printf("Can't %s %s %s.\nError: %d (%s)\n", getset, thing,

for_dev,
+ ret, errno_str(ret));

blank line here.

Quoted 1 line

I don't see the blank line here in the patch, which I send.

Odd, there seem to be two blank lines there, and we only need one.

Quoted 11 lines
Quoted 7 lines

I worry that if someone gets one of these messages they will not be able to find it in the source code. How about passing in the full printf() string in each case, or just using printf() in situ? I don't think the code space saving is significant.

It's not a debug message. And each one is different, and easy to grep "failed". The code is a little cleaner with this. Also the command code is not complicated.

git grep -i failed |wc -l
2089

Is there some way to know it is a PMIC error message, and find it that way?

Quoted 27 lines
Quoted 11 lines
Quoted 6 lines
common/cmd_regulator.c new file +4 -0
+       return CMD_RET_FAILURE;
+}
+
+static int regulator_get(bool list_only, int get_seq, struct udevice

**devp)

This function seems to do multiple things (find and list). Should we split it into two?

Quoted 15 lines

common/cmd_regulator.c line 38

Quoted 10 lines
common/cmd_regulator.c new file +10 -0
+{
+       struct dm_regulator_uclass_platdata *uc_pdata;
+       struct udevice *dev;
+       int ret;
+
+       if (devp)
+               *devp = NULL;
+
+       for (ret = uclass_first_device(UCLASS_REGULATOR, &dev); dev;
+            ret = uclass_next_device(&dev)) {

This will probe all regulators that it checks. I think it should avoid that. Do you mean to use

Quoted 5 lines

Regarding the two above comments, we have two problems:

1. Getting the regulator by sequencial number (dev->seq).
I think it's required, because only this method returns the right device.
Disadvantage: need to probe all devices.

But you can use req_seq, or if you have platform data, check that.

Quoted 6 lines

2. Getting the regulator by "regulator-name" (regulator_uclass_platdata->name).
This would be clean, but unreliable if we have few regulators with the same name - I think we should keep this in mind. Advantage: can use for non-probed devices.

We could probably refuse to bind regulators with the same name. That's just going to lead to confusion.

Quoted 6 lines

And about the doing multiple things by the regulator_get(). Following your comments about avoiding the code duplication, I put those things into one function, since both actually do the same - loops over the uclass's devices.

Quoted 6 lines

So we can threat it as a subcommands:
- regulator_get list
- regulator_get dev
Maybe the enum { GET_LIST, GET_DEV } would be better, than the bool.

Is that really bad?

I suspect it would be better as two completely separate functions, and probably not much more code size.

Quoted 394 lines
Quoted 52 lines
Quoted 52 lines
common/cmd_regulator.c new file +6 -0
+               if (list_only) {
+                       uc_pdata = dev_get_uclass_platdata(dev);
+                       printf("|%*d | %*.*s @ %-*.*s| %s @ %s\n",
+                              LIMIT_SEQ, dev->seq,
+                              LIMIT_DEVNAME, LIMIT_DEVNAME, dev->name,
+                              LIMIT_OFNAME, LIMIT_OFNAME,

uc_pdata->name,

common/cmd_regulator.c new file +22 -0
+                              dev->parent->name,
+                              dev_get_uclass_name(dev->parent));
+                       continue;
+               }
+
+               if (dev->seq == get_seq) {
+                       if (devp)
+                               *devp = dev;
+                       else
+                               return -EINVAL;
+
+                       return 0;
+               }
+       }
+
+       if (list_only)
+               return ret;
+
+       return -ENODEV;
+}
+
+static int do_dev(cmd_tbl_t *cmdtp, int flag, int argc, char * const

argv[])

common/cmd_regulator.c new file +8 -0
+{
+       struct dm_regulator_uclass_platdata *uc_pdata;
+       int seq, ret = -ENXIO;
+
+       switch (argc) {
+       case 2:
+               seq = simple_strtoul(argv[1], NULL, 0);
+               ret = uclass_get_device_by_seq(UCLASS_REGULATOR, seq,

&currdev);

common/cmd_regulator.c new file +11 -0
+               if (ret && (ret = regulator_get(false, seq, &currdev)))
+                       goto failed;
+       case 1:
+               uc_pdata = dev_get_uclass_platdata(currdev);
+               if (!uc_pdata)
+                       goto failed;
+
+               printf("dev: %d @ %s\n", currdev->seq, uc_pdata->name);
+       }
+
+       return CMD_RET_SUCCESS;
Quoted 9 lines

common/cmd_regulator.c line 90

Quoted 5 lines
common/cmd_regulator.c new file +5 -0
+failed:
+       return failed("get", "the", "device", ret);
+}
+
+static int get_curr_dev_and_pl(struct udevice **devp,

What is pl? The name does not seem very meaningful to me.

The platdata, ok I will tune it.

Quoted 329 lines
Quoted 329 lines

+ struct dm_regulator_uclass_platdata
**uc_pdata,

common/cmd_regulator.c new file +15 -0
+                              bool allow_type_fixed)
+{
+       *devp = NULL;
+       *uc_pdata = NULL;
+
+       if (!currdev)
+               return failed("get", "current", "device", -ENODEV);
+
+       *devp = currdev;
+
+       *uc_pdata = dev_get_uclass_platdata(*devp);
+       if (!*uc_pdata)
+               return failed("get", "regulator", "platdata", -ENXIO);
+
+       if (!allow_type_fixed && (*uc_pdata)->type ==

REGULATOR_TYPE_FIXED) {

common/cmd_regulator.c new file +8 -0
+               printf("Operation not allowed for fixed regulator!\n");
+               return CMD_RET_FAILURE;
+       }
+
+       return CMD_RET_SUCCESS;
+}
+
+static int do_list(cmd_tbl_t *cmdtp, int flag, int argc, char * const

argv[])

common/cmd_regulator.c new file +46 -0
+{
+       int ret;
+
+       printf("|%*s | %*.*s @ %-*.*s| %s @ %s\n",
+              LIMIT_SEQ, "Seq",
+              LIMIT_DEVNAME, LIMIT_DEVNAME, "Name",
+              LIMIT_OFNAME, LIMIT_OFNAME, "fdtname",
+              "Parent", "uclass");
+
+       ret = regulator_get(true, 0, NULL);
+       if (ret)
+               return CMD_RET_FAILURE;
+
+       return CMD_RET_SUCCESS;
+}
+
+static int constraint(const char *name, int val, const char *val_name)
+{
+       printf("%-*s", LIMIT_INFO, name);
+       if (val < 0) {
+               printf(" %s (err: %d)\n", errno_str(val), val);
+               return val;
+       }
+
+       if (val_name)
+               printf(" %d (%s)\n", val, val_name);
+       else
+               printf(" %d\n", val);
+
+       return 0;
+}
+
+static const char *get_mode_name(struct dm_regulator_mode *mode,
+                                int mode_count,
+                                int mode_id)
+{
+       while (mode_count--) {
+               if (mode->id == mode_id)
+                       return mode->name;
+               mode++;
+       }
+
+       return NULL;
+}
+
+static int do_info(cmd_tbl_t *cmdtp, int flag, int argc, char * const

argv[])

common/cmd_regulator.c new file +41 -0
+{
+       struct udevice *dev;
+       struct dm_regulator_uclass_platdata *uc_pdata;
+       struct dm_regulator_mode *modes;
+       const char *parent_uc;
+       int mode_count;
+       int ret;
+       int i;
+
+       ret = get_curr_dev_and_pl(&dev, &uc_pdata, true);
+       if (ret)
+               return ret;
+
+       parent_uc = dev_get_uclass_name(dev->parent);
+
+       printf("Uclass regulator dev %d info:\n", dev->seq);
+       printf("%-*s %s @ %s\n%-*s %s\n%-*s %s\n%-*s\n",
+              LIMIT_INFO, "* parent:", dev->parent->name, parent_uc,
+              LIMIT_INFO, "* dev name:", dev->name,
+              LIMIT_INFO, "* fdt name:", uc_pdata->name,
+              LIMIT_INFO, "* constraints:");
+
+       constraint("  - min uV:", uc_pdata->min_uV, NULL);
+       constraint("  - max uV:", uc_pdata->max_uV, NULL);
+       constraint("  - min uA:", uc_pdata->min_uA, NULL);
+       constraint("  - max uA:", uc_pdata->max_uA, NULL);
+       constraint("  - always on:", uc_pdata->always_on,
+                  uc_pdata->always_on ? "true" : "false");
+       constraint("  - boot on:", uc_pdata->boot_on,
+                  uc_pdata->boot_on ? "true" : "false");
+
+       mode_count = regulator_mode(dev, &modes);
+       constraint("* op modes:", mode_count, NULL);
+
+       for (i = 0; i < mode_count; i++, modes++)
+               constraint("  - mode id:", modes->id, modes->name);
+
+       return CMD_RET_SUCCESS;
+}
+
+static int do_status(cmd_tbl_t *cmdtp, int flag, int argc, char * const

argv[])

common/cmd_regulator.c new file +22 -0
+{
+       struct dm_regulator_uclass_platdata *uc_pdata;
+       int current, value, mode, ret;
+       const char *mode_name = NULL;
+       struct udevice *dev;
+       bool enabled;
+
+       ret = get_curr_dev_and_pl(&dev, &uc_pdata, true);
+       if (ret)
+               return ret;
+
+       enabled = regulator_get_enable(dev);
+       constraint(" * enable:", enabled, enabled ? "true" : "false");
+
+       value = regulator_get_value(dev);
+       constraint(" * value uV:", value, NULL);
+
+       current = regulator_get_current(dev);
+       constraint(" * current uA:", current, NULL);
+
+       mode = regulator_get_mode(dev);
+       mode_name = get_mode_name(uc_pdata->mode, uc_pdata->mode_count,

mode);

common/cmd_regulator.c new file +6 -0
+       constraint(" * mode id:", mode, mode_name);
+
+       return CMD_RET_SUCCESS;
+}
+
+static int do_value(cmd_tbl_t *cmdtp, int flag, int argc, char * const

argv[])

common/cmd_regulator.c new file +15 -0
+{
+       struct udevice *dev;
+       struct dm_regulator_uclass_platdata *uc_pdata;
+       int value;
+       int force;
+       int ret;
+
+       ret = get_curr_dev_and_pl(&dev, &uc_pdata, argc == 1);
+       if (ret)
+               return ret;
+
+       if (argc == 1) {
+               value = regulator_get_value(dev);
+               if (value < 0)
+                       return failed("get", uc_pdata->name, "voltage",

value);

common/cmd_regulator.c new file +12 -0
+
+               printf("%d uV\n", value);
+               return CMD_RET_SUCCESS;
+       }
+
+       if (argc == 3)
+               force = !strcmp("-f", argv[2]);
+       else
+               force = 0;
+
+       value = simple_strtoul(argv[1], NULL, 0);
+       if ((value < uc_pdata->min_uV || value > uc_pdata->max_uV) &&

!force) {

common/cmd_regulator.c new file +7 -0
+               printf("Value exceeds regulator constraint limits\n");
+               return CMD_RET_FAILURE;
+       }
+
+       ret = regulator_set_value(dev, value);
+       if (ret)
+               return failed("set", uc_pdata->name, "voltage value",

ret);

common/cmd_regulator.c new file +5 -0
+
+       return CMD_RET_SUCCESS;
+}
+
+static int do_current(cmd_tbl_t *cmdtp, int flag, int argc, char * const

argv[])

common/cmd_regulator.c new file +14 -0
+{
+       struct udevice *dev;
+       struct dm_regulator_uclass_platdata *uc_pdata;
+       int current;
+       int ret;
+
+       ret = get_curr_dev_and_pl(&dev, &uc_pdata, argc == 1);
+       if (ret)
+               return ret;
+
+       if (argc == 1) {
+               current = regulator_get_current(dev);
+               if (current < 0)
+                       return failed("get", uc_pdata->name, "current",

current);

common/cmd_regulator.c new file +14 -0
+
+               printf("%d uA\n", current);
+               return CMD_RET_SUCCESS;
+       }
+
+       current = simple_strtoul(argv[1], NULL, 0);
+       if (current < uc_pdata->min_uA || current > uc_pdata->max_uA) {
+               printf("Current exceeds regulator constraint limits\n");
+               return CMD_RET_FAILURE;
+       }
+
+       ret = regulator_set_current(dev, current);
+       if (ret)
+               return failed("set", uc_pdata->name, "current value",

ret);

common/cmd_regulator.c new file +5 -0
+
+       return CMD_RET_SUCCESS;
+}
+
+static int do_mode(cmd_tbl_t *cmdtp, int flag, int argc, char * const

argv[])

common/cmd_regulator.c new file +15 -0
+{
+       struct udevice *dev;
+       struct dm_regulator_uclass_platdata *uc_pdata;
+       int new_mode;
+       int mode;
+       int ret;
+
+       ret = get_curr_dev_and_pl(&dev, &uc_pdata, false);
+       if (ret)
+               return ret;
+
+       if (argc == 1) {
+               mode = regulator_get_mode(dev);
+               if (mode < 0)
+                       return failed("get", uc_pdata->name, "mode",

mode);

common/cmd_regulator.c new file +15 -0
+
+               printf("mode id: %d\n", mode);
+               return CMD_RET_SUCCESS;
+       }
+
+       new_mode = simple_strtoul(argv[1], NULL, 0);
+
+       ret = regulator_set_mode(dev, new_mode);
+       if (ret)
+               return failed("set", uc_pdata->name, "mode", ret);
+
+       return CMD_RET_SUCCESS;
+}
+
+static int do_enable(cmd_tbl_t *cmdtp, int flag, int argc, char * const

argv[])

common/cmd_regulator.c new file +12 -0
+{
+       struct udevice *dev;
+       struct dm_regulator_uclass_platdata *uc_pdata;
+       int ret;
+
+       ret = get_curr_dev_and_pl(&dev, &uc_pdata, true);
+       if (ret)
+               return ret;
+
+       ret = regulator_set_enable(dev, true);
+       if (ret)
+               return failed("enable", "regulator", uc_pdata->name,

ret);

common/cmd_regulator.c new file +5 -0
+
+       return CMD_RET_SUCCESS;
+}
+
+static int do_disable(cmd_tbl_t *cmdtp, int flag, int argc, char * const

argv[])

common/cmd_regulator.c new file +12 -0
+{
+       struct udevice *dev;
+       struct dm_regulator_uclass_platdata *uc_pdata;
+       int ret;
+
+       ret = get_curr_dev_and_pl(&dev, &uc_pdata, true);
+       if (ret)
+               return ret;
+
+       ret = regulator_set_enable(dev, false);
+       if (ret)
+               return failed("disable", "regulator", uc_pdata->name,

ret);

common/cmd_regulator.c new file +35 -0
+
+       return CMD_RET_SUCCESS;
+}
+
+static cmd_tbl_t subcmd[] = {
+       U_BOOT_CMD_MKENT(dev, 2, 1, do_dev, "", ""),
+       U_BOOT_CMD_MKENT(list, 1, 1, do_list, "", ""),
+       U_BOOT_CMD_MKENT(info, 2, 1, do_info, "", ""),
+       U_BOOT_CMD_MKENT(status, 2, 1, do_status, "", ""),
+       U_BOOT_CMD_MKENT(value, 3, 1, do_value, "", ""),
+       U_BOOT_CMD_MKENT(current, 3, 1, do_current, "", ""),
+       U_BOOT_CMD_MKENT(mode, 2, 1, do_mode, "", ""),
+       U_BOOT_CMD_MKENT(enable, 1, 1, do_enable, "", ""),
+       U_BOOT_CMD_MKENT(disable, 1, 1, do_disable, "", ""),
+};
+
+static int do_regulator(cmd_tbl_t *cmdtp, int flag, int argc,
+                       char * const argv[])
+{
+       cmd_tbl_t *cmd;
+
+       argc--;
+       argv++;
+
+       cmd = find_cmd_tbl(argv[0], subcmd, ARRAY_SIZE(subcmd));
+       if (cmd == NULL || argc > cmd->maxargs)
+               return CMD_RET_USAGE;
+
+       return cmd->cmd(cmdtp, flag, argc, argv);
+}
+
+U_BOOT_CMD(regulator, CONFIG_SYS_MAXARGS, 1, do_regulator,
+       "uclass operations",
+       "list         - list UCLASS regulator devices\n"
+       "regulator dev [id]     - show or [set] operating regulator

device\n"

common/cmd_regulator.c new file +3 -0
+       "regulator [info]       - print constraints info\n"
+       "regulator [status]     - print operating status\n"
+       "regulator [value] [-f] - print/[set] voltage value [uV]

(force)\n"

Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
common/cmd_regulator.c new file +5 -1
+       "regulator [current]    - print/[set] current value [uA]\n"
+       "regulator [mode_id]    - print/[set] operating mode id\n"
+       "regulator [enable]     - enable the regulator output\n"
+       "regulator [disable]    - disable the regulator output\n"
+);
--

1.9.1

Regards,
Simon

#177 lore raw

PATCH v4 7/16 dm: regulator: add regulator command

Hello Simon,

Quoted 140 lines · Simon Glass

Hi Przemyslaw,

Quoted 137 lines · Przemyslaw Marczak

Hello Simon,

Quoted 42 lines · Simon Glass

Hi Przemyslaw,

Quoted 28 lines · Przemyslaw Marczak

This command is based on driver model regulator's API. The user interface provides:
- list UCLASS regulator devices
- show or [set] operating regulator device
- print constraints info
- print operating status
- print/[set] voltage value [uV] (force)
- print/[set] current value [uA]
- print/[set] operating mode id
- enable the regulator output
- disable the regulator output

The 'force' option can be used for setting the value which exceeds the constraints min/max limits.

---
Changes v3:
- new file
- Kconfig entry

Changes V4:
- cmd regulator: move platdata to uc pdata
- cmd_regulator: includes cleanup
- cmd_regulator: add get_curr_dev_and_pl() check type
- move config name: CONFIG_DM_REGULATOR_CMD to CONFIG_CMD_REGULATOR
- common/Kconfig - cleanup

Quoted 7 lines
---
   common/Kconfig         |  22 +++
   common/Makefile        |   1 +
   common/cmd_regulator.c | 403
+++++++++++++++++++++++++++++++++++++++++++++++++
   3 files changed, 426 insertions(+)

create mode 100644 common/cmd_regulator.c

Quoted 4 lines

I have a few nits that could be dealt with by a follow-on patch.

Ok.

Quoted 81 lines
Quoted 76 lines
common/Kconfig +18 -0
index 4666f8e..52f8bb1 100644
@@ -470,5 +470,27 @@ config CMD_PMIC
            - pmic read address  - read byte of register at address
            - pmic write address - write byte to register at address
            The only one change for this command is 'dev' subcommand.
+
+config CMD_REGULATOR
+       bool "Enable Driver Model REGULATOR command"
+       depends on DM_REGULATOR
+       help
+         This command is based on driver model regulator's API.
+         User interface features:
+         - list               - list regulator devices
+         - regulator dev <id> - show or [set] operating regulator device
+         - regulator info     - print constraints info
+         - regulator status   - print operating status
+         - regulator value <val] <-f> - print/[set] voltage value [uV]
+         - regulator current <val>    - print/[set] current value [uA]
+         - regulator mode <id>        - print/[set] operating mode id
+         - regulator enable           - enable the regulator output
+         - regulator disable          - disable the regulator output
+
+         The '-f' (force) option can be used for set the value which

exceeds
+ the limits, which are found in device-tree and are kept in
regulator's

common/Kconfig +3 -0
+         uclass platdata structure.
+
   endmenu
+
   endmenu
common/Makefile +1 -0
index 87a3efe..93bded3 100644
@@ -212,6 +212,7 @@ obj-$(CONFIG_CMD_GPT) += cmd_gpt.o
 
   # Power
   obj-$(CONFIG_CMD_PMIC) += cmd_pmic.o
+obj-$(CONFIG_CMD_REGULATOR) += cmd_regulator.o
   endif
 
   ifdef CONFIG_SPL_BUILD
common/cmd_regulator.c new file +23 -0
new file mode 100644
index 0000000..b1b9e87
@@ -0,0 +1,403 @@
+/*
+ * Copyright (C) 2014-2015 Samsung Electronics
+ * Przemyslaw Marczak <[email protected]>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+#include <common.h>
+#include <errno.h>
+#include <dm.h>
+#include <dm/uclass-internal.h>
+#include <power/regulator.h>
+
+#define LIMIT_SEQ      3
+#define LIMIT_DEVNAME  20
+#define LIMIT_OFNAME   20
+#define LIMIT_INFO     16
+
+static struct udevice *currdev;
+
+static int failed(const char *getset, const char *thing,
+                 const char *for_dev, int ret)
+{
+       printf("Can't %s %s %s.\nError: %d (%s)\n", getset, thing,
Quoted 2 lines

for_dev,
+ ret, errno_str(ret));

blank line here.

Quoted 4 lines
Quoted 1 line

I don't see the blank line here in the patch, which I send.

Odd, there seem to be two blank lines there, and we only need one.

Ah, sorry. You mean, that there should be added a blank line. Ok, will add one.

Quoted 8 lines
Quoted 8 lines
Quoted 7 lines

I worry that if someone gets one of these messages they will not be able to find it in the source code. How about passing in the full printf() string in each case, or just using printf() in situ? I don't think the code space saving is significant.

Quoted 9 lines
Quoted 3 lines

It's not a debug message. And each one is different, and easy to grep "failed". The code is a little cleaner with this. Also the command code is not complicated.

git grep -i failed |wc -l
2089

Is there some way to know it is a PMIC error message, and find it that way?

Ok, I assumed that you know which command you called, and where to find it, so you could use:
grep -i "failed" common/cmd_regulator.c | wc -l
15

But this was only the function name, not a useful text for grep. Now I see that this should use the printf instead of the helper funcion.

Quoted 27 lines
Quoted 27 lines
Quoted 26 lines
Quoted 6 lines
common/cmd_regulator.c new file +4 -0
+       return CMD_RET_FAILURE;
+}
+
+static int regulator_get(bool list_only, int get_seq, struct udevice

**devp)

This function seems to do multiple things (find and list). Should we split it into two?

common/cmd_regulator.c line 38

Quoted 10 lines
common/cmd_regulator.c new file +10 -0
+{
+       struct dm_regulator_uclass_platdata *uc_pdata;
+       struct udevice *dev;
+       int ret;
+
+       if (devp)
+               *devp = NULL;
+
+       for (ret = uclass_first_device(UCLASS_REGULATOR, &dev); dev;
+            ret = uclass_next_device(&dev)) {

This will probe all regulators that it checks. I think it should avoid that. Do you mean to use

Quoted 8 lines
Quoted 5 lines

Regarding the two above comments, we have two problems:

1. Getting the regulator by sequencial number (dev->seq).
I think it's required, because only this method returns the right device.
Disadvantage: need to probe all devices.

But you can use req_seq, or if you have platform data, check that.

Ok, we could use the req_seq for the PMIC uclass, it's natural that interface, has its address and <reg> property - but this can repeat, if we have two PMICs on a different busses. This is probably possible.

We also shouldn't set the req_seq as the number found in node name, because those numbers can repeat: ldo1 {}; buck1 {}; regulator1 { }.

I think that, using the req_seq is bad idea, since we can't be sure that those values are unique.

I understand that, the probe is not ideal here? But from the other side, if we call "pmic list", then we are sure, that listed devices are ready to use. Shouldn't we expect this?

Quoted 10 lines
Quoted 6 lines

2. Getting the regulator by "regulator-name" (regulator_uclass_platdata->name).
This would be clean, but unreliable if we have few regulators with the same name - I think we should keep this in mind. Advantage: can use for non-probed devices.

We could probably refuse to bind regulators with the same name. That's just going to lead to confusion.

This could be good, because at present we can get only the first matching device, for the given "regulator-name" constraint. Ok, I need add the checking routine to regulator's post_bind() method. And then refuse the bind of the repeated one.

Quoted 11 lines
Quoted 11 lines

And about the doing multiple things by the regulator_get(). Following your comments about avoiding the code duplication, I put those things into one function, since both actually do the same - loops over the uclass's devices.

So we can threat it as a subcommands:
- regulator_get list
- regulator_get dev
Maybe the enum { GET_LIST, GET_DEV } would be better, than the bool.

Quoted 5 lines
Quoted 1 line

Is that really bad?

I suspect it would be better as two completely separate functions, and probably not much more code size.

Ok.

Quoted 397 lines
Quoted 397 lines
Quoted 52 lines
Quoted 52 lines
common/cmd_regulator.c new file +6 -0
+               if (list_only) {
+                       uc_pdata = dev_get_uclass_platdata(dev);
+                       printf("|%*d | %*.*s @ %-*.*s| %s @ %s\n",
+                              LIMIT_SEQ, dev->seq,
+                              LIMIT_DEVNAME, LIMIT_DEVNAME, dev->name,
+                              LIMIT_OFNAME, LIMIT_OFNAME,

uc_pdata->name,

common/cmd_regulator.c new file +22 -0
+                              dev->parent->name,
+                              dev_get_uclass_name(dev->parent));
+                       continue;
+               }
+
+               if (dev->seq == get_seq) {
+                       if (devp)
+                               *devp = dev;
+                       else
+                               return -EINVAL;
+
+                       return 0;
+               }
+       }
+
+       if (list_only)
+               return ret;
+
+       return -ENODEV;
+}
+
+static int do_dev(cmd_tbl_t *cmdtp, int flag, int argc, char * const

argv[])

common/cmd_regulator.c new file +8 -0
+{
+       struct dm_regulator_uclass_platdata *uc_pdata;
+       int seq, ret = -ENXIO;
+
+       switch (argc) {
+       case 2:
+               seq = simple_strtoul(argv[1], NULL, 0);
+               ret = uclass_get_device_by_seq(UCLASS_REGULATOR, seq,

&currdev);

common/cmd_regulator.c new file +11 -0
+               if (ret && (ret = regulator_get(false, seq, &currdev)))
+                       goto failed;
+       case 1:
+               uc_pdata = dev_get_uclass_platdata(currdev);
+               if (!uc_pdata)
+                       goto failed;
+
+               printf("dev: %d @ %s\n", currdev->seq, uc_pdata->name);
+       }
+
+       return CMD_RET_SUCCESS;
Quoted 9 lines

common/cmd_regulator.c line 90

Quoted 5 lines
common/cmd_regulator.c new file +5 -0
+failed:
+       return failed("get", "the", "device", ret);
+}
+
+static int get_curr_dev_and_pl(struct udevice **devp,

What is pl? The name does not seem very meaningful to me.

The platdata, ok I will tune it.

Quoted 332 lines
Quoted 332 lines

+ struct dm_regulator_uclass_platdata
**uc_pdata,

common/cmd_regulator.c new file +15 -0
+                              bool allow_type_fixed)
+{
+       *devp = NULL;
+       *uc_pdata = NULL;
+
+       if (!currdev)
+               return failed("get", "current", "device", -ENODEV);
+
+       *devp = currdev;
+
+       *uc_pdata = dev_get_uclass_platdata(*devp);
+       if (!*uc_pdata)
+               return failed("get", "regulator", "platdata", -ENXIO);
+
+       if (!allow_type_fixed && (*uc_pdata)->type ==

REGULATOR_TYPE_FIXED) {

common/cmd_regulator.c new file +8 -0
+               printf("Operation not allowed for fixed regulator!\n");
+               return CMD_RET_FAILURE;
+       }
+
+       return CMD_RET_SUCCESS;
+}
+
+static int do_list(cmd_tbl_t *cmdtp, int flag, int argc, char * const

argv[])

common/cmd_regulator.c new file +46 -0
+{
+       int ret;
+
+       printf("|%*s | %*.*s @ %-*.*s| %s @ %s\n",
+              LIMIT_SEQ, "Seq",
+              LIMIT_DEVNAME, LIMIT_DEVNAME, "Name",
+              LIMIT_OFNAME, LIMIT_OFNAME, "fdtname",
+              "Parent", "uclass");
+
+       ret = regulator_get(true, 0, NULL);
+       if (ret)
+               return CMD_RET_FAILURE;
+
+       return CMD_RET_SUCCESS;
+}
+
+static int constraint(const char *name, int val, const char *val_name)
+{
+       printf("%-*s", LIMIT_INFO, name);
+       if (val < 0) {
+               printf(" %s (err: %d)\n", errno_str(val), val);
+               return val;
+       }
+
+       if (val_name)
+               printf(" %d (%s)\n", val, val_name);
+       else
+               printf(" %d\n", val);
+
+       return 0;
+}
+
+static const char *get_mode_name(struct dm_regulator_mode *mode,
+                                int mode_count,
+                                int mode_id)
+{
+       while (mode_count--) {
+               if (mode->id == mode_id)
+                       return mode->name;
+               mode++;
+       }
+
+       return NULL;
+}
+
+static int do_info(cmd_tbl_t *cmdtp, int flag, int argc, char * const

argv[])

common/cmd_regulator.c new file +41 -0
+{
+       struct udevice *dev;
+       struct dm_regulator_uclass_platdata *uc_pdata;
+       struct dm_regulator_mode *modes;
+       const char *parent_uc;
+       int mode_count;
+       int ret;
+       int i;
+
+       ret = get_curr_dev_and_pl(&dev, &uc_pdata, true);
+       if (ret)
+               return ret;
+
+       parent_uc = dev_get_uclass_name(dev->parent);
+
+       printf("Uclass regulator dev %d info:\n", dev->seq);
+       printf("%-*s %s @ %s\n%-*s %s\n%-*s %s\n%-*s\n",
+              LIMIT_INFO, "* parent:", dev->parent->name, parent_uc,
+              LIMIT_INFO, "* dev name:", dev->name,
+              LIMIT_INFO, "* fdt name:", uc_pdata->name,
+              LIMIT_INFO, "* constraints:");
+
+       constraint("  - min uV:", uc_pdata->min_uV, NULL);
+       constraint("  - max uV:", uc_pdata->max_uV, NULL);
+       constraint("  - min uA:", uc_pdata->min_uA, NULL);
+       constraint("  - max uA:", uc_pdata->max_uA, NULL);
+       constraint("  - always on:", uc_pdata->always_on,
+                  uc_pdata->always_on ? "true" : "false");
+       constraint("  - boot on:", uc_pdata->boot_on,
+                  uc_pdata->boot_on ? "true" : "false");
+
+       mode_count = regulator_mode(dev, &modes);
+       constraint("* op modes:", mode_count, NULL);
+
+       for (i = 0; i < mode_count; i++, modes++)
+               constraint("  - mode id:", modes->id, modes->name);
+
+       return CMD_RET_SUCCESS;
+}
+
+static int do_status(cmd_tbl_t *cmdtp, int flag, int argc, char * const

argv[])

common/cmd_regulator.c new file +22 -0
+{
+       struct dm_regulator_uclass_platdata *uc_pdata;
+       int current, value, mode, ret;
+       const char *mode_name = NULL;
+       struct udevice *dev;
+       bool enabled;
+
+       ret = get_curr_dev_and_pl(&dev, &uc_pdata, true);
+       if (ret)
+               return ret;
+
+       enabled = regulator_get_enable(dev);
+       constraint(" * enable:", enabled, enabled ? "true" : "false");
+
+       value = regulator_get_value(dev);
+       constraint(" * value uV:", value, NULL);
+
+       current = regulator_get_current(dev);
+       constraint(" * current uA:", current, NULL);
+
+       mode = regulator_get_mode(dev);
+       mode_name = get_mode_name(uc_pdata->mode, uc_pdata->mode_count,

mode);

common/cmd_regulator.c new file +6 -0
+       constraint(" * mode id:", mode, mode_name);
+
+       return CMD_RET_SUCCESS;
+}
+
+static int do_value(cmd_tbl_t *cmdtp, int flag, int argc, char * const

argv[])

common/cmd_regulator.c new file +15 -0
+{
+       struct udevice *dev;
+       struct dm_regulator_uclass_platdata *uc_pdata;
+       int value;
+       int force;
+       int ret;
+
+       ret = get_curr_dev_and_pl(&dev, &uc_pdata, argc == 1);
+       if (ret)
+               return ret;
+
+       if (argc == 1) {
+               value = regulator_get_value(dev);
+               if (value < 0)
+                       return failed("get", uc_pdata->name, "voltage",

value);

common/cmd_regulator.c new file +12 -0
+
+               printf("%d uV\n", value);
+               return CMD_RET_SUCCESS;
+       }
+
+       if (argc == 3)
+               force = !strcmp("-f", argv[2]);
+       else
+               force = 0;
+
+       value = simple_strtoul(argv[1], NULL, 0);
+       if ((value < uc_pdata->min_uV || value > uc_pdata->max_uV) &&

!force) {

common/cmd_regulator.c new file +7 -0
+               printf("Value exceeds regulator constraint limits\n");
+               return CMD_RET_FAILURE;
+       }
+
+       ret = regulator_set_value(dev, value);
+       if (ret)
+               return failed("set", uc_pdata->name, "voltage value",

ret);

common/cmd_regulator.c new file +5 -0
+
+       return CMD_RET_SUCCESS;
+}
+
+static int do_current(cmd_tbl_t *cmdtp, int flag, int argc, char * const

argv[])

common/cmd_regulator.c new file +14 -0
+{
+       struct udevice *dev;
+       struct dm_regulator_uclass_platdata *uc_pdata;
+       int current;
+       int ret;
+
+       ret = get_curr_dev_and_pl(&dev, &uc_pdata, argc == 1);
+       if (ret)
+               return ret;
+
+       if (argc == 1) {
+               current = regulator_get_current(dev);
+               if (current < 0)
+                       return failed("get", uc_pdata->name, "current",

current);

common/cmd_regulator.c new file +14 -0
+
+               printf("%d uA\n", current);
+               return CMD_RET_SUCCESS;
+       }
+
+       current = simple_strtoul(argv[1], NULL, 0);
+       if (current < uc_pdata->min_uA || current > uc_pdata->max_uA) {
+               printf("Current exceeds regulator constraint limits\n");
+               return CMD_RET_FAILURE;
+       }
+
+       ret = regulator_set_current(dev, current);
+       if (ret)
+               return failed("set", uc_pdata->name, "current value",

ret);

common/cmd_regulator.c new file +5 -0
+
+       return CMD_RET_SUCCESS;
+}
+
+static int do_mode(cmd_tbl_t *cmdtp, int flag, int argc, char * const

argv[])

common/cmd_regulator.c new file +15 -0
+{
+       struct udevice *dev;
+       struct dm_regulator_uclass_platdata *uc_pdata;
+       int new_mode;
+       int mode;
+       int ret;
+
+       ret = get_curr_dev_and_pl(&dev, &uc_pdata, false);
+       if (ret)
+               return ret;
+
+       if (argc == 1) {
+               mode = regulator_get_mode(dev);
+               if (mode < 0)
+                       return failed("get", uc_pdata->name, "mode",

mode);

common/cmd_regulator.c new file +15 -0
+
+               printf("mode id: %d\n", mode);
+               return CMD_RET_SUCCESS;
+       }
+
+       new_mode = simple_strtoul(argv[1], NULL, 0);
+
+       ret = regulator_set_mode(dev, new_mode);
+       if (ret)
+               return failed("set", uc_pdata->name, "mode", ret);
+
+       return CMD_RET_SUCCESS;
+}
+
+static int do_enable(cmd_tbl_t *cmdtp, int flag, int argc, char * const

argv[])

common/cmd_regulator.c new file +12 -0
+{
+       struct udevice *dev;
+       struct dm_regulator_uclass_platdata *uc_pdata;
+       int ret;
+
+       ret = get_curr_dev_and_pl(&dev, &uc_pdata, true);
+       if (ret)
+               return ret;
+
+       ret = regulator_set_enable(dev, true);
+       if (ret)
+               return failed("enable", "regulator", uc_pdata->name,

ret);

common/cmd_regulator.c new file +5 -0
+
+       return CMD_RET_SUCCESS;
+}
+
+static int do_disable(cmd_tbl_t *cmdtp, int flag, int argc, char * const

argv[])

common/cmd_regulator.c new file +12 -0
+{
+       struct udevice *dev;
+       struct dm_regulator_uclass_platdata *uc_pdata;
+       int ret;
+
+       ret = get_curr_dev_and_pl(&dev, &uc_pdata, true);
+       if (ret)
+               return ret;
+
+       ret = regulator_set_enable(dev, false);
+       if (ret)
+               return failed("disable", "regulator", uc_pdata->name,

ret);

common/cmd_regulator.c new file +35 -0
+
+       return CMD_RET_SUCCESS;
+}
+
+static cmd_tbl_t subcmd[] = {
+       U_BOOT_CMD_MKENT(dev, 2, 1, do_dev, "", ""),
+       U_BOOT_CMD_MKENT(list, 1, 1, do_list, "", ""),
+       U_BOOT_CMD_MKENT(info, 2, 1, do_info, "", ""),
+       U_BOOT_CMD_MKENT(status, 2, 1, do_status, "", ""),
+       U_BOOT_CMD_MKENT(value, 3, 1, do_value, "", ""),
+       U_BOOT_CMD_MKENT(current, 3, 1, do_current, "", ""),
+       U_BOOT_CMD_MKENT(mode, 2, 1, do_mode, "", ""),
+       U_BOOT_CMD_MKENT(enable, 1, 1, do_enable, "", ""),
+       U_BOOT_CMD_MKENT(disable, 1, 1, do_disable, "", ""),
+};
+
+static int do_regulator(cmd_tbl_t *cmdtp, int flag, int argc,
+                       char * const argv[])
+{
+       cmd_tbl_t *cmd;
+
+       argc--;
+       argv++;
+
+       cmd = find_cmd_tbl(argv[0], subcmd, ARRAY_SIZE(subcmd));
+       if (cmd == NULL || argc > cmd->maxargs)
+               return CMD_RET_USAGE;
+
+       return cmd->cmd(cmdtp, flag, argc, argv);
+}
+
+U_BOOT_CMD(regulator, CONFIG_SYS_MAXARGS, 1, do_regulator,
+       "uclass operations",
+       "list         - list UCLASS regulator devices\n"
+       "regulator dev [id]     - show or [set] operating regulator

device\n"

common/cmd_regulator.c new file +3 -0
+       "regulator [info]       - print constraints info\n"
+       "regulator [status]     - print operating status\n"
+       "regulator [value] [-f] - print/[set] voltage value [uV]

(force)\n"

common/cmd_regulator.c new file +3 -0
+       "regulator [current]    - print/[set] current value [uA]\n"
+       "regulator [mode_id]    - print/[set] operating mode id\n"
+       "regulator [enable]     - enable the regulator output\n"
Quoted 9 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
common/cmd_regulator.c new file +2 -1
+       "regulator [disable]    - disable the regulator output\n"
+);
--

1.9.1

Regards,
Simon

Best regards,

Signature · 4 lines
Przemyslaw Marczak
Samsung R&D Institute Poland
Samsung Electronics
p.marczak at samsung.com
#178 lore raw

PATCH v4 7/16 dm: regulator: add regulator command

Hi Przemyslaw,

Quoted 238 lines · Przemyslaw Marczak

Hello Simon,

Quoted 150 lines · Simon Glass

Hi Przemyslaw,

Quoted 145 lines · Przemyslaw Marczak

Hello Simon,

Quoted 45 lines · Simon Glass

Hi Przemyslaw,

Quoted 29 lines · Przemyslaw Marczak

This command is based on driver model regulator's API. The user interface provides:
- list UCLASS regulator devices
- show or [set] operating regulator device
- print constraints info
- print operating status
- print/[set] voltage value [uV] (force)
- print/[set] current value [uA]
- print/[set] operating mode id
- enable the regulator output
- disable the regulator output

The 'force' option can be used for setting the value which exceeds the constraints min/max limits.

---
Changes v3:
- new file
- Kconfig entry

Changes V4:
- cmd regulator: move platdata to uc pdata
- cmd_regulator: includes cleanup
- cmd_regulator: add get_curr_dev_and_pl() check type
- move config name: CONFIG_DM_REGULATOR_CMD to CONFIG_CMD_REGULATOR
- common/Kconfig - cleanup

Quoted 7 lines
---
   common/Kconfig         |  22 +++
   common/Makefile        |   1 +
   common/cmd_regulator.c | 403
+++++++++++++++++++++++++++++++++++++++++++++++++
   3 files changed, 426 insertions(+)

create mode 100644 common/cmd_regulator.c

Quoted 4 lines

I have a few nits that could be dealt with by a follow-on patch.

Ok.

Quoted 84 lines
Quoted 77 lines
common/Kconfig +9 -0
index 4666f8e..52f8bb1 100644
@@ -470,5 +470,27 @@ config CMD_PMIC
            - pmic read address  - read byte of register at address
            - pmic write address - write byte to register at address
            The only one change for this command is 'dev' subcommand.
+
+config CMD_REGULATOR
+       bool "Enable Driver Model REGULATOR command"
+       depends on DM_REGULATOR
+       help
+         This command is based on driver model regulator's API.
+         User interface features:
+         - list               - list regulator devices
+         - regulator dev <id> - show or [set] operating regulator

device

common/Kconfig +9 -0
+         - regulator info     - print constraints info
+         - regulator status   - print operating status
+         - regulator value <val] <-f> - print/[set] voltage value [uV]
+         - regulator current <val>    - print/[set] current value [uA]
+         - regulator mode <id>        - print/[set] operating mode id
+         - regulator enable           - enable the regulator output
+         - regulator disable          - disable the regulator output
+
+         The '-f' (force) option can be used for set the value which

exceeds
+ the limits, which are found in device-tree and are kept in
regulator's

common/Kconfig +3 -0
+         uclass platdata structure.
+
   endmenu
+
   endmenu
common/Makefile +1 -0
index 87a3efe..93bded3 100644
@@ -212,6 +212,7 @@ obj-$(CONFIG_CMD_GPT) += cmd_gpt.o
 
   # Power
   obj-$(CONFIG_CMD_PMIC) += cmd_pmic.o
+obj-$(CONFIG_CMD_REGULATOR) += cmd_regulator.o
   endif
 
   ifdef CONFIG_SPL_BUILD
common/cmd_regulator.c new file +23 -0
new file mode 100644
index 0000000..b1b9e87
@@ -0,0 +1,403 @@
+/*
+ * Copyright (C) 2014-2015 Samsung Electronics
+ * Przemyslaw Marczak <[email protected]>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+#include <common.h>
+#include <errno.h>
+#include <dm.h>
+#include <dm/uclass-internal.h>
+#include <power/regulator.h>
+
+#define LIMIT_SEQ      3
+#define LIMIT_DEVNAME  20
+#define LIMIT_OFNAME   20
+#define LIMIT_INFO     16
+
+static struct udevice *currdev;
+
+static int failed(const char *getset, const char *thing,
+                 const char *for_dev, int ret)
+{
+       printf("Can't %s %s %s.\nError: %d (%s)\n", getset, thing,
Quoted 3 lines

for_dev,
+ ret,
errno_str(ret));

blank line here.

Quoted 5 lines
Quoted 1 line

I don't see the blank line here in the patch, which I send.

Odd, there seem to be two blank lines there, and we only need one.

Ah, sorry. You mean, that there should be added a blank line. Ok, will add one.

Quoted 14 lines
Quoted 8 lines
Quoted 7 lines

I worry that if someone gets one of these messages they will not be able to find it in the source code. How about passing in the full printf() string in each case, or just using printf() in situ? I don't think the code space saving is significant.

Quoted 4 lines

It's not a debug message. And each one is different, and easy to grep "failed". The code is a little cleaner with this. Also the command code is
not complicated.

Quoted 6 lines

git grep -i failed |wc -l
2089

Is there some way to know it is a PMIC error message, and find it that way?

Ok, I assumed that you know which command you called, and where to find it, so you could use:
grep -i "failed" common/cmd_regulator.c | wc -l
15

But this was only the function name, not a useful text for grep. Now I see that this should use the printf instead of the helper funcion.

Quoted 29 lines
Quoted 29 lines
Quoted 28 lines
Quoted 6 lines
common/cmd_regulator.c new file +4 -0
+       return CMD_RET_FAILURE;
+}
+
+static int regulator_get(bool list_only, int get_seq, struct udevice

**devp)

This function seems to do multiple things (find and list). Should we split it into two?

common/cmd_regulator.c line 38

Quoted 10 lines
common/cmd_regulator.c new file +10 -0
+{
+       struct dm_regulator_uclass_platdata *uc_pdata;
+       struct udevice *dev;
+       int ret;
+
+       if (devp)
+               *devp = NULL;
+
+       for (ret = uclass_first_device(UCLASS_REGULATOR, &dev); dev;
+            ret = uclass_next_device(&dev)) {

This will probe all regulators that it checks. I think it should avoid that. Do you mean to use

Quoted 9 lines
Quoted 5 lines

Regarding the two above comments, we have two problems:

1. Getting the regulator by sequencial number (dev->seq).
I think it's required, because only this method returns the right device.
Disadvantage: need to probe all devices.

But you can use req_seq, or if you have platform data, check that.

Ok, we could use the req_seq for the PMIC uclass, it's natural that interface, has its address and <reg> property - but this can repeat, if we have two PMICs on a different busses. This is probably possible.

We also shouldn't set the req_seq as the number found in node name, because those numbers can repeat: ldo1 {}; buck1 {}; regulator1 { }.

Quoted 6 lines

I think that, using the req_seq is bad idea, since we can't be sure that those values are unique.

I understand that, the probe is not ideal here? But from the other side, if we call "pmic list", then we are sure, that listed devices are ready to use. Shouldn't we expect this?

I was hoping that we would not probe devices until they are actually used, and that listing them would not constitute 'use'.

In the case of listing, you should not need to worry about ->seq or ->req_seq. If you avoid 'getting' the device you will not probe it.

In the case of getting a device ready for use, yes, it must be probed. But I am only commenting on your 'list' function.

Quoted 31 lines
Quoted 10 lines
Quoted 8 lines

2. Getting the regulator by "regulator-name" (regulator_uclass_platdata->name).
This would be clean, but unreliable if we have few regulators with the same
name - I think we should keep this in mind. Advantage: can use for non-probed devices.

Quoted 3 lines

We could probably refuse to bind regulators with the same name. That's just going to lead to confusion.

This could be good, because at present we can get only the first matching device, for the given "regulator-name" constraint.
Ok, I need add the checking routine to regulator's post_bind() method. And then refuse the bind of the repeated one.

Quoted 12 lines
Quoted 12 lines

And about the doing multiple things by the regulator_get(). Following your comments about avoiding the code duplication, I put those things into one function, since both actually do the same - loops over the
uclass's devices.

So we can threat it as a subcommands:
- regulator_get list
- regulator_get dev
Maybe the enum { GET_LIST, GET_DEV } would be better, than the bool.

Quoted 421 lines
Quoted 6 lines
Quoted 1 line

Is that really bad?

I suspect it would be better as two completely separate functions, and probably not much more code size.

Ok.

Quoted 411 lines
Quoted 400 lines
Quoted 53 lines
Quoted 53 lines
common/cmd_regulator.c new file +6 -0
+               if (list_only) {
+                       uc_pdata = dev_get_uclass_platdata(dev);
+                       printf("|%*d | %*.*s @ %-*.*s| %s @ %s\n",
+                              LIMIT_SEQ, dev->seq,
+                              LIMIT_DEVNAME, LIMIT_DEVNAME, dev->name,
+                              LIMIT_OFNAME, LIMIT_OFNAME,

uc_pdata->name,

common/cmd_regulator.c new file +22 -0
+                              dev->parent->name,
+                              dev_get_uclass_name(dev->parent));
+                       continue;
+               }
+
+               if (dev->seq == get_seq) {
+                       if (devp)
+                               *devp = dev;
+                       else
+                               return -EINVAL;
+
+                       return 0;
+               }
+       }
+
+       if (list_only)
+               return ret;
+
+       return -ENODEV;
+}
+
+static int do_dev(cmd_tbl_t *cmdtp, int flag, int argc, char * const

argv[])

common/cmd_regulator.c new file +8 -0
+{
+       struct dm_regulator_uclass_platdata *uc_pdata;
+       int seq, ret = -ENXIO;
+
+       switch (argc) {
+       case 2:
+               seq = simple_strtoul(argv[1], NULL, 0);
+               ret = uclass_get_device_by_seq(UCLASS_REGULATOR, seq,

&currdev);

common/cmd_regulator.c new file +12 -0
+               if (ret && (ret = regulator_get(false, seq, &currdev)))
+                       goto failed;
+       case 1:
+               uc_pdata = dev_get_uclass_platdata(currdev);
+               if (!uc_pdata)
+                       goto failed;
+
+               printf("dev: %d @ %s\n", currdev->seq, uc_pdata->name);
+       }
+
+       return CMD_RET_SUCCESS;
+failed:
Quoted 9 lines

common/cmd_regulator.c line 90

Quoted 4 lines
common/cmd_regulator.c new file +4 -0
+       return failed("get", "the", "device", ret);
+}
+
+static int get_curr_dev_and_pl(struct udevice **devp,

What is pl? The name does not seem very meaningful to me.

The platdata, ok I will tune it.

Quoted 334 lines
Quoted 334 lines

+ struct dm_regulator_uclass_platdata
**uc_pdata,

common/cmd_regulator.c new file +15 -0
+                              bool allow_type_fixed)
+{
+       *devp = NULL;
+       *uc_pdata = NULL;
+
+       if (!currdev)
+               return failed("get", "current", "device", -ENODEV);
+
+       *devp = currdev;
+
+       *uc_pdata = dev_get_uclass_platdata(*devp);
+       if (!*uc_pdata)
+               return failed("get", "regulator", "platdata", -ENXIO);
+
+       if (!allow_type_fixed && (*uc_pdata)->type ==

REGULATOR_TYPE_FIXED) {

common/cmd_regulator.c new file +8 -0
+               printf("Operation not allowed for fixed regulator!\n");
+               return CMD_RET_FAILURE;
+       }
+
+       return CMD_RET_SUCCESS;
+}
+
+static int do_list(cmd_tbl_t *cmdtp, int flag, int argc, char * const

argv[])

common/cmd_regulator.c new file +46 -0
+{
+       int ret;
+
+       printf("|%*s | %*.*s @ %-*.*s| %s @ %s\n",
+              LIMIT_SEQ, "Seq",
+              LIMIT_DEVNAME, LIMIT_DEVNAME, "Name",
+              LIMIT_OFNAME, LIMIT_OFNAME, "fdtname",
+              "Parent", "uclass");
+
+       ret = regulator_get(true, 0, NULL);
+       if (ret)
+               return CMD_RET_FAILURE;
+
+       return CMD_RET_SUCCESS;
+}
+
+static int constraint(const char *name, int val, const char *val_name)
+{
+       printf("%-*s", LIMIT_INFO, name);
+       if (val < 0) {
+               printf(" %s (err: %d)\n", errno_str(val), val);
+               return val;
+       }
+
+       if (val_name)
+               printf(" %d (%s)\n", val, val_name);
+       else
+               printf(" %d\n", val);
+
+       return 0;
+}
+
+static const char *get_mode_name(struct dm_regulator_mode *mode,
+                                int mode_count,
+                                int mode_id)
+{
+       while (mode_count--) {
+               if (mode->id == mode_id)
+                       return mode->name;
+               mode++;
+       }
+
+       return NULL;
+}
+
+static int do_info(cmd_tbl_t *cmdtp, int flag, int argc, char * const

argv[])

common/cmd_regulator.c new file +41 -0
+{
+       struct udevice *dev;
+       struct dm_regulator_uclass_platdata *uc_pdata;
+       struct dm_regulator_mode *modes;
+       const char *parent_uc;
+       int mode_count;
+       int ret;
+       int i;
+
+       ret = get_curr_dev_and_pl(&dev, &uc_pdata, true);
+       if (ret)
+               return ret;
+
+       parent_uc = dev_get_uclass_name(dev->parent);
+
+       printf("Uclass regulator dev %d info:\n", dev->seq);
+       printf("%-*s %s @ %s\n%-*s %s\n%-*s %s\n%-*s\n",
+              LIMIT_INFO, "* parent:", dev->parent->name, parent_uc,
+              LIMIT_INFO, "* dev name:", dev->name,
+              LIMIT_INFO, "* fdt name:", uc_pdata->name,
+              LIMIT_INFO, "* constraints:");
+
+       constraint("  - min uV:", uc_pdata->min_uV, NULL);
+       constraint("  - max uV:", uc_pdata->max_uV, NULL);
+       constraint("  - min uA:", uc_pdata->min_uA, NULL);
+       constraint("  - max uA:", uc_pdata->max_uA, NULL);
+       constraint("  - always on:", uc_pdata->always_on,
+                  uc_pdata->always_on ? "true" : "false");
+       constraint("  - boot on:", uc_pdata->boot_on,
+                  uc_pdata->boot_on ? "true" : "false");
+
+       mode_count = regulator_mode(dev, &modes);
+       constraint("* op modes:", mode_count, NULL);
+
+       for (i = 0; i < mode_count; i++, modes++)
+               constraint("  - mode id:", modes->id, modes->name);
+
+       return CMD_RET_SUCCESS;
+}
+
+static int do_status(cmd_tbl_t *cmdtp, int flag, int argc, char *

const
argv[])

common/cmd_regulator.c new file +22 -0
+{
+       struct dm_regulator_uclass_platdata *uc_pdata;
+       int current, value, mode, ret;
+       const char *mode_name = NULL;
+       struct udevice *dev;
+       bool enabled;
+
+       ret = get_curr_dev_and_pl(&dev, &uc_pdata, true);
+       if (ret)
+               return ret;
+
+       enabled = regulator_get_enable(dev);
+       constraint(" * enable:", enabled, enabled ? "true" : "false");
+
+       value = regulator_get_value(dev);
+       constraint(" * value uV:", value, NULL);
+
+       current = regulator_get_current(dev);
+       constraint(" * current uA:", current, NULL);
+
+       mode = regulator_get_mode(dev);
+       mode_name = get_mode_name(uc_pdata->mode, uc_pdata->mode_count,

mode);

common/cmd_regulator.c new file +6 -0
+       constraint(" * mode id:", mode, mode_name);
+
+       return CMD_RET_SUCCESS;
+}
+
+static int do_value(cmd_tbl_t *cmdtp, int flag, int argc, char * const

argv[])

common/cmd_regulator.c new file +15 -0
+{
+       struct udevice *dev;
+       struct dm_regulator_uclass_platdata *uc_pdata;
+       int value;
+       int force;
+       int ret;
+
+       ret = get_curr_dev_and_pl(&dev, &uc_pdata, argc == 1);
+       if (ret)
+               return ret;
+
+       if (argc == 1) {
+               value = regulator_get_value(dev);
+               if (value < 0)
+                       return failed("get", uc_pdata->name, "voltage",

value);

common/cmd_regulator.c new file +12 -0
+
+               printf("%d uV\n", value);
+               return CMD_RET_SUCCESS;
+       }
+
+       if (argc == 3)
+               force = !strcmp("-f", argv[2]);
+       else
+               force = 0;
+
+       value = simple_strtoul(argv[1], NULL, 0);
+       if ((value < uc_pdata->min_uV || value > uc_pdata->max_uV) &&

!force) {

common/cmd_regulator.c new file +7 -0
+               printf("Value exceeds regulator constraint limits\n");
+               return CMD_RET_FAILURE;
+       }
+
+       ret = regulator_set_value(dev, value);
+       if (ret)
+               return failed("set", uc_pdata->name, "voltage value",

ret);

common/cmd_regulator.c new file +5 -0
+
+       return CMD_RET_SUCCESS;
+}
+
+static int do_current(cmd_tbl_t *cmdtp, int flag, int argc, char *

const
argv[])

common/cmd_regulator.c new file +14 -0
+{
+       struct udevice *dev;
+       struct dm_regulator_uclass_platdata *uc_pdata;
+       int current;
+       int ret;
+
+       ret = get_curr_dev_and_pl(&dev, &uc_pdata, argc == 1);
+       if (ret)
+               return ret;
+
+       if (argc == 1) {
+               current = regulator_get_current(dev);
+               if (current < 0)
+                       return failed("get", uc_pdata->name, "current",

current);

common/cmd_regulator.c new file +8 -0
+
+               printf("%d uA\n", current);
+               return CMD_RET_SUCCESS;
+       }
+
+       current = simple_strtoul(argv[1], NULL, 0);
+       if (current < uc_pdata->min_uA || current > uc_pdata->max_uA) {
+               printf("Current exceeds regulator constraint

limits\n");

common/cmd_regulator.c new file +6 -0
+               return CMD_RET_FAILURE;
+       }
+
+       ret = regulator_set_current(dev, current);
+       if (ret)
+               return failed("set", uc_pdata->name, "current value",

ret);

common/cmd_regulator.c new file +5 -0
+
+       return CMD_RET_SUCCESS;
+}
+
+static int do_mode(cmd_tbl_t *cmdtp, int flag, int argc, char * const

argv[])

common/cmd_regulator.c new file +15 -0
+{
+       struct udevice *dev;
+       struct dm_regulator_uclass_platdata *uc_pdata;
+       int new_mode;
+       int mode;
+       int ret;
+
+       ret = get_curr_dev_and_pl(&dev, &uc_pdata, false);
+       if (ret)
+               return ret;
+
+       if (argc == 1) {
+               mode = regulator_get_mode(dev);
+               if (mode < 0)
+                       return failed("get", uc_pdata->name, "mode",

mode);

common/cmd_regulator.c new file +15 -0
+
+               printf("mode id: %d\n", mode);
+               return CMD_RET_SUCCESS;
+       }
+
+       new_mode = simple_strtoul(argv[1], NULL, 0);
+
+       ret = regulator_set_mode(dev, new_mode);
+       if (ret)
+               return failed("set", uc_pdata->name, "mode", ret);
+
+       return CMD_RET_SUCCESS;
+}
+
+static int do_enable(cmd_tbl_t *cmdtp, int flag, int argc, char *

const
argv[])

common/cmd_regulator.c new file +12 -0
+{
+       struct udevice *dev;
+       struct dm_regulator_uclass_platdata *uc_pdata;
+       int ret;
+
+       ret = get_curr_dev_and_pl(&dev, &uc_pdata, true);
+       if (ret)
+               return ret;
+
+       ret = regulator_set_enable(dev, true);
+       if (ret)
+               return failed("enable", "regulator", uc_pdata->name,

ret);

common/cmd_regulator.c new file +5 -0
+
+       return CMD_RET_SUCCESS;
+}
+
+static int do_disable(cmd_tbl_t *cmdtp, int flag, int argc, char *

const
argv[])

common/cmd_regulator.c new file +12 -0
+{
+       struct udevice *dev;
+       struct dm_regulator_uclass_platdata *uc_pdata;
+       int ret;
+
+       ret = get_curr_dev_and_pl(&dev, &uc_pdata, true);
+       if (ret)
+               return ret;
+
+       ret = regulator_set_enable(dev, false);
+       if (ret)
+               return failed("disable", "regulator", uc_pdata->name,

ret);

common/cmd_regulator.c new file +35 -0
+
+       return CMD_RET_SUCCESS;
+}
+
+static cmd_tbl_t subcmd[] = {
+       U_BOOT_CMD_MKENT(dev, 2, 1, do_dev, "", ""),
+       U_BOOT_CMD_MKENT(list, 1, 1, do_list, "", ""),
+       U_BOOT_CMD_MKENT(info, 2, 1, do_info, "", ""),
+       U_BOOT_CMD_MKENT(status, 2, 1, do_status, "", ""),
+       U_BOOT_CMD_MKENT(value, 3, 1, do_value, "", ""),
+       U_BOOT_CMD_MKENT(current, 3, 1, do_current, "", ""),
+       U_BOOT_CMD_MKENT(mode, 2, 1, do_mode, "", ""),
+       U_BOOT_CMD_MKENT(enable, 1, 1, do_enable, "", ""),
+       U_BOOT_CMD_MKENT(disable, 1, 1, do_disable, "", ""),
+};
+
+static int do_regulator(cmd_tbl_t *cmdtp, int flag, int argc,
+                       char * const argv[])
+{
+       cmd_tbl_t *cmd;
+
+       argc--;
+       argv++;
+
+       cmd = find_cmd_tbl(argv[0], subcmd, ARRAY_SIZE(subcmd));
+       if (cmd == NULL || argc > cmd->maxargs)
+               return CMD_RET_USAGE;
+
+       return cmd->cmd(cmdtp, flag, argc, argv);
+}
+
+U_BOOT_CMD(regulator, CONFIG_SYS_MAXARGS, 1, do_regulator,
+       "uclass operations",
+       "list         - list UCLASS regulator devices\n"
+       "regulator dev [id]     - show or [set] operating regulator

device\n"

common/cmd_regulator.c new file +3 -0
+       "regulator [info]       - print constraints info\n"
+       "regulator [status]     - print operating status\n"
+       "regulator [value] [-f] - print/[set] voltage value [uV]

(force)\n"

Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
common/cmd_regulator.c new file +5 -1
+       "regulator [current]    - print/[set] current value [uA]\n"
+       "regulator [mode_id]    - print/[set] operating mode id\n"
+       "regulator [enable]     - enable the regulator output\n"
+       "regulator [disable]    - disable the regulator output\n"
+);
--

1.9.1

Regards,
Simon

Regards,
Simon

#179 lore raw

PATCH v4 7/16 dm: regulator: add regulator command

Hello Simon,

Quoted 248 lines · Simon Glass

Hi Przemyslaw,

Quoted 238 lines · Przemyslaw Marczak

Hello Simon,

Quoted 150 lines · Simon Glass

Hi Przemyslaw,

Quoted 145 lines · Przemyslaw Marczak

Hello Simon,

Quoted 45 lines · Simon Glass

Hi Przemyslaw,

Quoted 29 lines · Przemyslaw Marczak

This command is based on driver model regulator's API. The user interface provides:
- list UCLASS regulator devices
- show or [set] operating regulator device
- print constraints info
- print operating status
- print/[set] voltage value [uV] (force)
- print/[set] current value [uA]
- print/[set] operating mode id
- enable the regulator output
- disable the regulator output

The 'force' option can be used for setting the value which exceeds the constraints min/max limits.

---
Changes v3:
- new file
- Kconfig entry

Changes V4:
- cmd regulator: move platdata to uc pdata
- cmd_regulator: includes cleanup
- cmd_regulator: add get_curr_dev_and_pl() check type
- move config name: CONFIG_DM_REGULATOR_CMD to CONFIG_CMD_REGULATOR
- common/Kconfig - cleanup

Quoted 7 lines
---
    common/Kconfig         |  22 +++
    common/Makefile        |   1 +
    common/cmd_regulator.c | 403
+++++++++++++++++++++++++++++++++++++++++++++++++
    3 files changed, 426 insertions(+)

create mode 100644 common/cmd_regulator.c

Quoted 4 lines

I have a few nits that could be dealt with by a follow-on patch.

Ok.

Quoted 84 lines
Quoted 77 lines
common/Kconfig +9 -0
index 4666f8e..52f8bb1 100644
@@ -470,5 +470,27 @@ config CMD_PMIC
             - pmic read address  - read byte of register at address
             - pmic write address - write byte to register at address
             The only one change for this command is 'dev' subcommand.
+
+config CMD_REGULATOR
+       bool "Enable Driver Model REGULATOR command"
+       depends on DM_REGULATOR
+       help
+         This command is based on driver model regulator's API.
+         User interface features:
+         - list               - list regulator devices
+         - regulator dev <id> - show or [set] operating regulator

device

common/Kconfig +9 -0
+         - regulator info     - print constraints info
+         - regulator status   - print operating status
+         - regulator value <val] <-f> - print/[set] voltage value [uV]
+         - regulator current <val>    - print/[set] current value [uA]
+         - regulator mode <id>        - print/[set] operating mode id
+         - regulator enable           - enable the regulator output
+         - regulator disable          - disable the regulator output
+
+         The '-f' (force) option can be used for set the value which

exceeds
+ the limits, which are found in device-tree and are kept in
regulator's

common/Kconfig +3 -0
+         uclass platdata structure.
+
    endmenu
+
    endmenu
common/Makefile +1 -0
index 87a3efe..93bded3 100644
@@ -212,6 +212,7 @@ obj-$(CONFIG_CMD_GPT) += cmd_gpt.o
 
    # Power
    obj-$(CONFIG_CMD_PMIC) += cmd_pmic.o
+obj-$(CONFIG_CMD_REGULATOR) += cmd_regulator.o
    endif
 
    ifdef CONFIG_SPL_BUILD
common/cmd_regulator.c new file +23 -0
new file mode 100644
index 0000000..b1b9e87
@@ -0,0 +1,403 @@
+/*
+ * Copyright (C) 2014-2015 Samsung Electronics
+ * Przemyslaw Marczak <[email protected]>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+#include <common.h>
+#include <errno.h>
+#include <dm.h>
+#include <dm/uclass-internal.h>
+#include <power/regulator.h>
+
+#define LIMIT_SEQ      3
+#define LIMIT_DEVNAME  20
+#define LIMIT_OFNAME   20
+#define LIMIT_INFO     16
+
+static struct udevice *currdev;
+
+static int failed(const char *getset, const char *thing,
+                 const char *for_dev, int ret)
+{
+       printf("Can't %s %s %s.\nError: %d (%s)\n", getset, thing,
Quoted 3 lines

for_dev,
+ ret,
errno_str(ret));

blank line here.

Quoted 5 lines
Quoted 1 line

I don't see the blank line here in the patch, which I send.

Odd, there seem to be two blank lines there, and we only need one.

Ah, sorry. You mean, that there should be added a blank line. Ok, will add one.

Quoted 14 lines
Quoted 8 lines
Quoted 7 lines

I worry that if someone gets one of these messages they will not be able to find it in the source code. How about passing in the full printf() string in each case, or just using printf() in situ? I don't think the code space saving is significant.

Quoted 4 lines

It's not a debug message. And each one is different, and easy to grep "failed". The code is a little cleaner with this. Also the command code is
not complicated.

Quoted 6 lines

git grep -i failed |wc -l
2089

Is there some way to know it is a PMIC error message, and find it that way?

Ok, I assumed that you know which command you called, and where to find it, so you could use:
grep -i "failed" common/cmd_regulator.c | wc -l
15

But this was only the function name, not a useful text for grep. Now I see that this should use the printf instead of the helper funcion.

Quoted 29 lines
Quoted 29 lines
Quoted 28 lines
Quoted 6 lines
common/cmd_regulator.c new file +4 -0
+       return CMD_RET_FAILURE;
+}
+
+static int regulator_get(bool list_only, int get_seq, struct udevice

**devp)

This function seems to do multiple things (find and list). Should we split it into two?

common/cmd_regulator.c line 38

Quoted 10 lines
common/cmd_regulator.c new file +10 -0
+{
+       struct dm_regulator_uclass_platdata *uc_pdata;
+       struct udevice *dev;
+       int ret;
+
+       if (devp)
+               *devp = NULL;
+
+       for (ret = uclass_first_device(UCLASS_REGULATOR, &dev); dev;
+            ret = uclass_next_device(&dev)) {

This will probe all regulators that it checks. I think it should avoid that. Do you mean to use

Quoted 9 lines
Quoted 5 lines

Regarding the two above comments, we have two problems:

1. Getting the regulator by sequencial number (dev->seq).
I think it's required, because only this method returns the right device.
Disadvantage: need to probe all devices.

But you can use req_seq, or if you have platform data, check that.

Ok, we could use the req_seq for the PMIC uclass, it's natural that interface, has its address and <reg> property - but this can repeat, if we have two PMICs on a different busses. This is probably possible.

We also shouldn't set the req_seq as the number found in node name, because those numbers can repeat: ldo1 {}; buck1 {}; regulator1 { }.

Quoted 6 lines

I think that, using the req_seq is bad idea, since we can't be sure that those values are unique.

I understand that, the probe is not ideal here? But from the other side, if we call "pmic list", then we are sure, that listed devices are ready to use. Shouldn't we expect this?

Quoted 5 lines

I was hoping that we would not probe devices until they are actually used, and that listing them would not constitute 'use'.

In the case of listing, you should not need to worry about ->seq or ->req_seq. If you avoid 'getting' the device you will not probe it.

Yes I know, that I can use the uclass_find_first/next_device() functions here. But only after moving the "regulator dev" command to getting the regulator by it's "name" constraint as will do in the fixup patches.

Quoted 4 lines

In the case of getting a device ready for use, yes, it must be probed. But I am only commenting on your 'list' function.

Yes this is clean for me.

I'm only wonder now, what to do with the "pmic list/dev" commands.

Actually, for the multi interface PMIC IC, we can be sure, that for each interface device will have a different name (dev->name).

But even if the nodes are inside a different parent bus nodes, and have the same names, we probably could assume, that each PMIC's interface has a different address.
To be sure we could put some note into the documentation, that for the PMICs, each node name should be unique.

Then I can use:
- uclass_find_first/next_device() for listing PMIC devices
- uclass_get_device_by_name() for getting the required PMIC

Is that correct, for you?

[snip]

Best regards,

Signature · 4 lines
Przemyslaw Marczak
Samsung R&D Institute Poland
Samsung Electronics
p.marczak at samsung.com
#180 lore raw

PATCH v4 7/16 dm: regulator: add regulator command

Hi Przemyslaw,

Quoted 305 lines · Przemyslaw Marczak

Hello Simon,

Quoted 272 lines · Simon Glass

Hi Przemyslaw,

Quoted 258 lines · Przemyslaw Marczak

Hello Simon,

Quoted 161 lines · Simon Glass

Hi Przemyslaw,

Quoted 155 lines · Przemyslaw Marczak

Hello Simon,

Quoted 48 lines · Simon Glass

Hi Przemyslaw,

Quoted 30 lines · Przemyslaw Marczak

This command is based on driver model regulator's API. The user interface provides:
- list UCLASS regulator devices
- show or [set] operating regulator device
- print constraints info
- print operating status
- print/[set] voltage value [uV] (force)
- print/[set] current value [uA]
- print/[set] operating mode id
- enable the regulator output
- disable the regulator output

The 'force' option can be used for setting the value which exceeds the constraints min/max limits.

---
Changes v3:
- new file
- Kconfig entry

Changes V4:
- cmd regulator: move platdata to uc pdata
- cmd_regulator: includes cleanup
- cmd_regulator: add get_curr_dev_and_pl() check type
- move config name: CONFIG_DM_REGULATOR_CMD to CONFIG_CMD_REGULATOR
- common/Kconfig - cleanup

Quoted 7 lines
---
    common/Kconfig         |  22 +++
    common/Makefile        |   1 +
    common/cmd_regulator.c | 403
+++++++++++++++++++++++++++++++++++++++++++++++++
    3 files changed, 426 insertions(+)

create mode 100644 common/cmd_regulator.c

Quoted 4 lines

I have a few nits that could be dealt with by a follow-on patch.

Ok.

Quoted 89 lines
Quoted 81 lines
common/Kconfig +0 -0
index 4666f8e..52f8bb1 100644
@@ -470,5 +470,27 @@ config CMD_PMIC
             - pmic read address  - read byte of register at address
             - pmic write address - write byte to register at address
             The only one change for this command is 'dev'

subcommand.

common/Kconfig +9 -0
+
+config CMD_REGULATOR
+       bool "Enable Driver Model REGULATOR command"
+       depends on DM_REGULATOR
+       help
+         This command is based on driver model regulator's API.
+         User interface features:
+         - list               - list regulator devices
+         - regulator dev <id> - show or [set] operating regulator

device

common/Kconfig +3 -0
+         - regulator info     - print constraints info
+         - regulator status   - print operating status
+         - regulator value <val] <-f> - print/[set] voltage value

[uV]
+ - regulator current <val> - print/[set] current value
[uA]
+ - regulator mode <id> - print/[set] operating mode
id

common/Kconfig +4 -0
+         - regulator enable           - enable the regulator output
+         - regulator disable          - disable the regulator output
+
+         The '-f' (force) option can be used for set the value which

exceeds
+ the limits, which are found in device-tree and are kept in
regulator's

common/Kconfig +3 -0
+         uclass platdata structure.
+
    endmenu
+
    endmenu
common/Makefile +1 -0
index 87a3efe..93bded3 100644
@@ -212,6 +212,7 @@ obj-$(CONFIG_CMD_GPT) += cmd_gpt.o
 
    # Power
    obj-$(CONFIG_CMD_PMIC) += cmd_pmic.o
+obj-$(CONFIG_CMD_REGULATOR) += cmd_regulator.o
    endif
 
    ifdef CONFIG_SPL_BUILD
common/cmd_regulator.c new file +23 -0
new file mode 100644
index 0000000..b1b9e87
@@ -0,0 +1,403 @@
+/*
+ * Copyright (C) 2014-2015 Samsung Electronics
+ * Przemyslaw Marczak <[email protected]>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+#include <common.h>
+#include <errno.h>
+#include <dm.h>
+#include <dm/uclass-internal.h>
+#include <power/regulator.h>
+
+#define LIMIT_SEQ      3
+#define LIMIT_DEVNAME  20
+#define LIMIT_OFNAME   20
+#define LIMIT_INFO     16
+
+static struct udevice *currdev;
+
+static int failed(const char *getset, const char *thing,
+                 const char *for_dev, int ret)
+{
+       printf("Can't %s %s %s.\nError: %d (%s)\n", getset, thing,
Quoted 3 lines

for_dev,
+ ret,
errno_str(ret));

blank line here.

Quoted 6 lines
Quoted 1 line

I don't see the blank line here in the patch, which I send.

Odd, there seem to be two blank lines there, and we only need one.

Ah, sorry. You mean, that there should be added a blank line. Ok, will add one.

Quoted 15 lines
Quoted 8 lines
Quoted 7 lines

I worry that if someone gets one of these messages they will not be able to find it in the source code. How about passing in the full printf() string in each case, or just using printf() in situ? I don't think the code space saving is significant.

Quoted 4 lines

It's not a debug message. And each one is different, and easy to grep "failed". The code is a little cleaner with this. Also the command code is
not complicated.

Quoted 6 lines

git grep -i failed |wc -l
2089

Is there some way to know it is a PMIC error message, and find it that way?

Ok, I assumed that you know which command you called, and where to find it,
so you could use:
grep -i "failed" common/cmd_regulator.c | wc -l
15

But this was only the function name, not a useful text for grep. Now I see that this should use the printf instead of the helper funcion.

Quoted 33 lines
Quoted 33 lines
Quoted 13 lines
Quoted 6 lines
common/cmd_regulator.c new file +4 -0
+       return CMD_RET_FAILURE;
+}
+
+static int regulator_get(bool list_only, int get_seq, struct udevice

**devp)

This function seems to do multiple things (find and list). Should we split it into two?

Quoted 17 lines

common/cmd_regulator.c

Quoted 10 lines
common/cmd_regulator.c new file +10 -0
+{
+       struct dm_regulator_uclass_platdata *uc_pdata;
+       struct udevice *dev;
+       int ret;
+
+       if (devp)
+               *devp = NULL;
+
+       for (ret = uclass_first_device(UCLASS_REGULATOR, &dev); dev;
+            ret = uclass_next_device(&dev)) {

This will probe all regulators that it checks. I think it should avoid that. Do you mean to use

Regarding the two above comments, we have two problems:

Quoted 9 lines
Quoted 4 lines

1. Getting the regulator by sequencial number (dev->seq). I think it's required, because only this method returns the right device.
Disadvantage: need to probe all devices.

But you can use req_seq, or if you have platform data, check that.

Ok, we could use the req_seq for the PMIC uclass, it's natural that interface, has its address and <reg> property - but this can repeat, if we have two PMICs on a different busses. This is probably possible.

We also shouldn't set the req_seq as the number found in node name, because
those numbers can repeat: ldo1 {}; buck1 {}; regulator1 { }.

Quoted 7 lines

I think that, using the req_seq is bad idea, since we can't be sure that those values are unique.

I understand that, the probe is not ideal here? But from the other side, if we call "pmic list", then we are sure, that listed devices are ready to
use. Shouldn't we expect this?

Quoted 5 lines

I was hoping that we would not probe devices until they are actually used, and that listing them would not constitute 'use'.

In the case of listing, you should not need to worry about ->seq or ->req_seq. If you avoid 'getting' the device you will not probe it.

Yes I know, that I can use the uclass_find_first/next_device() functions here. But only after moving the "regulator dev" command to getting the regulator by it's "name" constraint as will do in the fixup patches.

Quoted 4 lines

In the case of getting a device ready for use, yes, it must be probed. But I am only commenting on your 'list' function.

Yes this is clean for me.

I'm only wonder now, what to do with the "pmic list/dev" commands.

Actually, for the multi interface PMIC IC, we can be sure, that for each interface device will have a different name (dev->name).

But even if the nodes are inside a different parent bus nodes, and have the same names, we probably could assume, that each PMIC's interface has a different address.
To be sure we could put some note into the documentation, that for the PMICs, each node name should be unique.

Quoted 5 lines

Then I can use:
- uclass_find_first/next_device() for listing PMIC devices
- uclass_get_device_by_name() for getting the required PMIC

Is that correct, for you?

Yes, I think that is good. It will just confuse everyone if we try to handle two PMICs with the same name (or two regulators for that matter). Adding a note to the doc sounds good.

Regards,
Simon

#181 lore raw

PATCH v4 8/16 pmic: max77686 set the same compatible as in the kernel

In reply to Przemyslaw Marczak

This commit also updates the proper dts files.

---
 arch/arm/dts/exynos4412-odroid.dts   | 2 +-
 arch/arm/dts/exynos4412-trats2.dts   | 2 +-
 arch/arm/dts/exynos5250-smdk5250.dts | 2 +-
 arch/arm/dts/exynos5250-snow.dts     | 2 +-
 lib/fdtdec.c                         | 2 +-
 5 files changed, 5 insertions(+), 5 deletions(-)
arch/arm/dts/exynos4412-odroid.dts +1 -1
index 582f6e5..5507d9a 100644
@@ -36,7 +36,7 @@
 		status = "okay";
 
 		max77686_pmic at 09 {
-			compatible = "maxim,max77686_pmic";
+			compatible = "maxim,max77686";
 			interrupts = <7 0>;
 			reg = <0x09 0 0>;
 			#clock-cells = <1>;
arch/arm/dts/exynos4412-trats2.dts +1 -1
index dd238df..5c0bb91 100644
@@ -41,7 +41,7 @@
 		status = "okay";
 
 		max77686_pmic at 09 {
-			compatible = "maxim,max77686_pmic";
+			compatible = "maxim,max77686";
 			interrupts = <7 0>;
 			reg = <0x09 0 0>;
 			#clock-cells = <1>;
arch/arm/dts/exynos5250-smdk5250.dts +1 -1
index 9273562..3cebfc2 100644
@@ -68,7 +68,7 @@
 	i2c at 12c60000 {
 		pmic at 9 {
 			reg = <0x9>;
-			compatible = "maxim,max77686_pmic";
+			compatible = "maxim,max77686";
 		};
 	};
 
arch/arm/dts/exynos5250-snow.dts +1 -1
index e89a94f..e4b3dc2 100644
@@ -108,7 +108,7 @@
 	i2c at 12c60000 {
 		pmic at 9 {
 			reg = <0x9>;
-			compatible = "maxim,max77686_pmic";
+			compatible = "maxim,max77686";
 		};
 	};
 
lib/fdtdec.c +1 -1
index 331eae2..244fd77 100644
@@ -54,7 +54,7 @@ static const char * const compat_names[COMPAT_COUNT] = {
 	COMPAT(SAMSUNG_EXYNOS_DWMMC, "samsung,exynos-dwmmc"),
 	COMPAT(SAMSUNG_EXYNOS_MMC, "samsung,exynos-mmc"),
 	COMPAT(SAMSUNG_EXYNOS_SERIAL, "samsung,exynos4210-uart"),
-	COMPAT(MAXIM_MAX77686_PMIC, "maxim,max77686_pmic"),
+	COMPAT(MAXIM_MAX77686_PMIC, "maxim,max77686"),
 	COMPAT(GENERIC_SPI_FLASH, "spi-flash"),
 	COMPAT(MAXIM_98095_CODEC, "maxim,max98095-codec"),
 	COMPAT(INFINEON_SLB9635_TPM, "infineon,slb9635-tpm"),
Signature · 1 line
1.9.1
#182 lore raw

PATCH v4 8/16 pmic: max77686 set the same compatible as in the kernel

Quoted 10 lines · Przemyslaw Marczak

This commit also updates the proper dts files.

---
 arch/arm/dts/exynos4412-odroid.dts   | 2 +-
 arch/arm/dts/exynos4412-trats2.dts   | 2 +-
 arch/arm/dts/exynos5250-smdk5250.dts | 2 +-
 arch/arm/dts/exynos5250-snow.dts     | 2 +-
 lib/fdtdec.c                         | 2 +-
 5 files changed, 5 insertions(+), 5 deletions(-)
#183 lore raw

PATCH v4 8/16 pmic: max77686 set the same compatible as in the kernel

Quoted 12 lines · Simon Glass
Quoted 10 lines · Przemyslaw Marczak

This commit also updates the proper dts files.

---
 arch/arm/dts/exynos4412-odroid.dts   | 2 +-
 arch/arm/dts/exynos4412-trats2.dts   | 2 +-
 arch/arm/dts/exynos5250-smdk5250.dts | 2 +-
 arch/arm/dts/exynos5250-snow.dts     | 2 +-
 lib/fdtdec.c                         | 2 +-
 5 files changed, 5 insertions(+), 5 deletions(-)
Quoted 1 line

Applied to u-boot-dm/next, thanks!

#184 lore raw

PATCH v4 9/16 dm: pmic: add max77686 pmic driver

In reply to Przemyslaw Marczak

This is the implementation of driver model PMIC driver. The max77686 PMIC driver implements read/write operations and driver bind method - to bind its childs.

This driver will try to bind the regulator devices by using it's child info array with regulator prefixes and driver names. This should succeed when compatible regulator driver is compiled. If no regulator driver found, then the pmic can still provide read/write operations, and can be used with PMIC function calls.

---
Changes V2:
- add implementation of pmic read/write
- max77686: add new operations
- max77686: header: change PMIC_NUM_OF_REGS to MAX77686_NUM_OF_REGS

Changes V3:
- pmic/max77686.c: call pmic_child_node_scan() to bind regulator device
- remove use of pmic platdata
- remove unused endian conversions
- Kconfig: add max77686 pmic entry

Changes V4:
- move DM_PMIC_MAX77686 Kconfig entry from: drivers/power/Kconfig to drivers/power/pmic/Kconfig
- pmic/max77686.c: cleanup
- pmic/max77686.c: includes cleanup
- max77686_pmic.h: define ldo and buck driver names
- power/Kconfig: cleanup
- add binding info

---
 doc/device-tree-bindings/pmic/max77686.txt | 36 +++++++++++++
 drivers/power/pmic/Kconfig                 |  7 +++
 drivers/power/pmic/Makefile                |  1 +
 drivers/power/pmic/max77686.c              | 87 ++++++++++++++++++++++++++++++
 drivers/power/pmic/pmic_max77686.c         |  2 +-
 include/power/max77686_pmic.h              | 10 +++-
 6 files changed, 140 insertions(+), 3 deletions(-)
 create mode 100644 doc/device-tree-bindings/pmic/max77686.txt
 create mode 100644 drivers/power/pmic/max77686.c
doc/device-tree-bindings/pmic/max77686.txt new file +36 -0
new file mode 100644
index 0000000..54e1f69
@@ -0,0 +1,36 @@
+MAXIM, MAX77686 pmic
+
+This device uses two drivers:
+- drivers/power/pmic/max77686.c (for parent device)
+- drivers/power/regulator/max77686.c (for child regulators)
+
+This file describes the binding info for the PMIC driver.
+
+To bind the regulators, please read the additional binding info:
+- doc/device-tree-bindings/regulator/max77686.txt
+
+Required properties:
+- compatible: "maxim,max77686"
+- reg = 0x9
+
+With those two properties, the pmic device can be used for read/write only.
+To bind each regulator, the optional regulators subnode should exists.
+
+Optional subnode:
+- voltage-regulators: subnode list of each device's regulator
+  (see max77686.txt - regulator binding info)
+
+Example:
+
+max77686 at 09 {
+	compatible = "maxim,max77686";
+	reg = <0x09>;
+
+	voltage-regulators {
+		ldo1 {
+			...
+		};
+		...
+	};
+};
+
drivers/power/pmic/Kconfig +7 -0
index d06d632..af68783 100644
@@ -9,3 +9,10 @@ config DM_PMIC
 	for read/write. For detailed description, please refer to the files:
 	- 'drivers/power/pmic/pmic-uclass.c'
 	- 'include/power/pmic.h'
+
+config DM_PMIC_MAX77686
+	bool "Enable Driver Model for PMIC MAX77686"
+	depends on DM_PMIC
+	---help---
+	This config enables implementation of driver-model pmic uclass features
+	for PMIC MAX77686. The driver implements read/write operations.
\ No newline at end of file
drivers/power/pmic/Makefile +1 -0
index 594f620..8cb993d 100644
@@ -11,6 +11,7 @@ obj-$(CONFIG_POWER_MAX8998) += pmic_max8998.o
 obj-$(CONFIG_POWER_MAX8997) += pmic_max8997.o
 obj-$(CONFIG_POWER_MUIC_MAX8997) += muic_max8997.o
 obj-$(CONFIG_POWER_MAX77686) += pmic_max77686.o
+obj-$(CONFIG_DM_PMIC_MAX77686) += max77686.o
 obj-$(CONFIG_POWER_PFUZE100) += pmic_pfuze100.o
 obj-$(CONFIG_POWER_TPS65090_I2C) += pmic_tps65090.o
 obj-$(CONFIG_POWER_TPS65090_EC) += pmic_tps65090_ec.o
drivers/power/pmic/max77686.c new file +87 -0

87 lines not on this page · raw message

drivers/power/pmic/pmic_max77686.c +1 -1
index 95b1a57..1ad810a 100644
@@ -295,7 +295,7 @@ int pmic_init(unsigned char bus)
 
 	p->name = name;
 	p->interface = PMIC_I2C;
-	p->number_of_regs = PMIC_NUM_OF_REGS;
+	p->number_of_regs = MAX77686_NUM_OF_REGS;
 	p->hw.i2c.tx_num = 1;
 
 	puts("Board PMIC init\n");
include/power/max77686_pmic.h +8 -2
index b0e4255..95597db 100644
@@ -122,11 +122,17 @@ enum {
 	MAX77686_REG_PMIC_BBAT		= 0x7e,
 	MAX77686_REG_PMIC_32KHZ,
 
-	PMIC_NUM_OF_REGS,
+	MAX77686_NUM_OF_REGS,
 };
 
 /* I2C device address for pmic max77686 */
-#define MAX77686_I2C_ADDR (0x12 >> 1)
+#define MAX77686_I2C_ADDR	(0x12 >> 1)
+#define MAX77686_LDO_NUM	26
+#define MAX77686_BUCK_NUM	9
+
+/* Drivers name */
+#define MAX77686_LDO_DRIVER	"max77686_ldo"
+#define MAX77686_BUCK_DRIVER	"max77686_buck"
 
 enum {
 	REG_DISABLE = 0,
Signature · 1 line
1.9.1
#185 lore raw

PATCH v4 9/16 dm: pmic: add max77686 pmic driver

Quoted 31 lines · Przemyslaw Marczak

This is the implementation of driver model PMIC driver. The max77686 PMIC driver implements read/write operations and driver bind method - to bind its childs.

This driver will try to bind the regulator devices by using it's child info array with regulator prefixes and driver names. This should succeed when compatible regulator driver is compiled. If no regulator driver found, then the pmic can still provide read/write operations, and can be used with PMIC function calls.

---
Changes V2:
- add implementation of pmic read/write
- max77686: add new operations
- max77686: header: change PMIC_NUM_OF_REGS to MAX77686_NUM_OF_REGS

Changes V3:
- pmic/max77686.c: call pmic_child_node_scan() to bind regulator device
- remove use of pmic platdata
- remove unused endian conversions
- Kconfig: add max77686 pmic entry

Changes V4:
- move DM_PMIC_MAX77686 Kconfig entry from: drivers/power/Kconfig to drivers/power/pmic/Kconfig
- pmic/max77686.c: cleanup
- pmic/max77686.c: includes cleanup
- max77686_pmic.h: define ldo and buck driver names
- power/Kconfig: cleanup
- add binding info

Quoted 10 lines
---
 doc/device-tree-bindings/pmic/max77686.txt | 36 +++++++++++++
 drivers/power/pmic/Kconfig                 |  7 +++
 drivers/power/pmic/Makefile                |  1 +
 drivers/power/pmic/max77686.c              | 87 ++++++++++++++++++++++++++++++
 drivers/power/pmic/pmic_max77686.c         |  2 +-
 include/power/max77686_pmic.h              | 10 +++-
 6 files changed, 140 insertions(+), 3 deletions(-)
 create mode 100644 doc/device-tree-bindings/pmic/max77686.txt
 create mode 100644 drivers/power/pmic/max77686.c
#186 lore raw

PATCH v4 9/16 dm: pmic: add max77686 pmic driver

Quoted 43 lines · Simon Glass
Quoted 31 lines · Przemyslaw Marczak

This is the implementation of driver model PMIC driver. The max77686 PMIC driver implements read/write operations and driver bind method - to bind its childs.

This driver will try to bind the regulator devices by using it's child info array with regulator prefixes and driver names. This should succeed when compatible regulator driver is compiled. If no regulator driver found, then the pmic can still provide read/write operations, and can be used with PMIC function calls.

---
Changes V2:
- add implementation of pmic read/write
- max77686: add new operations
- max77686: header: change PMIC_NUM_OF_REGS to MAX77686_NUM_OF_REGS

Changes V3:
- pmic/max77686.c: call pmic_child_node_scan() to bind regulator device
- remove use of pmic platdata
- remove unused endian conversions
- Kconfig: add max77686 pmic entry

Changes V4:
- move DM_PMIC_MAX77686 Kconfig entry from: drivers/power/Kconfig to drivers/power/pmic/Kconfig
- pmic/max77686.c: cleanup
- pmic/max77686.c: includes cleanup
- max77686_pmic.h: define ldo and buck driver names
- power/Kconfig: cleanup
- add binding info

Quoted 10 lines
---
 doc/device-tree-bindings/pmic/max77686.txt | 36 +++++++++++++
 drivers/power/pmic/Kconfig                 |  7 +++
 drivers/power/pmic/Makefile                |  1 +
 drivers/power/pmic/max77686.c              | 87 ++++++++++++++++++++++++++++++
 drivers/power/pmic/pmic_max77686.c         |  2 +-
 include/power/max77686_pmic.h              | 10 +++-
 6 files changed, 140 insertions(+), 3 deletions(-)
 create mode 100644 doc/device-tree-bindings/pmic/max77686.txt
 create mode 100644 drivers/power/pmic/max77686.c
Quoted 1 line

Applied to u-boot-dm/next, thanks!

#187 lore raw

PATCH v4 10/16 dm: regulator: add max77686 regulator driver

In reply to Przemyslaw Marczak

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

---
Changes V2:
- change debug() to error()
- code cleanup
- fix data types
- ldo/buck state implementation
- adjust to new uclass api

Changes V3:
- regulator/max77686.c:
-- adjust to api changes
-- add separeted drivers for buck and ldo
-- bind regulators by its compatibles
- Kconfig: add regulator max77686 entry

Changes V4:
- move DM_REGULATOR_MAX77686 Kconfig entry from: drivers/power/Kconfig to drivers/power/regulator/Kconfig
- regulator/max77686.c: cleanup
- regulator/max77686.c: add missing break for switch
- regulator/max77686.c: includes cleanup
- regulator.h: comments cleanup
- add binding info

---
 doc/device-tree-bindings/regulator/max77686.txt |  70 ++
 drivers/power/Makefile                          |   1 -
 drivers/power/regulator/Kconfig                 |   8 +
 drivers/power/regulator/Makefile                |   1 +
 drivers/power/regulator/max77686.c              | 825 ++++++++++++++++++++++++
 include/power/max77686_pmic.h                   |  19 +-
 include/power/regulator.h                       |  42 +-
 7 files changed, 942 insertions(+), 24 deletions(-)
 create mode 100644 doc/device-tree-bindings/regulator/max77686.txt
 create mode 100644 drivers/power/regulator/max77686.c
doc/device-tree-bindings/regulator/max77686.txt new file +70 -0
new file mode 100644
index 0000000..ae9b1b6
@@ -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>;
+	};
+};
drivers/power/Makefile +0 -1
index 2145652..a2d3c04 100644
@@ -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
drivers/power/regulator/Kconfig +8 -0
index cb15162..0cdfabc 100644
@@ -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.
drivers/power/regulator/Makefile +1 -0
index 27c9006..f9c4e6d 100644
@@ -6,3 +6,4 @@
 #
 
 obj-$(CONFIG_DM_REGULATOR) += regulator-uclass.o
+obj-$(CONFIG_DM_REGULATOR_MAX77686) += max77686.o
drivers/power/regulator/max77686.c new file +825 -0

825 lines not on this page · raw message

include/power/max77686_pmic.h +17 -2
index 95597db..2300352 100644
@@ -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 */
include/power/regulator.h +21 -21

156 lines not on this page · raw message

Signature · 1 line
1.9.1
#188 lore raw

PATCH v4 10/16 dm: regulator: add max77686 regulator driver

Quoted 34 lines · Przemyslaw Marczak

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

---
Changes V2:
- change debug() to error()
- code cleanup
- fix data types
- ldo/buck state implementation
- adjust to new uclass api

Changes V3:
- regulator/max77686.c:
-- adjust to api changes
-- add separeted drivers for buck and ldo
-- bind regulators by its compatibles
- Kconfig: add regulator max77686 entry

Changes V4:
- move DM_REGULATOR_MAX77686 Kconfig entry from: drivers/power/Kconfig to drivers/power/regulator/Kconfig
- regulator/max77686.c: cleanup
- regulator/max77686.c: add missing break for switch
- regulator/max77686.c: includes cleanup
- regulator.h: comments cleanup
- add binding info

Quoted 11 lines
---
 doc/device-tree-bindings/regulator/max77686.txt |  70 ++
 drivers/power/Makefile                          |   1 -
 drivers/power/regulator/Kconfig                 |   8 +
 drivers/power/regulator/Makefile                |   1 +
 drivers/power/regulator/max77686.c              | 825 ++++++++++++++++++++++++
 include/power/max77686_pmic.h                   |  19 +-
 include/power/regulator.h                       |  42 +-
 7 files changed, 942 insertions(+), 24 deletions(-)
 create mode 100644 doc/device-tree-bindings/regulator/max77686.txt
 create mode 100644 drivers/power/regulator/max77686.c
#189 lore raw

PATCH v4 10/16 dm: regulator: add max77686 regulator driver

Quoted 47 lines · Simon Glass
Quoted 34 lines · Przemyslaw Marczak

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

---
Changes V2:
- change debug() to error()
- code cleanup
- fix data types
- ldo/buck state implementation
- adjust to new uclass api

Changes V3:
- regulator/max77686.c:
-- adjust to api changes
-- add separeted drivers for buck and ldo
-- bind regulators by its compatibles
- Kconfig: add regulator max77686 entry

Changes V4:
- move DM_REGULATOR_MAX77686 Kconfig entry from: drivers/power/Kconfig to drivers/power/regulator/Kconfig
- regulator/max77686.c: cleanup
- regulator/max77686.c: add missing break for switch
- regulator/max77686.c: includes cleanup
- regulator.h: comments cleanup
- add binding info

Quoted 11 lines
---
 doc/device-tree-bindings/regulator/max77686.txt |  70 ++
 drivers/power/Makefile                          |   1 -
 drivers/power/regulator/Kconfig                 |   8 +
 drivers/power/regulator/Makefile                |   1 +
 drivers/power/regulator/max77686.c              | 825 ++++++++++++++++++++++++
 include/power/max77686_pmic.h                   |  19 +-
 include/power/regulator.h                       |  42 +-
 7 files changed, 942 insertions(+), 24 deletions(-)
 create mode 100644 doc/device-tree-bindings/regulator/max77686.txt
 create mode 100644 drivers/power/regulator/max77686.c
Quoted 1 line

Applied to u-boot-dm/next, thanks!

#190 lore raw

PATCH v4 11/16 dm: regulator: add fixed voltage regulator driver

In reply to Przemyslaw Marczak

This driver implements regulator operations for fixed Voltage/Current value regulators. beside the standard regulator constraints, which are put into the uclass platform data, a typical fixed regulator node provides few additional properties like:
- gpio
- gpio-open-drain
- enable-active-high
- startup-delay-us
The only 'gpio' is used by this driver and is kept in structure of type 'fixed_regulator_platdata', as a device platform data (dev->platdata).

The driver implements:
- get_value
- get_current
- get_enable
- set_enable

The regulator calls and commands can be used for fixed-regulator devices, and the proper error will be returned for prohibited.

Changes v3:
- new file
- Kconfig add fixed-regulator entry

Changes V4:
- move DM_REGULATOR_FIXED Kconfig entry from: drivers/power/Kconfig to drivers/power/regulator/Kconfig
- regulator/fixed.c: adjust to use of uclass platdata and device platdata
- regulator/fixed.c: includes cleanup
- regulator/fixed.c: fix gpio request
- add binding info

---
 doc/device-tree-bindings/regulator/fixed.txt |  38 ++++++++
 drivers/power/regulator/Kconfig              |   8 ++
 drivers/power/regulator/Makefile             |   1 +
 drivers/power/regulator/fixed.c              | 126 +++++++++++++++++++++++++++
 4 files changed, 173 insertions(+)
 create mode 100644 doc/device-tree-bindings/regulator/fixed.txt
 create mode 100644 drivers/power/regulator/fixed.c
doc/device-tree-bindings/regulator/fixed.txt new file +38 -0
new file mode 100644
index 0000000..4ff39b8
@@ -0,0 +1,38 @@
+Fixed Voltage regulator
+
+Binding:
+The binding is done by the property "compatible" - this is different, than for
+binding by the node prefix (doc/device-tree-bindings/regulator/regulator.txt).
+
+Required properties:
+- compatible: "regulator-fixed"
+- regulator-name: this is required by the regulator uclass
+
+Optional properties:
+- gpio: GPIO to use for enable control
+- regulator constraints (binding info: regulator.txt)
+
+Other kernel-style properties, are currently not used.
+
+Note:
+For the regulator constraints, driver expects that:
+- regulator-min-microvolt is equal to regulator-max-microvolt
+- regulator-min-microamp is equal to regulator-max-microamp
+
+Example:
+fixed_regulator at 0 {
+	/* Mandatory */
+	compatible = "regulator-fixed";
+	regulator-name = "LED_3.3V";
+
+	/* Optional: */
+	gpio = <&gpc1 0 GPIO_ACTIVE_LOW>;
+
+	/* Optional for regulator uclass */
+	regulator-min-microvolt = <3300000>;
+	regulator-max-microvolt = <3300000>;
+	regulator-min-microamp = <15000>;
+	regulator-max-microamp = <15000>;
+	regulator-always-on;
+	regulator-boot-on;
+};
drivers/power/regulator/Kconfig +8 -0
index 0cdfabc..54ce188 100644
@@ -23,3 +23,11 @@ config DM_REGULATOR_MAX77686
 	This config enables implementation of driver-model regulator uclass
 	features for REGULATOR MAX77686. The driver implements get/set api for:
 	value, enable and mode.
+
+config DM_REGULATOR_FIXED
+	bool "Enable Driver Model for REGULATOR Fixed value"
+	depends on DM_REGULATOR
+	---help---
+	This config enables implementation of driver-model regulator uclass
+	features for fixed value regulators. The driver implements get/set api
+	for enable and get only for voltage value.
drivers/power/regulator/Makefile +1 -0
index f9c4e6d..cc8326d 100644
@@ -7,3 +7,4 @@
 
 obj-$(CONFIG_DM_REGULATOR) += regulator-uclass.o
 obj-$(CONFIG_DM_REGULATOR_MAX77686) += max77686.o
+obj-$(CONFIG_DM_REGULATOR_FIXED) += fixed.o
drivers/power/regulator/fixed.c new file +126 -0

126 lines not on this page · raw message

Signature · 1 line
1.9.1
#191 lore raw

PATCH v4 11/16 dm: regulator: add fixed voltage regulator driver

Quoted 33 lines · Przemyslaw Marczak

This driver implements regulator operations for fixed Voltage/Current value regulators. beside the standard regulator constraints, which are put into the uclass platform data, a typical fixed regulator node provides few additional properties like:
- gpio
- gpio-open-drain
- enable-active-high
- startup-delay-us
The only 'gpio' is used by this driver and is kept in structure of type 'fixed_regulator_platdata', as a device platform data (dev->platdata).

The driver implements:
- get_value
- get_current
- get_enable
- set_enable

The regulator calls and commands can be used for fixed-regulator devices, and the proper error will be returned for prohibited.

Changes v3:
- new file
- Kconfig add fixed-regulator entry

Changes V4:
- move DM_REGULATOR_FIXED Kconfig entry from: drivers/power/Kconfig to drivers/power/regulator/Kconfig
- regulator/fixed.c: adjust to use of uclass platdata and device platdata
- regulator/fixed.c: includes cleanup
- regulator/fixed.c: fix gpio request
- add binding info

Quoted 8 lines
---
 doc/device-tree-bindings/regulator/fixed.txt |  38 ++++++++
 drivers/power/regulator/Kconfig              |   8 ++
 drivers/power/regulator/Makefile             |   1 +
 drivers/power/regulator/fixed.c              | 126 +++++++++++++++++++++++++++
 4 files changed, 173 insertions(+)
 create mode 100644 doc/device-tree-bindings/regulator/fixed.txt
 create mode 100644 drivers/power/regulator/fixed.c
#192 lore raw

PATCH v4 11/16 dm: regulator: add fixed voltage regulator driver

Quoted 43 lines · Simon Glass
Quoted 33 lines · Przemyslaw Marczak

This driver implements regulator operations for fixed Voltage/Current value regulators. beside the standard regulator constraints, which are put into the uclass platform data, a typical fixed regulator node provides few additional properties like:
- gpio
- gpio-open-drain
- enable-active-high
- startup-delay-us
The only 'gpio' is used by this driver and is kept in structure of type 'fixed_regulator_platdata', as a device platform data (dev->platdata).

The driver implements:
- get_value
- get_current
- get_enable
- set_enable

The regulator calls and commands can be used for fixed-regulator devices, and the proper error will be returned for prohibited.

Changes v3:
- new file
- Kconfig add fixed-regulator entry

Changes V4:
- move DM_REGULATOR_FIXED Kconfig entry from: drivers/power/Kconfig to drivers/power/regulator/Kconfig
- regulator/fixed.c: adjust to use of uclass platdata and device platdata
- regulator/fixed.c: includes cleanup
- regulator/fixed.c: fix gpio request
- add binding info

Quoted 8 lines
---
 doc/device-tree-bindings/regulator/fixed.txt |  38 ++++++++
 drivers/power/regulator/Kconfig              |   8 ++
 drivers/power/regulator/Makefile             |   1 +
 drivers/power/regulator/fixed.c              | 126 +++++++++++++++++++++++++++
 4 files changed, 173 insertions(+)
 create mode 100644 doc/device-tree-bindings/regulator/fixed.txt
 create mode 100644 drivers/power/regulator/fixed.c
Quoted 1 line

Applied to u-boot-dm/next, thanks!

#193 lore raw

PATCH v4 11/16 dm: regulator: add fixed voltage regulator driver

In reply to Przemyslaw Marczak

Hello Simon,

Quoted 17 lines · Przemyslaw Marczak

This driver implements regulator operations for fixed Voltage/Current value regulators. beside the standard regulator constraints, which are put into the uclass platform data, a typical fixed regulator node provides few additional properties like:
- gpio
- gpio-open-drain
- enable-active-high
- startup-delay-us
The only 'gpio' is used by this driver and is kept in structure of type 'fixed_regulator_platdata', as a device platform data (dev->platdata).

The driver implements:
- get_value
- get_current
- get_enable
- set_enable

Quoted 5 lines

The regulator calls and commands can be used for fixed-regulator devices, and the proper error will be returned for prohibited.

I missed the separation (---) here and I see that you add ACK below the changes.
Could you remove them from the tree?

Quoted 11 lines

Changes v3:
- new file
- Kconfig add fixed-regulator entry

Changes V4:
- move DM_REGULATOR_FIXED Kconfig entry from: drivers/power/Kconfig to drivers/power/regulator/Kconfig
- regulator/fixed.c: adjust to use of uclass platdata and device platdata
- regulator/fixed.c: includes cleanup
- regulator/fixed.c: fix gpio request
- add binding info

Quoted 8 lines
---
  doc/device-tree-bindings/regulator/fixed.txt |  38 ++++++++
  drivers/power/regulator/Kconfig              |   8 ++
  drivers/power/regulator/Makefile             |   1 +
  drivers/power/regulator/fixed.c              | 126 +++++++++++++++++++++++++++
  4 files changed, 173 insertions(+)

create mode 100644 doc/device-tree-bindings/regulator/fixed.txt create mode 100644 drivers/power/regulator/fixed.c

Best regards,

Signature · 4 lines
Przemyslaw Marczak
Samsung R&D Institute Poland
Samsung Electronics
p.marczak at samsung.com
#194 lore raw

PATCH v4 11/16 dm: regulator: add fixed voltage regulator driver

+CC Simon

Quoted 24 lines · Przemyslaw Marczak

Hello Simon,

Quoted 21 lines · Przemyslaw Marczak

This driver implements regulator operations for fixed Voltage/Current value regulators. beside the standard regulator constraints, which are put into the uclass platform data, a typical fixed regulator node provides
few additional properties like:
- gpio
- gpio-open-drain
- enable-active-high
- startup-delay-us
The only 'gpio' is used by this driver and is kept in structure of type 'fixed_regulator_platdata', as a device platform data (dev->platdata).

The driver implements:
- get_value
- get_current
- get_enable
- set_enable

The regulator calls and commands can be used for fixed-regulator devices, and the proper error will be returned for prohibited.

Quoted 7 lines
Quoted 2 lines

I missed the separation (---) here and I see that you add ACK below the changes.
Could you remove them from the tree?

[...]

Best regards,

Signature · 4 lines
Przemyslaw Marczak
Samsung R&D Institute Poland
Samsung Electronics
p.marczak at samsung.com
#195 lore raw

PATCH v4 11/16 dm: regulator: add fixed voltage regulator driver

In reply to Przemyslaw Marczak

Hi Przemyslaw,

Quoted 24 lines · Przemyslaw Marczak

Hello Simon,

Quoted 21 lines · Przemyslaw Marczak

This driver implements regulator operations for fixed Voltage/Current value regulators. beside the standard regulator constraints, which are put into the uclass platform data, a typical fixed regulator node provides few additional properties like:
- gpio
- gpio-open-drain
- enable-active-high
- startup-delay-us
The only 'gpio' is used by this driver and is kept in structure of type 'fixed_regulator_platdata', as a device platform data (dev->platdata).

The driver implements:
- get_value
- get_current
- get_enable
- set_enable

The regulator calls and commands can be used for fixed-regulator devices, and the proper error will be returned for prohibited.

Quoted 6 lines
Quoted 2 lines

I missed the separation (---) here and I see that you add ACK below the changes.
Could you remove them from the tree?

OK, done. You could try patman which handles this automatically.

Regards,
Simon

#196 lore raw

PATCH v4 12/16 doc: driver-model: pmic and regulator uclass documentation

In reply to Przemyslaw Marczak

Since this framework is still under the construction, the main documentation is kept in the header files.

---
Changes v2, V3:
- update documentation with the framework api changes
- remove doc file name 'dm' prefix

Changes V4:
- move the description to the headers and leave only general info

---
 doc/driver-model/pmic-framework.txt | 142 ++++++++++++++++++++++++++++++++++++
 1 file changed, 142 insertions(+)
 create mode 100644 doc/driver-model/pmic-framework.txt
doc/driver-model/pmic-framework.txt new file +142 -0
new file mode 100644
index 0000000..cc82236
@@ -0,0 +1,142 @@
+#
+# (C) Copyright 2014-2015 Samsung Electronics
+# Przemyslaw Marczak <[email protected]>
+#
+# SPDX-License-Identifier:      GPL-2.0+
+#
+
+PMIC framework based on Driver Model
+====================================
+TOC:
+1. Introduction
+2. How does it work
+3. Pmic uclass
+4. Regulator uclass
+
+1. Introduction
+===============
+This is an introduction to driver-model multi uclass PMIC IC's support.
+At present it's based on two uclass types:
+- UCLASS_PMIC      - basic uclass type for PMIC I/O, which provides common
+                     read/write interface.
+- UCLASS_REGULATOR - additional uclass type for specific PMIC features,
+                     which are Voltage/Current regulators.
+
+New files:
+UCLASS_PMIC:
+- drivers/power/pmic/pmic-uclass.c
+- include/power/pmic.h
+UCLASS_REGULATOR:
+- drivers/power/regulator/regulator-uclass.c
+- include/power/regulator.h
+
+Commands:
+- common/cmd_pmic.c
+- common/cmd_regulator.c
+
+2. How doees it work
+====================
+The Power Management Integrated Circuits (PMIC) are used in embedded systems
+to provide stable, precise and specific voltage power source with over-voltage
+and thermal protection circuits.
+
+The single PMIC can provide various functions by single or multiple interfaces,
+like in the example below.
+
+-- SoC
+ |
+ |            ______________________________________
+ | BUS 0     |       Multi interface PMIC IC        |--> LDO out 1
+ | e.g.I2C0  |                                      |--> LDO out N
+ |-----------|---- PMIC device 0 (READ/WRITE ops)   |
+ | or SPI0   |    |_ REGULATOR device (ldo/... ops) |--> BUCK out 1
+ |           |    |_ CHARGER device (charger ops)   |--> BUCK out M
+ |           |    |_ MUIC device (microUSB con ops) |
+ | BUS 1     |    |_ ...                            |---> BATTERY
+ | e.g.I2C1  |                                      |
+ |-----------|---- PMIC device 1 (READ/WRITE ops)   |---> USB in 1
+ . or SPI1   |    |_ RTC device (rtc ops)           |---> USB in 2
+ .           |______________________________________|---> USB out
+ .
+
+Since U-Boot provides driver model features for I2C and SPI bus drivers,
+the PMIC devices should also support this. By the pmic and regulator API's,
+PMIC drivers can simply provide a common functions, for multi-interface and
+and multi-instance device support.
+
+Basic design assumptions:
+
+- Common I/O API - UCLASS_PMIC
+For the multi-function PMIC devices, this can be used as parent I/O device
+for each IC's interface. Then, each children uses the same dev for read/write.
+
+- Common regulator API - UCLASS_REGULATOR
+For driving the regulator attributes, auto setting function or command line
+interface, based on kernel-style regulator device tree constraints.
+
+For simple implementations, regulator drivers are not required, so the code can
+use pmic read/write directly.
+
+3. Pmic uclass
+==============
+The basic informations:
+* Uclass:   'UCLASS_PMIC'
+* Header:   'include/power/pmic.h'
+* Core:     'drivers/power/pmic/pmic-uclass.c'
+  config:   'CONFIG_DM_PMIC'
+* Command:  'common/cmd_pmic.c'
+  config:   'CONFIG_CMD_PMIC'
+* Example:  'drivers/power/pmic/max77686.c'
+
+This is still under the construction. So for the API description, please refer
+to the header file.
+
+As an example of the pmic driver, please refer to the MAX77686 driver.
+
+Please pay attention for the driver's '.bind' method. Exactly the function call:
+'pmic_bind_childs()', which is used to bind the regulators by using the array of
+regulator's node, compatible prefixes.
+
+The 'pmic; command also supports the new API. So the pmic command can be enabled
+by adding CONFIG_CMD_PMIC.
+The new pmic command allows to:
+- list pmic devices
+- choose the current device (like the mmc command)
+- read or write the pmic register
+- dump all pmic registers
+
+This command can use only UCLASS_PMIC devices, since this uclass is designed
+for pmic I/O operations only.
+
+For more informations, please refer to the file: 'common/cmd_pmic.c'.
+
+4. Regulator uclass
+===================
+The basic informations:
+* Uclass:  'UCLASS_REGULATOR'
+* Header:  'include/power/regulator.h'
+* Core:    'drivers/power/regulator/regulator-uclass.c'
+  config:  'CONFIG_DM_REGULATOR'
+  binding: 'doc/device-tree-bindings/regulator/regulator.txt'
+* Command: 'common/cmd_regulator.c'
+  config:  'CONFIG_CMD_REGULATOR'
+* Example: 'drivers/power/regulator/max77686.c'
+           'drivers/power/pmic/max77686.c' (required I/O driver for the above)
+* Example: 'drivers/power/regulator/fixed.c'
+  config"  'CONFIG_DM_REGULATOR_FIXED'
+
+This is still under the construction. So for the API description, please refer
+to the header file.
+
+For the example regulator driver, please refer to the MAX77686 regulator driver,
+but this driver can't operate without pmic's example driver, which provides an
+I/O interface for MAX77686 regulator.
+
+The second example is a fixed Voltage/Current regulator for a common use.
+
+The 'regulator' command also supports the new API. The command allow:
+- list regulator devices
+- choose the current device (like the mmc command)
+- do all regulator-specific operations
+
+For more informations, please refer to the file: 'common/cmd_regulator.c'
Signature · 1 line
1.9.1
#197 lore raw

PATCH v4 12/16 doc: driver-model: pmic and regulator uclass documentation

Hi Przemyslaw,

Quoted 9 lines · Przemyslaw Marczak

Since this framework is still under the construction, the main documentation is kept in the header files.

---
Changes v2, V3:
- update documentation with the framework api changes
- remove doc file name 'dm' prefix

Quoted 7 lines

Changes V4:
- move the description to the headers and leave only general info

---
 doc/driver-model/pmic-framework.txt | 142 ++++++++++++++++++++++++++++++++++++
 1 file changed, 142 insertions(+)
 create mode 100644 doc/driver-model/pmic-framework.txt
Quoted 93 lines
doc/driver-model/pmic-framework.txt new file +86 -0
new file mode 100644
index 0000000..cc82236
@@ -0,0 +1,142 @@
+#
+# (C) Copyright 2014-2015 Samsung Electronics
+# Przemyslaw Marczak <[email protected]>
+#
+# SPDX-License-Identifier:      GPL-2.0+
+#
+
+PMIC framework based on Driver Model
+====================================
+TOC:
+1. Introduction
+2. How does it work
+3. Pmic uclass
+4. Regulator uclass
+
+1. Introduction
+===============
+This is an introduction to driver-model multi uclass PMIC IC's support.
+At present it's based on two uclass types:
+- UCLASS_PMIC      - basic uclass type for PMIC I/O, which provides common
+                     read/write interface.
+- UCLASS_REGULATOR - additional uclass type for specific PMIC features,
+                     which are Voltage/Current regulators.
+
+New files:
+UCLASS_PMIC:
+- drivers/power/pmic/pmic-uclass.c
+- include/power/pmic.h
+UCLASS_REGULATOR:
+- drivers/power/regulator/regulator-uclass.c
+- include/power/regulator.h
+
+Commands:
+- common/cmd_pmic.c
+- common/cmd_regulator.c
+
+2. How doees it work
+====================
+The Power Management Integrated Circuits (PMIC) are used in embedded systems
+to provide stable, precise and specific voltage power source with over-voltage
+and thermal protection circuits.
+
+The single PMIC can provide various functions by single or multiple interfaces,
+like in the example below.
+
+-- SoC
+ |
+ |            ______________________________________
+ | BUS 0     |       Multi interface PMIC IC        |--> LDO out 1
+ | e.g.I2C0  |                                      |--> LDO out N
+ |-----------|---- PMIC device 0 (READ/WRITE ops)   |
+ | or SPI0   |    |_ REGULATOR device (ldo/... ops) |--> BUCK out 1
+ |           |    |_ CHARGER device (charger ops)   |--> BUCK out M
+ |           |    |_ MUIC device (microUSB con ops) |
+ | BUS 1     |    |_ ...                            |---> BATTERY
+ | e.g.I2C1  |                                      |
+ |-----------|---- PMIC device 1 (READ/WRITE ops)   |---> USB in 1
+ . or SPI1   |    |_ RTC device (rtc ops)           |---> USB in 2
+ .           |______________________________________|---> USB out
+ .
+
+Since U-Boot provides driver model features for I2C and SPI bus drivers,
+the PMIC devices should also support this. By the pmic and regulator API's,
+PMIC drivers can simply provide a common functions, for multi-interface and
+and multi-instance device support.
+
+Basic design assumptions:
+
+- Common I/O API - UCLASS_PMIC
+For the multi-function PMIC devices, this can be used as parent I/O device
+for each IC's interface. Then, each children uses the same dev for read/write.
+
+- Common regulator API - UCLASS_REGULATOR
+For driving the regulator attributes, auto setting function or command line
+interface, based on kernel-style regulator device tree constraints.
+
+For simple implementations, regulator drivers are not required, so the code can
+use pmic read/write directly.
+
+3. Pmic uclass
+==============
+The basic informations:
+* Uclass:   'UCLASS_PMIC'
+* Header:   'include/power/pmic.h'
+* Core:     'drivers/power/pmic/pmic-uclass.c'
+  config:   'CONFIG_DM_PMIC'

doc/driver-model/pmic-framework.txt line 96

Quoted 10 lines
doc/driver-model/pmic-framework.txt new file +10 -0
+* Command:  'common/cmd_pmic.c'
+  config:   'CONFIG_CMD_PMIC'
+* Example:  'drivers/power/pmic/max77686.c'
+
+This is still under the construction. So for the API description, please refer
+to the header file.
+
+As an example of the pmic driver, please refer to the MAX77686 driver.
+
+Please pay attention for the driver's '.bind' method. Exactly the function call:

I think 'driver's bind() method' is better than a quoted '.bind'.

Quoted 5 lines
doc/driver-model/pmic-framework.txt new file +5 -0
+'pmic_bind_childs()', which is used to bind the regulators by using the array of
+regulator's node, compatible prefixes.
+
+The 'pmic; command also supports the new API. So the pmic command can be enabled
+by adding CONFIG_CMD_PMIC.

doc/driver-model/pmic-framework.txt line 111

Quoted 10 lines
doc/driver-model/pmic-framework.txt new file +10 -0
+The new pmic command allows to:
+- list pmic devices
+- choose the current device (like the mmc command)
+- read or write the pmic register
+- dump all pmic registers
+
+This command can use only UCLASS_PMIC devices, since this uclass is designed
+for pmic I/O operations only.
+
+For more informations, please refer to the file: 'common/cmd_pmic.c'.

information

doc/driver-model/pmic-framework.txt line 115

Quoted 4 lines
doc/driver-model/pmic-framework.txt new file +4 -0
+
+4. Regulator uclass
+===================
+The basic informations:

information

Quoted 4 lines
doc/driver-model/pmic-framework.txt new file +4 -0
+* Uclass:  'UCLASS_REGULATOR'
+* Header:  'include/power/regulator.h'
+* Core:    'drivers/power/regulator/regulator-uclass.c'
+  config:  'CONFIG_DM_REGULATOR'

doc/driver-model/pmic-framework.txt line 129

Quoted 10 lines
doc/driver-model/pmic-framework.txt new file +10 -0
+  binding: 'doc/device-tree-bindings/regulator/regulator.txt'
+* Command: 'common/cmd_regulator.c'
+  config:  'CONFIG_CMD_REGULATOR'
+* Example: 'drivers/power/regulator/max77686.c'
+           'drivers/power/pmic/max77686.c' (required I/O driver for the above)
+* Example: 'drivers/power/regulator/fixed.c'
+  config"  'CONFIG_DM_REGULATOR_FIXED'
+
+This is still under the construction. So for the API description, please refer
+to the header file.

What is still under construction?

doc/driver-model/pmic-framework.txt line 137

Quoted 8 lines
doc/driver-model/pmic-framework.txt new file +8 -0
+
+For the example regulator driver, please refer to the MAX77686 regulator driver,
+but this driver can't operate without pmic's example driver, which provides an
+I/O interface for MAX77686 regulator.
+
+The second example is a fixed Voltage/Current regulator for a common use.
+
+The 'regulator' command also supports the new API. The command allow:

allows, or maybe s/allow/allows you to/

Quoted 8 lines
doc/driver-model/pmic-framework.txt new file +5 -1
+- list regulator devices
+- choose the current device (like the mmc command)
+- do all regulator-specific operations
+
+For more informations, please refer to the file: 'common/cmd_regulator.c'
--

1.9.1

Regards,
Simon

#198 lore raw

PATCH v4 12/16 doc: driver-model: pmic and regulator uclass documentation

Quoted 15 lines · Simon Glass

Hi Przemyslaw,

Quoted 12 lines · Przemyslaw Marczak

Since this framework is still under the construction, the main documentation is kept in the header files.

---
Changes v2, V3:
- update documentation with the framework api changes
- remove doc file name 'dm' prefix

Changes V4:
- move the description to the headers and leave only general info

Quoted 6 lines
Quoted 4 lines
---
 doc/driver-model/pmic-framework.txt | 142 ++++++++++++++++++++++++++++++++++++
 1 file changed, 142 insertions(+)
 create mode 100644 doc/driver-model/pmic-framework.txt

Applied to u-boot-dm/next, thanks!

#199 lore raw

PATCH v4 12/16 doc: driver-model: pmic and regulator uclass documentation

In reply to Simon Glass

Hello,

Quoted 153 lines · Simon Glass

Hi Przemyslaw,

Quoted 9 lines · Przemyslaw Marczak

Since this framework is still under the construction, the main documentation is kept in the header files.

---
Changes v2, V3:
- update documentation with the framework api changes
- remove doc file name 'dm' prefix

Quoted 7 lines

Changes V4:
- move the description to the headers and leave only general info

---
  doc/driver-model/pmic-framework.txt | 142 ++++++++++++++++++++++++++++++++++++
  1 file changed, 142 insertions(+)

create mode 100644 doc/driver-model/pmic-framework.txt

Quoted 93 lines
doc/driver-model/pmic-framework.txt new file +86 -0
new file mode 100644
index 0000000..cc82236
@@ -0,0 +1,142 @@
+#
+# (C) Copyright 2014-2015 Samsung Electronics
+# Przemyslaw Marczak <[email protected]>
+#
+# SPDX-License-Identifier:      GPL-2.0+
+#
+
+PMIC framework based on Driver Model
+====================================
+TOC:
+1. Introduction
+2. How does it work
+3. Pmic uclass
+4. Regulator uclass
+
+1. Introduction
+===============
+This is an introduction to driver-model multi uclass PMIC IC's support.
+At present it's based on two uclass types:
+- UCLASS_PMIC      - basic uclass type for PMIC I/O, which provides common
+                     read/write interface.
+- UCLASS_REGULATOR - additional uclass type for specific PMIC features,
+                     which are Voltage/Current regulators.
+
+New files:
+UCLASS_PMIC:
+- drivers/power/pmic/pmic-uclass.c
+- include/power/pmic.h
+UCLASS_REGULATOR:
+- drivers/power/regulator/regulator-uclass.c
+- include/power/regulator.h
+
+Commands:
+- common/cmd_pmic.c
+- common/cmd_regulator.c
+
+2. How doees it work
+====================
+The Power Management Integrated Circuits (PMIC) are used in embedded systems
+to provide stable, precise and specific voltage power source with over-voltage
+and thermal protection circuits.
+
+The single PMIC can provide various functions by single or multiple interfaces,
+like in the example below.
+
+-- SoC
+ |
+ |            ______________________________________
+ | BUS 0     |       Multi interface PMIC IC        |--> LDO out 1
+ | e.g.I2C0  |                                      |--> LDO out N
+ |-----------|---- PMIC device 0 (READ/WRITE ops)   |
+ | or SPI0   |    |_ REGULATOR device (ldo/... ops) |--> BUCK out 1
+ |           |    |_ CHARGER device (charger ops)   |--> BUCK out M
+ |           |    |_ MUIC device (microUSB con ops) |
+ | BUS 1     |    |_ ...                            |---> BATTERY
+ | e.g.I2C1  |                                      |
+ |-----------|---- PMIC device 1 (READ/WRITE ops)   |---> USB in 1
+ . or SPI1   |    |_ RTC device (rtc ops)           |---> USB in 2
+ .           |______________________________________|---> USB out
+ .
+
+Since U-Boot provides driver model features for I2C and SPI bus drivers,
+the PMIC devices should also support this. By the pmic and regulator API's,
+PMIC drivers can simply provide a common functions, for multi-interface and
+and multi-instance device support.
+
+Basic design assumptions:
+
+- Common I/O API - UCLASS_PMIC
+For the multi-function PMIC devices, this can be used as parent I/O device
+for each IC's interface. Then, each children uses the same dev for read/write.
+
+- Common regulator API - UCLASS_REGULATOR
+For driving the regulator attributes, auto setting function or command line
+interface, based on kernel-style regulator device tree constraints.
+
+For simple implementations, regulator drivers are not required, so the code can
+use pmic read/write directly.
+
+3. Pmic uclass
+==============
+The basic informations:
+* Uclass:   'UCLASS_PMIC'
+* Header:   'include/power/pmic.h'
+* Core:     'drivers/power/pmic/pmic-uclass.c'
+  config:   'CONFIG_DM_PMIC'

doc/driver-model/pmic-framework.txt line 96

Quoted 10 lines
doc/driver-model/pmic-framework.txt new file +10 -0
+* Command:  'common/cmd_pmic.c'
+  config:   'CONFIG_CMD_PMIC'
+* Example:  'drivers/power/pmic/max77686.c'
+
+This is still under the construction. So for the API description, please refer
+to the header file.
+
+As an example of the pmic driver, please refer to the MAX77686 driver.
+
+Please pay attention for the driver's '.bind' method. Exactly the function call:

I think 'driver's bind() method' is better than a quoted '.bind'.

Quoted 5 lines
doc/driver-model/pmic-framework.txt new file +5 -0
+'pmic_bind_childs()', which is used to bind the regulators by using the array of
+regulator's node, compatible prefixes.
+
+The 'pmic; command also supports the new API. So the pmic command can be enabled
+by adding CONFIG_CMD_PMIC.

doc/driver-model/pmic-framework.txt line 111

Quoted 10 lines
doc/driver-model/pmic-framework.txt new file +10 -0
+The new pmic command allows to:
+- list pmic devices
+- choose the current device (like the mmc command)
+- read or write the pmic register
+- dump all pmic registers
+
+This command can use only UCLASS_PMIC devices, since this uclass is designed
+for pmic I/O operations only.
+
+For more informations, please refer to the file: 'common/cmd_pmic.c'.

information

doc/driver-model/pmic-framework.txt line 115

Quoted 4 lines
doc/driver-model/pmic-framework.txt new file +4 -0
+
+4. Regulator uclass
+===================
+The basic informations:

information

Quoted 17 lines
Quoted 4 lines
doc/driver-model/pmic-framework.txt new file +4 -0
+* Uclass:  'UCLASS_REGULATOR'
+* Header:  'include/power/regulator.h'
+* Core:    'drivers/power/regulator/regulator-uclass.c'
+  config:  'CONFIG_DM_REGULATOR'

doc/driver-model/pmic-framework.txt line 129

Quoted 10 lines
doc/driver-model/pmic-framework.txt new file +10 -0
+  binding: 'doc/device-tree-bindings/regulator/regulator.txt'
+* Command: 'common/cmd_regulator.c'
+  config:  'CONFIG_CMD_REGULATOR'
+* Example: 'drivers/power/regulator/max77686.c'
+           'drivers/power/pmic/max77686.c' (required I/O driver for the above)
+* Example: 'drivers/power/regulator/fixed.c'
+  config"  'CONFIG_DM_REGULATOR_FIXED'
+
+This is still under the construction. So for the API description, please refer
+to the header file.

What is still under construction?

We need add muic, charger, etc., so the whole framework isn't finished yet.

Quoted 11 lines

doc/driver-model/pmic-framework.txt line 137

Quoted 8 lines
doc/driver-model/pmic-framework.txt new file +8 -0
+
+For the example regulator driver, please refer to the MAX77686 regulator driver,
+but this driver can't operate without pmic's example driver, which provides an
+I/O interface for MAX77686 regulator.
+
+The second example is a fixed Voltage/Current regulator for a common use.
+
+The 'regulator' command also supports the new API. The command allow:

allows, or maybe s/allow/allows you to/

Quoted 12 lines
Quoted 8 lines
doc/driver-model/pmic-framework.txt new file +5 -1
+- list regulator devices
+- choose the current device (like the mmc command)
+- do all regulator-specific operations
+
+For more informations, please refer to the file: 'common/cmd_regulator.c'
--

1.9.1

Regards,
Simon

Thank you, I will fix the mistakes.

Best regards,

Signature · 4 lines
Przemyslaw Marczak
Samsung R&D Institute Poland
Samsung Electronics
p.marczak at samsung.com
#200 lore raw

PATCH v4 13/16 dm: board:samsung: power_init_board: add requirement of CONFIG_DM_PMIC

In reply to Przemyslaw Marczak

In the power_init_board function call, regulator driver init is called, so before compile, make sure that any power framework is defined.

---
 board/samsung/common/board.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
board/samsung/common/board.c +2 -2
index 9be2950..20dd75c 100644
@@ -21,9 +21,9 @@
 #include <asm/arch/pinmux.h>
 #include <asm/arch/power.h>
 #include <asm/arch/system.h>
-#include <power/pmic.h>
 #include <asm/arch/sromc.h>
 #include <lcd.h>
+#include <i2c.h>
 #include <samsung/misc.h>
 #include <usb.h>
 
@@ -169,7 +169,7 @@ int board_early_init_f(void)
 }
 #endif
 
-#if defined(CONFIG_POWER)
+#if defined(CONFIG_POWER) || defined(CONFIG_DM_PMIC)
 int power_init_board(void)
 {
 	set_ps_hold_ctrl();
Signature · 1 line
1.9.1
#201 lore raw

PATCH v4 13/16 dm: board:samsung: power_init_board: add requirement of CONFIG_DM_PMIC

Quoted 7 lines · Przemyslaw Marczak

In the power_init_board function call, regulator driver init is called, so before compile, make sure that any power framework is defined.

---
 board/samsung/common/board.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

Would be good to sort the includes correctly (unrelated to your patch).

#202 lore raw

PATCH v4 13/16 dm: board:samsung: power_init_board: add requirement of CONFIG_DM_PMIC

Quoted 4 lines · Simon Glass
Quoted 3 lines · Przemyslaw Marczak

In the power_init_board function call, regulator driver init is called, so before compile, make sure that any power framework is defined.

Quoted 8 lines
Quoted 4 lines
---
 board/samsung/common/board.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

Would be good to sort the includes correctly (unrelated to your patch).

Applied to u-boot-dm/next, thanks!

#203 lore raw

PATCH v4 13/16 dm: board:samsung: power_init_board: add requirement of CONFIG_DM_PMIC

In reply to Simon Glass

Hello,

Quoted 4 lines · Simon Glass
Quoted 3 lines · Przemyslaw Marczak

In the power_init_board function call, regulator driver init is called, so before compile, make sure that any power framework is defined.

Quoted 9 lines
Quoted 4 lines
---
  board/samsung/common/board.c | 4 ++--
  1 file changed, 2 insertions(+), 2 deletions(-)

Would be good to sort the includes correctly (unrelated to your patch).

Ok, will do that.

Best regards,

Signature · 4 lines
Przemyslaw Marczak
Samsung R&D Institute Poland
Samsung Electronics
p.marczak at samsung.com
#204 lore raw

PATCH v4 14/16 odroid: board: add support to dm pmic api

In reply to Przemyslaw Marczak

This commit change the old pmic framework calls to the new ones.

---
Changes v2:
- remove board_init_i2c() call
- update regulator calls
- update headers
- samsung/misc.c: include required header

Changes v3:
- adjust regulator calls to new api

Changes V4:
- use regulator_list_autoset() for mmc regulators

---
 board/samsung/common/misc.c   |  1 +
 board/samsung/odroid/odroid.c | 77 +++++++++++++++++++++++++------------------
 2 files changed, 46 insertions(+), 32 deletions(-)
board/samsung/common/misc.c +1 -0
index 1a77c82..f0d69d4 100644
@@ -16,6 +16,7 @@
 #include <asm/arch/cpu.h>
 #include <asm/gpio.h>
 #include <linux/input.h>
+#include <dm.h>
 #include <power/pmic.h>
 #include <mmc.h>
 
board/samsung/odroid/odroid.c +45 -32

127 lines not on this page · raw message

Signature · 1 line
1.9.1
#205 lore raw

PATCH v4 14/16 odroid: board: add support to dm pmic api

Hi Przemyslaw,

Quoted 13 lines · Przemyslaw Marczak

This commit change the old pmic framework calls to the new ones.

---
Changes v2:
- remove board_init_i2c() call
- update regulator calls
- update headers
- samsung/misc.c: include required header

Changes v3:
- adjust regulator calls to new api

Quoted 7 lines

Changes V4:
- use regulator_list_autoset() for mmc regulators

---
 board/samsung/common/misc.c   |  1 +
 board/samsung/odroid/odroid.c | 77 +++++++++++++++++++++++++------------------
 2 files changed, 46 insertions(+), 32 deletions(-)
Quoted 28 lines
board/samsung/common/misc.c +1 -0
index 1a77c82..f0d69d4 100644
@@ -16,6 +16,7 @@
 #include <asm/arch/cpu.h>
 #include <asm/gpio.h>
 #include <linux/input.h>
+#include <dm.h>
 #include <power/pmic.h>
 #include <mmc.h>
 
board/samsung/odroid/odroid.c +2 -0
index ae41c29..29de325 100644
@@ -12,7 +12,9 @@
 #include <asm/arch/gpio.h>
 #include <asm/gpio.h>
 #include <asm/arch/cpu.h>
+#include <dm.h>
 #include <power/pmic.h>
+#include <power/regulator.h>
 #include <power/max77686_pmic.h>
 #include <errno.h>
 #include <mmc.h>

board/samsung/odroid/odroid.c enum { · line 39

Quoted 7 lines
board/samsung/odroid/odroid.c +4 -0
@@ -31,6 +33,12 @@ enum {
        ODROID_TYPES,
 };
 
+static const char *mmc_regulators[] = {
+       "VDDQ_EMMC_1.8V",
+       "VDDQ_EMMC_2.8V",
+       "TFLASH_2.8V",

I wonder if it would be better to terminate with NULL instead of requiring an ARRAY_SIZE?

Quoted 117 lines
board/samsung/odroid/odroid.c +39 -33
+};
+
 void set_board_type(void)
 {
        /* Set GPA1 pin 1 to HI - enable XCL205 output */
@@ -403,21 +411,6 @@ static void board_gpio_init(void)
 #endif
 }
 
-static int pmic_init_max77686(void)
-{
-       struct pmic *p = pmic_get("MAX77686_PMIC");
-
-       if (pmic_probe(p))
-               return -ENODEV;
-
-       /* Set LDO Voltage */
-       max77686_set_ldo_voltage(p, 20, 1800000);       /* LDO20 eMMC */
-       max77686_set_ldo_voltage(p, 21, 2800000);       /* LDO21 SD */
-       max77686_set_ldo_voltage(p, 22, 2800000);       /* LDO22 eMMC */
-
-       return 0;
-}
-
 int exynos_early_init_f(void)
 {
        board_clock_init();
@@ -434,8 +427,10 @@ int exynos_init(void)
 
 int exynos_power_init(void)
 {
-       pmic_init(0);
-       pmic_init_max77686();
+       int list_count = ARRAY_SIZE(mmc_regulators);
+
+       if (regulator_list_autoset(mmc_regulators, list_count, NULL, true))
+               error("Unable to init all mmc regulators");
 
        return 0;
 }
@@ -443,19 +438,20 @@ int exynos_power_init(void)
 #ifdef CONFIG_USB_GADGET
 static int s5pc210_phy_control(int on)
 {
-       struct pmic *p_pmic;
+       struct udevice *dev;
+       int ret;
 
-       p_pmic = pmic_get("MAX77686_PMIC");
-       if (!p_pmic)
-               return -ENODEV;
-
-       if (pmic_probe(p_pmic))
-               return -1;
+       ret = regulator_by_platname("VDD_UOTG_3.0V", &dev);
+       if (ret) {
+               error("Regulator get error: %d", ret);
+               return ret;
+       }
 
        if (on)
-               return max77686_set_ldo_mode(p_pmic, 12, OPMODE_ON);
+               return regulator_set_mode(dev, OPMODE_ON);
        else
-               return max77686_set_ldo_mode(p_pmic, 12, OPMODE_LPM);
+               return regulator_set_mode(dev, OPMODE_LPM);
+
 }
 
 struct s3c_plat_otg_data s5pc210_otg_data = {
@@ -472,7 +468,8 @@ struct s3c_plat_otg_data s5pc210_otg_data = {
 int board_usb_init(int index, enum usb_init_type init)
 {
 #ifdef CONFIG_CMD_USB
-       struct pmic *p_pmic;
+       struct udevice *dev;
+       int ret;
 
        /* Set Ref freq 0 => 24MHz, 1 => 26MHz*/
        /* Odroid Us have it at 24MHz, Odroid Xs at 26MHz */
@@ -490,14 +487,30 @@ int board_usb_init(int index, enum usb_init_type init)
        /* Power off and on BUCK8 for LAN9730 */
        debug("LAN9730 - Turning power buck 8 OFF and ON.\n");
 
-       p_pmic = pmic_get("MAX77686_PMIC");
-       if (p_pmic && !pmic_probe(p_pmic)) {
-               max77686_set_buck_voltage(p_pmic, 8, 750000);
-               max77686_set_buck_voltage(p_pmic, 8, 3300000);
+       ret = regulator_by_platname("VCC_P3V3_2.85V", &dev);
+       if (ret) {
+               error("Regulator get error: %d", ret);
+               return ret;
        }
 
-#endif
+       ret = regulator_set_enable(dev, true);
+       if (ret) {
+               error("Regulator %s enable setting error: %d", dev->name, ret);
+               return ret;
+       }
 
+       ret = regulator_set_value(dev, 750000);
+       if (ret) {
+               error("Regulator %s value setting error: %d", dev->name, ret);
+               return ret;
+       }
+
+       ret = regulator_set_value(dev, 3300000);
+       if (ret) {
+               error("Regulator %s value setting error: %d", dev->name, ret);
+               return ret;
+       }
+#endif
        debug("USB_udc_probe\n");
        return s3c_udc_probe(&s5pc210_otg_data);
 }
--
Quoted 2 lines

1.9.1

Regards,
Simon

#206 lore raw

PATCH v4 14/16 odroid: board: add support to dm pmic api

Quoted 19 lines · Simon Glass

Hi Przemyslaw,

Quoted 16 lines · Przemyslaw Marczak

This commit change the old pmic framework calls to the new ones.

---
Changes v2:
- remove board_init_i2c() call
- update regulator calls
- update headers
- samsung/misc.c: include required header

Changes v3:
- adjust regulator calls to new api

Changes V4:
- use regulator_list_autoset() for mmc regulators

Quoted 6 lines
Quoted 4 lines
---
 board/samsung/common/misc.c   |  1 +
 board/samsung/odroid/odroid.c | 77 +++++++++++++++++++++++++------------------
 2 files changed, 46 insertions(+), 32 deletions(-)

Applied to u-boot-dm/next, thanks!

#207 lore raw

PATCH v4 14/16 odroid: board: add support to dm pmic api

In reply to Simon Glass

Hello Simon,

Quoted 57 lines · Simon Glass

Hi Przemyslaw,

Quoted 13 lines · Przemyslaw Marczak

This commit change the old pmic framework calls to the new ones.

---
Changes v2:
- remove board_init_i2c() call
- update regulator calls
- update headers
- samsung/misc.c: include required header

Changes v3:
- adjust regulator calls to new api

Quoted 7 lines

Changes V4:
- use regulator_list_autoset() for mmc regulators

---
  board/samsung/common/misc.c   |  1 +
  board/samsung/odroid/odroid.c | 77 +++++++++++++++++++++++++------------------
  2 files changed, 46 insertions(+), 32 deletions(-)
Quoted 31 lines
board/samsung/common/misc.c +1 -0
index 1a77c82..f0d69d4 100644
@@ -16,6 +16,7 @@
  #include <asm/arch/cpu.h>
  #include <asm/gpio.h>
  #include <linux/input.h>
+#include <dm.h>
  #include <power/pmic.h>
  #include <mmc.h>
 
board/samsung/odroid/odroid.c +2 -0
index ae41c29..29de325 100644
@@ -12,7 +12,9 @@
  #include <asm/arch/gpio.h>
  #include <asm/gpio.h>
  #include <asm/arch/cpu.h>
+#include <dm.h>
  #include <power/pmic.h>
+#include <power/regulator.h>
  #include <power/max77686_pmic.h>
  #include <errno.h>
  #include <mmc.h>
@@ -31,6 +33,12 @@ enum {
         ODROID_TYPES,
  };
 
Quoted 8 lines

board/samsung/odroid/odroid.c enum { · line 39

Quoted 4 lines
board/samsung/odroid/odroid.c +4 -0
+static const char *mmc_regulators[] = {
+       "VDDQ_EMMC_1.8V",
+       "VDDQ_EMMC_2.8V",
+       "TFLASH_2.8V",

I wonder if it would be better to terminate with NULL instead of requiring an ARRAY_SIZE?

Yes, I should do this, will fix.

Quoted 114 lines
Quoted 114 lines
board/samsung/odroid/odroid.c +39 -32
+};
+
  void set_board_type(void)
  {
         /* Set GPA1 pin 1 to HI - enable XCL205 output */
@@ -403,21 +411,6 @@ static void board_gpio_init(void)
  #endif
  }
 
-static int pmic_init_max77686(void)
-{
-       struct pmic *p = pmic_get("MAX77686_PMIC");
-
-       if (pmic_probe(p))
-               return -ENODEV;
-
-       /* Set LDO Voltage */
-       max77686_set_ldo_voltage(p, 20, 1800000);       /* LDO20 eMMC */
-       max77686_set_ldo_voltage(p, 21, 2800000);       /* LDO21 SD */
-       max77686_set_ldo_voltage(p, 22, 2800000);       /* LDO22 eMMC */
-
-       return 0;
-}
-
  int exynos_early_init_f(void)
  {
         board_clock_init();
@@ -434,8 +427,10 @@ int exynos_init(void)
 
  int exynos_power_init(void)
  {
-       pmic_init(0);
-       pmic_init_max77686();
+       int list_count = ARRAY_SIZE(mmc_regulators);
+
+       if (regulator_list_autoset(mmc_regulators, list_count, NULL, true))
+               error("Unable to init all mmc regulators");
 
         return 0;
  }
@@ -443,19 +438,20 @@ int exynos_power_init(void)
  #ifdef CONFIG_USB_GADGET
  static int s5pc210_phy_control(int on)
  {
-       struct pmic *p_pmic;
+       struct udevice *dev;
+       int ret;
 
-       p_pmic = pmic_get("MAX77686_PMIC");
-       if (!p_pmic)
-               return -ENODEV;
-
-       if (pmic_probe(p_pmic))
-               return -1;
+       ret = regulator_by_platname("VDD_UOTG_3.0V", &dev);
+       if (ret) {
+               error("Regulator get error: %d", ret);
+               return ret;
+       }
 
         if (on)
-               return max77686_set_ldo_mode(p_pmic, 12, OPMODE_ON);
+               return regulator_set_mode(dev, OPMODE_ON);
         else
-               return max77686_set_ldo_mode(p_pmic, 12, OPMODE_LPM);
+               return regulator_set_mode(dev, OPMODE_LPM);
+
  }
 
  struct s3c_plat_otg_data s5pc210_otg_data = {
@@ -472,7 +468,8 @@ struct s3c_plat_otg_data s5pc210_otg_data = {
  int board_usb_init(int index, enum usb_init_type init)
  {
  #ifdef CONFIG_CMD_USB
-       struct pmic *p_pmic;
+       struct udevice *dev;
+       int ret;
 
         /* Set Ref freq 0 => 24MHz, 1 => 26MHz*/
         /* Odroid Us have it at 24MHz, Odroid Xs at 26MHz */
@@ -490,14 +487,30 @@ int board_usb_init(int index, enum usb_init_type init)
         /* Power off and on BUCK8 for LAN9730 */
         debug("LAN9730 - Turning power buck 8 OFF and ON.\n");
 
-       p_pmic = pmic_get("MAX77686_PMIC");
-       if (p_pmic && !pmic_probe(p_pmic)) {
-               max77686_set_buck_voltage(p_pmic, 8, 750000);
-               max77686_set_buck_voltage(p_pmic, 8, 3300000);
+       ret = regulator_by_platname("VCC_P3V3_2.85V", &dev);
+       if (ret) {
+               error("Regulator get error: %d", ret);
+               return ret;
         }
 
-#endif
+       ret = regulator_set_enable(dev, true);
+       if (ret) {
+               error("Regulator %s enable setting error: %d", dev->name, ret);
+               return ret;
+       }
 
+       ret = regulator_set_value(dev, 750000);
+       if (ret) {
+               error("Regulator %s value setting error: %d", dev->name, ret);
+               return ret;
+       }
+
+       ret = regulator_set_value(dev, 3300000);
+       if (ret) {
+               error("Regulator %s value setting error: %d", dev->name, ret);
+               return ret;
+       }
+#endif
         debug("USB_udc_probe\n");
Quoted 9 lines
Quoted 5 lines
board/samsung/odroid/odroid.c +0 -1
         return s3c_udc_probe(&s5pc210_otg_data);
  }
--

1.9.1

Regards,
Simon

Best regards,

Signature · 4 lines
Przemyslaw Marczak
Samsung R&D Institute Poland
Samsung Electronics
p.marczak at samsung.com
#208 lore raw

PATCH v4 15/16 odroid: dts: add 'voltage-regulators' description to max77686 node

In reply to Przemyslaw Marczak

Adding regulators subnode to fdt max77686 node, allows properly init regulators by the max77686 regulator driver. This enables the complete functionality of the regulator command.

---
Changes V2:
- odroid: dts: remove pmic alias

Changes V3:
- none

Changes V4:
- add constraints for mmc regulators auto enable

---
 arch/arm/dts/exynos4412-odroid.dts | 253 +++++++++++++++++++++++++++++++++++++
 1 file changed, 253 insertions(+)
arch/arm/dts/exynos4412-odroid.dts +253 -0
index 5507d9a..415dfea 100644
@@ -40,6 +40,259 @@
 			interrupts = <7 0>;
 			reg = <0x09 0 0>;
 			#clock-cells = <1>;
+
+			voltage-regulators {
+				ldo1_reg: ldo1 {
+					regulator-compatible = "LDO1";
+					regulator-name = "VDD_ALIVE_1.0V";
+					regulator-min-microvolt = <1000000>;
+					regulator-max-microvolt = <1000000>;
+				};
+
+				ldo2_reg: ldo2 {
+					regulator-compatible = "LDO2";
+					regulator-name = "VDDQ_VM1M2_1.2V";
+					regulator-min-microvolt = <1200000>;
+					regulator-max-microvolt = <1200000>;
+				};
+
+				ldo3_reg: ldo3 {
+					regulator-compatible = "LDO3";
+					regulator-name = "VCC_1.8V_AP";
+					regulator-min-microvolt = <1800000>;
+					regulator-max-microvolt = <1800000>;
+				};
+
+				ldo4_reg: ldo4 {
+					regulator-compatible = "LDO4";
+					regulator-name = "VDDQ_MMC2_2.8V";
+					regulator-min-microvolt = <2800000>;
+					regulator-max-microvolt = <2800000>;
+				};
+
+				ldo5_reg: ldo5 {
+					regulator-compatible = "LDO5";
+					regulator-name = "VDDQ_MMC0/1/3_1.8V";
+					regulator-min-microvolt = <1800000>;
+					regulator-max-microvolt = <1800000>;
+				};
+
+				ldo6_reg: ldo6 {
+					regulator-compatible = "LDO6";
+					regulator-name = "VMPLL_1.0V";
+					regulator-min-microvolt = <1100000>;
+					regulator-max-microvolt = <1100000>;
+				};
+
+				ldo7_reg: ldo7 {
+					regulator-compatible = "LDO7";
+					regulator-name = "VPLL_1.1V";
+					regulator-min-microvolt = <1100000>;
+					regulator-max-microvolt = <1100000>;
+				};
+
+				ldo8_reg: ldo8 {
+					regulator-compatible = "LDO8";
+					regulator-name = "VDD_MIPI/HDMI_1.0V";
+					regulator-min-microvolt = <1000000>;
+					regulator-max-microvolt = <1000000>;
+				};
+
+				ldo9_reg: ldo9 {
+					regulator-compatible = "LDO9";
+					regulator-name = "nc";
+					regulator-min-microvolt = <1800000>;
+					regulator-max-microvolt = <1800000>;
+				};
+
+				ldo10_reg: ldo10 {
+					regulator-compatible = "LDO10";
+					regulator-name = "VDD_MIPI/HDMI_1.8V";
+					regulator-min-microvolt = <1800000>;
+					regulator-max-microvolt = <1800000>;
+				};
+
+				ldo11_reg: ldo11 {
+					regulator-compatible = "LDO11";
+					regulator-name = "VDD_ABB1_1.8V";
+					regulator-min-microvolt = <1800000>;
+					regulator-max-microvolt = <1800000>;
+				};
+
+				ldo12_reg: ldo12 {
+					regulator-compatible = "LDO12";
+					regulator-name = "VDD_UOTG_3.0V";
+					regulator-min-microvolt = <3000000>;
+					regulator-max-microvolt = <3000000>;
+				};
+
+				ldo13_reg: ldo13 {
+					regulator-compatible = "LDO13";
+					regulator-name = "VDD_C2C_1.8V";
+					regulator-min-microvolt = <1800000>;
+					regulator-max-microvolt = <1800000>;
+				};
+
+				ldo14_reg: ldo14 {
+					regulator-compatible = "LDO14";
+					regulator-name = "VDD_ABB02_1.8V";
+					regulator-min-microvolt = <1800000>;
+					regulator-max-microvolt = <1800000>;
+				};
+
+				ldo15_reg: ldo15 {
+					regulator-compatible = "LDO15";
+					regulator-name = "VDD_HSIC/OTG_1.0V";
+					regulator-min-microvolt = <1000000>;
+					regulator-max-microvolt = <1000000>;
+				};
+
+				ldo16_reg: ldo16 {
+					regulator-compatible = "LDO16";
+					regulator-name = "VDD_HSIC_1.8V";
+					regulator-min-microvolt = <1800000>;
+					regulator-max-microvolt = <1800000>;
+				};
+
+				ldo17_reg: ldo17 {
+					regulator-compatible = "LDO17";
+					regulator-name = "VDDQ_CAM_1.2V";
+					regulator-min-microvolt = <1200000>;
+					regulator-max-microvolt = <1200000>;
+				};
+
+				ldo18_reg: ldo18 {
+					regulator-compatible = "LDO18";
+					regulator-name = "nc";
+					regulator-min-microvolt = <1800000>;
+					regulator-max-microvolt = <1800000>;
+				};
+
+				ldo19_reg: ldo19 {
+					regulator-compatible = "LDO19";
+					regulator-name = "nc";
+					regulator-min-microvolt = <1800000>;
+					regulator-max-microvolt = <1800000>;
+				};
+
+				ldo20_reg: ldo20 {
+					regulator-compatible = "LDO20";
+					regulator-name = "VDDQ_EMMC_1.8V";
+					regulator-min-microvolt = <1800000>;
+					regulator-max-microvolt = <1800000>;
+					regulator-always-on;
+					regulator-boot-on;
+				};
+
+				ldo21_reg: ldo21 {
+					regulator-compatible = "LDO21";
+					regulator-name = "TFLASH_2.8V";
+					regulator-min-microvolt = <2800000>;
+					regulator-max-microvolt = <2800000>;
+					regulator-always-on;
+					regulator-boot-on;
+				};
+
+				ldo22_reg: ldo22 {
+					regulator-compatible = "LDO22";
+					regulator-name = "VDDQ_EMMC_2.8V";
+					regulator-min-microvolt = <2800000>;
+					regulator-max-microvolt = <2800000>;
+					regulator-always-on;
+					regulator-boot-on;
+				};
+
+				ldo23_reg: ldo23 {
+					regulator-compatible = "LDO23";
+					regulator-name = "nc";
+					regulator-min-microvolt = <3300000>;
+					regulator-max-microvolt = <3300000>;
+				};
+
+				ldo24_reg: ldo24 {
+					regulator-compatible = "LDO24";
+					regulator-name = "nc";
+					regulator-min-microvolt = <3000000>;
+					regulator-max-microvolt = <3000000>;
+				};
+
+				ldo25_reg: ldo25 {
+					regulator-compatible = "LDO25";
+					regulator-name = "VDDQ_LCD_3.0V";
+					regulator-min-microvolt = <3000000>;
+					regulator-max-microvolt = <3000000>;
+				};
+
+				ldo26_reg: ldo26 {
+					regulator-compatible = "LDO26";
+					regulator-name = "nc";
+					regulator-min-microvolt = <3000000>;
+					regulator-max-microvolt = <3000000>;
+				};
+
+				buck1_reg: buck at 1 {
+					regulator-compatible = "BUCK1";
+					regulator-name = "VDD_MIF_1.0V";
+					regulator-min-microvolt = <8500000>;
+					regulator-max-microvolt = <1100000>;
+				};
+
+				buck2_reg: buck at 2 {
+					regulator-compatible = "BUCK2";
+					regulator-name = "VDD_ARM_1.0V";
+					regulator-min-microvolt = <850000>;
+					regulator-max-microvolt = <1500000>;
+				};
+
+				buck3_reg: buck3 {
+					regulator-compatible = "BUCK3";
+					regulator-name = "VDD_INT_1.1V";
+					regulator-min-microvolt = <850000>;
+					regulator-max-microvolt = <1150000>;
+				};
+
+				buck4_reg: buck4 {
+					regulator-compatible = "BUCK4";
+					regulator-name = "VDD_G3D_1.0V";
+					regulator-min-microvolt = <850000>;
+					regulator-max-microvolt = <1150000>;
+				};
+
+				buck5_reg: buck5 {
+					regulator-compatible = "BUCK5";
+					regulator-name = "VDDQ_AP_1.2V";
+					regulator-min-microvolt = <1200000>;
+					regulator-max-microvolt = <1200000>;
+				};
+
+				buck6_reg: buck6 {
+					regulator-compatible = "BUCK6";
+					regulator-name = "VCC_INL1/7_1.35V";
+					regulator-min-microvolt = <1350000>;
+					regulator-max-microvolt = <1350000>;
+				};
+
+				buck7_reg: buck7 {
+					regulator-compatible = "BUCK7";
+					regulator-name = "VCC_INL2/3/5_2.0V";
+					regulator-min-microvolt = <2000000>;
+					regulator-max-microvolt = <2000000>;
+				};
+
+				buck8_reg: buck8 {
+					regulator-compatible = "BUCK8";
+					regulator-name = "VCC_P3V3_2.85V";
+					regulator-min-microvolt = <2850000>;
+					regulator-max-microvolt = <3300000>;
+				};
+
+				buck9_reg: buck9 {
+					regulator-compatible = "BUCK9";
+					regulator-name = "nc";
+					regulator-min-microvolt = <1200000>;
+					regulator-max-microvolt = <1200000>;
+				};
+			};
 		};
 	};
 
Signature · 1 line
1.9.1
#209 lore raw

PATCH v4 15/16 odroid: dts: add 'voltage-regulators' description to max77686 node

Quoted 12 lines · Przemyslaw Marczak

Adding regulators subnode to fdt max77686 node, allows properly init regulators by the max77686 regulator driver. This enables the complete functionality of the regulator command.

---
Changes V2:
- odroid: dts: remove pmic alias

Changes V3:
- none

Quoted 7 lines

Changes V4:
- add constraints for mmc regulators auto enable

---
 arch/arm/dts/exynos4412-odroid.dts | 253 +++++++++++++++++++++++++++++++++++++
 1 file changed, 253 insertions(+)
#210 lore raw

PATCH v4 15/16 odroid: dts: add 'voltage-regulators' description to max77686 node

Quoted 16 lines · Simon Glass
Quoted 15 lines · Przemyslaw Marczak

Adding regulators subnode to fdt max77686 node, allows properly init regulators by the max77686 regulator driver. This enables the complete functionality of the regulator command.

---
Changes V2:
- odroid: dts: remove pmic alias

Changes V3:
- none

Changes V4:
- add constraints for mmc regulators auto enable

Quoted 6 lines
Quoted 4 lines
---
 arch/arm/dts/exynos4412-odroid.dts | 253 +++++++++++++++++++++++++++++++++++++
 1 file changed, 253 insertions(+)

Applied to u-boot-dm/next, thanks!

#211 lore raw

PATCH v4 16/16 odroid: config: enable dm pmic, dm regulator and max77686 driver

In reply to Przemyslaw Marczak

This change enables the configs required to init and setup max77686 regulator driver, using the new driver model pmic and regulator API.

This commits enables:
- CONFIG_ERRNO_STR
- CONFIG_DM_PMIC
- CONFIG_DM_PMIC_CMD
- CONFIG_DM_PMIC_MAX77686
- CONFIG_DM_REGULATOR
- CONFIG_DM_REGULATOR_CMD
- CONFIG_DM_REGULATOR_MAX77686

And removes the unused:
- CONFIG_DM_I2C_COMPAT
- CONFIG_POWER
- CONFIG_POWER_I2C
- CONFIG_POWER_MAX77686

---
Changes V2:
- config: enable dm i2c; cleanup
- remove CONFIG_DM_I2C_COMPAT
- enable regulator command

Changes V3:
- move options to defconfig

Changes V4:
- update commands config names

---
 configs/odroid_defconfig | 8 +++++++-
 include/configs/odroid.h | 5 -----
 2 files changed, 7 insertions(+), 6 deletions(-)
configs/odroid_defconfig +7 -1
index d32b5b5..6ca9586 100644
@@ -4,5 +4,11 @@ CONFIG_TARGET_ODROID=y
 CONFIG_OF_CONTROL=y
 CONFIG_DEFAULT_DEVICE_TREE="exynos4412-odroid"
 CONFIG_DM_I2C=y
-CONFIG_DM_I2C_COMPAT=y
 # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+CONFIG_ERRNO_STR=y
+CONFIG_DM_PMIC=y
+CONFIG_CMD_PMIC=y
+CONFIG_DM_PMIC_MAX77686=y
+CONFIG_DM_REGULATOR=y
+CONFIG_CMD_REGULATOR=y
+CONFIG_DM_REGULATOR_MAX77686=y
include/configs/odroid.h +0 -5
index 5ee0abe..3874baa 100644
@@ -182,11 +182,6 @@
 #define CONFIG_SYS_I2C_S3C24X0_SPEED	100000
 #define CONFIG_SYS_I2C_S3C24X0_SLAVE	0
 
-/* POWER */
-#define CONFIG_POWER
-#define CONFIG_POWER_I2C
-#define CONFIG_POWER_MAX77686
-
 /* GPT */
 #define CONFIG_RANDOM_UUID
 
Signature · 1 line
1.9.1
#212 lore raw

PATCH v4 16/16 odroid: config: enable dm pmic, dm regulator and max77686 driver

Quoted 28 lines · Przemyslaw Marczak

This change enables the configs required to init and setup max77686 regulator driver, using the new driver model pmic and regulator API.

This commits enables:
- CONFIG_ERRNO_STR
- CONFIG_DM_PMIC
- CONFIG_DM_PMIC_CMD
- CONFIG_DM_PMIC_MAX77686
- CONFIG_DM_REGULATOR
- CONFIG_DM_REGULATOR_CMD
- CONFIG_DM_REGULATOR_MAX77686

And removes the unused:
- CONFIG_DM_I2C_COMPAT
- CONFIG_POWER
- CONFIG_POWER_I2C
- CONFIG_POWER_MAX77686

---
Changes V2:
- config: enable dm i2c; cleanup
- remove CONFIG_DM_I2C_COMPAT
- enable regulator command

Changes V3:
- move options to defconfig

Quoted 7 lines

Changes V4:
- update commands config names

---
 configs/odroid_defconfig | 8 +++++++-
 include/configs/odroid.h | 5 -----
 2 files changed, 7 insertions(+), 6 deletions(-)
#213 lore raw

PATCH v4 16/16 odroid: config: enable dm pmic, dm regulator and max77686 driver

Quoted 32 lines · Simon Glass
Quoted 31 lines · Przemyslaw Marczak

This change enables the configs required to init and setup max77686 regulator driver, using the new driver model pmic and regulator API.

This commits enables:
- CONFIG_ERRNO_STR
- CONFIG_DM_PMIC
- CONFIG_DM_PMIC_CMD
- CONFIG_DM_PMIC_MAX77686
- CONFIG_DM_REGULATOR
- CONFIG_DM_REGULATOR_CMD
- CONFIG_DM_REGULATOR_MAX77686

And removes the unused:
- CONFIG_DM_I2C_COMPAT
- CONFIG_POWER
- CONFIG_POWER_I2C
- CONFIG_POWER_MAX77686

---
Changes V2:
- config: enable dm i2c; cleanup
- remove CONFIG_DM_I2C_COMPAT
- enable regulator command

Changes V3:
- move options to defconfig

Changes V4:
- update commands config names

Quoted 6 lines
Quoted 4 lines
---
 configs/odroid_defconfig | 8 +++++++-
 include/configs/odroid.h | 5 -----
 2 files changed, 7 insertions(+), 6 deletions(-)

Applied to u-boot-dm/next, thanks!

#214 lore raw

v4 cover Power(full) framework based on Driver Model

In reply to Przemyslaw Marczak

Hi Przemyslaw,

Quoted 87 lines · Przemyslaw Marczak

Hello,
Again the next version. The changes are described below each commit message. This is rebased on last u-boot-dm/master after apply this patchset:
https://patchwork.ozlabs.org/patch/462775/
https://patchwork.ozlabs.org/patch/462777/
https://patchwork.ozlabs.org/patch/462776/

This all can be found in here:
https://github.com/bobenstein/u-boot/tree/dm-pmic-v4

Best regards,

Przemyslaw Marczak (16):
exynos5: fix build break by adding CONFIG_POWER
exynos4-common: remove the unsued CONFIG_CMD_PMIC
lib: Kconfig: add entry for errno_str() function
dm: pmic: add implementation of driver model pmic uclass
dm: regulator: add implementation of driver model regulator uclass
dm: pmic: add pmic command
dm: regulator: add regulator command
pmic: max77686 set the same compatible as in the kernel
dm: pmic: add max77686 pmic driver
dm: regulator: add max77686 regulator driver
dm: regulator: add fixed voltage regulator driver
doc: driver-model: pmic and regulator uclass documentation
dm: board:samsung: power_init_board: add requirement of CONFIG_DM_PMIC
odroid: board: add support to dm pmic api
odroid: dts: add 'voltage-regulators' description to max77686 node
odroid: config: enable dm pmic, dm regulator and max77686 driver

 Makefile                                         |   3 +-
 arch/arm/dts/exynos4412-odroid.dts               | 255 ++++++-
 arch/arm/dts/exynos4412-trats2.dts               |   2 +-
 arch/arm/dts/exynos5250-smdk5250.dts             |   2 +-
 arch/arm/dts/exynos5250-snow.dts                 |   2 +-
 board/samsung/common/board.c                     |   4 +-
 board/samsung/common/misc.c                      |   1 +
 board/samsung/odroid/odroid.c                    |  77 ++-
 common/Kconfig                                   |  36 +
 common/Makefile                                  |   4 +
 common/cmd_pmic.c                                | 231 +++++++
 common/cmd_regulator.c                           | 403 +++++++++++
 configs/odroid_defconfig                         |   8 +-
 doc/device-tree-bindings/pmic/max77686.txt       |  36 +
 doc/device-tree-bindings/regulator/fixed.txt     |  38 ++
 doc/device-tree-bindings/regulator/max77686.txt  |  70 ++
 doc/device-tree-bindings/regulator/regulator.txt |  55 ++
 doc/driver-model/pmic-framework.txt              | 142 ++++
 drivers/power/Kconfig                            |   8 +
 drivers/power/Makefile                           |   1 -
 drivers/power/pmic/Kconfig                       |  18 +
 drivers/power/pmic/Makefile                      |   2 +
 drivers/power/pmic/max77686.c                    |  87 +++
 drivers/power/pmic/pmic-uclass.c                 | 158 +++++
 drivers/power/pmic/pmic_max77686.c               |   2 +-
 drivers/power/regulator/Kconfig                  |  33 +
 drivers/power/regulator/Makefile                 |  10 +
 drivers/power/regulator/fixed.c                  | 126 ++++
 drivers/power/regulator/max77686.c               | 825 +++++++++++++++++++++++
 drivers/power/regulator/regulator-uclass.c       | 300 +++++++++
 include/configs/exynos4-common.h                 |   1 -
 include/configs/exynos5-common.h                 |   4 +
 include/configs/odroid.h                         |   5 -
 include/dm/uclass-id.h                           |   4 +
 include/power/max77686_pmic.h                    |  29 +-
 include/power/pmic.h                             | 189 ++++++
 include/power/regulator.h                        | 384 +++++++++++
 lib/Kconfig                                      |   8 +
 lib/fdtdec.c                                     |   2 +-
 39 files changed, 3512 insertions(+), 53 deletions(-)
 create mode 100644 common/cmd_pmic.c
 create mode 100644 common/cmd_regulator.c
 create mode 100644 doc/device-tree-bindings/pmic/max77686.txt
 create mode 100644 doc/device-tree-bindings/regulator/fixed.txt
 create mode 100644 doc/device-tree-bindings/regulator/max77686.txt
 create mode 100644 doc/device-tree-bindings/regulator/regulator.txt
 create mode 100644 doc/driver-model/pmic-framework.txt
 create mode 100644 drivers/power/pmic/Kconfig
 create mode 100644 drivers/power/pmic/max77686.c
 create mode 100644 drivers/power/pmic/pmic-uclass.c
 create mode 100644 drivers/power/regulator/Kconfig
 create mode 100644 drivers/power/regulator/Makefile
 create mode 100644 drivers/power/regulator/fixed.c
 create mode 100644 drivers/power/regulator/max77686.c
 create mode 100644 drivers/power/regulator/regulator-uclass.c
 create mode 100644 include/power/regulator.h
Quoted 3 lines

--
1.9.1

I'm going to test this and apply to u-boot-dm/next while we wait for you to finish the sandbox test code. I've made a few comments on the series. They are minor so I don't want to do another whole spin of the series (it takes time to review!), but you could do a fix-up patch or two if you like. I could perhaps squash them in if you prefer that, but honestly they are nits.

It will be great to get this into mainline soon!

Regards,
Simon

#215 lore raw

v4 cover Power(full) framework based on Driver Model

Hello Simon,

Quoted 101 lines · Simon Glass

Hi Przemyslaw,

Quoted 87 lines · Przemyslaw Marczak

Hello,
Again the next version. The changes are described below each commit message. This is rebased on last u-boot-dm/master after apply this patchset:
https://patchwork.ozlabs.org/patch/462775/
https://patchwork.ozlabs.org/patch/462777/
https://patchwork.ozlabs.org/patch/462776/

This all can be found in here:
https://github.com/bobenstein/u-boot/tree/dm-pmic-v4

Best regards,

Przemyslaw Marczak (16):
exynos5: fix build break by adding CONFIG_POWER
exynos4-common: remove the unsued CONFIG_CMD_PMIC
lib: Kconfig: add entry for errno_str() function
dm: pmic: add implementation of driver model pmic uclass
dm: regulator: add implementation of driver model regulator uclass
dm: pmic: add pmic command
dm: regulator: add regulator command
pmic: max77686 set the same compatible as in the kernel
dm: pmic: add max77686 pmic driver
dm: regulator: add max77686 regulator driver
dm: regulator: add fixed voltage regulator driver
doc: driver-model: pmic and regulator uclass documentation
dm: board:samsung: power_init_board: add requirement of CONFIG_DM_PMIC
odroid: board: add support to dm pmic api
odroid: dts: add 'voltage-regulators' description to max77686 node
odroid: config: enable dm pmic, dm regulator and max77686 driver

  Makefile                                         |   3 +-
  arch/arm/dts/exynos4412-odroid.dts               | 255 ++++++-
  arch/arm/dts/exynos4412-trats2.dts               |   2 +-
  arch/arm/dts/exynos5250-smdk5250.dts             |   2 +-
  arch/arm/dts/exynos5250-snow.dts                 |   2 +-
  board/samsung/common/board.c                     |   4 +-
  board/samsung/common/misc.c                      |   1 +
  board/samsung/odroid/odroid.c                    |  77 ++-
  common/Kconfig                                   |  36 +
  common/Makefile                                  |   4 +
  common/cmd_pmic.c                                | 231 +++++++
  common/cmd_regulator.c                           | 403 +++++++++++
  configs/odroid_defconfig                         |   8 +-
  doc/device-tree-bindings/pmic/max77686.txt       |  36 +
  doc/device-tree-bindings/regulator/fixed.txt     |  38 ++
  doc/device-tree-bindings/regulator/max77686.txt  |  70 ++
  doc/device-tree-bindings/regulator/regulator.txt |  55 ++
  doc/driver-model/pmic-framework.txt              | 142 ++++
  drivers/power/Kconfig                            |   8 +
  drivers/power/Makefile                           |   1 -
  drivers/power/pmic/Kconfig                       |  18 +
  drivers/power/pmic/Makefile                      |   2 +
  drivers/power/pmic/max77686.c                    |  87 +++
  drivers/power/pmic/pmic-uclass.c                 | 158 +++++
  drivers/power/pmic/pmic_max77686.c               |   2 +-
  drivers/power/regulator/Kconfig                  |  33 +
  drivers/power/regulator/Makefile                 |  10 +
  drivers/power/regulator/fixed.c                  | 126 ++++
  drivers/power/regulator/max77686.c               | 825 +++++++++++++++++++++++
  drivers/power/regulator/regulator-uclass.c       | 300 +++++++++
  include/configs/exynos4-common.h                 |   1 -
  include/configs/exynos5-common.h                 |   4 +
  include/configs/odroid.h                         |   5 -
  include/dm/uclass-id.h                           |   4 +
  include/power/max77686_pmic.h                    |  29 +-
  include/power/pmic.h                             | 189 ++++++
  include/power/regulator.h                        | 384 +++++++++++
  lib/Kconfig                                      |   8 +
  lib/fdtdec.c                                     |   2 +-
  39 files changed, 3512 insertions(+), 53 deletions(-)

create mode 100644 common/cmd_pmic.c
create mode 100644 common/cmd_regulator.c
create mode 100644 doc/device-tree-bindings/pmic/max77686.txt create mode 100644 doc/device-tree-bindings/regulator/fixed.txt create mode 100644 doc/device-tree-bindings/regulator/max77686.txt create mode 100644 doc/device-tree-bindings/regulator/regulator.txt create mode 100644 doc/driver-model/pmic-framework.txt create mode 100644 drivers/power/pmic/Kconfig
create mode 100644 drivers/power/pmic/max77686.c
create mode 100644 drivers/power/pmic/pmic-uclass.c create mode 100644 drivers/power/regulator/Kconfig create mode 100644 drivers/power/regulator/Makefile create mode 100644 drivers/power/regulator/fixed.c create mode 100644 drivers/power/regulator/max77686.c create mode 100644 drivers/power/regulator/regulator-uclass.c create mode 100644 include/power/regulator.h

Quoted 3 lines

--
1.9.1

I'm going to test this and apply to u-boot-dm/next while we wait for you to finish the sandbox test code. I've made a few comments on the series. They are minor so I don't want to do another whole spin of the series (it takes time to review!), but you could do a fix-up patch or two if you like. I could perhaps squash them in if you prefer that, but honestly they are nits.

Quoted 5 lines

It will be great to get this into mainline soon!

Regards,
Simon

Thank you again for the review. I know, that it takes a time, especially when things are fully reworked.
I have some other things to do now. So I think, that the end of the next week is reliable time to have the sandbox tests ready.

I will try to resend the fixes today or tomorrow.

One more question about the sandbox.

What do you think about adding: "drivers/power/pmic/max77686-sandbox.c"? The read/write could be done for the file as in the sandbox SPI driver. Then it's no problem to enable the max77686 regulator for the sandbox. This could probably work without dump the real device, when keep the set -> get I/O order.

Best regards,

Signature · 4 lines
Przemyslaw Marczak
Samsung R&D Institute Poland
Samsung Electronics
p.marczak at samsung.com
#216 lore raw

v4 cover Power(full) framework based on Driver Model

Hi Przemyslaw,

Quoted 123 lines · Przemyslaw Marczak

Hello Simon,

Quoted 106 lines · Simon Glass

Hi Przemyslaw,

Quoted 90 lines · Przemyslaw Marczak

Hello,
Again the next version. The changes are described below each commit message.
This is rebased on last u-boot-dm/master after apply this patchset:
https://patchwork.ozlabs.org/patch/462775/
https://patchwork.ozlabs.org/patch/462777/
https://patchwork.ozlabs.org/patch/462776/

This all can be found in here:
https://github.com/bobenstein/u-boot/tree/dm-pmic-v4

Best regards,

Przemyslaw Marczak (16):
exynos5: fix build break by adding CONFIG_POWER
exynos4-common: remove the unsued CONFIG_CMD_PMIC
lib: Kconfig: add entry for errno_str() function
dm: pmic: add implementation of driver model pmic uclass
dm: regulator: add implementation of driver model regulator uclass
dm: pmic: add pmic command
dm: regulator: add regulator command
pmic: max77686 set the same compatible as in the kernel
dm: pmic: add max77686 pmic driver
dm: regulator: add max77686 regulator driver
dm: regulator: add fixed voltage regulator driver
doc: driver-model: pmic and regulator uclass documentation
dm: board:samsung: power_init_board: add requirement of CONFIG_DM_PMIC
odroid: board: add support to dm pmic api
odroid: dts: add 'voltage-regulators' description to max77686 node
odroid: config: enable dm pmic, dm regulator and max77686 driver

  Makefile                                         |   3 +-
  arch/arm/dts/exynos4412-odroid.dts               | 255 ++++++-
  arch/arm/dts/exynos4412-trats2.dts               |   2 +-
  arch/arm/dts/exynos5250-smdk5250.dts             |   2 +-
  arch/arm/dts/exynos5250-snow.dts                 |   2 +-
  board/samsung/common/board.c                     |   4 +-
  board/samsung/common/misc.c                      |   1 +
  board/samsung/odroid/odroid.c                    |  77 ++-
  common/Kconfig                                   |  36 +
  common/Makefile                                  |   4 +
  common/cmd_pmic.c                                | 231 +++++++
  common/cmd_regulator.c                           | 403 +++++++++++
  configs/odroid_defconfig                         |   8 +-
  doc/device-tree-bindings/pmic/max77686.txt       |  36 +
  doc/device-tree-bindings/regulator/fixed.txt     |  38 ++
  doc/device-tree-bindings/regulator/max77686.txt  |  70 ++
  doc/device-tree-bindings/regulator/regulator.txt |  55 ++
  doc/driver-model/pmic-framework.txt              | 142 ++++
  drivers/power/Kconfig                            |   8 +
  drivers/power/Makefile                           |   1 -
  drivers/power/pmic/Kconfig                       |  18 +
  drivers/power/pmic/Makefile                      |   2 +
  drivers/power/pmic/max77686.c                    |  87 +++
  drivers/power/pmic/pmic-uclass.c                 | 158 +++++
  drivers/power/pmic/pmic_max77686.c               |   2 +-
  drivers/power/regulator/Kconfig                  |  33 +
  drivers/power/regulator/Makefile                 |  10 +
  drivers/power/regulator/fixed.c                  | 126 ++++
  drivers/power/regulator/max77686.c               | 825
+++++++++++++++++++++++
  drivers/power/regulator/regulator-uclass.c       | 300 +++++++++
  include/configs/exynos4-common.h                 |   1 -
  include/configs/exynos5-common.h                 |   4 +
  include/configs/odroid.h                         |   5 -
  include/dm/uclass-id.h                           |   4 +
  include/power/max77686_pmic.h                    |  29 +-
  include/power/pmic.h                             | 189 ++++++
  include/power/regulator.h                        | 384 +++++++++++
  lib/Kconfig                                      |   8 +
  lib/fdtdec.c                                     |   2 +-
  39 files changed, 3512 insertions(+), 53 deletions(-)

create mode 100644 common/cmd_pmic.c
create mode 100644 common/cmd_regulator.c
create mode 100644 doc/device-tree-bindings/pmic/max77686.txt create mode 100644 doc/device-tree-bindings/regulator/fixed.txt create mode 100644 doc/device-tree-bindings/regulator/max77686.txt create mode 100644 doc/device-tree-bindings/regulator/regulator.txt create mode 100644 doc/driver-model/pmic-framework.txt create mode 100644 drivers/power/pmic/Kconfig
create mode 100644 drivers/power/pmic/max77686.c
create mode 100644 drivers/power/pmic/pmic-uclass.c create mode 100644 drivers/power/regulator/Kconfig create mode 100644 drivers/power/regulator/Makefile create mode 100644 drivers/power/regulator/fixed.c create mode 100644 drivers/power/regulator/max77686.c create mode 100644 drivers/power/regulator/regulator-uclass.c create mode 100644 include/power/regulator.h

Quoted 3 lines

--
1.9.1

I'm going to test this and apply to u-boot-dm/next while we wait for you to finish the sandbox test code. I've made a few comments on the series. They are minor so I don't want to do another whole spin of the series (it takes time to review!), but you could do a fix-up patch or two if you like. I could perhaps squash them in if you prefer that, but honestly they are nits.

Quoted 5 lines

It will be great to get this into mainline soon!

Regards,
Simon

Thank you again for the review. I know, that it takes a time, especially when things are fully reworked.
I have some other things to do now. So I think, that the end of the next week is reliable time to have the sandbox tests ready.

I will try to resend the fixes today or tomorrow.

Quoted 7 lines

One more question about the sandbox.

What do you think about adding: "drivers/power/pmic/max77686-sandbox.c"? The read/write could be done for the file as in the sandbox SPI driver. Then it's no problem to enable the max77686 regulator for the sandbox. This could probably work without dump the real device, when keep the set -> get I/O order.

I'd be more comfortable with a new pmic, a really simple 'fake' one with just a few LDOs, maybe one BUCK. Enough to support some reasonable tests.

The problem with max77686 is that is it quite complicated, and when writing and expanding tests, we really want things to be simple.

Also for the tests, we really don't need anything elaborate. Try to test the main functions.

Regards,
Simon

#217 lore raw

v4 cover Power(full) framework based on Driver Model

Hello Simon,

Quoted 138 lines · Simon Glass

Hi Przemyslaw,

Quoted 123 lines · Przemyslaw Marczak

Hello Simon,

Quoted 106 lines · Simon Glass

Hi Przemyslaw,

Quoted 90 lines · Przemyslaw Marczak

Hello,
Again the next version. The changes are described below each commit message.
This is rebased on last u-boot-dm/master after apply this patchset:
https://patchwork.ozlabs.org/patch/462775/
https://patchwork.ozlabs.org/patch/462777/
https://patchwork.ozlabs.org/patch/462776/

This all can be found in here:
https://github.com/bobenstein/u-boot/tree/dm-pmic-v4

Best regards,

Przemyslaw Marczak (16):
exynos5: fix build break by adding CONFIG_POWER
exynos4-common: remove the unsued CONFIG_CMD_PMIC
lib: Kconfig: add entry for errno_str() function
dm: pmic: add implementation of driver model pmic uclass
dm: regulator: add implementation of driver model regulator uclass
dm: pmic: add pmic command
dm: regulator: add regulator command
pmic: max77686 set the same compatible as in the kernel
dm: pmic: add max77686 pmic driver
dm: regulator: add max77686 regulator driver
dm: regulator: add fixed voltage regulator driver
doc: driver-model: pmic and regulator uclass documentation
dm: board:samsung: power_init_board: add requirement of CONFIG_DM_PMIC
odroid: board: add support to dm pmic api
odroid: dts: add 'voltage-regulators' description to max77686 node
odroid: config: enable dm pmic, dm regulator and max77686 driver

   Makefile                                         |   3 +-
   arch/arm/dts/exynos4412-odroid.dts               | 255 ++++++-
   arch/arm/dts/exynos4412-trats2.dts               |   2 +-
   arch/arm/dts/exynos5250-smdk5250.dts             |   2 +-
   arch/arm/dts/exynos5250-snow.dts                 |   2 +-
   board/samsung/common/board.c                     |   4 +-
   board/samsung/common/misc.c                      |   1 +
   board/samsung/odroid/odroid.c                    |  77 ++-
   common/Kconfig                                   |  36 +
   common/Makefile                                  |   4 +
   common/cmd_pmic.c                                | 231 +++++++
   common/cmd_regulator.c                           | 403 +++++++++++
   configs/odroid_defconfig                         |   8 +-
   doc/device-tree-bindings/pmic/max77686.txt       |  36 +
   doc/device-tree-bindings/regulator/fixed.txt     |  38 ++
   doc/device-tree-bindings/regulator/max77686.txt  |  70 ++
   doc/device-tree-bindings/regulator/regulator.txt |  55 ++
   doc/driver-model/pmic-framework.txt              | 142 ++++
   drivers/power/Kconfig                            |   8 +
   drivers/power/Makefile                           |   1 -
   drivers/power/pmic/Kconfig                       |  18 +
   drivers/power/pmic/Makefile                      |   2 +
   drivers/power/pmic/max77686.c                    |  87 +++
   drivers/power/pmic/pmic-uclass.c                 | 158 +++++
   drivers/power/pmic/pmic_max77686.c               |   2 +-
   drivers/power/regulator/Kconfig                  |  33 +
   drivers/power/regulator/Makefile                 |  10 +
   drivers/power/regulator/fixed.c                  | 126 ++++
   drivers/power/regulator/max77686.c               | 825
+++++++++++++++++++++++
   drivers/power/regulator/regulator-uclass.c       | 300 +++++++++
   include/configs/exynos4-common.h                 |   1 -
   include/configs/exynos5-common.h                 |   4 +
   include/configs/odroid.h                         |   5 -
   include/dm/uclass-id.h                           |   4 +
   include/power/max77686_pmic.h                    |  29 +-
   include/power/pmic.h                             | 189 ++++++
   include/power/regulator.h                        | 384 +++++++++++
   lib/Kconfig                                      |   8 +
   lib/fdtdec.c                                     |   2 +-
   39 files changed, 3512 insertions(+), 53 deletions(-)

create mode 100644 common/cmd_pmic.c
create mode 100644 common/cmd_regulator.c
create mode 100644 doc/device-tree-bindings/pmic/max77686.txt create mode 100644 doc/device-tree-bindings/regulator/fixed.txt create mode 100644 doc/device-tree-bindings/regulator/max77686.txt create mode 100644 doc/device-tree-bindings/regulator/regulator.txt create mode 100644 doc/driver-model/pmic-framework.txt create mode 100644 drivers/power/pmic/Kconfig
create mode 100644 drivers/power/pmic/max77686.c
create mode 100644 drivers/power/pmic/pmic-uclass.c create mode 100644 drivers/power/regulator/Kconfig create mode 100644 drivers/power/regulator/Makefile create mode 100644 drivers/power/regulator/fixed.c create mode 100644 drivers/power/regulator/max77686.c create mode 100644 drivers/power/regulator/regulator-uclass.c create mode 100644 include/power/regulator.h

Quoted 3 lines

--
1.9.1

I'm going to test this and apply to u-boot-dm/next while we wait for you to finish the sandbox test code. I've made a few comments on the series. They are minor so I don't want to do another whole spin of the series (it takes time to review!), but you could do a fix-up patch or two if you like. I could perhaps squash them in if you prefer that, but honestly they are nits.

Quoted 5 lines

It will be great to get this into mainline soon!

Regards,
Simon

Thank you again for the review. I know, that it takes a time, especially when things are fully reworked.
I have some other things to do now. So I think, that the end of the next week is reliable time to have the sandbox tests ready.

I will try to resend the fixes today or tomorrow.

Quoted 7 lines

One more question about the sandbox.

What do you think about adding: "drivers/power/pmic/max77686-sandbox.c"? The read/write could be done for the file as in the sandbox SPI driver. Then it's no problem to enable the max77686 regulator for the sandbox. This could probably work without dump the real device, when keep the set -> get I/O order.

I'd be more comfortable with a new pmic, a really simple 'fake' one with just a few LDOs, maybe one BUCK. Enough to support some reasonable tests.

Quoted 9 lines

The problem with max77686 is that is it quite complicated, and when writing and expanding tests, we really want things to be simple.

Also for the tests, we really don't need anything elaborate. Try to test the main functions.

Regards,
Simon

Ok, I see. This should be easy.

Best regards,

Signature · 4 lines
Przemyslaw Marczak
Samsung R&D Institute Poland
Samsung Electronics
p.marczak at samsung.com