-
Notifications
You must be signed in to change notification settings - Fork 863
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
base: main
Are you sure you want to change the base?
Add support for ADP5055 #2668
Conversation
Please, fix first the valid CI errors you have... |
5d77901
to
36d5ba8
Compare
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. Edit: was fixed by rebasing to latest main |
36d5ba8
to
03486f9
Compare
There was a problem hiding this 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?
The datasheet did say "pmbus compatible" but it didn't have any pmbus commands the other typical pmbus dataseet contain some colleagues agreed with me that it was just an i2c interface and decided it is better off in the regulator subsystem |
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. |
There was a problem hiding this 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. |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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.
8e79e38
to
bdc82e1
Compare
2469301
to
d4b3989
Compare
(still correcting CI check) v3: .yaml: -removed copyright
.c:
Kconfig:
|
description: | ||
If present, configure channels to be enabled via software | ||
instead of hardware enable. | ||
type: boolean |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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> |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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; | ||
|
There was a problem hiding this comment.
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."); |
There was a problem hiding this comment.
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"); | ||
} |
There was a problem hiding this comment.
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
e74a25c
to
e773abc
Compare
v4 yaml:
c:
|
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 |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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 | ||
|
There was a problem hiding this comment.
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; | ||
|
There was a problem hiding this comment.
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"); |
There was a problem hiding this comment.
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; | ||
|
There was a problem hiding this comment.
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...
There was a problem hiding this comment.
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) { |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
14c83c9
to
dc69faf
Compare
v5 yaml:
c:
|
There was a problem hiding this 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:
- Remove the .yaml suffix on the commit subject;
- 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. |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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]); |
There was a problem hiding this comment.
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); | ||
|
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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; | ||
|
There was a problem hiding this comment.
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]>
0621ee4
to
7d1a960
Compare
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]>
7d1a960
to
1d5c990
Compare
PR Description
PR Type
PR Checklist