Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

power: supply: pf1550: add battery charger support

Add support for the battery charger for pf1550 PMIC.

Signed-off-by: Samuel Kayode <samuel.kayode@savoirfairelinux.com>
Acked-by: Sebastian Reichel <sebastian.reichel@collabora.com>
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Tested-by: Sean Nyekjaer <sean@geanix.com>
Link: https://patch.msgid.link/20251001-pf1550-v12-5-a3302aa41687@savoirfairelinux.com
Signed-off-by: Lee Jones <lee@kernel.org>

authored by

Samuel Kayode and committed by
Lee Jones
4b6b6433 9acb215c

+653
+11
drivers/power/supply/Kconfig
··· 486 486 help 487 487 Say Y here to enable charger for Marvell 88PM860x chip. 488 488 489 + config CHARGER_PF1550 490 + tristate "NXP PF1550 battery charger driver" 491 + depends on MFD_PF1550 492 + help 493 + Say Y to enable support for the NXP PF1550 battery charger. 494 + The device is a single cell Li-Ion/Li-Polymer battery charger for 495 + portable application. 496 + 497 + This driver can also be built as a module. If so, the module will be 498 + called pf1550-charger. 499 + 489 500 config BATTERY_RX51 490 501 tristate "Nokia RX-51 (N900) battery driver" 491 502 depends on TWL4030_MADC
+1
drivers/power/supply/Makefile
··· 66 66 obj-$(CONFIG_CHARGER_RT9471) += rt9471.o 67 67 obj-$(CONFIG_BATTERY_TWL4030_MADC) += twl4030_madc_battery.o 68 68 obj-$(CONFIG_CHARGER_88PM860X) += 88pm860x_charger.o 69 + obj-$(CONFIG_CHARGER_PF1550) += pf1550-charger.o 69 70 obj-$(CONFIG_BATTERY_RX51) += rx51_battery.o 70 71 obj-$(CONFIG_AB8500_BM) += ab8500_bmdata.o ab8500_charger.o ab8500_fg.o ab8500_btemp.o ab8500_chargalg.o 71 72 obj-$(CONFIG_CHARGER_CPCAP) += cpcap-charger.o
+641
drivers/power/supply/pf1550-charger.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * charger driver for the PF1550 4 + * 5 + * Copyright (C) 2016 Freescale Semiconductor, Inc. 6 + * Robin Gong <yibin.gong@freescale.com> 7 + * 8 + * Portions Copyright (c) 2025 Savoir-faire Linux Inc. 9 + * Samuel Kayode <samuel.kayode@savoirfairelinux.com> 10 + */ 11 + 12 + #include <linux/devm-helpers.h> 13 + #include <linux/interrupt.h> 14 + #include <linux/mfd/pf1550.h> 15 + #include <linux/module.h> 16 + #include <linux/platform_device.h> 17 + #include <linux/power_supply.h> 18 + 19 + #define PF1550_DEFAULT_CONSTANT_VOLT 4200000 20 + #define PF1550_DEFAULT_MIN_SYSTEM_VOLT 3500000 21 + #define PF1550_DEFAULT_THERMAL_TEMP 95 22 + #define PF1550_CHARGER_IRQ_NR 5 23 + 24 + struct pf1550_charger { 25 + struct device *dev; 26 + const struct pf1550_ddata *pf1550; 27 + struct power_supply *charger; 28 + struct power_supply *battery; 29 + struct delayed_work vbus_sense_work; 30 + struct delayed_work chg_sense_work; 31 + struct delayed_work bat_sense_work; 32 + int virqs[PF1550_CHARGER_IRQ_NR]; 33 + 34 + u32 constant_volt; 35 + u32 min_system_volt; 36 + u32 thermal_regulation_temp; 37 + }; 38 + 39 + static int pf1550_get_charger_state(struct regmap *regmap, int *val) 40 + { 41 + unsigned int data; 42 + int ret; 43 + 44 + ret = regmap_read(regmap, PF1550_CHARG_REG_CHG_SNS, &data); 45 + if (ret < 0) 46 + return ret; 47 + 48 + data &= PF1550_CHG_SNS_MASK; 49 + 50 + switch (data) { 51 + case PF1550_CHG_PRECHARGE: 52 + case PF1550_CHG_CONSTANT_CURRENT: 53 + case PF1550_CHG_CONSTANT_VOL: 54 + case PF1550_CHG_EOC: 55 + *val = POWER_SUPPLY_STATUS_CHARGING; 56 + break; 57 + case PF1550_CHG_DONE: 58 + *val = POWER_SUPPLY_STATUS_FULL; 59 + break; 60 + case PF1550_CHG_TIMER_FAULT: 61 + case PF1550_CHG_SUSPEND: 62 + *val = POWER_SUPPLY_STATUS_NOT_CHARGING; 63 + break; 64 + case PF1550_CHG_OFF_INV: 65 + case PF1550_CHG_OFF_TEMP: 66 + case PF1550_CHG_LINEAR_ONLY: 67 + *val = POWER_SUPPLY_STATUS_DISCHARGING; 68 + break; 69 + default: 70 + *val = POWER_SUPPLY_STATUS_UNKNOWN; 71 + } 72 + 73 + return 0; 74 + } 75 + 76 + static int pf1550_get_charge_type(struct regmap *regmap, int *val) 77 + { 78 + unsigned int data; 79 + int ret; 80 + 81 + ret = regmap_read(regmap, PF1550_CHARG_REG_CHG_SNS, &data); 82 + if (ret < 0) 83 + return ret; 84 + 85 + data &= PF1550_CHG_SNS_MASK; 86 + 87 + switch (data) { 88 + case PF1550_CHG_SNS_MASK: 89 + *val = POWER_SUPPLY_CHARGE_TYPE_TRICKLE; 90 + break; 91 + case PF1550_CHG_CONSTANT_CURRENT: 92 + case PF1550_CHG_CONSTANT_VOL: 93 + case PF1550_CHG_EOC: 94 + *val = POWER_SUPPLY_CHARGE_TYPE_FAST; 95 + break; 96 + case PF1550_CHG_DONE: 97 + case PF1550_CHG_TIMER_FAULT: 98 + case PF1550_CHG_SUSPEND: 99 + case PF1550_CHG_OFF_INV: 100 + case PF1550_CHG_BAT_OVER: 101 + case PF1550_CHG_OFF_TEMP: 102 + case PF1550_CHG_LINEAR_ONLY: 103 + *val = POWER_SUPPLY_CHARGE_TYPE_NONE; 104 + break; 105 + default: 106 + *val = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN; 107 + } 108 + 109 + return 0; 110 + } 111 + 112 + /* 113 + * Supported health statuses: 114 + * - POWER_SUPPLY_HEALTH_DEAD 115 + * - POWER_SUPPLY_HEALTH_GOOD 116 + * - POWER_SUPPLY_HEALTH_OVERVOLTAGE 117 + * - POWER_SUPPLY_HEALTH_UNKNOWN 118 + */ 119 + static int pf1550_get_battery_health(struct regmap *regmap, int *val) 120 + { 121 + unsigned int data; 122 + int ret; 123 + 124 + ret = regmap_read(regmap, PF1550_CHARG_REG_BATT_SNS, &data); 125 + if (ret < 0) 126 + return ret; 127 + 128 + data &= PF1550_BAT_SNS_MASK; 129 + 130 + switch (data) { 131 + case PF1550_BAT_NO_DETECT: 132 + *val = POWER_SUPPLY_HEALTH_NO_BATTERY; 133 + break; 134 + case PF1550_BAT_NO_VBUS: 135 + case PF1550_BAT_LOW_THAN_PRECHARG: 136 + case PF1550_BAT_CHARG_FAIL: 137 + case PF1550_BAT_HIGH_THAN_PRECHARG: 138 + *val = POWER_SUPPLY_HEALTH_GOOD; 139 + break; 140 + case PF1550_BAT_OVER_VOL: 141 + *val = POWER_SUPPLY_HEALTH_OVERVOLTAGE; 142 + break; 143 + default: 144 + *val = POWER_SUPPLY_HEALTH_UNKNOWN; 145 + break; 146 + } 147 + 148 + return 0; 149 + } 150 + 151 + static int pf1550_get_present(struct regmap *regmap, int *val) 152 + { 153 + unsigned int data; 154 + int ret; 155 + 156 + ret = regmap_read(regmap, PF1550_CHARG_REG_BATT_SNS, &data); 157 + if (ret < 0) 158 + return ret; 159 + 160 + data &= PF1550_BAT_SNS_MASK; 161 + *val = (data == PF1550_BAT_NO_DETECT) ? 0 : 1; 162 + 163 + return 0; 164 + } 165 + 166 + static int pf1550_get_online(struct regmap *regmap, int *val) 167 + { 168 + unsigned int data; 169 + int ret; 170 + 171 + ret = regmap_read(regmap, PF1550_CHARG_REG_VBUS_SNS, &data); 172 + if (ret < 0) 173 + return ret; 174 + 175 + *val = (data & PF1550_VBUS_VALID) ? 1 : 0; 176 + 177 + return 0; 178 + } 179 + 180 + static void pf1550_chg_bat_work(struct work_struct *work) 181 + { 182 + struct pf1550_charger *chg = container_of(to_delayed_work(work), 183 + struct pf1550_charger, 184 + bat_sense_work); 185 + unsigned int data; 186 + 187 + if (regmap_read(chg->pf1550->regmap, PF1550_CHARG_REG_BATT_SNS, &data)) { 188 + dev_err(chg->dev, "Read BATT_SNS error.\n"); 189 + return; 190 + } 191 + 192 + switch (data & PF1550_BAT_SNS_MASK) { 193 + case PF1550_BAT_NO_VBUS: 194 + dev_dbg(chg->dev, "No valid VBUS input.\n"); 195 + break; 196 + case PF1550_BAT_LOW_THAN_PRECHARG: 197 + dev_dbg(chg->dev, "VBAT < VPRECHG.LB.\n"); 198 + break; 199 + case PF1550_BAT_CHARG_FAIL: 200 + dev_dbg(chg->dev, "Battery charging failed.\n"); 201 + break; 202 + case PF1550_BAT_HIGH_THAN_PRECHARG: 203 + dev_dbg(chg->dev, "VBAT > VPRECHG.LB.\n"); 204 + break; 205 + case PF1550_BAT_OVER_VOL: 206 + dev_dbg(chg->dev, "VBAT > VBATOV.\n"); 207 + break; 208 + case PF1550_BAT_NO_DETECT: 209 + dev_dbg(chg->dev, "Battery not detected.\n"); 210 + break; 211 + default: 212 + dev_err(chg->dev, "Unknown value read:%x\n", 213 + data & PF1550_CHG_SNS_MASK); 214 + } 215 + } 216 + 217 + static void pf1550_chg_chg_work(struct work_struct *work) 218 + { 219 + struct pf1550_charger *chg = container_of(to_delayed_work(work), 220 + struct pf1550_charger, 221 + chg_sense_work); 222 + unsigned int data; 223 + 224 + if (regmap_read(chg->pf1550->regmap, PF1550_CHARG_REG_CHG_SNS, &data)) { 225 + dev_err(chg->dev, "Read CHG_SNS error.\n"); 226 + return; 227 + } 228 + 229 + switch (data & PF1550_CHG_SNS_MASK) { 230 + case PF1550_CHG_PRECHARGE: 231 + dev_dbg(chg->dev, "In pre-charger mode.\n"); 232 + break; 233 + case PF1550_CHG_CONSTANT_CURRENT: 234 + dev_dbg(chg->dev, "In fast-charge constant current mode.\n"); 235 + break; 236 + case PF1550_CHG_CONSTANT_VOL: 237 + dev_dbg(chg->dev, "In fast-charge constant voltage mode.\n"); 238 + break; 239 + case PF1550_CHG_EOC: 240 + dev_dbg(chg->dev, "In EOC mode.\n"); 241 + break; 242 + case PF1550_CHG_DONE: 243 + dev_dbg(chg->dev, "In DONE mode.\n"); 244 + break; 245 + case PF1550_CHG_TIMER_FAULT: 246 + dev_info(chg->dev, "In timer fault mode.\n"); 247 + break; 248 + case PF1550_CHG_SUSPEND: 249 + dev_info(chg->dev, "In thermistor suspend mode.\n"); 250 + break; 251 + case PF1550_CHG_OFF_INV: 252 + dev_info(chg->dev, "Input invalid, charger off.\n"); 253 + break; 254 + case PF1550_CHG_BAT_OVER: 255 + dev_warn(chg->dev, "Battery over-voltage.\n"); 256 + break; 257 + case PF1550_CHG_OFF_TEMP: 258 + dev_info(chg->dev, "Temp high, charger off.\n"); 259 + break; 260 + case PF1550_CHG_LINEAR_ONLY: 261 + dev_dbg(chg->dev, "In Linear mode, not charging.\n"); 262 + break; 263 + default: 264 + dev_err(chg->dev, "Unknown value read:%x\n", 265 + data & PF1550_CHG_SNS_MASK); 266 + } 267 + } 268 + 269 + static void pf1550_chg_vbus_work(struct work_struct *work) 270 + { 271 + struct pf1550_charger *chg = container_of(to_delayed_work(work), 272 + struct pf1550_charger, 273 + vbus_sense_work); 274 + unsigned int data; 275 + 276 + if (regmap_read(chg->pf1550->regmap, PF1550_CHARG_REG_VBUS_SNS, &data)) { 277 + dev_err(chg->dev, "Read VBUS_SNS error.\n"); 278 + return; 279 + } 280 + 281 + if (data & PF1550_VBUS_UVLO) { 282 + dev_dbg(chg->dev, "VBUS detached.\n"); 283 + power_supply_changed(chg->battery); 284 + } 285 + if (data & PF1550_VBUS_IN2SYS) 286 + dev_dbg(chg->dev, "VBUS_IN2SYS_SNS.\n"); 287 + if (data & PF1550_VBUS_OVLO) 288 + dev_dbg(chg->dev, "VBUS_OVLO_SNS.\n"); 289 + if (data & PF1550_VBUS_VALID) { 290 + dev_dbg(chg->dev, "VBUS attached.\n"); 291 + power_supply_changed(chg->charger); 292 + } 293 + } 294 + 295 + static irqreturn_t pf1550_charger_irq_handler(int irq, void *data) 296 + { 297 + struct pf1550_charger *chg = data; 298 + struct device *dev = chg->dev; 299 + int i, irq_type = -1; 300 + 301 + for (i = 0; i < PF1550_CHARGER_IRQ_NR; i++) 302 + if (irq == chg->virqs[i]) 303 + irq_type = i; 304 + 305 + switch (irq_type) { 306 + case PF1550_CHARG_IRQ_BAT2SOCI: 307 + dev_info(dev, "BAT to SYS Overcurrent interrupt.\n"); 308 + break; 309 + case PF1550_CHARG_IRQ_BATI: 310 + schedule_delayed_work(&chg->bat_sense_work, 311 + msecs_to_jiffies(10)); 312 + break; 313 + case PF1550_CHARG_IRQ_CHGI: 314 + schedule_delayed_work(&chg->chg_sense_work, 315 + msecs_to_jiffies(10)); 316 + break; 317 + case PF1550_CHARG_IRQ_VBUSI: 318 + schedule_delayed_work(&chg->vbus_sense_work, 319 + msecs_to_jiffies(10)); 320 + break; 321 + case PF1550_CHARG_IRQ_THMI: 322 + dev_info(dev, "Thermal interrupt.\n"); 323 + break; 324 + default: 325 + dev_err(dev, "unknown interrupt occurred.\n"); 326 + } 327 + 328 + return IRQ_HANDLED; 329 + } 330 + 331 + static enum power_supply_property pf1550_charger_props[] = { 332 + POWER_SUPPLY_PROP_ONLINE, 333 + POWER_SUPPLY_PROP_MODEL_NAME, 334 + POWER_SUPPLY_PROP_MANUFACTURER, 335 + }; 336 + 337 + static enum power_supply_property pf1550_battery_props[] = { 338 + POWER_SUPPLY_PROP_STATUS, 339 + POWER_SUPPLY_PROP_CHARGE_TYPE, 340 + POWER_SUPPLY_PROP_HEALTH, 341 + POWER_SUPPLY_PROP_PRESENT, 342 + POWER_SUPPLY_PROP_MODEL_NAME, 343 + POWER_SUPPLY_PROP_MANUFACTURER, 344 + }; 345 + 346 + static int pf1550_charger_get_property(struct power_supply *psy, 347 + enum power_supply_property psp, 348 + union power_supply_propval *val) 349 + { 350 + struct pf1550_charger *chg = power_supply_get_drvdata(psy); 351 + struct regmap *regmap = chg->pf1550->regmap; 352 + int ret = 0; 353 + 354 + switch (psp) { 355 + case POWER_SUPPLY_PROP_STATUS: 356 + ret = pf1550_get_charger_state(regmap, &val->intval); 357 + break; 358 + case POWER_SUPPLY_PROP_CHARGE_TYPE: 359 + ret = pf1550_get_charge_type(regmap, &val->intval); 360 + break; 361 + case POWER_SUPPLY_PROP_HEALTH: 362 + ret = pf1550_get_battery_health(regmap, &val->intval); 363 + break; 364 + case POWER_SUPPLY_PROP_PRESENT: 365 + ret = pf1550_get_present(regmap, &val->intval); 366 + break; 367 + case POWER_SUPPLY_PROP_ONLINE: 368 + ret = pf1550_get_online(regmap, &val->intval); 369 + break; 370 + case POWER_SUPPLY_PROP_MODEL_NAME: 371 + val->strval = "PF1550"; 372 + break; 373 + case POWER_SUPPLY_PROP_MANUFACTURER: 374 + val->strval = "NXP"; 375 + break; 376 + default: 377 + return -EINVAL; 378 + } 379 + 380 + return ret; 381 + } 382 + 383 + static const struct power_supply_desc pf1550_charger_desc = { 384 + .name = "pf1550-charger", 385 + .type = POWER_SUPPLY_TYPE_MAINS, 386 + .properties = pf1550_charger_props, 387 + .num_properties = ARRAY_SIZE(pf1550_charger_props), 388 + .get_property = pf1550_charger_get_property, 389 + }; 390 + 391 + static const struct power_supply_desc pf1550_battery_desc = { 392 + .name = "pf1550-battery", 393 + .type = POWER_SUPPLY_TYPE_BATTERY, 394 + .properties = pf1550_battery_props, 395 + .num_properties = ARRAY_SIZE(pf1550_battery_props), 396 + .get_property = pf1550_charger_get_property, 397 + }; 398 + 399 + static int pf1550_set_constant_volt(struct pf1550_charger *chg, 400 + unsigned int uvolt) 401 + { 402 + unsigned int data; 403 + 404 + if (uvolt >= 3500000 && uvolt <= 4440000) 405 + data = 8 + (uvolt - 3500000) / 20000; 406 + else 407 + return dev_err_probe(chg->dev, -EINVAL, 408 + "Wrong value for constant voltage\n"); 409 + 410 + dev_dbg(chg->dev, "Charging constant voltage: %u (0x%x)\n", uvolt, 411 + data); 412 + 413 + return regmap_update_bits(chg->pf1550->regmap, 414 + PF1550_CHARG_REG_BATT_REG, 415 + PF1550_CHARG_REG_BATT_REG_CHGCV_MASK, data); 416 + } 417 + 418 + static int pf1550_set_min_system_volt(struct pf1550_charger *chg, 419 + unsigned int uvolt) 420 + { 421 + unsigned int data; 422 + 423 + switch (uvolt) { 424 + case 3500000: 425 + data = 0x0; 426 + break; 427 + case 3700000: 428 + data = 0x1; 429 + break; 430 + case 4300000: 431 + data = 0x2; 432 + break; 433 + default: 434 + return dev_err_probe(chg->dev, -EINVAL, 435 + "Wrong value for minimum system voltage\n"); 436 + } 437 + 438 + data <<= PF1550_CHARG_REG_BATT_REG_VMINSYS_SHIFT; 439 + 440 + dev_dbg(chg->dev, "Minimum system regulation voltage: %u (0x%x)\n", 441 + uvolt, data); 442 + 443 + return regmap_update_bits(chg->pf1550->regmap, 444 + PF1550_CHARG_REG_BATT_REG, 445 + PF1550_CHARG_REG_BATT_REG_VMINSYS_MASK, data); 446 + } 447 + 448 + static int pf1550_set_thermal_regulation_temp(struct pf1550_charger *chg, 449 + unsigned int cells) 450 + { 451 + unsigned int data; 452 + 453 + switch (cells) { 454 + case 80: 455 + data = 0x0; 456 + break; 457 + case 95: 458 + data = 0x1; 459 + break; 460 + case 110: 461 + data = 0x2; 462 + break; 463 + case 125: 464 + data = 0x3; 465 + break; 466 + default: 467 + return dev_err_probe(chg->dev, -EINVAL, 468 + "Wrong value for thermal temperature\n"); 469 + } 470 + 471 + data <<= PF1550_CHARG_REG_THM_REG_CNFG_REGTEMP_SHIFT; 472 + 473 + dev_dbg(chg->dev, "Thermal regulation loop temperature: %u (0x%x)\n", 474 + cells, data); 475 + 476 + return regmap_update_bits(chg->pf1550->regmap, 477 + PF1550_CHARG_REG_THM_REG_CNFG, 478 + PF1550_CHARG_REG_THM_REG_CNFG_REGTEMP_MASK, 479 + data); 480 + } 481 + 482 + /* 483 + * Sets charger registers to proper and safe default values. 484 + */ 485 + static int pf1550_reg_init(struct pf1550_charger *chg) 486 + { 487 + struct power_supply_battery_info *info; 488 + struct device *dev = chg->dev; 489 + int ret; 490 + 491 + /* Unmask charger interrupt, mask DPMI and reserved bit */ 492 + ret = regmap_write(chg->pf1550->regmap, PF1550_CHARG_REG_CHG_INT_MASK, 493 + PF1550_CHG_INT_MASK); 494 + if (ret) 495 + return dev_err_probe(dev, ret, 496 + "Error unmask charger interrupt\n"); 497 + 498 + ret = pf1550_set_constant_volt(chg, chg->constant_volt); 499 + if (ret) 500 + return ret; 501 + 502 + ret = pf1550_set_min_system_volt(chg, chg->min_system_volt); 503 + if (ret) 504 + return ret; 505 + 506 + ret = pf1550_set_thermal_regulation_temp(chg, 507 + chg->thermal_regulation_temp); 508 + if (ret) 509 + return ret; 510 + 511 + /* 512 + * The PF1550 charger has 3 modes of operation. By default, the charger 513 + * is in mode 1; it remains off. Appropriate for applications not using 514 + * a battery. The other supported mode is mode 2, the charger is turned 515 + * on to charge a battery when present. 516 + */ 517 + if (power_supply_get_battery_info(chg->charger, &info)) { 518 + ret = regmap_write(chg->pf1550->regmap, 519 + PF1550_CHARG_REG_CHG_OPER, 520 + PF1550_CHG_BAT_ON); 521 + if (ret) 522 + return dev_err_probe(dev, ret, 523 + "Error turn on charger\n"); 524 + } 525 + 526 + return 0; 527 + } 528 + 529 + static void pf1550_dt_parse_dev_info(struct pf1550_charger *chg) 530 + { 531 + struct power_supply_battery_info *info; 532 + struct device *dev = chg->dev; 533 + 534 + if (device_property_read_u32(dev->parent, "nxp,min-system-microvolt", 535 + &chg->min_system_volt)) 536 + chg->min_system_volt = PF1550_DEFAULT_MIN_SYSTEM_VOLT; 537 + 538 + if (device_property_read_u32(dev->parent, 539 + "nxp,thermal-regulation-celsius", 540 + &chg->thermal_regulation_temp)) 541 + chg->thermal_regulation_temp = PF1550_DEFAULT_THERMAL_TEMP; 542 + 543 + if (power_supply_get_battery_info(chg->charger, &info)) 544 + chg->constant_volt = PF1550_DEFAULT_CONSTANT_VOLT; 545 + else 546 + chg->constant_volt = info->constant_charge_voltage_max_uv; 547 + } 548 + 549 + static int pf1550_charger_probe(struct platform_device *pdev) 550 + { 551 + const struct pf1550_ddata *pf1550 = dev_get_drvdata(pdev->dev.parent); 552 + struct power_supply_config psy_cfg = {}; 553 + struct pf1550_charger *chg; 554 + int i, irq, ret; 555 + 556 + chg = devm_kzalloc(&pdev->dev, sizeof(*chg), GFP_KERNEL); 557 + if (!chg) 558 + return -ENOMEM; 559 + 560 + chg->dev = &pdev->dev; 561 + chg->pf1550 = pf1550; 562 + 563 + if (!chg->pf1550->regmap) 564 + return dev_err_probe(&pdev->dev, -ENODEV, 565 + "failed to get regmap\n"); 566 + 567 + platform_set_drvdata(pdev, chg); 568 + 569 + ret = devm_delayed_work_autocancel(chg->dev, &chg->vbus_sense_work, 570 + pf1550_chg_vbus_work); 571 + if (ret) 572 + return dev_err_probe(chg->dev, ret, 573 + "failed to add vbus sense work\n"); 574 + 575 + ret = devm_delayed_work_autocancel(chg->dev, &chg->chg_sense_work, 576 + pf1550_chg_chg_work); 577 + if (ret) 578 + return dev_err_probe(chg->dev, ret, 579 + "failed to add charger sense work\n"); 580 + 581 + ret = devm_delayed_work_autocancel(chg->dev, &chg->bat_sense_work, 582 + pf1550_chg_bat_work); 583 + if (ret) 584 + return dev_err_probe(chg->dev, ret, 585 + "failed to add battery sense work\n"); 586 + 587 + for (i = 0; i < PF1550_CHARGER_IRQ_NR; i++) { 588 + irq = platform_get_irq(pdev, i); 589 + if (irq < 0) 590 + return irq; 591 + 592 + chg->virqs[i] = irq; 593 + 594 + ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, 595 + pf1550_charger_irq_handler, 596 + IRQF_NO_SUSPEND, 597 + "pf1550-charger", chg); 598 + if (ret) 599 + return dev_err_probe(&pdev->dev, ret, 600 + "failed irq request\n"); 601 + } 602 + 603 + psy_cfg.drv_data = chg; 604 + 605 + chg->charger = devm_power_supply_register(&pdev->dev, 606 + &pf1550_charger_desc, 607 + &psy_cfg); 608 + if (IS_ERR(chg->charger)) 609 + return dev_err_probe(&pdev->dev, PTR_ERR(chg->charger), 610 + "failed: power supply register\n"); 611 + 612 + chg->battery = devm_power_supply_register(&pdev->dev, 613 + &pf1550_battery_desc, 614 + &psy_cfg); 615 + if (IS_ERR(chg->battery)) 616 + return dev_err_probe(&pdev->dev, PTR_ERR(chg->battery), 617 + "failed: power supply register\n"); 618 + 619 + pf1550_dt_parse_dev_info(chg); 620 + 621 + return pf1550_reg_init(chg); 622 + } 623 + 624 + static const struct platform_device_id pf1550_charger_id[] = { 625 + { "pf1550-charger", }, 626 + { /* sentinel */ } 627 + }; 628 + MODULE_DEVICE_TABLE(platform, pf1550_charger_id); 629 + 630 + static struct platform_driver pf1550_charger_driver = { 631 + .driver = { 632 + .name = "pf1550-charger", 633 + }, 634 + .probe = pf1550_charger_probe, 635 + .id_table = pf1550_charger_id, 636 + }; 637 + module_platform_driver(pf1550_charger_driver); 638 + 639 + MODULE_AUTHOR("Robin Gong <yibin.gong@freescale.com>"); 640 + MODULE_DESCRIPTION("PF1550 charger driver"); 641 + MODULE_LICENSE("GPL");