/*
* Power Supply driver for a Greybus module.
*
* Copyright 2014-2015 Google Inc.
* Copyright 2014-2015 Linaro Ltd.
*
* Released under the GPLv2 only.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/power_supply.h>
#include <linux/slab.h>
#include "greybus.h"
#define PROP_MAX 32
struct gb_power_supply_prop {
enum power_supply_property prop;
u8 gb_prop;
int val;
int previous_val;
bool is_writeable;
};
struct gb_power_supply {
u8 id;
bool registered;
struct power_supply *psy;
struct power_supply_desc desc;
char name[64];
struct gb_power_supplies *supplies;
struct delayed_work work;
char *manufacturer;
char *model_name;
char *serial_number;
u8 type;
u8 properties_count;
u8 properties_count_str;
unsigned long last_update;
u8 cache_invalid;
unsigned int update_interval;
bool changed;
struct gb_power_supply_prop *props;
enum power_supply_property *props_raw;
bool pm_acquired;
struct mutex supply_lock;
};
struct gb_power_supplies {
struct gb_connection *connection;
u8 supplies_count;
struct gb_power_supply *supply;
struct mutex supplies_lock;
};
#define to_gb_power_supply(x) power_supply_get_drvdata(x)
/*
* General power supply properties that could be absent from various reasons,
* like kernel versions or vendor specific versions
*/
#ifndef POWER_SUPPLY_PROP_VOLTAGE_BOOT
#define POWER_SUPPLY_PROP_VOLTAGE_BOOT -1
#endif
#ifndef POWER_SUPPLY_PROP_CURRENT_BOOT
#define POWER_SUPPLY_PROP_CURRENT_BOOT -1
#endif
#ifndef POWER_SUPPLY_PROP_CALIBRATE
#define POWER_SUPPLY_PROP_CALIBRATE -1
#endif
/* cache time in milliseconds, if cache_time is set to 0 cache is disable */
static unsigned int cache_time = 1000;
/*
* update interval initial and maximum value, between the two will
* back-off exponential
*/
static unsigned int update_interval_init = 1 * HZ;
static unsigned int update_interval_max = 30 * HZ;
struct gb_power_supply_changes {
enum power_supply_property prop;
u32 tolerance_change;
void (*prop_changed)(struct gb_power_supply *gbpsy,
struct gb_power_supply_prop *prop);
};
static void gb_power_supply_state_change(struct gb_power_supply *gbpsy,
struct gb_power_supply_prop *prop);
static const struct gb_power_supply_changes psy_props_changes[] = {
{ .prop = GB_POWER_SUPPLY_PROP_STATUS,
.tolerance_change = 0,
.prop_changed = gb_power_supply_state_change,
},
{ .prop = GB_POWER_SUPPLY_PROP_TEMP,
.tolerance_change = 500,
.prop_changed = NULL,
},
{ .prop = GB_POWER_SUPPLY_PROP_ONLINE,
.tolerance_change = 0,
.prop_changed = NULL,
},
};
static int get_psp_from_gb_prop(int gb_prop, enum power_supply_property *psp)
{
int prop;
switch (gb_prop) {
case GB_POWER_SUPPLY_PROP_STATUS:
prop = POWER_SUPPLY_PROP_STATUS;
break;
case GB_POWER_SUPPLY_PROP_CHARGE_TYPE:
prop = POWER_SUPPLY_PROP_CHARGE_TYPE;
break;
case GB_POWER_SUPPLY_PROP_HEALTH:
prop = POWER_SUPPLY_PROP_HEALTH;
break;
case GB_POWER_SUPPLY_PROP_PRESENT:
prop = POWER_SUPPLY_PROP_PRESENT;
break;
case GB_POWER_SUPPLY_PROP_ONLINE:
prop = POWER_SUPPLY_PROP_ONLINE;
break;
case GB_POWER_SUPPLY_PROP_AUTHENTIC:
prop = POWER_SUPPLY_PROP_AUTHENTIC;
break;
case GB_POWER_SUPPLY_PROP_TECHNOLOGY:
prop = POWER_SUPPLY_PROP_TECHNOLOGY;
break;
case GB_POWER_SUPPLY_PROP_CYCLE_COUNT:
prop = POWER_SUPPLY_PROP_CYCLE_COUNT;
break;
cas