1 /*
2  * Copyright 2024 Arduino SA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT nxp_pf1550_charger
8 
9 #include <zephyr/device.h>
10 #include <zephyr/drivers/charger.h>
11 #include <zephyr/drivers/gpio.h>
12 #include <zephyr/drivers/i2c.h>
13 #include <zephyr/kernel.h>
14 #include <zephyr/sys/util.h>
15 #include <zephyr/sys/linear_range.h>
16 
17 #include <zephyr/logging/log.h>
18 LOG_MODULE_REGISTER(pf1550_charger, CONFIG_CHARGER_LOG_LEVEL);
19 
20 #define INT_ENABLE_DELAY K_MSEC(500)
21 
22 #define CHARGER_CHG_INT           (0x80 + 0x00)
23 #define CHARGER_CHG_INT_MASK      (0x80 + 0x02)
24 #define CHARGER_CHG_INT_OK        (0x80 + 0x04)
25 #define CHARGER_VBUS_SNS          (0x80 + 0x06)
26 #define CHARGER_CHG_SNS           (0x80 + 0x07)
27 #define CHARGER_BATT_SNS          (0x80 + 0x08)
28 #define CHARGER_CHG_OPER          (0x80 + 0x09)
29 #define CHARGER_CHG_TMR           (0x80 + 0x0A)
30 #define CHARGER_CHG_EOC_CNFG      (0x80 + 0x0D)
31 #define CHARGER_CHG_CURR_CNFG     (0x80 + 0x0E)
32 #define CHARGER_BATT_REG          (0x80 + 0x0F)
33 #define CHARGER_BATFET_CNFG       (0x80 + 0x11)
34 #define CHARGER_THM_REG_CNFG      (0x80 + 0x12)
35 #define CHARGER_VBUS_INLIM_CNFG   (0x80 + 0x14)
36 #define CHARGER_VBUS_LIN_DPM      (0x80 + 0x15)
37 #define CHARGER_USB_PHY_LDO_CNFG  (0x80 + 0x16)
38 #define CHARGER_DBNC_DELAY_TIME   (0x80 + 0x18)
39 #define CHARGER_CHG_INT_CNFG      (0x80 + 0x19)
40 #define CHARGER_THM_ADJ_SETTING   (0x80 + 0x1A)
41 #define CHARGER_VBUS2SYS_CNFG     (0x80 + 0x1B)
42 #define CHARGER_LED_PWM           (0x80 + 0x1C)
43 #define CHARGER_FAULT_BATFET_CNFG (0x80 + 0x1D)
44 #define CHARGER_LED_CNFG          (0x80 + 0x1E)
45 #define CHARGER_CHGR_KEY2         (0x80 + 0x1F)
46 
47 #define PF1550_BAT_IRQ      BIT(2)
48 #define PF1550_CHG_IRQ      BIT(3)
49 #define PF1550_VBUS_IRQ     BIT(5)
50 #define PF1550_VBUS_DPM_IRQ BIT(5)
51 #define CHG_INT_ENABLE_ALL  (0xFF)
52 
53 #define LED_PWM_LED_EN          BIT(7)
54 #define LED_PWM_FULL_ON         BIT(5)
55 
56 #define LED_CNFG_LED_CFG        BIT(4)
57 #define LED_CNFG_LEDOVRD        BIT(5)
58 
59 #define CHG_OPER_CHG_OPER_MASK          GENMASK(1, 0)
60 #define CHG_CURR_CNFG_CHG_CC_MASK       GENMASK(4, 0)
61 #define CHG_SNS_CHG_SNS_MASK            GENMASK(3, 0)
62 #define VBUS_INLIM_CNFG_VBUS_INLIM_MASK GENMASK(7, 3)
63 #define BATT_REG_CHGCV_MASK             GENMASK(5, 0)
64 #define BATT_REG_VSYSMIN_MASK           GENMASK(7, 6)
65 #define THM_REG_CNFG_THM_CNFG_MASK      GENMASK(1, 0)
66 
67 #define CHG_OPER_CHARGER_OFF_LINEAR_OFF     0
68 #define CHG_OPER_CHARGER_OFF_LINEAR_ON      1
69 #define CHG_OPER_CHARGER_ON_LINEAR_ON       2
70 
71 enum charger_pf1550_therm_mode {
72 	PF1550_THERM_MODE_DISABLED,
73 	PF1550_THERM_MODE_THERMISTOR,
74 	PF1550_THERM_MODE_JEITA_1,
75 	PF1550_THERM_MODE_JEITA_2,
76 	PF1550_THERM_MODE_UNKNOWN,
77 };
78 
79 /* synced with YAML binding */
80 enum charger_pf1550_led_behaviour {
81 	PF1550_LED_ON_IN_CHARGING_FLASH_IN_FAULT,
82 	PF1550_LED_FLASH_IN_CHARGING_ON_IN_FAULT,
83 	PF1550_LED_MANUAL_OFF
84 };
85 
86 struct charger_pf1550_led_config {
87 	bool enabled;
88 	bool manual;
89 	enum charger_pf1550_led_behaviour behaviour;
90 };
91 
92 struct charger_pf1550_config {
93 	struct i2c_dt_spec bus;
94 	struct gpio_dt_spec int_gpio;
95 	char *therm_mon_mode;
96 	uint32_t charge_current_ua;
97 	uint32_t vbus_ilim_ua;
98 	uint32_t charge_voltage_max_uv;
99 	uint32_t vsys_min_uv;
100 };
101 
102 struct charger_pf1550_data {
103 	const struct device *dev;
104 	struct gpio_callback gpio_cb;
105 	struct k_work int_routine_work;
106 	struct k_work_delayable int_enable_work;
107 	enum charger_status charger_status;
108 	enum charger_online charger_online;
109 	charger_status_notifier_t charger_status_notifier;
110 	charger_online_notifier_t charger_online_notifier;
111 	bool charger_enabled;
112 	uint32_t charge_current_ua;
113 	uint32_t vbus_ilim_ua;
114 	struct charger_pf1550_led_config *led_config;
115 };
116 
117 static const struct linear_range charger_vbus_ilim_range[] = {
118 	LINEAR_RANGE_INIT(10000, 5000, 0, 8),
119 	LINEAR_RANGE_INIT(100000, 50000, 9, 10),
120 	LINEAR_RANGE_INIT(200000, 100000, 11, 19),
121 	LINEAR_RANGE_INIT(1500000, 0, 20, 20),
122 };
123 
124 static const struct linear_range charger_fast_charge_ua_range[] = {
125 	LINEAR_RANGE_INIT(100000, 50000, 0, 18),
126 };
127 
128 static const struct linear_range charger_battery_termination_uv_range[] = {
129 	LINEAR_RANGE_INIT(3500000, 20000, 8, 55),
130 };
131 
132 static const struct linear_range charger_vsysmin_uv[] = {
133 	LINEAR_RANGE_INIT(3500000, 0, 0, 0),
134 	LINEAR_RANGE_INIT(3700000, 0, 1, 1),
135 	LINEAR_RANGE_INIT(4300000, 0, 2, 2),
136 };
137 
pf1550_get_charger_status(const struct device * dev,enum charger_status * status)138 static int pf1550_get_charger_status(const struct device *dev, enum charger_status *status)
139 {
140 	enum chg_sns {
141 		PF1550_CHARGER_PRECHARGE,
142 		PF1550_FAST_CHARGE_CONSTANT_CURRENT,
143 		PF1550_FAST_CHARGE_CONSTANT_VOLTAGE,
144 		PF1550_END_OF_CHARGE,
145 		PF1550_CHARGE_DONE,
146 		PF1550_TIMER_FAULT = 6,
147 		PF1550_THERMISTOR_SUSPEND,
148 		PF1550_CHARGER_OFF_INVALID_INPUT,
149 		PF1550_BATTERY_OVERVOLTAGE,
150 		PF1550_BATTERY_OVERTEMPERATURE,
151 		PF1550_CHARGER_OFF_LINEAR_MODE = 12,
152 	};
153 
154 	const struct charger_pf1550_config *const config = dev->config;
155 	uint8_t val;
156 	int ret;
157 
158 	ret = i2c_reg_read_byte_dt(&config->bus, CHARGER_CHG_SNS, &val);
159 	if (ret) {
160 		return ret;
161 	}
162 
163 	val = FIELD_GET(CHG_SNS_CHG_SNS_MASK, val);
164 
165 	if (val == PF1550_CHARGE_DONE) {
166 		*status = CHARGER_STATUS_FULL;
167 	} else if (val < PF1550_CHARGE_DONE) {
168 		*status = CHARGER_STATUS_CHARGING;
169 	} else {
170 		*status = CHARGER_STATUS_NOT_CHARGING;
171 	}
172 
173 	return 0;
174 }
175 
pf1550_get_charger_online(const struct device * dev,enum charger_online * online)176 static int pf1550_get_charger_online(const struct device *dev, enum charger_online *online)
177 {
178 	const struct charger_pf1550_config *const config = dev->config;
179 	uint8_t val;
180 	int ret;
181 
182 	ret = i2c_reg_read_byte_dt(&config->bus, CHARGER_CHG_OPER, &val);
183 	if (ret) {
184 		return ret;
185 	}
186 
187 	val = FIELD_GET(CHG_OPER_CHG_OPER_MASK, val);
188 
189 	switch (val) {
190 	case CHG_OPER_CHARGER_ON_LINEAR_ON:
191 		*online = CHARGER_ONLINE_FIXED;
192 		break;
193 	default:
194 		*online = CHARGER_ONLINE_OFFLINE;
195 		break;
196 	};
197 
198 	return 0;
199 }
200 
pf1550_set_constant_charge_current(const struct device * dev,uint32_t current_ua)201 static int pf1550_set_constant_charge_current(const struct device *dev, uint32_t current_ua)
202 {
203 	const struct charger_pf1550_config *const config = dev->config;
204 	uint16_t idx;
205 	uint8_t val;
206 	int ret;
207 
208 	ret = linear_range_group_get_index(charger_fast_charge_ua_range,
209 					   ARRAY_SIZE(charger_fast_charge_ua_range), current_ua,
210 					   &idx);
211 	if (ret < 0) {
212 		return ret;
213 	}
214 
215 	val = FIELD_PREP(CHG_CURR_CNFG_CHG_CC_MASK, idx);
216 
217 	return i2c_reg_update_byte_dt(&config->bus, CHARGER_CHG_CURR_CNFG,
218 				      CHG_CURR_CNFG_CHG_CC_MASK, val);
219 }
220 
pf1550_set_vbus_ilim(const struct device * dev,uint32_t current_ua)221 static int pf1550_set_vbus_ilim(const struct device *dev, uint32_t current_ua)
222 {
223 	const struct charger_pf1550_config *const config = dev->config;
224 	uint16_t idx;
225 	uint8_t val;
226 	int ret;
227 
228 	ret = linear_range_group_get_index(charger_vbus_ilim_range,
229 					   ARRAY_SIZE(charger_vbus_ilim_range), current_ua, &idx);
230 	if (ret < 0) {
231 		return ret;
232 	}
233 
234 	val = FIELD_PREP(VBUS_INLIM_CNFG_VBUS_INLIM_MASK, idx);
235 
236 	return i2c_reg_update_byte_dt(&config->bus, CHARGER_VBUS_INLIM_CNFG,
237 				      VBUS_INLIM_CNFG_VBUS_INLIM_MASK, val);
238 }
239 
pf1550_set_vsys_min(const struct device * dev,uint32_t voltage_uv)240 static int pf1550_set_vsys_min(const struct device *dev, uint32_t voltage_uv)
241 {
242 	const struct charger_pf1550_config *const config = dev->config;
243 	uint16_t idx;
244 	uint8_t val;
245 	int ret;
246 
247 	ret = linear_range_group_get_index(charger_vsysmin_uv, ARRAY_SIZE(charger_vsysmin_uv),
248 					   voltage_uv, &idx);
249 	if (ret < 0) {
250 		return ret;
251 	}
252 
253 	val = FIELD_PREP(BATT_REG_VSYSMIN_MASK, idx);
254 
255 	return i2c_reg_update_byte_dt(&config->bus, CHARGER_BATT_REG, BATT_REG_VSYSMIN_MASK, val);
256 }
257 
pf1550_set_charge_termination_uv(const struct device * dev,uint32_t voltage_uv)258 static int pf1550_set_charge_termination_uv(const struct device *dev, uint32_t voltage_uv)
259 {
260 	const struct charger_pf1550_config *const config = dev->config;
261 	uint16_t idx;
262 	uint8_t val;
263 	int ret;
264 
265 	ret = linear_range_group_get_index(charger_battery_termination_uv_range,
266 					   ARRAY_SIZE(charger_battery_termination_uv_range),
267 					   voltage_uv, &idx);
268 	if (ret < 0) {
269 		return ret;
270 	}
271 
272 	val = FIELD_PREP(BATT_REG_CHGCV_MASK, idx);
273 
274 	return i2c_reg_update_byte_dt(&config->bus, CHARGER_BATT_REG, BATT_REG_CHGCV_MASK, val);
275 }
276 
pf1550_set_thermistor_mode(const struct device * dev,enum charger_pf1550_therm_mode mode)277 static int pf1550_set_thermistor_mode(const struct device *dev, enum charger_pf1550_therm_mode mode)
278 {
279 	const struct charger_pf1550_config *const config = dev->config;
280 	uint8_t val;
281 
282 	val = FIELD_PREP(THM_REG_CNFG_THM_CNFG_MASK, mode);
283 
284 	return i2c_reg_update_byte_dt(&config->bus, CHARGER_THM_REG_CNFG,
285 				      THM_REG_CNFG_THM_CNFG_MASK, val);
286 }
287 
pf1550_set_enabled(const struct device * dev,bool enable)288 static int pf1550_set_enabled(const struct device *dev, bool enable)
289 {
290 	struct charger_pf1550_data *data = dev->data;
291 	const struct charger_pf1550_config *const config = dev->config;
292 
293 	int ret = i2c_reg_update_byte_dt(&config->bus, CHARGER_CHG_OPER, CHG_OPER_CHG_OPER_MASK,
294 					 enable ? 2 : 0);
295 
296 	if (ret == 0) {
297 		data->charger_enabled = enable;
298 	}
299 
300 	return ret;
301 }
302 
pf1550_get_interrupt_source(const struct device * dev,uint8_t * int_a)303 static int pf1550_get_interrupt_source(const struct device *dev, uint8_t *int_a)
304 {
305 	const struct charger_pf1550_config *config = dev->config;
306 	uint8_t buf = 0;
307 	int ret;
308 
309 	ret = i2c_reg_read_byte_dt(&config->bus, CHARGER_CHG_INT, &buf);
310 
311 	if (int_a) {
312 		*int_a = buf;
313 	}
314 	return ret;
315 }
316 
pf1550_enable_interrupts(const struct device * dev)317 static int pf1550_enable_interrupts(const struct device *dev)
318 {
319 	const struct charger_pf1550_config *config = dev->config;
320 	int ret;
321 
322 	ret = pf1550_get_interrupt_source(dev, NULL);
323 	if (ret < 0) {
324 		LOG_WRN("Failed to clear pending interrupts: %d", ret);
325 		return ret;
326 	}
327 
328 	return i2c_reg_write_byte_dt(&config->bus, CHARGER_CHG_INT_MASK, CHG_INT_ENABLE_ALL);
329 }
330 
pf1550_led_config(const struct device * dev)331 static int pf1550_led_config(const struct device *dev)
332 {
333 	struct charger_pf1550_data *data = dev->data;
334 	const struct charger_pf1550_config *config = dev->config;
335 	struct charger_pf1550_led_config *cfg = data->led_config;
336 	int ret;
337 	uint8_t val;
338 
339 	cfg->enabled = true;
340 
341 	if (cfg->behaviour == PF1550_LED_MANUAL_OFF) {
342 		cfg->manual = true;
343 		cfg->enabled = false;
344 	}
345 
346 	val = (cfg->enabled ? LED_PWM_LED_EN : 0) | LED_PWM_FULL_ON;
347 
348 	ret = i2c_reg_write_byte_dt(&config->bus, CHARGER_LED_PWM, val);
349 	if (ret < 0) {
350 		return ret;
351 	}
352 
353 	val = (cfg->manual ? LED_CNFG_LEDOVRD : 0) |
354 	      (cfg->behaviour == PF1550_LED_FLASH_IN_CHARGING_ON_IN_FAULT ?
355 	       LED_CNFG_LED_CFG : 0);
356 
357 	return i2c_reg_write_byte_dt(&config->bus, CHARGER_LED_CNFG, val);
358 }
359 
pf1550_init_properties(const struct device * dev)360 static int pf1550_init_properties(const struct device *dev)
361 {
362 	struct charger_pf1550_data *data = dev->data;
363 	const struct charger_pf1550_config *config = dev->config;
364 	int ret;
365 
366 	data->charger_enabled = true;
367 	data->charge_current_ua = config->charge_current_ua;
368 	data->vbus_ilim_ua = config->vbus_ilim_ua;
369 
370 	ret = pf1550_get_charger_status(dev, &data->charger_status);
371 	if (ret < 0) {
372 		LOG_ERR("Failed to read charger status: %d", ret);
373 		return ret;
374 	}
375 
376 	ret = pf1550_get_charger_online(dev, &data->charger_online);
377 	if (ret < 0) {
378 		LOG_ERR("Failed to read charger online: %d", ret);
379 		return ret;
380 	}
381 
382 	return 0;
383 }
384 
pf1550_string_to_therm_mode(const char * mode_string)385 enum charger_pf1550_therm_mode pf1550_string_to_therm_mode(const char *mode_string)
386 {
387 	static const char *const modes[] = {
388 		[PF1550_THERM_MODE_DISABLED] = "disabled",
389 		[PF1550_THERM_MODE_THERMISTOR] = "thermistor",
390 		[PF1550_THERM_MODE_JEITA_1] = "JEITA-1",
391 		[PF1550_THERM_MODE_JEITA_2] = "JEITA-2",
392 	};
393 	enum charger_pf1550_therm_mode i;
394 
395 	for (i = PF1550_THERM_MODE_DISABLED; i < ARRAY_SIZE(modes); i++) {
396 		if (strncmp(mode_string, modes[i], strlen(modes[i])) == 0) {
397 			return i;
398 		}
399 	}
400 
401 	return PF1550_THERM_MODE_UNKNOWN;
402 }
403 
pf1550_update_properties(const struct device * dev)404 static int pf1550_update_properties(const struct device *dev)
405 {
406 	struct charger_pf1550_data *data = dev->data;
407 	const struct charger_pf1550_config *config = dev->config;
408 	enum charger_pf1550_therm_mode therm_mode;
409 	int ret;
410 
411 	ret = pf1550_set_vbus_ilim(dev, config->vbus_ilim_ua);
412 	if (ret < 0) {
413 		LOG_ERR("Failed to set vbus current limit: %d", ret);
414 		return ret;
415 	}
416 
417 	ret = pf1550_set_vsys_min(dev, config->vsys_min_uv);
418 	if (ret < 0) {
419 		LOG_ERR("Failed to set minimum system voltage threshold: %d", ret);
420 		return ret;
421 	}
422 
423 	ret = pf1550_set_charge_termination_uv(dev, config->charge_voltage_max_uv);
424 	if (ret < 0) {
425 		LOG_ERR("Failed to set recharge threshold: %d", ret);
426 		return ret;
427 	}
428 
429 	therm_mode = pf1550_string_to_therm_mode(config->therm_mon_mode);
430 	ret = pf1550_set_thermistor_mode(dev, therm_mode);
431 	if (ret < 0) {
432 		LOG_ERR("Failed to set thermistor mode: %d", ret);
433 		return ret;
434 	}
435 
436 	ret = pf1550_set_constant_charge_current(dev, data->charge_current_ua);
437 	if (ret < 0) {
438 		LOG_ERR("Failed to set charge voltage: %d", ret);
439 		return ret;
440 	}
441 
442 	ret = pf1550_set_enabled(dev, data->charger_enabled);
443 	if (ret < 0) {
444 		LOG_ERR("Failed to set enabled: %d", ret);
445 		return ret;
446 	}
447 
448 	ret = pf1550_led_config(dev);
449 	if (ret < 0) {
450 		LOG_ERR("Failed to configure led: %d", ret);
451 		return ret;
452 	}
453 
454 	return 0;
455 }
456 
pf1550_get_prop(const struct device * dev,charger_prop_t prop,union charger_propval * val)457 static int pf1550_get_prop(const struct device *dev, charger_prop_t prop,
458 			   union charger_propval *val)
459 {
460 	struct charger_pf1550_data *data = dev->data;
461 
462 	switch (prop) {
463 	case CHARGER_PROP_ONLINE:
464 		val->online = data->charger_online;
465 		return 0;
466 	case CHARGER_PROP_STATUS:
467 		val->status = data->charger_status;
468 		return 0;
469 	case CHARGER_PROP_CONSTANT_CHARGE_CURRENT_UA:
470 		val->const_charge_current_ua = data->charge_current_ua;
471 		return 0;
472 	default:
473 		return -ENOTSUP;
474 	}
475 }
476 
pf1550_set_prop(const struct device * dev,charger_prop_t prop,const union charger_propval * val)477 static int pf1550_set_prop(const struct device *dev, charger_prop_t prop,
478 			   const union charger_propval *val)
479 {
480 	struct charger_pf1550_data *data = dev->data;
481 	int ret;
482 
483 	switch (prop) {
484 	case CHARGER_PROP_CONSTANT_CHARGE_CURRENT_UA:
485 		ret = pf1550_set_constant_charge_current(dev, val->const_charge_current_ua);
486 		if (ret == 0) {
487 			data->charge_current_ua = val->const_charge_current_ua;
488 		}
489 		return ret;
490 	case CHARGER_PROP_INPUT_REGULATION_CURRENT_UA:
491 		ret = pf1550_set_vbus_ilim(dev, val->input_current_regulation_current_ua);
492 		if (ret == 0) {
493 			data->vbus_ilim_ua = val->input_current_regulation_current_ua;
494 		}
495 		return ret;
496 	case CHARGER_PROP_STATUS_NOTIFICATION:
497 		data->charger_status_notifier = val->status_notification;
498 		return 0;
499 	case CHARGER_PROP_ONLINE_NOTIFICATION:
500 		data->charger_online_notifier = val->online_notification;
501 		return 0;
502 	default:
503 		return -ENOTSUP;
504 	}
505 }
506 
pf1550_enable_interrupt_pin(const struct device * dev,bool enabled)507 static int pf1550_enable_interrupt_pin(const struct device *dev, bool enabled)
508 {
509 	const struct charger_pf1550_config *const config = dev->config;
510 	gpio_flags_t flags;
511 	int ret;
512 
513 	flags = enabled ? GPIO_INT_EDGE_TO_ACTIVE : GPIO_INT_DISABLE;
514 
515 	ret = gpio_pin_interrupt_configure_dt(&config->int_gpio, flags);
516 	if (ret < 0) {
517 		LOG_ERR("Could not %s interrupt GPIO callback: %d", enabled ? "enable" : "disable",
518 			ret);
519 	}
520 
521 	return ret;
522 }
523 
pf1550_gpio_callback(const struct device * dev,struct gpio_callback * cb,uint32_t pins)524 static void pf1550_gpio_callback(const struct device *dev, struct gpio_callback *cb, uint32_t pins)
525 {
526 	struct charger_pf1550_data *data = CONTAINER_OF(cb, struct charger_pf1550_data, gpio_cb);
527 	int ret;
528 
529 	(void)pf1550_enable_interrupt_pin(data->dev, false);
530 
531 	ret = k_work_submit(&data->int_routine_work);
532 	if (ret < 0) {
533 		LOG_WRN("Could not submit int work: %d", ret);
534 	}
535 }
536 
pf1550_int_routine_work_handler(struct k_work * work)537 static void pf1550_int_routine_work_handler(struct k_work *work)
538 {
539 	struct charger_pf1550_data *data =
540 		CONTAINER_OF(work, struct charger_pf1550_data, int_routine_work);
541 	uint8_t int_src;
542 	int ret;
543 
544 	ret = pf1550_get_interrupt_source(data->dev, &int_src);
545 	if (ret < 0) {
546 		LOG_WRN("Failed to read interrupt source: %d", ret);
547 		return;
548 	}
549 
550 	LOG_DBG("Interrupt received: %x", int_src);
551 
552 	ret = pf1550_get_charger_status(data->dev, &data->charger_status);
553 	if (ret < 0) {
554 		LOG_WRN("Failed to read charger status: %d", ret);
555 		return;
556 	}
557 
558 	ret = pf1550_get_charger_online(data->dev, &data->charger_online);
559 	if (ret < 0) {
560 		LOG_WRN("Failed to read charger online %d", ret);
561 		return;
562 	}
563 
564 	if (data->charger_status_notifier != NULL) {
565 		data->charger_status_notifier(data->charger_status);
566 	}
567 	if (data->charger_online_notifier != NULL) {
568 		data->charger_online_notifier(data->charger_online);
569 	}
570 
571 	if (data->charger_online != CHARGER_ONLINE_OFFLINE) {
572 		(void)pf1550_update_properties(data->dev);
573 	}
574 
575 	ret = k_work_reschedule(&data->int_enable_work, INT_ENABLE_DELAY);
576 	if (ret < 0) {
577 		LOG_WRN("Could not reschedule int_enable_work: %d", ret);
578 	}
579 }
580 
pf1550_int_enable_work_handler(struct k_work * work)581 static void pf1550_int_enable_work_handler(struct k_work *work)
582 {
583 	struct k_work_delayable *dwork = k_work_delayable_from_work(work);
584 	struct charger_pf1550_data *data =
585 		CONTAINER_OF(dwork, struct charger_pf1550_data, int_enable_work);
586 
587 	(void)pf1550_enable_interrupt_pin(data->dev, true);
588 }
589 
pf1550_configure_interrupt_pin(const struct device * dev)590 static int pf1550_configure_interrupt_pin(const struct device *dev)
591 {
592 	struct charger_pf1550_data *data = dev->data;
593 	const struct charger_pf1550_config *config = dev->config;
594 	int ret;
595 
596 	ret = gpio_is_ready_dt(&config->int_gpio) ? 0 : -ENODEV;
597 	if (ret < 0) {
598 		LOG_ERR("Interrupt GPIO device not ready: %d", ret);
599 		return ret;
600 	}
601 
602 	ret = gpio_pin_configure_dt(&config->int_gpio, GPIO_INPUT);
603 	if (ret < 0) {
604 		LOG_ERR("Could not configure interrupt GPIO: %d", ret);
605 		return ret;
606 	}
607 
608 	gpio_init_callback(&data->gpio_cb, pf1550_gpio_callback, BIT(config->int_gpio.pin));
609 	ret = gpio_add_callback_dt(&config->int_gpio, &data->gpio_cb);
610 	if (ret < 0) {
611 		LOG_ERR("Could not add interrupt GPIO callback: %d", ret);
612 		return ret;
613 	}
614 
615 	return 0;
616 }
617 
pf1550_init(const struct device * dev)618 static int pf1550_init(const struct device *dev)
619 {
620 	struct charger_pf1550_data *data = dev->data;
621 	const struct charger_pf1550_config *config = dev->config;
622 	int ret;
623 
624 	if (!i2c_is_ready_dt(&config->bus)) {
625 		return -ENODEV;
626 	}
627 
628 	data->dev = dev;
629 
630 	ret = pf1550_init_properties(dev);
631 	if (ret < 0) {
632 		return ret;
633 	}
634 
635 	k_work_init(&data->int_routine_work, pf1550_int_routine_work_handler);
636 	k_work_init_delayable(&data->int_enable_work, pf1550_int_enable_work_handler);
637 
638 	ret = pf1550_configure_interrupt_pin(dev);
639 	if (ret < 0) {
640 		return ret;
641 	}
642 
643 	ret = pf1550_enable_interrupt_pin(dev, true);
644 	if (ret < 0) {
645 		return ret;
646 	}
647 
648 	ret = pf1550_enable_interrupts(dev);
649 	if (ret < 0) {
650 		LOG_ERR("Failed to enable interrupts: %d", ret);
651 		return ret;
652 	}
653 
654 	ret = pf1550_update_properties(dev);
655 	if (ret < 0) {
656 		LOG_ERR("Failed to setup charger: %d", ret);
657 		return ret;
658 	}
659 
660 	return 0;
661 }
662 
663 static DEVICE_API(charger, pf1550_driver_api) = {
664 	.get_property = pf1550_get_prop,
665 	.set_property = pf1550_set_prop,
666 	.charge_enable = pf1550_set_enabled,
667 };
668 
669 #define PF1550_DEFINE(inst)                                                                        \
670 	static struct charger_pf1550_led_config charger_pf1550_led_config_##inst = {               \
671 		.behaviour = DT_INST_ENUM_IDX(inst, pf1550_led_behaviour),                         \
672 	};                                                                                         \
673 	static struct charger_pf1550_data charger_pf1550_data_##inst = {                           \
674 		.led_config = &charger_pf1550_led_config_##inst,                                   \
675 	};                                                                                         \
676 	static const struct charger_pf1550_config charger_pf1550_config_##inst = {                 \
677 		.bus = I2C_DT_SPEC_GET(DT_INST_PARENT(inst)),                                      \
678 		.int_gpio = GPIO_DT_SPEC_INST_GET(inst, pf1550_int_gpios),                         \
679 		.charge_current_ua = DT_INST_PROP(inst, constant_charge_current_max_microamp),     \
680 		.vsys_min_uv = DT_INST_PROP(inst, pf1550_system_voltage_min_threshold_microvolt),  \
681 		.therm_mon_mode = DT_INST_PROP(inst, pf1550_thermistor_monitoring_mode),           \
682 		.vbus_ilim_ua = DT_INST_PROP(inst, pf1550_vbus_current_limit_microamp),            \
683 		.charge_voltage_max_uv =                                                           \
684 			DT_INST_PROP(inst, constant_charge_voltage_max_microvolt),                 \
685 	};                                                                                         \
686 												   \
687 	DEVICE_DT_INST_DEFINE(inst, &pf1550_init, NULL, &charger_pf1550_data_##inst,               \
688 			      &charger_pf1550_config_##inst, POST_KERNEL,                          \
689 			      CONFIG_MFD_INIT_PRIORITY, &pf1550_driver_api);
690 
691 DT_INST_FOREACH_STATUS_OKAY(PF1550_DEFINE)
692