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