regulator: bq24192: add shutdown functionality
[linux-2.6.git] / drivers / regulator / bq2419x-regulator.c
1 /*
2  * bq2419x-regulator.c --  bq2419x
3  *
4  * Regulator driver for BQ2419X charger.
5  *
6  * Copyright (c) 2012, NVIDIA Corporation.
7  *
8  * Author: Laxman Dewangan <ldewangan@nvidia.com>
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License as
12  * published by the Free Software Foundation version 2.
13  *
14  * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
15  * whether express or implied; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
22  * 02111-1307, USA
23  */
24
25 #include <linux/err.h>
26 #include <linux/gpio.h>
27 #include <linux/i2c.h>
28 #include <linux/init.h>
29 #include <linux/kernel.h>
30 #include <linux/module.h>
31 #include <linux/platform_device.h>
32 #include <linux/regmap.h>
33 #include <linux/regulator/driver.h>
34 #include <linux/regulator/machine.h>
35 #include <linux/mfd/bq2419x.h>
36 #include <linux/slab.h>
37
38 struct bq2419x_regulator_info {
39         struct device *dev;
40         struct regulator_desc desc;
41         struct regulator_dev *rdev;
42         struct bq2419x_chip *chip;
43         int gpio_otg_iusb;
44         struct mutex mutex;
45         int shutdown_complete;
46 };
47
48 static int bq2419x_regulator_enable_time(struct regulator_dev *rdev)
49 {
50         return 500000;
51 }
52
53 static int bq2419x_dcdc_enable(struct regulator_dev *rdev)
54 {
55         struct bq2419x_regulator_info *bq = rdev_get_drvdata(rdev);
56         int ret;
57
58         if (gpio_is_valid(bq->gpio_otg_iusb))
59                 gpio_set_value(bq->gpio_otg_iusb, 1);
60
61         mutex_lock(&bq->mutex);
62         if (bq && bq->shutdown_complete) {
63                 mutex_unlock(&bq->mutex);
64                 return -ENODEV;
65         }
66         ret = regmap_update_bits(bq->chip->regmap, BQ2419X_OTG,
67                         BQ2419X_OTG_ENABLE_MASK, BQ2419X_OTG_ENABLE);
68         if (ret < 0) {
69                 dev_err(bq->dev, "register %d update failed with err %d",
70                          BQ2419X_OTG, ret);
71                 mutex_unlock(&bq->mutex);
72                 return ret;
73         }
74         mutex_unlock(&bq->mutex);
75         return ret;
76 }
77
78 static int bq2419x_dcdc_disable(struct regulator_dev *rdev)
79 {
80         struct bq2419x_regulator_info *bq = rdev_get_drvdata(rdev);
81         int ret = 0;
82
83         mutex_lock(&bq->mutex);
84         if (bq && bq->shutdown_complete) {
85                 mutex_unlock(&bq->mutex);
86                 return -ENODEV;
87         }
88
89         ret = regmap_update_bits(bq->chip->regmap, BQ2419X_OTG,
90                                         BQ2419X_OTG_ENABLE_MASK, 0x10);
91         if (ret < 0) {
92                 dev_err(bq->dev, "register %d update failed with err %d",
93                         BQ2419X_OTG, ret);
94                 mutex_unlock(&bq->mutex);
95                 return ret;
96         }
97
98         if (gpio_is_valid(bq->gpio_otg_iusb))
99                 gpio_set_value(bq->gpio_otg_iusb, 0);
100
101         mutex_unlock(&bq->mutex);
102         return ret;
103 }
104
105 static int bq2419x_dcdc_is_enabled(struct regulator_dev *rdev)
106 {
107         struct bq2419x_regulator_info *bq = rdev_get_drvdata(rdev);
108         int ret;
109         unsigned int data;
110
111         mutex_lock(&bq->mutex);
112         if (bq && bq->shutdown_complete) {
113                 mutex_unlock(&bq->mutex);
114                 return -ENODEV;
115         }
116         ret = regmap_read(bq->chip->regmap, BQ2419X_OTG, &data);
117         if (ret < 0) {
118                 dev_err(bq->dev, "register %d read failed with err %d",
119                         BQ2419X_OTG, ret);
120                 mutex_unlock(&bq->mutex);
121                 return ret;
122         }
123         mutex_unlock(&bq->mutex);
124         return (data & BQ2419X_OTG_ENABLE_MASK) == BQ2419X_OTG_ENABLE;
125 }
126
127 static struct regulator_ops bq2419x_dcdc_ops = {
128         .enable                 = bq2419x_dcdc_enable,
129         .disable                = bq2419x_dcdc_disable,
130         .is_enabled             = bq2419x_dcdc_is_enabled,
131         .enable_time            = bq2419x_regulator_enable_time,
132 };
133
134 static void bq2419x_regulator_shutdown(struct platform_device *pdev)
135 {
136         struct bq2419x_regulator_info *bq = platform_get_drvdata(pdev);
137
138         mutex_lock(&bq->mutex);
139         bq->shutdown_complete = 1;
140         mutex_unlock(&bq->mutex);
141 }
142
143 static int __devinit bq2419x_regulator_probe(struct platform_device *pdev)
144 {
145         struct bq2419x_regulator_platform_data *pdata = NULL;
146         struct bq2419x_platform_data *chip_pdata;
147         struct regulator_dev *rdev;
148         struct bq2419x_regulator_info *bq;
149         int ret;
150
151         chip_pdata = dev_get_platdata(pdev->dev.parent);
152         if (chip_pdata)
153                 pdata = chip_pdata->reg_pdata;
154
155         if (!pdata) {
156                 dev_err(&pdev->dev, "No Platform data");
157                 return -EIO;
158         }
159
160         bq = devm_kzalloc(&pdev->dev, sizeof(*bq), GFP_KERNEL);
161         if (!bq) {
162                 dev_err(&pdev->dev, "Memory allocation failed\n");
163                 return -ENOMEM;
164         }
165
166         bq->dev = &pdev->dev;
167         bq->chip = dev_get_drvdata(pdev->dev.parent);
168
169         bq->gpio_otg_iusb = pdata->gpio_otg_iusb;
170         bq->desc.name = "bq2419x-vbus";
171         bq->desc.id = 0;
172         bq->desc.ops = &bq2419x_dcdc_ops;
173         bq->desc.type = REGULATOR_VOLTAGE;
174         bq->desc.owner = THIS_MODULE;
175         bq->shutdown_complete = 0;
176         mutex_init(&bq->mutex);
177
178         platform_set_drvdata(pdev, bq);
179
180         if (gpio_is_valid(bq->gpio_otg_iusb)) {
181                 ret = gpio_request(bq->gpio_otg_iusb, dev_name(&pdev->dev));
182                 if (ret < 0) {
183                         dev_err(&pdev->dev,
184                                 "gpio request failed, err = %d\n", ret);
185                         return ret;
186                 }
187                 gpio_direction_output(bq->gpio_otg_iusb, 0);
188         }
189
190         /* Register the regulators */
191         rdev = regulator_register(&bq->desc, &pdev->dev,
192                         pdata->reg_init_data, bq, NULL);
193         if (IS_ERR(rdev)) {
194                 ret = PTR_ERR(rdev);
195                 dev_err(bq->dev, "regulator register failed, err %d\n", ret);
196                 goto err_init;
197         }
198
199         bq->rdev = rdev;
200
201         ret = regmap_update_bits(bq->chip->regmap, BQ2419X_OTG,
202                                         BQ2419X_OTG_ENABLE_MASK, 0x10);
203         if (ret < 0) {
204                 dev_err(bq->dev, "register %d update failed with err %d",
205                         BQ2419X_OTG, ret);
206                 goto err_reg_update;
207         }
208         return 0;
209
210 err_reg_update:
211         regulator_unregister(bq->rdev);
212 err_init:
213         if (gpio_is_valid(bq->gpio_otg_iusb))
214                 gpio_free(bq->gpio_otg_iusb);
215         mutex_destroy(&bq->mutex);
216         return ret;
217 }
218
219 static int __devexit bq2419x_regulator_remove(struct platform_device *pdev)
220 {
221         struct bq2419x_regulator_info *bq = platform_get_drvdata(pdev);
222
223         mutex_destroy(&bq->mutex);
224         regulator_unregister(bq->rdev);
225         if (gpio_is_valid(bq->gpio_otg_iusb))
226                 gpio_free(bq->gpio_otg_iusb);
227         return 0;
228 }
229
230 static struct platform_driver bq2419x_regulator_driver = {
231         .driver = {
232                 .name = "bq2419x-pmic",
233                 .owner = THIS_MODULE,
234         },
235         .probe = bq2419x_regulator_probe,
236         .shutdown = bq2419x_regulator_shutdown,
237         .remove = __devexit_p(bq2419x_regulator_remove),
238 };
239
240 static int __init bq2419x_init(void)
241 {
242         return platform_driver_register(&bq2419x_regulator_driver);
243 }
244 subsys_initcall(bq2419x_init);
245
246 static void __exit bq2419x_cleanup(void)
247 {
248         platform_driver_unregister(&bq2419x_regulator_driver);
249 }
250 module_exit(bq2419x_cleanup);
251
252 MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
253 MODULE_DESCRIPTION("BQ2419X voltage regulator driver");
254 MODULE_LICENSE("GPL v2");