Power(full) framework based on Driver Model
Subsystems (4)
PATCH v2 5/12 dm: pmic: new commands: pmic and regulator
In reply to Simon GlassHello Simon,
Quoted 953 lines · Simon Glass
Hi Przemyslaw,
Quoted 38 lines · Przemyslaw Marczak
This introduces new commands:
- pmic (new) -CONFIG_DM_PMIC_CMD
- regulator -CONFIG_DM_REGULATOR_CMD
Both uses a common code and dm pmic api.To avoid code mess the old pmic command is kept without changes.
Command pmic
The new pmic command uses driver model pmic api. The previous pmic I/O functionality is keept. And now read/write is the main pmic command feature. This command can be used only forUCLASS_PMICdevices, since this uclass is designed for pmic I/O operations only and provides pmic platform data.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
The user interface is changed. Before any operation, first the device should be chosen.
Command regulator
It uses the same code, but provides user interface for regulator devices.This was designed to access the regulator device without it's documentation. It is possible, if driver implements uclass features, e.g. output descriptors.
Available commands:
- list - list UCLASS regulator devices
- dev [id] - show or set current regulator device
- dump - dump registers of current regulator device
- [ldo/buck/dvs][N] [name/state/desc]- print regulator(s) info
- [ldoN/buckN/dvsN] [setval/setmode] [mV/modeN] [-f] - set val (mV) or mode - only if descriptor existsQuoted 5 lines
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 pmic device design.
This help could go in
Kconfig.Quoted 22 lines
Signed-off-by Przemyslaw Marczak <[email protected]>---
Changes v2:
- removeerrno_str()call
- pmic command: move some code to pmic uclass
- pmic command: code cleanup
- fix data types
- add command line, regulator on/off setting feature
- adjust to new pmic api
- cleanup--- drivers/power/Makefile | 2 + drivers/power/cmd_pmic.c | 820 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 822 insertions(+)create mode 100644
drivers/power/cmd_pmic.cdrivers/power/Makefile +0
-0drivers/power/Makefile obj-$(CONFIG_POWER_FSL) += power_fsl.o · line 27
Quoted 6 lines
drivers/power/Makefile +2
-0@@ -22,4 +22,6 @@ obj-$(CONFIG_POWER_FSL) += power_fsl.o obj-$(CONFIG_POWER_I2C) += power_i2c.o obj-$(CONFIG_POWER_SPI) += power_spi.o obj-$(CONFIG_DM_PMIC) += pmic-uclass.o +obj-$(CONFIG_DM_PMIC_CMD) += cmd_pmic.o obj-$(CONFIG_DM_REGULATOR) += regulator-uclass.o +obj-$(CONFIG_DM_REGULATOR_CMD) += cmd_pmic.oCan we put this in its own file? Also perhaps it should go in common? Not sure about that though.
Quoted 13 lines
drivers/power/cmd_pmic.c new file +7
-0@@ -0,0 +1,820 @@ +/* +* Copyright (C) 2014-2015 Samsung Electronics +* Przemyslaw Marczak <[email protected]> +* +* SPDX-License-Identifier: GPL-2.0+ +*/ +#include <common.h> drivers/power/cmd_pmic.c line 17
Quoted 10 lines
drivers/power/cmd_pmic.c new file +10
-0+#include <linux/types.h> +#include <linux/ctype.h> +#include <fdtdec.h> +#include <dm.h> +#include <power/pmic.h> +#include <power/regulator.h> +#include <dm/device-internal.h> +#include <dm/uclass-internal.h> +#include <dm/root.h> +#include <dm/lists.h> Please sort includes:
common.h
others in order
<asm/...>
<dm/...>
<linux/...>
"local includes"Quoted 143 lines
drivers/power/cmd_pmic.c new file +143
-0+#include <i2c.h> +#include <compiler.h> +#include <errno.h> + +#define LINE_BUF_LIMIT 80 +#define STR_BUF_LEN 26 +#define ID_STR_LIMIT 4 +#define UC_STR_LIMIT 16 +#define DRV_STR_LIMIT 26 +#define IF_STR_LIMIT 12 + +static struct udevice *pmic_curr; +static struct udevice *reg_curr; + +#ifdef CONFIG_DM_REGULATOR_CMD +#define TYPE_INFO (_id, _name) { \ + .id = _id, \ + .len = ARRAY_SIZE(_name) - 1, \ + .name = _name, \ +} + +enum display_info { +INFO_NAME , +INFO_STATE , +INFO_DESC , +INFO_DESC_MODE , +INFO_DESC_VAL , +}; + +struct regulator_type_info { +int id; +int len; +char *name; +}; + +static struct regulator_type_info type_info[] = { +TYPE_INFO (REGULATOR_TYPE_LDO ,"ldo" ), +TYPE_INFO (REGULATOR_TYPE_BUCK ,"buck" ), +TYPE_INFO (REGULATOR_TYPE_DVS ,"dvs" ), +}; + +char *regulator_type_str (int regulator_type) +{ +switch (regulator_type) { +case REGULATOR_TYPE_LDO : +case REGULATOR_TYPE_BUCK : +case REGULATOR_TYPE_DVS : +return type_info[regulator_type].name; +default : +return NULL ; + } +} +#endif /* CONFIG_DM_REGULATOR_CMD */ + +static int set_curr_dev (struct udevice *dev) +{ +if (!dev) +return -EINVAL ; + +if (!dev->driver) +return -EINVAL ; + +switch (dev->driver->id) { +case UCLASS_PMIC : + pmic_curr = dev; +break ; +case UCLASS_PMIC_REGULATOR : + reg_curr = dev; +break ; +default : +error ("Bad driver uclass!\n" ); +return -EINVAL ; + } + +return 0 ; +} + +static struct udevice *get_curr_dev (int uclass_id) +{ +switch (uclass_id) { +case UCLASS_PMIC : +return pmic_curr; +case UCLASS_PMIC_REGULATOR : +return reg_curr; +default : +error ("Bad uclass ID!\n" ); +return NULL ; + } +} + +static int curr_dev_name (int uclass_id) +{ +struct udevice *dev =get_curr_dev (uclass_id); + +if (dev) { +printf ("PMIC: %s\n" , dev->name); +return 0 ; + }else { +puts ("PMIC dev is not set!\n" ); +return -ENODEV ; + } +} + +static int pmic_dump (int uclass_id) +{ +struct udevice *dev; +struct udevice *io_dev; +int i, ret, max_offset; +unsigned char val; + + dev =get_curr_dev (uclass_id); +if (!dev) +return -ENODEV ; + +if (pmic_io_dev (dev, &io_dev)) { +printf ("PMIC I/O dev not found\n" ); +return -ENODEV ; + } + + ret =curr_dev_name (uclass_id); +if (ret) +return CMD_RET_USAGE ; + + max_offset =pmic_if_max_offset (io_dev); +printf ("Register count: %u\n" , max_offset); + +for (i =0 ; i < max_offset; i++) { + ret =pmic_read (io_dev, i, &val); +if (ret) { +printf ("PMIC: Registers dump failed: %d\n" , ret); +return -EIO ; + } + +if (!(i %16 )) +printf ("\n0x%02x: " , i); + +printf ("%2.2x " , val); + } +puts ("\n" ); +return 0 ; +} + +/** drivers/power/cmd_pmic.c line 170
Quoted 10 lines
drivers/power/cmd_pmic.c new file +10
-0+* display_column - display a string from buffer limited by the column len. +* Allows display well aligned string columns. +* +* @buf: a pointer to the buffer with the string to display as a column +* @str_len: len of the string +* @column_len: a number of characters to be printed, but it is actually +* decremented by 1 for the ending character: '|' +*/ +static int display_column (char *buf,unsigned int str_len, +unsigned int column_len)What about using
printf("%.*s", str_len, buf)instead of this function?Quoted 32 lines
drivers/power/cmd_pmic.c new file +32
-0+{ +int i = column_len; + +if (str_len < column_len -1 ) { +for (i = str_len; i < column_len; i++) + buf[i] =' ' ; + } + + buf[column_len -1 ] ='|' ; + buf[column_len] ='\0' ; + +puts (buf); + +return i; +} + +static int pmic_list_uclass_devices (int uclass_id) +{ +ALLOC_CACHE_ALIGN_BUFFER (char, buf,LINE_BUF_LIMIT ); +struct uclass_driver *uc_drv =NULL ; +struct udevice *dev =NULL ; +struct driver *drv =NULL ; +struct uclass *uc =NULL ; +int len; +int ret; + +puts ("| Id | Uclass | Driver | Interface |\n" ); + + ret =uclass_get (uclass_id, &uc); +if (ret) { +error ("PMIC uclass: %d not found!\n" , uclass_id); +return -EINVAL ;drivers/power/cmd_pmic.c line 212
Quoted 10 lines
drivers/power/cmd_pmic.c new file +10
-0+ } + + uc_drv = uc->uc_drv; + uclass_foreach_dev(dev, uc) { +if (dev) +device_probe (dev); +else +continue ; + +printf ("| %2.d |" , dev->seq);Why do you need the '.'?
Quoted 10 lines
drivers/power/cmd_pmic.c new file +10
-0+ + len =snprintf (buf,STR_BUF_LEN ," %2.d@%.10s" , + uc_drv->id, uc_drv->name); + +display_column (buf, len,UC_STR_LIMIT ); + + drv = dev->driver; +if (drv && drv->name) + len =snprintf (buf,STR_BUF_LEN ," %.26s" , drv->name); +else drivers/power/cmd_pmic.c line 232
Quoted 10 lines
drivers/power/cmd_pmic.c new file +10
-0+ len =snprintf (buf,STR_BUF_LEN ," - " ); + +display_column (buf, len,DRV_STR_LIMIT ); + + len =snprintf (buf,STR_BUF_LEN ," %s%d at 0x%x" , +pmic_if_str (dev), +pmic_if_bus_num (dev), +pmic_if_addr_cs (dev)); + +display_column (buf, len,IF_STR_LIMIT );Then I hope you might get all this into one
printf()and drop buf?Quoted 22 lines
drivers/power/cmd_pmic.c new file +22
-0+ +puts ("\n" ); + } + +return 0 ; +} + +static int pmic_cmd (char *const argv[],int argc,int uclass_id) +{ +const char *cmd = argv[0 ]; +struct udevice *dev =NULL ; +int seq; + +if (strcmp (cmd,"list" ) ==0 ) +return pmic_list_uclass_devices (uclass_id); + +if (strcmp (cmd,"dev" ) ==0 ) { +switch (argc) { +case 2 : + seq =simple_strtoul (argv[1 ],NULL ,0 ); +uclass_get_device_by_seq (uclass_id, seq, &dev); +if (dev)drivers/power/cmd_pmic.c line 264
Quoted 10 lines
drivers/power/cmd_pmic.c new file +10
-0+set_curr_dev (dev); + else + printf("Device: %d not found\n", seq); +case 1 : +return curr_dev_name (uclass_id); + } + } + +if (strcmp (cmd,"dump" ) ==0 ) +return pmic_dump (uclass_id);Can we use a sub-command table here, like i2c?
Quoted 75 lines
drivers/power/cmd_pmic.c new file +75
-0+ +if (!get_curr_dev (uclass_id)) +return -ENODEV ; + +return 1 ; +} + +#ifdef CONFIG_DM_REGULATOR_CMD +static char *get_reg_mode_name (int reg,int mode, +struct regulator_mode_desc *mode_desc, +int desc_cnt) +{ +int i; +char *mode_name =NULL ; + +if (!mode_desc) +return NULL ; + +for (i =0 ; i < desc_cnt; i++) { +if (mode_desc[i].mode == mode) + mode_name = mode_desc[i].name; + } + +return mode_name; +} + +static int set_reg_state (int type,int reg_num,int on_off) +{ +struct udevice *dev; + + dev =get_curr_dev (UCLASS_PMIC_REGULATOR ); +if (!dev) +return -ENODEV ; + +return regulator_set_state (dev,type, reg_num, on_off); +} + +/** +* display_reg_info: list regualtor(s) info +* @start_reg; @end_reg - first and last regulator number to list +* if start_reg == end_reg - then displays only one regulator info +* +* @display_info options: +* +* =?INFO_NAME: +* regN: name +* +* =?INFO_STATE: +* regN: name +* - Vout: val mV mode: N (name) +* +* =?INFO_DESC +* regN: name +* - Vout: val mV +* - Vmin: val mV +* - Vmax: val mV +* - mode: 1 (name1) [active] +* - mode: 2 (name2) [active] +* - mode: N (nameN) [active] +* +* =?INFO_DESC_VAL +* regN: +* - Vout: val mV +* - Vmin: val mV +* - Vmax: val mV +* +* =?INFO_DESC_VAL +* regN: +* - mode: 1 (name1) [active] +* - mode: 2 (name2) [active] +* - mode: N (nameN) [active] +*/ +static int display_reg_info (int type,int start_reg, +int end_reg,int display_info) +{drivers/power/cmd_pmic.c line 349
Quoted 10 lines
drivers/power/cmd_pmic.c new file +10
-0+struct udevice *dev; +struct regulator_value_desc *desc; +struct regulator_mode_desc *mode_desc; +char *mode_name; +int mode_cnt; +int mode; +int ret; +int state; +int reg_val, i, j; +int div =1000 ;This should be a #define or const int.
drivers/power/cmd_pmic.c line 360
Quoted 11 lines
drivers/power/cmd_pmic.c new file +11
-0+ +if (start_reg > end_reg) +return -EINVAL ; + + dev =get_curr_dev (UCLASS_PMIC_REGULATOR ); +if (!dev) +return -ENODEV ; + +switch (display_info) { +case INFO_STATE : +puts (" RegN: val mV state mode" );I think we are supposed to use
printf()now instead ofputs(), unless in SPL for code size reasons.Quoted 127 lines
drivers/power/cmd_pmic.c new file +127
-0+break ; +case INFO_DESC : +puts (" RegN: @descriptors data" ); +break ; +case INFO_DESC_VAL : +case INFO_DESC_MODE : +break ; +case INFO_NAME : +puts (" RegN: name" ); +break ; +default : +return -EINVAL ; + } + +for (i = start_reg; i <= end_reg; i++) { + ret =regulator_get_mode (dev, type, i, &mode); + ret |=regulator_get_value (dev, type, i, ®_val); + ret |=regulator_get_value_desc (dev, type, i, &desc); + ret |=regulator_get_mode_desc (dev, type, i, &mode_cnt, + &mode_desc); + +/* Probably no such regulator number */ +if (ret) +continue ; + +/* Display in mV */ + reg_val /= div; + +printf ("\n%s%.2d:" ,regulator_type_str (type), i); + +switch (display_info) { +case INFO_STATE : +printf (" %d mV " , reg_val); + +regulator_get_state (dev, type, i, &state); + +printf (" %s" , state ?"ON " :"OFF" ); + + mode_name =get_reg_mode_name (i, mode, mode_desc, + mode_cnt); +if (mode_name) +printf (" %d@%s" , mode, mode_name); + +continue ; +case INFO_DESC : +case INFO_DESC_VAL : +if (desc) +printf ("\n @name: %s" , desc->name); + +/* display voltage range */ +printf ("\n @Vout: %d mV" , reg_val); + +if (!desc) +puts ("\n @no value descriptors" ); +else +printf ("\n @Vmin: %d mV\n @Vmax: %d mV" , + (desc->min_uV / div), + (desc->max_uV / div)); + +if (display_info !=INFO_DESC ) +continue ; +case INFO_DESC_MODE : +if (!mode_desc) { +puts ("\n @no mode descriptors" ); +continue ; + } + +/* display operation modes info */ +for (j =0 ; j < mode_cnt; j++) { +printf ("\n @mode: %d (%s)" , mode_desc[j].mode, + mode_desc[j].name); +if (mode_desc[j].mode == mode) +puts (" (active)" ); + } +continue ; +case INFO_NAME : +if (desc) +printf (" %s" , desc->name); +else +puts (" -" ); +continue ; + } + } + +puts ("\n" ); + +return 0 ; +} + +/** +* check_reg_mode: check if the given regulator supports the given mode +* +* @dev: device to check +* @reg_num: given devices regulator number +* @set_mode: mode to check - a mode value of struct regulator_mode_desc +* @type: descriptor type: REGULATOR_TYPE_LDO or REGULATOR_TYPE_BUCK +*/ +static int check_reg_mode (struct udevice *dev,int reg_num,int set_mode, +int type) +{ +struct regulator_mode_desc *mode_desc; +int i, mode_cnt; + +regulator_get_mode_desc (dev, type, reg_num, &mode_cnt, &mode_desc); +if (!mode_desc) + goto nodesc; + +for (i =0 ; i < mode_cnt; i++) { +if (mode_desc[i].mode == set_mode) +return 0 ; + } + +printf ("Mode:%d not found in the descriptor:" , set_mode); + +display_reg_info (type, reg_num, reg_num,INFO_DESC_MODE ); + +return -EINVAL ; + +nodesc: +printf ("%s%.2d - no descriptor found\n" ,regulator_type_str (type), + reg_num); +return -ENODEV ; +} + +static int set_reg_mode (int type,int reg_num,int set_mode) +{ +int ret;drivers/power/cmd_pmic.c line 497
Quoted 10 lines
drivers/power/cmd_pmic.c new file +10
-0+struct udevice *dev; + + dev =get_curr_dev (UCLASS_PMIC_REGULATOR ); +if (!dev) +return -ENODEV ; + +if (check_reg_mode (dev, reg_num, set_mode, type)) +return -EPERM ; + + printf("Set %s%.2d mode: %d\n", regulator_type_str(type),Why %2d? Why not just %d?
Quoted 40 lines
drivers/power/cmd_pmic.c new file +40
-0+ reg_num, set_mode); + + ret =regulator_set_mode (dev, type, reg_num, set_mode); + +return ret; +} + +/** +* check_reg_val: check if the given regulator value meets +* the descriptor min and max values +* +* @dev: device to check +* @reg_num: given devices regulator number +* @set_val: value to check - in uV +* @type: descriptor type: REGULATOR_TYPE_LDO or REGULATOR_TYPE_BUCK +*/ +static int check_reg_val (struct udevice *dev,int reg_num,int set_val, +int type) +{ +struct regulator_value_desc *desc; + +regulator_get_value_desc (dev, type, reg_num, &desc); +if (!desc) + goto nodesc; + +if (set_val >= desc->min_uV && set_val <= desc->max_uV) +return 0 ; + +printf ("Value: %d mV exceeds descriptor limits:" , (set_val /1000 )); + +display_reg_info (type, reg_num, reg_num,INFO_DESC_VAL ); + +return -EINVAL ; +nodesc: +printf ("%s%.2d - no descriptor found\n" ,regulator_type_str (type), + reg_num); +return -ENODEV ; +} + +static int set_reg_val (int type,int reg_num,int set_val,int set_force)drivers/power/cmd_pmic.c line 547
Quoted 10 lines
drivers/power/cmd_pmic.c new file +10
-0+{ +int ret; +struct udevice *dev; + + dev =get_curr_dev (UCLASS_PMIC_REGULATOR ); +if (!dev) +return -ENODEV ; + +/* get mV and set as uV */ + set_val *=1000 ;Perhaps the command should work in uV too? Or maybe a 'mV' suffix on numbers?
Quoted 4 lines
drivers/power/cmd_pmic.c new file +4
-0+ +if (!set_force &&check_reg_val (dev, reg_num, set_val, type)) +return -EPERM ; +drivers/power/cmd_pmic.c line 561
Quoted 10 lines
drivers/power/cmd_pmic.c new file +10
-0+printf ("Set %s%.2d val: %d mV" ,regulator_type_str (type), + reg_num, (set_val /1000 )); + +if (set_force) +puts (" (force)\n" ); +else +puts ("\n" ); + + ret =regulator_set_value (dev, type, reg_num, set_val); +return ret;You don't need ret.
Quoted 27 lines
drivers/power/cmd_pmic.c new file +27
-0+} + +static int regulator_subcmd (char *const argv[],int argc,int type, +int reg_num,int reg_cnt) +{ +int start_reg, end_reg; +int set_val, set_force; +const char *cmd; + +/* If reg number is given */ +if (reg_num >=0 ) { + start_reg = reg_num; + end_reg = reg_num; + }else { + start_reg =0 ; + end_reg = reg_cnt; + } + + cmd = argv[0 ]; +if (!strcmp ("name" , cmd)) +return display_reg_info (type, start_reg, end_reg,INFO_NAME ); +else if (!strcmp ("state" , cmd)) +return display_reg_info (type, start_reg, end_reg,INFO_STATE ); +else if (!strcmp ("desc" , cmd)) +return display_reg_info (type, start_reg, end_reg,INFO_DESC ); + +/* Check if regulator number is given */ drivers/power/cmd_pmic.c line 598
Quoted 10 lines
drivers/power/cmd_pmic.c new file +10
-0+if (reg_num <0 ) { +puts ("reg num?\n" ); +return -EINVAL ; + } + +if (!strcmp ("on" , cmd)) +return set_reg_state (type, reg_num,REGULATOR_ON ); + +if (!strcmp ("off" , cmd)) +return set_reg_state (type, reg_num,REGULATOR_OFF );Can we use a sub command table again?
Quoted 104 lines
drivers/power/cmd_pmic.c new file +104
-0+ +/* Check argument value */ +if (argc <2 || !isdigit (*argv[1 ])) { +puts ("Expected positive value!\n" ); +return -EINVAL ; + } + + set_val =simple_strtoul (argv[1 ],NULL ,0 ); + set_force =0 ; + +if (!strcmp ("setval" , cmd)) { +if (argc ==3 && !strcmp ("-f" , argv[2 ])) + set_force =1 ; + +return set_reg_val (type, reg_num, set_val, set_force); + } + +if (!strcmp ("setmode" , cmd)) +return set_reg_mode (type, reg_num, set_val); + +return -EINVAL ; +} + +static int do_regulator (cmd_tbl_t *cmdtp,int flag,int argc, +char *const argv[]) +{ +struct udevice *dev =NULL ; +int cmd_len; +int ret =0 ; +int reg_num =-1 ; +int reg_cnt; +int i; +char *cmd; + +if (!argc) +return CMD_RET_USAGE ; + +/* list, dev, dump */ + ret =pmic_cmd (argv, argc,UCLASS_PMIC_REGULATOR ); +if (ret !=1 ) + goto finish; + + cmd = argv[0 ]; + cmd_len =strlen (cmd); + + dev =get_curr_dev (UCLASS_PMIC_REGULATOR ); +if (!dev) +return CMD_RET_USAGE ; + +for (i =0 ; i <ARRAY_SIZE (type_info); i++) { +if (!strncmp (cmd, type_info[i].name, type_info[i].len)) { + ret =regulator_get_cnt (dev, type_info[i].id, ®_cnt); +break ; + } + } + +if (!reg_cnt) { +printf ("Bad regulator type!\n" ); + goto finish; + } + +/* Get regulator number */ + reg_num =-1 ; +if (cmd_len > type_info[i].len &&isdigit (cmd[type_info[i].len])) + reg_num = (int )simple_strtoul (cmd + type_info[i].len ,NULL ,0 ); + +if (reg_num > reg_cnt) { +printf ("Max dev %s number is: %d\n" , type_info[i].name, + reg_cnt); +return CMD_RET_SUCCESS ; + } + +/* Subcommand missed? */ +if (argc ==1 ) { +printf ("name/state/desc/setval/setmode/on/off ?\n" ); +return CMD_RET_SUCCESS ; + } + + argv++; + argc--; + ret =regulator_subcmd (argv, argc, type_info[i].id, reg_num, reg_cnt); + +finish: +if (ret <0 ) +return CMD_RET_FAILURE ; + +return CMD_RET_SUCCESS ; +} +#endif /* CONFIG_DM_REGULATOR_CMD */ + +#ifdef CONFIG_DM_PMIC_CMD +static int do_pmic (cmd_tbl_t *cmdtp,int flag,int argc,char *const argv[]) +{ +struct udevice *dev, *io_dev; +unsigned reg; +unsigned char val; +char *cmd; +int ret =0 ; + +if (!argc) +return CMD_RET_USAGE ; + +/* list, dev, dump */ + ret =pmic_cmd (argv, argc,UCLASS_PMIC );drivers/power/cmd_pmic.c line 712
Quoted 10 lines
drivers/power/cmd_pmic.c new file +10
-0+if (ret !=1 ) + goto finish; + + dev =get_curr_dev (UCLASS_PMIC ); + ret =pmic_io_dev (dev, &io_dev); +if (ret) + goto finish; + + cmd = argv[0 ]; +if (strcmp (cmd,"read" ) ==0 ) {Probably not worth a sub-command table here.
Quoted 96 lines
drivers/power/cmd_pmic.c new file +96
-0+if (argc !=2 ) { + ret = -EINVAL ; + goto finish; + } + +printf ("cur dev: %p name: %s\n" , dev, dev->name); + reg =simple_strtoul (argv[1 ],NULL ,0 ); + +printf ("read reg: %#x\n" , reg); + ret =pmic_read (io_dev, reg, &val); +if (ret) +puts ("PMIC: Register read failed\n" ); +else +printf ("0x%02x: 0x%2.2x\n" , reg, val); + + goto finish; + } + +if (strcmp (cmd,"write" ) ==0 ) { +if (argc !=3 ) { + ret = -EINVAL ; + goto finish; + } + + reg =simple_strtoul (argv[1 ],NULL ,0 ); + val =simple_strtoul (argv[2 ],NULL ,0 ); + +printf ("Write reg:%#x val: %#x\n" , reg, val); + + ret =pmic_write (io_dev, reg, val); +if (ret) +puts ("PMIC: Register write failed\n" ); + + goto finish; + } + +finish: +if (ret <0 ) { +printf ("Error: %d\n" , ret); +return CMD_RET_FAILURE ; + } + +return CMD_RET_SUCCESS ; +} +#endif /* CONFIG_DM_PMIC_CMD */ + +static cmd_tbl_t cmd_pmic[] = { +#ifdef CONFIG_DM_PMIC_CMD + U_BOOT_CMD_MKENT(pmic, 5, 1, do_pmic, "", ""), +#endif +#ifdef CONFIG_DM_REGULATOR_CMD + U_BOOT_CMD_MKENT(regulator, 5, 1, do_regulator, "", ""), +#endif +}; + +static int do_pmicops (cmd_tbl_t *cmdtp,int flag,int argc,char *const argv[]) +{ +cmd_tbl_t *cmd; + + cmd =find_cmd_tbl (argv[0 ], cmd_pmic,ARRAY_SIZE (cmd_pmic)); +if (cmd ==NULL || argc > cmd->maxargs) +return CMD_RET_USAGE ; + + argc--; + argv++; + +return cmd->cmd (cmdtp, flag, argc, argv); +} + +#ifdef CONFIG_DM_PMIC_CMD +U_BOOT_CMD (pmic,CONFIG_SYS_MAXARGS ,1 , do_pmicops, +"PMIC" , +"list - list available PMICs\n" +"pmic dev <id> - set id to current pmic device\n" +"pmic dump - dump registers\n" +"pmic read <reg> - read register\n" +"pmic write <reg> <value> - write register\n" +); +#endif /* CONFIG_DM_PMIC_CMD */ +#ifdef CONFIG_DM_REGULATOR_CMD +U_BOOT_CMD (regulator,CONFIG_SYS_MAXARGS ,1 , do_pmicops, +"PMIC Regulator" , +"list\n\t- list UCLASS regulator devices\n" +"regulator dev [id]\n\t- show or set operating regulator device\n" +"regulator dump\n\t- dump registers of current regulator\n" +"regulator [ldo/buck/dvs][N] [name/state/desc]" +"\n\t- print regulator(s) info\n" +"regulator [ldoN/buckN/dvsN] [setval/setmode] [mV/modeN] [-f]" +"\n\t- set val (mV) (forcibly) or mode - only if desc available\n\n" +"Example of usage:\n" +"First get available commands:\n" +" # regulator\n" +"Look after the regulator device 'Id' number:\n" +" # regulator list\n" +"Set the operating device:\n" + " # regulator dev 'Id'\n"drivers/power/cmd_pmic.c line 818
Quoted 10 lines
drivers/power/cmd_pmic.c new file +10
-0+"List state of device ldo's:\n" +" # regulator ldo state\n" +"List descriptors of device ldo's:\n" +" # regulator ldo desc\n" +"Set the voltage of ldo number 1 to 1200mV\n" +" # regulator ldo1 setval 1200\n" +"Use option: '-f', if given value exceeds the limits(be careful!):\n" +" # regulator ldo1 setval 1200 -f\n" +"Set the mode of ldo number 1 to '5' (force not available):\n" +" # regulator ldo1 setmode 5\n" So the regulators in the device have numbers. I presume they also have names by virtue of the device tree?
Quoted 9 lines
Quoted 5 lines
drivers/power/cmd_pmic.c new file +2
-1+); +#endif /* CONFIG_DM_REGULATOR_CMD */ --1.9.1
Regards,
Simon
Thanks for the suggestions. The commands in the V3 are reimplemented into a separated files. The rework of API allowed to make this more clear.
Best regards,
Signature · 4 lines
Przemyslaw Marczak Samsung R&D Institute Poland Samsung Electronics p.marczak at samsung.com
PATCH v2 6/12 dm: pmic: add max77686 pmic driver
In reply to Przemyslaw MarczakThis is the implementation of driver model uclass pmic driver. The max77686 pmic driver implements read/write operations and driver bind method - to bind other pmic uclass devices as a parent pmic device. This driver provides pmic_platdata for also for child regulator.
This driver will try to bind the regulator device with regulator driver. This should succeed if regulator driver is compiled.
If no regulator driver found, then the pmic can still provide read/write operations, and can be used with pmic framework 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
--- drivers/power/pmic/Makefile | 1 + drivers/power/pmic/max77686.c | 102 +++++++++++++++++++++++++++++++++++++ drivers/power/pmic/pmic_max77686.c | 2 +- include/power/max77686_pmic.h | 2 +- 4 files changed, 105 insertions(+), 2 deletions(-) create mode 100644 drivers/power/pmic/max77686.c
drivers/power/pmic/Makefile +1 -0
@@ -10,6 +10,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 +102 -0
102 lines not on this page · raw message
drivers/power/pmic/pmic_max77686.c +1 -1
@@ -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 +1 -1
@@ -122,7 +122,7 @@ enum {MAX77686_REG_PMIC_BBAT =0x7e ,MAX77686_REG_PMIC_32KHZ , - PMIC_NUM_OF_REGS, + MAX77686_NUM_OF_REGS, };/* I2C device address for pmic max77686 */
Signature · 1 line
1.9.1
PATCH v2 7/12 dm: regulator: add max77686 regulator driver
In reply to Przemyslaw MarczakThis commit adds support to max77686 regulator driver based on a uclass regulator driver-model api, which provides implementation of all uclass regulator api function calls.
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
--- Makefile | 1 + drivers/power/Makefile | 1 - drivers/power/regulator/Makefile | 8 + drivers/power/regulator/max77686.c | 926 +++++++++++++++++++++++++++++++++++++ include/power/max77686_pmic.h | 24 +- 5 files changed, 956 insertions(+), 4 deletions(-) create mode 100644 drivers/power/regulator/Makefile create mode 100644 drivers/power/regulator/max77686.c
Makefile +1 -0
@@ -627,6 +627,7 @@ libs-y += drivers/power/ \ drivers/power/fuel_gauge/ \ drivers/power/mfd/ \ drivers/power/pmic/ \ + drivers/power/regulator/ \ drivers/power/battery/ libs-y += drivers/spi/ libs-$(CONFIG_FMAN_ENET) += drivers/net/fm/
drivers/power/Makefile +0 -1
@@ -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/Makefile new file +8 -0
@@ -0,0 +1,8 @@ +# +# Copyright (C) 2014 Samsung Electronics +# Przemyslaw Marczak <[email protected]> +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-$(CONFIG_DM_REGULATOR_MAX77686) += max77686.o
drivers/power/regulator/max77686.c new file +926 -0
926 lines not on this page · raw message
include/power/max77686_pmic.h +21 -3
@@ -126,7 +126,10 @@ enum { };/* 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 +#define MAX77686_DESC_NUM (MAX77686_LDO_NUM + MAX77686_BUCK_NUM)enum {REG_DISABLE =0 ,
@@ -143,23 +146,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
@@ -170,6 +179,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 */
Signature · 1 line
1.9.1
PATCH v2 7/12 dm: regulator: add max77686 regulator driver
Hi Przemyslaw,
Quoted 85 lines · Przemyslaw Marczak
This commit adds support to max77686 regulator driver based on a uclass regulator driver-model api, which provides implementation of all uclass regulator api function calls.
New file:
drivers/power/regulator/max77686.c
New config:CONFIG_DM_REGULATOR_MAX77686Signed-off-by Przemyslaw Marczak <[email protected]>---
Changes V2:
- changedebug()toerror()
- code cleanup
- fix data types
- ldo/buck state implementation
- adjust to new uclass api--- Makefile | 1 + drivers/power/Makefile | 1 - drivers/power/regulator/Makefile | 8 + drivers/power/regulator/max77686.c | 926 +++++++++++++++++++++++++++++++++++++ include/power/max77686_pmic.h | 24 +- 5 files changed, 956 insertions(+), 4 deletions(-) create mode 100644 drivers/power/regulator/Makefile create mode 100644 drivers/power/regulator/max77686.cMakefile +1
-0@@ -627,6 +627,7 @@ libs-y += drivers/power/ \ drivers/power/fuel_gauge/ \ drivers/power/mfd/ \ drivers/power/pmic/ \ + drivers/power/regulator/ \ drivers/power/battery/ libs-y += drivers/spi/ libs-$(CONFIG_FMAN_ENET) += drivers/net/fm/drivers/power/Makefile +0
-1@@ -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.odrivers/power/regulator/Makefile new file +8
-0@@ -0,0 +1,8 @@ +# +# Copyright (C) 2014 Samsung Electronics +# Przemyslaw Marczak <[email protected]> +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-$(CONFIG_DM_REGULATOR_MAX77686) += max77686.odrivers/power/regulator/max77686.c new file +15
-0@@ -0,0 +1,926 @@ +/* +* Copyright (C) 2012-2015 Samsung Electronics +* +* Rajeshwari Shinde <[email protected]> +* Przemyslaw Marczak <[email protected]> +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#include <common.h> +#include <fdtdec.h> +#include <i2c.h> +#include <dm.h> +#include <power/pmic.h> +#include <power/regulator.h>
drivers/power/regulator/max77686.c line 25
Quoted 10 lines
drivers/power/regulator/max77686.c new file +10
-0+#include <power/max77686_pmic.h> +#include <errno.h> +#include <dm.h> + +DECLARE_GLOBAL_DATA_PTR ; + +struct max77686_regulator_info { +int ldo_cnt; +int buck_cnt; +struct regulator_value_desc ldo_desc[MAX77686_LDO_NUM +1 ];
Why +1? Then let's use MAX77686_LDO_COUNT for the number of LDOs.
Quoted 234 lines
drivers/power/regulator/max77686.c new file +234
-0+struct regulator_value_desc buck_desc[MAX77686_BUCK_NUM +1 ]; +}; + +#define MODE (_mode, _val, _name) { \ + .mode = _mode, \ + .register_value = _val, \ + .name = _name, \ +} + +/* LDO: 1,3,4,5,9,17,18,19,20,21,22,23,24,26,26,27 */ +static struct regulator_mode_desc max77686_ldo_mode_standby1[] = { +MODE (OPMODE_OFF ,MAX77686_LDO_MODE_OFF ,"OFF" ), +MODE (OPMODE_LPM ,MAX77686_LDO_MODE_LPM ,"LPM" ), +MODE (OPMODE_STANDBY_LPM ,MAX77686_LDO_MODE_STANDBY_LPM ,"ON/LPM" ), +MODE (OPMODE_ON ,MAX77686_LDO_MODE_ON ,"ON" ), +}; + +/* LDO: 2,6,7,8,10,11,12,14,15,16 */ +static struct regulator_mode_desc max77686_ldo_mode_standby2[] = { +MODE (OPMODE_OFF ,MAX77686_LDO_MODE_OFF ,"OFF" ), +MODE (OPMODE_STANDBY ,MAX77686_LDO_MODE_STANDBY ,"ON/OFF" ), +MODE (OPMODE_STANDBY_LPM ,MAX77686_LDO_MODE_STANDBY_LPM ,"ON/LPM" ), +MODE (OPMODE_ON ,MAX77686_LDO_MODE_ON ,"ON" ), +}; + +/* Buck: 1 */ +static struct regulator_mode_desc max77686_buck_mode_standby[] = { +MODE (OPMODE_OFF ,MAX77686_BUCK_MODE_OFF ,"OFF" ), +MODE (OPMODE_STANDBY ,MAX77686_BUCK_MODE_STANDBY ,"ON/OFF" ), +MODE (OPMODE_ON ,MAX77686_BUCK_MODE_ON ,"ON" ), +}; + +/* Buck: 2,3,4 */ +static struct regulator_mode_desc max77686_buck_mode_lpm[] = { +MODE (OPMODE_OFF ,MAX77686_BUCK_MODE_OFF ,"OFF" ), +MODE (OPMODE_STANDBY ,MAX77686_BUCK_MODE_STANDBY ,"ON/OFF" ), +MODE (OPMODE_LPM ,MAX77686_BUCK_MODE_LPM ,"LPM" ), +MODE (OPMODE_ON ,MAX77686_BUCK_MODE_ON ,"ON" ), +}; + +/* Buck: 5,6,7,8,9 */ +static struct regulator_mode_desc max77686_buck_mode_onoff[] = { +MODE (OPMODE_OFF ,MAX77686_BUCK_MODE_OFF ,"OFF" ), +MODE (OPMODE_ON ,MAX77686_BUCK_MODE_ON ,"ON" ), +}; + +static const char max77686_buck_addr[] = { +0xff ,0x10 ,0x12 ,0x1c ,0x26 ,0x30 ,0x32 ,0x34 ,0x36 ,0x38 +}; + +static int max77686_buck_volt2hex (int buck,int uV) +{ +unsigned int hex =0 ; +unsigned int hex_max =0 ; + +switch (buck) { +case 2 : +case 3 : +case 4 : +/* hex = (uV - 600000) / 12500; */ + hex = (uV -MAX77686_BUCK_UV_LMIN ) /MAX77686_BUCK_UV_LSTEP ; + hex_max =MAX77686_BUCK234_VOLT_MAX_HEX ; +/** +* This uses voltage scaller - temporary not implemented +* so return just 0 +*/ +return 0 ; +default : +/* hex = (uV - 750000) / 50000; */ + hex = (uV -MAX77686_BUCK_UV_HMIN ) /MAX77686_BUCK_UV_HSTEP ; + hex_max =MAX77686_BUCK_VOLT_MAX_HEX ; +break ; + } + +if (hex >=0 && hex <= hex_max) +return hex; + +error ("Value: %d uV is wrong for BUCK%d" , uV, buck); +return -EINVAL ; +} + +static int max77686_buck_hex2volt (int buck,int hex) +{ +unsigned uV =0 ; +unsigned int hex_max =0 ; + +if (hex <0 ) + goto bad_hex; + +switch (buck) { +case 2 : +case 3 : +case 4 : + hex_max =MAX77686_BUCK234_VOLT_MAX_HEX ; +if (hex > hex_max) + goto bad_hex; + +/* uV = hex * 12500 + 600000; */ + uV = hex *MAX77686_BUCK_UV_LSTEP +MAX77686_BUCK_UV_LMIN ; +break ; +default : + hex_max =MAX77686_BUCK_VOLT_MAX_HEX ; +if (hex > hex_max) + goto bad_hex; + +/* uV = hex * 50000 + 750000; */ + uV = hex *MAX77686_BUCK_UV_HSTEP +MAX77686_BUCK_UV_HMIN ; +break ; + } + +return uV; + +bad_hex: +error ("Value: %#x is wrong for BUCK%d" , hex, buck); +return -EINVAL ; +} + +static int max77686_ldo_volt2hex (int ldo,int uV) +{ +unsigned int hex =0 ; + +switch (ldo) { +case 1 : +case 2 : +case 6 : +case 7 : +case 8 : +case 15 : + hex = (uV -MAX77686_LDO_UV_MIN ) /MAX77686_LDO_UV_LSTEP ; +/* hex = (uV - 800000) / 25000; */ +break ; +default : + hex = (uV -MAX77686_LDO_UV_MIN ) /MAX77686_LDO_UV_HSTEP ; +/* hex = (uV - 800000) / 50000; */ + } + +if (hex >=0 && hex <=MAX77686_LDO_VOLT_MAX_HEX ) +return hex; + +error ("Value: %d uV is wrong for LDO%d" , uV, ldo); +return -EINVAL ; +} + +static int max77686_ldo_hex2volt (int ldo,int hex) +{ +unsigned int uV =0 ; + +if (hex >MAX77686_LDO_VOLT_MAX_HEX ) + goto bad_hex; + +switch (ldo) { +case 1 : +case 2 : +case 6 : +case 7 : +case 8 : +case 15 : +/* uV = hex * 25000 + 800000; */ + uV = hex *MAX77686_LDO_UV_LSTEP +MAX77686_LDO_UV_MIN ; +break ; +default : +/* uV = hex * 50000 + 800000; */ + uV = hex *MAX77686_LDO_UV_HSTEP +MAX77686_LDO_UV_MIN ; + } + +return uV; + +bad_hex: +error ("Value: %#x is wrong for ldo%d" , hex, ldo); +return -EINVAL ; +} + +static int max77686_ldo_hex2mode (int ldo,int hex) +{ +if (hex >MAX77686_LDO_MODE_MASK ) +return -EINVAL ; + +switch (hex) { +case MAX77686_LDO_MODE_OFF : +return OPMODE_OFF ; +case MAX77686_LDO_MODE_LPM :/* == MAX77686_LDO_MODE_STANDBY: */ +/* The same mode values but different meaning for each ldo */ +switch (ldo) { +case 2 : +case 6 : +case 7 : +case 8 : +case 10 : +case 11 : +case 12 : +case 14 : +case 15 : +case 16 : +return OPMODE_STANDBY ; +default : +return OPMODE_LPM ; + } +case MAX77686_LDO_MODE_STANDBY_LPM : +return OPMODE_STANDBY_LPM ; +case MAX77686_LDO_MODE_ON : +return OPMODE_ON ; +default : +return -EINVAL ; + } +} + +static int max77686_buck_hex2mode (int buck,int hex) +{ +if (hex >MAX77686_BUCK_MODE_MASK ) +return -EINVAL ; + +switch (hex) { +case MAX77686_BUCK_MODE_OFF : +return OPMODE_OFF ; +case MAX77686_BUCK_MODE_ON : +return OPMODE_ON ; +case MAX77686_BUCK_MODE_STANDBY : +switch (buck) { +case 1 : +case 2 : +case 3 : +case 4 : +return OPMODE_STANDBY ; +default : +return -EINVAL ; + } +case MAX77686_BUCK_MODE_LPM : +switch (buck) { +case 2 : +case 3 : +case 4 : +return OPMODE_LPM ; +default : +return -EINVAL ;
drivers/power/regulator/max77686.c line 269
Quoted 10 lines
drivers/power/regulator/max77686.c new file +10
-0+ } +default : +return -EINVAL ; + } +} + +static int max77686_get_value_desc (struct udevice *dev,int type,int d_num, +struct regulator_value_desc **desc) +{ +struct max77686_regulator_info *dev_info;
Can we just pass struct max77686_regulator_info into this function avoid all this checking? Similar elsewhere it applied.
Quoted 116 lines
drivers/power/regulator/max77686.c new file +116
-0+ +if (!dev) +return -ENODEV ; + +if (!dev->priv) +return -ENXIO ; + + dev_info = dev->priv; + +switch (type) { +case REGULATOR_TYPE_LDO : +if (d_num <1 || d_num >26 ) +return -EINVAL ; + + *desc = &dev_info->ldo_desc[d_num]; +return 0 ; +case REGULATOR_TYPE_BUCK : +if (d_num <1 || d_num >9 ) +return -EINVAL ; + + *desc = &dev_info->buck_desc[d_num]; +return 0 ; +default : +return -EPERM ; + } +} + +static int max77686_get_mode_desc_array (struct udevice *dev,int type, +int d_num,int *d_mode_cnt, +struct regulator_mode_desc **desc) +{ +struct max77686_regulator_info *dev_info; + +if (!dev) +return -ENODEV ; + +if (!dev->priv) +return -ENXIO ; + + dev_info = dev->priv; + *d_mode_cnt =0 ; + +if (type ==REGULATOR_TYPE_LDO ) { +if (d_num <1 || d_num > dev_info->ldo_cnt) +return -EINVAL ; + +switch (d_num) { +case 2 : +case 6 : +case 7 : +case 8 : +case 10 : +case 11 : +case 12 : +case 14 : +case 15 : +case 16 : + *d_mode_cnt =ARRAY_SIZE (max77686_ldo_mode_standby2); + *desc = max77686_ldo_mode_standby2; +return 0 ; +default : + *d_mode_cnt =ARRAY_SIZE (max77686_ldo_mode_standby1); + *desc = max77686_ldo_mode_standby1; +return 0 ; + } + }else if (type ==REGULATOR_TYPE_BUCK ) { +if (d_num <1 || d_num > dev_info->buck_cnt) +return -EINVAL ; + +switch (d_num) { +case 1 : + *d_mode_cnt =ARRAY_SIZE (max77686_buck_mode_standby); + *desc = max77686_buck_mode_standby; +return 0 ; +case 2 : +case 3 : +case 4 : + *d_mode_cnt =ARRAY_SIZE (max77686_buck_mode_lpm); + *desc = max77686_buck_mode_lpm; +return 0 ; +default : + *d_mode_cnt =ARRAY_SIZE (max77686_buck_mode_onoff); + *desc = max77686_buck_mode_onoff; +return 0 ; + } + } + +return -EINVAL ; +} + +static int max77686_ldo_val (struct udevice *dev,int op, +int ldo,int *uV) +{ +unsigned int ret, hex, adr; +unsigned char val; + +if (op ==PMIC_OP_GET ) + *uV =0 ; + +if (ldo <1 || ldo >26 ) { +error ("Wrong ldo number: %d" , ldo); +return -EINVAL ; + } + + adr =MAX77686_REG_PMIC_LDO1CTRL1 + ldo -1 ; + + ret =pmic_read (dev->parent, adr, &val); +if (ret) +return ret; + +if (op ==PMIC_OP_GET ) { + val &=MAX77686_LDO_VOLT_MASK ; + ret =max77686_ldo_hex2volt (ldo, val); +if (ret <0 ) +return ret; + *uV = ret;
drivers/power/regulator/max77686.c line 395
Quoted 10 lines
drivers/power/regulator/max77686.c new file +10
-0+return 0 ; + } + + hex =max77686_ldo_volt2hex (ldo, *uV); +if (hex <0 ) +return -EINVAL ; + + val &= ~MAX77686_LDO_VOLT_MASK ; + val |= hex; + ret |=pmic_write (dev->parent, adr, val);
You should not | error values together as you will get nonsense. Try:
ret = pmic_write()
if (ret)
return ret
or
if (ret)
goto err:
/* more code *.
err:
return ret;
Quoted 314 lines
drivers/power/regulator/max77686.c new file +314
-0+ +return ret; +} + +static int max77686_buck_val (struct udevice *dev,int op, +int buck,int *uV) +{ +unsigned int hex, ret, mask, adr; +unsigned char val; + +if (buck <1 || buck >9 ) { +error ("Wrong buck number: %d" , buck); +return -EINVAL ; + } + +if (op ==PMIC_OP_GET ) + *uV =0 ; + +/* &buck_out = ctrl + 1 */ + adr = max77686_buck_addr[buck] +1 ; + +/* mask */ +switch (buck) { +case 2 : +case 3 : +case 4 : +/* Those uses voltage scallers - will support in the future */ + mask =MAX77686_BUCK234_VOLT_MASK ; +return -EPERM ; +default : + mask =MAX77686_BUCK_VOLT_MASK ; + } + + ret =pmic_read (dev->parent, adr, &val); +if (ret) +return ret; + +if (op ==PMIC_OP_GET ) { + val &= mask; + ret =max77686_buck_hex2volt (buck, val); +if (ret <0 ) +return ret; + *uV = ret; +return 0 ; + } + + hex =max77686_buck_volt2hex (buck, *uV); +if (hex <0 ) +return -EINVAL ; + + val &= ~mask; + val |= hex; + ret =pmic_write (dev->parent, adr, val); + +return ret; +} + +static int max77686_ldo_mode (struct udevice *dev,int op,int ldo,int *opmode) +{ +unsigned int ret, adr, mode; +unsigned char val; + +if (op ==PMIC_OP_GET ) + *opmode = -EINVAL ; + +if (ldo <1 || ldo >26 ) { +error ("Wrong ldo number: %d" , ldo); +return -EINVAL ; + } + + adr =MAX77686_REG_PMIC_LDO1CTRL1 + ldo -1 ; + + ret =pmic_read (dev->parent, adr, &val); +if (ret) +return ret; + +if (op ==PMIC_OP_GET ) { + val &=MAX77686_LDO_MODE_MASK ; + ret =max77686_ldo_hex2mode (ldo, val); +if (ret <0 ) +return ret; + *opmode = ret; +return 0 ; + } + +/* mode */ +switch (*opmode) { +case OPMODE_OFF : + mode =MAX77686_LDO_MODE_OFF ; +break ; +case OPMODE_LPM : +switch (ldo) { +case 2 : +case 6 : +case 7 : +case 8 : +case 10 : +case 11 : +case 12 : +case 14 : +case 15 : +case 16 : +return -EINVAL ; +default : + mode =MAX77686_LDO_MODE_LPM ; + } +break ; +case OPMODE_STANDBY : +switch (ldo) { +case 2 : +case 6 : +case 7 : +case 8 : +case 10 : +case 11 : +case 12 : +case 14 : +case 15 : +case 16 : + mode =MAX77686_LDO_MODE_STANDBY ; +break ; +default : +return -EINVAL ; + } +break ; +case OPMODE_STANDBY_LPM : + mode =MAX77686_LDO_MODE_STANDBY_LPM ; +break ; +case OPMODE_ON : + mode =MAX77686_LDO_MODE_ON ; +break ; +default : + mode =0xff ; + } + +if (mode ==0xff ) { +error ("Wrong mode: %d for ldo%d" , *opmode, ldo); +return -EINVAL ; + } + + val &= ~MAX77686_LDO_MODE_MASK ; + val |= mode; + ret |=pmic_write (dev->parent, adr, val); + +return ret; +} + +static int max77686_ldo_state (struct udevice *dev,int op,int ldo,int *state) +{ +int ret, on_off; + +if (op ==PMIC_OP_GET ) { + ret =max77686_ldo_mode (dev, op, ldo, &on_off); +if (ret) +return ret; + +switch (on_off) { +case OPMODE_OFF : + *state =0 ; +break ; +case OPMODE_ON : + *state =1 ; +break ; +default : +return -EINVAL ; + } + }else if (op ==PMIC_OP_SET ) { +switch (*state) { +case 0 : + on_off =OPMODE_OFF ; +break ; +case 1 : + on_off =OPMODE_ON ; +break ; +default : +return -EINVAL ; + } + + ret =max77686_ldo_mode (dev, op, ldo, &on_off); +if (ret) +return ret; + } + +return 0 ; +} + +static int max77686_buck_mode (struct udevice *dev,int op,int buck, +int *opmode) +{ +unsigned int ret, mask, adr, mode, mode_shift; +unsigned char val; + +if (buck <1 || buck >9 ) { +error ("Wrong buck number: %d" , buck); +return -EINVAL ; + } + + adr = max77686_buck_addr[buck]; + +/* mask */ +switch (buck) { +case 2 : +case 3 : +case 4 : + mode_shift =MAX77686_BUCK_MODE_SHIFT_2 ; +break ; +default : + mode_shift =MAX77686_BUCK_MODE_SHIFT_1 ; + } + + mask =MAX77686_BUCK_MODE_MASK << mode_shift; + + ret =pmic_read (dev->parent, adr, &val); +if (ret) +return ret; + +if (op ==PMIC_OP_GET ) { + val &= mask; + val >>= mode_shift; + ret =max77686_buck_hex2mode (buck, val); +if (ret <0 ) +return ret; + *opmode = ret; +return 0 ; + } + +/* mode */ +switch (*opmode) { +case OPMODE_OFF : + mode =MAX77686_BUCK_MODE_OFF ; +break ; +case OPMODE_STANDBY : +switch (buck) { +case 1 : +case 2 : +case 3 : +case 4 : + mode =MAX77686_BUCK_MODE_STANDBY << mode_shift; +break ; +default : + mode =0xff ; + } +break ; +case OPMODE_LPM : +switch (buck) { +case 2 : +case 3 : +case 4 : + mode =MAX77686_BUCK_MODE_LPM << mode_shift; +break ; +default : + mode =0xff ; + } +break ; +case OPMODE_ON : + mode =MAX77686_BUCK_MODE_ON << mode_shift; +break ; +default : + mode =0xff ; + } + +if (mode ==0xff ) { +error ("Wrong mode:%d for buck%d\n" , *opmode, buck); +return -EINVAL ; + } + + val &= ~mask; + val |= mode; + ret |=pmic_write (dev->parent, adr, val); + +return ret; +} + +static int max77686_buck_state (struct udevice *dev,int op, +int buck,int *state) +{ +int ret, on_off; + +if (op ==PMIC_OP_GET ) { + ret =max77686_buck_mode (dev, op, buck, &on_off); +if (ret) +return ret; + +switch (on_off) { +case OPMODE_OFF : + *state =0 ; +break ; +case OPMODE_ON : + *state =1 ; +break ; +default : +return -EINVAL ; + } + }else if (op ==PMIC_OP_SET ) { +switch (*state) { +case 0 : + on_off =OPMODE_OFF ; +break ; +case 1 : + on_off =OPMODE_ON ; +break ; +default : +return -EINVAL ; + } + + ret =max77686_buck_mode (dev, op, buck, &on_off); +if (ret) +return ret; + } + +return 0 ; +} + +int fill_reg_desc(int offset, struct regulator_value_desc *desc, int reg_num,
drivers/power/regulator/max77686.c line 719
Quoted 10 lines
drivers/power/regulator/max77686.c new file +10
-0+ int desc_type) +{ +const void *blob = gd->fdt_blob; +char *reg_name; +int reg_min, reg_max, len; + + desc->type = desc_type; + desc->number = reg_num; + + reg_name = (char *)fdt_getprop (blob, offset,"regulator-name" , &len);
You can drop the cast.
Quoted 72 lines
drivers/power/regulator/max77686.c new file +72
-0+if (reg_name) { +strncpy (&desc->name[0 ], reg_name,DESC_NAME_LEN ); + desc->name[DESC_NAME_LEN -1 ] ='\0' ; + }else { +sprintf (&desc->name[0 ],"-" ); + } + + reg_min =fdtdec_get_int (blob, offset,"regulator-min-microvolt" ,-1 ); + desc->min_uV = reg_min; + + reg_max =fdtdec_get_int (blob, offset,"regulator-min-microvolt" ,-1 ); + desc->max_uV = reg_max; + +return 0 ; +} + +static int get_desc_for_compat (int regulators_node,char *compat,int desc_type, +struct regulator_value_desc *desc,int desc_num) +{ +const void *blob = gd->fdt_blob; +const char *reg_compat; +int compat_len =strlen (compat); +int reg_num; +int offset; +int cnt =0 ; + +/* First subnode of "voltage_regulators" node */ + offset =fdt_first_subnode (blob, regulators_node); + +while (offset >0 ) { +/* Get regulator properties */ + reg_compat = (char *)fdt_getprop (blob, offset, +"regulator-compatible" ,NULL ); + +/* Check compat and compare the number only */ + reg_num =0 ; +if (strstr (reg_compat, compat)) + reg_num =simple_strtoul (reg_compat + compat_len, +NULL ,0 ); +else + goto next_offset; + +if (reg_num && reg_num <= desc_num) +fill_reg_desc (offset, &desc[reg_num], reg_num, + desc_type); + + cnt++; +if (cnt == desc_num) +return cnt; + +next_offset: + offset =fdt_next_subnode (blob, offset); + } + +return cnt; +} + +static int reg_max77686_ofdata_to_platdata (struct udevice *dev) +{ +struct max77686_regulator_info *dev_info = dev->priv; +const void *blob = gd->fdt_blob; +int node = dev->of_offset; +int offset; + +if (node <0 ) { +error ("Device: %s - bad of_offset" , dev->name); +return 0 ; + } + + offset =fdt_subnode_offset (blob, node,"voltage-regulators" ); +if (offset <0 ) { +error ("Node %s has no 'voltage-regulators' subnode" , dev->name);
drivers/power/regulator/max77686.c line 801
Quoted 10 lines
drivers/power/regulator/max77686.c new file +10
-0+return 0 ; + } + + dev_info->ldo_cnt =get_desc_for_compat (offset,"LDO" ,REGULATOR_TYPE_LDO , + dev_info->ldo_desc, +MAX77686_LDO_NUM ); + + dev_info->buck_cnt =get_desc_for_compat (offset,"BUCK" ,REGULATOR_TYPE_BUCK , + dev_info->buck_desc, +MAX77686_BUCK_NUM );
Do you think these should be child devices?
drivers/power/regulator/max77686.c line 803
Quoted 2 lines
drivers/power/regulator/max77686.c new file +2
-0+ +/* Even if there is no voltage regulators node in dts,
Comment style
Quoted 188 lines
drivers/power/regulator/max77686.c new file +123
-0+* always return success and allow the driver to bind. +* Then we can still do read/write pmic registers. +*/ +return 0 ; + +} + +static int max77686_get_cnt (struct udevice *dev,int type,int *cnt) +{ +switch (type) { +case REGULATOR_TYPE_LDO : + *cnt =MAX77686_LDO_NUM ; +break ; +case REGULATOR_TYPE_BUCK : + *cnt =MAX77686_BUCK_NUM ; +break ; +default : + *cnt =0 ; +return -EPERM ; + } + +return 0 ; +} + + +static int max77686_get_value (struct udevice *dev,int type,int number, +int *value) +{ +switch (type) { +case REGULATOR_TYPE_LDO : +return max77686_ldo_val (dev,PMIC_OP_GET , number, value); +case REGULATOR_TYPE_BUCK : +return max77686_buck_val (dev,PMIC_OP_GET , number, value); +default : +return -EPERM ; + } +} + +static int max77686_set_value (struct udevice *dev,int type,int number, +int value) +{ +switch (type) { +case REGULATOR_TYPE_LDO : +return max77686_ldo_val (dev,PMIC_OP_SET , number, &value); +case REGULATOR_TYPE_BUCK : +return max77686_buck_val (dev,PMIC_OP_SET , number, &value); +default : +return -EPERM ; + } +} + +static int max77686_get_state (struct udevice *dev,int type,int number, +int *state) +{ +switch (type) { +case REGULATOR_TYPE_LDO : +return max77686_ldo_state (dev,PMIC_OP_GET , number, state); +case REGULATOR_TYPE_BUCK : +return max77686_buck_state (dev,PMIC_OP_GET , number, state); +default : + *state =-1 ; +return -EPERM ; + } +} + +static int max77686_set_state (struct udevice *dev,int type,int number, +int state) +{ +switch (type) { +case REGULATOR_TYPE_LDO : +return max77686_ldo_state (dev,PMIC_OP_SET , number, &state); +case REGULATOR_TYPE_BUCK : +return max77686_buck_state (dev,PMIC_OP_SET , number, &state); +default : +return -EPERM ; + } +} + +static int max77686_get_mode (struct udevice *dev,int type,int number, +int *mode) +{ +switch (type) { +case REGULATOR_TYPE_LDO : +return max77686_ldo_mode (dev,PMIC_OP_GET , number, mode); +case REGULATOR_TYPE_BUCK : +return max77686_buck_mode (dev,PMIC_OP_GET , number, mode); +default : +return -EPERM ; + } +} + +static int max77686_set_mode (struct udevice *dev,int type,int number, +int mode) +{ +switch (type) { +case REGULATOR_TYPE_LDO : +return max77686_ldo_mode (dev,PMIC_OP_SET , number, &mode); +case REGULATOR_TYPE_BUCK : +return max77686_buck_mode (dev,PMIC_OP_SET , number, &mode); +default : +return -EPERM ; + } +} + +static const struct dm_regulator_ops reg_max77686_ops = { + .get_cnt = max77686_get_cnt, + .get_value_desc = max77686_get_value_desc, + .get_mode_desc_array = max77686_get_mode_desc_array, + .get_value = max77686_get_value, + .set_value = max77686_set_value, + .get_state = max77686_get_state, + .set_state = max77686_set_state, + .get_mode = max77686_get_mode, + .set_mode = max77686_set_mode, +}; + +U_BOOT_DRIVER (max77686_regulator) = { + .name ="max77686 regulator" , + .id =UCLASS_PMIC_REGULATOR , + .ops = ®_max77686_ops, + .ofdata_to_platdata = reg_max77686_ofdata_to_platdata, + .priv_auto_alloc_size =sizeof (struct max77686_regulator_info ), +};include/power/max77686_pmic.h +21
-4@@ -126,7 +126,10 @@ enum { };/* 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 +#define MAX77686_DESC_NUM (MAX77686_LDO_NUM + MAX77686_BUCK_NUM)enum {REG_DISABLE =0 ,@@ -143,23 +146,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@@ -170,6 +179,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 */ --
Quoted 2 lines
1.9.1
Regards,
Simon
PATCH v2 7/12 dm: regulator: add max77686 regulator driver
Hello Simon,
Quoted 1,094 lines · Simon Glass
Hi Przemyslaw,
Quoted 85 lines · Przemyslaw Marczak
This commit adds support to max77686 regulator driver based on a uclass regulator driver-model api, which provides implementation of all uclass regulator api function calls.
New file:
drivers/power/regulator/max77686.c
New config:CONFIG_DM_REGULATOR_MAX77686Signed-off-by Przemyslaw Marczak <[email protected]>---
Changes V2:
- changedebug()toerror()
- code cleanup
- fix data types
- ldo/buck state implementation
- adjust to new uclass api--- Makefile | 1 + drivers/power/Makefile | 1 - drivers/power/regulator/Makefile | 8 + drivers/power/regulator/max77686.c | 926 +++++++++++++++++++++++++++++++++++++ include/power/max77686_pmic.h | 24 +- 5 files changed, 956 insertions(+), 4 deletions(-)create mode 100644
drivers/power/regulator/Makefilecreate mode 100644drivers/power/regulator/max77686.cMakefile +1
-0@@ -627,6 +627,7 @@ libs-y += drivers/power/ \ drivers/power/fuel_gauge/ \ drivers/power/mfd/ \ drivers/power/pmic/ \ + drivers/power/regulator/ \ drivers/power/battery/ libs-y += drivers/spi/ libs-$(CONFIG_FMAN_ENET) += drivers/net/fm/drivers/power/Makefile +0
-1@@ -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.odrivers/power/regulator/Makefile new file +8
-0@@ -0,0 +1,8 @@ +# +# Copyright (C) 2014 Samsung Electronics +# Przemyslaw Marczak <[email protected]> +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-$(CONFIG_DM_REGULATOR_MAX77686) += max77686.odrivers/power/regulator/max77686.c new file +15
-0@@ -0,0 +1,926 @@ +/* +* Copyright (C) 2012-2015 Samsung Electronics +* +* Rajeshwari Shinde <[email protected]> +* Przemyslaw Marczak <[email protected]> +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#include <common.h> +#include <fdtdec.h> +#include <i2c.h> +#include <dm.h> +#include <power/pmic.h> +#include <power/regulator.h> drivers/power/regulator/max77686.c line 25
Quoted 10 lines
drivers/power/regulator/max77686.c new file +10
-0+#include <power/max77686_pmic.h> +#include <errno.h> +#include <dm.h> + +DECLARE_GLOBAL_DATA_PTR ; + +struct max77686_regulator_info { +int ldo_cnt; +int buck_cnt; +struct regulator_value_desc ldo_desc[MAX77686_LDO_NUM +1 ];Why +1? Then let's use
MAX77686_LDO_COUNTfor the number of LDOs.Quoted 234 lines
drivers/power/regulator/max77686.c new file +234
-0+struct regulator_value_desc buck_desc[MAX77686_BUCK_NUM +1 ]; +}; + +#define MODE (_mode, _val, _name) { \ + .mode = _mode, \ + .register_value = _val, \ + .name = _name, \ +} + +/* LDO: 1,3,4,5,9,17,18,19,20,21,22,23,24,26,26,27 */ +static struct regulator_mode_desc max77686_ldo_mode_standby1[] = { +MODE (OPMODE_OFF ,MAX77686_LDO_MODE_OFF ,"OFF" ), +MODE (OPMODE_LPM ,MAX77686_LDO_MODE_LPM ,"LPM" ), +MODE (OPMODE_STANDBY_LPM ,MAX77686_LDO_MODE_STANDBY_LPM ,"ON/LPM" ), +MODE (OPMODE_ON ,MAX77686_LDO_MODE_ON ,"ON" ), +}; + +/* LDO: 2,6,7,8,10,11,12,14,15,16 */ +static struct regulator_mode_desc max77686_ldo_mode_standby2[] = { +MODE (OPMODE_OFF ,MAX77686_LDO_MODE_OFF ,"OFF" ), +MODE (OPMODE_STANDBY ,MAX77686_LDO_MODE_STANDBY ,"ON/OFF" ), +MODE (OPMODE_STANDBY_LPM ,MAX77686_LDO_MODE_STANDBY_LPM ,"ON/LPM" ), +MODE (OPMODE_ON ,MAX77686_LDO_MODE_ON ,"ON" ), +}; + +/* Buck: 1 */ +static struct regulator_mode_desc max77686_buck_mode_standby[] = { +MODE (OPMODE_OFF ,MAX77686_BUCK_MODE_OFF ,"OFF" ), +MODE (OPMODE_STANDBY ,MAX77686_BUCK_MODE_STANDBY ,"ON/OFF" ), +MODE (OPMODE_ON ,MAX77686_BUCK_MODE_ON ,"ON" ), +}; + +/* Buck: 2,3,4 */ +static struct regulator_mode_desc max77686_buck_mode_lpm[] = { +MODE (OPMODE_OFF ,MAX77686_BUCK_MODE_OFF ,"OFF" ), +MODE (OPMODE_STANDBY ,MAX77686_BUCK_MODE_STANDBY ,"ON/OFF" ), +MODE (OPMODE_LPM ,MAX77686_BUCK_MODE_LPM ,"LPM" ), +MODE (OPMODE_ON ,MAX77686_BUCK_MODE_ON ,"ON" ), +}; + +/* Buck: 5,6,7,8,9 */ +static struct regulator_mode_desc max77686_buck_mode_onoff[] = { +MODE (OPMODE_OFF ,MAX77686_BUCK_MODE_OFF ,"OFF" ), +MODE (OPMODE_ON ,MAX77686_BUCK_MODE_ON ,"ON" ), +}; + +static const char max77686_buck_addr[] = { +0xff ,0x10 ,0x12 ,0x1c ,0x26 ,0x30 ,0x32 ,0x34 ,0x36 ,0x38 +}; + +static int max77686_buck_volt2hex (int buck,int uV) +{ +unsigned int hex =0 ; +unsigned int hex_max =0 ; + +switch (buck) { +case 2 : +case 3 : +case 4 : +/* hex = (uV - 600000) / 12500; */ + hex = (uV -MAX77686_BUCK_UV_LMIN ) /MAX77686_BUCK_UV_LSTEP ; + hex_max =MAX77686_BUCK234_VOLT_MAX_HEX ; +/** +* This uses voltage scaller - temporary not implemented +* so return just 0 +*/ +return 0 ; +default : +/* hex = (uV - 750000) / 50000; */ + hex = (uV -MAX77686_BUCK_UV_HMIN ) /MAX77686_BUCK_UV_HSTEP ; + hex_max =MAX77686_BUCK_VOLT_MAX_HEX ; +break ; + } + +if (hex >=0 && hex <= hex_max) +return hex; + +error ("Value: %d uV is wrong for BUCK%d" , uV, buck); +return -EINVAL ; +} + +static int max77686_buck_hex2volt (int buck,int hex) +{ +unsigned uV =0 ; +unsigned int hex_max =0 ; + +if (hex <0 ) + goto bad_hex; + +switch (buck) { +case 2 : +case 3 : +case 4 : + hex_max =MAX77686_BUCK234_VOLT_MAX_HEX ; +if (hex > hex_max) + goto bad_hex; + +/* uV = hex * 12500 + 600000; */ + uV = hex *MAX77686_BUCK_UV_LSTEP +MAX77686_BUCK_UV_LMIN ; +break ; +default : + hex_max =MAX77686_BUCK_VOLT_MAX_HEX ; +if (hex > hex_max) + goto bad_hex; + +/* uV = hex * 50000 + 750000; */ + uV = hex *MAX77686_BUCK_UV_HSTEP +MAX77686_BUCK_UV_HMIN ; +break ; + } + +return uV; + +bad_hex: +error ("Value: %#x is wrong for BUCK%d" , hex, buck); +return -EINVAL ; +} + +static int max77686_ldo_volt2hex (int ldo,int uV) +{ +unsigned int hex =0 ; + +switch (ldo) { +case 1 : +case 2 : +case 6 : +case 7 : +case 8 : +case 15 : + hex = (uV -MAX77686_LDO_UV_MIN ) /MAX77686_LDO_UV_LSTEP ; +/* hex = (uV - 800000) / 25000; */ +break ; +default : + hex = (uV -MAX77686_LDO_UV_MIN ) /MAX77686_LDO_UV_HSTEP ; +/* hex = (uV - 800000) / 50000; */ + } + +if (hex >=0 && hex <=MAX77686_LDO_VOLT_MAX_HEX ) +return hex; + +error ("Value: %d uV is wrong for LDO%d" , uV, ldo); +return -EINVAL ; +} + +static int max77686_ldo_hex2volt (int ldo,int hex) +{ +unsigned int uV =0 ; + +if (hex >MAX77686_LDO_VOLT_MAX_HEX ) + goto bad_hex; + +switch (ldo) { +case 1 : +case 2 : +case 6 : +case 7 : +case 8 : +case 15 : +/* uV = hex * 25000 + 800000; */ + uV = hex *MAX77686_LDO_UV_LSTEP +MAX77686_LDO_UV_MIN ; +break ; +default : +/* uV = hex * 50000 + 800000; */ + uV = hex *MAX77686_LDO_UV_HSTEP +MAX77686_LDO_UV_MIN ; + } + +return uV; + +bad_hex: +error ("Value: %#x is wrong for ldo%d" , hex, ldo); +return -EINVAL ; +} + +static int max77686_ldo_hex2mode (int ldo,int hex) +{ +if (hex >MAX77686_LDO_MODE_MASK ) +return -EINVAL ; + +switch (hex) { +case MAX77686_LDO_MODE_OFF : +return OPMODE_OFF ; +case MAX77686_LDO_MODE_LPM :/* == MAX77686_LDO_MODE_STANDBY: */ +/* The same mode values but different meaning for each ldo */ +switch (ldo) { +case 2 : +case 6 : +case 7 : +case 8 : +case 10 : +case 11 : +case 12 : +case 14 : +case 15 : +case 16 : +return OPMODE_STANDBY ; +default : +return OPMODE_LPM ; + } +case MAX77686_LDO_MODE_STANDBY_LPM : +return OPMODE_STANDBY_LPM ; +case MAX77686_LDO_MODE_ON : +return OPMODE_ON ; +default : +return -EINVAL ; + } +} + +static int max77686_buck_hex2mode (int buck,int hex) +{ +if (hex >MAX77686_BUCK_MODE_MASK ) +return -EINVAL ; + +switch (hex) { +case MAX77686_BUCK_MODE_OFF : +return OPMODE_OFF ; +case MAX77686_BUCK_MODE_ON : +return OPMODE_ON ; +case MAX77686_BUCK_MODE_STANDBY : +switch (buck) { +case 1 : +case 2 : +case 3 : +case 4 : +return OPMODE_STANDBY ; +default : +return -EINVAL ; + } +case MAX77686_BUCK_MODE_LPM : +switch (buck) { +case 2 : +case 3 : +case 4 : +return OPMODE_LPM ; +default : +return -EINVAL ;drivers/power/regulator/max77686.c line 269
Quoted 10 lines
drivers/power/regulator/max77686.c new file +10
-0+ } +default : +return -EINVAL ; + } +} + +static int max77686_get_value_desc (struct udevice *dev,int type,int d_num, +struct regulator_value_desc **desc) +{ +struct max77686_regulator_info *dev_info;Can we just pass struct
max77686_regulator_infointo this function avoid all this checking? Similar elsewhere it applied.Quoted 116 lines
drivers/power/regulator/max77686.c new file +116
-0+ +if (!dev) +return -ENODEV ; + +if (!dev->priv) +return -ENXIO ; + + dev_info = dev->priv; + +switch (type) { +case REGULATOR_TYPE_LDO : +if (d_num <1 || d_num >26 ) +return -EINVAL ; + + *desc = &dev_info->ldo_desc[d_num]; +return 0 ; +case REGULATOR_TYPE_BUCK : +if (d_num <1 || d_num >9 ) +return -EINVAL ; + + *desc = &dev_info->buck_desc[d_num]; +return 0 ; +default : +return -EPERM ; + } +} + +static int max77686_get_mode_desc_array (struct udevice *dev,int type, +int d_num,int *d_mode_cnt, +struct regulator_mode_desc **desc) +{ +struct max77686_regulator_info *dev_info; + +if (!dev) +return -ENODEV ; + +if (!dev->priv) +return -ENXIO ; + + dev_info = dev->priv; + *d_mode_cnt =0 ; + +if (type ==REGULATOR_TYPE_LDO ) { +if (d_num <1 || d_num > dev_info->ldo_cnt) +return -EINVAL ; + +switch (d_num) { +case 2 : +case 6 : +case 7 : +case 8 : +case 10 : +case 11 : +case 12 : +case 14 : +case 15 : +case 16 : + *d_mode_cnt =ARRAY_SIZE (max77686_ldo_mode_standby2); + *desc = max77686_ldo_mode_standby2; +return 0 ; +default : + *d_mode_cnt =ARRAY_SIZE (max77686_ldo_mode_standby1); + *desc = max77686_ldo_mode_standby1; +return 0 ; + } + }else if (type ==REGULATOR_TYPE_BUCK ) { +if (d_num <1 || d_num > dev_info->buck_cnt) +return -EINVAL ; + +switch (d_num) { +case 1 : + *d_mode_cnt =ARRAY_SIZE (max77686_buck_mode_standby); + *desc = max77686_buck_mode_standby; +return 0 ; +case 2 : +case 3 : +case 4 : + *d_mode_cnt =ARRAY_SIZE (max77686_buck_mode_lpm); + *desc = max77686_buck_mode_lpm; +return 0 ; +default : + *d_mode_cnt =ARRAY_SIZE (max77686_buck_mode_onoff); + *desc = max77686_buck_mode_onoff; +return 0 ; + } + } + +return -EINVAL ; +} + +static int max77686_ldo_val (struct udevice *dev,int op, +int ldo,int *uV) +{ +unsigned int ret, hex, adr; +unsigned char val; + +if (op ==PMIC_OP_GET ) + *uV =0 ; + +if (ldo <1 || ldo >26 ) { +error ("Wrong ldo number: %d" , ldo); +return -EINVAL ; + } + + adr =MAX77686_REG_PMIC_LDO1CTRL1 + ldo -1 ; + + ret =pmic_read (dev->parent, adr, &val); +if (ret) +return ret; + +if (op ==PMIC_OP_GET ) { + val &=MAX77686_LDO_VOLT_MASK ; + ret =max77686_ldo_hex2volt (ldo, val); +if (ret <0 ) +return ret; + *uV = ret;drivers/power/regulator/max77686.c line 395
Quoted 10 lines
drivers/power/regulator/max77686.c new file +10
-0+return 0 ; + } + + hex =max77686_ldo_volt2hex (ldo, *uV); +if (hex <0 ) +return -EINVAL ; + + val &= ~MAX77686_LDO_VOLT_MASK ; + val |= hex; + ret |=pmic_write (dev->parent, adr, val);You should not | error values together as you will get nonsense. Try:
ret =
pmic_write()
if (ret)
return retor
if (ret)
goto err:/* more code *.
err:
return ret;Quoted 314 lines
drivers/power/regulator/max77686.c new file +314
-0+ +return ret; +} + +static int max77686_buck_val (struct udevice *dev,int op, +int buck,int *uV) +{ +unsigned int hex, ret, mask, adr; +unsigned char val; + +if (buck <1 || buck >9 ) { +error ("Wrong buck number: %d" , buck); +return -EINVAL ; + } + +if (op ==PMIC_OP_GET ) + *uV =0 ; + +/* &buck_out = ctrl + 1 */ + adr = max77686_buck_addr[buck] +1 ; + +/* mask */ +switch (buck) { +case 2 : +case 3 : +case 4 : +/* Those uses voltage scallers - will support in the future */ + mask =MAX77686_BUCK234_VOLT_MASK ; +return -EPERM ; +default : + mask =MAX77686_BUCK_VOLT_MASK ; + } + + ret =pmic_read (dev->parent, adr, &val); +if (ret) +return ret; + +if (op ==PMIC_OP_GET ) { + val &= mask; + ret =max77686_buck_hex2volt (buck, val); +if (ret <0 ) +return ret; + *uV = ret; +return 0 ; + } + + hex =max77686_buck_volt2hex (buck, *uV); +if (hex <0 ) +return -EINVAL ; + + val &= ~mask; + val |= hex; + ret =pmic_write (dev->parent, adr, val); + +return ret; +} + +static int max77686_ldo_mode (struct udevice *dev,int op,int ldo,int *opmode) +{ +unsigned int ret, adr, mode; +unsigned char val; + +if (op ==PMIC_OP_GET ) + *opmode = -EINVAL ; + +if (ldo <1 || ldo >26 ) { +error ("Wrong ldo number: %d" , ldo); +return -EINVAL ; + } + + adr =MAX77686_REG_PMIC_LDO1CTRL1 + ldo -1 ; + + ret =pmic_read (dev->parent, adr, &val); +if (ret) +return ret; + +if (op ==PMIC_OP_GET ) { + val &=MAX77686_LDO_MODE_MASK ; + ret =max77686_ldo_hex2mode (ldo, val); +if (ret <0 ) +return ret; + *opmode = ret; +return 0 ; + } + +/* mode */ +switch (*opmode) { +case OPMODE_OFF : + mode =MAX77686_LDO_MODE_OFF ; +break ; +case OPMODE_LPM : +switch (ldo) { +case 2 : +case 6 : +case 7 : +case 8 : +case 10 : +case 11 : +case 12 : +case 14 : +case 15 : +case 16 : +return -EINVAL ; +default : + mode =MAX77686_LDO_MODE_LPM ; + } +break ; +case OPMODE_STANDBY : +switch (ldo) { +case 2 : +case 6 : +case 7 : +case 8 : +case 10 : +case 11 : +case 12 : +case 14 : +case 15 : +case 16 : + mode =MAX77686_LDO_MODE_STANDBY ; +break ; +default : +return -EINVAL ; + } +break ; +case OPMODE_STANDBY_LPM : + mode =MAX77686_LDO_MODE_STANDBY_LPM ; +break ; +case OPMODE_ON : + mode =MAX77686_LDO_MODE_ON ; +break ; +default : + mode =0xff ; + } + +if (mode ==0xff ) { +error ("Wrong mode: %d for ldo%d" , *opmode, ldo); +return -EINVAL ; + } + + val &= ~MAX77686_LDO_MODE_MASK ; + val |= mode; + ret |=pmic_write (dev->parent, adr, val); + +return ret; +} + +static int max77686_ldo_state (struct udevice *dev,int op,int ldo,int *state) +{ +int ret, on_off; + +if (op ==PMIC_OP_GET ) { + ret =max77686_ldo_mode (dev, op, ldo, &on_off); +if (ret) +return ret; + +switch (on_off) { +case OPMODE_OFF : + *state =0 ; +break ; +case OPMODE_ON : + *state =1 ; +break ; +default : +return -EINVAL ; + } + }else if (op ==PMIC_OP_SET ) { +switch (*state) { +case 0 : + on_off =OPMODE_OFF ; +break ; +case 1 : + on_off =OPMODE_ON ; +break ; +default : +return -EINVAL ; + } + + ret =max77686_ldo_mode (dev, op, ldo, &on_off); +if (ret) +return ret; + } + +return 0 ; +} + +static int max77686_buck_mode (struct udevice *dev,int op,int buck, +int *opmode) +{ +unsigned int ret, mask, adr, mode, mode_shift; +unsigned char val; + +if (buck <1 || buck >9 ) { +error ("Wrong buck number: %d" , buck); +return -EINVAL ; + } + + adr = max77686_buck_addr[buck]; + +/* mask */ +switch (buck) { +case 2 : +case 3 : +case 4 : + mode_shift =MAX77686_BUCK_MODE_SHIFT_2 ; +break ; +default : + mode_shift =MAX77686_BUCK_MODE_SHIFT_1 ; + } + + mask =MAX77686_BUCK_MODE_MASK << mode_shift; + + ret =pmic_read (dev->parent, adr, &val); +if (ret) +return ret; + +if (op ==PMIC_OP_GET ) { + val &= mask; + val >>= mode_shift; + ret =max77686_buck_hex2mode (buck, val); +if (ret <0 ) +return ret; + *opmode = ret; +return 0 ; + } + +/* mode */ +switch (*opmode) { +case OPMODE_OFF : + mode =MAX77686_BUCK_MODE_OFF ; +break ; +case OPMODE_STANDBY : +switch (buck) { +case 1 : +case 2 : +case 3 : +case 4 : + mode =MAX77686_BUCK_MODE_STANDBY << mode_shift; +break ; +default : + mode =0xff ; + } +break ; +case OPMODE_LPM : +switch (buck) { +case 2 : +case 3 : +case 4 : + mode =MAX77686_BUCK_MODE_LPM << mode_shift; +break ; +default : + mode =0xff ; + } +break ; +case OPMODE_ON : + mode =MAX77686_BUCK_MODE_ON << mode_shift; +break ; +default : + mode =0xff ; + } + +if (mode ==0xff ) { +error ("Wrong mode:%d for buck%d\n" , *opmode, buck); +return -EINVAL ; + } + + val &= ~mask; + val |= mode; + ret |=pmic_write (dev->parent, adr, val); + +return ret; +} + +static int max77686_buck_state (struct udevice *dev,int op, +int buck,int *state) +{ +int ret, on_off; + +if (op ==PMIC_OP_GET ) { + ret =max77686_buck_mode (dev, op, buck, &on_off); +if (ret) +return ret; + +switch (on_off) { +case OPMODE_OFF : + *state =0 ; +break ; +case OPMODE_ON : + *state =1 ; +break ; +default : +return -EINVAL ; + } + }else if (op ==PMIC_OP_SET ) { +switch (*state) { +case 0 : + on_off =OPMODE_OFF ; +break ; +case 1 : + on_off =OPMODE_ON ; +break ; +default : +return -EINVAL ; + } + + ret =max77686_buck_mode (dev, op, buck, &on_off); +if (ret) +return ret; + } + +return 0 ; +} + +int fill_reg_desc(int offset, struct regulator_value_desc *desc, int reg_num,drivers/power/regulator/max77686.c line 719
Quoted 10 lines
drivers/power/regulator/max77686.c new file +10
-0+ int desc_type) +{ +const void *blob = gd->fdt_blob; +char *reg_name; +int reg_min, reg_max, len; + + desc->type = desc_type; + desc->number = reg_num; + + reg_name = (char *)fdt_getprop (blob, offset,"regulator-name" , &len);You can drop the cast.
Quoted 72 lines
drivers/power/regulator/max77686.c new file +72
-0+if (reg_name) { +strncpy (&desc->name[0 ], reg_name,DESC_NAME_LEN ); + desc->name[DESC_NAME_LEN -1 ] ='\0' ; + }else { +sprintf (&desc->name[0 ],"-" ); + } + + reg_min =fdtdec_get_int (blob, offset,"regulator-min-microvolt" ,-1 ); + desc->min_uV = reg_min; + + reg_max =fdtdec_get_int (blob, offset,"regulator-min-microvolt" ,-1 ); + desc->max_uV = reg_max; + +return 0 ; +} + +static int get_desc_for_compat (int regulators_node,char *compat,int desc_type, +struct regulator_value_desc *desc,int desc_num) +{ +const void *blob = gd->fdt_blob; +const char *reg_compat; +int compat_len =strlen (compat); +int reg_num; +int offset; +int cnt =0 ; + +/* First subnode of "voltage_regulators" node */ + offset =fdt_first_subnode (blob, regulators_node); + +while (offset >0 ) { +/* Get regulator properties */ + reg_compat = (char *)fdt_getprop (blob, offset, +"regulator-compatible" ,NULL ); + +/* Check compat and compare the number only */ + reg_num =0 ; +if (strstr (reg_compat, compat)) + reg_num =simple_strtoul (reg_compat + compat_len, +NULL ,0 ); +else + goto next_offset; + +if (reg_num && reg_num <= desc_num) +fill_reg_desc (offset, &desc[reg_num], reg_num, + desc_type); + + cnt++; +if (cnt == desc_num) +return cnt; + +next_offset: + offset =fdt_next_subnode (blob, offset); + } + +return cnt; +} + +static int reg_max77686_ofdata_to_platdata (struct udevice *dev) +{ +struct max77686_regulator_info *dev_info = dev->priv; +const void *blob = gd->fdt_blob; +int node = dev->of_offset; +int offset; + +if (node <0 ) { +error ("Device: %s - bad of_offset" , dev->name); +return 0 ; + } + + offset =fdt_subnode_offset (blob, node,"voltage-regulators" ); +if (offset <0 ) { +error ("Node %s has no 'voltage-regulators' subnode" , dev->name);drivers/power/regulator/max77686.c line 801
Quoted 10 lines
drivers/power/regulator/max77686.c new file +10
-0+return 0 ; + } + + dev_info->ldo_cnt =get_desc_for_compat (offset,"LDO" ,REGULATOR_TYPE_LDO , + dev_info->ldo_desc, +MAX77686_LDO_NUM ); + + dev_info->buck_cnt =get_desc_for_compat (offset,"BUCK" ,REGULATOR_TYPE_BUCK , + dev_info->buck_desc, +MAX77686_BUCK_NUM );Do you think these should be child devices?
drivers/power/regulator/max77686.c line 803
Quoted 2 lines
drivers/power/regulator/max77686.c new file +2
-0+ +/* Even if there is no voltage regulators node in dts, Comment style
Quoted 185 lines
drivers/power/regulator/max77686.c new file +123
-0+* always return success and allow the driver to bind. +* Then we can still do read/write pmic registers. +*/ +return 0 ; + +} + +static int max77686_get_cnt (struct udevice *dev,int type,int *cnt) +{ +switch (type) { +case REGULATOR_TYPE_LDO : + *cnt =MAX77686_LDO_NUM ; +break ; +case REGULATOR_TYPE_BUCK : + *cnt =MAX77686_BUCK_NUM ; +break ; +default : + *cnt =0 ; +return -EPERM ; + } + +return 0 ; +} + + +static int max77686_get_value (struct udevice *dev,int type,int number, +int *value) +{ +switch (type) { +case REGULATOR_TYPE_LDO : +return max77686_ldo_val (dev,PMIC_OP_GET , number, value); +case REGULATOR_TYPE_BUCK : +return max77686_buck_val (dev,PMIC_OP_GET , number, value); +default : +return -EPERM ; + } +} + +static int max77686_set_value (struct udevice *dev,int type,int number, +int value) +{ +switch (type) { +case REGULATOR_TYPE_LDO : +return max77686_ldo_val (dev,PMIC_OP_SET , number, &value); +case REGULATOR_TYPE_BUCK : +return max77686_buck_val (dev,PMIC_OP_SET , number, &value); +default : +return -EPERM ; + } +} + +static int max77686_get_state (struct udevice *dev,int type,int number, +int *state) +{ +switch (type) { +case REGULATOR_TYPE_LDO : +return max77686_ldo_state (dev,PMIC_OP_GET , number, state); +case REGULATOR_TYPE_BUCK : +return max77686_buck_state (dev,PMIC_OP_GET , number, state); +default : + *state =-1 ; +return -EPERM ; + } +} + +static int max77686_set_state (struct udevice *dev,int type,int number, +int state) +{ +switch (type) { +case REGULATOR_TYPE_LDO : +return max77686_ldo_state (dev,PMIC_OP_SET , number, &state); +case REGULATOR_TYPE_BUCK : +return max77686_buck_state (dev,PMIC_OP_SET , number, &state); +default : +return -EPERM ; + } +} + +static int max77686_get_mode (struct udevice *dev,int type,int number, +int *mode) +{ +switch (type) { +case REGULATOR_TYPE_LDO : +return max77686_ldo_mode (dev,PMIC_OP_GET , number, mode); +case REGULATOR_TYPE_BUCK : +return max77686_buck_mode (dev,PMIC_OP_GET , number, mode); +default : +return -EPERM ; + } +} + +static int max77686_set_mode (struct udevice *dev,int type,int number, +int mode) +{ +switch (type) { +case REGULATOR_TYPE_LDO : +return max77686_ldo_mode (dev,PMIC_OP_SET , number, &mode); +case REGULATOR_TYPE_BUCK : +return max77686_buck_mode (dev,PMIC_OP_SET , number, &mode); +default : +return -EPERM ; + } +} + +static const struct dm_regulator_ops reg_max77686_ops = { + .get_cnt = max77686_get_cnt, + .get_value_desc = max77686_get_value_desc, + .get_mode_desc_array = max77686_get_mode_desc_array, + .get_value = max77686_get_value, + .set_value = max77686_set_value, + .get_state = max77686_get_state, + .set_state = max77686_set_state, + .get_mode = max77686_get_mode, + .set_mode = max77686_set_mode, +}; + +U_BOOT_DRIVER (max77686_regulator) = { + .name ="max77686 regulator" , + .id =UCLASS_PMIC_REGULATOR , + .ops = ®_max77686_ops, + .ofdata_to_platdata = reg_max77686_ofdata_to_platdata, + .priv_auto_alloc_size =sizeof (struct max77686_regulator_info ), +};include/power/max77686_pmic.h +21
-3@@ -126,7 +126,10 @@ enum { };/* 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 +#define MAX77686_DESC_NUM (MAX77686_LDO_NUM + MAX77686_BUCK_NUM)enum {REG_DISABLE =0 ,@@ -143,23 +146,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@@ -170,6 +179,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 */
Quoted 9 lines
Quoted 5 lines
include/power/max77686_pmic.h +0
-1#define MAX77686_BUCK1OUT_1V 0x5/* Buck1 1.05 volt value */ --1.9.1
Regards,
Simon
After the rework in the V3, the binding is done by each regulator compatible, so now each ldo and each buck are independent childs. And the regulator file implements two drivers(ldo and buck). Thanks for the suggestions!
Best regards,
Signature · 4 lines
Przemyslaw Marczak Samsung R&D Institute Poland Samsung Electronics p.marczak at samsung.com
PATCH v2 8/12 doc: driver-model: pmic and regulator uclass documentation
In reply to Przemyslaw Marczak---
Changes v2:
- update documentation with the framework api changes
--- doc/driver-model/dm-pmic-framework.txt | 367 +++++++++++++++++++++++++++++++++ 1 file changed, 367 insertions(+) create mode 100644 doc/driver-model/dm-pmic-framework.txt
doc/driver-model/dm-pmic-framework.txt new file +367 -0
@@ -0,0 +1,367 @@ +# +# (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. Design limitations +8. Regulator driver +9. 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_PMIC_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_PMIC_REGULATOR: +- drivers/power/regulator-uclass.c +- include/power/regulator.h + +Commands: +- drivers/power/cmd_pmic.c (pmic; regulator) + +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 + . + +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, +for devices other uclass types. It is no matter what is the type of device +physical I/O interface. Usually PMIC devices are using SPI or I2C interface, +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, +this uclass can be implemented. This allows to drive the each regulator output +value, on/off state and custom defined operation modes. It also provides the +user interface for all operations. +For the very simple implementation, the regulator drivers are not required, +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' + +3.1 Getting the device: +- By name only - usefull if the name is unique, or only one pmic device exists: + int pmic_get(char *name, struct udevice **pmic); + +- By I2C or SPI bus number and chip address - when few pmic devices exists: + int pmic_i2c_get(int bus, int addr, struct udevice **pmic) + int pmic_spi_get(int bus, int cs, struct udevice **pmic); + +- To get the given PMIC/REGULATOR I/O dev by pmic platdata: + int pmic_io_dev(struct udevice *pmic, struct udevice **pmic_io); + +3.2 Pmic platdata function calls - useful for pmic/regulator commands: +- Get the device interface type: + int pmic_if_type(struct udevice *pmic); + +- Get the device interface bus number: + int pmic_if_bus_num(struct udevice *pmic); + +- Get the device addres(I2C) or cs(SPI) on bus: + int pmic_if_addr_cs(struct udevice *pmic); + +- Get the device max internal address offset: + int pmic_if_max_offset(struct udevice *pmic); + +- Get the device interface name string: + const char *pmic_if_str(struct udevice *pmic); + +3.3. Device I/O interface +Can be used with UCLASS_PMIC devices: +- Read the device 'reg': + int pmic_read(struct udevice *pmic, unsigned reg, unsigned char *val); + +- Write to the device 'reg': + int pmic_write(struct udevice *pmic, unsigned reg, unsigned char val); + +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. +To make the device useful with the pmic command, the driver must define +the size of platform data allocation size. + +Driver ops: +.read = max77686_read() - allows to use pmic_read() +.write = max77686_write() - allows to use pmic_write() + +Driver bind: +- max77686_bind(): is called on device bind and: + - fills the platform data structure + - bind MAX77686 regulator child device + +Note: +For the simply case, when regulator driver doesn't exists, the driver bind +method should only fill the platform data structure. + +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 + +The pmic platform data is mandatory to use this command with devices. +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 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. +The same as for the pmic devices, regulator drivers should alloc platform data. +It's the same type as for uclass pmic drivers: 'struct pmic_platdata', and can +be shared with the parent pmic device. + +The api is described in file: 'include/power/regulator.h' + +6.1 Getting the device: +- By name - usefull for unique names, or if only one regulator device exists: + int regulator_get(char *name, struct udevice **regulator); + +- By I2C or SPI bus number and chip address of pmic parent - when few regulator + devices exists: + int regulator_i2c_get(int bus, int addr, struct udevice **regulator); + int regulator_spi_get(int bus, int cs, struct udevice **regulator); + +6.2 Pmic platdata function calls - useful for pmic/regulator commands +It's the same as for Point 3.2. + +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_val); +- pmic_write(regulator->parent, some_reg, &some_val); + +6.4 Device regulator operations +The regulator function calls are based on few data types: +- enum regulator_type {...} - standard types: LDO, BUCK and DVS +- enum regulator_out_state {...} - ON/OFF states +- struct regulator_value_desc {...} - output name and value limits +- struct regulator_mode_desc {...} - 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_PMIC_REGULATOR' + +Function details are described in regulator header. The basic features are: +- Get the number of the given regulator type outputs + int regulator_get_cnt(struct udevice *dev, int type, int *cnt); + +- Get the given output value descriptor + int regulator_get_value_desc(struct udevice *dev, int type, int number, + struct regulator_value_desc **desc); + +- Get the given output mode descriptor array (usually more then one mode) + int regulator_get_mode_desc(struct udevice *dev, int type, int number, + int *mode_cnt, struct regulator_mode_desc **desc); + +- Get or set the given output voltage value (micro Volts unit) + int regulator_get_value(struct udevice *dev, int type, int number, int *val); + int regulator_set_value(struct udevice *dev, int type, int number, int val); + +- Get or set the given output on/off state + int regulator_get_state(struct udevice *dev, int type, int number, int *state); + int regulator_set_state(struct udevice *dev, int type, int number, int state); + +- Get or set the given output operation mode (mode defined by the driver) + int regulator_get_mode(struct udevice *dev, int type, int number, int *mode); + int regulator_set_mode(struct udevice *dev, int type, int number, int mode); + +7. Design limitations: +The child devices of the single parent device (pmic, interface), should not +provide it's features by more then one device each uclass types. +It's because, e.g. regulator_i2c_get() function will: +- look for the pmic device at address given by args, +- return it's first child device, which uclass type is 'UCLASS_PMIC_REGULATOR' +So, if more then one pmic child device exists, each the same uclass type, then +the regulator_i2c_get(), will return only first device. But usually there is no +need to implement the same functionality with more than one instance of each +uclass type device. + +8. Regulator driver +====================================== +As an example of the regulator driver, please take a look into the MAX77686 +regulator driver (drivers/power/regulator/max77686.c). The driver structure: + +U_BOOT_DRIVER(max77686_regulator) = { + .name = "max77686 regulator", + .id = UCLASS_PMIC_REGULATOR, + .ops = ®_max77686_ops, + .ofdata_to_platdata = reg_max77686_ofdata_to_platdata, + .priv_auto_alloc_size = sizeof(struct max77686_regulator_info), +}; + +This driver structure is different than for the pmic driver. + +It doesn't provide: +.of_match +.platdata_auto_alloc_size + +Both are not required in this case, because .of_match is known at the bind call, +and the platdata pointer is the same as for the parent device (pmic). + +But instead of the pmic driver, this driver provides: +.of_data_to_platdata + +And this call above is responsible for fill the regulator outputs descriptors, +which are described in device-tree, e.g. 'arch/arm/dts/exynos4412-odroid.dts' + +The bind for this driver is called in pmic/max77686.c driver bind. +After the pmic driver successful bind, there are two max77686 devices: +- max77686 pmic (parent) - UCLASS_PMIC + '- max77686 regulator (child) - UCLASS_PMIC_REGULATOR + +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); + +9. Regulator command +==================== +To use the pmic command, config: CONFIG_DM_REGULATOR_CMD is required. + +The extension for the 'pmic' command is 'regulator' command. +This actually uses the same code, but provides the interface +to pmic optional 'UCLASS_PMIC_REGULATOR' operations. + +If pmic device driver provides support to this another pmic +uclass, then this command provides useful user interface. + +This was designed to allow safe I/O access to the pmic device, +without the pmic documentation. If driver provide each regulator +output - value and mode descriptor - then user can operate on it. + +Usage: +regulator list - list UCLASS regulator devices +regulator dev [id] - show or set operating regulator device +regulator dump - dump registers of current regulator +regulator [ldo/buck/dvs][N] [name/state/desc] - print regulator(s) info +regulator [ldoN/buckN/dvsN] [setval/setmode] [mV/modeN] [-f] - set val (mV) + +The -f option (forcibly) or mode - only if descriptor is available + +Example of usage: +regulator list - look after regulator 'Id' number +regulator dev 'Id' - set current device +regulator ldo state - list state of current device all ldo's +regulator ldo desc - list ldo's descriptors +regulator ldo1 setval 1000 - set device ldo 1 voltage to 1000mV +regulator ldo1 setval 1200 -f - if value exceeds limits - set force +regulator ldo1 setmode 5 - set device ldo 1 mode to '5' + +The same for 'buck' regulators. + +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.
Signature · 1 line
1.9.1
PATCH v2 8/12 doc: driver-model: pmic and regulator uclass documentation
Hi,
Quoted 383 lines · Przemyslaw Marczak
Signed-off-by Przemyslaw Marczak <[email protected]>---
Changes v2:
- update documentation with the framework api changes--- doc/driver-model/dm-pmic-framework.txt | 367 +++++++++++++++++++++++++++++++++ 1 file changed, 367 insertions(+) create mode 100644 doc/driver-model/dm-pmic-framework.txtdoc/driver-model/dm-pmic-framework.txt new file +367
-1@@ -0,0 +1,367 @@ +# +# (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. Design limitations +8. Regulator driver +9. 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_PMIC_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_PMIC_REGULATOR: +- drivers/power/regulator-uclass.c +- include/power/regulator.h + +Commands: +- drivers/power/cmd_pmic.c (pmic; regulator) + +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 + . + +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, +for devices other uclass types. It is no matter what is the type of device +physical I/O interface. Usually PMIC devices are using SPI or I2C interface, +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, +this uclass can be implemented. This allows to drive the each regulator output +value, on/off state and custom defined operation modes. It also provides the +user interface for all operations. +For the very simple implementation, the regulator drivers are not required, +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' + +3.1 Getting the device: +- By name only - usefull if the name is unique, or only one pmic device exists: + int pmic_get(char *name, struct udevice **pmic); + +- By I2C or SPI bus number and chip address - when few pmic devices exists: + int pmic_i2c_get(int bus, int addr, struct udevice **pmic) + int pmic_spi_get(int bus, int cs, struct udevice **pmic); + +- To get the given PMIC/REGULATOR I/O dev by pmic platdata: + int pmic_io_dev(struct udevice *pmic, struct udevice **pmic_io); + +3.2 Pmic platdata function calls - useful for pmic/regulator commands: +- Get the device interface type: + int pmic_if_type(struct udevice *pmic); + +- Get the device interface bus number: + int pmic_if_bus_num(struct udevice *pmic); + +- Get the device addres(I2C) or cs(SPI) on bus: + int pmic_if_addr_cs(struct udevice *pmic); + +- Get the device max internal address offset: + int pmic_if_max_offset(struct udevice *pmic); + +- Get the device interface name string: + const char *pmic_if_str(struct udevice *pmic); + +3.3. Device I/O interface +Can be used with UCLASS_PMIC devices: +- Read the device 'reg': + int pmic_read(struct udevice *pmic, unsigned reg, unsigned char *val); + +- Write to the device 'reg': + int pmic_write(struct udevice *pmic, unsigned reg, unsigned char val); + +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. +To make the device useful with the pmic command, the driver must define +the size of platform data allocation size. + +Driver ops: +.read = max77686_read() - allows to use pmic_read() +.write = max77686_write() - allows to use pmic_write() + +Driver bind: +- max77686_bind(): is called on device bind and: + - fills the platform data structure + - bind MAX77686 regulator child device + +Note: +For the simply case, when regulator driver doesn't exists, the driver bind +method should only fill the platform data structure. + +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 + +The pmic platform data is mandatory to use this command with devices. +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 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. +The same as for the pmic devices, regulator drivers should alloc platform data. +It's the same type as for uclass pmic drivers: 'struct pmic_platdata', and can +be shared with the parent pmic device. + +The api is described in file: 'include/power/regulator.h' + +6.1 Getting the device: +- By name - usefull for unique names, or if only one regulator device exists: + int regulator_get(char *name, struct udevice **regulator); + +- By I2C or SPI bus number and chip address of pmic parent - when few regulator + devices exists: + int regulator_i2c_get(int bus, int addr, struct udevice **regulator); + int regulator_spi_get(int bus, int cs, struct udevice **regulator); + +6.2 Pmic platdata function calls - useful for pmic/regulator commands +It's the same as for Point 3.2. + +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_val); +- pmic_write(regulator->parent, some_reg, &some_val); + +6.4 Device regulator operations +The regulator function calls are based on few data types: +- enum regulator_type {...} - standard types: LDO, BUCK and DVS +- enum regulator_out_state {...} - ON/OFF states +- struct regulator_value_desc {...} - output name and value limits +- struct regulator_mode_desc {...} - 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_PMIC_REGULATOR' + +Function details are described in regulator header. The basic features are: +- Get the number of the given regulator type outputs + int regulator_get_cnt(struct udevice *dev, int type, int *cnt); + +- Get the given output value descriptor + int regulator_get_value_desc(struct udevice *dev, int type, int number, + struct regulator_value_desc **desc); + +- Get the given output mode descriptor array (usually more then one mode) + int regulator_get_mode_desc(struct udevice *dev, int type, int number, + int *mode_cnt, struct regulator_mode_desc **desc); + +- Get or set the given output voltage value (micro Volts unit) + int regulator_get_value(struct udevice *dev, int type, int number, int *val); + int regulator_set_value(struct udevice *dev, int type, int number, int val); + +- Get or set the given output on/off state + int regulator_get_state(struct udevice *dev, int type, int number, int *state); + int regulator_set_state(struct udevice *dev, int type, int number, int state); + +- Get or set the given output operation mode (mode defined by the driver) + int regulator_get_mode(struct udevice *dev, int type, int number, int *mode); + int regulator_set_mode(struct udevice *dev, int type, int number, int mode); + +7. Design limitations: +The child devices of the single parent device (pmic, interface), should not +provide it's features by more then one device each uclass types. +It's because, e.g. regulator_i2c_get() function will: +- look for the pmic device at address given by args, +- return it's first child device, which uclass type is 'UCLASS_PMIC_REGULATOR' +So, if more then one pmic child device exists, each the same uclass type, then +the regulator_i2c_get(), will return only first device. But usually there is no +need to implement the same functionality with more than one instance of each +uclass type device. + +8. Regulator driver +====================================== +As an example of the regulator driver, please take a look into the MAX77686 +regulator driver (drivers/power/regulator/max77686.c). The driver structure: + +U_BOOT_DRIVER(max77686_regulator) = { + .name = "max77686 regulator", + .id = UCLASS_PMIC_REGULATOR, + .ops = ®_max77686_ops, + .ofdata_to_platdata = reg_max77686_ofdata_to_platdata, + .priv_auto_alloc_size = sizeof(struct max77686_regulator_info), +}; + +This driver structure is different than for the pmic driver. + +It doesn't provide: +.of_match +.platdata_auto_alloc_size + +Both are not required in this case, because .of_match is known at the bind call, +and the platdata pointer is the same as for the parent device (pmic). + +But instead of the pmic driver, this driver provides: +.of_data_to_platdata + +And this call above is responsible for fill the regulator outputs descriptors, +which are described in device-tree, e.g. 'arch/arm/dts/exynos4412-odroid.dts' + +The bind for this driver is called in pmic/max77686.c driver bind. +After the pmic driver successful bind, there are two max77686 devices: +- max77686 pmic (parent) - UCLASS_PMIC + '- max77686 regulator (child) - UCLASS_PMIC_REGULATOR + +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); + +9. Regulator command +==================== +To use the pmic command, config: CONFIG_DM_REGULATOR_CMD is required. + +The extension for the 'pmic' command is 'regulator' command. +This actually uses the same code, but provides the interface +to pmic optional 'UCLASS_PMIC_REGULATOR' operations. + +If pmic device driver provides support to this another pmic +uclass, then this command provides useful user interface. + +This was designed to allow safe I/O access to the pmic device, +without the pmic documentation. If driver provide each regulator +output - value and mode descriptor - then user can operate on it. + +Usage: +regulator list - list UCLASS regulator devices +regulator dev [id] - show or set operating regulator device +regulator dump - dump registers of current regulator +regulator [ldo/buck/dvs][N] [name/state/desc] - print regulator(s) info +regulator [ldoN/buckN/dvsN] [setval/setmode] [mV/modeN] [-f] - set val (mV) + +The -f option (forcibly) or mode - only if descriptor is available + +Example of usage: +regulator list - look after regulator 'Id' number +regulator dev 'Id' - set current device +regulator ldo state - list state of current device all ldo's +regulator ldo desc - list ldo's descriptors +regulator ldo1 setval 1000 - set device ldo 1 voltage to 1000mV +regulator ldo1 setval 1200 -f - if value exceeds limits - set force +regulator ldo1 setmode 5 - set device ldo 1 mode to '5' + +The same for 'buck' regulators. + +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. --
Quoted 2 lines
1.9.1
This is a good and thorough overview. Can we drop the 'dm-' prefix on the filename and word-wrap it a bit more consistently towards the end (lots of short lines at present). Some of the phrasing is a bit hard to parse, but we can figure out that later.
Regards,
Simon
PATCH v2 8/12 doc: driver-model: pmic and regulator uclass documentation
Hello,
On 03/06/2015 03:14 PM, Simon Glass wrote:
[...]
Quoted 9 lines
This is a good and thorough overview. Can we drop the 'dm-' prefix on the filename and word-wrap it a bit more consistently towards the end (lots of short lines at present). Some of the phrasing is a bit hard to parse, but we can figure out that later.
Regards,
Simon
The V3 version of this file, is updated with the new framework changes, I will compress the lines in the next patch version.
Signature · 4 lines
Przemyslaw Marczak Samsung R&D Institute Poland Samsung Electronics p.marczak at samsung.com
PATCH v2 9/12 dm: board:samsung: power_init_board: add requirement of CONFIG_DM_PMIC
In reply to Przemyslaw MarczakIn 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
@@ -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 ;
@@ -162,7 +162,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
PATCH v2 10/12 odroid: board: add support to dm pmic api
In reply to Przemyslaw MarczakThis 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
--- board/samsung/common/misc.c | 1 + board/samsung/odroid/odroid.c | 52 ++++++++++++++++++++++++++----------------- 2 files changed, 33 insertions(+), 20 deletions(-)
board/samsung/common/misc.c +1 -0
@@ -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 +32 -20
101 lines not on this page · raw message
Signature · 1 line
1.9.1
PATCH v2 10/12 odroid: board: add support to dm pmic api
Hi Przemyslaw,
Quoted 56 lines · Przemyslaw Marczak
This commit change the old pmic framework calls with the new ones.
Signed-off-by Przemyslaw Marczak <[email protected]>---
Changes v2:
- removeboard_init_i2c()call
- update regulator calls
- update headers
-samsung/misc.c: include required header--- board/samsung/common/misc.c | 1 + board/samsung/odroid/odroid.c | 52 ++++++++++++++++++++++++++----------------- 2 files changed, 33 insertions(+), 20 deletions(-)board/samsung/common/misc.c +1
-0@@ -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 +7
-3@@ -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 <usb.h> @@ -402,15 +404,23 @@ static void board_gpio_init(void)static int pmic_init_max77686 (void ) { -struct pmic *p =pmic_get ("MAX77686_PMIC" ); +struct udevice *reg; +int type; -if (pmic_probe (p)) +if (regulator_get ("max77686" , ®)) { +error ("Regulator get error\n" );return -ENODEV ; + }/* Set LDO Voltage */ -max77686_set_ldo_voltage (p,20 ,1800000 );/* LDO20 eMMC */
board/samsung/odroid/odroid.c static void board_gpio_init(void) · line 423
Quoted 10 lines
board/samsung/odroid/odroid.c +8
-2-max77686_set_ldo_voltage (p,21 ,2800000 );/* LDO21 SD */ -max77686_set_ldo_voltage (p,22 ,2800000 );/* LDO22 eMMC */ + type =REGULATOR_TYPE_LDO ; +regulator_set_value (reg, type,20 ,1800000 );/* LDO20 eMMC */ +regulator_set_value (reg, type,21 ,2800000 );/* LDO21 SD */ +regulator_set_value (reg, type,22 ,2800000 );/* LDO22 eMMC */ + +regulator_set_mode (reg, type,20 ,OPMODE_ON ); +regulator_set_mode (reg, type,21 ,OPMODE_ON ); +regulator_set_mode (reg, type,22 ,OPMODE_ON );
These 20, 21, 22 values seem bad to me. Do we not have names? Also I see in the device tree that these regulators have the same min and max voltage, so perhaps you can use that voltage automatically?
I think when you change the LDOs to devices you might end up with:
struct udevice *ldo;
ret = regulator_get("VCCQ_MMC2_2.8V", &ldo); // use the regulator
device name which comes from regulator-name property. if (ret) {
debug(...)
goto err;
}
ret = regulator_set_voltage(ldo, 1800000); ...error check
ret = regulator_set_mode(ldo, OPMODE_ON); ...error check
Quoted 54 lines
board/samsung/odroid/odroid.c +11
-9return 0 ; }@@ -435,7 +445,6 @@ int exynos_init(void)int exynos_power_init (void ) { -pmic_init (0 );pmic_init_max77686 ();return 0 ;@@ -444,19 +453,21 @@ int exynos_power_init(void)#ifdef CONFIG_USB_GADGET static int s5pc210_phy_control (int on) { -struct pmic *p_pmic; +struct udevice *reg; +int type; - p_pmic =pmic_get ("MAX77686_PMIC" ); -if (!p_pmic) +if (regulator_get ("max77686" , ®)) { +error ("Regulator get error\n" );return -ENODEV ; + } -if (pmic_probe (p_pmic)) -return -1 ; + type =REGULATOR_TYPE_LDO ;if (on) -return max77686_set_ldo_mode (p_pmic,12 ,OPMODE_ON ); +return regulator_set_mode (reg, type,12 ,OPMODE_ON );else -return max77686_set_ldo_mode (p_pmic,12 ,OPMODE_LPM ); +return regulator_set_mode (reg, type,12 ,OPMODE_LPM ); + } struct s3c_plat_otg_data s5pc210_otg_data = {@@ -473,7 +484,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 *reg; +int type, ret;/* Set Ref freq 0 => 24MHz, 1 => 26MHz*/ /* Odroid Us have it at 24MHz, Odroid Xs at 26MHz */ @@ -491,14 +503,14 @@ 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" );
board/samsung/odroid/odroid.c int board_usb_init(int index, enum usb_init_type init) · line 511
Quoted 10 lines
board/samsung/odroid/odroid.c +6
-4- 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 ); +if (regulator_get ("max77686" , ®)) { + type =REGULATOR_TYPE_BUCK ; + ret =regulator_set_value (reg, type,8 ,750000 ); + ret |=regulator_set_value (reg, type,8 ,3300000 ); +if (ret) +error ("Can't set regulator\n" );
We should return a proper error number. Also print it here as it might provide clues.
Quoted 10 lines
board/samsung/odroid/odroid.c +0
-3} -#endif -debug ("USB_udc_probe\n" );return s3c_udc_probe (&s5pc210_otg_data); } --1.9.1
Regards,
Simon
PATCH v2 10/12 odroid: board: add support to dm pmic api
Hello,
Quoted 80 lines · Simon Glass
Hi Przemyslaw,
Quoted 56 lines · Przemyslaw Marczak
This commit change the old pmic framework calls with the new ones.
Signed-off-by Przemyslaw Marczak <[email protected]>---
Changes v2:
- removeboard_init_i2c()call
- update regulator calls
- update headers
-samsung/misc.c: include required header--- board/samsung/common/misc.c | 1 + board/samsung/odroid/odroid.c | 52 ++++++++++++++++++++++++++----------------- 2 files changed, 33 insertions(+), 20 deletions(-)board/samsung/common/misc.c +1
-0@@ -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 +7
-3@@ -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 <usb.h> @@ -402,15 +404,23 @@ static void board_gpio_init(void)static int pmic_init_max77686 (void ) { -struct pmic *p =pmic_get ("MAX77686_PMIC" ); +struct udevice *reg; +int type; -if (pmic_probe (p)) +if (regulator_get ("max77686" , ®)) { +error ("Regulator get error\n" );return -ENODEV ; + }/* Set LDO Voltage */ -max77686_set_ldo_voltage (p,20 ,1800000 );/* LDO20 eMMC */ board/samsung/odroid/odroid.c static void board_gpio_init(void) · line 423
Quoted 10 lines
board/samsung/odroid/odroid.c +8
-2-max77686_set_ldo_voltage (p,21 ,2800000 );/* LDO21 SD */ -max77686_set_ldo_voltage (p,22 ,2800000 );/* LDO22 eMMC */ + type =REGULATOR_TYPE_LDO ; +regulator_set_value (reg, type,20 ,1800000 );/* LDO20 eMMC */ +regulator_set_value (reg, type,21 ,2800000 );/* LDO21 SD */ +regulator_set_value (reg, type,22 ,2800000 );/* LDO22 eMMC */ + +regulator_set_mode (reg, type,20 ,OPMODE_ON ); +regulator_set_mode (reg, type,21 ,OPMODE_ON ); +regulator_set_mode (reg, type,22 ,OPMODE_ON );These 20, 21, 22 values seem bad to me. Do we not have names? Also I see in the device tree that these regulators have the same min and max voltage, so perhaps you can use that voltage automatically?
I think when you change the LDOs to devices you might end up with:
struct udevice *ldo;
ret =
regulator_get("VCCQ_MMC2_2.8V", &ldo); // use the regulator
device name which comes from regulator-name property.
Quoted 9 lines
if (ret) { debug(...) goto err; }ret =
regulator_set_voltage(ldo, 1800000);
...error check
ret =regulator_set_mode(ldo, OPMODE_ON);
...error check
The above suggestion is implemented in V3.
Quoted 68 lines
Quoted 54 lines
board/samsung/odroid/odroid.c +11
-9return 0 ; }@@ -435,7 +445,6 @@ int exynos_init(void)int exynos_power_init (void ) { -pmic_init (0 );pmic_init_max77686 ();return 0 ;@@ -444,19 +453,21 @@ int exynos_power_init(void)#ifdef CONFIG_USB_GADGET static int s5pc210_phy_control (int on) { -struct pmic *p_pmic; +struct udevice *reg; +int type; - p_pmic =pmic_get ("MAX77686_PMIC" ); -if (!p_pmic) +if (regulator_get ("max77686" , ®)) { +error ("Regulator get error\n" );return -ENODEV ; + } -if (pmic_probe (p_pmic)) -return -1 ; + type =REGULATOR_TYPE_LDO ;if (on) -return max77686_set_ldo_mode (p_pmic,12 ,OPMODE_ON ); +return regulator_set_mode (reg, type,12 ,OPMODE_ON );else -return max77686_set_ldo_mode (p_pmic,12 ,OPMODE_LPM ); +return regulator_set_mode (reg, type,12 ,OPMODE_LPM ); + } struct s3c_plat_otg_data s5pc210_otg_data = {@@ -473,7 +484,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 *reg; +int type, ret;/* Set Ref freq 0 => 24MHz, 1 => 26MHz*/ /* Odroid Us have it at 24MHz, Odroid Xs at 26MHz */ @@ -491,14 +503,14 @@ 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" );board/samsung/odroid/odroid.c int board_usb_init(int index, enum usb_init_type init) · line 511
Quoted 10 lines
board/samsung/odroid/odroid.c +6
-4- 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 ); +if (regulator_get ("max77686" , ®)) { + type =REGULATOR_TYPE_BUCK ; + ret =regulator_set_value (reg, type,8 ,750000 ); + ret |=regulator_set_value (reg, type,8 ,3300000 ); +if (ret) +error ("Can't set regulator\n" );We should return a proper error number. Also print it here as it might provide clues.
Quoted 14 lines
Quoted 10 lines
board/samsung/odroid/odroid.c +0
-3} -#endif -debug ("USB_udc_probe\n" );return s3c_udc_probe (&s5pc210_otg_data); } --1.9.1
Regards,
Simon
Thanks,
Signature · 4 lines
Przemyslaw Marczak Samsung R&D Institute Poland Samsung Electronics p.marczak at samsung.com
PATCH v2 11/12 odroid: dts: add 'voltage-regulators' description to max77686 node
In reply to Przemyslaw MarczakAdding regulators subnode to fdt max77686 node allows properly init regulators descriptors from by the max77686 regulator driver. This enables the complete functionality of the regulator command.
---
Changes V2:
- odroid: dts: remove pmic alias
--- arch/arm/dts/exynos4412-odroid.dts | 249 ++++++++++++++++++++++++++++++++++++- 1 file changed, 248 insertions(+), 1 deletion(-)
arch/arm/dts/exynos4412-odroid.dts +248 -1
@@ -35,11 +35,258 @@ samsung,i2c-max-bus-freq = <100000>; status = "okay"; - max77686_pmic at 09 { + max77686 { compatible = "maxim,max77686_pmic"; 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
PATCH v2 12/12 odroid: config: enable dm pmic, dm regulator and max77686 driver
In reply to Przemyslaw MarczakThis change enables the configs required to init and setup max77686 regulator driver, using the new driver model pmic API.
Enabled configs:
- CONFIG_DM_PMIC_I2C
- CONFIG_DM_PMIC_MAX77686
- CONFIG_DM_REGULATOR
- 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
--- configs/odroid_defconfig | 1 - include/configs/odroid.h | 9 ++++++--- 2 files changed, 6 insertions(+), 4 deletions(-)
configs/odroid_defconfig +0 -1
@@ -4,4 +4,3 @@ CONFIG_TARGET_ODROID=y CONFIG_OF_CONTROL=y CONFIG_DEFAULT_DEVICE_TREE="exynos4412-odroid" CONFIG_DM_I2C=y -CONFIG_DM_I2C_COMPAT=y
include/configs/odroid.h +6 -3
@@ -182,9 +182,12 @@#define CONFIG_SYS_I2C_S3C24X0_SLAVE 0/* POWER */ -#define CONFIG_POWER -#define CONFIG_POWER_I2C -#define CONFIG_POWER_MAX77686 +#define CONFIG_DM_PMIC +#define CONFIG_DM_PMIC_CMD +#define CONFIG_DM_PMIC_MAX77686 +#define CONFIG_DM_REGULATOR +#define CONFIG_DM_REGULATOR_CMD +#define CONFIG_DM_REGULATOR_MAX77686 /* GPT */ #define CONFIG_RANDOM_UUID
Signature · 1 line
1.9.1
PATCH v2 12/12 odroid: config: enable dm pmic, dm regulator and max77686 driver
Hi Przemyslaw,
Quoted 42 lines · Przemyslaw Marczak
This change enables the configs required to init and setup max77686 regulator driver, using the new driver model pmic API.
Enabled configs:
-CONFIG_DM_PMIC_I2C
-CONFIG_DM_PMIC_MAX77686
-CONFIG_DM_REGULATOR
-CONFIG_DM_REGULATOR_MAX77686And removes the unused:
-CONFIG_DM_I2C_COMPAT
-CONFIG_POWER
-CONFIG_POWER_I2C
-CONFIG_POWER_MAX77686Signed-off-by Przemyslaw Marczak <[email protected]>---
Changes V2:
- config: enable dm i2c; cleanup
- removeCONFIG_DM_I2C_COMPAT
- enable regulator command--- configs/odroid_defconfig | 1 - include/configs/odroid.h | 9 ++++++--- 2 files changed, 6 insertions(+), 4 deletions(-)configs/odroid_defconfig +0
-1@@ -4,4 +4,3 @@ CONFIG_TARGET_ODROID=y CONFIG_OF_CONTROL=y CONFIG_DEFAULT_DEVICE_TREE="exynos4412-odroid" CONFIG_DM_I2C=y -CONFIG_DM_I2C_COMPAT=yinclude/configs/odroid.h +0
-0@@ -182,9 +182,12 @@#define CONFIG_SYS_I2C_S3C24X0_SLAVE 0
include/configs/odroid.h line 190
Quoted 10 lines
include/configs/odroid.h +6
-3/* POWER */ -#define CONFIG_POWER -#define CONFIG_POWER_I2C -#define CONFIG_POWER_MAX77686 +#define CONFIG_DM_PMIC +#define CONFIG_DM_PMIC_CMD +#define CONFIG_DM_PMIC_MAX77686 +#define CONFIG_DM_REGULATOR +#define CONFIG_DM_REGULATOR_CMD +#define CONFIG_DM_REGULATOR_MAX77686
These should move to Kconfig.
Quoted 6 lines
include/configs/odroid.h +0
-1/* GPT */ #define CONFIG_RANDOM_UUID --1.9.1
Regards,
Simon
v2 cover Power(full) framework based on Driver Model
In reply to Przemyslaw MarczakHello,
Quoted 95 lines · Przemyslaw Marczak
Hello,
Here is the second RFC version of the new PMIC framework. The changes made in this version are described below each commit.So again, a quick summary of:
Framework:
- Add new uclass types:
--UCLASS_PMIC(for device I/O)
--UCLASS_PMIC_REGULATOR(for common regulator ops)
- Two uclass drivers for the above types
- A common regulator operations - will easy cover the real devices design
- V2: pmic: add read/write ops
- V2: regulator: use regulator type as an argument - not as function nameDrivers:
- Introduce new PMIC API for drivers - now everything base on "struct udevice"
- Introduce Regulator Voltage descriptors and Operation Mode descriptors which are usually taken from the device tree (board dependent data)
- Two uclass device drivers for MAX77686(PMIC+REGULATOR)
- V2: don't use the 'hw union' from old pmic
- V2: remove the files:pmic_i2c.c/pmic_spi.c- now using bus drivers
- V2: cleanup thepmic_get()functions
- V2: addpmic_io_dev()function for getting the proper I/O dev for devices
- V2: add function calls for getting pmic devices platdata
- V2: remove regulator type from regulator operations function calls, use type as an argumentUser Interface:
- command pmic, unchanged functionality and ported to the driver model
- command regulator(NEW) for safe regulator setup from commandline,
- now can check output Voltage and operation mode of the regulators,
- also can check the board Voltage limits and driver available modes
- V2: simplify the code after remove the regulator type from function naming
- V2: add on/off commandSupported boards:
- Odroid U3
- V2: drop the commits for Trats2 - wait for charger and muic uclass typesThe assumptions of this work is:
- Add new code to independent files
- Keep two Frameworks as independent and without conflicts
- Don't mix OLD/NEW Framework code - for the readabilityThe future plans:
- Add additional uclass types: MUIC, CHARGER, BATTERY, MFD and maybe more.
- Port all U-Boot drivers to the new Framework
- Remove the old drivers and the old PMIC Framework codeNeed help:
- After merge this, it is welcome to help with driver porting
- Every new driver should be tested on real hardwareBest regards
Przemyslaw Marczak (12):
exynos5: fix build break by addingCONFIG_POWER
dm: device: add functiondevice_get_first_child_by_uclass_id()
dm: pmic: add implementation of driver model pmic uclass
dm: pmic: add implementation of driver model regulator uclass
dm: pmic: new commands: pmic and regulator
dm: pmic: add max77686 pmic driver
dm: regulator: add max77686 regulator driver
doc: driver-model: pmic and regulator uclass documentation
dm: board:samsung:power_init_board: add requirement ofCONFIG_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 driverMakefile | 1 + arch/arm/dts/exynos4412-odroid.dts | 249 ++++++++- board/samsung/common/board.c | 4 +- board/samsung/common/misc.c | 1 + board/samsung/odroid/odroid.c | 52 +- configs/odroid_defconfig | 1 - doc/driver-model/dm-pmic-framework.txt | 367 +++++++++++++ drivers/core/device.c | 15 + drivers/power/Makefile | 5 +- drivers/power/cmd_pmic.c | 820 +++++++++++++++++++++++++++++ drivers/power/pmic-uclass.c | 191 +++++++ drivers/power/pmic/Makefile | 1 + drivers/power/pmic/max77686.c | 102 ++++ drivers/power/pmic/pmic_max77686.c | 2 +- drivers/power/regulator-uclass.c | 227 ++++++++ drivers/power/regulator/Makefile | 8 + drivers/power/regulator/max77686.c | 926 +++++++++++++++++++++++++++++++++ include/configs/exynos5-common.h | 4 + include/configs/odroid.h | 9 +- include/dm/device.h | 16 + include/dm/uclass-id.h | 4 + include/power/max77686_pmic.h | 26 +- include/power/pmic.h | 265 ++++++++++ include/power/regulator.h | 310 +++++++++++ 24 files changed, 3573 insertions(+), 33 deletions(-)
Quoted 9 lines
create mode 100644
doc/driver-model/dm-pmic-framework.txtcreate mode 100644drivers/power/cmd_pmic.ccreate mode 100644drivers/power/pmic-uclass.ccreate mode 100644drivers/power/pmic/max77686.ccreate mode 100644drivers/power/regulator-uclass.ccreate mode 100644drivers/power/regulator/Makefilecreate mode 100644drivers/power/regulator/max77686.ccreate mode 100644include/power/regulator.h
Missed one e-mail:
+cc: trini at konsulko.com
Best regards,
Signature · 4 lines
Przemyslaw Marczak Samsung R&D Institute Poland Samsung Electronics p.marczak at samsung.com
v2 cover Power(full) framework based on Driver Model
In reply to Przemyslaw MarczakAnd the patchset on github:
https://github.com/bobenstein/u-boot/tree/dm-pmic-v2
Best regards,
Signature · 4 lines
Przemyslaw Marczak Samsung R&D Institute Poland Samsung Electronics p.marczak at samsung.com
v2 cover Power(full) framework based on Driver Model
In reply to Przemyslaw MarczakHi Przemyslaw,
Quoted 95 lines · Przemyslaw Marczak
Hello,
Here is the second RFC version of the new PMIC framework. The changes made in this version are described below each commit.So again, a quick summary of:
Framework:
- Add new uclass types:
--UCLASS_PMIC(for device I/O)
--UCLASS_PMIC_REGULATOR(for common regulator ops)
- Two uclass drivers for the above types
- A common regulator operations - will easy cover the real devices design
- V2: pmic: add read/write ops
- V2: regulator: use regulator type as an argument - not as function nameDrivers:
- Introduce new PMIC API for drivers - now everything base on "struct udevice"
- Introduce Regulator Voltage descriptors and Operation Mode descriptors which are usually taken from the device tree (board dependent data)
- Two uclass device drivers for MAX77686(PMIC+REGULATOR)
- V2: don't use the 'hw union' from old pmic
- V2: remove the files:pmic_i2c.c/pmic_spi.c- now using bus drivers
- V2: cleanup thepmic_get()functions
- V2: addpmic_io_dev()function for getting the proper I/O dev for devices
- V2: add function calls for getting pmic devices platdata
- V2: remove regulator type from regulator operations function calls, use type as an argumentUser Interface:
- command pmic, unchanged functionality and ported to the driver model
- command regulator(NEW) for safe regulator setup from commandline,
- now can check output Voltage and operation mode of the regulators,
- also can check the board Voltage limits and driver available modes
- V2: simplify the code after remove the regulator type from function naming
- V2: add on/off commandSupported boards:
- Odroid U3
- V2: drop the commits for Trats2 - wait for charger and muic uclass typesThe assumptions of this work is:
- Add new code to independent files
- Keep two Frameworks as independent and without conflicts
- Don't mix OLD/NEW Framework code - for the readabilityThe future plans:
- Add additional uclass types: MUIC, CHARGER, BATTERY, MFD and maybe more.
- Port all U-Boot drivers to the new Framework
- Remove the old drivers and the old PMIC Framework codeNeed help:
- After merge this, it is welcome to help with driver porting
- Every new driver should be tested on real hardwareBest regards
Przemyslaw Marczak (12):
exynos5: fix build break by addingCONFIG_POWER
dm: device: add functiondevice_get_first_child_by_uclass_id()
dm: pmic: add implementation of driver model pmic uclass
dm: pmic: add implementation of driver model regulator uclass
dm: pmic: new commands: pmic and regulator
dm: pmic: add max77686 pmic driver
dm: regulator: add max77686 regulator driver
doc: driver-model: pmic and regulator uclass documentation
dm: board:samsung:power_init_board: add requirement ofCONFIG_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 driverMakefile | 1 + arch/arm/dts/exynos4412-odroid.dts | 249 ++++++++- board/samsung/common/board.c | 4 +- board/samsung/common/misc.c | 1 + board/samsung/odroid/odroid.c | 52 +- configs/odroid_defconfig | 1 - doc/driver-model/dm-pmic-framework.txt | 367 +++++++++++++ drivers/core/device.c | 15 + drivers/power/Makefile | 5 +- drivers/power/cmd_pmic.c | 820 +++++++++++++++++++++++++++++ drivers/power/pmic-uclass.c | 191 +++++++ drivers/power/pmic/Makefile | 1 + drivers/power/pmic/max77686.c | 102 ++++ drivers/power/pmic/pmic_max77686.c | 2 +- drivers/power/regulator-uclass.c | 227 ++++++++ drivers/power/regulator/Makefile | 8 + drivers/power/regulator/max77686.c | 926 +++++++++++++++++++++++++++++++++ include/configs/exynos5-common.h | 4 + include/configs/odroid.h | 9 +- include/dm/device.h | 16 + include/dm/uclass-id.h | 4 + include/power/max77686_pmic.h | 26 +- include/power/pmic.h | 265 ++++++++++ include/power/regulator.h | 310 +++++++++++ 24 files changed, 3573 insertions(+), 33 deletions(-)
Quoted 8 lines
create mode 100644 doc/driver-model/dm-pmic-framework.txt create mode 100644 drivers/power/cmd_pmic.c 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/max77686.c create mode 100644 include/power/regulator.h
This is an impressive pieces of work! It will be great to get these in.
Here are some high-level comments on this series:
1. I think regulator LDOs and bucks should be proper devices (struct udevice), bound by the pmic when it is probed. The advantages are
a. You can see them in the device list - the pmic will end up with a lot more children
b. You can use the same regulator uclass for each, but have different operations for each driver (e.g. max77686 might provide two different drivers, one for LDO, one for buck).
c. Things like your 'switch (type)' in max7786_get_state() etc. will go away d. You can perform operations on them without having to specify their parent and number - e.g. regulator_set_mode(struct udevice *ldo, int mode) which is much more natural for users
e. You avoid needing your own list of regulators and bucks - struct max7786_regulator_info. After all, keeping track of child devices is something that driver model can do
2. I see device tree support, but the Linux device tree bindings are not fully supported, e.g. the regulators sub-node uses regulator-compatible instead of regulator-name. I think it should be exactly the same (and we should copy the device tree files, only leaving out what we don't support)
3. The I2C/SPI difference is a bit clunky. We should try to hide this away. The most obvious problem is in getting the device. Instead of pmic_i2c_get() we should use the "power-supply" property in the device tree, so we need a function which can find the regulator given the device node (a bit like gpio_request_by_name() but for PMICs). The pmic_get() function is OK and will be needed also, as I am sure we will use names in some places. We should remove any mention of the bus type from the API I think. Also regulator number seems and odd concept
- better to use the name/device tree link to find the right device. One way to avoid I2C/SPI problems is to create a helper file which allows you to read and write registers given a struct udevice. It could look at whether the device is I2C or SPI and do the right thing. This could be generally useful, not just for PMICs.
4. Should use Kconfig now.
Regards,
Simon
v2 cover Power(full) framework based on Driver Model
Hello Simon,
Quoted 107 lines · Simon Glass
Hi Przemyslaw,
Quoted 95 lines · Przemyslaw Marczak
Hello,
Here is the second RFC version of the new PMIC framework. The changes made in this version are described below each commit.So again, a quick summary of:
Framework:
- Add new uclass types:
--UCLASS_PMIC(for device I/O)
--UCLASS_PMIC_REGULATOR(for common regulator ops)
- Two uclass drivers for the above types
- A common regulator operations - will easy cover the real devices design
- V2: pmic: add read/write ops
- V2: regulator: use regulator type as an argument - not as function nameDrivers:
- Introduce new PMIC API for drivers - now everything base on "struct udevice"
- Introduce Regulator Voltage descriptors and Operation Mode descriptors which are usually taken from the device tree (board dependent data)
- Two uclass device drivers for MAX77686(PMIC+REGULATOR)
- V2: don't use the 'hw union' from old pmic
- V2: remove the files:pmic_i2c.c/pmic_spi.c- now using bus drivers
- V2: cleanup thepmic_get()functions
- V2: addpmic_io_dev()function for getting the proper I/O dev for devices
- V2: add function calls for getting pmic devices platdata
- V2: remove regulator type from regulator operations function calls, use type as an argumentUser Interface:
- command pmic, unchanged functionality and ported to the driver model
- command regulator(NEW) for safe regulator setup from commandline,
- now can check output Voltage and operation mode of the regulators,
- also can check the board Voltage limits and driver available modes
- V2: simplify the code after remove the regulator type from function naming
- V2: add on/off commandSupported boards:
- Odroid U3
- V2: drop the commits for Trats2 - wait for charger and muic uclass typesThe assumptions of this work is:
- Add new code to independent files
- Keep two Frameworks as independent and without conflicts
- Don't mix OLD/NEW Framework code - for the readabilityThe future plans:
- Add additional uclass types: MUIC, CHARGER, BATTERY, MFD and maybe more.
- Port all U-Boot drivers to the new Framework
- Remove the old drivers and the old PMIC Framework codeNeed help:
- After merge this, it is welcome to help with driver porting
- Every new driver should be tested on real hardwareBest regards
Przemyslaw Marczak (12):
exynos5: fix build break by addingCONFIG_POWER
dm: device: add functiondevice_get_first_child_by_uclass_id()
dm: pmic: add implementation of driver model pmic uclass
dm: pmic: add implementation of driver model regulator uclass
dm: pmic: new commands: pmic and regulator
dm: pmic: add max77686 pmic driver
dm: regulator: add max77686 regulator driver
doc: driver-model: pmic and regulator uclass documentation
dm: board:samsung:power_init_board: add requirement ofCONFIG_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 driverMakefile | 1 + arch/arm/dts/exynos4412-odroid.dts | 249 ++++++++- board/samsung/common/board.c | 4 +- board/samsung/common/misc.c | 1 + board/samsung/odroid/odroid.c | 52 +- configs/odroid_defconfig | 1 - doc/driver-model/dm-pmic-framework.txt | 367 +++++++++++++ drivers/core/device.c | 15 + drivers/power/Makefile | 5 +- drivers/power/cmd_pmic.c | 820 +++++++++++++++++++++++++++++ drivers/power/pmic-uclass.c | 191 +++++++ drivers/power/pmic/Makefile | 1 + drivers/power/pmic/max77686.c | 102 ++++ drivers/power/pmic/pmic_max77686.c | 2 +- drivers/power/regulator-uclass.c | 227 ++++++++ drivers/power/regulator/Makefile | 8 + drivers/power/regulator/max77686.c | 926 +++++++++++++++++++++++++++++++++ include/configs/exynos5-common.h | 4 + include/configs/odroid.h | 9 +- include/dm/device.h | 16 + include/dm/uclass-id.h | 4 + include/power/max77686_pmic.h | 26 +- include/power/pmic.h | 265 ++++++++++ include/power/regulator.h | 310 +++++++++++ 24 files changed, 3573 insertions(+), 33 deletions(-)Quoted 8 lines
create mode 100644
doc/driver-model/dm-pmic-framework.txtcreate mode 100644drivers/power/cmd_pmic.ccreate mode 100644drivers/power/pmic-uclass.ccreate mode 100644drivers/power/pmic/max77686.ccreate mode 100644drivers/power/regulator-uclass.ccreate mode 100644drivers/power/regulator/Makefilecreate mode 100644drivers/power/regulator/max77686.ccreate mode 100644include/power/regulator.h
Quoted 1 line
This is an impressive pieces of work! It will be great to get these in.
Thank you, and also thank you for the review.
I hope to finish this all successfully.
Quoted 39 lines
Here are some high-level comments on this series:
1. I think regulator LDOs and bucks should be proper devices (struct udevice), bound by the pmic when it is probed. The advantages are
a. You can see them in the device list - the pmic will end up with a lot more children
b. You can use the same regulator uclass for each, but have different operations for each driver (e.g. max77686 might provide two different drivers, one for LDO, one for buck).
c. Things like your 'switch (type)' inmax7786_get_state()etc. will go away d. You can perform operations on them without having to specify their parent and number - e.g.regulator_set_mode(struct udevice *ldo, int mode)which is much more natural for users
e. You avoid needing your own list of regulators and bucks - structmax7786_regulator_info. After all, keeping track of child devices is something that driver model can do2. I see device tree support, but the Linux device tree bindings are not fully supported, e.g. the regulators sub-node uses regulator-compatible instead of regulator-name. I think it should be exactly the same (and we should copy the device tree files, only leaving out what we don't support)
3. The I2C/SPI difference is a bit clunky. We should try to hide this away. The most obvious problem is in getting the device. Instead of
pmic_i2c_get()we should use the "power-supply" property in the device tree, so we need a function which can find the regulator given the device node (a bit likegpio_request_by_name()but for PMICs). Thepmic_get()function is OK and will be needed also, as I am sure we will use names in some places. We should remove any mention of the bus type from the API I think. Also regulator number seems and odd concept
- better to use the name/device tree link to find the right device. One way to avoid I2C/SPI problems is to create a helper file which allows you to read and write registers given a struct udevice. It could look at whether the device is I2C or SPI and do the right thing. This could be generally useful, not just for PMICs.
Quoted 5 lines
4. Should use
Kconfignow.Regards,
Simon
I quickly read your all comments, and all are very helpful for me, I will reply to each in the next week.
I see that this piece of code should be done as e.g. the gpio uclass is.
My previous assumption was, to use the regulator numbers rather than names - as it is easy and faster - cause we have one driver instance for few regulators - but I agree, need change.
Usually there are numbers in the pmic documentation, and the names are in the board schematics which uses both names and numbers. So I added getting the names from dts just as some useful info for the regulator command.
I agree with you, that using the names instead of the numbers allow to make some things more easy, e.g. getting the 'udevice' by name.
I made some rework of the soft i2c with dm support, it looks that it is working fine. I will need this for work on next pmic devices in my Trats2 (charger, muic and fuelgauge).
Probably, I will send the dm soft i2c as independent patch set, and then get back to this framework code.
Thank you and best regards,
Signature · 4 lines
Przemyslaw Marczak Samsung R&D Institute Poland Samsung Electronics p.marczak at samsung.com
v2 cover Power(full) framework based on Driver Model
Hi Przemyslaw,
Quoted 192 lines · Przemyslaw Marczak
Hello Simon,
Quoted 118 lines · Simon Glass
Hi Przemyslaw,
Quoted 103 lines · Przemyslaw Marczak
Hello,
Here is the second RFC version of the new PMIC framework. The changes made in this version are described below each commit.So again, a quick summary of:
Framework:
- Add new uclass types:
--UCLASS_PMIC(for device I/O)
--UCLASS_PMIC_REGULATOR(for common regulator ops)
- Two uclass drivers for the above types
- A common regulator operations - will easy cover the real devices design
- V2: pmic: add read/write ops
- V2: regulator: use regulator type as an argument - not as function nameDrivers:
- Introduce new PMIC API for drivers - now everything base on "struct udevice"
- Introduce Regulator Voltage descriptors and Operation Mode descriptors which are usually taken from the device tree (board dependent data)
- Two uclass device drivers for MAX77686(PMIC+REGULATOR)
- V2: don't use the 'hw union' from old pmic
- V2: remove the files:pmic_i2c.c/pmic_spi.c- now using bus drivers
- V2: cleanup thepmic_get()functions
- V2: addpmic_io_dev()function for getting the proper I/O dev for devices
- V2: add function calls for getting pmic devices platdata
- V2: remove regulator type from regulator operations function calls, use type as an argumentUser Interface:
- command pmic, unchanged functionality and ported to the driver model
- command regulator(NEW) for safe regulator setup from commandline,
- now can check output Voltage and operation mode of the regulators,
- also can check the board Voltage limits and driver available modes
- V2: simplify the code after remove the regulator type from function naming
- V2: add on/off commandSupported boards:
- Odroid U3
- V2: drop the commits for Trats2 - wait for charger and muic uclass typesThe assumptions of this work is:
- Add new code to independent files
- Keep two Frameworks as independent and without conflicts
- Don't mix OLD/NEW Framework code - for the readabilityThe future plans:
- Add additional uclass types: MUIC, CHARGER, BATTERY, MFD and maybe more.
- Port all U-Boot drivers to the new Framework
- Remove the old drivers and the old PMIC Framework codeNeed help:
- After merge this, it is welcome to help with driver porting
- Every new driver should be tested on real hardwareBest regards
Przemyslaw Marczak (12):
exynos5: fix build break by addingCONFIG_POWER
dm: device: add functiondevice_get_first_child_by_uclass_id()
dm: pmic: add implementation of driver model pmic uclass
dm: pmic: add implementation of driver model regulator uclass
dm: pmic: new commands: pmic and regulator
dm: pmic: add max77686 pmic driver
dm: regulator: add max77686 regulator driver
doc: driver-model: pmic and regulator uclass documentation
dm: board:samsung:power_init_board: add requirement ofCONFIG_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 driverMakefile | 1 + arch/arm/dts/exynos4412-odroid.dts | 249 ++++++++- board/samsung/common/board.c | 4 +- board/samsung/common/misc.c | 1 + board/samsung/odroid/odroid.c | 52 +- configs/odroid_defconfig | 1 - doc/driver-model/dm-pmic-framework.txt | 367 +++++++++++++ drivers/core/device.c | 15 + drivers/power/Makefile | 5 +- drivers/power/cmd_pmic.c | 820 +++++++++++++++++++++++++++++ drivers/power/pmic-uclass.c | 191 +++++++ drivers/power/pmic/Makefile | 1 + drivers/power/pmic/max77686.c | 102 ++++ drivers/power/pmic/pmic_max77686.c | 2 +- drivers/power/regulator-uclass.c | 227 ++++++++ drivers/power/regulator/Makefile | 8 + drivers/power/regulator/max77686.c | 926 +++++++++++++++++++++++++++++++++ include/configs/exynos5-common.h | 4 + include/configs/odroid.h | 9 +- include/dm/device.h | 16 + include/dm/uclass-id.h | 4 + include/power/max77686_pmic.h | 26 +- include/power/pmic.h | 265 ++++++++++ include/power/regulator.h | 310 +++++++++++ 24 files changed, 3573 insertions(+), 33 deletions(-)Quoted 8 lines
create mode 100644
doc/driver-model/dm-pmic-framework.txtcreate mode 100644drivers/power/cmd_pmic.ccreate mode 100644drivers/power/pmic-uclass.ccreate mode 100644drivers/power/pmic/max77686.ccreate mode 100644drivers/power/regulator-uclass.ccreate mode 100644drivers/power/regulator/Makefilecreate mode 100644drivers/power/regulator/max77686.ccreate mode 100644include/power/regulator.hQuoted 1 line
This is an impressive pieces of work! It will be great to get these in.
Thank you, and also thank you for the review.
I hope to finish this all successfully.Quoted 40 lines
Here are some high-level comments on this series:
1. I think regulator LDOs and bucks should be proper devices (struct udevice), bound by the pmic when it is probed. The advantages are
a. You can see them in the device list - the pmic will end up with a lot more children
b. You can use the same regulator uclass for each, but have different operations for each driver (e.g. max77686 might provide two different drivers, one for LDO, one for buck).
c. Things like your 'switch (type)' inmax7786_get_state()etc. will go away
d. You can perform operations on them without having to specify their parent and number - e.g.regulator_set_mode(struct udevice *ldo, int mode)which is much more natural for users
e. You avoid needing your own list of regulators and bucks - structmax7786_regulator_info. After all, keeping track of child devices is something that driver model can do2. I see device tree support, but the Linux device tree bindings are not fully supported, e.g. the regulators sub-node uses regulator-compatible instead of regulator-name. I think it should be exactly the same (and we should copy the device tree files, only leaving out what we don't support)
3. The I2C/SPI difference is a bit clunky. We should try to hide this away. The most obvious problem is in getting the device. Instead of
pmic_i2c_get()we should use the "power-supply" property in the device tree, so we need a function which can find the regulator given the device node (a bit likegpio_request_by_name()but for PMICs). Thepmic_get()function is OK and will be needed also, as I am sure we will use names in some places. We should remove any mention of the bus type from the API I think. Also regulator number seems and odd concept
- better to use the name/device tree link to find the right device. One way to avoid I2C/SPI problems is to create a helper file which allows you to read and write registers given a struct udevice. It could look at whether the device is I2C or SPI and do the right thing. This could be generally useful, not just for PMICs.Quoted 5 lines
4. Should use
Kconfignow.Regards,
SimonI quickly read your all comments, and all are very helpful for me, I will reply to each in the next week.
I see that this piece of code should be done as e.g. the gpio uclass is.
My previous assumption was, to use the regulator numbers rather than names - as it is easy and faster - cause we have one driver instance for few regulators - but I agree, need change.
Usually there are numbers in the pmic documentation, and the names are in the board schematics which uses both names and numbers.
So I added getting the names from dts just as some useful info for the regulator command.I agree with you, that using the names instead of the numbers allow to make some things more easy, e.g. getting the 'udevice' by name.
Quoted 6 lines
I made some rework of the soft i2c with dm support, it looks that it is working fine. I will need this for work on next pmic devices in my Trats2 (charger, muic and fuelgauge).
Probably, I will send the dm soft i2c as independent patch set, and then get back to this framework code.
Sounds good! It's a lot of work but it will be nice to have all this done.
Regards,
Simon
v2 cover Power(full) framework based on Driver Model
In reply to Simon GlassHi Przemyslaw,
Quoted 147 lines · Simon Glass
Hi Przemyslaw,
Quoted 95 lines · Przemyslaw Marczak
Hello,
Here is the second RFC version of the new PMIC framework. The changes made in this version are described below each commit.So again, a quick summary of:
Framework:
- Add new uclass types:
--UCLASS_PMIC(for device I/O)
--UCLASS_PMIC_REGULATOR(for common regulator ops)
- Two uclass drivers for the above types
- A common regulator operations - will easy cover the real devices design
- V2: pmic: add read/write ops
- V2: regulator: use regulator type as an argument - not as function nameDrivers:
- Introduce new PMIC API for drivers - now everything base on "struct udevice"
- Introduce Regulator Voltage descriptors and Operation Mode descriptors which are usually taken from the device tree (board dependent data)
- Two uclass device drivers for MAX77686(PMIC+REGULATOR)
- V2: don't use the 'hw union' from old pmic
- V2: remove the files:pmic_i2c.c/pmic_spi.c- now using bus drivers
- V2: cleanup thepmic_get()functions
- V2: addpmic_io_dev()function for getting the proper I/O dev for devices
- V2: add function calls for getting pmic devices platdata
- V2: remove regulator type from regulator operations function calls, use type as an argumentUser Interface:
- command pmic, unchanged functionality and ported to the driver model
- command regulator(NEW) for safe regulator setup from commandline,
- now can check output Voltage and operation mode of the regulators,
- also can check the board Voltage limits and driver available modes
- V2: simplify the code after remove the regulator type from function naming
- V2: add on/off commandSupported boards:
- Odroid U3
- V2: drop the commits for Trats2 - wait for charger and muic uclass typesThe assumptions of this work is:
- Add new code to independent files
- Keep two Frameworks as independent and without conflicts
- Don't mix OLD/NEW Framework code - for the readabilityThe future plans:
- Add additional uclass types: MUIC, CHARGER, BATTERY, MFD and maybe more.
- Port all U-Boot drivers to the new Framework
- Remove the old drivers and the old PMIC Framework codeNeed help:
- After merge this, it is welcome to help with driver porting
- Every new driver should be tested on real hardwareBest regards
Przemyslaw Marczak (12):
exynos5: fix build break by addingCONFIG_POWER
dm: device: add functiondevice_get_first_child_by_uclass_id()
dm: pmic: add implementation of driver model pmic uclass
dm: pmic: add implementation of driver model regulator uclass
dm: pmic: new commands: pmic and regulator
dm: pmic: add max77686 pmic driver
dm: regulator: add max77686 regulator driver
doc: driver-model: pmic and regulator uclass documentation
dm: board:samsung:power_init_board: add requirement ofCONFIG_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 driverMakefile | 1 + arch/arm/dts/exynos4412-odroid.dts | 249 ++++++++- board/samsung/common/board.c | 4 +- board/samsung/common/misc.c | 1 + board/samsung/odroid/odroid.c | 52 +- configs/odroid_defconfig | 1 - doc/driver-model/dm-pmic-framework.txt | 367 +++++++++++++ drivers/core/device.c | 15 + drivers/power/Makefile | 5 +- drivers/power/cmd_pmic.c | 820 +++++++++++++++++++++++++++++ drivers/power/pmic-uclass.c | 191 +++++++ drivers/power/pmic/Makefile | 1 + drivers/power/pmic/max77686.c | 102 ++++ drivers/power/pmic/pmic_max77686.c | 2 +- drivers/power/regulator-uclass.c | 227 ++++++++ drivers/power/regulator/Makefile | 8 + drivers/power/regulator/max77686.c | 926 +++++++++++++++++++++++++++++++++ include/configs/exynos5-common.h | 4 + include/configs/odroid.h | 9 +- include/dm/device.h | 16 + include/dm/uclass-id.h | 4 + include/power/max77686_pmic.h | 26 +- include/power/pmic.h | 265 ++++++++++ include/power/regulator.h | 310 +++++++++++ 24 files changed, 3573 insertions(+), 33 deletions(-)Quoted 8 lines
create mode 100644 doc/driver-model/dm-pmic-framework.txt create mode 100644 drivers/power/cmd_pmic.c 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/max77686.c create mode 100644 include/power/regulator.hThis is an impressive pieces of work! It will be great to get these in.
Here are some high-level comments on this series:
1. I think regulator LDOs and bucks should be proper devices (struct udevice), bound by the pmic when it is probed. The advantages are
a. You can see them in the device list - the pmic will end up with a lot more children
b. You can use the same regulator uclass for each, but have different operations for each driver (e.g. max77686 might provide two different drivers, one for LDO, one for buck).
c. Things like your 'switch (type)' inmax7786_get_state()etc. will go away d. You can perform operations on them without having to specify their parent and number - e.g.regulator_set_mode(struct udevice *ldo, int mode)which is much more natural for users
e. You avoid needing your own list of regulators and bucks - structmax7786_regulator_info. After all, keeping track of child devices is something that driver model can do2. I see device tree support, but the Linux device tree bindings are not fully supported, e.g. the regulators sub-node uses regulator-compatible instead of regulator-name. I think it should be exactly the same (and we should copy the device tree files, only leaving out what we don't support)
3. The I2C/SPI difference is a bit clunky. We should try to hide this away. The most obvious problem is in getting the device. Instead of
pmic_i2c_get()we should use the "power-supply" property in the device tree, so we need a function which can find the regulator given the device node (a bit likegpio_request_by_name()but for PMICs). Thepmic_get()function is OK and will be needed also, as I am sure we will use names in some places. We should remove any mention of the bus type from the API I think. Also regulator number seems and odd concept
- better to use the name/device tree link to find the right device. One way to avoid I2C/SPI problems is to create a helper file which allows you to read and write registers given a struct udevice. It could look at whether the device is I2C or SPI and do the right thing. This could be generally useful, not just for PMICs.
Quoted 1 line
4. Should use
Kconfignow.
Sorry I don't know how I forgot to mention this:
5. A test PMIC device for sandbox so that the tests can run (test/dm/pmic.c).
Regards,
Simon
v2 cover Power(full) framework based on Driver Model
Hello Simon,
Quoted 114 lines · Simon Glass
Hi Przemyslaw,
Quoted 111 lines · Simon Glass
Hi Przemyslaw,
Quoted 95 lines · Przemyslaw Marczak
Hello,
Here is the second RFC version of the new PMIC framework. The changes made in this version are described below each commit.So again, a quick summary of:
Framework:
- Add new uclass types:
--UCLASS_PMIC(for device I/O)
--UCLASS_PMIC_REGULATOR(for common regulator ops)
- Two uclass drivers for the above types
- A common regulator operations - will easy cover the real devices design
- V2: pmic: add read/write ops
- V2: regulator: use regulator type as an argument - not as function nameDrivers:
- Introduce new PMIC API for drivers - now everything base on "struct udevice"
- Introduce Regulator Voltage descriptors and Operation Mode descriptors which are usually taken from the device tree (board dependent data)
- Two uclass device drivers for MAX77686(PMIC+REGULATOR)
- V2: don't use the 'hw union' from old pmic
- V2: remove the files:pmic_i2c.c/pmic_spi.c- now using bus drivers
- V2: cleanup thepmic_get()functions
- V2: addpmic_io_dev()function for getting the proper I/O dev for devices
- V2: add function calls for getting pmic devices platdata
- V2: remove regulator type from regulator operations function calls, use type as an argumentUser Interface:
- command pmic, unchanged functionality and ported to the driver model
- command regulator(NEW) for safe regulator setup from commandline,
- now can check output Voltage and operation mode of the regulators,
- also can check the board Voltage limits and driver available modes
- V2: simplify the code after remove the regulator type from function naming
- V2: add on/off commandSupported boards:
- Odroid U3
- V2: drop the commits for Trats2 - wait for charger and muic uclass typesThe assumptions of this work is:
- Add new code to independent files
- Keep two Frameworks as independent and without conflicts
- Don't mix OLD/NEW Framework code - for the readabilityThe future plans:
- Add additional uclass types: MUIC, CHARGER, BATTERY, MFD and maybe more.
- Port all U-Boot drivers to the new Framework
- Remove the old drivers and the old PMIC Framework codeNeed help:
- After merge this, it is welcome to help with driver porting
- Every new driver should be tested on real hardwareBest regards
Przemyslaw Marczak (12):
exynos5: fix build break by addingCONFIG_POWER
dm: device: add functiondevice_get_first_child_by_uclass_id()
dm: pmic: add implementation of driver model pmic uclass
dm: pmic: add implementation of driver model regulator uclass
dm: pmic: new commands: pmic and regulator
dm: pmic: add max77686 pmic driver
dm: regulator: add max77686 regulator driver
doc: driver-model: pmic and regulator uclass documentation
dm: board:samsung:power_init_board: add requirement ofCONFIG_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 driverMakefile | 1 + arch/arm/dts/exynos4412-odroid.dts | 249 ++++++++- board/samsung/common/board.c | 4 +- board/samsung/common/misc.c | 1 + board/samsung/odroid/odroid.c | 52 +- configs/odroid_defconfig | 1 - doc/driver-model/dm-pmic-framework.txt | 367 +++++++++++++ drivers/core/device.c | 15 + drivers/power/Makefile | 5 +- drivers/power/cmd_pmic.c | 820 +++++++++++++++++++++++++++++ drivers/power/pmic-uclass.c | 191 +++++++ drivers/power/pmic/Makefile | 1 + drivers/power/pmic/max77686.c | 102 ++++ drivers/power/pmic/pmic_max77686.c | 2 +- drivers/power/regulator-uclass.c | 227 ++++++++ drivers/power/regulator/Makefile | 8 + drivers/power/regulator/max77686.c | 926 +++++++++++++++++++++++++++++++++ include/configs/exynos5-common.h | 4 + include/configs/odroid.h | 9 +- include/dm/device.h | 16 + include/dm/uclass-id.h | 4 + include/power/max77686_pmic.h | 26 +- include/power/pmic.h | 265 ++++++++++ include/power/regulator.h | 310 +++++++++++ 24 files changed, 3573 insertions(+), 33 deletions(-)Quoted 8 lines
create mode 100644
doc/driver-model/dm-pmic-framework.txtcreate mode 100644drivers/power/cmd_pmic.ccreate mode 100644drivers/power/pmic-uclass.ccreate mode 100644drivers/power/pmic/max77686.ccreate mode 100644drivers/power/regulator-uclass.ccreate mode 100644drivers/power/regulator/Makefilecreate mode 100644drivers/power/regulator/max77686.ccreate mode 100644include/power/regulator.hThis is an impressive pieces of work! It will be great to get these in.
Here are some high-level comments on this series:
So, just as a summary of V3 rework.
Quoted 5 lines
Quoted 5 lines
1. I think regulator LDOs and bucks should be proper devices (struct udevice), bound by the pmic when it is probed. The advantages are
a. You can see them in the device list - the pmic will end up with a lot more children
This is done.
Quoted 3 lines
Quoted 3 lines
b. You can use the same regulator uclass for each, but have different operations for each driver (e.g. max77686 might provide two different drivers, one for LDO, one for buck).
This is done.
Quoted 1 line
Quoted 1 line
c. Things like your 'switch (type)' in
max7786_get_state()etc. will go away
This is done.
Quoted 3 lines
Quoted 3 lines
d. You can perform operations on them without having to specify their parent and number - e.g.
regulator_set_mode(struct udevice *ldo, int mode)which is much more natural for users
This is done.
Quoted 3 lines
Quoted 3 lines
e. You avoid needing your own list of regulators and bucks - struct
max7786_regulator_info. After all, keeping track of child devices is something that driver model can do
This is done. Now, each regulator device keeps the common regulator constraints as uclass private data (dev->uclass_priv) and the additional constraints for the fixed-regulator (gpio constraints) are kept as the device private data (dev->priv).
Quoted 6 lines
Quoted 6 lines
2. I see device tree support, but the Linux device tree bindings are not fully supported, e.g. the regulators sub-node uses regulator-compatible instead of regulator-name. I think it should be exactly the same (and we should copy the device tree files, only leaving out what we don't support)
This is done. Since the compatible is stored in a different property than just 'compatible', I added the function to bind devices by custom compatible property name. So regulators are bind by 'regulator-compatible' property compatibles
Quoted 10 lines
Quoted 10 lines
3. The I2C/SPI difference is a bit clunky. We should try to hide this away. The most obvious problem is in getting the device. Instead of
pmic_i2c_get()we should use the "power-supply" property in the device tree, so we need a function which can find the regulator given the device node (a bit likegpio_request_by_name()but for PMICs). Thepmic_get()function is OK and will be needed also, as I am sure we will use names in some places. We should remove any mention of the bus type from the API I think. Also regulator number seems and odd concept
- better to use the name/device tree link to find the right device.
This is done partially. My time was limited. The bus type and address is now removed from the api. I think that the 'pmic_get()' by the name should be ok, when we have different device-tree names for each pmic intarface.
From the other side this is not so needed, since we are going to
provide the device features by driver-model uclass drivers. This will take some time, so I add some extended function for getting the pmic in the next version.
The 'power-supply' seem to be right for all devices, I will work on it in the next version.
Quoted 4 lines
Quoted 4 lines
One way to avoid I2C/SPI problems is to create a helper file which allows you to read and write registers given a struct udevice. It could look at whether the device is I2C or SPI and do the right thing. This could be generally useful, not just for PMICs.
Yes, this would be useful, and actually will make something like the relationship for the pmic device and it's regulator child.
Quoted 2 lines
Quoted 2 lines
4. Should use
Kconfignow.
This is done.
Quoted 4 lines
Sorry I don't know how I forgot to mention this:
5. A test PMIC device for sandbox so that the tests can run (
test/dm/pmic.c).
This one, will be task for the future.
Quoted 4 lines
Regards,
Simon
Thank you again for the helpful suggestions!
Best regards,
Signature · 4 lines
Przemyslaw Marczak Samsung R&D Institute Poland Samsung Electronics p.marczak at samsung.com
v3 cover Power(full) framework based on Driver Model
In reply to Przemyslaw MarczakHello,
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(-) 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
Signature · 1 line
1.9.1
PATCH v3 1/17 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
@@ -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
PATCH v3 1/17 exynos5: fix build break by adding CONFIG_POWER
Quoted 9 lines · Przemyslaw Marczak
Move the configs listed below from
exynos5-dt-common.htoexynos5-common.h:
-CONFIG_POWER
-CONFIG_POWER_I2C
fixes build break for Arndale and Smdk5250 boards.Signed-off-by Przemyslaw Marczak <[email protected]>--- include/configs/exynos5-common.h | 4 ++++ 1 file changed, 4 insertions(+)
PATCH v3 2/17 fdt_ro.c: add new function: fdt_node_check_prop_compatible()
In reply to Przemyslaw MarczakThis commit:
- moves fdt_node_check_compatible() code to fdt_node_check_prop_compatible()
- adds call to fdt_node_check_prop_compatible() in fdt_node_check_compatible() with 'compatible' as the name of compatible property.
The function: fdt_node_check_compatible() - works the same as previous. The function fdt_node_check_prop_compatible() - allows for checking compatible string in given property name.
If some fdt node uses different name for compatible property, than 'compatible', then the function fdt_node_check_prop_compatible() can be used with the custom compatible property name as an argument.
--- include/libfdt.h | 27 +++++++++++++++++++++++++++ lib/libfdt/fdt_ro.c | 14 +++++++++++--- 2 files changed, 38 insertions(+), 3 deletions(-)
include/libfdt.h +27 -0
@@ -807,6 +807,33 @@ int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,int fdt_node_offset_by_phandle (const void *fdt,uint32_t phandle);/** +* fdt_node_check_prop_compatible: check a node's 'property_name' for compatible +* @fdt: pointer to the device tree blob +* @nodeoffset: offset of a tree node +* @property_name: name of property within looking for the 'compatible' string +* @compatible: string to match against +* +* +* fdt_node_check_prop_compatible() returns 0 if the given node contains a +* 'compatible' property with the given string as one of its elements, +* it returns non-zero otherwise, or on error. +* +* returns: +* 0, if the node has a 'compatible' property listing the given string +* 1, if the node has a 'compatible' property, but it does not list +* the given string +* -FDT_ERR_NOTFOUND, if the given node has no 'compatible' property +* -FDT_ERR_BADOFFSET, if nodeoffset does not refer to a BEGIN_NODE tag +* -FDT_ERR_BADMAGIC, +* -FDT_ERR_BADVERSION, +* -FDT_ERR_BADSTATE, +* -FDT_ERR_BADSTRUCTURE, standard meanings +*/ +int fdt_node_check_prop_compatible (const void *fdt,int nodeoffset, +const char *property_name, +const char *compatible); + +/** * fdt_node_check_compatible: check a node's compatible property * @fdt: pointer to the device tree blob * @nodeoffset: offset of a tree node
lib/libfdt/fdt_ro.c +11 -3
@@ -567,13 +567,14 @@ int fdt_get_string(const void *fdt, int node, const char *property,return fdt_get_string_index (fdt, node, property,0 , output); } -int fdt_node_check_compatible (const void *fdt,int nodeoffset, -const char *compatible) +int fdt_node_check_prop_compatible (const void *fdt,int nodeoffset, +const char *prop_name, +const char *compatible) {const void *prop;int len; - prop =fdt_getprop (fdt, nodeoffset,"compatible" , &len); + prop =fdt_getprop (fdt, nodeoffset, prop_name, &len);if (!prop)return len;if (fdt_stringlist_contains (prop, len, compatible))
@@ -582,6 +583,13 @@ int fdt_node_check_compatible(const void *fdt, int nodeoffset,return 1 ; } +int fdt_node_check_compatible (const void *fdt,int nodeoffset, +const char *compatible) +{ +return fdt_node_check_prop_compatible (fdt, nodeoffset,"compatible" , + compatible); +} +int fdt_node_offset_by_compatible (const void *fdt,int startoffset,const char *compatible) {
Signature · 1 line
1.9.1
PATCH v3 2/17 fdt_ro.c: add new function: fdt_node_check_prop_compatible()
Hi Przemyslaw,
Quoted 9 lines · Przemyslaw Marczak
This commit:
- movesfdt_node_check_compatible()code tofdt_node_check_prop_compatible()
- adds call tofdt_node_check_prop_compatible()infdt_node_check_compatible()with 'compatible' as the name of compatible property.The function:
fdt_node_check_compatible()- works the same as previous. The functionfdt_node_check_prop_compatible()- allows for checking compatible string in given property name.
Quoted 5 lines
If some fdt node uses different name for compatible property, than 'compatible', then the function
fdt_node_check_prop_compatible()can be used with the custom compatible property name as an argument.Signed-off-by Przemyslaw Marczak <[email protected]>
I doubt this would be accepted by libfdt upstream. I don't think we need it - see my cover letter response.
Regards,
Simon
PATCH v3 3/17 dm: core: lists.c: add new function lists_bind_fdt_by_prop()
In reply to Przemyslaw MarczakThis change adds new function: lists_bind_fdt_by_prop(), which can be used for bind the devices by custom property name for the compatible string.
The function lists_bind_fdt() works the same as previous.
--- drivers/core/lists.c | 28 +++++++++++++++++++--------- include/dm/lists.h | 18 ++++++++++++++++++ 2 files changed, 37 insertions(+), 9 deletions(-)
drivers/core/lists.c +19 -9
@@ -99,14 +99,17 @@ int device_bind_driver(struct udevice *parent, const char *drv_name,* @param blob: Device tree pointer * @param offset: Offset of node in device tree * @param of_match: List of compatible strings to match +* @param prop: Name of compatible string property * @param of_idp: Returns the match that was found * @return 0 if there is a match, -ENOENT if no match, -ENODEV if the node * does not have a compatible string, other error <0 if there is a device * tree error */ -static int driver_check_compatible (const void *blob,int offset, -const struct udevice_id *of_match, -const struct udevice_id **of_idp) +static int driver_check_prop_compatible (const void *blob, +int offset, +const char *prop, +const struct udevice_id *of_match, +const struct udevice_id **of_idp) {int ret;
@@ -115,8 +118,8 @@ static int driver_check_compatible(const void *blob, int offset,return -ENOENT ;while (of_match->compatible) { - ret =fdt_node_check_compatible (blob, offset, - of_match->compatible); + ret =fdt_node_check_prop_compatible (blob, offset, prop, + of_match->compatible);if (!ret) { *of_idp = of_match;return 0 ;
@@ -131,8 +134,8 @@ static int driver_check_compatible(const void *blob, int offset,return -ENOENT ; } -int lists_bind_fdt (struct udevice *parent,const void *blob,int offset, -struct udevice **devp) +int lists_bind_fdt_by_prop (struct udevice *parent,const void *blob,int offset, +const char *prop,struct udevice **devp) { struct driver *driver = ll_entry_start(struct driver, driver); const int n_ents = ll_entry_count(struct driver, driver);
@@ -148,8 +151,8 @@ int lists_bind_fdt(struct udevice *parent, const void *blob, int offset,if (devp) *devp =NULL ;for (entry = driver; entry != driver + n_ents; entry++) { - ret =driver_check_compatible (blob, offset, entry->of_match, - &id); + ret =driver_check_prop_compatible (blob, offset, prop, + entry->of_match, &id); name =fdt_get_name (blob, offset,NULL );if (ret == -ENOENT ) {continue ;
@@ -183,4 +186,11 @@ int lists_bind_fdt(struct udevice *parent, const void *blob, int offset, return result; } + +int lists_bind_fdt (struct udevice *parent,const void *blob,int offset, +struct udevice **devp) +{ +return lists_bind_fdt_by_prop (parent, blob, offset,"compatible" , devp); + +}#endif
include/dm/lists.h +18 -0
@@ -45,6 +45,24 @@ struct uclass_driver *lists_uclass_lookup(enum uclass_id id);int lists_bind_drivers (struct udevice *parent,bool pre_reloc_only);/** +* lists_bind_fdt_by_prop() - bind a device tree node by the given compatible +* property name. +* +* This creates a new device bound to the given device tree node, with +* @parent as its parent. +* +* @parent: parent device (root) +* @blob: device tree blob +* @offset: offset of this device tree node +* @prop: fdt property name within looking for the driver compatible string +* @devp: if non-NULL, returns a pointer to the bound device +* @return 0 if device was bound, -EINVAL if the device tree is invalid, +* other -ve value on error +*/ +int lists_bind_fdt_by_prop (struct udevice *parent,const void *blob,int offset, +const char *prop,struct udevice **devp); + +/** * lists_bind_fdt() - bind a device tree node * * This creates a new device bound to the given device tree node, with
Signature · 1 line
1.9.1
PATCH v3 3/17 dm: core: lists.c: add new function lists_bind_fdt_by_prop()
Hi Przemyslaw,
Quoted 10 lines · Przemyslaw Marczak
This change adds new function:
lists_bind_fdt_by_prop(), which can be used for bind the devices by custom property name for the compatible string.The function
lists_bind_fdt()works the same as previous.Signed-off-by Przemyslaw Marczak <[email protected]>--- drivers/core/lists.c | 28 +++++++++++++++++++--------- include/dm/lists.h | 18 ++++++++++++++++++ 2 files changed, 37 insertions(+), 9 deletions(-)
I think we should do this another way - see my cover letter response.
Regards,
Simon
PATCH v3 4/17 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
@@ -65,4 +65,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
PATCH v3 4/17 lib: Kconfig: add entry for errno_str() function
Quoted 4 lines · Przemyslaw Marczak
Signed-off-by Przemyslaw Marczak <[email protected]>--- lib/Kconfig | 8 ++++++++ 1 file changed, 8 insertions(+)
PATCH v3 5/17 dm: pmic: add implementation of driver model pmic uclass
In reply to Przemyslaw MarczakThis is an introduction to driver-model multi uclass PMIC support. It starts with UCLASS_PMIC - a common PMIC devices uclass type to provide device read/write operations only.
Beside two basic operations the pmic platform data is introduced, which provides basic informations about the pmic device I/O interface and is shared with all childs (and should also for childs new uclass types in the future).
Usually PMIC devices provides various functionalities with single or multiple I/O interfaces.
Using this new framework and new uclass types introduced in the future, it can be handle like this:
_ root device
| |_ BUS 0 device (e.g. I2C0) - UCLASS_I2C/SPI/... | |_ PMIC device 1 (read/write ops) - UCLASS_PMIC | |_ REGULATOR device (ldo/buck/... ops) - UCLASS_REGULATOR | |_ CHARGER device (charger ops) - UCLASS_CHARGER (in the future) | |_ MUIC device (microUSB con ops) - UCLASS_MUIC (in the future) | |_ ... | |_ BUS 1 device (e.g. I2C1) - UCLASS_I2C/SPI/...
|_ PMIC device 2 (read/write ops) - UCLASS_PMIC
|_ RTC device (rtc ops) - UCLASS_MUIC (in the future)
For each PMIC device interface, new UCLASS_PMIC device is bind with proper pmic driver, and it's child devices provides some specified operations.
All new definitions can be found in file:
- 'include/power/pmic.h'
Uclass file:
- pmic-uclass.c - provides a common code for UCLASS_PMIC device drivers
The old pmic framework is still kept and is independent.
Changes:
- new uclass-id: UCLASS_PMIC
- new config: CONFIG_DM_PMIC
New pmic api is documented in: doc/driver-model/pmic-framework.txt
---
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
--- drivers/power/Kconfig | 68 ++++++++++++++ drivers/power/Makefile | 1 + drivers/power/pmic-uclass.c | 130 +++++++++++++++++++++++++++ include/dm/uclass-id.h | 3 + include/power/pmic.h | 210 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 412 insertions(+) create mode 100644 drivers/power/pmic-uclass.c
drivers/power/Kconfig +68 -0
@@ -1,3 +1,71 @@ +config DM_PMIC + bool "Enable Driver Model for PMIC drivers (UCLASS_PMIC)" + depends on DM + ---help--- + This config enables the driver-model multi uclass PMIC support. + Its basic uclass type is: UCLASS_PMIC, which is designed to provide + a common I/O interface for pmic child devices of various uclass types. + + Usually PMIC IC's provides more than one functionality, which means + that we should implement new uclass operations for each one. Usually + PMIC's provide those various functionalities by one or more interfaces. + And this could looks like this: + + root device + |_ BUS 0 device (e.g. I2C0) - UCLASS_I2C/SPI/... + | |_ PMIC device (READ/WRITE ops) - UCLASS_PMIC + | | (pmic sub-devices) + | |_ REGULATOR device (ldo/buck/... ops) - UCLASS_REGULATOR + | |_ CHARGER device (charger ops) - UCLASS_CHARGER (future) + | |_ MUIC device (microUSB connector ops) - UCLASS_MUIC (future) + | |_ ... + | + |_ BUS 1 device (e.g. I2C1) - UCLASS_I2C/SPI/... + |_ PMIC device (READ/WRITE ops) - UCLASS_PMIC + | (pmic sub-devices) + |_ RTC device (rtc ops) - UCLASS_MUIC (future) + + From the I/O interface point of view, there can be found two PMIC types: + - single I/O interface - then UCLASS_PMIC device should be a parent of + all pmic sub-devices, where each is usually different uclass type, but + need to access the same interface + + - multiple I/O interfaces - 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. + + For each case, binding should be done automatically. If only 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: + | (pmic sub-devices) + |_ regulator (child) + |_ charger (child) + |_ other (child) + + The same for other I/O bus nodes, if pmic uses more then one interface. + + Note: + Each PMIC interface driver should use different compatible string. + + There are few basic functions in the UCLASS_PMIC driver API, declared + in the file 'include/power/pmic.h': + - int pmic_get(...); + - int pmic_read(struct udevice *pmic, ...); + - int pmic_write(struct udevice *pmic, ...); + For the simple implementation, in some cases the pmic uclass device, + can be self-sufficient to drive the PMIC functionality. In other case, + if each pmic sub-device(child) driver need access to the pmic specified + registers, it need to know only the register address and then the access + is done through the parent pmic driver. Like in the example: + _ root driver + |_ dev: bus I2C0 - UCLASS_I2C + | |_ dev: my_pmic (read/write) (parent) - UCLASS_PMIC + | |_ dev: my_regulator (set value/etc.) (child) - UCLASS_REGULATOR + So the call will looks like below: + 'pmic_write(regulator->parent, addr, value, len);' + config AXP221_POWER boolean "axp221 / axp223 pmic support" depends on MACH_SUN6I || MACH_SUN8I
drivers/power/Makefile +1 -0
@@ -21,3 +21,4 @@ obj-$(CONFIG_DIALOG_POWER) += power_dialog.o obj-$(CONFIG_POWER_FSL) += power_fsl.o obj-$(CONFIG_POWER_I2C) += power_i2c.o obj-$(CONFIG_POWER_SPI) += power_spi.o +obj-$(CONFIG_DM_PMIC) += pmic-uclass.o
drivers/power/pmic-uclass.c new file +130 -0
130 lines not on this page · raw message
include/dm/uclass-id.h +3 -0
@@ -35,6 +35,9 @@ enum uclass_id {UCLASS_I2C_EEPROM ,/* I2C EEPROM device */ UCLASS_MOD_EXP ,/* RSA Mod Exp device */ +/* PMIC uclass and PMIC-related uclass types */ +UCLASS_PMIC , +UCLASS_COUNT , UCLASS_INVALID = -1, };
include/power/pmic.h +210 -0
237 lines not on this page · raw message
Signature · 1 line
1.9.1
PATCH v3 5/17 dm: pmic: add implementation of driver model pmic uclass
Hi Prazemyslaw,
Quoted 3 lines · Przemyslaw Marczak
This is an introduction to driver-model multi uclass PMIC support. It starts with
UCLASS_PMIC- a common PMIC devices uclass type to provide device read/write operations only.
Your Kconfig docs are a model to others! It describes the function very nicely without a lot of words.
Please excuse the nits, they are intended to help it read better.
Quoted 72 lines
Beside two basic operations the pmic platform data is introduced, which provides basic informations about the pmic device I/O interface and is shared with all childs (and should also for childs new uclass types in the future).
Usually PMIC devices provides various functionalities with single or multiple I/O interfaces.
Using this new framework and new uclass types introduced in the future, it can be handle like this:_ root device
| |_ BUS 0 device (e.g. I2C0) - UCLASS_I2C/SPI/... | |_ PMIC device 1 (read/write ops) - UCLASS_PMIC | |_ REGULATOR device (ldo/buck/... ops) - UCLASS_REGULATOR | |_ CHARGER device (charger ops) - UCLASS_CHARGER (in the future) | |_ MUIC device (microUSB con ops) - UCLASS_MUIC (in the future) | |_ ... | |_ BUS 1 device (e.g. I2C1) - UCLASS_I2C/SPI/...|_ PMIC device 2 (read/write ops) -
UCLASS_PMIC
|_ RTC device (rtc ops) -UCLASS_MUIC(in the future)For each PMIC device interface, new
UCLASS_PMICdevice is bind with proper pmic driver, and it's child devices provides some specified operations.All new definitions can be found in file:
- 'include/power/pmic.h'Uclass file:
-pmic-uclass.c- provides a common code forUCLASS_PMICdevice driversThe old pmic framework is still kept and is independent.
Changes:
- new uclass-id:UCLASS_PMIC
- new config:CONFIG_DM_PMICNew pmic api is documented in:
doc/driver-model/pmic-framework.txtSigned-off-by Przemyslaw Marczak <[email protected]>---
Changes V2:
- pmic uclass: adjust uclass code to the mainline changes
- pmic uclass: removepmic_i2candpmic_spi
- pmic uclass: modifypmic_platdata
- pmic uclass: add pmic_if_* functions
- pmic uclass: removepmic_init_dm()
- pmic uclass: cleanup
-pmic.h: define pmic ops structure (read/write operations)
-pmic.h: add comments to functionsChanges V3:
-pmic-uclass.candpmic.h:
-- remove pmic_if_* functions
-- add new functionpmic_child_node_scan()
- addKconfigentry--- drivers/power/Kconfig | 68 ++++++++++++++ drivers/power/Makefile | 1 + drivers/power/pmic-uclass.c | 130 +++++++++++++++++++++++++++ include/dm/uclass-id.h | 3 + include/power/pmic.h | 210 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 412 insertions(+) create mode 100644 drivers/power/pmic-uclass.cdrivers/power/Kconfig +0
-0
drivers/power/Kconfig line 7
Quoted 7 lines
drivers/power/Kconfig +7
-0@@ -1,3 +1,71 @@ +config DM_PMIC + bool "Enable Driver Model for PMIC drivers (UCLASS_PMIC)" + depends on DM + ---help--- + This config enables the driver-model multi uclass PMIC support. + Its basic uclass type is: UCLASS_PMIC, which is designed to provide + a common I/O interface for pmic child devices of various uclass types.
Should be consistent - and use PMIC instead pmic.
drivers/power/Kconfig line 9
Quoted 2 lines
drivers/power/Kconfig +2
-0+ + Usually PMIC IC's provides more than one functionality, which means
s/functionality/function/
drivers/power/Kconfig line 11
Quoted 2 lines
drivers/power/Kconfig +2
-0+ that we should implement new uclass operations for each one. Usually + PMIC's provide those various functionalities by one or more interfaces.
functions
Quoted 5 lines
drivers/power/Kconfig +5
-0+ And this could looks like this: + + root device + |_ BUS 0 device (e.g. I2C0) - UCLASS_I2C/SPI/... + | |_ PMIC device (READ/WRITE ops) - UCLASS_PMIC
drivers/power/Kconfig line 26
Quoted 10 lines
drivers/power/Kconfig +10
-0+ | | (pmic sub-devices) + | |_ REGULATOR device (ldo/buck/... ops) - UCLASS_REGULATOR + | |_ CHARGER device (charger ops) - UCLASS_CHARGER (future) + | |_ MUIC device (microUSB connector ops) - UCLASS_MUIC (future) + | |_ ... + | + |_ BUS 1 device (e.g. I2C1) - UCLASS_I2C/SPI/... + |_ PMIC device (READ/WRITE ops) - UCLASS_PMIC + | (pmic sub-devices) + |_ RTC device (rtc ops) - UCLASS_MUIC (future)
Would this be UCLASS_RTC?
drivers/power/Kconfig line 37
Quoted 11 lines
drivers/power/Kconfig +11
-0+ + From the I/O interface point of view, there can be found two PMIC types: + - single I/O interface - then UCLASS_PMIC device should be a parent of + all pmic sub-devices, where each is usually different uclass type, but + need to access the same interface + + - multiple I/O interfaces - 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. + + For each case, binding should be done automatically. If only device tree
Remove the word 'only'?
drivers/power/Kconfig line 38
Quoted 1 line
drivers/power/Kconfig +1
-0+ nodes/subnodes are proper defined, then:
how about a blank line here?
drivers/power/Kconfig line 50
Quoted 12 lines
drivers/power/Kconfig +12
-0+ |_ 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: + | (pmic sub-devices) + |_ regulator (child) + |_ charger (child) + |_ other (child) + + The same for other I/O bus nodes, if pmic uses more then one interface. + + Note: + Each PMIC interface driver should use different compatible string.
use a different
drivers/power/Kconfig line 52
Quoted 2 lines
drivers/power/Kconfig +2
-0+ + There are few basic functions in the UCLASS_PMIC driver API, declared
There are a few
drivers/power/Kconfig line 58
Quoted 6 lines
drivers/power/Kconfig +6
-0+ in the file 'include/power/pmic.h': + - int pmic_get(...); + - int pmic_read(struct udevice *pmic, ...); + - int pmic_write(struct udevice *pmic, ...); + For the simple implementation, in some cases the pmic uclass device, + can be self-sufficient to drive the PMIC functionality. In other case,
s/self-sufficient/enough/
drivers/power/Kconfig line 59
Quoted 1 line
drivers/power/Kconfig +1
-0+ if each pmic sub-device(child) driver need access to the pmic specified
PMIC-specified
drivers/power/Kconfig line 60
Quoted 1 line
drivers/power/Kconfig +1
-0+ registers, it need to know only the register address and then the access
s/to//
drivers/power/Kconfig line 61
Quoted 1 line
drivers/power/Kconfig +1
-0+ is done through the parent pmic driver. Like in the example:
s/is/can be/
For example: (blank line here?)
Quoted 52 lines
drivers/power/Kconfig +7
-0+ _ root driver + |_ dev: bus I2C0 - UCLASS_I2C + | |_ dev: my_pmic (read/write) (parent) - UCLASS_PMIC + | |_ dev: my_regulator (set value/etc.) (child) - UCLASS_REGULATOR + So the call will looks like below: + 'pmic_write(regulator->parent, addr, value, len);' + config AXP221_POWER boolean "axp221 / axp223 pmic support" depends on MACH_SUN6I || MACH_SUN8Idrivers/power/Makefile +1
-0@@ -21,3 +21,4 @@ obj-$(CONFIG_DIALOG_POWER) += power_dialog.o obj-$(CONFIG_POWER_FSL) += power_fsl.o obj-$(CONFIG_POWER_I2C) += power_i2c.o obj-$(CONFIG_POWER_SPI) += power_spi.o +obj-$(CONFIG_DM_PMIC) += pmic-uclass.odrivers/power/pmic-uclass.c new file +27
-0@@ -0,0 +1,130 @@ +/* +* Copyright (C) 2014-2015 Samsung Electronics +* Przemyslaw Marczak <[email protected]> +* +* SPDX-License-Identifier: GPL-2.0+ +*/ +#include <common.h> +#include <linux/types.h> +#include <fdtdec.h> +#include <dm.h> +#include <power/pmic.h> +#include <dm/device-internal.h> +#include <dm/uclass-internal.h> +#include <dm/root.h> +#include <dm/lists.h> +#include <compiler.h> +#include <errno.h> + +DECLARE_GLOBAL_DATA_PTR ; + +int pmic_get (char *name,struct udevice **devp) +{ +struct udevice *dev; +int ret; + + *devp =NULL ; +
drivers/power/pmic-uclass.c line 37
Quoted 10 lines
drivers/power/pmic-uclass.c new file +10
-0+for (ret =uclass_first_device (UCLASS_PMIC , &dev); + dev; + ret =uclass_next_device (&dev)) { +if (!strcmp (name, dev->name)) { + *devp = dev; +return ret; + } + } + +return -ENODEV ;
This function will probe every PMIC, looking for the correct one.
I think you should change pmic_get() to call a core function in uclass.c, like uclass_get_device_by_name(). It should use uclass_foreach_dev() so that it doesn't probe anything except the one it finds.You can use uclass_get_device_tail() at the end of that function - see uclass_get_device_by_of_offset() as an example.
Quoted 13 lines
drivers/power/pmic-uclass.c new file +13
-0+} + +int pmic_reg_count (struct udevice *dev) +{ +const struct dm_pmic_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_PMIC ); +if (!ops) +return -ENODEV ; + +return ops->reg_count; +} +
drivers/power/pmic-uclass.c line 60
Quoted 10 lines
drivers/power/pmic-uclass.c new file +10
-0+int pmic_read (struct udevice *dev,uint reg,uint8_t *buffer,int len) +{ +const struct dm_pmic_ops *ops; + +if (!buffer) +return -EFAULT ; + + ops =pmic_get_uclass_ops (dev,UCLASS_PMIC ); +if (!ops) +return -ENODEV ;
-ENOSYS, although IMO assert() would be OK.
drivers/power/pmic-uclass.c line 63
Quoted 3 lines
drivers/power/pmic-uclass.c new file +3
-0+ +if (!ops->read) +return -EPERM ;
-ENOSYS
drivers/power/pmic-uclass.c line 66
Quoted 3 lines
drivers/power/pmic-uclass.c new file +3
-0+ +if (ops->read (dev, reg, buffer, len)) +return -EIO ;
We must not swallow errors.
ret = ops->read(...)
if (ret)
return ret;
Please adjust below also.
Quoted 69 lines
drivers/power/pmic-uclass.c new file +64
-0+ +return 0 ; +} + +int pmic_write (struct udevice *dev,uint reg,uint8_t *buffer,int len) +{ +const struct dm_pmic_ops *ops; + +if (!buffer) +return -EFAULT ; + + ops =pmic_get_uclass_ops (dev,UCLASS_PMIC ); +if (!ops) +return -ENODEV ; + +if (!ops->write) +return -EPERM ; + +if (ops->write (dev, reg, buffer, len)) +return -EIO ; + +return 0 ; +} + +int pmic_child_node_scan (struct udevice *parent, +const char *optional_subnode, +const char *compatible_property_name) +{ +const void *blob = gd->fdt_blob; +struct udevice *childp; +int offset = parent->of_offset; +int childs =0 ; +int ret; + +debug ("%s: bind child for %s\n" , __func__, parent->name); + +if (optional_subnode) { +debug ("Looking for %s optional subnode: %s \n" , parent->name, + optional_subnode); + offset =fdt_subnode_offset (blob, offset, optional_subnode); +if (offset <=0 ) { +debug ("Pmic: %s subnode: %s not found!" , + parent->name, optional_subnode); +return -ENXIO ; + } + } + +for (offset =fdt_first_subnode (blob, offset); offset >0 ; + offset =fdt_next_subnode (blob, offset)) { + ret =lists_bind_fdt_by_prop (parent, blob, offset, + compatible_property_name, &childp); +if (ret) +continue ; + + childs++; + } + +return childs; +} + +UCLASS_DRIVER (pmic) = { + .id =UCLASS_PMIC , + .name ="pmic" , +};include/dm/uclass-id.h +0
-0
include/dm/uclass-id.h enum uclass_id { · line 38
Quoted 4 lines
include/dm/uclass-id.h +1
-0@@ -35,6 +35,9 @@ enum uclass_id {UCLASS_I2C_EEPROM ,/* I2C EEPROM device */ UCLASS_MOD_EXP, /* RSA Mod Exp device */ +/* PMIC uclass and PMIC-related uclass types */
This comment seemed confusing - is it for PMICs or other things also?
Quoted 32 lines
include/dm/uclass-id.h +2
-0+UCLASS_PMIC , +UCLASS_COUNT , UCLASS_INVALID = -1, };include/power/pmic.h +6
-0@@ -1,4 +1,7 @@/* +* Copyright (C) 2014-2015 Samsung Electronics +* Przemyslaw Marczak <[email protected]> +* * Copyright (C) 2011-2012 Samsung Electronics * Lukasz Majewski <[email protected]> * @@ -9,10 +12,13 @@#define __CORE_PMIC_H_#include <linux/list.h> +#include <spi.h> #include <i2c.h> #include <power/power_chrg.h> 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 , };
include/power/pmic.h struct pmic { · line 92
Quoted 10 lines
include/power/pmic.h +7
-0@@ -77,7 +83,210 @@ struct pmic {struct pmic *parent; struct list_head list; }; +#endif /* CONFIG_POWER */ + +#ifdef CONFIG_DM_PMIC +/** +* Driver model pmic framework. +* The PMIC_UCLASS uclass is designed to provide a common I/O +* interface for pmic child devices of various uclass types.
I worry about having the docs in multiple places. Should you adjust this to point to the Kconfig? Or change the Kconfig to point here? Or maybe it would be better to drop both and put these in your README? I am concerned that if we later change something, we end up with inconsistent docs.
Quoted 88 lines
include/power/pmic.h +88
-0+* +* Usually PMIC devices provides more than one functionality, +* which means that we should implement uclass operations for +* each functionality - one driver per uclass. +* +* And usually PMIC devices provide those various functionalities +* by one or more interfaces. And this could looks 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/... +* |_ PMIC device (READ/WRITE ops) - UCLASS_PMIC +* |_ RTC device (rtc ops) - UCLASS_MUIC (in the future) +* +* Two PMIC types are possible: +* - single I/O interface +* 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 +* 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. +* +* For each case binding should be done automatically. If only 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) +* +* The same for other bus nodes, if pmic uses more then one interface. +* +* Note: +* Each PMIC interface driver should use different compatible string. +* +* If each pmic child device driver need access the pmic specified registers, +* it need to know only the register address and the access is 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 by the call +* to 'pmic_child_node_scan()' - it allows bind in optional subnode and with +* optional compatible property, e.g. "regulator-compatible" or "regulator". +* +* my_pmic.c - pmic driver: +* +* int my_pmic_bind(struct udevice *my_pmic) +* { +* ... +* ret = pmic_child_node_scan(my_pmic, NULL, "compatible"); +* ... +* ... +* } +* +* my_regulator.c - regulator driver (child of pmic I/O driver): +* +* int my_regulator_set_value(struct udevice *dev, int type, int num, int *val) +* { +* ... +* some_val = ...; +* +* // dev->parent == my_pmic +* pmic_write(dev->parent, some_reg, some_val); +* ... +* } +* +* In this example pmic driver is always a parent for other pmic devices. +*/ + +/** +* struct dm_pmic_ops - PMIC device I/O interface +* +* Should be implemented by UCLASS_PMIC device drivers. The standard
include/power/pmic.h struct pmic { · line 190
Quoted 10 lines
include/power/pmic.h +10
-0+* 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; +int (*read)(struct udevice *dev,uint reg,uint8_t *buffer,int len); +int (*write)(struct udevice *dev,uint reg,uint8_t *buffer,int len);
nit: const uint8_t *buffer?
Quoted 46 lines
include/power/pmic.h +46
-0+}; + +/* enum pmic_op_type - used for various pmic devices operation calls, +* 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 , +}; + +/** +* pmic_get_uclass_ops - inline function for getting device uclass operations +* +* @dev - device to check +* @uclass_id - device uclass id +* +* Returns: +* void pointer to device operations or NULL pointer on error +*/ +static __inline__const void *pmic_get_uclass_ops (struct udevice *dev, +int uclass_id) +{ +const void *ops; + +if (!dev) +return NULL ; + +if (dev->driver->id != uclass_id) +return NULL ; + + ops = dev->driver->ops; +if (!ops) +return NULL ; + +return ops; +} + +/* drivers/power/pmic-uclass.c */ + +/** +* pmic_child_node_scan - scan the pmic node or its 'optional_subnode' for its +* childs, by the compatible property name given by arg 'compatible_prop_name'. +*
include/power/pmic.h struct pmic { · line 246
Quoted 10 lines
include/power/pmic.h +10
-0+* Few dts files with a different pmic regulators, uses different property +* name for its driver 'compatible' string, like: +* - 'compatible' +* 'regulator-compatible' +* The pmic driver should should bind its devices by proper compatible property +* name. +* +* @parent - pmic parent device (usually UCLASS_PMIC) +* @optional_subnode - optional pmic subnode with the childs within it +* @compatible_property_name - e.g.: 'compatible'; 'regulator-compatible', ...
@return
include/power/pmic.h struct pmic { · line 257
Quoted 11 lines
include/power/pmic.h +11
-0+*/ +int pmic_child_node_scan (struct udevice *parent, +const char *optional_subnode, +const char *compatible_property_name); + +/** +* pmic_get: get the pmic device using its name +* +* @name - device name +* @devp - returned pointer to the pmic device +* Returns: 0 on success or negative value of errno.
* @return 0 on success or negative value of errno.
Quoted 14 lines
include/power/pmic.h +14
-0+* +* The returned devp device can be used with pmic_read/write calls +*/ +int pmic_get (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 +* +* Returns: register count value on success or negative value of errno. +*/
include/power/pmic.h struct pmic { · line 281
Quoted 10 lines
include/power/pmic.h +10
-0+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 +* @val - value for write or its pointer to read
This doesn't match the functions.
include/power/pmic.h struct pmic { · line 286
Quoted 5 lines
include/power/pmic.h +5
-0+* +* Returns: 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,uint8_t *buffer,int len);
const uint8_t buffer for pmic_write()?
Quoted 15 lines
include/power/pmic.h +3
-1+#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 +297,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
PATCH v3 5/17 dm: pmic: add implementation of driver model pmic uclass
Hello Simon,
Quoted 12 lines · Simon Glass
Hi Prazemyslaw,
Quoted 3 lines · Przemyslaw Marczak
This is an introduction to driver-model multi uclass PMIC support. It starts with
UCLASS_PMIC- a common PMIC devices uclass type to provide device read/write operations only.Your
Kconfigdocs are a model to others! It describes the function very nicely without a lot of words.Please excuse the nits, they are intended to help it read better.
That's ok, it's better to fix if needs.
Quoted 163 lines
Quoted 72 lines
Beside two basic operations the pmic platform data is introduced, which provides basic informations about the pmic device I/O interface and is shared with all childs (and should also for childs new uclass types in the future).
Usually PMIC devices provides various functionalities with single or multiple I/O interfaces.
Using this new framework and new uclass types introduced in the future, it can be handle like this:_ root device
| |_ BUS 0 device (e.g. I2C0) - UCLASS_I2C/SPI/... | |_ PMIC device 1 (read/write ops) - UCLASS_PMIC | |_ REGULATOR device (ldo/buck/... ops) - UCLASS_REGULATOR | |_ CHARGER device (charger ops) - UCLASS_CHARGER (in the future) | |_ MUIC device (microUSB con ops) - UCLASS_MUIC (in the future) | |_ ... | |_ BUS 1 device (e.g. I2C1) - UCLASS_I2C/SPI/...|_ PMIC device 2 (read/write ops) -
UCLASS_PMIC
|_ RTC device (rtc ops) -UCLASS_MUIC(in the future)For each PMIC device interface, new
UCLASS_PMICdevice is bind with proper pmic driver, and it's child devices provides some specified operations.All new definitions can be found in file:
- 'include/power/pmic.h'Uclass file:
-pmic-uclass.c- provides a common code forUCLASS_PMICdevice driversThe old pmic framework is still kept and is independent.
Changes:
- new uclass-id:UCLASS_PMIC
- new config:CONFIG_DM_PMICNew pmic api is documented in:
doc/driver-model/pmic-framework.txtSigned-off-by Przemyslaw Marczak <[email protected]>---
Changes V2:
- pmic uclass: adjust uclass code to the mainline changes
- pmic uclass: removepmic_i2candpmic_spi
- pmic uclass: modifypmic_platdata
- pmic uclass: add pmic_if_* functions
- pmic uclass: removepmic_init_dm()
- pmic uclass: cleanup
-pmic.h: define pmic ops structure (read/write operations)
-pmic.h: add comments to functionsChanges V3:
-pmic-uclass.candpmic.h:
-- remove pmic_if_* functions
-- add new functionpmic_child_node_scan()
- addKconfigentry--- drivers/power/Kconfig | 68 ++++++++++++++ drivers/power/Makefile | 1 + drivers/power/pmic-uclass.c | 130 +++++++++++++++++++++++++++ include/dm/uclass-id.h | 3 + include/power/pmic.h | 210 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 412 insertions(+)create mode 100644
drivers/power/pmic-uclass.cdrivers/power/Kconfig +0
-0drivers/power/Kconfig line 7
Quoted 7 lines
drivers/power/Kconfig +7
-0@@ -1,3 +1,71 @@ +config DM_PMIC + bool "Enable Driver Model for PMIC drivers (UCLASS_PMIC)" + depends on DM + ---help--- + This config enables the driver-model multi uclass PMIC support. + Its basic uclass type is: UCLASS_PMIC, which is designed to provide + a common I/O interface for pmic child devices of various uclass types.Should be consistent - and use PMIC instead pmic.
drivers/power/Kconfig line 9
Quoted 2 lines
drivers/power/Kconfig +2
-0+ + Usually PMIC IC's provides more than one functionality, which meanss/functionality/function/
drivers/power/Kconfig line 11
Quoted 2 lines
drivers/power/Kconfig +2
-0+ that we should implement new uclass operations for each one. Usually + PMIC's provide those various functionalities by one or more interfaces.functions
Quoted 5 lines
drivers/power/Kconfig +5
-0+ And this could looks like this: + + root device + |_ BUS 0 device (e.g. I2C0) - UCLASS_I2C/SPI/... + | |_ PMIC device (READ/WRITE ops) - UCLASS_PMICdrivers/power/Kconfig line 26
Quoted 10 lines
drivers/power/Kconfig +10
-0+ | | (pmic sub-devices) + | |_ REGULATOR device (ldo/buck/... ops) - UCLASS_REGULATOR + | |_ CHARGER device (charger ops) - UCLASS_CHARGER (future) + | |_ MUIC device (microUSB connector ops) - UCLASS_MUIC (future) + | |_ ... + | + |_ BUS 1 device (e.g. I2C1) - UCLASS_I2C/SPI/... + |_ PMIC device (READ/WRITE ops) - UCLASS_PMIC + | (pmic sub-devices) + |_ RTC device (rtc ops) - UCLASS_MUIC (future)Would this be
UCLASS_RTC?drivers/power/Kconfig line 37
Quoted 11 lines
drivers/power/Kconfig +11
-0+ + From the I/O interface point of view, there can be found two PMIC types: + - single I/O interface - then UCLASS_PMIC device should be a parent of + all pmic sub-devices, where each is usually different uclass type, but + need to access the same interface + + - multiple I/O interfaces - 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. + + For each case, binding should be done automatically. If only device treeRemove the word 'only'?
drivers/power/Kconfig line 38
Quoted 1 line
drivers/power/Kconfig +1
-0+ nodes/subnodes are proper defined, then:how about a blank line here?
drivers/power/Kconfig line 50
Quoted 12 lines
drivers/power/Kconfig +12
-0+ |_ 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: + | (pmic sub-devices) + |_ regulator (child) + |_ charger (child) + |_ other (child) + + The same for other I/O bus nodes, if pmic uses more then one interface. + + Note: + Each PMIC interface driver should use different compatible string.use a different
drivers/power/Kconfig line 52
Quoted 2 lines
drivers/power/Kconfig +2
-0+ + There are few basic functions in the UCLASS_PMIC driver API, declaredThere are a few
drivers/power/Kconfig line 58
Quoted 6 lines
drivers/power/Kconfig +6
-0+ in the file 'include/power/pmic.h': + - int pmic_get(...); + - int pmic_read(struct udevice *pmic, ...); + - int pmic_write(struct udevice *pmic, ...); + For the simple implementation, in some cases the pmic uclass device, + can be self-sufficient to drive the PMIC functionality. In other case,s/self-sufficient/enough/
drivers/power/Kconfig line 59
Quoted 1 line
drivers/power/Kconfig +1
-0+ if each pmic sub-device(child) driver need access to the pmic specifiedPMIC-specified
drivers/power/Kconfig line 60
Quoted 1 line
drivers/power/Kconfig +1
-0+ registers, it need to know only the register address and then the access
Quoted 8 lines
s/to//
drivers/power/Kconfig line 61
Quoted 1 line
drivers/power/Kconfig +1
-0+ is done through the parent pmic driver. Like in the example:s/is/can be/
For example: (blank line here?)
Thanks, will fix the all above.
Quoted 65 lines
Quoted 52 lines
drivers/power/Kconfig +7
-0+ _ root driver + |_ dev: bus I2C0 - UCLASS_I2C + | |_ dev: my_pmic (read/write) (parent) - UCLASS_PMIC + | |_ dev: my_regulator (set value/etc.) (child) - UCLASS_REGULATOR + So the call will looks like below: + 'pmic_write(regulator->parent, addr, value, len);' + config AXP221_POWER boolean "axp221 / axp223 pmic support" depends on MACH_SUN6I || MACH_SUN8Idrivers/power/Makefile +1
-0@@ -21,3 +21,4 @@ obj-$(CONFIG_DIALOG_POWER) += power_dialog.o obj-$(CONFIG_POWER_FSL) += power_fsl.o obj-$(CONFIG_POWER_I2C) += power_i2c.o obj-$(CONFIG_POWER_SPI) += power_spi.o +obj-$(CONFIG_DM_PMIC) += pmic-uclass.odrivers/power/pmic-uclass.c new file +27
-0@@ -0,0 +1,130 @@ +/* +* Copyright (C) 2014-2015 Samsung Electronics +* Przemyslaw Marczak <[email protected]> +* +* SPDX-License-Identifier: GPL-2.0+ +*/ +#include <common.h> +#include <linux/types.h> +#include <fdtdec.h> +#include <dm.h> +#include <power/pmic.h> +#include <dm/device-internal.h> +#include <dm/uclass-internal.h> +#include <dm/root.h> +#include <dm/lists.h> +#include <compiler.h> +#include <errno.h> + +DECLARE_GLOBAL_DATA_PTR ; + +int pmic_get (char *name,struct udevice **devp) +{ +struct udevice *dev; +int ret; + + *devp =NULL ; +drivers/power/pmic-uclass.c line 37
Quoted 10 lines
drivers/power/pmic-uclass.c new file +10
-0+for (ret =uclass_first_device (UCLASS_PMIC , &dev); + dev; + ret =uclass_next_device (&dev)) { +if (!strcmp (name, dev->name)) { + *devp = dev; +return ret; + } + } + +return -ENODEV ;This function will probe every PMIC, looking for the correct one.
Quoted 6 lines
I think you should change
pmic_get()to call a core function inuclass.c, likeuclass_get_device_by_name(). It should useuclass_foreach_dev()so that it doesn't probe anything except the one it finds.You can useuclass_get_device_tail()at the end of that function - seeuclass_get_device_by_of_offset()as an example.
Right, this is not good. The sequence, which you described, was in V2 of this code. I will adjust it and move to uclass.c.
Quoted 36 lines
Quoted 13 lines
drivers/power/pmic-uclass.c new file +13
-0+} + +int pmic_reg_count (struct udevice *dev) +{ +const struct dm_pmic_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_PMIC ); +if (!ops) +return -ENODEV ; + +return ops->reg_count; +} +drivers/power/pmic-uclass.c line 60
Quoted 10 lines
drivers/power/pmic-uclass.c new file +10
-0+int pmic_read (struct udevice *dev,uint reg,uint8_t *buffer,int len) +{ +const struct dm_pmic_ops *ops; + +if (!buffer) +return -EFAULT ; + + ops =pmic_get_uclass_ops (dev,UCLASS_PMIC ); +if (!ops) +return -ENODEV ;
-ENOSYS, although IMOassert()would be OK.drivers/power/pmic-uclass.c line 63
Quoted 3 lines
drivers/power/pmic-uclass.c new file +3
-0+ +if (!ops->read) +return -EPERM ;
-ENOSYSdrivers/power/pmic-uclass.c line 66
Quoted 3 lines
drivers/power/pmic-uclass.c new file +3
-0+ +if (ops->read (dev, reg, buffer, len)) +return -EIO ;
Quoted 8 lines
We must not swallow errors.
ret =
ops->read(...)
if (ret)return ret;Please adjust below also.
Right, will fix.
Quoted 72 lines
Quoted 72 lines
drivers/power/pmic-uclass.c new file +64
-0+ +return 0 ; +} + +int pmic_write (struct udevice *dev,uint reg,uint8_t *buffer,int len) +{ +const struct dm_pmic_ops *ops; + +if (!buffer) +return -EFAULT ; + + ops =pmic_get_uclass_ops (dev,UCLASS_PMIC ); +if (!ops) +return -ENODEV ; + +if (!ops->write) +return -EPERM ; + +if (ops->write (dev, reg, buffer, len)) +return -EIO ; + +return 0 ; +} + +int pmic_child_node_scan (struct udevice *parent, +const char *optional_subnode, +const char *compatible_property_name) +{ +const void *blob = gd->fdt_blob; +struct udevice *childp; +int offset = parent->of_offset; +int childs =0 ; +int ret; + +debug ("%s: bind child for %s\n" , __func__, parent->name); + +if (optional_subnode) { +debug ("Looking for %s optional subnode: %s \n" , parent->name, + optional_subnode); + offset =fdt_subnode_offset (blob, offset, optional_subnode); +if (offset <=0 ) { +debug ("Pmic: %s subnode: %s not found!" , + parent->name, optional_subnode); +return -ENXIO ; + } + } + +for (offset =fdt_first_subnode (blob, offset); offset >0 ; + offset =fdt_next_subnode (blob, offset)) { + ret =lists_bind_fdt_by_prop (parent, blob, offset, + compatible_property_name, &childp); +if (ret) +continue ; + + childs++; + } + +return childs; +} + +UCLASS_DRIVER (pmic) = { + .id =UCLASS_PMIC , + .name ="pmic" , +};include/dm/uclass-id.h +0
-0@@ -35,6 +35,9 @@ enum uclass_id {UCLASS_I2C_EEPROM ,/* I2C EEPROM device */ UCLASS_MOD_EXP, /* RSA Mod Exp device */
Quoted 4 lines
include/dm/uclass-id.h enum uclass_id { · line 38
Quoted 1 line
include/dm/uclass-id.h +1
-0+/* PMIC uclass and PMIC-related uclass types */ This comment seemed confusing - is it for PMICs or other things also?
Ah, my mistake when rebasing the code. This should be added with regulator uclass.
Quoted 40 lines
Quoted 40 lines
include/dm/uclass-id.h +2
-0+UCLASS_PMIC , +UCLASS_COUNT , UCLASS_INVALID = -1, };include/power/pmic.h +11
-0@@ -1,4 +1,7 @@/* +* Copyright (C) 2014-2015 Samsung Electronics +* Przemyslaw Marczak <[email protected]> +* * Copyright (C) 2011-2012 Samsung Electronics * Lukasz Majewski <[email protected]> * @@ -9,10 +12,13 @@#define __CORE_PMIC_H_#include <linux/list.h> +#include <spi.h> #include <i2c.h> #include <power/power_chrg.h> 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,210 @@ struct pmic {struct pmic *parent; struct list_head list; }; +#endif /* CONFIG_POWER */ + +#ifdef CONFIG_DM_PMIC +/** +* Driver model pmic framework.
Quoted 9 lines
include/power/pmic.h struct pmic { · line 92
Quoted 2 lines
include/power/pmic.h +2
-0+* The PMIC_UCLASS uclass is designed to provide a common I/O +* interface for pmic child devices of various uclass types. I worry about having the docs in multiple places. Should you adjust this to point to the
Kconfig? Or change theKconfigto point here? Or maybe it would be better to drop both and put these in your README? I am concerned that if we later change something, we end up with inconsistent docs.
Right, this could be an issue in the future. I suppose that first thing is to look at this header file, before anyone starts work with this framework.
So maybe it's better keep the description only in this file, and add some basic info to Kconfig and doc, with the links to here?
Quoted 92 lines
Quoted 92 lines
include/power/pmic.h +92
-0+* +* Usually PMIC devices provides more than one functionality, +* which means that we should implement uclass operations for +* each functionality - one driver per uclass. +* +* And usually PMIC devices provide those various functionalities +* by one or more interfaces. And this could looks 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/... +* |_ PMIC device (READ/WRITE ops) - UCLASS_PMIC +* |_ RTC device (rtc ops) - UCLASS_MUIC (in the future) +* +* Two PMIC types are possible: +* - single I/O interface +* 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 +* 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. +* +* For each case binding should be done automatically. If only 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) +* +* The same for other bus nodes, if pmic uses more then one interface. +* +* Note: +* Each PMIC interface driver should use different compatible string. +* +* If each pmic child device driver need access the pmic specified registers, +* it need to know only the register address and the access is 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 by the call +* to 'pmic_child_node_scan()' - it allows bind in optional subnode and with +* optional compatible property, e.g. "regulator-compatible" or "regulator". +* +* my_pmic.c - pmic driver: +* +* int my_pmic_bind(struct udevice *my_pmic) +* { +* ... +* ret = pmic_child_node_scan(my_pmic, NULL, "compatible"); +* ... +* ... +* } +* +* my_regulator.c - regulator driver (child of pmic I/O driver): +* +* int my_regulator_set_value(struct udevice *dev, int type, int num, int *val) +* { +* ... +* some_val = ...; +* +* // dev->parent == my_pmic +* pmic_write(dev->parent, some_reg, some_val); +* ... +* } +* +* In this example pmic driver is always a parent for other pmic devices. +*/ + +/** +* 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'
Quoted 9 lines
include/power/pmic.h struct pmic { · line 190
Quoted 6 lines
include/power/pmic.h +6
-0+* @write: write 'len' bytes from the 'buffer' to the register at 'reg' address +*/ +struct dm_pmic_ops { +int reg_count; +int (*read)(struct udevice *dev,uint reg,uint8_t *buffer,int len); +int (*write)(struct udevice *dev,uint reg,uint8_t *buffer,int len);nit: const
uint8_t*buffer?
Right, will fix this.
Quoted 50 lines
Quoted 50 lines
include/power/pmic.h +50
-0+}; + +/* enum pmic_op_type - used for various pmic devices operation calls, +* 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 , +}; + +/** +* pmic_get_uclass_ops - inline function for getting device uclass operations +* +* @dev - device to check +* @uclass_id - device uclass id +* +* Returns: +* void pointer to device operations or NULL pointer on error +*/ +static __inline__const void *pmic_get_uclass_ops (struct udevice *dev, +int uclass_id) +{ +const void *ops; + +if (!dev) +return NULL ; + +if (dev->driver->id != uclass_id) +return NULL ; + + ops = dev->driver->ops; +if (!ops) +return NULL ; + +return ops; +} + +/* drivers/power/pmic-uclass.c */ + +/** +* pmic_child_node_scan - scan the pmic node or its 'optional_subnode' for its +* childs, by the compatible property name given by arg 'compatible_prop_name'. +* +* Few dts files with a different pmic regulators, uses different property +* name for its driver 'compatible' string, like: +* - 'compatible' +* 'regulator-compatible'
Quoted 9 lines
include/power/pmic.h struct pmic { · line 246
Quoted 6 lines
include/power/pmic.h +6
-0+* The pmic driver should should bind its devices by proper compatible property +* name. +* +* @parent - pmic parent device (usually UCLASS_PMIC) +* @optional_subnode - optional pmic subnode with the childs within it +* @compatible_property_name - e.g.: 'compatible'; 'regulator-compatible', ... @return
Ok
Quoted 32 lines
include/power/pmic.h struct pmic { · line 257
Quoted 11 lines
include/power/pmic.h +11
-0+*/ +int pmic_child_node_scan (struct udevice *parent, +const char *optional_subnode, +const char *compatible_property_name); + +/** +* pmic_get: get the pmic device using its name +* +* @name - device name +* @devp - returned pointer to the pmic device +* Returns: 0 on success or negative value of errno. * @return 0 on success or negative value of errno.
Quoted 18 lines
include/power/pmic.h +18
-0+* +* The returned devp device can be used with pmic_read/write calls +*/ +int pmic_get (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 +* +* Returns: 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
Quoted 9 lines
include/power/pmic.h struct pmic { · line 281
Quoted 6 lines
include/power/pmic.h +6
-0+* +* The required pmic device can be obtained by 'pmic_get()' +* +* @pmic - pointer to the UCLASS_PMIC device +* @reg - device register offset +* @val - value for write or its pointer to read This doesn't match the functions.
Ah, missed this - will fix
Quoted 8 lines
include/power/pmic.h struct pmic { · line 286
Quoted 5 lines
include/power/pmic.h +5
-0+* +* Returns: 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,uint8_t *buffer,int len);const
uint8_tbuffer forpmic_write()?
Yes, will adjust to ops prototypes.
Quoted 12 lines
Quoted 12 lines
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 +297,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,
Signature · 4 lines
Przemyslaw Marczak Samsung R&D Institute Poland Samsung Electronics p.marczak at samsung.com
PATCH v3 5/17 dm: pmic: add implementation of driver model pmic uclass
Hi Przemyslaw,
Quoted 61 lines · Przemyslaw Marczak
Hello Simon,
Quoted 48 lines · Simon Glass
Hi Prazemyslaw,
Quoted 43 lines · Przemyslaw Marczak
include/dm/uclass-id.h +2
-0+UCLASS_PMIC , +UCLASS_COUNT , UCLASS_INVALID = -1, };include/power/pmic.h +12
-0@@ -1,4 +1,7 @@/* +* Copyright (C) 2014-2015 Samsung Electronics +* Przemyslaw Marczak <[email protected]> +* * Copyright (C) 2011-2012 Samsung Electronics * Lukasz Majewski <[email protected]> * @@ -9,10 +12,13 @@#define __CORE_PMIC_H_#include <linux/list.h> +#include <spi.h> #include <i2c.h> #include <power/power_chrg.h> 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,210 @@ struct pmic {struct pmic *parent; struct list_head list; }; +#endif /* CONFIG_POWER */ + +#ifdef CONFIG_DM_PMIC +/** +* Driver model pmic framework. +* The PMIC_UCLASS uclass is designed to provide a common I/O Quoted 9 lines
include/power/pmic.h struct pmic { · line 92
Quoted 1 line
include/power/pmic.h +1
-0+* interface for pmic child devices of various uclass types. I worry about having the docs in multiple places. Should you adjust this to point to the
Kconfig? Or change theKconfigto point here? Or maybe it would be better to drop both and put these in your README? I am concerned that if we later change something, we end up with inconsistent docs.
Quoted 4 lines
Right, this could be an issue in the future. I suppose that first thing is to look at this header file, before anyone starts work with this framework. So maybe it's better keep the description only in this file, and add some basic info to
Kconfigand doc, with the links to here?
Yes that sounds good to me. It's great that you have documented this so well.
Regards,
Simon
PATCH v3 6/17 dm: regulator: add implementation of driver model regulator uclass
In reply to Przemyslaw MarczakThis is the implementation of driver model regulator uclass api. To use it, the CONFIG_DM_PMIC is required with driver implementation, since it provides pmic devices basic I/O API.
To get the regulator device:
- regulator_get() - get the regulator device
The regulator framework is based on a 'struct dm_regulator_ops'. It provides a common function calls, for it's basic features:
- 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
An optional and useful regulator framework features are two descriptors:
- struct dm_regulator_info- describes the regulator name and output value limits
- struct dm_regulator_mode - (array) describes the regulators operation modes
The regulator framework features are described in file:
- include/power/regulator.h
Main 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_PMIC_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
--- drivers/power/Kconfig | 33 ++++- drivers/power/Makefile | 1 + drivers/power/regulator-uclass.c | 219 +++++++++++++++++++++++++++++++++ include/dm/uclass-id.h | 1 + include/power/regulator.h | 259 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 512 insertions(+), 1 deletion(-) create mode 100644 drivers/power/regulator-uclass.c create mode 100644 include/power/regulator.h
drivers/power/Kconfig +32 -1
@@ -66,7 +66,38 @@ config DM_PMIC So the call will looks like below: 'pmic_write(regulator->parent, addr, value, len);' -config AXP221_POWER +config DM_REGULATOR + bool "Enable Driver Model for REGULATOR drivers (UCLASS_REGULATOR)" + depends on DM + ---help--- + This config enables the driver-model regulator uclass support, which + provides implementation of driver model regulator uclass api. + + Regulator uclass API calls: + To get the regulator device: + - regulator_get() - get the regulator device + + The regulator framework is based on a 'struct dm_regulator_ops'. + It provides a common function calls, for it's basic features: + - regulator_info() - get the regulator info structure + - regulator_mode() - get the regulator mode info structure + - regulator_get/set_value() - operate on output voltage value + - regulator_get/set_current() - operate on output current value + - regulator_get/set_enable() - operate on output enable state + - regulator_get/set_mode() - operate on output operation mode + + An optional and useful regulator framework features are two descriptors: + - struct dm_regulator_info - describes the regulator name and output limits + - struct dm_regulator_mode - describes the regulators operation mode + + The regulator framework features are described in file: + - include/power/regulator.h + + Main files: + - drivers/power/regulator-uclass.c - provides regulator common functions api + - include/power/regulator.h - define all structures required by the regulato + + config AXP221_POWER boolean "axp221 / axp223 pmic support" depends on MACH_SUN6I || MACH_SUN8I default y
drivers/power/Makefile +1 -0
@@ -22,3 +22,4 @@ obj-$(CONFIG_POWER_FSL) += power_fsl.o obj-$(CONFIG_POWER_I2C) += power_i2c.o obj-$(CONFIG_POWER_SPI) += power_spi.o obj-$(CONFIG_DM_PMIC) += pmic-uclass.o +obj-$(CONFIG_DM_REGULATOR) += regulator-uclass.o
drivers/power/regulator-uclass.c new file +219 -0
219 lines not on this page · raw message
include/dm/uclass-id.h +1 -0
@@ -37,6 +37,7 @@ enum uclass_id {/* PMIC uclass and PMIC-related uclass types */ UCLASS_PMIC , +UCLASS_REGULATOR ,UCLASS_COUNT , UCLASS_INVALID = -1,
include/power/regulator.h new file +259 -0
259 lines not on this page · raw message
Signature · 1 line
1.9.1
PATCH v3 6/17 dm: regulator: add implementation of driver model regulator uclass
Hi Przemyslaw,
Quoted 72 lines · Przemyslaw Marczak
This is the implementation of driver model regulator uclass api. To use it, the
CONFIG_DM_PMICis required with driver implementation, since it provides pmic devices basic I/O API.To get the regulator device:
-regulator_get()- get the regulator deviceThe regulator framework is based on a 'struct
dm_regulator_ops'. It provides a common function calls, for it's basic features:- 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 modeAn optional and useful regulator framework features are two descriptors:
- struct dm_regulator_info- describes the regulator name and output value limits- struct
dm_regulator_mode- (array) describes the regulators operation modesThe regulator framework features are described in file:
-include/power/regulator.hMain files:
-drivers/power/regulator-uclass.c- provides regulator common functions api
-include/power/regulator.h- define all structures required by the regulatorChanges:
- new uclass-id:UCLASS_PMIC_REGULATOR
- new config:CONFIG_DM_REGULATORSigned-off-by Przemyslaw Marczak <[email protected]>---
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 commentsChanges V3:
-regulator-uclass.candregulator.h:
-- api cleanup
-- new functionregulator_ofdata_to_platdata()
-- update of comments
-- addKconfig--- drivers/power/Kconfig | 33 ++++- drivers/power/Makefile | 1 + drivers/power/regulator-uclass.c | 219 +++++++++++++++++++++++++++++++++ include/dm/uclass-id.h | 1 + include/power/regulator.h | 259 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 512 insertions(+), 1 deletion(-) create mode 100644 drivers/power/regulator-uclass.c create mode 100644 include/power/regulator.hdrivers/power/Kconfig +0
-0
drivers/power/Kconfig config DM_PMIC · line 69
Quoted 5 lines
drivers/power/Kconfig +1
-1@@ -66,7 +66,38 @@ config DM_PMIC So the call will looks like below: 'pmic_write(regulator->parent, addr, value, len);' -config AXP221_POWER +config DM_REGULATOR
Can you move this to drivers/power/regulator?
Quoted 21 lines
drivers/power/Kconfig +21
-0+ bool "Enable Driver Model for REGULATOR drivers (UCLASS_REGULATOR)" + depends on DM + ---help--- + This config enables the driver-model regulator uclass support, which + provides implementation of driver model regulator uclass api. + + Regulator uclass API calls: + To get the regulator device: + - regulator_get() - get the regulator device + + The regulator framework is based on a 'struct dm_regulator_ops'. + It provides a common function calls, for it's basic features: + - regulator_info() - get the regulator info structure + - regulator_mode() - get the regulator mode info structure + - regulator_get/set_value() - operate on output voltage value + - regulator_get/set_current() - operate on output current value + - regulator_get/set_enable() - operate on output enable state + - regulator_get/set_mode() - operate on output operation mode + + An optional and useful regulator framework features are two descriptors: + - struct dm_regulator_info - describes the regulator name and output limits
drivers/power/Kconfig config DM_PMIC · line 100
Quoted 10 lines
drivers/power/Kconfig +10
-0+ - struct dm_regulator_mode - describes the regulators operation mode + + The regulator framework features are described in file: + - include/power/regulator.h + + Main files: + - drivers/power/regulator-uclass.c - provides regulator common functions api + - include/power/regulator.h - define all structures required by the regulato + + config AXP221_POWER
I don't think this should be indented.
Quoted 32 lines
drivers/power/Kconfig +0
-0boolean "axp221 / axp223 pmic support" depends on MACH_SUN6I || MACH_SUN8I default ydrivers/power/Makefile +1
-0@@ -22,3 +22,4 @@ obj-$(CONFIG_POWER_FSL) += power_fsl.o obj-$(CONFIG_POWER_I2C) += power_i2c.o obj-$(CONFIG_POWER_SPI) += power_spi.o obj-$(CONFIG_DM_PMIC) += pmic-uclass.o +obj-$(CONFIG_DM_REGULATOR) += regulator-uclass.odrivers/power/regulator-uclass.c new file +14
-0@@ -0,0 +1,219 @@ +/* +* Copyright (C) 2014-2015 Samsung Electronics +* Przemyslaw Marczak <[email protected]> +* +* SPDX-License-Identifier: GPL-2.0+ +*/ +#include <common.h> +#include <linux/types.h> +#include <fdtdec.h> +#include <dm.h> +#include <power/pmic.h> +#include <power/regulator.h> +#include <compiler.h> +#include <dm/device.h>
drivers/power/regulator-uclass.c line 24
Quoted 10 lines
drivers/power/regulator-uclass.c new file +10
-0+#include <dm/lists.h> +#include <dm/device-internal.h> +#include <errno.h> + +DECLARE_GLOBAL_DATA_PTR ; + +int regulator_info (struct udevice *dev,struct dm_regulator_info **infop) +{ +if (!dev || !dev->uclass_priv) +return -ENODEV ;
assert() would be OK here, but if you prefer this, OK.
Quoted 14 lines
drivers/power/regulator-uclass.c new file +14
-0+ + *infop = dev->uclass_priv; + +return 0 ; +} + +int regulator_mode (struct udevice *dev,struct dm_regulator_mode **modep) +{ +struct dm_regulator_info *info; +int ret; + + ret =regulator_info (dev, &info); +if (ret) +return ret;
drivers/power/regulator-uclass.c line 48
Quoted 10 lines
drivers/power/regulator-uclass.c new file +10
-0+ + *modep = info->mode; +return info->mode_count; +} + +int regulator_get_value (struct udevice *dev) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_REGULATOR );
Can you instead define regulator_get_uclass_ops()?
drivers/power/regulator-uclass.c line 50
Quoted 2 lines
drivers/power/regulator-uclass.c new file +2
-0+if (!ops) +return -ENODEV ;
-ENOSYS
We normally assume that operations existing, so assert() is OK. But if you are worried about this, then this is OK.
drivers/power/regulator-uclass.c line 53
Quoted 3 lines
drivers/power/regulator-uclass.c new file +3
-0+ +if (!ops->get_value) +return -EPERM ;
-ENOSYS
i.e.
if (!ops || !ops->get_value)
return -ENOSYS;
Please fix below also.
Quoted 103 lines
drivers/power/regulator-uclass.c new file +103
-0+ +return ops->get_value (dev); +} + +int regulator_set_value (struct udevice *dev,int uV) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_REGULATOR ); +if (!ops) +return -ENODEV ; + +if (!ops->set_value) +return -EPERM ; + +return ops->set_value (dev, uV); +} + +int regulator_get_current (struct udevice *dev) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_REGULATOR ); +if (!ops) +return -ENODEV ; + +if (!ops->get_current) +return -EPERM ; + +return ops->get_current (dev); +} + +int regulator_set_current (struct udevice *dev,int uA) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_REGULATOR ); +if (!ops) +return -ENODEV ; + +if (!ops->set_current) +return -EPERM ; + +return ops->set_current (dev, uA); +} + +bool regulator_get_enable (struct udevice *dev) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_REGULATOR ); +if (!ops) +return -ENODEV ; + +if (!ops->get_enable) +return -EPERM ; + +return ops->get_enable (dev); +} + +int regulator_set_enable (struct udevice *dev,bool enable) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_REGULATOR ); +if (!ops) +return -ENODEV ; + +if (!ops->set_enable) +return -EPERM ; + +return ops->set_enable (dev, enable); +} + +int regulator_get_mode (struct udevice *dev) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_REGULATOR ); +if (!ops) +return -ENODEV ; + +if (!ops->get_mode) +return -EPERM ; + +return ops->get_mode (dev); +} + +int regulator_set_mode (struct udevice *dev,int mode) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_REGULATOR ); +if (!ops) +return -ENODEV ; + +if (!ops->set_mode) +return -EPERM ; + +return ops->set_mode (dev, mode); +} + +int regulator_ofdata_to_platdata (struct udevice *dev)
drivers/power/regulator-uclass.c line 166
Quoted 10 lines
drivers/power/regulator-uclass.c new file +10
-0+{ +struct dm_regulator_info *info = dev->uclass_priv; +int offset = dev->of_offset; +int len; + +/* Mandatory constraints */ + info->name =strdup (fdt_getprop (gd->fdt_blob, offset, +"regulator-name" , &len)); +if (!info->name) +return -ENXIO ;
-ENOMEM
But there is no need to strdup() this - the device tree does not move.
Quoted 25 lines
drivers/power/regulator-uclass.c new file +25
-0+ + info->min_uV =fdtdec_get_int (gd->fdt_blob, offset, +"regulator-min-microvolt" ,-1 ); +if (info->min_uV <0 ) +return -ENXIO ; + + info->max_uV =fdtdec_get_int (gd->fdt_blob, offset, +"regulator-max-microvolt" ,-1 ); +if (info->max_uV <0 ) +return -ENXIO ; + +/* Optional constraints */ + info->min_uA =fdtdec_get_int (gd->fdt_blob, offset, +"regulator-min-microamp" ,-1 ); + info->max_uA =fdtdec_get_int (gd->fdt_blob, offset, +"regulator-max-microamp" ,-1 ); + info->always_on =fdtdec_get_bool (gd->fdt_blob, offset, +"regulator-always-on" ); + info->boot_on =fdtdec_get_bool (gd->fdt_blob, offset, +"regulator-boot-on" ); + +return 0 ; +} + +int regulator_get (char *name,struct udevice **devp)
drivers/power/regulator-uclass.c line 201
Quoted 10 lines
drivers/power/regulator-uclass.c new file +10
-0+{ +struct dm_regulator_info *info; +struct udevice *dev; +int ret; + + *devp =NULL ; + +for (ret =uclass_first_device (UCLASS_REGULATOR , &dev); + dev; + ret =uclass_next_device (&dev)) {
This will probe all devices. See my suggestion about creating uclass_find_first_device()/uclass_find_next_device() in the next patch.
As before, I think this could use a function like uclass_get_device_by_name().
Quoted 23 lines
drivers/power/regulator-uclass.c new file +18
-0+ info = dev->uclass_priv; +if (!info) +continue ; + +if (!strcmp (name, info->name)) { + *devp = dev; +return ret; + } + } + +return -ENODEV ; +} + +UCLASS_DRIVER (regulator) = { + .id =UCLASS_REGULATOR , + .name ="regulator" , + .per_device_auto_alloc_size =sizeof (struct dm_regulator_info ), +};include/dm/uclass-id.h +0
-0
include/dm/uclass-id.h enum uclass_id { · line 40
Quoted 4 lines
include/dm/uclass-id.h +1
-0@@ -37,6 +37,7 @@ enum uclass_id {/* PMIC uclass and PMIC-related uclass types */ UCLASS_PMIC , + UCLASS_REGULATOR,
OK I see what the comment means now. I think it would be nice to have a comment here 'Voltage regulator'
Quoted 110 lines
include/dm/uclass-id.h +0
-0UCLASS_COUNT , UCLASS_INVALID = -1,include/power/regulator.h new file +101
-0@@ -0,0 +1,259 @@ +/* +* Copyright (C) 2014-2015 Samsung Electronics +* Przemyslaw Marczak <[email protected]> +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#ifndef _INCLUDE_REGULATOR_H_ +#define _INCLUDE_REGULATOR_H_ + +/* 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_info - this structure holds an information about + * each regulator 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: for attributes signed with '*' + * These platform-specific constraints can be taken by regulator api function, + * which is 'regulator_ofdata_to_platdata()'. Please read the description, which + * can be found near the declaration of the mentioned function. +*/ +struct dm_regulator_info { + 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; +}; + +/* PMIC 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
include/power/regulator.h line 111
Quoted 10 lines
include/power/regulator.h new file +10
-0+* @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
driver-
Quoted 12 lines
include/power/regulator.h new file +12
-0+* 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. +*/
include/power/regulator.h line 133
Quoted 10 lines
include/power/regulator.h new file +10
-0+int (*get_mode)(struct udevice *dev); +int (*set_mode)(struct udevice *dev,int mode_id); +}; + +/** +* regulator_info: returns a pointer to the devices regulator info structure +* +* @dev - pointer to the regulator device +* @infop - pointer to the returned regulator info +* Returns - 0 on success or negative value of errno.
@return 0 on success...
Quoted 114 lines
include/power/regulator.h new file +114
-0+*/ +int regulator_info (struct udevice *dev,struct dm_regulator_info **infop); + +/** +* 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 +* 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. +*/ +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_ofdata_to_platdata: get the regulator constraints from its fdt node +* and put it into the regulator 'dm_regulator_info' (dev->uclass_priv). +* +* An example of required regulator fdt node constraints: +* 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) +* }; +* +* @dev - pointer to the regulator device +* Returns - 0 on success or -errno value if fails +* Note2: +* This function can be called at stage in which 'dev->uclass_priv' is non-NULL. +* It is possible at two driver call stages: '.ofdata_to_platdata' or '.probe'. +*/ +int regulator_ofdata_to_platdata (struct udevice *dev); + +/** +* regulator_get: returns the pointer to the pmic regulator device based on
include/power/regulator.h line 257
Quoted 10 lines
include/power/regulator.h new file +10
-0+* regulator fdt node data +* +* @fdt_name - property 'regulator-name' value of regulator fdt node +* @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_get (char *fdt_name,struct udevice **devp);
Can we s/fdt_name/name/ since by now it is a device name, not a device tree name.
Quoted 5 lines
include/power/regulator.h new file +2
-1+ +#endif /* _INCLUDE_REGULATOR_H_ */ --1.9.1
Regards,
Simon
PATCH v3 6/17 dm: regulator: add implementation of driver model regulator uclass
Hello Simon,
Quoted 78 lines · Simon Glass
Hi Przemyslaw,
Quoted 75 lines · Przemyslaw Marczak
This is the implementation of driver model regulator uclass api. To use it, the
CONFIG_DM_PMICis required with driver implementation, since it provides pmic devices basic I/O API.To get the regulator device:
-regulator_get()- get the regulator deviceThe regulator framework is based on a 'struct
dm_regulator_ops'. It provides a common function calls, for it's basic features:- 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 modeAn optional and useful regulator framework features are two descriptors:
- struct dm_regulator_info- describes the regulator name and output value limits- struct
dm_regulator_mode- (array) describes the regulators operation modesThe regulator framework features are described in file:
-include/power/regulator.hMain files:
-drivers/power/regulator-uclass.c- provides regulator common functions api
-include/power/regulator.h- define all structures required by the regulatorChanges:
- new uclass-id:UCLASS_PMIC_REGULATOR
- new config:CONFIG_DM_REGULATORSigned-off-by Przemyslaw Marczak <[email protected]>---
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 commentsChanges V3:
-regulator-uclass.candregulator.h:
-- api cleanup
-- new functionregulator_ofdata_to_platdata()
-- update of comments
-- addKconfig--- drivers/power/Kconfig | 33 ++++- drivers/power/Makefile | 1 + drivers/power/regulator-uclass.c | 219 +++++++++++++++++++++++++++++++++ include/dm/uclass-id.h | 1 + include/power/regulator.h | 259 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 512 insertions(+), 1 deletion(-)create mode 100644
drivers/power/regulator-uclass.ccreate mode 100644include/power/regulator.hdrivers/power/Kconfig +0
-0@@ -66,7 +66,38 @@ config DM_PMIC So the call will looks like below: 'pmic_write(regulator->parent, addr, value, len);'
Quoted 5 lines
drivers/power/Kconfig config DM_PMIC · line 69
Quoted 2 lines
drivers/power/Kconfig +1
-1-config AXP221_POWER +config DM_REGULATORCan you move this to
drivers/power/regulator?
Ok, will do this.
Quoted 25 lines
Quoted 25 lines
drivers/power/Kconfig +25
-0+ bool "Enable Driver Model for REGULATOR drivers (UCLASS_REGULATOR)" + depends on DM + ---help--- + This config enables the driver-model regulator uclass support, which + provides implementation of driver model regulator uclass api. + + Regulator uclass API calls: + To get the regulator device: + - regulator_get() - get the regulator device + + The regulator framework is based on a 'struct dm_regulator_ops'. + It provides a common function calls, for it's basic features: + - regulator_info() - get the regulator info structure + - regulator_mode() - get the regulator mode info structure + - regulator_get/set_value() - operate on output voltage value + - regulator_get/set_current() - operate on output current value + - regulator_get/set_enable() - operate on output enable state + - regulator_get/set_mode() - operate on output operation mode + + An optional and useful regulator framework features are two descriptors: + - struct dm_regulator_info - describes the regulator name and output limits + - struct dm_regulator_mode - describes the regulators operation mode + + The regulator framework features are described in file: + - include/power/regulator.h
Quoted 9 lines
drivers/power/Kconfig config DM_PMIC · line 100
Quoted 6 lines
drivers/power/Kconfig +6
-0+ + Main files: + - drivers/power/regulator-uclass.c - provides regulator common functions api + - include/power/regulator.h - define all structures required by the regulato + + config AXP221_POWERI don't think this should be indented.
Right, will fix.
Quoted 36 lines
Quoted 36 lines
drivers/power/Kconfig +0
-0boolean "axp221 / axp223 pmic support" depends on MACH_SUN6I || MACH_SUN8I default ydrivers/power/Makefile +1
-0@@ -22,3 +22,4 @@ obj-$(CONFIG_POWER_FSL) += power_fsl.o obj-$(CONFIG_POWER_I2C) += power_i2c.o obj-$(CONFIG_POWER_SPI) += power_spi.o obj-$(CONFIG_DM_PMIC) += pmic-uclass.o +obj-$(CONFIG_DM_REGULATOR) += regulator-uclass.odrivers/power/regulator-uclass.c new file +18
-0@@ -0,0 +1,219 @@ +/* +* Copyright (C) 2014-2015 Samsung Electronics +* Przemyslaw Marczak <[email protected]> +* +* SPDX-License-Identifier: GPL-2.0+ +*/ +#include <common.h> +#include <linux/types.h> +#include <fdtdec.h> +#include <dm.h> +#include <power/pmic.h> +#include <power/regulator.h> +#include <compiler.h> +#include <dm/device.h> +#include <dm/lists.h> +#include <dm/device-internal.h> +#include <errno.h> +
Quoted 9 lines
drivers/power/regulator-uclass.c line 24
Quoted 6 lines
drivers/power/regulator-uclass.c new file +6
-0+DECLARE_GLOBAL_DATA_PTR ; + +int regulator_info (struct udevice *dev,struct dm_regulator_info **infop) +{ +if (!dev || !dev->uclass_priv) +return -ENODEV ;
assert()would be OK here, but if you prefer this, OK.
Sorry, I should add this in this version - will fix.
Quoted 18 lines
Quoted 18 lines
drivers/power/regulator-uclass.c new file +18
-0+ + *infop = dev->uclass_priv; + +return 0 ; +} + +int regulator_mode (struct udevice *dev,struct dm_regulator_mode **modep) +{ +struct dm_regulator_info *info; +int ret; + + ret =regulator_info (dev, &info); +if (ret) +return ret; + + *modep = info->mode; +return info->mode_count; +}
Quoted 9 lines
drivers/power/regulator-uclass.c line 48
Quoted 6 lines
drivers/power/regulator-uclass.c new file +6
-0+ +int regulator_get_value (struct udevice *dev) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_REGULATOR );Can you instead define
regulator_get_uclass_ops()?
So maybe I will add this to uclass.c ?
Quoted 8 lines
drivers/power/regulator-uclass.c line 50
Quoted 2 lines
drivers/power/regulator-uclass.c new file +2
-0+if (!ops) +return -ENODEV ;
-ENOSYSWe normally assume that operations existing, so
assert()is OK. But if you are worried about this, then this is OK.
Yes, but the pmic_get_uclass_ops, can return NULL, so I would prefer to leave this null-checking here and also add the assert.
Quoted 4 lines
drivers/power/regulator-uclass.c line 53
Quoted 3 lines
drivers/power/regulator-uclass.c new file +3
-0+ +if (!ops->get_value) +return -EPERM ;
Quoted 9 lines
-ENOSYSi.e.
if (!ops || !ops->get_value)
return -ENOSYS;Please fix below also.
Ok.
Quoted 116 lines
Quoted 103 lines
drivers/power/regulator-uclass.c new file +103
-0+ +return ops->get_value (dev); +} + +int regulator_set_value (struct udevice *dev,int uV) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_REGULATOR ); +if (!ops) +return -ENODEV ; + +if (!ops->set_value) +return -EPERM ; + +return ops->set_value (dev, uV); +} + +int regulator_get_current (struct udevice *dev) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_REGULATOR ); +if (!ops) +return -ENODEV ; + +if (!ops->get_current) +return -EPERM ; + +return ops->get_current (dev); +} + +int regulator_set_current (struct udevice *dev,int uA) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_REGULATOR ); +if (!ops) +return -ENODEV ; + +if (!ops->set_current) +return -EPERM ; + +return ops->set_current (dev, uA); +} + +bool regulator_get_enable (struct udevice *dev) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_REGULATOR ); +if (!ops) +return -ENODEV ; + +if (!ops->get_enable) +return -EPERM ; + +return ops->get_enable (dev); +} + +int regulator_set_enable (struct udevice *dev,bool enable) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_REGULATOR ); +if (!ops) +return -ENODEV ; + +if (!ops->set_enable) +return -EPERM ; + +return ops->set_enable (dev, enable); +} + +int regulator_get_mode (struct udevice *dev) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_REGULATOR ); +if (!ops) +return -ENODEV ; + +if (!ops->get_mode) +return -EPERM ; + +return ops->get_mode (dev); +} + +int regulator_set_mode (struct udevice *dev,int mode) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_REGULATOR ); +if (!ops) +return -ENODEV ; + +if (!ops->set_mode) +return -EPERM ; + +return ops->set_mode (dev, mode); +} + +int regulator_ofdata_to_platdata (struct udevice *dev)drivers/power/regulator-uclass.c line 166
Quoted 10 lines
drivers/power/regulator-uclass.c new file +10
-0+{ +struct dm_regulator_info *info = dev->uclass_priv; +int offset = dev->of_offset; +int len; + +/* Mandatory constraints */ + info->name =strdup (fdt_getprop (gd->fdt_blob, offset, +"regulator-name" , &len)); +if (!info->name) +return -ENXIO ;
-ENOMEM
Quoted 2 lines
But there is no need to
strdup()this - the device tree does not move.
Ok, will fix.
Quoted 40 lines
Quoted 25 lines
drivers/power/regulator-uclass.c new file +25
-0+ + info->min_uV =fdtdec_get_int (gd->fdt_blob, offset, +"regulator-min-microvolt" ,-1 ); +if (info->min_uV <0 ) +return -ENXIO ; + + info->max_uV =fdtdec_get_int (gd->fdt_blob, offset, +"regulator-max-microvolt" ,-1 ); +if (info->max_uV <0 ) +return -ENXIO ; + +/* Optional constraints */ + info->min_uA =fdtdec_get_int (gd->fdt_blob, offset, +"regulator-min-microamp" ,-1 ); + info->max_uA =fdtdec_get_int (gd->fdt_blob, offset, +"regulator-max-microamp" ,-1 ); + info->always_on =fdtdec_get_bool (gd->fdt_blob, offset, +"regulator-always-on" ); + info->boot_on =fdtdec_get_bool (gd->fdt_blob, offset, +"regulator-boot-on" ); + +return 0 ; +} + +int regulator_get (char *name,struct udevice **devp)drivers/power/regulator-uclass.c line 201
Quoted 10 lines
drivers/power/regulator-uclass.c new file +10
-0+{ +struct dm_regulator_info *info; +struct udevice *dev; +int ret; + + *devp =NULL ; + +for (ret =uclass_first_device (UCLASS_REGULATOR , &dev); + dev; + ret =uclass_next_device (&dev)) {This will probe all devices. See my suggestion about creating uclass_find_first_device()/uclass_find_next_device() in the next patch.
Quoted 2 lines
As before, I think this could use a function like
uclass_get_device_by_name().
Yes, this is the same. But in this case, there is one more issue, which is the regulator device name.
Usually after bind -> the dev->name is the same as node name. This is good, since it's natural that regulator IC, provides e.g "ldo1", or some other device-output name.
But we would like check the "regulator-name" property. For this patch-set, the name is fixed at device probe stage, when dev->ofdata_to_platdata() is called, and the regulator constraints, the same as it's name goes to struct dm_regulator_info.
I put the dm_regulator_info into uclass priv, because it it uclass-specific, the same as struct dm_i2c_bus is specific for i2c buses.
But, the ucalss priv is allocated at device probe stage.
I can't use the .per_child_platdata_auto_alloc_size, since the parent is a pmic, and its uclass type is different.
Actually I could, move the dm_regulator_info only to device platdata, but then, the drivers should take care of this uclass-specific structure allocation.
Is it acceptable?
But then, also ambiguous seem to be filling platdata (struct dm_regulator_info) in uclass post_bind() method.
So then, maybe reasonable is:
- move dm_regulator_info from dev->uclass_priv to dev->platdata - is allocated after device bind
- add .post_bind() method to regulator uclass, and get the "regulator-name" in it - only
- fill all platdata constraints on call to dev->ofdata_to_platdata()
Then, I could avoid probing every device, when checking the regulator name. But, still I can't use the uclass.c functions, since I'm checking the regulator info at dev->platdata.
So I update the function as below:
+ uclass_foreach_dev(dev, uc) {
+ if (!dev->platdata)
+ continue;
+
+ info = dev->platdata;
+ if (!strcmp(name, info->name)) {
+ ret = device_probe(dev);
+ if (ret)
+ ....
+ *regulator = dev;
+ return ret;
+ }
+ }
Quoted 24 lines
Quoted 24 lines
drivers/power/regulator-uclass.c new file +18
-0+ info = dev->uclass_priv; +if (!info) +continue ; + +if (!strcmp (name, info->name)) { + *devp = dev; +return ret; + } + } + +return -ENODEV ; +} + +UCLASS_DRIVER (regulator) = { + .id =UCLASS_REGULATOR , + .name ="regulator" , + .per_device_auto_alloc_size =sizeof (struct dm_regulator_info ), +};include/dm/uclass-id.h +0
-0@@ -37,6 +37,7 @@ enum uclass_id {
Quoted 7 lines
include/dm/uclass-id.h enum uclass_id { · line 40
Quoted 3 lines
include/dm/uclass-id.h +1
-0/* PMIC uclass and PMIC-related uclass types */ UCLASS_PMIC , + UCLASS_REGULATOR,OK I see what the comment means now. I think it would be nice to have a comment here 'Voltage regulator'
Yes, will fix it.
Quoted 267 lines
Quoted 110 lines
include/dm/uclass-id.h +0
-0UCLASS_COUNT , UCLASS_INVALID = -1,include/power/regulator.h new file +101
-0@@ -0,0 +1,259 @@ +/* +* Copyright (C) 2014-2015 Samsung Electronics +* Przemyslaw Marczak <[email protected]> +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#ifndef _INCLUDE_REGULATOR_H_ +#define _INCLUDE_REGULATOR_H_ + +/* 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_info - this structure holds an information about + * each regulator 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: for attributes signed with '*' + * These platform-specific constraints can be taken by regulator api function, + * which is 'regulator_ofdata_to_platdata()'. Please read the description, which + * can be found near the declaration of the mentioned function. +*/ +struct dm_regulator_info { + 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; +}; + +/* PMIC 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 numberinclude/power/regulator.h line 111
Quoted 10 lines
include/power/regulator.h new file +10
-0+* @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 driver-
Quoted 12 lines
include/power/regulator.h new file +12
-0+* 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. +*/ include/power/regulator.h line 133
Quoted 10 lines
include/power/regulator.h new file +10
-0+int (*get_mode)(struct udevice *dev); +int (*set_mode)(struct udevice *dev,int mode_id); +}; + +/** +* regulator_info: returns a pointer to the devices regulator info structure +* +* @dev - pointer to the regulator device +* @infop - pointer to the returned regulator info +* Returns - 0 on success or negative value of errno. @return 0 on success...
Quoted 119 lines
include/power/regulator.h new file +119
-0+*/ +int regulator_info (struct udevice *dev,struct dm_regulator_info **infop); + +/** +* 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 +* 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. +*/ +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_ofdata_to_platdata: get the regulator constraints from its fdt node +* and put it into the regulator 'dm_regulator_info' (dev->uclass_priv). +* +* An example of required regulator fdt node constraints: +* 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) +* }; +* +* @dev - pointer to the regulator device +* Returns - 0 on success or -errno value if fails +* Note2: +* This function can be called at stage in which 'dev->uclass_priv' is non-NULL. +* It is possible at two driver call stages: '.ofdata_to_platdata' or '.probe'. +*/ +int regulator_ofdata_to_platdata (struct udevice *dev); + +/** +* regulator_get: returns the pointer to the pmic regulator device based on +* regulator fdt node data +* +* @fdt_name - property 'regulator-name' value of regulator fdt node +* @devp - returned pointer to the regulator device +* Returns: 0 on success or negative value of errno.
Quoted 8 lines
include/power/regulator.h line 257
Quoted 5 lines
include/power/regulator.h new file +5
-0+* +* The returned 'regulator' device can be used with: +* - regulator_get/set_* +*/ +int regulator_get (char *fdt_name,struct udevice **devp);Can we s/fdt_name/name/ since by now it is a device name, not a device tree name.
Right, thanks for catching this all.
Quoted 9 lines
Quoted 5 lines
include/power/regulator.h new file +2
-1+ +#endif /* _INCLUDE_REGULATOR_H_ */ --1.9.1
Regards,
Simon
Best regards,
Signature · 4 lines
Przemyslaw Marczak Samsung R&D Institute Poland Samsung Electronics p.marczak at samsung.com
PATCH v3 6/17 dm: regulator: add implementation of driver model regulator uclass
Hi Przemyslaw,
Quoted 9 lines · Przemyslaw Marczak
Hello Simon,
Quoted 5 lines · Simon Glass
Hi Przemyslaw,
On 24 March 2015 at 14:30, Przemyslaw Marczak <[email protected]> wrote:
[snip]
Quoted 92 lines
Quoted 42 lines
Quoted 26 lines
drivers/power/regulator-uclass.c new file +25
-0+ + info->min_uV =fdtdec_get_int (gd->fdt_blob, offset, +"regulator-min-microvolt" ,-1 ); +if (info->min_uV <0 ) +return -ENXIO ; + + info->max_uV =fdtdec_get_int (gd->fdt_blob, offset, +"regulator-max-microvolt" ,-1 ); +if (info->max_uV <0 ) +return -ENXIO ; + +/* Optional constraints */ + info->min_uA =fdtdec_get_int (gd->fdt_blob, offset, +"regulator-min-microamp" ,-1 ); + info->max_uA =fdtdec_get_int (gd->fdt_blob, offset, +"regulator-max-microamp" ,-1 ); + info->always_on =fdtdec_get_bool (gd->fdt_blob, offset, +"regulator-always-on" ); + info->boot_on =fdtdec_get_bool (gd->fdt_blob, offset, +"regulator-boot-on" ); + +return 0 ; +} + +int regulator_get (char *name,struct udevice **devp)drivers/power/regulator-uclass.c line 201
Quoted 10 lines
drivers/power/regulator-uclass.c new file +10
-0+{ +struct dm_regulator_info *info; +struct udevice *dev; +int ret; + + *devp =NULL ; + +for (ret =uclass_first_device (UCLASS_REGULATOR , &dev); + dev; + ret =uclass_next_device (&dev)) {This will probe all devices. See my suggestion about creating uclass_find_first_device()/uclass_find_next_device() in the next patch.
Quoted 3 lines
As before, I think this could use a function like
uclass_get_device_by_name().Yes, this is the same. But in this case, there is one more issue, which is the regulator device name.
Usually after bind -> thedev->nameis the same as node name. This is good, since it's natural that regulator IC, provides e.g "ldo1", or some other device-output name.
But we would like check the "regulator-name" property. For this patch-set, the name is fixed at device probe stage, whendev->ofdata_to_platdata()is called, and the regulator constraints, the same as it's name goes to structdm_regulator_info.I put the
dm_regulator_infointo uclass priv, because it it uclass-specific, the same as structdm_i2c_busis specific for i2c buses.But, the ucalss priv is allocated at device probe stage.
I can't use the .per_child_platdata_auto_alloc_size, since the parent is a pmic, and its uclass type is different.
Actually I could, move the
dm_regulator_infoonly to device platdata, but then, the drivers should take care of this uclass-specific structure allocation.
Is it acceptable?But then, also ambiguous seem to be filling platdata (struct
dm_regulator_info) in uclasspost_bind()method.So then, maybe reasonable is:
- movedm_regulator_infofromdev->uclass_privtodev->platdata- is allocated after device bind- add .post_bind() method to regulator uclass, and get the "regulator-name" in it - only
- fill all platdata constraints on call to
dev->ofdata_to_platdata()Then, I could avoid probing every device, when checking the regulator name. But, still I can't use the
uclass.cfunctions, since I'm checking the regulator info atdev->platdata.So I update the function as below:
+
uclass_foreach_dev(dev, uc){drivers/power/regulator-uclass.c new file +2
-0+if (!dev->platdata) +continue ;
drivers/power/regulator-uclass.c line 210
Quoted 10 lines
drivers/power/regulator-uclass.c new file +10
-0+ + info = dev->platdata; +if (!strcmp (name, info->name)) { + ret =device_probe (dev); +if (ret) + .... + *regulator = dev; +return ret; + } + }
The problem here is similar to I2C which uses per-child platdata (specified by the uclass) for the bus address. This is different from device platdata. I think you are suggesting that we should support uclass platdata. In this case we would have for each device:
- device platform data
- parent platform data
- uclass platform data
The last one is not supported. I have through several times about adding it. The alternative is to require each device to provide a platform data struct at the start of its own platform data, which the uclass can find and use. This is not really in the spirit of driver model. But for now this is what I have done with USB (see dm/usb-working). struct usb_platdata appears at the start of struct exynos_ehci_platdata but is owned by the uclass.
If PMIC has use for uclass platform data, then perhaps that would be enough users to warrant it. You could add a patch to do this (don't forget to update tests) or you could do what I have done with USB and we can tidy it up later.
Re your naming problem, apart from case the device name and regulator-compatible name are the same. So perhaps just use case-insensitive search for regulators? But if not then I take back my comment about using a common function for searching for regulator names. You are really searching the platform data for the regulator-compatible string, not the device name, and so the common function cannot be used.
[snip]
Regards,
Simon
PATCH v3 6/17 dm: regulator: add implementation of driver model regulator uclass
Hello Simon,
Quoted 118 lines · Simon Glass
Hi Przemyslaw,
Quoted 9 lines · Przemyslaw Marczak
Hello Simon,
Quoted 5 lines · Simon Glass
Hi Przemyslaw,
On 24 March 2015 at 14:30, Przemyslaw Marczak <[email protected]> wrote:
[snip]
Quoted 92 lines
Quoted 42 lines
Quoted 26 lines
drivers/power/regulator-uclass.c new file +25
-0+ + info->min_uV =fdtdec_get_int (gd->fdt_blob, offset, +"regulator-min-microvolt" ,-1 ); +if (info->min_uV <0 ) +return -ENXIO ; + + info->max_uV =fdtdec_get_int (gd->fdt_blob, offset, +"regulator-max-microvolt" ,-1 ); +if (info->max_uV <0 ) +return -ENXIO ; + +/* Optional constraints */ + info->min_uA =fdtdec_get_int (gd->fdt_blob, offset, +"regulator-min-microamp" ,-1 ); + info->max_uA =fdtdec_get_int (gd->fdt_blob, offset, +"regulator-max-microamp" ,-1 ); + info->always_on =fdtdec_get_bool (gd->fdt_blob, offset, +"regulator-always-on" ); + info->boot_on =fdtdec_get_bool (gd->fdt_blob, offset, +"regulator-boot-on" ); + +return 0 ; +} + +int regulator_get (char *name,struct udevice **devp)drivers/power/regulator-uclass.c line 201
Quoted 10 lines
drivers/power/regulator-uclass.c new file +10
-0+{ +struct dm_regulator_info *info; +struct udevice *dev; +int ret; + + *devp =NULL ; + +for (ret =uclass_first_device (UCLASS_REGULATOR , &dev); + dev; + ret =uclass_next_device (&dev)) {This will probe all devices. See my suggestion about creating uclass_find_first_device()/uclass_find_next_device() in the next patch.
Quoted 3 lines
As before, I think this could use a function like
uclass_get_device_by_name().Yes, this is the same. But in this case, there is one more issue, which is the regulator device name.
Usually after bind -> thedev->nameis the same as node name. This is good, since it's natural that regulator IC, provides e.g "ldo1", or some other device-output name.
But we would like check the "regulator-name" property. For this patch-set, the name is fixed at device probe stage, whendev->ofdata_to_platdata()is called, and the regulator constraints, the same as it's name goes to structdm_regulator_info.I put the
dm_regulator_infointo uclass priv, because it it uclass-specific, the same as structdm_i2c_busis specific for i2c buses.But, the ucalss priv is allocated at device probe stage.
I can't use the .per_child_platdata_auto_alloc_size, since the parent is a pmic, and its uclass type is different.
Actually I could, move the
dm_regulator_infoonly to device platdata, but then, the drivers should take care of this uclass-specific structure allocation.
Is it acceptable?But then, also ambiguous seem to be filling platdata (struct
dm_regulator_info) in uclasspost_bind()method.So then, maybe reasonable is:
- movedm_regulator_infofromdev->uclass_privtodev->platdata- is allocated after device bind- add .post_bind() method to regulator uclass, and get the "regulator-name" in it - only
- fill all platdata constraints on call to
dev->ofdata_to_platdata()Then, I could avoid probing every device, when checking the regulator name. But, still I can't use the
uclass.cfunctions, since I'm checking the regulator info atdev->platdata.So I update the function as below:
+
uclass_foreach_dev(dev, uc){drivers/power/regulator-uclass.c new file +2
-0+if (!dev->platdata) +continue ;drivers/power/regulator-uclass.c line 210
Quoted 10 lines
drivers/power/regulator-uclass.c new file +10
-0+ + info = dev->platdata; +if (!strcmp (name, info->name)) { + ret =device_probe (dev); +if (ret) + .... + *regulator = dev; +return ret; + } + }
Quoted 8 lines
The problem here is similar to I2C which uses per-child platdata (specified by the uclass) for the bus address. This is different from device platdata. I think you are suggesting that we should support uclass platdata. In this case we would have for each device:
- device platform data
- parent platform data
- uclass platform data
Yes, but note, that the uclass type is the same for I2C bus and i2c chip. This is a different than for the PMIC, for which childs uclass type are usually different than for the parent.
In this case I can't use the field per-child-platdata.
Quoted 9 lines
The last one is not supported. I have through several times about adding it. The alternative is to require each device to provide a platform data struct at the start of its own platform data, which the uclass can find and use. This is not really in the spirit of driver model. But for now this is what I have done with USB (see dm/usb-working). struct
usb_platdataappears at the start of structexynos_ehci_platdatabut is owned by the uclass.
Quoted 4 lines
If PMIC has use for uclass platform data, then perhaps that would be enough users to warrant it. You could add a patch to do this (don't forget to update tests) or you could do what I have done with USB and we can tidy it up later.
The example of usb is good enough. I could move the "dm_regulator_info" into the dm_regulator_platdata, and add "void *dev_platdata" at the end of it.
From the other side, the regulator constraints and modes, are all what
we need for this uclass.
We have also the fixed-regulators which some platform data are the same as for the generic regulators - then the dev->uclass_platdata is reasonable for this purpose.
I will add the uclass platdata to struct udevice and also some test to test/dm drivers. I will send it as a separate patch.
Quoted 8 lines
Re your naming problem, apart from case the device name and regulator-compatible name are the same. So perhaps just use case-insensitive search for regulators? But if not then I take back my comment about using a common function for searching for regulator names. You are really searching the platform data for the regulator-compatible string, not the device name, and so the common function cannot be used.
Then we could provide two functions:
- regulator_by_devname() - search for device -> name
- regulator_by_platname() - search for platdata -> name
Quoted 6 lines
[snip]
Regards,
Simon
Best regards,
Signature · 4 lines
Przemyslaw Marczak Samsung R&D Institute Poland Samsung Electronics p.marczak at samsung.com
PATCH v3 6/17 dm: regulator: add implementation of driver model regulator uclass
Hi Przemyslaw,
Quoted 147 lines · Przemyslaw Marczak
Hello Simon,
Quoted 133 lines · Simon Glass
Hi Przemyslaw,
Quoted 11 lines · Przemyslaw Marczak
Hello Simon,
Quoted 6 lines · Simon Glass
Hi Przemyslaw,
On 24 March 2015 at 14:30, Przemyslaw Marczak <[email protected]> wrote:
[snip]
Quoted 102 lines
Quoted 43 lines
Quoted 26 lines
drivers/power/regulator-uclass.c new file +25
-0+ + info->min_uV =fdtdec_get_int (gd->fdt_blob, offset, +"regulator-min-microvolt" ,-1 ); +if (info->min_uV <0 ) +return -ENXIO ; + + info->max_uV =fdtdec_get_int (gd->fdt_blob, offset, +"regulator-max-microvolt" ,-1 ); +if (info->max_uV <0 ) +return -ENXIO ; + +/* Optional constraints */ + info->min_uA =fdtdec_get_int (gd->fdt_blob, offset, +"regulator-min-microamp" ,-1 ); + info->max_uA =fdtdec_get_int (gd->fdt_blob, offset, +"regulator-max-microamp" ,-1 ); + info->always_on =fdtdec_get_bool (gd->fdt_blob, offset, +"regulator-always-on" ); + info->boot_on =fdtdec_get_bool (gd->fdt_blob, offset, +"regulator-boot-on" ); + +return 0 ; +} + +int regulator_get (char *name,struct udevice **devp)drivers/power/regulator-uclass.c line 201
Quoted 10 lines
drivers/power/regulator-uclass.c new file +10
-0+{ +struct dm_regulator_info *info; +struct udevice *dev; +int ret; + + *devp =NULL ; + +for (ret =uclass_first_device (UCLASS_REGULATOR , &dev); + dev; + ret =uclass_next_device (&dev)) {This will probe all devices. See my suggestion about creating uclass_find_first_device()/uclass_find_next_device() in the next patch.
Quoted 3 lines
As before, I think this could use a function like
uclass_get_device_by_name().Yes, this is the same. But in this case, there is one more issue, which is
the regulator device name.
Usually after bind -> thedev->nameis the same as node name. This is good,
since it's natural that regulator IC, provides e.g "ldo1", or some other device-output name.
But we would like check the "regulator-name" property. For this patch-set,
the name is fixed at device probe stage, whendev->ofdata_to_platdata()is
called, and the regulator constraints, the same as it's name goes to structdm_regulator_info.I put the
dm_regulator_infointo uclass priv, because it it uclass-specific,
the same as structdm_i2c_busis specific for i2c buses.But, the ucalss priv is allocated at device probe stage.
I can't use the .per_child_platdata_auto_alloc_size, since the parent is a
pmic, and its uclass type is different.Actually I could, move the
dm_regulator_infoonly to device platdata, but then, the drivers should take care of this uclass-specific structure allocation.
Is it acceptable?But then, also ambiguous seem to be filling platdata (struct
dm_regulator_info) in uclasspost_bind()method.So then, maybe reasonable is:
- movedm_regulator_infofromdev->uclass_privtodev->platdata- is allocated after device bind- add .post_bind() method to regulator uclass, and get the "regulator-name"
in it - only- fill all platdata constraints on call to
dev->ofdata_to_platdata()Then, I could avoid probing every device, when checking the regulator name.
But, still I can't use theuclass.cfunctions, since I'm checking the regulator info atdev->platdata.So I update the function as below:
+
uclass_foreach_dev(dev, uc){drivers/power/regulator-uclass.c new file +2
-0+if (!dev->platdata) +continue ;drivers/power/regulator-uclass.c line 210
Quoted 10 lines
drivers/power/regulator-uclass.c new file +10
-0+ + info = dev->platdata; +if (!strcmp (name, info->name)) { + ret =device_probe (dev); +if (ret) + .... + *regulator = dev; +return ret; + } + }Quoted 8 lines
The problem here is similar to I2C which uses per-child platdata (specified by the uclass) for the bus address. This is different from device platdata. I think you are suggesting that we should support uclass platdata. In this case we would have for each device:
- device platform data
- parent platform data
- uclass platform data
Quoted 4 lines
Yes, but note, that the uclass type is the same for I2C bus and i2c chip. This is a different than for the PMIC, for which childs uclass type are usually different than for the parent.
In this case I can't use the field per-child-platdata.
The I2C bus uses UCLASS_I2C. The chips use a different UCLASS. If there is no specific driver for the chip then we will use UCLASS_I2C_GENERIC, but in general it could be anything. So perhaps there is no difference here?
Per-child platdata works for I2C buses because its children are all I2C chips, whatever their uclass.
Quoted 24 lines
Quoted 10 lines
The last one is not supported. I have through several times about adding it. The alternative is to require each device to provide a platform data struct at the start of its own platform data, which the uclass can find and use. This is not really in the spirit of driver model. But for now this is what I have done with USB (see dm/usb-working). struct
usb_platdataappears at the start of structexynos_ehci_platdatabut is owned by the uclass.Quoted 4 lines
If PMIC has use for uclass platform data, then perhaps that would be enough users to warrant it. You could add a patch to do this (don't forget to update tests) or you could do what I have done with USB and we can tidy it up later.
The example of usb is good enough. I could move the "
dm_regulator_info" into thedm_regulator_platdata, and add "void*dev_platdata" at the end of it. From the other side, the regulator constraints and modes, are all what we need for this uclass.
We have also the fixed-regulators which some platform data are the same as for the generic regulators - then thedev->uclass_platdatais reasonable for this purpose.
Quoted 2 lines
I will add the uclass platdata to struct udevice and also some test to test/dm drivers. I will send it as a separate patch.
OK thanks. As a reminded, please continue to rebase on dm/next.
Quoted 11 lines
Quoted 9 lines
Re your naming problem, apart from case the device name and regulator-compatible name are the same. So perhaps just use case-insensitive search for regulators? But if not then I take back my comment about using a common function for searching for regulator names. You are really searching the platform data for the regulator-compatible string, not the device name, and so the common function cannot be used.
Quoted 3 lines
Then we could provide two functions:
-regulator_by_devname()- search for device -> name
-regulator_by_platname()- search for platdata -> name
OK.
Regards,
Simon
PATCH v3 6/17 dm: regulator: add implementation of driver model regulator uclass
Hello Simon,
Quoted 155 lines · Simon Glass
Hi Przemyslaw,
Quoted 147 lines · Przemyslaw Marczak
Hello Simon,
Quoted 133 lines · Simon Glass
Hi Przemyslaw,
Quoted 11 lines · Przemyslaw Marczak
Hello Simon,
Quoted 6 lines · Simon Glass
Hi Przemyslaw,
On 24 March 2015 at 14:30, Przemyslaw Marczak <[email protected]> wrote:
[snip]
Quoted 102 lines
Quoted 43 lines
Quoted 26 lines
drivers/power/regulator-uclass.c new file +25
-0+ + info->min_uV =fdtdec_get_int (gd->fdt_blob, offset, +"regulator-min-microvolt" ,-1 ); +if (info->min_uV <0 ) +return -ENXIO ; + + info->max_uV =fdtdec_get_int (gd->fdt_blob, offset, +"regulator-max-microvolt" ,-1 ); +if (info->max_uV <0 ) +return -ENXIO ; + +/* Optional constraints */ + info->min_uA =fdtdec_get_int (gd->fdt_blob, offset, +"regulator-min-microamp" ,-1 ); + info->max_uA =fdtdec_get_int (gd->fdt_blob, offset, +"regulator-max-microamp" ,-1 ); + info->always_on =fdtdec_get_bool (gd->fdt_blob, offset, +"regulator-always-on" ); + info->boot_on =fdtdec_get_bool (gd->fdt_blob, offset, +"regulator-boot-on" ); + +return 0 ; +} + +int regulator_get (char *name,struct udevice **devp)drivers/power/regulator-uclass.c line 201
Quoted 10 lines
drivers/power/regulator-uclass.c new file +10
-0+{ +struct dm_regulator_info *info; +struct udevice *dev; +int ret; + + *devp =NULL ; + +for (ret =uclass_first_device (UCLASS_REGULATOR , &dev); + dev; + ret =uclass_next_device (&dev)) {This will probe all devices. See my suggestion about creating uclass_find_first_device()/uclass_find_next_device() in the next patch.
Quoted 3 lines
As before, I think this could use a function like
uclass_get_device_by_name().Yes, this is the same. But in this case, there is one more issue, which is
the regulator device name.
Usually after bind -> thedev->nameis the same as node name. This is good,
since it's natural that regulator IC, provides e.g "ldo1", or some other device-output name.
But we would like check the "regulator-name" property. For this patch-set,
the name is fixed at device probe stage, whendev->ofdata_to_platdata()is
called, and the regulator constraints, the same as it's name goes to structdm_regulator_info.I put the
dm_regulator_infointo uclass priv, because it it uclass-specific,
the same as structdm_i2c_busis specific for i2c buses.But, the ucalss priv is allocated at device probe stage.
I can't use the .per_child_platdata_auto_alloc_size, since the parent is a
pmic, and its uclass type is different.Actually I could, move the
dm_regulator_infoonly to device platdata, but then, the drivers should take care of this uclass-specific structure allocation.
Is it acceptable?But then, also ambiguous seem to be filling platdata (struct
dm_regulator_info) in uclasspost_bind()method.So then, maybe reasonable is:
- movedm_regulator_infofromdev->uclass_privtodev->platdata- is allocated after device bind- add .post_bind() method to regulator uclass, and get the "regulator-name"
in it - only- fill all platdata constraints on call to
dev->ofdata_to_platdata()Then, I could avoid probing every device, when checking the regulator name.
But, still I can't use theuclass.cfunctions, since I'm checking the regulator info atdev->platdata.So I update the function as below:
+
uclass_foreach_dev(dev, uc){drivers/power/regulator-uclass.c new file +2
-0+if (!dev->platdata) +continue ;drivers/power/regulator-uclass.c line 210
Quoted 10 lines
drivers/power/regulator-uclass.c new file +10
-0+ + info = dev->platdata; +if (!strcmp (name, info->name)) { + ret =device_probe (dev); +if (ret) + .... + *regulator = dev; +return ret; + } + }Quoted 8 lines
The problem here is similar to I2C which uses per-child platdata (specified by the uclass) for the bus address. This is different from device platdata. I think you are suggesting that we should support uclass platdata. In this case we would have for each device:
- device platform data
- parent platform data
- uclass platform dataQuoted 4 lines
Yes, but note, that the uclass type is the same for I2C bus and i2c chip. This is a different than for the PMIC, for which childs uclass type are usually different than for the parent.
In this case I can't use the field per-child-platdata.
Quoted 8 lines
The I2C bus uses
UCLASS_I2C. The chips use a different UCLASS. If there is no specific driver for the chip then we will useUCLASS_I2C_GENERIC, but in general it could be anything. So perhaps there is no difference here?Per-child platdata works for I2C buses because its children are all I2C chips, whatever their uclass.
Sorry, I wrote nonsense. I meant something different.
We could use per-child-platdata field for pmic uclass driver with the assumption, that each pmic's child's uclass is the same type (e.g. regulator). But this assumption will be broken by fixed-regulator. And also, pmic's childs are not only regulators - e.g. one can be RTC, other charger, etc...
Quoted 24 lines
Quoted 24 lines
Quoted 10 lines
The last one is not supported. I have through several times about adding it. The alternative is to require each device to provide a platform data struct at the start of its own platform data, which the uclass can find and use. This is not really in the spirit of driver model. But for now this is what I have done with USB (see dm/usb-working). struct
usb_platdataappears at the start of structexynos_ehci_platdatabut is owned by the uclass.Quoted 4 lines
If PMIC has use for uclass platform data, then perhaps that would be enough users to warrant it. You could add a patch to do this (don't forget to update tests) or you could do what I have done with USB and we can tidy it up later.
The example of usb is good enough. I could move the "
dm_regulator_info" into thedm_regulator_platdata, and add "void*dev_platdata" at the end of it.
From the other side, the regulator constraints and modes, are all what we
need for this uclass.
We have also the fixed-regulators which some platform data are the same as for the generic regulators - then thedev->uclass_platdatais reasonable for this purpose.
Quoted 5 lines
Quoted 2 lines
I will add the uclass platdata to struct udevice and also some test to test/dm drivers. I will send it as a separate patch.
OK thanks. As a reminded, please continue to rebase on dm/next.
Ok, I will rebase it.
Quoted 11 lines
Quoted 11 lines
Quoted 9 lines
Re your naming problem, apart from case the device name and regulator-compatible name are the same. So perhaps just use case-insensitive search for regulators? But if not then I take back my comment about using a common function for searching for regulator names. You are really searching the platform data for the regulator-compatible string, not the device name, and so the common function cannot be used.
Quoted 9 lines
Quoted 3 lines
Then we could provide two functions:
-regulator_by_devname()- search for device -> name
-regulator_by_platname()- search for platdata -> nameOK.
Regards,
Simon
Thanks,
Signature · 4 lines
Przemyslaw Marczak Samsung R&D Institute Poland Samsung Electronics p.marczak at samsung.com
PATCH v3 7/17 dm: pmic: add pmic command
In reply to Przemyslaw MarczakThis is new command for the pmic devices based on driver model pmic api. Command features are unchanged:
- list - list UCLASS 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.
Changes v3:
- new file
- add Kconfig
--- common/Kconfig | 14 ++++ common/Makefile | 3 + common/cmd_pmic.c | 210 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 227 insertions(+) create mode 100644 common/cmd_pmic.c
common/Kconfig +14 -0
@@ -335,4 +335,18 @@ config CMD_SETGETDCR endmenu +menu "Power commands" +config DM_PMIC_CMD + bool "Enable Driver Model PMIC command" + depends on DM_PMIC + help + This is new command for the pmic devices based on driver model pmic api. + Command features are unchanged: + - list - list UCLASS 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
@@ -208,6 +208,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_DM_PMIC_CMD) += cmd_pmic.o endif ifdef CONFIG_SPL_BUILD
common/cmd_pmic.c new file +210 -0
210 lines not on this page · raw message
Signature · 1 line
1.9.1
PATCH v3 7/17 dm: pmic: add pmic command
Hi Prazemyslaw,
Quoted 27 lines · Przemyslaw Marczak
This is new command for the pmic devices based on driver model pmic api. Command features are unchanged:
- list - list UCLASS 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.
Signed-off-by Przemyslaw Marczak <[email protected]>Changes v3:
- new file
- addKconfig--- common/Kconfig | 14 ++++ common/Makefile | 3 + common/cmd_pmic.c | 210 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 227 insertions(+) create mode 100644 common/cmd_pmic.ccommon/Kconfig +0
-0
common/Kconfig config CMD_SETGETDCR · line 339
Quoted 5 lines
common/Kconfig +2
-0@@ -335,4 +335,18 @@ config CMD_SETGETDCR endmenu +menu "Power commands" +config DM_PMIC_CMD
CMD_DM_PMIC
since this fits better with the other ones
Quoted 89 lines
common/Kconfig +12
-0+ bool "Enable Driver Model PMIC command" + depends on DM_PMIC + help + This is new command for the pmic devices based on driver model pmic api. + Command features are unchanged: + - list - list UCLASS 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 endmenucommon/Makefile +3
-0@@ -208,6 +208,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_DM_PMIC_CMD) += cmd_pmic.o endif ifdef CONFIG_SPL_BUILDcommon/cmd_pmic.c new file +56
-0@@ -0,0 +1,210 @@ +/* +* Copyright (C) 2014-2015 Samsung Electronics +* Przemyslaw Marczak <[email protected]> +* +* SPDX-License-Identifier: GPL-2.0+ +*/ +#include <common.h> +#include <linux/types.h> +#include <linux/ctype.h> +#include <fdtdec.h> +#include <dm.h> +#include <power/pmic.h> +#include <power/regulator.h> +#include <dm/device-internal.h> +#include <dm/uclass-internal.h> +#include <dm/root.h> +#include <dm/lists.h> +#include <i2c.h> +#include <compiler.h> +#include <errno.h> + +#define LIMIT_SEQ 3 +#define LIMIT_DEVNAME 20 + +static struct udevice *pmic_curr; + +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)); +return CMD_RET_FAILURE ; +} + +static int do_dev (cmd_tbl_t *cmdtp,int flag,int argc,char *const argv[]) +{ +int seq, ret = -ENODEV ; + +switch (argc) { +case 2 : + seq =simple_strtoul (argv[1 ],NULL ,0 ); + ret =uclass_get_device_by_seq (UCLASS_PMIC , seq, &pmic_curr); +case 1 : +if (!pmic_curr) +return failed ("get" ,"the" ,"device" , ret); + +printf ("dev: %d @ %s\n" , pmic_curr->seq, pmic_curr->name); + } + +return CMD_RET_SUCCESS ; +} + +static int do_list (cmd_tbl_t *cmdtp,int flag,int argc,char *const argv[]) +{ +struct udevice *dev; +const char *parent_uc;
common/cmd_pmic.c line 66
Quoted 10 lines
common/cmd_pmic.c new file +10
-0+int ret; + +printf ("|%*s | %-*.*s| %-*.*s| %s @ %s\n" , +LIMIT_SEQ ,"Seq" , +LIMIT_DEVNAME ,LIMIT_DEVNAME ,"Name" , +LIMIT_DEVNAME ,LIMIT_DEVNAME ,"Parent name" , +"Parent uclass" ,"seq" ); + +for (ret =uclass_first_device (UCLASS_PMIC , &dev); dev; + ret =uclass_next_device (&dev)) {
Note this will probe everything.
Perhaps we need uclass_find_first_device() and uclass_find_next_device() which don't probe before returning each device?
common/cmd_pmic.c line 71
Quoted 5 lines
common/cmd_pmic.c new file +5
-0+if (!dev) +continue ; + +/* Parent uclass name*/ + parent_uc = dev->parent->uclass->uc_drv->name;
What do you think about a new function at some point, so you can call dev_uclass_name(dev_get_parent(dev))? We want to avoid digging around in the driver model data structures outside drivers/core.
Quoted 21 lines
common/cmd_pmic.c new file +21
-0+ +printf ("|%*d | %-*.*s| %-*.*s| %s @ %d\n" , +LIMIT_SEQ , dev->seq, +LIMIT_DEVNAME ,LIMIT_DEVNAME , dev->name, +LIMIT_DEVNAME ,LIMIT_DEVNAME , dev->parent->name, + parent_uc, dev->parent->seq); + } + +if (ret) +return CMD_RET_FAILURE ; + +return CMD_RET_SUCCESS ; +} + +static int do_dump (cmd_tbl_t *cmdtp,int flag,int argc,char *const argv[]) +{ +struct udevice *dev; +int regs, ret; +uint8_t value; +uint reg; +
common/cmd_pmic.c line 102
Quoted 10 lines
common/cmd_pmic.c new file +10
-0+if (!pmic_curr) +return failed ("get" ,"current" ,"device" , -ENODEV ); + + dev = pmic_curr; + +printf ("Dump pmic: %s registers\n" , dev->name); + + regs =pmic_reg_count (dev); + reg =0 ; +while (reg < regs) {
for (ret = 0; ret < regs; reg++) {
Quoted 93 lines
common/cmd_pmic.c new file +93
-0+ ret =pmic_read (dev, reg, &value,1 ); +if (ret) +return failed ("read" , dev->name,"register" , ret); + +if (!(reg %16 )) +printf ("\n0x%02x: " , reg); + +printf ("%2.2x " , value); + reg++; + } +printf ("\n" ); + +return CMD_RET_SUCCESS ; +} + +static int do_read (cmd_tbl_t *cmdtp,int flag,int argc,char *const argv[]) +{ +struct udevice *dev; +int regs, ret; +uint8_t value; +uint reg; + +if (!pmic_curr) +return failed ("get" ,"current" ,"device" , -ENODEV ); + + dev = pmic_curr; + +if (argc !=2 ) +return CMD_RET_USAGE ; + + reg =simple_strtoul (argv[1 ],NULL ,0 ); + regs =pmic_reg_count (dev); +if (reg > regs) { +printf ("Pmic max reg: %d\n" , regs); +return failed ("read" ,"given" ,"address" , -EFAULT ); + } + + ret =pmic_read (dev, reg, &value,1 ); +if (ret) +return failed ("read" , dev->name,"register" , ret); + +printf ("0x%02x: 0x%2.2x\n" , reg, value); + +return CMD_RET_SUCCESS ; +} + +static int do_write (cmd_tbl_t *cmdtp,int flag,int argc,char *const argv[]) +{ +struct udevice *dev; +int regs, ret; +uint8_t value; +uint reg; + +if (!pmic_curr) +return failed ("get" ,"current" ,"device" , -ENODEV ); + + dev = pmic_curr; + +if (argc !=3 ) +return CMD_RET_USAGE ; + + reg =simple_strtoul (argv[1 ],NULL ,0 ); + regs =pmic_reg_count (dev); +if (reg > regs) { +printf ("Pmic max reg: %d\n" , regs); +return failed ("write" ,"given" ,"address" , -EFAULT ); + } + + value =simple_strtoul (argv[2 ],NULL ,0 ); + + ret =pmic_write (dev, reg, &value,1 ); +if (ret) +return failed ("write" , dev->name,"register" , 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 (dump,1 ,1 , do_dump,"" ,"" ), +U_BOOT_CMD_MKENT (read,2 ,1 , do_read,"" ,"" ), +U_BOOT_CMD_MKENT (write,3 ,1 , do_write,"" ,"" ), +}; + +static int do_pmic (cmd_tbl_t *cmdtp,int flag,int argc, +char *const argv[]) +{ +cmd_tbl_t *cmd; + + argc--; + argv++; +
common/cmd_pmic.c line 205
Quoted 10 lines
common/cmd_pmic.c new file +10
-0+ 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 (pmic,CONFIG_SYS_MAXARGS ,1 , do_pmic, +"uclass operations" , + "list - list UCLASS pmic devices\n"
Can we drop the 'UCLASS' ?
Quoted 8 lines
common/cmd_pmic.c new file +5
-1+"pmic dev [id] - show or [set] operating pmic device\n" +"pmic dump - dump registers\n" +"pmic read address - read byte of register at address\n" +"pmic write address - write byte to register at address\n" +); --1.9.1
Regards,
Simon
PATCH v3 7/17 dm: pmic: add pmic command
Hello Simon,
Quoted 31 lines · Simon Glass
Hi Prazemyslaw,
Quoted 28 lines · Przemyslaw Marczak
This is new command for the pmic devices based on driver model pmic api. Command features are unchanged:
- list - list UCLASS 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.
Signed-off-by Przemyslaw Marczak <[email protected]>Changes v3:
- new file
- addKconfig--- common/Kconfig | 14 ++++ common/Makefile | 3 + common/cmd_pmic.c | 210 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 227 insertions(+)create mode 100644
common/cmd_pmic.ccommon/Kconfig +0
-0@@ -335,4 +335,18 @@ config CMD_SETGETDCR
Quoted 9 lines
common/Kconfig config CMD_SETGETDCR · line 339
Quoted 4 lines
common/Kconfig +2
-0endmenu +menu "Power commands" +config DM_PMIC_CMD
CMD_DM_PMICsince this fits better with the other ones
Ok
Quoted 102 lines
Quoted 89 lines
common/Kconfig +12
-0+ bool "Enable Driver Model PMIC command" + depends on DM_PMIC + help + This is new command for the pmic devices based on driver model pmic api. + Command features are unchanged: + - list - list UCLASS 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 endmenucommon/Makefile +3
-0@@ -208,6 +208,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_DM_PMIC_CMD) += cmd_pmic.o endif ifdef CONFIG_SPL_BUILDcommon/cmd_pmic.c new file +56
-0@@ -0,0 +1,210 @@ +/* +* Copyright (C) 2014-2015 Samsung Electronics +* Przemyslaw Marczak <[email protected]> +* +* SPDX-License-Identifier: GPL-2.0+ +*/ +#include <common.h> +#include <linux/types.h> +#include <linux/ctype.h> +#include <fdtdec.h> +#include <dm.h> +#include <power/pmic.h> +#include <power/regulator.h> +#include <dm/device-internal.h> +#include <dm/uclass-internal.h> +#include <dm/root.h> +#include <dm/lists.h> +#include <i2c.h> +#include <compiler.h> +#include <errno.h> + +#define LIMIT_SEQ 3 +#define LIMIT_DEVNAME 20 + +static struct udevice *pmic_curr; + +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)); +return CMD_RET_FAILURE ; +} + +static int do_dev (cmd_tbl_t *cmdtp,int flag,int argc,char *const argv[]) +{ +int seq, ret = -ENODEV ; + +switch (argc) { +case 2 : + seq =simple_strtoul (argv[1 ],NULL ,0 ); + ret =uclass_get_device_by_seq (UCLASS_PMIC , seq, &pmic_curr); +case 1 : +if (!pmic_curr) +return failed ("get" ,"the" ,"device" , ret); + +printf ("dev: %d @ %s\n" , pmic_curr->seq, pmic_curr->name); + } + +return CMD_RET_SUCCESS ; +} + +static int do_list (cmd_tbl_t *cmdtp,int flag,int argc,char *const argv[]) +{ +struct udevice *dev; +const char *parent_uc;common/cmd_pmic.c line 66
Quoted 10 lines
common/cmd_pmic.c new file +10
-0+int ret; + +printf ("|%*s | %-*.*s| %-*.*s| %s @ %s\n" , +LIMIT_SEQ ,"Seq" , +LIMIT_DEVNAME ,LIMIT_DEVNAME ,"Name" , +LIMIT_DEVNAME ,LIMIT_DEVNAME ,"Parent name" , +"Parent uclass" ,"seq" ); + +for (ret =uclass_first_device (UCLASS_PMIC , &dev); dev; + ret =uclass_next_device (&dev)) {Note this will probe everything.
Quoted 5 lines
Perhaps we need
uclass_find_first_device()anduclass_find_next_device()which don't probe before returning each device?
Right, I will extend the uclass.c API.
Quoted 10 lines
common/cmd_pmic.c line 71
Quoted 5 lines
common/cmd_pmic.c new file +5
-0+if (!dev) +continue ; + +/* Parent uclass name*/ + parent_uc = dev->parent->uclass->uc_drv->name;What do you think about a new function at some point, so you can call dev_uclass_name(dev_get_parent(dev))? We want to avoid digging around in the driver model data structures outside
drivers/core.
Good idea, will move to uclass API.
Quoted 25 lines
Quoted 25 lines
common/cmd_pmic.c new file +25
-0+ +printf ("|%*d | %-*.*s| %-*.*s| %s @ %d\n" , +LIMIT_SEQ , dev->seq, +LIMIT_DEVNAME ,LIMIT_DEVNAME , dev->name, +LIMIT_DEVNAME ,LIMIT_DEVNAME , dev->parent->name, + parent_uc, dev->parent->seq); + } + +if (ret) +return CMD_RET_FAILURE ; + +return CMD_RET_SUCCESS ; +} + +static int do_dump (cmd_tbl_t *cmdtp,int flag,int argc,char *const argv[]) +{ +struct udevice *dev; +int regs, ret; +uint8_t value; +uint reg; + +if (!pmic_curr) +return failed ("get" ,"current" ,"device" , -ENODEV ); + + dev = pmic_curr;
Quoted 9 lines
common/cmd_pmic.c line 102
Quoted 6 lines
common/cmd_pmic.c new file +6
-0+ +printf ("Dump pmic: %s registers\n" , dev->name); + + regs =pmic_reg_count (dev); + reg =0 ; +while (reg < regs) {for (ret = 0; ret < regs; reg++) {
Ok.
Quoted 97 lines
Quoted 97 lines
common/cmd_pmic.c new file +97
-0+ ret =pmic_read (dev, reg, &value,1 ); +if (ret) +return failed ("read" , dev->name,"register" , ret); + +if (!(reg %16 )) +printf ("\n0x%02x: " , reg); + +printf ("%2.2x " , value); + reg++; + } +printf ("\n" ); + +return CMD_RET_SUCCESS ; +} + +static int do_read (cmd_tbl_t *cmdtp,int flag,int argc,char *const argv[]) +{ +struct udevice *dev; +int regs, ret; +uint8_t value; +uint reg; + +if (!pmic_curr) +return failed ("get" ,"current" ,"device" , -ENODEV ); + + dev = pmic_curr; + +if (argc !=2 ) +return CMD_RET_USAGE ; + + reg =simple_strtoul (argv[1 ],NULL ,0 ); + regs =pmic_reg_count (dev); +if (reg > regs) { +printf ("Pmic max reg: %d\n" , regs); +return failed ("read" ,"given" ,"address" , -EFAULT ); + } + + ret =pmic_read (dev, reg, &value,1 ); +if (ret) +return failed ("read" , dev->name,"register" , ret); + +printf ("0x%02x: 0x%2.2x\n" , reg, value); + +return CMD_RET_SUCCESS ; +} + +static int do_write (cmd_tbl_t *cmdtp,int flag,int argc,char *const argv[]) +{ +struct udevice *dev; +int regs, ret; +uint8_t value; +uint reg; + +if (!pmic_curr) +return failed ("get" ,"current" ,"device" , -ENODEV ); + + dev = pmic_curr; + +if (argc !=3 ) +return CMD_RET_USAGE ; + + reg =simple_strtoul (argv[1 ],NULL ,0 ); + regs =pmic_reg_count (dev); +if (reg > regs) { +printf ("Pmic max reg: %d\n" , regs); +return failed ("write" ,"given" ,"address" , -EFAULT ); + } + + value =simple_strtoul (argv[2 ],NULL ,0 ); + + ret =pmic_write (dev, reg, &value,1 ); +if (ret) +return failed ("write" , dev->name,"register" , 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 (dump,1 ,1 , do_dump,"" ,"" ), +U_BOOT_CMD_MKENT (read,2 ,1 , do_read,"" ,"" ), +U_BOOT_CMD_MKENT (write,3 ,1 , do_write,"" ,"" ), +}; + +static int do_pmic (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 ; +
Quoted 9 lines
common/cmd_pmic.c line 205
Quoted 6 lines
common/cmd_pmic.c new file +6
-0+return cmd->cmd (cmdtp, flag, argc, argv); +} + +U_BOOT_CMD (pmic,CONFIG_SYS_MAXARGS ,1 , do_pmic, +"uclass operations" , + "list - list UCLASS pmic devices\n"Can we drop the 'UCLASS' ?
Ok
Quoted 9 lines
Quoted 8 lines
common/cmd_pmic.c new file +5
-1+"pmic dev [id] - show or [set] operating pmic device\n" +"pmic dump - dump registers\n" +"pmic read address - read byte of register at address\n" +"pmic write address - write byte to register at address\n" +); --1.9.1
Quoted 3 lines
Regards,
Simon
Thanks,
Signature · 4 lines
Przemyslaw Marczak Samsung R&D Institute Poland Samsung Electronics p.marczak at samsung.com
PATCH v3 8/17 dm: regulator: add regulator command
In reply to Przemyslaw MarczakThis 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
The 'force' option can be used for setting the value which exceeds the limits, which are found in device-tree and are keept in regulators info structure.
---
Changes v3:
- new file
- Kconfig entry
--- common/Kconfig | 22 +++ common/Makefile | 1 + common/cmd_regulator.c | 385 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 408 insertions(+) create mode 100644 common/cmd_regulator.c
common/Kconfig +22 -0
@@ -348,5 +348,27 @@ config DM_PMIC_CMD - 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 DM_REGULATOR_CMD + bool "Enable Driver Model REGULATOR command" + depends on DM_REGULATOR + help + 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 + + The 'force' option can be used for setting the value which exceeds + the limit which are found in device-tree and are keept in regulators + info structure. + endmenu + endmenu
common/Makefile +1 -0
@@ -211,6 +211,7 @@ obj-$(CONFIG_CMD_GPT) += cmd_gpt.o # Power obj-$(CONFIG_DM_PMIC_CMD) += cmd_pmic.o +obj-$(CONFIG_DM_REGULATOR_CMD) += cmd_regulator.o endif ifdef CONFIG_SPL_BUILD
common/cmd_regulator.c new file +385 -0
385 lines not on this page · raw message
Signature · 1 line
1.9.1
PATCH v3 8/17 dm: regulator: add regulator command
Hi Przemyslaw,
Quoted 33 lines · Przemyslaw Marczak
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 outputThe 'force' option can be used for setting the value which exceeds the limits, which are found in device-tree and are keept in regulators info structure.
Signed-off-by Przemyslaw Marczak <[email protected]>---
Changes v3:
- new file
-Kconfigentry--- common/Kconfig | 22 +++ common/Makefile | 1 + common/cmd_regulator.c | 385 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 408 insertions(+) create mode 100644 common/cmd_regulator.ccommon/Kconfig +0
-0
common/Kconfig config DM_PMIC_CMD · line 352
Quoted 5 lines
common/Kconfig +2
-0@@ -348,5 +348,27 @@ config DM_PMIC_CMD - 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 DM_REGULATOR_CMD
CMD_DM_REGULATOR
common/Kconfig config DM_PMIC_CMD · line 358
Quoted 6 lines
common/Kconfig +6
-0+ bool "Enable Driver Model REGULATOR command" + depends on DM_REGULATOR + help + This command is based on driver model regulator api. + User interface features: + - list - list UCLASS regulator devices
Do you need 'UCLASS" in there? What does it mean?
common/Kconfig config DM_PMIC_CMD · line 366
Quoted 8 lines
common/Kconfig +8
-0+ - 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
I don't think the sub-commands should be in [].
Quoted 61 lines
common/Kconfig +6
-0+ + The 'force' option can be used for setting the value which exceeds + the limit which are found in device-tree and are keept in regulators + info structure. + endmenu + endmenucommon/Makefile +1
-0@@ -211,6 +211,7 @@ obj-$(CONFIG_CMD_GPT) += cmd_gpt.o # Power obj-$(CONFIG_DM_PMIC_CMD) += cmd_pmic.o +obj-$(CONFIG_DM_REGULATOR_CMD) += cmd_regulator.o endif ifdef CONFIG_SPL_BUILDcommon/cmd_regulator.c new file +35
-0@@ -0,0 +1,385 @@ +/* +* Copyright (C) 2014-2015 Samsung Electronics +* Przemyslaw Marczak <[email protected]> +* +* SPDX-License-Identifier: GPL-2.0+ +*/ +#include <common.h> +#include <linux/types.h> +#include <linux/ctype.h> +#include <fdtdec.h> +#include <dm.h> +#include <power/pmic.h> +#include <power/regulator.h> +#include <dm/device-internal.h> +#include <dm/uclass-internal.h> +#include <dm/root.h> +#include <dm/lists.h> +#include <i2c.h> +#include <compiler.h> +#include <errno.h> + +#define LIMIT_SEQ 3 +#define LIMIT_DEVNAME 20 +#define LIMIT_OFNAME 20 +#define LIMIT_INFO 12 + +static struct udevice *reg_curr; + +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)); +return CMD_RET_FAILURE ; +}
common/cmd_regulator.c line 45
Quoted 10 lines
common/cmd_regulator.c new file +10
-0+ +static int do_dev (cmd_tbl_t *cmdtp,int flag,int argc,char *const argv[]) +{ +struct dm_regulator_info *info; +int seq, ret =CMD_RET_FAILURE ; + +switch (argc) { +case 2 : + seq =simple_strtoul (argv[1 ],NULL ,0 ); +uclass_get_device_by_seq (UCLASS_REGULATOR , seq, ®_curr);
This can return an error.
Quoted 247 lines
common/cmd_regulator.c new file +247
-0+case 1 : + ret =regulator_info (reg_curr, &info); +if (ret) +return failed ("get" ,"the" ,"device" , ret); + +printf ("dev: %d @ %s\n" , reg_curr->seq, info->name); + } + +return CMD_RET_SUCCESS ; +} + +static int get_curr_dev_and_info (struct udevice **devp, +struct dm_regulator_info **infop) +{ +int ret = -ENODEV ; + + *devp = reg_curr; +if (!*devp) +return failed ("get" ,"current" ,"device" , ret); + + ret =regulator_info (*devp, infop); +if (ret) +return failed ("get" , reg_curr->name,"info" , ret); + +return CMD_RET_SUCCESS ; +} + +static int do_list (cmd_tbl_t *cmdtp,int flag,int argc,char *const argv[]) +{ +struct dm_regulator_info *info; +const char *parent_uc; +struct udevice *dev; +int ret; + +printf ("|%*s | %*.*s @ %-*.*s| %s @ %s\n" , +LIMIT_SEQ ,"Seq" , +LIMIT_DEVNAME ,LIMIT_DEVNAME ,"Name" , +LIMIT_OFNAME ,LIMIT_OFNAME ,"fdtname" , +"Parent" ,"uclass" ); + +for (ret =uclass_first_device (UCLASS_REGULATOR , &dev); dev; + ret =uclass_next_device (&dev)) { +if (regulator_info (dev, &info)) { +printf ("(null) info for: %s\n" , dev->name); +continue ; + } + +/* Parent uclass name*/ + parent_uc = dev->parent->uclass->uc_drv->name; + +printf ("|%*d | %*.*s @ %-*.*s| %s @ %s\n" , +LIMIT_SEQ , dev->seq, +LIMIT_DEVNAME ,LIMIT_DEVNAME , dev->name, +LIMIT_OFNAME ,LIMIT_OFNAME , info->name, + dev->parent->name, parent_uc); + } + +if (ret) +return CMD_RET_FAILURE ; + +return CMD_RET_SUCCESS ; +} + +static int do_info (cmd_tbl_t *cmdtp,int flag,int argc,char *const argv[]) +{ +struct udevice *dev; +struct dm_regulator_info *info; +struct dm_regulator_mode *modes; +const char *parent_uc; +int mode_count; +int ret; +int i; + + ret =get_curr_dev_and_info (&dev, &info); +if (ret) +return CMD_RET_FAILURE ; + + parent_uc = dev->parent->uclass->uc_drv->name; + +printf ("Uclass regulator dev %d info:\n" , dev->seq); +printf ("%-*s %s @ %s\n%-*s %s\n%-*s %s\n" , +LIMIT_INFO ,"* parent:" , dev->parent->name, parent_uc, +LIMIT_INFO ,"* dev name:" , dev->name, +LIMIT_INFO ,"* fdt name:" , info->name); + +printf ("%-*s %d\n%-*s %d\n%-*s %d\n%-*s %d\n%-*s %s\n%-*s %s\n" , +LIMIT_INFO ,"* min uV:" , info->min_uV, +LIMIT_INFO ,"* max uV:" , info->max_uV, +LIMIT_INFO ,"* min uA:" , info->min_uA, +LIMIT_INFO ,"* max uA:" , info->max_uA, +LIMIT_INFO ,"* always on:" , info->always_on ?"true" :"false" , +LIMIT_INFO ,"* boot on:" , info->boot_on ?"true" :"false" ); + + mode_count =regulator_mode (dev, &modes); +if (!mode_count) +return failed ("get mode" ,"for mode" ,"null count" , -EPERM ); + +if (mode_count <0 ) +return failed ("get" , info->name,"mode count" , mode_count); + +printf ("* operation modes:\n" ); +for (i =0 ; i < mode_count; i++, modes++) +printf (" - mode %d (%s)\n" , modes->id, modes->name); + +return CMD_RET_SUCCESS ; +} + +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_status (cmd_tbl_t *cmdtp,int flag,int argc,char *const argv[]) +{ +struct udevice *dev; +struct dm_regulator_info *info; +const char *mode_name; +int value, mode, ret; +bool enabled; + + ret =get_curr_dev_and_info (&dev, &info); +if (ret) +return CMD_RET_FAILURE ; + +/* Value is mandatory */ + value =regulator_get_value (dev); +if (value <0 ) +return failed ("get" , info->name,"voltage value" , value); + + mode =regulator_get_mode (dev); + mode_name =get_mode_name (info->mode, info->mode_count, mode); + enabled =regulator_get_enable (dev); + +printf ("Regulator seq %d status:\n" , dev->seq); +printf ("%-*s %d\n%-*s %d (%s)\n%-*s %s\n" , +LIMIT_INFO ," * value:" , value, +LIMIT_INFO ," * mode:" , mode, mode_name, +LIMIT_INFO ," * enabled:" , enabled ?"true" :"false" ); + +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_info *info; +int value; +int force; +int ret; + + ret =get_curr_dev_and_info (&dev, &info); +if (ret) +return CMD_RET_FAILURE ; + +if (argc ==1 ) { + value =regulator_get_value (dev); +if (value <0 ) +return failed ("get" , info->name,"voltage" , value); + +printf ("%d uV\n" , value); +return CMD_RET_SUCCESS ; + } + +if (info->type ==REGULATOR_TYPE_FIXED ) { +printf ("Fixed regulator value change not allowed.\n" ); +return CMD_RET_SUCCESS ; + } + +if (argc ==3 ) + force = !strcmp ("-f" , argv[2 ]); +else + force =0 ; + + value =simple_strtoul (argv[1 ],NULL ,0 ); +if ((value < info->min_uV || value > info->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" , info->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_info *info; +int current; +int ret; + + ret =get_curr_dev_and_info (&dev, &info); +if (ret) +return CMD_RET_FAILURE ; + +if (argc ==1 ) { + current =regulator_get_current (dev); +if (current <0 ) +return failed ("get" , info->name,"current" , current); + +printf ("%d uA\n" , current); +return CMD_RET_SUCCESS ; + } + +if (info->type ==REGULATOR_TYPE_FIXED ) { +printf ("Fixed regulator current change not allowed.\n" ); +return CMD_RET_SUCCESS ; + } + + current =simple_strtoul (argv[1 ],NULL ,0 ); +if (current < info->min_uA || current > info->max_uA) { +printf ("Current exceeds regulator constraint limits\n" ); +return CMD_RET_FAILURE ; + } + + ret =regulator_set_current (dev, current); +if (ret) +return failed ("set" , info->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_info *info; +int new_mode; +int mode; +int ret; + + ret =get_curr_dev_and_info (&dev, &info); +if (ret) +return CMD_RET_FAILURE ; + +if (info->type ==REGULATOR_TYPE_FIXED ) { +printf ("Fixed regulator mode option not allowed.\n" ); +return CMD_RET_SUCCESS ;
common/cmd_regulator.c line 302
Quoted 10 lines
common/cmd_regulator.c new file +10
-0+ } + +if (argc ==1 ) { + mode =regulator_get_mode (dev); +if (mode <0 ) +return failed ("get" , info->name,"mode" , ret); + +printf ("mode id: %d\n" , mode); +return CMD_RET_SUCCESS ; + }
The code above is the same for the above 2 functions also. Can you move it to a common function? Something list get_non_fixed_regulator()?
Quoted 72 lines
common/cmd_regulator.c new file +72
-0+ + new_mode =simple_strtoul (argv[1 ],NULL ,0 ); + + ret =regulator_set_mode (dev, new_mode); +if (ret) +return failed ("set" , info->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_info *info; +int ret; + + ret =get_curr_dev_and_info (&dev, &info); +if (ret) +return CMD_RET_FAILURE ; + + ret =regulator_set_enable (dev, true); +if (ret) +return failed ("enable" ,"regulator" , info->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_info *info; +int ret; + + ret =get_curr_dev_and_info (&dev, &info); +if (ret) +return CMD_RET_FAILURE ; + + ret =regulator_set_enable (dev, false); +if (ret) +return failed ("disable" ,"regulator" , info->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,
common/cmd_regulator.c line 384
Quoted 10 lines
common/cmd_regulator.c new file +10
-0+"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"
I think [info] should not be in brackets as it is not optional. Similar with other ones.
Regards,
Simon
PATCH v3 8/17 dm: regulator: add regulator command
Hello Simon,
Quoted 31 lines · Simon Glass
Hi Przemyslaw,
Quoted 28 lines · Przemyslaw Marczak
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 outputThe 'force' option can be used for setting the value which exceeds the limits, which are found in device-tree and are keept in regulators info structure.
Signed-off-by Przemyslaw Marczak <[email protected]>---
Changes v3:
- new file
-Kconfigentry--- common/Kconfig | 22 +++ common/Makefile | 1 + common/cmd_regulator.c | 385 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 408 insertions(+)create mode 100644
common/cmd_regulator.c
Quoted 13 lines
common/Kconfig config DM_PMIC_CMD · line 352
Quoted 10 lines
common/Kconfig +2
-0@@ -348,5 +348,27 @@ config DM_PMIC_CMD - 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 DM_REGULATOR_CMD
CMD_DM_REGULATOR
Ok
Quoted 9 lines
common/Kconfig config DM_PMIC_CMD · line 358
Quoted 6 lines
common/Kconfig +6
-0+ bool "Enable Driver Model REGULATOR command" + depends on DM_REGULATOR + help + This command is based on driver model regulator api. + User interface features: + - list - list UCLASS regulator devicesDo you need 'UCLASS" in there? What does it mean?
Right, it has no sense...
Quoted 11 lines
common/Kconfig config DM_PMIC_CMD · line 366
Quoted 8 lines
common/Kconfig +8
-0+ - 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 outputI don't think the sub-commands should be in [].
Right, will fix it.
Quoted 65 lines
Quoted 65 lines
common/Kconfig +6
-0+ + The 'force' option can be used for setting the value which exceeds + the limit which are found in device-tree and are keept in regulators + info structure. + endmenu + endmenucommon/Makefile +1
-0@@ -211,6 +211,7 @@ obj-$(CONFIG_CMD_GPT) += cmd_gpt.o # Power obj-$(CONFIG_DM_PMIC_CMD) += cmd_pmic.o +obj-$(CONFIG_DM_REGULATOR_CMD) += cmd_regulator.o endif ifdef CONFIG_SPL_BUILDcommon/cmd_regulator.c new file +39
-0@@ -0,0 +1,385 @@ +/* +* Copyright (C) 2014-2015 Samsung Electronics +* Przemyslaw Marczak <[email protected]> +* +* SPDX-License-Identifier: GPL-2.0+ +*/ +#include <common.h> +#include <linux/types.h> +#include <linux/ctype.h> +#include <fdtdec.h> +#include <dm.h> +#include <power/pmic.h> +#include <power/regulator.h> +#include <dm/device-internal.h> +#include <dm/uclass-internal.h> +#include <dm/root.h> +#include <dm/lists.h> +#include <i2c.h> +#include <compiler.h> +#include <errno.h> + +#define LIMIT_SEQ 3 +#define LIMIT_DEVNAME 20 +#define LIMIT_OFNAME 20 +#define LIMIT_INFO 12 + +static struct udevice *reg_curr; + +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)); +return CMD_RET_FAILURE ; +} + +static int do_dev (cmd_tbl_t *cmdtp,int flag,int argc,char *const argv[]) +{ +struct dm_regulator_info *info;
Quoted 9 lines
common/cmd_regulator.c line 45
Quoted 6 lines
common/cmd_regulator.c new file +6
-0+int seq, ret =CMD_RET_FAILURE ; + +switch (argc) { +case 2 : + seq =simple_strtoul (argv[1 ],NULL ,0 ); +uclass_get_device_by_seq (UCLASS_REGULATOR , seq, ®_curr);This can return an error.
Yes, but there is no case break, and the below regulator_info(), checks if reg_curr isn't NULL, and here the ret is returned.
Quoted 253 lines
Quoted 253 lines
common/cmd_regulator.c new file +253
-0+case 1 : + ret =regulator_info (reg_curr, &info); +if (ret) +return failed ("get" ,"the" ,"device" , ret); + +printf ("dev: %d @ %s\n" , reg_curr->seq, info->name); + } + +return CMD_RET_SUCCESS ; +} + +static int get_curr_dev_and_info (struct udevice **devp, +struct dm_regulator_info **infop) +{ +int ret = -ENODEV ; + + *devp = reg_curr; +if (!*devp) +return failed ("get" ,"current" ,"device" , ret); + + ret =regulator_info (*devp, infop); +if (ret) +return failed ("get" , reg_curr->name,"info" , ret); + +return CMD_RET_SUCCESS ; +} + +static int do_list (cmd_tbl_t *cmdtp,int flag,int argc,char *const argv[]) +{ +struct dm_regulator_info *info; +const char *parent_uc; +struct udevice *dev; +int ret; + +printf ("|%*s | %*.*s @ %-*.*s| %s @ %s\n" , +LIMIT_SEQ ,"Seq" , +LIMIT_DEVNAME ,LIMIT_DEVNAME ,"Name" , +LIMIT_OFNAME ,LIMIT_OFNAME ,"fdtname" , +"Parent" ,"uclass" ); + +for (ret =uclass_first_device (UCLASS_REGULATOR , &dev); dev; + ret =uclass_next_device (&dev)) { +if (regulator_info (dev, &info)) { +printf ("(null) info for: %s\n" , dev->name); +continue ; + } + +/* Parent uclass name*/ + parent_uc = dev->parent->uclass->uc_drv->name; + +printf ("|%*d | %*.*s @ %-*.*s| %s @ %s\n" , +LIMIT_SEQ , dev->seq, +LIMIT_DEVNAME ,LIMIT_DEVNAME , dev->name, +LIMIT_OFNAME ,LIMIT_OFNAME , info->name, + dev->parent->name, parent_uc); + } + +if (ret) +return CMD_RET_FAILURE ; + +return CMD_RET_SUCCESS ; +} + +static int do_info (cmd_tbl_t *cmdtp,int flag,int argc,char *const argv[]) +{ +struct udevice *dev; +struct dm_regulator_info *info; +struct dm_regulator_mode *modes; +const char *parent_uc; +int mode_count; +int ret; +int i; + + ret =get_curr_dev_and_info (&dev, &info); +if (ret) +return CMD_RET_FAILURE ; + + parent_uc = dev->parent->uclass->uc_drv->name; + +printf ("Uclass regulator dev %d info:\n" , dev->seq); +printf ("%-*s %s @ %s\n%-*s %s\n%-*s %s\n" , +LIMIT_INFO ,"* parent:" , dev->parent->name, parent_uc, +LIMIT_INFO ,"* dev name:" , dev->name, +LIMIT_INFO ,"* fdt name:" , info->name); + +printf ("%-*s %d\n%-*s %d\n%-*s %d\n%-*s %d\n%-*s %s\n%-*s %s\n" , +LIMIT_INFO ,"* min uV:" , info->min_uV, +LIMIT_INFO ,"* max uV:" , info->max_uV, +LIMIT_INFO ,"* min uA:" , info->min_uA, +LIMIT_INFO ,"* max uA:" , info->max_uA, +LIMIT_INFO ,"* always on:" , info->always_on ?"true" :"false" , +LIMIT_INFO ,"* boot on:" , info->boot_on ?"true" :"false" ); + + mode_count =regulator_mode (dev, &modes); +if (!mode_count) +return failed ("get mode" ,"for mode" ,"null count" , -EPERM ); + +if (mode_count <0 ) +return failed ("get" , info->name,"mode count" , mode_count); + +printf ("* operation modes:\n" ); +for (i =0 ; i < mode_count; i++, modes++) +printf (" - mode %d (%s)\n" , modes->id, modes->name); + +return CMD_RET_SUCCESS ; +} + +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_status (cmd_tbl_t *cmdtp,int flag,int argc,char *const argv[]) +{ +struct udevice *dev; +struct dm_regulator_info *info; +const char *mode_name; +int value, mode, ret; +bool enabled; + + ret =get_curr_dev_and_info (&dev, &info); +if (ret) +return CMD_RET_FAILURE ; + +/* Value is mandatory */ + value =regulator_get_value (dev); +if (value <0 ) +return failed ("get" , info->name,"voltage value" , value); + + mode =regulator_get_mode (dev); + mode_name =get_mode_name (info->mode, info->mode_count, mode); + enabled =regulator_get_enable (dev); + +printf ("Regulator seq %d status:\n" , dev->seq); +printf ("%-*s %d\n%-*s %d (%s)\n%-*s %s\n" , +LIMIT_INFO ," * value:" , value, +LIMIT_INFO ," * mode:" , mode, mode_name, +LIMIT_INFO ," * enabled:" , enabled ?"true" :"false" ); + +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_info *info; +int value; +int force; +int ret; + + ret =get_curr_dev_and_info (&dev, &info); +if (ret) +return CMD_RET_FAILURE ; + +if (argc ==1 ) { + value =regulator_get_value (dev); +if (value <0 ) +return failed ("get" , info->name,"voltage" , value); + +printf ("%d uV\n" , value); +return CMD_RET_SUCCESS ; + } + +if (info->type ==REGULATOR_TYPE_FIXED ) { +printf ("Fixed regulator value change not allowed.\n" ); +return CMD_RET_SUCCESS ; + } + +if (argc ==3 ) + force = !strcmp ("-f" , argv[2 ]); +else + force =0 ; + + value =simple_strtoul (argv[1 ],NULL ,0 ); +if ((value < info->min_uV || value > info->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" , info->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_info *info; +int current; +int ret; + + ret =get_curr_dev_and_info (&dev, &info); +if (ret) +return CMD_RET_FAILURE ; + +if (argc ==1 ) { + current =regulator_get_current (dev); +if (current <0 ) +return failed ("get" , info->name,"current" , current); + +printf ("%d uA\n" , current); +return CMD_RET_SUCCESS ; + } + +if (info->type ==REGULATOR_TYPE_FIXED ) { +printf ("Fixed regulator current change not allowed.\n" ); +return CMD_RET_SUCCESS ; + } + + current =simple_strtoul (argv[1 ],NULL ,0 ); +if (current < info->min_uA || current > info->max_uA) { +printf ("Current exceeds regulator constraint limits\n" ); +return CMD_RET_FAILURE ; + } + + ret =regulator_set_current (dev, current); +if (ret) +return failed ("set" , info->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_info *info; +int new_mode; +int mode; +int ret; + + ret =get_curr_dev_and_info (&dev, &info); +if (ret) +return CMD_RET_FAILURE ; + +if (info->type ==REGULATOR_TYPE_FIXED ) { +printf ("Fixed regulator mode option not allowed.\n" ); +return CMD_RET_SUCCESS ; + } + +if (argc ==1 ) { + mode =regulator_get_mode (dev); +if (mode <0 ) +return failed ("get" , info->name,"mode" , ret);
Quoted 9 lines
common/cmd_regulator.c line 302
Quoted 4 lines
common/cmd_regulator.c new file +4
-0+ +printf ("mode id: %d\n" , mode); +return CMD_RET_SUCCESS ; + }The code above is the same for the above 2 functions also. Can you move it to a common function? Something list
get_non_fixed_regulator()?
Ok, will add something like this.
Quoted 77 lines
Quoted 77 lines
common/cmd_regulator.c new file +77
-0+ + new_mode =simple_strtoul (argv[1 ],NULL ,0 ); + + ret =regulator_set_mode (dev, new_mode); +if (ret) +return failed ("set" , info->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_info *info; +int ret; + + ret =get_curr_dev_and_info (&dev, &info); +if (ret) +return CMD_RET_FAILURE ; + + ret =regulator_set_enable (dev, true); +if (ret) +return failed ("enable" ,"regulator" , info->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_info *info; +int ret; + + ret =get_curr_dev_and_info (&dev, &info); +if (ret) +return CMD_RET_FAILURE ; + + ret =regulator_set_enable (dev, false); +if (ret) +return failed ("disable" ,"regulator" , info->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"
Quoted 8 lines
common/cmd_regulator.c line 384
Quoted 5 lines
common/cmd_regulator.c new file +5
-0+"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" I think [info] should not be in brackets as it is not optional. Similar with other ones.
Right, will fix.
Quoted 4 lines
Regards,
Simon
Thanks,
Signature · 4 lines
Przemyslaw Marczak Samsung R&D Institute Poland Samsung Electronics p.marczak at samsung.com
PATCH v3 9/17 pmic: max77686 set the same compatible as in the kernel
In reply to Przemyslaw MarczakThis 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
@@ -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
@@ -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
@@ -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
@@ -107,7 +107,7 @@ i2c at 12c60000 { pmic at 9 { reg = <0x9>; - compatible = "maxim,max77686_pmic"; + compatible = "maxim,max77686"; }; };
lib/fdtdec.c +1 -1
@@ -55,7 +55,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
PATCH v3 9/17 pmic: max77686 set the same compatible as in the kernel
Quoted 11 lines · Przemyslaw Marczak
This commit also updates the proper dts files.
Signed-off-by Przemyslaw Marczak <[email protected]>--- 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(-)
PATCH v3 10/17 dm: pmic: add max77686 pmic driver
In reply to Przemyslaw MarczakThis is the implementation of driver model uclass pmic driver. The max77686 pmic driver implements read/write operations and driver bind method - to bind other pmic uclass devices as a parent pmic device. This driver provides pmic_platdata for also for child regulator.
This driver will try to bind the regulator device with regulator driver. This should succeed if regulator driver is compiled.
If no regulator driver found, then the pmic can still provide read/write operations, and can be used with pmic framework 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
--- drivers/power/Kconfig | 7 ++++ drivers/power/pmic/Makefile | 1 + drivers/power/pmic/max77686.c | 76 ++++++++++++++++++++++++++++++++++++++ drivers/power/pmic/pmic_max77686.c | 2 +- include/power/max77686_pmic.h | 2 +- 5 files changed, 86 insertions(+), 2 deletions(-) create mode 100644 drivers/power/pmic/max77686.c
drivers/power/Kconfig +7 -0
@@ -66,6 +66,13 @@ config DM_PMIC So the call will looks like below: 'pmic_write(regulator->parent, addr, value, len);' +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/ + config DM_REGULATOR bool "Enable Driver Model for REGULATOR drivers (UCLASS_REGULATOR)" depends on DM
drivers/power/pmic/Makefile +1 -0
@@ -10,6 +10,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 +76 -0
76 lines not on this page · raw message
drivers/power/pmic/pmic_max77686.c +1 -1
@@ -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 +1 -1
@@ -122,7 +122,7 @@ enum {MAX77686_REG_PMIC_BBAT =0x7e ,MAX77686_REG_PMIC_32KHZ , - PMIC_NUM_OF_REGS, + MAX77686_NUM_OF_REGS, };/* I2C device address for pmic max77686 */
Signature · 1 line
1.9.1
PATCH v3 10/17 dm: pmic: add max77686 pmic driver
Hi Przemyslaw,
Quoted 5 lines · Przemyslaw Marczak
This is the implementation of driver model uclass pmic driver. The max77686 pmic driver implements read/write operations and driver bind method - to bind other pmic uclass devices as a parent pmic device. This driver provides
pmic_platdatafor also for child regulator.
Quoted 7 lines
This driver will try to bind the regulator device with regulator driver. This should succeed if regulator driver is compiled.
If no regulator driver found, then the pmic can still provide read/write operations, and can be used with pmic framework function calls.
Signed-off-by Przemyslaw Marczak <[email protected]>
One nit below.
Quoted 25 lines
---
Changes V2:
- add implementation of pmic read/write
- max77686: add new operations
- max77686: header: changePMIC_NUM_OF_REGStoMAX77686_NUM_OF_REGSChanges V3:
-pmic/max77686.c: callpmic_child_node_scan()to bind regulator device
- remove use of pmic platdata
- remove unused endian conversions
-Kconfig: add max77686 pmic entry--- drivers/power/Kconfig | 7 ++++ drivers/power/pmic/Makefile | 1 + drivers/power/pmic/max77686.c | 76 ++++++++++++++++++++++++++++++++++++++ drivers/power/pmic/pmic_max77686.c | 2 +- include/power/max77686_pmic.h | 2 +- 5 files changed, 86 insertions(+), 2 deletions(-) create mode 100644 drivers/power/pmic/max77686.cdrivers/power/Kconfig +0
-0
drivers/power/Kconfig config DM_PMIC · line 74
Quoted 9 lines
drivers/power/Kconfig +6
-0@@ -66,6 +66,13 @@ config DM_PMIC So the call will looks like below: 'pmic_write(regulator->parent, addr, value, len);' +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/
nit: '.' at end?
Regards,
Simon
PATCH v3 11/17 dm: regulator: add max77686 regulator driver
In reply to Przemyslaw MarczakThis commit adds support to max77686 regulator driver based on a uclass regulator driver-model api, which provides implementation of all uclass regulator api function calls.
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
--- Makefile | 1 + drivers/power/Kconfig | 8 + drivers/power/Makefile | 1 - drivers/power/regulator/Makefile | 8 + drivers/power/regulator/max77686.c | 876 +++++++++++++++++++++++++++++++++++++ include/power/max77686_pmic.h | 24 +- 6 files changed, 914 insertions(+), 4 deletions(-) create mode 100644 drivers/power/regulator/Makefile create mode 100644 drivers/power/regulator/max77686.c
Makefile +1 -0
@@ -632,6 +632,7 @@ libs-y += drivers/power/ \ drivers/power/fuel_gauge/ \ drivers/power/mfd/ \ drivers/power/pmic/ \ + drivers/power/regulator/ \ drivers/power/battery/ libs-y += drivers/spi/ libs-$(CONFIG_FMAN_ENET) += drivers/net/fm/
drivers/power/Kconfig +8 -0
@@ -112,6 +112,14 @@ config DM_REGULATOR Say y here to enable support for the axp221 / axp223 pmic found on most sun6i (A31) / sun8i (A23) boards. +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. + config AXP221_DCDC1_VOLT int "axp221 dcdc1 voltage" depends on AXP221_POWER
drivers/power/Makefile +0 -1
@@ -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/Makefile new file +8 -0
@@ -0,0 +1,8 @@ +# +# Copyright (C) 2014 Samsung Electronics +# Przemyslaw Marczak <[email protected]> +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-$(CONFIG_DM_REGULATOR_MAX77686) += max77686.o
drivers/power/regulator/max77686.c new file +876 -0
876 lines not on this page · raw message
include/power/max77686_pmic.h +21 -3
@@ -126,7 +126,10 @@ enum { };/* 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 +#define MAX77686_DESC_NUM (MAX77686_LDO_NUM + MAX77686_BUCK_NUM)enum {REG_DISABLE =0 ,
@@ -143,23 +146,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
@@ -170,6 +179,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 */
Signature · 1 line
1.9.1
PATCH v3 11/17 dm: regulator: add max77686 regulator driver
Hi Przemyslaw,
Quoted 9 lines · Przemyslaw Marczak
This commit adds support to max77686 regulator driver based on a uclass regulator driver-model api, which provides implementation of all uclass regulator api function calls.
New file:
drivers/power/regulator/max77686.c
New config:CONFIG_DM_REGULATOR_MAX77686Signed-off-by Przemyslaw Marczak <[email protected]>
See nit below.
Quoted 42 lines
---
Changes V2:
- changedebug()toerror()
- code cleanup
- fix data types
- ldo/buck state implementation
- adjust to new uclass apiChanges 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--- Makefile | 1 + drivers/power/Kconfig | 8 + drivers/power/Makefile | 1 - drivers/power/regulator/Makefile | 8 + drivers/power/regulator/max77686.c | 876 +++++++++++++++++++++++++++++++++++++ include/power/max77686_pmic.h | 24 +- 6 files changed, 914 insertions(+), 4 deletions(-) create mode 100644 drivers/power/regulator/Makefile create mode 100644 drivers/power/regulator/max77686.cMakefile +1
-0@@ -632,6 +632,7 @@ libs-y += drivers/power/ \ drivers/power/fuel_gauge/ \ drivers/power/mfd/ \ drivers/power/pmic/ \ + drivers/power/regulator/ \ drivers/power/battery/ libs-y += drivers/spi/ libs-$(CONFIG_FMAN_ENET) += drivers/net/fm/drivers/power/Kconfig +0
-0
drivers/power/Kconfig config DM_REGULATOR · line 121
Quoted 10 lines
drivers/power/Kconfig +7
-0@@ -112,6 +112,14 @@ config DM_REGULATOR Say y here to enable support for the axp221 / axp223 pmic found on most sun6i (A31) / sun8i (A23) boards. +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.
This should probably go in drivers/power/regulator/Kconfig.
Quoted 977 lines
drivers/power/Kconfig +1
-0+ config AXP221_DCDC1_VOLT int "axp221 dcdc1 voltage" depends on AXP221_POWERdrivers/power/Makefile +0
-1@@ -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.odrivers/power/regulator/Makefile new file +8
-0@@ -0,0 +1,8 @@ +# +# Copyright (C) 2014 Samsung Electronics +# Przemyslaw Marczak <[email protected]> +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-$(CONFIG_DM_REGULATOR_MAX77686) += max77686.odrivers/power/regulator/max77686.c new file +876
-0@@ -0,0 +1,876 @@ +/* +* Copyright (C) 2012-2015 Samsung Electronics +* +* Rajeshwari Shinde <[email protected]> +* Przemyslaw Marczak <[email protected]> +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#include <common.h> +#include <fdtdec.h> +#include <i2c.h> +#include <dm.h> +#include <power/pmic.h> +#include <power/regulator.h> +#include <power/max77686_pmic.h> +#include <errno.h> +#include <dm.h> + +DECLARE_GLOBAL_DATA_PTR ; + +#define MODE (_id, _val, _name) { \ + .id = _id, \ + .register_value = _val, \ + .name = _name, \ +} + +/* LDO: 1,3,4,5,9,17,18,19,20,21,22,23,24,26,26,27 */ +static struct dm_regulator_mode max77686_ldo_mode_standby1[] = { +MODE (OPMODE_OFF ,MAX77686_LDO_MODE_OFF ,"OFF" ), +MODE (OPMODE_LPM ,MAX77686_LDO_MODE_LPM ,"LPM" ), +MODE (OPMODE_STANDBY_LPM ,MAX77686_LDO_MODE_STANDBY_LPM ,"ON/LPM" ), +MODE (OPMODE_ON ,MAX77686_LDO_MODE_ON ,"ON" ), +}; + +/* LDO: 2,6,7,8,10,11,12,14,15,16 */ +static struct dm_regulator_mode max77686_ldo_mode_standby2[] = { +MODE (OPMODE_OFF ,MAX77686_LDO_MODE_OFF ,"OFF" ), +MODE (OPMODE_STANDBY ,MAX77686_LDO_MODE_STANDBY ,"ON/OFF" ), +MODE (OPMODE_STANDBY_LPM ,MAX77686_LDO_MODE_STANDBY_LPM ,"ON/LPM" ), +MODE (OPMODE_ON ,MAX77686_LDO_MODE_ON ,"ON" ), +}; + +/* Buck: 1 */ +static struct dm_regulator_mode max77686_buck_mode_standby[] = { +MODE (OPMODE_OFF ,MAX77686_BUCK_MODE_OFF ,"OFF" ), +MODE (OPMODE_STANDBY ,MAX77686_BUCK_MODE_STANDBY ,"ON/OFF" ), +MODE (OPMODE_ON ,MAX77686_BUCK_MODE_ON ,"ON" ), +}; + +/* Buck: 2,3,4 */ +static struct dm_regulator_mode max77686_buck_mode_lpm[] = { +MODE (OPMODE_OFF ,MAX77686_BUCK_MODE_OFF ,"OFF" ), +MODE (OPMODE_STANDBY ,MAX77686_BUCK_MODE_STANDBY ,"ON/OFF" ), +MODE (OPMODE_LPM ,MAX77686_BUCK_MODE_LPM ,"LPM" ), +MODE (OPMODE_ON ,MAX77686_BUCK_MODE_ON ,"ON" ), +}; + +/* Buck: 5,6,7,8,9 */ +static struct dm_regulator_mode max77686_buck_mode_onoff[] = { +MODE (OPMODE_OFF ,MAX77686_BUCK_MODE_OFF ,"OFF" ), +MODE (OPMODE_ON ,MAX77686_BUCK_MODE_ON ,"ON" ), +}; + +static const char max77686_buck_addr[] = { +0xff ,0x10 ,0x12 ,0x1c ,0x26 ,0x30 ,0x32 ,0x34 ,0x36 ,0x38 +}; + +static int max77686_buck_volt2hex (int buck,int uV) +{ +unsigned int hex =0 ; +unsigned int hex_max =0 ; + +switch (buck) { +case 2 : +case 3 : +case 4 : +/* hex = (uV - 600000) / 12500; */ + hex = (uV -MAX77686_BUCK_UV_LMIN ) /MAX77686_BUCK_UV_LSTEP ; + hex_max =MAX77686_BUCK234_VOLT_MAX_HEX ; +/** +* This uses voltage scaller - temporary not implemented +* so return just 0 +*/ +return 0 ; +default : +/* hex = (uV - 750000) / 50000; */ + hex = (uV -MAX77686_BUCK_UV_HMIN ) /MAX77686_BUCK_UV_HSTEP ; + hex_max =MAX77686_BUCK_VOLT_MAX_HEX ; +break ; + } + +if (hex >=0 && hex <= hex_max) +return hex; + +error ("Value: %d uV is wrong for BUCK%d" , uV, buck); +return -EINVAL ; +} + +static int max77686_buck_hex2volt (int buck,int hex) +{ +unsigned uV =0 ; +unsigned int hex_max =0 ; + +if (hex <0 ) + goto bad_hex; + +switch (buck) { +case 2 : +case 3 : +case 4 : + hex_max =MAX77686_BUCK234_VOLT_MAX_HEX ; +if (hex > hex_max) + goto bad_hex; + +/* uV = hex * 12500 + 600000; */ + uV = hex *MAX77686_BUCK_UV_LSTEP +MAX77686_BUCK_UV_LMIN ; +break ; +default : + hex_max =MAX77686_BUCK_VOLT_MAX_HEX ; +if (hex > hex_max) + goto bad_hex; + +/* uV = hex * 50000 + 750000; */ + uV = hex *MAX77686_BUCK_UV_HSTEP +MAX77686_BUCK_UV_HMIN ; +break ; + } + +return uV; + +bad_hex: +error ("Value: %#x is wrong for BUCK%d" , hex, buck); +return -EINVAL ; +} + +static int max77686_ldo_volt2hex (int ldo,int uV) +{ +unsigned int hex =0 ; + +switch (ldo) { +case 1 : +case 2 : +case 6 : +case 7 : +case 8 : +case 15 : + hex = (uV -MAX77686_LDO_UV_MIN ) /MAX77686_LDO_UV_LSTEP ; +/* hex = (uV - 800000) / 25000; */ +break ; +default : + hex = (uV -MAX77686_LDO_UV_MIN ) /MAX77686_LDO_UV_HSTEP ; +/* hex = (uV - 800000) / 50000; */ + } + +if (hex >=0 && hex <=MAX77686_LDO_VOLT_MAX_HEX ) +return hex; + +error ("Value: %d uV is wrong for LDO%d" , uV, ldo); +return -EINVAL ; +} + +static int max77686_ldo_hex2volt (int ldo,int hex) +{ +unsigned int uV =0 ; + +if (hex >MAX77686_LDO_VOLT_MAX_HEX ) + goto bad_hex; + +switch (ldo) { +case 1 : +case 2 : +case 6 : +case 7 : +case 8 : +case 15 : +/* uV = hex * 25000 + 800000; */ + uV = hex *MAX77686_LDO_UV_LSTEP +MAX77686_LDO_UV_MIN ; +break ; +default : +/* uV = hex * 50000 + 800000; */ + uV = hex *MAX77686_LDO_UV_HSTEP +MAX77686_LDO_UV_MIN ; + } + +return uV; + +bad_hex: +error ("Value: %#x is wrong for ldo%d" , hex, ldo); +return -EINVAL ; +} + +static int max77686_ldo_hex2mode (int ldo,int hex) +{ +if (hex >MAX77686_LDO_MODE_MASK ) +return -EINVAL ; + +switch (hex) { +case MAX77686_LDO_MODE_OFF : +return OPMODE_OFF ; +case MAX77686_LDO_MODE_LPM :/* == MAX77686_LDO_MODE_STANDBY: */ +/* The same mode values but different meaning for each ldo */ +switch (ldo) { +case 2 : +case 6 : +case 7 : +case 8 : +case 10 : +case 11 : +case 12 : +case 14 : +case 15 : +case 16 : +return OPMODE_STANDBY ; +default : +return OPMODE_LPM ; + } +case MAX77686_LDO_MODE_STANDBY_LPM : +return OPMODE_STANDBY_LPM ; +case MAX77686_LDO_MODE_ON : +return OPMODE_ON ; +default : +return -EINVAL ; + } +} + +static int max77686_buck_hex2mode (int buck,int hex) +{ +if (hex >MAX77686_BUCK_MODE_MASK ) +return -EINVAL ; + +switch (hex) { +case MAX77686_BUCK_MODE_OFF : +return OPMODE_OFF ; +case MAX77686_BUCK_MODE_ON : +return OPMODE_ON ; +case MAX77686_BUCK_MODE_STANDBY : +switch (buck) { +case 1 : +case 2 : +case 3 : +case 4 : +return OPMODE_STANDBY ; +default : +return -EINVAL ; + } +case MAX77686_BUCK_MODE_LPM : +switch (buck) { +case 2 : +case 3 : +case 4 : +return OPMODE_LPM ; +default : +return -EINVAL ; + } +default : +return -EINVAL ; + } +} + +static int max77686_buck_modes (int buck,struct dm_regulator_mode **modesp) +{ +int ret = -EINVAL ; + +if (buck <1 || buck >MAX77686_BUCK_NUM ) +return ret; + +switch (buck) { +case 1 : + *modesp = max77686_buck_mode_standby; + ret =ARRAY_SIZE (max77686_buck_mode_standby); +case 2 : +case 3 : +case 4 : + *modesp = max77686_buck_mode_lpm; + ret =ARRAY_SIZE (max77686_buck_mode_lpm); +default : + *modesp = max77686_buck_mode_onoff; + ret =ARRAY_SIZE (max77686_buck_mode_onoff); + } + +return ret; +} + +static int max77686_ldo_modes (int ldo,struct dm_regulator_mode **modesp) +{ +int ret = -EINVAL ; + +if (ldo <1 || ldo >MAX77686_LDO_NUM ) +return ret; + +switch (ldo) { +case 2 : +case 6 : +case 7 : +case 8 : +case 10 : +case 11 : +case 12 : +case 14 : +case 15 : +case 16 : + *modesp = max77686_ldo_mode_standby2; + ret =ARRAY_SIZE (max77686_ldo_mode_standby2); +default : + *modesp = max77686_ldo_mode_standby1; + ret =ARRAY_SIZE (max77686_ldo_mode_standby1); + } + +return ret; +} + +static int dev2num (struct udevice *dev) +{ +return dev->of_id->data; +} + +static int max77686_ldo_val (struct udevice *dev,int op,int *uV) +{ +unsigned int ret, hex, adr; +unsigned char val; +int ldo; + +if (op ==PMIC_OP_GET ) + *uV =0 ; + + ldo =dev2num (dev); +if (ldo <1 || ldo >MAX77686_LDO_NUM ) { +error ("Wrong ldo number: %d" , ldo); +return -EINVAL ; + } + + adr =MAX77686_REG_PMIC_LDO1CTRL1 + ldo -1 ; + + ret =pmic_read (dev->parent, adr, &val,1 ); +if (ret) +return ret; + +if (op ==PMIC_OP_GET ) { + val &=MAX77686_LDO_VOLT_MASK ; + ret =max77686_ldo_hex2volt (ldo, val); +if (ret <0 ) +return ret; + *uV = ret; +return 0 ; + } + + hex =max77686_ldo_volt2hex (ldo, *uV); +if (hex <0 ) +return -EINVAL ; + + val &= ~MAX77686_LDO_VOLT_MASK ; + val |= hex; + ret =pmic_write (dev->parent, adr, &val,1 ); + +return ret; +} + +static int max77686_buck_val (struct udevice *dev,int op,int *uV) +{ +unsigned int hex, ret, mask, adr; +unsigned char val; +int buck; + + buck =dev2num (dev); +if (buck <1 || buck >MAX77686_BUCK_NUM ) { +error ("Wrong buck number: %d" , buck); +return -EINVAL ; + } + +if (op ==PMIC_OP_GET ) + *uV =0 ; + +/* &buck_out = ctrl + 1 */ + adr = max77686_buck_addr[buck] +1 ; + +/* mask */ +switch (buck) { +case 2 : +case 3 : +case 4 : +/* Those uses voltage scallers - will support in the future */ + mask =MAX77686_BUCK234_VOLT_MASK ; +return -EPERM ; +default : + mask =MAX77686_BUCK_VOLT_MASK ; + } + + ret =pmic_read (dev->parent, adr, &val,1 ); +if (ret) +return ret; + +if (op ==PMIC_OP_GET ) { + val &= mask; + ret =max77686_buck_hex2volt (buck, val); +if (ret <0 ) +return ret; + *uV = ret; +return 0 ; + } + + hex =max77686_buck_volt2hex (buck, *uV); +if (hex <0 ) +return -EINVAL ; + + val &= ~mask; + val |= hex; + ret =pmic_write (dev->parent, adr, &val,1 ); + +return ret; +} + +static int max77686_ldo_mode (struct udevice *dev,int op,int *opmode) +{ +unsigned int ret, adr, mode; +unsigned char val; +int ldo; + +if (op ==PMIC_OP_GET ) + *opmode = -EINVAL ; + + ldo =dev2num (dev); +if (ldo <1 || ldo >MAX77686_LDO_NUM ) { +error ("Wrong ldo number: %d" , ldo); +return -EINVAL ; + } + + adr =MAX77686_REG_PMIC_LDO1CTRL1 + ldo -1 ; + + ret =pmic_read (dev->parent, adr, &val,1 ); +if (ret) +return ret; + +if (op ==PMIC_OP_GET ) { + val &=MAX77686_LDO_MODE_MASK ; + ret =max77686_ldo_hex2mode (ldo, val); +if (ret <0 ) +return ret; + *opmode = ret; +return 0 ; + } + +/* mode */ +switch (*opmode) { +case OPMODE_OFF : + mode =MAX77686_LDO_MODE_OFF ; +break ; +case OPMODE_LPM : +switch (ldo) { +case 2 : +case 6 : +case 7 : +case 8 : +case 10 : +case 11 : +case 12 : +case 14 : +case 15 : +case 16 : +return -EINVAL ; +default : + mode =MAX77686_LDO_MODE_LPM ; + } +break ; +case OPMODE_STANDBY : +switch (ldo) { +case 2 : +case 6 : +case 7 : +case 8 : +case 10 : +case 11 : +case 12 : +case 14 : +case 15 : +case 16 : + mode =MAX77686_LDO_MODE_STANDBY ; +break ; +default : +return -EINVAL ; + } +break ; +case OPMODE_STANDBY_LPM : + mode =MAX77686_LDO_MODE_STANDBY_LPM ; +break ; +case OPMODE_ON : + mode =MAX77686_LDO_MODE_ON ; +break ; +default : + mode =0xff ; + } + +if (mode ==0xff ) { +error ("Wrong mode: %d for ldo%d" , *opmode, ldo); +return -EINVAL ; + } + + val &= ~MAX77686_LDO_MODE_MASK ; + val |= mode; + ret =pmic_write (dev->parent, adr, &val,1 ); + +return ret; +} + +static int max77686_ldo_enable (struct udevice *dev,int op,bool *enable) +{ +int ret, on_off; + +if (op ==PMIC_OP_GET ) { + ret =max77686_ldo_mode (dev, op, &on_off); +if (ret) +return ret; + +switch (on_off) { +case OPMODE_OFF : + *enable =0 ; +break ; +case OPMODE_ON : + *enable =1 ; +break ; +default : +return -EINVAL ; + } + }else if (op ==PMIC_OP_SET ) { +switch (*enable) { +case 0 : + on_off =OPMODE_OFF ; +break ; +case 1 : + on_off =OPMODE_ON ; +break ; +default : +return -EINVAL ; + } + + ret =max77686_ldo_mode (dev, op, &on_off); +if (ret) +return ret; + } + +return 0 ; +} + +static int max77686_buck_mode (struct udevice *dev,int op,int *opmode) +{ +unsigned int ret, mask, adr, mode, mode_shift; +unsigned char val; +int buck; + + buck =dev2num (dev); +if (buck <1 || buck >MAX77686_BUCK_NUM ) { +error ("Wrong buck number: %d" , buck); +return -EINVAL ; + } + + adr = max77686_buck_addr[buck]; + +/* mask */ +switch (buck) { +case 2 : +case 3 : +case 4 : + mode_shift =MAX77686_BUCK_MODE_SHIFT_2 ; +break ; +default : + mode_shift =MAX77686_BUCK_MODE_SHIFT_1 ; + } + + mask =MAX77686_BUCK_MODE_MASK << mode_shift; + + ret =pmic_read (dev->parent, adr, &val,1 ); +if (ret) +return ret; + +if (op ==PMIC_OP_GET ) { + val &= mask; + val >>= mode_shift; + ret =max77686_buck_hex2mode (buck, val); +if (ret <0 ) +return ret; + *opmode = ret; +return 0 ; + } + +/* mode */ +switch (*opmode) { +case OPMODE_OFF : + mode =MAX77686_BUCK_MODE_OFF ; +break ; +case OPMODE_STANDBY : +switch (buck) { +case 1 : +case 2 : +case 3 : +case 4 : + mode =MAX77686_BUCK_MODE_STANDBY << mode_shift; +break ; +default : + mode =0xff ; + } +break ; +case OPMODE_LPM : +switch (buck) { +case 2 : +case 3 : +case 4 : + mode =MAX77686_BUCK_MODE_LPM << mode_shift; +break ; +default : + mode =0xff ; + } +break ; +case OPMODE_ON : + mode =MAX77686_BUCK_MODE_ON << mode_shift; +break ; +default : + mode =0xff ; + } + +if (mode ==0xff ) { +error ("Wrong mode: %d for buck: %d\n" , *opmode, buck); +return -EINVAL ; + } + + val &= ~mask; + val |= mode; + ret =pmic_write (dev->parent, adr, &val,1 ); + +return ret; +} + +static int max77686_buck_enable (struct udevice *dev,int op,bool *enable) +{ +int ret, on_off; + +if (op ==PMIC_OP_GET ) { + ret =max77686_buck_mode (dev, op, &on_off); +if (ret) +return ret; + +switch (on_off) { +case OPMODE_OFF : + *enable = false; +break ; +case OPMODE_ON : + *enable = true; +break ; +default : +return -EINVAL ; + } + }else if (op ==PMIC_OP_SET ) { +switch (*enable) { +case 0 : + on_off =OPMODE_OFF ; +break ; +case 1 : + on_off =OPMODE_ON ; +break ; +default : +return -EINVAL ; + } + + ret =max77686_buck_mode (dev, op, &on_off); +if (ret) +return ret; + } + +return 0 ; +} + +static int max77686_ldo_ofdata_to_platdata (struct udevice *dev) +{ +struct dm_regulator_info *info = dev->uclass_priv; +int ret; + + ret =regulator_ofdata_to_platdata (dev); +if (ret) +return ret; + + info->type =REGULATOR_TYPE_LDO ; + info->mode_count =max77686_ldo_modes (dev2num (dev), &info->mode); + +return 0 ; +} + +static int ldo_get_value (struct udevice *dev) +{ +int uV; +int ret; + + ret =max77686_ldo_val (dev,PMIC_OP_GET , &uV); +if (ret) +return ret; + +return uV; +} + +static int ldo_set_value (struct udevice *dev,int uV) +{ +return max77686_ldo_val (dev,PMIC_OP_SET , &uV); +} + +static bool ldo_get_enable (struct udevice *dev) +{ +bool enable = false; +int ret; + + ret =max77686_ldo_enable (dev,PMIC_OP_GET , &enable); +if (ret) +return ret; + +return enable; +} + +static int ldo_set_enable (struct udevice *dev,bool enable) +{ +return max77686_ldo_enable (dev,PMIC_OP_SET , &enable); +} + +static int ldo_get_mode (struct udevice *dev) +{ +int mode; +int ret; + + ret =max77686_ldo_mode (dev,PMIC_OP_GET , &mode); +if (ret) +return ret; + +return mode; +} + +static int ldo_set_mode (struct udevice *dev,int mode) +{ +return max77686_ldo_mode (dev,PMIC_OP_SET , &mode); +} + +static int max77686_buck_ofdata_to_platdata (struct udevice *dev) +{ +struct dm_regulator_info *info = dev->uclass_priv; +int ret; + + ret =regulator_ofdata_to_platdata (dev); +if (ret) +return ret; + + info->type =REGULATOR_TYPE_BUCK ; + info->mode_count =max77686_buck_modes (dev2num (dev), &info->mode); + +return 0 ; +} + +static int buck_get_value (struct udevice *dev) +{ +int uV; +int ret; + + ret =max77686_buck_val (dev,PMIC_OP_GET , &uV); +if (ret) +return ret; + +return uV; +} + +static int buck_set_value (struct udevice *dev,int uV) +{ +return max77686_buck_val (dev,PMIC_OP_SET , &uV); +} + +static bool buck_get_enable (struct udevice *dev) +{ +bool enable = false; +int ret; + + ret =max77686_buck_enable (dev,PMIC_OP_GET , &enable); +if (ret) +return ret; + +return enable; +} + +static int buck_set_enable (struct udevice *dev,bool enable) +{ +return max77686_buck_enable (dev,PMIC_OP_SET , &enable); +} + +static int buck_get_mode (struct udevice *dev) +{ +int mode; +int ret; + + ret =max77686_buck_mode (dev,PMIC_OP_GET , &mode); +if (ret) +return ret; + +return mode; +} + +static int buck_set_mode (struct udevice *dev,int mode) +{ +return max77686_buck_mode (dev,PMIC_OP_SET , &mode); +} + +static const struct dm_regulator_ops max77686_ldo_ops = { + .get_value = ldo_get_value, + .set_value = ldo_set_value, + .get_enable = ldo_get_enable, + .set_enable = ldo_set_enable, + .get_mode = ldo_get_mode, + .set_mode = ldo_set_mode, +}; + +static const struct udevice_id max77686_ldo_ids[] = { + { .compatible ="LDO1" , .data =1 }, + { .compatible ="LDO2" , .data =2 }, + { .compatible ="LDO3" , .data =3 }, + { .compatible ="LDO4" , .data =4 }, + { .compatible ="LDO5" , .data =5 }, + { .compatible ="LDO6" , .data =6 }, + { .compatible ="LDO7" , .data =7 }, + { .compatible ="LDO8" , .data =8 }, + { .compatible ="LDO9" , .data =9 }, + { .compatible ="LDO10" , .data =10 }, + { .compatible ="LDO11" , .data =11 }, + { .compatible ="LDO12" , .data =12 }, + { .compatible ="LDO13" , .data =13 }, + { .compatible ="LDO14" , .data =14 }, + { .compatible ="LDO15" , .data =15 }, + { .compatible ="LDO16" , .data =16 }, + { .compatible ="LDO17" , .data =17 }, + { .compatible ="LDO18" , .data =18 }, + { .compatible ="LDO19" , .data =19 }, + { .compatible ="LDO20" , .data =20 }, + { .compatible ="LDO21" , .data =21 }, + { .compatible ="LDO22" , .data =22 }, + { .compatible ="LDO23" , .data =23 }, + { .compatible ="LDO24" , .data =24 }, + { .compatible ="LDO25" , .data =25 }, + { .compatible ="LDO26" , .data =26 }, + { }, +}; + +U_BOOT_DRIVER (max77686_ldo) = { + .name ="max77686 ldo" , + .id =UCLASS_REGULATOR , + .ops = &max77686_ldo_ops, + .of_match = max77686_ldo_ids, + .ofdata_to_platdata = max77686_ldo_ofdata_to_platdata, +}; + +static const struct dm_regulator_ops max77686_buck_ops = { + .get_value = buck_get_value, + .set_value = buck_set_value, + .get_enable = buck_get_enable, + .set_enable = buck_set_enable, + .get_mode = buck_get_mode, + .set_mode = buck_set_mode, +}; + +static const struct udevice_id max77686_buck_ids[] = { + { .compatible ="BUCK1" , .data =1 }, + { .compatible ="BUCK2" , .data =2 }, + { .compatible ="BUCK3" , .data =3 }, + { .compatible ="BUCK4" , .data =4 }, + { .compatible ="BUCK5" , .data =5 }, + { .compatible ="BUCK6" , .data =6 }, + { .compatible ="BUCK7" , .data =7 }, + { .compatible ="BUCK8" , .data =8 }, + { .compatible ="BUCK9" , .data =9 }, + { }, +}; + +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, +};include/power/max77686_pmic.h +21
-4@@ -126,7 +126,10 @@ enum { };/* 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 +#define MAX77686_DESC_NUM (MAX77686_LDO_NUM + MAX77686_BUCK_NUM)enum {REG_DISABLE =0 ,@@ -143,23 +146,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@@ -170,6 +179,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 */ --
Quoted 2 lines
1.9.1
Regards,
Simon
PATCH v3 11/17 dm: regulator: add max77686 regulator driver
Hello Simon,
Quoted 62 lines · Simon Glass
Hi Przemyslaw,
Quoted 9 lines · Przemyslaw Marczak
This commit adds support to max77686 regulator driver based on a uclass regulator driver-model api, which provides implementation of all uclass regulator api function calls.
New file:
drivers/power/regulator/max77686.c
New config:CONFIG_DM_REGULATOR_MAX77686Signed-off-by Przemyslaw Marczak <[email protected]>Acked-by Simon Glass <[email protected]>See nit below.
Quoted 45 lines
---
Changes V2:
- changedebug()toerror()
- code cleanup
- fix data types
- ldo/buck state implementation
- adjust to new uclass apiChanges 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--- Makefile | 1 + drivers/power/Kconfig | 8 + drivers/power/Makefile | 1 - drivers/power/regulator/Makefile | 8 + drivers/power/regulator/max77686.c | 876 +++++++++++++++++++++++++++++++++++++ include/power/max77686_pmic.h | 24 +- 6 files changed, 914 insertions(+), 4 deletions(-)create mode 100644
drivers/power/regulator/Makefilecreate mode 100644drivers/power/regulator/max77686.cMakefile +1
-0@@ -632,6 +632,7 @@ libs-y += drivers/power/ \ drivers/power/fuel_gauge/ \ drivers/power/mfd/ \ drivers/power/pmic/ \ + drivers/power/regulator/ \ drivers/power/battery/ libs-y += drivers/spi/ libs-$(CONFIG_FMAN_ENET) += drivers/net/fm/drivers/power/Kconfig +0
-0@@ -112,6 +112,14 @@ config DM_REGULATOR Say y here to enable support for the axp221 / axp223 pmic found on most sun6i (A31) / sun8i (A23) boards.
Quoted 10 lines
drivers/power/Kconfig config DM_REGULATOR · line 121
Quoted 7 lines
drivers/power/Kconfig +7
-0+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.This should probably go in
drivers/power/regulator/Kconfig.
Ok, will fix this.
[snip]
Quoted 4 lines
Regards,
Simon
Thanks,
Signature · 4 lines
Przemyslaw Marczak Samsung R&D Institute Poland Samsung Electronics p.marczak at samsung.com
PATCH v3 12/17 dm: regulator: add fixed voltage regulator driver
In reply to Przemyslaw MarczakThis driver implements regulator uclass features for fixed value regulators. For getting the basic regulator device-tree node constraints, this driver calls function 'regulator_ofdata_to_platdata()'. The typical fixed regulator node provides few additional properties:
- gpio
- gpio-open-drain
- enable-active-high
- startup-delay-us
All above are checked and keept in structure of type 'fixed_regulator_priv', which is private for each fixed-regulator device (dev->priv).
The driver implements only three of regulator uclass features:
- get_value
- get_enable
- set_enable
The regulator calls and command line features can be used for fixed-regulator, and the proper error will be returned for prohibited.
Changes v3:
- new file
- Kconfig add fixed-regulator entry
--- drivers/power/Kconfig | 8 +++ drivers/power/regulator/Makefile | 1 + drivers/power/regulator/fixed.c | 124 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 133 insertions(+) create mode 100644 drivers/power/regulator/fixed.c
drivers/power/Kconfig +8 -0
@@ -120,6 +120,14 @@ config DM_REGULATOR_MAX77686 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. + config AXP221_DCDC1_VOLT int "axp221 dcdc1 voltage" depends on AXP221_POWER
drivers/power/regulator/Makefile +1 -0
@@ -5,4 +5,5 @@ # SPDX-License-Identifier: GPL-2.0+ # +obj-$(CONFIG_DM_REGULATOR_FIXED) += fixed.o obj-$(CONFIG_DM_REGULATOR_MAX77686) += max77686.o
drivers/power/regulator/fixed.c new file +124 -0
124 lines not on this page · raw message
Signature · 1 line
1.9.1
PATCH v3 12/17 dm: regulator: add fixed voltage regulator driver
Hi Przemyslaw,
Quoted 37 lines · Przemyslaw Marczak
This driver implements regulator uclass features for fixed value regulators. For getting the basic regulator device-tree node constraints, this driver calls function '
regulator_ofdata_to_platdata()'. The typical fixed regulator node provides few additional properties:
- gpio
- gpio-open-drain
- enable-active-high
- startup-delay-us
All above are checked and keept in structure of type 'fixed_regulator_priv', which is private for each fixed-regulator device (dev->priv).The driver implements only three of regulator uclass features:
-get_value
-get_enable
-set_enableThe regulator calls and command line features can be used for fixed-regulator, and the proper error will be returned for prohibited.
Signed-off-by Przemyslaw Marczak <[email protected]>Changes v3:
- new file
-Kconfigadd fixed-regulator entry--- drivers/power/Kconfig | 8 +++ drivers/power/regulator/Makefile | 1 + drivers/power/regulator/fixed.c | 124 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 133 insertions(+) create mode 100644 drivers/power/regulator/fixed.cdrivers/power/Kconfig +0
-0@@ -120,6 +120,14 @@ config DM_REGULATOR_MAX77686 features for REGULATOR MAX77686. The driver implements get/set api for:
drivers/power/Kconfig config DM_REGULATOR_MAX77686 · line 130
Quoted 10 lines
drivers/power/Kconfig +8
-0value, 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. +
Should be in drivers/regulator/Kconfig I think
Quoted 34 lines
drivers/power/Kconfig +0
-0config AXP221_DCDC1_VOLT int "axp221 dcdc1 voltage" depends on AXP221_POWERdrivers/power/regulator/Makefile +1
-0@@ -5,4 +5,5 @@ # SPDX-License-Identifier: GPL-2.0+ # +obj-$(CONFIG_DM_REGULATOR_FIXED) += fixed.o obj-$(CONFIG_DM_REGULATOR_MAX77686) += max77686.odrivers/power/regulator/fixed.c new file +15
-0@@ -0,0 +1,124 @@ +/* +* Copyright (C) 2015 Samsung Electronics +* +* Przemyslaw Marczak <[email protected]> +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#include <common.h> +#include <fdtdec.h> +#include <i2c.h> +#include <dm.h> +#include <asm/gpio.h> +#include <power/pmic.h> +#include <power/regulator.h>
drivers/power/regulator/fixed.c line 25
Quoted 10 lines
drivers/power/regulator/fixed.c new file +10
-0+#include <errno.h> +#include <dm.h> + +DECLARE_GLOBAL_DATA_PTR ; + +struct fixed_regulator_priv { +struct gpio_desc gpio; +bool gpio_open_drain; +bool enable_active_high; +unsigned startup_delay_us;
Docs for these?
Quoted 8 lines
drivers/power/regulator/fixed.c new file +8
-0+}; + +static int fixed_regulator_ofdata_to_platdata (struct udevice *dev) +{ +struct dm_regulator_info *info = dev->uclass_priv; +struct fixed_regulator_priv *priv = dev->priv; +int ret, offset = dev->of_offset; +
drivers/power/regulator/fixed.c line 43
Quoted 10 lines
drivers/power/regulator/fixed.c new file +10
-0+/* Get the basic regulator constraints */ + ret =regulator_ofdata_to_platdata (dev); +if (ret) { +error ("Can't get regulator constraints for %s" , dev->name); +return ret; + } + +/* Get fixed regulator gpio desc */ + ret =gpio_request_by_name_nodev (gd->fdt_blob, offset,"gpio" ,0 , + &priv->gpio,GPIOD_IS_OUT );
Should not use the nodev version - you have a device.
Quoted 34 lines
drivers/power/regulator/fixed.c new file +34
-0+if (ret) { +error ("Fixed regulator gpio - not found! Error: %d" , ret); +return ret; + } + +/* Get fixed regulator addidional constraints */ + priv->gpio_open_drain =fdtdec_get_bool (gd->fdt_blob, offset, +"gpio-open-drain" ); + priv->enable_active_high =fdtdec_get_bool (gd->fdt_blob, offset, +"enable-active-high" ); + priv->startup_delay_us =fdtdec_get_int (gd->fdt_blob, offset, +"startup-delay-us" ,0 ); + +/* Set type to fixed - used by regulator command */ + info->type =REGULATOR_TYPE_FIXED ; + +debug ("%s:%d\n" , __func__, __LINE__); +debug (" name:%s, boot_on:%d, active_hi: %d start_delay:%u\n" , + info->name, info->boot_on, priv->enable_active_high, + priv->startup_delay_us); + +return 0 ; +} + +static int fixed_regulator_get_value (struct udevice *dev) +{ +struct dm_regulator_info *info; +int ret; + + ret =regulator_info (dev, &info); +if (ret) +return ret; + +if (info->min_uV == info->max_uV)
drivers/power/regulator/fixed.c line 87
Quoted 10 lines
drivers/power/regulator/fixed.c new file +10
-0+return info->min_uV; + +error ("Invalid constraints for: %s\n" , info->name); + +return -EINVAL ; +} + +static bool fixed_regulator_get_enable (struct udevice *dev) +{ +struct fixed_regulator_priv *priv = dev->priv;
get_get_priv(dev)
Please use that everywhere.
Quoted 38 lines
drivers/power/regulator/fixed.c new file +37
-1+ +return dm_gpio_get_value (&priv->gpio); +} + +static int fixed_regulator_set_enable (struct udevice *dev,bool enable) +{ +struct fixed_regulator_priv *priv = dev->priv; +int ret; + + ret =dm_gpio_set_value (&priv->gpio, enable); +if (ret) { +error ("Can't set regulator : %s gpio to: %d\n" , dev->name, + enable); +return ret; + } +return 0 ; +} + +static const struct dm_regulator_ops fixed_regulator_ops = { + .get_value = fixed_regulator_get_value, + .get_enable = fixed_regulator_get_enable, + .set_enable = fixed_regulator_set_enable, +}; + +static const struct udevice_id fixed_regulator_ids[] = { + { .compatible ="regulator-fixed" }, + { }, +}; + +U_BOOT_DRIVER (fixed_regulator) = { + .name ="fixed regulator" , + .id =UCLASS_REGULATOR , + .ops = &fixed_regulator_ops, + .of_match = fixed_regulator_ids, + .ofdata_to_platdata = fixed_regulator_ofdata_to_platdata, + .priv_auto_alloc_size =sizeof (struct fixed_regulator_priv ), +}; --
Quoted 2 lines
1.9.1
Regards,
Simon
PATCH v3 12/17 dm: regulator: add fixed voltage regulator driver
Hello Simon,
Quoted 42 lines · Simon Glass
Hi Przemyslaw,
Quoted 39 lines · Przemyslaw Marczak
This driver implements regulator uclass features for fixed value regulators. For getting the basic regulator device-tree node constraints, this driver calls function '
regulator_ofdata_to_platdata()'. The typical fixed regulator node provides few additional properties:
- gpio
- gpio-open-drain
- enable-active-high
- startup-delay-us
All above are checked and keept in structure of type 'fixed_regulator_priv', which is private for each fixed-regulator device (dev->priv).The driver implements only three of regulator uclass features:
-get_value
-get_enable
-set_enableThe regulator calls and command line features can be used for fixed-regulator, and the proper error will be returned for prohibited.
Signed-off-by Przemyslaw Marczak <[email protected]>Changes v3:
- new file
-Kconfigadd fixed-regulator entry--- drivers/power/Kconfig | 8 +++ drivers/power/regulator/Makefile | 1 + drivers/power/regulator/fixed.c | 124 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 133 insertions(+)create mode 100644
drivers/power/regulator/fixed.cdrivers/power/Kconfig +0
-0@@ -120,6 +120,14 @@ config DM_REGULATOR_MAX77686 features for REGULATOR MAX77686. The driver implements get/set api for: value, enable and mode.
Quoted 11 lines
drivers/power/Kconfig config DM_REGULATOR_MAX77686 · line 130
Quoted 8 lines
drivers/power/Kconfig +8
-0+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. +Should be in
drivers/regulator/KconfigI think
Right, will fix.
Quoted 38 lines
Quoted 38 lines
drivers/power/Kconfig +0
-0config AXP221_DCDC1_VOLT int "axp221 dcdc1 voltage" depends on AXP221_POWERdrivers/power/regulator/Makefile +1
-0@@ -5,4 +5,5 @@ # SPDX-License-Identifier: GPL-2.0+ # +obj-$(CONFIG_DM_REGULATOR_FIXED) += fixed.o obj-$(CONFIG_DM_REGULATOR_MAX77686) += max77686.odrivers/power/regulator/fixed.c new file +19
-0@@ -0,0 +1,124 @@ +/* +* Copyright (C) 2015 Samsung Electronics +* +* Przemyslaw Marczak <[email protected]> +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#include <common.h> +#include <fdtdec.h> +#include <i2c.h> +#include <dm.h> +#include <asm/gpio.h> +#include <power/pmic.h> +#include <power/regulator.h> +#include <errno.h> +#include <dm.h> + +DECLARE_GLOBAL_DATA_PTR ;
Quoted 9 lines
drivers/power/regulator/fixed.c line 25
Quoted 6 lines
drivers/power/regulator/fixed.c new file +6
-0+ +struct fixed_regulator_priv { +struct gpio_desc gpio; +bool gpio_open_drain; +bool enable_active_high; +unsigned startup_delay_us;Docs for these?
Right, will add.
Quoted 12 lines
Quoted 12 lines
drivers/power/regulator/fixed.c new file +12
-0+}; + +static int fixed_regulator_ofdata_to_platdata (struct udevice *dev) +{ +struct dm_regulator_info *info = dev->uclass_priv; +struct fixed_regulator_priv *priv = dev->priv; +int ret, offset = dev->of_offset; + +/* Get the basic regulator constraints */ + ret =regulator_ofdata_to_platdata (dev); +if (ret) { +error ("Can't get regulator constraints for %s" , dev->name);
Quoted 9 lines
drivers/power/regulator/fixed.c line 43
Quoted 6 lines
drivers/power/regulator/fixed.c new file +6
-0+return ret; + } + +/* Get fixed regulator gpio desc */ + ret =gpio_request_by_name_nodev (gd->fdt_blob, offset,"gpio" ,0 , + &priv->gpio,GPIOD_IS_OUT );Should not use the nodev version - you have a device.
Yes, will update this.
Quoted 47 lines
Quoted 34 lines
drivers/power/regulator/fixed.c new file +34
-0+if (ret) { +error ("Fixed regulator gpio - not found! Error: %d" , ret); +return ret; + } + +/* Get fixed regulator addidional constraints */ + priv->gpio_open_drain =fdtdec_get_bool (gd->fdt_blob, offset, +"gpio-open-drain" ); + priv->enable_active_high =fdtdec_get_bool (gd->fdt_blob, offset, +"enable-active-high" ); + priv->startup_delay_us =fdtdec_get_int (gd->fdt_blob, offset, +"startup-delay-us" ,0 ); + +/* Set type to fixed - used by regulator command */ + info->type =REGULATOR_TYPE_FIXED ; + +debug ("%s:%d\n" , __func__, __LINE__); +debug (" name:%s, boot_on:%d, active_hi: %d start_delay:%u\n" , + info->name, info->boot_on, priv->enable_active_high, + priv->startup_delay_us); + +return 0 ; +} + +static int fixed_regulator_get_value (struct udevice *dev) +{ +struct dm_regulator_info *info; +int ret; + + ret =regulator_info (dev, &info); +if (ret) +return ret; + +if (info->min_uV == info->max_uV)drivers/power/regulator/fixed.c line 87
Quoted 10 lines
drivers/power/regulator/fixed.c new file +10
-0+return info->min_uV; + +error ("Invalid constraints for: %s\n" , info->name); + +return -EINVAL ; +} + +static bool fixed_regulator_get_enable (struct udevice *dev) +{ +struct fixed_regulator_priv *priv = dev->priv;
get_get_priv(dev)
Quoted 2 lines
Please use that everywhere.
Ok, will fix this.
Quoted 35 lines
Quoted 35 lines
drivers/power/regulator/fixed.c new file +35
-0+ +return dm_gpio_get_value (&priv->gpio); +} + +static int fixed_regulator_set_enable (struct udevice *dev,bool enable) +{ +struct fixed_regulator_priv *priv = dev->priv; +int ret; + + ret =dm_gpio_set_value (&priv->gpio, enable); +if (ret) { +error ("Can't set regulator : %s gpio to: %d\n" , dev->name, + enable); +return ret; + } +return 0 ; +} + +static const struct dm_regulator_ops fixed_regulator_ops = { + .get_value = fixed_regulator_get_value, + .get_enable = fixed_regulator_get_enable, + .set_enable = fixed_regulator_set_enable, +}; + +static const struct udevice_id fixed_regulator_ids[] = { + { .compatible ="regulator-fixed" }, + { }, +}; + +U_BOOT_DRIVER (fixed_regulator) = { + .name ="fixed regulator" , + .id =UCLASS_REGULATOR , + .ops = &fixed_regulator_ops, + .of_match = fixed_regulator_ids, + .ofdata_to_platdata = fixed_regulator_ofdata_to_platdata,
Quoted 9 lines
Quoted 5 lines
drivers/power/regulator/fixed.c new file +2
-1+ .priv_auto_alloc_size = sizeof(struct fixed_regulator_priv), +}; --1.9.1
Regards,
Simon
Thanks,
Signature · 4 lines
Przemyslaw Marczak Samsung R&D Institute Poland Samsung Electronics p.marczak at samsung.com
PATCH v3 13/17 doc: driver-model: pmic and regulator uclass documentation
In reply to 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 +350 -0
@@ -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 + . + +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, +for devices other uclass types. It is no matter what is the type of device +physical I/O interface. Usually PMIC devices are using SPI or I2C interface, +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, +this uclass can be implemented. This allows to drive the each regulator output +value, on/off state and custom defined operation modes. It also provides the +user interface for all operations. +For the very simple implementation, the regulator drivers are not required, +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. +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 +'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 +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 + +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.
Signature · 1 line
1.9.1
PATCH v3 13/17 doc: driver-model: pmic and regulator uclass documentation
Hi Przemyslaw,
Quoted 81 lines · Przemyslaw Marczak
Signed-off-by Przemyslaw Marczak <[email protected]>---
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.txtdoc/driver-model/pmic-framework.txt new file +65
-0@@ -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.
What does "e..g. if some hardware uses pins header" mean? Can you reword that to be clearer?
Quoted 3 lines
--
1.9.1
Regards,
Simon