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

Commit 92526087 authored by Anirudh Ghayal's avatar Anirudh Ghayal Committed by Gerrit - the friendly Code Review server
Browse files

regulator: fan53555: Add i2c retry logic



The i2c-core may perform a bus recovery procedure if
the I2C lines are stuck low. In such a case the client
is expected to retry its i2c transaction. Add a mechanism
to perform multiple delayed retries in case of a I2C
transaction failure.

CRs-Fixed: 715354
Change-Id: I7ef83f1a633ed80830e52e8ccd7bb36144900093
Signed-off-by: default avatarAnirudh Ghayal <aghayal@codeaurora.org>
parent 156ba172
Loading
Loading
Loading
Loading
+68 −11
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@
#include <linux/slab.h>
#include <linux/regmap.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/regulator/fan53555.h>

/* Voltage setting */
@@ -106,6 +107,62 @@ struct fan53555_device_info {
	bool disable_suspend;
};

static int delay_array[] = {10, 20, 30, 40, 50};

static int fan53555_read(struct fan53555_device_info *di, unsigned int reg,
						unsigned int *val)
{
	int i = 0, rc = 0;

	rc = regmap_read(di->regmap, reg, val);
	for (i = 0; rc && i < ARRAY_SIZE(delay_array); i++) {
		pr_debug("Failed reading reg=%u - retry(%d)\n", reg, i);
		msleep(delay_array[i]);
		rc = regmap_read(di->regmap, reg, val);
	}

	if (rc)
		pr_err("Failed reading reg=%u rc=%d\n", reg, rc);

	return rc;
}

static int fan53555_write(struct fan53555_device_info *di, unsigned int reg,
						unsigned int val)
{
	int i = 0, rc = 0;

	rc = regmap_write(di->regmap, reg, val);
	for (i = 0; rc && i < ARRAY_SIZE(delay_array); i++) {
		pr_debug("Failed writing reg=%u - retry(%d)\n", reg, i);
		msleep(delay_array[i]);
		rc = regmap_write(di->regmap, reg, val);
	}

	if (rc)
		pr_err("Failed writing reg=%u rc=%d\n", reg, rc);

	return rc;
}

static int fan53555_update_bits(struct fan53555_device_info *di,
			unsigned int reg, unsigned int mask, unsigned int val)
{
	int i = 0, rc = 0;

	rc = regmap_update_bits(di->regmap, reg, mask, val);
	for (i = 0; rc && i < ARRAY_SIZE(delay_array); i++) {
		pr_debug("Failed updating reg=%u - retry(%d)\n", reg, i);
		msleep(delay_array[i]);
		rc = regmap_update_bits(di->regmap, reg, mask, val);
	}

	if (rc)
		pr_err("Failed updating reg=%u rc=%d\n", reg, rc);

	return rc;
}

static int fan53555_set_suspend_voltage(struct regulator_dev *rdev, int uV)
{
	struct fan53555_device_info *di = rdev_get_drvdata(rdev);
@@ -116,7 +173,7 @@ static int fan53555_set_suspend_voltage(struct regulator_dev *rdev, int uV)
	ret = regulator_map_voltage_linear(rdev, uV, uV);
	if (ret < 0)
		return -EINVAL;
	ret = regmap_update_bits(di->regmap, di->sleep_reg,
	ret = fan53555_update_bits(di, di->sleep_reg,
					VSEL_NSEL_MASK, ret);
	if (ret < 0)
		return -EINVAL;
@@ -133,11 +190,11 @@ static int fan53555_set_mode(struct regulator_dev *rdev, unsigned int mode)

	switch (mode) {
	case REGULATOR_MODE_FAST:
		regmap_update_bits(di->regmap, di->vol_reg,
		fan53555_update_bits(di, di->vol_reg,
				VSEL_MODE, VSEL_MODE);
		break;
	case REGULATOR_MODE_NORMAL:
		regmap_update_bits(di->regmap, di->vol_reg, VSEL_MODE, 0);
		fan53555_update_bits(di, di->vol_reg, VSEL_MODE, 0);
		break;
	default:
		return -EINVAL;
@@ -151,7 +208,7 @@ static unsigned int fan53555_get_mode(struct regulator_dev *rdev)
	unsigned int val;
	int ret = 0;

	ret = regmap_read(di->regmap, di->vol_reg, &val);
	ret = fan53555_read(di, di->vol_reg, &val);
	if (ret < 0)
		return ret;
	if (val & VSEL_MODE)
@@ -280,7 +337,7 @@ static int fan53555_device_setup(struct fan53555_device_info *di,
	reg = FAN53555_CONTROL;
	data = di->slew_rate << CTL_SLEW_SHIFT;
	mask = CTL_SLEW_MASK;
	return regmap_update_bits(di->regmap, reg, mask, data);
	return fan53555_update_bits(di, reg, mask, data);
}

static int fan53555_regulator_register(struct fan53555_device_info *di,
@@ -383,7 +440,7 @@ static int fan53555_restore_working_reg(struct device_node *node,
	u32 val;

	/* Restore register from back up register */
	ret = regmap_read(di->regmap, di->sleep_reg, &val);
	ret = fan53555_read(di, di->sleep_reg, &val);
	if (ret < 0) {
		dev_err(di->dev,
			"Failed to get backup data from reg %d, ret = %d\n",
@@ -391,7 +448,7 @@ static int fan53555_restore_working_reg(struct device_node *node,
		return ret;
	}

	ret = regmap_update_bits(di->regmap,
	ret = fan53555_update_bits(di,
		di->vol_reg, VSEL_FULL_MASK, val);
	if (ret < 0) {
		dev_err(di->dev,
@@ -456,7 +513,7 @@ static int get_reg(void *data, u64 *val)
	int rc;
	unsigned int temp = 0;

	rc = regmap_read(di->regmap, di->peek_poke_address, &temp);
	rc = fan53555_read(di, di->peek_poke_address, &temp);
	if (rc < 0)
		dev_err(di->dev, "Couldn't read reg %x rc = %d\n",
				di->peek_poke_address, rc);
@@ -473,7 +530,7 @@ static int set_reg(void *data, u64 val)
	unsigned int temp = 0;

	temp = (unsigned int) val;
	rc = regmap_write(di->regmap, di->peek_poke_address, temp);
	rc = fan53555_write(di, di->peek_poke_address, temp);
	if (rc < 0)
		dev_err(di->dev, "Couldn't write 0x%02x to 0x%02x rc= %d\n",
			di->peek_poke_address, temp, rc);
@@ -516,14 +573,14 @@ static int fan53555_regulator_probe(struct i2c_client *client,
	di->regulator = pdata->regulator;
	i2c_set_clientdata(client, di);
	/* Get chip ID */
	ret = regmap_read(di->regmap, FAN53555_ID1, &val);
	ret = fan53555_read(di, FAN53555_ID1, &val);
	if (ret < 0) {
		dev_err(&client->dev, "Failed to get chip ID!\n");
		return -ENODEV;
	}
	di->chip_id = val & DIE_ID;
	/* Get chip revision */
	ret = regmap_read(di->regmap, FAN53555_ID2, &val);
	ret = fan53555_read(di, FAN53555_ID2, &val);
	if (ret < 0) {
		dev_err(&client->dev, "Failed to get chip Rev!\n");
		return -ENODEV;