summaryrefslogtreecommitdiffstats
path: root/target/linux/s3c24xx/patches-2.6.24/1242-fix-bq27000-charger-state-tracking.patch.patch
blob: 20442adb4c924827a63c4f07ed5b7fa8138f2d16 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
From 46159c9a3fba291d106625092fd62358548894e0 Mon Sep 17 00:00:00 2001
From: Andy Green <andy@openmoko.com>
Date: Tue, 22 Jul 2008 13:16:16 +0100
Subject: [PATCH] fix-bq27000-charger-state-tracking.patch

Charger trigger stuff goes and asks for POWER_SUPPLY_PROP_STATUS
to figure out what the charger state is.  But until now, we only
reported there what we found out from HDQ, and the HDQ registers
are not updated very often in the coulomb counter, it can be 4
or more second lag before it tells us about what it experiences.

When we react to USB insertion and only after 500ms debounce tell
power_supply stuff that something changed, it most times will
see old pre-USB-insertion state from bq27000 over HDQ at that time
and will report it ain't charging, buggering up the LED trigger
tracking.

This patch maintains distance between bq27000 and pcf50633 by
having platform callbacks in bq27000 that it can use to ask about
definitive charger "online" presence and "activity", whether the
charger says it is charging.  If these callbacks are implemented
(and we implement them in this patch up in mach_gta02.c) then
this information is used in preference to what is found from
HDQ.

Result is if you set the LED trigger like this:

echo bat-charging > /sys/devices/platform/gta02-led.0/leds/gta02-aux:red/trigger

then it lights up properly on USB insertion now, goes away on
removal properly, as as far as I saw, when charging stops too.

Signed-off-by: Andy Green <andy@openmoko.com>
---
 arch/arm/mach-s3c2440/mach-gta02.c |   32 +++++++++++++++--
 drivers/power/bq27000_battery.c    |   65 ++++++++++++++++++++++++-----------
 include/linux/bq27000_battery.h    |    2 +
 3 files changed, 74 insertions(+), 25 deletions(-)

diff --git a/arch/arm/mach-s3c2440/mach-gta02.c b/arch/arm/mach-s3c2440/mach-gta02.c
index 59ba890..1fcd3fd 100644
--- a/arch/arm/mach-s3c2440/mach-gta02.c
+++ b/arch/arm/mach-s3c2440/mach-gta02.c
@@ -96,6 +96,9 @@ struct resume_dependency resume_dep_jbt_glamo;
 struct resume_dependency resume_dep_glamo_mci_pcf;
 
 
+static int gta02_charger_online_status;
+static int gta02_charger_active_status;
+
 /* define FIQ IPC struct */
 /*
  * contains stuff FIQ ISR modifies and normal kernel code can see and use
@@ -457,12 +460,25 @@ static struct s3c2410_uartcfg gta02_uartcfgs[] = {
 
 /* BQ27000 Battery */
 
