linux/arch/arm/mach-pxa/spitz_pm.c
<<
>>
Prefs
   1/*
   2 * Battery and Power Management code for the Sharp SL-Cxx00
   3 *
   4 * Copyright (c) 2005 Richard Purdie
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2 as
   8 * published by the Free Software Foundation.
   9 *
  10 */
  11
  12#include <linux/module.h>
  13#include <linux/stat.h>
  14#include <linux/init.h>
  15#include <linux/kernel.h>
  16#include <linux/delay.h>
  17#include <linux/gpio.h>
  18#include <linux/interrupt.h>
  19#include <linux/platform_device.h>
  20#include <linux/apm-emulation.h>
  21
  22#include <asm/irq.h>
  23#include <asm/mach-types.h>
  24#include <mach/hardware.h>
  25
  26#include <mach/spitz.h>
  27#include <mach/pxa27x.h>
  28#include <mach/sharpsl_pm.h>
  29
  30#include "generic.h"
  31
  32#define SHARPSL_CHARGE_ON_VOLT         0x99  /* 2.9V */
  33#define SHARPSL_CHARGE_ON_TEMP         0xe0  /* 2.9V */
  34#define SHARPSL_CHARGE_ON_ACIN_HIGH    0x9b  /* 6V */
  35#define SHARPSL_CHARGE_ON_ACIN_LOW     0x34  /* 2V */
  36#define SHARPSL_FATAL_ACIN_VOLT        182   /* 3.45V */
  37#define SHARPSL_FATAL_NOACIN_VOLT      170   /* 3.40V */
  38
  39static int spitz_last_ac_status;
  40
  41static struct gpio spitz_charger_gpios[] = {
  42        { SPITZ_GPIO_KEY_INT,   GPIOF_IN, "Keyboard Interrupt" },
  43        { SPITZ_GPIO_SYNC,      GPIOF_IN, "Sync" },
  44        { SPITZ_GPIO_ADC_TEMP_ON, GPIOF_OUT_INIT_LOW, "ADC Temp On" },
  45        { SPITZ_GPIO_JK_B,        GPIOF_OUT_INIT_LOW, "JK B" },
  46        { SPITZ_GPIO_CHRG_ON,     GPIOF_OUT_INIT_LOW, "Charger On" },
  47};
  48
  49static void spitz_charger_init(void)
  50{
  51        gpio_request_array(ARRAY_AND_SIZE(spitz_charger_gpios));
  52}
  53
  54static void spitz_measure_temp(int on)
  55{
  56        gpio_set_value(SPITZ_GPIO_ADC_TEMP_ON, on);
  57}
  58
  59static void spitz_charge(int on)
  60{
  61        if (on) {
  62                if (sharpsl_pm.flags & SHARPSL_SUSPENDED) {
  63                        gpio_set_value(SPITZ_GPIO_JK_B, 1);
  64                        gpio_set_value(SPITZ_GPIO_CHRG_ON, 0);
  65                } else {
  66                        gpio_set_value(SPITZ_GPIO_JK_B, 0);
  67                        gpio_set_value(SPITZ_GPIO_CHRG_ON, 0);
  68                }
  69        } else {
  70                gpio_set_value(SPITZ_GPIO_JK_B, 0);
  71                gpio_set_value(SPITZ_GPIO_CHRG_ON, 1);
  72        }
  73}
  74
  75static void spitz_discharge(int on)
  76{
  77        gpio_set_value(SPITZ_GPIO_JK_A, on);
  78}
  79
  80/* HACK - For unknown reasons, accurate voltage readings are only made with a load
  81   on the power bus which the green led on spitz provides */
  82static void spitz_discharge1(int on)
  83{
  84        gpio_set_value(SPITZ_GPIO_LED_GREEN, on);
  85}
  86
  87static unsigned long gpio18_config[] = {
  88        GPIO18_RDY,
  89        GPIO18_GPIO,
  90};
  91
  92static void spitz_presuspend(void)
  93{
  94        spitz_last_ac_status = sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN);
  95
  96        /* GPIO Sleep Register */
  97        PGSR0 = 0x00144018;
  98        PGSR1 = 0x00EF0000;
  99        if (machine_is_akita()) {
 100                PGSR2 = 0x2121C000;
 101                PGSR3 = 0x00600400;
 102        } else {
 103                PGSR2 = 0x0121C000;
 104                PGSR3 = 0x00600000;
 105        }
 106
 107        PGSR0 &= ~SPITZ_GPIO_G0_STROBE_BIT;
 108        PGSR1 &= ~SPITZ_GPIO_G1_STROBE_BIT;
 109        PGSR2 &= ~SPITZ_GPIO_G2_STROBE_BIT;
 110        PGSR3 &= ~SPITZ_GPIO_G3_STROBE_BIT;
 111        PGSR2 |= GPIO_bit(SPITZ_GPIO_KEY_STROBE0);
 112
 113        pxa2xx_mfp_config(&gpio18_config[0], 1);
 114        gpio_request_one(18, GPIOF_OUT_INIT_HIGH, "Unknown");
 115        gpio_free(18);
 116
 117        PRER = GPIO_bit(SPITZ_GPIO_KEY_INT);
 118        PFER = GPIO_bit(SPITZ_GPIO_KEY_INT) | GPIO_bit(SPITZ_GPIO_RESET);
 119        PWER = GPIO_bit(SPITZ_GPIO_KEY_INT) | GPIO_bit(SPITZ_GPIO_RESET) | PWER_RTC;
 120        PKWR = GPIO_bit(SPITZ_GPIO_SYNC) | GPIO_bit(SPITZ_GPIO_KEY_INT) | GPIO_bit(SPITZ_GPIO_RESET);
 121        PKSR = 0xffffffff; /* clear */
 122
 123        /* nRESET_OUT Disable */
 124        PSLR |= PSLR_SL_ROD;
 125
 126        /* Stop 3.6MHz and drive HIGH to PCMCIA and CS */
 127        PCFR = PCFR_GPR_EN | PCFR_OPDE;
 128}
 129
 130static void spitz_postsuspend(void)
 131{
 132        pxa2xx_mfp_config(&gpio18_config[1], 1);
 133}
 134
 135static int spitz_should_wakeup(unsigned int resume_on_alarm)
 136{
 137        int is_resume = 0;
 138        int acin = sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN);
 139
 140        if (spitz_last_ac_status != acin) {
 141                if (acin) {
 142                        /* charge on */
 143                        sharpsl_pm.flags |= SHARPSL_DO_OFFLINE_CHRG;
 144                        dev_dbg(sharpsl_pm.dev, "AC Inserted\n");
 145                } else {
 146                        /* charge off */
 147                        dev_dbg(sharpsl_pm.dev, "AC Removed\n");
 148                        sharpsl_pm_led(SHARPSL_LED_OFF);
 149                        sharpsl_pm.machinfo->charge(0);
 150                        sharpsl_pm.charge_mode = CHRG_OFF;
 151                }
 152                spitz_last_ac_status = acin;
 153                /* Return to suspend as this must be what we were woken for */
 154                return 0;
 155        }
 156
 157        if (PEDR & GPIO_bit(SPITZ_GPIO_KEY_INT))
 158                is_resume |= GPIO_bit(SPITZ_GPIO_KEY_INT);
 159
 160        if (PKSR & GPIO_bit(SPITZ_GPIO_SYNC))
 161                is_resume |= GPIO_bit(SPITZ_GPIO_SYNC);
 162
 163        if (resume_on_alarm && (PEDR & PWER_RTC))
 164                is_resume |= PWER_RTC;
 165
 166        dev_dbg(sharpsl_pm.dev, "is_resume: %x\n", is_resume);
 167        return is_resume;
 168}
 169
 170static unsigned long spitz_charger_wakeup(void)
 171{
 172        return (~GPLR0 & GPIO_bit(SPITZ_GPIO_KEY_INT)) | (GPLR0 & GPIO_bit(SPITZ_GPIO_SYNC));
 173}
 174
 175unsigned long spitzpm_read_devdata(int type)
 176{
 177        switch (type) {
 178        case SHARPSL_STATUS_ACIN:
 179                return (((~GPLR(SPITZ_GPIO_AC_IN)) & GPIO_bit(SPITZ_GPIO_AC_IN)) != 0);
 180        case SHARPSL_STATUS_LOCK:
 181                return gpio_get_value(sharpsl_pm.machinfo->gpio_batlock);
 182        case SHARPSL_STATUS_CHRGFULL:
 183                return gpio_get_value(sharpsl_pm.machinfo->gpio_batfull);
 184        case SHARPSL_STATUS_FATAL:
 185                return gpio_get_value(sharpsl_pm.machinfo->gpio_fatal);
 186        case SHARPSL_ACIN_VOLT:
 187                return sharpsl_pm_pxa_read_max1111(MAX1111_ACIN_VOLT);
 188        case SHARPSL_BATT_TEMP:
 189                return sharpsl_pm_pxa_read_max1111(MAX1111_BATT_TEMP);
 190        case SHARPSL_BATT_VOLT:
 191        default:
 192                return sharpsl_pm_pxa_read_max1111(MAX1111_BATT_VOLT);
 193        }
 194}
 195
 196struct sharpsl_charger_machinfo spitz_pm_machinfo = {
 197        .init             = spitz_charger_init,
 198        .exit             = NULL,
 199        .gpio_batlock     = SPITZ_GPIO_BAT_COVER,
 200        .gpio_acin        = SPITZ_GPIO_AC_IN,
 201        .gpio_batfull     = SPITZ_GPIO_CHRG_FULL,
 202        .batfull_irq      = 1,
 203        .gpio_fatal       = SPITZ_GPIO_FATAL_BAT,
 204        .discharge        = spitz_discharge,
 205        .discharge1       = spitz_discharge1,
 206        .charge           = spitz_charge,
 207        .measure_temp     = spitz_measure_temp,
 208        .presuspend       = spitz_presuspend,
 209        .postsuspend      = spitz_postsuspend,
 210        .read_devdata     = spitzpm_read_devdata,
 211        .charger_wakeup   = spitz_charger_wakeup,
 212        .should_wakeup    = spitz_should_wakeup,
 213#if defined(CONFIG_LCD_CORGI)
 214        .backlight_limit = corgi_lcd_limit_intensity,
 215#endif
 216        .charge_on_volt   = SHARPSL_CHARGE_ON_VOLT,
 217        .charge_on_temp   = SHARPSL_CHARGE_ON_TEMP,
 218        .charge_acin_high = SHARPSL_CHARGE_ON_ACIN_HIGH,
 219        .charge_acin_low  = SHARPSL_CHARGE_ON_ACIN_LOW,
 220        .fatal_acin_volt  = SHARPSL_FATAL_ACIN_VOLT,
 221        .fatal_noacin_volt= SHARPSL_FATAL_NOACIN_VOLT,
 222        .bat_levels       = 40,
 223        .bat_levels_noac  = sharpsl_battery_levels_noac,
 224        .bat_levels_acin  = sharpsl_battery_levels_acin,
 225        .status_high_acin = 188,
 226        .status_low_acin  = 178,
 227        .status_high_noac = 185,
 228        .status_low_noac  = 175,
 229};
 230
 231static struct platform_device *spitzpm_device;
 232
 233static int __devinit spitzpm_init(void)
 234{
 235        int ret;
 236
 237        if (!machine_is_spitz() && !machine_is_akita()
 238                        && !machine_is_borzoi())
 239                return -ENODEV;
 240
 241        spitzpm_device = platform_device_alloc("sharpsl-pm", -1);
 242        if (!spitzpm_device)
 243                return -ENOMEM;
 244
 245        spitzpm_device->dev.platform_data = &spitz_pm_machinfo;
 246        ret = platform_device_add(spitzpm_device);
 247
 248        if (ret)
 249                platform_device_put(spitzpm_device);
 250
 251        return ret;
 252}
 253
 254static void spitzpm_exit(void)
 255{
 256        platform_device_unregister(spitzpm_device);
 257}
 258
 259module_init(spitzpm_init);
 260module_exit(spitzpm_exit);
 261
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.