Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fd642bb9 authored by Sebastian Reichel's avatar Sebastian Reichel
Browse files

Merge tag 'tags/mfd-power-charger-regulator-v3.18' into next

Immutable branch between MFD, Power, Charger and Regulator for v3.18
parents 4d96fb1e d6cc1f58
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -18,3 +18,17 @@ Description:
		This file is writeable and can be used to set the assumed
		battery 'full level'. As batteries age, this value has to be
		amended over time.

What:		/sys/class/power_supply/max14577-charger/device/fast_charge_timer
Date:		July 2014
KernelVersion:	3.18.0
Contact:	Krzysztof Kozlowski <k.kozlowski@samsung.com>
Description:
		This entry shows and sets the maximum time the max14577
		charger operates in fast-charge mode. When the timer expires
		the device will terminate fast-charge mode (charging current
		will drop to 0 A) and will trigger interrupt.

		Valid values:
		- 5, 6 or 7 (hours),
		- 0: disabled.
+146 −0
Original line number Diff line number Diff line
Maxim MAX14577/77836 Multi-Function Device

MAX14577 is a Multi-Function Device with Micro-USB Interface Circuit, Li+
Battery Charger and SFOUT LDO output for powering USB devices. It is
interfaced to host controller using I2C.

MAX77836 additionally contains PMIC (with two LDO regulators) and Fuel Gauge.


Required properties:
- compatible : Must be "maxim,max14577" or "maxim,max77836".
- reg : I2C slave address for the max14577 chip (0x25 for max14577/max77836)
- interrupts : IRQ line for the chip.
- interrupt-parent :  The parent interrupt controller.


Required nodes:
 - charger :
	Node for configuring the charger driver.
	Required properties:
		- compatible : "maxim,max14577-charger"
			or "maxim,max77836-charger"
		- maxim,fast-charge-uamp : Current in uA for Fast Charge;
			Valid values:
			- for max14577: 90000 - 950000;
			- for max77836: 45000 - 475000;
		- maxim,eoc-uamp : Current in uA for End-Of-Charge mode;
			Valid values:
			- for max14577: 50000 - 200000;
			- for max77836: 5000 - 100000;
		- maxim,ovp-uvolt : OverVoltage Protection Threshold in uV;
			In an overvoltage condition, INT asserts and charging
			stops. Valid values:
			- 6000000, 6500000, 7000000, 7500000;
		- maxim,constant-uvolt : Battery Constant Voltage in uV;
			Valid values:
			- 4000000 - 4280000 (step by 20000);
			- 4350000;


Optional nodes:
- max14577-muic/max77836-muic :
	Node used only by extcon consumers.
	Required properties:
		- compatible : "maxim,max14577-muic" or "maxim,max77836-muic"

- regulators :
	Required properties:
		- compatible : "maxim,max14577-regulator"
			or "maxim,max77836-regulator"

	May contain a sub-node per regulator from the list below. Each
	sub-node should contain the constraints and initialization information
	for that regulator. See regulator.txt for a description of standard
	properties for these sub-nodes.

	List of valid regulator names:
	- for max14577: CHARGER, SAFEOUT.
	- for max77836: CHARGER, SAFEOUT, LDO1, LDO2.

	The SAFEOUT is a fixed voltage regulator so there is no need to specify
	voltages for it.


Example:

#include <dt-bindings/interrupt-controller/irq.h>

max14577@25 {
	compatible = "maxim,max14577";
	reg = <0x25>;
	interrupt-parent = <&gpx1>;
	interrupts = <5 IRQ_TYPE_NONE>;

	muic: max14577-muic {
		compatible = "maxim,max14577-muic";
	};

	regulators {
		compatible = "maxim,max14577-regulator";

		SAFEOUT {
			regulator-name = "SAFEOUT";
		};
		CHARGER {
			regulator-name = "CHARGER";
			regulator-min-microamp = <90000>;
			regulator-max-microamp = <950000>;
			regulator-boot-on;
		};
	};

	charger {
		compatible = "maxim,max14577-charger";

		maxim,constant-uvolt = <4350000>;
		maxim,fast-charge-uamp = <450000>;
		maxim,eoc-uamp = <50000>;
		maxim,ovp-uvolt = <6500000>;
	};
};


