[Letux-kernel] [PATCH 1/6] drivers: power: supply: bq2429x: use regmap for i2c register access

Nick Elsmore nicholaselsmore at gmail.com
Thu Aug 13 03:06:21 CEST 2020


Signed-off-by: Nick Elsmore <nicholaselsmore at gmail.com>
---

 drivers/power/supply/Kconfig           |   1 +
 drivers/power/supply/bq2429x_charger.c | 564 +++++++++++--------------
 2 files changed, 256 insertions(+), 309 deletions(-)

diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index e706adb86462..64a4396d9103 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -593,6 +593,7 @@ config CHARGER_BQ2429X
 	tristate "TI BQ2429x battery charger driver"
 	depends on I2C
 	depends on GPIOLIB || COMPILE_TEST
+	depends on REGMAP_I2C
 	help
 	  Say Y to enable support for the TI BQ24296/297 battery charger.

diff --git a/drivers/power/supply/bq2429x_charger.c
b/drivers/power/supply/bq2429x_charger.c
index 792525a5a1a4..b3f05c7eac9d 100644
--- a/drivers/power/supply/bq2429x_charger.c
+++ b/drivers/power/supply/bq2429x_charger.c
@@ -26,6 +26,7 @@
 #include <linux/param.h>
 #include <linux/platform_device.h>
 #include <linux/power_supply.h>
+#include <linux/regmap.h>
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
 #include <linux/regulator/of_regulator.h>
@@ -36,118 +37,19 @@
 #define OTG_REGULATOR	1
 #define NUM_REGULATORS	2

-/* I2C register defines */
-#define INPUT_SOURCE_CONTROL_REGISTER		0x00
-#define POWER_ON_CONFIGURATION_REGISTER		0x01
-#define CHARGE_CURRENT_CONTROL_REGISTER		0x02
-#define PRE_CHARGE_TERMINATION_CURRENT_CONTROL_REGISTER		0x03
-#define CHARGE_VOLTAGE_CONTROL_REGISTER		0x04
-#define TERMINATION_TIMER_CONTROL_REGISTER		0x05
-#define THERMAL_REGULATION_CONTROL_REGISTER		0x06
-#define MISC_OPERATION_CONTROL_REGISTER		0x07
-#define SYSTEM_STATS_REGISTER		0x08
-#define FAULT_STATS_REGISTER		0x09
-#define VENDOR_STATS_REGISTER		0x0A
-
 /* REG00 input source control register value */
 #define EN_HIZ_ENABLE	 1
 #define EN_HIZ_DISABLE	 0
-#define EN_HIZ_OFF	 7
-#define EN_HIZ_MASK	 1
-
-#define VINDPM_OFF		3
-#define VINDPM_MASK		0xf
-
-#define IINLIM_100MA		0
-#define IINLIM_150MA		1
-#define IINLIM_500MA		2
-#define IINLIM_900MA		3
-#define IINLIM_1200MA		4
-#define IINLIM_1500MA		5
-#define IINLIM_2000MA		6
-#define IINLIM_3000MA		7
-#define IINLIM_OFF		0
-#define IINLIM_MASK		7

 /* REG01 power-on configuration register value */
 /* OTG Mode Current Config */
 #define OTG_MODE_CURRENT_CONFIG_500MA	0x00
 #define OTG_MODE_CURRENT_CONFIG_1300MA	0x01
-#define OTG_MODE_CURRENT_CONFIG_OFF	0
-#define OTG_MODE_CURRENT_CONFIG_MASK	0x01
-
-/* VSYS Minimum */
-#define SYS_MIN_OFF		1
-#define SYS_MIN_MASK		0x7

 /* Charge Mode Config */
 #define CHARGE_MODE_CONFIG_CHARGE_DISABLE	0x00
 #define CHARGE_MODE_CONFIG_CHARGE_BATTERY	0x01
 #define CHARGE_MODE_CONFIG_OTG_OUTPUT		0x02
