Version:  2.0.40 2.2.26 2.4.37 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9 3.10 3.11 3.12 3.13 3.14 3.15 3.16 3.17

Linux/drivers/power/bq24735-charger.c

  1 /*
  2  * Battery charger driver for TI BQ24735
  3  *
  4  * Copyright (c) 2013, NVIDIA CORPORATION.  All rights reserved.
  5  *
  6  * This program is free software; you can redistribute it and/or modify
  7  * it under the terms of the GNU General Public License as published by
  8  * the Free Software Foundation;
  9  *
 10  * This program is distributed in the hope that it will be useful, but WITHOUT
 11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 13  * more details.
 14  *
 15  * You should have received a copy of the GNU General Public License along
 16  * with this program; if not, write to the Free Software Foundation, Inc.,
 17  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 18  */
 19 
 20 #include <linux/err.h>
 21 #include <linux/gpio.h>
 22 #include <linux/i2c.h>
 23 #include <linux/init.h>
 24 #include <linux/interrupt.h>
 25 #include <linux/kernel.h>
 26 #include <linux/module.h>
 27 #include <linux/of.h>
 28 #include <linux/of_gpio.h>
 29 #include <linux/power_supply.h>
 30 #include <linux/slab.h>
 31 
 32 #include <linux/power/bq24735-charger.h>
 33 
 34 #define BQ24735_CHG_OPT                 0x12
 35 #define BQ24735_CHG_OPT_CHARGE_DISABLE  (1 << 0)
 36 #define BQ24735_CHG_OPT_AC_PRESENT      (1 << 4)
 37 #define BQ24735_CHARGE_CURRENT          0x14
 38 #define BQ24735_CHARGE_CURRENT_MASK     0x1fc0
 39 #define BQ24735_CHARGE_VOLTAGE          0x15
 40 #define BQ24735_CHARGE_VOLTAGE_MASK     0x7ff0
 41 #define BQ24735_INPUT_CURRENT           0x3f
 42 #define BQ24735_INPUT_CURRENT_MASK      0x1f80
 43 #define BQ24735_MANUFACTURER_ID         0xfe
 44 #define BQ24735_DEVICE_ID               0xff
 45 
 46 struct bq24735 {
 47         struct power_supply     charger;
 48         struct i2c_client       *client;
 49         struct bq24735_platform *pdata;
 50 };
 51 
 52 static inline struct bq24735 *to_bq24735(struct power_supply *psy)
 53 {
 54         return container_of(psy, struct bq24735, charger);
 55 }
 56 
 57 static enum power_supply_property bq24735_charger_properties[] = {
 58         POWER_SUPPLY_PROP_ONLINE,
 59 };
 60 
 61 static inline int bq24735_write_word(struct i2c_client *client, u8 reg,
 62                                      u16 value)
 63 {
 64         return i2c_smbus_write_word_data(client, reg, le16_to_cpu(value));
 65 }
 66 
 67 static inline int bq24735_read_word(struct i2c_client *client, u8 reg)
 68 {
 69         s32 ret = i2c_smbus_read_word_data(client, reg);
 70 
 71         return ret < 0 ? ret : le16_to_cpu(ret);
 72 }
 73 
 74 static int bq24735_update_word(struct i2c_client *client, u8 reg,
 75                                u16 mask, u16 value)
 76 {
 77         unsigned int tmp;
 78         int ret;
 79 
 80         ret = bq24735_read_word(client, reg);
 81         if (ret < 0)
 82                 return ret;
 83 
 84         tmp = ret & ~mask;
 85         tmp |= value & mask;
 86 
 87         return bq24735_write_word(client, reg, tmp);
 88 }
 89 
 90 static inline int bq24735_enable_charging(struct bq24735 *charger)
 91 {
 92         return bq24735_update_word(charger->client, BQ24735_CHG_OPT,
 93                                    BQ24735_CHG_OPT_CHARGE_DISABLE,
 94                                    ~BQ24735_CHG_OPT_CHARGE_DISABLE);
 95 }
 96 
 97 static inline int bq24735_disable_charging(struct bq24735 *charger)
 98 {
 99         return bq24735_update_word(charger->client, BQ24735_CHG_OPT,
100                                    BQ24735_CHG_OPT_CHARGE_DISABLE,
101                                    BQ24735_CHG_OPT_CHARGE_DISABLE);
102 }
103 
104 static int bq24735_config_charger(struct bq24735 *charger)
105 {
106         struct bq24735_platform *pdata = charger->pdata;
107         int ret;
108         u16 value;
109 
110         if (pdata->charge_current) {
111                 value = pdata->charge_current & BQ24735_CHARGE_CURRENT_MASK;
112 
113                 ret = bq24735_write_word(charger->client,
114                                          BQ24735_CHARGE_CURRENT, value);
115                 if (ret < 0) {
116                         dev_err(&charger->client->dev,
117                                 "Failed to write charger current : %d\n",
118                                 ret);
119                         return ret;
120                 }
121         }
122 
123         if (pdata->charge_voltage) {
124                 value = pdata->charge_voltage & BQ24735_CHARGE_VOLTAGE_MASK;
125 
126                 ret = bq24735_write_word(charger->client,
127                                          BQ24735_CHARGE_VOLTAGE, value);
128                 if (ret < 0) {
129                         dev_err(&charger->client->dev,
130                                 "Failed to write charger voltage : %d\n",
131                                 ret);
132                         return ret;
133                 }
134         }
135 
136         if (pdata->input_current) {
137                 value = pdata->input_current & BQ24735_INPUT_CURRENT_MASK;
138 
139                 ret = bq24735_write_word(charger->client,
140                                          BQ24735_INPUT_CURRENT, value);
141                 if (ret < 0) {
142                         dev_err(&charger->client->dev,
143                                 "Failed to write input current : %d\n",
144                                 ret);
145                         return ret;
146                 }
147         }
148 
149         return 0;
150 }
151 
152 static bool bq24735_charger_is_present(struct bq24735 *charger)
153 {
154         struct bq24735_platform *pdata = charger->pdata;
155         int ret;
156 
157         if (pdata->status_gpio_valid) {
158                 ret = gpio_get_value_cansleep(pdata->status_gpio);
159                 return ret ^= pdata->status_gpio_active_low == 0;
160         } else {
161                 int ac = 0;
162 
163                 ac = bq24735_read_word(charger->client, BQ24735_CHG_OPT);
164                 if (ac < 0) {
165                         dev_err(&charger->client->dev,
166                                 "Failed to read charger options : %d\n",
167                                 ac);
168                         return false;
169                 }
170                 return (ac & BQ24735_CHG_OPT_AC_PRESENT) ? true : false;
171         }
172 
173         return false;
174 }
175 
176 static irqreturn_t bq24735_charger_isr(int irq, void *devid)
177 {
178         struct power_supply *psy = devid;
179         struct bq24735 *charger = to_bq24735(psy);
180 
181         if (bq24735_charger_is_present(charger))
182                 bq24735_enable_charging(charger);
183         else
184                 bq24735_disable_charging(charger);
185 
186         power_supply_changed(psy);
187 
188         return IRQ_HANDLED;
189 }
190 
191 static int bq24735_charger_get_property(struct power_supply *psy,
192                                         enum power_supply_property psp,
193                                         union power_supply_propval *val)
194 {
195         struct bq24735 *charger;
196 
197         charger = container_of(psy, struct bq24735, charger);
198 
199         switch (psp) {
200         case POWER_SUPPLY_PROP_ONLINE:
201                 val->intval = bq24735_charger_is_present(charger) ? 1 : 0;
202                 break;
203         default:
204                 return -EINVAL;
205         }
206 
207         return 0;
208 }
209 
210 static struct bq24735_platform *bq24735_parse_dt_data(struct i2c_client *client)
211 {
212         struct bq24735_platform *pdata;
213         struct device_node *np = client->dev.of_node;
214         u32 val;
215         int ret;
216         enum of_gpio_flags flags;
217 
218         pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL);
219         if (!pdata) {
220                 dev_err(&client->dev,
221                         "Memory alloc for bq24735 pdata failed\n");
222                 return NULL;
223         }
224 
225         pdata->status_gpio = of_get_named_gpio_flags(np, "ti,ac-detect-gpios",
226                                                      0, &flags);
227 
228         if (flags & OF_GPIO_ACTIVE_LOW)
229                 pdata->status_gpio_active_low = 1;
230 
231         ret = of_property_read_u32(np, "ti,charge-current", &val);
232         if (!ret)
233                 pdata->charge_current = val;
234 
235         ret = of_property_read_u32(np, "ti,charge-voltage", &val);
236         if (!ret)
237                 pdata->charge_voltage = val;
238 
239         ret = of_property_read_u32(np, "ti,input-current", &val);
240         if (!ret)
241                 pdata->input_current = val;
242 
243         return pdata;
244 }
245 
246 static int bq24735_charger_probe(struct i2c_client *client,
247                                  const struct i2c_device_id *id)
248 {
249         int ret;
250         struct bq24735 *charger;
251         struct power_supply *supply;
252         char *name;
253 
254         charger = devm_kzalloc(&client->dev, sizeof(*charger), GFP_KERNEL);
255         if (!charger)
256                 return -ENOMEM;
257 
258         charger->pdata = client->dev.platform_data;
259 
260         if (IS_ENABLED(CONFIG_OF) && !charger->pdata && client->dev.of_node)
261                 charger->pdata = bq24735_parse_dt_data(client);
262 
263         if (!charger->pdata) {
264                 dev_err(&client->dev, "no platform data provided\n");
265                 return -EINVAL;
266         }
267 
268         name = (char *)charger->pdata->name;
269         if (!name) {
270                 name = kasprintf(GFP_KERNEL, "bq24735@%s",
271                                  dev_name(&client->dev));
272                 if (!name) {
273                         dev_err(&client->dev, "Failed to alloc device name\n");
274                         return -ENOMEM;
275                 }
276         }
277 
278         charger->client = client;
279 
280         supply = &charger->charger;
281 
282         supply->name = name;
283         supply->type = POWER_SUPPLY_TYPE_MAINS;
284         supply->properties = bq24735_charger_properties;
285         supply->num_properties = ARRAY_SIZE(bq24735_charger_properties);
286         supply->get_property = bq24735_charger_get_property;
287         supply->supplied_to = charger->pdata->supplied_to;
288         supply->num_supplicants = charger->pdata->num_supplicants;
289         supply->of_node = client->dev.of_node;
290 
291         i2c_set_clientdata(client, charger);
292 
293         ret = bq24735_read_word(client, BQ24735_MANUFACTURER_ID);
294         if (ret < 0) {
295                 dev_err(&client->dev, "Failed to read manufacturer id : %d\n",
296                         ret);
297                 goto err_free_name;
298         } else if (ret != 0x0040) {
299                 dev_err(&client->dev,
300                         "manufacturer id mismatch. 0x0040 != 0x%04x\n", ret);
301                 ret = -ENODEV;
302                 goto err_free_name;
303         }
304 
305         ret = bq24735_read_word(client, BQ24735_DEVICE_ID);
306         if (ret < 0) {
307                 dev_err(&client->dev, "Failed to read device id : %d\n", ret);
308                 goto err_free_name;
309         } else if (ret != 0x000B) {
310                 dev_err(&client->dev,
311                         "device id mismatch. 0x000b != 0x%04x\n", ret);
312                 ret = -ENODEV;
313                 goto err_free_name;
314         }
315 
316         if (gpio_is_valid(charger->pdata->status_gpio)) {
317                 ret = devm_gpio_request(&client->dev,
318                                         charger->pdata->status_gpio,
319                                         name);
320                 if (ret) {
321                         dev_err(&client->dev,
322                                 "Failed GPIO request for GPIO %d: %d\n",
323                                 charger->pdata->status_gpio, ret);
324                 }
325 
326                 charger->pdata->status_gpio_valid = !ret;
327         }
328 
329         ret = bq24735_config_charger(charger);
330         if (ret < 0) {
331                 dev_err(&client->dev, "failed in configuring charger");
332                 goto err_free_name;
333         }
334 
335         /* check for AC adapter presence */
336         if (bq24735_charger_is_present(charger)) {
337                 ret = bq24735_enable_charging(charger);
338                 if (ret < 0) {
339                         dev_err(&client->dev, "Failed to enable charging\n");
340                         goto err_free_name;
341                 }
342         }
343 
344         ret = power_supply_register(&client->dev, supply);
345         if (ret < 0) {
346                 dev_err(&client->dev, "Failed to register power supply: %d\n",
347                         ret);
348                 goto err_free_name;
349         }
350 
351         if (client->irq) {
352                 ret = devm_request_threaded_irq(&client->dev, client->irq,
353                                                 NULL, bq24735_charger_isr,
354                                                 IRQF_TRIGGER_RISING |
355                                                 IRQF_TRIGGER_FALLING |
356                                                 IRQF_ONESHOT,
357                                                 supply->name, supply);
358                 if (ret) {
359                         dev_err(&client->dev,
360                                 "Unable to register IRQ %d err %d\n",
361                                 client->irq, ret);
362                         goto err_unregister_supply;
363                 }
364         }
365 
366         return 0;
367 err_unregister_supply:
368         power_supply_unregister(supply);
369 err_free_name:
370         if (name != charger->pdata->name)
371                 kfree(name);
372 
373         return ret;
374 }
375 
376 static int bq24735_charger_remove(struct i2c_client *client)
377 {
378         struct bq24735 *charger = i2c_get_clientdata(client);
379 
380         if (charger->client->irq)
381                 devm_free_irq(&charger->client->dev, charger->client->irq,
382                               &charger->charger);
383 
384         power_supply_unregister(&charger->charger);
385 
386         if (charger->charger.name != charger->pdata->name)
387                 kfree(charger->charger.name);
388 
389         return 0;
390 }
391 
392 static const struct i2c_device_id bq24735_charger_id[] = {
393         { "bq24735-charger", 0 },
394         {}
395 };
396 MODULE_DEVICE_TABLE(i2c, bq24735_charger_id);
397 
398 static const struct of_device_id bq24735_match_ids[] = {
399         { .compatible = "ti,bq24735", },
400         { /* end */ }
401 };
402 MODULE_DEVICE_TABLE(of, bq24735_match_ids);
403 
404 static struct i2c_driver bq24735_charger_driver = {
405         .driver = {
406                 .name = "bq24735-charger",
407                 .owner = THIS_MODULE,
408                 .of_match_table = bq24735_match_ids,
409         },
410         .probe = bq24735_charger_probe,
411         .remove = bq24735_charger_remove,
412         .id_table = bq24735_charger_id,
413 };
414 
415 module_i2c_driver(bq24735_charger_driver);
416 
417 MODULE_DESCRIPTION("bq24735 battery charging driver");
418 MODULE_AUTHOR("Darbha Sriharsha <dsriharsha@nvidia.com>");
419 MODULE_LICENSE("GPL v2");
420 

This page was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us