Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |     |   von Columbo akzeptierte Syntax  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  leds-rt4505.c  Sprache: unbekannt

 
// SPDX-License-Identifier: GPL-2.0-only

#include <linux/bitops.h>
#include <linux/i2c.h>
#include <linux/kernel.h>
#include <linux/led-class-flash.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/property.h>
#include <linux/regmap.h>
#include <media/v4l2-flash-led-class.h>

#define RT4505_REG_RESET 0x0
#define RT4505_REG_CONFIG 0x8
#define RT4505_REG_ILED  0x9
#define RT4505_REG_ENABLE 0xA
#define RT4505_REG_FLAGS 0xB

#define RT4505_RESET_MASK BIT(7)
#define RT4505_FLASHTO_MASK GENMASK(2, 0)
#define RT4505_ITORCH_MASK GENMASK(7, 5)
#define RT4505_ITORCH_SHIFT 5
#define RT4505_IFLASH_MASK GENMASK(4, 0)
#define RT4505_ENABLE_MASK GENMASK(5, 0)
#define RT4505_TORCH_SET (BIT(0) | BIT(4))
#define RT4505_FLASH_SET (BIT(0) | BIT(1) | BIT(2) | BIT(4))
#define RT4505_EXT_FLASH_SET (BIT(0) | BIT(1) | BIT(4) | BIT(5))
#define RT4505_FLASH_GET (BIT(0) | BIT(1) | BIT(4))
#define RT4505_OVP_MASK  BIT(3)
#define RT4505_SHORT_MASK BIT(2)
#define RT4505_OTP_MASK  BIT(1)
#define RT4505_TIMEOUT_MASK BIT(0)

#define RT4505_ITORCH_MINUA 46000
#define RT4505_ITORCH_MAXUA 375000
#define RT4505_ITORCH_STPUA 47000
#define RT4505_IFLASH_MINUA 93750
#define RT4505_IFLASH_MAXUA 1500000
#define RT4505_IFLASH_STPUA 93750
#define RT4505_FLASHTO_MINUS 100000
#define RT4505_FLASHTO_MAXUS 800000
#define RT4505_FLASHTO_STPUS 100000

struct rt4505_priv {
 struct device *dev;
 struct regmap *regmap;
 struct mutex lock;
 struct led_classdev_flash flash;
 struct v4l2_flash *v4l2_flash;
};

static int rt4505_torch_brightness_set(struct led_classdev *lcdev,
           enum led_brightness level)
{
 struct rt4505_priv *priv =
  container_of(lcdev, struct rt4505_priv, flash.led_cdev);
 u32 val = 0;
 int ret;

 mutex_lock(&priv->lock);

 if (level != LED_OFF) {
  ret = regmap_update_bits(priv->regmap,
      RT4505_REG_ILED, RT4505_ITORCH_MASK,
      (level - 1) << RT4505_ITORCH_SHIFT);
  if (ret)
   goto unlock;

  val = RT4505_TORCH_SET;
 }

 ret = regmap_update_bits(priv->regmap, RT4505_REG_ENABLE,
     RT4505_ENABLE_MASK, val);

unlock:
 mutex_unlock(&priv->lock);
 return ret;
}

static enum led_brightness rt4505_torch_brightness_get(
      struct led_classdev *lcdev)
{
 struct rt4505_priv *priv =
  container_of(lcdev, struct rt4505_priv, flash.led_cdev);
 u32 val;
 int ret;

 mutex_lock(&priv->lock);

 ret = regmap_read(priv->regmap, RT4505_REG_ENABLE, &val);
 if (ret) {
  dev_err(lcdev->dev, "Failed to get LED enable\n");
  ret = LED_OFF;
  goto unlock;
 }

 if ((val & RT4505_ENABLE_MASK) != RT4505_TORCH_SET) {
  ret = LED_OFF;
  goto unlock;
 }

