18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci// 38c2ecf20Sopenharmony_ci// Copyright (C) 2018 BayLibre SAS 48c2ecf20Sopenharmony_ci// Author: Bartosz Golaszewski <bgolaszewski@baylibre.com> 58c2ecf20Sopenharmony_ci// 68c2ecf20Sopenharmony_ci// Battery charger driver for MAXIM 77650/77651 charger/power-supply. 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/i2c.h> 98c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 108c2ecf20Sopenharmony_ci#include <linux/mfd/max77650.h> 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 138c2ecf20Sopenharmony_ci#include <linux/power_supply.h> 148c2ecf20Sopenharmony_ci#include <linux/regmap.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#define MAX77650_CHARGER_ENABLED BIT(0) 178c2ecf20Sopenharmony_ci#define MAX77650_CHARGER_DISABLED 0x00 188c2ecf20Sopenharmony_ci#define MAX77650_CHARGER_CHG_EN_MASK BIT(0) 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#define MAX77650_CHG_DETAILS_MASK GENMASK(7, 4) 218c2ecf20Sopenharmony_ci#define MAX77650_CHG_DETAILS_BITS(_reg) \ 228c2ecf20Sopenharmony_ci (((_reg) & MAX77650_CHG_DETAILS_MASK) >> 4) 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci/* Charger is OFF. */ 258c2ecf20Sopenharmony_ci#define MAX77650_CHG_OFF 0x00 268c2ecf20Sopenharmony_ci/* Charger is in prequalification mode. */ 278c2ecf20Sopenharmony_ci#define MAX77650_CHG_PREQ 0x01 288c2ecf20Sopenharmony_ci/* Charger is in fast-charge constant current mode. */ 298c2ecf20Sopenharmony_ci#define MAX77650_CHG_ON_CURR 0x02 308c2ecf20Sopenharmony_ci/* Charger is in JEITA modified fast-charge constant-current mode. */ 318c2ecf20Sopenharmony_ci#define MAX77650_CHG_ON_CURR_JEITA 0x03 328c2ecf20Sopenharmony_ci/* Charger is in fast-charge constant-voltage mode. */ 338c2ecf20Sopenharmony_ci#define MAX77650_CHG_ON_VOLT 0x04 348c2ecf20Sopenharmony_ci/* Charger is in JEITA modified fast-charge constant-voltage mode. */ 358c2ecf20Sopenharmony_ci#define MAX77650_CHG_ON_VOLT_JEITA 0x05 368c2ecf20Sopenharmony_ci/* Charger is in top-off mode. */ 378c2ecf20Sopenharmony_ci#define MAX77650_CHG_ON_TOPOFF 0x06 388c2ecf20Sopenharmony_ci/* Charger is in JEITA modified top-off mode. */ 398c2ecf20Sopenharmony_ci#define MAX77650_CHG_ON_TOPOFF_JEITA 0x07 408c2ecf20Sopenharmony_ci/* Charger is done. */ 418c2ecf20Sopenharmony_ci#define MAX77650_CHG_DONE 0x08 428c2ecf20Sopenharmony_ci/* Charger is JEITA modified done. */ 438c2ecf20Sopenharmony_ci#define MAX77650_CHG_DONE_JEITA 0x09 448c2ecf20Sopenharmony_ci/* Charger is suspended due to a prequalification timer fault. */ 458c2ecf20Sopenharmony_ci#define MAX77650_CHG_SUSP_PREQ_TIM_FAULT 0x0a 468c2ecf20Sopenharmony_ci/* Charger is suspended due to a fast-charge timer fault. */ 478c2ecf20Sopenharmony_ci#define MAX77650_CHG_SUSP_FAST_CHG_TIM_FAULT 0x0b 488c2ecf20Sopenharmony_ci/* Charger is suspended due to a battery temperature fault. */ 498c2ecf20Sopenharmony_ci#define MAX77650_CHG_SUSP_BATT_TEMP_FAULT 0x0c 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci#define MAX77650_CHGIN_DETAILS_MASK GENMASK(3, 2) 528c2ecf20Sopenharmony_ci#define MAX77650_CHGIN_DETAILS_BITS(_reg) \ 538c2ecf20Sopenharmony_ci (((_reg) & MAX77650_CHGIN_DETAILS_MASK) >> 2) 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci#define MAX77650_CHGIN_UNDERVOLTAGE_LOCKOUT 0x00 568c2ecf20Sopenharmony_ci#define MAX77650_CHGIN_OVERVOLTAGE_LOCKOUT 0x01 578c2ecf20Sopenharmony_ci#define MAX77650_CHGIN_OKAY 0x11 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci#define MAX77650_CHARGER_CHG_MASK BIT(1) 608c2ecf20Sopenharmony_ci#define MAX77650_CHARGER_CHG_CHARGING(_reg) \ 618c2ecf20Sopenharmony_ci (((_reg) & MAX77650_CHARGER_CHG_MASK) > 1) 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci#define MAX77650_CHARGER_VCHGIN_MIN_MASK 0xc0 648c2ecf20Sopenharmony_ci#define MAX77650_CHARGER_VCHGIN_MIN_SHIFT(_val) ((_val) << 5) 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci#define MAX77650_CHARGER_ICHGIN_LIM_MASK 0x1c 678c2ecf20Sopenharmony_ci#define MAX77650_CHARGER_ICHGIN_LIM_SHIFT(_val) ((_val) << 2) 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistruct max77650_charger_data { 708c2ecf20Sopenharmony_ci struct regmap *map; 718c2ecf20Sopenharmony_ci struct device *dev; 728c2ecf20Sopenharmony_ci}; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic enum power_supply_property max77650_charger_properties[] = { 758c2ecf20Sopenharmony_ci POWER_SUPPLY_PROP_STATUS, 768c2ecf20Sopenharmony_ci POWER_SUPPLY_PROP_ONLINE, 778c2ecf20Sopenharmony_ci POWER_SUPPLY_PROP_CHARGE_TYPE 788c2ecf20Sopenharmony_ci}; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cistatic const unsigned int max77650_charger_vchgin_min_table[] = { 818c2ecf20Sopenharmony_ci 4000000, 4100000, 4200000, 4300000, 4400000, 4500000, 4600000, 4700000 828c2ecf20Sopenharmony_ci}; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic const unsigned int max77650_charger_ichgin_lim_table[] = { 858c2ecf20Sopenharmony_ci 95000, 190000, 285000, 380000, 475000 868c2ecf20Sopenharmony_ci}; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic int max77650_charger_set_vchgin_min(struct max77650_charger_data *chg, 898c2ecf20Sopenharmony_ci unsigned int val) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci int i, rv; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(max77650_charger_vchgin_min_table); i++) { 948c2ecf20Sopenharmony_ci if (val == max77650_charger_vchgin_min_table[i]) { 958c2ecf20Sopenharmony_ci rv = regmap_update_bits(chg->map, 968c2ecf20Sopenharmony_ci MAX77650_REG_CNFG_CHG_B, 978c2ecf20Sopenharmony_ci MAX77650_CHARGER_VCHGIN_MIN_MASK, 988c2ecf20Sopenharmony_ci MAX77650_CHARGER_VCHGIN_MIN_SHIFT(i)); 998c2ecf20Sopenharmony_ci if (rv) 1008c2ecf20Sopenharmony_ci return rv; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci return 0; 1038c2ecf20Sopenharmony_ci } 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci return -EINVAL; 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic int max77650_charger_set_ichgin_lim(struct max77650_charger_data *chg, 1108c2ecf20Sopenharmony_ci unsigned int val) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci int i, rv; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(max77650_charger_ichgin_lim_table); i++) { 1158c2ecf20Sopenharmony_ci if (val == max77650_charger_ichgin_lim_table[i]) { 1168c2ecf20Sopenharmony_ci rv = regmap_update_bits(chg->map, 1178c2ecf20Sopenharmony_ci MAX77650_REG_CNFG_CHG_B, 1188c2ecf20Sopenharmony_ci MAX77650_CHARGER_ICHGIN_LIM_MASK, 1198c2ecf20Sopenharmony_ci MAX77650_CHARGER_ICHGIN_LIM_SHIFT(i)); 1208c2ecf20Sopenharmony_ci if (rv) 1218c2ecf20Sopenharmony_ci return rv; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci return 0; 1248c2ecf20Sopenharmony_ci } 1258c2ecf20Sopenharmony_ci } 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci return -EINVAL; 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic int max77650_charger_enable(struct max77650_charger_data *chg) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci int rv; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci rv = regmap_update_bits(chg->map, 1358c2ecf20Sopenharmony_ci MAX77650_REG_CNFG_CHG_B, 1368c2ecf20Sopenharmony_ci MAX77650_CHARGER_CHG_EN_MASK, 1378c2ecf20Sopenharmony_ci MAX77650_CHARGER_ENABLED); 1388c2ecf20Sopenharmony_ci if (rv) 1398c2ecf20Sopenharmony_ci dev_err(chg->dev, "unable to enable the charger: %d\n", rv); 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci return rv; 1428c2ecf20Sopenharmony_ci} 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_cistatic int max77650_charger_disable(struct max77650_charger_data *chg) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci int rv; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci rv = regmap_update_bits(chg->map, 1498c2ecf20Sopenharmony_ci MAX77650_REG_CNFG_CHG_B, 1508c2ecf20Sopenharmony_ci MAX77650_CHARGER_CHG_EN_MASK, 1518c2ecf20Sopenharmony_ci MAX77650_CHARGER_DISABLED); 1528c2ecf20Sopenharmony_ci if (rv) 1538c2ecf20Sopenharmony_ci dev_err(chg->dev, "unable to disable the charger: %d\n", rv); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci return rv; 1568c2ecf20Sopenharmony_ci} 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_cistatic irqreturn_t max77650_charger_check_status(int irq, void *data) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci struct max77650_charger_data *chg = data; 1618c2ecf20Sopenharmony_ci int rv, reg; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci rv = regmap_read(chg->map, MAX77650_REG_STAT_CHG_B, ®); 1648c2ecf20Sopenharmony_ci if (rv) { 1658c2ecf20Sopenharmony_ci dev_err(chg->dev, 1668c2ecf20Sopenharmony_ci "unable to read the charger status: %d\n", rv); 1678c2ecf20Sopenharmony_ci return IRQ_HANDLED; 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci switch (MAX77650_CHGIN_DETAILS_BITS(reg)) { 1718c2ecf20Sopenharmony_ci case MAX77650_CHGIN_UNDERVOLTAGE_LOCKOUT: 1728c2ecf20Sopenharmony_ci dev_err(chg->dev, "undervoltage lockout detected, disabling charger\n"); 1738c2ecf20Sopenharmony_ci max77650_charger_disable(chg); 1748c2ecf20Sopenharmony_ci break; 1758c2ecf20Sopenharmony_ci case MAX77650_CHGIN_OVERVOLTAGE_LOCKOUT: 1768c2ecf20Sopenharmony_ci dev_err(chg->dev, "overvoltage lockout detected, disabling charger\n"); 1778c2ecf20Sopenharmony_ci max77650_charger_disable(chg); 1788c2ecf20Sopenharmony_ci break; 1798c2ecf20Sopenharmony_ci case MAX77650_CHGIN_OKAY: 1808c2ecf20Sopenharmony_ci max77650_charger_enable(chg); 1818c2ecf20Sopenharmony_ci break; 1828c2ecf20Sopenharmony_ci default: 1838c2ecf20Sopenharmony_ci /* May be 0x10 - debouncing */ 1848c2ecf20Sopenharmony_ci break; 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci return IRQ_HANDLED; 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_cistatic int max77650_charger_get_property(struct power_supply *psy, 1918c2ecf20Sopenharmony_ci enum power_supply_property psp, 1928c2ecf20Sopenharmony_ci union power_supply_propval *val) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci struct max77650_charger_data *chg = power_supply_get_drvdata(psy); 1958c2ecf20Sopenharmony_ci int rv, reg; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci switch (psp) { 1988c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_STATUS: 1998c2ecf20Sopenharmony_ci rv = regmap_read(chg->map, MAX77650_REG_STAT_CHG_B, ®); 2008c2ecf20Sopenharmony_ci if (rv) 2018c2ecf20Sopenharmony_ci return rv; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci if (MAX77650_CHARGER_CHG_CHARGING(reg)) { 2048c2ecf20Sopenharmony_ci val->intval = POWER_SUPPLY_STATUS_CHARGING; 2058c2ecf20Sopenharmony_ci break; 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci switch (MAX77650_CHG_DETAILS_BITS(reg)) { 2098c2ecf20Sopenharmony_ci case MAX77650_CHG_OFF: 2108c2ecf20Sopenharmony_ci case MAX77650_CHG_SUSP_PREQ_TIM_FAULT: 2118c2ecf20Sopenharmony_ci case MAX77650_CHG_SUSP_FAST_CHG_TIM_FAULT: 2128c2ecf20Sopenharmony_ci case MAX77650_CHG_SUSP_BATT_TEMP_FAULT: 2138c2ecf20Sopenharmony_ci val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; 2148c2ecf20Sopenharmony_ci break; 2158c2ecf20Sopenharmony_ci case MAX77650_CHG_PREQ: 2168c2ecf20Sopenharmony_ci case MAX77650_CHG_ON_CURR: 2178c2ecf20Sopenharmony_ci case MAX77650_CHG_ON_CURR_JEITA: 2188c2ecf20Sopenharmony_ci case MAX77650_CHG_ON_VOLT: 2198c2ecf20Sopenharmony_ci case MAX77650_CHG_ON_VOLT_JEITA: 2208c2ecf20Sopenharmony_ci case MAX77650_CHG_ON_TOPOFF: 2218c2ecf20Sopenharmony_ci case MAX77650_CHG_ON_TOPOFF_JEITA: 2228c2ecf20Sopenharmony_ci val->intval = POWER_SUPPLY_STATUS_CHARGING; 2238c2ecf20Sopenharmony_ci break; 2248c2ecf20Sopenharmony_ci case MAX77650_CHG_DONE: 2258c2ecf20Sopenharmony_ci val->intval = POWER_SUPPLY_STATUS_FULL; 2268c2ecf20Sopenharmony_ci break; 2278c2ecf20Sopenharmony_ci default: 2288c2ecf20Sopenharmony_ci val->intval = POWER_SUPPLY_STATUS_UNKNOWN; 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci break; 2318c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_ONLINE: 2328c2ecf20Sopenharmony_ci rv = regmap_read(chg->map, MAX77650_REG_STAT_CHG_B, ®); 2338c2ecf20Sopenharmony_ci if (rv) 2348c2ecf20Sopenharmony_ci return rv; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci val->intval = MAX77650_CHARGER_CHG_CHARGING(reg); 2378c2ecf20Sopenharmony_ci break; 2388c2ecf20Sopenharmony_ci case POWER_SUPPLY_PROP_CHARGE_TYPE: 2398c2ecf20Sopenharmony_ci rv = regmap_read(chg->map, MAX77650_REG_STAT_CHG_B, ®); 2408c2ecf20Sopenharmony_ci if (rv) 2418c2ecf20Sopenharmony_ci return rv; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci if (!MAX77650_CHARGER_CHG_CHARGING(reg)) { 2448c2ecf20Sopenharmony_ci val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE; 2458c2ecf20Sopenharmony_ci break; 2468c2ecf20Sopenharmony_ci } 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci switch (MAX77650_CHG_DETAILS_BITS(reg)) { 2498c2ecf20Sopenharmony_ci case MAX77650_CHG_PREQ: 2508c2ecf20Sopenharmony_ci case MAX77650_CHG_ON_CURR: 2518c2ecf20Sopenharmony_ci case MAX77650_CHG_ON_CURR_JEITA: 2528c2ecf20Sopenharmony_ci case MAX77650_CHG_ON_VOLT: 2538c2ecf20Sopenharmony_ci case MAX77650_CHG_ON_VOLT_JEITA: 2548c2ecf20Sopenharmony_ci val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST; 2558c2ecf20Sopenharmony_ci break; 2568c2ecf20Sopenharmony_ci case MAX77650_CHG_ON_TOPOFF: 2578c2ecf20Sopenharmony_ci case MAX77650_CHG_ON_TOPOFF_JEITA: 2588c2ecf20Sopenharmony_ci val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE; 2598c2ecf20Sopenharmony_ci break; 2608c2ecf20Sopenharmony_ci default: 2618c2ecf20Sopenharmony_ci val->intval = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN; 2628c2ecf20Sopenharmony_ci } 2638c2ecf20Sopenharmony_ci break; 2648c2ecf20Sopenharmony_ci default: 2658c2ecf20Sopenharmony_ci return -EINVAL; 2668c2ecf20Sopenharmony_ci } 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci return 0; 2698c2ecf20Sopenharmony_ci} 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_cistatic const struct power_supply_desc max77650_battery_desc = { 2728c2ecf20Sopenharmony_ci .name = "max77650", 2738c2ecf20Sopenharmony_ci .type = POWER_SUPPLY_TYPE_USB, 2748c2ecf20Sopenharmony_ci .get_property = max77650_charger_get_property, 2758c2ecf20Sopenharmony_ci .properties = max77650_charger_properties, 2768c2ecf20Sopenharmony_ci .num_properties = ARRAY_SIZE(max77650_charger_properties), 2778c2ecf20Sopenharmony_ci}; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_cistatic int max77650_charger_probe(struct platform_device *pdev) 2808c2ecf20Sopenharmony_ci{ 2818c2ecf20Sopenharmony_ci struct power_supply_config pscfg = {}; 2828c2ecf20Sopenharmony_ci struct max77650_charger_data *chg; 2838c2ecf20Sopenharmony_ci struct power_supply *battery; 2848c2ecf20Sopenharmony_ci struct device *dev, *parent; 2858c2ecf20Sopenharmony_ci int rv, chg_irq, chgin_irq; 2868c2ecf20Sopenharmony_ci unsigned int prop; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci dev = &pdev->dev; 2898c2ecf20Sopenharmony_ci parent = dev->parent; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci chg = devm_kzalloc(dev, sizeof(*chg), GFP_KERNEL); 2928c2ecf20Sopenharmony_ci if (!chg) 2938c2ecf20Sopenharmony_ci return -ENOMEM; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, chg); 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci chg->map = dev_get_regmap(parent, NULL); 2988c2ecf20Sopenharmony_ci if (!chg->map) 2998c2ecf20Sopenharmony_ci return -ENODEV; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci chg->dev = dev; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci pscfg.of_node = dev->of_node; 3048c2ecf20Sopenharmony_ci pscfg.drv_data = chg; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci chg_irq = platform_get_irq_byname(pdev, "CHG"); 3078c2ecf20Sopenharmony_ci if (chg_irq < 0) 3088c2ecf20Sopenharmony_ci return chg_irq; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci chgin_irq = platform_get_irq_byname(pdev, "CHGIN"); 3118c2ecf20Sopenharmony_ci if (chgin_irq < 0) 3128c2ecf20Sopenharmony_ci return chgin_irq; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci rv = devm_request_any_context_irq(dev, chg_irq, 3158c2ecf20Sopenharmony_ci max77650_charger_check_status, 3168c2ecf20Sopenharmony_ci IRQF_ONESHOT, "chg", chg); 3178c2ecf20Sopenharmony_ci if (rv < 0) 3188c2ecf20Sopenharmony_ci return rv; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci rv = devm_request_any_context_irq(dev, chgin_irq, 3218c2ecf20Sopenharmony_ci max77650_charger_check_status, 3228c2ecf20Sopenharmony_ci IRQF_ONESHOT, "chgin", chg); 3238c2ecf20Sopenharmony_ci if (rv < 0) 3248c2ecf20Sopenharmony_ci return rv; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci battery = devm_power_supply_register(dev, 3278c2ecf20Sopenharmony_ci &max77650_battery_desc, &pscfg); 3288c2ecf20Sopenharmony_ci if (IS_ERR(battery)) 3298c2ecf20Sopenharmony_ci return PTR_ERR(battery); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci rv = of_property_read_u32(dev->of_node, 3328c2ecf20Sopenharmony_ci "input-voltage-min-microvolt", &prop); 3338c2ecf20Sopenharmony_ci if (rv == 0) { 3348c2ecf20Sopenharmony_ci rv = max77650_charger_set_vchgin_min(chg, prop); 3358c2ecf20Sopenharmony_ci if (rv) 3368c2ecf20Sopenharmony_ci return rv; 3378c2ecf20Sopenharmony_ci } 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci rv = of_property_read_u32(dev->of_node, 3408c2ecf20Sopenharmony_ci "input-current-limit-microamp", &prop); 3418c2ecf20Sopenharmony_ci if (rv == 0) { 3428c2ecf20Sopenharmony_ci rv = max77650_charger_set_ichgin_lim(chg, prop); 3438c2ecf20Sopenharmony_ci if (rv) 3448c2ecf20Sopenharmony_ci return rv; 3458c2ecf20Sopenharmony_ci } 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci return max77650_charger_enable(chg); 3488c2ecf20Sopenharmony_ci} 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_cistatic int max77650_charger_remove(struct platform_device *pdev) 3518c2ecf20Sopenharmony_ci{ 3528c2ecf20Sopenharmony_ci struct max77650_charger_data *chg = platform_get_drvdata(pdev); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci return max77650_charger_disable(chg); 3558c2ecf20Sopenharmony_ci} 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_cistatic const struct of_device_id max77650_charger_of_match[] = { 3588c2ecf20Sopenharmony_ci { .compatible = "maxim,max77650-charger" }, 3598c2ecf20Sopenharmony_ci { } 3608c2ecf20Sopenharmony_ci}; 3618c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, max77650_charger_of_match); 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_cistatic struct platform_driver max77650_charger_driver = { 3648c2ecf20Sopenharmony_ci .driver = { 3658c2ecf20Sopenharmony_ci .name = "max77650-charger", 3668c2ecf20Sopenharmony_ci .of_match_table = max77650_charger_of_match, 3678c2ecf20Sopenharmony_ci }, 3688c2ecf20Sopenharmony_ci .probe = max77650_charger_probe, 3698c2ecf20Sopenharmony_ci .remove = max77650_charger_remove, 3708c2ecf20Sopenharmony_ci}; 3718c2ecf20Sopenharmony_cimodule_platform_driver(max77650_charger_driver); 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("MAXIM 77650/77651 charger driver"); 3748c2ecf20Sopenharmony_ciMODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>"); 3758c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 3768c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:max77650-charger"); 377