1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * AXP20X and AXP22X PMICs' ACIN power supply driver
4 *
5 * Copyright (C) 2016 Free Electrons
6 *	Quentin Schulz <quentin.schulz@free-electrons.com>
7 */
8
9#include <linux/device.h>
10#include <linux/init.h>
11#include <linux/interrupt.h>
12#include <linux/kernel.h>
13#include <linux/mfd/axp20x.h>
14#include <linux/module.h>
15#include <linux/of.h>
16#include <linux/platform_device.h>
17#include <linux/pm.h>
18#include <linux/power_supply.h>
19#include <linux/regmap.h>
20#include <linux/slab.h>
21#include <linux/iio/consumer.h>
22
23#define AXP20X_PWR_STATUS_ACIN_PRESENT	BIT(7)
24#define AXP20X_PWR_STATUS_ACIN_AVAIL	BIT(6)
25
26#define AXP813_ACIN_PATH_SEL		BIT(7)
27#define AXP813_ACIN_PATH_SEL_TO_BIT(x)	(!!(x) << 7)
28
29#define AXP813_VHOLD_MASK		GENMASK(5, 3)
30#define AXP813_VHOLD_UV_TO_BIT(x)	((((x) / 100000) - 40) << 3)
31#define AXP813_VHOLD_REG_TO_UV(x)	\
32	(((((x) & AXP813_VHOLD_MASK) >> 3) + 40) * 100000)
33
34#define AXP813_CURR_LIMIT_MASK		GENMASK(2, 0)
35#define AXP813_CURR_LIMIT_UA_TO_BIT(x)	(((x) / 500000) - 3)
36#define AXP813_CURR_LIMIT_REG_TO_UA(x)	\
37	((((x) & AXP813_CURR_LIMIT_MASK) + 3) * 500000)
38
39#define DRVNAME "axp20x-ac-power-supply"
40
41struct axp20x_ac_power {
42	struct regmap *regmap;
43	struct power_supply *supply;
44	struct iio_channel *acin_v;
45	struct iio_channel *acin_i;
46	bool has_acin_path_sel;
47	unsigned int num_irqs;
48	unsigned int irqs[];
49};
50
51static irqreturn_t axp20x_ac_power_irq(int irq, void *devid)
52{
53	struct axp20x_ac_power *power = devid;
54
55	power_supply_changed(power->supply);
56
57	return IRQ_HANDLED;
58}
59
60static int axp20x_ac_power_get_property(struct power_supply *psy,
61					enum power_supply_property psp,
62					union power_supply_propval *val)
63{
64	struct axp20x_ac_power *power = power_supply_get_drvdata(psy);
65	int ret, reg;
66
67	switch (psp) {
68	case POWER_SUPPLY_PROP_HEALTH:
69		ret = regmap_read(power->regmap, AXP20X_PWR_INPUT_STATUS, &reg);
70		if (ret)
71			return ret;
72
73		if (reg & AXP20X_PWR_STATUS_ACIN_PRESENT) {
74			val->intval = POWER_SUPPLY_HEALTH_GOOD;
75			return 0;
76		}
77
78		val->intval = POWER_SUPPLY_HEALTH_UNKNOWN;
79		return 0;
80
81	case POWER_SUPPLY_PROP_PRESENT:
82		ret = regmap_read(power->regmap, AXP20X_PWR_INPUT_STATUS, &reg);
83		if (ret)
84			return ret;
85
86		val->intval = !!(reg & AXP20X_PWR_STATUS_ACIN_PRESENT);
87		return 0;
88
89	case POWER_SUPPLY_PROP_ONLINE:
90		ret = regmap_read(power->regmap, AXP20X_PWR_INPUT_STATUS, &reg);
91		if (ret)
92			return ret;
93
94		val->intval = !!(reg & AXP20X_PWR_STATUS_ACIN_AVAIL);
95
96		/* ACIN_PATH_SEL disables ACIN even if ACIN_AVAIL is set. */
97		if (val->intval && power->has_acin_path_sel) {
98			ret = regmap_read(power->regmap, AXP813_ACIN_PATH_CTRL,
99					  &reg);
100			if (ret)
101				return ret;
102
103			val->intval = !!(reg & AXP813_ACIN_PATH_SEL);
104		}
105
106		return 0;
107
108	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
109		ret = iio_read_channel_processed(power->acin_v, &val->intval);
110		if (ret)
111			return ret;
112
113		/* IIO framework gives mV but Power Supply framework gives uV */
114		val->intval *= 1000;
115
116		return 0;
117
118	case POWER_SUPPLY_PROP_CURRENT_NOW:
119		ret = iio_read_channel_processed(power->acin_i, &val->intval);
120		if (ret)
121			return ret;
122
123		/* IIO framework gives mA but Power Supply framework gives uA */
124		val->intval *= 1000;
125
126		return 0;
127
128	case POWER_SUPPLY_PROP_VOLTAGE_MIN:
129		ret = regmap_read(power->regmap, AXP813_ACIN_PATH_CTRL, &reg);
130		if (ret)
131			return ret;
132
133		val->intval = AXP813_VHOLD_REG_TO_UV(reg);
134
135		return 0;
136
137	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
138		ret = regmap_read(power->regmap, AXP813_ACIN_PATH_CTRL, &reg);
139		if (ret)
140			return ret;
141
142		val->intval = AXP813_CURR_LIMIT_REG_TO_UA(reg);
143		/* AXP813 datasheet defines values 11x as 4000mA */
144		if (val->intval > 4000000)
145			val->intval = 4000000;
146
147		return 0;
148
149	default:
150		return -EINVAL;
151	}
152
153	return -EINVAL;
154}
155
156static int axp813_ac_power_set_property(struct power_supply *psy,
157					enum power_supply_property psp,
158					const union power_supply_propval *val)
159{
160	struct axp20x_ac_power *power = power_supply_get_drvdata(psy);
161
162	switch (psp) {
163	case POWER_SUPPLY_PROP_ONLINE:
164		return regmap_update_bits(power->regmap, AXP813_ACIN_PATH_CTRL,
165					  AXP813_ACIN_PATH_SEL,
166					  AXP813_ACIN_PATH_SEL_TO_BIT(val->intval));
167
168	case POWER_SUPPLY_PROP_VOLTAGE_MIN:
169		if (val->intval < 4000000 || val->intval > 4700000)
170			return -EINVAL;
171
172		return regmap_update_bits(power->regmap, AXP813_ACIN_PATH_CTRL,
173					  AXP813_VHOLD_MASK,
174					  AXP813_VHOLD_UV_TO_BIT(val->intval));
175
176	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
177		if (val->intval < 1500000 || val->intval > 4000000)
178			return -EINVAL;
179
180		return regmap_update_bits(power->regmap, AXP813_ACIN_PATH_CTRL,
181					  AXP813_CURR_LIMIT_MASK,
182					  AXP813_CURR_LIMIT_UA_TO_BIT(val->intval));
183
184	default:
185		return -EINVAL;
186	}
187
188	return -EINVAL;
189}
190
191static int axp813_ac_power_prop_writeable(struct power_supply *psy,
192					  enum power_supply_property psp)
193{
194	return psp == POWER_SUPPLY_PROP_ONLINE ||
195	       psp == POWER_SUPPLY_PROP_VOLTAGE_MIN ||
196	       psp == POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT;
197}
198
199static enum power_supply_property axp20x_ac_power_properties[] = {
200	POWER_SUPPLY_PROP_HEALTH,
201	POWER_SUPPLY_PROP_PRESENT,
202	POWER_SUPPLY_PROP_ONLINE,
203	POWER_SUPPLY_PROP_VOLTAGE_NOW,
204	POWER_SUPPLY_PROP_CURRENT_NOW,
205};
206
207static enum power_supply_property axp22x_ac_power_properties[] = {
208	POWER_SUPPLY_PROP_HEALTH,
209	POWER_SUPPLY_PROP_PRESENT,
210	POWER_SUPPLY_PROP_ONLINE,
211};
212
213static enum power_supply_property axp813_ac_power_properties[] = {
214	POWER_SUPPLY_PROP_HEALTH,
215	POWER_SUPPLY_PROP_PRESENT,
216	POWER_SUPPLY_PROP_ONLINE,
217	POWER_SUPPLY_PROP_VOLTAGE_MIN,
218	POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
219};
220
221static const struct power_supply_desc axp20x_ac_power_desc = {
222	.name = "axp20x-ac",
223	.type = POWER_SUPPLY_TYPE_MAINS,
224	.properties = axp20x_ac_power_properties,
225	.num_properties = ARRAY_SIZE(axp20x_ac_power_properties),
226	.get_property = axp20x_ac_power_get_property,
227};
228
229static const struct power_supply_desc axp22x_ac_power_desc = {
230	.name = "axp22x-ac",
231	.type = POWER_SUPPLY_TYPE_MAINS,
232	.properties = axp22x_ac_power_properties,
233	.num_properties = ARRAY_SIZE(axp22x_ac_power_properties),
234	.get_property = axp20x_ac_power_get_property,
235};
236
237static const struct power_supply_desc axp813_ac_power_desc = {
238	.name = "axp813-ac",
239	.type = POWER_SUPPLY_TYPE_MAINS,
240	.properties = axp813_ac_power_properties,
241	.num_properties = ARRAY_SIZE(axp813_ac_power_properties),
242	.property_is_writeable = axp813_ac_power_prop_writeable,
243	.get_property = axp20x_ac_power_get_property,
244	.set_property = axp813_ac_power_set_property,
245};
246
247static const char * const axp20x_irq_names[] = {
248	"ACIN_PLUGIN",
249	"ACIN_REMOVAL",
250};
251
252struct axp_data {
253	const struct power_supply_desc	*power_desc;
254	const char * const		*irq_names;
255	unsigned int			num_irq_names;
256	bool				acin_adc;
257	bool				acin_path_sel;
258};
259
260static const struct axp_data axp20x_data = {
261	.power_desc	= &axp20x_ac_power_desc,
262	.irq_names	= axp20x_irq_names,
263	.num_irq_names	= ARRAY_SIZE(axp20x_irq_names),
264	.acin_adc	= true,
265	.acin_path_sel	= false,
266};
267
268static const struct axp_data axp22x_data = {
269	.power_desc	= &axp22x_ac_power_desc,
270	.irq_names	= axp20x_irq_names,
271	.num_irq_names	= ARRAY_SIZE(axp20x_irq_names),
272	.acin_adc	= false,
273	.acin_path_sel	= false,
274};
275
276static const struct axp_data axp813_data = {
277	.power_desc	= &axp813_ac_power_desc,
278	.irq_names	= axp20x_irq_names,
279	.num_irq_names	= ARRAY_SIZE(axp20x_irq_names),
280	.acin_adc	= false,
281	.acin_path_sel	= true,
282};
283
284#ifdef CONFIG_PM_SLEEP
285static int axp20x_ac_power_suspend(struct device *dev)
286{
287	struct axp20x_ac_power *power = dev_get_drvdata(dev);
288	int i = 0;
289
290	/*
291	 * Allow wake via ACIN_PLUGIN only.
292	 *
293	 * As nested threaded IRQs are not automatically disabled during
294	 * suspend, we must explicitly disable the remainder of the IRQs.
295	 */
296	if (device_may_wakeup(&power->supply->dev))
297		enable_irq_wake(power->irqs[i++]);
298	while (i < power->num_irqs)
299		disable_irq(power->irqs[i++]);
300
301	return 0;
302}
303
304static int axp20x_ac_power_resume(struct device *dev)
305{
306	struct axp20x_ac_power *power = dev_get_drvdata(dev);
307	int i = 0;
308
309	if (device_may_wakeup(&power->supply->dev))
310		disable_irq_wake(power->irqs[i++]);
311	while (i < power->num_irqs)
312		enable_irq(power->irqs[i++]);
313
314	return 0;
315}
316#endif
317
318static SIMPLE_DEV_PM_OPS(axp20x_ac_power_pm_ops, axp20x_ac_power_suspend,
319						 axp20x_ac_power_resume);
320
321static int axp20x_ac_power_probe(struct platform_device *pdev)
322{
323	struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
324	struct power_supply_config psy_cfg = {};
325	struct axp20x_ac_power *power;
326	const struct axp_data *axp_data;
327	int i, irq, ret;
328
329	if (!of_device_is_available(pdev->dev.of_node))
330		return -ENODEV;
331
332	if (!axp20x) {
333		dev_err(&pdev->dev, "Parent drvdata not set\n");
334		return -EINVAL;
335	}
336
337	axp_data = of_device_get_match_data(&pdev->dev);
338
339	power = devm_kzalloc(&pdev->dev,
340			     struct_size(power, irqs, axp_data->num_irq_names),
341			     GFP_KERNEL);
342	if (!power)
343		return -ENOMEM;
344
345	if (axp_data->acin_adc) {
346		power->acin_v = devm_iio_channel_get(&pdev->dev, "acin_v");
347		if (IS_ERR(power->acin_v)) {
348			if (PTR_ERR(power->acin_v) == -ENODEV)
349				return -EPROBE_DEFER;
350			return PTR_ERR(power->acin_v);
351		}
352
353		power->acin_i = devm_iio_channel_get(&pdev->dev, "acin_i");
354		if (IS_ERR(power->acin_i)) {
355			if (PTR_ERR(power->acin_i) == -ENODEV)
356				return -EPROBE_DEFER;
357			return PTR_ERR(power->acin_i);
358		}
359	}
360
361	power->regmap = dev_get_regmap(pdev->dev.parent, NULL);
362	power->has_acin_path_sel = axp_data->acin_path_sel;
363	power->num_irqs = axp_data->num_irq_names;
364
365	platform_set_drvdata(pdev, power);
366
367	psy_cfg.of_node = pdev->dev.of_node;
368	psy_cfg.drv_data = power;
369
370	power->supply = devm_power_supply_register(&pdev->dev,
371						   axp_data->power_desc,
372						   &psy_cfg);
373	if (IS_ERR(power->supply))
374		return PTR_ERR(power->supply);
375
376	/* Request irqs after registering, as irqs may trigger immediately */
377	for (i = 0; i < axp_data->num_irq_names; i++) {
378		irq = platform_get_irq_byname(pdev, axp_data->irq_names[i]);
379		if (irq < 0)
380			return irq;
381
382		power->irqs[i] = regmap_irq_get_virq(axp20x->regmap_irqc, irq);
383		ret = devm_request_any_context_irq(&pdev->dev, power->irqs[i],
384						   axp20x_ac_power_irq, 0,
385						   DRVNAME, power);
386		if (ret < 0) {
387			dev_err(&pdev->dev, "Error requesting %s IRQ: %d\n",
388				axp_data->irq_names[i], ret);
389			return ret;
390		}
391	}
392
393	return 0;
394}
395
396static const struct of_device_id axp20x_ac_power_match[] = {
397	{
398		.compatible = "x-powers,axp202-ac-power-supply",
399		.data = &axp20x_data,
400	}, {
401		.compatible = "x-powers,axp221-ac-power-supply",
402		.data = &axp22x_data,
403	}, {
404		.compatible = "x-powers,axp813-ac-power-supply",
405		.data = &axp813_data,
406	}, { /* sentinel */ }
407};
408MODULE_DEVICE_TABLE(of, axp20x_ac_power_match);
409
410static struct platform_driver axp20x_ac_power_driver = {
411	.probe = axp20x_ac_power_probe,
412	.driver = {
413		.name		= DRVNAME,
414		.of_match_table	= axp20x_ac_power_match,
415		.pm		= &axp20x_ac_power_pm_ops,
416	},
417};
418
419module_platform_driver(axp20x_ac_power_driver);
420
421MODULE_AUTHOR("Quentin Schulz <quentin.schulz@free-electrons.com>");
422MODULE_DESCRIPTION("AXP20X and AXP22X PMICs' AC power supply driver");
423MODULE_LICENSE("GPL");
424