Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for ADP5055 #2668

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open

Add support for ADP5055 #2668

wants to merge 3 commits into from

Conversation

actorreno
Copy link

PR Description

PR Type

  • Bug fix (a change that fixes an issue)
  • New feature (a change that adds new functionality)
  • Breaking change (a change that affects other repos or cause CIs to fail)

PR Checklist

  • I have conducted a self-review of my own code changes
  • I have tested the changes on the relevant hardware
  • I have updated the documentation outside this repo accordingly (if there is the case)

@nunojsa
Copy link
Collaborator

nunojsa commented Dec 6, 2024

Please, fix first the valid CI errors you have...

@actorreno actorreno force-pushed the dev/adp5055-regulator branch 9 times, most recently from 5d77901 to 36d5ba8 Compare December 9, 2024 02:38
@actorreno
Copy link
Author

actorreno commented Dec 9, 2024

It seems the checks returns some errors I couldn't capture when locally running commit check scripts like "./scripts/checkpatch <driver_file>"

I have fixed them except 1 last error which I am confused about since the error is not related to my files.
Screenshot below.

image

Edit: was fixed by rebasing to latest main

@actorreno actorreno force-pushed the dev/adp5055-regulator branch from 36d5ba8 to 03486f9 Compare December 18, 2024 04:25
Copy link
Contributor

@kister-jimenez kister-jimenez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ADP5055 is PMBUS compatible, should this be under hwmon/pmbus?

@actorreno
Copy link
Author

The datasheet did say "pmbus compatible" but it didn't have any pmbus commands the other typical pmbus dataseet contain
it also doesn't have an eeprom for the usual "pages" I see in other pmbus codes.

some colleagues agreed with me that it was just an i2c interface and decided it is better off in the regulator subsystem

@nunojsa
Copy link
Collaborator

nunojsa commented Jan 20, 2025

ADP5055 is PMBUS compatible, should this be under hwmon/pmbus?

Hmm, I do think this is a pertinent question... Looking at the description:

"The ADP5055 is a power management unit that combines three high performance buck regulators with a PMBus interface..."

So this looks like a typical power management device that fits in HWMON/PMBUs. Note that the pmbus subsystem also has an interface with the regulator subsystem and it will also check what standard PMbus registers are supported by the device. On top of that, you can pretty much bypass the standard registers and control the device as you want. Example, I see the VIDx_LOW/HIGH registers that could fit in the standard HWMON ABI and you totally support it even not using standard pmbus commands. There's also power good and overcurrent stuff that could very likely be made to work.

All the above to say that pmbus might be doable and allows you to better support this device (meaning, more features). You can also internally reach the apps engineer for this part and try to understand the actual PMBUS commands supported. Looking at the datasheet, I can see STATUS_CML to be supported.

Copy link
Collaborator

@nunojsa nunojsa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm still not convinced on the location of the driver but i'm already doing some comments on the DT bindings

0 - Physical EN pin is used for enabling.
1 - Internal Register is used for enabling.
2 - Both register and physical pin needed.
3 - Either register or physical pin.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks custom implementation of a subset of the ON_OFF_CONFIG command. Moreover, DT maintainers do not like much of properties like this where you just give the register code. You should have a string property and do the mapping in the driver (for register values). On top of that, you should likely control 3 gpios that should be mandatory for options 0 and 3.

Enables or disables over current protection
blanking (OCP) for all channels.
0 = Disabled
1 = Enabled
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need for the 0/1 description. Should encode the state in the property name. Simply adi,ocp-blanking and if the property is enabled, then it's pretty clear we're enabling the feature.

items:
minimum: 0
maximum: 3
default: 3, 3, 3
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You have a lot properties for the channels so I think it might be a good idea to create channel child nodes and have the properties per channel instead of this.

@actorreno
Copy link
Author

ADP5055 is PMBUS compatible, should this be under hwmon/pmbus?

Hmm, I do think this is a pertinent question... Looking at the description:

"The ADP5055 is a power management unit that combines three high performance buck regulators with a PMBus interface..."

So this looks like a typical power management device that fits in HWMON/PMBUs. Note that the pmbus subsystem also has an interface with the regulator subsystem and it will also check what standard PMbus registers are supported by the device. On top of that, you can pretty much bypass the standard registers and control the device as you want. Example, I see the VIDx_LOW/HIGH registers that could fit in the standard HWMON ABI and you totally support it even not using standard pmbus commands. There's also power good and overcurrent stuff that could very likely be made to work.

All the above to say that pmbus might be doable and allows you to better support this device (meaning, more features). You can also internally reach the apps engineer for this part and try to understand the actual PMBUS commands supported. Looking at the datasheet, I can see STATUS_CML to be supported.


