ip5xxx_power.c (16777B)
1// SPDX-License-Identifier: GPL-2.0 2// 3// Copyright (C) 2021 Samuel Holland <samuel@sholland.org> 4 5#include <linux/i2c.h> 6#include <linux/module.h> 7#include <linux/power_supply.h> 8#include <linux/regmap.h> 9 10#define IP5XXX_SYS_CTL0 0x01 11#define IP5XXX_SYS_CTL0_WLED_DET_EN BIT(4) 12#define IP5XXX_SYS_CTL0_WLED_EN BIT(3) 13#define IP5XXX_SYS_CTL0_BOOST_EN BIT(2) 14#define IP5XXX_SYS_CTL0_CHARGER_EN BIT(1) 15#define IP5XXX_SYS_CTL1 0x02 16#define IP5XXX_SYS_CTL1_LIGHT_SHDN_EN BIT(1) 17#define IP5XXX_SYS_CTL1_LOAD_PWRUP_EN BIT(0) 18#define IP5XXX_SYS_CTL2 0x0c 19#define IP5XXX_SYS_CTL2_LIGHT_SHDN_TH GENMASK(7, 3) 20#define IP5XXX_SYS_CTL3 0x03 21#define IP5XXX_SYS_CTL3_LONG_PRESS_TIME_SEL GENMASK(7, 6) 22#define IP5XXX_SYS_CTL3_BTN_SHDN_EN BIT(5) 23#define IP5XXX_SYS_CTL4 0x04 24#define IP5XXX_SYS_CTL4_SHDN_TIME_SEL GENMASK(7, 6) 25#define IP5XXX_SYS_CTL4_VIN_PULLOUT_BOOST_EN BIT(5) 26#define IP5XXX_SYS_CTL5 0x07 27#define IP5XXX_SYS_CTL5_NTC_DIS BIT(6) 28#define IP5XXX_SYS_CTL5_WLED_MODE_SEL BIT(1) 29#define IP5XXX_SYS_CTL5_BTN_SHDN_SEL BIT(0) 30#define IP5XXX_CHG_CTL1 0x22 31#define IP5XXX_CHG_CTL1_BOOST_UVP_SEL GENMASK(3, 2) 32#define IP5XXX_CHG_CTL2 0x24 33#define IP5XXX_CHG_CTL2_BAT_TYPE_SEL GENMASK(6, 5) 34#define IP5XXX_CHG_CTL2_BAT_TYPE_SEL_4_2V (0x0 << 5) 35#define IP5XXX_CHG_CTL2_BAT_TYPE_SEL_4_3V (0x1 << 5) 36#define IP5XXX_CHG_CTL2_BAT_TYPE_SEL_4_35V (0x2 << 5) 37#define IP5XXX_CHG_CTL2_CONST_VOLT_SEL GENMASK(2, 1) 38#define IP5XXX_CHG_CTL4 0x26 39#define IP5XXX_CHG_CTL4_BAT_TYPE_SEL_EN BIT(6) 40#define IP5XXX_CHG_CTL4A 0x25 41#define IP5XXX_CHG_CTL4A_CONST_CUR_SEL GENMASK(4, 0) 42#define IP5XXX_MFP_CTL0 0x51 43#define IP5XXX_MFP_CTL1 0x52 44#define IP5XXX_GPIO_CTL2 0x53 45#define IP5XXX_GPIO_CTL2A 0x54 46#define IP5XXX_GPIO_CTL3 0x55 47#define IP5XXX_READ0 0x71 48#define IP5XXX_READ0_CHG_STAT GENMASK(7, 5) 49#define IP5XXX_READ0_CHG_STAT_IDLE (0x0 << 5) 50#define IP5XXX_READ0_CHG_STAT_TRICKLE (0x1 << 5) 51#define IP5XXX_READ0_CHG_STAT_CONST_VOLT (0x2 << 5) 52#define IP5XXX_READ0_CHG_STAT_CONST_CUR (0x3 << 5) 53#define IP5XXX_READ0_CHG_STAT_CONST_VOLT_STOP (0x4 << 5) 54#define IP5XXX_READ0_CHG_STAT_FULL (0x5 << 5) 55#define IP5XXX_READ0_CHG_STAT_TIMEOUT (0x6 << 5) 56#define IP5XXX_READ0_CHG_OP BIT(4) 57#define IP5XXX_READ0_CHG_END BIT(3) 58#define IP5XXX_READ0_CONST_VOLT_TIMEOUT BIT(2) 59#define IP5XXX_READ0_CHG_TIMEOUT BIT(1) 60#define IP5XXX_READ0_TRICKLE_TIMEOUT BIT(0) 61#define IP5XXX_READ0_TIMEOUT GENMASK(2, 0) 62#define IP5XXX_READ1 0x72 63#define IP5XXX_READ1_WLED_PRESENT BIT(7) 64#define IP5XXX_READ1_LIGHT_LOAD BIT(6) 65#define IP5XXX_READ1_VIN_OVERVOLT BIT(5) 66#define IP5XXX_READ2 0x77 67#define IP5XXX_READ2_BTN_PRESS BIT(3) 68#define IP5XXX_READ2_BTN_LONG_PRESS BIT(1) 69#define IP5XXX_READ2_BTN_SHORT_PRESS BIT(0) 70#define IP5XXX_BATVADC_DAT0 0xa2 71#define IP5XXX_BATVADC_DAT1 0xa3 72#define IP5XXX_BATIADC_DAT0 0xa4 73#define IP5XXX_BATIADC_DAT1 0xa5 74#define IP5XXX_BATOCV_DAT0 0xa8 75#define IP5XXX_BATOCV_DAT1 0xa9 76 77struct ip5xxx { 78 struct regmap *regmap; 79 bool initialized; 80}; 81 82/* 83 * The IP5xxx charger only responds on I2C when it is "awake". The charger is 84 * generally only awake when VIN is powered or when its boost converter is 85 * enabled. Going into shutdown resets all register values. To handle this: 86 * 1) When any bus error occurs, assume the charger has gone into shutdown. 87 * 2) Attempt the initialization sequence on each subsequent register access 88 * until it succeeds. 89 */ 90static int ip5xxx_read(struct ip5xxx *ip5xxx, unsigned int reg, 91 unsigned int *val) 92{ 93 int ret; 94 95 ret = regmap_read(ip5xxx->regmap, reg, val); 96 if (ret) 97 ip5xxx->initialized = false; 98 99 return ret; 100} 101 102static int ip5xxx_update_bits(struct ip5xxx *ip5xxx, unsigned int reg, 103 unsigned int mask, unsigned int val) 104{ 105 int ret; 106 107 ret = regmap_update_bits(ip5xxx->regmap, reg, mask, val); 108 if (ret) 109 ip5xxx->initialized = false; 110 111 return ret; 112} 113 114static int ip5xxx_initialize(struct power_supply *psy) 115{ 116 struct ip5xxx *ip5xxx = power_supply_get_drvdata(psy); 117 int ret; 118 119 if (ip5xxx->initialized) 120 return 0; 121 122 /* 123 * Disable shutdown under light load. 124 * Enable power on when under load. 125 */ 126 ret = ip5xxx_update_bits(ip5xxx, IP5XXX_SYS_CTL1, 127 IP5XXX_SYS_CTL1_LIGHT_SHDN_EN | 128 IP5XXX_SYS_CTL1_LOAD_PWRUP_EN, 129 IP5XXX_SYS_CTL1_LOAD_PWRUP_EN); 130 if (ret) 131 return ret; 132 133 /* 134 * Enable shutdown after a long button press (as configured below). 135 */ 136 ret = ip5xxx_update_bits(ip5xxx, IP5XXX_SYS_CTL3, 137 IP5XXX_SYS_CTL3_BTN_SHDN_EN, 138 IP5XXX_SYS_CTL3_BTN_SHDN_EN); 139 if (ret) 140 return ret; 141 142 /* 143 * Power on automatically when VIN is removed. 144 */ 145 ret = ip5xxx_update_bits(ip5xxx, IP5XXX_SYS_CTL4, 146 IP5XXX_SYS_CTL4_VIN_PULLOUT_BOOST_EN, 147 IP5XXX_SYS_CTL4_VIN_PULLOUT_BOOST_EN); 148 if (ret) 149 return ret; 150 151 /* 152 * Enable the NTC. 153 * Configure the button for two presses => LED, long press => shutdown. 154 */ 155 ret = ip5xxx_update_bits(ip5xxx, IP5XXX_SYS_CTL5, 156 IP5XXX_SYS_CTL5_NTC_DIS | 157 IP5XXX_SYS_CTL5_WLED_MODE_SEL | 158 IP5XXX_SYS_CTL5_BTN_SHDN_SEL, 159 IP5XXX_SYS_CTL5_WLED_MODE_SEL | 160 IP5XXX_SYS_CTL5_BTN_SHDN_SEL); 161 if (ret) 162 return ret; 163 164 ip5xxx->initialized = true; 165 dev_dbg(psy->dev.parent, "Initialized after power on\n"); 166 167 return 0; 168} 169 170static const enum power_supply_property ip5xxx_battery_properties[] = { 171 POWER_SUPPLY_PROP_STATUS, 172 POWER_SUPPLY_PROP_CHARGE_TYPE, 173 POWER_SUPPLY_PROP_HEALTH, 174 POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, 175 POWER_SUPPLY_PROP_VOLTAGE_NOW, 176 POWER_SUPPLY_PROP_VOLTAGE_OCV, 177 POWER_SUPPLY_PROP_CURRENT_NOW, 178 POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT, 179 POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, 180 POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, 181 POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX, 182}; 183 184static int ip5xxx_battery_get_status(struct ip5xxx *ip5xxx, int *val) 185{ 186 unsigned int rval; 187 int ret; 188 189 ret = ip5xxx_read(ip5xxx, IP5XXX_READ0, &rval); 190 if (ret) 191 return ret; 192 193 switch (rval & IP5XXX_READ0_CHG_STAT) { 194 case IP5XXX_READ0_CHG_STAT_IDLE: 195 *val = POWER_SUPPLY_STATUS_DISCHARGING; 196 break; 197 case IP5XXX_READ0_CHG_STAT_TRICKLE: 198 case IP5XXX_READ0_CHG_STAT_CONST_CUR: 199 case IP5XXX_READ0_CHG_STAT_CONST_VOLT: 200 *val = POWER_SUPPLY_STATUS_CHARGING; 201 break; 202 case IP5XXX_READ0_CHG_STAT_CONST_VOLT_STOP: 203 case IP5XXX_READ0_CHG_STAT_FULL: 204 *val = POWER_SUPPLY_STATUS_FULL; 205 break; 206 case IP5XXX_READ0_CHG_STAT_TIMEOUT: 207 *val = POWER_SUPPLY_STATUS_NOT_CHARGING; 208 break; 209 default: 210 return -EINVAL; 211 } 212 213 return 0; 214} 215 216static int ip5xxx_battery_get_charge_type(struct ip5xxx *ip5xxx, int *val) 217{ 218 unsigned int rval; 219 int ret; 220 221 ret = ip5xxx_read(ip5xxx, IP5XXX_READ0, &rval); 222 if (ret) 223 return ret; 224 225 switch (rval & IP5XXX_READ0_CHG_STAT) { 226 case IP5XXX_READ0_CHG_STAT_IDLE: 227 case IP5XXX_READ0_CHG_STAT_CONST_VOLT_STOP: 228 case IP5XXX_READ0_CHG_STAT_FULL: 229 case IP5XXX_READ0_CHG_STAT_TIMEOUT: 230 *val = POWER_SUPPLY_CHARGE_TYPE_NONE; 231 break; 232 case IP5XXX_READ0_CHG_STAT_TRICKLE: 233 *val = POWER_SUPPLY_CHARGE_TYPE_TRICKLE; 234 break; 235 case IP5XXX_READ0_CHG_STAT_CONST_CUR: 236 case IP5XXX_READ0_CHG_STAT_CONST_VOLT: 237 *val = POWER_SUPPLY_CHARGE_TYPE_STANDARD; 238 break; 239 default: 240 return -EINVAL; 241 } 242 243 return 0; 244} 245 246static int ip5xxx_battery_get_health(struct ip5xxx *ip5xxx, int *val) 247{ 248 unsigned int rval; 249 int ret; 250 251 ret = ip5xxx_read(ip5xxx, IP5XXX_READ0, &rval); 252 if (ret) 253 return ret; 254 255 if (rval & IP5XXX_READ0_TIMEOUT) 256 *val = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE; 257 else 258 *val = POWER_SUPPLY_HEALTH_GOOD; 259 260 return 0; 261} 262 263static int ip5xxx_battery_get_voltage_max(struct ip5xxx *ip5xxx, int *val) 264{ 265 unsigned int rval; 266 int ret; 267 268 ret = ip5xxx_read(ip5xxx, IP5XXX_CHG_CTL2, &rval); 269 if (ret) 270 return ret; 271 272 /* 273 * It is not clear what this will return if 274 * IP5XXX_CHG_CTL4_BAT_TYPE_SEL_EN is not set... 275 */ 276 switch (rval & IP5XXX_CHG_CTL2_BAT_TYPE_SEL) { 277 case IP5XXX_CHG_CTL2_BAT_TYPE_SEL_4_2V: 278 *val = 4200000; 279 break; 280 case IP5XXX_CHG_CTL2_BAT_TYPE_SEL_4_3V: 281 *val = 4300000; 282 break; 283 case IP5XXX_CHG_CTL2_BAT_TYPE_SEL_4_35V: 284 *val = 4350000; 285 break; 286 default: 287 return -EINVAL; 288 } 289 290 return 0; 291} 292 293static int ip5xxx_battery_read_adc(struct ip5xxx *ip5xxx, 294 u8 lo_reg, u8 hi_reg, int *val) 295{ 296 unsigned int hi, lo; 297 int ret; 298 299 ret = ip5xxx_read(ip5xxx, lo_reg, &lo); 300 if (ret) 301 return ret; 302 303 ret = ip5xxx_read(ip5xxx, hi_reg, &hi); 304 if (ret) 305 return ret; 306 307 *val = sign_extend32(hi << 8 | lo, 13); 308 309 return 0; 310} 311 312static int ip5xxx_battery_get_property(struct power_supply *psy, 313 enum power_supply_property psp, 314 union power_supply_propval *val) 315{ 316 struct ip5xxx *ip5xxx = power_supply_get_drvdata(psy); 317 int raw, ret, vmax; 318 unsigned int rval; 319 320 ret = ip5xxx_initialize(psy); 321 if (ret) 322 return ret; 323 324 switch (psp) { 325 case POWER_SUPPLY_PROP_STATUS: 326 return ip5xxx_battery_get_status(ip5xxx, &val->intval); 327 328 case POWER_SUPPLY_PROP_CHARGE_TYPE: 329 return ip5xxx_battery_get_charge_type(ip5xxx, &val->intval); 330 331 case POWER_SUPPLY_PROP_HEALTH: 332 return ip5xxx_battery_get_health(ip5xxx, &val->intval); 333 334 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: 335 return ip5xxx_battery_get_voltage_max(ip5xxx, &val->intval); 336 337 case POWER_SUPPLY_PROP_VOLTAGE_NOW: 338 ret = ip5xxx_battery_read_adc(ip5xxx, IP5XXX_BATVADC_DAT0, 339 IP5XXX_BATVADC_DAT1, &raw); 340 341 val->intval = 2600000 + DIV_ROUND_CLOSEST(raw * 26855, 100); 342 return 0; 343 344 case POWER_SUPPLY_PROP_VOLTAGE_OCV: 345 ret = ip5xxx_battery_read_adc(ip5xxx, IP5XXX_BATOCV_DAT0, 346 IP5XXX_BATOCV_DAT1, &raw); 347 348 val->intval = 2600000 + DIV_ROUND_CLOSEST(raw * 26855, 100); 349 return 0; 350 351 case POWER_SUPPLY_PROP_CURRENT_NOW: 352 ret = ip5xxx_battery_read_adc(ip5xxx, IP5XXX_BATIADC_DAT0, 353 IP5XXX_BATIADC_DAT1, &raw); 354 355 val->intval = DIV_ROUND_CLOSEST(raw * 745985, 1000); 356 return 0; 357 358 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: 359 ret = ip5xxx_read(ip5xxx, IP5XXX_CHG_CTL4A, &rval); 360 if (ret) 361 return ret; 362 363 rval &= IP5XXX_CHG_CTL4A_CONST_CUR_SEL; 364 val->intval = 100000 * rval; 365 return 0; 366 367 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: 368 val->intval = 100000 * 0x1f; 369 return 0; 370 371 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: 372 ret = ip5xxx_battery_get_voltage_max(ip5xxx, &vmax); 373 if (ret) 374 return ret; 375 376 ret = ip5xxx_read(ip5xxx, IP5XXX_CHG_CTL2, &rval); 377 if (ret) 378 return ret; 379 380 rval &= IP5XXX_CHG_CTL2_CONST_VOLT_SEL; 381 val->intval = vmax + 14000 * (rval >> 1); 382 return 0; 383 384 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX: 385 ret = ip5xxx_battery_get_voltage_max(ip5xxx, &vmax); 386 if (ret) 387 return ret; 388 389 val->intval = vmax + 14000 * 3; 390 return 0; 391 392 default: 393 return -EINVAL; 394 } 395} 396 397static int ip5xxx_battery_set_voltage_max(struct ip5xxx *ip5xxx, int val) 398{ 399 unsigned int rval; 400 int ret; 401 402 switch (val) { 403 case 4200000: 404 rval = IP5XXX_CHG_CTL2_BAT_TYPE_SEL_4_2V; 405 break; 406 case 4300000: 407 rval = IP5XXX_CHG_CTL2_BAT_TYPE_SEL_4_3V; 408 break; 409 case 4350000: 410 rval = IP5XXX_CHG_CTL2_BAT_TYPE_SEL_4_35V; 411 break; 412 default: 413 return -EINVAL; 414 } 415 416 ret = ip5xxx_update_bits(ip5xxx, IP5XXX_CHG_CTL2, 417 IP5XXX_CHG_CTL2_BAT_TYPE_SEL, rval); 418 if (ret) 419 return ret; 420 421 ret = ip5xxx_update_bits(ip5xxx, IP5XXX_CHG_CTL4, 422 IP5XXX_CHG_CTL4_BAT_TYPE_SEL_EN, 423 IP5XXX_CHG_CTL4_BAT_TYPE_SEL_EN); 424 if (ret) 425 return ret; 426 427 return 0; 428} 429 430static int ip5xxx_battery_set_property(struct power_supply *psy, 431 enum power_supply_property psp, 432 const union power_supply_propval *val) 433{ 434 struct ip5xxx *ip5xxx = power_supply_get_drvdata(psy); 435 unsigned int rval; 436 int ret, vmax; 437 438 ret = ip5xxx_initialize(psy); 439 if (ret) 440 return ret; 441 442 switch (psp) { 443 case POWER_SUPPLY_PROP_STATUS: 444 switch (val->intval) { 445 case POWER_SUPPLY_STATUS_CHARGING: 446 rval = IP5XXX_SYS_CTL0_CHARGER_EN; 447 break; 448 case POWER_SUPPLY_STATUS_DISCHARGING: 449 case POWER_SUPPLY_STATUS_NOT_CHARGING: 450 rval = 0; 451 break; 452 default: 453 return -EINVAL; 454 } 455 return ip5xxx_update_bits(ip5xxx, IP5XXX_SYS_CTL0, 456 IP5XXX_SYS_CTL0_CHARGER_EN, rval); 457 458 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: 459 return ip5xxx_battery_set_voltage_max(ip5xxx, val->intval); 460 461 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: 462 rval = val->intval / 100000; 463 return ip5xxx_update_bits(ip5xxx, IP5XXX_CHG_CTL4A, 464 IP5XXX_CHG_CTL4A_CONST_CUR_SEL, rval); 465 466 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: 467 ret = ip5xxx_battery_get_voltage_max(ip5xxx, &vmax); 468 if (ret) 469 return ret; 470 471 rval = ((val->intval - vmax) / 14000) << 1; 472 return ip5xxx_update_bits(ip5xxx, IP5XXX_CHG_CTL2, 473 IP5XXX_CHG_CTL2_CONST_VOLT_SEL, rval); 474 475 default: 476 return -EINVAL; 477 } 478} 479 480static int ip5xxx_battery_property_is_writeable(struct power_supply *psy, 481 enum power_supply_property psp) 482{ 483 return psp == POWER_SUPPLY_PROP_STATUS || 484 psp == POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN || 485 psp == POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT || 486 psp == POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE; 487} 488 489static const struct power_supply_desc ip5xxx_battery_desc = { 490 .name = "ip5xxx-battery", 491 .type = POWER_SUPPLY_TYPE_BATTERY, 492 .properties = ip5xxx_battery_properties, 493 .num_properties = ARRAY_SIZE(ip5xxx_battery_properties), 494 .get_property = ip5xxx_battery_get_property, 495 .set_property = ip5xxx_battery_set_property, 496 .property_is_writeable = ip5xxx_battery_property_is_writeable, 497}; 498 499static const enum power_supply_property ip5xxx_boost_properties[] = { 500 POWER_SUPPLY_PROP_ONLINE, 501 POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, 502}; 503 504static int ip5xxx_boost_get_property(struct power_supply *psy, 505 enum power_supply_property psp, 506 union power_supply_propval *val) 507{ 508 struct ip5xxx *ip5xxx = power_supply_get_drvdata(psy); 509 unsigned int rval; 510 int ret; 511 512 ret = ip5xxx_initialize(psy); 513 if (ret) 514 return ret; 515 516 switch (psp) { 517 case POWER_SUPPLY_PROP_ONLINE: 518 ret = ip5xxx_read(ip5xxx, IP5XXX_SYS_CTL0, &rval); 519 if (ret) 520 return ret; 521 522 val->intval = !!(rval & IP5XXX_SYS_CTL0_BOOST_EN); 523 return 0; 524 525 case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: 526 ret = ip5xxx_read(ip5xxx, IP5XXX_CHG_CTL1, &rval); 527 if (ret) 528 return ret; 529 530 rval &= IP5XXX_CHG_CTL1_BOOST_UVP_SEL; 531 val->intval = 4530000 + 100000 * (rval >> 2); 532 return 0; 533 534 default: 535 return -EINVAL; 536 } 537} 538 539static int ip5xxx_boost_set_property(struct power_supply *psy, 540 enum power_supply_property psp, 541 const union power_supply_propval *val) 542{ 543 struct ip5xxx *ip5xxx = power_supply_get_drvdata(psy); 544 unsigned int rval; 545 int ret; 546 547 ret = ip5xxx_initialize(psy); 548 if (ret) 549 return ret; 550 551 switch (psp) { 552 case POWER_SUPPLY_PROP_ONLINE: 553 rval = val->intval ? IP5XXX_SYS_CTL0_BOOST_EN : 0; 554 return ip5xxx_update_bits(ip5xxx, IP5XXX_SYS_CTL0, 555 IP5XXX_SYS_CTL0_BOOST_EN, rval); 556 557 case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: 558 rval = ((val->intval - 4530000) / 100000) << 2; 559 return ip5xxx_update_bits(ip5xxx, IP5XXX_CHG_CTL1, 560 IP5XXX_CHG_CTL1_BOOST_UVP_SEL, rval); 561 562 default: 563 return -EINVAL; 564 } 565} 566 567static int ip5xxx_boost_property_is_writeable(struct power_supply *psy, 568 enum power_supply_property psp) 569{ 570 return true; 571} 572 573static const struct power_supply_desc ip5xxx_boost_desc = { 574 .name = "ip5xxx-boost", 575 .type = POWER_SUPPLY_TYPE_USB, 576 .properties = ip5xxx_boost_properties, 577 .num_properties = ARRAY_SIZE(ip5xxx_boost_properties), 578 .get_property = ip5xxx_boost_get_property, 579 .set_property = ip5xxx_boost_set_property, 580 .property_is_writeable = ip5xxx_boost_property_is_writeable, 581}; 582 583static const struct regmap_config ip5xxx_regmap_config = { 584 .reg_bits = 8, 585 .val_bits = 8, 586 .max_register = IP5XXX_BATOCV_DAT1, 587}; 588 589static int ip5xxx_power_probe(struct i2c_client *client) 590{ 591 struct power_supply_config psy_cfg = {}; 592 struct device *dev = &client->dev; 593 struct power_supply *psy; 594 struct ip5xxx *ip5xxx; 595 596 ip5xxx = devm_kzalloc(dev, sizeof(*ip5xxx), GFP_KERNEL); 597 if (!ip5xxx) 598 return -ENOMEM; 599 600 ip5xxx->regmap = devm_regmap_init_i2c(client, &ip5xxx_regmap_config); 601 if (IS_ERR(ip5xxx->regmap)) 602 return PTR_ERR(ip5xxx->regmap); 603 604 psy_cfg.of_node = dev->of_node; 605 psy_cfg.drv_data = ip5xxx; 606 607 psy = devm_power_supply_register(dev, &ip5xxx_battery_desc, &psy_cfg); 608 if (IS_ERR(psy)) 609 return PTR_ERR(psy); 610 611 psy = devm_power_supply_register(dev, &ip5xxx_boost_desc, &psy_cfg); 612 if (IS_ERR(psy)) 613 return PTR_ERR(psy); 614 615 return 0; 616} 617 618static const struct of_device_id ip5xxx_power_of_match[] = { 619 { .compatible = "injoinic,ip5108" }, 620 { .compatible = "injoinic,ip5109" }, 621 { .compatible = "injoinic,ip5207" }, 622 { .compatible = "injoinic,ip5209" }, 623 { } 624}; 625MODULE_DEVICE_TABLE(of, ip5xxx_power_of_match); 626 627static struct i2c_driver ip5xxx_power_driver = { 628 .probe_new = ip5xxx_power_probe, 629 .driver = { 630 .name = "ip5xxx-power", 631 .of_match_table = ip5xxx_power_of_match, 632 } 633}; 634module_i2c_driver(ip5xxx_power_driver); 635 636MODULE_AUTHOR("Samuel Holland <samuel@sholland.org>"); 637MODULE_DESCRIPTION("Injoinic IP5xxx power bank IC driver"); 638MODULE_LICENSE("GPL");