0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/device.h>
0013 #include <linux/i2c.h>
0014 #include <linux/kernel.h>
0015 #include <linux/leds.h>
0016 #include <linux/module.h>
0017 #include <linux/of.h>
0018 #include <linux/of_device.h>
0019
0020
0021 #define IS31FL32XX_REG_NONE 0xFF
0022
0023
0024 #define IS31FL32XX_SHUTDOWN_SSD_ENABLE 0
0025 #define IS31FL32XX_SHUTDOWN_SSD_DISABLE BIT(0)
0026
0027
0028 #define IS31FL3216_CONFIG_REG 0x00
0029 #define IS31FL3216_LIGHTING_EFFECT_REG 0x03
0030 #define IS31FL3216_CHANNEL_CONFIG_REG 0x04
0031
0032
0033 #define IS31FL3216_CONFIG_SSD_ENABLE BIT(7)
0034 #define IS31FL3216_CONFIG_SSD_DISABLE 0
0035
0036 struct is31fl32xx_priv;
0037 struct is31fl32xx_led_data {
0038 struct led_classdev cdev;
0039 u8 channel;
0040 struct is31fl32xx_priv *priv;
0041 };
0042
0043 struct is31fl32xx_priv {
0044 const struct is31fl32xx_chipdef *cdef;
0045 struct i2c_client *client;
0046 unsigned int num_leds;
0047 struct is31fl32xx_led_data leds[];
0048 };
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074 struct is31fl32xx_chipdef {
0075 u8 channels;
0076 u8 shutdown_reg;
0077 u8 pwm_update_reg;
0078 u8 global_control_reg;
0079 u8 reset_reg;
0080 u8 pwm_register_base;
0081 bool pwm_registers_reversed;
0082 u8 led_control_register_base;
0083 u8 enable_bits_per_led_control_register;
0084 int (*reset_func)(struct is31fl32xx_priv *priv);
0085 int (*sw_shutdown_func)(struct is31fl32xx_priv *priv, bool enable);
0086 };
0087
0088 static const struct is31fl32xx_chipdef is31fl3236_cdef = {
0089 .channels = 36,
0090 .shutdown_reg = 0x00,
0091 .pwm_update_reg = 0x25,
0092 .global_control_reg = 0x4a,
0093 .reset_reg = 0x4f,
0094 .pwm_register_base = 0x01,
0095 .led_control_register_base = 0x26,
0096 .enable_bits_per_led_control_register = 1,
0097 };
0098
0099 static const struct is31fl32xx_chipdef is31fl3235_cdef = {
0100 .channels = 28,
0101 .shutdown_reg = 0x00,
0102 .pwm_update_reg = 0x25,
0103 .global_control_reg = 0x4a,
0104 .reset_reg = 0x4f,
0105 .pwm_register_base = 0x05,
0106 .led_control_register_base = 0x2a,
0107 .enable_bits_per_led_control_register = 1,
0108 };
0109
0110 static const struct is31fl32xx_chipdef is31fl3218_cdef = {
0111 .channels = 18,
0112 .shutdown_reg = 0x00,
0113 .pwm_update_reg = 0x16,
0114 .global_control_reg = IS31FL32XX_REG_NONE,
0115 .reset_reg = 0x17,
0116 .pwm_register_base = 0x01,
0117 .led_control_register_base = 0x13,
0118 .enable_bits_per_led_control_register = 6,
0119 };
0120
0121 static int is31fl3216_reset(struct is31fl32xx_priv *priv);
0122 static int is31fl3216_software_shutdown(struct is31fl32xx_priv *priv,
0123 bool enable);
0124 static const struct is31fl32xx_chipdef is31fl3216_cdef = {
0125 .channels = 16,
0126 .shutdown_reg = IS31FL32XX_REG_NONE,
0127 .pwm_update_reg = 0xB0,
0128 .global_control_reg = IS31FL32XX_REG_NONE,
0129 .reset_reg = IS31FL32XX_REG_NONE,
0130 .pwm_register_base = 0x10,
0131 .pwm_registers_reversed = true,
0132 .led_control_register_base = 0x01,
0133 .enable_bits_per_led_control_register = 8,
0134 .reset_func = is31fl3216_reset,
0135 .sw_shutdown_func = is31fl3216_software_shutdown,
0136 };
0137
0138 static int is31fl32xx_write(struct is31fl32xx_priv *priv, u8 reg, u8 val)
0139 {
0140 int ret;
0141
0142 dev_dbg(&priv->client->dev, "writing register 0x%02X=0x%02X", reg, val);
0143
0144 ret = i2c_smbus_write_byte_data(priv->client, reg, val);
0145 if (ret) {
0146 dev_err(&priv->client->dev,
0147 "register write to 0x%02X failed (error %d)",
0148 reg, ret);
0149 }
0150 return ret;
0151 }
0152
0153
0154
0155
0156
0157
0158
0159 static int is31fl3216_reset(struct is31fl32xx_priv *priv)
0160 {
0161 unsigned int i;
0162 int ret;
0163
0164 ret = is31fl32xx_write(priv, IS31FL3216_CONFIG_REG,
0165 IS31FL3216_CONFIG_SSD_ENABLE);
0166 if (ret)
0167 return ret;
0168 for (i = 0; i < priv->cdef->channels; i++) {
0169 ret = is31fl32xx_write(priv, priv->cdef->pwm_register_base+i,
0170 0x00);
0171 if (ret)
0172 return ret;
0173 }
0174 ret = is31fl32xx_write(priv, priv->cdef->pwm_update_reg, 0);
0175 if (ret)
0176 return ret;
0177 ret = is31fl32xx_write(priv, IS31FL3216_LIGHTING_EFFECT_REG, 0x00);
0178 if (ret)
0179 return ret;
0180 ret = is31fl32xx_write(priv, IS31FL3216_CHANNEL_CONFIG_REG, 0x00);
0181 if (ret)
0182 return ret;
0183
0184 return 0;
0185 }
0186
0187
0188
0189
0190
0191
0192
0193 static int is31fl3216_software_shutdown(struct is31fl32xx_priv *priv,
0194 bool enable)
0195 {
0196 u8 value = enable ? IS31FL3216_CONFIG_SSD_ENABLE :
0197 IS31FL3216_CONFIG_SSD_DISABLE;
0198
0199 return is31fl32xx_write(priv, IS31FL3216_CONFIG_REG, value);
0200 }
0201
0202
0203
0204
0205
0206
0207
0208
0209
0210
0211
0212
0213
0214
0215
0216
0217
0218
0219
0220
0221
0222
0223 static int is31fl32xx_brightness_set(struct led_classdev *led_cdev,
0224 enum led_brightness brightness)
0225 {
0226 const struct is31fl32xx_led_data *led_data =
0227 container_of(led_cdev, struct is31fl32xx_led_data, cdev);
0228 const struct is31fl32xx_chipdef *cdef = led_data->priv->cdef;
0229 u8 pwm_register_offset;
0230 int ret;
0231
0232 dev_dbg(led_cdev->dev, "%s: %d\n", __func__, brightness);
0233
0234
0235 if (cdef->pwm_registers_reversed)
0236 pwm_register_offset = cdef->channels - led_data->channel;
0237 else
0238 pwm_register_offset = led_data->channel - 1;
0239
0240 ret = is31fl32xx_write(led_data->priv,
0241 cdef->pwm_register_base + pwm_register_offset,
0242 brightness);
0243 if (ret)
0244 return ret;
0245
0246 return is31fl32xx_write(led_data->priv, cdef->pwm_update_reg, 0);
0247 }
0248
0249 static int is31fl32xx_reset_regs(struct is31fl32xx_priv *priv)
0250 {
0251 const struct is31fl32xx_chipdef *cdef = priv->cdef;
0252 int ret;
0253
0254 if (cdef->reset_reg != IS31FL32XX_REG_NONE) {
0255 ret = is31fl32xx_write(priv, cdef->reset_reg, 0);
0256 if (ret)
0257 return ret;
0258 }
0259
0260 if (cdef->reset_func)
0261 return cdef->reset_func(priv);
0262
0263 return 0;
0264 }
0265
0266 static int is31fl32xx_software_shutdown(struct is31fl32xx_priv *priv,
0267 bool enable)
0268 {
0269 const struct is31fl32xx_chipdef *cdef = priv->cdef;
0270 int ret;
0271
0272 if (cdef->shutdown_reg != IS31FL32XX_REG_NONE) {
0273 u8 value = enable ? IS31FL32XX_SHUTDOWN_SSD_ENABLE :
0274 IS31FL32XX_SHUTDOWN_SSD_DISABLE;
0275 ret = is31fl32xx_write(priv, cdef->shutdown_reg, value);
0276 if (ret)
0277 return ret;
0278 }
0279
0280 if (cdef->sw_shutdown_func)
0281 return cdef->sw_shutdown_func(priv, enable);
0282
0283 return 0;
0284 }
0285
0286 static int is31fl32xx_init_regs(struct is31fl32xx_priv *priv)
0287 {
0288 const struct is31fl32xx_chipdef *cdef = priv->cdef;
0289 int ret;
0290
0291 ret = is31fl32xx_reset_regs(priv);
0292 if (ret)
0293 return ret;
0294
0295
0296
0297
0298
0299 if (cdef->led_control_register_base != IS31FL32XX_REG_NONE) {
0300 u8 value =
0301 GENMASK(cdef->enable_bits_per_led_control_register-1, 0);
0302 u8 num_regs = cdef->channels /
0303 cdef->enable_bits_per_led_control_register;
0304 int i;
0305
0306 for (i = 0; i < num_regs; i++) {
0307 ret = is31fl32xx_write(priv,
0308 cdef->led_control_register_base+i,
0309 value);
0310 if (ret)
0311 return ret;
0312 }
0313 }
0314
0315 ret = is31fl32xx_software_shutdown(priv, false);
0316 if (ret)
0317 return ret;
0318
0319 if (cdef->global_control_reg != IS31FL32XX_REG_NONE) {
0320 ret = is31fl32xx_write(priv, cdef->global_control_reg, 0x00);
0321 if (ret)
0322 return ret;
0323 }
0324
0325 return 0;
0326 }
0327
0328 static int is31fl32xx_parse_child_dt(const struct device *dev,
0329 const struct device_node *child,
0330 struct is31fl32xx_led_data *led_data)
0331 {
0332 struct led_classdev *cdev = &led_data->cdev;
0333 int ret = 0;
0334 u32 reg;
0335
0336 ret = of_property_read_u32(child, "reg", ®);
0337 if (ret || reg < 1 || reg > led_data->priv->cdef->channels) {
0338 dev_err(dev,
0339 "Child node %pOF does not have a valid reg property\n",
0340 child);
0341 return -EINVAL;
0342 }
0343 led_data->channel = reg;
0344
0345 cdev->brightness_set_blocking = is31fl32xx_brightness_set;
0346
0347 return 0;
0348 }
0349
0350 static struct is31fl32xx_led_data *is31fl32xx_find_led_data(
0351 struct is31fl32xx_priv *priv,
0352 u8 channel)
0353 {
0354 size_t i;
0355
0356 for (i = 0; i < priv->num_leds; i++) {
0357 if (priv->leds[i].channel == channel)
0358 return &priv->leds[i];
0359 }
0360
0361 return NULL;
0362 }
0363
0364 static int is31fl32xx_parse_dt(struct device *dev,
0365 struct is31fl32xx_priv *priv)
0366 {
0367 struct device_node *child;
0368 int ret = 0;
0369
0370 for_each_available_child_of_node(dev_of_node(dev), child) {
0371 struct led_init_data init_data = {};
0372 struct is31fl32xx_led_data *led_data =
0373 &priv->leds[priv->num_leds];
0374 const struct is31fl32xx_led_data *other_led_data;
0375
0376 led_data->priv = priv;
0377
0378 ret = is31fl32xx_parse_child_dt(dev, child, led_data);
0379 if (ret)
0380 goto err;
0381
0382
0383 other_led_data = is31fl32xx_find_led_data(priv,
0384 led_data->channel);
0385 if (other_led_data) {
0386 dev_err(dev,
0387 "Node %pOF 'reg' conflicts with another LED\n",
0388 child);
0389 ret = -EINVAL;
0390 goto err;
0391 }
0392
0393 init_data.fwnode = of_fwnode_handle(child);
0394
0395 ret = devm_led_classdev_register_ext(dev, &led_data->cdev,
0396 &init_data);
0397 if (ret) {
0398 dev_err(dev, "Failed to register LED for %pOF: %d\n",
0399 child, ret);
0400 goto err;
0401 }
0402
0403 priv->num_leds++;
0404 }
0405
0406 return 0;
0407
0408 err:
0409 of_node_put(child);
0410 return ret;
0411 }
0412
0413 static const struct of_device_id of_is31fl32xx_match[] = {
0414 { .compatible = "issi,is31fl3236", .data = &is31fl3236_cdef, },
0415 { .compatible = "issi,is31fl3235", .data = &is31fl3235_cdef, },
0416 { .compatible = "issi,is31fl3218", .data = &is31fl3218_cdef, },
0417 { .compatible = "si-en,sn3218", .data = &is31fl3218_cdef, },
0418 { .compatible = "issi,is31fl3216", .data = &is31fl3216_cdef, },
0419 { .compatible = "si-en,sn3216", .data = &is31fl3216_cdef, },
0420 {},
0421 };
0422
0423 MODULE_DEVICE_TABLE(of, of_is31fl32xx_match);
0424
0425 static int is31fl32xx_probe(struct i2c_client *client,
0426 const struct i2c_device_id *id)
0427 {
0428 const struct is31fl32xx_chipdef *cdef;
0429 struct device *dev = &client->dev;
0430 struct is31fl32xx_priv *priv;
0431 int count;
0432 int ret = 0;
0433
0434 cdef = device_get_match_data(dev);
0435
0436 count = of_get_available_child_count(dev_of_node(dev));
0437 if (!count)
0438 return -EINVAL;
0439
0440 priv = devm_kzalloc(dev, struct_size(priv, leds, count),
0441 GFP_KERNEL);
0442 if (!priv)
0443 return -ENOMEM;
0444
0445 priv->client = client;
0446 priv->cdef = cdef;
0447 i2c_set_clientdata(client, priv);
0448
0449 ret = is31fl32xx_init_regs(priv);
0450 if (ret)
0451 return ret;
0452
0453 ret = is31fl32xx_parse_dt(dev, priv);
0454 if (ret)
0455 return ret;
0456
0457 return 0;
0458 }
0459
0460 static int is31fl32xx_remove(struct i2c_client *client)
0461 {
0462 struct is31fl32xx_priv *priv = i2c_get_clientdata(client);
0463 int ret;
0464
0465 ret = is31fl32xx_reset_regs(priv);
0466 if (ret)
0467 dev_err(&client->dev, "Failed to reset registers on removal (%pe)\n",
0468 ERR_PTR(ret));
0469
0470 return 0;
0471 }
0472
0473
0474
0475
0476
0477 static const struct i2c_device_id is31fl32xx_id[] = {
0478 { "is31fl3236" },
0479 { "is31fl3235" },
0480 { "is31fl3218" },
0481 { "sn3218" },
0482 { "is31fl3216" },
0483 { "sn3216" },
0484 {},
0485 };
0486
0487 MODULE_DEVICE_TABLE(i2c, is31fl32xx_id);
0488
0489 static struct i2c_driver is31fl32xx_driver = {
0490 .driver = {
0491 .name = "is31fl32xx",
0492 .of_match_table = of_is31fl32xx_match,
0493 },
0494 .probe = is31fl32xx_probe,
0495 .remove = is31fl32xx_remove,
0496 .id_table = is31fl32xx_id,
0497 };
0498
0499 module_i2c_driver(is31fl32xx_driver);
0500
0501 MODULE_AUTHOR("David Rivshin <drivshin@allworx.com>");
0502 MODULE_DESCRIPTION("ISSI IS31FL32xx LED driver");
0503 MODULE_LICENSE("GPL v2");