uboot/drivers/power/regulator/pwm_regulator.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2016 Rockchip Electronics Co., Ltd
   4 *
   5 * Based on kernel drivers/regulator/pwm-regulator.c
   6 * Copyright (C) 2014 - STMicroelectronics Inc.
   7 * Author: Lee Jones <lee.jones@linaro.org>
   8 */
   9
  10#include <common.h>
  11#include <dm.h>
  12#include <errno.h>
  13#include <pwm.h>
  14#include <power/regulator.h>
  15#include <linux/libfdt.h>
  16#include <fdt_support.h>
  17#include <fdtdec.h>
  18
  19DECLARE_GLOBAL_DATA_PTR;
  20
  21struct pwm_regulator_info {
  22        /* pwm id corresponding to the PWM driver */
  23        int pwm_id;
  24        /* the period of one PWM cycle */
  25        int period_ns;
  26        /*
  27         * the polarity of one PWM
  28         * 0: normal polarity
  29         * 1: inverted polarity
  30         */
  31        bool polarity;
  32        struct udevice *pwm;
  33        /* initialize voltage of regulator */
  34        int init_voltage;
  35        /* the maximum voltage of regulator */
  36        int max_voltage;
  37        /* the minimum voltage of regulator */
  38        int min_voltage;
  39        /* the current voltage of regulator */
  40        int volt_uV;
  41};
  42
  43static int pwm_regulator_enable(struct udevice *dev, bool enable)
  44{
  45        struct pwm_regulator_info *priv = dev_get_priv(dev);
  46
  47        return pwm_set_enable(priv->pwm, priv->pwm_id, enable);
  48}
  49
  50static int pwm_voltage_to_duty_cycle_percentage(struct udevice *dev, int req_uV)
  51{
  52        struct pwm_regulator_info *priv = dev_get_priv(dev);
  53        int min_uV = priv->min_voltage;
  54        int max_uV = priv->max_voltage;
  55        int diff = max_uV - min_uV;
  56
  57        return ((req_uV * 100) - (min_uV * 100)) / diff;
  58}
  59
  60static int pwm_regulator_get_voltage(struct udevice *dev)
  61{
  62        struct pwm_regulator_info *priv = dev_get_priv(dev);
  63
  64        return priv->volt_uV;
  65}
  66
  67static int pwm_regulator_set_voltage(struct udevice *dev, int uvolt)
  68{
  69        struct pwm_regulator_info *priv = dev_get_priv(dev);
  70        int duty_cycle;
  71        int ret = 0;
  72
  73        duty_cycle = pwm_voltage_to_duty_cycle_percentage(dev, uvolt);
  74
  75        ret = pwm_set_invert(priv->pwm, priv->pwm_id, priv->polarity);
  76        if (ret) {
  77                dev_err(dev, "Failed to init PWM\n");
  78                return ret;
  79        }
  80
  81        ret = pwm_set_config(priv->pwm, priv->pwm_id,
  82                        priv->period_ns, (priv->period_ns / 100) * duty_cycle);
  83        if (ret) {
  84                dev_err(dev, "Failed to configure PWM\n");
  85                return ret;
  86        }
  87
  88        priv->volt_uV = uvolt;
  89
  90        return ret;
  91}
  92
  93static int pwm_regulator_ofdata_to_platdata(struct udevice *dev)
  94{
  95        struct pwm_regulator_info *priv = dev_get_priv(dev);
  96        struct fdtdec_phandle_args args;
  97        const void *blob = gd->fdt_blob;
  98        int node = dev_of_offset(dev);
  99        int ret;
 100
 101        ret = fdtdec_parse_phandle_with_args(blob, node, "pwms", "#pwm-cells",
 102                                             0, 0, &args);
 103        if (ret) {
 104                debug("%s: Cannot get PWM phandle: ret=%d\n", __func__, ret);
 105                return ret;
 106        }
 107
 108        priv->period_ns = args.args[1];
 109        priv->polarity = args.args[2];
 110
 111        priv->init_voltage = fdtdec_get_int(blob, node,
 112                        "regulator-init-microvolt", -1);
 113        if (priv->init_voltage < 0) {
 114                printf("Cannot find regulator pwm init_voltage\n");
 115                return -EINVAL;
 116        }
 117
 118        ret = uclass_get_device_by_of_offset(UCLASS_PWM, args.node, &priv->pwm);
 119        if (ret) {
 120                debug("%s: Cannot get PWM: ret=%d\n", __func__, ret);
 121                return ret;
 122        }
 123
 124        return 0;
 125}
 126
 127static int pwm_regulator_probe(struct udevice *dev)
 128{
 129        struct pwm_regulator_info *priv = dev_get_priv(dev);
 130        struct dm_regulator_uclass_platdata *uc_pdata;
 131
 132        uc_pdata = dev_get_uclass_platdata(dev);
 133
 134        uc_pdata->type = REGULATOR_TYPE_BUCK;
 135        uc_pdata->mode_count = 0;
 136        priv->max_voltage = uc_pdata->max_uV;
 137        priv->min_voltage = uc_pdata->min_uV;
 138
 139        if (priv->init_voltage)
 140                pwm_regulator_set_voltage(dev, priv->init_voltage);
 141
 142        return 0;
 143}
 144
 145static const struct dm_regulator_ops pwm_regulator_ops = {
 146        .get_value  = pwm_regulator_get_voltage,
 147        .set_value  = pwm_regulator_set_voltage,
 148        .set_enable = pwm_regulator_enable,
 149};
 150
 151static const struct udevice_id pwm_regulator_ids[] = {
 152        { .compatible = "pwm-regulator" },
 153        { }
 154};
 155
 156U_BOOT_DRIVER(pwm_regulator) = {
 157        .name = "pwm_regulator",
 158        .id = UCLASS_REGULATOR,
 159        .ops = &pwm_regulator_ops,
 160        .probe = pwm_regulator_probe,
 161        .of_match = pwm_regulator_ids,
 162        .ofdata_to_platdata     = pwm_regulator_ofdata_to_platdata,
 163        .priv_auto_alloc_size   = sizeof(struct pwm_regulator_info),
 164};
 165