max77836@25 {
	compatible = "maxim,max77836";
	reg = <0x25>;
	interrupt-parent = <&gpx1>;
	interrupts = <5 IRQ_TYPE_NONE>;

	muic: max77836-muic {
		compatible = "maxim,max77836-muic";
	};

	regulators {
		compatible = "maxim,max77836-regulator";

		SAFEOUT {
			regulator-name = "SAFEOUT";
		};
		CHARGER {
			regulator-name = "CHARGER";
			regulator-min-microamp = <90000>;
			regulator-max-microamp = <950000>;
			regulator-boot-on;
		};
		LDO1 {
			regulator-name = "LDO1";
			regulator-min-microvolt = <2700000>;
			regulator-max-microvolt = <2700000>;
		};
		LDO2 {
			regulator-name = "LDO2";
			regulator-min-microvolt = <800000>;
			regulator-max-microvolt = <3950000>;
		};
	};

	charger {
		compatible = "maxim,max77836-charger";

		maxim,constant-uvolt = <4350000>;
		maxim,fast-charge-uamp = <225000>;
		maxim,eoc-uamp = <7500>;
		maxim,ovp-uvolt = <6500000>;
	};
};
+99 −1
Original line number Diff line number Diff line
@@ -26,6 +26,87 @@
#include <linux/mfd/max14577.h>
#include <linux/mfd/max14577-private.h>

/*
 * Table of valid charger currents for different Maxim chipsets.
 * It is placed here because it is used by both charger and regulator driver.
 */
const struct maxim_charger_current maxim_charger_currents[] = {
	[MAXIM_DEVICE_TYPE_UNKNOWN] = { 0, 0, 0, 0 },
	[MAXIM_DEVICE_TYPE_MAX14577] = {
		.min		= MAX14577_CHARGER_CURRENT_LIMIT_MIN,
		.high_start	= MAX14577_CHARGER_CURRENT_LIMIT_HIGH_START,
		.high_step	= MAX14577_CHARGER_CURRENT_LIMIT_HIGH_STEP,
		.max		= MAX14577_CHARGER_CURRENT_LIMIT_MAX,
	},
	[MAXIM_DEVICE_TYPE_MAX77836] = {
		.min		= MAX77836_CHARGER_CURRENT_LIMIT_MIN,
		.high_start	= MAX77836_CHARGER_CURRENT_LIMIT_HIGH_START,
		.high_step	= MAX77836_CHARGER_CURRENT_LIMIT_HIGH_STEP,
		.max		= MAX77836_CHARGER_CURRENT_LIMIT_MAX,
	},
};
EXPORT_SYMBOL_GPL(maxim_charger_currents);

/*
 * maxim_charger_calc_reg_current - Calculate register value for current
 * @limits:	constraints for charger, matching the MBCICHWRC register
 * @min_ua:	minimal requested current, micro Amps
 * @max_ua:	maximum requested current, micro Amps
 * @dst:	destination to store calculated register value
 *
 * Calculates the value of MBCICHWRC (Fast Battery Charge Current) register
 * for given current and stores it under pointed 'dst'. The stored value
 * combines low bit (MBCICHWRCL) and high bits (MBCICHWRCH). It is also
 * properly shifted.
 *
 * The calculated register value matches the current which:
 *  - is always between <limits.min, limits.max>;
 *  - is always less or equal to max_ua;
 *  - is the highest possible value;
 *  - may be lower than min_ua.
 *
 * On success returns 0. On error returns -EINVAL (requested min/max current
 * is outside of given charger limits) and 'dst' is not set.
 */
