/* * Copyright (C) 2015 Samsung Electronics * * Przemyslaw Marczak * * SPDX-License-Identifier: GPL-2.0+ */ #include #include #include #include #include #include #include DECLARE_GLOBAL_DATA_PTR; struct fixed_regulator_platdata { struct gpio_desc gpio; /* GPIO for regulator enable control */ unsigned int startup_delay_us; }; static int fixed_regulator_ofdata_to_platdata(struct udevice *dev) { struct dm_regulator_uclass_platdata *uc_pdata; struct fixed_regulator_platdata *dev_pdata; struct gpio_desc *gpio; int flags = GPIOD_IS_OUT; int ret; dev_pdata = dev_get_platdata(dev); uc_pdata = dev_get_uclass_platdata(dev); if (!uc_pdata) return -ENXIO; /* Set type to fixed */ uc_pdata->type = REGULATOR_TYPE_FIXED; if (dev_read_bool(dev, "enable-active-high")) flags |= GPIOD_IS_OUT_ACTIVE; /* Get fixed regulator optional enable GPIO desc */ gpio = &dev_pdata->gpio; ret = gpio_request_by_name(dev, "gpio", 0, gpio, flags); if (ret) { debug("Fixed regulator optional enable GPIO - not found! Error: %d\n", ret); if (ret != -ENOENT) return ret; } /* Get optional ramp up delay */ dev_pdata->startup_delay_us = dev_read_u32_default(dev, "startup-delay-us", 0); return 0; } static int fixed_regulator_get_value(struct udevice *dev) { struct dm_regulator_uclass_platdata *uc_pdata; uc_pdata = dev_get_uclass_platdata(dev); if (!uc_pdata) return -ENXIO; if (uc_pdata->min_uV != uc_pdata->max_uV) { debug("Invalid constraints for: %s\n", uc_pdata->name); return -EINVAL; } return uc_pdata->min_uV; } static int fixed_regulator_get_current(struct udevice *dev) { struct dm_regulator_uclass_platdata *uc_pdata; uc_pdata = dev_get_uclass_platdata(dev); if (!uc_pdata) return -ENXIO; if (uc_pdata->min_uA != uc_pdata->max_uA) { debug("Invalid constraints for: %s\n", uc_pdata->name); return -EINVAL; } return uc_pdata->min_uA; } static int fixed_regulator_get_enable(struct udevice *dev) { struct fixed_regulator_platdata *dev_pdata = dev_get_platdata(dev); /* Enable GPIO is optional */ if (!dev_pdata->gpio.dev) return true; return dm_gpio_get_value(&dev_pdata->gpio); } static int fixed_regulator_set_enable(struct udevice *dev, bool enable) { struct fixed_regulator_platdata *dev_pdata = dev_get_platdata(dev); int ret; debug("%s: dev='%s', enable=%d, delay=%d, has_gpio=%d\n", __func__, dev->name, enable, dev_pdata->startup_delay_us, dm_gpio_is_valid(&dev_pdata->gpio)); /* Enable GPIO is optional */ if (!dm_gpio_is_valid(&dev_pdata->gpio)) { if (!enable) return -ENOSYS; return 0; } ret = dm_gpio_set_value(&dev_pdata->gpio, enable); if (ret) { pr_err("Can't set regulator : %s gpio to: %d\n", dev->name, enable); return ret; } if (enable && dev_pdata->startup_delay_us) udelay(dev_pdata->startup_delay_us); debug("%s: done\n", __func__); return 0; } static const struct dm_regulator_ops fixed_regulator_ops = { .get_value = fixed_regulator_get_value, .get_current = fixed_regulator_get_current, .get_enable = fixed_regulator_get_enable, .set_enable = fixed_regulator_set_enable, }; static const struct udevice_id fixed_regulator_ids[] = { { .compatible = "regulator-fixed" }, { }, }; U_BOOT_DRIVER(fixed_regulator) = { .name = "fixed regulator", .id = UCLASS_REGULATOR, .ops = &fixed_regulator_ops, .of_match = fixed_regulator_ids, .ofdata_to_platdata = fixed_regulator_ofdata_to_platdata, .platdata_auto_alloc_size = sizeof(struct fixed_regulator_platdata), };