brintos

brintos / linux-shallow public Read only

0
0
Text · 23.0 KiB · 2e4bc74 Raw
931 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 *  Driver for Analog Devices (Linear Technology) LTC4162-L charger IC.4 *  Copyright (C) 2020, Topic Embedded Products5 */6 7#include <linux/module.h>8#include <linux/delay.h>9#include <linux/of.h>10#include <linux/pm_runtime.h>11#include <linux/power_supply.h>12#include <linux/i2c.h>13#include <linux/regmap.h>14 15/* Registers (names based on what datasheet uses) */16#define LTC4162L_EN_LIMIT_ALERTS_REG		0x0D17#define LTC4162L_EN_CHARGER_STATE_ALERTS_REG	0x0E18#define LTC4162L_EN_CHARGE_STATUS_ALERTS_REG	0x0F19#define LTC4162L_CONFIG_BITS_REG		0x1420#define LTC4162L_IIN_LIMIT_TARGET		0x1521#define LTC4162L_ARM_SHIP_MODE			0x1922#define LTC4162L_CHARGE_CURRENT_SETTING		0X1A23#define LTC4162L_VCHARGE_SETTING		0X1B24#define LTC4162L_C_OVER_X_THRESHOLD		0x1C25#define LTC4162L_MAX_CV_TIME			0X1D26#define LTC4162L_MAX_CHARGE_TIME		0X1E27#define LTC4162L_CHARGER_CONFIG_BITS		0x2928#define LTC4162L_CHARGER_STATE			0x3429#define LTC4162L_CHARGE_STATUS			0x3530#define LTC4162L_LIMIT_ALERTS_REG		0x3631#define LTC4162L_CHARGER_STATE_ALERTS_REG	0x3732#define LTC4162L_CHARGE_STATUS_ALERTS_REG	0x3833#define LTC4162L_SYSTEM_STATUS_REG		0x3934#define LTC4162L_VBAT				0x3A35#define LTC4162L_VIN				0x3B36#define LTC4162L_VOUT				0x3C37#define LTC4162L_IBAT				0x3D38#define LTC4162L_IIN				0x3E39#define LTC4162L_DIE_TEMPERATURE		0x3F40#define LTC4162L_THERMISTOR_VOLTAGE		0x4041#define LTC4162L_BSR				0x4142#define LTC4162L_JEITA_REGION			0x4243#define LTC4162L_CHEM_CELLS_REG			0x4344#define LTC4162L_ICHARGE_DAC			0x4445#define LTC4162L_VCHARGE_DAC			0x4546#define LTC4162L_IIN_LIMIT_DAC			0x4647#define LTC4162L_VBAT_FILT			0x4748#define LTC4162L_INPUT_UNDERVOLTAGE_DAC		0x4B49 50/* Enumeration as in datasheet. Individual bits are mutually exclusive. */51enum ltc4162l_state {52	battery_detection = 2048,53	charger_suspended = 256,54	precharge = 128,   /* trickle on low bat voltage */55	cc_cv_charge = 64, /* normal charge */56	ntc_pause = 32,57	timer_term = 16,58	c_over_x_term = 8, /* battery is full */59	max_charge_time_fault = 4,60	bat_missing_fault = 2,61	bat_short_fault = 162};63 64/* Individual bits are mutually exclusive. Only active in charging states.*/65enum ltc4162l_charge_status {66	ilim_reg_active = 32,67	thermal_reg_active = 16,68	vin_uvcl_active = 8,69	iin_limit_active = 4,70	constant_current = 2,71	constant_voltage = 1,72	charger_off = 073};74 75/* Magic number to write to ARM_SHIP_MODE register */76#define LTC4162L_ARM_SHIP_MODE_MAGIC 2132577 78struct ltc4162l_info {79	struct i2c_client	*client;80	struct regmap		*regmap;81	struct power_supply	*charger;82	u32 rsnsb;	/* Series resistor that sets charge current, microOhm */83	u32 rsnsi;	/* Series resistor to measure input current, microOhm */84	u8 cell_count;	/* Number of connected cells, 0 while unknown */85};86 87static u8 ltc4162l_get_cell_count(struct ltc4162l_info *info)88{89	int ret;90	unsigned int val;91 92	/* Once read successfully */93	if (info->cell_count)94		return info->cell_count;95 96	ret = regmap_read(info->regmap, LTC4162L_CHEM_CELLS_REG, &val);97	if (ret)98		return 0;99 100	/* Lower 4 bits is the cell count, or 0 if the chip doesn't know yet */101	val &= 0x0f;102	if (!val)103		return 0;104 105	/* Once determined, keep the value */106	info->cell_count = val;107 108	return val;109};110 111/* Convert enum value to POWER_SUPPLY_STATUS value */112static int ltc4162l_state_decode(enum ltc4162l_state value)113{114	switch (value) {115	case precharge:116	case cc_cv_charge:117		return POWER_SUPPLY_STATUS_CHARGING;118	case c_over_x_term:119		return POWER_SUPPLY_STATUS_FULL;120	case bat_missing_fault:121	case bat_short_fault:122		return POWER_SUPPLY_STATUS_UNKNOWN;123	default:124		return POWER_SUPPLY_STATUS_NOT_CHARGING;125	}126};127 128static int ltc4162l_get_status(struct ltc4162l_info *info,129			       union power_supply_propval *val)130{131	unsigned int regval;132	int ret;133 134	ret = regmap_read(info->regmap, LTC4162L_CHARGER_STATE, &regval);135	if (ret) {136		dev_err(&info->client->dev, "Failed to read CHARGER_STATE\n");137		return ret;138	}139 140	val->intval = ltc4162l_state_decode(regval);141 142	return 0;143}144 145static int ltc4162l_charge_status_decode(enum ltc4162l_charge_status value)146{147	if (!value)148		return POWER_SUPPLY_CHARGE_TYPE_NONE;149 150	/* constant voltage/current and input_current limit are "fast" modes */151	if (value <= iin_limit_active)152		return POWER_SUPPLY_CHARGE_TYPE_FAST;153 154	/* Anything that's not fast we'll return as trickle */155	return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;156}157 158static int ltc4162l_get_charge_type(struct ltc4162l_info *info,159				    union power_supply_propval *val)160{161	unsigned int regval;162	int ret;163 164	ret = regmap_read(info->regmap, LTC4162L_CHARGE_STATUS, &regval);165	if (ret)166		return ret;167 168	val->intval = ltc4162l_charge_status_decode(regval);169 170	return 0;171}172 173static int ltc4162l_state_to_health(enum ltc4162l_state value)174{175	switch (value) {176	case ntc_pause:177		return POWER_SUPPLY_HEALTH_OVERHEAT;178	case timer_term:179		return POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE;180	case max_charge_time_fault:181		return POWER_SUPPLY_HEALTH_WATCHDOG_TIMER_EXPIRE;182	case bat_missing_fault:183		return POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;184	case bat_short_fault:185		return POWER_SUPPLY_HEALTH_DEAD;186	default:187		return POWER_SUPPLY_HEALTH_GOOD;188	}189}190 191static int ltc4162l_get_health(struct ltc4162l_info *info,192			       union power_supply_propval *val)193{194	unsigned int regval;195	int ret;196 197	ret = regmap_read(info->regmap, LTC4162L_CHARGER_STATE, &regval);198	if (ret)199		return ret;200 201	val->intval = ltc4162l_state_to_health(regval);202 203	return 0;204}205 206static int ltc4162l_get_online(struct ltc4162l_info *info,207			       union power_supply_propval *val)208{209	unsigned int regval;210	int ret;211 212	ret = regmap_read(info->regmap, LTC4162L_SYSTEM_STATUS_REG, &regval);213	if (ret)214		return ret;215 216	/* BIT(2) indicates if input voltage is sufficient to charge */217	val->intval = !!(regval & BIT(2));218 219	return 0;220}221 222static int ltc4162l_get_vbat(struct ltc4162l_info *info,223				  unsigned int reg,224				  union power_supply_propval *val)225{226	unsigned int regval;227	int ret;228 229	ret = regmap_read(info->regmap, reg, &regval);230	if (ret)231		return ret;232 233	/* cell_count × 192.4μV/LSB */234	regval *= 1924;235	regval *= ltc4162l_get_cell_count(info);236	regval /= 10;237	val->intval = regval;238 239	return 0;240}241 242static int ltc4162l_get_ibat(struct ltc4162l_info *info,243			     union power_supply_propval *val)244{245	unsigned int regval;246	int ret;247 248	ret = regmap_read(info->regmap, LTC4162L_IBAT, &regval);249	if (ret)250		return ret;251 252	/* Signed 16-bit number, 1.466μV / RSNSB amperes/LSB. */253	ret = (s16)(regval & 0xFFFF);254	val->intval = 100 * mult_frac(ret, 14660, (int)info->rsnsb);255 256	return 0;257}258 259 260static int ltc4162l_get_input_voltage(struct ltc4162l_info *info,261				      union power_supply_propval *val)262{263	unsigned int regval;264	int ret;265 266	ret = regmap_read(info->regmap, LTC4162L_VIN, &regval);267	if (ret)268		return ret;269 270	/* 1.649mV/LSB */271	val->intval =  regval * 1694;272 273	return 0;274}275 276static int ltc4162l_get_input_current(struct ltc4162l_info *info,277				      union power_supply_propval *val)278{279	unsigned int regval;280	int ret;281 282	ret = regmap_read(info->regmap, LTC4162L_IIN, &regval);283	if (ret)284		return ret;285 286	/* Signed 16-bit number, 1.466μV / RSNSI amperes/LSB. */287	ret = (s16)(regval & 0xFFFF);288	ret *= 14660;289	ret /= info->rsnsi;290	ret *= 100;291 292	val->intval = ret;293 294	return 0;295}296 297static int ltc4162l_get_icharge(struct ltc4162l_info *info,298				unsigned int reg,299				union power_supply_propval *val)300{301	unsigned int regval;302	int ret;303 304	ret = regmap_read(info->regmap, reg, &regval);305	if (ret)306		return ret;307 308	regval &= BIT(6) - 1; /* Only the lower 5 bits */309 310	/* The charge current servo level: (icharge_dac + 1) × 1mV/RSNSB */311	++regval;312	val->intval = 10000u * mult_frac(regval, 100000u, info->rsnsb);313 314	return 0;315}316 317static int ltc4162l_set_icharge(struct ltc4162l_info *info,318				unsigned int reg,319				unsigned int value)320{321	value = mult_frac(value, info->rsnsb, 100000u);322	value /= 10000u;323 324	/* Round to lowest possible */325	if (value)326		--value;327 328	if (value > 31)329		return -EINVAL;330 331	return regmap_write(info->regmap, reg, value);332}333 334 335static int ltc4162l_get_vcharge(struct ltc4162l_info *info,336				unsigned int reg,337				union power_supply_propval *val)338{339	unsigned int regval;340	int ret;341	u32 voltage;342 343	ret = regmap_read(info->regmap, reg, &regval);344	if (ret)345		return ret;346 347	regval &= BIT(6) - 1; /* Only the lower 5 bits */348 349	/*350	 * charge voltage setting can be computed from351	 * cell_count × (vcharge_setting × 12.5mV + 3.8125V)352	 * where vcharge_setting ranges from 0 to 31 (4.2V max).353	 */354	voltage = 3812500 + (regval * 12500);355	voltage *= ltc4162l_get_cell_count(info);356	val->intval = voltage;357 358	return 0;359}360 361static int ltc4162l_set_vcharge(struct ltc4162l_info *info,362				unsigned int reg,363				unsigned int value)364{365	u8 cell_count = ltc4162l_get_cell_count(info);366 367	if (!cell_count)368		return -EBUSY; /* Not available yet, try again later */369 370	value /= cell_count;371 372	if (value < 3812500)373		return -EINVAL;374 375	value -= 3812500;376	value /= 12500;377 378	if (value > 31)379		return -EINVAL;380 381	return regmap_write(info->regmap, reg, value);382}383 384static int ltc4162l_get_iin_limit_dac(struct ltc4162l_info *info,385				     union power_supply_propval *val)386{387	unsigned int regval;388	int ret;389 390	ret = regmap_read(info->regmap, LTC4162L_IIN_LIMIT_DAC, &regval);391	if (ret)392		return ret;393 394	regval &= BIT(6) - 1; /* Only 6 bits */395 396	/* (iin_limit_dac + 1) × 500μV / RSNSI */397	++regval;398	regval *= 5000000u;399	regval /= info->rsnsi;400	val->intval = 100u * regval;401 402	return 0;403}404 405static int ltc4162l_set_iin_limit(struct ltc4162l_info *info,406				  unsigned int value)407{408	unsigned int regval;409 410	regval = mult_frac(value, info->rsnsi, 50000u);411	regval /= 10000u;412	if (regval)413		--regval;414	if (regval > 63)415		regval = 63;416 417	return regmap_write(info->regmap, LTC4162L_IIN_LIMIT_TARGET, regval);418}419 420static int ltc4162l_get_die_temp(struct ltc4162l_info *info,421				 union power_supply_propval *val)422{423	unsigned int regval;424	int ret;425 426	ret = regmap_read(info->regmap, LTC4162L_DIE_TEMPERATURE, &regval);427	if (ret)428		return ret;429 430	/* die_temp × 0.0215°C/LSB - 264.4°C */431	ret = (s16)(regval & 0xFFFF);432	ret *= 215;433	ret /= 100; /* Centidegrees scale */434	ret -= 26440;435	val->intval = ret;436 437	return 0;438}439 440static int ltc4162l_get_term_current(struct ltc4162l_info *info,441				     union power_supply_propval *val)442{443	unsigned int regval;444	int ret;445 446	ret = regmap_read(info->regmap, LTC4162L_CHARGER_CONFIG_BITS, &regval);447	if (ret)448		return ret;449 450	/* Check if C_OVER_X_THRESHOLD is enabled */451	if (!(regval & BIT(2))) {452		val->intval = 0;453		return 0;454	}455 456	ret = regmap_read(info->regmap, LTC4162L_C_OVER_X_THRESHOLD, &regval);457	if (ret)458		return ret;459 460	/* 1.466μV / RSNSB amperes/LSB */461	regval *= 14660u;462	regval /= info->rsnsb;463	val->intval = 100 * regval;464 465	return 0;466}467 468static int ltc4162l_set_term_current(struct ltc4162l_info *info,469				     unsigned int value)470{471	int ret;472	unsigned int regval;473 474	if (!value) {475		/* Disable en_c_over_x_term when set to zero */476		return regmap_update_bits(info->regmap,477					  LTC4162L_CHARGER_CONFIG_BITS,478					  BIT(2), 0);479	}480 481	regval = mult_frac(value, info->rsnsb, 14660u);482	regval /= 100u;483 484	ret =  regmap_write(info->regmap, LTC4162L_C_OVER_X_THRESHOLD, regval);485	if (ret)486		return ret;487 488	/* Set en_c_over_x_term after changing the threshold value */489	return regmap_update_bits(info->regmap, LTC4162L_CHARGER_CONFIG_BITS,490				  BIT(2), BIT(2));491}492 493/* Custom properties */494static const char * const ltc4162l_charge_status_name[] = {495	"ilim_reg_active", /* 32 */496	"thermal_reg_active",497	"vin_uvcl_active",498	"iin_limit_active",499	"constant_current",500	"constant_voltage",501	"charger_off" /* 0 */502};503 504static ssize_t charge_status_show(struct device *dev,505				  struct device_attribute *attr, char *buf)506{507	struct power_supply *psy = to_power_supply(dev);508	struct ltc4162l_info *info = power_supply_get_drvdata(psy);509	const char *result = ltc4162l_charge_status_name[510				ARRAY_SIZE(ltc4162l_charge_status_name) - 1];511	unsigned int regval;512	unsigned int mask;513	unsigned int index;514	int ret;515 516	ret = regmap_read(info->regmap, LTC4162L_CHARGE_STATUS, &regval);517	if (ret)518		return ret;519 520	/* Only one bit is set according to datasheet, let's be safe here */521	for (mask = 32, index = 0; mask != 0; mask >>= 1, ++index) {522		if (regval & mask) {523			result = ltc4162l_charge_status_name[index];524			break;525		}526	}527 528	return sysfs_emit(buf, "%s\n", result);529}530static DEVICE_ATTR_RO(charge_status);531 532static ssize_t vbat_show(struct device *dev,533				  struct device_attribute *attr, char *buf)534{535	struct power_supply *psy = to_power_supply(dev);536	struct ltc4162l_info *info = power_supply_get_drvdata(psy);537	union power_supply_propval val;538	int ret;539 540	ret = ltc4162l_get_vbat(info, LTC4162L_VBAT, &val);541	if (ret)542		return ret;543 544	return sysfs_emit(buf, "%d\n", val.intval);545}546static DEVICE_ATTR_RO(vbat);547 548static ssize_t vbat_avg_show(struct device *dev,549				  struct device_attribute *attr, char *buf)550{551	struct power_supply *psy = to_power_supply(dev);552	struct ltc4162l_info *info = power_supply_get_drvdata(psy);553	union power_supply_propval val;554	int ret;555 556	ret = ltc4162l_get_vbat(info, LTC4162L_VBAT_FILT, &val);557	if (ret)558		return ret;559 560	return sysfs_emit(buf, "%d\n", val.intval);561}562static DEVICE_ATTR_RO(vbat_avg);563 564static ssize_t ibat_show(struct device *dev,565				  struct device_attribute *attr, char *buf)566{567	struct power_supply *psy = to_power_supply(dev);568	struct ltc4162l_info *info = power_supply_get_drvdata(psy);569	union power_supply_propval val;570	int ret;571 572	ret = ltc4162l_get_ibat(info, &val);573	if (ret)574		return ret;575 576	return sysfs_emit(buf, "%d\n", val.intval);577}578static DEVICE_ATTR_RO(ibat);579 580static ssize_t force_telemetry_show(struct device *dev,581				    struct device_attribute *attr, char *buf)582{583	struct power_supply *psy = to_power_supply(dev);584	struct ltc4162l_info *info = power_supply_get_drvdata(psy);585	unsigned int regval;586	int ret;587 588	ret = regmap_read(info->regmap, LTC4162L_CONFIG_BITS_REG, &regval);589	if (ret)590		return ret;591 592	return sysfs_emit(buf, "%u\n", regval & BIT(2) ? 1 : 0);593}594 595static ssize_t force_telemetry_store(struct device *dev,596	struct device_attribute *attr,597	const char *buf,598	size_t count)599{600	struct power_supply *psy = to_power_supply(dev);601	struct ltc4162l_info *info = power_supply_get_drvdata(psy);602	int ret;603	unsigned int value;604 605	ret = kstrtouint(buf, 0, &value);606	if (ret < 0)607		return ret;608 609	ret = regmap_update_bits(info->regmap, LTC4162L_CONFIG_BITS_REG,610				 BIT(2), value ? BIT(2) : 0);611	if (ret < 0)612		return ret;613 614	return count;615}616 617static DEVICE_ATTR_RW(force_telemetry);618 619static ssize_t arm_ship_mode_show(struct device *dev,620				    struct device_attribute *attr, char *buf)621{622	struct power_supply *psy = to_power_supply(dev);623	struct ltc4162l_info *info = power_supply_get_drvdata(psy);624	unsigned int regval;625	int ret;626 627	ret = regmap_read(info->regmap, LTC4162L_ARM_SHIP_MODE, &regval);628	if (ret)629		return ret;630 631	return sysfs_emit(buf, "%u\n",632		regval == LTC4162L_ARM_SHIP_MODE_MAGIC ? 1 : 0);633}634 635static ssize_t arm_ship_mode_store(struct device *dev,636	struct device_attribute *attr,637	const char *buf,638	size_t count)639{640	struct power_supply *psy = to_power_supply(dev);641	struct ltc4162l_info *info = power_supply_get_drvdata(psy);642	int ret;643	unsigned int value;644 645	ret = kstrtouint(buf, 0, &value);646	if (ret < 0)647		return ret;648 649	ret = regmap_write(info->regmap, LTC4162L_ARM_SHIP_MODE,650				value ? LTC4162L_ARM_SHIP_MODE_MAGIC : 0);651	if (ret < 0)652		return ret;653 654	return count;655}656 657static DEVICE_ATTR_RW(arm_ship_mode);658 659static struct attribute *ltc4162l_sysfs_entries[] = {660	&dev_attr_charge_status.attr,661	&dev_attr_ibat.attr,662	&dev_attr_vbat.attr,663	&dev_attr_vbat_avg.attr,664	&dev_attr_force_telemetry.attr,665	&dev_attr_arm_ship_mode.attr,666	NULL,667};668 669static const struct attribute_group ltc4162l_attr_group = {670	.name	= NULL,	/* put in device directory */671	.attrs	= ltc4162l_sysfs_entries,672};673 674static const struct attribute_group *ltc4162l_attr_groups[] = {675	&ltc4162l_attr_group,676	NULL,677};678 679static int ltc4162l_get_property(struct power_supply *psy,680				 enum power_supply_property psp,681				 union power_supply_propval *val)682{683	struct ltc4162l_info *info = power_supply_get_drvdata(psy);684 685	switch (psp) {686	case POWER_SUPPLY_PROP_STATUS:687		return ltc4162l_get_status(info, val);688	case POWER_SUPPLY_PROP_CHARGE_TYPE:689		return ltc4162l_get_charge_type(info, val);690	case POWER_SUPPLY_PROP_HEALTH:691		return ltc4162l_get_health(info, val);692	case POWER_SUPPLY_PROP_ONLINE:693		return ltc4162l_get_online(info, val);694	case POWER_SUPPLY_PROP_VOLTAGE_NOW:695		return ltc4162l_get_input_voltage(info, val);696	case POWER_SUPPLY_PROP_CURRENT_NOW:697		return ltc4162l_get_input_current(info, val);698	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:699		return ltc4162l_get_icharge(info,700				LTC4162L_ICHARGE_DAC, val);701	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:702		return ltc4162l_get_icharge(info,703				LTC4162L_CHARGE_CURRENT_SETTING, val);704	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:705		return ltc4162l_get_vcharge(info,706				LTC4162L_VCHARGE_DAC, val);707	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:708		return ltc4162l_get_vcharge(info,709				LTC4162L_VCHARGE_SETTING, val);710	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:711		return ltc4162l_get_iin_limit_dac(info, val);712	case POWER_SUPPLY_PROP_TEMP:713		return ltc4162l_get_die_temp(info, val);714	case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:715		return ltc4162l_get_term_current(info, val);716	default:717		return -EINVAL;718	}719}720 721static int ltc4162l_set_property(struct power_supply *psy,722					 enum power_supply_property psp,723					 const union power_supply_propval *val)724{725	struct ltc4162l_info *info = power_supply_get_drvdata(psy);726 727	switch (psp) {728	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:729		return ltc4162l_set_icharge(info,730				LTC4162L_CHARGE_CURRENT_SETTING, val->intval);731	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:732		return ltc4162l_set_vcharge(info,733				LTC4162L_VCHARGE_SETTING, val->intval);734	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:735		return ltc4162l_set_iin_limit(info, val->intval);736	case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:737		return ltc4162l_set_term_current(info, val->intval);738	default:739		return -EINVAL;740	}741}742 743static int ltc4162l_property_is_writeable(struct power_supply *psy,744						enum power_supply_property psp)745{746	switch (psp) {747	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:748	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:749	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:750	case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:751		return 1;752	default:753		return 0;754	}755}756 757/* Charger power supply property routines */758static enum power_supply_property ltc4162l_properties[] = {759	POWER_SUPPLY_PROP_STATUS,760	POWER_SUPPLY_PROP_CHARGE_TYPE,761	POWER_SUPPLY_PROP_HEALTH,762	POWER_SUPPLY_PROP_ONLINE,763	POWER_SUPPLY_PROP_VOLTAGE_NOW,764	POWER_SUPPLY_PROP_CURRENT_NOW,765	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,766	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,767	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,768	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,769	POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,770	POWER_SUPPLY_PROP_TEMP,771	POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT,772};773 774static const struct power_supply_desc ltc4162l_desc = {775	.name		= "ltc4162-l",776	.type		= POWER_SUPPLY_TYPE_MAINS,777	.properties	= ltc4162l_properties,778	.num_properties	= ARRAY_SIZE(ltc4162l_properties),779	.get_property	= ltc4162l_get_property,780	.set_property	= ltc4162l_set_property,781	.property_is_writeable = ltc4162l_property_is_writeable,782};783 784static bool ltc4162l_is_writeable_reg(struct device *dev, unsigned int reg)785{786	/* all registers up to this one are writeable */787	if (reg <= LTC4162L_CHARGER_CONFIG_BITS)788		return true;789 790	/* The ALERTS registers can be written to clear alerts */791	if (reg >= LTC4162L_LIMIT_ALERTS_REG &&792	    reg <= LTC4162L_CHARGE_STATUS_ALERTS_REG)793		return true;794 795	return false;796}797 798static bool ltc4162l_is_volatile_reg(struct device *dev, unsigned int reg)799{800	/* all registers after this one are read-only status registers */801	return reg > LTC4162L_CHARGER_CONFIG_BITS;802}803 804static const struct regmap_config ltc4162l_regmap_config = {805	.reg_bits	= 8,806	.val_bits	= 16,807	.val_format_endian = REGMAP_ENDIAN_LITTLE,808	.writeable_reg	= ltc4162l_is_writeable_reg,809	.volatile_reg	= ltc4162l_is_volatile_reg,810	.max_register	= LTC4162L_INPUT_UNDERVOLTAGE_DAC,811	.cache_type	= REGCACHE_RBTREE,812};813 814static void ltc4162l_clear_interrupts(struct ltc4162l_info *info)815{816	/* Acknowledge interrupt to chip by clearing all events */817	regmap_write(info->regmap, LTC4162L_LIMIT_ALERTS_REG, 0);818	regmap_write(info->regmap, LTC4162L_CHARGER_STATE_ALERTS_REG, 0);819	regmap_write(info->regmap, LTC4162L_CHARGE_STATUS_ALERTS_REG, 0);820}821 822static int ltc4162l_probe(struct i2c_client *client)823{824	struct i2c_adapter *adapter = client->adapter;825	struct device *dev = &client->dev;826	struct ltc4162l_info *info;827	struct power_supply_config ltc4162l_config = {};828	u32 value;829	int ret;830 831	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {832		dev_err(dev, "No support for SMBUS_WORD_DATA\n");833		return -ENODEV;834	}835	info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);836	if (!info)837		return -ENOMEM;838 839	info->client = client;840	i2c_set_clientdata(client, info);841 842	info->regmap = devm_regmap_init_i2c(client, &ltc4162l_regmap_config);843	if (IS_ERR(info->regmap)) {844		dev_err(dev, "Failed to initialize register map\n");845		return PTR_ERR(info->regmap);846	}847 848	ret = device_property_read_u32(dev, "lltc,rsnsb-micro-ohms",849				       &info->rsnsb);850	if (ret) {851		dev_err(dev, "Missing lltc,rsnsb-micro-ohms property\n");852		return ret;853	}854	if (!info->rsnsb)855		return -EINVAL;856 857	ret = device_property_read_u32(dev, "lltc,rsnsi-micro-ohms",858				       &info->rsnsi);859	if (ret) {860		dev_err(dev, "Missing lltc,rsnsi-micro-ohms property\n");861		return ret;862	}863	if (!info->rsnsi)864		return -EINVAL;865 866	if (!device_property_read_u32(dev, "lltc,cell-count", &value))867		info->cell_count = value;868 869	ltc4162l_config.of_node = dev->of_node;870	ltc4162l_config.drv_data = info;871	ltc4162l_config.attr_grp = ltc4162l_attr_groups;872 873	info->charger = devm_power_supply_register(dev, &ltc4162l_desc,874						   &ltc4162l_config);875	if (IS_ERR(info->charger)) {876		dev_err(dev, "Failed to register charger\n");877		return PTR_ERR(info->charger);878	}879 880	/* Disable the threshold alerts, we're not using them */881	regmap_write(info->regmap, LTC4162L_EN_LIMIT_ALERTS_REG, 0);882 883	/* Enable interrupts on all status changes */884	regmap_write(info->regmap, LTC4162L_EN_CHARGER_STATE_ALERTS_REG,885		     0x1fff);886	regmap_write(info->regmap, LTC4162L_EN_CHARGE_STATUS_ALERTS_REG, 0x1f);887 888	ltc4162l_clear_interrupts(info);889 890	return 0;891}892 893static void ltc4162l_alert(struct i2c_client *client,894			   enum i2c_alert_protocol type, unsigned int flag)895{896	struct ltc4162l_info *info = i2c_get_clientdata(client);897 898	if (type != I2C_PROTOCOL_SMBUS_ALERT)899		return;900 901	ltc4162l_clear_interrupts(info);902	power_supply_changed(info->charger);903}904 905static const struct i2c_device_id ltc4162l_i2c_id_table[] = {906	{ "ltc4162-l" },907	{ }908};909MODULE_DEVICE_TABLE(i2c, ltc4162l_i2c_id_table);910 911static const struct of_device_id ltc4162l_of_match[] __maybe_unused = {912	{ .compatible = "lltc,ltc4162-l", },913	{ },914};915MODULE_DEVICE_TABLE(of, ltc4162l_of_match);916 917static struct i2c_driver ltc4162l_driver = {918	.probe		= ltc4162l_probe,919	.alert		= ltc4162l_alert,920	.id_table	= ltc4162l_i2c_id_table,921	.driver = {922		.name		= "ltc4162-l-charger",923		.of_match_table	= of_match_ptr(ltc4162l_of_match),924	},925};926module_i2c_driver(ltc4162l_driver);927 928MODULE_LICENSE("GPL");929MODULE_AUTHOR("Mike Looijmans <mike.looijmans@topic.nl>");930MODULE_DESCRIPTION("LTC4162-L charger driver");931