Hi,

I understand the reason on why pmbus should be reconsidered and I have been trying to learn how regulators are incorporated in the subsystem. However, it seems that when using "pmbus_do_probe" it calls a function called "pmbus_init_common" that looks for specific registers mainly PMBUS_STATUS_BYTE or PMBUS_STATUS_WORD (address 0x78 and 0x79) and this doesn't exist in the device hence the driver cannot properly load.

A manual i2c transaction does yield a read error
image

Keeping it under the regulator subsystem still seems appropriate due to this.

Will yet to address dt-bindings feedbacks.

@actorreno actorreno force-pushed the dev/adp5055-regulator branch 2 times, most recently from 8e79e38 to bdc82e1 Compare February 5, 2025 01:46
@actorreno actorreno force-pushed the dev/adp5055-regulator branch 4 times, most recently from 2469301 to d4b3989 Compare February 10, 2025 08:40
@actorreno
Copy link
Author

(still correcting CI check)

v3:

.yaml:

-removed copyright
-removed description on "properties -> reg"
-added vendor prefix to gpios

  • regarding enable-mode property, I initailly coded the options but
    reduced this now to boolean. if 1, SW enable, if none use HW GPIOs
  • removed 0,1 definition for delay-power-good, also stated Tset value as suggested
  • removed mention of True False for boolean 'mask-power-good', plus uin32 ref removed
  • for dvs upper/lower limit, changed from 4 bits code to microvolts.
  • Calling enable/disbale-delay-ch as multiplier rather than a delay
  • removed GPIOs from "required"

.c:

  • removed OF header (not needed anymore) to not change kconfig
  • removed of_gpio.h
  • alphabetized headers
  • removed OF properties, now uses device_ or fwnode_
  • dropped all initialization to 0
  • edited enable-mode to a boolean to choose if sw or hw enable. if this
    is still too much, can remove everything including GPIOs next version
  • added some dev_err_probe and logs
  • removed duplicate property
  • kept previous state variables to just local ones
  • compacted val1-val3 as just val
  • regarding repetitive initiation using regmap_write, placed some inside device_for_each_child_node_scoped
  • removed redundant if-else
  • added an o_match_table/of_device_id
  • removed newline before module_device_table
  • removed i2c_set_clientdata
  • kept dev_err, still curious why dev_err_probe should replace it unlike other regulator driver
  • passed &adp5055_regmap_config instead

Kconfig:

  • select regmap_i2c

@actorreno actorreno requested a review from nunojsa February 10, 2025 23:57
description:
If present, configure channels to be enabled via software
instead of hardware enable.
type: boolean
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not think we need this. Can't we assume that if the gpios are not given, then we have SW enabled mode?

$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 7
default: 0
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, but we do not have that many possibilities for TSET right? That is why I mentioned 16 entries... Anyways, not going to push for it but bear in mind that DT maintainers can complain about this

Vout_low = Vout - DVS_lower_limit.
$ref: /schemas/types.yaml#/definitions/uint32
minimum: -190500
maximum: -10500
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are the above in uV? If so you should add the proper suffix in the property and drop $ref. See the available standard suffixes here:

https://github.com/devicetree-org/dt-schema/blob/main/dtschema/schemas/property-units.yaml#L81

#include <linux/device.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/module.h>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should include mod_devicetable.h for of_device_id

if (IS_ERR(adp5055->regmap)) {
ret = PTR_ERR(adp5055->regmap);
dev_err(dev, "Failed to allocate register map: %d\n", ret);
return ret;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can simply be:

return dev_err_probe(dev, PTR_ERR(adp5055->regmap), "...");

Ditto for all other error logs during probe()

if (adp5055->enable_mode_sw)
return (val_sw & mask) != 0;
else
return val_hw;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

redundant else


id = rdev_get_id(dev);
mask = 1 << id;
ret = regmap_read(adp5055->regmap, ADP5055_CTRL_MODE1, &val_sw);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

check the error code

int i, ret;
struct regmap *regmap = adp5055->regmap;
int val;

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need for this new line

ARRAY_SIZE(adp5055_disable_delay_ch_vals),
enable_delay_ch[i]);
if (ret < 0)
return dev_err_probe(dev, ret, "Failed to initialize enable-delay-ch. Using default.");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

80 column limit... You should break after ret I guess