-#define CHARGE_MODE_CONFIG_OFF			4
-#define CHARGE_MODE_CONFIG_MASK			0x03
-
-/* Watchdog */
-#define WATCHDOG_RESET	0x40
-
-/* Reset */
-#define REGISTER_RESET_ENABLE	 1
-#define REGISTER_RESET_DISABLE	 0
-#define REGISTER_RESET_OFF	 7
-#define REGISTER_RESET_MASK	 1
-
-/* REG02 charge current limit register value */
-#define CHARGE_CURRENT_64MA		0x01
-#define CHARGE_CURRENT_128MA		0x02
-#define CHARGE_CURRENT_256MA		0x04
-#define CHARGE_CURRENT_512MA		0x08
-#define CHARGE_CURRENT_1024MA		0x10
-#define CHARGE_CURRENT_1536MA		0x18
-#define CHARGE_CURRENT_2048MA		0x20
-#define CHARGE_CURRENT_OFF		2
-#define CHARGE_CURRENT_MASK		0x3f
-
-/* REG03 Pre-Charge/Termination Current Control Register value */
-/* Pre-Charge Current Limit */
-#define PRE_CHARGE_CURRENT_LIMIT_128MA		0x00
-#define PRE_CHARGE_CURRENT_LIMIT_256MA		0x01
-#define PRE_CHARGE_CURRENT_LIMIT_OFF		4
-#define PRE_CHARGE_CURRENT_LIMIT_MASK		0x0f
-/* Termination Current Limit */
-#define TERMINATION_CURRENT_LIMIT_128MA		0x00
-#define TERMINATION_CURRENT_LIMIT_256MA		0x01
-#define TERMINATION_CURRENT_LIMIT_OFF		0
-#define TERMINATION_CURRENT_LIMIT_MASK		0x0f
-
-/* REG04 Charge Voltage Register */
-#define VREG_MASK	0x3f
-#define VREG_OFF	2
-
-/* REG05 Charge Termination/Timer control register value */
-#define WATCHDOG_DISABLE	0
-#define WATCHDOG_40S		1
-#define WATCHDOG_80S		2
-#define WATCHDOG_160S		3
-#define WATCHDOG_OFF		4
-#define WATCHDOG_MASK		3
-
-/* REG06 boost voltage/thermal regulation register */
-#define BOOSTV_OFF	4
-#define BOOSTV_MASK	0xf
-
-/* REG07 misc operation control register value */
-#define DPDM_ENABLE	 1
-#define DPDM_DISABLE	 0
-#define DPDM_OFF	 7
-#define DPDM_MASK	 1
-
-/* REG08 system status register value */
-#define VBUS_UNKNOWN		0
-#define VBUS_USB_HOST		1
-#define VBUS_ADAPTER_PORT	2
-#define VBUS_OTG		3
-#define VBUS_OFF		6
-#define VBUS_MASK		3

 #define CHRG_NO_CHARGING	0
 #define CHRG_PRE_CHARGE		1
@@ -158,16 +60,10 @@

 #define DPM_STAT	0x08
 #define PG_STAT		0x04
-#define THERM_STAT	0x02
-#define VSYS_STAT	0x01

 /* REG09 fault status register value */
-
-#define WATCHDOG_FAULT	0x80
-#define OTG_FAULT	0x40
 #define CHRG_FAULT_OFF	4
 #define CHRG_FAULT_MASK	0x3
-#define BAT_FAULT	0x08
 #define NTC_FAULT_OFF	0
 // FIXME: MP2624 has 3 bits
 #define NTC_FAULT_MASK	0x3
@@ -181,11 +77,122 @@
 #define ID_BQ24297		1
 #define ID_MP2624		2

