From 86d9884b6a3646bc24e57430f1f694c5171c1bf6 Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Thu, 6 Aug 2009 19:37:29 +0300 Subject: [PATCH] regulator: Add GPIO enable control to fixed voltage regulator driver Now fixed regulators that have their enable pin connected to a GPIO line can use the fixed regulator driver for regulator enable/disable control. The GPIO number and polarity information is passed through platform data. GPIO enable control is achieved using gpiolib. Signed-off-by: Roger Quadros Reviewed-by: Philipp Zabel Reviewed-by: Felipe Balbi Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/fixed.c | 88 ++++++++++++++++++++++++++++++++- include/linux/regulator/fixed.h | 24 +++++++++ 2 files changed, 110 insertions(+), 2 deletions(-) diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c index 9c7f956d57c4..f8b295700d7d 100644 --- a/drivers/regulator/fixed.c +++ b/drivers/regulator/fixed.c @@ -5,6 +5,9 @@ * * Author: Mark Brown * + * Copyright (c) 2009 Nokia Corporation + * Roger Quadros + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the @@ -20,20 +23,45 @@ #include #include #include +#include struct fixed_voltage_data { struct regulator_desc desc; struct regulator_dev *dev; int microvolts; + int gpio; + unsigned enable_high:1; + unsigned is_enabled:1; }; static int fixed_voltage_is_enabled(struct regulator_dev *dev) { - return 1; + 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 = 1; + } + + 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 = 0; + } + return 0; } @@ -58,6 +86,7 @@ static int fixed_voltage_list_voltage(struct regulator_dev *dev, static struct regulator_ops fixed_voltage_ops = { .is_enabled = fixed_voltage_is_enabled, .enable = fixed_voltage_enable, + .disable = fixed_voltage_disable, .get_voltage = fixed_voltage_get_voltage, .list_voltage = fixed_voltage_list_voltage, }; @@ -87,13 +116,62 @@ static int regulator_fixed_voltage_probe(struct platform_device *pdev) drvdata->desc.n_voltages = 1; drvdata->microvolts = config->microvolts; + drvdata->gpio = config->gpio; + + 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; + + ret = gpio_direction_output(config->gpio, ret); + if (ret) { + dev_err(&pdev->dev, + "Could not configure regulator enable GPIO %d direction: %d\n", + config->gpio, ret); + goto err_gpio; + } + + } else { + /* Regulator without GPIO control is considered + * always enabled + */ + drvdata->is_enabled = 1; + } drvdata->dev = regulator_register(&drvdata->desc, &pdev->dev, config->init_data, drvdata); if (IS_ERR(drvdata->dev)) { ret = PTR_ERR(drvdata->dev); dev_err(&pdev->dev, "Failed to register regulator: %d\n", ret); - goto err_name; + goto err_gpio; } platform_set_drvdata(pdev, drvdata); @@ -103,6 +181,9 @@ static int regulator_fixed_voltage_probe(struct platform_device *pdev) return 0; +err_gpio: + if (gpio_is_valid(config->gpio)) + gpio_free(config->gpio); err_name: kfree(drvdata->desc.name); err: @@ -118,6 +199,9 @@ static int regulator_fixed_voltage_remove(struct platform_device *pdev) kfree(drvdata->desc.name); kfree(drvdata); + if (gpio_is_valid(drvdata->gpio)) + gpio_free(drvdata->gpio); + return 0; } diff --git a/include/linux/regulator/fixed.h b/include/linux/regulator/fixed.h index 91b4da31f1b5..e94a4a1c7c8a 100644 --- a/include/linux/regulator/fixed.h +++ b/include/linux/regulator/fixed.h @@ -5,6 +5,9 @@ * * Author: Mark Brown * + * Copyright (c) 2009 Nokia Corporation + * Roger Quadros + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the @@ -16,9 +19,30 @@ struct regulator_init_data; +/** + * struct fixed_voltage_config - fixed_voltage_config structure + * @supply_name: Name of the regulator supply + * @microvolts: Output voltage of regulator + * @gpio: GPIO to use for enable control + * set to -EINVAL if not used + * @enable_high: Polarity of enable GPIO + * 1 = Active high, 0 = Active low + * @enabled_at_boot: Whether regulator has been enabled at + * boot or not. 1 = Yes, 0 = No + * This is used to keep the regulator at + * the default state + * @init_data: regulator_init_data + * + * This structure contains fixed voltage regulator configuration + * information that must be passed by platform code to the fixed + * voltage regulator driver. + */ struct fixed_voltage_config { const char *supply_name; int microvolts; + int gpio; + unsigned enable_high:1; + unsigned enabled_at_boot:1; struct regulator_init_data *init_data; };