1/* 2 * Battery and Power Management code for the Sharp SL-C7xx 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/corgi.h> 27#include <mach/pxa2xx-regs.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 struct gpio charger_gpios[] = { 40 { CORGI_GPIO_ADC_TEMP_ON, GPIOF_OUT_INIT_LOW, "ADC Temp On" }, 41 { CORGI_GPIO_CHRG_ON, GPIOF_OUT_INIT_LOW, "Charger On" }, 42 { CORGI_GPIO_CHRG_UKN, GPIOF_OUT_INIT_LOW, "Charger Unknown" }, 43 { CORGI_GPIO_KEY_INT, GPIOF_IN, "Key Interrupt" }, 44}; 45 46static void corgi_charger_init(void) 47{ 48 gpio_request_array(ARRAY_AND_SIZE(charger_gpios)); 49} 50 51static void corgi_measure_temp(int on) 52{ 53 gpio_set_value(CORGI_GPIO_ADC_TEMP_ON, on); 54} 55 56static void corgi_charge(int on) 57{ 58 if (on) { 59 if (machine_is_corgi() && (sharpsl_pm.flags & SHARPSL_SUSPENDED)) { 60 gpio_set_value(CORGI_GPIO_CHRG_ON, 0); 61 gpio_set_value(CORGI_GPIO_CHRG_UKN, 1); 62 } else { 63 gpio_set_value(CORGI_GPIO_CHRG_ON, 1); 64 gpio_set_value(CORGI_GPIO_CHRG_UKN, 0); 65 } 66 } else { 67 gpio_set_value(CORGI_GPIO_CHRG_ON, 0); 68 gpio_set_value(CORGI_GPIO_CHRG_UKN, 0); 69 } 70} 71 72static void corgi_discharge(int on) 73{ 74 gpio_set_value(CORGI_GPIO_DISCHARGE_ON, on); 75} 76 77static void corgi_presuspend(void) 78{ 79} 80 81static void corgi_postsuspend(void) 82{ 83} 84 85/* 86 * Check what brought us out of the suspend. 87 * Return: 0 to sleep, otherwise wake 88 */ 89static int corgi_should_wakeup(unsigned int resume_on_alarm) 90{ 91 int is_resume = 0; 92 93 dev_dbg(sharpsl_pm.dev, "GPLR0 = %x,%x\n", GPLR0, PEDR); 94 95 if ((PEDR & GPIO_bit(CORGI_GPIO_AC_IN))) { 96 if (sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN)) { 97 /* charge on */ 98 dev_dbg(sharpsl_pm.dev, "ac insert\n"); 99 sharpsl_pm.flags |= SHARPSL_DO_OFFLINE_CHRG; 100 } else { 101 /* charge off */ 102 dev_dbg(sharpsl_pm.dev, "ac remove\n"); 103 sharpsl_pm_led(SHARPSL_LED_OFF); 104 sharpsl_pm.machinfo->charge(0); 105 sharpsl_pm.charge_mode = CHRG_OFF; 106 } 107 } 108 109 if ((PEDR & GPIO_bit(CORGI_GPIO_CHRG_FULL))) 110 dev_dbg(sharpsl_pm.dev, "Charge full interrupt\n"); 111 112 if (PEDR & GPIO_bit(CORGI_GPIO_KEY_INT)) 113 is_resume |= GPIO_bit(CORGI_GPIO_KEY_INT); 114 115 if (PEDR & GPIO_bit(CORGI_GPIO_WAKEUP)) 116 is_resume |= GPIO_bit(CORGI_GPIO_WAKEUP); 117 118 if (resume_on_alarm && (PEDR & PWER_RTC)) 119 is_resume |= PWER_RTC; 120 121 dev_dbg(sharpsl_pm.dev, "is_resume: %x\n",is_resume); 122 return is_resume; 123} 124 125static unsigned long corgi_charger_wakeup(void) 126{ 127 return ~GPLR0 & ( GPIO_bit(CORGI_GPIO_AC_IN) | GPIO_bit(CORGI_GPIO_KEY_INT) | GPIO_bit(CORGI_GPIO_WAKEUP) ); 128} 129 130unsigned long corgipm_read_devdata(int type) 131{ 132 switch(type) { 133 case SHARPSL_STATUS_ACIN: 134 return ((GPLR(CORGI_GPIO_AC_IN) & GPIO_bit(CORGI_GPIO_AC_IN)) != 0); 135 case SHARPSL_STATUS_LOCK: 136 return gpio_get_value(sharpsl_pm.machinfo->gpio_batlock); 137 case SHARPSL_STATUS_CHRGFULL: 138 return gpio_get_value(sharpsl_pm.machinfo->gpio_batfull); 139 case SHARPSL_STATUS_FATAL: 140 return gpio_get_value(sharpsl_pm.machinfo->gpio_fatal); 141 case SHARPSL_ACIN_VOLT: 142 return sharpsl_pm_pxa_read_max1111(MAX1111_ACIN_VOLT); 143 case SHARPSL_BATT_TEMP: 144 return sharpsl_pm_pxa_read_max1111(MAX1111_BATT_TEMP); 145 case SHARPSL_BATT_VOLT: 146 default: 147 return sharpsl_pm_pxa_read_max1111(MAX1111_BATT_VOLT); 148 } 149} 150 151static struct sharpsl_charger_machinfo corgi_pm_machinfo = { 152 .init = corgi_charger_init, 153 .exit = NULL, 154 .gpio_batlock = CORGI_GPIO_BAT_COVER, 155 .gpio_acin = CORGI_GPIO_AC_IN, 156 .gpio_batfull = CORGI_GPIO_CHRG_FULL, 157 .discharge = corgi_discharge, 158 .charge = corgi_charge, 159 .measure_temp = corgi_measure_temp, 160 .presuspend = corgi_presuspend, 161 .postsuspend = corgi_postsuspend, 162 .read_devdata = corgipm_read_devdata, 163 .charger_wakeup = corgi_charger_wakeup, 164 .should_wakeup = corgi_should_wakeup, 165#if defined(CONFIG_LCD_CORGI) 166 .backlight_limit = corgi_lcd_limit_intensity, 167#endif 168 .charge_on_volt = SHARPSL_CHARGE_ON_VOLT, 169 .charge_on_temp = SHARPSL_CHARGE_ON_TEMP, 170 .charge_acin_high = SHARPSL_CHARGE_ON_ACIN_HIGH, 171 .charge_acin_low = SHARPSL_CHARGE_ON_ACIN_LOW, 172 .fatal_acin_volt = SHARPSL_FATAL_ACIN_VOLT, 173 .fatal_noacin_volt= SHARPSL_FATAL_NOACIN_VOLT, 174 .bat_levels = 40, 175 .bat_levels_noac = sharpsl_battery_levels_noac, 176 .bat_levels_acin = sharpsl_battery_levels_acin, 177 .status_high_acin = 188, 178 .status_low_acin = 178, 179 .status_high_noac = 185, 180 .status_low_noac = 175, 181}; 182 183static struct platform_device *corgipm_device; 184 185static int __devinit corgipm_init(void) 186{ 187 int ret; 188 189 if (!machine_is_corgi() && !machine_is_shepherd() 190 && !machine_is_husky()) 191 return -ENODEV; 192 193 corgipm_device = platform_device_alloc("sharpsl-pm", -1); 194 if (!corgipm_device) 195 return -ENOMEM; 196 197 if (!machine_is_corgi()) 198 corgi_pm_machinfo.batfull_irq = 1; 199 200 corgipm_device->dev.platform_data = &corgi_pm_machinfo; 201 ret = platform_device_add(corgipm_device); 202 203 if (ret) 204 platform_device_put(corgipm_device); 205 206 return ret; 207} 208 209static void corgipm_exit(void) 210{ 211 platform_device_unregister(corgipm_device); 212} 213 214module_init(corgipm_init); 215module_exit(corgipm_exit); 216