Changeset 25429


Ignore:
Timestamp:
2011-02-09T13:53:37+01:00 (7 years ago)
Author:
mb
Message:

n810bm: Add charger detection

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/target/linux/omap24xx/patches-2.6.37/900-n810-battery-management.patch

    r25380 r25429  
    1313Index: linux-2.6.37/drivers/cbus/Kconfig 
    1414=================================================================== 
    15 --- linux-2.6.37.orig/drivers/cbus/Kconfig      2011-02-06 00:24:48.502005279 +0100 
    16 +++ linux-2.6.37/drivers/cbus/Kconfig   2011-02-06 00:24:48.550008091 +0100 
     15--- linux-2.6.37.orig/drivers/cbus/Kconfig      2011-02-06 14:05:49.838388760 +0100 
     16+++ linux-2.6.37/drivers/cbus/Kconfig   2011-02-06 14:05:49.885395646 +0100 
    1717@@ -94,4 +94,12 @@ 
    1818          to Retu/Vilma. Detection state and events are exposed through 
     
    3030Index: linux-2.6.37/drivers/cbus/Makefile 
    3131=================================================================== 
    32 --- linux-2.6.37.orig/drivers/cbus/Makefile     2011-02-06 00:24:48.493004751 +0100 
    33 +++ linux-2.6.37/drivers/cbus/Makefile  2011-02-06 00:24:48.550008091 +0100 
     32--- linux-2.6.37.orig/drivers/cbus/Makefile     2011-02-06 14:05:49.829387442 +0100 
     33+++ linux-2.6.37/drivers/cbus/Makefile  2011-02-06 14:05:49.885395646 +0100 
    3434@@ -12,3 +12,6 @@ 
    3535 obj-$(CONFIG_CBUS_TAHVO_USER)  += tahvo-user.o 
     
    4242=================================================================== 
    4343--- /dev/null   1970-01-01 00:00:00.000000000 +0000 
    44 +++ linux-2.6.37/drivers/cbus/n810bm_main.c     2011-02-06 13:36:49.581078785 +0100 
    45 @@ -0,0 +1,959 @@ 
     44+++ linux-2.6.37/drivers/cbus/n810bm_main.c     2011-02-09 13:47:23.831144291 +0100 
     45@@ -0,0 +1,1169 @@ 
    4646+/* 
    4747+ *   Nokia n810 battery management 
     
    7070+#include <linux/platform_device.h> 
    7171+#include <linux/slab.h> 
    72 +#include <linux/spinlock.h> 
     72+#include <linux/mutex.h> 
    7373+#include <linux/timer.h> 
    74 +#include <linux/reboot.h> 
    7574+#include <linux/firmware.h> 
    76 + 
     75+#include <linux/bitops.h> 
     76+#include <linux/workqueue.h> 
     77+#include <linux/delay.h> 
     78+ 
     79+#include "cbus.h" 
    7780+#include "retu.h" 
    7881+#include "tahvo.h" 
     
    133136+}; 
    134137+ 
     138+enum n810bm_notify_flags { 
     139+       N810BM_NOTIFY_battery_charging, 
     140+       N810BM_NOTIFY_charger_pwm, 
     141+}; 
     142+ 
    135143+struct n810bm { 
    136144+       bool battery_present;                   /* A battery is inserted */ 
     
    138146+       enum n810bm_capacity capacity;          /* The capacity of the inserted battery (if any) */ 
    139147+ 
    140 +       bool charger_enabled;                   /* Want to charge? */ //TODO 
     148+       bool charger_enabled;                   /* Want to charge? */ 
    141149+       struct lipocharge charger;              /* Charger subsystem */ 
     150+       unsigned int active_current_pwm;        /* Active value of TAHVO_REG_CHGCURR */ 
     151+       int current_measure_enabled;            /* Current measure enable refcount */ 
    142152+ 
    143153+       struct platform_device *pdev; 
    144154+       const struct firmware *pmm_block;       /* CAL PMM block */ 
    145155+ 
    146 +       struct timer_list check_timer; 
     156+       bool verbose_charge_log;                /* Verbose charge logging */ 
     157+ 
     158+       unsigned long notify_flags; 
     159+       struct work_struct notify_work; 
     160+       struct work_struct currmeas_irq_work; 
     161+       struct delayed_work periodic_check_work; 
    147162+ 
    148163+       bool initialized;                       /* The hardware was initialized */ 
    149 +       spinlock_t lock; 
     164+       struct mutex mutex; 
    150165+}; 
     166+ 
     167+static void n810bm_notify_battery_charging(struct n810bm *bm); 
     168+static void n810bm_notify_charger_pwm(struct n810bm *bm); 
    151169+ 
    152170+ 
     
    159177+} 
    160178+ 
     179+static inline bool n810bm_known_battery_present(struct n810bm *bm) 
     180+{ 
     181+       return bm->battery_present && 
     182+              bm->capacity != N810BM_CAP_UNKNOWN && 
     183+              bm->capacity != N810BM_CAP_NONE; 
     184+} 
     185+ 
    161186+static NORET_TYPE void n810bm_emergency(struct n810bm *bm, const char *message) ATTRIB_NORET; 
    162187+static void n810bm_emergency(struct n810bm *bm, const char *message) 
    163188+{ 
    164189+       printk(KERN_EMERG "n810 battery management fatal fault: %s\n", message); 
    165 +       /* Force a hard shutdown. */ 
    166 +       machine_power_off(); 
    167 +       panic("n810bm: Failed to halt machine in emergency state\n"); 
     190+       cbus_emergency(); 
    168191+} 
    169192+ 
     
    291314+} 
    292315+ 
    293 +/* Set the current measure timer that triggers on Tahvo IRQ 7 */ 
     316+/* Set the current measure timer that triggers on Tahvo IRQ 7 
     317+ * An interval of zero disables the timer. */ 
    294318+static void n810bm_set_current_measure_timer(struct n810bm *bm, 
    295319+                                            u16 millisec_interval) 
     
    309333+       tahvo_clear(bm, TAHVO_REG_CHGCTL, 
    310334+                   TAHVO_REG_CHGCTL_CURTIMRST); 
    311 +} 
    312 + 
    313 +static void n810bm_enable_current_measure(struct n810bm *bm, bool slow, bool irq) 
    314 +{ 
    315 +       u16 millisec_interval; 
    316 + 
    317 +       if (slow) 
    318 +               millisec_interval = 1000; 
     335+ 
     336+       if (millisec_interval) 
     337+               tahvo_enable_irq(TAHVO_INT_BATCURR); 
    319338+       else 
    320 +               millisec_interval = 250; 
    321 + 
    322 +       /* Enable the current measurement circuitry */ 
    323 +       tahvo_set(bm, TAHVO_REG_CHGCTL, 
    324 +                 TAHVO_REG_CHGCTL_CURMEAS); 
    325 + 
    326 +       /* Setup the measurement timer */ 
    327 +       n810bm_set_current_measure_timer(bm, millisec_interval); 
    328 +       if (irq) 
    329 +               tahvo_enable_irq(TAHVO_INT_BATCURR); 
     339+               tahvo_disable_irq(TAHVO_INT_BATCURR); 
    330340+ 
    331341+       //TODO also do a software timer for safety. 
    332342+} 
    333343+ 
     344+static void n810bm_enable_current_measure(struct n810bm *bm) 
     345+{ 
     346+       WARN_ON(bm->current_measure_enabled < 0); 
     347+       if (!bm->current_measure_enabled) { 
     348+               /* Enable the current measurement circuitry */ 
     349+               tahvo_set(bm, TAHVO_REG_CHGCTL, 
     350+                         TAHVO_REG_CHGCTL_CURMEAS); 
     351+               dev_dbg(&bm->pdev->dev, 
     352+                       "Current measurement circuitry enabled"); 
     353+       } 
     354+       bm->current_measure_enabled++; 
     355+} 
     356+ 
    334357+static void n810bm_disable_current_measure(struct n810bm *bm) 
    335358+{ 
    336 +       /* Disable the measurement timer */ 
    337 +       n810bm_set_current_measure_timer(bm, 0); 
    338 +       tahvo_disable_irq(TAHVO_INT_BATCURR); 
    339 + 
    340 +       /* Disable the current measurement circuitry */ 
    341 +       tahvo_clear(bm, TAHVO_REG_CHGCTL, 
    342 +                   TAHVO_REG_CHGCTL_CURMEAS); 
     359+       bm->current_measure_enabled--; 
     360+       WARN_ON(bm->current_measure_enabled < 0); 
     361+       if (!bm->current_measure_enabled) { 
     362+               /* Disable the current measurement circuitry */ 
     363+               tahvo_clear(bm, TAHVO_REG_CHGCTL, 
     364+                           TAHVO_REG_CHGCTL_CURMEAS); 
     365+               dev_dbg(&bm->pdev->dev, 
     366+                       "Current measurement circuitry disabled"); 
     367+       } 
    343368+} 
    344369+ 
     
    350375+       int adc = 0, ma, i; 
    351376+ 
     377+       if (WARN_ON(bm->current_measure_enabled <= 0)) 
     378+               return 0; 
    352379+       for (i = 0; i < 3; i++) { 
    353380+               retval = tahvo_read(bm, TAHVO_REG_BATCURR); 
     
    358385+       //TODO convert to mA 
    359386+       ma = adc; 
     387+ 
     388+       return ma; 
     389+} 
     390+ 
     391+/* Requires bm->mutex locked */ 
     392+static int n810bm_measure_batt_current_async(struct n810bm *bm) 
     393+{ 
     394+       int ma; 
     395+       bool charging = lipocharge_is_charging(&bm->charger); 
     396+ 
     397+       n810bm_enable_current_measure(bm); 
     398+       if (!charging) 
     399+               WARN_ON(bm->active_current_pwm != 0); 
     400+       tahvo_maskset(bm, TAHVO_REG_CHGCTL, 
     401+                     TAHVO_REG_CHGCTL_EN | 
     402+                     TAHVO_REG_CHGCTL_PWMOVR | 
     403+                     TAHVO_REG_CHGCTL_PWMOVRZERO, 
     404+                     TAHVO_REG_CHGCTL_EN | 
     405+                     TAHVO_REG_CHGCTL_PWMOVR | 
     406+                     (charging ? 0 : TAHVO_REG_CHGCTL_PWMOVRZERO)); 
     407+       ma = n810bm_measure_batt_current(bm); 
     408+       tahvo_maskset(bm, TAHVO_REG_CHGCTL, 
     409+                     TAHVO_REG_CHGCTL_EN | 
     410+                     TAHVO_REG_CHGCTL_PWMOVR | 
     411+                     TAHVO_REG_CHGCTL_PWMOVRZERO, 
     412+                     (charging ? TAHVO_REG_CHGCTL_EN : 0)); 
     413+       n810bm_disable_current_measure(bm); 
    360414+ 
    361415+       return ma; 
     
    412466+       mv = 2800 + ((adc - 0x37) * (((4200 - 2800) * scale) / (0x236 - 0x37))) / scale; 
    413467+ 
     468+       //TODO compensate for power consumption 
     469+       //TODO honor calibration values 
     470+ 
    414471+       return mv; 
    415472+} 
     
    493550+} 
    494551+ 
     552+static void n810bm_start_charge(struct n810bm *bm) 
     553+{ 
     554+       int err; 
     555+ 
     556+       WARN_ON(!bm->battery_present); 
     557+       WARN_ON(!bm->charger_present); 
     558+ 
     559+       /* Set PWM to zero */ 
     560+       bm->active_current_pwm = 0; 
     561+       tahvo_write(bm, TAHVO_REG_CHGCURR, bm->active_current_pwm); 
     562+ 
     563+       /* Charge global enable */ 
     564+       tahvo_maskset(bm, TAHVO_REG_CHGCTL, 
     565+                     TAHVO_REG_CHGCTL_EN | 
     566+                     TAHVO_REG_CHGCTL_PWMOVR | 
     567+                     TAHVO_REG_CHGCTL_PWMOVRZERO, 
     568+                     TAHVO_REG_CHGCTL_EN); 
     569+ 
     570+       WARN_ON((int)bm->capacity <= 0); 
     571+       bm->charger.capacity = bm->capacity; 
     572+       err = lipocharge_start(&bm->charger); 
     573+       WARN_ON(err); 
     574+ 
     575+       /* Initialize current measurement circuitry */ 
     576+       n810bm_enable_current_measure(bm); 
     577+       n810bm_set_current_measure_timer(bm, 250); 
     578+ 
     579+       dev_info(&bm->pdev->dev, "Charging battery"); 
     580+       n810bm_notify_charger_pwm(bm); 
     581+       n810bm_notify_battery_charging(bm); 
     582+} 
     583+ 
     584+static void n810bm_stop_charge(struct n810bm *bm) 
     585+{ 
     586+       if (lipocharge_is_charging(&bm->charger)) { 
     587+               n810bm_set_current_measure_timer(bm, 0); 
     588+               n810bm_disable_current_measure(bm); 
     589+       } 
     590+       lipocharge_stop(&bm->charger); 
     591+ 
     592+       /* Set PWM to zero */ 
     593+       bm->active_current_pwm = 0; 
     594+       tahvo_write(bm, TAHVO_REG_CHGCURR, bm->active_current_pwm); 
     595+ 
     596+       /* Charge global disable */ 
     597+       tahvo_maskset(bm, TAHVO_REG_CHGCTL, 
     598+                     TAHVO_REG_CHGCTL_EN | 
     599+                     TAHVO_REG_CHGCTL_PWMOVR | 
     600+                     TAHVO_REG_CHGCTL_PWMOVRZERO, 
     601+                     0); 
     602+ 
     603+       dev_info(&bm->pdev->dev, "Not charging battery"); 
     604+       n810bm_notify_charger_pwm(bm); 
     605+       n810bm_notify_battery_charging(bm); 
     606+} 
     607+ 
    495608+/* Periodic check */ 
    496 +static void n810bm_check_timer(unsigned long data) 
    497 +{ 
    498 +       struct n810bm *bm = (struct n810bm *)data; 
    499 +       unsigned long flags; 
     609+static void n810bm_periodic_check_work(struct work_struct *work) 
     610+{ 
     611+       struct n810bm *bm = container_of(to_delayed_work(work), 
     612+                                        struct n810bm, periodic_check_work); 
    500613+       u16 status; 
    501614+       bool battery_was_present, charger_was_present; 
     
    503616+       int mv; 
    504617+ 
    505 +       spin_lock_irqsave(&bm->lock, flags); 
     618+       mutex_lock(&bm->mutex); 
    506619+ 
    507620+       status = retu_read(bm, RETU_REG_STATUS); 
     
    524637+                       bm->capacity = N810BM_CAP_NONE; 
    525638+                       dev_info(&bm->pdev->dev, "The main battery was removed"); 
    526 +                       //TODO what do if charging? 
     639+                       //TODO disable charging 
    527640+               } 
    528641+       } 
     
    535648+ 
    536649+       if (bm->battery_present && !lipocharge_is_charging(&bm->charger)) { 
     650+               /* We're draining the battery */ 
    537651+               mv = n810bm_measure_batt_voltage(bm); 
    538652+               if (mv < 0) 
     
    547661+       } 
    548662+ 
    549 +       if (bm->charger_present && bm->battery_present) { 
     663+       if (bm->charger_present && n810bm_known_battery_present(bm)) { 
     664+               /* Known battery and charger are connected */ 
    550665+               if (bm->charger_enabled || force_charge) { 
     666+                       /* Charger is enabled */ 
    551667+                       if (!lipocharge_is_charging(&bm->charger)) { 
    552668+                               //TODO start charging, if battery is below some threshold 
     669+                               n810bm_start_charge(bm); 
    553670+                       } 
    554671+               } 
    555672+       } 
    556673+ 
    557 +       mod_timer(&bm->check_timer, round_jiffies(jiffies + N810BM_CHECK_INTERVAL)); 
    558 +       spin_unlock_irqrestore(&bm->lock, flags); 
    559 + 
    560 +       return; 
     674+       if (lipocharge_is_charging(&bm->charger) && !bm->charger_present) { 
     675+               /* Charger was unplugged. */ 
     676+               n810bm_stop_charge(bm); 
     677+       } 
     678+ 
     679+       mutex_unlock(&bm->mutex); 
     680+       schedule_delayed_work(&bm->periodic_check_work, 
     681+                             round_jiffies_relative(N810BM_CHECK_INTERVAL)); 
    561682+} 
    562683+ 
     
    567688+       retu_ack_irq(RETU_INT_ADCS); 
    568689+       //TODO 
    569 +dev_dbg(&bm->pdev->dev, "ADC interrupt triggered\n"); 
     690+dev_info(&bm->pdev->dev, "ADC interrupt triggered\n"); 
     691+} 
     692+ 
     693+static void n810bm_tahvo_current_measure_work(struct work_struct *work) 
     694+{ 
     695+       struct n810bm *bm = container_of(work, struct n810bm, currmeas_irq_work); 
     696+       int res, ma, mv, temp; 
     697+ 
     698+       mutex_lock(&bm->mutex); 
     699+       if (!lipocharge_is_charging(&bm->charger)) 
     700+               goto out_unlock; 
     701+ 
     702+       tahvo_maskset(bm, TAHVO_REG_CHGCTL, 
     703+                     TAHVO_REG_CHGCTL_PWMOVR | 
     704+                     TAHVO_REG_CHGCTL_PWMOVRZERO, 
     705+                     TAHVO_REG_CHGCTL_PWMOVR); 
     706+       ma = n810bm_measure_batt_current(bm); 
     707+       tahvo_maskset(bm, TAHVO_REG_CHGCTL, 
     708+                     TAHVO_REG_CHGCTL_PWMOVR | 
     709+                     TAHVO_REG_CHGCTL_PWMOVRZERO, 
     710+                     TAHVO_REG_CHGCTL_PWMOVR | 
     711+                     TAHVO_REG_CHGCTL_PWMOVRZERO); 
     712+       msleep(10); 
     713+       mv = n810bm_measure_batt_voltage(bm); 
     714+       tahvo_maskset(bm, TAHVO_REG_CHGCTL, 
     715+                     TAHVO_REG_CHGCTL_PWMOVR | 
     716+                     TAHVO_REG_CHGCTL_PWMOVRZERO, 
     717+                     0); 
     718+       temp = n810bm_measure_batt_temp(bm); 
     719+       if (WARN_ON(mv < 0)) 
     720+               goto out_unlock; 
     721+       if (WARN_ON(temp < 0)) 
     722+               goto out_unlock; 
     723+ 
     724+       if (bm->verbose_charge_log) { 
     725+               dev_info(&bm->pdev->dev, 
     726+                        "Battery charge state: %d mV, %d mA (%s)", 
     727+                        mv, ma, 
     728+                        (ma <= 0) ? "discharging" : "charging"); 
     729+       } 
     730+       res = lipocharge_update_state(&bm->charger, mv, ma, temp); 
     731+       if (res) { 
     732+               if (res > 0) 
     733+                       dev_info(&bm->pdev->dev, "Battery fully charged"); 
     734+               n810bm_stop_charge(bm); 
     735+       } 
     736+out_unlock: 
     737+       mutex_unlock(&bm->mutex); 
    570738+} 
    571739+ 
     
    575743+ 
    576744+       tahvo_ack_irq(TAHVO_INT_BATCURR); 
    577 +       //TODO 
    578 +dev_dbg(&bm->pdev->dev, "Tahvo measure IRQ triggered\n"); 
    579 +} 
     745+       schedule_work(&bm->currmeas_irq_work); 
     746+} 
     747+ 
     748+#define DEFINE_ATTR_NOTIFY(attr_name)                                          \ 
     749+       void n810bm_notify_##attr_name(struct n810bm *bm)                       \ 
     750+       {                                                                       \ 
     751+               set_bit(N810BM_NOTIFY_##attr_name, &bm->notify_flags);          \ 
     752+               wmb();                                                          \ 
     753+               schedule_work(&bm->notify_work);                                \ 
     754+       } 
    580755+ 
    581756+#define DEFINE_SHOW_INT_FUNC(name, member)                                     \ 
    582 +       static ssize_t n810bm_##name##_show(struct device *dev,                 \ 
    583 +                                           struct device_attribute *attr,      \ 
    584 +                                           char *buf)                          \ 
     757+       static ssize_t n810bm_attr_##name##_show(struct device *dev,            \ 
     758+                                               struct device_attribute *attr, \ 
     759+                                                char *buf)                     \ 
    585760+       {                                                                       \ 
    586761+               struct n810bm *bm = device_to_n810bm(dev);                      \ 
    587762+               ssize_t count;                                                  \ 
    588763+                                                                               \ 
    589 +               spin_lock_irq(&bm->lock);                                       \ 
     764+               mutex_lock(&bm->mutex);                                         \ 
    590765+               count = snprintf(buf, PAGE_SIZE, "%d\n", (int)(bm->member));    \ 
    591 +               spin_unlock_irq(&bm->lock);                                     \ 
     766+               mutex_unlock(&bm->mutex);                                       \ 
    592767+                                                                               \ 
    593768+               return count;                                                   \ 
     
    595770+ 
    596771+#define DEFINE_STORE_INT_FUNC(name, member)                                    \ 
    597 +       static ssize_t n810bm_##name##_store(struct device *dev,                \ 
    598 +                                            struct device_attribute *attr,     \ 
    599 +                                            const char *buf, size_t count)     \ 
     772+       static ssize_t n810bm_attr_##name##_store(struct device *dev,           \ 
     773+                                                 struct device_attribute *attr,\ 
     774+                                                 const char *buf, size_t count)\ 
    600775+       {                                                                       \ 
    601776+               struct n810bm *bm = device_to_n810bm(dev);                      \ 
     
    603778+               int err;                                                        \ 
    604779+                                                                               \ 
    605 +               spin_lock_irq(&bm->lock);                                       \ 
     780+               mutex_lock(&bm->mutex);                                         \ 
    606781+               err = strict_strtol(buf, 0, &val);                              \ 
    607782+               if (!err)                                                       \ 
    608783+                       bm->member = (typeof(bm->member))val;                   \ 
    609 +               spin_unlock_irq(&bm->lock);                                     \ 
     784+               mutex_unlock(&bm->mutex);                                       \ 
    610785+                                                                               \ 
    611786+               return err ? err : count;                                       \ 
     
    614789+#define DEFINE_ATTR_SHOW_INT(name, member)                                     \ 
    615790+       DEFINE_SHOW_INT_FUNC(name, member)                                      \ 
    616 +       static DEVICE_ATTR(name, 0444, n810bm_##name##_show, NULL); 
     791+       static DEVICE_ATTR(name, S_IRUGO,                                       \ 
     792+                          n810bm_attr_##name##_show, NULL); 
    617793+ 
    618794+#define DEFINE_ATTR_SHOW_STORE_INT(name, member)                               \ 
    619795+       DEFINE_SHOW_INT_FUNC(name, member)                                      \ 
    620796+       DEFINE_STORE_INT_FUNC(name, member)                                     \ 
    621 +       static DEVICE_ATTR(name, 0644, n810bm_##name##_show,                    \ 
    622 +                                      n810bm_##name##_store); 
    623 + 
    624 +DEFINE_ATTR_SHOW_INT(batt_present, battery_present); 
     797+       static DEVICE_ATTR(name, S_IRUGO | S_IWUSR,                             \ 
     798+                          n810bm_attr_##name##_show,                           \ 
     799+                          n810bm_attr_##name##_store); 
     800+ 
     801+DEFINE_ATTR_SHOW_INT(battery_present, battery_present); 
    625802+DEFINE_ATTR_SHOW_INT(charger_present, charger_present); 
     803+DEFINE_ATTR_SHOW_INT(charger_pwm, active_current_pwm); 
     804+static DEFINE_ATTR_NOTIFY(charger_pwm); 
    626805+DEFINE_ATTR_SHOW_STORE_INT(charger_enable, charger_enabled); 
    627 + 
    628 +static ssize_t n810bm_attr_charge_show(struct device *dev, 
    629 +                                      struct device_attribute *attr, 
    630 +                                      char *buf) 
    631 +{ 
    632 +       struct n810bm *bm = device_to_n810bm(dev); 
    633 +       int err = -ENODEV; 
    634 +       ssize_t count = 0; 
    635 +       int millivolt; 
    636 + 
    637 +       spin_lock_irq(&bm->lock); 
    638 +       if (bm->battery_present) { 
    639 +               millivolt = n810bm_measure_batt_voltage(bm); 
    640 +               if (millivolt >= 0) { 
    641 +                       count = snprintf(buf, PAGE_SIZE, "%u\n", 
    642 +                                        n810bm_mvolt2percent(millivolt)); 
    643 +                       err = 0; 
    644 +               } 
    645 +       } else { 
    646 +               count = snprintf(buf, PAGE_SIZE, "no battery\n"); 
    647 +               err = 0; 
    648 +       } 
    649 +       spin_unlock_irq(&bm->lock); 
    650 + 
    651 +       return err ? err : count; 
    652 +} 
    653 +static DEVICE_ATTR(batt_charge, 0444, n810bm_attr_charge_show, NULL); 
    654 + 
    655 +static ssize_t n810bm_attr_capacity_show(struct device *dev, 
    656 +                                        struct device_attribute *attr, 
    657 +                                        char *buf) 
     806+DEFINE_ATTR_SHOW_STORE_INT(charger_verbose, verbose_charge_log); 
     807+ 
     808+static ssize_t n810bm_attr_battery_charging(struct device *dev, 
     809+                                           struct device_attribute *attr, 
     810+                                           char *buf) 
    658811+{ 
    659812+       struct n810bm *bm = device_to_n810bm(dev); 
    660813+       ssize_t count; 
    661814+ 
    662 +       spin_lock_irq(&bm->lock); 
    663 +       if (bm->battery_present) { 
    664 +               count = snprintf(buf, PAGE_SIZE, "%d\n", 
    665 +                                (int)bm->capacity); 
    666 +       } else 
    667 +               count = snprintf(buf, PAGE_SIZE, "no battery\n"); 
    668 +       spin_unlock_irq(&bm->lock); 
     815+       mutex_lock(&bm->mutex); 
     816+       count = snprintf(buf, PAGE_SIZE, "%d\n", 
     817+                        (int)lipocharge_is_charging(&bm->charger)); 
     818+       mutex_unlock(&bm->mutex); 
    669819+ 
    670820+       return count; 
    671821+} 
    672 +static DEVICE_ATTR(batt_capacity, 0444, n810bm_attr_capacity_show, NULL); 
    673 + 
    674 +static ssize_t n810bm_attr_battemp_show(struct device *dev, 
    675 +                                       struct device_attribute *attr, 
    676 +                                       char *buf) 
     822+static DEVICE_ATTR(battery_charging, S_IRUGO, 
     823+                  n810bm_attr_battery_charging, NULL); 
     824+static DEFINE_ATTR_NOTIFY(battery_charging); 
     825+ 
     826+static ssize_t n810bm_attr_battery_level_show(struct device *dev, 
     827+                                             struct device_attribute *attr, 
     828+                                             char *buf) 
    677829+{ 
    678830+       struct n810bm *bm = device_to_n810bm(dev); 
    679 +       ssize_t count = 0; 
    680 +       int k, err = -ENODEV; 
    681 + 
    682 +       spin_lock_irq(&bm->lock); 
     831+       ssize_t count = -ENODEV; 
     832+       int millivolt; 
     833+ 
     834+       mutex_lock(&bm->mutex); 
     835+       if (!bm->battery_present || lipocharge_is_charging(&bm->charger)) 
     836+               millivolt = 0; 
     837+       else 
     838+               millivolt = n810bm_measure_batt_voltage(bm); 
     839+       if (millivolt >= 0) { 
     840+               count = snprintf(buf, PAGE_SIZE, "%u\n", 
     841+                                n810bm_mvolt2percent(millivolt)); 
     842+       } 
     843+       mutex_unlock(&bm->mutex); 
     844+ 
     845+       return count; 
     846+} 
     847+static DEVICE_ATTR(battery_level, S_IRUGO, 
     848+                  n810bm_attr_battery_level_show, NULL); 
     849+ 
     850+static ssize_t n810bm_attr_battery_capacity_show(struct device *dev, 
     851+                                                struct device_attribute *attr, 
     852+                                                char *buf) 
     853+{ 
     854+       struct n810bm *bm = device_to_n810bm(dev); 
     855+       ssize_t count; 
     856+       int capacity = 0; 
     857+ 
     858+       mutex_lock(&bm->mutex); 
     859+       if (n810bm_known_battery_present(bm)) 
     860+               capacity = (int)bm->capacity; 
     861+       count = snprintf(buf, PAGE_SIZE, "%d\n", capacity); 
     862+       mutex_unlock(&bm->mutex); 
     863+ 
     864+       return count; 
     865+} 
     866+static DEVICE_ATTR(battery_capacity, S_IRUGO, 
     867+                  n810bm_attr_battery_capacity_show, NULL); 
     868+ 
     869+static ssize_t n810bm_attr_battery_temp_show(struct device *dev, 
     870+                                            struct device_attribute *attr, 
     871+                                            char *buf) 
     872+{ 
     873+       struct n810bm *bm = device_to_n810bm(dev); 
     874+       ssize_t count = -ENODEV; 
     875+       int k; 
     876+ 
     877+       mutex_lock(&bm->mutex); 
    683878+       k = n810bm_measure_batt_temp(bm); 
    684 +       if (k >= 0) { 
     879+       if (k >= 0) 
    685880+               count = snprintf(buf, PAGE_SIZE, "%d\n", k); 
    686 +               err = 0; 
    687 +       } 
    688 +       spin_unlock_irq(&bm->lock); 
    689 + 
    690 +       return err ? err : count; 
    691 +} 
    692 +static DEVICE_ATTR(batt_temp, 0444, n810bm_attr_battemp_show, NULL); 
     881+       mutex_unlock(&bm->mutex); 
     882+ 
     883+       return count; 
     884+} 
     885+static DEVICE_ATTR(battery_temp, S_IRUGO, 
     886+                  n810bm_attr_battery_temp_show, NULL); 
    693887+ 
    694888+static ssize_t n810bm_attr_charger_voltage_show(struct device *dev, 
     
    697891+{ 
    698892+       struct n810bm *bm = device_to_n810bm(dev); 
    699 +       ssize_t count = 0; 
    700 +       int mv, err = -ENODEV; 
    701 + 
    702 +       spin_lock_irq(&bm->lock); 
    703 +       if (bm->charger_present) { 
     893+       ssize_t count = -ENODEV; 
     894+       int mv = 0; 
     895+ 
     896+       mutex_lock(&bm->mutex); 
     897+       if (bm->charger_present) 
    704898+               mv = n810bm_measure_charger_voltage(bm); 
    705 +               if (mv >= 0) { 
    706 +                       count = snprintf(buf, PAGE_SIZE, "%d\n", mv); 
    707 +                       err = 0; 
    708 +               } 
    709 +       } else { 
    710 +               count = snprintf(buf, PAGE_SIZE, "no charger\n"); 
    711 +               err = 0; 
    712 +       } 
    713 +       spin_unlock_irq(&bm->lock); 
    714 + 
    715 +       return err ? err : count; 
    716 +} 
    717 +static DEVICE_ATTR(charger_voltage, 0444, n810bm_attr_charger_voltage_show, NULL); 
    718 + 
    719 +static ssize_t n810bm_attr_backup_batt_voltage_show(struct device *dev, 
    720 +                                                   struct device_attribute *attr, 
    721 +                                                   char *buf) 
     899+       if (mv >= 0) 
     900+               count = snprintf(buf, PAGE_SIZE, "%d\n", mv); 
     901+       mutex_unlock(&bm->mutex); 
     902+ 
     903+       return count; 
     904+} 
     905+static DEVICE_ATTR(charger_voltage, S_IRUGO, 
     906+                  n810bm_attr_charger_voltage_show, NULL); 
     907+ 
     908+static ssize_t n810bm_attr_backup_battery_voltage_show(struct device *dev, 
     909+                                                      struct device_attribute *attr, 
     910+                                                      char *buf) 
    722911+{ 
    723912+       struct n810bm *bm = device_to_n810bm(dev); 
    724 +       ssize_t count = 0; 
    725 +       int mv, err = -ENODEV; 
    726 + 
    727 +       spin_lock_irq(&bm->lock); 
     913+       ssize_t count = -ENODEV; 
     914+       int mv; 
     915+ 
     916+       mutex_lock(&bm->mutex); 
    728917+       mv = n810bm_measure_backup_batt_voltage(bm); 
    729 +       if (mv >= 0) { 
     918+       if (mv >= 0) 
    730919+               count = snprintf(buf, PAGE_SIZE, "%d\n", mv); 
    731 +               err = 0; 
    732 +       } 
    733 +       spin_unlock_irq(&bm->lock); 
    734 + 
    735 +       return err ? err : count; 
    736 +} 
    737 +static DEVICE_ATTR(backup_batt_voltage, 0444, n810bm_attr_backup_batt_voltage_show, NULL); 
    738 + 
    739 +static ssize_t n810bm_attr_batt_current_show(struct device *dev, 
    740 +                                            struct device_attribute *attr, 
    741 +                                            char *buf) 
     920+       mutex_unlock(&bm->mutex); 
     921+ 
     922+       return count; 
     923+} 
     924+static DEVICE_ATTR(backup_battery_voltage, S_IRUGO, 
     925+                  n810bm_attr_backup_battery_voltage_show, NULL); 
     926+ 
     927+static ssize_t n810bm_attr_battery_current_show(struct device *dev, 
     928+                                               struct device_attribute *attr, 
     929+                                               char *buf) 
    742930+{ 
    743931+       struct n810bm *bm = device_to_n810bm(dev); 
    744 +       ssize_t count = 0; 
    745 +       int ma; 
    746 + 
    747 +       spin_lock_irq(&bm->lock); 
    748 +       if (bm->battery_present) { 
    749 +               ma = n810bm_measure_batt_current(bm);//FIXME 
    750 +               count = snprintf(buf, PAGE_SIZE, "%d\n", ma); 
    751 +       } else 
    752 +               count = snprintf(buf, PAGE_SIZE, "no battery\n"); 
    753 +       spin_unlock_irq(&bm->lock); 
     932+       ssize_t count = -ENODEV; 
     933+       int ma = 0; 
     934+ 
     935+       mutex_lock(&bm->mutex); 
     936+       if (bm->battery_present) 
     937+               ma = n810bm_measure_batt_current_async(bm); 
     938+       count = snprintf(buf, PAGE_SIZE, "%d\n", ma); 
     939+       mutex_unlock(&bm->mutex); 
    754940+ 
    755941+       return count; 
    756942+} 
    757 +static DEVICE_ATTR(batt_current, 0444, n810bm_attr_batt_current_show, NULL); 
    758 + 
    759 +//TODO remove this 
    760 +static ssize_t n810bm_attr_charger_status_show(struct device *dev, 
    761 +                                              struct device_attribute *attr, 
    762 +                                              char *buf) 
    763 +{ 
    764 +       struct n810bm *bm = device_to_n810bm(dev); 
    765 +       ssize_t count = 0; 
    766 +       unsigned int stat; 
    767 + 
    768 +       spin_lock_irq(&bm->lock); 
    769 +       stat = retu_read(bm, RETU_REG_STATUS); 
    770 +       count = snprintf(buf, PAGE_SIZE, "0x%X\n", stat); 
    771 +       spin_unlock_irq(&bm->lock); 
    772 + 
    773 +       return count; 
    774 +} 
    775 +static DEVICE_ATTR(charger_status, 0444, n810bm_attr_charger_status_show, NULL); 
    776 + 
    777 +//TODO remove this 
    778 +static ssize_t n810bm_attr_charge_current_show(struct device *dev, 
    779 +                                              struct device_attribute *attr, 
    780 +                                              char *buf) 
    781 +{ 
    782 +       struct n810bm *bm = device_to_n810bm(dev); 
    783 +       ssize_t count = 0; 
    784 +       unsigned int val; 
    785 + 
    786 +       spin_lock_irq(&bm->lock); 
    787 +       val = tahvo_read(bm, TAHVO_REG_CHGCURR); 
    788 +       count = snprintf(buf, PAGE_SIZE, "0x%X\n", val); 
    789 +       spin_unlock_irq(&bm->lock); 
    790 + 
    791 +       return count; 
    792 +} 
    793 + 
    794 +static ssize_t n810bm_attr_charge_current_store(struct device *dev, 
    795 +                                               struct device_attribute *attr, 
    796 +                                               const char *buf, size_t count) 
    797 +{ 
    798 +       struct n810bm *bm = device_to_n810bm(dev); 
    799 +       unsigned long val; 
    800 +       int err; 
    801 + 
    802 +       spin_lock_irq(&bm->lock); 
    803 +       err = strict_strtoul(buf, 0, &val); 
    804 +       if (!err && val <= 0xFF) 
    805 +               tahvo_write(bm, TAHVO_REG_CHGCURR, val); 
    806 +       spin_unlock_irq(&bm->lock); 
    807 + 
    808 +       return err ? err : count; 
    809 +} 
    810 +static DEVICE_ATTR(charge_current, 0644, 
    811 +                  n810bm_attr_charge_current_show, 
    812 +                  n810bm_attr_charge_current_store); 
     943+static DEVICE_ATTR(battery_current, S_IRUGO, 
     944+                  n810bm_attr_battery_current_show, NULL); 
    813945+ 
    814946+static const struct device_attribute *n810bm_attrs[] = { 
    815 +       &dev_attr_batt_present, 
    816 +       &dev_attr_batt_charge, 
    817 +       &dev_attr_batt_current, 
    818 +       &dev_attr_batt_capacity, 
    819 +       &dev_attr_batt_temp, 
    820 +       &dev_attr_backup_batt_voltage, 
     947+       &dev_attr_battery_present, 
     948+       &dev_attr_battery_level, 
     949+       &dev_attr_battery_charging, 
     950+       &dev_attr_battery_current, 
     951+       &dev_attr_battery_capacity, 
     952+       &dev_attr_battery_temp, 
     953+       &dev_attr_backup_battery_voltage, 
    821954+       &dev_attr_charger_present, 
     955+       &dev_attr_charger_verbose, 
    822956+       &dev_attr_charger_voltage, 
    823 +       &dev_attr_charger_status, 
    824957+       &dev_attr_charger_enable, 
    825 +       &dev_attr_charge_current, 
     958+       &dev_attr_charger_pwm, 
    826959+}; 
    827960+ 
     961+static void n810bm_notify_work(struct work_struct *work) 
     962+{ 
     963+       struct n810bm *bm = container_of(work, struct n810bm, notify_work); 
     964+       unsigned long notify_flags; 
     965+ 
     966+       notify_flags = xchg(&bm->notify_flags, 0); 
     967+       mb(); 
     968+ 
     969+#define do_notify(attr_name)                                           \ 
     970+       do {                                                            \ 
     971+               if (notify_flags & (1 << N810BM_NOTIFY_##attr_name)) {  \ 
     972+                       sysfs_notify(&bm->pdev->dev.kobj, NULL,         \ 
     973+                                    dev_attr_##attr_name.attr.name);   \ 
     974+               }                                                       \ 
     975+       } while (0) 
     976+ 
     977+       do_notify(battery_charging); 
     978+       do_notify(charger_pwm); 
     979+} 
     980+ 
     981+static int n810bm_charger_set_current_pwm(struct lipocharge *c, 
     982+                                         unsigned int duty_cycle) 
     983+{ 
     984+       struct n810bm *bm = container_of(c, struct n810bm, charger); 
     985+       int err = -EINVAL; 
     986+ 
     987+       WARN_ON(!mutex_is_locked(&bm->mutex)); 
     988+       if (WARN_ON(duty_cycle > 0xFF)) 
     989+               goto out; 
     990+       if (WARN_ON(!bm->charger_enabled)) 
     991+               goto out; 
     992+       if (WARN_ON(!bm->battery_present || !bm->charger_present)) 
     993+               goto out; 
     994+ 
     995+       if (duty_cycle != bm->active_current_pwm) { 
     996+               bm->active_current_pwm = duty_cycle; 
     997+               tahvo_write(bm, TAHVO_REG_CHGCURR, duty_cycle); 
     998+               n810bm_notify_charger_pwm(bm); 
     999+       } 
     1000+ 
     1001+       err = 0; 
     1002+out: 
     1003+ 
     1004+       return err; 
     1005+} 
     1006+ 
     1007+static void n810bm_charger_emergency(struct lipocharge *c) 
     1008+{ 
     1009+       struct n810bm *bm = container_of(c, struct n810bm, charger); 
     1010+ 
     1011+       n810bm_emergency(bm, "Battery charger fault"); 
     1012+} 
     1013+ 
    8281014+static void n810bm_hw_exit(struct n810bm *bm) 
    8291015+{ 
     1016+       n810bm_stop_charge(bm); 
    8301017+       retu_write(bm, RETU_REG_ADCSCR, 0); 
    831 +       //TODO 
    8321018+} 
    8331019+ 
     
    8401026+               return err; 
    8411027+ 
     1028+       n810bm_stop_charge(bm); 
     1029+ 
    8421030+       return 0; 
     1031+} 
     1032+ 
     1033+static void n810bm_cancel_and_flush_work(struct n810bm *bm) 
     1034+{ 
     1035+       cancel_delayed_work_sync(&bm->periodic_check_work); 
     1036+       cancel_work_sync(&bm->notify_work); 
     1037+       cancel_work_sync(&bm->currmeas_irq_work); 
     1038+       flush_scheduled_work(); 
    8431039+} 
    8441040+ 
     
    8471043+       int attr_index; 
    8481044+       int err; 
     1045+ 
     1046+       bm->charger.rate = LIPORATE_p6C; 
     1047+       bm->charger.top_voltage = 4100; 
     1048+       bm->charger.duty_cycle_max = 0xFF; 
     1049+       bm->charger.set_current_pwm = n810bm_charger_set_current_pwm; 
     1050+       bm->charger.emergency = n810bm_charger_emergency; 
     1051+       lipocharge_init(&bm->charger, &bm->pdev->dev); 
    8491052+ 
    8501053+       err = n810bm_hw_init(bm); 
     
    8661069+       if (err) 
    8671070+               goto err_free_retu_irq; 
    868 + 
    869 +       lipocharge_init(&bm->charger); 
    870 +       mod_timer(&bm->check_timer, round_jiffies(jiffies + N810BM_CHECK_INTERVAL)); 
     1071+       tahvo_disable_irq(TAHVO_INT_BATCURR); 
     1072+ 
     1073+       schedule_delayed_work(&bm->periodic_check_work, 
     1074+                             round_jiffies_relative(N810BM_CHECK_INTERVAL)); 
    8711075+ 
    8721076+       bm->initialized = 1; 
     
    8831087+       n810bm_hw_exit(bm); 
    8841088+error: 
     1089+       n810bm_cancel_and_flush_work(bm); 
     1090+ 
    8851091+       return err; 
    8861092+} 
     
    8961102+       tahvo_free_irq(TAHVO_INT_BATCURR); 
    8971103+       retu_free_irq(RETU_INT_ADCS); 
    898 +       del_timer_sync(&bm->check_timer); 
    8991104+       for (i = 0; i < ARRAY_SIZE(n810bm_attrs); i++) 
    9001105+               device_remove_file(&bm->pdev->dev, n810bm_attrs[i]); 
     1106+ 
     1107+       n810bm_cancel_and_flush_work(bm); 
     1108+ 
    9011109+       n810bm_hw_exit(bm); 
    9021110+       release_firmware(bm->pmm_block); 
     
    9451153+       bm->pdev = pdev; 
    9461154+       platform_set_drvdata(pdev, bm); 
    947 +       spin_lock_init(&bm->lock); 
    948 +       setup_timer(&bm->check_timer, n810bm_check_timer, (unsigned long)bm); 
     1155+       mutex_init(&bm->mutex); 
     1156+       INIT_DELAYED_WORK(&bm->periodic_check_work, n810bm_periodic_check_work); 
     1157+       INIT_WORK(&bm->notify_work, n810bm_notify_work); 
     1158+       INIT_WORK(&bm->currmeas_irq_work, n810bm_tahvo_current_measure_work); 
    9491159+ 
    9501160+       dev_info(&bm->pdev->dev, "Requesting CAL BME PMM block firmware file " 
     
    10051215Index: linux-2.6.37/drivers/cbus/retu.c 
    10061216=================================================================== 
    1007 --- linux-2.6.37.orig/drivers/cbus/retu.c       2011-02-06 00:24:48.493004751 +0100 
    1008 +++ linux-2.6.37/drivers/cbus/retu.c    2011-02-06 00:24:48.551008149 +0100 
     1217--- linux-2.6.37.orig/drivers/cbus/retu.c       2011-02-06 14:05:49.829387442 +0100 
     1218+++ linux-2.6.37/drivers/cbus/retu.c    2011-02-08 17:33:18.981369017 +0100 
    10091219@@ -85,10 +85,10 @@ 
    10101220  * 
     
    10201230  
    10211231 void retu_set_clear_reg_bits(int reg, u16 set, u16 clear) 
     1232@@ -459,6 +459,7 @@ 
     1233 EXPORT_SYMBOL(retu_ack_irq); 
     1234 EXPORT_SYMBOL(retu_read_reg); 
     1235 EXPORT_SYMBOL(retu_write_reg); 
     1236+EXPORT_SYMBOL(retu_read_adc); 
     1237  
     1238 subsys_initcall(retu_init); 
     1239 module_exit(retu_exit); 
    10221240Index: linux-2.6.37/drivers/cbus/retu.h 
    10231241=================================================================== 
    1024 --- linux-2.6.37.orig/drivers/cbus/retu.h       2011-02-06 00:24:48.493004751 +0100 
    1025 +++ linux-2.6.37/drivers/cbus/retu.h    2011-02-06 00:24:48.551008149 +0100 
     1242--- linux-2.6.37.orig/drivers/cbus/retu.h       2011-02-06 14:05:49.829387442 +0100 
     1243+++ linux-2.6.37/drivers/cbus/retu.h    2011-02-06 14:05:49.886395793 +0100 
    10261244@@ -40,6 +40,8 @@ 
    10271245 #define RETU_REG_CTRL_CLR      0x0f    /* Regulator clear register */ 
     
    10621280Index: linux-2.6.37/arch/arm/mach-omap2/board-n8x0.c 
    10631281=================================================================== 
    1064 --- linux-2.6.37.orig/arch/arm/mach-omap2/board-n8x0.c  2011-02-06 00:24:48.478003872 +0100 
    1065 +++ linux-2.6.37/arch/arm/mach-omap2/board-n8x0.c       2011-02-06 00:24:48.551008149 +0100 
     1282--- linux-2.6.37.orig/arch/arm/mach-omap2/board-n8x0.c  2011-02-06 14:05:49.815385390 +0100 
     1283+++ linux-2.6.37/arch/arm/mach-omap2/board-n8x0.c       2011-02-06 14:05:49.886395793 +0100 
    10661284@@ -907,6 +907,17 @@ 
    10671285                                    ARRAY_SIZE(n8x0_gpio_switches)); 
     
    10941312=================================================================== 
    10951313--- /dev/null   1970-01-01 00:00:00.000000000 +0000 
    1096 +++ linux-2.6.37/drivers/cbus/lipocharge.c      2011-02-06 12:57:01.427475867 +0100 
    1097 @@ -0,0 +1,58 @@ 
     1314+++ linux-2.6.37/drivers/cbus/lipocharge.c      2011-02-09 12:42:58.243147563 +0100 
     1315@@ -0,0 +1,183 @@ 
    10981316+/* 
    10991317+ *   Generic LIPO battery charger 
    11001318+ * 
    1101 + *   Copyright (c) 2010 Michael Buesch <mb@bu3sch.de> 
     1319+ *   Copyright (c) 2010-2011 Michael Buesch <mb@bu3sch.de> 
    11021320+ * 
    11031321+ *   This program is free software; you can redistribute it and/or 
     
    11121330+ */ 
    11131331+ 
     1332+#define DEBUG 
     1333+ 
    11141334+#include "lipocharge.h" 
    11151335+ 
     
    11171337+ 
    11181338+ 
    1119 +static void lipocharge_timer(unsigned long data) 
    1120 +{ 
    1121 +       struct lipocharge *c = (struct lipocharge *)data; 
    1122 + 
    1123 +       spin_lock(&c->lock); 
    1124 +       //TODO 
    1125 +       spin_unlock(&c->lock); 
    1126 +} 
    1127 + 
    1128 +void lipocharge_init(struct lipocharge *c) 
    1129 +{ 
    1130 +       spin_lock_init(&c->lock); 
    1131 +       setup_timer(&c->timer, lipocharge_timer, (unsigned long)c); 
     1339+/* Hysteresis constants */ 
     1340+#define CURRENT_HYST           30 /* mA */ 
     1341+#define VOLTAGE_HYST           10 /* mV */ 
     1342+ 
     1343+/* Threshold constants */ 
     1344+#define FINISH_CURRENT_PERCENT 3 
     1345+ 
     1346+ 
     1347+/* Returns the requested first-stage charge current in mA */ 
     1348+static inline unsigned int get_stage1_charge_current(struct lipocharge *c) 
     1349+{ 
     1350+       /* current = (capacity * C) */ 
     1351+       return c->capacity * c->rate / 1000; 
     1352+} 
     1353+ 
     1354+void lipocharge_init(struct lipocharge *c, struct device *dev) 
     1355+{ 
     1356+       c->dev = dev; 
     1357+       c->state = LIPO_IDLE; 
    11321358+} 
    11331359+ 
    11341360+void lipocharge_exit(struct lipocharge *c) 
    11351361+{ 
     1362+       c->state = LIPO_IDLE; 
    11361363+} 
    11371364+ 
    11381365+int lipocharge_start(struct lipocharge *c) 
    11391366+{ 
    1140 +       if (!c->set_charge_current || !c->get_charge_current || 
    1141 +           !c->get_voltage || 
    1142 +           !c->finished || !c->emergency) 
     1367+       int err; 
     1368+ 
     1369+       if (c->state != LIPO_IDLE) 
     1370+               return -EBUSY; 
     1371+       if (!c->set_current_pwm || !c->emergency) 
    11431372+               return -EINVAL; 
    11441373+       if (!c->top_voltage || c->top_voltage > 4200) 
    11451374+               return -EINVAL; 
    1146 +       //TODO 
     1375+ 
     1376+       c->active_duty_cycle = 0; 
     1377+       err = c->set_current_pwm(c, c->active_duty_cycle); 
     1378+       if (err) 
     1379+               return err; 
     1380+       c->state = LIPO_FIRST_STAGE; 
    11471381+ 
    11481382+       return 0; 
     
    11511385+void lipocharge_stop(struct lipocharge *c) 
    11521386+{ 
    1153 +       del_timer_sync(&c->timer); 
    1154 +       //TODO 
     1387+       if (c->state == LIPO_IDLE) 
     1388+               return; 
     1389+       c->state = LIPO_IDLE; 
     1390+} 
     1391+ 
     1392+static int lipocharge_increase_current(struct lipocharge *c, 
     1393+                                      unsigned int inc_permille) 
     1394+{ 
     1395+       int old_pwm, new_pwm; 
     1396+ 
     1397+       if (c->active_duty_cycle >= c->duty_cycle_max) 
     1398+               return 0; 
     1399+ 
     1400+       old_pwm = c->active_duty_cycle; 
     1401+       new_pwm = old_pwm + (c->duty_cycle_max * inc_permille / 1000); 
     1402+       new_pwm = min(new_pwm, (int)c->duty_cycle_max); 
     1403+       c->active_duty_cycle = new_pwm; 
     1404+ 
     1405+       dev_dbg(c->dev, "lipo: Increasing duty_cycle by " 
     1406+               "%u permille (0x%02X -> 0x%02X)", 
     1407+               inc_permille, old_pwm, new_pwm); 
     1408+ 
     1409+       return c->set_current_pwm(c, c->active_duty_cycle); 
     1410+} 
     1411+ 
     1412+static int lipocharge_decrease_current(struct lipocharge *c, 
     1413+                                      unsigned int dec_permille) 
     1414+{ 
     1415+       int old_pwm, new_pwm; 
     1416+ 
     1417+       if (c->active_duty_cycle <= 0) 
     1418+               return 0; 
     1419+ 
     1420+       old_pwm = c->active_duty_cycle; 
     1421+       new_pwm = old_pwm - (c->duty_cycle_max * dec_permille / 1000); 
     1422+       new_pwm = max(0, new_pwm); 
     1423+       c->active_duty_cycle = new_pwm; 
     1424+ 
     1425+       dev_dbg(c->dev, "lipo: Decreasing duty_cycle by " 
     1426+               "%u permille (0x%02X -> 0x%02X)", 
     1427+               dec_permille, old_pwm, new_pwm); 
     1428+ 
     1429+       return c->set_current_pwm(c, c->active_duty_cycle); 
     1430+} 
     1431+ 
     1432+/** lipocharge_update_state - Update the charge state 
     1433+ * @c: The context. 
     1434+ * @voltage_mV: The measured battery voltage. 
     1435+ * @current_mA: The measured charge current. 
     1436+ *             negative -> drain. 
     1437+ *             positive -> charge. 
     1438+ * @temp_K: Battery temperature in K. 
     1439+ * 
     1440+ * Returns 0 on success, -1 on error. 
     1441+ * Returns 1, if the charging process is finished. 
     1442+ */ 
     1443+int lipocharge_update_state(struct lipocharge *c, 
     1444+                           unsigned int voltage_mV, 
     1445+                           int current_mA, 
     1446+                           unsigned int temp_K) 
     1447+{ 
     1448+       int requested_current, current_diff; 
     1449+       int err; 
     1450+       unsigned int permille; 
     1451+ 
     1452+       //TODO temp 
     1453+ 
     1454+restart: 
     1455+       switch (c->state) { 
     1456+       case LIPO_IDLE: 
     1457+               dev_err(c->dev, "%s: called while idle", __func__); 
     1458+               return -EINVAL; 
     1459+       case LIPO_FIRST_STAGE:  /* Constant current */ 
     1460+//printk("GOT %u %d %u\n", voltage_mV, current_mA, temp_K); 
     1461+               if (voltage_mV >= c->top_voltage) { 
     1462+                       /* Float voltage reached. 
     1463+                        * Switch charger mode to "constant current" */ 
     1464+                       c->state = LIPO_SECOND_STAGE; 
     1465+                       dev_dbg(c->dev, "Switched to second charging stage."); 
     1466+                       goto restart; 
     1467+               } 
     1468+               /* Float voltage not reached, yet. 
     1469+                * Try to get the requested constant current. */ 
     1470+               requested_current = get_stage1_charge_current(c); 
     1471+               if (current_mA < 0) 
     1472+                       current_mA = 0; 
     1473+               current_diff = requested_current - current_mA; 
     1474+               if (abs(requested_current - current_mA) > CURRENT_HYST) { 
     1475+                       if (current_diff > 0) { 
     1476+                               /* Increase current */ 
     1477+                               permille = current_diff * 1000 / requested_current; 
     1478+                               permille /= 2; 
     1479+                               err = lipocharge_increase_current(c, permille); 
     1480+                               if (err) 
     1481+                                       return err; 
     1482+                       } else { 
     1483+                               /* Decrease current */ 
     1484+                               permille = (-current_diff) * 1000 / requested_current; 
     1485+                               permille /= 2; 
     1486+                               err = lipocharge_decrease_current(c, permille); 
     1487+                               if (err) 
     1488+                                       return err; 
     1489+                       } 
     1490+               } 
     1491+               break; 
     1492+       case LIPO_SECOND_STAGE: /* Constant voltage */ 
     1493+               //TODO 
     1494+               break; 
     1495+       } 
     1496+ 
     1497+       return 0; 
    11551498+} 
    11561499Index: linux-2.6.37/drivers/cbus/lipocharge.h 
    11571500=================================================================== 
    11581501--- /dev/null   1970-01-01 00:00:00.000000000 +0000 
    1159 +++ linux-2.6.37/drivers/cbus/lipocharge.h      2011-02-06 12:36:29.800830614 +0100 
    1160 @@ -0,0 +1,55 @@ 
     1502+++ linux-2.6.37/drivers/cbus/lipocharge.h      2011-02-07 20:07:29.669098631 +0100 
     1503@@ -0,0 +1,60 @@ 
    11611504+#ifndef LIPOCHARGE_H_ 
    11621505+#define LIPOCHARGE_H_ 
    11631506+ 
    1164 +#include <linux/timer.h> 
    1165 +#include <linux/spinlock.h> 
    1166 + 
    1167 + 
    1168 +#define LIPORATE(a,b)  (((a) * 1000) + (b)) 
    1169 +#define LIPORATE_1C    LIPORATE(1,0)   /* 1C */ 
    1170 +#define LIPORATE_p8C   LIPORATE(0,8)   /* 0.8C */ 
     1507+#include <linux/types.h> 
     1508+#include <linux/device.h> 
     1509+ 
     1510+ 
     1511+#define LIPORATE(a,b)  (((a) * 1000) + ((b) * 100)) 
    11711512+#define LIPORATE_p6C   LIPORATE(0,6)   /* 0.6C */ 
     1513+ 
     1514+enum lipocharge_state { 
     1515+       LIPO_IDLE,              /* Not charging */ 
     1516+       LIPO_FIRST_STAGE,       /* Charging: constant current */ 
     1517+       LIPO_SECOND_STAGE,      /* Charging: constant voltage */ 
     1518+}; 
    11721519+ 
    11731520+/** struct lipocharge - A generic LIPO charger 
     
    11761523+ * @rate: Charge rate. 
    11771524+ * @top_voltage: Fully charged voltage, in mV. 
     1525+ * @duty_cycle_max: Max value for duty_cycle. 
    11781526+ * 
    1179 + * @set_charge_current: Set the charge current, in mA. 
    1180 + * @get_charge_current: Get the battery current, in signed mA. 
    1181 + * @get_voltage: Get the battery voltage, in mV. 
    1182 + * 
    1183 + * @finished: Charging finished. 
     1527+ * @set_charge_current: Set the charge current PWM duty cycle. 
    11841528+ * @emergency: Something went wrong. Force shutdown. 
    11851529+ */ 
     
    11881532+       unsigned int rate; 
    11891533+       unsigned int top_voltage; 
    1190 + 
    1191 +       int (*set_charge_current)(struct lipocharge *c, unsigned int ma); 
    1192 +       int (*get_charge_current)(struct lipocharge *c, int *ma); 
    1193 +       int (*get_voltage)(struct lipocharge *c, unsigned int *mv); 
    1194 + 
    1195 +       void (*finished)(struct lipocharge *c); 
     1534+       unsigned int duty_cycle_max; 
     1535+ 
     1536+       int (*set_current_pwm)(struct lipocharge *c, unsigned int duty_cycle); 
    11961537+       void (*emergency)(struct lipocharge *c); 
    11971538+ 
    11981539+       /* internal */ 
    1199 +       spinlock_t lock; 
    1200 +       struct timer_list timer; 
    1201 +       bool charging; 
     1540+       struct device *dev; 
     1541+       enum lipocharge_state state; 
     1542+       unsigned int active_duty_cycle; 
     1543+ 
     1544+       //TODO implement timer to cut power after maximum charge time. 
    12021545+}; 
    12031546+ 
    1204 +void lipocharge_init(struct lipocharge *c); 
     1547+void lipocharge_init(struct lipocharge *c, struct device *dev); 
    12051548+void lipocharge_exit(struct lipocharge *c); 
    12061549+ 
     
    12081551+void lipocharge_stop(struct lipocharge *c); 
    12091552+ 
     1553+int lipocharge_update_state(struct lipocharge *c, 
     1554+                           unsigned int voltage_mV, 
     1555+                           int current_mA, 
     1556+                           unsigned int temp_K); 
     1557+ 
    12101558+static inline bool lipocharge_is_charging(struct lipocharge *c) 
    12111559+{ 
    1212 +       return c->charging; 
     1560+       return (c->state != LIPO_IDLE); 
    12131561+} 
    12141562+ 
     
    12161564Index: linux-2.6.37/drivers/cbus/tahvo.h 
    12171565=================================================================== 
    1218 --- linux-2.6.37.orig/drivers/cbus/tahvo.h      2011-02-06 00:24:48.494004810 +0100 
    1219 +++ linux-2.6.37/drivers/cbus/tahvo.h   2011-02-06 00:24:48.551008149 +0100 
     1566--- linux-2.6.37.orig/drivers/cbus/tahvo.h      2011-02-06 14:05:49.830387588 +0100 
     1567+++ linux-2.6.37/drivers/cbus/tahvo.h   2011-02-06 16:22:25.902331536 +0100 
    12201568@@ -30,17 +30,28 @@ 
    12211569 #define TAHVO_REG_IDR          0x01    /* Interrupt ID */ 
     
    12271575+#define TAHVO_REG_CHGCTL       0x08    /* Charge control register */ 
    12281576+#define  TAHVO_REG_CHGCTL_EN           0x0001  /* Global charge enable */ 
    1229 +#define  TAHVO_REG_CHGCTL_PWMOVR       0x0004  /* PWM override. Force charge PWM to 100% duty cycle. */ 
    1230 +#define  TAHVO_REG_CHGCTL_UNK8         0x0008  /* XXX: Unknown. Written on init. */ 
     1577+#define  TAHVO_REG_CHGCTL_PWMOVR       0x0004  /* PWM override. Force charge PWM to 0%/100% duty cycle. */ 
     1578+#define  TAHVO_REG_CHGCTL_PWMOVRZERO   0x0008  /* If set, PWM override is 0% (If unset -> 100%) */ 
    12311579+#define  TAHVO_REG_CHGCTL_CURMEAS      0x0040  /* Enable battery current measurement. */ 
    12321580+#define  TAHVO_REG_CHGCTL_CURTIMRST    0x0080  /* Current measure timer reset. */ 
     
    12501598Index: linux-2.6.37/drivers/cbus/tahvo.c 
    12511599=================================================================== 
    1252 --- linux-2.6.37.orig/drivers/cbus/tahvo.c      2011-02-06 00:24:48.494004810 +0100 
    1253 +++ linux-2.6.37/drivers/cbus/tahvo.c   2011-02-06 00:24:48.552008207 +0100 
     1600--- linux-2.6.37.orig/drivers/cbus/tahvo.c      2011-02-06 14:05:49.830387588 +0100 
     1601+++ linux-2.6.37/drivers/cbus/tahvo.c   2011-02-06 14:05:49.886395793 +0100 
    12541602@@ -85,10 +85,10 @@ 
    12551603  * 
     
    12651613  
    12661614 /** 
     1615Index: linux-2.6.37/drivers/cbus/cbus.c 
     1616=================================================================== 
     1617--- linux-2.6.37.orig/drivers/cbus/cbus.c       2011-02-08 17:34:34.988926130 +0100 
     1618+++ linux-2.6.37/drivers/cbus/cbus.c    2011-02-08 17:38:16.980407594 +0100 
     1619@@ -31,6 +31,7 @@ 
     1620 #include <linux/gpio.h> 
     1621 #include <linux/platform_device.h> 
     1622 #include <linux/slab.h> 
     1623+#include <linux/reboot.h> 
     1624  
     1625 #include <asm/io.h> 
     1626 #include <asm/mach-types.h> 
     1627@@ -301,6 +302,13 @@ 
     1628 } 
     1629 module_exit(cbus_bus_exit); 
     1630  
     1631+void cbus_emergency(void) 
     1632+{ 
     1633+       machine_power_off(); 
     1634+       panic("cbus: Failed to halt machine in emergency state\n"); 
     1635+} 
     1636+EXPORT_SYMBOL(cbus_emergency); 
     1637+ 
     1638 MODULE_DESCRIPTION("CBUS serial protocol"); 
     1639 MODULE_LICENSE("GPL"); 
     1640 MODULE_AUTHOR("Juha Yrjölä"); 
     1641Index: linux-2.6.37/drivers/cbus/cbus.h 
     1642=================================================================== 
     1643--- linux-2.6.37.orig/drivers/cbus/cbus.h       2011-02-08 17:36:40.172074049 +0100 
     1644+++ linux-2.6.37/drivers/cbus/cbus.h    2011-02-08 17:41:32.680647478 +0100 
     1645@@ -33,4 +33,6 @@ 
     1646 extern int cbus_read_reg(struct cbus_host *host, int dev, int reg); 
     1647 extern int cbus_write_reg(struct cbus_host *host, int dev, int reg, u16 val); 
     1648  
     1649+NORET_TYPE void cbus_emergency(void) ATTRIB_NORET; 
     1650+ 
     1651 #endif /* __DRIVERS_CBUS_CBUS_H */ 
Note: See TracChangeset for help on using the changeset viewer.