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