1 /* 2 * fixed.c 3 * 4 * Copyright 2008 Wolfson Microelectronics PLC. 5 * 6 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> 7 * 8 * Copyright (c) 2009 Nokia Corporation 9 * Roger Quadros <ext-roger.quadros@nokia.com> 10 * 11 * This program is free software; you can redistribute it and/or 12 * modify it under the terms of the GNU General Public License as 13 * published by the Free Software Foundation; either version 2 of the 14 * License, or (at your option) any later version. 15 * 16 * This is useful for systems with mixed controllable and 17 * non-controllable regulators, as well as for allowing testing on 18 * systems with no controllable regulators. 19 */ 20 21 #include <linux/err.h> 22 #include <linux/mutex.h> 23 #include <linux/platform_device.h> 24 #include <linux/regulator/driver.h> 25 #include <linux/regulator/fixed.h> 26 #include <linux/gpio.h> 27 28 struct fixed_voltage_data { 29 struct regulator_desc desc; 30 struct regulator_dev *dev; 31 int microvolts; 32 int gpio; 33 unsigned enable_high:1; 34 unsigned is_enabled:1; 35 }; 36 37 static int fixed_voltage_is_enabled(struct regulator_dev *dev) 38 { 39 struct fixed_voltage_data *data = rdev_get_drvdata(dev); 40 41 return data->is_enabled; 42 } 43 44 static int fixed_voltage_enable(struct regulator_dev *dev) 45 { 46 struct fixed_voltage_data *data = rdev_get_drvdata(dev); 47 48 if (gpio_is_valid(data->gpio)) { 49 gpio_set_value_cansleep(data->gpio, data->enable_high); 50 data->is_enabled = 1; 51 } 52 53 return 0; 54 } 55 56 static int fixed_voltage_disable(struct regulator_dev *dev) 57 { 58 struct fixed_voltage_data *data = rdev_get_drvdata(dev); 59 60 if (gpio_is_valid(data->gpio)) { 61 gpio_set_value_cansleep(data->gpio, !data->enable_high); 62 data->is_enabled = 0; 63 } 64 65 return 0; 66 } 67 68 static int fixed_voltage_get_voltage(struct regulator_dev *dev) 69 { 70 struct fixed_voltage_data *data = rdev_get_drvdata(dev); 71 72 return data->microvolts; 73 } 74 75 static int fixed_voltage_list_voltage(struct regulator_dev *dev, 76 unsigned selector) 77 { 78 struct fixed_voltage_data *data = rdev_get_drvdata(dev); 79 80 if (selector != 0) 81 return -EINVAL; 82 83 return data->microvolts; 84 } 85 86 static struct regulator_ops fixed_voltage_ops = { 87 .is_enabled = fixed_voltage_is_enabled, 88 .enable = fixed_voltage_enable, 89 .disable = fixed_voltage_disable, 90 .get_voltage = fixed_voltage_get_voltage, 91 .list_voltage = fixed_voltage_list_voltage, 92 }; 93 94 static int regulator_fixed_voltage_probe(struct platform_device *pdev) 95 { 96 struct fixed_voltage_config *config = pdev->dev.platform_data; 97 struct fixed_voltage_data *drvdata; 98 int ret; 99 100 drvdata = kzalloc(sizeof(struct fixed_voltage_data), GFP_KERNEL); 101 if (drvdata == NULL) { 102 dev_err(&pdev->dev, "Failed to allocate device data\n"); 103 ret = -ENOMEM; 104 goto err; 105 } 106 107 drvdata->desc.name = kstrdup(config->supply_name, GFP_KERNEL); 108 if (drvdata->desc.name == NULL) { 109 dev_err(&pdev->dev, "Failed to allocate supply name\n"); 110 ret = -ENOMEM; 111 goto err; 112 } 113 drvdata->desc.type = REGULATOR_VOLTAGE; 114 drvdata->desc.owner = THIS_MODULE; 115 drvdata->desc.ops = &fixed_voltage_ops; 116 drvdata->desc.n_voltages = 1; 117 118 drvdata->microvolts = config->microvolts; 119 drvdata->gpio = config->gpio; 120 121 if (gpio_is_valid(config->gpio)) { 122 drvdata->enable_high = config->enable_high; 123 124 /* FIXME: Remove below print warning 125 * 126 * config->gpio must be set to -EINVAL by platform code if 127 * GPIO control is not required. However, early adopters 128 * not requiring GPIO control may forget to initialize 129 * config->gpio to -EINVAL. This will cause GPIO 0 to be used 130 * for GPIO control. 131 * 132 * This warning will be removed once there are a couple of users 133 * for this driver. 134 */ 135 if (!config->gpio) 136 dev_warn(&pdev->dev, 137 "using GPIO 0 for regulator enable control\n"); 138 139 ret = gpio_request(config->gpio, config->supply_name); 140 if (ret) { 141 dev_err(&pdev->dev, 142 "Could not obtain regulator enable GPIO %d: %d\n", 143 config->gpio, ret); 144 goto err_name; 145 } 146 147 /* set output direction without changing state 148 * to prevent glitch 149 */ 150 drvdata->is_enabled = config->enabled_at_boot; 151 ret = drvdata->is_enabled ? 152 config->enable_high : !config->enable_high; 153 154 ret = gpio_direction_output(config->gpio, ret); 155 if (ret) { 156 dev_err(&pdev->dev, 157 "Could not configure regulator enable GPIO %d direction: %d\n", 158 config->gpio, ret); 159 goto err_gpio; 160 } 161 162 } else { 163 /* Regulator without GPIO control is considered 164 * always enabled 165 */ 166 drvdata->is_enabled = 1; 167 } 168 169 drvdata->dev = regulator_register(&drvdata->desc, &pdev->dev, 170 config->init_data, drvdata); 171 if (IS_ERR(drvdata->dev)) { 172 ret = PTR_ERR(drvdata->dev); 173 dev_err(&pdev->dev, "Failed to register regulator: %d\n", ret); 174 goto err_gpio; 175 } 176 177 platform_set_drvdata(pdev, drvdata); 178 179 dev_dbg(&pdev->dev, "%s supplying %duV\n", drvdata->desc.name, 180 drvdata->microvolts); 181 182 return 0; 183 184 err_gpio: 185 if (gpio_is_valid(config->gpio)) 186 gpio_free(config->gpio); 187 err_name: 188 kfree(drvdata->desc.name); 189 err: 190 kfree(drvdata); 191 return ret; 192 } 193 194 static int regulator_fixed_voltage_remove(struct platform_device *pdev) 195 { 196 struct fixed_voltage_data *drvdata = platform_get_drvdata(pdev); 197 198 regulator_unregister(drvdata->dev); 199 if (gpio_is_valid(drvdata->gpio)) 200 gpio_free(drvdata->gpio); 201 kfree(drvdata->desc.name); 202 kfree(drvdata); 203 204 return 0; 205 } 206 207 static struct platform_driver regulator_fixed_voltage_driver = { 208 .probe = regulator_fixed_voltage_probe, 209 .remove = regulator_fixed_voltage_remove, 210 .driver = { 211 .name = "reg-fixed-voltage", 212 }, 213 }; 214 215 static int __init regulator_fixed_voltage_init(void) 216 { 217 return platform_driver_register(®ulator_fixed_voltage_driver); 218 } 219 subsys_initcall(regulator_fixed_voltage_init); 220 221 static void __exit regulator_fixed_voltage_exit(void) 222 { 223 platform_driver_unregister(®ulator_fixed_voltage_driver); 224 } 225 module_exit(regulator_fixed_voltage_exit); 226 227 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); 228 MODULE_DESCRIPTION("Fixed voltage regulator"); 229 MODULE_LICENSE("GPL"); 230 MODULE_ALIAS("platform:reg-fixed-voltage"); 231