summaryrefslogtreecommitdiffstats
path: root/kernel/drivers/leds/leds-syscon.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/drivers/leds/leds-syscon.c')
-rw-r--r--kernel/drivers/leds/leds-syscon.c170
1 files changed, 85 insertions, 85 deletions
diff --git a/kernel/drivers/leds/leds-syscon.c b/kernel/drivers/leds/leds-syscon.c
index 6896e2d9b..b88900d72 100644
--- a/kernel/drivers/leds/leds-syscon.c
+++ b/kernel/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 (IS_ERR(map)) {
+ dev_err(dev, "no regmap for syscon LED parent\n");
+ return PTR_ERR(map);
+ }
+
+ 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);