linux/drivers/leds/leds-tlc591xx.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright 2014 Belkin Inc.
   4 * Copyright 2015 Andrew Lunn <andrew@lunn.ch>
   5 */
   6
   7#include <linux/i2c.h>
   8#include <linux/leds.h>
   9#include <linux/module.h>
  10#include <linux/of.h>
  11#include <linux/of_device.h>
  12#include <linux/regmap.h>
  13#include <linux/slab.h>
  14
  15#define TLC591XX_MAX_LEDS       16
  16
  17#define TLC591XX_REG_MODE1      0x00
  18#define MODE1_RESPON_ADDR_MASK  0xF0
  19#define MODE1_NORMAL_MODE       (0 << 4)
  20#define MODE1_SPEED_MODE        (1 << 4)
  21
  22#define TLC591XX_REG_MODE2      0x01
  23#define MODE2_DIM               (0 << 5)
  24#define MODE2_BLINK             (1 << 5)
  25#define MODE2_OCH_STOP          (0 << 3)
  26#define MODE2_OCH_ACK           (1 << 3)
  27
  28#define TLC591XX_REG_PWM(x)     (0x02 + (x))
  29
  30#define TLC591XX_REG_GRPPWM     0x12
  31#define TLC591XX_REG_GRPFREQ    0x13
  32
  33/* LED Driver Output State, determine the source that drives LED outputs */
  34#define LEDOUT_OFF              0x0     /* Output LOW */
  35#define LEDOUT_ON               0x1     /* Output HI-Z */
  36#define LEDOUT_DIM              0x2     /* Dimming */
  37#define LEDOUT_BLINK            0x3     /* Blinking */
  38#define LEDOUT_MASK             0x3
  39
  40#define ldev_to_led(c)          container_of(c, struct tlc591xx_led, ldev)
  41
  42struct tlc591xx_led {
  43        bool active;
  44        unsigned int led_no;
  45        struct led_classdev ldev;
  46        struct tlc591xx_priv *priv;
  47};
  48
  49struct tlc591xx_priv {
  50        struct tlc591xx_led leds[TLC591XX_MAX_LEDS];
  51        struct regmap *regmap;
  52        unsigned int reg_ledout_offset;
  53};
  54
  55struct tlc591xx {
  56        unsigned int max_leds;
  57        unsigned int reg_ledout_offset;
  58};
  59
  60static const struct tlc591xx tlc59116 = {
  61        .max_leds = 16,
  62        .reg_ledout_offset = 0x14,
  63};
  64
  65static const struct tlc591xx tlc59108 = {
  66        .max_leds = 8,
  67        .reg_ledout_offset = 0x0c,
  68};
  69
  70static int
  71tlc591xx_set_mode(struct regmap *regmap, u8 mode)
  72{
  73        int err;
  74        u8 val;
  75
  76        err = regmap_write(regmap, TLC591XX_REG_MODE1, MODE1_NORMAL_MODE);
  77        if (err)
  78                return err;
  79
  80        val = MODE2_OCH_STOP | mode;
  81
  82        return regmap_write(regmap, TLC591XX_REG_MODE2, val);
  83}
  84
  85static int
  86tlc591xx_set_ledout(struct tlc591xx_priv *priv, struct tlc591xx_led *led,
  87                    u8 val)
  88{
  89        unsigned int i = (led->led_no % 4) * 2;
  90        unsigned int mask = LEDOUT_MASK << i;
  91        unsigned int addr = priv->reg_ledout_offset + (led->led_no >> 2);
  92
  93        val = val << i;
  94
  95        return regmap_update_bits(priv->regmap, addr, mask, val);
  96}
  97
  98static int
  99tlc591xx_set_pwm(struct tlc591xx_priv *priv, struct tlc591xx_led *led,
 100                 u8 brightness)
 101{
 102        u8 pwm = TLC591XX_REG_PWM(led->led_no);
 103
 104        return regmap_write(priv->regmap, pwm, brightness);
 105}
 106
 107static int
 108tlc591xx_brightness_set(struct led_classdev *led_cdev,
 109                        enum led_brightness brightness)
 110{
 111        struct tlc591xx_led *led = ldev_to_led(led_cdev);
 112        struct tlc591xx_priv *priv = led->priv;
 113        int err;
 114
 115        switch (brightness) {
 116        case 0:
 117                err = tlc591xx_set_ledout(priv, led, LEDOUT_OFF);
 118                break;
 119        case LED_FULL:
 120                err = tlc591xx_set_ledout(priv, led, LEDOUT_ON);
 121                break;
 122        default:
 123                err = tlc591xx_set_ledout(priv, led, LEDOUT_DIM);
 124                if (!err)
 125                        err = tlc591xx_set_pwm(priv, led, brightness);
 126        }
 127
 128        return err;
 129}
 130
 131static void
 132tlc591xx_destroy_devices(struct tlc591xx_priv *priv, unsigned int j)
 133{
 134        int i = j;
 135
 136        while (--i >= 0) {
 137                if (priv->leds[i].active)
 138                        led_classdev_unregister(&priv->leds[i].ldev);
 139        }
 140}
 141
 142static int
 143tlc591xx_configure(struct device *dev,
 144                   struct tlc591xx_priv *priv,
 145                   const struct tlc591xx *tlc591xx)
 146{
 147        unsigned int i;
 148        int err = 0;
 149
 150        tlc591xx_set_mode(priv->regmap, MODE2_DIM);
 151        for (i = 0; i < TLC591XX_MAX_LEDS; i++) {
 152                struct tlc591xx_led *led = &priv->leds[i];
 153
 154                if (!led->active)
 155                        continue;
 156
 157                led->priv = priv;
 158                led->led_no = i;
 159                led->ldev.brightness_set_blocking = tlc591xx_brightness_set;
 160                led->ldev.max_brightness = LED_FULL;
 161                err = led_classdev_register(dev, &led->ldev);
 162                if (err < 0) {
 163                        dev_err(dev, "couldn't register LED %s\n",
 164                                led->ldev.name);
 165                        goto exit;
 166                }
 167        }
 168
 169        return 0;
 170
 171exit:
 172        tlc591xx_destroy_devices(priv, i);
 173        return err;
 174}
 175
 176static const struct regmap_config tlc591xx_regmap = {
 177        .reg_bits = 8,
 178        .val_bits = 8,
 179        .max_register = 0x1e,
 180};
 181
 182static const struct of_device_id of_tlc591xx_leds_match[] = {
 183        { .compatible = "ti,tlc59116",
 184          .data = &tlc59116 },
 185        { .compatible = "ti,tlc59108",
 186          .data = &tlc59108 },
 187        {},
 188};
 189MODULE_DEVICE_TABLE(of, of_tlc591xx_leds_match);
 190
 191static int
 192tlc591xx_probe(struct i2c_client *client,
 193               const struct i2c_device_id *id)
 194{
 195        struct device_node *np = client->dev.of_node, *child;
 196        struct device *dev = &client->dev;
 197        const struct of_device_id *match;
 198        const struct tlc591xx *tlc591xx;
 199        struct tlc591xx_priv *priv;
 200        int err, count, reg;
 201
 202        match = of_match_device(of_tlc591xx_leds_match, dev);
 203        if (!match)
 204                return -ENODEV;
 205
 206        tlc591xx = match->data;
 207        if (!np)
 208                return -ENODEV;
 209
 210        count = of_get_child_count(np);
 211        if (!count || count > tlc591xx->max_leds)
 212                return -EINVAL;
 213
 214        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
 215        if (!priv)
 216                return -ENOMEM;
 217
 218        priv->regmap = devm_regmap_init_i2c(client, &tlc591xx_regmap);
 219        if (IS_ERR(priv->regmap)) {
 220                err = PTR_ERR(priv->regmap);
 221                dev_err(dev, "Failed to allocate register map: %d\n", err);
 222                return err;
 223        }
 224        priv->reg_ledout_offset = tlc591xx->reg_ledout_offset;
 225
 226        i2c_set_clientdata(client, priv);
 227
 228        for_each_child_of_node(np, child) {
 229                err = of_property_read_u32(child, "reg", &reg);
 230                if (err) {
 231                        of_node_put(child);
 232                        return err;
 233                }
 234                if (reg < 0 || reg >= tlc591xx->max_leds ||
 235                    priv->leds[reg].active) {
 236                        of_node_put(child);
 237                        return -EINVAL;
 238                }
 239                priv->leds[reg].active = true;
 240                priv->leds[reg].ldev.name =
 241                        of_get_property(child, "label", NULL) ? : child->name;
 242                priv->leds[reg].ldev.default_trigger =
 243                        of_get_property(child, "linux,default-trigger", NULL);
 244        }
 245        return tlc591xx_configure(dev, priv, tlc591xx);
 246}
 247
 248static int
 249tlc591xx_remove(struct i2c_client *client)
 250{
 251        struct tlc591xx_priv *priv = i2c_get_clientdata(client);
 252
 253        tlc591xx_destroy_devices(priv, TLC591XX_MAX_LEDS);
 254
 255        return 0;
 256}
 257
 258static const struct i2c_device_id tlc591xx_id[] = {
 259        { "tlc59116" },
 260        { "tlc59108" },
 261        {},
 262};
 263MODULE_DEVICE_TABLE(i2c, tlc591xx_id);
 264
 265static struct i2c_driver tlc591xx_driver = {
 266        .driver = {
 267                .name = "tlc591xx",
 268                .of_match_table = of_match_ptr(of_tlc591xx_leds_match),
 269        },
 270        .probe = tlc591xx_probe,
 271        .remove = tlc591xx_remove,
 272        .id_table = tlc591xx_id,
 273};
 274
 275module_i2c_driver(tlc591xx_driver);
 276
 277MODULE_AUTHOR("Andrew Lunn <andrew@lunn.ch>");
 278MODULE_LICENSE("GPL");
 279MODULE_DESCRIPTION("TLC591XX LED driver");
 280