Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 // Battery charger driver for TI's tps65217
0003 //
0004 // Copyright (C) 2015 Collabora Ltd.
0005 // Author: Enric Balletbo i Serra <enric.balletbo@collabora.com>
0006 
0007 /*
0008  * Battery charger driver for TI's tps65217
0009  */
0010 #include <linux/kernel.h>
0011 #include <linux/kthread.h>
0012 #include <linux/device.h>
0013 #include <linux/module.h>
0014 #include <linux/platform_device.h>
0015 #include <linux/init.h>
0016 #include <linux/interrupt.h>
0017 #include <linux/slab.h>
0018 #include <linux/err.h>
0019 #include <linux/of.h>
0020 #include <linux/of_device.h>
0021 #include <linux/power_supply.h>
0022 
0023 #include <linux/mfd/core.h>
0024 #include <linux/mfd/tps65217.h>
0025 
0026 #define CHARGER_STATUS_PRESENT  (TPS65217_STATUS_ACPWR | TPS65217_STATUS_USBPWR)
0027 #define NUM_CHARGER_IRQS    2
0028 #define POLL_INTERVAL       (HZ * 2)
0029 
0030 struct tps65217_charger {
0031     struct tps65217 *tps;
0032     struct device *dev;
0033     struct power_supply *psy;
0034 
0035     int online;
0036     int prev_online;
0037 
0038     struct task_struct  *poll_task;
0039 };
0040 
0041 static enum power_supply_property tps65217_charger_props[] = {
0042     POWER_SUPPLY_PROP_ONLINE,
0043 };
0044 
0045 static int tps65217_config_charger(struct tps65217_charger *charger)
0046 {
0047     int ret;
0048 
0049     /*
0050      * tps65217 rev. G, p. 31 (see p. 32 for NTC schematic)
0051      *
0052      * The device can be configured to support a 100k NTC (B = 3960) by
0053      * setting the the NTC_TYPE bit in register CHGCONFIG1 to 1. However it
0054      * is not recommended to do so. In sleep mode, the charger continues
0055      * charging the battery, but all register values are reset to default
0056      * values. Therefore, the charger would get the wrong temperature
0057      * information. If 100k NTC setting is required, please contact the
0058      * factory.
0059      *
0060      * ATTENTION, conflicting information, from p. 46
0061      *
0062      * NTC TYPE (for battery temperature measurement)
0063      *   0 – 100k (curve 1, B = 3960)
0064      *   1 – 10k  (curve 2, B = 3480) (default on reset)
0065      *
0066      */
0067     ret = tps65217_clear_bits(charger->tps, TPS65217_REG_CHGCONFIG1,
0068                   TPS65217_CHGCONFIG1_NTC_TYPE,
0069                   TPS65217_PROTECT_NONE);
0070     if (ret) {
0071         dev_err(charger->dev,
0072             "failed to set 100k NTC setting: %d\n", ret);
0073         return ret;
0074     }
0075 
0076     return 0;
0077 }
0078 
0079 static int tps65217_enable_charging(struct tps65217_charger *charger)
0080 {
0081     int ret;
0082 
0083     /* charger already enabled */
0084     if (charger->online)
0085         return 0;
0086 
0087     dev_dbg(charger->dev, "%s: enable charging\n", __func__);
0088     ret = tps65217_set_bits(charger->tps, TPS65217_REG_CHGCONFIG1,
0089                 TPS65217_CHGCONFIG1_CHG_EN,
0090                 TPS65217_CHGCONFIG1_CHG_EN,
0091                 TPS65217_PROTECT_NONE);
0092     if (ret) {
0093         dev_err(charger->dev,
0094             "%s: Error in writing CHG_EN in reg 0x%x: %d\n",
0095             __func__, TPS65217_REG_CHGCONFIG1, ret);
0096         return ret;
0097     }
0098 
0099     charger->online = 1;
0100 
0101     return 0;
0102 }
0103 
0104 static int tps65217_charger_get_property(struct power_supply *psy,
0105                      enum power_supply_property psp,
0106                      union power_supply_propval *val)
0107 {
0108     struct tps65217_charger *charger = power_supply_get_drvdata(psy);
0109 
0110     if (psp == POWER_SUPPLY_PROP_ONLINE) {
0111         val->intval = charger->online;
0112         return 0;
0113     }
0114     return -EINVAL;
0115 }
0116 
0117 static irqreturn_t tps65217_charger_irq(int irq, void *dev)
0118 {
0119     int ret, val;
0120     struct tps65217_charger *charger = dev;
0121 
0122     charger->prev_online = charger->online;
0123 
0124     ret = tps65217_reg_read(charger->tps, TPS65217_REG_STATUS, &val);
0125     if (ret < 0) {
0126         dev_err(charger->dev, "%s: Error in reading reg 0x%x\n",
0127             __func__, TPS65217_REG_STATUS);
0128         return IRQ_HANDLED;
0129     }
0130 
0131     dev_dbg(charger->dev, "%s: 0x%x\n", __func__, val);
0132 
0133     /* check for charger status bit */
0134     if (val & CHARGER_STATUS_PRESENT) {
0135         ret = tps65217_enable_charging(charger);
0136         if (ret) {
0137             dev_err(charger->dev,
0138                 "failed to enable charger: %d\n", ret);
0139             return IRQ_HANDLED;
0140         }
0141     } else {
0142         charger->online = 0;
0143     }
0144 
0145     if (charger->prev_online != charger->online)
0146         power_supply_changed(charger->psy);
0147 
0148     ret = tps65217_reg_read(charger->tps, TPS65217_REG_CHGCONFIG0, &val);
0149     if (ret < 0) {
0150         dev_err(charger->dev, "%s: Error in reading reg 0x%x\n",
0151             __func__, TPS65217_REG_CHGCONFIG0);
0152         return IRQ_HANDLED;
0153     }
0154 
0155     if (val & TPS65217_CHGCONFIG0_ACTIVE)
0156         dev_dbg(charger->dev, "%s: charger is charging\n", __func__);
0157     else
0158         dev_dbg(charger->dev,
0159             "%s: charger is NOT charging\n", __func__);
0160 
0161     return IRQ_HANDLED;
0162 }
0163 
0164 static int tps65217_charger_poll_task(void *data)
0165 {
0166     set_freezable();
0167 
0168     while (!kthread_should_stop()) {
0169         schedule_timeout_interruptible(POLL_INTERVAL);
0170         try_to_freeze();
0171         tps65217_charger_irq(-1, data);
0172     }
0173     return 0;
0174 }
0175 
0176 static const struct power_supply_desc tps65217_charger_desc = {
0177     .name           = "tps65217-charger",
0178     .type           = POWER_SUPPLY_TYPE_MAINS,
0179     .get_property       = tps65217_charger_get_property,
0180     .properties     = tps65217_charger_props,
0181     .num_properties     = ARRAY_SIZE(tps65217_charger_props),
0182 };
0183 
0184 static int tps65217_charger_probe(struct platform_device *pdev)
0185 {
0186     struct tps65217 *tps = dev_get_drvdata(pdev->dev.parent);
0187     struct tps65217_charger *charger;
0188     struct power_supply_config cfg = {};
0189     struct task_struct *poll_task;
0190     int irq[NUM_CHARGER_IRQS];
0191     int ret;
0192     int i;
0193 
0194     charger = devm_kzalloc(&pdev->dev, sizeof(*charger), GFP_KERNEL);
0195     if (!charger)
0196         return -ENOMEM;
0197 
0198     platform_set_drvdata(pdev, charger);
0199     charger->tps = tps;
0200     charger->dev = &pdev->dev;
0201 
0202     cfg.of_node = pdev->dev.of_node;
0203     cfg.drv_data = charger;
0204 
0205     charger->psy = devm_power_supply_register(&pdev->dev,
0206                           &tps65217_charger_desc,
0207                           &cfg);
0208     if (IS_ERR(charger->psy)) {
0209         dev_err(&pdev->dev, "failed: power supply register\n");
0210         return PTR_ERR(charger->psy);
0211     }
0212 
0213     irq[0] = platform_get_irq_byname(pdev, "USB");
0214     irq[1] = platform_get_irq_byname(pdev, "AC");
0215 
0216     ret = tps65217_config_charger(charger);
0217     if (ret < 0) {
0218         dev_err(charger->dev, "charger config failed, err %d\n", ret);
0219         return ret;
0220     }
0221 
0222     /* Create a polling thread if an interrupt is invalid */
0223     if (irq[0] < 0 || irq[1] < 0) {
0224         poll_task = kthread_run(tps65217_charger_poll_task,
0225                     charger, "ktps65217charger");
0226         if (IS_ERR(poll_task)) {
0227             ret = PTR_ERR(poll_task);
0228             dev_err(charger->dev,
0229                 "Unable to run kthread err %d\n", ret);
0230             return ret;
0231         }
0232 
0233         charger->poll_task = poll_task;
0234         return 0;
0235     }
0236 
0237     /* Create IRQ threads for charger interrupts */
0238     for (i = 0; i < NUM_CHARGER_IRQS; i++) {
0239         ret = devm_request_threaded_irq(&pdev->dev, irq[i], NULL,
0240                         tps65217_charger_irq,
0241                         IRQF_ONESHOT, "tps65217-charger",
0242                         charger);
0243         if (ret) {
0244             dev_err(charger->dev,
0245                 "Unable to register irq %d err %d\n", irq[i],
0246                 ret);
0247             return ret;
0248         }
0249 
0250         /* Check current state */
0251         tps65217_charger_irq(-1, charger);
0252     }
0253 
0254     return 0;
0255 }
0256 
0257 static int tps65217_charger_remove(struct platform_device *pdev)
0258 {
0259     struct tps65217_charger *charger = platform_get_drvdata(pdev);
0260 
0261     if (charger->poll_task)
0262         kthread_stop(charger->poll_task);
0263 
0264     return 0;
0265 }
0266 
0267 static const struct of_device_id tps65217_charger_match_table[] = {
0268     { .compatible = "ti,tps65217-charger", },
0269     { /* sentinel */ }
0270 };
0271 MODULE_DEVICE_TABLE(of, tps65217_charger_match_table);
0272 
0273 static struct platform_driver tps65217_charger_driver = {
0274     .probe  = tps65217_charger_probe,
0275     .remove = tps65217_charger_remove,
0276     .driver = {
0277         .name   = "tps65217-charger",
0278         .of_match_table = of_match_ptr(tps65217_charger_match_table),
0279     },
0280 
0281 };
0282 module_platform_driver(tps65217_charger_driver);
0283 
0284 MODULE_LICENSE("GPL v2");
0285 MODULE_AUTHOR("Enric Balletbo Serra <enric.balletbo@collabora.com>");
0286 MODULE_DESCRIPTION("TPS65217 battery charger driver");