12d00f35cSSimon Shields // SPDX-License-Identifier: GPL-2.0+
22d00f35cSSimon Shields //
32d00f35cSSimon Shields // Driver for Panasonic AN30259A 3-channel LED driver
42d00f35cSSimon Shields //
52d00f35cSSimon Shields // Copyright (c) 2018 Simon Shields <simon@lineageos.org>
62d00f35cSSimon Shields //
72d00f35cSSimon Shields // Datasheet:
82d00f35cSSimon Shields // https://www.alliedelec.com/m/d/a9d2b3ee87c2d1a535a41dd747b1c247.pdf
92d00f35cSSimon Shields
102d00f35cSSimon Shields #include <linux/i2c.h>
112d00f35cSSimon Shields #include <linux/leds.h>
122d00f35cSSimon Shields #include <linux/module.h>
132d00f35cSSimon Shields #include <linux/mutex.h>
142d00f35cSSimon Shields #include <linux/of.h>
152d00f35cSSimon Shields #include <linux/regmap.h>
162d00f35cSSimon Shields
172d00f35cSSimon Shields #define AN30259A_MAX_LEDS 3
182d00f35cSSimon Shields
192d00f35cSSimon Shields #define AN30259A_REG_SRESET 0x00
202d00f35cSSimon Shields #define AN30259A_LED_SRESET BIT(0)
212d00f35cSSimon Shields
222d00f35cSSimon Shields /* LED power registers */
232d00f35cSSimon Shields #define AN30259A_REG_LED_ON 0x01
242d00f35cSSimon Shields #define AN30259A_LED_EN(x) BIT((x) - 1)
252d00f35cSSimon Shields #define AN30259A_LED_SLOPE(x) BIT(((x) - 1) + 4)
262d00f35cSSimon Shields
272d00f35cSSimon Shields #define AN30259A_REG_LEDCC(x) (0x03 + ((x) - 1))
282d00f35cSSimon Shields
292d00f35cSSimon Shields /* slope control registers */
302d00f35cSSimon Shields #define AN30259A_REG_SLOPE(x) (0x06 + ((x) - 1))
312d00f35cSSimon Shields #define AN30259A_LED_SLOPETIME1(x) (x)
322d00f35cSSimon Shields #define AN30259A_LED_SLOPETIME2(x) ((x) << 4)
332d00f35cSSimon Shields
342d00f35cSSimon Shields #define AN30259A_REG_LEDCNT1(x) (0x09 + (4 * ((x) - 1)))
352d00f35cSSimon Shields #define AN30259A_LED_DUTYMAX(x) ((x) << 4)
362d00f35cSSimon Shields #define AN30259A_LED_DUTYMID(x) (x)
372d00f35cSSimon Shields
382d00f35cSSimon Shields #define AN30259A_REG_LEDCNT2(x) (0x0A + (4 * ((x) - 1)))
392d00f35cSSimon Shields #define AN30259A_LED_DELAY(x) ((x) << 4)
402d00f35cSSimon Shields #define AN30259A_LED_DUTYMIN(x) (x)
412d00f35cSSimon Shields
422d00f35cSSimon Shields /* detention time control (length of each slope step) */
432d00f35cSSimon Shields #define AN30259A_REG_LEDCNT3(x) (0x0B + (4 * ((x) - 1)))
442d00f35cSSimon Shields #define AN30259A_LED_DT1(x) (x)
452d00f35cSSimon Shields #define AN30259A_LED_DT2(x) ((x) << 4)
462d00f35cSSimon Shields
472d00f35cSSimon Shields #define AN30259A_REG_LEDCNT4(x) (0x0C + (4 * ((x) - 1)))
482d00f35cSSimon Shields #define AN30259A_LED_DT3(x) (x)
492d00f35cSSimon Shields #define AN30259A_LED_DT4(x) ((x) << 4)
502d00f35cSSimon Shields
512d00f35cSSimon Shields #define AN30259A_REG_MAX 0x14
522d00f35cSSimon Shields
532d00f35cSSimon Shields #define AN30259A_BLINK_MAX_TIME 7500 /* ms */
542d00f35cSSimon Shields #define AN30259A_SLOPE_RESOLUTION 500 /* ms */
552d00f35cSSimon Shields
561817208eSJacek Anaszewski #define AN30259A_NAME "an30259a"
571817208eSJacek Anaszewski
582d00f35cSSimon Shields struct an30259a;
592d00f35cSSimon Shields
602d00f35cSSimon Shields struct an30259a_led {
612d00f35cSSimon Shields struct an30259a *chip;
621817208eSJacek Anaszewski struct fwnode_handle *fwnode;
632d00f35cSSimon Shields struct led_classdev cdev;
642d00f35cSSimon Shields u32 num;
655ff422a7SAndy Shevchenko enum led_default_state default_state;
662d00f35cSSimon Shields bool sloping;
672d00f35cSSimon Shields };
682d00f35cSSimon Shields
692d00f35cSSimon Shields struct an30259a {
702d00f35cSSimon Shields struct mutex mutex; /* held when writing to registers */
712d00f35cSSimon Shields struct i2c_client *client;
722d00f35cSSimon Shields struct an30259a_led leds[AN30259A_MAX_LEDS];
732d00f35cSSimon Shields struct regmap *regmap;
742d00f35cSSimon Shields int num_leds;
752d00f35cSSimon Shields };
762d00f35cSSimon Shields
an30259a_brightness_set(struct led_classdev * cdev,enum led_brightness brightness)772d00f35cSSimon Shields static int an30259a_brightness_set(struct led_classdev *cdev,
782d00f35cSSimon Shields enum led_brightness brightness)
792d00f35cSSimon Shields {
802d00f35cSSimon Shields struct an30259a_led *led;
812d00f35cSSimon Shields int ret;
822d00f35cSSimon Shields unsigned int led_on;
832d00f35cSSimon Shields
842d00f35cSSimon Shields led = container_of(cdev, struct an30259a_led, cdev);
852d00f35cSSimon Shields mutex_lock(&led->chip->mutex);
862d00f35cSSimon Shields
872d00f35cSSimon Shields ret = regmap_read(led->chip->regmap, AN30259A_REG_LED_ON, &led_on);
882d00f35cSSimon Shields if (ret)
892d00f35cSSimon Shields goto error;
902d00f35cSSimon Shields
912d00f35cSSimon Shields switch (brightness) {
922d00f35cSSimon Shields case LED_OFF:
932d00f35cSSimon Shields led_on &= ~AN30259A_LED_EN(led->num);
942d00f35cSSimon Shields led_on &= ~AN30259A_LED_SLOPE(led->num);
952d00f35cSSimon Shields led->sloping = false;
962d00f35cSSimon Shields break;
972d00f35cSSimon Shields default:
982d00f35cSSimon Shields led_on |= AN30259A_LED_EN(led->num);
992d00f35cSSimon Shields if (led->sloping)
1002d00f35cSSimon Shields led_on |= AN30259A_LED_SLOPE(led->num);
1012d00f35cSSimon Shields ret = regmap_write(led->chip->regmap,
1022d00f35cSSimon Shields AN30259A_REG_LEDCNT1(led->num),
1032d00f35cSSimon Shields AN30259A_LED_DUTYMAX(0xf) |
1042d00f35cSSimon Shields AN30259A_LED_DUTYMID(0xf));
1052d00f35cSSimon Shields if (ret)
1062d00f35cSSimon Shields goto error;
1072d00f35cSSimon Shields break;
1082d00f35cSSimon Shields }
1092d00f35cSSimon Shields
1102d00f35cSSimon Shields ret = regmap_write(led->chip->regmap, AN30259A_REG_LED_ON, led_on);
1112d00f35cSSimon Shields if (ret)
1122d00f35cSSimon Shields goto error;
1132d00f35cSSimon Shields
1142d00f35cSSimon Shields ret = regmap_write(led->chip->regmap, AN30259A_REG_LEDCC(led->num),
1152d00f35cSSimon Shields brightness);
1162d00f35cSSimon Shields
1172d00f35cSSimon Shields error:
1182d00f35cSSimon Shields mutex_unlock(&led->chip->mutex);
1192d00f35cSSimon Shields
1202d00f35cSSimon Shields return ret;
1212d00f35cSSimon Shields }
1222d00f35cSSimon Shields
an30259a_blink_set(struct led_classdev * cdev,unsigned long * delay_off,unsigned long * delay_on)1232d00f35cSSimon Shields static int an30259a_blink_set(struct led_classdev *cdev,
1242d00f35cSSimon Shields unsigned long *delay_off, unsigned long *delay_on)
1252d00f35cSSimon Shields {
1262d00f35cSSimon Shields struct an30259a_led *led;
1272d00f35cSSimon Shields int ret, num;
1282d00f35cSSimon Shields unsigned int led_on;
1292d00f35cSSimon Shields unsigned long off = *delay_off, on = *delay_on;
1302d00f35cSSimon Shields
1312d00f35cSSimon Shields led = container_of(cdev, struct an30259a_led, cdev);
1322d00f35cSSimon Shields
1332d00f35cSSimon Shields mutex_lock(&led->chip->mutex);
1342d00f35cSSimon Shields num = led->num;
1352d00f35cSSimon Shields
1362d00f35cSSimon Shields /* slope time can only be a multiple of 500ms. */
1372d00f35cSSimon Shields if (off % AN30259A_SLOPE_RESOLUTION || on % AN30259A_SLOPE_RESOLUTION) {
1382d00f35cSSimon Shields ret = -EINVAL;
1392d00f35cSSimon Shields goto error;
1402d00f35cSSimon Shields }
1412d00f35cSSimon Shields
1422d00f35cSSimon Shields /* up to a maximum of 7500ms. */
1432d00f35cSSimon Shields if (off > AN30259A_BLINK_MAX_TIME || on > AN30259A_BLINK_MAX_TIME) {
1442d00f35cSSimon Shields ret = -EINVAL;
1452d00f35cSSimon Shields goto error;
1462d00f35cSSimon Shields }
1472d00f35cSSimon Shields
1482d00f35cSSimon Shields /* if no blink specified, default to 1 Hz. */
1492d00f35cSSimon Shields if (!off && !on) {
1502d00f35cSSimon Shields *delay_off = off = 500;
1512d00f35cSSimon Shields *delay_on = on = 500;
1522d00f35cSSimon Shields }
1532d00f35cSSimon Shields
1542d00f35cSSimon Shields /* convert into values the HW will understand. */
1552d00f35cSSimon Shields off /= AN30259A_SLOPE_RESOLUTION;
1562d00f35cSSimon Shields on /= AN30259A_SLOPE_RESOLUTION;
1572d00f35cSSimon Shields
1582d00f35cSSimon Shields /* duty min should be zero (=off), delay should be zero. */
1592d00f35cSSimon Shields ret = regmap_write(led->chip->regmap, AN30259A_REG_LEDCNT2(num),
1602d00f35cSSimon Shields AN30259A_LED_DELAY(0) | AN30259A_LED_DUTYMIN(0));
1612d00f35cSSimon Shields if (ret)
1622d00f35cSSimon Shields goto error;
1632d00f35cSSimon Shields
1642d00f35cSSimon Shields /* reset detention time (no "breathing" effect). */
1652d00f35cSSimon Shields ret = regmap_write(led->chip->regmap, AN30259A_REG_LEDCNT3(num),
1662d00f35cSSimon Shields AN30259A_LED_DT1(0) | AN30259A_LED_DT2(0));
1672d00f35cSSimon Shields if (ret)
1682d00f35cSSimon Shields goto error;
1692d00f35cSSimon Shields ret = regmap_write(led->chip->regmap, AN30259A_REG_LEDCNT4(num),
1702d00f35cSSimon Shields AN30259A_LED_DT3(0) | AN30259A_LED_DT4(0));
1712d00f35cSSimon Shields if (ret)
1722d00f35cSSimon Shields goto error;
1732d00f35cSSimon Shields
1742d00f35cSSimon Shields /* slope time controls on/off cycle length. */
1752d00f35cSSimon Shields ret = regmap_write(led->chip->regmap, AN30259A_REG_SLOPE(num),
1762d00f35cSSimon Shields AN30259A_LED_SLOPETIME1(off) |
1772d00f35cSSimon Shields AN30259A_LED_SLOPETIME2(on));
1782d00f35cSSimon Shields if (ret)
1792d00f35cSSimon Shields goto error;
1802d00f35cSSimon Shields
1812d00f35cSSimon Shields /* Finally, enable slope mode. */
1822d00f35cSSimon Shields ret = regmap_read(led->chip->regmap, AN30259A_REG_LED_ON, &led_on);
1832d00f35cSSimon Shields if (ret)
1842d00f35cSSimon Shields goto error;
1852d00f35cSSimon Shields
1862d00f35cSSimon Shields led_on |= AN30259A_LED_SLOPE(num) | AN30259A_LED_EN(led->num);
1872d00f35cSSimon Shields
1882d00f35cSSimon Shields ret = regmap_write(led->chip->regmap, AN30259A_REG_LED_ON, led_on);
1892d00f35cSSimon Shields
1902d00f35cSSimon Shields if (!ret)
1912d00f35cSSimon Shields led->sloping = true;
1922d00f35cSSimon Shields error:
1932d00f35cSSimon Shields mutex_unlock(&led->chip->mutex);
1942d00f35cSSimon Shields
1952d00f35cSSimon Shields return ret;
1962d00f35cSSimon Shields }
1972d00f35cSSimon Shields
an30259a_dt_init(struct i2c_client * client,struct an30259a * chip)1982d00f35cSSimon Shields static int an30259a_dt_init(struct i2c_client *client,
1992d00f35cSSimon Shields struct an30259a *chip)
2002d00f35cSSimon Shields {
2018853c95eSMarek Behún struct device_node *np = dev_of_node(&client->dev), *child;
2022d00f35cSSimon Shields int count, ret;
2032d00f35cSSimon Shields int i = 0;
2042d00f35cSSimon Shields struct an30259a_led *led;
2052d00f35cSSimon Shields
20699a013c8SMarek Behún count = of_get_available_child_count(np);
2072d00f35cSSimon Shields if (!count || count > AN30259A_MAX_LEDS)
2082d00f35cSSimon Shields return -EINVAL;
2092d00f35cSSimon Shields
2102d00f35cSSimon Shields for_each_available_child_of_node(np, child) {
2112d00f35cSSimon Shields u32 source;
2122d00f35cSSimon Shields
2132d00f35cSSimon Shields ret = of_property_read_u32(child, "reg", &source);
2142d00f35cSSimon Shields if (ret != 0 || !source || source > AN30259A_MAX_LEDS) {
2152d00f35cSSimon Shields dev_err(&client->dev, "Couldn't read LED address: %d\n",
2162d00f35cSSimon Shields ret);
2172d00f35cSSimon Shields count--;
2182d00f35cSSimon Shields continue;
2192d00f35cSSimon Shields }
2202d00f35cSSimon Shields
2212d00f35cSSimon Shields led = &chip->leds[i];
2222d00f35cSSimon Shields
2232d00f35cSSimon Shields led->num = source;
2242d00f35cSSimon Shields led->chip = chip;
2251817208eSJacek Anaszewski led->fwnode = of_fwnode_handle(child);
2265ff422a7SAndy Shevchenko led->default_state = led_init_default_state_get(led->fwnode);
2272d00f35cSSimon Shields
2282d00f35cSSimon Shields i++;
2292d00f35cSSimon Shields }
2302d00f35cSSimon Shields
2312d00f35cSSimon Shields if (!count)
2322d00f35cSSimon Shields return -EINVAL;
2332d00f35cSSimon Shields
2342d00f35cSSimon Shields chip->num_leds = i;
2352d00f35cSSimon Shields
2362d00f35cSSimon Shields return 0;
2372d00f35cSSimon Shields }
2382d00f35cSSimon Shields
2392d00f35cSSimon Shields static const struct regmap_config an30259a_regmap_config = {
2402d00f35cSSimon Shields .reg_bits = 8,
2412d00f35cSSimon Shields .val_bits = 8,
2422d00f35cSSimon Shields .max_register = AN30259A_REG_MAX,
2432d00f35cSSimon Shields };
2442d00f35cSSimon Shields
an30259a_init_default_state(struct an30259a_led * led)2452d00f35cSSimon Shields static void an30259a_init_default_state(struct an30259a_led *led)
2462d00f35cSSimon Shields {
2472d00f35cSSimon Shields struct an30259a *chip = led->chip;
2482d00f35cSSimon Shields int led_on, err;
2492d00f35cSSimon Shields
2502d00f35cSSimon Shields switch (led->default_state) {
2515ff422a7SAndy Shevchenko case LEDS_DEFSTATE_ON:
2522d00f35cSSimon Shields led->cdev.brightness = LED_FULL;
2532d00f35cSSimon Shields break;
2545ff422a7SAndy Shevchenko case LEDS_DEFSTATE_KEEP:
2552d00f35cSSimon Shields err = regmap_read(chip->regmap, AN30259A_REG_LED_ON, &led_on);
2562d00f35cSSimon Shields if (err)
2572d00f35cSSimon Shields break;
2582d00f35cSSimon Shields
2592d00f35cSSimon Shields if (!(led_on & AN30259A_LED_EN(led->num))) {
2602d00f35cSSimon Shields led->cdev.brightness = LED_OFF;
2612d00f35cSSimon Shields break;
2622d00f35cSSimon Shields }
2632d00f35cSSimon Shields regmap_read(chip->regmap, AN30259A_REG_LEDCC(led->num),
2642d00f35cSSimon Shields &led->cdev.brightness);
2652d00f35cSSimon Shields break;
2662d00f35cSSimon Shields default:
2672d00f35cSSimon Shields led->cdev.brightness = LED_OFF;
2682d00f35cSSimon Shields }
2692d00f35cSSimon Shields
2702d00f35cSSimon Shields an30259a_brightness_set(&led->cdev, led->cdev.brightness);
2712d00f35cSSimon Shields }
2722d00f35cSSimon Shields
an30259a_probe(struct i2c_client * client)2732d00f35cSSimon Shields static int an30259a_probe(struct i2c_client *client)
2742d00f35cSSimon Shields {
2752d00f35cSSimon Shields struct an30259a *chip;
2762d00f35cSSimon Shields int i, err;
2772d00f35cSSimon Shields
2782d00f35cSSimon Shields chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
2792d00f35cSSimon Shields if (!chip)
2802d00f35cSSimon Shields return -ENOMEM;
2812d00f35cSSimon Shields
2822d00f35cSSimon Shields err = an30259a_dt_init(client, chip);
2832d00f35cSSimon Shields if (err < 0)
2842d00f35cSSimon Shields return err;
2852d00f35cSSimon Shields
286*3ead19aaSGeorge Stark err = devm_mutex_init(&client->dev, &chip->mutex);
287*3ead19aaSGeorge Stark if (err)
288*3ead19aaSGeorge Stark return err;
289*3ead19aaSGeorge Stark
2902d00f35cSSimon Shields chip->client = client;
2912d00f35cSSimon Shields i2c_set_clientdata(client, chip);
2922d00f35cSSimon Shields
2932d00f35cSSimon Shields chip->regmap = devm_regmap_init_i2c(client, &an30259a_regmap_config);
2942d00f35cSSimon Shields
295fc7b5028SChuhong Yuan if (IS_ERR(chip->regmap)) {
296fc7b5028SChuhong Yuan err = PTR_ERR(chip->regmap);
297fc7b5028SChuhong Yuan dev_err(&client->dev, "Failed to allocate register map: %d\n",
298fc7b5028SChuhong Yuan err);
299fc7b5028SChuhong Yuan goto exit;
300fc7b5028SChuhong Yuan }
301fc7b5028SChuhong Yuan
3022d00f35cSSimon Shields for (i = 0; i < chip->num_leds; i++) {
3031817208eSJacek Anaszewski struct led_init_data init_data = {};
3041817208eSJacek Anaszewski
3052d00f35cSSimon Shields an30259a_init_default_state(&chip->leds[i]);
3062d00f35cSSimon Shields chip->leds[i].cdev.brightness_set_blocking =
3072d00f35cSSimon Shields an30259a_brightness_set;
3082d00f35cSSimon Shields chip->leds[i].cdev.blink_set = an30259a_blink_set;
3092d00f35cSSimon Shields
3101817208eSJacek Anaszewski init_data.fwnode = chip->leds[i].fwnode;
3111817208eSJacek Anaszewski init_data.devicename = AN30259A_NAME;
3121817208eSJacek Anaszewski init_data.default_label = ":";
3131817208eSJacek Anaszewski
3141817208eSJacek Anaszewski err = devm_led_classdev_register_ext(&client->dev,
3151817208eSJacek Anaszewski &chip->leds[i].cdev,
3161817208eSJacek Anaszewski &init_data);
3172d00f35cSSimon Shields if (err < 0)
3182d00f35cSSimon Shields goto exit;
3192d00f35cSSimon Shields }
3202d00f35cSSimon Shields return 0;
3212d00f35cSSimon Shields
3222d00f35cSSimon Shields exit:
3232d00f35cSSimon Shields return err;
3242d00f35cSSimon Shields }
3252d00f35cSSimon Shields
3262d00f35cSSimon Shields static const struct of_device_id an30259a_match_table[] = {
3272d00f35cSSimon Shields { .compatible = "panasonic,an30259a", },
3282d00f35cSSimon Shields { /* sentinel */ },
3292d00f35cSSimon Shields };
3302d00f35cSSimon Shields
3312d00f35cSSimon Shields MODULE_DEVICE_TABLE(of, an30259a_match_table);
3322d00f35cSSimon Shields
3332d00f35cSSimon Shields static const struct i2c_device_id an30259a_id[] = {
3342d00f35cSSimon Shields { "an30259a", 0 },
3352d00f35cSSimon Shields { /* sentinel */ },
3362d00f35cSSimon Shields };
3372d00f35cSSimon Shields MODULE_DEVICE_TABLE(i2c, an30259a_id);
3382d00f35cSSimon Shields
3392d00f35cSSimon Shields static struct i2c_driver an30259a_driver = {
3402d00f35cSSimon Shields .driver = {
341f3b357c2SChristophe JAILLET .name = "leds-an30259a",
3423d590af8SZhu Wang .of_match_table = an30259a_match_table,
3432d00f35cSSimon Shields },
344d9ff8a8eSUwe Kleine-König .probe = an30259a_probe,
3452d00f35cSSimon Shields .id_table = an30259a_id,
3462d00f35cSSimon Shields };
3472d00f35cSSimon Shields
3482d00f35cSSimon Shields module_i2c_driver(an30259a_driver);
3492d00f35cSSimon Shields
3502d00f35cSSimon Shields MODULE_AUTHOR("Simon Shields <simon@lineageos.org>");
351f3b357c2SChristophe JAILLET MODULE_DESCRIPTION("AN30259A LED driver");
3522d00f35cSSimon Shields MODULE_LICENSE("GPL v2");
353