1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Greybus Lights protocol driver. |
4 | * |
5 | * Copyright 2015 Google Inc. |
6 | * Copyright 2015 Linaro Ltd. |
7 | */ |
8 | |
9 | #include <linux/kernel.h> |
10 | #include <linux/leds.h> |
11 | #include <linux/led-class-flash.h> |
12 | #include <linux/module.h> |
13 | #include <linux/slab.h> |
14 | #include <linux/greybus.h> |
15 | #include <media/v4l2-flash-led-class.h> |
16 | |
17 | #define NAMES_MAX 32 |
18 | |
19 | struct gb_channel { |
20 | u8 id; |
21 | u32 flags; |
22 | u32 color; |
23 | char *color_name; |
24 | u8 fade_in; |
25 | u8 fade_out; |
26 | u32 mode; |
27 | char *mode_name; |
28 | struct attribute **attrs; |
29 | struct attribute_group *attr_group; |
30 | const struct attribute_group **attr_groups; |
31 | struct led_classdev *led; |
32 | struct led_classdev_flash fled; |
33 | struct led_flash_setting intensity_uA; |
34 | struct led_flash_setting timeout_us; |
35 | struct gb_light *light; |
36 | bool is_registered; |
37 | bool releasing; |
38 | bool strobe_state; |
39 | bool active; |
40 | struct mutex lock; |
41 | }; |
42 | |
43 | struct gb_light { |
44 | u8 id; |
45 | char *name; |
46 | struct gb_lights *glights; |
47 | u32 flags; |
48 | u8 channels_count; |
49 | struct gb_channel *channels; |
50 | bool has_flash; |
51 | bool ready; |
52 | #if IS_REACHABLE(CONFIG_V4L2_FLASH_LED_CLASS) |
53 | struct v4l2_flash *v4l2_flash; |
54 | struct v4l2_flash *v4l2_flash_ind; |
55 | #endif |
56 | }; |
57 | |
58 | struct gb_lights { |
59 | struct gb_connection *connection; |
60 | u8 lights_count; |
61 | struct gb_light *lights; |
62 | struct mutex lights_lock; |
63 | }; |
64 | |
65 | static void gb_lights_channel_free(struct gb_channel *channel); |
66 | |
67 | static struct gb_connection *get_conn_from_channel(struct gb_channel *channel) |
68 | { |
69 | return channel->light->glights->connection; |
70 | } |
71 | |
72 | static struct gb_connection *get_conn_from_light(struct gb_light *light) |
73 | { |
74 | return light->glights->connection; |
75 | } |
76 | |
77 | static bool is_channel_flash(struct gb_channel *channel) |
78 | { |
79 | return !!(channel->mode & (GB_CHANNEL_MODE_FLASH | GB_CHANNEL_MODE_TORCH |
80 | | GB_CHANNEL_MODE_INDICATOR)); |
81 | } |
82 | |
83 | static struct gb_channel *get_channel_from_cdev(struct led_classdev *cdev) |
84 | { |
85 | struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(lcdev: cdev); |
86 | |
87 | return container_of(fled_cdev, struct gb_channel, fled); |
88 | } |
89 | |
90 | static struct led_classdev *get_channel_cdev(struct gb_channel *channel) |
91 | { |
92 | return &channel->fled.led_cdev; |
93 | } |
94 | |
95 | static struct gb_channel *get_channel_from_mode(struct gb_light *light, |
96 | u32 mode) |
97 | { |
98 | struct gb_channel *channel; |
99 | int i; |
100 | |
101 | for (i = 0; i < light->channels_count; i++) { |
102 | channel = &light->channels[i]; |
103 | if (channel->mode == mode) |
104 | return channel; |
105 | } |
106 | return NULL; |
107 | } |
108 | |
109 | static int __gb_lights_flash_intensity_set(struct gb_channel *channel, |
110 | u32 intensity) |
111 | { |
112 | struct gb_connection *connection = get_conn_from_channel(channel); |
113 | struct gb_bundle *bundle = connection->bundle; |
114 | struct gb_lights_set_flash_intensity_request req; |
115 | int ret; |
116 | |
117 | if (channel->releasing) |
118 | return -ESHUTDOWN; |
119 | |
120 | ret = gb_pm_runtime_get_sync(bundle); |
121 | if (ret < 0) |
122 | return ret; |
123 | |
124 | req.light_id = channel->light->id; |
125 | req.channel_id = channel->id; |
126 | req.intensity_uA = cpu_to_le32(intensity); |
127 | |
128 | ret = gb_operation_sync(connection, GB_LIGHTS_TYPE_SET_FLASH_INTENSITY, |
129 | request: &req, request_size: sizeof(req), NULL, response_size: 0); |
130 | |
131 | gb_pm_runtime_put_autosuspend(bundle); |
132 | |
133 | return ret; |
134 | } |
135 | |
136 | static int __gb_lights_flash_brightness_set(struct gb_channel *channel) |
137 | { |
138 | u32 intensity; |
139 | |
140 | /* If the channel is flash we need to get the attached torch channel */ |
141 | if (channel->mode & GB_CHANNEL_MODE_FLASH) |
142 | channel = get_channel_from_mode(light: channel->light, |
143 | GB_CHANNEL_MODE_TORCH); |
144 | |
145 | /* For not flash we need to convert brightness to intensity */ |
146 | intensity = channel->intensity_uA.min + |
147 | (channel->intensity_uA.step * channel->led->brightness); |
148 | |
149 | return __gb_lights_flash_intensity_set(channel, intensity); |
150 | } |
151 | |
152 | static int gb_lights_color_set(struct gb_channel *channel, u32 color); |
153 | static int gb_lights_fade_set(struct gb_channel *channel); |
154 | |
155 | static void led_lock(struct led_classdev *cdev) |
156 | { |
157 | mutex_lock(&cdev->led_access); |
158 | } |
159 | |
160 | static void led_unlock(struct led_classdev *cdev) |
161 | { |
162 | mutex_unlock(lock: &cdev->led_access); |
163 | } |
164 | |
165 | #define gb_lights_fade_attr(__dir) \ |
166 | static ssize_t fade_##__dir##_show(struct device *dev, \ |
167 | struct device_attribute *attr, \ |
168 | char *buf) \ |
169 | { \ |
170 | struct led_classdev *cdev = dev_get_drvdata(dev); \ |
171 | struct gb_channel *channel = get_channel_from_cdev(cdev); \ |
172 | \ |
173 | return sprintf(buf, "%u\n", channel->fade_##__dir); \ |
174 | } \ |
175 | \ |
176 | static ssize_t fade_##__dir##_store(struct device *dev, \ |
177 | struct device_attribute *attr, \ |
178 | const char *buf, size_t size) \ |
179 | { \ |
180 | struct led_classdev *cdev = dev_get_drvdata(dev); \ |
181 | struct gb_channel *channel = get_channel_from_cdev(cdev); \ |
182 | u8 fade; \ |
183 | int ret; \ |
184 | \ |
185 | led_lock(cdev); \ |
186 | if (led_sysfs_is_disabled(cdev)) { \ |
187 | ret = -EBUSY; \ |
188 | goto unlock; \ |
189 | } \ |
190 | \ |
191 | ret = kstrtou8(buf, 0, &fade); \ |
192 | if (ret < 0) { \ |
193 | dev_err(dev, "could not parse fade value %d\n", ret); \ |
194 | goto unlock; \ |
195 | } \ |
196 | if (channel->fade_##__dir == fade) \ |
197 | goto unlock; \ |
198 | channel->fade_##__dir = fade; \ |
199 | \ |
200 | ret = gb_lights_fade_set(channel); \ |
201 | if (ret < 0) \ |
202 | goto unlock; \ |
203 | \ |
204 | ret = size; \ |
205 | unlock: \ |
206 | led_unlock(cdev); \ |
207 | return ret; \ |
208 | } \ |
209 | static DEVICE_ATTR_RW(fade_##__dir) |
210 | |
211 | gb_lights_fade_attr(in); |
212 | gb_lights_fade_attr(out); |
213 | |
214 | static ssize_t color_show(struct device *dev, struct device_attribute *attr, |
215 | char *buf) |
216 | { |
217 | struct led_classdev *cdev = dev_get_drvdata(dev); |
218 | struct gb_channel *channel = get_channel_from_cdev(cdev); |
219 | |
220 | return sprintf(buf, fmt: "0x%08x\n" , channel->color); |
221 | } |
222 | |
223 | static ssize_t color_store(struct device *dev, struct device_attribute *attr, |
224 | const char *buf, size_t size) |
225 | { |
226 | struct led_classdev *cdev = dev_get_drvdata(dev); |
227 | struct gb_channel *channel = get_channel_from_cdev(cdev); |
228 | u32 color; |
229 | int ret; |
230 | |
231 | led_lock(cdev); |
232 | if (led_sysfs_is_disabled(led_cdev: cdev)) { |
233 | ret = -EBUSY; |
234 | goto unlock; |
235 | } |
236 | ret = kstrtou32(s: buf, base: 0, res: &color); |
237 | if (ret < 0) { |
238 | dev_err(dev, "could not parse color value %d\n" , ret); |
239 | goto unlock; |
240 | } |
241 | |
242 | ret = gb_lights_color_set(channel, color); |
243 | if (ret < 0) |
244 | goto unlock; |
245 | |
246 | channel->color = color; |
247 | ret = size; |
248 | unlock: |
249 | led_unlock(cdev); |
250 | return ret; |
251 | } |
252 | static DEVICE_ATTR_RW(color); |
253 | |
254 | static int channel_attr_groups_set(struct gb_channel *channel, |
255 | struct led_classdev *cdev) |
256 | { |
257 | int attr = 0; |
258 | int size = 0; |
259 | |
260 | if (channel->flags & GB_LIGHT_CHANNEL_MULTICOLOR) |
261 | size++; |
262 | if (channel->flags & GB_LIGHT_CHANNEL_FADER) |
263 | size += 2; |
264 | |
265 | if (!size) |
266 | return 0; |
267 | |
268 | /* Set attributes based in the channel flags */ |
269 | channel->attrs = kcalloc(n: size + 1, size: sizeof(*channel->attrs), GFP_KERNEL); |
270 | if (!channel->attrs) |
271 | return -ENOMEM; |
272 | channel->attr_group = kzalloc(size: sizeof(*channel->attr_group), GFP_KERNEL); |
273 | if (!channel->attr_group) |
274 | return -ENOMEM; |
275 | channel->attr_groups = kcalloc(n: 2, size: sizeof(*channel->attr_groups), |
276 | GFP_KERNEL); |
277 | if (!channel->attr_groups) |
278 | return -ENOMEM; |
279 | |
280 | if (channel->flags & GB_LIGHT_CHANNEL_MULTICOLOR) |
281 | channel->attrs[attr++] = &dev_attr_color.attr; |
282 | if (channel->flags & GB_LIGHT_CHANNEL_FADER) { |
283 | channel->attrs[attr++] = &dev_attr_fade_in.attr; |
284 | channel->attrs[attr++] = &dev_attr_fade_out.attr; |
285 | } |
286 | |
287 | channel->attr_group->attrs = channel->attrs; |
288 | |
289 | channel->attr_groups[0] = channel->attr_group; |
290 | |
291 | cdev->groups = channel->attr_groups; |
292 | |
293 | return 0; |
294 | } |
295 | |
296 | static int gb_lights_fade_set(struct gb_channel *channel) |
297 | { |
298 | struct gb_connection *connection = get_conn_from_channel(channel); |
299 | struct gb_bundle *bundle = connection->bundle; |
300 | struct gb_lights_set_fade_request req; |
301 | int ret; |
302 | |
303 | if (channel->releasing) |
304 | return -ESHUTDOWN; |
305 | |
306 | ret = gb_pm_runtime_get_sync(bundle); |
307 | if (ret < 0) |
308 | return ret; |
309 | |
310 | req.light_id = channel->light->id; |
311 | req.channel_id = channel->id; |
312 | req.fade_in = channel->fade_in; |
313 | req.fade_out = channel->fade_out; |
314 | ret = gb_operation_sync(connection, GB_LIGHTS_TYPE_SET_FADE, |
315 | request: &req, request_size: sizeof(req), NULL, response_size: 0); |
316 | |
317 | gb_pm_runtime_put_autosuspend(bundle); |
318 | |
319 | return ret; |
320 | } |
321 | |
322 | static int gb_lights_color_set(struct gb_channel *channel, u32 color) |
323 | { |
324 | struct gb_connection *connection = get_conn_from_channel(channel); |
325 | struct gb_bundle *bundle = connection->bundle; |
326 | struct gb_lights_set_color_request req; |
327 | int ret; |
328 | |
329 | if (channel->releasing) |
330 | return -ESHUTDOWN; |
331 | |
332 | ret = gb_pm_runtime_get_sync(bundle); |
333 | if (ret < 0) |
334 | return ret; |
335 | |
336 | req.light_id = channel->light->id; |
337 | req.channel_id = channel->id; |
338 | req.color = cpu_to_le32(color); |
339 | ret = gb_operation_sync(connection, GB_LIGHTS_TYPE_SET_COLOR, |
340 | request: &req, request_size: sizeof(req), NULL, response_size: 0); |
341 | |
342 | gb_pm_runtime_put_autosuspend(bundle); |
343 | |
344 | return ret; |
345 | } |
346 | |
347 | static int __gb_lights_led_brightness_set(struct gb_channel *channel) |
348 | { |
349 | struct gb_lights_set_brightness_request req; |
350 | struct gb_connection *connection = get_conn_from_channel(channel); |
351 | struct gb_bundle *bundle = connection->bundle; |
352 | bool old_active; |
353 | int ret; |
354 | |
355 | mutex_lock(&channel->lock); |
356 | ret = gb_pm_runtime_get_sync(bundle); |
357 | if (ret < 0) |
358 | goto out_unlock; |
359 | |
360 | old_active = channel->active; |
361 | |
362 | req.light_id = channel->light->id; |
363 | req.channel_id = channel->id; |
364 | req.brightness = (u8)channel->led->brightness; |
365 | |
366 | ret = gb_operation_sync(connection, GB_LIGHTS_TYPE_SET_BRIGHTNESS, |
367 | request: &req, request_size: sizeof(req), NULL, response_size: 0); |
368 | if (ret < 0) |
369 | goto out_pm_put; |
370 | |
371 | if (channel->led->brightness) |
372 | channel->active = true; |
373 | else |
374 | channel->active = false; |
375 | |
376 | /* we need to keep module alive when turning to active state */ |
377 | if (!old_active && channel->active) |
378 | goto out_unlock; |
379 | |
380 | /* |
381 | * on the other hand if going to inactive we still hold a reference and |
382 | * need to put it, so we could go to suspend. |
383 | */ |
384 | if (old_active && !channel->active) |
385 | gb_pm_runtime_put_autosuspend(bundle); |
386 | |
387 | out_pm_put: |
388 | gb_pm_runtime_put_autosuspend(bundle); |
389 | out_unlock: |
390 | mutex_unlock(lock: &channel->lock); |
391 | |
392 | return ret; |
393 | } |
394 | |
395 | static int __gb_lights_brightness_set(struct gb_channel *channel) |
396 | { |
397 | int ret; |
398 | |
399 | if (channel->releasing) |
400 | return 0; |
401 | |
402 | if (is_channel_flash(channel)) |
403 | ret = __gb_lights_flash_brightness_set(channel); |
404 | else |
405 | ret = __gb_lights_led_brightness_set(channel); |
406 | |
407 | return ret; |
408 | } |
409 | |
410 | static int gb_brightness_set(struct led_classdev *cdev, |
411 | enum led_brightness value) |
412 | { |
413 | struct gb_channel *channel = get_channel_from_cdev(cdev); |
414 | |
415 | channel->led->brightness = value; |
416 | |
417 | return __gb_lights_brightness_set(channel); |
418 | } |
419 | |
420 | static enum led_brightness gb_brightness_get(struct led_classdev *cdev) |
421 | |
422 | { |
423 | struct gb_channel *channel = get_channel_from_cdev(cdev); |
424 | |
425 | return channel->led->brightness; |
426 | } |
427 | |
428 | static int gb_blink_set(struct led_classdev *cdev, unsigned long *delay_on, |
429 | unsigned long *delay_off) |
430 | { |
431 | struct gb_channel *channel = get_channel_from_cdev(cdev); |
432 | struct gb_connection *connection = get_conn_from_channel(channel); |
433 | struct gb_bundle *bundle = connection->bundle; |
434 | struct gb_lights_blink_request req; |
435 | bool old_active; |
436 | int ret; |
437 | |
438 | if (channel->releasing) |
439 | return -ESHUTDOWN; |
440 | |
441 | if (!delay_on || !delay_off) |
442 | return -EINVAL; |
443 | |
444 | mutex_lock(&channel->lock); |
445 | ret = gb_pm_runtime_get_sync(bundle); |
446 | if (ret < 0) |
447 | goto out_unlock; |
448 | |
449 | old_active = channel->active; |
450 | |
451 | req.light_id = channel->light->id; |
452 | req.channel_id = channel->id; |
453 | req.time_on_ms = cpu_to_le16(*delay_on); |
454 | req.time_off_ms = cpu_to_le16(*delay_off); |
455 | |
456 | ret = gb_operation_sync(connection, GB_LIGHTS_TYPE_SET_BLINK, request: &req, |
457 | request_size: sizeof(req), NULL, response_size: 0); |
458 | if (ret < 0) |
459 | goto out_pm_put; |
460 | |
461 | if (*delay_on) |
462 | channel->active = true; |
463 | else |
464 | channel->active = false; |
465 | |
466 | /* we need to keep module alive when turning to active state */ |
467 | if (!old_active && channel->active) |
468 | goto out_unlock; |
469 | |
470 | /* |
471 | * on the other hand if going to inactive we still hold a reference and |
472 | * need to put it, so we could go to suspend. |
473 | */ |
474 | if (old_active && !channel->active) |
475 | gb_pm_runtime_put_autosuspend(bundle); |
476 | |
477 | out_pm_put: |
478 | gb_pm_runtime_put_autosuspend(bundle); |
479 | out_unlock: |
480 | mutex_unlock(lock: &channel->lock); |
481 | |
482 | return ret; |
483 | } |
484 | |
485 | static void gb_lights_led_operations_set(struct gb_channel *channel, |
486 | struct led_classdev *cdev) |
487 | { |
488 | cdev->brightness_get = gb_brightness_get; |
489 | cdev->brightness_set_blocking = gb_brightness_set; |
490 | |
491 | if (channel->flags & GB_LIGHT_CHANNEL_BLINK) |
492 | cdev->blink_set = gb_blink_set; |
493 | } |
494 | |
495 | #if IS_REACHABLE(CONFIG_V4L2_FLASH_LED_CLASS) |
496 | /* V4L2 specific helpers */ |
497 | static const struct v4l2_flash_ops v4l2_flash_ops; |
498 | |
499 | static void __gb_lights_channel_v4l2_config(struct led_flash_setting *channel_s, |
500 | struct led_flash_setting *v4l2_s) |
501 | { |
502 | v4l2_s->min = channel_s->min; |
503 | v4l2_s->max = channel_s->max; |
504 | v4l2_s->step = channel_s->step; |
505 | /* For v4l2 val is the default value */ |
506 | v4l2_s->val = channel_s->max; |
507 | } |
508 | |
509 | static int gb_lights_light_v4l2_register(struct gb_light *light) |
510 | { |
511 | struct gb_connection *connection = get_conn_from_light(light); |
512 | struct device *dev = &connection->bundle->dev; |
513 | struct v4l2_flash_config sd_cfg = { {0} }, sd_cfg_ind = { {0} }; |
514 | struct led_classdev_flash *fled; |
515 | struct led_classdev *iled = NULL; |
516 | struct gb_channel *channel_torch, *channel_ind, *channel_flash; |
517 | |
518 | channel_torch = get_channel_from_mode(light, GB_CHANNEL_MODE_TORCH); |
519 | if (channel_torch) |
520 | __gb_lights_channel_v4l2_config(channel_s: &channel_torch->intensity_uA, |
521 | v4l2_s: &sd_cfg.intensity); |
522 | |
523 | channel_ind = get_channel_from_mode(light, GB_CHANNEL_MODE_INDICATOR); |
524 | if (channel_ind) { |
525 | __gb_lights_channel_v4l2_config(channel_s: &channel_ind->intensity_uA, |
526 | v4l2_s: &sd_cfg_ind.intensity); |
527 | iled = &channel_ind->fled.led_cdev; |
528 | } |
529 | |
530 | channel_flash = get_channel_from_mode(light, GB_CHANNEL_MODE_FLASH); |
531 | WARN_ON(!channel_flash); |
532 | |
533 | fled = &channel_flash->fled; |
534 | |
535 | snprintf(buf: sd_cfg.dev_name, size: sizeof(sd_cfg.dev_name), fmt: "%s" , light->name); |
536 | snprintf(buf: sd_cfg_ind.dev_name, size: sizeof(sd_cfg_ind.dev_name), |
537 | fmt: "%s indicator" , light->name); |
538 | |
539 | /* Set the possible values to faults, in our case all faults */ |
540 | sd_cfg.flash_faults = LED_FAULT_OVER_VOLTAGE | LED_FAULT_TIMEOUT | |
541 | LED_FAULT_OVER_TEMPERATURE | LED_FAULT_SHORT_CIRCUIT | |
542 | LED_FAULT_OVER_CURRENT | LED_FAULT_INDICATOR | |
543 | LED_FAULT_UNDER_VOLTAGE | LED_FAULT_INPUT_VOLTAGE | |
544 | LED_FAULT_LED_OVER_TEMPERATURE; |
545 | |
546 | light->v4l2_flash = v4l2_flash_init(dev, NULL, fled_cdev: fled, ops: &v4l2_flash_ops, |
547 | config: &sd_cfg); |
548 | if (IS_ERR(ptr: light->v4l2_flash)) |
549 | return PTR_ERR(ptr: light->v4l2_flash); |
550 | |
551 | if (channel_ind) { |
552 | light->v4l2_flash_ind = |
553 | v4l2_flash_indicator_init(dev, NULL, iled_cdev: iled, config: &sd_cfg_ind); |
554 | if (IS_ERR(ptr: light->v4l2_flash_ind)) { |
555 | v4l2_flash_release(v4l2_flash: light->v4l2_flash); |
556 | return PTR_ERR(ptr: light->v4l2_flash_ind); |
557 | } |
558 | } |
559 | |
560 | return 0; |
561 | } |
562 | |
563 | static void gb_lights_light_v4l2_unregister(struct gb_light *light) |
564 | { |
565 | v4l2_flash_release(v4l2_flash: light->v4l2_flash_ind); |
566 | v4l2_flash_release(v4l2_flash: light->v4l2_flash); |
567 | } |
568 | #else |
569 | static int gb_lights_light_v4l2_register(struct gb_light *light) |
570 | { |
571 | struct gb_connection *connection = get_conn_from_light(light); |
572 | |
573 | dev_err(&connection->bundle->dev, "no support for v4l2 subdevices\n" ); |
574 | return 0; |
575 | } |
576 | |
577 | static void gb_lights_light_v4l2_unregister(struct gb_light *light) |
578 | { |
579 | } |
580 | #endif |
581 | |
582 | #if IS_REACHABLE(CONFIG_LEDS_CLASS_FLASH) |
583 | /* Flash specific operations */ |
584 | static int gb_lights_flash_intensity_set(struct led_classdev_flash *fcdev, |
585 | u32 brightness) |
586 | { |
587 | struct gb_channel *channel = container_of(fcdev, struct gb_channel, |
588 | fled); |
589 | int ret; |
590 | |
591 | ret = __gb_lights_flash_intensity_set(channel, intensity: brightness); |
592 | if (ret < 0) |
593 | return ret; |
594 | |
595 | fcdev->brightness.val = brightness; |
596 | |
597 | return 0; |
598 | } |
599 | |
600 | static int gb_lights_flash_intensity_get(struct led_classdev_flash *fcdev, |
601 | u32 *brightness) |
602 | { |
603 | *brightness = fcdev->brightness.val; |
604 | |
605 | return 0; |
606 | } |
607 | |
608 | static int gb_lights_flash_strobe_set(struct led_classdev_flash *fcdev, |
609 | bool state) |
610 | { |
611 | struct gb_channel *channel = container_of(fcdev, struct gb_channel, |
612 | fled); |
613 | struct gb_connection *connection = get_conn_from_channel(channel); |
614 | struct gb_bundle *bundle = connection->bundle; |
615 | struct gb_lights_set_flash_strobe_request req; |
616 | int ret; |
617 | |
618 | if (channel->releasing) |
619 | return -ESHUTDOWN; |
620 | |
621 | ret = gb_pm_runtime_get_sync(bundle); |
622 | if (ret < 0) |
623 | return ret; |
624 | |
625 | req.light_id = channel->light->id; |
626 | req.channel_id = channel->id; |
627 | req.state = state ? 1 : 0; |
628 | |
629 | ret = gb_operation_sync(connection, GB_LIGHTS_TYPE_SET_FLASH_STROBE, |
630 | request: &req, request_size: sizeof(req), NULL, response_size: 0); |
631 | if (!ret) |
632 | channel->strobe_state = state; |
633 | |
634 | gb_pm_runtime_put_autosuspend(bundle); |
635 | |
636 | return ret; |
637 | } |
638 | |
639 | static int gb_lights_flash_strobe_get(struct led_classdev_flash *fcdev, |
640 | bool *state) |
641 | { |
642 | struct gb_channel *channel = container_of(fcdev, struct gb_channel, |
643 | fled); |
644 | |
645 | *state = channel->strobe_state; |
646 | return 0; |
647 | } |
648 | |
649 | static int gb_lights_flash_timeout_set(struct led_classdev_flash *fcdev, |
650 | u32 timeout) |
651 | { |
652 | struct gb_channel *channel = container_of(fcdev, struct gb_channel, |
653 | fled); |
654 | struct gb_connection *connection = get_conn_from_channel(channel); |
655 | struct gb_bundle *bundle = connection->bundle; |
656 | struct gb_lights_set_flash_timeout_request req; |
657 | int ret; |
658 | |
659 | if (channel->releasing) |
660 | return -ESHUTDOWN; |
661 | |
662 | ret = gb_pm_runtime_get_sync(bundle); |
663 | if (ret < 0) |
664 | return ret; |
665 | |
666 | req.light_id = channel->light->id; |
667 | req.channel_id = channel->id; |
668 | req.timeout_us = cpu_to_le32(timeout); |
669 | |
670 | ret = gb_operation_sync(connection, GB_LIGHTS_TYPE_SET_FLASH_TIMEOUT, |
671 | request: &req, request_size: sizeof(req), NULL, response_size: 0); |
672 | if (!ret) |
673 | fcdev->timeout.val = timeout; |
674 | |
675 | gb_pm_runtime_put_autosuspend(bundle); |
676 | |
677 | return ret; |
678 | } |
679 | |
680 | static int gb_lights_flash_fault_get(struct led_classdev_flash *fcdev, |
681 | u32 *fault) |
682 | { |
683 | struct gb_channel *channel = container_of(fcdev, struct gb_channel, |
684 | fled); |
685 | struct gb_connection *connection = get_conn_from_channel(channel); |
686 | struct gb_bundle *bundle = connection->bundle; |
687 | struct gb_lights_get_flash_fault_request req; |
688 | struct gb_lights_get_flash_fault_response resp; |
689 | int ret; |
690 | |
691 | if (channel->releasing) |
692 | return -ESHUTDOWN; |
693 | |
694 | ret = gb_pm_runtime_get_sync(bundle); |
695 | if (ret < 0) |
696 | return ret; |
697 | |
698 | req.light_id = channel->light->id; |
699 | req.channel_id = channel->id; |
700 | |
701 | ret = gb_operation_sync(connection, GB_LIGHTS_TYPE_GET_FLASH_FAULT, |
702 | request: &req, request_size: sizeof(req), response: &resp, response_size: sizeof(resp)); |
703 | if (!ret) |
704 | *fault = le32_to_cpu(resp.fault); |
705 | |
706 | gb_pm_runtime_put_autosuspend(bundle); |
707 | |
708 | return ret; |
709 | } |
710 | |
711 | static const struct led_flash_ops gb_lights_flash_ops = { |
712 | .flash_brightness_set = gb_lights_flash_intensity_set, |
713 | .flash_brightness_get = gb_lights_flash_intensity_get, |
714 | .strobe_set = gb_lights_flash_strobe_set, |
715 | .strobe_get = gb_lights_flash_strobe_get, |
716 | .timeout_set = gb_lights_flash_timeout_set, |
717 | .fault_get = gb_lights_flash_fault_get, |
718 | }; |
719 | |
720 | static int __gb_lights_channel_torch_attach(struct gb_channel *channel, |
721 | struct gb_channel *channel_torch) |
722 | { |
723 | char *name; |
724 | |
725 | /* we can only attach torch to a flash channel */ |
726 | if (!(channel->mode & GB_CHANNEL_MODE_FLASH)) |
727 | return 0; |
728 | |
729 | /* Move torch brightness to the destination */ |
730 | channel->led->max_brightness = channel_torch->led->max_brightness; |
731 | |
732 | /* append mode name to flash name */ |
733 | name = kasprintf(GFP_KERNEL, fmt: "%s_%s" , channel->led->name, |
734 | channel_torch->mode_name); |
735 | if (!name) |
736 | return -ENOMEM; |
737 | kfree(objp: channel->led->name); |
738 | channel->led->name = name; |
739 | |
740 | channel_torch->led = channel->led; |
741 | |
742 | return 0; |
743 | } |
744 | |
745 | static int __gb_lights_flash_led_register(struct gb_channel *channel) |
746 | { |
747 | struct gb_connection *connection = get_conn_from_channel(channel); |
748 | struct led_classdev_flash *fled = &channel->fled; |
749 | struct led_flash_setting *fset; |
750 | struct gb_channel *channel_torch; |
751 | int ret; |
752 | |
753 | fled->ops = &gb_lights_flash_ops; |
754 | |
755 | fled->led_cdev.flags |= LED_DEV_CAP_FLASH; |
756 | |
757 | fset = &fled->brightness; |
758 | fset->min = channel->intensity_uA.min; |
759 | fset->max = channel->intensity_uA.max; |
760 | fset->step = channel->intensity_uA.step; |
761 | fset->val = channel->intensity_uA.max; |
762 | |
763 | /* Only the flash mode have the timeout constraints settings */ |
764 | if (channel->mode & GB_CHANNEL_MODE_FLASH) { |
765 | fset = &fled->timeout; |
766 | fset->min = channel->timeout_us.min; |
767 | fset->max = channel->timeout_us.max; |
768 | fset->step = channel->timeout_us.step; |
769 | fset->val = channel->timeout_us.max; |
770 | } |
771 | |
772 | /* |
773 | * If light have torch mode channel, this channel will be the led |
774 | * classdev of the registered above flash classdev |
775 | */ |
776 | channel_torch = get_channel_from_mode(light: channel->light, |
777 | GB_CHANNEL_MODE_TORCH); |
778 | if (channel_torch) { |
779 | ret = __gb_lights_channel_torch_attach(channel, channel_torch); |
780 | if (ret < 0) |
781 | goto fail; |
782 | } |
783 | |
784 | ret = led_classdev_flash_register(parent: &connection->bundle->dev, fled_cdev: fled); |
785 | if (ret < 0) |
786 | goto fail; |
787 | |
788 | channel->is_registered = true; |
789 | return 0; |
790 | fail: |
791 | channel->led = NULL; |
792 | return ret; |
793 | } |
794 | |
795 | static void __gb_lights_flash_led_unregister(struct gb_channel *channel) |
796 | { |
797 | if (!channel->is_registered) |
798 | return; |
799 | |
800 | led_classdev_flash_unregister(fled_cdev: &channel->fled); |
801 | } |
802 | |
803 | static int gb_lights_channel_flash_config(struct gb_channel *channel) |
804 | { |
805 | struct gb_connection *connection = get_conn_from_channel(channel); |
806 | struct gb_lights_get_channel_flash_config_request req; |
807 | struct gb_lights_get_channel_flash_config_response conf; |
808 | struct led_flash_setting *fset; |
809 | int ret; |
810 | |
811 | req.light_id = channel->light->id; |
812 | req.channel_id = channel->id; |
813 | |
814 | ret = gb_operation_sync(connection, |
815 | GB_LIGHTS_TYPE_GET_CHANNEL_FLASH_CONFIG, |
816 | request: &req, request_size: sizeof(req), response: &conf, response_size: sizeof(conf)); |
817 | if (ret < 0) |
818 | return ret; |
819 | |
820 | /* |
821 | * Intensity constraints for flash related modes: flash, torch, |
822 | * indicator. They will be needed for v4l2 registration. |
823 | */ |
824 | fset = &channel->intensity_uA; |
825 | fset->min = le32_to_cpu(conf.intensity_min_uA); |
826 | fset->max = le32_to_cpu(conf.intensity_max_uA); |
827 | fset->step = le32_to_cpu(conf.intensity_step_uA); |
828 | |
829 | /* |
830 | * On flash type, max brightness is set as the number of intensity steps |
831 | * available. |
832 | */ |
833 | channel->led->max_brightness = (fset->max - fset->min) / fset->step; |
834 | |
835 | /* Only the flash mode have the timeout constraints settings */ |
836 | if (channel->mode & GB_CHANNEL_MODE_FLASH) { |
837 | fset = &channel->timeout_us; |
838 | fset->min = le32_to_cpu(conf.timeout_min_us); |
839 | fset->max = le32_to_cpu(conf.timeout_max_us); |
840 | fset->step = le32_to_cpu(conf.timeout_step_us); |
841 | } |
842 | |
843 | return 0; |
844 | } |
845 | #else |
846 | static int gb_lights_channel_flash_config(struct gb_channel *channel) |
847 | { |
848 | struct gb_connection *connection = get_conn_from_channel(channel); |
849 | |
850 | dev_err(&connection->bundle->dev, "no support for flash devices\n" ); |
851 | return 0; |
852 | } |
853 | |
854 | static int __gb_lights_flash_led_register(struct gb_channel *channel) |
855 | { |
856 | return 0; |
857 | } |
858 | |
859 | static void __gb_lights_flash_led_unregister(struct gb_channel *channel) |
860 | { |
861 | } |
862 | |
863 | #endif |
864 | |
865 | static int __gb_lights_led_register(struct gb_channel *channel) |
866 | { |
867 | struct gb_connection *connection = get_conn_from_channel(channel); |
868 | struct led_classdev *cdev = get_channel_cdev(channel); |
869 | int ret; |
870 | |
871 | ret = led_classdev_register(parent: &connection->bundle->dev, led_cdev: cdev); |
872 | if (ret < 0) |
873 | channel->led = NULL; |
874 | else |
875 | channel->is_registered = true; |
876 | return ret; |
877 | } |
878 | |
879 | static int gb_lights_channel_register(struct gb_channel *channel) |
880 | { |
881 | /* Normal LED channel, just register in led classdev and we are done */ |
882 | if (!is_channel_flash(channel)) |
883 | return __gb_lights_led_register(channel); |
884 | |
885 | /* |
886 | * Flash Type need more work, register flash classdev, indicator as |
887 | * flash classdev, torch will be led classdev of the flash classdev. |
888 | */ |
889 | if (!(channel->mode & GB_CHANNEL_MODE_TORCH)) |
890 | return __gb_lights_flash_led_register(channel); |
891 | |
892 | return 0; |
893 | } |
894 | |
895 | static void __gb_lights_led_unregister(struct gb_channel *channel) |
896 | { |
897 | struct led_classdev *cdev = get_channel_cdev(channel); |
898 | |
899 | if (!channel->is_registered) |
900 | return; |
901 | |
902 | led_classdev_unregister(led_cdev: cdev); |
903 | kfree(objp: cdev->name); |
904 | cdev->name = NULL; |
905 | channel->led = NULL; |
906 | } |
907 | |
908 | static void gb_lights_channel_unregister(struct gb_channel *channel) |
909 | { |
910 | /* The same as register, handle channels differently */ |
911 | if (!is_channel_flash(channel)) { |
912 | __gb_lights_led_unregister(channel); |
913 | return; |
914 | } |
915 | |
916 | if (channel->mode & GB_CHANNEL_MODE_TORCH) |
917 | __gb_lights_led_unregister(channel); |
918 | else |
919 | __gb_lights_flash_led_unregister(channel); |
920 | } |
921 | |
922 | static int gb_lights_channel_config(struct gb_light *light, |
923 | struct gb_channel *channel) |
924 | { |
925 | struct gb_lights_get_channel_config_response conf; |
926 | struct gb_lights_get_channel_config_request req; |
927 | struct gb_connection *connection = get_conn_from_light(light); |
928 | struct led_classdev *cdev = get_channel_cdev(channel); |
929 | char *name; |
930 | int ret; |
931 | |
932 | req.light_id = light->id; |
933 | req.channel_id = channel->id; |
934 | |
935 | ret = gb_operation_sync(connection, GB_LIGHTS_TYPE_GET_CHANNEL_CONFIG, |
936 | request: &req, request_size: sizeof(req), response: &conf, response_size: sizeof(conf)); |
937 | if (ret < 0) |
938 | return ret; |
939 | |
940 | channel->light = light; |
941 | channel->mode = le32_to_cpu(conf.mode); |
942 | channel->flags = le32_to_cpu(conf.flags); |
943 | channel->color = le32_to_cpu(conf.color); |
944 | channel->color_name = kstrndup(s: conf.color_name, NAMES_MAX, GFP_KERNEL); |
945 | if (!channel->color_name) |
946 | return -ENOMEM; |
947 | channel->mode_name = kstrndup(s: conf.mode_name, NAMES_MAX, GFP_KERNEL); |
948 | if (!channel->mode_name) |
949 | return -ENOMEM; |
950 | |
951 | channel->led = cdev; |
952 | |
953 | name = kasprintf(GFP_KERNEL, fmt: "%s:%s:%s" , light->name, |
954 | channel->color_name, channel->mode_name); |
955 | if (!name) |
956 | return -ENOMEM; |
957 | |
958 | cdev->name = name; |
959 | |
960 | cdev->max_brightness = conf.max_brightness; |
961 | |
962 | ret = channel_attr_groups_set(channel, cdev); |
963 | if (ret < 0) |
964 | return ret; |
965 | |
966 | gb_lights_led_operations_set(channel, cdev); |
967 | |
968 | /* |
969 | * If it is not a flash related channel (flash, torch or indicator) we |
970 | * are done here. If not, continue and fetch flash related |
971 | * configurations. |
972 | */ |
973 | if (!is_channel_flash(channel)) |
974 | return ret; |
975 | |
976 | light->has_flash = true; |
977 | |
978 | return gb_lights_channel_flash_config(channel); |
979 | } |
980 | |
981 | static int gb_lights_light_config(struct gb_lights *glights, u8 id) |
982 | { |
983 | struct gb_light *light = &glights->lights[id]; |
984 | struct gb_lights_get_light_config_request req; |
985 | struct gb_lights_get_light_config_response conf; |
986 | int ret; |
987 | int i; |
988 | |
989 | light->glights = glights; |
990 | light->id = id; |
991 | |
992 | req.id = id; |
993 | |
994 | ret = gb_operation_sync(connection: glights->connection, |
995 | GB_LIGHTS_TYPE_GET_LIGHT_CONFIG, |
996 | request: &req, request_size: sizeof(req), response: &conf, response_size: sizeof(conf)); |
997 | if (ret < 0) |
998 | return ret; |
999 | |
1000 | if (!conf.channel_count) |
1001 | return -EINVAL; |
1002 | if (!strlen(conf.name)) |
1003 | return -EINVAL; |
1004 | |
1005 | light->channels_count = conf.channel_count; |
1006 | light->name = kstrndup(s: conf.name, NAMES_MAX, GFP_KERNEL); |
1007 | if (!light->name) |
1008 | return -ENOMEM; |
1009 | light->channels = kcalloc(n: light->channels_count, |
1010 | size: sizeof(struct gb_channel), GFP_KERNEL); |
1011 | if (!light->channels) |
1012 | return -ENOMEM; |
1013 | |
1014 | /* First we collect all the configurations for all channels */ |
1015 | for (i = 0; i < light->channels_count; i++) { |
1016 | light->channels[i].id = i; |
1017 | ret = gb_lights_channel_config(light, channel: &light->channels[i]); |
1018 | if (ret < 0) |
1019 | return ret; |
1020 | } |
1021 | |
1022 | return 0; |
1023 | } |
1024 | |
1025 | static int gb_lights_light_register(struct gb_light *light) |
1026 | { |
1027 | int ret; |
1028 | int i; |
1029 | |
1030 | /* |
1031 | * Then, if everything went ok in getting configurations, we register |
1032 | * the classdev, flash classdev and v4l2 subsystem, if a flash device is |
1033 | * found. |
1034 | */ |
1035 | for (i = 0; i < light->channels_count; i++) { |
1036 | ret = gb_lights_channel_register(channel: &light->channels[i]); |
1037 | if (ret < 0) |
1038 | return ret; |
1039 | |
1040 | mutex_init(&light->channels[i].lock); |
1041 | } |
1042 | |
1043 | light->ready = true; |
1044 | |
1045 | if (light->has_flash) { |
1046 | ret = gb_lights_light_v4l2_register(light); |
1047 | if (ret < 0) { |
1048 | light->has_flash = false; |
1049 | return ret; |
1050 | } |
1051 | } |
1052 | |
1053 | return 0; |
1054 | } |
1055 | |
1056 | static void gb_lights_channel_free(struct gb_channel *channel) |
1057 | { |
1058 | kfree(objp: channel->attrs); |
1059 | kfree(objp: channel->attr_group); |
1060 | kfree(objp: channel->attr_groups); |
1061 | kfree(objp: channel->color_name); |
1062 | kfree(objp: channel->mode_name); |
1063 | mutex_destroy(lock: &channel->lock); |
1064 | } |
1065 | |
1066 | static void gb_lights_channel_release(struct gb_channel *channel) |
1067 | { |
1068 | channel->releasing = true; |
1069 | |
1070 | gb_lights_channel_unregister(channel); |
1071 | |
1072 | gb_lights_channel_free(channel); |
1073 | } |
1074 | |
1075 | static void gb_lights_light_release(struct gb_light *light) |
1076 | { |
1077 | int i; |
1078 | |
1079 | light->ready = false; |
1080 | |
1081 | if (light->has_flash) |
1082 | gb_lights_light_v4l2_unregister(light); |
1083 | light->has_flash = false; |
1084 | |
1085 | for (i = 0; i < light->channels_count; i++) |
1086 | gb_lights_channel_release(channel: &light->channels[i]); |
1087 | light->channels_count = 0; |
1088 | |
1089 | kfree(objp: light->channels); |
1090 | light->channels = NULL; |
1091 | kfree(objp: light->name); |
1092 | light->name = NULL; |
1093 | } |
1094 | |
1095 | static void gb_lights_release(struct gb_lights *glights) |
1096 | { |
1097 | int i; |
1098 | |
1099 | if (!glights) |
1100 | return; |
1101 | |
1102 | mutex_lock(&glights->lights_lock); |
1103 | if (!glights->lights) |
1104 | goto free_glights; |
1105 | |
1106 | for (i = 0; i < glights->lights_count; i++) |
1107 | gb_lights_light_release(light: &glights->lights[i]); |
1108 | |
1109 | kfree(objp: glights->lights); |
1110 | |
1111 | free_glights: |
1112 | mutex_unlock(lock: &glights->lights_lock); |
1113 | mutex_destroy(lock: &glights->lights_lock); |
1114 | kfree(objp: glights); |
1115 | } |
1116 | |
1117 | static int gb_lights_get_count(struct gb_lights *glights) |
1118 | { |
1119 | struct gb_lights_get_lights_response resp; |
1120 | int ret; |
1121 | |
1122 | ret = gb_operation_sync(connection: glights->connection, GB_LIGHTS_TYPE_GET_LIGHTS, |
1123 | NULL, request_size: 0, response: &resp, response_size: sizeof(resp)); |
1124 | if (ret < 0) |
1125 | return ret; |
1126 | |
1127 | if (!resp.lights_count) |
1128 | return -EINVAL; |
1129 | |
1130 | glights->lights_count = resp.lights_count; |
1131 | |
1132 | return 0; |
1133 | } |
1134 | |
1135 | static int gb_lights_create_all(struct gb_lights *glights) |
1136 | { |
1137 | struct gb_connection *connection = glights->connection; |
1138 | int ret; |
1139 | int i; |
1140 | |
1141 | mutex_lock(&glights->lights_lock); |
1142 | ret = gb_lights_get_count(glights); |
1143 | if (ret < 0) |
1144 | goto out; |
1145 | |
1146 | glights->lights = kcalloc(n: glights->lights_count, |
1147 | size: sizeof(struct gb_light), GFP_KERNEL); |
1148 | if (!glights->lights) { |
1149 | ret = -ENOMEM; |
1150 | goto out; |
1151 | } |
1152 | |
1153 | for (i = 0; i < glights->lights_count; i++) { |
1154 | ret = gb_lights_light_config(glights, id: i); |
1155 | if (ret < 0) { |
1156 | dev_err(&connection->bundle->dev, |
1157 | "Fail to configure lights device\n" ); |
1158 | goto out; |
1159 | } |
1160 | } |
1161 | |
1162 | out: |
1163 | mutex_unlock(lock: &glights->lights_lock); |
1164 | return ret; |
1165 | } |
1166 | |
1167 | static int gb_lights_register_all(struct gb_lights *glights) |
1168 | { |
1169 | struct gb_connection *connection = glights->connection; |
1170 | int ret = 0; |
1171 | int i; |
1172 | |
1173 | mutex_lock(&glights->lights_lock); |
1174 | for (i = 0; i < glights->lights_count; i++) { |
1175 | ret = gb_lights_light_register(light: &glights->lights[i]); |
1176 | if (ret < 0) { |
1177 | dev_err(&connection->bundle->dev, |
1178 | "Fail to enable lights device\n" ); |
1179 | break; |
1180 | } |
1181 | } |
1182 | |
1183 | mutex_unlock(lock: &glights->lights_lock); |
1184 | return ret; |
1185 | } |
1186 | |
1187 | static int gb_lights_request_handler(struct gb_operation *op) |
1188 | { |
1189 | struct gb_connection *connection = op->connection; |
1190 | struct device *dev = &connection->bundle->dev; |
1191 | struct gb_lights *glights = gb_connection_get_data(connection); |
1192 | struct gb_light *light; |
1193 | struct gb_message *request; |
1194 | struct gb_lights_event_request *payload; |
1195 | int ret = 0; |
1196 | u8 light_id; |
1197 | u8 event; |
1198 | |
1199 | if (op->type != GB_LIGHTS_TYPE_EVENT) { |
1200 | dev_err(dev, "Unsupported unsolicited event: %u\n" , op->type); |
1201 | return -EINVAL; |
1202 | } |
1203 | |
1204 | request = op->request; |
1205 | |
1206 | if (request->payload_size < sizeof(*payload)) { |
1207 | dev_err(dev, "Wrong event size received (%zu < %zu)\n" , |
1208 | request->payload_size, sizeof(*payload)); |
1209 | return -EINVAL; |
1210 | } |
1211 | |
1212 | payload = request->payload; |
1213 | light_id = payload->light_id; |
1214 | |
1215 | if (light_id >= glights->lights_count || |
1216 | !glights->lights[light_id].ready) { |
1217 | dev_err(dev, "Event received for unconfigured light id: %d\n" , |
1218 | light_id); |
1219 | return -EINVAL; |
1220 | } |
1221 | |
1222 | event = payload->event; |
1223 | |
1224 | if (event & GB_LIGHTS_LIGHT_CONFIG) { |
1225 | light = &glights->lights[light_id]; |
1226 | |
1227 | mutex_lock(&glights->lights_lock); |
1228 | gb_lights_light_release(light); |
1229 | ret = gb_lights_light_config(glights, id: light_id); |
1230 | if (!ret) |
1231 | ret = gb_lights_light_register(light); |
1232 | if (ret < 0) |
1233 | gb_lights_light_release(light); |
1234 | mutex_unlock(lock: &glights->lights_lock); |
1235 | } |
1236 | |
1237 | return ret; |
1238 | } |
1239 | |
1240 | static int gb_lights_probe(struct gb_bundle *bundle, |
1241 | const struct greybus_bundle_id *id) |
1242 | { |
1243 | struct greybus_descriptor_cport *cport_desc; |
1244 | struct gb_connection *connection; |
1245 | struct gb_lights *glights; |
1246 | int ret; |
1247 | |
1248 | if (bundle->num_cports != 1) |
1249 | return -ENODEV; |
1250 | |
1251 | cport_desc = &bundle->cport_desc[0]; |
1252 | if (cport_desc->protocol_id != GREYBUS_PROTOCOL_LIGHTS) |
1253 | return -ENODEV; |
1254 | |
1255 | glights = kzalloc(size: sizeof(*glights), GFP_KERNEL); |
1256 | if (!glights) |
1257 | return -ENOMEM; |
1258 | |
1259 | mutex_init(&glights->lights_lock); |
1260 | |
1261 | connection = gb_connection_create(bundle, le16_to_cpu(cport_desc->id), |
1262 | handler: gb_lights_request_handler); |
1263 | if (IS_ERR(ptr: connection)) { |
1264 | ret = PTR_ERR(ptr: connection); |
1265 | goto out; |
1266 | } |
1267 | |
1268 | glights->connection = connection; |
1269 | gb_connection_set_data(connection, data: glights); |
1270 | |
1271 | greybus_set_drvdata(bundle, data: glights); |
1272 | |
1273 | /* We aren't ready to receive an incoming request yet */ |
1274 | ret = gb_connection_enable_tx(connection); |
1275 | if (ret) |
1276 | goto error_connection_destroy; |
1277 | |
1278 | /* |
1279 | * Setup all the lights devices over this connection, if anything goes |
1280 | * wrong tear down all lights |
1281 | */ |
1282 | ret = gb_lights_create_all(glights); |
1283 | if (ret < 0) |
1284 | goto error_connection_disable; |
1285 | |
1286 | /* We are ready to receive an incoming request now, enable RX as well */ |
1287 | ret = gb_connection_enable(connection); |
1288 | if (ret) |
1289 | goto error_connection_disable; |
1290 | |
1291 | /* Enable & register lights */ |
1292 | ret = gb_lights_register_all(glights); |
1293 | if (ret < 0) |
1294 | goto error_connection_disable; |
1295 | |
1296 | gb_pm_runtime_put_autosuspend(bundle); |
1297 | |
1298 | return 0; |
1299 | |
1300 | error_connection_disable: |
1301 | gb_connection_disable(connection); |
1302 | error_connection_destroy: |
1303 | gb_connection_destroy(connection); |
1304 | out: |
1305 | gb_lights_release(glights); |
1306 | return ret; |
1307 | } |
1308 | |
1309 | static void gb_lights_disconnect(struct gb_bundle *bundle) |
1310 | { |
1311 | struct gb_lights *glights = greybus_get_drvdata(bundle); |
1312 | |
1313 | if (gb_pm_runtime_get_sync(bundle)) |
1314 | gb_pm_runtime_get_noresume(bundle); |
1315 | |
1316 | gb_connection_disable(connection: glights->connection); |
1317 | gb_connection_destroy(connection: glights->connection); |
1318 | |
1319 | gb_lights_release(glights); |
1320 | } |
1321 | |
1322 | static const struct greybus_bundle_id gb_lights_id_table[] = { |
1323 | { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_LIGHTS) }, |
1324 | { } |
1325 | }; |
1326 | MODULE_DEVICE_TABLE(greybus, gb_lights_id_table); |
1327 | |
1328 | static struct greybus_driver gb_lights_driver = { |
1329 | .name = "lights" , |
1330 | .probe = gb_lights_probe, |
1331 | .disconnect = gb_lights_disconnect, |
1332 | .id_table = gb_lights_id_table, |
1333 | }; |
1334 | module_greybus_driver(gb_lights_driver); |
1335 | |
1336 | MODULE_LICENSE("GPL v2" ); |
1337 | |