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