diff options
| author | Richard Purdie <rpurdie@rpsys.net> | 2005-11-13 05:07:46 -0500 |
|---|---|---|
| committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2005-11-13 05:07:46 -0500 |
| commit | d72f25b0dfb0807bd758da56a7ed88c0eb6e70d8 (patch) | |
| tree | 0e65a1e0dcfd8a374e9e7a2560f086ce77d3e0bf | |
| parent | 865052fd51a4f95a9c61961198695877ddc3dc9e (diff) | |
[ARM] 3158/1: SharpSL: Add PM device driver for the SL-C7x0 machines.
Patch from Richard Purdie
Add a SharpSL PM device driver for the SL-C7x0 machines.
Signed-off-by: Richard Purdie <rpurdie@rpsys.net>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
| -rw-r--r-- | arch/arm/mach-pxa/Makefile | 2 | ||||
| -rw-r--r-- | arch/arm/mach-pxa/corgi_pm.c | 228 |
2 files changed, 229 insertions, 1 deletions
diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile index d210bd5032ce..eecc5c199678 100644 --- a/arch/arm/mach-pxa/Makefile +++ b/arch/arm/mach-pxa/Makefile | |||
| @@ -11,7 +11,7 @@ obj-$(CONFIG_PXA27x) += pxa27x.o | |||
| 11 | obj-$(CONFIG_ARCH_LUBBOCK) += lubbock.o | 11 | obj-$(CONFIG_ARCH_LUBBOCK) += lubbock.o |
| 12 | obj-$(CONFIG_MACH_MAINSTONE) += mainstone.o | 12 | obj-$(CONFIG_MACH_MAINSTONE) += mainstone.o |
| 13 | obj-$(CONFIG_ARCH_PXA_IDP) += idp.o | 13 | obj-$(CONFIG_ARCH_PXA_IDP) += idp.o |
| 14 | obj-$(CONFIG_PXA_SHARP_C7xx) += corgi.o corgi_ssp.o corgi_lcd.o | 14 | obj-$(CONFIG_PXA_SHARP_C7xx) += corgi.o corgi_ssp.o corgi_lcd.o sharpsl_pm.o corgi_pm.o |
| 15 | obj-$(CONFIG_PXA_SHARP_Cxx00) += spitz.o corgi_ssp.o corgi_lcd.o | 15 | obj-$(CONFIG_PXA_SHARP_Cxx00) += spitz.o corgi_ssp.o corgi_lcd.o |
| 16 | obj-$(CONFIG_MACH_POODLE) += poodle.o | 16 | obj-$(CONFIG_MACH_POODLE) += poodle.o |
| 17 | obj-$(CONFIG_MACH_TOSA) += tosa.o | 17 | obj-$(CONFIG_MACH_TOSA) += tosa.o |
diff --git a/arch/arm/mach-pxa/corgi_pm.c b/arch/arm/mach-pxa/corgi_pm.c new file mode 100644 index 000000000000..599be14754f9 --- /dev/null +++ b/arch/arm/mach-pxa/corgi_pm.c | |||
| @@ -0,0 +1,228 @@ | |||
| 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/interrupt.h> | ||
| 18 | #include <linux/platform_device.h> | ||
| 19 | #include <asm/apm.h> | ||
| 20 | #include <asm/irq.h> | ||
| 21 | #include <asm/mach-types.h> | ||
| 22 | #include <asm/hardware.h> | ||
| 23 | #include <asm/hardware/scoop.h> | ||
| 24 | |||
| 25 | #include <asm/arch/sharpsl.h> | ||
| 26 | #include <asm/arch/corgi.h> | ||
| 27 | #include <asm/arch/pxa-regs.h> | ||
| 28 | #include "sharpsl.h" | ||
| 29 | |||
| 30 | static void corgi_charger_init(void) | ||
| 31 | { | ||
| 32 | pxa_gpio_mode(CORGI_GPIO_ADC_TEMP_ON | GPIO_OUT); | ||
| 33 | pxa_gpio_mode(CORGI_GPIO_CHRG_ON | GPIO_OUT); | ||
| 34 | pxa_gpio_mode(CORGI_GPIO_CHRG_UKN | GPIO_OUT); | ||
| 35 | pxa_gpio_mode(CORGI_GPIO_KEY_INT | GPIO_IN); | ||
| 36 | } | ||
| 37 | |||
| 38 | static void corgi_charge_led(int val) | ||
| 39 | { | ||
| 40 | if (val == SHARPSL_LED_ERROR) { | ||
| 41 | dev_dbg(sharpsl_pm.dev, "Charge LED Error\n"); | ||
| 42 | } else if (val == SHARPSL_LED_ON) { | ||
| 43 | dev_dbg(sharpsl_pm.dev, "Charge LED On\n"); | ||
| 44 | GPSR0 = GPIO_bit(CORGI_GPIO_LED_ORANGE); | ||
| 45 | } else { | ||
| 46 | dev_dbg(sharpsl_pm.dev, "Charge LED Off\n"); | ||
| 47 | GPCR0 = GPIO_bit(CORGI_GPIO_LED_ORANGE); | ||
| 48 | } | ||
| 49 | } | ||
| 50 | |||
| 51 | static void corgi_measure_temp(int on) | ||
| 52 | { | ||
| 53 | if (on) | ||
| 54 | GPSR(CORGI_GPIO_ADC_TEMP_ON) = GPIO_bit(CORGI_GPIO_ADC_TEMP_ON); | ||
| 55 | else | ||
| 56 | GPCR(CORGI_GPIO_ADC_TEMP_ON) = GPIO_bit(CORGI_GPIO_ADC_TEMP_ON); | ||
| 57 | } | ||
| 58 | |||
| 59 | static void corgi_charge(int on) | ||
| 60 | { | ||
| 61 | if (on) { | ||
| 62 | if (machine_is_corgi() && (sharpsl_pm.flags & SHARPSL_SUSPENDED)) { | ||
| 63 | GPCR(CORGI_GPIO_CHRG_ON) = GPIO_bit(CORGI_GPIO_CHRG_ON); | ||
| 64 | GPSR(CORGI_GPIO_CHRG_UKN) = GPIO_bit(CORGI_GPIO_CHRG_UKN); | ||
| 65 | } else { | ||
| 66 | GPSR(CORGI_GPIO_CHRG_ON) = GPIO_bit(CORGI_GPIO_CHRG_ON); | ||
| 67 | GPCR(CORGI_GPIO_CHRG_UKN) = GPIO_bit(CORGI_GPIO_CHRG_UKN); | ||
| 68 | } | ||
| 69 | } else { | ||
| 70 | GPCR(CORGI_GPIO_CHRG_ON) = GPIO_bit(CORGI_GPIO_CHRG_ON); | ||
| 71 | GPCR(CORGI_GPIO_CHRG_UKN) = GPIO_bit(CORGI_GPIO_CHRG_UKN); | ||
| 72 | } | ||
| 73 | } | ||
| 74 | |||
| 75 | static void corgi_discharge(int on) | ||
| 76 | { | ||
| 77 | if (on) | ||
| 78 | GPSR(CORGI_GPIO_DISCHARGE_ON) = GPIO_bit(CORGI_GPIO_DISCHARGE_ON); | ||
| 79 | else | ||
| 80 | GPCR(CORGI_GPIO_DISCHARGE_ON) = GPIO_bit(CORGI_GPIO_DISCHARGE_ON); | ||
| 81 | } | ||
| 82 | |||
| 83 | static void corgi_presuspend(void) | ||
| 84 | { | ||
| 85 | int i; | ||
| 86 | unsigned long wakeup_mask; | ||
| 87 | |||
| 88 | /* charging , so CHARGE_ON bit is HIGH during OFF. */ | ||
| 89 | if (READ_GPIO_BIT(CORGI_GPIO_CHRG_ON)) | ||
| 90 | PGSR1 |= GPIO_bit(CORGI_GPIO_CHRG_ON); | ||
| 91 | else | ||
| 92 | PGSR1 &= ~GPIO_bit(CORGI_GPIO_CHRG_ON); | ||
| 93 | |||
| 94 | if (READ_GPIO_BIT(CORGI_GPIO_LED_ORANGE)) | ||
| 95 | PGSR0 |= GPIO_bit(CORGI_GPIO_LED_ORANGE); | ||
| 96 | else | ||
| 97 | PGSR0 &= ~GPIO_bit(CORGI_GPIO_LED_ORANGE); | ||
| 98 | |||
| 99 | if (READ_GPIO_BIT(CORGI_GPIO_CHRG_UKN)) | ||
| 100 | PGSR1 |= GPIO_bit(CORGI_GPIO_CHRG_UKN); | ||
| 101 | else | ||
| 102 | PGSR1 &= ~GPIO_bit(CORGI_GPIO_CHRG_UKN); | ||
| 103 | |||
| 104 | /* Resume on keyboard power key */ | ||
| 105 | PGSR2 = (PGSR2 & ~CORGI_GPIO_ALL_STROBE_BIT) | CORGI_GPIO_STROBE_BIT(0); | ||
| 106 | |||
| 107 | wakeup_mask = GPIO_bit(CORGI_GPIO_KEY_INT) | GPIO_bit(CORGI_GPIO_WAKEUP) | GPIO_bit(CORGI_GPIO_AC_IN) | GPIO_bit(CORGI_GPIO_CHRG_FULL); | ||
| 108 | |||
| 109 | if (!machine_is_corgi()) | ||
| 110 | wakeup_mask |= GPIO_bit(CORGI_GPIO_MAIN_BAT_LOW); | ||
| 111 | |||
| 112 | PWER = wakeup_mask | PWER_RTC; | ||
| 113 | PRER = wakeup_mask; | ||
| 114 | PFER = wakeup_mask; | ||
| 115 | |||
| 116 | for (i = 0; i <=15; i++) { | ||
| 117 | if (PRER & PFER & GPIO_bit(i)) { | ||
| 118 | if (GPLR0 & GPIO_bit(i) ) | ||
| 119 | PRER &= ~GPIO_bit(i); | ||
| 120 | else | ||
| 121 | PFER &= ~GPIO_bit(i); | ||
| 122 | } | ||
| 123 | } | ||
| 124 | } | ||
| 125 | |||
| 126 | static void corgi_postsuspend(void) | ||
| 127 | { | ||
| 128 | } | ||
| 129 | |||
| 130 | /* | ||
| 131 | * Check what brought us out of the suspend. | ||
| 132 | * Return: 0 to sleep, otherwise wake | ||
| 133 | */ | ||
| 134 | static int corgi_should_wakeup(unsigned int resume_on_alarm) | ||
| 135 | { | ||
| 136 | int is_resume = 0; | ||
| 137 | |||
| 138 | dev_dbg(sharpsl_pm.dev, "GPLR0 = %x,%x\n", GPLR0, PEDR); | ||
| 139 | |||
| 140 | if ((PEDR & GPIO_bit(CORGI_GPIO_AC_IN))) { | ||
| 141 | if (STATUS_AC_IN()) { | ||
| 142 | /* charge on */ | ||
| 143 | dev_dbg(sharpsl_pm.dev, "ac insert\n"); | ||
| 144 | sharpsl_pm.flags |= SHARPSL_DO_OFFLINE_CHRG; | ||
| 145 | } else { | ||
| 146 | /* charge off */ | ||
| 147 | dev_dbg(sharpsl_pm.dev, "ac remove\n"); | ||
| 148 | CHARGE_LED_OFF(); | ||
| 149 | CHARGE_OFF(); | ||
| 150 | sharpsl_pm.charge_mode = CHRG_OFF; | ||
| 151 | } | ||
| 152 | } | ||
| 153 | |||
| 154 | if ((PEDR & GPIO_bit(CORGI_GPIO_CHRG_FULL))) | ||
| 155 | dev_dbg(sharpsl_pm.dev, "Charge full interrupt\n"); | ||
| 156 | |||
| 157 | if (PEDR & GPIO_bit(CORGI_GPIO_KEY_INT)) | ||
| 158 | is_resume |= GPIO_bit(CORGI_GPIO_KEY_INT); | ||
| 159 | |||
| 160 | if (PEDR & GPIO_bit(CORGI_GPIO_WAKEUP)) | ||
| 161 | is_resume |= GPIO_bit(CORGI_GPIO_WAKEUP); | ||
| 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 | |||
| 170 | static unsigned long corgi_charger_wakeup(void) | ||
| 171 | { | ||
| 172 | return ~GPLR0 & ( GPIO_bit(CORGI_GPIO_AC_IN) | GPIO_bit(CORGI_GPIO_KEY_INT) | GPIO_bit(CORGI_GPIO_WAKEUP) ); | ||
| 173 | } | ||
| 174 | |||
| 175 | static int corgi_acin_status(void) | ||
| 176 | { | ||
| 177 | return ((GPLR(CORGI_GPIO_AC_IN) & GPIO_bit(CORGI_GPIO_AC_IN)) != 0); | ||
| 178 | } | ||
| 179 | |||
| 180 | static struct sharpsl_charger_machinfo corgi_pm_machinfo = { | ||
| 181 | .init = corgi_charger_init, | ||
| 182 | .gpio_batlock = CORGI_GPIO_BAT_COVER, | ||
| 183 | .gpio_acin = CORGI_GPIO_AC_IN, | ||
| 184 | .gpio_batfull = CORGI_GPIO_CHRG_FULL, | ||
| 185 | .status_acin = corgi_acin_status, | ||
| 186 | .discharge = corgi_discharge, | ||
| 187 | .charge = corgi_charge, | ||
| 188 | .chargeled = corgi_charge_led, | ||
| 189 | .measure_temp = corgi_measure_temp, | ||
| 190 | .presuspend = corgi_presuspend, | ||
| 191 | .postsuspend = corgi_postsuspend, | ||
| 192 | .charger_wakeup = corgi_charger_wakeup, | ||
| 193 | .should_wakeup = corgi_should_wakeup, | ||
| 194 | .bat_levels = 40, | ||
| 195 | .bat_levels_noac = spitz_battery_levels_noac, | ||
| 196 | .bat_levels_acin = spitz_battery_levels_acin, | ||
| 197 | .status_high_acin = 188, | ||
| 198 | .status_low_acin = 178, | ||
| 199 | .status_high_noac = 185, | ||
| 200 | .status_low_noac = 175, | ||
| 201 | }; | ||
| 202 | |||
| 203 | static struct platform_device *corgipm_device; | ||
| 204 | |||
| 205 | static int __devinit corgipm_init(void) | ||
| 206 | { | ||
| 207 | int ret; | ||
| 208 | |||
| 209 | corgipm_device = platform_device_alloc("sharpsl-pm", -1); | ||
| 210 | if (!corgipm_device) | ||
| 211 | return -ENOMEM; | ||
| 212 | |||
| 213 | corgipm_device->dev.platform_data = &corgi_pm_machinfo; | ||
| 214 | ret = platform_device_add(corgipm_device); | ||
| 215 | |||
| 216 | if (ret) | ||
| 217 | platform_device_put(corgipm_device); | ||
| 218 | |||
| 219 | return ret; | ||
| 220 | } | ||
| 221 | |||
| 222 | static void corgipm_exit(void) | ||
| 223 | { | ||
| 224 | platform_device_unregister(corgipm_device); | ||
| 225 | } | ||
| 226 | |||
| 227 | module_init(corgipm_init); | ||
| 228 | module_exit(corgipm_exit); | ||
