brintos

brintos / linux-shallow public Read only

0
0
Text · 5.9 KiB · 8de500f Raw
208 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 *  Driver for Analog Devices (Linear Technology) LT3651 charger IC.4 *  Copyright (C) 2017, Topic Embedded Products5 */6 7#include <linux/device.h>8#include <linux/gpio/consumer.h>9#include <linux/init.h>10#include <linux/interrupt.h>11#include <linux/kernel.h>12#include <linux/module.h>13#include <linux/platform_device.h>14#include <linux/power_supply.h>15#include <linux/slab.h>16#include <linux/of.h>17 18struct lt3651_charger {19	struct power_supply *charger;20	struct power_supply_desc charger_desc;21	struct gpio_desc *acpr_gpio;22	struct gpio_desc *fault_gpio;23	struct gpio_desc *chrg_gpio;24};25 26static irqreturn_t lt3651_charger_irq(int irq, void *devid)27{28	struct power_supply *charger = devid;29 30	power_supply_changed(charger);31 32	return IRQ_HANDLED;33}34 35static inline struct lt3651_charger *psy_to_lt3651_charger(36	struct power_supply *psy)37{38	return power_supply_get_drvdata(psy);39}40 41static int lt3651_charger_get_property(struct power_supply *psy,42		enum power_supply_property psp, union power_supply_propval *val)43{44	struct lt3651_charger *lt3651_charger = psy_to_lt3651_charger(psy);45 46	switch (psp) {47	case POWER_SUPPLY_PROP_STATUS:48		if (!lt3651_charger->chrg_gpio) {49			val->intval = POWER_SUPPLY_STATUS_UNKNOWN;50			break;51		}52		if (gpiod_get_value(lt3651_charger->chrg_gpio))53			val->intval = POWER_SUPPLY_STATUS_CHARGING;54		else55			val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;56		break;57	case POWER_SUPPLY_PROP_ONLINE:58		val->intval = gpiod_get_value(lt3651_charger->acpr_gpio);59		break;60	case POWER_SUPPLY_PROP_HEALTH:61		if (!lt3651_charger->fault_gpio) {62			val->intval = POWER_SUPPLY_HEALTH_UNKNOWN;63			break;64		}65		if (!gpiod_get_value(lt3651_charger->fault_gpio)) {66			val->intval = POWER_SUPPLY_HEALTH_GOOD;67			break;68		}69		/*70		 * If the fault pin is active, the chrg pin explains the type71		 * of failure.72		 */73		if (!lt3651_charger->chrg_gpio) {74			val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;75			break;76		}77		val->intval = gpiod_get_value(lt3651_charger->chrg_gpio) ?78				POWER_SUPPLY_HEALTH_OVERHEAT :79				POWER_SUPPLY_HEALTH_DEAD;80		break;81	default:82		return -EINVAL;83	}84 85	return 0;86}87 88static enum power_supply_property lt3651_charger_properties[] = {89	POWER_SUPPLY_PROP_STATUS,90	POWER_SUPPLY_PROP_ONLINE,91	POWER_SUPPLY_PROP_HEALTH,92};93 94static int lt3651_charger_probe(struct platform_device *pdev)95{96	struct power_supply_config psy_cfg = {};97	struct lt3651_charger *lt3651_charger;98	struct power_supply_desc *charger_desc;99	int ret;100 101	lt3651_charger = devm_kzalloc(&pdev->dev, sizeof(*lt3651_charger),102					GFP_KERNEL);103	if (!lt3651_charger)104		return -ENOMEM;105 106	lt3651_charger->acpr_gpio = devm_gpiod_get(&pdev->dev,107					"lltc,acpr", GPIOD_IN);108	if (IS_ERR(lt3651_charger->acpr_gpio)) {109		ret = PTR_ERR(lt3651_charger->acpr_gpio);110		dev_err(&pdev->dev, "Failed to acquire acpr GPIO: %d\n", ret);111		return ret;112	}113	lt3651_charger->fault_gpio = devm_gpiod_get_optional(&pdev->dev,114					"lltc,fault", GPIOD_IN);115	if (IS_ERR(lt3651_charger->fault_gpio)) {116		ret = PTR_ERR(lt3651_charger->fault_gpio);117		dev_err(&pdev->dev, "Failed to acquire fault GPIO: %d\n", ret);118		return ret;119	}120	lt3651_charger->chrg_gpio = devm_gpiod_get_optional(&pdev->dev,121					"lltc,chrg", GPIOD_IN);122	if (IS_ERR(lt3651_charger->chrg_gpio)) {123		ret = PTR_ERR(lt3651_charger->chrg_gpio);124		dev_err(&pdev->dev, "Failed to acquire chrg GPIO: %d\n", ret);125		return ret;126	}127 128	charger_desc = &lt3651_charger->charger_desc;129	charger_desc->name = pdev->dev.of_node->name;130	charger_desc->type = POWER_SUPPLY_TYPE_MAINS;131	charger_desc->properties = lt3651_charger_properties;132	charger_desc->num_properties = ARRAY_SIZE(lt3651_charger_properties);133	charger_desc->get_property = lt3651_charger_get_property;134	psy_cfg.of_node = pdev->dev.of_node;135	psy_cfg.drv_data = lt3651_charger;136 137	lt3651_charger->charger = devm_power_supply_register(&pdev->dev,138						      charger_desc, &psy_cfg);139	if (IS_ERR(lt3651_charger->charger)) {140		ret = PTR_ERR(lt3651_charger->charger);141		dev_err(&pdev->dev, "Failed to register power supply: %d\n",142			ret);143		return ret;144	}145 146	/*147	 * Acquire IRQs for the GPIO pins if possible. If the system does not148	 * support IRQs on these pins, userspace will have to poll the sysfs149	 * files manually.150	 */151	if (lt3651_charger->acpr_gpio) {152		ret = gpiod_to_irq(lt3651_charger->acpr_gpio);153		if (ret >= 0)154			ret = devm_request_any_context_irq(&pdev->dev, ret,155				lt3651_charger_irq,156				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,157				dev_name(&pdev->dev), lt3651_charger->charger);158		if (ret < 0)159			dev_warn(&pdev->dev, "Failed to request acpr irq\n");160	}161	if (lt3651_charger->fault_gpio) {162		ret = gpiod_to_irq(lt3651_charger->fault_gpio);163		if (ret >= 0)164			ret = devm_request_any_context_irq(&pdev->dev, ret,165				lt3651_charger_irq,166				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,167				dev_name(&pdev->dev), lt3651_charger->charger);168		if (ret < 0)169			dev_warn(&pdev->dev, "Failed to request fault irq\n");170	}171	if (lt3651_charger->chrg_gpio) {172		ret = gpiod_to_irq(lt3651_charger->chrg_gpio);173		if (ret >= 0)174			ret = devm_request_any_context_irq(&pdev->dev, ret,175				lt3651_charger_irq,176				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,177				dev_name(&pdev->dev), lt3651_charger->charger);178		if (ret < 0)179			dev_warn(&pdev->dev, "Failed to request chrg irq\n");180	}181 182	platform_set_drvdata(pdev, lt3651_charger);183 184	return 0;185}186 187static const struct of_device_id lt3651_charger_match[] = {188	{ .compatible = "lltc,ltc3651-charger" }, /* DEPRECATED */189	{ .compatible = "lltc,lt3651-charger" },190	{ }191};192MODULE_DEVICE_TABLE(of, lt3651_charger_match);193 194static struct platform_driver lt3651_charger_driver = {195	.probe = lt3651_charger_probe,196	.driver = {197		.name = "lt3651-charger",198		.of_match_table = lt3651_charger_match,199	},200};201 202module_platform_driver(lt3651_charger_driver);203 204MODULE_AUTHOR("Mike Looijmans <mike.looijmans@topic.nl>");205MODULE_DESCRIPTION("Driver for LT3651 charger");206MODULE_LICENSE("GPL");207MODULE_ALIAS("platform:lt3651-charger");208