123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301 |
- /*
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
- #define pr_fmt(fmt) "%s: " fmt, __func__
- #include <linux/module.h>
- #include <linux/err.h>
- #include <linux/kernel.h>
- #include <linux/of.h>
- #include <linux/of_device.h>
- #include <linux/platform_device.h>
- #include <linux/slab.h>
- #include <linux/types.h>
- #include <linux/regulator/driver.h>
- #include <linux/regulator/of_regulator.h>
- #include <linux/regulator/stub-regulator.h>
- #define STUB_REGULATOR_MAX_NAME 40
- struct regulator_stub {
- struct regulator_desc rdesc;
- struct regulator_dev *rdev;
- int voltage;
- bool enabled;
- int mode;
- int hpm_min_load;
- int system_uA;
- char name[STUB_REGULATOR_MAX_NAME];
- };
- static int regulator_stub_set_voltage(struct regulator_dev *rdev, int min_uV,
- int max_uV, unsigned *selector)
- {
- struct regulator_stub *vreg_priv = rdev_get_drvdata(rdev);
- vreg_priv->voltage = min_uV;
- return 0;
- }
- static int regulator_stub_get_voltage(struct regulator_dev *rdev)
- {
- struct regulator_stub *vreg_priv = rdev_get_drvdata(rdev);
- return vreg_priv->voltage;
- }
- static int regulator_stub_list_voltage(struct regulator_dev *rdev,
- unsigned selector)
- {
- struct regulation_constraints *constraints = rdev->constraints;
- if (selector >= 2)
- return -EINVAL;
- else if (selector == 0)
- return constraints->min_uV;
- else
- return constraints->max_uV;
- }
- static unsigned int regulator_stub_get_mode(struct regulator_dev *rdev)
- {
- struct regulator_stub *vreg_priv = rdev_get_drvdata(rdev);
- return vreg_priv->mode;
- }
- static int regulator_stub_set_mode(struct regulator_dev *rdev,
- unsigned int mode)
- {
- struct regulator_stub *vreg_priv = rdev_get_drvdata(rdev);
- if (mode != REGULATOR_MODE_NORMAL && mode != REGULATOR_MODE_IDLE) {
- dev_err(&rdev->dev, "%s: invalid mode requested %u\n",
- __func__, mode);
- return -EINVAL;
- }
- vreg_priv->mode = mode;
- return 0;
- }
- static unsigned int regulator_stub_get_optimum_mode(struct regulator_dev *rdev,
- int input_uV, int output_uV, int load_uA)
- {
- struct regulator_stub *vreg_priv = rdev_get_drvdata(rdev);
- unsigned int mode;
- if (load_uA + vreg_priv->system_uA >= vreg_priv->hpm_min_load)
- mode = REGULATOR_MODE_NORMAL;
- else
- mode = REGULATOR_MODE_IDLE;
- return mode;
- }
- static int regulator_stub_enable(struct regulator_dev *rdev)
- {
- struct regulator_stub *vreg_priv = rdev_get_drvdata(rdev);
- vreg_priv->enabled = true;
- return 0;
- }
- static int regulator_stub_disable(struct regulator_dev *rdev)
- {
- struct regulator_stub *vreg_priv = rdev_get_drvdata(rdev);
- vreg_priv->enabled = false;
- return 0;
- }
- static int regulator_stub_is_enabled(struct regulator_dev *rdev)
- {
- struct regulator_stub *vreg_priv = rdev_get_drvdata(rdev);
- return vreg_priv->enabled;
- }
- /* Real regulator operations. */
- static struct regulator_ops regulator_stub_ops = {
- .enable = regulator_stub_enable,
- .disable = regulator_stub_disable,
- .is_enabled = regulator_stub_is_enabled,
- .set_voltage = regulator_stub_set_voltage,
- .get_voltage = regulator_stub_get_voltage,
- .list_voltage = regulator_stub_list_voltage,
- .set_mode = regulator_stub_set_mode,
- .get_mode = regulator_stub_get_mode,
- .get_optimum_mode = regulator_stub_get_optimum_mode,
- };
- static void regulator_stub_cleanup(struct regulator_stub *vreg_priv)
- {
- if (vreg_priv && vreg_priv->rdev)
- regulator_unregister(vreg_priv->rdev);
- kfree(vreg_priv);
- }
- static int __devinit regulator_stub_probe(struct platform_device *pdev)
- {
- struct regulator_init_data *init_data = NULL;
- struct device *dev = &pdev->dev;
- struct stub_regulator_pdata *vreg_pdata;
- struct regulator_desc *rdesc;
- struct regulator_stub *vreg_priv;
- int rc;
- vreg_priv = kzalloc(sizeof(*vreg_priv), GFP_KERNEL);
- if (!vreg_priv) {
- dev_err(dev, "%s: Unable to allocate memory\n",
- __func__);
- return -ENOMEM;
- }
- if (dev->of_node) {
- /* Use device tree. */
- init_data = of_get_regulator_init_data(dev,
- dev->of_node);
- if (!init_data) {
- dev_err(dev, "%s: unable to allocate memory\n",
- __func__);
- rc = -ENOMEM;
- goto err_probe;
- }
- if (init_data->constraints.name == NULL) {
- dev_err(dev, "%s: regulator name not specified\n",
- __func__);
- rc = -EINVAL;
- goto err_probe;
- }
- if (of_get_property(dev->of_node, "parent-supply", NULL))
- init_data->supply_regulator = "parent";
- of_property_read_u32(dev->of_node, "qcom,system-load",
- &vreg_priv->system_uA);
- of_property_read_u32(dev->of_node, "qcom,hpm-min-load",
- &vreg_priv->hpm_min_load);
- init_data->constraints.input_uV = init_data->constraints.max_uV;
- init_data->constraints.valid_ops_mask
- |= REGULATOR_CHANGE_STATUS;
- init_data->constraints.valid_ops_mask
- |= REGULATOR_CHANGE_VOLTAGE;
- init_data->constraints.valid_ops_mask
- |= REGULATOR_CHANGE_MODE | REGULATOR_CHANGE_DRMS;
- init_data->constraints.valid_modes_mask
- = REGULATOR_MODE_NORMAL | REGULATOR_MODE_IDLE;
- } else {
- /* Use platform data. */
- vreg_pdata = dev->platform_data;
- if (!vreg_pdata) {
- dev_err(dev, "%s: no platform data\n", __func__);
- rc = -EINVAL;
- goto err_probe;
- }
- init_data = &vreg_pdata->init_data;
- vreg_priv->system_uA = vreg_pdata->system_uA;
- vreg_priv->hpm_min_load = vreg_pdata->hpm_min_load;
- }
- dev_set_drvdata(dev, vreg_priv);
- rdesc = &vreg_priv->rdesc;
- strlcpy(vreg_priv->name, init_data->constraints.name,
- STUB_REGULATOR_MAX_NAME);
- rdesc->name = vreg_priv->name;
- rdesc->ops = ®ulator_stub_ops;
- /*
- * Ensure that voltage set points are handled correctly for regulators
- * which have a specified voltage constraint range, as well as those
- * that do not.
- */
- if (init_data->constraints.min_uV == 0 &&
- init_data->constraints.max_uV == 0)
- rdesc->n_voltages = 0;
- else
- rdesc->n_voltages = 2;
- rdesc->id = pdev->id;
- rdesc->owner = THIS_MODULE;
- rdesc->type = REGULATOR_VOLTAGE;
- vreg_priv->voltage = init_data->constraints.min_uV;
- if (vreg_priv->system_uA >= vreg_priv->hpm_min_load)
- vreg_priv->mode = REGULATOR_MODE_NORMAL;
- else
- vreg_priv->mode = REGULATOR_MODE_IDLE;
- vreg_priv->rdev = regulator_register(rdesc, dev, init_data, vreg_priv,
- dev->of_node);
- if (IS_ERR(vreg_priv->rdev)) {
- rc = PTR_ERR(vreg_priv->rdev);
- vreg_priv->rdev = NULL;
- if (rc != -EPROBE_DEFER)
- dev_err(dev, "%s: regulator_register failed\n",
- __func__);
- goto err_probe;
- }
- return 0;
- err_probe:
- regulator_stub_cleanup(vreg_priv);
- return rc;
- }
- static int __devexit regulator_stub_remove(struct platform_device *pdev)
- {
- struct regulator_stub *vreg_priv = dev_get_drvdata(&pdev->dev);
- regulator_stub_cleanup(vreg_priv);
- return 0;
- }
- static struct of_device_id regulator_stub_match_table[] = {
- { .compatible = "qcom," STUB_REGULATOR_DRIVER_NAME, },
- {}
- };
- static struct platform_driver regulator_stub_driver = {
- .probe = regulator_stub_probe,
- .remove = __devexit_p(regulator_stub_remove),
- .driver = {
- .name = STUB_REGULATOR_DRIVER_NAME,
- .owner = THIS_MODULE,
- .of_match_table = regulator_stub_match_table,
- },
- };
- int __init regulator_stub_init(void)
- {
- static int registered;
- if (registered)
- return 0;
- else
- registered = 1;
- return platform_driver_register(®ulator_stub_driver);
- }
- postcore_initcall(regulator_stub_init);
- EXPORT_SYMBOL(regulator_stub_init);
- static void __exit regulator_stub_exit(void)
- {
- platform_driver_unregister(®ulator_stub_driver);
- }
- module_exit(regulator_stub_exit);
- MODULE_LICENSE("GPL v2");
- MODULE_DESCRIPTION("stub regulator driver");
- MODULE_VERSION("1.0");
- MODULE_ALIAS("platform: " STUB_REGULATOR_DRIVER_NAME);
|