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