diff options
Diffstat (limited to 'drivers/mfd')
-rw-r--r-- | drivers/mfd/Kconfig | 3 | ||||
-rw-r--r-- | drivers/mfd/twl-core.c | 12 | ||||
-rw-r--r-- | drivers/mfd/twl4030-power.c | 148 | ||||
-rw-r--r-- | drivers/mfd/vexpress-sysreg.c | 10 |
4 files changed, 127 insertions, 46 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 29f7363f6bc4..3e3be603cf82 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -1151,7 +1151,8 @@ config MCP_UCB1200_TS endmenu config VEXPRESS_CONFIG - bool + bool "ARM Versatile Express platform infrastructure" + depends on ARM || ARM64 help Platform configuration infrastructure for the ARM Ltd. Versatile Express. diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index 8d9bc10c5312..dbd52b373b27 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 dd362c1078e1..a5fd3c738211 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> @@ -492,6 +493,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 @@ -507,43 +541,58 @@ void twl4030_power_off(void) pr_err("TWL4030 Unable to power off\n"); } -void twl4030_power_init(struct twl4030_power_data *twl4030_scripts) +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; - int i; - struct twl4030_resconfig *resconfig; - u8 val, address = twl4030_start_script_address; + int err2 = 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) - 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; - for (i = 0; i < twl4030_scripts->num; i++) { - err = load_twl4030_script(twl4030_scripts->scripts[i], address); - if (err) - goto load; - address += twl4030_scripts->scripts[i]->size; + if (err) { + pr_err("TWL4030 Unable to unlock registers\n"); + return err; } - resconfig = twl4030_scripts->resource_config; - if (resconfig) { - while (resconfig->resource) { - err = twl4030_configure_resource(resconfig); - if (err) - goto resource; - resconfig++; - + if (pdata) { + /* TODO: convert to device tree */ + err = twl4030_power_configure_scripts(pdata); + if (err) { + pr_err("TWL4030 failed to load scripts\n"); + goto relock; + } + err = twl4030_power_configure_resources(pdata); + if (err) { + pr_err("TWL4030 failed to configure resource\n"); + goto relock; } } /* Board has to be wired properly to use this feature */ - if (twl4030_scripts->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); @@ -564,22 +613,43 @@ void twl4030_power_init(struct twl4030_power_data *twl4030_scripts) } 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; + return err2; + } -unlock: - if (err) - pr_err("TWL4030 Unable to unlock registers\n"); - return; -load: - if (err) - pr_err("TWL4030 failed to load scripts\n"); - return; -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; +} + +#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, +}; + +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/drivers/mfd/vexpress-sysreg.c b/drivers/mfd/vexpress-sysreg.c index 96a020b1dcd1..981bef4b7ebc 100644 --- a/drivers/mfd/vexpress-sysreg.c +++ b/drivers/mfd/vexpress-sysreg.c @@ -351,6 +351,8 @@ void __init vexpress_sysreg_of_early_init(void) } +#ifdef CONFIG_GPIOLIB + #define VEXPRESS_SYSREG_GPIO(_name, _reg, _value) \ [VEXPRESS_GPIO_##_name] = { \ .reg = _reg, \ @@ -445,6 +447,8 @@ struct gpio_led_platform_data vexpress_sysreg_leds_pdata = { .leds = vexpress_sysreg_leds, }; +#endif + static ssize_t vexpress_sysreg_sys_id_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -480,6 +484,9 @@ static int vexpress_sysreg_probe(struct platform_device *pdev) setup_timer(&vexpress_sysreg_config_timer, vexpress_sysreg_config_complete, 0); + vexpress_sysreg_dev = &pdev->dev; + +#ifdef CONFIG_GPIOLIB vexpress_sysreg_gpio_chip.dev = &pdev->dev; err = gpiochip_add(&vexpress_sysreg_gpio_chip); if (err) { @@ -490,11 +497,10 @@ static int vexpress_sysreg_probe(struct platform_device *pdev) return err; } - vexpress_sysreg_dev = &pdev->dev; - platform_device_register_data(vexpress_sysreg_dev, "leds-gpio", PLATFORM_DEVID_AUTO, &vexpress_sysreg_leds_pdata, sizeof(vexpress_sysreg_leds_pdata)); +#endif device_create_file(vexpress_sysreg_dev, &dev_attr_sys_id); |