Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v6.14-rc5 204 lines 5.2 kB view raw
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> 5 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> 13 14int led_mc_calc_color_components(struct led_classdev_mc *mcled_cdev, 15 enum led_brightness brightness) 16{ 17 struct led_classdev *led_cdev = &mcled_cdev->led_cdev; 18 int i; 19 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); 25 26 return 0; 27} 28EXPORT_SYMBOL_GPL(led_mc_calc_color_components); 29 30static ssize_t multi_intensity_store(struct device *dev, 31 struct device_attribute *intensity_attr, 32 const char *buf, size_t size) 33{ 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]; 38 int i; 39 ssize_t ret; 40 41 mutex_lock(&led_cdev->led_access); 42 43 for (i = 0; i < mcled_cdev->num_colors; i++) { 44 ret = sscanf(buf + offset, "%i%n", 45 &intensity_value[i], &nrchars); 46 if (ret != 1) { 47 ret = -EINVAL; 48 goto err_out; 49 } 50 offset += nrchars; 51 } 52 53 offset++; 54 if (offset < size) { 55 ret = -EINVAL; 56 goto err_out; 57 } 58 59 for (i = 0; i < mcled_cdev->num_colors; i++) 60 mcled_cdev->subled_info[i].intensity = intensity_value[i]; 61 62 led_set_brightness(led_cdev, led_cdev->brightness); 63 ret = size; 64err_out: 65 mutex_unlock(&led_cdev->led_access); 66 return ret; 67} 68 69static ssize_t multi_intensity_show(struct device *dev, 70 struct device_attribute *intensity_attr, 71 char *buf) 72{ 73 struct led_classdev *led_cdev = dev_get_drvdata(dev); 74 struct led_classdev_mc *mcled_cdev = lcdev_to_mccdev(led_cdev); 75 int len = 0; 76 int i; 77 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, " "); 83 } 84 85 buf[len++] = '\n'; 86 return len; 87} 88static DEVICE_ATTR_RW(multi_intensity); 89 90static ssize_t multi_index_show(struct device *dev, 91 struct device_attribute *multi_index_attr, 92 char *buf) 93{ 94 struct led_classdev *led_cdev = dev_get_drvdata(dev); 95 struct led_classdev_mc *mcled_cdev = lcdev_to_mccdev(led_cdev); 96 int len = 0; 97 int index; 98 int i; 99 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, " "); 105 } 106 107 buf[len++] = '\n'; 108 return len; 109} 110static DEVICE_ATTR_RO(multi_index); 111 112static struct attribute *led_multicolor_attrs[] = { 113 &dev_attr_multi_intensity.attr, 114 &dev_attr_multi_index.attr, 115 NULL, 116}; 117ATTRIBUTE_GROUPS(led_multicolor); 118 119int led_classdev_multicolor_register_ext(struct device *parent, 120 struct led_classdev_mc *mcled_cdev, 121 struct led_init_data *init_data) 122{ 123 struct led_classdev *led_cdev; 124 125 if (!mcled_cdev) 126 return -EINVAL; 127 128 if (mcled_cdev->num_colors <= 0) 129 return -EINVAL; 130 131 if (mcled_cdev->num_colors > LED_COLOR_ID_MAX) 132 return -EINVAL; 133 134 led_cdev = &mcled_cdev->led_cdev; 135 led_cdev->flags |= LED_MULTI_COLOR; 136 mcled_cdev->led_cdev.groups = led_multicolor_groups; 137 138 return led_classdev_register_ext(parent, led_cdev, init_data); 139} 140EXPORT_SYMBOL_GPL(led_classdev_multicolor_register_ext); 141 142void led_classdev_multicolor_unregister(struct led_classdev_mc *mcled_cdev) 143{ 144 if (!mcled_cdev) 145 return; 146 147 led_classdev_unregister(&mcled_cdev->led_cdev); 148} 149EXPORT_SYMBOL_GPL(led_classdev_multicolor_unregister); 150 151static void devm_led_classdev_multicolor_release(struct device *dev, void *res) 152{ 153 led_classdev_multicolor_unregister(*(struct led_classdev_mc **)res); 154} 155 156int devm_led_classdev_multicolor_register_ext(struct device *parent, 157 struct led_classdev_mc *mcled_cdev, 158 struct led_init_data *init_data) 159{ 160 struct led_classdev_mc **dr; 161 int ret; 162 163 dr = devres_alloc(devm_led_classdev_multicolor_release, 164 sizeof(*dr), GFP_KERNEL); 165 if (!dr) 166 return -ENOMEM; 167 168 ret = led_classdev_multicolor_register_ext(parent, mcled_cdev, 169 init_data); 170 if (ret) { 171 devres_free(dr); 172 return ret; 173 } 174 175 *dr = mcled_cdev; 176 devres_add(parent, dr); 177 178 return 0; 179} 180EXPORT_SYMBOL_GPL(devm_led_classdev_multicolor_register_ext); 181 182static int devm_led_classdev_multicolor_match(struct device *dev, 183 void *res, void *data) 184{ 185 struct led_classdev_mc **p = res; 186 187 if (WARN_ON(!p || !*p)) 188 return 0; 189 190 return *p == data; 191} 192 193void devm_led_classdev_multicolor_unregister(struct device *dev, 194 struct led_classdev_mc *mcled_cdev) 195{ 196 WARN_ON(devres_release(dev, 197 devm_led_classdev_multicolor_release, 198 devm_led_classdev_multicolor_match, mcled_cdev)); 199} 200EXPORT_SYMBOL_GPL(devm_led_classdev_multicolor_unregister); 201 202MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>"); 203MODULE_DESCRIPTION("Multicolor LED class interface"); 204MODULE_LICENSE("GPL v2");