brintos

brintos / linux-shallow public Read only

0
0
Text · 28.9 KiB · a3424f6 Raw
1167 lines · c
1// SPDX-License-Identifier: GPL-2.02// BQ2515X Battery Charger Driver3// Copyright (C) 2020 Texas Instruments Incorporated - https://www.ti.com/4 5#include <linux/err.h>6#include <linux/i2c.h>7#include <linux/init.h>8#include <linux/kernel.h>9#include <linux/module.h>10#include <linux/gpio/consumer.h>11#include <linux/power_supply.h>12#include <linux/regmap.h>13#include <linux/types.h>14 15#define BQ2515X_MANUFACTURER "Texas Instruments"16 17#define BQ2515X_STAT0		0x0018#define BQ2515X_STAT1		0x0119#define BQ2515X_STAT2		0x0220#define BQ2515X_FLAG0		0x0321#define BQ2515X_FLAG1		0x0422#define BQ2515X_FLAG2		0x0523#define BQ2515X_FLAG3		0x0624#define BQ2515X_MASK0		0x0725#define BQ2515X_MASK1		0x0826#define BQ2515X_MASK2		0x0927#define BQ2515X_MASK3		0x0a28#define BQ2515X_VBAT_CTRL	0x1229#define BQ2515X_ICHG_CTRL	0x1330#define BQ2515X_PCHRGCTRL	0x1431#define BQ2515X_TERMCTRL	0x1532#define BQ2515X_BUVLO		0x1633#define BQ2515X_CHARGERCTRL0	0x1734#define BQ2515X_CHARGERCTRL1	0x1835#define BQ2515X_ILIMCTRL	0x1936#define BQ2515X_LDOCTRL		0x1d37#define BQ2515X_MRCTRL		0x3038#define BQ2515X_ICCTRL0		0x3539#define BQ2515X_ICCTRL1		0x3640#define BQ2515X_ICCTRL2		0x3741#define BQ2515X_ADCCTRL0	0x4042#define BQ2515X_ADCCTRL1	0x4143#define BQ2515X_ADC_VBAT_M	0x4244#define BQ2515X_ADC_VBAT_L	0x4345#define BQ2515X_ADC_TS_M	0x4446#define BQ2515X_ADC_TS_L	0x4547#define BQ2515X_ADC_ICHG_M	0x4648#define BQ2515X_ADC_ICHG_L	0x4749#define BQ2515X_ADC_ADCIN_M	0x4850#define BQ2515X_ADC_ADCIN_L	0x4951#define BQ2515X_ADC_VIN_M	0x4a52#define BQ2515X_ADC_VIN_L	0x4b53#define BQ2515X_ADC_PMID_M	0x4c54#define BQ2515X_ADC_PMID_L	0x4d55#define BQ2515X_ADC_IIN_M	0x4e56#define BQ2515X_ADC_IIN_L	0x4f57#define BQ2515X_ADC_COMP1_M	0x5258#define BQ2515X_ADC_COMP1_L	0X5359#define BQ2515X_ADC_COMP2_M	0X5460#define BQ2515X_ADC_COMP2_L	0x5561#define BQ2515X_ADC_COMP3_M	0x5662#define BQ2515X_ADC_COMP3_L	0x5763#define BQ2515X_ADC_READ_EN	0x5864#define BQ2515X_TS_FASTCHGCTRL	0x6165#define BQ2515X_TS_COLD		0x6266#define BQ2515X_TS_COOL		0x6367#define BQ2515X_TS_WARM		0x6468#define BQ2515X_TS_HOT		0x6569#define BQ2515X_DEVICE_ID	0x6f70 71#define BQ2515X_DEFAULT_ICHG_UA		1000072#define BQ25150_DEFAULT_ILIM_UA		10000073#define BQ25155_DEFAULT_ILIM_UA		50000074#define BQ2515X_DEFAULT_VBAT_REG_UV	420000075#define BQ2515X_DEFAULT_IPRECHARGE_UA	250076 77#define BQ2515X_DIVISOR				6553678#define BQ2515X_VBAT_BASE_VOLT			360000079#define BQ2515X_VBAT_REG_MAX			460000080#define BQ2515X_VBAT_REG_MIN			360000081#define BQ2515X_VBAT_STEP_UV			1000082#define BQ2515X_UV_FACTOR			100000083#define BQ2515X_VBAT_MULTIPLIER			684#define BQ2515X_ICHG_DIVISOR			5242985#define BQ2515X_ICHG_CURR_STEP_THRESH_UA	31875086#define BQ2515X_ICHG_MIN_UA			087#define BQ2515X_ICHG_MAX_UA			50000088#define BQ2515X_ICHG_RNG_1B0_UA			125089#define BQ2515X_ICHG_RNG_1B1_UA			250090#define BQ2515X_VLOWV_SEL_1B0_UV		300000091#define BQ2515X_VLOWV_SEL_1B1_UV		280000092#define BQ2515X_PRECHRG_ICHRG_RNGE_1875_UA	1875093#define BQ2515X_PRECHRG_ICHRG_RNGE_3750_UA	3750094#define BQ2515X_TWAKE2_MIN_US			170000095#define BQ2515X_TWAKE2_MAX_US			230000096 97#define BQ2515X_ILIM_150MA	0x298#define BQ2515X_ILIM_MASK	0x799#define BQ2515X_ILIM_MIN	50000100#define BQ2515X_ILIM_MAX	600000101#define BQ2515X_HEALTH_MASK	0xf102#define BQ2515X_ICHGRNG_MASK	0x80103#define BQ2515X_STAT0_MASK	0x0f104#define BQ2515X_STAT1_MASK	0x1f105#define BQ2515X_PRECHARGE_MASK	0x1f106 107#define BQ2515X_TS_HOT_STAT		BIT(0)108#define BQ2515X_TS_WARM_STAT		BIT(1)109#define BQ2515X_TS_COOL_STAT		BIT(2)110#define BQ2515X_TS_COLD_STAT		BIT(3)111#define BQ2515X_SAFETY_TIMER_EXP	BIT(5)112 113#define BQ2515X_EN_VBAT_READ		BIT(3)114#define BQ2515X_EN_ICHG_READ		BIT(5)115 116#define BQ2515X_VIN_GOOD		BIT(0)117#define BQ2515X_CHRG_DONE		BIT(5)118#define BQ2515X_CV_CHRG_MODE		BIT(6)119 120#define BQ2515X_VIN_OVP_FAULT_STAT	BIT(7)121 122#define BQ2515X_WATCHDOG_DISABLE	BIT(4)123 124#define BQ2515X_ICHARGE_RANGE		BIT(7)125 126#define BQ2515X_VLOWV_SEL		BIT(5)127 128#define BQ2515X_CHARGER_DISABLE		BIT(0)129 130#define BQ2515X_HWRESET_14S_WD		BIT(1)131 132static const int bq2515x_ilim_lvl_values[] = {133	50000, 100000, 150000, 200000, 300000, 400000, 500000, 600000134};135 136/**137 * struct bq2515x_init_data -138 * @ilim: input current limit139 * @ichg: fast charge current140 * @vbatreg: battery regulation voltage141 * @iprechg: precharge current142 */143struct bq2515x_init_data {144	int ilim;145	int ichg;146	int vbatreg;147	int iprechg;148};149 150/**151 * struct bq2515x_info -152 * @regmap_config: register map config153 * @ilim: input current limit154 */155struct bq2515x_info {156	const struct regmap_config *regmap_config;157	int ilim;158};159 160/**161 * struct bq2515x_device -162 * @mains: mains properties163 * @battery: battery properties164 * @regmap: register map structure165 * @dev: device structure166 *167 * @reset_gpio: manual reset (MR) pin168 * @powerdown_gpio: low power mode pin169 * @ac_detect_gpio: power good (PG) pin170 * @ce_gpio: charge enable (CE) pin171 *172 * @info: device info173 * @model_name: string value describing device model174 * @mains_online: boolean value indicating power supply online175 *176 * @init_data: charger initialization data structure177 */178struct bq2515x_device {179	struct power_supply *mains;180	struct power_supply *battery;181	struct regmap *regmap;182	struct device *dev;183 184	struct gpio_desc *reset_gpio;185	struct gpio_desc *powerdown_gpio;186	struct gpio_desc *ac_detect_gpio;187	struct gpio_desc *ce_gpio;188 189	const struct bq2515x_info *info;190	char model_name[I2C_NAME_SIZE];191	bool mains_online;192 193	struct bq2515x_init_data init_data;194};195 196static const struct reg_default bq25150_reg_defaults[] = {197	{BQ2515X_FLAG0, 0x0},198	{BQ2515X_FLAG1, 0x0},199	{BQ2515X_FLAG2, 0x0},200	{BQ2515X_FLAG3, 0x0},201	{BQ2515X_MASK0, 0x0},202	{BQ2515X_MASK1, 0x0},203	{BQ2515X_MASK2, 0x71},204	{BQ2515X_MASK3, 0x0},205	{BQ2515X_VBAT_CTRL, 0x3C},206	{BQ2515X_ICHG_CTRL, 0x8},207	{BQ2515X_PCHRGCTRL, 0x2},208	{BQ2515X_TERMCTRL, 0x14},209	{BQ2515X_BUVLO, 0x0},210	{BQ2515X_CHARGERCTRL0, 0x82},211	{BQ2515X_CHARGERCTRL1, 0x42},212	{BQ2515X_ILIMCTRL, 0x1},213	{BQ2515X_LDOCTRL, 0xB0},214	{BQ2515X_MRCTRL, 0x2A},215	{BQ2515X_ICCTRL0, 0x10},216	{BQ2515X_ICCTRL1, 0x0},217	{BQ2515X_ICCTRL2, 0x0},218	{BQ2515X_ADCCTRL0, 0x2},219	{BQ2515X_ADCCTRL1, 0x40},220	{BQ2515X_ADC_COMP1_M, 0x23},221	{BQ2515X_ADC_COMP1_L, 0x20},222	{BQ2515X_ADC_COMP2_M, 0x38},223	{BQ2515X_ADC_COMP2_L, 0x90},224	{BQ2515X_ADC_COMP3_M, 0x0},225	{BQ2515X_ADC_COMP3_L, 0x0},226	{BQ2515X_ADC_READ_EN, 0x0},227	{BQ2515X_TS_FASTCHGCTRL, 0x34},228	{BQ2515X_TS_COLD, 0x7C},229	{BQ2515X_TS_COOL, 0x6D},230	{BQ2515X_TS_WARM, 0x38},231	{BQ2515X_TS_HOT, 0x27},232	{BQ2515X_DEVICE_ID, 0x20},233};234 235static const struct reg_default bq25155_reg_defaults[] = {236	{BQ2515X_FLAG0, 0x0},237	{BQ2515X_FLAG1, 0x0},238	{BQ2515X_FLAG2, 0x0},239	{BQ2515X_FLAG3, 0x0},240	{BQ2515X_MASK0, 0x0},241	{BQ2515X_MASK1, 0x0},242	{BQ2515X_MASK2, 0x71},243	{BQ2515X_MASK3, 0x0},244	{BQ2515X_VBAT_CTRL, 0x3C},245	{BQ2515X_ICHG_CTRL, 0x8},246	{BQ2515X_PCHRGCTRL, 0x2},247	{BQ2515X_TERMCTRL, 0x14},248	{BQ2515X_BUVLO, 0x0},249	{BQ2515X_CHARGERCTRL0, 0x82},250	{BQ2515X_CHARGERCTRL1, 0xC2},251	{BQ2515X_ILIMCTRL, 0x6},252	{BQ2515X_LDOCTRL, 0xB0},253	{BQ2515X_MRCTRL, 0x2A},254	{BQ2515X_ICCTRL0, 0x10},255	{BQ2515X_ICCTRL1, 0x0},256	{BQ2515X_ICCTRL2, 0x40},257	{BQ2515X_ADCCTRL0, 0x2},258	{BQ2515X_ADCCTRL1, 0x40},259	{BQ2515X_ADC_COMP1_M, 0x23},260	{BQ2515X_ADC_COMP1_L, 0x20},261	{BQ2515X_ADC_COMP2_M, 0x38},262	{BQ2515X_ADC_COMP2_L, 0x90},263	{BQ2515X_ADC_COMP3_M, 0x0},264	{BQ2515X_ADC_COMP3_L, 0x0},265	{BQ2515X_ADC_READ_EN, 0x0},266	{BQ2515X_TS_FASTCHGCTRL, 0x34},267	{BQ2515X_TS_COLD, 0x7C},268	{BQ2515X_TS_COOL, 0x6D},269	{BQ2515X_TS_WARM, 0x38},270	{BQ2515X_TS_HOT, 0x27},271	{BQ2515X_DEVICE_ID, 0x35},272};273 274static int bq2515x_wake_up(struct bq2515x_device *bq2515x)275{276	int ret;277	int val;278 279	/* Read the STAT register if we can read it then the device is out280	 * of ship mode.  If the register cannot be read then attempt to wake281	 * it up and enable the ADC.282	 */283	ret = regmap_read(bq2515x->regmap, BQ2515X_STAT0, &val);284	if (ret)285		return ret;286 287	/* Need to toggle LP and bring device out of ship mode. The device288	 * will exit the ship mode when the MR pin is held low for at least289	 * t_WAKE2 as shown in section 8.3.7.1 of the datasheet.290	 */291	gpiod_set_value_cansleep(bq2515x->powerdown_gpio, 0);292 293	gpiod_set_value_cansleep(bq2515x->reset_gpio, 0);294	usleep_range(BQ2515X_TWAKE2_MIN_US, BQ2515X_TWAKE2_MAX_US);295	gpiod_set_value_cansleep(bq2515x->reset_gpio, 1);296 297	return regmap_write(bq2515x->regmap, BQ2515X_ADC_READ_EN,298				(BQ2515X_EN_VBAT_READ | BQ2515X_EN_ICHG_READ));299}300 301static int bq2515x_update_ps_status(struct bq2515x_device *bq2515x)302{303	bool dc = false;304	unsigned int val;305	int ret;306 307	if (bq2515x->ac_detect_gpio)308		val = gpiod_get_value_cansleep(bq2515x->ac_detect_gpio);309	else {310		ret = regmap_read(bq2515x->regmap, BQ2515X_STAT0, &val);311		if (ret)312			return ret;313	}314 315	dc = val & BQ2515X_VIN_GOOD;316 317	ret = bq2515x->mains_online != dc;318 319	bq2515x->mains_online = dc;320 321	return ret;322}323 324static int bq2515x_disable_watchdog_timers(struct bq2515x_device *bq2515x)325{326	int ret;327 328	ret = regmap_update_bits(bq2515x->regmap, BQ2515X_CHARGERCTRL0,329			BQ2515X_WATCHDOG_DISABLE, BQ2515X_WATCHDOG_DISABLE);330	if (ret)331		return ret;332 333	return regmap_update_bits(bq2515x->regmap, BQ2515X_ICCTRL2,334						BQ2515X_HWRESET_14S_WD, 0);335}336 337static int bq2515x_get_battery_voltage_now(struct bq2515x_device *bq2515x)338{339	int ret;340	int vbat_msb;341	int vbat_lsb;342	uint32_t vbat_measurement;343 344	if (!bq2515x->mains_online)345		bq2515x_wake_up(bq2515x);346 347	ret = regmap_read(bq2515x->regmap, BQ2515X_ADC_VBAT_M, &vbat_msb);348	if (ret)349		return ret;350 351	ret = regmap_read(bq2515x->regmap, BQ2515X_ADC_VBAT_L, &vbat_lsb);352	if (ret)353		return ret;354 355	vbat_measurement = (vbat_msb << 8) | vbat_lsb;356 357	return vbat_measurement * (BQ2515X_UV_FACTOR / BQ2515X_DIVISOR) *358						BQ2515X_VBAT_MULTIPLIER;359}360 361static int bq2515x_get_battery_current_now(struct bq2515x_device *bq2515x)362{363	int ret;364	int ichg_msb;365	int ichg_lsb;366	uint32_t ichg_measurement;367	u16 ichg_multiplier = BQ2515X_ICHG_RNG_1B0_UA;368	unsigned int ichg_reg_code, reg_code;369	unsigned int icharge_range = 0, pchrgctrl;370	unsigned int buvlo, vlowv_sel, vlowv = BQ2515X_VLOWV_SEL_1B0_UV;371 372	if (!bq2515x->mains_online)373		return -ENODATA;374 375	ret = regmap_read(bq2515x->regmap, BQ2515X_ADC_ICHG_M, &ichg_msb);376	if (ret)377		return ret;378 379	ret = regmap_read(bq2515x->regmap, BQ2515X_ADC_ICHG_L, &ichg_lsb);380	if (ret)381		return ret;382 383	ichg_measurement = (ichg_msb << 8) | ichg_lsb;384 385	ret = regmap_read(bq2515x->regmap, BQ2515X_BUVLO, &buvlo);386	if (ret)387		return ret;388 389	vlowv_sel = buvlo & BQ2515X_VLOWV_SEL;390 391	if (vlowv_sel)392		vlowv = BQ2515X_VLOWV_SEL_1B1_UV;393 394	if (bq2515x_get_battery_voltage_now(bq2515x) < vlowv) {395		ret = regmap_read(bq2515x->regmap, BQ2515X_PCHRGCTRL,396								&pchrgctrl);397		if (ret)398			return ret;399 400		reg_code = pchrgctrl & BQ2515X_PRECHARGE_MASK;401	} else {402		ret = regmap_read(bq2515x->regmap, BQ2515X_ICHG_CTRL,403							&ichg_reg_code);404		if (ret)405			return ret;406 407		reg_code = ichg_reg_code;408	}409 410	ret = regmap_read(bq2515x->regmap, BQ2515X_PCHRGCTRL, &pchrgctrl);411	if (ret)412		return ret;413 414	icharge_range = pchrgctrl & BQ2515X_ICHARGE_RANGE;415 416	if (icharge_range)417		ichg_multiplier = BQ2515X_ICHG_RNG_1B1_UA;418 419	return reg_code * (ichg_multiplier * ichg_measurement /420							BQ2515X_ICHG_DIVISOR);421}422 423static bool bq2515x_get_charge_disable(struct bq2515x_device *bq2515x)424{425	int ret;426	int ce_pin;427	int icctrl2;428	int charger_disable;429 430	ce_pin = gpiod_get_value_cansleep(bq2515x->ce_gpio);431 432	ret = regmap_read(bq2515x->regmap, BQ2515X_ICCTRL2, &icctrl2);433	if (ret)434		return ret;435 436	charger_disable = icctrl2 & BQ2515X_CHARGER_DISABLE;437 438	if (charger_disable || ce_pin)439		return true;440 441	return false;442}443 444static int bq2515x_set_charge_disable(struct bq2515x_device *bq2515x, int val)445{446	gpiod_set_value_cansleep(bq2515x->ce_gpio, val);447 448	return regmap_update_bits(bq2515x->regmap, BQ2515X_ICCTRL2,449					BQ2515X_CHARGER_DISABLE, val);450}451 452static int bq2515x_get_const_charge_current(struct bq2515x_device *bq2515x)453{454	int ret;455	u16 ichg_multiplier = BQ2515X_ICHG_RNG_1B0_UA;456	unsigned int ichg_reg_code;457	unsigned int pchrgctrl;458	unsigned int icharge_range;459 460	ret = regmap_read(bq2515x->regmap, BQ2515X_ICHG_CTRL, &ichg_reg_code);461	if (ret)462		return ret;463 464	ret = regmap_read(bq2515x->regmap, BQ2515X_PCHRGCTRL, &pchrgctrl);465	if (ret)466		return ret;467 468	icharge_range = pchrgctrl & BQ2515X_ICHARGE_RANGE;469 470	if (icharge_range)471		ichg_multiplier = BQ2515X_ICHG_RNG_1B1_UA;472 473	return ichg_reg_code * ichg_multiplier;474}475 476static int bq2515x_set_const_charge_current(struct bq2515x_device *bq2515x,477								int val)478{479	int ret;480	unsigned int ichg_reg_code;481	u16 ichg_multiplier = BQ2515X_ICHG_RNG_1B0_UA;482	unsigned int icharge_range = 0;483 484	if (val > BQ2515X_ICHG_MAX_UA || val < BQ2515X_ICHG_MIN_UA)485		return -EINVAL;486 487	if (val > BQ2515X_ICHG_CURR_STEP_THRESH_UA) {488		ichg_multiplier = BQ2515X_ICHG_RNG_1B1_UA;489		icharge_range = BQ2515X_ICHARGE_RANGE;490	}491 492	bq2515x_set_charge_disable(bq2515x, 1);493 494	ret = regmap_update_bits(bq2515x->regmap, BQ2515X_PCHRGCTRL,495					BQ2515X_ICHARGE_RANGE, icharge_range);496	if (ret)497		return ret;498 499	ichg_reg_code = val / ichg_multiplier;500 501	ret = regmap_write(bq2515x->regmap, BQ2515X_ICHG_CTRL, ichg_reg_code);502	if (ret)503		return ret;504 505	return bq2515x_set_charge_disable(bq2515x, 0);506}507 508static int bq2515x_get_precharge_current(struct bq2515x_device *bq2515x)509{510	int ret;511	unsigned int pchrgctrl;512	unsigned int icharge_range;513	u16 precharge_multiplier = BQ2515X_ICHG_RNG_1B0_UA;514	unsigned int precharge_reg_code;515 516	ret = regmap_read(bq2515x->regmap, BQ2515X_PCHRGCTRL, &pchrgctrl);517	if (ret)518		return ret;519 520	icharge_range = pchrgctrl & BQ2515X_ICHARGE_RANGE;521 522	if (icharge_range)523		precharge_multiplier = BQ2515X_ICHG_RNG_1B1_UA;524 525	precharge_reg_code = pchrgctrl & BQ2515X_PRECHARGE_MASK;526 527	return precharge_reg_code * precharge_multiplier;528}529 530static int bq2515x_set_precharge_current(struct bq2515x_device *bq2515x,531					int val)532{533	int ret;534	unsigned int pchrgctrl;535	unsigned int icharge_range;536	unsigned int precharge_reg_code;537	unsigned int precharge_multiplier = BQ2515X_ICHG_RNG_1B0_UA;538	unsigned int precharge_max_ua = BQ2515X_PRECHRG_ICHRG_RNGE_1875_UA;539 540	ret = regmap_read(bq2515x->regmap, BQ2515X_PCHRGCTRL, &pchrgctrl);541	if (ret)542		return ret;543 544	icharge_range = pchrgctrl & BQ2515X_ICHARGE_RANGE;545 546	if (icharge_range) {547		precharge_max_ua = BQ2515X_PRECHRG_ICHRG_RNGE_3750_UA;548		precharge_multiplier = BQ2515X_ICHG_RNG_1B1_UA;549	} else {550		precharge_max_ua = BQ2515X_PRECHRG_ICHRG_RNGE_1875_UA;551		precharge_multiplier = BQ2515X_ICHG_RNG_1B0_UA;552	}553	if (val > precharge_max_ua || val < BQ2515X_ICHG_MIN_UA)554		return -EINVAL;555 556	precharge_reg_code = val / precharge_multiplier;557 558	ret = bq2515x_set_charge_disable(bq2515x, 1);559	if (ret)560		return ret;561 562	ret = regmap_update_bits(bq2515x->regmap, BQ2515X_PCHRGCTRL,563				BQ2515X_PRECHARGE_MASK, precharge_reg_code);564	if (ret)565		return ret;566 567	return bq2515x_set_charge_disable(bq2515x, 0);568}569 570static int bq2515x_charging_status(struct bq2515x_device *bq2515x,571				   union power_supply_propval *val)572{573	bool status0_no_fault;574	bool status1_no_fault;575	bool ce_status;576	bool charge_done;577	unsigned int status;578	int ret;579 580	if (!bq2515x->mains_online) {581		val->intval = POWER_SUPPLY_STATUS_DISCHARGING;582		return 0;583	}584 585	ret = regmap_read(bq2515x->regmap, BQ2515X_STAT0, &status);586	if (ret)587		return ret;588 589	/*590	 * The code block below is used to determine if any faults from the591	 * STAT0 register are disbaling charging or if the charge has completed592	 * according to the CHARGE_DONE_STAT bit.593	 */594	if (((status & BQ2515X_STAT0_MASK) == true) &595			((status & BQ2515X_CHRG_DONE) == false)) {596		status0_no_fault = true;597		charge_done = false;598	} else if (status & BQ2515X_CHRG_DONE) {599		charge_done = true;600		status0_no_fault = false;601	} else {602		status0_no_fault = false;603		charge_done = false;604	}605 606	ret = regmap_read(bq2515x->regmap, BQ2515X_STAT1, &status);607	if (ret)608		return ret;609	/*610	 * The code block below is used to determine if any faults from the611	 * STAT1 register are disbaling charging612	 */613	if ((status & BQ2515X_STAT1_MASK) == false)614		status1_no_fault = true;615	else616		status1_no_fault = false;617 618	ce_status = (!bq2515x_get_charge_disable(bq2515x));619 620	/*621	 * If there are no faults and charging is enabled, then status is622	 * charging. Otherwise, if charging is complete, then status is full.623	 * Otherwise, if a fault exists or charging is disabled, then status is624	 * not charging625	 */626	if (status0_no_fault & status1_no_fault & ce_status)627		val->intval = POWER_SUPPLY_STATUS_CHARGING;628	else if (charge_done)629		val->intval = POWER_SUPPLY_STATUS_FULL;630	else if (!(status0_no_fault & status1_no_fault & ce_status))631		val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;632 633	return 0;634}635 636static int bq2515x_get_batt_reg(struct bq2515x_device *bq2515x)637{638	int vbat_reg_code;639	int ret;640 641	ret = regmap_read(bq2515x->regmap, BQ2515X_VBAT_CTRL, &vbat_reg_code);642	if (ret)643		return ret;644 645	return BQ2515X_VBAT_BASE_VOLT + vbat_reg_code * BQ2515X_VBAT_STEP_UV;646}647 648static int bq2515x_set_batt_reg(struct bq2515x_device *bq2515x, int val)649{650	int vbat_reg_code;651 652	if (val > BQ2515X_VBAT_REG_MAX || val < BQ2515X_VBAT_REG_MIN)653		return -EINVAL;654 655	vbat_reg_code = (val - BQ2515X_VBAT_BASE_VOLT) / BQ2515X_VBAT_STEP_UV;656 657	return regmap_write(bq2515x->regmap, BQ2515X_VBAT_CTRL, vbat_reg_code);658}659 660static int bq2515x_get_ilim_lvl(struct bq2515x_device *bq2515x)661{662	int ret;663	int ilimctrl;664 665	ret = regmap_read(bq2515x->regmap, BQ2515X_ILIMCTRL, &ilimctrl);666	if (ret)667		return ret;668 669	return bq2515x_ilim_lvl_values[ilimctrl & BQ2515X_ILIM_MASK];670}671 672static int bq2515x_set_ilim_lvl(struct bq2515x_device *bq2515x, int val)673{674	int i = 0;675	unsigned int array_size = ARRAY_SIZE(bq2515x_ilim_lvl_values);676 677	for (i = array_size - 1; i > 0; i--) {678		if (val >= bq2515x_ilim_lvl_values[i])679			break;680	}681	return regmap_write(bq2515x->regmap, BQ2515X_ILIMCTRL, i);682}683 684static int bq2515x_power_supply_property_is_writeable(struct power_supply *psy,685					enum power_supply_property prop)686{687	switch (prop) {688	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:689	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:690	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:691	case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:692		return true;693	default:694		return false;695	}696}697 698static int bq2515x_charger_get_health(struct bq2515x_device *bq2515x,699				      union power_supply_propval *val)700{701	int health = POWER_SUPPLY_HEALTH_GOOD;702	int ret;703	unsigned int stat1;704	unsigned int flag3;705 706	if (!bq2515x->mains_online)707		bq2515x_wake_up(bq2515x);708 709	ret = regmap_read(bq2515x->regmap, BQ2515X_FLAG3, &flag3);710	if (ret)711		return ret;712 713	ret = regmap_read(bq2515x->regmap, BQ2515X_STAT1, &stat1);714	if (ret)715		return ret;716 717	if (stat1 & BQ2515X_HEALTH_MASK) {718		switch (stat1 & BQ2515X_HEALTH_MASK) {719		case BQ2515X_TS_HOT_STAT:720			health = POWER_SUPPLY_HEALTH_HOT;721			break;722		case BQ2515X_TS_WARM_STAT:723			health = POWER_SUPPLY_HEALTH_WARM;724			break;725		case BQ2515X_TS_COOL_STAT:726			health = POWER_SUPPLY_HEALTH_COOL;727			break;728		case BQ2515X_TS_COLD_STAT:729			health = POWER_SUPPLY_HEALTH_COLD;730			break;731		default:732			health = POWER_SUPPLY_HEALTH_UNKNOWN;733			break;734		}735	}736 737	if (stat1 & BQ2515X_VIN_OVP_FAULT_STAT)738		health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;739 740	if (flag3 & BQ2515X_SAFETY_TIMER_EXP)741		health = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE;742 743	val->intval = health;744	return 0;745}746 747static int bq2515x_mains_set_property(struct power_supply *psy,748		enum power_supply_property prop,749		const union power_supply_propval *val)750{751	struct bq2515x_device *bq2515x = power_supply_get_drvdata(psy);752	int ret;753 754	switch (prop) {755	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:756		ret = bq2515x_set_batt_reg(bq2515x, val->intval);757		break;758 759	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:760		ret = bq2515x_set_const_charge_current(bq2515x, val->intval);761		break;762 763	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:764		ret = bq2515x_set_ilim_lvl(bq2515x, val->intval);765		break;766 767	case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:768		ret = bq2515x_set_precharge_current(bq2515x, val->intval);769		break;770 771	default:772		return -EINVAL;773	}774 775	return ret;776}777 778static int bq2515x_mains_get_property(struct power_supply *psy,779				     enum power_supply_property prop,780				     union power_supply_propval *val)781{782	struct bq2515x_device *bq2515x = power_supply_get_drvdata(psy);783	int ret = 0;784 785	switch (prop) {786 787	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:788		ret = bq2515x_get_const_charge_current(bq2515x);789		if (ret < 0)790			return ret;791 792		val->intval = ret;793		break;794 795	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:796		ret = bq2515x_get_batt_reg(bq2515x);797		if (ret < 0)798			return ret;799		val->intval = ret;800		break;801 802	case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:803		ret = bq2515x_get_precharge_current(bq2515x);804		if (ret < 0)805			return ret;806		val->intval = ret;807		break;808 809	case POWER_SUPPLY_PROP_ONLINE:810		val->intval = bq2515x->mains_online;811		break;812 813	case POWER_SUPPLY_PROP_HEALTH:814		ret = bq2515x_charger_get_health(bq2515x, val);815		if (ret)816			val->intval = POWER_SUPPLY_HEALTH_UNKNOWN;817		break;818 819	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:820		ret = bq2515x_get_ilim_lvl(bq2515x);821		if (ret < 0)822			return ret;823		val->intval = ret;824		break;825 826	case POWER_SUPPLY_PROP_MODEL_NAME:827		val->strval = bq2515x->model_name;828		break;829 830	case POWER_SUPPLY_PROP_MANUFACTURER:831		val->strval = BQ2515X_MANUFACTURER;832		break;833 834	case POWER_SUPPLY_PROP_STATUS:835		ret = bq2515x_charging_status(bq2515x, val);836		if (ret)837			return ret;838		break;839 840	default:841		return -EINVAL;842	}843 844	return ret;845}846 847static int bq2515x_battery_get_property(struct power_supply *psy,848				       enum power_supply_property prop,849				       union power_supply_propval *val)850{851	struct bq2515x_device *bq2515x = power_supply_get_drvdata(psy);852	int ret;853 854	ret = bq2515x_update_ps_status(bq2515x);855	if (ret)856		return ret;857 858	switch (prop) {859 860	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:861		ret = bq2515x->init_data.vbatreg;862		if (ret < 0)863			return ret;864		val->intval = ret;865		break;866 867	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:868		ret = bq2515x->init_data.ichg;869		if (ret < 0)870			return ret;871		val->intval = ret;872		break;873 874	case POWER_SUPPLY_PROP_VOLTAGE_NOW:875		ret = bq2515x_get_battery_voltage_now(bq2515x);876		if (ret < 0)877			return ret;878		val->intval = ret;879		break;880 881	case POWER_SUPPLY_PROP_CURRENT_NOW:882		ret = bq2515x_get_battery_current_now(bq2515x);883		if (ret < 0)884			return ret;885		val->intval = ret;886		break;887 888	default:889		return -EINVAL;890	}891	return 0;892}893 894static const enum power_supply_property bq2515x_battery_properties[] = {895	POWER_SUPPLY_PROP_VOLTAGE_NOW,896	POWER_SUPPLY_PROP_CURRENT_NOW,897	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,898	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,899};900 901static const enum power_supply_property bq2515x_mains_properties[] = {902	POWER_SUPPLY_PROP_ONLINE,903	POWER_SUPPLY_PROP_STATUS,904	POWER_SUPPLY_PROP_HEALTH,905	POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,906	POWER_SUPPLY_PROP_MODEL_NAME,907	POWER_SUPPLY_PROP_MANUFACTURER,908	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,909	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,910	POWER_SUPPLY_PROP_PRECHARGE_CURRENT,911};912 913static const struct power_supply_desc bq2515x_mains_desc = {914	.name			= "bq2515x-mains",915	.type			= POWER_SUPPLY_TYPE_MAINS,916	.get_property		= bq2515x_mains_get_property,917	.set_property		= bq2515x_mains_set_property,918	.properties		= bq2515x_mains_properties,919	.num_properties		= ARRAY_SIZE(bq2515x_mains_properties),920	.property_is_writeable	= bq2515x_power_supply_property_is_writeable,921};922 923static const struct power_supply_desc bq2515x_battery_desc = {924	.name			= "bq2515x-battery",925	.type			= POWER_SUPPLY_TYPE_BATTERY,926	.get_property		= bq2515x_battery_get_property,927	.properties		= bq2515x_battery_properties,928	.num_properties		= ARRAY_SIZE(bq2515x_battery_properties),929	.property_is_writeable	= bq2515x_power_supply_property_is_writeable,930};931 932static int bq2515x_power_supply_register(struct bq2515x_device *bq2515x,933		struct device *dev, struct power_supply_config psy_cfg)934{935	bq2515x->mains = devm_power_supply_register(bq2515x->dev,936						    &bq2515x_mains_desc,937						    &psy_cfg);938	if (IS_ERR(bq2515x->mains))939		return -EINVAL;940 941	bq2515x->battery = devm_power_supply_register(bq2515x->dev,942						      &bq2515x_battery_desc,943						      &psy_cfg);944	if (IS_ERR(bq2515x->battery))945		return -EINVAL;946 947	return 0;948}949 950static int bq2515x_hw_init(struct bq2515x_device *bq2515x)951{952	int ret;953	struct power_supply_battery_info *bat_info;954 955	ret = bq2515x_disable_watchdog_timers(bq2515x);956	if (ret)957		return ret;958 959	if (bq2515x->init_data.ilim) {960		ret = bq2515x_set_ilim_lvl(bq2515x, bq2515x->init_data.ilim);961		if (ret)962			return ret;963	}964 965	ret = power_supply_get_battery_info(bq2515x->mains, &bat_info);966	if (ret) {967		dev_warn(bq2515x->dev, "battery info missing, default values will be applied\n");968 969		bq2515x->init_data.ichg = BQ2515X_DEFAULT_ICHG_UA;970 971		bq2515x->init_data.vbatreg = BQ2515X_DEFAULT_VBAT_REG_UV;972 973		bq2515x->init_data.iprechg = BQ2515X_DEFAULT_IPRECHARGE_UA;974 975	} else {976		bq2515x->init_data.ichg =977				bat_info->constant_charge_current_max_ua;978 979		bq2515x->init_data.vbatreg =980				bat_info->constant_charge_voltage_max_uv;981 982		bq2515x->init_data.iprechg =983				bat_info->precharge_current_ua;984	}985 986	ret = bq2515x_set_const_charge_current(bq2515x,987						bq2515x->init_data.ichg);988	if (ret)989		return ret;990 991	ret = bq2515x_set_batt_reg(bq2515x, bq2515x->init_data.vbatreg);992	if (ret)993		return ret;994 995	return bq2515x_set_precharge_current(bq2515x,996						bq2515x->init_data.iprechg);997}998 999static int bq2515x_read_properties(struct bq2515x_device *bq2515x)1000{1001	int ret;1002 1003	ret = device_property_read_u32(bq2515x->dev,1004				      "input-current-limit-microamp",1005				      &bq2515x->init_data.ilim);1006	if (ret)1007		bq2515x->init_data.ilim = bq2515x->info->ilim;1008 1009	bq2515x->ac_detect_gpio = devm_gpiod_get_optional(bq2515x->dev,1010						   "ac-detect", GPIOD_IN);1011	if (IS_ERR(bq2515x->ac_detect_gpio)) {1012		ret = PTR_ERR(bq2515x->ac_detect_gpio);1013		dev_err(bq2515x->dev, "Failed to get ac detect");1014		return ret;1015	}1016 1017	bq2515x->reset_gpio = devm_gpiod_get_optional(bq2515x->dev,1018						   "reset", GPIOD_OUT_LOW);1019	if (IS_ERR(bq2515x->reset_gpio)) {1020		ret = PTR_ERR(bq2515x->reset_gpio);1021		dev_err(bq2515x->dev, "Failed to get reset");1022		return ret;1023	}1024 1025	bq2515x->powerdown_gpio = devm_gpiod_get_optional(bq2515x->dev,1026						"powerdown", GPIOD_OUT_LOW);1027	if (IS_ERR(bq2515x->powerdown_gpio)) {1028		ret = PTR_ERR(bq2515x->powerdown_gpio);1029		dev_err(bq2515x->dev, "Failed to get powerdown");1030		return ret;1031	}1032 1033	bq2515x->ce_gpio = devm_gpiod_get_optional(bq2515x->dev,1034						   "charge-enable",1035						   GPIOD_OUT_LOW);1036	if (IS_ERR(bq2515x->ce_gpio)) {1037		ret = PTR_ERR(bq2515x->ce_gpio);1038		dev_err(bq2515x->dev, "Failed to get ce");1039		return ret;1040	}1041 1042	return 0;1043}1044 1045static bool bq2515x_volatile_register(struct device *dev, unsigned int reg)1046{1047	switch (reg) {1048	case BQ2515X_STAT0 ... BQ2515X_FLAG3:1049	case BQ2515X_ADC_VBAT_M ... BQ2515X_ADC_IIN_L:1050		return true;1051	default:1052		return false;1053	}1054}1055 1056static const struct regmap_config bq25150_regmap_config = {1057	.reg_bits = 8,1058	.val_bits = 8,1059 1060	.max_register		= BQ2515X_DEVICE_ID,1061	.reg_defaults		= bq25150_reg_defaults,1062	.num_reg_defaults	= ARRAY_SIZE(bq25150_reg_defaults),1063	.cache_type		= REGCACHE_RBTREE,1064	.volatile_reg		= bq2515x_volatile_register,1065};1066 1067static const struct regmap_config bq25155_regmap_config = {1068	.reg_bits = 8,1069	.val_bits = 8,1070 1071	.max_register		= BQ2515X_DEVICE_ID,1072	.reg_defaults		= bq25155_reg_defaults,1073	.num_reg_defaults	= ARRAY_SIZE(bq25155_reg_defaults),1074	.cache_type		= REGCACHE_RBTREE,1075	.volatile_reg		= bq2515x_volatile_register,1076};1077 1078static int bq2515x_probe(struct i2c_client *client)1079{1080	const struct i2c_device_id *id = i2c_client_get_device_id(client);1081	struct device *dev = &client->dev;1082	struct bq2515x_device *bq2515x;1083	struct power_supply_config charger_cfg = {};1084	int ret;1085 1086	bq2515x = devm_kzalloc(dev, sizeof(*bq2515x), GFP_KERNEL);1087	if (!bq2515x)1088		return -ENOMEM;1089 1090	bq2515x->dev = dev;1091 1092	strscpy(bq2515x->model_name, id->name, sizeof(bq2515x->model_name));1093 1094	bq2515x->info = i2c_get_match_data(client);1095	bq2515x->regmap = devm_regmap_init_i2c(client,1096					       bq2515x->info->regmap_config);1097	if (IS_ERR(bq2515x->regmap)) {1098		dev_err(dev, "failed to allocate register map\n");1099		return PTR_ERR(bq2515x->regmap);1100	}1101 1102	i2c_set_clientdata(client, bq2515x);1103 1104	charger_cfg.drv_data = bq2515x;1105	charger_cfg.of_node = dev->of_node;1106 1107	ret = bq2515x_read_properties(bq2515x);1108	if (ret) {1109		dev_err(dev, "Failed to read device tree properties %d\n",1110									ret);1111		return ret;1112	}1113 1114	ret = bq2515x_power_supply_register(bq2515x, dev, charger_cfg);1115	if (ret) {1116		dev_err(dev, "failed to register power supply\n");1117		return ret;1118	}1119 1120	ret = bq2515x_hw_init(bq2515x);1121	if (ret) {1122		dev_err(dev, "Cannot initialize the chip\n");1123		return ret;1124	}1125 1126	return 0;1127}1128 1129static const struct bq2515x_info bq25150 = {1130	.regmap_config = &bq25150_regmap_config,1131	.ilim = BQ25150_DEFAULT_ILIM_UA,1132};1133 1134static const struct bq2515x_info bq25155 = {1135	.regmap_config = &bq25155_regmap_config,1136	.ilim = BQ25155_DEFAULT_ILIM_UA,1137};1138 1139static const struct i2c_device_id bq2515x_i2c_ids[] = {1140	{ "bq25150", (kernel_ulong_t)&bq25150 },1141	{ "bq25155", (kernel_ulong_t)&bq25155 },1142	{}1143};1144MODULE_DEVICE_TABLE(i2c, bq2515x_i2c_ids);1145 1146static const struct of_device_id bq2515x_of_match[] = {1147	{ .compatible = "ti,bq25150", .data = &bq25150 },1148	{ .compatible = "ti,bq25155", .data = &bq25155 },1149	{}1150};1151MODULE_DEVICE_TABLE(of, bq2515x_of_match);1152 1153static struct i2c_driver bq2515x_driver = {1154	.driver = {1155		.name = "bq2515x-charger",1156		.of_match_table = bq2515x_of_match,1157	},1158	.probe = bq2515x_probe,1159	.id_table = bq2515x_i2c_ids,1160};1161module_i2c_driver(bq2515x_driver);1162 1163MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");1164MODULE_AUTHOR("Ricardo Rivera-Matos <r-rivera-matos@ti.com>");1165MODULE_DESCRIPTION("BQ2515X charger driver");1166MODULE_LICENSE("GPL v2");1167