1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * (C) Copyright 2016 Texas Instruments Incorporated, <www.ti.com> 4 * Keerthy <j-keerthy@ti.com> 5 */ 6 7#include <common.h> 8#include <fdtdec.h> 9#include <errno.h> 10#include <dm.h> 11#include <log.h> 12#include <asm/gpio.h> 13#include <linux/printk.h> 14#include <power/pmic.h> 15#include <power/regulator.h> 16#include "regulator_common.h" 17 18#include "regulator_common.h" 19 20#define GPIO_REGULATOR_MAX_STATES 2 21 22struct gpio_regulator_plat { 23 struct regulator_common_plat common; 24 struct gpio_desc gpio; /* GPIO for regulator voltage control */ 25 int states[GPIO_REGULATOR_MAX_STATES]; 26 int voltages[GPIO_REGULATOR_MAX_STATES]; 27}; 28 29static int gpio_regulator_of_to_plat(struct udevice *dev) 30{ 31 struct dm_regulator_uclass_plat *uc_pdata; 32 struct gpio_regulator_plat *plat; 33 struct gpio_desc *gpio; 34 int ret, count, i, j; 35 u32 states_array[GPIO_REGULATOR_MAX_STATES * 2]; 36 37 plat = dev_get_plat(dev); 38 uc_pdata = dev_get_uclass_plat(dev); 39 if (!uc_pdata) 40 return -ENXIO; 41 42 /* Set type to gpio */ 43 uc_pdata->type = REGULATOR_TYPE_GPIO; 44 45 /* 46 * Get gpio regulator gpio desc 47 * Assuming one GPIO per regulator. 48 * Can be extended later to multiple GPIOs 49 * per gpio-regulator. As of now no instance with multiple 50 * gpios is presnt 51 */ 52 gpio = &plat->gpio; 53 ret = gpio_request_by_name(dev, "gpios", 0, gpio, GPIOD_IS_OUT); 54 if (ret) 55 debug("regulator gpio - not found! Error: %d", ret); 56 57 ret = dev_read_size(dev, "states"); 58 if (ret < 0) 59 return ret; 60 61 count = ret / sizeof(states_array[0]); 62 if (count > ARRAY_SIZE(states_array)) { 63 debug("regulator gpio - to many states (%d > %d)", 64 count / 2, GPIO_REGULATOR_MAX_STATES); 65 count = ARRAY_SIZE(states_array); 66 } 67 68 ret = dev_read_u32_array(dev, "states", states_array, count); 69 if (ret < 0) 70 return ret; 71 72 for (i = 0, j = 0; i < count; i += 2) { 73 plat->voltages[j] = states_array[i]; 74 plat->states[j] = states_array[i + 1]; 75 j++; 76 } 77 78 return regulator_common_of_to_plat(dev, &plat->common, "enable-gpios"); 79} 80 81static int gpio_regulator_get_value(struct udevice *dev) 82{ 83 struct dm_regulator_uclass_plat *uc_pdata; 84 struct gpio_regulator_plat *plat = dev_get_plat(dev); 85 int enable; 86 87 if (!plat->gpio.dev) 88 return -ENOSYS; 89 90 uc_pdata = dev_get_uclass_plat(dev); 91 if (uc_pdata->min_uV > uc_pdata->max_uV) { 92 debug("Invalid constraints for: %s\n", uc_pdata->name); 93 return -EINVAL; 94 } 95 96 enable = dm_gpio_get_value(&plat->gpio); 97 if (enable == plat->states[0]) 98 return plat->voltages[0]; 99 else 100 return plat->voltages[1]; 101} 102 103static int gpio_regulator_set_value(struct udevice *dev, int uV) 104{ 105 struct gpio_regulator_plat *plat = dev_get_plat(dev); 106 int ret; 107 bool enable; 108 109 if (!plat->gpio.dev) 110 return -ENOSYS; 111 112 if (uV == plat->voltages[0]) 113 enable = plat->states[0]; 114 else if (uV == plat->voltages[1]) 115 enable = plat->states[1]; 116 else 117 return -EINVAL; 118 119 ret = dm_gpio_set_value(&plat->gpio, enable); 120 if (ret) { 121 pr_err("Can't set regulator : %s gpio to: %d\n", dev->name, 122 enable); 123 return ret; 124 } 125 126 return 0; 127} 128 129static int gpio_regulator_get_enable(struct udevice *dev) 130{ 131 struct gpio_regulator_plat *plat = dev_get_plat(dev); 132 return regulator_common_get_enable(dev, &plat->common); 133} 134 135static int gpio_regulator_set_enable(struct udevice *dev, bool enable) 136{ 137 struct gpio_regulator_plat *plat = dev_get_plat(dev); 138 return regulator_common_set_enable(dev, &plat->common, enable); 139} 140 141static const struct dm_regulator_ops gpio_regulator_ops = { 142 .get_value = gpio_regulator_get_value, 143 .set_value = gpio_regulator_set_value, 144 .get_enable = gpio_regulator_get_enable, 145 .set_enable = gpio_regulator_set_enable, 146}; 147 148static const struct udevice_id gpio_regulator_ids[] = { 149 { .compatible = "regulator-gpio" }, 150 { }, 151}; 152 153U_BOOT_DRIVER(gpio_regulator) = { 154 .name = "gpio regulator", 155 .id = UCLASS_REGULATOR, 156 .ops = &gpio_regulator_ops, 157 .of_match = gpio_regulator_ids, 158 .of_to_plat = gpio_regulator_of_to_plat, 159 .plat_auto = sizeof(struct gpio_regulator_plat), 160}; 161