1 // SPDX-License-Identifier: GPL-2.0 2 // Battery charger driver for TI's tps65217 3 // 4 // Copyright (C) 2015 Collabora Ltd. 5 // Author: Enric Balletbo i Serra <enric.balletbo@collabora.com> 6 7 /* 8 * Battery charger driver for TI's tps65217 9 */ 10 #include <linux/kernel.h> 11 #include <linux/kthread.h> 12 #include <linux/device.h> 13 #include <linux/module.h> 14 #include <linux/platform_device.h> 15 #include <linux/init.h> 16 #include <linux/interrupt.h> 17 #include <linux/slab.h> 18 #include <linux/err.h> 19 #include <linux/of.h> 20 #include <linux/power_supply.h> 21 22 #include <linux/mfd/core.h> 23 #include <linux/mfd/tps65217.h> 24 25 #define CHARGER_STATUS_PRESENT (TPS65217_STATUS_ACPWR | TPS65217_STATUS_USBPWR) 26 #define NUM_CHARGER_IRQS 2 27 #define POLL_INTERVAL (HZ * 2) 28 29 struct tps65217_charger { 30 struct tps65217 *tps; 31 struct device *dev; 32 struct power_supply *psy; 33 34 int online; 35 int prev_online; 36 37 struct task_struct *poll_task; 38 }; 39 40 static enum power_supply_property tps65217_charger_props[] = { 41 POWER_SUPPLY_PROP_ONLINE, 42 }; 43 44 static int tps65217_config_charger(struct tps65217_charger *charger) 45 { 46 int ret; 47 48 /* 49 * tps65217 rev. G, p. 31 (see p. 32 for NTC schematic) 50 * 51 * The device can be configured to support a 100k NTC (B = 3960) by 52 * setting the NTC_TYPE bit in register CHGCONFIG1 to 1. However it 53 * is not recommended to do so. In sleep mode, the charger continues 54 * charging the battery, but all register values are reset to default 55 * values. Therefore, the charger would get the wrong temperature 56 * information. If 100k NTC setting is required, please contact the 57 * factory. 58 * 59 * ATTENTION, conflicting information, from p. 46 60 * 61 * NTC TYPE (for battery temperature measurement) 62 * 0 – 100k (curve 1, B = 3960) 63 * 1 – 10k (curve 2, B = 3480) (default on reset) 64 * 65 */ 66 ret = tps65217_clear_bits(charger->tps, TPS65217_REG_CHGCONFIG1, 67 TPS65217_CHGCONFIG1_NTC_TYPE, 68 TPS65217_PROTECT_NONE); 69 if (ret) { 70 dev_err(charger->dev, 71 "failed to set 100k NTC setting: %d\n", ret); 72 return ret; 73 } 74 75 return 0; 76 } 77 78 static int tps65217_enable_charging(struct tps65217_charger *charger) 79 { 80 int ret; 81 82 /* charger already enabled */ 83 if (charger->online) 84 return 0; 85 86 dev_dbg(charger->dev, "%s: enable charging\n", __func__); 87 ret = tps65217_set_bits(charger->tps, TPS65217_REG_CHGCONFIG1, 88 TPS65217_CHGCONFIG1_CHG_EN, 89 TPS65217_CHGCONFIG1_CHG_EN, 90 TPS65217_PROTECT_NONE); 91 if (ret) { 92 dev_err(charger->dev, 93 "%s: Error in writing CHG_EN in reg 0x%x: %d\n", 94 __func__, TPS65217_REG_CHGCONFIG1, ret); 95 return ret; 96 } 97 98 charger->online = 1; 99 100 return 0; 101 } 102 103 static int tps65217_charger_get_property(struct power_supply *psy, 104 enum power_supply_property psp, 105 union power_supply_propval *val) 106 { 107 struct tps65217_charger *charger = power_supply_get_drvdata(psy); 108 109 if (psp == POWER_SUPPLY_PROP_ONLINE) { 110 val->intval = charger->online; 111 return 0; 112 } 113 return -EINVAL; 114 } 115 116 static irqreturn_t tps65217_charger_irq(int irq, void *dev) 117 { 118 int ret, val; 119 struct tps65217_charger *charger = dev; 120 121 charger->prev_online = charger->online; 122 123 ret = tps65217_reg_read(charger->tps, TPS65217_REG_STATUS, &val); 124 if (ret < 0) { 125 dev_err(charger->dev, "%s: Error in reading reg 0x%x\n", 126 __func__, TPS65217_REG_STATUS); 127 return IRQ_HANDLED; 128 } 129 130 dev_dbg(charger->dev, "%s: 0x%x\n", __func__, val); 131 132 /* check for charger status bit */ 133 if (val & CHARGER_STATUS_PRESENT) { 134 ret = tps65217_enable_charging(charger); 135 if (ret) { 136 dev_err(charger->dev, 137 "failed to enable charger: %d\n", ret); 138 return IRQ_HANDLED; 139 } 140 } else { 141 charger->online = 0; 142 } 143 144 if (charger->prev_online != charger->online) 145 power_supply_changed(charger->psy); 146 147 ret = tps65217_reg_read(charger->tps, TPS65217_REG_CHGCONFIG0, &val); 148 if (ret < 0) { 149 dev_err(charger->dev, "%s: Error in reading reg 0x%x\n", 150 __func__, TPS65217_REG_CHGCONFIG0); 151 return IRQ_HANDLED; 152 } 153 154 if (val & TPS65217_CHGCONFIG0_ACTIVE) 155 dev_dbg(charger->dev, "%s: charger is charging\n", __func__); 156 else 157 dev_dbg(charger->dev, 158 "%s: charger is NOT charging\n", __func__); 159 160 return IRQ_HANDLED; 161 } 162 163 static int tps65217_charger_poll_task(void *data) 164 { 165 set_freezable(); 166 167 while (!kthread_should_stop()) { 168 schedule_timeout_interruptible(POLL_INTERVAL); 169 try_to_freeze(); 170 tps65217_charger_irq(-1, data); 171 } 172 return 0; 173 } 174 175 static const struct power_supply_desc tps65217_charger_desc = { 176 .name = "tps65217-charger", 177 .type = POWER_SUPPLY_TYPE_MAINS, 178 .get_property = tps65217_charger_get_property, 179 .properties = tps65217_charger_props, 180 .num_properties = ARRAY_SIZE(tps65217_charger_props), 181 }; 182 183 static int tps65217_charger_probe(struct platform_device *pdev) 184 { 185 struct tps65217 *tps = dev_get_drvdata(pdev->dev.parent); 186 struct tps65217_charger *charger; 187 struct power_supply_config cfg = {}; 188 struct task_struct *poll_task; 189 int irq[NUM_CHARGER_IRQS]; 190 int ret; 191 int i; 192 193 charger = devm_kzalloc(&pdev->dev, sizeof(*charger), GFP_KERNEL); 194 if (!charger) 195 return -ENOMEM; 196 197 platform_set_drvdata(pdev, charger); 198 charger->tps = tps; 199 charger->dev = &pdev->dev; 200 201 cfg.of_node = pdev->dev.of_node; 202 cfg.drv_data = charger; 203 204 charger->psy = devm_power_supply_register(&pdev->dev, 205 &tps65217_charger_desc, 206 &cfg); 207 if (IS_ERR(charger->psy)) { 208 dev_err(&pdev->dev, "failed: power supply register\n"); 209 return PTR_ERR(charger->psy); 210 } 211 212 irq[0] = platform_get_irq_byname(pdev, "USB"); 213 irq[1] = platform_get_irq_byname(pdev, "AC"); 214 215 ret = tps65217_config_charger(charger); 216 if (ret < 0) { 217 dev_err(charger->dev, "charger config failed, err %d\n", ret); 218 return ret; 219 } 220 221 /* Create a polling thread if an interrupt is invalid */ 222 if (irq[0] < 0 || irq[1] < 0) { 223 poll_task = kthread_run(tps65217_charger_poll_task, 224 charger, "ktps65217charger"); 225 if (IS_ERR(poll_task)) { 226 ret = PTR_ERR(poll_task); 227 dev_err(charger->dev, 228 "Unable to run kthread err %d\n", ret); 229 return ret; 230 } 231 232 charger->poll_task = poll_task; 233 return 0; 234 } 235 236 /* Create IRQ threads for charger interrupts */ 237 for (i = 0; i < NUM_CHARGER_IRQS; i++) { 238 ret = devm_request_threaded_irq(&pdev->dev, irq[i], NULL, 239 tps65217_charger_irq, 240 IRQF_SHARED, "tps65217-charger", 241 charger); 242 if (ret) { 243 dev_err(charger->dev, 244 "Unable to register irq %d err %d\n", irq[i], 245 ret); 246 return ret; 247 } 248 249 /* Check current state */ 250 tps65217_charger_irq(-1, charger); 251 } 252 253 return 0; 254 } 255 256 static void tps65217_charger_remove(struct platform_device *pdev) 257 { 258 struct tps65217_charger *charger = platform_get_drvdata(pdev); 259 260 if (charger->poll_task) 261 kthread_stop(charger->poll_task); 262 } 263 264 static const struct of_device_id tps65217_charger_match_table[] = { 265 { .compatible = "ti,tps65217-charger", }, 266 { /* sentinel */ } 267 }; 268 MODULE_DEVICE_TABLE(of, tps65217_charger_match_table); 269 270 static struct platform_driver tps65217_charger_driver = { 271 .probe = tps65217_charger_probe, 272 .remove_new = tps65217_charger_remove, 273 .driver = { 274 .name = "tps65217-charger", 275 .of_match_table = of_match_ptr(tps65217_charger_match_table), 276 }, 277 278 }; 279 module_platform_driver(tps65217_charger_driver); 280 281 MODULE_LICENSE("GPL v2"); 282 MODULE_AUTHOR("Enric Balletbo Serra <enric.balletbo@collabora.com>"); 283 MODULE_DESCRIPTION("TPS65217 battery charger driver"); 284