Blame view

drivers/power/supply/pmu_battery.c 5.59 KB
efea58e39   David Woodhouse   [BATTERY] Apple P...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  /*
   * Battery class driver for Apple PMU
   *
   *	Copyright © 2006  David Woodhouse <dwmw2@infradead.org>
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License version 2 as
   * published by the Free Software Foundation.
   */
  
  #include <linux/module.h>
  #include <linux/platform_device.h>
  #include <linux/err.h>
  #include <linux/power_supply.h>
  #include <linux/adb.h>
  #include <linux/pmu.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
17
  #include <linux/slab.h>
efea58e39   David Woodhouse   [BATTERY] Apple P...
18
19
  
  static struct pmu_battery_dev {
297d716f6   Krzysztof Kozlowski   power_supply: Cha...
20
21
  	struct power_supply *bat;
  	struct power_supply_desc bat_desc;
efea58e39   David Woodhouse   [BATTERY] Apple P...
22
23
24
25
  	struct pmu_battery_info *pbi;
  	char name[16];
  	int propval;
  } *pbats[PMU_MAX_BATTERIES];
297d716f6   Krzysztof Kozlowski   power_supply: Cha...
26
  #define to_pmu_battery_dev(x) power_supply_get_drvdata(x)
efea58e39   David Woodhouse   [BATTERY] Apple P...
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
  
  /*********************************************************************
   *		Power
   *********************************************************************/
  
  static int pmu_get_ac_prop(struct power_supply *psy,
  			   enum power_supply_property psp,
  			   union power_supply_propval *val)
  {
  	switch (psp) {
  	case POWER_SUPPLY_PROP_ONLINE:
  		val->intval = (!!(pmu_power_flags & PMU_PWR_AC_PRESENT)) ||
  			      (pmu_battery_count == 0);
  		break;
  	default:
  		return -EINVAL;
  	}
  
  	return 0;
  }
  
  static enum power_supply_property pmu_ac_props[] = {
  	POWER_SUPPLY_PROP_ONLINE,
  };
297d716f6   Krzysztof Kozlowski   power_supply: Cha...
51
  static const struct power_supply_desc pmu_ac_desc = {
efea58e39   David Woodhouse   [BATTERY] Apple P...
52
53
54
55
56
57
  	.name = "pmu-ac",
  	.type = POWER_SUPPLY_TYPE_MAINS,
  	.properties = pmu_ac_props,
  	.num_properties = ARRAY_SIZE(pmu_ac_props),
  	.get_property = pmu_get_ac_prop,
  };
297d716f6   Krzysztof Kozlowski   power_supply: Cha...
58
  static struct power_supply *pmu_ac;
