linux/drivers/leds/flash/leds-rt4505.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2
   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        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
  18
  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)
  33
  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
  43
  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#else
 283static 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#endif
 289
 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        } else
 304                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        } else
 317                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        } else
 330                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 int 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        return 0;
 402}
 403
 404static void rt4505_shutdown(struct i2c_client *client)
 405{
 406        struct rt4505_priv *priv = i2c_get_clientdata(client);
 407
 408        /* Reset registers to make sure all off before shutdown */
 409        regmap_write(priv->regmap, RT4505_REG_RESET, RT4505_RESET_MASK);
 410}
 411
 412static const struct of_device_id __maybe_unused rt4505_leds_match[] = {
 413        { .compatible = "richtek,rt4505", },
 414        {}
 415};
 416MODULE_DEVICE_TABLE(of, rt4505_leds_match);
 417
 418static struct i2c_driver rt4505_driver = {
 419        .driver = {
 420                .name = "rt4505",
 421                .of_match_table = of_match_ptr(rt4505_leds_match),
 422        },
 423        .probe_new = rt4505_probe,
 424        .remove = rt4505_remove,
 425        .shutdown = rt4505_shutdown,
 426};
 427module_i2c_driver(rt4505_driver);
 428
 429MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
 430MODULE_LICENSE("GPL v2");
 431