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

Unverified Commit 955741a5 authored by Raag Jadav's avatar Raag Jadav Committed by Mark Brown
Browse files

regulator: act8865: operating mode and suspend state support

Implement ->set_mode(), ->get_mode() and ->set_suspend_xx() hooks
for act8865 with unlocked expert registers.

Based on work done by Borris Brezillon on [1].
[1] https://www.spinics.net/lists/kernel/msg2942960.html



Signed-off-by: default avatarRaag Jadav <raagjadav@gmail.com>
Link: https://lore.kernel.org/r/1565721176-8955-2-git-send-email-raagjadav@gmail.com


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 81eeb0a3
Loading
Loading
Loading
Loading
+186 −1
Original line number Original line Diff line number Diff line
@@ -19,6 +19,7 @@
#include <linux/power_supply.h>
#include <linux/power_supply.h>
#include <linux/regulator/of_regulator.h>
#include <linux/regulator/of_regulator.h>
#include <linux/regmap.h>
#include <linux/regmap.h>
#include <dt-bindings/regulator/active-semi,8865-regulator.h>


/*
/*
 * ACT8600 Global Register Map.
 * ACT8600 Global Register Map.
@@ -90,23 +91,31 @@
 */
 */
#define	ACT8865_SYS_MODE	0x00
#define	ACT8865_SYS_MODE	0x00
#define	ACT8865_SYS_CTRL	0x01
#define	ACT8865_SYS_CTRL	0x01
#define	ACT8865_SYS_UNLK_REGS	0x0b
#define	ACT8865_DCDC1_VSET1	0x20
#define	ACT8865_DCDC1_VSET1	0x20
#define	ACT8865_DCDC1_VSET2	0x21
#define	ACT8865_DCDC1_VSET2	0x21
#define	ACT8865_DCDC1_CTRL	0x22
#define	ACT8865_DCDC1_CTRL	0x22
#define	ACT8865_DCDC1_SUS	0x24
#define	ACT8865_DCDC2_VSET1	0x30
#define	ACT8865_DCDC2_VSET1	0x30
#define	ACT8865_DCDC2_VSET2	0x31
#define	ACT8865_DCDC2_VSET2	0x31
#define	ACT8865_DCDC2_CTRL	0x32
#define	ACT8865_DCDC2_CTRL	0x32
#define	ACT8865_DCDC2_SUS	0x34
#define	ACT8865_DCDC3_VSET1	0x40
#define	ACT8865_DCDC3_VSET1	0x40
#define	ACT8865_DCDC3_VSET2	0x41
#define	ACT8865_DCDC3_VSET2	0x41
#define	ACT8865_DCDC3_CTRL	0x42
#define	ACT8865_DCDC3_CTRL	0x42
#define	ACT8865_DCDC3_SUS	0x44
#define	ACT8865_LDO1_VSET	0x50
#define	ACT8865_LDO1_VSET	0x50
#define	ACT8865_LDO1_CTRL	0x51
#define	ACT8865_LDO1_CTRL	0x51
#define	ACT8865_LDO1_SUS	0x52
#define	ACT8865_LDO2_VSET	0x54
#define	ACT8865_LDO2_VSET	0x54
#define	ACT8865_LDO2_CTRL	0x55
#define	ACT8865_LDO2_CTRL	0x55
#define	ACT8865_LDO2_SUS	0x56
#define	ACT8865_LDO3_VSET	0x60
#define	ACT8865_LDO3_VSET	0x60
#define	ACT8865_LDO3_CTRL	0x61
#define	ACT8865_LDO3_CTRL	0x61
#define	ACT8865_LDO3_SUS	0x62
#define	ACT8865_LDO4_VSET	0x64
#define	ACT8865_LDO4_VSET	0x64
#define	ACT8865_LDO4_CTRL	0x65
#define	ACT8865_LDO4_CTRL	0x65
#define	ACT8865_LDO4_SUS	0x66
#define	ACT8865_MSTROFF		0x20
#define	ACT8865_MSTROFF		0x20


