1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright (C) 2015 Samsung Electronics 4 * 5 * Przemyslaw Marczak <p.marczak@samsung.com> 6 */ 7 8#include <common.h> 9#include <clk.h> 10#include <errno.h> 11#include <dm.h> 12#include <linux/delay.h> 13#include <log.h> 14#include <asm/gpio.h> 15#include <power/pmic.h> 16#include <power/regulator.h> 17#include "regulator_common.h" 18 19#include "regulator_common.h" 20 21struct fixed_clock_regulator_plat { 22 struct clk *enable_clock; 23 unsigned int clk_enable_counter; 24}; 25 26static int fixed_regulator_of_to_plat(struct udevice *dev) 27{ 28 struct dm_regulator_uclass_plat *uc_pdata; 29 struct regulator_common_plat *plat; 30 bool gpios; 31 32 plat = dev_get_plat(dev); 33 uc_pdata = dev_get_uclass_plat(dev); 34 if (!uc_pdata) 35 return -ENXIO; 36 37 uc_pdata->type = REGULATOR_TYPE_FIXED; 38 39 gpios = dev_read_bool(dev, "gpios"); 40 return regulator_common_of_to_plat(dev, plat, gpios ? "gpios" : "gpio"); 41} 42 43static int fixed_regulator_get_value(struct udevice *dev) 44{ 45 struct dm_regulator_uclass_plat *uc_pdata; 46 47 uc_pdata = dev_get_uclass_plat(dev); 48 if (!uc_pdata) 49 return -ENXIO; 50 51 if (uc_pdata->min_uV != uc_pdata->max_uV) { 52 debug("Invalid constraints for: %s\n", uc_pdata->name); 53 return -EINVAL; 54 } 55 56 return uc_pdata->min_uV; 57} 58 59static int fixed_regulator_get_current(struct udevice *dev) 60{ 61 struct dm_regulator_uclass_plat *uc_pdata; 62 63 uc_pdata = dev_get_uclass_plat(dev); 64 if (!uc_pdata) 65 return -ENXIO; 66 67 if (uc_pdata->min_uA != uc_pdata->max_uA) { 68 debug("Invalid constraints for: %s\n", uc_pdata->name); 69 return -EINVAL; 70 } 71 72 return uc_pdata->min_uA; 73} 74 75static int fixed_regulator_get_enable(struct udevice *dev) 76{ 77 return regulator_common_get_enable(dev, dev_get_plat(dev)); 78} 79 80static int fixed_regulator_set_enable(struct udevice *dev, bool enable) 81{ 82 return regulator_common_set_enable(dev, dev_get_plat(dev), enable); 83} 84 85static int fixed_clock_regulator_get_enable(struct udevice *dev) 86{ 87 struct fixed_clock_regulator_plat *priv = dev_get_priv(dev); 88 89 return priv->clk_enable_counter > 0; 90} 91 92static int fixed_clock_regulator_set_enable(struct udevice *dev, bool enable) 93{ 94 struct fixed_clock_regulator_plat *priv = dev_get_priv(dev); 95 struct regulator_common_plat *plat = dev_get_plat(dev); 96 int ret = 0; 97 98 if (enable) { 99 ret = clk_enable(priv->enable_clock); 100 priv->clk_enable_counter++; 101 } else { 102 ret = clk_disable(priv->enable_clock); 103 priv->clk_enable_counter--; 104 } 105 if (ret) 106 return ret; 107 108 if (enable && plat->startup_delay_us) 109 udelay(plat->startup_delay_us); 110 111 if (!enable && plat->off_on_delay_us) 112 udelay(plat->off_on_delay_us); 113 114 return ret; 115} 116 117static const struct dm_regulator_ops fixed_regulator_ops = { 118 .get_value = fixed_regulator_get_value, 119 .get_current = fixed_regulator_get_current, 120 .get_enable = fixed_regulator_get_enable, 121 .set_enable = fixed_regulator_set_enable, 122}; 123 124static const struct dm_regulator_ops fixed_clock_regulator_ops = { 125 .get_enable = fixed_clock_regulator_get_enable, 126 .set_enable = fixed_clock_regulator_set_enable, 127}; 128 129static const struct udevice_id fixed_regulator_ids[] = { 130 { .compatible = "regulator-fixed" }, 131 { }, 132}; 133 134static const struct udevice_id fixed_clock_regulator_ids[] = { 135 { .compatible = "regulator-fixed-clock" }, 136 { }, 137}; 138 139U_BOOT_DRIVER(regulator_fixed) = { 140 .name = "regulator_fixed", 141 .id = UCLASS_REGULATOR, 142 .ops = &fixed_regulator_ops, 143 .of_match = fixed_regulator_ids, 144 .of_to_plat = fixed_regulator_of_to_plat, 145 .plat_auto = sizeof(struct regulator_common_plat), 146}; 147 148U_BOOT_DRIVER(regulator_fixed_clock) = { 149 .name = "regulator_fixed_clk", 150 .id = UCLASS_REGULATOR, 151 .ops = &fixed_clock_regulator_ops, 152 .of_match = fixed_clock_regulator_ids, 153 .of_to_plat = fixed_regulator_of_to_plat, 154 .plat_auto = sizeof(struct fixed_clock_regulator_plat), 155}; 156