brintos

brintos / linux-shallow public Read only

0
0
Text · 7.0 KiB · 2382749 Raw
284 lines · c
1// SPDX-License-Identifier: GPL-2.02// Battery charger driver for TI's tps652173//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 tps652179 */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	227#define POLL_INTERVAL		(HZ * 2)28 29struct 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 40static enum power_supply_property tps65217_charger_props[] = {41	POWER_SUPPLY_PROP_ONLINE,42};43 44static 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) by52	 * setting the NTC_TYPE bit in register CHGCONFIG1 to 1. However it53	 * is not recommended to do so. In sleep mode, the charger continues54	 * charging the battery, but all register values are reset to default55	 * values. Therefore, the charger would get the wrong temperature56	 * information. If 100k NTC setting is required, please contact the57	 * factory.58	 *59	 * ATTENTION, conflicting information, from p. 4660	 *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 78static 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 103static 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 116static 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	else157		dev_dbg(charger->dev,158			"%s: charger is NOT charging\n", __func__);159 160	return IRQ_HANDLED;161}162 163static 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 175static 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 183static 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 256static 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 264static const struct of_device_id tps65217_charger_match_table[] = {265	{ .compatible = "ti,tps65217-charger", },266	{ /* sentinel */ }267};268MODULE_DEVICE_TABLE(of, tps65217_charger_match_table);269 270static 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};279module_platform_driver(tps65217_charger_driver);280 281MODULE_LICENSE("GPL v2");282MODULE_AUTHOR("Enric Balletbo Serra <enric.balletbo@collabora.com>");283MODULE_DESCRIPTION("TPS65217 battery charger driver");284