/*
/*
@@ -225,6 +234,171 @@ static const struct regulator_linear_range act8600_sudcdc_voltage_ranges[] = {
	REGULATOR_LINEAR_RANGE(41400000, 248, 255, 0),
	REGULATOR_LINEAR_RANGE(41400000, 248, 255, 0),
};
};


static int act8865_set_suspend_state(struct regulator_dev *rdev, bool enable)
{
	struct regmap *regmap = rdev->regmap;
	int id = rdev->desc->id, reg, val;

	switch (id) {
	case ACT8865_ID_DCDC1:
		reg = ACT8865_DCDC1_SUS;
		val = 0xa8;
		break;
	case ACT8865_ID_DCDC2:
		reg = ACT8865_DCDC2_SUS;
		val = 0xa8;
		break;
	case ACT8865_ID_DCDC3:
		reg = ACT8865_DCDC3_SUS;
		val = 0xa8;
		break;
	case ACT8865_ID_LDO1:
		reg = ACT8865_LDO1_SUS;
		val = 0xe8;
		break;
	case ACT8865_ID_LDO2:
		reg = ACT8865_LDO2_SUS;
		val = 0xe8;
		break;
	case ACT8865_ID_LDO3:
		reg = ACT8865_LDO3_SUS;
		val = 0xe8;
		break;
	case ACT8865_ID_LDO4:
		reg = ACT8865_LDO4_SUS;
		val = 0xe8;
		break;
	default:
		return -EINVAL;
	}

	if (enable)
		val |= BIT(4);

	/*
	 * Ask the PMIC to enable/disable this output when entering hibernate
	 * mode.
	 */
	return regmap_write(regmap, reg, val);
}

static int act8865_set_suspend_enable(struct regulator_dev *rdev)
{
	return act8865_set_suspend_state(rdev, true);
}

static int act8865_set_suspend_disable(struct regulator_dev *rdev)
{
	return act8865_set_suspend_state(rdev, false);
}

static unsigned int act8865_of_map_mode(unsigned int mode)
{
	switch (mode) {
	case ACT8865_REGULATOR_MODE_FIXED:
		return REGULATOR_MODE_FAST;
	case ACT8865_REGULATOR_MODE_NORMAL:
		return REGULATOR_MODE_NORMAL;
	case ACT8865_REGULATOR_MODE_LOWPOWER:
		return REGULATOR_MODE_STANDBY;
	default:
		return REGULATOR_MODE_INVALID;
	}
}

static int act8865_set_mode(struct regulator_dev *rdev, unsigned int mode)
{
	struct regmap *regmap = rdev->regmap;
	int id = rdev_get_id(rdev);
	int reg, val = 0;

	switch (id) {
	case ACT8865_ID_DCDC1:
		reg = ACT8865_DCDC1_CTRL;
		break;
	case ACT8865_ID_DCDC2:
		reg = ACT8865_DCDC2_CTRL;
		break;
	case ACT8865_ID_DCDC3:
		reg = ACT8865_DCDC3_CTRL;
		break;
	case ACT8865_ID_LDO1:
		reg = ACT8865_LDO1_CTRL;
		break;
	case ACT8865_ID_LDO2:
		reg = ACT8865_LDO2_CTRL;
		break;
	case ACT8865_ID_LDO3:
		reg = ACT8865_LDO3_CTRL;
		break;
	case ACT8865_ID_LDO4:
		reg = ACT8865_LDO4_CTRL;
		break;
	default:
		return -EINVAL;
	}

	switch (mode) {
	case REGULATOR_MODE_FAST:
	case REGULATOR_MODE_NORMAL:
		if (id <= ACT8865_ID_DCDC3)
			val = BIT(5);
		break;
	case REGULATOR_MODE_STANDBY:
		if (id > ACT8865_ID_DCDC3)
			val = BIT(5);
		break;
	default:
		return -EINVAL;
	}

	return regmap_update_bits(regmap, reg, BIT(5), val);
}

