1 // SPDX-License-Identifier: GPL-2.0-only
3 #include <linux/bitops.h>
5 #include <linux/kernel.h>
6 #include <linux/led-class-flash.h>
7 #include <linux/module.h>
8 #include <linux/mutex.h>
9 #include <linux/property.h>
10 #include <linux/regmap.h>
11 #include <media/v4l2-flash-led-class.h>
13 #define RT4505_REG_RESET 0x0
14 #define RT4505_REG_CONFIG 0x8
15 #define RT4505_REG_ILED 0x9
16 #define RT4505_REG_ENABLE 0xA
17 #define RT4505_REG_FLAGS 0xB
19 #define RT4505_RESET_MASK BIT(7)
20 #define RT4505_FLASHTO_MASK GENMASK(2, 0)
21 #define RT4505_ITORCH_MASK GENMASK(7, 5)
22 #define RT4505_ITORCH_SHIFT 5
23 #define RT4505_IFLASH_MASK GENMASK(4, 0)
24 #define RT4505_ENABLE_MASK GENMASK(5, 0)
25 #define RT4505_TORCH_SET (BIT(0) | BIT(4))
26 #define RT4505_FLASH_SET (BIT(0) | BIT(1) | BIT(2) | BIT(4))
27 #define RT4505_EXT_FLASH_SET (BIT(0) | BIT(1) | BIT(4) | BIT(5))
28 #define RT4505_FLASH_GET (BIT(0) | BIT(1) | BIT(4))
29 #define RT4505_OVP_MASK BIT(3)
30 #define RT4505_SHORT_MASK BIT(2)
31 #define RT4505_OTP_MASK BIT(1)
32 #define RT4505_TIMEOUT_MASK BIT(0)
34 #define RT4505_ITORCH_MINUA 46000
35 #define RT4505_ITORCH_MAXUA 375000
36 #define RT4505_ITORCH_STPUA 47000
37 #define RT4505_IFLASH_MINUA 93750
38 #define RT4505_IFLASH_MAXUA 1500000
39 #define RT4505_IFLASH_STPUA 93750
40 #define RT4505_FLASHTO_MINUS 100000
41 #define RT4505_FLASHTO_MAXUS 800000
42 #define RT4505_FLASHTO_STPUS 100000
46 struct regmap *regmap;
48 struct led_classdev_flash flash;
49 struct v4l2_flash *v4l2_flash;
52 static int rt4505_torch_brightness_set(struct led_classdev *lcdev,
53 enum led_brightness level)
55 struct rt4505_priv *priv =
56 container_of(lcdev, struct rt4505_priv, flash.led_cdev);
60 mutex_lock(&priv->lock);
62 if (level != LED_OFF) {
63 ret = regmap_update_bits(priv->regmap,
64 RT4505_REG_ILED, RT4505_ITORCH_MASK,
65 (level - 1) << RT4505_ITORCH_SHIFT);
69 val = RT4505_TORCH_SET;
72 ret = regmap_update_bits(priv->regmap, RT4505_REG_ENABLE,
73 RT4505_ENABLE_MASK, val);
76 mutex_unlock(&priv->lock);
80 static enum led_brightness rt4505_torch_brightness_get(
81 struct led_classdev *lcdev)
83 struct rt4505_priv *priv =
84 container_of(lcdev, struct rt4505_priv, flash.led_cdev);
88 mutex_lock(&priv->lock);
90 ret = regmap_read(priv->regmap, RT4505_REG_ENABLE, &val);
92 dev_err(lcdev->dev, "Failed to get LED enable\n");
97 if ((val & RT4505_ENABLE_MASK) != RT4505_TORCH_SET) {
102 ret = regmap_read(priv->regmap, RT4505_REG_ILED, &val);
104 dev_err(lcdev->dev, "Failed to get LED brightness\n");
109 ret = ((val & RT4505_ITORCH_MASK) >> RT4505_ITORCH_SHIFT) + 1;
112 mutex_unlock(&priv->lock);
116 static int rt4505_flash_brightness_set(struct led_classdev_flash *fled_cdev,
119 struct rt4505_priv *priv =
120 container_of(fled_cdev, struct rt4505_priv, flash);
121 struct led_flash_setting *s = &fled_cdev->brightness;
122 u32 val = (brightness - s->min) / s->step;
125 mutex_lock(&priv->lock);
126 ret = regmap_update_bits(priv->regmap, RT4505_REG_ILED,
127 RT4505_IFLASH_MASK, val);
128 mutex_unlock(&priv->lock);
133 static int rt4505_flash_strobe_set(struct led_classdev_flash *fled_cdev,
136 struct rt4505_priv *priv =
137 container_of(fled_cdev, struct rt4505_priv, flash);
138 u32 val = state ? RT4505_FLASH_SET : 0;
141 mutex_lock(&priv->lock);
142 ret = regmap_update_bits(priv->regmap, RT4505_REG_ENABLE,
143 RT4505_ENABLE_MASK, val);
144 mutex_unlock(&priv->lock);
149 static int rt4505_flash_strobe_get(struct led_classdev_flash *fled_cdev,
152 struct rt4505_priv *priv =
153 container_of(fled_cdev, struct rt4505_priv, flash);
157 mutex_lock(&priv->lock);
159 ret = regmap_read(priv->regmap, RT4505_REG_ENABLE, &val);
163 *state = (val & RT4505_FLASH_GET) == RT4505_FLASH_GET;
166 mutex_unlock(&priv->lock);
170 static int rt4505_flash_timeout_set(struct led_classdev_flash *fled_cdev,
173 struct rt4505_priv *priv =
174 container_of(fled_cdev, struct rt4505_priv, flash);
175 struct led_flash_setting *s = &fled_cdev->timeout;
176 u32 val = (timeout - s->min) / s->step;
179 mutex_lock(&priv->lock);
180 ret = regmap_update_bits(priv->regmap, RT4505_REG_CONFIG,
181 RT4505_FLASHTO_MASK, val);
182 mutex_unlock(&priv->lock);
187 static int rt4505_fault_get(struct led_classdev_flash *fled_cdev, u32 *fault)
189 struct rt4505_priv *priv =
190 container_of(fled_cdev, struct rt4505_priv, flash);
191 u32 val, led_faults = 0;
194 ret = regmap_read(priv->regmap, RT4505_REG_FLAGS, &val);
198 if (val & RT4505_OVP_MASK)
199 led_faults |= LED_FAULT_OVER_VOLTAGE;
201 if (val & RT4505_SHORT_MASK)
202 led_faults |= LED_FAULT_SHORT_CIRCUIT;
204 if (val & RT4505_OTP_MASK)
205 led_faults |= LED_FAULT_OVER_TEMPERATURE;
207 if (val & RT4505_TIMEOUT_MASK)
208 led_faults |= LED_FAULT_TIMEOUT;
214 static const struct led_flash_ops rt4505_flash_ops = {
215 .flash_brightness_set = rt4505_flash_brightness_set,
216 .strobe_set = rt4505_flash_strobe_set,
217 .strobe_get = rt4505_flash_strobe_get,
218 .timeout_set = rt4505_flash_timeout_set,
219 .fault_get = rt4505_fault_get,
222 static bool rt4505_is_accessible_reg(struct device *dev, unsigned int reg)
224 if (reg == RT4505_REG_RESET ||
225 (reg >= RT4505_REG_CONFIG && reg <= RT4505_REG_FLAGS))
230 static const struct regmap_config rt4505_regmap_config = {
233 .max_register = RT4505_REG_FLAGS,
235 .readable_reg = rt4505_is_accessible_reg,
236 .writeable_reg = rt4505_is_accessible_reg,
239 #if IS_ENABLED(CONFIG_V4L2_FLASH_LED_CLASS)
240 static int rt4505_flash_external_strobe_set(struct v4l2_flash *v4l2_flash,
243 struct led_classdev_flash *flash = v4l2_flash->fled_cdev;
244 struct rt4505_priv *priv =
245 container_of(flash, struct rt4505_priv, flash);
246 u32 val = enable ? RT4505_EXT_FLASH_SET : 0;
249 mutex_lock(&priv->lock);
250 ret = regmap_update_bits(priv->regmap, RT4505_REG_ENABLE,
251 RT4505_ENABLE_MASK, val);
252 mutex_unlock(&priv->lock);
257 static const struct v4l2_flash_ops v4l2_flash_ops = {
258 .external_strobe_set = rt4505_flash_external_strobe_set,
261 static void rt4505_init_v4l2_config(struct rt4505_priv *priv,
262 struct v4l2_flash_config *config)
264 struct led_classdev_flash *flash = &priv->flash;
265 struct led_classdev *lcdev = &flash->led_cdev;
266 struct led_flash_setting *s;
268 strscpy(config->dev_name, lcdev->dev->kobj.name,
269 sizeof(config->dev_name));
271 s = &config->intensity;
272 s->min = RT4505_ITORCH_MINUA;
273 s->step = RT4505_ITORCH_STPUA;
274 s->max = s->val = s->min + (lcdev->max_brightness - 1) * s->step;
276 config->flash_faults = LED_FAULT_OVER_VOLTAGE |
277 LED_FAULT_SHORT_CIRCUIT |
278 LED_FAULT_LED_OVER_TEMPERATURE |
280 config->has_external_strobe = 1;
283 static const struct v4l2_flash_ops v4l2_flash_ops;
284 static void rt4505_init_v4l2_config(struct rt4505_priv *priv,
285 struct v4l2_flash_config *config)
290 static void rt4505_init_flash_properties(struct rt4505_priv *priv,
291 struct fwnode_handle *child)
293 struct led_classdev_flash *flash = &priv->flash;
294 struct led_classdev *lcdev = &flash->led_cdev;
295 struct led_flash_setting *s;
299 ret = fwnode_property_read_u32(child, "led-max-microamp", &val);
301 dev_warn(priv->dev, "led-max-microamp DT property missing\n");
302 val = RT4505_ITORCH_MINUA;
304 val = clamp_val(val, RT4505_ITORCH_MINUA, RT4505_ITORCH_MAXUA);
306 lcdev->max_brightness =
307 (val - RT4505_ITORCH_MINUA) / RT4505_ITORCH_STPUA + 1;
308 lcdev->brightness_set_blocking = rt4505_torch_brightness_set;
309 lcdev->brightness_get = rt4505_torch_brightness_get;
310 lcdev->flags |= LED_DEV_CAP_FLASH;
312 ret = fwnode_property_read_u32(child, "flash-max-microamp", &val);
314 dev_warn(priv->dev, "flash-max-microamp DT property missing\n");
315 val = RT4505_IFLASH_MINUA;
317 val = clamp_val(val, RT4505_IFLASH_MINUA, RT4505_IFLASH_MAXUA);
319 s = &flash->brightness;
320 s->min = RT4505_IFLASH_MINUA;
321 s->step = RT4505_IFLASH_STPUA;
322 s->max = s->val = val;
324 ret = fwnode_property_read_u32(child, "flash-max-timeout-us", &val);
327 "flash-max-timeout-us DT property missing\n");
328 val = RT4505_FLASHTO_MINUS;
330 val = clamp_val(val, RT4505_FLASHTO_MINUS,
331 RT4505_FLASHTO_MAXUS);
334 s->min = RT4505_FLASHTO_MINUS;
335 s->step = RT4505_FLASHTO_STPUS;
336 s->max = s->val = val;
338 flash->ops = &rt4505_flash_ops;
341 static int rt4505_probe(struct i2c_client *client)
343 struct rt4505_priv *priv;
344 struct fwnode_handle *child;
345 struct led_init_data init_data = {};
346 struct v4l2_flash_config v4l2_config = {};
349 priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
353 priv->dev = &client->dev;
354 mutex_init(&priv->lock);
356 priv->regmap = devm_regmap_init_i2c(client, &rt4505_regmap_config);
357 if (IS_ERR(priv->regmap)) {
358 dev_err(priv->dev, "Failed to allocate register map\n");
359 return PTR_ERR(priv->regmap);
362 ret = regmap_write(priv->regmap, RT4505_REG_RESET, RT4505_RESET_MASK);
364 dev_err(priv->dev, "Failed to reset registers\n");
368 child = fwnode_get_next_available_child_node(client->dev.fwnode, NULL);
370 dev_err(priv->dev, "Failed to get child node\n");
373 init_data.fwnode = child;
375 rt4505_init_flash_properties(priv, child);
376 ret = devm_led_classdev_flash_register_ext(priv->dev, &priv->flash,
379 dev_err(priv->dev, "Failed to register flash\n");
383 rt4505_init_v4l2_config(priv, &v4l2_config);
384 priv->v4l2_flash = v4l2_flash_init(priv->dev, init_data.fwnode,
385 &priv->flash, &v4l2_flash_ops,
387 if (IS_ERR(priv->v4l2_flash)) {
388 dev_err(priv->dev, "Failed to register v4l2 flash\n");
389 return PTR_ERR(priv->v4l2_flash);
392 i2c_set_clientdata(client, priv);
396 static int rt4505_remove(struct i2c_client *client)
398 struct rt4505_priv *priv = i2c_get_clientdata(client);
400 v4l2_flash_release(priv->v4l2_flash);
404 static void rt4505_shutdown(struct i2c_client *client)
406 struct rt4505_priv *priv = i2c_get_clientdata(client);
408 /* Reset registers to make sure all off before shutdown */
409 regmap_write(priv->regmap, RT4505_REG_RESET, RT4505_RESET_MASK);
412 static const struct of_device_id __maybe_unused rt4505_leds_match[] = {
413 { .compatible = "richtek,rt4505", },
416 MODULE_DEVICE_TABLE(of, rt4505_leds_match);
418 static struct i2c_driver rt4505_driver = {
421 .of_match_table = of_match_ptr(rt4505_leds_match),
423 .probe_new = rt4505_probe,
424 .remove = rt4505_remove,
425 .shutdown = rt4505_shutdown,
427 module_i2c_driver(rt4505_driver);
429 MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
430 MODULE_LICENSE("GPL v2");