regulator: pcf50633: Don't write to reserved bits of AUTO output voltage select register
PATCH v2 1/2 regulator: pcf50633: Don't write to reserved bits of AUTO output voltage select register
The datasheet says 00000000 to 00101110 are reserved, and the min value of the voltage setting is 1.8 V.
Thus don't write 0 to AUTO output voltage select register (address 1Ah).
Table 50. AUTOOUT - AUTO output voltage select register (address 1Ah) bit description[1] Bit Symbol Access Description
7:0 auto_out R/W VO(prog) = 0.625 + auto_out × 0.025 V
eg. 00000000 to 00101110: reserved
00101111: 1.8 V (min)
01010011: 2.7 V
01101010: 3.275 V
01101011: 3.300 V
01101100: 3.325 V
01111111 : 3.800 V (max)
..... .....
11111110 : 3.800 V
11111111 : 3.800 V
This patch also fixes a bug in pcf50633_regulator_list_voltage.
It is wrong to do "index += 0x2f" for PCF50633_REGULATOR_AUTO in pcf50633_regulator_list_voltage. The purpose of adding 0x2f to index is because current code return 0 in auto_voltage_bits when millivolts < 1800. For millivolts > 1800, adding 0x2f to index is wrong.
We should handle this by
return 0 if the selector is in the reserved range of AUTOOUT.
--- drivers/regulator/pcf50633-regulator.c | 23 +++++------------------ 1 files changed, 5 insertions(+), 18 deletions(-)
drivers/regulator/pcf50633-regulator.c +5 -18
@@ -52,7 +52,7 @@ static const u8 pcf50633_regulator_registers[PCF50633_NUM_REGULATORS] = {static u8 auto_voltage_bits (unsigned int millivolts) {if (millivolts <1800 ) -return 0 ; +return 0x2f ;if (millivolts >3800 )return 0xff ;
@@ -87,9 +87,6 @@ static u8 ldo_voltage_bits(unsigned int millivolts)/* Obtain voltage value from bits */ static unsigned int auto_voltage_value (u8 bits) { -if (bits <0x2f ) -return 0 ; -return 625 + (bits *25 ); }
@@ -161,6 +158,9 @@ static int pcf50633_regulator_voltage_value(enum pcf50633_regulator_id id,switch (id) {case PCF50633_REGULATOR_AUTO : +/* AUTOOUT: 00000000 to 00101110 are reserved */ +if (bits <0x2f ) +return 0 ; millivolts =auto_voltage_value (bits);break ;case PCF50633_REGULATOR_DOWN1 :
@@ -208,20 +208,7 @@ static int pcf50633_regulator_get_voltage(struct regulator_dev *rdev)static int pcf50633_regulator_list_voltage (struct regulator_dev *rdev,unsigned int index) { -struct pcf50633 *pcf; -int regulator_id; - - pcf =rdev_get_drvdata (rdev); - - regulator_id =rdev_get_id (rdev); - -switch (regulator_id) { -case PCF50633_REGULATOR_AUTO : - index +=0x2f ; -break ; -default : -break ; - } +int regulator_id =rdev_get_id (rdev);return pcf50633_regulator_voltage_value (regulator_id, index); }
Signature · 1 line
1.7.5.4
PATCH v2 2/2 regulator: Convert pcf50633 to get_voltage_sel
Convert pcf50633 to get_voltage_sel and then we can remove pcf50633_regulator_voltage_value function and move its implementation to pcf50633_regulator_list_voltage.
--- drivers/regulator/pcf50633-regulator.c | 65 ++++++++++++++----------------- 1 files changed, 29 insertions(+), 36 deletions(-)
drivers/regulator/pcf50633-regulator.c +29 -36
@@ -151,23 +151,43 @@ static int pcf50633_regulator_set_voltage(struct regulator_dev *rdev,return pcf50633_reg_write (pcf, regnr, volt_bits); } -static int pcf50633_regulator_voltage_value (enum pcf50633_regulator_id id, -u8 bits) +static int pcf50633_regulator_get_voltage_sel (struct regulator_dev *rdev) { +struct pcf50633 *pcf; +int regulator_id; +u8 volt_bits, regnr; + + pcf =rdev_get_drvdata (rdev); + + regulator_id =rdev_get_id (rdev); +if (regulator_id >=PCF50633_NUM_REGULATORS ) +return -EINVAL ; + + regnr = pcf50633_regulator_registers[regulator_id]; + + volt_bits =pcf50633_reg_read (pcf, regnr); + +return volt_bits; +} + +static int pcf50633_regulator_list_voltage (struct regulator_dev *rdev, +unsigned int index) +{ +int regulator_id =rdev_get_id (rdev);int millivolts; -switch (id) { +switch (regulator_id) {case PCF50633_REGULATOR_AUTO :/* AUTOOUT: 00000000 to 00101110 are reserved */ -if (bits <0x2f ) +if (index <0x2f )return 0 ; - millivolts =auto_voltage_value (bits); + millivolts =auto_voltage_value (index);break ;case PCF50633_REGULATOR_DOWN1 : - millivolts =down_voltage_value (bits); + millivolts =down_voltage_value (index);break ;case PCF50633_REGULATOR_DOWN2 : - millivolts =down_voltage_value (bits); + millivolts =down_voltage_value (index);break ;case PCF50633_REGULATOR_LDO1 :case PCF50633_REGULATOR_LDO2 :
@@ -177,7 +197,7 @@ static int pcf50633_regulator_voltage_value(enum pcf50633_regulator_id id,case PCF50633_REGULATOR_LDO6 :case PCF50633_REGULATOR_HCLDO :case PCF50633_REGULATOR_MEMLDO : - millivolts =ldo_voltage_value (bits); + millivolts =ldo_voltage_value (index);break ;default :return -EINVAL ;
@@ -186,33 +206,6 @@ static int pcf50633_regulator_voltage_value(enum pcf50633_regulator_id id,return millivolts *1000 ; } -static int pcf50633_regulator_get_voltage (struct regulator_dev *rdev) -{ -struct pcf50633 *pcf; -int regulator_id; -u8 volt_bits, regnr; - - pcf =rdev_get_drvdata (rdev); - - regulator_id =rdev_get_id (rdev); -if (regulator_id >=PCF50633_NUM_REGULATORS ) -return -EINVAL ; - - regnr = pcf50633_regulator_registers[regulator_id]; - - volt_bits =pcf50633_reg_read (pcf, regnr); - -return pcf50633_regulator_voltage_value (regulator_id, volt_bits); -} - -static int pcf50633_regulator_list_voltage (struct regulator_dev *rdev, -unsigned int index) -{ -int regulator_id =rdev_get_id (rdev); - -return pcf50633_regulator_voltage_value (regulator_id, index); -} -static int pcf50633_regulator_enable (struct regulator_dev *rdev) {struct pcf50633 *pcf =rdev_get_drvdata (rdev);
@@ -265,7 +258,7 @@ static int pcf50633_regulator_is_enabled(struct regulator_dev *rdev)static struct regulator_ops pcf50633_regulator_ops = { .set_voltage = pcf50633_regulator_set_voltage, - .get_voltage = pcf50633_regulator_get_voltage, + .get_voltage_sel = pcf50633_regulator_get_voltage_sel, .list_voltage = pcf50633_regulator_list_voltage, .enable = pcf50633_regulator_enable, .disable = pcf50633_regulator_disable,
Signature · 1 line
1.7.5.4
Re: [PATCH v2 2/2] regulator: Convert pcf50633 to get_voltage_sel
Quoted 5 lines · Axel Lin
Convert pcf50633 to
get_voltage_seland then we can removepcf50633_regulator_voltage_valuefunction and move its implementation topcf50633_regulator_list_voltage.Signed-off-by Axel Lin <[email protected]>
One minor comment inline though.
Quoted 21 lines
--- drivers/regulator/pcf50633-regulator.c | 65 ++++++++++++++----------------- 1 files changed, 29 insertions(+), 36 deletions(-)drivers/regulator/pcf50633-regulator.c +6
-2@@ -151,23 +151,43 @@ static int pcf50633_regulator_set_voltage(struct regulator_dev *rdev,return pcf50633_reg_write (pcf, regnr, volt_bits); } -static int pcf50633_regulator_voltage_value (enum pcf50633_regulator_id id, -u8 bits) +static int pcf50633_regulator_get_voltage_sel (struct regulator_dev *rdev) { +struct pcf50633 *pcf; +int regulator_id; +u8 volt_bits, regnr; + + pcf =rdev_get_drvdata (rdev);
drivers/regulator/pcf50633-regulator.c static int pcf50633_regulator_set_voltage(struct regulator_dev *rdev, · line 170
Quoted 10 lines
drivers/regulator/pcf50633-regulator.c +10
-0+ + regulator_id =rdev_get_id (rdev); +if (regulator_id >=PCF50633_NUM_REGULATORS ) +return -EINVAL ; + + regnr = pcf50633_regulator_registers[regulator_id]; + + volt_bits =pcf50633_reg_read (pcf, regnr); + +return volt_bits;
Might as well just do "return pcf50633_reg_read(pcf, regnr);"
Quoted 18 lines · Axel Lin
The datasheet says 00000000 to 00101110 are reserved, and the min value of the voltage setting is 1.8 V.
Thus don't write 0 to AUTO output voltage select register (address 1Ah).Table 50. AUTOOUT - AUTO output voltage select register (address 1Ah) bit description[1] Bit Symbol Access Description
7:0auto_outR/W VO(prog) = 0.625 +auto_out× 0.025 V
eg. 00000000 to 00101110: reserved
00101111: 1.8 V (min)
01010011: 2.7 V
01101010: 3.275 V
01101011: 3.300 V
01101100: 3.325 V
01111111 : 3.800 V (max)
..... .....
11111110 : 3.800 V
11111111 : 3.800 V
Quoted 6 lines
This patch also fixes a bug in
pcf50633_regulator_list_voltage.
It is wrong to do "index +=0x2f" forPCF50633_REGULATOR_AUTOinpcf50633_regulator_list_voltage. The purpose of adding0x2fto index is because current code return 0 inauto_voltage_bitswhen millivolts < 1800. For millivolts > 1800, adding0x2fto index is wrong.
I think you misunderstood what the current code does. The first usable voltage is 1.8V which is equal to a index of of 0x2f. So the driver adds 0x2f to the index so that there is not a headroom of 0x2f unusable voltages. So a selector of 0 translates to 1.8V, a selector of 1 translates to 1.825V and so on.
I can see why you'd want to change it to simplify the code, but you also have to change the number of voltages for the AUTO regulator to 128.
2012/3/18 Lars-Peter Clausen <[email protected]>:
Quoted 26 lines · Axel Lin
Quoted 18 lines
The datasheet says 00000000 to 00101110 are reserved, and the min value of the voltage setting is 1.8 V.
Thus don't write 0 to AUTO output voltage select register (address 1Ah).Table 50. AUTOOUT - AUTO output voltage select register (address 1Ah) bit description[1] Bit Symbol Access Description
7:0auto_outR/W VO(prog) = 0.625 +auto_out× 0.025 V
eg. 00000000 to 00101110: reserved
00101111: 1.8 V (min)
01010011: 2.7 V
01101010: 3.275 V
01101011: 3.300 V
01101100: 3.325 V
01111111 : 3.800 V (max)
..... .....
11111110 : 3.800 V
11111111 : 3.800 VQuoted 6 lines
This patch also fixes a bug in
pcf50633_regulator_list_voltage.
It is wrong to do "index +=0x2f" forPCF50633_REGULATOR_AUTOinpcf50633_regulator_list_voltage. The purpose of adding0x2fto index is because current code return 0 inauto_voltage_bitswhen millivolts < 1800. For millivolts > 1800, adding0x2fto index is wrong.
Quoted 4 lines
I think you misunderstood what the current code does. The first usable voltage is 1.8V which is equal to a index of of
0x2f. So the driver adds0x2fto the index so that there is not a headroom of0x2funusable voltages. So a selector of 0 translates to 1.8V, a selector of 1 translates to 1.825V and so on.
I think what I wry to explain is:
In regulator core _regulator_do_set_voltage function:
if (rdev->desc->ops->set_voltage) {
ret = rdev->desc->ops->set_voltage(rdev, min_uV, max_uV,
&selector);
if (rdev->desc->ops->list_voltage)
selector = rdev->desc->ops->list_voltage(rdev,
selector);
else
selector = -1;The list_voltage call here takes the selector got from set_voltage callback. Thus adding 0x2f to the index in pcf50633_regulator_list_voltage looks wrong to me.
e.g.
If min_uV < 1.8V, pcf50633_regulator_set_voltage sets 0 to selector. For this case, adding 0x2f to the index in pcf50633_regulator_list_voltage is exactly what you want. However, if min_uV == 1.8V, pcf50633_regulator_set_voltage sets 0x2f to selector.
Adding 0x2f to the index in pcf50633_regulator_list_voltage in this case is wrong.
What this patch does is:
The minimal voltage setting for AUTOOUT is 0x2f.
Thus for the case min_uV < 1.8, set the voltage setting to 1.8V by writting 0x2f to AUTOOUT register and set selector = 0x2f.
So we don't write the rserved range to AUTOOUT register.
Which means the possible range of AUTOOUT register value is 0x2f ~ 0xff.
We have no problem in regulator_get_voltage.
Since we won't write 0~0x2e to AUTOOUT register, we have no problem converting the bits we read to voltage. The equation in auto_voltage_value works fine.
For list_voltage, we need to take into account the case selector is 0 ~ 0x2e because the regulator core assumes the selector is starting from 0. This patch returns 0 for the cases selector is 0 ~ 0x2e, which means "this selector code can't be used on this system".
Quoted 3 lines
I can see why you'd want to change it to simplify the code, but you also have to change the number of voltages for the AUTO regulator to 128.
yes, I missed that.
The regulator core iterates from 0 to n_voltages to find the small voltage in the specific range.
So yes, I think the n_voltages settings for AUTOOUT should be 128 now, including the reserved range of AUTOOUT.
I'll send a V3 for review and update the commit log. Thanks,
Axel
Quoted 44 lines · Axel Lin
2012/3/18 Lars-Peter Clausen <[email protected]>:
Quoted 26 lines · Axel Lin
Quoted 18 lines
The datasheet says 00000000 to 00101110 are reserved, and the min value of the voltage setting is 1.8 V.
Thus don't write 0 to AUTO output voltage select register (address 1Ah).Table 50. AUTOOUT - AUTO output voltage select register (address 1Ah) bit description[1] Bit Symbol Access Description
7:0auto_outR/W VO(prog) = 0.625 +auto_out× 0.025 V
eg. 00000000 to 00101110: reserved
00101111: 1.8 V (min)
01010011: 2.7 V
01101010: 3.275 V
01101011: 3.300 V
01101100: 3.325 V
01111111 : 3.800 V (max)
..... .....
11111110 : 3.800 V
11111111 : 3.800 VQuoted 6 lines
This patch also fixes a bug in
pcf50633_regulator_list_voltage.
It is wrong to do "index +=0x2f" forPCF50633_REGULATOR_AUTOinpcf50633_regulator_list_voltage. The purpose of adding0x2fto index is because current code return 0 inauto_voltage_bitswhen millivolts < 1800. For millivolts > 1800, adding0x2fto index is wrong.Quoted 4 lines
I think you misunderstood what the current code does. The first usable voltage is 1.8V which is equal to a index of of
0x2f. So the driver adds0x2fto the index so that there is not a headroom of0x2funusable voltages. So a selector of 0 translates to 1.8V, a selector of 1 translates to 1.825V and so on.I think what I wry to explain is:
In regulator core_regulator_do_set_voltagefunction:if (rdev->desc->ops->set_voltage) { ret = rdev->desc->ops->set_voltage(rdev, min_uV, max_uV, &selector); if (rdev->desc->ops->list_voltage) selector = rdev->desc->ops->list_voltage(rdev, selector); else selector = -1;
Quoted 4 lines
The
list_voltagecall here takes the selector got fromset_voltagecallback. Thus adding0x2fto the index inpcf50633_regulator_list_voltagelooks wrong to me.
Ah ok, now I understand what you mean. When the selector parameter to set_voltage was introduced we already had list_voltage adding the 0x2f, so from my point of view list_voltage is correct and the bug is in the commit which introduced the selector parameter to select voltage, that's why I was confused as to why you think there was a bug in list_voltage. But it all makes sense now, thanks.
Luckily the bug is not so critical, since selector is not really used in _regulator_do_set_voltage in this case except for the trace message.
- Lars