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; 65*5ff422a7SAndy 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 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 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 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); 226*5ff422a7SAndy 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 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) { 251*5ff422a7SAndy Shevchenko case LEDS_DEFSTATE_ON: 2522d00f35cSSimon Shields led->cdev.brightness = LED_FULL; 2532d00f35cSSimon Shields break; 254*5ff422a7SAndy 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 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 2862d00f35cSSimon Shields mutex_init(&chip->mutex); 2872d00f35cSSimon Shields chip->client = client; 2882d00f35cSSimon Shields i2c_set_clientdata(client, chip); 2892d00f35cSSimon Shields 2902d00f35cSSimon Shields chip->regmap = devm_regmap_init_i2c(client, &an30259a_regmap_config); 2912d00f35cSSimon Shields 292fc7b5028SChuhong Yuan if (IS_ERR(chip->regmap)) { 293fc7b5028SChuhong Yuan err = PTR_ERR(chip->regmap); 294fc7b5028SChuhong Yuan dev_err(&client->dev, "Failed to allocate register map: %d\n", 295fc7b5028SChuhong Yuan err); 296fc7b5028SChuhong Yuan goto exit; 297fc7b5028SChuhong Yuan } 298fc7b5028SChuhong Yuan 2992d00f35cSSimon Shields for (i = 0; i < chip->num_leds; i++) { 3001817208eSJacek Anaszewski struct led_init_data init_data = {}; 3011817208eSJacek Anaszewski 3022d00f35cSSimon Shields an30259a_init_default_state(&chip->leds[i]); 3032d00f35cSSimon Shields chip->leds[i].cdev.brightness_set_blocking = 3042d00f35cSSimon Shields an30259a_brightness_set; 3052d00f35cSSimon Shields chip->leds[i].cdev.blink_set = an30259a_blink_set; 3062d00f35cSSimon Shields 3071817208eSJacek Anaszewski init_data.fwnode = chip->leds[i].fwnode; 3081817208eSJacek Anaszewski init_data.devicename = AN30259A_NAME; 3091817208eSJacek Anaszewski init_data.default_label = ":"; 3101817208eSJacek Anaszewski 3111817208eSJacek Anaszewski err = devm_led_classdev_register_ext(&client->dev, 3121817208eSJacek Anaszewski &chip->leds[i].cdev, 3131817208eSJacek Anaszewski &init_data); 3142d00f35cSSimon Shields if (err < 0) 3152d00f35cSSimon Shields goto exit; 3162d00f35cSSimon Shields } 3172d00f35cSSimon Shields return 0; 3182d00f35cSSimon Shields 3192d00f35cSSimon Shields exit: 3202d00f35cSSimon Shields mutex_destroy(&chip->mutex); 3212d00f35cSSimon Shields return err; 3222d00f35cSSimon Shields } 3232d00f35cSSimon Shields 324ed5c2f5fSUwe Kleine-König static void an30259a_remove(struct i2c_client *client) 3252d00f35cSSimon Shields { 3262d00f35cSSimon Shields struct an30259a *chip = i2c_get_clientdata(client); 3272d00f35cSSimon Shields 3282d00f35cSSimon Shields mutex_destroy(&chip->mutex); 3292d00f35cSSimon Shields } 3302d00f35cSSimon Shields 3312d00f35cSSimon Shields static const struct of_device_id an30259a_match_table[] = { 3322d00f35cSSimon Shields { .compatible = "panasonic,an30259a", }, 3332d00f35cSSimon Shields { /* sentinel */ }, 3342d00f35cSSimon Shields }; 3352d00f35cSSimon Shields 3362d00f35cSSimon Shields MODULE_DEVICE_TABLE(of, an30259a_match_table); 3372d00f35cSSimon Shields 3382d00f35cSSimon Shields static const struct i2c_device_id an30259a_id[] = { 3392d00f35cSSimon Shields { "an30259a", 0 }, 3402d00f35cSSimon Shields { /* sentinel */ }, 3412d00f35cSSimon Shields }; 3422d00f35cSSimon Shields MODULE_DEVICE_TABLE(i2c, an30259a_id); 3432d00f35cSSimon Shields 3442d00f35cSSimon Shields static struct i2c_driver an30259a_driver = { 3452d00f35cSSimon Shields .driver = { 346f3b357c2SChristophe JAILLET .name = "leds-an30259a", 3472d00f35cSSimon Shields .of_match_table = of_match_ptr(an30259a_match_table), 3482d00f35cSSimon Shields }, 3492d00f35cSSimon Shields .probe_new = an30259a_probe, 3502d00f35cSSimon Shields .remove = an30259a_remove, 3512d00f35cSSimon Shields .id_table = an30259a_id, 3522d00f35cSSimon Shields }; 3532d00f35cSSimon Shields 3542d00f35cSSimon Shields module_i2c_driver(an30259a_driver); 3552d00f35cSSimon Shields 3562d00f35cSSimon Shields MODULE_AUTHOR("Simon Shields <simon@lineageos.org>"); 357f3b357c2SChristophe JAILLET MODULE_DESCRIPTION("AN30259A LED driver"); 3582d00f35cSSimon Shields MODULE_LICENSE("GPL v2"); 359