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/module.h> 24 #include <linux/platform_device.h> 25 #include <linux/regulator/driver.h> 26 #include <linux/regulator/fixed.h> 27 #include <linux/gpio.h> 28 #include <linux/delay.h> 29 #include <linux/slab.h> 30 31 struct fixed_voltage_data { 32 struct regulator_desc desc; 33 struct regulator_dev *dev; 34 int microvolts; 35 int gpio; 36 unsigned startup_delay; 37 bool enable_high; 38 bool is_enabled; 39 }; 40 41 static int fixed_voltage_is_enabled(struct regulator_dev *dev) 42 { 43 struct fixed_voltage_data *data = rdev_get_drvdata(dev); 44 45 return data->is_enabled; 46 } 47 48 static int fixed_voltage_enable(struct regulator_dev *dev) 49 { 50 struct fixed_voltage_data *data = rdev_get_drvdata(dev); 51 52 if (gpio_is_valid(data->gpio)) { 53 gpio_set_value_cansleep(data->gpio, data->enable_high); 54 data->is_enabled = true; 55 } 56 57 return 0; 58 } 59 60 static int fixed_voltage_disable(struct regulator_dev *dev) 61 { 62 struct fixed_voltage_data *data = rdev_get_drvdata(dev); 63 64 if (gpio_is_valid(data->gpio)) { 65 gpio_set_value_cansleep(data->gpio, !data->enable_high); 66 data->is_enabled = false; 67 } 68 69 return 0; 70 } 71 72 static int fixed_voltage_enable_time(struct regulator_dev *dev) 73 { 74 struct fixed_voltage_data *data = rdev_get_drvdata(dev); 75 76 return data->startup_delay; 77 } 78 79 static int fixed_voltage_get_voltage(struct regulator_dev *dev) 80 { 81 struct fixed_voltage_data *data = rdev_get_drvdata(dev); 82 83 return data->microvolts; 84 } 85 86 static int fixed_voltage_list_voltage(struct regulator_dev *dev, 87 unsigned selector) 88 { 89 struct fixed_voltage_data *data = rdev_get_drvdata(dev); 90 91 if (selector != 0) 92 return -EINVAL; 93 94 return data->microvolts; 95 } 96 97 static struct regulator_ops fixed_voltage_ops = { 98 .is_enabled = fixed_voltage_is_enabled, 99 .enable = fixed_voltage_enable, 100 .disable = fixed_voltage_disable, 101 .enable_time = fixed_voltage_enable_time, 102 .get_voltage = fixed_voltage_get_voltage, 103 .list_voltage = fixed_voltage_list_voltage, 104 }; 105 106 static int __devinit reg_fixed_voltage_probe(struct platform_device *pdev) 107 { 108 struct fixed_voltage_config *config = pdev->dev.platform_data; 109 struct fixed_voltage_data *drvdata; 110 int ret; 111 112 drvdata = kzalloc(sizeof(struct fixed_voltage_data), GFP_KERNEL); 113 if (drvdata == NULL) { 114 dev_err(&pdev->dev, "Failed to allocate device data\n"); 115 ret = -ENOMEM; 116 goto err; 117 } 118 119 drvdata->desc.name = kstrdup(config->supply_name, GFP_KERNEL); 120 if (drvdata->desc.name == NULL) { 121 dev_err(&pdev->dev, "Failed to allocate supply name\n"); 122 ret = -ENOMEM; 123 goto err; 124 } 125 drvdata->desc.type = REGULATOR_VOLTAGE; 126 drvdata->desc.owner = THIS_MODULE; 127 drvdata->desc.ops = &fixed_voltage_ops; 128 drvdata->desc.n_voltages = 1; 129 130 drvdata->microvolts = config->microvolts; 131 drvdata->gpio = config->gpio; 132 drvdata->startup_delay = config->startup_delay; 133 134 if (gpio_is_valid(config->gpio)) { 135 drvdata->enable_high = config->enable_high; 136 137 /* FIXME: Remove below print warning 138 * 139 * config->gpio must be set to -EINVAL by platform code if 140 * GPIO control is not required. However, early adopters 141 * not requiring GPIO control may forget to initialize 142 * config->gpio to -EINVAL. This will cause GPIO 0 to be used 143 * for GPIO control. 144 * 145 * This warning will be removed once there are a couple of users 146 * for this driver. 147 */ 148 if (!config->gpio) 149 dev_warn(&pdev->dev, 150 "using GPIO 0 for regulator enable control\n"); 151 152 ret = gpio_request(config->gpio, config->supply_name); 153 if (ret) { 154 dev_err(&pdev->dev, 155 "Could not obtain regulator enable GPIO %d: %d\n", 156 config->gpio, ret); 157 goto err_name; 158 } 159 160 /* set output direction without changing state 161 * to prevent glitch 162 */ 163 drvdata->is_enabled = config->enabled_at_boot; 164 ret = drvdata->is_enabled ? 165 config->enable_high : !config->enable_high; 166 167 ret = gpio_direction_output(config->gpio, ret); 168 if (ret) { 169 dev_err(&pdev->dev, 170 "Could not configure regulator enable GPIO %d direction: %d\n", 171 config->gpio, ret); 172 goto err_gpio; 173 } 174 175 } else { 176 /* Regulator without GPIO control is considered 177 * always enabled 178 */ 179 drvdata->is_enabled = true; 180 } 181 182 drvdata->dev = regulator_register(&drvdata->desc, &pdev->dev, 183 config->init_data, drvdata); 184 if (IS_ERR(drvdata->dev)) { 185 ret = PTR_ERR(drvdata->dev); 186 dev_err(&pdev->dev, "Failed to register regulator: %d\n", ret); 187 goto err_gpio; 188 } 189 190 platform_set_drvdata(pdev, drvdata); 191 192 dev_dbg(&pdev->dev, "%s supplying %duV\n", drvdata->desc.name, 193 drvdata->microvolts); 194 195 return 0; 196 197 err_gpio: 198 if (gpio_is_valid(config->gpio)) 199 gpio_free(config->gpio); 200 err_name: 201 kfree(drvdata->desc.name); 202 err: 203 kfree(drvdata); 204 return ret; 205 } 206 207 static int __devexit reg_fixed_voltage_remove(struct platform_device *pdev) 208 { 209 struct fixed_voltage_data *drvdata = platform_get_drvdata(pdev); 210 211 regulator_unregister(drvdata->dev); 212 if (gpio_is_valid(drvdata->gpio)) 213 gpio_free(drvdata->gpio); 214 kfree(drvdata->desc.name); 215 kfree(drvdata); 216 217 return 0; 218 } 219 220 static struct platform_driver regulator_fixed_voltage_driver = { 221 .probe = reg_fixed_voltage_probe, 222 .remove = __devexit_p(reg_fixed_voltage_remove), 223 .driver = { 224 .name = "reg-fixed-voltage", 225 .owner = THIS_MODULE, 226 }, 227 }; 228 229 static int __init regulator_fixed_voltage_init(void) 230 { 231 return platform_driver_register(®ulator_fixed_voltage_driver); 232 } 233 subsys_initcall(regulator_fixed_voltage_init); 234 235 static void __exit regulator_fixed_voltage_exit(void) 236 { 237 platform_driver_unregister(®ulator_fixed_voltage_driver); 238 } 239 module_exit(regulator_fixed_voltage_exit); 240 241 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); 242 MODULE_DESCRIPTION("Fixed voltage regulator"); 243 MODULE_LICENSE("GPL"); 244 MODULE_ALIAS("platform:reg-fixed-voltage"); 245