880 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			880 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
/*******************************************************************************
 | 
						|
  Copyright (C), 2014, TP-LINK TECHNOLOGIES CO., LTD.
 | 
						|
  File name   : mp2617-charger.c
 | 
						|
  Description : Driver for charge ic mp2617.
 | 
						|
  Author      : linyunfeng
 | 
						|
 | 
						|
  History:
 | 
						|
------------------------------
 | 
						|
V0.2, 2014-04-29, linyunfeng    complete the driver of mp2617.
 | 
						|
V0.1, 2014-03-29, linyunfeng    create file.
 | 
						|
*******************************************************************************/
 | 
						|
 | 
						|
#include <linux/module.h>
 | 
						|
#include <linux/mutex.h>
 | 
						|
#include <linux/of.h>
 | 
						|
#include <linux/of_device.h>
 | 
						|
#include <linux/power_supply.h>
 | 
						|
#include <linux/slab.h>
 | 
						|
#include <linux/of_gpio.h>
 | 
						|
#include <linux/qpnp/qpnp-adc.h>
 | 
						|
 | 
						|
#ifdef MP2617_DEBUG
 | 
						|
#undef dev_dbg
 | 
						|
#define dev_dbg(dev, format, arg...)  dev_printk(KERN_INFO, dev, format, ##arg)
 | 
						|
#endif
 | 
						|
 | 
						|
/* USB, set 500mA limit */
 | 
						|
#define USB_INPUT_CURRENT_LIMIT_UA	500000
 | 
						|
 | 
						|
/* Charger, set 1000mA limit */
 | 
						|
#define CHARGER_INPUT_CURRENT_LIMIT_UA	1000000
 | 
						|
 | 
						|
static u32 supported_input_current[] = {
 | 
						|
	USB_INPUT_CURRENT_LIMIT_UA,
 | 
						|
	CHARGER_INPUT_CURRENT_LIMIT_UA,
 | 
						|
};
 | 
						|
 | 
						|
#define DEFAULT_INPUT_CURRENT_LIMIT_UA	CHARGER_INPUT_CURRENT_LIMIT_UA
 | 
						|
 | 
						|
/* Default resistor used for detection */
 | 
						|
#define DEFAULT_CHARGE_DET_RESISTOR	100
 | 
						|
 | 
						|
/* Default battery resistor */
 | 
						|
#define DEFAULT_BATTERY_RESISTOR	120
 | 
						|
 | 
						|
/* Correspondence table of voltage and temperature */
 | 
						|
static const int adc_map_temp[][2] =
 | 
						|
{
 | 
						|
   {1800, -100},
 | 
						|
   {1577, -20},
 | 
						|
   {1524, -15},
 | 
						|
   {1463, -10},
 | 
						|
   {1396,  -5},
 | 
						|
   {1322,   0},
 | 
						|
   {1243,   5},
 | 
						|
   {1159,  10},
 | 
						|
   {1073,  15},
 | 
						|
   {986,   20},
 | 
						|
   {900,   25},
 | 
						|
   {816,   30},
 | 
						|
   {736,   35},
 | 
						|
   {660,   40},
 | 
						|
   {590,   45},
 | 
						|
   {526,   50},
 | 
						|
   {468,   55},
 | 
						|
   {416,   60},
 | 
						|
   {369,   65},
 | 
						|
   {327,   70},
 | 
						|
   {0,   1000}
 | 
						|
};
 | 
						|
 | 
						|
struct mp2617_chip {
 | 
						|
	struct platform_device	*client;
 | 
						|
	struct power_supply	psy;
 | 
						|
	struct power_supply	*usb_psy;
 | 
						|
	struct mutex		lock;
 | 
						|
	int			input_current_limit_ua;
 | 
						|
#ifdef CONFIG_POWER_BANK_DETECT_SUPPORT
 | 
						|
	int			charging_det_resistor;
 | 
						|
	int			battery_resistor;
 | 
						|
	u32			boost_en_gpio;
 | 
						|
#endif
 | 
						|
	int			battery_health;
 | 
						|
	int			charging_vbat_div;
 | 
						|
	bool			battery_present;
 | 
						|
	bool			charging_enabled;
 | 
						|
	bool			charging_allowed;
 | 
						|
	u32			charging_en_gpio;
 | 
						|
	u32			charging_ok_gpio;
 | 
						|
	u32			charging_m0_gpio;
 | 
						|
	u32			charging_m1_gpio;
 | 
						|
};
 | 
						|
 | 
						|
static enum power_supply_property mp2617_power_properties[] = {
 | 
						|
	POWER_SUPPLY_PROP_HEALTH,
 | 
						|
	POWER_SUPPLY_PROP_PRESENT,
 | 
						|
	POWER_SUPPLY_PROP_VOLTAGE_NOW,
 | 
						|
	POWER_SUPPLY_PROP_TEMP,
 | 
						|
	POWER_SUPPLY_PROP_CHARGING_ENABLED,
 | 
						|
	POWER_SUPPLY_PROP_CURRENT_MAX,
 | 
						|
	POWER_SUPPLY_PROP_TECHNOLOGY,
 | 
						|
	POWER_SUPPLY_PROP_MODEL_NAME,
 | 
						|
	POWER_SUPPLY_PROP_MANUFACTURER,
 | 
						|
	POWER_SUPPLY_PROP_CHG_OK,
 | 
						|
#ifdef CONFIG_POWER_BANK_DETECT_SUPPORT
 | 
						|
	POWER_SUPPLY_PROP_VOLTAGE_DROP,
 | 
						|
#endif
 | 
						|
};
 | 
						|
 | 
						|
