1 /* 2 * max8903_charger.c - Maxim 8903 USB/Adapter Charger Driver 3 * 4 * Copyright (C) 2011 Samsung Electronics 5 * MyungJoo Ham <myungjoo.ham@samsung.com> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 * 21 */ 22 23 #include <linux/gpio.h> 24 #include <linux/interrupt.h> 25 #include <linux/module.h> 26 #include <linux/of.h> 27 #include <linux/of_device.h> 28 #include <linux/of_gpio.h> 29 #include <linux/slab.h> 30 #include <linux/power_supply.h> 31 #include <linux/platform_device.h> 32 #include <linux/power/max8903_charger.h> 33 34 struct max8903_data { 35 struct max8903_pdata *pdata; 36 struct device *dev; 37 struct power_supply *psy; 38 struct power_supply_desc psy_desc; 39 bool fault; 40 bool usb_in; 41 bool ta_in; 42 }; 43 44 static enum power_supply_property max8903_charger_props[] = { 45 POWER_SUPPLY_PROP_STATUS, /* Charger status output */ 46 POWER_SUPPLY_PROP_ONLINE, /* External power source */ 47 POWER_SUPPLY_PROP_HEALTH, /* Fault or OK */ 48 }; 49 50 static int max8903_get_property(struct power_supply *psy, 51 enum power_supply_property psp, 52 union power_supply_propval *val) 53 { 54 struct max8903_data *data = power_supply_get_drvdata(psy); 55 56 switch (psp) { 57 case POWER_SUPPLY_PROP_STATUS: 58 val->intval = POWER_SUPPLY_STATUS_UNKNOWN; 59 if (gpio_is_valid(data->pdata->chg)) { 60 if (gpio_get_value(data->pdata->chg) == 0) 61 val->intval = POWER_SUPPLY_STATUS_CHARGING; 62 else if (data->usb_in || data->ta_in) 63 val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; 64 else 65 val->intval = POWER_SUPPLY_STATUS_DISCHARGING; 66 } 67 break; 68 case POWER_SUPPLY_PROP_ONLINE: 69 val->intval = 0; 70 if (data->usb_in || data->ta_in) 71 val->intval = 1; 72 break; 73 case POWER_SUPPLY_PROP_HEALTH: 74 val->intval = POWER_SUPPLY_HEALTH_GOOD; 75 if (data->fault) 76 val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; 77 break; 78 default: 79 return -EINVAL; 80 } 81 82 return 0; 83 } 84 85 static irqreturn_t max8903_dcin(int irq, void *_data) 86 { 87 struct max8903_data *data = _data; 88 struct max8903_pdata *pdata = data->pdata; 89 bool ta_in; 90 enum power_supply_type old_type; 91 92 ta_in = gpio_get_value(pdata->dok) ? false : true; 93 94 if (ta_in == data->ta_in) 95 return IRQ_HANDLED; 96 97 data->ta_in = ta_in; 98 99 /* Set Current-Limit-Mode 1:DC 0:USB */ 100 if (gpio_is_valid(pdata->dcm)) 101 gpio_set_value(pdata->dcm, ta_in ? 1 : 0); 102 103 /* Charger Enable / Disable (cen is negated) */ 104 if (gpio_is_valid(pdata->cen)) 105 gpio_set_value(pdata->cen, ta_in ? 0 : 106 (data->usb_in ? 0 : 1)); 107 108 dev_dbg(data->dev, "TA(DC-IN) Charger %s.\n", ta_in ? 109 "Connected" : "Disconnected"); 110 111 old_type = data->psy_desc.type; 112 113 if (data->ta_in) 114 data->psy_desc.type = POWER_SUPPLY_TYPE_MAINS; 115 else if (data->usb_in) 116 data->psy_desc.type = POWER_SUPPLY_TYPE_USB; 117 else 118 data->psy_desc.type = POWER_SUPPLY_TYPE_BATTERY; 119 120 if (old_type != data->psy_desc.type) 121 power_supply_changed(data->psy); 122 123 return IRQ_HANDLED; 124 } 125 126 static irqreturn_t max8903_usbin(int irq, void *_data) 127 { 128 struct max8903_data *data = _data; 129 struct max8903_pdata *pdata = data->pdata; 130 bool usb_in; 131 enum power_supply_type old_type; 132 133 usb_in = gpio_get_value(pdata->uok) ? false : true; 134 135 if (usb_in == data->usb_in) 136 return IRQ_HANDLED; 137 138 data->usb_in = usb_in; 139 140 /* Do not touch Current-Limit-Mode */ 141 142 /* Charger Enable / Disable (cen is negated) */ 143 if (gpio_is_valid(pdata->cen)) 144 gpio_set_value(pdata->cen, usb_in ? 0 : 145 (data->ta_in ? 0 : 1)); 146 147 dev_dbg(data->dev, "USB Charger %s.\n", usb_in ? 148 "Connected" : "Disconnected"); 149 150 old_type = data->psy_desc.type; 151 152 if (data->ta_in) 153 data->psy_desc.type = POWER_SUPPLY_TYPE_MAINS; 154 else if (data->usb_in) 155 data->psy_desc.type = POWER_SUPPLY_TYPE_USB; 156 else 157 data->psy_desc.type = POWER_SUPPLY_TYPE_BATTERY; 158 159 if (old_type != data->psy_desc.type) 160 power_supply_changed(data->psy); 161 162 return IRQ_HANDLED; 163 } 164 165 static irqreturn_t max8903_fault(int irq, void *_data) 166 { 167 struct max8903_data *data = _data; 168 struct max8903_pdata *pdata = data->pdata; 169 bool fault; 170 171 fault = gpio_get_value(pdata->flt) ? false : true; 172 173 if (fault == data->fault) 174 return IRQ_HANDLED; 175 176 data->fault = fault; 177 178 if (fault) 179 dev_err(data->dev, "Charger suffers a fault and stops.\n"); 180 else 181 dev_err(data->dev, "Charger recovered from a fault.\n"); 182 183 return IRQ_HANDLED; 184 } 185 186 static struct max8903_pdata *max8903_parse_dt_data(struct device *dev) 187 { 188 struct device_node *np = dev->of_node; 189 struct max8903_pdata *pdata = NULL; 190 191 if (!np) 192 return NULL; 193 194 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); 195 if (!pdata) 196 return NULL; 197 198 pdata->dc_valid = false; 199 pdata->usb_valid = false; 200 201 pdata->cen = of_get_named_gpio(np, "cen-gpios", 0); 202 if (!gpio_is_valid(pdata->cen)) 203 pdata->cen = -EINVAL; 204 205 pdata->chg = of_get_named_gpio(np, "chg-gpios", 0); 206 if (!gpio_is_valid(pdata->chg)) 207 pdata->chg = -EINVAL; 208 209 pdata->flt = of_get_named_gpio(np, "flt-gpios", 0); 210 if (!gpio_is_valid(pdata->flt)) 211 pdata->flt = -EINVAL; 212 213 pdata->usus = of_get_named_gpio(np, "usus-gpios", 0); 214 if (!gpio_is_valid(pdata->usus)) 215 pdata->usus = -EINVAL; 216 217 pdata->dcm = of_get_named_gpio(np, "dcm-gpios", 0); 218 if (!gpio_is_valid(pdata->dcm)) 219 pdata->dcm = -EINVAL; 220 221 pdata->dok = of_get_named_gpio(np, "dok-gpios", 0); 222 if (!gpio_is_valid(pdata->dok)) 223 pdata->dok = -EINVAL; 224 else 225 pdata->dc_valid = true; 226 227 pdata->uok = of_get_named_gpio(np, "uok-gpios", 0); 228 if (!gpio_is_valid(pdata->uok)) 229 pdata->uok = -EINVAL; 230 else 231 pdata->usb_valid = true; 232 233 return pdata; 234 } 235 236 static int max8903_setup_gpios(struct platform_device *pdev) 237 { 238 struct max8903_data *data = platform_get_drvdata(pdev); 239 struct device *dev = &pdev->dev; 240 struct max8903_pdata *pdata = pdev->dev.platform_data; 241 int ret = 0; 242 int gpio; 243 int ta_in = 0; 244 int usb_in = 0; 245 246 if (pdata->dc_valid) { 247 if (gpio_is_valid(pdata->dok)) { 248 ret = devm_gpio_request(dev, pdata->dok, 249 data->psy_desc.name); 250 if (ret) { 251 dev_err(dev, 252 "Failed GPIO request for dok: %d err %d\n", 253 pdata->dok, ret); 254 return ret; 255 } 256 257 gpio = pdata->dok; /* PULL_UPed Interrupt */ 258 ta_in = gpio_get_value(gpio) ? 0 : 1; 259 } else { 260 dev_err(dev, "When DC is wired, DOK should be wired as well.\n"); 261 return -EINVAL; 262 } 263 } 264 265 if (gpio_is_valid(pdata->dcm)) { 266 ret = devm_gpio_request(dev, pdata->dcm, data->psy_desc.name); 267 if (ret) { 268 dev_err(dev, 269 "Failed GPIO request for dcm: %d err %d\n", 270 pdata->dcm, ret); 271 return ret; 272 } 273 274 gpio = pdata->dcm; /* Output */ 275 gpio_set_value(gpio, ta_in); 276 } 277 278 if (pdata->usb_valid) { 279 if (gpio_is_valid(pdata->uok)) { 280 ret = devm_gpio_request(dev, pdata->uok, 281 data->psy_desc.name); 282 if (ret) { 283 dev_err(dev, 284 "Failed GPIO request for uok: %d err %d\n", 285 pdata->uok, ret); 286 return ret; 287 } 288 289 gpio = pdata->uok; 290 usb_in = gpio_get_value(gpio) ? 0 : 1; 291 } else { 292 dev_err(dev, "When USB is wired, UOK should be wired." 293 "as well.\n"); 294 return -EINVAL; 295 } 296 } 297 298 if (gpio_is_valid(pdata->cen)) { 299 ret = devm_gpio_request(dev, pdata->cen, data->psy_desc.name); 300 if (ret) { 301 dev_err(dev, 302 "Failed GPIO request for cen: %d err %d\n", 303 pdata->cen, ret); 304 return ret; 305 } 306 307 gpio_set_value(pdata->cen, (ta_in || usb_in) ? 0 : 1); 308 } 309 310 if (gpio_is_valid(pdata->chg)) { 311 ret = devm_gpio_request(dev, pdata->chg, data->psy_desc.name); 312 if (ret) { 313 dev_err(dev, 314 "Failed GPIO request for chg: %d err %d\n", 315 pdata->chg, ret); 316 return ret; 317 } 318 } 319 320 if (gpio_is_valid(pdata->flt)) { 321 ret = devm_gpio_request(dev, pdata->flt, data->psy_desc.name); 322 if (ret) { 323 dev_err(dev, 324 "Failed GPIO request for flt: %d err %d\n", 325 pdata->flt, ret); 326 return ret; 327 } 328 } 329 330 if (gpio_is_valid(pdata->usus)) { 331 ret = devm_gpio_request(dev, pdata->usus, data->psy_desc.name); 332 if (ret) { 333 dev_err(dev, 334 "Failed GPIO request for usus: %d err %d\n", 335 pdata->usus, ret); 336 return ret; 337 } 338 } 339 340 data->fault = false; 341 data->ta_in = ta_in; 342 data->usb_in = usb_in; 343 344 return 0; 345 } 346 347 static int max8903_probe(struct platform_device *pdev) 348 { 349 struct max8903_data *data; 350 struct device *dev = &pdev->dev; 351 struct max8903_pdata *pdata = pdev->dev.platform_data; 352 struct power_supply_config psy_cfg = {}; 353 int ret = 0; 354 355 data = devm_kzalloc(dev, sizeof(struct max8903_data), GFP_KERNEL); 356 if (!data) 357 return -ENOMEM; 358 359 if (IS_ENABLED(CONFIG_OF) && !pdata && dev->of_node) 360 pdata = max8903_parse_dt_data(dev); 361 362 if (!pdata) { 363 dev_err(dev, "No platform data.\n"); 364 return -EINVAL; 365 } 366 367 pdev->dev.platform_data = pdata; 368 data->pdata = pdata; 369 data->dev = dev; 370 platform_set_drvdata(pdev, data); 371 372 if (pdata->dc_valid == false && pdata->usb_valid == false) { 373 dev_err(dev, "No valid power sources.\n"); 374 return -EINVAL; 375 } 376 377 ret = max8903_setup_gpios(pdev); 378 if (ret) 379 return ret; 380 381 data->psy_desc.name = "max8903_charger"; 382 data->psy_desc.type = (data->ta_in) ? POWER_SUPPLY_TYPE_MAINS : 383 ((data->usb_in) ? POWER_SUPPLY_TYPE_USB : 384 POWER_SUPPLY_TYPE_BATTERY); 385 data->psy_desc.get_property = max8903_get_property; 386 data->psy_desc.properties = max8903_charger_props; 387 data->psy_desc.num_properties = ARRAY_SIZE(max8903_charger_props); 388 389 psy_cfg.of_node = dev->of_node; 390 psy_cfg.drv_data = data; 391 392 data->psy = devm_power_supply_register(dev, &data->psy_desc, &psy_cfg); 393 if (IS_ERR(data->psy)) { 394 dev_err(dev, "failed: power supply register.\n"); 395 return PTR_ERR(data->psy); 396 } 397 398 if (pdata->dc_valid) { 399 ret = devm_request_threaded_irq(dev, gpio_to_irq(pdata->dok), 400 NULL, max8903_dcin, 401 IRQF_TRIGGER_FALLING | 402 IRQF_TRIGGER_RISING | IRQF_ONESHOT, 403 "MAX8903 DC IN", data); 404 if (ret) { 405 dev_err(dev, "Cannot request irq %d for DC (%d)\n", 406 gpio_to_irq(pdata->dok), ret); 407 return ret; 408 } 409 } 410 411 if (pdata->usb_valid) { 412 ret = devm_request_threaded_irq(dev, gpio_to_irq(pdata->uok), 413 NULL, max8903_usbin, 414 IRQF_TRIGGER_FALLING | 415 IRQF_TRIGGER_RISING | IRQF_ONESHOT, 416 "MAX8903 USB IN", data); 417 if (ret) { 418 dev_err(dev, "Cannot request irq %d for USB (%d)\n", 419 gpio_to_irq(pdata->uok), ret); 420 return ret; 421 } 422 } 423 424 if (gpio_is_valid(pdata->flt)) { 425 ret = devm_request_threaded_irq(dev, gpio_to_irq(pdata->flt), 426 NULL, max8903_fault, 427 IRQF_TRIGGER_FALLING | 428 IRQF_TRIGGER_RISING | IRQF_ONESHOT, 429 "MAX8903 Fault", data); 430 if (ret) { 431 dev_err(dev, "Cannot request irq %d for Fault (%d)\n", 432 gpio_to_irq(pdata->flt), ret); 433 return ret; 434 } 435 } 436 437 return 0; 438 } 439 440 static const struct of_device_id max8903_match_ids[] = { 441 { .compatible = "maxim,max8903", }, 442 { /* sentinel */ } 443 }; 444 MODULE_DEVICE_TABLE(of, max8903_match_ids); 445 446 static struct platform_driver max8903_driver = { 447 .probe = max8903_probe, 448 .driver = { 449 .name = "max8903-charger", 450 .of_match_table = max8903_match_ids 451 }, 452 }; 453 454 module_platform_driver(max8903_driver); 455 456 MODULE_LICENSE("GPL"); 457 MODULE_DESCRIPTION("MAX8903 Charger Driver"); 458 MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>"); 459 MODULE_ALIAS("platform:max8903-charger"); 460