diff options
Diffstat (limited to 'arch/arm/mach-pxa/corgi_pm.c')
-rw-r--r-- | arch/arm/mach-pxa/corgi_pm.c | 231 |
1 files changed, 231 insertions, 0 deletions
diff --git a/arch/arm/mach-pxa/corgi_pm.c b/arch/arm/mach-pxa/corgi_pm.c new file mode 100644 index 00000000..048c4299 --- /dev/null +++ b/arch/arm/mach-pxa/corgi_pm.c @@ -0,0 +1,231 @@ +/* + * Battery and Power Management code for the Sharp SL-C7xx + * + * Copyright (c) 2005 Richard Purdie + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include <linux/module.h> +#include <linux/stat.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/gpio.h> +#include <linux/gpio-pxa.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/apm-emulation.h> +#include <linux/io.h> + +#include <asm/irq.h> +#include <asm/mach-types.h> +#include <mach/hardware.h> + +#include <mach/corgi.h> +#include <mach/pxa2xx-regs.h> +#include <mach/sharpsl_pm.h> + +#include "generic.h" + +#define SHARPSL_CHARGE_ON_VOLT 0x99 /* 2.9V */ +#define SHARPSL_CHARGE_ON_TEMP 0xe0 /* 2.9V */ +#define SHARPSL_CHARGE_ON_ACIN_HIGH 0x9b /* 6V */ +#define SHARPSL_CHARGE_ON_ACIN_LOW 0x34 /* 2V */ +#define SHARPSL_FATAL_ACIN_VOLT 182 /* 3.45V */ +#define SHARPSL_FATAL_NOACIN_VOLT 170 /* 3.40V */ + +static struct gpio charger_gpios[] = { + { CORGI_GPIO_ADC_TEMP_ON, GPIOF_OUT_INIT_LOW, "ADC Temp On" }, + { CORGI_GPIO_CHRG_ON, GPIOF_OUT_INIT_LOW, "Charger On" }, + { CORGI_GPIO_CHRG_UKN, GPIOF_OUT_INIT_LOW, "Charger Unknown" }, + { CORGI_GPIO_AC_IN, GPIOF_IN, "Charger Detection" }, + { CORGI_GPIO_KEY_INT, GPIOF_IN, "Key Interrupt" }, + { CORGI_GPIO_WAKEUP, GPIOF_IN, "System wakeup notification" }, +}; + +static void corgi_charger_init(void) +{ + gpio_request_array(ARRAY_AND_SIZE(charger_gpios)); +} + +static void corgi_measure_temp(int on) +{ + gpio_set_value(CORGI_GPIO_ADC_TEMP_ON, on); +} + +static void corgi_charge(int on) +{ + if (on) { + if (machine_is_corgi() && (sharpsl_pm.flags & SHARPSL_SUSPENDED)) { + gpio_set_value(CORGI_GPIO_CHRG_ON, 0); + gpio_set_value(CORGI_GPIO_CHRG_UKN, 1); + } else { + gpio_set_value(CORGI_GPIO_CHRG_ON, 1); + gpio_set_value(CORGI_GPIO_CHRG_UKN, 0); + } + } else { + gpio_set_value(CORGI_GPIO_CHRG_ON, 0); + gpio_set_value(CORGI_GPIO_CHRG_UKN, 0); + } +} + +static void corgi_discharge(int on) +{ + gpio_set_value(CORGI_GPIO_DISCHARGE_ON, on); +} + +static void corgi_presuspend(void) +{ +} + +static void corgi_postsuspend(void) +{ +} + +/* + * Check what brought us out of the suspend. + * Return: 0 to sleep, otherwise wake + */ +static int corgi_should_wakeup(unsigned int resume_on_alarm) +{ + int is_resume = 0; + + dev_dbg(sharpsl_pm.dev, "PEDR = %x, GPIO_AC_IN = %d, " + "GPIO_CHRG_FULL = %d, GPIO_KEY_INT = %d, GPIO_WAKEUP = %d\n", + PEDR, gpio_get_value(CORGI_GPIO_AC_IN), + gpio_get_value(CORGI_GPIO_CHRG_FULL), + gpio_get_value(CORGI_GPIO_KEY_INT), + gpio_get_value(CORGI_GPIO_WAKEUP)); + + if ((PEDR & GPIO_bit(CORGI_GPIO_AC_IN))) { + if (sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN)) { + /* charge on */ + dev_dbg(sharpsl_pm.dev, "ac insert\n"); + sharpsl_pm.flags |= SHARPSL_DO_OFFLINE_CHRG; + } else { + /* charge off */ + dev_dbg(sharpsl_pm.dev, "ac remove\n"); + sharpsl_pm_led(SHARPSL_LED_OFF); + sharpsl_pm.machinfo->charge(0); + sharpsl_pm.charge_mode = CHRG_OFF; + } + } + + if ((PEDR & GPIO_bit(CORGI_GPIO_CHRG_FULL))) + dev_dbg(sharpsl_pm.dev, "Charge full interrupt\n"); + + if (PEDR & GPIO_bit(CORGI_GPIO_KEY_INT)) + is_resume |= GPIO_bit(CORGI_GPIO_KEY_INT); + + if (PEDR & GPIO_bit(CORGI_GPIO_WAKEUP)) + is_resume |= GPIO_bit(CORGI_GPIO_WAKEUP); + + if (resume_on_alarm && (PEDR & PWER_RTC)) + is_resume |= PWER_RTC; + + dev_dbg(sharpsl_pm.dev, "is_resume: %x\n",is_resume); + return is_resume; +} + +static unsigned long corgi_charger_wakeup(void) +{ + unsigned long ret; + + ret = (!gpio_get_value(CORGI_GPIO_AC_IN) << GPIO_bit(CORGI_GPIO_AC_IN)) + | (!gpio_get_value(CORGI_GPIO_KEY_INT) + << GPIO_bit(CORGI_GPIO_KEY_INT)) + | (!gpio_get_value(CORGI_GPIO_WAKEUP) + << GPIO_bit(CORGI_GPIO_WAKEUP)); + return ret; +} + +unsigned long corgipm_read_devdata(int type) +{ + switch(type) { + case SHARPSL_STATUS_ACIN: + return !gpio_get_value(CORGI_GPIO_AC_IN); + case SHARPSL_STATUS_LOCK: + return gpio_get_value(sharpsl_pm.machinfo->gpio_batlock); + case SHARPSL_STATUS_CHRGFULL: + return gpio_get_value(sharpsl_pm.machinfo->gpio_batfull); + case SHARPSL_STATUS_FATAL: + return gpio_get_value(sharpsl_pm.machinfo->gpio_fatal); + case SHARPSL_ACIN_VOLT: + return sharpsl_pm_pxa_read_max1111(MAX1111_ACIN_VOLT); + case SHARPSL_BATT_TEMP: + return sharpsl_pm_pxa_read_max1111(MAX1111_BATT_TEMP); + case SHARPSL_BATT_VOLT: + default: + return sharpsl_pm_pxa_read_max1111(MAX1111_BATT_VOLT); + } +} + +static struct sharpsl_charger_machinfo corgi_pm_machinfo = { + .init = corgi_charger_init, + .exit = NULL, + .gpio_batlock = CORGI_GPIO_BAT_COVER, + .gpio_acin = CORGI_GPIO_AC_IN, + .gpio_batfull = CORGI_GPIO_CHRG_FULL, + .discharge = corgi_discharge, + .charge = corgi_charge, + .measure_temp = corgi_measure_temp, + .presuspend = corgi_presuspend, + .postsuspend = corgi_postsuspend, + .read_devdata = corgipm_read_devdata, + .charger_wakeup = corgi_charger_wakeup, + .should_wakeup = corgi_should_wakeup, +#if defined(CONFIG_LCD_CORGI) + .backlight_limit = corgi_lcd_limit_intensity, +#endif + .charge_on_volt = SHARPSL_CHARGE_ON_VOLT, + .charge_on_temp = SHARPSL_CHARGE_ON_TEMP, + .charge_acin_high = SHARPSL_CHARGE_ON_ACIN_HIGH, + .charge_acin_low = SHARPSL_CHARGE_ON_ACIN_LOW, + .fatal_acin_volt = SHARPSL_FATAL_ACIN_VOLT, + .fatal_noacin_volt= SHARPSL_FATAL_NOACIN_VOLT, + .bat_levels = 40, + .bat_levels_noac = sharpsl_battery_levels_noac, + .bat_levels_acin = sharpsl_battery_levels_acin, + .status_high_acin = 188, + .status_low_acin = 178, + .status_high_noac = 185, + .status_low_noac = 175, +}; + +static struct platform_device *corgipm_device; + +static int __devinit corgipm_init(void) +{ + int ret; + + if (!machine_is_corgi() && !machine_is_shepherd() + && !machine_is_husky()) + return -ENODEV; + + corgipm_device = platform_device_alloc("sharpsl-pm", -1); + if (!corgipm_device) + return -ENOMEM; + + if (!machine_is_corgi()) + corgi_pm_machinfo.batfull_irq = 1; + + corgipm_device->dev.platform_data = &corgi_pm_machinfo; + ret = platform_device_add(corgipm_device); + + if (ret) + platform_device_put(corgipm_device); + + return ret; +} + +static void corgipm_exit(void) +{ + platform_device_unregister(corgipm_device); +} + +module_init(corgipm_init); +module_exit(corgipm_exit); |