root/drivers/leds/leds-tlc591xx.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. tlc591xx_set_mode
  2. tlc591xx_set_ledout
  3. tlc591xx_set_pwm
  4. tlc591xx_brightness_set
  5. tlc591xx_destroy_devices
  6. tlc591xx_configure
  7. tlc591xx_probe
  8. tlc591xx_remove

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

/* [<][>][^][v][top][bottom][index][help] */