brintos

brintos / linux-shallow public Read only

0
0
Text · 5.1 KiB · 30c1ecb Raw
207 lines · c
1// SPDX-License-Identifier: GPL-2.02// LED Multicolor class interface3// 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_get_color_name(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	led_cdev->flags |= LED_MULTI_COLOR;138	mcled_cdev->led_cdev.groups = led_multicolor_groups;139 140	return led_classdev_register_ext(parent, led_cdev, init_data);141}142EXPORT_SYMBOL_GPL(led_classdev_multicolor_register_ext);143 144void led_classdev_multicolor_unregister(struct led_classdev_mc *mcled_cdev)145{146	if (!mcled_cdev)147		return;148 149	led_classdev_unregister(&mcled_cdev->led_cdev);150}151EXPORT_SYMBOL_GPL(led_classdev_multicolor_unregister);152 153static void devm_led_classdev_multicolor_release(struct device *dev, void *res)154{155	led_classdev_multicolor_unregister(*(struct led_classdev_mc **)res);156}157 158int devm_led_classdev_multicolor_register_ext(struct device *parent,159					     struct led_classdev_mc *mcled_cdev,160					     struct led_init_data *init_data)161{162	struct led_classdev_mc **dr;163	int ret;164 165	dr = devres_alloc(devm_led_classdev_multicolor_release,166			  sizeof(*dr), GFP_KERNEL);167	if (!dr)168		return -ENOMEM;169 170	ret = led_classdev_multicolor_register_ext(parent, mcled_cdev,171						   init_data);172	if (ret) {173		devres_free(dr);174		return ret;175	}176 177	*dr = mcled_cdev;178	devres_add(parent, dr);179 180	return 0;181}182EXPORT_SYMBOL_GPL(devm_led_classdev_multicolor_register_ext);183 184static int devm_led_classdev_multicolor_match(struct device *dev,185					      void *res, void *data)186{187	struct led_classdev_mc **p = res;188 189	if (WARN_ON(!p || !*p))190		return 0;191 192	return *p == data;193}194 195void devm_led_classdev_multicolor_unregister(struct device *dev,196					     struct led_classdev_mc *mcled_cdev)197{198	WARN_ON(devres_release(dev,199			       devm_led_classdev_multicolor_release,200			       devm_led_classdev_multicolor_match, mcled_cdev));201}202EXPORT_SYMBOL_GPL(devm_led_classdev_multicolor_unregister);203 204MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");205MODULE_DESCRIPTION("Multicolor LED class interface");206MODULE_LICENSE("GPL v2");207