aboutsummaryrefslogtreecommitdiffstats
path: root/mm/vmalloc.c
diff options
context:
space:
mode:
Diffstat (limited to 'mm/vmalloc.c')
-rw-r--r--mm/vmalloc.c38
1 files changed, 14 insertions, 24 deletions
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index 266162d2ba28..1ac191ce5641 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -24,6 +24,9 @@
24DEFINE_RWLOCK(vmlist_lock); 24DEFINE_RWLOCK(vmlist_lock);
25struct vm_struct *vmlist; 25struct vm_struct *vmlist;
26 26
27static void *__vmalloc_node(unsigned long size, gfp_t gfp_mask, pgprot_t prot,
28 int node);
29
27static void vunmap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end) 30static void vunmap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end)
28{ 31{
29 pte_t *pte; 32 pte_t *pte;
@@ -238,7 +241,6 @@ struct vm_struct *__get_vm_area(unsigned long size, unsigned long flags,
238 241
239/** 242/**
240 * get_vm_area - reserve a contingous kernel virtual area 243 * get_vm_area - reserve a contingous kernel virtual area
241 *
242 * @size: size of the area 244 * @size: size of the area
243 * @flags: %VM_IOREMAP for I/O mappings or VM_ALLOC 245 * @flags: %VM_IOREMAP for I/O mappings or VM_ALLOC
244 * 246 *
@@ -270,7 +272,7 @@ static struct vm_struct *__find_vm_area(void *addr)
270} 272}
271 273
272/* Caller must hold vmlist_lock */ 274/* Caller must hold vmlist_lock */
273struct vm_struct *__remove_vm_area(void *addr) 275static struct vm_struct *__remove_vm_area(void *addr)
274{ 276{
275 struct vm_struct **p, *tmp; 277 struct vm_struct **p, *tmp;
276 278
@@ -293,7 +295,6 @@ found:
293 295
294/** 296/**
295 * remove_vm_area - find and remove a contingous kernel virtual area 297 * remove_vm_area - find and remove a contingous kernel virtual area
296 *
297 * @addr: base address 298 * @addr: base address
298 * 299 *
299 * Search for the kernel VM area starting at @addr, and remove it. 300 * Search for the kernel VM area starting at @addr, and remove it.
@@ -352,7 +353,6 @@ void __vunmap(void *addr, int deallocate_pages)
352 353
353/** 354/**
354 * vfree - release memory allocated by vmalloc() 355 * vfree - release memory allocated by vmalloc()
355 *
356 * @addr: memory base address 356 * @addr: memory base address
357 * 357 *
358 * Free the virtually contiguous memory area starting at @addr, as 358 * Free the virtually contiguous memory area starting at @addr, as
@@ -370,7 +370,6 @@ EXPORT_SYMBOL(vfree);
370 370
371/** 371/**
372 * vunmap - release virtual mapping obtained by vmap() 372 * vunmap - release virtual mapping obtained by vmap()
373 *
374 * @addr: memory base address 373 * @addr: memory base address
375 * 374 *
376 * Free the virtually contiguous memory area starting at @addr, 375 * Free the virtually contiguous memory area starting at @addr,
@@ -387,7 +386,6 @@ EXPORT_SYMBOL(vunmap);
387 386
388/** 387/**
389 * vmap - map an array of pages into virtually contiguous space 388 * vmap - map an array of pages into virtually contiguous space
390 *
391 * @pages: array of page pointers 389 * @pages: array of page pointers
392 * @count: number of pages to map 390 * @count: number of pages to map
393 * @flags: vm_area->flags 391 * @flags: vm_area->flags
@@ -468,7 +466,6 @@ void *__vmalloc_area(struct vm_struct *area, gfp_t gfp_mask, pgprot_t prot)
468 466
469/** 467/**
470 * __vmalloc_node - allocate virtually contiguous memory 468 * __vmalloc_node - allocate virtually contiguous memory
471 *
472 * @size: allocation size 469 * @size: allocation size
473 * @gfp_mask: flags for the page level allocator 470 * @gfp_mask: flags for the page level allocator
474 * @prot: protection mask for the allocated pages 471 * @prot: protection mask for the allocated pages
@@ -478,8 +475,8 @@ void *__vmalloc_area(struct vm_struct *area, gfp_t gfp_mask, pgprot_t prot)
478 * allocator with @gfp_mask flags. Map them into contiguous 475 * allocator with @gfp_mask flags. Map them into contiguous
479 * kernel virtual space, using a pagetable protection of @prot. 476 * kernel virtual space, using a pagetable protection of @prot.
480 */ 477 */
481void *__vmalloc_node(unsigned long size, gfp_t gfp_mask, pgprot_t prot, 478static void *__vmalloc_node(unsigned long size, gfp_t gfp_mask, pgprot_t prot,
482 int node) 479 int node)
483{ 480{
484 struct vm_struct *area; 481 struct vm_struct *area;
485 482
@@ -493,7 +490,6 @@ void *__vmalloc_node(unsigned long size, gfp_t gfp_mask, pgprot_t prot,
493 490
494 return __vmalloc_area_node(area, gfp_mask, prot, node); 491 return __vmalloc_area_node(area, gfp_mask, prot, node);
495} 492}
496EXPORT_SYMBOL(__vmalloc_node);
497 493
498void *__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot) 494void *__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot)
499{ 495{
@@ -503,9 +499,7 @@ EXPORT_SYMBOL(__vmalloc);
503 499
504/** 500/**
505 * vmalloc - allocate virtually contiguous memory 501 * vmalloc - allocate virtually contiguous memory
506 *
507 * @size: allocation size 502 * @size: allocation size
508 *
509 * Allocate enough pages to cover @size from the page level 503 * Allocate enough pages to cover @size from the page level
510 * allocator and map them into contiguous kernel virtual space. 504 * allocator and map them into contiguous kernel virtual space.
511 * 505 *
@@ -519,11 +513,11 @@ void *vmalloc(unsigned long size)
519EXPORT_SYMBOL(vmalloc); 513EXPORT_SYMBOL(vmalloc);
520 514
521/** 515/**
522 * vmalloc_user - allocate virtually contiguous memory which has 516 * vmalloc_user - allocate zeroed virtually contiguous memory for userspace
523 * been zeroed so it can be mapped to userspace without 517 * @size: allocation size
524 * leaking data.
525 * 518 *
526 * @size: allocation size 519 * The resulting memory area is zeroed so it can be mapped to userspace
520 * without leaking data.
527 */ 521 */
528void *vmalloc_user(unsigned long size) 522void *vmalloc_user(unsigned long size)
529{ 523{
@@ -542,7 +536,6 @@ EXPORT_SYMBOL(vmalloc_user);
542 536
543/** 537/**
544 * vmalloc_node - allocate memory on a specific node 538 * vmalloc_node - allocate memory on a specific node
545 *
546 * @size: allocation size 539 * @size: allocation size
547 * @node: numa node 540 * @node: numa node
548 * 541 *
@@ -564,7 +557,6 @@ EXPORT_SYMBOL(vmalloc_node);
564 557
565/** 558/**
566 * vmalloc_exec - allocate virtually contiguous, executable memory 559 * vmalloc_exec - allocate virtually contiguous, executable memory
567 *
568 * @size: allocation size 560 * @size: allocation size
569 * 561 *
570 * Kernel-internal function to allocate enough pages to cover @size 562 * Kernel-internal function to allocate enough pages to cover @size
@@ -582,7 +574,6 @@ void *vmalloc_exec(unsigned long size)
582 574
583/** 575/**
584 * vmalloc_32 - allocate virtually contiguous memory (32bit addressable) 576 * vmalloc_32 - allocate virtually contiguous memory (32bit addressable)
585 *
586 * @size: allocation size 577 * @size: allocation size
587 * 578 *
588 * Allocate enough 32bit PA addressable pages to cover @size from the 579 * Allocate enough 32bit PA addressable pages to cover @size from the
@@ -595,11 +586,11 @@ void *vmalloc_32(unsigned long size)
595EXPORT_SYMBOL(vmalloc_32); 586EXPORT_SYMBOL(vmalloc_32);
596 587
597/** 588/**
598 * vmalloc_32_user - allocate virtually contiguous memory (32bit 589 * vmalloc_32_user - allocate zeroed virtually contiguous 32bit memory
599 * addressable) which is zeroed so it can be
600 * mapped to userspace without leaking data.
601 *
602 * @size: allocation size 590 * @size: allocation size
591 *
592 * The resulting memory area is 32bit addressable and zeroed so it can be
593 * mapped to userspace without leaking data.
603 */ 594 */
604void *vmalloc_32_user(unsigned long size) 595void *vmalloc_32_user(unsigned long size)
605{ 596{
@@ -693,7 +684,6 @@ finished:
693 684
694/** 685/**
695 * remap_vmalloc_range - map vmalloc pages to userspace 686 * remap_vmalloc_range - map vmalloc pages to userspace
696 *
697 * @vma: vma to cover (map full range of vma) 687 * @vma: vma to cover (map full range of vma)
698 * @addr: vmalloc memory 688 * @addr: vmalloc memory
699 * @pgoff: number of pages into addr before first page to map 689 * @pgoff: number of pages into addr before first page to map
mV) = data * 1.8 * 1000 / (2^12) */ *data = ((*data & 0xfff) * 9 * 25) >> 9; return 0; } static int measure_vbatt(struct pm860x_battery_info *info, int state, int *data) { unsigned char buf[5]; int ret; switch (state) { case OCV_MODE_ACTIVE: ret = measure_12bit_voltage(info, PM8607_VBAT_MEAS1, data); if (ret) return ret; /* V_BATT_MEAS(mV) = value * 3 * 1.8 * 1000 / (2^12) */ *data *= 3; break; case OCV_MODE_SLEEP: /* * voltage value of VBATT in sleep mode is saved in different * registers. * bit[11:10] -- bit[7:6] of LDO9(0x18) * bit[9:8] -- bit[7:6] of LDO8(0x17) * bit[7:6] -- bit[7:6] of LDO7(0x16) * bit[5:4] -- bit[7:6] of LDO6(0x15) * bit[3:0] -- bit[7:4] of LDO5(0x14) */ ret = pm860x_bulk_read(info->i2c, PM8607_LDO5, 5, buf); if (ret < 0) return ret; ret = ((buf[4] >> 6) << 10) | ((buf[3] >> 6) << 8) | ((buf[2] >> 6) << 6) | ((buf[1] >> 6) << 4) | (buf[0] >> 4); /* V_BATT_MEAS(mV) = data * 3 * 1.8 * 1000 / (2^12) */ *data = ((*data & 0xff) * 27 * 25) >> 9; break; default: return -EINVAL; } return 0; } /* * Return value is signed data. * Negative value means discharging, and positive value means charging. */ static int measure_current(struct pm860x_battery_info *info, int *data) { unsigned char buf[2]; short s; int ret; ret = pm860x_bulk_read(info->i2c, PM8607_IBAT_MEAS1, 2, buf); if (ret < 0) return ret; s = ((buf[0] & 0xff) << 8) | (buf[1] & 0xff); /* current(mA) = value * 0.125 */ *data = s >> 3; return 0; } static int set_charger_current(struct pm860x_battery_info *info, int data, int *old) { int ret; if (data < 50 || data > 1600 || !old) return -EINVAL; data = ((data - 50) / 50) & 0x1f; *old = pm860x_reg_read(info->i2c, PM8607_CHG_CTRL2); *old = (*old & 0x1f) * 50 + 50; ret = pm860x_set_bits(info->i2c, PM8607_CHG_CTRL2, 0x1f, data); if (ret < 0) return ret; return 0; } static int read_ccnt(struct pm860x_battery_info *info, int offset, int *ccnt) { unsigned char buf[2]; int ret; ret = pm860x_set_bits(info->i2c, PM8607_CCNT, 7, offset & 7); if (ret < 0) goto out; ret = pm860x_bulk_read(info->i2c, PM8607_CCNT_MEAS1, 2, buf); if (ret < 0) goto out; *ccnt = ((buf[0] & 0xff) << 8) | (buf[1] & 0xff); return 0; out: return ret; } static int calc_ccnt(struct pm860x_battery_info *info, struct ccnt *ccnt) { unsigned int sum; int ret; int data; ret = read_ccnt(info, CCNT_POS1, &data); if (ret) goto out; sum = data & 0xffff; ret = read_ccnt(info, CCNT_POS2, &data); if (ret) goto out; sum |= (data & 0xffff) << 16; ccnt->pos += sum; ret = read_ccnt(info, CCNT_NEG1, &data); if (ret) goto out; sum = data & 0xffff; ret = read_ccnt(info, CCNT_NEG2, &data); if (ret) goto out; sum |= (data & 0xffff) << 16; sum = ~sum + 1; /* since it's negative */ ccnt->neg += sum; ret = read_ccnt(info, CCNT_SPOS, &data); if (ret) goto out; ccnt->spos += data; ret = read_ccnt(info, CCNT_SNEG, &data); if (ret) goto out; /* * charge(mAh) = count * 1.6984 * 1e(-8) * = count * 16984 * 1.024 * 1.024 * 1.024 / (2 ^ 40) * = count * 18236 / (2 ^ 40) */ ccnt->total_chg = (int) ((ccnt->pos * 18236) >> 40); ccnt->total_dischg = (int) ((ccnt->neg * 18236) >> 40); return 0; out: return ret; } static int clear_ccnt(struct pm860x_battery_info *info, struct ccnt *ccnt) { int data; memset(ccnt, 0, sizeof(*ccnt)); /* read to clear ccnt */ read_ccnt(info, CCNT_POS1, &data); read_ccnt(info, CCNT_POS2, &data); read_ccnt(info, CCNT_NEG1, &data); read_ccnt(info, CCNT_NEG2, &data); read_ccnt(info, CCNT_SPOS, &data); read_ccnt(info, CCNT_SNEG, &data); return 0; } /* Calculate Open Circuit Voltage */ static int calc_ocv(struct pm860x_battery_info *info, int *ocv) { int ret; int i; int data; int vbatt_avg; int vbatt_sum; int ibatt_avg; int ibatt_sum; if (!ocv) return -EINVAL; for (i = 0, ibatt_sum = 0, vbatt_sum = 0; i < 10; i++) { ret = measure_vbatt(info, OCV_MODE_ACTIVE, &data); if (ret) goto out; vbatt_sum += data; ret = measure_current(info, &data); if (ret) goto out; ibatt_sum += data; } vbatt_avg = vbatt_sum / 10; ibatt_avg = ibatt_sum / 10; mutex_lock(&info->lock); if (info->present) *ocv = vbatt_avg - ibatt_avg * info->resistor / 1000; else *ocv = vbatt_avg; mutex_unlock(&info->lock); dev_dbg(info->dev, "VBAT average:%d, OCV:%d\n", vbatt_avg, *ocv); return 0; out: return ret; } /* Calculate State of Charge (percent points) */ static int calc_soc(struct pm860x_battery_info *info, int state, int *soc) { int i; int ocv; int count; int ret = -EINVAL; if (!soc) return -EINVAL; switch (state) { case OCV_MODE_ACTIVE: ret = calc_ocv(info, &ocv); break; case OCV_MODE_SLEEP: ret = measure_vbatt(info, OCV_MODE_SLEEP, &ocv); break; } if (ret) return ret; count = ARRAY_SIZE(array_soc); if (ocv < array_soc[count - 1][0]) { *soc = 0; return 0; } for (i = 0; i < count; i++) { if (ocv >= array_soc[i][0]) { *soc = array_soc[i][1]; break; } } return 0; } static irqreturn_t pm860x_coulomb_handler(int irq, void *data) { struct pm860x_battery_info *info = data; calc_ccnt(info, &ccnt_data); return IRQ_HANDLED; } static irqreturn_t pm860x_batt_handler(int irq, void *data) { struct pm860x_battery_info *info = data; int ret; mutex_lock(&info->lock); ret = pm860x_reg_read(info->i2c, PM8607_STATUS_2); if (ret & STATUS2_BAT) { info->present = 1; info->temp_type = PM860X_TEMP_TBAT; } else { info->present = 0; info->temp_type = PM860X_TEMP_TINT; } mutex_unlock(&info->lock); /* clear ccnt since battery is attached or dettached */ clear_ccnt(info, &ccnt_data); return IRQ_HANDLED; } static void pm860x_init_battery(struct pm860x_battery_info *info) { unsigned char buf[2]; int ret; int data; int bat_remove; int soc; /* measure enable on GPADC1 */ data = MEAS1_GP1; if (info->temp_type == PM860X_TEMP_TINT) data |= MEAS1_TINT; ret = pm860x_set_bits(info->i2c, PM8607_MEAS_EN1, data, data); if (ret) goto out; /* measure enable on IBAT, BAT_DET, CC. IBAT is depend on CC. */ data = MEAS3_IBAT | MEAS3_BAT_DET | MEAS3_CC; ret = pm860x_set_bits(info->i2c, PM8607_MEAS_EN3, data, data); if (ret) goto out; /* measure disable CC in sleep time */ ret = pm860x_reg_write(info->i2c, PM8607_MEAS_OFF_TIME1, 0x82); if (ret) goto out; ret = pm860x_reg_write(info->i2c, PM8607_MEAS_OFF_TIME2, 0x6c); if (ret) goto out; /* enable GPADC */ ret = pm860x_set_bits(info->i2c, PM8607_GPADC_MISC1, GPMISC1_GPADC_EN, GPMISC1_GPADC_EN); if (ret < 0) goto out; /* detect battery via GPADC1 */ ret = pm860x_set_bits(info->i2c, PM8607_CHG_CTRL6, CC6_BAT_DET_GPADC1, CC6_BAT_DET_GPADC1); if (ret < 0) goto out; ret = pm860x_set_bits(info->i2c, PM8607_CCNT, 7 << 3, CCNT_AVG_SEL); if (ret < 0) goto out; /* set GPADC1 bias */ ret = pm860x_set_bits(info->i2c, PM8607_GP_BIAS2, 0xF << 4, GPBIAS2_GPADC1_SET); if (ret < 0) goto out; /* check whether battery present) */ mutex_lock(&info->lock); ret = pm860x_reg_read(info->i2c, PM8607_STATUS_2); if (ret < 0) { mutex_unlock(&info->lock); goto out; } if (ret & STATUS2_BAT) { info->present = 1; info->temp_type = PM860X_TEMP_TBAT; } else { info->present = 0; info->temp_type = PM860X_TEMP_TINT; } mutex_unlock(&info->lock); calc_soc(info, OCV_MODE_ACTIVE, &soc); data = pm860x_reg_read(info->i2c, PM8607_POWER_UP_LOG); bat_remove = data & BAT_WU_LOG; dev_dbg(info->dev, "battery wake up? %s\n", bat_remove != 0 ? "yes" : "no"); /* restore SOC from RTC domain register */ if (bat_remove == 0) { buf[0] = pm860x_reg_read(info->i2c, PM8607_RTC_MISC2); buf[1] = pm860x_reg_read(info->i2c, PM8607_RTC1); data = ((buf[1] & 0x3) << 5) | ((buf[0] >> 3) & 0x1F); if (data > soc + 15) info->start_soc = soc; else if (data < soc - 15) info->start_soc = soc; else info->start_soc = data; dev_dbg(info->dev, "soc_rtc %d, soc_ocv :%d\n", data, soc); } else { pm860x_set_bits(info->i2c, PM8607_POWER_UP_LOG, BAT_WU_LOG, BAT_WU_LOG); info->start_soc = soc; } info->last_capacity = info->start_soc; dev_dbg(info->dev, "init soc : %d\n", info->last_capacity); out: return; } static void set_temp_threshold(struct pm860x_battery_info *info, int min, int max) { int data; /* (tmp << 8) / 1800 */ if (min <= 0) data = 0; else data = (min << 8) / 1800; pm860x_reg_write(info->i2c, PM8607_GPADC1_HIGHTH, data); dev_dbg(info->dev, "TEMP_HIGHTH : min: %d, 0x%x\n", min, data); if (max <= 0) data = 0xff; else data = (max << 8) / 1800; pm860x_reg_write(info->i2c, PM8607_GPADC1_LOWTH, data); dev_dbg(info->dev, "TEMP_LOWTH:max : %d, 0x%x\n", max, data); } static int measure_temp(struct pm860x_battery_info *info, int *data) { int ret; int temp; int min; int max; if (info->temp_type == PM860X_TEMP_TINT) { ret = measure_12bit_voltage(info, PM8607_TINT_MEAS1, data); if (ret) return ret; *data = (*data - 884) * 1000 / 3611; } else { ret = measure_12bit_voltage(info, PM8607_GPADC1_MEAS1, data); if (ret) return ret; /* meausered Vtbat(mV) / Ibias_current(11uA)*/ *data = (*data * 1000) / GPBIAS2_GPADC1_UA; if (*data > TBAT_NEG_25D) { temp = -30; /* over cold , suppose -30 roughly */ max = TBAT_NEG_10D * GPBIAS2_GPADC1_UA / 1000; set_temp_threshold(info, 0, max); } else if (*data > TBAT_NEG_10D) { temp = -15; /* -15 degree, code */ max = TBAT_NEG_10D * GPBIAS2_GPADC1_UA / 1000; set_temp_threshold(info, 0, max); } else if (*data > TBAT_0D) { temp = -5; /* -5 degree */ min = TBAT_NEG_10D * GPBIAS2_GPADC1_UA / 1000; max = TBAT_40D * GPBIAS2_GPADC1_UA / 1000; set_temp_threshold(info, min, max); } else if (*data > TBAT_10D) { temp = 5; /* in range of (0, 10) */ min = TBAT_NEG_10D * GPBIAS2_GPADC1_UA / 1000; max = TBAT_40D * GPBIAS2_GPADC1_UA / 1000; set_temp_threshold(info, min, max); } else if (*data > TBAT_20D) { temp = 15; /* in range of (10, 20) */ min = TBAT_NEG_10D * GPBIAS2_GPADC1_UA / 1000; max = TBAT_40D * GPBIAS2_GPADC1_UA / 1000; set_temp_threshold(info, min, max); } else if (*data > TBAT_30D) { temp = 25; /* in range of (20, 30) */ min = TBAT_NEG_10D * GPBIAS2_GPADC1_UA / 1000; max = TBAT_40D * GPBIAS2_GPADC1_UA / 1000; set_temp_threshold(info, min, max); } else if (*data > TBAT_40D) { temp = 35; /* in range of (30, 40) */ min = TBAT_NEG_10D * GPBIAS2_GPADC1_UA / 1000; max = TBAT_40D * GPBIAS2_GPADC1_UA / 1000; set_temp_threshold(info, min, max); } else { min = TBAT_40D * GPBIAS2_GPADC1_UA / 1000; set_temp_threshold(info, min, 0); temp = 45; /* over heat ,suppose 45 roughly */ } dev_dbg(info->dev, "temp_C:%d C,temp_mv:%d mv\n", temp, *data); *data = temp; } return 0; } static int calc_resistor(struct pm860x_battery_info *info) { int vbatt_sum1; int vbatt_sum2; int chg_current; int ibatt_sum1; int ibatt_sum2; int data; int ret; int i; ret = measure_current(info, &data); /* make sure that charging is launched by data > 0 */ if (ret || data < 0) goto out; ret = measure_vbatt(info, OCV_MODE_ACTIVE, &data); if (ret) goto out; /* calculate resistor only in CC charge mode */ if (data < VBATT_RESISTOR_MIN || data > VBATT_RESISTOR_MAX) goto out; /* current is saved */ if (set_charger_current(info, 500, &chg_current)) goto out; /* * set charge current as 500mA, wait about 500ms till charging * process is launched and stable with the newer charging current. */ msleep(500); for (i = 0, vbatt_sum1 = 0, ibatt_sum1 = 0; i < 10; i++) { ret = measure_vbatt(info, OCV_MODE_ACTIVE, &data); if (ret) goto out_meas; vbatt_sum1 += data; ret = measure_current(info, &data); if (ret) goto out_meas; if (data < 0) ibatt_sum1 = ibatt_sum1 - data; /* discharging */ else ibatt_sum1 = ibatt_sum1 + data; /* charging */ } if (set_charger_current(info, 100, &ret)) goto out_meas; /* * set charge current as 100mA, wait about 500ms till charging * process is launched and stable with the newer charging current. */ msleep(500); for (i = 0, vbatt_sum2 = 0, ibatt_sum2 = 0; i < 10; i++) { ret = measure_vbatt(info, OCV_MODE_ACTIVE, &data); if (ret) goto out_meas; vbatt_sum2 += data; ret = measure_current(info, &data); if (ret) goto out_meas; if (data < 0) ibatt_sum2 = ibatt_sum2 - data; /* discharging */ else ibatt_sum2 = ibatt_sum2 + data; /* charging */ } /* restore current setting */ if (set_charger_current(info, chg_current, &ret)) goto out_meas; if ((vbatt_sum1 > vbatt_sum2) && (ibatt_sum1 > ibatt_sum2) && (ibatt_sum2 > 0)) { /* calculate resistor in discharging case */ data = 1000 * (vbatt_sum1 - vbatt_sum2) / (ibatt_sum1 - ibatt_sum2); if ((data - info->resistor > 0) && (data - info->resistor < info->resistor)) info->resistor = data; if ((info->resistor - data > 0) && (info->resistor - data < data)) info->resistor = data; } return 0; out_meas: set_charger_current(info, chg_current, &ret); out: return -EINVAL; } static int calc_capacity(struct pm860x_battery_info *info, int *cap) { int ret; int data; int ibat; int cap_ocv = 0; int cap_cc = 0; ret = calc_ccnt(info, &ccnt_data); if (ret) goto out; soc: data = info->max_capacity * info->start_soc / 100; if (ccnt_data.total_dischg - ccnt_data.total_chg <= data) { cap_cc = data + ccnt_data.total_chg - ccnt_data.total_dischg; } else { clear_ccnt(info, &ccnt_data); calc_soc(info, OCV_MODE_ACTIVE, &info->start_soc); dev_dbg(info->dev, "restart soc = %d !\n", info->start_soc); goto soc; } cap_cc = cap_cc * 100 / info->max_capacity;