Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 
0003 #include <linux/bitops.h>
0004 #include <linux/i2c.h>
0005 #include <linux/kernel.h>
0006 #include <linux/led-class-flash.h>
0007 #include <linux/module.h>
0008 #include <linux/mutex.h>
0009 #include <linux/property.h>
0010 #include <linux/regmap.h>
0011 #include <media/v4l2-flash-led-class.h>
0012 
0013 #define RT4505_REG_RESET    0x0
0014 #define RT4505_REG_CONFIG   0x8
0015 #define RT4505_REG_ILED     0x9
0016 #define RT4505_REG_ENABLE   0xA
0017 #define RT4505_REG_FLAGS    0xB
0018 
0019 #define RT4505_RESET_MASK   BIT(7)
0020 #define RT4505_FLASHTO_MASK GENMASK(2, 0)
0021 #define RT4505_ITORCH_MASK  GENMASK(7, 5)
0022 #define RT4505_ITORCH_SHIFT 5
0023 #define RT4505_IFLASH_MASK  GENMASK(4, 0)
0024 #define RT4505_ENABLE_MASK  GENMASK(5, 0)
0025 #define RT4505_TORCH_SET    (BIT(0) | BIT(4))
0026 #define RT4505_FLASH_SET    (BIT(0) | BIT(1) | BIT(2) | BIT(4))
0027 #define RT4505_EXT_FLASH_SET    (BIT(0) | BIT(1) | BIT(4) | BIT(5))
0028 #define RT4505_FLASH_GET    (BIT(0) | BIT(1) | BIT(4))
0029 #define RT4505_OVP_MASK     BIT(3)
0030 #define RT4505_SHORT_MASK   BIT(2)
0031 #define RT4505_OTP_MASK     BIT(1)
0032 #define RT4505_TIMEOUT_MASK BIT(0)
0033 
0034 #define RT4505_ITORCH_MINUA 46000
0035 #define RT4505_ITORCH_MAXUA 375000
0036 #define RT4505_ITORCH_STPUA 47000
0037 #define RT4505_IFLASH_MINUA 93750
0038 #define RT4505_IFLASH_MAXUA 1500000
0039 #define RT4505_IFLASH_STPUA 93750
0040 #define RT4505_FLASHTO_MINUS    100000
0041 #define RT4505_FLASHTO_MAXUS    800000
0042 #define RT4505_FLASHTO_STPUS    100000
0043 
0044 struct rt4505_priv {
0045     struct device *dev;
0046     struct regmap *regmap;
0047     struct mutex lock;
0048     struct led_classdev_flash flash;
0049     struct v4l2_flash *v4l2_flash;
0050 };
0051 
0052 static int rt4505_torch_brightness_set(struct led_classdev *lcdev,
0053                        enum led_brightness level)
0054 {
0055     struct rt4505_priv *priv =
0056         container_of(lcdev, struct rt4505_priv, flash.led_cdev);
0057     u32 val = 0;
0058     int ret;
0059 
0060     mutex_lock(&priv->lock);
0061 
0062     if (level != LED_OFF) {
0063         ret = regmap_update_bits(priv->regmap,
0064                      RT4505_REG_ILED, RT4505_ITORCH_MASK,
0065                      (level - 1) << RT4505_ITORCH_SHIFT);
0066         if (ret)
0067             goto unlock;
0068 
0069         val = RT4505_TORCH_SET;
0070     }
0071 
0072     ret = regmap_update_bits(priv->regmap, RT4505_REG_ENABLE,
0073                  RT4505_ENABLE_MASK, val);
0074 
0075 unlock:
0076     mutex_unlock(&priv->lock);
0077     return ret;
0078 }
0079 
0080 static enum led_brightness rt4505_torch_brightness_get(
0081                         struct led_classdev *lcdev)
0082 {
0083     struct rt4505_priv *priv =
0084         container_of(lcdev, struct rt4505_priv, flash.led_cdev);
0085     u32 val;
0086     int ret;
0087 
0088     mutex_lock(&priv->lock);
0089 
0090     ret = regmap_read(priv->regmap, RT4505_REG_ENABLE, &val);
0091     if (ret) {
0092         dev_err(lcdev->dev, "Failed to get LED enable\n");
0093         ret = LED_OFF;
0094         goto unlock;
0095     }
0096 
0097     if ((val & RT4505_ENABLE_MASK) != RT4505_TORCH_SET) {
0098         ret = LED_OFF;
0099         goto unlock;
0100     }
0101 
0102     ret = regmap_read(priv->regmap, RT4505_REG_ILED, &val);
0103     if (ret) {
0104         dev_err(lcdev->dev, "Failed to get LED brightness\n");
0105         ret = LED_OFF;
0106         goto unlock;
0107     }
0108 
0109     ret = ((val & RT4505_ITORCH_MASK) >> RT4505_ITORCH_SHIFT) + 1;
0110 
0111 unlock:
0112     mutex_unlock(&priv->lock);
0113     return ret;
0114 }
0115 
0116 static int rt4505_flash_brightness_set(struct led_classdev_flash *fled_cdev,
0117                        u32 brightness)
0118 {
0119     struct rt4505_priv *priv =
0120         container_of(fled_cdev, struct rt4505_priv, flash);
0121     struct led_flash_setting *s = &fled_cdev->brightness;
0122     u32 val = (brightness - s->min) / s->step;
0123     int ret;
0124 
0125     mutex_lock(&priv->lock);
0126     ret = regmap_update_bits(priv->regmap, RT4505_REG_ILED,
0127                  RT4505_IFLASH_MASK, val);
0128     mutex_unlock(&priv->lock);
0129 
0130     return ret;
0131 }
0132 
0133 static int rt4505_flash_strobe_set(struct led_classdev_flash *fled_cdev,
0134                    bool state)
0135 {
0136     struct rt4505_priv *priv =
0137         container_of(fled_cdev, struct rt4505_priv, flash);
0138     u32 val = state ? RT4505_FLASH_SET : 0;
0139     int ret;
0140 
0141     mutex_lock(&priv->lock);
0142     ret = regmap_update_bits(priv->regmap, RT4505_REG_ENABLE,
0143                  RT4505_ENABLE_MASK, val);
0144     mutex_unlock(&priv->lock);
0145 
0146     return ret;
0147 }
0148 
0149 static int rt4505_flash_strobe_get(struct led_classdev_flash *fled_cdev,
0150                    bool *state)
0151 {
0152     struct rt4505_priv *priv =
0153         container_of(fled_cdev, struct rt4505_priv, flash);
0154     u32 val;
0155     int ret;
0156 
0157     mutex_lock(&priv->lock);
0158 
0159     ret = regmap_read(priv->regmap, RT4505_REG_ENABLE, &val);
0160     if (ret)
0161         goto unlock;
0162 
0163     *state = (val & RT4505_FLASH_GET) == RT4505_FLASH_GET;
0164 
0165 unlock:
0166     mutex_unlock(&priv->lock);
0167     return ret;
0168 }
0169 
0170 static int rt4505_flash_timeout_set(struct led_classdev_flash *fled_cdev,
0171                     u32 timeout)
0172 {
0173     struct rt4505_priv *priv =
0174         container_of(fled_cdev, struct rt4505_priv, flash);
0175     struct led_flash_setting *s = &fled_cdev->timeout;
0176     u32 val = (timeout - s->min) / s->step;
0177     int ret;
0178 
0179     mutex_lock(&priv->lock);
0180     ret = regmap_update_bits(priv->regmap, RT4505_REG_CONFIG,
0181                  RT4505_FLASHTO_MASK, val);
0182     mutex_unlock(&priv->lock);
0183 
0184     return ret;
0185 }
0186 
0187 static int rt4505_fault_get(struct led_classdev_flash *fled_cdev, u32 *fault)
0188 {
0189     struct rt4505_priv *priv =
0190         container_of(fled_cdev, struct rt4505_priv, flash);
0191     u32 val, led_faults = 0;
0192     int ret;
0193 
0194     ret = regmap_read(priv->regmap, RT4505_REG_FLAGS, &val);
0195     if (ret)
0196         return ret;
0197 
0198     if (val & RT4505_OVP_MASK)
0199         led_faults |= LED_FAULT_OVER_VOLTAGE;
0200 
0201     if (val & RT4505_SHORT_MASK)
0202         led_faults |= LED_FAULT_SHORT_CIRCUIT;
0203 
0204     if (val & RT4505_OTP_MASK)
0205         led_faults |= LED_FAULT_OVER_TEMPERATURE;
0206 
0207     if (val & RT4505_TIMEOUT_MASK)
0208         led_faults |= LED_FAULT_TIMEOUT;
0209 
0210     *fault = led_faults;
0211     return 0;
0212 }
0213 
0214 static const struct led_flash_ops rt4505_flash_ops = {
0215     .flash_brightness_set = rt4505_flash_brightness_set,
0216     .strobe_set = rt4505_flash_strobe_set,
0217     .strobe_get = rt4505_flash_strobe_get,
0218     .timeout_set = rt4505_flash_timeout_set,
0219     .fault_get = rt4505_fault_get,
0220 };
0221 
0222 static bool rt4505_is_accessible_reg(struct device *dev, unsigned int reg)
0223 {
0224     if (reg == RT4505_REG_RESET ||
0225         (reg >= RT4505_REG_CONFIG && reg <= RT4505_REG_FLAGS))
0226         return true;
0227     return false;
0228 }
0229 
0230 static const struct regmap_config rt4505_regmap_config = {
0231     .reg_bits = 8,
0232     .val_bits = 8,
0233     .max_register = RT4505_REG_FLAGS,
0234 
0235     .readable_reg = rt4505_is_accessible_reg,
0236     .writeable_reg = rt4505_is_accessible_reg,
0237 };
0238 
0239 #if IS_ENABLED(CONFIG_V4L2_FLASH_LED_CLASS)
0240 static int rt4505_flash_external_strobe_set(struct v4l2_flash *v4l2_flash,
0241                         bool enable)
0242 {
0243     struct led_classdev_flash *flash = v4l2_flash->fled_cdev;
0244     struct rt4505_priv *priv =
0245         container_of(flash, struct rt4505_priv, flash);
0246     u32 val = enable ? RT4505_EXT_FLASH_SET : 0;
0247     int ret;
0248 
0249     mutex_lock(&priv->lock);
0250     ret = regmap_update_bits(priv->regmap, RT4505_REG_ENABLE,
0251                  RT4505_ENABLE_MASK, val);
0252     mutex_unlock(&priv->lock);
0253 
0254     return ret;
0255 }
0256 
0257 static const struct v4l2_flash_ops v4l2_flash_ops = {
0258     .external_strobe_set = rt4505_flash_external_strobe_set,
0259 };
0260 
0261 static void rt4505_init_v4l2_config(struct rt4505_priv *priv,
0262                     struct v4l2_flash_config *config)
0263 {
0264     struct led_classdev_flash *flash = &priv->flash;
0265     struct led_classdev *lcdev = &flash->led_cdev;
0266     struct led_flash_setting *s;
0267 
0268     strscpy(config->dev_name, lcdev->dev->kobj.name,
0269         sizeof(config->dev_name));
0270 
0271     s = &config->intensity;
0272     s->min = RT4505_ITORCH_MINUA;
0273     s->step = RT4505_ITORCH_STPUA;
0274     s->max = s->val = s->min + (lcdev->max_brightness - 1) * s->step;
0275 
0276     config->flash_faults = LED_FAULT_OVER_VOLTAGE |
0277                    LED_FAULT_SHORT_CIRCUIT |
0278                    LED_FAULT_LED_OVER_TEMPERATURE |
0279                    LED_FAULT_TIMEOUT;
0280     config->has_external_strobe = 1;
0281 }
0282 #else
0283 static const struct v4l2_flash_ops v4l2_flash_ops;
0284 static void rt4505_init_v4l2_config(struct rt4505_priv *priv,
0285                     struct v4l2_flash_config *config)
0286 {
0287 }
0288 #endif
0289 
0290 static void rt4505_init_flash_properties(struct rt4505_priv *priv,
0291                      struct fwnode_handle *child)
0292 {
0293     struct led_classdev_flash *flash = &priv->flash;
0294     struct led_classdev *lcdev = &flash->led_cdev;
0295     struct led_flash_setting *s;
0296     u32 val;
0297     int ret;
0298 
0299     ret = fwnode_property_read_u32(child, "led-max-microamp", &val);
0300     if (ret) {
0301         dev_warn(priv->dev, "led-max-microamp DT property missing\n");
0302         val = RT4505_ITORCH_MINUA;
0303     } else
0304         val = clamp_val(val, RT4505_ITORCH_MINUA, RT4505_ITORCH_MAXUA);
0305 
0306     lcdev->max_brightness =
0307         (val - RT4505_ITORCH_MINUA) / RT4505_ITORCH_STPUA + 1;
0308     lcdev->brightness_set_blocking = rt4505_torch_brightness_set;
0309     lcdev->brightness_get = rt4505_torch_brightness_get;
0310     lcdev->flags |= LED_DEV_CAP_FLASH;
0311 
0312     ret = fwnode_property_read_u32(child, "flash-max-microamp", &val);
0313     if (ret) {
0314         dev_warn(priv->dev, "flash-max-microamp DT property missing\n");
0315         val = RT4505_IFLASH_MINUA;
0316     } else
0317         val = clamp_val(val, RT4505_IFLASH_MINUA, RT4505_IFLASH_MAXUA);
0318 
0319     s = &flash->brightness;
0320     s->min = RT4505_IFLASH_MINUA;
0321     s->step = RT4505_IFLASH_STPUA;
0322     s->max = s->val = val;
0323 
0324     ret = fwnode_property_read_u32(child, "flash-max-timeout-us", &val);
0325     if (ret) {
0326         dev_warn(priv->dev,
0327              "flash-max-timeout-us DT property missing\n");
0328         val = RT4505_FLASHTO_MINUS;
0329     } else
0330         val = clamp_val(val, RT4505_FLASHTO_MINUS,
0331                 RT4505_FLASHTO_MAXUS);
0332 
0333     s = &flash->timeout;
0334     s->min = RT4505_FLASHTO_MINUS;
0335     s->step = RT4505_FLASHTO_STPUS;
0336     s->max = s->val = val;
0337 
0338     flash->ops = &rt4505_flash_ops;
0339 }
0340 
0341 static int rt4505_probe(struct i2c_client *client)
0342 {
0343     struct rt4505_priv *priv;
0344     struct fwnode_handle *child;
0345     struct led_init_data init_data = {};
0346     struct v4l2_flash_config v4l2_config = {};
0347     int ret;
0348 
0349     priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
0350     if (!priv)
0351         return -ENOMEM;
0352 
0353     priv->dev = &client->dev;
0354     mutex_init(&priv->lock);
0355 
0356     priv->regmap = devm_regmap_init_i2c(client, &rt4505_regmap_config);
0357     if (IS_ERR(priv->regmap)) {
0358         dev_err(priv->dev, "Failed to allocate register map\n");
0359         return PTR_ERR(priv->regmap);
0360     }
0361 
0362     ret = regmap_write(priv->regmap, RT4505_REG_RESET, RT4505_RESET_MASK);
0363     if (ret) {
0364         dev_err(priv->dev, "Failed to reset registers\n");
0365         return ret;
0366     }
0367 
0368     child = fwnode_get_next_available_child_node(client->dev.fwnode, NULL);
0369     if (!child) {
0370         dev_err(priv->dev, "Failed to get child node\n");
0371         return -EINVAL;
0372     }
0373     init_data.fwnode = child;
0374 
0375     rt4505_init_flash_properties(priv, child);
0376     ret = devm_led_classdev_flash_register_ext(priv->dev, &priv->flash,
0377                            &init_data);
0378     if (ret) {
0379         dev_err(priv->dev, "Failed to register flash\n");
0380         return ret;
0381     }
0382 
0383     rt4505_init_v4l2_config(priv, &v4l2_config);
0384     priv->v4l2_flash = v4l2_flash_init(priv->dev, init_data.fwnode,
0385                        &priv->flash, &v4l2_flash_ops,
0386                        &v4l2_config);
0387     if (IS_ERR(priv->v4l2_flash)) {
0388         dev_err(priv->dev, "Failed to register v4l2 flash\n");
0389         return PTR_ERR(priv->v4l2_flash);
0390     }
0391 
0392     i2c_set_clientdata(client, priv);
0393     return 0;
0394 }
0395 
0396 static int rt4505_remove(struct i2c_client *client)
0397 {
0398     struct rt4505_priv *priv = i2c_get_clientdata(client);
0399 
0400     v4l2_flash_release(priv->v4l2_flash);
0401     return 0;
0402 }
0403 
0404 static void rt4505_shutdown(struct i2c_client *client)
0405 {
0406     struct rt4505_priv *priv = i2c_get_clientdata(client);
0407 
0408     /* Reset registers to make sure all off before shutdown */
0409     regmap_write(priv->regmap, RT4505_REG_RESET, RT4505_RESET_MASK);
0410 }
0411 
0412 static const struct of_device_id __maybe_unused rt4505_leds_match[] = {
0413     { .compatible = "richtek,rt4505", },
0414     {}
0415 };
0416 MODULE_DEVICE_TABLE(of, rt4505_leds_match);
0417 
0418 static struct i2c_driver rt4505_driver = {
0419     .driver = {
0420         .name = "rt4505",
0421         .of_match_table = of_match_ptr(rt4505_leds_match),
0422     },
0423     .probe_new = rt4505_probe,
0424     .remove = rt4505_remove,
0425     .shutdown = rt4505_shutdown,
0426 };
0427 module_i2c_driver(rt4505_driver);
0428 
0429 MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
0430 MODULE_LICENSE("GPL v2");