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-lm36274.c (4311B)


      1// SPDX-License-Identifier: GPL-2.0
      2// TI LM36274 LED chip family driver
      3// Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com/
      4
      5#include <linux/bitops.h>
      6#include <linux/device.h>
      7#include <linux/err.h>
      8#include <linux/leds.h>
      9#include <linux/leds-ti-lmu-common.h>
     10#include <linux/mod_devicetable.h>
     11#include <linux/module.h>
     12#include <linux/platform_device.h>
     13#include <linux/property.h>
     14
     15#include <linux/mfd/ti-lmu.h>
     16#include <linux/mfd/ti-lmu-register.h>
     17
     18#include <uapi/linux/uleds.h>
     19
     20#define LM36274_MAX_STRINGS	4
     21#define LM36274_BL_EN		BIT(4)
     22
     23/**
     24 * struct lm36274
     25 * @pdev: platform device
     26 * @led_dev: led class device
     27 * @lmu_data: Register and setting values for common code
     28 * @regmap: Devices register map
     29 * @dev: Pointer to the devices device struct
     30 * @led_sources: The LED strings supported in this array
     31 * @num_leds: Number of LED strings are supported in this array
     32 */
     33struct lm36274 {
     34	struct platform_device *pdev;
     35	struct led_classdev led_dev;
     36	struct ti_lmu_bank lmu_data;
     37	struct regmap *regmap;
     38	struct device *dev;
     39
     40	u32 led_sources[LM36274_MAX_STRINGS];
     41	int num_leds;
     42};
     43
     44static int lm36274_brightness_set(struct led_classdev *led_cdev,
     45				  enum led_brightness brt_val)
     46{
     47	struct lm36274 *chip = container_of(led_cdev, struct lm36274, led_dev);
     48
     49	return ti_lmu_common_set_brightness(&chip->lmu_data, brt_val);
     50}
     51
     52static int lm36274_init(struct lm36274 *chip)
     53{
     54	int enable_val = 0;
     55	int i;
     56
     57	for (i = 0; i < chip->num_leds; i++)
     58		enable_val |= (1 << chip->led_sources[i]);
     59
     60	if (!enable_val) {
     61		dev_err(chip->dev, "No LEDs were enabled\n");
     62		return -EINVAL;
     63	}
     64
     65	enable_val |= LM36274_BL_EN;
     66
     67	return regmap_write(chip->regmap, LM36274_REG_BL_EN, enable_val);
     68}
     69
     70static int lm36274_parse_dt(struct lm36274 *chip,
     71			    struct led_init_data *init_data)
     72{
     73	struct device *dev = chip->dev;
     74	struct fwnode_handle *child;
     75	int ret;
     76
     77	/* There should only be 1 node */
     78	if (device_get_child_node_count(dev) != 1)
     79		return -EINVAL;
     80
     81	child = device_get_next_child_node(dev, NULL);
     82
     83	init_data->fwnode = child;
     84	init_data->devicename = chip->pdev->name;
     85	/* for backwards compatibility when `label` property is not present */
     86	init_data->default_label = ":";
     87
     88	chip->num_leds = fwnode_property_count_u32(child, "led-sources");
     89	if (chip->num_leds <= 0) {
     90		ret = -ENODEV;
     91		goto err;
     92	}
     93
     94	ret = fwnode_property_read_u32_array(child, "led-sources",
     95					     chip->led_sources, chip->num_leds);
     96	if (ret) {
     97		dev_err(dev, "led-sources property missing\n");
     98		goto err;
     99	}
    100
    101	return 0;
    102err:
    103	fwnode_handle_put(child);
    104	return ret;
    105}
    106
    107static int lm36274_probe(struct platform_device *pdev)
    108{
    109	struct ti_lmu *lmu = dev_get_drvdata(pdev->dev.parent);
    110	struct led_init_data init_data = {};
    111	struct lm36274 *chip;
    112	int ret;
    113
    114	chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
    115	if (!chip)
    116		return -ENOMEM;
    117
    118	chip->pdev = pdev;
    119	chip->dev = &pdev->dev;
    120	chip->regmap = lmu->regmap;
    121	platform_set_drvdata(pdev, chip);
    122
    123	ret = lm36274_parse_dt(chip, &init_data);
    124	if (ret) {
    125		dev_err(chip->dev, "Failed to parse DT node\n");
    126		return ret;
    127	}
    128
    129	ret = lm36274_init(chip);
    130	if (ret) {
    131		fwnode_handle_put(init_data.fwnode);
    132		dev_err(chip->dev, "Failed to init the device\n");
    133		return ret;
    134	}
    135
    136	chip->lmu_data.regmap = chip->regmap;
    137	chip->lmu_data.max_brightness = MAX_BRIGHTNESS_11BIT;
    138	chip->lmu_data.msb_brightness_reg = LM36274_REG_BRT_MSB;
    139	chip->lmu_data.lsb_brightness_reg = LM36274_REG_BRT_LSB;
    140
    141	chip->led_dev.max_brightness = MAX_BRIGHTNESS_11BIT;
    142	chip->led_dev.brightness_set_blocking = lm36274_brightness_set;
    143
    144	ret = devm_led_classdev_register_ext(chip->dev, &chip->led_dev,
    145					     &init_data);
    146	if (ret)
    147		dev_err(chip->dev, "Failed to register LED for node %pfw\n",
    148			init_data.fwnode);
    149
    150	fwnode_handle_put(init_data.fwnode);
    151
    152	return ret;
    153}
    154
    155static const struct of_device_id of_lm36274_leds_match[] = {
    156	{ .compatible = "ti,lm36274-backlight", },
    157	{},
    158};
    159MODULE_DEVICE_TABLE(of, of_lm36274_leds_match);
    160
    161static struct platform_driver lm36274_driver = {
    162	.probe  = lm36274_probe,
    163	.driver = {
    164		.name = "lm36274-leds",
    165		.of_match_table = of_lm36274_leds_match,
    166	},
    167};
    168module_platform_driver(lm36274_driver)
    169
    170MODULE_DESCRIPTION("Texas Instruments LM36274 LED driver");
    171MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");
    172MODULE_LICENSE("GPL v2");