 ret = regmap_read(priv->regmap, RT4505_REG_ILED, &val);
 if (ret) {
  dev_err(lcdev->dev, "Failed to get LED brightness\n");
  ret = LED_OFF;
  goto unlock;
 }

 ret = ((val & RT4505_ITORCH_MASK) >> RT4505_ITORCH_SHIFT) + 1;

unlock:
 mutex_unlock(&priv->lock);
 return ret;
}

static int rt4505_flash_brightness_set(struct led_classdev_flash *fled_cdev,
           u32 brightness)
{
 struct rt4505_priv *priv =
  container_of(fled_cdev, struct rt4505_priv, flash);
 struct led_flash_setting *s = &fled_cdev->brightness;
 u32 val = (brightness - s->min) / s->step;
 int ret;

 mutex_lock(&priv->lock);
 ret = regmap_update_bits(priv->regmap, RT4505_REG_ILED,
     RT4505_IFLASH_MASK, val);
 mutex_unlock(&priv->lock);

 return ret;
}

static int rt4505_flash_strobe_set(struct led_classdev_flash *fled_cdev,
       bool state)
{
 struct rt4505_priv *priv =
  container_of(fled_cdev, struct rt4505_priv, flash);
 u32 val = state ? RT4505_FLASH_SET : 0;
 int ret;

 mutex_lock(&priv->lock);
 ret = regmap_update_bits(priv->regmap, RT4505_REG_ENABLE,
     RT4505_ENABLE_MASK, val);
 mutex_unlock(&priv->lock);

 return ret;
}

static int rt4505_flash_strobe_get(struct led_classdev_flash *fled_cdev,
       bool *state)
{
 struct rt4505_priv *priv =
  container_of(fled_cdev, struct rt4505_priv, flash);
 u32 val;
 int ret;

 mutex_lock(&priv->lock);

 ret = regmap_read(priv->regmap, RT4505_REG_ENABLE, &val);
 if (ret)
  goto unlock;

 *state = (val & RT4505_FLASH_GET) == RT4505_FLASH_GET;

unlock:
 mutex_unlock(&priv->lock);
 return ret;
}

static int rt4505_flash_timeout_set(struct led_classdev_flash *fled_cdev,
        u32 timeout)
{
 struct rt4505_priv *priv =
  container_of(fled_cdev, struct rt4505_priv, flash);
 struct led_flash_setting *s = &fled_cdev->timeout;
 u32 val = (timeout - s->min) / s->step;
 int ret;

 mutex_lock(&priv->lock);
 ret = regmap_update_bits(priv->regmap, RT4505_REG_CONFIG,
     RT4505_FLASHTO_MASK, val);
 mutex_unlock(&priv->lock);

 return ret;
}

static int rt4505_fault_get(struct led_classdev_flash *fled_cdev, u32 *fault)
{
 struct rt4505_priv *priv =
  container_of(fled_cdev, struct rt4505_priv, flash);
 u32 val, led_faults = 0;
 int ret;

 ret = regmap_read(priv->regmap, RT4505_REG_FLAGS, &val);
 if (ret)
  return ret;

 if (val & RT4505_OVP_MASK)
  led_faults |= LED_FAULT_OVER_VOLTAGE;

 if (val & RT4505_SHORT_MASK)
  led_faults |= LED_FAULT_SHORT_CIRCUIT;

 if (val & RT4505_OTP_MASK)
  led_faults |= LED_FAULT_OVER_TEMPERATURE;

 if (val & RT4505_TIMEOUT_MASK)
  led_faults |= LED_FAULT_TIMEOUT;

 *fault = led_faults;
 return 0;
}

static const struct led_flash_ops rt4505_flash_ops = {
 .flash_brightness_set = rt4505_flash_brightness_set,
 .strobe_set = rt4505_flash_strobe_set,
 .strobe_get = rt4505_flash_strobe_get,
 .timeout_set = rt4505_flash_timeout_set,
 .fault_get = rt4505_fault_get,
};

