431 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2 3#include <linux/bitops.h>4#include <linux/i2c.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>12 13#define RT4505_REG_RESET 0x014#define RT4505_REG_CONFIG 0x815#define RT4505_REG_ILED 0x916#define RT4505_REG_ENABLE 0xA17#define RT4505_REG_FLAGS 0xB18 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 523#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)33 34#define RT4505_ITORCH_MINUA 4600035#define RT4505_ITORCH_MAXUA 37500036#define RT4505_ITORCH_STPUA 4700037#define RT4505_IFLASH_MINUA 9375038#define RT4505_IFLASH_MAXUA 150000039#define RT4505_IFLASH_STPUA 9375040#define RT4505_FLASHTO_MINUS 10000041#define RT4505_FLASHTO_MAXUS 80000042#define RT4505_FLASHTO_STPUS 10000043 44struct rt4505_priv {45 struct device *dev;46 struct regmap *regmap;47 struct mutex lock;48 struct led_classdev_flash flash;49 struct v4l2_flash *v4l2_flash;50};51 52static int rt4505_torch_brightness_set(struct led_classdev *lcdev,53 enum led_brightness level)54{55 struct rt4505_priv *priv =56 container_of(lcdev, struct rt4505_priv, flash.led_cdev);57 u32 val = 0;58 int ret;59 60 mutex_lock(&priv->lock);61 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);66 if (ret)67 goto unlock;68 69 val = RT4505_TORCH_SET;70 }71 72 ret = regmap_update_bits(priv->regmap, RT4505_REG_ENABLE,73 RT4505_ENABLE_MASK, val);74 75unlock:76 mutex_unlock(&priv->lock);77 return ret;78}79 80static enum led_brightness rt4505_torch_brightness_get(81 struct led_classdev *lcdev)82{83 struct rt4505_priv *priv =84 container_of(lcdev, struct rt4505_priv, flash.led_cdev);85 u32 val;86 int ret;87 88 mutex_lock(&priv->lock);89 90 ret = regmap_read(priv->regmap, RT4505_REG_ENABLE, &val);91 if (ret) {92 dev_err(lcdev->dev, "Failed to get LED enable\n");93 ret = LED_OFF;94 goto unlock;95 }96 97 if ((val & RT4505_ENABLE_MASK) != RT4505_TORCH_SET) {98 ret = LED_OFF;99 goto unlock;100 }101 102 ret = regmap_read(priv->regmap, RT4505_REG_ILED, &val);103 if (ret) {104 dev_err(lcdev->dev, "Failed to get LED brightness\n");105 ret = LED_OFF;106 goto unlock;107 }108 109 ret = ((val & RT4505_ITORCH_MASK) >> RT4505_ITORCH_SHIFT) + 1;110 111unlock:112 mutex_unlock(&priv->lock);113 return ret;114}115 116static int rt4505_flash_brightness_set(struct led_classdev_flash *fled_cdev,117 u32 brightness)118{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;123 int ret;124 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);129 130 return ret;131}132 133static int rt4505_flash_strobe_set(struct led_classdev_flash *fled_cdev,134 bool state)135{136 struct rt4505_priv *priv =137 container_of(fled_cdev, struct rt4505_priv, flash);138 u32 val = state ? RT4505_FLASH_SET : 0;139 int ret;140 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);145 146 return ret;147}148 149static int rt4505_flash_strobe_get(struct led_classdev_flash *fled_cdev,150 bool *state)151{152 struct rt4505_priv *priv =153 container_of(fled_cdev, struct rt4505_priv, flash);154 u32 val;155 int ret;156 157 mutex_lock(&priv->lock);158 159 ret = regmap_read(priv->regmap, RT4505_REG_ENABLE, &val);160 if (ret)161 goto unlock;162 163 *state = (val & RT4505_FLASH_GET) == RT4505_FLASH_GET;164 165unlock:166 mutex_unlock(&priv->lock);167 return ret;168}169 170static int rt4505_flash_timeout_set(struct led_classdev_flash *fled_cdev,171 u32 timeout)172{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;177 int ret;178 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);183 184 return ret;185}186 187static int rt4505_fault_get(struct led_classdev_flash *fled_cdev, u32 *fault)188{189 struct rt4505_priv *priv =190 container_of(fled_cdev, struct rt4505_priv, flash);191 u32 val, led_faults = 0;192 int ret;193 194 ret = regmap_read(priv->regmap, RT4505_REG_FLAGS, &val);195 if (ret)196 return ret;197 198 if (val & RT4505_OVP_MASK)199 led_faults |= LED_FAULT_OVER_VOLTAGE;200 201 if (val & RT4505_SHORT_MASK)202 led_faults |= LED_FAULT_SHORT_CIRCUIT;203 204 if (val & RT4505_OTP_MASK)205 led_faults |= LED_FAULT_OVER_TEMPERATURE;206 207 if (val & RT4505_TIMEOUT_MASK)208 led_faults |= LED_FAULT_TIMEOUT;209 210 *fault = led_faults;211 return 0;212}213 214static 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,220};221 222static bool rt4505_is_accessible_reg(struct device *dev, unsigned int reg)223{224 if (reg == RT4505_REG_RESET ||225 (reg >= RT4505_REG_CONFIG && reg <= RT4505_REG_FLAGS))226 return true;227 return false;228}229 230static const struct regmap_config rt4505_regmap_config = {231 .reg_bits = 8,232 .val_bits = 8,233 .max_register = RT4505_REG_FLAGS,234 235 .readable_reg = rt4505_is_accessible_reg,236 .writeable_reg = rt4505_is_accessible_reg,237};238 239#if IS_ENABLED(CONFIG_V4L2_FLASH_LED_CLASS)240static int rt4505_flash_external_strobe_set(struct v4l2_flash *v4l2_flash,241 bool enable)242{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;247 int ret;248 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);253 254 return ret;255}256 257static const struct v4l2_flash_ops v4l2_flash_ops = {258 .external_strobe_set = rt4505_flash_external_strobe_set,259};260 261static void rt4505_init_v4l2_config(struct rt4505_priv *priv,262 struct v4l2_flash_config *config)263{264 struct led_classdev_flash *flash = &priv->flash;265 struct led_classdev *lcdev = &flash->led_cdev;266 struct led_flash_setting *s;267 268 strscpy(config->dev_name, lcdev->dev->kobj.name,269 sizeof(config->dev_name));270 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;275 276 config->flash_faults = LED_FAULT_OVER_VOLTAGE |277 LED_FAULT_SHORT_CIRCUIT |278 LED_FAULT_LED_OVER_TEMPERATURE |279 LED_FAULT_TIMEOUT;280 config->has_external_strobe = 1;281}282#else283static const struct v4l2_flash_ops v4l2_flash_ops;284static void rt4505_init_v4l2_config(struct rt4505_priv *priv,285 struct v4l2_flash_config *config)286{287}288#endif289 290static void rt4505_init_flash_properties(struct rt4505_priv *priv,291 struct fwnode_handle *child)292{293 struct led_classdev_flash *flash = &priv->flash;294 struct led_classdev *lcdev = &flash->led_cdev;295 struct led_flash_setting *s;296 u32 val;297 int ret;298 299 ret = fwnode_property_read_u32(child, "led-max-microamp", &val);300 if (ret) {301 dev_warn(priv->dev, "led-max-microamp DT property missing\n");302 val = RT4505_ITORCH_MINUA;303 } else304 val = clamp_val(val, RT4505_ITORCH_MINUA, RT4505_ITORCH_MAXUA);305 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;311 312 ret = fwnode_property_read_u32(child, "flash-max-microamp", &val);313 if (ret) {314 dev_warn(priv->dev, "flash-max-microamp DT property missing\n");315 val = RT4505_IFLASH_MINUA;316 } else317 val = clamp_val(val, RT4505_IFLASH_MINUA, RT4505_IFLASH_MAXUA);318 319 s = &flash->brightness;320 s->min = RT4505_IFLASH_MINUA;321 s->step = RT4505_IFLASH_STPUA;322 s->max = s->val = val;323 324 ret = fwnode_property_read_u32(child, "flash-max-timeout-us", &val);325 if (ret) {326 dev_warn(priv->dev,327 "flash-max-timeout-us DT property missing\n");328 val = RT4505_FLASHTO_MINUS;329 } else330 val = clamp_val(val, RT4505_FLASHTO_MINUS,331 RT4505_FLASHTO_MAXUS);332 333 s = &flash->timeout;334 s->min = RT4505_FLASHTO_MINUS;335 s->step = RT4505_FLASHTO_STPUS;336 s->max = s->val = val;337 338 flash->ops = &rt4505_flash_ops;339}340 341static int rt4505_probe(struct i2c_client *client)342{343 struct rt4505_priv *priv;344 struct fwnode_handle *child;345 struct led_init_data init_data = {};346 struct v4l2_flash_config v4l2_config = {};347 int ret;348 349 priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);350 if (!priv)351 return -ENOMEM;352 353 priv->dev = &client->dev;354 mutex_init(&priv->lock);355 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);360 }361 362 ret = regmap_write(priv->regmap, RT4505_REG_RESET, RT4505_RESET_MASK);363 if (ret) {364 dev_err(priv->dev, "Failed to reset registers\n");365 return ret;366 }367 368 child = fwnode_get_next_available_child_node(client->dev.fwnode, NULL);369 if (!child) {370 dev_err(priv->dev, "Failed to get child node\n");371 return -EINVAL;372 }373 init_data.fwnode = child;374 375 rt4505_init_flash_properties(priv, child);376 ret = devm_led_classdev_flash_register_ext(priv->dev, &priv->flash,377 &init_data);378 if (ret) {379 dev_err(priv->dev, "Failed to register flash\n");380 return ret;381 }382 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,386 &v4l2_config);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);390 }391 392 i2c_set_clientdata(client, priv);393 return 0;394}395 396static void rt4505_remove(struct i2c_client *client)397{398 struct rt4505_priv *priv = i2c_get_clientdata(client);399 400 v4l2_flash_release(priv->v4l2_flash);401}402 403static void rt4505_shutdown(struct i2c_client *client)404{405 struct rt4505_priv *priv = i2c_get_clientdata(client);406 407 /* Reset registers to make sure all off before shutdown */408 regmap_write(priv->regmap, RT4505_REG_RESET, RT4505_RESET_MASK);409}410 411static const struct of_device_id __maybe_unused rt4505_leds_match[] = {412 { .compatible = "richtek,rt4505", },413 {}414};415MODULE_DEVICE_TABLE(of, rt4505_leds_match);416 417static struct i2c_driver rt4505_driver = {418 .driver = {419 .name = "rt4505",420 .of_match_table = of_match_ptr(rt4505_leds_match),421 },422 .probe = rt4505_probe,423 .remove = rt4505_remove,424 .shutdown = rt4505_shutdown,425};426module_i2c_driver(rt4505_driver);427 428MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");429MODULE_DESCRIPTION("Richtek RT4505 LED driver");430MODULE_LICENSE("GPL v2");431