Linux Audio

Check our new training course

Linux debugging, profiling, tracing and performance analysis training

Apr 14-17, 2025
Register
Loading...
v6.8
  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");
v5.14.15
  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/module.h>
 10#include <linux/slab.h>
 11#include <linux/uaccess.h>
 12
 13#include "leds.h"
 14
 15int led_mc_calc_color_components(struct led_classdev_mc *mcled_cdev,
 16				 enum led_brightness brightness)
 17{
 18	struct led_classdev *led_cdev = &mcled_cdev->led_cdev;
 19	int i;
 20
 21	for (i = 0; i < mcled_cdev->num_colors; i++)
 22		mcled_cdev->subled_info[i].brightness = 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_colors[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	mcled_cdev->led_cdev.groups = led_multicolor_groups;
136
137	return led_classdev_register_ext(parent, led_cdev, init_data);
138}
139EXPORT_SYMBOL_GPL(led_classdev_multicolor_register_ext);
140
141void led_classdev_multicolor_unregister(struct led_classdev_mc *mcled_cdev)
142{
143	if (!mcled_cdev)
144		return;
145
146	led_classdev_unregister(&mcled_cdev->led_cdev);
147}
148EXPORT_SYMBOL_GPL(led_classdev_multicolor_unregister);
149
150static void devm_led_classdev_multicolor_release(struct device *dev, void *res)
151{
152	led_classdev_multicolor_unregister(*(struct led_classdev_mc **)res);
153}
154
155int devm_led_classdev_multicolor_register_ext(struct device *parent,
156					     struct led_classdev_mc *mcled_cdev,
157					     struct led_init_data *init_data)
158{
159	struct led_classdev_mc **dr;
160	int ret;
161
162	dr = devres_alloc(devm_led_classdev_multicolor_release,
163			  sizeof(*dr), GFP_KERNEL);
164	if (!dr)
165		return -ENOMEM;
166
167	ret = led_classdev_multicolor_register_ext(parent, mcled_cdev,
168						   init_data);
169	if (ret) {
170		devres_free(dr);
171		return ret;
172	}
173
174	*dr = mcled_cdev;
175	devres_add(parent, dr);
176
177	return 0;
178}
179EXPORT_SYMBOL_GPL(devm_led_classdev_multicolor_register_ext);
180
181static int devm_led_classdev_multicolor_match(struct device *dev,
182					      void *res, void *data)
183{
184	struct led_classdev_mc **p = res;
185
186	if (WARN_ON(!p || !*p))
187		return 0;
188
189	return *p == data;
190}
191
192void devm_led_classdev_multicolor_unregister(struct device *dev,
193					     struct led_classdev_mc *mcled_cdev)
194{
195	WARN_ON(devres_release(dev,
196			       devm_led_classdev_multicolor_release,
197			       devm_led_classdev_multicolor_match, mcled_cdev));
198}
199EXPORT_SYMBOL_GPL(devm_led_classdev_multicolor_unregister);
200
201MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");
202MODULE_DESCRIPTION("Multicolor LED class interface");
203MODULE_LICENSE("GPL v2");