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