static unsigned int act8865_get_mode(struct regulator_dev *rdev)
{
	struct regmap *regmap = rdev->regmap;
	int id = rdev_get_id(rdev);
	int reg, ret, val = 0;

	switch (id) {
	case ACT8865_ID_DCDC1:
		reg = ACT8865_DCDC1_CTRL;
		break;
	case ACT8865_ID_DCDC2:
		reg = ACT8865_DCDC2_CTRL;
		break;
	case ACT8865_ID_DCDC3:
		reg = ACT8865_DCDC3_CTRL;
		break;
	case ACT8865_ID_LDO1:
		reg = ACT8865_LDO1_CTRL;
		break;
	case ACT8865_ID_LDO2:
		reg = ACT8865_LDO2_CTRL;
		break;
	case ACT8865_ID_LDO3:
		reg = ACT8865_LDO3_CTRL;
		break;
	case ACT8865_ID_LDO4:
		reg = ACT8865_LDO4_CTRL;
		break;
	default:
		return -EINVAL;
	}

	ret = regmap_read(regmap, reg, &val);
	if (ret)
		return ret;

	if (id <= ACT8865_ID_DCDC3 && (val & BIT(5)))
		return REGULATOR_MODE_FAST;
	else if	(id > ACT8865_ID_DCDC3 && !(val & BIT(5)))
		return REGULATOR_MODE_NORMAL;
	else
		return REGULATOR_MODE_STANDBY;
}

static const struct regulator_ops act8865_ops = {
static const struct regulator_ops act8865_ops = {
	.list_voltage		= regulator_list_voltage_linear_range,
	.list_voltage		= regulator_list_voltage_linear_range,
	.map_voltage		= regulator_map_voltage_linear_range,
	.map_voltage		= regulator_map_voltage_linear_range,
@@ -232,7 +406,11 @@ static const struct regulator_ops act8865_ops = {
	.set_voltage_sel	= regulator_set_voltage_sel_regmap,
	.set_voltage_sel	= regulator_set_voltage_sel_regmap,
	.enable			= regulator_enable_regmap,
	.enable			= regulator_enable_regmap,
	.disable		= regulator_disable_regmap,
	.disable		= regulator_disable_regmap,
	.set_mode		= act8865_set_mode,
	.get_mode		= act8865_get_mode,
	.is_enabled		= regulator_is_enabled_regmap,
	.is_enabled		= regulator_is_enabled_regmap,
	.set_suspend_enable	= act8865_set_suspend_enable,
	.set_suspend_disable	= act8865_set_suspend_disable,
};
};


static const struct regulator_ops act8865_ldo_ops = {
static const struct regulator_ops act8865_ldo_ops = {
@@ -242,7 +420,11 @@ static const struct regulator_ops act8865_ldo_ops = {
	.set_voltage_sel	= regulator_set_voltage_sel_regmap,
	.set_voltage_sel	= regulator_set_voltage_sel_regmap,
	.enable			= regulator_enable_regmap,
	.enable			= regulator_enable_regmap,
	.disable		= regulator_disable_regmap,
	.disable		= regulator_disable_regmap,
	.set_mode		= act8865_set_mode,
	.get_mode		= act8865_get_mode,
	.is_enabled		= regulator_is_enabled_regmap,
	.is_enabled		= regulator_is_enabled_regmap,
	.set_suspend_enable	= act8865_set_suspend_enable,
	.set_suspend_disable	= act8865_set_suspend_disable,
	.set_pull_down		= regulator_set_pull_down_regmap,
	.set_pull_down		= regulator_set_pull_down_regmap,
};
};


@@ -256,6 +438,7 @@ static const struct regulator_ops act8865_fixed_ldo_ops = {
	[_family##_ID_##_id] = {					\
	[_family##_ID_##_id] = {					\
		.name			= _name,			\
		.name			= _name,			\
		.of_match		= of_match_ptr(_name),		\
		.of_match		= of_match_ptr(_name),		\
		.of_map_mode		= act8865_of_map_mode,		\
		.regulators_node	= of_match_ptr("regulators"),	\
		.regulators_node	= of_match_ptr("regulators"),	\
		.supply_name		= _supply,			\
		.supply_name		= _supply,			\
		.id			= _family##_ID_##_id,		\
		.id			= _family##_ID_##_id,		\
@@ -590,7 +773,9 @@ static int act8865_pmic_probe(struct i2c_client *client,


	i2c_set_clientdata(client, act8865);
	i2c_set_clientdata(client, act8865);


	return 0;
	/* Unlock expert registers for ACT8865. */
	return type != ACT8865 ? 0 : regmap_write(act8865->regmap,
						  ACT8865_SYS_UNLK_REGS, 0xef);
}
}


static const struct i2c_device_id act8865_ids[] = {
static const struct i2c_device_id act8865_ids[] = {