static bool rt4505_is_accessible_reg(struct device *dev, unsigned int reg)
{
 if (reg == RT4505_REG_RESET ||
  (reg >= RT4505_REG_CONFIG && reg <= RT4505_REG_FLAGS))
  return true;
 return false;
}

static const struct regmap_config rt4505_regmap_config = {
 .reg_bits = 8,
 .val_bits = 8,
 .max_register = RT4505_REG_FLAGS,

 .readable_reg = rt4505_is_accessible_reg,
 .writeable_reg = rt4505_is_accessible_reg,
};

#if IS_ENABLED(CONFIG_V4L2_FLASH_LED_CLASS)
static int rt4505_flash_external_strobe_set(struct v4l2_flash *v4l2_flash,
         bool enable)
{
 struct led_classdev_flash *flash = v4l2_flash->fled_cdev;
 struct rt4505_priv *priv =
  container_of(flash, struct rt4505_priv, flash);
 u32 val = enable ? RT4505_EXT_FLASH_SET : 0;
 int ret;

 mutex_lock(&priv->lock);
 ret = regmap_update_bits(priv->regmap, RT4505_REG_ENABLE,
     RT4505_ENABLE_MASK, val);
 mutex_unlock(&priv->lock);

 return ret;
}

static const struct v4l2_flash_ops v4l2_flash_ops = {
 .external_strobe_set = rt4505_flash_external_strobe_set,
};

static void rt4505_init_v4l2_config(struct rt4505_priv *priv,
        struct v4l2_flash_config *config)
{
 struct led_classdev_flash *flash = &priv->flash;
 struct led_classdev *lcdev = &flash->led_cdev;
 struct led_flash_setting *s;

 strscpy(config->dev_name, lcdev->dev->kobj.name,
  sizeof(config->dev_name));

 s = &config->intensity;
 s->min = RT4505_ITORCH_MINUA;
 s->step = RT4505_ITORCH_STPUA;
 s->max = s->val = s->min + (lcdev->max_brightness - 1) * s->step;

 config->flash_faults = LED_FAULT_OVER_VOLTAGE |
          LED_FAULT_SHORT_CIRCUIT |
          LED_FAULT_LED_OVER_TEMPERATURE |
          LED_FAULT_TIMEOUT;
 config->has_external_strobe = 1;
}
#else
static const struct v4l2_flash_ops v4l2_flash_ops;
static void rt4505_init_v4l2_config(struct rt4505_priv *priv,
        struct v4l2_flash_config *config)
{
}
#endif

static void rt4505_init_flash_properties(struct rt4505_priv *priv,
      struct fwnode_handle *child)
{
 struct led_classdev_flash *flash = &priv->flash;
 struct led_classdev *lcdev = &flash->led_cdev;
 struct led_flash_setting *s;
 u32 val;
 int ret;

 ret = fwnode_property_read_u32(child, "led-max-microamp", &val);
 if (ret) {
  dev_warn(priv->dev, "led-max-microamp DT property missing\n");
  val = RT4505_ITORCH_MINUA;
 } else
  val = clamp_val(val, RT4505_ITORCH_MINUA, RT4505_ITORCH_MAXUA);

 lcdev->max_brightness =
  (val - RT4505_ITORCH_MINUA) / RT4505_ITORCH_STPUA + 1;
 lcdev->brightness_set_blocking = rt4505_torch_brightness_set;
 lcdev->brightness_get = rt4505_torch_brightness_get;
 lcdev->flags |= LED_DEV_CAP_FLASH;

 ret = fwnode_property_read_u32(child, "flash-max-microamp", &val);
 if (ret) {
  dev_warn(priv->dev, "flash-max-microamp DT property missing\n");
  val = RT4505_IFLASH_MINUA;
 } else
  val = clamp_val(val, RT4505_IFLASH_MINUA, RT4505_IFLASH_MAXUA);

 s = &flash->brightness;
 s->min = RT4505_IFLASH_MINUA;
 s->step = RT4505_IFLASH_STPUA;
 s->max = s->val = val;

