2013-06-18 13:18:24

by Florian Vaussard

[permalink] [raw]
Subject: [PATCH v2 0/5] mfd: twl4030-power: Start DT conversion and updates

Hello,

This series enables a partial DT support for twl4030-power. The
missing part is the power management scripts, as the required
binding should be defined first. It however enables the complete
shutdown of the processor at poweroff when booting with DT,
dropping the power consumption from around 350 mA on Overo+Tobi
to about 40 mA.

The poweroff callback was tested with both DT and non-DT boots.

The last two patches simplify the error path in the probe function,
and fix registers relocking on error.

Best regards,

Florian

Since v1:
- use module_platform_driver()
- split the refactoring of the probe function into a dedicated patch
- new patch to fix registers relocking on error
- rebased on mfd-next


Florian Vaussard (5):
mfd: twl4030-power: Split from twl-core into a dedicated module
mfd: twl4030-power: Simplify probing of power scripts and resources
mfd: twl4030-power: Start transition to DT
mfd: twl4030-power: Simplify error path
mfd: twl4030-power: Fix relocking on error

.../devicetree/bindings/mfd/twl4030-power.txt | 28 ++++
drivers/mfd/twl-core.c | 12 +-
drivers/mfd/twl4030-power.c | 149 ++++++++++++++-----
include/linux/i2c/twl.h | 1 -
4 files changed, 146 insertions(+), 44 deletions(-)
create mode 100644 Documentation/devicetree/bindings/mfd/twl4030-power.txt

--
1.7.5.4


2013-06-18 13:18:26

by Florian Vaussard

[permalink] [raw]
Subject: [PATCH v2 3/5] mfd: twl4030-power: Start transition to DT

Support for loading twl4030-power module via devicetree.
For now, when booting with a DT, only the poweroff callback
feature is supported through the ti,use_poweroff property.

Signed-off-by: Florian Vaussard <[email protected]>
---
.../devicetree/bindings/mfd/twl4030-power.txt | 28 ++++++++++++
drivers/mfd/twl4030-power.c | 45 ++++++++++++++++---
2 files changed, 66 insertions(+), 7 deletions(-)
create mode 100644 Documentation/devicetree/bindings/mfd/twl4030-power.txt

diff --git a/Documentation/devicetree/bindings/mfd/twl4030-power.txt b/Documentation/devicetree/bindings/mfd/twl4030-power.txt
new file mode 100644
index 0000000..8e15ec3
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/twl4030-power.txt
@@ -0,0 +1,28 @@
+Texas Instruments TWL family (twl4030) reset and power management module
+
+The power management module inside the TWL family provides several facilities
+to control the power resources, including power scripts. For now, the
+binding only supports the complete shutdown of the system after poweroff.
+
+Required properties:
+- compatible : must be "ti,twl4030-power"
+
+Optional properties:
+- ti,use_poweroff: With this flag, the chip will initiates an ACTIVE-to-OFF or
+ SLEEP-to-OFF transition when the system poweroffs.
+
+Example:
+&i2c1 {
+ clock-frequency = <2600000>;
+
+ twl: twl@48 {
+ reg = <0x48>;
+ interrupts = <7>; /* SYS_NIRQ cascaded to intc */
+ interrupt-parent = <&intc>;
+
+ twl_power: power {
+ compatible = "ti,twl4030-power";
+ ti,use_poweroff;
+ };
+ };
+};
diff --git a/drivers/mfd/twl4030-power.c b/drivers/mfd/twl4030-power.c
index 8fa6c7b..9f59c94 100644
--- a/drivers/mfd/twl4030-power.c
+++ b/drivers/mfd/twl4030-power.c
@@ -28,6 +28,7 @@
#include <linux/pm.h>
#include <linux/i2c/twl.h>
#include <linux/platform_device.h>
+#include <linux/of.h>

#include <asm/mach-types.h>

@@ -540,12 +541,30 @@ void twl4030_power_off(void)
pr_err("TWL4030 Unable to power off\n");
}

