1 // SPDX-License-Identifier: GPL-2.0
2 // LED Multicolor class interface
3 // Copyright (C) 2019-20 Texas Instruments Incorporated - http://www.ti.com/
4 // Author: Dan Murphy <dmurphy@ti.com>
6 #include <linux/device.h>
7 #include <linux/init.h>
8 #include <linux/led-class-multicolor.h>
9 #include <linux/math.h>
10 #include <linux/module.h>
11 #include <linux/slab.h>
12 #include <linux/uaccess.h>
14 int led_mc_calc_color_components(struct led_classdev_mc
*mcled_cdev
,
15 enum led_brightness brightness
)
17 struct led_classdev
*led_cdev
= &mcled_cdev
->led_cdev
;
20 for (i
= 0; i
< mcled_cdev
->num_colors
; i
++)
21 mcled_cdev
->subled_info
[i
].brightness
=
22 DIV_ROUND_CLOSEST(brightness
*
23 mcled_cdev
->subled_info
[i
].intensity
,
24 led_cdev
->max_brightness
);
28 EXPORT_SYMBOL_GPL(led_mc_calc_color_components
);
30 static ssize_t
multi_intensity_store(struct device
*dev
,
31 struct device_attribute
*intensity_attr
,
32 const char *buf
, size_t size
)
34 struct led_classdev
*led_cdev
= dev_get_drvdata(dev
);
35 struct led_classdev_mc
*mcled_cdev
= lcdev_to_mccdev(led_cdev
);
36 int nrchars
, offset
= 0;
37 int intensity_value
[LED_COLOR_ID_MAX
];
41 mutex_lock(&led_cdev
->led_access
);
43 for (i
= 0; i
< mcled_cdev
->num_colors
; i
++) {
44 ret
= sscanf(buf
+ offset
, "%i%n",
45 &intensity_value
[i
], &nrchars
);
59 for (i
= 0; i
< mcled_cdev
->num_colors
; i
++)
60 mcled_cdev
->subled_info
[i
].intensity
= intensity_value
[i
];
62 led_set_brightness(led_cdev
, led_cdev
->brightness
);
65 mutex_unlock(&led_cdev
->led_access
);
69 static ssize_t
multi_intensity_show(struct device
*dev
,
70 struct device_attribute
*intensity_attr
,
73 struct led_classdev
*led_cdev
= dev_get_drvdata(dev
);
74 struct led_classdev_mc
*mcled_cdev
= lcdev_to_mccdev(led_cdev
);
78 for (i
= 0; i
< mcled_cdev
->num_colors
; i
++) {
79 len
+= sprintf(buf
+ len
, "%d",
80 mcled_cdev
->subled_info
[i
].intensity
);
81 if (i
< mcled_cdev
->num_colors
- 1)
82 len
+= sprintf(buf
+ len
, " ");
88 static DEVICE_ATTR_RW(multi_intensity
);
90 static ssize_t
multi_index_show(struct device
*dev
,
91 struct device_attribute
*multi_index_attr
,
94 struct led_classdev
*led_cdev
= dev_get_drvdata(dev
);
95 struct led_classdev_mc
*mcled_cdev
= lcdev_to_mccdev(led_cdev
);
100 for (i
= 0; i
< mcled_cdev
->num_colors
; i
++) {
101 index
= mcled_cdev
->subled_info
[i
].color_index
;
102 len
+= sprintf(buf
+ len
, "%s", led_get_color_name(index
));
103 if (i
< mcled_cdev
->num_colors
- 1)
104 len
+= sprintf(buf
+ len
, " ");
110 static DEVICE_ATTR_RO(multi_index
);
112 static struct attribute
*led_multicolor_attrs
[] = {
113 &dev_attr_multi_intensity
.attr
,
114 &dev_attr_multi_index
.attr
,
117 ATTRIBUTE_GROUPS(led_multicolor
);
119 int led_classdev_multicolor_register_ext(struct device
*parent
,
120 struct led_classdev_mc
*mcled_cdev
,
121 struct led_init_data
*init_data
)
123 struct led_classdev
*led_cdev
;
128 if (mcled_cdev
->num_colors
<= 0)
131 if (mcled_cdev
->num_colors
> LED_COLOR_ID_MAX
)
134 led_cdev
= &mcled_cdev
->led_cdev
;
135 led_cdev
->flags
|= LED_MULTI_COLOR
;
136 mcled_cdev
->led_cdev
.groups
= led_multicolor_groups
;
138 return led_classdev_register_ext(parent
, led_cdev
, init_data
);
140 EXPORT_SYMBOL_GPL(led_classdev_multicolor_register_ext
);
142 void led_classdev_multicolor_unregister(struct led_classdev_mc
*mcled_cdev
)
147 led_classdev_unregister(&mcled_cdev
->led_cdev
);
149 EXPORT_SYMBOL_GPL(led_classdev_multicolor_unregister
);
151 static void devm_led_classdev_multicolor_release(struct device
*dev
, void *res
)
153 led_classdev_multicolor_unregister(*(struct led_classdev_mc
**)res
);
156 int devm_led_classdev_multicolor_register_ext(struct device
*parent
,
157 struct led_classdev_mc
*mcled_cdev
,
158 struct led_init_data
*init_data
)
160 struct led_classdev_mc
**dr
;
163 dr
= devres_alloc(devm_led_classdev_multicolor_release
,
164 sizeof(*dr
), GFP_KERNEL
);
168 ret
= led_classdev_multicolor_register_ext(parent
, mcled_cdev
,
176 devres_add(parent
, dr
);
180 EXPORT_SYMBOL_GPL(devm_led_classdev_multicolor_register_ext
);
182 static int devm_led_classdev_multicolor_match(struct device
*dev
,
183 void *res
, void *data
)
185 struct led_classdev_mc
**p
= res
;
187 if (WARN_ON(!p
|| !*p
))
193 void devm_led_classdev_multicolor_unregister(struct device
*dev
,
194 struct led_classdev_mc
*mcled_cdev
)
196 WARN_ON(devres_release(dev
,
197 devm_led_classdev_multicolor_release
,
198 devm_led_classdev_multicolor_match
, mcled_cdev
));
200 EXPORT_SYMBOL_GPL(devm_led_classdev_multicolor_unregister
);
202 MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");
203 MODULE_DESCRIPTION("Multicolor LED class interface");
204 MODULE_LICENSE("GPL v2");