0001
0002
0003
0004
0005
0006 #include <linux/device.h>
0007 #include <linux/init.h>
0008 #include <linux/led-class-multicolor.h>
0009 #include <linux/module.h>
0010 #include <linux/slab.h>
0011 #include <linux/uaccess.h>
0012
0013 #include "leds.h"
0014
0015 int led_mc_calc_color_components(struct led_classdev_mc *mcled_cdev,
0016 enum led_brightness brightness)
0017 {
0018 struct led_classdev *led_cdev = &mcled_cdev->led_cdev;
0019 int i;
0020
0021 for (i = 0; i < mcled_cdev->num_colors; i++)
0022 mcled_cdev->subled_info[i].brightness = brightness *
0023 mcled_cdev->subled_info[i].intensity /
0024 led_cdev->max_brightness;
0025
0026 return 0;
0027 }
0028 EXPORT_SYMBOL_GPL(led_mc_calc_color_components);
0029
0030 static ssize_t multi_intensity_store(struct device *dev,
0031 struct device_attribute *intensity_attr,
0032 const char *buf, size_t size)
0033 {
0034 struct led_classdev *led_cdev = dev_get_drvdata(dev);
0035 struct led_classdev_mc *mcled_cdev = lcdev_to_mccdev(led_cdev);
0036 int nrchars, offset = 0;
0037 int intensity_value[LED_COLOR_ID_MAX];
0038 int i;
0039 ssize_t ret;
0040
0041 mutex_lock(&led_cdev->led_access);
0042
0043 for (i = 0; i < mcled_cdev->num_colors; i++) {
0044 ret = sscanf(buf + offset, "%i%n",
0045 &intensity_value[i], &nrchars);
0046 if (ret != 1) {
0047 ret = -EINVAL;
0048 goto err_out;
0049 }
0050 offset += nrchars;
0051 }
0052
0053 offset++;
0054 if (offset < size) {
0055 ret = -EINVAL;
0056 goto err_out;
0057 }
0058
0059 for (i = 0; i < mcled_cdev->num_colors; i++)
0060 mcled_cdev->subled_info[i].intensity = intensity_value[i];
0061
0062 led_set_brightness(led_cdev, led_cdev->brightness);
0063 ret = size;
0064 err_out:
0065 mutex_unlock(&led_cdev->led_access);
0066 return ret;
0067 }
0068
0069 static ssize_t multi_intensity_show(struct device *dev,
0070 struct device_attribute *intensity_attr,
0071 char *buf)
0072 {
0073 struct led_classdev *led_cdev = dev_get_drvdata(dev);
0074 struct led_classdev_mc *mcled_cdev = lcdev_to_mccdev(led_cdev);
0075 int len = 0;
0076 int i;
0077
0078 for (i = 0; i < mcled_cdev->num_colors; i++) {
0079 len += sprintf(buf + len, "%d",
0080 mcled_cdev->subled_info[i].intensity);
0081 if (i < mcled_cdev->num_colors - 1)
0082 len += sprintf(buf + len, " ");
0083 }
0084
0085 buf[len++] = '\n';
0086 return len;
0087 }
0088 static DEVICE_ATTR_RW(multi_intensity);
0089
0090 static ssize_t multi_index_show(struct device *dev,
0091 struct device_attribute *multi_index_attr,
0092 char *buf)
0093 {
0094 struct led_classdev *led_cdev = dev_get_drvdata(dev);
0095 struct led_classdev_mc *mcled_cdev = lcdev_to_mccdev(led_cdev);
0096 int len = 0;
0097 int index;
0098 int i;
0099
0100 for (i = 0; i < mcled_cdev->num_colors; i++) {
0101 index = mcled_cdev->subled_info[i].color_index;
0102 len += sprintf(buf + len, "%s", led_colors[index]);
0103 if (i < mcled_cdev->num_colors - 1)
0104 len += sprintf(buf + len, " ");
0105 }
0106
0107 buf[len++] = '\n';
0108 return len;
0109 }
0110 static DEVICE_ATTR_RO(multi_index);
0111
0112 static struct attribute *led_multicolor_attrs[] = {
0113 &dev_attr_multi_intensity.attr,
0114 &dev_attr_multi_index.attr,
0115 NULL,
0116 };
0117 ATTRIBUTE_GROUPS(led_multicolor);
0118
0119 int led_classdev_multicolor_register_ext(struct device *parent,
0120 struct led_classdev_mc *mcled_cdev,
0121 struct led_init_data *init_data)
0122 {
0123 struct led_classdev *led_cdev;
0124
0125 if (!mcled_cdev)
0126 return -EINVAL;
0127
0128 if (mcled_cdev->num_colors <= 0)
0129 return -EINVAL;
0130
0131 if (mcled_cdev->num_colors > LED_COLOR_ID_MAX)
0132 return -EINVAL;
0133
0134 led_cdev = &mcled_cdev->led_cdev;
0135 mcled_cdev->led_cdev.groups = led_multicolor_groups;
0136
0137 return led_classdev_register_ext(parent, led_cdev, init_data);
0138 }
0139 EXPORT_SYMBOL_GPL(led_classdev_multicolor_register_ext);
0140
0141 void led_classdev_multicolor_unregister(struct led_classdev_mc *mcled_cdev)
0142 {
0143 if (!mcled_cdev)
0144 return;
0145
0146 led_classdev_unregister(&mcled_cdev->led_cdev);
0147 }
0148 EXPORT_SYMBOL_GPL(led_classdev_multicolor_unregister);
0149
0150 static void devm_led_classdev_multicolor_release(struct device *dev, void *res)
0151 {
0152 led_classdev_multicolor_unregister(*(struct led_classdev_mc **)res);
0153 }
0154
0155 int devm_led_classdev_multicolor_register_ext(struct device *parent,
0156 struct led_classdev_mc *mcled_cdev,
0157 struct led_init_data *init_data)
0158 {
0159 struct led_classdev_mc **dr;
0160 int ret;
0161
0162 dr = devres_alloc(devm_led_classdev_multicolor_release,
0163 sizeof(*dr), GFP_KERNEL);
0164 if (!dr)
0165 return -ENOMEM;
0166
0167 ret = led_classdev_multicolor_register_ext(parent, mcled_cdev,
0168 init_data);
0169 if (ret) {
0170 devres_free(dr);
0171 return ret;
0172 }
0173
0174 *dr = mcled_cdev;
0175 devres_add(parent, dr);
0176
0177 return 0;
0178 }
0179 EXPORT_SYMBOL_GPL(devm_led_classdev_multicolor_register_ext);
0180
0181 static int devm_led_classdev_multicolor_match(struct device *dev,
0182 void *res, void *data)
0183 {
0184 struct led_classdev_mc **p = res;
0185
0186 if (WARN_ON(!p || !*p))
0187 return 0;
0188
0189 return *p == data;
0190 }
0191
0192 void devm_led_classdev_multicolor_unregister(struct device *dev,
0193 struct led_classdev_mc *mcled_cdev)
0194 {
0195 WARN_ON(devres_release(dev,
0196 devm_led_classdev_multicolor_release,
0197 devm_led_classdev_multicolor_match, mcled_cdev));
0198 }
0199 EXPORT_SYMBOL_GPL(devm_led_classdev_multicolor_unregister);
0200
0201 MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");
0202 MODULE_DESCRIPTION("Multicolor LED class interface");
0203 MODULE_LICENSE("GPL v2");