+static int gta02_get_charger_online_status(void)
+{
+	return gta02_charger_online_status;
+}
+
+static int gta02_get_charger_active_status(void)
+{
+	return gta02_charger_active_status;
+}
+
+
 struct bq27000_platform_data bq27000_pdata = {
 	.name = "bat",
 	.rsense_mohms = 20,
 	.hdq_read = gta02hdq_read,
 	.hdq_write = gta02hdq_write,
 	.hdq_initialized = gta02hdq_initialized,
+	.get_charger_online_status = gta02_get_charger_online_status,
+	.get_charger_active_status = gta02_get_charger_active_status
 };
 
 struct platform_device bq27000_battery_device = {
@@ -481,12 +497,20 @@ static int pmu_callback(struct device *dev, unsigned int feature,
 	switch (feature) {
 	case PCF50633_FEAT_MBC:
 		switch (event) {
-		case PMU_EVT_USB_INSERT:
-		case PMU_EVT_USB_REMOVE:
 		case PMU_EVT_CHARGER_IDLE:
+			gta02_charger_active_status = 0;
+			break;
 		case PMU_EVT_CHARGER_ACTIVE:
-		case PMU_EVT_INSERT: /* adapter */
-		case PMU_EVT_REMOVE: /* adapter */
+			gta02_charger_active_status = 1;
+			break;
+		case PMU_EVT_USB_INSERT:
+			gta02_charger_online_status = 1;
+			break;
+		case PMU_EVT_USB_REMOVE:
+			gta02_charger_online_status = 0;
+			break;
+		case PMU_EVT_INSERT: /* adapter is unsused */
+		case PMU_EVT_REMOVE: /* adapter is unused */
 			break;
 		default:
 			break;
diff --git a/drivers/power/bq27000_battery.c b/drivers/power/bq27000_battery.c
index 4855d5a..7020608 100644
--- a/drivers/power/bq27000_battery.c
+++ b/drivers/power/bq27000_battery.c
@@ -113,12 +113,7 @@ enum bq27000_status_flags {
 struct bq27000_device_info {
 	struct device *dev;
 	struct power_supply bat;
-
-	int rsense_mohms;		/* from platform */
-
-	int (*hdq_initialized)(void); /* from platform */
-	int (*hdq_read)(int); /* from platform */
-	int (*hdq_write)(int, u8); /* from platform */
+	struct bq27000_platform_data *pdata;
 };
 
 /*
@@ -136,16 +131,16 @@ static int hdq_read16(struct bq27000_device_info *di, int address)
 
 	while (retries--) {
 
-		high = (di->hdq_read)(address + 1); /* high part */
+		high = (di->pdata->hdq_read)(address + 1); /* high part */
 
 		if (high < 0)
 			return high;
-		acc = (di->hdq_read)(address);
+		acc = (di->pdata->hdq_read)(address);
 		if (acc < 0)
 			return acc;
 
 		/* confirm high didn't change between reading it and low */
-		if (high == (di->hdq_read)(address + 1))
+		if (high == (di->pdata->hdq_read)(address + 1))
 			return (high << 8) | acc;
 	}
 
@@ -170,12 +165,36 @@ static int bq27000_battery_get_property(struct power_supply *psy,
 	int v, n;
 	struct bq27000_device_info *di = to_bq27000_device_info(psy);
 
-	if (!(di->hdq_initialized)())
+	if (!(di->pdata->hdq_initialized)())
 		return -EINVAL;
 
 	switch (psp) {
 	case POWER_SUPPLY_PROP_STATUS:
 		val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
+
+		if (!di->pdata->get_charger_online_status)
+			goto use_bat;
+		if ((di->pdata->get_charger_online_status)()) {
+			/*
+			 * charger is definitively present
+			 * we report our state in terms of what it says it
+			 * is doing
+			 */
+			if (!di->pdata->get_charger_active_status)
+				goto use_bat;
+			if ((di->pdata->get_charger_active_status)())
+				val->intval = POWER_SUPPLY_STATUS_CHARGING;
+			else
+				val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
+			break;
+		}
+use_bat:
+		/*
+		 * either the charger is not connected, or the
+		 * platform doesn't give info about charger, use battery state
+		 * but... battery state can be out of date by 4 seconds or
+		 * so... use the platform callbacks if possible.
+		 */
 		v = hdq_read16(di, BQ27000_AI_L);
 		if (v < 0)
 			return v;
@@ -189,7 +208,7 @@ static int bq27000_battery_get_property(struct power_supply *psy,
 			break;
 		}
 		/* power is actually going in or out... */
-		v = (di->hdq_read)(BQ27000_FLAGS);
+		v = (di->pdata->hdq_read)(BQ27000_FLAGS);
 		if (v < 0)
 			return v;
 		if (v & BQ27000_STATUS_CHGS)
@@ -205,7 +224,7 @@ static int bq27000_battery_get_property(struct power_supply *psy,
 		val->intval = v * 1000;
 		break;
 	case POWER_SUPPLY_PROP_CURRENT_NOW:
-		v = (di->hdq_read)(BQ27000_FLAGS);
+		v = (di->pdata->hdq_read)(BQ27000_FLAGS);
 		if (v < 0)
 			return v;
 		if (v & BQ27000_STATUS_CHGS)
@@ -215,13 +234,13 @@ static int bq27000_battery_get_property(struct power_supply *psy,
 		v = hdq_read16(di, BQ27000_AI_L);
 		if (v < 0)
 			return v;
-		val->intval = (v * n) / di->rsense_mohms;
+		val->intval = (v * n) / di->pdata->rsense_mohms;
 		break;
 	case POWER_SUPPLY_PROP_CHARGE_FULL:
 		v = hdq_read16(di, BQ27000_LMD_L);
 		if (v < 0)
 			return v;
-		val->intval = (v * 3570) / di->rsense_mohms;
+		val->intval = (v * 3570) / di->pdata->rsense_mohms;
 		break;
 	case POWER_SUPPLY_PROP_TEMP:
 		v = hdq_read16(di, BQ27000_TEMP_L);
@@ -235,12 +254,12 @@ static int bq27000_battery_get_property(struct power_supply *psy,
 		val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
 		break;
 	case POWER_SUPPLY_PROP_CAPACITY:
-		val->intval = (di->hdq_read)(BQ27000_RSOC);
+		val->intval = (di->pdata->hdq_read)(BQ27000_RSOC);
 		if (val->intval < 0)
 			return val->intval;
 		break;
 	case POWER_SUPPLY_PROP_PRESENT:
-		v = (di->hdq_read)(BQ27000_RSOC);
+		v = (di->pdata->hdq_read)(BQ27000_RSOC);
 		val->intval = !(v < 0);
 		break;
 	case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW:
@@ -255,6 +274,12 @@ static int bq27000_battery_get_property(struct power_supply *psy,
 			return v;
 		val->intval = 60 * v;
 		break;
+	case POWER_SUPPLY_PROP_ONLINE:
+		if (di->pdata->get_charger_online_status)
+			val->intval = (di->pdata->get_charger_online_status)();
+		else
+			return -EINVAL;
+		break;
 	default:
 		return -EINVAL;
 	}
@@ -272,7 +297,8 @@ static enum power_supply_property bq27000_battery_props[] = {
 	POWER_SUPPLY_PROP_PRESENT,
 	POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
 	POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
-	POWER_SUPPLY_PROP_CAPACITY
+	POWER_SUPPLY_PROP_CAPACITY,
+	POWER_SUPPLY_PROP_ONLINE
 };
 
 static int bq27000_battery_probe(struct platform_device *pdev)
@@ -302,10 +328,7 @@ static int bq27000_battery_probe(struct platform_device *pdev)
 	di->bat.external_power_changed =
 				  bq27000_battery_external_power_changed;
 	di->bat.use_for_apm = 1;
-	di->hdq_read = pdata->hdq_read;
-	di->hdq_write = pdata->hdq_write;
-	di->rsense_mohms = pdata->rsense_mohms;
-	di->hdq_initialized = pdata->hdq_initialized;
+	di->pdata = pdata;
 
 	retval = power_supply_register(&pdev->dev, &di->bat);
 	if (retval) {
diff --git a/include/linux/bq27000_battery.h b/include/linux/bq27000_battery.h
index fed4287..a617466 100644
--- a/include/linux/bq27000_battery.h
+++ b/include/linux/bq27000_battery.h
@@ -9,6 +9,8 @@ struct bq27000_platform_data {
 	int (*hdq_read)(int);
 	int (*hdq_write)(int, u8);
 	int (*hdq_initialized)(void);
+	int (*get_charger_online_status)(void);
+	int (*get_charger_active_status)(void);
 };
 
 #endif
-- 
1.5.6.5