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

Last change on this file since 29007 was 29007, checked in by jogo, 5 years ago

linux: update 3.1 to 3.1.1

File size: 49.1 KB
  • drivers/cbus/Kconfig

    a b 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

    a b 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 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#include <linux/interrupt.h> 
     34 
     35#include "cbus.h" 
     36#include "retu.h" 
     37#include "tahvo.h" 
     38#include "lipocharge.h" 
     39 
     40 
     41#define N810BM_PMM_BLOCK_FILENAME       "n810-cal-bme-pmm.fw" 
     42#define N810BM_PMM_BLOCK_SIZE           0x600 
     43#define N810BM_PMM_GROUP_SIZE           0x200 
     44#define N810BM_PMM_ELEM_SIZE            0x10 
     45 
     46#define N810BM_CHECK_INTERVAL           (HZ * 2) 
     47#define N810BM_MIN_VOLTAGE_THRES        3200 /* Absolute minimum voltage threshold */ 
     48 
     49 
     50/* RETU_ADC_BSI 
     51 * The battery size indicator ADC measures the resistance between 
     52 * the battery BSI pin and ground. This is used to detect the battery 
     53 * capacity, as the BSI resistor is related to capacity. 
     54 * 
     55 * Manually measured lookup table. 
     56 * Hard to measure, thus not very accurate. 
     57 * 
     58 * Resistance  |  ADC value 
     59 * ======================== 
     60 * 120k        |  0x3AC 
     61 * 110k        |  0x37C 
     62 * 100k        |  0x351 
     63 *  90k        |  0x329 
     64 */ 
     65 
     66/* RETU_ADC_BATTVOLT 
     67 * Manually measured lookup table. 
     68 * Hard to measure, thus not very accurate. 
     69 * 
     70 * Voltage  |  ADC value 
     71 * ===================== 
     72 * 2.80V    |  0x037 
     73 * 2.90V    |  0x05E 
     74 * 3.00V    |  0x090 
     75 * 3.10V    |  0x0A4 
     76 * 3.20V    |  0x0CC 
     77 * 3.30V    |  0x0EF 
     78 * 3.40V    |  0x115 
     79 * 3.50V    |  0x136 
     80 * 3.60V    |  0x15C 
     81 * 3.70V    |  0x187 
     82 * 3.80V    |  0x1A5 
     83 * 3.90V    |  0x1C9 
     84 * 4.00V    |  0x1ED 
     85 * 4.10V    |  0x212 
     86 * 4.20V    |  0x236 
     87 */ 
     88 
     89 
     90/* PMM block ADC IDs */ 
     91enum n810bm_pmm_adc_id { 
     92        N810BM_PMM_ADC_BATVOLT          = 0x01, /* Battery voltage */ 
     93        N810BM_PMM_ADC_CHGVOLT          = 0x02, /* Charger voltage */ 
     94        N810BM_PMM_ADC_GND2             = 0x03, /* Ground 0V */ 
     95        N810BM_PMM_ADC_BSI              = 0x04, /* Battery size indicator */ 
     96        N810BM_PMM_ADC_BATTEMP          = 0x05, /* Battery temperature */ 
     97        N810BM_PMM_ADC_HEADSET          = 0x06, /* Headset detection */ 
     98        N810BM_PMM_ADC_HOOKDET          = 0x07, /* Hook detection */ 
     99        N810BM_PMM_ADC_LIGHTSENS        = 0x08, /* Light sensor */ 
     100        N810BM_PMM_ADC_BATCURR          = 0x0E, /* Battery current */ 
     101        N810BM_PMM_ADC_BKUPVOLT         = 0x13, /* Backup battery voltage */ 
     102        N810BM_PMM_ADC_LIGHTTEMP        = 0x14, /* Light sensor temperature */ 
     103        N810BM_PMM_ADC_RFGP             = 0x15, /* RF GP */ 
     104        N810BM_PMM_ADC_WBTX             = 0x16, /* Wideband TX detection */ 
     105        N810BM_PMM_ADC_RETUTEMP         = 0x17, /* RETU chip temperature */ 
     106        N810BM_PMM_ADC_0xFE             = 0xFE, 
     107}; 
     108 
     109struct n810bm_adc_calib { 
     110        enum n810bm_pmm_adc_id id; 
     111        u8 flags; 
     112        u8 adc_groupnr; 
     113        u32 field1; 
     114        u32 field2; 
     115        u16 field3; 
     116        u16 field4; 
     117}; 
     118 
     119struct n810bm_calib { 
     120        struct n810bm_adc_calib adc[25]; 
     121}; 
     122 
     123enum n810bm_capacity { 
     124        N810BM_CAP_UNKNOWN      = -1, 
     125        N810BM_CAP_NONE         = 0, 
     126        N810BM_CAP_1500MAH      = 1500, /* 1500 mAh battery */ 
     127}; 
     128 
     129enum n810bm_notify_flags { 
     130        N810BM_NOTIFY_charger_present, 
     131        N810BM_NOTIFY_charger_state, 
     132        N810BM_NOTIFY_charger_pwm, 
     133}; 
     134 
     135struct n810bm { 
     136        int tahvo_irq; 
     137        bool tahvo_irq_enabled; 
     138 
     139        bool battery_present;                   /* A battery is inserted */ 
     140        bool charger_present;                   /* The charger is connected */ 
     141        enum n810bm_capacity capacity;          /* The capacity of the inserted battery (if any) */ 
     142 
     143        bool charger_enabled;                   /* Want to charge? */ 
     144        struct lipocharge charger;              /* Charger subsystem */ 
     145        unsigned int active_current_pwm;        /* Active value of TAHVO_REG_CHGCURR */ 
     146        int current_measure_enabled;            /* Current measure enable refcount */ 
     147 
     148        struct platform_device *pdev; 
     149        struct n810bm_calib calib;              /* Calibration data */ 
     150 
     151        bool verbose_charge_log;                /* Verbose charge logging */ 
     152 
     153        unsigned long notify_flags; 
     154        struct work_struct notify_work; 
     155        struct delayed_work periodic_check_work; 
     156 
     157        bool initialized;                       /* The hardware was initialized */ 
     158        struct mutex mutex; 
     159}; 
     160 
     161static void n810bm_notify_charger_present(struct n810bm *bm); 
     162static void n810bm_notify_charger_state(struct n810bm *bm); 
     163static void n810bm_notify_charger_pwm(struct n810bm *bm); 
     164 
     165 
     166static struct platform_device *n810bm_retu_device; 
     167static struct platform_device *n810bm_tahvo_device; 
     168 
     169 
     170static inline struct n810bm * device_to_n810bm(struct device *dev) 
     171{ 
     172        struct platform_device *pdev = to_platform_device(dev); 
     173        struct n810bm *bm = platform_get_drvdata(pdev); 
     174 
     175        return bm; 
     176} 
     177 
     178static inline bool n810bm_known_battery_present(struct n810bm *bm) 
     179{ 
     180        return bm->battery_present && 
     181               bm->capacity != N810BM_CAP_UNKNOWN && 
     182               bm->capacity != N810BM_CAP_NONE; 
     183} 
     184 
     185static NORET_TYPE void n810bm_emergency(struct n810bm *bm, const char *message) ATTRIB_NORET; 
     186static void n810bm_emergency(struct n810bm *bm, const char *message) 
     187{ 
     188        printk(KERN_EMERG "n810 battery management fatal fault: %s\n", message); 
     189        cbus_emergency(); 
     190} 
     191 
     192static u16 tahvo_read(struct n810bm *bm, unsigned int reg) 
     193{ 
     194        return tahvo_read_reg(&n810bm_tahvo_device->dev, reg); 
     195} 
     196 
     197static void tahvo_maskset(struct n810bm *bm, unsigned int reg, u16 mask, u16 set) 
     198{ 
     199        tahvo_set_clear_reg_bits(&n810bm_tahvo_device->dev, reg, set, mask); 
     200} 
     201 
     202static inline void tahvo_write(struct n810bm *bm, unsigned int reg, u16 value) 
     203{ 
     204        tahvo_write_reg(&n810bm_tahvo_device->dev, reg, value); 
     205} 
     206 
     207static inline void tahvo_set(struct n810bm *bm, unsigned int reg, u16 mask) 
     208{ 
     209        tahvo_set_clear_reg_bits(&n810bm_tahvo_device->dev, reg, mask, mask); 
     210} 
     211 
     212static inline void tahvo_clear(struct n810bm *bm, unsigned int reg, u16 mask) 
     213{ 
     214        tahvo_set_clear_reg_bits(&n810bm_tahvo_device->dev, reg, 0, mask); 
     215} 
     216 
     217static u16 retu_read(struct n810bm *bm, unsigned int reg) 
     218{ 
     219        return retu_read_reg(&n810bm_retu_device->dev, reg); 
     220} 
     221 
     222static void retu_maskset(struct n810bm *bm, unsigned int reg, u16 mask, u16 set) 
     223{ 
     224        retu_set_clear_reg_bits(&n810bm_retu_device->dev, reg, set, mask); 
     225} 
     226 
     227static inline void retu_write(struct n810bm *bm, unsigned int reg, u16 value) 
     228{ 
     229        retu_write_reg(&n810bm_retu_device->dev, reg, value); 
     230} 
     231 
     232static int retu_adc_average(struct n810bm *bm, unsigned int chan, 
     233                            unsigned int nr_passes) 
     234{ 
     235        unsigned int i, value = 0; 
     236        int ret; 
     237 
     238        if (WARN_ON(!nr_passes)) 
     239                return 0; 
     240        for (i = 0; i < nr_passes; i++) { 
     241                ret = retu_read_adc(&n810bm_retu_device->dev, chan); 
     242                if (ret < 0) 
     243                        return ret; 
     244                value += ret; 
     245        } 
     246        value /= nr_passes; 
     247 
     248        return value; 
     249} 
     250 
     251static struct n810bm_adc_calib * n810bm_get_adc_calib(struct n810bm *bm, 
     252                                                enum n810bm_pmm_adc_id id) 
     253{ 
     254        unsigned int index = 0; 
     255        struct n810bm_adc_calib *cal; 
     256 
     257        if (id != N810BM_PMM_ADC_0xFE) 
     258                index = (unsigned int)id + 1; 
     259        if (index >= ARRAY_SIZE(bm->calib.adc)) 
     260                return NULL; 
     261 
     262        cal = &bm->calib.adc[index]; 
     263        WARN_ON(cal->id && cal->id != id); 
     264 
     265        return cal; 
     266} 
     267 
     268static int pmm_record_get(struct n810bm *bm, 
     269                          const struct firmware *pmm_block, 
     270                          void *buffer, size_t length, 
     271                          unsigned int group, unsigned int element, unsigned int offset) 
     272{ 
     273        const u8 *pmm_area = pmm_block->data; 
     274        u8 active_group_mask; 
     275 
     276        if (pmm_block->size != N810BM_PMM_BLOCK_SIZE) 
     277                return -EINVAL; 
     278        if (group >= N810BM_PMM_BLOCK_SIZE / N810BM_PMM_GROUP_SIZE) 
     279                return -EINVAL; 
     280        if (element >= N810BM_PMM_GROUP_SIZE / N810BM_PMM_ELEM_SIZE) 
     281                return -EINVAL; 
     282        if (offset >= N810BM_PMM_ELEM_SIZE || length > N810BM_PMM_ELEM_SIZE || 
     283            length + offset > N810BM_PMM_ELEM_SIZE) 
     284                return -EINVAL; 
     285 
     286        active_group_mask = pmm_area[16]; 
     287        if (!(active_group_mask & (1 << group))) { 
     288                dev_dbg(&bm->pdev->dev, "pwm_record_get: Requested group %u, " 
     289                        "but group is not active", group); 
     290                return -ENOENT; 
     291        } 
     292 
     293        memcpy(buffer, 
     294               pmm_area + group * N810BM_PMM_GROUP_SIZE 
     295                        + element * N810BM_PMM_ELEM_SIZE 
     296                        + offset, 
     297               length); 
     298 
     299        return 0; 
     300} 
     301 
     302/* PMM block group 1 element */ 
     303struct group1_element { 
     304        u8 id; 
     305        u8 flags; 
     306        u8 adc_groupnr; 
     307        u8 _padding; 
     308        __le32 field1; 
     309        __le32 field2; 
     310} __packed; 
     311 
     312static int extract_group1_elem(struct n810bm *bm, 
     313                               const struct firmware *pmm_block, 
     314                               const enum n810bm_pmm_adc_id *pmm_adc_ids, size_t nr_pmm_adc_ids, 
     315                               u32 field1_mask, u32 field2_mask) 
     316{ 
     317        struct group1_element elem; 
     318        int err; 
     319        unsigned int i, element_nr; 
     320        struct n810bm_adc_calib *adc_calib; 
     321 
     322        for (i = 0; i < nr_pmm_adc_ids; i++) { 
     323                element_nr = (unsigned int)(pmm_adc_ids[i]) + 3; 
     324 
     325                err = pmm_record_get(bm, pmm_block, &elem, sizeof(elem), 
     326                                     1, element_nr, 0); 
     327                if (err) 
     328                        continue; 
     329                adc_calib = n810bm_get_adc_calib(bm, elem.id); 
     330                if (!adc_calib) { 
     331                        dev_err(&bm->pdev->dev, "extract_group1_elem: " 
     332                                "Could not get calib element for 0x%02X", 
     333                                elem.id); 
     334                        return -EINVAL; 
     335                } 
     336 
     337                if (adc_calib->flags == elem.flags) { 
     338                        adc_calib->field1 = le32_to_cpu(elem.field1) & field1_mask; 
     339                        adc_calib->field2 = le32_to_cpu(elem.field2) & field2_mask; 
     340                } else { 
     341                        dev_dbg(&bm->pdev->dev, "extract_group1_elem: " 
     342                                "Not extracting fields due to flags mismatch: " 
     343                                "0x%02X vs 0x%02X", 
     344                                adc_calib->flags, elem.flags); 
     345                } 
     346        } 
     347 
     348        return 0; 
     349} 
     350 
     351static int n810bm_parse_pmm_group1(struct n810bm *bm, 
     352                                   const struct firmware *pmm_block) 
     353{ 
     354        struct n810bm_adc_calib *adc_calib; 
     355        struct group1_element elem; 
     356        int err; 
     357 
     358        static const enum n810bm_pmm_adc_id pmm_adc_ids_1[] = { 
     359                N810BM_PMM_ADC_BATVOLT, 
     360                N810BM_PMM_ADC_CHGVOLT, 
     361                N810BM_PMM_ADC_BKUPVOLT, 
     362                N810BM_PMM_ADC_BATCURR, 
     363        }; 
     364        static const enum n810bm_pmm_adc_id pmm_adc_ids_2[] = { 
     365                N810BM_PMM_ADC_BSI, 
     366        }; 
     367        static const enum n810bm_pmm_adc_id pmm_adc_ids_3[] = { 
     368                N810BM_PMM_ADC_BATTEMP, 
     369        }; 
     370 
     371        /* Parse element 2 */ 
     372        err = pmm_record_get(bm, pmm_block, &elem, sizeof(elem), 
     373                             1, 2, 0); 
     374        if (err) { 
     375                dev_err(&bm->pdev->dev, 
     376                        "PMM: Failed to get group 1 / element 2"); 
     377                return err; 
     378        } 
     379        if (elem.id == N810BM_PMM_ADC_0xFE && elem.flags == 0x05) { 
     380                adc_calib = n810bm_get_adc_calib(bm, elem.id); 
     381                if (!adc_calib) { 
     382                        dev_err(&bm->pdev->dev, 
     383                                "calib extract: Failed to get 0xFE calib"); 
     384                        return -EINVAL; 
     385                } 
     386                adc_calib->id = elem.id; 
     387                adc_calib->flags = elem.flags; 
     388                adc_calib->field1 = le32_to_cpu(elem.field1); 
     389                adc_calib->field2 = le32_to_cpu(elem.field2); 
     390        } 
     391 
     392        err = extract_group1_elem(bm, pmm_block, 
     393                                  pmm_adc_ids_1, ARRAY_SIZE(pmm_adc_ids_1), 
     394                                  0xFFFFFFFF, 0xFFFFFFFF); 
     395        if (err) 
     396                return err; 
     397        err = extract_group1_elem(bm, pmm_block, 
     398                                  pmm_adc_ids_2, ARRAY_SIZE(pmm_adc_ids_2), 
     399                                  0xFFFFFFFF, 0); 
     400        if (err) 
     401                return err; 
     402        err = extract_group1_elem(bm, pmm_block, 
     403                                  pmm_adc_ids_3, ARRAY_SIZE(pmm_adc_ids_3), 
     404                                  0xFFFFFFFF, 0x0000FFFF); 
     405        if (err) 
     406                return err; 
     407 
     408        return 0; 
     409} 
     410 
     411static int n810bm_parse_pmm_group2(struct n810bm *bm, 
     412                                   const struct firmware *pmm_block) 
     413{ 
     414        dev_err(&bm->pdev->dev, "TODO: CAL BME PMM group 2 parser not implemented, yet"); 
     415        return -EOPNOTSUPP; 
     416} 
     417 
     418static void n810bm_adc_calib_set_defaults(struct n810bm *bm) 
     419{ 
     420        struct n810bm_adc_calib *adc_calib; 
     421        unsigned int i; 
     422 
     423        static const struct n810bm_adc_calib defaults[] = { 
     424                /* ADC group-nr 0 */ 
     425                { 
     426                        .id             = N810BM_PMM_ADC_HEADSET, 
     427                        .flags          = 0x00, 
     428                        .adc_groupnr    = 0, 
     429                }, { 
     430                        .id             = N810BM_PMM_ADC_HOOKDET, 
     431                        .flags          = 0x00, 
     432                        .adc_groupnr    = 0, 
     433                }, { 
     434                        .id             = N810BM_PMM_ADC_RFGP, 
     435                        .flags          = 0x00, 
     436                        .adc_groupnr    = 0, 
     437                }, { 
     438                        .id             = N810BM_PMM_ADC_LIGHTSENS, 
     439                        .flags          = 0x00, 
     440                        .adc_groupnr    = 0, 
     441                }, { 
     442                        .id             = N810BM_PMM_ADC_WBTX, 
     443                        .flags          = 0x00, 
     444                        .adc_groupnr    = 0, 
     445                }, { 
     446                        .id             = N810BM_PMM_ADC_RETUTEMP, 
     447                        .flags          = 0x00, 
     448                        .adc_groupnr    = 0, 
     449                }, { 
     450                        .id             = N810BM_PMM_ADC_GND2, 
     451                        .flags          = 0x00, 
     452                        .adc_groupnr    = 0, 
     453                }, 
     454                /* ADC group-nr 1 */ 
     455                { 
     456                        .id             = N810BM_PMM_ADC_0xFE, 
     457                        .flags          = 0x05, 
     458                        .adc_groupnr    = 1, 
     459                        .field1         = (u32)-2, 
     460                        .field2         = 13189, 
     461                }, { 
     462                        .id             = N810BM_PMM_ADC_BATVOLT, 
     463                        .flags          = 0x01, 
     464                        .adc_groupnr    = 1, 
     465                        .field1         = 2527, 
     466                        .field2         = 21373, 
     467                }, { 
     468                        .id             = N810BM_PMM_ADC_CHGVOLT, 
     469                        .flags          = 0x01, 
     470                        .adc_groupnr    = 1, 
     471                        .field1         = 0, 
     472                        .field2         = 129848, 
     473                }, { 
     474                        .id             = N810BM_PMM_ADC_BKUPVOLT, 
     475                        .flags          = 0x01, 
     476                        .adc_groupnr    = 1, 
     477                        .field1         = 0, 
     478                        .field2         = 20000, 
     479                }, { 
     480                        .id             = N810BM_PMM_ADC_BATCURR, 
     481                        .flags          = 0x06, 
     482                        .adc_groupnr    = 1, 
     483                        .field1         = 0, 
     484                        .field2         = 9660, 
     485                }, 
     486                /* ADC group-nr 2 */ 
     487                { 
     488                        .id             = N810BM_PMM_ADC_BSI, 
     489                        .flags          = 0x02, 
     490                        .adc_groupnr    = 2, 
     491                        .field1         = 1169, 
     492                        .field2         = 0, 
     493                }, 
     494                /* ADC group-nr 3 */ 
     495                { 
     496                        .id             = N810BM_PMM_ADC_BATTEMP, 
     497                        .flags          = 0x03, 
     498                        .adc_groupnr    = 3, 
     499                        .field1         = 265423000, 
     500                        .field2         = 298, 
     501                }, 
     502                /* ADC group-nr 4 */ 
     503                { 
     504                        .id             = N810BM_PMM_ADC_LIGHTTEMP, 
     505                        .flags          = 0x04, 
     506                        .adc_groupnr    = 4, 
     507                        .field1         = 19533778, 
     508                        .field2         = 308019670, 
     509                        .field3         = 4700, 
     510                        .field4         = 2500, 
     511                }, 
     512        }; 
     513 
     514        /* Clear the array */ 
     515        memset(&bm->calib.adc, 0, sizeof(bm->calib.adc)); 
     516        for (i = 0; i < ARRAY_SIZE(bm->calib.adc); i++) 
     517                bm->calib.adc[i].flags = 0xFF; 
     518 
     519        /* Copy the defaults */ 
     520        for (i = 0; i < ARRAY_SIZE(defaults); i++) { 
     521                adc_calib = n810bm_get_adc_calib(bm, defaults[i].id); 
     522                if (WARN_ON(!adc_calib)) 
     523                        continue; 
     524                *adc_calib = defaults[i]; 
     525        } 
     526} 
     527 
     528static int n810bm_parse_pmm_block(struct n810bm *bm, 
     529                                  const struct firmware *pmm_block) 
     530{ 
     531        u8 byte; 
     532        int err; 
     533        unsigned int i, count; 
     534        struct n810bm_adc_calib *adc_calib; 
     535 
     536        /* Initialize to defaults */ 
     537        n810bm_adc_calib_set_defaults(bm); 
     538 
     539        /* Parse the PMM data */ 
     540        err = pmm_record_get(bm, pmm_block, &byte, sizeof(byte), 
     541                             1, 0, 0); /* group 1 / element 0 */ 
     542        err |= (byte != 0x01); 
     543        err |= pmm_record_get(bm, pmm_block, &byte, sizeof(byte), 
     544                              1, 1, 0); /* group 1 / element 1 */ 
     545        err |= (byte != 0x01); 
     546        if (err) 
     547                err = n810bm_parse_pmm_group2(bm, pmm_block); 
     548        else 
     549                err = n810bm_parse_pmm_group1(bm, pmm_block); 
     550        if (err) 
     551                return err; 
     552 
     553        /* Sanity checks */ 
     554        for (i = 0, count = 0; i < ARRAY_SIZE(bm->calib.adc); i++) { 
     555                adc_calib = &bm->calib.adc[i]; 
     556                if (adc_calib->flags == 0xFF) 
     557                        continue; 
     558                switch (adc_calib->id) { 
     559                case N810BM_PMM_ADC_BATVOLT: 
     560                        if (adc_calib->field1 < 2400 || 
     561                            adc_calib->field1 > 2700) 
     562                                goto value_check_fail; 
     563                        if (adc_calib->field2 < 20000 || 
     564                            adc_calib->field2 > 23000) 
     565                                goto value_check_fail; 
     566                        count++; 
     567                        break; 
     568                case N810BM_PMM_ADC_BSI: 
     569                        if (adc_calib->field1 < 1100 || 
     570                            adc_calib->field1 > 1300) 
     571                                goto value_check_fail; 
     572                        count++; 
     573                        break; 
     574                case N810BM_PMM_ADC_BATCURR: 
     575                        if (adc_calib->field2 < 7000 || 
     576                            adc_calib->field2 > 12000) 
     577                                goto value_check_fail; 
     578                        count++; 
     579                        break; 
     580                case N810BM_PMM_ADC_0xFE: 
     581                        if ((s32)adc_calib->field1 > 14 || 
     582                            (s32)adc_calib->field1 < -14) 
     583                                goto value_check_fail; 
     584                        if (adc_calib->field2 < 13000 || 
     585                            adc_calib->field2 > 13350) 
     586                                goto value_check_fail; 
     587                        count++; 
     588                        break; 
     589                case N810BM_PMM_ADC_CHGVOLT: 
     590                case N810BM_PMM_ADC_BATTEMP: 
     591                case N810BM_PMM_ADC_BKUPVOLT: 
     592                        count++; 
     593                        break; 
     594                case N810BM_PMM_ADC_GND2: 
     595                case N810BM_PMM_ADC_HOOKDET: 
     596                case N810BM_PMM_ADC_LIGHTSENS: 
     597                case N810BM_PMM_ADC_HEADSET: 
     598                case N810BM_PMM_ADC_LIGHTTEMP: 
     599                case N810BM_PMM_ADC_RFGP: 
     600                case N810BM_PMM_ADC_WBTX: 
     601                case N810BM_PMM_ADC_RETUTEMP: 
     602                        break; 
     603                } 
     604                dev_dbg(&bm->pdev->dev, 
     605                        "ADC 0x%02X calib: 0x%02X 0x%02X 0x%08X 0x%08X 0x%04X 0x%04X", 
     606                        adc_calib->id, adc_calib->flags, adc_calib->adc_groupnr, 
     607                        adc_calib->field1, adc_calib->field2, 
     608                        adc_calib->field3, adc_calib->field4); 
     609        } 
     610        if (count != 7) { 
     611                dev_err(&bm->pdev->dev, "PMM sanity check: Did not find " 
     612                        "all required values (count=%u)", count); 
     613                goto check_fail; 
     614        } 
     615 
     616        return 0; 
     617 
     618value_check_fail: 
     619        dev_err(&bm->pdev->dev, "PMM image sanity check failed " 
     620                "(id=%02X, field1=%08X, field2=%08X)", 
     621                adc_calib->id, adc_calib->field1, adc_calib->field2); 
     622check_fail: 
     623        return -EILSEQ; 
     624} 
     625 
     626/* Set the current measure timer that triggers on Tahvo IRQ 7 
     627 * An interval of zero disables the timer. */ 
     628static void n810bm_set_current_measure_timer(struct n810bm *bm, 
     629                                             u16 millisec_interval) 
     630{ 
     631        u16 value = millisec_interval; 
     632 
     633        if (value <= 0xF905) { 
     634                value = ((u64)0x10624DD3 * (u64)(value + 0xF9)) >> 32; 
     635                value /= 16; 
     636        } else 
     637                value = 0xFF; 
     638 
     639        tahvo_write(bm, TAHVO_REG_BATCURRTIMER, value & 0xFF); 
     640 
     641        tahvo_set(bm, TAHVO_REG_CHGCTL, 
     642                  TAHVO_REG_CHGCTL_CURTIMRST); 
     643        tahvo_clear(bm, TAHVO_REG_CHGCTL, 
     644                    TAHVO_REG_CHGCTL_CURTIMRST); 
     645 
     646        if (millisec_interval) { 
     647                if (!bm->tahvo_irq_enabled) { 
     648                        bm->tahvo_irq_enabled = 1; 
     649                        enable_irq(bm->tahvo_irq); 
     650                } 
     651        } else { 
     652                if (bm->tahvo_irq_enabled) { 
     653                        bm->tahvo_irq_enabled = 0; 
     654                        disable_irq_nosync(bm->tahvo_irq); 
     655                } 
     656        } 
     657 
     658        //TODO also do a software timer for safety. 
     659} 
     660 
     661static void n810bm_enable_current_measure(struct n810bm *bm) 
     662{ 
     663        WARN_ON(bm->current_measure_enabled < 0); 
     664        if (!bm->current_measure_enabled) { 
     665                /* Enable the current measurement circuitry */ 
     666                tahvo_set(bm, TAHVO_REG_CHGCTL, 
     667                          TAHVO_REG_CHGCTL_CURMEAS); 
     668                dev_dbg(&bm->pdev->dev, 
     669                        "Current measurement circuitry enabled"); 
     670        } 
     671        bm->current_measure_enabled++; 
     672} 
     673 
     674static void n810bm_disable_current_measure(struct n810bm *bm) 
     675{ 
     676        bm->current_measure_enabled--; 
     677        WARN_ON(bm->current_measure_enabled < 0); 
     678        if (!bm->current_measure_enabled) { 
     679                /* Disable the current measurement circuitry */ 
     680                tahvo_clear(bm, TAHVO_REG_CHGCTL, 
     681                            TAHVO_REG_CHGCTL_CURMEAS); 
     682                dev_dbg(&bm->pdev->dev, 
     683                        "Current measurement circuitry disabled"); 
     684        } 
     685} 
     686 
     687/* Measure the actual battery current. Returns a signed value in mA. 
     688 * Does only work, if current measurement was enabled. */ 
     689static int n810bm_measure_batt_current(struct n810bm *bm) 
     690{ 
     691        u16 retval; 
     692        int adc = 0, ma, i; 
     693 
     694        if (WARN_ON(bm->current_measure_enabled <= 0)) 
     695                return 0; 
     696        for (i = 0; i < 3; i++) { 
     697                retval = tahvo_read(bm, TAHVO_REG_BATCURR); 
     698                adc += (s16)retval; /* Value is signed */ 
     699        } 
     700        adc /= 3; 
     701 
     702        //TODO convert to mA 
     703        ma = adc; 
     704 
     705        return ma; 
     706} 
     707 
     708/* Requires bm->mutex locked */ 
     709static int n810bm_measure_batt_current_async(struct n810bm *bm) 
     710{ 
     711        int ma; 
     712        bool charging = lipocharge_is_charging(&bm->charger); 
     713 
     714        n810bm_enable_current_measure(bm); 
     715        if (!charging) 
     716                WARN_ON(bm->active_current_pwm != 0); 
     717        tahvo_maskset(bm, TAHVO_REG_CHGCTL, 
     718                      TAHVO_REG_CHGCTL_EN | 
     719                      TAHVO_REG_CHGCTL_PWMOVR | 
     720                      TAHVO_REG_CHGCTL_PWMOVRZERO, 
     721                      TAHVO_REG_CHGCTL_EN | 
     722                      TAHVO_REG_CHGCTL_PWMOVR | 
     723                      (charging ? 0 : TAHVO_REG_CHGCTL_PWMOVRZERO)); 
     724        ma = n810bm_measure_batt_current(bm); 
     725        tahvo_maskset(bm, TAHVO_REG_CHGCTL, 
     726                      TAHVO_REG_CHGCTL_EN | 
     727                      TAHVO_REG_CHGCTL_PWMOVR | 
     728                      TAHVO_REG_CHGCTL_PWMOVRZERO, 
     729                      (charging ? TAHVO_REG_CHGCTL_EN : 0)); 
     730        n810bm_disable_current_measure(bm); 
     731 
     732        return ma; 
     733} 
     734 
     735static int adc_sanity_check(struct n810bm *bm, unsigned int channel) 
     736{ 
     737        int value; 
     738 
     739        value = retu_read_adc(&n810bm_retu_device->dev, channel); 
     740        if (value < 0) { 
     741                dev_err(&bm->pdev->dev, "Failed to read GND ADC channel %u", 
     742                        channel); 
     743                return -EIO; 
     744        } 
     745        dev_dbg(&bm->pdev->dev, 
     746                "GND ADC channel %u sanity check got value: %d", 
     747                channel, value); 
     748        if (value > 5) { 
     749                n810bm_emergency(bm, "GND ADC sanity check failed"); 
     750                return -EIO; 
     751        } 
     752 
     753        return 0; 
     754} 
     755 
     756static int n810bm_check_adc_sanity(struct n810bm *bm) 
     757{ 
     758        int err; 
     759 
     760        /* Discard one conversion */ 
     761        retu_write(bm, RETU_REG_ADCSCR, 0); 
     762        retu_read_adc(&n810bm_retu_device->dev, RETU_ADC_GND2); 
     763 
     764        err = adc_sanity_check(bm, RETU_ADC_GND2); 
     765        if (err) 
     766                return err; 
     767 
     768        return 0; 
     769} 
     770 
     771/* Measure the battery voltage. Returns the value in mV (or negative value on error). */ 
     772static int n810bm_measure_batt_voltage(struct n810bm *bm) 
     773{ 
     774        int adc; 
     775        unsigned int mv; 
     776        const unsigned int scale = 1000; 
     777 
     778        adc = retu_adc_average(bm, RETU_ADC_BATTVOLT, 5); 
     779        if (adc < 0) 
     780                return adc; 
     781        if (adc <= 0x37) 
     782                return 2800; 
     783        mv = 2800 + ((adc - 0x37) * (((4200 - 2800) * scale) / (0x236 - 0x37))) / scale; 
     784 
     785        //TODO compensate for power consumption 
     786        //TODO honor calibration values 
     787 
     788        return mv; 
     789} 
     790 
     791/* Measure the charger voltage. Returns the value in mV (or negative value on error). */ 
     792static int n810bm_measure_charger_voltage(struct n810bm *bm) 
     793{ 
     794        int adc; 
     795        unsigned int mv; 
     796 
     797        adc = retu_adc_average(bm, RETU_ADC_CHGVOLT, 5); 
     798        if (adc < 0) 
     799                return adc; 
     800        //TODO convert to mV 
     801        mv = adc; 
     802 
     803        return mv; 
     804} 
     805 
     806/* Measure backup battery voltage. Returns the value in mV (or negative value on error). */ 
     807static int n810bm_measure_backup_batt_voltage(struct n810bm *bm) 
     808{ 
     809        int adc; 
     810        unsigned int mv; 
     811 
     812        adc = retu_adc_average(bm, RETU_ADC_BKUPVOLT, 3); 
     813        if (adc < 0) 
     814                return adc; 
     815        //TODO convert to mV 
     816        mv = adc; 
     817 
     818        return mv; 
     819} 
     820 
     821/* Measure the battery temperature. Returns the value in K (or negative value on error). */ 
     822static int n810bm_measure_batt_temp(struct n810bm *bm) 
     823{ 
     824        int adc; 
     825        unsigned int k; 
     826 
     827        adc = retu_adc_average(bm, RETU_ADC_BATTEMP, 3); 
     828        if (adc < 0) 
     829                return adc; 
     830        //TODO convert to K 
     831        k = adc; 
     832 
     833        return k; 
     834} 
     835 
     836/* Read the battery capacity via BSI pin. */ 
     837static enum n810bm_capacity n810bm_read_batt_capacity(struct n810bm *bm) 
     838{ 
     839        int adc; 
     840        const unsigned int hyst = 20; 
     841 
     842        adc = retu_adc_average(bm, RETU_ADC_BSI, 5); 
     843        if (adc < 0) { 
     844                dev_err(&bm->pdev->dev, "Failed to read BSI ADC"); 
     845                return N810BM_CAP_UNKNOWN; 
     846        } 
     847 
     848        if (adc >= 0x3B5 - hyst && adc <= 0x3B5 + hyst) 
     849                return N810BM_CAP_1500MAH; 
     850 
     851        dev_err(&bm->pdev->dev, "Capacity indicator 0x%X unknown", adc); 
     852 
     853        return N810BM_CAP_UNKNOWN; 
     854} 
     855 
     856/* Convert a battery voltage (in mV) to percentage. */ 
     857static unsigned int n810bm_mvolt2percent(unsigned int mv) 
     858{ 
     859        const unsigned int minv = 3700; 
     860        const unsigned int maxv = 4150; 
     861        unsigned int percent; 
     862 
     863        mv = clamp(mv, minv, maxv); 
     864        percent = (mv - minv) * 100 / (maxv - minv); 
     865 
     866        return percent; 
     867} 
     868 
     869static void n810bm_start_charge(struct n810bm *bm) 
     870{ 
     871        int err; 
     872 
     873        WARN_ON(!bm->battery_present); 
     874        WARN_ON(!bm->charger_present); 
     875 
     876        /* Set PWM to zero */ 
     877        bm->active_current_pwm = 0; 
     878        tahvo_write(bm, TAHVO_REG_CHGCURR, bm->active_current_pwm); 
     879 
     880        /* Charge global enable */ 
     881        tahvo_maskset(bm, TAHVO_REG_CHGCTL, 
     882                      TAHVO_REG_CHGCTL_EN | 
     883                      TAHVO_REG_CHGCTL_PWMOVR | 
     884                      TAHVO_REG_CHGCTL_PWMOVRZERO, 
     885                      TAHVO_REG_CHGCTL_EN); 
     886 
     887        WARN_ON((int)bm->capacity <= 0); 
     888        bm->charger.capacity = bm->capacity; 
     889        err = lipocharge_start(&bm->charger); 
     890        WARN_ON(err); 
     891 
     892        /* Initialize current measurement circuitry */ 
     893        n810bm_enable_current_measure(bm); 
     894        n810bm_set_current_measure_timer(bm, 250); 
     895 
     896        dev_info(&bm->pdev->dev, "Charging battery"); 
     897        n810bm_notify_charger_state(bm); 
     898        n810bm_notify_charger_pwm(bm); 
     899} 
     900 
     901static void n810bm_stop_charge(struct n810bm *bm) 
     902{ 
     903        if (lipocharge_is_charging(&bm->charger)) { 
     904                n810bm_set_current_measure_timer(bm, 0); 
     905                n810bm_disable_current_measure(bm); 
     906        } 
     907        lipocharge_stop(&bm->charger); 
     908 
     909        /* Set PWM to zero */ 
     910        bm->active_current_pwm = 0; 
     911        tahvo_write(bm, TAHVO_REG_CHGCURR, bm->active_current_pwm); 
     912 
     913        /* Charge global disable */ 
     914        tahvo_maskset(bm, TAHVO_REG_CHGCTL, 
     915                      TAHVO_REG_CHGCTL_EN | 
     916                      TAHVO_REG_CHGCTL_PWMOVR | 
     917                      TAHVO_REG_CHGCTL_PWMOVRZERO, 
     918                      0); 
     919 
     920        dev_info(&bm->pdev->dev, "Not charging battery"); 
     921        n810bm_notify_charger_state(bm); 
     922        n810bm_notify_charger_pwm(bm); 
     923} 
     924 
     925/* Periodic check */ 
     926static void n810bm_periodic_check_work(struct work_struct *work) 
     927{ 
     928        struct n810bm *bm = container_of(to_delayed_work(work), 
     929                                         struct n810bm, periodic_check_work); 
     930        u16 status; 
     931        bool battery_was_present, charger_was_present; 
     932        int mv; 
     933 
     934        mutex_lock(&bm->mutex); 
     935 
     936        status = retu_read(bm, RETU_REG_STATUS); 
     937        battery_was_present = bm->battery_present; 
     938        charger_was_present = bm->charger_present; 
     939        bm->battery_present = !!(status & RETU_REG_STATUS_BATAVAIL); 
     940        bm->charger_present = !!(status & RETU_REG_STATUS_CHGPLUG); 
     941 
     942        if (bm->battery_present != battery_was_present) { 
     943                /* Battery state changed */ 
     944                if (bm->battery_present) { 
     945                        bm->capacity = n810bm_read_batt_capacity(bm); 
     946                        if (bm->capacity == N810BM_CAP_UNKNOWN) { 
     947                                dev_err(&bm->pdev->dev, "Unknown battery detected"); 
     948                        } else { 
     949                                dev_info(&bm->pdev->dev, "Detected %u mAh battery", 
     950                                         (unsigned int)bm->capacity); 
     951                        } 
     952                } else { 
     953                        bm->capacity = N810BM_CAP_NONE; 
     954                        dev_info(&bm->pdev->dev, "The main battery was removed"); 
     955                        //TODO disable charging 
     956                } 
     957        } 
     958 
     959        if (bm->charger_present != charger_was_present) { 
     960                /* Charger state changed */ 
     961                dev_info(&bm->pdev->dev, "The charger was %s", 
     962                         bm->charger_present ? "plugged in" : "removed"); 
     963                n810bm_notify_charger_present(bm); 
     964        } 
     965 
     966        if ((bm->battery_present && !bm->charger_present) || 
     967            !n810bm_known_battery_present(bm)){ 
     968                /* We're draining the battery */ 
     969                mv = n810bm_measure_batt_voltage(bm); 
     970                if (mv < 0) { 
     971                        n810bm_emergency(bm, 
     972                                "check: Failed to measure voltage"); 
     973                } 
     974                if (mv < N810BM_MIN_VOLTAGE_THRES) { 
     975                        n810bm_emergency(bm, 
     976                                "check: Minimum voltage threshold reached"); 
     977                } 
     978        } 
     979 
     980        if (bm->charger_present && n810bm_known_battery_present(bm)) { 
     981                /* Known battery and charger are connected */ 
     982                if (bm->charger_enabled) { 
     983                        /* Charger is enabled */ 
     984                        if (!lipocharge_is_charging(&bm->charger)) { 
     985                                //TODO start charging, if battery is below some threshold 
     986                                n810bm_start_charge(bm); 
     987                        } 
     988                } 
     989        } 
     990 
     991        if (lipocharge_is_charging(&bm->charger) && !bm->charger_present) { 
     992                /* Charger was unplugged. */ 
     993                n810bm_stop_charge(bm); 
     994        } 
     995 
     996        mutex_unlock(&bm->mutex); 
     997        schedule_delayed_work(&bm->periodic_check_work, 
     998                              round_jiffies_relative(N810BM_CHECK_INTERVAL)); 
     999} 
     1000 
     1001/*XXX 
     1002static void n810bm_adc_irq_handler(unsigned long data) 
     1003{ 
     1004        struct n810bm *bm = (struct n810bm *)data; 
     1005 
     1006        retu_ack_irq(RETU_INT_ADCS); 
     1007        //TODO 
     1008dev_info(&bm->pdev->dev, "ADC interrupt triggered\n"); 
     1009} 
     1010*/ 
     1011 
     1012static irqreturn_t n810bm_tahvo_current_measure_irq_handler(int irq, void *data) 
     1013{ 
     1014        struct n810bm *bm = data; 
     1015        int res, ma, mv, temp; 
     1016 
     1017        mutex_lock(&bm->mutex); 
     1018        if (!lipocharge_is_charging(&bm->charger)) 
     1019                goto out_unlock; 
     1020 
     1021        tahvo_maskset(bm, TAHVO_REG_CHGCTL, 
     1022                      TAHVO_REG_CHGCTL_PWMOVR | 
     1023                      TAHVO_REG_CHGCTL_PWMOVRZERO, 
     1024                      TAHVO_REG_CHGCTL_PWMOVR); 
     1025        ma = n810bm_measure_batt_current(bm); 
     1026        tahvo_maskset(bm, TAHVO_REG_CHGCTL, 
     1027                      TAHVO_REG_CHGCTL_PWMOVR | 
     1028                      TAHVO_REG_CHGCTL_PWMOVRZERO, 
     1029                      TAHVO_REG_CHGCTL_PWMOVR | 
     1030                      TAHVO_REG_CHGCTL_PWMOVRZERO); 
     1031        msleep(10); 
     1032        mv = n810bm_measure_batt_voltage(bm); 
     1033        tahvo_maskset(bm, TAHVO_REG_CHGCTL, 
     1034                      TAHVO_REG_CHGCTL_PWMOVR | 
     1035                      TAHVO_REG_CHGCTL_PWMOVRZERO, 
     1036                      0); 
     1037        temp = n810bm_measure_batt_temp(bm); 
     1038        if (WARN_ON(mv < 0)) 
     1039                goto out_unlock; 
     1040        if (WARN_ON(temp < 0)) 
     1041                goto out_unlock; 
     1042 
     1043        if (bm->verbose_charge_log) { 
     1044                dev_info(&bm->pdev->dev, 
     1045                         "Battery charge state: %d mV, %d mA (%s)", 
     1046                         mv, ma, 
     1047                         (ma <= 0) ? "discharging" : "charging"); 
     1048        } 
     1049        res = lipocharge_update_state(&bm->charger, mv, ma, temp); 
     1050        if (res) { 
     1051                if (res > 0) 
     1052                        dev_info(&bm->pdev->dev, "Battery fully charged"); 
     1053                n810bm_stop_charge(bm); 
     1054        } 
     1055out_unlock: 
     1056        mutex_unlock(&bm->mutex); 
     1057 
     1058        return IRQ_HANDLED; 
     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        flush_scheduled_work(); 
     1337} 
     1338 
     1339static int n810bm_device_init(struct n810bm *bm) 
     1340{ 
     1341        int attr_index; 
     1342        int err; 
     1343 
     1344        bm->charger.rate = LIPORATE_p6C; 
     1345        bm->charger.top_voltage = 4100; 
     1346        bm->charger.duty_cycle_max = 0xFF; 
     1347        bm->charger.set_current_pwm = n810bm_charger_set_current_pwm; 
     1348        bm->charger.emergency = n810bm_charger_emergency; 
     1349        lipocharge_init(&bm->charger, &bm->pdev->dev); 
     1350 
     1351        err = n810bm_hw_init(bm); 
     1352        if (err) 
     1353                goto error; 
     1354        for (attr_index = 0; attr_index < ARRAY_SIZE(n810bm_attrs); attr_index++) { 
     1355                err = device_create_file(&bm->pdev->dev, n810bm_attrs[attr_index]); 
     1356                if (err) 
     1357                        goto err_unwind_attrs; 
     1358        } 
     1359/*XXX 
     1360        err = retu_request_irq(RETU_INT_ADCS, 
     1361                               n810bm_adc_irq_handler, 
     1362                               (unsigned long)bm, "n810bm"); 
     1363        if (err) 
     1364                goto err_unwind_attrs; 
     1365*/ 
     1366        bm->tahvo_irq = platform_get_irq(n810bm_tahvo_device, 0); 
     1367        err = request_threaded_irq(bm->tahvo_irq, NULL, 
     1368                                   n810bm_tahvo_current_measure_irq_handler, 
     1369                                   IRQF_ONESHOT, "tahvo-n810bm", bm); 
     1370        if (err) 
     1371                goto err_free_retu_irq; 
     1372        disable_irq_nosync(bm->tahvo_irq); 
     1373        bm->tahvo_irq_enabled = 0; 
     1374 
     1375        schedule_delayed_work(&bm->periodic_check_work, 
     1376                              round_jiffies_relative(N810BM_CHECK_INTERVAL)); 
     1377 
     1378        bm->initialized = 1; 
     1379        dev_info(&bm->pdev->dev, "Battery management initialized"); 
     1380 
     1381        return 0; 
     1382 
     1383err_free_retu_irq: 
     1384//XXX   retu_free_irq(RETU_INT_ADCS); 
     1385err_unwind_attrs: 
     1386        for (attr_index--; attr_index >= 0; attr_index--) 
     1387                device_remove_file(&bm->pdev->dev, n810bm_attrs[attr_index]); 
     1388/*err_exit:*/ 
     1389        n810bm_hw_exit(bm); 
     1390error: 
     1391        n810bm_cancel_and_flush_work(bm); 
     1392 
     1393        return err; 
     1394} 
     1395 
     1396static void n810bm_device_exit(struct n810bm *bm) 
     1397{ 
     1398        int i; 
     1399 
     1400        if (!bm->initialized) 
     1401                return; 
     1402 
     1403        lipocharge_exit(&bm->charger); 
     1404        free_irq(bm->tahvo_irq, bm); 
     1405//XXX   retu_free_irq(RETU_INT_ADCS); 
     1406        for (i = 0; i < ARRAY_SIZE(n810bm_attrs); i++) 
     1407                device_remove_file(&bm->pdev->dev, n810bm_attrs[i]); 
     1408 
     1409        n810bm_cancel_and_flush_work(bm); 
     1410 
     1411        n810bm_hw_exit(bm); 
     1412 
     1413        bm->initialized = 0; 
     1414} 
     1415 
     1416static void n810bm_pmm_block_found(const struct firmware *fw, void *context) 
     1417{ 
     1418        struct n810bm *bm = context; 
     1419        int err; 
     1420 
     1421        if (!fw) { 
     1422                dev_err(&bm->pdev->dev, 
     1423                        "CAL PMM block image file not found"); 
     1424                goto err_release; 
     1425        } 
     1426        if (fw->size != N810BM_PMM_BLOCK_SIZE || 
     1427            memcmp(fw->data, "BME-PMM-BLOCK01", 15) != 0) { 
     1428                dev_err(&bm->pdev->dev, 
     1429                        "CAL PMM block image file has an invalid format"); 
     1430                goto err_release; 
     1431        } 
     1432 
     1433        err = n810bm_parse_pmm_block(bm, fw); 
     1434        if (err) 
     1435                goto err_release; 
     1436        release_firmware(fw); 
     1437 
     1438        err = n810bm_device_init(bm); 
     1439        if (err) { 
     1440                dev_err(&bm->pdev->dev, 
     1441                        "Failed to initialized battery management (%d)", err); 
     1442                goto error; 
     1443        } 
     1444 
     1445        return; 
     1446err_release: 
     1447        release_firmware(fw); 
     1448error: 
     1449        return; 
     1450} 
     1451 
     1452static int __devinit n810bm_probe(void) 
     1453{ 
     1454        struct n810bm *bm; 
     1455        int err; 
     1456 
     1457        if (!n810bm_retu_device || !n810bm_tahvo_device) 
     1458                return 0; 
     1459 
     1460        bm = kzalloc(sizeof(*bm), GFP_KERNEL); 
     1461        if (!bm) 
     1462                return -ENOMEM; 
     1463        bm->pdev = n810bm_retu_device; 
     1464        platform_set_drvdata(n810bm_retu_device, bm); 
     1465        platform_set_drvdata(n810bm_tahvo_device, bm); 
     1466        mutex_init(&bm->mutex); 
     1467        INIT_DELAYED_WORK(&bm->periodic_check_work, n810bm_periodic_check_work); 
     1468        INIT_WORK(&bm->notify_work, n810bm_notify_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 
     1545static int __init n810bm_modinit(void) 
     1546{ 
     1547        int err; 
     1548 
     1549        err = platform_driver_probe(&n810bm_retu_driver, n810bm_retu_probe); 
     1550        if (err) 
     1551                return err; 
     1552        err = platform_driver_probe(&n810bm_tahvo_driver, n810bm_tahvo_probe); 
     1553        if (err) { 
     1554                platform_driver_unregister(&n810bm_retu_driver); 
     1555                return err; 
     1556        } 
     1557 
     1558        return 0; 
     1559} 
     1560module_init(n810bm_modinit); 
     1561 
     1562static void __exit n810bm_modexit(void) 
     1563{ 
     1564        platform_driver_unregister(&n810bm_tahvo_driver); 
     1565        platform_driver_unregister(&n810bm_retu_driver); 
     1566} 
     1567module_exit(n810bm_modexit); 
     1568 
     1569MODULE_DESCRIPTION("Nokia n810 battery management"); 
     1570MODULE_FIRMWARE(N810BM_PMM_BLOCK_FILENAME); 
     1571MODULE_LICENSE("GPL"); 
     1572MODULE_AUTHOR("Michael Buesch"); 
  • new file 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 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

    a b  
    3434#include <linux/gpio.h> 
    3535#include <linux/platform_device.h> 
    3636#include <linux/platform_data/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

    a b 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

    a b 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

    a b void tahvo_set_clear_reg_bits(struct dev 
    131131        __tahvo_write_reg(tahvo, reg, w); 
    132132        mutex_unlock(&tahvo->mutex); 
    133133} 
     134EXPORT_SYMBOL(tahvo_set_clear_reg_bits); 
    134135 
    135136static irqreturn_t tahvo_irq_handler(int irq, void *_tahvo) 
    136137{ 
    static int tahvo_allocate_children(struc 
    307308        if (!child) 
    308309                return -ENOMEM; 
    309310 
     311        child = tahvo_allocate_child("tahvo-n810bm", parent, 
     312                                     irq_base + TAHVO_INT_BATCURR); 
     313        if (!child) 
     314                return -ENOMEM; 
     315 
    310316        return 0; 
    311317} 
    312318 
Note: See TracBrowser for help on using the repository browser.