xref: /openbmc/linux/drivers/leds/leds-an30259a.c (revision f3b357c280738781df3b25c1cbb8166e11982eeb)
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 #include <uapi/linux/uleds.h>
172d00f35cSSimon Shields 
182d00f35cSSimon Shields #define AN30259A_MAX_LEDS 3
192d00f35cSSimon Shields 
202d00f35cSSimon Shields #define AN30259A_REG_SRESET 0x00
212d00f35cSSimon Shields #define AN30259A_LED_SRESET BIT(0)
222d00f35cSSimon Shields 
232d00f35cSSimon Shields /* LED power registers */
242d00f35cSSimon Shields #define AN30259A_REG_LED_ON 0x01
252d00f35cSSimon Shields #define AN30259A_LED_EN(x) BIT((x) - 1)
262d00f35cSSimon Shields #define AN30259A_LED_SLOPE(x) BIT(((x) - 1) + 4)
272d00f35cSSimon Shields 
282d00f35cSSimon Shields #define AN30259A_REG_LEDCC(x) (0x03 + ((x) - 1))
292d00f35cSSimon Shields 
302d00f35cSSimon Shields /* slope control registers */
312d00f35cSSimon Shields #define AN30259A_REG_SLOPE(x) (0x06 + ((x) - 1))
322d00f35cSSimon Shields #define AN30259A_LED_SLOPETIME1(x) (x)
332d00f35cSSimon Shields #define AN30259A_LED_SLOPETIME2(x) ((x) << 4)
342d00f35cSSimon Shields 
352d00f35cSSimon Shields #define AN30259A_REG_LEDCNT1(x) (0x09 + (4 * ((x) - 1)))
362d00f35cSSimon Shields #define AN30259A_LED_DUTYMAX(x) ((x) << 4)
372d00f35cSSimon Shields #define AN30259A_LED_DUTYMID(x) (x)
382d00f35cSSimon Shields 
392d00f35cSSimon Shields #define AN30259A_REG_LEDCNT2(x) (0x0A + (4 * ((x) - 1)))
402d00f35cSSimon Shields #define AN30259A_LED_DELAY(x) ((x) << 4)
412d00f35cSSimon Shields #define AN30259A_LED_DUTYMIN(x) (x)
422d00f35cSSimon Shields 
432d00f35cSSimon Shields /* detention time control (length of each slope step) */
442d00f35cSSimon Shields #define AN30259A_REG_LEDCNT3(x) (0x0B + (4 * ((x) - 1)))
452d00f35cSSimon Shields #define AN30259A_LED_DT1(x) (x)
462d00f35cSSimon Shields #define AN30259A_LED_DT2(x) ((x) << 4)
472d00f35cSSimon Shields 
482d00f35cSSimon Shields #define AN30259A_REG_LEDCNT4(x) (0x0C + (4 * ((x) - 1)))
492d00f35cSSimon Shields #define AN30259A_LED_DT3(x) (x)
502d00f35cSSimon Shields #define AN30259A_LED_DT4(x) ((x) << 4)
512d00f35cSSimon Shields 
522d00f35cSSimon Shields #define AN30259A_REG_MAX 0x14
532d00f35cSSimon Shields 
542d00f35cSSimon Shields #define AN30259A_BLINK_MAX_TIME 7500 /* ms */
552d00f35cSSimon Shields #define AN30259A_SLOPE_RESOLUTION 500 /* ms */
562d00f35cSSimon Shields 
572d00f35cSSimon Shields #define STATE_OFF 0
582d00f35cSSimon Shields #define STATE_KEEP 1
592d00f35cSSimon Shields #define STATE_ON 2
602d00f35cSSimon Shields 
612d00f35cSSimon Shields struct an30259a;
622d00f35cSSimon Shields 
632d00f35cSSimon Shields struct an30259a_led {
642d00f35cSSimon Shields 	struct an30259a *chip;
652d00f35cSSimon Shields 	struct led_classdev cdev;
662d00f35cSSimon Shields 	u32 num;
672d00f35cSSimon Shields 	u32 default_state;
682d00f35cSSimon Shields 	bool sloping;
692d00f35cSSimon Shields 	char label[LED_MAX_NAME_SIZE];
702d00f35cSSimon Shields };
712d00f35cSSimon Shields 
722d00f35cSSimon Shields struct an30259a {
732d00f35cSSimon Shields 	struct mutex mutex; /* held when writing to registers */
742d00f35cSSimon Shields 	struct i2c_client *client;
752d00f35cSSimon Shields 	struct an30259a_led leds[AN30259A_MAX_LEDS];
762d00f35cSSimon Shields 	struct regmap *regmap;
772d00f35cSSimon Shields 	int num_leds;
782d00f35cSSimon Shields };
792d00f35cSSimon Shields 
802d00f35cSSimon Shields static int an30259a_brightness_set(struct led_classdev *cdev,
812d00f35cSSimon Shields 				   enum led_brightness brightness)
822d00f35cSSimon Shields {
832d00f35cSSimon Shields 	struct an30259a_led *led;
842d00f35cSSimon Shields 	int ret;
852d00f35cSSimon Shields 	unsigned int led_on;
862d00f35cSSimon Shields 
872d00f35cSSimon Shields 	led = container_of(cdev, struct an30259a_led, cdev);
882d00f35cSSimon Shields 	mutex_lock(&led->chip->mutex);
892d00f35cSSimon Shields 
902d00f35cSSimon Shields 	ret = regmap_read(led->chip->regmap, AN30259A_REG_LED_ON, &led_on);
912d00f35cSSimon Shields 	if (ret)
922d00f35cSSimon Shields 		goto error;
932d00f35cSSimon Shields 
942d00f35cSSimon Shields 	switch (brightness) {
952d00f35cSSimon Shields 	case LED_OFF:
962d00f35cSSimon Shields 		led_on &= ~AN30259A_LED_EN(led->num);
972d00f35cSSimon Shields 		led_on &= ~AN30259A_LED_SLOPE(led->num);
982d00f35cSSimon Shields 		led->sloping = false;
992d00f35cSSimon Shields 		break;
1002d00f35cSSimon Shields 	default:
1012d00f35cSSimon Shields 		led_on |= AN30259A_LED_EN(led->num);
1022d00f35cSSimon Shields 		if (led->sloping)
1032d00f35cSSimon Shields 			led_on |= AN30259A_LED_SLOPE(led->num);
1042d00f35cSSimon Shields 		ret = regmap_write(led->chip->regmap,
1052d00f35cSSimon Shields 				   AN30259A_REG_LEDCNT1(led->num),
1062d00f35cSSimon Shields 				   AN30259A_LED_DUTYMAX(0xf) |
1072d00f35cSSimon Shields 				   AN30259A_LED_DUTYMID(0xf));
1082d00f35cSSimon Shields 		if (ret)
1092d00f35cSSimon Shields 			goto error;
1102d00f35cSSimon Shields 		break;
1112d00f35cSSimon Shields 	}
1122d00f35cSSimon Shields 
1132d00f35cSSimon Shields 	ret = regmap_write(led->chip->regmap, AN30259A_REG_LED_ON, led_on);
1142d00f35cSSimon Shields 	if (ret)
1152d00f35cSSimon Shields 		goto error;
1162d00f35cSSimon Shields 
1172d00f35cSSimon Shields 	ret = regmap_write(led->chip->regmap, AN30259A_REG_LEDCC(led->num),
1182d00f35cSSimon Shields 			   brightness);
1192d00f35cSSimon Shields 
1202d00f35cSSimon Shields error:
1212d00f35cSSimon Shields 	mutex_unlock(&led->chip->mutex);
1222d00f35cSSimon Shields 
1232d00f35cSSimon Shields 	return ret;
1242d00f35cSSimon Shields }
1252d00f35cSSimon Shields 
1262d00f35cSSimon Shields static int an30259a_blink_set(struct led_classdev *cdev,
1272d00f35cSSimon Shields 			      unsigned long *delay_off, unsigned long *delay_on)
1282d00f35cSSimon Shields {
1292d00f35cSSimon Shields 	struct an30259a_led *led;
1302d00f35cSSimon Shields 	int ret, num;
1312d00f35cSSimon Shields 	unsigned int led_on;
1322d00f35cSSimon Shields 	unsigned long off = *delay_off, on = *delay_on;
1332d00f35cSSimon Shields 
1342d00f35cSSimon Shields 	led = container_of(cdev, struct an30259a_led, cdev);
1352d00f35cSSimon Shields 
1362d00f35cSSimon Shields 	mutex_lock(&led->chip->mutex);
1372d00f35cSSimon Shields 	num = led->num;
1382d00f35cSSimon Shields 
1392d00f35cSSimon Shields 	/* slope time can only be a multiple of 500ms. */
1402d00f35cSSimon Shields 	if (off % AN30259A_SLOPE_RESOLUTION || on % AN30259A_SLOPE_RESOLUTION) {
1412d00f35cSSimon Shields 		ret = -EINVAL;
1422d00f35cSSimon Shields 		goto error;
1432d00f35cSSimon Shields 	}
1442d00f35cSSimon Shields 
1452d00f35cSSimon Shields 	/* up to a maximum of 7500ms. */
1462d00f35cSSimon Shields 	if (off > AN30259A_BLINK_MAX_TIME || on > AN30259A_BLINK_MAX_TIME) {
1472d00f35cSSimon Shields 		ret = -EINVAL;
1482d00f35cSSimon Shields 		goto error;
1492d00f35cSSimon Shields 	}
1502d00f35cSSimon Shields 
1512d00f35cSSimon Shields 	/* if no blink specified, default to 1 Hz. */
1522d00f35cSSimon Shields 	if (!off && !on) {
1532d00f35cSSimon Shields 		*delay_off = off = 500;
1542d00f35cSSimon Shields 		*delay_on = on = 500;
1552d00f35cSSimon Shields 	}
1562d00f35cSSimon Shields 
1572d00f35cSSimon Shields 	/* convert into values the HW will understand. */
1582d00f35cSSimon Shields 	off /= AN30259A_SLOPE_RESOLUTION;
1592d00f35cSSimon Shields 	on /= AN30259A_SLOPE_RESOLUTION;
1602d00f35cSSimon Shields 
1612d00f35cSSimon Shields 	/* duty min should be zero (=off), delay should be zero. */
1622d00f35cSSimon Shields 	ret = regmap_write(led->chip->regmap, AN30259A_REG_LEDCNT2(num),
1632d00f35cSSimon Shields 			   AN30259A_LED_DELAY(0) | AN30259A_LED_DUTYMIN(0));
1642d00f35cSSimon Shields 	if (ret)
1652d00f35cSSimon Shields 		goto error;
1662d00f35cSSimon Shields 
1672d00f35cSSimon Shields 	/* reset detention time (no "breathing" effect). */
1682d00f35cSSimon Shields 	ret = regmap_write(led->chip->regmap, AN30259A_REG_LEDCNT3(num),
1692d00f35cSSimon Shields 			   AN30259A_LED_DT1(0) | AN30259A_LED_DT2(0));
1702d00f35cSSimon Shields 	if (ret)
1712d00f35cSSimon Shields 		goto error;
1722d00f35cSSimon Shields 	ret = regmap_write(led->chip->regmap, AN30259A_REG_LEDCNT4(num),
1732d00f35cSSimon Shields 			   AN30259A_LED_DT3(0) | AN30259A_LED_DT4(0));
1742d00f35cSSimon Shields 	if (ret)
1752d00f35cSSimon Shields 		goto error;
1762d00f35cSSimon Shields 
1772d00f35cSSimon Shields 	/* slope time controls on/off cycle length. */
1782d00f35cSSimon Shields 	ret = regmap_write(led->chip->regmap, AN30259A_REG_SLOPE(num),
1792d00f35cSSimon Shields 			   AN30259A_LED_SLOPETIME1(off) |
1802d00f35cSSimon Shields 			   AN30259A_LED_SLOPETIME2(on));
1812d00f35cSSimon Shields 	if (ret)
1822d00f35cSSimon Shields 		goto error;
1832d00f35cSSimon Shields 
1842d00f35cSSimon Shields 	/* Finally, enable slope mode. */
1852d00f35cSSimon Shields 	ret = regmap_read(led->chip->regmap, AN30259A_REG_LED_ON, &led_on);
1862d00f35cSSimon Shields 	if (ret)
1872d00f35cSSimon Shields 		goto error;
1882d00f35cSSimon Shields 
1892d00f35cSSimon Shields 	led_on |= AN30259A_LED_SLOPE(num) | AN30259A_LED_EN(led->num);
1902d00f35cSSimon Shields 
1912d00f35cSSimon Shields 	ret = regmap_write(led->chip->regmap, AN30259A_REG_LED_ON, led_on);
1922d00f35cSSimon Shields 
1932d00f35cSSimon Shields 	if (!ret)
1942d00f35cSSimon Shields 		led->sloping = true;
1952d00f35cSSimon Shields error:
1962d00f35cSSimon Shields 	mutex_unlock(&led->chip->mutex);
1972d00f35cSSimon Shields 
1982d00f35cSSimon Shields 	return ret;
1992d00f35cSSimon Shields }
2002d00f35cSSimon Shields 
2012d00f35cSSimon Shields static int an30259a_dt_init(struct i2c_client *client,
2022d00f35cSSimon Shields 			    struct an30259a *chip)
2032d00f35cSSimon Shields {
2042d00f35cSSimon Shields 	struct device_node *np = client->dev.of_node, *child;
2052d00f35cSSimon Shields 	int count, ret;
2062d00f35cSSimon Shields 	int i = 0;
2072d00f35cSSimon Shields 	const char *str;
2082d00f35cSSimon Shields 	struct an30259a_led *led;
2092d00f35cSSimon Shields 
2102d00f35cSSimon Shields 	count = of_get_child_count(np);
2112d00f35cSSimon Shields 	if (!count || count > AN30259A_MAX_LEDS)
2122d00f35cSSimon Shields 		return -EINVAL;
2132d00f35cSSimon Shields 
2142d00f35cSSimon Shields 	for_each_available_child_of_node(np, child) {
2152d00f35cSSimon Shields 		u32 source;
2162d00f35cSSimon Shields 
2172d00f35cSSimon Shields 		ret = of_property_read_u32(child, "reg", &source);
2182d00f35cSSimon Shields 		if (ret != 0 || !source || source > AN30259A_MAX_LEDS) {
2192d00f35cSSimon Shields 			dev_err(&client->dev, "Couldn't read LED address: %d\n",
2202d00f35cSSimon Shields 				ret);
2212d00f35cSSimon Shields 			count--;
2222d00f35cSSimon Shields 			continue;
2232d00f35cSSimon Shields 		}
2242d00f35cSSimon Shields 
2252d00f35cSSimon Shields 		led = &chip->leds[i];
2262d00f35cSSimon Shields 
2272d00f35cSSimon Shields 		led->num = source;
2282d00f35cSSimon Shields 		led->chip = chip;
2292d00f35cSSimon Shields 
2302d00f35cSSimon Shields 		if (of_property_read_string(child, "label", &str))
2312d00f35cSSimon Shields 			snprintf(led->label, sizeof(led->label), "an30259a::");
2322d00f35cSSimon Shields 		else
2332d00f35cSSimon Shields 			snprintf(led->label, sizeof(led->label), "an30259a:%s",
2342d00f35cSSimon Shields 				 str);
2352d00f35cSSimon Shields 
2362d00f35cSSimon Shields 		led->cdev.name = led->label;
2372d00f35cSSimon Shields 
2382d00f35cSSimon Shields 		if (!of_property_read_string(child, "default-state", &str)) {
2392d00f35cSSimon Shields 			if (!strcmp(str, "on"))
2402d00f35cSSimon Shields 				led->default_state = STATE_ON;
2412d00f35cSSimon Shields 			else if (!strcmp(str, "keep"))
2422d00f35cSSimon Shields 				led->default_state = STATE_KEEP;
2432d00f35cSSimon Shields 			else
2442d00f35cSSimon Shields 				led->default_state = STATE_OFF;
2452d00f35cSSimon Shields 		}
2462d00f35cSSimon Shields 
2472d00f35cSSimon Shields 		of_property_read_string(child, "linux,default-trigger",
2482d00f35cSSimon Shields 					&led->cdev.default_trigger);
2492d00f35cSSimon Shields 
2502d00f35cSSimon Shields 		i++;
2512d00f35cSSimon Shields 	}
2522d00f35cSSimon Shields 
2532d00f35cSSimon Shields 	if (!count)
2542d00f35cSSimon Shields 		return -EINVAL;
2552d00f35cSSimon Shields 
2562d00f35cSSimon Shields 	chip->num_leds = i;
2572d00f35cSSimon Shields 
2582d00f35cSSimon Shields 	return 0;
2592d00f35cSSimon Shields }
2602d00f35cSSimon Shields 
2612d00f35cSSimon Shields static const struct regmap_config an30259a_regmap_config = {
2622d00f35cSSimon Shields 	.reg_bits = 8,
2632d00f35cSSimon Shields 	.val_bits = 8,
2642d00f35cSSimon Shields 	.max_register = AN30259A_REG_MAX,
2652d00f35cSSimon Shields };
2662d00f35cSSimon Shields 
2672d00f35cSSimon Shields static void an30259a_init_default_state(struct an30259a_led *led)
2682d00f35cSSimon Shields {
2692d00f35cSSimon Shields 	struct an30259a *chip = led->chip;
2702d00f35cSSimon Shields 	int led_on, err;
2712d00f35cSSimon Shields 
2722d00f35cSSimon Shields 	switch (led->default_state) {
2732d00f35cSSimon Shields 	case STATE_ON:
2742d00f35cSSimon Shields 		led->cdev.brightness = LED_FULL;
2752d00f35cSSimon Shields 		break;
2762d00f35cSSimon Shields 	case STATE_KEEP:
2772d00f35cSSimon Shields 		err = regmap_read(chip->regmap, AN30259A_REG_LED_ON, &led_on);
2782d00f35cSSimon Shields 		if (err)
2792d00f35cSSimon Shields 			break;
2802d00f35cSSimon Shields 
2812d00f35cSSimon Shields 		if (!(led_on & AN30259A_LED_EN(led->num))) {
2822d00f35cSSimon Shields 			led->cdev.brightness = LED_OFF;
2832d00f35cSSimon Shields 			break;
2842d00f35cSSimon Shields 		}
2852d00f35cSSimon Shields 		regmap_read(chip->regmap, AN30259A_REG_LEDCC(led->num),
2862d00f35cSSimon Shields 			    &led->cdev.brightness);
2872d00f35cSSimon Shields 		break;
2882d00f35cSSimon Shields 	default:
2892d00f35cSSimon Shields 		led->cdev.brightness = LED_OFF;
2902d00f35cSSimon Shields 	}
2912d00f35cSSimon Shields 
2922d00f35cSSimon Shields 	an30259a_brightness_set(&led->cdev, led->cdev.brightness);
2932d00f35cSSimon Shields }
2942d00f35cSSimon Shields 
2952d00f35cSSimon Shields static int an30259a_probe(struct i2c_client *client)
2962d00f35cSSimon Shields {
2972d00f35cSSimon Shields 	struct an30259a *chip;
2982d00f35cSSimon Shields 	int i, err;
2992d00f35cSSimon Shields 
3002d00f35cSSimon Shields 	chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
3012d00f35cSSimon Shields 	if (!chip)
3022d00f35cSSimon Shields 		return -ENOMEM;
3032d00f35cSSimon Shields 
3042d00f35cSSimon Shields 	err = an30259a_dt_init(client, chip);
3052d00f35cSSimon Shields 	if (err < 0)
3062d00f35cSSimon Shields 		return err;
3072d00f35cSSimon Shields 
3082d00f35cSSimon Shields 	mutex_init(&chip->mutex);
3092d00f35cSSimon Shields 	chip->client = client;
3102d00f35cSSimon Shields 	i2c_set_clientdata(client, chip);
3112d00f35cSSimon Shields 
3122d00f35cSSimon Shields 	chip->regmap = devm_regmap_init_i2c(client, &an30259a_regmap_config);
3132d00f35cSSimon Shields 
3142d00f35cSSimon Shields 	for (i = 0; i < chip->num_leds; i++) {
3152d00f35cSSimon Shields 		an30259a_init_default_state(&chip->leds[i]);
3162d00f35cSSimon Shields 		chip->leds[i].cdev.brightness_set_blocking =
3172d00f35cSSimon Shields 			an30259a_brightness_set;
3182d00f35cSSimon Shields 		chip->leds[i].cdev.blink_set = an30259a_blink_set;
3192d00f35cSSimon Shields 
3202d00f35cSSimon Shields 		err = devm_led_classdev_register(&client->dev,
3212d00f35cSSimon Shields 						 &chip->leds[i].cdev);
3222d00f35cSSimon Shields 		if (err < 0)
3232d00f35cSSimon Shields 			goto exit;
3242d00f35cSSimon Shields 	}
3252d00f35cSSimon Shields 	return 0;
3262d00f35cSSimon Shields 
3272d00f35cSSimon Shields exit:
3282d00f35cSSimon Shields 	mutex_destroy(&chip->mutex);
3292d00f35cSSimon Shields 	return err;
3302d00f35cSSimon Shields }
3312d00f35cSSimon Shields 
3322d00f35cSSimon Shields static int an30259a_remove(struct i2c_client *client)
3332d00f35cSSimon Shields {
3342d00f35cSSimon Shields 	struct an30259a *chip = i2c_get_clientdata(client);
3352d00f35cSSimon Shields 
3362d00f35cSSimon Shields 	mutex_destroy(&chip->mutex);
3372d00f35cSSimon Shields 
3382d00f35cSSimon Shields 	return 0;
3392d00f35cSSimon Shields }
3402d00f35cSSimon Shields 
3412d00f35cSSimon Shields static const struct of_device_id an30259a_match_table[] = {
3422d00f35cSSimon Shields 	{ .compatible = "panasonic,an30259a", },
3432d00f35cSSimon Shields 	{ /* sentinel */ },
3442d00f35cSSimon Shields };
3452d00f35cSSimon Shields 
3462d00f35cSSimon Shields MODULE_DEVICE_TABLE(of, an30259a_match_table);
3472d00f35cSSimon Shields 
3482d00f35cSSimon Shields static const struct i2c_device_id an30259a_id[] = {
3492d00f35cSSimon Shields 	{ "an30259a", 0 },
3502d00f35cSSimon Shields 	{ /* sentinel */ },
3512d00f35cSSimon Shields };
3522d00f35cSSimon Shields MODULE_DEVICE_TABLE(i2c, an30259a_id);
3532d00f35cSSimon Shields 
3542d00f35cSSimon Shields static struct i2c_driver an30259a_driver = {
3552d00f35cSSimon Shields 	.driver = {
356*f3b357c2SChristophe JAILLET 		.name = "leds-an30259a",
3572d00f35cSSimon Shields 		.of_match_table = of_match_ptr(an30259a_match_table),
3582d00f35cSSimon Shields 	},
3592d00f35cSSimon Shields 	.probe_new = an30259a_probe,
3602d00f35cSSimon Shields 	.remove = an30259a_remove,
3612d00f35cSSimon Shields 	.id_table = an30259a_id,
3622d00f35cSSimon Shields };
3632d00f35cSSimon Shields 
3642d00f35cSSimon Shields module_i2c_driver(an30259a_driver);
3652d00f35cSSimon Shields 
3662d00f35cSSimon Shields MODULE_AUTHOR("Simon Shields <simon@lineageos.org>");
367*f3b357c2SChristophe JAILLET MODULE_DESCRIPTION("AN30259A LED driver");
3682d00f35cSSimon Shields MODULE_LICENSE("GPL v2");
369