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 19 /* Used to indicate a device has no such register */ 20 #define IS31FL32XX_REG_NONE 0xFF 21 22 /* Software Shutdown bit in Shutdown Register */ 23 #define IS31FL32XX_SHUTDOWN_SSD_ENABLE 0 24 #define IS31FL32XX_SHUTDOWN_SSD_DISABLE BIT(0) 25 26 /* IS31FL3216 has a number of unique registers */ 27 #define IS31FL3216_CONFIG_REG 0x00 28 #define IS31FL3216_LIGHTING_EFFECT_REG 0x03 29 #define IS31FL3216_CHANNEL_CONFIG_REG 0x04 30 31 /* Software Shutdown bit in 3216 Config Register */ 32 #define IS31FL3216_CONFIG_SSD_ENABLE BIT(7) 33 #define IS31FL3216_CONFIG_SSD_DISABLE 0 34 35 struct is31fl32xx_priv; 36 struct is31fl32xx_led_data { 37 struct led_classdev cdev; 38 u8 channel; /* 1-based, max priv->cdef->channels */ 39 struct is31fl32xx_priv *priv; 40 }; 41 42 struct is31fl32xx_priv { 43 const struct is31fl32xx_chipdef *cdef; 44 struct i2c_client *client; 45 unsigned int num_leds; 46 struct is31fl32xx_led_data leds[]; 47 }; 48 49 /** 50 * struct is31fl32xx_chipdef - chip-specific attributes 51 * @channels : Number of LED channels 52 * @shutdown_reg : address of Shutdown register (optional) 53 * @pwm_update_reg : address of PWM Update register 54 * @global_control_reg : address of Global Control register (optional) 55 * @reset_reg : address of Reset register (optional) 56 * @pwm_register_base : address of first PWM register 57 * @pwm_registers_reversed: : true if PWM registers count down instead of up 58 * @led_control_register_base : address of first LED control register (optional) 59 * @enable_bits_per_led_control_register: number of LEDs enable bits in each 60 * @reset_func : pointer to reset function 61 * @sw_shutdown_func : pointer to software shutdown 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 ret = of_property_read_u32(child, "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 349 static 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 363 static 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 ret = -EINVAL; 389 goto err; 390 } 391 392 init_data.fwnode = of_fwnode_handle(child); 393 394 ret = devm_led_classdev_register_ext(dev, &led_data->cdev, 395 &init_data); 396 if (ret) { 397 dev_err(dev, "Failed to register LED for %pOF: %d\n", 398 child, ret); 399 goto err; 400 } 401 402 priv->num_leds++; 403 } 404 405 return 0; 406 407 err: 408 of_node_put(child); 409 return ret; 410 } 411 412 static const struct of_device_id of_is31fl32xx_match[] = { 413 { .compatible = "issi,is31fl3236", .data = &is31fl3236_cdef, }, 414 { .compatible = "issi,is31fl3235", .data = &is31fl3235_cdef, }, 415 { .compatible = "issi,is31fl3218", .data = &is31fl3218_cdef, }, 416 { .compatible = "si-en,sn3218", .data = &is31fl3218_cdef, }, 417 { .compatible = "issi,is31fl3216", .data = &is31fl3216_cdef, }, 418 { .compatible = "si-en,sn3216", .data = &is31fl3216_cdef, }, 419 {}, 420 }; 421 422 MODULE_DEVICE_TABLE(of, of_is31fl32xx_match); 423 424 static int is31fl32xx_probe(struct i2c_client *client) 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 458 static void is31fl32xx_remove(struct i2c_client *client) 459 { 460 struct is31fl32xx_priv *priv = i2c_get_clientdata(client); 461 int ret; 462 463 ret = is31fl32xx_reset_regs(priv); 464 if (ret) 465 dev_err(&client->dev, "Failed to reset registers on removal (%pe)\n", 466 ERR_PTR(ret)); 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