18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Battery charger driver for TI's tps65090 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci#include <linux/delay.h> 98c2ecf20Sopenharmony_ci#include <linux/err.h> 108c2ecf20Sopenharmony_ci#include <linux/freezer.h> 118c2ecf20Sopenharmony_ci#include <linux/init.h> 128c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 138c2ecf20Sopenharmony_ci#include <linux/kernel.h> 148c2ecf20Sopenharmony_ci#include <linux/kthread.h> 158c2ecf20Sopenharmony_ci#include <linux/module.h> 168c2ecf20Sopenharmony_ci#include <linux/of_device.h> 178c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 188c2ecf20Sopenharmony_ci#include <linux/power_supply.h> 198c2ecf20Sopenharmony_ci#include <linux/slab.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include <linux/mfd/tps65090.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define TPS65090_CHARGER_ENABLE BIT(0) 248c2ecf20Sopenharmony_ci#define TPS65090_VACG BIT(1) 258c2ecf20Sopenharmony_ci#define TPS65090_NOITERM BIT(5) 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#define POLL_INTERVAL (HZ * 2) /* Used when no irq */ 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistruct tps65090_charger { 308c2ecf20Sopenharmony_ci struct device *dev; 318c2ecf20Sopenharmony_ci int ac_online; 328c2ecf20Sopenharmony_ci int prev_ac_online; 338c2ecf20Sopenharmony_ci int irq; 348c2ecf20Sopenharmony_ci struct task_struct *poll_task; 358c2ecf20Sopenharmony_ci bool passive_mode; 368c2ecf20Sopenharmony_ci struct power_supply *ac; 378c2ecf20Sopenharmony_ci struct tps65090_platform_data *pdata; 388c2ecf20Sopenharmony_ci}; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistatic enum power_supply_property tps65090_ac_props[] = { 418c2ecf20Sopenharmony_ci POWER_SUPPLY_PROP_ONLINE, 428c2ecf20Sopenharmony_ci}; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic int tps65090_low_chrg_current(struct tps65090_charger *charger) 458c2ecf20Sopenharmony_ci{ 468c2ecf20Sopenharmony_ci int ret; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci if (charger->passive_mode) 498c2ecf20Sopenharmony_ci return 0; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci ret = tps65090_write(charger->dev->parent, TPS65090_REG_CG_CTRL5, 528c2ecf20Sopenharmony_ci TPS65090_NOITERM); 538c2ecf20Sopenharmony_ci if (ret < 0) { 548c2ecf20Sopenharmony_ci dev_err(charger->dev, "%s(): error reading in register 0x%x\n", 558c2ecf20Sopenharmony_ci __func__, TPS65090_REG_CG_CTRL5); 568c2ecf20Sopenharmony_ci return ret; 578c2ecf20Sopenharmony_ci } 588c2ecf20Sopenharmony_ci return 0; 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistatic int tps65090_enable_charging(struct tps65090_charger *charger) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci int ret; 648c2ecf20Sopenharmony_ci uint8_t ctrl0 = 0; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci if (charger->passive_mode) 678c2ecf20Sopenharmony_ci return 0; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci ret = tps65090_read(charger->dev->parent, TPS65090_REG_CG_CTRL0, 708c2ecf20Sopenharmony_ci &ctrl0); 718c2ecf20Sopenharmony_ci if (ret < 0) { 728c2ecf20Sopenharmony_ci dev_err(charger->dev, "%s(): error reading in register 0x%x\n", 738c2ecf20Sopenharmony_ci __func__, TPS65090_REG_CG_CTRL0); 748c2ecf20Sopenharmony_ci return ret; 758c2ecf20Sopenharmony_ci } 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci ret = tps65090_write(charger->dev->parent, TPS65090_REG_CG_CTRL0, 788c2ecf20Sopenharmony_ci (ctrl0 | TPS65090_CHARGER_ENABLE)); 798c2ecf20Sopenharmony_ci if (ret < 0) { 808c2ecf20Sopenharmony_ci dev_err(charger->dev, "%s(): error writing in register 0x%x\n", 818c2ecf20Sopenharmony_ci __func__, TPS65090_REG_CG_CTRL0); 828c2ecf20Sopenharmony_ci return ret; 838c2ecf20Sopenharmony_ci } 848c2ecf20Sopenharmony_ci return 0; 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistatic int tps65090_config_charger(struct tps65090_charger *charger) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci uint8_t intrmask = 0; 908c2ecf20Sopenharmony_ci int ret; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci if (charger->passive_mode) 938c2ecf20Sopenharmony_ci return 0; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci if (charger->pdata->enable_low_current_chrg) { 968c2ecf20Sopenharmony_ci ret = tps65090_low_chrg_current(charger); 978c2ecf20Sopenharmony_ci if (ret < 0) { 988c2ecf20Sopenharmony_ci dev_err(charger->dev, 998c2ecf20Sopenharmony_ci "error configuring low charge current\n"); 1008c2ecf20Sopenharmony_ci return ret; 1018c2ecf20Sopenharmony_ci } 1028c2ecf20Sopenharmony_ci } 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci /* Enable the VACG interrupt for AC power detect */ 1058c2ecf20Sopenharmony_ci ret = tps65090_read(charger->dev->parent, TPS65090_REG_INTR_MASK, 1068c2ecf20Sopenharmony_ci &intrmask); 1078c2ecf20Sopenharmony_ci if (ret < 0) { 1088c2ecf20Sopenharmony_ci dev_err(charger->dev, "%s(): error reading in register 0x%x\n", 1098c2ecf20Sopenharmony_ci __func__, TPS65090_REG_INTR_MASK); 1108c2ecf20Sopenharmony_ci return ret; 1118c2ecf20Sopenharmony_ci } 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci ret = tps65090_write(charger->dev->parent, TPS65090_REG_INTR_MASK, 1148c2ecf20Sopenharmony_ci (intrmask | TPS65090_VACG)); 1158c2ecf20Sopenharmony_ci if (ret < 0) { 1168c2ecf20Sopenharmony_ci dev_err(charger->dev, "%s(): error writing in register 0x%x\n", 1178c2ecf20Sopenharmony_ci __func__, TPS65090_REG_CG_CTRL0); 1188c2ecf20Sopenharmony_ci return ret; 1198c2ecf20Sopenharmony_ci } 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci return 0; 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistatic int tps65090_ac_get_property(struct power_supply *psy, 1258c2ecf20Sopenharmony_ci enum power_supply_property psp, 1268c2ecf20Sopenharmony_ci union power_supply_propval *val) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci struct tps65090_charger *charger = power_supply_get_drvdata(psy); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci if (psp == POWER_SUPPLY_PROP_ONLINE) { 1318c2ecf20Sopenharmony_ci val->intval = charger->ac_online; 1328c2ecf20Sopenharmony_ci charger->prev_ac_online = charger->ac_online; 1338c2ecf20Sopenharmony_ci return 0; 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci return -EINVAL; 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cistatic irqreturn_t tps65090_charger_isr(int irq, void *dev_id) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci struct tps65090_charger *charger = dev_id; 1418c2ecf20Sopenharmony_ci int ret; 1428c2ecf20Sopenharmony_ci uint8_t status1 = 0; 1438c2ecf20Sopenharmony_ci uint8_t intrsts = 0; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci ret = tps65090_read(charger->dev->parent, TPS65090_REG_CG_STATUS1, 1468c2ecf20Sopenharmony_ci &status1); 1478c2ecf20Sopenharmony_ci if (ret < 0) { 1488c2ecf20Sopenharmony_ci dev_err(charger->dev, "%s(): Error in reading reg 0x%x\n", 1498c2ecf20Sopenharmony_ci __func__, TPS65090_REG_CG_STATUS1); 1508c2ecf20Sopenharmony_ci return IRQ_HANDLED; 1518c2ecf20Sopenharmony_ci } 1528c2ecf20Sopenharmony_ci msleep(75); 1538c2ecf20Sopenharmony_ci ret = tps65090_read(charger->dev->parent, TPS65090_REG_INTR_STS, 1548c2ecf20Sopenharmony_ci &intrsts); 1558c2ecf20Sopenharmony_ci if (ret < 0) { 1568c2ecf20Sopenharmony_ci dev_err(charger->dev, "%s(): Error in reading reg 0x%x\n", 1578c2ecf20Sopenharmony_ci __func__, TPS65090_REG_INTR_STS); 1588c2ecf20Sopenharmony_ci return IRQ_HANDLED; 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci if (intrsts & TPS65090_VACG) { 1628c2ecf20Sopenharmony_ci ret = tps65090_enable_charging(charger); 1638c2ecf20Sopenharmony_ci if (ret < 0) 1648c2ecf20Sopenharmony_ci return IRQ_HANDLED; 1658c2ecf20Sopenharmony_ci charger->ac_online = 1; 1668c2ecf20Sopenharmony_ci } else { 1678c2ecf20Sopenharmony_ci charger->ac_online = 0; 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci /* Clear interrupts. */ 1718c2ecf20Sopenharmony_ci if (!charger->passive_mode) { 1728c2ecf20Sopenharmony_ci ret = tps65090_write(charger->dev->parent, 1738c2ecf20Sopenharmony_ci TPS65090_REG_INTR_STS, 0x00); 1748c2ecf20Sopenharmony_ci if (ret < 0) { 1758c2ecf20Sopenharmony_ci dev_err(charger->dev, 1768c2ecf20Sopenharmony_ci "%s(): Error in writing reg 0x%x\n", 1778c2ecf20Sopenharmony_ci __func__, TPS65090_REG_INTR_STS); 1788c2ecf20Sopenharmony_ci } 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci if (charger->prev_ac_online != charger->ac_online) 1828c2ecf20Sopenharmony_ci power_supply_changed(charger->ac); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci return IRQ_HANDLED; 1858c2ecf20Sopenharmony_ci} 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_cistatic struct tps65090_platform_data * 1888c2ecf20Sopenharmony_ci tps65090_parse_dt_charger_data(struct platform_device *pdev) 1898c2ecf20Sopenharmony_ci{ 1908c2ecf20Sopenharmony_ci struct tps65090_platform_data *pdata; 1918c2ecf20Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 1928c2ecf20Sopenharmony_ci unsigned int prop; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); 1958c2ecf20Sopenharmony_ci if (!pdata) { 1968c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Memory alloc for tps65090_pdata failed\n"); 1978c2ecf20Sopenharmony_ci return NULL; 1988c2ecf20Sopenharmony_ci } 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci prop = of_property_read_bool(np, "ti,enable-low-current-chrg"); 2018c2ecf20Sopenharmony_ci pdata->enable_low_current_chrg = prop; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci pdata->irq_base = -1; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci return pdata; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci} 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_cistatic int tps65090_charger_poll_task(void *data) 2108c2ecf20Sopenharmony_ci{ 2118c2ecf20Sopenharmony_ci set_freezable(); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci while (!kthread_should_stop()) { 2148c2ecf20Sopenharmony_ci schedule_timeout_interruptible(POLL_INTERVAL); 2158c2ecf20Sopenharmony_ci try_to_freeze(); 2168c2ecf20Sopenharmony_ci tps65090_charger_isr(-1, data); 2178c2ecf20Sopenharmony_ci } 2188c2ecf20Sopenharmony_ci return 0; 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic const struct power_supply_desc tps65090_charger_desc = { 2228c2ecf20Sopenharmony_ci .name = "tps65090-ac", 2238c2ecf20Sopenharmony_ci .type = POWER_SUPPLY_TYPE_MAINS, 2248c2ecf20Sopenharmony_ci .get_property = tps65090_ac_get_property, 2258c2ecf20Sopenharmony_ci .properties = tps65090_ac_props, 2268c2ecf20Sopenharmony_ci .num_properties = ARRAY_SIZE(tps65090_ac_props), 2278c2ecf20Sopenharmony_ci}; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_cistatic int tps65090_charger_probe(struct platform_device *pdev) 2308c2ecf20Sopenharmony_ci{ 2318c2ecf20Sopenharmony_ci struct tps65090_charger *cdata; 2328c2ecf20Sopenharmony_ci struct tps65090_platform_data *pdata; 2338c2ecf20Sopenharmony_ci struct power_supply_config psy_cfg = {}; 2348c2ecf20Sopenharmony_ci uint8_t status1 = 0; 2358c2ecf20Sopenharmony_ci int ret; 2368c2ecf20Sopenharmony_ci int irq; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci pdata = dev_get_platdata(pdev->dev.parent); 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_OF) && !pdata && pdev->dev.of_node) 2418c2ecf20Sopenharmony_ci pdata = tps65090_parse_dt_charger_data(pdev); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci if (!pdata) { 2448c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "%s():no platform data available\n", 2458c2ecf20Sopenharmony_ci __func__); 2468c2ecf20Sopenharmony_ci return -ENODEV; 2478c2ecf20Sopenharmony_ci } 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci cdata = devm_kzalloc(&pdev->dev, sizeof(*cdata), GFP_KERNEL); 2508c2ecf20Sopenharmony_ci if (!cdata) { 2518c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to allocate memory status\n"); 2528c2ecf20Sopenharmony_ci return -ENOMEM; 2538c2ecf20Sopenharmony_ci } 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, cdata); 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci cdata->dev = &pdev->dev; 2588c2ecf20Sopenharmony_ci cdata->pdata = pdata; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci psy_cfg.supplied_to = pdata->supplied_to; 2618c2ecf20Sopenharmony_ci psy_cfg.num_supplicants = pdata->num_supplicants; 2628c2ecf20Sopenharmony_ci psy_cfg.of_node = pdev->dev.of_node; 2638c2ecf20Sopenharmony_ci psy_cfg.drv_data = cdata; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci cdata->ac = power_supply_register(&pdev->dev, &tps65090_charger_desc, 2668c2ecf20Sopenharmony_ci &psy_cfg); 2678c2ecf20Sopenharmony_ci if (IS_ERR(cdata->ac)) { 2688c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed: power supply register\n"); 2698c2ecf20Sopenharmony_ci return PTR_ERR(cdata->ac); 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci irq = platform_get_irq(pdev, 0); 2738c2ecf20Sopenharmony_ci if (irq < 0) 2748c2ecf20Sopenharmony_ci irq = -ENXIO; 2758c2ecf20Sopenharmony_ci cdata->irq = irq; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci ret = tps65090_config_charger(cdata); 2788c2ecf20Sopenharmony_ci if (ret < 0) { 2798c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "charger config failed, err %d\n", ret); 2808c2ecf20Sopenharmony_ci goto fail_unregister_supply; 2818c2ecf20Sopenharmony_ci } 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci /* Check for charger presence */ 2848c2ecf20Sopenharmony_ci ret = tps65090_read(cdata->dev->parent, TPS65090_REG_CG_STATUS1, 2858c2ecf20Sopenharmony_ci &status1); 2868c2ecf20Sopenharmony_ci if (ret < 0) { 2878c2ecf20Sopenharmony_ci dev_err(cdata->dev, "%s(): Error in reading reg 0x%x", __func__, 2888c2ecf20Sopenharmony_ci TPS65090_REG_CG_STATUS1); 2898c2ecf20Sopenharmony_ci goto fail_unregister_supply; 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci if (status1 != 0) { 2938c2ecf20Sopenharmony_ci ret = tps65090_enable_charging(cdata); 2948c2ecf20Sopenharmony_ci if (ret < 0) { 2958c2ecf20Sopenharmony_ci dev_err(cdata->dev, "error enabling charger\n"); 2968c2ecf20Sopenharmony_ci goto fail_unregister_supply; 2978c2ecf20Sopenharmony_ci } 2988c2ecf20Sopenharmony_ci cdata->ac_online = 1; 2998c2ecf20Sopenharmony_ci power_supply_changed(cdata->ac); 3008c2ecf20Sopenharmony_ci } 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci if (irq != -ENXIO) { 3038c2ecf20Sopenharmony_ci ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, 3048c2ecf20Sopenharmony_ci tps65090_charger_isr, IRQF_ONESHOT, "tps65090-charger", cdata); 3058c2ecf20Sopenharmony_ci if (ret) { 3068c2ecf20Sopenharmony_ci dev_err(cdata->dev, 3078c2ecf20Sopenharmony_ci "Unable to register irq %d err %d\n", irq, 3088c2ecf20Sopenharmony_ci ret); 3098c2ecf20Sopenharmony_ci goto fail_unregister_supply; 3108c2ecf20Sopenharmony_ci } 3118c2ecf20Sopenharmony_ci } else { 3128c2ecf20Sopenharmony_ci cdata->poll_task = kthread_run(tps65090_charger_poll_task, 3138c2ecf20Sopenharmony_ci cdata, "ktps65090charger"); 3148c2ecf20Sopenharmony_ci cdata->passive_mode = true; 3158c2ecf20Sopenharmony_ci if (IS_ERR(cdata->poll_task)) { 3168c2ecf20Sopenharmony_ci ret = PTR_ERR(cdata->poll_task); 3178c2ecf20Sopenharmony_ci dev_err(cdata->dev, 3188c2ecf20Sopenharmony_ci "Unable to run kthread err %d\n", ret); 3198c2ecf20Sopenharmony_ci goto fail_unregister_supply; 3208c2ecf20Sopenharmony_ci } 3218c2ecf20Sopenharmony_ci } 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci return 0; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_cifail_unregister_supply: 3268c2ecf20Sopenharmony_ci power_supply_unregister(cdata->ac); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci return ret; 3298c2ecf20Sopenharmony_ci} 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_cistatic int tps65090_charger_remove(struct platform_device *pdev) 3328c2ecf20Sopenharmony_ci{ 3338c2ecf20Sopenharmony_ci struct tps65090_charger *cdata = platform_get_drvdata(pdev); 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci if (cdata->irq == -ENXIO) 3368c2ecf20Sopenharmony_ci kthread_stop(cdata->poll_task); 3378c2ecf20Sopenharmony_ci power_supply_unregister(cdata->ac); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci return 0; 3408c2ecf20Sopenharmony_ci} 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_cistatic const struct of_device_id of_tps65090_charger_match[] = { 3438c2ecf20Sopenharmony_ci { .compatible = "ti,tps65090-charger", }, 3448c2ecf20Sopenharmony_ci { /* end */ } 3458c2ecf20Sopenharmony_ci}; 3468c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, of_tps65090_charger_match); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_cistatic struct platform_driver tps65090_charger_driver = { 3498c2ecf20Sopenharmony_ci .driver = { 3508c2ecf20Sopenharmony_ci .name = "tps65090-charger", 3518c2ecf20Sopenharmony_ci .of_match_table = of_tps65090_charger_match, 3528c2ecf20Sopenharmony_ci }, 3538c2ecf20Sopenharmony_ci .probe = tps65090_charger_probe, 3548c2ecf20Sopenharmony_ci .remove = tps65090_charger_remove, 3558c2ecf20Sopenharmony_ci}; 3568c2ecf20Sopenharmony_cimodule_platform_driver(tps65090_charger_driver); 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 3598c2ecf20Sopenharmony_ciMODULE_AUTHOR("Syed Rafiuddin <srafiuddin@nvidia.com>"); 3608c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("tps65090 battery charger driver"); 361