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