uboot/drivers/led/led_gpio.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (c) 2015 Google, Inc
   4 * Written by Simon Glass <sjg@chromium.org>
   5 */
   6
   7#include <common.h>
   8#include <dm.h>
   9#include <errno.h>
  10#include <led.h>
  11#include <log.h>
  12#include <malloc.h>
  13#include <asm/gpio.h>
  14#include <dm/lists.h>
  15
  16struct led_gpio_priv {
  17        struct gpio_desc gpio;
  18};
  19
  20static int gpio_led_set_state(struct udevice *dev, enum led_state_t state)
  21{
  22        struct led_gpio_priv *priv = dev_get_priv(dev);
  23        int ret;
  24
  25        if (!dm_gpio_is_valid(&priv->gpio))
  26                return -EREMOTEIO;
  27        switch (state) {
  28        case LEDST_OFF:
  29        case LEDST_ON:
  30                break;
  31        case LEDST_TOGGLE:
  32                ret = dm_gpio_get_value(&priv->gpio);
  33                if (ret < 0)
  34                        return ret;
  35                state = !ret;
  36                break;
  37        default:
  38                return -ENOSYS;
  39        }
  40
  41        return dm_gpio_set_value(&priv->gpio, state);
  42}
  43
  44static enum led_state_t gpio_led_get_state(struct udevice *dev)
  45{
  46        struct led_gpio_priv *priv = dev_get_priv(dev);
  47        int ret;
  48
  49        if (!dm_gpio_is_valid(&priv->gpio))
  50                return -EREMOTEIO;
  51        ret = dm_gpio_get_value(&priv->gpio);
  52        if (ret < 0)
  53                return ret;
  54
  55        return ret ? LEDST_ON : LEDST_OFF;
  56}
  57
  58static int led_gpio_probe(struct udevice *dev)
  59{
  60        struct led_uc_plat *uc_plat = dev_get_uclass_plat(dev);
  61        struct led_gpio_priv *priv = dev_get_priv(dev);
  62        int ret;
  63
  64        /* Ignore the top-level LED node */
  65        if (!uc_plat->label)
  66                return 0;
  67
  68        ret = gpio_request_by_name(dev, "gpios", 0, &priv->gpio, GPIOD_IS_OUT);
  69        if (ret)
  70                return ret;
  71
  72        return 0;
  73}
  74
  75static int led_gpio_remove(struct udevice *dev)
  76{
  77        /*
  78         * The GPIO driver may have already been removed. We will need to
  79         * address this more generally.
  80         */
  81#ifndef CONFIG_SANDBOX
  82        struct led_gpio_priv *priv = dev_get_priv(dev);
  83
  84        if (dm_gpio_is_valid(&priv->gpio))
  85                dm_gpio_free(dev, &priv->gpio);
  86#endif
  87
  88        return 0;
  89}
  90
  91static int led_gpio_bind(struct udevice *parent)
  92{
  93        struct udevice *dev;
  94        ofnode node;
  95        int ret;
  96
  97        dev_for_each_subnode(node, parent) {
  98                struct led_uc_plat *uc_plat;
  99                const char *label;
 100
 101                label = ofnode_read_string(node, "label");
 102                if (!label)
 103                        label = ofnode_get_name(node);
 104                ret = device_bind_driver_to_node(parent, "gpio_led",
 105                                                 ofnode_get_name(node),
 106                                                 node, &dev);
 107                if (ret)
 108                        return ret;
 109                uc_plat = dev_get_uclass_plat(dev);
 110                uc_plat->label = label;
 111        }
 112
 113        return 0;
 114}
 115
 116static const struct led_ops gpio_led_ops = {
 117        .set_state      = gpio_led_set_state,
 118        .get_state      = gpio_led_get_state,
 119};
 120
 121static const struct udevice_id led_gpio_ids[] = {
 122        { .compatible = "gpio-leds" },
 123        { }
 124};
 125
 126U_BOOT_DRIVER(led_gpio) = {
 127        .name   = "gpio_led",
 128        .id     = UCLASS_LED,
 129        .of_match = led_gpio_ids,
 130        .ops    = &gpio_led_ops,
 131        .priv_auto      = sizeof(struct led_gpio_priv),
 132        .bind   = led_gpio_bind,
 133        .probe  = led_gpio_probe,
 134        .remove = led_gpio_remove,
 135};
 136