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 - 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/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_count_u32(child, "led-sources");
  94                if (lm36274_data->num_leds <= 0)
  95                        return -ENODEV;
  96
  97                ret = fwnode_property_read_u32_array(child, "led-sources",
  98                                                     lm36274_data->led_sources,
  99                                                     lm36274_data->num_leds);
 100                if (ret) {
 101                        dev_err(dev, "led-sources property missing\n");
 102                        return ret;
 103                }
 104
 105                fwnode_property_read_string(child, "linux,default-trigger",
 106                                        &lm36274_data->led_dev.default_trigger);
 107
 108        }
 109
 110        lm36274_data->lmu_data.regmap = lm36274_data->regmap;
 111        lm36274_data->lmu_data.max_brightness = MAX_BRIGHTNESS_11BIT;
 112        lm36274_data->lmu_data.msb_brightness_reg = LM36274_REG_BRT_MSB;
 113        lm36274_data->lmu_data.lsb_brightness_reg = LM36274_REG_BRT_LSB;
 114
 115        lm36274_data->led_dev.name = label;
 116        lm36274_data->led_dev.max_brightness = MAX_BRIGHTNESS_11BIT;
 117        lm36274_data->led_dev.brightness_set_blocking = lm36274_brightness_set;
 118
 119        return 0;
 120}
 121
 122static int lm36274_probe(struct platform_device *pdev)
 123{
 124        struct ti_lmu *lmu = dev_get_drvdata(pdev->dev.parent);
 125        struct lm36274 *lm36274_data;
 126        int ret;
 127
 128        lm36274_data = devm_kzalloc(&pdev->dev, sizeof(*lm36274_data),
 129                                    GFP_KERNEL);
 130        if (!lm36274_data)
 131                return -ENOMEM;
 132
 133        lm36274_data->pdev = pdev;
 134        lm36274_data->dev = lmu->dev;
 135        lm36274_data->regmap = lmu->regmap;
 136        platform_set_drvdata(pdev, lm36274_data);
 137
 138        ret = lm36274_parse_dt(lm36274_data);
 139        if (ret) {
 140                dev_err(lm36274_data->dev, "Failed to parse DT node\n");
 141                return ret;
 142        }
 143
 144        ret = lm36274_init(lm36274_data);
 145        if (ret) {
 146                dev_err(lm36274_data->dev, "Failed to init the device\n");
 147                return ret;
 148        }
 149
 150        return led_classdev_register(lm36274_data->dev, &lm36274_data->led_dev);
 151}
 152
 153static int lm36274_remove(struct platform_device *pdev)
 154{
 155        struct lm36274 *lm36274_data = platform_get_drvdata(pdev);
 156
 157        led_classdev_unregister(&lm36274_data->led_dev);
 158
 159        return 0;
 160}
 161
 162static const struct of_device_id of_lm36274_leds_match[] = {
 163        { .compatible = "ti,lm36274-backlight", },
 164        {},
 165};
 166MODULE_DEVICE_TABLE(of, of_lm36274_leds_match);
 167
 168static struct platform_driver lm36274_driver = {
 169        .probe  = lm36274_probe,
 170        .remove = lm36274_remove,
 171        .driver = {
 172                .name = "lm36274-leds",
 173        },
 174};
 175module_platform_driver(lm36274_driver)
 176
 177MODULE_DESCRIPTION("Texas Instruments LM36274 LED driver");
 178MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");
 179MODULE_LICENSE("GPL v2");
 180