diff options
Diffstat (limited to 'drivers/regulator/fixed.c')
| -rw-r--r-- | drivers/regulator/fixed.c | 251 |
1 files changed, 79 insertions, 172 deletions
diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c index e24e3a174c4..354105eff1f 100644 --- a/drivers/regulator/fixed.c +++ b/drivers/regulator/fixed.c @@ -25,7 +25,6 @@ #include <linux/regulator/driver.h> #include <linux/regulator/fixed.h> #include <linux/gpio.h> -#include <linux/delay.h> #include <linux/slab.h> #include <linux/of.h> #include <linux/of_gpio.h> @@ -35,11 +34,6 @@ struct fixed_voltage_data { struct regulator_desc desc; struct regulator_dev *dev; - int microvolts; - int gpio; - unsigned startup_delay; - bool enable_high; - bool is_enabled; }; @@ -56,17 +50,16 @@ of_get_fixed_voltage_config(struct device *dev) { struct fixed_voltage_config *config; struct device_node *np = dev->of_node; - const __be32 *delay; struct regulator_init_data *init_data; config = devm_kzalloc(dev, sizeof(struct fixed_voltage_config), GFP_KERNEL); if (!config) - return NULL; + return ERR_PTR(-ENOMEM); config->init_data = of_get_regulator_init_data(dev, dev->of_node); if (!config->init_data) - return NULL; + return ERR_PTR(-EINVAL); init_data = config->init_data; init_data->constraints.apply_uV = 0; @@ -77,231 +70,145 @@ of_get_fixed_voltage_config(struct device *dev) } else { dev_err(dev, "Fixed regulator specified with variable voltages\n"); - return NULL; + return ERR_PTR(-EINVAL); } if (init_data->constraints.boot_on) config->enabled_at_boot = true; config->gpio = of_get_named_gpio(np, "gpio", 0); - delay = of_get_property(np, "startup-delay-us", NULL); - if (delay) - config->startup_delay = be32_to_cpu(*delay); - - if (of_find_property(np, "enable-active-high", NULL)) - config->enable_high = true; + /* + * of_get_named_gpio() currently returns ENODEV rather than + * EPROBE_DEFER. This code attempts to be compatible with both + * for now; the ENODEV check can be removed once the API is fixed. + * of_get_named_gpio() doesn't differentiate between a missing + * property (which would be fine here, since the GPIO is optional) + * and some other error. Patches have been posted for both issues. + * Once they are check in, we should replace this with: + * if (config->gpio < 0 && config->gpio != -ENOENT) + */ + if ((config->gpio == -ENODEV) || (config->gpio == -EPROBE_DEFER)) + return ERR_PTR(-EPROBE_DEFER); + + of_property_read_u32(np, "startup-delay-us", &config->startup_delay); + + config->enable_high = of_property_read_bool(np, "enable-active-high"); + config->gpio_is_open_drain = of_property_read_bool(np, + "gpio-open-drain"); + + if (of_find_property(np, "vin-supply", NULL)) + config->input_supply = "vin"; return config; } -static int fixed_voltage_is_enabled(struct regulator_dev *dev) -{ - struct fixed_voltage_data *data = rdev_get_drvdata(dev); - - return data->is_enabled; -} - -static int fixed_voltage_enable(struct regulator_dev *dev) -{ - struct fixed_voltage_data *data = rdev_get_drvdata(dev); - - if (gpio_is_valid(data->gpio)) { - gpio_set_value_cansleep(data->gpio, data->enable_high); - data->is_enabled = true; - } - - return 0; -} - -static int fixed_voltage_disable(struct regulator_dev *dev) -{ - struct fixed_voltage_data *data = rdev_get_drvdata(dev); - - if (gpio_is_valid(data->gpio)) { - gpio_set_value_cansleep(data->gpio, !data->enable_high); - data->is_enabled = false; - } - - return 0; -} - -static int fixed_voltage_enable_time(struct regulator_dev *dev) -{ - struct fixed_voltage_data *data = rdev_get_drvdata(dev); - - return data->startup_delay; -} - -static int fixed_voltage_get_voltage(struct regulator_dev *dev) -{ - struct fixed_voltage_data *data = rdev_get_drvdata(dev); - - if (data->microvolts) - return data->microvolts; - else - return -EINVAL; -} - -static int fixed_voltage_list_voltage(struct regulator_dev *dev, - unsigned selector) -{ - struct fixed_voltage_data *data = rdev_get_drvdata(dev); - - if (selector != 0) - return -EINVAL; - - return data->microvolts; -} - static struct regulator_ops fixed_voltage_ops = { - .is_enabled = fixed_voltage_is_enabled, - .enable = fixed_voltage_enable, - .disable = fixed_voltage_disable, - .enable_time = fixed_voltage_enable_time, - .get_voltage = fixed_voltage_get_voltage, - .list_voltage = fixed_voltage_list_voltage, }; -static int __devinit reg_fixed_voltage_probe(struct platform_device *pdev) +static int reg_fixed_voltage_probe(struct platform_device *pdev) { struct fixed_voltage_config *config; struct fixed_voltage_data *drvdata; + struct regulator_config cfg = { }; int ret; - if (pdev->dev.of_node) + if (pdev->dev.of_node) { config = of_get_fixed_voltage_config(&pdev->dev); - else - config = pdev->dev.platform_data; + if (IS_ERR(config)) + return PTR_ERR(config); + } else { + config = dev_get_platdata(&pdev->dev); + } if (!config) return -ENOMEM; - drvdata = kzalloc(sizeof(struct fixed_voltage_data), GFP_KERNEL); - if (drvdata == NULL) { - dev_err(&pdev->dev, "Failed to allocate device data\n"); - ret = -ENOMEM; - goto err; - } + drvdata = devm_kzalloc(&pdev->dev, sizeof(struct fixed_voltage_data), + GFP_KERNEL); + if (!drvdata) + return -ENOMEM; - drvdata->desc.name = kstrdup(config->supply_name, GFP_KERNEL); + drvdata->desc.name = devm_kstrdup(&pdev->dev, + config->supply_name, + GFP_KERNEL); if (drvdata->desc.name == NULL) { dev_err(&pdev->dev, "Failed to allocate supply name\n"); - ret = -ENOMEM; - goto err; + return -ENOMEM; } drvdata->desc.type = REGULATOR_VOLTAGE; drvdata->desc.owner = THIS_MODULE; drvdata->desc.ops = &fixed_voltage_ops; - drvdata->desc.n_voltages = 1; - - drvdata->microvolts = config->microvolts; - drvdata->gpio = config->gpio; - drvdata->startup_delay = config->startup_delay; - - if (gpio_is_valid(config->gpio)) { - drvdata->enable_high = config->enable_high; - - /* FIXME: Remove below print warning - * - * config->gpio must be set to -EINVAL by platform code if - * GPIO control is not required. However, early adopters - * not requiring GPIO control may forget to initialize - * config->gpio to -EINVAL. This will cause GPIO 0 to be used - * for GPIO control. - * - * This warning will be removed once there are a couple of users - * for this driver. - */ - if (!config->gpio) - dev_warn(&pdev->dev, - "using GPIO 0 for regulator enable control\n"); - - ret = gpio_request(config->gpio, config->supply_name); - if (ret) { - dev_err(&pdev->dev, - "Could not obtain regulator enable GPIO %d: %d\n", - config->gpio, ret); - goto err_name; - } - /* set output direction without changing state - * to prevent glitch - */ - drvdata->is_enabled = config->enabled_at_boot; - ret = drvdata->is_enabled ? - config->enable_high : !config->enable_high; + drvdata->desc.enable_time = config->startup_delay; - ret = gpio_direction_output(config->gpio, ret); - if (ret) { + if (config->input_supply) { + drvdata->desc.supply_name = devm_kstrdup(&pdev->dev, + config->input_supply, + GFP_KERNEL); + if (!drvdata->desc.supply_name) { dev_err(&pdev->dev, - "Could not configure regulator enable GPIO %d direction: %d\n", - config->gpio, ret); - goto err_gpio; + "Failed to allocate input supply\n"); + return -ENOMEM; } + } + + if (config->microvolts) + drvdata->desc.n_voltages = 1; + drvdata->desc.fixed_uV = config->microvolts; + + if (config->gpio >= 0) + cfg.ena_gpio = config->gpio; + cfg.ena_gpio_invert = !config->enable_high; + if (config->enabled_at_boot) { + if (config->enable_high) + cfg.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH; + else + cfg.ena_gpio_flags |= GPIOF_OUT_INIT_LOW; } else { - /* Regulator without GPIO control is considered - * always enabled - */ - drvdata->is_enabled = true; + if (config->enable_high) + cfg.ena_gpio_flags |= GPIOF_OUT_INIT_LOW; + else + cfg.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH; } + if (config->gpio_is_open_drain) + cfg.ena_gpio_flags |= GPIOF_OPEN_DRAIN; + + cfg.dev = &pdev->dev; + cfg.init_data = config->init_data; + cfg.driver_data = drvdata; + cfg.of_node = pdev->dev.of_node; - drvdata->dev = regulator_register(&drvdata->desc, &pdev->dev, - config->init_data, drvdata, - pdev->dev.of_node); + drvdata->dev = devm_regulator_register(&pdev->dev, &drvdata->desc, + &cfg); if (IS_ERR(drvdata->dev)) { ret = PTR_ERR(drvdata->dev); dev_err(&pdev->dev, "Failed to register regulator: %d\n", ret); - goto err_gpio; + return ret; } platform_set_drvdata(pdev, drvdata); dev_dbg(&pdev->dev, "%s supplying %duV\n", drvdata->desc.name, - drvdata->microvolts); - - return 0; - -err_gpio: - if (gpio_is_valid(config->gpio)) - gpio_free(config->gpio); -err_name: - kfree(drvdata->desc.name); -err: - kfree(drvdata); - return ret; -} - -static int __devexit reg_fixed_voltage_remove(struct platform_device *pdev) -{ - struct fixed_voltage_data *drvdata = platform_get_drvdata(pdev); - - regulator_unregister(drvdata->dev); - if (gpio_is_valid(drvdata->gpio)) - gpio_free(drvdata->gpio); - kfree(drvdata->desc.name); - kfree(drvdata); + drvdata->desc.fixed_uV); return 0; } #if defined(CONFIG_OF) -static const struct of_device_id fixed_of_match[] __devinitconst = { +static const struct of_device_id fixed_of_match[] = { { .compatible = "regulator-fixed", }, {}, }; MODULE_DEVICE_TABLE(of, fixed_of_match); -#else -#define fixed_of_match NULL #endif static struct platform_driver regulator_fixed_voltage_driver = { .probe = reg_fixed_voltage_probe, - .remove = __devexit_p(reg_fixed_voltage_remove), .driver = { .name = "reg-fixed-voltage", .owner = THIS_MODULE, - .of_match_table = fixed_of_match, + .of_match_table = of_match_ptr(fixed_of_match), }, }; |
