| /* | 
 |  * Copyright (c) 2023 Martin Kiepfer <mrmarteng@teleschirm.org> | 
 |  * SPDX-License-Identifier: Apache-2.0 | 
 |  */ | 
 |  | 
 | #include <errno.h> | 
 | #include <stdbool.h> | 
 |  | 
 | #include <zephyr/drivers/mfd/axp192.h> | 
 | #include <zephyr/drivers/i2c.h> | 
 | #include <zephyr/sys/util.h> | 
 | #include <zephyr/logging/log.h> | 
 |  | 
 | LOG_MODULE_REGISTER(mfd_axp192, CONFIG_MFD_LOG_LEVEL); | 
 |  | 
 | struct mfd_axp192_config { | 
 | 	struct i2c_dt_spec i2c; | 
 | 	bool vbusen_disable; | 
 | 	uint8_t vbus_config_reg; | 
 | 	uint8_t val_vbusen_disable; | 
 | }; | 
 |  | 
 | /* Chip ID value */ | 
 | #define AXP192_CHIP_ID 0x03U | 
 |  | 
 | /* Registers definitions */ | 
 | #define AXP192_REG_CHIP_ID 0x03U | 
 |  | 
 | /* AXP192 GPIO register addresses */ | 
 | #define AXP192_EXTEN_DCDC2_CONTROL_REG 0x10U | 
 | #define AXP192_VBUS_CFG_REG            0x30U | 
 | #define AXP192_GPIO0_FUNC_REG          0x90U | 
 | #define AXP192_GPIO1_FUNC_REG          0x92U | 
 | #define AXP192_GPIO2_FUNC_REG          0x93U | 
 | #define AXP192_GPIO34_FUNC_REG         0x95U | 
 | #define AXP192_GPIO012_PINVAL_REG      0x94U | 
 | #define AXP192_GPIO34_PINVAL_REG       0x96U | 
 | #define AXP192_GPIO012_PULLDOWN_REG    0x97U | 
 |  | 
 | /* VBUS control reg values */ | 
 | #define AXP192_VBUS_CFG_VAL_VBUSEN_DISABLE 0x80U | 
 |  | 
 | /* GPIO function control parameters */ | 
 | #define AXP192_GPIO012_FUNC_VAL_OUTPUT_OD  0x00U | 
 | #define AXP192_GPIO012_FUNC_VAL_INPUT      0x01U | 
 | #define AXP192_GPIO012_FUNC_VAL_LDO        0x02U /* only applicable for GPIO0 */ | 
 | #define AXP192_GPIO012_FUNC_VAL_ADC        0x04U | 
 | #define AXP192_GPIO012_FUNC_VAL_OUTPUT_LOW 0x05U | 
 | #define AXP192_GPIO012_FUNC_VAL_FLOAT      0x06U | 
 | #define AXP192_GPIO012_FUNC_MASK                                                                   \ | 
 | 	(AXP192_GPIO012_FUNC_VAL_OUTPUT_OD | AXP192_GPIO012_FUNC_VAL_INPUT |                       \ | 
 | 	 AXP192_GPIO012_FUNC_VAL_LDO | AXP192_GPIO012_FUNC_VAL_ADC |                               \ | 
 | 	 AXP192_GPIO012_FUNC_VAL_OUTPUT_LOW | AXP192_GPIO012_FUNC_VAL_FLOAT) | 
 |  | 
 | #define AXP192_GPIO34_FUNC_ENA           0x80U | 
 | #define AXP192_GPIO3_FUNC_VAL_CHARGE_CTL 0x00U | 
 | #define AXP192_GPIO3_FUNC_VAL_OUTPUT_OD  0x01U | 
 | #define AXP192_GPIO3_FUNC_VAL_INPUT      0x02U | 
 | #define AXP192_GPIO3_FUNC_MASK                                                                     \ | 
 | 	(AXP192_GPIO34_FUNC_ENA | AXP192_GPIO3_FUNC_VAL_CHARGE_CTL |                               \ | 
 | 	 AXP192_GPIO3_FUNC_VAL_OUTPUT_OD | AXP192_GPIO3_FUNC_VAL_INPUT) | 
 |  | 
 | #define AXP192_GPIO4_FUNC_VAL_CHARGE_CTL 0x00U | 
 | #define AXP192_GPIO4_FUNC_VAL_OUTPUT_OD  0x04U | 
 | #define AXP192_GPIO4_FUNC_VAL_INPUT      0x08U | 
 | #define AXP192_GPIO4_FUNC_VAL_ADC        0x0CU | 
 | #define AXP192_GPIO4_FUNC_MASK                                                                     \ | 
 | 	(AXP192_GPIO34_FUNC_ENA | AXP192_GPIO4_FUNC_VAL_CHARGE_CTL |                               \ | 
 | 	 AXP192_GPIO4_FUNC_VAL_OUTPUT_OD | AXP192_GPIO4_FUNC_VAL_INPUT) | 
 |  | 
 | #define AXP192_EXTEN_ENA  0x04U | 
 | #define AXP192_EXTEN_MASK 0x04U | 
 |  | 
 | /* Pull-Down enable parameters */ | 
 | #define AXP192_GPIO0_PULLDOWN_ENABLE 0x01U | 
 | #define AXP192_GPIO1_PULLDOWN_ENABLE 0x02U | 
 | #define AXP192_GPIO2_PULLDOWN_ENABLE 0x04U | 
 |  | 
 | /* GPIO Value parameters */ | 
 | #define AXP192_GPIO0_INPUT_VAL      0x10U | 
 | #define AXP192_GPIO1_INPUT_VAL      0x20U | 
 | #define AXP192_GPIO2_INPUT_VAL      0x40U | 
 | #define AXP192_GPIO012_INTPUT_SHIFT 4U | 
 | #define AXP192_GPIO012_INTPUT_MASK                                                                 \ | 
 | 	(AXP192_GPIO0_INPUT_VAL | AXP192_GPIO1_INPUT_VAL | AXP192_GPIO2_INPUT_VAL) | 
 | #define AXP192_GPIO3_INPUT_VAL     0x10U | 
 | #define AXP192_GPIO4_INPUT_VAL     0x20U | 
 | #define AXP192_GPIO34_INTPUT_SHIFT 4U | 
 | #define AXP192_GPIO34_INTPUT_MASK  (AXP192_GPIO3_INPUT_VAL | AXP192_GPIO4_INPUT_VAL) | 
 |  | 
 | #define AXP192_GPIO0_OUTPUT_VAL 0x01U | 
 | #define AXP192_GPIO1_OUTPUT_VAL 0x02U | 
 | #define AXP192_GPIO2_OUTPUT_VAL 0x04U | 
 | #define AXP192_GPIO012_OUTPUT_MASK                                                                 \ | 
 | 	(AXP192_GPIO0_OUTPUT_VAL | AXP192_GPIO1_OUTPUT_VAL | AXP192_GPIO2_OUTPUT_VAL) | 
 |  | 
 | #define AXP192_GPIO3_OUTPUT_VAL   0x01U | 
 | #define AXP192_GPIO4_OUTPUT_VAL   0x02U | 
 | #define AXP192_GPIO34_OUTPUT_MASK (AXP192_GPIO3_OUTPUT_VAL | AXP192_GPIO4_OUTPUT_VAL) | 
 |  | 
 | #define AXP192_GPIO5_OUTPUT_MASK  0x04U | 
 | #define AXP192_GPIO5_OUTPUT_VAL   0x04U | 
 | #define AXP192_GPIO5_OUTPUT_SHIFT 2U | 
 |  | 
 | struct mfd_axp192_data { | 
 | 	const struct device *gpio_mask_used[AXP192_GPIO_MAX_NUM]; | 
 | 	uint8_t gpio_mask_output; | 
 | }; | 
 |  | 
 | struct mfd_axp192_func_reg_desc { | 
 | 	uint8_t reg; | 
 | 	uint8_t mask; | 
 | }; | 
 |  | 
 | const struct mfd_axp192_func_reg_desc gpio_reg_desc[AXP192_GPIO_MAX_NUM] = { | 
 | 	{ | 
 | 		/* GPIO0 */ | 
 | 		.reg = AXP192_GPIO0_FUNC_REG, | 
 | 		.mask = AXP192_GPIO012_FUNC_MASK, | 
 | 	}, | 
 | 	{ | 
 | 		/* GPIO1 */ | 
 | 		.reg = AXP192_GPIO1_FUNC_REG, | 
 | 		.mask = AXP192_GPIO012_FUNC_MASK, | 
 | 	}, | 
 | 	{ | 
 | 		/* GPIO2 */ | 
 | 		.reg = AXP192_GPIO2_FUNC_REG, | 
 | 		.mask = AXP192_GPIO012_FUNC_MASK, | 
 | 	}, | 
 | 	{ | 
 | 		/* GPIO3 */ | 
 | 		.reg = AXP192_GPIO34_FUNC_REG, | 
 | 		.mask = AXP192_GPIO3_FUNC_MASK, | 
 | 	}, | 
 | 	{ | 
 | 		/* GPIO4 */ | 
 | 		.reg = AXP192_GPIO34_FUNC_REG, | 
 | 		.mask = AXP192_GPIO4_FUNC_MASK, | 
 | 	}, | 
 | }; | 
 |  | 
 | static int mfd_axp192_init(const struct device *dev) | 
 | { | 
 | 	const struct mfd_axp192_config *config = dev->config; | 
 | 	uint8_t chip_id; | 
 | 	int ret; | 
 |  | 
 | 	LOG_DBG("Initializing instance"); | 
 |  | 
 | 	if (!i2c_is_ready_dt(&config->i2c)) { | 
 | 		LOG_ERR("I2C bus not ready"); | 
 | 		return -ENODEV; | 
 | 	} | 
 |  | 
 | 	/* Check if AXP192 chip is available */ | 
 | 	ret = i2c_reg_read_byte_dt(&config->i2c, AXP192_REG_CHIP_ID, &chip_id); | 
 | 	if (ret < 0) { | 
 | 		return ret; | 
 | 	} | 
 | 	if (chip_id != AXP192_CHIP_ID) { | 
 | 		LOG_ERR("Invalid Chip detected (%d)", chip_id); | 
 | 		return -EINVAL; | 
 | 	} | 
 |  | 
 | 	/* Disable N_VBUSEN */ | 
 | 	ret = i2c_reg_update_byte_dt( | 
 | 		&config->i2c, config->vbus_config_reg, config->val_vbusen_disable, | 
 | 		config->vbusen_disable ? config->val_vbusen_disable : 0); | 
 | 	if (ret < 0) { | 
 | 		return ret; | 
 | 	} | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | int mfd_axp192_gpio_func_get(const struct device *dev, uint8_t gpio, enum axp192_gpio_func *func) | 
 | { | 
 | 	const struct mfd_axp192_config *config = dev->config; | 
 | 	int ret; | 
 | 	uint8_t reg_fnc; | 
 |  | 
 | 	if (gpio >= AXP192_GPIO_MAX_NUM) { | 
 | 		LOG_ERR("Invalid gpio (%d)", gpio); | 
 | 		return -EINVAL; | 
 | 	} | 
 |  | 
 | 	if (gpio < ARRAY_SIZE(gpio_reg_desc)) { | 
 | 		ret = i2c_reg_read_byte_dt(&(config->i2c), gpio_reg_desc[gpio].reg, ®_fnc); | 
 | 		if (ret != 0) { | 
 | 			return ret; | 
 | 		} | 
 | 	} | 
 |  | 
 | 	switch (gpio) { | 
 | 	case 0U: | 
 | 		__fallthrough; | 
 | 	case 1U: | 
 | 		__fallthrough; | 
 | 	case 2U: | 
 | 		/* GPIO 0-2*/ | 
 | 		switch (reg_fnc) { | 
 | 		case AXP192_GPIO012_FUNC_VAL_INPUT: | 
 | 			*func = AXP192_GPIO_FUNC_INPUT; | 
 | 			break; | 
 | 		case AXP192_GPIO012_FUNC_VAL_OUTPUT_OD: | 
 | 			*func = AXP192_GPIO_FUNC_OUTPUT_OD; | 
 | 			break; | 
 | 		case AXP192_GPIO012_FUNC_VAL_OUTPUT_LOW: | 
 | 			*func = AXP192_GPIO_FUNC_OUTPUT_LOW; | 
 | 			break; | 
 | 		case AXP192_GPIO012_FUNC_VAL_LDO: | 
 | 			if (gpio == 0) { | 
 | 				/* LDO is only applicable on GPIO0 */ | 
 | 				*func = AXP192_GPIO_FUNC_LDO; | 
 | 			} else { | 
 | 				ret = -ENOTSUP; | 
 | 			} | 
 | 			break; | 
 | 		case AXP192_GPIO012_FUNC_VAL_ADC: | 
 | 			*func = AXP192_GPIO_FUNC_ADC; | 
 | 			break; | 
 | 		case AXP192_GPIO012_FUNC_VAL_FLOAT: | 
 | 			*func = AXP192_GPIO_FUNC_FLOAT; | 
 | 			break; | 
 | 		default: | 
 | 			ret = -ENOTSUP; | 
 | 			break; | 
 | 		} | 
 | 		break; | 
 |  | 
 | 	case 3U: | 
 | 		/* GPIO3 */ | 
 | 		switch (reg_fnc) { | 
 | 		case (AXP192_GPIO3_FUNC_VAL_INPUT | AXP192_GPIO34_FUNC_ENA): | 
 | 			*func = AXP192_GPIO_FUNC_INPUT; | 
 | 			break; | 
 | 		case (AXP192_GPIO3_FUNC_VAL_OUTPUT_OD | AXP192_GPIO34_FUNC_ENA): | 
 | 			*func = AXP192_GPIO_FUNC_OUTPUT_OD; | 
 | 			break; | 
 | 		case AXP192_GPIO3_FUNC_VAL_CHARGE_CTL: | 
 | 			*func = AXP192_GPIO_FUNC_CHARGE_CTL; | 
 | 			break; | 
 | 		default: | 
 | 			ret = -ENOTSUP; | 
 | 			break; | 
 | 		} | 
 | 		break; | 
 |  | 
 | 	case 4U: | 
 | 		/* GPIO4 */ | 
 | 		switch (reg_fnc) { | 
 | 		case (AXP192_GPIO4_FUNC_VAL_INPUT | AXP192_GPIO34_FUNC_ENA): | 
 | 			*func = AXP192_GPIO_FUNC_INPUT; | 
 | 			break; | 
 | 		case (AXP192_GPIO4_FUNC_VAL_OUTPUT_OD | AXP192_GPIO34_FUNC_ENA): | 
 | 			*func = AXP192_GPIO_FUNC_OUTPUT_OD; | 
 | 			break; | 
 | 		case (AXP192_GPIO4_FUNC_VAL_ADC | AXP192_GPIO34_FUNC_ENA): | 
 | 			*func = AXP192_GPIO_FUNC_ADC; | 
 | 			break; | 
 | 		case AXP192_GPIO4_FUNC_VAL_CHARGE_CTL: | 
 | 			*func = AXP192_GPIO_FUNC_CHARGE_CTL; | 
 | 			break; | 
 | 		default: | 
 | 			ret = -ENOTSUP; | 
 | 			break; | 
 | 		} | 
 | 		break; | 
 |  | 
 | 	case 5U: | 
 | 		/* EXTEN is an output only pin */ | 
 | 		*func = AXP192_GPIO_FUNC_OUTPUT_LOW; | 
 | 		break; | 
 |  | 
 | 	default: | 
 | 		ret = -EINVAL; | 
 | 	} | 
 |  | 
 | 	return ret; | 
 | } | 
 |  | 
 | int mfd_axp192_gpio_func_ctrl(const struct device *dev, const struct device *client_dev, | 
 | 			      uint8_t gpio, enum axp192_gpio_func func) | 
 | { | 
 | 	const struct mfd_axp192_config *config = dev->config; | 
 | 	struct mfd_axp192_data *data = dev->data; | 
 | 	bool is_output = false; | 
 | 	int ret = 0; | 
 | 	uint8_t reg_cfg = 0; | 
 |  | 
 | 	if (!AXP192_GPIO_FUNC_VALID(func)) { | 
 | 		LOG_ERR("Invalid function"); | 
 | 		return -EINVAL; | 
 | 	} | 
 |  | 
 | 	if (gpio >= AXP192_GPIO_MAX_NUM) { | 
 | 		LOG_ERR("Invalid gpio (%d)", gpio); | 
 | 		return -EINVAL; | 
 | 	} | 
 |  | 
 | 	if ((data->gpio_mask_used[gpio] != 0) && (data->gpio_mask_used[gpio] != client_dev)) { | 
 | 		LOG_INF("Warning: Pin already configured. Please check dt configuration"); | 
 | 	} | 
 |  | 
 | 	switch (gpio) { | 
 | 	case 0U: | 
 | 		__fallthrough; | 
 | 	case 1U: | 
 | 		__fallthrough; | 
 | 	case 2U: | 
 | 		/* GPIO 0-2*/ | 
 | 		switch (func) { | 
 | 		case AXP192_GPIO_FUNC_INPUT: | 
 | 			reg_cfg = AXP192_GPIO012_FUNC_VAL_INPUT; | 
 | 			break; | 
 | 		case AXP192_GPIO_FUNC_OUTPUT_OD: | 
 | 			reg_cfg = AXP192_GPIO012_FUNC_VAL_OUTPUT_OD; | 
 | 			is_output = true; | 
 | 			break; | 
 | 		case AXP192_GPIO_FUNC_OUTPUT_LOW: | 
 | 			reg_cfg = AXP192_GPIO012_FUNC_VAL_OUTPUT_LOW; | 
 | 			is_output = true; | 
 | 			break; | 
 | 		case AXP192_GPIO_FUNC_LDO: | 
 | 			if (gpio == 0) { | 
 | 				/* LDO is only applicable on GPIO0 */ | 
 | 				reg_cfg = AXP192_GPIO012_FUNC_VAL_LDO; | 
 | 			} else { | 
 | 				ret = -ENOTSUP; | 
 | 			} | 
 | 			break; | 
 | 		case AXP192_GPIO_FUNC_ADC: | 
 | 			reg_cfg = AXP192_GPIO012_FUNC_VAL_ADC; | 
 | 			break; | 
 | 		case AXP192_GPIO_FUNC_FLOAT: | 
 | 			reg_cfg = AXP192_GPIO012_FUNC_VAL_FLOAT; | 
 | 			break; | 
 | 		default: | 
 | 			ret = -ENOTSUP; | 
 | 			break; | 
 | 		} | 
 | 		break; | 
 |  | 
 | 	case 3U: | 
 | 		/* GPIO3 */ | 
 | 		switch (func) { | 
 | 		case AXP192_GPIO_FUNC_INPUT: | 
 | 			reg_cfg = AXP192_GPIO3_FUNC_VAL_INPUT | AXP192_GPIO34_FUNC_ENA; | 
 | 			break; | 
 | 		case AXP192_GPIO_FUNC_OUTPUT_OD: | 
 | 			reg_cfg = AXP192_GPIO3_FUNC_VAL_OUTPUT_OD | AXP192_GPIO34_FUNC_ENA; | 
 | 			is_output = true; | 
 | 			break; | 
 | 		case AXP192_GPIO_FUNC_CHARGE_CTL: | 
 | 			reg_cfg = AXP192_GPIO3_FUNC_VAL_CHARGE_CTL; | 
 | 			break; | 
 | 		default: | 
 | 			ret = -ENOTSUP; | 
 | 			break; | 
 | 		} | 
 | 		break; | 
 |  | 
 | 	case 4U: | 
 | 		/* GPIO4 */ | 
 | 		switch (func) { | 
 | 		case AXP192_GPIO_FUNC_INPUT: | 
 | 			reg_cfg = AXP192_GPIO4_FUNC_VAL_INPUT | AXP192_GPIO34_FUNC_ENA; | 
 | 			break; | 
 | 		case AXP192_GPIO_FUNC_OUTPUT_OD: | 
 | 			reg_cfg = AXP192_GPIO4_FUNC_VAL_OUTPUT_OD | AXP192_GPIO34_FUNC_ENA; | 
 | 			is_output = true; | 
 | 			break; | 
 | 		case AXP192_GPIO_FUNC_ADC: | 
 | 			reg_cfg = AXP192_GPIO4_FUNC_VAL_ADC | AXP192_GPIO34_FUNC_ENA; | 
 | 			break; | 
 | 		case AXP192_GPIO_FUNC_CHARGE_CTL: | 
 | 			reg_cfg = AXP192_GPIO4_FUNC_VAL_CHARGE_CTL; | 
 | 			break; | 
 | 		default: | 
 | 			ret = -ENOTSUP; | 
 | 			break; | 
 | 		} | 
 | 		break; | 
 |  | 
 | 	case 5U: | 
 | 		/* EXTEN is an output only pin */ | 
 | 		break; | 
 |  | 
 | 	default: | 
 | 		ret = -EINVAL; | 
 | 	} | 
 |  | 
 | 	if (ret != 0) { | 
 | 		LOG_ERR("Invalid function (0x%x) for gpio %d", func, gpio); | 
 | 		return ret; | 
 | 	} | 
 |  | 
 | 	if (gpio < ARRAY_SIZE(gpio_reg_desc)) { | 
 | 		ret = i2c_reg_update_byte_dt(&(config->i2c), gpio_reg_desc[gpio].reg, | 
 | 					     gpio_reg_desc[gpio].mask, reg_cfg); | 
 | 		if (ret != 0) { | 
 | 			return ret; | 
 | 		} | 
 | 	} | 
 |  | 
 | 	/* Save gpio configuration state */ | 
 | 	data->gpio_mask_used[gpio] = client_dev; | 
 | 	if (is_output) { | 
 | 		data->gpio_mask_output |= (1u << gpio); | 
 | 	} else { | 
 | 		data->gpio_mask_output &= ~(1u << gpio); | 
 | 	} | 
 | 	LOG_DBG("GPIO %d configured successfully (func=0x%x)", gpio, reg_cfg); | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | int mfd_axp192_gpio_pd_get(const struct device *dev, uint8_t gpio, bool *enabled) | 
 | { | 
 | 	const struct mfd_axp192_config *config = dev->config; | 
 | 	uint8_t gpio_val; | 
 | 	uint8_t pd_reg_mask = 0; | 
 | 	int ret = 0; | 
 |  | 
 | 	switch (gpio) { | 
 | 	case 0U: | 
 | 		pd_reg_mask = AXP192_GPIO0_PULLDOWN_ENABLE; | 
 | 		break; | 
 | 	case 1U: | 
 | 		pd_reg_mask = AXP192_GPIO1_PULLDOWN_ENABLE; | 
 | 		break; | 
 | 	case 2U: | 
 | 		pd_reg_mask = AXP192_GPIO2_PULLDOWN_ENABLE; | 
 | 		break; | 
 |  | 
 | 	case 3U: | 
 | 		__fallthrough; | 
 | 	case 4U: | 
 | 		__fallthrough; | 
 | 	case 5U: | 
 | 		LOG_DBG("Pull-Down not support on gpio %d", gpio); | 
 | 		return -ENOTSUP; | 
 |  | 
 | 	default: | 
 | 		LOG_ERR("Invalid gpio (%d)", gpio); | 
 | 		return -EINVAL; | 
 | 	} | 
 |  | 
 | 	ret = i2c_reg_read_byte_dt(&(config->i2c), AXP192_GPIO012_PULLDOWN_REG, &gpio_val); | 
 |  | 
 | 	if (ret == 0) { | 
 | 		*enabled = ((gpio_val & pd_reg_mask) != 0); | 
 | 		LOG_DBG("Pull-Down stats of gpio %d: %d", gpio, *enabled); | 
 | 	} | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | int mfd_axp192_gpio_pd_ctrl(const struct device *dev, uint8_t gpio, bool enable) | 
 | { | 
 | 	uint8_t reg_pd_val = 0; | 
 | 	uint8_t reg_pd_mask = 0; | 
 | 	const struct mfd_axp192_config *config = dev->config; | 
 | 	int ret = 0; | 
 |  | 
 | 	/* Configure pull-down. Pull-down is only supported by GPIO3 and GPIO4 */ | 
 | 	switch (gpio) { | 
 | 	case 0U: | 
 | 		reg_pd_mask = AXP192_GPIO0_PULLDOWN_ENABLE; | 
 | 		if (enable) { | 
 | 			reg_pd_val = AXP192_GPIO0_PULLDOWN_ENABLE; | 
 | 		} | 
 | 		break; | 
 |  | 
 | 	case 1U: | 
 | 		reg_pd_mask = AXP192_GPIO1_PULLDOWN_ENABLE; | 
 | 		if (enable) { | 
 | 			reg_pd_val = AXP192_GPIO1_PULLDOWN_ENABLE; | 
 | 		} | 
 | 		break; | 
 |  | 
 | 	case 2U: | 
 | 		reg_pd_mask = AXP192_GPIO2_PULLDOWN_ENABLE; | 
 | 		if (enable) { | 
 | 			reg_pd_val = AXP192_GPIO2_PULLDOWN_ENABLE; | 
 | 		} | 
 | 		break; | 
 |  | 
 | 	case 3U: | 
 | 		__fallthrough; | 
 | 	case 4U: | 
 | 		__fallthrough; | 
 | 	case 5U: | 
 | 		LOG_ERR("Pull-Down not support on gpio %d", gpio); | 
 | 		return -ENOTSUP; | 
 |  | 
 | 	default: | 
 | 		LOG_ERR("Invalid gpio (%d)", gpio); | 
 | 		return -EINVAL; | 
 | 	} | 
 |  | 
 | 	ret = i2c_reg_update_byte_dt(&(config->i2c), AXP192_GPIO012_PULLDOWN_REG, reg_pd_mask, | 
 | 				     reg_pd_val); | 
 |  | 
 | 	return ret; | 
 | } | 
 |  | 
 | int mfd_axp192_gpio_read_port(const struct device *dev, uint8_t *value) | 
 | { | 
 | 	const struct mfd_axp192_config *config = dev->config; | 
 | 	const struct mfd_axp192_data *data = dev->data; | 
 | 	int ret; | 
 | 	uint8_t gpio012_val; | 
 | 	uint8_t gpio34_val; | 
 | 	uint8_t gpio5_val; | 
 | 	uint8_t gpio_input_val; | 
 | 	uint8_t gpio_output_val; | 
 |  | 
 | 	/* read gpio0-2 */ | 
 | 	ret = i2c_reg_read_byte_dt(&(config->i2c), AXP192_GPIO012_PINVAL_REG, &gpio012_val); | 
 | 	if (ret != 0) { | 
 | 		return ret; | 
 | 	} | 
 |  | 
 | 	/* read gpio3-4 */ | 
 | 	ret = i2c_reg_read_byte_dt(&(config->i2c), AXP192_GPIO34_PINVAL_REG, &gpio34_val); | 
 | 	if (ret != 0) { | 
 | 		return ret; | 
 | 	} | 
 |  | 
 | 	/* read gpio5 */ | 
 | 	ret = i2c_reg_read_byte_dt(&(config->i2c), AXP192_EXTEN_DCDC2_CONTROL_REG, &gpio5_val); | 
 | 	if (ret != 0) { | 
 | 		return ret; | 
 | 	} | 
 |  | 
 | 	LOG_DBG("GPIO012 pinval-reg=0x%x", gpio012_val); | 
 | 	LOG_DBG("GPIO34 pinval-reg =0x%x", gpio34_val); | 
 | 	LOG_DBG("GPIO5 pinval-reg =0x%x", gpio5_val); | 
 | 	LOG_DBG("Output-Mask       =0x%x", data->gpio_mask_output); | 
 |  | 
 | 	gpio_input_val = | 
 | 		((gpio012_val & AXP192_GPIO012_INTPUT_MASK) >> AXP192_GPIO012_INTPUT_SHIFT); | 
 | 	gpio_input_val |= | 
 | 		(((gpio34_val & AXP192_GPIO34_INTPUT_MASK) >> AXP192_GPIO34_INTPUT_SHIFT) << 3u); | 
 |  | 
 | 	gpio_output_val = (gpio012_val & AXP192_GPIO012_OUTPUT_MASK); | 
 | 	gpio_output_val |= ((gpio34_val & AXP192_GPIO34_OUTPUT_MASK) << 3u); | 
 | 	gpio_output_val |= | 
 | 		(((gpio5_val & AXP192_GPIO5_OUTPUT_MASK) >> AXP192_GPIO5_OUTPUT_SHIFT) << 5u); | 
 |  | 
 | 	*value = gpio_input_val & ~(data->gpio_mask_output); | 
 | 	*value |= (gpio_output_val & data->gpio_mask_output); | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | int mfd_axp192_gpio_write_port(const struct device *dev, uint8_t value, uint8_t mask) | 
 | { | 
 | 	const struct mfd_axp192_config *config = dev->config; | 
 | 	int ret; | 
 | 	uint8_t gpio_reg_val; | 
 | 	uint8_t gpio_reg_mask; | 
 |  | 
 | 	/* Write gpio0-2. Mask out other port pins */ | 
 | 	gpio_reg_val = (value & AXP192_GPIO012_OUTPUT_MASK); | 
 | 	gpio_reg_mask = (mask & AXP192_GPIO012_OUTPUT_MASK); | 
 | 	if (gpio_reg_mask != 0) { | 
 | 		ret = i2c_reg_update_byte_dt(&(config->i2c), AXP192_GPIO012_PINVAL_REG, | 
 | 					     gpio_reg_mask, gpio_reg_val); | 
 | 		if (ret != 0) { | 
 | 			return ret; | 
 | 		} | 
 | 		LOG_DBG("GPIO012 pinval-reg=0x%x mask=0x%x", gpio_reg_val, gpio_reg_mask); | 
 | 	} | 
 |  | 
 | 	/* Write gpio3-4. Mask out other port pins */ | 
 | 	gpio_reg_val = value >> 3U; | 
 | 	gpio_reg_mask = (mask >> 3U) & AXP192_GPIO34_OUTPUT_MASK; | 
 | 	if (gpio_reg_mask != 0) { | 
 | 		ret = i2c_reg_update_byte_dt(&(config->i2c), AXP192_GPIO34_PINVAL_REG, | 
 | 					     gpio_reg_mask, gpio_reg_val); | 
 | 		if (ret != 0) { | 
 | 			return ret; | 
 | 		} | 
 | 		LOG_DBG("GPIO34 pinval-reg =0x%x mask=0x%x", gpio_reg_val, gpio_reg_mask); | 
 | 	} | 
 |  | 
 | 	/* Write gpio5. Mask out other port pins */ | 
 | 	if ((mask & BIT(5)) != 0) { | 
 | 		gpio_reg_mask = AXP192_EXTEN_MASK; | 
 | 		gpio_reg_val = (value & BIT(5)) ? AXP192_EXTEN_ENA : 0U; | 
 | 		ret = i2c_reg_update_byte_dt(&(config->i2c), AXP192_EXTEN_DCDC2_CONTROL_REG, | 
 | 					     gpio_reg_mask, gpio_reg_val); | 
 | 		if (ret != 0) { | 
 | 			return ret; | 
 | 		} | 
 | 		LOG_DBG("GPIO5 pinval-reg =0x%x mask=0x%x\n", gpio_reg_val, gpio_reg_mask); | 
 | 	} | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | #define MFD_AXP192_DEFINE(node)                                                                    \ | 
 | 	static const struct mfd_axp192_config config##node = {                                     \ | 
 | 		.i2c = I2C_DT_SPEC_GET(node),                                                      \ | 
 | 		.vbusen_disable = DT_PROP_OR(node, vbusen_disable, false),                         \ | 
 | 		.vbus_config_reg = AXP192_VBUS_CFG_REG,                                            \ | 
 | 		.val_vbusen_disable = AXP192_VBUS_CFG_VAL_VBUSEN_DISABLE,                          \ | 
 | 	};                                                                                         \ | 
 |                                                                                                    \ | 
 | 	static struct mfd_axp192_data data##node;                                                  \ | 
 |                                                                                                    \ | 
 | 	DEVICE_DT_DEFINE(node, mfd_axp192_init, NULL, &data##node,                                 \ | 
 | 			 &config##node, POST_KERNEL, CONFIG_MFD_INIT_PRIORITY, NULL); | 
 |  | 
 | DT_FOREACH_STATUS_OKAY(x_powers_axp192, MFD_AXP192_DEFINE); |