uboot/drivers/video/pwm_backlight.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2016 Google, Inc
   3 * Written by Simon Glass <sjg@chromium.org>
   4 *
   5 * SPDX-License-Identifier:     GPL-2.0+
   6 */
   7
   8#include <common.h>
   9#include <dm.h>
  10#include <backlight.h>
  11#include <pwm.h>
  12#include <asm/gpio.h>
  13#include <power/regulator.h>
  14
  15DECLARE_GLOBAL_DATA_PTR;
  16
  17struct pwm_backlight_priv {
  18        struct udevice *reg;
  19        struct gpio_desc enable;
  20        struct udevice *pwm;
  21        uint channel;
  22        uint period_ns;
  23        uint default_level;
  24        uint min_level;
  25        uint max_level;
  26};
  27
  28static int pwm_backlight_enable(struct udevice *dev)
  29{
  30        struct pwm_backlight_priv *priv = dev_get_priv(dev);
  31        uint duty_cycle;
  32        int ret;
  33
  34        debug("%s: Enable '%s', regulator '%s'\n", __func__, dev->name,
  35              priv->reg->name);
  36        ret = regulator_set_enable(priv->reg, true);
  37        if (ret) {
  38                debug("%s: Cannot enable regulator for PWM '%s'\n", __func__,
  39                      dev->name);
  40                return ret;
  41        }
  42        mdelay(120);
  43
  44        duty_cycle = priv->period_ns * (priv->default_level - priv->min_level) /
  45                (priv->max_level - priv->min_level + 1);
  46        ret = pwm_set_config(priv->pwm, priv->channel, priv->period_ns,
  47                             duty_cycle);
  48        if (ret)
  49                return ret;
  50        ret = pwm_set_enable(priv->pwm, priv->channel, true);
  51        if (ret)
  52                return ret;
  53        mdelay(10);
  54        dm_gpio_set_value(&priv->enable, 1);
  55
  56        return 0;
  57}
  58
  59static int pwm_backlight_ofdata_to_platdata(struct udevice *dev)
  60{
  61        struct pwm_backlight_priv *priv = dev_get_priv(dev);
  62        struct fdtdec_phandle_args args;
  63        const void *blob = gd->fdt_blob;
  64        int node = dev->of_offset;
  65        int index, ret, count, len;
  66        const u32 *cell;
  67
  68        ret = uclass_get_device_by_phandle(UCLASS_REGULATOR, dev,
  69                                           "power-supply", &priv->reg);
  70        if (ret) {
  71                debug("%s: Cannot get power supply: ret=%d\n", __func__, ret);
  72                return ret;
  73        }
  74        ret = gpio_request_by_name(dev, "enable-gpios", 0, &priv->enable,
  75                                   GPIOD_IS_OUT);
  76        if (ret) {
  77                debug("%s: Warning: cannot get enable GPIO: ret=%d\n",
  78                      __func__, ret);
  79                if (ret != -ENOENT)
  80                        return ret;
  81        }
  82        ret = fdtdec_parse_phandle_with_args(blob, node, "pwms", "#pwm-cells",
  83                                             0, 0, &args);
  84        if (ret) {
  85                debug("%s: Cannot get PWM phandle: ret=%d\n", __func__, ret);
  86                return ret;
  87        }
  88
  89        ret = uclass_get_device_by_of_offset(UCLASS_PWM, args.node, &priv->pwm);
  90        if (ret) {
  91                debug("%s: Cannot get PWM: ret=%d\n", __func__, ret);
  92                return ret;
  93        }
  94        priv->channel = args.args[0];
  95        priv->period_ns = args.args[1];
  96
  97        index = fdtdec_get_int(blob, node, "default-brightness-level", 255);
  98        cell = fdt_getprop(blob, node, "brightness-levels", &len);
  99        count = len / sizeof(u32);
 100        if (cell && count > index) {
 101                priv->default_level = fdt32_to_cpu(cell[index]);
 102                priv->max_level = fdt32_to_cpu(cell[count - 1]);
 103        } else {
 104                priv->default_level = index;
 105                priv->max_level = 255;
 106        }
 107
 108
 109        return 0;
 110}
 111
 112static int pwm_backlight_probe(struct udevice *dev)
 113{
 114        return 0;
 115}
 116
 117static const struct backlight_ops pwm_backlight_ops = {
 118        .enable = pwm_backlight_enable,
 119};
 120
 121static const struct udevice_id pwm_backlight_ids[] = {
 122        { .compatible = "pwm-backlight" },
 123        { }
 124};
 125
 126U_BOOT_DRIVER(pwm_backlight) = {
 127        .name   = "pwm_backlight",
 128        .id     = UCLASS_PANEL_BACKLIGHT,
 129        .of_match = pwm_backlight_ids,
 130        .ops    = &pwm_backlight_ops,
 131        .ofdata_to_platdata     = pwm_backlight_ofdata_to_platdata,
 132        .probe          = pwm_backlight_probe,
 133        .priv_auto_alloc_size   = sizeof(struct pwm_backlight_priv),
 134};
 135