summaryrefslogtreecommitdiffstats
path: root/drivers/leds/leds-syscon.c
diff options
context:
space:
mode:
authorLinus Walleij <linus.walleij@linaro.org>2015-03-03 04:08:19 -0500
committerLinus Walleij <linus.walleij@linaro.org>2015-05-11 02:55:03 -0400
commita917d4b44afc968d35e9b2717fea52946f512df1 (patch)
treef634e3b7b8e3ac08c2eb6025b412976b635998ce /drivers/leds/leds-syscon.c
parent480aa74c386121644336d9b59d0b61cde1c3c29c (diff)
leds: syscon: instantiate from platform device
Currently syscon LEDs will traverse the device tree looking for syscon devices and if found, traverse any subnodes of these to identify matching children and from there instantiate LED class devices. This is not a good use of the Linux device model. Instead we have converted the device trees to add the "simple-mfd" property to the MFD nexi spawning syscon LEDs so that these will appear as platform devices in the system and we can use the proper device probing mechanism. Cc: Arnd Bergmann <arnd@arndb.de> Cc: Lee Jones <lee.jones@linaro.org> Cc: Pawel Moll <pawel.moll@arm.com> Cc: Mark Rutland <mark.rutland@arm.com> Reviewed-by: Bjorn Andersson <bjorn.andersson@sonymobile.com> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/leds/leds-syscon.c')
-rw-r--r--drivers/leds/leds-syscon.c170
1 files changed, 85 insertions, 85 deletions
diff --git a/drivers/leds/leds-syscon.c b/drivers/leds/leds-syscon.c
index 6896e2d9ba58..d1660b039812 100644
--- a/drivers/leds/leds-syscon.c
+++ b/drivers/leds/leds-syscon.c
@@ -20,6 +20,7 @@
20 * MA 02111-1307 USA 20 * MA 02111-1307 USA
21 */ 21 */
22#include <linux/io.h> 22#include <linux/io.h>
23#include <linux/module.h>
23#include <linux/of_device.h> 24#include <linux/of_device.h>
24#include <linux/of_address.h> 25#include <linux/of_address.h>
25#include <linux/platform_device.h> 26#include <linux/platform_device.h>
@@ -66,102 +67,101 @@ static void syscon_led_set(struct led_classdev *led_cdev,
66 dev_err(sled->cdev.dev, "error updating LED status\n"); 67 dev_err(sled->cdev.dev, "error updating LED status\n");
67} 68}
68 69
69static int __init syscon_leds_spawn(struct device_node *np, 70static int syscon_led_probe(struct platform_device *pdev)
70 struct device *dev,
71 struct regmap *map)
72{ 71{
73 struct device_node *child; 72 struct device *dev = &pdev->dev;
73 struct device_node *np = dev->of_node;
74 struct device *parent;
75 struct regmap *map;
76 struct syscon_led *sled;
77 const char *state;
74 int ret; 78 int ret;
75 79
76 for_each_available_child_of_node(np, child) { 80 parent = dev->parent;
77 struct syscon_led *sled; 81 if (!parent) {
78 const char *state; 82 dev_err(dev, "no parent for syscon LED\n");
79 83 return -ENODEV;
80 /* Only check for register-bit-leds */ 84 }
81 if (of_property_match_string(child, "compatible", 85 map = syscon_node_to_regmap(parent->of_node);
82 "register-bit-led") < 0) 86 if (!map) {
83 continue; 87 dev_err(dev, "no regmap for syscon LED parent\n");
84 88 return -ENODEV;
85 sled = devm_kzalloc(dev, sizeof(*sled), GFP_KERNEL); 89 }
86 if (!sled) 90
87 return -ENOMEM; 91 sled = devm_kzalloc(dev, sizeof(*sled), GFP_KERNEL);
88 92 if (!sled)
89 sled->map = map; 93 return -ENOMEM;
90 94
91 if (of_property_read_u32(child, "offset", &sled->offset)) 95 sled->map = map;
92 return -EINVAL; 96
93 if (of_property_read_u32(child, "mask", &sled->mask)) 97 if (of_property_read_u32(np, "offset", &sled->offset))
94 return -EINVAL; 98 return -EINVAL;
95 sled->cdev.name = 99 if (of_property_read_u32(np, "mask", &sled->mask))
96 of_get_property(child, "label", NULL) ? : child->name; 100 return -EINVAL;
97 sled->cdev.default_trigger = 101 sled->cdev.name =
98 of_get_property(child, "linux,default-trigger", NULL); 102 of_get_property(np, "label", NULL) ? : np->name;
99 103 sled->cdev.default_trigger =
100 state = of_get_property(child, "default-state", NULL); 104 of_get_property(np, "linux,default-trigger", NULL);
101 if (state) { 105
102 if (!strcmp(state, "keep")) { 106 state = of_get_property(np, "default-state", NULL);
103 u32 val; 107 if (state) {
104 108 if (!strcmp(state, "keep")) {
105 ret = regmap_read(map, sled->offset, &val); 109 u32 val;
106 if (ret < 0) 110
107 return ret; 111 ret = regmap_read(map, sled->offset, &val);
108 sled->state = !!(val & sled->mask); 112 if (ret < 0)
109 } else if (!strcmp(state, "on")) { 113 return ret;
110 sled->state = true; 114 sled->state = !!(val & sled->mask);
111 ret = regmap_update_bits(map, sled->offset, 115 } else if (!strcmp(state, "on")) {
112 sled->mask, 116 sled->state = true;
113 sled->mask); 117 ret = regmap_update_bits(map, sled->offset,
114 if (ret < 0) 118 sled->mask,
115 return ret; 119 sled->mask);
116 } else { 120 if (ret < 0)
117 sled->state = false; 121 return ret;
118 ret = regmap_update_bits(map, sled->offset, 122 } else {
119 sled->mask, 0); 123 sled->state = false;
120 if (ret < 0) 124 ret = regmap_update_bits(map, sled->offset,
121 return ret; 125 sled->mask, 0);
122 } 126 if (ret < 0)
127 return ret;
123 } 128 }
124 sled->cdev.brightness_set = syscon_led_set; 129 }
130 sled->cdev.brightness_set = syscon_led_set;
125 131
126 ret = led_classdev_register(dev, &sled->cdev); 132 ret = led_classdev_register(dev, &sled->cdev);
127 if (ret < 0) 133 if (ret < 0)
128 return ret; 134 return ret;
135
136 platform_set_drvdata(pdev, sled);
137 dev_info(dev, "registered LED %s\n", sled->cdev.name);
129 138
130 dev_info(dev, "registered LED %s\n", sled->cdev.name);
131 }
132 return 0; 139 return 0;
133} 140}
134 141
135static int __init syscon_leds_init(void) 142static int syscon_led_remove(struct platform_device *pdev)
136{ 143{
137 struct device_node *np; 144 struct syscon_led *sled = platform_get_drvdata(pdev);
138
139 for_each_of_allnodes(np) {
140 struct platform_device *pdev;
141 struct regmap *map;
142 int ret;
143 145
144 if (!of_device_is_compatible(np, "syscon")) 146 led_classdev_unregister(&sled->cdev);
145 continue; 147 /* Turn it off */
148 regmap_update_bits(sled->map, sled->offset, sled->mask, 0);
149 return 0;
150}
146 151
147 map = syscon_node_to_regmap(np); 152static const struct of_device_id of_syscon_leds_match[] = {
148 if (IS_ERR(map)) { 153 { .compatible = "register-bit-led", },
149 pr_err("error getting regmap for syscon LEDs\n"); 154 {},
150 continue; 155};
151 }
152 156
153 /* 157MODULE_DEVICE_TABLE(of, of_syscon_leds_match);
154 * If the map is there, the device should be there, we allocate
155 * memory on the syscon device's behalf here.
156 */
157 pdev = of_find_device_by_node(np);
158 if (!pdev)
159 return -ENODEV;
160 ret = syscon_leds_spawn(np, &pdev->dev, map);
161 if (ret)
162 dev_err(&pdev->dev, "could not spawn syscon LEDs\n");
163 }
164 158
165 return 0; 159static struct platform_driver syscon_led_driver = {
166} 160 .probe = syscon_led_probe,
167device_initcall(syscon_leds_init); 161 .remove = syscon_led_remove,
162 .driver = {
163 .name = "leds-syscon",
164 .of_match_table = of_syscon_leds_match,
165 },
166};
167module_platform_driver(syscon_led_driver);