219 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * LED driver for PCA995x I2C LED drivers4 *5 * Copyright 2011 bct electronic GmbH6 * Copyright 2013 Qtechnology/AS7 * Copyright 2022 NXP8 * Copyright 2023 Marek Vasut9 */10 11#include <linux/i2c.h>12#include <linux/leds.h>13#include <linux/module.h>14#include <linux/mod_devicetable.h>15#include <linux/property.h>16#include <linux/regmap.h>17 18/* Register definition */19#define PCA995X_MODE1 0x0020#define PCA995X_MODE2 0x0121#define PCA995X_LEDOUT0 0x0222 23/* Auto-increment disabled. Normal mode */24#define PCA995X_MODE1_CFG 0x0025 26/* LED select registers determine the source that drives LED outputs */27#define PCA995X_LED_OFF 0x028#define PCA995X_LED_ON 0x129#define PCA995X_LED_PWM_MODE 0x230#define PCA995X_LDRX_MASK 0x331#define PCA995X_LDRX_BITS 232 33#define PCA995X_MAX_OUTPUTS 2434#define PCA995X_OUTPUTS_PER_REG 435 36#define PCA995X_IREFALL_FULL_CFG 0xFF37#define PCA995X_IREFALL_HALF_CFG (PCA995X_IREFALL_FULL_CFG / 2)38 39#define ldev_to_led(c) container_of(c, struct pca995x_led, ldev)40 41struct pca995x_chipdef {42 unsigned int num_leds;43 u8 pwm_base;44 u8 irefall;45};46 47static const struct pca995x_chipdef pca9952_chipdef = {48 .num_leds = 16,49 .pwm_base = 0x0a,50 .irefall = 0x43,51};52 53static const struct pca995x_chipdef pca9955b_chipdef = {54 .num_leds = 16,55 .pwm_base = 0x08,56 .irefall = 0x45,57};58 59static const struct pca995x_chipdef pca9956b_chipdef = {60 .num_leds = 24,61 .pwm_base = 0x0a,62 .irefall = 0x40,63};64 65struct pca995x_led {66 unsigned int led_no;67 struct led_classdev ldev;68 struct pca995x_chip *chip;69};70 71struct pca995x_chip {72 struct regmap *regmap;73 struct pca995x_led leds[PCA995X_MAX_OUTPUTS];74 const struct pca995x_chipdef *chipdef;75};76 77static int pca995x_brightness_set(struct led_classdev *led_cdev,78 enum led_brightness brightness)79{80 struct pca995x_led *led = ldev_to_led(led_cdev);81 struct pca995x_chip *chip = led->chip;82 const struct pca995x_chipdef *chipdef = chip->chipdef;83 u8 ledout_addr, pwmout_addr;84 int shift, ret;85 86 pwmout_addr = chipdef->pwm_base + led->led_no;87 ledout_addr = PCA995X_LEDOUT0 + (led->led_no / PCA995X_OUTPUTS_PER_REG);88 shift = PCA995X_LDRX_BITS * (led->led_no % PCA995X_OUTPUTS_PER_REG);89 90 switch (brightness) {91 case LED_FULL:92 return regmap_update_bits(chip->regmap, ledout_addr,93 PCA995X_LDRX_MASK << shift,94 PCA995X_LED_ON << shift);95 case LED_OFF:96 return regmap_update_bits(chip->regmap, ledout_addr,97 PCA995X_LDRX_MASK << shift, 0);98 default:99 /* Adjust brightness as per user input by changing individual PWM */100 ret = regmap_write(chip->regmap, pwmout_addr, brightness);101 if (ret)102 return ret;103 104 /*105 * Change LDRx configuration to individual brightness via PWM.106 * LED will stop blinking if it's doing so.107 */108 return regmap_update_bits(chip->regmap, ledout_addr,109 PCA995X_LDRX_MASK << shift,110 PCA995X_LED_PWM_MODE << shift);111 }112}113 114static const struct regmap_config pca995x_regmap = {115 .reg_bits = 8,116 .val_bits = 8,117 .max_register = 0x49,118};119 120static int pca995x_probe(struct i2c_client *client)121{122 struct fwnode_handle *led_fwnodes[PCA995X_MAX_OUTPUTS] = { 0 };123 struct device *dev = &client->dev;124 const struct pca995x_chipdef *chipdef;125 struct pca995x_chip *chip;126 struct pca995x_led *led;127 int i, j, reg, ret;128 129 chipdef = device_get_match_data(&client->dev);130 131 if (!dev_fwnode(dev))132 return -ENODEV;133 134 chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);135 if (!chip)136 return -ENOMEM;137 138 chip->chipdef = chipdef;139 chip->regmap = devm_regmap_init_i2c(client, &pca995x_regmap);140 if (IS_ERR(chip->regmap))141 return PTR_ERR(chip->regmap);142 143 i2c_set_clientdata(client, chip);144 145 device_for_each_child_node_scoped(dev, child) {146 ret = fwnode_property_read_u32(child, "reg", ®);147 if (ret)148 return ret;149 150 if (reg < 0 || reg >= PCA995X_MAX_OUTPUTS || led_fwnodes[reg])151 return -EINVAL;152 153 led = &chip->leds[reg];154 led_fwnodes[reg] = fwnode_handle_get(child);155 led->chip = chip;156 led->led_no = reg;157 led->ldev.brightness_set_blocking = pca995x_brightness_set;158 led->ldev.max_brightness = 255;159 }160 161 for (i = 0; i < PCA995X_MAX_OUTPUTS; i++) {162 struct led_init_data init_data = {};163 164 if (!led_fwnodes[i])165 continue;166 167 init_data.fwnode = led_fwnodes[i];168 169 ret = devm_led_classdev_register_ext(dev,170 &chip->leds[i].ldev,171 &init_data);172 if (ret < 0) {173 for (j = i; j < PCA995X_MAX_OUTPUTS; j++)174 fwnode_handle_put(led_fwnodes[j]);175 return dev_err_probe(dev, ret,176 "Could not register LED %s\n",177 chip->leds[i].ldev.name);178 }179 }180 181 /* Disable LED all-call address and set normal mode */182 ret = regmap_write(chip->regmap, PCA995X_MODE1, PCA995X_MODE1_CFG);183 if (ret)184 return ret;185 186 /* IREF Output current value for all LEDn outputs */187 return regmap_write(chip->regmap, chipdef->irefall, PCA995X_IREFALL_HALF_CFG);188}189 190static const struct i2c_device_id pca995x_id[] = {191 { "pca9952", .driver_data = (kernel_ulong_t)&pca9952_chipdef },192 { "pca9955b", .driver_data = (kernel_ulong_t)&pca9955b_chipdef },193 { "pca9956b", .driver_data = (kernel_ulong_t)&pca9956b_chipdef },194 {}195};196MODULE_DEVICE_TABLE(i2c, pca995x_id);197 198static const struct of_device_id pca995x_of_match[] = {199 { .compatible = "nxp,pca9952", .data = &pca9952_chipdef },200 { .compatible = "nxp,pca9955b", . data = &pca9955b_chipdef },201 { .compatible = "nxp,pca9956b", .data = &pca9956b_chipdef },202 {},203};204MODULE_DEVICE_TABLE(of, pca995x_of_match);205 206static struct i2c_driver pca995x_driver = {207 .driver = {208 .name = "leds-pca995x",209 .of_match_table = pca995x_of_match,210 },211 .probe = pca995x_probe,212 .id_table = pca995x_id,213};214module_i2c_driver(pca995x_driver);215 216MODULE_AUTHOR("Isai Gaspar <isaiezequiel.gaspar@nxp.com>");217MODULE_DESCRIPTION("PCA995x LED driver");218MODULE_LICENSE("GPL");219