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