linux/drivers/leds/leds-is31fl32xx.c
<<
>>
Prefs
   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
  36struct is31fl32xx_priv;
  37struct is31fl32xx_led_data {
  38        struct led_classdev cdev;
  39        u8 channel; /* 1-based, max priv->cdef->channels */
  40        struct is31fl32xx_priv *priv;
  41};
  42
  43struct is31fl32xx_priv {
  44        const struct is31fl32xx_chipdef *cdef;
  45        struct i2c_client *client;
  46        unsigned int num_leds;
  47        struct is31fl32xx_led_data leds[];
  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 */
  73struct 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
  87static 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
  98static 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
 109static 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
 120static int is31fl3216_reset(struct is31fl32xx_priv *priv);
 121static int is31fl3216_software_shutdown(struct is31fl32xx_priv *priv,
 122                                        bool enable);
 123static 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
 137static 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 */
 158static 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 */
 192static 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 */
 222static 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
 248static 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
 265static 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
 285static 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
 327static 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        ret = of_property_read_u32(child, "reg", &reg);
 336        if (ret || reg < 1 || reg > led_data->priv->cdef->channels) {
 337                dev_err(dev,
 338                        "Child node %pOF does not have a valid reg property\n",
 339                        child);
 340                return -EINVAL;
 341        }
 342        led_data->channel = reg;
 343
 344        cdev->brightness_set_blocking = is31fl32xx_brightness_set;
 345
 346        return 0;
 347}
 348
 349static struct is31fl32xx_led_data *is31fl32xx_find_led_data(
 350                                        struct is31fl32xx_priv *priv,
 351                                        u8 channel)
 352{
 353        size_t i;
 354
 355        for (i = 0; i < priv->num_leds; i++) {
 356                if (priv->leds[i].channel == channel)
 357                        return &priv->leds[i];
 358        }
 359
 360        return NULL;
 361}
 362
 363static int is31fl32xx_parse_dt(struct device *dev,
 364                               struct is31fl32xx_priv *priv)
 365{
 366        struct device_node *child;
 367        int ret = 0;
 368
 369        for_each_available_child_of_node(dev_of_node(dev), child) {
 370                struct led_init_data init_data = {};
 371                struct is31fl32xx_led_data *led_data =
 372                        &priv->leds[priv->num_leds];
 373                const struct is31fl32xx_led_data *other_led_data;
 374
 375                led_data->priv = priv;
 376
 377                ret = is31fl32xx_parse_child_dt(dev, child, led_data);
 378                if (ret)
 379                        goto err;
 380
 381                /* Detect if channel is already in use by another child */
 382                other_led_data = is31fl32xx_find_led_data(priv,
 383                                                          led_data->channel);
 384                if (other_led_data) {
 385                        dev_err(dev,
 386                                "Node %pOF 'reg' conflicts with another LED\n",
 387                                child);
 388                        goto err;
 389                }
 390
 391                init_data.fwnode = of_fwnode_handle(child);
 392
 393                ret = devm_led_classdev_register_ext(dev, &led_data->cdev,
 394                                                     &init_data);
 395                if (ret) {
 396                        dev_err(dev, "Failed to register LED for %pOF: %d\n",
 397                                child, ret);
 398                        goto err;
 399                }
 400
 401                priv->num_leds++;
 402        }
 403
 404        return 0;
 405
 406err:
 407        of_node_put(child);
 408        return ret;
 409}
 410
 411static const struct of_device_id of_is31fl32xx_match[] = {
 412        { .compatible = "issi,is31fl3236", .data = &is31fl3236_cdef, },
 413        { .compatible = "issi,is31fl3235", .data = &is31fl3235_cdef, },
 414        { .compatible = "issi,is31fl3218", .data = &is31fl3218_cdef, },
 415        { .compatible = "si-en,sn3218",    .data = &is31fl3218_cdef, },
 416        { .compatible = "issi,is31fl3216", .data = &is31fl3216_cdef, },
 417        { .compatible = "si-en,sn3216",    .data = &is31fl3216_cdef, },
 418        {},
 419};
 420
 421MODULE_DEVICE_TABLE(of, of_is31fl32xx_match);
 422
 423static int is31fl32xx_probe(struct i2c_client *client,
 424                            const struct i2c_device_id *id)
 425{
 426        const struct is31fl32xx_chipdef *cdef;
 427        struct device *dev = &client->dev;
 428        struct is31fl32xx_priv *priv;
 429        int count;
 430        int ret = 0;
 431
 432        cdef = device_get_match_data(dev);
 433
 434        count = of_get_available_child_count(dev_of_node(dev));
 435        if (!count)
 436                return -EINVAL;
 437
 438        priv = devm_kzalloc(dev, struct_size(priv, leds, count),
 439                            GFP_KERNEL);
 440        if (!priv)
 441                return -ENOMEM;
 442
 443        priv->client = client;
 444        priv->cdef = cdef;
 445        i2c_set_clientdata(client, priv);
 446
 447        ret = is31fl32xx_init_regs(priv);
 448        if (ret)
 449                return ret;
 450
 451        ret = is31fl32xx_parse_dt(dev, priv);
 452        if (ret)
 453                return ret;
 454
 455        return 0;
 456}
 457
 458static int is31fl32xx_remove(struct i2c_client *client)
 459{
 460        struct is31fl32xx_priv *priv = i2c_get_clientdata(client);
 461
 462        return is31fl32xx_reset_regs(priv);
 463}
 464
 465/*
 466 * i2c-core (and modalias) requires that id_table be properly filled,
 467 * even though it is not used for DeviceTree based instantiation.
 468 */
 469static const struct i2c_device_id is31fl32xx_id[] = {
 470        { "is31fl3236" },
 471        { "is31fl3235" },
 472        { "is31fl3218" },
 473        { "sn3218" },
 474        { "is31fl3216" },
 475        { "sn3216" },
 476        {},
 477};
 478
 479MODULE_DEVICE_TABLE(i2c, is31fl32xx_id);
 480
 481static struct i2c_driver is31fl32xx_driver = {
 482        .driver = {
 483                .name   = "is31fl32xx",
 484                .of_match_table = of_is31fl32xx_match,
 485        },
 486        .probe          = is31fl32xx_probe,
 487        .remove         = is31fl32xx_remove,
 488        .id_table       = is31fl32xx_id,
 489};
 490
 491module_i2c_driver(is31fl32xx_driver);
 492
 493MODULE_AUTHOR("David Rivshin <drivshin@allworx.com>");
 494MODULE_DESCRIPTION("ISSI IS31FL32xx LED driver");
 495MODULE_LICENSE("GPL v2");
 496