int maxim_charger_calc_reg_current(const struct maxim_charger_current *limits,
		unsigned int min_ua, unsigned int max_ua, u8 *dst)
{
	unsigned int current_bits = 0xf;

	if (min_ua > max_ua)
		return -EINVAL;

	if (min_ua > limits->max || max_ua < limits->min)
		return -EINVAL;

	if (max_ua < limits->high_start) {
		/*
		 * Less than high_start, so set the minimal current
		 * (turn Low Bit off, 0 as high bits).
		 */
		*dst = 0x0;
		return 0;
	}

	/* max_ua is in range: <high_start, infinite>, cut it to limits.max */
	max_ua = min(limits->max, max_ua);
	max_ua -= limits->high_start;
	/*
	 * There is no risk of overflow 'max_ua' here because:
	 *  - max_ua >= limits.high_start
	 *  - BUILD_BUG checks that 'limits' are: max >= high_start + high_step
	 */
	current_bits = max_ua / limits->high_step;

	/* Turn Low Bit on (use range <limits.high_start, limits.max>) ... */
	*dst = 0x1 << CHGCTRL4_MBCICHWRCL_SHIFT;
	/* and set proper High Bits */
	*dst |= current_bits << CHGCTRL4_MBCICHWRCH_SHIFT;

	return 0;
}
EXPORT_SYMBOL_GPL(maxim_charger_calc_reg_current);