#ifdef CONFIG_POWER_BANK_DETECT_SUPPORT
 | 
						|
/*******************************************************************************
 | 
						|
  Function    : mp2617_enable_boost
 | 
						|
  Description : Enable or disable the boost chip
 | 
						|
  Input       : chip: chip data
 | 
						|
                enable: true: enable, false: disable
 | 
						|
  Output      : None
 | 
						|
  Return      : 0: OK, Others: Error
 | 
						|
  Others      : None
 | 
						|
*******************************************************************************/
 | 
						|
static int mp2617_enable_boost(struct mp2617_chip *chip, bool enable)
 | 
						|
{
 | 
						|
	int rc = 0;
 | 
						|
 | 
						|
	if (true == enable) {
 | 
						|
		rc = gpio_direction_output(chip->boost_en_gpio, 1);
 | 
						|
	} else {
 | 
						|
		rc = gpio_direction_output(chip->boost_en_gpio, 0);
 | 
						|
	}
 | 
						|
 | 
						|
	if (rc < 0) {
 | 
						|
		dev_err(&chip->client->dev, "%s: enable or disable boost error\n",
 | 
						|
			__func__);
 | 
						|
	}
 | 
						|
 | 
						|
	dev_dbg(&chip->client->dev, "%s, enable=%d, rc = %d\n", __func__, enable, rc);
 | 
						|
 | 
						|
	return rc;
 | 
						|
}
 | 
						|
 | 
						|
/*******************************************************************************
 | 
						|
  Function    : mp2617_get_property_voltage_drop
 | 
						|
  Description : Get the voltage drop by power supply
 | 
						|
  Input       : chip: chip data
 | 
						|
  Output      : None
 | 
						|
  Return      : voltage or error code
 | 
						|
  Others      : None
 | 
						|
*******************************************************************************/
 | 
						|
