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