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[]; 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", ®); 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(dev), 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 struct device *dev = &client->dev; 432 struct is31fl32xx_priv *priv; 433 int count; 434 int ret = 0; 435 436 cdef = device_get_match_data(dev); 437 438 count = of_get_child_count(dev_of_node(dev)); 439 if (!count) 440 return -EINVAL; 441 442 priv = devm_kzalloc(dev, struct_size(priv, leds, count), 443 GFP_KERNEL); 444 if (!priv) 445 return -ENOMEM; 446 447 priv->client = client; 448 priv->cdef = cdef; 449 i2c_set_clientdata(client, priv); 450 451 ret = is31fl32xx_init_regs(priv); 452 if (ret) 453 return ret; 454 455 ret = is31fl32xx_parse_dt(dev, priv); 456 if (ret) 457 return ret; 458 459 return 0; 460 } 461 462 static int is31fl32xx_remove(struct i2c_client *client) 463 { 464 struct is31fl32xx_priv *priv = i2c_get_clientdata(client); 465 466 return is31fl32xx_reset_regs(priv); 467 } 468 469 /* 470 * i2c-core (and modalias) requires that id_table be properly filled, 471 * even though it is not used for DeviceTree based instantiation. 472 */ 473 static const struct i2c_device_id is31fl32xx_id[] = { 474 { "is31fl3236" }, 475 { "is31fl3235" }, 476 { "is31fl3218" }, 477 { "sn3218" }, 478 { "is31fl3216" }, 479 { "sn3216" }, 480 {}, 481 }; 482 483 MODULE_DEVICE_TABLE(i2c, is31fl32xx_id); 484 485 static struct i2c_driver is31fl32xx_driver = { 486 .driver = { 487 .name = "is31fl32xx", 488 .of_match_table = of_is31fl32xx_match, 489 }, 490 .probe = is31fl32xx_probe, 491 .remove = is31fl32xx_remove, 492 .id_table = is31fl32xx_id, 493 }; 494 495 module_i2c_driver(is31fl32xx_driver); 496 497 MODULE_AUTHOR("David Rivshin <drivshin@allworx.com>"); 498 MODULE_DESCRIPTION("ISSI IS31FL32xx LED driver"); 499 MODULE_LICENSE("GPL v2"); 500