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