• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #define pr_fmt(x) KBUILD_MODNAME ": " x "\n"
2 
3 #include <linux/kernel.h>
4 #include <linux/module.h>
5 #include <linux/init.h>
6 #include <linux/slab.h>
7 #include <linux/interrupt.h>
8 #include <linux/device.h>
9 #include <linux/mutex.h>
10 #include <linux/param.h>
11 #include <linux/jiffies.h>
12 #include <linux/platform_device.h>
13 #include <linux/power_supply.h>
14 #include <linux/fs.h>
15 #include <linux/ktime.h>
16 #include <linux/of.h>
17 #include <linux/timekeeping.h>
18 #include <linux/types.h>
19 #include <linux/string.h>
20 #include <asm/irq.h>
21 #include <linux/cdev.h>
22 #include <linux/delay.h>
23 #include <linux/pm_runtime.h>
24 #include <linux/gpio/consumer.h>
25 #include <linux/kthread.h>
26 #include <linux/freezer.h>
27 #include <linux/err.h>
28 #include "power/axp2101.h"
29 #include "axp803_charger.h"
30 
31 struct axp803_ac_power {
32 	char                      *name;
33 	struct device             *dev;
34 	struct axp_config_info     dts_info;
35 	struct regmap             *regmap;
36 	struct power_supply       *ac_supply;
37 	struct delayed_work        ac_supply_mon;
38 };
39 
axp803_ac_set_vhold(struct axp803_ac_power * ac_power,int vol)40 static int axp803_ac_set_vhold(struct axp803_ac_power *ac_power, int vol)
41 {
42 	unsigned int tmp;
43 	struct regmap *map = ac_power->regmap;
44 
45 	if (vol) {
46 		regmap_update_bits(map, AXP803_CHARGE_AC_SET, 0x40, 0x40);
47 		if (vol >= 4000 && vol <= 4700) {
48 			tmp = (vol - 4000)/100;
49 			regmap_update_bits(map, AXP803_CHARGE_AC_SET,
50 					0x7 << 3, tmp << 3);
51 		} else {
52 			pr_err("set ac limit voltage error, %d mV\n", vol);
53 		}
54 	} else {
55 		regmap_update_bits(map, AXP803_CHARGE_AC_SET, 0x40, 0x00);
56 	}
57 
58 	return 0;
59 }
60 
axp803_ac_set_ihold(struct axp803_ac_power * ac_power,int cur)61 static int axp803_ac_set_ihold(struct axp803_ac_power *ac_power, int cur)
62 {
63 	unsigned int tmp;
64 	struct regmap *map = ac_power->regmap;
65 
66 	if (cur) {
67 		if (cur >= 1500 && cur <= 4000) {
68 			tmp = (cur - 1500) / 500;
69 			regmap_update_bits(map, AXP803_CHARGE_AC_SET, 0x7, tmp);
70 		} else {
71 			pr_err("set ac limit current error, %d mA\n", cur);
72 		}
73 	} else {
74 		regmap_update_bits(map, AXP803_CHARGE_AC_SET, 0x40, 0x40);
75 	}
76 
77 	return 0;
78 }
79 
80 static enum power_supply_property axp803_ac_props[] = {
81 	POWER_SUPPLY_PROP_MODEL_NAME,
82 	POWER_SUPPLY_PROP_PRESENT,
83 	POWER_SUPPLY_PROP_ONLINE,
84 };
85 
axp803_ac_get_property(struct power_supply * psy,enum power_supply_property psp,union power_supply_propval * val)86 static int axp803_ac_get_property(struct power_supply *psy,
87 					enum power_supply_property psp,
88 					union power_supply_propval *val)
89 {
90 	int ret = 0;
91 	unsigned int reg_value;
92 	struct axp803_ac_power *ac_power = power_supply_get_drvdata(psy);
93 
94 	switch (psp) {
95 	case POWER_SUPPLY_PROP_MODEL_NAME:
96 		val->strval = psy->desc->name;
97 		break;
98 	case POWER_SUPPLY_PROP_PRESENT:
99 		ret = regmap_read(ac_power->regmap, AXP803_STATUS, &reg_value);
100 		if (ret)
101 			return ret;
102 		val->intval = !!(reg_value & AXP803_STATUS_AC_PRESENT);
103 		break;
104 	case POWER_SUPPLY_PROP_ONLINE:
105 		ret = regmap_read(ac_power->regmap, AXP803_STATUS, &reg_value);
106 		if (ret)
107 			return ret;
108 		val->intval = !!(reg_value & AXP803_STATUS_AC_USED);
109 		break;
110 	default:
111 		ret = -EINVAL;
112 		break;
113 	}
114 
115 	return ret;
116 }
117 
118 static const struct power_supply_desc axp803_ac_desc = {
119 	.name = "axp803-ac",
120 	.type = POWER_SUPPLY_TYPE_MAINS,
121 	.get_property = axp803_ac_get_property,
122 	.properties = axp803_ac_props,
123 	.num_properties = ARRAY_SIZE(axp803_ac_props),
124 };
125 
axp803_ac_power_init(struct axp803_ac_power * ac_power)126 static int axp803_ac_power_init(struct axp803_ac_power *ac_power)
127 {
128 	struct axp_config_info *axp_config = &ac_power->dts_info;
129 
130 	axp803_ac_set_vhold(ac_power, axp_config->pmu_ac_vol);
131 	axp803_ac_set_ihold(ac_power, axp_config->pmu_ac_cur);
132 	return 0;
133 }
134 
axp803_ac_power_irq(int irq,void * data)135 static irqreturn_t axp803_ac_power_irq(int irq, void *data)
136 {
137 	struct axp803_ac_power *ac_power = data;
138 
139 	power_supply_changed(ac_power->ac_supply);
140 
141 	return IRQ_HANDLED;
142 }
143 
144 enum axp803_ac_power_virqs {
145 	AXP803_VIRQ_ACIN,
146 	AXP803_VIRQ_ACRE,
147 
148 	AXP803_AC_VIRQ_MAX_VIRQ,
149 };
150 
151 static struct axp_interrupts axp803_ac_irq[] = {
152 	[AXP803_VIRQ_ACIN] = {"ac in", axp803_ac_power_irq},
153 	[AXP803_VIRQ_ACRE] = {"ac out", axp803_ac_power_irq},
154 };
155 
axp803_ac_power_monitor(struct work_struct * work)156 static void axp803_ac_power_monitor(struct work_struct *work)
157 {
158 	struct axp803_ac_power *ac_power =
159 		container_of(work, typeof(*ac_power), ac_supply_mon.work);
160 
161 	schedule_delayed_work(&ac_power->ac_supply_mon, msecs_to_jiffies(500));
162 }
163 
axp803_ac_power_dt_parse(struct axp803_ac_power * ac_power)164 static int axp803_ac_power_dt_parse(struct axp803_ac_power *ac_power)
165 {
166 	struct axp_config_info *axp_config = &ac_power->dts_info;
167 	struct device_node *node = ac_power->dev->of_node;
168 
169 	if (!of_device_is_available(node)) {
170 		pr_err("%s: failed\n", __func__);
171 		return -1;
172 	}
173 
174 	AXP_OF_PROP_READ(pmu_ac_vol,                     4400);
175 	AXP_OF_PROP_READ(pmu_ac_cur,                        0);
176 
177 	axp_config->wakeup_ac_in =
178 		of_property_read_bool(node, "wakeup_ac_in");
179 	axp_config->wakeup_ac_out =
180 		of_property_read_bool(node, "wakeup_ac_out");
181 
182 	return 0;
183 }
184 
axp803_ac_power_probe(struct platform_device * pdev)185 static int axp803_ac_power_probe(struct platform_device *pdev)
186 {
187 	struct axp20x_dev *axp_dev = dev_get_drvdata(pdev->dev.parent);
188 	struct power_supply_config psy_cfg = {};
189 	struct axp803_ac_power *ac_power;
190 	int i, irq;
191 	int ret = 0;
192 
193 	if (!axp_dev->irq) {
194 		pr_err("can not register axp803 ac without irq\n");
195 		return -EINVAL;
196 	}
197 
198 	ac_power = devm_kzalloc(&pdev->dev, sizeof(*ac_power), GFP_KERNEL);
199 	if (!ac_power) {
200 		pr_err("axp803 ac power alloc failed\n");
201 		ret = -ENOMEM;
202 		return ret;
203 	}
204 
205 	ac_power->name = "axp803-ac-power";
206 	ac_power->dev = &pdev->dev;
207 	ac_power->regmap = axp_dev->regmap;
208 
209 	platform_set_drvdata(pdev, ac_power);
210 
211 	ret = axp803_ac_power_dt_parse(ac_power);
212 	if (ret) {
213 		pr_err("%s parse device tree err\n", __func__);
214 		ret = -EINVAL;
215 		return ret;
216 	}
217 
218 	ret = axp803_ac_power_init(ac_power);
219 	if (ret < 0) {
220 		pr_err("axp210x init chip fail!\n");
221 		ret = -ENODEV;
222 		return ret;
223 	}
224 
225 	psy_cfg.of_node = pdev->dev.of_node;
226 	psy_cfg.drv_data = ac_power;
227 
228 	ac_power->ac_supply = devm_power_supply_register(ac_power->dev,
229 			&axp803_ac_desc, &psy_cfg);
230 
231 	if (IS_ERR(ac_power->ac_supply)) {
232 		pr_err("axp803 failed to register ac power\n");
233 		ret = PTR_ERR(ac_power->ac_supply);
234 		return ret;
235 	}
236 
237 	for (i = 0; i < ARRAY_SIZE(axp803_ac_irq); i++) {
238 		irq = platform_get_irq_byname(pdev, axp803_ac_irq[i].name);
239 		if (irq < 0) {
240 			dev_warn(&pdev->dev, "No IRQ for %s: %d\n",
241 				 axp803_ac_irq[i].name, irq);
242 			continue;
243 		}
244 		irq = regmap_irq_get_virq(axp_dev->regmap_irqc, irq);
245 		ret = devm_request_any_context_irq(&pdev->dev, irq,
246 						   axp803_ac_irq[i].isr, 0,
247 						   axp803_ac_irq[i].name, ac_power);
248 		if (ret < 0)
249 			dev_warn(&pdev->dev, "Error requesting %s IRQ %d: %d\n",
250 				axp803_ac_irq[i].name, irq, ret);
251 
252 		dev_dbg(&pdev->dev, "Requested %s IRQ %d: %d\n",
253 			axp803_ac_irq[i].name, irq, ret);
254 
255 		/* we use this variable to suspend irq */
256 		axp803_ac_irq[i].irq = irq;
257 	}
258 
259 
260 	INIT_DELAYED_WORK(&ac_power->ac_supply_mon, axp803_ac_power_monitor);
261 	schedule_delayed_work(&ac_power->ac_supply_mon, msecs_to_jiffies(500));
262 
263 	return 0;
264 }
265 
axp803_ac_power_remove(struct platform_device * pdev)266 static int axp803_ac_power_remove(struct platform_device *pdev)
267 {
268 	struct axp803_ac_power *ac_power = platform_get_drvdata(pdev);
269 
270 	cancel_delayed_work_sync(&ac_power->ac_supply_mon);
271 
272 	return 0;
273 }
274 
axp_irq_set(unsigned int irq,bool enable)275 static inline void axp_irq_set(unsigned int irq, bool enable)
276 {
277 	if (enable)
278 		enable_irq(irq);
279 	else
280 		disable_irq(irq);
281 }
282 
axp803_ac_virq_dts_set(struct axp803_ac_power * ac_power,bool enable)283 static void axp803_ac_virq_dts_set(struct axp803_ac_power *ac_power, bool enable)
284 {
285 	struct axp_config_info *dts_info = &ac_power->dts_info;
286 
287 	if (!dts_info->wakeup_usb_in)
288 		axp_irq_set(axp803_ac_irq[AXP803_VIRQ_ACIN].irq,
289 				enable);
290 	if (!dts_info->wakeup_usb_out)
291 		axp_irq_set(axp803_ac_irq[AXP803_VIRQ_ACRE].irq,
292 				enable);
293 }
294 
axp803_ac_power_suspend(struct platform_device * pdev,pm_message_t state)295 static int axp803_ac_power_suspend(struct platform_device *pdev, pm_message_t state)
296 {
297 	struct axp803_ac_power *ac_power = platform_get_drvdata(pdev);
298 
299 	axp803_ac_virq_dts_set(ac_power, false);
300 
301 	return 0;
302 }
303 
axp803_ac_power_resume(struct platform_device * pdev)304 static int axp803_ac_power_resume(struct platform_device *pdev)
305 {
306 	struct axp803_ac_power *ac_power = platform_get_drvdata(pdev);
307 
308 	axp803_ac_virq_dts_set(ac_power, true);
309 
310 	return 0;
311 }
312 
313 static const struct of_device_id axp803_ac_power_match[] = {
314 	{
315 		.compatible = "x-powers,axp803-ac-power-supply",
316 		.data = (void *)AXP803_ID,
317 	}, { /* sentinel */ }
318 };
319 MODULE_DEVICE_TABLE(of, axp803_ac_power_match);
320 
321 static struct platform_driver axp803_ac_power_driver = {
322 	.driver = {
323 		.name = "axp803-ac-power-supply",
324 		.of_match_table = axp803_ac_power_match,
325 	},
326 	.probe = axp803_ac_power_probe,
327 	.remove = axp803_ac_power_remove,
328 	.suspend = axp803_ac_power_suspend,
329 	.resume = axp803_ac_power_resume,
330 };
331 
332 module_platform_driver(axp803_ac_power_driver);
333 
334 MODULE_AUTHOR("wangxiaoliang <wangxiaoliang@x-powers.com>");
335 MODULE_DESCRIPTION("axp803 ac power driver");
336 MODULE_LICENSE("GPL");
337