Power(full) framework based on Driver Model
Subsystems (4)
cover Power(full) framework based on Driver Model
Hello,
This piece of code was a base for prepare my presentation talk for the U-Boot Mini Summit, which taking place at ELCE2014 conference, 13-th October 2014 Dusseldorf, Germany.
The tittle of talk: "Power(full) framework based on Driver Model"
The presentation will be shared after the Summit.
This patchset introduces the new one PMIC framework for the U-Boot. It is still under the construction, but the basic functionality was achieved and tested. Please feel free to comment and share the opinion.
I think that each patch is described full enough, but for some more design details, please look into the documentation file. It includes some basic examples for the PMIC drivers.
Quick summary of:
Framework:
- The new approach - UCLASS_PMIC - simple and designed for device I/O only
- Add new uclass types: UCLASS_PMIC and UCLASS_PMIC_REGULATOR
- Two uclass drivers for above types
- A common regulator operations - will easy cover the real devices design
Drivers:
- 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)
User 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
The future plans:
- Wait for the I2c Driver Model implementation
- Introduce a common way to bind pmic devices - now done by alias "pmic"
- Add additional uclass types: MUIC, CHARGER, BATTERY, MFD and maybe more.
- Introduce optimal operations for new uclasses
- Port all U-Boot drivers to the new Framework
- Remove the old drivers and the old PMIC Framework code
The 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 readability
- Port all drivers using new API
- Remove the old Framework and the old drivers
A disadvantage:
- some parts of the present code is duplicated
Need help:
- After merge this, it is welcome to help with driver porting.
- Everything should be tested
The extra feature:
The first commit introduces errno_str() function.
It is a common function which I hope will be usefull for commands and not only. If any visible error says: -19 or some other magic number, then it means that this function should be used.
U-Boot Mini Summit members:
This code is maybe not as good as it could be, but the time was limited, and the conference is comming soon. I don't expects a code review of this now, but it would be nice if you take a look of this piece of code before our U-Boot Mini Summit. Of course it depends on you.
Best Regards and see you in Dusseldorf!
Przemyslaw Marczak
Przemyslaw Marczak (19):
lib: errno: introduce errno_str(): returns errno related message
exynos: config-common: enable errno_str() function
exynos: config-common: enable generic fs command
dm: pmic: add implementation of driver model pmic uclass
dm: pmic: add implementation of driver model regulator uclass
dm: common: board_r: add call and weak of power_init_dm()
dm: pmic: add max77686 pmic driver
dm: regulator: add max77686 regulator driver
dm: pmic: new commands: pmic and regulator
dm: board:samsung: power_init_board: add requirement of CONFIG_DM_PMIC
doc: driver-model: pmic and regulator uclass documentation
samsung: board: lcd menu: check if any power framework is enabled
samsung: misc: power_key_pressed: add support to dm pmic framework
trats2: board: add support to dm pmic api
trats2: dts: max77686: add pmic alias and names cleanup
trats2: config: enable dm pmic, dm regulator api, dm max77686
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 | 250 +++++++++- arch/arm/dts/exynos4412-trats2.dts | 17 +- board/samsung/common/board.c | 5 +- board/samsung/common/misc.c | 21 +- board/samsung/odroid/odroid.c | 31 +- board/samsung/trats2/trats2.c | 208 ++------ common/board_r.c | 8 + doc/driver-model/dm-pmic-framework.txt | 450 ++++++++++++++++++ drivers/power/Makefile | 6 +- drivers/power/cmd_pmic.c | 845 +++++++++++++++++++++++++++++++++ drivers/power/pmic-uclass.c | 255 ++++++++++ drivers/power/pmic/Makefile | 1 + drivers/power/pmic/max77686.c | 89 ++++ drivers/power/pmic_i2c.c | 136 ++++++ drivers/power/pmic_spi.c | 137 ++++++ drivers/power/regulator-uclass.c | 250 ++++++++++ drivers/power/regulator/Makefile | 8 + drivers/power/regulator/max77686.c | 749 +++++++++++++++++++++++++++++ include/configs/exynos-common.h | 3 + include/configs/odroid.h | 8 +- include/configs/trats2.h | 14 +- include/dm/uclass-id.h | 4 + include/errno.h | 3 + include/power/max77686_pmic.h | 28 +- include/power/pmic.h | 82 ++++ include/power/regulator.h | 267 +++++++++++ lib/Makefile | 1 + lib/errno_str.c | 147 ++++++ 29 files changed, 3823 insertions(+), 201 deletions(-) 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/pmic_i2c.c create mode 100644 drivers/power/pmic_spi.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 create mode 100644 lib/errno_str.c
Signature · 1 line
1.9.1
PATCH 1/19 lib: errno: introduce errno_str(): returns errno related message
The functions error's numbers are standarized - but the error messages are not.
The errors are often handled with unclear error messages, so why not use an errno standarized messages.
Advantages:
- This could decrease the binary size.
- Appended with a detailed information,
the error message will be clear.
This commit introduces new function:
- const char *errno_to_str(int errno)
The functions 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
--- include/errno.h | 3 ++ lib/Makefile | 1 + lib/errno_str.c | 147 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 151 insertions(+) create mode 100644 lib/errno_str.c
include/errno.h +3 -0
@@ -6,4 +6,7 @@ extern int errno;#define __set_errno (val) do { errno = val; } while (0) +#ifdef CONFIG_ERRNO_STR +const char *errno_str (int errno); +#endif #endif /* _ERRNO_H */
lib/Makefile +1 -0
@@ -53,6 +53,7 @@ endif obj-$(CONFIG_ADDR_MAP) += addr_map.o obj-y += hashtable.o obj-y += errno.o +obj-$(CONFIG_ERRNO_STR) += errno_str.o obj-y += display_options.o obj-$(CONFIG_BCH) += bch.o obj-y += crc32.o
lib/errno_str.c new file +147 -0
147 lines not on this page · raw message
Signature · 1 line
1.9.1
PATCH 1/19 lib: errno: introduce errno_str(): returns errno related message
Quoted 10 lines
From: Przemyslaw Marczak <[email protected]>
The functions error's numbers are standarized - but the error messages are not.
The errors are often handled with unclear error messages, so why not use an errno standarized messages.
Advantages:
- This could decrease the binary size.
Having an array of string ptrs adds some extra space needs. Each str needs a ptr and that ptr needs relocation, 8 bytes on 32 bits
If you want to save space do this instead
static const char const errno_message[] =
"Success\0Operation not permitted\0No such file or directory" etc.
Then count "\0" to find the error msg.
Jocke
PATCH 1/19 lib: errno: introduce errno_str(): returns errno related message
Hello Joakim,
Quoted 14 lines · Joakim Tjernlund
Quoted 10 lines
From: Przemyslaw Marczak <[email protected]>
The functions error's numbers are standarized - but the error messages are not.
The errors are often handled with unclear error messages, so why not use an errno standarized messages.
Advantages:
- This could decrease the binary size.Having an array of string ptrs adds some extra space needs. Each str needs a ptr and that ptr needs relocation, 8 bytes on 32 bits
Quoted 7 lines
If you want to save space do this instead
static const char const errno_message[] =
"Success\0Operation not permitted\0No such file or directory" etc.
Then count "\0" to find the error msg.Jocke
Is this really a problem to add some array with the pointers?
You are right, this array requires some additional space, but this is not the main reason of introducing this function. This can be enabled optional, so maybe for the less memory and slower devices this shouldn't be used - but in the other way, we see many text messages in the code that could be replaced with the one from that array.
So, which is better?
This helps me sometimes, so I added this as some extra feature.
Best Regards,
Signature · 4 lines
Przemyslaw Marczak Samsung R&D Institute Poland Samsung Electronics p.marczak at samsung.com
PATCH 1/19 lib: errno: introduce errno_str(): returns errno related message
Quoted 29 lines · Przemyslaw Marczak
Hello Joakim,
Quoted 15 lines · Joakim Tjernlund
From: Przemyslaw Marczak <[email protected]>
Quoted 10 lines
The functions error's numbers are standarized - but the error messages are not.
The errors are often handled with unclear error messages, so why not use an errno standarized messages.
Advantages:
- This could decrease the binary size.Having an array of string ptrs adds some extra space needs. Each str needs a ptr and that ptr needs relocation, 8 bytes on 32 bits
Quoted 8 lines
If you want to save space do this instead
static const char const errno_message[] =
"Success\0Operation not permitted\0No such file or directory" etc.
Then count "\0" to find the error msg.Jocke
Is this really a problem to add some array with the pointers?
Quoted 9 lines
You are right, this array requires some additional space, but this is not the main reason of introducing this function. This can be enabled optional, so maybe for the less memory and slower devices this shouldn't be used - but in the other way, we see many text messages in the code that could be replaced with the one from that array.
So, which is better?This helps me sometimes, so I added this as some extra feature.
I think it looks good as it is as it is simple. My only suggestion is that the CONFIG should not remove the function, merely make it return an empty string or "Error strings unavailable". Otherwise you will force #ifdefs in the code.
Regards,
Simon
PATCH 1/19 lib: errno: introduce errno_str(): returns errno related message
In reply to Przemyslaw MarczakPrzemyslaw Marczak <[email protected]> wrote on 2014/10/09 18:23:54:
Quoted 23 lines
Hello Joakim,
Quoted 19 lines · Joakim Tjernlund
Quoted 10 lines
From: Przemyslaw Marczak <[email protected]>
The functions error's numbers are standarized - but the error messages are not.
The errors are often handled with unclear error messages, so why not use an errno standarized messages.
Advantages:
- This could decrease the binary size.Having an array of string ptrs adds some extra space needs. Each str needs a ptr and that ptr needs relocation, 8 bytes on 32 bits
If you want to save space do this instead
static const char const errno_message[] =
"Success\0Operation not permitted\0No such file or directory" etc.
Then count "\0" to find the error msg.
Quoted 4 lines
Quoted 2 lines
Jocke
Is this really a problem to add some array with the pointers?
Probably not, I only mentioned this because you claimed it could reduces size
as if that was important to you.
Jocke
Quoted 10 lines
You are right, this array requires some additional space, but this is not the main reason of introducing this function. This can be enabled optional, so maybe for the less memory and slower devices this shouldn't
be used - but in the other way, we see many text messages in the code that could be replaced with the one from that array.
So, which is better?This helps me sometimes, so I added this as some extra feature.
PATCH 1/19 lib: errno: introduce errno_str(): returns errno related message
Hello Joakim,
Quoted 27 lines · Joakim Tjernlund
Przemyslaw Marczak <[email protected]> wrote on 2014/10/09 18:23:54:
Quoted 26 lines
Hello Joakim,
Quoted 21 lines · Joakim Tjernlund
Quoted 10 lines
From: Przemyslaw Marczak <[email protected]>
The functions error's numbers are standarized - but the error messages are not.
The errors are often handled with unclear error messages, so why not use an errno standarized messages.
Advantages:
- This could decrease the binary size.Having an array of string ptrs adds some extra space needs. Each str needs a ptr and that ptr needs relocation, 8 bytes on 32 bits
If you want to save space do this instead
static const char const errno_message[] =
"Success\0Operation not permitted\0No such file or directory" etc.
Then count "\0" to find the error msg.Jocke
Quoted 8 lines
Quoted 1 line
Is this really a problem to add some array with the pointers?
Probably not, I only mentioned this because you claimed it could reduces size
as if that was important to you.Jocke
I meant that it will reduce the size, if we could change the whole code "common message string parts" with a pointer to some standard message.
Quoted 5 lines
Quoted 4 lines
You are right, this array requires some additional space, but this is not the main reason of introducing this function. This can be enabled optional, so maybe for the less memory and slower devices this shouldn't
Quoted 8 lines
Quoted 5 lines
be used - but in the other way, we see many text messages in the code that could be replaced with the one from that array.
So, which is better?This helps me sometimes, so I added this as some extra feature.
Your notice about the size was right, but I hope that U-Boot is used for machines, in which this doesn't make a difference - and the code is still simple and the "error messages" - means what they should mean.
Best Regards,
Signature · 4 lines
Przemyslaw Marczak Samsung R&D Institute Poland Samsung Electronics p.marczak at samsung.com
PATCH 1/19 lib: errno: introduce errno_str(): returns errno related message
In reply to Przemyslaw MarczakQuoted 11 lines · Przemyslaw Marczak
The functions error's numbers are standarized - but the error messages are not.
The errors are often handled with unclear error messages, so why not use an errno standarized messages.
Advantages:
- This could decrease the binary size.
- Appended with a detailed information,
the error message will be clear.
Quoted 8 lines
This commit introduces new function:
- const char *errno_to_str(int errno)The functions 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 messageSigned-off-by Przemyslaw Marczak <[email protected]>
In and of itself,
Signature · 8 lines
Tom -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 836 bytes Desc: Digital signature URL: <http://lists.denx.de/pipermail/u-boot/attachments/20141022/e45c54a3/attachment.pgp>
PATCH 1/19 lib: errno: introduce errno_str(): returns errno related message
Quoted 20 lines · Tom Rini
Quoted 18 lines · Przemyslaw Marczak
The functions error's numbers are standarized - but the error messages are not.
The errors are often handled with unclear error messages, so why not use an errno standarized messages.
Advantages:
- This could decrease the binary size.
- Appended with a detailed information,
the error message will be clear.This commit introduces new function:
- const char *errno_to_str(int errno)The functions 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
Quoted 5 lines
Quoted 1 line
Signed-off-by Przemyslaw Marczak <[email protected]>In and of itself,
Reviewed-by Tom Rini <[email protected]>
Applied to u-boot-dm, thanks!
- Simon
PATCH 1/19 lib: errno: introduce errno_str(): returns errno related message
Hello Simon,
Quoted 23 lines · Simon Glass
Quoted 22 lines · Tom Rini
Quoted 19 lines · Przemyslaw Marczak
The functions error's numbers are standarized - but the error messages are not.
The errors are often handled with unclear error messages, so why not use an errno standarized messages.
Advantages:
- This could decrease the binary size.
- Appended with a detailed information,
the error message will be clear.This commit introduces new function:
- const char *errno_to_str(int errno)The functions 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 messageSigned-off-by Przemyslaw Marczak <[email protected]>
Quoted 8 lines
Quoted 3 lines
In and of itself,
Reviewed-by Tom Rini <[email protected]>Applied to u-boot-dm, thanks!
- Simon
Thank, maybe today or tomorrow I will send the I2C for exynos and next I can continue work on pmic.
Best regards,
Signature · 4 lines
Przemyslaw Marczak Samsung R&D Institute Poland Samsung Electronics p.marczak at samsung.com
PATCH 1/19 lib: errno: introduce errno_str(): returns errno related message
Hi Przemyslaw,
Quoted 35 lines · Przemyslaw Marczak
Hello Simon,
Quoted 31 lines · Simon Glass
Quoted 27 lines · Tom Rini
Quoted 11 lines · Przemyslaw Marczak
The functions error's numbers are standarized - but the error messages are not.
The errors are often handled with unclear error messages, so why not use an errno standarized messages.
Advantages:
- This could decrease the binary size.
- Appended with a detailed information,
the error message will be clear.Quoted 8 lines
This commit introduces new function:
- const char *errno_to_str(int errno)The functions 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 messageSigned-off-by Przemyslaw Marczak <[email protected]>In and of itself,
Reviewed-by Tom Rini <[email protected]>
Quoted 7 lines
Quoted 4 lines
Applied to u-boot-dm, thanks!
- Simon
Thank, maybe today or tomorrow I will send the I2C for exynos and next I can continue work on pmic.
OK sounds good. I've pushed DM I2C things to dm/master, although not Tegra yet while I wait on the nyan-big patch.
Regards,
Simon
PATCH 2/19 exynos: config-common: enable errno_str() function
In reply to Przemyslaw Marczak--- include/configs/exynos-common.h | 2 ++ 1 file changed, 2 insertions(+)
include/configs/exynos-common.h +2 -0
@@ -95,4 +95,6 @@#define CONFIG_SYS_NO_FLASH #undef CONFIG_CMD_IMLS +#define CONFIG_ERRNO_STR +#endif /* __CONFIG_H */
Signature · 1 line
1.9.1
PATCH 3/19 exynos: config-common: enable generic fs command
In reply to Przemyslaw MarczakThis command is required for trats2 and odroid
environment, since those boards uses it.
--- include/configs/exynos-common.h | 1 + 1 file changed, 1 insertion(+)
include/configs/exynos-common.h +1 -0
@@ -80,6 +80,7 @@#define CONFIG_EFI_PARTITION #define CONFIG_CMD_PART #define CONFIG_PARTITION_UUIDS +#define CONFIG_CMD_FS_GENERIC /* Miscellaneous configurable options */ #define CONFIG_SYS_LONGHELP /* undef to save memory */
Signature · 1 line
1.9.1
PATCH 4/19 dm: pmic: add implementation of driver model pmic uclass
In reply to Przemyslaw MarczakThis is an introduction to driver-model multi class PMIC support. It starts with UCLASS_PMIC - a common PMIC class type for I/O, which doesn't need to implement any specific operations and features beside the platform data, which is the 'struct pmic_platdata' defined in file:
- 'include/power/pmic.h'
New files:
- pmic-uclass.c - provides a common code for UCLASS_PMIC drivers
- pmic_i2c.c - provides dm interface for i2c pmic drivers
- pmic_spi.c - provides dm interface for spi pmic drivers
Those files are based on a current PMIC framework files and code. The new files are introduced to keep code readability and allow to make an easy drivers migration. The old pmic framework is still kept and full independent.
Changes:
- new uclass-id: UCLASS_PMIC,
- new configs: CONFIG_DM_PMIC; CONFIG_DM_PMIC_SPI; CONFIG_DM_PMIC_I2C,
New pmic api is documented in: doc/README.power-framework-dm
--- drivers/power/Makefile | 3 + drivers/power/pmic-uclass.c | 255 ++++++++++++++++++++++++++++++++++++++++++++ drivers/power/pmic_i2c.c | 136 +++++++++++++++++++++++ drivers/power/pmic_spi.c | 137 ++++++++++++++++++++++++ include/dm/uclass-id.h | 3 + include/power/pmic.h | 64 +++++++++++ 6 files changed, 598 insertions(+) create mode 100644 drivers/power/pmic-uclass.c create mode 100644 drivers/power/pmic_i2c.c create mode 100644 drivers/power/pmic_spi.c
drivers/power/Makefile +3 -0
@@ -19,3 +19,6 @@ 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_SPI) += pmic_spi.o +obj-$(CONFIG_DM_PMIC_I2C) += pmic_i2c.o +obj-$(CONFIG_DM_PMIC) += pmic-uclass.o
drivers/power/pmic-uclass.c new file +255 -0
255 lines not on this page · raw message
drivers/power/pmic_i2c.c new file +136 -0
136 lines not on this page · raw message
drivers/power/pmic_spi.c new file +137 -0
137 lines not on this page · raw message
include/dm/uclass-id.h +3 -0
@@ -29,6 +29,9 @@ enum uclass_id {UCLASS_SPI_FLASH ,/* SPI flash */ UCLASS_CROS_EC ,/* Chrome OS EC */ +/* PMIC uclass and PMIC related uclasses */ +UCLASS_PMIC , +UCLASS_COUNT , UCLASS_INVALID = -1, };
include/power/pmic.h +64 -0
89 lines not on this page · raw message
Signature · 1 line
1.9.1
PATCH 4/19 dm: pmic: add implementation of driver model pmic uclass
Hi,
Quoted 97 lines · Przemyslaw Marczak
This is an introduction to driver-model multi class PMIC support. It starts with
UCLASS_PMIC- a common PMIC class type for I/O, which doesn't need to implement any specific operations and features beside the platform data, which is the 'structpmic_platdata' defined in file:
- 'include/power/pmic.h'New files:
-pmic-uclass.c- provides a common code forUCLASS_PMICdrivers
-pmic_i2c.c- provides dm interface for i2c pmic drivers
-pmic_spi.c- provides dm interface for spi pmic driversThose files are based on a current PMIC framework files and code. The new files are introduced to keep code readability and allow to make an easy drivers migration. The old pmic framework is still kept and full independent.
Changes:
- new uclass-id:UCLASS_PMIC,
- new configs:CONFIG_DM_PMIC;CONFIG_DM_PMIC_SPI;CONFIG_DM_PMIC_I2C,New pmic api is documented in: doc/README.power-framework-dm
Signed-off-by Przemyslaw Marczak <[email protected]>--- drivers/power/Makefile | 3 + drivers/power/pmic-uclass.c | 255 ++++++++++++++++++++++++++++++++++++++++++++ drivers/power/pmic_i2c.c | 136 +++++++++++++++++++++++ drivers/power/pmic_spi.c | 137 ++++++++++++++++++++++++ include/dm/uclass-id.h | 3 + include/power/pmic.h | 64 +++++++++++ 6 files changed, 598 insertions(+) create mode 100644 drivers/power/pmic-uclass.c create mode 100644 drivers/power/pmic_i2c.c create mode 100644 drivers/power/pmic_spi.cdrivers/power/Makefile +3
-0@@ -19,3 +19,6 @@ 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_SPI) += pmic_spi.o +obj-$(CONFIG_DM_PMIC_I2C) += pmic_i2c.o +obj-$(CONFIG_DM_PMIC) += pmic-uclass.odrivers/power/pmic-uclass.c new file +45
-0@@ -0,0 +1,255 @@ +/* +* Copyright (C) 2014 Samsung Electronics +* Przemyslaw Marczak <[email protected]> +* +* SPDX-License-Identifier: GPL-2.0+ +*/ +#include <common.h> +#include <linux/types.h> +#include <fdtdec.h> +#include <power/pmic.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> + +DECLARE_GLOBAL_DATA_PTR ; + +int pmic_check_reg (struct pmic_platdata *p,unsigned reg) +{ +if (!p) +return -ENODEV ; + +if (reg >= p->regs_num) { +error ("<reg num> = %d is invalid. Should be less than %d" , + reg, p->regs_num); +return -EINVAL ; + } + +return 0 ; +} + +int pmic_reg_write (struct udevice *dev,unsigned reg,unsigned val) +{ +struct pmic_platdata *p; + + p =dev_get_platdata (dev); +if (!p) +return -EPERM ; + +switch (p->interface) { +case PMIC_I2C : +#ifdef CONFIG_DM_PMIC_I2C
drivers/power/pmic-uclass.c line 55
Quoted 10 lines
drivers/power/pmic-uclass.c new file +10
-0+return pmic_i2c_reg_write (dev, reg, val); +#else +return -ENOSYS ; +#endif +case PMIC_SPI : +#ifdef CONFIG_DM_PMIC_SPI +return pmic_spi_reg_write (dev, reg, val); +#else +return -ENOSYS ; +#endif
Perhaps one day we should add another uclass which is some sort of register cache. It could be implemented by I2C and SPI drivers (or better perhaps the I2C and SPI uclasses could provide a register cache uclass device for their main when requested).
For now this seems fine though. I think the 'return -ENOSYS' can just go at the end of the function and appear once.
Quoted 54 lines
drivers/power/pmic-uclass.c new file +54
-0+default : +return -ENODEV ; + } +} + +int pmic_reg_read (struct udevice *dev,unsigned reg,unsigned *val) +{ +struct pmic_platdata *p; + + p =dev_get_platdata (dev); +if (!p) +return -EPERM ; + +switch (p->interface) { +case PMIC_I2C : +#ifdef CONFIG_DM_PMIC_I2C +return pmic_i2c_reg_read (dev, reg, val); +#else +return -ENOSYS ; +#endif +case PMIC_SPI : +#ifdef CONFIG_DM_PMIC_SPI +return pmic_spi_reg_read (dev, reg, val); +#else +return -ENOSYS ; +#endif +default : +return -ENODEV ; + } +} + +int pmic_probe (struct udevice *dev,struct spi_slave *spi_slave) +{ +struct pmic_platdata *p; + + p =dev_get_platdata (dev); +if (!p) +return -EPERM ; + +switch (p->interface) { +case PMIC_I2C : +#ifdef CONFIG_DM_PMIC_I2C +return pmic_i2c_probe (dev); +#else +return -ENOSYS ; +#endif +case PMIC_SPI : +if (!spi_slave) +return -EINVAL ; +#ifdef CONFIG_DM_PMIC_SPI + spi_slave =pmic_spi_probe (dev); +if (!spi_slave) +return -EIO ; +
drivers/power/pmic-uclass.c line 119
Quoted 10 lines
drivers/power/pmic-uclass.c new file +10
-0+return 0 ; +#else +return -ENOSYS ; +#endif +default : +return -ENODEV ; + } +} + +struct udevice *pmic_get_by_interface (int uclass_id,int bus,int addr_cs)
This is an interesting function! Again we can probably improve things when we have an i2c uclass.
Quoted 74 lines
drivers/power/pmic-uclass.c new file +74
-0+{ +struct pmic_platdata *pl; +struct udevice *dev; +struct uclass *uc; +int ret; + +if (uclass_id <0 || uclass_id >=UCLASS_COUNT ) { +error ("Bad uclass id.\n" ); +return NULL ; + } + + ret =uclass_get (uclass_id, &uc); +if (ret) { +error ("PMIC uclass: %d not initialized!\n" , uclass_id); +return NULL ; + } + + uclass_foreach_dev(dev, uc) { +if (!dev || !dev->platdata) +continue ; + + pl =dev_get_platdata (dev); + +if (pl->bus != bus) +continue ; + +switch (pl->interface) { +case PMIC_I2C : +if (addr_cs != pl->hw.i2c.addr) +continue ; +break ; +case PMIC_SPI : +if (addr_cs != pl->hw.spi.cs) +continue ; +break ; +default : +error ("Unsupported interface of: %s" , dev->name); +return NULL ; + } + + ret =device_probe (dev); +if (ret) { +error ("Dev: %s probe failed" , dev->name); +return NULL ; + } +return dev; + } + +return NULL ; +} + +struct udevice *pmic_get_by_name (int uclass_id,char *name) +{ +struct udevice *dev; +struct uclass *uc; +int ret; + +if (uclass_id <0 || uclass_id >=UCLASS_COUNT ) { +error ("Bad uclass id.\n" ); +return NULL ; + } + + ret =uclass_get (uclass_id, &uc); +if (ret) { +error ("PMIC uclass: %d not initialized!" , uclass_id); +return NULL ; + } + + uclass_foreach_dev(dev, uc) { +if (!dev) +continue ; + +if (!strncmp (name, dev->name,strlen (name))) { + ret =device_probe (dev);
drivers/power/pmic-uclass.c line 203
Quoted 10 lines
drivers/power/pmic-uclass.c new file +10
-0+if (ret) +error ("Dev: %s probe failed" , dev->name); +return dev; + } + } + +return NULL ; +} + +int pmic_init_dm (void )
I don't understand why you need this function at all. Driver model should find the pmics automatically. Is it because we don't have an i2c uclass? In that case I think it would be better to limit this hack to I2C. For SPI it should work correctly without this function.
Quoted 391 lines
drivers/power/pmic-uclass.c new file +52
-0+{ +const void *blob = gd->fdt_blob; +const struct fdt_property *prop; +struct udevice *dev =NULL ; +const char *path; +const char *alias; +int alias_node, node, offset, ret =0 ; +int alias_len; +int len; + + alias ="pmic" ; + alias_len =strlen (alias); + + alias_node =fdt_path_offset (blob,"/aliases" ); + offset =fdt_first_property_offset (blob, alias_node); + +if (offset <0 ) { +error ("Alias node not found." ); +return -ENODEV ; + } + + offset =fdt_first_property_offset (blob, alias_node); +for (; offset >0 ; offset =fdt_next_property_offset (blob, offset)) { + prop =fdt_get_property_by_offset (blob, offset, &len); +if (!len) +continue ; + + path =fdt_string (blob,fdt32_to_cpu (prop->nameoff)); + +if (!strncmp (alias, path, alias_len)) + node =fdt_path_offset (blob, prop->data); +else + node =0 ; + +if (node <=0 ) +continue ; + + ret =lists_bind_fdt (gd->dm_root, blob, node, &dev); +if (ret <0 ) +continue ; + +if (device_probe (dev)) +error ("Device: %s, probe error" , dev->name); + } + +return 0 ; +} + +UCLASS_DRIVER (pmic) = { + .id =UCLASS_PMIC , + .name ="pmic" , +};drivers/power/pmic_i2c.c new file +136
-0@@ -0,0 +1,136 @@ +/* +* Copyright (C) 2014 Samsung Electronics +* Przemyslaw Marczak <[email protected]> +* +* Copyright (C) 2011 Samsung Electronics +* Lukasz Majewski <[email protected]> +* +* (C) Copyright 2010 +* Stefano Babic, DENX Software Engineering, sbabic at denx.de +* +* (C) Copyright 2008-2009 Freescale Semiconductor, Inc. +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#include <common.h> +#include <linux/types.h> +#include <power/pmic.h> +#include <errno.h> +#include <dm.h> +#include <i2c.h> + +int pmic_i2c_reg_write (struct udevice *dev,unsigned reg,unsigned val) +{ +struct pmic_platdata *p; +unsigned char buf[4 ] = {0 }; + +if (!dev) +return -ENODEV ; + + p = dev->platdata; + +if (pmic_check_reg (p, reg)) +return -EINVAL ; + +I2C_SET_BUS (p->bus); + +switch (pmic_i2c_tx_num) { +case 3 : +if (p->byte_order ==PMIC_SENSOR_BYTE_ORDER_BIG ) { + buf[2 ] = (cpu_to_le32 (val) >>16 ) &0xff ; + buf[1 ] = (cpu_to_le32 (val) >>8 ) &0xff ; + buf[0 ] =cpu_to_le32 (val) &0xff ; + }else { + buf[0 ] = (cpu_to_le32 (val) >>16 ) &0xff ; + buf[1 ] = (cpu_to_le32 (val) >>8 ) &0xff ; + buf[2 ] =cpu_to_le32 (val) &0xff ; + } +break ; +case 2 : +if (p->byte_order ==PMIC_SENSOR_BYTE_ORDER_BIG ) { + buf[1 ] = (cpu_to_le32 (val) >>8 ) &0xff ; + buf[0 ] =cpu_to_le32 (val) &0xff ; + }else { + buf[0 ] = (cpu_to_le32 (val) >>8 ) &0xff ; + buf[1 ] =cpu_to_le32 (val) &0xff ; + } +break ; +case 1 : + buf[0 ] =cpu_to_le32 (val) &0xff ; +break ; +default : +printf ("%s: invalid tx_num: %d" , __func__, pmic_i2c_tx_num); +return -1 ; + } + +if (i2c_write (pmic_i2c_addr, reg,1 , buf, pmic_i2c_tx_num)) +return -1 ; + +return 0 ; +} + +int pmic_i2c_reg_read (struct udevice *dev,unsigned reg,unsigned *val) +{ +struct pmic_platdata *p; +unsigned char buf[4 ] = {0 }; +u32 ret_val =0 ; + +if (!dev) +return -ENODEV ; + + p = dev->platdata; + +if (pmic_check_reg (p, reg)) +return -EINVAL ; + +I2C_SET_BUS (p->bus); + +if (i2c_read (pmic_i2c_addr, reg,1 , buf, pmic_i2c_tx_num)) +return -1 ; + +switch (pmic_i2c_tx_num) { +case 3 : +if (p->byte_order ==PMIC_SENSOR_BYTE_ORDER_BIG ) + ret_val =le32_to_cpu (buf[2 ] <<16 + | buf[1 ] <<8 | buf[0 ]); +else + ret_val =le32_to_cpu (buf[0 ] <<16 | + buf[1 ] <<8 | buf[2 ]); +break ; +case 2 : +if (p->byte_order ==PMIC_SENSOR_BYTE_ORDER_BIG ) + ret_val =le32_to_cpu (buf[1 ] <<8 | buf[0 ]); +else + ret_val =le32_to_cpu (buf[0 ] <<8 | buf[1 ]); +break ; +case 1 : + ret_val =le32_to_cpu (buf[0 ]); +break ; +default : +printf ("%s: invalid tx_num: %d" , __func__, pmic_i2c_tx_num); +return -1 ; + } +memcpy (val, &ret_val,sizeof (ret_val)); + +return 0 ; +} + +int pmic_i2c_probe (struct udevice *dev) +{ +struct pmic_platdata *p; + +if (!dev) +return -ENODEV ; + + p = dev->platdata; + +i2c_set_bus_num (p->bus); +debug ("Bus: %d PMIC:%s probed!\n" , p->bus, dev->name); +if (i2c_probe (pmic_i2c_addr)) { +printf ("Can't find PMIC:%s\n" , dev->name); +return -1 ; + } + +return 0 ; +}drivers/power/pmic_spi.c new file +137
-0@@ -0,0 +1,137 @@ +/* +* Copyright (C) 2014 Samsung Electronics +* Przemyslaw Marczak <[email protected]> +* +* Copyright (C) 2011 Samsung Electronics +* Lukasz Majewski <[email protected]> +* +* (C) Copyright 2010 +* Stefano Babic, DENX Software Engineering, sbabic at denx.de +* +* (C) Copyright 2008-2009 Freescale Semiconductor, Inc. +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#include <common.h> +#include <linux/types.h> +#include <power/pmic.h> +#include <errno.h> +#include <dm.h> +#include <spi.h> + +static struct spi_slave *slave; + +void pmic_spi_free (struct spi_slave *slave) +{ +if (slave) +spi_free_slave (slave); +} + +struct spi_slave *pmic_spi_probe (struct udevice *dev) +{ +struct pmic_platdata *p; + +if (!dev) +return NULL ; + + p = dev->platdata; + +if (pmic_check_reg (p, reg)) +return NULL ; + +return spi_setup_slave (p->bus, + p->hw.spi.cs, + p->hw.spi.clk, + p->hw.spi.mode); +} + +static int pmic_spi_reg (struct udevice *dev,unsigned reg,unsigned *val, +int write) +{ +struct pmic_platdata *p; +u32 pmic_tx, pmic_rx; +u32 tmp; + +if (!dev) +return -EINVAL ; + + p = dev->platdata; + +if (pmic_check_reg (p, reg)) +return -EFAULT ; + +if (!slave) { + slave =pmic_spi_probe (p); + +if (!slave) +return -ENODEV ; + } + +if (pmic_check_reg (p, reg)) +return -EFAULT ; + +if (spi_claim_bus (slave)) +return -EIO ; + + pmic_tx = p->hw.spi.prepare_tx (reg, val, write); + + tmp =cpu_to_be32 (pmic_tx); + +if (spi_xfer (slave, pmic_spi_bitlen, &tmp, &pmic_rx, + pmic_spi_flags)) { +spi_release_bus (slave); +return -EIO ; + } + +if (write) { + pmic_tx = p->hw.spi.prepare_tx (reg, val,0 ); + tmp =cpu_to_be32 (pmic_tx); +if (spi_xfer (slave, pmic_spi_bitlen, &tmp, &pmic_rx, + pmic_spi_flags)) { +spi_release_bus (slave); +return -EIO ; + } + } + +spi_release_bus (slave); + *val =cpu_to_be32 (pmic_rx); + +return 0 ; +} + +int pmic_spi_reg_write (struct udevice *dev,unsigned reg,unsigned val) +{ +struct pmic_platdata *p; + +if (!dev) +return -EINVAL ; + + p = dev->platdata; + +if (pmic_check_reg (p, reg)) +return -EFAULT ; + +if (pmic_spi_reg (p, reg, &val,1 )) +return -1 ; + +return 0 ; +} + +int pmic_spi_reg_read (struct udevice *dev,unsigned reg,unsigned *val) +{ +struct pmic_platdata *p; + +if (!dev) +return -EINVAL ; + + p = dev->platdata; + +if (pmic_check_reg (p, reg)) +return -EFAULT ; + +if (pmic_spi_reg (p, reg, val,0 )) +return -1 ; + +return 0 ; +}include/dm/uclass-id.h +3
-0@@ -29,6 +29,9 @@ enum uclass_id {UCLASS_SPI_FLASH ,/* SPI flash */ UCLASS_CROS_EC ,/* Chrome OS EC */ +/* PMIC uclass and PMIC related uclasses */ +UCLASS_PMIC , +UCLASS_COUNT , UCLASS_INVALID = -1, };include/power/pmic.h +17
-0@@ -1,4 +1,7 @@/* +* Copyright (C) 2014 Samsung Electronics +* Przemyslaw Marczak <[email protected]> +* * Copyright (C) 2011-2012 Samsung Electronics * Lukasz Majewski <[email protected]> * @@ -8,9 +11,12 @@#ifndef __CORE_PMIC_H_#define __CORE_PMIC_H_ +#include <dm.h> #include <linux/list.h> +#include <spi.h> #include <i2c.h> #include <power/power_chrg.h> +#include <power/regulator.h> enum {PMIC_I2C ,PMIC_SPI ,PMIC_NONE };enum {I2C_PMIC ,I2C_NUM , };@@ -78,6 +84,63 @@ struct pmic {struct list_head list; }; +#ifdef CONFIG_DM_PMIC +/* struct pmic_platdata - a standard descriptor for pmic device, which holds +* an informations about interface. It is common for all pmic devices. +* +* Note: +* Interface fields are the same as in: struct pmic. +* Note: struct pmic will be removed in the future after drivers migration +* +* @bus - a physical bus on which device is connected +* @interface - an interface type, one of enum: PMIC_I2C, PMIC_SPI, PMIC_NONE +* @byte_order - one of enum: PMIC_SENSOR_BYTE_ORDER*_LITTLE/_BIG
include/power/pmic.h struct pmic { · line 107
Quoted 10 lines
include/power/pmic.h +10
-0+* @regs_num - number of device registers +* @hw - one of union structure: p_i2c or p_spi +* based on @interface field +*/ +struct pmic_platdata { +int bus; +int interface; +int byte_order; +int regs_num; +union hw hw;
If we have a 'register cache' uclass (later, once i2c is done) then this could just be a device.
Quoted 40 lines
include/power/pmic.h +36
-0+}; + +/* enum pmic_op_type - used for various pmic devices operation calls, +* for decrease a number of functions 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 , +}; + +/* drivers/power/pmic-uclass.c */ +int power_init_dm (void ); +struct udevice *pmic_get_by_name (int uclass_id,char *name); +struct udevice *pmic_get_by_interface (int uclass_id,int bus,int addr_cs); +const char *pmic_if_str (int interface); +int pmic_check_reg (struct pmic_platdata *p,unsigned reg); +int pmic_reg_write (struct udevice *dev,unsigned reg,unsigned val); +int pmic_reg_read (struct udevice *dev,unsigned reg,unsigned *val); +int pmic_probe (struct udevice *dev,struct spi_slave *spi_slave); + +/* drivers/power/pmic_i2c.c */ +int pmic_i2c_reg_write (struct udevice *dev,unsigned reg,unsigned val); +int pmic_i2c_reg_read (struct udevice *dev,unsigned reg,unsigned *val); +int pmic_i2c_probe (struct udevice *dev); + +/* drivers/power/pmic_spi.c */ +int pmic_spi_reg_write (struct udevice *dev,unsigned reg,unsigned val); +int pmic_spi_reg_read (struct udevice *dev,unsigned reg,unsigned *val); +struct spi_slave *pmic_spi_probe (struct udevice *dev); +#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);
include/power/pmic.h int pmic_probe(struct pmic *p); · line 153
Quoted 3 lines
include/power/pmic.h +0
-0@@ -88,6 +151,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);
These should have comments.
Quoted 7 lines
include/power/pmic.h +1
-1+#endif #define pmic_i2c_addr (p->hw.i2c.addr)#define pmic_i2c_tx_num (p->hw.i2c.tx_num) --1.9.1
Regards,
Simon
PATCH 4/19 dm: pmic: add implementation of driver model pmic uclass
Hello Simon,
Quoted 116 lines · Simon Glass
Hi,
Quoted 97 lines · Przemyslaw Marczak
This is an introduction to driver-model multi class PMIC support. It starts with
UCLASS_PMIC- a common PMIC class type for I/O, which doesn't need to implement any specific operations and features beside the platform data, which is the 'structpmic_platdata' defined in file:
- 'include/power/pmic.h'New files:
-pmic-uclass.c- provides a common code forUCLASS_PMICdrivers
-pmic_i2c.c- provides dm interface for i2c pmic drivers
-pmic_spi.c- provides dm interface for spi pmic driversThose files are based on a current PMIC framework files and code. The new files are introduced to keep code readability and allow to make an easy drivers migration. The old pmic framework is still kept and full independent.
Changes:
- new uclass-id:UCLASS_PMIC,
- new configs:CONFIG_DM_PMIC;CONFIG_DM_PMIC_SPI;CONFIG_DM_PMIC_I2C,New pmic api is documented in: doc/README.power-framework-dm
Signed-off-by Przemyslaw Marczak <[email protected]>--- drivers/power/Makefile | 3 + drivers/power/pmic-uclass.c | 255 ++++++++++++++++++++++++++++++++++++++++++++ drivers/power/pmic_i2c.c | 136 +++++++++++++++++++++++ drivers/power/pmic_spi.c | 137 ++++++++++++++++++++++++ include/dm/uclass-id.h | 3 + include/power/pmic.h | 64 +++++++++++ 6 files changed, 598 insertions(+)create mode 100644
drivers/power/pmic-uclass.c
create mode 100644drivers/power/pmic_i2c.c
create mode 100644drivers/power/pmic_spi.cdrivers/power/Makefile +3
-0@@ -19,3 +19,6 @@ 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_SPI) += pmic_spi.o +obj-$(CONFIG_DM_PMIC_I2C) += pmic_i2c.o +obj-$(CONFIG_DM_PMIC) += pmic-uclass.odrivers/power/pmic-uclass.c new file +45
-0@@ -0,0 +1,255 @@ +/* +* Copyright (C) 2014 Samsung Electronics +* Przemyslaw Marczak <[email protected]> +* +* SPDX-License-Identifier: GPL-2.0+ +*/ +#include <common.h> +#include <linux/types.h> +#include <fdtdec.h> +#include <power/pmic.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> + +DECLARE_GLOBAL_DATA_PTR ; + +int pmic_check_reg (struct pmic_platdata *p,unsigned reg) +{ +if (!p) +return -ENODEV ; + +if (reg >= p->regs_num) { +error ("<reg num> = %d is invalid. Should be less than %d" , + reg, p->regs_num); +return -EINVAL ; + } + +return 0 ; +} + +int pmic_reg_write (struct udevice *dev,unsigned reg,unsigned val) +{ +struct pmic_platdata *p; + + p =dev_get_platdata (dev); +if (!p) +return -EPERM ; + +switch (p->interface) { +case PMIC_I2C : +#ifdef CONFIG_DM_PMIC_I2C drivers/power/pmic-uclass.c line 55
Quoted 10 lines
drivers/power/pmic-uclass.c new file +10
-0+return pmic_i2c_reg_write (dev, reg, val); +#else +return -ENOSYS ; +#endif +case PMIC_SPI : +#ifdef CONFIG_DM_PMIC_SPI +return pmic_spi_reg_write (dev, reg, val); +#else +return -ENOSYS ; +#endif Perhaps one day we should add another uclass which is some sort of register cache. It could be implemented by I2C and SPI drivers (or better perhaps the I2C and SPI uclasses could provide a register cache uclass device for their main when requested).
Quoted 3 lines
For now this seems fine though. I think the 'return
-ENOSYS' can just go at the end of the function and appear once.
Why do we need the registers cache?
This maybe is good for a many read operations at a time in the system, but actually I think, that it is not required for the bootloader purposes.
If we write some data - sequential, then we probably would like to check it in the same time, e.g. update some range of I2C registers.
I don't know the Chromebook design, but how it could be useful for you?
Quoted 59 lines
Quoted 59 lines
drivers/power/pmic-uclass.c new file +59
-0+default : +return -ENODEV ; + } +} + +int pmic_reg_read (struct udevice *dev,unsigned reg,unsigned *val) +{ +struct pmic_platdata *p; + + p =dev_get_platdata (dev); +if (!p) +return -EPERM ; + +switch (p->interface) { +case PMIC_I2C : +#ifdef CONFIG_DM_PMIC_I2C +return pmic_i2c_reg_read (dev, reg, val); +#else +return -ENOSYS ; +#endif +case PMIC_SPI : +#ifdef CONFIG_DM_PMIC_SPI +return pmic_spi_reg_read (dev, reg, val); +#else +return -ENOSYS ; +#endif +default : +return -ENODEV ; + } +} + +int pmic_probe (struct udevice *dev,struct spi_slave *spi_slave) +{ +struct pmic_platdata *p; + + p =dev_get_platdata (dev); +if (!p) +return -EPERM ; + +switch (p->interface) { +case PMIC_I2C : +#ifdef CONFIG_DM_PMIC_I2C +return pmic_i2c_probe (dev); +#else +return -ENOSYS ; +#endif +case PMIC_SPI : +if (!spi_slave) +return -EINVAL ; +#ifdef CONFIG_DM_PMIC_SPI + spi_slave =pmic_spi_probe (dev); +if (!spi_slave) +return -EIO ; + +return 0 ; +#else +return -ENOSYS ; +#endif +default :
Quoted 9 lines
drivers/power/pmic-uclass.c line 119
Quoted 5 lines
drivers/power/pmic-uclass.c new file +5
-0+return -ENODEV ; + } +} + +struct udevice *pmic_get_by_interface (int uclass_id,int bus,int addr_cs)This is an interesting function! Again we can probably improve things when we have an i2c uclass.
Thanks! But even if we have i2c uclass, then we also should know how to recognize each device, e.g. in the board code. So the interface and address will probably no change.
Quoted 81 lines
Quoted 81 lines
drivers/power/pmic-uclass.c new file +81
-0+{ +struct pmic_platdata *pl; +struct udevice *dev; +struct uclass *uc; +int ret; + +if (uclass_id <0 || uclass_id >=UCLASS_COUNT ) { +error ("Bad uclass id.\n" ); +return NULL ; + } + + ret =uclass_get (uclass_id, &uc); +if (ret) { +error ("PMIC uclass: %d not initialized!\n" , uclass_id); +return NULL ; + } + + uclass_foreach_dev(dev, uc) { +if (!dev || !dev->platdata) +continue ; + + pl =dev_get_platdata (dev); + +if (pl->bus != bus) +continue ; + +switch (pl->interface) { +case PMIC_I2C : +if (addr_cs != pl->hw.i2c.addr) +continue ; +break ; +case PMIC_SPI : +if (addr_cs != pl->hw.spi.cs) +continue ; +break ; +default : +error ("Unsupported interface of: %s" , dev->name); +return NULL ; + } + + ret =device_probe (dev); +if (ret) { +error ("Dev: %s probe failed" , dev->name); +return NULL ; + } +return dev; + } + +return NULL ; +} + +struct udevice *pmic_get_by_name (int uclass_id,char *name) +{ +struct udevice *dev; +struct uclass *uc; +int ret; + +if (uclass_id <0 || uclass_id >=UCLASS_COUNT ) { +error ("Bad uclass id.\n" ); +return NULL ; + } + + ret =uclass_get (uclass_id, &uc); +if (ret) { +error ("PMIC uclass: %d not initialized!" , uclass_id); +return NULL ; + } + + uclass_foreach_dev(dev, uc) { +if (!dev) +continue ; + +if (!strncmp (name, dev->name,strlen (name))) { + ret =device_probe (dev); +if (ret) +error ("Dev: %s probe failed" , dev->name); +return dev; + } + } + +return NULL ;
Quoted 9 lines
drivers/power/pmic-uclass.c line 203
Quoted 3 lines
drivers/power/pmic-uclass.c new file +3
-0+} + +int pmic_init_dm (void )I don't understand why you need this function at all. Driver model should find the pmics automatically. Is it because we don't have an i2c uclass? In that case I think it would be better to limit this hack to I2C. For SPI it should work correctly without this function.
Currently, it shouldn't and yes - it isn't because of the I2C uclass missing. So no one check the I2C nodes - and its child subnodes. Actually, this can be easy fixed - just don't add the "pmic" alias to the dts. But I will also change fix the code.
And by the way - is there any check in the code, which protects for the device bind more than once?
Quoted 442 lines
Quoted 391 lines
drivers/power/pmic-uclass.c new file +52
-0+{ +const void *blob = gd->fdt_blob; +const struct fdt_property *prop; +struct udevice *dev =NULL ; +const char *path; +const char *alias; +int alias_node, node, offset, ret =0 ; +int alias_len; +int len; + + alias ="pmic" ; + alias_len =strlen (alias); + + alias_node =fdt_path_offset (blob,"/aliases" ); + offset =fdt_first_property_offset (blob, alias_node); + +if (offset <0 ) { +error ("Alias node not found." ); +return -ENODEV ; + } + + offset =fdt_first_property_offset (blob, alias_node); +for (; offset >0 ; offset =fdt_next_property_offset (blob, offset)) { + prop =fdt_get_property_by_offset (blob, offset, &len); +if (!len) +continue ; + + path =fdt_string (blob,fdt32_to_cpu (prop->nameoff)); + +if (!strncmp (alias, path, alias_len)) + node =fdt_path_offset (blob, prop->data); +else + node =0 ; + +if (node <=0 ) +continue ; + + ret =lists_bind_fdt (gd->dm_root, blob, node, &dev); +if (ret <0 ) +continue ; + +if (device_probe (dev)) +error ("Device: %s, probe error" , dev->name); + } + +return 0 ; +} + +UCLASS_DRIVER (pmic) = { + .id =UCLASS_PMIC , + .name ="pmic" , +};drivers/power/pmic_i2c.c new file +136
-0@@ -0,0 +1,136 @@ +/* +* Copyright (C) 2014 Samsung Electronics +* Przemyslaw Marczak <[email protected]> +* +* Copyright (C) 2011 Samsung Electronics +* Lukasz Majewski <[email protected]> +* +* (C) Copyright 2010 +* Stefano Babic, DENX Software Engineering, sbabic at denx.de +* +* (C) Copyright 2008-2009 Freescale Semiconductor, Inc. +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#include <common.h> +#include <linux/types.h> +#include <power/pmic.h> +#include <errno.h> +#include <dm.h> +#include <i2c.h> + +int pmic_i2c_reg_write (struct udevice *dev,unsigned reg,unsigned val) +{ +struct pmic_platdata *p; +unsigned char buf[4 ] = {0 }; + +if (!dev) +return -ENODEV ; + + p = dev->platdata; + +if (pmic_check_reg (p, reg)) +return -EINVAL ; + +I2C_SET_BUS (p->bus); + +switch (pmic_i2c_tx_num) { +case 3 : +if (p->byte_order ==PMIC_SENSOR_BYTE_ORDER_BIG ) { + buf[2 ] = (cpu_to_le32 (val) >>16 ) &0xff ; + buf[1 ] = (cpu_to_le32 (val) >>8 ) &0xff ; + buf[0 ] =cpu_to_le32 (val) &0xff ; + }else { + buf[0 ] = (cpu_to_le32 (val) >>16 ) &0xff ; + buf[1 ] = (cpu_to_le32 (val) >>8 ) &0xff ; + buf[2 ] =cpu_to_le32 (val) &0xff ; + } +break ; +case 2 : +if (p->byte_order ==PMIC_SENSOR_BYTE_ORDER_BIG ) { + buf[1 ] = (cpu_to_le32 (val) >>8 ) &0xff ; + buf[0 ] =cpu_to_le32 (val) &0xff ; + }else { + buf[0 ] = (cpu_to_le32 (val) >>8 ) &0xff ; + buf[1 ] =cpu_to_le32 (val) &0xff ; + } +break ; +case 1 : + buf[0 ] =cpu_to_le32 (val) &0xff ; +break ; +default : +printf ("%s: invalid tx_num: %d" , __func__, pmic_i2c_tx_num); +return -1 ; + } + +if (i2c_write (pmic_i2c_addr, reg,1 , buf, pmic_i2c_tx_num)) +return -1 ; + +return 0 ; +} + +int pmic_i2c_reg_read (struct udevice *dev,unsigned reg,unsigned *val) +{ +struct pmic_platdata *p; +unsigned char buf[4 ] = {0 }; +u32 ret_val =0 ; + +if (!dev) +return -ENODEV ; + + p = dev->platdata; + +if (pmic_check_reg (p, reg)) +return -EINVAL ; + +I2C_SET_BUS (p->bus); + +if (i2c_read (pmic_i2c_addr, reg,1 , buf, pmic_i2c_tx_num)) +return -1 ; + +switch (pmic_i2c_tx_num) { +case 3 : +if (p->byte_order ==PMIC_SENSOR_BYTE_ORDER_BIG ) + ret_val =le32_to_cpu (buf[2 ] <<16 + | buf[1 ] <<8 | buf[0 ]); +else + ret_val =le32_to_cpu (buf[0 ] <<16 | + buf[1 ] <<8 | buf[2 ]); +break ; +case 2 : +if (p->byte_order ==PMIC_SENSOR_BYTE_ORDER_BIG ) + ret_val =le32_to_cpu (buf[1 ] <<8 | buf[0 ]); +else + ret_val =le32_to_cpu (buf[0 ] <<8 | buf[1 ]); +break ; +case 1 : + ret_val =le32_to_cpu (buf[0 ]); +break ; +default : +printf ("%s: invalid tx_num: %d" , __func__, pmic_i2c_tx_num); +return -1 ; + } +memcpy (val, &ret_val,sizeof (ret_val)); + +return 0 ; +} + +int pmic_i2c_probe (struct udevice *dev) +{ +struct pmic_platdata *p; + +if (!dev) +return -ENODEV ; + + p = dev->platdata; + +i2c_set_bus_num (p->bus); +debug ("Bus: %d PMIC:%s probed!\n" , p->bus, dev->name); +if (i2c_probe (pmic_i2c_addr)) { +printf ("Can't find PMIC:%s\n" , dev->name); +return -1 ; + } + +return 0 ; +}drivers/power/pmic_spi.c new file +137
-0@@ -0,0 +1,137 @@ +/* +* Copyright (C) 2014 Samsung Electronics +* Przemyslaw Marczak <[email protected]> +* +* Copyright (C) 2011 Samsung Electronics +* Lukasz Majewski <[email protected]> +* +* (C) Copyright 2010 +* Stefano Babic, DENX Software Engineering, sbabic at denx.de +* +* (C) Copyright 2008-2009 Freescale Semiconductor, Inc. +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#include <common.h> +#include <linux/types.h> +#include <power/pmic.h> +#include <errno.h> +#include <dm.h> +#include <spi.h> + +static struct spi_slave *slave; + +void pmic_spi_free (struct spi_slave *slave) +{ +if (slave) +spi_free_slave (slave); +} + +struct spi_slave *pmic_spi_probe (struct udevice *dev) +{ +struct pmic_platdata *p; + +if (!dev) +return NULL ; + + p = dev->platdata; + +if (pmic_check_reg (p, reg)) +return NULL ; + +return spi_setup_slave (p->bus, + p->hw.spi.cs, + p->hw.spi.clk, + p->hw.spi.mode); +} + +static int pmic_spi_reg (struct udevice *dev,unsigned reg,unsigned *val, +int write) +{ +struct pmic_platdata *p; +u32 pmic_tx, pmic_rx; +u32 tmp; + +if (!dev) +return -EINVAL ; + + p = dev->platdata; + +if (pmic_check_reg (p, reg)) +return -EFAULT ; + +if (!slave) { + slave =pmic_spi_probe (p); + +if (!slave) +return -ENODEV ; + } + +if (pmic_check_reg (p, reg)) +return -EFAULT ; + +if (spi_claim_bus (slave)) +return -EIO ; + + pmic_tx = p->hw.spi.prepare_tx (reg, val, write); + + tmp =cpu_to_be32 (pmic_tx); + +if (spi_xfer (slave, pmic_spi_bitlen, &tmp, &pmic_rx, + pmic_spi_flags)) { +spi_release_bus (slave); +return -EIO ; + } + +if (write) { + pmic_tx = p->hw.spi.prepare_tx (reg, val,0 ); + tmp =cpu_to_be32 (pmic_tx); +if (spi_xfer (slave, pmic_spi_bitlen, &tmp, &pmic_rx, + pmic_spi_flags)) { +spi_release_bus (slave); +return -EIO ; + } + } + +spi_release_bus (slave); + *val =cpu_to_be32 (pmic_rx); + +return 0 ; +} + +int pmic_spi_reg_write (struct udevice *dev,unsigned reg,unsigned val) +{ +struct pmic_platdata *p; + +if (!dev) +return -EINVAL ; + + p = dev->platdata; + +if (pmic_check_reg (p, reg)) +return -EFAULT ; + +if (pmic_spi_reg (p, reg, &val,1 )) +return -1 ; + +return 0 ; +} + +int pmic_spi_reg_read (struct udevice *dev,unsigned reg,unsigned *val) +{ +struct pmic_platdata *p; + +if (!dev) +return -EINVAL ; + + p = dev->platdata; + +if (pmic_check_reg (p, reg)) +return -EFAULT ; + +if (pmic_spi_reg (p, reg, val,0 )) +return -1 ; + +return 0 ; +}include/dm/uclass-id.h +3
-0@@ -29,6 +29,9 @@ enum uclass_id {UCLASS_SPI_FLASH ,/* SPI flash */ UCLASS_CROS_EC ,/* Chrome OS EC */ +/* PMIC uclass and PMIC related uclasses */ +UCLASS_PMIC , +UCLASS_COUNT , UCLASS_INVALID = -1, };include/power/pmic.h +17
-0@@ -1,4 +1,7 @@/* +* Copyright (C) 2014 Samsung Electronics +* Przemyslaw Marczak <[email protected]> +* * Copyright (C) 2011-2012 Samsung Electronics * Lukasz Majewski <[email protected]> * @@ -8,9 +11,12 @@#ifndef __CORE_PMIC_H_#define __CORE_PMIC_H_ +#include <dm.h> #include <linux/list.h> +#include <spi.h> #include <i2c.h> #include <power/power_chrg.h> +#include <power/regulator.h> enum {PMIC_I2C ,PMIC_SPI ,PMIC_NONE };enum {I2C_PMIC ,I2C_NUM , };@@ -78,6 +84,63 @@ struct pmic {struct list_head list; }; +#ifdef CONFIG_DM_PMIC +/* struct pmic_platdata - a standard descriptor for pmic device, which holds +* an informations about interface. It is common for all pmic devices. +* +* Note: +* Interface fields are the same as in: struct pmic. +* Note: struct pmic will be removed in the future after drivers migration +* +* @bus - a physical bus on which device is connected +* @interface - an interface type, one of enum: PMIC_I2C, PMIC_SPI, PMIC_NONE +* @byte_order - one of enum: PMIC_SENSOR_BYTE_ORDER*_LITTLE/_BIG include/power/pmic.h struct pmic { · line 107
Quoted 10 lines
include/power/pmic.h +10
-0+* @regs_num - number of device registers +* @hw - one of union structure: p_i2c or p_spi +* based on @interface field +*/ +struct pmic_platdata { +int bus; +int interface; +int byte_order; +int regs_num; +union hw hw;If we have a 'register cache' uclass (later, once i2c is done) then this could just be a device.
Quoted 37 lines
include/power/pmic.h +36
-0+}; + +/* enum pmic_op_type - used for various pmic devices operation calls, +* for decrease a number of functions 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 , +}; + +/* drivers/power/pmic-uclass.c */ +int power_init_dm (void ); +struct udevice *pmic_get_by_name (int uclass_id,char *name); +struct udevice *pmic_get_by_interface (int uclass_id,int bus,int addr_cs); +const char *pmic_if_str (int interface); +int pmic_check_reg (struct pmic_platdata *p,unsigned reg); +int pmic_reg_write (struct udevice *dev,unsigned reg,unsigned val); +int pmic_reg_read (struct udevice *dev,unsigned reg,unsigned *val); +int pmic_probe (struct udevice *dev,struct spi_slave *spi_slave); + +/* drivers/power/pmic_i2c.c */ +int pmic_i2c_reg_write (struct udevice *dev,unsigned reg,unsigned val); +int pmic_i2c_reg_read (struct udevice *dev,unsigned reg,unsigned *val); +int pmic_i2c_probe (struct udevice *dev); + +/* drivers/power/pmic_spi.c */ +int pmic_spi_reg_write (struct udevice *dev,unsigned reg,unsigned val); +int pmic_spi_reg_read (struct udevice *dev,unsigned reg,unsigned *val); +struct spi_slave *pmic_spi_probe (struct udevice *dev); +#endif /* CONFIG_DM_PMIC */ + +#ifdef CONFIG_POWER int pmic_init (unsigned char bus);
Quoted 9 lines
include/power/pmic.h int pmic_probe(struct pmic *p); · line 153
Quoted 6 lines
include/power/pmic.h +0
-0int power_init_board (void );int pmic_dialog_init (unsigned char bus);@@ -88,6 +151,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);These should have comments.
Ok, I will add it.
Quoted 11 lines
Quoted 7 lines
include/power/pmic.h +1
-1+#endif #define pmic_i2c_addr (p->hw.i2c.addr)#define pmic_i2c_tx_num (p->hw.i2c.tx_num) --1.9.1
Regards,
Simon
Thank you for the fast review :)
Best Regards,
Signature · 4 lines
Przemyslaw Marczak Samsung R&D Institute Poland Samsung Electronics p.marczak at samsung.com
PATCH 4/19 dm: pmic: add implementation of driver model pmic uclass
Hi,
Quoted 129 lines · Przemyslaw Marczak
Hello Simon,
Quoted 121 lines · Simon Glass
Hi,
Quoted 100 lines · Przemyslaw Marczak
This is an introduction to driver-model multi class PMIC support. It starts with
UCLASS_PMIC- a common PMIC class type for I/O, which doesn't need to implement any specific operations and features beside the platform data, which is the 'structpmic_platdata' defined in file:
- 'include/power/pmic.h'New files:
-pmic-uclass.c- provides a common code forUCLASS_PMICdrivers
-pmic_i2c.c- provides dm interface for i2c pmic drivers
-pmic_spi.c- provides dm interface for spi pmic driversThose files are based on a current PMIC framework files and code. The new files are introduced to keep code readability and allow to make an easy drivers migration. The old pmic framework is still kept and full independent.
Changes:
- new uclass-id:UCLASS_PMIC,
- new configs:CONFIG_DM_PMIC;CONFIG_DM_PMIC_SPI;CONFIG_DM_PMIC_I2C,New pmic api is documented in: doc/README.power-framework-dm
Signed-off-by Przemyslaw Marczak <[email protected]>--- drivers/power/Makefile | 3 + drivers/power/pmic-uclass.c | 255 ++++++++++++++++++++++++++++++++++++++++++++ drivers/power/pmic_i2c.c | 136 +++++++++++++++++++++++ drivers/power/pmic_spi.c | 137 ++++++++++++++++++++++++ include/dm/uclass-id.h | 3 + include/power/pmic.h | 64 +++++++++++ 6 files changed, 598 insertions(+)create mode 100644
drivers/power/pmic-uclass.c
create mode 100644drivers/power/pmic_i2c.c
create mode 100644drivers/power/pmic_spi.cdrivers/power/Makefile +3
-0@@ -19,3 +19,6 @@ 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_SPI) += pmic_spi.o +obj-$(CONFIG_DM_PMIC_I2C) += pmic_i2c.o +obj-$(CONFIG_DM_PMIC) += pmic-uclass.odrivers/power/pmic-uclass.c new file +27
-0@@ -0,0 +1,255 @@ +/* +* Copyright (C) 2014 Samsung Electronics +* Przemyslaw Marczak <[email protected]> +* +* SPDX-License-Identifier: GPL-2.0+ +*/ +#include <common.h> +#include <linux/types.h> +#include <fdtdec.h> +#include <power/pmic.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> + +DECLARE_GLOBAL_DATA_PTR ; + +int pmic_check_reg (struct pmic_platdata *p,unsigned reg) +{ +if (!p) +return -ENODEV ; + +if (reg >= p->regs_num) { + error("<reg num> = %d is invalid. Should be less than%d",
drivers/power/pmic-uclass.c new file +18
-0+ reg, p->regs_num); +return -EINVAL ; + } + +return 0 ; +} + +int pmic_reg_write (struct udevice *dev,unsigned reg,unsigned val) +{ +struct pmic_platdata *p; + + p =dev_get_platdata (dev); +if (!p) +return -EPERM ; + +switch (p->interface) { +case PMIC_I2C : +#ifdef CONFIG_DM_PMIC_I2C drivers/power/pmic-uclass.c line 55
Quoted 10 lines
drivers/power/pmic-uclass.c new file +10
-0+return pmic_i2c_reg_write (dev, reg, val); +#else +return -ENOSYS ; +#endif +case PMIC_SPI : +#ifdef CONFIG_DM_PMIC_SPI +return pmic_spi_reg_write (dev, reg, val); +#else +return -ENOSYS ; +#endif Perhaps one day we should add another uclass which is some sort of register cache. It could be implemented by I2C and SPI drivers (or better perhaps the I2C and SPI uclasses could provide a register cache uclass device for their main when requested).
Quoted 3 lines
For now this seems fine though. I think the 'return
-ENOSYS' can just go at the end of the function and appear once.
Quoted 8 lines
Why do we need the registers cache?
This maybe is good for a many read operations at a time in the system, but actually I think, that it is not required for the bootloader purposes.If we write some data - sequential, then we probably would like to check it in the same time, e.g. update some range of I2C registers.
I don't know the Chromebook design, but how it could be useful for you?
We don't need a register cache - I was just thinking of that from the kernel. But it feels like an interface like:
int reg_read(int reg, uint32_t *value)
int reg_write(int reg, uint32_t value)
int reg_write_range(int reg_start, int reg_count, uint32_t value[])
might be useful - it could be implemented for both I2C and SPI.
Quoted 72 lines
Quoted 63 lines
Quoted 63 lines
drivers/power/pmic-uclass.c new file +61
-0+default : +return -ENODEV ; + } +} + +int pmic_reg_read (struct udevice *dev,unsigned reg,unsigned *val) +{ +struct pmic_platdata *p; + + p =dev_get_platdata (dev); +if (!p) +return -EPERM ; + +switch (p->interface) { +case PMIC_I2C : +#ifdef CONFIG_DM_PMIC_I2C +return pmic_i2c_reg_read (dev, reg, val); +#else +return -ENOSYS ; +#endif +case PMIC_SPI : +#ifdef CONFIG_DM_PMIC_SPI +return pmic_spi_reg_read (dev, reg, val); +#else +return -ENOSYS ; +#endif +default : +return -ENODEV ; + } +} + +int pmic_probe (struct udevice *dev,struct spi_slave *spi_slave) +{ +struct pmic_platdata *p; + + p =dev_get_platdata (dev); +if (!p) +return -EPERM ; + +switch (p->interface) { +case PMIC_I2C : +#ifdef CONFIG_DM_PMIC_I2C +return pmic_i2c_probe (dev); +#else +return -ENOSYS ; +#endif +case PMIC_SPI : +if (!spi_slave) +return -EINVAL ; +#ifdef CONFIG_DM_PMIC_SPI + spi_slave =pmic_spi_probe (dev); +if (!spi_slave) +return -EIO ; + +return 0 ; +#else +return -ENOSYS ; +#endif +default : +return -ENODEV ; + }Quoted 9 lines
Quoted 4 lines
drivers/power/pmic-uclass.c new file +3
-0+} + +struct udevice *pmic_get_by_interface(int uclass_id, int bus, int
addr_cs)This is an interesting function! Again we can probably improve things when we have an i2c uclass.
Quoted 3 lines
Thanks! But even if we have i2c uclass, then we also should know how to recognize each device, e.g. in the board code. So the interface and address will probably no change.
I'm thinking that one day you could do something like:
// Find the regmap associated with the devicereg_dev = device_get_child(UCLASS_REGMAP, dev);
// Call the regmap uclass to access registers whether it is I2C or SPI regmap_write(reg_dev, value);
Quoted 93 lines
Quoted 84 lines
Quoted 84 lines
drivers/power/pmic-uclass.c new file +82
-0+{ +struct pmic_platdata *pl; +struct udevice *dev; +struct uclass *uc; +int ret; + +if (uclass_id <0 || uclass_id >=UCLASS_COUNT ) { +error ("Bad uclass id.\n" ); +return NULL ; + } + + ret =uclass_get (uclass_id, &uc); +if (ret) { +error ("PMIC uclass: %d not initialized!\n" , uclass_id); +return NULL ; + } + + uclass_foreach_dev(dev, uc) { +if (!dev || !dev->platdata) +continue ; + + pl =dev_get_platdata (dev); + +if (pl->bus != bus) +continue ; + +switch (pl->interface) { +case PMIC_I2C : +if (addr_cs != pl->hw.i2c.addr) +continue ; +break ; +case PMIC_SPI : +if (addr_cs != pl->hw.spi.cs) +continue ; +break ; +default : +error ("Unsupported interface of: %s" , dev->name); +return NULL ; + } + + ret =device_probe (dev); +if (ret) { +error ("Dev: %s probe failed" , dev->name); +return NULL ; + } +return dev; + } + +return NULL ; +} + +struct udevice *pmic_get_by_name (int uclass_id,char *name) +{ +struct udevice *dev; +struct uclass *uc; +int ret; + +if (uclass_id <0 || uclass_id >=UCLASS_COUNT ) { +error ("Bad uclass id.\n" ); +return NULL ; + } + + ret =uclass_get (uclass_id, &uc); +if (ret) { +error ("PMIC uclass: %d not initialized!" , uclass_id); +return NULL ; + } + + uclass_foreach_dev(dev, uc) { +if (!dev) +continue ; + +if (!strncmp (name, dev->name,strlen (name))) { + ret =device_probe (dev); +if (ret) +error ("Dev: %s probe failed" , dev->name); +return dev; + } + } + +return NULL ; +}Quoted 9 lines
drivers/power/pmic-uclass.c
Quoted 2 lines
drivers/power/pmic-uclass.c new file +2
-0+ +int pmic_init_dm (void )I don't understand why you need this function at all. Driver model should find the pmics automatically. Is it because we don't have an i2c uclass? In that case I think it would be better to limit this hack to I2C. For SPI it should work correctly without this function.
Quoted 7 lines
Currently, it shouldn't and yes - it isn't because of the I2C uclass missing. So no one check the I2C nodes - and its child subnodes. Actually, this can be easy fixed - just don't add the "pmic" alias to the dts. But I will also change fix the code.
And by the way - is there any check in the code, which protects for the device bind more than once?
No there is no such check at present.
Quoted 473 lines
Quoted 454 lines
Quoted 403 lines
drivers/power/pmic-uclass.c new file +23
-0+{ + const void *blob = gd->fdt_blob; + const struct fdt_property *prop; + struct udevice *dev = NULL; + const char *path; + const char *alias; + int alias_node, node, offset, ret = 0; + int alias_len; + int len; + + alias = "pmic"; + alias_len = strlen(alias); + + alias_node = fdt_path_offset(blob, "/aliases"); + offset = fdt_first_property_offset(blob, alias_node); + + if (offset < 0) { + error("Alias node not found."); + return -ENODEV; + } + + offset = fdt_first_property_offset(blob, alias_node); + for (; offset > 0; offset = fdt_next_property_offset(blob,offset)) {
drivers/power/pmic-uclass.c new file +29
-0+ prop =fdt_get_property_by_offset (blob, offset, &len); +if (!len) +continue ; + + path =fdt_string (blob,fdt32_to_cpu (prop->nameoff)); + +if (!strncmp (alias, path, alias_len)) + node =fdt_path_offset (blob, prop->data); +else + node =0 ; + +if (node <=0 ) +continue ; + + ret =lists_bind_fdt (gd->dm_root, blob, node, &dev); +if (ret <0 ) +continue ; + +if (device_probe (dev)) +error ("Device: %s, probe error" , dev->name); + } + +return 0 ; +} + +UCLASS_DRIVER (pmic) = { + .id =UCLASS_PMIC , + .name ="pmic" , +};drivers/power/pmic_i2c.c new file +63
-0@@ -0,0 +1,136 @@ +/* +* Copyright (C) 2014 Samsung Electronics +* Przemyslaw Marczak <[email protected]> +* +* Copyright (C) 2011 Samsung Electronics +* Lukasz Majewski <[email protected]> +* +* (C) Copyright 2010 +* Stefano Babic, DENX Software Engineering, sbabic at denx.de +* +* (C) Copyright 2008-2009 Freescale Semiconductor, Inc. +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#include <common.h> +#include <linux/types.h> +#include <power/pmic.h> +#include <errno.h> +#include <dm.h> +#include <i2c.h> + +int pmic_i2c_reg_write (struct udevice *dev,unsigned reg,unsigned val) +{ +struct pmic_platdata *p; +unsigned char buf[4 ] = {0 }; + +if (!dev) +return -ENODEV ; + + p = dev->platdata; + +if (pmic_check_reg (p, reg)) +return -EINVAL ; + +I2C_SET_BUS (p->bus); + +switch (pmic_i2c_tx_num) { +case 3 : +if (p->byte_order ==PMIC_SENSOR_BYTE_ORDER_BIG ) { + buf[2 ] = (cpu_to_le32 (val) >>16 ) &0xff ; + buf[1 ] = (cpu_to_le32 (val) >>8 ) &0xff ; + buf[0 ] =cpu_to_le32 (val) &0xff ; + }else { + buf[0 ] = (cpu_to_le32 (val) >>16 ) &0xff ; + buf[1 ] = (cpu_to_le32 (val) >>8 ) &0xff ; + buf[2 ] =cpu_to_le32 (val) &0xff ; + } +break ; +case 2 : +if (p->byte_order ==PMIC_SENSOR_BYTE_ORDER_BIG ) { + buf[1 ] = (cpu_to_le32 (val) >>8 ) &0xff ; + buf[0 ] =cpu_to_le32 (val) &0xff ; + }else { + buf[0 ] = (cpu_to_le32 (val) >>8 ) &0xff ; + buf[1 ] =cpu_to_le32 (val) &0xff ; + } +break ; +case 1 : + buf[0 ] =cpu_to_le32 (val) &0xff ; +break ; +default : + printf("%s: invalid tx_num: %d", __func__,
pmic_i2c_tx_num);drivers/power/pmic_i2c.c new file +48
-0+return -1 ; + } + +if (i2c_write (pmic_i2c_addr, reg,1 , buf, pmic_i2c_tx_num)) +return -1 ; + +return 0 ; +} + +int pmic_i2c_reg_read (struct udevice *dev,unsigned reg,unsigned *val) +{ +struct pmic_platdata *p; +unsigned char buf[4 ] = {0 }; +u32 ret_val =0 ; + +if (!dev) +return -ENODEV ; + + p = dev->platdata; + +if (pmic_check_reg (p, reg)) +return -EINVAL ; + +I2C_SET_BUS (p->bus); + +if (i2c_read (pmic_i2c_addr, reg,1 , buf, pmic_i2c_tx_num)) +return -1 ; + +switch (pmic_i2c_tx_num) { +case 3 : +if (p->byte_order ==PMIC_SENSOR_BYTE_ORDER_BIG ) + ret_val =le32_to_cpu (buf[2 ] <<16 + | buf[1 ] <<8 | buf[0 ]); +else + ret_val =le32_to_cpu (buf[0 ] <<16 | + buf[1 ] <<8 | buf[2 ]); +break ; +case 2 : +if (p->byte_order ==PMIC_SENSOR_BYTE_ORDER_BIG ) + ret_val =le32_to_cpu (buf[1 ] <<8 | buf[0 ]); +else + ret_val =le32_to_cpu (buf[0 ] <<8 | buf[1 ]); +break ; +case 1 : + ret_val =le32_to_cpu (buf[0 ]); +break ; +default : + printf("%s: invalid tx_num: %d", __func__,
pmic_i2c_tx_num);drivers/power/pmic_i2c.c new file +25
-0+return -1 ; + } +memcpy (val, &ret_val,sizeof (ret_val)); + +return 0 ; +} + +int pmic_i2c_probe (struct udevice *dev) +{ +struct pmic_platdata *p; + +if (!dev) +return -ENODEV ; + + p = dev->platdata; + +i2c_set_bus_num (p->bus); +debug ("Bus: %d PMIC:%s probed!\n" , p->bus, dev->name); +if (i2c_probe (pmic_i2c_addr)) { +printf ("Can't find PMIC:%s\n" , dev->name); +return -1 ; + } + +return 0 ; +}drivers/power/pmic_spi.c new file +49
-0@@ -0,0 +1,137 @@ +/* +* Copyright (C) 2014 Samsung Electronics +* Przemyslaw Marczak <[email protected]> +* +* Copyright (C) 2011 Samsung Electronics +* Lukasz Majewski <[email protected]> +* +* (C) Copyright 2010 +* Stefano Babic, DENX Software Engineering, sbabic at denx.de +* +* (C) Copyright 2008-2009 Freescale Semiconductor, Inc. +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#include <common.h> +#include <linux/types.h> +#include <power/pmic.h> +#include <errno.h> +#include <dm.h> +#include <spi.h> + +static struct spi_slave *slave; + +void pmic_spi_free (struct spi_slave *slave) +{ +if (slave) +spi_free_slave (slave); +} + +struct spi_slave *pmic_spi_probe (struct udevice *dev) +{ +struct pmic_platdata *p; + +if (!dev) +return NULL ; + + p = dev->platdata; + +if (pmic_check_reg (p, reg)) +return NULL ; + +return spi_setup_slave (p->bus, + p->hw.spi.cs, + p->hw.spi.clk, + p->hw.spi.mode); +} + +static int pmic_spi_reg(struct udevice *dev, unsigned reg, unsigned*val,
drivers/power/pmic_spi.c new file +88
-0+ int write) +{ +struct pmic_platdata *p; +u32 pmic_tx, pmic_rx; +u32 tmp; + +if (!dev) +return -EINVAL ; + + p = dev->platdata; + +if (pmic_check_reg (p, reg)) +return -EFAULT ; + +if (!slave) { + slave =pmic_spi_probe (p); + +if (!slave) +return -ENODEV ; + } + +if (pmic_check_reg (p, reg)) +return -EFAULT ; + +if (spi_claim_bus (slave)) +return -EIO ; + + pmic_tx = p->hw.spi.prepare_tx (reg, val, write); + + tmp =cpu_to_be32 (pmic_tx); + +if (spi_xfer (slave, pmic_spi_bitlen, &tmp, &pmic_rx, + pmic_spi_flags)) { +spi_release_bus (slave); +return -EIO ; + } + +if (write) { + pmic_tx = p->hw.spi.prepare_tx (reg, val,0 ); + tmp =cpu_to_be32 (pmic_tx); +if (spi_xfer (slave, pmic_spi_bitlen, &tmp, &pmic_rx, + pmic_spi_flags)) { +spi_release_bus (slave); +return -EIO ; + } + } + +spi_release_bus (slave); + *val =cpu_to_be32 (pmic_rx); + +return 0 ; +} + +int pmic_spi_reg_write (struct udevice *dev,unsigned reg,unsigned val) +{ +struct pmic_platdata *p; + +if (!dev) +return -EINVAL ; + + p = dev->platdata; + +if (pmic_check_reg (p, reg)) +return -EFAULT ; + +if (pmic_spi_reg (p, reg, &val,1 )) +return -1 ; + +return 0 ; +} + +int pmic_spi_reg_read (struct udevice *dev,unsigned reg,unsigned *val) +{ +struct pmic_platdata *p; + +if (!dev) +return -EINVAL ; + + p = dev->platdata; + +if (pmic_check_reg (p, reg)) +return -EFAULT ; + +if (pmic_spi_reg (p, reg, val,0 )) +return -1 ; + +return 0 ; +}include/dm/uclass-id.h +3
-0@@ -29,6 +29,9 @@ enum uclass_id {UCLASS_SPI_FLASH ,/* SPI flash */ UCLASS_CROS_EC ,/* Chrome OS EC */ +/* PMIC uclass and PMIC related uclasses */ +UCLASS_PMIC , +UCLASS_COUNT , UCLASS_INVALID = -1, };include/power/pmic.h +8
-0@@ -1,4 +1,7 @@/* +* Copyright (C) 2014 Samsung Electronics +* Przemyslaw Marczak <[email protected]> +* * Copyright (C) 2011-2012 Samsung Electronics * Lukasz Majewski <[email protected]> * @@ -8,9 +11,12 @@#ifndef __CORE_PMIC_H_#define __CORE_PMIC_H_ +#include <dm.h> #include <linux/list.h> +#include <spi.h> #include <i2c.h> #include <power/power_chrg.h> +#include <power/regulator.h> enum {PMIC_I2C ,PMIC_SPI ,PMIC_NONE };enum {I2C_PMIC ,I2C_NUM , };@@ -78,6 +84,63 @@ struct pmic {struct list_head list; }; +#ifdef CONFIG_DM_PMIC +/* struct pmic_platdata - a standard descriptor for pmic device, which holds
+ * an informations about interface. It is common for all pmic devices.
+ *
+ * Note:
+ * Interface fields are the same as in: struct pmic.
+ * Note: struct pmic will be removed in the future after drivers migration
+ *
+ * @bus - a physical bus on which device is connected
+ * @interface - an interface type, one of enum:PMIC_I2C,PMIC_SPI,PMIC_NONE
+ * @byte_order - one of enum: PMIC_SENSOR_BYTE_ORDER*_LITTLE/_BIG
+ * @regs_num - number of device registers
+ * @hw - one of union structure:p_i2corp_spi
+ * based on @interface fieldinclude/power/pmic.h struct pmic { · line 107
Quoted 7 lines
include/power/pmic.h +7
-0+*/ +struct pmic_platdata { +int bus; +int interface; +int byte_order; +int regs_num; +union hw hw;If we have a 'register cache' uclass (later, once i2c is done) then this could just be a device.
Quoted 39 lines
include/power/pmic.h +18
-0+}; + +/* enum pmic_op_type - used for various pmic devices operation calls, +* for decrease a number of functions 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 , +}; + +/* drivers/power/pmic-uclass.c */ +int power_init_dm (void ); +struct udevice *pmic_get_by_name (int uclass_id,char *name); +struct udevice *pmic_get_by_interface(int uclass_id, int bus, int
addr_cs);include/power/pmic.h +18
-0+const char *pmic_if_str (int interface); +int pmic_check_reg (struct pmic_platdata *p,unsigned reg); +int pmic_reg_write (struct udevice *dev,unsigned reg,unsigned val); +int pmic_reg_read (struct udevice *dev,unsigned reg,unsigned *val); +int pmic_probe (struct udevice *dev,struct spi_slave *spi_slave); + +/* drivers/power/pmic_i2c.c */ +int pmic_i2c_reg_write (struct udevice *dev,unsigned reg,unsigned val); +int pmic_i2c_reg_read (struct udevice *dev,unsigned reg,unsigned *val); +int pmic_i2c_probe (struct udevice *dev); + +/* drivers/power/pmic_spi.c */ +int pmic_spi_reg_write (struct udevice *dev,unsigned reg,unsigned val); +int pmic_spi_reg_read (struct udevice *dev,unsigned reg,unsigned *val); +struct spi_slave *pmic_spi_probe (struct udevice *dev); +#endif /* CONFIG_DM_PMIC */ + +#ifdef CONFIG_POWER int pmic_init (unsigned char bus);int power_init_board (void );Quoted 9 lines
include/power/pmic.h int pmic_probe(struct pmic *p); · line 153
Quoted 5 lines
int pmic_dialog_init(unsigned char bus);include/power/pmic.h +0
-0@@ -88,6 +151,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);These should have comments.
Ok, I will add it.
Quoted 8 lines
Quoted 7 lines
include/power/pmic.h +1
-1+#endif #define pmic_i2c_addr (p->hw.i2c.addr)#define pmic_i2c_tx_num (p->hw.i2c.tx_num) --1.9.1
Quoted 4 lines
Quoted 3 lines
Regards,
SimonThank you for the fast review :)
Very interested to see this development.
Regards,
Simon
PATCH 4/19 dm: pmic: add implementation of driver model pmic uclass
Hello Simon,
I missed some of your comments.
Quoted 141 lines · Simon Glass
Hi,
Quoted 129 lines · Przemyslaw Marczak
Hello Simon,
Quoted 121 lines · Simon Glass
Hi,
Quoted 100 lines · Przemyslaw Marczak
This is an introduction to driver-model multi class PMIC support. It starts with
UCLASS_PMIC- a common PMIC class type for I/O, which doesn't need to implement any specific operations and features beside the platform data, which is the 'structpmic_platdata' defined in file:
- 'include/power/pmic.h'New files:
-pmic-uclass.c- provides a common code forUCLASS_PMICdrivers
-pmic_i2c.c- provides dm interface for i2c pmic drivers
-pmic_spi.c- provides dm interface for spi pmic driversThose files are based on a current PMIC framework files and code. The new files are introduced to keep code readability and allow to make an easy drivers migration. The old pmic framework is still kept and full independent.
Changes:
- new uclass-id:UCLASS_PMIC,
- new configs:CONFIG_DM_PMIC;CONFIG_DM_PMIC_SPI;CONFIG_DM_PMIC_I2C,New pmic api is documented in: doc/README.power-framework-dm
Signed-off-by Przemyslaw Marczak <[email protected]>--- drivers/power/Makefile | 3 + drivers/power/pmic-uclass.c | 255 ++++++++++++++++++++++++++++++++++++++++++++ drivers/power/pmic_i2c.c | 136 +++++++++++++++++++++++ drivers/power/pmic_spi.c | 137 ++++++++++++++++++++++++ include/dm/uclass-id.h | 3 + include/power/pmic.h | 64 +++++++++++ 6 files changed, 598 insertions(+)create mode 100644
drivers/power/pmic-uclass.c
create mode 100644drivers/power/pmic_i2c.c
create mode 100644drivers/power/pmic_spi.cdrivers/power/Makefile +3
-0@@ -19,3 +19,6 @@ 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_SPI) += pmic_spi.o +obj-$(CONFIG_DM_PMIC_I2C) += pmic_i2c.o +obj-$(CONFIG_DM_PMIC) += pmic-uclass.odrivers/power/pmic-uclass.c new file +27
-0@@ -0,0 +1,255 @@ +/* +* Copyright (C) 2014 Samsung Electronics +* Przemyslaw Marczak <[email protected]> +* +* SPDX-License-Identifier: GPL-2.0+ +*/ +#include <common.h> +#include <linux/types.h> +#include <fdtdec.h> +#include <power/pmic.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> + +DECLARE_GLOBAL_DATA_PTR ; + +int pmic_check_reg (struct pmic_platdata *p,unsigned reg) +{ +if (!p) +return -ENODEV ; + +if (reg >= p->regs_num) { + error("<reg num> = %d is invalid. Should be less than%d",
drivers/power/pmic-uclass.c new file +18
-0+ reg, p->regs_num); +return -EINVAL ; + } + +return 0 ; +} + +int pmic_reg_write (struct udevice *dev,unsigned reg,unsigned val) +{ +struct pmic_platdata *p; + + p =dev_get_platdata (dev); +if (!p) +return -EPERM ; + +switch (p->interface) { +case PMIC_I2C : +#ifdef CONFIG_DM_PMIC_I2C drivers/power/pmic-uclass.c line 55
Quoted 10 lines
drivers/power/pmic-uclass.c new file +10
-0+return pmic_i2c_reg_write (dev, reg, val); +#else +return -ENOSYS ; +#endif +case PMIC_SPI : +#ifdef CONFIG_DM_PMIC_SPI +return pmic_spi_reg_write (dev, reg, val); +#else +return -ENOSYS ; +#endif Perhaps one day we should add another uclass which is some sort of register cache. It could be implemented by I2C and SPI drivers (or better perhaps the I2C and SPI uclasses could provide a register cache uclass device for their main when requested).
Quoted 3 lines
For now this seems fine though. I think the 'return
-ENOSYS' can just go at the end of the function and appear once.Quoted 8 lines
Why do we need the registers cache?
This maybe is good for a many read operations at a time in the system, but actually I think, that it is not required for the bootloader purposes.If we write some data - sequential, then we probably would like to check it in the same time, e.g. update some range of I2C registers.
I don't know the Chromebook design, but how it could be useful for you?
Quoted 9 lines
We don't need a register cache - I was just thinking of that from the kernel. But it feels like an interface like:
int
reg_read(int reg, uint32_t *value)
intreg_write(int reg, uint32_t value)
intreg_write_range(int reg_start, int reg_count, uint32_t value[])might be useful - it could be implemented for both I2C and SPI.
Ok, now I see.
Quoted 76 lines
Quoted 72 lines
Quoted 63 lines
Quoted 63 lines
drivers/power/pmic-uclass.c new file +61
-0+default : +return -ENODEV ; + } +} + +int pmic_reg_read (struct udevice *dev,unsigned reg,unsigned *val) +{ +struct pmic_platdata *p; + + p =dev_get_platdata (dev); +if (!p) +return -EPERM ; + +switch (p->interface) { +case PMIC_I2C : +#ifdef CONFIG_DM_PMIC_I2C +return pmic_i2c_reg_read (dev, reg, val); +#else +return -ENOSYS ; +#endif +case PMIC_SPI : +#ifdef CONFIG_DM_PMIC_SPI +return pmic_spi_reg_read (dev, reg, val); +#else +return -ENOSYS ; +#endif +default : +return -ENODEV ; + } +} + +int pmic_probe (struct udevice *dev,struct spi_slave *spi_slave) +{ +struct pmic_platdata *p; + + p =dev_get_platdata (dev); +if (!p) +return -EPERM ; + +switch (p->interface) { +case PMIC_I2C : +#ifdef CONFIG_DM_PMIC_I2C +return pmic_i2c_probe (dev); +#else +return -ENOSYS ; +#endif +case PMIC_SPI : +if (!spi_slave) +return -EINVAL ; +#ifdef CONFIG_DM_PMIC_SPI + spi_slave =pmic_spi_probe (dev); +if (!spi_slave) +return -EIO ; + +return 0 ; +#else +return -ENOSYS ; +#endif +default : +return -ENODEV ; + }Quoted 9 lines
Quoted 4 lines
drivers/power/pmic-uclass.c new file +3
-0+} + +struct udevice *pmic_get_by_interface(int uclass_id, int bus, int
addr_cs)This is an interesting function! Again we can probably improve things when we have an i2c uclass.
Quoted 3 lines
Thanks! But even if we have i2c uclass, then we also should know how to recognize each device, e.g. in the board code. So the interface and address will probably no change.
Quoted 8 lines
I'm thinking that one day you could do something like:
// Find the regmap associated with the device
reg_dev=device_get_child(UCLASS_REGMAP, dev);// Call the regmap uclass to access registers whether it is I2C or SPI
regmap_write(reg_dev, value);
This could be an another interesting possible feature of dm.
Quoted 579 lines
Quoted 93 lines
Quoted 84 lines
Quoted 84 lines
drivers/power/pmic-uclass.c new file +82
-0+{ +struct pmic_platdata *pl; +struct udevice *dev; +struct uclass *uc; +int ret; + +if (uclass_id <0 || uclass_id >=UCLASS_COUNT ) { +error ("Bad uclass id.\n" ); +return NULL ; + } + + ret =uclass_get (uclass_id, &uc); +if (ret) { +error ("PMIC uclass: %d not initialized!\n" , uclass_id); +return NULL ; + } + + uclass_foreach_dev(dev, uc) { +if (!dev || !dev->platdata) +continue ; + + pl =dev_get_platdata (dev); + +if (pl->bus != bus) +continue ; + +switch (pl->interface) { +case PMIC_I2C : +if (addr_cs != pl->hw.i2c.addr) +continue ; +break ; +case PMIC_SPI : +if (addr_cs != pl->hw.spi.cs) +continue ; +break ; +default : +error ("Unsupported interface of: %s" , dev->name); +return NULL ; + } + + ret =device_probe (dev); +if (ret) { +error ("Dev: %s probe failed" , dev->name); +return NULL ; + } +return dev; + } + +return NULL ; +} + +struct udevice *pmic_get_by_name (int uclass_id,char *name) +{ +struct udevice *dev; +struct uclass *uc; +int ret; + +if (uclass_id <0 || uclass_id >=UCLASS_COUNT ) { +error ("Bad uclass id.\n" ); +return NULL ; + } + + ret =uclass_get (uclass_id, &uc); +if (ret) { +error ("PMIC uclass: %d not initialized!" , uclass_id); +return NULL ; + } + + uclass_foreach_dev(dev, uc) { +if (!dev) +continue ; + +if (!strncmp (name, dev->name,strlen (name))) { + ret =device_probe (dev); +if (ret) +error ("Dev: %s probe failed" , dev->name); +return dev; + } + } + +return NULL ; +}Quoted 9 lines
drivers/power/pmic-uclass.c
Quoted 2 lines
drivers/power/pmic-uclass.c new file +2
-0+ +int pmic_init_dm (void )I don't understand why you need this function at all. Driver model should find the pmics automatically. Is it because we don't have an i2c uclass? In that case I think it would be better to limit this hack to I2C. For SPI it should work correctly without this function.
Quoted 7 lines
Currently, it shouldn't and yes - it isn't because of the I2C uclass missing. So no one check the I2C nodes - and its child subnodes. Actually, this can be easy fixed - just don't add the "pmic" alias to the dts. But I will also change fix the code.
And by the way - is there any check in the code, which protects for the device bind more than once?
No there is no such check at present.
Quoted 476 lines
Quoted 454 lines
Quoted 403 lines
drivers/power/pmic-uclass.c new file +23
-0+{ + const void *blob = gd->fdt_blob; + const struct fdt_property *prop; + struct udevice *dev = NULL; + const char *path; + const char *alias; + int alias_node, node, offset, ret = 0; + int alias_len; + int len; + + alias = "pmic"; + alias_len = strlen(alias); + + alias_node = fdt_path_offset(blob, "/aliases"); + offset = fdt_first_property_offset(blob, alias_node); + + if (offset < 0) { + error("Alias node not found."); + return -ENODEV; + } + + offset = fdt_first_property_offset(blob, alias_node); + for (; offset > 0; offset = fdt_next_property_offset(blob,offset)) {
drivers/power/pmic-uclass.c new file +29
-0+ prop =fdt_get_property_by_offset (blob, offset, &len); +if (!len) +continue ; + + path =fdt_string (blob,fdt32_to_cpu (prop->nameoff)); + +if (!strncmp (alias, path, alias_len)) + node =fdt_path_offset (blob, prop->data); +else + node =0 ; + +if (node <=0 ) +continue ; + + ret =lists_bind_fdt (gd->dm_root, blob, node, &dev); +if (ret <0 ) +continue ; + +if (device_probe (dev)) +error ("Device: %s, probe error" , dev->name); + } + +return 0 ; +} + +UCLASS_DRIVER (pmic) = { + .id =UCLASS_PMIC , + .name ="pmic" , +};drivers/power/pmic_i2c.c new file +63
-0@@ -0,0 +1,136 @@ +/* +* Copyright (C) 2014 Samsung Electronics +* Przemyslaw Marczak <[email protected]> +* +* Copyright (C) 2011 Samsung Electronics +* Lukasz Majewski <[email protected]> +* +* (C) Copyright 2010 +* Stefano Babic, DENX Software Engineering, sbabic at denx.de +* +* (C) Copyright 2008-2009 Freescale Semiconductor, Inc. +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#include <common.h> +#include <linux/types.h> +#include <power/pmic.h> +#include <errno.h> +#include <dm.h> +#include <i2c.h> + +int pmic_i2c_reg_write (struct udevice *dev,unsigned reg,unsigned val) +{ +struct pmic_platdata *p; +unsigned char buf[4 ] = {0 }; + +if (!dev) +return -ENODEV ; + + p = dev->platdata; + +if (pmic_check_reg (p, reg)) +return -EINVAL ; + +I2C_SET_BUS (p->bus); + +switch (pmic_i2c_tx_num) { +case 3 : +if (p->byte_order ==PMIC_SENSOR_BYTE_ORDER_BIG ) { + buf[2 ] = (cpu_to_le32 (val) >>16 ) &0xff ; + buf[1 ] = (cpu_to_le32 (val) >>8 ) &0xff ; + buf[0 ] =cpu_to_le32 (val) &0xff ; + }else { + buf[0 ] = (cpu_to_le32 (val) >>16 ) &0xff ; + buf[1 ] = (cpu_to_le32 (val) >>8 ) &0xff ; + buf[2 ] =cpu_to_le32 (val) &0xff ; + } +break ; +case 2 : +if (p->byte_order ==PMIC_SENSOR_BYTE_ORDER_BIG ) { + buf[1 ] = (cpu_to_le32 (val) >>8 ) &0xff ; + buf[0 ] =cpu_to_le32 (val) &0xff ; + }else { + buf[0 ] = (cpu_to_le32 (val) >>8 ) &0xff ; + buf[1 ] =cpu_to_le32 (val) &0xff ; + } +break ; +case 1 : + buf[0 ] =cpu_to_le32 (val) &0xff ; +break ; +default : + printf("%s: invalid tx_num: %d", __func__,
pmic_i2c_tx_num);drivers/power/pmic_i2c.c new file +48
-0+return -1 ; + } + +if (i2c_write (pmic_i2c_addr, reg,1 , buf, pmic_i2c_tx_num)) +return -1 ; + +return 0 ; +} + +int pmic_i2c_reg_read (struct udevice *dev,unsigned reg,unsigned *val) +{ +struct pmic_platdata *p; +unsigned char buf[4 ] = {0 }; +u32 ret_val =0 ; + +if (!dev) +return -ENODEV ; + + p = dev->platdata; + +if (pmic_check_reg (p, reg)) +return -EINVAL ; + +I2C_SET_BUS (p->bus); + +if (i2c_read (pmic_i2c_addr, reg,1 , buf, pmic_i2c_tx_num)) +return -1 ; + +switch (pmic_i2c_tx_num) { +case 3 : +if (p->byte_order ==PMIC_SENSOR_BYTE_ORDER_BIG ) + ret_val =le32_to_cpu (buf[2 ] <<16 + | buf[1 ] <<8 | buf[0 ]); +else + ret_val =le32_to_cpu (buf[0 ] <<16 | + buf[1 ] <<8 | buf[2 ]); +break ; +case 2 : +if (p->byte_order ==PMIC_SENSOR_BYTE_ORDER_BIG ) + ret_val =le32_to_cpu (buf[1 ] <<8 | buf[0 ]); +else + ret_val =le32_to_cpu (buf[0 ] <<8 | buf[1 ]); +break ; +case 1 : + ret_val =le32_to_cpu (buf[0 ]); +break ; +default : + printf("%s: invalid tx_num: %d", __func__,
pmic_i2c_tx_num);drivers/power/pmic_i2c.c new file +25
-0+return -1 ; + } +memcpy (val, &ret_val,sizeof (ret_val)); + +return 0 ; +} + +int pmic_i2c_probe (struct udevice *dev) +{ +struct pmic_platdata *p; + +if (!dev) +return -ENODEV ; + + p = dev->platdata; + +i2c_set_bus_num (p->bus); +debug ("Bus: %d PMIC:%s probed!\n" , p->bus, dev->name); +if (i2c_probe (pmic_i2c_addr)) { +printf ("Can't find PMIC:%s\n" , dev->name); +return -1 ; + } + +return 0 ; +}drivers/power/pmic_spi.c new file +49
-0@@ -0,0 +1,137 @@ +/* +* Copyright (C) 2014 Samsung Electronics +* Przemyslaw Marczak <[email protected]> +* +* Copyright (C) 2011 Samsung Electronics +* Lukasz Majewski <[email protected]> +* +* (C) Copyright 2010 +* Stefano Babic, DENX Software Engineering, sbabic at denx.de +* +* (C) Copyright 2008-2009 Freescale Semiconductor, Inc. +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#include <common.h> +#include <linux/types.h> +#include <power/pmic.h> +#include <errno.h> +#include <dm.h> +#include <spi.h> + +static struct spi_slave *slave; + +void pmic_spi_free (struct spi_slave *slave) +{ +if (slave) +spi_free_slave (slave); +} + +struct spi_slave *pmic_spi_probe (struct udevice *dev) +{ +struct pmic_platdata *p; + +if (!dev) +return NULL ; + + p = dev->platdata; + +if (pmic_check_reg (p, reg)) +return NULL ; + +return spi_setup_slave (p->bus, + p->hw.spi.cs, + p->hw.spi.clk, + p->hw.spi.mode); +} + +static int pmic_spi_reg(struct udevice *dev, unsigned reg, unsigned*val,
drivers/power/pmic_spi.c new file +88
-0+ int write) +{ +struct pmic_platdata *p; +u32 pmic_tx, pmic_rx; +u32 tmp; + +if (!dev) +return -EINVAL ; + + p = dev->platdata; + +if (pmic_check_reg (p, reg)) +return -EFAULT ; + +if (!slave) { + slave =pmic_spi_probe (p); + +if (!slave) +return -ENODEV ; + } + +if (pmic_check_reg (p, reg)) +return -EFAULT ; + +if (spi_claim_bus (slave)) +return -EIO ; + + pmic_tx = p->hw.spi.prepare_tx (reg, val, write); + + tmp =cpu_to_be32 (pmic_tx); + +if (spi_xfer (slave, pmic_spi_bitlen, &tmp, &pmic_rx, + pmic_spi_flags)) { +spi_release_bus (slave); +return -EIO ; + } + +if (write) { + pmic_tx = p->hw.spi.prepare_tx (reg, val,0 ); + tmp =cpu_to_be32 (pmic_tx); +if (spi_xfer (slave, pmic_spi_bitlen, &tmp, &pmic_rx, + pmic_spi_flags)) { +spi_release_bus (slave); +return -EIO ; + } + } + +spi_release_bus (slave); + *val =cpu_to_be32 (pmic_rx); + +return 0 ; +} + +int pmic_spi_reg_write (struct udevice *dev,unsigned reg,unsigned val) +{ +struct pmic_platdata *p; + +if (!dev) +return -EINVAL ; + + p = dev->platdata; + +if (pmic_check_reg (p, reg)) +return -EFAULT ; + +if (pmic_spi_reg (p, reg, &val,1 )) +return -1 ; + +return 0 ; +} + +int pmic_spi_reg_read (struct udevice *dev,unsigned reg,unsigned *val) +{ +struct pmic_platdata *p; + +if (!dev) +return -EINVAL ; + + p = dev->platdata; + +if (pmic_check_reg (p, reg)) +return -EFAULT ; + +if (pmic_spi_reg (p, reg, val,0 )) +return -1 ; + +return 0 ; +}include/dm/uclass-id.h +3
-0@@ -29,6 +29,9 @@ enum uclass_id {UCLASS_SPI_FLASH ,/* SPI flash */ UCLASS_CROS_EC ,/* Chrome OS EC */ +/* PMIC uclass and PMIC related uclasses */ +UCLASS_PMIC , +UCLASS_COUNT , UCLASS_INVALID = -1, };include/power/pmic.h +8
-0@@ -1,4 +1,7 @@/* +* Copyright (C) 2014 Samsung Electronics +* Przemyslaw Marczak <[email protected]> +* * Copyright (C) 2011-2012 Samsung Electronics * Lukasz Majewski <[email protected]> * @@ -8,9 +11,12 @@#ifndef __CORE_PMIC_H_#define __CORE_PMIC_H_ +#include <dm.h> #include <linux/list.h> +#include <spi.h> #include <i2c.h> #include <power/power_chrg.h> +#include <power/regulator.h> enum {PMIC_I2C ,PMIC_SPI ,PMIC_NONE };enum {I2C_PMIC ,I2C_NUM , };@@ -78,6 +84,63 @@ struct pmic {struct list_head list; }; +#ifdef CONFIG_DM_PMIC +/* struct pmic_platdata - a standard descriptor for pmic device, which holds
+ * an informations about interface. It is common for all pmic devices.
+ *
+ * Note:
+ * Interface fields are the same as in: struct pmic.
+ * Note: struct pmic will be removed in the future after drivers migration
+ *
+ * @bus - a physical bus on which device is connected
+ * @interface - an interface type, one of enum:PMIC_I2C,PMIC_SPI,PMIC_NONE
+ * @byte_order - one of enum: PMIC_SENSOR_BYTE_ORDER*_LITTLE/_BIG
+ * @regs_num - number of device registers
+ * @hw - one of union structure:p_i2corp_spi
+ * based on @interface fieldinclude/power/pmic.h struct pmic { · line 107
Quoted 7 lines
include/power/pmic.h +7
-0+*/ +struct pmic_platdata { +int bus; +int interface; +int byte_order; +int regs_num; +union hw hw;If we have a 'register cache' uclass (later, once i2c is done) then this could just be a device.
Quoted 39 lines
include/power/pmic.h +18
-0+}; + +/* enum pmic_op_type - used for various pmic devices operation calls, +* for decrease a number of functions 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 , +}; + +/* drivers/power/pmic-uclass.c */ +int power_init_dm (void ); +struct udevice *pmic_get_by_name (int uclass_id,char *name); +struct udevice *pmic_get_by_interface(int uclass_id, int bus, int
addr_cs);include/power/pmic.h +18
-0+const char *pmic_if_str (int interface); +int pmic_check_reg (struct pmic_platdata *p,unsigned reg); +int pmic_reg_write (struct udevice *dev,unsigned reg,unsigned val); +int pmic_reg_read (struct udevice *dev,unsigned reg,unsigned *val); +int pmic_probe (struct udevice *dev,struct spi_slave *spi_slave); + +/* drivers/power/pmic_i2c.c */ +int pmic_i2c_reg_write (struct udevice *dev,unsigned reg,unsigned val); +int pmic_i2c_reg_read (struct udevice *dev,unsigned reg,unsigned *val); +int pmic_i2c_probe (struct udevice *dev); + +/* drivers/power/pmic_spi.c */ +int pmic_spi_reg_write (struct udevice *dev,unsigned reg,unsigned val); +int pmic_spi_reg_read (struct udevice *dev,unsigned reg,unsigned *val); +struct spi_slave *pmic_spi_probe (struct udevice *dev); +#endif /* CONFIG_DM_PMIC */ + +#ifdef CONFIG_POWER int pmic_init (unsigned char bus);int power_init_board (void );Quoted 9 lines
include/power/pmic.h int pmic_probe(struct pmic *p); · line 153
Quoted 5 lines
int pmic_dialog_init(unsigned char bus);include/power/pmic.h +0
-0@@ -88,6 +151,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);These should have comments.
Ok, I will add it.
Quoted 11 lines
Quoted 7 lines
include/power/pmic.h +1
-1+#endif #define pmic_i2c_addr (p->hw.i2c.addr)#define pmic_i2c_tx_num (p->hw.i2c.tx_num) --1.9.1
Regards,
Simon
Quoted 7 lines
Quoted 1 line
Thank you for the fast review :)
Very interested to see this development.
Regards,
Simon
Thank you again.
I'm going to check the i2c-working tree and maybe rebase the dm-pmic onto it.
Is it good idea?
Best Regards,
Signature · 4 lines
Przemyslaw Marczak Samsung R&D Institute Poland Samsung Electronics p.marczak at samsung.com
PATCH 4/19 dm: pmic: add implementation of driver model pmic uclass
Hi,
Quoted 864 lines · Przemyslaw Marczak
Hello Simon,
I missed some of your comments.
Quoted 151 lines · Simon Glass
Hi,
Quoted 139 lines · Przemyslaw Marczak
Hello Simon,
Quoted 125 lines · Simon Glass
Hi,
Quoted 101 lines · Przemyslaw Marczak
This is an introduction to driver-model multi class PMIC support. It starts with
UCLASS_PMIC- a common PMIC class type for I/O, which doesn't need to implement any specific operations and features beside the platform data, which is the 'structpmic_platdata' defined in file:
- 'include/power/pmic.h'New files:
-pmic-uclass.c- provides a common code forUCLASS_PMICdrivers
-pmic_i2c.c- provides dm interface for i2c pmic drivers
-pmic_spi.c- provides dm interface for spi pmic driversThose files are based on a current PMIC framework files and code. The new files are introduced to keep code readability and allow to make an easy drivers migration. The old pmic framework is still kept and full independent.
Changes:
- new uclass-id:UCLASS_PMIC,
- new configs:CONFIG_DM_PMIC;CONFIG_DM_PMIC_SPI;CONFIG_DM_PMIC_I2C,New pmic api is documented in: doc/README.power-framework-dm
Signed-off-by Przemyslaw Marczak <[email protected]>--- drivers/power/Makefile | 3 + drivers/power/pmic-uclass.c | 255 ++++++++++++++++++++++++++++++++++++++++++++ drivers/power/pmic_i2c.c | 136 +++++++++++++++++++++++ drivers/power/pmic_spi.c | 137 ++++++++++++++++++++++++ include/dm/uclass-id.h | 3 + include/power/pmic.h | 64 +++++++++++ 6 files changed, 598 insertions(+)create mode 100644
drivers/power/pmic-uclass.c
create mode 100644drivers/power/pmic_i2c.c
create mode 100644drivers/power/pmic_spi.cdrivers/power/Makefile +3
-0@@ -19,3 +19,6 @@ 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_SPI) += pmic_spi.o +obj-$(CONFIG_DM_PMIC_I2C) += pmic_i2c.o +obj-$(CONFIG_DM_PMIC) += pmic-uclass.odrivers/power/pmic-uclass.c new file +27
-0@@ -0,0 +1,255 @@ +/* +* Copyright (C) 2014 Samsung Electronics +* Przemyslaw Marczak <[email protected]> +* +* SPDX-License-Identifier: GPL-2.0+ +*/ +#include <common.h> +#include <linux/types.h> +#include <fdtdec.h> +#include <power/pmic.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> + +DECLARE_GLOBAL_DATA_PTR ; + +int pmic_check_reg (struct pmic_platdata *p,unsigned reg) +{ +if (!p) +return -ENODEV ; + +if (reg >= p->regs_num) { + error("<reg num> = %d is invalid. Should be less than%d",
drivers/power/pmic-uclass.c new file +18
-0+ reg, p->regs_num); +return -EINVAL ; + } + +return 0 ; +} + +int pmic_reg_write (struct udevice *dev,unsigned reg,unsigned val) +{ +struct pmic_platdata *p; + + p =dev_get_platdata (dev); +if (!p) +return -EPERM ; + +switch (p->interface) { +case PMIC_I2C : +#ifdef CONFIG_DM_PMIC_I2C drivers/power/pmic-uclass.c line 55
Quoted 10 lines
drivers/power/pmic-uclass.c new file +10
-0+return pmic_i2c_reg_write (dev, reg, val); +#else +return -ENOSYS ; +#endif +case PMIC_SPI : +#ifdef CONFIG_DM_PMIC_SPI +return pmic_spi_reg_write (dev, reg, val); +#else +return -ENOSYS ; +#endif Perhaps one day we should add another uclass which is some sort of register cache. It could be implemented by I2C and SPI drivers (or better perhaps the I2C and SPI uclasses could provide a register cache uclass device for their main when requested).
Quoted 3 lines
For now this seems fine though. I think the 'return
-ENOSYS' can just go at the end of the function and appear once.Why do we need the registers cache?
This maybe is good for a many read operations at a time in the system, but actually I think, that it is not required for the bootloader purposes.Quoted 5 lines
If we write some data - sequential, then we probably would like to check it
in the same time, e.g. update some range of I2C registers.I don't know the Chromebook design, but how it could be useful for you?
Quoted 9 lines
We don't need a register cache - I was just thinking of that from the kernel. But it feels like an interface like:
int
reg_read(int reg, uint32_t *value)
intreg_write(int reg, uint32_t value)
intreg_write_range(int reg_start, int reg_count, uint32_t value[])might be useful - it could be implemented for both I2C and SPI.
Ok, now I see.
Quoted 79 lines
Quoted 73 lines
Quoted 64 lines
Quoted 64 lines
drivers/power/pmic-uclass.c new file +62
-0+default : +return -ENODEV ; + } +} + +int pmic_reg_read (struct udevice *dev,unsigned reg,unsigned *val) +{ +struct pmic_platdata *p; + + p =dev_get_platdata (dev); +if (!p) +return -EPERM ; + +switch (p->interface) { +case PMIC_I2C : +#ifdef CONFIG_DM_PMIC_I2C +return pmic_i2c_reg_read (dev, reg, val); +#else +return -ENOSYS ; +#endif +case PMIC_SPI : +#ifdef CONFIG_DM_PMIC_SPI +return pmic_spi_reg_read (dev, reg, val); +#else +return -ENOSYS ; +#endif +default : +return -ENODEV ; + } +} + +int pmic_probe (struct udevice *dev,struct spi_slave *spi_slave) +{ +struct pmic_platdata *p; + + p =dev_get_platdata (dev); +if (!p) +return -EPERM ; + +switch (p->interface) { +case PMIC_I2C : +#ifdef CONFIG_DM_PMIC_I2C +return pmic_i2c_probe (dev); +#else +return -ENOSYS ; +#endif +case PMIC_SPI : +if (!spi_slave) +return -EINVAL ; +#ifdef CONFIG_DM_PMIC_SPI + spi_slave =pmic_spi_probe (dev); +if (!spi_slave) +return -EIO ; + +return 0 ; +#else +return -ENOSYS ; +#endif +default : +return -ENODEV ; + } +}Quoted 9 lines
Quoted 3 lines
drivers/power/pmic-uclass.c new file +2
-0+ +struct udevice *pmic_get_by_interface(int uclass_id, int bus, int
addr_cs)This is an interesting function! Again we can probably improve things when we have an i2c uclass.
Quoted 4 lines
Thanks! But even if we have i2c uclass, then we also should know how to recognize each device, e.g. in the board code. So the interface and address
will probably no change.Quoted 8 lines
I'm thinking that one day you could do something like:
// Find the regmap associated with the device
reg_dev=device_get_child(UCLASS_REGMAP, dev);// Call the regmap uclass to access registers whether it is I2C or SPI
regmap_write(reg_dev, value);This could be an another interesting possible feature of dm.
Quoted 594 lines
Quoted 96 lines
Quoted 87 lines
Quoted 87 lines
drivers/power/pmic-uclass.c new file +37
-0+{ +struct pmic_platdata *pl; +struct udevice *dev; +struct uclass *uc; +int ret; + +if (uclass_id <0 || uclass_id >=UCLASS_COUNT ) { +error ("Bad uclass id.\n" ); +return NULL ; + } + + ret =uclass_get (uclass_id, &uc); +if (ret) { +error ("PMIC uclass: %d not initialized!\n" , uclass_id); +return NULL ; + } + + uclass_foreach_dev(dev, uc) { +if (!dev || !dev->platdata) +continue ; + + pl =dev_get_platdata (dev); + +if (pl->bus != bus) +continue ; + +switch (pl->interface) { +case PMIC_I2C : +if (addr_cs != pl->hw.i2c.addr) +continue ; +break ; +case PMIC_SPI : +if (addr_cs != pl->hw.spi.cs) +continue ; +break ; +default : + error("Unsupported interface of: %s",
dev->name);drivers/power/pmic-uclass.c new file +39
-0+return NULL ; + } + + ret =device_probe (dev); +if (ret) { +error ("Dev: %s probe failed" , dev->name); +return NULL ; + } +return dev; + } + +return NULL ; +} + +struct udevice *pmic_get_by_name (int uclass_id,char *name) +{ +struct udevice *dev; +struct uclass *uc; +int ret; + +if (uclass_id <0 || uclass_id >=UCLASS_COUNT ) { +error ("Bad uclass id.\n" ); +return NULL ; + } + + ret =uclass_get (uclass_id, &uc); +if (ret) { +error ("PMIC uclass: %d not initialized!" , uclass_id); +return NULL ; + } + + uclass_foreach_dev(dev, uc) { +if (!dev) +continue ; + +if (!strncmp (name, dev->name,strlen (name))) { + ret =device_probe (dev); +if (ret) + error("Dev: %s probe failed",
dev->name);drivers/power/pmic-uclass.c new file +7
-0+return dev; + } + } + +return NULL ; +} +Quoted 9 lines
Quoted 1 line
+int
pmic_init_dm(void)I don't understand why you need this function at all. Driver model should find the pmics automatically. Is it because we don't have an i2c uclass? In that case I think it would be better to limit this hack to I2C. For SPI it should work correctly without this function.
Quoted 7 lines
Currently, it shouldn't and yes - it isn't because of the I2C uclass missing. So no one check the I2C nodes - and its child subnodes. Actually, this can be easy fixed - just don't add the "pmic" alias to the dts. But I will also change fix the code.
And by the way - is there any check in the code, which protects for the device bind more than once?
No there is no such check at present.
Quoted 487 lines
Quoted 465 lines
Quoted 407 lines
drivers/power/pmic-uclass.c new file +23
-0+{ + const void *blob = gd->fdt_blob; + const struct fdt_property *prop; + struct udevice *dev = NULL; + const char *path; + const char *alias; + int alias_node, node, offset, ret = 0; + int alias_len; + int len; + + alias = "pmic"; + alias_len = strlen(alias); + + alias_node = fdt_path_offset(blob, "/aliases"); + offset = fdt_first_property_offset(blob, alias_node); + + if (offset < 0) { + error("Alias node not found."); + return -ENODEV; + } + + offset = fdt_first_property_offset(blob, alias_node); + for (; offset > 0; offset = fdt_next_property_offset(blob,offset)) {
drivers/power/pmic-uclass.c new file +29
-0+ prop =fdt_get_property_by_offset (blob, offset, &len); +if (!len) +continue ; + + path =fdt_string (blob,fdt32_to_cpu (prop->nameoff)); + +if (!strncmp (alias, path, alias_len)) + node =fdt_path_offset (blob, prop->data); +else + node =0 ; + +if (node <=0 ) +continue ; + + ret =lists_bind_fdt (gd->dm_root, blob, node, &dev); +if (ret <0 ) +continue ; + +if (device_probe (dev)) +error ("Device: %s, probe error" , dev->name); + } + +return 0 ; +} + +UCLASS_DRIVER (pmic) = { + .id =UCLASS_PMIC , + .name ="pmic" , +};drivers/power/pmic_i2c.c new file +23
-0@@ -0,0 +1,136 @@ +/* +* Copyright (C) 2014 Samsung Electronics +* Przemyslaw Marczak <[email protected]> +* +* Copyright (C) 2011 Samsung Electronics +* Lukasz Majewski <[email protected]> +* +* (C) Copyright 2010 +* Stefano Babic, DENX Software Engineering, sbabic at denx.de +* +* (C) Copyright 2008-2009 Freescale Semiconductor, Inc. +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#include <common.h> +#include <linux/types.h> +#include <power/pmic.h> +#include <errno.h> +#include <dm.h> +#include <i2c.h> + +int pmic_i2c_reg_write(struct udevice *dev, unsigned reg, unsignedval)
drivers/power/pmic_i2c.c new file +40
-0+{ +struct pmic_platdata *p; +unsigned char buf[4 ] = {0 }; + +if (!dev) +return -ENODEV ; + + p = dev->platdata; + +if (pmic_check_reg (p, reg)) +return -EINVAL ; + +I2C_SET_BUS (p->bus); + +switch (pmic_i2c_tx_num) { +case 3 : +if (p->byte_order ==PMIC_SENSOR_BYTE_ORDER_BIG ) { + buf[2 ] = (cpu_to_le32 (val) >>16 ) &0xff ; + buf[1 ] = (cpu_to_le32 (val) >>8 ) &0xff ; + buf[0 ] =cpu_to_le32 (val) &0xff ; + }else { + buf[0 ] = (cpu_to_le32 (val) >>16 ) &0xff ; + buf[1 ] = (cpu_to_le32 (val) >>8 ) &0xff ; + buf[2 ] =cpu_to_le32 (val) &0xff ; + } +break ; +case 2 : +if (p->byte_order ==PMIC_SENSOR_BYTE_ORDER_BIG ) { + buf[1 ] = (cpu_to_le32 (val) >>8 ) &0xff ; + buf[0 ] =cpu_to_le32 (val) &0xff ; + }else { + buf[0 ] = (cpu_to_le32 (val) >>8 ) &0xff ; + buf[1 ] =cpu_to_le32 (val) &0xff ; + } +break ; +case 1 : + buf[0 ] =cpu_to_le32 (val) &0xff ; +break ; +default : + printf("%s: invalid tx_num: %d", __func__,
pmic_i2c_tx_num);drivers/power/pmic_i2c.c new file +10
-0+return -1 ; + } + +if (i2c_write (pmic_i2c_addr, reg,1 , buf, pmic_i2c_tx_num)) +return -1 ; + +return 0 ; +} + +int pmic_i2c_reg_read(struct udevice *dev, unsigned reg, unsigned*val)
drivers/power/pmic_i2c.c new file +38
-0+{ +struct pmic_platdata *p; +unsigned char buf[4 ] = {0 }; +u32 ret_val =0 ; + +if (!dev) +return -ENODEV ; + + p = dev->platdata; + +if (pmic_check_reg (p, reg)) +return -EINVAL ; + +I2C_SET_BUS (p->bus); + +if (i2c_read (pmic_i2c_addr, reg,1 , buf, pmic_i2c_tx_num)) +return -1 ; + +switch (pmic_i2c_tx_num) { +case 3 : +if (p->byte_order ==PMIC_SENSOR_BYTE_ORDER_BIG ) + ret_val =le32_to_cpu (buf[2 ] <<16 + | buf[1 ] <<8 | buf[0 ]); +else + ret_val =le32_to_cpu (buf[0 ] <<16 | + buf[1 ] <<8 | buf[2 ]); +break ; +case 2 : +if (p->byte_order ==PMIC_SENSOR_BYTE_ORDER_BIG ) + ret_val =le32_to_cpu (buf[1 ] <<8 | buf[0 ]); +else + ret_val =le32_to_cpu (buf[0 ] <<8 | buf[1 ]); +break ; +case 1 : + ret_val =le32_to_cpu (buf[0 ]); +break ; +default : + printf("%s: invalid tx_num: %d", __func__,
pmic_i2c_tx_num);drivers/power/pmic_i2c.c new file +25
-0+return -1 ; + } +memcpy (val, &ret_val,sizeof (ret_val)); + +return 0 ; +} + +int pmic_i2c_probe (struct udevice *dev) +{ +struct pmic_platdata *p; + +if (!dev) +return -ENODEV ; + + p = dev->platdata; + +i2c_set_bus_num (p->bus); +debug ("Bus: %d PMIC:%s probed!\n" , p->bus, dev->name); +if (i2c_probe (pmic_i2c_addr)) { +printf ("Can't find PMIC:%s\n" , dev->name); +return -1 ; + } + +return 0 ; +}drivers/power/pmic_spi.c new file +49
-0@@ -0,0 +1,137 @@ +/* +* Copyright (C) 2014 Samsung Electronics +* Przemyslaw Marczak <[email protected]> +* +* Copyright (C) 2011 Samsung Electronics +* Lukasz Majewski <[email protected]> +* +* (C) Copyright 2010 +* Stefano Babic, DENX Software Engineering, sbabic at denx.de +* +* (C) Copyright 2008-2009 Freescale Semiconductor, Inc. +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#include <common.h> +#include <linux/types.h> +#include <power/pmic.h> +#include <errno.h> +#include <dm.h> +#include <spi.h> + +static struct spi_slave *slave; + +void pmic_spi_free (struct spi_slave *slave) +{ +if (slave) +spi_free_slave (slave); +} + +struct spi_slave *pmic_spi_probe (struct udevice *dev) +{ +struct pmic_platdata *p; + +if (!dev) +return NULL ; + + p = dev->platdata; + +if (pmic_check_reg (p, reg)) +return NULL ; + +return spi_setup_slave (p->bus, + p->hw.spi.cs, + p->hw.spi.clk, + p->hw.spi.mode); +} + +static int pmic_spi_reg(struct udevice *dev, unsigned reg, unsigned*val,
drivers/power/pmic_spi.c new file +54
-0+ int write) +{ +struct pmic_platdata *p; +u32 pmic_tx, pmic_rx; +u32 tmp; + +if (!dev) +return -EINVAL ; + + p = dev->platdata; + +if (pmic_check_reg (p, reg)) +return -EFAULT ; + +if (!slave) { + slave =pmic_spi_probe (p); + +if (!slave) +return -ENODEV ; + } + +if (pmic_check_reg (p, reg)) +return -EFAULT ; + +if (spi_claim_bus (slave)) +return -EIO ; + + pmic_tx = p->hw.spi.prepare_tx (reg, val, write); + + tmp =cpu_to_be32 (pmic_tx); + +if (spi_xfer (slave, pmic_spi_bitlen, &tmp, &pmic_rx, + pmic_spi_flags)) { +spi_release_bus (slave); +return -EIO ; + } + +if (write) { + pmic_tx = p->hw.spi.prepare_tx (reg, val,0 ); + tmp =cpu_to_be32 (pmic_tx); +if (spi_xfer (slave, pmic_spi_bitlen, &tmp, &pmic_rx, + pmic_spi_flags)) { +spi_release_bus (slave); +return -EIO ; + } + } + +spi_release_bus (slave); + *val =cpu_to_be32 (pmic_rx); + +return 0 ; +} + +int pmic_spi_reg_write(struct udevice *dev, unsigned reg, unsignedval)
drivers/power/pmic_spi.c new file +18
-0+{ +struct pmic_platdata *p; + +if (!dev) +return -EINVAL ; + + p = dev->platdata; + +if (pmic_check_reg (p, reg)) +return -EFAULT ; + +if (pmic_spi_reg (p, reg, &val,1 )) +return -1 ; + +return 0 ; +} + +int pmic_spi_reg_read(struct udevice *dev, unsigned reg, unsigned*val)
drivers/power/pmic_spi.c new file +16
-0+{ +struct pmic_platdata *p; + +if (!dev) +return -EINVAL ; + + p = dev->platdata; + +if (pmic_check_reg (p, reg)) +return -EFAULT ; + +if (pmic_spi_reg (p, reg, val,0 )) +return -1 ; + +return 0 ; +}include/dm/uclass-id.h +3
-0@@ -29,6 +29,9 @@ enum uclass_id {UCLASS_SPI_FLASH ,/* SPI flash */ UCLASS_CROS_EC ,/* Chrome OS EC */ +/* PMIC uclass and PMIC related uclasses */ +UCLASS_PMIC , +UCLASS_COUNT , UCLASS_INVALID = -1, };include/power/pmic.h +8
-0@@ -1,4 +1,7 @@/* +* Copyright (C) 2014 Samsung Electronics +* Przemyslaw Marczak <[email protected]> +* * Copyright (C) 2011-2012 Samsung Electronics * Lukasz Majewski <[email protected]> * @@ -8,9 +11,12 @@#ifndef __CORE_PMIC_H_#define __CORE_PMIC_H_ +#include <dm.h> #include <linux/list.h> +#include <spi.h> #include <i2c.h> #include <power/power_chrg.h> +#include <power/regulator.h> enum {PMIC_I2C ,PMIC_SPI ,PMIC_NONE };enum {I2C_PMIC ,I2C_NUM , };@@ -78,6 +84,63 @@ struct pmic {struct list_head list; }; +#ifdef CONFIG_DM_PMIC +/* struct pmic_platdata - a standard descriptor for pmic device, which holds
+ * an informations about interface. It is common for all pmic devices.
+ *
+ * Note:
+ * Interface fields are the same as in: struct pmic.
+ * Note: struct pmic will be removed in the future after drivers migration
+ *
+ * @bus - a physical bus on which device is connected
+ * @interface - an interface type, one of enum:PMIC_I2C,PMIC_SPI,PMIC_NONE
+ * @byte_order - one of enum: PMIC_SENSOR_BYTE_ORDER*_LITTLE/_BIG
+ * @regs_num - number of device registers
+ * @hw - one of union structure:p_i2corp_spi
+ * based on @interface fieldinclude/power/pmic.h struct pmic { · line 107
Quoted 7 lines
include/power/pmic.h +7
-0+*/ +struct pmic_platdata { +int bus; +int interface; +int byte_order; +int regs_num; +union hw hw;If we have a 'register cache' uclass (later, once i2c is done) then this could just be a device.
Quoted 45 lines
include/power/pmic.h +4
-0+}; + +/* enum pmic_op_type - used for various pmic devices operation calls, +* for decrease a number of functions with the same code for read/write
+ * or get/set.
+ *
+ * @PMIC_OP_GET - get operation
+ * @PMIC_OP_SET - set operationinclude/power/pmic.h +10
-0+*/ +enum pmic_op_type { +PMIC_OP_GET , +PMIC_OP_SET , +}; + +/* drivers/power/pmic-uclass.c */ +int power_init_dm (void ); +struct udevice *pmic_get_by_name (int uclass_id,char *name); +struct udevice *pmic_get_by_interface(int uclass_id, int bus, int
addr_cs);include/power/pmic.h +8
-0+const char *pmic_if_str (int interface); +int pmic_check_reg (struct pmic_platdata *p,unsigned reg); +int pmic_reg_write (struct udevice *dev,unsigned reg,unsigned val); +int pmic_reg_read (struct udevice *dev,unsigned reg,unsigned *val); +int pmic_probe (struct udevice *dev,struct spi_slave *spi_slave); + +/* drivers/power/pmic_i2c.c */ +int pmic_i2c_reg_write(struct udevice *dev, unsigned reg, unsignedval);
+intpmic_i2c_reg_read(struct udevice *dev, unsigned reg, unsigned *val);include/power/pmic.h +4
-0+int pmic_i2c_probe (struct udevice *dev); + +/* drivers/power/pmic_spi.c */ +int pmic_spi_reg_write(struct udevice *dev, unsigned reg, unsignedval);
+intpmic_spi_reg_read(struct udevice *dev, unsigned reg, unsigned *val);include/power/pmic.h +4
-0+struct spi_slave *pmic_spi_probe (struct udevice *dev); +#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);Quoted 9 lines
include/power/pmic.h int pmic_probe(struct pmic *p); · line 153
Quoted 4 lines
include/power/pmic.h +0
-0@@ -88,6 +151,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);These should have comments.
Ok, I will add it.
Quoted 11 lines
Quoted 7 lines
include/power/pmic.h +1
-1+#endif #define pmic_i2c_addr (p->hw.i2c.addr)#define pmic_i2c_tx_num (p->hw.i2c.tx_num) --1.9.1
Regards,
SimonQuoted 8 lines
Quoted 1 line
Thank you for the fast review :)
Very interested to see this development.
Regards,
Simon
Quoted 5 lines
Thank you again.
I'm going to check the i2c-working tree and maybe rebase the dm-pmic onto it.Is it good idea?
Sounds good. Once I get the main DM patches landed (hopefully this week) I'll rebase the other series including I2C. But for now you should be good to use it.
Regards,
Simon
PATCH 4/19 dm: pmic: add implementation of driver model pmic uclass
Hello,
... snip ...
Quoted 5 lines
Quoted 5 lines
Thank you again.
I'm going to check the i2c-working tree and maybe rebase the dm-pmic onto it.
Quoted 9 lines
Quoted 1 line
Is it good idea?
Sounds good. Once I get the main DM patches landed (hopefully this week) I'll rebase the other series including I2C. But for now you should be good to use it.
Regards,
Simon
I have also some other tasks, but I hope to check this in this week.
Regards,
Signature · 4 lines
Przemyslaw Marczak Samsung R&D Institute Poland Samsung Electronics p.marczak at samsung.com
PATCH 4/19 dm: pmic: add implementation of driver model pmic uclass
Hi,
Quoted 17 lines · Przemyslaw Marczak
Hello,
... snip ...
Quoted 13 lines
Quoted 7 lines
Thank you again.
I'm going to check the i2c-working tree and maybe rebase the dm-pmic onto it.Is it good idea?
Sounds good. Once I get the main DM patches landed (hopefully this week) I'll rebase the other series including I2C. But for now you should be good to use it.
Quoted 5 lines
Quoted 3 lines
Regards,
SimonI have also some other tasks, but I hope to check this in this week.
How are you going with this? Also did you get driver model going for I2C on exynos? If not, need help?
Regards,
Simon
PATCH 4/19 dm: pmic: add implementation of driver model pmic uclass
Hello Simon,
Quoted 25 lines · Simon Glass
Hi,
Quoted 21 lines · Przemyslaw Marczak
Hello,
... snip ...
Quoted 16 lines
Quoted 7 lines
Thank you again.
I'm going to check the i2c-working tree and maybe rebase the dm-pmic onto it.Is it good idea?
Sounds good. Once I get the main DM patches landed (hopefully this week) I'll rebase the other series including I2C. But for now you should be good to use it.
Regards,
Simon
Quoted 8 lines
Quoted 1 line
I have also some other tasks, but I hope to check this in this week.
How are you going with this? Also did you get driver model going for I2C on exynos? If not, need help?
Regards,
Simon
Each time, I would like to start working on it - some other task comes. Maybe tomorrow I will start this.
Best regards,
Signature · 4 lines
Przemyslaw Marczak Samsung R&D Institute Poland Samsung Electronics p.marczak at samsung.com
PATCH 4/19 dm: pmic: add implementation of driver model pmic uclass
Hi Prezemyslaw,
Quoted 41 lines · Przemyslaw Marczak
Hello Simon,
Quoted 37 lines · Simon Glass
Hi,
Quoted 21 lines · Przemyslaw Marczak
Hello,
... snip ...
Quoted 16 lines
Quoted 9 lines
Thank you again.
I'm going to check the i2c-working tree and maybe rebase the dm-pmic onto
it.Is it good idea?
Sounds good. Once I get the main DM patches landed (hopefully this week) I'll rebase the other series including I2C. But for now you should be good to use it.
Quoted 5 lines
Quoted 3 lines
Regards,
SimonI have also some other tasks, but I hope to check this in this week.
How are you going with this? Also did you get driver model going for I2C on exynos? If not, need help?
Quoted 6 lines
Quoted 3 lines
Regards,
SimonEach time, I would like to start working on it - some other task comes. Maybe tomorrow I will start this.
OK. I posted driver model I2C for Tegra a few days ago so that will be a better base for exynos than the previous version.
Regards,
Simon
PATCH 5/19 dm: pmic: 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 I/O API.
The regulator framework is based on a 'structure dm_regulator_ops', which provides all regulator functions call types.
The optional and useful regulator features are two descriptor types:
- struct regulator_desc - describes the regulator name and value limits should be set by device driver for each regulator number.
- struct regulator_mode_desc - also should be defined as mode array for each regulator, since regulators supports few modes, at least: ON/OFF.
The regulator driver operations are clear and described in file:include/power/regulator.h:
Each regulator "struct driver.ops" should point to "struct dm_regulator_ops". If do, then the drivers can use the regulator api(if implemented):
- pmic_ldo_cnt(...)
- pmic_buck_cnt(...)
- pmic_get_ldo_val(...)
- pmic_set_ldo_val(...)
- pmic_get_ldo_mode(...)
- pmic_set_ldo_mode(...)
- pmic_get_buck_val(...)
- pmic_set_buck_val(...)
- pmic_get_buck_mode(...)
- pmic_set_buck_mode(...)
To get the regulator device we can use two functions:
- pmic_get_by_name(...)
- pmic_get_by_interface(...)
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
--- drivers/power/Makefile | 1 + drivers/power/regulator-uclass.c | 250 ++++++++++++++++++++++++++++++++++++ include/dm/uclass-id.h | 1 + include/power/pmic.h | 18 +++ include/power/regulator.h | 267 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 537 insertions(+) create mode 100644 drivers/power/regulator-uclass.c create mode 100644 include/power/regulator.h
drivers/power/Makefile +1 -0
@@ -22,3 +22,4 @@ obj-$(CONFIG_POWER_SPI) += power_spi.o obj-$(CONFIG_DM_PMIC_SPI) += pmic_spi.o obj-$(CONFIG_DM_PMIC_I2C) += pmic_i2c.o obj-$(CONFIG_DM_PMIC) += pmic-uclass.o +obj-$(CONFIG_DM_REGULATOR) += regulator-uclass.o
drivers/power/regulator-uclass.c new file +250 -0
250 lines not on this page · raw message
include/dm/uclass-id.h +1 -0
@@ -31,6 +31,7 @@ enum uclass_id {/* PMIC uclass and PMIC related uclasses */ UCLASS_PMIC , +UCLASS_PMIC_REGULATOR ,UCLASS_COUNT , UCLASS_INVALID = -1,
include/power/pmic.h +18 -0
@@ -119,6 +119,24 @@ enum pmic_op_type { PMIC_OP_SET, }; +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 */ int power_init_dm (void );struct udevice *pmic_get_by_name (int uclass_id,char *name);
include/power/regulator.h new file +267 -0
267 lines not on this page · raw message
Signature · 1 line
1.9.1
PATCH 5/19 dm: pmic: add implementation of driver model regulator uclass
Hi,
Quoted 29 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 I/O API.The regulator framework is based on a 'structure
dm_regulator_ops', which provides all regulator functions call types.The optional and useful regulator features are two descriptor types:
- structregulator_desc- describes the regulator name and value limits should be set by device driver for each regulator number.
- structregulator_mode_desc- also should be defined as mode array for each regulator, since regulators supports few modes, at least: ON/OFF.The regulator driver operations are clear and described in file:
include/power/regulator.h:Each regulator "struct driver.ops" should point to "struct
dm_regulator_ops". If do, then the drivers can use the regulator api(if implemented):
-pmic_ldo_cnt(...)
-pmic_buck_cnt(...)
-pmic_get_ldo_val(...)
-pmic_set_ldo_val(...)
-pmic_get_ldo_mode(...)
-pmic_set_ldo_mode(...)
-pmic_get_buck_val(...)
-pmic_set_buck_val(...)
-pmic_get_buck_mode(...)
-pmic_set_buck_mode(...)
Quoted 3 lines
To get the regulator device we can use two functions:
-pmic_get_by_name(...)
-pmic_get_by_interface(...)
I've just got a few high-level comment on this series so will respond to each patch.
Quoted 74 lines
Main 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]>--- drivers/power/Makefile | 1 + drivers/power/regulator-uclass.c | 250 ++++++++++++++++++++++++++++++++++++ include/dm/uclass-id.h | 1 + include/power/pmic.h | 18 +++ include/power/regulator.h | 267 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 537 insertions(+) create mode 100644 drivers/power/regulator-uclass.c create mode 100644 include/power/regulator.hdrivers/power/Makefile +1
-0@@ -22,3 +22,4 @@ obj-$(CONFIG_POWER_SPI) += power_spi.o obj-$(CONFIG_DM_PMIC_SPI) += pmic_spi.o obj-$(CONFIG_DM_PMIC_I2C) += pmic_i2c.o obj-$(CONFIG_DM_PMIC) += pmic-uclass.o +obj-$(CONFIG_DM_REGULATOR) += regulator-uclass.odrivers/power/regulator-uclass.c new file +39
-0@@ -0,0 +1,250 @@ +/* +* Copyright (C) 2014 Samsung Electronics +* Przemyslaw Marczak <[email protected]> +* +* SPDX-License-Identifier: GPL-2.0+ +*/ +#include <common.h> +#include <linux/types.h> +#include <fdtdec.h> +#include <power/pmic.h> +#include <i2c.h> +#include <compiler.h> +#include <dm.h> +#include <dm/device.h> +#include <dm/lists.h> +#include <dm/device-internal.h> +#include <errno.h> + +DECLARE_GLOBAL_DATA_PTR ; + +int pmic_ldo_cnt (struct udevice *dev) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_PMIC_REGULATOR ); +if (!ops) +return -ENODEV ; + +if (!ops->get_ldo_cnt) +return -EPERM ; + +return ops->get_ldo_cnt (dev); +} + +int pmic_buck_cnt (struct udevice *dev) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_PMIC_REGULATOR );
drivers/power/regulator-uclass.c line 49
Quoted 10 lines
drivers/power/regulator-uclass.c new file +10
-0+if (!ops) +return -ENODEV ; + +if (!ops->get_buck_cnt) +return -EPERM ; + +return ops->get_buck_cnt (dev); +} + +struct regulator_desc *pmic_ldo_desc (struct udevice *dev,int ldo)
I think these should return an error, with the struct * return as a parameter.
Quoted 65 lines
drivers/power/regulator-uclass.c new file +65
-0+{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_PMIC_REGULATOR ); +if (!ops) +return NULL ; + +if (!ops->get_val_desc) +return NULL ; + +return ops->get_val_desc (dev,DESC_TYPE_LDO , ldo); +} + +struct regulator_desc *pmic_buck_desc (struct udevice *dev,int buck) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_PMIC_REGULATOR ); +if (!ops) +return NULL ; + +if (!ops->get_val_desc) +return NULL ; + +return ops->get_val_desc (dev,DESC_TYPE_BUCK , buck); +} + +struct regulator_mode_desc *pmic_ldo_mode_desc (struct udevice *dev,int ldo, +int *mode_cnt) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_PMIC_REGULATOR ); +if (!ops) +return NULL ; + +if (!ops->get_mode_desc_array) +return NULL ; + +return ops->get_mode_desc_array (dev,DESC_TYPE_LDO , ldo, mode_cnt); +} + +struct regulator_mode_desc *pmic_buck_mode_desc (struct udevice *dev,int buck, +int *mode_cnt) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_PMIC_REGULATOR ); +if (!ops) +return NULL ; + +if (!ops->get_mode_desc_array) +return NULL ; + +return ops->get_mode_desc_array (dev,DESC_TYPE_BUCK , buck, mode_cnt); +} + +int pmic_get_ldo_val (struct udevice *dev,int ldo) +{ +const struct dm_regulator_ops *ops; +int val =-1 ; + + ops =pmic_get_uclass_ops (dev,UCLASS_PMIC_REGULATOR ); +if (!ops) +return -ENODEV ;
drivers/power/regulator-uclass.c line 124
Quoted 10 lines
drivers/power/regulator-uclass.c new file +10
-0+ +if (!ops->ldo_val) +return -EPERM ; + +if (ops->ldo_val (dev,PMIC_OP_GET , ldo, &val)) +return -EIO ; + +return val; +} +
Regards,
Simon
PATCH 5/19 dm: pmic: add implementation of driver model regulator uclass
Quoted 32 lines · Simon Glass
Hi,
Quoted 29 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 I/O API.The regulator framework is based on a 'structure
dm_regulator_ops', which provides all regulator functions call types.The optional and useful regulator features are two descriptor types:
- structregulator_desc- describes the regulator name and value limits should be set by device driver for each regulator number.
- structregulator_mode_desc- also should be defined as mode array for each regulator, since regulators supports few modes, at least: ON/OFF.The regulator driver operations are clear and described in file:
include/power/regulator.h:Each regulator "struct driver.ops" should point to "struct
dm_regulator_ops". If do, then the drivers can use the regulator api(if implemented):
-pmic_ldo_cnt(...)
-pmic_buck_cnt(...)
-pmic_get_ldo_val(...)
-pmic_set_ldo_val(...)
-pmic_get_ldo_mode(...)
-pmic_set_ldo_mode(...)
-pmic_get_buck_val(...)
-pmic_set_buck_val(...)
-pmic_get_buck_mode(...)
-pmic_set_buck_mode(...)
Quoted 7 lines
Quoted 3 lines
To get the regulator device we can use two functions:
-pmic_get_by_name(...)
-pmic_get_by_interface(...)I've just got a few high-level comment on this series so will respond to each patch.
Ok
Quoted 78 lines
Quoted 78 lines
Main 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]>--- drivers/power/Makefile | 1 + drivers/power/regulator-uclass.c | 250 ++++++++++++++++++++++++++++++++++++ include/dm/uclass-id.h | 1 + include/power/pmic.h | 18 +++ include/power/regulator.h | 267 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 537 insertions(+)create mode 100644
drivers/power/regulator-uclass.ccreate mode 100644include/power/regulator.hdrivers/power/Makefile +1
-0@@ -22,3 +22,4 @@ obj-$(CONFIG_POWER_SPI) += power_spi.o obj-$(CONFIG_DM_PMIC_SPI) += pmic_spi.o obj-$(CONFIG_DM_PMIC_I2C) += pmic_i2c.o obj-$(CONFIG_DM_PMIC) += pmic-uclass.o +obj-$(CONFIG_DM_REGULATOR) += regulator-uclass.odrivers/power/regulator-uclass.c new file +43
-0@@ -0,0 +1,250 @@ +/* +* Copyright (C) 2014 Samsung Electronics +* Przemyslaw Marczak <[email protected]> +* +* SPDX-License-Identifier: GPL-2.0+ +*/ +#include <common.h> +#include <linux/types.h> +#include <fdtdec.h> +#include <power/pmic.h> +#include <i2c.h> +#include <compiler.h> +#include <dm.h> +#include <dm/device.h> +#include <dm/lists.h> +#include <dm/device-internal.h> +#include <errno.h> + +DECLARE_GLOBAL_DATA_PTR ; + +int pmic_ldo_cnt (struct udevice *dev) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_PMIC_REGULATOR ); +if (!ops) +return -ENODEV ; + +if (!ops->get_ldo_cnt) +return -EPERM ; + +return ops->get_ldo_cnt (dev); +} + +int pmic_buck_cnt (struct udevice *dev) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_PMIC_REGULATOR ); +if (!ops) +return -ENODEV ; + +if (!ops->get_buck_cnt)
Quoted 9 lines
drivers/power/regulator-uclass.c line 49
Quoted 6 lines
drivers/power/regulator-uclass.c new file +6
-0+return -EPERM ; + +return ops->get_buck_cnt (dev); +} + +struct regulator_desc *pmic_ldo_desc (struct udevice *dev,int ldo)I think these should return an error, with the struct * return as a parameter.
Ok, maybe this could be better.
Quoted 70 lines
Quoted 70 lines
drivers/power/regulator-uclass.c new file +70
-0+{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_PMIC_REGULATOR ); +if (!ops) +return NULL ; + +if (!ops->get_val_desc) +return NULL ; + +return ops->get_val_desc (dev,DESC_TYPE_LDO , ldo); +} + +struct regulator_desc *pmic_buck_desc (struct udevice *dev,int buck) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_PMIC_REGULATOR ); +if (!ops) +return NULL ; + +if (!ops->get_val_desc) +return NULL ; + +return ops->get_val_desc (dev,DESC_TYPE_BUCK , buck); +} + +struct regulator_mode_desc *pmic_ldo_mode_desc (struct udevice *dev,int ldo, +int *mode_cnt) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_PMIC_REGULATOR ); +if (!ops) +return NULL ; + +if (!ops->get_mode_desc_array) +return NULL ; + +return ops->get_mode_desc_array (dev,DESC_TYPE_LDO , ldo, mode_cnt); +} + +struct regulator_mode_desc *pmic_buck_mode_desc (struct udevice *dev,int buck, +int *mode_cnt) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_PMIC_REGULATOR ); +if (!ops) +return NULL ; + +if (!ops->get_mode_desc_array) +return NULL ; + +return ops->get_mode_desc_array (dev,DESC_TYPE_BUCK , buck, mode_cnt); +} + +int pmic_get_ldo_val (struct udevice *dev,int ldo) +{ +const struct dm_regulator_ops *ops; +int val =-1 ; + + ops =pmic_get_uclass_ops (dev,UCLASS_PMIC_REGULATOR ); +if (!ops) +return -ENODEV ; + +if (!ops->ldo_val) +return -EPERM ; + +if (ops->ldo_val (dev,PMIC_OP_GET , ldo, &val))
Quoted 9 lines
drivers/power/regulator-uclass.c line 124
Quoted 5 lines
drivers/power/regulator-uclass.c new file +5
-0+return -EIO ; + +return val; +} +Regards,
Simon
Thanks,
Signature · 4 lines
Przemyslaw Marczak Samsung R&D Institute Poland Samsung Electronics p.marczak at samsung.com
PATCH 6/19 dm: common: board_r: add call and weak of power_init_dm()
In reply to Przemyslaw MarczakThis function call is required to init dm pmic framework and drivers before call to power_init_board().
--- common/board_r.c | 8 ++++++++ 1 file changed, 8 insertions(+)
common/board_r.c +8 -0
@@ -285,6 +285,11 @@ __weak int power_init_board(void)return 0 ; } +__weak int pmic_init_dm (void ) +{ +return 0 ; +} +static int initr_announce (void ) {debug ("Now running in RAM - U-Boot at: %08lx\n" , gd->relocaddr);
@@ -775,6 +780,9 @@ init_fnc_t init_sequence_r[] = {#ifdef CONFIG_ARCH_EARLY_INIT_R arch_early_init_r,#endif +#ifdef CONFIG_DM_PMIC + pmic_init_dm, +#endif power_init_board,#ifndef CONFIG_SYS_NO_FLASH initr_flash,
Signature · 1 line
1.9.1
PATCH 6/19 dm: common: board_r: add call and weak of power_init_dm()
Hi,
Quoted 25 lines · Przemyslaw Marczak
This function call is required to init dm pmic framework and drivers before call to
power_init_board().Signed-off-by Przemyslaw Marczak <[email protected]>--- common/board_r.c | 8 ++++++++ 1 file changed, 8 insertions(+)common/board_r.c +5
-0@@ -285,6 +285,11 @@ __weak int power_init_board(void)return 0 ; } +__weak int pmic_init_dm (void ) +{ +return 0 ; +} +static int initr_announce (void ) {debug ("Now running in RAM - U-Boot at: %08lx\n" , gd->relocaddr);
common/board_r.c init_fnc_t init_sequence_r[] = { · line 785
Quoted 6 lines
common/board_r.c +3
-0@@ -775,6 +780,9 @@ init_fnc_t init_sequence_r[] = {#ifdef CONFIG_ARCH_EARLY_INIT_R arch_early_init_r,#endif +#ifdef CONFIG_DM_PMIC + pmic_init_dm, +#endif
Can the call to init this just go in initr_dm()?
Quoted 6 lines
common/board_r.c +0
-1power_init_board,#ifndef CONFIG_SYS_NO_FLASH initr_flash, --1.9.1
Regards,
Simon
PATCH 6/19 dm: common: board_r: add call and weak of power_init_dm()
Hello Simon,
Quoted 28 lines · Simon Glass
Hi,
Quoted 25 lines · Przemyslaw Marczak
This function call is required to init dm pmic framework and drivers before call to
power_init_board().Signed-off-by Przemyslaw Marczak <[email protected]>--- common/board_r.c | 8 ++++++++ 1 file changed, 8 insertions(+)common/board_r.c +5
-0@@ -285,6 +285,11 @@ __weak int power_init_board(void)return 0 ; } +__weak int pmic_init_dm (void ) +{ +return 0 ; +} +static int initr_announce (void ) {debug ("Now running in RAM - U-Boot at: %08lx\n" , gd->relocaddr);@@ -775,6 +780,9 @@ init_fnc_t init_sequence_r[] = {
Quoted 9 lines
common/board_r.c init_fnc_t init_sequence_r[] = { · line 785
Quoted 6 lines
common/board_r.c +3
-0#ifdef CONFIG_ARCH_EARLY_INIT_R arch_early_init_r,#endif +#ifdef CONFIG_DM_PMIC + pmic_init_dm, +#endif Can the call to init this just go in
initr_dm()?
Yes, it can, but if the I2C uclass code is ready soon - then probably we don't need this call.
Quoted 10 lines
Quoted 6 lines
common/board_r.c +0
-1power_init_board,#ifndef CONFIG_SYS_NO_FLASH initr_flash, --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 7/19 dm: pmic: add max77686 pmic driver
In reply to Przemyslaw MarczakThis adds a simple implementation of driver model uclass pmic driver. This implementation includes two funcitons:
- max77686_ofdata_to_platdada(...) - init I/O data from fdt
- max77686_probe(...) - looks for max77686 regulator driver and bind it
If there is no regulator driver, then pmic can still provide read/write operations, and can be accessed by 'pmic' commands.
--- drivers/power/pmic/Makefile | 1 + drivers/power/pmic/max77686.c | 89 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+) 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 +89 -0
89 lines not on this page · raw message
Signature · 1 line
1.9.1
PATCH 7/19 dm: pmic: add max77686 pmic driver
Quoted 9 lines · Przemyslaw Marczak
This adds a simple implementation of driver model uclass pmic driver. This implementation includes two funcitons:
-max77686_ofdata_to_platdada(...)- init I/O data from fdt
-max77686_probe(...)- looks for max77686 regulator driver and bind itIf there is no regulator driver, then pmic can still provide read/write operations, and can be accessed by 'pmic' commands.
Signed-off-by Przemyslaw Marczak <[email protected]>
[snip]
drivers/power/pmic/max77686.c line 43
Quoted 12 lines
drivers/power/pmic/max77686.c new file +12
-0+ parent =fdt_parent_offset (blob, node); + +if (parent <0 ) { +error ("%s: Cannot find node parent" , __func__); +return -EINVAL ; + } + + pl->bus =i2c_get_bus_num_fdt (parent); +if (pl->bus <0 ) { +debug ("%s: Cannot find bus num\n" , __func__); +return -EINVAL ; + }
Both of those should be error() and please note (and fix globally!) that error() already has __FILE__, __LINE__ and __func__ so you can drop those duplications.
Otherwise:
Signature · 8 lines
Tom -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 836 bytes Desc: Digital signature URL: <http://lists.denx.de/pipermail/u-boot/attachments/20141022/2098aa10/attachment.pgp>
PATCH 8/19 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
--- Makefile | 1 + drivers/power/Makefile | 1 - drivers/power/regulator/Makefile | 8 + drivers/power/regulator/max77686.c | 749 +++++++++++++++++++++++++++++++++++++ include/power/max77686_pmic.h | 28 +- 5 files changed, 781 insertions(+), 6 deletions(-) create mode 100644 drivers/power/regulator/Makefile create mode 100644 drivers/power/regulator/max77686.c
Makefile +1 -0
@@ -629,6 +629,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
@@ -13,7 +13,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 +749 -0
749 lines not on this page · raw message
include/power/max77686_pmic.h +23 -5
@@ -8,8 +8,6 @@#ifndef __MAX77686_H_#define __MAX77686_H_ -#include <power/pmic.h> -enum {MAX77686_REG_PMIC_ID =0x0 , MAX77686_REG_PMIC_INTSRC,
@@ -126,7 +124,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,22 +144,30 @@ 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_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#define MAX77686_BUCK_MODE_SHIFT_1 0x00#define MAX77686_BUCK_MODE_SHIFT_2 0x04
@@ -167,6 +176,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 8/19 dm: regulator: add max77686 regulator driver
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]>
[snip]
Quoted 4 lines
drivers/power/regulator/max77686.c new file +4
-0+if (ldo <1 || ldo >26 ) { +debug ("%s: %d is wrong ldo number\n" , __func__, ldo); +return -EINVAL ; + }
[snip]
Quoted 4 lines
drivers/power/regulator/max77686.c new file +4
-0+if (buck <1 || buck >9 ) { +debug ("%s: %d is wrong buck number\n" , __func__, buck); +return -EINVAL ; + }
[snip]
Quoted 4 lines
drivers/power/regulator/max77686.c new file +4
-0+if (ldo <1 || ldo >26 ) { +debug ("%s: %d is wrong ldo number\n" , __func__, ldo); +return -EINVAL ; + }
[snip]
Quoted 5 lines
drivers/power/regulator/max77686.c new file +5
-0+if (mode ==0xff ) { +debug ("%s: %d is not supported on LDO%d\n" , __func__, *opmode, + ldo); +return -EINVAL ; + }
[snip]
Quoted 4 lines
drivers/power/regulator/max77686.c new file +4
-0+if (buck <1 || buck >9 ) { +debug ("%s: %d is wrong buck number\n" , __func__, buck); +return -EINVAL ; + }
[snip]
drivers/power/regulator/max77686.c line 617
Quoted 5 lines
drivers/power/regulator/max77686.c new file +5
-0+if (mode ==0xff ) { +debug ("%s: %d is not supported on BUCK%d\n" , __func__, *opmode, + buck); +return -EINVAL ; + }
In my mind, all of these error messages are things the user would want to see because they passed the wrong value in, higher up in the chain, as these are eventually exposed at the cli, right? If so, they should be error() prints or otherwise changed around so it's clear to the user what they did wrong.
Signature · 8 lines
Tom -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 836 bytes Desc: Digital signature URL: <http://lists.denx.de/pipermail/u-boot/attachments/20141022/05169e9e/attachment.pgp>
PATCH 9/19 dm: pmic: new commands: pmic and regulator
In reply to Przemyslaw MarczakThis introduces new commands:
- pmic (new) - CONFIG_DM_PMIC
- regulator - CONFIG_DM_PMIC
Both uses a common code and dm pmic api.
To avoid code mess the old pmic command is kept without changes.
Command pmic
This is based on an old pmic command code - the new one uses driver model pmic api. The previous pmic I/O functionalities, stays unchanged. And now read/write is the main pmic command purpose. 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
The user interface is similar to the 'mmc' command.
Each pmic device driver should provide at least UCLASS_PMIC support, as a basic pmic device I/O interface.
Command regulator
The extension for 'pmic' command is 'regulator' command. This actually uses the same code, but provides an 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.
The regulator operations and required structures can be found in this header: 'include/power/regulator.h'
This was designed to allow safe I/O access to pmic device without the pmic documentation. If driver provide each regulator
- value and mode descriptor - then user can operate on it.
Command options (regulator [option]):
- list - list UCLASS regulator devices
- dev [id] - show or set current regulator device
- dump - dump registers of current regulator
- [ldo/buck][N] [name/state/desc]- print regulator(s) info
- [ldoN/buckN] [setval/setmode] [mV/modeN] [-f] - set val (mV) (forcibly) or mode - only if desc 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
!!And the next one can be risky!!
regulator ldo1 setval 1200 -f - if value exceeds limits - set force regulator ldo1 setmode 5 - set device ldo 1 mode to '5' (force no available)
The same for 'buck' regulators.
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, but the required voltage value can change, e.g. if some hardware uses pins header.
--- drivers/power/Makefile | 1 + drivers/power/cmd_pmic.c | 845 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 846 insertions(+) create mode 100644 drivers/power/cmd_pmic.c
drivers/power/Makefile +1 -0
@@ -20,5 +20,6 @@ obj-$(CONFIG_POWER_I2C) += power_i2c.o obj-$(CONFIG_POWER_SPI) += power_spi.o obj-$(CONFIG_DM_PMIC_SPI) += pmic_spi.o obj-$(CONFIG_DM_PMIC_I2C) += pmic_i2c.o +obj-$(CONFIG_DM_PMIC) += cmd_pmic.o obj-$(CONFIG_DM_PMIC) += pmic-uclass.o obj-$(CONFIG_DM_REGULATOR) += regulator-uclass.o
drivers/power/cmd_pmic.c new file +845 -0
845 lines not on this page · raw message
Signature · 1 line
1.9.1
PATCH 9/19 dm: pmic: new commands: pmic and regulator
Quoted 69 lines · Przemyslaw Marczak
This introduces new commands:
- pmic (new) -CONFIG_DM_PMIC
- regulator -CONFIG_DM_PMIC
Both uses a common code and dm pmic api.To avoid code mess the old pmic command is kept without changes.
Command pmic
This is based on an old pmic command code - the new one uses driver model pmic api. The previous pmic I/O functionalities, stays unchanged. And now read/write is the main pmic command purpose. This command can use onlyUCLASS_PMICdevices, 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
The user interface is similar to the 'mmc' command.
Each pmic device driver should provide at least
UCLASS_PMICsupport, as a basic pmic device I/O interface.Command regulator
The extension for 'pmic' command is 'regulator' command. This actually uses the same code, but provides an 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.
The regulator operations and required structures can be found in this header: '
include/power/regulator.h'This was designed to allow safe I/O access to pmic device without the pmic documentation. If driver provide each regulator
- value and mode descriptor - then user can operate on it.Command options (regulator [option]):
- list - list UCLASS regulator devices
- dev [id] - show or set current regulator device
- dump - dump registers of current regulator
- [ldo/buck][N] [name/state/desc]- print regulator(s) info
- [ldoN/buckN] [setval/setmode] [mV/modeN] [-f] - set val (mV) (forcibly) or mode - only if desc availableExample 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
!!And the next one can be risky!!
regulator ldo1 setval 1200 -f - if value exceeds limits - set force regulator ldo1 setmode 5 - set device ldo 1 mode to '5' (force no available)The same for 'buck' regulators.
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, but the required voltage value can change, e.g. if some hardware uses pins header.
Signed-off-by Przemyslaw Marczak <[email protected]>
[snip]
Quoted 4 lines
drivers/power/cmd_pmic.c new file +4
-0+if (ret <0 ) { +printf ("Error: %s\n" ,errno_str (ret)); +return CMD_RET_FAILURE ; + }
[snip]
drivers/power/cmd_pmic.c line 725
Quoted 5 lines
drivers/power/cmd_pmic.c new file +5
-0+finish: +if (ret <0 ) { +printf ("Error: %s\n" ,errno_str (ret)); +return CMD_RET_FAILURE ; + }
So, my main concern with this patch is we have here the only users of errno_str. In my reading over of the patch it looked like in nearly every case it was -ENODEV/-EINVAL and we had already printed a useful looking error message just before. Further, I'm not convinced (yet!) that the errno print is adding to the utility in discovering what was passed in wrong. Can you please re-work this patch to not need errno_str(), ensure that errors still print _something_ and see what the delta is, both in binary and lines of code? Thanks!
Signature · 8 lines
Tom -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 836 bytes Desc: Digital signature URL: <http://lists.denx.de/pipermail/u-boot/attachments/20141022/cf9e34b5/attachment.pgp>
PATCH 10/19 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 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
board/samsung/common/board.c +1 -1
@@ -166,7 +166,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 11/19 doc: driver-model: pmic and regulator uclass documentation
In reply to Przemyslaw Marczak--- doc/driver-model/dm-pmic-framework.txt | 450 +++++++++++++++++++++++++++++++++ 1 file changed, 450 insertions(+) create mode 100644 doc/driver-model/dm-pmic-framework.txt
doc/driver-model/dm-pmic-framework.txt new file +450 -0
@@ -0,0 +1,450 @@ +# +# (C) Copyright 2014 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. Driver API +4. Simple UCLASS_PMIC driver +5. Pmic command +6. Uclass UCLASS_PMIC_REGULATOR API +7. Simple UCLASS_PMIC_REGULATOR driver +8. Regulator command + +1. Introduction +=============== +This is an introduction to driver-model multi class PMIC support. +It starts with UCLASS_PMIC - a common PMIC class type for I/O, which +doesn't need to implement any specific operations and features beside +the platform data, which is a 'struct pmic_platdata' defined in file: +- 'include/power/pmic.h' + +New files: +- pmic-uclass.c - provides a common code for UCLASS_PMIC drivers +- pmic_i2c.c - provides dm interface for i2c pmic drivers +- pmic_spi.c - provides dm interface for spi pmic drivers + +Those files are based on a current PMIC framework files and code. +And the new files are introduced to avoid code mess and allow to +make an easy drivers migration. The old pmic is still kept. + +Changes: +- add uclass-id: UCLASS_PMIC +- add new configs: + CONFIG_DM_PMIC - enables driver model pmic framework and requires one + or both of: + CONFIG_DM_PMIC_SPI - enables an interface to pmic SPI + CONFIG_DM_PMIC_I2C - enables an interface to pmic I2C + +The old pmic interface API worked very well so it is kept, but the framework +architecture is changed. + +2. How doees it work +==================== +The framework init starts in file: drivers/power/pmic-uclass.c +The function pmic_init_dm() looks after the 'pmic' alias in the device-tree +and do the driver bind. +If board uses more than one PMIC device, then a few 'pmic' aliases should +be defined with numbers, e.g. pmic0, pmic1... + +Note: +The I2C doesn't use the driver model yet, so the drivers are bind thanks to the +'pmic' alias. + +3. PMIC drivers API +=================== +The new API is as simple as previously: + +File: drivers/power/pmic-uclass.c: +- void power_init_dm(void) + The main init function, called after the i2c init and before power_init_board. + Bind the UCLASS_PMIC drivers. + +- struct udevice *pmic_get_by_name(int uclass_id, char *name) + This function provides similar function as old pmic_get(), but the returned + device pointer doesn't require any allocation. + The uclass_id argument if to chose proper device uclass, e.g. pmic or next + others, pmic related. + +- struct udevice *pmic_get_by_interface(int uclass_id, int bus, int addr_cs) + This is similar function as previous but is designed for boards with more + than one pmic device or the same device instances. In this case we can't + get the device by the name, so the best and accurate method is to get it by + known uclass, bus and address or cs(spi). This is new framework feature. + +- const char *pmic_if_str(int interface) + This function returns the interface name string for i2c or spi, and uses + pmic interface enum from: include/power/pmic.h + +- int pmic_check_reg(struct pmic_platdata *p, unsigned reg) + This function check if the given register number is valid for the given + pmic_platdata. + +- int pmic_reg_write(struct udevice *dev, unsigned reg, unsigned val) + The same functionality as in old framework but changed to driver-model. + +- int pmic_reg_read(struct udevice *dev, unsigned reg, unsigned *val) + The same functionality as in old framework but changed to driver-model. + +- int pmic_probe(struct udevice *dev, struct spi_slave *spi_slave) + The same functionality as in an old framework but changed to driver model, + and extended by support to both pmic interfaces. + +The below functions, are implemented with use of common calls, described above. + +File: drivers/power/pmic_i2c.c: +- int pmic_i2c_reg_write(struct udevice *dev, unsigned reg, unsigned val) +- int pmic_i2c_reg_read(struct udevice *dev, unsigned reg, unsigned *val) +- int pmic_i2c_probe(struct udevice *dev) + +File: drivers/power/pmic_spi.c: +- int pmic_spi_reg_write(struct udevice *dev, unsigned reg, unsigned val) +- int pmic_spi_reg_read(struct udevice *dev, unsigned reg, unsigned *val) +- struct spi_slave *pmic_spi_probe(struct udevice *dev) + +4. Simple UCLASS_PMIC driver +============================ +At this stage the framework supports only drivers that have proper fdt alias. +The alias is "pmic" or "pmicN". + +The exaple of dts node(): + aliases { + ... + ... + pmic0 = &simple_pmic0; + } + + i2c at some_addr { + ; some i2c data + + simple_pmic0: simple_pmic at 09 { + compatible = "vandor, simple_pmic"; + reg = <0x09 0 0>; + } + +The exaple of driver code: + +/** + * simple_pmic_probe(...) - this function is optional and is a preffered way + * to bind the "simple regulator" device. + * Than we have: + * device: "simple_pmic" - provides device I/O + * device: "simple regulator" - provides regualtor operations and is binded + * as a child of "simple_pmic" + */ +static int simple_pmic_probe(struct udevice *parent) +{ + struct udevice *reg_dev; + struct driver *reg_drv; + int ret; + + reg_drv = lists_driver_lookup_name("simple regulator"); + if (!reg_drv) { + error("%s regulator driver not found!\n", parent->name); + return 0; + } + + if (!parent->platdata) { + error("%s platdata not found!\n", parent->name); + return -EINVAL; + } + + ret = device_bind(parent, reg_drv, parent->name, parent->platdata, + parent->of_offset, ®_dev); + if (ret) + error("%s regulator bind failed", parent->name); + + /** + * Return an error only if no parent platdata set + * so if no regulator found - still have pmic I/O. + * This scheme will be used in most board configs. + */ + return 0; +} + +static int simple_pmic_ofdata_to_platdata(struct udevice *dev) +{ + struct pmic_platdata *pl = dev->platdata; + + /** + * Here, driver should init the platdata structure based on device-tree, + * The fields bus, interface, byte_order and the struct spi or i2c, + * provide information about I/O acces, so are required. + */ + const void *blob = gd->fdt_blob; + int node = dev->of_offset; + int parent; + + pl->interface = PMIC_I2C; + pl->regs_num = PMIC_NUM_OF_REGS; + + parent = fdt_parent_offset(blob, node); + + if (parent < 0) { + error("%s: Cannot find node parent", __func__); + return -EINVAL; + } + + pl->bus = i2c_get_bus_num_fdt(parent); + if (pl->bus < 0) { + debug("%s: Cannot find bus num\n", __func__); + return -EINVAL; + } + + pl->hw.i2c.addr = fdtdec_get_int(blob, node, "reg", SIMPLE_PMIC_I2C_ADDR); + pl->hw.i2c.tx_num = 1; + + return 0; +} + +static const struct udevice_id simple_pmic_ids[] = { + { .compatible = "vendor,simple_pmic"}, + { } +}; + +U_BOOT_DRIVER(simple_pmic) = { + .name = "simple pmic", + .id = UCLASS_PMIC, + .of_match = simple_pmic_ids, + .probe = simple_pmic_probe, + .ofdata_to_platdata = simple_pmic_ofdata_to_platdata, + .platdata_auto_alloc_size = sizeof(struct pmic_platdata), +}; + +5. Pmic command +=============== +This is based on an old pmic command code - the new one uses +the driver model pmic API. The previous pmic I/O functionalities, +stays unchanged. And now read/write is the main pmic command +purpose. 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 3 - set dev 3 as current device +# pmic dump - dump the registers of pmic dev id 3 +# pmic read 0x0 - read the register of addres 0x0 +# pmic write 0x0 0x1 - write 0x1 to the register of addres 0x0 + +The user interface is similar to the 'mmc' command. + +Each pmic device driver should provide at least UCLASS_PMIC support, +as a basic pmic device I/O interface. + +6. Uclass UCLASS_PMIC_REGULATOR API +=================================== +To use the regulator API, config: CONFIG_DM_REGULATOR is required. + +Driver API is simple and clear: +To get the regulator device we can use two functions: +- pmic_get_by_name(...) +- pmic_get_by_interface(...) + +This returns "struct udevice *" pointer to uclass regulator device, +which can provide API functions. + +To operate on device regulators, we can use API functions +(if provided by the driver): +- pmic_ldo_cnt(...) +- pmic_buck_cnt(...) +- pmic_get_ldo_val(...) +- pmic_set_ldo_val(...) +- pmic_get_ldo_mode(...) +- pmic_set_ldo_mode(...) +- pmic_get_buck_val(...) +- pmic_set_buck_val(...) +- pmic_get_buck_mode(...) +- pmic_set_buck_mode(...) + +For detailed description please look into the file: +- include/power/regulator.h + +7. Simple UCLASS_PMIC_REGULATOR driver +====================================== +The regulator ops implementation can be different for each driver, +so this is only a piece of driver design. +As a reference, please take the MAX77686 pmic and regulator drivers. +- drivers/power/pmic/max77686.c +- drivers/power/regulator/max77686.c + +The regulator driver code should look like below: +(Please read the 'include/power/regulator.h' for more details) + +Note: +The regulator device should act as a child of pmic device. +This is a natural scheme of a physical PMIC IC: + +Some PMIC physical IC: + |_ dev pmic (parent) - simple and sufficient for the most board configs + |_ dev regulator (child) - provide regulator operations + |_ dev other (child) - some other pmic uclasses, (in the future) + +struct regulator_desc *simple_regulator_get_val_desc(struct udevice *dev, + int d_type, int d_num) +{ + /* Here returns regulator value descriptor */ + return NULL; +} + +static struct regulator_mode_desc * +simple_regulator_get_mode_desc_array(struct udevice *dev, int d_type, int d_num, + int *d_mode_cnt) +{ + /* Here return arra of mode descriptors for given device */ + return NULL; +} + +static int simple_regulator_get_ldo_cnt(struct udevice *dev) +{ + /* Here return regulators ldo count */ + return 0; +} + +static int simple_regulator_get_buck_cnt(struct udevice *dev) +{ + /* Here return regulator buck count */ + return 0; +} + +static int simple_regulator_ldo_val(struct udevice *dev, int op, + int ldo, int *uV) +{ + /* Here return or sets given ldo value in uV */ + return 0; +} + +static int simple_regulator_buck_val(struct udevice *dev, int op, + int buck, int *uV) +{ + /* Here return or sets given buck value in uV */ + return 0; +} + +static int simple_regulator_ldo_mode(struct udevice *dev, int op, int ldo, + int *opmode) +{ + /* Here return or sets regulator ldo mode */ + return 0; +} + +static int simple_regulator_buck_mode(struct udevice *dev, int op, int buck, + int *opmode) +{ + /* Here return or sets regulator buck mode */ + return 0; +} + +static int simple_regulator_ofdata_to_platdata(struct udevice *dev) +{ + /** + * PMIC Interface, Case 1: common + * If PMIC uses only one (SPI/I2C) physical interface for driving + * it's functionalities. + * + * Then the bind of "simple regulator" device in the "simple pmic" probe + * is called with args: + * ret = device_bind(parent, reg_drv, parent->name, parent->platdata, + * parent->of_offset, ®_dev); + */ + + /** + * PMIC Interface, case 2: independent + * If PMIC uses more then one (SPI/I2C) physical interfaces for driving + * it's functionalities. + * + * Then the bind of "simple regulator" device in the "simple pmic" + * drivers 'probe', is called with args: + * ret = device_bind(parent, reg_drv, parent->name, NULL, + * regulator_fdt_of_offset, ®_dev); + * + * In this case "driver.platdata_auto_alloc_size" + */ + + /** + * Here driver should get the 'regulator-voltage' node data + * into a proper descriptors. + * Actually there is no standard voltage description in dts, + * but please check trats2 or odroid dts files and regulator/max77686.c + * driver file to check some simple solution. + * + */ + return 0; +} + +static const struct dm_regulator_ops simple_regulator_ops = { + .get_ldo_cnt = simple_regulator_get_ldo_cnt, + .get_buck_cnt = simple_regulator_get_buck_cnt, + .get_val_desc = simple_regulator_get_val_desc, + .get_mode_desc_array = simple_regulator_get_mode_desc_array, + .ldo_val = simple_regulator_ldo_val, + .buck_val = simple_regulator_buck_val, + .ldo_mode = simple_regulator_ldo_mode, + .buck_mode = simple_regulator_buck_mode, +}; + +U_BOOT_DRIVER(simple_regulator) = { + .name = "simple regulator", + .id = UCLASS_PMIC_REGULATOR, + .ops = &simple_regulator_ops, + .ofdata_to_platdata = reg_simple_regulator_ofdata_to_platdata, + .priv_auto_alloc_size = sizeof(struct simple_regulator_info), + + /** + * .platdata_auto_alloc_size - is optional, only if regulator uses + * a different interface than parent pmic. + */ + .platdata_auto_alloc_size = sizeof(struct pmic_platdata), +}; + +8. Regulator command +==================== +The extension for 'pmic' command is a 'regulator' command. +This actually uses the same code, but provides an 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 pmic device +without the pmic documentation. If driver provide each regulator +- value and mode descriptor - then user can operate on it. + +Command options (regulator [option]): +- list - list UCLASS regulator devices +- dev [id] - show or set current regulator device +- dump - dump registers of current regulator +- [ldo/buck][N] [name/state/desc]- print regulator(s) info +- [ldoN/buckN] [setval/setmode] [mV/modeN] [-f] - set val (mV) +(forcibly) or mode - only if desc 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' (force no available) + +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 11/19 doc: driver-model: pmic and regulator uclass documentation
Hi,
Quoted 161 lines · Przemyslaw Marczak
Signed-off-by Przemyslaw Marczak <[email protected]>--- doc/driver-model/dm-pmic-framework.txt | 450 +++++++++++++++++++++++++++++++++ 1 file changed, 450 insertions(+) create mode 100644 doc/driver-model/dm-pmic-framework.txtdoc/driver-model/dm-pmic-framework.txt new file +149
-0@@ -0,0 +1,450 @@ +# +# (C) Copyright 2014 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. Driver API +4. Simple UCLASS_PMIC driver +5. Pmic command +6. Uclass UCLASS_PMIC_REGULATOR API +7. Simple UCLASS_PMIC_REGULATOR driver +8. Regulator command + +1. Introduction +=============== +This is an introduction to driver-model multi class PMIC support. +It starts with UCLASS_PMIC - a common PMIC class type for I/O, which +doesn't need to implement any specific operations and features beside +the platform data, which is a 'struct pmic_platdata' defined in file: +- 'include/power/pmic.h' + +New files: +- pmic-uclass.c - provides a common code for UCLASS_PMIC drivers +- pmic_i2c.c - provides dm interface for i2c pmic drivers +- pmic_spi.c - provides dm interface for spi pmic drivers + +Those files are based on a current PMIC framework files and code. +And the new files are introduced to avoid code mess and allow to +make an easy drivers migration. The old pmic is still kept. + +Changes: +- add uclass-id: UCLASS_PMIC +- add new configs: + CONFIG_DM_PMIC - enables driver model pmic framework and requires one + or both of: + CONFIG_DM_PMIC_SPI - enables an interface to pmic SPI + CONFIG_DM_PMIC_I2C - enables an interface to pmic I2C + +The old pmic interface API worked very well so it is kept, but the framework +architecture is changed. + +2. How doees it work +==================== +The framework init starts in file: drivers/power/pmic-uclass.c +The function pmic_init_dm() looks after the 'pmic' alias in the device-tree +and do the driver bind. +If board uses more than one PMIC device, then a few 'pmic' aliases should +be defined with numbers, e.g. pmic0, pmic1... + +Note: +The I2C doesn't use the driver model yet, so the drivers are bind thanks to the +'pmic' alias. + +3. PMIC drivers API +=================== +The new API is as simple as previously: + +File: drivers/power/pmic-uclass.c: +- void power_init_dm(void) + The main init function, called after the i2c init and before power_init_board. + Bind the UCLASS_PMIC drivers. + +- struct udevice *pmic_get_by_name(int uclass_id, char *name) + This function provides similar function as old pmic_get(), but the returned + device pointer doesn't require any allocation. + The uclass_id argument if to chose proper device uclass, e.g. pmic or next + others, pmic related. + +- struct udevice *pmic_get_by_interface(int uclass_id, int bus, int addr_cs) + This is similar function as previous but is designed for boards with more + than one pmic device or the same device instances. In this case we can't + get the device by the name, so the best and accurate method is to get it by + known uclass, bus and address or cs(spi). This is new framework feature. + +- const char *pmic_if_str(int interface) + This function returns the interface name string for i2c or spi, and uses + pmic interface enum from: include/power/pmic.h + +- int pmic_check_reg(struct pmic_platdata *p, unsigned reg) + This function check if the given register number is valid for the given + pmic_platdata. + +- int pmic_reg_write(struct udevice *dev, unsigned reg, unsigned val) + The same functionality as in old framework but changed to driver-model. + +- int pmic_reg_read(struct udevice *dev, unsigned reg, unsigned *val) + The same functionality as in old framework but changed to driver-model. + +- int pmic_probe(struct udevice *dev, struct spi_slave *spi_slave) + The same functionality as in an old framework but changed to driver model, + and extended by support to both pmic interfaces. + +The below functions, are implemented with use of common calls, described above. + +File: drivers/power/pmic_i2c.c: +- int pmic_i2c_reg_write(struct udevice *dev, unsigned reg, unsigned val) +- int pmic_i2c_reg_read(struct udevice *dev, unsigned reg, unsigned *val) +- int pmic_i2c_probe(struct udevice *dev) + +File: drivers/power/pmic_spi.c: +- int pmic_spi_reg_write(struct udevice *dev, unsigned reg, unsigned val) +- int pmic_spi_reg_read(struct udevice *dev, unsigned reg, unsigned *val) +- struct spi_slave *pmic_spi_probe(struct udevice *dev) + +4. Simple UCLASS_PMIC driver +============================ +At this stage the framework supports only drivers that have proper fdt alias. +The alias is "pmic" or "pmicN". + +The exaple of dts node(): + aliases { + ... + ... + pmic0 = &simple_pmic0; + } + + i2c at some_addr { + ; some i2c data + + simple_pmic0: simple_pmic at 09 { + compatible = "vandor, simple_pmic"; + reg = <0x09 0 0>; + } + +The exaple of driver code: + +/** + * simple_pmic_probe(...) - this function is optional and is a preffered way + * to bind the "simple regulator" device. + * Than we have: + * device: "simple_pmic" - provides device I/O + * device: "simple regulator" - provides regualtor operations and is binded + * as a child of "simple_pmic" + */ +static int simple_pmic_probe(struct udevice *parent) +{ + struct udevice *reg_dev; + struct driver *reg_drv; + int ret; + + reg_drv = lists_driver_lookup_name("simple regulator"); + if (!reg_drv) { + error("%s regulator driver not found!\n", parent->name);
doc/driver-model/dm-pmic-framework.txt line 159
Quoted 10 lines
doc/driver-model/dm-pmic-framework.txt new file +10
-0+ return 0; + } + + if (!parent->platdata) { + error("%s platdata not found!\n", parent->name); + return -EINVAL; + } + + ret = device_bind(parent, reg_drv, parent->name, parent->platdata, + parent->of_offset, ®_dev);
I wonder if we can avoid this? Really the regulator should be bound at init time, and this function should use something like uclass_get_device_by_of_offset() to find it.
Quoted 292 lines
doc/driver-model/dm-pmic-framework.txt new file +291
-1+ if (ret) + error("%s regulator bind failed", parent->name); + + /** + * Return an error only if no parent platdata set + * so if no regulator found - still have pmic I/O. + * This scheme will be used in most board configs. + */ + return 0; +} + +static int simple_pmic_ofdata_to_platdata(struct udevice *dev) +{ + struct pmic_platdata *pl = dev->platdata; + + /** + * Here, driver should init the platdata structure based on device-tree, + * The fields bus, interface, byte_order and the struct spi or i2c, + * provide information about I/O acces, so are required. + */ + const void *blob = gd->fdt_blob; + int node = dev->of_offset; + int parent; + + pl->interface = PMIC_I2C; + pl->regs_num = PMIC_NUM_OF_REGS; + + parent = fdt_parent_offset(blob, node); + + if (parent < 0) { + error("%s: Cannot find node parent", __func__); + return -EINVAL; + } + + pl->bus = i2c_get_bus_num_fdt(parent); + if (pl->bus < 0) { + debug("%s: Cannot find bus num\n", __func__); + return -EINVAL; + } + + pl->hw.i2c.addr = fdtdec_get_int(blob, node, "reg", SIMPLE_PMIC_I2C_ADDR); + pl->hw.i2c.tx_num = 1; + + return 0; +} + +static const struct udevice_id simple_pmic_ids[] = { + { .compatible = "vendor,simple_pmic"}, + { } +}; + +U_BOOT_DRIVER(simple_pmic) = { + .name = "simple pmic", + .id = UCLASS_PMIC, + .of_match = simple_pmic_ids, + .probe = simple_pmic_probe, + .ofdata_to_platdata = simple_pmic_ofdata_to_platdata, + .platdata_auto_alloc_size = sizeof(struct pmic_platdata), +}; + +5. Pmic command +=============== +This is based on an old pmic command code - the new one uses +the driver model pmic API. The previous pmic I/O functionalities, +stays unchanged. And now read/write is the main pmic command +purpose. 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 3 - set dev 3 as current device +# pmic dump - dump the registers of pmic dev id 3 +# pmic read 0x0 - read the register of addres 0x0 +# pmic write 0x0 0x1 - write 0x1 to the register of addres 0x0 + +The user interface is similar to the 'mmc' command. + +Each pmic device driver should provide at least UCLASS_PMIC support, +as a basic pmic device I/O interface. + +6. Uclass UCLASS_PMIC_REGULATOR API +=================================== +To use the regulator API, config: CONFIG_DM_REGULATOR is required. + +Driver API is simple and clear: +To get the regulator device we can use two functions: +- pmic_get_by_name(...) +- pmic_get_by_interface(...) + +This returns "struct udevice *" pointer to uclass regulator device, +which can provide API functions. + +To operate on device regulators, we can use API functions +(if provided by the driver): +- pmic_ldo_cnt(...) +- pmic_buck_cnt(...) +- pmic_get_ldo_val(...) +- pmic_set_ldo_val(...) +- pmic_get_ldo_mode(...) +- pmic_set_ldo_mode(...) +- pmic_get_buck_val(...) +- pmic_set_buck_val(...) +- pmic_get_buck_mode(...) +- pmic_set_buck_mode(...) + +For detailed description please look into the file: +- include/power/regulator.h + +7. Simple UCLASS_PMIC_REGULATOR driver +====================================== +The regulator ops implementation can be different for each driver, +so this is only a piece of driver design. +As a reference, please take the MAX77686 pmic and regulator drivers. +- drivers/power/pmic/max77686.c +- drivers/power/regulator/max77686.c + +The regulator driver code should look like below: +(Please read the 'include/power/regulator.h' for more details) + +Note: +The regulator device should act as a child of pmic device. +This is a natural scheme of a physical PMIC IC: + +Some PMIC physical IC: + |_ dev pmic (parent) - simple and sufficient for the most board configs + |_ dev regulator (child) - provide regulator operations + |_ dev other (child) - some other pmic uclasses, (in the future) + +struct regulator_desc *simple_regulator_get_val_desc(struct udevice *dev, + int d_type, int d_num) +{ + /* Here returns regulator value descriptor */ + return NULL; +} + +static struct regulator_mode_desc * +simple_regulator_get_mode_desc_array(struct udevice *dev, int d_type, int d_num, + int *d_mode_cnt) +{ + /* Here return arra of mode descriptors for given device */ + return NULL; +} + +static int simple_regulator_get_ldo_cnt(struct udevice *dev) +{ + /* Here return regulators ldo count */ + return 0; +} + +static int simple_regulator_get_buck_cnt(struct udevice *dev) +{ + /* Here return regulator buck count */ + return 0; +} + +static int simple_regulator_ldo_val(struct udevice *dev, int op, + int ldo, int *uV) +{ + /* Here return or sets given ldo value in uV */ + return 0; +} + +static int simple_regulator_buck_val(struct udevice *dev, int op, + int buck, int *uV) +{ + /* Here return or sets given buck value in uV */ + return 0; +} + +static int simple_regulator_ldo_mode(struct udevice *dev, int op, int ldo, + int *opmode) +{ + /* Here return or sets regulator ldo mode */ + return 0; +} + +static int simple_regulator_buck_mode(struct udevice *dev, int op, int buck, + int *opmode) +{ + /* Here return or sets regulator buck mode */ + return 0; +} + +static int simple_regulator_ofdata_to_platdata(struct udevice *dev) +{ + /** + * PMIC Interface, Case 1: common + * If PMIC uses only one (SPI/I2C) physical interface for driving + * it's functionalities. + * + * Then the bind of "simple regulator" device in the "simple pmic" probe + * is called with args: + * ret = device_bind(parent, reg_drv, parent->name, parent->platdata, + * parent->of_offset, ®_dev); + */ + + /** + * PMIC Interface, case 2: independent + * If PMIC uses more then one (SPI/I2C) physical interfaces for driving + * it's functionalities. + * + * Then the bind of "simple regulator" device in the "simple pmic" + * drivers 'probe', is called with args: + * ret = device_bind(parent, reg_drv, parent->name, NULL, + * regulator_fdt_of_offset, ®_dev); + * + * In this case "driver.platdata_auto_alloc_size" + */ + + /** + * Here driver should get the 'regulator-voltage' node data + * into a proper descriptors. + * Actually there is no standard voltage description in dts, + * but please check trats2 or odroid dts files and regulator/max77686.c + * driver file to check some simple solution. + * + */ + return 0; +} + +static const struct dm_regulator_ops simple_regulator_ops = { + .get_ldo_cnt = simple_regulator_get_ldo_cnt, + .get_buck_cnt = simple_regulator_get_buck_cnt, + .get_val_desc = simple_regulator_get_val_desc, + .get_mode_desc_array = simple_regulator_get_mode_desc_array, + .ldo_val = simple_regulator_ldo_val, + .buck_val = simple_regulator_buck_val, + .ldo_mode = simple_regulator_ldo_mode, + .buck_mode = simple_regulator_buck_mode, +}; + +U_BOOT_DRIVER(simple_regulator) = { + .name = "simple regulator", + .id = UCLASS_PMIC_REGULATOR, + .ops = &simple_regulator_ops, + .ofdata_to_platdata = reg_simple_regulator_ofdata_to_platdata, + .priv_auto_alloc_size = sizeof(struct simple_regulator_info), + + /** + * .platdata_auto_alloc_size - is optional, only if regulator uses + * a different interface than parent pmic. + */ + .platdata_auto_alloc_size = sizeof(struct pmic_platdata), +}; + +8. Regulator command +==================== +The extension for 'pmic' command is a 'regulator' command. +This actually uses the same code, but provides an 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 pmic device +without the pmic documentation. If driver provide each regulator +- value and mode descriptor - then user can operate on it. + +Command options (regulator [option]): +- list - list UCLASS regulator devices +- dev [id] - show or set current regulator device +- dump - dump registers of current regulator +- [ldo/buck][N] [name/state/desc]- print regulator(s) info +- [ldoN/buckN] [setval/setmode] [mV/modeN] [-f] - set val (mV) +(forcibly) or mode - only if desc 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' (force no available) + +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
Regards,
Simon
PATCH 11/19 doc: driver-model: pmic and regulator uclass documentation
Hello,
Quoted 170 lines · Simon Glass
Hi,
Quoted 167 lines · Przemyslaw Marczak
Signed-off-by Przemyslaw Marczak <[email protected]>--- doc/driver-model/dm-pmic-framework.txt | 450 +++++++++++++++++++++++++++++++++ 1 file changed, 450 insertions(+)create mode 100644
doc/driver-model/dm-pmic-framework.txtdoc/driver-model/dm-pmic-framework.txt new file +155
-0@@ -0,0 +1,450 @@ +# +# (C) Copyright 2014 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. Driver API +4. Simple UCLASS_PMIC driver +5. Pmic command +6. Uclass UCLASS_PMIC_REGULATOR API +7. Simple UCLASS_PMIC_REGULATOR driver +8. Regulator command + +1. Introduction +=============== +This is an introduction to driver-model multi class PMIC support. +It starts with UCLASS_PMIC - a common PMIC class type for I/O, which +doesn't need to implement any specific operations and features beside +the platform data, which is a 'struct pmic_platdata' defined in file: +- 'include/power/pmic.h' + +New files: +- pmic-uclass.c - provides a common code for UCLASS_PMIC drivers +- pmic_i2c.c - provides dm interface for i2c pmic drivers +- pmic_spi.c - provides dm interface for spi pmic drivers + +Those files are based on a current PMIC framework files and code. +And the new files are introduced to avoid code mess and allow to +make an easy drivers migration. The old pmic is still kept. + +Changes: +- add uclass-id: UCLASS_PMIC +- add new configs: + CONFIG_DM_PMIC - enables driver model pmic framework and requires one + or both of: + CONFIG_DM_PMIC_SPI - enables an interface to pmic SPI + CONFIG_DM_PMIC_I2C - enables an interface to pmic I2C + +The old pmic interface API worked very well so it is kept, but the framework +architecture is changed. + +2. How doees it work +==================== +The framework init starts in file: drivers/power/pmic-uclass.c +The function pmic_init_dm() looks after the 'pmic' alias in the device-tree +and do the driver bind. +If board uses more than one PMIC device, then a few 'pmic' aliases should +be defined with numbers, e.g. pmic0, pmic1... + +Note: +The I2C doesn't use the driver model yet, so the drivers are bind thanks to the +'pmic' alias. + +3. PMIC drivers API +=================== +The new API is as simple as previously: + +File: drivers/power/pmic-uclass.c: +- void power_init_dm(void) + The main init function, called after the i2c init and before power_init_board. + Bind the UCLASS_PMIC drivers. + +- struct udevice *pmic_get_by_name(int uclass_id, char *name) + This function provides similar function as old pmic_get(), but the returned + device pointer doesn't require any allocation. + The uclass_id argument if to chose proper device uclass, e.g. pmic or next + others, pmic related. + +- struct udevice *pmic_get_by_interface(int uclass_id, int bus, int addr_cs) + This is similar function as previous but is designed for boards with more + than one pmic device or the same device instances. In this case we can't + get the device by the name, so the best and accurate method is to get it by + known uclass, bus and address or cs(spi). This is new framework feature. + +- const char *pmic_if_str(int interface) + This function returns the interface name string for i2c or spi, and uses + pmic interface enum from: include/power/pmic.h + +- int pmic_check_reg(struct pmic_platdata *p, unsigned reg) + This function check if the given register number is valid for the given + pmic_platdata. + +- int pmic_reg_write(struct udevice *dev, unsigned reg, unsigned val) + The same functionality as in old framework but changed to driver-model. + +- int pmic_reg_read(struct udevice *dev, unsigned reg, unsigned *val) + The same functionality as in old framework but changed to driver-model. + +- int pmic_probe(struct udevice *dev, struct spi_slave *spi_slave) + The same functionality as in an old framework but changed to driver model, + and extended by support to both pmic interfaces. + +The below functions, are implemented with use of common calls, described above. + +File: drivers/power/pmic_i2c.c: +- int pmic_i2c_reg_write(struct udevice *dev, unsigned reg, unsigned val) +- int pmic_i2c_reg_read(struct udevice *dev, unsigned reg, unsigned *val) +- int pmic_i2c_probe(struct udevice *dev) + +File: drivers/power/pmic_spi.c: +- int pmic_spi_reg_write(struct udevice *dev, unsigned reg, unsigned val) +- int pmic_spi_reg_read(struct udevice *dev, unsigned reg, unsigned *val) +- struct spi_slave *pmic_spi_probe(struct udevice *dev) + +4. Simple UCLASS_PMIC driver +============================ +At this stage the framework supports only drivers that have proper fdt alias. +The alias is "pmic" or "pmicN". + +The exaple of dts node(): + aliases { + ... + ... + pmic0 = &simple_pmic0; + } + + i2c at some_addr { + ; some i2c data + + simple_pmic0: simple_pmic at 09 { + compatible = "vandor, simple_pmic"; + reg = <0x09 0 0>; + } + +The exaple of driver code: + +/** + * simple_pmic_probe(...) - this function is optional and is a preffered way + * to bind the "simple regulator" device. + * Than we have: + * device: "simple_pmic" - provides device I/O + * device: "simple regulator" - provides regualtor operations and is binded + * as a child of "simple_pmic" + */ +static int simple_pmic_probe(struct udevice *parent) +{ + struct udevice *reg_dev; + struct driver *reg_drv; + int ret; + + reg_drv = lists_driver_lookup_name("simple regulator"); + if (!reg_drv) { + error("%s regulator driver not found!\n", parent->name); + return 0; + } + + if (!parent->platdata) { + error("%s platdata not found!\n", parent->name); + return -EINVAL;
Quoted 9 lines
doc/driver-model/dm-pmic-framework.txt line 159
Quoted 4 lines
doc/driver-model/dm-pmic-framework.txt new file +4
-0+ } + + ret = device_bind(parent, reg_drv, parent->name, parent->platdata, + parent->of_offset, ®_dev);I wonder if we can avoid this? Really the regulator should be bound at init time, and this function should use something like
uclass_get_device_by_of_offset()to find it.
Yes, if I2C class will be ready, then we can simplify this, but for now it is simple.
Quoted 289 lines
Quoted 289 lines
doc/driver-model/dm-pmic-framework.txt new file +289
-0+ if (ret) + error("%s regulator bind failed", parent->name); + + /** + * Return an error only if no parent platdata set + * so if no regulator found - still have pmic I/O. + * This scheme will be used in most board configs. + */ + return 0; +} + +static int simple_pmic_ofdata_to_platdata(struct udevice *dev) +{ + struct pmic_platdata *pl = dev->platdata; + + /** + * Here, driver should init the platdata structure based on device-tree, + * The fields bus, interface, byte_order and the struct spi or i2c, + * provide information about I/O acces, so are required. + */ + const void *blob = gd->fdt_blob; + int node = dev->of_offset; + int parent; + + pl->interface = PMIC_I2C; + pl->regs_num = PMIC_NUM_OF_REGS; + + parent = fdt_parent_offset(blob, node); + + if (parent < 0) { + error("%s: Cannot find node parent", __func__); + return -EINVAL; + } + + pl->bus = i2c_get_bus_num_fdt(parent); + if (pl->bus < 0) { + debug("%s: Cannot find bus num\n", __func__); + return -EINVAL; + } + + pl->hw.i2c.addr = fdtdec_get_int(blob, node, "reg", SIMPLE_PMIC_I2C_ADDR); + pl->hw.i2c.tx_num = 1; + + return 0; +} + +static const struct udevice_id simple_pmic_ids[] = { + { .compatible = "vendor,simple_pmic"}, + { } +}; + +U_BOOT_DRIVER(simple_pmic) = { + .name = "simple pmic", + .id = UCLASS_PMIC, + .of_match = simple_pmic_ids, + .probe = simple_pmic_probe, + .ofdata_to_platdata = simple_pmic_ofdata_to_platdata, + .platdata_auto_alloc_size = sizeof(struct pmic_platdata), +}; + +5. Pmic command +=============== +This is based on an old pmic command code - the new one uses +the driver model pmic API. The previous pmic I/O functionalities, +stays unchanged. And now read/write is the main pmic command +purpose. 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 3 - set dev 3 as current device +# pmic dump - dump the registers of pmic dev id 3 +# pmic read 0x0 - read the register of addres 0x0 +# pmic write 0x0 0x1 - write 0x1 to the register of addres 0x0 + +The user interface is similar to the 'mmc' command. + +Each pmic device driver should provide at least UCLASS_PMIC support, +as a basic pmic device I/O interface. + +6. Uclass UCLASS_PMIC_REGULATOR API +=================================== +To use the regulator API, config: CONFIG_DM_REGULATOR is required. + +Driver API is simple and clear: +To get the regulator device we can use two functions: +- pmic_get_by_name(...) +- pmic_get_by_interface(...) + +This returns "struct udevice *" pointer to uclass regulator device, +which can provide API functions. + +To operate on device regulators, we can use API functions +(if provided by the driver): +- pmic_ldo_cnt(...) +- pmic_buck_cnt(...) +- pmic_get_ldo_val(...) +- pmic_set_ldo_val(...) +- pmic_get_ldo_mode(...) +- pmic_set_ldo_mode(...) +- pmic_get_buck_val(...) +- pmic_set_buck_val(...) +- pmic_get_buck_mode(...) +- pmic_set_buck_mode(...) + +For detailed description please look into the file: +- include/power/regulator.h + +7. Simple UCLASS_PMIC_REGULATOR driver +====================================== +The regulator ops implementation can be different for each driver, +so this is only a piece of driver design. +As a reference, please take the MAX77686 pmic and regulator drivers. +- drivers/power/pmic/max77686.c +- drivers/power/regulator/max77686.c + +The regulator driver code should look like below: +(Please read the 'include/power/regulator.h' for more details) + +Note: +The regulator device should act as a child of pmic device. +This is a natural scheme of a physical PMIC IC: + +Some PMIC physical IC: + |_ dev pmic (parent) - simple and sufficient for the most board configs + |_ dev regulator (child) - provide regulator operations + |_ dev other (child) - some other pmic uclasses, (in the future) + +struct regulator_desc *simple_regulator_get_val_desc(struct udevice *dev, + int d_type, int d_num) +{ + /* Here returns regulator value descriptor */ + return NULL; +} + +static struct regulator_mode_desc * +simple_regulator_get_mode_desc_array(struct udevice *dev, int d_type, int d_num, + int *d_mode_cnt) +{ + /* Here return arra of mode descriptors for given device */ + return NULL; +} + +static int simple_regulator_get_ldo_cnt(struct udevice *dev) +{ + /* Here return regulators ldo count */ + return 0; +} + +static int simple_regulator_get_buck_cnt(struct udevice *dev) +{ + /* Here return regulator buck count */ + return 0; +} + +static int simple_regulator_ldo_val(struct udevice *dev, int op, + int ldo, int *uV) +{ + /* Here return or sets given ldo value in uV */ + return 0; +} + +static int simple_regulator_buck_val(struct udevice *dev, int op, + int buck, int *uV) +{ + /* Here return or sets given buck value in uV */ + return 0; +} + +static int simple_regulator_ldo_mode(struct udevice *dev, int op, int ldo, + int *opmode) +{ + /* Here return or sets regulator ldo mode */ + return 0; +} + +static int simple_regulator_buck_mode(struct udevice *dev, int op, int buck, + int *opmode) +{ + /* Here return or sets regulator buck mode */ + return 0; +} + +static int simple_regulator_ofdata_to_platdata(struct udevice *dev) +{ + /** + * PMIC Interface, Case 1: common + * If PMIC uses only one (SPI/I2C) physical interface for driving + * it's functionalities. + * + * Then the bind of "simple regulator" device in the "simple pmic" probe + * is called with args: + * ret = device_bind(parent, reg_drv, parent->name, parent->platdata, + * parent->of_offset, ®_dev); + */ + + /** + * PMIC Interface, case 2: independent + * If PMIC uses more then one (SPI/I2C) physical interfaces for driving + * it's functionalities. + * + * Then the bind of "simple regulator" device in the "simple pmic" + * drivers 'probe', is called with args: + * ret = device_bind(parent, reg_drv, parent->name, NULL, + * regulator_fdt_of_offset, ®_dev); + * + * In this case "driver.platdata_auto_alloc_size" + */ + + /** + * Here driver should get the 'regulator-voltage' node data + * into a proper descriptors. + * Actually there is no standard voltage description in dts, + * but please check trats2 or odroid dts files and regulator/max77686.c + * driver file to check some simple solution. + * + */ + return 0; +} + +static const struct dm_regulator_ops simple_regulator_ops = { + .get_ldo_cnt = simple_regulator_get_ldo_cnt, + .get_buck_cnt = simple_regulator_get_buck_cnt, + .get_val_desc = simple_regulator_get_val_desc, + .get_mode_desc_array = simple_regulator_get_mode_desc_array, + .ldo_val = simple_regulator_ldo_val, + .buck_val = simple_regulator_buck_val, + .ldo_mode = simple_regulator_ldo_mode, + .buck_mode = simple_regulator_buck_mode, +}; + +U_BOOT_DRIVER(simple_regulator) = { + .name = "simple regulator", + .id = UCLASS_PMIC_REGULATOR, + .ops = &simple_regulator_ops, + .ofdata_to_platdata = reg_simple_regulator_ofdata_to_platdata, + .priv_auto_alloc_size = sizeof(struct simple_regulator_info), + + /** + * .platdata_auto_alloc_size - is optional, only if regulator uses + * a different interface than parent pmic. + */ + .platdata_auto_alloc_size = sizeof(struct pmic_platdata), +}; + +8. Regulator command +==================== +The extension for 'pmic' command is a 'regulator' command. +This actually uses the same code, but provides an 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 pmic device +without the pmic documentation. If driver provide each regulator +- value and mode descriptor - then user can operate on it. + +Command options (regulator [option]): +- list - list UCLASS regulator devices +- dev [id] - show or set current regulator device +- dump - dump registers of current regulator +- [ldo/buck][N] [name/state/desc]- print regulator(s) info +- [ldoN/buckN] [setval/setmode] [mV/modeN] [-f] - set val (mV) +(forcibly) or mode - only if desc 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' (force no available) + +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
Quoted 9 lines
Quoted 5 lines
doc/driver-model/dm-pmic-framework.txt new file +2
-1+on a pmic device design, but the required voltage value can change, +e.g. if some hardware uses pins header. --1.9.1
Regards,
Simon
Thank you,
Signature · 4 lines
Przemyslaw Marczak Samsung R&D Institute Poland Samsung Electronics p.marczak at samsung.com
PATCH 12/19 samsung: board: lcd menu: check if any power framework is enabled
In reply to Przemyslaw MarczakThe lcd menu requires pmic framework to get the power key state. Now two pmic frameworks are available - the old one and the new one based on a driver-model.
--- board/samsung/common/board.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
board/samsung/common/board.c +2 -1
@@ -348,7 +348,8 @@ int misc_init_r(void)#ifdef CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG set_board_info ();#endif -#ifdef CONFIG_LCD_MENU +#if defined(CONFIG_LCD_MENU ) && (defined(CONFIG_POWER ) || \ + defined(CONFIG_DM_PMIC ))keys_init ();check_boot_mode ();#endif
Signature · 1 line
1.9.1
PATCH 13/19 samsung: misc: power_key_pressed: add support to dm pmic framework
In reply to Przemyslaw MarczakIn case of two pmic frameworks availability - enable support of both, since the new pmic framework is not fully finished and some boards still supports only the old framework.
--- board/samsung/common/misc.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-)
board/samsung/common/misc.c +18 -3
@@ -93,12 +93,13 @@ void set_board_info(void) }#endif /* CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG */ -#ifdef CONFIG_LCD_MENU +#if defined(CONFIG_LCD_MENU )static int power_key_pressed (u32 reg) { +unsigned status; +unsigned mask; +#if defined(CONFIG_POWER )struct pmic *pmic; -u32 status; -u32 mask; pmic =pmic_get (KEY_PWR_PMIC_NAME );if (!pmic) {
@@ -108,7 +109,21 @@ static int power_key_pressed(u32 reg)if (pmic_probe (pmic))return 0 ; +#elif defined(CONFIG_DM_PMIC ) +struct udevice *pmic; + pmic =pmic_get_by_name (UCLASS_PMIC ,KEY_PWR_PMIC_NAME ); + +if (!pmic) { +printf ("%s: Not found\n" ,KEY_PWR_PMIC_NAME ); +return 0 ; + } + +if (pmic_probe (pmic,NULL )) +return 0 ; +#else +#error one of: CONFIG_DM_PMIC or CONFIG_POWER must be defined! +#endif if (reg ==KEY_PWR_STATUS_REG ) mask =KEY_PWR_STATUS_MASK ;else
Signature · 1 line
1.9.1
PATCH 13/19 samsung: misc: power_key_pressed: add support to dm pmic framework
Hi,
Quoted 31 lines · Przemyslaw Marczak
In case of two pmic frameworks availability - enable support of both, since the new pmic framework is not fully finished and some boards still supports only the old framework.
Signed-off-by Przemyslaw Marczak <[email protected]>--- board/samsung/common/misc.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-)board/samsung/common/misc.c +4
-3@@ -93,12 +93,13 @@ void set_board_info(void) }#endif /* CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG */ -#ifdef CONFIG_LCD_MENU +#if defined(CONFIG_LCD_MENU )static int power_key_pressed (u32 reg) { +unsigned status; +unsigned mask; +#if defined(CONFIG_POWER )struct pmic *pmic; -u32 status; -u32 mask; pmic =pmic_get (KEY_PWR_PMIC_NAME );if (!pmic) {
board/samsung/common/misc.c static int power_key_pressed(u32 reg) · line 115
Quoted 7 lines
board/samsung/common/misc.c +3
-0@@ -108,7 +109,21 @@ static int power_key_pressed(u32 reg)if (pmic_probe (pmic))return 0 ; +#elif defined(CONFIG_DM_PMIC ) +struct udevice *pmic; + pmic =pmic_get_by_name (UCLASS_PMIC ,KEY_PWR_PMIC_NAME );
If we are going to get pmics by name, perhaps we should have uclass_get_device_by_name() instead? So long as the device has the right name, this should work, and avoids adding another layer of naming.
Quoted 15 lines
board/samsung/common/misc.c +11
-1+ +if (!pmic) { +printf ("%s: Not found\n" ,KEY_PWR_PMIC_NAME ); +return 0 ; + } + +if (pmic_probe (pmic,NULL )) +return 0 ; +#else +#error one of: CONFIG_DM_PMIC or CONFIG_POWER must be defined! +#endif if (reg ==KEY_PWR_STATUS_REG ) mask =KEY_PWR_STATUS_MASK ;else --
Quoted 2 lines
1.9.1
Regards,
Simon
PATCH 14/19 trats2: board: add support to dm pmic api
In reply to Przemyslaw MarczakChanges required to support dm pmic and dm regulator api:
- move call to board_init_i2c() into exynos_init() - earlier init the i2c
- remove redundant ldo setup - default hardware configuration is proper
- adjust pmic/regulator calls to new pmic api
--- board/samsung/trats2/trats2.c | 208 +++++++++++------------------------------- 1 file changed, 52 insertions(+), 156 deletions(-)
board/samsung/trats2/trats2.c +52 -156
@@ -23,6 +23,7 @@#include <usb.h> #include <usb/s3c_udc.h> #include <usb_mass_storage.h> +#include <dm.h> DECLARE_GLOBAL_DATA_PTR ;
@@ -151,7 +152,9 @@ int exynos_early_init_f(void)return 0 ; } +#ifdef CONFIG_DM_PMIC static int pmic_init_max77686 (void ); +#endif int exynos_init (void ) {
@@ -171,71 +174,16 @@ int exynos_init(void)writel (0 , &pwr->inform4);writel (0 , &pwr->inform5); +#ifdef CONFIG_SYS_I2C_INIT_BOARD +board_init_i2c (); +#endif +return 0 ; }int exynos_power_init (void ) { -int chrg; -struct power_battery *pb; -struct pmic *p_chrg, *p_muic, *p_fg, *p_bat; - -#ifdef CONFIG_SYS_I2C_INIT_BOARD -board_init_i2c (); -#endif -pmic_init (I2C_7 );/* I2C adapter 7 - bus name s3c24x0_7 */ pmic_init_max77686 (); -pmic_init_max77693 (I2C_10 );/* I2C adapter 10 - bus name soft1 */ -power_muic_init (I2C_10 );/* I2C adapter 10 - bus name soft1 */ -power_fg_init (I2C_9 );/* I2C adapter 9 - bus name soft0 */ -power_bat_init (0 ); - - p_chrg =pmic_get ("MAX77693_PMIC" ); -if (!p_chrg) { -puts ("MAX77693_PMIC: Not found\n" ); -return -ENODEV ; - } - - p_muic =pmic_get ("MAX77693_MUIC" ); -if (!p_muic) { -puts ("MAX77693_MUIC: Not found\n" ); -return -ENODEV ; - } - - p_fg =pmic_get ("MAX77693_FG" ); -if (!p_fg) { -puts ("MAX17042_FG: Not found\n" ); -return -ENODEV ; - } - -if (p_chrg->chrg->chrg_bat_present (p_chrg) ==0 ) -puts ("No battery detected\n" ); - - p_bat =pmic_get ("BAT_TRATS2" ); -if (!p_bat) { -puts ("BAT_TRATS2: Not found\n" ); -return -ENODEV ; - } - - p_fg->parent = p_bat; - p_chrg->parent = p_bat; - p_muic->parent = p_bat; - - p_bat->pbat->battery_init (p_bat, p_fg, p_chrg, p_muic); - - pb = p_bat->pbat; - chrg = p_muic->chrg->chrg_type (p_muic); -debug ("CHARGER TYPE: %d\n" , chrg); - -if (!p_chrg->chrg->chrg_bat_present (p_chrg)) { -puts ("No battery detected\n" ); -return 0 ; - } - - p_fg->fg->fg_battery_check (p_fg, p_bat); - -if (pb->bat->state ==CHARGE && chrg ==CHARGER_USB ) -puts ("CHARGE Battery !\n" );return 0 ; }
@@ -244,62 +192,22 @@ int exynos_power_init(void)static int s5pc210_phy_control (int on) {int ret =0 ; -unsigned int val; -struct pmic *p, *p_pmic, *p_muic; +struct udevice *pmic; - p_pmic =pmic_get ("MAX77686_PMIC" ); -if (!p_pmic) + pmic =pmic_get_by_name (UCLASS_PMIC_REGULATOR ,"max77686" ); +if (!pmic)return -ENODEV ; -if (pmic_probe (p_pmic)) -return -1 ; - - p_muic =pmic_get ("MAX77693_MUIC" ); -if (!p_muic) -return -ENODEV ; - -if (pmic_probe (p_muic)) -return -1 ; -if (on) { - ret =max77686_set_ldo_mode (p_pmic,12 ,OPMODE_ON ); -if (ret) -return -1 ; - - p =pmic_get ("MAX77693_PMIC" ); -if (!p) -return -ENODEV ; - -if (pmic_probe (p)) -return -1 ; - -/* SAFEOUT */ - ret =pmic_reg_read (p,MAX77693_SAFEOUT , &val); -if (ret) -return -1 ; - - val |=MAX77693_ENSAFEOUT1 ; - ret =pmic_reg_write (p,MAX77693_SAFEOUT , val); + ret =pmic_set_ldo_mode (pmic,12 ,OPMODE_ON );if (ret) -return -1 ; - -/* PATH: USB */ - ret =pmic_reg_write (p_muic,MAX77693_MUIC_CONTROL1 , -MAX77693_MUIC_CTRL1_DN1DP2 ); - +return -EIO ; }else { - ret =max77686_set_ldo_mode (p_pmic,12 ,OPMODE_LPM ); + ret =pmic_set_ldo_mode (pmic,12 ,OPMODE_LPM );if (ret) -return -1 ; - -/* PATH: UART */ - ret =pmic_reg_write (p_muic,MAX77693_MUIC_CONTROL1 , -MAX77693_MUIC_CTRL1_UT1UR2 ); +return -EIO ; } -if (ret) -return -1 ; -return 0 ; }
@@ -319,66 +227,47 @@ int board_usb_init(int index, enum usb_init_type init)int g_dnl_board_usb_cable_connected (void ) { +#ifdef CONFIG_POWER struct pmic *muic =pmic_get ("MAX77693_MUIC" );if (!muic)return 0 ;return !!muic->chrg->chrg_type (muic); +#else +return 1 ; +#endif }#endif - +#ifdef CONFIG_DM_PMIC static int pmic_init_max77686 (void ) { -struct pmic *p =pmic_get ("MAX77686_PMIC" ); +struct udevice *p; -if (pmic_probe (p)) -return -1 ; + p =pmic_get_by_name (UCLASS_PMIC_REGULATOR ,"max77686" ); +if (!p) { +error ("Regulator driver not found" ); +return -ENODEV ; + }/* BUCK/LDO Output Voltage */ -max77686_set_ldo_voltage (p,21 ,2800000 );/* LDO21 VTF_2.8V */ -max77686_set_ldo_voltage (p,23 ,3300000 );/* LDO23 TSP_AVDD_3.3V*/ -max77686_set_ldo_voltage (p,24 ,1800000 );/* LDO24 TSP_VDD_1.8V */ +pmic_set_ldo_val (p,21 ,2800000 );/* LDO21 VTF_2.8V */ +pmic_set_ldo_val (p,23 ,3300000 );/* LDO23 TSP_AVDD_3.3V*/ +pmic_set_ldo_val (p,24 ,1800000 );/* LDO24 TSP_VDD_1.8V */ /* BUCK/LDO Output Mode */ -max77686_set_buck_mode (p,1 ,OPMODE_STANDBY );/* BUCK1 VMIF_1.1V_AP */ -max77686_set_buck_mode (p,2 ,OPMODE_ON );/* BUCK2 VARM_1.0V_AP */ -max77686_set_buck_mode (p,3 ,OPMODE_ON );/* BUCK3 VINT_1.0V_AP */ -max77686_set_buck_mode (p,4 ,OPMODE_ON );/* BUCK4 VG3D_1.0V_AP */ -max77686_set_buck_mode (p,5 ,OPMODE_ON );/* BUCK5 VMEM_1.2V_AP */ -max77686_set_buck_mode (p,6 ,OPMODE_ON );/* BUCK6 VCC_SUB_1.35V*/ -max77686_set_buck_mode (p,7 ,OPMODE_ON );/* BUCK7 VCC_SUB_2.0V */ -max77686_set_buck_mode (p,8 ,OPMODE_OFF );/* VMEM_VDDF_2.85V */ -max77686_set_buck_mode (p,9 ,OPMODE_OFF );/* CAM_ISP_CORE_1.2V*/ - -max77686_set_ldo_mode (p,1 ,OPMODE_LPM );/* LDO1 VALIVE_1.0V_AP*/ -max77686_set_ldo_mode (p,2 ,OPMODE_STANDBY );/* LDO2 VM1M2_1.2V_AP */ -max77686_set_ldo_mode (p,3 ,OPMODE_LPM );/* LDO3 VCC_1.8V_AP */ -max77686_set_ldo_mode (p,4 ,OPMODE_LPM );/* LDO4 VCC_2.8V_AP */ -max77686_set_ldo_mode (p,5 ,OPMODE_OFF );/* LDO5_VCC_1.8V_IO */ -max77686_set_ldo_mode (p,6 ,OPMODE_STANDBY );/* LDO6 VMPLL_1.0V_AP */ -max77686_set_ldo_mode (p,7 ,OPMODE_STANDBY );/* LDO7 VPLL_1.0V_AP */ -max77686_set_ldo_mode (p,8 ,OPMODE_LPM );/* LDO8 VMIPI_1.0V_AP */ -max77686_set_ldo_mode (p,9 ,OPMODE_OFF );/* CAM_ISP_MIPI_1.2*/ -max77686_set_ldo_mode (p,10 ,OPMODE_LPM );/* LDO10 VMIPI_1.8V_AP*/ -max77686_set_ldo_mode (p,11 ,OPMODE_STANDBY );/* LDO11 VABB1_1.8V_AP*/ -max77686_set_ldo_mode (p,12 ,OPMODE_LPM );/* LDO12 VUOTG_3.0V_AP*/ -max77686_set_ldo_mode (p,13 ,OPMODE_OFF );/* LDO13 VC2C_1.8V_AP */ -max77686_set_ldo_mode (p,14 ,OPMODE_STANDBY );/* VABB02_1.8V_AP */ -max77686_set_ldo_mode (p,15 ,OPMODE_STANDBY );/* LDO15 VHSIC_1.0V_AP*/ -max77686_set_ldo_mode (p,16 ,OPMODE_STANDBY );/* LDO16 VHSIC_1.8V_AP*/ -max77686_set_ldo_mode (p,17 ,OPMODE_OFF );/* CAM_SENSOR_CORE_1.2*/ -max77686_set_ldo_mode (p,18 ,OPMODE_OFF );/* CAM_ISP_SEN_IO_1.8V*/ -max77686_set_ldo_mode (p,19 ,OPMODE_OFF );/* LDO19 VT_CAM_1.8V */ -max77686_set_ldo_mode (p,20 ,OPMODE_ON );/* LDO20 VDDQ_PRE_1.8V*/ -max77686_set_ldo_mode (p,21 ,OPMODE_OFF );/* LDO21 VTF_2.8V */ -max77686_set_ldo_mode (p,22 ,OPMODE_OFF );/* LDO22 VMEM_VDD_2.8V*/ -max77686_set_ldo_mode (p,23 ,OPMODE_OFF );/* LDO23 TSP_AVDD_3.3V*/ -max77686_set_ldo_mode (p,24 ,OPMODE_OFF );/* LDO24 TSP_VDD_1.8V */ -max77686_set_ldo_mode (p,25 ,OPMODE_OFF );/* LDO25 VCC_3.3V_LCD */ -max77686_set_ldo_mode (p,26 ,OPMODE_OFF );/*LDO26 VCC_3.0V_MOTOR*/ +pmic_set_buck_mode (p,1 ,OPMODE_STANDBY );/* BUCK1 VMIF_1.1V_AP */ +pmic_set_buck_mode (p,2 ,OPMODE_ON );/* BUCK2 VARM_1.0V_AP */ +pmic_set_buck_mode (p,3 ,OPMODE_ON );/* BUCK3 VINT_1.0V_AP */ +pmic_set_buck_mode (p,4 ,OPMODE_ON );/* BUCK4 VG3D_1.0V_AP */ +pmic_set_buck_mode (p,5 ,OPMODE_ON );/* BUCK5 VMEM_1.2V_AP */ +pmic_set_buck_mode (p,6 ,OPMODE_ON );/* BUCK6 VCC_SUB_1.35V*/ +pmic_set_buck_mode (p,7 ,OPMODE_ON );/* BUCK7 VCC_SUB_2.0V */ +pmic_set_buck_mode (p,8 ,OPMODE_OFF );/* VMEM_VDDF_2.85V */ +pmic_set_buck_mode (p,9 ,OPMODE_OFF );/* CAM_ISP_CORE_1.2V*/ return 0 ; } +#endif /* * LCD
@@ -387,19 +276,27 @@ static int pmic_init_max77686(void)#ifdef CONFIG_LCD int mipi_power (void ) { -struct pmic *p =pmic_get ("MAX77686_PMIC" ); +struct udevice *p =pmic_get_by_name (UCLASS_PMIC_REGULATOR ,"max77686" ); +if (!p) { +error ("Regulator driver not found" ); +return -ENODEV ; + }/* LDO8 VMIPI_1.0V_AP */ -max77686_set_ldo_mode (p,8 ,OPMODE_ON ); +pmic_set_ldo_mode (p,8 ,OPMODE_ON );/* LDO10 VMIPI_1.8V_AP */ -max77686_set_ldo_mode (p,10 ,OPMODE_ON ); +pmic_set_ldo_mode (p,10 ,OPMODE_ON );return 0 ; }void exynos_lcd_power_on (void ) { -struct pmic *p =pmic_get ("MAX77686_PMIC" ); +struct udevice *p =pmic_get_by_name (UCLASS_PMIC_REGULATOR ,"max77686" ); +if (!p) { +error ("Regulator driver not found\n" ); +return ; + }/* LCD_2.2V_EN: GPC0[1] */ gpio_request (EXYNOS4X12_GPIO_C01 ,"lcd_2v2_en" );
@@ -407,9 +304,8 @@ void exynos_lcd_power_on(void)gpio_direction_output (EXYNOS4X12_GPIO_C01 ,1 );/* LDO25 VCC_3.1V_LCD */ -pmic_probe (p); -max77686_set_ldo_voltage (p,25 ,3100000 ); -max77686_set_ldo_mode (p,25 ,OPMODE_LPM ); +pmic_set_ldo_val (p,25 ,3100000 ); +pmic_set_ldo_mode (p,25 ,OPMODE_ON ); }void exynos_reset_lcd (void )
Signature · 1 line
1.9.1
PATCH 14/19 trats2: board: add support to dm pmic api
Hi,
Quoted 23 lines · Przemyslaw Marczak
Changes required to support dm pmic and dm regulator api:
- move call toboard_init_i2c()intoexynos_init()- earlier init the i2c
- remove redundant ldo setup - default hardware configuration is proper
- adjust pmic/regulator calls to new pmic apiSigned-off-by Przemyslaw Marczak <[email protected]>--- board/samsung/trats2/trats2.c | 208 +++++++++++------------------------------- 1 file changed, 52 insertions(+), 156 deletions(-)board/samsung/trats2/trats2.c +1
-0@@ -23,6 +23,7 @@#include <usb.h> #include <usb/s3c_udc.h> #include <usb_mass_storage.h> +#include <dm.h> DECLARE_GLOBAL_DATA_PTR ;
board/samsung/trats2/trats2.c int exynos_early_init_f(void) · line 156
Quoted 5 lines
board/samsung/trats2/trats2.c +1
-0@@ -151,7 +152,9 @@ int exynos_early_init_f(void)return 0 ; } +#ifdef CONFIG_DM_PMIC static int pmic_init_max77686 (void );
If you just ensure that CONFIG_DM_PMIC is defined by the board then you can avoid this.
Quoted 286 lines
board/samsung/trats2/trats2.c +50
-157+#endif int exynos_init (void ) {@@ -171,71 +174,16 @@ int exynos_init(void)writel (0 , &pwr->inform4);writel (0 , &pwr->inform5); +#ifdef CONFIG_SYS_I2C_INIT_BOARD +board_init_i2c (); +#endif +return 0 ; }int exynos_power_init (void ) { -int chrg; -struct power_battery *pb; -struct pmic *p_chrg, *p_muic, *p_fg, *p_bat; - -#ifdef CONFIG_SYS_I2C_INIT_BOARD -board_init_i2c (); -#endif -pmic_init (I2C_7 );/* I2C adapter 7 - bus name s3c24x0_7 */ pmic_init_max77686 (); -pmic_init_max77693 (I2C_10 );/* I2C adapter 10 - bus name soft1 */ -power_muic_init (I2C_10 );/* I2C adapter 10 - bus name soft1 */ -power_fg_init (I2C_9 );/* I2C adapter 9 - bus name soft0 */ -power_bat_init (0 ); - - p_chrg =pmic_get ("MAX77693_PMIC" ); -if (!p_chrg) { -puts ("MAX77693_PMIC: Not found\n" ); -return -ENODEV ; - } - - p_muic =pmic_get ("MAX77693_MUIC" ); -if (!p_muic) { -puts ("MAX77693_MUIC: Not found\n" ); -return -ENODEV ; - } - - p_fg =pmic_get ("MAX77693_FG" ); -if (!p_fg) { -puts ("MAX17042_FG: Not found\n" ); -return -ENODEV ; - } - -if (p_chrg->chrg->chrg_bat_present (p_chrg) ==0 ) -puts ("No battery detected\n" ); - - p_bat =pmic_get ("BAT_TRATS2" ); -if (!p_bat) { -puts ("BAT_TRATS2: Not found\n" ); -return -ENODEV ; - } - - p_fg->parent = p_bat; - p_chrg->parent = p_bat; - p_muic->parent = p_bat; - - p_bat->pbat->battery_init (p_bat, p_fg, p_chrg, p_muic); - - pb = p_bat->pbat; - chrg = p_muic->chrg->chrg_type (p_muic); -debug ("CHARGER TYPE: %d\n" , chrg); - -if (!p_chrg->chrg->chrg_bat_present (p_chrg)) { -puts ("No battery detected\n" ); -return 0 ; - } - - p_fg->fg->fg_battery_check (p_fg, p_bat); - -if (pb->bat->state ==CHARGE && chrg ==CHARGER_USB ) -puts ("CHARGE Battery !\n" );return 0 ; }@@ -244,62 +192,22 @@ int exynos_power_init(void)static int s5pc210_phy_control (int on) {int ret =0 ; -unsigned int val; -struct pmic *p, *p_pmic, *p_muic; +struct udevice *pmic; - p_pmic =pmic_get ("MAX77686_PMIC" ); -if (!p_pmic) + pmic =pmic_get_by_name (UCLASS_PMIC_REGULATOR ,"max77686" ); +if (!pmic)return -ENODEV ; -if (pmic_probe (p_pmic)) -return -1 ; - - p_muic =pmic_get ("MAX77693_MUIC" ); -if (!p_muic) -return -ENODEV ; - -if (pmic_probe (p_muic)) -return -1 ; -if (on) { - ret =max77686_set_ldo_mode (p_pmic,12 ,OPMODE_ON ); -if (ret) -return -1 ; - - p =pmic_get ("MAX77693_PMIC" ); -if (!p) -return -ENODEV ; - -if (pmic_probe (p)) -return -1 ; - -/* SAFEOUT */ - ret =pmic_reg_read (p,MAX77693_SAFEOUT , &val); -if (ret) -return -1 ; - - val |=MAX77693_ENSAFEOUT1 ; - ret =pmic_reg_write (p,MAX77693_SAFEOUT , val); + ret =pmic_set_ldo_mode (pmic,12 ,OPMODE_ON );if (ret) -return -1 ; - -/* PATH: USB */ - ret =pmic_reg_write (p_muic,MAX77693_MUIC_CONTROL1 , -MAX77693_MUIC_CTRL1_DN1DP2 ); - +return -EIO ; }else { - ret =max77686_set_ldo_mode (p_pmic,12 ,OPMODE_LPM ); + ret =pmic_set_ldo_mode (pmic,12 ,OPMODE_LPM );if (ret) -return -1 ; - -/* PATH: UART */ - ret =pmic_reg_write (p_muic,MAX77693_MUIC_CONTROL1 , -MAX77693_MUIC_CTRL1_UT1UR2 ); +return -EIO ; } -if (ret) -return -1 ; -return 0 ; }@@ -319,66 +227,47 @@ int board_usb_init(int index, enum usb_init_type init)int g_dnl_board_usb_cable_connected (void ) { +#ifdef CONFIG_POWER struct pmic *muic =pmic_get ("MAX77693_MUIC" );if (!muic)return 0 ;return !!muic->chrg->chrg_type (muic); +#else +return 1 ; +#endif }#endif - +#ifdef CONFIG_DM_PMIC static int pmic_init_max77686 (void ) { -struct pmic *p =pmic_get ("MAX77686_PMIC" ); +struct udevice *p; -if (pmic_probe (p)) -return -1 ; + p =pmic_get_by_name (UCLASS_PMIC_REGULATOR ,"max77686" ); +if (!p) { +error ("Regulator driver not found" ); +return -ENODEV ; + }/* BUCK/LDO Output Voltage */ -max77686_set_ldo_voltage (p,21 ,2800000 );/* LDO21 VTF_2.8V */ -max77686_set_ldo_voltage (p,23 ,3300000 );/* LDO23 TSP_AVDD_3.3V*/ -max77686_set_ldo_voltage (p,24 ,1800000 );/* LDO24 TSP_VDD_1.8V */ +pmic_set_ldo_val (p,21 ,2800000 );/* LDO21 VTF_2.8V */ +pmic_set_ldo_val (p,23 ,3300000 );/* LDO23 TSP_AVDD_3.3V*/ +pmic_set_ldo_val (p,24 ,1800000 );/* LDO24 TSP_VDD_1.8V */ /* BUCK/LDO Output Mode */ -max77686_set_buck_mode (p,1 ,OPMODE_STANDBY );/* BUCK1 VMIF_1.1V_AP */ -max77686_set_buck_mode (p,2 ,OPMODE_ON );/* BUCK2 VARM_1.0V_AP */ -max77686_set_buck_mode (p,3 ,OPMODE_ON );/* BUCK3 VINT_1.0V_AP */ -max77686_set_buck_mode (p,4 ,OPMODE_ON );/* BUCK4 VG3D_1.0V_AP */ -max77686_set_buck_mode (p,5 ,OPMODE_ON );/* BUCK5 VMEM_1.2V_AP */ -max77686_set_buck_mode (p,6 ,OPMODE_ON );/* BUCK6 VCC_SUB_1.35V*/ -max77686_set_buck_mode (p,7 ,OPMODE_ON );/* BUCK7 VCC_SUB_2.0V */ -max77686_set_buck_mode (p,8 ,OPMODE_OFF );/* VMEM_VDDF_2.85V */ -max77686_set_buck_mode (p,9 ,OPMODE_OFF );/* CAM_ISP_CORE_1.2V*/ - -max77686_set_ldo_mode (p,1 ,OPMODE_LPM );/* LDO1 VALIVE_1.0V_AP*/ -max77686_set_ldo_mode (p,2 ,OPMODE_STANDBY );/* LDO2 VM1M2_1.2V_AP */ -max77686_set_ldo_mode (p,3 ,OPMODE_LPM );/* LDO3 VCC_1.8V_AP */ -max77686_set_ldo_mode (p,4 ,OPMODE_LPM );/* LDO4 VCC_2.8V_AP */ -max77686_set_ldo_mode (p,5 ,OPMODE_OFF );/* LDO5_VCC_1.8V_IO */ -max77686_set_ldo_mode (p,6 ,OPMODE_STANDBY );/* LDO6 VMPLL_1.0V_AP */ -max77686_set_ldo_mode (p,7 ,OPMODE_STANDBY );/* LDO7 VPLL_1.0V_AP */ -max77686_set_ldo_mode (p,8 ,OPMODE_LPM );/* LDO8 VMIPI_1.0V_AP */ -max77686_set_ldo_mode (p,9 ,OPMODE_OFF );/* CAM_ISP_MIPI_1.2*/ -max77686_set_ldo_mode (p,10 ,OPMODE_LPM );/* LDO10 VMIPI_1.8V_AP*/ -max77686_set_ldo_mode (p,11 ,OPMODE_STANDBY );/* LDO11 VABB1_1.8V_AP*/ -max77686_set_ldo_mode (p,12 ,OPMODE_LPM );/* LDO12 VUOTG_3.0V_AP*/ -max77686_set_ldo_mode (p,13 ,OPMODE_OFF );/* LDO13 VC2C_1.8V_AP */ -max77686_set_ldo_mode (p,14 ,OPMODE_STANDBY );/* VABB02_1.8V_AP */ -max77686_set_ldo_mode (p,15 ,OPMODE_STANDBY );/* LDO15 VHSIC_1.0V_AP*/ -max77686_set_ldo_mode (p,16 ,OPMODE_STANDBY );/* LDO16 VHSIC_1.8V_AP*/ -max77686_set_ldo_mode (p,17 ,OPMODE_OFF );/* CAM_SENSOR_CORE_1.2*/ -max77686_set_ldo_mode (p,18 ,OPMODE_OFF );/* CAM_ISP_SEN_IO_1.8V*/ -max77686_set_ldo_mode (p,19 ,OPMODE_OFF );/* LDO19 VT_CAM_1.8V */ -max77686_set_ldo_mode (p,20 ,OPMODE_ON );/* LDO20 VDDQ_PRE_1.8V*/ -max77686_set_ldo_mode (p,21 ,OPMODE_OFF );/* LDO21 VTF_2.8V */ -max77686_set_ldo_mode (p,22 ,OPMODE_OFF );/* LDO22 VMEM_VDD_2.8V*/ -max77686_set_ldo_mode (p,23 ,OPMODE_OFF );/* LDO23 TSP_AVDD_3.3V*/ -max77686_set_ldo_mode (p,24 ,OPMODE_OFF );/* LDO24 TSP_VDD_1.8V */ -max77686_set_ldo_mode (p,25 ,OPMODE_OFF );/* LDO25 VCC_3.3V_LCD */ -max77686_set_ldo_mode (p,26 ,OPMODE_OFF );/*LDO26 VCC_3.0V_MOTOR*/ +pmic_set_buck_mode (p,1 ,OPMODE_STANDBY );/* BUCK1 VMIF_1.1V_AP */ +pmic_set_buck_mode (p,2 ,OPMODE_ON );/* BUCK2 VARM_1.0V_AP */ +pmic_set_buck_mode (p,3 ,OPMODE_ON );/* BUCK3 VINT_1.0V_AP */ +pmic_set_buck_mode (p,4 ,OPMODE_ON );/* BUCK4 VG3D_1.0V_AP */ +pmic_set_buck_mode (p,5 ,OPMODE_ON );/* BUCK5 VMEM_1.2V_AP */ +pmic_set_buck_mode (p,6 ,OPMODE_ON );/* BUCK6 VCC_SUB_1.35V*/ +pmic_set_buck_mode (p,7 ,OPMODE_ON );/* BUCK7 VCC_SUB_2.0V */ +pmic_set_buck_mode (p,8 ,OPMODE_OFF );/* VMEM_VDDF_2.85V */ +pmic_set_buck_mode (p,9 ,OPMODE_OFF );/* CAM_ISP_CORE_1.2V*/ return 0 ; } +#endif /* * LCD @@ -387,19 +276,27 @@ static int pmic_init_max77686(void)#ifdef CONFIG_LCD int mipi_power (void ) { -struct pmic *p =pmic_get ("MAX77686_PMIC" ); +struct udevice *p =pmic_get_by_name (UCLASS_PMIC_REGULATOR ,"max77686" ); +if (!p) { +error ("Regulator driver not found" ); +return -ENODEV ; + }/* LDO8 VMIPI_1.0V_AP */ -max77686_set_ldo_mode (p,8 ,OPMODE_ON ); +pmic_set_ldo_mode (p,8 ,OPMODE_ON );/* LDO10 VMIPI_1.8V_AP */ -max77686_set_ldo_mode (p,10 ,OPMODE_ON ); +pmic_set_ldo_mode (p,10 ,OPMODE_ON );return 0 ; }void exynos_lcd_power_on (void ) { -struct pmic *p =pmic_get ("MAX77686_PMIC" ); +struct udevice *p =pmic_get_by_name (UCLASS_PMIC_REGULATOR ,"max77686" ); +if (!p) { +error ("Regulator driver not found\n" ); +return ; + }/* LCD_2.2V_EN: GPC0[1] */ gpio_request (EXYNOS4X12_GPIO_C01 ,"lcd_2v2_en" );@@ -407,9 +304,8 @@ void exynos_lcd_power_on(void)gpio_direction_output (EXYNOS4X12_GPIO_C01 ,1 );/* LDO25 VCC_3.1V_LCD */ -pmic_probe (p); -max77686_set_ldo_voltage (p,25 ,3100000 ); -max77686_set_ldo_mode (p,25 ,OPMODE_LPM ); +pmic_set_ldo_val (p,25 ,3100000 ); +pmic_set_ldo_mode (p,25 ,OPMODE_ON ); }void exynos_reset_lcd (void ) --
Quoted 2 lines
1.9.1
Regards,
Simon
PATCH 14/19 trats2: board: add support to dm pmic api
Hello,
Quoted 29 lines · Simon Glass
Hi,
Quoted 26 lines · Przemyslaw Marczak
Changes required to support dm pmic and dm regulator api:
- move call toboard_init_i2c()intoexynos_init()- earlier init the i2c
- remove redundant ldo setup - default hardware configuration is proper
- adjust pmic/regulator calls to new pmic apiSigned-off-by Przemyslaw Marczak <[email protected]>--- board/samsung/trats2/trats2.c | 208 +++++++++++------------------------------- 1 file changed, 52 insertions(+), 156 deletions(-)board/samsung/trats2/trats2.c +1
-0@@ -23,6 +23,7 @@#include <usb.h> #include <usb/s3c_udc.h> #include <usb_mass_storage.h> +#include <dm.h> DECLARE_GLOBAL_DATA_PTR ;@@ -151,7 +152,9 @@ int exynos_early_init_f(void)return 0 ; }
Quoted 6 lines
board/samsung/trats2/trats2.c int exynos_early_init_f(void) · line 156
Quoted 2 lines
board/samsung/trats2/trats2.c +1
-0+#ifdef CONFIG_DM_PMIC static int pmic_init_max77686 (void );If you just ensure that
CONFIG_DM_PMICis defined by the board then you can avoid this.
Ok
Quoted 284 lines
Quoted 284 lines
board/samsung/trats2/trats2.c +50
-156+#endif int exynos_init (void ) {@@ -171,71 +174,16 @@ int exynos_init(void)writel (0 , &pwr->inform4);writel (0 , &pwr->inform5); +#ifdef CONFIG_SYS_I2C_INIT_BOARD +board_init_i2c (); +#endif +return 0 ; }int exynos_power_init (void ) { -int chrg; -struct power_battery *pb; -struct pmic *p_chrg, *p_muic, *p_fg, *p_bat; - -#ifdef CONFIG_SYS_I2C_INIT_BOARD -board_init_i2c (); -#endif -pmic_init (I2C_7 );/* I2C adapter 7 - bus name s3c24x0_7 */ pmic_init_max77686 (); -pmic_init_max77693 (I2C_10 );/* I2C adapter 10 - bus name soft1 */ -power_muic_init (I2C_10 );/* I2C adapter 10 - bus name soft1 */ -power_fg_init (I2C_9 );/* I2C adapter 9 - bus name soft0 */ -power_bat_init (0 ); - - p_chrg =pmic_get ("MAX77693_PMIC" ); -if (!p_chrg) { -puts ("MAX77693_PMIC: Not found\n" ); -return -ENODEV ; - } - - p_muic =pmic_get ("MAX77693_MUIC" ); -if (!p_muic) { -puts ("MAX77693_MUIC: Not found\n" ); -return -ENODEV ; - } - - p_fg =pmic_get ("MAX77693_FG" ); -if (!p_fg) { -puts ("MAX17042_FG: Not found\n" ); -return -ENODEV ; - } - -if (p_chrg->chrg->chrg_bat_present (p_chrg) ==0 ) -puts ("No battery detected\n" ); - - p_bat =pmic_get ("BAT_TRATS2" ); -if (!p_bat) { -puts ("BAT_TRATS2: Not found\n" ); -return -ENODEV ; - } - - p_fg->parent = p_bat; - p_chrg->parent = p_bat; - p_muic->parent = p_bat; - - p_bat->pbat->battery_init (p_bat, p_fg, p_chrg, p_muic); - - pb = p_bat->pbat; - chrg = p_muic->chrg->chrg_type (p_muic); -debug ("CHARGER TYPE: %d\n" , chrg); - -if (!p_chrg->chrg->chrg_bat_present (p_chrg)) { -puts ("No battery detected\n" ); -return 0 ; - } - - p_fg->fg->fg_battery_check (p_fg, p_bat); - -if (pb->bat->state ==CHARGE && chrg ==CHARGER_USB ) -puts ("CHARGE Battery !\n" );return 0 ; }@@ -244,62 +192,22 @@ int exynos_power_init(void)static int s5pc210_phy_control (int on) {int ret =0 ; -unsigned int val; -struct pmic *p, *p_pmic, *p_muic; +struct udevice *pmic; - p_pmic =pmic_get ("MAX77686_PMIC" ); -if (!p_pmic) + pmic =pmic_get_by_name (UCLASS_PMIC_REGULATOR ,"max77686" ); +if (!pmic)return -ENODEV ; -if (pmic_probe (p_pmic)) -return -1 ; - - p_muic =pmic_get ("MAX77693_MUIC" ); -if (!p_muic) -return -ENODEV ; - -if (pmic_probe (p_muic)) -return -1 ; -if (on) { - ret =max77686_set_ldo_mode (p_pmic,12 ,OPMODE_ON ); -if (ret) -return -1 ; - - p =pmic_get ("MAX77693_PMIC" ); -if (!p) -return -ENODEV ; - -if (pmic_probe (p)) -return -1 ; - -/* SAFEOUT */ - ret =pmic_reg_read (p,MAX77693_SAFEOUT , &val); -if (ret) -return -1 ; - - val |=MAX77693_ENSAFEOUT1 ; - ret =pmic_reg_write (p,MAX77693_SAFEOUT , val); + ret =pmic_set_ldo_mode (pmic,12 ,OPMODE_ON );if (ret) -return -1 ; - -/* PATH: USB */ - ret =pmic_reg_write (p_muic,MAX77693_MUIC_CONTROL1 , -MAX77693_MUIC_CTRL1_DN1DP2 ); - +return -EIO ; }else { - ret =max77686_set_ldo_mode (p_pmic,12 ,OPMODE_LPM ); + ret =pmic_set_ldo_mode (pmic,12 ,OPMODE_LPM );if (ret) -return -1 ; - -/* PATH: UART */ - ret =pmic_reg_write (p_muic,MAX77693_MUIC_CONTROL1 , -MAX77693_MUIC_CTRL1_UT1UR2 ); +return -EIO ; } -if (ret) -return -1 ; -return 0 ; }@@ -319,66 +227,47 @@ int board_usb_init(int index, enum usb_init_type init)int g_dnl_board_usb_cable_connected (void ) { +#ifdef CONFIG_POWER struct pmic *muic =pmic_get ("MAX77693_MUIC" );if (!muic)return 0 ;return !!muic->chrg->chrg_type (muic); +#else +return 1 ; +#endif }#endif - +#ifdef CONFIG_DM_PMIC static int pmic_init_max77686 (void ) { -struct pmic *p =pmic_get ("MAX77686_PMIC" ); +struct udevice *p; -if (pmic_probe (p)) -return -1 ; + p =pmic_get_by_name (UCLASS_PMIC_REGULATOR ,"max77686" ); +if (!p) { +error ("Regulator driver not found" ); +return -ENODEV ; + }/* BUCK/LDO Output Voltage */ -max77686_set_ldo_voltage (p,21 ,2800000 );/* LDO21 VTF_2.8V */ -max77686_set_ldo_voltage (p,23 ,3300000 );/* LDO23 TSP_AVDD_3.3V*/ -max77686_set_ldo_voltage (p,24 ,1800000 );/* LDO24 TSP_VDD_1.8V */ +pmic_set_ldo_val (p,21 ,2800000 );/* LDO21 VTF_2.8V */ +pmic_set_ldo_val (p,23 ,3300000 );/* LDO23 TSP_AVDD_3.3V*/ +pmic_set_ldo_val (p,24 ,1800000 );/* LDO24 TSP_VDD_1.8V */ /* BUCK/LDO Output Mode */ -max77686_set_buck_mode (p,1 ,OPMODE_STANDBY );/* BUCK1 VMIF_1.1V_AP */ -max77686_set_buck_mode (p,2 ,OPMODE_ON );/* BUCK2 VARM_1.0V_AP */ -max77686_set_buck_mode (p,3 ,OPMODE_ON );/* BUCK3 VINT_1.0V_AP */ -max77686_set_buck_mode (p,4 ,OPMODE_ON );/* BUCK4 VG3D_1.0V_AP */ -max77686_set_buck_mode (p,5 ,OPMODE_ON );/* BUCK5 VMEM_1.2V_AP */ -max77686_set_buck_mode (p,6 ,OPMODE_ON );/* BUCK6 VCC_SUB_1.35V*/ -max77686_set_buck_mode (p,7 ,OPMODE_ON );/* BUCK7 VCC_SUB_2.0V */ -max77686_set_buck_mode (p,8 ,OPMODE_OFF );/* VMEM_VDDF_2.85V */ -max77686_set_buck_mode (p,9 ,OPMODE_OFF );/* CAM_ISP_CORE_1.2V*/ - -max77686_set_ldo_mode (p,1 ,OPMODE_LPM );/* LDO1 VALIVE_1.0V_AP*/ -max77686_set_ldo_mode (p,2 ,OPMODE_STANDBY );/* LDO2 VM1M2_1.2V_AP */ -max77686_set_ldo_mode (p,3 ,OPMODE_LPM );/* LDO3 VCC_1.8V_AP */ -max77686_set_ldo_mode (p,4 ,OPMODE_LPM );/* LDO4 VCC_2.8V_AP */ -max77686_set_ldo_mode (p,5 ,OPMODE_OFF );/* LDO5_VCC_1.8V_IO */ -max77686_set_ldo_mode (p,6 ,OPMODE_STANDBY );/* LDO6 VMPLL_1.0V_AP */ -max77686_set_ldo_mode (p,7 ,OPMODE_STANDBY );/* LDO7 VPLL_1.0V_AP */ -max77686_set_ldo_mode (p,8 ,OPMODE_LPM );/* LDO8 VMIPI_1.0V_AP */ -max77686_set_ldo_mode (p,9 ,OPMODE_OFF );/* CAM_ISP_MIPI_1.2*/ -max77686_set_ldo_mode (p,10 ,OPMODE_LPM );/* LDO10 VMIPI_1.8V_AP*/ -max77686_set_ldo_mode (p,11 ,OPMODE_STANDBY );/* LDO11 VABB1_1.8V_AP*/ -max77686_set_ldo_mode (p,12 ,OPMODE_LPM );/* LDO12 VUOTG_3.0V_AP*/ -max77686_set_ldo_mode (p,13 ,OPMODE_OFF );/* LDO13 VC2C_1.8V_AP */ -max77686_set_ldo_mode (p,14 ,OPMODE_STANDBY );/* VABB02_1.8V_AP */ -max77686_set_ldo_mode (p,15 ,OPMODE_STANDBY );/* LDO15 VHSIC_1.0V_AP*/ -max77686_set_ldo_mode (p,16 ,OPMODE_STANDBY );/* LDO16 VHSIC_1.8V_AP*/ -max77686_set_ldo_mode (p,17 ,OPMODE_OFF );/* CAM_SENSOR_CORE_1.2*/ -max77686_set_ldo_mode (p,18 ,OPMODE_OFF );/* CAM_ISP_SEN_IO_1.8V*/ -max77686_set_ldo_mode (p,19 ,OPMODE_OFF );/* LDO19 VT_CAM_1.8V */ -max77686_set_ldo_mode (p,20 ,OPMODE_ON );/* LDO20 VDDQ_PRE_1.8V*/ -max77686_set_ldo_mode (p,21 ,OPMODE_OFF );/* LDO21 VTF_2.8V */ -max77686_set_ldo_mode (p,22 ,OPMODE_OFF );/* LDO22 VMEM_VDD_2.8V*/ -max77686_set_ldo_mode (p,23 ,OPMODE_OFF );/* LDO23 TSP_AVDD_3.3V*/ -max77686_set_ldo_mode (p,24 ,OPMODE_OFF );/* LDO24 TSP_VDD_1.8V */ -max77686_set_ldo_mode (p,25 ,OPMODE_OFF );/* LDO25 VCC_3.3V_LCD */ -max77686_set_ldo_mode (p,26 ,OPMODE_OFF );/*LDO26 VCC_3.0V_MOTOR*/ +pmic_set_buck_mode (p,1 ,OPMODE_STANDBY );/* BUCK1 VMIF_1.1V_AP */ +pmic_set_buck_mode (p,2 ,OPMODE_ON );/* BUCK2 VARM_1.0V_AP */ +pmic_set_buck_mode (p,3 ,OPMODE_ON );/* BUCK3 VINT_1.0V_AP */ +pmic_set_buck_mode (p,4 ,OPMODE_ON );/* BUCK4 VG3D_1.0V_AP */ +pmic_set_buck_mode (p,5 ,OPMODE_ON );/* BUCK5 VMEM_1.2V_AP */ +pmic_set_buck_mode (p,6 ,OPMODE_ON );/* BUCK6 VCC_SUB_1.35V*/ +pmic_set_buck_mode (p,7 ,OPMODE_ON );/* BUCK7 VCC_SUB_2.0V */ +pmic_set_buck_mode (p,8 ,OPMODE_OFF );/* VMEM_VDDF_2.85V */ +pmic_set_buck_mode (p,9 ,OPMODE_OFF );/* CAM_ISP_CORE_1.2V*/ return 0 ; } +#endif /* * LCD @@ -387,19 +276,27 @@ static int pmic_init_max77686(void)#ifdef CONFIG_LCD int mipi_power (void ) { -struct pmic *p =pmic_get ("MAX77686_PMIC" ); +struct udevice *p =pmic_get_by_name (UCLASS_PMIC_REGULATOR ,"max77686" ); +if (!p) { +error ("Regulator driver not found" ); +return -ENODEV ; + }/* LDO8 VMIPI_1.0V_AP */ -max77686_set_ldo_mode (p,8 ,OPMODE_ON ); +pmic_set_ldo_mode (p,8 ,OPMODE_ON );/* LDO10 VMIPI_1.8V_AP */ -max77686_set_ldo_mode (p,10 ,OPMODE_ON ); +pmic_set_ldo_mode (p,10 ,OPMODE_ON );return 0 ; }void exynos_lcd_power_on (void ) { -struct pmic *p =pmic_get ("MAX77686_PMIC" ); +struct udevice *p =pmic_get_by_name (UCLASS_PMIC_REGULATOR ,"max77686" ); +if (!p) { +error ("Regulator driver not found\n" ); +return ; + }/* LCD_2.2V_EN: GPC0[1] */ gpio_request (EXYNOS4X12_GPIO_C01 ,"lcd_2v2_en" );@@ -407,9 +304,8 @@ void exynos_lcd_power_on(void)gpio_direction_output (EXYNOS4X12_GPIO_C01 ,1 );/* LDO25 VCC_3.1V_LCD */ -pmic_probe (p); -max77686_set_ldo_voltage (p,25 ,3100000 ); -max77686_set_ldo_mode (p,25 ,OPMODE_LPM ); +pmic_set_ldo_val (p,25 ,3100000 ); +pmic_set_ldo_mode (p,25 ,OPMODE_ON ); }
Quoted 8 lines
Quoted 4 lines
board/samsung/trats2/trats2.c +0
-1void exynos_reset_lcd (void ) --1.9.1
Regards,
Simon
Thanks,
Signature · 4 lines
Przemyslaw Marczak Samsung R&D Institute Poland Samsung Electronics p.marczak at samsung.com
PATCH 15/19 trats2: dts: max77686: add pmic alias and names cleanup
In reply to Przemyslaw MarczakChanges to support new pmic api:
- add pmic alias - currently required for new pmic
- remove i2c addr from max77686 node name
- fix names of some regulators
--- arch/arm/dts/exynos4412-trats2.dts | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-)
arch/arm/dts/exynos4412-trats2.dts +9 -8
@@ -32,6 +32,7 @@ mmc0 = "sdhci at 12510000"; mmc2 = "sdhci at 12530000"; mmc4 = "dwmmc at 12550000"; + pmic0 = &max77686; }; i2c at 138d0000 {
@@ -40,7 +41,7 @@ samsung,i2c-max-bus-freq = <100000>; status = "okay"; - max77686_pmic at 09 { + max77686: max77686 { compatible = "maxim,max77686_pmic"; interrupts = <7 0>; reg = <0x09 0 0>;
@@ -112,7 +113,7 @@ ldo8_reg: ldo8 { regulator-compatible = "LDO8"; - regulator-name = "VMIPI_1.0V"; + regulator-name = "VMIPI_1.0V_AP"; regulator-min-microvolt = <1000000>; regulator-max-microvolt = <1000000>; regulator-mem-off;
@@ -251,7 +252,7 @@ ldo25_reg: ldo25 { regulator-compatible = "LDO25"; - regulator-name = "LCD_VCC_3.3V"; + regulator-name = "LCD_VCC_2.8V"; regulator-min-microvolt = <2800000>; regulator-max-microvolt = <2800000>; regulator-mem-idle;
@@ -267,7 +268,7 @@ buck1_reg: buck1 { regulator-compatible = "BUCK1"; - regulator-name = "vdd_mif"; + regulator-name = "VMIF_1.0V_AP"; regulator-min-microvolt = <850000>; regulator-max-microvolt = <1100000>; regulator-always-on;
@@ -277,7 +278,7 @@ buck2_reg: buck2 { regulator-compatible = "BUCK2"; - regulator-name = "vdd_arm"; + regulator-name = "VARM_1.0V_AP"; regulator-min-microvolt = <850000>; regulator-max-microvolt = <1500000>; regulator-always-on;
@@ -287,7 +288,7 @@ buck3_reg: buck3 { regulator-compatible = "BUCK3"; - regulator-name = "vdd_int"; + regulator-name = "VINT_1.1V_AP"; regulator-min-microvolt = <850000>; regulator-max-microvolt = <1150000>; regulator-always-on;
@@ -297,7 +298,7 @@ buck4_reg: buck4 { regulator-compatible = "BUCK4"; - regulator-name = "vdd_g3d"; + regulator-name = "VG3D_1.0V_AP"; regulator-min-microvolt = <850000>; regulator-max-microvolt = <1150000>; regulator-boot-on;
@@ -330,7 +331,7 @@ buck8_reg: buck8 { regulator-compatible = "BUCK8"; - regulator-name = "VMEM_VDDF_3.0V"; + regulator-name = "VMEM_VDDF_2.85V"; regulator-min-microvolt = <2850000>; regulator-max-microvolt = <2850000>; regulator-always-on;
Signature · 1 line
1.9.1
PATCH 16/19 trats2: config: enable dm pmic, dm regulator api, dm max77686
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
- CONFIG_DM_PMIC_MAX77686
- CONFIG_DM_PMIC_I2C
- CONFIG_DM_REGULATOR
- CONFIG_DM_REGULATOR_MAX77686
--- include/configs/trats2.h | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-)
include/configs/trats2.h +6 -8
@@ -185,13 +185,11 @@ int get_soft_i2c_sda_pin(void);#define CONFIG_SOFT_I2C_GPIO_SDA get_soft_i2c_sda_pin()/* POWER */ -#define CONFIG_POWER -#define CONFIG_POWER_I2C -#define CONFIG_POWER_MAX77686 -#define CONFIG_POWER_PMIC_MAX77693 -#define CONFIG_POWER_MUIC_MAX77693 -#define CONFIG_POWER_FG_MAX77693 -#define CONFIG_POWER_BATTERY_TRATS2 +#define CONFIG_DM_PMIC +#define CONFIG_DM_PMIC_MAX77686 +#define CONFIG_DM_PMIC_I2C +#define CONFIG_DM_REGULATOR +#define CONFIG_DM_REGULATOR_MAX77686 /* Security subsystem - enable hw_rand() */ #define CONFIG_EXYNOS_ACE_SHA
@@ -210,7 +208,7 @@ int get_soft_i2c_sda_pin(void);#ifndef __ASSEMBLY__#include <power/max77686_pmic.h> -#define KEY_PWR_PMIC_NAME "MAX77686_PMIC" +#define KEY_PWR_PMIC_NAME "max77686"#define KEY_PWR_STATUS_REG MAX77686_REG_PMIC_STATUS1#define KEY_PWR_STATUS_MASK (1 << 0)#define KEY_PWR_INTERRUPT_REG MAX77686_REG_PMIC_INT1
Signature · 1 line
1.9.1
PATCH 16/19 trats2: config: enable dm pmic, dm regulator api, dm max77686
Hi,
Quoted 48 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
-CONFIG_DM_PMIC_MAX77686
-CONFIG_DM_PMIC_I2C
-CONFIG_DM_REGULATOR
-CONFIG_DM_REGULATOR_MAX77686Signed-off-by Przemyslaw Marczak <[email protected]>--- include/configs/trats2.h | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-)include/configs/trats2.h +6
-9@@ -185,13 +185,11 @@ int get_soft_i2c_sda_pin(void);#define CONFIG_SOFT_I2C_GPIO_SDA get_soft_i2c_sda_pin()/* POWER */ -#define CONFIG_POWER -#define CONFIG_POWER_I2C -#define CONFIG_POWER_MAX77686 -#define CONFIG_POWER_PMIC_MAX77693 -#define CONFIG_POWER_MUIC_MAX77693 -#define CONFIG_POWER_FG_MAX77693 -#define CONFIG_POWER_BATTERY_TRATS2 +#define CONFIG_DM_PMIC +#define CONFIG_DM_PMIC_MAX77686 +#define CONFIG_DM_PMIC_I2C +#define CONFIG_DM_REGULATOR +#define CONFIG_DM_REGULATOR_MAX77686 /* Security subsystem - enable hw_rand() */ #define CONFIG_EXYNOS_ACE_SHA @@ -210,7 +208,7 @@ int get_soft_i2c_sda_pin(void);#ifndef __ASSEMBLY__#include <power/max77686_pmic.h> -#define KEY_PWR_PMIC_NAME "MAX77686_PMIC" +#define KEY_PWR_PMIC_NAME "max77686"#define KEY_PWR_STATUS_REG MAX77686_REG_PMIC_STATUS1#define KEY_PWR_STATUS_MASK (1 << 0)#define KEY_PWR_INTERRUPT_REG MAX77686_REG_PMIC_INT1 --
Quoted 2 lines
1.9.1
I suppose at some point we should start putting these into Kconfig board trats_defconfig instead of board config files.
Regards,
Simon
PATCH 16/19 trats2: config: enable dm pmic, dm regulator api, dm max77686
Hello,
Quoted 57 lines · Simon Glass
Hi,
Quoted 48 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
-CONFIG_DM_PMIC_MAX77686
-CONFIG_DM_PMIC_I2C
-CONFIG_DM_REGULATOR
-CONFIG_DM_REGULATOR_MAX77686Signed-off-by Przemyslaw Marczak <[email protected]>--- include/configs/trats2.h | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-)include/configs/trats2.h +6
-9@@ -185,13 +185,11 @@ int get_soft_i2c_sda_pin(void);#define CONFIG_SOFT_I2C_GPIO_SDA get_soft_i2c_sda_pin()/* POWER */ -#define CONFIG_POWER -#define CONFIG_POWER_I2C -#define CONFIG_POWER_MAX77686 -#define CONFIG_POWER_PMIC_MAX77693 -#define CONFIG_POWER_MUIC_MAX77693 -#define CONFIG_POWER_FG_MAX77693 -#define CONFIG_POWER_BATTERY_TRATS2 +#define CONFIG_DM_PMIC +#define CONFIG_DM_PMIC_MAX77686 +#define CONFIG_DM_PMIC_I2C +#define CONFIG_DM_REGULATOR +#define CONFIG_DM_REGULATOR_MAX77686 /* Security subsystem - enable hw_rand() */ #define CONFIG_EXYNOS_ACE_SHA @@ -210,7 +208,7 @@ int get_soft_i2c_sda_pin(void);#ifndef __ASSEMBLY__#include <power/max77686_pmic.h> -#define KEY_PWR_PMIC_NAME "MAX77686_PMIC" +#define KEY_PWR_PMIC_NAME "max77686"#define KEY_PWR_STATUS_REG MAX77686_REG_PMIC_STATUS1#define KEY_PWR_STATUS_MASK (1 << 0)#define KEY_PWR_INTERRUPT_REG MAX77686_REG_PMIC_INT1 --Quoted 2 lines
1.9.1
I suppose at some point we should start putting these into
Kconfigboardtrats_defconfiginstead of board config files.
Quoted 3 lines
Regards,
Simon
You, know - the aim of PMIC framework is to support such feature as something common - so this should be some device soon. I think that we can leave it here temporary.
Thanks,
Signature · 4 lines
Przemyslaw Marczak Samsung R&D Institute Poland Samsung Electronics p.marczak at samsung.com
PATCH 17/19 odroid: board: add support to dm pmic api
In reply to Przemyslaw MarczakChanges added to support new pmic api:
- call board_init_i2c() in exynos_init(),
do i2c init before pmic_init_dm()
- change max77686 regulator calls to new pmic api calls
--- board/samsung/odroid/odroid.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-)
board/samsung/odroid/odroid.c +17 -14
@@ -378,15 +378,19 @@ static void board_gpio_init(void)static int pmic_init_max77686 (void ) { -struct pmic *p =pmic_get ("MAX77686_PMIC" ); +struct udevice *p =pmic_get_by_name (UCLASS_PMIC_REGULATOR ,"max77686" ); -if (pmic_probe (p)) +if (pmic_probe (p,NULL ))return -ENODEV ;/* Set LDO Voltage */ -max77686_set_ldo_voltage (p,20 ,1800000 );/* LDO20 eMMC */ -max77686_set_ldo_voltage (p,21 ,2800000 );/* LDO21 SD */ -max77686_set_ldo_voltage (p,22 ,2800000 );/* LDO22 eMMC */ +pmic_set_ldo_val (p,20 ,1800000 );/* LDO20 eMMC */ +pmic_set_ldo_val (p,21 ,2800000 );/* LDO21 SD */ +pmic_set_ldo_val (p,22 ,2800000 );/* LDO22 eMMC */ + +pmic_set_ldo_mode (p,20 ,OPMODE_ON ); +pmic_set_ldo_mode (p,21 ,OPMODE_ON ); +pmic_set_ldo_mode (p,22 ,OPMODE_ON );return 0 ; }
@@ -414,15 +418,14 @@ int exynos_init(void) gd->ram_size -=SZ_1M ; gd->bd->bi_dram[CONFIG_NR_DRAM_BANKS -1 ].size -=SZ_1M ; +#ifdef CONFIG_SYS_I2C_INIT_BOARD +board_init_i2c (); +#endif return 0 ; }int exynos_power_init (void ) { -#ifdef CONFIG_SYS_I2C_INIT_BOARD -board_init_i2c (); -#endif -pmic_init (I2C_0 );pmic_init_max77686 ();return 0 ;
@@ -431,19 +434,19 @@ int exynos_power_init(void)#ifdef CONFIG_USB_GADGET static int s5pc210_phy_control (int on) { -struct pmic *p_pmic; +struct udevice *p_pmic; - p_pmic =pmic_get ("MAX77686_PMIC" ); + p_pmic =pmic_get_by_name (UCLASS_PMIC_REGULATOR ,"max77686" );if (!p_pmic)return -ENODEV ; -if (pmic_probe (p_pmic)) +if (pmic_probe (p_pmic,NULL ))return -1 ;if (on) -return max77686_set_ldo_mode (p_pmic,12 ,OPMODE_ON ); +return pmic_set_ldo_mode (p_pmic,12 ,OPMODE_ON );else -return max77686_set_ldo_mode (p_pmic,12 ,OPMODE_LPM ); +return pmic_set_ldo_mode (p_pmic,12 ,OPMODE_LPM ); } struct s3c_plat_otg_data s5pc210_otg_data = {
Signature · 1 line
1.9.1
PATCH 18/19 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.
--- arch/arm/dts/exynos4412-odroid.dts | 250 ++++++++++++++++++++++++++++++++++++- 1 file changed, 249 insertions(+), 1 deletion(-)
arch/arm/dts/exynos4412-odroid.dts +249 -1
@@ -20,6 +20,7 @@ console = "/serial at 13810000"; mmc2 = "sdhci at 12530000"; mmc4 = "dwmmc at 12550000"; + pmic = &max77686; }; i2c at 13860000 {
@@ -28,11 +29,258 @@ samsung,i2c-max-bus-freq = <100000>; status = "okay"; - max77686_pmic at 09 { + max77686: max77686 at 09 { 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 19/19 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
- CONFIG_DM_PMIC_MAX77686
- CONFIG_DM_PMIC_I2C
- CONFIG_DM_REGULATOR
- CONFIG_DM_REGULATOR_MAX77686
--- include/configs/odroid.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
include/configs/odroid.h +5 -3
@@ -185,9 +185,11 @@#define CONFIG_SYS_I2C_INIT_BOARD /* POWER */ -#define CONFIG_POWER -#define CONFIG_POWER_I2C -#define CONFIG_POWER_MAX77686 +#define CONFIG_DM_PMIC +#define CONFIG_DM_PMIC_MAX77686 +#define CONFIG_DM_PMIC_I2C +#define CONFIG_DM_REGULATOR +#define CONFIG_DM_REGULATOR_MAX77686 /* GPT */ #define CONFIG_RANDOM_UUID
Signature · 1 line
1.9.1
cover Power(full) framework based on Driver Model
In reply to Przemyslaw MarczakHello all,
Quoted 124 lines · Przemyslaw Marczak
Hello,
This piece of code was a base for prepare my presentation talk for the U-Boot Mini Summit, which taking place at ELCE2014 conference, 13-th October 2014 Dusseldorf, Germany.The tittle of talk: "Power(full) framework based on Driver Model"
The presentation will be shared after the Summit.
This patchset introduces the new one PMIC framework for the U-Boot. It is still under the construction, but the basic functionality was achieved and tested. Please feel free to comment and share the opinion.
I think that each patch is described full enough, but for some more design details, please look into the documentation file. It includes some basic examples for the PMIC drivers.
Quick summary of:
Framework:
- The new approach -UCLASS_PMIC- simple and designed for device I/O only
- Add new uclass types:UCLASS_PMICandUCLASS_PMIC_REGULATOR
- Two uclass drivers for above types
- A common regulator operations - will easy cover the real devices designDrivers:
- 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)User 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 modesThe future plans:
- Wait for the I2c Driver Model implementation
- Introduce a common way to bind pmic devices - now done by alias "pmic"
- Add additional uclass types: MUIC, CHARGER, BATTERY, MFD and maybe more.
- Introduce optimal operations for new uclasses
- Port all U-Boot drivers to the new Framework
- Remove the old drivers and the old PMIC Framework codeThe 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 readability
- Port all drivers using new API
- Remove the old Framework and the old driversA disadvantage:
- some parts of the present code is duplicatedNeed help:
- After merge this, it is welcome to help with driver porting.
- Everything should be testedThe extra feature:
The first commit introduceserrno_str()function.
It is a common function which I hope will be usefull for commands and not only. If any visible error says: -19 or some other magic number, then it means that this function should be used.U-Boot Mini Summit members:
This code is maybe not as good as it could be, but the time was limited, and the conference is comming soon. I don't expects a code review of this now, but it would be nice if you take a look of this piece of code before our U-Boot Mini Summit. Of course it depends on you.Best Regards and see you in Dusseldorf!
Przemyslaw MarczakPrzemyslaw Marczak (19):
lib: errno: introduceerrno_str(): returns errno related message
exynos: config-common: enableerrno_str()function
exynos: config-common: enable generic fs command
dm: pmic: add implementation of driver model pmic uclass
dm: pmic: add implementation of driver model regulator uclass
dm: common:board_r: add call and weak ofpower_init_dm()
dm: pmic: add max77686 pmic driver
dm: regulator: add max77686 regulator driver
dm: pmic: new commands: pmic and regulator
dm: board:samsung:power_init_board: add requirement ofCONFIG_DM_PMIC
doc: driver-model: pmic and regulator uclass documentation
samsung: board: lcd menu: check if any power framework is enabled
samsung: misc:power_key_pressed: add support to dm pmic framework
trats2: board: add support to dm pmic api
trats2: dts: max77686: add pmic alias and names cleanup
trats2: config: enable dm pmic, dm regulator api, dm max77686
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 | 250 +++++++++- arch/arm/dts/exynos4412-trats2.dts | 17 +- board/samsung/common/board.c | 5 +- board/samsung/common/misc.c | 21 +- board/samsung/odroid/odroid.c | 31 +- board/samsung/trats2/trats2.c | 208 ++------ common/board_r.c | 8 + doc/driver-model/dm-pmic-framework.txt | 450 ++++++++++++++++++ drivers/power/Makefile | 6 +- drivers/power/cmd_pmic.c | 845 +++++++++++++++++++++++++++++++++ drivers/power/pmic-uclass.c | 255 ++++++++++ drivers/power/pmic/Makefile | 1 + drivers/power/pmic/max77686.c | 89 ++++ drivers/power/pmic_i2c.c | 136 ++++++ drivers/power/pmic_spi.c | 137 ++++++ drivers/power/regulator-uclass.c | 250 ++++++++++ drivers/power/regulator/Makefile | 8 + drivers/power/regulator/max77686.c | 749 +++++++++++++++++++++++++++++ include/configs/exynos-common.h | 3 + include/configs/odroid.h | 8 +- include/configs/trats2.h | 14 +- include/dm/uclass-id.h | 4 + include/errno.h | 3 + include/power/max77686_pmic.h | 28 +- include/power/pmic.h | 82 ++++ include/power/regulator.h | 267 +++++++++++ lib/Makefile | 1 + lib/errno_str.c | 147 ++++++ 29 files changed, 3823 insertions(+), 201 deletions(-)
Quoted 12 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/pmic_i2c.ccreate mode 100644drivers/power/pmic_spi.ccreate mode 100644drivers/power/regulator-uclass.ccreate mode 100644drivers/power/regulator/Makefilecreate mode 100644drivers/power/regulator/max77686.ccreate mode 100644include/power/regulator.hcreate mode 100644lib/errno_str.c
I missed one thing - this should be applied on the top of the u-boot-dm/working tree, which is now:
"dm: gpio: Remove unused get_state() uclass method" (2109ad5b8d4298d4ee9e9ba612d151c2bf65dd1a)
Best Regards,
Signature · 4 lines
Przemyslaw Marczak Samsung R&D Institute Poland Samsung Electronics p.marczak at samsung.com
cover Power(full) framework based on Driver Model
Hi,
Quoted 4 lines · Przemyslaw Marczak
Hello all,
On 10/08/2014 10:48 PM, Przemyslaw Marczak wrote:
[snip]
Quoted 5 lines
I missed one thing - this should be applied on the top of the u-boot-dm/working tree, which is now:
"dm: gpio: Remove unusedget_state()uclass method" (2109ad5b8d4298d4ee9e9ba612d151c2bf65dd1a)
Thanks - also is it available in a git tree somewhere please?
Regards,
Simon
cover Power(full) framework based on Driver Model
Hello,
Quoted 16 lines · Simon Glass
Hi,
Quoted 4 lines · Przemyslaw Marczak
Hello all,
On 10/08/2014 10:48 PM, Przemyslaw Marczak wrote:
[snip]
Quoted 5 lines
I missed one thing - this should be applied on the top of the u-boot-dm/working tree, which is now:
"dm: gpio: Remove unusedget_state()uclass method" (2109ad5b8d4298d4ee9e9ba612d151c2bf65dd1a)
Quoted 5 lines
Thanks - also is it available in a git tree somewhere please?
Regards,
Simon
No problem, it is available here:
https://bobenstein at github.com/bobenstein/u-boot.git
branch: dm-working-pmic
Best regards,
Signature · 4 lines
Przemyslaw Marczak Samsung R&D Institute Poland Samsung Electronics p.marczak at samsung.com
cover Power(full) framework based on Driver Model
In reply to Przemyslaw MarczakQuoted 64 lines · Przemyslaw Marczak
Hello,
This piece of code was a base for prepare my presentation talk for the U-Boot Mini Summit, which taking place at ELCE2014 conference, 13-th October 2014 Dusseldorf, Germany.The tittle of talk: "Power(full) framework based on Driver Model"
The presentation will be shared after the Summit.
This patchset introduces the new one PMIC framework for the U-Boot. It is still under the construction, but the basic functionality was achieved and tested. Please feel free to comment and share the opinion.
I think that each patch is described full enough, but for some more design details, please look into the documentation file. It includes some basic examples for the PMIC drivers.
Quick summary of:
Framework:
- The new approach -UCLASS_PMIC- simple and designed for device I/O only
- Add new uclass types:UCLASS_PMICandUCLASS_PMIC_REGULATOR
- Two uclass drivers for above types
- A common regulator operations - will easy cover the real devices designDrivers:
- 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)User 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 modesThe future plans:
- Wait for the I2c Driver Model implementation
- Introduce a common way to bind pmic devices - now done by alias "pmic"
- Add additional uclass types: MUIC, CHARGER, BATTERY, MFD and maybe more.
- Introduce optimal operations for new uclasses
- Port all U-Boot drivers to the new Framework
- Remove the old drivers and the old PMIC Framework codeThe 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 readability
- Port all drivers using new API
- Remove the old Framework and the old driversA disadvantage:
- some parts of the present code is duplicatedNeed help:
- After merge this, it is welcome to help with driver porting.
- Everything should be testedThe extra feature:
The first commit introduceserrno_str()function.
It is a common function which I hope will be usefull for commands and not only. If any visible error says: -19 or some other magic number, then it means that this function should be used.
Quoted 5 lines
U-Boot Mini Summit members:
This code is maybe not as good as it could be, but the time was limited, and the conference is comming soon. I don't expects a code review of this now, but it would be nice if you take a look of this piece of code before our U-Boot Mini Summit. Of course it depends on you.
Per the mini-summit, please add a patch adding yourself as pmic custodian (so something to doc/git-mailrc, shoot me your patchwork username and Detlev an ssh key so we can get a repo setup). For this series, I'm going to review/ack and I want Simon to pick it up for the DM tree since I think that makes the most sense, yes? Thanks!
And for all the patches in the series I don't reply to, they seem fine but aren't for me to ack (being board specific stuff, that looked fine but I don't have the HW) or I just agree with Simon's comments.
Signature · 8 lines
Tom -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 836 bytes Desc: Digital signature URL: <http://lists.denx.de/pipermail/u-boot/attachments/20141022/cdafd78a/attachment.pgp>
cover Power(full) framework based on Driver Model
Hello,
On 10/22/2014 05:31 PM, Tom Rini wrote:
... snip ...
Quoted 11 lines
Per the mini-summit, please add a patch adding yourself as pmic custodian (so something to doc/git-mailrc, shoot me your patchwork username and Detlev an ssh key so we can get a repo setup). For this series, I'm going to review/ack and I want Simon to pick it up for the DM tree since I think that makes the most sense, yes? Thanks!
And for all the patches in the series I don't reply to, they seem fine but aren't for me to ack (being board specific stuff, that looked fine but I don't have the HW) or I just agree with Simon's comments.
Tom, thank you for review. And I'm sorry, but I will take care of this all in the next week.
Signature · 4 lines
Przemyslaw Marczak Samsung R&D Institute Poland Samsung Electronics p.marczak at samsung.com
cover Power(full) framework based on Driver Model
In reply to Tom RiniHello Tom,
Quoted 78 lines · Tom Rini
Quoted 64 lines · Przemyslaw Marczak
Hello,
This piece of code was a base for prepare my presentation talk for the U-Boot Mini Summit, which taking place at ELCE2014 conference, 13-th October 2014 Dusseldorf, Germany.The tittle of talk: "Power(full) framework based on Driver Model"
The presentation will be shared after the Summit.
This patchset introduces the new one PMIC framework for the U-Boot. It is still under the construction, but the basic functionality was achieved and tested. Please feel free to comment and share the opinion.
I think that each patch is described full enough, but for some more design details, please look into the documentation file. It includes some basic examples for the PMIC drivers.
Quick summary of:
Framework:
- The new approach -UCLASS_PMIC- simple and designed for device I/O only
- Add new uclass types:UCLASS_PMICandUCLASS_PMIC_REGULATOR
- Two uclass drivers for above types
- A common regulator operations - will easy cover the real devices designDrivers:
- 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)User 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 modesThe future plans:
- Wait for the I2c Driver Model implementation
- Introduce a common way to bind pmic devices - now done by alias "pmic"
- Add additional uclass types: MUIC, CHARGER, BATTERY, MFD and maybe more.
- Introduce optimal operations for new uclasses
- Port all U-Boot drivers to the new Framework
- Remove the old drivers and the old PMIC Framework codeThe 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 readability
- Port all drivers using new API
- Remove the old Framework and the old driversA disadvantage:
- some parts of the present code is duplicatedNeed help:
- After merge this, it is welcome to help with driver porting.
- Everything should be testedThe extra feature:
The first commit introduceserrno_str()function.
It is a common function which I hope will be usefull for commands and not only. If any visible error says: -19 or some other magic number, then it means that this function should be used.Quoted 5 lines
U-Boot Mini Summit members:
This code is maybe not as good as it could be, but the time was limited, and the conference is comming soon. I don't expects a code review of this now, but it would be nice if you take a look of this piece of code before our U-Boot Mini Summit. Of course it depends on you.Per the mini-summit, please add a patch adding yourself as pmic custodian (so something to doc/git-mailrc, shoot me your patchwork username and Detlev an ssh key so we can get a repo setup). For this series, I'm going to review/ack and I want Simon to pick it up for the DM tree since I think that makes the most sense, yes? Thanks!
Quoted 4 lines
And for all the patches in the series I don't reply to, they seem fine but aren't for me to ack (being board specific stuff, that looked fine but I don't have the HW) or I just agree with Simon's comments.
Ok, so this code will be rebased on to u-boot-dm/i2c-working. And I will send the required informations to you and Detlev.
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 MarczakHello,
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 name
Drivers:
- 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 the pmic_get() functions
- V2: add pmic_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 argument
User 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 command
Supported boards:
- Odroid U3
- V2: drop the commits for Trats2 - wait for charger and muic uclass types
The 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 readability
The 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 code
Need help:
- After merge this, it is welcome to help with driver porting
- Every new driver should be tested on real hardware
Best regards
Przemyslaw Marczak (12):
exynos5: fix build break by adding CONFIG_POWER
dm: device: add function device_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 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 ++++++++- 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(-) 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
Signature · 1 line
1.9.1
PATCH v2 1/12 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 v2 1/12 exynos5: fix build break by adding CONFIG_POWER
Quoted 16 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(+)include/configs/exynos5-common.h +0
-0
include/configs/exynos5-common.h line 158
Quoted 10 lines
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
Thanks,
Minkyu Kang.
PATCH v2 2/12 dm: device: add function device_get_first_child_by_uclass_id()
In reply to Przemyslaw MarczakTo implement functionality for devices connected by some external interface, sometimes there is need to implement more then one, and different uclass type drivers.
But only one i2c/spi dm chip can exists, per each bus i2c address or spi select. Then, it seems to be useful, to get the child device by uclass type, for the parent with known chip address.
So, this change will be useful for the pmic case:
|- i2c bus
'- pmic i2c chip (parent)
'- uclass regulator (child 1)
'- uclass charger (child 2)
This will allow to get the regulator or charger device if knows only parent i2c/spi address.
---
Changes V2:
- new commit
--- drivers/core/device.c | 15 +++++++++++++++ include/dm/device.h | 16 ++++++++++++++++ 2 files changed, 31 insertions(+)
drivers/core/device.c +15 -0
@@ -397,6 +397,21 @@ int device_find_child_by_of_offset(struct udevice *parent, int of_offset,return -ENODEV ; } +int device_get_first_child_by_uclass_id (struct udevice *parent,int uclass_id, +struct udevice **devp) +{ +struct udevice *dev; + + *devp =NULL ; + +list_for_each_entry (dev, &parent->child_head, sibling_node) { +if (dev->driver->id == uclass_id) +return device_get_device_tail (dev,0 , devp); + } + +return -ENODEV ; +} +int device_get_child_by_of_offset (struct udevice *parent,int seq,struct udevice **devp) {
include/dm/device.h +16 -0
@@ -335,6 +335,22 @@ int device_get_child_by_of_offset(struct udevice *parent, int seq, struct udevice **devp);/** +* device_get_first_child_by_uclass_id() - Get the first child device based +* on UCLASS_ID +* +* Locates a child device by its uclass id. +* +* The device is probed to activate it ready for use. +* +* @parent: Parent device +* @uclass_id: child uclass id +* @devp: Returns pointer to device if found, otherwise this is set to NULL +* @return 0 if OK, -ve on error +*/ +int device_get_first_child_by_uclass_id (struct udevice *parent,int uclass_id, +struct udevice **devp); + +/** * device_find_first_child() - Find the first child of a device * * @parent: Parent device to search
Signature · 1 line
1.9.1
PATCH v2 2/12 dm: device: add function device_get_first_child_by_uclass_id()
Hi Przemyslaw,
Quoted 32 lines · Przemyslaw Marczak
To implement functionality for devices connected by some external interface, sometimes there is need to implement more then one, and different uclass type drivers.
But only one i2c/spi dm chip can exists, per each bus i2c address or spi select. Then, it seems to be useful, to get the child device by uclass type, for the parent with known chip address.
So, this change will be useful for the pmic case:
|- i2c bus
'- pmic i2c chip (parent)
'- uclass regulator (child 1)
'- uclass charger (child 2)This will allow to get the regulator or charger device if knows only parent i2c/spi address.
Signed-off-by Przemyslaw Marczak <[email protected]>---
Changes V2:
- new commit--- drivers/core/device.c | 15 +++++++++++++++ include/dm/device.h | 16 ++++++++++++++++ 2 files changed, 31 insertions(+)drivers/core/device.c +0
-0
drivers/core/device.c int device_find_child_by_of_offset(struct udevice *parent, int of_offset, · line 400
Quoted 4 lines
drivers/core/device.c +1
-0@@ -397,6 +397,21 @@ int device_find_child_by_of_offset(struct udevice *parent, int of_offset,return -ENODEV ; } +int device_get_first_child_by_uclass_id(struct udevice *parent, int uclass_id,
Can you please use the enum here instead of int?
Quoted 46 lines
drivers/core/device.c +14
-0+ struct udevice **devp) +{ +struct udevice *dev; + + *devp =NULL ; + +list_for_each_entry (dev, &parent->child_head, sibling_node) { +if (dev->driver->id == uclass_id) +return device_get_device_tail (dev,0 , devp); + } + +return -ENODEV ; +} +int device_get_child_by_of_offset (struct udevice *parent,int seq,struct udevice **devp) {include/dm/device.h +16
-1@@ -335,6 +335,22 @@ int device_get_child_by_of_offset(struct udevice *parent, int seq, struct udevice **devp);/** +* device_get_first_child_by_uclass_id() - Get the first child device based +* on UCLASS_ID +* +* Locates a child device by its uclass id. +* +* The device is probed to activate it ready for use. +* +* @parent: Parent device +* @uclass_id: child uclass id +* @devp: Returns pointer to device if found, otherwise this is set to NULL +* @return 0 if OK, -ve on error +*/ +int device_get_first_child_by_uclass_id (struct udevice *parent,int uclass_id, +struct udevice **devp); + +/** * device_find_first_child() - Find the first child of a device * * @parent: Parent device to search --
Quoted 2 lines
1.9.1
Regards,
Simon
PATCH v2 2/12 dm: device: add function device_get_first_child_by_uclass_id()
Hello Simon,
Quoted 85 lines · Simon Glass
Hi Przemyslaw,
Quoted 32 lines · Przemyslaw Marczak
To implement functionality for devices connected by some external interface, sometimes there is need to implement more then one, and different uclass type drivers.
But only one i2c/spi dm chip can exists, per each bus i2c address or spi select. Then, it seems to be useful, to get the child device by uclass type, for the parent with known chip address.
So, this change will be useful for the pmic case:
|- i2c bus
'- pmic i2c chip (parent)
'- uclass regulator (child 1)
'- uclass charger (child 2)This will allow to get the regulator or charger device if knows only parent i2c/spi address.
Signed-off-by Przemyslaw Marczak <[email protected]>---
Changes V2:
- new commit--- drivers/core/device.c | 15 +++++++++++++++ include/dm/device.h | 16 ++++++++++++++++ 2 files changed, 31 insertions(+)drivers/core/device.c +0
-0drivers/core/device.c int device_find_child_by_of_offset(struct udevice *parent, int of_offset, · line 400
Quoted 4 lines
drivers/core/device.c +1
-0@@ -397,6 +397,21 @@ int device_find_child_by_of_offset(struct udevice *parent, int of_offset,return -ENODEV ; } +int device_get_first_child_by_uclass_id(struct udevice *parent, int uclass_id,Can you please use the enum here instead of int?
Quoted 43 lines
drivers/core/device.c +14
-0+ struct udevice **devp) +{ +struct udevice *dev; + + *devp =NULL ; + +list_for_each_entry (dev, &parent->child_head, sibling_node) { +if (dev->driver->id == uclass_id) +return device_get_device_tail (dev,0 , devp); + } + +return -ENODEV ; +} +int device_get_child_by_of_offset (struct udevice *parent,int seq,struct udevice **devp) {include/dm/device.h +16
-0@@ -335,6 +335,22 @@ int device_get_child_by_of_offset(struct udevice *parent, int seq, struct udevice **devp);/** +* device_get_first_child_by_uclass_id() - Get the first child device based +* on UCLASS_ID +* +* Locates a child device by its uclass id. +* +* The device is probed to activate it ready for use. +* +* @parent: Parent device +* @uclass_id: child uclass id +* @devp: Returns pointer to device if found, otherwise this is set to NULL +* @return 0 if OK, -ve on error +*/ +int device_get_first_child_by_uclass_id (struct udevice *parent,int uclass_id, +struct udevice **devp); + +/** * device_find_first_child() - Find the first child of a device
Quoted 9 lines
Quoted 5 lines
include/dm/device.h +0
-1* * @parent: Parent device to search -- 1.9.1
Regards,
Simon
This function is discarded in the V3.
Best regards,
Signature · 4 lines
Przemyslaw Marczak Samsung R&D Institute Poland Samsung Electronics p.marczak at samsung.com
PATCH v2 3/12 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/README.power-framework-dm
---
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
--- drivers/power/Makefile | 1 + drivers/power/pmic-uclass.c | 191 +++++++++++++++++++++++++++++++ include/dm/uclass-id.h | 3 + include/power/pmic.h | 265 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 460 insertions(+) create mode 100644 drivers/power/pmic-uclass.c
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 +191 -0
191 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 uclasses */ +UCLASS_PMIC , +UCLASS_COUNT , UCLASS_INVALID = -1, };
include/power/pmic.h +265 -0
292 lines not on this page · raw message
Signature · 1 line
1.9.1
PATCH v2 3/12 dm: pmic: add implementation of driver model pmic uclass
Hi Przemyslaw,
Quoted 55 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.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/README.power-framework-dm
Signed-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 functions
Quoted 7 lines
--- drivers/power/Makefile | 1 + drivers/power/pmic-uclass.c | 191 +++++++++++++++++++++++++++++++ include/dm/uclass-id.h | 3 + include/power/pmic.h | 265 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 460 insertions(+) create mode 100644 drivers/power/pmic-uclass.c
This should have a Kconfig file.
Quoted 212 lines
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.odrivers/power/pmic-uclass.c new file +191
-0@@ -0,0 +1,191 @@ +/* +* 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 ; + +static char *const pmic_interfaces[] = { +"I2C" , +"SPI" , +"--" , +}; + +const char *pmic_if_str (struct udevice *pmic) +{ +int if_types =ARRAY_SIZE (pmic_interfaces); +int if_type; + + if_type =pmic_if_type (pmic); +if (if_type <0 || if_type >= if_types) +return pmic_interfaces[if_types -1 ]; + +return pmic_interfaces[if_type]; +} + +int pmic_if_type (struct udevice *pmic) +{ +struct pmic_platdata *pl = pmic->platdata; + +return pl->if_type; +} + +int pmic_if_bus_num (struct udevice *pmic) +{ +struct pmic_platdata *pl = pmic->platdata; + +return pl->if_bus_num; +} + +int pmic_if_addr_cs (struct udevice *pmic) +{ +struct pmic_platdata *pl = pmic->platdata; + +return pl->if_addr_cs; +} + +int pmic_if_max_offset (struct udevice *pmic) +{ +struct pmic_platdata *pl = pmic->platdata; + +return pl->if_max_offset; +} + +int pmic_read (struct udevice *pmic,unsigned reg,unsigned char *val) +{ +const struct dm_pmic_ops *ops; + + ops =pmic_get_uclass_ops (pmic,UCLASS_PMIC ); +if (!ops) +return -ENODEV ; + +if (!ops->read) +return -EPERM ; + +if (ops->read (pmic, reg, val)) +return -EIO ; + +return 0 ; +} + +int pmic_write (struct udevice *pmic,unsigned reg,unsigned char val) +{ +const struct dm_pmic_ops *ops; + + ops =pmic_get_uclass_ops (pmic,UCLASS_PMIC ); +if (!ops) +return -ENODEV ; + +if (!ops->write) +return -EPERM ; + +if (ops->write (pmic, reg, val)) +return -EIO ; + +return 0 ; +} + +int pmic_get (char *name,struct udevice **pmic) +{ +struct udevice *dev; +struct uclass *uc; +int ret; + + ret =uclass_get (UCLASS_PMIC , &uc); +if (ret) { +error ("PMIC uclass not initialized!" ); +return ret; + } + + uclass_foreach_dev(dev, uc) { +if (!dev) +continue ; + +if (!strncmp (name, dev->name,strlen (name))) { + ret =device_probe (dev); +if (ret) +error ("Dev: %s probe failed" , dev->name); + *pmic = dev; +return ret; + } + } + + *pmic =NULL ; +return -EINVAL ; +} + +int pmic_i2c_get (int bus,int addr,struct udevice **pmic) +{ +struct udevice *dev; +int ret; + + ret =i2c_get_chip_for_busnum (bus, addr,1 , &dev); +if (ret) { +error ("Chip: %d on bus %d not found!" , addr, bus); + *pmic =NULL ; +return ret; + } + + *pmic = dev; +return 0 ; +} + +int pmic_spi_get (int bus,int cs,struct udevice **pmic) +{ +struct udevice *busp, *devp; +int ret; + + ret =spi_find_bus_and_cs (bus, cs, &busp, &devp); +if (ret) { +error ("Chip: %d on bus %d not found!" , cs, bus); + *pmic =NULL ; +return ret; + } + + *pmic = devp; +return 0 ; +} + +int pmic_io_dev (struct udevice *pmic,struct udevice **pmic_io) +{ +struct pmic_platdata *pl; +int ret; + + pl =dev_get_platdata (pmic); +if (!pl) { +error ("pmic: %s platdata not found!" , pmic->name); +return -EINVAL ; + } + +switch (pl->if_type) { +case PMIC_I2C : + ret =pmic_i2c_get (pl->if_bus_num, pl->if_addr_cs, pmic_io); +break ; +case PMIC_SPI : + ret =pmic_spi_get (pl->if_bus_num, pl->if_addr_cs, pmic_io); +break ; +default : +error ("Unsupported interface for: %s" , pmic->name); + ret = -ENXIO ; + } + +return ret; +} + +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 uclasses */
PMIC-related
Quoted 109 lines
include/dm/uclass-id.h +2
-0+UCLASS_PMIC , +UCLASS_COUNT , UCLASS_INVALID = -1, };include/power/pmic.h +80
-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,265 @@ 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. +* +* 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 this example: +* +* my_pmic.c - pmic driver: +* +* int my_pmic_bind(struct udevice *my_pmic) +* { +* // A list of other drivers for this pmic +* char *my_pmic_drv_list = {"my_regulator", "my_charger", "my_rtc"}; +* struct udevice *my_pmic_child_dev[3]; +* ... +* for (i=0; i < ARRAY_SIZE(my_pmic_drv_list); i++) { +* // Look for child device driver
include/power/pmic.h struct pmic { · line 169
Quoted 10 lines
include/power/pmic.h +10
-0+* drv_my_reg = lists_driver_lookup_name(my_pmic_drv_list[i]); +* +* // If driver found, then bind the new device to it +* if (drv_my_reg) +* ret = device_bind(my_pmic, my_pmic_drv_list[i], +* my_pmic->name, my_pmic->platdata, +* my_pmic->of_offset, +* my_pmic_child_dev[i]); +* ... +* }
Can we not automatically do this with dm_scan_fdt_node() as in spi_post_bind(), etc.?
Quoted 31 lines
include/power/pmic.h +31
-0+* ... +* } +* +* 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, +* because the first argument of device_bind() call is the parent device, +* and here it is 'my_pmic'. +* +* For all childs the device->platdata is the same, and provide an info about +* the same interface - it's used for getting the devices by interface address +* and uclass types. +*/ + +/** +* struct pmic_platdata - PMIC chip interface info +* +* This is required for pmic command purposes and should be shared +* by pmic device and it's childs as the same platdata pointer. +* +* @if_type: one of: PMIC_I2C, PMIC_SPI, PMIC_NONE
include/power/pmic.h struct pmic { · line 210
Quoted 10 lines
include/power/pmic.h +10
-0+* @if_bus_num: usually alias seq of i2c/spi bus device +* @if_addr_cd: i2c/spi chip addr or cs +* @if_max_offset: max register offset within the chip +*/ +struct pmic_platdata { +int if_type; +int if_bus_num; +int if_addr_cs; +int if_max_offset; +};
Can we drop the if_ prefix and use an enum for if_type?
For bus_num, this will be the parent of the pmic. There should be no need to store it.
For addr_cs, there should be no need to store this. The pmic will be either on an i2c or spi bus - both of these provide the address information in dev_get_parent_platdata().
if_max_offset should be in the PMIC platdata but not that of its children. So I don't think they should all use the same platdata.
include/power/pmic.h struct pmic { · line 222
Quoted 12 lines
include/power/pmic.h +12
-0+ +/** +* struct dm_pmic_ops - PMIC device I/O interface +* +* Should be implemented by UCLASS_PMIC device drivers. The standard +* device operations provides the I/O interface for it's childs. +* +* @read: called for read "reg" value into "val" through "pmic" parent +* @write: called for write "val" into "reg" through the "pmic" parent +*/ +struct dm_pmic_ops { +int (*read)(struct udevice *pmic,unsigned reg,unsigned char *val);
Can any pmics support reading 16 bits or more?
include/power/pmic.h struct pmic { · line 226
Quoted 4 lines
include/power/pmic.h +4
-0+int (*write)(struct udevice *pmic,unsigned reg,unsigned char val); +}; + +/* enum pmic_op_type - used for various pmic devices operation calls,
Comment style
Quoted 11 lines
include/power/pmic.h +11
-0+* for reduce a number of lines with the same code for read/write or get/set. +* +* @PMIC_OP_GET - get operation +* @PMIC_OP_SET - set operation +*/ +enum pmic_op_type { +PMIC_OP_GET , +PMIC_OP_SET , +}; + +/**
include/power/pmic.h struct pmic { · line 247
Quoted 10 lines
include/power/pmic.h +10
-0+* 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)
enum
Quoted 30 lines
include/power/pmic.h +30
-0+{ +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_..._get: looking for the pmic device using the specified arguments: +* +* NAME: +* @name - device name (useful for single specific names) +* +* or SPI/I2C interface: +* @bus - device I2C/SPI bus number +* @addr_cs - device specific address for I2C or chip select for SPI, +* on the given bus number +* +* Returns:
include/power/pmic.h struct pmic { · line 287
Quoted 10 lines
include/power/pmic.h +10
-0+* @pmic - returned pointer to the pmic device +* Returns: 0 on success or negative value of errno. +* +* The returned pmic device can be used with: +* - pmic_read/write calls +* - pmic_if_* calls +*/ +int pmic_get (char *name,struct udevice **pmic); +int pmic_i2c_get (int bus,int addr,struct udevice **pmic); +int pmic_spi_get (int bus,int cs,struct udevice **pmic);
These last two should be internal to the pmic framework I think. Clients should not care.
Also we should reference SPI and I2C devices with a struct udevice, not a bus/addr or bus/cs pair.
Quoted 27 lines
include/power/pmic.h +27
-0+ +/** +* pmic_io_dev: returns given pmic/regulator, uclass pmic I/O udevice +* +* @pmic - pointer to pmic_io child device +* +* Returns: +* @pmic_io - pointer to the I/O chip device +* +* This is used for pmic command, and also can be used if +* needs raw read/write operations for uclass regulator device. +* Example of use: +* pmic_io_dev(regulator, &pmic_io); +* pmic_write(pmic_io, 0x0, 0x1); +* +* This base on pmic_platdata info, so for the given pmic i2c/spi chip, +* as '@pmic', it should return the same chip, if platdata is filled. +*/ +int pmic_io_dev (struct udevice *pmic,struct udevice **pmic_io); + +/** +* pmic_if_* functions: returns one of given pmic interface attribute: +* - type - one of enum { PMIC_I2C, PMIC_SPI, PMIC_NONE} +* - bus number - usually i2c/spi bus seq number +* - addres for i2c or cs for spi - basaed on dm_i2c/spi_chip +* - max offset - device internal address range +* - string - "I2C"/"SPI"/"--"
include/power/pmic.h struct pmic { · line 324
Quoted 10 lines
include/power/pmic.h +10
-0+* +* @pmic - pointer to the pmic device +* +* Returns: one of listed attribute on success, or a negative value of errno. +*/ +int pmic_if_type (struct udevice *pmic); +int pmic_if_bus_num (struct udevice *pmic); +int pmic_if_addr_cs (struct udevice *pmic); +int pmic_if_max_offset (struct udevice *pmic); +const char *pmic_if_str (struct udevice *pmic);
I hope that none of these is needed in fact.
Quoted 4 lines
include/power/pmic.h +4
-0+ +/** +* pmic_read/write: read/write to the UCLASS_PMIC device +*
include/power/pmic.h struct pmic { · line 338
Quoted 10 lines
include/power/pmic.h +10
-0+* The required pmic device can be obtained by: +* - pmic_i2c_get() +* - pmic_spi_get() +* - pmic_io_dev() - for pmic command purposes +* +* @pmic - pointer to the UCLASS_PMIC device +* @reg - device register offset +* @val - value for write or its pointer to read +* +* Returns: offset value on success or negative value of errno.
s/offset/register/ ?
Quoted 18 lines
include/power/pmic.h +6
-1+*/ +int pmic_read (struct udevice *pmic,unsigned reg,unsigned char *val); +int pmic_write (struct udevice *pmic,unsigned reg,unsigned char val); +#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 +352,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 v2 3/12 dm: pmic: add implementation of driver model pmic uclass
Hello Simon,
Quoted 401 lines · Simon Glass
Hi Przemyslaw,
Quoted 55 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.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/README.power-framework-dm
Signed-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 functionsQuoted 7 lines
--- drivers/power/Makefile | 1 + drivers/power/pmic-uclass.c | 191 +++++++++++++++++++++++++++++++ include/dm/uclass-id.h | 3 + include/power/pmic.h | 265 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 460 insertions(+)create mode 100644
drivers/power/pmic-uclass.cThis should have a
Kconfigfile.Quoted 212 lines
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.odrivers/power/pmic-uclass.c new file +191
-0@@ -0,0 +1,191 @@ +/* +* 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 ; + +static char *const pmic_interfaces[] = { +"I2C" , +"SPI" , +"--" , +}; + +const char *pmic_if_str (struct udevice *pmic) +{ +int if_types =ARRAY_SIZE (pmic_interfaces); +int if_type; + + if_type =pmic_if_type (pmic); +if (if_type <0 || if_type >= if_types) +return pmic_interfaces[if_types -1 ]; + +return pmic_interfaces[if_type]; +} + +int pmic_if_type (struct udevice *pmic) +{ +struct pmic_platdata *pl = pmic->platdata; + +return pl->if_type; +} + +int pmic_if_bus_num (struct udevice *pmic) +{ +struct pmic_platdata *pl = pmic->platdata; + +return pl->if_bus_num; +} + +int pmic_if_addr_cs (struct udevice *pmic) +{ +struct pmic_platdata *pl = pmic->platdata; + +return pl->if_addr_cs; +} + +int pmic_if_max_offset (struct udevice *pmic) +{ +struct pmic_platdata *pl = pmic->platdata; + +return pl->if_max_offset; +} + +int pmic_read (struct udevice *pmic,unsigned reg,unsigned char *val) +{ +const struct dm_pmic_ops *ops; + + ops =pmic_get_uclass_ops (pmic,UCLASS_PMIC ); +if (!ops) +return -ENODEV ; + +if (!ops->read) +return -EPERM ; + +if (ops->read (pmic, reg, val)) +return -EIO ; + +return 0 ; +} + +int pmic_write (struct udevice *pmic,unsigned reg,unsigned char val) +{ +const struct dm_pmic_ops *ops; + + ops =pmic_get_uclass_ops (pmic,UCLASS_PMIC ); +if (!ops) +return -ENODEV ; + +if (!ops->write) +return -EPERM ; + +if (ops->write (pmic, reg, val)) +return -EIO ; + +return 0 ; +} + +int pmic_get (char *name,struct udevice **pmic) +{ +struct udevice *dev; +struct uclass *uc; +int ret; + + ret =uclass_get (UCLASS_PMIC , &uc); +if (ret) { +error ("PMIC uclass not initialized!" ); +return ret; + } + + uclass_foreach_dev(dev, uc) { +if (!dev) +continue ; + +if (!strncmp (name, dev->name,strlen (name))) { + ret =device_probe (dev); +if (ret) +error ("Dev: %s probe failed" , dev->name); + *pmic = dev; +return ret; + } + } + + *pmic =NULL ; +return -EINVAL ; +} + +int pmic_i2c_get (int bus,int addr,struct udevice **pmic) +{ +struct udevice *dev; +int ret; + + ret =i2c_get_chip_for_busnum (bus, addr,1 , &dev); +if (ret) { +error ("Chip: %d on bus %d not found!" , addr, bus); + *pmic =NULL ; +return ret; + } + + *pmic = dev; +return 0 ; +} + +int pmic_spi_get (int bus,int cs,struct udevice **pmic) +{ +struct udevice *busp, *devp; +int ret; + + ret =spi_find_bus_and_cs (bus, cs, &busp, &devp); +if (ret) { +error ("Chip: %d on bus %d not found!" , cs, bus); + *pmic =NULL ; +return ret; + } + + *pmic = devp; +return 0 ; +} + +int pmic_io_dev (struct udevice *pmic,struct udevice **pmic_io) +{ +struct pmic_platdata *pl; +int ret; + + pl =dev_get_platdata (pmic); +if (!pl) { +error ("pmic: %s platdata not found!" , pmic->name); +return -EINVAL ; + } + +switch (pl->if_type) { +case PMIC_I2C : + ret =pmic_i2c_get (pl->if_bus_num, pl->if_addr_cs, pmic_io); +break ; +case PMIC_SPI : + ret =pmic_spi_get (pl->if_bus_num, pl->if_addr_cs, pmic_io); +break ; +default : +error ("Unsupported interface for: %s" , pmic->name); + ret = -ENXIO ; + } + +return ret; +} + +UCLASS_DRIVER (pmic) = { + .id =UCLASS_PMIC , + .name ="pmic" , +};include/dm/uclass-id.h +0
-0include/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 uclasses */ PMIC-related
Quoted 114 lines
include/dm/uclass-id.h +2
-0+UCLASS_PMIC , +UCLASS_COUNT , UCLASS_INVALID = -1, };include/power/pmic.h +85
-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,265 @@ 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. +* +* 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 this example: +* +* my_pmic.c - pmic driver: +* +* int my_pmic_bind(struct udevice *my_pmic) +* { +* // A list of other drivers for this pmic +* char *my_pmic_drv_list = {"my_regulator", "my_charger", "my_rtc"}; +* struct udevice *my_pmic_child_dev[3]; +* ... +* for (i=0; i < ARRAY_SIZE(my_pmic_drv_list); i++) { +* // Look for child device driver +* drv_my_reg = lists_driver_lookup_name(my_pmic_drv_list[i]); +* +* // If driver found, then bind the new device to it +* if (drv_my_reg) +* ret = device_bind(my_pmic, my_pmic_drv_list[i],
Quoted 9 lines
include/power/pmic.h struct pmic { · line 169
Quoted 5 lines
include/power/pmic.h +5
-0+* my_pmic->name, my_pmic->platdata, +* my_pmic->of_offset, +* my_pmic_child_dev[i]); +* ... +* } Can we not automatically do this with
dm_scan_fdt_node()as inspi_post_bind(), etc.?
This was solved partially in V3, in which I added the common function to bind childs by checking compatible string in the property given by arg. Looking at few dts files, we can found that some boards uses "compatible", and some uses "regulator-compatible" for the compatible property name of the regulators. I think, that this is not bad.
Quoted 47 lines
Quoted 31 lines
include/power/pmic.h +31
-0+* ... +* } +* +* 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, +* because the first argument of device_bind() call is the parent device, +* and here it is 'my_pmic'. +* +* For all childs the device->platdata is the same, and provide an info about +* the same interface - it's used for getting the devices by interface address +* and uclass types. +*/ + +/** +* struct pmic_platdata - PMIC chip interface info +* +* This is required for pmic command purposes and should be shared +* by pmic device and it's childs as the same platdata pointer. +* +* @if_type: one of: PMIC_I2C, PMIC_SPI, PMIC_NONE include/power/pmic.h struct pmic { · line 210
Quoted 10 lines
include/power/pmic.h +10
-0+* @if_bus_num: usually alias seq of i2c/spi bus device +* @if_addr_cd: i2c/spi chip addr or cs +* @if_max_offset: max register offset within the chip +*/ +struct pmic_platdata { +int if_type; +int if_bus_num; +int if_addr_cs; +int if_max_offset; +};Can we drop the
if_prefix and use an enum forif_type?For
bus_num, this will be the parent of the pmic. There should be no need to store it.
Quoted 7 lines
For
addr_cs, there should be no need to store this. The pmic will be either on an i2c or spi bus - both of these provide the address information indev_get_parent_platdata().
if_max_offsetshould be in the PMIC platdata but not that of its children. So I don't think they should all use the same platdata.
Right, this feature was not pretty, and is removed in V3.
Quoted 6 lines
Quoted 6 lines
include/power/pmic.h +6
-0+ +/** +* struct dm_pmic_ops - PMIC device I/O interface +* +* Should be implemented by UCLASS_PMIC device drivers. The standard +* device operations provides the I/O interface for it's childs.
Quoted 9 lines
include/power/pmic.h struct pmic { · line 222
Quoted 6 lines
include/power/pmic.h +6
-0+* +* @read: called for read "reg" value into "val" through "pmic" parent +* @write: called for write "val" into "reg" through the "pmic" parent +*/ +struct dm_pmic_ops { +int (*read)(struct udevice *pmic,unsigned reg,unsigned char *val);Can any pmics support reading 16 bits or more?
Shame on me for missing this. The new declarations are fixed with the '*buffer' and 'len'.
Quoted 75 lines
include/power/pmic.h struct pmic { · line 226
Quoted 4 lines
include/power/pmic.h +4
-0+int (*write)(struct udevice *pmic,unsigned reg,unsigned char val); +}; + +/* enum pmic_op_type - used for various pmic devices operation calls, Comment style
Quoted 11 lines
include/power/pmic.h +11
-0+* for reduce a number of lines with the same code for read/write or get/set. +* +* @PMIC_OP_GET - get operation +* @PMIC_OP_SET - set operation +*/ +enum pmic_op_type { +PMIC_OP_GET , +PMIC_OP_SET , +}; + +/** include/power/pmic.h struct pmic { · line 247
Quoted 10 lines
include/power/pmic.h +10
-0+* 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)enum
Quoted 30 lines
include/power/pmic.h +30
-0+{ +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_..._get: looking for the pmic device using the specified arguments: +* +* NAME: +* @name - device name (useful for single specific names) +* +* or SPI/I2C interface: +* @bus - device I2C/SPI bus number +* @addr_cs - device specific address for I2C or chip select for SPI, +* on the given bus number +* +* Returns: include/power/pmic.h struct pmic { · line 287
Quoted 10 lines
include/power/pmic.h +10
-0+* @pmic - returned pointer to the pmic device +* Returns: 0 on success or negative value of errno. +* +* The returned pmic device can be used with: +* - pmic_read/write calls +* - pmic_if_* calls +*/ +int pmic_get (char *name,struct udevice **pmic); +int pmic_i2c_get (int bus,int addr,struct udevice **pmic); +int pmic_spi_get (int bus,int cs,struct udevice **pmic);These last two should be internal to the pmic framework I think. Clients should not care.
Quoted 3 lines
Also we should reference SPI and I2C devices with a struct udevice, not a bus/addr or bus/cs pair.
After rework, the V3 doesn't use this.
Quoted 72 lines
Quoted 27 lines
include/power/pmic.h +27
-0+ +/** +* pmic_io_dev: returns given pmic/regulator, uclass pmic I/O udevice +* +* @pmic - pointer to pmic_io child device +* +* Returns: +* @pmic_io - pointer to the I/O chip device +* +* This is used for pmic command, and also can be used if +* needs raw read/write operations for uclass regulator device. +* Example of use: +* pmic_io_dev(regulator, &pmic_io); +* pmic_write(pmic_io, 0x0, 0x1); +* +* This base on pmic_platdata info, so for the given pmic i2c/spi chip, +* as '@pmic', it should return the same chip, if platdata is filled. +*/ +int pmic_io_dev (struct udevice *pmic,struct udevice **pmic_io); + +/** +* pmic_if_* functions: returns one of given pmic interface attribute: +* - type - one of enum { PMIC_I2C, PMIC_SPI, PMIC_NONE} +* - bus number - usually i2c/spi bus seq number +* - addres for i2c or cs for spi - basaed on dm_i2c/spi_chip +* - max offset - device internal address range +* - string - "I2C"/"SPI"/"--" include/power/pmic.h struct pmic { · line 324
Quoted 10 lines
include/power/pmic.h +10
-0+* +* @pmic - pointer to the pmic device +* +* Returns: one of listed attribute on success, or a negative value of errno. +*/ +int pmic_if_type (struct udevice *pmic); +int pmic_if_bus_num (struct udevice *pmic); +int pmic_if_addr_cs (struct udevice *pmic); +int pmic_if_max_offset (struct udevice *pmic); +const char *pmic_if_str (struct udevice *pmic);I hope that none of these is needed in fact.
Quoted 4 lines
include/power/pmic.h +4
-0+ +/** +* pmic_read/write: read/write to the UCLASS_PMIC device +* include/power/pmic.h struct pmic { · line 338
Quoted 10 lines
include/power/pmic.h +10
-0+* The required pmic device can be obtained by: +* - pmic_i2c_get() +* - pmic_spi_get() +* - pmic_io_dev() - for pmic command purposes +* +* @pmic - pointer to the UCLASS_PMIC device +* @reg - device register offset +* @val - value for write or its pointer to read +* +* Returns: offset value on success or negative value of errno. s/offset/register/ ?
Quoted 15 lines
include/power/pmic.h +6
-0+*/ +int pmic_read (struct udevice *pmic,unsigned reg,unsigned char *val); +int pmic_write (struct udevice *pmic,unsigned reg,unsigned char val); +#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 +352,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
Thank you for comments.
Best regards,
Signature · 4 lines
Przemyslaw Marczak Samsung R&D Institute Poland Samsung Electronics p.marczak at samsung.com
PATCH v2 4/12 dm: pmic: 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.
The regulator framework is based on a 'struct dm_regulator_ops'. It provides a common function calls, for it's basic features:
- regulator_get_cnt() - number of outputs each type
- regulator_get_value_desc() - describe output value limits
- regulator_get_mode_desc() - describe output operation modes - regulator_get/set_value() - output value (uV) - regulator_get/set_state() - output on/off state - regulator_get/set_mode() - output operation mode
To get the regulator device:
- regulator_get() - by name only
- regulator_i2c_get() - by i2c bus address (of pmic parent)
- regulator_spi_get() - by spi bus address (of pmic parent)
An optional and useful regulator framework features are two descriptors:
- struct regulator_desc - describes the regulator name and output value limits should be defined by device driver for each regulator output.
- struct regulator_mode_desc - (array) describes a number of operation modes supported by each regulator output.
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
--- drivers/power/Makefile | 1 + drivers/power/regulator-uclass.c | 227 ++++++++++++++++++++++++++++ include/dm/uclass-id.h | 1 + include/power/regulator.h | 310 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 539 insertions(+) create mode 100644 drivers/power/regulator-uclass.c create mode 100644 include/power/regulator.h
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 +227 -0
227 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 uclasses */ UCLASS_PMIC , +UCLASS_PMIC_REGULATOR ,UCLASS_COUNT , UCLASS_INVALID = -1,
include/power/regulator.h new file +310 -0
310 lines not on this page · raw message
Signature · 1 line
1.9.1
PATCH v2 4/12 dm: pmic: add implementation of driver model regulator uclass
Hi Przemyslaw,
Quoted 11 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.The regulator framework is based on a 'struct
dm_regulator_ops'. It provides a common function calls, for it's basic features:
-regulator_get_cnt()- number of outputs each type
-regulator_get_value_desc()- describe output value limits- regulator_get_mode_desc() - describe output operation modes - regulator_get/set_value() - output value (uV) - regulator_get/set_state() - output on/off state
Would get/set_enable() be better?
Quoted 6 lines
- regulator_get/set_mode() - output operation mode
To get the regulator device:
-regulator_get()- by name only
-regulator_i2c_get()- by i2c bus address (of pmic parent)
-regulator_spi_get()- by spi bus address (of pmic parent)
For the last two, why are we using bus address? This should be by a phandle reference or nane.
Quoted 78 lines
An optional and useful regulator framework features are two descriptors:
- structregulator_desc- describes the regulator name and output value limits should be defined by device driver for each regulator output.- struct
regulator_mode_desc- (array) describes a number of operation modes supported by each regulator output.The 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 comments--- drivers/power/Makefile | 1 + drivers/power/regulator-uclass.c | 227 ++++++++++++++++++++++++++++ include/dm/uclass-id.h | 1 + include/power/regulator.h | 310 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 539 insertions(+) create mode 100644 drivers/power/regulator-uclass.c create mode 100644 include/power/regulator.hdrivers/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 +17
-0@@ -0,0 +1,227 @@ +/* +* 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>
drivers/power/regulator-uclass.c line 27
Quoted 10 lines
drivers/power/regulator-uclass.c new file +10
-0+ +DECLARE_GLOBAL_DATA_PTR ; + +int regulator_get_cnt (struct udevice *dev,int type,int *cnt) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_PMIC_REGULATOR ); +if (!ops) +return -ENODEV ;
This is an error so you should be able to just assert(). Failing that let's use -ENXIO as you do below.
drivers/power/regulator-uclass.c line 30
Quoted 3 lines
drivers/power/regulator-uclass.c new file +3
-0+ +if (!ops->get_cnt) +return -EPERM ;
-ENOSYS for these.
Quoted 229 lines
drivers/power/regulator-uclass.c new file +197
-0+ +return ops->get_cnt (dev, type, cnt); +} + +int regulator_get_value_desc (struct udevice *dev,int type,int number, +struct regulator_value_desc **desc) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_PMIC_REGULATOR ); +if (!ops) +return -ENXIO ; + +if (!ops->get_value_desc) +return -EPERM ; + +return ops->get_value_desc (dev, type, number, desc); +} + +int regulator_get_mode_desc (struct udevice *dev,int type,int number, +int *mode_cnt,struct regulator_mode_desc **desc) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_PMIC_REGULATOR ); +if (!ops) +return -ENXIO ; + +if (!ops->get_mode_desc_array) +return -EPERM ; + +return ops->get_mode_desc_array (dev, type, number, mode_cnt, desc); +} + +int regulator_get_value (struct udevice *dev,int type,int number,int *value) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_PMIC_REGULATOR ); +if (!ops) +return -ENODEV ; + +if (!ops->get_value) +return -EPERM ; + +return ops->get_value (dev, type, number, value); +} + +int regulator_set_value (struct udevice *dev,int type,int number,int value) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_PMIC_REGULATOR ); +if (!ops) +return -ENODEV ; + +if (!ops->set_value) +return -EPERM ; + +return ops->set_value (dev, type, number, value); +} + +int regulator_get_state (struct udevice *dev,int type,int number,int *state) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_PMIC_REGULATOR ); +if (!ops) +return -ENODEV ; + +if (!ops->get_state) +return -EPERM ; + +return ops->get_state (dev, type, number, state); +} + +int regulator_set_state (struct udevice *dev,int type,int number,int state) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_PMIC_REGULATOR ); +if (!ops) +return -ENODEV ; + +if (!ops->set_state) +return -EPERM ; + +return ops->set_state (dev, type, number, state); +} + +int regulator_get_mode (struct udevice *dev,int type,int number,int *mode) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_PMIC_REGULATOR ); +if (!ops) +return -ENODEV ; + +if (!ops->get_mode) +return -EPERM ; + +return ops->get_mode (dev, type, number, mode); +} + +int regulator_set_mode (struct udevice *dev,int type,int number,int mode) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_PMIC_REGULATOR ); +if (!ops) +return -ENODEV ; + +if (!ops->set_mode) +return -EPERM ; + +return ops->set_mode (dev, type, number, mode); +} + +int regulator_get (char *name,struct udevice **regulator) +{ +struct udevice *dev; +struct uclass *uc; +int ret; + + ret =uclass_get (UCLASS_PMIC_REGULATOR , &uc); +if (ret) { +error ("Regulator uclass not initialized!" ); +return ret; + } + + uclass_foreach_dev(dev, uc) { +if (!dev) +continue ; + +if (!strncmp (name, dev->name,strlen (name))) { + ret =device_probe (dev); +if (ret) +error ("Dev: %s probe failed" , dev->name); + *regulator = dev; +return ret; + } + } + + *regulator =NULL ; +return -EINVAL ; +} + +int regulator_i2c_get (int bus,int addr,struct udevice **regulator) +{ +struct udevice *pmic; +int ret; + +/* First get parent pmic device */ + ret =pmic_i2c_get (bus, addr, &pmic); +if (ret) { +error ("Chip: %d on bus %d not found!" , addr, bus); +return ret; + } + +/* Get the first regulator child of pmic device */ +if (device_get_first_child_by_uclass_id (pmic,UCLASS_PMIC_REGULATOR , + regulator)) { +error ("PMIC: %s regulator child not found!" , pmic->name); + *regulator =NULL ; +return ret; + } + +return 0 ; +} + +int regulator_spi_get (int bus,int cs,struct udevice **regulator) +{ +struct udevice *pmic; +int ret; + +/* First get parent pmic device */ + ret =pmic_spi_get (bus, cs, &pmic); +if (ret) { +error ("Chip: %d on bus %d not found!" , cs, bus); +return ret; + } + +/* Get the first regulator child of pmic device */ +if (device_get_first_child_by_uclass_id (pmic,UCLASS_PMIC_REGULATOR , + regulator)) { +error ("PMIC: %s regulator child not found!" , pmic->name); + *regulator =NULL ; +return ret; + } + +return 0 ; +} + +UCLASS_DRIVER (regulator) = { + .id =UCLASS_PMIC_REGULATOR , + .name ="regulator" , +};include/dm/uclass-id.h +1
-0@@ -37,6 +37,7 @@ enum uclass_id {/* PMIC uclass and PMIC related uclasses */ UCLASS_PMIC , +UCLASS_PMIC_REGULATOR ,UCLASS_COUNT , UCLASS_INVALID = -1,include/power/regulator.h new file +14
-0@@ -0,0 +1,310 @@ +/* +* Copyright (C) 2014-2015 Samsung Electronics +* Przemyslaw Marczak <[email protected]> +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#ifndef _INCLUDE_REGULATOR_H_ +#define _INCLUDE_REGULATOR_H_ + +#define DESC_NAME_LEN 20 + +/* enum regulator_type - used for regulator_*() variant calls */ +enum regulator_type {
include/power/regulator.h line 24
Quoted 10 lines
include/power/regulator.h new file +10
-0+REGULATOR_TYPE_LDO =0 , +REGULATOR_TYPE_BUCK , + REGULATOR_TYPE_DVS, +}; + +/* enum regulator_out_state - used for ldo/buck output state setting */ +enum regulator_out_state { +REGULATOR_OFF =0 , +REGULATOR_ON , +};
If we will only ever have on/off perhaps we don't need this enum and could just use a bool?
include/power/regulator.h line 33
Quoted 9 lines
include/power/regulator.h new file +9
-0+ +/** +* struct regulator_value_desc - this structure holds an information about +* each regulator voltage limits. There is no "step" voltage value - so driver +* should take care of this. This is rather platform specific so can be +* taken from the device-tree. +* +* @type - one of: DESC_TYPE_LDO, DESC_TYPE_BUCK or DESC_TYPE_DVS +* @number - hardware internal regulator number
What is this numbering and where does it come from? It is specified by the PMIC datasheet? Can you expand the comment a bit?
Actually I think this numbering should go away and we should use names instead.
include/power/regulator.h line 44
Quoted 11 lines
include/power/regulator.h new file +11
-0+* @min_uV - minimum voltage (micro Volts) +* @max_uV - maximum voltage (micro Volts) +* @name - name of regulator - usually will be taken from device tree and +* can describe regulator output connected hardware, e.g. "eMMC" +*/ +struct regulator_value_desc { +int type; +int number; +int min_uV; +int max_uV; +char name[DESC_NAME_LEN ];
What do you think about making this a const char * and we alloc it with strdup()?
include/power/regulator.h line 50
Quoted 6 lines
include/power/regulator.h new file +6
-0+}; + +/** +* struct regulator_mode_desc - this structure holds an information about +* each regulator operation modes. Probably in most cases - an array. +* This will be probably a driver static data since it's device specific.
driver-static (I think you mean)
include/power/regulator.h line 53
Quoted 3 lines
include/power/regulator.h new file +3
-0+* +* @mode - a driver specific mode number - used for regulator command +* @register_value - a driver specific value for this mode
driver-specific, you are creating an adjective
Quoted 10 lines
include/power/regulator.h new file +10
-0+* @name - the name of mode - used for regulator command +*/ +struct regulator_mode_desc { +int mode; +int register_value; +char *name; +}; + +/* PMIC regulator device operations */ +struct dm_regulator_ops {
include/power/regulator.h line 73
Quoted 10 lines
include/power/regulator.h new file +10
-0+/** +* get_cnt - get the number of a given regulator 'type' outputs +* +* @dev - regulator device +* @type - regulator type, one of enum regulator_type +* Gets: +* @cnt - regulator count +* Returns: 0 on success or negative value of errno. +*/ +int (*get_cnt)(struct udevice *dev,int type,int *cnt);
get_count
Return count in return value instead of a parameter.
Quoted 7 lines
include/power/regulator.h new file +7
-0+ +/** +* Regulator output value descriptor is specific for each output. +* It's usually driver static data, but output value limits are +* often defined in the device-tree, so those are platform dependent +* attributes. +*
include/power/regulator.h line 90
Quoted 10 lines
include/power/regulator.h new file +10
-0+* get_value_desc - get value descriptor of the given regulator output +* @dev - regulator device +* @type - regulator type, one of enum regulator_type +* @number - regulator number +* Gets: +* @desc - pointer to the descriptor +* Returns: 0 on success or negative value of errno. +*/ +int (*get_value_desc)(struct udevice *dev,int type,int number, +struct regulator_value_desc **desc);
You could use descp, to indicate it returns a pointer.
include/power/regulator.h line 103
Quoted 13 lines
include/power/regulator.h new file +13
-0+ +/** +* Regulator output mode descriptors are device specific. +* It's usually driver static data. +* Each regulator output can support different mode types, +* so usually will return an array with a number 'mode_desc_cnt' +* of mode descriptors. +* +* get_mode_desc_array - get mode descriptor array of the given +* regulator output number +* @dev - regulator device +* @type - regulator type, one of 'enum regulator_type' +* @number - regulator number
regulator_num would be better
include/power/regulator.h line 109
Quoted 6 lines
include/power/regulator.h new file +6
-0+* Gets: +* @mode_desc_cnt - descriptor array entry count +* @desc - pointer to the descriptor array +* Returns: 0 on success or negative value of errno. +*/ + int (*get_mode_desc_array)(struct udevice *dev, int type,
So should type be an enum?
Quoted 6 lines
include/power/regulator.h new file +6
-0+ int number, int *mode_desc_cnt, + struct regulator_mode_desc **desc); + +/** +* The regulator output value function calls operates on a micro Volts, +* however the regulator commands operates on a mili Volt unit.
include/power/regulator.h line 125
Quoted 10 lines
include/power/regulator.h new file +10
-0+* +* get/set_value - get/set output value of the given output number +* @dev - regulator device +* @type - regulator type, one of 'enum regulator_type' +* @number - regulator number +* Sets/Gets: +* @value - set or get output value +* Returns: 0 on success or negative value of errno. +*/ +int (*get_value)(struct udevice *dev,int type,int number,int *value);
Return value in return value instead of a parameter.
include/power/regulator.h line 129
Quoted 4 lines
include/power/regulator.h new file +4
-0+int (*set_value)(struct udevice *dev,int type,int number,int value); + +/** +* The most basic feature of the regulator output is it's on/off state.
its
include/power/regulator.h line 139
Quoted 10 lines
include/power/regulator.h new file +10
-0+* +* get/set_state - get/set on/off state of the given output number +* @dev - regulator device +* @type - regulator type, one of 'enum regulator_type' +* @number - regulator number +* Sets/Gets: +* @state - set or get one of 'enum regulator_out_state' +* Returns: 0 on success or negative value of errno. +*/ +int (*get_state)(struct udevice *dev,int type,int number,int *state);
Return state in return value instead of a parameter.
Quoted 6 lines
include/power/regulator.h new file +6
-0+int (*set_state)(struct udevice *dev,int type,int number,int state); + +/** +* The 'get/set_mode()' function calls should operate on a driver +* specific mode definitions, which should be found in: +* field 'mode' of struct regulator_mode_desc.
include/power/regulator.h line 155
Quoted 10 lines
include/power/regulator.h new file +10
-0+* +* get/set_mode - get/set operation mode of the given output number +* @dev - regulator device +* @type - regulator type, one of 'enum regulator_type' +* @number - regulator number +* Sets/Gets: +* @mode - set or get output mode +* Returns: 0 on success or negative value of errno. +*/ +int (*get_mode)(struct udevice *dev,int type,int number,int *mode);
Return mode in return value.
include/power/regulator.h line 160
Quoted 5 lines
include/power/regulator.h new file +5
-0+int (*set_mode)(struct udevice *dev,int type,int number,int mode); +}; + +/** +* regulator_get_cnt: returns the number of driver registered regulators.
driver-registered
include/power/regulator.h line 169
Quoted 9 lines
include/power/regulator.h new file +9
-0+* This is used for pmic regulator command purposes. +* +* @dev - pointer to the regulator device +* @type - regulator type: device specific +* Gets: +* @cnt - regulator count +* Returns: 0 on success or negative value of errno. +*/ +int regulator_get_cnt (struct udevice *dev,int type,int *cnt);
regulator_get_count. Return count in return value instead of a parameter.
Quoted 30 lines
include/power/regulator.h new file +30
-0+ +/** +* regulator_get_value_desc: returns a pointer to the regulator value +* descriptor of a given device regulator output number. +* +* @dev - pointer to the regulator device +* @type - regulator descriptor type +* @number - descriptor number (regulator output number) +* Gets: +* @desc - pointer to the descriptor +* Returns: 0 on success or negative value of errno. +*/ +int regulator_get_value_desc (struct udevice *dev,int type,int number, +struct regulator_value_desc **desc); + +/** +* regulator_get_mode_desc: returns a pointer to the array of regulator mode +* descriptors of a given device regulator type and number. +* +* @dev - pointer to the regulator device +* @type - regulator type: device specific +* @number - output number: device specific +* Gets: +* @mode_cnt - descriptor array entry count +* @desc - pointer to the descriptor array +* Returns: 0 on success or negative value of errno. +*/ +int regulator_get_mode_desc (struct udevice *dev,int type,int number, +int *mode_cnt,struct regulator_mode_desc **desc); +
include/power/regulator.h line 209
Quoted 10 lines
include/power/regulator.h new file +10
-0+/** +* regulator_get_value: returns voltage value of a given device +* regulator type number. +* +* @dev - pointer to the regulator device +* @type - regulator type: device specific +* @number - output number: device specific +* Gets: +* @val - returned voltage - unit: uV (micro Volts) +* Returns: 0 on success or negative value of errno.
You may as well return the voltage in the return value, unless it can be -ve (I assume not?)
Quoted 19 lines
include/power/regulator.h new file +19
-0+*/ +int regulator_get_value (struct udevice *dev,int type,int number,int *val); + +/** +* regulator_set_value: set the voltage value of a given device regulator type +* number to the given one passed by the argument: @val +* +* @dev - pointer to the regulator device +* @type - regulator type: device specific +* @number - output number: device specific +* @val - voltage value to set - unit: uV (micro Volts) +* Returns - 0 on success or -errno val if fails +*/ +int regulator_set_value (struct udevice *dev,int type,int number,int val); + +/** +* regulator_get_state: returns output state of a given device +* regulator type number. +*
include/power/regulator.h line 238
Quoted 10 lines
include/power/regulator.h new file +10
-0+* @dev - pointer to the regulator device +* @type - regulator type, device specific +* @number - regulator number, device specific +* Gets: +* @state - returned regulator number output state: +* - REGULATOR_OFF (0) - disable +* - REGULATOR_ON (1) - enable +* Returns: - 0 on success or -errno val if fails +*/ +int regulator_get_state (struct udevice *dev,int type,int number,int *state);
Return state in return value instead of a parameter.
Quoted 20 lines
include/power/regulator.h new file +20
-0+ +/** +* regulator_set_state: set output state of a given device regulator type +* number to the given one passed by the argument: @state +* +* @dev - pointer to the regulator device +* @type - regulator type: device specific +* @number - output number: device specific +* @state - output state to set +* - enum REGULATOR_OFF == 0 - disable +* - enum REGULATOR_ON == 1 - enable +* Returns - 0 on success or -errno val if fails +*/ +int regulator_set_state (struct udevice *dev,int type,int number,int state); + +/** +* regulator_get_mode: get mode number of a given device regulator type number +* +* @dev - pointer to the regulator device +* @type - output number: device specific
include/power/regulator.h line 268
Quoted 10 lines
include/power/regulator.h new file +10
-0+* @number - output number: device specific +* Gets: +* @mode - returned mode number +* Returns - 0 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 'regulator_mode_desc' has +* a mode field for this purpose and register_value for a raw register value. +*/ +int regulator_get_mode (struct udevice *dev,int type,int number,int *mode);
Return mode in return value instead of a parameter.
Quoted 30 lines
include/power/regulator.h new file +30
-0+ +/** +* regulator_set_mode: set given regulator type and number mode to the given +* one passed by the argument: @mode +* +* @dev - pointer to the regulator device +* @type - output number: device specific +* @number - output number: device specific +* @mode - mode type (struct regulator_mode_desc.mode) +* 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 type,int number,int mode); + +/** +* regulator_..._get: returns the pointer to the pmic regulator device +* by specified arguments: +* +* NAME: +* @name - device name (useful for specific names) +* or SPI/I2C interface: +* @bus - device I2C/SPI bus number +* @addr_cs - device specific address for I2C or chip select for SPI, +* on the given bus number +* Gets: +* @regulator - pointer to the pmic device +* Returns: 0 on success or negative value of errno.
include/power/regulator.h line 308
Quoted 10 lines
include/power/regulator.h new file +10
-0+* +* The returned 'regulator' device can be used with: +* - regulator_get/set_* +* and if pmic_platdata is given, then also with: +* - pmic_if_* calls +* The last one is used for the pmic command purposes. +*/ +int regulator_get (char *name,struct udevice **regulator); +int regulator_i2c_get (int bus,int addr,struct udevice **regulator); +int regulator_spi_get (int bus,int cs,struct udevice **regulator);
Hoping you don't need these last two!
Quoted 5 lines
include/power/regulator.h new file +2
-1+ +#endif /* _INCLUDE_REGULATOR_H_ */ --1.9.1
Regards,
Simon
PATCH v2 4/12 dm: pmic: add implementation of driver model regulator uclass
Hello Simon,
Quoted 119 lines · Simon Glass
Hi Przemyslaw,
Quoted 11 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.The regulator framework is based on a 'struct
dm_regulator_ops'. It provides a common function calls, for it's basic features:
-regulator_get_cnt()- number of outputs each type
-regulator_get_value_desc()- describe output value limits- regulator_get_mode_desc() - describe output operation modes - regulator_get/set_value() - output value (uV) - regulator_get/set_state() - output on/off stateWould get/set_enable() be better?
Quoted 6 lines
- regulator_get/set_mode() - output operation mode
To get the regulator device:
-regulator_get()- by name only
-regulator_i2c_get()- by i2c bus address (of pmic parent)
-regulator_spi_get()- by spi bus address (of pmic parent)For the last two, why are we using bus address? This should be by a phandle reference or nane.
Quoted 78 lines
An optional and useful regulator framework features are two descriptors:
- structregulator_desc- describes the regulator name and output value limits should be defined by device driver for each regulator output.- struct
regulator_mode_desc- (array) describes a number of operation modes supported by each regulator output.The 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 comments--- drivers/power/Makefile | 1 + drivers/power/regulator-uclass.c | 227 ++++++++++++++++++++++++++++ include/dm/uclass-id.h | 1 + include/power/regulator.h | 310 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 539 insertions(+)create mode 100644
drivers/power/regulator-uclass.ccreate mode 100644include/power/regulator.hdrivers/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 +17
-0@@ -0,0 +1,227 @@ +/* +* 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> drivers/power/regulator-uclass.c line 27
Quoted 10 lines
drivers/power/regulator-uclass.c new file +10
-0+ +DECLARE_GLOBAL_DATA_PTR ; + +int regulator_get_cnt (struct udevice *dev,int type,int *cnt) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_PMIC_REGULATOR ); +if (!ops) +return -ENODEV ;This is an error so you should be able to just
assert(). Failing that let's use-ENXIOas you do below.
Quoted 6 lines
drivers/power/regulator-uclass.c line 30
Quoted 3 lines
drivers/power/regulator-uclass.c new file +3
-0+ +if (!ops->get_cnt) +return -EPERM ;
-ENOSYSfor these.
Ah, I missed this one, will fix in V4.
Quoted 234 lines
Quoted 234 lines
drivers/power/regulator-uclass.c new file +197
-0+ +return ops->get_cnt (dev, type, cnt); +} + +int regulator_get_value_desc (struct udevice *dev,int type,int number, +struct regulator_value_desc **desc) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_PMIC_REGULATOR ); +if (!ops) +return -ENXIO ; + +if (!ops->get_value_desc) +return -EPERM ; + +return ops->get_value_desc (dev, type, number, desc); +} + +int regulator_get_mode_desc (struct udevice *dev,int type,int number, +int *mode_cnt,struct regulator_mode_desc **desc) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_PMIC_REGULATOR ); +if (!ops) +return -ENXIO ; + +if (!ops->get_mode_desc_array) +return -EPERM ; + +return ops->get_mode_desc_array (dev, type, number, mode_cnt, desc); +} + +int regulator_get_value (struct udevice *dev,int type,int number,int *value) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_PMIC_REGULATOR ); +if (!ops) +return -ENODEV ; + +if (!ops->get_value) +return -EPERM ; + +return ops->get_value (dev, type, number, value); +} + +int regulator_set_value (struct udevice *dev,int type,int number,int value) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_PMIC_REGULATOR ); +if (!ops) +return -ENODEV ; + +if (!ops->set_value) +return -EPERM ; + +return ops->set_value (dev, type, number, value); +} + +int regulator_get_state (struct udevice *dev,int type,int number,int *state) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_PMIC_REGULATOR ); +if (!ops) +return -ENODEV ; + +if (!ops->get_state) +return -EPERM ; + +return ops->get_state (dev, type, number, state); +} + +int regulator_set_state (struct udevice *dev,int type,int number,int state) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_PMIC_REGULATOR ); +if (!ops) +return -ENODEV ; + +if (!ops->set_state) +return -EPERM ; + +return ops->set_state (dev, type, number, state); +} + +int regulator_get_mode (struct udevice *dev,int type,int number,int *mode) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_PMIC_REGULATOR ); +if (!ops) +return -ENODEV ; + +if (!ops->get_mode) +return -EPERM ; + +return ops->get_mode (dev, type, number, mode); +} + +int regulator_set_mode (struct udevice *dev,int type,int number,int mode) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_PMIC_REGULATOR ); +if (!ops) +return -ENODEV ; + +if (!ops->set_mode) +return -EPERM ; + +return ops->set_mode (dev, type, number, mode); +} + +int regulator_get (char *name,struct udevice **regulator) +{ +struct udevice *dev; +struct uclass *uc; +int ret; + + ret =uclass_get (UCLASS_PMIC_REGULATOR , &uc); +if (ret) { +error ("Regulator uclass not initialized!" ); +return ret; + } + + uclass_foreach_dev(dev, uc) { +if (!dev) +continue ; + +if (!strncmp (name, dev->name,strlen (name))) { + ret =device_probe (dev); +if (ret) +error ("Dev: %s probe failed" , dev->name); + *regulator = dev; +return ret; + } + } + + *regulator =NULL ; +return -EINVAL ; +} + +int regulator_i2c_get (int bus,int addr,struct udevice **regulator) +{ +struct udevice *pmic; +int ret; + +/* First get parent pmic device */ + ret =pmic_i2c_get (bus, addr, &pmic); +if (ret) { +error ("Chip: %d on bus %d not found!" , addr, bus); +return ret; + } + +/* Get the first regulator child of pmic device */ +if (device_get_first_child_by_uclass_id (pmic,UCLASS_PMIC_REGULATOR , + regulator)) { +error ("PMIC: %s regulator child not found!" , pmic->name); + *regulator =NULL ; +return ret; + } + +return 0 ; +} + +int regulator_spi_get (int bus,int cs,struct udevice **regulator) +{ +struct udevice *pmic; +int ret; + +/* First get parent pmic device */ + ret =pmic_spi_get (bus, cs, &pmic); +if (ret) { +error ("Chip: %d on bus %d not found!" , cs, bus); +return ret; + } + +/* Get the first regulator child of pmic device */ +if (device_get_first_child_by_uclass_id (pmic,UCLASS_PMIC_REGULATOR , + regulator)) { +error ("PMIC: %s regulator child not found!" , pmic->name); + *regulator =NULL ; +return ret; + } + +return 0 ; +} + +UCLASS_DRIVER (regulator) = { + .id =UCLASS_PMIC_REGULATOR , + .name ="regulator" , +};include/dm/uclass-id.h +1
-0@@ -37,6 +37,7 @@ enum uclass_id {/* PMIC uclass and PMIC related uclasses */ UCLASS_PMIC , +UCLASS_PMIC_REGULATOR ,UCLASS_COUNT , UCLASS_INVALID = -1,include/power/regulator.h new file +19
-0@@ -0,0 +1,310 @@ +/* +* Copyright (C) 2014-2015 Samsung Electronics +* Przemyslaw Marczak <[email protected]> +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#ifndef _INCLUDE_REGULATOR_H_ +#define _INCLUDE_REGULATOR_H_ + +#define DESC_NAME_LEN 20 + +/* enum regulator_type - used for regulator_*() variant calls */ +enum regulator_type { +REGULATOR_TYPE_LDO =0 , +REGULATOR_TYPE_BUCK , +REGULATOR_TYPE_DVS , +}; +
Quoted 9 lines
include/power/regulator.h line 24
Quoted 5 lines
include/power/regulator.h new file +5
-0+/* enum regulator_out_state - used for ldo/buck output state setting */ +enum regulator_out_state { +REGULATOR_OFF =0 , +REGULATOR_ON , +};If we will only ever have on/off perhaps we don't need this enum and could just use a bool?
Fixed in V3.
Quoted 13 lines
include/power/regulator.h line 33
Quoted 9 lines
include/power/regulator.h new file +9
-0+ +/** +* struct regulator_value_desc - this structure holds an information about +* each regulator voltage limits. There is no "step" voltage value - so driver +* should take care of this. This is rather platform specific so can be +* taken from the device-tree. +* +* @type - one of: DESC_TYPE_LDO, DESC_TYPE_BUCK or DESC_TYPE_DVS +* @number - hardware internal regulator number What is this numbering and where does it come from? It is specified by the PMIC datasheet? Can you expand the comment a bit?
Quoted 2 lines
Actually I think this numbering should go away and we should use names instead.
This suggestion is implemented in V3.
Quoted 6 lines
Quoted 6 lines
include/power/regulator.h new file +6
-0+* @min_uV - minimum voltage (micro Volts) +* @max_uV - maximum voltage (micro Volts) +* @name - name of regulator - usually will be taken from device tree and +* can describe regulator output connected hardware, e.g. "eMMC" +*/ +struct regulator_value_desc {
Quoted 9 lines
include/power/regulator.h line 44
Quoted 5 lines
include/power/regulator.h new file +5
-0+int type; +int number; +int min_uV; +int max_uV; +char name[DESC_NAME_LEN ];What do you think about making this a const char * and we alloc it with
strdup()?
Also implemented in V3.
Quoted 315 lines
include/power/regulator.h line 50
Quoted 6 lines
include/power/regulator.h new file +6
-0+}; + +/** +* struct regulator_mode_desc - this structure holds an information about +* each regulator operation modes. Probably in most cases - an array. +* This will be probably a driver static data since it's device specific. driver-static (I think you mean)
include/power/regulator.h line 53
Quoted 3 lines
include/power/regulator.h new file +3
-0+* +* @mode - a driver specific mode number - used for regulator command +* @register_value - a driver specific value for this mode driver-specific, you are creating an adjective
Quoted 10 lines
include/power/regulator.h new file +10
-0+* @name - the name of mode - used for regulator command +*/ +struct regulator_mode_desc { +int mode; +int register_value; +char *name; +}; + +/* PMIC regulator device operations */ +struct dm_regulator_ops {include/power/regulator.h line 73
Quoted 10 lines
include/power/regulator.h new file +10
-0+/** +* get_cnt - get the number of a given regulator 'type' outputs +* +* @dev - regulator device +* @type - regulator type, one of enum regulator_type +* Gets: +* @cnt - regulator count +* Returns: 0 on success or negative value of errno. +*/ +int (*get_cnt)(struct udevice *dev,int type,int *cnt);
get_countReturn count in return value instead of a parameter.
Quoted 7 lines
include/power/regulator.h new file +7
-0+ +/** +* Regulator output value descriptor is specific for each output. +* It's usually driver static data, but output value limits are +* often defined in the device-tree, so those are platform dependent +* attributes. +* include/power/regulator.h line 90
Quoted 10 lines
include/power/regulator.h new file +10
-0+* get_value_desc - get value descriptor of the given regulator output +* @dev - regulator device +* @type - regulator type, one of enum regulator_type +* @number - regulator number +* Gets: +* @desc - pointer to the descriptor +* Returns: 0 on success or negative value of errno. +*/ +int (*get_value_desc)(struct udevice *dev,int type,int number, +struct regulator_value_desc **desc);You could use descp, to indicate it returns a pointer.
include/power/regulator.h line 103
Quoted 13 lines
include/power/regulator.h new file +13
-0+ +/** +* Regulator output mode descriptors are device specific. +* It's usually driver static data. +* Each regulator output can support different mode types, +* so usually will return an array with a number 'mode_desc_cnt' +* of mode descriptors. +* +* get_mode_desc_array - get mode descriptor array of the given +* regulator output number +* @dev - regulator device +* @type - regulator type, one of 'enum regulator_type' +* @number - regulator number
regulator_numwould be betterinclude/power/regulator.h line 109
Quoted 6 lines
include/power/regulator.h new file +6
-0+* Gets: +* @mode_desc_cnt - descriptor array entry count +* @desc - pointer to the descriptor array +* Returns: 0 on success or negative value of errno. +*/ + int (*get_mode_desc_array)(struct udevice *dev, int type,So should type be an enum?
Quoted 6 lines
include/power/regulator.h new file +6
-0+ int number, int *mode_desc_cnt, + struct regulator_mode_desc **desc); + +/** +* The regulator output value function calls operates on a micro Volts, +* however the regulator commands operates on a mili Volt unit. include/power/regulator.h line 125
Quoted 10 lines
include/power/regulator.h new file +10
-0+* +* get/set_value - get/set output value of the given output number +* @dev - regulator device +* @type - regulator type, one of 'enum regulator_type' +* @number - regulator number +* Sets/Gets: +* @value - set or get output value +* Returns: 0 on success or negative value of errno. +*/ +int (*get_value)(struct udevice *dev,int type,int number,int *value);Return value in return value instead of a parameter.
include/power/regulator.h line 129
Quoted 4 lines
include/power/regulator.h new file +4
-0+int (*set_value)(struct udevice *dev,int type,int number,int value); + +/** +* The most basic feature of the regulator output is it's on/off state. its
include/power/regulator.h line 139
Quoted 10 lines
include/power/regulator.h new file +10
-0+* +* get/set_state - get/set on/off state of the given output number +* @dev - regulator device +* @type - regulator type, one of 'enum regulator_type' +* @number - regulator number +* Sets/Gets: +* @state - set or get one of 'enum regulator_out_state' +* Returns: 0 on success or negative value of errno. +*/ +int (*get_state)(struct udevice *dev,int type,int number,int *state);Return state in return value instead of a parameter.
Quoted 6 lines
include/power/regulator.h new file +6
-0+int (*set_state)(struct udevice *dev,int type,int number,int state); + +/** +* The 'get/set_mode()' function calls should operate on a driver +* specific mode definitions, which should be found in: +* field 'mode' of struct regulator_mode_desc. include/power/regulator.h line 155
Quoted 10 lines
include/power/regulator.h new file +10
-0+* +* get/set_mode - get/set operation mode of the given output number +* @dev - regulator device +* @type - regulator type, one of 'enum regulator_type' +* @number - regulator number +* Sets/Gets: +* @mode - set or get output mode +* Returns: 0 on success or negative value of errno. +*/ +int (*get_mode)(struct udevice *dev,int type,int number,int *mode);Return mode in return value.
include/power/regulator.h line 160
Quoted 5 lines
include/power/regulator.h new file +5
-0+int (*set_mode)(struct udevice *dev,int type,int number,int mode); +}; + +/** +* regulator_get_cnt: returns the number of driver registered regulators. driver-registered
include/power/regulator.h line 169
Quoted 9 lines
include/power/regulator.h new file +9
-0+* This is used for pmic regulator command purposes. +* +* @dev - pointer to the regulator device +* @type - regulator type: device specific +* Gets: +* @cnt - regulator count +* Returns: 0 on success or negative value of errno. +*/ +int regulator_get_cnt (struct udevice *dev,int type,int *cnt);
regulator_get_count. Return count in return value instead of a parameter.Quoted 30 lines
include/power/regulator.h new file +30
-0+ +/** +* regulator_get_value_desc: returns a pointer to the regulator value +* descriptor of a given device regulator output number. +* +* @dev - pointer to the regulator device +* @type - regulator descriptor type +* @number - descriptor number (regulator output number) +* Gets: +* @desc - pointer to the descriptor +* Returns: 0 on success or negative value of errno. +*/ +int regulator_get_value_desc (struct udevice *dev,int type,int number, +struct regulator_value_desc **desc); + +/** +* regulator_get_mode_desc: returns a pointer to the array of regulator mode +* descriptors of a given device regulator type and number. +* +* @dev - pointer to the regulator device +* @type - regulator type: device specific +* @number - output number: device specific +* Gets: +* @mode_cnt - descriptor array entry count +* @desc - pointer to the descriptor array +* Returns: 0 on success or negative value of errno. +*/ +int regulator_get_mode_desc (struct udevice *dev,int type,int number, +int *mode_cnt,struct regulator_mode_desc **desc); +include/power/regulator.h line 209
Quoted 10 lines
include/power/regulator.h new file +10
-0+/** +* regulator_get_value: returns voltage value of a given device +* regulator type number. +* +* @dev - pointer to the regulator device +* @type - regulator type: device specific +* @number - output number: device specific +* Gets: +* @val - returned voltage - unit: uV (micro Volts) +* Returns: 0 on success or negative value of errno. You may as well return the voltage in the return value, unless it can be -ve (I assume not?)
Quoted 19 lines
include/power/regulator.h new file +19
-0+*/ +int regulator_get_value (struct udevice *dev,int type,int number,int *val); + +/** +* regulator_set_value: set the voltage value of a given device regulator type +* number to the given one passed by the argument: @val +* +* @dev - pointer to the regulator device +* @type - regulator type: device specific +* @number - output number: device specific +* @val - voltage value to set - unit: uV (micro Volts) +* Returns - 0 on success or -errno val if fails +*/ +int regulator_set_value (struct udevice *dev,int type,int number,int val); + +/** +* regulator_get_state: returns output state of a given device +* regulator type number. +* include/power/regulator.h line 238
Quoted 10 lines
include/power/regulator.h new file +10
-0+* @dev - pointer to the regulator device +* @type - regulator type, device specific +* @number - regulator number, device specific +* Gets: +* @state - returned regulator number output state: +* - REGULATOR_OFF (0) - disable +* - REGULATOR_ON (1) - enable +* Returns: - 0 on success or -errno val if fails +*/ +int regulator_get_state (struct udevice *dev,int type,int number,int *state);Return state in return value instead of a parameter.
Quoted 20 lines
include/power/regulator.h new file +20
-0+ +/** +* regulator_set_state: set output state of a given device regulator type +* number to the given one passed by the argument: @state +* +* @dev - pointer to the regulator device +* @type - regulator type: device specific +* @number - output number: device specific +* @state - output state to set +* - enum REGULATOR_OFF == 0 - disable +* - enum REGULATOR_ON == 1 - enable +* Returns - 0 on success or -errno val if fails +*/ +int regulator_set_state (struct udevice *dev,int type,int number,int state); + +/** +* regulator_get_mode: get mode number of a given device regulator type number +* +* @dev - pointer to the regulator device +* @type - output number: device specific include/power/regulator.h line 268
Quoted 10 lines
include/power/regulator.h new file +10
-0+* @number - output number: device specific +* Gets: +* @mode - returned mode number +* Returns - 0 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 'regulator_mode_desc' has +* a mode field for this purpose and register_value for a raw register value. +*/ +int regulator_get_mode (struct udevice *dev,int type,int number,int *mode);Return mode in return value instead of a parameter.
Quoted 30 lines
include/power/regulator.h new file +30
-0+ +/** +* regulator_set_mode: set given regulator type and number mode to the given +* one passed by the argument: @mode +* +* @dev - pointer to the regulator device +* @type - output number: device specific +* @number - output number: device specific +* @mode - mode type (struct regulator_mode_desc.mode) +* 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 type,int number,int mode); + +/** +* regulator_..._get: returns the pointer to the pmic regulator device +* by specified arguments: +* +* NAME: +* @name - device name (useful for specific names) +* or SPI/I2C interface: +* @bus - device I2C/SPI bus number +* @addr_cs - device specific address for I2C or chip select for SPI, +* on the given bus number +* Gets: +* @regulator - pointer to the pmic device +* Returns: 0 on success or negative value of errno. include/power/regulator.h line 308
Quoted 10 lines
include/power/regulator.h new file +10
-0+* +* The returned 'regulator' device can be used with: +* - regulator_get/set_* +* and if pmic_platdata is given, then also with: +* - pmic_if_* calls +* The last one is used for the pmic command purposes. +*/ +int regulator_get (char *name,struct udevice **regulator); +int regulator_i2c_get (int bus,int addr,struct udevice **regulator); +int regulator_spi_get (int bus,int cs,struct udevice **regulator);Hoping you don't need these last two!
Quoted 9 lines
Quoted 5 lines
include/power/regulator.h new file +2
-1+ +#endif /* _INCLUDE_REGULATOR_H_ */ --1.9.1
Regards,
Simon
Thank you,
Signature · 4 lines
Przemyslaw Marczak Samsung R&D Institute Poland Samsung Electronics p.marczak at samsung.com
PATCH v2 4/12 dm: pmic: add implementation of driver model regulator uclass
In reply to Przemyslaw MarczakHi,
Quoted 237 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.The regulator framework is based on a 'struct
dm_regulator_ops'. It provides a common function calls, for it's basic features:
-regulator_get_cnt()- number of outputs each type
-regulator_get_value_desc()- describe output value limits- regulator_get_mode_desc() - describe output operation modes - regulator_get/set_value() - output value (uV) - regulator_get/set_state() - output on/off state - regulator_get/set_mode() - output operation modeTo get the regulator device:
-regulator_get()- by name only
-regulator_i2c_get()- by i2c bus address (of pmic parent)
-regulator_spi_get()- by spi bus address (of pmic parent)An optional and useful regulator framework features are two descriptors:
- structregulator_desc- describes the regulator name and output value limits should be defined by device driver for each regulator output.- struct
regulator_mode_desc- (array) describes a number of operation modes supported by each regulator output.The 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 comments--- drivers/power/Makefile | 1 + drivers/power/regulator-uclass.c | 227 ++++++++++++++++++++++++++++ include/dm/uclass-id.h | 1 + include/power/regulator.h | 310 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 539 insertions(+) create mode 100644 drivers/power/regulator-uclass.c create mode 100644 include/power/regulator.hdrivers/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 +159
-0@@ -0,0 +1,227 @@ +/* +* 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> + +DECLARE_GLOBAL_DATA_PTR ; + +int regulator_get_cnt (struct udevice *dev,int type,int *cnt) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_PMIC_REGULATOR ); +if (!ops) +return -ENODEV ; + +if (!ops->get_cnt) +return -EPERM ; + +return ops->get_cnt (dev, type, cnt); +} + +int regulator_get_value_desc (struct udevice *dev,int type,int number, +struct regulator_value_desc **desc) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_PMIC_REGULATOR ); +if (!ops) +return -ENXIO ; + +if (!ops->get_value_desc) +return -EPERM ; + +return ops->get_value_desc (dev, type, number, desc); +} + +int regulator_get_mode_desc (struct udevice *dev,int type,int number, +int *mode_cnt,struct regulator_mode_desc **desc) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_PMIC_REGULATOR ); +if (!ops) +return -ENXIO ; + +if (!ops->get_mode_desc_array) +return -EPERM ; + +return ops->get_mode_desc_array (dev, type, number, mode_cnt, desc); +} + +int regulator_get_value (struct udevice *dev,int type,int number,int *value) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_PMIC_REGULATOR ); +if (!ops) +return -ENODEV ; + +if (!ops->get_value) +return -EPERM ; + +return ops->get_value (dev, type, number, value); +} + +int regulator_set_value (struct udevice *dev,int type,int number,int value) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_PMIC_REGULATOR ); +if (!ops) +return -ENODEV ; + +if (!ops->set_value) +return -EPERM ; + +return ops->set_value (dev, type, number, value); +} + +int regulator_get_state (struct udevice *dev,int type,int number,int *state) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_PMIC_REGULATOR ); +if (!ops) +return -ENODEV ; + +if (!ops->get_state) +return -EPERM ; + +return ops->get_state (dev, type, number, state); +} + +int regulator_set_state (struct udevice *dev,int type,int number,int state) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_PMIC_REGULATOR ); +if (!ops) +return -ENODEV ; + +if (!ops->set_state) +return -EPERM ; + +return ops->set_state (dev, type, number, state); +} + +int regulator_get_mode (struct udevice *dev,int type,int number,int *mode) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_PMIC_REGULATOR ); +if (!ops) +return -ENODEV ; + +if (!ops->get_mode) +return -EPERM ; + +return ops->get_mode (dev, type, number, mode); +} + +int regulator_set_mode (struct udevice *dev,int type,int number,int mode) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_PMIC_REGULATOR ); +if (!ops) +return -ENODEV ; + +if (!ops->set_mode) +return -EPERM ; + +return ops->set_mode (dev, type, number, mode); +} + +int regulator_get (char *name,struct udevice **regulator) +{ +struct udevice *dev; +struct uclass *uc; +int ret; + + ret =uclass_get (UCLASS_PMIC_REGULATOR , &uc); +if (ret) { +error ("Regulator uclass not initialized!" ); +return ret; + }
drivers/power/regulator-uclass.c line 169
Quoted 10 lines
drivers/power/regulator-uclass.c new file +10
-0+ + uclass_foreach_dev(dev, uc) { +if (!dev) +continue ; + +if (!strncmp (name, dev->name,strlen (name))) { + ret =device_probe (dev); +if (ret) +error ("Dev: %s probe failed" , dev->name); + *regulator = dev;
Shouldn't we set regulator=NULL if device_probe() returns an error?
Quoted 377 lines
drivers/power/regulator-uclass.c new file +58
-0+return ret; + } + } + + *regulator =NULL ; +return -EINVAL ; +} + +int regulator_i2c_get (int bus,int addr,struct udevice **regulator) +{ +struct udevice *pmic; +int ret; + +/* First get parent pmic device */ + ret =pmic_i2c_get (bus, addr, &pmic); +if (ret) { +error ("Chip: %d on bus %d not found!" , addr, bus); +return ret; + } + +/* Get the first regulator child of pmic device */ +if (device_get_first_child_by_uclass_id (pmic,UCLASS_PMIC_REGULATOR , + regulator)) { +error ("PMIC: %s regulator child not found!" , pmic->name); + *regulator =NULL ; +return ret; + } + +return 0 ; +} + +int regulator_spi_get (int bus,int cs,struct udevice **regulator) +{ +struct udevice *pmic; +int ret; + +/* First get parent pmic device */ + ret =pmic_spi_get (bus, cs, &pmic); +if (ret) { +error ("Chip: %d on bus %d not found!" , cs, bus); +return ret; + } + +/* Get the first regulator child of pmic device */ +if (device_get_first_child_by_uclass_id (pmic,UCLASS_PMIC_REGULATOR , + regulator)) { +error ("PMIC: %s regulator child not found!" , pmic->name); + *regulator =NULL ; +return ret; + } + +return 0 ; +} + +UCLASS_DRIVER (regulator) = { + .id =UCLASS_PMIC_REGULATOR , + .name ="regulator" , +};include/dm/uclass-id.h +1
-0@@ -37,6 +37,7 @@ enum uclass_id {/* PMIC uclass and PMIC related uclasses */ UCLASS_PMIC , +UCLASS_PMIC_REGULATOR ,UCLASS_COUNT , UCLASS_INVALID = -1,include/power/regulator.h new file +300
-0@@ -0,0 +1,310 @@ +/* +* Copyright (C) 2014-2015 Samsung Electronics +* Przemyslaw Marczak <[email protected]> +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#ifndef _INCLUDE_REGULATOR_H_ +#define _INCLUDE_REGULATOR_H_ + +#define DESC_NAME_LEN 20 + +/* enum regulator_type - used for regulator_*() variant calls */ +enum regulator_type { +REGULATOR_TYPE_LDO =0 , +REGULATOR_TYPE_BUCK , +REGULATOR_TYPE_DVS , +}; + +/* enum regulator_out_state - used for ldo/buck output state setting */ +enum regulator_out_state { +REGULATOR_OFF =0 , +REGULATOR_ON , +}; + +/** +* struct regulator_value_desc - this structure holds an information about +* each regulator voltage limits. There is no "step" voltage value - so driver +* should take care of this. This is rather platform specific so can be +* taken from the device-tree. +* +* @type - one of: DESC_TYPE_LDO, DESC_TYPE_BUCK or DESC_TYPE_DVS +* @number - hardware internal regulator number +* @min_uV - minimum voltage (micro Volts) +* @max_uV - maximum voltage (micro Volts) +* @name - name of regulator - usually will be taken from device tree and +* can describe regulator output connected hardware, e.g. "eMMC" +*/ +struct regulator_value_desc { +int type; +int number; +int min_uV; +int max_uV; +char name[DESC_NAME_LEN ]; +}; + +/** +* struct regulator_mode_desc - this structure holds an information about +* each regulator operation modes. Probably in most cases - an array. +* This will be probably a driver static data since it's device specific. +* +* @mode - a driver specific mode number - used for regulator command +* @register_value - a driver specific value for this mode +* @name - the name of mode - used for regulator command +*/ +struct regulator_mode_desc { +int mode; +int register_value; +char *name; +}; + +/* PMIC regulator device operations */ +struct dm_regulator_ops { +/** +* get_cnt - get the number of a given regulator 'type' outputs +* +* @dev - regulator device +* @type - regulator type, one of enum regulator_type +* Gets: +* @cnt - regulator count +* Returns: 0 on success or negative value of errno. +*/ +int (*get_cnt)(struct udevice *dev,int type,int *cnt); + +/** +* Regulator output value descriptor is specific for each output. +* It's usually driver static data, but output value limits are +* often defined in the device-tree, so those are platform dependent +* attributes. +* +* get_value_desc - get value descriptor of the given regulator output +* @dev - regulator device +* @type - regulator type, one of enum regulator_type +* @number - regulator number +* Gets: +* @desc - pointer to the descriptor +* Returns: 0 on success or negative value of errno. +*/ +int (*get_value_desc)(struct udevice *dev,int type,int number, +struct regulator_value_desc **desc); + +/** +* Regulator output mode descriptors are device specific. +* It's usually driver static data. +* Each regulator output can support different mode types, +* so usually will return an array with a number 'mode_desc_cnt' +* of mode descriptors. +* +* get_mode_desc_array - get mode descriptor array of the given +* regulator output number +* @dev - regulator device +* @type - regulator type, one of 'enum regulator_type' +* @number - regulator number +* Gets: +* @mode_desc_cnt - descriptor array entry count +* @desc - pointer to the descriptor array +* Returns: 0 on success or negative value of errno. +*/ +int (*get_mode_desc_array)(struct udevice *dev,int type, +int number,int *mode_desc_cnt, +struct regulator_mode_desc **desc); + +/** +* The regulator output value function calls operates on a micro Volts, +* however the regulator commands operates on a mili Volt unit. +* +* get/set_value - get/set output value of the given output number +* @dev - regulator device +* @type - regulator type, one of 'enum regulator_type' +* @number - regulator number +* Sets/Gets: +* @value - set or get output value +* Returns: 0 on success or negative value of errno. +*/ +int (*get_value)(struct udevice *dev,int type,int number,int *value); +int (*set_value)(struct udevice *dev,int type,int number,int value); + +/** +* The most basic feature of the regulator output is it's on/off state. +* +* get/set_state - get/set on/off state of the given output number +* @dev - regulator device +* @type - regulator type, one of 'enum regulator_type' +* @number - regulator number +* Sets/Gets: +* @state - set or get one of 'enum regulator_out_state' +* Returns: 0 on success or negative value of errno. +*/ +int (*get_state)(struct udevice *dev,int type,int number,int *state); +int (*set_state)(struct udevice *dev,int type,int number,int state); + +/** +* The 'get/set_mode()' function calls should operate on a driver +* specific mode definitions, which should be found in: +* field 'mode' of struct regulator_mode_desc. +* +* get/set_mode - get/set operation mode of the given output number +* @dev - regulator device +* @type - regulator type, one of 'enum regulator_type' +* @number - regulator number +* Sets/Gets: +* @mode - set or get output mode +* Returns: 0 on success or negative value of errno. +*/ +int (*get_mode)(struct udevice *dev,int type,int number,int *mode); +int (*set_mode)(struct udevice *dev,int type,int number,int mode); +}; + +/** +* regulator_get_cnt: returns the number of driver registered regulators. +* This is used for pmic regulator command purposes. +* +* @dev - pointer to the regulator device +* @type - regulator type: device specific +* Gets: +* @cnt - regulator count +* Returns: 0 on success or negative value of errno. +*/ +int regulator_get_cnt (struct udevice *dev,int type,int *cnt); + +/** +* regulator_get_value_desc: returns a pointer to the regulator value +* descriptor of a given device regulator output number. +* +* @dev - pointer to the regulator device +* @type - regulator descriptor type +* @number - descriptor number (regulator output number) +* Gets: +* @desc - pointer to the descriptor +* Returns: 0 on success or negative value of errno. +*/ +int regulator_get_value_desc (struct udevice *dev,int type,int number, +struct regulator_value_desc **desc); + +/** +* regulator_get_mode_desc: returns a pointer to the array of regulator mode +* descriptors of a given device regulator type and number. +* +* @dev - pointer to the regulator device +* @type - regulator type: device specific +* @number - output number: device specific +* Gets: +* @mode_cnt - descriptor array entry count +* @desc - pointer to the descriptor array +* Returns: 0 on success or negative value of errno. +*/ +int regulator_get_mode_desc (struct udevice *dev,int type,int number, +int *mode_cnt,struct regulator_mode_desc **desc); + +/** +* regulator_get_value: returns voltage value of a given device +* regulator type number. +* +* @dev - pointer to the regulator device +* @type - regulator type: device specific +* @number - output number: device specific +* Gets: +* @val - returned voltage - unit: uV (micro Volts) +* Returns: 0 on success or negative value of errno. +*/ +int regulator_get_value (struct udevice *dev,int type,int number,int *val); + +/** +* regulator_set_value: set the voltage value of a given device regulator type +* number to the given one passed by the argument: @val +* +* @dev - pointer to the regulator device +* @type - regulator type: device specific +* @number - output number: device specific +* @val - voltage value to set - unit: uV (micro Volts) +* Returns - 0 on success or -errno val if fails +*/ +int regulator_set_value (struct udevice *dev,int type,int number,int val); + +/** +* regulator_get_state: returns output state of a given device +* regulator type number. +* +* @dev - pointer to the regulator device +* @type - regulator type, device specific +* @number - regulator number, device specific +* Gets: +* @state - returned regulator number output state: +* - REGULATOR_OFF (0) - disable +* - REGULATOR_ON (1) - enable +* Returns: - 0 on success or -errno val if fails +*/ +int regulator_get_state (struct udevice *dev,int type,int number,int *state); + +/** +* regulator_set_state: set output state of a given device regulator type +* number to the given one passed by the argument: @state +* +* @dev - pointer to the regulator device +* @type - regulator type: device specific +* @number - output number: device specific +* @state - output state to set +* - enum REGULATOR_OFF == 0 - disable +* - enum REGULATOR_ON == 1 - enable +* Returns - 0 on success or -errno val if fails +*/ +int regulator_set_state (struct udevice *dev,int type,int number,int state); + +/** +* regulator_get_mode: get mode number of a given device regulator type number +* +* @dev - pointer to the regulator device +* @type - output number: device specific +* @number - output number: device specific +* Gets: +* @mode - returned mode number +* Returns - 0 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 'regulator_mode_desc' has +* a mode field for this purpose and register_value for a raw register value. +*/ +int regulator_get_mode (struct udevice *dev,int type,int number,int *mode); + +/** +* regulator_set_mode: set given regulator type and number mode to the given +* one passed by the argument: @mode +* +* @dev - pointer to the regulator device +* @type - output number: device specific +* @number - output number: device specific +* @mode - mode type (struct regulator_mode_desc.mode) +* 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 type,int number,int mode); + +/** +* regulator_..._get: returns the pointer to the pmic regulator device +* by specified arguments: +* +* NAME: +* @name - device name (useful for specific names) +* or SPI/I2C interface: +* @bus - device I2C/SPI bus number +* @addr_cs - device specific address for I2C or chip select for SPI, +* on the given bus number +* Gets: +* @regulator - pointer to the pmic device +* Returns: 0 on success or negative value of errno. +* +* The returned 'regulator' device can be used with:
include/power/regulator.h line 310
Quoted 10 lines
include/power/regulator.h new file +10
-0+* - regulator_get/set_* +* and if pmic_platdata is given, then also with: +* - pmic_if_* calls +* The last one is used for the pmic command purposes. +*/ +int regulator_get (char *name,struct udevice **regulator); +int regulator_i2c_get (int bus,int addr,struct udevice **regulator); +int regulator_spi_get (int bus,int cs,struct udevice **regulator); + +#endif /* _INCLUDE_REGULATOR_H_ */
Br,
Robert
PATCH v2 4/12 dm: pmic: add implementation of driver model regulator uclass
Hello Robert,
Quoted 244 lines · Robert Baldyga
Hi,
Quoted 241 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.The regulator framework is based on a 'struct
dm_regulator_ops'. It provides a common function calls, for it's basic features:
-regulator_get_cnt()- number of outputs each type
-regulator_get_value_desc()- describe output value limits- regulator_get_mode_desc() - describe output operation modes - regulator_get/set_value() - output value (uV) - regulator_get/set_state() - output on/off state - regulator_get/set_mode() - output operation modeTo get the regulator device:
-regulator_get()- by name only
-regulator_i2c_get()- by i2c bus address (of pmic parent)
-regulator_spi_get()- by spi bus address (of pmic parent)An optional and useful regulator framework features are two descriptors:
- structregulator_desc- describes the regulator name and output value limits should be defined by device driver for each regulator output.- struct
regulator_mode_desc- (array) describes a number of operation modes supported by each regulator output.The 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 comments--- drivers/power/Makefile | 1 + drivers/power/regulator-uclass.c | 227 ++++++++++++++++++++++++++++ include/dm/uclass-id.h | 1 + include/power/regulator.h | 310 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 539 insertions(+)create mode 100644
drivers/power/regulator-uclass.ccreate mode 100644include/power/regulator.hdrivers/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 +163
-0@@ -0,0 +1,227 @@ +/* +* 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> + +DECLARE_GLOBAL_DATA_PTR ; + +int regulator_get_cnt (struct udevice *dev,int type,int *cnt) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_PMIC_REGULATOR ); +if (!ops) +return -ENODEV ; + +if (!ops->get_cnt) +return -EPERM ; + +return ops->get_cnt (dev, type, cnt); +} + +int regulator_get_value_desc (struct udevice *dev,int type,int number, +struct regulator_value_desc **desc) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_PMIC_REGULATOR ); +if (!ops) +return -ENXIO ; + +if (!ops->get_value_desc) +return -EPERM ; + +return ops->get_value_desc (dev, type, number, desc); +} + +int regulator_get_mode_desc (struct udevice *dev,int type,int number, +int *mode_cnt,struct regulator_mode_desc **desc) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_PMIC_REGULATOR ); +if (!ops) +return -ENXIO ; + +if (!ops->get_mode_desc_array) +return -EPERM ; + +return ops->get_mode_desc_array (dev, type, number, mode_cnt, desc); +} + +int regulator_get_value (struct udevice *dev,int type,int number,int *value) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_PMIC_REGULATOR ); +if (!ops) +return -ENODEV ; + +if (!ops->get_value) +return -EPERM ; + +return ops->get_value (dev, type, number, value); +} + +int regulator_set_value (struct udevice *dev,int type,int number,int value) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_PMIC_REGULATOR ); +if (!ops) +return -ENODEV ; + +if (!ops->set_value) +return -EPERM ; + +return ops->set_value (dev, type, number, value); +} + +int regulator_get_state (struct udevice *dev,int type,int number,int *state) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_PMIC_REGULATOR ); +if (!ops) +return -ENODEV ; + +if (!ops->get_state) +return -EPERM ; + +return ops->get_state (dev, type, number, state); +} + +int regulator_set_state (struct udevice *dev,int type,int number,int state) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_PMIC_REGULATOR ); +if (!ops) +return -ENODEV ; + +if (!ops->set_state) +return -EPERM ; + +return ops->set_state (dev, type, number, state); +} + +int regulator_get_mode (struct udevice *dev,int type,int number,int *mode) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_PMIC_REGULATOR ); +if (!ops) +return -ENODEV ; + +if (!ops->get_mode) +return -EPERM ; + +return ops->get_mode (dev, type, number, mode); +} + +int regulator_set_mode (struct udevice *dev,int type,int number,int mode) +{ +const struct dm_regulator_ops *ops; + + ops =pmic_get_uclass_ops (dev,UCLASS_PMIC_REGULATOR ); +if (!ops) +return -ENODEV ; + +if (!ops->set_mode) +return -EPERM ; + +return ops->set_mode (dev, type, number, mode); +} + +int regulator_get (char *name,struct udevice **regulator) +{ +struct udevice *dev; +struct uclass *uc; +int ret; + + ret =uclass_get (UCLASS_PMIC_REGULATOR , &uc); +if (ret) { +error ("Regulator uclass not initialized!" ); +return ret; + } + + uclass_foreach_dev(dev, uc) { +if (!dev) +continue ;
Quoted 9 lines
drivers/power/regulator-uclass.c line 169
Quoted 6 lines
drivers/power/regulator-uclass.c new file +6
-0+ +if (!strncmp (name, dev->name,strlen (name))) { + ret =device_probe (dev); +if (ret) +error ("Dev: %s probe failed" , dev->name); + *regulator = dev;Shouldn't we set regulator=NULL if
device_probe()returns an error?
Thanks, this is fixed in V3.
Quoted 4 lines
Br,
Robert
Best regards,
Signature · 4 lines
Przemyslaw Marczak Samsung R&D Institute Poland Samsung Electronics p.marczak at samsung.com
PATCH v2 5/12 dm: pmic: new commands: pmic and regulator
In reply to Przemyslaw MarczakThis 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 for UCLASS_PMIC devices, 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 exists
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.
---
Changes v2:
- remove errno_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.c
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.o
drivers/power/cmd_pmic.c new file +820 -0
820 lines not on this page · raw message
Signature · 1 line
1.9.1
PATCH v2 5/12 dm: pmic: new commands: pmic and regulator
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 exists
Quoted 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
-0
drivers/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.o
Can 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 of puts(), 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 5 lines
drivers/power/cmd_pmic.c new file +2
-1+); +#endif /* CONFIG_DM_REGULATOR_CMD */ --1.9.1
Regards,
Simon