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