0001
0002
0003
0004
0005
0006
0007
0008
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
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
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
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
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
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
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
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 { }
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");