File Index
Files and directories
Sign in
FILE

bd71828-power.c

File preview with syntax highlighting.

linux-6.19.14/drivers/power/supply/bd71828-power.c C
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/* ROHM BD71815, BD71828 and BD71878 Charger driver */
   3
   4#include <linux/interrupt.h>
   5#include <linux/kernel.h>
   6#include <linux/mfd/rohm-bd71815.h>
   7#include <linux/mfd/rohm-bd71828.h>
   8#include <linux/module.h>
   9#include <linux/mod_devicetable.h>
  10#include <linux/platform_device.h>
  11#include <linux/property.h>
  12#include <linux/power_supply.h>
  13#include <linux/slab.h>
  14
  15/* common defines */
  16#define BD7182x_MASK_VBAT_U			0x1f
  17#define BD7182x_MASK_VDCIN_U			0x0f
  18#define BD7182x_MASK_IBAT_U			0x3f
  19#define BD7182x_MASK_CURDIR_DISCHG		0x80
  20#define BD7182x_MASK_CHG_STATE			0x7f
  21#define BD7182x_MASK_BAT_TEMP			0x07
  22#define BD7182x_MASK_DCIN_DET			BIT(0)
  23#define BD7182x_MASK_CONF_PON			BIT(0)
  24#define BD71815_MASK_CONF_XSTB			BIT(1)
  25#define BD7182x_MASK_BAT_STAT			0x3f
  26#define BD7182x_MASK_DCIN_STAT			0x07
  27
  28#define BD7182x_MASK_WDT_AUTO			0x40
  29#define BD7182x_MASK_VBAT_ALM_LIMIT_U		0x01
  30#define BD7182x_MASK_CHG_EN			0x01
  31
  32#define BD7182x_DCIN_COLLAPSE_DEFAULT		0x36
  33
  34#define MAX_CURRENT_DEFAULT			890000		/* uA */
  35#define AC_NAME					"bd71828_ac"
  36#define BAT_NAME				"bd71828_bat"
  37
  38#define BAT_OPEN	0x7
  39
  40/*
  41 * VBAT Low voltage detection Threshold
  42 * 0x00D4*16mV = 212*0.016 = 3.392v
  43 */
  44#define VBAT_LOW_TH			0x00D4
  45
  46struct pwr_regs {
  47	u8 vbat_avg;
  48	u8 ibat;
  49	u8 ibat_avg;
  50	u8 btemp_vth;
  51	u8 chg_state;
  52	u8 bat_temp;
  53	u8 dcin_stat;
  54	u8 dcin_collapse_limit;
  55	u8 chg_set1;
  56	u8 chg_en;
  57	u8 vbat_alm_limit_u;
  58	u8 conf;
  59	u8 vdcin;
  60};
  61
  62static const struct pwr_regs pwr_regs_bd71828 = {
  63	.vbat_avg = BD71828_REG_VBAT_U,
  64	.ibat = BD71828_REG_IBAT_U,
  65	.ibat_avg = BD71828_REG_IBAT_AVG_U,
  66	.btemp_vth = BD71828_REG_VM_BTMP_U,
  67	.chg_state = BD71828_REG_CHG_STATE,
  68	.bat_temp = BD71828_REG_BAT_TEMP,
  69	.dcin_stat = BD71828_REG_DCIN_STAT,
  70	.dcin_collapse_limit = BD71828_REG_DCIN_CLPS,
  71	.chg_set1 = BD71828_REG_CHG_SET1,
  72	.chg_en   = BD71828_REG_CHG_EN,
  73	.vbat_alm_limit_u = BD71828_REG_ALM_VBAT_LIMIT_U,
  74	.conf = BD71828_REG_CONF,
  75	.vdcin = BD71828_REG_VDCIN_U,
  76};
  77
  78static const struct pwr_regs pwr_regs_bd71815 = {
  79	.vbat_avg = BD71815_REG_VM_SA_VBAT_U,
  80	/* BD71815 does not have separate current and current avg */
  81	.ibat = BD71815_REG_CC_CURCD_U,
  82	.ibat_avg = BD71815_REG_CC_CURCD_U,
  83
  84	.btemp_vth = BD71815_REG_VM_BTMP,
  85	.chg_state = BD71815_REG_CHG_STATE,
  86	.bat_temp = BD71815_REG_BAT_TEMP,
  87	.dcin_stat = BD71815_REG_DCIN_STAT,
  88	.dcin_collapse_limit = BD71815_REG_DCIN_CLPS,
  89	.chg_set1 = BD71815_REG_CHG_SET1,
  90	.chg_en   = BD71815_REG_CHG_SET1,
  91	.vbat_alm_limit_u = BD71815_REG_ALM_VBAT_TH_U,
  92	.conf = BD71815_REG_CONF,
  93
  94	.vdcin = BD71815_REG_VM_DCIN_U,
  95};
  96
  97struct bd71828_power {
  98	struct regmap *regmap;
  99	enum rohm_chip_type chip_type;
 100	struct device *dev;
 101	struct power_supply *ac;
 102	struct power_supply *bat;
 103
 104	const struct pwr_regs *regs;
 105	/* Reg val to uA */
 106	int curr_factor;
 107	int rsens;
 108	int (*get_temp)(struct bd71828_power *pwr, int *temp);
 109	int (*bat_inserted)(struct bd71828_power *pwr);
 110};
 111
 112static int bd7182x_write16(struct bd71828_power *pwr, int reg, u16 val)
 113{
 114	__be16 tmp;
 115
 116	tmp = cpu_to_be16(val);
 117
 118	return regmap_bulk_write(pwr->regmap, reg, &tmp, sizeof(tmp));
 119}
 120
 121static int bd7182x_read16_himask(struct bd71828_power *pwr, int reg, int himask,
 122				 u16 *val)
 123{
 124	struct regmap *regmap = pwr->regmap;
 125	int ret;
 126	__be16 rvals;
 127	u8 *tmp = (u8 *)&rvals;
 128
 129	ret = regmap_bulk_read(regmap, reg, &rvals, sizeof(*val));
 130	if (!ret) {
 131		*tmp &= himask;
 132		*val = be16_to_cpu(rvals);
 133	}
 134
 135	return ret;
 136}
 137
 138static int bd71828_get_vbat(struct bd71828_power *pwr, int *vcell)
 139{
 140	u16 tmp_vcell;
 141	int ret;
 142
 143	ret = bd7182x_read16_himask(pwr, pwr->regs->vbat_avg,
 144				    BD7182x_MASK_VBAT_U, &tmp_vcell);
 145	if (ret)
 146		dev_err(pwr->dev, "Failed to read battery average voltage\n");
 147	else
 148		*vcell = ((int)tmp_vcell) * 1000;
 149
 150	return ret;
 151}
 152
 153static int bd71828_get_current_ds_adc(struct bd71828_power *pwr, int *curr, int *curr_avg)
 154{
 155	__be16 tmp_curr;
 156	char *tmp = (char *)&tmp_curr;
 157	int dir = 1;
 158	int regs[] = { pwr->regs->ibat, pwr->regs->ibat_avg };
 159	int *vals[] = { curr, curr_avg };
 160	int ret, i;
 161
 162	for (dir = 1, i = 0; i < ARRAY_SIZE(regs); i++) {
 163		ret = regmap_bulk_read(pwr->regmap, regs[i], &tmp_curr,
 164				       sizeof(tmp_curr));
 165		if (ret)
 166			break;
 167
 168		if (*tmp & BD7182x_MASK_CURDIR_DISCHG)
 169			dir = -1;
 170
 171		*tmp &= BD7182x_MASK_IBAT_U;
 172
 173		*vals[i] = dir * ((int)be16_to_cpu(tmp_curr)) * pwr->curr_factor;
 174	}
 175
 176	return ret;
 177}
 178
 179/* Unit is tenths of degree C */
 180static int bd71815_get_temp(struct bd71828_power *pwr, int *temp)
 181{
 182	struct regmap *regmap = pwr->regmap;
 183	int ret;
 184	int t;
 185
 186	ret = regmap_read(regmap, pwr->regs->btemp_vth, &t);
 187	if (ret)
 188		return ret;
 189
 190	t = 200 - t;
 191
 192	if (t > 200) {
 193		dev_err(pwr->dev, "Failed to read battery temperature\n");
 194		return -ENODATA;
 195	}
 196
 197	return 0;
 198}
 199
 200/* Unit is tenths of degree C */
 201static int bd71828_get_temp(struct bd71828_power *pwr, int *temp)
 202{
 203	u16 t;
 204	int ret;
 205	int tmp = 200 * 10000;
 206
 207	ret = bd7182x_read16_himask(pwr, pwr->regs->btemp_vth,
 208				    BD71828_MASK_VM_BTMP_U, &t);
 209	if (ret)
 210		return ret;
 211
 212	if (t > 3200) {
 213		dev_err(pwr->dev,
 214			"Failed to read battery temperature\n");
 215		return -ENODATA;
 216	}
 217
 218	tmp -= 625ULL * (unsigned int)t;
 219	*temp = tmp / 1000;
 220
 221	return ret;
 222}
 223
 224static int bd71828_charge_status(struct bd71828_power *pwr,
 225				 int *s, int *h)
 226{
 227	unsigned int state;
 228	int status, health;
 229	int ret = 1;
 230
 231	ret = regmap_read(pwr->regmap, pwr->regs->chg_state, &state);
 232	if (ret) {
 233		dev_err(pwr->dev, "charger status reading failed (%d)\n", ret);
 234		return ret;
 235	}
 236
 237	state &= BD7182x_MASK_CHG_STATE;
 238
 239	dev_dbg(pwr->dev, "CHG_STATE %d\n", state);
 240
 241	switch (state) {
 242	case 0x00:
 243		status = POWER_SUPPLY_STATUS_DISCHARGING;
 244		health = POWER_SUPPLY_HEALTH_GOOD;
 245		break;
 246	case 0x01:
 247	case 0x02:
 248	case 0x03:
 249	case 0x0E:
 250		status = POWER_SUPPLY_STATUS_CHARGING;
 251		health = POWER_SUPPLY_HEALTH_GOOD;
 252		break;
 253	case 0x0F:
 254		status = POWER_SUPPLY_STATUS_FULL;
 255		health = POWER_SUPPLY_HEALTH_GOOD;
 256		break;
 257	case 0x10:
 258	case 0x11:
 259	case 0x12:
 260	case 0x13:
 261	case 0x14:
 262	case 0x20:
 263	case 0x21:
 264	case 0x22:
 265	case 0x23:
 266	case 0x24:
 267		status = POWER_SUPPLY_STATUS_NOT_CHARGING;
 268		health = POWER_SUPPLY_HEALTH_OVERHEAT;
 269		break;
 270	case 0x30:
 271	case 0x31:
 272	case 0x32:
 273	case 0x40:
 274		status = POWER_SUPPLY_STATUS_DISCHARGING;
 275		health = POWER_SUPPLY_HEALTH_GOOD;
 276		break;
 277	case 0x7f:
 278	default:
 279		status = POWER_SUPPLY_STATUS_NOT_CHARGING;
 280		health = POWER_SUPPLY_HEALTH_DEAD;
 281		break;
 282	}
 283
 284	if (s)
 285		*s = status;
 286	if (h)
 287		*h = health;
 288
 289	return ret;
 290}
 291
 292static int get_chg_online(struct bd71828_power *pwr, int *chg_online)
 293{
 294	int r, ret;
 295
 296	ret = regmap_read(pwr->regmap, pwr->regs->dcin_stat, &r);
 297	if (ret) {
 298		dev_err(pwr->dev, "Failed to read DCIN status\n");
 299		return ret;
 300	}
 301	*chg_online = ((r & BD7182x_MASK_DCIN_DET) != 0);
 302
 303	return 0;
 304}
 305
 306static int get_bat_online(struct bd71828_power *pwr, int *bat_online)
 307{
 308	int r, ret;
 309
 310	ret = regmap_read(pwr->regmap, pwr->regs->bat_temp, &r);
 311	if (ret) {
 312		dev_err(pwr->dev, "Failed to read battery temperature\n");
 313		return ret;
 314	}
 315	*bat_online = ((r & BD7182x_MASK_BAT_TEMP) != BAT_OPEN);
 316
 317	return 0;
 318}
 319
 320static int bd71828_bat_inserted(struct bd71828_power *pwr)
 321{
 322	int ret, val;
 323
 324	ret = regmap_read(pwr->regmap, pwr->regs->conf, &val);
 325	if (ret) {
 326		dev_err(pwr->dev, "Failed to read CONF register\n");
 327		return 0;
 328	}
 329	ret = val & BD7182x_MASK_CONF_PON;
 330
 331	if (ret)
 332		regmap_update_bits(pwr->regmap, pwr->regs->conf,
 333				   BD7182x_MASK_CONF_PON, 0);
 334
 335	return ret;
 336}
 337
 338static int bd71815_bat_inserted(struct bd71828_power *pwr)
 339{
 340	int ret, val;
 341
 342	ret = regmap_read(pwr->regmap, pwr->regs->conf, &val);
 343	if (ret) {
 344		dev_err(pwr->dev, "Failed to read CONF register\n");
 345		return ret;
 346	}
 347
 348	ret = !(val & BD71815_MASK_CONF_XSTB);
 349	if (ret)
 350		regmap_write(pwr->regmap, pwr->regs->conf,  val |
 351			     BD71815_MASK_CONF_XSTB);
 352
 353	return ret;
 354}
 355
 356static int bd71828_init_hardware(struct bd71828_power *pwr)
 357{
 358	int ret;
 359
 360	/* TODO: Collapse limit should come from device-tree ? */
 361	ret = regmap_write(pwr->regmap, pwr->regs->dcin_collapse_limit,
 362			   BD7182x_DCIN_COLLAPSE_DEFAULT);
 363	if (ret) {
 364		dev_err(pwr->dev, "Failed to write DCIN collapse limit\n");
 365		return ret;
 366	}
 367
 368	ret = pwr->bat_inserted(pwr);
 369	if (ret < 0)
 370		return ret;
 371
 372	if (ret) {
 373		/* WDT_FST auto set */
 374		ret = regmap_update_bits(pwr->regmap, pwr->regs->chg_set1,
 375					 BD7182x_MASK_WDT_AUTO,
 376					 BD7182x_MASK_WDT_AUTO);
 377		if (ret)
 378			return ret;
 379
 380		ret = bd7182x_write16(pwr, pwr->regs->vbat_alm_limit_u,
 381				      VBAT_LOW_TH);
 382		if (ret)
 383			return ret;
 384
 385		/*
 386		 * On BD71815 "we mask the power-state" from relax detection.
 387		 * I am unsure what the impact of the power-state would be if
 388		 * we didn't - but this is what the vendor driver did - and
 389		 * that driver has been used in few projects so I just assume
 390		 * this is needed.
 391		 */
 392		if (pwr->chip_type == ROHM_CHIP_TYPE_BD71815) {
 393			ret = regmap_set_bits(pwr->regmap,
 394					      BD71815_REG_REX_CTRL_1,
 395					      REX_PMU_STATE_MASK);
 396			if (ret)
 397				return ret;
 398		}
 399	}
 400
 401	return 0;
 402}
 403
 404static int bd71828_charger_get_property(struct power_supply *psy,
 405					enum power_supply_property psp,
 406					union power_supply_propval *val)
 407{
 408	struct bd71828_power *pwr = dev_get_drvdata(psy->dev.parent);
 409	u32 vot;
 410	u16 tmp;
 411	int online;
 412	int ret;
 413
 414	switch (psp) {
 415	case POWER_SUPPLY_PROP_ONLINE:
 416		ret = get_chg_online(pwr, &online);
 417		if (!ret)
 418			val->intval = online;
 419		break;
 420	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
 421		ret = bd7182x_read16_himask(pwr, pwr->regs->vdcin,
 422					    BD7182x_MASK_VDCIN_U, &tmp);
 423		if (ret)
 424			return ret;
 425
 426		vot = tmp;
 427		/* 5 milli volt steps */
 428		val->intval = 5000 * vot;
 429		break;
 430	default:
 431		return -EINVAL;
 432	}
 433
 434	return 0;
 435}
 436
 437static int bd71828_battery_get_property(struct power_supply *psy,
 438					enum power_supply_property psp,
 439					union power_supply_propval *val)
 440{
 441	struct bd71828_power *pwr = dev_get_drvdata(psy->dev.parent);
 442	int ret = 0;
 443	int status, health, tmp, curr, curr_avg, chg_en;
 444
 445	if (psp == POWER_SUPPLY_PROP_STATUS ||
 446	    psp == POWER_SUPPLY_PROP_HEALTH ||
 447	    psp == POWER_SUPPLY_PROP_CHARGE_TYPE)
 448		ret = bd71828_charge_status(pwr, &status, &health);
 449	else if (psp == POWER_SUPPLY_PROP_CURRENT_AVG ||
 450		 psp == POWER_SUPPLY_PROP_CURRENT_NOW)
 451		ret = bd71828_get_current_ds_adc(pwr, &curr, &curr_avg);
 452	if (ret)
 453		return ret;
 454
 455	switch (psp) {
 456	case POWER_SUPPLY_PROP_STATUS:
 457		val->intval = status;
 458		break;
 459	case POWER_SUPPLY_PROP_HEALTH:
 460		val->intval = health;
 461		break;
 462	case POWER_SUPPLY_PROP_PRESENT:
 463		ret = get_bat_online(pwr, &tmp);
 464		if (!ret)
 465			val->intval = tmp;
 466		break;
 467	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
 468		ret = bd71828_get_vbat(pwr, &tmp);
 469		val->intval = tmp;
 470		break;
 471	case POWER_SUPPLY_PROP_TECHNOLOGY:
 472		val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
 473		break;
 474	case POWER_SUPPLY_PROP_CURRENT_AVG:
 475		val->intval = curr_avg;
 476		break;
 477	case POWER_SUPPLY_PROP_CURRENT_NOW:
 478		val->intval = curr;
 479		break;
 480	case POWER_SUPPLY_PROP_CURRENT_MAX:
 481		val->intval = MAX_CURRENT_DEFAULT;
 482		break;
 483	case POWER_SUPPLY_PROP_TEMP:
 484		ret = pwr->get_temp(pwr, &val->intval);
 485		break;
 486	case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR:
 487		ret = regmap_read(pwr->regmap, pwr->regs->chg_en, &chg_en);
 488		if (ret)
 489			return ret;
 490
 491		val->intval = (chg_en & BD7182x_MASK_CHG_EN) ?
 492			POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO :
 493			POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE;
 494		break;
 495	default:
 496		ret = -EINVAL;
 497		break;
 498	}
 499
 500	return ret;
 501}
 502
 503static int bd71828_battery_set_property(struct power_supply *psy,
 504					enum power_supply_property psp,
 505					const union power_supply_propval *val)
 506{
 507	struct bd71828_power *pwr = dev_get_drvdata(psy->dev.parent);
 508	int ret = 0;
 509
 510	switch (psp) {
 511	case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR:
 512		if (val->intval == POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO)
 513			ret = regmap_update_bits(pwr->regmap, pwr->regs->chg_en,
 514						 BD7182x_MASK_CHG_EN,
 515						 BD7182x_MASK_CHG_EN);
 516		else
 517			ret = regmap_update_bits(pwr->regmap, pwr->regs->chg_en,
 518						 BD7182x_MASK_CHG_EN,
 519						 0);
 520		break;
 521	default:
 522		return -EINVAL;
 523	}
 524
 525	return ret;
 526}
 527
 528static int bd71828_battery_property_is_writeable(struct power_supply *psy,
 529						 enum power_supply_property psp)
 530{
 531	switch (psp) {
 532	case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR:
 533		return true;
 534	default:
 535		return false;
 536	}
 537}
 538
 539/** @brief ac properties */
 540static const enum power_supply_property bd71828_charger_props[] = {
 541	POWER_SUPPLY_PROP_ONLINE,
 542	POWER_SUPPLY_PROP_VOLTAGE_NOW,
 543};
 544
 545static const enum power_supply_property bd71828_battery_props[] = {
 546	POWER_SUPPLY_PROP_STATUS,
 547	POWER_SUPPLY_PROP_HEALTH,
 548	POWER_SUPPLY_PROP_VOLTAGE_NOW,
 549	POWER_SUPPLY_PROP_HEALTH,
 550	POWER_SUPPLY_PROP_PRESENT,
 551	POWER_SUPPLY_PROP_TECHNOLOGY,
 552	POWER_SUPPLY_PROP_TEMP,
 553	POWER_SUPPLY_PROP_CURRENT_AVG,
 554	POWER_SUPPLY_PROP_CURRENT_NOW,
 555	POWER_SUPPLY_PROP_CURRENT_MAX,
 556	POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR,
 557};
 558
 559/** @brief powers supplied by bd71828_ac */
 560static char *bd71828_ac_supplied_to[] = {
 561	BAT_NAME,
 562};
 563
 564static const struct power_supply_desc bd71828_ac_desc = {
 565	.name		= AC_NAME,
 566	.type		= POWER_SUPPLY_TYPE_MAINS,
 567	.properties	= bd71828_charger_props,
 568	.num_properties	= ARRAY_SIZE(bd71828_charger_props),
 569	.get_property	= bd71828_charger_get_property,
 570};
 571
 572static const struct power_supply_desc bd71828_bat_desc = {
 573	.name		= BAT_NAME,
 574	.type		= POWER_SUPPLY_TYPE_BATTERY,
 575	.charge_behaviours = BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO) |
 576			     BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE),
 577	.properties	= bd71828_battery_props,
 578	.num_properties = ARRAY_SIZE(bd71828_battery_props),
 579	.get_property	= bd71828_battery_get_property,
 580	.set_property	= bd71828_battery_set_property,
 581	.property_is_writeable   = bd71828_battery_property_is_writeable,
 582};
 583
 584#define RSENS_CURR 10000000LLU
 585
 586#define BD_ISR_NAME(name) \
 587bd7181x_##name##_isr
 588
 589#define BD_ISR_BAT(name, print, run_gauge)				\
 590static irqreturn_t BD_ISR_NAME(name)(int irq, void *data)		\
 591{									\
 592	struct bd71828_power *pwr = (struct bd71828_power *)data;	\
 593									\
 594	dev_dbg(pwr->dev, "%s\n", print);				\
 595	power_supply_changed(pwr->bat);				\
 596									\
 597	return IRQ_HANDLED;						\
 598}
 599
 600#define BD_ISR_AC(name, print, run_gauge)				\
 601static irqreturn_t BD_ISR_NAME(name)(int irq, void *data)		\
 602{									\
 603	struct bd71828_power *pwr = (struct bd71828_power *)data;	\
 604									\
 605	power_supply_changed(pwr->ac);					\
 606	dev_dbg(pwr->dev, "%s\n", print);				\
 607	power_supply_changed(pwr->bat);				\
 608									\
 609	return IRQ_HANDLED;						\
 610}
 611
 612#define BD_ISR_DUMMY(name, print)					\
 613static irqreturn_t BD_ISR_NAME(name)(int irq, void *data)		\
 614{									\
 615	struct bd71828_power *pwr = (struct bd71828_power *)data;	\
 616									\
 617	dev_dbg(pwr->dev, "%s\n", print);				\
 618									\
 619	return IRQ_HANDLED;						\
 620}
 621
 622BD_ISR_BAT(chg_state_changed, "CHG state changed", true)
 623/* DCIN voltage changes */
 624BD_ISR_AC(dcin_removed, "DCIN removed", true)
 625BD_ISR_AC(clps_out, "DCIN voltage back to normal", true)
 626BD_ISR_AC(clps_in, "DCIN voltage collapsed", false)
 627BD_ISR_AC(dcin_ovp_res, "DCIN voltage normal", true)
 628BD_ISR_AC(dcin_ovp_det, "DCIN OVER VOLTAGE", true)
 629
 630BD_ISR_DUMMY(dcin_mon_det, "DCIN voltage below threshold")
 631BD_ISR_DUMMY(dcin_mon_res, "DCIN voltage above threshold")
 632
 633BD_ISR_DUMMY(vsys_uv_res, "VSYS under-voltage cleared")
 634BD_ISR_DUMMY(vsys_uv_det, "VSYS under-voltage")
 635BD_ISR_DUMMY(vsys_low_res, "'VSYS low' cleared")
 636BD_ISR_DUMMY(vsys_low_det, "VSYS low")
 637BD_ISR_DUMMY(vsys_mon_res, "VSYS mon - resumed")
 638BD_ISR_DUMMY(vsys_mon_det, "VSYS mon - detected")
 639BD_ISR_BAT(chg_wdg_temp, "charger temperature watchdog triggered", true)
 640BD_ISR_BAT(chg_wdg, "charging watchdog triggered", true)
 641BD_ISR_BAT(bat_removed, "Battery removed", true)
 642BD_ISR_BAT(bat_det, "Battery detected", true)
 643/* TODO: Verify the meaning of these interrupts */
 644BD_ISR_BAT(rechg_det, "Recharging", true)
 645BD_ISR_BAT(rechg_res, "Recharge ending", true)
 646BD_ISR_DUMMY(temp_transit, "Temperature transition")
 647BD_ISR_BAT(therm_rmv, "bd71815-therm-rmv", false)
 648BD_ISR_BAT(therm_det, "bd71815-therm-det", true)
 649BD_ISR_BAT(bat_dead, "bd71815-bat-dead", false)
 650BD_ISR_BAT(bat_short_res, "bd71815-bat-short-res", true)
 651BD_ISR_BAT(bat_short, "bd71815-bat-short-det", false)
 652BD_ISR_BAT(bat_low_res, "bd71815-bat-low-res", true)
 653BD_ISR_BAT(bat_low, "bd71815-bat-low-det", true)
 654BD_ISR_BAT(bat_ov_res, "bd71815-bat-over-res", true)
 655/* What should we do here? */
 656BD_ISR_BAT(bat_ov, "bd71815-bat-over-det", false)
 657BD_ISR_BAT(bat_mon_res, "bd71815-bat-mon-res", true)
 658BD_ISR_BAT(bat_mon, "bd71815-bat-mon-det", true)
 659BD_ISR_BAT(bat_cc_mon, "bd71815-bat-cc-mon2", false)
 660BD_ISR_BAT(bat_oc1_res, "bd71815-bat-oc1-res", true)
 661BD_ISR_BAT(bat_oc1, "bd71815-bat-oc1-det", false)
 662BD_ISR_BAT(bat_oc2_res, "bd71815-bat-oc2-res", true)
 663BD_ISR_BAT(bat_oc2, "bd71815-bat-oc2-det", false)
 664BD_ISR_BAT(bat_oc3_res, "bd71815-bat-oc3-res", true)
 665BD_ISR_BAT(bat_oc3, "bd71815-bat-oc3-det", false)
 666BD_ISR_BAT(temp_bat_low_res, "bd71815-temp-bat-low-res", true)
 667BD_ISR_BAT(temp_bat_low, "bd71815-temp-bat-low-det", true)
 668BD_ISR_BAT(temp_bat_hi_res, "bd71815-temp-bat-hi-res", true)
 669BD_ISR_BAT(temp_bat_hi, "bd71815-temp-bat-hi-det", true)
 670
 671static irqreturn_t bd7182x_dcin_removed(int irq, void *data)
 672{
 673	struct bd71828_power *pwr = (struct bd71828_power *)data;
 674
 675	power_supply_changed(pwr->ac);
 676	dev_dbg(pwr->dev, "DCIN removed\n");
 677
 678	return IRQ_HANDLED;
 679}
 680
 681static irqreturn_t bd718x7_chg_done(int irq, void *data)
 682{
 683	struct bd71828_power *pwr = (struct bd71828_power *)data;
 684
 685	power_supply_changed(pwr->bat);
 686
 687	return IRQ_HANDLED;
 688}
 689
 690static irqreturn_t bd7182x_dcin_detected(int irq, void *data)
 691{
 692	struct bd71828_power *pwr = (struct bd71828_power *)data;
 693
 694	dev_dbg(pwr->dev, "DCIN inserted\n");
 695	power_supply_changed(pwr->ac);
 696
 697	return IRQ_HANDLED;
 698}
 699
 700static irqreturn_t bd71828_vbat_low_res(int irq, void *data)
 701{
 702	struct bd71828_power *pwr = (struct bd71828_power *)data;
 703
 704	dev_dbg(pwr->dev, "VBAT LOW Resumed\n");
 705
 706	return IRQ_HANDLED;
 707}
 708
 709static irqreturn_t bd71828_vbat_low_det(int irq, void *data)
 710{
 711	struct bd71828_power *pwr = (struct bd71828_power *)data;
 712
 713	dev_dbg(pwr->dev, "VBAT LOW Detected\n");
 714
 715	return IRQ_HANDLED;
 716}
 717
 718static irqreturn_t bd71828_temp_bat_hi_det(int irq, void *data)
 719{
 720	struct bd71828_power *pwr = (struct bd71828_power *)data;
 721
 722	dev_warn(pwr->dev, "Overtemp Detected\n");
 723	power_supply_changed(pwr->bat);
 724
 725	return IRQ_HANDLED;
 726}
 727
 728static irqreturn_t bd71828_temp_bat_hi_res(int irq, void *data)
 729{
 730	struct bd71828_power *pwr = (struct bd71828_power *)data;
 731
 732	dev_dbg(pwr->dev, "Overtemp Resumed\n");
 733	power_supply_changed(pwr->bat);
 734
 735	return IRQ_HANDLED;
 736}
 737
 738static irqreturn_t bd71828_temp_bat_low_det(int irq, void *data)
 739{
 740	struct bd71828_power *pwr = (struct bd71828_power *)data;
 741
 742	dev_dbg(pwr->dev, "Lowtemp Detected\n");
 743	power_supply_changed(pwr->bat);
 744
 745	return IRQ_HANDLED;
 746}
 747
 748static irqreturn_t bd71828_temp_bat_low_res(int irq, void *data)
 749{
 750	struct bd71828_power *pwr = (struct bd71828_power *)data;
 751
 752	dev_dbg(pwr->dev, "Lowtemp Resumed\n");
 753	power_supply_changed(pwr->bat);
 754
 755	return IRQ_HANDLED;
 756}
 757
 758static irqreturn_t bd71828_temp_vf_det(int irq, void *data)
 759{
 760	struct bd71828_power *pwr = (struct bd71828_power *)data;
 761
 762	dev_dbg(pwr->dev, "VF Detected\n");
 763	power_supply_changed(pwr->bat);
 764
 765	return IRQ_HANDLED;
 766}
 767
 768static irqreturn_t bd71828_temp_vf_res(int irq, void *data)
 769{
 770	struct bd71828_power *pwr = (struct bd71828_power *)data;
 771
 772	dev_dbg(pwr->dev, "VF Resumed\n");
 773	power_supply_changed(pwr->bat);
 774
 775	return IRQ_HANDLED;
 776}
 777
 778static irqreturn_t bd71828_temp_vf125_det(int irq, void *data)
 779{
 780	struct bd71828_power *pwr = (struct bd71828_power *)data;
 781
 782	dev_dbg(pwr->dev, "VF125 Detected\n");
 783	power_supply_changed(pwr->bat);
 784
 785	return IRQ_HANDLED;
 786}
 787
 788static irqreturn_t bd71828_temp_vf125_res(int irq, void *data)
 789{
 790	struct bd71828_power *pwr = (struct bd71828_power *)data;
 791
 792	dev_dbg(pwr->dev, "VF125 Resumed\n");
 793	power_supply_changed(pwr->bat);
 794
 795	return IRQ_HANDLED;
 796}
 797
 798struct bd7182x_irq_res {
 799	const char *name;
 800	irq_handler_t handler;
 801};
 802
 803#define BDIRQ(na, hn) { .name = (na), .handler = (hn) }
 804
 805static int bd7182x_get_irqs(struct platform_device *pdev,
 806			    struct bd71828_power *pwr)
 807{
 808	int i, irq, ret;
 809	static const struct bd7182x_irq_res bd71815_irqs[] = {
 810		BDIRQ("bd71815-dcin-rmv", BD_ISR_NAME(dcin_removed)),
 811		BDIRQ("bd71815-dcin-clps-out", BD_ISR_NAME(clps_out)),
 812		BDIRQ("bd71815-dcin-clps-in", BD_ISR_NAME(clps_in)),
 813		BDIRQ("bd71815-dcin-ovp-res", BD_ISR_NAME(dcin_ovp_res)),
 814		BDIRQ("bd71815-dcin-ovp-det", BD_ISR_NAME(dcin_ovp_det)),
 815		BDIRQ("bd71815-dcin-mon-res", BD_ISR_NAME(dcin_mon_res)),
 816		BDIRQ("bd71815-dcin-mon-det", BD_ISR_NAME(dcin_mon_det)),
 817
 818		BDIRQ("bd71815-vsys-uv-res", BD_ISR_NAME(vsys_uv_res)),
 819		BDIRQ("bd71815-vsys-uv-det", BD_ISR_NAME(vsys_uv_det)),
 820		BDIRQ("bd71815-vsys-low-res", BD_ISR_NAME(vsys_low_res)),
 821		BDIRQ("bd71815-vsys-low-det",  BD_ISR_NAME(vsys_low_det)),
 822		BDIRQ("bd71815-vsys-mon-res",  BD_ISR_NAME(vsys_mon_res)),
 823		BDIRQ("bd71815-vsys-mon-det",  BD_ISR_NAME(vsys_mon_det)),
 824		BDIRQ("bd71815-chg-wdg-temp", BD_ISR_NAME(chg_wdg_temp)),
 825		BDIRQ("bd71815-chg-wdg",  BD_ISR_NAME(chg_wdg)),
 826		BDIRQ("bd71815-rechg-det", BD_ISR_NAME(rechg_det)),
 827		BDIRQ("bd71815-rechg-res", BD_ISR_NAME(rechg_res)),
 828		BDIRQ("bd71815-ranged-temp-transit", BD_ISR_NAME(temp_transit)),
 829		BDIRQ("bd71815-chg-state-change", BD_ISR_NAME(chg_state_changed)),
 830		BDIRQ("bd71815-bat-temp-normal", bd71828_temp_bat_hi_res),
 831		BDIRQ("bd71815-bat-temp-erange", bd71828_temp_bat_hi_det),
 832		BDIRQ("bd71815-bat-rmv", BD_ISR_NAME(bat_removed)),
 833		BDIRQ("bd71815-bat-det", BD_ISR_NAME(bat_det)),
 834
 835		/* Add ISRs for these */
 836		BDIRQ("bd71815-therm-rmv", BD_ISR_NAME(therm_rmv)),
 837		BDIRQ("bd71815-therm-det", BD_ISR_NAME(therm_det)),
 838		BDIRQ("bd71815-bat-dead", BD_ISR_NAME(bat_dead)),
 839		BDIRQ("bd71815-bat-short-res", BD_ISR_NAME(bat_short_res)),
 840		BDIRQ("bd71815-bat-short-det", BD_ISR_NAME(bat_short)),
 841		BDIRQ("bd71815-bat-low-res", BD_ISR_NAME(bat_low_res)),
 842		BDIRQ("bd71815-bat-low-det", BD_ISR_NAME(bat_low)),
 843		BDIRQ("bd71815-bat-over-res", BD_ISR_NAME(bat_ov_res)),
 844		BDIRQ("bd71815-bat-over-det", BD_ISR_NAME(bat_ov)),
 845		BDIRQ("bd71815-bat-mon-res", BD_ISR_NAME(bat_mon_res)),
 846		BDIRQ("bd71815-bat-mon-det", BD_ISR_NAME(bat_mon)),
 847		/* cc-mon 1 & 3 ? */
 848		BDIRQ("bd71815-bat-cc-mon2", BD_ISR_NAME(bat_cc_mon)),
 849		BDIRQ("bd71815-bat-oc1-res", BD_ISR_NAME(bat_oc1_res)),
 850		BDIRQ("bd71815-bat-oc1-det", BD_ISR_NAME(bat_oc1)),
 851		BDIRQ("bd71815-bat-oc2-res", BD_ISR_NAME(bat_oc2_res)),
 852		BDIRQ("bd71815-bat-oc2-det", BD_ISR_NAME(bat_oc2)),
 853		BDIRQ("bd71815-bat-oc3-res", BD_ISR_NAME(bat_oc3_res)),
 854		BDIRQ("bd71815-bat-oc3-det", BD_ISR_NAME(bat_oc3)),
 855		BDIRQ("bd71815-temp-bat-low-res", BD_ISR_NAME(temp_bat_low_res)),
 856		BDIRQ("bd71815-temp-bat-low-det", BD_ISR_NAME(temp_bat_low)),
 857		BDIRQ("bd71815-temp-bat-hi-res", BD_ISR_NAME(temp_bat_hi_res)),
 858		BDIRQ("bd71815-temp-bat-hi-det", BD_ISR_NAME(temp_bat_hi)),
 859		/*
 860		 * TODO: add rest of the IRQs and re-check the handling.
 861		 * Check the bd71815-bat-cc-mon1, bd71815-bat-cc-mon3,
 862		 * bd71815-bat-low-res, bd71815-bat-low-det,
 863		 * bd71815-bat-hi-res, bd71815-bat-hi-det.
 864		 */
 865	};
 866	static const struct bd7182x_irq_res bd71828_irqs[] = {
 867		BDIRQ("bd71828-chg-done", bd718x7_chg_done),
 868		BDIRQ("bd71828-pwr-dcin-in", bd7182x_dcin_detected),
 869		BDIRQ("bd71828-pwr-dcin-out", bd7182x_dcin_removed),
 870		BDIRQ("bd71828-vbat-normal", bd71828_vbat_low_res),
 871		BDIRQ("bd71828-vbat-low", bd71828_vbat_low_det),
 872		BDIRQ("bd71828-btemp-hi", bd71828_temp_bat_hi_det),
 873		BDIRQ("bd71828-btemp-cool", bd71828_temp_bat_hi_res),
 874		BDIRQ("bd71828-btemp-lo", bd71828_temp_bat_low_det),
 875		BDIRQ("bd71828-btemp-warm", bd71828_temp_bat_low_res),
 876		BDIRQ("bd71828-temp-hi", bd71828_temp_vf_det),
 877		BDIRQ("bd71828-temp-norm", bd71828_temp_vf_res),
 878		BDIRQ("bd71828-temp-125-over", bd71828_temp_vf125_det),
 879		BDIRQ("bd71828-temp-125-under", bd71828_temp_vf125_res),
 880	};
 881	int num_irqs;
 882	const struct bd7182x_irq_res *irqs;
 883
 884	switch (pwr->chip_type) {
 885	case ROHM_CHIP_TYPE_BD71828:
 886		irqs = &bd71828_irqs[0];
 887		num_irqs = ARRAY_SIZE(bd71828_irqs);
 888		break;
 889	case ROHM_CHIP_TYPE_BD71815:
 890		irqs = &bd71815_irqs[0];
 891		num_irqs = ARRAY_SIZE(bd71815_irqs);
 892		break;
 893	default:
 894		return -EINVAL;
 895	}
 896
 897	for (i = 0; i < num_irqs; i++) {
 898		irq = platform_get_irq_byname(pdev, irqs[i].name);
 899
 900		ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
 901						irqs[i].handler, 0,
 902						irqs[i].name, pwr);
 903		if (ret)
 904			break;
 905	}
 906
 907	return ret;
 908}
 909
 910#define RSENS_DEFAULT_30MOHM 30000 /* 30 mOhm in uOhms*/
 911
 912static int bd7182x_get_rsens(struct bd71828_power *pwr)
 913{
 914	u64 tmp = RSENS_CURR;
 915	int rsens_ohm = RSENS_DEFAULT_30MOHM;
 916	struct fwnode_handle *node = NULL;
 917
 918	if (pwr->dev->parent)
 919		node = dev_fwnode(pwr->dev->parent);
 920
 921	if (node) {
 922		int ret;
 923		u32 rs;
 924
 925		ret = fwnode_property_read_u32(node,
 926					       "rohm,charger-sense-resistor-micro-ohms",
 927					       &rs);
 928		if (ret) {
 929			if (ret == -EINVAL) {
 930				rs = RSENS_DEFAULT_30MOHM;
 931			} else {
 932				dev_err(pwr->dev, "Bad RSENS dt property\n");
 933				return ret;
 934			}
 935		}
 936		if (!rs) {
 937			dev_err(pwr->dev, "Bad RSENS value\n");
 938			return -EINVAL;
 939		}
 940
 941		rsens_ohm = (int)rs;
 942	}
 943
 944	/* Reg val to uA */
 945	do_div(tmp, rsens_ohm);
 946
 947	pwr->curr_factor = tmp;
 948	pwr->rsens = rsens_ohm;
 949	dev_dbg(pwr->dev, "Setting rsens to %u micro ohm\n", pwr->rsens);
 950	dev_dbg(pwr->dev, "Setting curr-factor to %u\n", pwr->curr_factor);
 951
 952	return 0;
 953}
 954
 955static int bd71828_power_probe(struct platform_device *pdev)
 956{
 957	struct bd71828_power *pwr;
 958	struct power_supply_config ac_cfg = {};
 959	struct power_supply_config bat_cfg = {};
 960	int ret;
 961	struct regmap *regmap;
 962
 963	regmap = dev_get_regmap(pdev->dev.parent, NULL);
 964	if (!regmap) {
 965		dev_err(&pdev->dev, "No parent regmap\n");
 966		return -EINVAL;
 967	}
 968
 969	pwr = devm_kzalloc(&pdev->dev, sizeof(*pwr), GFP_KERNEL);
 970	if (!pwr)
 971		return -ENOMEM;
 972
 973	pwr->regmap = regmap;
 974	pwr->dev = &pdev->dev;
 975	pwr->chip_type = platform_get_device_id(pdev)->driver_data;
 976
 977	switch (pwr->chip_type) {
 978	case ROHM_CHIP_TYPE_BD71828:
 979		pwr->bat_inserted = bd71828_bat_inserted;
 980		pwr->get_temp = bd71828_get_temp;
 981		pwr->regs = &pwr_regs_bd71828;
 982		break;
 983	case ROHM_CHIP_TYPE_BD71815:
 984		pwr->bat_inserted = bd71815_bat_inserted;
 985		pwr->get_temp = bd71815_get_temp;
 986		pwr->regs = &pwr_regs_bd71815;
 987		break;
 988	default:
 989		dev_err(pwr->dev, "Unknown PMIC\n");
 990		return -EINVAL;
 991	}
 992
 993	ret = bd7182x_get_rsens(pwr);
 994	if (ret)
 995		return dev_err_probe(&pdev->dev, ret, "sense resistor missing\n");
 996
 997	dev_set_drvdata(&pdev->dev, pwr);
 998	bd71828_init_hardware(pwr);
 999
1000	bat_cfg.drv_data	= pwr;
1001	bat_cfg.fwnode		= dev_fwnode(&pdev->dev);
1002
1003	ac_cfg.supplied_to	= bd71828_ac_supplied_to;
1004	ac_cfg.num_supplicants	= ARRAY_SIZE(bd71828_ac_supplied_to);
1005	ac_cfg.drv_data		= pwr;
1006
1007	pwr->ac = devm_power_supply_register(&pdev->dev, &bd71828_ac_desc,
1008					     &ac_cfg);
1009	if (IS_ERR(pwr->ac))
1010		return dev_err_probe(&pdev->dev, PTR_ERR(pwr->ac),
1011				     "failed to register ac\n");
1012
1013	pwr->bat = devm_power_supply_register(&pdev->dev, &bd71828_bat_desc,
1014					      &bat_cfg);
1015	if (IS_ERR(pwr->bat))
1016		return dev_err_probe(&pdev->dev, PTR_ERR(pwr->bat),
1017				     "failed to register bat\n");
1018
1019	ret = bd7182x_get_irqs(pdev, pwr);
1020	if (ret)
1021		return dev_err_probe(&pdev->dev, ret, "failed to request IRQs");
1022
1023	/* Configure wakeup capable */
1024	device_set_wakeup_capable(pwr->dev, 1);
1025	device_set_wakeup_enable(pwr->dev, 1);
1026
1027	return 0;
1028}
1029
1030static const struct platform_device_id bd71828_charger_id[] = {
1031	{ "bd71815-power", ROHM_CHIP_TYPE_BD71815 },
1032	{ "bd71828-power", ROHM_CHIP_TYPE_BD71828 },
1033	{ },
1034};
1035MODULE_DEVICE_TABLE(platform, bd71828_charger_id);
1036
1037static struct platform_driver bd71828_power_driver = {
1038	.driver = {
1039		.name = "bd718xx-power",
1040	},
1041	.probe = bd71828_power_probe,
1042	.id_table = bd71828_charger_id,
1043};
1044
1045module_platform_driver(bd71828_power_driver);
1046
1047MODULE_AUTHOR("Cong Pham <cpham2403@gmail.com>");
1048MODULE_DESCRIPTION("ROHM BD718(15/28/78) PMIC Battery Charger driver");
1049MODULE_LICENSE("GPL");
~/ Read-only file preview.