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