1/*
2 * Battery and Power Management code for the Sharp SL-C7xx and SL-Cxx00
3 * series of PDAs
4 *
5 * Copyright (c) 2004-2005 Richard Purdie
6 *
7 * Based on code written by Sharp for 2.4 kernels
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 *
13 */
14
15#undef DEBUG
16
17#include <linux/module.h>
18#include <linux/init.h>
19#include <linux/kernel.h>
20#include <linux/interrupt.h>
21#include <linux/irq.h>
22#include <linux/platform_device.h>
23#include <linux/apm-emulation.h>
24
25#include <asm/hardware.h>
26#include <asm/mach-types.h>
27#include <asm/arch/pm.h>
28#include <asm/arch/pxa-regs.h>
29#include <asm/arch/sharpsl.h>
30#include "sharpsl.h"
31
32struct battery_thresh spitz_battery_levels_acin[] = {
33	{ 213, 100},
34	{ 212,  98},
35	{ 211,  95},
36	{ 210,  93},
37	{ 209,  90},
38	{ 208,  88},
39	{ 207,  85},
40	{ 206,  83},
41	{ 205,  80},
42	{ 204,  78},
43	{ 203,  75},
44	{ 202,  73},
45	{ 201,  70},
46	{ 200,  68},
47	{ 199,  65},
48	{ 198,  63},
49	{ 197,  60},
50	{ 196,  58},
51	{ 195,  55},
52	{ 194,  53},
53	{ 193,  50},
54	{ 192,  48},
55	{ 192,  45},
56	{ 191,  43},
57	{ 191,  40},
58	{ 190,  38},
59	{ 190,  35},
60	{ 189,  33},
61	{ 188,  30},
62	{ 187,  28},
63	{ 186,  25},
64	{ 185,  23},
65	{ 184,  20},
66	{ 183,  18},
67	{ 182,  15},
68	{ 181,  13},
69	{ 180,  10},
70	{ 179,   8},
71	{ 178,   5},
72	{   0,   0},
73};
74
75struct battery_thresh  spitz_battery_levels_noac[] = {
76	{ 213, 100},
77	{ 212,  98},
78	{ 211,  95},
79	{ 210,  93},
80	{ 209,  90},
81	{ 208,  88},
82	{ 207,  85},
83	{ 206,  83},
84	{ 205,  80},
85	{ 204,  78},
86	{ 203,  75},
87	{ 202,  73},
88	{ 201,  70},
89	{ 200,  68},
90	{ 199,  65},
91	{ 198,  63},
92	{ 197,  60},
93	{ 196,  58},
94	{ 195,  55},
95	{ 194,  53},
96	{ 193,  50},
97	{ 192,  48},
98	{ 191,  45},
99	{ 190,  43},
100	{ 189,  40},
101	{ 188,  38},
102	{ 187,  35},
103	{ 186,  33},
104	{ 185,  30},
105	{ 184,  28},
106	{ 183,  25},
107	{ 182,  23},
108	{ 181,  20},
109	{ 180,  18},
110	{ 179,  15},
111	{ 178,  13},
112	{ 177,  10},
113	{ 176,   8},
114	{ 175,   5},
115	{   0,   0},
116};
117
118/* MAX1111 Commands */
119#define MAXCTRL_PD0      1u << 0
120#define MAXCTRL_PD1      1u << 1
121#define MAXCTRL_SGL      1u << 2
122#define MAXCTRL_UNI      1u << 3
123#define MAXCTRL_SEL_SH   4
124#define MAXCTRL_STR      1u << 7
125
126/*
127 * Read MAX1111 ADC
128 */
129int sharpsl_pm_pxa_read_max1111(int channel)
130{
131	if (machine_is_tosa()) // Ugly, better move this function into another module
132	    return 0;
133
134	return corgi_ssp_max1111_get((channel << MAXCTRL_SEL_SH) | MAXCTRL_PD0 | MAXCTRL_PD1
135			| MAXCTRL_SGL | MAXCTRL_UNI | MAXCTRL_STR);
136}
137
138void sharpsl_pm_pxa_init(void)
139{
140	pxa_gpio_mode(sharpsl_pm.machinfo->gpio_acin | GPIO_IN);
141	pxa_gpio_mode(sharpsl_pm.machinfo->gpio_batfull | GPIO_IN);
142	pxa_gpio_mode(sharpsl_pm.machinfo->gpio_batlock | GPIO_IN);
143
144	/* Register interrupt handlers */
145	if (request_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_acin), sharpsl_ac_isr, IRQF_DISABLED, "AC Input Detect", sharpsl_ac_isr)) {
146		dev_err(sharpsl_pm.dev, "Could not get irq %d.\n", IRQ_GPIO(sharpsl_pm.machinfo->gpio_acin));
147	}
148	else set_irq_type(IRQ_GPIO(sharpsl_pm.machinfo->gpio_acin),IRQT_BOTHEDGE);
149
150	if (request_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batlock), sharpsl_fatal_isr, IRQF_DISABLED, "Battery Cover", sharpsl_fatal_isr)) {
151		dev_err(sharpsl_pm.dev, "Could not get irq %d.\n", IRQ_GPIO(sharpsl_pm.machinfo->gpio_batlock));
152	}
153	else set_irq_type(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batlock),IRQT_FALLING);
154
155	if (sharpsl_pm.machinfo->gpio_fatal) {
156		if (request_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_fatal), sharpsl_fatal_isr, IRQF_DISABLED, "Fatal Battery", sharpsl_fatal_isr)) {
157			dev_err(sharpsl_pm.dev, "Could not get irq %d.\n", IRQ_GPIO(sharpsl_pm.machinfo->gpio_fatal));
158		}
159		else set_irq_type(IRQ_GPIO(sharpsl_pm.machinfo->gpio_fatal),IRQT_FALLING);
160	}
161
162	if (sharpsl_pm.machinfo->batfull_irq)
163	{
164		/* Register interrupt handler. */
165		if (request_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batfull), sharpsl_chrg_full_isr, IRQF_DISABLED, "CO", sharpsl_chrg_full_isr)) {
166			dev_err(sharpsl_pm.dev, "Could not get irq %d.\n", IRQ_GPIO(sharpsl_pm.machinfo->gpio_batfull));
167		}
168		else set_irq_type(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batfull),IRQT_RISING);
169	}
170}
171
172void sharpsl_pm_pxa_remove(void)
173{
174	free_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_acin), sharpsl_ac_isr);
175	free_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batlock), sharpsl_fatal_isr);
176
177	if (sharpsl_pm.machinfo->gpio_fatal)
178		free_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_fatal), sharpsl_fatal_isr);
179
180	if (sharpsl_pm.machinfo->batfull_irq)
181		free_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batfull), sharpsl_chrg_full_isr);
182}
183