Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/leds/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 7 kB image not shown  

Quelle  leds-max77705.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0
/*
 * Based on leds-max77650 driver
 *
 * LED driver for MAXIM 77705 PMIC.
 * Copyright (C) 2025 Dzmitry Sankouski <dsankouski@gmail.org>
 */


#include <linux/i2c.h>
#include <linux/led-class-multicolor.h>
#include <linux/leds.h>
#include <linux/mfd/max77705-private.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>

#define MAX77705_LED_NUM_LEDS   4
#define MAX77705_LED_EN_MASK   GENMASK(1, 0)
#define MAX77705_LED_MAX_BRIGHTNESS  0xff
#define MAX77705_LED_EN_SHIFT(reg)  (reg * MAX77705_RGBLED_EN_WIDTH)
#define MAX77705_LED_REG_BRIGHTNESS(reg) (reg + MAX77705_RGBLED_REG_LED0BRT)

struct max77705_led {
 struct led_classdev cdev;
 struct led_classdev_mc mcdev;
 struct regmap *regmap;

 struct mc_subled *subled_info;
};

static const struct regmap_config max77705_leds_regmap_config = {
 .reg_base = MAX77705_RGBLED_REG_BASE,
 .reg_bits = 8,
 .val_bits = 8,
 .max_register = MAX77705_LED_REG_END,
};

static int max77705_rgb_blink(struct led_classdev *cdev,
    unsigned long *delay_on,
    unsigned long *delay_off)
{
 struct max77705_led *led = container_of(cdev, struct max77705_led, cdev);
 int value, on_value, off_value;

 if (*delay_on < MAX77705_RGB_DELAY_100_STEP)
  on_value = 0;
 else if (*delay_on < MAX77705_RGB_DELAY_100_STEP_LIM)
  on_value = *delay_on / MAX77705_RGB_DELAY_100_STEP - 1;
 else if (*delay_on < MAX77705_RGB_DELAY_250_STEP_LIM)
  on_value = (*delay_on - MAX77705_RGB_DELAY_100_STEP_LIM) /
    MAX77705_RGB_DELAY_250_STEP +
    MAX77705_RGB_DELAY_100_STEP_COUNT;
 else
  on_value = 15;

 on_value <<= 4;

 if (*delay_off < 1)
  off_value = 0;
 else if (*delay_off < MAX77705_RGB_DELAY_500_STEP)
  off_value = 1;
 else if (*delay_off < MAX77705_RGB_DELAY_500_STEP_LIM)
  off_value = *delay_off / MAX77705_RGB_DELAY_500_STEP;
 else if (*delay_off < MAX77705_RGB_DELAY_1000_STEP_LIM)
  off_value = (*delay_off - MAX77705_RGB_DELAY_1000_STEP_LIM) /
    MAX77705_RGB_DELAY_1000_STEP +
    MAX77705_RGB_DELAY_500_STEP_COUNT;
 else if (*delay_off < MAX77705_RGB_DELAY_2000_STEP_LIM)
  off_value = (*delay_off - MAX77705_RGB_DELAY_2000_STEP_LIM) /
    MAX77705_RGB_DELAY_2000_STEP +
    MAX77705_RGB_DELAY_1000_STEP_COUNT;
 else
  off_value = 15;

 value = on_value | off_value;
 return regmap_write(led->regmap, MAX77705_RGBLED_REG_LEDBLNK, value);
}

static int max77705_led_brightness_set(struct regmap *regmap, struct mc_subled *subled,
    int num_colors)
{
 int ret;

 for (int i = 0; i < num_colors; i++) {
  unsigned int channel, brightness;

  channel = subled[i].channel;
  brightness = subled[i].brightness;

  if (brightness == LED_OFF) {
   /* Flash OFF */
   ret = regmap_update_bits(regmap,
     MAX77705_RGBLED_REG_LEDEN,
     MAX77705_LED_EN_MASK << MAX77705_LED_EN_SHIFT(channel), 0);
  } else {
   /* Set current */
   ret = regmap_write(regmap, MAX77705_LED_REG_BRIGHTNESS(channel),
     brightness);
   if (ret < 0)
    return ret;

   ret = regmap_update_bits(regmap,
     MAX77705_RGBLED_REG_LEDEN,
     LED_ON << MAX77705_LED_EN_SHIFT(channel),
     MAX77705_LED_EN_MASK << MAX77705_LED_EN_SHIFT(channel));
  }
 }

 return ret;
}

static int max77705_led_brightness_set_single(struct led_classdev *cdev,
     enum led_brightness brightness)
{
 struct max77705_led *led = container_of(cdev, struct max77705_led, cdev);

 led->subled_info->brightness = brightness;

 return max77705_led_brightness_set(led->regmap, led->subled_info, 1);
}

static int max77705_led_brightness_set_multi(struct led_classdev *cdev,
     enum led_brightness brightness)
{
 struct led_classdev_mc *mcdev = lcdev_to_mccdev(cdev);
 struct max77705_led *led = container_of(mcdev, struct max77705_led, mcdev);

