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