2 * Battery driver for a Greybus module.
4 * Copyright 2014 Google Inc.
6 * Released under the GPLv2 only.
9 #include <linux/kernel.h>
10 #include <linux/module.h>
11 #include <linux/slab.h>
12 #include <linux/power_supply.h>
16 struct power_supply bat;
18 // we will want to keep the battery stats in here as we will be getting
19 // updates from the SVC "on the fly" so we don't have to always go ask
20 // the battery for some information. Hopefully...
21 struct gb_connection *connection;
26 #define to_gb_battery(x) container_of(x, struct gb_battery, bat)
28 /* Version of the Greybus battery protocol we support */
29 #define GB_BATTERY_VERSION_MAJOR 0x00
30 #define GB_BATTERY_VERSION_MINOR 0x01
32 /* Greybus battery request types */
33 #define GB_BATTERY_TYPE_INVALID 0x00
34 #define GB_BATTERY_TYPE_PROTOCOL_VERSION 0x01
35 #define GB_BATTERY_TYPE_TECHNOLOGY 0x02
36 #define GB_BATTERY_TYPE_STATUS 0x03
37 #define GB_BATTERY_TYPE_MAX_VOLTAGE 0x04
38 #define GB_BATTERY_TYPE_CAPACITY 0x05
39 #define GB_BATTERY_TYPE_TEMPERATURE 0x06
40 #define GB_BATTERY_TYPE_VOLTAGE 0x07
42 struct gb_battery_proto_version_response {
48 /* Should match up with battery types in linux/power_supply.h */
49 #define GB_BATTERY_TECH_UNKNOWN 0x0000
50 #define GB_BATTERY_TECH_NiMH 0x0001
51 #define GB_BATTERY_TECH_LION 0x0002
52 #define GB_BATTERY_TECH_LIPO 0x0003
53 #define GB_BATTERY_TECH_LiFe 0x0004
54 #define GB_BATTERY_TECH_NiCd 0x0005
55 #define GB_BATTERY_TECH_LiMn 0x0006
57 struct gb_battery_technology_request {
62 /* Should match up with battery status in linux/power_supply.h */
63 #define GB_BATTERY_STATUS_UNKNOWN 0x0000
64 #define GB_BATTERY_STATUS_CHARGING 0x0001
65 #define GB_BATTERY_STATUS_DISCHARGING 0x0002
66 #define GB_BATTERY_STATUS_NOT_CHARGING 0x0003
67 #define GB_BATTERY_STATUS_FULL 0x0004
69 struct gb_battery_status_request {
71 __le16 battery_status;
74 struct gb_battery_max_voltage_request {
79 struct gb_battery_capacity_request {
84 struct gb_battery_temperature_request {
89 struct gb_battery_voltage_request {
95 static const struct greybus_module_id id_table[] = {
96 { GREYBUS_DEVICE(0x42, 0x42) }, /* make shit up */
97 { }, /* terminating NULL entry */
100 static int battery_operation(struct gb_battery *gb, int type,
101 void *response, int response_size)
103 struct gb_connection *connection = gb->connection;
104 struct gb_operation *operation;
105 struct gb_battery_technology_request *fake_request;
109 local_response = kmalloc(response_size, GFP_KERNEL);
113 operation = gb_operation_create(connection, type, 0, response_size);
115 kfree(local_response);
119 /* Synchronous operation--no callback */
120 ret = gb_operation_request_send(operation, NULL);
122 pr_err("version operation failed (%d)\n", ret);
127 * We only want to look at the status, and all requests have the same
128 * layout for where the status is, so cast this to a random request so
129 * we can see the status easier.
131 fake_request = (struct gb_battery_technology_request *)local_response;
132 if (fake_request->status) {
133 gb_connection_err(connection, "version response %hhu",
134 fake_request->status);
137 /* Good request, so copy to the caller's buffer */
138 memcpy(response, local_response, response_size);
141 gb_operation_destroy(operation);
147 * This request only uses the connection field, and if successful,
148 * fills in the major and minor protocol version of the target.
150 static int get_version(struct gb_battery *gb)
152 struct gb_battery_proto_version_response version_request;
155 retval = battery_operation(gb, GB_BATTERY_TYPE_PROTOCOL_VERSION,
156 &version_request, sizeof(version_request));
160 if (version_request.major > GB_BATTERY_VERSION_MAJOR) {
161 pr_err("unsupported major version (%hhu > %hhu)\n",
162 version_request.major, GB_BATTERY_VERSION_MAJOR);
166 gb->version_major = version_request.major;
167 gb->version_minor = version_request.minor;
171 static int get_tech(struct gb_battery *gb)
173 struct gb_battery_technology_request tech_request;
177 retval = battery_operation(gb, GB_BATTERY_TYPE_TECHNOLOGY,
178 &tech_request, sizeof(tech_request));
183 * We have a one-to-one mapping of tech types to power_supply
184 * status, so just return that value.
186 technology = le32_to_cpu(tech_request.technology);
190 static int get_status(struct gb_battery *gb)
192 struct gb_battery_status_request status_request;
196 retval = battery_operation(gb, GB_BATTERY_TYPE_STATUS,
197 &status_request, sizeof(status_request));
202 * We have a one-to-one mapping of battery status to power_supply
203 * status, so just return that value.
205 battery_status = le16_to_cpu(status_request.battery_status);
206 return battery_status;
209 static int get_max_voltage(struct gb_battery *gb)
211 struct gb_battery_max_voltage_request volt_request;
215 retval = battery_operation(gb, GB_BATTERY_TYPE_MAX_VOLTAGE,
216 &volt_request, sizeof(volt_request));
220 max_voltage = le32_to_cpu(volt_request.max_voltage);
224 static int get_capacity(struct gb_battery *gb)
226 struct gb_battery_capacity_request capacity_request;
230 retval = battery_operation(gb, GB_BATTERY_TYPE_CAPACITY,
231 &capacity_request, sizeof(capacity_request));
235 capacity = le32_to_cpu(capacity_request.capacity);
239 static int get_temp(struct gb_battery *gb)
241 struct gb_battery_temperature_request temp_request;
245 retval = battery_operation(gb, GB_BATTERY_TYPE_TEMPERATURE,
246 &temp_request, sizeof(temp_request));
250 temperature = le32_to_cpu(temp_request.temperature);
254 static int get_voltage(struct gb_battery *gb)
256 struct gb_battery_voltage_request voltage_request;
260 retval = battery_operation(gb, GB_BATTERY_TYPE_VOLTAGE,
261 &voltage_request, sizeof(voltage_request));
265 voltage = le32_to_cpu(voltage_request.voltage);
269 static int get_property(struct power_supply *b,
270 enum power_supply_property psp,
271 union power_supply_propval *val)
273 struct gb_battery *gb = to_gb_battery(b);
276 case POWER_SUPPLY_PROP_TECHNOLOGY:
277 val->intval = get_tech(gb);
280 case POWER_SUPPLY_PROP_STATUS:
281 val->intval = get_status(gb);
284 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
285 val->intval = get_max_voltage(gb);
288 case POWER_SUPPLY_PROP_CAPACITY:
289 val->intval = get_capacity(gb);
292 case POWER_SUPPLY_PROP_TEMP:
293 val->intval = get_temp(gb);
296 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
297 val->intval = get_voltage(gb);
307 // FIXME - verify this list, odds are some can be removed and others added.
308 static enum power_supply_property battery_props[] = {
309 POWER_SUPPLY_PROP_TECHNOLOGY,
310 POWER_SUPPLY_PROP_STATUS,
311 POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
312 POWER_SUPPLY_PROP_CAPACITY,
313 POWER_SUPPLY_PROP_TEMP,
314 POWER_SUPPLY_PROP_VOLTAGE_NOW,
317 int gb_battery_device_init(struct gb_connection *connection)
319 struct gb_battery *gb;
320 struct power_supply *b;
323 gb = kzalloc(sizeof(*gb), GFP_KERNEL);
327 gb->connection = connection; // FIXME refcount!
328 connection->private = gb;
330 /* Check the version */
331 retval = get_version(gb);
338 // FIXME - get a better (i.e. unique) name
339 // FIXME - anything else needs to be set?
340 b->name = "gb_battery";
341 b->type = POWER_SUPPLY_TYPE_BATTERY,
342 b->properties = battery_props,
343 b->num_properties = ARRAY_SIZE(battery_props),
344 b->get_property = get_property,
346 retval = power_supply_register(&connection->interface->gmod->dev, b);
355 void gb_battery_device_exit(struct gb_connection *connection)
357 struct gb_battery *gb = connection->private;
359 power_supply_unregister(&gb->bat);
363 void gb_battery_disconnect(struct gb_module *gmod)
366 struct gb_battery *gb;
368 gb = gmod->gb_battery;
372 power_supply_unregister(&gb->bat);
379 static struct greybus_driver battery_gb_driver = {
380 .probe = gb_battery_probe,
381 .disconnect = gb_battery_disconnect,
382 .id_table = id_table,
385 module_greybus_driver(battery_gb_driver);
386 MODULE_LICENSE("GPL");
387 MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@linuxfoundation.org>");