if (IS_ERR(adp5055->hw_en_gpio[2])) {
return dev_err_probe(dev, PTR_ERR(adp5055->hw_en_gpio[2]),
"Failed to get hw_en_2 GPIO\n");
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need for {} when we just have one liner

@actorreno actorreno force-pushed the dev/adp5055-regulator branch 6 times, most recently from e74a25c to e773abc Compare February 18, 2025 05:05
@actorreno
Copy link
Author

v4

yaml:

  • turned 3 gpios into a gpio array
  • turned the delay from multipleir to actual delay in ms
    -added a tset property to change enum of dis/enable-delay-ch
    -edited dvs-limit-upper/lower default value actual value, it was 0 before
    -added suffix microvolt to the property and removed $ref
    -edited examples to match entry of yaml property list

c:

  • edited code for changes in yaml
    -added mod_devicetable.h
    -simplified error probes in probe()
  • dropped tabs and just used a space
  • removed redundant 'else'
  • added error code check in one regmap_read that had none
  • removed newline in between variable declarations
  • fixed 80 column limit issue
  • removed {} for one liner if/else
  • needed to add dvs-limit-upper/lower volts to register value code
  • placed gpio array check earlier than other properties

@actorreno actorreno requested a review from nunojsa February 18, 2025 05:42
specific resistor values on the CFG2 pin. If property is absent,
the setting time Tset defaults to 2.6ms. If present, Tset is
increased 8 times to 20.8ms.
type: boolean
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not having this with default suffixes? Just use an enum with two possible values with a default. I guess TSET has a default value if no resistor is soldered?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually the fact the supposed enum is only two choices made me think of using bool. will use an enum similar to the microseconds feedback below

hardware enable for channels 0-2. Should be marked 0 for active
low. Requires all three channels to be initialized. Not adding
the property turns the system to a software only enable mode.
maxItems: 3
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you also need minItems. IIRC, this is an all or nothing property. So we need to require all three GPIOs

description:
If present, enables power saving mode for
individual channels.
type: boolean
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would remove the -ch for all properties. It's already clear these properties are for the channel

description:
Configures the disable delay for each channel. Dependent on Tset.
enum: [0ms, 5.2ms, 10.4ms, 15.6ms, 20.8ms, 26ms, 31.2ms, 36.4ms]
default: 0ms
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, this is not how it should be done... Moreover you'll need the property to be in microseconds. This should be:

adi,disable-delay-us:
  description:
    Configures the disable delay for each channel. Dependent on Tset.
  enum: [0, 5200, 10400, 15600, 20800, 26000, 31200, 36400]
  default: 0

Ditto for all the other properties

- if:
properties:
adi,tset-8x: true

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: no need for extra line


if (adp5055->hw_en_array_gpios->ndescs != ADP5055_NUM_CH)
return -EINVAL;

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The above check only makes sense if the gpios are given. So, if (adp5055->hw_en_array_gpios)

device_for_each_child_node_scoped(dev, child) {
ret = fwnode_property_read_u32(child, "reg", &i);
if (ret || i >= ADP5055_NUM_CH)
return dev_err_probe(dev, ret, "Failed to read reg value of child node");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please separate the checks. It's checking for different things and the error message will be misleading in case i >= ADP5055_NUM_CH

&dvs_limit_lower_ch[i]);
if (ret)
return ret;

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The above two do not exist in the bindings and are not mandatory...

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The above was not addressed...

id = rdev_get_id(dev);
mask = BIT(id);

if (adp5055->enable_mode_sw) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where are you setting the above flag?. Anyways, I think you can use the hw_en_array_gpios pointer:

if (!adp5055->hw_en_array_gpios)
    return regmap_update_bits(adp5055->regmap, ADP5055_CTRL_MODE1, mask, en_val);

gpiod_set_value_cansleep(adp5055->hw_en_array_gpios->desc[id], en_val);
return 0;


gpiod_set_value_cansleep(adp5055->hw_en_array_gpios->desc[0], 0);
gpiod_set_value_cansleep(adp5055->hw_en_array_gpios->desc[1], 0);
gpiod_set_value_cansleep(adp5055->hw_en_array_gpios->desc[2], 0);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why doing this? Do you really want to force an HIGH to LOW transition? If not, just use GPIOD_OUT_LOW when requesting the pins.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i see, all this time I thought when requesting the pins the GPIOD_OUT_LOW/HIGH just tells the "active" level of a pin.
then a gpiod_set..... will actually initialize it to a value we want. will remove

@actorreno actorreno force-pushed the dev/adp5055-regulator branch 5 times, most recently from 14c83c9 to dc69faf Compare February 20, 2025 09:11
@actorreno
Copy link
Author

v5

yaml:

  • changed tset-8x to tset-us and the enum choices
  • added minItems for gpio property
  • removed -ch for all channel properties
  • edited dis/enable-delay-us with actual values in microsec not string

c:

  • edited code to match yaml feedback on ms values
  • turned devm_gpiod.. to devm_gpiod_get_array_optional()
  • for the check if (adp5055->hw_en_array_gpios->ndescs != ADP5055_NUM_CH), used
    the !adp5055->hw_en_array_gpios
  • separated checks under fwnode_property_read_u32
  • edited the two properties to match the missed new name in bindings
  • removing all "adp5055->enable_mode_sw" populated by device_property_present
    and replacing it with checks using "!adp5055->hw_en_array_gpios"
  • removed gpiod_set_value_cansleep that just initializes the gpio pin. simplified to GPIOD_OUT_LOW

Copy link
Collaborator

@nunojsa nunojsa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feel free to take my last comments and send this upstream... I would also recommend to improve the commit message for the bindings:

  1. Remove the .yaml suffix on the commit subject;
  2. Add a meaningful message to the commit message. Saying "Adding bindings docs" says nothing and the maintainers will likely complain. Give a small description of the device.

description:
Setting time used by the device. This is changed via soldering
specific resistor values on the CFG2 pin. Soldering nothing results
to the default value in microseconds.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I would drop the below

" Soldering nothing results to the default value in microseconds."

You already define the default value....

if (!adp5055->hw_en_array_gpios) {
ret = regmap_update_bits(adp5055->regmap, ADP5055_CTRL_MODE1, mask, en_val);
if (ret)
return ret;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be simplified... Do return regmap_update_bits() and then you do not need the else {

if (ret)
return ret;

val_hw = gpiod_get_value_cansleep(adp5055->hw_en_array_gpios->desc[id]);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move this after the if(). No need to do it if not in hw mode


adp5055->hw_en_array_gpios = devm_gpiod_get_array_optional(dev,
"adi,hw-en-array", GPIOD_OUT_LOW);

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: no new line

return dev_err_probe(dev, PTR_ERR(adp5055->hw_en_array_gpios),
"Failed to get hw_en_array GPIOs\n");

if (!adp5055->hw_en_array_gpios)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you mean if (adp5055->hw_en_array_gpios)

"Failed to get hw_en_array GPIOs\n");

if (!adp5055->hw_en_array_gpios)
if (adp5055->hw_en_array_gpios->ndescs != ADP5055_NUM_CH)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a dev_err_probe() log message could be useful...

ret = device_property_read_u32(dev, "adi,tset-us", &tset);
if (!ret) {
ret = adp5055_get_prop_index(adp5055_tset_vals,
ARRAY_SIZE(adp5055_tset_vals), tset);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: align on open parenthesis...

&dvs_limit_lower_ch[i]);
if (ret)
return ret;

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The above was not addressed...

Add documentation for devicetree bindings for ADP5055. The device consists
of 3 buck regulators able to connect to high input voltages of up to 18V
with no preregulators.

Signed-off-by: Alexis Czezar Torreno <[email protected]>
@actorreno actorreno force-pushed the dev/adp5055-regulator branch 2 times, most recently from 0621ee4 to 7d1a960 Compare February 25, 2025 04:32
Add ADI ADP5055 triple buck regulator driver support.

Signed-off-by: Alexis Czezar Torreno <[email protected]>
imply REGULATOR_ADP5055.

Signed-off-by: Alexis Czezar Torreno <[email protected]>
@actorreno actorreno force-pushed the dev/adp5055-regulator branch from 7d1a960 to 1d5c990 Compare February 25, 2025 04:39
@actorreno
Copy link
Author

This version shall be sent upstream

v6

yaml:

  • dropped tset-us description "Soldering nothing results to the default value in microseconds."
  • edited commit subject and added more on the message to describe device

c:

  • simplified an if else with {} by 'return regmap_update_bits()'
  • moved a code used during HW_en after the "hw_en check" to lessen code during sw_en
  • removed new line after 'adp5055->hw_en_array_gpios = devm_gpiod_get_array_optional', error check now directly follows
  • changed an if by removing '!' -> if (adp5055->hw_en_array_gpios) during a check where the code needs to make sure it exist first
  • added dev_err_probe about not having the valid amount of channels
  • adjusted indent to align on open parenthesis
  • removed the for loop initializing fast_transient due to a check, putting the default in case of error
  • dvs-limit-lower/upper now not mandatory code wise, will default in case of error. also added Out of range check

Note:

the CI check for the dtbinding for this version had a package error and is not related to the code. the changes done for this version is only editing the description so should be no error from previous. see image below of azure error msg
image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants