162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * AXP20X and AXP22X PMICs' ACIN power supply driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2016 Free Electrons
662306a36Sopenharmony_ci *	Quentin Schulz <quentin.schulz@free-electrons.com>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/device.h>
1062306a36Sopenharmony_ci#include <linux/init.h>
1162306a36Sopenharmony_ci#include <linux/interrupt.h>
1262306a36Sopenharmony_ci#include <linux/kernel.h>
1362306a36Sopenharmony_ci#include <linux/mfd/axp20x.h>
1462306a36Sopenharmony_ci#include <linux/module.h>
1562306a36Sopenharmony_ci#include <linux/of.h>
1662306a36Sopenharmony_ci#include <linux/platform_device.h>
1762306a36Sopenharmony_ci#include <linux/pm.h>
1862306a36Sopenharmony_ci#include <linux/power_supply.h>
1962306a36Sopenharmony_ci#include <linux/regmap.h>
2062306a36Sopenharmony_ci#include <linux/slab.h>
2162306a36Sopenharmony_ci#include <linux/iio/consumer.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#define AXP20X_PWR_STATUS_ACIN_PRESENT	BIT(7)
2462306a36Sopenharmony_ci#define AXP20X_PWR_STATUS_ACIN_AVAIL	BIT(6)
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#define AXP813_ACIN_PATH_SEL		BIT(7)
2762306a36Sopenharmony_ci#define AXP813_ACIN_PATH_SEL_TO_BIT(x)	(!!(x) << 7)
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#define AXP813_VHOLD_MASK		GENMASK(5, 3)
3062306a36Sopenharmony_ci#define AXP813_VHOLD_UV_TO_BIT(x)	((((x) / 100000) - 40) << 3)
3162306a36Sopenharmony_ci#define AXP813_VHOLD_REG_TO_UV(x)	\
3262306a36Sopenharmony_ci	(((((x) & AXP813_VHOLD_MASK) >> 3) + 40) * 100000)
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci#define AXP813_CURR_LIMIT_MASK		GENMASK(2, 0)
3562306a36Sopenharmony_ci#define AXP813_CURR_LIMIT_UA_TO_BIT(x)	(((x) / 500000) - 3)
3662306a36Sopenharmony_ci#define AXP813_CURR_LIMIT_REG_TO_UA(x)	\
3762306a36Sopenharmony_ci	((((x) & AXP813_CURR_LIMIT_MASK) + 3) * 500000)
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci#define DRVNAME "axp20x-ac-power-supply"
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_cistruct axp20x_ac_power {
4262306a36Sopenharmony_ci	struct regmap *regmap;
4362306a36Sopenharmony_ci	struct power_supply *supply;
4462306a36Sopenharmony_ci	struct iio_channel *acin_v;
4562306a36Sopenharmony_ci	struct iio_channel *acin_i;
4662306a36Sopenharmony_ci	bool has_acin_path_sel;
4762306a36Sopenharmony_ci	unsigned int num_irqs;
4862306a36Sopenharmony_ci	unsigned int irqs[];
4962306a36Sopenharmony_ci};
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cistatic irqreturn_t axp20x_ac_power_irq(int irq, void *devid)
5262306a36Sopenharmony_ci{
5362306a36Sopenharmony_ci	struct axp20x_ac_power *power = devid;
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	power_supply_changed(power->supply);
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	return IRQ_HANDLED;
5862306a36Sopenharmony_ci}
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_cistatic int axp20x_ac_power_get_property(struct power_supply *psy,
6162306a36Sopenharmony_ci					enum power_supply_property psp,
6262306a36Sopenharmony_ci					union power_supply_propval *val)
6362306a36Sopenharmony_ci{
6462306a36Sopenharmony_ci	struct axp20x_ac_power *power = power_supply_get_drvdata(psy);
6562306a36Sopenharmony_ci	int ret, reg;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	switch (psp) {
6862306a36Sopenharmony_ci	case POWER_SUPPLY_PROP_HEALTH:
6962306a36Sopenharmony_ci		ret = regmap_read(power->regmap, AXP20X_PWR_INPUT_STATUS, &reg);
7062306a36Sopenharmony_ci		if (ret)
7162306a36Sopenharmony_ci			return ret;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci		if (reg & AXP20X_PWR_STATUS_ACIN_PRESENT) {
7462306a36Sopenharmony_ci			val->intval = POWER_SUPPLY_HEALTH_GOOD;
7562306a36Sopenharmony_ci			return 0;
7662306a36Sopenharmony_ci		}
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci		val->intval = POWER_SUPPLY_HEALTH_UNKNOWN;
7962306a36Sopenharmony_ci		return 0;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	case POWER_SUPPLY_PROP_PRESENT:
8262306a36Sopenharmony_ci		ret = regmap_read(power->regmap, AXP20X_PWR_INPUT_STATUS, &reg);
8362306a36Sopenharmony_ci		if (ret)
8462306a36Sopenharmony_ci			return ret;
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci		val->intval = !!(reg & AXP20X_PWR_STATUS_ACIN_PRESENT);
8762306a36Sopenharmony_ci		return 0;
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	case POWER_SUPPLY_PROP_ONLINE:
9062306a36Sopenharmony_ci		ret = regmap_read(power->regmap, AXP20X_PWR_INPUT_STATUS, &reg);
9162306a36Sopenharmony_ci		if (ret)
9262306a36Sopenharmony_ci			return ret;
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci		val->intval = !!(reg & AXP20X_PWR_STATUS_ACIN_AVAIL);
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci		/* ACIN_PATH_SEL disables ACIN even if ACIN_AVAIL is set. */
9762306a36Sopenharmony_ci		if (val->intval && power->has_acin_path_sel) {
9862306a36Sopenharmony_ci			ret = regmap_read(power->regmap, AXP813_ACIN_PATH_CTRL,
9962306a36Sopenharmony_ci					  &reg);
10062306a36Sopenharmony_ci			if (ret)
10162306a36Sopenharmony_ci				return ret;
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci			val->intval = !!(reg & AXP813_ACIN_PATH_SEL);
10462306a36Sopenharmony_ci		}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci		return 0;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
10962306a36Sopenharmony_ci		ret = iio_read_channel_processed(power->acin_v, &val->intval);
11062306a36Sopenharmony_ci		if (ret)
11162306a36Sopenharmony_ci			return ret;
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci		/* IIO framework gives mV but Power Supply framework gives uV */
11462306a36Sopenharmony_ci		val->intval *= 1000;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci		return 0;
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	case POWER_SUPPLY_PROP_CURRENT_NOW:
11962306a36Sopenharmony_ci		ret = iio_read_channel_processed(power->acin_i, &val->intval);
12062306a36Sopenharmony_ci		if (ret)
12162306a36Sopenharmony_ci			return ret;
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci		/* IIO framework gives mA but Power Supply framework gives uA */
12462306a36Sopenharmony_ci		val->intval *= 1000;
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci		return 0;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	case POWER_SUPPLY_PROP_VOLTAGE_MIN:
12962306a36Sopenharmony_ci		ret = regmap_read(power->regmap, AXP813_ACIN_PATH_CTRL, &reg);
13062306a36Sopenharmony_ci		if (ret)
13162306a36Sopenharmony_ci			return ret;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci		val->intval = AXP813_VHOLD_REG_TO_UV(reg);
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci		return 0;
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
13862306a36Sopenharmony_ci		ret = regmap_read(power->regmap, AXP813_ACIN_PATH_CTRL, &reg);
13962306a36Sopenharmony_ci		if (ret)
14062306a36Sopenharmony_ci			return ret;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci		val->intval = AXP813_CURR_LIMIT_REG_TO_UA(reg);
14362306a36Sopenharmony_ci		/* AXP813 datasheet defines values 11x as 4000mA */
14462306a36Sopenharmony_ci		if (val->intval > 4000000)
14562306a36Sopenharmony_ci			val->intval = 4000000;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci		return 0;
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	default:
15062306a36Sopenharmony_ci		return -EINVAL;
15162306a36Sopenharmony_ci	}
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	return -EINVAL;
15462306a36Sopenharmony_ci}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_cistatic int axp813_ac_power_set_property(struct power_supply *psy,
15762306a36Sopenharmony_ci					enum power_supply_property psp,
15862306a36Sopenharmony_ci					const union power_supply_propval *val)
15962306a36Sopenharmony_ci{
16062306a36Sopenharmony_ci	struct axp20x_ac_power *power = power_supply_get_drvdata(psy);
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	switch (psp) {
16362306a36Sopenharmony_ci	case POWER_SUPPLY_PROP_ONLINE:
16462306a36Sopenharmony_ci		return regmap_update_bits(power->regmap, AXP813_ACIN_PATH_CTRL,
16562306a36Sopenharmony_ci					  AXP813_ACIN_PATH_SEL,
16662306a36Sopenharmony_ci					  AXP813_ACIN_PATH_SEL_TO_BIT(val->intval));
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	case POWER_SUPPLY_PROP_VOLTAGE_MIN:
16962306a36Sopenharmony_ci		if (val->intval < 4000000 || val->intval > 4700000)
17062306a36Sopenharmony_ci			return -EINVAL;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci		return regmap_update_bits(power->regmap, AXP813_ACIN_PATH_CTRL,
17362306a36Sopenharmony_ci					  AXP813_VHOLD_MASK,
17462306a36Sopenharmony_ci					  AXP813_VHOLD_UV_TO_BIT(val->intval));
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
17762306a36Sopenharmony_ci		if (val->intval < 1500000 || val->intval > 4000000)
17862306a36Sopenharmony_ci			return -EINVAL;
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci		return regmap_update_bits(power->regmap, AXP813_ACIN_PATH_CTRL,
18162306a36Sopenharmony_ci					  AXP813_CURR_LIMIT_MASK,
18262306a36Sopenharmony_ci					  AXP813_CURR_LIMIT_UA_TO_BIT(val->intval));
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	default:
18562306a36Sopenharmony_ci		return -EINVAL;
18662306a36Sopenharmony_ci	}
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	return -EINVAL;
18962306a36Sopenharmony_ci}
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_cistatic int axp813_ac_power_prop_writeable(struct power_supply *psy,
19262306a36Sopenharmony_ci					  enum power_supply_property psp)
19362306a36Sopenharmony_ci{
19462306a36Sopenharmony_ci	return psp == POWER_SUPPLY_PROP_ONLINE ||
19562306a36Sopenharmony_ci	       psp == POWER_SUPPLY_PROP_VOLTAGE_MIN ||
19662306a36Sopenharmony_ci	       psp == POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT;
19762306a36Sopenharmony_ci}
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_cistatic enum power_supply_property axp20x_ac_power_properties[] = {
20062306a36Sopenharmony_ci	POWER_SUPPLY_PROP_HEALTH,
20162306a36Sopenharmony_ci	POWER_SUPPLY_PROP_PRESENT,
20262306a36Sopenharmony_ci	POWER_SUPPLY_PROP_ONLINE,
20362306a36Sopenharmony_ci	POWER_SUPPLY_PROP_VOLTAGE_NOW,
20462306a36Sopenharmony_ci	POWER_SUPPLY_PROP_CURRENT_NOW,
20562306a36Sopenharmony_ci};
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_cistatic enum power_supply_property axp22x_ac_power_properties[] = {
20862306a36Sopenharmony_ci	POWER_SUPPLY_PROP_HEALTH,
20962306a36Sopenharmony_ci	POWER_SUPPLY_PROP_PRESENT,
21062306a36Sopenharmony_ci	POWER_SUPPLY_PROP_ONLINE,
21162306a36Sopenharmony_ci};
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_cistatic enum power_supply_property axp813_ac_power_properties[] = {
21462306a36Sopenharmony_ci	POWER_SUPPLY_PROP_HEALTH,
21562306a36Sopenharmony_ci	POWER_SUPPLY_PROP_PRESENT,
21662306a36Sopenharmony_ci	POWER_SUPPLY_PROP_ONLINE,
21762306a36Sopenharmony_ci	POWER_SUPPLY_PROP_VOLTAGE_MIN,
21862306a36Sopenharmony_ci	POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
21962306a36Sopenharmony_ci};
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_cistatic const struct power_supply_desc axp20x_ac_power_desc = {
22262306a36Sopenharmony_ci	.name = "axp20x-ac",
22362306a36Sopenharmony_ci	.type = POWER_SUPPLY_TYPE_MAINS,
22462306a36Sopenharmony_ci	.properties = axp20x_ac_power_properties,
22562306a36Sopenharmony_ci	.num_properties = ARRAY_SIZE(axp20x_ac_power_properties),
22662306a36Sopenharmony_ci	.get_property = axp20x_ac_power_get_property,
22762306a36Sopenharmony_ci};
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_cistatic const struct power_supply_desc axp22x_ac_power_desc = {
23062306a36Sopenharmony_ci	.name = "axp22x-ac",
23162306a36Sopenharmony_ci	.type = POWER_SUPPLY_TYPE_MAINS,
23262306a36Sopenharmony_ci	.properties = axp22x_ac_power_properties,
23362306a36Sopenharmony_ci	.num_properties = ARRAY_SIZE(axp22x_ac_power_properties),
23462306a36Sopenharmony_ci	.get_property = axp20x_ac_power_get_property,
23562306a36Sopenharmony_ci};
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_cistatic const struct power_supply_desc axp813_ac_power_desc = {
23862306a36Sopenharmony_ci	.name = "axp813-ac",
23962306a36Sopenharmony_ci	.type = POWER_SUPPLY_TYPE_MAINS,
24062306a36Sopenharmony_ci	.properties = axp813_ac_power_properties,
24162306a36Sopenharmony_ci	.num_properties = ARRAY_SIZE(axp813_ac_power_properties),
24262306a36Sopenharmony_ci	.property_is_writeable = axp813_ac_power_prop_writeable,
24362306a36Sopenharmony_ci	.get_property = axp20x_ac_power_get_property,
24462306a36Sopenharmony_ci	.set_property = axp813_ac_power_set_property,
24562306a36Sopenharmony_ci};
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_cistatic const char * const axp20x_irq_names[] = {
24862306a36Sopenharmony_ci	"ACIN_PLUGIN",
24962306a36Sopenharmony_ci	"ACIN_REMOVAL",
25062306a36Sopenharmony_ci};
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_cistruct axp_data {
25362306a36Sopenharmony_ci	const struct power_supply_desc	*power_desc;
25462306a36Sopenharmony_ci	const char * const		*irq_names;
25562306a36Sopenharmony_ci	unsigned int			num_irq_names;
25662306a36Sopenharmony_ci	bool				acin_adc;
25762306a36Sopenharmony_ci	bool				acin_path_sel;
25862306a36Sopenharmony_ci};
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_cistatic const struct axp_data axp20x_data = {
26162306a36Sopenharmony_ci	.power_desc	= &axp20x_ac_power_desc,
26262306a36Sopenharmony_ci	.irq_names	= axp20x_irq_names,
26362306a36Sopenharmony_ci	.num_irq_names	= ARRAY_SIZE(axp20x_irq_names),
26462306a36Sopenharmony_ci	.acin_adc	= true,
26562306a36Sopenharmony_ci	.acin_path_sel	= false,
26662306a36Sopenharmony_ci};
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_cistatic const struct axp_data axp22x_data = {
26962306a36Sopenharmony_ci	.power_desc	= &axp22x_ac_power_desc,
27062306a36Sopenharmony_ci	.irq_names	= axp20x_irq_names,
27162306a36Sopenharmony_ci	.num_irq_names	= ARRAY_SIZE(axp20x_irq_names),
27262306a36Sopenharmony_ci	.acin_adc	= false,
27362306a36Sopenharmony_ci	.acin_path_sel	= false,
27462306a36Sopenharmony_ci};
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_cistatic const struct axp_data axp813_data = {
27762306a36Sopenharmony_ci	.power_desc	= &axp813_ac_power_desc,
27862306a36Sopenharmony_ci	.irq_names	= axp20x_irq_names,
27962306a36Sopenharmony_ci	.num_irq_names	= ARRAY_SIZE(axp20x_irq_names),
28062306a36Sopenharmony_ci	.acin_adc	= false,
28162306a36Sopenharmony_ci	.acin_path_sel	= true,
28262306a36Sopenharmony_ci};
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
28562306a36Sopenharmony_cistatic int axp20x_ac_power_suspend(struct device *dev)
28662306a36Sopenharmony_ci{
28762306a36Sopenharmony_ci	struct axp20x_ac_power *power = dev_get_drvdata(dev);
28862306a36Sopenharmony_ci	int i = 0;
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	/*
29162306a36Sopenharmony_ci	 * Allow wake via ACIN_PLUGIN only.
29262306a36Sopenharmony_ci	 *
29362306a36Sopenharmony_ci	 * As nested threaded IRQs are not automatically disabled during
29462306a36Sopenharmony_ci	 * suspend, we must explicitly disable the remainder of the IRQs.
29562306a36Sopenharmony_ci	 */
29662306a36Sopenharmony_ci	if (device_may_wakeup(&power->supply->dev))
29762306a36Sopenharmony_ci		enable_irq_wake(power->irqs[i++]);
29862306a36Sopenharmony_ci	while (i < power->num_irqs)
29962306a36Sopenharmony_ci		disable_irq(power->irqs[i++]);
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	return 0;
30262306a36Sopenharmony_ci}
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_cistatic int axp20x_ac_power_resume(struct device *dev)
30562306a36Sopenharmony_ci{
30662306a36Sopenharmony_ci	struct axp20x_ac_power *power = dev_get_drvdata(dev);
30762306a36Sopenharmony_ci	int i = 0;
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	if (device_may_wakeup(&power->supply->dev))
31062306a36Sopenharmony_ci		disable_irq_wake(power->irqs[i++]);
31162306a36Sopenharmony_ci	while (i < power->num_irqs)
31262306a36Sopenharmony_ci		enable_irq(power->irqs[i++]);
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	return 0;
31562306a36Sopenharmony_ci}
31662306a36Sopenharmony_ci#endif
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(axp20x_ac_power_pm_ops, axp20x_ac_power_suspend,
31962306a36Sopenharmony_ci						 axp20x_ac_power_resume);
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_cistatic int axp20x_ac_power_probe(struct platform_device *pdev)
32262306a36Sopenharmony_ci{
32362306a36Sopenharmony_ci	struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
32462306a36Sopenharmony_ci	struct power_supply_config psy_cfg = {};
32562306a36Sopenharmony_ci	struct axp20x_ac_power *power;
32662306a36Sopenharmony_ci	const struct axp_data *axp_data;
32762306a36Sopenharmony_ci	int i, irq, ret;
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	if (!of_device_is_available(pdev->dev.of_node))
33062306a36Sopenharmony_ci		return -ENODEV;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	if (!axp20x) {
33362306a36Sopenharmony_ci		dev_err(&pdev->dev, "Parent drvdata not set\n");
33462306a36Sopenharmony_ci		return -EINVAL;
33562306a36Sopenharmony_ci	}
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	axp_data = of_device_get_match_data(&pdev->dev);
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	power = devm_kzalloc(&pdev->dev,
34062306a36Sopenharmony_ci			     struct_size(power, irqs, axp_data->num_irq_names),
34162306a36Sopenharmony_ci			     GFP_KERNEL);
34262306a36Sopenharmony_ci	if (!power)
34362306a36Sopenharmony_ci		return -ENOMEM;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	if (axp_data->acin_adc) {
34662306a36Sopenharmony_ci		power->acin_v = devm_iio_channel_get(&pdev->dev, "acin_v");
34762306a36Sopenharmony_ci		if (IS_ERR(power->acin_v)) {
34862306a36Sopenharmony_ci			if (PTR_ERR(power->acin_v) == -ENODEV)
34962306a36Sopenharmony_ci				return -EPROBE_DEFER;
35062306a36Sopenharmony_ci			return PTR_ERR(power->acin_v);
35162306a36Sopenharmony_ci		}
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci		power->acin_i = devm_iio_channel_get(&pdev->dev, "acin_i");
35462306a36Sopenharmony_ci		if (IS_ERR(power->acin_i)) {
35562306a36Sopenharmony_ci			if (PTR_ERR(power->acin_i) == -ENODEV)
35662306a36Sopenharmony_ci				return -EPROBE_DEFER;
35762306a36Sopenharmony_ci			return PTR_ERR(power->acin_i);
35862306a36Sopenharmony_ci		}
35962306a36Sopenharmony_ci	}
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	power->regmap = dev_get_regmap(pdev->dev.parent, NULL);
36262306a36Sopenharmony_ci	power->has_acin_path_sel = axp_data->acin_path_sel;
36362306a36Sopenharmony_ci	power->num_irqs = axp_data->num_irq_names;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	platform_set_drvdata(pdev, power);
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	psy_cfg.of_node = pdev->dev.of_node;
36862306a36Sopenharmony_ci	psy_cfg.drv_data = power;
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	power->supply = devm_power_supply_register(&pdev->dev,
37162306a36Sopenharmony_ci						   axp_data->power_desc,
37262306a36Sopenharmony_ci						   &psy_cfg);
37362306a36Sopenharmony_ci	if (IS_ERR(power->supply))
37462306a36Sopenharmony_ci		return PTR_ERR(power->supply);
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	/* Request irqs after registering, as irqs may trigger immediately */
37762306a36Sopenharmony_ci	for (i = 0; i < axp_data->num_irq_names; i++) {
37862306a36Sopenharmony_ci		irq = platform_get_irq_byname(pdev, axp_data->irq_names[i]);
37962306a36Sopenharmony_ci		if (irq < 0)
38062306a36Sopenharmony_ci			return irq;
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci		power->irqs[i] = regmap_irq_get_virq(axp20x->regmap_irqc, irq);
38362306a36Sopenharmony_ci		ret = devm_request_any_context_irq(&pdev->dev, power->irqs[i],
38462306a36Sopenharmony_ci						   axp20x_ac_power_irq, 0,
38562306a36Sopenharmony_ci						   DRVNAME, power);
38662306a36Sopenharmony_ci		if (ret < 0) {
38762306a36Sopenharmony_ci			dev_err(&pdev->dev, "Error requesting %s IRQ: %d\n",
38862306a36Sopenharmony_ci				axp_data->irq_names[i], ret);
38962306a36Sopenharmony_ci			return ret;
39062306a36Sopenharmony_ci		}
39162306a36Sopenharmony_ci	}
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	return 0;
39462306a36Sopenharmony_ci}
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_cistatic const struct of_device_id axp20x_ac_power_match[] = {
39762306a36Sopenharmony_ci	{
39862306a36Sopenharmony_ci		.compatible = "x-powers,axp202-ac-power-supply",
39962306a36Sopenharmony_ci		.data = &axp20x_data,
40062306a36Sopenharmony_ci	}, {
40162306a36Sopenharmony_ci		.compatible = "x-powers,axp221-ac-power-supply",
40262306a36Sopenharmony_ci		.data = &axp22x_data,
40362306a36Sopenharmony_ci	}, {
40462306a36Sopenharmony_ci		.compatible = "x-powers,axp813-ac-power-supply",
40562306a36Sopenharmony_ci		.data = &axp813_data,
40662306a36Sopenharmony_ci	}, { /* sentinel */ }
40762306a36Sopenharmony_ci};
40862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, axp20x_ac_power_match);
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_cistatic struct platform_driver axp20x_ac_power_driver = {
41162306a36Sopenharmony_ci	.probe = axp20x_ac_power_probe,
41262306a36Sopenharmony_ci	.driver = {
41362306a36Sopenharmony_ci		.name		= DRVNAME,
41462306a36Sopenharmony_ci		.of_match_table	= axp20x_ac_power_match,
41562306a36Sopenharmony_ci		.pm		= &axp20x_ac_power_pm_ops,
41662306a36Sopenharmony_ci	},
41762306a36Sopenharmony_ci};
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_cimodule_platform_driver(axp20x_ac_power_driver);
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ciMODULE_AUTHOR("Quentin Schulz <quentin.schulz@free-electrons.com>");
42262306a36Sopenharmony_ciMODULE_DESCRIPTION("AXP20X and AXP22X PMICs' AC power supply driver");
42362306a36Sopenharmony_ciMODULE_LICENSE("GPL");
424