linux/arch/arm/mach-pxa/sharpsl_pm.c
<<
>>
Prefs
   1/*
   2 * Battery and Power Management code for the Sharp SL-C7xx and SL-Cxx00
   3 * series of PDAs
   4 *
   5 * Copyright (c) 2004-2005 Richard Purdie
   6 *
   7 * Based on code written by Sharp for 2.4 kernels
   8 *
   9 * This program is free software; you can redistribute it and/or modify
  10 * it under the terms of the GNU General Public License version 2 as
  11 * published by the Free Software Foundation.
  12 *
  13 */
  14
  15#undef DEBUG
  16
  17#include <linux/module.h>
  18#include <linux/kernel.h>
  19#include <linux/interrupt.h>
  20#include <linux/platform_device.h>
  21#include <linux/apm-emulation.h>
  22#include <linux/timer.h>
  23#include <linux/delay.h>
  24#include <linux/leds.h>
  25#include <linux/suspend.h>
  26#include <linux/gpio.h>
  27
  28#include <asm/mach-types.h>
  29#include <mach/pm.h>
  30#include <mach/pxa2xx-regs.h>
  31#include <mach/pxa2xx-gpio.h>
  32#include <mach/regs-rtc.h>
  33#include <mach/sharpsl.h>
  34#include <mach/sharpsl_pm.h>
  35
  36#include "sharpsl.h"
  37
  38/*
  39 * Constants
  40 */
  41#define SHARPSL_CHARGE_ON_TIME_INTERVAL        (msecs_to_jiffies(1*60*1000))  /* 1 min */
  42#define SHARPSL_CHARGE_FINISH_TIME             (msecs_to_jiffies(10*60*1000)) /* 10 min */
  43#define SHARPSL_BATCHK_TIME                    (msecs_to_jiffies(15*1000))    /* 15 sec */
  44#define SHARPSL_BATCHK_TIME_SUSPEND            (60*10)                        /* 10 min */
  45
  46#define SHARPSL_WAIT_CO_TIME                   15  /* 15 sec */
  47#define SHARPSL_WAIT_DISCHARGE_ON              100 /* 100 msec */
  48#define SHARPSL_CHECK_BATTERY_WAIT_TIME_TEMP   10  /* 10 msec */
  49#define SHARPSL_CHECK_BATTERY_WAIT_TIME_VOLT   10  /* 10 msec */
  50#define SHARPSL_CHECK_BATTERY_WAIT_TIME_ACIN   10  /* 10 msec */
  51#define SHARPSL_CHARGE_WAIT_TIME               15  /* 15 msec */
  52#define SHARPSL_CHARGE_CO_CHECK_TIME           5   /* 5 msec */
  53#define SHARPSL_CHARGE_RETRY_CNT               1   /* eqv. 10 min */
  54
  55/*
  56 * Prototypes
  57 */
  58#ifdef CONFIG_PM
  59static int sharpsl_off_charge_battery(void);
  60static int sharpsl_check_battery_voltage(void);
  61static int sharpsl_fatal_check(void);
  62#endif
  63static int sharpsl_check_battery_temp(void);
  64static int sharpsl_ac_check(void);
  65static int sharpsl_average_value(int ad);
  66static void sharpsl_average_clear(void);
  67static void sharpsl_charge_toggle(struct work_struct *private_);
  68static void sharpsl_battery_thread(struct work_struct *private_);
  69
  70
  71/*
  72 * Variables
  73 */
  74struct sharpsl_pm_status sharpsl_pm;
  75static DECLARE_DELAYED_WORK(toggle_charger, sharpsl_charge_toggle);
  76static DECLARE_DELAYED_WORK(sharpsl_bat, sharpsl_battery_thread);
  77DEFINE_LED_TRIGGER(sharpsl_charge_led_trigger);
  78
  79
  80
  81struct battery_thresh spitz_battery_levels_acin[] = {
  82        { 213, 100},
  83        { 212,  98},
  84        { 211,  95},
  85        { 210,  93},
  86        { 209,  90},
  87        { 208,  88},
  88        { 207,  85},
  89        { 206,  83},
  90        { 205,  80},
  91        { 204,  78},
  92        { 203,  75},
  93        { 202,  73},
  94        { 201,  70},
  95        { 200,  68},
  96        { 199,  65},
  97        { 198,  63},
  98        { 197,  60},
  99        { 196,  58},
 100        { 195,  55},
 101        { 194,  53},
 102        { 193,  50},
 103        { 192,  48},
 104        { 192,  45},
 105        { 191,  43},
 106        { 191,  40},
 107        { 190,  38},
 108        { 190,  35},
 109        { 189,  33},
 110        { 188,  30},
 111        { 187,  28},
 112        { 186,  25},
 113        { 185,  23},
 114        { 184,  20},
 115        { 183,  18},
 116        { 182,  15},
 117        { 181,  13},
 118        { 180,  10},
 119        { 179,   8},
 120        { 178,   5},
 121        {   0,   0},
 122};
 123
 124struct battery_thresh  spitz_battery_levels_noac[] = {
 125        { 213, 100},
 126        { 212,  98},
 127        { 211,  95},
 128        { 210,  93},
 129        { 209,  90},
 130        { 208,  88},
 131        { 207,  85},
 132        { 206,  83},
 133        { 205,  80},
 134        { 204,  78},
 135        { 203,  75},
 136        { 202,  73},
 137        { 201,  70},
 138        { 200,  68},
 139        { 199,  65},
 140        { 198,  63},
 141        { 197,  60},
 142        { 196,  58},
 143        { 195,  55},
 144        { 194,  53},
 145        { 193,  50},
 146        { 192,  48},
 147        { 191,  45},
 148        { 190,  43},
 149        { 189,  40},
 150        { 188,  38},
 151        { 187,  35},
 152        { 186,  33},
 153        { 185,  30},
 154        { 184,  28},
 155        { 183,  25},
 156        { 182,  23},
 157        { 181,  20},
 158        { 180,  18},
 159        { 179,  15},
 160        { 178,  13},
 161        { 177,  10},
 162        { 176,   8},
 163        { 175,   5},
 164        {   0,   0},
 165};
 166
 167/* MAX1111 Commands */
 168#define MAXCTRL_PD0      1u << 0
 169#define MAXCTRL_PD1      1u << 1
 170#define MAXCTRL_SGL      1u << 2
 171#define MAXCTRL_UNI      1u << 3
 172#define MAXCTRL_SEL_SH   4
 173#define MAXCTRL_STR      1u << 7
 174
 175/*
 176 * Read MAX1111 ADC
 177 */
 178int sharpsl_pm_pxa_read_max1111(int channel)
 179{
 180        if (machine_is_tosa()) // Ugly, better move this function into another module
 181            return 0;
 182
 183#ifdef CONFIG_CORGI_SSP_DEPRECATED
 184        return corgi_ssp_max1111_get((channel << MAXCTRL_SEL_SH) | MAXCTRL_PD0 | MAXCTRL_PD1
 185                        | MAXCTRL_SGL | MAXCTRL_UNI | MAXCTRL_STR);
 186#else
 187        extern int max1111_read_channel(int);
 188
 189        /* max1111 accepts channels from 0-3, however,
 190         * it is encoded from 0-7 here in the code.
 191         */
 192        return max1111_read_channel(channel >> 1);
 193#endif
 194}
 195
 196static int get_percentage(int voltage)
 197{
 198        int i = sharpsl_pm.machinfo->bat_levels - 1;
 199        int bl_status = sharpsl_pm.machinfo->backlight_get_status ? sharpsl_pm.machinfo->backlight_get_status() : 0;
 200        struct battery_thresh *thresh;
 201
 202        if (sharpsl_pm.charge_mode == CHRG_ON)
 203                thresh = bl_status ? sharpsl_pm.machinfo->bat_levels_acin_bl : sharpsl_pm.machinfo->bat_levels_acin;
 204        else
 205                thresh = bl_status ? sharpsl_pm.machinfo->bat_levels_noac_bl : sharpsl_pm.machinfo->bat_levels_noac;
 206
 207        while (i > 0 && (voltage > thresh[i].voltage))
 208                i--;
 209
 210        return thresh[i].percentage;
 211}
 212
 213static int get_apm_status(int voltage)
 214{
 215        int low_thresh, high_thresh;
 216
 217        if (sharpsl_pm.charge_mode == CHRG_ON) {
 218                high_thresh = sharpsl_pm.machinfo->status_high_acin;
 219                low_thresh = sharpsl_pm.machinfo->status_low_acin;
 220        } else {
 221                high_thresh = sharpsl_pm.machinfo->status_high_noac;
 222                low_thresh = sharpsl_pm.machinfo->status_low_noac;
 223        }
 224
 225        if (voltage >= high_thresh)
 226                return APM_BATTERY_STATUS_HIGH;
 227        if (voltage >= low_thresh)
 228                return APM_BATTERY_STATUS_LOW;
 229        return APM_BATTERY_STATUS_CRITICAL;
 230}
 231
 232void sharpsl_battery_kick(void)
 233{
 234        schedule_delayed_work(&sharpsl_bat, msecs_to_jiffies(125));
 235}
 236EXPORT_SYMBOL(sharpsl_battery_kick);
 237
 238
 239static void sharpsl_battery_thread(struct work_struct *private_)
 240{
 241        int voltage, percent, apm_status, i = 0;
 242
 243        if (!sharpsl_pm.machinfo)
 244                return;
 245
 246        sharpsl_pm.battstat.ac_status = (sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN) ? APM_AC_ONLINE : APM_AC_OFFLINE);
 247
 248        /* Corgi cannot confirm when battery fully charged so periodically kick! */
 249        if (!sharpsl_pm.machinfo->batfull_irq && (sharpsl_pm.charge_mode == CHRG_ON)
 250                        && time_after(jiffies, sharpsl_pm.charge_start_time +  SHARPSL_CHARGE_ON_TIME_INTERVAL))
 251                schedule_delayed_work(&toggle_charger, 0);
 252
 253        while(1) {
 254                voltage = sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_VOLT);
 255
 256                if (voltage > 0) break;
 257                if (i++ > 5) {
 258                        voltage = sharpsl_pm.machinfo->bat_levels_noac[0].voltage;
 259                        dev_warn(sharpsl_pm.dev, "Warning: Cannot read main battery!\n");
 260                        break;
 261                }
 262        }
 263
 264        voltage = sharpsl_average_value(voltage);
 265        apm_status = get_apm_status(voltage);
 266        percent = get_percentage(voltage);
 267
 268        /* At low battery voltages, the voltage has a tendency to start
 269           creeping back up so we try to avoid this here */
 270        if ((sharpsl_pm.battstat.ac_status == APM_AC_ONLINE) || (apm_status == APM_BATTERY_STATUS_HIGH) ||  percent <= sharpsl_pm.battstat.mainbat_percent) {
 271                sharpsl_pm.battstat.mainbat_voltage = voltage;
 272                sharpsl_pm.battstat.mainbat_status = apm_status;
 273                sharpsl_pm.battstat.mainbat_percent = percent;
 274        }
 275
 276        dev_dbg(sharpsl_pm.dev, "Battery: voltage: %d, status: %d, percentage: %d, time: %ld\n", voltage,
 277                        sharpsl_pm.battstat.mainbat_status, sharpsl_pm.battstat.mainbat_percent, jiffies);
 278
 279#ifdef CONFIG_BACKLIGHT_CORGI
 280        /* If battery is low. limit backlight intensity to save power. */
 281        if ((sharpsl_pm.battstat.ac_status != APM_AC_ONLINE)
 282                        && ((sharpsl_pm.battstat.mainbat_status == APM_BATTERY_STATUS_LOW) ||
 283                        (sharpsl_pm.battstat.mainbat_status == APM_BATTERY_STATUS_CRITICAL))) {
 284                if (!(sharpsl_pm.flags & SHARPSL_BL_LIMIT)) {
 285                        sharpsl_pm.machinfo->backlight_limit(1);
 286                        sharpsl_pm.flags |= SHARPSL_BL_LIMIT;
 287                }
 288        } else if (sharpsl_pm.flags & SHARPSL_BL_LIMIT) {
 289                sharpsl_pm.machinfo->backlight_limit(0);
 290                sharpsl_pm.flags &= ~SHARPSL_BL_LIMIT;
 291        }
 292#endif
 293
 294        /* Suspend if critical battery level */
 295        if ((sharpsl_pm.battstat.ac_status != APM_AC_ONLINE)
 296                        && (sharpsl_pm.battstat.mainbat_status == APM_BATTERY_STATUS_CRITICAL)
 297                        && !(sharpsl_pm.flags & SHARPSL_APM_QUEUED)) {
 298                sharpsl_pm.flags |= SHARPSL_APM_QUEUED;
 299                dev_err(sharpsl_pm.dev, "Fatal Off\n");
 300                apm_queue_event(APM_CRITICAL_SUSPEND);
 301        }
 302
 303        schedule_delayed_work(&sharpsl_bat, SHARPSL_BATCHK_TIME);
 304}
 305
 306void sharpsl_pm_led(int val)
 307{
 308        if (val == SHARPSL_LED_ERROR) {
 309                dev_err(sharpsl_pm.dev, "Charging Error!\n");
 310        } else if (val == SHARPSL_LED_ON) {
 311                dev_dbg(sharpsl_pm.dev, "Charge LED On\n");
 312                led_trigger_event(sharpsl_charge_led_trigger, LED_FULL);
 313        } else {
 314                dev_dbg(sharpsl_pm.dev, "Charge LED Off\n");
 315                led_trigger_event(sharpsl_charge_led_trigger, LED_OFF);
 316        }
 317}
 318
 319static void sharpsl_charge_on(void)
 320{
 321        dev_dbg(sharpsl_pm.dev, "Turning Charger On\n");
 322
 323        sharpsl_pm.full_count = 0;
 324        sharpsl_pm.charge_mode = CHRG_ON;
 325        schedule_delayed_work(&toggle_charger, msecs_to_jiffies(250));
 326        schedule_delayed_work(&sharpsl_bat, msecs_to_jiffies(500));
 327}
 328
 329static void sharpsl_charge_off(void)
 330{
 331        dev_dbg(sharpsl_pm.dev, "Turning Charger Off\n");
 332
 333        sharpsl_pm.machinfo->charge(0);
 334        sharpsl_pm_led(SHARPSL_LED_OFF);
 335        sharpsl_pm.charge_mode = CHRG_OFF;
 336
 337        schedule_delayed_work(&sharpsl_bat, 0);
 338}
 339
 340static void sharpsl_charge_error(void)
 341{
 342        sharpsl_pm_led(SHARPSL_LED_ERROR);
 343        sharpsl_pm.machinfo->charge(0);
 344        sharpsl_pm.charge_mode = CHRG_ERROR;
 345}
 346
 347static void sharpsl_charge_toggle(struct work_struct *private_)
 348{
 349        dev_dbg(sharpsl_pm.dev, "Toogling Charger at time: %lx\n", jiffies);
 350
 351        if (!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN)) {
 352                sharpsl_charge_off();
 353                return;
 354        } else if ((sharpsl_check_battery_temp() < 0) || (sharpsl_ac_check() < 0)) {
 355                sharpsl_charge_error();
 356                return;
 357        }
 358
 359        sharpsl_pm_led(SHARPSL_LED_ON);
 360        sharpsl_pm.machinfo->charge(0);
 361        mdelay(SHARPSL_CHARGE_WAIT_TIME);
 362        sharpsl_pm.machinfo->charge(1);
 363
 364        sharpsl_pm.charge_start_time = jiffies;
 365}
 366
 367static void sharpsl_ac_timer(unsigned long data)
 368{
 369        int acin = sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN);
 370
 371        dev_dbg(sharpsl_pm.dev, "AC Status: %d\n",acin);
 372
 373        sharpsl_average_clear();
 374        if (acin && (sharpsl_pm.charge_mode != CHRG_ON))
 375                sharpsl_charge_on();
 376        else if (sharpsl_pm.charge_mode == CHRG_ON)
 377                sharpsl_charge_off();
 378
 379        schedule_delayed_work(&sharpsl_bat, 0);
 380}
 381
 382
 383static irqreturn_t sharpsl_ac_isr(int irq, void *dev_id)
 384{
 385        /* Delay the event slightly to debounce */
 386        /* Must be a smaller delay than the chrg_full_isr below */
 387        mod_timer(&sharpsl_pm.ac_timer, jiffies + msecs_to_jiffies(250));
 388
 389        return IRQ_HANDLED;
 390}
 391
 392static void sharpsl_chrg_full_timer(unsigned long data)
 393{
 394        dev_dbg(sharpsl_pm.dev, "Charge Full at time: %lx\n", jiffies);
 395
 396        sharpsl_pm.full_count++;
 397
 398        if (!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN)) {
 399                dev_dbg(sharpsl_pm.dev, "Charge Full: AC removed - stop charging!\n");
 400                if (sharpsl_pm.charge_mode == CHRG_ON)
 401                        sharpsl_charge_off();
 402        } else if (sharpsl_pm.full_count < 2) {
 403                dev_dbg(sharpsl_pm.dev, "Charge Full: Count too low\n");
 404                schedule_delayed_work(&toggle_charger, 0);
 405        } else if (time_after(jiffies, sharpsl_pm.charge_start_time + SHARPSL_CHARGE_FINISH_TIME)) {
 406                dev_dbg(sharpsl_pm.dev, "Charge Full: Interrupt generated too slowly - retry.\n");
 407                schedule_delayed_work(&toggle_charger, 0);
 408        } else {
 409                sharpsl_charge_off();
 410                sharpsl_pm.charge_mode = CHRG_DONE;
 411                dev_dbg(sharpsl_pm.dev, "Charge Full: Charging Finished\n");
 412        }
 413}
 414
 415/* Charging Finished Interrupt (Not present on Corgi) */
 416/* Can trigger at the same time as an AC status change so
 417   delay until after that has been processed */
 418static irqreturn_t sharpsl_chrg_full_isr(int irq, void *dev_id)
 419{
 420        if (sharpsl_pm.flags & SHARPSL_SUSPENDED)
 421                return IRQ_HANDLED;
 422
 423        /* delay until after any ac interrupt */
 424        mod_timer(&sharpsl_pm.chrg_full_timer, jiffies + msecs_to_jiffies(500));
 425
 426        return IRQ_HANDLED;
 427}
 428
 429static irqreturn_t sharpsl_fatal_isr(int irq, void *dev_id)
 430{
 431        int is_fatal = 0;
 432
 433        if (!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_LOCK)) {
 434                dev_err(sharpsl_pm.dev, "Battery now Unlocked! Suspending.\n");
 435                is_fatal = 1;
 436        }
 437
 438        if (!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_FATAL)) {
 439                dev_err(sharpsl_pm.dev, "Fatal Batt Error! Suspending.\n");
 440                is_fatal = 1;
 441        }
 442
 443        if (!(sharpsl_pm.flags & SHARPSL_APM_QUEUED) && is_fatal) {
 444                sharpsl_pm.flags |= SHARPSL_APM_QUEUED;
 445                apm_queue_event(APM_CRITICAL_SUSPEND);
 446        }
 447
 448        return IRQ_HANDLED;
 449}
 450
 451/*
 452 * Maintain an average of the last 10 readings
 453 */
 454#define SHARPSL_CNV_VALUE_NUM    10
 455static int sharpsl_ad_index;
 456
 457static void sharpsl_average_clear(void)
 458{
 459        sharpsl_ad_index = 0;
 460}
 461
 462static int sharpsl_average_value(int ad)
 463{
 464        int i, ad_val = 0;
 465        static int sharpsl_ad[SHARPSL_CNV_VALUE_NUM+1];
 466
 467        if (sharpsl_pm.battstat.mainbat_status != APM_BATTERY_STATUS_HIGH) {
 468                sharpsl_ad_index = 0;
 469                return ad;
 470        }
 471
 472        sharpsl_ad[sharpsl_ad_index] = ad;
 473        sharpsl_ad_index++;
 474        if (sharpsl_ad_index >= SHARPSL_CNV_VALUE_NUM) {
 475                for (i=0; i < (SHARPSL_CNV_VALUE_NUM-1); i++)
 476                        sharpsl_ad[i] = sharpsl_ad[i+1];
 477                sharpsl_ad_index = SHARPSL_CNV_VALUE_NUM - 1;
 478        }
 479        for (i=0; i < sharpsl_ad_index; i++)
 480                ad_val += sharpsl_ad[i];
 481
 482        return (ad_val / sharpsl_ad_index);
 483}
 484
 485/*
 486 * Take an array of 5 integers, remove the maximum and minimum values
 487 * and return the average.
 488 */
 489static int get_select_val(int *val)
 490{
 491        int i, j, k, temp, sum = 0;
 492
 493        /* Find MAX val */
 494        temp = val[0];
 495        j=0;
 496        for (i=1; i<5; i++) {
 497                if (temp < val[i]) {
 498                        temp = val[i];
 499                        j = i;
 500                }
 501        }
 502
 503        /* Find MIN val */
 504        temp = val[4];
 505        k=4;
 506        for (i=3; i>=0; i--) {
 507                if (temp > val[i]) {
 508                        temp = val[i];
 509                        k = i;
 510                }
 511        }
 512
 513        for (i=0; i<5; i++)
 514                if (i != j && i != k )
 515                        sum += val[i];
 516
 517        dev_dbg(sharpsl_pm.dev, "Average: %d from values: %d, %d, %d, %d, %d\n", sum/3, val[0], val[1], val[2], val[3], val[4]);
 518
 519        return (sum/3);
 520}
 521
 522static int sharpsl_check_battery_temp(void)
 523{
 524        int val, i, buff[5];
 525
 526        /* Check battery temperature */
 527        for (i=0; i<5; i++) {
 528                mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_TEMP);
 529                sharpsl_pm.machinfo->measure_temp(1);
 530                mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_TEMP);
 531                buff[i] = sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_TEMP);
 532                sharpsl_pm.machinfo->measure_temp(0);
 533        }
 534
 535        val = get_select_val(buff);
 536
 537        dev_dbg(sharpsl_pm.dev, "Temperature: %d\n", val);
 538        if (val > sharpsl_pm.machinfo->charge_on_temp) {
 539                printk(KERN_WARNING "Not charging: temperature out of limits.\n");
 540                return -1;
 541        }
 542
 543        return 0;
 544}
 545
 546#ifdef CONFIG_PM
 547static int sharpsl_check_battery_voltage(void)
 548{
 549        int val, i, buff[5];
 550
 551        /* disable charge, enable discharge */
 552        sharpsl_pm.machinfo->charge(0);
 553        sharpsl_pm.machinfo->discharge(1);
 554        mdelay(SHARPSL_WAIT_DISCHARGE_ON);
 555
 556        if (sharpsl_pm.machinfo->discharge1)
 557                sharpsl_pm.machinfo->discharge1(1);
 558
 559        /* Check battery voltage */
 560        for (i=0; i<5; i++) {
 561                buff[i] = sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_VOLT);
 562                mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_VOLT);
 563        }
 564
 565        if (sharpsl_pm.machinfo->discharge1)
 566                sharpsl_pm.machinfo->discharge1(0);
 567
 568        sharpsl_pm.machinfo->discharge(0);
 569
 570        val = get_select_val(buff);
 571        dev_dbg(sharpsl_pm.dev, "Battery Voltage: %d\n", val);
 572
 573        if (val < sharpsl_pm.machinfo->charge_on_volt)
 574                return -1;
 575
 576        return 0;
 577}
 578#endif
 579
 580static int sharpsl_ac_check(void)
 581{
 582        int temp, i, buff[5];
 583
 584        for (i=0; i<5; i++) {
 585                buff[i] = sharpsl_pm.machinfo->read_devdata(SHARPSL_ACIN_VOLT);
 586                mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_ACIN);
 587        }
 588
 589        temp = get_select_val(buff);
 590        dev_dbg(sharpsl_pm.dev, "AC Voltage: %d\n",temp);
 591
 592        if ((temp > sharpsl_pm.machinfo->charge_acin_high) || (temp < sharpsl_pm.machinfo->charge_acin_low)) {
 593                dev_err(sharpsl_pm.dev, "Error: AC check failed.\n");
 594                return -1;
 595        }
 596
 597        return 0;
 598}
 599
 600#ifdef CONFIG_PM
 601static int sharpsl_pm_suspend(struct platform_device *pdev, pm_message_t state)
 602{
 603        sharpsl_pm.flags |= SHARPSL_SUSPENDED;
 604        flush_scheduled_work();
 605
 606        if (sharpsl_pm.charge_mode == CHRG_ON)
 607                sharpsl_pm.flags |= SHARPSL_DO_OFFLINE_CHRG;
 608        else
 609                sharpsl_pm.flags &= ~SHARPSL_DO_OFFLINE_CHRG;
 610
 611        return 0;
 612}
 613
 614static int sharpsl_pm_resume(struct platform_device *pdev)
 615{
 616        /* Clear the reset source indicators as they break the bootloader upon reboot */
 617        RCSR = 0x0f;
 618        sharpsl_average_clear();
 619        sharpsl_pm.flags &= ~SHARPSL_APM_QUEUED;
 620        sharpsl_pm.flags &= ~SHARPSL_SUSPENDED;
 621
 622        return 0;
 623}
 624
 625static void corgi_goto_sleep(unsigned long alarm_time, unsigned int alarm_enable, suspend_state_t state)
 626{
 627        dev_dbg(sharpsl_pm.dev, "Time is: %08x\n",RCNR);
 628
 629        dev_dbg(sharpsl_pm.dev, "Offline Charge Activate = %d\n",sharpsl_pm.flags & SHARPSL_DO_OFFLINE_CHRG);
 630        /* not charging and AC-IN! */
 631
 632        if ((sharpsl_pm.flags & SHARPSL_DO_OFFLINE_CHRG) && (sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN))) {
 633                dev_dbg(sharpsl_pm.dev, "Activating Offline Charger...\n");
 634                sharpsl_pm.charge_mode = CHRG_OFF;
 635                sharpsl_pm.flags &= ~SHARPSL_DO_OFFLINE_CHRG;
 636                sharpsl_off_charge_battery();
 637        }
 638
 639        sharpsl_pm.machinfo->presuspend();
 640
 641        PEDR = 0xffffffff; /* clear it */
 642
 643        sharpsl_pm.flags &= ~SHARPSL_ALARM_ACTIVE;
 644        if ((sharpsl_pm.charge_mode == CHRG_ON) && ((alarm_enable && ((alarm_time - RCNR) > (SHARPSL_BATCHK_TIME_SUSPEND + 30))) || !alarm_enable)) {
 645                RTSR &= RTSR_ALE;
 646                RTAR = RCNR + SHARPSL_BATCHK_TIME_SUSPEND;
 647                dev_dbg(sharpsl_pm.dev, "Charging alarm at: %08x\n",RTAR);
 648                sharpsl_pm.flags |= SHARPSL_ALARM_ACTIVE;
 649        } else if (alarm_enable) {
 650                RTSR &= RTSR_ALE;
 651                RTAR = alarm_time;
 652                dev_dbg(sharpsl_pm.dev, "User alarm at: %08x\n",RTAR);
 653        } else {
 654                dev_dbg(sharpsl_pm.dev, "No alarms set.\n");
 655        }
 656
 657        pxa_pm_enter(state);
 658
 659        sharpsl_pm.machinfo->postsuspend();
 660
 661        dev_dbg(sharpsl_pm.dev, "Corgi woken up from suspend: %08x\n",PEDR);
 662}
 663
 664static int corgi_enter_suspend(unsigned long alarm_time, unsigned int alarm_enable, suspend_state_t state)
 665{
 666        if (!sharpsl_pm.machinfo->should_wakeup(!(sharpsl_pm.flags & SHARPSL_ALARM_ACTIVE) && alarm_enable) )
 667        {
 668                if (!(sharpsl_pm.flags & SHARPSL_ALARM_ACTIVE)) {
 669                        dev_dbg(sharpsl_pm.dev, "No user triggered wakeup events and not charging. Strange. Suspend.\n");
 670                        corgi_goto_sleep(alarm_time, alarm_enable, state);
 671                        return 1;
 672                }
 673                if(sharpsl_off_charge_battery()) {
 674                        dev_dbg(sharpsl_pm.dev, "Charging. Suspend...\n");
 675                        corgi_goto_sleep(alarm_time, alarm_enable, state);
 676                        return 1;
 677                }
 678                dev_dbg(sharpsl_pm.dev, "User triggered wakeup in offline charger.\n");
 679        }
 680
 681        if ((!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_LOCK)) ||
 682            (!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_FATAL))) {
 683                dev_err(sharpsl_pm.dev, "Fatal condition. Suspend.\n");
 684                corgi_goto_sleep(alarm_time, alarm_enable, state);
 685                return 1;
 686        }
 687
 688        return 0;
 689}
 690
 691static int corgi_pxa_pm_enter(suspend_state_t state)
 692{
 693        unsigned long alarm_time = RTAR;
 694        unsigned int alarm_status = ((RTSR & RTSR_ALE) != 0);
 695
 696        dev_dbg(sharpsl_pm.dev, "SharpSL suspending for first time.\n");
 697
 698        corgi_goto_sleep(alarm_time, alarm_status, state);
 699
 700        while (corgi_enter_suspend(alarm_time,alarm_status,state))
 701                {}
 702
 703        if (sharpsl_pm.machinfo->earlyresume)
 704                sharpsl_pm.machinfo->earlyresume();
 705
 706        dev_dbg(sharpsl_pm.dev, "SharpSL resuming...\n");
 707
 708        return 0;
 709}
 710
 711/*
 712 * Check for fatal battery errors
 713 * Fatal returns -1
 714 */
 715static int sharpsl_fatal_check(void)
 716{
 717        int buff[5], temp, i, acin;
 718
 719        dev_dbg(sharpsl_pm.dev, "sharpsl_fatal_check entered\n");
 720
 721        /* Check AC-Adapter */
 722        acin = sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN);
 723
 724        if (acin && (sharpsl_pm.charge_mode == CHRG_ON)) {
 725                sharpsl_pm.machinfo->charge(0);
 726                udelay(100);
 727                sharpsl_pm.machinfo->discharge(1);      /* enable discharge */
 728                mdelay(SHARPSL_WAIT_DISCHARGE_ON);
 729        }
 730
 731        if (sharpsl_pm.machinfo->discharge1)
 732                sharpsl_pm.machinfo->discharge1(1);
 733
 734        /* Check battery : check inserting battery ? */
 735        for (i=0; i<5; i++) {
 736                buff[i] = sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_VOLT);
 737                mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_VOLT);
 738        }
 739
 740        if (sharpsl_pm.machinfo->discharge1)
 741                sharpsl_pm.machinfo->discharge1(0);
 742
 743        if (acin && (sharpsl_pm.charge_mode == CHRG_ON)) {
 744                udelay(100);
 745                sharpsl_pm.machinfo->charge(1);
 746                sharpsl_pm.machinfo->discharge(0);
 747        }
 748
 749        temp = get_select_val(buff);
 750        dev_dbg(sharpsl_pm.dev, "sharpsl_fatal_check: acin: %d, discharge voltage: %d, no discharge: %ld\n", acin, temp, sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_VOLT));
 751
 752        if ((acin && (temp < sharpsl_pm.machinfo->fatal_acin_volt)) ||
 753                        (!acin && (temp < sharpsl_pm.machinfo->fatal_noacin_volt)))
 754                return -1;
 755        return 0;
 756}
 757
 758static int sharpsl_off_charge_error(void)
 759{
 760        dev_err(sharpsl_pm.dev, "Offline Charger: Error occurred.\n");
 761        sharpsl_pm.machinfo->charge(0);
 762        sharpsl_pm_led(SHARPSL_LED_ERROR);
 763        sharpsl_pm.charge_mode = CHRG_ERROR;
 764        return 1;
 765}
 766
 767/*
 768 * Charging Control while suspended
 769 * Return 1 - go straight to sleep
 770 * Return 0 - sleep or wakeup depending on other factors
 771 */
 772static int sharpsl_off_charge_battery(void)
 773{
 774        int time;
 775
 776        dev_dbg(sharpsl_pm.dev, "Charge Mode: %d\n", sharpsl_pm.charge_mode);
 777
 778        if (sharpsl_pm.charge_mode == CHRG_OFF) {
 779                dev_dbg(sharpsl_pm.dev, "Offline Charger: Step 1\n");
 780
 781                /* AC Check */
 782                if ((sharpsl_ac_check() < 0) || (sharpsl_check_battery_temp() < 0))
 783                        return sharpsl_off_charge_error();
 784
 785                /* Start Charging */
 786                sharpsl_pm_led(SHARPSL_LED_ON);
 787                sharpsl_pm.machinfo->charge(0);
 788                mdelay(SHARPSL_CHARGE_WAIT_TIME);
 789                sharpsl_pm.machinfo->charge(1);
 790
 791                sharpsl_pm.charge_mode = CHRG_ON;
 792                sharpsl_pm.full_count = 0;
 793
 794                return 1;
 795        } else if (sharpsl_pm.charge_mode != CHRG_ON) {
 796                return 1;
 797        }
 798
 799        if (sharpsl_pm.full_count == 0) {
 800                int time;
 801
 802                dev_dbg(sharpsl_pm.dev, "Offline Charger: Step 2\n");
 803
 804                if ((sharpsl_check_battery_temp() < 0) || (sharpsl_check_battery_voltage() < 0))
 805                        return sharpsl_off_charge_error();
 806
 807                sharpsl_pm.machinfo->charge(0);
 808                mdelay(SHARPSL_CHARGE_WAIT_TIME);
 809                sharpsl_pm.machinfo->charge(1);
 810                sharpsl_pm.charge_mode = CHRG_ON;
 811
 812                mdelay(SHARPSL_CHARGE_CO_CHECK_TIME);
 813
 814                time = RCNR;
 815                while(1) {
 816                        /* Check if any wakeup event had occurred */
 817                        if (sharpsl_pm.machinfo->charger_wakeup() != 0)
 818                                return 0;
 819                        /* Check for timeout */
 820                        if ((RCNR - time) > SHARPSL_WAIT_CO_TIME)
 821                                return 1;
 822                        if (sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_CHRGFULL)) {
 823                                dev_dbg(sharpsl_pm.dev, "Offline Charger: Charge full occurred. Retrying to check\n");
 824                                sharpsl_pm.full_count++;
 825                                sharpsl_pm.machinfo->charge(0);
 826                                mdelay(SHARPSL_CHARGE_WAIT_TIME);
 827                                sharpsl_pm.machinfo->charge(1);
 828                                return 1;
 829                        }
 830                }
 831        }
 832
 833        dev_dbg(sharpsl_pm.dev, "Offline Charger: Step 3\n");
 834
 835        mdelay(SHARPSL_CHARGE_CO_CHECK_TIME);
 836
 837        time = RCNR;
 838        while(1) {
 839                /* Check if any wakeup event had occurred */
 840                if (sharpsl_pm.machinfo->charger_wakeup() != 0)
 841                        return 0;
 842                /* Check for timeout */
 843                if ((RCNR-time) > SHARPSL_WAIT_CO_TIME) {
 844                        if (sharpsl_pm.full_count > SHARPSL_CHARGE_RETRY_CNT) {
 845                                dev_dbg(sharpsl_pm.dev, "Offline Charger: Not charged sufficiently. Retrying.\n");
 846                                sharpsl_pm.full_count = 0;
 847                        }
 848                        sharpsl_pm.full_count++;
 849                        return 1;
 850                }
 851                if (sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_CHRGFULL)) {
 852                        dev_dbg(sharpsl_pm.dev, "Offline Charger: Charging complete.\n");
 853                        sharpsl_pm_led(SHARPSL_LED_OFF);
 854                        sharpsl_pm.machinfo->charge(0);
 855                        sharpsl_pm.charge_mode = CHRG_DONE;
 856                        return 1;
 857                }
 858        }
 859}
 860#else
 861#define sharpsl_pm_suspend      NULL
 862#define sharpsl_pm_resume       NULL
 863#endif
 864
 865static ssize_t battery_percentage_show(struct device *dev, struct device_attribute *attr, char *buf)
 866{
 867        return sprintf(buf, "%d\n",sharpsl_pm.battstat.mainbat_percent);
 868}
 869
 870static ssize_t battery_voltage_show(struct device *dev, struct device_attribute *attr, char *buf)
 871{
 872        return sprintf(buf, "%d\n",sharpsl_pm.battstat.mainbat_voltage);
 873}
 874
 875static DEVICE_ATTR(battery_percentage, 0444, battery_percentage_show, NULL);
 876static DEVICE_ATTR(battery_voltage, 0444, battery_voltage_show, NULL);
 877
 878extern void (*apm_get_power_status)(struct apm_power_info *);
 879
 880static void sharpsl_apm_get_power_status(struct apm_power_info *info)
 881{
 882        info->ac_line_status = sharpsl_pm.battstat.ac_status;
 883
 884        if (sharpsl_pm.charge_mode == CHRG_ON)
 885                info->battery_status = APM_BATTERY_STATUS_CHARGING;
 886        else
 887                info->battery_status = sharpsl_pm.battstat.mainbat_status;
 888
 889        info->battery_flag = (1 << info->battery_status);
 890        info->battery_life = sharpsl_pm.battstat.mainbat_percent;
 891}
 892
 893#ifdef CONFIG_PM
 894static struct platform_suspend_ops sharpsl_pm_ops = {
 895        .prepare        = pxa_pm_prepare,
 896        .finish         = pxa_pm_finish,
 897        .enter          = corgi_pxa_pm_enter,
 898        .valid          = suspend_valid_only_mem,
 899};
 900#endif
 901
 902static int __init sharpsl_pm_probe(struct platform_device *pdev)
 903{
 904        int ret;
 905
 906        if (!pdev->dev.platform_data)
 907                return -EINVAL;
 908
 909        sharpsl_pm.dev = &pdev->dev;
 910        sharpsl_pm.machinfo = pdev->dev.platform_data;
 911        sharpsl_pm.charge_mode = CHRG_OFF;
 912        sharpsl_pm.flags = 0;
 913
 914        init_timer(&sharpsl_pm.ac_timer);
 915        sharpsl_pm.ac_timer.function = sharpsl_ac_timer;
 916
 917        init_timer(&sharpsl_pm.chrg_full_timer);
 918        sharpsl_pm.chrg_full_timer.function = sharpsl_chrg_full_timer;
 919
 920        led_trigger_register_simple("sharpsl-charge", &sharpsl_charge_led_trigger);
 921
 922        sharpsl_pm.machinfo->init();
 923
 924        gpio_request(sharpsl_pm.machinfo->gpio_acin, "AC IN");
 925        gpio_direction_input(sharpsl_pm.machinfo->gpio_acin);
 926        gpio_request(sharpsl_pm.machinfo->gpio_batfull, "Battery Full");
 927        gpio_direction_input(sharpsl_pm.machinfo->gpio_batfull);
 928        gpio_request(sharpsl_pm.machinfo->gpio_batlock, "Battery Lock");
 929        gpio_direction_input(sharpsl_pm.machinfo->gpio_batlock);
 930
 931        /* Register interrupt handlers */
 932        if (request_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_acin), sharpsl_ac_isr, IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "AC Input Detect", sharpsl_ac_isr)) {
 933                dev_err(sharpsl_pm.dev, "Could not get irq %d.\n", IRQ_GPIO(sharpsl_pm.machinfo->gpio_acin));
 934        }
 935
 936        if (request_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batlock), sharpsl_fatal_isr, IRQF_DISABLED | IRQF_TRIGGER_FALLING, "Battery Cover", sharpsl_fatal_isr)) {
 937                dev_err(sharpsl_pm.dev, "Could not get irq %d.\n", IRQ_GPIO(sharpsl_pm.machinfo->gpio_batlock));
 938        }
 939
 940        if (sharpsl_pm.machinfo->gpio_fatal) {
 941                if (request_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_fatal), sharpsl_fatal_isr, IRQF_DISABLED | IRQF_TRIGGER_FALLING, "Fatal Battery", sharpsl_fatal_isr)) {
 942                        dev_err(sharpsl_pm.dev, "Could not get irq %d.\n", IRQ_GPIO(sharpsl_pm.machinfo->gpio_fatal));
 943                }
 944        }
 945
 946        if (sharpsl_pm.machinfo->batfull_irq)
 947        {
 948                /* Register interrupt handler. */
 949                if (request_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batfull), sharpsl_chrg_full_isr, IRQF_DISABLED | IRQF_TRIGGER_RISING, "CO", sharpsl_chrg_full_isr)) {
 950                        dev_err(sharpsl_pm.dev, "Could not get irq %d.\n", IRQ_GPIO(sharpsl_pm.machinfo->gpio_batfull));
 951                }
 952        }
 953
 954        ret = device_create_file(&pdev->dev, &dev_attr_battery_percentage);
 955        ret |= device_create_file(&pdev->dev, &dev_attr_battery_voltage);
 956        if (ret != 0)
 957                dev_warn(&pdev->dev, "Failed to register attributes (%d)\n", ret);
 958
 959        apm_get_power_status = sharpsl_apm_get_power_status;
 960
 961#ifdef CONFIG_PM
 962        suspend_set_ops(&sharpsl_pm_ops);
 963#endif
 964
 965        mod_timer(&sharpsl_pm.ac_timer, jiffies + msecs_to_jiffies(250));
 966
 967        return 0;
 968}
 969
 970static int sharpsl_pm_remove(struct platform_device *pdev)
 971{
 972        suspend_set_ops(NULL);
 973
 974        device_remove_file(&pdev->dev, &dev_attr_battery_percentage);
 975        device_remove_file(&pdev->dev, &dev_attr_battery_voltage);
 976
 977        led_trigger_unregister_simple(sharpsl_charge_led_trigger);
 978
 979        free_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_acin), sharpsl_ac_isr);
 980        free_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batlock), sharpsl_fatal_isr);
 981
 982        if (sharpsl_pm.machinfo->gpio_fatal)
 983                free_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_fatal), sharpsl_fatal_isr);
 984
 985        if (sharpsl_pm.machinfo->batfull_irq)
 986                free_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batfull), sharpsl_chrg_full_isr);
 987
 988        gpio_free(sharpsl_pm.machinfo->gpio_batlock);
 989        gpio_free(sharpsl_pm.machinfo->gpio_batfull);
 990        gpio_free(sharpsl_pm.machinfo->gpio_acin);
 991
 992        if (sharpsl_pm.machinfo->exit)
 993                sharpsl_pm.machinfo->exit();
 994
 995        del_timer_sync(&sharpsl_pm.chrg_full_timer);
 996        del_timer_sync(&sharpsl_pm.ac_timer);
 997
 998        return 0;
 999}
1000
1001static struct platform_driver sharpsl_pm_driver = {
1002        .probe          = sharpsl_pm_probe,
1003        .remove         = sharpsl_pm_remove,
1004        .suspend        = sharpsl_pm_suspend,
1005        .resume         = sharpsl_pm_resume,
1006        .driver         = {
1007                .name           = "sharpsl-pm",
1008        },
1009};
1010
1011static int __devinit sharpsl_pm_init(void)
1012{
1013        return platform_driver_register(&sharpsl_pm_driver);
1014}
1015
1016static void sharpsl_pm_exit(void)
1017{
1018        platform_driver_unregister(&sharpsl_pm_driver);
1019}
1020
1021late_initcall(sharpsl_pm_init);
1022module_exit(sharpsl_pm_exit);
1023