18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * I2C client/driver for the Linear Technology LTC2941, LTC2942, LTC2943
48c2ecf20Sopenharmony_ci * and LTC2944 Battery Gas Gauge IC
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Copyright (C) 2014 Topic Embedded Systems
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Author: Auryn Verwegen
98c2ecf20Sopenharmony_ci * Author: Mike Looijmans
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci#include <linux/kernel.h>
128c2ecf20Sopenharmony_ci#include <linux/module.h>
138c2ecf20Sopenharmony_ci#include <linux/of_device.h>
148c2ecf20Sopenharmony_ci#include <linux/types.h>
158c2ecf20Sopenharmony_ci#include <linux/errno.h>
168c2ecf20Sopenharmony_ci#include <linux/swab.h>
178c2ecf20Sopenharmony_ci#include <linux/i2c.h>
188c2ecf20Sopenharmony_ci#include <linux/delay.h>
198c2ecf20Sopenharmony_ci#include <linux/power_supply.h>
208c2ecf20Sopenharmony_ci#include <linux/slab.h>
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#define I16_MSB(x)			((x >> 8) & 0xFF)
238c2ecf20Sopenharmony_ci#define I16_LSB(x)			(x & 0xFF)
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#define LTC294X_WORK_DELAY		10	/* Update delay in seconds */
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#define LTC294X_MAX_VALUE		0xFFFF
288c2ecf20Sopenharmony_ci#define LTC294X_MID_SUPPLY		0x7FFF
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci#define LTC2941_MAX_PRESCALER_EXP	7
318c2ecf20Sopenharmony_ci#define LTC2943_MAX_PRESCALER_EXP	6
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_cienum ltc294x_reg {
348c2ecf20Sopenharmony_ci	LTC294X_REG_STATUS		= 0x00,
358c2ecf20Sopenharmony_ci	LTC294X_REG_CONTROL		= 0x01,
368c2ecf20Sopenharmony_ci	LTC294X_REG_ACC_CHARGE_MSB	= 0x02,
378c2ecf20Sopenharmony_ci	LTC294X_REG_ACC_CHARGE_LSB	= 0x03,
388c2ecf20Sopenharmony_ci	LTC294X_REG_CHARGE_THR_HIGH_MSB	= 0x04,
398c2ecf20Sopenharmony_ci	LTC294X_REG_CHARGE_THR_HIGH_LSB	= 0x05,
408c2ecf20Sopenharmony_ci	LTC294X_REG_CHARGE_THR_LOW_MSB	= 0x06,
418c2ecf20Sopenharmony_ci	LTC294X_REG_CHARGE_THR_LOW_LSB	= 0x07,
428c2ecf20Sopenharmony_ci	LTC294X_REG_VOLTAGE_MSB		= 0x08,
438c2ecf20Sopenharmony_ci	LTC294X_REG_VOLTAGE_LSB		= 0x09,
448c2ecf20Sopenharmony_ci	LTC2942_REG_TEMPERATURE_MSB	= 0x0C,
458c2ecf20Sopenharmony_ci	LTC2942_REG_TEMPERATURE_LSB	= 0x0D,
468c2ecf20Sopenharmony_ci	LTC2943_REG_CURRENT_MSB		= 0x0E,
478c2ecf20Sopenharmony_ci	LTC2943_REG_CURRENT_LSB		= 0x0F,
488c2ecf20Sopenharmony_ci	LTC2943_REG_TEMPERATURE_MSB	= 0x14,
498c2ecf20Sopenharmony_ci	LTC2943_REG_TEMPERATURE_LSB	= 0x15,
508c2ecf20Sopenharmony_ci};
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_cienum ltc294x_id {
538c2ecf20Sopenharmony_ci	LTC2941_ID,
548c2ecf20Sopenharmony_ci	LTC2942_ID,
558c2ecf20Sopenharmony_ci	LTC2943_ID,
568c2ecf20Sopenharmony_ci	LTC2944_ID,
578c2ecf20Sopenharmony_ci};
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci#define LTC2941_REG_STATUS_CHIP_ID	BIT(7)
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci#define LTC2942_REG_CONTROL_MODE_SCAN	(BIT(7) | BIT(6))
628c2ecf20Sopenharmony_ci#define LTC2943_REG_CONTROL_MODE_SCAN	BIT(7)
638c2ecf20Sopenharmony_ci#define LTC294X_REG_CONTROL_PRESCALER_MASK	(BIT(5) | BIT(4) | BIT(3))
648c2ecf20Sopenharmony_ci#define LTC294X_REG_CONTROL_SHUTDOWN_MASK	(BIT(0))
658c2ecf20Sopenharmony_ci#define LTC294X_REG_CONTROL_PRESCALER_SET(x) \
668c2ecf20Sopenharmony_ci	((x << 3) & LTC294X_REG_CONTROL_PRESCALER_MASK)
678c2ecf20Sopenharmony_ci#define LTC294X_REG_CONTROL_ALCC_CONFIG_DISABLED	0
688c2ecf20Sopenharmony_ci#define LTC294X_REG_CONTROL_ADC_DISABLE(x)	((x) & ~(BIT(7) | BIT(6)))
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_cistruct ltc294x_info {
718c2ecf20Sopenharmony_ci	struct i2c_client *client;	/* I2C Client pointer */
728c2ecf20Sopenharmony_ci	struct power_supply *supply;	/* Supply pointer */
738c2ecf20Sopenharmony_ci	struct power_supply_desc supply_desc;	/* Supply description */
748c2ecf20Sopenharmony_ci	struct delayed_work work;	/* Work scheduler */
758c2ecf20Sopenharmony_ci	enum ltc294x_id id;		/* Chip type */
768c2ecf20Sopenharmony_ci	int charge;	/* Last charge register content */
778c2ecf20Sopenharmony_ci	int r_sense;	/* mOhm */
788c2ecf20Sopenharmony_ci	int Qlsb;	/* nAh */
798c2ecf20Sopenharmony_ci};
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_cistatic inline int convert_bin_to_uAh(
828c2ecf20Sopenharmony_ci	const struct ltc294x_info *info, int Q)
838c2ecf20Sopenharmony_ci{
848c2ecf20Sopenharmony_ci	return ((Q * (info->Qlsb / 10))) / 100;
858c2ecf20Sopenharmony_ci}
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_cistatic inline int convert_uAh_to_bin(
888c2ecf20Sopenharmony_ci	const struct ltc294x_info *info, int uAh)
898c2ecf20Sopenharmony_ci{
908c2ecf20Sopenharmony_ci	int Q;
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	Q = (uAh * 100) / (info->Qlsb/10);
938c2ecf20Sopenharmony_ci	return (Q < LTC294X_MAX_VALUE) ? Q : LTC294X_MAX_VALUE;
948c2ecf20Sopenharmony_ci}
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_cistatic int ltc294x_read_regs(struct i2c_client *client,
978c2ecf20Sopenharmony_ci	enum ltc294x_reg reg, u8 *buf, int num_regs)
988c2ecf20Sopenharmony_ci{
998c2ecf20Sopenharmony_ci	int ret;
1008c2ecf20Sopenharmony_ci	struct i2c_msg msgs[2] = { };
1018c2ecf20Sopenharmony_ci	u8 reg_start = reg;
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	msgs[0].addr	= client->addr;
1048c2ecf20Sopenharmony_ci	msgs[0].len	= 1;
1058c2ecf20Sopenharmony_ci	msgs[0].buf	= &reg_start;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	msgs[1].addr	= client->addr;
1088c2ecf20Sopenharmony_ci	msgs[1].len	= num_regs;
1098c2ecf20Sopenharmony_ci	msgs[1].buf	= buf;
1108c2ecf20Sopenharmony_ci	msgs[1].flags	= I2C_M_RD;
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	ret = i2c_transfer(client->adapter, &msgs[0], 2);
1138c2ecf20Sopenharmony_ci	if (ret < 0) {
1148c2ecf20Sopenharmony_ci		dev_err(&client->dev, "ltc2941 read_reg failed!\n");
1158c2ecf20Sopenharmony_ci		return ret;
1168c2ecf20Sopenharmony_ci	}
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	dev_dbg(&client->dev, "%s (%#x, %d) -> %#x\n",
1198c2ecf20Sopenharmony_ci		__func__, reg, num_regs, *buf);
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	return 0;
1228c2ecf20Sopenharmony_ci}
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_cistatic int ltc294x_write_regs(struct i2c_client *client,
1258c2ecf20Sopenharmony_ci	enum ltc294x_reg reg, const u8 *buf, int num_regs)
1268c2ecf20Sopenharmony_ci{
1278c2ecf20Sopenharmony_ci	int ret;
1288c2ecf20Sopenharmony_ci	u8 reg_start = reg;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	ret = i2c_smbus_write_i2c_block_data(client, reg_start, num_regs, buf);
1318c2ecf20Sopenharmony_ci	if (ret < 0) {
1328c2ecf20Sopenharmony_ci		dev_err(&client->dev, "ltc2941 write_reg failed!\n");
1338c2ecf20Sopenharmony_ci		return ret;
1348c2ecf20Sopenharmony_ci	}
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	dev_dbg(&client->dev, "%s (%#x, %d) -> %#x\n",
1378c2ecf20Sopenharmony_ci		__func__, reg, num_regs, *buf);
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	return 0;
1408c2ecf20Sopenharmony_ci}
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_cistatic int ltc294x_reset(const struct ltc294x_info *info, int prescaler_exp)
1438c2ecf20Sopenharmony_ci{
1448c2ecf20Sopenharmony_ci	int ret;
1458c2ecf20Sopenharmony_ci	u8 value;
1468c2ecf20Sopenharmony_ci	u8 control;
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	/* Read status and control registers */
1498c2ecf20Sopenharmony_ci	ret = ltc294x_read_regs(info->client, LTC294X_REG_CONTROL, &value, 1);
1508c2ecf20Sopenharmony_ci	if (ret < 0) {
1518c2ecf20Sopenharmony_ci		dev_err(&info->client->dev,
1528c2ecf20Sopenharmony_ci			"Could not read registers from device\n");
1538c2ecf20Sopenharmony_ci		goto error_exit;
1548c2ecf20Sopenharmony_ci	}
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	control = LTC294X_REG_CONTROL_PRESCALER_SET(prescaler_exp) |
1578c2ecf20Sopenharmony_ci				LTC294X_REG_CONTROL_ALCC_CONFIG_DISABLED;
1588c2ecf20Sopenharmony_ci	/* Put device into "monitor" mode */
1598c2ecf20Sopenharmony_ci	switch (info->id) {
1608c2ecf20Sopenharmony_ci	case LTC2942_ID:	/* 2942 measures every 2 sec */
1618c2ecf20Sopenharmony_ci		control |= LTC2942_REG_CONTROL_MODE_SCAN;
1628c2ecf20Sopenharmony_ci		break;
1638c2ecf20Sopenharmony_ci	case LTC2943_ID:
1648c2ecf20Sopenharmony_ci	case LTC2944_ID:	/* 2943 and 2944 measure every 10 sec */
1658c2ecf20Sopenharmony_ci		control |= LTC2943_REG_CONTROL_MODE_SCAN;
1668c2ecf20Sopenharmony_ci		break;
1678c2ecf20Sopenharmony_ci	default:
1688c2ecf20Sopenharmony_ci		break;
1698c2ecf20Sopenharmony_ci	}
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	if (value != control) {
1728c2ecf20Sopenharmony_ci		ret = ltc294x_write_regs(info->client,
1738c2ecf20Sopenharmony_ci			LTC294X_REG_CONTROL, &control, 1);
1748c2ecf20Sopenharmony_ci		if (ret < 0) {
1758c2ecf20Sopenharmony_ci			dev_err(&info->client->dev,
1768c2ecf20Sopenharmony_ci				"Could not write register\n");
1778c2ecf20Sopenharmony_ci			goto error_exit;
1788c2ecf20Sopenharmony_ci		}
1798c2ecf20Sopenharmony_ci	}
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	return 0;
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_cierror_exit:
1848c2ecf20Sopenharmony_ci	return ret;
1858c2ecf20Sopenharmony_ci}
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_cistatic int ltc294x_read_charge_register(const struct ltc294x_info *info,
1888c2ecf20Sopenharmony_ci					enum ltc294x_reg reg)
1898c2ecf20Sopenharmony_ci {
1908c2ecf20Sopenharmony_ci	int ret;
1918c2ecf20Sopenharmony_ci	u8 datar[2];
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	ret = ltc294x_read_regs(info->client, reg, &datar[0], 2);
1948c2ecf20Sopenharmony_ci	if (ret < 0)
1958c2ecf20Sopenharmony_ci		return ret;
1968c2ecf20Sopenharmony_ci	return (datar[0] << 8) + datar[1];
1978c2ecf20Sopenharmony_ci}
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_cistatic int ltc294x_get_charge(const struct ltc294x_info *info,
2008c2ecf20Sopenharmony_ci				enum ltc294x_reg reg, int *val)
2018c2ecf20Sopenharmony_ci{
2028c2ecf20Sopenharmony_ci	int value = ltc294x_read_charge_register(info, reg);
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	if (value < 0)
2058c2ecf20Sopenharmony_ci		return value;
2068c2ecf20Sopenharmony_ci	/* When r_sense < 0, this counts up when the battery discharges */
2078c2ecf20Sopenharmony_ci	if (info->Qlsb < 0)
2088c2ecf20Sopenharmony_ci		value -= 0xFFFF;
2098c2ecf20Sopenharmony_ci	*val = convert_bin_to_uAh(info, value);
2108c2ecf20Sopenharmony_ci	return 0;
2118c2ecf20Sopenharmony_ci}
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_cistatic int ltc294x_set_charge_now(const struct ltc294x_info *info, int val)
2148c2ecf20Sopenharmony_ci{
2158c2ecf20Sopenharmony_ci	int ret;
2168c2ecf20Sopenharmony_ci	u8 dataw[2];
2178c2ecf20Sopenharmony_ci	u8 ctrl_reg;
2188c2ecf20Sopenharmony_ci	s32 value;
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	value = convert_uAh_to_bin(info, val);
2218c2ecf20Sopenharmony_ci	/* Direction depends on how sense+/- were connected */
2228c2ecf20Sopenharmony_ci	if (info->Qlsb < 0)
2238c2ecf20Sopenharmony_ci		value += 0xFFFF;
2248c2ecf20Sopenharmony_ci	if ((value < 0) || (value > 0xFFFF)) /* input validation */
2258c2ecf20Sopenharmony_ci		return -EINVAL;
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	/* Read control register */
2288c2ecf20Sopenharmony_ci	ret = ltc294x_read_regs(info->client,
2298c2ecf20Sopenharmony_ci		LTC294X_REG_CONTROL, &ctrl_reg, 1);
2308c2ecf20Sopenharmony_ci	if (ret < 0)
2318c2ecf20Sopenharmony_ci		return ret;
2328c2ecf20Sopenharmony_ci	/* Disable analog section */
2338c2ecf20Sopenharmony_ci	ctrl_reg |= LTC294X_REG_CONTROL_SHUTDOWN_MASK;
2348c2ecf20Sopenharmony_ci	ret = ltc294x_write_regs(info->client,
2358c2ecf20Sopenharmony_ci		LTC294X_REG_CONTROL, &ctrl_reg, 1);
2368c2ecf20Sopenharmony_ci	if (ret < 0)
2378c2ecf20Sopenharmony_ci		return ret;
2388c2ecf20Sopenharmony_ci	/* Set new charge value */
2398c2ecf20Sopenharmony_ci	dataw[0] = I16_MSB(value);
2408c2ecf20Sopenharmony_ci	dataw[1] = I16_LSB(value);
2418c2ecf20Sopenharmony_ci	ret = ltc294x_write_regs(info->client,
2428c2ecf20Sopenharmony_ci		LTC294X_REG_ACC_CHARGE_MSB, &dataw[0], 2);
2438c2ecf20Sopenharmony_ci	if (ret < 0)
2448c2ecf20Sopenharmony_ci		goto error_exit;
2458c2ecf20Sopenharmony_ci	/* Enable analog section */
2468c2ecf20Sopenharmony_cierror_exit:
2478c2ecf20Sopenharmony_ci	ctrl_reg &= ~LTC294X_REG_CONTROL_SHUTDOWN_MASK;
2488c2ecf20Sopenharmony_ci	ret = ltc294x_write_regs(info->client,
2498c2ecf20Sopenharmony_ci		LTC294X_REG_CONTROL, &ctrl_reg, 1);
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	return ret < 0 ? ret : 0;
2528c2ecf20Sopenharmony_ci}
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_cistatic int ltc294x_set_charge_thr(const struct ltc294x_info *info,
2558c2ecf20Sopenharmony_ci					enum ltc294x_reg reg, int val)
2568c2ecf20Sopenharmony_ci{
2578c2ecf20Sopenharmony_ci	u8 dataw[2];
2588c2ecf20Sopenharmony_ci	s32 value;
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	value = convert_uAh_to_bin(info, val);
2618c2ecf20Sopenharmony_ci	/* Direction depends on how sense+/- were connected */
2628c2ecf20Sopenharmony_ci	if (info->Qlsb < 0)
2638c2ecf20Sopenharmony_ci		value += 0xFFFF;
2648c2ecf20Sopenharmony_ci	if ((value < 0) || (value > 0xFFFF)) /* input validation */
2658c2ecf20Sopenharmony_ci		return -EINVAL;
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	/* Set new charge value */
2688c2ecf20Sopenharmony_ci	dataw[0] = I16_MSB(value);
2698c2ecf20Sopenharmony_ci	dataw[1] = I16_LSB(value);
2708c2ecf20Sopenharmony_ci	return ltc294x_write_regs(info->client, reg, &dataw[0], 2);
2718c2ecf20Sopenharmony_ci}
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_cistatic int ltc294x_get_charge_counter(
2748c2ecf20Sopenharmony_ci	const struct ltc294x_info *info, int *val)
2758c2ecf20Sopenharmony_ci{
2768c2ecf20Sopenharmony_ci	int value = ltc294x_read_charge_register(info, LTC294X_REG_ACC_CHARGE_MSB);
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	if (value < 0)
2798c2ecf20Sopenharmony_ci		return value;
2808c2ecf20Sopenharmony_ci	value -= LTC294X_MID_SUPPLY;
2818c2ecf20Sopenharmony_ci	*val = convert_bin_to_uAh(info, value);
2828c2ecf20Sopenharmony_ci	return 0;
2838c2ecf20Sopenharmony_ci}
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_cistatic int ltc294x_get_voltage(const struct ltc294x_info *info, int *val)
2868c2ecf20Sopenharmony_ci{
2878c2ecf20Sopenharmony_ci	int ret;
2888c2ecf20Sopenharmony_ci	u8 datar[2];
2898c2ecf20Sopenharmony_ci	u32 value;
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	ret = ltc294x_read_regs(info->client,
2928c2ecf20Sopenharmony_ci		LTC294X_REG_VOLTAGE_MSB, &datar[0], 2);
2938c2ecf20Sopenharmony_ci	value = (datar[0] << 8) | datar[1];
2948c2ecf20Sopenharmony_ci	switch (info->id) {
2958c2ecf20Sopenharmony_ci	case LTC2943_ID:
2968c2ecf20Sopenharmony_ci		value *= 23600 * 2;
2978c2ecf20Sopenharmony_ci		value /= 0xFFFF;
2988c2ecf20Sopenharmony_ci		value *= 1000 / 2;
2998c2ecf20Sopenharmony_ci		break;
3008c2ecf20Sopenharmony_ci	case LTC2944_ID:
3018c2ecf20Sopenharmony_ci		value *= 70800 / 5*4;
3028c2ecf20Sopenharmony_ci		value /= 0xFFFF;
3038c2ecf20Sopenharmony_ci		value *= 1000 * 5/4;
3048c2ecf20Sopenharmony_ci		break;
3058c2ecf20Sopenharmony_ci	default:
3068c2ecf20Sopenharmony_ci		value *= 6000 * 10;
3078c2ecf20Sopenharmony_ci		value /= 0xFFFF;
3088c2ecf20Sopenharmony_ci		value *= 1000 / 10;
3098c2ecf20Sopenharmony_ci		break;
3108c2ecf20Sopenharmony_ci	}
3118c2ecf20Sopenharmony_ci	*val = value;
3128c2ecf20Sopenharmony_ci	return ret;
3138c2ecf20Sopenharmony_ci}
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_cistatic int ltc294x_get_current(const struct ltc294x_info *info, int *val)
3168c2ecf20Sopenharmony_ci{
3178c2ecf20Sopenharmony_ci	int ret;
3188c2ecf20Sopenharmony_ci	u8 datar[2];
3198c2ecf20Sopenharmony_ci	s32 value;
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	ret = ltc294x_read_regs(info->client,
3228c2ecf20Sopenharmony_ci		LTC2943_REG_CURRENT_MSB, &datar[0], 2);
3238c2ecf20Sopenharmony_ci	value = (datar[0] << 8) | datar[1];
3248c2ecf20Sopenharmony_ci	value -= 0x7FFF;
3258c2ecf20Sopenharmony_ci	if (info->id == LTC2944_ID)
3268c2ecf20Sopenharmony_ci		value *= 64000;
3278c2ecf20Sopenharmony_ci	else
3288c2ecf20Sopenharmony_ci		value *= 60000;
3298c2ecf20Sopenharmony_ci	/* Value is in range -32k..+32k, r_sense is usually 10..50 mOhm,
3308c2ecf20Sopenharmony_ci	 * the formula below keeps everything in s32 range while preserving
3318c2ecf20Sopenharmony_ci	 * enough digits */
3328c2ecf20Sopenharmony_ci	*val = 1000 * (value / (info->r_sense * 0x7FFF)); /* in uA */
3338c2ecf20Sopenharmony_ci	return ret;
3348c2ecf20Sopenharmony_ci}
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_cistatic int ltc294x_get_temperature(const struct ltc294x_info *info, int *val)
3378c2ecf20Sopenharmony_ci{
3388c2ecf20Sopenharmony_ci	enum ltc294x_reg reg;
3398c2ecf20Sopenharmony_ci	int ret;
3408c2ecf20Sopenharmony_ci	u8 datar[2];
3418c2ecf20Sopenharmony_ci	u32 value;
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	if (info->id == LTC2942_ID) {
3448c2ecf20Sopenharmony_ci		reg = LTC2942_REG_TEMPERATURE_MSB;
3458c2ecf20Sopenharmony_ci		value = 6000;	/* Full-scale is 600 Kelvin */
3468c2ecf20Sopenharmony_ci	} else {
3478c2ecf20Sopenharmony_ci		reg = LTC2943_REG_TEMPERATURE_MSB;
3488c2ecf20Sopenharmony_ci		value = 5100;	/* Full-scale is 510 Kelvin */
3498c2ecf20Sopenharmony_ci	}
3508c2ecf20Sopenharmony_ci	ret = ltc294x_read_regs(info->client, reg, &datar[0], 2);
3518c2ecf20Sopenharmony_ci	value *= (datar[0] << 8) | datar[1];
3528c2ecf20Sopenharmony_ci	/* Convert to tenths of degree Celsius */
3538c2ecf20Sopenharmony_ci	*val = value / 0xFFFF - 2722;
3548c2ecf20Sopenharmony_ci	return ret;
3558c2ecf20Sopenharmony_ci}
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_cistatic int ltc294x_get_property(struct power_supply *psy,
3588c2ecf20Sopenharmony_ci				enum power_supply_property prop,
3598c2ecf20Sopenharmony_ci				union power_supply_propval *val)
3608c2ecf20Sopenharmony_ci{
3618c2ecf20Sopenharmony_ci	struct ltc294x_info *info = power_supply_get_drvdata(psy);
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	switch (prop) {
3648c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_CHARGE_FULL:
3658c2ecf20Sopenharmony_ci		return ltc294x_get_charge(info, LTC294X_REG_CHARGE_THR_HIGH_MSB,
3668c2ecf20Sopenharmony_ci						&val->intval);
3678c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_CHARGE_EMPTY:
3688c2ecf20Sopenharmony_ci		return ltc294x_get_charge(info, LTC294X_REG_CHARGE_THR_LOW_MSB,
3698c2ecf20Sopenharmony_ci						&val->intval);
3708c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_CHARGE_NOW:
3718c2ecf20Sopenharmony_ci		return ltc294x_get_charge(info, LTC294X_REG_ACC_CHARGE_MSB,
3728c2ecf20Sopenharmony_ci						&val->intval);
3738c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_CHARGE_COUNTER:
3748c2ecf20Sopenharmony_ci		return ltc294x_get_charge_counter(info, &val->intval);
3758c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
3768c2ecf20Sopenharmony_ci		return ltc294x_get_voltage(info, &val->intval);
3778c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_CURRENT_NOW:
3788c2ecf20Sopenharmony_ci		return ltc294x_get_current(info, &val->intval);
3798c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_TEMP:
3808c2ecf20Sopenharmony_ci		return ltc294x_get_temperature(info, &val->intval);
3818c2ecf20Sopenharmony_ci	default:
3828c2ecf20Sopenharmony_ci		return -EINVAL;
3838c2ecf20Sopenharmony_ci	}
3848c2ecf20Sopenharmony_ci}
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_cistatic int ltc294x_set_property(struct power_supply *psy,
3878c2ecf20Sopenharmony_ci	enum power_supply_property psp,
3888c2ecf20Sopenharmony_ci	const union power_supply_propval *val)
3898c2ecf20Sopenharmony_ci{
3908c2ecf20Sopenharmony_ci	struct ltc294x_info *info = power_supply_get_drvdata(psy);
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci	switch (psp) {
3938c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_CHARGE_FULL:
3948c2ecf20Sopenharmony_ci		return ltc294x_set_charge_thr(info,
3958c2ecf20Sopenharmony_ci			LTC294X_REG_CHARGE_THR_HIGH_MSB, val->intval);
3968c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_CHARGE_EMPTY:
3978c2ecf20Sopenharmony_ci		return ltc294x_set_charge_thr(info,
3988c2ecf20Sopenharmony_ci			LTC294X_REG_CHARGE_THR_LOW_MSB, val->intval);
3998c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_CHARGE_NOW:
4008c2ecf20Sopenharmony_ci		return ltc294x_set_charge_now(info, val->intval);
4018c2ecf20Sopenharmony_ci	default:
4028c2ecf20Sopenharmony_ci		return -EPERM;
4038c2ecf20Sopenharmony_ci	}
4048c2ecf20Sopenharmony_ci}
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_cistatic int ltc294x_property_is_writeable(
4078c2ecf20Sopenharmony_ci	struct power_supply *psy, enum power_supply_property psp)
4088c2ecf20Sopenharmony_ci{
4098c2ecf20Sopenharmony_ci	switch (psp) {
4108c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_CHARGE_FULL:
4118c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_CHARGE_EMPTY:
4128c2ecf20Sopenharmony_ci	case POWER_SUPPLY_PROP_CHARGE_NOW:
4138c2ecf20Sopenharmony_ci		return 1;
4148c2ecf20Sopenharmony_ci	default:
4158c2ecf20Sopenharmony_ci		return 0;
4168c2ecf20Sopenharmony_ci	}
4178c2ecf20Sopenharmony_ci}
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_cistatic void ltc294x_update(struct ltc294x_info *info)
4208c2ecf20Sopenharmony_ci{
4218c2ecf20Sopenharmony_ci	int charge = ltc294x_read_charge_register(info, LTC294X_REG_ACC_CHARGE_MSB);
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	if (charge != info->charge) {
4248c2ecf20Sopenharmony_ci		info->charge = charge;
4258c2ecf20Sopenharmony_ci		power_supply_changed(info->supply);
4268c2ecf20Sopenharmony_ci	}
4278c2ecf20Sopenharmony_ci}
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_cistatic void ltc294x_work(struct work_struct *work)
4308c2ecf20Sopenharmony_ci{
4318c2ecf20Sopenharmony_ci	struct ltc294x_info *info;
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	info = container_of(work, struct ltc294x_info, work.work);
4348c2ecf20Sopenharmony_ci	ltc294x_update(info);
4358c2ecf20Sopenharmony_ci	schedule_delayed_work(&info->work, LTC294X_WORK_DELAY * HZ);
4368c2ecf20Sopenharmony_ci}
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_cistatic enum power_supply_property ltc294x_properties[] = {
4398c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_CHARGE_COUNTER,
4408c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_CHARGE_FULL,
4418c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_CHARGE_EMPTY,
4428c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_CHARGE_NOW,
4438c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_VOLTAGE_NOW,
4448c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_TEMP,
4458c2ecf20Sopenharmony_ci	POWER_SUPPLY_PROP_CURRENT_NOW,
4468c2ecf20Sopenharmony_ci};
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_cistatic int ltc294x_i2c_remove(struct i2c_client *client)
4498c2ecf20Sopenharmony_ci{
4508c2ecf20Sopenharmony_ci	struct ltc294x_info *info = i2c_get_clientdata(client);
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci	cancel_delayed_work_sync(&info->work);
4538c2ecf20Sopenharmony_ci	power_supply_unregister(info->supply);
4548c2ecf20Sopenharmony_ci	return 0;
4558c2ecf20Sopenharmony_ci}
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_cistatic int ltc294x_i2c_probe(struct i2c_client *client,
4588c2ecf20Sopenharmony_ci	const struct i2c_device_id *id)
4598c2ecf20Sopenharmony_ci{
4608c2ecf20Sopenharmony_ci	struct power_supply_config psy_cfg = {};
4618c2ecf20Sopenharmony_ci	struct ltc294x_info *info;
4628c2ecf20Sopenharmony_ci	struct device_node *np;
4638c2ecf20Sopenharmony_ci	int ret;
4648c2ecf20Sopenharmony_ci	u32 prescaler_exp;
4658c2ecf20Sopenharmony_ci	s32 r_sense;
4668c2ecf20Sopenharmony_ci	u8 status;
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci	info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL);
4698c2ecf20Sopenharmony_ci	if (info == NULL)
4708c2ecf20Sopenharmony_ci		return -ENOMEM;
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	i2c_set_clientdata(client, info);
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci	np = of_node_get(client->dev.of_node);
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci	info->id = (enum ltc294x_id) (uintptr_t) of_device_get_match_data(
4778c2ecf20Sopenharmony_ci							&client->dev);
4788c2ecf20Sopenharmony_ci	info->supply_desc.name = np->name;
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci	/* r_sense can be negative, when sense+ is connected to the battery
4818c2ecf20Sopenharmony_ci	 * instead of the sense-. This results in reversed measurements. */
4828c2ecf20Sopenharmony_ci	ret = of_property_read_u32(np, "lltc,resistor-sense", &r_sense);
4838c2ecf20Sopenharmony_ci	if (ret < 0) {
4848c2ecf20Sopenharmony_ci		dev_err(&client->dev,
4858c2ecf20Sopenharmony_ci			"Could not find lltc,resistor-sense in devicetree\n");
4868c2ecf20Sopenharmony_ci		return ret;
4878c2ecf20Sopenharmony_ci	}
4888c2ecf20Sopenharmony_ci	info->r_sense = r_sense;
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci	ret = of_property_read_u32(np, "lltc,prescaler-exponent",
4918c2ecf20Sopenharmony_ci		&prescaler_exp);
4928c2ecf20Sopenharmony_ci	if (ret < 0) {
4938c2ecf20Sopenharmony_ci		dev_warn(&client->dev,
4948c2ecf20Sopenharmony_ci			"lltc,prescaler-exponent not in devicetree\n");
4958c2ecf20Sopenharmony_ci		prescaler_exp = LTC2941_MAX_PRESCALER_EXP;
4968c2ecf20Sopenharmony_ci	}
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci	if (info->id == LTC2943_ID) {
4998c2ecf20Sopenharmony_ci		if (prescaler_exp > LTC2943_MAX_PRESCALER_EXP)
5008c2ecf20Sopenharmony_ci			prescaler_exp = LTC2943_MAX_PRESCALER_EXP;
5018c2ecf20Sopenharmony_ci		info->Qlsb = ((340 * 50000) / r_sense) /
5028c2ecf20Sopenharmony_ci				(4096 / (1 << (2*prescaler_exp)));
5038c2ecf20Sopenharmony_ci	} else {
5048c2ecf20Sopenharmony_ci		if (prescaler_exp > LTC2941_MAX_PRESCALER_EXP)
5058c2ecf20Sopenharmony_ci			prescaler_exp = LTC2941_MAX_PRESCALER_EXP;
5068c2ecf20Sopenharmony_ci		info->Qlsb = ((85 * 50000) / r_sense) /
5078c2ecf20Sopenharmony_ci				(128 / (1 << prescaler_exp));
5088c2ecf20Sopenharmony_ci	}
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci	/* Read status register to check for LTC2942 */
5118c2ecf20Sopenharmony_ci	if (info->id == LTC2941_ID || info->id == LTC2942_ID) {
5128c2ecf20Sopenharmony_ci		ret = ltc294x_read_regs(client, LTC294X_REG_STATUS, &status, 1);
5138c2ecf20Sopenharmony_ci		if (ret < 0) {
5148c2ecf20Sopenharmony_ci			dev_err(&client->dev,
5158c2ecf20Sopenharmony_ci				"Could not read status register\n");
5168c2ecf20Sopenharmony_ci			return ret;
5178c2ecf20Sopenharmony_ci		}
5188c2ecf20Sopenharmony_ci		if (status & LTC2941_REG_STATUS_CHIP_ID)
5198c2ecf20Sopenharmony_ci			info->id = LTC2941_ID;
5208c2ecf20Sopenharmony_ci		else
5218c2ecf20Sopenharmony_ci			info->id = LTC2942_ID;
5228c2ecf20Sopenharmony_ci	}
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci	info->client = client;
5258c2ecf20Sopenharmony_ci	info->supply_desc.type = POWER_SUPPLY_TYPE_BATTERY;
5268c2ecf20Sopenharmony_ci	info->supply_desc.properties = ltc294x_properties;
5278c2ecf20Sopenharmony_ci	switch (info->id) {
5288c2ecf20Sopenharmony_ci	case LTC2944_ID:
5298c2ecf20Sopenharmony_ci	case LTC2943_ID:
5308c2ecf20Sopenharmony_ci		info->supply_desc.num_properties =
5318c2ecf20Sopenharmony_ci			ARRAY_SIZE(ltc294x_properties);
5328c2ecf20Sopenharmony_ci		break;
5338c2ecf20Sopenharmony_ci	case LTC2942_ID:
5348c2ecf20Sopenharmony_ci		info->supply_desc.num_properties =
5358c2ecf20Sopenharmony_ci			ARRAY_SIZE(ltc294x_properties) - 1;
5368c2ecf20Sopenharmony_ci		break;
5378c2ecf20Sopenharmony_ci	case LTC2941_ID:
5388c2ecf20Sopenharmony_ci	default:
5398c2ecf20Sopenharmony_ci		info->supply_desc.num_properties =
5408c2ecf20Sopenharmony_ci			ARRAY_SIZE(ltc294x_properties) - 3;
5418c2ecf20Sopenharmony_ci		break;
5428c2ecf20Sopenharmony_ci	}
5438c2ecf20Sopenharmony_ci	info->supply_desc.get_property = ltc294x_get_property;
5448c2ecf20Sopenharmony_ci	info->supply_desc.set_property = ltc294x_set_property;
5458c2ecf20Sopenharmony_ci	info->supply_desc.property_is_writeable = ltc294x_property_is_writeable;
5468c2ecf20Sopenharmony_ci	info->supply_desc.external_power_changed	= NULL;
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci	psy_cfg.drv_data = info;
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	INIT_DELAYED_WORK(&info->work, ltc294x_work);
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	ret = ltc294x_reset(info, prescaler_exp);
5538c2ecf20Sopenharmony_ci	if (ret < 0) {
5548c2ecf20Sopenharmony_ci		dev_err(&client->dev, "Communication with chip failed\n");
5558c2ecf20Sopenharmony_ci		return ret;
5568c2ecf20Sopenharmony_ci	}
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_ci	info->supply = power_supply_register(&client->dev, &info->supply_desc,
5598c2ecf20Sopenharmony_ci					     &psy_cfg);
5608c2ecf20Sopenharmony_ci	if (IS_ERR(info->supply)) {
5618c2ecf20Sopenharmony_ci		dev_err(&client->dev, "failed to register ltc2941\n");
5628c2ecf20Sopenharmony_ci		return PTR_ERR(info->supply);
5638c2ecf20Sopenharmony_ci	} else {
5648c2ecf20Sopenharmony_ci		schedule_delayed_work(&info->work, LTC294X_WORK_DELAY * HZ);
5658c2ecf20Sopenharmony_ci	}
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci	return 0;
5688c2ecf20Sopenharmony_ci}
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_cistatic void ltc294x_i2c_shutdown(struct i2c_client *client)
5718c2ecf20Sopenharmony_ci{
5728c2ecf20Sopenharmony_ci	struct ltc294x_info *info = i2c_get_clientdata(client);
5738c2ecf20Sopenharmony_ci	int ret;
5748c2ecf20Sopenharmony_ci	u8 value;
5758c2ecf20Sopenharmony_ci	u8 control;
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci	/* The LTC2941 does not need any special handling */
5788c2ecf20Sopenharmony_ci	if (info->id == LTC2941_ID)
5798c2ecf20Sopenharmony_ci		return;
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci	/* Read control register */
5828c2ecf20Sopenharmony_ci	ret = ltc294x_read_regs(info->client, LTC294X_REG_CONTROL, &value, 1);
5838c2ecf20Sopenharmony_ci	if (ret < 0)
5848c2ecf20Sopenharmony_ci		return;
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci	/* Disable continuous ADC conversion as this drains the battery */
5878c2ecf20Sopenharmony_ci	control = LTC294X_REG_CONTROL_ADC_DISABLE(value);
5888c2ecf20Sopenharmony_ci	if (control != value)
5898c2ecf20Sopenharmony_ci		ltc294x_write_regs(info->client, LTC294X_REG_CONTROL,
5908c2ecf20Sopenharmony_ci			&control, 1);
5918c2ecf20Sopenharmony_ci}
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_cistatic int ltc294x_suspend(struct device *dev)
5968c2ecf20Sopenharmony_ci{
5978c2ecf20Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
5988c2ecf20Sopenharmony_ci	struct ltc294x_info *info = i2c_get_clientdata(client);
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci	cancel_delayed_work(&info->work);
6018c2ecf20Sopenharmony_ci	return 0;
6028c2ecf20Sopenharmony_ci}
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_cistatic int ltc294x_resume(struct device *dev)
6058c2ecf20Sopenharmony_ci{
6068c2ecf20Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
6078c2ecf20Sopenharmony_ci	struct ltc294x_info *info = i2c_get_clientdata(client);
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci	schedule_delayed_work(&info->work, LTC294X_WORK_DELAY * HZ);
6108c2ecf20Sopenharmony_ci	return 0;
6118c2ecf20Sopenharmony_ci}
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(ltc294x_pm_ops, ltc294x_suspend, ltc294x_resume);
6148c2ecf20Sopenharmony_ci#define LTC294X_PM_OPS (&ltc294x_pm_ops)
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci#else
6178c2ecf20Sopenharmony_ci#define LTC294X_PM_OPS NULL
6188c2ecf20Sopenharmony_ci#endif /* CONFIG_PM_SLEEP */
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_cistatic const struct i2c_device_id ltc294x_i2c_id[] = {
6228c2ecf20Sopenharmony_ci	{ "ltc2941", LTC2941_ID, },
6238c2ecf20Sopenharmony_ci	{ "ltc2942", LTC2942_ID, },
6248c2ecf20Sopenharmony_ci	{ "ltc2943", LTC2943_ID, },
6258c2ecf20Sopenharmony_ci	{ "ltc2944", LTC2944_ID, },
6268c2ecf20Sopenharmony_ci	{ },
6278c2ecf20Sopenharmony_ci};
6288c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, ltc294x_i2c_id);
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_cistatic const struct of_device_id ltc294x_i2c_of_match[] = {
6318c2ecf20Sopenharmony_ci	{
6328c2ecf20Sopenharmony_ci		.compatible = "lltc,ltc2941",
6338c2ecf20Sopenharmony_ci		.data = (void *)LTC2941_ID,
6348c2ecf20Sopenharmony_ci	},
6358c2ecf20Sopenharmony_ci	{
6368c2ecf20Sopenharmony_ci		.compatible = "lltc,ltc2942",
6378c2ecf20Sopenharmony_ci		.data = (void *)LTC2942_ID,
6388c2ecf20Sopenharmony_ci	},
6398c2ecf20Sopenharmony_ci	{
6408c2ecf20Sopenharmony_ci		.compatible = "lltc,ltc2943",
6418c2ecf20Sopenharmony_ci		.data = (void *)LTC2943_ID,
6428c2ecf20Sopenharmony_ci	},
6438c2ecf20Sopenharmony_ci	{
6448c2ecf20Sopenharmony_ci		.compatible = "lltc,ltc2944",
6458c2ecf20Sopenharmony_ci		.data = (void *)LTC2944_ID,
6468c2ecf20Sopenharmony_ci	},
6478c2ecf20Sopenharmony_ci	{ },
6488c2ecf20Sopenharmony_ci};
6498c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, ltc294x_i2c_of_match);
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_cistatic struct i2c_driver ltc294x_driver = {
6528c2ecf20Sopenharmony_ci	.driver = {
6538c2ecf20Sopenharmony_ci		.name	= "LTC2941",
6548c2ecf20Sopenharmony_ci		.of_match_table = ltc294x_i2c_of_match,
6558c2ecf20Sopenharmony_ci		.pm	= LTC294X_PM_OPS,
6568c2ecf20Sopenharmony_ci	},
6578c2ecf20Sopenharmony_ci	.probe		= ltc294x_i2c_probe,
6588c2ecf20Sopenharmony_ci	.remove		= ltc294x_i2c_remove,
6598c2ecf20Sopenharmony_ci	.shutdown	= ltc294x_i2c_shutdown,
6608c2ecf20Sopenharmony_ci	.id_table	= ltc294x_i2c_id,
6618c2ecf20Sopenharmony_ci};
6628c2ecf20Sopenharmony_cimodule_i2c_driver(ltc294x_driver);
6638c2ecf20Sopenharmony_ci
6648c2ecf20Sopenharmony_ciMODULE_AUTHOR("Auryn Verwegen, Topic Embedded Systems");
6658c2ecf20Sopenharmony_ciMODULE_AUTHOR("Mike Looijmans, Topic Embedded Products");
6668c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("LTC2941/LTC2942/LTC2943/LTC2944 Battery Gas Gauge IC driver");
6678c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
668