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