static int mp2617_get_property_voltage_drop(struct mp2617_chip *chip)
 | 
						|
{
 | 
						|
	int rc = 0;
 | 
						|
	int vol_drop = 0;
 | 
						|
 | 
						|
	struct qpnp_vadc_result results;
 | 
						|
 | 
						|
	rc = qpnp_vadc_read(P_MUX1_1_1, &results);
 | 
						|
	if (rc) {
 | 
						|
		pr_err("Unable to read vbat rc=%d\n", rc);
 | 
						|
		return rc;
 | 
						|
	}
 | 
						|
 | 
						|
	vol_drop = ((int)(results.physical)/chip->charging_det_resistor)
 | 
						|
			* chip->battery_resistor / 1000;
 | 
						|
	return vol_drop;
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
/*******************************************************************************
 | 
						|
  Function    : mp2617_enable_charging
 | 
						|
  Description : Enable charging
 | 
						|
  Input       : chip: chip data
 | 
						|
  Output      : None
 | 
						|
  Return      : 0: OK, Others: Error
 | 
						|
  Others      : None
 | 
						|
*******************************************************************************/
 | 
						|
static int mp2617_enable_charging(struct mp2617_chip *chip)
 | 
						|
{
 | 
						|
	int rc = 0;
 | 
						|
 | 
						|
	if ((!chip->charging_enabled) && (true == chip->charging_allowed)
 | 
						|
		&& (true == chip->battery_present)) {
 | 
						|
		rc = gpio_direction_output(chip->charging_en_gpio, 1);
 | 
						|
 | 
						|
		if (!rc) {
 | 
						|
			chip->charging_enabled = true;
 | 
						|
#ifdef CONFIG_POWER_BANK_DETECT_SUPPORT
 | 
						|
			mp2617_enable_boost(chip, false);
 | 
						|
#endif
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	dev_dbg(&chip->client->dev, "%s, rc = %d\n", __func__, rc);
 | 
						|
 | 
						|
	return rc;
 | 
						|
}
 | 
						|
 | 
						|
/*******************************************************************************
 | 
						|
  Function    : mp2617_disable_charging
 | 
						|
  Description : Disable charging
 | 
						|
  Input       : chip: chip data
 | 
						|
  Output      : None
 | 
						|
  Return      : 0: OK, Others: Error
 | 
						|
  Others      : None
 | 
						|
*******************************************************************************/
 | 
						|
static int mp2617_disable_charging(struct mp2617_chip *chip)
 | 
						|
{
 | 
						|
	int rc = 0;
 | 
						|
 | 
						|
	if (chip->charging_enabled) {
 | 
						|
		rc = gpio_direction_output(chip->charging_en_gpio, 0);
 | 
						|
 | 
						|
		if (!rc) {
 | 
						|
			chip->charging_enabled = false;
 | 
						|
#ifdef CONFIG_POWER_BANK_DETECT_SUPPORT
 | 
						|
			mp2617_enable_boost(chip, true);
 | 
						|
#endif
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	dev_dbg(&chip->client->dev, "%s, rc = %d\n", __func__, rc);
 | 
						|
 | 
						|
	return rc;
 | 
						|
}
 | 
						|
 | 
						|
/*******************************************************************************
 | 
						|
  Function    : mp2617_get_property_chg_ok_level
 | 
						|
  Description : Get the level of chg_ok gpio
 | 
						|
  Input       : chip: chip data
 | 
						|
  Output      : None
 | 
						|
  Return      : Gpio level
 | 
						|
  Others      : None
 | 
						|
*******************************************************************************/
 | 
						|
static int mp2617_get_property_chg_ok_level(struct mp2617_chip *chip)
 | 
						|
{
 | 
						|
	int rc = 0;
 | 
						|
	int result = 0;
 | 
						|
 | 
						|
	rc = gpio_direction_input(chip->charging_ok_gpio);
 | 
						|
	if (!rc) {
 | 
						|
		result = gpio_get_value_cansleep(chip->charging_ok_gpio);
 | 
						|
	}
 | 
						|
 | 
						|
	return result;
 | 
						|
}
 | 
						|
 | 
						|
/*******************************************************************************
 | 
						|
  Function    : mp2617_set_input_current_limit
 | 
						|
  Description : Set the limit of input current
 | 
						|
  Input       : chip: chip data
 | 
						|
                current_limit_ua: the limit of input current
 | 
						|
  Output      : None
 | 
						|
  Return      : 0: OK, Others: Error
 | 
						|
  Others      : None
 | 
						|
*******************************************************************************/
 | 
						|
static int mp2617_set_input_current_limit(struct mp2617_chip *chip,
 | 
						|
					int current_limit_ua)
 | 
						|
{
 | 
						|
	int rc = 0;
 | 
						|
	int i = 0;
 | 
						|
 | 
						|
	for (i = ARRAY_SIZE(supported_input_current) - 1; i >= 0; i--) {
 | 
						|
		if (current_limit_ua >= supported_input_current[i]) {
 | 
						|
			current_limit_ua = supported_input_current[i];
 | 
						|
			break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	switch (current_limit_ua) {
 | 
						|
	case USB_INPUT_CURRENT_LIMIT_UA:
 | 
						|
		gpio_direction_output(chip->charging_m0_gpio, 0);
 | 
						|
		gpio_direction_output(chip->charging_m1_gpio, 0);
 | 
						|
		break;
 | 
						|
 | 
						|
	case CHARGER_INPUT_CURRENT_LIMIT_UA:
 | 
						|
		gpio_direction_output(chip->charging_m0_gpio, 1);
 | 
						|
		gpio_direction_output(chip->charging_m1_gpio, 0);
 | 
						|
		break;
 | 
						|
 | 
						|
	default:
 | 
						|
		dev_err(&chip->client->dev, "%s: Unsupported current_limit_ua=%d uA\n",
 | 
						|
			__func__, current_limit_ua);
 | 
						|
		rc = -EINVAL;
 | 
						|
		break;
 | 
						|
 | 
						|
	}
 | 
						|
 | 
						|
	if (!rc) {
 | 
						|
		chip->input_current_limit_ua = current_limit_ua;
 | 
						|
 | 
						|
		dev_dbg(&chip->client->dev, "%s: current_limit_ua=%d uA\n", __func__,
 | 
						|
			current_limit_ua);
 | 
						|
	}
 | 
						|
 | 
						|
	return rc;
 | 
						|
}
 | 
						|
 | 
						|
/*******************************************************************************
 | 
						|
  Function    : mp2617_set_property_battery_present
 | 
						|
  Description : Set the present state of battery
 | 
						|
  Input       : chip: chip data
 | 
						|
                batt_present_state: the present state of battery
 | 
						|
  Output      : None
 | 
						|
  Return      : 0: OK
 | 
						|
  Others      : None
 | 
						|
*******************************************************************************/
 | 
						|
static int mp2617_set_property_battery_present(struct mp2617_chip *chip,
 | 
						|
					bool batt_present_state)
 | 
						|
{
 | 
						|
	chip->battery_present = batt_present_state;
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
/*******************************************************************************
 | 
						|
  Function    : mp2617_get_property_battery_present
 | 
						|
  Description : Get the present state of battery
 | 
						|
  Input       : chip: chip data
 | 
						|
  Output      : None
 | 
						|
  Return      : The present state of battery
 | 
						|
  Others      : None
 | 
						|
*******************************************************************************/
 | 
						|
static int mp2617_get_property_battery_present(struct mp2617_chip *chip)
 | 
						|
{
 | 
						|
	return chip->battery_present;
 | 
						|
}
 | 
						|
 | 
						|
/*******************************************************************************
 | 
						|
  Function    : mp2617_set_property_battery_health
 | 
						|
  Description : Set the health state of battery
 | 
						|
  Input       : chip: chip data
 | 
						|
                health_state: the health state of battery
 | 
						|
  Output      : None
 | 
						|
  Return      : 0: OK
 | 
						|
  Others      : None
 | 
						|
*******************************************************************************/
 | 
						|
static int mp2617_set_property_battery_health(struct mp2617_chip *chip,
 | 
						|
					int health_state)
 | 
						|
{
 | 
						|
	if ((health_state > POWER_SUPPLY_HEALTH_UNKNOWN) &&
 | 
						|
		(health_state <= POWER_SUPPLY_HEALTH_DEAD_OVERCOLD))
 | 
						|
	{
 | 
						|
		chip->battery_health = health_state;
 | 
						|
 | 
						|
		if (POWER_SUPPLY_HEALTH_GOOD == health_state)
 | 
						|
		{
 | 
						|
			chip->charging_allowed = true;
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			chip->charging_allowed = false;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		chip->battery_health = POWER_SUPPLY_HEALTH_UNKNOWN;
 | 
						|
	}
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
/*******************************************************************************
 | 
						|
  Function    : mp2617_get_property_battery_health
 | 
						|
  Description : Get the health state of battery
 | 
						|
  Input       : chip: chip data
 | 
						|
  Output      : None
 | 
						|
  Return      : The health state of battery
 | 
						|
  Others      : None
 | 
						|
*******************************************************************************/
 | 
						|
static int mp2617_get_property_battery_health(struct mp2617_chip *chip)
 | 
						|
{
 | 
						|
	return chip->battery_health;
 | 
						|
}
 | 
						|
 | 
						|
/*******************************************************************************
 | 
						|
  Function    : mp2617_get_property_battery_voltage
 | 
						|
  Description : Get the voltage of battery
 | 
						|
  Input       : chip: chip data
 | 
						|
  Output      : None
 | 
						|
  Return      : The voltage of battery
 | 
						|
  Others      : None
 | 
						|
*******************************************************************************/
 | 
						|
static int mp2617_get_property_battery_voltage(struct mp2617_chip *chip)
 | 
						|
{
 | 
						|
	int rc = 0;
 | 
						|
	struct qpnp_vadc_result results;
 | 
						|
 | 
						|
	rc = qpnp_vadc_read(P_MUX2_1_1, &results);
 | 
						|
	if (rc) {
 | 
						|
		pr_err("Unable to read vbat rc=%d\n", rc);
 | 
						|
		return rc;
 | 
						|
	}
 | 
						|
 | 
						|
	return ((int)(results.physical * chip->charging_vbat_div)/1000);
 | 
						|
}
 | 
						|
 | 
						|
/*******************************************************************************
 | 
						|
  Function    : em_batt_map_linear
 | 
						|
  Description : Get the result form table by linear map
 | 
						|
  Input       : table: linear map table
 | 
						|
                table_size: table size
 | 
						|
                in_num: number input
 | 
						|
  Output      : out_num: result with linear map
 | 
						|
  Return      : 0: OK, Others: Error
 | 
						|
  Others      : None
 | 
						|
*******************************************************************************/
 | 
						|
static int em_batt_map_linear(const int (*table)[2], const u32 table_size,
 | 
						|
	int in_num, int *out_num)
 | 
						|
{
 | 
						|
	u32 i = 0;
 | 
						|
 | 
						|
	if ((NULL == table) || (NULL == out_num)) {
 | 
						|
		pr_err("Invalid input or output parameter\n");
 | 
						|
		return -EINVAL;
 | 
						|
	}
 | 
						|
 | 
						|
	while (i < table_size) {
 | 
						|
		if (table[i][0] < in_num) {
 | 
						|
			break;
 | 
						|
		} else {
 | 
						|
			i++;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (i == 0) {
 | 
						|
		*out_num = table[0][1];
 | 
						|
	} else if (i == table_size) {
 | 
						|
		*out_num = table[table_size-1][1];
 | 
						|
	} else {
 | 
						|
		/* result is between search_index and search_index-1, interpolate linearly */
 | 
						|
		*out_num = (((table[i][1] - table[i-1][1]) * (in_num - table[i-1][0]))
 | 
						|
		/ (table[i][0] - table[i-1][0])) + table[i-1][1];
 | 
						|
	}
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
/*******************************************************************************
 | 
						|
  Function    : mp2617_get_property_battery_id_therm
 | 
						|
  Description : Get the temperature of battery
 | 
						|
  Input       : chip: chip data
 | 
						|
  Output      : None
 | 
						|
  Return      : The temperature of battery or error code
 | 
						|
  Others      : None
 | 
						|
*******************************************************************************/
 | 
						|
static int mp2617_get_property_battery_id_therm(struct mp2617_chip *chip)
 | 
						|
{
 | 
						|
	int rc = 0;
 | 
						|
	int temp_value = 0;
 | 
						|
	struct qpnp_vadc_result results;
 | 
						|
 | 
						|
	rc = qpnp_vadc_read(LR_MUX2_BAT_ID, &results);
 | 
						|
	if (rc) {
 | 
						|
		pr_err("Unable to read battery temperature, rc=%d\n", rc);
 | 
						|
		return rc;
 | 
						|
	}
 | 
						|
 | 
						|
	temp_value = ((int)results.physical) / 1000; /* convert to mV */
 | 
						|
 | 
						|
	rc = em_batt_map_linear(adc_map_temp,
 | 
						|
		sizeof(adc_map_temp)/sizeof(adc_map_temp[0]),
 | 
						|
		temp_value, &temp_value);
 | 
						|
	if(rc) {
 | 
						|
		pr_err("Unable to get battery temperature, rc=%d\n", rc);
 | 
						|
		return rc;
 | 
						|
	}
 | 
						|
 | 
						|
	return temp_value;
 | 
						|
}
 | 
						|
 | 
						|
static int mp2617_property_is_writeable(struct power_supply *psy,
 | 
						|
						enum power_supply_property psp)
 | 
						|
{
 | 
						|
	switch (psp) {
 | 
						|
	case POWER_SUPPLY_PROP_CHARGING_ENABLED:
 | 
						|
	case POWER_SUPPLY_PROP_CURRENT_MAX:
 | 
						|
	case POWER_SUPPLY_PROP_HEALTH:
 | 
						|
	case POWER_SUPPLY_PROP_PRESENT:
 | 
						|
		return 1;
 | 
						|
	default:
 | 
						|
		break;
 | 
						|
	}
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int mp2617_power_set_property(struct power_supply *psy,
 | 
						|
				  enum power_supply_property psp,
 | 
						|
				  const union power_supply_propval *val)
 | 
						|
{
 | 
						|
	struct mp2617_chip *chip = container_of(psy, struct mp2617_chip, psy);
 | 
						|
 | 
						|
	mutex_lock(&chip->lock);
 | 
						|
 | 
						|
	switch (psp) {
 | 
						|
	case POWER_SUPPLY_PROP_CHARGING_ENABLED:
 | 
						|
		if (val->intval) {
 | 
						|
			mp2617_enable_charging(chip);
 | 
						|
		} else {
 | 
						|
			mp2617_disable_charging(chip);
 | 
						|
		}
 | 
						|
		break;
 | 
						|
	case POWER_SUPPLY_PROP_CURRENT_MAX:
 | 
						|
		mp2617_set_input_current_limit(chip, val->intval);
 | 
						|
		break;
 | 
						|
	case POWER_SUPPLY_PROP_HEALTH:
 | 
						|
		mp2617_set_property_battery_health(chip, val->intval);
 | 
						|
		break;
 | 
						|
	case POWER_SUPPLY_PROP_PRESENT:
 | 
						|
		mp2617_set_property_battery_present(chip, (bool)val->intval);
 | 
						|
		break;
 | 
						|
	default:
 | 
						|
		mutex_unlock(&chip->lock);
 | 
						|
		return -EINVAL;
 | 
						|
	}
 | 
						|
 | 
						|
	mutex_unlock(&chip->lock);
 | 
						|
 | 
						|
	power_supply_changed(&chip->psy);
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int mp2617_power_get_property(struct power_supply *psy,
 | 
						|
				       enum power_supply_property psp,
 | 
						|
				       union power_supply_propval *val)
 | 
						|
{
 | 
						|
	struct mp2617_chip *chip = container_of(psy, struct mp2617_chip, psy);
 | 
						|
 | 
						|
	mutex_lock(&chip->lock);
 | 
						|
 | 
						|
	switch (psp) {
 | 
						|
	case POWER_SUPPLY_PROP_HEALTH:
 | 
						|
		val->intval = mp2617_get_property_battery_health(chip);
 | 
						|
		break;
 | 
						|
	case POWER_SUPPLY_PROP_PRESENT:
 | 
						|
		val->intval = mp2617_get_property_battery_present(chip);
 | 
						|
		break;
 | 
						|
	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
 | 
						|
		val->intval = mp2617_get_property_battery_voltage(chip);
 | 
						|
		break;
 | 
						|
	case POWER_SUPPLY_PROP_TEMP:
 | 
						|
		val->intval = mp2617_get_property_battery_id_therm(chip);
 | 
						|
		break;
 | 
						|
	case POWER_SUPPLY_PROP_CHG_OK:
 | 
						|
		val->intval = mp2617_get_property_chg_ok_level(chip);
 | 
						|
		break;
 | 
						|
	case POWER_SUPPLY_PROP_CHARGING_ENABLED:
 | 
						|
		val->intval = chip->charging_enabled;
 | 
						|
		break;
 | 
						|
	case POWER_SUPPLY_PROP_CURRENT_MAX:
 | 
						|
		val->intval = chip->input_current_limit_ua;
 | 
						|
		break;
 | 
						|
	case POWER_SUPPLY_PROP_TECHNOLOGY:
 | 
						|
		val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
 | 
						|
		break;
 | 
						|
	case POWER_SUPPLY_PROP_MODEL_NAME:
 | 
						|
		val->strval = "MP2617";
 | 
						|
		break;
 | 
						|
	case POWER_SUPPLY_PROP_MANUFACTURER:
 | 
						|
		val->strval = "MPS";
 | 
						|
		break;
 | 
						|
#ifdef CONFIG_POWER_BANK_DETECT_SUPPORT
 | 
						|
	case POWER_SUPPLY_PROP_VOLTAGE_DROP:
 | 
						|
		val->intval = mp2617_get_property_voltage_drop(chip);
 | 
						|
		break;
 | 
						|
#endif
 | 
						|
	default:
 | 
						|
		mutex_unlock(&chip->lock);
 | 
						|
		return -EINVAL;
 | 
						|
	}
 | 
						|
 | 
						|
	mutex_unlock(&chip->lock);
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
/*******************************************************************************
 | 
						|
  Function    : mp2617_external_power_changed
 | 
						|
  Description : Set charging parameters because power supply device changes
 | 
						|
  Input       : psy: power supply psy
 | 
						|
  Output      : None
 | 
						|
  Return      : None
 | 
						|
  Others      : None
 | 
						|
*******************************************************************************/
 | 
						|
static void mp2617_external_power_changed(struct power_supply *psy)
 | 
						|
{
 | 
						|
	struct mp2617_chip *chip = container_of(psy, struct mp2617_chip, psy);
 | 
						|
	union power_supply_propval prop = {0,};
 | 
						|
	int scope = POWER_SUPPLY_SCOPE_DEVICE;
 | 
						|
	int current_limit = 0;
 | 
						|
	int online = 0;
 | 
						|
	int rc;
 | 
						|
 | 
						|
	mutex_lock(&chip->lock);
 | 
						|
	dev_dbg(&chip->client->dev, "%s: start\n", __func__);
 | 
						|
 | 
						|
	rc = chip->usb_psy->get_property(chip->usb_psy,
 | 
						|
					POWER_SUPPLY_PROP_ONLINE, &prop);
 | 
						|
	if (rc) {
 | 
						|
		dev_err(&chip->client->dev,
 | 
						|
			"%s: could not read USB online property, rc=%d\n", __func__, rc);
 | 
						|
	} else {
 | 
						|
		online = prop.intval;
 | 
						|
	}
 | 
						|
 | 
						|
	rc = chip->usb_psy->get_property(chip->usb_psy, POWER_SUPPLY_PROP_SCOPE,
 | 
						|
					&prop);
 | 
						|
	if (rc) {
 | 
						|
		dev_err(&chip->client->dev,
 | 
						|
			"%s: could not read USB scope property, rc=%d\n", __func__, rc);
 | 
						|
	} else {
 | 
						|
		scope = prop.intval;
 | 
						|
	}
 | 
						|
 | 
						|
	rc = chip->usb_psy->get_property(chip->usb_psy,
 | 
						|
					POWER_SUPPLY_PROP_CURRENT_MAX, &prop);
 | 
						|
	if (rc) {
 | 
						|
		dev_err(&chip->client->dev,
 | 
						|
			"%s: could not read USB current max property, rc=%d\n", __func__, rc);
 | 
						|
	} else {
 | 
						|
		current_limit = prop.intval;
 | 
						|
	}
 | 
						|
 | 
						|
	dev_dbg(&chip->client->dev,
 | 
						|
		"%s: online=%d, scope=%d, current_limit=%d, present=%d\n",
 | 
						|
		__func__, online, scope, current_limit, chip->battery_present);
 | 
						|
 | 
						|
	if (scope == POWER_SUPPLY_SCOPE_DEVICE) {
 | 
						|
		if (online && chip->battery_present) {
 | 
						|
			mp2617_set_input_current_limit(chip, current_limit);
 | 
						|
 | 
						|
			if (current_limit != 0 &&
 | 
						|
				POWER_SUPPLY_HEALTH_GOOD == chip->battery_health) {
 | 
						|
				mp2617_enable_charging(chip);
 | 
						|
			}
 | 
						|
		} else {
 | 
						|
			mp2617_disable_charging(chip);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	dev_dbg(&chip->client->dev, "%s: end\n", __func__);
 | 
						|
	mutex_unlock(&chip->lock);
 | 
						|
 | 
						|
	power_supply_changed(&chip->psy);
 | 
						|
}
 | 
						|
 | 
						|
/*******************************************************************************
 | 
						|
  Function    : mp2617_apply_dt_configs
 | 
						|
  Description : Set default config
 | 
						|
  Input       : chip: chip data
 | 
						|
  Output      : None
 | 
						|
  Return      : 0: OK, Others: Error
 | 
						|
  Others      : None
 | 
						|
*******************************************************************************/
 | 
						|
static int __devinit mp2617_apply_dt_configs(struct mp2617_chip *chip)
 | 
						|
{
 | 
						|
	struct device *dev = &chip->client->dev;
 | 
						|
	struct device_node *node = chip->client->dev.of_node;
 | 
						|
	int current_ma = 0;
 | 
						|
	int value = 0;
 | 
						|
	int rc = 0;
 | 
						|
 | 
						|
	chip->input_current_limit_ua = DEFAULT_INPUT_CURRENT_LIMIT_UA;
 | 
						|
#ifdef CONFIG_POWER_BANK_DETECT_SUPPORT
 | 
						|
	chip->charging_det_resistor = DEFAULT_CHARGE_DET_RESISTOR;
 | 
						|
	chip->battery_resistor = DEFAULT_BATTERY_RESISTOR;
 | 
						|
	mp2617_enable_boost(chip, true);
 | 
						|
#endif
 | 
						|
	chip->battery_health = POWER_SUPPLY_HEALTH_GOOD;
 | 
						|
	chip->battery_present = true;
 | 
						|
	chip->charging_allowed = true;
 | 
						|
 | 
						|
	mp2617_disable_charging(chip);
 | 
						|
 | 
						|
	/*
 | 
						|
	 * All device tree parameters are optional so it is ok if read calls
 | 
						|
	 * fail.
 | 
						|
	 */
 | 
						|
	rc = of_property_read_u32(node, "mps,chg-current-ma", ¤t_ma);
 | 
						|
	if (rc == 0) {
 | 
						|
		chip->input_current_limit_ua = current_ma * 1000;
 | 
						|
	} else {
 | 
						|
		dev_err(dev, "%s: Failed to get charge current node, rc=%d\n",
 | 
						|
			__func__, rc);
 | 
						|
	}
 | 
						|
 | 
						|
	rc = of_property_read_u32(node, "mps,chg-vbat-div", &value);
 | 
						|
	if (rc == 0) {
 | 
						|
		chip->charging_vbat_div = value;
 | 
						|
	} else {
 | 
						|
		chip->charging_vbat_div = 1;
 | 
						|
 | 
						|
		dev_err(dev, "%s: Failed to get battery voltage division, rc=%d\n",
 | 
						|
			__func__, rc);
 | 
						|
	}
 | 
						|
 | 
						|
	rc = mp2617_set_input_current_limit(chip, chip->input_current_limit_ua);
 | 
						|
	if (rc) {
 | 
						|
		dev_err(dev, "%s: Failed to set charge current, rc=%d\n",
 | 
						|
			__func__, rc);
 | 
						|
		return rc;
 | 
						|
	}
 | 
						|
 | 
						|
#ifdef CONFIG_POWER_BANK_DETECT_SUPPORT
 | 
						|
	rc = of_property_read_u32(node, "mps,chg-det-resistor", &value);
 | 
						|
	if (rc == 0) {
 | 
						|
		chip->charging_det_resistor = value;
 | 
						|
	} else {
 | 
						|
		dev_err(dev, "%s: Failed to get detection resistor, rc=%d\n",
 | 
						|
			__func__, rc);
 | 
						|
	}
 | 
						|
 | 
						|
	rc = of_property_read_u32(node, "mps,chg-batt-resistor", &value);
 | 
						|
	if (rc == 0) {
 | 
						|
		chip->battery_resistor = value;
 | 
						|
	} else {
 | 
						|
		dev_err(dev, "%s: Failed to get battery resistor, rc=%d\n",
 | 
						|
			__func__, rc);
 | 
						|
	}
 | 
						|
 | 
						|
#endif
 | 
						|
	return rc;
 | 
						|
}
 | 
						|
 | 
						|
/*******************************************************************************
 | 
						|
  Function    : mp2617_gpio_configs
 | 
						|
  Description : Set gpio default config
 | 
						|
  Input       : chip: chip data
 | 
						|
  Output      : None
 | 
						|
  Return      : 0: OK, Others: Error
 | 
						|
  Others      : None
 | 
						|
*******************************************************************************/
 | 
						|
static int __devinit mp2617_gpio_configs(struct mp2617_chip *chip)
 | 
						|
{
 | 
						|
	struct device_node *node = chip->client->dev.of_node;
 | 
						|
	int rc = 0;
 | 
						|
 | 
						|
	chip->charging_en_gpio = of_get_named_gpio(node, "mps,chg-en-gpio", 0);
 | 
						|
	rc = gpio_request(chip->charging_en_gpio, "mps,chg-en-gpio");
 | 
						|
	if (rc) {
 | 
						|
		pr_err("request charge en gpio failed, rc=%d\n", rc);
 | 
						|
		gpio_free(chip->charging_en_gpio);
 | 
						|
		return rc;
 | 
						|
	}
 | 
						|
 | 
						|
	chip->charging_ok_gpio = of_get_named_gpio(node, "mps,chg-ok-gpio", 0);
 | 
						|
	rc = gpio_request(chip->charging_ok_gpio, "mps,chg-ok-gpio");
 | 
						|
	if (rc) {
 | 
						|
		pr_err("request charge ok gpio failed, rc=%d\n",rc);
 | 
						|
		gpio_free(chip->charging_ok_gpio);
 | 
						|
		return rc;
 | 
						|
	}
 | 
						|
 | 
						|
	chip->charging_m0_gpio = of_get_named_gpio(node, "mps,chg-m0-gpio", 0);
 | 
						|
	rc = gpio_request(chip->charging_m0_gpio, "mps,chg-m0-gpio");
 | 
						|
	if (rc) {
 | 
						|
		pr_err("request charge m0 gpio failed, rc=%d\n",
 | 
						|
			rc);
 | 
						|
		gpio_free(chip->charging_m0_gpio);
 | 
						|
		return rc;
 | 
						|
	}
 | 
						|
 | 
						|
	chip->charging_m1_gpio = of_get_named_gpio(node, "mps,chg-m1-gpio", 0);
 | 
						|
	rc = gpio_request(chip->charging_m1_gpio, "mps,chg-m1-gpio");
 | 
						|
	if (rc) {
 | 
						|
		pr_err("request charge m1 gpio failed, rc=%d\n",
 | 
						|
			rc);
 | 
						|
		gpio_free(chip->charging_m1_gpio);
 | 
						|
		return rc;
 | 
						|
	}
 | 
						|
 | 
						|
#ifdef CONFIG_POWER_BANK_DETECT_SUPPORT
 | 
						|
	chip->boost_en_gpio = of_get_named_gpio(node, "mps,chg-boost-en-gpio", 0);
 | 
						|
	rc = gpio_request(chip->boost_en_gpio, "mps,chg-boost-en-gpio");
 | 
						|
	if (rc) {
 | 
						|
		pr_err("request charge m1 gpio failed, rc=%d\n",
 | 
						|
			rc);
 | 
						|
		gpio_free(chip->boost_en_gpio);
 | 
						|
		return rc;
 | 
						|
	}
 | 
						|
#endif
 | 
						|
 | 
						|
	return rc;
 | 
						|
}
 | 
						|
 | 
						|
static int __devinit mp2617_probe(struct platform_device *pdev)
 | 
						|
{
 | 
						|
	struct mp2617_chip *chip;
 | 
						|
	struct device *dev = &pdev->dev;
 | 
						|
	struct device_node *node = pdev->dev.of_node;
 | 
						|
	int rc = 0;
 | 
						|
 | 
						|
	if (!node) {
 | 
						|
		dev_err(dev, "%s: device tree information missing\n", __func__);
 | 
						|
		return -ENODEV;
 | 
						|
	}
 | 
						|
 | 
						|
	chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
 | 
						|
	if (!chip) {
 | 
						|
		dev_err(dev, "%s: devm_kzalloc failed\n", __func__);
 | 
						|
		return -ENOMEM;
 | 
						|
	}
 | 
						|
 | 
						|
	mutex_init(&chip->lock);
 | 
						|
	chip->client = pdev;
 | 
						|
 | 
						|
	chip->usb_psy = power_supply_get_by_name("usb");
 | 
						|
	if (!chip->usb_psy) {
 | 
						|
		dev_dbg(dev, "%s: USB supply not found; deferring charger probe\n",
 | 
						|
			__func__);
 | 
						|
		return -EPROBE_DEFER;
 | 
						|
	}
 | 
						|
 | 
						|
	rc = mp2617_gpio_configs(chip);
 | 
						|
	if (rc) {
 | 
						|
		return rc;
 | 
						|
	}
 | 
						|
 | 
						|
	rc = mp2617_apply_dt_configs(chip);
 | 
						|
	if (rc) {
 | 
						|
		return rc;
 | 
						|
	}
 | 
						|
 | 
						|
	chip->psy.name			 = "battery";
 | 
						|
	chip->psy.type			 = POWER_SUPPLY_TYPE_BATTERY;
 | 
						|
	chip->psy.properties		 = mp2617_power_properties;
 | 
						|
	chip->psy.num_properties	 = ARRAY_SIZE(mp2617_power_properties);
 | 
						|
	chip->psy.get_property		 = mp2617_power_get_property;
 | 
						|
	chip->psy.set_property		 = mp2617_power_set_property;
 | 
						|
	chip->psy.property_is_writeable  = mp2617_property_is_writeable;
 | 
						|
	chip->psy.external_power_changed = mp2617_external_power_changed;
 | 
						|
 | 
						|
	rc = power_supply_register(dev, &chip->psy);
 | 
						|
	if (rc < 0) {
 | 
						|
		dev_err(dev, "%s: power_supply_register failed, rc=%d\n",
 | 
						|
						__func__, rc);
 | 
						|
		return rc;
 | 
						|
	}
 | 
						|
 | 
						|
	mp2617_external_power_changed(&chip->psy);
 | 
						|
 | 
						|
	dev_info(dev, "%s: MP2617 charger probed successfully\n", __func__);
 | 
						|
 | 
						|
	return rc;
 | 
						|
}
 | 
						|
 | 
						|
static int __devexit mp2617_remove(struct platform_device *pdev)
 | 
						|
{
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static const struct of_device_id mp2617_match[] = {
 | 
						|
	{ .compatible = "mps,mp2617", },
 | 
						|
	{ },
 | 
						|
};
 | 
						|
 | 
						|
static struct platform_driver mp2617_driver = {
 | 
						|
	.driver	= {
 | 
						|
		.name		= "mp2617",
 | 
						|
		.owner		= THIS_MODULE,
 | 
						|
		.of_match_table	= mp2617_match,
 | 
						|
	},
 | 
						|
	.probe		= mp2617_probe,
 | 
						|
	.remove		= __devexit_p(mp2617_remove),
 | 
						|
};
 | 
						|
 | 
						|
static int __init mp2617_init(void)
 | 
						|
{
 | 
						|
	return platform_driver_register(&mp2617_driver);
 | 
						|
}
 | 
						|
module_init(mp2617_init);
 | 
						|
 | 
						|
static void __exit mp2617_exit(void)
 | 
						|
{
 | 
						|
	return platform_driver_unregister(&mp2617_driver);
 | 
						|
}
 | 
						|
module_exit(mp2617_exit);
 | 
						|
 | 
						|
MODULE_DESCRIPTION("MP2617 Charger");
 | 
						|
MODULE_LICENSE("GPL v2");
 | 
						|
MODULE_ALIAS("mp2617");
 |