+static bool twl4030_power_use_poweroff(struct twl4030_power_data *pdata,
+ struct device_node *node)
+{
+ if (pdata && pdata->use_poweroff)
+ return true;
+
+ if (of_property_read_bool(node, "ti,use_poweroff"))
+ return true;
+
+ return false;
+}
+
int twl4030_power_probe(struct platform_device *pdev)
{
struct twl4030_power_data *pdata = pdev->dev.platform_data;
+ struct device_node *node = pdev->dev.of_node;
int err = 0;
u8 val;

+ if (!pdata && !node) {
+ dev_err(&pdev->dev, "Platform data is missing\n");
+ return -EINVAL;
+ }
+
err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, TWL4030_PM_MASTER_KEY_CFG1,
TWL4030_PM_MASTER_PROTECT_KEY);
if (err)
@@ -556,15 +575,18 @@ int twl4030_power_probe(struct platform_device *pdev)
if (err)
goto unlock;

- err = twl4030_power_configure_scripts(pdata);
- if (err)
- goto load;
- err = twl4030_power_configure_resources(pdata);
- if (err)
- goto resource;
+ if (pdata) {
+ /* TODO: convert to device tree */
+ err = twl4030_power_configure_scripts(pdata);
+ if (err)
+ goto load;
+ err = twl4030_power_configure_resources(pdata);
+ if (err)
+ goto resource;
+ }

/* Board has to be wired properly to use this feature */
- if (pdata->use_poweroff && !pm_power_off) {
+ if (twl4030_power_use_poweroff(pdata, node) && !pm_power_off) {
/* Default for SEQ_OFFSYNC is set, lets ensure this */
err = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &val,
TWL4030_PM_MASTER_CFG_P123_TRANSITION);
@@ -610,10 +632,19 @@ static int twl4030_power_remove(struct platform_device *pdev)
return 0;
}

+#ifdef CONFIG_OF
+static const struct of_device_id twl4030_power_of_match[] = {
+ {.compatible = "ti,twl4030-power", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, twl4030_power_of_match);
+#endif
+
static struct platform_driver twl4030_power_driver = {
.driver = {
.name = "twl4030_power",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(twl4030_power_of_match),
},
.probe = twl4030_power_probe,
.remove = twl4030_power_remove,
--
1.7.5.4

2013-06-18 13:18:30

by Florian Vaussard

[permalink] [raw]
Subject: [PATCH v2 5/5] mfd: twl4030-power: Fix relocking on error

If an error occurs when loading power scripts or resources, the
registers are not correctly relocked. Fix it.

Signed-off-by: Florian Vaussard <[email protected]>
---
drivers/mfd/twl4030-power.c | 12 ++++++++----
1 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/drivers/mfd/twl4030-power.c b/drivers/mfd/twl4030-power.c
index 1c19d82..a8b33c9 100644
--- a/drivers/mfd/twl4030-power.c
+++ b/drivers/mfd/twl4030-power.c
@@ -558,6 +558,7 @@ int twl4030_power_probe(struct platform_device *pdev)
struct twl4030_power_data *pdata = pdev->dev.platform_data;
struct device_node *node = pdev->dev.of_node;
int err = 0;
+ int err2 = 0;
u8 val;

if (!pdata && !node) {
@@ -581,12 +582,12 @@ int twl4030_power_probe(struct platform_device *pdev)
err = twl4030_power_configure_scripts(pdata);
if (err) {
pr_err("TWL4030 failed to load scripts\n");
- return err;
+ goto relock;
}
err = twl4030_power_configure_resources(pdata);
if (err) {
pr_err("TWL4030 failed to configure resource\n");
- return err;
+ goto relock;
}
}

@@ -612,10 +613,13 @@ int twl4030_power_probe(struct platform_device *pdev)
}

relock:
- err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, 0,
+ err2 = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, 0,
TWL4030_PM_MASTER_PROTECT_KEY);
- if (err)
+ if (err2) {
pr_err("TWL4030 Unable to relock registers\n");
+ return err2;
+ }
+
return err;
}

--
1.7.5.4

2013-06-18 13:19:04

by Florian Vaussard

[permalink] [raw]
Subject: [PATCH v2 4/5] mfd: twl4030-power: Simplify error path

Remove unnecessary goto statements, causing duplicated if
conditions.

Signed-off-by: Florian Vaussard <[email protected]>
---
drivers/mfd/twl4030-power.c | 38 +++++++++++++++-----------------------
1 files changed, 15 insertions(+), 23 deletions(-)

diff --git a/drivers/mfd/twl4030-power.c b/drivers/mfd/twl4030-power.c
index 9f59c94..1c19d82 100644
--- a/drivers/mfd/twl4030-power.c
+++ b/drivers/mfd/twl4030-power.c
@@ -567,22 +567,27 @@ int twl4030_power_probe(struct platform_device *pdev)

err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, TWL4030_PM_MASTER_KEY_CFG1,
TWL4030_PM_MASTER_PROTECT_KEY);
- if (err)
- goto unlock;
-
- err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, TWL4030_PM_MASTER_KEY_CFG2,
+ err |= twl_i2c_write_u8(TWL_MODULE_PM_MASTER,
+ TWL4030_PM_MASTER_KEY_CFG2,
TWL4030_PM_MASTER_PROTECT_KEY);
- if (err)
- goto unlock;
+
+ if (err) {
+ pr_err("TWL4030 Unable to unlock registers\n");
+ return err;
+ }

if (pdata) {
/* TODO: convert to device tree */
err = twl4030_power_configure_scripts(pdata);
- if (err)
- goto load;
+ if (err) {
+ pr_err("TWL4030 failed to load scripts\n");
+ return err;
+ }
err = twl4030_power_configure_resources(pdata);
- if (err)
- goto resource;
+ if (err) {
+ pr_err("TWL4030 failed to configure resource\n");
+ return err;
+ }
}

/* Board has to be wired properly to use this feature */
@@ -612,19 +617,6 @@ relock:
if (err)
pr_err("TWL4030 Unable to relock registers\n");
return err;
-
-unlock:
- if (err)
- pr_err("TWL4030 Unable to unlock registers\n");
- return err;
-load:
- if (err)
- pr_err("TWL4030 failed to load scripts\n");
- return err;
-resource:
- if (err)
- pr_err("TWL4030 failed to configure resource\n");
- return err;
}

static int twl4030_power_remove(struct platform_device *pdev)
--
1.7.5.4

2013-06-18 13:19:21

by Florian Vaussard

[permalink] [raw]
Subject: [PATCH v2 2/5] mfd: twl4030-power: Simplify probing of power scripts and resources

Increase lisibility when probing power scripts and resources by
creating dedicated functions.

Signed-off-by: Florian Vaussard <[email protected]>
---
drivers/mfd/twl4030-power.c | 60 ++++++++++++++++++++++++++++--------------
1 files changed, 40 insertions(+), 20 deletions(-)

diff --git a/drivers/mfd/twl4030-power.c b/drivers/mfd/twl4030-power.c
index 7ade81b..8fa6c7b 100644
--- a/drivers/mfd/twl4030-power.c
+++ b/drivers/mfd/twl4030-power.c
@@ -492,6 +492,39 @@ int twl4030_remove_script(u8 flags)
return err;
}

+int twl4030_power_configure_scripts(struct twl4030_power_data *pdata)
+{
+ int err;
+ int i;
+ u8 address = twl4030_start_script_address;
+
+ for (i = 0; i < pdata->num; i++) {
+ err = load_twl4030_script(pdata->scripts[i], address);
+ if (err)
+ return err;
+ address += pdata->scripts[i]->size;
+ }
+
+ return 0;
+}
+
+int twl4030_power_configure_resources(struct twl4030_power_data *pdata)
+{
+ struct twl4030_resconfig *resconfig = pdata->resource_config;
+ int err;
+
+ if (resconfig) {
+ while (resconfig->resource) {
+ err = twl4030_configure_resource(resconfig);
+ if (err)
+ return err;
+ resconfig++;
+ }
+ }
+
+ return 0;
+}
+
/*
* In master mode, start the power off sequence.
* After a successful execution, TWL shuts down the power to the SoC
@@ -511,9 +544,7 @@ int twl4030_power_probe(struct platform_device *pdev)
{
struct twl4030_power_data *pdata = pdev->dev.platform_data;
int err = 0;
- int i;
- struct twl4030_resconfig *resconfig;
- u8 val, address = twl4030_start_script_address;
+ u8 val;

err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, TWL4030_PM_MASTER_KEY_CFG1,
TWL4030_PM_MASTER_PROTECT_KEY);
@@ -525,23 +556,12 @@ int twl4030_power_probe(struct platform_device *pdev)
if (err)
goto unlock;

- for (i = 0; i < pdata->num; i++) {
- err = load_twl4030_script(pdata->scripts[i], address);
- if (err)
- goto load;
- address += pdata->scripts[i]->size;
- }
-
- resconfig = pdata->resource_config;
- if (resconfig) {
- while (resconfig->resource) {
- err = twl4030_configure_resource(resconfig);
- if (err)
- goto resource;
- resconfig++;
-
- }
- }
+ err = twl4030_power_configure_scripts(pdata);
+ if (err)
+ goto load;
+ err = twl4030_power_configure_resources(pdata);
+ if (err)
+ goto resource;

/* Board has to be wired properly to use this feature */
if (pdata->use_poweroff && !pm_power_off) {
--
1.7.5.4

2013-06-18 13:19:42

by Florian Vaussard

[permalink] [raw]
Subject: [PATCH v2 1/5] mfd: twl4030-power: Split from twl-core into a dedicated module

For now, the call to twl4030-power is hard-wired inside twl-core.
To ease the future transition to DT, make twl4030-power as a
separate module, like what is already done for twl4030-audio
and others.

Signed-off-by: Florian Vaussard <[email protected]>
---
drivers/mfd/twl-core.c | 12 +++++++---
drivers/mfd/twl4030-power.c | 44 +++++++++++++++++++++++++++++++++---------
include/linux/i2c/twl.h | 1 -
3 files changed, 42 insertions(+), 15 deletions(-)

diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
index 8d9bc10..dbd52b3 100644
--- a/drivers/mfd/twl-core.c
+++ b/drivers/mfd/twl-core.c
@@ -1023,6 +1023,14 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
return PTR_ERR(child);
}

+ if (IS_ENABLED(CONFIG_TWL4030_POWER) && pdata->power) {
+ child = add_child(TWL_MODULE_PM_MASTER, "twl4030_power",
+ pdata->power, sizeof(*pdata->power), false,
+ 0, 0);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
+ }
+
return 0;
}

@@ -1234,10 +1242,6 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
WARN(status < 0, "Error: reading twl_idcode register value\n");
}

- /* load power event scripts */
- if (IS_ENABLED(CONFIG_TWL4030_POWER) && pdata && pdata->power)
- twl4030_power_init(pdata->power);
-
/* Maybe init the T2 Interrupt subsystem */
if (client->irq) {
if (twl_class_is_4030()) {
diff --git a/drivers/mfd/twl4030-power.c b/drivers/mfd/twl4030-power.c
index dd362c1..7ade81b 100644
--- a/drivers/mfd/twl4030-power.c
+++ b/drivers/mfd/twl4030-power.c
@@ -507,8 +507,9 @@ void twl4030_power_off(void)
pr_err("TWL4030 Unable to power off\n");
}

-void twl4030_power_init(struct twl4030_power_data *twl4030_scripts)
+int twl4030_power_probe(struct platform_device *pdev)
{
+ struct twl4030_power_data *pdata = pdev->dev.platform_data;
int err = 0;
int i;
struct twl4030_resconfig *resconfig;
@@ -524,14 +525,14 @@ void twl4030_power_init(struct twl4030_power_data *twl4030_scripts)
if (err)
goto unlock;

- for (i = 0; i < twl4030_scripts->num; i++) {
- err = load_twl4030_script(twl4030_scripts->scripts[i], address);
+ for (i = 0; i < pdata->num; i++) {
+ err = load_twl4030_script(pdata->scripts[i], address);
if (err)
goto load;
- address += twl4030_scripts->scripts[i]->size;
+ address += pdata->scripts[i]->size;
}

- resconfig = twl4030_scripts->resource_config;
+ resconfig = pdata->resource_config;
if (resconfig) {
while (resconfig->resource) {
err = twl4030_configure_resource(resconfig);
@@ -543,7 +544,7 @@ void twl4030_power_init(struct twl4030_power_data *twl4030_scripts)
}

/* Board has to be wired properly to use this feature */
- if (twl4030_scripts->use_poweroff && !pm_power_off) {
+ if (pdata->use_poweroff && !pm_power_off) {
/* Default for SEQ_OFFSYNC is set, lets ensure this */
err = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &val,
TWL4030_PM_MASTER_CFG_P123_TRANSITION);
@@ -568,18 +569,41 @@ relock:
TWL4030_PM_MASTER_PROTECT_KEY);
if (err)
pr_err("TWL4030 Unable to relock registers\n");
- return;
+ return err;

unlock:
if (err)
pr_err("TWL4030 Unable to unlock registers\n");
- return;
+ return err;
load:
if (err)
pr_err("TWL4030 failed to load scripts\n");
- return;
+ return err;
resource:
if (err)
pr_err("TWL4030 failed to configure resource\n");
- return;
+ return err;
}
+
+static int twl4030_power_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static struct platform_driver twl4030_power_driver = {
+ .driver = {
+ .name = "twl4030_power",
+ .owner = THIS_MODULE,
+ },
+ .probe = twl4030_power_probe,
+ .remove = twl4030_power_remove,
+};
+
+module_platform_driver(twl4030_power_driver);
+
+MODULE_AUTHOR("Nokia Corporation");
+MODULE_AUTHOR("Texas Instruments, Inc.");
+MODULE_DESCRIPTION("Power management for TWL4030");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:twl4030_power");
+
diff --git a/include/linux/i2c/twl.h b/include/linux/i2c/twl.h
index 488debb..2167c0d0 100644
--- a/include/linux/i2c/twl.h
+++ b/include/linux/i2c/twl.h
@@ -658,7 +658,6 @@ struct twl4030_power_data {
bool use_poweroff; /* Board is wired for TWL poweroff */
};

-extern void twl4030_power_init(struct twl4030_power_data *triton2_scripts);
extern int twl4030_remove_script(u8 flags);
extern void twl4030_power_off(void);

--
1.7.5.4

2013-06-19 08:24:00

by Samuel Ortiz

[permalink] [raw]
Subject: Re: [PATCH v2 0/5] mfd: twl4030-power: Start DT conversion and updates

Hi Florian,

On Tue, Jun 18, 2013 at 03:17:55PM +0200, Florian Vaussard wrote:
> Hello,
>
> This series enables a partial DT support for twl4030-power. The
> missing part is the power management scripts, as the required
> binding should be defined first. It however enables the complete
> shutdown of the processor at poweroff when booting with DT,
> dropping the power consumption from around 350 mA on Overo+Tobi
> to about 40 mA.
>
> The poweroff callback was tested with both DT and non-DT boots.
>
> The last two patches simplify the error path in the probe function,
> and fix registers relocking on error.
>
> Best regards,
>
> Florian
>
> Since v1:
> - use module_platform_driver()
> - split the refactoring of the probe function into a dedicated patch
> - new patch to fix registers relocking on error
> - rebased on mfd-next
>
>
> Florian Vaussard (5):
> mfd: twl4030-power: Split from twl-core into a dedicated module
> mfd: twl4030-power: Simplify probing of power scripts and resources
> mfd: twl4030-power: Start transition to DT
> mfd: twl4030-power: Simplify error path
> mfd: twl4030-power: Fix relocking on error
All 5 patches applied, thanks.

Cheers,
Samuel.

--
Intel Open Source Technology Centre
http://oss.intel.com/