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