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