11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 2b14a9cccSMyungJoo Ham /* 3b14a9cccSMyungJoo Ham * max8903_charger.c - Maxim 8903 USB/Adapter Charger Driver 4b14a9cccSMyungJoo Ham * 5b14a9cccSMyungJoo Ham * Copyright (C) 2011 Samsung Electronics 6b14a9cccSMyungJoo Ham * MyungJoo Ham <myungjoo.ham@samsung.com> 7b14a9cccSMyungJoo Ham */ 8b14a9cccSMyungJoo Ham 950da8d04SLinus Walleij #include <linux/gpio/consumer.h> 10b14a9cccSMyungJoo Ham #include <linux/interrupt.h> 117e6d62dbSPaul Gortmaker #include <linux/module.h> 12c5ed3307SChris Lapa #include <linux/of.h> 13b14a9cccSMyungJoo Ham #include <linux/slab.h> 14b14a9cccSMyungJoo Ham #include <linux/power_supply.h> 15b14a9cccSMyungJoo Ham #include <linux/platform_device.h> 163188677dSLinus Walleij 17b14a9cccSMyungJoo Ham struct max8903_data { 18b14a9cccSMyungJoo Ham struct device *dev; 19297d716fSKrzysztof Kozlowski struct power_supply *psy; 20297d716fSKrzysztof Kozlowski struct power_supply_desc psy_desc; 2150da8d04SLinus Walleij /* 2250da8d04SLinus Walleij * GPIOs 2350da8d04SLinus Walleij * chg, flt, dcm and usus are optional. 2450da8d04SLinus Walleij * dok or uok must be present. 2550da8d04SLinus Walleij * If dok is present, cen must be present. 2650da8d04SLinus Walleij */ 2750da8d04SLinus Walleij struct gpio_desc *cen; /* Charger Enable input */ 2850da8d04SLinus Walleij struct gpio_desc *dok; /* DC (Adapter) Power OK output */ 2950da8d04SLinus Walleij struct gpio_desc *uok; /* USB Power OK output */ 3050da8d04SLinus Walleij struct gpio_desc *chg; /* Charger status output */ 3150da8d04SLinus Walleij struct gpio_desc *flt; /* Fault output */ 3250da8d04SLinus Walleij struct gpio_desc *dcm; /* Current-Limit Mode input (1: DC, 2: USB) */ 3350da8d04SLinus Walleij struct gpio_desc *usus; /* USB Suspend Input (1: suspended) */ 34b14a9cccSMyungJoo Ham bool fault; 35b14a9cccSMyungJoo Ham bool usb_in; 36b14a9cccSMyungJoo Ham bool ta_in; 37b14a9cccSMyungJoo Ham }; 38b14a9cccSMyungJoo Ham 39b14a9cccSMyungJoo Ham static enum power_supply_property max8903_charger_props[] = { 40b14a9cccSMyungJoo Ham POWER_SUPPLY_PROP_STATUS, /* Charger status output */ 41b14a9cccSMyungJoo Ham POWER_SUPPLY_PROP_ONLINE, /* External power source */ 42b14a9cccSMyungJoo Ham POWER_SUPPLY_PROP_HEALTH, /* Fault or OK */ 43b14a9cccSMyungJoo Ham }; 44b14a9cccSMyungJoo Ham 45b14a9cccSMyungJoo Ham static int max8903_get_property(struct power_supply *psy, 46b14a9cccSMyungJoo Ham enum power_supply_property psp, 47b14a9cccSMyungJoo Ham union power_supply_propval *val) 48b14a9cccSMyungJoo Ham { 49297d716fSKrzysztof Kozlowski struct max8903_data *data = power_supply_get_drvdata(psy); 50b14a9cccSMyungJoo Ham 51b14a9cccSMyungJoo Ham switch (psp) { 52b14a9cccSMyungJoo Ham case POWER_SUPPLY_PROP_STATUS: 53b14a9cccSMyungJoo Ham val->intval = POWER_SUPPLY_STATUS_UNKNOWN; 5450da8d04SLinus Walleij if (data->chg) { 5550da8d04SLinus Walleij if (gpiod_get_value(data->chg)) 5650da8d04SLinus Walleij /* CHG asserted */ 57b14a9cccSMyungJoo Ham val->intval = POWER_SUPPLY_STATUS_CHARGING; 58b14a9cccSMyungJoo Ham else if (data->usb_in || data->ta_in) 59b14a9cccSMyungJoo Ham val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; 60b14a9cccSMyungJoo Ham else 61b14a9cccSMyungJoo Ham val->intval = POWER_SUPPLY_STATUS_DISCHARGING; 62b14a9cccSMyungJoo Ham } 63b14a9cccSMyungJoo Ham break; 64b14a9cccSMyungJoo Ham case POWER_SUPPLY_PROP_ONLINE: 65b14a9cccSMyungJoo Ham val->intval = 0; 66b14a9cccSMyungJoo Ham if (data->usb_in || data->ta_in) 67b14a9cccSMyungJoo Ham val->intval = 1; 68b14a9cccSMyungJoo Ham break; 69b14a9cccSMyungJoo Ham case POWER_SUPPLY_PROP_HEALTH: 70b14a9cccSMyungJoo Ham val->intval = POWER_SUPPLY_HEALTH_GOOD; 71b14a9cccSMyungJoo Ham if (data->fault) 72b14a9cccSMyungJoo Ham val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; 73b14a9cccSMyungJoo Ham break; 74b14a9cccSMyungJoo Ham default: 75b14a9cccSMyungJoo Ham return -EINVAL; 76b14a9cccSMyungJoo Ham } 77c5ed3307SChris Lapa 78b14a9cccSMyungJoo Ham return 0; 79b14a9cccSMyungJoo Ham } 80b14a9cccSMyungJoo Ham 81b14a9cccSMyungJoo Ham static irqreturn_t max8903_dcin(int irq, void *_data) 82b14a9cccSMyungJoo Ham { 83b14a9cccSMyungJoo Ham struct max8903_data *data = _data; 84b14a9cccSMyungJoo Ham bool ta_in; 85b14a9cccSMyungJoo Ham enum power_supply_type old_type; 86b14a9cccSMyungJoo Ham 8750da8d04SLinus Walleij /* 8850da8d04SLinus Walleij * This means the line is asserted. 8950da8d04SLinus Walleij * 9050da8d04SLinus Walleij * The signal is active low, but the inversion is handled in the GPIO 9150da8d04SLinus Walleij * library as the line should be flagged GPIO_ACTIVE_LOW in the device 9250da8d04SLinus Walleij * tree. 9350da8d04SLinus Walleij */ 9450da8d04SLinus Walleij ta_in = gpiod_get_value(data->dok); 95b14a9cccSMyungJoo Ham 96b14a9cccSMyungJoo Ham if (ta_in == data->ta_in) 97b14a9cccSMyungJoo Ham return IRQ_HANDLED; 98b14a9cccSMyungJoo Ham 99b14a9cccSMyungJoo Ham data->ta_in = ta_in; 100b14a9cccSMyungJoo Ham 101b14a9cccSMyungJoo Ham /* Set Current-Limit-Mode 1:DC 0:USB */ 10250da8d04SLinus Walleij if (data->dcm) 10350da8d04SLinus Walleij gpiod_set_value(data->dcm, ta_in); 104b14a9cccSMyungJoo Ham 10550da8d04SLinus Walleij /* Charger Enable / Disable */ 10650da8d04SLinus Walleij if (data->cen) { 10750da8d04SLinus Walleij int val; 10850da8d04SLinus Walleij 10950da8d04SLinus Walleij if (ta_in) 11050da8d04SLinus Walleij /* Certainly enable if DOK is asserted */ 11150da8d04SLinus Walleij val = 1; 11250da8d04SLinus Walleij else if (data->usb_in) 11350da8d04SLinus Walleij /* Enable if the USB charger is enabled */ 11450da8d04SLinus Walleij val = 1; 11550da8d04SLinus Walleij else 11650da8d04SLinus Walleij /* Else default-disable */ 11750da8d04SLinus Walleij val = 0; 11850da8d04SLinus Walleij 11950da8d04SLinus Walleij gpiod_set_value(data->cen, val); 12050da8d04SLinus Walleij } 121b14a9cccSMyungJoo Ham 122b14a9cccSMyungJoo Ham dev_dbg(data->dev, "TA(DC-IN) Charger %s.\n", ta_in ? 123b14a9cccSMyungJoo Ham "Connected" : "Disconnected"); 124b14a9cccSMyungJoo Ham 125297d716fSKrzysztof Kozlowski old_type = data->psy_desc.type; 126b14a9cccSMyungJoo Ham 127b14a9cccSMyungJoo Ham if (data->ta_in) 128297d716fSKrzysztof Kozlowski data->psy_desc.type = POWER_SUPPLY_TYPE_MAINS; 129b14a9cccSMyungJoo Ham else if (data->usb_in) 130297d716fSKrzysztof Kozlowski data->psy_desc.type = POWER_SUPPLY_TYPE_USB; 131b14a9cccSMyungJoo Ham else 132297d716fSKrzysztof Kozlowski data->psy_desc.type = POWER_SUPPLY_TYPE_BATTERY; 133b14a9cccSMyungJoo Ham 134297d716fSKrzysztof Kozlowski if (old_type != data->psy_desc.type) 135297d716fSKrzysztof Kozlowski power_supply_changed(data->psy); 136b14a9cccSMyungJoo Ham 137b14a9cccSMyungJoo Ham return IRQ_HANDLED; 138b14a9cccSMyungJoo Ham } 139b14a9cccSMyungJoo Ham 140b14a9cccSMyungJoo Ham static irqreturn_t max8903_usbin(int irq, void *_data) 141b14a9cccSMyungJoo Ham { 142b14a9cccSMyungJoo Ham struct max8903_data *data = _data; 143b14a9cccSMyungJoo Ham bool usb_in; 144b14a9cccSMyungJoo Ham enum power_supply_type old_type; 145b14a9cccSMyungJoo Ham 14650da8d04SLinus Walleij /* 14750da8d04SLinus Walleij * This means the line is asserted. 14850da8d04SLinus Walleij * 14950da8d04SLinus Walleij * The signal is active low, but the inversion is handled in the GPIO 15050da8d04SLinus Walleij * library as the line should be flagged GPIO_ACTIVE_LOW in the device 15150da8d04SLinus Walleij * tree. 15250da8d04SLinus Walleij */ 15350da8d04SLinus Walleij usb_in = gpiod_get_value(data->uok); 154b14a9cccSMyungJoo Ham 155b14a9cccSMyungJoo Ham if (usb_in == data->usb_in) 156b14a9cccSMyungJoo Ham return IRQ_HANDLED; 157b14a9cccSMyungJoo Ham 158b14a9cccSMyungJoo Ham data->usb_in = usb_in; 159b14a9cccSMyungJoo Ham 160b14a9cccSMyungJoo Ham /* Do not touch Current-Limit-Mode */ 161b14a9cccSMyungJoo Ham 16250da8d04SLinus Walleij /* Charger Enable / Disable */ 16350da8d04SLinus Walleij if (data->cen) { 16450da8d04SLinus Walleij int val; 16550da8d04SLinus Walleij 16650da8d04SLinus Walleij if (usb_in) 16750da8d04SLinus Walleij /* Certainly enable if UOK is asserted */ 16850da8d04SLinus Walleij val = 1; 16950da8d04SLinus Walleij else if (data->ta_in) 17050da8d04SLinus Walleij /* Enable if the DC charger is enabled */ 17150da8d04SLinus Walleij val = 1; 17250da8d04SLinus Walleij else 17350da8d04SLinus Walleij /* Else default-disable */ 17450da8d04SLinus Walleij val = 0; 17550da8d04SLinus Walleij 17650da8d04SLinus Walleij gpiod_set_value(data->cen, val); 17750da8d04SLinus Walleij } 178b14a9cccSMyungJoo Ham 179b14a9cccSMyungJoo Ham dev_dbg(data->dev, "USB Charger %s.\n", usb_in ? 180b14a9cccSMyungJoo Ham "Connected" : "Disconnected"); 181b14a9cccSMyungJoo Ham 182297d716fSKrzysztof Kozlowski old_type = data->psy_desc.type; 183b14a9cccSMyungJoo Ham 184b14a9cccSMyungJoo Ham if (data->ta_in) 185297d716fSKrzysztof Kozlowski data->psy_desc.type = POWER_SUPPLY_TYPE_MAINS; 186b14a9cccSMyungJoo Ham else if (data->usb_in) 187297d716fSKrzysztof Kozlowski data->psy_desc.type = POWER_SUPPLY_TYPE_USB; 188b14a9cccSMyungJoo Ham else 189297d716fSKrzysztof Kozlowski data->psy_desc.type = POWER_SUPPLY_TYPE_BATTERY; 190b14a9cccSMyungJoo Ham 191297d716fSKrzysztof Kozlowski if (old_type != data->psy_desc.type) 192297d716fSKrzysztof Kozlowski power_supply_changed(data->psy); 193b14a9cccSMyungJoo Ham 194b14a9cccSMyungJoo Ham return IRQ_HANDLED; 195b14a9cccSMyungJoo Ham } 196b14a9cccSMyungJoo Ham 197b14a9cccSMyungJoo Ham static irqreturn_t max8903_fault(int irq, void *_data) 198b14a9cccSMyungJoo Ham { 199b14a9cccSMyungJoo Ham struct max8903_data *data = _data; 200b14a9cccSMyungJoo Ham bool fault; 201b14a9cccSMyungJoo Ham 20250da8d04SLinus Walleij /* 20350da8d04SLinus Walleij * This means the line is asserted. 20450da8d04SLinus Walleij * 20550da8d04SLinus Walleij * The signal is active low, but the inversion is handled in the GPIO 20650da8d04SLinus Walleij * library as the line should be flagged GPIO_ACTIVE_LOW in the device 20750da8d04SLinus Walleij * tree. 20850da8d04SLinus Walleij */ 20950da8d04SLinus Walleij fault = gpiod_get_value(data->flt); 210b14a9cccSMyungJoo Ham 211b14a9cccSMyungJoo Ham if (fault == data->fault) 212b14a9cccSMyungJoo Ham return IRQ_HANDLED; 213b14a9cccSMyungJoo Ham 214b14a9cccSMyungJoo Ham data->fault = fault; 215b14a9cccSMyungJoo Ham 216b14a9cccSMyungJoo Ham if (fault) 217b14a9cccSMyungJoo Ham dev_err(data->dev, "Charger suffers a fault and stops.\n"); 218b14a9cccSMyungJoo Ham else 219b14a9cccSMyungJoo Ham dev_err(data->dev, "Charger recovered from a fault.\n"); 220b14a9cccSMyungJoo Ham 221b14a9cccSMyungJoo Ham return IRQ_HANDLED; 222b14a9cccSMyungJoo Ham } 223b14a9cccSMyungJoo Ham 22488a469bbSChris Lapa static int max8903_setup_gpios(struct platform_device *pdev) 22588a469bbSChris Lapa { 22688a469bbSChris Lapa struct max8903_data *data = platform_get_drvdata(pdev); 22788a469bbSChris Lapa struct device *dev = &pdev->dev; 22850da8d04SLinus Walleij bool ta_in = false; 22950da8d04SLinus Walleij bool usb_in = false; 23050da8d04SLinus Walleij enum gpiod_flags flags; 23188a469bbSChris Lapa 23250da8d04SLinus Walleij data->dok = devm_gpiod_get_optional(dev, "dok", GPIOD_IN); 23350da8d04SLinus Walleij if (IS_ERR(data->dok)) 23450da8d04SLinus Walleij return dev_err_probe(dev, PTR_ERR(data->dok), 23550da8d04SLinus Walleij "failed to get DOK GPIO"); 23650da8d04SLinus Walleij if (data->dok) { 23750da8d04SLinus Walleij gpiod_set_consumer_name(data->dok, data->psy_desc.name); 23850da8d04SLinus Walleij /* 23950da8d04SLinus Walleij * The DC OK is pulled up to 1 and goes low when a charger 24050da8d04SLinus Walleij * is plugged in (active low) but in the device tree the 24150da8d04SLinus Walleij * line is marked as GPIO_ACTIVE_LOW so we get a 1 (asserted) 24250da8d04SLinus Walleij * here if the DC charger is plugged in. 24350da8d04SLinus Walleij */ 24450da8d04SLinus Walleij ta_in = gpiod_get_value(data->dok); 24588a469bbSChris Lapa } 24688a469bbSChris Lapa 24750da8d04SLinus Walleij data->uok = devm_gpiod_get_optional(dev, "uok", GPIOD_IN); 24850da8d04SLinus Walleij if (IS_ERR(data->uok)) 24950da8d04SLinus Walleij return dev_err_probe(dev, PTR_ERR(data->uok), 25050da8d04SLinus Walleij "failed to get UOK GPIO"); 25150da8d04SLinus Walleij if (data->uok) { 25250da8d04SLinus Walleij gpiod_set_consumer_name(data->uok, data->psy_desc.name); 25350da8d04SLinus Walleij /* 25450da8d04SLinus Walleij * The USB OK is pulled up to 1 and goes low when a USB charger 25550da8d04SLinus Walleij * is plugged in (active low) but in the device tree the 25650da8d04SLinus Walleij * line is marked as GPIO_ACTIVE_LOW so we get a 1 (asserted) 25750da8d04SLinus Walleij * here if the USB charger is plugged in. 25850da8d04SLinus Walleij */ 25950da8d04SLinus Walleij usb_in = gpiod_get_value(data->uok); 26050da8d04SLinus Walleij } 26150da8d04SLinus Walleij 26250da8d04SLinus Walleij /* Either DC OK or USB OK must be provided */ 26350da8d04SLinus Walleij if (!data->dok && !data->uok) { 26450da8d04SLinus Walleij dev_err(dev, "no valid power source\n"); 26588a469bbSChris Lapa return -EINVAL; 26688a469bbSChris Lapa } 26788a469bbSChris Lapa 26850da8d04SLinus Walleij /* 26950da8d04SLinus Walleij * If either charger is already connected at this point, 27050da8d04SLinus Walleij * assert the CEN line and enable charging from the start. 27150da8d04SLinus Walleij * 27250da8d04SLinus Walleij * The line is active low but also marked with GPIO_ACTIVE_LOW 27350da8d04SLinus Walleij * in the device tree, so when we assert the line with 27450da8d04SLinus Walleij * GPIOD_OUT_HIGH the line will be driven low. 27550da8d04SLinus Walleij */ 27650da8d04SLinus Walleij flags = (ta_in || usb_in) ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW; 27750da8d04SLinus Walleij /* 27850da8d04SLinus Walleij * If DC OK is provided, Charger Enable CEN is compulsory 27950da8d04SLinus Walleij * so this is not optional here. 28050da8d04SLinus Walleij */ 28150da8d04SLinus Walleij data->cen = devm_gpiod_get(dev, "cen", flags); 28250da8d04SLinus Walleij if (IS_ERR(data->cen)) 28350da8d04SLinus Walleij return dev_err_probe(dev, PTR_ERR(data->cen), 28450da8d04SLinus Walleij "failed to get CEN GPIO"); 28550da8d04SLinus Walleij gpiod_set_consumer_name(data->cen, data->psy_desc.name); 28688a469bbSChris Lapa 28750da8d04SLinus Walleij /* 28850da8d04SLinus Walleij * If the DC charger is connected, then select it. 28950da8d04SLinus Walleij * 29050da8d04SLinus Walleij * The DCM line should be marked GPIO_ACTIVE_HIGH in the 29150da8d04SLinus Walleij * device tree. Driving it high will enable the DC charger 29250da8d04SLinus Walleij * input over the USB charger input. 29350da8d04SLinus Walleij */ 29450da8d04SLinus Walleij flags = ta_in ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW; 29550da8d04SLinus Walleij data->dcm = devm_gpiod_get_optional(dev, "dcm", flags); 29650da8d04SLinus Walleij if (IS_ERR(data->dcm)) 29750da8d04SLinus Walleij return dev_err_probe(dev, PTR_ERR(data->dcm), 29850da8d04SLinus Walleij "failed to get DCM GPIO"); 29950da8d04SLinus Walleij gpiod_set_consumer_name(data->dcm, data->psy_desc.name); 30088a469bbSChris Lapa 30150da8d04SLinus Walleij data->chg = devm_gpiod_get_optional(dev, "chg", GPIOD_IN); 30250da8d04SLinus Walleij if (IS_ERR(data->chg)) 30350da8d04SLinus Walleij return dev_err_probe(dev, PTR_ERR(data->chg), 30450da8d04SLinus Walleij "failed to get CHG GPIO"); 30550da8d04SLinus Walleij gpiod_set_consumer_name(data->chg, data->psy_desc.name); 30688a469bbSChris Lapa 30750da8d04SLinus Walleij data->flt = devm_gpiod_get_optional(dev, "flt", GPIOD_IN); 30850da8d04SLinus Walleij if (IS_ERR(data->flt)) 30950da8d04SLinus Walleij return dev_err_probe(dev, PTR_ERR(data->flt), 31050da8d04SLinus Walleij "failed to get FLT GPIO"); 31150da8d04SLinus Walleij gpiod_set_consumer_name(data->flt, data->psy_desc.name); 31288a469bbSChris Lapa 31350da8d04SLinus Walleij data->usus = devm_gpiod_get_optional(dev, "usus", GPIOD_IN); 31450da8d04SLinus Walleij if (IS_ERR(data->usus)) 31550da8d04SLinus Walleij return dev_err_probe(dev, PTR_ERR(data->usus), 31650da8d04SLinus Walleij "failed to get USUS GPIO"); 31750da8d04SLinus Walleij gpiod_set_consumer_name(data->usus, data->psy_desc.name); 31888a469bbSChris Lapa 31988a469bbSChris Lapa data->fault = false; 32088a469bbSChris Lapa data->ta_in = ta_in; 32188a469bbSChris Lapa data->usb_in = usb_in; 32288a469bbSChris Lapa 32388a469bbSChris Lapa return 0; 32488a469bbSChris Lapa } 32588a469bbSChris Lapa 326c8afa640SBill Pemberton static int max8903_probe(struct platform_device *pdev) 327b14a9cccSMyungJoo Ham { 328b14a9cccSMyungJoo Ham struct max8903_data *data; 329b14a9cccSMyungJoo Ham struct device *dev = &pdev->dev; 330297d716fSKrzysztof Kozlowski struct power_supply_config psy_cfg = {}; 331b14a9cccSMyungJoo Ham int ret = 0; 332b14a9cccSMyungJoo Ham 333f3f66b3eSJingoo Han data = devm_kzalloc(dev, sizeof(struct max8903_data), GFP_KERNEL); 334e6518a43SChris Lapa if (!data) 335b14a9cccSMyungJoo Ham return -ENOMEM; 3360c3ae04bSChris Lapa 337b14a9cccSMyungJoo Ham data->dev = dev; 338b14a9cccSMyungJoo Ham platform_set_drvdata(pdev, data); 339b14a9cccSMyungJoo Ham 34088a469bbSChris Lapa ret = max8903_setup_gpios(pdev); 34188a469bbSChris Lapa if (ret) 34288a469bbSChris Lapa return ret; 343b14a9cccSMyungJoo Ham 344297d716fSKrzysztof Kozlowski data->psy_desc.name = "max8903_charger"; 34588a469bbSChris Lapa data->psy_desc.type = (data->ta_in) ? POWER_SUPPLY_TYPE_MAINS : 34688a469bbSChris Lapa ((data->usb_in) ? POWER_SUPPLY_TYPE_USB : 347b14a9cccSMyungJoo Ham POWER_SUPPLY_TYPE_BATTERY); 348297d716fSKrzysztof Kozlowski data->psy_desc.get_property = max8903_get_property; 349297d716fSKrzysztof Kozlowski data->psy_desc.properties = max8903_charger_props; 350297d716fSKrzysztof Kozlowski data->psy_desc.num_properties = ARRAY_SIZE(max8903_charger_props); 351b14a9cccSMyungJoo Ham 352*46d0c03cSSebastian Reichel psy_cfg.fwnode = dev_fwnode(dev); 353297d716fSKrzysztof Kozlowski psy_cfg.drv_data = data; 354297d716fSKrzysztof Kozlowski 3550df2deeaSVaishali Thakkar data->psy = devm_power_supply_register(dev, &data->psy_desc, &psy_cfg); 356297d716fSKrzysztof Kozlowski if (IS_ERR(data->psy)) { 357b14a9cccSMyungJoo Ham dev_err(dev, "failed: power supply register.\n"); 3580df2deeaSVaishali Thakkar return PTR_ERR(data->psy); 359b14a9cccSMyungJoo Ham } 360b14a9cccSMyungJoo Ham 36150da8d04SLinus Walleij if (data->dok) { 36250da8d04SLinus Walleij ret = devm_request_threaded_irq(dev, gpiod_to_irq(data->dok), 363b14a9cccSMyungJoo Ham NULL, max8903_dcin, 3640df2deeaSVaishali Thakkar IRQF_TRIGGER_FALLING | 365d5fdfedcSSaurabh Sengar IRQF_TRIGGER_RISING | IRQF_ONESHOT, 366b14a9cccSMyungJoo Ham "MAX8903 DC IN", data); 367b14a9cccSMyungJoo Ham if (ret) { 368b14a9cccSMyungJoo Ham dev_err(dev, "Cannot request irq %d for DC (%d)\n", 36950da8d04SLinus Walleij gpiod_to_irq(data->dok), ret); 3700df2deeaSVaishali Thakkar return ret; 371b14a9cccSMyungJoo Ham } 372b14a9cccSMyungJoo Ham } 373b14a9cccSMyungJoo Ham 37450da8d04SLinus Walleij if (data->uok) { 37550da8d04SLinus Walleij ret = devm_request_threaded_irq(dev, gpiod_to_irq(data->uok), 376b14a9cccSMyungJoo Ham NULL, max8903_usbin, 3770df2deeaSVaishali Thakkar IRQF_TRIGGER_FALLING | 378d5fdfedcSSaurabh Sengar IRQF_TRIGGER_RISING | IRQF_ONESHOT, 379b14a9cccSMyungJoo Ham "MAX8903 USB IN", data); 380b14a9cccSMyungJoo Ham if (ret) { 381b14a9cccSMyungJoo Ham dev_err(dev, "Cannot request irq %d for USB (%d)\n", 38250da8d04SLinus Walleij gpiod_to_irq(data->uok), ret); 3830df2deeaSVaishali Thakkar return ret; 384b14a9cccSMyungJoo Ham } 385b14a9cccSMyungJoo Ham } 386b14a9cccSMyungJoo Ham 38750da8d04SLinus Walleij if (data->flt) { 38850da8d04SLinus Walleij ret = devm_request_threaded_irq(dev, gpiod_to_irq(data->flt), 389b14a9cccSMyungJoo Ham NULL, max8903_fault, 3900df2deeaSVaishali Thakkar IRQF_TRIGGER_FALLING | 391d5fdfedcSSaurabh Sengar IRQF_TRIGGER_RISING | IRQF_ONESHOT, 392b14a9cccSMyungJoo Ham "MAX8903 Fault", data); 393b14a9cccSMyungJoo Ham if (ret) { 394b14a9cccSMyungJoo Ham dev_err(dev, "Cannot request irq %d for Fault (%d)\n", 39550da8d04SLinus Walleij gpiod_to_irq(data->flt), ret); 396b14a9cccSMyungJoo Ham return ret; 397b14a9cccSMyungJoo Ham } 398b14a9cccSMyungJoo Ham } 399b14a9cccSMyungJoo Ham 400b14a9cccSMyungJoo Ham return 0; 401b14a9cccSMyungJoo Ham } 402b14a9cccSMyungJoo Ham 403c5ed3307SChris Lapa static const struct of_device_id max8903_match_ids[] = { 404c5ed3307SChris Lapa { .compatible = "maxim,max8903", }, 405c5ed3307SChris Lapa { /* sentinel */ } 406c5ed3307SChris Lapa }; 407c5ed3307SChris Lapa MODULE_DEVICE_TABLE(of, max8903_match_ids); 408c5ed3307SChris Lapa 409b14a9cccSMyungJoo Ham static struct platform_driver max8903_driver = { 410b14a9cccSMyungJoo Ham .probe = max8903_probe, 411b14a9cccSMyungJoo Ham .driver = { 412b14a9cccSMyungJoo Ham .name = "max8903-charger", 413c5ed3307SChris Lapa .of_match_table = max8903_match_ids 414b14a9cccSMyungJoo Ham }, 415b14a9cccSMyungJoo Ham }; 416b14a9cccSMyungJoo Ham 417300bac7fSAxel Lin module_platform_driver(max8903_driver); 418b14a9cccSMyungJoo Ham 419b14a9cccSMyungJoo Ham MODULE_LICENSE("GPL"); 420b14a9cccSMyungJoo Ham MODULE_DESCRIPTION("MAX8903 Charger Driver"); 421b14a9cccSMyungJoo Ham MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>"); 422bd19c756SAxel Lin MODULE_ALIAS("platform:max8903-charger"); 423