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 5 kB image not shown  

Quelle  leds-bcm6358.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * Driver for BCM6358 memory-mapped LEDs, based on leds-syscon.c
 *
 * Copyright 2015 Álvaro Fernández Rojas <noltari@gmail.com>
 */

#include <linux/delay.h>
#include <linux/io.h>
#include <linux/leds.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>

#define BCM6358_REG_MODE  0x0
#define BCM6358_REG_CTRL  0x4

#define BCM6358_SLED_CLKDIV_MASK 3
#define BCM6358_SLED_CLKDIV_1  0
#define BCM6358_SLED_CLKDIV_2  1
#define BCM6358_SLED_CLKDIV_4  2
#define BCM6358_SLED_CLKDIV_8  3

#define BCM6358_SLED_POLARITY  BIT(2)
#define BCM6358_SLED_BUSY  BIT(3)

#define BCM6358_SLED_MAX_COUNT  32
#define BCM6358_SLED_WAIT  100

/**
 * struct bcm6358_led - state container for bcm6358 based LEDs
 * @cdev: LED class device for this LED
 * @mem: memory resource
 * @lock: memory lock
 * @pin: LED pin number
 * @active_low: LED is active low
 */

struct bcm6358_led {
 struct led_classdev cdev;
 void __iomem *mem;
 spinlock_t *lock;
 unsigned long pin;
 bool active_low;
};

static void bcm6358_led_write(void __iomem *reg, unsigned long data)
{
#ifdef CONFIG_CPU_BIG_ENDIAN
 iowrite32be(data, reg);
#else
 writel(data, reg);
#endif
}

static unsigned long bcm6358_led_read(void __iomem *reg)
{
#ifdef CONFIG_CPU_BIG_ENDIAN
 return ioread32be(reg);
#else
 return readl(reg);
#endif
}

static unsigned long bcm6358_led_busy(void __iomem *mem)
{
 unsigned long val;

 while ((val = bcm6358_led_read(mem + BCM6358_REG_CTRL)) &
  BCM6358_SLED_BUSY)
  udelay(BCM6358_SLED_WAIT);

 return val;
}

static void bcm6358_led_set(struct led_classdev *led_cdev,
       enum led_brightness value)
{
 struct bcm6358_led *led =
  container_of(led_cdev, struct bcm6358_led, cdev);
 unsigned long flags, val;

 spin_lock_irqsave(led->lock, flags);
 bcm6358_led_busy(led->mem);
 val = bcm6358_led_read(led->mem + BCM6358_REG_MODE);
 if ((led->active_low && value == LED_OFF) ||
     (!led->active_low && value != LED_OFF))
  val |= BIT(led->pin);
 else
  val &= ~(BIT(led->pin));
 bcm6358_led_write(led->mem + BCM6358_REG_MODE, val);
 spin_unlock_irqrestore(led->lock, flags);
}

static int bcm6358_led(struct device *dev, struct device_node *nc, u32 reg,
         void __iomem *mem, spinlock_t *lock)
{
 struct led_init_data init_data = {};
 struct bcm6358_led *led;
 enum led_default_state state;
 unsigned long val;
 int rc;

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

 led->pin = reg;
 led->mem = mem;
 led->lock = lock;

 if (of_property_read_bool(nc, "active-low"))
  led->active_low = true;

 init_data.fwnode = of_fwnode_handle(nc);

 state = led_init_default_state_get(init_data.fwnode);
 switch (state) {
 case LEDS_DEFSTATE_ON:
  led->cdev.brightness = LED_FULL;
  break;
 case LEDS_DEFSTATE_KEEP:
  val = bcm6358_led_read(led->mem + BCM6358_REG_MODE);
  val &= BIT(led->pin);
  if ((led->active_low && !val) || (!led->active_low && val))
   led->cdev.brightness = LED_FULL;
  else
   led->cdev.brightness = LED_OFF;
  break;
 default:
  led->cdev.brightness = LED_OFF;
 }

 bcm6358_led_set(&led->cdev, led->cdev.brightness);

 led->cdev.brightness_set = bcm6358_led_set;

 rc = devm_led_classdev_register_ext(dev, &led->cdev, &init_data);
 if (rc < 0)
  return rc;

 dev_dbg(dev, "registered LED %s\n", led->cdev.name);

 return 0;
}

static int bcm6358_leds_probe(struct platform_device *pdev)
{
 struct device *dev = &pdev->dev;
 struct device_node *np = dev_of_node(&pdev->dev);
 void __iomem *mem;
 spinlock_t *lock; /* memory lock */
 unsigned long val;
 u32 clk_div;

 mem = devm_platform_ioremap_resource(pdev, 0);
 if (IS_ERR(mem))
  return PTR_ERR(mem);

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

 spin_lock_init(lock);

 val = bcm6358_led_busy(mem);
 val &= ~(BCM6358_SLED_POLARITY | BCM6358_SLED_CLKDIV_MASK);
 if (of_property_read_bool(np, "brcm,clk-dat-low"))
  val |= BCM6358_SLED_POLARITY;
 of_property_read_u32(np, "brcm,clk-div", &clk_div);
 switch (clk_div) {
 case 8:
  val |= BCM6358_SLED_CLKDIV_8;
  break;
 case 4:
  val |= BCM6358_SLED_CLKDIV_4;
  break;
 case 2:
  val |= BCM6358_SLED_CLKDIV_2;
  break;
 default:
  val |= BCM6358_SLED_CLKDIV_1;
  break;
 }
 bcm6358_led_write(mem + BCM6358_REG_CTRL, val);

 for_each_available_child_of_node_scoped(np, child) {
  int rc;
  u32 reg;

  if (of_property_read_u32(child, "reg", ®))
   continue;

  if (reg >= BCM6358_SLED_MAX_COUNT) {
   dev_err(dev, "invalid LED (%u >= %d)\n", reg,
    BCM6358_SLED_MAX_COUNT);
   continue;
  }

  rc = bcm6358_led(dev, child, reg, mem, lock);
  if (rc < 0)
   return rc;
 }

 return 0;
}

static const struct of_device_id bcm6358_leds_of_match[] = {
 { .compatible = "brcm,bcm6358-leds", },
 { },
};
MODULE_DEVICE_TABLE(of, bcm6358_leds_of_match);

static struct platform_driver bcm6358_leds_driver = {
 .probe = bcm6358_leds_probe,
 .driver = {
  .name = "leds-bcm6358",
  .of_match_table = bcm6358_leds_of_match,
 },
};

module_platform_driver(bcm6358_leds_driver);

MODULE_AUTHOR("Álvaro Fernández Rojas ");
MODULE_DESCRIPTION("LED driver for BCM6358 controllers");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:leds-bcm6358");

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

¤ Dauer der Verarbeitung: 0.10 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.