Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v6.18-rc4 157 lines 4.0 kB view raw
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Copyright (C) 2023 Andreas Kemnade 4 * 5 * Datasheet: 6 * https://fscdn.rohm.com/en/products/databook/datasheet/ic/power/led_driver/bd2606mvv_1-e.pdf 7 * 8 * If LED brightness cannot be controlled independently due to shared 9 * brightness registers, max_brightness is set to 1 and only on/off 10 * is possible for the affected LED pair. 11 */ 12 13#include <linux/i2c.h> 14#include <linux/leds.h> 15#include <linux/module.h> 16#include <linux/mod_devicetable.h> 17#include <linux/property.h> 18#include <linux/regmap.h> 19#include <linux/slab.h> 20 21#define BD2606_MAX_LEDS 6 22#define BD2606_MAX_BRIGHTNESS 63 23#define BD2606_REG_PWRCNT 3 24#define ldev_to_led(c) container_of(c, struct bd2606mvv_led, ldev) 25 26struct bd2606mvv_led { 27 unsigned int led_no; 28 struct led_classdev ldev; 29 struct bd2606mvv_priv *priv; 30}; 31 32struct bd2606mvv_priv { 33 struct bd2606mvv_led leds[BD2606_MAX_LEDS]; 34 struct regmap *regmap; 35}; 36 37static int 38bd2606mvv_brightness_set(struct led_classdev *led_cdev, 39 enum led_brightness brightness) 40{ 41 struct bd2606mvv_led *led = ldev_to_led(led_cdev); 42 struct bd2606mvv_priv *priv = led->priv; 43 int err; 44 45 if (brightness == 0) 46 return regmap_update_bits(priv->regmap, 47 BD2606_REG_PWRCNT, 48 1 << led->led_no, 49 0); 50 51 /* shared brightness register */ 52 err = regmap_write(priv->regmap, led->led_no / 2, 53 led_cdev->max_brightness == 1 ? 54 BD2606_MAX_BRIGHTNESS : brightness); 55 if (err) 56 return err; 57 58 return regmap_update_bits(priv->regmap, 59 BD2606_REG_PWRCNT, 60 1 << led->led_no, 61 1 << led->led_no); 62} 63 64static const struct regmap_config bd2606mvv_regmap = { 65 .reg_bits = 8, 66 .val_bits = 8, 67 .max_register = 0x3, 68}; 69 70static int bd2606mvv_probe(struct i2c_client *client) 71{ 72 struct device *dev = &client->dev; 73 struct bd2606mvv_priv *priv; 74 struct fwnode_handle *led_fwnodes[BD2606_MAX_LEDS] = { 0 }; 75 int active_pairs[BD2606_MAX_LEDS / 2] = { 0 }; 76 int err, reg; 77 int i, j; 78 79 if (!dev_fwnode(dev)) 80 return -ENODEV; 81 82 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 83 if (!priv) 84 return -ENOMEM; 85 86 priv->regmap = devm_regmap_init_i2c(client, &bd2606mvv_regmap); 87 if (IS_ERR(priv->regmap)) { 88 err = PTR_ERR(priv->regmap); 89 dev_err(dev, "Failed to allocate register map: %d\n", err); 90 return err; 91 } 92 93 i2c_set_clientdata(client, priv); 94 95 device_for_each_child_node_scoped(dev, child) { 96 struct bd2606mvv_led *led; 97 98 err = fwnode_property_read_u32(child, "reg", &reg); 99 if (err) 100 return err; 101 102 if (reg < 0 || reg >= BD2606_MAX_LEDS || led_fwnodes[reg]) 103 return -EINVAL; 104 105 led = &priv->leds[reg]; 106 led_fwnodes[reg] = fwnode_handle_get(child); 107 active_pairs[reg / 2]++; 108 led->priv = priv; 109 led->led_no = reg; 110 led->ldev.brightness_set_blocking = bd2606mvv_brightness_set; 111 led->ldev.max_brightness = BD2606_MAX_BRIGHTNESS; 112 } 113 114 for (i = 0; i < BD2606_MAX_LEDS; i++) { 115 struct led_init_data init_data = {}; 116 117 if (!led_fwnodes[i]) 118 continue; 119 120 init_data.fwnode = led_fwnodes[i]; 121 /* Check whether brightness can be independently adjusted. */ 122 if (active_pairs[i / 2] == 2) 123 priv->leds[i].ldev.max_brightness = 1; 124 125 err = devm_led_classdev_register_ext(dev, 126 &priv->leds[i].ldev, 127 &init_data); 128 if (err < 0) { 129 for (j = i; j < BD2606_MAX_LEDS; j++) 130 fwnode_handle_put(led_fwnodes[j]); 131 return dev_err_probe(dev, err, 132 "couldn't register LED %s\n", 133 priv->leds[i].ldev.name); 134 } 135 } 136 return 0; 137} 138 139static const struct of_device_id __maybe_unused of_bd2606mvv_leds_match[] = { 140 { .compatible = "rohm,bd2606mvv", }, 141 {}, 142}; 143MODULE_DEVICE_TABLE(of, of_bd2606mvv_leds_match); 144 145static struct i2c_driver bd2606mvv_driver = { 146 .driver = { 147 .name = "leds-bd2606mvv", 148 .of_match_table = of_match_ptr(of_bd2606mvv_leds_match), 149 }, 150 .probe = bd2606mvv_probe, 151}; 152 153module_i2c_driver(bd2606mvv_driver); 154 155MODULE_AUTHOR("Andreas Kemnade <andreas@kemnade.info>"); 156MODULE_DESCRIPTION("BD2606 LED driver"); 157MODULE_LICENSE("GPL");