regulator: Add regulator driver for the MC34708 PMIC
Subsystems (2)
cover regulator: Add regulator driver for the MC34708 PMIC
Add regulator driver and associated DT bindings for the regulators in the Freescale MC34708 PMIC.
PATCH 1/2 Regulator: mc34708: Add DT binding documentation
--- .../bindings/regulator/mc34708-regulator.txt | 198 ++++++++++++++++++++ 1 file changed, 198 insertions(+) create mode 100644 Documentation/devicetree/bindings/regulator/mc34708-regulator.txt
Documentation/devicetree/bindings/regulator/mc34708-regulator.txt new file +198 -0
@@ -0,0 +1,198 @@ +Regulators included in the Freescale MC34708 PMIC + +Required properties: +- compatible: "fsl,mc34708" +- reg: I2C slave address + + +Regulators subnode: +------------------- +This node contains children following the standard regulator binding format +described in Documentation/devicetree/bindings/regulator/regulator.txt + +The allowed node names are: + Switchers: + sw1, sw2, sw3, sw4a, sw4b, sw5, swbst + LDOs: + vpll, vrefddr, vusb, vusb2, vdac, vgen1, vgen2 + +The mode values are: + Switchers: + 1 : Pulse Frequency Modulation (PFM) [for low loads] + 2 : Auto + 3 : Pulse Width Modulation (PWM) [for high loads] + LDOs: + 1 : Low power + 2 : Normal + +Optional properties: +The input supply of regulators are the optional properties on the +regulator node. + +- vinsw1-supply : phandle to input supply for sw1 regulator +- vinsw2-supply : phandle to input supply for sw2 regulator +- vinsw3-supply : phandle to input supply for sw3 regulator +- vinsw4a-supply : phandle to input supply for sw4a regulator +- vinsw4b-supply : phandle to input supply for sw4b regulator +- vinsw5-supply : phandle to input supply for sw5 regulator +- vinswbst-supply : phandle to input supply for swbst regulator +- vinrefddr-supply : phandle to input supply for vrefddr regulator (/2) + + +Example: +&i2c3 { + pmic: mc34708 at 08 { + compatible = "fsl,mc34708"; + reg = <0x08>; + regulators { +#define PMIC_REGMODE_SW_PFM 1 +#define PMIC_REGMODE_SW_AUTO 2 +#define PMIC_REGMODE_SW_PWM 3 +#define PMIC_REGMODE_LDO_LP 1 +#define PMIC_REGMODE_LDO_NORMAL 2 + + vinrefddr-supply = <&pmic_sw4a_reg>; + pmic_sw1_reg: sw1 { + /* CPU Core */ + regulator-name = "SW1"; + regulator-min-microvolt = <650000>; + regulator-max-microvolt = <1437500>; + regulator-boot-on; + regulator-always-on; + regulator-initial-mode = <PMIC_REGMODE_SW_PWM>; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <850000>; + regulator-mode = <PMIC_REGMODE_SW_PFM>; + }; + }; + + pmic_sw2_reg: sw2 { + /* SOC Periperals */ + regulator-name = "SW2"; + regulator-min-microvolt = <650000>; + regulator-max-microvolt = <1437500>; + regulator-boot-on; + regulator-always-on; + regulator-initial-mode = <PMIC_REGMODE_SW_PWM>; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <950000>; + regulator-mode = <PMIC_REGMODE_SW_PFM>; + }; + }; + + pmic_sw3_reg: sw3 { + regulator-name = "SW3"; + regulator-min-microvolt = <650000>; + regulator-max-microvolt = <1425000>; + }; + + pmic_sw4a_reg: sw4a { + /* DDR Ram */ + regulator-name = "SW4A"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + regulator-initial-mode = <PMIC_REGMODE_SW_PWM>; + regulator-state-mem { + regulator-on-in-suspend; + regulator-mode = <PMIC_REGMODE_SW_PFM>; + }; + }; + + pmic_sw5_reg: sw5 { + /* 1v8 power */ + regulator-name = "SW5"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1975000>; + regulator-boot-on; + regulator-always-on; + regulator-initial-mode = <PMIC_REGMODE_SW_PWM>; + regulator-state-mem { + regulator-on-in-suspend; + regulator-mode = <PMIC_REGMODE_SW_PFM>; + }; + }; + + pmic_swbst_reg: swbst { + regulator-name = "SWBST"; + regulator-boot-on; + regulator-always-on; + regulator-initial-mode = <PMIC_REGMODE_SW_AUTO>; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + pmic_vpll_reg: vpll { + regulator-name = "VPLL"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + pmic_vrefddr_reg: vrefddr { + regulator-name = "VREFDDR"; + regulator-boot-on; + regulator-always-on; + }; + + pmic_vusb_reg: vusb { + regulator-name = "VUSB"; + regulator-boot-on; + regulator-always-on; + }; + + pmic_vusb2_reg: vusb2 { + regulator-name = "VUSB2"; + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <3000000>; + regulator-boot-on; + regulator-always-on; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + pmic_vdac_reg: vdac { + regulator-name = "VDAC"; + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <2775000>; + regulator-boot-on; + regulator-always-on; + regulator-initial-mode = <PMIC_REGMODE_LDO_NORMAL>; + regulator-state-mem { + regulator-on-in-suspend; + regulator-mode = <PMIC_REGMODE_LDO_LP>; + }; + }; + + pmic_vgen1_reg: vgen1 { + regulator-name = "VGEN1"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1550000>; + regulator-boot-on; + regulator-always-on; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + pmic_vgen2_reg: vgen2 { + regulator-name = "VGEN2"; + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + regulator-initial-mode = <PMIC_REGMODE_LDO_NORMAL>; + regulator-state-mem { + regulator-on-in-suspend; + regulator-mode = <PMIC_REGMODE_LDO_LP>; + }; + }; + }; + }; +};
Mark Brown
maintainerRe: [PATCH 1/2] Regulator: mc34708: Add DT binding documentation
Documentation/devicetree/bindings/regulator/mc34708-regulator.txt line 89
Quoted 5 lines · Martin Fuzzey
Documentation/devicetree/bindings/regulator/mc34708-regulator.txt new file +5
-0+ pmic_sw3_reg: sw3 { + regulator-name = "SW3"; + regulator-min-microvolt = <650000>; + regulator-max-microvolt = <1425000>; + };
These examples look awfully like you're just listiong the maximum range
allowed by the PMIC for all the supplies which is almost never something
someone would want to do on a real board. Similarly all the names are
just the name of the regulator rather than something that looks like a
board specific name.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 473 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150430/f3d90701/attachment-0001.sig>
Re: [PATCH 1/2] Regulator: mc34708: Add DT binding documentation
In reply to Martin FuzzeyHi Martin,
Quoted 5 lines
Martin Fuzzey <[email protected]> hat am 28. April 2015 um 16:17 geschrieben:
Signed-off-by Martin Fuzzey <[email protected]>
a commit message would be nice and the subject should specify dt-bindings instead of regulator subsystem.
Stefan
Mark Brown
maintainerRe: [PATCH 1/2] Regulator: mc34708: Add DT binding documentation
Quoted 2 lines · Stefan Wahren
a commit message would be nice and the subject should specify dt-bindings instead of regulator subsystem.
No, it shouldn't. DT bindings for a subsystem go through the subsystem
and the subsystem maintainer needs to see them to read them.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 473 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150501/f7e65c1f/attachment.sig>
Re: [PATCH 1/2] Regulator: mc34708: Add DT binding documentation
Hi Mark,
Quoted 10 lines
Mark Brown <[email protected]> hat am 1. Mai 2015 um 13:01 geschrieben:
Quoted 2 lines · Stefan Wahren
a commit message would be nice and the subject should specify dt-bindings instead of regulator subsystem.
No, it shouldn't. DT bindings for a subsystem go through the subsystem and the subsystem maintainer needs to see them to read them.
sorry for my bad expressing.
I tought the subject line should be something like:
DT: add binding documentation for mc34708 regulator
Stefan
Mark Brown
maintainerRe: [PATCH 1/2] Regulator: mc34708: Add DT binding documentation
Quoted 7 lines · Stefan Wahren
Quoted 6 lines
Mark Brown <[email protected]> hat am 1. Mai 2015 um 13:01 geschrieben:
Quoted 2 lines · Stefan Wahren
a commit message would be nice and the subject should specify dt-bindings instead of regulator subsystem.
Quoted 8 lines
Quoted 2 lines
No, it shouldn't. DT bindings for a subsystem go through the subsystem and the subsystem maintainer needs to see them to read them.
sorry for my bad expressing.
I tought the subject line should be something like:
DT: add binding documentation for mc34708 regulator
No, it shouldn't. The subject line should start "regulator: " like all
other regulator commits.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 473 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150501/8ee4b2e6/attachment.sig>
Re: [PATCH 1/2] Regulator: mc34708: Add DT binding documentation
In reply to Martin FuzzeyHello Martin,
I haven't looked at your regulator driver in detail so this is not a full review but I just noticed something so I wanted mention.
Quoted 4 lines
Documentation/devicetree/bindings/regulator/mc34708-regulator.txt new file +4
-0+ + +Example: +&i2c3 {
Documentation/devicetree/bindings/regulator/mc34708-regulator.txt line 53
Quoted 10 lines
Documentation/devicetree/bindings/regulator/mc34708-regulator.txt new file +10
-0+ pmic: mc34708 at 08 { + compatible = "fsl,mc34708"; + reg = <0x08>; + regulators { +#define PMIC_REGMODE_SW_PFM 1 +#define PMIC_REGMODE_SW_AUTO 2 +#define PMIC_REGMODE_SW_PWM 3 +#define PMIC_REGMODE_LDO_LP 1 +#define PMIC_REGMODE_LDO_NORMAL 2 +
I see that you are defining these constants in your driver too (albeit with slightly different names). These kind of constants that are shared between the driver implementation and the Device Tree source files should be added to include/dt-bindings/regulator/ and included in both the driver and the DTS.
Best regards,
Javier
PATCH 2/2 Regulator: add driver for Freescale MC34708
In reply to Martin Fuzzey--- drivers/regulator/Kconfig | 7 drivers/regulator/Makefile | 1 drivers/regulator/mc34708-regulator.c | 1266 +++++++++++++++++++++++++++++++++ 3 files changed, 1274 insertions(+) create mode 100644 drivers/regulator/mc34708-regulator.c
drivers/regulator/Kconfig +7 -0
@@ -440,6 +440,13 @@ config REGULATOR_MC13892 Say y here to support the regulators found on the Freescale MC13892 PMIC. +config REGULATOR_MC34708 + tristate "Freescale MC34708 regulator driver" + depends on MFD_MC13XXX + help + Say y here to support the regulators found on the Freescale MC34708 + and MC34709 PMICs. + config REGULATOR_PALMAS tristate "TI Palmas PMIC Regulators" depends on MFD_PALMAS
drivers/regulator/Makefile +1 -0
@@ -59,6 +59,7 @@ obj-$(CONFIG_REGULATOR_MAX77802) += max77802.o obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o +obj-$(CONFIG_REGULATOR_MC34708) += mc34708-regulator.o obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o obj-$(CONFIG_REGULATOR_PFUZE100) += pfuze100-regulator.o
drivers/regulator/mc34708-regulator.c new file +1266 -0
1,266 lines not on this page · raw message
Re: [PATCH 2/2] Regulator: add driver for Freescale MC34708
Just a nit: a license mismatch.
drivers/regulator/mc34708-regulator.c line 29
Quoted 7 lines · Martin Fuzzey
drivers/regulator/mc34708-regulator.c new file +4
-0+* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation; either version 2 of the +* License, or (at your option) any later version.
This states the license is GPL v2 or later.
Quoted 1 line
+MODULE_LICENSE("GPL v2");
And, according to inlcude/linux/module.h, this states the license is (just) GPL v2. So I think either to comment at the top of this file or the ident used in the MODULE_LICENSE() macro should be changed.
Thanks,
Paul Bolle
Mark Brown
maintainerRe: [PATCH 2/2] Regulator: add driver for Freescale MC34708
In reply to Martin FuzzeyQuoted 1 line · Martin Fuzzey
Signed-off-by Martin Fuzzey <[email protected]>
Please use subject lines reflecting the style for the subsystem.
drivers/regulator/mc34708-regulator.c line 110
Quoted 12 lines
drivers/regulator/mc34708-regulator.c new file +12
-0+static int mc34708_read_bits (struct mc34708_regulator *mc34708_reg, +unsigned int reg,u32 mask) +{ +int ret; +u32 val; + + ret =mc13xxx_reg_read (mc34708_reg->mc13xxx, reg, &val); +if (ret <0 ) +return ret; + + val &= mask; + val >>=ffs (mask) -1 ;
Ick, this looks confusing - it's wrapping something which should hopefully be a regmap in multiple layer. The bitfield access helper does seem reasonable though.
drivers/regulator/mc34708-regulator.c line 120
Quoted 6 lines
drivers/regulator/mc34708-regulator.c new file +6
-0+static int mc34708_update_bits (struct mc34708_regulator *mc34708_reg, +unsigned int reg,u32 mask,u32 val) +{ + val <<=ffs (mask) -1 ; + +return mc13xxx_reg_rmw (mc34708_reg->mc13xxx, reg, mask, val);
This is a wrapper for the widely used _update_bits() interface which has a different interface - that's *definitely* confusing.
drivers/regulator/mc34708-regulator.c line 129
Quoted 7 lines
drivers/regulator/mc34708-regulator.c new file +7
-0+static int mc34708_get_voltage_sel (struct regulator_dev *rdev) +{ +struct mc34708_regulator *mc34708_reg = rdev->reg_data; + +return mc34708_read_bits (mc34708_reg, + rdev->desc->vsel_reg, rdev->desc->vsel_mask); +}
Don't open code this, use the standard regmap helpers.
drivers/regulator/mc34708-regulator.c line 168
Quoted 7 lines
drivers/regulator/mc34708-regulator.c new file +7
-0+ val =mc34708_read_bits (mc34708_reg, + mc34708_reg->def->mode_reg, + mc34708_reg->def->mode_mask); +if (val <0 ) +return ERR_PTR (val); + +BUG_ON (val >= mc34708_reg->def->kind->num_hw_modes);
This is too severe, could be a hardware error.
Quoted 10 lines
drivers/regulator/mc34708-regulator.c new file +10
-0+static int mc34708_sw_find_hw_mode_sel ( +const struct mc34708_regulator_kind *kind, +unsigned int normal, +unsigned int standby) +{ +const struct mc34708_hw_mode *mode; +int i; + +for (i =0 , mode = kind->hw_modes; + i < kind->num_hw_modes; i++, mode++) {
drivers/regulator/mc34708-regulator.c line 197
Quoted 10 lines
drivers/regulator/mc34708-regulator.c new file +10
-0+if (mode->normal ==-1 || mode->standby ==-1 ) +continue ; + +if (mode->standby != standby) +continue ; + +if ((mode->normal == normal) || + (normal && (mode->alt_normal == normal))) +return i; + }
I honestly don't really know what the above is supposed to do. It's mapping something to something but what exactly is unclear... skipping most of the rest of the mode code.
drivers/regulator/mc34708-regulator.c line 448
Quoted 6 lines
drivers/regulator/mc34708-regulator.c new file +6
-0+static int mc34708_swbst_mode_to_hwmode (unsigned int mode) +{ +switch (mode) { +case REGULATOR_MODE_IDLE : +case REGULATOR_MODE_STANDBY : +return MC34708_SW_OPMODE_PFM ;
No, this is broken - you're mapping two different modes to one hardware setting. If the device doesn't support something it just doesn't support it, let the upper layers work out how to handle that.
Also an extra space there.
Quoted 13 lines
drivers/regulator/mc34708-regulator.c new file +13
-0+static int mc34708_swbst_setup (struct mc34708_regulator *mc34708_reg) +{ +int val, mode; + + val =mc34708_read_bits (mc34708_reg, + mc34708_reg->def->mode_reg, + mc34708_reg->def->mode_mask); +if (val <0 ) +return val; + +if (val >0 ) { + mode =mc34708_swbst_hwmode_to_mode (val); +if (mode <0 )
drivers/regulator/mc34708-regulator.c line 488
Quoted 10 lines
drivers/regulator/mc34708-regulator.c new file +10
-0+return mode; + + mc34708_reg->req_mode_normal = mode; + }else { +/* +* If regulator is intially off we don't know the mode +* but we need a mode to be able to enable it later. +*/ + mc34708_reg->req_mode_normal =REGULATOR_MODE_NORMAL ; + }
I don't really understand what the above is supposed to do, some comments would probably help.
drivers/regulator/mc34708-regulator.c line 529
Quoted 9 lines
drivers/regulator/mc34708-regulator.c new file +9
-0+static int mc34708_swbst_enable (struct regulator_dev *rdev) +{ +struct mc34708_regulator *mc34708_reg = rdev->reg_data; + +return mc34708_update_bits (mc34708_reg, + mc34708_reg->def->mode_reg, + mc34708_reg->def->mode_mask, + mc34708_reg->req_mode_normal); +}
Again use the standard regmap helpers.
drivers/regulator/mc34708-regulator.c line 807
Quoted 10 lines
drivers/regulator/mc34708-regulator.c new file +10
-0+static int mc34708_ldo_set_suspend_enable (struct regulator_dev *rdev) +{ +struct mc34708_regulator *mc34708_reg = rdev->reg_data; +int ret; + + ret =mc34708_update_hw_mode (mc34708_reg, + mc34708_reg->req_mode_normal, + mc34708_reg->req_mode_standby); +if (!ret) + mc34708_reg->suspend_off = false;
This looks like it should be a noop. It also seems very familiar from some of the other code.
drivers/regulator/mc34708-regulator.c line 833
Quoted 8 lines
drivers/regulator/mc34708-regulator.c new file +8
-0+static int mc34708_ldo_set_suspend_mode (struct regulator_dev *rdev, +unsigned int mode) +{ +struct mc34708_regulator *mc34708_reg = rdev->reg_data; +int ret; + +if (!mc34708_ldo_has_mode_bit (mc34708_reg)) +return 0 ;
Again, if the driver doesn't support something don't implement it.
drivers/regulator/mc34708-regulator.c line 943
Quoted 3 lines
drivers/regulator/mc34708-regulator.c new file +3
-0+static const unsigned int mc34708_vgen1_volt_table[] = { +1200000 ,1250000 ,1300000 ,1350000 ,1400000 ,1450000 ,1500000 ,1550000 +};
This looks like a linear mapping, use the standard helpers please.
Quoted 8 lines
+/*
+ * Setting some LDO standby states also requires changing the normal state.
+ * Therefore save the LDO configuration register on suspend and restore it
+ * on resume.
+ *
+ * This works because .set_suspend_X are called by the platform suspend handler
+ * AFTER device suspend
+ */
That's not something you can rely on, I suggest omitting this for now and doing it separately.
drivers/regulator/mc34708-regulator.c line 1170
Quoted 13 lines
drivers/regulator/mc34708-regulator.c new file +13
-0+ num_regs =of_get_child_count (regs_np); + mc34708_data =devm_kzalloc (dev,sizeof (*mc34708_data) + + num_regs *sizeof (*mc34708_reg), +GFP_KERNEL ); +if (!mc34708_data) { + ret = -ENOMEM ; + goto out; + } + +dev_set_drvdata (dev, mc34708_data); + + mc34708_reg = mc34708_data->regulators; +for_each_child_of_node (regs_np, reg_np) {
No, this is broken - your driver should like all the others register all
the regulators on the device uncondtionally. It should also be using
.of_match to allow the core to look up the init data.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 473 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150430/2c35161e/attachment.sig>
Re: [PATCH 2/2] Regulator: add driver for Freescale MC34708
Thank you for the review.
Quoted 4 lines · Mark Brown
Quoted 1 line · Martin Fuzzey
Signed-off-by Martin Fuzzey <[email protected]>Please use subject lines reflecting the style for the subsystem.
You mean
regulator: mc34708: Add driver?
I ommitted the mc34708 part because it's a new driver
Quoted 7 lines
Quoted 7 lines
drivers/regulator/mc34708-regulator.c new file +7
-0+static int mc34708_read_bits (struct mc34708_regulator *mc34708_reg, +unsigned int reg,u32 mask) +{ +int ret; +u32 val; + + ret =mc13xxx_reg_read (mc34708_reg->mc13xxx, reg, &val);
Quoted 8 lines
drivers/regulator/mc34708-regulator.c line 110
Quoted 5 lines
drivers/regulator/mc34708-regulator.c new file +5
-0+if (ret <0 ) +return ret; + + val &= mask; + val >>=ffs (mask) -1 ;Ick, this looks confusing - it's wrapping something which should hopefully be a regmap in multiple layer. The bitfield access helper does seem reasonable though.
The reason for this wrapping stuff is that this is not a standalone driver, rather a "subdriver" of the mc13xxx MFD driver. That already exists and supports the mc34708 (for the RTC for example) but not yet the regulator parts.
It does not expose regmap (although it does use it internally).
Quoted 8 lines
drivers/regulator/mc34708-regulator.c line 120
Quoted 6 lines
drivers/regulator/mc34708-regulator.c new file +6
-0+static int mc34708_update_bits (struct mc34708_regulator *mc34708_reg, +unsigned int reg,u32 mask,u32 val) +{ + val <<=ffs (mask) -1 ; + +return mc13xxx_reg_rmw (mc34708_reg->mc13xxx, reg, mask, val);This is a wrapper for the widely used
_update_bits()interface which has a different interface - that's *definitely* confusing.
You are referring to the fact that the "val" parameter in my function is the non shifted value?
I think this makes the call sites much cleaner.
I get your point about it having the same name but different semantics as other functions though.
Would you be happier if I rename this to mc34708_set_bitfield() for example?
Quoted 8 lines
drivers/regulator/mc34708-regulator.c line 129
Quoted 7 lines
drivers/regulator/mc34708-regulator.c new file +7
-0+static int mc34708_get_voltage_sel (struct regulator_dev *rdev) +{ +struct mc34708_regulator *mc34708_reg = rdev->reg_data; + +return mc34708_read_bits (mc34708_reg, + rdev->desc->vsel_reg, rdev->desc->vsel_mask); +}Don't open code this, use the standard regmap helpers.
See above.
Quoted 9 lines
drivers/regulator/mc34708-regulator.c line 168
Quoted 8 lines
drivers/regulator/mc34708-regulator.c new file +7
-0+ val =mc34708_read_bits (mc34708_reg, + mc34708_reg->def->mode_reg, + mc34708_reg->def->mode_mask); +if (val <0 ) +return ERR_PTR (val); + +BUG_ON (val >= mc34708_reg->def->kind->num_hw_modes);This is too severe, could be a hardware error.
The purpose of this function is to read a number of bits from the hardware and convert this to a hardware mode based on a lookup table. The size of this lookup table should encompase all the possible values read from that bitfield.
Hence a hardware error alone won't trigger this unless the table size itself is wrong (a code BUG, not a hardware error).
I could change the check to use the mask though, rather than the value read from hardware to make this clearer.
Quoted 15 lines
Quoted 15 lines
drivers/regulator/mc34708-regulator.c new file +15
-0+static int mc34708_sw_find_hw_mode_sel ( +const struct mc34708_regulator_kind *kind, +unsigned int normal, +unsigned int standby) +{ +const struct mc34708_hw_mode *mode; +int i; + +for (i =0 , mode = kind->hw_modes; + i < kind->num_hw_modes; i++, mode++) { +if (mode->normal ==-1 || mode->standby ==-1 ) +continue ; + +if (mode->standby != standby) +continue ;
Quoted 8 lines
drivers/regulator/mc34708-regulator.c line 197
Quoted 5 lines
drivers/regulator/mc34708-regulator.c new file +5
-0+ +if ((mode->normal == normal) || + (normal && (mode->alt_normal == normal))) +return i; + }I honestly don't really know what the above is supposed to do. It's mapping something to something but what exactly is unclear... skipping most of the rest of the mode code.
The mode code is indeed complicated, but mostly because the hardware doesn't map directly nor orthogonally to the regulator framework concepts.
I tried to explain this in the block comments at the start of each the code for each type of regulator.
Looks like I failed :(
For the switching regulators:
There is a 4 bit "mode" field (which I call hwmode to distinguish from the regulator framework concept of mode.
This field encodes:
* The enable / disable state when the standby signal is not asserted (there is no seperate enable bit)
* The enable / disable state when the standby signal is not asserted
* The operating mode when the standby signal is asserted
* The operating mode when the standby signal is not asserted
Not all of the 16 possible values are valid. There is no documented or discernable direct mapping of the individual bits.
For the LDO regulators:
There is a dedicated enable bit (ouf)
There are 2 bits (VxMode, VxSTBY) controlling the regulator operating mode when the standaby signal is or is not asserted. However these bits are not seperate.
From the comment block:
* VxMODE VxSTBY Normal Standby * 0 0 ON ON * 0 1 ON OFF * 1 0 LP LP * 1 1 ON LP
*
So, the function above takes the desired regulator modes for the normal and standby states (or 0 for off) and finds the corresponding hwmode (value to write to the register bits).
Then the way I handle all this is just use mc34708_sw_find_hw_mode_sel() to recalculate the hardware mode by walking the tables every time something needs to change.
The table is different depending on the regulator type.
This turned out to be *much* simpler that the initial open code approach I first tried.
Quoted 9 lines
drivers/regulator/mc34708-regulator.c line 448
Quoted 6 lines
drivers/regulator/mc34708-regulator.c new file +6
-0+static int mc34708_swbst_mode_to_hwmode (unsigned int mode) +{ +switch (mode) { +case REGULATOR_MODE_IDLE : +case REGULATOR_MODE_STANDBY : +return MC34708_SW_OPMODE_PFM ;No, this is broken - you're mapping two different modes to one hardware setting. If the device doesn't support something it just doesn't support it, let the upper layers work out how to handle that.
Ok
Quoted 19 lines
Also an extra space there.
Quoted 17 lines
drivers/regulator/mc34708-regulator.c new file +17
-0+static int mc34708_swbst_setup (struct mc34708_regulator *mc34708_reg) +{ +int val, mode; + + val =mc34708_read_bits (mc34708_reg, + mc34708_reg->def->mode_reg, + mc34708_reg->def->mode_mask); +if (val <0 ) +return val; + +if (val >0 ) { + mode =mc34708_swbst_hwmode_to_mode (val); +if (mode <0 ) +return mode; + + mc34708_reg->req_mode_normal = mode; + }else {
Quoted 8 lines
drivers/regulator/mc34708-regulator.c line 331
Quoted 6 lines
drivers/regulator/mc34708-regulator.c new file +6
-0+/* +* If regulator is intially off we don't know the mode +* but we need a mode to be able to enable it later. +*/ + mc34708_reg->req_mode_normal =REGULATOR_MODE_NORMAL ; + }I don't really understand what the above is supposed to do, some comments would probably help.
We need to store the desired modes (for normal and standby state) since .set_mode() and .set_suspend_mode() are not always called before enable() / disable().
For example, for a .enable() on a switching regulator requires the desired normal and standby mode to be known (to find the appropriate value for the hardware mode bits since there is no hardware enable bit. I try to determine the current mode at startup to initialise the desired mode for a later enable by reading the registers but that is only possible if the regulator is already enabled.
The hardware has no concept of "disabled but will be in PFM mode when enabled" for example.
Quoted 4 lines
Quoted 4 lines
drivers/regulator/mc34708-regulator.c new file +4
-0+static int mc34708_ldo_set_suspend_enable (struct regulator_dev *rdev) +{ +struct mc34708_regulator *mc34708_reg = rdev->reg_data; +int ret;
Quoted 8 lines
drivers/regulator/mc34708-regulator.c line 401
Quoted 6 lines
drivers/regulator/mc34708-regulator.c new file +6
-0+ + ret =mc34708_update_hw_mode (mc34708_reg, + mc34708_reg->req_mode_normal, + mc34708_reg->req_mode_standby); +if (!ret) + mc34708_reg->suspend_off = false;This looks like it should be a noop. It also seems very familiar from some of the other code.
It's not a noop.
If .set_suspend_disable() is called then later .set_suspend_enable() the regulator needs to be recofigured.
Note that neither .set_suspend_enable(), nor .set_suspend_disable() change the stored modes (req_mode_normal, req_mode_standby) since the regulator framework seperates the concept of enable and mode but this hardware does not.
Quoted 10 lines
drivers/regulator/mc34708-regulator.c line 833
Quoted 8 lines
drivers/regulator/mc34708-regulator.c new file +8
-0+static int mc34708_ldo_set_suspend_mode (struct regulator_dev *rdev, +unsigned int mode) +{ +struct mc34708_regulator *mc34708_reg = rdev->reg_data; +int ret; + +if (!mc34708_ldo_has_mode_bit (mc34708_reg)) +return 0 ;Again, if the driver doesn't support something don't implement it.
Ok
Quoted 4 lines
drivers/regulator/mc34708-regulator.c line 943
Quoted 3 lines
drivers/regulator/mc34708-regulator.c new file +3
-0+static const unsigned int mc34708_vgen1_volt_table[] = { +1200000 ,1250000 ,1300000 ,1350000 ,1400000 ,1450000 ,1500000 ,1550000 +};This looks like a linear mapping, use the standard helpers please.
Ok
Quoted 11 lines
Quoted 8 lines
+/*
+ * Setting some LDO standby states also requires changing the normal state.
+ * Therefore save the LDO configuration register on suspend and restore it
+ * on resume.
+ *
+ * This works because .set_suspend_X are called by the platform suspend handler
+ * AFTER device suspend
+ */That's not something you can rely on, I suggest omitting this for now and doing it separately.
Quoted 16 lines
drivers/regulator/mc34708-regulator.c line 1170
Quoted 13 lines
drivers/regulator/mc34708-regulator.c new file +13
-0+ num_regs =of_get_child_count (regs_np); + mc34708_data =devm_kzalloc (dev,sizeof (*mc34708_data) + + num_regs *sizeof (*mc34708_reg), +GFP_KERNEL ); +if (!mc34708_data) { + ret = -ENOMEM ; + goto out; + } + +dev_set_drvdata (dev, mc34708_data); + + mc34708_reg = mc34708_data->regulators; +for_each_child_of_node (regs_np, reg_np) {No, this is broken - your driver should like all the others register all the regulators on the device uncondtionally. It should also be using .of_match to allow the core to look up the init data.
Ok
Mark Brown
maintainerRe: [PATCH 2/2] Regulator: add driver for Freescale MC34708
On Mon, May 11, 2015 at 11:04:39AM +0200, Martin Fuzzey wrote:
Please leave blank lines between paragraphs and between old text and new text, it makes things a lot easier to read - this is extremely difficult to follow.
Quoted 9 lines · Mark Brown
Quoted 3 lines · Martin Fuzzey
Quoted 1 line
Signed-off-by Martin Fuzzey <[email protected]>Please use subject lines reflecting the style for the subsystem.
You mean
regulator: mc34708: Add driver?I ommitted the mc34708 part because it's a new driver
That and the fact that you spelt regulator Regulator.
Quoted 9 lines
Quoted 3 lines
Ick, this looks confusing - it's wrapping something which should hopefully be a regmap in multiple layer. The bitfield access helper does seem reasonable though.
The reason for this wrapping stuff is that this is not a standalone driver, rather a "subdriver" of the mc13xxx MFD driver.
That already exists and supports the mc34708 (for the RTC for example) but not yet the regulator parts.
It does not expose regmap (although it does use it internally).
Well, fix that then...
Quoted 1 line
Would you be happier if I rename this to
mc34708_set_bitfield()for example?
I guess, it would probably be preferable to go with the more common _update_bits() pattern though.
Quoted 7 lines
Then the way I handle all this is just use
mc34708_sw_find_hw_mode_sel()to recalculate the hardware mode by walking the tables every time something needs to change.
The table is different depending on the regulator type.This turned out to be *much* simpler that the initial open code approach I first tried.
This all needs to be apparent to someone reading the code. Probably having comments about what individual functions are supposed to be doing would help a lot here.
Quoted 6 lines
Quoted 2 lines
I don't really understand what the above is supposed to do, some comments would probably help.
We need to store the desired modes (for normal and standby state) since .set_mode() and .set_suspend_mode() are not always called before
enable()/disable().
The point is that this needs to be something someone reading the code
could reasonably be expected to understand.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 473 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150511/0b2dbba1/attachment.sig>
Re: [PATCH 2/2] Regulator: add driver for Freescale MC34708
In reply to Martin FuzzeyHi Martin,
Quoted 12 lines
Martin Fuzzey <[email protected]> hat am 28. April 2015 um 16:17 geschrieben:
[...]
drivers/regulator/mc34708-regulator.c new file +0
-0
drivers/regulator/mc34708-regulator.c line 3
Quoted 3 lines
drivers/regulator/mc34708-regulator.c new file +3
-0@@ -0,0 +1,1266 @@ +/* +* Driver for regulators in the Fresscale MC34708/9 PMICs +*
just a typo: Freescale
Stefan
Hi Martin,
Quoted 6 lines
Martin Fuzzey <[email protected]> hat am 28. April 2015 um 16:17 geschrieben:
Add regulator driver and associated DT bindings for the regulators in the Freescale MC34708 PMIC.
from my understanding this PMIC is used typically for i.MX50/53 SoCs. So in this case
it would make sense to mention it here and CC this patch series also to the IMX maintainers.
Btw
git format-patch --cover-letter
is your friend.
Stefan
Quoted 5 lines
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel at lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel