[PATCH 3/6] mfd: twl4030-power: Add generic reset configuration

Matthias Brugger matthias.bgg at gmail.com
Wed Jun 4 06:02:21 PDT 2014


2014-05-27 20:08 GMT+02:00 Tony Lindgren <tony at atomide.com>:
> The twl4030 PMIC needs to be configured properly for things like
> warm reset and deeper idle states so the PMIC manages the regulators
> properly based on the hardware triggers from the SoC. Earlier
> we have configured twl4030 using platform data, but we want to
> do it for device tree based booting also.
>
> In some cases configuring twl4030 is needed for things to work.
> For example, when rebooting an OMAP3530 at 125 MHz, it hangs.
> With this patch, TWL4030 will be reset when a warm reset occures,
> and OMAP3530 does not hang on reboot.
>
> Let's add device tree support and configure things for warm reset
> as the default when compatible = "ti,twl4030-power". More
> complicated configurations can be added to the driver based on
> other compatible flags.
>
> Note we now also make the pdata const like it should be.
> This allows use it for match->data with the device tree
> related functions.
>
> Based on earlier patch by Matthias Brugger <matthias.bgg at gmail.com>
> and Lesly A M <leslyam at ti.com>.
>
> Cc: Matthias Brugger <matthias.bgg at gmail.com>
> Cc: Robert Nelson <robertcnelson at gmail.com>
> Cc: Peter De Schrijver <pdeschrijver at nvidia.com>
> Cc: Samuel Ortiz <sameo at linux.intel.com>
> Cc: Lee Jones <lee.jones at linaro.org>
> Signed-off-by: Tony Lindgren <tony at atomide.com>
> ---
>  .../devicetree/bindings/mfd/twl4030-power.txt      |   7 +-
>  drivers/mfd/twl4030-power.c                        | 109 ++++++++++++++++++---
>  include/linux/i2c/twl.h                            |   3 +
>  3 files changed, 105 insertions(+), 14 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/mfd/twl4030-power.txt b/Documentation/devicetree/bindings/mfd/twl4030-power.txt
> index 8e15ec3..b906116 100644
> --- a/Documentation/devicetree/bindings/mfd/twl4030-power.txt
> +++ b/Documentation/devicetree/bindings/mfd/twl4030-power.txt
> @@ -5,7 +5,12 @@ 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"
> +- compatible : must be one of the following
> +       "ti,twl4030-power"
> +       "ti,twl4030-power-reset"
> +
> +The use of ti,twl4030-power-reset is recommended at least on
> +3530 that needs a special configuration for warm reset to work.
>
>  Optional properties:
>  - ti,use_poweroff: With this flag, the chip will initiates an ACTIVE-to-OFF or
> diff --git a/drivers/mfd/twl4030-power.c b/drivers/mfd/twl4030-power.c
> index 0b037dc..cb5b0cb 100644
> --- a/drivers/mfd/twl4030-power.c
> +++ b/drivers/mfd/twl4030-power.c
> @@ -29,6 +29,7 @@
>  #include <linux/i2c/twl.h>
>  #include <linux/platform_device.h>
>  #include <linux/of.h>
> +#include <linux/of_device.h>
>
>  #include <asm/mach-types.h>
>
> @@ -128,6 +129,40 @@ static u8 res_config_addrs[] = {
>         [RES_MAIN_REF]  = 0x94,
>  };
>
> +/*
> + * Usable values for .remap_sleep and .remap_off
> + * Based on table "5.3.3 Resource Operating modes"
> + */
> +enum {
> +       TWL_REMAP_OFF = 0,
> +       TWL_REMAP_SLEEP = 8,
> +       TWL_REMAP_ACTIVE = 9,

Do we really need remap active?
As far as I can see it's not used anywhere.

> +};
> +
> +/*
> + * Macros to configure the PM register states for various resources.
> + * Note that we can make MSG_SINGULAR etc private to this driver once
> + * omap3 has been made DT only.
> + */
> +#define TWL_DFLT_DELAY         2       /* typically 2 32 KiHz cycles */
> +#define TWL_RESOURCE_SET(res, state)                                   \
> +       { MSG_SINGULAR(DEV_GRP_NULL, (res), (state)), TWL_DFLT_DELAY }
> +#define TWL_RESOURCE_ON(res)   TWL_RESOURCE_SET(res, RES_STATE_ACTIVE)
> +#define TWL_RESOURCE_OFF(res)  TWL_RESOURCE_SET(res, RES_STATE_OFF)
> +#define TWL_RESOURCE_RESET(res)        TWL_RESOURCE_SET(res, RES_STATE_WRST)
> +/*
> + * It seems that type1 and type2 is just the resource init order
> + * number for the type1 and type2 group.
> + */
> +#define TWL_RESOURCE_GROUP_RESET(group, type1, type2)                  \
> +       { MSG_BROADCAST(DEV_GRP_NULL, (group), (type1), (type2),        \
> +               RES_STATE_WRST), TWL_DFLT_DELAY }
> +#define TWL_REMAP_SLEEP(res, devgrp, typ, typ2)                                \
> +       { .resource = (res), .devgroup = (devgrp),                      \
> +         .type = (typ), .type2 = (typ2),                               \
> +         .remap_off = TWL_REMAP_OFF,                                   \
> +         .remap_sleep = TWL_REMAP_SLEEP, }
> +
>  static int twl4030_write_script_byte(u8 address, u8 byte)
>  {
>         int err;
> @@ -502,7 +537,8 @@ int twl4030_remove_script(u8 flags)
>         return err;
>  }
>
> -static int twl4030_power_configure_scripts(struct twl4030_power_data *pdata)
> +static int
> +twl4030_power_configure_scripts(const struct twl4030_power_data *pdata)
>  {
>         int err;
>         int i;
> @@ -518,7 +554,8 @@ static int twl4030_power_configure_scripts(struct twl4030_power_data *pdata)
>         return 0;
>  }
>
> -static int twl4030_power_configure_resources(struct twl4030_power_data *pdata)
> +static int
> +twl4030_power_configure_resources(const struct twl4030_power_data *pdata)
>  {
>         struct twl4030_resconfig *resconfig = pdata->resource_config;
>         int err;
> @@ -550,7 +587,7 @@ void twl4030_power_off(void)
>                 pr_err("TWL4030 Unable to power off\n");
>  }
>
> -static bool twl4030_power_use_poweroff(struct twl4030_power_data *pdata,
> +static bool twl4030_power_use_poweroff(const struct twl4030_power_data *pdata,
>                                         struct device_node *node)
>  {
>         if (pdata && pdata->use_poweroff)
> @@ -562,10 +599,60 @@ static bool twl4030_power_use_poweroff(struct twl4030_power_data *pdata,
>         return false;
>  }
>
> +#ifdef CONFIG_OF
> +
> +/* Generic warm reset configuration for omap3 */
> +
> +static struct twl4030_ins omap3_wrst_seq[] = {
> +       TWL_RESOURCE_OFF(RES_NRES_PWRON),
> +       TWL_RESOURCE_OFF(RES_RESET),
> +       TWL_RESOURCE_RESET(RES_MAIN_REF),
> +       TWL_RESOURCE_GROUP_RESET(RES_GRP_ALL, RES_TYPE_R0, RES_TYPE2_R2),
> +       TWL_RESOURCE_RESET(RES_VUSB_3V1),
> +       TWL_RESOURCE_GROUP_RESET(RES_GRP_ALL, RES_TYPE_R0, RES_TYPE2_R1),
> +       TWL_RESOURCE_GROUP_RESET(RES_GRP_RC, RES_TYPE_ALL, RES_TYPE2_R0),
> +       TWL_RESOURCE_ON(RES_RESET),
> +       TWL_RESOURCE_ON(RES_NRES_PWRON),
> +};
> +
> +static struct twl4030_script omap3_wrst_script = {
> +       .script = omap3_wrst_seq,
> +       .size   = ARRAY_SIZE(omap3_wrst_seq),
> +       .flags  = TWL4030_WRST_SCRIPT,
> +};
> +
> +static struct twl4030_script *omap3_reset_scripts[] = {
> +       &omap3_wrst_script,
> +};
> +
> +static struct twl4030_resconfig omap3_rconfig[] = {
> +       TWL_REMAP_SLEEP(RES_HFCLKOUT, DEV_GRP_P3, -1, -1),
> +       TWL_REMAP_SLEEP(RES_VDD1, DEV_GRP_P1, -1, -1),
> +       TWL_REMAP_SLEEP(RES_VDD2, DEV_GRP_P1, -1, -1),
> +       { 0, 0 },
> +};
> +
> +static struct twl4030_power_data omap3_reset = {
> +       .scripts                = omap3_reset_scripts,
> +       .num                    = ARRAY_SIZE(omap3_reset_scripts),
> +       .resource_config        = omap3_rconfig,
> +};
> +
> +static struct of_device_id twl4030_power_of_match[] = {
> +       {
> +               .compatible = "ti,twl4030-power-reset",
> +               .data = &omap3_reset,
> +       },
> +       { },
> +};
> +MODULE_DEVICE_TABLE(of, twl4030_power_of_match);
> +#endif /* CONFIG_OF */
> +
>  static int twl4030_power_probe(struct platform_device *pdev)
>  {
> -       struct twl4030_power_data *pdata = dev_get_platdata(&pdev->dev);
> +       const struct twl4030_power_data *pdata = dev_get_platdata(&pdev->dev);
>         struct device_node *node = pdev->dev.of_node;
> +       const struct of_device_id *match;
>         int err = 0;
>         int err2 = 0;
>         u8 val;
> @@ -586,8 +673,12 @@ static int twl4030_power_probe(struct platform_device *pdev)
>                 return err;
>         }
>
> +       match = of_match_device(of_match_ptr(twl4030_power_of_match),
> +                               &pdev->dev);
> +       if (match && match->data)
> +               pdata = match->data;
> +
>         if (pdata) {
> -               /* TODO: convert to device tree */
>                 err = twl4030_power_configure_scripts(pdata);
>                 if (err) {
>                         pr_err("TWL4030 failed to load scripts\n");
> @@ -637,14 +728,6 @@ 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",
> diff --git a/include/linux/i2c/twl.h b/include/linux/i2c/twl.h
> index ade1c06..5fe0313 100644
> --- a/include/linux/i2c/twl.h
> +++ b/include/linux/i2c/twl.h
> @@ -486,7 +486,10 @@ static inline int twl6030_mmc_card_detect(struct device *dev, int slot)
>  #define RES_GRP_ALL            0x7     /* All resource groups */
>
>  #define RES_TYPE2_R0           0x0
> +#define RES_TYPE2_R1           0x1
> +#define RES_TYPE2_R2           0x2
>
> +#define RES_TYPE_R0            0x0
>  #define RES_TYPE_ALL           0x7
>
>  /* Resource states */
> --
> 1.8.1.1
>



-- 
motzblog.wordpress.com



More information about the linux-arm-kernel mailing list