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