 ret = fwnode_property_read_u32(child, "flash-max-timeout-us", &val);
 if (ret) {
  dev_warn(priv->dev,
    "flash-max-timeout-us DT property missing\n");
  val = RT4505_FLASHTO_MINUS;
 } else
  val = clamp_val(val, RT4505_FLASHTO_MINUS,
    RT4505_FLASHTO_MAXUS);

 s = &flash->timeout;
 s->min = RT4505_FLASHTO_MINUS;
 s->step = RT4505_FLASHTO_STPUS;
 s->max = s->val = val;

 flash->ops = &rt4505_flash_ops;
}

static int rt4505_probe(struct i2c_client *client)
{
 struct rt4505_priv *priv;
 struct fwnode_handle *child;
 struct led_init_data init_data = {};
 struct v4l2_flash_config v4l2_config = {};
 int ret;

 priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
 if (!priv)
  return -ENOMEM;

 priv->dev = &client->dev;
 mutex_init(&priv->lock);

 priv->regmap = devm_regmap_init_i2c(client, &rt4505_regmap_config);
 if (IS_ERR(priv->regmap)) {
  dev_err(priv->dev, "Failed to allocate register map\n");
  return PTR_ERR(priv->regmap);
 }

 ret = regmap_write(priv->regmap, RT4505_REG_RESET, RT4505_RESET_MASK);
 if (ret) {
  dev_err(priv->dev, "Failed to reset registers\n");
  return ret;
 }

 child = fwnode_get_next_available_child_node(client->dev.fwnode, NULL);
 if (!child) {
  dev_err(priv->dev, "Failed to get child node\n");
  return -EINVAL;
 }
 init_data.fwnode = child;

 rt4505_init_flash_properties(priv, child);
 ret = devm_led_classdev_flash_register_ext(priv->dev, &priv->flash,
         &init_data);
 if (ret) {
  dev_err(priv->dev, "Failed to register flash\n");
  return ret;
 }

 rt4505_init_v4l2_config(priv, &v4l2_config);
 priv->v4l2_flash = v4l2_flash_init(priv->dev, init_data.fwnode,
        &priv->flash, &v4l2_flash_ops,
        &v4l2_config);
 if (IS_ERR(priv->v4l2_flash)) {
  dev_err(priv->dev, "Failed to register v4l2 flash\n");
  return PTR_ERR(priv->v4l2_flash);
 }

 i2c_set_clientdata(client, priv);
 return 0;
}

static void rt4505_remove(struct i2c_client *client)
{
 struct rt4505_priv *priv = i2c_get_clientdata(client);

 v4l2_flash_release(priv->v4l2_flash);
}

static void rt4505_shutdown(struct i2c_client *client)
{
 struct rt4505_priv *priv = i2c_get_clientdata(client);

 /* Reset registers to make sure all off before shutdown */
 regmap_write(priv->regmap, RT4505_REG_RESET, RT4505_RESET_MASK);
}

static const struct of_device_id __maybe_unused rt4505_leds_match[] = {
 { .compatible = "richtek,rt4505", },
 {}
};
MODULE_DEVICE_TABLE(of, rt4505_leds_match);

static struct i2c_driver rt4505_driver = {
 .driver = {
  .name = "rt4505",
  .of_match_table = of_match_ptr(rt4505_leds_match),
 },
 .probe = rt4505_probe,
 .remove = rt4505_remove,
 .shutdown = rt4505_shutdown,
};
module_i2c_driver(rt4505_driver);

MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
MODULE_DESCRIPTION("Richtek RT4505 LED driver");
MODULE_LICENSE("GPL v2");

Messung V0.5 in Prozent
C=100 H=95 G=97

[zur Elbe Produktseite wechseln0.8QuellennavigatorsAnalyse erneut starten2026-09-28]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Statistik
#Sources=1126864
#Domains=2039723