diff --git a/doc/_doxygen/groups.dox b/doc/_doxygen/groups.dox index ddc0c1c3640..cd4efcd6294 100644 --- a/doc/_doxygen/groups.dox +++ b/doc/_doxygen/groups.dox @@ -22,6 +22,12 @@ @{ @} +@brief Multi Function Device Drivers APIs +@defgroup mfd_interfaces Multi Function Device Drivers APIs +@ingroup io_interfaces +@{ +@} + @brief Testing @defgroup testing Testing @{ diff --git a/drivers/mfd/CMakeLists.txt b/drivers/mfd/CMakeLists.txt index 6719916cc1b..d7071a6af95 100644 --- a/drivers/mfd/CMakeLists.txt +++ b/drivers/mfd/CMakeLists.txt @@ -3,4 +3,5 @@ zephyr_library() +zephyr_library_sources_ifdef(CONFIG_MFD_NPM1300 mfd_npm1300.c) zephyr_library_sources_ifdef(CONFIG_MFD_NPM6001 mfd_npm6001.c) diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 42ac815e55b..64a166c7cc7 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -18,6 +18,7 @@ config MFD_INIT_PRIORITY help Multi-function devices initialization priority. +source "drivers/mfd/Kconfig.npm1300" source "drivers/mfd/Kconfig.npm6001" endif # MFD diff --git a/drivers/mfd/Kconfig.npm1300 b/drivers/mfd/Kconfig.npm1300 new file mode 100644 index 00000000000..cc3eb0ef303 --- /dev/null +++ b/drivers/mfd/Kconfig.npm1300 @@ -0,0 +1,10 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX -License-Identifier: Apache-2.0 + +config MFD_NPM1300 + bool "nPM1300 PMIC multi-function device driver" + default y + depends on DT_HAS_NORDIC_NPM1300_ENABLED + select I2C + help + Enable the Nordic nPM1300 PMIC multi-function device driver diff --git a/drivers/mfd/mfd_npm1300.c b/drivers/mfd/mfd_npm1300.c new file mode 100644 index 00000000000..34b03b85bc4 --- /dev/null +++ b/drivers/mfd/mfd_npm1300.c @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nordic_npm1300 + +#include + +#include +#include +#include + +struct mfd_npm1300_config { + struct i2c_dt_spec i2c; +}; + +struct mfd_npm1300_data { + struct k_mutex mutex; +}; + +static int mfd_npm1300_init(const struct device *dev) +{ + const struct mfd_npm1300_config *config = dev->config; + struct mfd_npm1300_data *mfd_data = dev->data; + + if (!i2c_is_ready_dt(&config->i2c)) { + return -ENODEV; + } + + k_mutex_init(&mfd_data->mutex); + + return 0; +} + +int mfd_npm1300_reg_read_burst(const struct device *dev, uint8_t base, uint8_t offset, void *data, + size_t len) +{ + const struct mfd_npm1300_config *config = dev->config; + struct mfd_npm1300_data *mfd_data = dev->data; + uint8_t buff[] = {base, offset}; + int ret; + + k_mutex_lock(&mfd_data->mutex, K_FOREVER); + + ret = i2c_write_read_dt(&config->i2c, buff, sizeof(buff), data, len); + + k_mutex_unlock(&mfd_data->mutex); + + return ret; +} + +int mfd_npm1300_reg_read(const struct device *dev, uint8_t base, uint8_t offset, uint8_t *data) +{ + return mfd_npm1300_reg_read_burst(dev, base, offset, data, 1U); +} + +int mfd_npm1300_reg_write(const struct device *dev, uint8_t base, uint8_t offset, uint8_t data) +{ + const struct mfd_npm1300_config *config = dev->config; + struct mfd_npm1300_data *mfd_data = dev->data; + uint8_t buff[] = {base, offset, data}; + int ret; + + k_mutex_lock(&mfd_data->mutex, K_FOREVER); + + ret = i2c_write_dt(&config->i2c, buff, sizeof(buff)); + + k_mutex_unlock(&mfd_data->mutex); + + return ret; +} + +int mfd_npm1300_reg_write2(const struct device *dev, uint8_t base, uint8_t offset, uint8_t data1, + uint8_t data2) +{ + const struct mfd_npm1300_config *config = dev->config; + struct mfd_npm1300_data *mfd_data = dev->data; + uint8_t buff[] = {base, offset, data1, data2}; + int ret; + + k_mutex_lock(&mfd_data->mutex, K_FOREVER); + + ret = i2c_write_dt(&config->i2c, buff, sizeof(buff)); + + k_mutex_unlock(&mfd_data->mutex); + + return ret; +} + +int mfd_npm1300_reg_update(const struct device *dev, uint8_t base, uint8_t offset, uint8_t data, + uint8_t mask) +{ + struct mfd_npm1300_data *mfd_data = dev->data; + uint8_t reg; + int ret; + + k_mutex_lock(&mfd_data->mutex, K_FOREVER); + + ret = mfd_npm1300_reg_read(dev, base, offset, ®); + + if (ret == 0) { + reg = (reg & ~mask) | (data & mask); + ret = mfd_npm1300_reg_write(dev, base, offset, reg); + } + + k_mutex_unlock(&mfd_data->mutex); + + return ret; +} + +#define MFD_NPM1300_DEFINE(inst) \ + static struct mfd_npm1300_data data_##inst; \ + \ + static const struct mfd_npm1300_config config##inst = { \ + .i2c = I2C_DT_SPEC_INST_GET(inst), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(inst, mfd_npm1300_init, NULL, &data_##inst, &config##inst, \ + POST_KERNEL, CONFIG_MFD_INIT_PRIORITY, NULL); + +DT_INST_FOREACH_STATUS_OKAY(MFD_NPM1300_DEFINE) diff --git a/include/zephyr/drivers/mfd/npm1300.h b/include/zephyr/drivers/mfd/npm1300.h new file mode 100644 index 00000000000..372ab725ed9 --- /dev/null +++ b/include/zephyr/drivers/mfd/npm1300.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_MFD_NPM1300_H_ +#define ZEPHYR_INCLUDE_DRIVERS_MFD_NPM1300_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup mdf_interface_npm1300 MFD NPM1300 Interface + * @ingroup mfd_interfaces + * @{ + */ + +#include +#include + +#include + +/** + * @brief Read multiple registers from npm1300 + * + * @param dev npm1300 mfd device + * @param base Register base address (bits 15..8 of 16-bit address) + * @param offset Register offset address (bits 7..0 of 16-bit address) + * @param data Pointer to buffer for received data + * @param len Number of bytes to read + * @retval 0 If successful + * @retval -errno In case of any bus error (see i2c_write_read_dt()) + */ +int mfd_npm1300_reg_read_burst(const struct device *dev, uint8_t base, uint8_t offset, + void *data, size_t len); + +/** + * @brief Read single register from npm1300 + * + * @param dev npm1300 mfd device + * @param base Register base address (bits 15..8 of 16-bit address) + * @param offset Register offset address (bits 7..0 of 16-bit address) + * @param data Pointer to buffer for received data + * @retval 0 If successful + * @retval -errno In case of any bus error (see i2c_write_read_dt()) + */ +int mfd_npm1300_reg_read(const struct device *dev, uint8_t base, uint8_t offset, uint8_t *data); + +/** + * @brief Write single register to npm1300 + * + * @param dev npm1300 mfd device + * @param base Register base address (bits 15..8 of 16-bit address) + * @param offset Register offset address (bits 7..0 of 16-bit address) + * @param data data to write + * @retval 0 If successful + * @retval -errno In case of any bus error (see i2c_write_dt()) + */ +int mfd_npm1300_reg_write(const struct device *dev, uint8_t base, uint8_t offset, uint8_t data); + +/** + * @brief Write two registers to npm1300 + * + * @param dev npm1300 mfd device + * @param base Register base address (bits 15..8 of 16-bit address) + * @param offset Register offset address (bits 7..0 of 16-bit address) + * @param data1 first byte of data to write + * @param data2 second byte of data to write + * @retval 0 If successful + * @retval -errno In case of any bus error (see i2c_write_dt()) + */ +int mfd_npm1300_reg_write2(const struct device *dev, uint8_t base, uint8_t offset, uint8_t data1, + uint8_t data2); + +/** + * @brief Update selected bits in npm1300 register + * + * @param dev npm1300 mfd device + * @param base Register base address (bits 15..8 of 16-bit address) + * @param offset Register offset address (bits 7..0 of 16-bit address) + * @param data data to write + * @param mask mask of bits to be modified + * @retval 0 If successful + * @retval -errno In case of any bus error (see i2c_write_read_dt(), i2c_write_dt()) + */ +int mfd_npm1300_reg_update(const struct device *dev, uint8_t base, uint8_t offset, uint8_t data, + uint8_t mask); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_DRIVERS_MFD_NPM1300_H_ */