source: trunk/target/linux/omap24xx/patches-3.1/900-n810-battery-management.patch @ 28676

Last change on this file since 28676 was 28676, checked in by mb, 5 years ago

omap24xx: Refresh 3.1 patches

File size: 50.9 KB
  • drivers/cbus/Kconfig

    old new config CBUS_RETU_HEADSET 
    8383 
    8484endif # CBUS_RETU 
    8585 
     86config N810BM 
     87        depends on CBUS_RETU && CBUS_TAHVO 
     88        tristate "Nokia n810 battery management" 
     89        ---help--- 
     90          Nokia n810 device battery management. 
     91 
     92          If unsure, say N. 
     93 
    8694endmenu 
  • drivers/cbus/Makefile

    old new obj-$(CONFIG_CBUS_RETU_POWERBUTTON) += r 
    1111obj-$(CONFIG_CBUS_RETU_RTC)     += retu-rtc.o 
    1212obj-$(CONFIG_CBUS_RETU_WDT)     += retu-wdt.o 
    1313obj-$(CONFIG_CBUS_RETU_HEADSET) += retu-headset.o 
     14n810bm-y                        += n810bm_main.o 
     15n810bm-y                        += lipocharge.o 
     16obj-$(CONFIG_N810BM)            += n810bm.o 
  • new file linux-3.1/drivers/cbus/n810bm_main.c

    - +  
     1/* 
     2 *   Nokia n810 battery management 
     3 * 
     4 *   WARNING: This driver is based on unconfirmed documentation. 
     5 *            It is possibly dangerous to use this software. 
     6 *            Use this software at your own risk! 
     7 * 
     8 *   Copyright (c) 2010-2011 Michael Buesch <mb@bu3sch.de> 
     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 
     12 *   as published by the Free Software Foundation; either version 2 
     13 *   of the License, or (at your option) any later version. 
     14 * 
     15 *   This program is distributed in the hope that it will be useful, 
     16 *   but WITHOUT ANY WARRANTY; without even the implied warranty of 
     17 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
     18 *   GNU General Public License for more details. 
     19 */ 
     20 
     21#define DEBUG 
     22 
     23#include <linux/module.h> 
     24#include <linux/device.h> 
     25#include <linux/platform_device.h> 
     26#include <linux/slab.h> 
     27#include <linux/mutex.h> 
     28#include <linux/timer.h> 
     29#include <linux/firmware.h> 
     30#include <linux/bitops.h> 
     31#include <linux/workqueue.h> 
     32#include <linux/delay.h> 
     33 
     34#include "cbus.h" 
     35#include "retu.h" 
     36#include "tahvo.h" 
     37#include "lipocharge.h" 
     38 
     39 
     40#define N810BM_PMM_BLOCK_FILENAME       "n810-cal-bme-pmm.fw" 
     41#define N810BM_PMM_BLOCK_SIZE           0x600 
     42#define N810BM_PMM_GROUP_SIZE           0x200 
     43#define N810BM_PMM_ELEM_SIZE            0x10 
     44 
     45#define N810BM_CHECK_INTERVAL           (HZ * 2) 
     46#define N810BM_MIN_VOLTAGE_THRES        3200 /* Absolute minimum voltage threshold */ 
     47 
     48 
     49/* RETU_ADC_BSI 
     50 * The battery size indicator ADC measures the resistance between 
     51 * the battery BSI pin and ground. This is used to detect the battery 
     52 * capacity, as the BSI resistor is related to capacity. 
     53 * 
     54 * Manually measured lookup table. 
     55 * Hard to measure, thus not very accurate. 
     56 * 
     57 * Resistance  |  ADC value 
     58 * ======================== 
     59 * 120k        |  0x3AC 
     60 * 110k        |  0x37C 
     61 * 100k        |  0x351 
     62 *  90k        |  0x329 
     63 */ 
     64 
     65/* RETU_ADC_BATTVOLT 
     66 * Manually measured lookup table. 
     67 * Hard to measure, thus not very accurate. 
     68 * 
     69 * Voltage  |  ADC value 
     70 * ===================== 
     71 * 2.80V    |  0x037 
     72 * 2.90V    |  0x05E 
     73 * 3.00V    |  0x090 
     74 * 3.10V    |  0x0A4 
     75 * 3.20V    |  0x0CC 
     76 * 3.30V    |  0x0EF 
     77 * 3.40V    |  0x115 
     78 * 3.50V    |  0x136 
     79 * 3.60V    |  0x15C 
     80 * 3.70V    |  0x187 
     81 * 3.80V    |  0x1A5 
     82 * 3.90V    |  0x1C9 
     83 * 4.00V    |  0x1ED 
     84 * 4.10V    |  0x212 
     85 * 4.20V    |  0x236 
     86 */ 
     87 
     88 
     89/* PMM block ADC IDs */ 
     90enum n810bm_pmm_adc_id { 
     91        N810BM_PMM_ADC_BATVOLT          = 0x01, /* Battery voltage */ 
     92        N810BM_PMM_ADC_CHGVOLT          = 0x02, /* Charger voltage */ 
     93        N810BM_PMM_ADC_GND2             = 0x03, /* Ground 0V */ 
     94        N810BM_PMM_ADC_BSI              = 0x04, /* Battery size indicator */ 
     95        N810BM_PMM_ADC_BATTEMP          = 0x05, /* Battery temperature */ 
     96        N810BM_PMM_ADC_HEADSET          = 0x06, /* Headset detection */ 
     97        N810BM_PMM_ADC_HOOKDET          = 0x07, /* Hook detection */ 
     98        N810BM_PMM_ADC_LIGHTSENS        = 0x08, /* Light sensor */ 
     99        N810BM_PMM_ADC_BATCURR          = 0x0E, /* Battery current */ 
     100        N810BM_PMM_ADC_BKUPVOLT         = 0x13, /* Backup battery voltage */ 
     101        N810BM_PMM_ADC_LIGHTTEMP        = 0x14, /* Light sensor temperature */ 
     102        N810BM_PMM_ADC_RFGP             = 0x15, /* RF GP */ 
     103        N810BM_PMM_ADC_WBTX             = 0x16, /* Wideband TX detection */ 
     104        N810BM_PMM_ADC_RETUTEMP         = 0x17, /* RETU chip temperature */ 
     105        N810BM_PMM_ADC_0xFE             = 0xFE, 
     106}; 
     107 
     108struct n810bm_adc_calib { 
     109        enum n810bm_pmm_adc_id id; 
     110        u8 flags; 
     111        u8 adc_groupnr; 
     112        u32 field1; 
     113        u32 field2; 
     114        u16 field3; 
     115        u16 field4; 
     116}; 
     117 
     118struct n810bm_calib { 
     119        struct n810bm_adc_calib adc[25]; 
     120}; 
     121 
     122enum n810bm_capacity { 
     123        N810BM_CAP_UNKNOWN      = -1, 
     124        N810BM_CAP_NONE         = 0, 
     125        N810BM_CAP_1500MAH      = 1500, /* 1500 mAh battery */ 
     126}; 
     127 
     128enum n810bm_notify_flags { 
     129        N810BM_NOTIFY_charger_present, 
     130        N810BM_NOTIFY_charger_state, 
     131        N810BM_NOTIFY_charger_pwm, 
     132}; 
     133 
     134struct n810bm { 
     135        bool battery_present;                   /* A battery is inserted */ 
     136        bool charger_present;                   /* The charger is connected */ 
     137        enum n810bm_capacity capacity;          /* The capacity of the inserted battery (if any) */ 
     138 
     139        bool charger_enabled;                   /* Want to charge? */ 
     140        struct lipocharge charger;              /* Charger subsystem */ 
     141        unsigned int active_current_pwm;        /* Active value of TAHVO_REG_CHGCURR */ 
     142        int current_measure_enabled;            /* Current measure enable refcount */ 
     143 
     144        struct platform_device *pdev; 
     145        struct n810bm_calib calib;              /* Calibration data */ 
     146 
     147        bool verbose_charge_log;                /* Verbose charge logging */ 
     148 
     149        unsigned long notify_flags; 
     150        struct work_struct notify_work; 
     151        struct work_struct currmeas_irq_work; 
     152        struct delayed_work periodic_check_work; 
     153 
     154        bool initialized;                       /* The hardware was initialized */ 
     155        struct mutex mutex; 
     156}; 
     157 
     158static void n810bm_notify_charger_present(struct n810bm *bm); 
     159static void n810bm_notify_charger_state(struct n810bm *bm); 
     160static void n810bm_notify_charger_pwm(struct n810bm *bm); 
     161 
     162 
     163static struct platform_device *n810bm_retu_device; 
     164static struct platform_device *n810bm_tahvo_device; 
     165 
     166 
     167static inline struct n810bm * device_to_n810bm(struct device *dev) 
     168{ 
     169        struct platform_device *pdev = to_platform_device(dev); 
     170        struct n810bm *bm = platform_get_drvdata(pdev); 
     171 
     172        return bm; 
     173} 
     174 
     175static inline bool n810bm_known_battery_present(struct n810bm *bm) 
     176{ 
     177        return bm->battery_present && 
     178               bm->capacity != N810BM_CAP_UNKNOWN && 
     179               bm->capacity != N810BM_CAP_NONE; 
     180} 
     181 
     182static NORET_TYPE void n810bm_emergency(struct n810bm *bm, const char *message) ATTRIB_NORET; 
     183static void n810bm_emergency(struct n810bm *bm, const char *message) 
     184{ 
     185        printk(KERN_EMERG "n810 battery management fatal fault: %s\n", message); 
     186        cbus_emergency(); 
     187} 
     188 
     189static u16 tahvo_read(struct n810bm *bm, unsigned int reg) 
     190{ 
     191        return tahvo_read_reg(reg); 
     192} 
     193 
     194static void tahvo_maskset(struct n810bm *bm, unsigned int reg, u16 mask, u16 set) 
     195{ 
     196        tahvo_set_clear_reg_bits(reg, set, mask); 
     197} 
     198 
     199static inline void tahvo_write(struct n810bm *bm, unsigned int reg, u16 value) 
     200{ 
     201        unsigned long flags; 
     202 
     203        spin_lock_irqsave(&tahvo_lock, flags); 
     204        tahvo_write_reg(reg, value); 
     205        spin_unlock_irqrestore(&tahvo_lock, flags); 
     206} 
     207 
     208static inline void tahvo_set(struct n810bm *bm, unsigned int reg, u16 mask) 
     209{ 
     210        tahvo_set_clear_reg_bits(reg, mask, mask); 
     211} 
     212 
     213static inline void tahvo_clear(struct n810bm *bm, unsigned int reg, u16 mask) 
     214{ 
     215        tahvo_set_clear_reg_bits(reg, 0, mask); 
     216} 
     217 
     218static u16 retu_read(struct n810bm *bm, unsigned int reg) 
     219{ 
     220        return retu_read_reg(&n810bm_retu_device->dev, reg); 
     221} 
     222 
     223static void retu_maskset(struct n810bm *bm, unsigned int reg, u16 mask, u16 set) 
     224{ 
     225        retu_set_clear_reg_bits(&n810bm_retu_device->dev, reg, set, mask); 
     226} 
     227 
     228static inline void retu_write(struct n810bm *bm, unsigned int reg, u16 value) 
     229{ 
     230        retu_write_reg(&n810bm_retu_device->dev, reg, value); 
     231} 
     232 
     233static int retu_adc_average(struct n810bm *bm, unsigned int chan, 
     234                            unsigned int nr_passes) 
     235{ 
     236        unsigned int i, value = 0; 
     237        int ret; 
     238 
     239        if (WARN_ON(!nr_passes)) 
     240                return 0; 
     241        for (i = 0; i < nr_passes; i++) { 
     242                ret = retu_read_adc(&n810bm_retu_device->dev, chan); 
     243                if (ret < 0) 
     244                        return ret; 
     245                value += ret; 
     246        } 
     247        value /= nr_passes; 
     248 
     249        return value; 
     250} 
     251 
     252static struct n810bm_adc_calib * n810bm_get_adc_calib(struct n810bm *bm, 
     253                                                enum n810bm_pmm_adc_id id) 
     254{ 
     255        unsigned int index = 0; 
     256        struct n810bm_adc_calib *cal; 
     257 
     258        if (id != N810BM_PMM_ADC_0xFE) 
     259                index = (unsigned int)id + 1; 
     260        if (index >= ARRAY_SIZE(bm->calib.adc)) 
     261                return NULL; 
     262 
     263        cal = &bm->calib.adc[index]; 
     264        WARN_ON(cal->id && cal->id != id); 
     265 
     266        return cal; 
     267} 
     268 
     269static int pmm_record_get(struct n810bm *bm, 
     270                          const struct firmware *pmm_block, 
     271                          void *buffer, size_t length, 
     272                          unsigned int group, unsigned int element, unsigned int offset) 
     273{ 
     274        const u8 *pmm_area = pmm_block->data; 
     275        u8 active_group_mask; 
     276 
     277        if (pmm_block->size != N810BM_PMM_BLOCK_SIZE) 
     278                return -EINVAL; 
     279        if (group >= N810BM_PMM_BLOCK_SIZE / N810BM_PMM_GROUP_SIZE) 
     280                return -EINVAL; 
     281        if (element >= N810BM_PMM_GROUP_SIZE / N810BM_PMM_ELEM_SIZE) 
     282                return -EINVAL; 
     283        if (offset >= N810BM_PMM_ELEM_SIZE || length > N810BM_PMM_ELEM_SIZE || 
     284            length + offset > N810BM_PMM_ELEM_SIZE) 
     285                return -EINVAL; 
     286 
     287        active_group_mask = pmm_area[16]; 
     288        if (!(active_group_mask & (1 << group))) { 
     289                dev_dbg(&bm->pdev->dev, "pwm_record_get: Requested group %u, " 
     290                        "but group is not active", group); 
     291                return -ENOENT; 
     292        } 
     293 
     294        memcpy(buffer, 
     295               pmm_area + group * N810BM_PMM_GROUP_SIZE 
     296                        + element * N810BM_PMM_ELEM_SIZE 
     297                        + offset, 
     298               length); 
     299 
     300        return 0; 
     301} 
     302 
     303/* PMM block group 1 element */ 
     304struct group1_element { 
     305        u8 id; 
     306        u8 flags; 
     307        u8 adc_groupnr; 
     308        u8 _padding; 
     309        __le32 field1; 
     310        __le32 field2; 
     311} __packed; 
     312 
     313static int extract_group1_elem(struct n810bm *bm, 
     314                               const struct firmware *pmm_block, 
     315                               const enum n810bm_pmm_adc_id *pmm_adc_ids, size_t nr_pmm_adc_ids, 
     316                               u32 field1_mask, u32 field2_mask) 
     317{ 
     318        struct group1_element elem; 
     319        int err; 
     320        unsigned int i, element_nr; 
     321        struct n810bm_adc_calib *adc_calib; 
     322 
     323        for (i = 0; i < nr_pmm_adc_ids; i++) { 
     324                element_nr = (unsigned int)(pmm_adc_ids[i]) + 3; 
     325 
     326                err = pmm_record_get(bm, pmm_block, &elem, sizeof(elem), 
     327                                     1, element_nr, 0); 
     328                if (err) 
     329                        continue; 
     330                adc_calib = n810bm_get_adc_calib(bm, elem.id); 
     331                if (!adc_calib) { 
     332                        dev_err(&bm->pdev->dev, "extract_group1_elem: " 
     333                                "Could not get calib element for 0x%02X", 
     334                                elem.id); 
     335                        return -EINVAL; 
     336                } 
     337 
     338                if (adc_calib->flags == elem.flags) { 
     339                        adc_calib->field1 = le32_to_cpu(elem.field1) & field1_mask; 
     340                        adc_calib->field2 = le32_to_cpu(elem.field2) & field2_mask; 
     341                } else { 
     342                        dev_dbg(&bm->pdev->dev, "extract_group1_elem: " 
     343                                "Not extracting fields due to flags mismatch: " 
     344                                "0x%02X vs 0x%02X", 
     345                                adc_calib->flags, elem.flags); 
     346                } 
     347        } 
     348 
     349        return 0; 
     350} 
     351 
     352static int n810bm_parse_pmm_group1(struct n810bm *bm, 
     353                                   const struct firmware *pmm_block) 
     354{ 
     355        struct n810bm_adc_calib *adc_calib; 
     356        struct group1_element elem; 
     357        int err; 
     358 
     359        static const enum n810bm_pmm_adc_id pmm_adc_ids_1[] = { 
     360                N810BM_PMM_ADC_BATVOLT, 
     361                N810BM_PMM_ADC_CHGVOLT, 
     362                N810BM_PMM_ADC_BKUPVOLT, 
     363                N810BM_PMM_ADC_BATCURR, 
     364        }; 
     365        static const enum n810bm_pmm_adc_id pmm_adc_ids_2[] = { 
     366                N810BM_PMM_ADC_BSI, 
     367        }; 
     368        static const enum n810bm_pmm_adc_id pmm_adc_ids_3[] = { 
     369                N810BM_PMM_ADC_BATTEMP, 
     370        }; 
     371 
     372        /* Parse element 2 */ 
     373        err = pmm_record_get(bm, pmm_block, &elem, sizeof(elem), 
     374                             1, 2, 0); 
     375        if (err) { 
     376                dev_err(&bm->pdev->dev, 
     377                        "PMM: Failed to get group 1 / element 2"); 
     378                return err; 
     379        } 
     380        if (elem.id == N810BM_PMM_ADC_0xFE && elem.flags == 0x05) { 
     381                adc_calib = n810bm_get_adc_calib(bm, elem.id); 
     382                if (!adc_calib) { 
     383                        dev_err(&bm->pdev->dev, 
     384                                "calib extract: Failed to get 0xFE calib"); 
     385                        return -EINVAL; 
     386                } 
     387                adc_calib->id = elem.id; 
     388                adc_calib->flags = elem.flags; 
     389                adc_calib->field1 = le32_to_cpu(elem.field1); 
     390                adc_calib->field2 = le32_to_cpu(elem.field2); 
     391        } 
     392 
     393        err = extract_group1_elem(bm, pmm_block, 
     394                                  pmm_adc_ids_1, ARRAY_SIZE(pmm_adc_ids_1), 
     395                                  0xFFFFFFFF, 0xFFFFFFFF); 
     396        if (err) 
     397                return err; 
     398        err = extract_group1_elem(bm, pmm_block, 
     399                                  pmm_adc_ids_2, ARRAY_SIZE(pmm_adc_ids_2), 
     400                                  0xFFFFFFFF, 0); 
     401        if (err) 
     402                return err; 
     403        err = extract_group1_elem(bm, pmm_block, 
     404                                  pmm_adc_ids_3, ARRAY_SIZE(pmm_adc_ids_3), 
     405                                  0xFFFFFFFF, 0x0000FFFF); 
     406        if (err) 
     407                return err; 
     408 
     409        return 0; 
     410} 
     411 
     412static int n810bm_parse_pmm_group2(struct n810bm *bm, 
     413                                   const struct firmware *pmm_block) 
     414{ 
     415        dev_err(&bm->pdev->dev, "TODO: CAL BME PMM group 2 parser not implemented, yet"); 
     416        return -EOPNOTSUPP; 
     417} 
     418 
     419static void n810bm_adc_calib_set_defaults(struct n810bm *bm) 
     420{ 
     421        struct n810bm_adc_calib *adc_calib; 
     422        unsigned int i; 
     423 
     424        static const struct n810bm_adc_calib defaults[] = { 
     425                /* ADC group-nr 0 */ 
     426                { 
     427                        .id             = N810BM_PMM_ADC_HEADSET, 
     428                        .flags          = 0x00, 
     429                        .adc_groupnr    = 0, 
     430                }, { 
     431                        .id             = N810BM_PMM_ADC_HOOKDET, 
     432                        .flags          = 0x00, 
     433                        .adc_groupnr    = 0, 
     434                }, { 
     435                        .id             = N810BM_PMM_ADC_RFGP, 
     436                        .flags          = 0x00, 
     437                        .adc_groupnr    = 0, 
     438                }, { 
     439                        .id             = N810BM_PMM_ADC_LIGHTSENS, 
     440                        .flags          = 0x00, 
     441                        .adc_groupnr    = 0, 
     442                }, { 
     443                        .id             = N810BM_PMM_ADC_WBTX, 
     444                        .flags          = 0x00, 
     445                        .adc_groupnr    = 0, 
     446                }, { 
     447                        .id             = N810BM_PMM_ADC_RETUTEMP, 
     448                        .flags          = 0x00, 
     449                        .adc_groupnr    = 0, 
     450                }, { 
     451                        .id             = N810BM_PMM_ADC_GND2, 
     452                        .flags          = 0x00, 
     453                        .adc_groupnr    = 0, 
     454                }, 
     455                /* ADC group-nr 1 */ 
     456                { 
     457                        .id             = N810BM_PMM_ADC_0xFE, 
     458                        .flags          = 0x05, 
     459                        .adc_groupnr    = 1, 
     460                        .field1         = (u32)-2, 
     461                        .field2         = 13189, 
     462                }, { 
     463                        .id             = N810BM_PMM_ADC_BATVOLT, 
     464                        .flags          = 0x01, 
     465                        .adc_groupnr    = 1, 
     466                        .field1         = 2527, 
     467                        .field2         = 21373, 
     468                }, { 
     469                        .id             = N810BM_PMM_ADC_CHGVOLT, 
     470                        .flags          = 0x01, 
     471                        .adc_groupnr    = 1, 
     472                        .field1         = 0, 
     473                        .field2         = 129848, 
     474                }, { 
     475                        .id             = N810BM_PMM_ADC_BKUPVOLT, 
     476                        .flags          = 0x01, 
     477                        .adc_groupnr    = 1, 
     478                        .field1         = 0, 
     479                        .field2         = 20000, 
     480                }, { 
     481                        .id             = N810BM_PMM_ADC_BATCURR, 
     482                        .flags          = 0x06, 
     483                        .adc_groupnr    = 1, 
     484                        .field1         = 0, 
     485                        .field2         = 9660, 
     486                }, 
     487                /* ADC group-nr 2 */ 
     488                { 
     489                        .id             = N810BM_PMM_ADC_BSI, 
     490                        .flags          = 0x02, 
     491                        .adc_groupnr    = 2, 
     492                        .field1         = 1169, 
     493                        .field2         = 0, 
     494                }, 
     495                /* ADC group-nr 3 */ 
     496                { 
     497                        .id             = N810BM_PMM_ADC_BATTEMP, 
     498                        .flags          = 0x03, 
     499                        .adc_groupnr    = 3, 
     500                        .field1         = 265423000, 
     501                        .field2         = 298, 
     502                }, 
     503                /* ADC group-nr 4 */ 
     504                { 
     505                        .id             = N810BM_PMM_ADC_LIGHTTEMP, 
     506                        .flags          = 0x04, 
     507                        .adc_groupnr    = 4, 
     508                        .field1         = 19533778, 
     509                        .field2         = 308019670, 
     510                        .field3         = 4700, 
     511                        .field4         = 2500, 
     512                }, 
     513        }; 
     514 
     515        /* Clear the array */ 
     516        memset(&bm->calib.adc, 0, sizeof(bm->calib.adc)); 
     517        for (i = 0; i < ARRAY_SIZE(bm->calib.adc); i++) 
     518                bm->calib.adc[i].flags = 0xFF; 
     519 
     520        /* Copy the defaults */ 
     521        for (i = 0; i < ARRAY_SIZE(defaults); i++) { 
     522                adc_calib = n810bm_get_adc_calib(bm, defaults[i].id); 
     523                if (WARN_ON(!adc_calib)) 
     524                        continue; 
     525                *adc_calib = defaults[i]; 
     526        } 
     527} 
     528 
     529static int n810bm_parse_pmm_block(struct n810bm *bm, 
     530                                  const struct firmware *pmm_block) 
     531{ 
     532        u8 byte; 
     533        int err; 
     534        unsigned int i, count; 
     535        struct n810bm_adc_calib *adc_calib; 
     536 
     537        /* Initialize to defaults */ 
     538        n810bm_adc_calib_set_defaults(bm); 
     539 
     540        /* Parse the PMM data */ 
     541        err = pmm_record_get(bm, pmm_block, &byte, sizeof(byte), 
     542                             1, 0, 0); /* group 1 / element 0 */ 
     543        err |= (byte != 0x01); 
     544        err |= pmm_record_get(bm, pmm_block, &byte, sizeof(byte), 
     545                              1, 1, 0); /* group 1 / element 1 */ 
     546        err |= (byte != 0x01); 
     547        if (err) 
     548                err = n810bm_parse_pmm_group2(bm, pmm_block); 
     549        else 
     550                err = n810bm_parse_pmm_group1(bm, pmm_block); 
     551        if (err) 
     552                return err; 
     553 
     554        /* Sanity checks */ 
     555        for (i = 0, count = 0; i < ARRAY_SIZE(bm->calib.adc); i++) { 
     556                adc_calib = &bm->calib.adc[i]; 
     557                if (adc_calib->flags == 0xFF) 
     558                        continue; 
     559                switch (adc_calib->id) { 
     560                case N810BM_PMM_ADC_BATVOLT: 
     561                        if (adc_calib->field1 < 2400 || 
     562                            adc_calib->field1 > 2700) 
     563                                goto value_check_fail; 
     564                        if (adc_calib->field2 < 20000 || 
     565                            adc_calib->field2 > 23000) 
     566                                goto value_check_fail; 
     567                        count++; 
     568                        break; 
     569                case N810BM_PMM_ADC_BSI: 
     570                        if (adc_calib->field1 < 1100 || 
     571                            adc_calib->field1 > 1300) 
     572                                goto value_check_fail; 
     573                        count++; 
     574                        break; 
     575                case N810BM_PMM_ADC_BATCURR: 
     576                        if (adc_calib->field2 < 7000 || 
     577                            adc_calib->field2 > 12000) 
     578                                goto value_check_fail; 
     579                        count++; 
     580                        break; 
     581                case N810BM_PMM_ADC_0xFE: 
     582                        if ((s32)adc_calib->field1 > 14 || 
     583                            (s32)adc_calib->field1 < -14) 
     584                                goto value_check_fail; 
     585                        if (adc_calib->field2 < 13000 || 
     586                            adc_calib->field2 > 13350) 
     587                                goto value_check_fail; 
     588                        count++; 
     589                        break; 
     590                case N810BM_PMM_ADC_CHGVOLT: 
     591                case N810BM_PMM_ADC_BATTEMP: 
     592                case N810BM_PMM_ADC_BKUPVOLT: 
     593                        count++; 
     594                        break; 
     595                case N810BM_PMM_ADC_GND2: 
     596                case N810BM_PMM_ADC_HOOKDET: 
     597                case N810BM_PMM_ADC_LIGHTSENS: 
     598                case N810BM_PMM_ADC_HEADSET: 
     599                case N810BM_PMM_ADC_LIGHTTEMP: 
     600                case N810BM_PMM_ADC_RFGP: 
     601                case N810BM_PMM_ADC_WBTX: 
     602                case N810BM_PMM_ADC_RETUTEMP: 
     603                        break; 
     604                } 
     605                dev_dbg(&bm->pdev->dev, 
     606                        "ADC 0x%02X calib: 0x%02X 0x%02X 0x%08X 0x%08X 0x%04X 0x%04X", 
     607                        adc_calib->id, adc_calib->flags, adc_calib->adc_groupnr, 
     608                        adc_calib->field1, adc_calib->field2, 
     609                        adc_calib->field3, adc_calib->field4); 
     610        } 
     611        if (count != 7) { 
     612                dev_err(&bm->pdev->dev, "PMM sanity check: Did not find " 
     613                        "all required values (count=%u)", count); 
     614                goto check_fail; 
     615        } 
     616 
     617        return 0; 
     618 
     619value_check_fail: 
     620        dev_err(&bm->pdev->dev, "PMM image sanity check failed " 
     621                "(id=%02X, field1=%08X, field2=%08X)", 
     622                adc_calib->id, adc_calib->field1, adc_calib->field2); 
     623check_fail: 
     624        return -EILSEQ; 
     625} 
     626 
     627/* Set the current measure timer that triggers on Tahvo IRQ 7 
     628 * An interval of zero disables the timer. */ 
     629static void n810bm_set_current_measure_timer(struct n810bm *bm, 
     630                                             u16 millisec_interval) 
     631{ 
     632        u16 value = millisec_interval; 
     633 
     634        if (value <= 0xF905) { 
     635                value = ((u64)0x10624DD3 * (u64)(value + 0xF9)) >> 32; 
     636                value /= 16; 
     637        } else 
     638                value = 0xFF; 
     639 
     640        tahvo_write(bm, TAHVO_REG_BATCURRTIMER, value & 0xFF); 
     641 
     642        tahvo_set(bm, TAHVO_REG_CHGCTL, 
     643                  TAHVO_REG_CHGCTL_CURTIMRST); 
     644        tahvo_clear(bm, TAHVO_REG_CHGCTL, 
     645                    TAHVO_REG_CHGCTL_CURTIMRST); 
     646 
     647        if (millisec_interval) 
     648                tahvo_enable_irq(TAHVO_INT_BATCURR); 
     649        else 
     650                tahvo_disable_irq(TAHVO_INT_BATCURR); 
     651 
     652        //TODO also do a software timer for safety. 
     653} 
     654 
     655static void n810bm_enable_current_measure(struct n810bm *bm) 
     656{ 
     657        WARN_ON(bm->current_measure_enabled < 0); 
     658        if (!bm->current_measure_enabled) { 
     659                /* Enable the current measurement circuitry */ 
     660                tahvo_set(bm, TAHVO_REG_CHGCTL, 
     661                          TAHVO_REG_CHGCTL_CURMEAS); 
     662                dev_dbg(&bm->pdev->dev, 
     663                        "Current measurement circuitry enabled"); 
     664        } 
     665        bm->current_measure_enabled++; 
     666} 
     667 
     668static void n810bm_disable_current_measure(struct n810bm *bm) 
     669{ 
     670        bm->current_measure_enabled--; 
     671        WARN_ON(bm->current_measure_enabled < 0); 
     672        if (!bm->current_measure_enabled) { 
     673                /* Disable the current measurement circuitry */ 
     674                tahvo_clear(bm, TAHVO_REG_CHGCTL, 
     675                            TAHVO_REG_CHGCTL_CURMEAS); 
     676                dev_dbg(&bm->pdev->dev, 
     677                        "Current measurement circuitry disabled"); 
     678        } 
     679} 
     680 
     681/* Measure the actual battery current. Returns a signed value in mA. 
     682 * Does only work, if current measurement was enabled. */ 
     683static int n810bm_measure_batt_current(struct n810bm *bm) 
     684{ 
     685        u16 retval; 
     686        int adc = 0, ma, i; 
     687 
     688        if (WARN_ON(bm->current_measure_enabled <= 0)) 
     689                return 0; 
     690        for (i = 0; i < 3; i++) { 
     691                retval = tahvo_read(bm, TAHVO_REG_BATCURR); 
     692                adc += (s16)retval; /* Value is signed */ 
     693        } 
     694        adc /= 3; 
     695 
     696        //TODO convert to mA 
     697        ma = adc; 
     698 
     699        return ma; 
     700} 
     701 
     702/* Requires bm->mutex locked */ 
     703static int n810bm_measure_batt_current_async(struct n810bm *bm) 
     704{ 
     705        int ma; 
     706        bool charging = lipocharge_is_charging(&bm->charger); 
     707 
     708        n810bm_enable_current_measure(bm); 
     709        if (!charging) 
     710                WARN_ON(bm->active_current_pwm != 0); 
     711        tahvo_maskset(bm, TAHVO_REG_CHGCTL, 
     712                      TAHVO_REG_CHGCTL_EN | 
     713                      TAHVO_REG_CHGCTL_PWMOVR | 
     714                      TAHVO_REG_CHGCTL_PWMOVRZERO, 
     715                      TAHVO_REG_CHGCTL_EN | 
     716                      TAHVO_REG_CHGCTL_PWMOVR | 
     717                      (charging ? 0 : TAHVO_REG_CHGCTL_PWMOVRZERO)); 
     718        ma = n810bm_measure_batt_current(bm); 
     719        tahvo_maskset(bm, TAHVO_REG_CHGCTL, 
     720                      TAHVO_REG_CHGCTL_EN | 
     721                      TAHVO_REG_CHGCTL_PWMOVR | 
     722                      TAHVO_REG_CHGCTL_PWMOVRZERO, 
     723                      (charging ? TAHVO_REG_CHGCTL_EN : 0)); 
     724        n810bm_disable_current_measure(bm); 
     725 
     726        return ma; 
     727} 
     728 
     729static int adc_sanity_check(struct n810bm *bm, unsigned int channel) 
     730{ 
     731        int value; 
     732 
     733        value = retu_read_adc(&n810bm_retu_device->dev, channel); 
     734        if (value < 0) { 
     735                dev_err(&bm->pdev->dev, "Failed to read GND ADC channel %u", 
     736                        channel); 
     737                return -EIO; 
     738        } 
     739        dev_dbg(&bm->pdev->dev, 
     740                "GND ADC channel %u sanity check got value: %d", 
     741                channel, value); 
     742        if (value > 5) { 
     743                n810bm_emergency(bm, "GND ADC sanity check failed"); 
     744                return -EIO; 
     745        } 
     746 
     747        return 0; 
     748} 
     749 
     750static int n810bm_check_adc_sanity(struct n810bm *bm) 
     751{ 
     752        int err; 
     753 
     754        /* Discard one conversion */ 
     755        retu_write(bm, RETU_REG_ADCSCR, 0); 
     756        retu_read_adc(&n810bm_retu_device->dev, RETU_ADC_GND2); 
     757 
     758        err = adc_sanity_check(bm, RETU_ADC_GND2); 
     759        if (err) 
     760                return err; 
     761 
     762        return 0; 
     763} 
     764 
     765/* Measure the battery voltage. Returns the value in mV (or negative value on error). */ 
     766static int n810bm_measure_batt_voltage(struct n810bm *bm) 
     767{ 
     768        int adc; 
     769        unsigned int mv; 
     770        const unsigned int scale = 1000; 
     771 
     772        adc = retu_adc_average(bm, RETU_ADC_BATTVOLT, 5); 
     773        if (adc < 0) 
     774                return adc; 
     775        if (adc <= 0x37) 
     776                return 2800; 
     777        mv = 2800 + ((adc - 0x37) * (((4200 - 2800) * scale) / (0x236 - 0x37))) / scale; 
     778 
     779        //TODO compensate for power consumption 
     780        //TODO honor calibration values 
     781 
     782        return mv; 
     783} 
     784 
     785/* Measure the charger voltage. Returns the value in mV (or negative value on error). */ 
     786static int n810bm_measure_charger_voltage(struct n810bm *bm) 
     787{ 
     788        int adc; 
     789        unsigned int mv; 
     790 
     791        adc = retu_adc_average(bm, RETU_ADC_CHGVOLT, 5); 
     792        if (adc < 0) 
     793                return adc; 
     794        //TODO convert to mV 
     795        mv = adc; 
     796 
     797        return mv; 
     798} 
     799 
     800/* Measure backup battery voltage. Returns the value in mV (or negative value on error). */ 
     801static int n810bm_measure_backup_batt_voltage(struct n810bm *bm) 
     802{ 
     803        int adc; 
     804        unsigned int mv; 
     805 
     806        adc = retu_adc_average(bm, RETU_ADC_BKUPVOLT, 3); 
     807        if (adc < 0) 
     808                return adc; 
     809        //TODO convert to mV 
     810        mv = adc; 
     811 
     812        return mv; 
     813} 
     814 
     815/* Measure the battery temperature. Returns the value in K (or negative value on error). */ 
     816static int n810bm_measure_batt_temp(struct n810bm *bm) 
     817{ 
     818        int adc; 
     819        unsigned int k; 
     820 
     821        adc = retu_adc_average(bm, RETU_ADC_BATTEMP, 3); 
     822        if (adc < 0) 
     823                return adc; 
     824        //TODO convert to K 
     825        k = adc; 
     826 
     827        return k; 
     828} 
     829 
     830/* Read the battery capacity via BSI pin. */ 
     831static enum n810bm_capacity n810bm_read_batt_capacity(struct n810bm *bm) 
     832{ 
     833        int adc; 
     834        const unsigned int hyst = 20; 
     835 
     836        adc = retu_adc_average(bm, RETU_ADC_BSI, 5); 
     837        if (adc < 0) { 
     838                dev_err(&bm->pdev->dev, "Failed to read BSI ADC"); 
     839                return N810BM_CAP_UNKNOWN; 
     840        } 
     841 
     842        if (adc >= 0x3B5 - hyst && adc <= 0x3B5 + hyst) 
     843                return N810BM_CAP_1500MAH; 
     844 
     845        dev_err(&bm->pdev->dev, "Capacity indicator 0x%X unknown", adc); 
     846 
     847        return N810BM_CAP_UNKNOWN; 
     848} 
     849 
     850/* Convert a battery voltage (in mV) to percentage. */ 
     851static unsigned int n810bm_mvolt2percent(unsigned int mv) 
     852{ 
     853        const unsigned int minv = 3700; 
     854        const unsigned int maxv = 4150; 
     855        unsigned int percent; 
     856 
     857        mv = clamp(mv, minv, maxv); 
     858        percent = (mv - minv) * 100 / (maxv - minv); 
     859 
     860        return percent; 
     861} 
     862 
     863static void n810bm_start_charge(struct n810bm *bm) 
     864{ 
     865        int err; 
     866 
     867        WARN_ON(!bm->battery_present); 
     868        WARN_ON(!bm->charger_present); 
     869 
     870        /* Set PWM to zero */ 
     871        bm->active_current_pwm = 0; 
     872        tahvo_write(bm, TAHVO_REG_CHGCURR, bm->active_current_pwm); 
     873 
     874        /* Charge global enable */ 
     875        tahvo_maskset(bm, TAHVO_REG_CHGCTL, 
     876                      TAHVO_REG_CHGCTL_EN | 
     877                      TAHVO_REG_CHGCTL_PWMOVR | 
     878                      TAHVO_REG_CHGCTL_PWMOVRZERO, 
     879                      TAHVO_REG_CHGCTL_EN); 
     880 
     881        WARN_ON((int)bm->capacity <= 0); 
     882        bm->charger.capacity = bm->capacity; 
     883        err = lipocharge_start(&bm->charger); 
     884        WARN_ON(err); 
     885 
     886        /* Initialize current measurement circuitry */ 
     887        n810bm_enable_current_measure(bm); 
     888        n810bm_set_current_measure_timer(bm, 250); 
     889 
     890        dev_info(&bm->pdev->dev, "Charging battery"); 
     891        n810bm_notify_charger_state(bm); 
     892        n810bm_notify_charger_pwm(bm); 
     893} 
     894 
     895static void n810bm_stop_charge(struct n810bm *bm) 
     896{ 
     897        if (lipocharge_is_charging(&bm->charger)) { 
     898                n810bm_set_current_measure_timer(bm, 0); 
     899                n810bm_disable_current_measure(bm); 
     900        } 
     901        lipocharge_stop(&bm->charger); 
     902 
     903        /* Set PWM to zero */ 
     904        bm->active_current_pwm = 0; 
     905        tahvo_write(bm, TAHVO_REG_CHGCURR, bm->active_current_pwm); 
     906 
     907        /* Charge global disable */ 
     908        tahvo_maskset(bm, TAHVO_REG_CHGCTL, 
     909                      TAHVO_REG_CHGCTL_EN | 
     910                      TAHVO_REG_CHGCTL_PWMOVR | 
     911                      TAHVO_REG_CHGCTL_PWMOVRZERO, 
     912                      0); 
     913 
     914        dev_info(&bm->pdev->dev, "Not charging battery"); 
     915        n810bm_notify_charger_state(bm); 
     916        n810bm_notify_charger_pwm(bm); 
     917} 
     918 
     919/* Periodic check */ 
     920static void n810bm_periodic_check_work(struct work_struct *work) 
     921{ 
     922        struct n810bm *bm = container_of(to_delayed_work(work), 
     923                                         struct n810bm, periodic_check_work); 
     924        u16 status; 
     925        bool battery_was_present, charger_was_present; 
     926        int mv; 
     927 
     928        mutex_lock(&bm->mutex); 
     929 
     930        status = retu_read(bm, RETU_REG_STATUS); 
     931        battery_was_present = bm->battery_present; 
     932        charger_was_present = bm->charger_present; 
     933        bm->battery_present = !!(status & RETU_REG_STATUS_BATAVAIL); 
     934        bm->charger_present = !!(status & RETU_REG_STATUS_CHGPLUG); 
     935 
     936        if (bm->battery_present != battery_was_present) { 
     937                /* Battery state changed */ 
     938                if (bm->battery_present) { 
     939                        bm->capacity = n810bm_read_batt_capacity(bm); 
     940                        if (bm->capacity == N810BM_CAP_UNKNOWN) { 
     941                                dev_err(&bm->pdev->dev, "Unknown battery detected"); 
     942                        } else { 
     943                                dev_info(&bm->pdev->dev, "Detected %u mAh battery", 
     944                                         (unsigned int)bm->capacity); 
     945                        } 
     946                } else { 
     947                        bm->capacity = N810BM_CAP_NONE; 
     948                        dev_info(&bm->pdev->dev, "The main battery was removed"); 
     949                        //TODO disable charging 
     950                } 
     951        } 
     952 
     953        if (bm->charger_present != charger_was_present) { 
     954                /* Charger state changed */ 
     955                dev_info(&bm->pdev->dev, "The charger was %s", 
     956                         bm->charger_present ? "plugged in" : "removed"); 
     957                n810bm_notify_charger_present(bm); 
     958        } 
     959 
     960        if ((bm->battery_present && !bm->charger_present) || 
     961            !n810bm_known_battery_present(bm)){ 
     962                /* We're draining the battery */ 
     963                mv = n810bm_measure_batt_voltage(bm); 
     964                if (mv < 0) { 
     965                        n810bm_emergency(bm, 
     966                                "check: Failed to measure voltage"); 
     967                } 
     968                if (mv < N810BM_MIN_VOLTAGE_THRES) { 
     969                        n810bm_emergency(bm, 
     970                                "check: Minimum voltage threshold reached"); 
     971                } 
     972        } 
     973 
     974        if (bm->charger_present && n810bm_known_battery_present(bm)) { 
     975                /* Known battery and charger are connected */ 
     976                if (bm->charger_enabled) { 
     977                        /* Charger is enabled */ 
     978                        if (!lipocharge_is_charging(&bm->charger)) { 
     979                                //TODO start charging, if battery is below some threshold 
     980                                n810bm_start_charge(bm); 
     981                        } 
     982                } 
     983        } 
     984 
     985        if (lipocharge_is_charging(&bm->charger) && !bm->charger_present) { 
     986                /* Charger was unplugged. */ 
     987                n810bm_stop_charge(bm); 
     988        } 
     989 
     990        mutex_unlock(&bm->mutex); 
     991        schedule_delayed_work(&bm->periodic_check_work, 
     992                              round_jiffies_relative(N810BM_CHECK_INTERVAL)); 
     993} 
     994 
     995/*XXX 
     996static void n810bm_adc_irq_handler(unsigned long data) 
     997{ 
     998        struct n810bm *bm = (struct n810bm *)data; 
     999 
     1000        retu_ack_irq(RETU_INT_ADCS); 
     1001        //TODO 
     1002dev_info(&bm->pdev->dev, "ADC interrupt triggered\n"); 
     1003} 
     1004*/ 
     1005 
     1006static void n810bm_tahvo_current_measure_work(struct work_struct *work) 
     1007{ 
     1008        struct n810bm *bm = container_of(work, struct n810bm, currmeas_irq_work); 
     1009        int res, ma, mv, temp; 
     1010 
     1011        mutex_lock(&bm->mutex); 
     1012        if (!lipocharge_is_charging(&bm->charger)) 
     1013                goto out_unlock; 
     1014 
     1015        tahvo_maskset(bm, TAHVO_REG_CHGCTL, 
     1016                      TAHVO_REG_CHGCTL_PWMOVR | 
     1017                      TAHVO_REG_CHGCTL_PWMOVRZERO, 
     1018                      TAHVO_REG_CHGCTL_PWMOVR); 
     1019        ma = n810bm_measure_batt_current(bm); 
     1020        tahvo_maskset(bm, TAHVO_REG_CHGCTL, 
     1021                      TAHVO_REG_CHGCTL_PWMOVR | 
     1022                      TAHVO_REG_CHGCTL_PWMOVRZERO, 
     1023                      TAHVO_REG_CHGCTL_PWMOVR | 
     1024                      TAHVO_REG_CHGCTL_PWMOVRZERO); 
     1025        msleep(10); 
     1026        mv = n810bm_measure_batt_voltage(bm); 
     1027        tahvo_maskset(bm, TAHVO_REG_CHGCTL, 
     1028                      TAHVO_REG_CHGCTL_PWMOVR | 
     1029                      TAHVO_REG_CHGCTL_PWMOVRZERO, 
     1030                      0); 
     1031        temp = n810bm_measure_batt_temp(bm); 
     1032        if (WARN_ON(mv < 0)) 
     1033                goto out_unlock; 
     1034        if (WARN_ON(temp < 0)) 
     1035                goto out_unlock; 
     1036 
     1037        if (bm->verbose_charge_log) { 
     1038                dev_info(&bm->pdev->dev, 
     1039                         "Battery charge state: %d mV, %d mA (%s)", 
     1040                         mv, ma, 
     1041                         (ma <= 0) ? "discharging" : "charging"); 
     1042        } 
     1043        res = lipocharge_update_state(&bm->charger, mv, ma, temp); 
     1044        if (res) { 
     1045                if (res > 0) 
     1046                        dev_info(&bm->pdev->dev, "Battery fully charged"); 
     1047                n810bm_stop_charge(bm); 
     1048        } 
     1049out_unlock: 
     1050        mutex_unlock(&bm->mutex); 
     1051} 
     1052 
     1053static void n810bm_tahvo_current_measure_irq_handler(unsigned long data) 
     1054{ 
     1055        struct n810bm *bm = (struct n810bm *)data; 
     1056 
     1057        tahvo_ack_irq(TAHVO_INT_BATCURR); 
     1058        schedule_work(&bm->currmeas_irq_work); 
     1059} 
     1060 
     1061#define DEFINE_ATTR_NOTIFY(attr_name)                                           \ 
     1062        void n810bm_notify_##attr_name(struct n810bm *bm)                       \ 
     1063        {                                                                       \ 
     1064                set_bit(N810BM_NOTIFY_##attr_name, &bm->notify_flags);          \ 
     1065                wmb();                                                          \ 
     1066                schedule_work(&bm->notify_work);                                \ 
     1067        } 
     1068 
     1069#define DEFINE_SHOW_INT_FUNC(name, member)                                      \ 
     1070        static ssize_t n810bm_attr_##name##_show(struct device *dev,            \ 
     1071                                                 struct device_attribute *attr, \ 
     1072                                                 char *buf)                     \ 
     1073        {                                                                       \ 
     1074                struct n810bm *bm = device_to_n810bm(dev);                      \ 
     1075                ssize_t count;                                                  \ 
     1076                                                                                \ 
     1077                mutex_lock(&bm->mutex);                                         \ 
     1078                count = snprintf(buf, PAGE_SIZE, "%d\n", (int)(bm->member));    \ 
     1079                mutex_unlock(&bm->mutex);                                       \ 
     1080                                                                                \ 
     1081                return count;                                                   \ 
     1082        } 
     1083 
     1084#define DEFINE_STORE_INT_FUNC(name, member)                                     \ 
     1085        static ssize_t n810bm_attr_##name##_store(struct device *dev,           \ 
     1086                                                  struct device_attribute *attr,\ 
     1087                                                  const char *buf, size_t count)\ 
     1088        {                                                                       \ 
     1089                struct n810bm *bm = device_to_n810bm(dev);                      \ 
     1090                long val;                                                       \ 
     1091                int err;                                                        \ 
     1092                                                                                \ 
     1093                mutex_lock(&bm->mutex);                                         \ 
     1094                err = strict_strtol(buf, 0, &val);                              \ 
     1095                if (!err)                                                       \ 
     1096                        bm->member = (typeof(bm->member))val;                   \ 
     1097                mutex_unlock(&bm->mutex);                                       \ 
     1098                                                                                \ 
     1099                return err ? err : count;                                       \ 
     1100        } 
     1101 
     1102#define DEFINE_ATTR_SHOW_INT(name, member)                                      \ 
     1103        DEFINE_SHOW_INT_FUNC(name, member)                                      \ 
     1104        static DEVICE_ATTR(name, S_IRUGO,                                       \ 
     1105                           n810bm_attr_##name##_show, NULL); 
     1106 
     1107#define DEFINE_ATTR_SHOW_STORE_INT(name, member)                                \ 
     1108        DEFINE_SHOW_INT_FUNC(name, member)                                      \ 
     1109        DEFINE_STORE_INT_FUNC(name, member)                                     \ 
     1110        static DEVICE_ATTR(name, S_IRUGO | S_IWUSR,                             \ 
     1111                           n810bm_attr_##name##_show,                           \ 
     1112                           n810bm_attr_##name##_store); 
     1113 
     1114DEFINE_ATTR_SHOW_INT(battery_present, battery_present); 
     1115DEFINE_ATTR_SHOW_INT(charger_present, charger_present); 
     1116static DEFINE_ATTR_NOTIFY(charger_present); 
     1117DEFINE_ATTR_SHOW_INT(charger_state, charger.state); 
     1118static DEFINE_ATTR_NOTIFY(charger_state); 
     1119DEFINE_ATTR_SHOW_INT(charger_pwm, active_current_pwm); 
     1120static DEFINE_ATTR_NOTIFY(charger_pwm); 
     1121DEFINE_ATTR_SHOW_STORE_INT(charger_enable, charger_enabled); 
     1122DEFINE_ATTR_SHOW_STORE_INT(charger_verbose, verbose_charge_log); 
     1123 
     1124static ssize_t n810bm_attr_battery_level_show(struct device *dev, 
     1125                                              struct device_attribute *attr, 
     1126                                              char *buf) 
     1127{ 
     1128        struct n810bm *bm = device_to_n810bm(dev); 
     1129        ssize_t count = -ENODEV; 
     1130        int millivolt; 
     1131 
     1132        mutex_lock(&bm->mutex); 
     1133        if (!bm->battery_present || lipocharge_is_charging(&bm->charger)) 
     1134                millivolt = 0; 
     1135        else 
     1136                millivolt = n810bm_measure_batt_voltage(bm); 
     1137        if (millivolt >= 0) { 
     1138                count = snprintf(buf, PAGE_SIZE, "%u\n", 
     1139                                 n810bm_mvolt2percent(millivolt)); 
     1140        } 
     1141        mutex_unlock(&bm->mutex); 
     1142 
     1143        return count; 
     1144} 
     1145static DEVICE_ATTR(battery_level, S_IRUGO, 
     1146                   n810bm_attr_battery_level_show, NULL); 
     1147 
     1148static ssize_t n810bm_attr_battery_capacity_show(struct device *dev, 
     1149                                                 struct device_attribute *attr, 
     1150                                                 char *buf) 
     1151{ 
     1152        struct n810bm *bm = device_to_n810bm(dev); 
     1153        ssize_t count; 
     1154        int capacity = 0; 
     1155 
     1156        mutex_lock(&bm->mutex); 
     1157        if (n810bm_known_battery_present(bm)) 
     1158                capacity = (int)bm->capacity; 
     1159        count = snprintf(buf, PAGE_SIZE, "%d\n", capacity); 
     1160        mutex_unlock(&bm->mutex); 
     1161 
     1162        return count; 
     1163} 
     1164static DEVICE_ATTR(battery_capacity, S_IRUGO, 
     1165                   n810bm_attr_battery_capacity_show, NULL); 
     1166 
     1167static ssize_t n810bm_attr_battery_temp_show(struct device *dev, 
     1168                                             struct device_attribute *attr, 
     1169                                             char *buf) 
     1170{ 
     1171        struct n810bm *bm = device_to_n810bm(dev); 
     1172        ssize_t count = -ENODEV; 
     1173        int k; 
     1174 
     1175        mutex_lock(&bm->mutex); 
     1176        k = n810bm_measure_batt_temp(bm); 
     1177        if (k >= 0) 
     1178                count = snprintf(buf, PAGE_SIZE, "%d\n", k); 
     1179        mutex_unlock(&bm->mutex); 
     1180 
     1181        return count; 
     1182} 
     1183static DEVICE_ATTR(battery_temp, S_IRUGO, 
     1184                   n810bm_attr_battery_temp_show, NULL); 
     1185 
     1186static ssize_t n810bm_attr_charger_voltage_show(struct device *dev, 
     1187                                                struct device_attribute *attr, 
     1188                                                char *buf) 
     1189{ 
     1190        struct n810bm *bm = device_to_n810bm(dev); 
     1191        ssize_t count = -ENODEV; 
     1192        int mv = 0; 
     1193 
     1194        mutex_lock(&bm->mutex); 
     1195        if (bm->charger_present) 
     1196                mv = n810bm_measure_charger_voltage(bm); 
     1197        if (mv >= 0) 
     1198                count = snprintf(buf, PAGE_SIZE, "%d\n", mv); 
     1199        mutex_unlock(&bm->mutex); 
     1200 
     1201        return count; 
     1202} 
     1203static DEVICE_ATTR(charger_voltage, S_IRUGO, 
     1204                   n810bm_attr_charger_voltage_show, NULL); 
     1205 
     1206static ssize_t n810bm_attr_backup_battery_voltage_show(struct device *dev, 
     1207                                                       struct device_attribute *attr, 
     1208                                                       char *buf) 
     1209{ 
     1210        struct n810bm *bm = device_to_n810bm(dev); 
     1211        ssize_t count = -ENODEV; 
     1212        int mv; 
     1213 
     1214        mutex_lock(&bm->mutex); 
     1215        mv = n810bm_measure_backup_batt_voltage(bm); 
     1216        if (mv >= 0) 
     1217                count = snprintf(buf, PAGE_SIZE, "%d\n", mv); 
     1218        mutex_unlock(&bm->mutex); 
     1219 
     1220        return count; 
     1221} 
     1222static DEVICE_ATTR(backup_battery_voltage, S_IRUGO, 
     1223                   n810bm_attr_backup_battery_voltage_show, NULL); 
     1224 
     1225static ssize_t n810bm_attr_battery_current_show(struct device *dev, 
     1226                                                struct device_attribute *attr, 
     1227                                                char *buf) 
     1228{ 
     1229        struct n810bm *bm = device_to_n810bm(dev); 
     1230        ssize_t count = -ENODEV; 
     1231        int ma = 0; 
     1232 
     1233        mutex_lock(&bm->mutex); 
     1234        if (bm->battery_present) 
     1235                ma = n810bm_measure_batt_current_async(bm); 
     1236        count = snprintf(buf, PAGE_SIZE, "%d\n", ma); 
     1237        mutex_unlock(&bm->mutex); 
     1238 
     1239        return count; 
     1240} 
     1241static DEVICE_ATTR(battery_current, S_IRUGO, 
     1242                   n810bm_attr_battery_current_show, NULL); 
     1243 
     1244static const struct device_attribute *n810bm_attrs[] = { 
     1245        &dev_attr_battery_present, 
     1246        &dev_attr_battery_level, 
     1247        &dev_attr_battery_current, 
     1248        &dev_attr_battery_capacity, 
     1249        &dev_attr_battery_temp, 
     1250        &dev_attr_backup_battery_voltage, 
     1251        &dev_attr_charger_present, 
     1252        &dev_attr_charger_state, 
     1253        &dev_attr_charger_verbose, 
     1254        &dev_attr_charger_voltage, 
     1255        &dev_attr_charger_enable, 
     1256        &dev_attr_charger_pwm, 
     1257}; 
     1258 
     1259static void n810bm_notify_work(struct work_struct *work) 
     1260{ 
     1261        struct n810bm *bm = container_of(work, struct n810bm, notify_work); 
     1262        unsigned long notify_flags; 
     1263 
     1264        notify_flags = xchg(&bm->notify_flags, 0); 
     1265        mb(); 
     1266 
     1267#define do_notify(attr_name)                                            \ 
     1268        do {                                                            \ 
     1269                if (notify_flags & (1 << N810BM_NOTIFY_##attr_name)) {  \ 
     1270                        sysfs_notify(&bm->pdev->dev.kobj, NULL,         \ 
     1271                                     dev_attr_##attr_name.attr.name);   \ 
     1272                }                                                       \ 
     1273        } while (0) 
     1274 
     1275        do_notify(charger_present); 
     1276        do_notify(charger_state); 
     1277        do_notify(charger_pwm); 
     1278} 
     1279 
     1280static int n810bm_charger_set_current_pwm(struct lipocharge *c, 
     1281                                          unsigned int duty_cycle) 
     1282{ 
     1283        struct n810bm *bm = container_of(c, struct n810bm, charger); 
     1284        int err = -EINVAL; 
     1285 
     1286        WARN_ON(!mutex_is_locked(&bm->mutex)); 
     1287        if (WARN_ON(duty_cycle > 0xFF)) 
     1288                goto out; 
     1289        if (WARN_ON(!bm->charger_enabled)) 
     1290                goto out; 
     1291        if (WARN_ON(!bm->battery_present || !bm->charger_present)) 
     1292                goto out; 
     1293 
     1294        if (duty_cycle != bm->active_current_pwm) { 
     1295                bm->active_current_pwm = duty_cycle; 
     1296                tahvo_write(bm, TAHVO_REG_CHGCURR, duty_cycle); 
     1297                n810bm_notify_charger_pwm(bm); 
     1298        } 
     1299 
     1300        err = 0; 
     1301out: 
     1302 
     1303        return err; 
     1304} 
     1305 
     1306static void n810bm_charger_emergency(struct lipocharge *c) 
     1307{ 
     1308        struct n810bm *bm = container_of(c, struct n810bm, charger); 
     1309 
     1310        n810bm_emergency(bm, "Battery charger fault"); 
     1311} 
     1312 
     1313static void n810bm_hw_exit(struct n810bm *bm) 
     1314{ 
     1315        n810bm_stop_charge(bm); 
     1316        retu_write(bm, RETU_REG_ADCSCR, 0); 
     1317} 
     1318 
     1319static int n810bm_hw_init(struct n810bm *bm) 
     1320{ 
     1321        int err; 
     1322 
     1323        err = n810bm_check_adc_sanity(bm); 
     1324        if (err) 
     1325                return err; 
     1326 
     1327        n810bm_stop_charge(bm); 
     1328 
     1329        return 0; 
     1330} 
     1331 
     1332static void n810bm_cancel_and_flush_work(struct n810bm *bm) 
     1333{ 
     1334        cancel_delayed_work_sync(&bm->periodic_check_work); 
     1335        cancel_work_sync(&bm->notify_work); 
     1336        cancel_work_sync(&bm->currmeas_irq_work); 
     1337        flush_scheduled_work(); 
     1338} 
     1339 
     1340static int n810bm_device_init(struct n810bm *bm) 
     1341{ 
     1342        int attr_index; 
     1343        int err; 
     1344 
     1345        bm->charger.rate = LIPORATE_p6C; 
     1346        bm->charger.top_voltage = 4100; 
     1347        bm->charger.duty_cycle_max = 0xFF; 
     1348        bm->charger.set_current_pwm = n810bm_charger_set_current_pwm; 
     1349        bm->charger.emergency = n810bm_charger_emergency; 
     1350        lipocharge_init(&bm->charger, &bm->pdev->dev); 
     1351 
     1352        err = n810bm_hw_init(bm); 
     1353        if (err) 
     1354                goto error; 
     1355        for (attr_index = 0; attr_index < ARRAY_SIZE(n810bm_attrs); attr_index++) { 
     1356                err = device_create_file(&bm->pdev->dev, n810bm_attrs[attr_index]); 
     1357                if (err) 
     1358                        goto err_unwind_attrs; 
     1359        } 
     1360/*XXX 
     1361        err = retu_request_irq(RETU_INT_ADCS, 
     1362                               n810bm_adc_irq_handler, 
     1363                               (unsigned long)bm, "n810bm"); 
     1364        if (err) 
     1365                goto err_unwind_attrs; 
     1366*/ 
     1367        err = tahvo_request_irq(TAHVO_INT_BATCURR, 
     1368                                n810bm_tahvo_current_measure_irq_handler, 
     1369                                (unsigned long)bm, "n810bm"); 
     1370        if (err) 
     1371                goto err_free_retu_irq; 
     1372        tahvo_disable_irq(TAHVO_INT_BATCURR); 
     1373 
     1374        schedule_delayed_work(&bm->periodic_check_work, 
     1375                              round_jiffies_relative(N810BM_CHECK_INTERVAL)); 
     1376 
     1377        bm->initialized = 1; 
     1378        dev_info(&bm->pdev->dev, "Battery management initialized"); 
     1379 
     1380        return 0; 
     1381 
     1382err_free_retu_irq: 
     1383//XXX   retu_free_irq(RETU_INT_ADCS); 
     1384err_unwind_attrs: 
     1385        for (attr_index--; attr_index >= 0; attr_index--) 
     1386                device_remove_file(&bm->pdev->dev, n810bm_attrs[attr_index]); 
     1387/*err_exit:*/ 
     1388        n810bm_hw_exit(bm); 
     1389error: 
     1390        n810bm_cancel_and_flush_work(bm); 
     1391 
     1392        return err; 
     1393} 
     1394 
     1395static void n810bm_device_exit(struct n810bm *bm) 
     1396{ 
     1397        int i; 
     1398 
     1399        if (!bm->initialized) 
     1400                return; 
     1401 
     1402        lipocharge_exit(&bm->charger); 
     1403        tahvo_free_irq(TAHVO_INT_BATCURR); 
     1404//XXX   retu_free_irq(RETU_INT_ADCS); 
     1405        for (i = 0; i < ARRAY_SIZE(n810bm_attrs); i++) 
     1406                device_remove_file(&bm->pdev->dev, n810bm_attrs[i]); 
     1407 
     1408        n810bm_cancel_and_flush_work(bm); 
     1409 
     1410        n810bm_hw_exit(bm); 
     1411 
     1412        bm->initialized = 0; 
     1413} 
     1414 
     1415static void n810bm_pmm_block_found(const struct firmware *fw, void *context) 
     1416{ 
     1417        struct n810bm *bm = context; 
     1418        int err; 
     1419 
     1420        if (!fw) { 
     1421                dev_err(&bm->pdev->dev, 
     1422                        "CAL PMM block image file not found"); 
     1423                goto err_release; 
     1424        } 
     1425        if (fw->size != N810BM_PMM_BLOCK_SIZE || 
     1426            memcmp(fw->data, "BME-PMM-BLOCK01", 15) != 0) { 
     1427                dev_err(&bm->pdev->dev, 
     1428                        "CAL PMM block image file has an invalid format"); 
     1429                goto err_release; 
     1430        } 
     1431 
     1432        err = n810bm_parse_pmm_block(bm, fw); 
     1433        if (err) 
     1434                goto err_release; 
     1435        release_firmware(fw); 
     1436 
     1437        err = n810bm_device_init(bm); 
     1438        if (err) { 
     1439                dev_err(&bm->pdev->dev, 
     1440                        "Failed to initialized battery management (%d)", err); 
     1441                goto error; 
     1442        } 
     1443 
     1444        return; 
     1445err_release: 
     1446        release_firmware(fw); 
     1447error: 
     1448        return; 
     1449} 
     1450 
     1451static int __devinit n810bm_probe(void) 
     1452{ 
     1453        struct n810bm *bm; 
     1454        int err; 
     1455 
     1456        if (!n810bm_retu_device || !n810bm_tahvo_device) 
     1457                return 0; 
     1458 
     1459        bm = kzalloc(sizeof(*bm), GFP_KERNEL); 
     1460        if (!bm) 
     1461                return -ENOMEM; 
     1462        bm->pdev = n810bm_retu_device; 
     1463        platform_set_drvdata(n810bm_retu_device, bm); 
     1464        platform_set_drvdata(n810bm_tahvo_device, bm); 
     1465        mutex_init(&bm->mutex); 
     1466        INIT_DELAYED_WORK(&bm->periodic_check_work, n810bm_periodic_check_work); 
     1467        INIT_WORK(&bm->notify_work, n810bm_notify_work); 
     1468        INIT_WORK(&bm->currmeas_irq_work, n810bm_tahvo_current_measure_work); 
     1469 
     1470        dev_info(&bm->pdev->dev, "Requesting CAL BME PMM block firmware file " 
     1471                 N810BM_PMM_BLOCK_FILENAME); 
     1472        err = request_firmware_nowait(THIS_MODULE, 1, 
     1473                                      N810BM_PMM_BLOCK_FILENAME, 
     1474                                      &bm->pdev->dev, GFP_KERNEL, 
     1475                                      bm, n810bm_pmm_block_found); 
     1476        if (err) { 
     1477                dev_err(&bm->pdev->dev, 
     1478                        "Failed to request CAL PMM block image file (%d)", err); 
     1479                goto err_free; 
     1480        } 
     1481 
     1482        return 0; 
     1483 
     1484err_free: 
     1485        kfree(bm); 
     1486 
     1487        return err; 
     1488} 
     1489 
     1490static void __devexit n810bm_remove(void) 
     1491{ 
     1492        struct n810bm *bm; 
     1493 
     1494        if (!n810bm_retu_device || !n810bm_tahvo_device) 
     1495                return; 
     1496        bm = platform_get_drvdata(n810bm_retu_device); 
     1497 
     1498        n810bm_device_exit(bm); 
     1499 
     1500        kfree(bm); 
     1501        platform_set_drvdata(n810bm_retu_device, NULL); 
     1502        platform_set_drvdata(n810bm_tahvo_device, NULL); 
     1503} 
     1504 
     1505static int __devinit n810bm_retu_probe(struct platform_device *pdev) 
     1506{ 
     1507        n810bm_retu_device = pdev; 
     1508        return n810bm_probe(); 
     1509} 
     1510 
     1511static int __devexit n810bm_retu_remove(struct platform_device *pdev) 
     1512{ 
     1513        n810bm_remove(); 
     1514        n810bm_retu_device = NULL; 
     1515        return 0; 
     1516} 
     1517 
     1518static int __devinit n810bm_tahvo_probe(struct platform_device *pdev) 
     1519{ 
     1520        n810bm_tahvo_device = pdev; 
     1521        return n810bm_probe(); 
     1522} 
     1523 
     1524static int __devexit n810bm_tahvo_remove(struct platform_device *pdev) 
     1525{ 
     1526        n810bm_remove(); 
     1527        n810bm_tahvo_device = NULL; 
     1528        return 0; 
     1529} 
     1530 
     1531static struct platform_driver n810bm_retu_driver = { 
     1532        .remove         = __devexit_p(n810bm_retu_remove), 
     1533        .driver         = { 
     1534                .name   = "retu-n810bm", 
     1535        } 
     1536}; 
     1537 
     1538static struct platform_driver n810bm_tahvo_driver = { 
     1539        .remove         = __devexit_p(n810bm_tahvo_remove), 
     1540        .driver         = { 
     1541                .name   = "tahvo-n810bm", 
     1542        } 
     1543}; 
     1544 
     1545/* FIXME: for now alloc the device here... */ 
     1546static struct platform_device n810bm_tahvo_dev = { 
     1547        .name   = "tahvo-n810bm", 
     1548        .id     = -1, 
     1549}; 
     1550 
     1551static int __init n810bm_modinit(void) 
     1552{ 
     1553        int err; 
     1554 
     1555        //FIXME 
     1556        err = platform_device_register(&n810bm_tahvo_dev); 
     1557        if (err) 
     1558                return err; 
     1559 
     1560        err = platform_driver_probe(&n810bm_retu_driver, n810bm_retu_probe); 
     1561        if (err) 
     1562                return err; 
     1563        err = platform_driver_probe(&n810bm_tahvo_driver, n810bm_tahvo_probe); 
     1564        if (err) { 
     1565                platform_driver_unregister(&n810bm_retu_driver); 
     1566                return err; 
     1567        } 
     1568 
     1569        return 0; 
     1570} 
     1571module_init(n810bm_modinit); 
     1572 
     1573static void __exit n810bm_modexit(void) 
     1574{ 
     1575        //FIXME 
     1576        platform_device_unregister(&n810bm_tahvo_dev); 
     1577 
     1578        platform_driver_unregister(&n810bm_tahvo_driver); 
     1579        platform_driver_unregister(&n810bm_retu_driver); 
     1580} 
     1581module_exit(n810bm_modexit); 
     1582 
     1583MODULE_DESCRIPTION("Nokia n810 battery management"); 
     1584MODULE_FIRMWARE(N810BM_PMM_BLOCK_FILENAME); 
     1585MODULE_LICENSE("GPL"); 
     1586MODULE_AUTHOR("Michael Buesch"); 
  • new file linux-3.1/drivers/cbus/lipocharge.c

    - +  
     1/* 
     2 *   Generic LIPO battery charger 
     3 * 
     4 *   Copyright (c) 2010-2011 Michael Buesch <mb@bu3sch.de> 
     5 * 
     6 *   This program is free software; you can redistribute it and/or 
     7 *   modify it under the terms of the GNU General Public License 
     8 *   as published by the Free Software Foundation; either version 2 
     9 *   of the License, or (at your option) any later version. 
     10 * 
     11 *   This program is distributed in the hope that it will be useful, 
     12 *   but WITHOUT ANY WARRANTY; without even the implied warranty of 
     13 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
     14 *   GNU General Public License for more details. 
     15 */ 
     16 
     17#define DEBUG 
     18 
     19#include "lipocharge.h" 
     20 
     21#include <linux/slab.h> 
     22 
     23 
     24/* Hysteresis constants */ 
     25#define CURRENT_HYST            30 /* mA */ 
     26#define VOLTAGE_HYST            10 /* mV */ 
     27 
     28/* Threshold constants */ 
     29#define FINISH_CURRENT_PERCENT  3 
     30 
     31 
     32/* Returns the requested first-stage charge current in mA */ 
     33static inline unsigned int get_stage1_charge_current(struct lipocharge *c) 
     34{ 
     35        /* current = (capacity * C) */ 
     36        return c->capacity * c->rate / 1000; 
     37} 
     38 
     39void lipocharge_init(struct lipocharge *c, struct device *dev) 
     40{ 
     41        c->dev = dev; 
     42        c->state = LIPO_IDLE; 
     43} 
     44 
     45void lipocharge_exit(struct lipocharge *c) 
     46{ 
     47        c->state = LIPO_IDLE; 
     48} 
     49 
     50int lipocharge_start(struct lipocharge *c) 
     51{ 
     52        int err; 
     53 
     54        if (c->state != LIPO_IDLE) 
     55                return -EBUSY; 
     56        if (!c->set_current_pwm || !c->emergency) 
     57                return -EINVAL; 
     58        if (!c->top_voltage || c->top_voltage > 4200) 
     59                return -EINVAL; 
     60 
     61        c->active_duty_cycle = 0; 
     62        err = c->set_current_pwm(c, c->active_duty_cycle); 
     63        if (err) 
     64                return err; 
     65        c->state = LIPO_FIRST_STAGE; 
     66 
     67        return 0; 
     68} 
     69 
     70void lipocharge_stop(struct lipocharge *c) 
     71{ 
     72        if (c->state == LIPO_IDLE) 
     73                return; 
     74        c->state = LIPO_IDLE; 
     75} 
     76 
     77static int lipocharge_increase_current(struct lipocharge *c, 
     78                                       unsigned int inc_permille) 
     79{ 
     80        int old_pwm, new_pwm; 
     81 
     82        if (c->active_duty_cycle >= c->duty_cycle_max) 
     83                return 0; 
     84 
     85        old_pwm = c->active_duty_cycle; 
     86        new_pwm = old_pwm + (c->duty_cycle_max * inc_permille / 1000); 
     87        new_pwm = min(new_pwm, (int)c->duty_cycle_max); 
     88        c->active_duty_cycle = new_pwm; 
     89 
     90        dev_dbg(c->dev, "lipo: Increasing duty_cycle by " 
     91                "%u permille (0x%02X -> 0x%02X)", 
     92                inc_permille, old_pwm, new_pwm); 
     93 
     94        return c->set_current_pwm(c, c->active_duty_cycle); 
     95} 
     96 
     97static int lipocharge_decrease_current(struct lipocharge *c, 
     98                                       unsigned int dec_permille) 
     99{ 
     100        int old_pwm, new_pwm; 
     101 
     102        if (c->active_duty_cycle <= 0) 
     103                return 0; 
     104 
     105        old_pwm = c->active_duty_cycle; 
     106        new_pwm = old_pwm - (c->duty_cycle_max * dec_permille / 1000); 
     107        new_pwm = max(0, new_pwm); 
     108        c->active_duty_cycle = new_pwm; 
     109 
     110        dev_dbg(c->dev, "lipo: Decreasing duty_cycle by " 
     111                "%u permille (0x%02X -> 0x%02X)", 
     112                dec_permille, old_pwm, new_pwm); 
     113 
     114        return c->set_current_pwm(c, c->active_duty_cycle); 
     115} 
     116 
     117/** lipocharge_update_state - Update the charge state 
     118 * @c: The context. 
     119 * @voltage_mV: The measured battery voltage. 
     120 * @current_mA: The measured charge current. 
     121 *              negative -> drain. 
     122 *              positive -> charge. 
     123 * @temp_K: Battery temperature in K. 
     124 * 
     125 * Returns 0 on success, -1 on error. 
     126 * Returns 1, if the charging process is finished. 
     127 */ 
     128int lipocharge_update_state(struct lipocharge *c, 
     129                            unsigned int voltage_mV, 
     130                            int current_mA, 
     131                            unsigned int temp_K) 
     132{ 
     133        int requested_current, current_diff; 
     134        int err; 
     135        unsigned int permille; 
     136 
     137        //TODO temp 
     138 
     139restart: 
     140        switch (c->state) { 
     141        case LIPO_IDLE: 
     142                dev_err(c->dev, "%s: called while idle", __func__); 
     143                return -EINVAL; 
     144        case LIPO_FIRST_STAGE:  /* Constant current */ 
     145//printk("GOT %u %d %u\n", voltage_mV, current_mA, temp_K); 
     146                if (voltage_mV >= c->top_voltage) { 
     147                        /* Float voltage reached. 
     148                         * Switch charger mode to "constant current" */ 
     149                        c->state = LIPO_SECOND_STAGE; 
     150                        dev_dbg(c->dev, "Switched to second charging stage."); 
     151                        goto restart; 
     152                } 
     153                /* Float voltage not reached, yet. 
     154                 * Try to get the requested constant current. */ 
     155                requested_current = get_stage1_charge_current(c); 
     156                if (current_mA < 0) 
     157                        current_mA = 0; 
     158                current_diff = requested_current - current_mA; 
     159                if (abs(requested_current - current_mA) > CURRENT_HYST) { 
     160                        if (current_diff > 0) { 
     161                                /* Increase current */ 
     162                                permille = current_diff * 1000 / requested_current; 
     163                                permille /= 2; 
     164                                err = lipocharge_increase_current(c, permille); 
     165                                if (err) 
     166                                        return err; 
     167                        } else { 
     168                                /* Decrease current */ 
     169                                permille = (-current_diff) * 1000 / requested_current; 
     170                                permille /= 2; 
     171                                err = lipocharge_decrease_current(c, permille); 
     172                                if (err) 
     173                                        return err; 
     174                        } 
     175                } 
     176                break; 
     177        case LIPO_SECOND_STAGE: /* Constant voltage */ 
     178                //TODO 
     179                break; 
     180        } 
     181 
     182        return 0; 
     183} 
  • new file linux-3.1/drivers/cbus/lipocharge.h

    - +  
     1#ifndef LIPOCHARGE_H_ 
     2#define LIPOCHARGE_H_ 
     3 
     4#include <linux/types.h> 
     5#include <linux/device.h> 
     6 
     7 
     8#define LIPORATE(a,b)   (((a) * 1000) + ((b) * 100)) 
     9#define LIPORATE_p6C    LIPORATE(0,6)   /* 0.6C */ 
     10 
     11enum lipocharge_state { 
     12        LIPO_IDLE = 0,          /* Not charging */ 
     13        LIPO_FIRST_STAGE,       /* Charging: constant current */ 
     14        LIPO_SECOND_STAGE,      /* Charging: constant voltage */ 
     15}; 
     16 
     17/** struct lipocharge - A generic LIPO charger 
     18 * 
     19 * @capacity: Battery capacity in mAh. 
     20 * @rate: Charge rate. 
     21 * @top_voltage: Fully charged voltage, in mV. 
     22 * @duty_cycle_max: Max value for duty_cycle. 
     23 * 
     24 * @set_charge_current: Set the charge current PWM duty cycle. 
     25 * @emergency: Something went wrong. Force shutdown. 
     26 */ 
     27struct lipocharge { 
     28        unsigned int capacity; 
     29        unsigned int rate; 
     30        unsigned int top_voltage; 
     31        unsigned int duty_cycle_max; 
     32 
     33        int (*set_current_pwm)(struct lipocharge *c, unsigned int duty_cycle); 
     34        void (*emergency)(struct lipocharge *c); 
     35 
     36        /* internal */ 
     37        struct device *dev; 
     38        enum lipocharge_state state; 
     39        unsigned int active_duty_cycle; 
     40 
     41        //TODO implement timer to cut power after maximum charge time. 
     42}; 
     43 
     44void lipocharge_init(struct lipocharge *c, struct device *dev); 
     45void lipocharge_exit(struct lipocharge *c); 
     46 
     47int lipocharge_start(struct lipocharge *c); 
     48void lipocharge_stop(struct lipocharge *c); 
     49 
     50int lipocharge_update_state(struct lipocharge *c, 
     51                            unsigned int voltage_mV, 
     52                            int current_mA, 
     53                            unsigned int temp_K); 
     54 
     55static inline bool lipocharge_is_charging(struct lipocharge *c) 
     56{ 
     57        return (c->state != LIPO_IDLE); 
     58} 
     59 
     60#endif /* LIPOCHARGE_H_ */ 
  • drivers/cbus/cbus.c

    old new  
    3434#include <linux/gpio.h> 
    3535#include <linux/platform_device.h> 
    3636#include <plat/cbus.h> 
     37#include <linux/reboot.h> 
    3738 
    3839#include "cbus.h" 
    3940 
    static void __exit cbus_bus_exit(void) 
    324325} 
    325326module_exit(cbus_bus_exit); 
    326327 
     328void cbus_emergency(void) 
     329{ 
     330        machine_power_off(); 
     331        panic("cbus: Failed to halt machine in emergency state\n"); 
     332} 
     333EXPORT_SYMBOL(cbus_emergency); 
     334 
    327335MODULE_DESCRIPTION("CBUS serial protocol"); 
    328336MODULE_LICENSE("GPL"); 
    329337MODULE_AUTHOR("Juha Yrjölä"); 
  • drivers/cbus/cbus.h

    old new extern int cbus_read_reg(struct device * 
    2727extern int cbus_write_reg(struct device *, unsigned dev, unsigned reg, 
    2828                unsigned val); 
    2929 
     30NORET_TYPE void cbus_emergency(void) ATTRIB_NORET; 
     31 
    3032#endif /* __DRIVERS_CBUS_CBUS_H */ 
  • drivers/cbus/retu.c

    old new static int retu_allocate_children(struct 
    417417        if (!child) 
    418418                return -ENOMEM; 
    419419 
     420        child = retu_allocate_child("retu-n810bm", parent, irq_base, 
     421                        RETU_INT_ADCS, -1, 1); 
     422        if (!child) 
     423                return -ENOMEM; 
     424 
    420425        return 0; 
    421426} 
    422427 
  • drivers/cbus/tahvo.c

    old new void tahvo_set_clear_reg_bits(struct dev 
    129129        __tahvo_write_reg(tahvo, reg, w); 
    130130        mutex_unlock(&tahvo->mutex); 
    131131} 
     132EXPORT_SYMBOL(tahvo_set_clear_reg_bits); 
    132133 
    133134static irqreturn_t tahvo_irq_handler(int irq, void *_tahvo) 
    134135{ 
Note: See TracBrowser for help on using the repository browser.