efea58e39   David Woodhouse   [BATTERY] Apple P...
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
  /*********************************************************************
   *		Battery properties
   *********************************************************************/
  
  static char *pmu_batt_types[] = {
  	"Smart", "Comet", "Hooper", "Unknown"
  };
  
  static char *pmu_bat_get_model_name(struct pmu_battery_info *pbi)
  {
  	switch (pbi->flags & PMU_BATT_TYPE_MASK) {
  	case PMU_BATT_TYPE_SMART:
  		return pmu_batt_types[0];
  	case PMU_BATT_TYPE_COMET:
  		return pmu_batt_types[1];
  	case PMU_BATT_TYPE_HOOPER:
  		return pmu_batt_types[2];
  	default: break;
  	}
  	return pmu_batt_types[3];
  }
  
  static int pmu_bat_get_property(struct power_supply *psy,
  				enum power_supply_property psp,
  				union power_supply_propval *val)
  {
  	struct pmu_battery_dev *pbat = to_pmu_battery_dev(psy);
  	struct pmu_battery_info *pbi = pbat->pbi;
  
  	switch (psp) {
  	case POWER_SUPPLY_PROP_STATUS:
  		if (pbi->flags & PMU_BATT_CHARGING)
  			val->intval = POWER_SUPPLY_STATUS_CHARGING;
d54e7929d   Thomas Champagne   pmu_battery: Fix ...
92
93
  		else if (pmu_power_flags & PMU_PWR_AC_PRESENT)
  			val->intval = POWER_SUPPLY_STATUS_FULL;
efea58e39   David Woodhouse   [BATTERY] Apple P...
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
  		else
  			val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
  		break;
  	case POWER_SUPPLY_PROP_PRESENT:
  		val->intval = !!(pbi->flags & PMU_BATT_PRESENT);
  		break;
  	case POWER_SUPPLY_PROP_MODEL_NAME:
  		val->strval = pmu_bat_get_model_name(pbi);
  		break;
  	case POWER_SUPPLY_PROP_ENERGY_AVG:
  		val->intval = pbi->charge     * 1000; /* mWh -> µWh */
  		break;
  	case POWER_SUPPLY_PROP_ENERGY_FULL:
  		val->intval = pbi->max_charge * 1000; /* mWh -> µWh */
  		break;
  	case POWER_SUPPLY_PROP_CURRENT_AVG:
  		val->intval = pbi->amperage   * 1000; /* mA -> µA */
  		break;
  	case POWER_SUPPLY_PROP_VOLTAGE_AVG:
  		val->intval = pbi->voltage    * 1000; /* mV -> µV */
  		break;
  	case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
  		val->intval = pbi->time_remaining;
  		break;
  	default:
  		return -EINVAL;
  	}
  
  	return 0;
  }
  
  static enum power_supply_property pmu_bat_props[] = {
  	POWER_SUPPLY_PROP_STATUS,
  	POWER_SUPPLY_PROP_PRESENT,
  	POWER_SUPPLY_PROP_MODEL_NAME,
  	POWER_SUPPLY_PROP_ENERGY_AVG,
  	POWER_SUPPLY_PROP_ENERGY_FULL,
  	POWER_SUPPLY_PROP_CURRENT_AVG,
  	POWER_SUPPLY_PROP_VOLTAGE_AVG,
  	POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
  };
  
  /*********************************************************************
   *		Initialisation
   *********************************************************************/
  
  static struct platform_device *bat_pdev;
  
  static int __init pmu_bat_init(void)
  {
297d716f6   Krzysztof Kozlowski   power_supply: Cha...
144
  	int ret = 0;
efea58e39   David Woodhouse   [BATTERY] Apple P...
145
146
147
148
149
150
151
152
  	int i;
  
  	bat_pdev = platform_device_register_simple("pmu-battery",
  						   0, NULL, 0);
  	if (IS_ERR(bat_pdev)) {
  		ret = PTR_ERR(bat_pdev);
  		goto pdev_register_failed;
  	}
297d716f6   Krzysztof Kozlowski   power_supply: Cha...
153
154
155
  	pmu_ac = power_supply_register(&bat_pdev->dev, &pmu_ac_desc, NULL);
  	if (IS_ERR(pmu_ac)) {
  		ret = PTR_ERR(pmu_ac);
efea58e39   David Woodhouse   [BATTERY] Apple P...
156
  		goto ac_register_failed;
297d716f6   Krzysztof Kozlowski   power_supply: Cha...
157
  	}
efea58e39   David Woodhouse   [BATTERY] Apple P...
158
159
  
  	for (i = 0; i < pmu_battery_count; i++) {
297d716f6   Krzysztof Kozlowski   power_supply: Cha...
160
  		struct power_supply_config psy_cfg = {};
efea58e39   David Woodhouse   [BATTERY] Apple P...
161
162
163
164
  		struct pmu_battery_dev *pbat = kzalloc(sizeof(*pbat),
  						       GFP_KERNEL);
  		if (!pbat)
  			break;
35bf55914   Christian Kujau   PMU battery: file...
165
  		sprintf(pbat->name, "PMU_battery_%d", i);
297d716f6   Krzysztof Kozlowski   power_supply: Cha...
166
167
168
169
  		pbat->bat_desc.name = pbat->name;
  		pbat->bat_desc.properties = pmu_bat_props;
  		pbat->bat_desc.num_properties = ARRAY_SIZE(pmu_bat_props);
  		pbat->bat_desc.get_property = pmu_bat_get_property;
efea58e39   David Woodhouse   [BATTERY] Apple P...
170
  		pbat->pbi = &pmu_batteries[i];
297d716f6   Krzysztof Kozlowski   power_supply: Cha...
171
  		psy_cfg.drv_data = pbat;
efea58e39   David Woodhouse   [BATTERY] Apple P...
172

297d716f6   Krzysztof Kozlowski   power_supply: Cha...
173
174
175
176
177
  		pbat->bat = power_supply_register(&bat_pdev->dev,
  						  &pbat->bat_desc,
  						  &psy_cfg);
  		if (IS_ERR(pbat->bat)) {
  			ret = PTR_ERR(pbat->bat);
efea58e39   David Woodhouse   [BATTERY] Apple P...
178
179
180
181
182
183
184
185
186
187
188
189
  			kfree(pbat);
  			goto battery_register_failed;
  		}
  		pbats[i] = pbat;
  	}
  
  	goto success;
  
  battery_register_failed:
  	while (i--) {
  		if (!pbats[i])
  			continue;
297d716f6   Krzysztof Kozlowski   power_supply: Cha...
190
  		power_supply_unregister(pbats[i]->bat);
efea58e39   David Woodhouse   [BATTERY] Apple P...
191
192
  		kfree(pbats[i]);
  	}
297d716f6   Krzysztof Kozlowski   power_supply: Cha...
193
  	power_supply_unregister(pmu_ac);
efea58e39   David Woodhouse   [BATTERY] Apple P...
194
195
196
197
198
199
200
201
202
203
204
205
206
207
  ac_register_failed:
  	platform_device_unregister(bat_pdev);
  pdev_register_failed:
  success:
  	return ret;
  }
  
  static void __exit pmu_bat_exit(void)
  {
  	int i;
  
  	for (i = 0; i < PMU_MAX_BATTERIES; i++) {
  		if (!pbats[i])
  			continue;
297d716f6   Krzysztof Kozlowski   power_supply: Cha...
208
  		power_supply_unregister(pbats[i]->bat);
efea58e39   David Woodhouse   [BATTERY] Apple P...
209
210
  		kfree(pbats[i]);
  	}
297d716f6   Krzysztof Kozlowski   power_supply: Cha...
211
  	power_supply_unregister(pmu_ac);
efea58e39   David Woodhouse   [BATTERY] Apple P...
212
  	platform_device_unregister(bat_pdev);
efea58e39   David Woodhouse   [BATTERY] Apple P...
213
214
215
216
217
218
219
220
  }
  
  module_init(pmu_bat_init);
  module_exit(pmu_bat_exit);
  
  MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
  MODULE_LICENSE("GPL");
  MODULE_DESCRIPTION("PMU battery driver");