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

Quelle  leds-ncp5623.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-only
/*
 * NCP5623 Multi-LED Driver
 *
 * Author: Abdel Alkuor <alkuor@gmail.com>
 * Datasheet: https://www.onsemi.com/pdf/datasheet/ncp5623-d.pdf
 */


#include <linux/i2c.h>
#include <linux/module.h>

#include <linux/led-class-multicolor.h>

#define NCP5623_FUNCTION_OFFSET  0x5
#define NCP5623_REG(x)   ((x) << NCP5623_FUNCTION_OFFSET)

#define NCP5623_SHUTDOWN_REG  NCP5623_REG(0x0)
#define NCP5623_ILED_REG  NCP5623_REG(0x1)
#define NCP5623_PWM_REG(index)  NCP5623_REG(0x2 + (index))
#define NCP5623_UPWARD_STEP_REG  NCP5623_REG(0x5)
#define NCP5623_DOWNWARD_STEP_REG NCP5623_REG(0x6)
#define NCP5623_DIMMING_TIME_REG NCP5623_REG(0x7)

#define NCP5623_MAX_BRIGHTNESS  0x1f
#define NCP5623_MAX_DIM_TIME_MS  240
#define NCP5623_DIM_STEP_MS  8

struct ncp5623 {
 struct i2c_client *client;
 struct led_classdev_mc mc_dev;
 struct mutex lock;

 int current_brightness;
 unsigned long delay;
};

static int ncp5623_write(struct i2c_client *client, u8 reg, u8 data)
{
 return i2c_smbus_write_byte_data(client, reg | data, 0);
}

static int ncp5623_brightness_set(struct led_classdev *cdev,
      enum led_brightness brightness)
{
 struct led_classdev_mc *mc_cdev = lcdev_to_mccdev(cdev);
 struct ncp5623 *ncp = container_of(mc_cdev, struct ncp5623, mc_dev);
 int ret;

 guard(mutex)(&ncp->lock);

 if (ncp->delay && time_is_after_jiffies(ncp->delay))
  return -EBUSY;

 ncp->delay = 0;

 for (int i = 0; i < mc_cdev->num_colors; i++) {
  ret = ncp5623_write(ncp->client,
        NCP5623_PWM_REG(mc_cdev->subled_info[i].channel),
        min(mc_cdev->subled_info[i].intensity,
     NCP5623_MAX_BRIGHTNESS));
  if (ret)
   return ret;
 }

 ret = ncp5623_write(ncp->client, NCP5623_DIMMING_TIME_REG, 0);
 if (ret)
  return ret;

 ret = ncp5623_write(ncp->client, NCP5623_ILED_REG, brightness);
 if (ret)
  return ret;

 ncp->current_brightness = brightness;

 return 0;
}

static int ncp5623_pattern_set(struct led_classdev *cdev,
          struct led_pattern *pattern,
          u32 len, int repeat)
{
 struct led_classdev_mc *mc_cdev = lcdev_to_mccdev(cdev);
 struct ncp5623 *ncp = container_of(mc_cdev, struct ncp5623, mc_dev);
 int brightness_diff;
 u8 reg;
 int ret;

 guard(mutex)(&ncp->lock);

 if (ncp->delay && time_is_after_jiffies(ncp->delay))
  return -EBUSY;

 ncp->delay = 0;

 if (pattern[0].delta_t > NCP5623_MAX_DIM_TIME_MS ||
    (pattern[0].delta_t % NCP5623_DIM_STEP_MS) != 0)
  return -EINVAL;

 brightness_diff = pattern[0].brightness - ncp->current_brightness;

 if (brightness_diff == 0)
  return 0;

 if (pattern[0].delta_t) {
  if (brightness_diff > 0)
   reg = NCP5623_UPWARD_STEP_REG;
  else
   reg = NCP5623_DOWNWARD_STEP_REG;
 } else {
  reg = NCP5623_ILED_REG;
 }

 ret = ncp5623_write(ncp->client, reg,
       min(pattern[0].brightness, NCP5623_MAX_BRIGHTNESS));
 if (ret)
  return ret;

 ret = ncp5623_write(ncp->client,
       NCP5623_DIMMING_TIME_REG,
       pattern[0].delta_t / NCP5623_DIM_STEP_MS);
 if (ret)
  return ret;

 /*
 * During testing, when the brightness difference is 1, for some
 * unknown reason, the time factor it takes to change to the new
 * value is the longest time possible. Otherwise, the time factor
 * is simply the brightness difference.
 *
 * For example:
 * current_brightness = 20 and new_brightness = 21 then the time it
 * takes to set the new brightness increments to the maximum possible
 * brightness from 20 then from 0 to 21.
 * time_factor = max_brightness - 20 + 21
 */

 if (abs(brightness_diff) == 1)
  ncp->delay = NCP5623_MAX_BRIGHTNESS + brightness_diff;
 else
  ncp->delay = abs(brightness_diff);

 ncp->delay = msecs_to_jiffies(ncp->delay * pattern[0].delta_t) + jiffies;

 ncp->current_brightness = pattern[0].brightness;

 return 0;
}