+#define BQ2429X_MANUFACTURER	"Texas Instruments"
+
+enum bq2429x_regs {
+	REG00 = 0,
+	REG01,
+	REG02,
+	REG03,
+	REG04,
+	REG05,
+	REG06,
+	REG07,
+	REG08,
+	REG09,
+	REG0A
+};
+
+enum bq2429x_fields {
+	F_EN_HIZ, F_VINDPM, F_IINLIM,			/* REG00 */
+	F_REG_RESET, F_WD_RESET, F_OTG_CONFIG,		/* REG01 */
+	F_CHG_CONFIG, F_SYS_MIN, F_BOOST_LIM,
+	F_ICHG, F_BCOLD, F_FORCE_20PCT,			/* REG02 */
+	F_IPRECHG, F_ITERM,				/* REG03 */
+	F_VREG, F_BATLOWV, F_VRECHG,			/* REG04 */
+	F_EN_TERM, F_WATCHDOG, F_EN_TIMER, F_CHG_TIMER, /* REG05 */
+	F_BOOSTV, F_BHOT, F_TREG,			/* REG06 */
+	F_IINDET_EN, F_TMR2X_EN, F_BATFET_DISABLE,	/* REG07 */
+	F_INT_MASK,
+	F_VBUS_STAT, F_CHRG_STAT, F_DPM_STAT,		/* REG08 */
+	F_PG_STAT, F_THERM_STAT, F_VSYS_STAT, F_SYS_STAT_REG,
+	F_WATCHDOG_FAULT, F_OTG_FAULT, F_CHRG_FAULT,	/* REG09 */
+	F_BAT_FAULT, F_NTC_FAULT, F_NEW_FAULT_REG,
+	F_PN_REV,					/* REG0A */
+	F_MAX_FIELDS
+};
+
+static const struct reg_field bq2429x_reg_fields[] = {
+	[F_EN_HIZ] 		= REG_FIELD(REG00, 7, 7),
+	[F_VINDPM]		= REG_FIELD(REG00, 3, 6),
+	[F_IINLIM]		= REG_FIELD(REG00, 0, 2),
+	[F_REG_RESET]		= REG_FIELD(REG01, 7, 7),
+	[F_WD_RESET]		= REG_FIELD(REG01, 6, 6),
+	[F_OTG_CONFIG]		= REG_FIELD(REG01, 5, 5),
+	[F_CHG_CONFIG]		= REG_FIELD(REG01, 4, 4),
+	[F_SYS_MIN]		= REG_FIELD(REG01, 1, 3),
+	[F_BOOST_LIM]		= REG_FIELD(REG01, 0, 0),
+	[F_ICHG]		= REG_FIELD(REG02, 2, 7),
+	[F_BCOLD]		= REG_FIELD(REG02, 1, 1),
+	[F_FORCE_20PCT]		= REG_FIELD(REG02, 0, 0),
+	[F_IPRECHG]		= REG_FIELD(REG03, 4, 7),
+	[F_ITERM]		= REG_FIELD(REG03, 0, 3),
+	[F_VREG]		= REG_FIELD(REG04, 2, 7),
+	[F_BATLOWV]		= REG_FIELD(REG04, 1, 1),
+	[F_VRECHG]		= REG_FIELD(REG04, 0, 0),
+	[F_EN_TERM]		= REG_FIELD(REG05, 7, 7),
+	[F_WATCHDOG]		= REG_FIELD(REG05, 4, 5),
+	[F_EN_TIMER]		= REG_FIELD(REG05, 3, 3),
+	[F_CHG_TIMER]		= REG_FIELD(REG05, 1, 2),
+	[F_BOOSTV]		= REG_FIELD(REG06, 4, 7),
+	[F_BHOT]		= REG_FIELD(REG06, 2, 3),
+	[F_TREG]		= REG_FIELD(REG06, 0, 1),
+	[F_IINDET_EN]		= REG_FIELD(REG07, 7, 7),
+	[F_TMR2X_EN]		= REG_FIELD(REG07, 6, 6),
+	[F_BATFET_DISABLE]	= REG_FIELD(REG07, 5, 5),
+	[F_INT_MASK]		= REG_FIELD(REG07, 0, 1),
+	[F_VBUS_STAT]		= REG_FIELD(REG08, 6, 7),
+	[F_CHRG_STAT]		= REG_FIELD(REG08, 4, 5),
+	[F_DPM_STAT]		= REG_FIELD(REG08, 3, 3),
+	[F_PG_STAT]		= REG_FIELD(REG08, 2, 2),
+	[F_THERM_STAT]		= REG_FIELD(REG08, 1, 1),
+	[F_VSYS_STAT]		= REG_FIELD(REG08, 0, 0),
+	[F_SYS_STAT_REG]	= REG_FIELD(REG08, 0, 7),
+	[F_WATCHDOG_FAULT]	= REG_FIELD(REG09, 7, 7),
+	[F_OTG_FAULT]		= REG_FIELD(REG09, 6, 6),
+	[F_CHRG_FAULT]		= REG_FIELD(REG09, 4, 5),
+	[F_BAT_FAULT]		= REG_FIELD(REG09, 3, 3),
+	[F_NTC_FAULT]		= REG_FIELD(REG09, 0, 1),
+	[F_NEW_FAULT_REG]	= REG_FIELD(REG09, 0, 7),
+	[F_PN_REV]		= REG_FIELD(REG0A, 0, 7),
+};
+
+static const struct regmap_range bq2429x_readonly_reg_ranges[] = {
+	regmap_reg_range(REG08, REG0A)
+};
+
+static const struct regmap_access_table bq2429x_writeable_regs = {
+	.no_ranges = bq2429x_readonly_reg_ranges,
+	.n_no_ranges = ARRAY_SIZE(bq2429x_readonly_reg_ranges)
+};
+
+static const struct regmap_range bq2429x_volatile_reg_ranges[] = {
+	regmap_reg_range(REG08, REG09)
+};
+
+static const struct regmap_access_table bq2429x_volatile_regs = {
+	.yes_ranges = bq2429x_volatile_reg_ranges,
+	.n_yes_ranges = ARRAY_SIZE(bq2429x_volatile_reg_ranges)
+};
+
+static const struct regmap_config bq2429x_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = REG0A,
+	.cache_type = REGCACHE_RBTREE,
+	.wr_table = &bq2429x_writeable_regs,
+	.volatile_table = &bq2429x_volatile_regs
+};
+
+
 struct bq2429x_device_info {
 	struct device			*dev;
 	struct i2c_client		*client;
 	const struct i2c_device_id	*id;

+	struct regmap *rmap;
+	struct regmap_field *rmap_fields[F_MAX_FIELDS];
+
 	struct power_supply		*usb;

 	struct regulator_desc		desc[NUM_REGULATORS];
@@ -269,99 +276,73 @@ static const unsigned int otg_VSEL_table[] = {
  * Common code for BQ24296 devices read
  */

-static int bq2429x_i2c_reg8_read(const struct i2c_client *client,
-				 const char reg, char *buf, int count)
+static char *bq2429x_field_to_string(enum bq2429x_fields field_id)
 {
-	struct i2c_adapter *adap = client->adapter;
-	struct i2c_msg msgs[2];
-	char reg_buf = reg;
-	int ret;
-
-	msgs[0].addr = client->addr;
-	msgs[0].flags = client->flags;
-	msgs[0].len = 1;
-	msgs[0].buf = &reg_buf;
-
-	msgs[1].addr = client->addr;
-	msgs[1].flags = client->flags | I2C_M_RD;
-	msgs[1].len = count;
-	msgs[1].buf = (char *)buf;
-
-	ret = i2c_transfer(adap, msgs, 2);
-
-	return (ret == 2) ? count : ret;
-}
+	switch (field_id) {
+	case F_EN_HIZ: return "EN_HIZ";
+	case F_VINDPM: return "VINDPM";
+	case F_IINLIM: return "IINLIM";
+	case F_REG_RESET: return "REG_RESET";
+	case F_WD_RESET: return "WD_RESET";
+	case F_OTG_CONFIG: return "OTG_CONFIG";
+	case F_CHG_CONFIG: return "CHG_CONFIG";
+	case F_SYS_MIN: return "SYS_MIN";
+	case F_BOOST_LIM: return "BOOST_LIM";
+	case F_ICHG: return "ICHG";
+	case F_BCOLD: return "BCOLD";
+	case F_FORCE_20PCT: return "FORCE_20PCT";
+	case F_IPRECHG: return "IPRECHG";
+	case F_ITERM: return "ITERM";
+	case F_VREG: return "VREG";
+	case F_BATLOWV: return "BATLOWV";
+	case F_VRECHG: return "VRECHG";
+	case F_EN_TERM: return "EN_TERM";
+	case F_WATCHDOG: return "WATCHDOG";
+	case F_EN_TIMER: return "EN_TIMER";
+	case F_CHG_TIMER: return "CHG_TIMER";
+	case F_BOOSTV: return "BOOSTV";
+	case F_BHOT: return "BHOT";
+	case F_TREG: return "TREG";
+	case F_IINDET_EN: return "IINDET_EN";
+	case F_TMR2X_EN: return "TMR2X_EN";
+	case F_BATFET_DISABLE: return "BATFET_DISABLE";
+	case F_INT_MASK: return "INT_MASK";
+	case F_VBUS_STAT: return "VBUS_STAT";
+	case F_CHRG_STAT: return "CHRG_STAT";
+	case F_DPM_STAT: return "DPM_STAT";
+	case F_PG_STAT: return "PG_STAT";
+	case F_THERM_STAT: return "THERM_STAT";
+	case F_VSYS_STAT: return "VSYS_STAT";
+	case F_SYS_STAT_REG: return "SYS_STAT_REG";
+	case F_WATCHDOG_FAULT: return "WATCHDOG_FAULT";
+	case F_OTG_FAULT: return "OTG_FAULT";
+	case F_CHRG_FAULT: return "CHRG_FAULT";
+	case F_BAT_FAULT: return "BAT_FAULT";
+	case F_NTC_FAULT: return "NTC_FAULT";
+	case F_NEW_FAULT_REG: return "NEW_FAULT_REG";
+	case F_PN_REV: return "PN_REV";
+	default: return "UNKNOWN";
+	};
+};

-static int bq2429x_i2c_reg8_write(const struct i2c_client *client,
-				  const char reg, const char *buf, int count)
+static int bq2429x_field_read(struct bq2429x_device_info *di,
+			      enum bq2429x_fields field_id)
 {
-	struct i2c_adapter *adap = client->adapter;
-	struct i2c_msg msg;
-	char *tx_buf = kmalloc(count + 1, GFP_KERNEL);
 	int ret;
+	int val;

-	if (!tx_buf)
-		return -ENOMEM;
-	tx_buf[0] = reg;
-	memcpy(tx_buf+1, buf, count);
-
-	msg.addr = client->addr;
-	msg.flags = client->flags;
-	msg.len = count + 1;
-	msg.buf = (char *)tx_buf;
-
-	ret = i2c_transfer(adap, &msg, 1);
-	kfree(tx_buf);
-	return (ret == 1) ? count : ret;
-}
-
-static inline int bq2429x_read(struct i2c_client *client,
-			       u8 reg, u8 buf[], unsigned int len)
-{
-	int ret;
+	ret = regmap_field_read(di->rmap_fields[field_id], &val);
+	if (ret < 0)
+		return ret;

-	ret = bq2429x_i2c_reg8_read(client, reg, buf, len);
-	return ret;
+	return val;
 }

-static inline int bq2429x_write(struct i2c_client *client,
-				u8 reg, u8 const buf[], unsigned int len)
+static int bq2429x_field_write(struct bq2429x_device_info *di,
+			       enum bq2429x_fields field_id,
+			       u8 val)
 {
-	int ret;
-
-	ret = bq2429x_i2c_reg8_write(client, reg, buf, (int)len);
-	return ret;
-}
-
-static int bq2429x_update_reg(struct i2c_client *client,
-			      int reg, u8 value, u8 mask)
-{
-	u8 retval = 0;
-	int ret;
-
-	ret = bq2429x_read(client, reg, &retval, 1);
-	if (ret < 0) {
-		dev_err(&client->dev, "%s: err %d\n", __func__, ret);
-		return ret;
-	}
-	ret = 0;
-
-	dev_dbg(&client->dev, "%s %02x: ( %02x & %02x ) | %02x -> %02x\n",
-		__func__, reg, retval, (u8) ~mask, value,
-		(u8) ((retval & ~mask) | value));
-
-	if ((retval & mask) != value) {
-		retval = (retval & ~mask) | value;
-		ret = bq2429x_write(client, reg, &retval, 1);
-		if (ret < 0) {
-			dev_err(&client->dev, "%s: err %d\n",
-				__func__, ret);
-			return ret;
-		}
-		ret = 0;
-	}
-
-	return ret;
+	return regmap_field_write(di->rmap_fields[field_id], val);
 }

 /* sysfs tool to show all register values */
@@ -375,12 +356,12 @@ static ssize_t show_registers(struct device
*dev, struct device_attribute *attr,
 	int len = 0;
 	int i;

-	for (i = 0; i < 11; i++) {
+	for (i = 0; i < ARRAY_SIZE(bq2429x_reg_fields); i++) {
 		int n;

-		bq2429x_read(di->client, i, &buffer, 1);
-		n = scnprintf(buf, 256, "reg %02x value %02x\n",
-			      i, buffer);
+		buffer = bq2429x_field_read(di, i);
+		n = scnprintf(buf, 256, "field %s value %02x\n",
+			      bq2429x_field_to_string(i), buffer);
 		buf += n;
 		len += n;
 	}
@@ -393,38 +374,40 @@ DEVICE_ATTR(registers, 0444, show_registers, NULL);

 static int bq2429x_get_vindpm_uV(struct bq2429x_device_info *di)
 {
-	u8 retval;
 	int ret;

-	ret = bq2429x_read(di->client, INPUT_SOURCE_CONTROL_REGISTER,
-			   &retval, 1);
+	ret = bq2429x_field_read(di, F_VINDPM);
 	if (ret < 0) {
 		dev_err(&di->client->dev, "%s: err %d\n", __func__, ret);
 		return ret;
 	}

-	return 3880000 + 80000*((retval >> VINDPM_OFF) & VINDPM_MASK);
+	return 3880000 + 80000 * ret;
 }

 static int bq2429x_input_current_limit_uA(struct bq2429x_device_info *di)
 {
 	int ret;
-	u8 retval;

-	ret = bq2429x_read(di->client, INPUT_SOURCE_CONTROL_REGISTER,
-			   &retval, 1);
+	ret = bq2429x_field_read(di, F_EN_HIZ);
 	if (ret < 0) {
 		dev_err(&di->client->dev, "%s: err %d\n", __func__, ret);
 		return ret;
 	}

-	if (((retval >> EN_HIZ_OFF) & EN_HIZ_MASK) == EN_HIZ_ENABLE)
+	if (ret == EN_HIZ_ENABLE)
 		return 0;	// High-Z state

-	if (di->id->driver_data == CHIP_MP2624 && ((retval >> IINLIM_OFF) &
IINLIM_MASK) == 5)
+	ret = bq2429x_field_read(di, F_IINLIM);
+	if (ret < 0) {
+		dev_err(&di->client->dev, "%s: err %d\n", __func__, ret);
+		return ret;
+	}
+
+	if (di->id->driver_data == CHIP_MP2624 && (ret == 5))
 		return 1800000;

-	return iinlim_table[(retval >> IINLIM_OFF) & IINLIM_MASK];
+	return iinlim_table[ret];
 }

 static int bq2429x_set_input_current_limit_uA(struct bq2429x_device_info *di,
@@ -456,37 +439,34 @@ static int
bq2429x_set_input_current_limit_uA(struct bq2429x_device_info *di,
 	else
 		data = 7;

-	ret = bq2429x_update_reg(di->client,
-				  INPUT_SOURCE_CONTROL_REGISTER,
-				  (((data & IINLIM_MASK) << IINLIM_OFF) |
-					(hiz << EN_HIZ_OFF)),
-				  ((IINLIM_MASK << IINLIM_OFF) |
-					(EN_HIZ_MASK << EN_HIZ_OFF)));
+	ret = bq2429x_field_write(di, F_IINLIM, data);
 	if (ret < 0) {
 		dev_err(&di->client->dev, "%s(): Failed to set input current limit (0x%x)\n",
 				__func__, data);
 	}

+	ret = bq2429x_field_write(di, F_EN_HIZ, hiz);
+	if (ret < 0) {
+		dev_err(&di->client->dev, "%s(): Failed to set hiz (0x%x)\n",
+				__func__, hiz);
+	}
+
 	return ret;
 }

 static int bq2429x_get_charge_current_uA(struct bq2429x_device_info *di)
 {
 	int ret;
-	u8 retval;

-	ret = bq2429x_read(di->client, CHARGE_CURRENT_CONTROL_REGISTER, &retval,
-			   1);
-	dev_dbg(di->dev, "bq2429x: CHARGE_CURRENT_CONTROL_REGISTER %02x\n",
-		retval);
+	ret = bq2429x_field_read(di, F_ICHG);
+	dev_dbg(di->dev, "bq2429x: F_ICHG %02x\n", ret);

 	if (ret < 0) {
 		dev_err(&di->client->dev, "%s: err %d\n", __func__, ret);
 		return ret;
 	}

-	return 64000 * ((retval >> CHARGE_CURRENT_OFF) & CHARGE_CURRENT_MASK)
-	       + 512000;
+	return 64000 * ret + 512000;
 }

 static int bq2429x_set_charge_current_uA(struct bq2429x_device_info
*di, int uA)
@@ -500,10 +480,7 @@ static int bq2429x_set_charge_current_uA(struct
bq2429x_device_info *di, int uA)
 	data = (uA - 512000 + 32000) / 64000;
 	data = min(0x27, max(data, 0));	/* limit to 512 mA .. 3008 mA */

-	ret = bq2429x_update_reg(di->client,
-				  CHARGE_CURRENT_CONTROL_REGISTER,
-				  (data << CHARGE_CURRENT_OFF),
-				  (CHARGE_CURRENT_MASK << CHARGE_CURRENT_OFF));
+	ret = bq2429x_field_write(di, F_ICHG, data);
 	if (ret < 0) {
 		dev_err(&di->client->dev, "%s(): Failed to set charge current limit (%d)\n",
 			__func__, uA);
@@ -513,22 +490,17 @@ static int bq2429x_set_charge_current_uA(struct
bq2429x_device_info *di, int uA)

 static int bq2429x_get_precharge_current_uA(struct bq2429x_device_info *di)
 {
-	u8 retval;
 	int ret;

-	ret = bq2429x_read(di->client,
-			   PRE_CHARGE_TERMINATION_CURRENT_CONTROL_REGISTER,
-			   &retval, 1);
-	dev_dbg(di->dev, "bq2429x:
PRE_CHARGE_TERMINATION_CURRENT_CONTROL_REGISTER %02x\n",
-		retval);
+	ret = bq2429x_field_read(di, F_IPRECHG);
+	dev_dbg(di->dev, "bq2429x: F_IPRECHG %02x\n", ret);

 	if (ret < 0) {
 		dev_err(&di->client->dev, "%s: err %d\n", __func__, ret);
 		return ret;
 	}

-	return 128000 * ((retval >> PRE_CHARGE_CURRENT_LIMIT_OFF) &
-			 PRE_CHARGE_CURRENT_LIMIT_MASK) + 128000;
+	return 128000 * ret + 128000;
 }

 static int bq2429x_set_precharge_current_uA(struct
bq2429x_device_info *di, int uA)
@@ -542,10 +514,7 @@ static int
bq2429x_set_precharge_current_uA(struct bq2429x_device_info *di, int
 	data = (uA - 128000 + 64000) / 128000;
 	data = min(0xf, max(data, 0));	/* limit to 128 mA .. 2048 mA */

-	ret = bq2429x_update_reg(di->client,
-				  PRE_CHARGE_TERMINATION_CURRENT_CONTROL_REGISTER,
-				  (data << PRE_CHARGE_CURRENT_LIMIT_OFF),
-				  (PRE_CHARGE_CURRENT_LIMIT_MASK << PRE_CHARGE_CURRENT_LIMIT_OFF));
+	ret = bq2429x_field_write(di, F_IPRECHG, data);
 	if (ret < 0) {
 		dev_err(&di->client->dev, "%s(): Failed to set precharge charge
current (%d)\n",
 			__func__, uA);
@@ -564,10 +533,7 @@ static int
bq2429x_set_charge_term_current_uA(struct bq2429x_device_info *di, in
 	data = (uA - 128000 + 64000) / 128000;
 	data = min(0xf, max(data, 0));	/* limit to 128 mA .. 2048 mA */

-	ret = bq2429x_update_reg(di->client,
-				  PRE_CHARGE_TERMINATION_CURRENT_CONTROL_REGISTER,
-				  (data << TERMINATION_CURRENT_LIMIT_OFF),
-				  (PRE_CHARGE_CURRENT_LIMIT_MASK << TERMINATION_CURRENT_LIMIT_OFF));
+	ret = bq2429x_field_write(di, F_ITERM, data);
 	if (ret < 0) {
 		dev_err(&di->client->dev, "%s(): Failed to set charge current limit (%d)\n",
 			__func__, uA);
@@ -579,10 +545,7 @@ static int bq2429x_en_hiz_disable(struct
bq2429x_device_info *di)
 {
 	int ret;

-	ret = bq2429x_update_reg(di->client,
-				  INPUT_SOURCE_CONTROL_REGISTER,
-				  EN_HIZ_DISABLE << EN_HIZ_OFF,
-				  EN_HIZ_MASK << EN_HIZ_OFF);
+	ret = bq2429x_field_write(di, F_EN_HIZ, EN_HIZ_DISABLE);
 	if (ret < 0) {
 		dev_err(&di->client->dev, "%s(): Failed to set en_hiz_disable\n",
 			__func__);
@@ -594,10 +557,7 @@ static int bq2429x_set_charge_mode(struct
bq2429x_device_info *di, u8 mode)
 {
 	int ret;

-	ret = bq2429x_update_reg(di->client,
-				  POWER_ON_CONFIGURATION_REGISTER,
-				  mode << CHARGE_MODE_CONFIG_OFF,
-				  CHARGE_MODE_CONFIG_MASK << CHARGE_MODE_CONFIG_OFF);
+	ret = bq2429x_field_write(di, F_CHG_CONFIG, mode);
 	if (ret < 0) {
 		dev_err(&di->client->dev, "%s(): Failed to set charge mode(0x%x)\n",
 				__func__, mode);
@@ -608,20 +568,18 @@ static int bq2429x_set_charge_mode(struct
bq2429x_device_info *di, u8 mode)

 static int bq2429x_get_vsys_voltage_uV(struct bq2429x_device_info *di)
 {
-	u8 retval;
 	int ret;

 	dev_dbg(di->dev, "%s\n", __func__);

-	ret = bq2429x_read(di->client, POWER_ON_CONFIGURATION_REGISTER, &retval,
-			   1);
+	ret = bq2429x_field_read(di, F_SYS_MIN);
 	if (ret < 0)
 		return ret;

 	dev_dbg(di->dev, " => %d uV\n",
-		vsys_VSEL_table[(retval >> SYS_MIN_OFF) & SYS_MIN_MASK]);
+		vsys_VSEL_table[ret]);

-	return vsys_VSEL_table[(retval >> SYS_MIN_OFF) & SYS_MIN_MASK];
+	return vsys_VSEL_table[ret];
 }

 static int bq2429x_set_vsys_voltage_uV(struct bq2429x_device_info *di,
@@ -632,32 +590,23 @@ static int bq2429x_set_vsys_voltage_uV(struct
bq2429x_device_info *di,
 // revisit: the driver should select the voltage closest to min_uV by
scanning vsys_VSEL_table

 	return 0;	/* disabled/untested */
-
-	/* set system voltage */
-
-	return bq2429x_update_reg(di->client,
-				  POWER_ON_CONFIGURATION_REGISTER,
-				  0,	/* 3.0V + 0.2V */
-				  SYS_MIN_MASK << SYS_MIN_OFF);
 }

 static int bq2429x_get_otg_voltage_uV(struct bq2429x_device_info *di)
 {
-	u8 retval;
 	int ret;

 	dev_dbg(di->dev, "%s\n", __func__);

 // FIXME: constant for MP2624
-	ret = bq2429x_read(di->client, THERMAL_REGULATION_CONTROL_REGISTER,
-			   &retval, 1);
+	ret = bq2429x_field_read(di, F_BOOSTV);
 	if (ret < 0)
 		return ret;

 	dev_dbg(di->dev, " => %d uV\n",
-		otg_VSEL_table[(retval >> BOOSTV_OFF) & BOOSTV_MASK]);
+		otg_VSEL_table[ret]);

-	return otg_VSEL_table[(retval >> BOOSTV_OFF) & BOOSTV_MASK];
+	return otg_VSEL_table[ret];
 }

 static int bq2429x_set_otg_voltage_uV(struct bq2429x_device_info *di,
@@ -670,24 +619,15 @@ static int bq2429x_set_otg_voltage_uV(struct
bq2429x_device_info *di,
 // revisit: the driver should select the voltage closest to min_uV by
scanning otg_VSEL_table

 	return 0;	/* disabled/untested */
-
-	/* set OTG step up converter voltage */
-
-	return bq2429x_update_reg(di->client,
-				  THERMAL_REGULATION_CONTROL_REGISTER,
-				  0,
-				  BOOSTV_MASK << BOOSTV_OFF);
 }

 static int bq2429x_is_otg_enabled(struct bq2429x_device_info *di)
 { /* check if OTG converter is enabled */
-	u8 retval;
 	int ret;

 	dev_dbg(di->dev, "%s\n", __func__);

-	ret = bq2429x_read(di->client, POWER_ON_CONFIGURATION_REGISTER, &retval,
-			   1);
+	ret = bq2429x_field_read(di, F_OTG_CONFIG);
 	if (ret < 0)
 		return 0;	/* assume disabled */

@@ -698,27 +638,22 @@ static int bq2429x_is_otg_enabled(struct
bq2429x_device_info *di)
 	 */

 	/* check bit 5 of POWER_ON_CONFIGURATION_REGISTER */
-	return ((retval >> CHARGE_MODE_CONFIG_OFF) & CHARGE_MODE_CONFIG_MASK)
-	       == CHARGE_MODE_CONFIG_OTG_OUTPUT;
+	return ret;
 }

 static int bq2429x_get_otg_current_limit_uA(struct bq2429x_device_info *di)
 {
-	u8 retval;
 	int ret;

 	dev_dbg(di->dev, "%s\n", __func__);

-	ret = bq2429x_read(di->client, POWER_ON_CONFIGURATION_REGISTER, &retval,
-			   1);
+	ret = bq2429x_field_read(di, F_BOOST_LIM);
 	if (ret < 0)
 		return ret;

 // FIXME: different bit(s) and values (500mA 1.3A) in MP2624 in REG02

-	return ((retval >> OTG_MODE_CURRENT_CONFIG_OFF) &
-		 OTG_MODE_CURRENT_CONFIG_MASK) ?
-		 1000000 : 1500000;	/* 1.0A or 1.5A */
+	return ret ? 1000000 : 1500000;	/* 1.0A or 1.5A */
 }

 static int bq2429x_set_otg_current_limit_uA(struct bq2429x_device_info *di,
@@ -726,6 +661,7 @@ static int bq2429x_set_otg_current_limit_uA(struct
bq2429x_device_info *di,
 {
 	int enable = true;
 	int val = OTG_MODE_CURRENT_CONFIG_500MA;
+	int ret;

 	dev_dbg(di->dev, "%s(%d, %d)\n", __func__, min_uA, max_uA);

@@ -743,25 +679,26 @@ static int
bq2429x_set_otg_current_limit_uA(struct bq2429x_device_info *di,

 // FIXME: different bit(s) and values (500mA 1.3A) in MP2624 in REG02

-	return bq2429x_update_reg(di->client,
-		POWER_ON_CONFIGURATION_REGISTER,
-		(enable << 5)|(val << OTG_MODE_CURRENT_CONFIG_OFF),
-		(1 << 5)|
-		(OTG_MODE_CURRENT_CONFIG_MASK << OTG_MODE_CURRENT_CONFIG_OFF));
+	ret = bq2429x_field_write(di, F_BOOST_LIM, val);
+	if (ret < 0) {
+		dev_err(&di->client->dev, "%s(): Failed to set OTG current limit\n",
+			__func__);
+	}
+
+	ret = bq2429x_field_write(di, F_OTG_CONFIG, enable);
+	if (ret < 0) {
+		dev_err(&di->client->dev, "%s(): Failed to set OTG enable\n",
+			__func__);
+	}
+
+	return 0;
 }

 /* initialize the chip */

 static int bq2429x_get_vendor_id(struct bq2429x_device_info *di)
 {
-	u8 retval;
-	int ret;
-
-	/* get the vendor id */
-	ret = bq2429x_read(di->client, VENDOR_STATS_REGISTER, &retval, 1);
-	if (ret < 0)
-		return ret;
-	return retval;
+	return bq2429x_field_read(di, F_PN_REV);
 }

 static int bq2429x_init_registers(struct bq2429x_device_info *di)
@@ -777,10 +714,7 @@ static int bq2429x_init_registers(struct
bq2429x_device_info *di)
 	// bq2429x_set_precharge_current_uA(di->precharge_current_uA);

 	/* set Pre-Charge Current Limit as 128mA */
-	ret = bq2429x_update_reg(di->client,
-		PRE_CHARGE_TERMINATION_CURRENT_CONTROL_REGISTER,
-		PRE_CHARGE_CURRENT_LIMIT_128MA << PRE_CHARGE_CURRENT_LIMIT_OFF,
-		PRE_CHARGE_CURRENT_LIMIT_MASK << PRE_CHARGE_CURRENT_LIMIT_OFF);
+	ret = bq2429x_field_write(di, F_IPRECHG, 0);
 	if (ret < 0) {
 		dev_err(&di->client->dev, "%s(): Failed to set pre-charge limit 128mA\n",
 				__func__);
@@ -790,10 +724,7 @@ static int bq2429x_init_registers(struct
bq2429x_device_info *di)
 	// bq2429x_set_charge_term_current_uA(di->charge_term_current_uA);

 	/* set Termination Current Limit as 128mA */
-	ret = bq2429x_update_reg(di->client,
-		PRE_CHARGE_TERMINATION_CURRENT_CONTROL_REGISTER,
-		TERMINATION_CURRENT_LIMIT_128MA << TERMINATION_CURRENT_LIMIT_OFF,
-		TERMINATION_CURRENT_LIMIT_MASK << TERMINATION_CURRENT_LIMIT_OFF);
+	ret = bq2429x_field_write(di, F_ITERM, 0);
 	if (ret < 0) {
 		dev_err(&di->client->dev, "%s(): Failed to set termination limit 128mA\n",
 				__func__);
@@ -828,10 +759,7 @@ static int bq2429x_init_registers(struct
bq2429x_device_info *di)

 	/* revisit: bq2429x_set_charge_current_uA(di, ?); */

-	ret = bq2429x_update_reg(di->client,
-				  CHARGE_VOLTAGE_CONTROL_REGISTER,
-				  bits << VREG_OFF,
-				  VREG_MASK << VREG_OFF);
+	ret = bq2429x_field_write(di, F_VREG, bits);
 	if (ret < 0) {
 		dev_err(&di->client->dev, "%s(): Failed to set max. battery voltage\n",
 				__func__);
@@ -916,23 +844,25 @@ static int bq2429x_usb_detect(struct
bq2429x_device_info *di)

 	dev_dbg(di->dev, "%s, line=%d\n", __func__, __LINE__);

-	ret = bq2429x_read(di->client, SYSTEM_STATS_REGISTER, &di->r8, 1);
-	if (ret != 1) {
+	ret = bq2429x_field_read(di, F_SYS_STAT_REG);
+	if (ret < 0) {
 		mutex_unlock(&di->var_lock);

 		dev_err(&di->client->dev, "%s: err %d\n", __func__, ret);

 		return ret;
 	}
+	di->r8 = ret;

-	ret = bq2429x_read(di->client, FAULT_STATS_REGISTER, &di->r9, 1);
-	if (ret != 1) {
+	ret = bq2429x_field_read(di, F_NEW_FAULT_REG);
+	if (ret < 0) {
 		mutex_unlock(&di->var_lock);

 		dev_err(&di->client->dev, "%s: err %d\n", __func__, ret);

 		return ret;
 	}
+	di->r9 = ret;

 	/* report changes to last state */
 	if (di->r8 != di->prev_r8 || di->r9 != di->prev_r9)
@@ -1649,8 +1579,24 @@ static int bq2429x_charger_probe(struct
i2c_client *client,
 	di->prev_r8 = 0xff;
 	di->prev_r9 = 0xff;

-	ret = bq2429x_get_vendor_id(di);
+	di->rmap = devm_regmap_init_i2c(client, &bq2429x_regmap_config);
+	if (IS_ERR(di->rmap)) {
+		dev_err(di->dev, "failed to allocate register map\n");
+		return PTR_ERR(di->rmap);
+	}

+	for (i=0; i < ARRAY_SIZE(bq2429x_reg_fields); i++) {
+		const struct reg_field *reg_fields = bq2429x_reg_fields;
+
+		di->rmap_fields[i] = devm_regmap_field_alloc(di->dev, di->rmap,
+								reg_fields[i]);
+		if (IS_ERR(di->rmap_fields[i])) {
+			dev_err(di->dev, "failed to allocate regmap fields\n");
+			return PTR_ERR(di->rmap_fields[i]);
+		}
+	}
+
+	ret = bq2429x_get_vendor_id(di);
 	if (ret < 0) {
 		dev_err(&di->client->dev,
 			"%s(): Failed reading vendor register\n", __func__);
-- 
2.25.1
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.goldelico.com/pipermail/letux-kernel/attachments/20200812/90bd1264/attachment-0001.htm>


More information about the Letux-kernel mailing list