1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * max8903_charger.c - Maxim 8903 USB/Adapter Charger Driver 4 * 5 * Copyright (C) 2011 Samsung Electronics 6 * MyungJoo Ham <myungjoo.ham@samsung.com> 7 */ 8 9 #include <linux/gpio/consumer.h> 10 #include <linux/interrupt.h> 11 #include <linux/module.h> 12 #include <linux/of.h> 13 #include <linux/slab.h> 14 #include <linux/power_supply.h> 15 #include <linux/platform_device.h> 16 17 struct max8903_data { 18 struct device *dev; 19 struct power_supply *psy; 20 struct power_supply_desc psy_desc; 21 /* 22 * GPIOs 23 * chg, flt, dcm and usus are optional. 24 * dok or uok must be present. 25 * If dok is present, cen must be present. 26 */ 27 struct gpio_desc *cen; /* Charger Enable input */ 28 struct gpio_desc *dok; /* DC (Adapter) Power OK output */ 29 struct gpio_desc *uok; /* USB Power OK output */ 30 struct gpio_desc *chg; /* Charger status output */ 31 struct gpio_desc *flt; /* Fault output */ 32 struct gpio_desc *dcm; /* Current-Limit Mode input (1: DC, 2: USB) */ 33 struct gpio_desc *usus; /* USB Suspend Input (1: suspended) */ 34 bool fault; 35 bool usb_in; 36 bool ta_in; 37 }; 38 39 static enum power_supply_property max8903_charger_props[] = { 40 POWER_SUPPLY_PROP_STATUS, /* Charger status output */ 41 POWER_SUPPLY_PROP_ONLINE, /* External power source */ 42 POWER_SUPPLY_PROP_HEALTH, /* Fault or OK */ 43 }; 44 45 static int max8903_get_property(struct power_supply *psy, 46 enum power_supply_property psp, 47 union power_supply_propval *val) 48 { 49 struct max8903_data *data = power_supply_get_drvdata(psy); 50 51 switch (psp) { 52 case POWER_SUPPLY_PROP_STATUS: 53 val->intval = POWER_SUPPLY_STATUS_UNKNOWN; 54 if (data->chg) { 55 if (gpiod_get_value(data->chg)) 56 /* CHG asserted */ 57 val->intval = POWER_SUPPLY_STATUS_CHARGING; 58 else if (data->usb_in || data->ta_in) 59 val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; 60 else 61 val->intval = POWER_SUPPLY_STATUS_DISCHARGING; 62 } 63 break; 64 case POWER_SUPPLY_PROP_ONLINE: 65 val->intval = 0; 66 if (data->usb_in || data->ta_in) 67 val->intval = 1; 68 break; 69 case POWER_SUPPLY_PROP_HEALTH: 70 val->intval = POWER_SUPPLY_HEALTH_GOOD; 71 if (data->fault) 72 val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; 73 break; 74 default: 75 return -EINVAL; 76 } 77 78 return 0; 79 } 80 81 static irqreturn_t max8903_dcin(int irq, void *_data) 82 { 83 struct max8903_data *data = _data; 84 bool ta_in; 85 enum power_supply_type old_type; 86 87 /* 88 * This means the line is asserted. 89 * 90 * The signal is active low, but the inversion is handled in the GPIO 91 * library as the line should be flagged GPIO_ACTIVE_LOW in the device 92 * tree. 93 */ 94 ta_in = gpiod_get_value(data->dok); 95 96 if (ta_in == data->ta_in) 97 return IRQ_HANDLED; 98 99 data->ta_in = ta_in; 100 101 /* Set Current-Limit-Mode 1:DC 0:USB */ 102 if (data->dcm) 103 gpiod_set_value(data->dcm, ta_in); 104 105 /* Charger Enable / Disable */ 106 if (data->cen) { 107 int val; 108 109 if (ta_in) 110 /* Certainly enable if DOK is asserted */ 111 val = 1; 112 else if (data->usb_in) 113 /* Enable if the USB charger is enabled */ 114 val = 1; 115 else 116 /* Else default-disable */ 117 val = 0; 118 119 gpiod_set_value(data->cen, val); 120 } 121 122 dev_dbg(data->dev, "TA(DC-IN) Charger %s.\n", ta_in ? 123 "Connected" : "Disconnected"); 124 125 old_type = data->psy_desc.type; 126 127 if (data->ta_in) 128 data->psy_desc.type = POWER_SUPPLY_TYPE_MAINS; 129 else if (data->usb_in) 130 data->psy_desc.type = POWER_SUPPLY_TYPE_USB; 131 else 132 data->psy_desc.type = POWER_SUPPLY_TYPE_BATTERY; 133 134 if (old_type != data->psy_desc.type) 135 power_supply_changed(data->psy); 136 137 return IRQ_HANDLED; 138 } 139 140 static irqreturn_t max8903_usbin(int irq, void *_data) 141 { 142 struct max8903_data *data = _data; 143 bool usb_in; 144 enum power_supply_type old_type; 145 146 /* 147 * This means the line is asserted. 148 * 149 * The signal is active low, but the inversion is handled in the GPIO 150 * library as the line should be flagged GPIO_ACTIVE_LOW in the device 151 * tree. 152 */ 153 usb_in = gpiod_get_value(data->uok); 154 155 if (usb_in == data->usb_in) 156 return IRQ_HANDLED; 157 158 data->usb_in = usb_in; 159 160 /* Do not touch Current-Limit-Mode */ 161 162 /* Charger Enable / Disable */ 163 if (data->cen) { 164 int val; 165 166 if (usb_in) 167 /* Certainly enable if UOK is asserted */ 168 val = 1; 169 else if (data->ta_in) 170 /* Enable if the DC charger is enabled */ 171 val = 1; 172 else 173 /* Else default-disable */ 174 val = 0; 175 176 gpiod_set_value(data->cen, val); 177 } 178 179 dev_dbg(data->dev, "USB Charger %s.\n", usb_in ? 180 "Connected" : "Disconnected"); 181 182 old_type = data->psy_desc.type; 183 184 if (data->ta_in) 185 data->psy_desc.type = POWER_SUPPLY_TYPE_MAINS; 186 else if (data->usb_in) 187 data->psy_desc.type = POWER_SUPPLY_TYPE_USB; 188 else 189 data->psy_desc.type = POWER_SUPPLY_TYPE_BATTERY; 190 191 if (old_type != data->psy_desc.type) 192 power_supply_changed(data->psy); 193 194 return IRQ_HANDLED; 195 } 196 197 static irqreturn_t max8903_fault(int irq, void *_data) 198 { 199 struct max8903_data *data = _data; 200 bool fault; 201 202 /* 203 * This means the line is asserted. 204 * 205 * The signal is active low, but the inversion is handled in the GPIO 206 * library as the line should be flagged GPIO_ACTIVE_LOW in the device 207 * tree. 208 */ 209 fault = gpiod_get_value(data->flt); 210 211 if (fault == data->fault) 212 return IRQ_HANDLED; 213 214 data->fault = fault; 215 216 if (fault) 217 dev_err(data->dev, "Charger suffers a fault and stops.\n"); 218 else 219 dev_err(data->dev, "Charger recovered from a fault.\n"); 220 221 return IRQ_HANDLED; 222 } 223 224 static int max8903_setup_gpios(struct platform_device *pdev) 225 { 226 struct max8903_data *data = platform_get_drvdata(pdev); 227 struct device *dev = &pdev->dev; 228 bool ta_in = false; 229 bool usb_in = false; 230 enum gpiod_flags flags; 231 232 data->dok = devm_gpiod_get_optional(dev, "dok", GPIOD_IN); 233 if (IS_ERR(data->dok)) 234 return dev_err_probe(dev, PTR_ERR(data->dok), 235 "failed to get DOK GPIO"); 236 if (data->dok) { 237 gpiod_set_consumer_name(data->dok, data->psy_desc.name); 238 /* 239 * The DC OK is pulled up to 1 and goes low when a charger 240 * is plugged in (active low) but in the device tree the 241 * line is marked as GPIO_ACTIVE_LOW so we get a 1 (asserted) 242 * here if the DC charger is plugged in. 243 */ 244 ta_in = gpiod_get_value(data->dok); 245 } 246 247 data->uok = devm_gpiod_get_optional(dev, "uok", GPIOD_IN); 248 if (IS_ERR(data->uok)) 249 return dev_err_probe(dev, PTR_ERR(data->uok), 250 "failed to get UOK GPIO"); 251 if (data->uok) { 252 gpiod_set_consumer_name(data->uok, data->psy_desc.name); 253 /* 254 * The USB OK is pulled up to 1 and goes low when a USB charger 255 * is plugged in (active low) but in the device tree the 256 * line is marked as GPIO_ACTIVE_LOW so we get a 1 (asserted) 257 * here if the USB charger is plugged in. 258 */ 259 usb_in = gpiod_get_value(data->uok); 260 } 261 262 /* Either DC OK or USB OK must be provided */ 263 if (!data->dok && !data->uok) { 264 dev_err(dev, "no valid power source\n"); 265 return -EINVAL; 266 } 267 268 /* 269 * If either charger is already connected at this point, 270 * assert the CEN line and enable charging from the start. 271 * 272 * The line is active low but also marked with GPIO_ACTIVE_LOW 273 * in the device tree, so when we assert the line with 274 * GPIOD_OUT_HIGH the line will be driven low. 275 */ 276 flags = (ta_in || usb_in) ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW; 277 /* 278 * If DC OK is provided, Charger Enable CEN is compulsory 279 * so this is not optional here. 280 */ 281 data->cen = devm_gpiod_get(dev, "cen", flags); 282 if (IS_ERR(data->cen)) 283 return dev_err_probe(dev, PTR_ERR(data->cen), 284 "failed to get CEN GPIO"); 285 gpiod_set_consumer_name(data->cen, data->psy_desc.name); 286 287 /* 288 * If the DC charger is connected, then select it. 289 * 290 * The DCM line should be marked GPIO_ACTIVE_HIGH in the 291 * device tree. Driving it high will enable the DC charger 292 * input over the USB charger input. 293 */ 294 flags = ta_in ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW; 295 data->dcm = devm_gpiod_get_optional(dev, "dcm", flags); 296 if (IS_ERR(data->dcm)) 297 return dev_err_probe(dev, PTR_ERR(data->dcm), 298 "failed to get DCM GPIO"); 299 gpiod_set_consumer_name(data->dcm, data->psy_desc.name); 300 301 data->chg = devm_gpiod_get_optional(dev, "chg", GPIOD_IN); 302 if (IS_ERR(data->chg)) 303 return dev_err_probe(dev, PTR_ERR(data->chg), 304 "failed to get CHG GPIO"); 305 gpiod_set_consumer_name(data->chg, data->psy_desc.name); 306 307 data->flt = devm_gpiod_get_optional(dev, "flt", GPIOD_IN); 308 if (IS_ERR(data->flt)) 309 return dev_err_probe(dev, PTR_ERR(data->flt), 310 "failed to get FLT GPIO"); 311 gpiod_set_consumer_name(data->flt, data->psy_desc.name); 312 313 data->usus = devm_gpiod_get_optional(dev, "usus", GPIOD_IN); 314 if (IS_ERR(data->usus)) 315 return dev_err_probe(dev, PTR_ERR(data->usus), 316 "failed to get USUS GPIO"); 317 gpiod_set_consumer_name(data->usus, data->psy_desc.name); 318 319 data->fault = false; 320 data->ta_in = ta_in; 321 data->usb_in = usb_in; 322 323 return 0; 324 } 325 326 static int max8903_probe(struct platform_device *pdev) 327 { 328 struct max8903_data *data; 329 struct device *dev = &pdev->dev; 330 struct power_supply_config psy_cfg = {}; 331 int ret = 0; 332 333 data = devm_kzalloc(dev, sizeof(struct max8903_data), GFP_KERNEL); 334 if (!data) 335 return -ENOMEM; 336 337 data->dev = dev; 338 platform_set_drvdata(pdev, data); 339 340 ret = max8903_setup_gpios(pdev); 341 if (ret) 342 return ret; 343 344 data->psy_desc.name = "max8903_charger"; 345 data->psy_desc.type = (data->ta_in) ? POWER_SUPPLY_TYPE_MAINS : 346 ((data->usb_in) ? POWER_SUPPLY_TYPE_USB : 347 POWER_SUPPLY_TYPE_BATTERY); 348 data->psy_desc.get_property = max8903_get_property; 349 data->psy_desc.properties = max8903_charger_props; 350 data->psy_desc.num_properties = ARRAY_SIZE(max8903_charger_props); 351 352 psy_cfg.of_node = dev->of_node; 353 psy_cfg.drv_data = data; 354 355 data->psy = devm_power_supply_register(dev, &data->psy_desc, &psy_cfg); 356 if (IS_ERR(data->psy)) { 357 dev_err(dev, "failed: power supply register.\n"); 358 return PTR_ERR(data->psy); 359 } 360 361 if (data->dok) { 362 ret = devm_request_threaded_irq(dev, gpiod_to_irq(data->dok), 363 NULL, max8903_dcin, 364 IRQF_TRIGGER_FALLING | 365 IRQF_TRIGGER_RISING | IRQF_ONESHOT, 366 "MAX8903 DC IN", data); 367 if (ret) { 368 dev_err(dev, "Cannot request irq %d for DC (%d)\n", 369 gpiod_to_irq(data->dok), ret); 370 return ret; 371 } 372 } 373 374 if (data->uok) { 375 ret = devm_request_threaded_irq(dev, gpiod_to_irq(data->uok), 376 NULL, max8903_usbin, 377 IRQF_TRIGGER_FALLING | 378 IRQF_TRIGGER_RISING | IRQF_ONESHOT, 379 "MAX8903 USB IN", data); 380 if (ret) { 381 dev_err(dev, "Cannot request irq %d for USB (%d)\n", 382 gpiod_to_irq(data->uok), ret); 383 return ret; 384 } 385 } 386 387 if (data->flt) { 388 ret = devm_request_threaded_irq(dev, gpiod_to_irq(data->flt), 389 NULL, max8903_fault, 390 IRQF_TRIGGER_FALLING | 391 IRQF_TRIGGER_RISING | IRQF_ONESHOT, 392 "MAX8903 Fault", data); 393 if (ret) { 394 dev_err(dev, "Cannot request irq %d for Fault (%d)\n", 395 gpiod_to_irq(data->flt), ret); 396 return ret; 397 } 398 } 399 400 return 0; 401 } 402 403 static const struct of_device_id max8903_match_ids[] = { 404 { .compatible = "maxim,max8903", }, 405 { /* sentinel */ } 406 }; 407 MODULE_DEVICE_TABLE(of, max8903_match_ids); 408 409 static struct platform_driver max8903_driver = { 410 .probe = max8903_probe, 411 .driver = { 412 .name = "max8903-charger", 413 .of_match_table = max8903_match_ids 414 }, 415 }; 416 417 module_platform_driver(max8903_driver); 418 419 MODULE_LICENSE("GPL"); 420 MODULE_DESCRIPTION("MAX8903 Charger Driver"); 421 MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>"); 422 MODULE_ALIAS("platform:max8903-charger"); 423