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 16 DECLARE_GLOBAL_DATA_PTR; 17 18 struct pwm_regulator_info { 19 /* pwm id corresponding to the PWM driver */ 20 int pwm_id; 21 /* the period of one PWM cycle */ 22 int period_ns; 23 /* 24 * the polarity of one PWM 25 * 0: normal polarity 26 * 1: inverted polarity 27 */ 28 bool polarity; 29 struct udevice *pwm; 30 /* initialize voltage of regulator */ 31 int init_voltage; 32 /* the maximum voltage of regulator */ 33 int max_voltage; 34 /* the minimum voltage of regulator */ 35 int min_voltage; 36 /* the current voltage of regulator */ 37 int volt_uV; 38 }; 39 40 static int pwm_regulator_enable(struct udevice *dev, bool enable) 41 { 42 struct pwm_regulator_info *priv = dev_get_priv(dev); 43 44 return pwm_set_enable(priv->pwm, priv->pwm_id, enable); 45 } 46 47 static int pwm_voltage_to_duty_cycle_percentage(struct udevice *dev, int req_uV) 48 { 49 struct pwm_regulator_info *priv = dev_get_priv(dev); 50 int min_uV = priv->min_voltage; 51 int max_uV = priv->max_voltage; 52 int diff = max_uV - min_uV; 53 54 return ((req_uV * 100) - (min_uV * 100)) / diff; 55 } 56 57 static int pwm_regulator_get_voltage(struct udevice *dev) 58 { 59 struct pwm_regulator_info *priv = dev_get_priv(dev); 60 61 return priv->volt_uV; 62 } 63 64 static int pwm_regulator_set_voltage(struct udevice *dev, int uvolt) 65 { 66 struct pwm_regulator_info *priv = dev_get_priv(dev); 67 int duty_cycle; 68 int ret = 0; 69 70 duty_cycle = pwm_voltage_to_duty_cycle_percentage(dev, uvolt); 71 72 ret = pwm_set_invert(priv->pwm, priv->pwm_id, priv->polarity); 73 if (ret) { 74 dev_err(dev, "Failed to init PWM\n"); 75 return ret; 76 } 77 78 ret = pwm_set_config(priv->pwm, priv->pwm_id, 79 priv->period_ns, (priv->period_ns / 100) * duty_cycle); 80 if (ret) { 81 dev_err(dev, "Failed to configure PWM\n"); 82 return ret; 83 } 84 85 priv->volt_uV = uvolt; 86 87 return ret; 88 } 89 90 static int pwm_regulator_ofdata_to_platdata(struct udevice *dev) 91 { 92 struct pwm_regulator_info *priv = dev_get_priv(dev); 93 struct ofnode_phandle_args args; 94 int ret; 95 96 ret = dev_read_phandle_with_args(dev, "pwms", "#pwm-cells", 0, 0, &args); 97 if (ret) { 98 debug("%s: Cannot get PWM phandle: ret=%d\n", __func__, ret); 99 return ret; 100 } 101 102 priv->period_ns = args.args[1]; 103 priv->polarity = args.args[2]; 104 105 priv->init_voltage = dev_read_u32_default(dev, "regulator-init-microvolt", -1); 106 if (priv->init_voltage < 0) { 107 printf("Cannot find regulator pwm init_voltage\n"); 108 return -EINVAL; 109 } 110 111 ret = uclass_get_device_by_ofnode(UCLASS_PWM, args.node, &priv->pwm); 112 if (ret) { 113 debug("%s: Cannot get PWM: ret=%d\n", __func__, ret); 114 return ret; 115 } 116 117 return 0; 118 } 119 120 static int pwm_regulator_probe(struct udevice *dev) 121 { 122 struct pwm_regulator_info *priv = dev_get_priv(dev); 123 struct dm_regulator_uclass_platdata *uc_pdata; 124 125 uc_pdata = dev_get_uclass_platdata(dev); 126 127 uc_pdata->type = REGULATOR_TYPE_BUCK; 128 uc_pdata->mode_count = 0; 129 priv->max_voltage = uc_pdata->max_uV; 130 priv->min_voltage = uc_pdata->min_uV; 131 132 if (priv->init_voltage) 133 pwm_regulator_set_voltage(dev, priv->init_voltage); 134 135 return 0; 136 } 137 138 static const struct dm_regulator_ops pwm_regulator_ops = { 139 .get_value = pwm_regulator_get_voltage, 140 .set_value = pwm_regulator_set_voltage, 141 .set_enable = pwm_regulator_enable, 142 }; 143 144 static const struct udevice_id pwm_regulator_ids[] = { 145 { .compatible = "pwm-regulator" }, 146 { } 147 }; 148 149 U_BOOT_DRIVER(pwm_regulator) = { 150 .name = "pwm_regulator", 151 .id = UCLASS_REGULATOR, 152 .ops = &pwm_regulator_ops, 153 .probe = pwm_regulator_probe, 154 .of_match = pwm_regulator_ids, 155 .ofdata_to_platdata = pwm_regulator_ofdata_to_platdata, 156 .priv_auto_alloc_size = sizeof(struct pwm_regulator_info), 157 }; 158