static const struct mfd_cell max14577_devs[] = {
	{
		.name = "max14577-muic",
@@ -35,7 +116,10 @@ static const struct mfd_cell max14577_devs[] = {
		.name = "max14577-regulator",
		.of_compatible = "maxim,max14577-regulator",
	},
	{ .name = "max14577-charger", },
	{
		.name = "max14577-charger",
		.of_compatible = "maxim,max14577-charger",
	},
};

static const struct mfd_cell max77836_devs[] = {
@@ -463,6 +547,20 @@ static int __init max14577_i2c_init(void)
	BUILD_BUG_ON(ARRAY_SIZE(max14577_i2c_id) != MAXIM_DEVICE_TYPE_NUM);
	BUILD_BUG_ON(ARRAY_SIZE(max14577_dt_match) != MAXIM_DEVICE_TYPE_NUM);

	/* Valid charger current values must be provided for each chipset */
	BUILD_BUG_ON(ARRAY_SIZE(maxim_charger_currents) != MAXIM_DEVICE_TYPE_NUM);

	/* Check for valid values for charger */
	BUILD_BUG_ON(MAX14577_CHARGER_CURRENT_LIMIT_HIGH_START +
			MAX14577_CHARGER_CURRENT_LIMIT_HIGH_STEP * 0xf !=
			MAX14577_CHARGER_CURRENT_LIMIT_MAX);
	BUILD_BUG_ON(MAX14577_CHARGER_CURRENT_LIMIT_HIGH_STEP == 0);

	BUILD_BUG_ON(MAX77836_CHARGER_CURRENT_LIMIT_HIGH_START +
			MAX77836_CHARGER_CURRENT_LIMIT_HIGH_STEP * 0xf !=
			MAX77836_CHARGER_CURRENT_LIMIT_MAX);
	BUILD_BUG_ON(MAX77836_CHARGER_CURRENT_LIMIT_HIGH_STEP == 0);

	return i2c_add_driver(&max14577_i2c_driver);
}
subsys_initcall(max14577_i2c_init);
+3 −2
Original line number Diff line number Diff line
@@ -325,11 +325,12 @@ config CHARGER_MANAGER
          with help of suspend_again support.

config CHARGER_MAX14577
	tristate "Maxim MAX14577 MUIC battery charger driver"
	tristate "Maxim MAX14577/77836 battery charger driver"
	depends on MFD_MAX14577
	select SYSFS
	help
	  Say Y to enable support for the battery charger control sysfs and
	  platform data of MAX14577 MUICs.
	  platform data of MAX14577/77836 MUICs.

config CHARGER_MAX8997
	tristate "Maxim MAX8997/MAX8966 PMIC battery charger driver"
+336 −34
Original line number Diff line number Diff line
/*
 * Battery charger driver for the Maxim 14577
 * max14577_charger.c - Battery charger driver for the Maxim 14577/77836
 *
 * Copyright (C) 2013 Samsung Electronics
 * Copyright (C) 2013,2014 Samsung Electronics
 * Krzysztof Kozlowski <k.kozlowski@samsung.com>
 *
 * This program is free software; you can redistribute it and/or modify
@@ -19,6 +19,7 @@
#include <linux/platform_device.h>
#include <linux/power_supply.h>
#include <linux/mfd/max14577-private.h>
#include <linux/mfd/max14577.h>

struct max14577_charger {
	struct device *dev;
@@ -27,8 +28,35 @@ struct max14577_charger {

	unsigned int		charging_state;
	unsigned int		battery_state;

	struct max14577_charger_platform_data	*pdata;
};

/*
 * Helper function for mapping values of STATUS2/CHGTYP register on max14577
 * and max77836 chipsets to enum maxim_muic_charger_type.
 */
static enum max14577_muic_charger_type maxim_get_charger_type(
		enum maxim_device_type dev_type, u8 val) {
	switch (val) {
	case MAX14577_CHARGER_TYPE_NONE:
	case MAX14577_CHARGER_TYPE_USB:
	case MAX14577_CHARGER_TYPE_DOWNSTREAM_PORT:
	case MAX14577_CHARGER_TYPE_DEDICATED_CHG:
	case MAX14577_CHARGER_TYPE_SPECIAL_500MA:
	case MAX14577_CHARGER_TYPE_SPECIAL_1A:
		return val;
	case MAX14577_CHARGER_TYPE_DEAD_BATTERY:
	case MAX14577_CHARGER_TYPE_RESERVED:
		if (dev_type == MAXIM_DEVICE_TYPE_MAX77836)
			val |= 0x8;
		return val;
	default:
		WARN_ONCE(1, "max14577: Unsupported chgtyp register value 0x%02x", val);
		return val;
	}
}

static int max14577_get_charger_state(struct max14577_charger *chg)
{
	struct regmap *rmap = chg->max14577->regmap;
@@ -89,19 +117,23 @@ static int max14577_get_online(struct max14577_charger *chg)
{
	struct regmap *rmap = chg->max14577->regmap;
	u8 reg_data;
	enum max14577_muic_charger_type chg_type;

	max14577_read_reg(rmap, MAX14577_MUIC_REG_STATUS2, &reg_data);
	reg_data = ((reg_data & STATUS2_CHGTYP_MASK) >> STATUS2_CHGTYP_SHIFT);
	switch (reg_data) {
	chg_type = maxim_get_charger_type(chg->max14577->dev_type, reg_data);
	switch (chg_type) {
	case MAX14577_CHARGER_TYPE_USB:
	case MAX14577_CHARGER_TYPE_DEDICATED_CHG:
	case MAX14577_CHARGER_TYPE_SPECIAL_500MA:
	case MAX14577_CHARGER_TYPE_SPECIAL_1A:
	case MAX14577_CHARGER_TYPE_DEAD_BATTERY:
	case MAX77836_CHARGER_TYPE_SPECIAL_BIAS:
		return 1;
	case MAX14577_CHARGER_TYPE_NONE:
	case MAX14577_CHARGER_TYPE_DOWNSTREAM_PORT:
	case MAX14577_CHARGER_TYPE_RESERVED:
	case MAX77836_CHARGER_TYPE_RESERVED:
	default:
		return 0;
	}
@@ -118,10 +150,12 @@ static int max14577_get_battery_health(struct max14577_charger *chg)
	struct regmap *rmap = chg->max14577->regmap;
	int state = POWER_SUPPLY_HEALTH_GOOD;
	u8 reg_data;
	enum max14577_muic_charger_type chg_type;

	max14577_read_reg(rmap, MAX14577_MUIC_REG_STATUS2, &reg_data);
	reg_data = ((reg_data & STATUS2_CHGTYP_MASK) >> STATUS2_CHGTYP_SHIFT);
	if (reg_data == MAX14577_CHARGER_TYPE_DEAD_BATTERY) {
	chg_type = maxim_get_charger_type(chg->max14577->dev_type, reg_data);
	if (chg_type == MAX14577_CHARGER_TYPE_DEAD_BATTERY) {
		state = POWER_SUPPLY_HEALTH_DEAD;
		goto state_set;
	}
@@ -147,15 +181,131 @@ static int max14577_get_present(struct max14577_charger *chg)
	return 1;
}

static int max14577_set_fast_charge_timer(struct max14577_charger *chg,
		unsigned long hours)
{
	u8 reg_data;

	switch (hours) {
	case 5 ... 7:
		reg_data = hours - 3;
		break;
	case 0:
		/* Disable */
		reg_data = 0x7;
		break;
	default:
		dev_err(chg->dev, "Wrong value for Fast-Charge Timer: %lu\n",
				hours);
		return -EINVAL;
	}
	reg_data <<= CHGCTRL1_TCHW_SHIFT;

	return max14577_update_reg(chg->max14577->regmap,
			MAX14577_REG_CHGCTRL1, CHGCTRL1_TCHW_MASK, reg_data);
}

static int max14577_init_constant_voltage(struct max14577_charger *chg,
		unsigned int uvolt)
{
	u8 reg_data;

	if (uvolt < MAXIM_CHARGER_CONSTANT_VOLTAGE_MIN ||
			uvolt > MAXIM_CHARGER_CONSTANT_VOLTAGE_MAX)
		return -EINVAL;

	if (uvolt == 4200000)
		reg_data = 0x0;
	else if (uvolt == MAXIM_CHARGER_CONSTANT_VOLTAGE_MAX)
		reg_data = 0x1f;
	else if (uvolt <= 4280000) {
		unsigned int val = uvolt;

		val -= MAXIM_CHARGER_CONSTANT_VOLTAGE_MIN;
		val /= MAXIM_CHARGER_CONSTANT_VOLTAGE_STEP;
		if (uvolt <= 4180000)
			reg_data = 0x1 + val;
		else
			reg_data = val; /* Fix for gap between 4.18V and 4.22V */
	} else
		return -EINVAL;

	reg_data <<= CHGCTRL3_MBCCVWRC_SHIFT;

	return max14577_write_reg(chg->max14577->regmap,
			MAX14577_CHG_REG_CHG_CTRL3, reg_data);
}

static int max14577_init_eoc(struct max14577_charger *chg,
		unsigned int uamp)
{
	unsigned int current_bits = 0xf;
	u8 reg_data;

	switch (chg->max14577->dev_type) {
	case MAXIM_DEVICE_TYPE_MAX77836:
		if (uamp < 5000)
			return -EINVAL; /* Requested current is too low */

		if (uamp >= 7500 && uamp < 10000)
			current_bits = 0x0;
		else if (uamp <= 50000) {
			/* <5000, 7499> and <10000, 50000> */
			current_bits = uamp / 5000;
		} else {
			uamp = min(uamp, 100000U) - 50000U;
			current_bits = 0xa + uamp / 10000;
		}
		break;

	case MAXIM_DEVICE_TYPE_MAX14577:
	default:
		if (uamp < MAX14577_CHARGER_EOC_CURRENT_LIMIT_MIN)
			return -EINVAL; /* Requested current is too low */

		uamp = min(uamp, MAX14577_CHARGER_EOC_CURRENT_LIMIT_MAX);
		uamp -= MAX14577_CHARGER_EOC_CURRENT_LIMIT_MIN;
		current_bits = uamp / MAX14577_CHARGER_EOC_CURRENT_LIMIT_STEP;
		break;
	}

	reg_data = current_bits << CHGCTRL5_EOCS_SHIFT;

	return max14577_update_reg(chg->max14577->regmap,
			MAX14577_CHG_REG_CHG_CTRL5, CHGCTRL5_EOCS_MASK,
			reg_data);
}

static int max14577_init_fast_charge(struct max14577_charger *chg,
		unsigned int uamp)
{
	u8 reg_data;
	int ret;
	const struct maxim_charger_current *limits =
		&maxim_charger_currents[chg->max14577->dev_type];

	ret = maxim_charger_calc_reg_current(limits, uamp, uamp, &reg_data);
	if (ret) {
		dev_err(chg->dev, "Wrong value for fast charge: %u\n", uamp);
		return ret;
	}

	return max14577_update_reg(chg->max14577->regmap,
			MAX14577_CHG_REG_CHG_CTRL4,
			CHGCTRL4_MBCICHWRCL_MASK | CHGCTRL4_MBCICHWRCH_MASK,
			reg_data);
}

/*
 * Sets charger registers to proper and safe default values.
 * Some of these values are equal to defaults in MAX14577E
 * data sheet but there are minor differences.
 */
static void max14577_charger_reg_init(struct max14577_charger *chg)
static int max14577_charger_reg_init(struct max14577_charger *chg)
{
	struct regmap *rmap = chg->max14577->regmap;
	u8 reg_data;
	int ret;

	/*
	 * Charger-Type Manual Detection, default off (set CHGTYPMAN to 0)
@@ -167,10 +317,6 @@ static void max14577_charger_reg_init(struct max14577_charger *chg)
			CDETCTRL1_CHGDETEN_MASK | CDETCTRL1_CHGTYPMAN_MASK,
			reg_data);

	/* Battery Fast-Charge Timer, from SM-V700: 6hrs */
	reg_data = 0x3 << CHGCTRL1_TCHW_SHIFT;
	max14577_write_reg(rmap, MAX14577_REG_CHGCTRL1, reg_data);

	/*
	 * Wall-Adapter Rapid Charge, default on
	 * Battery-Charger, default on
@@ -179,29 +325,46 @@ static void max14577_charger_reg_init(struct max14577_charger *chg)
	reg_data |= 0x1 << CHGCTRL2_MBCHOSTEN_SHIFT;
	max14577_write_reg(rmap, MAX14577_REG_CHGCTRL2, reg_data);

	/* Battery-Charger Constant Voltage (CV) Mode, from SM-V700: 4.35V */
	reg_data = 0xf << CHGCTRL3_MBCCVWRC_SHIFT;
	max14577_write_reg(rmap, MAX14577_REG_CHGCTRL3, reg_data);

	/*
	 * Fast Battery-Charge Current Low, default 200-950mA
	 * Fast Battery-Charge Current High, from SM-V700: 450mA
	 */
	reg_data = 0x1 << CHGCTRL4_MBCICHWRCL_SHIFT;
	reg_data |= 0x5 << CHGCTRL4_MBCICHWRCH_SHIFT;
	max14577_write_reg(rmap, MAX14577_REG_CHGCTRL4, reg_data);

	/* End-of-Charge Current, from SM-V700: 50mA */
	reg_data = 0x0 << CHGCTRL5_EOCS_SHIFT;
	max14577_write_reg(rmap, MAX14577_REG_CHGCTRL5, reg_data);

	/* Auto Charging Stop, default off */
	reg_data = 0x0 << CHGCTRL6_AUTOSTOP_SHIFT;
	max14577_write_reg(rmap, MAX14577_REG_CHGCTRL6, reg_data);

	/* Overvoltage-Protection Threshold, from SM-V700: 6.5V */
	reg_data = 0x2 << CHGCTRL7_OTPCGHCVS_SHIFT;
	ret = max14577_init_constant_voltage(chg, chg->pdata->constant_uvolt);
	if (ret)
		return ret;

	ret = max14577_init_eoc(chg, chg->pdata->eoc_uamp);
	if (ret)
		return ret;

	ret = max14577_init_fast_charge(chg, chg->pdata->fast_charge_uamp);
	if (ret)
		return ret;

	ret = max14577_set_fast_charge_timer(chg,
			MAXIM_CHARGER_FAST_CHARGE_TIMER_DEFAULT);
	if (ret)
		return ret;

	/* Initialize Overvoltage-Protection Threshold */
	switch (chg->pdata->ovp_uvolt) {
	case 7500000:
		reg_data = 0x0;
		break;
	case 6000000:
	case 6500000:
	case 7000000:
		reg_data = 0x1 + (chg->pdata->ovp_uvolt - 6000000) / 500000;
		break;
	default:
		dev_err(chg->dev, "Wrong value for OVP: %u\n",
				chg->pdata->ovp_uvolt);
		return -EINVAL;
	}
	reg_data <<= CHGCTRL7_OTPCGHCVS_SHIFT;
	max14577_write_reg(rmap, MAX14577_REG_CHGCTRL7, reg_data);

	return 0;
}

/* Support property from charger */
@@ -215,7 +378,11 @@ static enum power_supply_property max14577_charger_props[] = {
	POWER_SUPPLY_PROP_MANUFACTURER,
};

static const char *model_name = "MAX14577";
static const char * const model_names[] = {
	[MAXIM_DEVICE_TYPE_UNKNOWN]	= "MAX14577-like",
	[MAXIM_DEVICE_TYPE_MAX14577]	= "MAX14577",
	[MAXIM_DEVICE_TYPE_MAX77836]	= "MAX77836",
};
static const char *manufacturer = "Maxim Integrated";

static int max14577_charger_get_property(struct power_supply *psy,
@@ -244,7 +411,8 @@ static int max14577_charger_get_property(struct power_supply *psy,
		val->intval = max14577_get_online(chg);
		break;
	case POWER_SUPPLY_PROP_MODEL_NAME:
		val->strval = model_name;
		BUILD_BUG_ON(ARRAY_SIZE(model_names) != MAXIM_DEVICE_TYPE_NUM);
		val->strval = model_names[chg->max14577->dev_type];
		break;
	case POWER_SUPPLY_PROP_MANUFACTURER:
		val->strval = manufacturer;
@@ -256,6 +424,110 @@ static int max14577_charger_get_property(struct power_supply *psy,
	return ret;
}

#ifdef CONFIG_OF
static struct max14577_charger_platform_data *max14577_charger_dt_init(
		struct platform_device *pdev)
{
	struct max14577_charger_platform_data *pdata;
	struct device_node *np = pdev->dev.of_node;
	int ret;

	if (!np) {
		dev_err(&pdev->dev, "No charger OF node\n");
		return ERR_PTR(-EINVAL);
	}

	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
	if (!pdata)
		return ERR_PTR(-ENOMEM);

	ret = of_property_read_u32(np, "maxim,constant-uvolt",
			&pdata->constant_uvolt);
	if (ret) {
		dev_err(&pdev->dev, "Cannot parse maxim,constant-uvolt field from DT\n");
		return ERR_PTR(ret);
	}

	ret = of_property_read_u32(np, "maxim,fast-charge-uamp",
			&pdata->fast_charge_uamp);
	if (ret) {
		dev_err(&pdev->dev, "Cannot parse maxim,fast-charge-uamp field from DT\n");
		return ERR_PTR(ret);
	}

	ret = of_property_read_u32(np, "maxim,eoc-uamp", &pdata->eoc_uamp);
	if (ret) {
		dev_err(&pdev->dev, "Cannot parse maxim,eoc-uamp field from DT\n");
		return ERR_PTR(ret);
	}

	ret = of_property_read_u32(np, "maxim,ovp-uvolt", &pdata->ovp_uvolt);
	if (ret) {
		dev_err(&pdev->dev, "Cannot parse maxim,ovp-uvolt field from DT\n");
		return ERR_PTR(ret);
	}

	return pdata;
}
#else /* CONFIG_OF */
static struct max14577_charger_platform_data *max14577_charger_dt_init(
		struct platform_device *pdev)
{
	return NULL;
}
#endif /* CONFIG_OF */

static ssize_t show_fast_charge_timer(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	struct max14577_charger *chg = dev_get_drvdata(dev);
	u8 reg_data;
	int ret;
	unsigned int val;

	ret = max14577_read_reg(chg->max14577->regmap, MAX14577_REG_CHGCTRL1,
			&reg_data);
	if (ret)
		return ret;

	reg_data &= CHGCTRL1_TCHW_MASK;
	reg_data >>= CHGCTRL1_TCHW_SHIFT;
	switch (reg_data) {
	case 0x2 ... 0x4:
		val = reg_data + 3;
		break;
	case 0x7:
		val = 0;
		break;
	default:
		val = 5;
		break;
	}

	return scnprintf(buf, PAGE_SIZE, "%u\n", val);
}

static ssize_t store_fast_charge_timer(struct device *dev,
		struct device_attribute *attr, const char *buf, size_t count)
{
	struct max14577_charger *chg = dev_get_drvdata(dev);
	unsigned long val;
	int ret;

	ret = kstrtoul(buf, 10, &val);
	if (ret)
		return ret;

	ret = max14577_set_fast_charge_timer(chg, val);
	if (ret)
		return ret;

	return count;
}

static DEVICE_ATTR(fast_charge_timer, S_IRUGO | S_IWUSR,
		show_fast_charge_timer, store_fast_charge_timer);

static int max14577_charger_probe(struct platform_device *pdev)
{
	struct max14577_charger *chg;
@@ -270,7 +542,13 @@ static int max14577_charger_probe(struct platform_device *pdev)
	chg->dev = &pdev->dev;
	chg->max14577 = max14577;

	max14577_charger_reg_init(chg);
	chg->pdata = max14577_charger_dt_init(pdev);
	if (IS_ERR_OR_NULL(chg->pdata))
		return PTR_ERR(chg->pdata);

	ret = max14577_charger_reg_init(chg);
	if (ret)
		return ret;

	chg->charger.name = "max14577-charger",
	chg->charger.type = POWER_SUPPLY_TYPE_BATTERY,
@@ -278,24 +556,47 @@ static int max14577_charger_probe(struct platform_device *pdev)
	chg->charger.num_properties = ARRAY_SIZE(max14577_charger_props),
	chg->charger.get_property = max14577_charger_get_property,

	ret = device_create_file(&pdev->dev, &dev_attr_fast_charge_timer);
	if (ret) {
		dev_err(&pdev->dev, "failed: create sysfs entry\n");
		return ret;
	}

	ret = power_supply_register(&pdev->dev, &chg->charger);
	if (ret) {
		dev_err(&pdev->dev, "failed: power supply register\n");
		return ret;
		goto err;
	}

	/* Check for valid values for charger */
	BUILD_BUG_ON(MAX14577_CHARGER_EOC_CURRENT_LIMIT_MIN +
			MAX14577_CHARGER_EOC_CURRENT_LIMIT_STEP * 0xf !=
			MAX14577_CHARGER_EOC_CURRENT_LIMIT_MAX);
	return 0;

err:
	device_remove_file(&pdev->dev, &dev_attr_fast_charge_timer);

	return ret;
}

static int max14577_charger_remove(struct platform_device *pdev)
{
	struct max14577_charger *chg = platform_get_drvdata(pdev);

	device_remove_file(&pdev->dev, &dev_attr_fast_charge_timer);
	power_supply_unregister(&chg->charger);

	return 0;
}

static const struct platform_device_id max14577_charger_id[] = {
	{ "max14577-charger", MAXIM_DEVICE_TYPE_MAX14577, },
	{ "max77836-charger", MAXIM_DEVICE_TYPE_MAX77836, },
	{ }
};
MODULE_DEVICE_TABLE(platform, max14577_charger_id);

static struct platform_driver max14577_charger_driver = {
	.driver = {
		.owner	= THIS_MODULE,
@@ -303,9 +604,10 @@ static struct platform_driver max14577_charger_driver = {
	},
	.probe		= max14577_charger_probe,
	.remove		= max14577_charger_remove,
	.id_table	= max14577_charger_id,
};
module_platform_driver(max14577_charger_driver);

MODULE_AUTHOR("Krzysztof Kozlowski <k.kozlowski@samsung.com>");
MODULE_DESCRIPTION("MAXIM 14577 charger driver");
MODULE_DESCRIPTION("Maxim 14577/77836 charger driver");
MODULE_LICENSE("GPL");
Loading