diff options
author | Arnd Bergmann <arnd@arndb.de> | 2015-05-12 16:35:29 +0200 |
---|---|---|
committer | Arnd Bergmann <arnd@arndb.de> | 2015-05-12 16:35:29 +0200 |
commit | a746568e5173214f0fa1b532c6c2f12482bc637f (patch) | |
tree | 80706d6cbe0342b05cb38e2a8eb43fc00a5ccfca /drivers | |
parent | 030bbdbf4c833bc69f502eae58498bc5572db736 (diff) | |
parent | 48f1a9a4e268dec7c7f3e79339cfb85699c48eb0 (diff) | |
download | op-kernel-dev-a746568e5173214f0fa1b532c6c2f12482bc637f.zip op-kernel-dev-a746568e5173214f0fa1b532c6c2f12482bc637f.tar.gz |
Merge tag 'simple-mfd' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-integrator into next/drivers
Merge "Simple MFD base patches and cleanups" from Linus Walleij:
- Document MFD DT bindings
- Instantiate subdevices for simple MFDs
- Switch Integrator and RealView to use the simple MFD
- Augment LED driver to probe from platform device
- Add LEDs to Juno Vexpress64
* tag 'simple-mfd' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-integrator:
arm64: add LEDs and some trigger support to defconfig
arm64: juno: Add APB registers and LEDs using syscon
leds: syscon: instantiate from platform device
ARM: dts: update syscons to use simple-mfd
MFD/OF: document MFD devices and handle simple-mfd
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/leds/leds-syscon.c | 170 | ||||
-rw-r--r-- | drivers/of/platform.c | 1 |
2 files changed, 86 insertions, 85 deletions
diff --git a/drivers/leds/leds-syscon.c b/drivers/leds/leds-syscon.c index 6896e2d..d1660b0 100644 --- a/drivers/leds/leds-syscon.c +++ b/drivers/leds/leds-syscon.c @@ -20,6 +20,7 @@ * MA 02111-1307 USA */ #include <linux/io.h> +#include <linux/module.h> #include <linux/of_device.h> #include <linux/of_address.h> #include <linux/platform_device.h> @@ -66,102 +67,101 @@ static void syscon_led_set(struct led_classdev *led_cdev, dev_err(sled->cdev.dev, "error updating LED status\n"); } -static int __init syscon_leds_spawn(struct device_node *np, - struct device *dev, - struct regmap *map) +static int syscon_led_probe(struct platform_device *pdev) { - struct device_node *child; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct device *parent; + struct regmap *map; + struct syscon_led *sled; + const char *state; int ret; - for_each_available_child_of_node(np, child) { - struct syscon_led *sled; - const char *state; - - /* Only check for register-bit-leds */ - if (of_property_match_string(child, "compatible", - "register-bit-led") < 0) - continue; - - sled = devm_kzalloc(dev, sizeof(*sled), GFP_KERNEL); - if (!sled) - return -ENOMEM; - - sled->map = map; - - if (of_property_read_u32(child, "offset", &sled->offset)) - return -EINVAL; - if (of_property_read_u32(child, "mask", &sled->mask)) - return -EINVAL; - sled->cdev.name = - of_get_property(child, "label", NULL) ? : child->name; - sled->cdev.default_trigger = - of_get_property(child, "linux,default-trigger", NULL); - - state = of_get_property(child, "default-state", NULL); - if (state) { - if (!strcmp(state, "keep")) { - u32 val; - - ret = regmap_read(map, sled->offset, &val); - if (ret < 0) - return ret; - sled->state = !!(val & sled->mask); - } else if (!strcmp(state, "on")) { - sled->state = true; - ret = regmap_update_bits(map, sled->offset, - sled->mask, - sled->mask); - if (ret < 0) - return ret; - } else { - sled->state = false; - ret = regmap_update_bits(map, sled->offset, - sled->mask, 0); - if (ret < 0) - return ret; - } + parent = dev->parent; + if (!parent) { + dev_err(dev, "no parent for syscon LED\n"); + return -ENODEV; + } + map = syscon_node_to_regmap(parent->of_node); + if (!map) { + dev_err(dev, "no regmap for syscon LED parent\n"); + return -ENODEV; + } + + sled = devm_kzalloc(dev, sizeof(*sled), GFP_KERNEL); + if (!sled) + return -ENOMEM; + + sled->map = map; + + if (of_property_read_u32(np, "offset", &sled->offset)) + return -EINVAL; + if (of_property_read_u32(np, "mask", &sled->mask)) + return -EINVAL; + sled->cdev.name = + of_get_property(np, "label", NULL) ? : np->name; + sled->cdev.default_trigger = + of_get_property(np, "linux,default-trigger", NULL); + + state = of_get_property(np, "default-state", NULL); + if (state) { + if (!strcmp(state, "keep")) { + u32 val; + + ret = regmap_read(map, sled->offset, &val); + if (ret < 0) + return ret; + sled->state = !!(val & sled->mask); + } else if (!strcmp(state, "on")) { + sled->state = true; + ret = regmap_update_bits(map, sled->offset, + sled->mask, + sled->mask); + if (ret < 0) + return ret; + } else { + sled->state = false; + ret = regmap_update_bits(map, sled->offset, + sled->mask, 0); + if (ret < 0) + return ret; } - sled->cdev.brightness_set = syscon_led_set; + } + sled->cdev.brightness_set = syscon_led_set; - ret = led_classdev_register(dev, &sled->cdev); - if (ret < 0) - return ret; + ret = led_classdev_register(dev, &sled->cdev); + if (ret < 0) + return ret; + + platform_set_drvdata(pdev, sled); + dev_info(dev, "registered LED %s\n", sled->cdev.name); - dev_info(dev, "registered LED %s\n", sled->cdev.name); - } return 0; } -static int __init syscon_leds_init(void) +static int syscon_led_remove(struct platform_device *pdev) { - struct device_node *np; - - for_each_of_allnodes(np) { - struct platform_device *pdev; - struct regmap *map; - int ret; + struct syscon_led *sled = platform_get_drvdata(pdev); - if (!of_device_is_compatible(np, "syscon")) - continue; + led_classdev_unregister(&sled->cdev); + /* Turn it off */ + regmap_update_bits(sled->map, sled->offset, sled->mask, 0); + return 0; +} - map = syscon_node_to_regmap(np); - if (IS_ERR(map)) { - pr_err("error getting regmap for syscon LEDs\n"); - continue; - } +static const struct of_device_id of_syscon_leds_match[] = { + { .compatible = "register-bit-led", }, + {}, +}; - /* - * If the map is there, the device should be there, we allocate - * memory on the syscon device's behalf here. - */ - pdev = of_find_device_by_node(np); - if (!pdev) - return -ENODEV; - ret = syscon_leds_spawn(np, &pdev->dev, map); - if (ret) - dev_err(&pdev->dev, "could not spawn syscon LEDs\n"); - } +MODULE_DEVICE_TABLE(of, of_syscon_leds_match); - return 0; -} -device_initcall(syscon_leds_init); +static struct platform_driver syscon_led_driver = { + .probe = syscon_led_probe, + .remove = syscon_led_remove, + .driver = { + .name = "leds-syscon", + .of_match_table = of_syscon_leds_match, + }, +}; +module_platform_driver(syscon_led_driver); diff --git a/drivers/of/platform.c b/drivers/of/platform.c index a01f57c..ddf8e42 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -25,6 +25,7 @@ const struct of_device_id of_default_bus_match_table[] = { { .compatible = "simple-bus", }, + { .compatible = "simple-mfd", }, #ifdef CONFIG_ARM_AMBA { .compatible = "arm,amba-bus", }, #endif /* CONFIG_ARM_AMBA */ |