 led_mc_calc_color_components(mcdev, brightness);

 return max77705_led_brightness_set(led->regmap, led->mcdev.subled_info, mcdev->num_colors);
}

static int max77705_parse_subled(struct device *dev, struct fwnode_handle *np,
    struct mc_subled *info)
{
 u32 color = LED_COLOR_ID_GREEN;
 u32 reg;
 int ret;

 ret = fwnode_property_read_u32(np, "reg", ®);
 if (ret || !reg || reg >= MAX77705_LED_NUM_LEDS)
  return dev_err_probe(dev, -EINVAL, "invalid \"reg\" of %pOFn\n", np);

 info->channel = reg;

 ret = fwnode_property_read_u32(np, "color", &color);
 if (ret < 0 && ret != -EINVAL)
  return dev_err_probe(dev, ret,
         "failed to parse \"color\" of %pOF\n", np);

 info->color_index = color;

 return 0;
}

static int max77705_add_led(struct device *dev, struct regmap *regmap, struct fwnode_handle *np)
{
 int ret, i = 0;
 unsigned int color, reg;
 struct max77705_led *led;
 struct led_classdev *cdev;
 struct mc_subled *info;
 struct fwnode_handle *child;
 struct led_init_data init_data = {};

 led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
 if (!led)
  return -ENOMEM;

 ret = fwnode_property_read_u32(np, "color", &color);
 if (ret < 0 && ret != -EINVAL)
  return dev_err_probe(dev, ret,
         "failed to parse \"color\" of %pOF\n", np);

 led->regmap = regmap;
 init_data.fwnode = np;

 if (color == LED_COLOR_ID_RGB) {
  int num_channels = of_get_available_child_count(to_of_node(np));

  ret = fwnode_property_read_u32(np, "reg", ®);
  if (ret || reg >= MAX77705_LED_NUM_LEDS)
   return -EINVAL;

  info = devm_kcalloc(dev, num_channels, sizeof(*info), GFP_KERNEL);
  if (!info)
   return -ENOMEM;

  cdev = &led->mcdev.led_cdev;
  cdev->max_brightness = MAX77705_LED_MAX_BRIGHTNESS;
  cdev->brightness_set_blocking = max77705_led_brightness_set_multi;
  cdev->blink_set = max77705_rgb_blink;

  fwnode_for_each_available_child_node(np, child) {
   ret = max77705_parse_subled(dev, child, &info[i]);
   if (ret < 0)
    return ret;

   info[i].intensity = 0;
   i++;
  }

  led->mcdev.subled_info = info;
  led->mcdev.num_colors = num_channels;
  led->cdev = *cdev;

  ret = devm_led_classdev_multicolor_register_ext(dev, &led->mcdev, &init_data);
  if (ret)
   return ret;

  ret = max77705_led_brightness_set_multi(&led->cdev, LED_OFF);
  if (ret)
   return ret;
 } else {
  info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
  if (!info)
   return -ENOMEM;

  max77705_parse_subled(dev, np, info);

  led->subled_info = info;
  led->cdev.brightness_set_blocking = max77705_led_brightness_set_single;
  led->cdev.blink_set = max77705_rgb_blink;
  led->cdev.max_brightness = MAX77705_LED_MAX_BRIGHTNESS;

  ret = devm_led_classdev_register_ext(dev, &led->cdev, &init_data);
  if (ret)
   return ret;

  ret = max77705_led_brightness_set_single(&led->cdev, LED_OFF);
  if (ret)
   return ret;
 }

 return 0;
}

static int max77705_led_probe(struct platform_device *pdev)
{
 struct device *dev = &pdev->dev;
 struct i2c_client *i2c = to_i2c_client(pdev->dev.parent);
 struct regmap *regmap;
 int ret;

 regmap = devm_regmap_init_i2c(i2c, &max77705_leds_regmap_config);
 if (IS_ERR(regmap))
  return dev_err_probe(dev, PTR_ERR(regmap), "Failed to register LEDs regmap\n");

 device_for_each_child_node_scoped(dev, child) {
  ret = max77705_add_led(dev, regmap, child);
  if (ret)
   return ret;
 }

 return 0;
}

static const struct of_device_id max77705_led_of_match[] = {
 { .compatible = "maxim,max77705-rgb" },
 { }
};
MODULE_DEVICE_TABLE(of, max77705_led_of_match);

static struct platform_driver max77705_led_driver = {
 .driver = {
  .name = "max77705-led",
  .of_match_table = max77705_led_of_match,
 },
 .probe = max77705_led_probe,
};
module_platform_driver(max77705_led_driver);

MODULE_DESCRIPTION("Maxim MAX77705 LED driver");
MODULE_AUTHOR("Dzmitry Sankouski ");
MODULE_LICENSE("GPL");

Messung V0.5
C=95 H=95 G=94

¤ Dauer der Verarbeitung: 0.3 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.