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