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