static int ncp5623_pattern_clear(struct led_classdev *led_cdev)
{
 return 0;
}

static int ncp5623_probe(struct i2c_client *client)
{
 struct device *dev = &client->dev;
 struct fwnode_handle *mc_node, *led_node;
 struct led_init_data init_data = { };
 struct ncp5623 *ncp;
 struct mc_subled *subled_info;
 unsigned int num_subleds;
 u32 color_index;
 u32 reg;
 int ret;

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

 ncp->client = client;

 mc_node = device_get_named_child_node(dev, "multi-led");
 if (!mc_node)
  return -EINVAL;

 num_subleds = fwnode_get_child_node_count(mc_node);

 subled_info = devm_kcalloc(dev, num_subleds, sizeof(*subled_info), GFP_KERNEL);
 if (!subled_info) {
  ret = -ENOMEM;
  goto release_mc_node;
 }

 fwnode_for_each_available_child_node(mc_node, led_node) {
  ret = fwnode_property_read_u32(led_node, "color", &color_index);
  if (ret)
   goto release_led_node;

  ret = fwnode_property_read_u32(led_node, "reg", ®);
  if (ret)
   goto release_led_node;

  subled_info[ncp->mc_dev.num_colors].channel = reg;
  subled_info[ncp->mc_dev.num_colors++].color_index = color_index;
 }

 init_data.fwnode = mc_node;

 ncp->mc_dev.led_cdev.max_brightness = NCP5623_MAX_BRIGHTNESS;
 ncp->mc_dev.subled_info = subled_info;
 ncp->mc_dev.led_cdev.brightness_set_blocking = ncp5623_brightness_set;
 ncp->mc_dev.led_cdev.pattern_set = ncp5623_pattern_set;
 ncp->mc_dev.led_cdev.pattern_clear = ncp5623_pattern_clear;
 ncp->mc_dev.led_cdev.default_trigger = "pattern";

 mutex_init(&ncp->lock);
 i2c_set_clientdata(client, ncp);

 ret = led_classdev_multicolor_register_ext(dev, &ncp->mc_dev, &init_data);
 if (ret)
  goto destroy_lock;

 return 0;

destroy_lock:
 mutex_destroy(&ncp->lock);

release_mc_node:
 fwnode_handle_put(mc_node);

 return ret;

release_led_node:
 fwnode_handle_put(led_node);
 goto release_mc_node;
}

static void ncp5623_remove(struct i2c_client *client)
{
 struct ncp5623 *ncp = i2c_get_clientdata(client);

 mutex_lock(&ncp->lock);
 ncp->delay = 0;
 mutex_unlock(&ncp->lock);

 ncp5623_write(client, NCP5623_DIMMING_TIME_REG, 0);
 led_classdev_multicolor_unregister(&ncp->mc_dev);
 mutex_destroy(&ncp->lock);
}

static void ncp5623_shutdown(struct i2c_client *client)
{
 struct ncp5623 *ncp = i2c_get_clientdata(client);

 if (!(ncp->mc_dev.led_cdev.flags & LED_RETAIN_AT_SHUTDOWN))
  ncp5623_write(client, NCP5623_SHUTDOWN_REG, 0);

 mutex_destroy(&ncp->lock);
}

static const struct of_device_id ncp5623_id[] = {
 { .compatible = "onnn,ncp5623" },
 { }
};
MODULE_DEVICE_TABLE(of, ncp5623_id);

static struct i2c_driver ncp5623_i2c_driver = {
 .driver = {
  .name = "ncp5623",
  .of_match_table = ncp5623_id,
 },
 .probe = ncp5623_probe,
 .remove = ncp5623_remove,
 .shutdown = ncp5623_shutdown,
};

module_i2c_driver(ncp5623_i2c_driver);

MODULE_AUTHOR("Abdel Alkuor ");
MODULE_DESCRIPTION("NCP5623 Multi-LED driver");
MODULE_LICENSE("GPL");

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

¤ Dauer der Verarbeitung: 0.18 Sekunden  (vorverarbeitet)  ¤

*© 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.