0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/module.h>
0009 #include <linux/stat.h>
0010 #include <linux/init.h>
0011 #include <linux/kernel.h>
0012 #include <linux/delay.h>
0013 #include <linux/gpio.h>
0014 #include <linux/gpio-pxa.h>
0015 #include <linux/interrupt.h>
0016 #include <linux/platform_device.h>
0017 #include <linux/apm-emulation.h>
0018 #include <linux/io.h>
0019
0020 #include <asm/irq.h>
0021 #include <asm/mach-types.h>
0022
0023 #include "corgi.h"
0024 #include "pxa2xx-regs.h"
0025 #include "sharpsl_pm.h"
0026
0027 #include "generic.h"
0028
0029 #define SHARPSL_CHARGE_ON_VOLT 0x99
0030 #define SHARPSL_CHARGE_ON_TEMP 0xe0
0031 #define SHARPSL_CHARGE_ON_ACIN_HIGH 0x9b
0032 #define SHARPSL_CHARGE_ON_ACIN_LOW 0x34
0033 #define SHARPSL_FATAL_ACIN_VOLT 182
0034 #define SHARPSL_FATAL_NOACIN_VOLT 170
0035
0036 static struct gpio charger_gpios[] = {
0037 { CORGI_GPIO_ADC_TEMP_ON, GPIOF_OUT_INIT_LOW, "ADC Temp On" },
0038 { CORGI_GPIO_CHRG_ON, GPIOF_OUT_INIT_LOW, "Charger On" },
0039 { CORGI_GPIO_CHRG_UKN, GPIOF_OUT_INIT_LOW, "Charger Unknown" },
0040 { CORGI_GPIO_AC_IN, GPIOF_IN, "Charger Detection" },
0041 { CORGI_GPIO_KEY_INT, GPIOF_IN, "Key Interrupt" },
0042 { CORGI_GPIO_WAKEUP, GPIOF_IN, "System wakeup notification" },
0043 };
0044
0045 static void corgi_charger_init(void)
0046 {
0047 gpio_request_array(ARRAY_AND_SIZE(charger_gpios));
0048 }
0049
0050 static void corgi_measure_temp(int on)
0051 {
0052 gpio_set_value(CORGI_GPIO_ADC_TEMP_ON, on);
0053 }
0054
0055 static void corgi_charge(int on)
0056 {
0057 if (on) {
0058 if (machine_is_corgi() && (sharpsl_pm.flags & SHARPSL_SUSPENDED)) {
0059 gpio_set_value(CORGI_GPIO_CHRG_ON, 0);
0060 gpio_set_value(CORGI_GPIO_CHRG_UKN, 1);
0061 } else {
0062 gpio_set_value(CORGI_GPIO_CHRG_ON, 1);
0063 gpio_set_value(CORGI_GPIO_CHRG_UKN, 0);
0064 }
0065 } else {
0066 gpio_set_value(CORGI_GPIO_CHRG_ON, 0);
0067 gpio_set_value(CORGI_GPIO_CHRG_UKN, 0);
0068 }
0069 }
0070
0071 static void corgi_discharge(int on)
0072 {
0073 gpio_set_value(CORGI_GPIO_DISCHARGE_ON, on);
0074 }
0075
0076 static void corgi_presuspend(void)
0077 {
0078 }
0079
0080 static void corgi_postsuspend(void)
0081 {
0082 }
0083
0084
0085
0086
0087
0088 static int corgi_should_wakeup(unsigned int resume_on_alarm)
0089 {
0090 int is_resume = 0;
0091
0092 dev_dbg(sharpsl_pm.dev, "PEDR = %x, GPIO_AC_IN = %d, "
0093 "GPIO_CHRG_FULL = %d, GPIO_KEY_INT = %d, GPIO_WAKEUP = %d\n",
0094 PEDR, gpio_get_value(CORGI_GPIO_AC_IN),
0095 gpio_get_value(CORGI_GPIO_CHRG_FULL),
0096 gpio_get_value(CORGI_GPIO_KEY_INT),
0097 gpio_get_value(CORGI_GPIO_WAKEUP));
0098
0099 if ((PEDR & GPIO_bit(CORGI_GPIO_AC_IN))) {
0100 if (sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN)) {
0101
0102 dev_dbg(sharpsl_pm.dev, "ac insert\n");
0103 sharpsl_pm.flags |= SHARPSL_DO_OFFLINE_CHRG;
0104 } else {
0105
0106 dev_dbg(sharpsl_pm.dev, "ac remove\n");
0107 sharpsl_pm_led(SHARPSL_LED_OFF);
0108 sharpsl_pm.machinfo->charge(0);
0109 sharpsl_pm.charge_mode = CHRG_OFF;
0110 }
0111 }
0112
0113 if ((PEDR & GPIO_bit(CORGI_GPIO_CHRG_FULL)))
0114 dev_dbg(sharpsl_pm.dev, "Charge full interrupt\n");
0115
0116 if (PEDR & GPIO_bit(CORGI_GPIO_KEY_INT))
0117 is_resume |= GPIO_bit(CORGI_GPIO_KEY_INT);
0118
0119 if (PEDR & GPIO_bit(CORGI_GPIO_WAKEUP))
0120 is_resume |= GPIO_bit(CORGI_GPIO_WAKEUP);
0121
0122 if (resume_on_alarm && (PEDR & PWER_RTC))
0123 is_resume |= PWER_RTC;
0124
0125 dev_dbg(sharpsl_pm.dev, "is_resume: %x\n",is_resume);
0126 return is_resume;
0127 }
0128
0129 static bool corgi_charger_wakeup(void)
0130 {
0131 return !gpio_get_value(CORGI_GPIO_AC_IN) ||
0132 !gpio_get_value(CORGI_GPIO_KEY_INT) ||
0133 !gpio_get_value(CORGI_GPIO_WAKEUP);
0134 }
0135
0136 unsigned long corgipm_read_devdata(int type)
0137 {
0138 switch(type) {
0139 case SHARPSL_STATUS_ACIN:
0140 return !gpio_get_value(CORGI_GPIO_AC_IN);
0141 case SHARPSL_STATUS_LOCK:
0142 return gpio_get_value(sharpsl_pm.machinfo->gpio_batlock);
0143 case SHARPSL_STATUS_CHRGFULL:
0144 return gpio_get_value(sharpsl_pm.machinfo->gpio_batfull);
0145 case SHARPSL_STATUS_FATAL:
0146 return gpio_get_value(sharpsl_pm.machinfo->gpio_fatal);
0147 case SHARPSL_ACIN_VOLT:
0148 return sharpsl_pm_pxa_read_max1111(MAX1111_ACIN_VOLT);
0149 case SHARPSL_BATT_TEMP:
0150 return sharpsl_pm_pxa_read_max1111(MAX1111_BATT_TEMP);
0151 case SHARPSL_BATT_VOLT:
0152 default:
0153 return sharpsl_pm_pxa_read_max1111(MAX1111_BATT_VOLT);
0154 }
0155 }
0156
0157 static struct sharpsl_charger_machinfo corgi_pm_machinfo = {
0158 .init = corgi_charger_init,
0159 .exit = NULL,
0160 .gpio_batlock = CORGI_GPIO_BAT_COVER,
0161 .gpio_acin = CORGI_GPIO_AC_IN,
0162 .gpio_batfull = CORGI_GPIO_CHRG_FULL,
0163 .discharge = corgi_discharge,
0164 .charge = corgi_charge,
0165 .measure_temp = corgi_measure_temp,
0166 .presuspend = corgi_presuspend,
0167 .postsuspend = corgi_postsuspend,
0168 .read_devdata = corgipm_read_devdata,
0169 .charger_wakeup = corgi_charger_wakeup,
0170 .should_wakeup = corgi_should_wakeup,
0171 #if defined(CONFIG_LCD_CORGI)
0172 .backlight_limit = corgi_lcd_limit_intensity,
0173 #endif
0174 .charge_on_volt = SHARPSL_CHARGE_ON_VOLT,
0175 .charge_on_temp = SHARPSL_CHARGE_ON_TEMP,
0176 .charge_acin_high = SHARPSL_CHARGE_ON_ACIN_HIGH,
0177 .charge_acin_low = SHARPSL_CHARGE_ON_ACIN_LOW,
0178 .fatal_acin_volt = SHARPSL_FATAL_ACIN_VOLT,
0179 .fatal_noacin_volt= SHARPSL_FATAL_NOACIN_VOLT,
0180 .bat_levels = 40,
0181 .bat_levels_noac = sharpsl_battery_levels_noac,
0182 .bat_levels_acin = sharpsl_battery_levels_acin,
0183 .status_high_acin = 188,
0184 .status_low_acin = 178,
0185 .status_high_noac = 185,
0186 .status_low_noac = 175,
0187 };
0188
0189 static struct platform_device *corgipm_device;
0190
0191 static int corgipm_init(void)
0192 {
0193 int ret;
0194
0195 if (!machine_is_corgi() && !machine_is_shepherd()
0196 && !machine_is_husky())
0197 return -ENODEV;
0198
0199 corgipm_device = platform_device_alloc("sharpsl-pm", -1);
0200 if (!corgipm_device)
0201 return -ENOMEM;
0202
0203 if (!machine_is_corgi())
0204 corgi_pm_machinfo.batfull_irq = 1;
0205
0206 corgipm_device->dev.platform_data = &corgi_pm_machinfo;
0207 ret = platform_device_add(corgipm_device);
0208
0209 if (ret)
0210 platform_device_put(corgipm_device);
0211
0212 return ret;
0213 }
0214
0215 static void corgipm_exit(void)
0216 {
0217 platform_device_unregister(corgipm_device);
0218 }
0219
0220 module_init(corgipm_init);
0221 module_exit(corgipm_exit);