Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
jz4740-battery.c
Go to the documentation of this file.
1 /*
2  * Battery measurement code for Ingenic JZ SOC.
3  *
4  * Copyright (C) 2009 Jiejing Zhang <[email protected]>
5  * Copyright (C) 2010, Lars-Peter Clausen <[email protected]>
6  *
7  * based on tosa_battery.c
8  *
9  * Copyright (C) 2008 Marek Vasut <[email protected]>
10 *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License version 2 as
13  * published by the Free Software Foundation.
14  *
15  */
16 
17 #include <linux/interrupt.h>
18 #include <linux/kernel.h>
19 #include <linux/module.h>
20 #include <linux/platform_device.h>
21 #include <linux/slab.h>
22 #include <linux/io.h>
23 
24 #include <linux/delay.h>
25 #include <linux/gpio.h>
26 #include <linux/mfd/core.h>
27 #include <linux/power_supply.h>
28 
30 #include <linux/jz4740-adc.h>
31 
32 struct jz_battery {
35 
36  struct resource *mem;
37  void __iomem *base;
38 
39  int irq;
41 
42  const struct mfd_cell *cell;
43 
44  int status;
45  long voltage;
46 
48 
51 
52  struct mutex lock;
53 };
54 
55 static inline struct jz_battery *psy_to_jz_battery(struct power_supply *psy)
56 {
57  return container_of(psy, struct jz_battery, battery);
58 }
59 
60 static irqreturn_t jz_battery_irq_handler(int irq, void *devid)
61 {
62  struct jz_battery *battery = devid;
63 
64  complete(&battery->read_completion);
65  return IRQ_HANDLED;
66 }
67 
68 static long jz_battery_read_voltage(struct jz_battery *battery)
69 {
70  long t;
71  unsigned long val;
72  long voltage;
73 
74  mutex_lock(&battery->lock);
75 
77 
78  enable_irq(battery->irq);
79  battery->cell->enable(battery->pdev);
80 
82  HZ);
83 
84  if (t > 0) {
85  val = readw(battery->base) & 0xfff;
86 
87  if (battery->pdata->info.voltage_max_design <= 2500000)
88  val = (val * 78125UL) >> 7UL;
89  else
90  val = ((val * 924375UL) >> 9UL) + 33000;
91  voltage = (long)val;
92  } else {
93  voltage = t ? t : -ETIMEDOUT;
94  }
95 
96  battery->cell->disable(battery->pdev);
97  disable_irq(battery->irq);
98 
99  mutex_unlock(&battery->lock);
100 
101  return voltage;
102 }
103 
104 static int jz_battery_get_capacity(struct power_supply *psy)
105 {
106  struct jz_battery *jz_battery = psy_to_jz_battery(psy);
107  struct power_supply_info *info = &jz_battery->pdata->info;
108  long voltage;
109  int ret;
110  int voltage_span;
111 
112  voltage = jz_battery_read_voltage(jz_battery);
113 
114  if (voltage < 0)
115  return voltage;
116 
117  voltage_span = info->voltage_max_design - info->voltage_min_design;
118  ret = ((voltage - info->voltage_min_design) * 100) / voltage_span;
119 
120  if (ret > 100)
121  ret = 100;
122  else if (ret < 0)
123  ret = 0;
124 
125  return ret;
126 }
127 
128 static int jz_battery_get_property(struct power_supply *psy,
129  enum power_supply_property psp, union power_supply_propval *val)
130 {
131  struct jz_battery *jz_battery = psy_to_jz_battery(psy);
132  struct power_supply_info *info = &jz_battery->pdata->info;
133  long voltage;
134 
135  switch (psp) {
137  val->intval = jz_battery->status;
138  break;
140  val->intval = jz_battery->pdata->info.technology;
141  break;
143  voltage = jz_battery_read_voltage(jz_battery);
144  if (voltage < info->voltage_min_design)
146  else
148  break;
150  val->intval = jz_battery_get_capacity(psy);
151  break;
153  val->intval = jz_battery_read_voltage(jz_battery);
154  if (val->intval < 0)
155  return val->intval;
156  break;
158  val->intval = info->voltage_max_design;
159  break;
161  val->intval = info->voltage_min_design;
162  break;
164  val->intval = 1;
165  break;
166  default:
167  return -EINVAL;
168  }
169  return 0;
170 }
171 
172 static void jz_battery_external_power_changed(struct power_supply *psy)
173 {
174  struct jz_battery *jz_battery = psy_to_jz_battery(psy);
175 
176  mod_delayed_work(system_wq, &jz_battery->work, 0);
177 }
178 
179 static irqreturn_t jz_battery_charge_irq(int irq, void *data)
180 {
181  struct jz_battery *jz_battery = data;
182 
183  mod_delayed_work(system_wq, &jz_battery->work, 0);
184 
185  return IRQ_HANDLED;
186 }
187 
188 static void jz_battery_update(struct jz_battery *jz_battery)
189 {
190  int status;
191  long voltage;
192  bool has_changed = false;
193  int is_charging;
194 
195  if (gpio_is_valid(jz_battery->pdata->gpio_charge)) {
196  is_charging = gpio_get_value(jz_battery->pdata->gpio_charge);
197  is_charging ^= jz_battery->pdata->gpio_charge_active_low;
198  if (is_charging)
200  else
202 
203  if (status != jz_battery->status) {
204  jz_battery->status = status;
205  has_changed = true;
206  }
207  }
208 
209  voltage = jz_battery_read_voltage(jz_battery);
210  if (abs(voltage - jz_battery->voltage) < 50000) {
211  jz_battery->voltage = voltage;
212  has_changed = true;
213  }
214 
215  if (has_changed)
216  power_supply_changed(&jz_battery->battery);
217 }
218 
219 static enum power_supply_property jz_battery_properties[] = {
228 };
229 
230 static void jz_battery_work(struct work_struct *work)
231 {
232  /* Too small interval will increase system workload */
233  const int interval = HZ * 30;
234  struct jz_battery *jz_battery = container_of(work, struct jz_battery,
235  work.work);
236 
237  jz_battery_update(jz_battery);
238  schedule_delayed_work(&jz_battery->work, interval);
239 }
240 
241 static int __devinit jz_battery_probe(struct platform_device *pdev)
242 {
243  int ret = 0;
244  struct jz_battery_platform_data *pdata = pdev->dev.parent->platform_data;
245  struct jz_battery *jz_battery;
246  struct power_supply *battery;
247 
248  if (!pdata) {
249  dev_err(&pdev->dev, "No platform_data supplied\n");
250  return -ENXIO;
251  }
252 
253  jz_battery = kzalloc(sizeof(*jz_battery), GFP_KERNEL);
254  if (!jz_battery) {
255  dev_err(&pdev->dev, "Failed to allocate driver structure\n");
256  return -ENOMEM;
257  }
258 
259  jz_battery->cell = mfd_get_cell(pdev);
260 
261  jz_battery->irq = platform_get_irq(pdev, 0);
262  if (jz_battery->irq < 0) {
263  ret = jz_battery->irq;
264  dev_err(&pdev->dev, "Failed to get platform irq: %d\n", ret);
265  goto err_free;
266  }
267 
268  jz_battery->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
269  if (!jz_battery->mem) {
270  ret = -ENOENT;
271  dev_err(&pdev->dev, "Failed to get platform mmio resource\n");
272  goto err_free;
273  }
274 
275  jz_battery->mem = request_mem_region(jz_battery->mem->start,
276  resource_size(jz_battery->mem), pdev->name);
277  if (!jz_battery->mem) {
278  ret = -EBUSY;
279  dev_err(&pdev->dev, "Failed to request mmio memory region\n");
280  goto err_free;
281  }
282 
283  jz_battery->base = ioremap_nocache(jz_battery->mem->start,
284  resource_size(jz_battery->mem));
285  if (!jz_battery->base) {
286  ret = -EBUSY;
287  dev_err(&pdev->dev, "Failed to ioremap mmio memory\n");
288  goto err_release_mem_region;
289  }
290 
291  battery = &jz_battery->battery;
292  battery->name = pdata->info.name;
293  battery->type = POWER_SUPPLY_TYPE_BATTERY;
294  battery->properties = jz_battery_properties;
295  battery->num_properties = ARRAY_SIZE(jz_battery_properties);
296  battery->get_property = jz_battery_get_property;
297  battery->external_power_changed = jz_battery_external_power_changed;
298  battery->use_for_apm = 1;
299 
300  jz_battery->pdata = pdata;
301  jz_battery->pdev = pdev;
302 
303  init_completion(&jz_battery->read_completion);
304  mutex_init(&jz_battery->lock);
305 
306  INIT_DELAYED_WORK(&jz_battery->work, jz_battery_work);
307 
308  ret = request_irq(jz_battery->irq, jz_battery_irq_handler, 0, pdev->name,
309  jz_battery);
310  if (ret) {
311  dev_err(&pdev->dev, "Failed to request irq %d\n", ret);
312  goto err_iounmap;
313  }
314  disable_irq(jz_battery->irq);
315 
316  if (gpio_is_valid(pdata->gpio_charge)) {
317  ret = gpio_request(pdata->gpio_charge, dev_name(&pdev->dev));
318  if (ret) {
319  dev_err(&pdev->dev, "charger state gpio request failed.\n");
320  goto err_free_irq;
321  }
322  ret = gpio_direction_input(pdata->gpio_charge);
323  if (ret) {
324  dev_err(&pdev->dev, "charger state gpio set direction failed.\n");
325  goto err_free_gpio;
326  }
327 
328  jz_battery->charge_irq = gpio_to_irq(pdata->gpio_charge);
329 
330  if (jz_battery->charge_irq >= 0) {
331  ret = request_irq(jz_battery->charge_irq,
332  jz_battery_charge_irq,
334  dev_name(&pdev->dev), jz_battery);
335  if (ret) {
336  dev_err(&pdev->dev, "Failed to request charge irq: %d\n", ret);
337  goto err_free_gpio;
338  }
339  }
340  } else {
341  jz_battery->charge_irq = -1;
342  }
343 
344  if (jz_battery->pdata->info.voltage_max_design <= 2500000)
347  else
349 
350  ret = power_supply_register(&pdev->dev, &jz_battery->battery);
351  if (ret) {
352  dev_err(&pdev->dev, "power supply battery register failed.\n");
353  goto err_free_charge_irq;
354  }
355 
356  platform_set_drvdata(pdev, jz_battery);
357  schedule_delayed_work(&jz_battery->work, 0);
358 
359  return 0;
360 
361 err_free_charge_irq:
362  if (jz_battery->charge_irq >= 0)
363  free_irq(jz_battery->charge_irq, jz_battery);
364 err_free_gpio:
365  if (gpio_is_valid(pdata->gpio_charge))
366  gpio_free(jz_battery->pdata->gpio_charge);
367 err_free_irq:
368  free_irq(jz_battery->irq, jz_battery);
369 err_iounmap:
370  platform_set_drvdata(pdev, NULL);
371  iounmap(jz_battery->base);
372 err_release_mem_region:
373  release_mem_region(jz_battery->mem->start, resource_size(jz_battery->mem));
374 err_free:
375  kfree(jz_battery);
376  return ret;
377 }
378 
379 static int __devexit jz_battery_remove(struct platform_device *pdev)
380 {
381  struct jz_battery *jz_battery = platform_get_drvdata(pdev);
382 
383  cancel_delayed_work_sync(&jz_battery->work);
384 
385  if (gpio_is_valid(jz_battery->pdata->gpio_charge)) {
386  if (jz_battery->charge_irq >= 0)
387  free_irq(jz_battery->charge_irq, jz_battery);
388  gpio_free(jz_battery->pdata->gpio_charge);
389  }
390 
391  power_supply_unregister(&jz_battery->battery);
392 
393  free_irq(jz_battery->irq, jz_battery);
394 
395  iounmap(jz_battery->base);
396  release_mem_region(jz_battery->mem->start, resource_size(jz_battery->mem));
397  kfree(jz_battery);
398 
399  return 0;
400 }
401 
402 #ifdef CONFIG_PM
403 static int jz_battery_suspend(struct device *dev)
404 {
405  struct jz_battery *jz_battery = dev_get_drvdata(dev);
406 
407  cancel_delayed_work_sync(&jz_battery->work);
408  jz_battery->status = POWER_SUPPLY_STATUS_UNKNOWN;
409 
410  return 0;
411 }
412 
413 static int jz_battery_resume(struct device *dev)
414 {
415  struct jz_battery *jz_battery = dev_get_drvdata(dev);
416 
417  schedule_delayed_work(&jz_battery->work, 0);
418 
419  return 0;
420 }
421 
422 static const struct dev_pm_ops jz_battery_pm_ops = {
423  .suspend = jz_battery_suspend,
424  .resume = jz_battery_resume,
425 };
426 
427 #define JZ_BATTERY_PM_OPS (&jz_battery_pm_ops)
428 #else
429 #define JZ_BATTERY_PM_OPS NULL
430 #endif
431 
432 static struct platform_driver jz_battery_driver = {
433  .probe = jz_battery_probe,
434  .remove = __devexit_p(jz_battery_remove),
435  .driver = {
436  .name = "jz4740-battery",
437  .owner = THIS_MODULE,
438  .pm = JZ_BATTERY_PM_OPS,
439  },
440 };
441 
442 module_platform_driver(jz_battery_driver);
443 
444 MODULE_ALIAS("platform:jz4740-battery");
445 MODULE_LICENSE("GPL");
446 MODULE_AUTHOR("Lars-Peter Clausen <[email protected]>");
447 MODULE_DESCRIPTION("JZ4740 SoC battery driver");