cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

leds-regulator.c (4612B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * leds-regulator.c - LED class driver for regulator driven LEDs.
      4 *
      5 * Copyright (C) 2009 Antonio Ospite <ospite@studenti.unina.it>
      6 *
      7 * Inspired by leds-wm8350 driver.
      8 */
      9
     10#include <linux/module.h>
     11#include <linux/mod_devicetable.h>
     12#include <linux/err.h>
     13#include <linux/slab.h>
     14#include <linux/leds.h>
     15#include <linux/leds-regulator.h>
     16#include <linux/platform_device.h>
     17#include <linux/regulator/consumer.h>
     18
     19#define to_regulator_led(led_cdev) \
     20	container_of(led_cdev, struct regulator_led, cdev)
     21
     22struct regulator_led {
     23	struct led_classdev cdev;
     24	int enabled;
     25	struct mutex mutex;
     26
     27	struct regulator *vcc;
     28};
     29
     30static inline int led_regulator_get_max_brightness(struct regulator *supply)
     31{
     32	int ret;
     33	int voltage = regulator_list_voltage(supply, 0);
     34
     35	if (voltage <= 0)
     36		return 1;
     37
     38	/* even if regulator can't change voltages,
     39	 * we still assume it can change status
     40	 * and the LED can be turned on and off.
     41	 */
     42	ret = regulator_set_voltage(supply, voltage, voltage);
     43	if (ret < 0)
     44		return 1;
     45
     46	return regulator_count_voltages(supply);
     47}
     48
     49static int led_regulator_get_voltage(struct regulator *supply,
     50		enum led_brightness brightness)
     51{
     52	if (brightness == 0)
     53		return -EINVAL;
     54
     55	return regulator_list_voltage(supply, brightness - 1);
     56}
     57
     58
     59static void regulator_led_enable(struct regulator_led *led)
     60{
     61	int ret;
     62
     63	if (led->enabled)
     64		return;
     65
     66	ret = regulator_enable(led->vcc);
     67	if (ret != 0) {
     68		dev_err(led->cdev.dev, "Failed to enable vcc: %d\n", ret);
     69		return;
     70	}
     71
     72	led->enabled = 1;
     73}
     74
     75static void regulator_led_disable(struct regulator_led *led)
     76{
     77	int ret;
     78
     79	if (!led->enabled)
     80		return;
     81
     82	ret = regulator_disable(led->vcc);
     83	if (ret != 0) {
     84		dev_err(led->cdev.dev, "Failed to disable vcc: %d\n", ret);
     85		return;
     86	}
     87
     88	led->enabled = 0;
     89}
     90
     91static int regulator_led_brightness_set(struct led_classdev *led_cdev,
     92					 enum led_brightness value)
     93{
     94	struct regulator_led *led = to_regulator_led(led_cdev);
     95	int voltage;
     96	int ret = 0;
     97
     98	mutex_lock(&led->mutex);
     99
    100	if (value == LED_OFF) {
    101		regulator_led_disable(led);
    102		goto out;
    103	}
    104
    105	if (led->cdev.max_brightness > 1) {
    106		voltage = led_regulator_get_voltage(led->vcc, value);
    107		dev_dbg(led->cdev.dev, "brightness: %d voltage: %d\n",
    108				value, voltage);
    109
    110		ret = regulator_set_voltage(led->vcc, voltage, voltage);
    111		if (ret != 0)
    112			dev_err(led->cdev.dev, "Failed to set voltage %d: %d\n",
    113				voltage, ret);
    114	}
    115
    116	regulator_led_enable(led);
    117
    118out:
    119	mutex_unlock(&led->mutex);
    120	return ret;
    121}
    122
    123static int regulator_led_probe(struct platform_device *pdev)
    124{
    125	struct led_regulator_platform_data *pdata =
    126			dev_get_platdata(&pdev->dev);
    127	struct device *dev = &pdev->dev;
    128	struct led_init_data init_data = {};
    129	struct regulator_led *led;
    130	struct regulator *vcc;
    131	int ret = 0;
    132
    133	vcc = devm_regulator_get_exclusive(dev, "vled");
    134	if (IS_ERR(vcc)) {
    135		dev_err(dev, "Cannot get vcc\n");
    136		return PTR_ERR(vcc);
    137	}
    138
    139	led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
    140	if (led == NULL)
    141		return -ENOMEM;
    142
    143	init_data.fwnode = dev->fwnode;
    144
    145	led->cdev.max_brightness = led_regulator_get_max_brightness(vcc);
    146	/* Legacy platform data label assignment */
    147	if (pdata) {
    148		if (pdata->brightness > led->cdev.max_brightness) {
    149			dev_err(dev, "Invalid default brightness %d\n",
    150				pdata->brightness);
    151			return -EINVAL;
    152		}
    153		led->cdev.brightness = pdata->brightness;
    154		init_data.default_label = pdata->name;
    155	}
    156
    157	led->cdev.brightness_set_blocking = regulator_led_brightness_set;
    158	led->cdev.flags |= LED_CORE_SUSPENDRESUME;
    159	led->vcc = vcc;
    160
    161	/* to handle correctly an already enabled regulator */
    162	if (regulator_is_enabled(led->vcc))
    163		led->enabled = 1;
    164
    165	mutex_init(&led->mutex);
    166
    167	platform_set_drvdata(pdev, led);
    168
    169	ret = led_classdev_register_ext(dev, &led->cdev, &init_data);
    170	if (ret < 0)
    171		return ret;
    172
    173	return 0;
    174}
    175
    176static int regulator_led_remove(struct platform_device *pdev)
    177{
    178	struct regulator_led *led = platform_get_drvdata(pdev);
    179
    180	led_classdev_unregister(&led->cdev);
    181	regulator_led_disable(led);
    182	return 0;
    183}
    184
    185static const struct of_device_id regulator_led_of_match[] = {
    186	{ .compatible = "regulator-led", },
    187	{}
    188};
    189MODULE_DEVICE_TABLE(of, regulator_led_of_match);
    190
    191static struct platform_driver regulator_led_driver = {
    192	.driver = {
    193		.name  = "leds-regulator",
    194		.of_match_table = regulator_led_of_match,
    195	},
    196	.probe  = regulator_led_probe,
    197	.remove = regulator_led_remove,
    198};
    199
    200module_platform_driver(regulator_led_driver);
    201
    202MODULE_AUTHOR("Antonio Ospite <ospite@studenti.unina.it>");
    203MODULE_DESCRIPTION("Regulator driven LED driver");
    204MODULE_LICENSE("GPL");
    205MODULE_ALIAS("platform:leds-regulator");