root/drivers/leds/leds-is31fl32xx.c

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

DEFINITIONS

This source file includes following definitions.
  1. is31fl32xx_write
  2. is31fl3216_reset
  3. is31fl3216_software_shutdown
  4. is31fl32xx_brightness_set
  5. is31fl32xx_reset_regs
  6. is31fl32xx_software_shutdown
  7. is31fl32xx_init_regs
  8. is31fl32xx_parse_child_dt
  9. is31fl32xx_find_led_data
  10. is31fl32xx_parse_dt
  11. is31fl32xx_probe
  12. is31fl32xx_remove

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Driver for ISSI IS31FL32xx family of I2C LED controllers
   4  *
   5  * Copyright 2015 Allworx Corp.
   6  *
   7  * Datasheets:
   8  *   http://www.issi.com/US/product-analog-fxled-driver.shtml
   9  *   http://www.si-en.com/product.asp?parentid=890
  10  */
  11 
  12 #include <linux/device.h>
  13 #include <linux/i2c.h>
  14 #include <linux/kernel.h>
  15 #include <linux/leds.h>
  16 #include <linux/module.h>
  17 #include <linux/of.h>
  18 #include <linux/of_device.h>
  19 
  20 /* Used to indicate a device has no such register */
  21 #define IS31FL32XX_REG_NONE 0xFF
  22 
  23 /* Software Shutdown bit in Shutdown Register */
  24 #define IS31FL32XX_SHUTDOWN_SSD_ENABLE  0
  25 #define IS31FL32XX_SHUTDOWN_SSD_DISABLE BIT(0)
  26 
  27 /* IS31FL3216 has a number of unique registers */
  28 #define IS31FL3216_CONFIG_REG 0x00
  29 #define IS31FL3216_LIGHTING_EFFECT_REG 0x03
  30 #define IS31FL3216_CHANNEL_CONFIG_REG 0x04
  31 
  32 /* Software Shutdown bit in 3216 Config Register */
  33 #define IS31FL3216_CONFIG_SSD_ENABLE  BIT(7)
  34 #define IS31FL3216_CONFIG_SSD_DISABLE 0
  35 
  36 struct is31fl32xx_priv;
  37 struct is31fl32xx_led_data {
  38         struct led_classdev cdev;
  39         u8 channel; /* 1-based, max priv->cdef->channels */
  40         struct is31fl32xx_priv *priv;
  41 };
  42 
  43 struct is31fl32xx_priv {
  44         const struct is31fl32xx_chipdef *cdef;
  45         struct i2c_client *client;
  46         unsigned int num_leds;
  47         struct is31fl32xx_led_data leds[0];
  48 };
  49 
  50 /**
  51  * struct is31fl32xx_chipdef - chip-specific attributes
  52  * @channels            : Number of LED channels
  53  * @shutdown_reg        : address of Shutdown register (optional)
  54  * @pwm_update_reg      : address of PWM Update register
  55  * @global_control_reg  : address of Global Control register (optional)
  56  * @reset_reg           : address of Reset register (optional)
  57  * @pwm_register_base   : address of first PWM register
  58  * @pwm_registers_reversed: : true if PWM registers count down instead of up
  59  * @led_control_register_base : address of first LED control register (optional)
  60  * @enable_bits_per_led_control_register: number of LEDs enable bits in each
  61  * @reset_func:         : pointer to reset function
  62  *
  63  * For all optional register addresses, the sentinel value %IS31FL32XX_REG_NONE
  64  * indicates that this chip has no such register.
  65  *
  66  * If non-NULL, @reset_func will be called during probing to set all
  67  * necessary registers to a known initialization state. This is needed
  68  * for chips that do not have a @reset_reg.
  69  *
  70  * @enable_bits_per_led_control_register must be >=1 if
  71  * @led_control_register_base != %IS31FL32XX_REG_NONE.
  72  */
  73 struct is31fl32xx_chipdef {
  74         u8      channels;
  75         u8      shutdown_reg;
  76         u8      pwm_update_reg;
  77         u8      global_control_reg;
  78         u8      reset_reg;
  79         u8      pwm_register_base;
  80         bool    pwm_registers_reversed;
  81         u8      led_control_register_base;
  82         u8      enable_bits_per_led_control_register;
  83         int (*reset_func)(struct is31fl32xx_priv *priv);
  84         int (*sw_shutdown_func)(struct is31fl32xx_priv *priv, bool enable);
  85 };
  86 
  87 static const struct is31fl32xx_chipdef is31fl3236_cdef = {
  88         .channels                               = 36,
  89         .shutdown_reg                           = 0x00,
  90         .pwm_update_reg                         = 0x25,
  91         .global_control_reg                     = 0x4a,
  92         .reset_reg                              = 0x4f,
  93         .pwm_register_base                      = 0x01,
  94         .led_control_register_base              = 0x26,
  95         .enable_bits_per_led_control_register   = 1,
  96 };
  97 
  98 static const struct is31fl32xx_chipdef is31fl3235_cdef = {
  99         .channels                               = 28,
 100         .shutdown_reg                           = 0x00,
 101         .pwm_update_reg                         = 0x25,
 102         .global_control_reg                     = 0x4a,
 103         .reset_reg                              = 0x4f,
 104         .pwm_register_base                      = 0x05,
 105         .led_control_register_base              = 0x2a,
 106         .enable_bits_per_led_control_register   = 1,
 107 };
 108 
 109 static const struct is31fl32xx_chipdef is31fl3218_cdef = {
 110         .channels                               = 18,
 111         .shutdown_reg                           = 0x00,
 112         .pwm_update_reg                         = 0x16,
 113         .global_control_reg                     = IS31FL32XX_REG_NONE,
 114         .reset_reg                              = 0x17,
 115         .pwm_register_base                      = 0x01,
 116         .led_control_register_base              = 0x13,
 117         .enable_bits_per_led_control_register   = 6,
 118 };
 119 
 120 static int is31fl3216_reset(struct is31fl32xx_priv *priv);
 121 static int is31fl3216_software_shutdown(struct is31fl32xx_priv *priv,
 122                                         bool enable);
 123 static const struct is31fl32xx_chipdef is31fl3216_cdef = {
 124         .channels                               = 16,
 125         .shutdown_reg                           = IS31FL32XX_REG_NONE,
 126         .pwm_update_reg                         = 0xB0,
 127         .global_control_reg                     = IS31FL32XX_REG_NONE,
 128         .reset_reg                              = IS31FL32XX_REG_NONE,
 129         .pwm_register_base                      = 0x10,
 130         .pwm_registers_reversed                 = true,
 131         .led_control_register_base              = 0x01,
 132         .enable_bits_per_led_control_register   = 8,
 133         .reset_func                             = is31fl3216_reset,
 134         .sw_shutdown_func                       = is31fl3216_software_shutdown,
 135 };
 136 
 137 static int is31fl32xx_write(struct is31fl32xx_priv *priv, u8 reg, u8 val)
 138 {
 139         int ret;
 140 
 141         dev_dbg(&priv->client->dev, "writing register 0x%02X=0x%02X", reg, val);
 142 
 143         ret =  i2c_smbus_write_byte_data(priv->client, reg, val);
 144         if (ret) {
 145                 dev_err(&priv->client->dev,
 146                         "register write to 0x%02X failed (error %d)",
 147                         reg, ret);
 148         }
 149         return ret;
 150 }
 151 
 152 /*
 153  * Custom reset function for IS31FL3216 because it does not have a RESET
 154  * register the way that the other IS31FL32xx chips do. We don't bother
 155  * writing the GPIO and animation registers, because the registers we
 156  * do write ensure those will have no effect.
 157  */
 158 static int is31fl3216_reset(struct is31fl32xx_priv *priv)
 159 {
 160         unsigned int i;
 161         int ret;
 162 
 163         ret = is31fl32xx_write(priv, IS31FL3216_CONFIG_REG,
 164                                IS31FL3216_CONFIG_SSD_ENABLE);
 165         if (ret)
 166                 return ret;
 167         for (i = 0; i < priv->cdef->channels; i++) {
 168                 ret = is31fl32xx_write(priv, priv->cdef->pwm_register_base+i,
 169                                        0x00);
 170                 if (ret)
 171                         return ret;
 172         }
 173         ret = is31fl32xx_write(priv, priv->cdef->pwm_update_reg, 0);
 174         if (ret)
 175                 return ret;
 176         ret = is31fl32xx_write(priv, IS31FL3216_LIGHTING_EFFECT_REG, 0x00);
 177         if (ret)
 178                 return ret;
 179         ret = is31fl32xx_write(priv, IS31FL3216_CHANNEL_CONFIG_REG, 0x00);
 180         if (ret)
 181                 return ret;
 182 
 183         return 0;
 184 }
 185 
 186 /*
 187  * Custom Software-Shutdown function for IS31FL3216 because it does not have
 188  * a SHUTDOWN register the way that the other IS31FL32xx chips do.
 189  * We don't bother doing a read/modify/write on the CONFIG register because
 190  * we only ever use a value of '0' for the other fields in that register.
 191  */
 192 static int is31fl3216_software_shutdown(struct is31fl32xx_priv *priv,
 193                                         bool enable)
 194 {
 195         u8 value = enable ? IS31FL3216_CONFIG_SSD_ENABLE :
 196                             IS31FL3216_CONFIG_SSD_DISABLE;
 197 
 198         return is31fl32xx_write(priv, IS31FL3216_CONFIG_REG, value);
 199 }
 200 
 201 /*
 202  * NOTE: A mutex is not needed in this function because:
 203  * - All referenced data is read-only after probe()
 204  * - The I2C core has a mutex on to protect the bus
 205  * - There are no read/modify/write operations
 206  * - Intervening operations between the write of the PWM register
 207  *   and the Update register are harmless.
 208  *
 209  * Example:
 210  *      PWM_REG_1 write 16
 211  *      UPDATE_REG write 0
 212  *      PWM_REG_2 write 128
 213  *      UPDATE_REG write 0
 214  *   vs:
 215  *      PWM_REG_1 write 16
 216  *      PWM_REG_2 write 128
 217  *      UPDATE_REG write 0
 218  *      UPDATE_REG write 0
 219  * are equivalent. Poking the Update register merely applies all PWM
 220  * register writes up to that point.
 221  */
 222 static int is31fl32xx_brightness_set(struct led_classdev *led_cdev,
 223                                      enum led_brightness brightness)
 224 {
 225         const struct is31fl32xx_led_data *led_data =
 226                 container_of(led_cdev, struct is31fl32xx_led_data, cdev);
 227         const struct is31fl32xx_chipdef *cdef = led_data->priv->cdef;
 228         u8 pwm_register_offset;
 229         int ret;
 230 
 231         dev_dbg(led_cdev->dev, "%s: %d\n", __func__, brightness);
 232 
 233         /* NOTE: led_data->channel is 1-based */
 234         if (cdef->pwm_registers_reversed)
 235                 pwm_register_offset = cdef->channels - led_data->channel;
 236         else
 237                 pwm_register_offset = led_data->channel - 1;
 238 
 239         ret = is31fl32xx_write(led_data->priv,
 240                                cdef->pwm_register_base + pwm_register_offset,
 241                                brightness);
 242         if (ret)
 243                 return ret;
 244 
 245         return is31fl32xx_write(led_data->priv, cdef->pwm_update_reg, 0);
 246 }
 247 
 248 static int is31fl32xx_reset_regs(struct is31fl32xx_priv *priv)
 249 {
 250         const struct is31fl32xx_chipdef *cdef = priv->cdef;
 251         int ret;
 252 
 253         if (cdef->reset_reg != IS31FL32XX_REG_NONE) {
 254                 ret = is31fl32xx_write(priv, cdef->reset_reg, 0);
 255                 if (ret)
 256                         return ret;
 257         }
 258 
 259         if (cdef->reset_func)
 260                 return cdef->reset_func(priv);
 261 
 262         return 0;
 263 }
 264 
 265 static int is31fl32xx_software_shutdown(struct is31fl32xx_priv *priv,
 266                                         bool enable)
 267 {
 268         const struct is31fl32xx_chipdef *cdef = priv->cdef;
 269         int ret;
 270 
 271         if (cdef->shutdown_reg != IS31FL32XX_REG_NONE) {
 272                 u8 value = enable ? IS31FL32XX_SHUTDOWN_SSD_ENABLE :
 273                                     IS31FL32XX_SHUTDOWN_SSD_DISABLE;
 274                 ret = is31fl32xx_write(priv, cdef->shutdown_reg, value);
 275                 if (ret)
 276                         return ret;
 277         }
 278 
 279         if (cdef->sw_shutdown_func)
 280                 return cdef->sw_shutdown_func(priv, enable);
 281 
 282         return 0;
 283 }
 284 
 285 static int is31fl32xx_init_regs(struct is31fl32xx_priv *priv)
 286 {
 287         const struct is31fl32xx_chipdef *cdef = priv->cdef;
 288         int ret;
 289 
 290         ret = is31fl32xx_reset_regs(priv);
 291         if (ret)
 292                 return ret;
 293 
 294         /*
 295          * Set enable bit for all channels.
 296          * We will control state with PWM registers alone.
 297          */
 298         if (cdef->led_control_register_base != IS31FL32XX_REG_NONE) {
 299                 u8 value =
 300                     GENMASK(cdef->enable_bits_per_led_control_register-1, 0);
 301                 u8 num_regs = cdef->channels /
 302                                 cdef->enable_bits_per_led_control_register;
 303                 int i;
 304 
 305                 for (i = 0; i < num_regs; i++) {
 306                         ret = is31fl32xx_write(priv,
 307                                                cdef->led_control_register_base+i,
 308                                                value);
 309                         if (ret)
 310                                 return ret;
 311                 }
 312         }
 313 
 314         ret = is31fl32xx_software_shutdown(priv, false);
 315         if (ret)
 316                 return ret;
 317 
 318         if (cdef->global_control_reg != IS31FL32XX_REG_NONE) {
 319                 ret = is31fl32xx_write(priv, cdef->global_control_reg, 0x00);
 320                 if (ret)
 321                         return ret;
 322         }
 323 
 324         return 0;
 325 }
 326 
 327 static int is31fl32xx_parse_child_dt(const struct device *dev,
 328                                      const struct device_node *child,
 329                                      struct is31fl32xx_led_data *led_data)
 330 {
 331         struct led_classdev *cdev = &led_data->cdev;
 332         int ret = 0;
 333         u32 reg;
 334 
 335         if (of_property_read_string(child, "label", &cdev->name))
 336                 cdev->name = child->name;
 337 
 338         ret = of_property_read_u32(child, "reg", &reg);
 339         if (ret || reg < 1 || reg > led_data->priv->cdef->channels) {
 340                 dev_err(dev,
 341                         "Child node %pOF does not have a valid reg property\n",
 342                         child);
 343                 return -EINVAL;
 344         }
 345         led_data->channel = reg;
 346 
 347         of_property_read_string(child, "linux,default-trigger",
 348                                 &cdev->default_trigger);
 349 
 350         cdev->brightness_set_blocking = is31fl32xx_brightness_set;
 351 
 352         return 0;
 353 }
 354 
 355 static struct is31fl32xx_led_data *is31fl32xx_find_led_data(
 356                                         struct is31fl32xx_priv *priv,
 357                                         u8 channel)
 358 {
 359         size_t i;
 360 
 361         for (i = 0; i < priv->num_leds; i++) {
 362                 if (priv->leds[i].channel == channel)
 363                         return &priv->leds[i];
 364         }
 365 
 366         return NULL;
 367 }
 368 
 369 static int is31fl32xx_parse_dt(struct device *dev,
 370                                struct is31fl32xx_priv *priv)
 371 {
 372         struct device_node *child;
 373         int ret = 0;
 374 
 375         for_each_child_of_node(dev->of_node, child) {
 376                 struct is31fl32xx_led_data *led_data =
 377                         &priv->leds[priv->num_leds];
 378                 const struct is31fl32xx_led_data *other_led_data;
 379 
 380                 led_data->priv = priv;
 381 
 382                 ret = is31fl32xx_parse_child_dt(dev, child, led_data);
 383                 if (ret)
 384                         goto err;
 385 
 386                 /* Detect if channel is already in use by another child */
 387                 other_led_data = is31fl32xx_find_led_data(priv,
 388                                                           led_data->channel);
 389                 if (other_led_data) {
 390                         dev_err(dev,
 391                                 "%s and %s both attempting to use channel %d\n",
 392                                 led_data->cdev.name,
 393                                 other_led_data->cdev.name,
 394                                 led_data->channel);
 395                         goto err;
 396                 }
 397 
 398                 ret = devm_led_classdev_register(dev, &led_data->cdev);
 399                 if (ret) {
 400                         dev_err(dev, "failed to register PWM led for %s: %d\n",
 401                                 led_data->cdev.name, ret);
 402                         goto err;
 403                 }
 404 
 405                 priv->num_leds++;
 406         }
 407 
 408         return 0;
 409 
 410 err:
 411         of_node_put(child);
 412         return ret;
 413 }
 414 
 415 static const struct of_device_id of_is31fl32xx_match[] = {
 416         { .compatible = "issi,is31fl3236", .data = &is31fl3236_cdef, },
 417         { .compatible = "issi,is31fl3235", .data = &is31fl3235_cdef, },
 418         { .compatible = "issi,is31fl3218", .data = &is31fl3218_cdef, },
 419         { .compatible = "si-en,sn3218",    .data = &is31fl3218_cdef, },
 420         { .compatible = "issi,is31fl3216", .data = &is31fl3216_cdef, },
 421         { .compatible = "si-en,sn3216",    .data = &is31fl3216_cdef, },
 422         {},
 423 };
 424 
 425 MODULE_DEVICE_TABLE(of, of_is31fl32xx_match);
 426 
 427 static int is31fl32xx_probe(struct i2c_client *client,
 428                             const struct i2c_device_id *id)
 429 {
 430         const struct is31fl32xx_chipdef *cdef;
 431         const struct of_device_id *of_dev_id;
 432         struct device *dev = &client->dev;
 433         struct is31fl32xx_priv *priv;
 434         int count;
 435         int ret = 0;
 436 
 437         of_dev_id = of_match_device(of_is31fl32xx_match, dev);
 438         if (!of_dev_id)
 439                 return -EINVAL;
 440 
 441         cdef = of_dev_id->data;
 442 
 443         count = of_get_child_count(dev->of_node);
 444         if (!count)
 445                 return -EINVAL;
 446 
 447         priv = devm_kzalloc(dev, struct_size(priv, leds, count),
 448                             GFP_KERNEL);
 449         if (!priv)
 450                 return -ENOMEM;
 451 
 452         priv->client = client;
 453         priv->cdef = cdef;
 454         i2c_set_clientdata(client, priv);
 455 
 456         ret = is31fl32xx_init_regs(priv);
 457         if (ret)
 458                 return ret;
 459 
 460         ret = is31fl32xx_parse_dt(dev, priv);
 461         if (ret)
 462                 return ret;
 463 
 464         return 0;
 465 }
 466 
 467 static int is31fl32xx_remove(struct i2c_client *client)
 468 {
 469         struct is31fl32xx_priv *priv = i2c_get_clientdata(client);
 470 
 471         return is31fl32xx_reset_regs(priv);
 472 }
 473 
 474 /*
 475  * i2c-core (and modalias) requires that id_table be properly filled,
 476  * even though it is not used for DeviceTree based instantiation.
 477  */
 478 static const struct i2c_device_id is31fl32xx_id[] = {
 479         { "is31fl3236" },
 480         { "is31fl3235" },
 481         { "is31fl3218" },
 482         { "sn3218" },
 483         { "is31fl3216" },
 484         { "sn3216" },
 485         {},
 486 };
 487 
 488 MODULE_DEVICE_TABLE(i2c, is31fl32xx_id);
 489 
 490 static struct i2c_driver is31fl32xx_driver = {
 491         .driver = {
 492                 .name   = "is31fl32xx",
 493                 .of_match_table = of_is31fl32xx_match,
 494         },
 495         .probe          = is31fl32xx_probe,
 496         .remove         = is31fl32xx_remove,
 497         .id_table       = is31fl32xx_id,
 498 };
 499 
 500 module_i2c_driver(is31fl32xx_driver);
 501 
 502 MODULE_AUTHOR("David Rivshin <drivshin@allworx.com>");
 503 MODULE_DESCRIPTION("ISSI IS31FL32xx LED driver");
 504 MODULE_LICENSE("GPL v2");

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